aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Tari <robert@tari.in>2020-07-22 14:17:17 +0200
committerMike Gabriel <mike.gabriel@das-netzwerkteam.de>2020-07-22 21:56:00 +0200
commitb619354abad7662a8ad53d4885741d4d2ea8f4a0 (patch)
tree4249d4c0b4370e6622dc94c22bebbf6585139624
parentc984cc5424987dbac8c6fcadcf85f87a9a3599b6 (diff)
downloadlibayatana-indicator-b619354abad7662a8ad53d4885741d4d2ea8f4a0.tar.gz
libayatana-indicator-b619354abad7662a8ad53d4885741d4d2ea8f4a0.tar.bz2
libayatana-indicator-b619354abad7662a8ad53d4885741d4d2ea8f4a0.zip
Display IDO widgets/Use own action muxer/Allow IDO CSS styling
-rw-r--r--libayatana-indicator/ayatanamenuitemfactory.c69
-rw-r--r--libayatana-indicator/ayatanamenuitemfactory.h61
-rw-r--r--libayatana-indicator/indicator-ng.c116
3 files changed, 245 insertions, 1 deletions
diff --git a/libayatana-indicator/ayatanamenuitemfactory.c b/libayatana-indicator/ayatanamenuitemfactory.c
new file mode 100644
index 0000000..0e333ab
--- /dev/null
+++ b/libayatana-indicator/ayatanamenuitemfactory.c
@@ -0,0 +1,69 @@
+/*
+* Copyright 2013 Canonical Ltd.
+*
+* This program is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 3, as published
+* by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranties of
+* MERCHANTABILITY, SATISFACTORY QUALITY, 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/>.
+*
+* Authors:
+* Lars Uebernickel <lars.uebernickel@canonical.com>
+*/
+
+#include "ayatanamenuitemfactory.h"
+
+G_DEFINE_INTERFACE_WITH_CODE (AyatanaMenuItemFactory, ayatana_menu_item_factory, G_TYPE_OBJECT,
+ GIOExtensionPoint *ep = g_io_extension_point_register (AYATANA_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME);
+ g_io_extension_point_set_required_type (ep, g_define_type_id);)
+
+/*
+ * ayatana_menu_item_factory_get_all:
+ *
+ * Returns a static list of all registered factories.
+ */
+GList *
+ayatana_menu_item_factory_get_all (void)
+{
+ static GList *factories = NULL;
+
+ if (factories == NULL)
+ {
+ GIOExtensionPoint *ep;
+ GList *it;
+
+ g_type_ensure (AYATANA_TYPE_MENU_ITEM_FACTORY);
+ ep = g_io_extension_point_lookup (AYATANA_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME);
+ for (it = g_io_extension_point_get_extensions (ep); it != NULL; it = it->next)
+ {
+ GIOExtension *ext = it->data;
+ AyatanaMenuItemFactory *factory;
+
+ factory = g_object_new (g_io_extension_get_type (ext), NULL);
+ factories = g_list_prepend (factories, factory);
+ }
+ factories = g_list_reverse (factories);
+ }
+
+ return factories;
+}
+
+static void
+ayatana_menu_item_factory_default_init (AyatanaMenuItemFactoryInterface *iface)
+{
+}
+
+GtkMenuItem *
+ayatana_menu_item_factory_create_menu_item (AyatanaMenuItemFactory *factory,
+ const gchar *type,
+ GMenuItem *menuitem,
+ GActionGroup *actions)
+{
+ return AYATANA_MENU_ITEM_FACTORY_GET_IFACE (factory)->create_menu_item (factory, type, menuitem, actions);
+}
diff --git a/libayatana-indicator/ayatanamenuitemfactory.h b/libayatana-indicator/ayatanamenuitemfactory.h
new file mode 100644
index 0000000..4a241be
--- /dev/null
+++ b/libayatana-indicator/ayatanamenuitemfactory.h
@@ -0,0 +1,61 @@
+/*
+* Copyright 2013 Canonical Ltd.
+*
+* This program is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 3, as published
+* by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranties of
+* MERCHANTABILITY, SATISFACTORY QUALITY, 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/>.
+*
+* Authors:
+* Lars Uebernickel <lars.uebernickel@canonical.com>
+*/
+
+#ifndef __AYATANA_MENU_ITEM_FACTORY_H__
+#define __AYATANA_MENU_ITEM_FACTORY_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define AYATANA_TYPE_MENU_ITEM_FACTORY (ayatana_menu_item_factory_get_type ())
+#define AYATANA_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), AYATANA_TYPE_MENU_ITEM_FACTORY, AyatanaMenuItemFactory))
+#define AYATANA_IS_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), AYATANA_TYPE_MENU_ITEM_FACTORY))
+#define AYATANA_MENU_ITEM_FACTORY_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), AYATANA_TYPE_MENU_ITEM_FACTORY, AyatanaMenuItemFactoryInterface))
+
+#define AYATANA_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME "ayatana-menu-item-factory"
+
+typedef struct _AyatanaMenuItemFactoryInterface AyatanaMenuItemFactoryInterface;
+typedef struct _AyatanaMenuItemFactory AyatanaMenuItemFactory;
+
+struct _AyatanaMenuItemFactoryInterface
+{
+ GTypeInterface iface;
+
+ GtkMenuItem * (*create_menu_item) (AyatanaMenuItemFactory *factory,
+ const gchar *type,
+ GMenuItem *menuitem,
+ GActionGroup *actions);
+};
+
+GDK_AVAILABLE_IN_3_10
+GList * ayatana_menu_item_factory_get_all (void);
+
+GDK_AVAILABLE_IN_3_10
+GType ayatana_menu_item_factory_get_type (void);
+
+GDK_AVAILABLE_IN_3_10
+GtkMenuItem * ayatana_menu_item_factory_create_menu_item (AyatanaMenuItemFactory *factory,
+ const gchar *type,
+ GMenuItem *menuitem,
+ GActionGroup *actions);
+
+G_END_DECLS
+
+#endif
diff --git a/libayatana-indicator/indicator-ng.c b/libayatana-indicator/indicator-ng.c
index d1040a1..9801d3c 100644
--- a/libayatana-indicator/indicator-ng.c
+++ b/libayatana-indicator/indicator-ng.c
@@ -19,9 +19,11 @@
#include "indicator-ng.h"
#include "indicator-image-helper.h"
-
+#include "ayatanamenuitemfactory.h"
#include <string.h>
+#define MENU_SECTIONS 20
+
struct _IndicatorNg
{
IndicatorObject parent;
@@ -48,6 +50,7 @@ struct _IndicatorNg
gchar *accessible_desc;
gint64 last_service_restart;
+ GMenuModel *lMenuSections[MENU_SECTIONS];
};
static void indicator_ng_initable_iface_init (GInitableIface *initable);
@@ -62,6 +65,7 @@ enum
N_PROPERTIES
};
+static GQuark m_pActionMuxer = 0;
static GParamSpec *properties[N_PROPERTIES];
static void
@@ -122,6 +126,15 @@ indicator_ng_free_actions_and_menu (IndicatorNg *self)
if (self->menu)
{
+ for (guint nMenuSection = 0; nMenuSection < MENU_SECTIONS; nMenuSection++)
+ {
+ if (self->lMenuSections[nMenuSection])
+ {
+ g_object_unref(self->lMenuSections[nMenuSection]);
+ self->lMenuSections[nMenuSection] = NULL;
+ }
+ }
+
g_signal_handlers_disconnect_by_data (self->menu, self);
g_clear_object (&self->menu);
}
@@ -219,12 +232,98 @@ indicator_ng_secondary_activate (IndicatorObject *io,
}
}
+static void indicator_ng_menu_section_changed(GMenuModel *pMenuSection, gint nPosition, gint nRemoved, gint nAdded, gpointer pUserData)
+{
+ IndicatorNg *self = pUserData;
+ GMenuModel *pMenuModel = g_menu_model_get_item_link(self->menu, 0, G_MENU_LINK_SUBMENU);
+ guint nCurrMenuItem = 0;
+
+ if (pMenuModel)
+ {
+ gint nSections = g_menu_model_get_n_items(pMenuModel);
+
+ for (gint nSection = 0; nSection < nSections; nSection++)
+ {
+ GMenuModel *pMenuModelSection = g_menu_model_get_item_link(pMenuModel, nSection, G_MENU_LINK_SECTION);
+
+ if (pMenuModelSection)
+ {
+ gint nMenuItems = g_menu_model_get_n_items(pMenuModelSection);
+
+ for (gint nMenuItem = 0; nMenuItem < nMenuItems; nMenuItem++)
+ {
+ gchar *sType;
+ gboolean bHasType = g_menu_model_get_item_attribute(pMenuModelSection, nMenuItem, "x-canonical-type", "s", &sType);
+
+ if (bHasType)
+ {
+ GList *lMenuItems = gtk_container_get_children(GTK_CONTAINER(self->entry.menu));
+ GtkWidget *pMenuItemOld = GTK_WIDGET(g_list_nth_data(lMenuItems, nCurrMenuItem));
+ const gchar *sName = gtk_widget_get_name(pMenuItemOld);
+
+ if (!g_str_equal(sName, sType))
+ {
+ GActionGroup *pActionGroup = (GActionGroup*)g_object_get_qdata(G_OBJECT(self->entry.menu), m_pActionMuxer);
+ GMenuItem *pMenuModelItem = g_menu_item_new_from_model(pMenuModelSection, nMenuItem);
+ GtkMenuItem* pMenuItemNew = NULL;
+
+ for (GList *pFactory = ayatana_menu_item_factory_get_all(); pFactory != NULL && pMenuItemNew == NULL; pFactory = pFactory->next)
+ {
+ pMenuItemNew = ayatana_menu_item_factory_create_menu_item(pFactory->data, sType, pMenuModelItem, pActionGroup);
+ }
+
+ gtk_widget_set_name(GTK_WIDGET(pMenuItemNew), sType);
+ gtk_widget_show(GTK_WIDGET(pMenuItemNew));
+ gtk_container_remove(GTK_CONTAINER(self->entry.menu), pMenuItemOld);
+ gtk_menu_shell_insert(GTK_MENU_SHELL(self->entry.menu), GTK_WIDGET(pMenuItemNew), nCurrMenuItem);
+ g_object_unref(pMenuModelItem);
+ }
+
+ g_list_free(lMenuItems);
+ }
+
+ nCurrMenuItem++;
+ }
+
+ g_object_unref(pMenuModelSection);
+ }
+
+ nCurrMenuItem++;
+ }
+
+ g_object_unref(pMenuModel);
+ }
+}
+
static void
indicator_ng_menu_shown (GtkWidget *widget,
gpointer user_data)
{
IndicatorNg *self = user_data;
+ if (!self->lMenuSections[0])
+ {
+ self->lMenuSections[0] = g_menu_model_get_item_link(self->menu, 0, G_MENU_LINK_SUBMENU);
+
+ if (self->lMenuSections[0])
+ {
+ gint nSections = g_menu_model_get_n_items(self->lMenuSections[0]);
+
+ for (gint nSection = 0; nSection < nSections; nSection++)
+ {
+ self->lMenuSections[nSection + 1] = g_menu_model_get_item_link(self->lMenuSections[0], nSection, G_MENU_LINK_SECTION);
+
+ if (self->lMenuSections[nSection + 1])
+ {
+ g_signal_connect(self->lMenuSections[nSection + 1], "items-changed", G_CALLBACK(indicator_ng_menu_section_changed), self);
+ }
+ }
+
+ g_signal_connect(self->lMenuSections[0], "items-changed", G_CALLBACK(indicator_ng_menu_section_changed), self);
+ indicator_ng_menu_section_changed(self->lMenuSections[0], 0, 0, 1, self);
+ }
+ }
+
if (self->submenu_action)
g_action_group_change_action_state (self->actions, self->submenu_action,
g_variant_new_boolean (TRUE));
@@ -425,6 +524,14 @@ indicator_ng_menu_changed (GMenuModel *menu,
g_free (action);
}
+ for (guint nMenuSection = 0; nMenuSection < MENU_SECTIONS; nMenuSection++)
+ {
+ if (self->lMenuSections[nMenuSection])
+ {
+ g_object_unref(self->lMenuSections[nMenuSection]);
+ }
+ }
+
popup = g_menu_model_get_item_link (self->menu, 0, G_MENU_LINK_SUBMENU);
if (popup)
{
@@ -687,6 +794,13 @@ indicator_ng_initable_iface_init (GInitableIface *initable)
static void
indicator_ng_init (IndicatorNg *self)
{
+ m_pActionMuxer = g_quark_from_static_string ("gtk-widget-action-muxer");
+
+ for (guint nMenuSection = 0; nMenuSection < MENU_SECTIONS; nMenuSection++)
+ {
+ self->lMenuSections[nMenuSection] = NULL;
+ }
+
self->entry.label = (GtkLabel*)g_object_ref_sink (gtk_label_new (NULL));
self->entry.image = (GtkImage*)g_object_ref_sink (gtk_image_new ());