[Xfce4-commits] <garcon:master> Add a garcon-gtk library for common gtk stuff.
Nick Schermer
noreply at xfce.org
Fri Aug 2 22:04:04 CEST 2013
Updating branch refs/heads/master
to 70bc6e0e3fbb0ee8b42daf13f446a809e06e77d0 (commit)
from 9d22a69a448799a8d68b203428a63ab34c7ed63f (commit)
commit 70bc6e0e3fbb0ee8b42daf13f446a809e06e77d0
Author: Nick Schermer <nick at xfce.org>
Date: Fri Aug 2 21:58:46 2013 +0200
Add a garcon-gtk library for common gtk stuff.
Now only contains a GtkMenu object to build a menu
from a GarconMenu.
Makefile.am | 2 +-
configure.ac.in | 18 +-
garcon-gtk/Makefile.am | 82 ++
garcon-gtk/garcon-gtk-menu.c | 871 ++++++++++++++++++++
garcon-gtk/garcon-gtk-menu.h | 80 ++
garcon/garcon.h => garcon-gtk/garcon-gtk.h | 29 +-
.../garcon-gtk2-1.pc.in | 6 +-
po/POTFILES.in | 1 +
8 files changed, 1058 insertions(+), 31 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index ee206db..f111da1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,6 +19,7 @@
SUBDIRS = \
garcon \
+ garcon-gtk \
docs \
data \
tests \
@@ -52,7 +53,6 @@ EXTRA_DIST = \
intltool-update.in
DISTCLEANFILES = \
- garcon.spec \
intltool-extract \
intltool-merge \
intltool-update
diff --git a/configure.ac.in b/configure.ac.in
index 4be5d9e..6073729 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -23,8 +23,8 @@ dnl ***************************
m4_define([garcon_verinfo], [0:0:0])
m4_define([garcon_version_api_major], [1])
m4_define([garcon_version_major], [0])
-m4_define([garcon_version_minor], [2])
-m4_define([garcon_version_micro], [1])
+m4_define([garcon_version_minor], [3])
+m4_define([garcon_version_micro], [0])
m4_define([garcon_version_build], [@REVISION@])
m4_define([garcon_version_tag], [git])
m4_define([garcon_version], [garcon_version_major().garcon_version_minor().garcon_version_micro()ifelse(garcon_version_tag(), [git], [garcon_version_tag()-garcon_version_build()], [garcon_version_tag()])])
@@ -113,11 +113,13 @@ XDT_I18N([@LINGUAS@])
dnl ***********************************
dnl *** Check for required packages ***
dnl ***********************************
-XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.14.0])
-XDT_CHECK_PACKAGE([GIO], [gio-2.0], [2.14.0])
-XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.8.0])
-XDT_CHECK_PACKAGE([GOBJECT], [gobject-2.0], [2.14.0])
-XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.14.0])
+XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.30.0])
+XDT_CHECK_PACKAGE([GIO], [gio-2.0], [2.30.0])
+XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.10.0])
+XDT_CHECK_PACKAGE([GOBJECT], [gobject-2.0], [2.30.0])
+XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.30.0])
+XDT_CHECK_PACKAGE([GTK2], [gtk+-2.0], [2.24.0])
+XDT_CHECK_PACKAGE([LIBXFCE4UI], [libxfce4ui-1], [4.10.0])
dnl *************************
dnl *** Check for gtk-doc ***
@@ -144,6 +146,8 @@ docs/reference/version.xml
garcon/Makefile
garcon/garcon-1.pc
garcon/garcon-config.h
+garcon-gtk/Makefile
+garcon-gtk/garcon-gtk2-1.pc
po/Makefile.in
tests/Makefile
])
diff --git a/garcon-gtk/Makefile.am b/garcon-gtk/Makefile.am
new file mode 100644
index 0000000..43fa9d2
--- /dev/null
+++ b/garcon-gtk/Makefile.am
@@ -0,0 +1,82 @@
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
+#
+# Copyright (c) 2013 Nick Schermer <nick at xfce.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, 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 Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General
+# Public License along with this library; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -DGARCON_COMPILATION \
+ -DGARCON_VERSION_API=\"$(GARCON_VERSION_API)\" \
+ -DG_LOG_DOMAIN=\"garcon\" \
+ -DSYSCONFIGDIR=\"$(sysconfdir)/xdg\" \
+ $(PLATFORM_CFLAGS)
+
+lib_LTLIBRARIES = \
+ libgarcon-gtk2-1.la
+
+libgarcon_gtk_headers = \
+ garcon-gtk.h \
+ garcon-gtk-menu.h
+
+libgarcon_gtk_sources = \
+ garcon-gtk-menu.c
+
+libgarcon_gtk2includedir = \
+ $(includedir)/garcon-gtk2-1/garcon-gtk
+
+libgarcon_gtk2include_HEADERS = \
+ $(libgarcon_gtk_headers)
+
+libgarcon_gtk2_1_la_SOURCES = \
+ $(libgarcon_gtk_sources) \
+ $(libgarcon_gtk_headers)
+
+libgarcon_gtk2_1_la_CFLAGS = \
+ $(GIO_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(GTK2_CFLAGS) \
+ $(LIBXFCE4UTIL_CFLAGS) \
+ $(GOBJECT_CFLAGS) \
+ $(GTHREAD_CFLAGS) \
+ $(LIBXFCE4UI_CFLAGS) \
+ $(PLATFORM_CFLAGS)
+
+libgarcon_gtk2_1_la_LDFLAGS = \
+ -no-undefined \
+ -export-dynamic \
+ -version-info $(GARCON_VERINFO) \
+ -export-symbols-regex "^[^_].*" \
+ $(PLATFORM_LDFLAGS)
+
+libgarcon_gtk2_1_la_LIBADD = \
+ $(top_builddir)/garcon/libgarcon-$(GARCON_VERSION_API).la \
+ $(GIO_LIBS) \
+ $(GLIB_LIBS) \
+ $(GTK2_LIBS) \
+ $(LIBXFCE4UTIL_LIBS) \
+ $(GOBJECT_LIBS) \
+ $(GTHREAD_LIBS) \
+ $(LIBXFCE4UI_LIBS)
+
+libgarcon_gtk2_DEPENDENCIES = \
+ $(top_builddir)/garcon/libgarcon-$(GARCON_VERSION_API).la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = garcon-gtk2-1.pc
+
+# Required for gtk-doc and make distcheck
+dist-hook: all
diff --git a/garcon-gtk/garcon-gtk-menu.c b/garcon-gtk/garcon-gtk-menu.c
new file mode 100644
index 0000000..ed32acb
--- /dev/null
+++ b/garcon-gtk/garcon-gtk-menu.c
@@ -0,0 +1,871 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2013 Nick Schermer <nick at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libxfce4util/libxfce4util.h>
+#include <libxfce4ui/libxfce4ui.h>
+
+#include <garcon-gtk/garcon-gtk-menu.h>
+
+#define STR_IS_EMPTY(str) ((str) == NULL || *(str) == '\0')
+
+
+/**
+ * SECTION: garcon-gtk-menu
+ * @title: GarconGtkMenu
+ * @short_description: Create a GtkMenu for a GarconMenu.
+ * @include: garcon-gtk/garcon-gtk.h
+ *
+ * Create a complete GtkMenu for the given GarconMenu
+ **/
+
+
+
+/* Property identifiers */
+enum
+{
+ PROP_0,
+ PROP_MENU,
+ PROP_SHOW_GENERIC_NAMES,
+ PROP_SHOW_MENU_ICONS,
+ PROP_SHOW_TOOLTIPS,
+ N_PROPERTIES
+};
+
+
+
+static void garcon_gtk_menu_finalize (GObject *object);
+static void garcon_gtk_menu_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void garcon_gtk_menu_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void garcon_gtk_menu_show (GtkWidget *widget);
+static void garcon_gtk_menu_load (GarconGtkMenu *menu);
+
+
+
+struct _GarconGtkMenuPrivate
+{
+ GarconMenu *menu;
+
+ guint is_loaded : 1;
+
+ /* reload idle */
+ guint reload_id;
+
+ /* settings */
+ guint show_generic_names : 1;
+ guint show_menu_icons : 1;
+ guint show_tooltips : 1;
+};
+
+
+
+static const GtkTargetEntry dnd_target_list[] = {
+ { "text/uri-list", 0, 0 }
+};
+
+
+
+static GParamSpec *menu_props[N_PROPERTIES] = { NULL, };
+
+
+
+G_DEFINE_TYPE (GarconGtkMenu, garcon_gtk_menu, GTK_TYPE_MENU)
+
+
+
+static void
+garcon_gtk_menu_class_init (GarconGtkMenuClass *klass)
+{
+ GObjectClass *gobject_class;
+ GtkWidgetClass *gtkwidget_class;
+
+ g_type_class_add_private (klass, sizeof (GarconGtkMenuPrivate));
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = garcon_gtk_menu_finalize;
+ gobject_class->get_property = garcon_gtk_menu_get_property;
+ gobject_class->set_property = garcon_gtk_menu_set_property;
+
+ gtkwidget_class = GTK_WIDGET_CLASS (klass);
+ gtkwidget_class->show = garcon_gtk_menu_show;
+
+ /**
+ * GarconMenu:menu:
+ *
+ *
+ **/
+ menu_props[PROP_MENU] =
+ g_param_spec_object ("menu",
+ "menu",
+ "menu",
+ GARCON_TYPE_MENU,
+ G_PARAM_READWRITE
+ | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GarconMenu:show-generic-names:
+ *
+ *
+ **/
+ menu_props[PROP_SHOW_GENERIC_NAMES] =
+ g_param_spec_boolean ("show-generic-names",
+ "show-generic-names",
+ "show-generic-names",
+ FALSE,
+ G_PARAM_READWRITE
+ | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GarconMenu:show-menu-icons:
+ *
+ *
+ **/
+ menu_props[PROP_SHOW_MENU_ICONS] =
+ g_param_spec_boolean ("show-menu-icons",
+ "show-menu-icons",
+ "show-menu-icons",
+ TRUE,
+ G_PARAM_READWRITE
+ | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GarconMenu:show-tooltips:
+ *
+ *
+ **/
+ menu_props[PROP_SHOW_TOOLTIPS] =
+ g_param_spec_boolean ("show-tooltips",
+ "show-tooltips",
+ "show-tooltips",
+ FALSE,
+ G_PARAM_READWRITE
+ | G_PARAM_STATIC_STRINGS);
+
+ /* install all properties */
+ g_object_class_install_properties (gobject_class, N_PROPERTIES, menu_props);
+}
+
+
+
+static void
+garcon_gtk_menu_init (GarconGtkMenu *menu)
+{
+ menu->priv = G_TYPE_INSTANCE_GET_PRIVATE (menu, GARCON_GTK_TYPE_MENU, GarconGtkMenuPrivate);
+
+ menu->priv->show_generic_names = FALSE;
+ menu->priv->show_menu_icons = TRUE;
+ menu->priv->show_tooltips = FALSE;
+
+ gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE);
+}
+
+
+
+static void
+garcon_gtk_menu_finalize (GObject *object)
+{
+ GarconGtkMenu *menu = GARCON_GTK_MENU (object);
+
+ /* Stop pending reload */
+ if (menu->priv->reload_id != 0)
+ g_source_remove (menu->priv->reload_id);
+
+ /* Release menu */
+ if (menu->priv->menu != NULL)
+ g_object_unref (menu->priv->menu);
+
+ (*G_OBJECT_CLASS (garcon_gtk_menu_parent_class)->finalize) (object);
+}
+
+
+
+static void
+garcon_gtk_menu_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GarconGtkMenu *menu = GARCON_GTK_MENU (object);
+
+ switch (prop_id)
+ {
+ case PROP_MENU:
+ g_value_set_object (value, menu->priv->menu);
+ break;
+
+ case PROP_SHOW_GENERIC_NAMES:
+ g_value_set_boolean (value, menu->priv->show_generic_names);
+ break;
+
+ case PROP_SHOW_MENU_ICONS:
+ g_value_set_boolean (value, menu->priv->show_menu_icons);
+ break;
+
+ case PROP_SHOW_TOOLTIPS:
+ g_value_set_boolean (value, menu->priv->show_tooltips);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+
+static void
+garcon_gtk_menu_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GarconGtkMenu *menu = GARCON_GTK_MENU (object);
+
+ switch (prop_id)
+ {
+ case PROP_MENU:
+ garcon_gtk_menu_set_menu (menu, g_value_get_object (value));
+ break;
+
+ case PROP_SHOW_GENERIC_NAMES:
+ garcon_gtk_menu_set_show_generic_names (menu, g_value_get_boolean (value));
+ break;
+
+ case PROP_SHOW_MENU_ICONS:
+ garcon_gtk_menu_set_show_menu_icons (menu, g_value_get_boolean (value));
+ break;
+
+ case PROP_SHOW_TOOLTIPS:
+ garcon_gtk_menu_set_show_tooltips (menu, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+
+static void
+garcon_gtk_menu_show (GtkWidget *widget)
+{
+ GarconGtkMenu *menu = GARCON_GTK_MENU (widget);
+
+ /* try to load the menu if needed */
+ if (!menu->priv->is_loaded)
+ garcon_gtk_menu_load (menu);
+
+ (*GTK_WIDGET_CLASS (garcon_gtk_menu_parent_class)->show) (widget);
+}
+
+
+
+static void
+garcon_gtk_menu_append_quoted (GString *string,
+ const gchar *unquoted)
+{
+ gchar *quoted;
+
+ quoted = g_shell_quote (unquoted);
+ g_string_append (string, quoted);
+ g_free (quoted);
+}
+
+
+
+static void
+garcon_gtk_menu_item_activate (GtkWidget *mi,
+ GarconMenuItem *item)
+{
+ GString *string;
+ const gchar *command;
+ const gchar *p;
+ const gchar *tmp;
+ gchar **argv;
+ gboolean result = FALSE;
+ gchar *uri;
+ GError *error = NULL;
+
+ g_return_if_fail (GTK_IS_WIDGET (mi));
+ g_return_if_fail (GARCON_IS_MENU_ITEM (item));
+
+ command = garcon_menu_item_get_command (item);
+ if (STR_IS_EMPTY (command))
+ return;
+
+ string = g_string_sized_new (100);
+
+ if (garcon_menu_item_requires_terminal (item))
+ g_string_append (string, "exo-open --launch TerminalEmulator ");
+
+ /* expand the field codes */
+ for (p = command; *p != '\0'; ++p)
+ {
+ if (G_UNLIKELY (p[0] == '%' && p[1] != '\0'))
+ {
+ switch (*++p)
+ {
+ case 'f': case 'F':
+ case 'u': case 'U':
+ /* TODO for dnd, not a regression, xfdesktop never had this */
+ break;
+
+ case 'i':
+ tmp = garcon_menu_item_get_icon_name (item);
+ if (!STR_IS_EMPTY (tmp))
+ {
+ g_string_append (string, "--icon ");
+ garcon_gtk_menu_append_quoted (string, tmp);
+ }
+ break;
+
+ case 'c':
+ tmp = garcon_menu_item_get_name (item);
+ if (!STR_IS_EMPTY (tmp))
+ garcon_gtk_menu_append_quoted (string, tmp);
+ break;
+
+ case 'k':
+ uri = garcon_menu_item_get_uri (item);
+ if (!STR_IS_EMPTY (uri))
+ garcon_gtk_menu_append_quoted (string, uri);
+ g_free (uri);
+ break;
+
+ case '%':
+ g_string_append_c (string, '%');
+ break;
+ }
+ }
+ else
+ {
+ g_string_append_c (string, *p);
+ }
+ }
+
+ /* parse and spawn command */
+ if (g_shell_parse_argv (string->str, NULL, &argv, &error))
+ {
+ result = xfce_spawn_on_screen (gtk_widget_get_screen (mi),
+ garcon_menu_item_get_path (item),
+ argv, NULL, G_SPAWN_SEARCH_PATH,
+ garcon_menu_item_supports_startup_notification (item),
+ gtk_get_current_event_time (),
+ garcon_menu_item_get_icon_name (item),
+ &error);
+
+ g_strfreev (argv);
+ }
+
+ if (G_UNLIKELY (!result))
+ {
+ xfce_dialog_show_error (NULL, error, _("Failed to execute command \"%s\"."), command);
+ g_error_free (error);
+ }
+
+ g_string_free (string, TRUE);
+}
+
+
+
+static void
+garcon_gtk_menu_item_drag_begin (GarconMenuItem *item,
+ GdkDragContext *drag_context)
+{
+ const gchar *icon_name;
+
+ g_return_if_fail (GARCON_IS_MENU_ITEM (item));
+
+ icon_name = garcon_menu_item_get_icon_name (item);
+ if (!STR_IS_EMPTY (icon_name))
+ gtk_drag_set_icon_name (drag_context, icon_name, 0, 0);
+}
+
+
+
+static void
+garcon_gtk_menu_item_drag_data_get (GarconMenuItem *item,
+ GdkDragContext *drag_context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint drag_time)
+{
+ gchar *uris[2] = { NULL, NULL };
+
+ g_return_if_fail (GARCON_IS_MENU_ITEM (item));
+
+ uris[0] = garcon_menu_item_get_uri (item);
+ if (G_LIKELY (uris[0] != NULL))
+ {
+ gtk_selection_data_set_uris (selection_data, uris);
+ g_free (uris[0]);
+ }
+}
+
+
+
+static void
+garcon_gtk_menu_item_drag_end (GarconGtkMenu *menu)
+{
+ g_return_if_fail (GTK_IS_MENU (menu));
+
+ /* make sure the menu is not visible */
+ gtk_menu_popdown (GTK_MENU (menu));
+
+ /* always emit this signal */
+ g_signal_emit_by_name (G_OBJECT (menu), "selection-done", 0);
+}
+
+
+
+static void
+garcon_gtk_menu_deactivate (GtkWidget *submenu,
+ GarconGtkMenu *menu)
+{
+ garcon_gtk_menu_item_drag_end (menu);
+}
+
+
+
+static gboolean
+garcon_gtk_menu_reload_idle (gpointer data)
+{
+ GarconGtkMenu *menu = GARCON_GTK_MENU (data);
+ GList *children;
+
+ /* wait until the menu is hidden */
+ if (gtk_widget_get_visible (GTK_WIDGET (menu)))
+ return TRUE;
+
+ /* destroy all menu item */
+ children = gtk_container_get_children (GTK_CONTAINER (menu));
+ g_list_free_full (children, (GDestroyNotify) gtk_widget_destroy);
+
+ /* reload the menu */
+ garcon_gtk_menu_load (menu);
+
+ /* reset */
+ menu->priv->reload_id = 0;
+
+ return FALSE;
+}
+
+
+
+static void
+garcon_gtk_menu_reload (GarconGtkMenu *menu)
+{
+ /* schedule a menu reload */
+ if (menu->priv->reload_id == 0
+ && menu->priv->is_loaded)
+ {
+ menu->priv->reload_id = g_timeout_add (100, garcon_gtk_menu_reload_idle, menu);
+ }
+}
+
+
+
+static gboolean
+garcon_gtk_menu_add (GarconGtkMenu *menu,
+ GtkMenu *gtk_menu,
+ GarconMenu *garcon_menu)
+{
+ GList *elements, *li;
+ GtkWidget *mi, *image;
+ const gchar *name, *icon_name;
+ const gchar *comment;
+ GtkWidget *submenu;
+ gboolean has_children = FALSE;
+ const gchar *command;
+ GarconMenuDirectory *directory;
+
+ g_return_val_if_fail (GARCON_GTK_IS_MENU (menu), FALSE);
+ g_return_val_if_fail (GTK_IS_MENU (gtk_menu), FALSE);
+ g_return_val_if_fail (GARCON_IS_MENU (garcon_menu), FALSE);
+
+ elements = garcon_menu_get_elements (garcon_menu);
+ for (li = elements; li != NULL; li = li->next)
+ {
+ g_assert (GARCON_IS_MENU_ELEMENT (li->data));
+
+ if (GARCON_IS_MENU_ITEM (li->data))
+ {
+ /* watch for changes */
+ g_signal_connect_swapped (G_OBJECT (li->data), "changed",
+ G_CALLBACK (garcon_gtk_menu_reload), menu);
+
+ /* skip invisible items */
+ if (!garcon_menu_element_get_visible (li->data))
+ continue;
+
+ /* get element name */
+ name = NULL;
+ if (menu->priv->show_generic_names)
+ name = garcon_menu_item_get_generic_name (li->data);
+ if (name == NULL)
+ name = garcon_menu_item_get_name (li->data);
+
+ if (G_UNLIKELY (name == NULL))
+ continue;
+
+ /* create item */
+ mi = gtk_image_menu_item_new_with_label (name);
+ gtk_menu_shell_append (GTK_MENU_SHELL (gtk_menu), mi);
+ g_signal_connect (G_OBJECT (mi), "activate",
+ G_CALLBACK (garcon_gtk_menu_item_activate), li->data);
+ gtk_widget_show (mi);
+
+ if (menu->priv->show_tooltips)
+ {
+ comment = garcon_menu_item_get_comment (li->data);
+ if (!STR_IS_EMPTY (comment))
+ gtk_widget_set_tooltip_text (mi, comment);
+ }
+
+ /* support for dnd item to for example the xfce4-panel */
+ gtk_drag_source_set (mi, GDK_BUTTON1_MASK, dnd_target_list,
+ G_N_ELEMENTS (dnd_target_list), GDK_ACTION_COPY);
+ g_signal_connect_swapped (G_OBJECT (mi), "drag-begin",
+ G_CALLBACK (garcon_gtk_menu_item_drag_begin), li->data);
+ g_signal_connect_swapped (G_OBJECT (mi), "drag-data-get",
+ G_CALLBACK (garcon_gtk_menu_item_drag_data_get), li->data);
+ g_signal_connect_swapped (G_OBJECT (mi), "drag-end",
+ G_CALLBACK (garcon_gtk_menu_item_drag_end), menu);
+
+ /* doesn't happen, but anyway... */
+ command = garcon_menu_item_get_command (li->data);
+ if (STR_IS_EMPTY (command))
+ gtk_widget_set_sensitive (mi, FALSE);
+
+ if (menu->priv->show_menu_icons)
+ {
+ icon_name = garcon_menu_item_get_icon_name (li->data);
+ if (STR_IS_EMPTY (icon_name))
+ icon_name = "applications-other";
+
+ image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), image);
+ gtk_widget_show (image);
+ }
+
+ /* atleast 1 visible child */
+ has_children = TRUE;
+ }
+ else if (GARCON_IS_MENU_SEPARATOR (li->data))
+ {
+ mi = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (gtk_menu), mi);
+ gtk_widget_show (mi);
+ }
+ else if (GARCON_IS_MENU (li->data))
+ {
+ /* the element check for menu also copies the item list to
+ * check if all the elements are visible, we do that with the
+ * return value of this function, so avoid that and only check
+ * the visibility of the menu directory */
+ directory = garcon_menu_get_directory (li->data);
+ if (directory != NULL
+ && !garcon_menu_directory_get_visible (directory))
+ continue;
+
+ submenu = gtk_menu_new ();
+ if (garcon_gtk_menu_add (menu, GTK_MENU (submenu), li->data))
+ {
+ /* attach submenu */
+ name = garcon_menu_element_get_name (li->data);
+ mi = gtk_image_menu_item_new_with_label (name);
+ gtk_menu_shell_append (GTK_MENU_SHELL (gtk_menu), mi);
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), submenu);
+ g_signal_connect (G_OBJECT (submenu), "selection-done",
+ G_CALLBACK (garcon_gtk_menu_deactivate), menu);
+ gtk_widget_show (mi);
+
+ if (menu->priv->show_menu_icons)
+ {
+ icon_name = garcon_menu_element_get_icon_name (li->data);
+ if (STR_IS_EMPTY (icon_name))
+ icon_name = "applications-other";
+
+ image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), image);
+ gtk_widget_show (image);
+ }
+ }
+ else
+ {
+ /* no visible element in the menu */
+ gtk_widget_destroy (submenu);
+ }
+ }
+ }
+
+ g_list_free (elements);
+
+ return has_children;
+}
+
+
+
+static void
+garcon_gtk_menu_load (GarconGtkMenu *menu)
+{
+ GError *error = NULL;
+ GtkWidget *mi;
+
+ g_return_if_fail (GARCON_GTK_IS_MENU (menu));
+ g_return_if_fail (menu->priv->menu == NULL || GARCON_IS_MENU (menu->priv->menu));
+
+ if (menu->priv->menu == NULL)
+ return;
+
+ if (garcon_menu_load (menu->priv->menu, NULL, &error))
+ {
+ if (!garcon_gtk_menu_add (menu, GTK_MENU (menu), menu->priv->menu))
+ {
+ mi = gtk_menu_item_new_with_label (_("No applications found"));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
+ gtk_widget_set_sensitive (mi, FALSE);
+ gtk_widget_show (mi);
+ }
+
+ /* watch for changes */
+ g_signal_connect_swapped (G_OBJECT (menu->priv->menu), "reload-required",
+ G_CALLBACK (garcon_gtk_menu_reload), menu);
+ }
+ else
+ {
+ xfce_dialog_show_error (NULL, error, _("Failed to load the applications menu"));
+ g_error_free (error);
+ }
+
+ menu->priv->reload_id = 0;
+ menu->priv->is_loaded = TRUE;
+}
+
+
+
+/**
+ * garcon_gtk_menu_new:
+ * @garcon_menu :
+ *
+ * Creates a new #GarconMenu for the .menu file referred to by @file.
+ * This operation only fails @file is invalid. To load the menu
+ * tree from the file, you need to call garcon_gtk_menu_load() with the
+ * returned #GarconMenu.
+ *
+ * The caller is responsible to destroy the returned #GarconMenu
+ * using g_object_unref().
+ *
+ * For more information about the usage @see garcon_gtk_menu_new().
+ *
+ * Returns: a new #GarconMenu for @file.
+ **/
+GtkWidget *
+garcon_gtk_menu_new (GarconMenu *garcon_menu)
+{
+ g_return_val_if_fail (garcon_menu == NULL || GARCON_IS_MENU (garcon_menu), NULL);
+ return g_object_new (GARCON_GTK_TYPE_MENU, "menu", garcon_menu, NULL);
+}
+
+
+
+/**
+ * garcon_gtk_menu_get_menu:
+ * @menu : A #GarconGtkMenu
+ *
+ * The #GarconMenu used to create the #GtkMenu.
+ *
+ * The caller is responsible to releasing the returned #GarconMenu
+ * using g_object_unref().
+ *
+ * Returns: the #GarconMenu for @menu.
+ **/
+void
+garcon_gtk_menu_set_menu (GarconGtkMenu *menu,
+ GarconMenu *garcon_menu)
+{
+ g_return_if_fail (GARCON_GTK_IS_MENU (menu));
+ g_return_if_fail (garcon_menu == NULL || GARCON_IS_MENU (garcon_menu));
+
+ if (menu->priv->menu == garcon_menu)
+ return;
+
+ if (menu->priv->menu != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (G_OBJECT (menu->priv->menu), garcon_gtk_menu_reload, menu);
+ g_object_unref (G_OBJECT (menu->priv->menu));
+ }
+
+ if (garcon_menu != NULL)
+ menu->priv->menu = g_object_ref (G_OBJECT (garcon_menu));
+ else
+ menu->priv->menu = NULL;
+
+ g_object_notify_by_pspec (G_OBJECT (menu), menu_props[PROP_MENU]);
+
+ garcon_gtk_menu_reload (menu);
+}
+
+
+
+/**
+ * garcon_gtk_menu_get_menu:
+ * @menu : A #GarconGtkMenu
+ *
+ * The #GarconMenu used to create the #GtkMenu.
+ *
+ * The caller is responsible to releasing the returned #GarconMenu
+ * using g_object_unref().
+ *
+ * Returns: the #GarconMenu for @menu.
+ **/
+GarconMenu *
+garcon_gtk_menu_get_menu (GarconGtkMenu *menu)
+{
+ g_return_val_if_fail (GARCON_GTK_IS_MENU (menu), NULL);
+ if (menu->priv->menu != NULL)
+ return g_object_ref (G_OBJECT (menu->priv->menu));
+ return NULL;
+}
+
+
+
+/**
+ * garcon_gtk_menu_set_show_generic_names:
+ * @menu : A #GarconGtkMenu
+ * @show_generic_names : new value
+ *
+ **/
+void
+garcon_gtk_menu_set_show_generic_names (GarconGtkMenu *menu,
+ gboolean show_generic_names)
+{
+ g_return_if_fail (GARCON_GTK_IS_MENU (menu));
+
+ if (menu->priv->show_generic_names == show_generic_names)
+ return;
+
+ menu->priv->show_generic_names = !!show_generic_names;
+ g_object_notify_by_pspec (G_OBJECT (menu), menu_props[PROP_SHOW_GENERIC_NAMES]);
+
+ garcon_gtk_menu_reload (menu);
+}
+
+
+
+/**
+ * garcon_gtk_menu_get_show_generic_names:
+ * @menu : A #GarconGtkMenu
+ *
+ * Return value: if generic names are shown
+ **/
+gboolean
+garcon_gtk_menu_get_show_generic_names (GarconGtkMenu *menu)
+{
+ g_return_val_if_fail (GARCON_GTK_IS_MENU (menu), FALSE);
+ return menu->priv->show_generic_names;
+}
+
+
+
+/**
+ * garcon_gtk_menu_set_show_menu_icons:
+ * @menu : A #GarconGtkMenu
+ * @show_menu_icons : new value
+ *
+ *
+ **/
+void
+garcon_gtk_menu_set_show_menu_icons (GarconGtkMenu *menu,
+ gboolean show_menu_icons)
+{
+ g_return_if_fail (GARCON_GTK_IS_MENU (menu));
+
+ if (menu->priv->show_menu_icons == show_menu_icons)
+ return;
+
+ menu->priv->show_menu_icons = !!show_menu_icons;
+ g_object_notify_by_pspec (G_OBJECT (menu), menu_props[PROP_SHOW_MENU_ICONS]);
+
+ garcon_gtk_menu_reload (menu);
+}
+
+
+
+/**
+ * garcon_gtk_menu_get_show_menu_icons:
+ * @menu : A #GarconGtkMenu
+ *
+ * Return value: if menu icons are shown
+ **/
+gboolean
+garcon_gtk_menu_get_show_menu_icons (GarconGtkMenu *menu)
+{
+ g_return_val_if_fail (GARCON_GTK_IS_MENU (menu), FALSE);
+ return menu->priv->show_menu_icons;
+}
+
+
+
+/**
+ * garcon_gtk_menu_set_show_tooltips:
+ * @menu : A #GarconGtkMenu
+ *
+ *
+ **/
+void
+garcon_gtk_menu_set_show_tooltips (GarconGtkMenu *menu,
+ gboolean show_tooltips)
+{
+ g_return_if_fail (GARCON_GTK_IS_MENU (menu));
+
+ if (menu->priv->show_tooltips == show_tooltips)
+ return;
+
+ menu->priv->show_tooltips = !!show_tooltips;
+ g_object_notify_by_pspec (G_OBJECT (menu), menu_props[PROP_SHOW_TOOLTIPS]);
+
+ garcon_gtk_menu_reload (menu);
+}
+
+
+
+/**
+ * garcon_gtk_menu_get_show_tooltips:
+ * @menu : A #GarconGtkMenu
+ *
+ * Return value: if descriptions are shown in tooltip
+ **/
+gboolean
+garcon_gtk_menu_get_show_tooltips (GarconGtkMenu *menu)
+{
+ g_return_val_if_fail (GARCON_GTK_IS_MENU (menu), FALSE);
+ return menu->priv->show_tooltips;
+}
diff --git a/garcon-gtk/garcon-gtk-menu.h b/garcon-gtk/garcon-gtk-menu.h
new file mode 100644
index 0000000..db7d08d
--- /dev/null
+++ b/garcon-gtk/garcon-gtk-menu.h
@@ -0,0 +1,80 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2013 Nick Schermer <nick at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#if !defined(GARCON_INSIDE_GARCON_GTK_H) && !defined(GARCON_COMPILATION)
+#error "Only <garcon-gtk/garcon-gtk.h> can be included directly. This file may disappear or change contents."
+#endif
+
+#ifndef __GARCON_GTK_MENU_H__
+#define __GARCON_GTK_MENU_H__
+
+#include <gtk/gtk.h>
+#include <garcon/garcon.h>
+
+G_BEGIN_DECLS
+
+#define GARCON_GTK_TYPE_MENU (garcon_gtk_menu_get_type ())
+#define GARCON_GTK_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GARCON_GTK_TYPE_MENU, GarconGtkMenu))
+#define GARCON_GTK_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GARCON_GTK_TYPE_MENU, GarcontkMenuClass))
+#define GARCON_GTK_IS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GARCON_GTK_TYPE_MENU))
+#define GARCON_GTK_IS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GARCON_GTK_TYPE_MENU))
+#define GARCON_GTK_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GARCON_GTK_TYPE_MENU, GarcontkMenuClass))
+
+typedef struct _GarconGtkMenuPrivate GarconGtkMenuPrivate;
+typedef struct _GarconGtkMenuClass GarconGtkMenuClass;
+typedef struct _GarconGtkMenu GarconGtkMenu;
+
+struct _GarconGtkMenuClass
+{
+ GtkMenuClass __parent__;
+};
+
+struct _GarconGtkMenu
+{
+ GtkMenu __parent__;
+
+ /* < private > */
+ GarconGtkMenuPrivate *priv;
+};
+
+GType garcon_gtk_menu_get_type (void) G_GNUC_CONST;
+
+GtkWidget *garcon_gtk_menu_new (GarconMenu *garcon_menu) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+
+void garcon_gtk_menu_set_menu (GarconGtkMenu *menu,
+ GarconMenu *garcon_menu);
+
+GarconMenu *garcon_gtk_menu_get_menu (GarconGtkMenu *menu);
+
+void garcon_gtk_menu_set_show_generic_names (GarconGtkMenu *menu,
+ gboolean show_generic_names);
+gboolean garcon_gtk_menu_get_show_generic_names (GarconGtkMenu *menu);
+
+void garcon_gtk_menu_set_show_menu_icons (GarconGtkMenu *menu,
+ gboolean show_menu_icons);
+gboolean garcon_gtk_menu_get_show_menu_icons (GarconGtkMenu *menu);
+
+void garcon_gtk_menu_set_show_tooltips (GarconGtkMenu *menu,
+ gboolean show_tooltips);
+gboolean garcon_gtk_menu_get_show_tooltips (GarconGtkMenu *menu);
+
+G_END_DECLS
+
+#endif /* !__GARCON_GTK_MENU_H__ */
diff --git a/garcon/garcon.h b/garcon-gtk/garcon-gtk.h
similarity index 52%
copy from garcon/garcon.h
copy to garcon-gtk/garcon-gtk.h
index 0a47778..9e68a14 100644
--- a/garcon/garcon.h
+++ b/garcon-gtk/garcon-gtk.h
@@ -1,6 +1,6 @@
/* vi:set et ai sw=2 sts=2 ts=2: */
/*-
- * Copyright (c) 2006-2009 Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2013 Nick Schermer <nick at xfce.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -18,27 +18,16 @@
* Boston, MA 02110-1301, USA.
*/
-#ifndef __GARCON_H__
-#define __GARCON_H__
+#ifndef __GARCON_GTK_H__
+#define __GARCON_GTK_H__
-#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <garcon/garcon.h>
-#define GARCON_INSIDE_GARCON_H
+#define GARCON_INSIDE_GARCON_GTK_H
-#include <garcon/garcon-config.h>
-#include <garcon/garcon-menu-directory.h>
-#include <garcon/garcon-menu-element.h>
-#include <garcon/garcon-environment.h>
-#include <garcon/garcon-menu.h>
-#include <garcon/garcon-menu-item.h>
-#include <garcon/garcon-menu-item-cache.h>
-#include <garcon/garcon-menu-item-pool.h>
-#include <garcon/garcon-menu-node.h>
-#include <garcon/garcon-menu-merger.h>
-#include <garcon/garcon-menu-parser.h>
-#include <garcon/garcon-menu-separator.h>
-#include <garcon/garcon-menu-tree-provider.h>
+#include <garcon-gtk/garcon-gtk-menu.h>
-#undef GARCON_INSIDE_GARCON_H
+#undef GARCON_INSIDE_GARCON_GTK_H
-#endif /* !__GARCON_H__ */
+#endif /* !__GARCON_GTK_H__ */
diff --git a/garcon/garcon-1.pc.in b/garcon-gtk/garcon-gtk2-1.pc.in
similarity index 59%
copy from garcon/garcon-1.pc.in
copy to garcon-gtk/garcon-gtk2-1.pc.in
index 10e4356..e20207c 100644
--- a/garcon/garcon-1.pc.in
+++ b/garcon-gtk/garcon-gtk2-1.pc.in
@@ -7,7 +7,7 @@ garcon_api_version=@GARCON_VERSION_API@
Name: @PACKAGE_TARNAME@
Description: Freedesktop.org compliant menu library
-Requires: glib-2.0 gio-2.0 gthread-2.0 gobject-2.0
+Requires: garcon-1 gtk+-2.0 libxfce4ui-1
Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -lgarcon-${garcon_api_version}
-Cflags: -I${includedir}/garcon-${garcon_api_version}
+Libs: -L${libdir} -lgarcon-gtk2-${garcon_api_version}
+Cflags: -I${includedir}/garcon-gtk2-${garcon_api_version}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1417181..c09482f 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -26,5 +26,6 @@ garcon/garcon-menu-parser.c
garcon/garcon-menu-separator.c
garcon/garcon-menu-tree-provider.c
garcon/garcon-private.c
+garcon-gtk/garcon-gtk-menu.c
tests/test-menu-parser.c
tests/test-menu-spec.c
More information about the Xfce4-commits
mailing list