aboutsummaryrefslogtreecommitdiff
path: root/main/src/ui/status_notifier_menu.vala
diff options
context:
space:
mode:
authorfrosty <gabriel@bwaaa.monster>2026-08-25 22:50:10 -0400
committerfrosty <gabriel@bwaaa.monster>2026-08-25 22:50:10 -0400
commitb19412a3d291f8cdbf037e00ac2f3641f7493de6 (patch)
tree8179bc8a64c2286fde58ce829f774ac3d0a32c1b /main/src/ui/status_notifier_menu.vala
parentd2c69cfb544c23042652dee9ebf0e7031d6c2b29 (diff)
feat: add tray icon
Diffstat (limited to 'main/src/ui/status_notifier_menu.vala')
-rw-r--r--main/src/ui/status_notifier_menu.vala100
1 files changed, 100 insertions, 0 deletions
diff --git a/main/src/ui/status_notifier_menu.vala b/main/src/ui/status_notifier_menu.vala
new file mode 100644
index 00000000..cc8b1375
--- /dev/null
+++ b/main/src/ui/status_notifier_menu.vala
@@ -0,0 +1,100 @@
+using GLib;
+
+namespace Dino.Ui {
+
+public struct DBusMenuLayout {
+ public int id;
+ public HashTable<string, Variant> properties;
+ public Variant[] children;
+}
+
+[DBus (name = "com.canonical.dbusmenu")]
+public class StatusNotifierMenu : Object {
+ private const int ROOT_ITEM_ID = 0;
+ private const int QUIT_ITEM_ID = 1;
+
+ private weak Application application;
+ private bool quit_scheduled;
+
+ public uint version { get { return 3; } }
+ public string text_direction { owned get { return "ltr"; } }
+ public string status { owned get { return "normal"; } }
+ public string[] icon_theme_path { owned get { return new string[0]; } }
+
+ public signal void layout_updated(uint revision, int parent);
+
+ public StatusNotifierMenu(Application application) {
+ this.application = application;
+ }
+
+ public void get_layout(int parent_id, int recursion_depth, string[] property_names,
+ out uint revision, out DBusMenuLayout layout) throws Error {
+ revision = 1;
+ layout = create_layout(parent_id, recursion_depth, property_names);
+ }
+
+ public void @event(int id, string event_id, Variant data, uint timestamp) throws Error {
+ if (id != QUIT_ITEM_ID || event_id != "clicked" || quit_scheduled) return;
+
+ quit_scheduled = true;
+ Idle.add(() => {
+ application.quit();
+ return Source.REMOVE;
+ });
+ }
+
+ public bool about_to_show(int id) throws Error {
+ return false;
+ }
+
+ private DBusMenuLayout create_layout(int id, int recursion_depth, string[] property_names) {
+ DBusMenuLayout layout = DBusMenuLayout();
+ layout.id = id;
+ layout.properties = get_item_properties(id, property_names);
+ layout.children = new Variant[0];
+
+ if (id == ROOT_ITEM_ID && recursion_depth != 0) {
+ DBusMenuLayout quit_item = create_layout(QUIT_ITEM_ID, 0, property_names);
+ layout.children = new Variant[] { layout_to_variant(quit_item) };
+ }
+ return layout;
+ }
+
+ private HashTable<string, Variant> get_item_properties(int id, string[] property_names) {
+ HashTable<string, Variant> properties = new HashTable<string, Variant>(str_hash, str_equal);
+
+ if (id == ROOT_ITEM_ID) {
+ add_property(properties, property_names, "children-display", new Variant.string("submenu"));
+ } else if (id == QUIT_ITEM_ID) {
+ add_property(properties, property_names, "label", new Variant.string(_("Quit Dino")));
+ }
+ return properties;
+ }
+
+ private static void add_property(HashTable<string, Variant> properties, string[] property_names,
+ string name, Variant value) {
+ if (property_names.length == 0 || name in property_names) {
+ properties.insert(name, value);
+ }
+ }
+
+ private static Variant layout_to_variant(DBusMenuLayout layout) {
+ VariantBuilder properties = new VariantBuilder(new VariantType("a{sv}"));
+ layout.properties.foreach((name, value) => {
+ properties.add("{sv}", name, value);
+ });
+
+ Variant[] children = new Variant[layout.children.length];
+ for (int i = 0; i < layout.children.length; i++) {
+ children[i] = new Variant.variant(layout.children[i]);
+ }
+
+ return new Variant.tuple(new Variant[] {
+ new Variant.int32(layout.id),
+ properties.end(),
+ new Variant.array(VariantType.VARIANT, children)
+ });
+ }
+}
+
+}