[mutter/wayland] wayland: implement transient hints for wayland clients



commit 81d979754451644fbcbb93ac0e36fb46bf40d15a
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Mon Sep 16 14:44:37 2013 +0200

    wayland: implement transient hints for wayland clients
    
    wl_shell supports a set_transient() map request that is equivalent
    to setting WM_TRANSIENT_FOR in X11, so implement that.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=707401

 src/core/window-private.h          |    4 ++
 src/core/window-props.c            |   50 +++----------------
 src/core/window.c                  |   99 ++++++++++++++++++++++++++----------
 src/wayland/meta-wayland-surface.c |   19 +++++++-
 src/wayland/meta-wayland-surface.h |    1 +
 5 files changed, 102 insertions(+), 71 deletions(-)
---
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 9974643..ef76e3d 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -127,6 +127,7 @@ struct _MetaWindow
   Window xtransient_for;
   Window xgroup_leader;
   Window xclient_leader;
+  MetaWindow *transient_for;
 
   /* Initial workspace property */
   int initial_workspace;  
@@ -727,4 +728,7 @@ void meta_window_set_gtk_dbus_properties  (MetaWindow *window,
                                            const char *application_object_path,
                                            const char *window_object_path);
 
+void meta_window_set_transient_for        (MetaWindow *window,
+                                           MetaWindow *parent);
+
 #endif
diff --git a/src/core/window-props.c b/src/core/window-props.c
index b97f040..1c79929 100644
--- a/src/core/window-props.c
+++ b/src/core/window-props.c
@@ -1518,7 +1518,7 @@ reload_transient_for (MetaWindow    *window,
                       gboolean       initial)
 {
   MetaWindow *parent = NULL;
-  Window transient_for, old_transient_for;
+  Window transient_for;
 
   if (value->type != META_PROP_VALUE_INVALID)
     {
@@ -1553,10 +1553,6 @@ reload_transient_for (MetaWindow    *window,
   if (transient_for == window->xtransient_for)
     return;
 
-  if (meta_window_appears_focused (window) && window->xtransient_for != None)
-    meta_window_propagate_focus_appearance (window, FALSE);
-
-  old_transient_for = window->xtransient_for;
   window->xtransient_for = transient_for;
 
   window->transient_parent_is_root_window =
@@ -1568,46 +1564,14 @@ reload_transient_for (MetaWindow    *window,
   else
     meta_verbose ("Window %s is not transient\n", window->desc);
 
-  /* may now be a dialog */
-  meta_window_recalc_window_type (window);
-
-  if (!window->constructing)
+  if (window->transient_parent_is_root_window || window->xtransient_for == None)
+    meta_window_set_transient_for (window, NULL);
+  else
     {
-      /* If the window attaches, detaches, or changes attached
-       * parents, we need to destroy the MetaWindow and let a new one
-       * be created (which happens as a side effect of
-       * meta_window_unmanage()). The condition below is correct
-       * because we know window->xtransient_for has changed.
-       */
-      if (window->attached || meta_window_should_attach_to_parent (window))
-        {
-          guint32 timestamp;
-
-          window->xtransient_for = old_transient_for;
-          timestamp = meta_display_get_current_time_roundtrip (window->display);
-          meta_window_unmanage (window, timestamp);
-          return;
-        }
+      parent = meta_display_lookup_x_window (window->display,
+                                             window->xtransient_for);
+      meta_window_set_transient_for (window, parent);
     }
-
-  /* update stacking constraints */
-  if (!window->override_redirect)
-    meta_stack_update_transient (window->screen->stack, window);
-
-  /* possibly change its group. We treat being a window's transient as
-   * equivalent to making it your group leader, to work around shortcomings
-   * in programs such as xmms-- see #328211.
-   */
-  if (window->xtransient_for != None &&
-      window->xgroup_leader != None &&
-      window->xtransient_for != window->xgroup_leader)
-    meta_window_group_leader_changed (window);
-
-  if (!window->constructing && !window->override_redirect)
-    meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
-
-  if (meta_window_appears_focused (window) && window->xtransient_for != None)
-    meta_window_propagate_focus_appearance (window, TRUE);
 }
 
 static void
diff --git a/src/core/window.c b/src/core/window.c
index 1043546..3b8cd4e 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -242,6 +242,9 @@ meta_window_finalize (GObject *object)
   if (window->opaque_region)
     cairo_region_destroy (window->opaque_region);
 
+  if (window->transient_for)
+    g_object_unref (window->transient_for);
+
   meta_icon_cache_free (&window->icon_cache);
 
   g_free (window->sm_client_id);
@@ -1119,11 +1122,6 @@ meta_window_new_shared (MetaDisplay         *display,
    * can use this time as a fallback.
    */
   if (!window->override_redirect && !window->net_wm_user_time_set) {
-    MetaWindow *parent = NULL;
-    if (window->xtransient_for)
-      parent = meta_display_lookup_x_window (window->display,
-                                             window->xtransient_for);
-
     /* First, maybe the app was launched with startup notification using an
      * obsolete version of the spec; use that timestamp if it exists.
      */
@@ -1132,8 +1130,8 @@ meta_window_new_shared (MetaDisplay         *display,
        * being recorded as a fallback for potential transients
        */
       window->net_wm_user_time = window->initial_timestamp;
-    else if (parent != NULL)
-      meta_window_set_user_time(window, parent->net_wm_user_time);
+    else if (window->transient_for != NULL)
+      meta_window_set_user_time (window, window->transient_for->net_wm_user_time);
     else
       /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
        * being recorded as a fallback for potential transients
@@ -1223,21 +1221,16 @@ meta_window_new_shared (MetaDisplay         *display,
   if (!window->override_redirect)
     {
       if (window->workspace == NULL &&
-          window->xtransient_for != None)
+          window->transient_for != NULL)
         {
           /* Try putting dialog on parent's workspace */
-          MetaWindow *parent;
-
-          parent = meta_display_lookup_x_window (window->display,
-                                                 window->xtransient_for);
-
-          if (parent && parent->workspace)
+          if (window->transient_for->workspace)
             {
               meta_topic (META_DEBUG_PLACEMENT,
                           "Putting window %s on same workspace as parent %s\n",
-                          window->desc, parent->desc);
+                          window->desc, window->transient_for->desc);
 
-              if (parent->on_all_workspaces_requested)
+              if (window->transient_for->on_all_workspaces_requested)
                 {
                   window->on_all_workspaces_requested = TRUE;
                   window->on_all_workspaces = TRUE;
@@ -1245,7 +1238,7 @@ meta_window_new_shared (MetaDisplay         *display,
 
               /* this will implicitly add to the appropriate MRU lists
                */
-              meta_workspace_add_window (parent->workspace, window);
+              meta_workspace_add_window (window->transient_for->workspace, window);
             }
         }
 
@@ -4463,14 +4456,14 @@ window_activate (MetaWindow     *window,
   /* For non-transient windows, we just set up a pulsing indicator,
      rather than move windows or workspaces.
      See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */
-  if (window->xtransient_for == None &&
+  if (window->transient_for == NULL &&
       !meta_window_located_on_workspace (window, workspace))
     {
       meta_window_set_demands_attention (window);
       /* We've marked it as demanding, don't need to do anything else. */
       return;
     }
-  else if (window->xtransient_for != None)
+  else if (window->transient_for != NULL)
     {
       /* Move transients to current workspace - preference dialogs should appear over
          the source window.  */
@@ -6136,7 +6129,7 @@ get_modal_transient (MetaWindow *window)
     {
       MetaWindow *transient = tmp->data;
 
-      if (transient->xtransient_for == modal_transient->xwindow &&
+      if (transient->transient_for == modal_transient &&
           transient->wm_state_modal)
         {
           modal_transient = transient;
@@ -8506,7 +8499,7 @@ recalc_window_type (MetaWindow *window)
             XFree (atom_name);
         }
     }
-  else if (window->xtransient_for != None)
+  else if (window->transient_for != NULL)
     {
       window->type = META_WINDOW_DIALOG;
     }
@@ -8849,8 +8842,7 @@ recalc_window_features (MetaWindow *window)
     case META_WINDOW_MODAL_DIALOG:
       /* only skip taskbar if we have a real transient parent
          (and ignore the application hints) */
-      if (window->xtransient_for != None &&
-          window->xtransient_for != window->screen->xroot)
+      if (window->transient_for != NULL)
         window->skip_taskbar = TRUE;
       else
         window->skip_taskbar = FALSE;
@@ -10454,11 +10446,10 @@ meta_window_foreach_ancestor (MetaWindow            *window,
   w = window;
   do
     {
-      if (w->xtransient_for == None ||
-          w->transient_parent_is_root_window)
+      if (w->transient_for == NULL)
         break;
 
-      w = meta_display_lookup_x_window (w->display, w->xtransient_for);
+      w = w->transient_for;
     }
   while (w && (* func) (w, user_data));
 }
@@ -11281,7 +11272,9 @@ meta_window_get_transient_for (MetaWindow *window)
 {
   g_return_val_if_fail (META_IS_WINDOW (window), NULL);
 
-  if (window->xtransient_for)
+  if (window->transient_for)
+    return window->transient_for;
+  else if (window->xtransient_for)
     return meta_display_lookup_x_window (window->display,
                                          window->xtransient_for);
   else
@@ -11686,3 +11679,55 @@ meta_window_set_gtk_dbus_properties (MetaWindow *window,
 
   g_object_thaw_notify (G_OBJECT (window));
 }
+
+void
+meta_window_set_transient_for (MetaWindow *window,
+                               MetaWindow *parent)
+{
+  if (meta_window_appears_focused (window) && window->transient_for != None)
+    meta_window_propagate_focus_appearance (window, FALSE);
+
+  /* may now be a dialog */
+  meta_window_recalc_window_type (window);
+
+  if (!window->constructing)
+    {
+      /* If the window attaches, detaches, or changes attached
+       * parents, we need to destroy the MetaWindow and let a new one
+       * be created (which happens as a side effect of
+       * meta_window_unmanage()). The condition below is correct
+       * because we know window->transient_for has changed.
+       */
+      if (window->attached || meta_window_should_attach_to_parent (window))
+        {
+          guint32 timestamp;
+
+          timestamp = meta_display_get_current_time_roundtrip (window->display);
+          meta_window_unmanage (window, timestamp);
+          return;
+        }
+    }
+
+  /* update stacking constraints */
+  if (!window->override_redirect)
+    meta_stack_update_transient (window->screen->stack, window);
+
+  /* We know this won't create a reference cycle because we check for loops */
+  g_clear_object (&window->transient_for);
+  window->transient_for = parent ? g_object_ref (parent) : NULL;
+
+  /* possibly change its group. We treat being a window's transient as
+   * equivalent to making it your group leader, to work around shortcomings
+   * in programs such as xmms-- see #328211.
+   */
+  if (window->xtransient_for != None &&
+      window->xgroup_leader != None &&
+      window->xtransient_for != window->xgroup_leader)
+    meta_window_group_leader_changed (window);
+
+  if (!window->constructing && !window->override_redirect)
+    meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
+
+  if (meta_window_appears_focused (window) && window->transient_for != None)
+    meta_window_propagate_focus_appearance (window, TRUE);
+}
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 329783f..ee4e7e9 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -712,13 +712,22 @@ shell_surface_set_transient (struct wl_client *client,
 {
   MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
   MetaWaylandSurface *surface = shell_surface->surface;
+  MetaWaylandSurface *parent_surface = wl_resource_get_user_data (parent);
   MetaWaylandCompositor *compositor = surface->compositor;
 
   /* NB: Surfaces from xwayland become managed based on X events. */
   if (client == compositor->xwayland_client)
     return;
 
-  ensure_surface_window (surface);
+  if (surface->window)
+    meta_window_set_transient_for (surface->window, parent_surface->window);
+  else
+    {
+      ensure_initial_state (surface);
+
+      surface->initial_state->initial_type = META_WAYLAND_SURFACE_TOPLEVEL;
+      surface->initial_state->transient_for = parent;
+    }
 }
 
 static void
@@ -1070,6 +1079,14 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
     default:
       g_assert_not_reached ();
     }
+
+  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 (initial->title)
     meta_window_set_title (window, initial->title);
 
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index a68f71f..dab4124 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -75,6 +75,7 @@ typedef enum {
 typedef struct
 {
   MetaWaylandSurfaceType initial_type;
+  struct wl_resource *transient_for;
 
   char *title;
   char *wm_class;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]