[mutter/wip/wayland-work: 19/22] wayland: implement support for popup surfaces
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/wayland-work: 19/22] wayland: implement support for popup surfaces
- Date: Wed, 11 Sep 2013 16:24:46 +0000 (UTC)
commit 85fa773973818b7f07e1caaa62dc97084ea6d3d6
Author: Giovanni Campagna <gcampagn redhat com>
Date: Tue Sep 10 15:53:31 2013 +0200
wayland: implement support for popup surfaces
Popup surfaces are mapped into override_redirect surfaces
of a DROPDOWN_MENU type, with the addition of a special pointer
grab.
https://bugzilla.gnome.org/show_bug.cgi?id=707863
src/core/window-private.h | 2 +
src/core/window.c | 74 ++++++++++++++-----------
src/wayland/meta-wayland-pointer.c | 105 ++++++++++++++++++++++++++++++++++++
src/wayland/meta-wayland-pointer.h | 7 +++
src/wayland/meta-wayland-surface.c | 56 ++++++++++++++++++-
src/wayland/meta-wayland-surface.h | 4 +-
6 files changed, 211 insertions(+), 37 deletions(-)
---
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 9504bca..4aa7dc7 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 c3ce153..b2aeaa6 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -1046,16 +1046,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);
@@ -1072,6 +1062,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)
{
@@ -1080,7 +1080,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);
@@ -8543,36 +8544,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
@@ -8670,7 +8675,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 6154c65..ca0dc49 100644
--- a/src/wayland/meta-wayland-pointer.c
+++ b/src/wayland/meta-wayland-pointer.c
@@ -52,6 +52,8 @@
#include <string.h>
+static void meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer);
+
static MetaWaylandSeat *
meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
{
@@ -110,6 +112,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);
}
@@ -470,3 +473,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 4c4aaff..bba28d0 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 ee4e7e9..58dab54 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 dab4124..1a1b3ad 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;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]