[mutter] Add support for app-menu button in window decorations



commit c2ea650b3c484312c14f69b8b245ab117ef7c6e1
Author: Florian Müllner <fmuellner gnome org>
Date:   Fri May 23 23:14:51 2014 +0200

    Add support for app-menu button in window decorations
    
    We want to synchronize the button layouts of our server side
    decorations and GTK+'s client side ones. However each currently
    may contain buttons not supported by the other, which makes this
    unnecessarily tricky.
    So add support for a new "appmenu" button in the layout, to display
    the fallback app menu in the decorations.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=730752

 src/core/frame.c       |    4 ++
 src/core/prefs.c       |   75 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/meta/common.h      |   41 ++++++++++++++------------
 src/meta/prefs.h       |    1 +
 src/ui/frames.c        |   12 +++++++
 src/ui/frames.h        |    1 +
 src/ui/theme-parser.c  |    2 +-
 src/ui/theme-private.h |    2 +
 src/ui/theme.c         |   27 ++++++++++++++++-
 9 files changed, 144 insertions(+), 21 deletions(-)
---
diff --git a/src/core/frame.c b/src/core/frame.c
index 2297b58..715be6f 100644
--- a/src/core/frame.c
+++ b/src/core/frame.c
@@ -250,6 +250,10 @@ meta_frame_get_flags (MetaFrame *frame)
     {
       flags |= META_FRAME_ALLOWS_MENU;
 
+      if (meta_prefs_get_show_fallback_app_menu () &&
+          frame->window->gtk_app_menu_object_path)
+        flags |= META_FRAME_ALLOWS_APPMENU;
+
       if (frame->window->has_close_func)
         flags |= META_FRAME_ALLOWS_DELETE;
 
diff --git a/src/core/prefs.c b/src/core/prefs.c
index 4847de6..3855dd9 100644
--- a/src/core/prefs.c
+++ b/src/core/prefs.c
@@ -55,6 +55,7 @@
 #define KEY_GNOME_CURSOR_THEME "cursor-theme"
 #define KEY_GNOME_CURSOR_SIZE "cursor-size"
 #define KEY_XKB_OPTIONS "xkb-options"
+#define KEY_XSETTINGS_OVERRIDES "overrides"
 
 #define KEY_OVERLAY_KEY "overlay-key"
 #define KEY_WORKSPACES_ONLY_ON_PRIMARY "workspaces-only-on-primary"
@@ -65,6 +66,7 @@
 #define SCHEMA_MUTTER          "org.gnome.mutter"
 #define SCHEMA_INTERFACE       "org.gnome.desktop.interface"
 #define SCHEMA_INPUT_SOURCES   "org.gnome.desktop.input-sources"
+#define SCHEMA_XSETTINGS       "org.gnome.settings-daemon.plugins.xsettings"
 
 #define SETTINGS(s) g_hash_table_lookup (settings_schemas, (s))
 
@@ -104,6 +106,7 @@ static gboolean edge_tiling = FALSE;
 static gboolean force_fullscreen = TRUE;
 static gboolean ignore_request_hide_titlebar = FALSE;
 static gboolean auto_maximize = TRUE;
+static gboolean show_fallback_app_menu = FALSE;
 
 static GDesktopVisualBellType visual_bell_type = G_DESKTOP_VISUAL_BELL_FULLSCREEN_FLASH;
 static MetaButtonLayout button_layout;
@@ -129,6 +132,10 @@ static void bindings_changed (GSettings      *settings,
                               gchar          *key,
                               gpointer        data);
 
+static void xsettings_overrides_changed (GSettings  *settings,
+                                         gchar      *key,
+                                         gpointer    data);
+
 static void queue_changed (MetaPreference  pref);
 
 static void maybe_give_disable_workarounds_warning (void);
@@ -936,6 +943,24 @@ queue_changed (MetaPreference pref)
 /* Initialisation.                                                          */
 /****************************************************************************/
 
+static GSettings *
+get_xsettings_settings (void)
+{
+  GSettings *settings = NULL;
+  GSettingsSchema *schema;
+
+  schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
+                                            SCHEMA_XSETTINGS, FALSE);
+
+  if (schema)
+    {
+      settings = g_settings_new_full (schema, NULL, NULL);
+      g_settings_schema_unref (schema);
+    }
+
+  return settings;
+}
+
 void
 meta_prefs_init (void)
 {
@@ -965,6 +990,16 @@ meta_prefs_init (void)
                     G_CALLBACK (settings_changed), NULL);
   g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_INTERFACE), settings);
 
+  settings = get_xsettings_settings ();
+  if (settings)
+    {
+      g_signal_connect (settings, "changed::" KEY_XSETTINGS_OVERRIDES,
+                        G_CALLBACK (xsettings_overrides_changed), NULL);
+      g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_XSETTINGS), settings);
+
+      xsettings_overrides_changed (settings, KEY_XSETTINGS_OVERRIDES, NULL);
+    }
+
   settings = g_settings_new (SCHEMA_INPUT_SOURCES);
   g_signal_connect (settings, "changed::" KEY_XKB_OPTIONS,
                     G_CALLBACK (settings_changed), NULL);
@@ -1184,6 +1219,38 @@ bindings_changed (GSettings *settings,
   g_strfreev (strokes);
 }
 
+/* The fallback app menu should be enabled if either we are not
+ * showing the app menu (e.g. when using the default plugin) or
+ * with a corresponding XSettings override; we ignore the former
+ * and assume that we always show the app menu, not least
+ * because we rely on the compositor implementation to display
+ * the fallback ...
+ */
+static void
+xsettings_overrides_changed (GSettings  *settings,
+                             gchar      *key,
+                             gpointer    data)
+{
+  GVariant *value;
+  GVariantDict overrides;
+  int shell_shows_app_menu = 1;
+
+  if (!g_settings_get_boolean (settings, "active"))
+    goto out;
+
+  value = g_settings_get_value (settings, KEY_XSETTINGS_OVERRIDES);
+
+  g_variant_dict_init (&overrides, value);
+  g_variant_unref (value);
+
+  g_variant_dict_lookup (&overrides,
+                         "Gtk/ShellShowsAppMenu", "i", &shell_shows_app_menu);
+  g_variant_dict_clear (&overrides);
+
+out:
+  show_fallback_app_menu = !shell_shows_app_menu;
+}
+
 /**
  * maybe_give_disable_workaround_warning:
  *
@@ -1243,6 +1310,12 @@ meta_prefs_get_raise_on_click (void)
   return raise_on_click || focus_mode == G_DESKTOP_FOCUS_MODE_CLICK;
 }
 
+gboolean
+meta_prefs_get_show_fallback_app_menu (void)
+{
+  return show_fallback_app_menu;
+}
+
 const char*
 meta_prefs_get_theme (void)
 {
@@ -1398,6 +1471,8 @@ button_function_from_string (const char *str)
 {
   if (strcmp (str, "menu") == 0)
     return META_BUTTON_FUNCTION_MENU;
+  else if (strcmp (str, "appmenu") == 0)
+    return META_BUTTON_FUNCTION_APPMENU;
   else if (strcmp (str, "minimize") == 0)
     return META_BUTTON_FUNCTION_MINIMIZE;
   else if (strcmp (str, "maximize") == 0)
diff --git a/src/meta/common.h b/src/meta/common.h
index bbfa77e..f413936 100644
--- a/src/meta/common.h
+++ b/src/meta/common.h
@@ -49,6 +49,7 @@ typedef struct _MetaResizePopup MetaResizePopup;
  * MetaFrameFlags:
  * @META_FRAME_ALLOWS_DELETE: frame allows delete
  * @META_FRAME_ALLOWS_MENU: frame allows menu
+ * @META_FRAME_ALLOWS_APPMENU: frame allows (fallback) app menu
  * @META_FRAME_ALLOWS_MINIMIZE: frame allows minimize
  * @META_FRAME_ALLOWS_MAXIMIZE: frame allows maximize
  * @META_FRAME_ALLOWS_VERTICAL_RESIZE: frame allows vertical resize
@@ -69,21 +70,22 @@ typedef enum
 {
   META_FRAME_ALLOWS_DELETE            = 1 << 0,
   META_FRAME_ALLOWS_MENU              = 1 << 1,
-  META_FRAME_ALLOWS_MINIMIZE          = 1 << 2,
-  META_FRAME_ALLOWS_MAXIMIZE          = 1 << 3,
-  META_FRAME_ALLOWS_VERTICAL_RESIZE   = 1 << 4,
-  META_FRAME_ALLOWS_HORIZONTAL_RESIZE = 1 << 5,
-  META_FRAME_HAS_FOCUS                = 1 << 6,
-  META_FRAME_SHADED                   = 1 << 7,
-  META_FRAME_STUCK                    = 1 << 8,
-  META_FRAME_MAXIMIZED                = 1 << 9,
-  META_FRAME_ALLOWS_SHADE             = 1 << 10,
-  META_FRAME_ALLOWS_MOVE              = 1 << 11,
-  META_FRAME_FULLSCREEN               = 1 << 12,
-  META_FRAME_IS_FLASHING              = 1 << 13,
-  META_FRAME_ABOVE                    = 1 << 14,
-  META_FRAME_TILED_LEFT               = 1 << 15,
-  META_FRAME_TILED_RIGHT              = 1 << 16
+  META_FRAME_ALLOWS_APPMENU           = 1 << 2,
+  META_FRAME_ALLOWS_MINIMIZE          = 1 << 3,
+  META_FRAME_ALLOWS_MAXIMIZE          = 1 << 4,
+  META_FRAME_ALLOWS_VERTICAL_RESIZE   = 1 << 5,
+  META_FRAME_ALLOWS_HORIZONTAL_RESIZE = 1 << 6,
+  META_FRAME_HAS_FOCUS                = 1 << 7,
+  META_FRAME_SHADED                   = 1 << 8,
+  META_FRAME_STUCK                    = 1 << 9,
+  META_FRAME_MAXIMIZED                = 1 << 10,
+  META_FRAME_ALLOWS_SHADE             = 1 << 11,
+  META_FRAME_ALLOWS_MOVE              = 1 << 12,
+  META_FRAME_FULLSCREEN               = 1 << 13,
+  META_FRAME_IS_FLASHING              = 1 << 14,
+  META_FRAME_ABOVE                    = 1 << 15,
+  META_FRAME_TILED_LEFT               = 1 << 16,
+  META_FRAME_TILED_RIGHT              = 1 << 17
 } MetaFrameFlags;
 
 /**
@@ -359,6 +361,7 @@ typedef enum
   META_BUTTON_FUNCTION_UNSHADE,
   META_BUTTON_FUNCTION_UNABOVE,
   META_BUTTON_FUNCTION_UNSTICK,
+  META_BUTTON_FUNCTION_APPMENU,
   META_BUTTON_FUNCTION_LAST
 } MetaButtonFunction;
 
@@ -367,10 +370,10 @@ typedef enum
 /* Keep array size in sync with MAX_BUTTONS_PER_CORNER */
 /**
  * MetaButtonLayout:
- * @left_buttons: (array fixed-size=10):
- * @right_buttons: (array fixed-size=10):
- * @left_buttons_has_spacer: (array fixed-size=10):
- * @right_buttons_has_spacer: (array fixed-size=10):
+ * @left_buttons: (array fixed-size=11):
+ * @right_buttons: (array fixed-size=11):
+ * @left_buttons_has_spacer: (array fixed-size=11):
+ * @right_buttons_has_spacer: (array fixed-size=11):
  */
 typedef struct _MetaButtonLayout MetaButtonLayout;
 struct _MetaButtonLayout
diff --git a/src/meta/prefs.h b/src/meta/prefs.h
index 0db03d0..a0b4a1d 100644
--- a/src/meta/prefs.h
+++ b/src/meta/prefs.h
@@ -141,6 +141,7 @@ gboolean                    meta_prefs_get_gnome_animations   (void);
 gboolean                    meta_prefs_get_edge_tiling        (void);
 gboolean                    meta_prefs_get_auto_maximize      (void);
 gboolean                    meta_prefs_get_center_new_windows (void);
+gboolean                    meta_prefs_get_show_fallback_app_menu (void);
 
 void                        meta_prefs_get_button_layout (MetaButtonLayout *button_layout);
 
diff --git a/src/ui/frames.c b/src/ui/frames.c
index 01f8bfa..36d477e 100644
--- a/src/ui/frames.c
+++ b/src/ui/frames.c
@@ -1425,6 +1425,8 @@ meta_frames_update_prelit_control (MetaFrames      *frames,
       break;
     case META_FRAME_CONTROL_MENU:
       break;
+    case META_FRAME_CONTROL_APPMENU:
+      break;
     case META_FRAME_CONTROL_MINIMIZE:
       break;
     case META_FRAME_CONTROL_MAXIMIZE:
@@ -1477,6 +1479,7 @@ meta_frames_update_prelit_control (MetaFrames      *frames,
   switch (control)
     {
     case META_FRAME_CONTROL_MENU:
+    case META_FRAME_CONTROL_APPMENU:
     case META_FRAME_CONTROL_MINIMIZE:
     case META_FRAME_CONTROL_MAXIMIZE:
     case META_FRAME_CONTROL_DELETE:
@@ -1796,6 +1799,9 @@ meta_frames_paint (MetaFrames   *frames,
     case META_FRAME_CONTROL_MENU:
       button_type = META_BUTTON_TYPE_MENU;
       break;
+    case META_FRAME_CONTROL_APPMENU:
+      button_type = META_BUTTON_TYPE_APPMENU;
+      break;
     case META_FRAME_CONTROL_MINIMIZE:
       button_type = META_BUTTON_TYPE_MINIMIZE;
       break;
@@ -1961,6 +1967,9 @@ control_rect (MetaFrameControl control,
     case META_FRAME_CONTROL_MENU:
       rect = &fgeom->menu_rect.visible;
       break;
+    case META_FRAME_CONTROL_APPMENU:
+      rect = &fgeom->appmenu_rect.visible;
+      break;
     case META_FRAME_CONTROL_MINIMIZE:
       rect = &fgeom->min_rect.visible;
       break;
@@ -2040,6 +2049,9 @@ get_control (MetaFrames *frames,
   if (POINT_IN_RECT (x, y, fgeom.menu_rect.clickable))
     return META_FRAME_CONTROL_MENU;
 
+  if (POINT_IN_RECT (x, y, fgeom.appmenu_rect.clickable))
+    return META_FRAME_CONTROL_APPMENU;
+
   meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
                  frame->xwindow,
                  META_CORE_GET_FRAME_FLAGS, &flags,
diff --git a/src/ui/frames.h b/src/ui/frames.h
index b6bf28b..5a0e58d 100644
--- a/src/ui/frames.h
+++ b/src/ui/frames.h
@@ -33,6 +33,7 @@ typedef enum
   META_FRAME_CONTROL_TITLE,
   META_FRAME_CONTROL_DELETE,
   META_FRAME_CONTROL_MENU,
+  META_FRAME_CONTROL_APPMENU,
   META_FRAME_CONTROL_MINIMIZE,
   META_FRAME_CONTROL_MAXIMIZE,
   META_FRAME_CONTROL_UNMAXIMIZE,
diff --git a/src/ui/theme-parser.c b/src/ui/theme-parser.c
index e224aa8..30811a8 100644
--- a/src/ui/theme-parser.c
+++ b/src/ui/theme-parser.c
@@ -36,7 +36,7 @@
  * look out for.
  */
 #define THEME_MAJOR_VERSION 3
-#define THEME_MINOR_VERSION 4
+#define THEME_MINOR_VERSION 5
 #define THEME_VERSION (1000 * THEME_MAJOR_VERSION + THEME_MINOR_VERSION)
 
 #define METACITY_THEME_FILENAME_FORMAT "metacity-theme-%d.xml"
diff --git a/src/ui/theme-private.h b/src/ui/theme-private.h
index 91b711f..b09bc1f 100644
--- a/src/ui/theme-private.h
+++ b/src/ui/theme-private.h
@@ -236,6 +236,7 @@ struct _MetaFrameGeometry
   MetaButtonSpace max_rect;
   MetaButtonSpace min_rect;
   MetaButtonSpace menu_rect;
+  MetaButtonSpace appmenu_rect;
   MetaButtonSpace shade_rect;
   MetaButtonSpace above_rect;
   MetaButtonSpace stick_rect;
@@ -658,6 +659,7 @@ typedef enum
   META_BUTTON_TYPE_MAXIMIZE,
   META_BUTTON_TYPE_MINIMIZE,
   META_BUTTON_TYPE_MENU,
+  META_BUTTON_TYPE_APPMENU,
   META_BUTTON_TYPE_SHADE,
   META_BUTTON_TYPE_ABOVE,
   META_BUTTON_TYPE_STICK,
diff --git a/src/ui/theme.c b/src/ui/theme.c
index a17af81..164b8f6 100644
--- a/src/ui/theme.c
+++ b/src/ui/theme.c
@@ -454,6 +454,8 @@ map_button_function_to_type (MetaButtonFunction  function)
       return META_BUTTON_TYPE_UNSTICK;
     case META_BUTTON_FUNCTION_MENU:
       return META_BUTTON_TYPE_MENU;
+    case META_BUTTON_FUNCTION_APPMENU:
+      return META_BUTTON_TYPE_APPMENU;
     case META_BUTTON_FUNCTION_MINIMIZE:
       return META_BUTTON_TYPE_MINIMIZE;
     case META_BUTTON_FUNCTION_MAXIMIZE:
@@ -522,6 +524,11 @@ rect_for_function (MetaFrameGeometry *fgeom,
         return &fgeom->menu_rect;
       else
         return NULL;
+    case META_BUTTON_FUNCTION_APPMENU:
+      if (flags & META_FRAME_ALLOWS_APPMENU)
+        return &fgeom->appmenu_rect;
+      else
+        return NULL;
     case META_BUTTON_FUNCTION_MINIMIZE:
       if (flags & META_FRAME_ALLOWS_MINIMIZE)
         return &fgeom->min_rect;
@@ -823,6 +830,12 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout  *layout,
       else if (strip_button (left_func_rects, left_bg_rects,
                              &n_left, &fgeom->menu_rect))
         continue;
+      else if (strip_button (right_func_rects, right_bg_rects,
+                             &n_right, &fgeom->appmenu_rect))
+        continue;
+      else if (strip_button (left_func_rects, left_bg_rects,
+                             &n_left, &fgeom->appmenu_rect))
+        continue;
       else
         {
           meta_bug ("Could not find a button to strip. n_left = %d n_right = %d\n",
@@ -4374,7 +4387,7 @@ map_button_state (MetaButtonType           button_type,
 
   switch (button_type)
     {
-    /* First hande functions, which map directly */
+    /* First handle functions, which map directly */
     case META_BUTTON_TYPE_SHADE:
     case META_BUTTON_TYPE_ABOVE:
     case META_BUTTON_TYPE_STICK:
@@ -4382,6 +4395,7 @@ map_button_state (MetaButtonType           button_type,
     case META_BUTTON_TYPE_UNABOVE:
     case META_BUTTON_TYPE_UNSTICK:
     case META_BUTTON_TYPE_MENU:
+    case META_BUTTON_TYPE_APPMENU:
     case META_BUTTON_TYPE_MINIMIZE:
     case META_BUTTON_TYPE_MAXIMIZE:
     case META_BUTTON_TYPE_CLOSE:
@@ -4588,6 +4602,10 @@ button_rect (MetaButtonType           type,
       *rect = fgeom->menu_rect.visible;
       break;
 
+    case META_BUTTON_TYPE_APPMENU:
+      *rect = fgeom->appmenu_rect.visible;
+      break;
+
     case META_BUTTON_TYPE_LAST:
       g_assert_not_reached ();
       break;
@@ -5971,6 +5989,8 @@ meta_button_type_from_string (const char *str, MetaTheme *theme)
     return META_BUTTON_TYPE_MINIMIZE;
   else if (strcmp ("menu", str) == 0)
     return META_BUTTON_TYPE_MENU;
+  else if (strcmp ("appmenu", str) == 0)
+    return META_BUTTON_TYPE_APPMENU;
   else if (strcmp ("left_left_background", str) == 0)
     return META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND;
   else if (strcmp ("left_middle_background", str) == 0)
@@ -6016,6 +6036,8 @@ meta_button_type_to_string (MetaButtonType type)
       return "unstick";
      case META_BUTTON_TYPE_MENU:
       return "menu";
+    case META_BUTTON_TYPE_APPMENU:
+      return "appmenu";
     case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
       return "left_left_background";
     case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
@@ -6796,6 +6818,9 @@ meta_theme_earliest_version_with_button (MetaButtonType type)
     case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
       return 3003;
 
+    case META_BUTTON_TYPE_APPMENU:
+      return 3005;
+
     default:
       meta_warning("Unknown button %d\n", type);
       return 1000;


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