Back to index

libindicator  12.10.0
indicator-object.c
Go to the documentation of this file.
00001 /*
00002 An object to represent loadable indicator modules to make loading
00003 them easy and objectified.
00004 
00005 Copyright 2009 Canonical Ltd.
00006 
00007 Authors:
00008     Ted Gould <ted@canonical.com>
00009 
00010 This library is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 version 3.0 as published by the Free Software Foundation.
00013 
00014 This library is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 GNU General Public License version 3.0 for more details.
00018 
00019 You should have received a copy of the GNU General Public
00020 License along with this library. If not, see
00021 <http://www.gnu.org/licenses/>.
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027 
00028 #include "indicator.h"
00029 #include "indicator-object.h"
00030 #include "indicator-object-marshal.h"
00031 #include "indicator-object-enum-types.h"
00032 
00039 typedef enum {
00040     ENTRY_INIT,
00041     ENTRY_VISIBLE,
00042     ENTRY_INVISIBLE
00043 }
00044 EntryVisibility;
00045 
00046 typedef struct _IndicatorObjectEntryPrivate {
00047      EntryVisibility visibility;
00048 }
00049 IndicatorObjectEntryPrivate;
00050 
00063 struct _IndicatorObjectPrivate {
00064        GModule * module;
00065 
00066        /* For get_entries_default */
00067        IndicatorObjectEntry entry;
00068        gboolean gotten_entries;
00069 
00070        /* Whether or not entries are visible by default */
00071        gboolean default_visibility;
00072        GHashTable * entry_privates;
00073 
00074        GStrv environments;
00075 };
00076 
00077 #define INDICATOR_OBJECT_GET_PRIVATE(o) (INDICATOR_OBJECT(o)->priv)
00078 
00079 
00080 /* Signals Stuff */
00081 enum {
00082        ENTRY_ADDED,
00083        ENTRY_REMOVED,
00084        ENTRY_MOVED,
00085        ENTRY_SCROLLED,
00086        MENU_SHOW,
00087        SHOW_NOW_CHANGED,
00088        ACCESSIBLE_DESC_UPDATE,
00089        SECONDARY_ACTIVATE,
00090        LAST_SIGNAL
00091 };
00092 
00093 /* Properties */
00094 /* Enum for the properties so that they can be quickly
00095    found and looked up. */
00096 enum {
00097        PROP_0,
00098        PROP_GSETTINGS_SCHEMA_ID,
00099        PROP_DEFAULT_VISIBILITY,
00100 };
00101 
00102 
00103 static guint signals[LAST_SIGNAL] = { 0 };
00104 
00105 /* GObject stuff */
00106 static void indicator_object_class_init (IndicatorObjectClass *klass);
00107 static void indicator_object_init       (IndicatorObject *self);
00108 static void indicator_object_dispose    (GObject *object);
00109 static void indicator_object_finalize   (GObject *object);
00110 static void set_property (GObject*, guint prop_id, const GValue*, GParamSpec* );
00111 static void get_property (GObject*, guint prop_id,       GValue*, GParamSpec* );
00112 
00113 /* entries' visibility */
00114 static GList * get_entries_default               (IndicatorObject*);
00115 static GList * get_all_entries                   (IndicatorObject*);
00116 static void entry_being_removed_default          (IndicatorObject*, IndicatorObjectEntry*);
00117 static void indicator_object_entry_being_removed (IndicatorObject*, IndicatorObjectEntry*);
00118 static void entry_was_added_default              (IndicatorObject*, IndicatorObjectEntry*);
00119 static void indicator_object_entry_was_added     (IndicatorObject*, IndicatorObjectEntry*);
00120 static IndicatorObjectEntryPrivate * entry_get_private (IndicatorObject*, IndicatorObjectEntry*);
00121 
00122 G_DEFINE_TYPE (IndicatorObject, indicator_object, G_TYPE_OBJECT);
00123 
00124 /* Setup the class and put the functions into the
00125    class structure */
00126 static void
00127 indicator_object_class_init (IndicatorObjectClass *klass)
00128 {
00129        GObjectClass *object_class = G_OBJECT_CLASS (klass);
00130 
00131        g_type_class_add_private (klass, sizeof (IndicatorObjectPrivate));
00132 
00133        object_class->dispose = indicator_object_dispose;
00134        object_class->finalize = indicator_object_finalize;
00135        object_class->set_property = set_property;
00136        object_class->get_property = get_property;
00137 
00138        klass->get_label =  NULL;
00139        klass->get_menu  =  NULL;
00140        klass->get_image =  NULL;
00141        klass->get_accessible_desc = NULL;
00142        klass->get_entries = get_entries_default;
00143        klass->get_location = NULL;
00144        klass->entry_being_removed = entry_being_removed_default;
00145        klass->entry_was_added = entry_was_added_default;
00146 
00147        klass->entry_activate = NULL;
00148        klass->entry_activate_window = NULL;
00149        klass->entry_close = NULL;
00150 
00160        signals[ENTRY_ADDED] = g_signal_new (INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,
00161                                             G_TYPE_FROM_CLASS(klass),
00162                                             G_SIGNAL_RUN_LAST,
00163                                             G_STRUCT_OFFSET (IndicatorObjectClass, entry_added),
00164                                             NULL, NULL,
00165                                             g_cclosure_marshal_VOID__POINTER,
00166                                             G_TYPE_NONE, 1, G_TYPE_POINTER, G_TYPE_NONE);
00167 
00177        signals[ENTRY_REMOVED] = g_signal_new (INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED,
00178                                               G_TYPE_FROM_CLASS(klass),
00179                                               G_SIGNAL_RUN_LAST,
00180                                               G_STRUCT_OFFSET (IndicatorObjectClass, entry_removed),
00181                                               NULL, NULL,
00182                                               g_cclosure_marshal_VOID__POINTER,
00183                                               G_TYPE_NONE, 1, G_TYPE_POINTER, G_TYPE_NONE);
00195        signals[ENTRY_MOVED] = g_signal_new (INDICATOR_OBJECT_SIGNAL_ENTRY_MOVED,
00196                                             G_TYPE_FROM_CLASS(klass),
00197                                             G_SIGNAL_RUN_LAST,
00198                                             G_STRUCT_OFFSET (IndicatorObjectClass, entry_moved),
00199                                             NULL, NULL,
00200                                             _indicator_object_marshal_VOID__POINTER_UINT_UINT,
00201                                             G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_NONE);
00213        signals[ENTRY_SCROLLED] = g_signal_new (INDICATOR_OBJECT_SIGNAL_ENTRY_SCROLLED,
00214                                        G_TYPE_FROM_CLASS(klass),
00215                                        G_SIGNAL_RUN_LAST,
00216                                        G_STRUCT_OFFSET (IndicatorObjectClass, entry_scrolled),
00217                                        NULL, NULL,
00218                                        _indicator_object_marshal_VOID__POINTER_UINT_ENUM,
00219                                        G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_UINT,
00220                                        INDICATOR_OBJECT_TYPE_SCROLL_DIRECTION);
00231        signals[SECONDARY_ACTIVATE] = g_signal_new (INDICATOR_OBJECT_SIGNAL_SECONDARY_ACTIVATE,
00232                                        G_TYPE_FROM_CLASS(klass),
00233                                        G_SIGNAL_RUN_LAST,
00234                                        G_STRUCT_OFFSET (IndicatorObjectClass, secondary_activate),
00235                                        NULL, NULL,
00236                                        _indicator_object_marshal_VOID__POINTER_UINT,
00237                                        G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
00238 
00249        signals[MENU_SHOW] = g_signal_new (INDICATOR_OBJECT_SIGNAL_MENU_SHOW,
00250                                           G_TYPE_FROM_CLASS(klass),
00251                                           G_SIGNAL_RUN_LAST,
00252                                           G_STRUCT_OFFSET (IndicatorObjectClass, menu_show),
00253                                           NULL, NULL,
00254                                           _indicator_object_marshal_VOID__POINTER_UINT,
00255                                           G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
00256 
00267        signals[SHOW_NOW_CHANGED] = g_signal_new (INDICATOR_OBJECT_SIGNAL_SHOW_NOW_CHANGED,
00268                                                  G_TYPE_FROM_CLASS(klass),
00269                                                  G_SIGNAL_RUN_LAST,
00270                                                  G_STRUCT_OFFSET (IndicatorObjectClass, show_now_changed),
00271                                                  NULL, NULL,
00272                                                  _indicator_object_marshal_VOID__POINTER_BOOLEAN,
00273                                                  G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
00274 
00285        signals[ACCESSIBLE_DESC_UPDATE] = g_signal_new (INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE,
00286                                             G_TYPE_FROM_CLASS(klass),
00287                                             G_SIGNAL_RUN_LAST,
00288                                             G_STRUCT_OFFSET (IndicatorObjectClass, accessible_desc_update),
00289                                             NULL, NULL,
00290                                             g_cclosure_marshal_VOID__POINTER,
00291                                             G_TYPE_NONE, 1, G_TYPE_POINTER, G_TYPE_NONE);
00292 
00293        /* Properties */
00294 
00295        GParamSpec * pspec = g_param_spec_boolean (INDICATOR_OBJECT_DEFAULT_VISIBILITY,
00296                      "default visibility",
00297                      "Whether or not entries should initially be visible.",
00298                      TRUE,
00299                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
00300        g_object_class_install_property (object_class, PROP_DEFAULT_VISIBILITY, pspec);
00301 }
00302 
00303 /* Initialize an instance */
00304 static void
00305 indicator_object_init (IndicatorObject *self)
00306 {
00307        IndicatorObjectPrivate * priv = G_TYPE_INSTANCE_GET_PRIVATE (self, INDICATOR_OBJECT_TYPE, IndicatorObjectPrivate);
00308 
00309        priv->module = NULL;
00310 
00311        priv->entry.parent_object = self;
00312        priv->entry.menu = NULL;
00313        priv->entry.label = NULL;
00314        priv->entry.image = NULL;
00315        priv->entry.accessible_desc = NULL;
00316        priv->entry.name_hint = NULL;
00317 
00318        priv->gotten_entries = FALSE;
00319        priv->default_visibility = TRUE;
00320        priv->entry_privates = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
00321 
00322        priv->environments = NULL;
00323 
00324        self->priv = priv;
00325 
00326        GObject * o = G_OBJECT(self);
00327        /* Invoke the entry-being-removed virtual function first */
00328        g_signal_connect (o, INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED,
00329                          G_CALLBACK(indicator_object_entry_being_removed), NULL);
00330        /* Invoke the entry-was-added virtual function last */
00331        g_signal_connect_after (o, INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,
00332                                G_CALLBACK(indicator_object_entry_was_added), NULL);
00333 }
00334 
00335 /* Unref the objects that we're holding on to. */
00336 static void
00337 indicator_object_dispose (GObject *object)
00338 {
00339        /* Ensure that hidden entries are re-added so their widgetry will
00340           be cleaned up properly by the client */
00341        indicator_object_set_visible (INDICATOR_OBJECT (object), TRUE);
00342 
00343        G_OBJECT_CLASS (indicator_object_parent_class)->dispose (object);
00344 }
00345 
00346 /* A small helper function that closes a module but
00347    in the function prototype of a GSourceFunc. */
00348 static gboolean
00349 module_unref (gpointer data)
00350 {
00351        if (!g_module_close((GModule *)data)) {
00352               /* All we can do is warn. */
00353               g_warning("Unable to close module!");
00354        }
00355        return FALSE;
00356 }
00357 
00358 /* Free memory */
00359 static void
00360 indicator_object_finalize (GObject *object)
00361 {
00362        IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(object);
00363 
00364        if (priv->entry_privates != NULL) {
00365               g_hash_table_destroy (priv->entry_privates);
00366               priv->entry_privates = NULL;
00367        }
00368 
00369        if (priv->environments != NULL) {
00370               g_strfreev(priv->environments);
00371               priv->environments = NULL;
00372        }
00373 
00374        if (priv->module != NULL) {
00375               /* Wow, this is convoluted.  So basically we want to unref
00376                  the module which will cause the code it included to be
00377                  removed.  But, since its finalize function is the function
00378                  that called this one, we can't really remove it before
00379                  it finishes being executed.  So we're putting the job into
00380                  the main loop to remove it the next time it gets a chance.
00381                  Slightly non-deterministic, but should work. */
00382               g_idle_add(module_unref, priv->module);
00383               priv->module = NULL;
00384        }
00385 
00386        G_OBJECT_CLASS (indicator_object_parent_class)->finalize (object);
00387        return;
00388 }
00389 
00401 IndicatorObject *
00402 indicator_object_new_from_file (const gchar * file)
00403 {
00404        GObject * object = NULL;
00405        GModule * module = NULL;
00406 
00407        /* Check to make sure the name exists and that the
00408           file itself exists */
00409        if (file == NULL) {
00410               g_warning("Invalid filename.");
00411               return NULL;
00412        }
00413 
00414        if (!g_file_test(file, G_FILE_TEST_EXISTS)) {
00415               g_warning("File '%s' does not exist.", file);
00416               return NULL;
00417        }
00418 
00419        /* Grab the g_module reference, pull it in but let's
00420           keep the symbols local to avoid conflicts. */
00421        module = g_module_open(file,
00422                            G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
00423        if (module == NULL) {
00424               g_warning("Unable to load module: %s", file);
00425               return NULL;
00426        }
00427 
00428        /* Look for the version function, error if not found. */
00429        get_version_t lget_version = NULL;
00430        if (!g_module_symbol(module, INDICATOR_GET_VERSION_S, (gpointer *)(&lget_version))) {
00431               g_warning("Unable to get the symbol for getting the version.");
00432               return NULL;
00433        }
00434 
00435        /* Check the version with the macro and make sure we're
00436           all talking the same language. */
00437        if (!INDICATOR_VERSION_CHECK(lget_version())) {
00438               g_warning("Indicator using API version '%s' we're expecting '%s'", lget_version(), INDICATOR_VERSION);
00439               return NULL;
00440        }
00441 
00442        /* The function for grabbing a label from the module
00443           execute it, and make sure everything is a-okay */
00444        get_type_t lget_type = NULL;
00445        if (!g_module_symbol(module, INDICATOR_GET_TYPE_S, (gpointer *)(&lget_type))) {
00446               g_warning("Unable to get '" INDICATOR_GET_TYPE_S "' symbol from module: %s", file);
00447               goto unrefandout;
00448        }
00449        if (lget_type == NULL) {
00450               g_warning("Symbol '" INDICATOR_GET_TYPE_S "' is (null) in module: %s", file);
00451               goto unrefandout;
00452        }
00453 
00454        /* A this point we allocate the object, any code beyond
00455           here needs to deallocate it if we're returning in an
00456           error'd state. */
00457        object = g_object_new(lget_type(), NULL);
00458        if (object == NULL) {
00459               g_warning("Unable to build an object if type '%d' in module: %s", (gint)lget_type(), file);
00460               goto unrefandout;
00461        }
00462        if (!INDICATOR_IS_OBJECT(object)) {
00463               g_warning("Type '%d' in file %s is not a subclass of IndicatorObject.", (gint)lget_type(), file);
00464               goto unrefandout;
00465        }
00466 
00467        /* Now we can track the module */
00468        INDICATOR_OBJECT_GET_PRIVATE(object)->module = module;
00469 
00470        return INDICATOR_OBJECT(object);
00471 
00472        /* Error, let's drop the object and return NULL.  Sad when
00473           this happens. */
00474 unrefandout:
00475        g_clear_object (&object);
00476        g_clear_object (&module);
00477        g_warning("Error building IndicatorObject from file: %s", file);
00478        return NULL;
00479 }
00480 
00481 /* The default get entries function uses the other single
00482    entries in the class to create an entry structure and
00483    put it into a list.  This makes it simple for simple objects
00484    to create the list.  Small changes from the way they
00485    previously were. */
00486 static GList *
00487 get_entries_default (IndicatorObject * io)
00488 {
00489        IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(io);
00490 
00491        if (!priv->gotten_entries) {
00492               IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
00493 
00494               priv->entry.parent_object = io;
00495 
00496               if (class->get_label) {
00497                      priv->entry.label = class->get_label(io);
00498               }
00499 
00500               if (class->get_image) {
00501                      priv->entry.image = class->get_image(io);
00502               }
00503 
00504               if (priv->entry.image == NULL && priv->entry.label == NULL) {
00505                      g_warning("IndicatorObject class does not create an image or a label.  We need one of those.");
00506                      return NULL;
00507               }
00508 
00509               if (class->get_menu) {
00510                      priv->entry.menu = class->get_menu(io);
00511               }
00512 
00513               if (priv->entry.menu == NULL) {
00514                      g_warning("IndicatorObject class does not create a menu.  We need one of those.");
00515                      return NULL;
00516               }
00517 
00518               if (class->get_accessible_desc) {
00519                      priv->entry.accessible_desc = class->get_accessible_desc(io);
00520               }
00521 
00522               if (priv->entry.accessible_desc == NULL) {
00523                      g_warning("IndicatorObject class does not have an accessible description.");
00524               }
00525 
00526               if (class->get_name_hint) {
00527                      priv->entry.name_hint = class->get_name_hint(io);
00528               }
00529 
00530               priv->gotten_entries = TRUE;
00531        }
00532 
00533        return g_list_append(NULL, &(priv->entry));
00534 }
00535 
00536 /* returns a list of all IndicatorObjectEntires, visible or not */
00537 static GList*
00538 get_all_entries (IndicatorObject * io)
00539 {
00540        GList * all_entries = NULL, *l;
00541 
00542        g_return_val_if_fail(INDICATOR_IS_OBJECT(io), NULL);
00543        IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
00544 
00545        if (class->get_entries == NULL)
00546               g_error("No get_entries function on object.  It must have been deleted?!?!");
00547        else
00548        {
00549               all_entries = class->get_entries(io);
00550 
00551               for (l = all_entries; l; l = l->next)
00552               {
00553                      IndicatorObjectEntry *entry = l->data;
00554 
00555                      if (entry)
00556                             entry->parent_object = io;
00557               }
00558        }
00559 
00560        return all_entries;
00561 }
00562 
00563 /* get the private structure that corresponds to a caller-specified entry */
00564 static IndicatorObjectEntryPrivate *
00565 entry_get_private (IndicatorObject * io, IndicatorObjectEntry * entry)
00566 {
00567        g_return_val_if_fail (INDICATOR_IS_OBJECT(io), NULL);
00568        g_return_val_if_fail (io->priv != NULL, NULL);
00569 
00570        GHashTable * h = io->priv->entry_privates;
00571        IndicatorObjectEntryPrivate * priv = g_hash_table_lookup (h, entry);
00572        if (priv == NULL)
00573        {
00574               priv = g_new0 (IndicatorObjectEntryPrivate, 1);
00575               priv->visibility = ENTRY_INIT;
00576               g_hash_table_insert (h, entry, priv);
00577        }
00578 
00579        return priv;
00580 }
00581 
00595 GList *
00596 indicator_object_get_entries (IndicatorObject * io)
00597 {
00598        GList * l;
00599        GList * ret = NULL;
00600        GList * all_entries = get_all_entries (io);
00601        const gboolean default_visibility = INDICATOR_OBJECT_GET_PRIVATE(io)->default_visibility;
00602 
00603        for (l=all_entries; l!=NULL; l=l->next)
00604        {
00605               gboolean show_me;
00606               IndicatorObjectEntry * entry = l->data;
00607 
00608               switch (entry_get_private(io,entry)->visibility) {
00609                      case ENTRY_VISIBLE:   show_me = TRUE; break;
00610                      case ENTRY_INVISIBLE: show_me = FALSE; break;
00611                      case ENTRY_INIT:      show_me = default_visibility; break;
00612                      default:              show_me = TRUE; g_warn_if_reached(); break;
00613               }
00614 
00615               if (show_me)
00616                      ret = g_list_prepend (ret, entry);
00617        }
00618 
00619        g_list_free (all_entries);
00620        return g_list_reverse (ret);
00621 }
00622 
00635 guint
00636 indicator_object_get_location (IndicatorObject * io, IndicatorObjectEntry * entry)
00637 {
00638        g_return_val_if_fail(INDICATOR_IS_OBJECT(io), 0);
00639        IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
00640 
00641        if (class->get_location) {
00642               return class->get_location(io, entry);
00643        }
00644 
00645        return 0;
00646 }
00647 
00659 guint
00660 indicator_object_get_show_now (IndicatorObject * io, IndicatorObjectEntry * entry)
00661 {
00662        g_return_val_if_fail(INDICATOR_IS_OBJECT(io), 0);
00663        IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
00664 
00665        if (class->get_show_now) {
00666               return class->get_show_now(io, entry);
00667        }
00668 
00669        return FALSE;
00670 }
00671 
00688 void
00689 indicator_object_entry_activate_window (IndicatorObject * io, IndicatorObjectEntry * entry, guint windowid, guint timestamp)
00690 {
00691        g_return_if_fail(INDICATOR_IS_OBJECT(io));
00692        IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
00693 
00694        if (class->entry_activate_window != NULL) {
00695               return class->entry_activate_window(io, entry, windowid, timestamp);
00696        } else {
00697               indicator_object_entry_activate(io, entry, timestamp);
00698        }
00699 
00700        return;
00701 }
00702 
00714 void
00715 indicator_object_entry_activate (IndicatorObject * io, IndicatorObjectEntry * entry, guint timestamp)
00716 {
00717        g_return_if_fail(INDICATOR_IS_OBJECT(io));
00718        IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
00719 
00720        if (class->entry_activate != NULL) {
00721               return class->entry_activate(io, entry, timestamp);
00722        }
00723 
00724        return;
00725 }
00726 
00736 void
00737 indicator_object_entry_close (IndicatorObject * io, IndicatorObjectEntry * entry, guint timestamp)
00738 {
00739        g_return_if_fail(INDICATOR_IS_OBJECT(io));
00740        IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
00741 
00742        if (class->entry_close != NULL) {
00743               return class->entry_close(io, entry, timestamp);
00744        }
00745 
00746        return;
00747 }
00748 
00749 static void
00750 indicator_object_entry_being_removed (IndicatorObject * io, IndicatorObjectEntry * entry)
00751 {
00752        g_return_if_fail(INDICATOR_IS_OBJECT(io));
00753        IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
00754 
00755        entry_get_private (io, entry)->visibility = ENTRY_INVISIBLE;
00756 
00757        if (entry)
00758               entry->parent_object = NULL;
00759 
00760        if (class->entry_being_removed != NULL)
00761        {
00762               class->entry_being_removed (io, entry);
00763        }
00764 }
00765 
00766 static void
00767 indicator_object_entry_was_added (IndicatorObject * io, IndicatorObjectEntry * entry)
00768 {
00769        g_return_if_fail(INDICATOR_IS_OBJECT(io));
00770        IndicatorObjectClass * class = INDICATOR_OBJECT_GET_CLASS(io);
00771 
00772        entry_get_private (io, entry)->visibility = ENTRY_VISIBLE;
00773 
00774        if (entry)
00775               entry->parent_object = io;
00776 
00777        if (class->entry_was_added != NULL)
00778        {
00779               class->entry_was_added (io, entry);
00780        }
00781 }
00782 
00792 void
00793 indicator_object_set_environment (IndicatorObject * io, GStrv env)
00794 {
00795        /* FIXME: should this be a property? */
00796        g_return_if_fail(INDICATOR_IS_OBJECT(io));
00797 
00798        if (io->priv->environments != NULL) {
00799               g_strfreev(io->priv->environments);
00800               io->priv->environments = NULL;
00801        }
00802 
00803        io->priv->environments = g_strdupv(env);
00804 
00805        return;
00806 }
00807 
00818 GStrv
00819 indicator_object_get_environment (IndicatorObject * io)
00820 {
00821        g_return_val_if_fail(INDICATOR_IS_OBJECT(io), NULL);
00822        return io->priv->environments;
00823 }
00824 
00835 gboolean
00836 indicator_object_check_environment (IndicatorObject * io, const gchar * env)
00837 {
00838        g_return_val_if_fail(INDICATOR_IS_OBJECT(io), FALSE);
00839        g_return_val_if_fail(env != NULL, FALSE);
00840 
00841        if (io->priv->environments == NULL) {
00842               return FALSE;
00843        }
00844 
00845        int i;
00846        for (i = 0; io->priv->environments[i] != NULL; i++) {
00847               if (g_strcmp0(env, io->priv->environments[i]) == 0) {
00848                      return TRUE;
00849               }
00850        }
00851 
00852        return FALSE;
00853 }
00854 
00862 void
00863 indicator_object_set_visible (IndicatorObject * io, gboolean visible)
00864 {
00865        g_return_if_fail(INDICATOR_IS_OBJECT(io));
00866 
00867        GList * l;
00868        GList * entries = get_all_entries (io);
00869        const guint signal_id = signals[visible ? ENTRY_ADDED : ENTRY_REMOVED];
00870        EntryVisibility visibility = visible ? ENTRY_VISIBLE : ENTRY_INVISIBLE;
00871        const GQuark detail = (GQuark)0;
00872 
00873        for (l=entries; l!=NULL; l=l->next) {
00874               IndicatorObjectEntry *entry = l->data;
00875               if (entry_get_private (io, entry)->visibility != visibility)
00876                      g_signal_emit(io, signal_id, detail, entry);
00877        }
00878        g_list_free (entries);
00879 }
00880 
00881 static void
00882 get_property (GObject     * object,
00883               guint         prop_id,
00884               GValue      * value,
00885               GParamSpec  * pspec)
00886 {
00887         IndicatorObject * self = INDICATOR_OBJECT(object);
00888         g_return_if_fail(self != NULL);
00889 
00890         IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(self);
00891         g_return_if_fail(priv != NULL);
00892 
00893         switch (prop_id) {
00894         /* *********************** */
00895         case PROP_DEFAULT_VISIBILITY:
00896                 if (G_VALUE_HOLDS_BOOLEAN(value)) {
00897                         g_value_set_boolean(value, priv->default_visibility);
00898                 } else {
00899                         g_warning("default-visibility property requires a boolean value.");
00900                 }
00901                 break;
00902         /* *********************** */
00903         default:
00904                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
00905                 break;
00906         }
00907 }
00908 
00909 static void
00910 set_property (GObject       * object,
00911               guint           prop_id,
00912               const GValue  * value,
00913               GParamSpec    * pspec)
00914 {
00915         IndicatorObject * self = INDICATOR_OBJECT(object);
00916         g_return_if_fail (self != NULL);
00917 
00918         IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(self);
00919         g_return_if_fail (priv != NULL);
00920 
00921 
00922         switch (prop_id) {
00923 
00924         /* *********************** */
00925         case PROP_DEFAULT_VISIBILITY:
00926                 if (G_VALUE_HOLDS_BOOLEAN(value)) {
00927                         priv->default_visibility = g_value_get_boolean (value);
00928                 } else {
00929                         g_warning("default-visibility property requires a boolean value.");
00930                 }
00931                 break;
00932     
00933     
00934         default:
00935                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
00936                 break;
00937         }
00938 }
00939 
00940 /***
00941 ****
00942 ***/
00943 
00944 /* Cloaked entries are ones which are hidden but may be re-added later.
00945    They are reffed + unparented so that they'll survive even if the
00946    rest of the widgetry is destroyed */
00947 #define CLOAKED_KEY "entry-is-cloaked"
00948 
00949 static void
00950 decloak_widget (gpointer w)
00951 {
00952        if (w != NULL) {
00953               GObject * o = G_OBJECT(w);
00954               if (g_object_steal_data (o, CLOAKED_KEY) != NULL) {
00955                      g_object_unref (o);
00956               }
00957        }
00958 }
00959 
00960 static void
00961 entry_was_added_default (IndicatorObject * io, IndicatorObjectEntry * entry)
00962 {
00963        decloak_widget (entry->image);
00964        decloak_widget (entry->label);
00965        decloak_widget (entry->menu);
00966 }
00967 
00968 static void
00969 cloak_widget (gpointer w)
00970 {
00971        if (w != NULL) {
00972               GtkWidget * parent;
00973 
00974               /* tag this object as cloaked */
00975               GObject * o = G_OBJECT(w);
00976               g_object_ref (o);
00977               g_object_set_data (o, CLOAKED_KEY, GINT_TO_POINTER(1));
00978 
00979               /* remove it from its surrounding widgetry */
00980               if(GTK_IS_MENU(w)) {
00981                      if (gtk_menu_get_attach_widget (GTK_MENU(w)) != NULL) {
00982                             gtk_menu_detach (GTK_MENU(w));
00983                      }
00984               }
00985               else if((parent = gtk_widget_get_parent(w))) {
00986                      gtk_container_remove(GTK_CONTAINER(parent), w);
00987               }
00988        }
00989 }
00990 
00991 static void
00992 entry_being_removed_default (IndicatorObject * io, IndicatorObjectEntry * entry)
00993 {
00994        cloak_widget (entry->image);
00995        cloak_widget (entry->label);
00996        cloak_widget (entry->menu);
00997 }