GtkWindow: better app menu fallback for CSD

Do the menubutton for app menu fallback ourselves in GtkWindow
for the csd, non-custom titlebar case. This fits better with
the way we handle other title buttons. Themes have control
over the placement of this button by placing menu in the
decoration-button-layout style property.
This commit is contained in:
Matthias Clasen 2013-11-16 14:46:10 -05:00
parent cb24305f1b
commit 73b02933d0
3 changed files with 76 additions and 20 deletions

View File

@ -297,12 +297,10 @@ gtk_application_window_update_shell_shows_app_menu (GtkApplicationWindow *window
{ {
gboolean shown_by_shell; gboolean shown_by_shell;
gboolean shown_by_titlebar; gboolean shown_by_titlebar;
GtkWidget *titlebar;
g_object_get (settings, "gtk-shell-shows-app-menu", &shown_by_shell, NULL); g_object_get (settings, "gtk-shell-shows-app-menu", &shown_by_shell, NULL);
titlebar = _gtk_window_get_titlebar (GTK_WINDOW (window)); shown_by_titlebar = _gtk_window_titlebar_shows_app_menu (GTK_WINDOW (window));
shown_by_titlebar = GTK_IS_HEADER_BAR (titlebar) && gtk_header_bar_get_show_fallback_app_menu (GTK_HEADER_BAR (titlebar));
if (shown_by_shell || shown_by_titlebar) if (shown_by_shell || shown_by_titlebar)
{ {
@ -632,13 +630,12 @@ gtk_application_window_real_realize (GtkWidget *widget)
g_signal_connect (settings, "notify::gtk-shell-shows-menubar", g_signal_connect (settings, "notify::gtk-shell-shows-menubar",
G_CALLBACK (gtk_application_window_shell_shows_menubar_changed), window); G_CALLBACK (gtk_application_window_shell_shows_menubar_changed), window);
GTK_WIDGET_CLASS (gtk_application_window_parent_class)->realize (widget);
gtk_application_window_update_shell_shows_app_menu (window, settings); gtk_application_window_update_shell_shows_app_menu (window, settings);
gtk_application_window_update_shell_shows_menubar (window, settings); gtk_application_window_update_shell_shows_menubar (window, settings);
gtk_application_window_update_menubar (window); gtk_application_window_update_menubar (window);
GTK_WIDGET_CLASS (gtk_application_window_parent_class)
->realize (widget);
#ifdef GDK_WINDOWING_X11 #ifdef GDK_WINDOWING_X11
{ {
GdkWindow *gdkwindow; GdkWindow *gdkwindow;
@ -679,8 +676,7 @@ gtk_application_window_real_unrealize (GtkWidget *widget)
g_signal_handlers_disconnect_by_func (settings, gtk_application_window_shell_shows_app_menu_changed, widget); g_signal_handlers_disconnect_by_func (settings, gtk_application_window_shell_shows_app_menu_changed, widget);
g_signal_handlers_disconnect_by_func (settings, gtk_application_window_shell_shows_menubar_changed, widget); g_signal_handlers_disconnect_by_func (settings, gtk_application_window_shell_shows_menubar_changed, widget);
GTK_WIDGET_CLASS (gtk_application_window_parent_class) GTK_WIDGET_CLASS (gtk_application_window_parent_class)->unrealize (widget);
->unrealize (widget);
} }
gboolean gboolean

View File

@ -157,6 +157,7 @@ struct _GtkWindowPrivate
GtkWidget *title_box; GtkWidget *title_box;
GtkWidget *titlebar; GtkWidget *titlebar;
GtkWidget *titlebar_icon; GtkWidget *titlebar_icon;
GtkWidget *titlebar_menu_button;
GtkWidget *titlebar_min_button; GtkWidget *titlebar_min_button;
GtkWidget *titlebar_max_button; GtkWidget *titlebar_max_button;
GtkWidget *titlebar_close_button; GtkWidget *titlebar_close_button;
@ -1068,7 +1069,7 @@ gtk_window_class_init (GtkWindowClass *klass)
g_param_spec_string ("decoration-button-layout", g_param_spec_string ("decoration-button-layout",
P_("Decorated button layout"), P_("Decorated button layout"),
P_("Decorated button layout"), P_("Decorated button layout"),
":close", "menu:close",
GTK_PARAM_READABLE)); GTK_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class, gtk_widget_class_install_style_property (widget_class,
@ -3473,6 +3474,7 @@ unset_titlebar (GtkWindow *window)
priv->title_box = NULL; priv->title_box = NULL;
priv->titlebar = NULL; priv->titlebar = NULL;
priv->titlebar_icon = NULL; priv->titlebar_icon = NULL;
priv->titlebar_menu_button = NULL;
priv->titlebar_min_button = NULL; priv->titlebar_min_button = NULL;
priv->titlebar_max_button = NULL; priv->titlebar_max_button = NULL;
priv->titlebar_close_button = NULL; priv->titlebar_close_button = NULL;
@ -3579,10 +3581,18 @@ gtk_window_set_titlebar (GtkWindow *window,
gtk_widget_queue_resize (widget); gtk_widget_queue_resize (widget);
} }
GtkWidget * gboolean
_gtk_window_get_titlebar (GtkWindow *window) _gtk_window_titlebar_shows_app_menu (GtkWindow *window)
{ {
return window->priv->title_box; GtkWindowPrivate *priv = window->priv;
if (priv->titlebar_menu_button)
return TRUE;
if (GTK_IS_HEADER_BAR (priv->title_box))
return gtk_header_bar_get_show_fallback_app_menu (GTK_HEADER_BAR (priv->title_box));
return FALSE;
} }
/** /**
@ -3811,12 +3821,18 @@ set_titlebar_icon (GtkWindow *window, GList *list)
{ {
GdkPixbuf *pixbuf, *best; GdkPixbuf *pixbuf, *best;
GList *l; GList *l;
gint size;
if (GTK_IS_BUTTON (gtk_widget_get_parent (priv->titlebar_icon)))
size = 16;
else
size = 20;
best = NULL; best = NULL;
for (l = list; l; l = l->next) for (l = list; l; l = l->next)
{ {
pixbuf = list->data; pixbuf = list->data;
if (gdk_pixbuf_get_width (pixbuf) <= 20) if (gdk_pixbuf_get_width (pixbuf) <= size)
{ {
best = g_object_ref (pixbuf); best = g_object_ref (pixbuf);
break; break;
@ -3824,7 +3840,7 @@ set_titlebar_icon (GtkWindow *window, GList *list)
} }
if (best == NULL) if (best == NULL)
best = gdk_pixbuf_scale_simple (GDK_PIXBUF (list->data), 20, 20, GDK_INTERP_BILINEAR); best = gdk_pixbuf_scale_simple (GDK_PIXBUF (list->data), size, size, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf (GTK_IMAGE (priv->titlebar_icon), best); gtk_image_set_from_pixbuf (GTK_IMAGE (priv->titlebar_icon), best);
g_object_unref (best); g_object_unref (best);
@ -5127,6 +5143,8 @@ update_window_buttons (GtkWindow *window)
gchar **tokens, **t; gchar **tokens, **t;
gint i, j; gint i, j;
GdkPixbuf *icon = NULL; GdkPixbuf *icon = NULL;
GMenuModel *menu;
gboolean shown_by_shell;
if (priv->title_box == NULL) if (priv->title_box == NULL)
return; return;
@ -5155,6 +5173,11 @@ update_window_buttons (GtkWindow *window)
gtk_widget_destroy (priv->titlebar_icon); gtk_widget_destroy (priv->titlebar_icon);
priv->titlebar_icon = NULL; priv->titlebar_icon = NULL;
} }
if (priv->titlebar_menu_button)
{
gtk_widget_destroy (priv->titlebar_menu_button);
priv->titlebar_menu_button = NULL;
}
if (priv->titlebar_min_button) if (priv->titlebar_min_button)
{ {
gtk_widget_destroy (priv->titlebar_min_button); gtk_widget_destroy (priv->titlebar_min_button);
@ -5175,6 +5198,14 @@ update_window_buttons (GtkWindow *window)
"decoration-button-layout", &layout_desc, "decoration-button-layout", &layout_desc,
NULL); NULL);
g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)),
"gtk-shell-shows-app-menu", &shown_by_shell, NULL);
if (!shown_by_shell && priv->application)
menu = gtk_application_get_app_menu (priv->application);
else
menu = NULL;
tokens = g_strsplit (layout_desc, ":", 2); tokens = g_strsplit (layout_desc, ":", 2);
if (tokens) if (tokens)
{ {
@ -5211,15 +5242,30 @@ update_window_buttons (GtkWindow *window)
gtk_widget_set_size_request (button, 20, 20); gtk_widget_set_size_request (button, 20, 20);
gtk_widget_show (button); gtk_widget_show (button);
if (icon != NULL) if (icon != NULL)
{
gtk_image_set_from_pixbuf (GTK_IMAGE (button), icon); gtk_image_set_from_pixbuf (GTK_IMAGE (button), icon);
g_object_unref (icon);
}
else else
gtk_widget_hide (button); gtk_widget_hide (button);
priv->titlebar_icon = button; priv->titlebar_icon = button;
} }
else if (strcmp (t[j], "menu") == 0 && menu != NULL)
{
button = gtk_menu_button_new ();
gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button), menu);
gtk_style_context_add_class (gtk_widget_get_style_context (button), "titlebutton");
if (icon != NULL)
image = gtk_image_new_from_pixbuf (icon);
else
image = gtk_image_new_from_icon_name ("process-stop-symbolic", GTK_ICON_SIZE_MENU);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_set_can_focus (button, FALSE);
gtk_widget_show_all (button);
accessible = gtk_widget_get_accessible (button);
if (GTK_IS_ACCESSIBLE (accessible))
atk_object_set_name (accessible, _("Application menu"));
priv->titlebar_icon = image;
priv->titlebar_menu_button = button;
}
else if (strcmp (t[j], "minimize") == 0 && else if (strcmp (t[j], "minimize") == 0 &&
priv->gdk_type_hint == GDK_WINDOW_TYPE_HINT_NORMAL) priv->gdk_type_hint == GDK_WINDOW_TYPE_HINT_NORMAL)
{ {
@ -5285,6 +5331,8 @@ update_window_buttons (GtkWindow *window)
g_strfreev (tokens); g_strfreev (tokens);
} }
g_free (layout_desc); g_free (layout_desc);
if (icon)
g_object_unref (icon);
} }
static GtkWidget * static GtkWidget *
@ -5297,7 +5345,9 @@ create_titlebar (GtkWindow *window)
gchar *title; gchar *title;
titlebar = gtk_header_bar_new (); titlebar = gtk_header_bar_new ();
g_object_set (titlebar, "spacing", 0, NULL); g_object_set (titlebar,
"spacing", 0,
NULL);
context = gtk_widget_get_style_context (titlebar); context = gtk_widget_get_style_context (titlebar);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_TITLEBAR); gtk_style_context_add_class (context, GTK_STYLE_CLASS_TITLEBAR);
gtk_style_context_add_class (context, "default-decoration"); gtk_style_context_add_class (context, "default-decoration");
@ -11687,3 +11737,10 @@ _gtk_window_handle_button_press_for_widget (GtkWidget *widget,
return FALSE; return FALSE;
} }
void
_gtk_window_get_decoration_size (GtkWindow *window,
GtkBorder *border)
{
get_decoration_size (window, border);
}

View File

@ -87,7 +87,10 @@ void _gtk_window_schedule_mnemonics_visible (GtkWindow *window);
void _gtk_window_notify_keys_changed (GtkWindow *window); void _gtk_window_notify_keys_changed (GtkWindow *window);
GtkWidget *_gtk_window_get_titlebar (GtkWindow *window); gboolean _gtk_window_titlebar_shows_app_menu (GtkWindow *window);
void _gtk_window_get_decoration_size (GtkWindow *window,
GtkBorder *border);
G_END_DECLS G_END_DECLS