[gnome-panel] menu: add GpMenu
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-panel] menu: add GpMenu
- Date: Sun, 21 Jan 2018 00:13:16 +0000 (UTC)
commit 9861fd0e429165d4aeef8801dcdd1ff9a6e0bfa8
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Sun Jan 21 01:53:42 2018 +0200
menu: add GpMenu
configure.ac | 1 +
modules/menu/Makefile.am | 3 +
modules/menu/gp-menu.c | 452 ++++++++++++++++++++++++++++++++++++++++++++++
modules/menu/gp-menu.h | 32 ++++
po/POTFILES.in | 1 +
5 files changed, 489 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 41fdc27..d08eb9d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -156,6 +156,7 @@ AC_SUBST(FISH_CFLAGS)
AC_SUBST(FISH_LIBS)
PKG_CHECK_MODULES([MENU], [
+ gio-unix-2.0 >= $GLIB_REQUIRED
gtk+-3.0 >= $GTK_REQUIRED
libgnome-menu-3.0 >= $LIBGNOME_MENU_REQUIRED
])
diff --git a/modules/menu/Makefile.am b/modules/menu/Makefile.am
index b2a7942..b997c5b 100644
--- a/modules/menu/Makefile.am
+++ b/modules/menu/Makefile.am
@@ -5,6 +5,7 @@ menu_lib_LTLIBRARIES = menu.la
menu_la_CPPFLAGS = \
-DLOCALEDIR=\""$(localedir)"\" \
+ -DGMENU_I_KNOW_THIS_IS_UNSTABLE \
-DG_LOG_DOMAIN=\""menu"\" \
-DG_LOG_USE_STRUCTURED=1 \
-I$(top_srcdir) \
@@ -19,6 +20,8 @@ menu_la_CFLAGS = \
$(NULL)
menu_la_SOURCES = \
+ gp-menu.c \
+ gp-menu.h \
main-menu-applet.c \
main-menu-applet.h \
menu-bar-applet.c \
diff --git a/modules/menu/gp-menu.c b/modules/menu/gp-menu.c
new file mode 100644
index 0000000..c8702b0
--- /dev/null
+++ b/modules/menu/gp-menu.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2018 Alberts Muktupāvels
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gio/gdesktopappinfo.h>
+#include <gmenu-tree.h>
+#include <libgnome-panel/gp-image-menu-item.h>
+
+#include "gp-menu.h"
+
+struct _GpMenu
+{
+ GtkMenu parent;
+
+ gchar *name;
+ gboolean enable_tooltips;
+
+ GMenuTree *tree;
+
+ guint load_id;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_NAME,
+ PROP_ENABLE_TOOLTIPS,
+
+ LAST_PROP
+};
+
+static GParamSpec *menu_properties[LAST_PROP] = { NULL };
+
+G_DEFINE_TYPE (GpMenu, gp_menu, GTK_TYPE_MENU)
+
+static void directory_to_menu_items (GMenuTreeDirectory *directory,
+ GtkWidget *widget,
+ GpMenu *menu);
+
+static void
+pid_cb (GDesktopAppInfo *info,
+ GPid pid,
+ gpointer user_data)
+{
+ g_child_watch_add (pid, (GChildWatchFunc) g_spawn_close_pid, NULL);
+}
+
+static void
+activate_cb (GtkWidget *item,
+ GDesktopAppInfo *info)
+{
+ GSpawnFlags flags;
+ GError *error;
+ gboolean ret;
+
+ flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD;
+ error = NULL;
+
+ ret = g_desktop_app_info_launch_uris_as_manager (info, NULL, NULL,
+ flags, NULL, NULL,
+ pid_cb, NULL,
+ &error);
+
+ if (ret == FALSE)
+ {
+ const gchar *display_name;
+ GtkWidget *dialog;
+
+ display_name = g_app_info_get_display_name (G_APP_INFO (info));
+ dialog = gtk_message_dialog_new (NULL, 0,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ _("Could not launch '%s'"),
+ display_name);
+
+ if (error != NULL)
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", error->message);
+
+ g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_window_present (GTK_WINDOW (dialog));
+ }
+
+ g_clear_error (&error);
+}
+
+static void
+append_directory (GtkMenuShell *shell,
+ GMenuTreeIter *iter,
+ GpMenu *menu)
+{
+ GMenuTreeDirectory *directory;
+ GtkWidget *submenu;
+ const gchar *name;
+ GIcon *icon;
+ GtkWidget *item;
+
+ directory = gmenu_tree_iter_get_directory (iter);
+ submenu = gtk_menu_new ();
+
+ directory_to_menu_items (directory, submenu, menu);
+
+ name = gmenu_tree_directory_get_name (directory);
+ icon = gmenu_tree_directory_get_icon (directory);
+ gmenu_tree_item_unref (directory);
+
+ item = gp_image_menu_item_new_with_label (name);
+ gtk_menu_shell_append (shell, item);
+ gtk_widget_show (item);
+
+ if (icon != NULL)
+ {
+ GtkWidget *image;
+
+ image = gtk_image_new ();
+
+ gtk_image_set_from_gicon (GTK_IMAGE (image), icon, GTK_ICON_SIZE_MENU);
+ gtk_image_set_pixel_size (GTK_IMAGE (image), 16);
+
+ gp_image_menu_item_set_image (GP_IMAGE_MENU_ITEM (item), image);
+ }
+
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
+}
+
+static void
+append_entry (GtkMenuShell *shell,
+ GMenuTreeIter *iter,
+ GpMenu *menu)
+{
+ GMenuTreeEntry *entry;
+ GDesktopAppInfo *info;
+ const gchar *name;
+ const gchar *description;
+ GIcon *icon;
+ GtkWidget *item;
+
+ entry = gmenu_tree_iter_get_entry (iter);
+ info = gmenu_tree_entry_get_app_info (entry);
+ gmenu_tree_item_unref (entry);
+
+ name = g_app_info_get_display_name (G_APP_INFO (info));
+ description = g_app_info_get_description (G_APP_INFO (info));
+ icon = g_app_info_get_icon (G_APP_INFO (info));
+
+ item = gp_image_menu_item_new_with_label (name);
+ gtk_menu_shell_append (shell, item);
+ gtk_widget_show (item);
+
+ if (icon != NULL)
+ {
+ GtkWidget *image;
+
+ image = gtk_image_new ();
+
+ gtk_image_set_from_gicon (GTK_IMAGE (image), icon, GTK_ICON_SIZE_MENU);
+ gtk_image_set_pixel_size (GTK_IMAGE (image), 16);
+
+ gp_image_menu_item_set_image (GP_IMAGE_MENU_ITEM (item), image);
+ }
+
+ if (description == NULL)
+ description = g_desktop_app_info_get_generic_name (info);
+
+ if (description != NULL)
+ {
+ gtk_widget_set_tooltip_text (item, description);
+
+ g_object_bind_property (menu, "enable-tooltips",
+ item, "has-tooltip",
+ G_BINDING_DEFAULT |
+ G_BINDING_SYNC_CREATE);
+ }
+
+ g_signal_connect (item, "activate", G_CALLBACK (activate_cb), info);
+}
+
+static void
+append_separator (GtkMenuShell *shell)
+{
+ GtkWidget *item;
+
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (shell, item);
+ gtk_widget_show (item);
+
+ gtk_widget_set_sensitive (item, FALSE);
+}
+
+static void
+directory_to_menu_items (GMenuTreeDirectory *directory,
+ GtkWidget *widget,
+ GpMenu *menu)
+{
+ GMenuTreeIter *iter;
+ GMenuTreeItemType next_type;
+
+ iter = gmenu_tree_directory_iter (directory);
+ next_type = gmenu_tree_iter_next (iter);
+
+ while (next_type != GMENU_TREE_ITEM_INVALID)
+ {
+ switch (next_type)
+ {
+ case GMENU_TREE_ITEM_DIRECTORY:
+ append_directory (GTK_MENU_SHELL (widget), iter, menu);
+ break;
+
+ case GMENU_TREE_ITEM_ENTRY:
+ append_entry (GTK_MENU_SHELL (widget), iter, menu);
+ break;
+
+ case GMENU_TREE_ITEM_SEPARATOR:
+ append_separator (GTK_MENU_SHELL (widget));
+ break;
+
+ case GMENU_TREE_ITEM_ALIAS:
+ break;
+
+ case GMENU_TREE_ITEM_HEADER:
+ break;
+
+ case GMENU_TREE_ITEM_INVALID:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ next_type = gmenu_tree_iter_next (iter);
+ }
+
+ gmenu_tree_iter_unref (iter);
+}
+
+static void
+remove_item (GtkWidget *widget,
+ gpointer user_data)
+{
+ gtk_widget_destroy (widget);
+}
+
+static void
+menu_tree_load (GpMenu *menu)
+{
+ GError *error;
+ GMenuTreeDirectory *directory;
+
+ gtk_container_foreach (GTK_CONTAINER (menu), remove_item, NULL);
+
+ error = NULL;
+ if (!gmenu_tree_load_sync (menu->tree, &error))
+ {
+ g_warning ("Failed to load menu: %s", error->message);
+ g_clear_error (&error);
+
+ return;
+ }
+
+ directory = gmenu_tree_get_directory_from_path (menu->tree, "/");
+ directory_to_menu_items (directory, GTK_WIDGET (menu), menu);
+ gmenu_tree_item_unref (directory);
+}
+
+static gboolean
+menu_tree_load_cb (gpointer user_data)
+{
+ GpMenu *menu;
+
+ menu = GP_MENU (user_data);
+
+ menu_tree_load (menu);
+ menu->load_id = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+menu_tree_changed_cb (GMenuTree *tree,
+ GpMenu *menu)
+{
+ if (menu->load_id != 0)
+ return;
+
+ menu->load_id = g_timeout_add_full (G_PRIORITY_LOW, 200,
+ menu_tree_load_cb, menu,
+ NULL);
+
+ g_source_set_name_by_id (menu->load_id, "[menu] menu_tree_load_cb");
+}
+
+static void
+gp_menu_constructed (GObject *object)
+{
+ GpMenu *menu;
+ GMenuTreeFlags flags;
+
+ menu = GP_MENU (object);
+
+ G_OBJECT_CLASS (gp_menu_parent_class)->constructed (object);
+
+ flags = GMENU_TREE_FLAGS_SORT_DISPLAY_NAME;
+ menu->tree = gmenu_tree_new (menu->name, flags);
+
+ g_signal_connect (menu->tree, "changed",
+ G_CALLBACK (menu_tree_changed_cb), menu);
+
+ menu_tree_changed_cb (menu->tree, menu);
+}
+
+static void
+gp_menu_dispose (GObject *object)
+{
+ GpMenu *menu;
+
+ menu = GP_MENU (object);
+
+ g_clear_object (&menu->tree);
+
+ if (menu->load_id != 0)
+ {
+ g_source_remove (menu->load_id);
+ menu->load_id = 0;
+ }
+
+ G_OBJECT_CLASS (gp_menu_parent_class)->dispose (object);
+}
+
+static void
+gp_menu_finalize (GObject *object)
+{
+ GpMenu *menu;
+
+ menu = GP_MENU (object);
+
+ g_clear_pointer (&menu->name, g_free);
+
+ G_OBJECT_CLASS (gp_menu_parent_class)->finalize (object);
+}
+
+static void
+gp_menu_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GpMenu *menu;
+
+ menu = GP_MENU (object);
+
+ switch (property_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, menu->name);
+ break;
+
+ case PROP_ENABLE_TOOLTIPS:
+ g_value_set_boolean (value, menu->enable_tooltips);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gp_menu_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GpMenu *menu;
+
+ menu = GP_MENU (object);
+
+ switch (property_id)
+ {
+ case PROP_NAME:
+ g_assert (menu->name == NULL);
+ menu->name = g_value_dup_string (value);
+ break;
+
+ case PROP_ENABLE_TOOLTIPS:
+ menu->enable_tooltips = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+install_properties (GObjectClass *object_class)
+{
+ menu_properties[PROP_NAME] =
+ g_param_spec_string ("name", "Name", "Name",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ menu_properties[PROP_ENABLE_TOOLTIPS] =
+ g_param_spec_boolean ("enable-tooltips", "Enable Tooltips", "Enable Tooltips",
+ TRUE,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, menu_properties);
+}
+
+static void
+gp_menu_class_init (GpMenuClass *menu_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (menu_class);
+
+ object_class->constructed = gp_menu_constructed;
+ object_class->dispose = gp_menu_dispose;
+ object_class->finalize = gp_menu_finalize;
+ object_class->get_property = gp_menu_get_property;
+ object_class->set_property = gp_menu_set_property;
+
+ install_properties (object_class);
+}
+
+static void
+gp_menu_init (GpMenu *menu)
+{
+}
+
+GtkWidget *
+gp_menu_new_from_name (const gchar *name)
+{
+ return g_object_new (GP_TYPE_MENU, "name", name, NULL);
+}
diff --git a/modules/menu/gp-menu.h b/modules/menu/gp-menu.h
new file mode 100644
index 0000000..4603d75
--- /dev/null
+++ b/modules/menu/gp-menu.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 Alberts Muktupāvels
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GP_MENU_H
+#define GP_MENU_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GP_TYPE_MENU (gp_menu_get_type ())
+G_DECLARE_FINAL_TYPE (GpMenu, gp_menu, GP, MENU, GtkMenu)
+
+GtkWidget *gp_menu_new_from_name (const gchar *name);
+
+G_END_DECLS
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6dee977..764d2fe 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -59,6 +59,7 @@ modules/fish/fish-applet.c
modules/fish/fish-module.c
modules/fish/fish-menu.ui
modules/fish/fish.ui
+modules/menu/gp-menu.c
modules/menu/menu-module.c
modules/notification-area/na-applet.c
modules/notification-area/na-module.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]