Back to index

indicator-session  12.10.0
indicator-session.c
Go to the documentation of this file.
00001 /*
00002 A small wrapper utility to load indicators and put them as menu items
00003 into the gnome-panel using its applet interface.
00004 
00005 Copyright 2009 Canonical Ltd.
00006 
00007 Authors:
00008     Ted Gould <ted@canonical.com>
00009     Conor Curran <conor.curran@canonical.com>
00010 
00011 This program is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU General Public License version 3, as published
00013 by the Free Software Foundation.
00014 
00015 This program is distributed in the hope that it will be useful, but
00016 WITHOUT ANY WARRANTY; without even the implied warranties of
00017 MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
00018 PURPOSE.  See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License along
00021 with this program.  If not, see <http://www.gnu.org/licenses/>.
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027 
00028 #include <glib.h>
00029 #include <glib-object.h>
00030 #include <glib/gi18n-lib.h>
00031 #include <gtk/gtk.h>
00032 #include <gio/gio.h>
00033 
00034 #include <libdbusmenu-gtk/menu.h>
00035 
00036 #include <libindicator/indicator.h>
00037 #include <libindicator/indicator-object.h>
00038 #include <libindicator/indicator-service-manager.h>
00039 #include <libindicator/indicator-image-helper.h>
00040 
00041 #include "shared-names.h"
00042 #include "user-widget.h"
00043 
00044 #define INDICATOR_SESSION_TYPE            (indicator_session_get_type ())
00045 #define INDICATOR_SESSION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SESSION_TYPE, IndicatorSession))
00046 #define INDICATOR_SESSION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_SESSION_TYPE, IndicatorSessionClass))
00047 #define IS_INDICATOR_SESSION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_SESSION_TYPE))
00048 #define IS_INDICATOR_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_SESSION_TYPE))
00049 #define INDICATOR_SESSION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_SESSION_TYPE, IndicatorSessionClass))
00050 
00051 typedef struct _IndicatorSession      IndicatorSession;
00052 typedef struct _IndicatorSessionClass IndicatorSessionClass;
00053 
00054 struct _IndicatorSessionClass
00055 {
00056   IndicatorObjectClass parent_class;
00057 };
00058 
00059 struct _IndicatorSession
00060 {
00061   IndicatorObject parent;
00062   IndicatorServiceManager * service;
00063   IndicatorObjectEntry entry;
00064   GCancellable * service_proxy_cancel;
00065   GDBusProxy * service_proxy;
00066   GSettings * settings;
00067 };
00068 
00069 static gboolean greeter_mode;
00070 
00071 GType indicator_session_get_type (void);
00072 
00073 /* Indicator stuff */
00074 INDICATOR_SET_VERSION
00075 INDICATOR_SET_TYPE(INDICATOR_SESSION_TYPE)
00076 
00077 /* Prototypes */
00078 static gboolean new_user_item (DbusmenuMenuitem * newitem,
00079                                DbusmenuMenuitem * parent,
00080                                DbusmenuClient * client,
00081                                gpointer user_data);
00082 static gboolean build_restart_item (DbusmenuMenuitem * newitem,
00083                                     DbusmenuMenuitem * parent,
00084                                     DbusmenuClient * client,
00085                                     gpointer user_data);
00086 static void indicator_session_update_users_label (IndicatorSession* self,
00087                                                   const gchar* name);
00088 static void service_connection_cb (IndicatorServiceManager * sm, gboolean connected, gpointer user_data);
00089 static void receive_signal (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name, GVariant * parameters, gpointer user_data);
00090 static void service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data);
00091 static void user_real_name_get_cb (GObject * obj, GAsyncResult * res, gpointer user_data);
00092 
00093 static void indicator_session_class_init (IndicatorSessionClass *klass);
00094 static void indicator_session_init       (IndicatorSession *self);
00095 static void indicator_session_dispose    (GObject *object);
00096 static void indicator_session_finalize   (GObject *object);
00097 static GList* indicator_session_get_entries (IndicatorObject* obj);
00098 static guint indicator_session_get_location (IndicatorObject * io,
00099                                              IndicatorObjectEntry * entry);
00100 
00101 G_DEFINE_TYPE (IndicatorSession, indicator_session, INDICATOR_OBJECT_TYPE);
00102 
00103 static void
00104 indicator_session_class_init (IndicatorSessionClass *klass)
00105 {
00106        GObjectClass *object_class = G_OBJECT_CLASS (klass);
00107 
00108        object_class->dispose = indicator_session_dispose;
00109        object_class->finalize = indicator_session_finalize;
00110 
00111        IndicatorObjectClass * io_class = INDICATOR_OBJECT_CLASS(klass);
00112        io_class->get_entries = indicator_session_get_entries;
00113        io_class->get_location = indicator_session_get_location;
00114        return;
00115 }
00116 
00117 static void
00118 indicator_session_init (IndicatorSession *self)
00119 {
00120   self->settings = g_settings_new ("com.canonical.indicator.session");
00121 
00122   /* Now let's fire these guys up. */
00123   self->service = indicator_service_manager_new_version(INDICATOR_SESSION_DBUS_NAME,
00124                                                         INDICATOR_SESSION_DBUS_VERSION);
00125   g_signal_connect (G_OBJECT(self->service),
00126                     INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE,
00127                     G_CALLBACK(service_connection_cb), self);
00128 
00129   greeter_mode = !g_strcmp0(g_getenv("INDICATOR_GREETER_MODE"), "1");
00130 
00131   self->entry.name_hint = PACKAGE;
00132   self->entry.accessible_desc = _("Session Menu");
00133   self->entry.label = GTK_LABEL (gtk_label_new ("User Name"));
00134   self->entry.image = greeter_mode
00135                     ? indicator_image_helper (GREETER_ICON_DEFAULT)
00136                     : indicator_image_helper (ICON_DEFAULT);
00137   self->entry.menu = GTK_MENU (dbusmenu_gtkmenu_new(INDICATOR_SESSION_DBUS_NAME,
00138                                                     INDICATOR_SESSION_DBUS_OBJECT));
00139   g_settings_bind (self->settings, "show-real-name-on-panel",
00140                    self->entry.label, "visible",
00141                    G_SETTINGS_BIND_GET);
00142 
00143   gtk_widget_show (GTK_WIDGET(self->entry.menu));
00144   gtk_widget_show (GTK_WIDGET(self->entry.image));
00145   g_object_ref_sink (self->entry.menu);
00146   g_object_ref_sink (self->entry.image);
00147 
00148   // set up the handlers
00149   DbusmenuClient * menu_client = DBUSMENU_CLIENT(dbusmenu_gtkmenu_get_client(DBUSMENU_GTKMENU(self->entry.menu)));
00150   dbusmenu_client_add_type_handler (menu_client,
00151                                     USER_ITEM_TYPE,
00152                                     new_user_item);
00153   dbusmenu_client_add_type_handler (menu_client,
00154                                     RESTART_ITEM_TYPE,
00155                                     build_restart_item);
00156   dbusmenu_gtkclient_set_accel_group (DBUSMENU_GTKCLIENT(menu_client),
00157                                       gtk_accel_group_new());
00158 }
00159 
00160 static void
00161 indicator_session_dispose (GObject *object)
00162 {
00163   IndicatorSession * self = INDICATOR_SESSION(object);
00164 
00165   g_clear_object (&self->settings);
00166   g_clear_object (&self->service);
00167   g_clear_object (&self->service_proxy);
00168 
00169   if (self->service_proxy_cancel != NULL)
00170     {
00171       g_cancellable_cancel(self->service_proxy_cancel);
00172       g_clear_object (&self->service_proxy_cancel);
00173     }
00174 
00175   g_clear_object (&self->entry.menu);
00176 
00177   G_OBJECT_CLASS (indicator_session_parent_class)->dispose (object);
00178 }
00179 
00180 static void
00181 indicator_session_finalize (GObject *object)
00182 {
00183 
00184        G_OBJECT_CLASS (indicator_session_parent_class)->finalize (object);
00185        return;
00186 }
00187 
00188 static GList*
00189 indicator_session_get_entries (IndicatorObject* obj)
00190 {
00191   g_return_val_if_fail(IS_INDICATOR_SESSION(obj), NULL);
00192 
00193   IndicatorSession* self = INDICATOR_SESSION (obj);
00194   return g_list_append (NULL, &self->entry);
00195 }
00196 
00197 static guint
00198 indicator_session_get_location (IndicatorObject * io,
00199                                 IndicatorObjectEntry * entry)
00200 {
00201   return 0;
00202 }
00203 
00204 /* callback for the service manager state of being */
00205 static void
00206 service_connection_cb (IndicatorServiceManager * sm, gboolean connected, gpointer user_data)
00207 {
00208        IndicatorSession * self = INDICATOR_SESSION (user_data);
00209 
00210        if (connected) {
00211     if (self->service_proxy != NULL){
00212       // Its a reconnect !
00213       // Fetch synchronisation data and return (proxy is still legit)
00214       g_dbus_proxy_call (self->service_proxy,
00215                          "GetUserRealName",
00216                          NULL,
00217                          G_DBUS_CALL_FLAGS_NONE,
00218                          -1,
00219                          NULL,
00220                          user_real_name_get_cb,
00221                          user_data);
00222       return;
00223     }
00224 
00225          self->service_proxy_cancel = g_cancellable_new();
00226          g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
00227                               G_DBUS_PROXY_FLAGS_NONE,
00228                               NULL,
00229                               INDICATOR_SESSION_DBUS_NAME,
00230                               INDICATOR_SESSION_SERVICE_DBUS_OBJECT,
00231                               INDICATOR_SESSION_SERVICE_DBUS_IFACE,
00232                               self->service_proxy_cancel,
00233                               service_proxy_cb,
00234                               self);
00235   }
00236        return;
00237 }
00238 
00239 
00240 static void
00241 service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data)
00242 {
00243        GError * error = NULL;
00244 
00245        IndicatorSession * self = INDICATOR_SESSION(user_data);
00246        g_return_if_fail(self != NULL);
00247 
00248        GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error);
00249 
00250        g_clear_object (&self->service_proxy_cancel);
00251 
00252        if (error != NULL) {
00253               g_warning("Could not grab DBus proxy for %s: %s", INDICATOR_SESSION_DBUS_NAME, error->message);
00254               g_error_free(error);
00255               return;
00256        }
00257 
00258        /* Okay, we're good to grab the proxy at this point, we're
00259        sure that it's ours. */
00260        self->service_proxy = proxy;
00261 
00262        g_signal_connect(proxy, "g-signal", G_CALLBACK(receive_signal), self);
00263 
00264   // Fetch the user's real name for the user entry label
00265   g_dbus_proxy_call (self->service_proxy,
00266                      "GetUserRealName",
00267                      NULL,
00268                      G_DBUS_CALL_FLAGS_NONE,
00269                      -1,
00270                      NULL,
00271                      user_real_name_get_cb,
00272                      user_data);
00273        return;
00274 }
00275 
00276 
00277 static gboolean
00278 new_user_item (DbusmenuMenuitem * newitem,
00279                DbusmenuMenuitem * parent,
00280                DbusmenuClient   * client,
00281                gpointer           user_data)
00282 {
00283   g_return_val_if_fail (DBUSMENU_IS_MENUITEM(newitem), FALSE);
00284   g_return_val_if_fail (DBUSMENU_IS_GTKCLIENT(client), FALSE);
00285 
00286   GtkWidget * user_item = user_widget_new (newitem);
00287 
00288   GtkMenuItem *user_widget = GTK_MENU_ITEM(user_item);
00289 
00290   dbusmenu_gtkclient_newitem_base (DBUSMENU_GTKCLIENT(client),
00291                                    newitem,
00292                                    user_widget,
00293                                    parent);
00294 
00295   g_debug ("%s (\"%s\")", __func__,
00296            dbusmenu_menuitem_property_get (newitem,
00297                                            USER_ITEM_PROP_NAME));
00298   gtk_widget_show_all (user_item);
00299 
00300   return TRUE;
00301 }
00302 
00303 
00304 static void
00305 user_real_name_get_cb (GObject * obj, GAsyncResult * res, gpointer user_data)
00306 {
00307   IndicatorSession * self = INDICATOR_SESSION(user_data);
00308 
00309   GError * error = NULL;
00310   GVariant * result = g_dbus_proxy_call_finish(self->service_proxy, res, &error);
00311 
00312   if (error != NULL)
00313     {
00314       g_warning ("Unable to complete real name dbus query: %s", error->message);
00315       g_clear_error (&error);
00316     }
00317   else
00318     {
00319       const gchar * username = NULL;
00320       g_variant_get (result, "(&s)", &username);
00321       indicator_session_update_users_label (self, username);
00322       g_variant_unref (result);
00323     }
00324 }
00325 
00326 /* Receives all signals from the service, routed to the appropriate functions */
00327 static void
00328 receive_signal (GDBusProxy * proxy,
00329                 gchar      * sender_name,
00330                 gchar      * signal_name,
00331                 GVariant   * parameters,
00332                 gpointer     user_data)
00333 {
00334   IndicatorSession * self = INDICATOR_SESSION(user_data);
00335 
00336   if (!g_strcmp0(signal_name, "UserRealNameUpdated"))
00337     {
00338       const gchar * username = NULL;
00339       g_variant_get (parameters, "(&s)", &username);
00340       indicator_session_update_users_label (self, username);   
00341     }
00342   else if (!g_strcmp0(signal_name, "RestartRequired"))
00343     {
00344       indicator_image_helper_update (self->entry.image, greeter_mode ? GREETER_ICON_RESTART : ICON_RESTART);
00345       self->entry.accessible_desc = _("Device Menu (reboot required)");
00346       g_signal_emit (G_OBJECT(self), INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE_ID, 0, &self->entry);
00347     }
00348 }
00349 
00350 
00351 
00352 
00353 static void
00354 restart_property_change (DbusmenuMenuitem * item,
00355                          const gchar * property,
00356                          GVariant * variant,
00357                          gpointer user_data)
00358 {
00359        DbusmenuGtkClient * client = DBUSMENU_GTKCLIENT(user_data);
00360        GtkMenuItem * gmi = dbusmenu_gtkclient_menuitem_get(client, item);
00361 
00362        if (g_strcmp0(property, RESTART_ITEM_LABEL) == 0) {
00363               gtk_menu_item_set_label(gmi, g_variant_get_string(variant, NULL));
00364        } else if (g_strcmp0(property, RESTART_ITEM_ICON) == 0) {
00365               GtkWidget * image = gtk_image_menu_item_get_image(GTK_IMAGE_MENU_ITEM(gmi));
00366 
00367               GIcon * gicon = g_themed_icon_new_with_default_fallbacks(g_variant_get_string(variant, NULL));
00368               if (image == NULL) {
00369                      image = gtk_image_new_from_gicon(gicon, GTK_ICON_SIZE_MENU);
00370                      gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(gmi), image);
00371               } else {
00372                      gtk_image_set_from_gicon(GTK_IMAGE(image), gicon, GTK_ICON_SIZE_MENU);
00373               }
00374               g_object_unref(G_OBJECT(gicon));
00375        }
00376        return;
00377 }
00378 
00379 static gboolean
00380 build_restart_item (DbusmenuMenuitem * newitem,
00381                     DbusmenuMenuitem * parent,
00382                     DbusmenuClient * client,
00383                     gpointer user_data)
00384 {
00385        GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_image_menu_item_new());
00386        if (gmi == NULL) {
00387               return FALSE;
00388        }
00389 
00390        dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
00391 
00392        g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(restart_property_change), client);
00393 
00394        GVariant * variant;
00395        variant = dbusmenu_menuitem_property_get_variant(newitem, RESTART_ITEM_LABEL);
00396        if (variant != NULL) {
00397               restart_property_change(newitem, RESTART_ITEM_LABEL, variant, client);
00398        }
00399 
00400        variant = dbusmenu_menuitem_property_get_variant(newitem, RESTART_ITEM_ICON);
00401        if (variant != NULL) {
00402               restart_property_change(newitem, RESTART_ITEM_ICON, variant, client);
00403        }
00404 
00405        return TRUE;
00406 }
00407 
00408 static void
00409 indicator_session_update_users_label (IndicatorSession * self,
00410                                       const gchar      * name)
00411 {
00412   gtk_label_set_text (self->entry.label, name ? name : "");
00413 }