diff --git a/gtk/Makefile.am b/gtk/Makefile.am index aad7bc7103..f84d23a2d4 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -183,6 +183,7 @@ gtk_public_h_sources = \ gtkappchooserwidget.h \ gtkapplication.h \ gtkapplicationwindow.h \ + gtkapplicationmenubutton.h \ gtkarrow.h \ gtkaspectframe.h \ gtkassistant.h \ @@ -532,6 +533,7 @@ gtk_base_c_sources = \ gtkappchooseronline.c \ gtkapplication.c \ gtkapplicationwindow.c \ + gtkapplicationmenubutton.c \ gtkanimationdescription.c \ gtkarrow.c \ gtkaspectframe.c \ diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index d6aa5e555a..b4fcf741cd 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -227,6 +227,8 @@ gtk_application_window_get_show_app_menu gtk_application_window_get_type gtk_application_window_new gtk_application_window_set_show_app_menu +gtk_application_menu_button_get_type +gtk_application_menu_button_new gtk_arrow_get_type gtk_arrow_new gtk_arrow_placement_get_type diff --git a/gtk/gtkapplicationmenubutton.c b/gtk/gtkapplicationmenubutton.c new file mode 100644 index 0000000000..cdfdbfd04f --- /dev/null +++ b/gtk/gtkapplicationmenubutton.c @@ -0,0 +1,209 @@ +/* + * Copyright © 2011 Canonical Ltd. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + * + * Author: Ryan Lortie + */ + +#include "config.h" + +#include "gtkapplicationmenubutton.h" + +#include "gtkapplicationwindow.h" +#include "gtkbutton.h" +#include "gtkmain.h" + +#include + +struct _GtkApplicationMenuButton +{ + GtkButton parent_instance; + + GtkSettings *settings; + + gboolean user_shown; + gboolean required; +}; + +typedef GtkButtonClass GtkApplicationMenuButtonClass; + +G_DEFINE_TYPE (GtkApplicationMenuButton, gtk_application_menu_button, GTK_TYPE_BUTTON) + +static void +gtk_application_menu_update_visibility (GtkApplicationMenuButton *amb) +{ + GtkWidget *widget = GTK_WIDGET (amb); + gboolean should_be_visible; + gboolean was_visible; + + should_be_visible = amb->user_shown && amb->required; + was_visible = gtk_widget_get_visible (widget); + + if (!was_visible && should_be_visible) + GTK_WIDGET_CLASS (gtk_application_menu_button_parent_class)->show (widget); + + else if (was_visible && !should_be_visible) + GTK_WIDGET_CLASS (gtk_application_menu_button_parent_class)->hide (widget); +} + +static void +gtk_application_menu_button_clicked (GtkButton *button) +{ + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button)); + if (toplevel != NULL && GTK_IS_APPLICATION_WINDOW (toplevel)) + { + GtkWidget *menu; + + menu = gtk_application_window_get_app_menu (GTK_APPLICATION_WINDOW (toplevel)); + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, + 1, gtk_get_current_event_time ()); + } +} + +static void +gtk_application_menu_button_show (GtkWidget *widget) +{ + GtkApplicationMenuButton *amb = GTK_APPLICATION_MENU_BUTTON (widget); + + amb->user_shown = TRUE; + + gtk_application_menu_update_visibility (amb); +} + +static void +gtk_application_menu_button_hide (GtkWidget *widget) +{ + GtkApplicationMenuButton *amb = GTK_APPLICATION_MENU_BUTTON (widget); + + amb->user_shown = FALSE; + + gtk_application_menu_update_visibility (amb); +} + +static void +gtk_application_menu_button_show_all (GtkWidget *widget) +{ + GtkApplicationMenuButton *amb = GTK_APPLICATION_MENU_BUTTON (widget); + + gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL); + amb->user_shown = TRUE; + + gtk_application_menu_update_visibility (amb); +} + +static void +gtk_application_menu_button_required_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + GtkApplicationMenuButton *amb = user_data; + gboolean required; + + g_object_get (object, "gtk-shell-shows-app-menu", &required, NULL); + required = !required; + + if (required != amb->required) + { + amb->required = required; + + gtk_application_menu_update_visibility (amb); + } +} + +static void +gtk_application_menu_button_screen_changed (GtkWidget *widget, + GdkScreen *old_screen) +{ + GtkApplicationMenuButton *amb = GTK_APPLICATION_MENU_BUTTON (widget); + GtkSettings *settings; + GdkScreen *screen; + + screen = gtk_widget_get_screen (widget); + settings = gtk_settings_get_for_screen (screen); + + if (settings != amb->settings) + { + if (amb->settings) + { + g_signal_handlers_disconnect_by_func (amb->settings, gtk_application_menu_button_required_changed, amb); + g_object_unref (amb->settings); + } + + amb->settings = g_object_ref (settings); + g_signal_connect (amb->settings, "notify::gtk-shell-shows-app-menu", + G_CALLBACK (gtk_application_menu_button_required_changed), amb); + gtk_application_menu_button_required_changed (G_OBJECT (settings), NULL, amb); + } +} + +static void +gtk_application_menu_button_hierarchy_changed (GtkWidget *widget, + GtkWidget *previous_toplevel) +{ + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (widget); + + if (toplevel != NULL && GTK_IS_APPLICATION_WINDOW (toplevel)) + gtk_application_window_set_show_app_menu (GTK_APPLICATION_WINDOW (toplevel), FALSE); +} + +static void +gtk_application_menu_button_finalize (GObject *object) +{ + GtkApplicationMenuButton *amb = GTK_APPLICATION_MENU_BUTTON (object); + + if (amb->settings) + { + g_signal_handlers_disconnect_by_func (amb->settings, gtk_application_menu_button_required_changed, amb); + g_object_unref (amb->settings); + } + + G_OBJECT_CLASS (gtk_application_menu_button_parent_class) + ->finalize (object); +} + +static void +gtk_application_menu_button_init (GtkApplicationMenuButton *menu) +{ +} + +static void +gtk_application_menu_button_class_init (GtkApplicationMenuButtonClass *class) +{ + GtkButtonClass *button_class = GTK_BUTTON_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + GObjectClass *object_class = G_OBJECT_CLASS (class); + + button_class->clicked = gtk_application_menu_button_clicked; + + widget_class->show = gtk_application_menu_button_show; + widget_class->show_all = gtk_application_menu_button_show_all; + widget_class->hide = gtk_application_menu_button_hide; + widget_class->screen_changed = gtk_application_menu_button_screen_changed; + widget_class->hierarchy_changed = gtk_application_menu_button_hierarchy_changed; + + object_class->finalize = gtk_application_menu_button_finalize; +} + +GtkWidget * +gtk_application_menu_button_new (void) +{ + return g_object_new (GTK_TYPE_APPLICATION_MENU_BUTTON, NULL); +} diff --git a/gtk/gtkapplicationmenubutton.h b/gtk/gtkapplicationmenubutton.h new file mode 100644 index 0000000000..9227c7abc4 --- /dev/null +++ b/gtk/gtkapplicationmenubutton.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2011 Canonical Ltd. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + * + * Author: Ryan Lortie + */ + +#ifndef __GTK_APPLICATION_MENU_BUTTON_H__ +#define __GTK_APPLICATION_MENU_BUTTON_H__ + +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_APPLICATION_MENU_BUTTON (gtk_application_menu_button_get_type ()) +#define GTK_APPLICATION_MENU_BUTTON(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ + GTK_TYPE_APPLICATION_MENU_BUTTON, \ + GtkApplicationMenuButton)) +#define GTK_IS_APPLICATION_MENU_BUTTON(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ + GTK_TYPE_APPLICATION_MENU_BUTTON)) + +typedef struct _GtkApplicationMenuButton GtkApplicationMenuButton; + +GType gtk_application_menu_button_get_type (void) G_GNUC_CONST; + +GtkWidget * gtk_application_menu_button_new (void); + +G_END_DECLS + +#endif /* __GTK_APPLICATION_MENU_BUTTON_H__ */