[mutter/wip/wayland-work: 25/25] wayland: implement support for popup surfaces



commit be4d7f31b8c86e296cb60b31f2ebe5de7dc14550
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 9505d28..b7c9944 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]