From c2ea650b3c484312c14f69b8b245ab117ef7c6e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 23 May 2014 23:14:51 +0200 Subject: [PATCH] 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 2297b5813..715be6f35 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 4847de6be..3855dd9fc 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 bbfa77e5f..f41393674 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 0db03d082..a0b4a1d4f 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 01f8bfa84..36d477eac 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 b6bf28bf5..5a0e58d8a 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 e224aa8be..30811a8df 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 91b711fa4..b09bc1f7d 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 a17af8109..164b8f68b 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;