[gnome-keyring] gcr: Implement GcrMenuButton which is copied from gnome-contacts
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-keyring] gcr: Implement GcrMenuButton which is copied from gnome-contacts
- Date: Tue, 27 Sep 2011 15:15:22 +0000 (UTC)
commit f03758232bcd6ca38ec9e4852aa3f4f7501c1cff
Author: Stef Walter <stefw collabora co uk>
Date: Wed Sep 21 17:13:27 2011 +0200
gcr: Implement GcrMenuButton which is copied from gnome-contacts
* The standard clickable button which drops down a menu.
gcr/Makefile.am | 1 +
gcr/gcr-menu-button.c | 366 +++++++++++++++++++++++++++++++++++++++++++++++++
gcr/gcr-menu-button.h | 61 ++++++++
3 files changed, 428 insertions(+), 0 deletions(-)
---
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index 4d31f9a..6494bc5 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -107,6 +107,7 @@ libgcr_base_ GCR_MAJOR@_la_SOURCES = \
gcr-internal.h \
gcr-memory.c \
gcr-memory-icon.c gcr-memory-icon.h \
+ gcr-menu-button.c gcr-menu-button.h \
gcr-openpgp.c gcr-openpgp.h \
gcr-openssh.c gcr-openssh.h \
gcr-parser.c gcr-parser.h \
diff --git a/gcr/gcr-menu-button.c b/gcr/gcr-menu-button.c
new file mode 100644
index 0000000..abcbcfa
--- /dev/null
+++ b/gcr/gcr-menu-button.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2011 Alexander Larsson <alexl redhat com>
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#include "config.h"
+
+#include "gcr-menu-button.h"
+
+enum {
+ PROP_0,
+ PROP_LABEL,
+ PROP_MENU
+};
+
+struct _GcrMenuButtonPrivate {
+ GtkMenu *menu;
+ gboolean popup_in_progress;
+ gchar *label;
+};
+
+G_DEFINE_TYPE (GcrMenuButton, _gcr_menu_button, GTK_TYPE_TOGGLE_BUTTON);
+
+static void
+_gcr_menu_button_init (GcrMenuButton *self)
+{
+ self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_MENU_BUTTON,
+ GcrMenuButtonPrivate));
+}
+
+static void
+_gcr_menu_button_constructed (GObject *obj)
+{
+ GcrMenuButton *self = GCR_MENU_BUTTON (obj);
+ GtkWidget *label_widget;
+ GtkWidget *arrow;
+ GtkWidget *grid;
+
+ G_OBJECT_CLASS (_gcr_menu_button_parent_class)->constructed (obj);
+
+ gtk_button_set_focus_on_click (GTK_BUTTON (self), FALSE);
+
+ label_widget = gtk_label_new (self->pv->label);
+ arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+ grid = gtk_grid_new ();
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_HORIZONTAL);
+ gtk_container_add (GTK_CONTAINER (grid), label_widget);
+ gtk_container_add (GTK_CONTAINER (grid), arrow);
+ gtk_grid_set_row_spacing (GTK_GRID (grid), 3);
+ gtk_widget_set_hexpand (grid, TRUE);
+ gtk_widget_set_halign (grid, GTK_ALIGN_CENTER);
+
+ gtk_container_add (GTK_CONTAINER (self), grid);
+}
+
+static void
+_gcr_menu_button_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GcrMenuButton *self = GCR_MENU_BUTTON (obj);
+
+ switch (prop_id) {
+ case PROP_MENU:
+ g_value_set_object (value, _gcr_menu_button_get_menu (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gcr_menu_button_set_property (GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GcrMenuButton *self = GCR_MENU_BUTTON (obj);
+
+ switch (prop_id) {
+ case PROP_LABEL:
+ self->pv->label = g_value_dup_string (value);
+ break;
+ case PROP_MENU:
+ _gcr_menu_button_set_menu (self, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gcr_menu_button_finalize (GObject *obj)
+{
+ GcrMenuButton *self = GCR_MENU_BUTTON (obj);
+
+ _gcr_menu_button_set_menu (self, NULL);
+ g_free (self->pv->label);
+
+ G_OBJECT_CLASS (_gcr_menu_button_parent_class)->finalize (obj);
+}
+
+
+static void
+on_menu_position (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ GcrMenuButton *self = GCR_MENU_BUTTON (user_data);
+ GtkWidget *widget = GTK_WIDGET (self);
+ GtkAllocation allocation;
+ GtkRequisition menu_req;
+ GdkRectangle monitor;
+ GdkWindow *window;
+ GtkWidget *toplevel;
+ GdkScreen *screen;
+ gint monitor_num;
+ gint sx = 0;
+ gint sy = 0;
+
+ g_return_if_fail (x != NULL);
+ g_return_if_fail (y != NULL);
+ g_return_if_fail (push_in != NULL);
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ if (!gtk_widget_get_has_window (widget)) {
+ sx += allocation.x;
+ sy += allocation.y;
+ }
+
+ window = gtk_widget_get_window (widget);
+ gdk_window_get_root_coords (window, sx, sy, &sx, &sy);
+
+ gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &menu_req);
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+ *x = sx;
+ else
+ *x = sx + allocation.width - menu_req.width;
+ *y = sy;
+
+ screen = gtk_widget_get_screen (widget);
+ monitor_num = gdk_screen_get_monitor_at_window (screen, window);
+ if (monitor_num < 0)
+ monitor_num = 0;
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+ if (*x < monitor.x)
+ *x = monitor.x;
+ else if (*x + menu_req.width > monitor.x + monitor.width)
+ *x = monitor.x + monitor.width - menu_req.width;
+
+ if (monitor.y + monitor.height - *y - allocation.height >= menu_req.height)
+ *y += allocation.height;
+ else if (*y - monitor.y >= menu_req.height)
+ *y -= menu_req.height;
+ else if (monitor.y + monitor.height - *y - allocation.height > *y - monitor.y)
+ *y += allocation.height;
+ else
+ *y -= menu_req.height;
+
+ gtk_menu_set_monitor (menu, monitor_num);
+
+ toplevel = gtk_widget_get_parent (GTK_WIDGET (menu));
+ if (GTK_IS_WINDOW (toplevel) && gtk_widget_get_visible (toplevel))
+ gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU);
+
+ *push_in = FALSE;
+}
+
+static void
+_gcr_menu_button_toggled (GtkToggleButton *togglebutton)
+{
+ GcrMenuButton *self = GCR_MENU_BUTTON (togglebutton);
+ GtkStyleContext *context;
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (self));
+ if (gtk_toggle_button_get_active (togglebutton)) {
+ if (!self->pv->popup_in_progress)
+ gtk_menu_popup (self->pv->menu, NULL, NULL,
+ on_menu_position, self, 1,
+ gtk_get_current_event_time ());
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENUBAR);
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENUITEM);
+ } else {
+ gtk_style_context_remove_class (context, GTK_STYLE_CLASS_MENUBAR);
+ gtk_style_context_remove_class (context, GTK_STYLE_CLASS_MENUITEM);
+ gtk_menu_popdown (self->pv->menu);
+ }
+
+ gtk_widget_reset_style (GTK_WIDGET (self));
+}
+
+static gboolean
+_gcr_menu_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GcrMenuButton *self = GCR_MENU_BUTTON (widget);
+ GtkWidget *ewidget;
+
+ ewidget = gtk_get_event_widget ((GdkEvent *)event);
+ if (ewidget != widget || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+ return FALSE;
+
+ gtk_menu_popup (self->pv->menu, NULL, NULL, on_menu_position, self,
+ 1, gtk_get_current_event_time ());
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+ self->pv->popup_in_progress = TRUE;
+ return TRUE;
+}
+
+static gboolean
+_gcr_menu_button_release_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GcrMenuButton *self = GCR_MENU_BUTTON (widget);
+ gboolean popup_in_progress_saved;
+ GtkWidget *ewidget;
+
+ popup_in_progress_saved = self->pv->popup_in_progress;
+ self->pv->popup_in_progress = FALSE;
+
+ ewidget = gtk_get_event_widget ((GdkEvent *)event);
+
+ if (ewidget == widget && !popup_in_progress_saved &&
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
+ gtk_menu_popdown (self->pv->menu);
+ return TRUE;
+ }
+
+ if (ewidget != widget) {
+ gtk_menu_popdown (self->pv->menu);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+_gcr_menu_button_draw (GtkWidget *widget,
+ cairo_t *cr)
+{
+ GTK_WIDGET_GET_CLASS (widget)->draw (widget, cr);
+ return FALSE;
+}
+
+static void
+_gcr_menu_button_class_init (GcrMenuButtonClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkToggleButtonClass *toggle_class = GTK_TOGGLE_BUTTON_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gobject_class->constructed = _gcr_menu_button_constructed;
+ gobject_class->get_property = _gcr_menu_button_get_property;
+ gobject_class->set_property = _gcr_menu_button_set_property;
+ gobject_class->finalize = _gcr_menu_button_finalize;
+
+ widget_class->button_press_event = _gcr_menu_button_press_event;
+ widget_class->button_release_event = _gcr_menu_button_release_event;
+ widget_class->draw = _gcr_menu_button_draw;
+
+ toggle_class->toggled = _gcr_menu_button_toggled;
+
+ g_type_class_add_private (klass, sizeof (GcrMenuButtonPrivate));
+
+ g_object_class_install_property (gobject_class, PROP_LABEL,
+ g_param_spec_string ("label", "Label", "Label for the button",
+ "", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (gobject_class, PROP_MENU,
+ g_param_spec_object ("menu", "Menu", "Menu for the button",
+ GTK_TYPE_MENU, G_PARAM_READWRITE));
+
+}
+
+GtkWidget *
+_gcr_menu_button_new (const gchar *label)
+{
+ return g_object_new (GCR_TYPE_MENU_BUTTON,
+ "label", label,
+ NULL);
+}
+
+static void
+on_menu_show (GtkWidget *menu,
+ gpointer user_data)
+{
+ GcrMenuButton *self = GCR_MENU_BUTTON (user_data);
+ self->pv->popup_in_progress = TRUE;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self), TRUE);
+ self->pv->popup_in_progress = FALSE;
+}
+
+static void
+on_menu_hide (GtkWidget *menu,
+ gpointer user_data)
+{
+ GcrMenuButton *self = GCR_MENU_BUTTON (user_data);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self), FALSE);
+}
+
+static void
+on_menu_detach (GtkWidget *attach_widget,
+ GtkMenu *menu)
+{
+
+}
+
+GtkMenu *
+_gcr_menu_button_get_menu (GcrMenuButton *self)
+{
+ g_return_val_if_fail (GCR_IS_MENU_BUTTON (self), NULL);
+ return self->pv->menu;
+}
+
+void
+_gcr_menu_button_set_menu (GcrMenuButton *self,
+ GtkMenu *menu)
+{
+ g_return_if_fail (GCR_IS_MENU_BUTTON (self));
+ g_return_if_fail (menu == NULL || GTK_IS_MENU (menu));
+
+ if (menu == self->pv->menu)
+ return;
+
+ if (self->pv->menu != NULL) {
+ g_signal_handlers_disconnect_by_func (self->pv->menu, on_menu_show, self);
+ g_signal_handlers_disconnect_by_func (self->pv->menu, on_menu_hide, self);
+ gtk_menu_detach (self->pv->menu);
+ g_object_unref (self->pv->menu);
+ }
+
+ self->pv->menu = menu;
+
+ if (self->pv->menu != NULL) {
+ g_object_ref (self->pv->menu);
+ g_signal_connect (self->pv->menu, "show", G_CALLBACK (on_menu_show), self);
+ g_signal_connect (self->pv->menu, "hide", G_CALLBACK (on_menu_hide), self);
+ gtk_menu_attach_to_widget (self->pv->menu, GTK_WIDGET (self), on_menu_detach);
+ }
+
+ g_object_notify (G_OBJECT (self), "menu");
+}
diff --git a/gcr/gcr-menu-button.h b/gcr/gcr-menu-button.h
new file mode 100644
index 0000000..02dbb9c
--- /dev/null
+++ b/gcr/gcr-menu-button.h
@@ -0,0 +1,61 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program 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.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#ifndef GCR_MENU_BUTTON_H
+#define GCR_MENU_BUTTON_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_MENU_BUTTON (_gcr_menu_button_get_type ())
+#define GCR_MENU_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_MENU_BUTTON, GcrMenuButton))
+#define GCR_MENU_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_MENU_BUTTON, GcrMenuButtonClass))
+#define GCR_IS_MENU_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_MENU_BUTTON))
+#define GCR_IS_MENU_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_MENU_BUTTON))
+#define GCR_MENU_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_MENU_BUTTON, GcrMenuButtonClass))
+
+typedef struct _GcrMenuButton GcrMenuButton;
+typedef struct _GcrMenuButtonClass GcrMenuButtonClass;
+typedef struct _GcrMenuButtonPrivate GcrMenuButtonPrivate;
+
+struct _GcrMenuButton {
+ GtkToggleButton parent;
+ GcrMenuButtonPrivate *pv;
+};
+
+struct _GcrMenuButtonClass {
+ GtkToggleButtonClass parent;
+};
+
+GType _gcr_menu_button_get_type (void);
+
+GtkWidget * _gcr_menu_button_new (const gchar *label);
+
+GtkMenu * _gcr_menu_button_get_menu (GcrMenuButton *self);
+
+void _gcr_menu_button_set_menu (GcrMenuButton *self,
+ GtkMenu *menu);
+G_END_DECLS
+
+#endif /* GCR_MENU_BUTTON_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]