1 /*
2 An object to represent loadable indicator modules to make loading
3 them easy and objectified.
4
5 Copyright 2009 Canonical Ltd.
6
7 Authors:
8 Ted Gould <ted@canonical.com>
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 version 3.0 as published by the Free Software Foundation.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License version 3.0 for more details.
18
19 You should have received a copy of the GNU General Public
20 License along with this library. If not, see
21 <http://www.gnu.org/licenses/>.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "indicator.h"
29 #include "indicator-object.h"
30 #include "indicator-object-marshal.h"
31 #include "indicator-object-enum-types.h"
32
33 /**
34 @ENTRY_INIT: The entry hasn't been initialized yet, so its
35 visibility will depend upon the inital-visibility property.
36 @ENTRY_VISIBLE: The entry is visible
37 @ENTRY_INVISIBLE: The entry is invisible
38 */
39 typedef enum {
40 ENTRY_INIT,
41 ENTRY_VISIBLE,
42 ENTRY_INVISIBLE
43 }
44 EntryVisibility;
45
46 typedef struct _IndicatorObjectEntryPrivate {
47 EntryVisibility visibility;
48 }
49 IndicatorObjectEntryPrivate;
50
51 /**
52 IndicatorObjectPrivate:
53 @module: The loaded module representing the object. Note to
54 subclasses: This will not be set when you're initalized.
55 @entry: A default entry for objects that don't need all the
56 fancy stuff. This works with #get_entries_default.
57 @gotten_entries: A check to see if the @entry has been
58 populated intelligently yet.
59
60 Structure to define the memory for the private area
61 of the object instance.
62 */
63 struct _IndicatorObjectPrivate {
64 GModule * module;
65
66 /* For get_entries_default */
67 IndicatorObjectEntry entry;
68 gboolean gotten_entries;
69
70 /* Whether or not entries are visible by default */
71 gboolean default_visibility;
72 GHashTable * entry_privates;
73
74 GStrv environments;
75 };
76
77 #define INDICATOR_OBJECT_GET_PRIVATE(o) (INDICATOR_OBJECT(o)->priv)
78
79
80 /* Signals Stuff */
81 enum {
82 ENTRY_ADDED,
83 ENTRY_REMOVED,
84 ENTRY_MOVED,
85 ENTRY_SCROLLED,
86 MENU_SHOW,
87 SHOW_NOW_CHANGED,
88 ACCESSIBLE_DESC_UPDATE,
89 SECONDARY_ACTIVATE,
90 LAST_SIGNAL
91 };
92
93 /* Properties */
94 /* Enum for the properties so that they can be quickly
95 found and looked up. */
96 enum {
97 PROP_0,
98 PROP_GSETTINGS_SCHEMA_ID,
99 PROP_DEFAULT_VISIBILITY,
100 };
101
102
103 static guint signals[LAST_SIGNAL] = { 0 };
104
105 /* GObject stuff */
106 static void indicator_object_class_init (IndicatorObjectClass *klass);
107 static void indicator_object_init (IndicatorObject *self);
108 static void indicator_object_dispose (GObject *object);
109 static void indicator_object_finalize (GObject *object);
110 static void set_property (GObject*, guint prop_id, const GValue*, GParamSpec* );
111 static void get_property (GObject*, guint prop_id, GValue*, GParamSpec* );
112
113 /* entries' visibility */
114 static GList * get_entries_default (IndicatorObject*);
115 static GList * get_all_entries (IndicatorObject*);
116 static void indicator_object_entry_being_removed (IndicatorObject*, IndicatorObjectEntry*);
117 static void indicator_object_entry_was_added (IndicatorObject*, IndicatorObjectEntry*);
118 static IndicatorObjectEntryPrivate * entry_get_private (IndicatorObject*, IndicatorObjectEntry*);
119
120 G_DEFINE_TYPE (IndicatorObject, indicator_object, G_TYPE_OBJECT);
121
122 /* Setup the class and put the functions into the
123 class structure */
124 static void
indicator_object_class_init(IndicatorObjectClass * klass)125 indicator_object_class_init (IndicatorObjectClass *klass)
126 {
127 GObjectClass *object_class = G_OBJECT_CLASS (klass);
128
129 g_type_class_add_private (klass, sizeof (IndicatorObjectPrivate));
130
131 object_class->dispose = indicator_object_dispose;
132 object_class->finalize = indicator_object_finalize;
133 object_class->set_property = set_property;
134 object_class->get_property = get_property;
135
136 klass->get_label = NULL;
137 klass->get_menu = NULL;
138 klass->get_image = NULL;
139 klass->get_accessible_desc = NULL;
140 klass->get_entries = get_entries_default;
141 klass->get_location = NULL;
142 klass->entry_being_removed = NULL;
143 klass->entry_was_added = NULL;
144
145 klass->entry_activate = NULL;
146 klass->entry_activate_window = NULL;
147 klass->entry_close = NULL;
148
149 /**
150 IndicatorObject::entry-added:
151 @arg0: The #IndicatorObject object
152 @arg1: A pointer to the #IndicatorObjectEntry that
153 is being added.
154
155 Signaled when a new entry is added and should
156 be shown by the person using this object.
157 */
158 signals[ENTRY_ADDED] = g_signal_new (INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,
159 G_TYPE_FROM_CLASS(klass),
160 G_SIGNAL_RUN_LAST,
161 G_STRUCT_OFFSET (IndicatorObjectClass, entry_added),
162 NULL, NULL,
163 g_cclosure_marshal_VOID__POINTER,
164 G_TYPE_NONE, 1, G_TYPE_POINTER, G_TYPE_NONE);
165
166 /**
167 IndicatorObject::entry-removed:
168 @arg0: The #IndicatorObject object
169 @arg1: A pointer to the #IndicatorObjectEntry that
170 is being removed.
171
172 Signaled when an entry is removed and should
173 be removed by the person using this object.
174 */
175 signals[ENTRY_REMOVED] = g_signal_new (INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED,
176 G_TYPE_FROM_CLASS(klass),
177 G_SIGNAL_RUN_LAST,
178 G_STRUCT_OFFSET (IndicatorObjectClass, entry_removed),
179 NULL, NULL,
180 g_cclosure_marshal_VOID__POINTER,
181 G_TYPE_NONE, 1, G_TYPE_POINTER, G_TYPE_NONE);
182 /**
183 IndicatorObject::entry-moved:
184 @arg0: The #IndicatorObject object
185 @arg1: A pointer to the #IndicatorObjectEntry that
186 is being moved.
187 @arg2: The old location of the entry
188 @arg3: The new location of the entry
189
190 When the order of the entries change, then this signal
191 is sent to tell the new location.
192 */
193 signals[ENTRY_MOVED] = g_signal_new (INDICATOR_OBJECT_SIGNAL_ENTRY_MOVED,
194 G_TYPE_FROM_CLASS(klass),
195 G_SIGNAL_RUN_LAST,
196 G_STRUCT_OFFSET (IndicatorObjectClass, entry_moved),
197 NULL, NULL,
198 _indicator_object_marshal_VOID__POINTER_UINT_UINT,
199 G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_NONE);
200 /**
201 IndicatorObject::entry-scrolled:
202 @arg0: The #IndicatorObject object
203 @arg1: A pointer to the #IndicatorObjectEntry that
204 receives the scroll event.
205 @arg2: The delta of the scroll event
206 @arg3: The orientation of the scroll event.
207
208 When the indicator receives a mouse scroll wheel event
209 from the user, this signal is emitted.
210 */
211 signals[ENTRY_SCROLLED] = g_signal_new (INDICATOR_OBJECT_SIGNAL_ENTRY_SCROLLED,
212 G_TYPE_FROM_CLASS(klass),
213 G_SIGNAL_RUN_LAST,
214 G_STRUCT_OFFSET (IndicatorObjectClass, entry_scrolled),
215 NULL, NULL,
216 _indicator_object_marshal_VOID__POINTER_UINT_ENUM,
217 G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_UINT,
218 INDICATOR_OBJECT_TYPE_SCROLL_DIRECTION);
219 /**
220 IndicatorObject::secondary-activate:
221 @arg0: The #IndicatorObject object
222 @arg1: A pointer to the #IndicatorObjectEntry that
223 receives the secondary activate event.
224 @arg2: The timestamp of the event
225
226 When the indicator receives a secondary activation event
227 from the user, this signal is emitted.
228 */
229 signals[SECONDARY_ACTIVATE] = g_signal_new (INDICATOR_OBJECT_SIGNAL_SECONDARY_ACTIVATE,
230 G_TYPE_FROM_CLASS(klass),
231 G_SIGNAL_RUN_LAST,
232 G_STRUCT_OFFSET (IndicatorObjectClass, secondary_activate),
233 NULL, NULL,
234 _indicator_object_marshal_VOID__POINTER_UINT,
235 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
236
237 /**
238 IndicatorObject::menu-show:
239 @arg0: The #IndicatorObject object
240 @arg1: A pointer to the #IndicatorObjectEntry that
241 is being shown.
242 @arg2: The timestamp of the event
243
244 Used when the indicator wants to signal up the stack
245 that the menu should be shown.
246 */
247 signals[MENU_SHOW] = g_signal_new (INDICATOR_OBJECT_SIGNAL_MENU_SHOW,
248 G_TYPE_FROM_CLASS(klass),
249 G_SIGNAL_RUN_LAST,
250 G_STRUCT_OFFSET (IndicatorObjectClass, menu_show),
251 NULL, NULL,
252 _indicator_object_marshal_VOID__POINTER_UINT,
253 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
254
255 /**
256 IndicatorObject::show-now-changed:
257 @arg0: The #IndicatorObject object
258 @arg1: A pointer to the #IndicatorObjectEntry that
259 is changing it's state
260 @arg2: The state of whether the entry should be shown
261
262 Whether the entry should be shown or not has changed so we need
263 to tell whoever is displaying it.
264 */
265 signals[SHOW_NOW_CHANGED] = g_signal_new (INDICATOR_OBJECT_SIGNAL_SHOW_NOW_CHANGED,
266 G_TYPE_FROM_CLASS(klass),
267 G_SIGNAL_RUN_LAST,
268 G_STRUCT_OFFSET (IndicatorObjectClass, show_now_changed),
269 NULL, NULL,
270 _indicator_object_marshal_VOID__POINTER_BOOLEAN,
271 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
272
273 /**
274 IndicatorObject::accessible-desc-update::
275 @arg0: The #IndicatorObject object
276 @arg1: A pointer to the #IndicatorObjectEntry whos
277 accessible description has been updated.
278
279 Signaled when an indicator's accessible description
280 has been updated, so that the displayer of the
281 indicator can fetch the new description.
282 */
283 signals[ACCESSIBLE_DESC_UPDATE] = g_signal_new (INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE,
284 G_TYPE_FROM_CLASS(klass),
285 G_SIGNAL_RUN_LAST,
286 G_STRUCT_OFFSET (IndicatorObjectClass, accessible_desc_update),
287 NULL, NULL,
288 g_cclosure_marshal_VOID__POINTER,
289 G_TYPE_NONE, 1, G_TYPE_POINTER, G_TYPE_NONE);
290
291 /* Properties */
292
293 GParamSpec * pspec = g_param_spec_boolean (INDICATOR_OBJECT_DEFAULT_VISIBILITY,
294 "default visibility",
295 "Whether or not entries should initially be visible.",
296 TRUE,
297 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
298 g_object_class_install_property (object_class, PROP_DEFAULT_VISIBILITY, pspec);
299 }
300
301 /* Initialize an instance */
302 static void
indicator_object_init(IndicatorObject * self)303 indicator_object_init (IndicatorObject *self)
304 {
305 IndicatorObjectPrivate * priv = G_TYPE_INSTANCE_GET_PRIVATE (self, INDICATOR_OBJECT_TYPE, IndicatorObjectPrivate);
306
307 priv->module = NULL;
308
309 priv->entry.parent_object = self;
310 priv->entry.menu = NULL;
311 priv->entry.label = NULL;
312 priv->entry.image = NULL;
313 priv->entry.accessible_desc = NULL;
314 priv->entry.name_hint = NULL;
315
316 priv->gotten_entries = FALSE;
317 priv->default_visibility = TRUE;
318 priv->entry_privates = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
319
320 priv->environments = NULL;
321
322 self->priv = priv;
323
324 GObject * o = G_OBJECT(self);
325 /* Invoke the entry-being-removed virtual function first */
326 g_signal_connect (o, INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED,
327 G_CALLBACK(indicator_object_entry_being_removed), NULL);
328 /* Invoke the entry-was-added virtual function last */
329 g_signal_connect_after (o, INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,
330 G_CALLBACK(indicator_object_entry_was_added), NULL);
331 }
332
333 /* Unref the objects that we're holding on to. */
334 static void
indicator_object_dispose(GObject * object)335 indicator_object_dispose (GObject *object)
336 {
337 /* Ensure that hidden entries are re-added so their widgetry will
338 be cleaned up properly by the client */
339 indicator_object_set_visible (INDICATOR_OBJECT (object), TRUE);
340
341 G_OBJECT_CLASS (indicator_object_parent_class)->dispose (object);
342 }
343
344 /* A small helper function that closes a module but
345 in the function prototype of a GSourceFunc. */
346 static gboolean
module_unref(gpointer data)347 module_unref (gpointer data)
348 {
349 if (!g_module_close((GModule *)data)) {
350 /* All we can do is warn. */
351 g_warning("Unable to close module!");
352 }
353 return FALSE;
354 }
355
356 /* Free memory */
357 static void
indicator_object_finalize(GObject * object)358 indicator_object_finalize (GObject *object)
359 {
360 IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(object);
361
362 if (priv->entry_privates != NULL) {
363 g_hash_table_destroy (priv->entry_privates);
364 priv->entry_privates = NULL;
365 }
366
367 if (priv->environments != NULL) {
368 g_strfreev(priv->environments);
369 priv->environments = NULL;
370 }
371
372 if (priv->module != NULL) {
373 /* Wow, this is convoluted. So basically we want to unref
374 the module which will cause the code it included to be
375 removed. But, since its finalize function is the function
376 that called this one, we can't really remove it before
377 it finishes being executed. So we're putting the job into
378 the main loop to remove it the next time it gets a chance.
379 Slightly non-deterministic, but should work. */
380 g_idle_add(module_unref, priv->module);
381 priv->module = NULL;
382 }
383
384 G_OBJECT_CLASS (indicator_object_parent_class)->finalize (object);
385 return;
386 }
387
388 /**
389 indicator_object_new_from_file:
390 @file: Filename containing a loadable module
391
392 This function builds an #IndicatorObject using the symbols
393 that are found in @file. The module is loaded and the
394 references are all kept by the object. To unload the
395 module the object must be destroyed.
396
397 Return value: A valid #IndicatorObject or #NULL if error.
398 */
399 IndicatorObject *
indicator_object_new_from_file(const gchar * file)400 indicator_object_new_from_file (const gchar * file)
401 {
402 GObject * object = NULL;
403 GModule * module = NULL;
404
405 /* Check to make sure the name exists and that the
406 file itself exists */
407 if (file == NULL) {
408 g_warning("Invalid filename.");
409 return NULL;
410 }
411
412 if (!g_file_test(file, G_FILE_TEST_EXISTS)) {
413 g_warning("File '%s' does not exist.", file);
414 return NULL;
415 }
416
417 /* Grab the g_module reference, pull it in but let's
418 keep the symbols local to avoid conflicts. */
419 module = g_module_open(file,
420 G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
421 if (module == NULL) {
422 g_warning("Unable to load module: %s", file);
423 return NULL;
424 }
425
426 /* Look for the version function, error if not found. */
427 get_version_t lget_version = NULL;
428 if (!g_module_symbol(module, INDICATOR_GET_VERSION_S, (gpointer *)(&lget_version))) {
429 g_warning("Unable to get the symbol for getting the version.");
430 return NULL;
431 }
432
433 /* Check the version with the macro and make sure we're
434 all talking the same language. */
435 if (!INDICATOR_VERSION_CHECK(lget_version())) {
436 g_warning("Indicator using API version '%s' we're expecting '%s'", lget_version(), INDICATOR_VERSION);
437 return NULL;
438 }
439
440 /* The function for grabbing a label from the module
441 execute it, and make sure everything is a-okay */
442 get_type_t lget_type = NULL;
443 if (!g_module_symbol(module, INDICATOR_GET_TYPE_S, (gpointer *)(&lget_type))) {
444 g_warning("Unable to get '" INDICATOR_GET_TYPE_S "' symbol from module: %s", file);
445 goto unrefandout;
446 }
447 if (lget_type == NULL) {
448 g_warning("Symbol '" INDICATOR_GET_TYPE_S "' is (null) in module: %s", file);
449 goto unrefandout;
450 }
451
452 /* A this point we allocate the object, any code beyond
453 here needs to deallocate it if we're returning in an
454 error'd state. */
455 object = g_object_new(lget_type(), NULL);
456 if (object == NULL) {
457 g_warning("Unable to build an object if type '%d' in module: %s", (gint)lget_type(), file);
458 goto unrefandout;
459 }
460 if (!INDICATOR_IS_OBJECT(object)) {
461 g_warning("Type '%d' in file %s is not a subclass of IndicatorObject.", (gint)lget_type(), file);
462 goto unrefandout;
463 }
464
465 /* Now we can track the module */
466 INDICATOR_OBJECT_GET_PRIVATE(object)->module = module;
467
468 return INDICATOR_OBJECT(object);
469
470 /* Error, let's drop the object and return NULL. Sad when
471 this happens. */
472 unrefandout:
473 g_clear_object (&object);
474 g_clear_object (&module);
475 g_warning("Error building IndicatorObject from file: %s", file);
476 return NULL;
477 }
478
479 /* The default get entries function uses the other single
480 entries in the class to create an entry structure and
481 put it into a list. This makes it simple for simple objects
482 to create the list. Small changes from the way they
483 previously were. */
484 static GList *
get_entries_default(IndicatorObject * io)485 get_entries_default (IndicatorObject * io)
486 {
487 IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(io);
488
489 if (!priv->gotten_entries) {
490 IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
491
492 priv->entry.parent_object = io;
493
494 if (class->get_label) {
495 priv->entry.label = class->get_label(io);
496 }
497
498 if (class->get_image) {
499 priv->entry.image = class->get_image(io);
500 }
501
502 if (priv->entry.image == NULL && priv->entry.label == NULL) {
503 g_warning("IndicatorObject class does not create an image or a label. We need one of those.");
504 return NULL;
505 }
506
507 if (class->get_menu) {
508 priv->entry.menu = class->get_menu(io);
509 }
510
511 if (priv->entry.menu == NULL) {
512 g_warning("IndicatorObject class does not create a menu. We need one of those.");
513 return NULL;
514 }
515
516 if (class->get_accessible_desc) {
517 priv->entry.accessible_desc = class->get_accessible_desc(io);
518 }
519
520 if (priv->entry.accessible_desc == NULL) {
521 g_warning("IndicatorObject class does not have an accessible description.");
522 }
523
524 if (class->get_name_hint) {
525 priv->entry.name_hint = class->get_name_hint(io);
526 }
527
528 priv->gotten_entries = TRUE;
529 }
530
531 return g_list_append(NULL, &(priv->entry));
532 }
533
534 /* returns a list of all IndicatorObjectEntires, visible or not */
535 static GList*
get_all_entries(IndicatorObject * io)536 get_all_entries (IndicatorObject * io)
537 {
538 GList * all_entries = NULL, *l;
539
540 g_return_val_if_fail(INDICATOR_IS_OBJECT(io), NULL);
541 IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
542
543 if (class->get_entries == NULL)
544 g_error("No get_entries function on object. It must have been deleted?!?!");
545 else
546 {
547 all_entries = class->get_entries(io);
548
549 for (l = all_entries; l; l = l->next)
550 {
551 IndicatorObjectEntry *entry = l->data;
552
553 if (entry)
554 entry->parent_object = io;
555 }
556 }
557
558 return all_entries;
559 }
560
561 /* get the private structure that corresponds to a caller-specified entry */
562 static IndicatorObjectEntryPrivate *
entry_get_private(IndicatorObject * io,IndicatorObjectEntry * entry)563 entry_get_private (IndicatorObject * io, IndicatorObjectEntry * entry)
564 {
565 g_return_val_if_fail (INDICATOR_IS_OBJECT(io), NULL);
566 g_return_val_if_fail (io->priv != NULL, NULL);
567
568 GHashTable * h = io->priv->entry_privates;
569 IndicatorObjectEntryPrivate * priv = g_hash_table_lookup (h, entry);
570 if (priv == NULL)
571 {
572 priv = g_new0 (IndicatorObjectEntryPrivate, 1);
573 priv->visibility = ENTRY_INIT;
574 g_hash_table_insert (h, entry, priv);
575 }
576
577 return priv;
578 }
579
580 /**
581 indicator_object_get_entries:
582 @io: #IndicatorObject to query
583
584 This function returns a list of visible entries. The list is built
585 by calling the object's #IndicatorObjectClass::get_entries
586 virtual function and testing each of the results for visibility.
587 Callers should free the GList with g_list_free(), but the entries
588 are owned by the IndicatorObject and should not be freed.
589
590 Return value: (element-type IndicatorObjectEntry) (transfer container):
591 A list if #IndicatorObjectEntry structures or NULL on error.
592 */
593 GList *
indicator_object_get_entries(IndicatorObject * io)594 indicator_object_get_entries (IndicatorObject * io)
595 {
596 GList * l;
597 GList * ret = NULL;
598 GList * all_entries = get_all_entries (io);
599 const gboolean default_visibility = INDICATOR_OBJECT_GET_PRIVATE(io)->default_visibility;
600
601 for (l=all_entries; l!=NULL; l=l->next)
602 {
603 gboolean show_me;
604 IndicatorObjectEntry * entry = l->data;
605
606 switch (entry_get_private(io,entry)->visibility) {
607 case ENTRY_VISIBLE: show_me = TRUE; break;
608 case ENTRY_INVISIBLE: show_me = FALSE; break;
609 case ENTRY_INIT: show_me = default_visibility; break;
610 default: show_me = TRUE; g_warn_if_reached(); break;
611 }
612
613 if (show_me)
614 ret = g_list_prepend (ret, entry);
615 }
616
617 g_list_free (all_entries);
618 return g_list_reverse (ret);
619 }
620
621 /**
622 indicator_object_get_location:
623 @io: #IndicatorObject to query
624 @entry: The #IndicatorObjectEntry to look for.
625
626 This function looks on the class for the object and calls
627 it's #IndicatorObjectClass::get_location function. If the
628 function doesn't exist it returns zero.
629
630 Return value: Location of the @entry in the display or
631 zero if no location is specified.
632 */
633 guint
indicator_object_get_location(IndicatorObject * io,IndicatorObjectEntry * entry)634 indicator_object_get_location (IndicatorObject * io, IndicatorObjectEntry * entry)
635 {
636 g_return_val_if_fail(INDICATOR_IS_OBJECT(io), 0);
637 IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
638
639 if (class->get_location) {
640 return class->get_location(io, entry);
641 }
642
643 return 0;
644 }
645
646 /**
647 indicator_object_get_show_now:
648 @io: #IndicatorObject to query
649 @entry: The #IndicatorObjectEntry to look for.
650
651 This function returns whether the entry should be shown with
652 priority on the panel. If the object does not support checking
653 it assumes that its entries should never have priority.
654
655 Return value: Whether the entry should be shown with priority.
656 */
657 guint
indicator_object_get_show_now(IndicatorObject * io,IndicatorObjectEntry * entry)658 indicator_object_get_show_now (IndicatorObject * io, IndicatorObjectEntry * entry)
659 {
660 g_return_val_if_fail(INDICATOR_IS_OBJECT(io), 0);
661 IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
662
663 if (class->get_show_now) {
664 return class->get_show_now(io, entry);
665 }
666
667 return FALSE;
668 }
669
670 /**
671 indicator_object_entry_activate_window:
672 @io: #IndicatorObject to query
673 @entry: The #IndicatorObjectEntry whose entry was shown
674 @windowid: ID of the window that is currently focused (or will
675 be very shortly)
676 @timestamp: The X11 timestamp of the event
677
678 Used to signal to the indicator that the menu on an entry has
679 been clicked on. This can either be an activate or a showing
680 of the menu. Also includes a window ID so that we can know what
681 application is going to be getting focused soon. If there is
682 no override of this function, it is the same as calling
683 indicator_object_entry_activate and in general is preferable
684 if you have that information available.
685 */
686 void
indicator_object_entry_activate_window(IndicatorObject * io,IndicatorObjectEntry * entry,guint windowid,guint timestamp)687 indicator_object_entry_activate_window (IndicatorObject * io, IndicatorObjectEntry * entry, guint windowid, guint timestamp)
688 {
689 g_return_if_fail(INDICATOR_IS_OBJECT(io));
690 IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
691
692 if (class->entry_activate_window != NULL) {
693 return class->entry_activate_window(io, entry, windowid, timestamp);
694 } else {
695 indicator_object_entry_activate(io, entry, timestamp);
696 }
697
698 return;
699 }
700
701 /**
702 indicator_object_entry_activate:
703 @io: #IndicatorObject to query
704 @entry: The #IndicatorObjectEntry whose entry was shown
705 @timestamp: The X11 timestamp of the event
706
707 Used to signal to the indicator that the menu on an entry has
708 been clicked on. This can either be an activate or a showing
709 of the menu. Note, this does not actually show the menu that's
710 left up to the reader.
711 */
712 void
indicator_object_entry_activate(IndicatorObject * io,IndicatorObjectEntry * entry,guint timestamp)713 indicator_object_entry_activate (IndicatorObject * io, IndicatorObjectEntry * entry, guint timestamp)
714 {
715 g_return_if_fail(INDICATOR_IS_OBJECT(io));
716 IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
717
718 if (class->entry_activate != NULL) {
719 return class->entry_activate(io, entry, timestamp);
720 }
721
722 return;
723 }
724
725 /**
726 indicator_object_entry_close:
727 @io: #IndicatorObject to query
728 @entry: The #IndicatorObjectEntry whose menu was closed
729 @timestamp: The X11 timestamp of the event
730
731 Used to tell the indicator that a menu has been closed for the
732 entry that is specified.
733 */
734 void
indicator_object_entry_close(IndicatorObject * io,IndicatorObjectEntry * entry,guint timestamp)735 indicator_object_entry_close (IndicatorObject * io, IndicatorObjectEntry * entry, guint timestamp)
736 {
737 g_return_if_fail(INDICATOR_IS_OBJECT(io));
738 IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
739
740 if (class->entry_close != NULL) {
741 return class->entry_close(io, entry, timestamp);
742 }
743
744 return;
745 }
746
747 static void
indicator_object_entry_being_removed(IndicatorObject * io,IndicatorObjectEntry * entry)748 indicator_object_entry_being_removed (IndicatorObject * io, IndicatorObjectEntry * entry)
749 {
750 g_return_if_fail(INDICATOR_IS_OBJECT(io));
751 IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
752
753 entry_get_private (io, entry)->visibility = ENTRY_INVISIBLE;
754
755 if (entry)
756 entry->parent_object = NULL;
757
758 if (class->entry_being_removed != NULL)
759 {
760 class->entry_being_removed (io, entry);
761 }
762 }
763
764 static void
indicator_object_entry_was_added(IndicatorObject * io,IndicatorObjectEntry * entry)765 indicator_object_entry_was_added (IndicatorObject * io, IndicatorObjectEntry * entry)
766 {
767 g_return_if_fail(INDICATOR_IS_OBJECT(io));
768 IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
769
770 entry_get_private (io, entry)->visibility = ENTRY_VISIBLE;
771
772 if (entry)
773 entry->parent_object = io;
774
775 if (class->entry_was_added != NULL)
776 {
777 class->entry_was_added (io, entry);
778 }
779 }
780
781 /**
782 indicator_object_set_environment:
783 @io: #IndicatorObject to set on
784 @env: List of enviroment names to use
785
786 Sets the names of the environment that the indicator is being
787 loaded into. This allows for indicators to behave differently
788 in different hosts if need be.
789 */
790 void
indicator_object_set_environment(IndicatorObject * io,GStrv env)791 indicator_object_set_environment (IndicatorObject * io, GStrv env)
792 {
793 /* FIXME: should this be a property? */
794 g_return_if_fail(INDICATOR_IS_OBJECT(io));
795
796 if (io->priv->environments != NULL) {
797 g_strfreev(io->priv->environments);
798 io->priv->environments = NULL;
799 }
800
801 io->priv->environments = g_strdupv(env);
802
803 return;
804 }
805
806 /**
807 indicator_object_get_environment:
808 @io: #IndicatorObject to get the environment from
809
810 Gets the list of environment strings that this object is
811 placed into.
812
813 Return value: (transfer none): Gets the list of strings that
814 represent the environment or NULL if none were given.
815 */
816 GStrv
indicator_object_get_environment(IndicatorObject * io)817 indicator_object_get_environment (IndicatorObject * io)
818 {
819 g_return_val_if_fail(INDICATOR_IS_OBJECT(io), NULL);
820 return io->priv->environments;
821 }
822
823 /**
824 indicator_object_check_environment:
825 @io: #IndicatorObject to check on
826 @env: Environment that we're looking for
827
828 Convience function to check to see if the specified environment
829 @env is in our list of environments.
830
831 Return Value: Whether we're in environment @env
832 */
833 gboolean
indicator_object_check_environment(IndicatorObject * io,const gchar * env)834 indicator_object_check_environment (IndicatorObject * io, const gchar * env)
835 {
836 g_return_val_if_fail(INDICATOR_IS_OBJECT(io), FALSE);
837 g_return_val_if_fail(env != NULL, FALSE);
838
839 if (io->priv->environments == NULL) {
840 return FALSE;
841 }
842
843 int i;
844 for (i = 0; io->priv->environments[i] != NULL; i++) {
845 if (g_strcmp0(env, io->priv->environments[i]) == 0) {
846 return TRUE;
847 }
848 }
849
850 return FALSE;
851 }
852
853 /**
854 indicator_object_set_visible:
855 @io: #IndicatorObject to check on
856 @visible: whether or not the entries should be visible
857
858 Used to set all of an indicator's entries to be visible or hidden.
859 */
860 void
indicator_object_set_visible(IndicatorObject * io,gboolean visible)861 indicator_object_set_visible (IndicatorObject * io, gboolean visible)
862 {
863 g_return_if_fail(INDICATOR_IS_OBJECT(io));
864
865 GList * l;
866 GList * entries = get_all_entries (io);
867 const guint signal_id = signals[visible ? ENTRY_ADDED : ENTRY_REMOVED];
868 EntryVisibility visibility = visible ? ENTRY_VISIBLE : ENTRY_INVISIBLE;
869 const GQuark detail = (GQuark)0;
870
871 for (l=entries; l!=NULL; l=l->next) {
872 IndicatorObjectEntry *entry = l->data;
873 if (entry_get_private (io, entry)->visibility != visibility)
874 g_signal_emit(io, signal_id, detail, entry);
875 }
876 g_list_free (entries);
877 }
878
879 static void
get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)880 get_property (GObject * object,
881 guint prop_id,
882 GValue * value,
883 GParamSpec * pspec)
884 {
885 IndicatorObject * self = INDICATOR_OBJECT(object);
886 g_return_if_fail(self != NULL);
887
888 IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(self);
889 g_return_if_fail(priv != NULL);
890
891 switch (prop_id) {
892 /* *********************** */
893 case PROP_DEFAULT_VISIBILITY:
894 if (G_VALUE_HOLDS_BOOLEAN(value)) {
895 g_value_set_boolean(value, priv->default_visibility);
896 } else {
897 g_warning("default-visibility property requires a boolean value.");
898 }
899 break;
900 /* *********************** */
901 default:
902 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
903 break;
904 }
905 }
906
907 static void
set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)908 set_property (GObject * object,
909 guint prop_id,
910 const GValue * value,
911 GParamSpec * pspec)
912 {
913 IndicatorObject * self = INDICATOR_OBJECT(object);
914 g_return_if_fail (self != NULL);
915
916 IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(self);
917 g_return_if_fail (priv != NULL);
918
919
920 switch (prop_id) {
921
922 /* *********************** */
923 case PROP_DEFAULT_VISIBILITY:
924 if (G_VALUE_HOLDS_BOOLEAN(value)) {
925 priv->default_visibility = g_value_get_boolean (value);
926 } else {
927 g_warning("default-visibility property requires a boolean value.");
928 }
929 break;
930
931
932 default:
933 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
934 break;
935 }
936 }
937
938