Back to index

libindicate  12.10.0
server.c
Go to the documentation of this file.
00001 /*
00002 A library to allow applictions to provide simple indications of
00003 information to be displayed to users of the application through the
00004 interface shell.
00005 
00006 Copyright 2009 Canonical Ltd.
00007 
00008 Authors:
00009     Ted Gould <ted@canonical.com>
00010 
00011 This program is free software: you can redistribute it and/or modify it 
00012 under the terms of either or both of the following licenses:
00013 
00014 1) the GNU Lesser General Public License version 3, as published by the 
00015 Free Software Foundation; and/or
00016 2) the GNU Lesser General Public License version 2.1, as published by 
00017 the Free Software Foundation.
00018 
00019 This program is distributed in the hope that it will be useful, but 
00020 WITHOUT ANY WARRANTY; without even the implied warranties of 
00021 MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR 
00022 PURPOSE.  See the applicable version of the GNU Lesser General Public 
00023 License for more details.
00024 
00025 You should have received a copy of both the GNU Lesser General Public 
00026 License version 3 and version 2.1 along with this program.  If not, see 
00027 <http://www.gnu.org/licenses/>
00028 */
00029  
00030 #include "server.h"
00031 #include "interests-priv.h"
00032 #include "indicate-marshal.h"
00033 #include <gio/gio.h>
00034 #include <libdbusmenu-glib/server.h>
00035 #include "dbus-shared.h"
00036 #include "gen-indicate-interface.xml.h"
00037 
00038 /* Errors */
00039 enum {
00040        NO_GET_DESKTOP,
00041        NO_GET_INDICATOR_COUNT,
00042        NO_GET_INDICATOR_LIST,
00043        NO_GET_INDICATOR_PROPERTY,
00044        NO_GET_INDICATOR_PROPERTY_GROUP,
00045        NO_GET_INDICATOR_PROPERTIES,
00046        NO_SHOW_INDICATOR_TO_USER,
00047        NO_INDICATOR_DISPLAYED,
00048        INVALID_INDICATOR_ID,
00049        NO_SHOW_INTEREST,
00050        NO_REMOVE_INTEREST,
00051        SHOW_INTEREST_FAILED,
00052        REMOVE_INTEREST_FAILED,
00053        NO_MAX_INDICATORS_SET,
00054        MAX_INDICATORS_SET_FAILED,
00055        NO_SUCH_PROPERTY,
00056        NOT_IMPLEMENTED,
00057        LAST_ERROR
00058 };
00059 
00060 /* Signals */
00061 enum {
00062        INDICATOR_ADDED,
00063        INDICATOR_REMOVED,
00064        INDICATOR_MODIFIED,
00065        SERVER_SHOW,
00066        SERVER_HIDE,
00067        SERVER_DISPLAY,
00068        INTEREST_ADDED,
00069        INTEREST_REMOVED,
00070        MAX_INDICATORS_CHANGED,
00071        INDICATOR_NOT_SHOWN,
00072        SERVER_COUNT_CHANGED,
00073        LAST_SIGNAL
00074 };
00075 
00076 /* Properties */
00077 enum {
00078        PROP_0,
00079        PROP_DESKTOP,
00080        PROP_TYPE,
00081        PROP_COUNT,
00082        PROP_MENU, 
00083        PROP_PATH,
00084        PROP_ICON_THEME
00085 };
00086 
00087 static guint signals[LAST_SIGNAL] = { 0 };
00088 
00089 /* Private area */
00090 typedef struct _IndicateServerPrivate IndicateServerPrivate;
00091 struct _IndicateServerPrivate
00092 {
00093        GCancellable * connection_cancel;
00094        GDBusConnection *connection;
00095        guint broadcast_signal;
00096 
00097        gchar * path;
00098        GSList * indicators;
00099        gboolean visible;
00100        guint current_id;
00101        guint registered;
00102 
00103        gchar * desktop;
00104        gchar * type;
00105        gchar * icon_theme;
00106 
00107        guint count;
00108 
00109        DbusmenuServer * dbusmenu;
00110 
00111        // TODO: Should have a more robust way to track this, but this'll work for now
00112        guint num_hidden;
00113 
00114        /* Folks storage */
00115        GList * interestedfolks;
00116 
00117        /* Folks caches */
00118        gint max_indicators;
00119        gboolean interests[INDICATE_INTEREST_LAST];
00120        gulong interest_timer;
00121 };
00122 
00123 #define INDICATE_SERVER_GET_PRIVATE(o) \
00124           (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATE_TYPE_SERVER, IndicateServerPrivate))
00125 
00126 typedef struct _IndicateServerInterestedFolk IndicateServerInterestedFolk;
00127 struct _IndicateServerInterestedFolk {
00128        gchar * sender;
00129        gboolean interests[INDICATE_INTEREST_LAST];
00130        gint max_indicators;
00131        GHashTable * indicators_displayed;
00132        GDBusProxy * proxy;
00133 };
00134 
00135 static const gint MAX_INDICATORS_INFINITE = -1;
00136 static const gint MAX_INDICATORS_UNSET = -2;
00137 
00138 /* Define Type */
00139 G_DEFINE_TYPE (IndicateServer, indicate_server, G_TYPE_OBJECT);
00140 
00141 /* Prototypes */
00142 static void indicate_server_dispose (GObject * obj);
00143 static void indicate_server_finalize (GObject * obj);
00144 static gboolean get_indicator_count (IndicateServer * server, guint * count, GError **error);
00145 static gboolean get_indicator_list (IndicateServer * server, GArray ** indicators, GError ** error);
00146 static IndicateIndicator * get_indicator (IndicateServer * server, guint id, GError **error);
00147 static gboolean get_indicator_property (IndicateServer * server, guint id, gchar * property, GVariant ** value, GError **error);
00148 static gboolean get_indicator_property_group (IndicateServer * server, guint id, const gchar ** properties, GVariant ** output, GError **error);
00149 static gboolean get_indicator_properties (IndicateServer * server, guint id, gchar *** properties, GError **error);
00150 static gboolean show_indicator_to_user (IndicateServer * server, guint id, guint timestamp, GError ** error);
00151 static gboolean indicator_displayed (IndicateServer * server, const gchar * sender, guint id, gboolean displayed, GError ** error);
00152 static void indicator_display_check_recalc (gpointer key, gpointer value, gpointer userdata);
00153 static void recalculate_indicator_displayed (IndicateServer * server, guint id);
00154 static guint get_next_id (IndicateServer * server);
00155 static void set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec);
00156 static void get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec);
00157 static gboolean show_interest (IndicateServer * server, const gchar * sender, IndicateInterests interest);
00158 static gboolean remove_interest (IndicateServer * server, const gchar * sender, IndicateInterests interest);
00159 static gboolean check_interest (IndicateServer * server, IndicateInterests intrest);
00160 static gint max_indicators_get (IndicateServer * server);
00161 static gboolean max_indicators_set (IndicateServer * server, const gchar * sender, gint max);
00162 static void recalculate_max_indicators (IndicateServer * server);
00163 static gint indicate_server_interested_folks_equal (gconstpointer a, gconstpointer b);
00164 static void indicate_server_interested_folks_init (IndicateServerInterestedFolk * folk, const gchar * sender, const gchar * path, GDBusConnection * connection);
00165 static void indicate_server_interested_folks_set (IndicateServerInterestedFolk * folk, IndicateInterests interest, gboolean value);
00166 static void indicate_server_interested_folks_copy (IndicateServerInterestedFolk * folk, gboolean * interests);
00167 static void indicate_server_interested_folks_destroy(IndicateServerInterestedFolk * folk);
00168 static void bus_connection_cb (GObject * obj, GAsyncResult * res, gpointer user_data);
00169 static void bus_broadcast_cb (GDBusConnection * connection, const gchar * sender, const gchar * object_path, const gchar * interface_name, const gchar * signal_name, GVariant * parameters, gpointer user_data);
00170 static void folk_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data);
00171 static void bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * method, GVariant * params, GDBusMethodInvocation * invocation, gpointer user_data);
00172 static GVariant * bus_get_prop (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * property, GError ** error, gpointer user_data);
00173 static void bus_get_indicator_count (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation);
00174 static void bus_get_indicator_list (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation);
00175 static void bus_get_indicator_property (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation);
00176 static void bus_get_indicator_property_group (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation);
00177 static void bus_get_indicator_properties (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation);
00178 static void bus_show_indicator_to_user (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation);
00179 static void bus_indicator_displayed (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation);
00180 static void bus_show_interest (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation);
00181 static void bus_remove_interest (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation);
00182 static void bus_set_max_indicators (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation);
00183 static GQuark indicate_server_error_quark (void);
00184 static gboolean interest_timer (gpointer user_data);
00185 
00186 /* Method Table */
00187 typedef void (*MethodTableFunc) (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation);
00188 
00189 typedef struct _method_table_t method_table_t;
00190 struct _method_table_t {
00191        const gchar * interned_name;
00192        MethodTableFunc func;
00193 };
00194 
00195 enum {
00196        METHOD_GET_INDICATOR_COUNT = 0,
00197        METHOD_GET_INDICATOR_LIST,
00198        METHOD_GET_INDICATOR_PROPERTY,
00199        METHOD_GET_INDICATOR_PROPERTY_GROUP,
00200        METHOD_GET_INDICATOR_PROPERTIES,
00201        METHOD_SHOW_INDICATOR_TO_USER,
00202        METHOD_INDICATOR_DISPLAYED,
00203        METHOD_SHOW_INTEREST,
00204        METHOD_REMOVE_INTEREST,
00205        METHOD_SET_MAX_INDICATORS,
00206        /* Counter, do not remove! */
00207        METHOD_COUNT
00208 };
00209 
00210 /* Bus Stuff */
00211 static GDBusNodeInfo *            bus_node_info = NULL;
00212 static GDBusInterfaceInfo *       bus_interface_info = NULL;
00213 static const GDBusInterfaceVTable bus_interface_table = {
00214        method_call:    bus_method_call,
00215        get_property:   bus_get_prop,
00216        set_property:   NULL /* No properties that can be set */
00217 };
00218 static method_table_t             bus_method_table[METHOD_COUNT];
00219 
00220 
00221 
00222 /* Code */
00223 static void
00224 indicate_server_class_init (IndicateServerClass * class)
00225 {
00226        /* g_debug("Server Class Initialized"); */
00227        GObjectClass * gobj;
00228        gobj = G_OBJECT_CLASS(class);
00229 
00230        g_type_class_add_private (class, sizeof (IndicateServerPrivate));
00231 
00232        gobj->dispose = indicate_server_dispose;
00233        gobj->finalize = indicate_server_finalize;
00234        gobj->set_property = set_property;
00235        gobj->get_property = get_property;
00236 
00245        signals[INDICATOR_ADDED] = g_signal_new(INDICATE_SERVER_SIGNAL_INDICATOR_ADDED,
00246                                                G_TYPE_FROM_CLASS (class),
00247                                                G_SIGNAL_RUN_LAST,
00248                                                G_STRUCT_OFFSET (IndicateServerClass, indicator_added),
00249                                                NULL, NULL,
00250                                                _indicate_marshal_VOID__UINT,
00251                                                G_TYPE_NONE, 1, G_TYPE_UINT);
00260        signals[INDICATOR_REMOVED] = g_signal_new(INDICATE_SERVER_SIGNAL_INDICATOR_REMOVED,
00261                                                G_TYPE_FROM_CLASS (class),
00262                                                G_SIGNAL_RUN_LAST,
00263                                                G_STRUCT_OFFSET (IndicateServerClass, indicator_removed),
00264                                                NULL, NULL,
00265                                                _indicate_marshal_VOID__UINT,
00266                                                G_TYPE_NONE, 1, G_TYPE_UINT);
00276        signals[INDICATOR_MODIFIED] = g_signal_new(INDICATE_SERVER_SIGNAL_INDICATOR_MODIFIED,
00277                                                G_TYPE_FROM_CLASS (class),
00278                                                G_SIGNAL_RUN_LAST,
00279                                                G_STRUCT_OFFSET (IndicateServerClass, indicator_modified),
00280                                                NULL, NULL,
00281                                                _indicate_marshal_VOID__UINT_STRING,
00282                                                G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
00292        signals[SERVER_SHOW] = g_signal_new(INDICATE_SERVER_SIGNAL_SERVER_SHOW,
00293                                                G_TYPE_FROM_CLASS (class),
00294                                                G_SIGNAL_RUN_LAST,
00295                                                G_STRUCT_OFFSET (IndicateServerClass, server_show),
00296                                                NULL, NULL,
00297                                                g_cclosure_marshal_VOID__STRING,
00298                                                G_TYPE_NONE, 1, G_TYPE_STRING);
00307        signals[SERVER_HIDE] = g_signal_new(INDICATE_SERVER_SIGNAL_SERVER_HIDE,
00308                                                G_TYPE_FROM_CLASS (class),
00309                                                G_SIGNAL_RUN_LAST,
00310                                                G_STRUCT_OFFSET (IndicateServerClass, server_hide),
00311                                                NULL, NULL,
00312                                                g_cclosure_marshal_VOID__STRING,
00313                                                G_TYPE_NONE, 1, G_TYPE_STRING);
00323        signals[SERVER_DISPLAY] = g_signal_new(INDICATE_SERVER_SIGNAL_SERVER_DISPLAY,
00324                                                G_TYPE_FROM_CLASS (class),
00325                                                G_SIGNAL_RUN_LAST,
00326                                                G_STRUCT_OFFSET (IndicateServerClass, server_display),
00327                                                NULL, NULL,
00328                                                g_cclosure_marshal_VOID__UINT,
00329                                                G_TYPE_NONE, 1, G_TYPE_UINT);
00338        signals[INTEREST_ADDED] = g_signal_new(INDICATE_SERVER_SIGNAL_INTEREST_ADDED,
00339                                                G_TYPE_FROM_CLASS (class),
00340                                                G_SIGNAL_RUN_LAST,
00341                                                G_STRUCT_OFFSET (IndicateServerClass, interest_added),
00342                                                NULL, NULL,
00343                                                g_cclosure_marshal_VOID__UINT,
00344                                                G_TYPE_NONE, 1, G_TYPE_UINT);
00357        signals[INTEREST_REMOVED] = g_signal_new(INDICATE_SERVER_SIGNAL_INTEREST_REMOVED,
00358                                                G_TYPE_FROM_CLASS (class),
00359                                                G_SIGNAL_RUN_LAST,
00360                                                G_STRUCT_OFFSET (IndicateServerClass, interest_removed),
00361                                                NULL, NULL,
00362                                                g_cclosure_marshal_VOID__UINT,
00363                                                G_TYPE_NONE, 1, G_TYPE_UINT);
00372        signals[MAX_INDICATORS_CHANGED] = g_signal_new(INDICATE_SERVER_SIGNAL_MAX_INDICATORS_CHANGED,
00373                                                G_TYPE_FROM_CLASS (class),
00374                                                G_SIGNAL_RUN_LAST,
00375                                                G_STRUCT_OFFSET (IndicateServerClass, max_indicators_changed),
00376                                                NULL, NULL,
00377                                                g_cclosure_marshal_VOID__INT,
00378                                                G_TYPE_NONE, 1, G_TYPE_INT);
00387        signals[SERVER_COUNT_CHANGED] = g_signal_new(INDICATE_SERVER_SIGNAL_SERVER_COUNT_CHANGED,
00388                                                G_TYPE_FROM_CLASS (class),
00389                                                G_SIGNAL_RUN_LAST,
00390                                                G_STRUCT_OFFSET (IndicateServerClass, server_count_changed),
00391                                                NULL, NULL,
00392                                                g_cclosure_marshal_VOID__UINT,
00393                                                G_TYPE_NONE, 1, G_TYPE_UINT);
00394 
00395        g_object_class_install_property (gobj, PROP_DESKTOP,
00396                                         g_param_spec_string("desktop", "Desktop File",
00397                                                      "The desktop file representing this server",
00398                                                      "",
00399                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
00400        g_object_class_install_property (gobj, PROP_TYPE,
00401                                         g_param_spec_string("type", "Server Type",
00402                                                      "The type of indicators that this server will provide",
00403                                                      "",
00404                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
00405        g_object_class_install_property (gobj, PROP_COUNT,
00406                                         g_param_spec_uint("count", "Server Count",
00407                                                      "A number reprsenting the number of items in a server",
00408                                                                                       0, G_MAXUINT, 0,
00409                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
00410        g_object_class_install_property (gobj, PROP_MENU,
00411                                         g_param_spec_string("menu", "DBus Menu Object Path",
00412                                                      "The DBus Object path to an object with a dbusmenu interface on it.",
00413                                                                                       "",
00414                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
00415        g_object_class_install_property (gobj, PROP_PATH,
00416                                     g_param_spec_string("path", "DBus Path for server", "DBus path for the server object", "/com/canonical/indicate",
00417                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
00418        g_object_class_install_property (gobj, PROP_ICON_THEME,
00419                                     g_param_spec_string("icon-theme", "Icon Theme Name",
00420                                                       "The Custom Icon Theme Name to use when displaying this Server.",
00421                                                       "",
00422                                                       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
00423 
00424        class->get_indicator_count = get_indicator_count;
00425        class->get_indicator_list = get_indicator_list;
00426        class->get_indicator_property = get_indicator_property;
00427        class->get_indicator_property_group = get_indicator_property_group;
00428        class->get_indicator_properties = get_indicator_properties;
00429        class->show_indicator_to_user = show_indicator_to_user;
00430        class->indicator_displayed = indicator_displayed;
00431        class->get_next_id = get_next_id;
00432        class->show_interest = show_interest;
00433        class->remove_interest = remove_interest;
00434        class->check_interest = check_interest;
00435        class->max_indicators_get = max_indicators_get;
00436        class->max_indicators_set = max_indicators_set;
00437 
00438        /* DBus interfaces */
00439        if (bus_node_info == NULL) {
00440               GError * error = NULL;
00441 
00442               bus_node_info = g_dbus_node_info_new_for_xml(_indicate_interface, &error);
00443               if (error != NULL) {
00444                      g_error("Unable to parse Indicate Interface description: %s", error->message);
00445                      g_error_free(error);
00446               }
00447        }
00448 
00449        if (bus_interface_info == NULL) {
00450               bus_interface_info = g_dbus_node_info_lookup_interface(bus_node_info, INDICATE_DBUS_IFACE);
00451 
00452               if (bus_interface_info == NULL) {
00453                      g_error("Unable to find interface '" INDICATE_DBUS_IFACE "'");
00454               }
00455        }
00456 
00457        /* Building our Method table :( */
00458        bus_method_table[METHOD_GET_INDICATOR_COUNT].interned_name          = g_intern_static_string("GetIndicatorCount");
00459        bus_method_table[METHOD_GET_INDICATOR_COUNT].func                   = bus_get_indicator_count;
00460 
00461        bus_method_table[METHOD_GET_INDICATOR_LIST].interned_name           = g_intern_static_string("GetIndicatorList");
00462        bus_method_table[METHOD_GET_INDICATOR_LIST].func                    = bus_get_indicator_list;
00463 
00464        bus_method_table[METHOD_GET_INDICATOR_PROPERTY].interned_name       = g_intern_static_string("GetIndicatorProperty");
00465        bus_method_table[METHOD_GET_INDICATOR_PROPERTY].func                = bus_get_indicator_property;
00466 
00467        bus_method_table[METHOD_GET_INDICATOR_PROPERTY_GROUP].interned_name = g_intern_static_string("GetIndicatorPropertyGroup");
00468        bus_method_table[METHOD_GET_INDICATOR_PROPERTY_GROUP].func          = bus_get_indicator_property_group;
00469 
00470        bus_method_table[METHOD_GET_INDICATOR_PROPERTIES].interned_name     = g_intern_static_string("GetIndicatorProperties");
00471        bus_method_table[METHOD_GET_INDICATOR_PROPERTIES].func              = bus_get_indicator_properties;
00472 
00473        bus_method_table[METHOD_SHOW_INDICATOR_TO_USER].interned_name       = g_intern_static_string("ShowIndicatorToUser");
00474        bus_method_table[METHOD_SHOW_INDICATOR_TO_USER].func                = bus_show_indicator_to_user;
00475 
00476        bus_method_table[METHOD_INDICATOR_DISPLAYED].interned_name          = g_intern_static_string("IndicatorDisplayed");
00477        bus_method_table[METHOD_INDICATOR_DISPLAYED].func                   = bus_indicator_displayed;
00478 
00479        bus_method_table[METHOD_SHOW_INTEREST].interned_name                = g_intern_static_string("ShowInterest");
00480        bus_method_table[METHOD_SHOW_INTEREST].func                         = bus_show_interest;
00481 
00482        bus_method_table[METHOD_REMOVE_INTEREST].interned_name              = g_intern_static_string("RemoveInterest");
00483        bus_method_table[METHOD_REMOVE_INTEREST].func                       = bus_remove_interest;
00484 
00485        bus_method_table[METHOD_SET_MAX_INDICATORS].interned_name           = g_intern_static_string("SetMaxIndicators");
00486        bus_method_table[METHOD_SET_MAX_INDICATORS].func                    = bus_set_max_indicators;
00487 
00488 
00489        return;
00490 }
00491 
00492 static void
00493 indicate_server_init (IndicateServer * server)
00494 {
00495        /* g_debug("Server Object Initialized"); */
00496 
00497        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
00498 
00499        priv->path = NULL;
00500        priv->indicators = NULL;
00501        priv->num_hidden = 0;
00502        priv->visible = FALSE;
00503        priv->registered = 0;
00504        priv->current_id = 0;
00505        priv->type = NULL;
00506        priv->desktop = NULL;
00507        priv->count = 0;
00508        priv->dbusmenu = NULL;
00509 
00510        guint i;
00511        for (i = INDICATE_INTEREST_NONE; i < INDICATE_INTEREST_LAST; i++) {
00512               priv->interests[i] = FALSE;
00513        }
00514        priv->interestedfolks = NULL;
00515        priv->max_indicators = MAX_INDICATORS_UNSET;
00516 
00517        priv->broadcast_signal = 0;
00518        priv->connection = NULL;
00519        priv->connection_cancel = g_cancellable_new();
00520        g_bus_get(G_BUS_TYPE_SESSION,
00521                  priv->connection_cancel, /* cancel */
00522                  bus_connection_cb,
00523                  server);
00524 
00525        priv->interest_timer = g_timeout_add(500, interest_timer, server);
00526 
00527        return;
00528 }
00529 
00530 static void
00531 indicate_server_dispose (GObject * obj)
00532 {
00533        IndicateServer * server = INDICATE_SERVER(obj);
00534        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
00535 
00536        if (priv->broadcast_signal != 0) {
00537               g_dbus_connection_signal_unsubscribe(priv->connection, priv->broadcast_signal);
00538               priv->broadcast_signal = 0;
00539        }
00540 
00541        if (priv->connection_cancel != NULL) {
00542               g_cancellable_cancel(priv->connection_cancel);
00543               g_object_unref(priv->connection_cancel);
00544               priv->connection_cancel = NULL;
00545        }
00546 
00547        if (priv->dbusmenu != NULL) {
00548               g_object_unref(priv->dbusmenu);
00549               priv->dbusmenu = NULL;
00550        }
00551 
00552        if (priv->visible) {
00553               if (priv->registered != 0) {
00554               g_dbus_connection_emit_signal(priv->connection,
00555                                             NULL, /* dest */
00556                                             priv->path,
00557                                             INDICATE_DBUS_IFACE,
00558                                             "ServerHide",
00559                                             g_variant_new("(s)", priv->type ? priv-> type : ""),
00560                                             NULL); /* error */
00561               }
00562               g_signal_emit(server, signals[SERVER_HIDE], 0, priv->type ? priv->type : "", TRUE);
00563        }
00564 
00565        if (priv->registered != 0) {
00566               g_dbus_connection_unregister_object(priv->connection, priv->registered);
00567        }
00568 
00569        if (priv->connection != NULL) {
00570               g_object_unref(priv->connection);
00571               priv->connection = NULL;
00572        }
00573 
00574        if (priv->interest_timer != 0) {
00575               g_source_remove(priv->interest_timer);
00576               priv->interest_timer = 0;
00577        }
00578 
00579        G_OBJECT_CLASS (indicate_server_parent_class)->dispose (obj);
00580        return;
00581 }
00582 
00583 static void
00584 indicate_server_finalize (GObject * obj)
00585 {
00586        IndicateServer * server = INDICATE_SERVER(obj);
00587        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
00588 
00589        if (priv->path) {
00590               g_free(priv->path);
00591        }
00592        if (priv->desktop) {
00593               g_free(priv->desktop);
00594        }
00595        if (priv->type) {
00596               g_free(priv->type);
00597        }
00598 
00599        G_OBJECT_CLASS (indicate_server_parent_class)->finalize (obj);
00600 
00601        return;
00602 }
00603 
00604 static void
00605 set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec)
00606 {
00607        g_return_if_fail(G_VALUE_HOLDS_STRING(value) || G_VALUE_HOLDS_UINT(value));
00608 
00609        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(obj);
00610        switch (id) {
00611        case PROP_DESKTOP:
00612               if (priv->desktop != NULL) {
00613                      g_free(priv->desktop);
00614               }
00615               priv->desktop = g_value_dup_string(value);
00616               break;
00617        case PROP_TYPE:
00618               if (priv->type != NULL) {
00619                      g_free(priv->type);
00620               }
00621               priv->type = g_value_dup_string(value);
00622               break;
00623        case PROP_COUNT: {
00624               guint newval = g_value_get_uint(value);
00625               if (newval != priv->count) {
00626                      priv->count = newval;
00627                      if (priv->registered != 0) {
00628                             g_dbus_connection_emit_signal(priv->connection,
00629                                                           NULL, /* dest */
00630                                                           priv->path,
00631                                                           INDICATE_DBUS_IFACE,
00632                                                           "ServerCountChanged",
00633                                                           g_variant_new("(u)", newval),
00634                                                           NULL); /* error */
00635                      }
00636                      g_signal_emit(obj, signals[SERVER_COUNT_CHANGED], 0, newval, TRUE);
00637               }
00638               break;
00639        }
00640        case PROP_PATH:
00641                if (priv->path != NULL) {
00642                        g_free(priv->path);
00643                }
00644                priv->path = g_value_dup_string(value);
00645                break;
00646        case PROP_ICON_THEME:
00647               if (priv->icon_theme != NULL) {
00648                      g_free (priv->icon_theme);
00649               }
00650               priv->icon_theme = g_value_dup_string(value);
00651               break;
00652        default:
00653               G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, id, pspec);
00654               break;
00655        }
00656 
00657        return;
00658 }
00659 
00660 /* Gets the Gobject properties for the IndicateServer.  Mostly
00661    just copies strings and a whole uint! */
00662 static void
00663 get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec)
00664 {
00665        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(obj);
00666        switch (id) {
00667        case PROP_DESKTOP:
00668               if (priv->desktop == NULL) {
00669                      g_value_set_string(value, "");
00670               } else {
00671                      g_value_set_string(value, priv->desktop);
00672               }
00673               break;
00674        case PROP_TYPE:
00675               if (priv->type == NULL) {
00676                      g_value_set_string(value, "");
00677               } else {
00678                      g_value_set_string(value, priv->type);
00679               }
00680               break;
00681        case PROP_COUNT:
00682               g_value_set_uint(value, priv->count);
00683               break;
00684        case PROP_MENU:
00685               if (priv->dbusmenu != NULL) {
00686                      GValue strvalue = {0};
00687                      g_value_init(&strvalue, G_TYPE_STRING);
00688                      g_object_get_property(G_OBJECT(priv->dbusmenu), DBUSMENU_SERVER_PROP_DBUS_OBJECT, &strvalue);
00689                      if (g_value_get_string(&strvalue) != NULL) {
00690                             g_value_set_boxed(value, g_value_dup_string(&strvalue));
00691                      } else {
00692                             g_value_set_boxed(value, g_strdup("/"));
00693                      }
00694                      g_value_unset(&strvalue);
00695               } else {
00696                      g_value_set_boxed(value, g_strdup("/"));
00697               }
00698               break;
00699        case PROP_PATH:
00700               g_value_set_string(value, priv->path);
00701               break;
00702        case PROP_ICON_THEME:
00703               if (priv->icon_theme == NULL) {
00704                      g_value_set_string(value, "");
00705               } else {
00706                      g_value_set_string(value, priv->icon_theme);
00707               }
00708               break;
00709        default:
00710               G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, id, pspec);
00711               break;
00712        }
00713 
00714        return;
00715 }
00716 
00717 /************************
00718   DBUS STUFF
00719  ************************/
00720 
00721 /* Response to trying to get on the session bus */
00722 static void
00723 bus_connection_cb (GObject * obj, GAsyncResult * res, gpointer user_data)
00724 {
00725        GError * error = NULL;
00726 
00727        GDBusConnection * connection = g_bus_get_finish(res, &error);
00728        if (error != NULL) {
00729               g_error("Unable to get session bus: %s", error->message);
00730               g_error_free(error);
00731               return;
00732        }
00733 
00734        IndicateServer * server = INDICATE_SERVER(user_data);
00735        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
00736 
00737        if (priv->connection_cancel != NULL) {
00738               g_object_unref(priv->connection_cancel);
00739               priv->connection_cancel = NULL;
00740        }
00741 
00742        if (priv->connection != NULL) {
00743               g_warning("Getting a second connection?");
00744               g_object_unref(priv->connection);
00745               priv->connection = NULL;
00746        }
00747        priv->connection = connection;
00748 
00749        priv->broadcast_signal = g_dbus_connection_signal_subscribe(priv->connection,
00750                                                                    NULL, /* sender */
00751                                                                    INDICATE_LISTENER_DBUS_IFACE,
00752                                                                    "IndicatorServersReport",
00753                                                                    NULL, /* object */
00754                                                                    NULL, /* arg0 */
00755                                                                    G_DBUS_SIGNAL_FLAGS_NONE,
00756                                                                    bus_broadcast_cb,
00757                                                                    server,
00758                                                                    NULL); /* destroy notify */
00759 
00760        if (priv->visible) {
00761               priv->visible = FALSE;
00762               indicate_server_show(server);
00763        }
00764 
00765        return;
00766 }
00767 
00768 /* A small dbus filter that waits on the IndicatorServersReport
00769    signal and sends the Show signal if this server is not hidden. */
00770 static void
00771 bus_broadcast_cb (GDBusConnection * connection, const gchar * sender, const gchar * object_path, const gchar * interface_name, const gchar * signal_name, GVariant * parameters, gpointer user_data)
00772 {
00773        g_return_if_fail(g_strcmp0(signal_name, "IndicatorServersReport") == 0);
00774 
00775        IndicateServer * server = INDICATE_SERVER(user_data);
00776 
00777        if (server != NULL) {
00778               IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
00779               if (priv->visible) {
00780                      if (priv->registered != 0) {
00781                             g_dbus_connection_emit_signal(priv->connection,
00782                                                           NULL, /* dest */
00783                                                           priv->path,
00784                                                           INDICATE_DBUS_IFACE,
00785                                                           "ServerShow",
00786                                                           g_variant_new("(s)", priv->type ? priv-> type : ""),
00787                                                           NULL); /* error */
00788                      }
00789                      g_signal_emit(server, signals[SERVER_SHOW], 0, priv->type ? priv->type : "", TRUE);
00790               }
00791        }
00792 
00793        return;
00794 }
00795 
00796 /* A method call has come from DBus */
00797 static void
00798 bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * method, GVariant * params, GDBusMethodInvocation * invocation, gpointer user_data)
00799 {
00800        int i;
00801        const gchar * interned_method = g_intern_string(method);
00802 
00803        for (i = 0; i < METHOD_COUNT; i++) {
00804               if (bus_method_table[i].interned_name == interned_method) {
00805                      if (bus_method_table[i].func != NULL) {
00806                             return bus_method_table[i].func(INDICATE_SERVER(user_data), params, invocation);
00807                      } else {
00808                             /* If we have a null function we're responding but nothing else. */
00809                             g_warning("Invalid function call for '%s' with parameters: %s", method, g_variant_print(params, TRUE));
00810                             g_dbus_method_invocation_return_value(invocation, NULL);
00811                             return;
00812                      }
00813               }
00814        }
00815 
00816        /* We're here because there's an error */
00817        g_dbus_method_invocation_return_error(invocation,
00818                                              indicate_server_error_quark(),
00819                                              NOT_IMPLEMENTED,
00820                                              "Unable to find method '%s'",
00821                                              method);
00822        return;
00823 }
00824 
00825 /* Dbus have asked for properties, let's talk to it. */
00826 static GVariant *
00827 bus_get_prop (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * property, GError ** error, gpointer user_data)
00828 {
00829        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(user_data);
00830        GVariant * retvariant = NULL;
00831        
00832        if (g_strcmp0(property, "desktop") == 0) {
00833               if (priv->desktop != NULL) {
00834                      retvariant = g_variant_new_string(priv->desktop);
00835               } else {
00836                      retvariant = g_variant_new_string("");
00837               }
00838        } else if (g_strcmp0(property, "type") == 0) {
00839               if (priv->type != NULL) {
00840                      retvariant = g_variant_new_string(priv->type);
00841               } else {
00842                      retvariant = g_variant_new_string("");
00843               }
00844        } else if (g_strcmp0(property, "count") == 0) {
00845               retvariant = g_variant_new_uint32(priv->count);
00846        } else if (g_strcmp0(property, "menu") == 0) {
00847               if (priv->dbusmenu != NULL) {
00848                      GValue strvalue = {0};
00849                      g_value_init(&strvalue, G_TYPE_STRING);
00850                      g_object_get_property(G_OBJECT(priv->dbusmenu), DBUSMENU_SERVER_PROP_DBUS_OBJECT, &strvalue);
00851                      if (g_value_get_string(&strvalue) != NULL) {
00852                             retvariant = g_variant_new_string(g_value_get_string(&strvalue));
00853                      } else {
00854                             retvariant = g_variant_new_string("/");
00855                      }
00856                      g_value_unset(&strvalue);
00857               } else {
00858                      retvariant = g_variant_new_string("/");
00859               }
00860 
00861        } else if (g_strcmp0(property, "icontheme") == 0) {
00862               if (priv->icon_theme != NULL) {
00863                      retvariant = g_variant_new_string (priv->icon_theme);
00864               } else {
00865                      retvariant = g_variant_new_string ("");
00866               }
00867        } else {
00868               g_warning("Unknown property");
00869        }
00870 
00871        return retvariant;
00872 }
00873 
00874 /* Small little function to get an error quark for usage
00875    with the GError errors back across DBus */
00876 static GQuark
00877 indicate_server_error_quark (void)
00878 {
00879        static GQuark quark = 0;
00880        if (quark == 0) {
00881               quark = g_quark_from_static_string (G_LOG_DOMAIN);
00882 
00883               /* Register our dbus error codes as well */
00884               g_dbus_error_register_error(quark, NO_GET_DESKTOP, "com.canonical.indicate.NO_GET_DESKTOP");
00885               g_dbus_error_register_error(quark, NO_GET_INDICATOR_COUNT, "com.canonical.indicate.NO_GET_INDICATOR_COUNT");
00886               g_dbus_error_register_error(quark, NO_GET_INDICATOR_LIST, "com.canonical.indicate.NO_GET_INDICATOR_LIST");
00887               g_dbus_error_register_error(quark, NO_GET_INDICATOR_PROPERTY, "com.canonical.indicate.NO_GET_INDICATOR_PROPERTY");
00888               g_dbus_error_register_error(quark, NO_GET_INDICATOR_PROPERTY_GROUP, "com.canonical.indicate.NO_GET_INDICATOR_PROPERTY_GROUP");
00889               g_dbus_error_register_error(quark, NO_GET_INDICATOR_PROPERTIES, "com.canonical.indicate.NO_GET_INDICATOR_PROPERTIES");
00890               g_dbus_error_register_error(quark, NO_SHOW_INDICATOR_TO_USER, "com.canonical.indicate.NO_SHOW_INDICATOR_TO_USER");
00891               g_dbus_error_register_error(quark, NO_INDICATOR_DISPLAYED, "com.canonical.indicate.NO_INDICATOR_DISPLAYED");
00892               g_dbus_error_register_error(quark, INVALID_INDICATOR_ID, "com.canonical.indicate.INVALID_INDICATOR_ID");
00893               g_dbus_error_register_error(quark, NO_SHOW_INTEREST, "com.canonical.indicate.NO_SHOW_INTEREST");
00894               g_dbus_error_register_error(quark, NO_REMOVE_INTEREST, "com.canonical.indicate.NO_REMOVE_INTEREST");
00895               g_dbus_error_register_error(quark, SHOW_INTEREST_FAILED, "com.canonical.indicate.SHOW_INTEREST_FAILED");
00896               g_dbus_error_register_error(quark, REMOVE_INTEREST_FAILED, "com.canonical.indicate.REMOVE_INTEREST_FAILED");
00897               g_dbus_error_register_error(quark, NO_MAX_INDICATORS_SET, "com.canonical.indicate.NO_MAX_INDICATORS_SET");
00898               g_dbus_error_register_error(quark, MAX_INDICATORS_SET_FAILED, "com.canonical.indicate.MAX_INDICATORS_SET_FAILED");
00899               g_dbus_error_register_error(quark, NO_SUCH_PROPERTY, "com.canonical.indicate.NO_SUCH_PROPERTY");
00900               g_dbus_error_register_error(quark, NOT_IMPLEMENTED, "com.canonical.indicate.NOT_IMPLEMENTED");
00901        }
00902        return quark;
00903 }
00904 
00916 void
00917 indicate_server_show (IndicateServer * server)
00918 {
00919        g_return_if_fail(INDICATE_IS_SERVER(server));
00920        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
00921 
00922        if (priv->visible) {
00923               return;
00924        }
00925 
00926        priv->visible = TRUE;
00927 
00928        if (priv->connection == NULL) {
00929               return;
00930        }
00931 
00932        if (priv->registered == 0) {
00933               GError * error = NULL;
00934               priv->registered = g_dbus_connection_register_object(priv->connection,
00935                                                                    priv->path,
00936                                                                    bus_interface_info,
00937                                                                    &bus_interface_table,
00938                                                                    server,
00939                                                                    NULL,
00940                                                                    &error);
00941 
00942               if (error != NULL) {
00943                      g_warning("Unable to export object '%s' with interface '" INDICATE_DBUS_IFACE "' on dbus: %s", priv->path, error->message);
00944                      g_error_free(error);
00945                      priv->registered = 0; /* Just to be sure */
00946                      return;
00947               }
00948        }
00949 
00950        if (priv->registered != 0) {
00951               g_dbus_connection_emit_signal(priv->connection,
00952                                             NULL, /* dest */
00953                                             priv->path,
00954                                             INDICATE_DBUS_IFACE,
00955                                             "ServerShow",
00956                                             g_variant_new("(s)", priv->type ? priv-> type : ""),
00957                                             NULL); /* error */
00958        }
00959        g_signal_emit(server, signals[SERVER_SHOW], 0, priv->type ? priv->type : "", TRUE);
00960 
00961        return;
00962 }
00963 
00974 void
00975 indicate_server_hide (IndicateServer * server)
00976 {
00977        g_return_if_fail(INDICATE_IS_SERVER(server));
00978        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
00979 
00980        if (!priv->visible)
00981               return;
00982 
00983        priv->visible = FALSE;
00984 
00985        /* Delete interested parties */
00986        g_list_foreach(priv->interestedfolks, (GFunc)indicate_server_interested_folks_destroy, NULL);
00987        g_list_free(priv->interestedfolks);
00988        priv->interestedfolks = NULL;
00989 
00990        /* Signal the lack of interest */
00991        guint i;
00992        for (i = INDICATE_INTEREST_NONE; i < INDICATE_INTEREST_LAST; i++) {
00993               if (priv->interests[i]) {
00994                      g_signal_emit(G_OBJECT(server), signals[INTEREST_REMOVED], 0, i, TRUE);
00995               }
00996               priv->interests[i] = FALSE;
00997        }
00998 
00999        /* Signal that we don't have a max */
01000        priv->max_indicators = MAX_INDICATORS_UNSET;
01001        g_signal_emit(G_OBJECT(server), signals[MAX_INDICATORS_CHANGED], 0, MAX_INDICATORS_INFINITE, TRUE);
01002 
01003        if (priv->registered != 0) {
01004               g_dbus_connection_emit_signal(priv->connection,
01005                                             NULL, /* dest */
01006                                             priv->path,
01007                                             INDICATE_DBUS_IFACE,
01008                                             "ServerHide",
01009                                             g_variant_new("(s)", priv->type ? priv-> type : ""),
01010                                             NULL); /* error */
01011        }
01012        g_signal_emit(server, signals[SERVER_HIDE], 0, priv->type ? priv->type : "", TRUE);
01013 
01014        return;
01015 }
01016 
01017 /* Checks each value in the hash table to see if it's
01018    been set.  If it is, then we need to recalculate
01019    the value of displayed. */
01020 static void
01021 indicator_display_check_recalc (gpointer key, gpointer value, gpointer userdata)
01022 {
01023        if (!GPOINTER_TO_UINT(value)) {
01024               return;
01025        }
01026 
01027        recalculate_indicator_displayed(INDICATE_SERVER(userdata), GPOINTER_TO_UINT(key));
01028        return;
01029 }
01030 
01031 /* Look to see if a specific indicator ID has anyone watching
01032    for it, and if not we need to set it to undisplayed. */
01033 static void
01034 recalculate_indicator_displayed (IndicateServer * server, guint id)
01035 {
01036        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01037        GList * folkpointer;
01038 
01039        for (folkpointer = priv->interestedfolks; folkpointer != NULL; folkpointer = g_list_next(folkpointer)) {
01040               IndicateServerInterestedFolk * folk = (IndicateServerInterestedFolk *)folkpointer->data;
01041               if (g_hash_table_lookup(folk->indicators_displayed, GUINT_TO_POINTER(id))) {
01042                      break;
01043               }
01044        }
01045 
01046        if (folkpointer == NULL) {
01047               /* We went through the list and no one cares about
01048                  this indicator.  It's not displayed anymore. */
01049               IndicateIndicator * indicator = get_indicator(server, id, NULL);
01050               if (indicator != NULL) {
01051                      indicate_indicator_set_displayed(indicator, FALSE);
01052               } else {
01053                      g_warning("I'm removing a displayed set from an indicator that doesn't seem to exist.");
01054               }
01055        }
01056 
01057        return;
01058 }
01059 
01060 /* Get the next ID from the server */
01061 static guint
01062 get_next_id (IndicateServer * server)
01063 {
01064        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01065        priv->current_id++;
01066        return priv->current_id;
01067 }
01068 
01069 /* Allows a listener to show interest.  First we look to see
01070    if we've talked to this listener before and if so we just
01071    mark their folk listing.  If it changes the overall setting
01072    then we need to signal. */
01073 static gboolean
01074 show_interest (IndicateServer * server, const gchar * sender, IndicateInterests interest)
01075 {
01076        if (!(interest > INDICATE_INTEREST_NONE && interest < INDICATE_INTEREST_LAST)) {
01077               return FALSE;
01078        }
01079 
01080        /* g_debug("Someone is showing interest.  %s in %d", sender, interest); */
01081        IndicateServerInterestedFolk localfolk;
01082        localfolk.sender = (gchar *)sender; /* Okay to drop the const as we're only using this for searching */
01083 
01084        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01085 
01086        if (priv->interest_timer != 0) {
01087               g_source_remove(priv->interest_timer);
01088               priv->interest_timer = 0;
01089        }
01090 
01091        GList * entry = g_list_find_custom(priv->interestedfolks, &localfolk, indicate_server_interested_folks_equal);
01092        IndicateServerInterestedFolk * folkpointer = NULL;
01093        if (entry == NULL) {
01094               folkpointer = g_new0(IndicateServerInterestedFolk, 1);
01095               indicate_server_interested_folks_init(folkpointer, sender, INDICATE_LISTENER_OBJ_PATH, priv->connection);
01096               priv->interestedfolks = g_list_append(priv->interestedfolks, folkpointer);
01097        } else {
01098               folkpointer = (IndicateServerInterestedFolk *)entry->data;
01099        }
01100 
01101        indicate_server_interested_folks_set(folkpointer, interest, TRUE);
01102        if (!priv->interests[interest]) {
01103               g_signal_emit(G_OBJECT(server), signals[INTEREST_ADDED], 0, interest, TRUE);
01104               priv->interests[interest] = TRUE;
01105        }
01106 
01107        return TRUE;
01108 }
01109 
01110 /* Removes an interest from a folk.  It removes it from the
01111    folk structure and then checks to see if that has global
01112    effect, and handles it.  */
01113 static gboolean
01114 remove_interest (IndicateServer * server, const gchar * sender, IndicateInterests interest)
01115 {
01116        if (!(interest > INDICATE_INTEREST_NONE && interest < INDICATE_INTEREST_LAST)) {
01117               return FALSE;
01118        }
01119 
01120        IndicateServerInterestedFolk localfolk;
01121        localfolk.sender = (gchar *)sender; /* Okay to drop the const as we're only using this for searching */
01122 
01123        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01124 
01125        /* NOTE: We're not removing the timer here, because we know the timer
01126           started in a state where there was no interest.  So if someone has
01127           since shown interest, there'll be no timer, and if they haven't then
01128           this function won't send a signal anyway. */
01129 
01130        /* Figure out the folk that we're talking to.  If we
01131           have an entry for them, use it, otherwise we need
01132           to create one. */
01133        GList * entry = g_list_find_custom(priv->interestedfolks, &localfolk, indicate_server_interested_folks_equal);
01134        IndicateServerInterestedFolk * folkpointer = NULL;
01135        if (entry == NULL) {
01136               folkpointer = g_new0(IndicateServerInterestedFolk, 1);
01137               indicate_server_interested_folks_init(folkpointer, sender, INDICATE_LISTENER_OBJ_PATH, priv->connection);
01138               priv->interestedfolks = g_list_append(priv->interestedfolks, folkpointer);
01139        } else {
01140               folkpointer = (IndicateServerInterestedFolk *)entry->data;
01141        }
01142 
01143        /* Set the interest for this guy */
01144        indicate_server_interested_folks_set(folkpointer, interest, FALSE);
01145 
01146        /* Check to see if the interest has changed as a result of
01147           this an announce it to the world */
01148        if (priv->interests[interest]) {
01149               guint i;
01150               for (i = INDICATE_INTEREST_NONE; i < INDICATE_INTEREST_LAST; i++) {
01151                      priv->interests[i] = FALSE;
01152               }
01153 
01154               GList * listi = NULL;
01155               for (listi = priv->interestedfolks ; listi != NULL ; listi = listi->next) {
01156                      folkpointer = (IndicateServerInterestedFolk *)listi->data;
01157                      indicate_server_interested_folks_copy(folkpointer, priv->interests);
01158               }
01159 
01160               if (!priv->interests[interest]) {
01161                      g_signal_emit(G_OBJECT(server), signals[INTEREST_REMOVED], 0, interest, TRUE);
01162               }
01163        }
01164 
01165        return TRUE;
01166 }
01167 
01168 /* This little timer fires if no one shows any interest at startup
01169    and signals a removed of NONE saying that there is no interest. */
01170 static gboolean
01171 interest_timer (gpointer user_data)
01172 {
01173        g_return_val_if_fail(INDICATE_IS_SERVER(user_data), FALSE);
01174        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(user_data);
01175 
01176        g_signal_emit(G_OBJECT(user_data), signals[INTEREST_REMOVED], 0, INDICATE_INTEREST_NONE, TRUE);
01177        priv->interest_timer = 0;
01178 
01179        return FALSE;
01180 }
01181 
01182 /* Checks to see if a particular interest value is
01183    set.  Uses the interest cache. */
01184 static gboolean
01185 check_interest (IndicateServer * server, IndicateInterests interest)
01186 {
01187        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01188        return priv->interests[interest];
01189 }
01190 
01191 /* Internal function that can be subclassed to get
01192    the value of the max number of indicators. */
01193 static gint
01194 max_indicators_get (IndicateServer * server)
01195 {
01196        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01197        if (priv->max_indicators == MAX_INDICATORS_UNSET) {
01198               return MAX_INDICATORS_INFINITE;
01199        } else {
01200               return priv->max_indicators;
01201        }
01202 }
01203 
01204 /* Internal function to set the number of max indicators
01205    from a particular listener. */
01206 static gboolean
01207 max_indicators_set (IndicateServer * server, const gchar * sender, gint max)
01208 {
01209        g_return_val_if_fail(max >= MAX_INDICATORS_INFINITE, FALSE);
01210 
01211        IndicateServerInterestedFolk localfolk;
01212        localfolk.sender = (gchar *)sender; /* Okay to drop the const as we're only using this for searching */
01213 
01214        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01215 
01216        /* Figure out the folk that we're talking to.  If we
01217           have an entry for them, use it, otherwise we need
01218           to create one. */
01219        GList * entry = g_list_find_custom(priv->interestedfolks, &localfolk, indicate_server_interested_folks_equal);
01220        IndicateServerInterestedFolk * folkpointer = NULL;
01221        if (entry == NULL) {
01222               folkpointer = g_new0(IndicateServerInterestedFolk, 1);
01223               indicate_server_interested_folks_init(folkpointer, sender, INDICATE_LISTENER_OBJ_PATH, priv->connection);
01224               priv->interestedfolks = g_list_append(priv->interestedfolks, folkpointer);
01225        } else {
01226               folkpointer = (IndicateServerInterestedFolk *)entry->data;
01227        }
01228 
01229        /* If there's a change going on... */
01230        if (max != folkpointer->max_indicators) {
01231               gboolean recalculate = FALSE;
01232               /* If this guy is setting it to infinite or is
01233                    increasing the number */
01234               if ((max == -1 && priv->max_indicators != -1) || max > priv->max_indicators) {
01235                      recalculate = TRUE;
01236               }
01237 
01238               /* Or if potentially we were the ones setting the
01239                  value for everyone */
01240               if (priv->max_indicators == folkpointer->max_indicators) {
01241                      recalculate = TRUE;
01242               }
01243 
01244               folkpointer->max_indicators = max;
01245               if (recalculate) {
01246                      recalculate_max_indicators(server);
01247               }
01248        }
01249 
01250        return TRUE;
01251 }
01252 
01253 /* Look through all the folks and trying to figure out
01254    what the max should be.  Signal if it changes. */
01255 static void
01256 recalculate_max_indicators (IndicateServer * server)
01257 {
01258        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01259 
01260        /* Let's talk to all the folks and see what they
01261           think the max should be. */
01262        GList * folkitem;
01263        gint newmax = MAX_INDICATORS_UNSET;
01264        for (folkitem = priv->interestedfolks; folkitem != NULL; folkitem = g_list_next(folkitem)) {
01265               IndicateServerInterestedFolk * thisfolk = (IndicateServerInterestedFolk *)folkitem->data;
01266               if (thisfolk->max_indicators == MAX_INDICATORS_UNSET) {
01267                      continue;
01268               }
01269               if (thisfolk->max_indicators == MAX_INDICATORS_INFINITE) {
01270                      newmax = MAX_INDICATORS_INFINITE;
01271                      break;
01272               }
01273               if (thisfolk->max_indicators > newmax) {
01274                      newmax = thisfolk->max_indicators;
01275               }
01276        }
01277 
01278        /* Okay, what ever happened, now it's changing
01279           things and we need to tell everyone. */
01280        if (priv->max_indicators != newmax) {
01281               priv->max_indicators = newmax;
01282               g_signal_emit(G_OBJECT(server), signals[MAX_INDICATORS_CHANGED], 0, newmax, TRUE);
01283        }
01284 
01285        return;
01286 }
01287 
01288 static void
01289 indicator_show_cb (IndicateIndicator * indicator, IndicateServer * server)
01290 {
01291        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01292        priv->num_hidden--;
01293        if (priv->registered != 0) {
01294               g_dbus_connection_emit_signal(priv->connection,
01295                                             NULL, /* dest */
01296                                             priv->path,
01297                                             INDICATE_DBUS_IFACE,
01298                                             "IndicatorNew",
01299                                             g_variant_new("(u)", indicate_indicator_get_id(indicator)),
01300                                             NULL); /* error */
01301        }
01302        g_signal_emit(server, signals[INDICATOR_ADDED], 0, indicate_indicator_get_id(indicator), TRUE);
01303        return;
01304 }
01305 
01306 static void
01307 indicator_hide_cb (IndicateIndicator * indicator, IndicateServer * server)
01308 {
01309        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01310        priv->num_hidden++;
01311        if (priv->registered != 0) {
01312               g_dbus_connection_emit_signal(priv->connection,
01313                                             NULL, /* dest */
01314                                             priv->path,
01315                                             INDICATE_DBUS_IFACE,
01316                                             "IndicatorDelete",
01317                                             g_variant_new("(u)", indicate_indicator_get_id(indicator)),
01318                                             NULL); /* error */
01319        }
01320        g_signal_emit(server, signals[INDICATOR_REMOVED], 0, indicate_indicator_get_id(indicator), TRUE);
01321        return;
01322 }
01323 
01324 static void
01325 indicator_modified_cb (IndicateIndicator * indicator, gchar * property, IndicateServer * server)
01326 {
01327        /* g_debug("Indicator Modified: %d %s", indicate_indicator_get_id(indicator), property); */
01328        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01329        if (priv->registered != 0) {
01330               g_dbus_connection_emit_signal(priv->connection,
01331                                             NULL, /* dest */
01332                                             priv->path,
01333                                             INDICATE_DBUS_IFACE,
01334                                             "IndicatorModified",
01335                                             g_variant_new("(us)", indicate_indicator_get_id(indicator), property),
01336                                             NULL); /* error */
01337        }
01338        g_signal_emit(server, signals[INDICATOR_MODIFIED], 0, indicate_indicator_get_id(indicator), property, TRUE);
01339 }
01340 
01351 void
01352 indicate_server_add_indicator (IndicateServer * server, IndicateIndicator * indicator)
01353 {
01354        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01355 
01356     if (g_slist_find (priv->indicators, indicator) != NULL)
01357             return;
01358 
01359     priv->indicators = g_slist_prepend(priv->indicators, indicator);
01360 
01361        if (!indicate_indicator_is_visible(indicator)) {
01362               priv->num_hidden++;
01363        } else {
01364               if (priv->registered != 0) {
01365                      g_dbus_connection_emit_signal(priv->connection,
01366                                                    NULL, /* dest */
01367                                                    priv->path,
01368                                                    INDICATE_DBUS_IFACE,
01369                                                    "IndicatorNew",
01370                                                    g_variant_new("(u)", indicate_indicator_get_id(indicator)),
01371                                                    NULL); /* error */
01372               }
01373               g_signal_emit(server, signals[INDICATOR_ADDED], 0, indicate_indicator_get_id(indicator), TRUE);
01374        }
01375 
01376        g_signal_connect(indicator, INDICATE_INDICATOR_SIGNAL_SHOW, G_CALLBACK(indicator_show_cb), server);
01377        g_signal_connect(indicator, INDICATE_INDICATOR_SIGNAL_HIDE, G_CALLBACK(indicator_hide_cb), server);
01378        g_signal_connect(indicator, INDICATE_INDICATOR_SIGNAL_MODIFIED, G_CALLBACK(indicator_modified_cb), server);
01379 
01380        return;
01381 }
01382 
01391 void
01392 indicate_server_remove_indicator (IndicateServer * server, IndicateIndicator * indicator)
01393 {
01394        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01395 
01396     if (g_slist_find (priv->indicators, indicator) == NULL)
01397             return;
01398 
01399        priv->indicators = g_slist_remove(priv->indicators, indicator);
01400        if (indicate_indicator_is_visible(indicator)) {
01401               if (priv->registered != 0) {
01402                      g_dbus_connection_emit_signal(priv->connection,
01403                                                    NULL, /* dest */
01404                                                    priv->path,
01405                                                    INDICATE_DBUS_IFACE,
01406                                                    "IndicatorDelete",
01407                                                    g_variant_new("(u)", indicate_indicator_get_id(indicator)),
01408                                                    NULL); /* error */
01409               }
01410               g_signal_emit(server, signals[INDICATOR_REMOVED], 0, indicate_indicator_get_id(indicator), TRUE);
01411        } else {
01412               priv->num_hidden--;
01413        }
01414 
01415        g_signal_handlers_disconnect_by_func(indicator, indicator_show_cb, server);
01416        g_signal_handlers_disconnect_by_func(indicator, indicator_hide_cb, server);
01417        g_signal_handlers_disconnect_by_func(indicator, indicator_modified_cb, server);
01418 
01419        return;
01420 }
01421 
01422 void
01423 indicate_server_set_dbus_object (const gchar * obj)
01424 {
01425        /* TODO */
01426 
01427        return;
01428 }
01429 
01439 void
01440 indicate_server_set_desktop_file (IndicateServer * server, const gchar * path)
01441 {
01442        GValue value = {0};
01443        g_value_init(&value, G_TYPE_STRING);
01444        g_value_set_string(&value, path);
01445        g_object_set_property(G_OBJECT(server), "desktop", &value);
01446        return;
01447 }
01448 
01458 void
01459 indicate_server_set_type (IndicateServer * server, const gchar * type)
01460 {
01461        GValue value = {0};
01462        g_value_init(&value, G_TYPE_STRING);
01463        g_value_set_string(&value, type);
01464        g_object_set_property(G_OBJECT(server), "type", &value);
01465        g_value_unset(&value);
01466        return;
01467 }
01468 
01481 void
01482 indicate_server_set_count (IndicateServer * server, guint count)
01483 {
01484        GValue value = {0};
01485        g_value_init(&value, G_TYPE_UINT);
01486        g_value_set_uint(&value, count);
01487        g_object_set_property(G_OBJECT(server), "count", &value);
01488        return;
01489 }
01490 
01501 void
01502 indicate_server_set_icon_theme (IndicateServer * server, const gchar * name)
01503 {
01504        GValue value = {0};
01505        g_value_init(&value, G_TYPE_STRING);
01506        g_value_set_string(&value, name);
01507        g_object_set_property(G_OBJECT(server), "icon-theme", &value);
01508        return;
01509 }
01510 
01511 static IndicateServer * default_indicate_interface_server = NULL;
01512 
01524 IndicateServer *
01525 indicate_server_ref_default (void)
01526 {
01527        if (default_indicate_interface_server != NULL) {
01528               g_object_ref(default_indicate_interface_server);
01529        } else {
01530               default_indicate_interface_server = g_object_new(INDICATE_TYPE_SERVER, NULL);
01531               g_object_add_weak_pointer(G_OBJECT(default_indicate_interface_server),
01532                                         (gpointer *)&default_indicate_interface_server);
01533        }
01534 
01535        return default_indicate_interface_server;
01536 }
01537 
01548 void
01549 indicate_server_set_default (IndicateServer * server)
01550 {
01551        if (default_indicate_interface_server != NULL) {
01552               g_warning("Setting a default Indicator Server when one has already been created.  I'm not going to destroy that one, but let it live.  This may create some odd results if you don't know what you're doing.");
01553        }
01554 
01555        if (server != NULL) {
01556               default_indicate_interface_server = server;
01557               g_object_add_weak_pointer(G_OBJECT(default_indicate_interface_server),
01558                                         (gpointer *)&default_indicate_interface_server);
01559        }
01560 
01561        return;
01562 }
01563 
01564 static gboolean
01565 get_indicator_count (IndicateServer * server, guint * count, GError **error)
01566 {
01567        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01568 
01569        guint lstcnt = g_slist_length(priv->indicators);
01570 
01571        g_return_val_if_fail(priv->num_hidden < lstcnt, TRUE);
01572        
01573        *count = lstcnt - priv->num_hidden;
01574 
01575        return TRUE;
01576 }
01577 
01578 static gboolean
01579 get_indicator_list (IndicateServer * server, GArray ** indicators, GError ** error)
01580 {
01581        g_return_val_if_fail(INDICATE_IS_SERVER(server), TRUE);
01582 
01583        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
01584        g_return_val_if_fail(class->get_indicator_count != NULL, TRUE);
01585 
01586        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01587 
01588        *indicators = g_array_sized_new(FALSE, FALSE, sizeof(guint), g_slist_length(priv->indicators) - priv->num_hidden);
01589 
01590        GSList * iter;
01591        int i;
01592        for (iter = priv->indicators, i = 0; iter != NULL; iter = iter->next) {
01593               IndicateIndicator * indicator = INDICATE_INDICATOR(iter->data);
01594               if (indicate_indicator_is_visible(indicator)) {
01595                      guint id = indicate_indicator_get_id(indicator);
01596                      g_array_insert_val(*indicators, i++, id);
01597               }
01598        }
01599 
01600        return TRUE;
01601 }
01602 
01603 static IndicateIndicator *
01604 get_indicator (IndicateServer * server, guint id, GError **error)
01605 {
01606        g_return_val_if_fail(INDICATE_IS_SERVER(server), NULL);
01607        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01608 
01609        GSList * iter;
01610        for (iter = priv->indicators; iter != NULL; iter = iter->next) {
01611               IndicateIndicator * indicator = INDICATE_INDICATOR(iter->data);
01612               if (indicate_indicator_get_id(indicator) == id) {
01613                      return indicator;
01614               }
01615        }
01616 
01617        if (error) {
01618               g_set_error(error,
01619                           indicate_server_error_quark(),
01620                           INVALID_INDICATOR_ID,
01621                           "Invalid Indicator ID: %d",
01622                           id);
01623        }
01624        return NULL;
01625 }
01626 
01627 static gboolean
01628 get_indicator_property (IndicateServer * server, guint id, gchar * property, GVariant ** variant, GError **error)
01629 {
01630        IndicateIndicator * indicator = get_indicator(server, id, error);
01631        if (indicator == NULL) {
01632               return FALSE;
01633        }
01634 
01635        GVariant * ind_property = indicate_indicator_get_property_variant(indicator, property);
01636        if (ind_property == NULL) {
01637               if (error != NULL) {
01638                      g_set_error(error,
01639                                  indicate_server_error_quark(),
01640                                  NO_SUCH_PROPERTY,
01641                                  "Indicator %d has no property named '%s'",
01642                                  id, property);
01643               }
01644               return FALSE;
01645        }
01646 
01647        *variant = ind_property;
01648        return TRUE;
01649 }
01650 
01651 static gboolean
01652 get_indicator_property_group (IndicateServer * server, guint id, const gchar ** properties, GVariant ** output, GError **error)
01653 {
01654        IndicateIndicator * indicator = get_indicator(server, id, error);
01655        if (indicator == NULL) {
01656               return FALSE;
01657        }
01658 
01659        GVariantBuilder builder;
01660        g_variant_builder_init(&builder, G_VARIANT_TYPE_DICTIONARY);
01661        int i;
01662        for (i = 0; properties[i] != NULL; i++) {
01663               GVariant * ind_property = indicate_indicator_get_property_variant(indicator, properties[i]);
01664 
01665               if (ind_property == NULL) {
01666                      continue;
01667               }
01668 
01669               GVariant * dictentry = g_variant_new_dict_entry(g_variant_new_string(properties[i]), ind_property);
01670               g_variant_builder_add_value(&builder, dictentry);
01671        }
01672 
01673        *output = g_variant_builder_end(&builder);
01674 
01675        return TRUE;
01676 }
01677 
01678 static gboolean
01679 get_indicator_properties (IndicateServer * server, guint id, gchar *** properties, GError **error)
01680 {
01681        IndicateIndicator * indicator = get_indicator(server, id, error);
01682        if (indicator == NULL) {
01683               return FALSE;
01684        }
01685 
01686        GPtrArray * array = indicate_indicator_list_properties(indicator);
01687        g_ptr_array_add(array, NULL);
01688 
01689        *properties = (gchar **)g_ptr_array_free(array, FALSE);
01690 
01691        return TRUE;
01692 }
01693 
01694 static gboolean
01695 show_indicator_to_user (IndicateServer * server, guint id, guint timestamp, GError ** error)
01696 {
01697        if (id == INDICATE_SERVER_INDICATOR_NULL) {
01698               g_signal_emit(server, signals[SERVER_DISPLAY], 0, timestamp, TRUE);
01699               return TRUE;
01700        }
01701 
01702        IndicateIndicator * indicator = get_indicator(server, id, error);
01703        if (indicator == NULL) {
01704               return FALSE;
01705        }
01706 
01707        indicate_indicator_user_display(indicator, timestamp);
01708        return TRUE;
01709 }
01710 
01711 /* A function representing when an indicator is shown
01712    to the user in some form.  First it sees if we've talked
01713    to this listener before and uses that entry.  Otherwise, we
01714    build one.  If we're displaying it, things are good, we can
01715    just set that.  If we're not, then we need to check to see
01716    if anyone else is before continuing.  */
01717 static gboolean
01718 indicator_displayed (IndicateServer * server, const gchar * sender, guint id, gboolean displayed, GError ** error)
01719 {
01720        IndicateServerInterestedFolk localfolk;
01721        localfolk.sender = (gchar *)sender; /* Okay to drop the const as we're only using this for searching */
01722 
01723        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
01724 
01725        GList * entry = g_list_find_custom(priv->interestedfolks, &localfolk, indicate_server_interested_folks_equal);
01726        IndicateServerInterestedFolk * folkpointer = NULL;
01727        if (entry == NULL) {
01728               folkpointer = g_new0(IndicateServerInterestedFolk, 1);
01729               indicate_server_interested_folks_init(folkpointer, sender, INDICATE_LISTENER_OBJ_PATH, priv->connection);
01730               priv->interestedfolks = g_list_append(priv->interestedfolks, folkpointer);
01731        } else {
01732               folkpointer = (IndicateServerInterestedFolk *)entry->data;
01733        }
01734 
01735        g_hash_table_insert(folkpointer->indicators_displayed, GUINT_TO_POINTER(id), GUINT_TO_POINTER(displayed));
01736 
01737        if (displayed) {
01738               IndicateIndicator * indicator = get_indicator(server, id, error);
01739               if (indicator == NULL) {
01740                      return FALSE;
01741               }
01742 
01743               indicate_indicator_set_displayed(indicator, displayed);
01744        } else {
01745               recalculate_indicator_displayed(server, id);
01746        }
01747 
01748        return TRUE;
01749 }
01750 
01751 /* Virtual Functions */
01752 static void
01753 bus_get_indicator_count (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation)
01754 {
01755        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
01756 
01757        if (class != NULL && class->get_indicator_count != NULL) {
01758               guint count = 0;
01759               GError * error = NULL;
01760 
01761               class->get_indicator_count (server, &count, &error);
01762 
01763               if (error != NULL) {
01764                      g_dbus_method_invocation_return_gerror(invocation, error);
01765                      g_error_free(error);
01766               } else {
01767                      g_dbus_method_invocation_return_value(invocation,
01768                                                            g_variant_new("(u)", count));
01769               }
01770 
01771               return;
01772        }
01773 
01774        g_dbus_method_invocation_return_error(invocation,
01775                           indicate_server_error_quark(),
01776                           NO_GET_INDICATOR_COUNT,
01777                           "get_indicator_count function doesn't exist for this server class: %s",
01778                           G_OBJECT_TYPE_NAME(server));
01779        return;
01780 }
01781 
01782 static void
01783 bus_get_indicator_list (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation)
01784 {
01785        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
01786 
01787        if (class != NULL && class->get_indicator_list != NULL) {
01788               GArray * array = NULL;
01789               GError * error = NULL;
01790 
01791               class->get_indicator_list (server, &array, &error);
01792 
01793               if (error != NULL) {
01794                      g_dbus_method_invocation_return_gerror(invocation, error);
01795                      g_error_free(error);
01796               } else {
01797                      GVariant * retval = NULL;
01798                      if (array->len != 0) {
01799                             GVariantBuilder builder;
01800                             g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
01801 
01802                             int i;
01803                             for (i = 0; array != NULL && i < array->len; i++) {
01804                                    g_variant_builder_add_value(&builder, g_variant_new_int32(g_array_index(array, gint, i)));
01805                             }
01806 
01807                             retval = g_variant_builder_end(&builder);
01808                      } else {
01809                             retval = g_variant_parse(g_variant_type_new("ai"), "[]", NULL, NULL, NULL);
01810                      }
01811                      g_dbus_method_invocation_return_value(invocation, g_variant_new_tuple(&retval, 1));
01812 
01813                      g_array_free(array, TRUE);
01814               }
01815 
01816               return;
01817        }
01818 
01819        g_dbus_method_invocation_return_error(invocation,
01820                           indicate_server_error_quark(),
01821                           NO_GET_INDICATOR_LIST,
01822                           "get_indicator_list function doesn't exist for this server class: %s",
01823                           G_OBJECT_TYPE_NAME(server));
01824        return;
01825 }
01826 
01827 static void
01828 bus_get_indicator_property (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation)
01829 {
01830        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
01831 
01832        if (class != NULL && class->get_indicator_property != NULL) {
01833               guint id;
01834               gchar * property;
01835               GVariant * variant;
01836               GError * error = NULL;
01837 
01838               g_variant_get(params, "(us)", &id, &property);
01839 
01840               class->get_indicator_property (server, id, property, &variant, &error);
01841 
01842               g_free(property);
01843               if (error != NULL) {
01844                      g_dbus_method_invocation_return_gerror(invocation, error);
01845               } else {
01846                      g_dbus_method_invocation_return_value(invocation, g_variant_new("(v)", variant));
01847               }
01848 
01849               return;
01850        }
01851 
01852        g_dbus_method_invocation_return_error(invocation,
01853                           indicate_server_error_quark(),
01854                           NO_GET_INDICATOR_PROPERTY,
01855                           "get_indicator_property function doesn't exist for this server class: %s",
01856                           G_OBJECT_TYPE_NAME(server));
01857        return;
01858 }
01859 
01860 static void
01861 bus_get_indicator_property_group (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation)
01862 {
01863        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
01864 
01865        if (class != NULL && class->get_indicator_property_group != NULL) {
01866               guint id = g_variant_get_uint32(g_variant_get_child_value(params, 0));;
01867               const gchar ** props = g_variant_get_strv(g_variant_get_child_value(params, 1), NULL);
01868               GVariant * output;
01869               GError * error = NULL;
01870 
01871               class->get_indicator_property_group (server, id, props, &output, &error);
01872 
01873               if (error != NULL) {
01874                      g_dbus_method_invocation_return_gerror(invocation, error);
01875                      g_error_free(error);
01876               } else {
01877                      if (output != NULL) {
01878                             output = g_variant_new_tuple(&output, 1);
01879                      }
01880                      g_dbus_method_invocation_return_value(invocation, output);
01881               }
01882 
01883               return;
01884        }
01885 
01886        g_dbus_method_invocation_return_error(invocation,
01887                           indicate_server_error_quark(),
01888                           NO_GET_INDICATOR_PROPERTY_GROUP,
01889                           "get_indicator_property_group function doesn't exist for this server class: %s",
01890                           G_OBJECT_TYPE_NAME(server));
01891        return;
01892 }
01893 
01894 static void
01895 bus_get_indicator_properties (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation)
01896 {
01897        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
01898 
01899        if (class != NULL && class->get_indicator_properties != NULL) {
01900               guint id = g_variant_get_uint32(g_variant_get_child_value(params, 0));
01901               gchar ** props = NULL;
01902               GError * error = NULL;
01903 
01904               class->get_indicator_properties (server, id, &props, &error);
01905 
01906               if (error != NULL) {
01907                      g_dbus_method_invocation_return_gerror(invocation, error);
01908                      g_error_free(error);
01909               } else {
01910                      GVariant * retvals = g_variant_new_strv((const gchar * const *)props, -1);
01911                      if (retvals != NULL) {
01912                             retvals = g_variant_new_tuple(&retvals, 1);
01913                      }
01914                      g_dbus_method_invocation_return_value(invocation, retvals);
01915                      g_strfreev(props);
01916               }
01917 
01918               return;
01919        }
01920 
01921        g_dbus_method_invocation_return_error(invocation,
01922                           indicate_server_error_quark(),
01923                           NO_GET_INDICATOR_PROPERTIES,
01924                           "get_indicator_properties function doesn't exist for this server class: %s",
01925                           G_OBJECT_TYPE_NAME(server));
01926        return;
01927 }
01928 
01929 static void
01930 bus_show_indicator_to_user (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation)
01931 {
01932        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
01933 
01934        if (class != NULL && class->show_indicator_to_user != NULL) {
01935               GError * error = NULL;
01936               guint id, timestamp;
01937               g_variant_get(params, "(uu)", &id, &timestamp);
01938 
01939               class->show_indicator_to_user (server, id, timestamp, &error);
01940 
01941               if (error != NULL) {
01942                      g_dbus_method_invocation_return_gerror(invocation, error);
01943                      g_error_free(error);
01944               } else {
01945                      g_dbus_method_invocation_return_value(invocation, NULL);
01946               }
01947 
01948               return;
01949        }
01950 
01951        g_dbus_method_invocation_return_error(invocation,
01952                           indicate_server_error_quark(),
01953                           NO_SHOW_INDICATOR_TO_USER,
01954                           "show_indicator_to_user function doesn't exist for this server class: %s",
01955                           G_OBJECT_TYPE_NAME(server));
01956        return;
01957 }
01958 
01959 /* DBus function to wrap a virtual function call so that
01960    it can be subclassed if someone so chooses */
01961 static void
01962 bus_indicator_displayed (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation)
01963 {
01964        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
01965 
01966        if (class != NULL && class->indicator_displayed != NULL) {
01967               GError * error = NULL;
01968               guint id;
01969               gboolean displayed;
01970 
01971               g_variant_get(params, "(ub)", &id, &displayed);
01972 
01973               if (class->indicator_displayed (server, g_dbus_method_invocation_get_sender(invocation), id, displayed, &error)) {
01974                      g_dbus_method_invocation_return_value(invocation, NULL);
01975               } else {
01976                      g_dbus_method_invocation_return_gerror(invocation, error);
01977                      g_error_free(error);
01978               }
01979 
01980               return;
01981        }
01982 
01983        g_dbus_method_invocation_return_error(invocation,
01984                    indicate_server_error_quark(),
01985                    NO_INDICATOR_DISPLAYED,
01986                    "indicator_displayed function doesn't exist for this server class: %s",
01987                    G_OBJECT_TYPE_NAME(server));
01988        return;
01989 }
01990 
02000 guint 
02001 indicate_server_get_next_id (IndicateServer * server)
02002 {
02003        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
02004 
02005        if (class != NULL && class->get_next_id != NULL) {
02006               return class->get_next_id (server);
02007        }
02008 
02009        return 0;
02010 }
02011 
02020 const gchar *
02021 indicate_server_get_path (IndicateServer *server)
02022 {
02023        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
02024 
02025         g_return_val_if_fail(INDICATE_IS_SERVER(server), NULL);
02026 
02027         return priv->path;
02028 }
02029 
02030 static IndicateInterests
02031 interest_string_to_enum (const gchar * interest_string)
02032 {
02033        if (!g_strcmp0(interest_string, INDICATE_INTEREST_STRING_SERVER_DISPLAY)) {
02034               return INDICATE_INTEREST_SERVER_DISPLAY;
02035        }
02036 
02037        if (!g_strcmp0(interest_string, INDICATE_INTEREST_STRING_SERVER_SIGNAL)) {
02038               return INDICATE_INTEREST_SERVER_SIGNAL;
02039        }
02040 
02041        if (!g_strcmp0(interest_string, INDICATE_INTEREST_STRING_INDICATOR_DISPLAY)) {
02042               return INDICATE_INTEREST_INDICATOR_DISPLAY;
02043        }
02044 
02045        if (!g_strcmp0(interest_string, INDICATE_INTEREST_STRING_INDICATOR_SIGNAL)) {
02046               return INDICATE_INTEREST_INDICATOR_SIGNAL;
02047        }
02048 
02049        if (!g_strcmp0(interest_string, INDICATE_INTEREST_STRING_INDICATOR_COUNT)) {
02050               return INDICATE_INTEREST_INDICATOR_COUNT;
02051        }
02052 
02053        return INDICATE_INTEREST_NONE;
02054 }
02055 
02056 static void
02057 bus_show_interest (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation)
02058 {
02059        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
02060 
02061        if (class != NULL && class->show_interest != NULL) {
02062               const gchar * interest = NULL;
02063 
02064               interest = g_variant_get_string(g_variant_get_child_value(params, 0), NULL);
02065 
02066               if (class->show_interest (server, g_dbus_method_invocation_get_sender(invocation), interest_string_to_enum(interest))){
02067                      g_dbus_method_invocation_return_value(invocation, NULL);
02068               } else {
02069                      g_dbus_method_invocation_return_error(invocation,
02070                                  indicate_server_error_quark(),
02071                                  SHOW_INTEREST_FAILED,
02072                                  "Unable to show interest: %s",
02073                                  interest);
02074               }
02075 
02076               return;
02077        }
02078 
02079        g_dbus_method_invocation_return_error(invocation,
02080                    indicate_server_error_quark(),
02081                    NO_SHOW_INTEREST,
02082                    "show_interest function doesn't exist for this server class: %s",
02083                    G_OBJECT_TYPE_NAME(server));
02084        return;
02085 }
02086 
02087 static void
02088 bus_remove_interest (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation)
02089 {
02090        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
02091 
02092        if (class != NULL && class->remove_interest != NULL) {
02093               const gchar * interest = NULL;
02094 
02095               interest = g_variant_get_string(g_variant_get_child_value(params, 0), NULL);
02096 
02097               if (class->remove_interest (server, g_dbus_method_invocation_get_sender(invocation), interest_string_to_enum(interest))){
02098                      g_dbus_method_invocation_return_value(invocation, NULL);
02099               } else {
02100                      g_dbus_method_invocation_return_error(invocation,
02101                                           indicate_server_error_quark(),
02102                                           REMOVE_INTEREST_FAILED,
02103                                           "Unable to remove interest: %s",
02104                                           interest);
02105               }
02106 
02107               return;
02108        }
02109 
02110        g_dbus_method_invocation_return_error(invocation,
02111                             indicate_server_error_quark(),
02112                             NO_REMOVE_INTEREST,
02113                             "remove_interest function doesn't exist for this server class: %s",
02114                             G_OBJECT_TYPE_NAME(server));
02115        return;
02116 }
02117 
02118 static void
02119 bus_set_max_indicators (IndicateServer * server, GVariant * params, GDBusMethodInvocation * invocation)
02120 {
02121        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
02122 
02123        if (class != NULL && class->max_indicators_set != NULL) {
02124               gint max = g_variant_get_int32(g_variant_get_child_value(params, 0));
02125 
02126               if (class->max_indicators_set (server, g_dbus_method_invocation_get_sender(invocation), max)){
02127                      g_dbus_method_invocation_return_value(invocation, NULL);
02128               } else {
02129                      g_dbus_method_invocation_return_error(invocation,
02130                                  indicate_server_error_quark(),
02131                                  MAX_INDICATORS_SET_FAILED,
02132                                  "Unable to set max indicators: %d",
02133                                  max);
02134               }
02135 
02136               return;
02137        }
02138 
02139        g_dbus_method_invocation_return_error(invocation,
02140                    indicate_server_error_quark(),
02141                    NO_MAX_INDICATORS_SET,
02142                    "max_indicators_set function doesn't exist for this server class: %s",
02143                    G_OBJECT_TYPE_NAME(server));
02144        return;
02145 }
02146 
02158 gboolean
02159 indicate_server_check_interest (IndicateServer * server, IndicateInterests interest)
02160 {
02161        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
02162 
02163        if (class != NULL && class->check_interest != NULL) {
02164               return class->check_interest (server, interest);
02165        }
02166 
02167        g_warning("check_interest function not implemented in this server class: %s", G_OBJECT_TYPE_NAME(server));
02168        return FALSE;
02169 }
02170 
02180 gint
02181 indicate_server_get_max_indicators (IndicateServer * server)
02182 {
02183        IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
02184 
02185        if (class != NULL && class->max_indicators_get != NULL) {
02186               return class->max_indicators_get (server);
02187        }
02188 
02189        g_warning("get_max_indicators function not implemented in this server class: %s", G_OBJECT_TYPE_NAME(server));
02190        return -1;
02191 }
02192 
02209 void
02210 indicate_server_set_menu (IndicateServer * server, DbusmenuServer * menu)
02211 {
02212        g_return_if_fail(INDICATE_IS_SERVER(server));
02213        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(server);
02214 
02215        if (priv->visible) {
02216               g_warning("Menu being changed when the indicator is visible.  Listeners will NOT be notified of this change.");
02217        }
02218 
02219        if (priv->dbusmenu != NULL) {
02220               g_object_unref(priv->dbusmenu);
02221               priv->dbusmenu = NULL;
02222        }
02223 
02224        priv->dbusmenu = menu;
02225        g_object_ref(priv->dbusmenu);
02226 
02227        return;
02228 }
02229 
02230 /* *** Folks stuff *** */
02231 
02232 /* This checks for folk by looking at the sender value
02233    and sees if we can find any that have the same sender. */
02234 static gint
02235 indicate_server_interested_folks_equal (gconstpointer a, gconstpointer b)
02236 {
02237        return g_strcmp0(((IndicateServerInterestedFolk *)a)->sender,((IndicateServerInterestedFolk *)b)->sender);
02238 }
02239 
02240 /* Creates a IndicateServerInterestedFolk structure and
02241    initializes the default values to reasonable defaults. */
02242 static void
02243 indicate_server_interested_folks_init (IndicateServerInterestedFolk * folk, const gchar * sender, const gchar * path, GDBusConnection * connection)
02244 {
02245        folk->sender = g_strdup(sender);
02246 
02247        guint i;
02248        for (i = INDICATE_INTEREST_NONE; i < INDICATE_INTEREST_LAST; i++) {
02249               folk->interests[i] = FALSE;
02250        }
02251 
02252        folk->max_indicators = MAX_INDICATORS_UNSET;
02253 
02254        folk->indicators_displayed = g_hash_table_new(g_direct_hash, g_direct_equal);
02255 
02256        g_dbus_proxy_new(connection,
02257                         G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
02258                         bus_interface_info,
02259                         sender,
02260                         path,
02261                         INDICATE_LISTENER_DBUS_IFACE,
02262                         NULL, /* TODO: cancelable */
02263                         folk_proxy_cb,
02264                         folk);
02265 
02266        return;
02267 }
02268 
02269 /* Look at when the name owner changes so that we can figure out
02270    if we need to delete the folks item */
02271 static void
02272 folks_name_owner_change (GObject * object, GParamSpec * pspec, gpointer user_data)
02273 {
02274        gchar * name = g_dbus_proxy_get_name_owner(G_DBUS_PROXY(object));
02275        if (name != NULL) {
02276               /* What?  Well, no matter, we don't care if it's there, we'll
02277                  just ignore this signal and move on. */
02278               g_free(name);
02279               return;
02280        }
02281 
02282        /* g_debug("\tBeing removed, interesting"); */
02283        IndicateServerPrivate * priv = INDICATE_SERVER_GET_PRIVATE(user_data);
02284 
02285        IndicateServerInterestedFolk searchitem;
02286        searchitem.sender = (gchar *)name;
02287        GList * entry = g_list_find_custom(priv->interestedfolks, &searchitem, indicate_server_interested_folks_equal);
02288 
02289        if (entry == NULL) {
02290               /* g_debug("\tWe don't have it, not interesting"); */
02291               return;
02292        }
02293 
02294        IndicateServerInterestedFolk * folk = (IndicateServerInterestedFolk *)entry->data;
02295        priv->interestedfolks = g_list_remove(priv->interestedfolks, entry->data);
02296 
02297        guint i;
02298        for (i = INDICATE_INTEREST_NONE; i < INDICATE_INTEREST_LAST; i++) {
02299               priv->interests[i] = FALSE;
02300        }
02301 
02302        GList * listi = NULL;
02303        for (listi = priv->interestedfolks ; listi != NULL ; listi = listi->next) {
02304               IndicateServerInterestedFolk * folkpointer = (IndicateServerInterestedFolk *)listi->data;
02305               /* g_debug("\tRebuild list from folk: %s", folkpointer->sender); */
02306               indicate_server_interested_folks_copy(folkpointer, priv->interests);
02307        }
02308 
02309        for (i = INDICATE_INTEREST_NONE; i < INDICATE_INTEREST_LAST; i++) {
02310               /* g_debug("\tComparing interests.  Interest: %d  Folk: %d  Everyone: %d", i, folk->interests[i], priv->interests[i]); */
02311               if (folk->interests[i] && !priv->interests[i]) {
02312                      /* We can only remove interest here.  Think about it for a
02313                         moment and I think you'll be cool with it. */
02314                      /* g_debug("\tOh, and it was interested in %d.  Not anymore.", i); */
02315                      g_signal_emit(G_OBJECT(user_data), signals[INTEREST_REMOVED], 0, i, TRUE);
02316               }
02317        }
02318 
02319        /* If the retired folk has set it's max indicators
02320           and it's the value we're using, we need to recalculate */
02321        if (folk->max_indicators != MAX_INDICATORS_UNSET && folk->max_indicators == priv->max_indicators) {
02322               recalculate_max_indicators(user_data);
02323        }
02324 
02325        g_hash_table_foreach(folk->indicators_displayed, indicator_display_check_recalc, INDICATE_SERVER(user_data));
02326 
02327        /* Finally destory everything */
02328        indicate_server_interested_folks_destroy(folk);
02329        return;
02330 
02331 }
02332 
02333 /* Callback for creating the proxy on the folks object */
02334 static void
02335 folk_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data)
02336 {
02337        GError * error = NULL;
02338 
02339        GDBusProxy * proxy = g_dbus_proxy_new_finish(res, &error);
02340        if (error != NULL) {
02341               g_warning("Unable to get folks proxy!");
02342               g_error_free(error);
02343               return;
02344        }
02345 
02346        IndicateServerInterestedFolk * folk = (IndicateServerInterestedFolk *)user_data;
02347        folk->proxy = proxy;
02348 
02349        g_signal_connect(G_OBJECT(proxy), "notify::g-name-owner", G_CALLBACK(folks_name_owner_change), folk);
02350 
02351        return;
02352 }
02353 
02354 /* Identifies an interest in the folk. */
02355 static void
02356 indicate_server_interested_folks_set (IndicateServerInterestedFolk * folk, IndicateInterests interest, gboolean value)
02357 {
02358        folk->interests[interest] = value;
02359        return;
02360 }
02361 
02362 /* Copies the interest table from a folk structure into a 
02363    generic gboolean array of length INDICATE_INTEREST_LAST */
02364 static void
02365 indicate_server_interested_folks_copy (IndicateServerInterestedFolk * folk, gboolean * interests)
02366 {
02367        guint i;
02368        for (i = INDICATE_INTEREST_NONE; i < INDICATE_INTEREST_LAST; i++) {
02369               if (folk->interests[i]) {
02370                      interests[i] = TRUE;
02371               }
02372        }
02373 
02374        return;
02375 }
02376 
02377 /* Destroys all the internal parts of the IndicateServerInterestedFolk
02378    and then destroys the structure itself */
02379 static void
02380 indicate_server_interested_folks_destroy(IndicateServerInterestedFolk * folk)
02381 {
02382        g_free(folk->sender);
02383        g_hash_table_destroy(folk->indicators_displayed);
02384 
02385        if (folk->proxy != NULL) {
02386               g_object_unref(folk->proxy);
02387        }
02388 
02389        g_free(folk);
02390        return;
02391 }
02392 
02393 /* *** End Folks *** */