[metacity] Optionally attach modal dialogs



commit bbf76b6b413111b5af930b1fd5a74bab070d83bf
Author: Maxim Ermilov <zaspire rambler ru>
Date:   Sat Sep 27 17:43:54 2014 +0300

    Optionally attach modal dialogs
    
    Add a preference /apps/mutter/general/attach_modal_dialogs. When
    true, instead of having independent titlebars, modal dialogs appear
    attached to the titlebar of the parent window and are moved
    together with the parent window.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=612726
    
    NOTE: Patch copied from mutter and adapted for metacity.

 src/core/constraints.c                |   47 +++++++++++++++++++++
 src/core/display.c                    |   28 +++++++++++++
 src/core/frame.c                      |    2 +-
 src/core/prefs.c                      |   18 ++++++++
 src/core/window-private.h             |    2 +
 src/core/window.c                     |   72 +++++++++++++++++++++++++++++++++
 src/include/prefs.h                   |    2 +
 src/org.gnome.metacity.gschema.xml.in |    9 ++++
 8 files changed, 179 insertions(+), 1 deletions(-)
---
diff --git a/src/core/constraints.c b/src/core/constraints.c
index c783847..359a9f6 100644
--- a/src/core/constraints.c
+++ b/src/core/constraints.c
@@ -140,6 +140,10 @@ typedef struct
   GList  *usable_xinerama_region;
 } ConstraintInfo;
 
+static gboolean constrain_modal_dialog       (MetaWindow         *window,
+                                              ConstraintInfo     *info,
+                                              ConstraintPriority  priority,
+                                              gboolean            check_only);
 static gboolean constrain_maximization       (MetaWindow         *window,
                                               ConstraintInfo     *info,
                                               ConstraintPriority  priority,
@@ -213,6 +217,7 @@ typedef struct {
 } Constraint;
 
 static const Constraint all_constraints[] = {
+  {constrain_modal_dialog,       "constrain_modal_dialog"},
   {constrain_maximization,       "constrain_maximization"},
   {constrain_tiling,             "constrain_tiling"},
   {constrain_fullscreen,         "constrain_fullscreen"},
@@ -733,6 +738,48 @@ get_size_limits (const MetaWindow        *window,
 }
 
 static gboolean
+constrain_modal_dialog (MetaWindow         *window,
+                        ConstraintInfo     *info,
+                        ConstraintPriority  priority,
+                        gboolean            check_only)
+{
+  int x, y;
+  MetaWindow *parent = meta_window_get_transient_for (window);
+  gboolean constraint_already_satisfied;
+
+  if (!meta_prefs_get_attach_modal_dialogs ())
+    return TRUE;
+  if (window->type != META_WINDOW_MODAL_DIALOG || !parent || parent == window)
+    return TRUE;
+
+  x = parent->rect.x + (parent->rect.width / 2 - info->current.width / 2);
+  y = 0;
+  if (parent->frame)
+    {
+      MetaFrameGeometry fgeom;
+
+      x += parent->frame->rect.x;
+      y += parent->frame->rect.y;
+
+      meta_frame_calc_geometry (parent->frame, &fgeom);
+      y += fgeom.top_height;
+
+      y += info->fgeom->top_height;
+   }
+  else
+    y = parent->rect.y + info->fgeom->top_height;
+
+  constraint_already_satisfied = (x == info->current.x) && (y == info->current.y);
+
+  if (check_only || constraint_already_satisfied)
+    return constraint_already_satisfied;
+
+  info->current.y = y;
+  info->current.x = x;
+  return TRUE;
+}
+
+static gboolean
 constrain_maximization (MetaWindow         *window,
                         ConstraintInfo     *info,
                         ConstraintPriority  priority,
diff --git a/src/core/display.c b/src/core/display.c
index f407583..31f3b4a 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -4951,6 +4951,34 @@ prefs_changed_callback (MetaPreference pref,
       else
        disable_compositor (display);
     }
+  else if (pref == META_PREF_ATTACH_MODAL_DIALOGS)
+    {
+      MetaDisplay *display = data;
+      GSList *windows;
+      GSList *tmp;
+
+      windows = meta_display_list_windows (display);
+
+      for (tmp = windows; tmp != NULL; tmp = tmp->next)
+        {
+          MetaWindow *w = tmp->data;
+          MetaWindow *parent = meta_window_get_transient_for (w);
+          meta_window_recalc_features (w);
+
+          if (w->type == META_WINDOW_MODAL_DIALOG && parent && parent != w)
+            {
+              int x, y;
+              /* Forcing a call to move_resize() does two things: first, it handles
+               * resizing the dialog frame window to the correct size when we remove
+               * or add the decorations. Second, it will take care of positioning the
+               * dialog as "attached" to the parent when we turn the preference on
+               * via the constrain_modal_dialog() constraint.
+               **/
+              meta_window_get_position (w, &x, &y);
+              meta_window_move (w, FALSE, x, y);
+            }
+        }
+    }
 }
 
 void
diff --git a/src/core/frame.c b/src/core/frame.c
index b574948..4009294 100644
--- a/src/core/frame.c
+++ b/src/core/frame.c
@@ -265,7 +265,7 @@ meta_frame_get_flags (MetaFrame *frame)
   if (META_WINDOW_ALLOWS_VERTICAL_RESIZE (frame->window))
     flags |= META_FRAME_ALLOWS_VERTICAL_RESIZE;
   
-  if (frame->window->has_focus)
+  if (meta_window_appears_focused (frame->window))
     flags |= META_FRAME_HAS_FOCUS;
 
   if (frame->window->shaded)
diff --git a/src/core/prefs.c b/src/core/prefs.c
index a76fbc4..21ebb64 100644
--- a/src/core/prefs.c
+++ b/src/core/prefs.c
@@ -70,6 +70,7 @@ static MetaVirtualModifier mouse_button_mods = Mod1Mask;
 static GDesktopFocusMode focus_mode = G_DESKTOP_FOCUS_MODE_CLICK;
 static GDesktopFocusNewWindows focus_new_windows = G_DESKTOP_FOCUS_NEW_WINDOWS_SMART;
 static gboolean raise_on_click = TRUE;
+static gboolean attach_modal_dialogs = FALSE;
 static char* current_theme = NULL;
 static int num_workspaces = 4;
 static GDesktopTitlebarAction action_double_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE;
@@ -259,6 +260,14 @@ static MetaEnumPreference preferences_enum[] =
 static MetaBoolPreference preferences_bool[] =
   {
     {
+      { "attach-modal-dialogs",
+        SCHEMA_METACITY,
+        META_PREF_ATTACH_MODAL_DIALOGS
+      },
+      &attach_modal_dialogs,
+      TRUE,
+    },
+    {
       { "raise-on-click",
         SCHEMA_GENERAL,
         META_PREF_RAISE_ON_CLICK,
@@ -915,6 +924,12 @@ meta_prefs_get_focus_new_windows (void)
 }
 
 gboolean
+meta_prefs_get_attach_modal_dialogs (void)
+{
+  return attach_modal_dialogs;
+}
+
+gboolean
 meta_prefs_get_raise_on_click (void)
 {
   /* Force raise_on_click on for click-to-focus, as requested by Havoc
@@ -1353,6 +1368,9 @@ meta_preference_to_string (MetaPreference pref)
     case META_PREF_FOCUS_NEW_WINDOWS:
       return "FOCUS_NEW_WINDOWS";
 
+    case META_PREF_ATTACH_MODAL_DIALOGS:
+      return "ATTACH_MODAL_DIALOGS";
+
     case META_PREF_RAISE_ON_CLICK:
       return "RAISE_ON_CLICK";
       
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 30f410d..78bbafb 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -452,6 +452,8 @@ void        meta_window_update_fullscreen_monitors (MetaWindow    *window,
                                                     unsigned long  left,
                                                     unsigned long  right);
 
+gboolean    meta_window_appears_focused    (MetaWindow *window);
+
 /* args to move are window pos, not frame pos */
 void        meta_window_move               (MetaWindow  *window,
                                             gboolean     user_op,
diff --git a/src/core/window.c b/src/core/window.c
index 5c613d1..afcbfa3 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -3305,6 +3305,19 @@ send_sync_request (MetaWindow *window)
 }
 #endif
 
+static gboolean
+move_attached_dialog (MetaWindow *window,
+                      void       *data)
+{
+  MetaWindow *parent = meta_window_get_transient_for (window);
+
+  if (window->type == META_WINDOW_MODAL_DIALOG && parent && parent != window)
+    /* It ignores x,y for such a dialog */
+    meta_window_move (window, FALSE, 0, 0);
+
+  return FALSE;
+}
+
 static void
 meta_window_move_resize_internal (MetaWindow          *window,
                                   MetaMoveResizeFlags  flags,
@@ -3759,6 +3772,9 @@ meta_window_move_resize_internal (MetaWindow          *window,
    *      server-side size/pos of window->xwindow and frame->xwindow
    *   b) all constraints are obeyed by window->rect and frame->rect
    */
+
+  if (meta_prefs_get_attach_modal_dialogs ())
+    meta_window_foreach_transient (window, move_attached_dialog, NULL);
 }
 
 void
@@ -5389,6 +5405,23 @@ meta_window_client_message (MetaWindow *window,
   return FALSE;
 }
 
+static void
+check_ancestor_focus_appearance (MetaWindow *window)
+{
+  MetaWindow *parent = meta_window_get_transient_for (window);
+
+  if (!meta_prefs_get_attach_modal_dialogs ())
+    return;
+
+  if (window->type != META_WINDOW_MODAL_DIALOG || !parent || parent == window)
+    return;
+
+  if (parent->frame)
+    meta_frame_queue_draw (parent->frame);
+
+  check_ancestor_focus_appearance (parent);
+}
+
 gboolean
 meta_window_notify_focus (MetaWindow *window,
                           XEvent     *event)
@@ -5525,6 +5558,9 @@ meta_window_notify_focus (MetaWindow *window,
           if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK ||
               !meta_prefs_get_raise_on_click())
             meta_display_ungrab_focus_window_button (window->display, window);
+
+          /* parent window become active. */
+          check_ancestor_focus_appearance (window);
         }
     }
   else if (event->type == FocusOut ||
@@ -5551,6 +5587,10 @@ meta_window_notify_focus (MetaWindow *window,
           
           window->display->focus_window = NULL;
           window->has_focus = FALSE;
+
+          /* parent window become active. */
+          check_ancestor_focus_appearance (window);
+
           if (window->frame)
             meta_frame_queue_draw (window->frame);
 
@@ -6350,6 +6390,16 @@ recalc_window_features (MetaWindow *window)
   if (window->type == META_WINDOW_TOOLBAR)
     window->decorated = FALSE;
 
+  if (window->type == META_WINDOW_MODAL_DIALOG && meta_prefs_get_attach_modal_dialogs ())
+    {
+      MetaWindow *parent = meta_window_get_transient_for (window);
+      if (parent)
+        {
+          window->has_resize_func = FALSE;
+          window->border_only = TRUE;
+        }
+    }
+
   if (window->type == META_WINDOW_DESKTOP ||
       window->type == META_WINDOW_DOCK)
     window->always_sticky = TRUE;
@@ -8431,6 +8481,28 @@ meta_window_get_frame (MetaWindow *window)
   return window->frame;
 }
 
+static gboolean
+transient_has_focus (MetaWindow *window,
+                     void       *data)
+{
+  if (window->type == META_WINDOW_MODAL_DIALOG && meta_window_appears_focused (window))
+    *((gboolean *)data) = TRUE;
+
+  return FALSE;
+}
+
+gboolean
+meta_window_appears_focused (MetaWindow *window)
+{
+  if (!window->has_focus && meta_prefs_get_attach_modal_dialogs ())
+    {
+      gboolean focus = FALSE;
+      meta_window_foreach_transient (window, transient_has_focus, &focus);
+      return focus;
+    }
+  return window->has_focus;
+}
+
 gboolean
 meta_window_has_focus (MetaWindow *window)
 {
diff --git a/src/include/prefs.h b/src/include/prefs.h
index 33430c1..4125371 100644
--- a/src/include/prefs.h
+++ b/src/include/prefs.h
@@ -34,6 +34,7 @@ typedef enum
   META_PREF_MOUSE_BUTTON_MODS,
   META_PREF_FOCUS_MODE,
   META_PREF_FOCUS_NEW_WINDOWS,
+  META_PREF_ATTACH_MODAL_DIALOGS,
   META_PREF_RAISE_ON_CLICK,
   META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
   META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
@@ -88,6 +89,7 @@ guint                       meta_prefs_get_mouse_button_resize (void);
 guint                       meta_prefs_get_mouse_button_menu  (void);
 GDesktopFocusMode           meta_prefs_get_focus_mode         (void);
 GDesktopFocusNewWindows     meta_prefs_get_focus_new_windows  (void);
+gboolean                    meta_prefs_get_attach_modal_dialogs (void);
 gboolean                    meta_prefs_get_raise_on_click     (void);
 const char*                 meta_prefs_get_theme              (void);
 /* returns NULL if GTK default should be used */
diff --git a/src/org.gnome.metacity.gschema.xml.in b/src/org.gnome.metacity.gschema.xml.in
index 6b4eb0d..a19db9b 100644
--- a/src/org.gnome.metacity.gschema.xml.in
+++ b/src/org.gnome.metacity.gschema.xml.in
@@ -10,6 +10,15 @@
 
   <schema id="org.gnome.metacity" path="/org/gnome/metacity/"
           gettext-domain="@GETTEXT_PACKAGE@">
+    <key name="attach-modal-dialogs" type="b">
+      <default>false</default>
+      <_summary>Attach modal dialogs</_summary>
+      <_description>
+        When true, instead of having independent titlebars, modal dialogs
+        appear attached to the titlebar of the parent window and are moved
+        together with the parent window.
+      </_description>
+    </key>
     <key name="compositing-manager" type="b">
       <default>true</default>
       <_summary>Compositing Manager</_summary>


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