Codebase list xapp / 14a5bb3
Implement XAppStatusIcon (#67) Implement a replacement class for Gtk.StatusIcon. Test scripts are located in test-scripts/. Clement Lefebvre authored 4 years ago GitHub committed 4 years ago
7 changed file(s) with 720 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
2222 <xi:include href="xml/xapp-monitor-blanker.xml"/>
2323 <xi:include href="xml/xapp-preferences-window.xml"/>
2424 <xi:include href="xml/xapp-stack-sidebar.xml"/>
25 <xi:include href="xml/xapp-status-icon.xml"/>
2526
2627 </chapter>
2728 <chapter id="object-tree">
00 GtkWindow cheader_filename="libxapp/xapp-gtk-window.h"
11 MonitorBlanker cheader_filename="libxapp/xapp-monitor-blanker.h"
22 KbdLayoutController cheader_filename="libxapp/xapp-kbd-layout-controller.h"
3 StatusIcon cheader_filename="libxapp/xapp-status-icon.h"
34 XApp cheader_filename="libxapp/xapp-gtk-window.h"
1616 'xapp-monitor-blanker.h',
1717 'xapp-preferences-window.h',
1818 'xapp-stack-sidebar.h',
19 'xapp-status-icon.h',
1920 ]
2021
2122 xapp_sources = [
2728 'xapp-monitor-blanker.c',
2829 'xapp-preferences-window.c',
2930 'xapp-stack-sidebar.c',
31 'xapp-status-icon.c',
3032 ]
3133
3234 xapp_enums = gnome.mkenums('xapp-enums',
0
1 #include <config.h>
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include <sys/types.h>
8 #include <unistd.h>
9
10 #include <gdk/gdkx.h>
11 #include <gtk/gtk.h>
12
13 #include <glib/gi18n-lib.h>
14
15 #include "xapp-status-icon.h"
16
17 static const gchar * DBUS_PATH = "/org/x/StatusIcon";
18 static const gchar * DBUS_NAME = "org.x.StatusIcon";
19
20 static const gchar introspection_xml[] =
21 "<node>"
22 " <interface name='org.x.StatusIcon'>"
23 " <method name='ButtonPress'>"
24 " <arg name='x' direction='in' type='i'/>"
25 " <arg name='y' direction='in' type='i'/>"
26 " <arg name='button' direction='in' type='i'/>"
27 " <arg name='time' direction='in' type='i'/>"
28 " <arg name='panel_position' direction='in' type='i'/>"
29 " </method>"
30 " <method name='ButtonRelease'>"
31 " <arg name='x' direction='in' type='i'/>"
32 " <arg name='y' direction='in' type='i'/>"
33 " <arg name='button' direction='in' type='i'/>"
34 " <arg name='time' direction='in' type='i'/>"
35 " <arg name='panel_position' direction='in' type='i'/>"
36 " </method>"
37 " <property type='s' name='Name' access='read'/>"
38 " <property type='s' name='IconName' access='read'/>"
39 " <property type='s' name='TooltipText' access='read'/>"
40 " <property type='s' name='Label' access='read'/>"
41 " <property type='b' name='Visible' access='read'/>"
42 " </interface>"
43 "</node>";
44
45 enum
46 {
47 BUTTON_PRESS,
48 BUTTON_RELEASE,
49 LAST_SIGNAL
50 };
51
52 static guint signals[LAST_SIGNAL] = {0, };
53
54 /**
55 * SECTION:xapp-status-icon
56 * @Short_description: Broadcasts status information over DBUS
57 * @Title: XAppStatusIcon
58 *
59 * The XAppStatusIcon allows applications to share status info
60 * about themselves. It replaces the obsolete and very similar
61 * Gtk.StatusIcon widget.
62 *
63 * If used in an environment where no applet is handling XAppStatusIcons,
64 * The XAppStatusIcon delegates its calls to a Gtk.StatusIcon.
65 */
66 struct _XAppStatusIconPrivate
67 {
68 gchar *name;
69 gchar *icon_name;
70 gchar *tooltip_text;
71 gchar *label;
72 gboolean visible;
73 GDBusConnection *connection;
74 guint owner_id;
75 guint registration_id;
76 GtkStatusIcon *gtk_status_icon;
77 };
78
79 G_DEFINE_TYPE (XAppStatusIcon, xapp_status_icon, G_TYPE_OBJECT);
80
81 void
82 emit_changed_properties_signal (XAppStatusIcon *self)
83 {
84 GVariantBuilder *builder;
85 GError *local_error;
86
87 if (self->priv->connection)
88 {
89 local_error = NULL;
90 builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
91 if (self->priv->name)
92 {
93 g_variant_builder_add (builder, "{sv}", "Name", g_variant_new_string (self->priv->name));
94 }
95 if (self->priv->icon_name)
96 {
97 g_variant_builder_add (builder, "{sv}", "IconName", g_variant_new_string (self->priv->icon_name));
98 }
99 if (self->priv->tooltip_text)
100 {
101 g_variant_builder_add (builder, "{sv}", "TooltipText", g_variant_new_string (self->priv->tooltip_text));
102 }
103 if (self->priv->label)
104 {
105 g_variant_builder_add (builder, "{sv}", "Label", g_variant_new_string (self->priv->label));
106 }
107 if (self->priv->visible)
108 {
109 g_variant_builder_add (builder, "{sv}", "Visible", g_variant_new_boolean (self->priv->visible));
110 }
111 g_dbus_connection_emit_signal (self->priv->connection,
112 NULL,
113 DBUS_PATH,
114 "org.freedesktop.DBus.Properties",
115 "PropertiesChanged",
116 g_variant_new ("(sa{sv}as)", DBUS_NAME, builder, NULL),
117 &local_error);
118 }
119 }
120
121 void
122 handle_method_call (GDBusConnection *connection,
123 const gchar *sender,
124 const gchar *object_path,
125 const gchar *interface_name,
126 const gchar *method_name,
127 GVariant *parameters,
128 GDBusMethodInvocation *invocation,
129 gpointer user_data)
130 {
131 int x, y, time, button, position;
132 XAppStatusIcon *icon = user_data;
133
134 if (g_strcmp0 (method_name, "ButtonPress") == 0)
135 {
136 g_variant_get (parameters, "(iiiii)", &x, &y, &button, &time, &position);
137 g_dbus_method_invocation_return_value (invocation, NULL);
138 g_signal_emit (icon, signals[BUTTON_PRESS], 0, x, y, button, time, position);
139 }
140 else if (g_strcmp0 (method_name, "ButtonRelease") == 0)
141 {
142 g_variant_get (parameters, "(iiiii)", &x, &y, &button, &time, &position);
143 g_dbus_method_invocation_return_value (invocation, NULL);
144 g_signal_emit (icon, signals[BUTTON_RELEASE], 0, x, y, button, time, position);
145 }
146 }
147
148 GVariant *
149 get_property (GDBusConnection *connection,
150 const gchar *sender,
151 const gchar *object_path,
152 const gchar *interface_name,
153 const gchar *property_name,
154 GError **error,
155 gpointer user_data)
156 {
157 GVariant *ret;
158 XAppStatusIcon *icon = user_data;
159 ret = NULL;
160
161 if (icon->priv->name && g_strcmp0 (property_name, "Name") == 0)
162 {
163 ret = g_variant_new_string (icon->priv->name);
164 }
165 else if (icon->priv->icon_name && g_strcmp0 (property_name, "IconName") == 0)
166 {
167 ret = g_variant_new_string (icon->priv->icon_name);
168 }
169 else if (icon->priv->tooltip_text && g_strcmp0 (property_name, "TooltipText") == 0)
170 {
171 ret = g_variant_new_string (icon->priv->tooltip_text);
172 }
173 else if (icon->priv->label && g_strcmp0 (property_name, "Label") == 0)
174 {
175 ret = g_variant_new_string (icon->priv->label);
176 }
177 else if (g_strcmp0 (property_name, "Visible") == 0)
178 {
179 ret = g_variant_new_boolean (icon->priv->visible);
180 }
181
182 return ret;
183 }
184
185 static const GDBusInterfaceVTable interface_vtable =
186 {
187 handle_method_call,
188 get_property,
189 NULL
190 };
191
192 void
193 on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data)
194 {
195 XAppStatusIcon *icon = user_data;
196 icon->priv->connection = connection;
197 GDBusNodeInfo *introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
198 icon->priv->registration_id = g_dbus_connection_register_object (connection,
199 DBUS_PATH,
200 introspection_data->interfaces[0],
201 &interface_vtable,
202 icon, /* user_data */
203 NULL, /* user_data_free_func */
204 NULL); /* GError** */
205 }
206
207 void on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) {}
208 void on_name_lost (GDBusConnection *connection, const gchar *name, gpointer user_data) {}
209
210 static gboolean
211 check_at_least_one_status_applet_is_running ()
212 {
213 // Check that there is at least one applet on DBUS
214 GDBusConnection *connection;
215 GVariant *result;
216 GError *error;
217 GVariantIter *iter;
218 gchar *str;
219 gboolean found = FALSE;
220
221 error = NULL;
222 connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
223 if (connection == NULL)
224 {
225 g_warning("Unable to connect to dbus: %s", error->message);
226 g_printerr ("Error: %s\n", error->message);
227 g_error_free (error);
228 return FALSE;
229 }
230
231 error = NULL;
232 result = g_dbus_connection_call_sync (connection,
233 "org.freedesktop.DBus",
234 "/org/freedesktop/DBus",
235 "org.freedesktop.DBus",
236 "ListNames",
237 NULL,
238 G_VARIANT_TYPE ("(as)"),
239 G_DBUS_CALL_FLAGS_NONE,
240 3000, /* 3 secs */
241 NULL,
242 &error);
243 if (result == NULL)
244 {
245 g_printerr (_("Error: %s\n"), error->message);
246 g_error_free (error);
247 return FALSE;
248 }
249
250 g_variant_get (result, "(as)", &iter);
251 while (g_variant_iter_loop (iter, "s", &str))
252 {
253 if (g_str_has_prefix (str, "org.x.StatusApplet"))
254 {
255 // printf("FOUND %s\n", str);
256 found = TRUE;
257 }
258 }
259 g_variant_iter_free (iter);
260 g_variant_unref (result);
261 return found;
262 }
263
264 static void
265 on_gtk_status_icon_activate (GtkStatusIcon *status_icon, gpointer user_data)
266 {
267 XAppStatusIcon *icon = user_data;
268 g_signal_emit (icon, signals[BUTTON_PRESS], 0, 0, 0, 1, 0, -1);
269 }
270
271 static void
272 on_gtk_status_icon_popup_menu (GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data)
273 {
274 XAppStatusIcon *icon = user_data;
275 g_signal_emit (icon, signals[BUTTON_RELEASE], 0, 0, 0, button, activate_time, -1);
276 }
277
278 static void
279 xapp_status_icon_init (XAppStatusIcon *self)
280 {
281 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, XAPP_TYPE_STATUS_ICON, XAppStatusIconPrivate);
282 self->priv->name = g_strdup_printf("%s", g_get_application_name());
283 self->priv->icon_name = NULL;
284 self->priv->tooltip_text = NULL;
285 self->priv->label = NULL;
286 self->priv->visible = TRUE;
287 self->priv->connection = NULL;
288 self->priv->owner_id = 0;
289 self->priv->registration_id = 0;
290 self->priv->gtk_status_icon = NULL;
291
292 // Check for an applet, if none.. fallback to delegating calls to a Gtk.StatusIcon
293 if (!check_at_least_one_status_applet_is_running())
294 {
295 self->priv->gtk_status_icon = gtk_status_icon_new ();
296 g_signal_connect (self->priv->gtk_status_icon, "activate", G_CALLBACK (on_gtk_status_icon_activate), self);
297 g_signal_connect (self->priv->gtk_status_icon, "popup-menu", G_CALLBACK (on_gtk_status_icon_popup_menu), self);
298 }
299 else
300 {
301 char *owner_name = g_strdup_printf("%s.PID-%d", DBUS_NAME, getpid());
302 self->priv->owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
303 owner_name,
304 G_DBUS_CONNECTION_FLAGS_NONE,
305 on_bus_acquired,
306 on_name_acquired,
307 on_name_lost,
308 self,
309 NULL);
310
311 g_free(owner_name);
312 }
313
314 signals[BUTTON_PRESS] =
315 g_signal_new ("button-press-event",
316 XAPP_TYPE_STATUS_ICON,
317 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
318 0,
319 NULL, NULL, NULL,
320 G_TYPE_NONE, 5, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
321
322 signals[BUTTON_RELEASE] =
323 g_signal_new ("button-release-event",
324 XAPP_TYPE_STATUS_ICON,
325 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
326 0,
327 NULL, NULL, NULL,
328 G_TYPE_NONE, 5, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
329 }
330
331 static void
332 xapp_status_icon_finalize (GObject *object)
333 {
334 XAppStatusIcon *self = XAPP_STATUS_ICON (object);
335
336 g_free (self->priv->name);
337 g_free (self->priv->icon_name);
338 g_free (self->priv->tooltip_text);
339 g_free (self->priv->label);
340
341 if (self->priv->gtk_status_icon != NULL)
342 {
343 g_signal_handlers_disconnect_by_func (self->priv->gtk_status_icon, on_gtk_status_icon_activate, self);
344 g_signal_handlers_disconnect_by_func (self->priv->gtk_status_icon, on_gtk_status_icon_popup_menu, self);
345 g_object_unref (self->priv->gtk_status_icon);
346 }
347
348 if (self->priv->connection != NULL && self->priv->registration_id > 0)
349 {
350 g_dbus_connection_unregister_object(self->priv->connection, self->priv->registration_id);
351 }
352
353 if (self->priv->owner_id > 0)
354 {
355 g_bus_unown_name(self->priv->owner_id);
356 }
357
358 G_OBJECT_CLASS (xapp_status_icon_parent_class)->finalize (object);
359 }
360
361 static void
362 xapp_status_icon_class_init (XAppStatusIconClass *klass)
363 {
364 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
365
366 gobject_class->finalize = xapp_status_icon_finalize;
367
368 g_type_class_add_private (gobject_class, sizeof (XAppStatusIconPrivate));
369 }
370
371 /**
372 * xapp_status_icon_set_name:
373 * @icon: a #XAppStatusIcon
374 * @name: a name (this defaults to the name of the application, if not set)
375 *
376 * Sets the status icon name. This is now shown to users.
377 *
378 * Since: 1.6
379 */
380 void
381 xapp_status_icon_set_name (XAppStatusIcon *icon, const gchar *name)
382 {
383 g_return_if_fail (XAPP_IS_STATUS_ICON (icon));
384 g_free (icon->priv->name);
385 icon->priv->name = g_strdup (name);
386 emit_changed_properties_signal (icon);
387
388 if (icon->priv->gtk_status_icon != NULL)
389 {
390 gtk_status_icon_set_name (icon->priv->gtk_status_icon, name);
391 }
392 }
393
394 /**
395 * xapp_status_icon_set_icon_name:
396 * @icon: a #XAppStatusIcon
397 * @icon_name: an icon name
398 *
399 * Sets the icon name
400 *
401 * Since: 1.6
402 */
403 void
404 xapp_status_icon_set_icon_name (XAppStatusIcon *icon, const gchar *icon_name)
405 {
406 g_return_if_fail (XAPP_IS_STATUS_ICON (icon));
407 g_free (icon->priv->icon_name);
408 icon->priv->icon_name = g_strdup (icon_name);
409 emit_changed_properties_signal (icon);
410
411 if (icon->priv->gtk_status_icon != NULL)
412 {
413 gtk_status_icon_set_from_icon_name (icon->priv->gtk_status_icon, icon_name);
414 }
415 }
416
417 /**
418 * xapp_status_icon_set_tooltip_text:
419 * @icon: a #XAppStatusIcon
420 * @tooltip_text: the text to show in the tooltip
421 *
422 * Sets the tooltip text
423 *
424 * Since: 1.6
425 */
426 void
427 xapp_status_icon_set_tooltip_text (XAppStatusIcon *icon, const gchar *tooltip_text)
428 {
429 g_return_if_fail (XAPP_IS_STATUS_ICON (icon));
430 g_free (icon->priv->tooltip_text);
431 icon->priv->tooltip_text = g_strdup (tooltip_text);
432 emit_changed_properties_signal (icon);
433
434 if (icon->priv->gtk_status_icon != NULL)
435 {
436 gtk_status_icon_set_tooltip_text (icon->priv->gtk_status_icon, tooltip_text);
437 }
438 }
439
440 /**
441 * xapp_status_icon_set_label:
442 * @icon: a #XAppStatusIcon
443 * @label: some text
444 *
445 * Sets a label, shown beside the icon
446 *
447 * Since: 1.6
448 */
449 void
450 xapp_status_icon_set_label (XAppStatusIcon *icon, const gchar *label)
451 {
452 g_return_if_fail (XAPP_IS_STATUS_ICON (icon));
453 g_free (icon->priv->label);
454 icon->priv->label = g_strdup (label);
455 emit_changed_properties_signal (icon);
456 }
457
458 /**
459 * xapp_status_icon_set_visible:
460 * @icon: a #XAppStatusIcon
461 * @visible: whether or not the status icon should be visible
462 *
463 * Sets the visibility of the status icon
464 *
465 * Since: 1.6
466 */
467 void
468 xapp_status_icon_set_visible (XAppStatusIcon *icon, const gboolean visible)
469 {
470 g_return_if_fail (XAPP_IS_STATUS_ICON (icon));
471 icon->priv->visible = visible;
472 emit_changed_properties_signal (icon);
473
474 if (icon->priv->gtk_status_icon != NULL)
475 {
476 gtk_status_icon_set_visible (icon->priv->gtk_status_icon, visible);
477 }
478 }
0 #ifndef __XAPP_STATUS_ICON_H__
1 #define __XAPP_STATUS_ICON_H__
2
3 #include <stdio.h>
4 #include <gtk/gtk.h>
5
6 #include <glib-object.h>
7
8 G_BEGIN_DECLS
9
10 #define XAPP_TYPE_STATUS_ICON (xapp_status_icon_get_type ())
11 #define XAPP_STATUS_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XAPP_TYPE_STATUS_ICON, XAppStatusIcon))
12 #define XAPP_STATUS_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XAPP_TYPE_STATUS_ICON, XAppStatusIconClass))
13 #define XAPP_IS_STATUS_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XAPP_TYPE_STATUS_ICON))
14 #define XAPP_IS_STATUS_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XAPP_TYPE_STATUS_ICON))
15 #define XAPP_STATUS_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XAPP_TYPE_STATUS_ICON, XAppStatusIconClass))
16
17 typedef struct _XAppStatusIconPrivate XAppStatusIconPrivate;
18 typedef struct _XAppStatusIcon XAppStatusIcon;
19 typedef struct _XAppStatusIconClass XAppStatusIconClass;
20
21 struct _XAppStatusIcon
22 {
23 GObject parent_object;
24
25 XAppStatusIconPrivate *priv;
26 };
27
28 struct _XAppStatusIconClass
29 {
30 GObjectClass parent_class;
31 };
32
33 GType xapp_status_icon_get_type (void);
34 void xapp_status_icon_set_name (XAppStatusIcon *icon, const gchar *name);
35 void xapp_status_icon_set_icon_name (XAppStatusIcon *icon, const gchar *icon_name);
36 void xapp_status_icon_set_tooltip_text (XAppStatusIcon *icon, const gchar *tooltip_text);
37 void xapp_status_icon_set_label (XAppStatusIcon *icon, const gchar *label);
38 void xapp_status_icon_set_visible (XAppStatusIcon *icon, const gboolean visible);
39
40 G_END_DECLS
41
42 #endif /* __XAPP_STATUS_ICON_H__ */
0 #!/usr/bin/python3
1 import gi
2 gi.require_version('Gtk', '3.0')
3 from gi.repository import Gio, GLib, GObject, Gtk
4 import os
5 import sys
6
7 DBUS_NAME = "org.x.StatusIcon"
8 DBUS_PATH = "/org/x/StatusIcon"
9
10 class StatusWidget(Gtk.Button):
11
12 def __init__(self, name, bus, dbus_proxy):
13 super(Gtk.Button, self).__init__()
14
15 self.name = name
16 self.bus = bus
17 self.dbus_proxy = dbus_proxy
18 self.properties_proxy = Gio.DBusProxy.new_sync(self.bus, Gio.DBusProxyFlags.NONE, None,
19 name, DBUS_PATH, 'org.freedesktop.DBus.Properties', None)
20 self.proxy = Gio.DBusProxy.new_sync(self.bus, Gio.DBusProxyFlags.NONE, None,
21 name, DBUS_PATH, DBUS_NAME, None)
22
23 owner = self.dbus_proxy.call_sync('GetNameOwner',
24 GLib.Variant('(s)', (name,)),
25 Gio.DBusCallFlags.NO_AUTO_START, 500, None)
26 self.owner_name = owner[0]
27
28 properties = self.properties_proxy.GetAll('(s)', DBUS_NAME)
29
30 box = Gtk.Box()
31 self.image = Gtk.Image()
32 self.label = Gtk.Label()
33 box.add(self.image)
34 box.add(self.label)
35 self.add(box)
36
37 self.update_widget(properties)
38 self.bus.signal_subscribe(sender=self.owner_name, interface_name="org.freedesktop.DBus.Properties", member="PropertiesChanged", object_path=None, arg0=None, flags=0, callback=self.on_properties_changed)
39
40 self.connect("button-press-event", self.on_button_press)
41 self.connect("button-release-event", self.on_button_release)
42
43 def on_properties_changed(self, connection, owner, path, interface, signal_name, properties):
44 self.update_widget(properties[1])
45
46 def update_widget(self, properties):
47 if 'IconName' in properties:
48 self.image.set_from_icon_name(properties['IconName'], Gtk.IconSize.DIALOG)
49 if 'TooltipText' in properties:
50 self.set_tooltip_text(properties['TooltipText'])
51 if 'Label' in properties:
52 self.label.set_text(properties['Label'])
53 if 'Visible' in properties:
54 self.set_visible(properties['Visible'])
55
56 def on_button_press(self, widget, event):
57 # We're simulating a top panel here
58 x = widget.get_window().get_origin().x
59 y = widget.get_window().get_origin().y + widget.get_allocation().height
60 time = event.time
61 print ("Button press : %d:%d" % (x, y))
62 self.proxy.call_sync('ButtonPress',
63 GLib.Variant('(iiiii)', (x, y, event.button, event.time, Gtk.PositionType.TOP,)),
64 Gio.DBusCallFlags.NO_AUTO_START, 500, None)
65
66 def on_button_release(self, widget, event):
67 # We're simulating a top panel here
68 x = widget.get_window().get_origin().x
69 y = widget.get_window().get_origin().y + widget.get_allocation().height
70 time = event.time
71 print ("Button press : %d:%d" % (x, y))
72 self.proxy.call_sync('ButtonRelease',
73 GLib.Variant('(iiiii)', (x, y, event.button, event.time, Gtk.PositionType.TOP,)),
74 Gio.DBusCallFlags.NO_AUTO_START, 500, None)
75
76 class StatusApplet(GObject.Object):
77
78 def __init__(self):
79 super(StatusApplet, self).__init__()
80
81 self.window = Gtk.Window()
82 self.window.connect("destroy", Gtk.main_quit)
83 self.window.show()
84
85 self.indicator_box = Gtk.Box()
86 self.window.add(self.indicator_box)
87
88 self.indicators = {}
89
90 self.bus = Gio.bus_get_sync(Gio.BusType.SESSION)
91
92 # Register an Applet name on DBUS to let icons know there's at least one applet running
93 Gio.bus_own_name(Gio.BusType.SESSION,
94 "org.x.StatusApplet.PID-%d" % os.getpid(),
95 Gio.BusNameOwnerFlags.NONE,
96 None,
97 self.on_name_acquired,
98 self.on_name_lost)
99
100 self.dbus_proxy = Gio.DBusProxy.new_sync(self.bus,
101 Gio.DBusProxyFlags.NONE,
102 None,
103 'org.freedesktop.DBus',
104 '/org/freedesktop/DBus',
105 'org.freedesktop.DBus',
106 None)
107
108 self.refresh_status_items()
109 self.bus.signal_subscribe(None, "org.freedesktop.DBus", "NameOwnerChanged", None, None, 0, self.on_bus_changes, None)
110
111 def on_name_lost(self, connection, name, data=None):
112 print("DBus name couldn't be acquired! Exiting...")
113 Gtk.main_quit()
114
115 def on_name_acquired(self, connection, name, data=None):
116 print("Registering applet on DBUS: %s" % name)
117
118 def refresh_status_items(self):
119 # Find all the status interfaces on the session bus
120 result = self.dbus_proxy.ListNames('()')
121 names = result
122 current_names = []
123 for name in names:
124 if name.startswith(DBUS_NAME):
125 current_names.append(name)
126
127 # Handle new names
128 for name in current_names:
129 if name not in self.indicators.keys():
130 print("Adding %s" % name)
131 self.indicators[name] = StatusWidget(name, self.bus, self.dbus_proxy)
132 self.indicator_box.add(self.indicators[name])
133 self.window.show_all()
134
135 # Handle names which vanishes
136 names_to_remove = []
137 for name in self.indicators.keys():
138 if name not in current_names:
139 names_to_remove.append(name)
140 for name in names_to_remove:
141 print("Removing %s" % name)
142 self.indicator_box.remove(self.indicators[name])
143 del(self.indicators[name])
144
145 def on_bus_changes(self, connection, sender_name, object_path, interface_name, signal_name, parameters, user_data):
146 self.refresh_status_items()
147
148 if __name__ == '__main__':
149 applet = StatusApplet()
150 Gtk.main()
151 sys.exit(0)
0 #!/usr/bin/python3
1
2 import gi
3 gi.require_version('XApp', '1.0')
4 from gi.repository import XApp
5 from gi.repository import GLib, GObject
6 import sys
7
8 class App(GObject.Object):
9
10 def __init__(self):
11 super(App, self).__init__()
12 self.status_icon = XApp.StatusIcon()
13 #self.status_icon.set_name("xapp-status-icon") # optional, defaults to program name, not shown to users
14 self.status_icon.set_icon_name("folder-symbolic")
15 self.status_icon.set_tooltip_text("My tooltip text")
16 self.status_icon.set_label("label 1")
17 self.counter = 1
18 self.status_icon.connect("button-press-event", self.on_button_press)
19 self.status_icon.connect("button-release-event", self.on_button_release)
20
21 GLib.timeout_add_seconds(2, self.on_timeout_cb)
22
23 def on_timeout_cb(self):
24 self.counter += 1
25 self.status_icon.set_label("label %d" % self.counter)
26 # self.status_icon.set_visible((self.counter % 2) == 0)
27 return True
28
29 def on_button_press(self, status_icon, x, y, button, time, position_type):
30 print("Mouse button %d was pressed at %d %d" % (button, x, y))
31
32 def on_button_release(self, status_icon, x, y, button, time, position_type):
33 print("Mouse button %d was released at %d %d" % (button, x, y))
34
35 if __name__ == '__main__':
36 app = App()
37 try:
38 GLib.MainLoop().run()
39 except KeyboardInterrupt:
40 pass
41 sys.exit(0)