diff options
author | Ken VanDine <ken.vandine@canonical.com> | 2011-07-14 14:29:14 -0400 |
---|---|---|
committer | Ken VanDine <ken.vandine@canonical.com> | 2011-07-14 14:29:14 -0400 |
commit | bd7fb2850d02ae416b2fd2a80f668f25dc861872 (patch) | |
tree | f8efc400fb73fd71148173d9c1ead62af33f5d6d | |
parent | 0882ce4518215749b0cbe6a02532f61013801bf7 (diff) | |
parent | 84fb2fdde96442f79bb1da1edf4d707019b68f98 (diff) | |
download | ayatana-indicator-session-bd7fb2850d02ae416b2fd2a80f668f25dc861872.tar.gz ayatana-indicator-session-bd7fb2850d02ae416b2fd2a80f668f25dc861872.tar.bz2 ayatana-indicator-session-bd7fb2850d02ae416b2fd2a80f668f25dc861872.zip |
Import upstream version 0.2.93
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | ChangeLog | 112 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/Makefile.in | 14 | ||||
-rw-r--r-- | src/dbus-shared-names.h | 10 | ||||
-rw-r--r-- | src/gen-session-dbus.xml.c | 13 | ||||
-rw-r--r-- | src/indicator-session.c | 729 | ||||
-rw-r--r-- | src/session-dbus.c | 74 | ||||
-rw-r--r-- | src/session-dbus.h | 4 | ||||
-rw-r--r-- | src/session-dbus.xml | 13 | ||||
-rw-r--r-- | src/session-service.c | 533 | ||||
-rw-r--r-- | src/user-widget.c | 341 | ||||
-rw-r--r-- | src/user-widget.h | 54 |
15 files changed, 1297 insertions, 607 deletions
@@ -3,6 +3,7 @@ Alexander Sack Christoph Korn Cody Russell + Conor Curran David Barth Gabor Kelemen Ken VanDine @@ -1,5 +1,117 @@ # Generated by Makefile. Do not edit. +2011-07-14 Conor Curran <conor.curran@canonical.com> + + bumped release version + +2011-07-14 Conor Curran <conor.curran@canonical.com> + + merge in the big menu reorg + +2011-07-14 Conor Curran <conor.curran@canonical.com> + + changed default return value of get location to 0 + +2011-07-14 Conor Curran <conor.curran@canonical.com> + + ref sink instead of ref on the images and menus + +2011-07-14 Conor Curran <conor.curran@canonical.com> + + get location overridden and debugs tidied up + +2011-07-14 Conor Curran <conor.curran@canonical.com> + + dynamic user menu hiding on the way# + +2011-07-13 Conor Curran <conor.curran@canonical.com> + + user label fixed for now + +2011-07-13 Conor Curran <conor.curran@canonical.com> + + tidied up signals and methods for the session service so as the users real name should be available and not the icon, icon should not change on the panel + +2011-07-12 Conor Curran <conor.curran@canonical.com> + + correct icon on the user panel + +2011-07-12 Conor Curran <conor.curran@canonical.com> + + radio button for is-current-user handled + +2011-07-12 Conor Curran <conor.curran@canonical.com> + + the beginnings of the custom user item + +2011-07-11 Conor Curran <conor.curran@canonical.com> + + online accounts item added@ + +2011-07-11 Conor Curran <conor.curran@canonical.com> + + user account items shown, items rearranged + +2011-07-11 Conor Curran <conor.curran@canonical.com> + + tidied user menu + +2011-07-11 Conor Curran <conor.curran@canonical.com> + + merged trunk to keep up with changes + +2011-07-07 Conor Curran <conor.curran@canonical.com> + + icon updates for the user menu panel + +2011-07-07 Conor Curran <conor.curran@canonical.com> + + user label is now updated dynamically + +2011-07-07 Conor Curran <conor.curran@canonical.com> + + added the username to the panel + +2011-07-07 Conor Curran <conor.curran@canonical.com> + + icon now being shown on the panel for devices + +2011-07-07 Conor Curran <conor.curran@canonical.com> + + merged ted's fixes + +2011-07-06 Ted Gould <ted@gould.cx> + + Making sure that users has the same dbus name as session as there is one process. + +2011-07-06 Ted Gould <ted@gould.cx> + + Remvoing unused result + +2011-07-06 Conor Curran <conor.curran@canonical.com> + + tidy up + +2011-07-05 Conor Curran <conor.curran@canonical.com> + + code tidied, menu splittage in progress + +2011-07-05 Conor Curran <conor.curran@canonical.com> + + split out the menus + +2011-07-04 Conor Curran <conor.curran@canonical.com> + + menus split somewhat + +2011-07-02 Conor Curran <conor.curran@canonical.com> + + compiling at least + +2011-07-01 Conor Curran <conor.curran@canonical.com> + + initial menu reshuffle in progress + 2011-07-07 Ted Gould <ted@gould.cx> 0.2.92 @@ -2759,7 +2759,7 @@ fi # Define the identity of the package. PACKAGE=indicator-session - VERSION=0.2.92 + VERSION=0.2.93 cat >>confdefs.h <<_ACEOF diff --git a/configure.ac b/configure.ac index 4f2cb04..59227b8 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ AC_INIT(src/indicator-session.c) AC_PREREQ(2.53) AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(indicator-session, 0.2.92) +AM_INIT_AUTOMAKE(indicator-session, 0.2.93) AM_MAINTAINER_MODE diff --git a/src/Makefile.am b/src/Makefile.am index df0ec0f..71537c5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,6 +14,8 @@ libsession_la_SOURCES = \ gen-session-dbus.xml.h \ dbus-shared-names.h \ dbusmenu-shared.h \ + user-widget.c \ + user-widget.h \ accounts-service-client.h \ accounts-service-user-client.h libsession_la_CFLAGS = \ diff --git a/src/Makefile.in b/src/Makefile.in index 4baae5f..4b282fd 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -73,7 +73,8 @@ am__installdirs = "$(DESTDIR)$(sessionlibdir)" \ LTLIBRARIES = $(sessionlib_LTLIBRARIES) am__DEPENDENCIES_1 = libsession_la_DEPENDENCIES = $(am__DEPENDENCIES_1) -am_libsession_la_OBJECTS = libsession_la-indicator-session.lo +am_libsession_la_OBJECTS = libsession_la-indicator-session.lo \ + libsession_la-user-widget.lo libsession_la_OBJECTS = $(am_libsession_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) @@ -310,6 +311,8 @@ libsession_la_SOURCES = \ gen-session-dbus.xml.h \ dbus-shared-names.h \ dbusmenu-shared.h \ + user-widget.c \ + user-widget.h \ accounts-service-client.h \ accounts-service-user-client.h @@ -530,6 +533,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_session_service-session-service.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_session_service-users-service-dbus.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsession_la-indicator-session.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsession_la-user-widget.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -563,6 +567,14 @@ libsession_la-indicator-session.lo: indicator-session.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsession_la_CFLAGS) $(CFLAGS) -c -o libsession_la-indicator-session.lo `test -f 'indicator-session.c' || echo '$(srcdir)/'`indicator-session.c +libsession_la-user-widget.lo: user-widget.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsession_la_CFLAGS) $(CFLAGS) -MT libsession_la-user-widget.lo -MD -MP -MF $(DEPDIR)/libsession_la-user-widget.Tpo -c -o libsession_la-user-widget.lo `test -f 'user-widget.c' || echo '$(srcdir)/'`user-widget.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsession_la-user-widget.Tpo $(DEPDIR)/libsession_la-user-widget.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='user-widget.c' object='libsession_la-user-widget.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsession_la_CFLAGS) $(CFLAGS) -c -o libsession_la-user-widget.lo `test -f 'user-widget.c' || echo '$(srcdir)/'`user-widget.c + gtk_logout_helper-gtk-logout-helper.o: gtk-logout-helper.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gtk_logout_helper_CFLAGS) $(CFLAGS) -MT gtk_logout_helper-gtk-logout-helper.o -MD -MP -MF $(DEPDIR)/gtk_logout_helper-gtk-logout-helper.Tpo -c -o gtk_logout_helper-gtk-logout-helper.o `test -f 'gtk-logout-helper.c' || echo '$(srcdir)/'`gtk-logout-helper.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gtk_logout_helper-gtk-logout-helper.Tpo $(DEPDIR)/gtk_logout_helper-gtk-logout-helper.Po diff --git a/src/dbus-shared-names.h b/src/dbus-shared-names.h index f97dddc..c4ccd05 100644 --- a/src/dbus-shared-names.h +++ b/src/dbus-shared-names.h @@ -24,12 +24,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #ifndef __DBUS_SHARED_NAMES_H__ #define __DBUS_SHARED_NAMES_H__ 1 -#define INDICATOR_STATUS_DBUS_NAME "com.canonical.indicator.status" -#define INDICATOR_STATUS_DBUS_OBJECT "/com/canonical/indicator/status/menu" -#define INDICATOR_STATUS_SERVICE_DBUS_OBJECT "/com/canonical/indicator/status/service" -#define INDICATOR_STATUS_SERVICE_DBUS_INTERFACE "com.canonical.indicator.status.service" - -#define INDICATOR_USERS_DBUS_NAME "com.canonical.indicator.users" +#define INDICATOR_USERS_DBUS_NAME INDICATOR_SESSION_DBUS_NAME #define INDICATOR_USERS_DBUS_OBJECT "/com/canonical/indicator/users/menu" #define INDICATOR_USERS_SERVICE_DBUS_OBJECT "/org/gnome/DisplayManager/UserManager" #define INDICATOR_USERS_SERVICE_DBUS_INTERFACE "org.gnome.DisplayManager.UserManager" @@ -44,8 +39,9 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define USER_ITEM_TYPE "x-canonical-user-item" #define USER_ITEM_PROP_NAME "user-item-name" #define USER_ITEM_PROP_LOGGED_IN "user-item-logged-in" +#define USER_ITEM_PROP_IS_CURRENT_USER "user-item-is-current-user" #define USER_ITEM_PROP_ICON "user-item-icon-path" -#define USER_ITEM_ICON_DEFAULT "default-icon" +#define USER_ITEM_ICON_DEFAULT "user-offline" #define RESTART_ITEM_TYPE "x-canonical-restart-item" #define RESTART_ITEM_LABEL "restart-label" diff --git a/src/gen-session-dbus.xml.c b/src/gen-session-dbus.xml.c index 493d18d..9b20569 100644 --- a/src/gen-session-dbus.xml.c +++ b/src/gen-session-dbus.xml.c @@ -3,15 +3,18 @@ const char * _session_dbus = "<node name=\"/com/canonical/indicator/session/service\">\n" " <interface name=\"com.canonical.indicator.session.service\">\n" "\n" -" <!-- Icon -->\n" -" <method name=\"GetIcon\">\n" +" <method name=\"GetUserRealName\">\n" " <arg name=\"name\" direction=\"out\" type=\"s\"/>\n" " </method>\n" -"\n" -" <signal name=\"IconUpdated\">\n" +" <method name=\"GetUserMenuVisibility\">\n" +" <arg name=\"update\" direction=\"out\" type=\"b\"/>\n" +" </method>\n" +" <signal name=\"UserRealNameUpdated\">\n" " <arg name=\"name\" type=\"s\"/>\n" " </signal>\n" -"\n" +" <signal name=\"UserMenuIsVisible\">\n" +" <arg name=\"update\" type=\"b\"/>\n" +" </signal>\n" " </interface>\n" "</node>\n" ; diff --git a/src/indicator-session.c b/src/indicator-session.c index c9617c4..068ffef 100644 --- a/src/indicator-session.c +++ b/src/indicator-session.c @@ -20,6 +20,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +//TODO - remember to reinsert Ted's comments. #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -43,6 +44,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include "dbus-shared-names.h" #include "dbusmenu-shared.h" +#include "user-widget.h" #define INDICATOR_SESSION_TYPE (indicator_session_get_type ()) #define INDICATOR_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SESSION_TYPE, IndicatorSession)) @@ -61,8 +63,9 @@ struct _IndicatorSessionClass { struct _IndicatorSession { IndicatorObject parent; IndicatorServiceManager * service; - GtkImage * status_image; - DbusmenuGtkMenu * menu; + IndicatorObjectEntry users; + IndicatorObjectEntry devices; + gboolean show_users_entry; GCancellable * service_proxy_cancel; GDBusProxy * service_proxy; }; @@ -74,26 +77,37 @@ INDICATOR_SET_VERSION INDICATOR_SET_TYPE(INDICATOR_SESSION_TYPE) /* Prototypes */ -static GtkLabel * get_label (IndicatorObject * io); -static GtkImage * get_icon (IndicatorObject * io); -static GtkMenu * get_menu (IndicatorObject * io); -static const gchar * get_accessible_desc (IndicatorObject * io); -static gboolean build_menu_switch (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data); -static gboolean new_user_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data); -static void icon_changed (IndicatorSession * session, const gchar * icon_name); +static gboolean build_menu_switch (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data); +static gboolean new_user_item (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data); +static gboolean build_restart_item (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data); +static void indicator_session_update_users_label (IndicatorSession* self, + const gchar* name); static void service_connection_cb (IndicatorServiceManager * sm, gboolean connected, gpointer user_data); -static gboolean build_restart_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data); static void receive_signal (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name, GVariant * parameters, gpointer user_data); static void service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data); +static void user_real_name_get_cb (GObject * obj, GAsyncResult * res, gpointer user_data); +static void user_menu_visibility_get_cb (GObject* obj, GAsyncResult* res, gpointer user_data); static void indicator_session_class_init (IndicatorSessionClass *klass); static void indicator_session_init (IndicatorSession *self); static void indicator_session_dispose (GObject *object); static void indicator_session_finalize (GObject *object); - +static GList* indicator_session_get_entries (IndicatorObject* obj); +static guint indicator_session_get_location (IndicatorObject * io, + IndicatorObjectEntry * entry); + G_DEFINE_TYPE (IndicatorSession, indicator_session, INDICATOR_OBJECT_TYPE); -static void +static void indicator_session_class_init (IndicatorSessionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); @@ -102,82 +116,89 @@ indicator_session_class_init (IndicatorSessionClass *klass) object_class->finalize = indicator_session_finalize; IndicatorObjectClass * io_class = INDICATOR_OBJECT_CLASS(klass); - io_class->get_label = get_label; - io_class->get_image = get_icon; - io_class->get_menu = get_menu; - io_class->get_accessible_desc = get_accessible_desc; - + io_class->get_entries = indicator_session_get_entries; + io_class->get_location = indicator_session_get_location; return; } static void indicator_session_init (IndicatorSession *self) { - /* Set good defaults */ self->service = NULL; self->service_proxy_cancel = NULL; self->service_proxy = NULL; - + self->show_users_entry = FALSE; + /* Now let's fire these guys up. */ - self->service = indicator_service_manager_new_version(INDICATOR_SESSION_DBUS_NAME, INDICATOR_SESSION_DBUS_VERSION); - g_signal_connect(G_OBJECT(self->service), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, G_CALLBACK(service_connection_cb), self); - - self->status_image = indicator_image_helper(ICON_DEFAULT); - self->menu = dbusmenu_gtkmenu_new(INDICATOR_SESSION_DBUS_NAME, INDICATOR_SESSION_DBUS_OBJECT); - - DbusmenuClient * client = DBUSMENU_CLIENT(dbusmenu_gtkmenu_get_client(self->menu)); - dbusmenu_client_add_type_handler(client, MENU_SWITCH_TYPE, build_menu_switch); - dbusmenu_client_add_type_handler(client, USER_ITEM_TYPE, new_user_item); - dbusmenu_client_add_type_handler(client, RESTART_ITEM_TYPE, build_restart_item); - + self->service = indicator_service_manager_new_version(INDICATOR_SESSION_DBUS_NAME, + INDICATOR_SESSION_DBUS_VERSION); + g_signal_connect(G_OBJECT(self->service), + INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, + G_CALLBACK(service_connection_cb), self); + + GtkWidget* avatar_icon = NULL; + // users + self->users.menu = GTK_MENU (dbusmenu_gtkmenu_new (INDICATOR_USERS_DBUS_NAME, + INDICATOR_USERS_DBUS_OBJECT)); + // Set the image to the default avator image + GdkPixbuf* pixbuf = NULL; + GError* error = NULL; + pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), + "avatar-default", + 17, + GTK_ICON_LOOKUP_FORCE_SIZE, + &error); + + // I think the avatar image is available always but just in case have a fallback + if (error != NULL) { + g_warning ("Could not load the default avatar image for some reason"); + self->users.image = indicator_image_helper (USER_ITEM_ICON_DEFAULT); + } + else{ + avatar_icon = gtk_image_new (); + gtk_image_set_from_pixbuf (GTK_IMAGE (avatar_icon), pixbuf); + self->users.image = GTK_IMAGE (avatar_icon); + g_object_unref (pixbuf); + g_error_free (error); + } + + self->users.label = GTK_LABEL (gtk_label_new (NULL)); + // Only show once we have a valid username + // gtk_widget_hide (GTK_WIDGET(self->users.label)); + + // devices + self->devices.menu = GTK_MENU (dbusmenu_gtkmenu_new(INDICATOR_SESSION_DBUS_NAME, + INDICATOR_SESSION_DBUS_OBJECT)); + self->devices.image = indicator_image_helper (ICON_DEFAULT); + + gtk_widget_show (GTK_WIDGET(self->devices.menu)); + gtk_widget_show (GTK_WIDGET(self->devices.image)); + gtk_widget_show (GTK_WIDGET(self->users.image)); + gtk_widget_show (GTK_WIDGET(self->users.menu)); + + g_object_ref_sink (self->users.menu); + g_object_ref_sink (self->users.image); + g_object_ref_sink (self->devices.menu); + g_object_ref_sink (self->devices.image); + + // Setup the handlers for users + DbusmenuClient * users_client = DBUSMENU_CLIENT(dbusmenu_gtkmenu_get_client(DBUSMENU_GTKMENU(self->users.menu))); + dbusmenu_client_add_type_handler (users_client, + USER_ITEM_TYPE, + new_user_item); + dbusmenu_client_add_type_handler_full (users_client, + MENU_SWITCH_TYPE, + build_menu_switch, + self, NULL); + + // Setup the handlers for devices + DbusmenuClient * devices_client = DBUSMENU_CLIENT(dbusmenu_gtkmenu_get_client(DBUSMENU_GTKMENU(self->devices.menu))); + dbusmenu_client_add_type_handler (devices_client, + RESTART_ITEM_TYPE, + build_restart_item); + GtkAccelGroup * agroup = gtk_accel_group_new(); - dbusmenu_gtkclient_set_accel_group(DBUSMENU_GTKCLIENT(client), agroup); - - self->service_proxy_cancel = g_cancellable_new(); - - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - INDICATOR_SESSION_DBUS_NAME, - INDICATOR_SESSION_SERVICE_DBUS_OBJECT, - INDICATOR_SESSION_SERVICE_DBUS_IFACE, - self->service_proxy_cancel, - service_proxy_cb, - self); - - return; -} - -/* Callback from trying to create the proxy for the serivce, this - could include starting the service. Sometime it'll fail and - we'll try to start that dang service again! */ -static void -service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data) -{ - GError * error = NULL; - - IndicatorSession * self = INDICATOR_SESSION(user_data); - g_return_if_fail(self != NULL); - - GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error); - - if (self->service_proxy_cancel != NULL) { - g_object_unref(self->service_proxy_cancel); - self->service_proxy_cancel = NULL; - } - - if (error != NULL) { - g_warning("Could not grab DBus proxy for %s: %s", INDICATOR_SESSION_DBUS_NAME, error->message); - g_error_free(error); - return; - } - - /* Okay, we're good to grab the proxy at this point, we're - sure that it's ours. */ - self->service_proxy = proxy; - - g_signal_connect(proxy, "g-signal", G_CALLBACK(receive_signal), self); - + dbusmenu_gtkclient_set_accel_group(DBUSMENU_GTKCLIENT(devices_client), agroup); return; } @@ -201,6 +222,14 @@ indicator_session_dispose (GObject *object) g_object_unref(self->service_proxy_cancel); self->service_proxy_cancel = NULL; } + + if (self->users.menu != NULL) { + g_object_unref (self->users.menu); + } + + if (self->devices.menu != NULL) { + g_object_unref (self->devices.menu); + } G_OBJECT_CLASS (indicator_session_parent_class)->dispose (object); return; @@ -214,256 +243,348 @@ indicator_session_finalize (GObject *object) return; } -static void -icon_name_get_cb (GObject * obj, GAsyncResult * res, gpointer user_data) +static GList* +indicator_session_get_entries (IndicatorObject* obj) { - IndicatorSession * self = INDICATOR_SESSION(user_data); - GError * error = NULL; - gchar * name; - GVariant * result; - - result = g_dbus_proxy_call_finish(self->service_proxy, res, &error); - - if (error != NULL) { - return; - } - - g_variant_get(result, "(&s)", &name); - - if (name == NULL || name[0] == '\0') { - return; + g_return_val_if_fail(IS_INDICATOR_SESSION(obj), NULL); + IndicatorSession* self = INDICATOR_SESSION (obj); + + g_debug ("get entries"); + GList * retval = NULL; + // Only show the users menu if we have more than one + if (self->show_users_entry == TRUE){ + retval = g_list_prepend (retval, &self->users); + } + retval = g_list_prepend (retval, &self->devices); + + if (retval != NULL) { + retval = g_list_reverse(retval); } + return retval; +} - indicator_image_helper_update(self->status_image, name); - return; +static guint +indicator_session_get_location (IndicatorObject * io, + IndicatorObjectEntry * entry) +{ + IndicatorSession * self = INDICATOR_SESSION (io); + if (entry == &self->users){ + return 1; + } + else if (entry == &self->devices){ + return 0; + } + g_warning ("IOEntry handed to us to position but we don't own it!"); + return 0; } +/* callback for the service manager state of being */ static void service_connection_cb (IndicatorServiceManager * sm, gboolean connected, gpointer user_data) { - IndicatorSession * self = INDICATOR_SESSION(user_data); + IndicatorSession * self = INDICATOR_SESSION (user_data); if (connected) { - g_dbus_proxy_call(self->service_proxy, "GetIcon", NULL, - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - icon_name_get_cb, user_data); - } else { - indicator_image_helper_update(self->status_image, ICON_DEFAULT); - } - + if (self->service_proxy != NULL){ + // Its a reconnect ! + // Fetch synchronisation data and return (proxy is still legit) + g_dbus_proxy_call (self->service_proxy, + "GetUserMenuVisibility", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + user_menu_visibility_get_cb, + user_data); + g_dbus_proxy_call (self->service_proxy, + "GetUserRealName", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + user_real_name_get_cb, + user_data); + return; + } + + self->service_proxy_cancel = g_cancellable_new(); + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + INDICATOR_SESSION_DBUS_NAME, + INDICATOR_SESSION_SERVICE_DBUS_OBJECT, + INDICATOR_SESSION_SERVICE_DBUS_IFACE, + self->service_proxy_cancel, + service_proxy_cb, + self); + } return; } -static GtkLabel * -get_label (IndicatorObject * io) -{ - return NULL; -} - -static const gchar * -get_accessible_desc (IndicatorObject * io) -{ - return _("Session"); -} static void -icon_changed (IndicatorSession * session, const gchar * icon_name) +service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data) { - indicator_image_helper_update(session->status_image, icon_name); - return; -} + GError * error = NULL; -/* Receives all signals from the service, routed to the appropriate functions */ -static void -receive_signal (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name, - GVariant * parameters, gpointer user_data) -{ IndicatorSession * self = INDICATOR_SESSION(user_data); + g_return_if_fail(self != NULL); - if (g_strcmp0(signal_name, "IconUpdated") == 0) { - const gchar *name; - g_variant_get (parameters, "(&s)", &name); - icon_changed(self, name); + GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error); + + if (self->service_proxy_cancel != NULL) { + g_object_unref(self->service_proxy_cancel); + self->service_proxy_cancel = NULL; } - return; -} + if (error != NULL) { + g_warning("Could not grab DBus proxy for %s: %s", INDICATOR_SESSION_DBUS_NAME, error->message); + g_error_free(error); + return; + } -static GtkImage * -get_icon (IndicatorObject * io) -{ - gtk_widget_show(GTK_WIDGET(INDICATOR_SESSION(io)->status_image)); - return INDICATOR_SESSION(io)->status_image; -} + /* Okay, we're good to grab the proxy at this point, we're + sure that it's ours. */ + self->service_proxy = proxy; -static void -user_property_change (DbusmenuMenuitem * item, const gchar * property, GVariant * variant, gpointer user_data) -{ - if (g_strcmp0(property, USER_ITEM_PROP_LOGGED_IN) == 0) { - if (g_variant_get_boolean(variant)) { - gtk_widget_show(GTK_WIDGET(user_data)); - } else { - gtk_widget_hide(GTK_WIDGET(user_data)); - } - } + g_signal_connect(proxy, "g-signal", G_CALLBACK(receive_signal), self); + + // Figure out whether we should show the user menu at all. + g_dbus_proxy_call (self->service_proxy, + "GetUserMenuVisibility", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + user_menu_visibility_get_cb, + user_data); + + // Fetch the user's real name for the user entry label + g_dbus_proxy_call (self->service_proxy, + "GetUserRealName", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + user_real_name_get_cb, + user_data); return; } -/* Builds an item with a hip little logged in icon. */ + static gboolean -new_user_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data) +new_user_item (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data) { - GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new()); - gint padding = 0; - gtk_widget_style_get(GTK_WIDGET(gmi), "horizontal-padding", &padding, NULL); - GtkWidget * hbox = gtk_hbox_new(FALSE, padding); - - GtkWidget * usericon = NULL; - const gchar * icon_name = dbusmenu_menuitem_property_get(newitem, USER_ITEM_PROP_ICON); - g_debug("Using user icon for '%s' from file: %s", dbusmenu_menuitem_property_get(newitem, USER_ITEM_PROP_NAME), icon_name); - if (icon_name != NULL && icon_name[0] != '\0') { - if (g_strcmp0(icon_name, USER_ITEM_ICON_DEFAULT) != 0 && g_file_test(icon_name, G_FILE_TEST_EXISTS)) { - gint width, height; - gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); - - GError * error = NULL; - GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file_at_size(icon_name, width, height, &error); - - if (error == NULL) { - usericon = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(pixbuf); - } else { - g_warning("Unable to load user icon '%s': %s", icon_name, error->message); - g_error_free(error); - } - } + - if (usericon == NULL) { - GIcon * gicon = g_themed_icon_new_with_default_fallbacks("stock_person-panel"); - usericon = gtk_image_new_from_gicon(gicon, GTK_ICON_SIZE_MENU); - g_object_unref(gicon); - } - } - if (usericon != NULL) { - gtk_misc_set_alignment(GTK_MISC(usericon), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), usericon, FALSE, FALSE, 0); - gtk_widget_show(usericon); - } + GtkWidget* user_item = NULL; - GtkWidget * label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, USER_ITEM_PROP_NAME)); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); - gtk_widget_show(label); - - GtkWidget * icon = gtk_image_new_from_icon_name("account-logged-in", GTK_ICON_SIZE_MENU); - gtk_misc_set_alignment(GTK_MISC(icon), 1.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0); - if (dbusmenu_menuitem_property_get_bool(newitem, USER_ITEM_PROP_LOGGED_IN)) { - gtk_widget_show(icon); - } else { - gtk_widget_hide(icon); - } + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); + g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); - gtk_container_add(GTK_CONTAINER(gmi), hbox); - gtk_widget_show(hbox); + user_item = user_widget_new(newitem); - dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent); + GtkMenuItem *user_widget = GTK_MENU_ITEM(user_item); - g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(user_property_change), icon); + dbusmenu_gtkclient_newitem_base (DBUSMENU_GTKCLIENT(client), + newitem, + user_widget, + parent); - return TRUE; -} + g_debug ("%s (\"%s\")", __func__, + dbusmenu_menuitem_property_get (newitem, + USER_ITEM_PROP_NAME)); + gtk_widget_show_all (user_item); -/* Indicator based function to get the menu for the whole - applet. This starts up asking for the parts of the menu - from the various services. */ -static GtkMenu * -get_menu (IndicatorObject * io) -{ - return GTK_MENU(INDICATOR_SESSION(io)->menu); + return TRUE; } + static void -switch_property_change (DbusmenuMenuitem * item, const gchar * property, GVariant * variant, gpointer user_data) +user_real_name_get_cb (GObject * obj, GAsyncResult * res, gpointer user_data) { - if (g_strcmp0(property, MENU_SWITCH_USER) != 0) { - return; - } - - GtkMenuItem * gmi = dbusmenu_gtkclient_menuitem_get(DBUSMENU_GTKCLIENT(user_data), item); - gchar * finalstring = NULL; - gboolean set_ellipsize = FALSE; - gboolean no_name_in_lang = FALSE; - - /* TRANSLATORS: Translate the '1' below into anything other than - '1' if "Switch From %s..." doesn't make sense in your language. - Instead, the string "Switch User..." will be used. */ - const gchar * translate = C_("session_menu:switchfrom", "1"); - if (g_strcmp0(translate, "1") != 0) { - no_name_in_lang = TRUE; - } + IndicatorSession * self = INDICATOR_SESSION(user_data); + GError * error = NULL; + GVariant * result; - /* If there's a NULL string of some type, then we want to - go back to our old 'Switch User' which isn't great but - eh, this error condition should never happen. */ - if (variant == NULL || g_variant_get_string(variant, NULL) == NULL || g_variant_get_string(variant, NULL)[0] == '\0' || no_name_in_lang) { - finalstring = _("Switch User..."); - set_ellipsize = FALSE; - } + result = g_dbus_proxy_call_finish(self->service_proxy, res, &error); - if (finalstring == NULL) { - const gchar * username = g_variant_get_string(variant, NULL); - GtkStyle * style = gtk_widget_get_style(GTK_WIDGET(gmi)); + if (error != NULL) { + g_warning ("unable to complete real name dbus query"); + g_error_free (error); + return; + } + + const gchar* username = NULL; + g_variant_get (result, "(s)", &username); + indicator_session_update_users_label (self, username); + return; +} - PangoLayout * layout = pango_layout_new(gtk_widget_get_pango_context(GTK_WIDGET(gmi))); - pango_layout_set_text(layout, username, -1); - pango_layout_set_font_description(layout, style->font_desc); +static void +user_menu_visibility_get_cb (GObject* obj, GAsyncResult* res, gpointer user_data) +{ + IndicatorSession * self = INDICATOR_SESSION(user_data); + GError * error = NULL; + GVariant * result; - gint width; - pango_layout_get_pixel_size(layout, &width, NULL); - g_object_unref(layout); - g_debug("Username width %dpx", width); + result = g_dbus_proxy_call_finish(self->service_proxy, res, &error); - gint point = pango_font_description_get_size(style->font_desc); - g_debug("Font size %f pt", (gfloat)point / PANGO_SCALE); + if (error != NULL) { + g_warning ("unable to complete real name dbus query"); + g_error_free (error); + return; + } + gboolean update; + g_variant_get (result, "(b)", &update); + + // If it is what we had before no need to do anything... + if (self->show_users_entry == update){ + return; + } + + //Otherwise + self->show_users_entry = update; + + IndicatorObjectEntry user_entry = self->users; + + if (self->show_users_entry == TRUE){ + g_signal_emit_by_name ((gpointer)self, + "entry-added", + &user_entry); + } + else{ + g_signal_emit_by_name ((gpointer)self, + "entry-removed", + &user_entry); + } +} - gdouble dpi = gdk_screen_get_resolution(gdk_screen_get_default()); - g_debug("Screen DPI %f", dpi); +/* Receives all signals from the service, routed to the appropriate functions */ +static void +receive_signal (GDBusProxy * proxy, + gchar * sender_name, + gchar * signal_name, + GVariant * parameters, + gpointer user_data) +{ + IndicatorSession * self = INDICATOR_SESSION(user_data); - gdouble pixels_per_em = ((point * dpi) / 72.0f) / PANGO_SCALE; - gdouble ems = width / pixels_per_em; - g_debug("Username width %fem", ems); + if (g_strcmp0(signal_name, "UserRealNameUpdated") == 0) { + const gchar* username = NULL; + g_variant_get (parameters, "(s)", &username); + indicator_session_update_users_label (self, username); + } + else if (g_strcmp0(signal_name, "UserMenuIsVisible") == 0) { + gboolean update; + g_variant_get (parameters, "(b)", &update); + + // If it is what we had before no need to do anything... + if (self->show_users_entry == update){ + return; + } + + //Otherwise + self->show_users_entry = update; + + IndicatorObjectEntry user_entry = self->users; + + if (self->show_users_entry == TRUE){ + g_signal_emit_by_name ((gpointer)self, + "entry-added", + &user_entry); + } + else{ + g_signal_emit_by_name ((gpointer)self, + "entry-removed", + &user_entry); + } + } +} - /* TODO: We need some way to remove the elipsis from appearing - twice in the label. Not sure how to do that yet. */ - finalstring = g_strdup_printf(_("Switch From %s..."), username); - if (ems >= 20.0f) { - set_ellipsize = TRUE; - } else { - set_ellipsize = FALSE; - } - } - gtk_menu_item_set_label(gmi, finalstring); - GtkLabel * label = GTK_LABEL(gtk_bin_get_child(GTK_BIN(gmi))); - if (label != NULL) { - if (set_ellipsize) { - gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_END); - } else { - gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_NONE); - } - } +static void +switch_property_change (DbusmenuMenuitem * item, + const gchar * property, + GVariant * variant, + gpointer user_data) +{ + if (g_strcmp0 (property, MENU_SWITCH_USER) != 0) { + return; + } + + GtkMenuItem * gmi = dbusmenu_gtkclient_menuitem_get(DBUSMENU_GTKCLIENT(user_data), item); + gchar * finalstring = NULL; + gboolean set_ellipsize = FALSE; + gboolean no_name_in_lang = FALSE; + + const gchar * translate = C_("session_menu:switchfrom", "1"); + if (g_strcmp0(translate, "1") != 0) { + no_name_in_lang = TRUE; + } + + if (variant == NULL || g_variant_get_string(variant, NULL) == NULL || + g_variant_get_string(variant, NULL)[0] == '\0' || no_name_in_lang) { + finalstring = _("Switch User..."); + set_ellipsize = FALSE; + } + + if (finalstring == NULL) { + const gchar * username = g_variant_get_string(variant, NULL); + GtkStyle * style = gtk_widget_get_style(GTK_WIDGET(gmi)); + + PangoLayout * layout = pango_layout_new(gtk_widget_get_pango_context(GTK_WIDGET(gmi))); + pango_layout_set_text (layout, username, -1); + pango_layout_set_font_description(layout, style->font_desc); + + gint width; + pango_layout_get_pixel_size(layout, &width, NULL); + g_object_unref(layout); + g_debug("Username width %dpx", width); + + gint point = pango_font_description_get_size(style->font_desc); + g_debug("Font size %f pt", (gfloat)point / PANGO_SCALE); + + gdouble dpi = gdk_screen_get_resolution(gdk_screen_get_default()); + g_debug("Screen DPI %f", dpi); + + gdouble pixels_per_em = ((point * dpi) / 72.0f) / PANGO_SCALE; + gdouble ems = width / pixels_per_em; + g_debug("Username width %fem", ems); + + finalstring = g_strdup_printf(_("Switch From %s..."), username); + if (ems >= 20.0f) { + set_ellipsize = TRUE; + } else { + set_ellipsize = FALSE; + } + + } + gtk_menu_item_set_label(gmi, finalstring); + + GtkLabel * label = GTK_LABEL(gtk_bin_get_child(GTK_BIN(gmi))); + if (label != NULL) { + if (set_ellipsize) { + gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_END); + } else { + gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_NONE); + } + } return; } static const gchar * dbusmenu_item_data = "dbusmenu-item"; -/* IF the label or icon changes we need to grab that and update - the menu item */ static void -restart_property_change (DbusmenuMenuitem * item, const gchar * property, GVariant * variant, gpointer user_data) +restart_property_change (DbusmenuMenuitem * item, + const gchar * property, + GVariant * variant, + gpointer user_data) { DbusmenuGtkClient * client = DBUSMENU_GTKCLIENT(user_data); GtkMenuItem * gmi = dbusmenu_gtkclient_menuitem_get(client, item); @@ -482,14 +603,14 @@ restart_property_change (DbusmenuMenuitem * item, const gchar * property, GVaria } g_object_unref(G_OBJECT(gicon)); } - return; } -/* Builds the restart item which is a more traditional GTK image - menu item that puts the graphic into the gutter. */ static gboolean -build_restart_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data) +build_restart_item (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data) { GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_image_menu_item_new()); if (gmi == NULL) { @@ -500,7 +621,6 @@ build_restart_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(restart_property_change), client); - /* Grab the inital variants and put them into the item */ GVariant * variant; variant = dbusmenu_menuitem_property_get_variant(newitem, RESTART_ITEM_LABEL); if (variant != NULL) { @@ -515,36 +635,63 @@ build_restart_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm return TRUE; } - -/* Callback for when the style changes so we can reevaluate the - size of the user name with the potentially new font. */ static void -switch_style_set (GtkWidget * widget, GtkStyle * prev_style, gpointer user_data) +switch_style_set (GtkWidget * widget, + GtkStyle * prev_style, + gpointer user_data) { DbusmenuGtkClient * client = DBUSMENU_GTKCLIENT(user_data); - DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(g_object_get_data(G_OBJECT(widget), dbusmenu_item_data)); + DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(g_object_get_data(G_OBJECT(widget), + dbusmenu_item_data)); - switch_property_change(mi, MENU_SWITCH_USER, dbusmenu_menuitem_property_get_variant(mi, MENU_SWITCH_USER), client); + switch_property_change (mi, + MENU_SWITCH_USER, + dbusmenu_menuitem_property_get_variant(mi, MENU_SWITCH_USER), + client); return; } -/* This function checks to see if the user name is short enough - to not need ellipsing itself, or if, it will get ellipsed by - the standard label processor. */ static gboolean -build_menu_switch (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data) +build_menu_switch (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data) { GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new()); if (gmi == NULL) { return FALSE; } - g_object_set_data(G_OBJECT(gmi), dbusmenu_item_data, newitem); + + g_object_set_data(G_OBJECT(gmi), dbusmenu_item_data, newitem); dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent); - g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(switch_property_change), client); - g_signal_connect(G_OBJECT(gmi), "style-set", G_CALLBACK(switch_style_set), client); - switch_property_change(newitem, MENU_SWITCH_USER, dbusmenu_menuitem_property_get_variant(newitem, MENU_SWITCH_USER), client); + g_signal_connect (G_OBJECT(newitem), + DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, + G_CALLBACK(switch_property_change), + client); + g_signal_connect (G_OBJECT(gmi), + "style-set", + G_CALLBACK(switch_style_set), + client); + + switch_property_change (newitem, + MENU_SWITCH_USER, + dbusmenu_menuitem_property_get_variant(newitem, MENU_SWITCH_USER), client); + + return TRUE; +} - return TRUE; +static void +indicator_session_update_users_label (IndicatorSession* self, + const gchar* name) +{ + g_debug ("update users label"); + + if (name == NULL){ + gtk_widget_hide(GTK_WIDGET(self->users.label)); + return; + } + gtk_label_set_text (self->users.label, g_strdup(name)); + gtk_widget_show(GTK_WIDGET(self->users.label)); } diff --git a/src/session-dbus.c b/src/session-dbus.c index fa9ea54..9aa75ef 100644 --- a/src/session-dbus.c +++ b/src/session-dbus.c @@ -5,6 +5,7 @@ Copyright 2010 Canonical Ltd. Authors: Ted Gould <ted@canonical.com> + Conor Curran <conor.curran@canonical.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published @@ -28,7 +29,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include "session-dbus.h" #include "dbus-shared-names.h" -static GVariant * get_icon (SessionDbus * service); +static GVariant * get_users_real_name (SessionDbus * service); static void bus_get_cb (GObject * object, GAsyncResult * res, gpointer user_data); 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); @@ -37,6 +38,7 @@ static void bus_method_call (GDBusConnection * connection, const gchar * sender, typedef struct _SessionDbusPrivate SessionDbusPrivate; struct _SessionDbusPrivate { gchar * name; + gboolean user_menu_is_visible; GDBusConnection * bus; GCancellable * bus_cancel; guint dbus_registration; @@ -98,10 +100,11 @@ session_dbus_init (SessionDbus *self) { SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(self); - priv->name = g_strdup(ICON_DEFAULT); + priv->name = NULL; priv->bus = NULL; priv->bus_cancel = NULL; priv->dbus_registration = 0; + priv->user_menu_is_visible = FALSE; priv->bus_cancel = g_cancellable_new(); g_bus_get(G_BUS_TYPE_SESSION, @@ -160,15 +163,20 @@ bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar * method, GVariant * params, GDBusMethodInvocation * invocation, gpointer user_data) { - SessionDbus * service = SESSION_DBUS(user_data); + SessionDbus * service = SESSION_DBUS (user_data); + SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE (service); + GVariant * retval = NULL; - if (g_strcmp0(method, "GetIcon") == 0) { - retval = get_icon(service); - } else { - g_warning("Calling method '%s' on the indicator service and it's unknown", method); + if (g_strcmp0(method, "GetUserRealName") == 0) { + retval = get_users_real_name (service); + } + else if (g_strcmp0 (method, "GetUserMenuVisibility") == 0){ + retval = g_variant_new ("(b)", priv->user_menu_is_visible); + } + else { + g_warning("Calling method '%s' on the indicator service and it's unknown", method); } - g_dbus_method_invocation_return_value(invocation, retval); return; } @@ -214,10 +222,10 @@ session_dbus_finalize (GObject *object) } static GVariant * -get_icon (SessionDbus * service) +get_users_real_name (SessionDbus * service) { SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(service); - return g_variant_new("(s)", priv->name); + return g_variant_new ("(s)", priv->name); } SessionDbus * @@ -229,29 +237,59 @@ session_dbus_new (void) void session_dbus_set_name (SessionDbus * session, const gchar * name) { +} + +void +session_dbus_set_users_real_name (SessionDbus * session, const gchar * name) +{ SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(session); GError * error = NULL; if (priv->name != NULL) { g_free(priv->name); priv->name = NULL; } + priv->name = g_strdup(name); if (priv->bus != NULL) { g_dbus_connection_emit_signal (priv->bus, - NULL, - INDICATOR_SESSION_SERVICE_DBUS_OBJECT, - INDICATOR_SESSION_SERVICE_DBUS_IFACE, - "IconUpdated", - g_variant_new ("(s)", priv->name, NULL), - &error); + NULL, + INDICATOR_SESSION_SERVICE_DBUS_OBJECT, + INDICATOR_SESSION_SERVICE_DBUS_IFACE, + "UserRealNameUpdated", + g_variant_new ("(s)", priv->name, NULL), + &error); if (error != NULL) { - g_warning("Unable to send IconUpdated signal: %s", error->message); + g_warning("Unable to send UserRealNameUpdated signal: %s", error->message); g_error_free(error); return; } } - return; } + +void +session_dbus_set_user_menu_visibility (SessionDbus* session, + gboolean visible) +{ + SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(session); + GError * error = NULL; + + priv->user_menu_is_visible = visible; + + if (priv->bus != NULL) { + g_dbus_connection_emit_signal (priv->bus, + NULL, + INDICATOR_SESSION_SERVICE_DBUS_OBJECT, + INDICATOR_SESSION_SERVICE_DBUS_IFACE, + "UserMenuIsVisible", + g_variant_new ("(b)", priv->user_menu_is_visible), + &error); + + if (error != NULL) { + g_warning("Unable to send UserMenuIsVisible signal: %s", error->message); + g_error_free(error); + } + } +} diff --git a/src/session-dbus.h b/src/session-dbus.h index 792917b..45ebae2 100644 --- a/src/session-dbus.h +++ b/src/session-dbus.h @@ -48,7 +48,9 @@ struct _SessionDbus { GType session_dbus_get_type (void); SessionDbus * session_dbus_new (void); -void session_dbus_set_name (SessionDbus * session, const gchar * name); +void session_dbus_set_name (SessionDbus * session, const gchar * name); +void session_dbus_set_users_real_name (SessionDbus * session, const gchar * name); +void session_dbus_set_user_menu_visibility (SessionDbus* session, gboolean visible); G_END_DECLS diff --git a/src/session-dbus.xml b/src/session-dbus.xml index ee724f5..f496ff1 100644 --- a/src/session-dbus.xml +++ b/src/session-dbus.xml @@ -2,14 +2,17 @@ <node name="/com/canonical/indicator/session/service"> <interface name="com.canonical.indicator.session.service"> - <!-- Icon --> - <method name="GetIcon"> + <method name="GetUserRealName"> <arg name="name" direction="out" type="s"/> </method> - - <signal name="IconUpdated"> + <method name="GetUserMenuVisibility"> + <arg name="update" direction="out" type="b"/> + </method> + <signal name="UserRealNameUpdated"> <arg name="name" type="s"/> </signal> - + <signal name="UserMenuIsVisible"> + <arg name="update" type="b"/> + </signal> </interface> </node> diff --git a/src/session-service.c b/src/session-service.c index dfc3805..fb6ce37 100644 --- a/src/session-service.c +++ b/src/session-service.c @@ -8,6 +8,7 @@ Authors: Ted Gould <ted@canonical.com> Christoph Korn <c_korn@gmx.de> Cody Russell <crussell@canonical.com> + Conor Curran <conor.curran@canonical.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published @@ -76,7 +77,9 @@ static SessionDbus *session_dbus = NULL; static DbusmenuMenuitem *lock_menuitem = NULL; static DbusmenuMenuitem *switch_menuitem = NULL; -static DbusmenuMenuitem * root_menuitem = NULL; +static DbusmenuMenuitem * session_root_menuitem = NULL; +static DbusmenuMenuitem * users_root_menuitem = NULL; + static GMainLoop * mainloop = NULL; static DBusGProxy * up_main_proxy = NULL; static DBusGProxy * up_prop_proxy = NULL; @@ -97,7 +100,9 @@ static gboolean allow_suspend = TRUE; static GConfClient * gconf_client = NULL; -static void rebuild_items (DbusmenuMenuitem *root, UsersServiceDbus *service); +static void rebuild_session_items (DbusmenuMenuitem *root, UsersServiceDbus *service); +static void rebuild_user_items (DbusmenuMenuitem *root, UsersServiceDbus *service); +static void activate_online_accounts (DbusmenuMenuitem *mi, guint timestamp, gpointer user_data); static void lockdown_changed (GConfClient *client, @@ -113,7 +118,7 @@ lockdown_changed (GConfClient *client, } if (g_strcmp0 (key, LOCKDOWN_KEY_USER) == 0 || g_strcmp0 (key, LOCKDOWN_KEY_SCREENSAVER) == 0) { - rebuild_items(root_menuitem, dbus_interface); + rebuild_session_items(session_root_menuitem, dbus_interface); } return; @@ -138,7 +143,6 @@ keybinding_changed (GConfClient *client, dbusmenu_menuitem_property_set_shortcut_string(lock_menuitem, gconf_value_get_string(value)); } } - return; } @@ -156,7 +160,7 @@ ensure_gconf_client (void) gconf_client_add_dir(gconf_client, KEYBINDING_DIR, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); gconf_client_notify_add(gconf_client, KEYBINDING_DIR, keybinding_changed, NULL, NULL, NULL); } - return; + return; } /* Check to see if the lockdown key is protecting from @@ -224,7 +228,7 @@ suspend_prop_cb (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata) gboolean local_can_suspend = g_value_get_boolean(&candoit); if (local_can_suspend != can_suspend) { can_suspend = local_can_suspend; - rebuild_items(root_menuitem, dbus_interface); + rebuild_session_items(session_root_menuitem, dbus_interface); } return; @@ -249,7 +253,7 @@ hibernate_prop_cb (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata) gboolean local_can_hibernate = g_value_get_boolean(&candoit); if (local_can_hibernate != can_hibernate) { can_hibernate = local_can_hibernate; - rebuild_items(root_menuitem, dbus_interface); + rebuild_session_items(session_root_menuitem, dbus_interface); } return; @@ -310,7 +314,7 @@ allowed_cb (DBusGProxy *proxy, gboolean OUT_allowed, GError *error, gpointer use if (OUT_allowed != *can_do) { *can_do = OUT_allowed; - rebuild_items (root_menuitem, dbus_interface); + rebuild_session_items (session_root_menuitem, dbus_interface); } } @@ -387,32 +391,6 @@ show_dialog (DbusmenuMenuitem * mi, guint timestamp, gchar * type) return; } -/* Checks to see if we should show the guest session item */ -static gboolean -check_guest_session (void) -{ - if (geteuid() < 500) { - /* System users shouldn't have guest account shown. Mosly - this would be the case of the guest user itself. */ - return FALSE; - } - // FIXME: Ask DisplayManager - - return TRUE; -} - -/* Called when someone clicks on the guest session item. */ -static void -activate_guest_session (DbusmenuMenuitem * mi, guint timestamp, gpointer user_data) -{ - lock_if_possible(); - - if (!users_service_dbus_activate_guest_session(USERS_SERVICE_DBUS(user_data))) - g_warning("Unable to activate guest session"); - - return; -} - /* Checks to see if we can create sessions */ static gboolean check_new_session (void) @@ -463,49 +441,16 @@ compare_users_by_username (const gchar *a, return retval; } -/* Take a desktop file and execute it */ -static void -desktop_activate_cb (DbusmenuMenuitem * mi, guint timestamp, gpointer data) -{ - GAppInfo * appinfo = G_APP_INFO(data); - g_return_if_fail(appinfo != NULL); - g_app_info_launch(appinfo, NULL, NULL, NULL); - return; -} - -/* Look at the GAppInfo structures and sort based on - the application names */ -static gint -sort_app_infos (gconstpointer a, gconstpointer b) -{ - GAppInfo * appa = G_APP_INFO(a); - GAppInfo * appb = G_APP_INFO(b); - - const gchar * namea = NULL; - const gchar * nameb = NULL; - - if (appa != NULL) { - namea = g_app_info_get_name(appa); - } - - if (appb != NULL) { - nameb = g_app_info_get_name(appb); - } - - return g_strcmp0(namea, nameb); -} - /* Builds up the menu for us */ -static void -rebuild_items (DbusmenuMenuitem *root, - UsersServiceDbus *service) +static void +rebuild_user_items (DbusmenuMenuitem *root, + UsersServiceDbus *service) { DbusmenuMenuitem *mi = NULL; - DbusmenuMenuitem * guest_mi = NULL; + DbusmenuMenuitem *guest_mi = NULL; GList *u; UserData *user; gboolean can_activate; - gboolean can_lockscreen; GList *children; /* Make sure we have a valid GConf client, and build one @@ -515,17 +460,163 @@ rebuild_items (DbusmenuMenuitem *root, /* Check to see which menu items we're allowed to have */ can_activate = users_service_dbus_can_activate_session (service) && !gconf_client_get_bool (gconf_client, LOCKDOWN_KEY_USER, NULL); - can_lockscreen = !gconf_client_get_bool (gconf_client, LOCKDOWN_KEY_SCREENSAVER, NULL); /* Remove the old menu items if that makes sense */ children = dbusmenu_menuitem_take_children (root); g_list_foreach (children, (GFunc)g_object_unref, NULL); g_list_free (children); + /* Set to NULL just incase we don't end up building one */ + users_service_dbus_set_guest_item(service, NULL); + + /* Build all of the user switching items */ + if (can_activate == TRUE) + { + if (check_new_session ()){ + switch_menuitem = dbusmenu_menuitem_new (); + dbusmenu_menuitem_property_set (switch_menuitem, + DBUSMENU_MENUITEM_PROP_TYPE, + MENU_SWITCH_TYPE); + dbusmenu_menuitem_property_set (switch_menuitem, + MENU_SWITCH_USER, + g_get_user_name()); + dbusmenu_menuitem_child_append (root, switch_menuitem); + g_signal_connect (G_OBJECT (switch_menuitem), + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK (activate_new_session), + service); + } + + GList * users = NULL; + users = users_service_dbus_get_user_list (service); + guint user_count = g_list_length(users); + // g_debug ("USER COUNT = %i", user_count); + // We only want to show this menu when we have more than one registered + // user + session_dbus_set_user_menu_visibility (session_dbus, user_count > 1); + + if (user_count > MINIMUM_USERS && user_count < MAXIMUM_USERS) { + users = g_list_sort (users, (GCompareFunc)compare_users_by_username); + } + + for (u = users; u != NULL; u = g_list_next (u)) { + user = u->data; + user->service = service; + + g_debug ("%i %s", (gint)user->uid, user->user_name); + + if (g_strcmp0(user->user_name, "guest") == 0) { + /* Check to see if the guest has sessions and so therefore should + get a check mark. */ + if (user->sessions != NULL) { + dbusmenu_menuitem_property_set_bool (guest_mi, + USER_ITEM_PROP_LOGGED_IN, + TRUE); + } + /* If we're showing user accounts, keep going through the list */ + if (user_count > MINIMUM_USERS && user_count < MAXIMUM_USERS) { + continue; + } + /* If not, we can stop here */ + break; + } + + if (user_count > MINIMUM_USERS && user_count < MAXIMUM_USERS) { + mi = dbusmenu_menuitem_new (); + dbusmenu_menuitem_property_set (mi, DBUSMENU_MENUITEM_PROP_TYPE, USER_ITEM_TYPE); + if (user->real_name_conflict) { + gchar * conflictedname = g_strdup_printf("%s (%s)", user->real_name, user->user_name); + dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_NAME, conflictedname); + g_free(conflictedname); + } else { + dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_NAME, user->real_name); + } + dbusmenu_menuitem_property_set_bool (mi, + USER_ITEM_PROP_LOGGED_IN, + user->sessions != NULL); + if (user->icon_file != NULL && user->icon_file[0] != '\0') { + dbusmenu_menuitem_property_set(mi, USER_ITEM_PROP_ICON, user->icon_file); + } else { + dbusmenu_menuitem_property_set(mi, USER_ITEM_PROP_ICON, USER_ITEM_ICON_DEFAULT); + } + + gboolean logged_in = g_strcmp0 (user->user_name, g_get_user_name()) == 0; + dbusmenu_menuitem_property_set_bool (mi, + USER_ITEM_PROP_IS_CURRENT_USER, + logged_in); + if (logged_in == TRUE){ + g_debug ("about to set the users real name to %s for user %s", + user->real_name, user->user_name); + session_dbus_set_users_real_name (session_dbus, user->real_name); + } + + dbusmenu_menuitem_child_append (root, mi); + g_signal_connect (G_OBJECT (mi), + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK (activate_user_session), + user); + user->menuitem = mi; + } + } + g_list_free(users); + } + // Add the online accounts and separator + DbusmenuMenuitem * separator1 = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set (separator1, + DBUSMENU_MENUITEM_PROP_TYPE, + DBUSMENU_CLIENT_TYPES_SEPARATOR); + dbusmenu_menuitem_child_append (root, separator1); + DbusmenuMenuitem * online_accounts_item = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set (online_accounts_item, + DBUSMENU_MENUITEM_PROP_TYPE, + DBUSMENU_CLIENT_TYPES_DEFAULT); + dbusmenu_menuitem_property_set (online_accounts_item, + DBUSMENU_MENUITEM_PROP_LABEL, + _("Online Accounts...")); + + g_signal_connect (G_OBJECT (online_accounts_item), + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK (activate_online_accounts), + NULL); + + dbusmenu_menuitem_child_append (root, online_accounts_item); +} + +// TODO +// Wait until dialog is complete to find out name to pass +// to the control centre. +static void +activate_online_accounts (DbusmenuMenuitem *mi, + guint timestamp, + gpointer user_data) +{ + GError * error = NULL; + if (!g_spawn_command_line_async("gnome-control-center online-accounts", &error)) + { + g_warning("Unable to show control centre: %s", error->message); + g_error_free(error); + } +} + +static void +rebuild_session_items (DbusmenuMenuitem *root, + UsersServiceDbus *service) +{ + gboolean can_lockscreen; + + /* Make sure we have a valid GConf client, and build one + if needed */ + ensure_gconf_client (); + + can_lockscreen = !gconf_client_get_bool ( gconf_client, + LOCKDOWN_KEY_SCREENSAVER, + NULL); /* Lock screen item */ if (can_lockscreen) { lock_menuitem = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(lock_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _("Lock Screen")); + dbusmenu_menuitem_property_set (lock_menuitem, + DBUSMENU_MENUITEM_PROP_LABEL, + _("Lock Screen")); gchar * shortcut = gconf_client_get_string(gconf_client, KEY_LOCK_SCREEN, NULL); if (shortcut != NULL) { @@ -536,154 +627,93 @@ rebuild_items (DbusmenuMenuitem *root, g_debug("Unable to get lock screen shortcut."); } - g_signal_connect(G_OBJECT(lock_menuitem), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(lock_screen), NULL); + g_signal_connect (G_OBJECT(lock_menuitem), + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK(lock_screen), NULL); dbusmenu_menuitem_child_append(root, lock_menuitem); } - /* Set to NULL just incase we don't end up building one */ - users_service_dbus_set_guest_item(service, NULL); - - /* Build all of the user switching items */ - if (can_activate == TRUE) - { - if (can_lockscreen) { - DbusmenuMenuitem * separator1 = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(separator1, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - dbusmenu_menuitem_child_append(root, separator1); - } - - if (check_guest_session ()) - { - guest_mi = dbusmenu_menuitem_new (); - dbusmenu_menuitem_property_set (guest_mi, DBUSMENU_MENUITEM_PROP_TYPE, USER_ITEM_TYPE); - dbusmenu_menuitem_property_set (guest_mi, USER_ITEM_PROP_NAME, _("Guest Session")); - dbusmenu_menuitem_property_set_bool (guest_mi, USER_ITEM_PROP_LOGGED_IN, FALSE); - dbusmenu_menuitem_child_append (root, guest_mi); - g_signal_connect (G_OBJECT (guest_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_guest_session), service); - users_service_dbus_set_guest_item(service, guest_mi); - } - - if (check_new_session ()) - { - - switch_menuitem = dbusmenu_menuitem_new (); - dbusmenu_menuitem_property_set (switch_menuitem, DBUSMENU_MENUITEM_PROP_TYPE, MENU_SWITCH_TYPE); - dbusmenu_menuitem_property_set (switch_menuitem, MENU_SWITCH_USER, g_get_user_name()); - dbusmenu_menuitem_child_append (root, switch_menuitem); - g_signal_connect (G_OBJECT (switch_menuitem), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_new_session), service); - } - - GList * users = NULL; - users = users_service_dbus_get_user_list (service); - guint user_count = g_list_length(users); - - if (user_count > MINIMUM_USERS && user_count < MAXIMUM_USERS) { - users = g_list_sort (users, (GCompareFunc)compare_users_by_username); - } - - for (u = users; u != NULL; u = g_list_next (u)) { - user = u->data; - user->service = service; - - if (user->uid == getuid()) { - /* Hide me from the list */ - continue; - } - g_debug ("%li %s", user->uid, user->user_name); - - if (g_strcmp0(user->user_name, "guest") == 0) { - /* Check to see if the guest has sessions and so therefore should - get a check mark. */ - if (user->sessions != NULL) { - dbusmenu_menuitem_property_set_bool (guest_mi, USER_ITEM_PROP_LOGGED_IN, TRUE); - } - /* If we're showing user accounts, keep going through the list */ - if (user_count > MINIMUM_USERS && user_count < MAXIMUM_USERS) { - continue; - } - /* If not, we can stop here */ - break; - } - - if (user_count > MINIMUM_USERS && user_count < MAXIMUM_USERS) { - mi = dbusmenu_menuitem_new (); - dbusmenu_menuitem_property_set (mi, DBUSMENU_MENUITEM_PROP_TYPE, USER_ITEM_TYPE); - if (user->real_name_conflict) { - gchar * conflictedname = g_strdup_printf("%s (%s)", user->real_name, user->user_name); - dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_NAME, conflictedname); - g_free(conflictedname); - } else { - dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_NAME, user->real_name); - } - dbusmenu_menuitem_property_set_bool (mi, USER_ITEM_PROP_LOGGED_IN, user->sessions != NULL); - if (user->icon_file != NULL && user->icon_file[0] != '\0') { - dbusmenu_menuitem_property_set(mi, USER_ITEM_PROP_ICON, user->icon_file); - } else { - dbusmenu_menuitem_property_set(mi, USER_ITEM_PROP_ICON, USER_ITEM_ICON_DEFAULT); - } - dbusmenu_menuitem_child_append (root, mi); - g_signal_connect (G_OBJECT (mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_user_session), user); - user->menuitem = mi; - } - } - - g_list_free(users); - } - - /* If there were a bunch of items before us, we need a - separator. */ - if (can_lockscreen || can_activate) { - DbusmenuMenuitem * separator = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - dbusmenu_menuitem_child_append(root, separator); - } - /* Start going through the session based items. */ logout_mi = dbusmenu_menuitem_new(); if (supress_confirmations()) { - dbusmenu_menuitem_property_set(logout_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Log Out")); + dbusmenu_menuitem_property_set (logout_mi, + DBUSMENU_MENUITEM_PROP_LABEL, + _("Log Out")); } else { - dbusmenu_menuitem_property_set(logout_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Log Out\342\200\246")); + dbusmenu_menuitem_property_set (logout_mi, + DBUSMENU_MENUITEM_PROP_LABEL, + _("Log Out\342\200\246")); } - dbusmenu_menuitem_property_set_bool(logout_mi, DBUSMENU_MENUITEM_PROP_VISIBLE, show_logout()); + dbusmenu_menuitem_property_set_bool (logout_mi, + DBUSMENU_MENUITEM_PROP_VISIBLE, + show_logout()); dbusmenu_menuitem_child_append(root, logout_mi); - g_signal_connect(G_OBJECT(logout_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(show_dialog), "logout"); + g_signal_connect( G_OBJECT(logout_mi), + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK(show_dialog), "logout"); if (can_suspend && allow_suspend) { suspend_mi = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(suspend_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Suspend")); - dbusmenu_menuitem_child_append(root, suspend_mi); - g_signal_connect(G_OBJECT(suspend_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(machine_sleep), "Suspend"); + dbusmenu_menuitem_property_set (suspend_mi, + DBUSMENU_MENUITEM_PROP_LABEL, + _("Suspend")); + dbusmenu_menuitem_child_append (root, suspend_mi); + g_signal_connect( G_OBJECT(suspend_mi), + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK(machine_sleep), + "Suspend"); } if (can_hibernate && allow_hibernate) { hibernate_mi = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(hibernate_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Hibernate")); + dbusmenu_menuitem_property_set (hibernate_mi, + DBUSMENU_MENUITEM_PROP_LABEL, + _("Hibernate")); dbusmenu_menuitem_child_append(root, hibernate_mi); - g_signal_connect(G_OBJECT(hibernate_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(machine_sleep), "Hibernate"); + g_signal_connect (G_OBJECT(hibernate_mi), + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK(machine_sleep), "Hibernate"); } restart_mi = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(restart_mi, DBUSMENU_MENUITEM_PROP_TYPE, RESTART_ITEM_TYPE); + dbusmenu_menuitem_property_set (restart_mi, + DBUSMENU_MENUITEM_PROP_TYPE, + RESTART_ITEM_TYPE); if (supress_confirmations()) { - dbusmenu_menuitem_property_set(restart_mi, RESTART_ITEM_LABEL, _("Restart")); + dbusmenu_menuitem_property_set (restart_mi, + RESTART_ITEM_LABEL, + _("Restart")); } else { - dbusmenu_menuitem_property_set(restart_mi, RESTART_ITEM_LABEL, _("Restart\342\200\246")); + dbusmenu_menuitem_property_set (restart_mi, + RESTART_ITEM_LABEL, + _("Restart\342\200\246")); } - dbusmenu_menuitem_property_set_bool(restart_mi, DBUSMENU_MENUITEM_PROP_VISIBLE, show_restart()); + dbusmenu_menuitem_property_set_bool (restart_mi, + DBUSMENU_MENUITEM_PROP_VISIBLE, + show_restart()); dbusmenu_menuitem_child_append(root, restart_mi); - g_signal_connect(G_OBJECT(restart_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(show_dialog), "restart"); + g_signal_connect (G_OBJECT(restart_mi), + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK(show_dialog), "restart"); shutdown_mi = dbusmenu_menuitem_new(); if (supress_confirmations()) { - dbusmenu_menuitem_property_set(shutdown_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Shut Down")); + dbusmenu_menuitem_property_set (shutdown_mi, + DBUSMENU_MENUITEM_PROP_LABEL, + _("Shut Down")); } else { - dbusmenu_menuitem_property_set(shutdown_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Shut Down\342\200\246")); - } - dbusmenu_menuitem_property_set_bool(shutdown_mi, DBUSMENU_MENUITEM_PROP_VISIBLE, show_shutdown()); - dbusmenu_menuitem_child_append(root, shutdown_mi); - g_signal_connect(G_OBJECT(shutdown_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(show_dialog), "shutdown"); + dbusmenu_menuitem_property_set (shutdown_mi, + DBUSMENU_MENUITEM_PROP_LABEL, + _("Shut Down\342\200\246")); + } + dbusmenu_menuitem_property_set_bool (shutdown_mi, + DBUSMENU_MENUITEM_PROP_VISIBLE, + show_shutdown()); + dbusmenu_menuitem_child_append (root, shutdown_mi); + g_signal_connect (G_OBJECT(shutdown_mi), + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK(show_dialog), "shutdown"); RestartShutdownLogoutMenuItems * restart_shutdown_logout_mi = g_new0 (RestartShutdownLogoutMenuItems, 1); restart_shutdown_logout_mi->logout_mi = logout_mi; @@ -692,61 +722,6 @@ rebuild_items (DbusmenuMenuitem *root, update_menu_entries(restart_shutdown_logout_mi); - /* now add extra launchers */ - GDir *extra_launchers_dir; - extra_launchers_dir = g_dir_open (EXTRA_LAUNCHER_DIR, 0, NULL); - if (extra_launchers_dir != NULL) { - GList * launchers = NULL; - - /* Find all the desktop files we want to use */ - for (;;) { - const gchar *extra_launcher_file; - - extra_launcher_file = g_dir_read_name (extra_launchers_dir); - if (extra_launcher_file == NULL) - break; - if (!g_str_has_suffix (extra_launcher_file, ".desktop")) - continue; - - gchar *full_path = g_build_filename (EXTRA_LAUNCHER_DIR, extra_launcher_file, NULL); - GAppInfo * appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename (full_path)); - g_free (full_path); - - launchers = g_list_prepend(launchers, appinfo); - } - g_dir_close(extra_launchers_dir); - - /* Sort the desktop files based on their names */ - launchers = g_list_sort(launchers, sort_app_infos); - - /* Turn each one into a separate menu item */ - GList * launcher = NULL; - gboolean sepadded = FALSE; - for (launcher = launchers; launcher != NULL; launcher = g_list_next(launcher)) { - GAppInfo * appinfo = G_APP_INFO(launcher->data); - - /* Make sure we have a separator */ - if (!sepadded) { - DbusmenuMenuitem * separator = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - dbusmenu_menuitem_child_append(root, separator); - g_object_unref(separator); - sepadded = TRUE; - } - - /* Build the item */ - DbusmenuMenuitem * desktop_mi = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(desktop_mi, DBUSMENU_MENUITEM_PROP_LABEL, g_app_info_get_name(appinfo)); - g_signal_connect(G_OBJECT(desktop_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(desktop_activate_cb), appinfo); - g_object_weak_ref(G_OBJECT(desktop_mi), (GWeakNotify)g_object_unref, appinfo); - - /* Put into the menu */ - dbusmenu_menuitem_child_append(root, desktop_mi); - } - - g_list_free(launchers); - } - return; } @@ -758,7 +733,7 @@ user_change (UsersServiceDbus *service, gpointer user_data) { DbusmenuMenuitem *root = (DbusmenuMenuitem *)user_data; - rebuild_items (root, service); + rebuild_user_items (root, service); return; } @@ -802,7 +777,6 @@ restart_dir_changed (void) session_dbus_set_name(session_dbus, ICON_DEFAULT); } } - return; } @@ -826,7 +800,7 @@ setup_restart_watch (void) int main (int argc, char ** argv) { - g_type_init(); + g_type_init(); /* Setting up i18n and gettext. Apparently, we need all of these. */ @@ -834,42 +808,47 @@ main (int argc, char ** argv) bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain (GETTEXT_PACKAGE); - IndicatorService * service = indicator_service_new_version(INDICATOR_SESSION_DBUS_NAME, - INDICATOR_SESSION_DBUS_VERSION); + IndicatorService * service = indicator_service_new_version (INDICATOR_SESSION_DBUS_NAME, + INDICATOR_SESSION_DBUS_VERSION); g_signal_connect(G_OBJECT(service), - INDICATOR_SERVICE_SIGNAL_SHUTDOWN, - G_CALLBACK(service_shutdown), NULL); + INDICATOR_SERVICE_SIGNAL_SHUTDOWN, + G_CALLBACK(service_shutdown), NULL); session_dbus = session_dbus_new(); g_idle_add(lock_screen_setup, NULL); - root_menuitem = dbusmenu_menuitem_new(); - g_debug("Root ID: %d", dbusmenu_menuitem_get_id(root_menuitem)); - - dbus_interface = g_object_new (USERS_SERVICE_DBUS_TYPE, NULL); - - rebuild_items (root_menuitem, dbus_interface); - - g_signal_connect (G_OBJECT (dbus_interface), - "user-added", - G_CALLBACK (user_change), - root_menuitem); - g_signal_connect (G_OBJECT (dbus_interface), - "user-deleted", - G_CALLBACK (user_change), - root_menuitem); - - setup_restart_watch(); + session_root_menuitem = dbusmenu_menuitem_new(); + g_debug("Session Root ID: %d", dbusmenu_menuitem_get_id(session_root_menuitem)); + + dbus_interface = g_object_new (USERS_SERVICE_DBUS_TYPE, NULL); + + rebuild_session_items (session_root_menuitem, dbus_interface); + + DbusmenuServer * server = dbusmenu_server_new(INDICATOR_SESSION_DBUS_OBJECT); + dbusmenu_server_set_root(server, session_root_menuitem); + + users_root_menuitem = dbusmenu_menuitem_new(); + rebuild_user_items (users_root_menuitem, dbus_interface); + g_signal_connect (G_OBJECT (dbus_interface), + "user-added", + G_CALLBACK (user_change), + users_root_menuitem); + g_signal_connect (G_OBJECT (dbus_interface), + "user-removed", + G_CALLBACK (user_change), + users_root_menuitem); + + setup_restart_watch(); setup_up(); - DbusmenuServer * server = dbusmenu_server_new(INDICATOR_SESSION_DBUS_OBJECT); - dbusmenu_server_set_root(server, root_menuitem); - - mainloop = g_main_loop_new(NULL, FALSE); - g_main_loop_run(mainloop); + DbusmenuServer * users_server = dbusmenu_server_new (INDICATOR_USERS_DBUS_OBJECT); + dbusmenu_server_set_root (users_server, users_root_menuitem); - return 0; + mainloop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(mainloop); + + return 0; } diff --git a/src/user-widget.c b/src/user-widget.c new file mode 100644 index 0000000..9b046c5 --- /dev/null +++ b/src/user-widget.c @@ -0,0 +1,341 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran <conor.curran@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <glib.h> +#include <libindicator/indicator-image-helper.h> +#include "user-widget.h" +#include "dbus-shared-names.h" + + +typedef struct _UserWidgetPrivate UserWidgetPrivate; + +struct _UserWidgetPrivate +{ + DbusmenuMenuitem* twin_item; + GtkWidget* user_image; + GtkWidget* user_name; + GtkWidget* container; + GtkWidget* tick_icon; + gboolean logged_in; + gboolean sessions_active; +}; + +#define USER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USER_WIDGET_TYPE, UserWidgetPrivate)) + +/* Prototypes */ +static void user_widget_class_init (UserWidgetClass *klass); +static void user_widget_init (UserWidget *self); +static void user_widget_dispose (GObject *object); +static void user_widget_finalize (GObject *object); + +static void user_widget_set_twin_item (UserWidget* self, + DbusmenuMenuitem* twin_item); +// keyevent consumers +static gboolean user_widget_button_release_event (GtkWidget *menuitem, + GdkEventButton *event); +// Dbusmenuitem properties update callback +static void user_widget_property_update (DbusmenuMenuitem* item, + gchar* property, + GVariant* value, + gpointer userdata); +#if GTK_CHECK_VERSION(3, 0, 0) +static gboolean user_widget_primitive_draw_cb_gtk_3 (GtkWidget *image, + cairo_t* cr, + gpointer user_data); +#else +static gboolean user_widget_primitive_draw_cb (GtkWidget *image, + GdkEventExpose *event, + gpointer user_data); +#endif + +G_DEFINE_TYPE (UserWidget, user_widget, GTK_TYPE_MENU_ITEM); + +static void +user_widget_class_init (UserWidgetClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + widget_class->button_release_event = user_widget_button_release_event; + + g_type_class_add_private (klass, sizeof (UserWidgetPrivate)); + + gobject_class->dispose = user_widget_dispose; + gobject_class->finalize = user_widget_finalize; +} + +static void +user_widget_init (UserWidget *self) +{ + UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(self); + + gint padding = 0; + gtk_widget_style_get (GTK_WIDGET(self), + "horizontal-padding", + &padding, + NULL); + + priv->user_image = NULL; + priv->user_name = NULL; + priv->logged_in = FALSE; + priv->sessions_active = FALSE; + priv->container = NULL; + priv->tick_icon = NULL; + + // Create the UI elements. + priv->user_image = gtk_image_new (); + + // Just for now set the image to the default avator image + GdkPixbuf* pixbuf = NULL; + GError* error = NULL; + pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), + "avatar-default", + 32, + GTK_ICON_LOOKUP_FORCE_SIZE, + &error); + + if (pixbuf == NULL || error != NULL) { + g_warning ("Could not load the default avatar image for some reason"); + } + else{ + gtk_image_set_from_pixbuf (GTK_IMAGE(priv->user_image), pixbuf); + g_object_unref (pixbuf); + } + + priv->user_name = gtk_label_new (""); + priv->container = gtk_hbox_new (FALSE, 0); + // TODO: + // Delete tick icon and draw primitively. + priv->tick_icon = gtk_image_new_from_icon_name ("account-logged-in", + GTK_ICON_SIZE_MENU); + gtk_misc_set_alignment(GTK_MISC(priv->tick_icon), 1.0, 0.5); + + // Pack it together + gtk_box_pack_start (GTK_BOX (priv->container), + priv->user_image, + FALSE, + FALSE, + 0); + gtk_box_pack_start (GTK_BOX (priv->container), + priv->user_name, + FALSE, + FALSE, + 3); + gtk_box_pack_start (GTK_BOX(priv->container), + priv->tick_icon, + FALSE, + FALSE, 5); + + gtk_widget_show_all (priv->container); + gtk_container_add (GTK_CONTAINER (self), priv->container); + + // Fetch the drawing context. + #if GTK_CHECK_VERSION(3, 0, 0) + g_signal_connect_after (GTK_WIDGET(self), "draw", + G_CALLBACK(user_widget_primitive_draw_cb_gtk_3), + GTK_WIDGET(self)); + #else + g_signal_connect_after (GTK_WIDGET(self), "expose-event", + G_CALLBACK(user_widget_primitive_draw_cb), + GTK_WIDGET(self)); + #endif +} + +static void +user_widget_dispose (GObject *object) +{ + //UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(USER_WIDGET(object)); + + G_OBJECT_CLASS (user_widget_parent_class)->dispose (object); +} + +// TODO tidy up image and name +static void +user_widget_finalize (GObject *object) +{ + G_OBJECT_CLASS (user_widget_parent_class)->finalize (object); +} + +/** + * We override the expose method to enable primitive drawing of the + * empty album art image and rounded rectangles on the album art. + */ + +#if GTK_CHECK_VERSION(3, 0, 0) + +// Draw the radio dot and/or green check mark +// TODO handle drawing of green check mark +static gboolean +user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, + cairo_t* cr, + gpointer user_data) +{ + + g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE); + UserWidget* meta = USER_WIDGET(user_data); + UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta); + + // Draw dot only when user is the current user. + if (!dbusmenu_menuitem_property_get_bool (priv->twin_item, + USER_ITEM_PROP_IS_CURRENT_USER)){ + return FALSE; + } + + GtkStyle *style; + gdouble x, y; + gdouble offset = 15.0; + + style = gtk_widget_get_style (widget); + + GtkAllocation allocation; + gtk_widget_get_allocation (widget, &allocation); + x = allocation.x + 13; + y = offset; + + cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI);; + + cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, + style->fg[gtk_widget_get_state(widget)].green/65535.0, + style->fg[gtk_widget_get_state(widget)].blue/65535.0); + cairo_fill (cr); + + return FALSE; +} + +// GTK 2 Expose handler +#else + +// Draw the triangle if the player is running ... +static gboolean +user_widget_primitive_draw_cb (GtkWidget *widget, + GdkEventExpose *event, + gpointer user_data) +{ + /* + g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE); + UserWidget* meta = USER_WIDGET(user_data); + UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta); + + GtkStyle *style; + cairo_t *cr; + int x, y, arrow_width, arrow_height; + + gint offset = 3; + arrow_width = 5; + arrow_height = 9; + + style = gtk_widget_get_style (widget); + + cr = (cairo_t*) gdk_cairo_create (gtk_widget_get_window (widget)); + + GtkAllocation allocation; + gtk_widget_get_allocation (widget, &allocation); + x = allocation.x; + y = allocation.y; + + // Draw player icon + if (priv->icon_buf != NULL){ + gdk_cairo_set_source_pixbuf (cr, + priv->icon_buf, + x + arrow_width + 1, + y + offset); + cairo_paint (cr); + } + + // Draw triangle but only if the player is running. + if (dbusmenu_menuitem_property_get_bool (priv->twin_item, + DBUSMENU_METADATA_MENUITEM_PLAYER_RUNNING)){ + y += (double)arrow_height/2.0 + offset; + cairo_set_line_width (cr, 1.0); + + cairo_move_to (cr, x, y); + cairo_line_to (cr, x, y + arrow_height); + cairo_line_to (cr, x + arrow_width, y + (double)arrow_height/2.0); + cairo_close_path (cr); + cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, + style->fg[gtk_widget_get_state(widget)].green/65535.0, + style->fg[gtk_widget_get_state(widget)].blue/65535.0); + cairo_fill (cr); + } + + cairo_destroy (cr);*/ + return FALSE; +} +#endif + + +/* Suppress/consume keyevents */ +static gboolean +user_widget_button_release_event (GtkWidget *menuitem, + GdkEventButton *event) +{ + return FALSE; +} + +static void +user_widget_property_update (DbusmenuMenuitem* item, gchar* property, + GVariant* value, gpointer userdata) +{ + g_return_if_fail (IS_USER_WIDGET (userdata)); + //gtk_widget_queue_redraw (GTK_WIDGET(userdata)); +} + + +static void +user_widget_set_twin_item (UserWidget* self, + DbusmenuMenuitem* twin_item) +{ + UserWidgetPrivate* priv = USER_WIDGET_GET_PRIVATE(self); + priv->twin_item = twin_item; + g_signal_connect( G_OBJECT(priv->twin_item), "property-changed", + G_CALLBACK(user_widget_property_update), self); + + const gchar * icon_name = dbusmenu_menuitem_property_get (twin_item, + USER_ITEM_PROP_ICON); + gtk_label_set_label (GTK_LABEL (priv->user_name), + dbusmenu_menuitem_property_get (twin_item, USER_ITEM_PROP_NAME)); + + //if (dbusmenu_menuitem_property_get_bool (twin_item, USER_ITEM_PROP_LOGGED_IN)) { + // gtk_widget_show(priv->tick_icon); + //} else { + gtk_widget_show(priv->tick_icon); + //} + + g_debug("Using user icon for '%s' from file: %s", + dbusmenu_menuitem_property_get(twin_item, USER_ITEM_PROP_NAME), icon_name); + +} + + /** + * transport_new: + * @returns: a new #UserWidget. + **/ +GtkWidget* +user_widget_new(DbusmenuMenuitem *item) +{ + GtkWidget* widget = g_object_new(USER_WIDGET_TYPE, NULL); + user_widget_set_twin_item ( USER_WIDGET(widget), item ); + return widget; +} diff --git a/src/user-widget.h b/src/user-widget.h new file mode 100644 index 0000000..e1f6d1a --- /dev/null +++ b/src/user-widget.h @@ -0,0 +1,54 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran <conor.curran@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef __USER_WIDGET_H__ +#define __USER_WIDGET_H__ + +#include <gtk/gtk.h> +#if GTK_CHECK_VERSION(3, 0, 0) +#include <libdbusmenu-gtk3/menuitem.h> +#else +#include <libdbusmenu-gtk/menuitem.h> +#endif + +G_BEGIN_DECLS + +#define USER_WIDGET_TYPE (user_widget_get_type ()) +#define USER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), USER_WIDGET_TYPE, UserWidget)) +#define USER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), USER_WIDGET_TYPE, UserWidgetClass)) +#define IS_USER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), USER_WIDGET_TYPE)) +#define IS_USER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), USER_WIDGET_TYPE)) +#define USER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), USER_WIDGET_TYPE, UserWidgetClass)) + +typedef struct _UserWidget UserWidget; +typedef struct _UserWidgetClass UserWidgetClass; + +struct _UserWidgetClass { + GtkMenuItemClass parent_class; +}; + +struct _UserWidget { + GtkMenuItem parent; +}; + +GType user_widget_get_type (void); +GtkWidget* user_widget_new(DbusmenuMenuitem *twin_item); + +G_END_DECLS + +#endif |