diff --git a/src/core/window-private.h b/src/core/window-private.h index ef76e3d32..c9e8e103f 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -678,7 +678,9 @@ void meta_window_update_layer (MetaWindow *window); void meta_window_recalc_features (MetaWindow *window); +/* recalc_window_type is x11 only, wayland does its thing and then calls type_changed */ void meta_window_recalc_window_type (MetaWindow *window); +void meta_window_type_changed (MetaWindow *window); void meta_window_stack_just_below (MetaWindow *window, MetaWindow *below_this_one); diff --git a/src/core/window.c b/src/core/window.c index 3b8cd4e9e..a99650b24 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -1049,16 +1049,6 @@ meta_window_new_shared (MetaDisplay *display, if (client_type == META_WINDOW_CLIENT_TYPE_X11) { - if (window->override_redirect) - { - window->decorated = FALSE; - window->always_sticky = TRUE; - window->has_close_func = FALSE; - window->has_shade_func = FALSE; - window->has_move_func = FALSE; - window->has_resize_func = FALSE; - } - meta_display_register_x_window (display, &window->xwindow, window); meta_window_update_shape_region_x11 (window); meta_window_update_input_region_x11 (window); @@ -1077,6 +1067,16 @@ meta_window_new_shared (MetaDisplay *display, else meta_wayland_surface_set_initial_state (window->surface, window); + if (window->override_redirect) + { + window->decorated = FALSE; + window->always_sticky = TRUE; + window->has_close_func = FALSE; + window->has_shade_func = FALSE; + window->has_move_func = FALSE; + window->has_resize_func = FALSE; + } + if (!window->override_redirect && client_type == META_WINDOW_CLIENT_TYPE_X11) { @@ -1085,7 +1085,8 @@ meta_window_new_shared (MetaDisplay *display, meta_window_update_role (window); } - meta_window_update_net_wm_type (window); + if (client_type == META_WINDOW_CLIENT_TYPE_X11) + meta_window_update_net_wm_type (window); if (!window->override_redirect) meta_window_update_icon_now (window); @@ -8549,36 +8550,40 @@ recalc_window_type (MetaWindow *window) window->type, window->desc, old_type); if (old_type != window->type) - { - gboolean old_decorated = window->decorated; - GObject *object = G_OBJECT (window); + meta_window_type_changed (window); +} - window->attached = meta_window_should_attach_to_parent (window); - recalc_window_features (window); +void +meta_window_type_changed (MetaWindow *window) +{ + gboolean old_decorated = window->decorated; + GObject *object = G_OBJECT (window); - if (!window->override_redirect) - set_net_wm_state (window); + window->attached = meta_window_should_attach_to_parent (window); + recalc_window_features (window); - /* Update frame */ - if (window->decorated) - meta_window_ensure_frame (window); - else - meta_window_destroy_frame (window); + if (!window->override_redirect) + set_net_wm_state (window); - /* update stacking constraints */ - meta_window_update_layer (window); + /* Update frame */ + if (window->decorated) + meta_window_ensure_frame (window); + else + meta_window_destroy_frame (window); - meta_window_grab_keys (window); + /* update stacking constraints */ + meta_window_update_layer (window); - g_object_freeze_notify (object); + meta_window_grab_keys (window); - if (old_decorated != window->decorated) - g_object_notify (object, "decorated"); + g_object_freeze_notify (object); - g_object_notify (object, "window-type"); + if (old_decorated != window->decorated) + g_object_notify (object, "decorated"); - g_object_thaw_notify (object); - } + g_object_notify (object, "window-type"); + + g_object_thaw_notify (object); } static void @@ -8676,7 +8681,10 @@ recalc_window_features (MetaWindow *window) old_always_sticky = window->always_sticky; /* Use MWM hints initially */ - window->decorated = window->mwm_decorated; + if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) + window->decorated = window->mwm_decorated; + else + window->decorated = FALSE; window->border_only = window->mwm_border_only; window->has_close_func = window->mwm_has_close_func; window->has_minimize_func = window->mwm_has_minimize_func; diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index cc4192c1c..a8b67e9c0 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -51,6 +51,8 @@ #include +static void meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer); + static MetaWaylandSeat * meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer) { @@ -109,6 +111,7 @@ default_grab_button (MetaWaylandPointerGrab *grab, struct wl_client *client = wl_resource_get_client (resource); struct wl_display *display = wl_client_get_display (client); serial = wl_display_next_serial (display); + pointer->click_serial = serial; wl_pointer_send_button (resource, serial, time, button, state_w); } @@ -459,3 +462,105 @@ meta_wayland_pointer_destroy_focus (MetaWaylandPointer *pointer) meta_wayland_pointer_set_focus (pointer, NULL, 0, 0); } } + +static void +popup_grab_focus (MetaWaylandPointerGrab *grab, + MetaWaylandSurface *surface, + wl_fixed_t x, + wl_fixed_t y) +{ + /* Popup grabs are in owner-events mode (ie, events for the same client + are reported as normal) */ + if (wl_resource_get_client (surface->resource) == + wl_resource_get_client (grab->focus->resource)) + default_grab_focus (grab, surface, x, y); + else + meta_wayland_pointer_set_focus (grab->pointer, NULL, 0, 0); +} + +static void +popup_grab_motion (MetaWaylandPointerGrab *grab, + uint32_t time, + wl_fixed_t x, + wl_fixed_t y) +{ + default_grab_motion (grab, time, x, y); +} + +static void +popup_grab_button (MetaWaylandPointerGrab *grab, + uint32_t time, + uint32_t button, + uint32_t state) +{ + MetaWaylandPointer *pointer = grab->pointer; + + if (pointer->focus_resource) + { + /* This is ensured by popup_grab_focus */ + g_assert (wl_resource_get_client (pointer->focus_resource) == + wl_resource_get_client (grab->focus->resource)); + + default_grab_button (grab, time, button, state); + } + else if (state == WL_POINTER_BUTTON_STATE_RELEASED && + pointer->button_count == 0) + meta_wayland_pointer_end_popup_grab (grab->pointer); +} + +static MetaWaylandPointerGrabInterface popup_grab = { + popup_grab_focus, + popup_grab_motion, + popup_grab_button +}; + +static void +meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer) +{ + MetaWaylandPointerGrab *grab; + + grab = pointer->grab; + + g_assert (grab->interface == &popup_grab); + + if (grab->focus) + { + wl_shell_surface_send_popup_done (grab->focus->shell_surface->resource); + wl_list_remove (&grab->focus_destroy_listener.link); + } + + meta_wayland_pointer_end_grab (pointer); + g_slice_free (MetaWaylandPointerGrab, grab); +} + +static void +on_popup_surface_destroy (struct wl_listener *listener, + void *data) +{ + MetaWaylandPointerGrab *grab = + wl_container_of (listener, grab, focus_destroy_listener); + + grab->focus = NULL; + meta_wayland_pointer_end_popup_grab (grab->pointer); +} + +gboolean +meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface) +{ + MetaWaylandPointerGrab *grab; + + if (pointer->grab != &pointer->default_grab) + return FALSE; + + grab = g_slice_new0 (MetaWaylandPointerGrab); + grab->interface = &popup_grab; + grab->pointer = pointer; + grab->focus = surface; + + grab->focus_destroy_listener.notify = on_popup_surface_destroy; + wl_resource_add_destroy_listener (surface->resource, &grab->focus_destroy_listener); + + meta_wayland_pointer_start_grab (pointer, grab); + return TRUE; +} diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h index 4c4aaffcf..bba28d023 100644 --- a/src/wayland/meta-wayland-pointer.h +++ b/src/wayland/meta-wayland-pointer.h @@ -42,6 +42,8 @@ struct _MetaWaylandPointerGrab MetaWaylandPointer *pointer; MetaWaylandSurface *focus; wl_fixed_t x, y; + + struct wl_listener focus_destroy_listener; }; struct _MetaWaylandPointer @@ -51,6 +53,7 @@ struct _MetaWaylandPointer struct wl_resource *focus_resource; struct wl_listener focus_listener; guint32 focus_serial; + guint32 click_serial; struct wl_signal focus_signal; MetaWaylandPointerGrab *grab; @@ -96,6 +99,10 @@ meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer); void meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer); +gboolean +meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, + MetaWaylandSurface *popup); + void meta_wayland_pointer_set_current (MetaWaylandPointer *pointer, MetaWaylandSurface *surface); diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index ee4e7e943..58dab549f 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -758,13 +758,38 @@ shell_surface_set_fullscreen (struct wl_client *client, static void shell_surface_set_popup (struct wl_client *client, struct wl_resource *resource, - struct wl_resource *seat, + struct wl_resource *seat_resource, guint32 serial, struct wl_resource *parent, gint32 x, gint32 y, guint32 flags) { + MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = shell_surface->surface; + MetaWaylandCompositor *compositor = surface->compositor; + MetaWaylandSeat *seat = compositor->seat; + + if (serial < seat->pointer.click_serial) + { + /* stale request */ + return; + } + + if (surface->window) + { + meta_warning ("Client set_popup() on an already visible window, this is not supported\n"); + } + else + { + ensure_initial_state (surface); + + surface->initial_state->initial_type = META_WAYLAND_SURFACE_POPUP; + surface->initial_state->transient_for = parent; + surface->initial_state->x = x; + surface->initial_state->y = y; + } + } static void @@ -1060,10 +1085,14 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface, MetaWindow *window) { MetaWaylandSurfaceInitialState *initial = surface->initial_state; + MetaWaylandCompositor *compositor = surface->compositor; + MetaWaylandSeat *seat = compositor->seat; if (initial == NULL) return; + window->type = META_WINDOW_NORMAL; + /* Note that we poke at the bits directly here, because we're in the middle of meta_window_new_shared() */ switch (initial->initial_type) @@ -1076,6 +1105,15 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface, case META_WAYLAND_SURFACE_MAXIMIZED: window->maximized_horizontally = window->maximized_vertically = TRUE; break; + case META_WAYLAND_SURFACE_POPUP: + window->override_redirect = TRUE; + window->type = META_WINDOW_DROPDOWN_MENU; + window->mapped = TRUE; + window->showing_for_first_time = FALSE; + window->placed = TRUE; + if (!meta_wayland_pointer_start_popup_grab (&seat->pointer, surface)) + wl_shell_surface_send_popup_done (surface->shell_surface->resource); + break; default: g_assert_not_reached (); } @@ -1083,8 +1121,18 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface, if (initial->transient_for) { MetaWaylandSurface *parent = wl_resource_get_user_data (initial->transient_for); - if (parent) - window->transient_for = g_object_ref (parent->window); + if (parent && parent->window) + { + window->transient_for = g_object_ref (parent->window); + + if (initial->initial_type == META_WAYLAND_SURFACE_POPUP) + { + window->rect.x = parent->window->rect.x + initial->x; + window->rect.y = parent->window->rect.y + initial->y; + } + } + + window->type = META_WINDOW_DIALOG; } if (initial->title) @@ -1101,6 +1149,8 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface, initial->gtk_application_object_path, initial->gtk_window_object_path); + meta_window_type_changed (window); + free_initial_state (initial); surface->initial_state = NULL; } diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index dab412488..1a1b3adc5 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -69,13 +69,15 @@ typedef struct typedef enum { META_WAYLAND_SURFACE_TOPLEVEL = 0, META_WAYLAND_SURFACE_MAXIMIZED, - META_WAYLAND_SURFACE_FULLSCREEN + META_WAYLAND_SURFACE_FULLSCREEN, + META_WAYLAND_SURFACE_POPUP, } MetaWaylandSurfaceType; typedef struct { MetaWaylandSurfaceType initial_type; struct wl_resource *transient_for; + int x, y; char *title; char *wm_class;