2
An object to represent the application as an application indicator
5
Copyright 2009 Canonical Ltd.
8
Ted Gould <ted@canonical.com>
9
Cody Russell <cody.russell@canonical.com>
11
This program is free software: you can redistribute it and/or modify it
12
under the terms of either or both of the following licenses:
14
1) the GNU Lesser General Public License version 3, as published by the
15
Free Software Foundation; and/or
16
2) the GNU Lesser General Public License version 2.1, as published by
17
the Free Software Foundation.
19
This program is distributed in the hope that it will be useful, but
20
WITHOUT ANY WARRANTY; without even the implied warranties of
21
MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
22
PURPOSE. See the applicable version of the GNU Lesser General Public
23
License for more details.
25
You should have received a copy of both the GNU Lesser General Public
26
License version 3 and version 2.1 along with this program. If not, see
27
<http://www.gnu.org/licenses/>
34
#include <dbus/dbus-glib.h>
35
#include <dbus/dbus-glib-bindings.h>
37
#include <libdbusmenu-glib/server.h>
39
#include <libdbusmenu-gtk3/client.h>
41
#include <libdbusmenu-gtk/client.h>
44
#include "app-indicator.h"
45
#include "app-indicator-enum-types.h"
46
#include "application-service-marshal.h"
48
#include "notification-item-server.h"
49
#include "notification-watcher-client.h"
51
#include "dbus-shared.h"
52
#include "generate-id.h"
54
#define PANEL_ICON_SUFFIX "panel"
59
All of the private data in an instance of a
60
application indicator.
63
@id: The ID of the indicator. Maps to AppIndicator:id.
64
@category: Which category the indicator is. Maps to AppIndicator:category.
65
@status: The status of the indicator. Maps to AppIndicator:status.
66
@icon_name: The name of the icon to use. Maps to AppIndicator:icon-name.
67
@attention_icon_name: The name of the attention icon to use. Maps to AppIndicator:attention-icon-name.
68
@menu: The menu for this indicator. Maps to AppIndicator:menu
69
@watcher_proxy: The proxy connection to the watcher we're connected to. If we're not connected to one this will be %NULL.
71
struct _AppIndicatorPrivate {
76
AppIndicatorCategory category;
77
AppIndicatorStatus status;
79
gchar *attention_icon_name;
80
gchar *icon_theme_path;
81
DbusmenuServer *menuservice;
83
guint32 ordering_index;
86
guint label_change_idle;
88
GtkStatusIcon * status_icon;
92
DBusGProxy *watcher_proxy;
93
DBusGConnection *connection;
94
DBusGProxy * dbus_proxy;
109
static guint signals[LAST_SIGNAL] = { 0 };
111
/* Enum for the properties so that they can be quickly
112
found and looked up. */
119
PROP_ATTENTION_ICON_NAME,
120
PROP_ICON_THEME_PATH,
128
PROP_X_ORDERING_INDEX
131
/* The strings so that they can be slowly looked up. */
132
#define PROP_ID_S "id"
133
#define PROP_CATEGORY_S "category"
134
#define PROP_STATUS_S "status"
135
#define PROP_ICON_NAME_S "icon-name"
136
#define PROP_ATTENTION_ICON_NAME_S "attention-icon-name"
137
#define PROP_ICON_THEME_PATH_S "icon-theme-path"
138
#define PROP_MENU_S "menu"
139
#define PROP_CONNECTED_S "connected"
140
#define PROP_LABEL_S "label"
141
#define PROP_LABEL_GUIDE_S "label-guide"
142
#define PROP_X_LABEL_S ("x-ayatana-" PROP_LABEL_S)
143
#define PROP_X_LABEL_GUIDE_S ("x-ayatana-" PROP_LABEL_GUIDE_S)
144
#define PROP_ORDERING_INDEX_S "ordering-index"
145
#define PROP_X_ORDERING_INDEX_S ("x-ayatana-" PROP_ORDERING_INDEX_S)
147
/* Private macro, shhhh! */
148
#define APP_INDICATOR_GET_PRIVATE(o) \
149
(G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_INDICATOR_TYPE, AppIndicatorPrivate))
152
#define APP_INDICATOR_SIGNAL_X_NEW_LABEL ("x-ayatana-" APP_INDICATOR_SIGNAL_NEW_LABEL)
155
#define DEFAULT_ITEM_PATH "/org/ayatana/NotificationItem"
158
#define DEFAULT_FALLBACK_TIMER 100 /* in milliseconds */
161
static void app_indicator_class_init (AppIndicatorClass *klass);
162
static void app_indicator_init (AppIndicator *self);
163
static void app_indicator_dispose (GObject *object);
164
static void app_indicator_finalize (GObject *object);
165
/* Property functions */
166
static void app_indicator_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);
167
static void app_indicator_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);
169
static void signal_label_change (AppIndicator * self);
170
static void check_connect (AppIndicator * self);
171
static void register_service_cb (DBusGProxy * proxy, GError * error, gpointer data);
172
static void start_fallback_timer (AppIndicator * self, gboolean disable_timeout);
173
static gboolean fallback_timer_expire (gpointer data);
174
static GtkStatusIcon * fallback (AppIndicator * self);
175
static void status_icon_status_wrapper (AppIndicator * self, const gchar * status, gpointer data);
176
static void status_icon_changes (AppIndicator * self, gpointer data);
177
static void status_icon_activate (GtkStatusIcon * icon, gpointer data);
178
static void unfallback (AppIndicator * self, GtkStatusIcon * status_icon);
179
static gchar * append_panel_icon_suffix (const gchar * icon_name);
180
static void watcher_proxy_destroyed (GObject * object, gpointer data);
181
static void client_menu_changed (GtkWidget *widget, GtkWidget *child, AppIndicator *indicator);
182
static void submenu_changed (GtkWidget *widget, GtkWidget *child, gpointer data);
184
static void theme_changed_cb (GtkIconTheme * theme, gpointer user_data);
187
G_DEFINE_TYPE (AppIndicator, app_indicator, G_TYPE_OBJECT);
190
app_indicator_class_init (AppIndicatorClass *klass)
192
GObjectClass *object_class = G_OBJECT_CLASS (klass);
194
g_type_class_add_private (klass, sizeof (AppIndicatorPrivate));
197
object_class->dispose = app_indicator_dispose;
198
object_class->finalize = app_indicator_finalize;
201
object_class->set_property = app_indicator_set_property;
202
object_class->get_property = app_indicator_get_property;
205
klass->fallback = fallback;
206
klass->unfallback = unfallback;
213
The ID for this indicator, which should be unique, but used consistently
214
by this program and its indicator.
216
g_object_class_install_property (object_class,
218
g_param_spec_string(PROP_ID_S,
219
"The ID for this indicator",
220
"An ID that should be unique, but used consistently by this program and its indicator.",
222
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
225
AppIndicator:category:
227
The type of indicator that this represents. Please don't use 'Other'.
228
Defaults to 'ApplicationStatus'.
230
g_object_class_install_property (object_class,
232
g_param_spec_string (PROP_CATEGORY_S,
233
"Indicator Category",
234
"The type of indicator that this represents. Please don't use 'other'. Defaults to 'ApplicationStatus'.",
236
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
241
Whether the indicator is shown or requests attention. Defaults to
244
g_object_class_install_property (object_class,
246
g_param_spec_string (PROP_STATUS_S,
248
"Whether the indicator is shown or requests attention. Defaults to 'Passive'.",
250
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
253
AppIndicator:icon-name:
255
The name of the regular icon that is shown for the indicator.
257
g_object_class_install_property(object_class,
259
g_param_spec_string (PROP_ICON_NAME_S,
260
"An icon for the indicator",
261
"The default icon that is shown for the indicator.",
263
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
266
AppIndicator:attention-icon-name:
268
If the indicator sets it's status to %APP_INDICATOR_STATUS_ATTENTION
269
then this icon is shown.
271
g_object_class_install_property (object_class,
272
PROP_ATTENTION_ICON_NAME,
273
g_param_spec_string (PROP_ATTENTION_ICON_NAME_S,
274
"An icon to show when the indicator request attention.",
275
"If the indicator sets it's status to 'attention' then this icon is shown.",
277
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
279
AppIndicator:icon-theme-path:
281
An additional place to look for icon names that may be installed by the
284
g_object_class_install_property(object_class,
285
PROP_ICON_THEME_PATH,
286
g_param_spec_string (PROP_ICON_THEME_PATH_S,
287
"An additional path for custom icons.",
288
"An additional place to look for icon names that may be installed by the application.",
290
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
295
A method for getting the menu path as a string for DBus.
297
g_object_class_install_property(object_class,
299
g_param_spec_boxed (PROP_MENU_S,
300
"The object path of the menu on DBus.",
301
"A method for getting the menu path as a string for DBus.",
302
DBUS_TYPE_G_OBJECT_PATH,
303
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
306
AppIndicator:connected:
308
Pretty simple, %TRUE if we have a reasonable expectation of being
309
displayed through this object. You should hide your TrayIcon if so.
311
g_object_class_install_property (object_class,
313
g_param_spec_boolean (PROP_CONNECTED_S,
314
"Whether we're conneced to a watcher",
315
"Pretty simple, true if we have a reasonable expectation of being displayed through this object. You should hide your TrayIcon if so.",
317
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
321
A label that can be shown next to the string in the application
322
indicator. The label will not be shown unless there is an icon
323
as well. The label is useful for numerical and other frequently
324
updated information. In general, it shouldn't be shown unless a
325
user requests it as it can take up a significant amount of space
326
on the user's panel. This may not be shown in all visualizations.
328
g_object_class_install_property(object_class,
330
g_param_spec_string (PROP_LABEL_S,
331
"A label next to the icon",
332
"A label to provide dynamic information.",
334
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
336
AppIndicator:label-guide:
338
An optional string to provide guidance to the panel on how big
339
the #AppIndicator:label string could get. If this is set correctly
340
then the panel should never 'jiggle' as the string adjusts through
341
out the range of options. For instance, if you were providing a
342
percentage like "54% thrust" in #AppIndicator:label you'd want to
343
set this string to "100% thrust" to ensure space when Scotty can
344
get you enough power.
346
g_object_class_install_property(object_class,
348
g_param_spec_string (PROP_LABEL_GUIDE_S,
349
"A string to size the space available for the label.",
350
"To ensure that the label does not cause the panel to 'jiggle' this string should provide information on how much space it could take.",
352
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
354
AppIndicator:ordering-index:
356
The ordering index is an odd parameter, and if you think you don't need
357
it you're probably right. In general, the application indicator try
358
to place the applications in a recreatable place taking into account
359
which category they're in to try and group them. But, there are some
360
cases where you'd want to ensure indicators are next to each other.
361
To do that you can override the generated ordering index and replace it
362
with a new one. Again, you probably don't want to be doing this, but
363
in case you do, this is the way.
365
g_object_class_install_property(object_class,
367
g_param_spec_uint (PROP_ORDERING_INDEX_S,
368
"The location that this app indicator should be in the list.",
369
"A way to override the default ordering of the applications by providing a very specific idea of where this entry should be placed.",
371
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
373
AppIndicator:x-ayatana-ordering-index:
375
A wrapper for #AppIndicator:ordering-index so that it can match the
376
dbus interface currently. It will hopefully be retired, please don't
379
g_object_class_install_property(object_class,
380
PROP_X_ORDERING_INDEX,
381
g_param_spec_uint (PROP_X_ORDERING_INDEX_S,
382
"A wrapper, please don't use.",
383
"A wrapper, please don't use.",
385
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
388
AppIndicator:x-ayatana-label:
390
Wrapper for #AppIndicator:label. Please use that in all of your
393
g_object_class_install_property(object_class,
395
g_param_spec_string (PROP_X_LABEL_S,
396
"A wrapper, please don't use.",
397
"A wrapper, please don't use.",
399
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
401
AppIndicator:x-ayatana-label-guide:
403
Wrapper for #AppIndicator:label-guide. Please use that in all of your
406
g_object_class_install_property(object_class,
408
g_param_spec_string (PROP_X_LABEL_GUIDE_S,
409
"A wrapper, please don't use.",
410
"A wrapper, please don't use.",
412
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
417
AppIndicator::new-icon:
418
@arg0: The #AppIndicator object
420
Emitted when #AppIndicator:icon-name is changed
422
signals[NEW_ICON] = g_signal_new (APP_INDICATOR_SIGNAL_NEW_ICON,
423
G_TYPE_FROM_CLASS(klass),
425
G_STRUCT_OFFSET (AppIndicatorClass, new_icon),
427
g_cclosure_marshal_VOID__VOID,
428
G_TYPE_NONE, 0, G_TYPE_NONE);
431
AppIndicator::new-attention-icon:
432
@arg0: The #AppIndicator object
434
Emitted when #AppIndicator:attention-icon-name is changed
436
signals[NEW_ATTENTION_ICON] = g_signal_new (APP_INDICATOR_SIGNAL_NEW_ATTENTION_ICON,
437
G_TYPE_FROM_CLASS(klass),
439
G_STRUCT_OFFSET (AppIndicatorClass, new_attention_icon),
441
g_cclosure_marshal_VOID__VOID,
442
G_TYPE_NONE, 0, G_TYPE_NONE);
445
AppIndicator::new-status:
446
@arg0: The #AppIndicator object
447
@arg1: The string value of the #AppIndicatorStatus enum.
449
Emitted when #AppIndicator:status is changed
451
signals[NEW_STATUS] = g_signal_new (APP_INDICATOR_SIGNAL_NEW_STATUS,
452
G_TYPE_FROM_CLASS(klass),
454
G_STRUCT_OFFSET (AppIndicatorClass, new_status),
456
g_cclosure_marshal_VOID__STRING,
461
AppIndicator::new-label:
462
@arg0: The #AppIndicator object
463
@arg1: The string for the label
464
@arg1: The string for the guide
466
Emitted when either #AppIndicator:label or #AppIndicator:label-guide are
469
signals[NEW_LABEL] = g_signal_new (APP_INDICATOR_SIGNAL_NEW_LABEL,
470
G_TYPE_FROM_CLASS(klass),
472
G_STRUCT_OFFSET (AppIndicatorClass, new_label),
474
_application_service_marshal_VOID__STRING_STRING,
475
G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
478
AppIndicator::x-ayatana-new-label:
479
@arg0: The #AppIndicator object
480
@arg1: The string for the label
481
@arg1: The string for the guide
483
Wrapper for #AppIndicator::new-label, please don't use this signal
486
signals[X_NEW_LABEL] = g_signal_new (APP_INDICATOR_SIGNAL_X_NEW_LABEL,
487
G_TYPE_FROM_CLASS(klass),
489
G_STRUCT_OFFSET (AppIndicatorClass, new_label),
491
_application_service_marshal_VOID__STRING_STRING,
492
G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
495
AppIndicator::connection-changed:
496
@arg0: The #AppIndicator object
497
@arg1: Whether we're connected or not
499
Signaled when we connect to a watcher, or when it drops away.
501
signals[CONNECTION_CHANGED] = g_signal_new (APP_INDICATOR_SIGNAL_CONNECTION_CHANGED,
502
G_TYPE_FROM_CLASS(klass),
504
G_STRUCT_OFFSET (AppIndicatorClass, connection_changed),
506
g_cclosure_marshal_VOID__BOOLEAN,
507
G_TYPE_NONE, 1, G_TYPE_BOOLEAN, G_TYPE_NONE);
510
AppIndicator::new-icon-theme-path:
511
@arg0: The #AppIndicator object
513
Signaled when there is a new icon set for the
516
signals[NEW_ICON_THEME_PATH] = g_signal_new (APP_INDICATOR_SIGNAL_NEW_ICON_THEME_PATH,
517
G_TYPE_FROM_CLASS(klass),
519
G_STRUCT_OFFSET (AppIndicatorClass, new_icon_theme_path),
521
g_cclosure_marshal_VOID__STRING,
522
G_TYPE_NONE, 1, G_TYPE_STRING);
524
/* Initialize the object as a DBus type */
525
dbus_g_object_type_install_info(APP_INDICATOR_TYPE,
526
&dbus_glib__notification_item_server_object_info);
532
app_indicator_init (AppIndicator *self)
534
AppIndicatorPrivate * priv = APP_INDICATOR_GET_PRIVATE(self);
537
priv->clean_id = NULL;
538
priv->category = APP_INDICATOR_CATEGORY_OTHER;
539
priv->status = APP_INDICATOR_STATUS_PASSIVE;
540
priv->icon_name = NULL;
541
priv->attention_icon_name = NULL;
542
priv->icon_theme_path = NULL;
544
priv->menuservice = NULL;
545
priv->ordering_index = 0;
547
priv->label_guide = NULL;
548
priv->label_change_idle = 0;
550
priv->watcher_proxy = NULL;
551
priv->connection = NULL;
552
priv->dbus_proxy = NULL;
554
priv->status_icon = NULL;
555
priv->fallback_timer = 0;
557
/* Put the object on DBus */
558
GError * error = NULL;
559
priv->connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
561
g_error("Unable to connect to the session bus when creating application indicator: %s", error->message);
565
dbus_g_connection_ref(priv->connection);
567
g_signal_connect(G_OBJECT(gtk_icon_theme_get_default()),
568
"changed", G_CALLBACK(theme_changed_cb), self);
575
/* Free all objects, make sure that all the dbus
576
signals are sent out before we shut this down. */
578
app_indicator_dispose (GObject *object)
580
AppIndicator *self = APP_INDICATOR (object);
581
AppIndicatorPrivate *priv = self->priv;
583
if (priv->status != APP_INDICATOR_STATUS_PASSIVE) {
584
app_indicator_set_status(self, APP_INDICATOR_STATUS_PASSIVE);
587
if (priv->status_icon != NULL) {
588
AppIndicatorClass * class = APP_INDICATOR_GET_CLASS(object);
589
if (class->unfallback != NULL) {
590
class->unfallback(self, priv->status_icon);
592
priv->status_icon = NULL;
595
if (priv->fallback_timer != 0) {
596
g_source_remove(priv->fallback_timer);
597
priv->fallback_timer = 0;
600
if (priv->label_change_idle != 0) {
601
g_source_remove(priv->label_change_idle);
602
priv->label_change_idle = 0;
605
if (priv->menu != NULL) {
606
g_signal_handlers_disconnect_by_func (G_OBJECT (priv->menu),
609
g_object_unref(G_OBJECT(priv->menu));
613
if (priv->menuservice != NULL) {
614
g_object_unref (priv->menuservice);
617
if (priv->dbus_proxy != NULL) {
618
g_object_unref(G_OBJECT(priv->dbus_proxy));
619
priv->dbus_proxy = NULL;
622
if (priv->watcher_proxy != NULL) {
623
dbus_g_connection_flush(priv->connection);
624
g_signal_handlers_disconnect_by_func(G_OBJECT(priv->watcher_proxy), watcher_proxy_destroyed, self);
625
g_object_unref(G_OBJECT(priv->watcher_proxy));
626
priv->watcher_proxy = NULL;
628
/* Emit the AppIndicator::connection-changed signal*/
629
g_signal_emit (self, signals[CONNECTION_CHANGED], 0, FALSE);
632
if (priv->connection != NULL) {
633
dbus_g_connection_unref(priv->connection);
634
priv->connection = NULL;
637
G_OBJECT_CLASS (app_indicator_parent_class)->dispose (object);
641
/* Free all of the memory that we could be using in
644
app_indicator_finalize (GObject *object)
646
AppIndicator * self = APP_INDICATOR(object);
647
AppIndicatorPrivate *priv = self->priv;
649
if (priv->status != APP_INDICATOR_STATUS_PASSIVE) {
650
g_warning("Finalizing Application Status with the status set to: %d", priv->status);
653
if (priv->id != NULL) {
658
if (priv->clean_id != NULL) {
659
g_free(priv->clean_id);
660
priv->clean_id = NULL;
663
if (priv->icon_name != NULL) {
664
g_free(priv->icon_name);
665
priv->icon_name = NULL;
668
if (priv->attention_icon_name != NULL) {
669
g_free(priv->attention_icon_name);
670
priv->attention_icon_name = NULL;
673
if (priv->icon_theme_path != NULL) {
674
g_free(priv->icon_theme_path);
675
priv->icon_theme_path = NULL;
678
if (priv->label != NULL) {
683
if (priv->label_guide != NULL) {
684
g_free(priv->label_guide);
685
priv->label_guide = NULL;
688
G_OBJECT_CLASS (app_indicator_parent_class)->finalize (object);
692
#define WARN_BAD_TYPE(prop, value) g_warning("Can not work with property '%s' with value of type '%s'.", prop, G_VALUE_TYPE_NAME(value))
694
/* Set some properties */
696
app_indicator_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
698
AppIndicator *self = APP_INDICATOR (object);
699
AppIndicatorPrivate *priv = self->priv;
700
GEnumValue *enum_val;
704
if (priv->id != NULL) {
705
g_warning ("Resetting ID value when I already had a value of: %s", priv->id);
709
priv->id = g_strdup (g_value_get_string (value));
711
priv->clean_id = g_strdup(priv->id);
713
for (cleaner = priv->clean_id; *cleaner != '\0'; cleaner++) {
714
if (!g_ascii_isalnum(*cleaner)) {
719
check_connect (self);
723
enum_val = g_enum_get_value_by_nick ((GEnumClass *) g_type_class_ref (APP_INDICATOR_TYPE_INDICATOR_CATEGORY),
724
g_value_get_string (value));
726
if (priv->category != enum_val->value)
728
priv->category = enum_val->value;
734
enum_val = g_enum_get_value_by_nick ((GEnumClass *) g_type_class_ref (APP_INDICATOR_TYPE_INDICATOR_STATUS),
735
g_value_get_string (value));
737
app_indicator_set_status (APP_INDICATOR (object),
742
app_indicator_set_icon (APP_INDICATOR (object),
743
g_value_get_string (value));
744
check_connect (self);
747
case PROP_ATTENTION_ICON_NAME:
748
app_indicator_set_attention_icon (APP_INDICATOR (object),
749
g_value_get_string (value));
752
case PROP_ICON_THEME_PATH:
753
app_indicator_set_icon_theme_path (APP_INDICATOR (object),
754
g_value_get_string (value));
755
check_connect (self);
760
gchar * oldlabel = priv->label;
761
priv->label = g_value_dup_string(value);
763
if (g_strcmp0(oldlabel, priv->label) != 0) {
764
signal_label_change(APP_INDICATOR(object));
767
if (priv->label != NULL && priv->label[0] == '\0') {
772
if (oldlabel != NULL) {
777
case PROP_X_LABEL_GUIDE:
778
case PROP_LABEL_GUIDE: {
779
gchar * oldguide = priv->label_guide;
780
priv->label_guide = g_value_dup_string(value);
782
if (g_strcmp0(oldguide, priv->label_guide) != 0) {
783
signal_label_change(APP_INDICATOR(object));
786
if (priv->label_guide != NULL && priv->label_guide[0] == '\0') {
787
g_free(priv->label_guide);
788
priv->label_guide = NULL;
791
if (oldguide != NULL) {
796
case PROP_X_ORDERING_INDEX:
797
case PROP_ORDERING_INDEX:
798
priv->ordering_index = g_value_get_uint(value);
802
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
809
/* Function to fill our value with the property it's requesting. */
811
app_indicator_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
813
AppIndicator *self = APP_INDICATOR (object);
814
AppIndicatorPrivate *priv = self->priv;
815
GEnumValue *enum_value;
819
g_value_set_string (value, priv->id);
823
enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (APP_INDICATOR_TYPE_INDICATOR_CATEGORY), priv->category);
824
g_value_set_string (value, enum_value->value_nick);
828
enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (APP_INDICATOR_TYPE_INDICATOR_STATUS), priv->status);
829
g_value_set_string (value, enum_value->value_nick);
833
g_value_set_string (value, priv->icon_name);
836
case PROP_ATTENTION_ICON_NAME:
837
g_value_set_string (value, priv->attention_icon_name);
840
case PROP_ICON_THEME_PATH:
841
g_value_set_string (value, priv->icon_theme_path);
845
if (priv->menuservice != NULL) {
846
GValue strval = { 0 };
847
g_value_init(&strval, G_TYPE_STRING);
848
g_object_get_property (G_OBJECT (priv->menuservice), DBUSMENU_SERVER_PROP_DBUS_OBJECT, &strval);
849
g_value_set_boxed(value, g_value_get_string(&strval));
850
g_value_unset(&strval);
855
g_value_set_boolean (value, priv->watcher_proxy != NULL ? TRUE : FALSE);
860
g_value_set_string (value, priv->label);
863
case PROP_X_LABEL_GUIDE:
864
case PROP_LABEL_GUIDE:
865
g_value_set_string (value, priv->label_guide);
868
case PROP_X_ORDERING_INDEX:
869
case PROP_ORDERING_INDEX:
870
g_value_set_uint(value, priv->ordering_index);
874
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
881
/* Sends the label changed signal and resets the source ID */
883
signal_label_change_idle (gpointer user_data)
885
AppIndicator * self = (AppIndicator *)user_data;
886
AppIndicatorPrivate *priv = self->priv;
888
g_signal_emit(G_OBJECT(self), signals[NEW_LABEL], 0,
889
priv->label != NULL ? priv->label : "",
890
priv->label_guide != NULL ? priv->label_guide : "",
892
g_signal_emit(G_OBJECT(self), signals[X_NEW_LABEL], 0,
893
priv->label != NULL ? priv->label : "",
894
priv->label_guide != NULL ? priv->label_guide : "",
897
priv->label_change_idle = 0;
902
/* Sets up an idle function to send the label changed signal
903
so that we don't send it too many times. */
905
signal_label_change (AppIndicator * self)
907
AppIndicatorPrivate *priv = self->priv;
909
/* don't set it twice */
910
if (priv->label_change_idle != 0) {
914
priv->label_change_idle = g_idle_add(signal_label_change_idle, self);
918
/* This function is used to see if we have enough information to
919
connect to things. If we do, and we're not connected, it
922
check_connect (AppIndicator *self)
924
AppIndicatorPrivate *priv = self->priv;
926
/* We're alreadying connecting or trying to connect. */
927
if (priv->watcher_proxy != NULL) return;
929
/* Do we have enough information? */
930
if (priv->menu == NULL) return;
931
if (priv->icon_name == NULL) return;
932
if (priv->id == NULL) return;
934
gchar * path = g_strdup_printf(DEFAULT_ITEM_PATH "/%s", priv->clean_id);
936
dbus_g_connection_register_g_object(priv->connection,
940
GError * error = NULL;
941
priv->watcher_proxy = dbus_g_proxy_new_for_name_owner(priv->connection,
942
NOTIFICATION_WATCHER_DBUS_ADDR,
943
NOTIFICATION_WATCHER_DBUS_OBJ,
944
NOTIFICATION_WATCHER_DBUS_IFACE,
947
/* Unable to get proxy, but we're handling that now so
948
it's not a warning anymore. */
950
dbus_g_connection_unregister_g_object(priv->connection,
952
start_fallback_timer(self, FALSE);
957
g_signal_connect(G_OBJECT(priv->watcher_proxy), "destroy", G_CALLBACK(watcher_proxy_destroyed), self);
958
org_kde_StatusNotifierWatcher_register_status_notifier_item_async(priv->watcher_proxy, path, register_service_cb, self);
961
/* Emit the AppIndicator::connection-changed signal*/
962
g_signal_emit (self, signals[CONNECTION_CHANGED], 0, TRUE);
967
/* A function that gets called when the watcher dies. Like
968
dies dies. Not our friend anymore. */
970
watcher_proxy_destroyed (GObject * object, gpointer data)
972
AppIndicator * self = APP_INDICATOR(data);
973
g_return_if_fail(self != NULL);
975
dbus_g_connection_unregister_g_object(self->priv->connection,
977
self->priv->watcher_proxy = NULL;
979
/* Emit the AppIndicator::connection-changed signal*/
980
g_signal_emit (self, signals[CONNECTION_CHANGED], 0, FALSE);
982
start_fallback_timer(self, FALSE);
986
/* Responce from the DBus command to register a service
987
with a NotificationWatcher. */
989
register_service_cb (DBusGProxy * proxy, GError * error, gpointer data)
991
g_return_if_fail(IS_APP_INDICATOR(data));
992
AppIndicatorPrivate * priv = APP_INDICATOR(data)->priv;
995
/* They didn't respond, ewww. Not sure what they could
997
g_warning("Unable to connect to the Notification Watcher: %s", error->message);
998
dbus_g_connection_unregister_g_object(priv->connection,
1000
g_object_unref(G_OBJECT(priv->watcher_proxy));
1001
priv->watcher_proxy = NULL;
1002
start_fallback_timer(APP_INDICATOR(data), TRUE);
1005
if (priv->status_icon) {
1006
AppIndicatorClass * class = APP_INDICATOR_GET_CLASS(data);
1007
if (class->unfallback != NULL) {
1008
class->unfallback(APP_INDICATOR(data), priv->status_icon);
1009
priv->status_icon = NULL;
1016
/* A helper function to get the nick out of a given
1017
category enum value. */
1018
static const gchar *
1019
category_from_enum (AppIndicatorCategory category)
1023
value = g_enum_get_value ((GEnumClass *)g_type_class_ref (APP_INDICATOR_TYPE_INDICATOR_CATEGORY), category);
1024
return value->value_nick;
1027
/* Watching the dbus owner change events to see if someone
1028
we care about pops up! */
1030
dbus_owner_change (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, gpointer data)
1032
if (new == NULL || new[0] == '\0') {
1033
/* We only care about folks coming on the bus. Exit quickly otherwise. */
1037
if (g_strcmp0(name, NOTIFICATION_WATCHER_DBUS_ADDR)) {
1038
/* We only care about this address, reject all others. */
1042
/* Woot, there's a new notification watcher in town. */
1044
AppIndicatorPrivate * priv = APP_INDICATOR_GET_PRIVATE(data);
1046
if (priv->fallback_timer != 0) {
1048
g_source_remove(priv->fallback_timer);
1050
/* Stop listening to bus events */
1051
g_object_unref(G_OBJECT(priv->dbus_proxy));
1052
priv->dbus_proxy = NULL;
1055
/* Let's start from the very beginning */
1056
check_connect(APP_INDICATOR(data));
1061
/* Checking to see if someone already has the name we're looking for */
1063
check_owner_cb (DBusGProxy *proxy, gboolean exists, GError *error, gpointer userdata)
1065
if (error != NULL) {
1066
g_warning("Unable to check for '" NOTIFICATION_WATCHER_DBUS_ADDR "' on DBus. No worries, but concerning.");
1071
g_debug("Woah, we actually has a race condition with dbus");
1072
dbus_owner_change(proxy, NOTIFICATION_WATCHER_DBUS_ADDR, NULL, "Non NULL", userdata);
1078
/* This is an idle function to create the proxy. This is mostly
1079
because start_fallback_timer can get called in the distruction
1080
of a proxy and thus the proxy manager gets confused when creating
1081
a new proxy as part of destroying an old one. This function being
1082
on idle means that we'll just do it outside of the same stack where
1083
the previous proxy is being destroyed. */
1085
setup_name_owner_proxy (gpointer data)
1087
g_return_val_if_fail(IS_APP_INDICATOR(data), FALSE);
1088
AppIndicatorPrivate * priv = APP_INDICATOR(data)->priv;
1090
if (priv->dbus_proxy == NULL) {
1091
priv->dbus_proxy = dbus_g_proxy_new_for_name(priv->connection,
1094
DBUS_INTERFACE_DBUS);
1095
dbus_g_proxy_add_signal(priv->dbus_proxy, "NameOwnerChanged",
1096
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
1098
dbus_g_proxy_connect_signal(priv->dbus_proxy, "NameOwnerChanged",
1099
G_CALLBACK(dbus_owner_change), data, NULL);
1101
/* Check to see if anyone has the name we're looking for
1102
just incase we missed it changing. */
1104
org_freedesktop_DBus_name_has_owner_async(priv->dbus_proxy, NOTIFICATION_WATCHER_DBUS_ADDR, check_owner_cb, data);
1110
/* A function that will start the fallback timer if it's not
1111
already started. It sets up the DBus watcher to see if
1112
there is a change. Also, provides an override mode for cases
1113
where it's unlikely that a timer will help anything. */
1115
start_fallback_timer (AppIndicator * self, gboolean disable_timeout)
1117
g_return_if_fail(IS_APP_INDICATOR(self));
1118
AppIndicatorPrivate * priv = APP_INDICATOR(self)->priv;
1120
if (priv->fallback_timer != 0) {
1121
/* The timer is set, let's just be happy with the one
1122
we've already got running */
1126
if (priv->status_icon != NULL) {
1127
/* We're already fallen back. Let's not do it again. */
1131
if (priv->dbus_proxy == NULL) {
1132
/* NOTE: Read the comment on setup_name_owner_proxy */
1133
g_idle_add(setup_name_owner_proxy, self);
1136
if (disable_timeout) {
1137
fallback_timer_expire(self);
1139
priv->fallback_timer = g_timeout_add(DEFAULT_FALLBACK_TIMER, fallback_timer_expire, self);
1145
/* A function that gets executed when we want to change the
1146
state of the fallback. */
1148
fallback_timer_expire (gpointer data)
1150
g_return_val_if_fail(IS_APP_INDICATOR(data), FALSE);
1152
AppIndicatorPrivate * priv = APP_INDICATOR(data)->priv;
1153
AppIndicatorClass * class = APP_INDICATOR_GET_CLASS(data);
1155
if (priv->status_icon == NULL) {
1156
if (class->fallback != NULL) {
1157
priv->status_icon = class->fallback(APP_INDICATOR(data));
1160
if (class->unfallback != NULL) {
1161
class->unfallback(APP_INDICATOR(data), priv->status_icon);
1162
priv->status_icon = NULL;
1164
g_warning("No 'unfallback' function but the 'fallback' function returned a non-NULL result.");
1168
priv->fallback_timer = 0;
1172
/* emit a NEW_ICON signal in response for the theme change */
1174
theme_changed_cb (GtkIconTheme * theme, gpointer user_data)
1176
g_signal_emit (user_data, signals[NEW_ICON], 0, TRUE);
1179
/* Creates a StatusIcon that can be used when the application
1180
indicator area isn't available. */
1181
static GtkStatusIcon *
1182
fallback (AppIndicator * self)
1184
GtkStatusIcon * icon = gtk_status_icon_new();
1186
gtk_status_icon_set_title(icon, app_indicator_get_id(self));
1188
g_signal_connect(G_OBJECT(self), APP_INDICATOR_SIGNAL_NEW_STATUS,
1189
G_CALLBACK(status_icon_status_wrapper), icon);
1190
g_signal_connect(G_OBJECT(self), APP_INDICATOR_SIGNAL_NEW_ICON,
1191
G_CALLBACK(status_icon_changes), icon);
1192
g_signal_connect(G_OBJECT(self), APP_INDICATOR_SIGNAL_NEW_ATTENTION_ICON,
1193
G_CALLBACK(status_icon_changes), icon);
1195
status_icon_changes(self, icon);
1197
g_signal_connect(G_OBJECT(icon), "activate", G_CALLBACK(status_icon_activate), self);
1202
/* A wrapper as the status update prototype is a little
1203
bit different, but we want to handle it the same. */
1205
status_icon_status_wrapper (AppIndicator * self, const gchar * status, gpointer data)
1207
return status_icon_changes(self, data);
1210
/* This tracks changes to either the status or the icons
1211
that are associated with the app indicator */
1213
status_icon_changes (AppIndicator * self, gpointer data)
1215
GtkStatusIcon * icon = GTK_STATUS_ICON(data);
1216
GIcon *themed_icon = NULL;
1217
gchar *longname = NULL;
1219
switch (app_indicator_get_status(self)) {
1220
case APP_INDICATOR_STATUS_PASSIVE:
1221
longname = append_panel_icon_suffix(app_indicator_get_icon(self));
1222
themed_icon = g_themed_icon_new_with_default_fallbacks (longname);
1223
gtk_status_icon_set_visible(icon, FALSE);
1224
gtk_status_icon_set_from_gicon(icon, themed_icon);
1226
case APP_INDICATOR_STATUS_ACTIVE:
1227
longname = append_panel_icon_suffix(app_indicator_get_icon(self));
1228
themed_icon = g_themed_icon_new_with_default_fallbacks (longname);
1229
gtk_status_icon_set_from_gicon(icon, themed_icon);
1230
gtk_status_icon_set_visible(icon, TRUE);
1232
case APP_INDICATOR_STATUS_ATTENTION:
1233
longname = append_panel_icon_suffix(app_indicator_get_attention_icon(self));
1234
themed_icon = g_themed_icon_new_with_default_fallbacks (longname);
1235
gtk_status_icon_set_from_gicon(icon, themed_icon);
1236
gtk_status_icon_set_visible(icon, TRUE);
1241
g_object_unref (themed_icon);
1251
/* Handles the activate action by the status icon by showing
1252
the menu in a popup. */
1254
status_icon_activate (GtkStatusIcon * icon, gpointer data)
1256
GtkMenu * menu = app_indicator_get_menu(APP_INDICATOR(data));
1260
gtk_menu_popup(menu,
1261
NULL, /* Parent Menu */
1262
NULL, /* Parent item */
1263
gtk_status_icon_position_menu,
1266
gtk_get_current_event_time());
1271
/* Removes the status icon as the application indicator area
1272
is now up and running again. */
1274
unfallback (AppIndicator * self, GtkStatusIcon * status_icon)
1276
g_signal_handlers_disconnect_by_func(G_OBJECT(self), status_icon_status_wrapper, status_icon);
1277
g_signal_handlers_disconnect_by_func(G_OBJECT(self), status_icon_changes, status_icon);
1278
gtk_status_icon_set_visible(status_icon, FALSE);
1279
g_object_unref(G_OBJECT(status_icon));
1283
/* A helper function that appends PANEL_ICON_SUFFIX to the given icon name
1286
append_panel_icon_suffix (const gchar *icon_name)
1288
gchar * long_name = NULL;
1290
if (!g_str_has_suffix (icon_name, PANEL_ICON_SUFFIX)) {
1292
g_strdup_printf("%s-%s", icon_name, PANEL_ICON_SUFFIX);
1294
long_name = g_strdup (icon_name);
1301
/* ************************* */
1302
/* Public Functions */
1303
/* ************************* */
1307
@id: The unique id of the indicator to create.
1308
@icon_name: The icon name for this indicator
1309
@category: The category of indicator.
1311
Creates a new #AppIndicator setting the properties:
1312
#AppIndicator:id with @id, #AppIndicator:category
1313
with @category and #AppIndicator:icon-name with
1316
Return value: A pointer to a new #AppIndicator object.
1319
app_indicator_new (const gchar *id,
1320
const gchar *icon_name,
1321
AppIndicatorCategory category)
1323
AppIndicator *indicator = g_object_new (APP_INDICATOR_TYPE,
1325
PROP_CATEGORY_S, category_from_enum (category),
1326
PROP_ICON_NAME_S, icon_name,
1333
app_indicator_new_with_path:
1334
@id: The unique id of the indicator to create.
1335
@icon_name: The icon name for this indicator
1336
@category: The category of indicator.
1337
@icon_theme_path: A custom path for finding icons.
1339
Creates a new #AppIndicator setting the properties:
1340
#AppIndicator:id with @id, #AppIndicator:category
1341
with @category, #AppIndicator:icon-name with
1342
@icon_name and #AppIndicator:icon-theme-path with @icon_theme_path.
1344
Return value: A pointer to a new #AppIndicator object.
1347
app_indicator_new_with_path (const gchar *id,
1348
const gchar *icon_name,
1349
AppIndicatorCategory category,
1350
const gchar *icon_theme_path)
1352
AppIndicator *indicator = g_object_new (APP_INDICATOR_TYPE,
1354
PROP_CATEGORY_S, category_from_enum (category),
1355
PROP_ICON_NAME_S, icon_name,
1356
PROP_ICON_THEME_PATH_S, icon_theme_path,
1363
app_indicator_get_type:
1365
Generates or returns the unique #GType for #AppIndicator.
1367
Return value: A unique #GType for #AppIndicator objects.
1371
app_indicator_set_status:
1372
@self: The #AppIndicator object to use
1373
@status: The status to set for this indicator
1375
Wrapper function for property #AppIndicator:status.
1378
app_indicator_set_status (AppIndicator *self, AppIndicatorStatus status)
1380
g_return_if_fail (IS_APP_INDICATOR (self));
1382
if (self->priv->status != status)
1384
GEnumValue *value = g_enum_get_value ((GEnumClass *) g_type_class_ref (APP_INDICATOR_TYPE_INDICATOR_STATUS), status);
1386
self->priv->status = status;
1387
g_signal_emit (self, signals[NEW_STATUS], 0, value->value_nick);
1392
app_indicator_set_attention_icon:
1393
@self: The #AppIndicator object to use
1394
@icon_name: The name of the attention icon to set for this indicator
1396
Wrapper function for property #AppIndicator:attention-icon-name.
1399
app_indicator_set_attention_icon (AppIndicator *self, const gchar *icon_name)
1401
g_return_if_fail (IS_APP_INDICATOR (self));
1402
g_return_if_fail (icon_name != NULL);
1404
if (g_strcmp0 (self->priv->attention_icon_name, icon_name) != 0)
1406
if (self->priv->attention_icon_name)
1407
g_free (self->priv->attention_icon_name);
1409
self->priv->attention_icon_name = g_strdup(icon_name);
1411
g_signal_emit (self, signals[NEW_ATTENTION_ICON], 0, TRUE);
1418
app_indicator_set_icon:
1419
@self: The #AppIndicator object to use
1420
@icon_name: The icon name to set.
1422
Sets the default icon to use when the status is active but
1423
not set to attention. In most cases, this should be the
1424
application icon for the program.
1425
Wrapper function for property #AppIndicator:icon-name.
1428
app_indicator_set_icon (AppIndicator *self, const gchar *icon_name)
1430
g_return_if_fail (IS_APP_INDICATOR (self));
1431
g_return_if_fail (icon_name != NULL);
1433
if (g_strcmp0 (self->priv->icon_name, icon_name) != 0)
1435
if (self->priv->icon_name)
1436
g_free (self->priv->icon_name);
1438
self->priv->icon_name = g_strdup(icon_name);
1440
g_signal_emit (self, signals[NEW_ICON], 0, TRUE);
1447
app_indicator_set_label:
1448
@self: The #AppIndicator object to use
1449
@label: The label to show next to the icon.
1450
@guide: A guide to size the label correctly.
1452
This is a wrapper function for the #AppIndicator:label and
1453
#AppIndicator:guide properties. This function can take #NULL
1454
as either @label or @guide and will clear the entries.
1457
app_indicator_set_label (AppIndicator *self, const gchar * label, const gchar * guide)
1459
g_return_if_fail (IS_APP_INDICATOR (self));
1460
/* Note: The label can be NULL, it's okay */
1461
/* Note: The guide can be NULL, it's okay */
1463
g_object_set(G_OBJECT(self),
1464
PROP_LABEL_S, label == NULL ? "" : label,
1465
PROP_LABEL_GUIDE_S, guide == NULL ? "" : guide,
1472
app_indicator_set_icon_theme_path:
1473
@self: The #AppIndicator object to use
1474
@icon_theme_path: The icon theme path to set.
1476
Sets the path to use when searching for icons.
1479
app_indicator_set_icon_theme_path (AppIndicator *self, const gchar *icon_theme_path)
1481
g_return_if_fail (IS_APP_INDICATOR (self));
1483
if (g_strcmp0 (self->priv->icon_theme_path, icon_theme_path) != 0)
1485
if (self->priv->icon_theme_path != NULL)
1486
g_free(self->priv->icon_theme_path);
1488
self->priv->icon_theme_path = g_strdup(icon_theme_path);
1490
g_signal_emit (self, signals[NEW_ICON_THEME_PATH], 0, g_strdup(self->priv->icon_theme_path));
1497
activate_menuitem (DbusmenuMenuitem *mi, guint timestamp, gpointer user_data)
1499
GtkWidget *widget = (GtkWidget *)user_data;
1501
gtk_menu_item_activate (GTK_MENU_ITEM (widget));
1505
widget_toggled (GtkWidget *widget, DbusmenuMenuitem *mi)
1507
dbusmenu_menuitem_property_set_int (mi,
1508
DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
1509
gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
1513
menuitem_iterate (GtkWidget *widget,
1516
if (GTK_IS_LABEL (widget))
1518
DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
1520
dbusmenu_menuitem_property_set (child,
1521
DBUSMENU_MENUITEM_PROP_LABEL,
1522
gtk_label_get_text (GTK_LABEL (widget)));
1527
should_show_image (GtkImage *image)
1531
item = gtk_widget_get_ancestor (GTK_WIDGET (image),
1532
GTK_TYPE_IMAGE_MENU_ITEM);
1536
GtkSettings *settings;
1537
gboolean gtk_menu_images;
1539
settings = gtk_widget_get_settings (item);
1541
g_object_get (settings, "gtk-menu-images", >k_menu_images, NULL);
1543
if (gtk_menu_images)
1546
return gtk_image_menu_item_get_always_show_image (GTK_IMAGE_MENU_ITEM (item));
1553
update_icon_name (DbusmenuMenuitem *menuitem,
1556
const gchar *icon_name = NULL;
1558
if (gtk_image_get_storage_type (image) != GTK_IMAGE_ICON_NAME)
1561
gtk_image_get_icon_name (image, &icon_name, NULL);
1563
if (should_show_image (image))
1564
dbusmenu_menuitem_property_set (menuitem,
1565
DBUSMENU_MENUITEM_PROP_ICON_NAME,
1568
dbusmenu_menuitem_property_remove (menuitem,
1569
DBUSMENU_MENUITEM_PROP_ICON_NAME);
1572
/* return value specifies whether the label is set or not */
1574
update_stock_item (DbusmenuMenuitem *menuitem,
1578
gchar *stock_id = NULL;
1580
if (gtk_image_get_storage_type (image) != GTK_IMAGE_STOCK)
1583
gtk_image_get_stock (image, &stock_id, NULL);
1584
gtk_stock_lookup (stock_id, &stock);
1586
if (should_show_image (image))
1587
dbusmenu_menuitem_property_set (menuitem,
1588
DBUSMENU_MENUITEM_PROP_ICON_NAME,
1591
dbusmenu_menuitem_property_remove (menuitem,
1592
DBUSMENU_MENUITEM_PROP_ICON_NAME);
1594
const gchar * label = dbusmenu_menuitem_property_get (menuitem,
1595
DBUSMENU_MENUITEM_PROP_LABEL);
1597
if (stock.label != NULL && label != NULL)
1599
dbusmenu_menuitem_property_set (menuitem,
1600
DBUSMENU_MENUITEM_PROP_LABEL,
1610
image_notify_cb (GtkWidget *widget,
1614
DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
1615
GtkImage *image = GTK_IMAGE (widget);
1617
if (pspec->name == g_intern_static_string ("stock"))
1619
update_stock_item (child, image);
1621
else if (pspec->name == g_intern_static_string ("icon-name"))
1623
update_icon_name (child, image);
1628
widget_notify_cb (GtkWidget *widget,
1632
DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
1634
if (pspec->name == g_intern_static_string ("sensitive"))
1636
dbusmenu_menuitem_property_set_bool (child,
1637
DBUSMENU_MENUITEM_PROP_ENABLED,
1638
gtk_widget_is_sensitive (widget));
1640
else if (pspec->name == g_intern_static_string ("label"))
1642
dbusmenu_menuitem_property_set (child,
1643
DBUSMENU_MENUITEM_PROP_LABEL,
1644
gtk_menu_item_get_label (GTK_MENU_ITEM (widget)));
1646
else if (pspec->name == g_intern_static_string ("visible"))
1648
dbusmenu_menuitem_property_set_bool (child,
1649
DBUSMENU_MENUITEM_PROP_VISIBLE,
1650
gtk_widget_get_visible (widget));
1655
action_notify_cb (GtkAction *action,
1659
DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
1661
if (pspec->name == g_intern_static_string ("active"))
1663
dbusmenu_menuitem_property_set_bool (child,
1664
DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
1665
gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
1668
if (pspec->name == g_intern_static_string ("label"))
1670
dbusmenu_menuitem_property_set (child,
1671
DBUSMENU_MENUITEM_PROP_LABEL,
1672
gtk_action_get_label (action));
1677
container_iterate (GtkWidget *widget,
1680
DbusmenuMenuitem *root = (DbusmenuMenuitem *)data;
1681
DbusmenuMenuitem *child;
1682
GtkWidget *submenu = NULL;
1683
const gchar *label = NULL;
1684
gboolean label_set = FALSE;
1686
if (GTK_IS_TEAROFF_MENU_ITEM(widget)) {
1690
child = dbusmenu_menuitem_new ();
1692
if (GTK_IS_SEPARATOR_MENU_ITEM (widget))
1694
dbusmenu_menuitem_property_set (child,
1696
DBUSMENU_CLIENT_TYPES_SEPARATOR);
1700
if (GTK_IS_CHECK_MENU_ITEM (widget))
1702
GtkCheckMenuItem *check;
1704
check = GTK_CHECK_MENU_ITEM (widget);
1705
label = gtk_menu_item_get_label (GTK_MENU_ITEM (widget));
1707
dbusmenu_menuitem_property_set (child,
1708
DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
1709
GTK_IS_RADIO_MENU_ITEM (widget) ? DBUSMENU_MENUITEM_TOGGLE_RADIO : DBUSMENU_MENUITEM_TOGGLE_CHECK);
1711
dbusmenu_menuitem_property_set (child,
1712
DBUSMENU_MENUITEM_PROP_LABEL,
1717
dbusmenu_menuitem_property_set_int (child,
1718
DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
1719
gtk_check_menu_item_get_active (check) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
1721
g_signal_connect (widget,
1723
G_CALLBACK (widget_toggled),
1726
else if (GTK_IS_IMAGE_MENU_ITEM (widget))
1729
GtkImageType image_type;
1731
image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (widget));
1732
image_type = gtk_image_get_storage_type (GTK_IMAGE (image));
1734
g_signal_connect (image,
1736
G_CALLBACK (image_notify_cb),
1739
if (image_type == GTK_IMAGE_STOCK)
1741
label_set = update_stock_item (child, GTK_IMAGE (image));
1743
else if (image_type == GTK_IMAGE_ICON_NAME)
1745
update_icon_name (child, GTK_IMAGE (image));
1754
dbusmenu_menuitem_property_set (child,
1755
DBUSMENU_MENUITEM_PROP_LABEL,
1760
/* find label child widget */
1761
gtk_container_forall (GTK_CONTAINER (widget),
1767
if (GTK_IS_MENU_ITEM (widget))
1769
submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
1770
if (submenu != NULL)
1772
gtk_container_foreach (GTK_CONTAINER (submenu),
1775
g_signal_connect_object (submenu,
1777
G_CALLBACK (submenu_changed),
1780
g_signal_connect_object (submenu,
1782
G_CALLBACK (submenu_changed),
1788
dbusmenu_menuitem_property_set_bool (child,
1789
DBUSMENU_MENUITEM_PROP_ENABLED,
1790
gtk_widget_is_sensitive (widget));
1791
dbusmenu_menuitem_property_set_bool (child,
1792
DBUSMENU_MENUITEM_PROP_VISIBLE,
1793
gtk_widget_get_visible (widget));
1795
g_signal_connect (widget, "notify",
1796
G_CALLBACK (widget_notify_cb), child);
1798
if (GTK_IS_ACTIVATABLE (widget))
1800
GtkActivatable *activatable = GTK_ACTIVATABLE (widget);
1802
if (gtk_activatable_get_use_action_appearance (activatable))
1804
GtkAction *action = gtk_activatable_get_related_action (activatable);
1808
g_signal_connect_object (action, "notify",
1809
G_CALLBACK (action_notify_cb),
1816
g_signal_connect (G_OBJECT (child),
1817
DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
1818
G_CALLBACK (activate_menuitem), widget);
1819
dbusmenu_menuitem_child_append (root, child);
1821
/* Get rid of initial ref now that the root is
1822
holding the object */
1823
g_object_unref(child);
1829
submenu_changed (GtkWidget *widget,
1833
DbusmenuMenuitem *root = (DbusmenuMenuitem *)data;
1834
GList *children, *l;
1835
children = dbusmenu_menuitem_get_children (root);
1837
for (l = children; l;)
1839
DbusmenuMenuitem *c = (DbusmenuMenuitem *)l->data;
1841
dbusmenu_menuitem_child_delete (root, c);
1844
gtk_container_foreach (GTK_CONTAINER (widget),
1850
setup_dbusmenu (AppIndicator *self)
1852
AppIndicatorPrivate *priv;
1853
DbusmenuMenuitem *root;
1856
root = dbusmenu_menuitem_new ();
1860
gtk_container_foreach (GTK_CONTAINER (priv->menu),
1865
if (priv->menuservice == NULL)
1867
gchar * path = g_strdup_printf(DEFAULT_ITEM_PATH "/%s/Menu", priv->clean_id);
1868
priv->menuservice = dbusmenu_server_new (path);
1872
dbusmenu_server_set_root (priv->menuservice, root);
1878
client_menu_changed (GtkWidget *widget,
1880
AppIndicator *indicator)
1882
setup_dbusmenu (indicator);
1886
app_indicator_set_menu:
1887
@self: The #AppIndicator
1888
@menu: A #GtkMenu to set
1890
Sets the menu that should be shown when the Application Indicator
1891
is clicked on in the panel. An application indicator will not
1892
be rendered unless it has a menu.
1894
Wrapper function for property #AppIndicator:menu.
1897
app_indicator_set_menu (AppIndicator *self, GtkMenu *menu)
1899
AppIndicatorPrivate *priv;
1901
g_return_if_fail (IS_APP_INDICATOR (self));
1902
g_return_if_fail (GTK_IS_MENU (menu));
1903
g_return_if_fail (self->priv->clean_id != NULL);
1907
if (priv->menu != NULL)
1909
g_object_unref (priv->menu);
1912
priv->menu = GTK_WIDGET (menu);
1913
g_object_ref (priv->menu);
1915
setup_dbusmenu (self);
1917
check_connect (self);
1919
g_signal_connect (menu,
1921
G_CALLBACK (client_menu_changed),
1923
g_signal_connect (menu,
1925
G_CALLBACK (client_menu_changed),
1930
app_indicator_set_ordering_index:
1931
@self: The #AppIndicator
1932
@ordering_index: A value for the ordering of this app indicator
1934
Sets the ordering index for the app indicator which effects the
1935
placement of it on the panel. For almost all app indicator
1936
this is not the function you're looking for.
1938
Wrapper function for property #AppIndicator:ordering-index.
1941
app_indicator_set_ordering_index (AppIndicator *self, guint32 ordering_index)
1943
g_return_if_fail (IS_APP_INDICATOR (self));
1945
self->priv->ordering_index = ordering_index;
1951
app_indicator_get_id:
1952
@self: The #AppIndicator object to use
1954
Wrapper function for property #AppIndicator:id.
1956
Return value: The current ID
1959
app_indicator_get_id (AppIndicator *self)
1961
g_return_val_if_fail (IS_APP_INDICATOR (self), NULL);
1963
return self->priv->id;
1967
app_indicator_get_category:
1968
@self: The #AppIndicator object to use
1970
Wrapper function for property #AppIndicator:category.
1972
Return value: The current category.
1974
AppIndicatorCategory
1975
app_indicator_get_category (AppIndicator *self)
1977
g_return_val_if_fail (IS_APP_INDICATOR (self), APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
1979
return self->priv->category;
1983
app_indicator_get_status:
1984
@self: The #AppIndicator object to use
1986
Wrapper function for property #AppIndicator:status.
1988
Return value: The current status.
1991
app_indicator_get_status (AppIndicator *self)
1993
g_return_val_if_fail (IS_APP_INDICATOR (self), APP_INDICATOR_STATUS_PASSIVE);
1995
return self->priv->status;
1999
app_indicator_get_icon:
2000
@self: The #AppIndicator object to use
2002
Wrapper function for property #AppIndicator:icon-name.
2004
Return value: The current icon name.
2007
app_indicator_get_icon (AppIndicator *self)
2009
g_return_val_if_fail (IS_APP_INDICATOR (self), NULL);
2011
return self->priv->icon_name;
2015
app_indicator_get_icon_theme_path:
2016
@self: The #AppIndicator object to use
2018
Wrapper function for property #AppIndicator:icon-theme-path.
2020
Return value: The current icon theme path.
2023
app_indicator_get_icon_theme_path (AppIndicator *self)
2025
g_return_val_if_fail (IS_APP_INDICATOR (self), NULL);
2027
return self->priv->icon_theme_path;
2031
app_indicator_get_attention_icon:
2032
@self: The #AppIndicator object to use
2034
Wrapper function for property #AppIndicator:attention-icon-name.
2036
Return value: The current attention icon name.
2039
app_indicator_get_attention_icon (AppIndicator *self)
2041
g_return_val_if_fail (IS_APP_INDICATOR (self), NULL);
2043
return self->priv->attention_icon_name;
2047
app_indicator_get_menu:
2048
@self: The #AppIndicator object to use
2050
Gets the menu being used for this application indicator.
2051
Wrapper function for property #AppIndicator:menu.
2053
Return value: A #GtkMenu object or %NULL if one hasn't been set.
2056
app_indicator_get_menu (AppIndicator *self)
2058
AppIndicatorPrivate *priv;
2060
g_return_val_if_fail (IS_APP_INDICATOR (self), NULL);
2064
return GTK_MENU(priv->menu);
2068
app_indicator_get_label:
2069
@self: The #AppIndicator object to use
2071
Wrapper function for property #AppIndicator:label.
2073
Return value: The current label.
2076
app_indicator_get_label (AppIndicator *self)
2078
g_return_val_if_fail (IS_APP_INDICATOR (self), NULL);
2080
return self->priv->label;
2084
app_indicator_get_label_guide:
2085
@self: The #AppIndicator object to use
2087
Wrapper function for property #AppIndicator:label-guide.
2089
Return value: The current label guide.
2092
app_indicator_get_label_guide (AppIndicator *self)
2094
g_return_val_if_fail (IS_APP_INDICATOR (self), NULL);
2096
return self->priv->label_guide;
2100
app_indicator_get_ordering_index:
2101
@self: The #AppIndicator object to use
2103
Wrapper function for property #AppIndicator:ordering-index.
2105
Return value: The current ordering index.
2108
app_indicator_get_ordering_index (AppIndicator *self)
2110
g_return_val_if_fail (IS_APP_INDICATOR (self), 0);
2112
if (self->priv->ordering_index == 0) {
2113
return generate_id(self->priv->category, self->priv->id);
2115
return self->priv->ordering_index;