kiran-menu/0004-feature-sn-icon-menu-Support-dynamic-increase-or-dec.patch
luoqing 4540098d94 feature(sn-icon-menu):Support dynamic increase or decrease of sub-item MenuItem in the tray right-click menu and property changes
- 支持托盘右键菜单中的子项MenuItem动态增减以及属性变化

Closed #15944
2023-09-15 09:50:54 +08:00

189 lines
7.1 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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