189 lines
7.1 KiB
Diff
189 lines
7.1 KiB
Diff
From c7bc43571acc57546cd732e3658be86d308f0256 Mon Sep 17 00:00:00 2001
|
||
From: luoqing <luoqing@kylinsec.com.cn>
|
||
Date: Thu, 14 Sep 2023 17:34:29 +0800
|
||
Subject: [PATCH] feature(sn-icon-menu):Support dynamic increase or decrease of
|
||
sub-item MenuItem in the tray right-click menu and property changes
|
||
MIME-Version: 1.0
|
||
Content-Type: text/plain; charset=UTF-8
|
||
Content-Transfer-Encoding: 8bit
|
||
|
||
- 支持托盘右键菜单中的子项MenuItem动态增减以及属性变化
|
||
|
||
Closed #15944
|
||
---
|
||
src/tray/kiran-sn-icon-menu.c | 126 +++++++++++++++++++++++++++++-----
|
||
1 file changed, 109 insertions(+), 17 deletions(-)
|
||
|
||
diff --git a/src/tray/kiran-sn-icon-menu.c b/src/tray/kiran-sn-icon-menu.c
|
||
index 22e321f..ffae1bb 100644
|
||
--- a/src/tray/kiran-sn-icon-menu.c
|
||
+++ b/src/tray/kiran-sn-icon-menu.c
|
||
@@ -1,19 +1,20 @@
|
||
/**
|
||
- * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd.
|
||
+ * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd.
|
||
* kiran-cc-daemon is licensed under Mulan PSL v2.
|
||
- * You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||
* You may obtain a copy of Mulan PSL v2 at:
|
||
- * http://license.coscl.org.cn/MulanPSL2
|
||
- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||
- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||
- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||
- * See the Mulan PSL v2 for more details.
|
||
- *
|
||
+ * http://license.coscl.org.cn/MulanPSL2
|
||
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||
+ * See the Mulan PSL v2 for more details.
|
||
+ *
|
||
* Author: wangxiaoqing <wangxiaoqing@kylinos.com.cn>
|
||
*/
|
||
|
||
#include "kiran-sn-icon-menu.h"
|
||
#include <libdbusmenu-glib/dbusmenu-glib.h>
|
||
+#include <libdbusmenu-glib/menuitem.h>
|
||
struct _KiranSnIconMenuPrivate
|
||
{
|
||
gchar *bus_name;
|
||
@@ -30,6 +31,7 @@ enum
|
||
LAST_PROP
|
||
};
|
||
|
||
+#define DATA_KEY_SIGNAL_PROPERTY_CHANGED_IS_CONNECTED "signal_property_changed_is_connected"
|
||
static GParamSpec *properties[LAST_PROP] = {NULL};
|
||
|
||
G_DEFINE_TYPE_WITH_PRIVATE(KiranSnIconMenu, kiran_sn_icon_menu, GTK_TYPE_MENU)
|
||
@@ -175,6 +177,88 @@ create_widget_from_menuitem(DbusmenuMenuitem *item)
|
||
return gmi;
|
||
}
|
||
|
||
+static void
|
||
+kiran_sn_icon_menu_create_widget_from_dbusmenuitem(KiranSnIconMenu *menu, DbusmenuMenuitem *item)
|
||
+{
|
||
+ GtkWidget *gmi = create_widget_from_menuitem(item);
|
||
+
|
||
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), gmi);
|
||
+ gtk_widget_show(gmi);
|
||
+
|
||
+ g_signal_connect(gmi,
|
||
+ "activate",
|
||
+ G_CALLBACK(activate_cb),
|
||
+ item);
|
||
+}
|
||
+
|
||
+static void
|
||
+kiran_sn_icon_menu_remove_widget_all(KiranSnIconMenu *menu)
|
||
+{
|
||
+ GList *child;
|
||
+ GList *container_children = gtk_container_get_children(GTK_CONTAINER(menu));
|
||
+ for (child = container_children; child; child = child->next)
|
||
+ {
|
||
+ gtk_container_remove(GTK_CONTAINER(menu), GTK_WIDGET(child->data));
|
||
+ gtk_widget_destroy(GTK_WIDGET(child->data));
|
||
+ }
|
||
+}
|
||
+
|
||
+static void
|
||
+property_changed_cb(DbusmenuMenuitem *item, gchar *property, GVariant *value, gpointer user_data)
|
||
+{
|
||
+ GList *child;
|
||
+ KiranSnIconMenu *menu = KIRAN_SN_ICON_MENU(user_data);
|
||
+
|
||
+ kiran_sn_icon_menu_remove_widget_all(menu);
|
||
+
|
||
+ // 遍历MenuItem,以找到root
|
||
+ DbusmenuMenuitem *root = dbusmenu_menuitem_get_parent(item);
|
||
+ gboolean is_root = dbusmenu_menuitem_get_root(root);
|
||
+
|
||
+ while (!is_root)
|
||
+ {
|
||
+ root = dbusmenu_menuitem_get_parent(root);
|
||
+ is_root = dbusmenu_menuitem_get_root(root);
|
||
+ }
|
||
+
|
||
+ GList *dbus_menuitem_children = dbusmenu_menuitem_get_children(root);
|
||
+ for (child = dbus_menuitem_children; child; child = child->next)
|
||
+ {
|
||
+ kiran_sn_icon_menu_create_widget_from_dbusmenuitem(menu,child->data);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void
|
||
+submenu_get_children_to_connect(DbusmenuMenuitem *submenu, gpointer user_data)
|
||
+{
|
||
+ KiranSnIconMenu *menu = KIRAN_SN_ICON_MENU(user_data);
|
||
+ GList *submenu_children = dbusmenu_menuitem_get_children(submenu);
|
||
+ GList *submenu_child;
|
||
+ for (submenu_child = submenu_children; submenu_child; submenu_child = submenu_child->next)
|
||
+ {
|
||
+ const gchar *children_display = dbusmenu_menuitem_property_get(submenu_child->data, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY);
|
||
+ if (g_strcmp0(children_display, "submenu") == 0)
|
||
+ {
|
||
+ submenu_get_children_to_connect(submenu_child->data, menu);
|
||
+ }
|
||
+
|
||
+ gboolean is_connected = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(submenu_child->data), DATA_KEY_SIGNAL_PROPERTY_CHANGED_IS_CONNECTED));
|
||
+ if (!is_connected)
|
||
+ {
|
||
+ g_signal_connect(submenu_child->data, DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(property_changed_cb), menu);
|
||
+ g_object_set_data(G_OBJECT(submenu_child->data), DATA_KEY_SIGNAL_PROPERTY_CHANGED_IS_CONNECTED, GINT_TO_POINTER(TRUE));
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+/**
|
||
+ * NOTE:
|
||
+ * dbus_menuitem 移除某个menuitem时,没有类似REMOVE_MENUITEM的信号,
|
||
+ * 而是会触发 DBUSMENU_CLIENT_SIGNAL_LAYOUT_UPDATED 信号。
|
||
+ * 新增时会触发 DBUSMENU_CLIENT_SIGNAL_NEW_MENUITEM 信号
|
||
+ *
|
||
+ * 因此layout_updated_cb中还会处理menuitem变化的情况
|
||
+ */
|
||
static void
|
||
layout_updated_cb(DbusmenuClient *client,
|
||
gpointer user_data)
|
||
@@ -182,21 +266,29 @@ layout_updated_cb(DbusmenuClient *client,
|
||
KiranSnIconMenu *menu;
|
||
DbusmenuMenuitem *root = dbusmenu_client_get_root(client);
|
||
GList *child;
|
||
- GList *children = dbusmenu_menuitem_get_children(root);
|
||
|
||
menu = KIRAN_SN_ICON_MENU(user_data);
|
||
|
||
- for (child = children; child; child = child->next)
|
||
+ kiran_sn_icon_menu_remove_widget_all(menu);
|
||
+
|
||
+ GList *dbus_menuitem_children = dbusmenu_menuitem_get_children(root);
|
||
+ for (child = dbus_menuitem_children; child; child = child->next)
|
||
{
|
||
- GtkWidget *gmi = create_widget_from_menuitem(child->data);
|
||
+ kiran_sn_icon_menu_create_widget_from_dbusmenuitem(menu,child->data);
|
||
|
||
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), gmi);
|
||
- gtk_widget_show(gmi);
|
||
+ // NOTE:只修改一个属性,可能会触发多个 PROPERTY_CHANGE 信号
|
||
+ const gchar *children_display = dbusmenu_menuitem_property_get(child->data, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY);
|
||
+ if (g_strcmp0(children_display, "submenu") == 0)
|
||
+ {
|
||
+ submenu_get_children_to_connect(child->data, menu);
|
||
+ }
|
||
|
||
- g_signal_connect(gmi,
|
||
- "activate",
|
||
- G_CALLBACK(activate_cb),
|
||
- child->data);
|
||
+ gboolean is_connected = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(child->data), DATA_KEY_SIGNAL_PROPERTY_CHANGED_IS_CONNECTED));
|
||
+ if (!is_connected)
|
||
+ {
|
||
+ g_signal_connect(child->data, DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(property_changed_cb), menu);
|
||
+ g_object_set_data(G_OBJECT(child->data), DATA_KEY_SIGNAL_PROPERTY_CHANGED_IS_CONNECTED, GINT_TO_POINTER(TRUE));
|
||
+ }
|
||
}
|
||
}
|
||
|
||
--
|
||
2.33.0
|
||
|