aboutsummaryrefslogtreecommitdiff
path: root/src/indicator-session.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/indicator-session.c')
-rw-r--r--src/indicator-session.c148
1 files changed, 144 insertions, 4 deletions
diff --git a/src/indicator-session.c b/src/indicator-session.c
index dda8c76..a97eb95 100644
--- a/src/indicator-session.c
+++ b/src/indicator-session.c
@@ -22,6 +22,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <glib.h>
#include <glib-object.h>
+#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <libdbusmenu-gtk/menu.h>
@@ -33,6 +34,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <libindicator/indicator-service-manager.h>
#include "dbus-shared-names.h"
+#include "dbusmenu-shared.h"
#define INDICATOR_SESSION_TYPE (indicator_session_get_type ())
#define INDICATOR_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SESSION_TYPE, IndicatorSession))
@@ -51,6 +53,8 @@ struct _IndicatorSessionClass {
struct _IndicatorSession {
IndicatorObject parent;
IndicatorServiceManager * service;
+ GtkImage * status_image;
+ DbusmenuGtkMenu * menu;
};
GType indicator_session_get_type (void);
@@ -63,6 +67,8 @@ INDICATOR_SET_TYPE(INDICATOR_SESSION_TYPE)
static GtkLabel * get_label (IndicatorObject * io);
static GtkImage * get_icon (IndicatorObject * io);
static GtkMenu * get_menu (IndicatorObject * io);
+static gboolean build_menu_switch (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
+static gboolean new_user_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
static void indicator_session_class_init (IndicatorSessionClass *klass);
static void indicator_session_init (IndicatorSession *self);
@@ -96,6 +102,13 @@ indicator_session_init (IndicatorSession *self)
/* Now let's fire these guys up. */
self->service = indicator_service_manager_new_version(INDICATOR_SESSION_DBUS_NAME, INDICATOR_SESSION_DBUS_VERSION);
+ self->status_image = GTK_IMAGE(gtk_image_new_from_icon_name("system-shutdown-panel", GTK_ICON_SIZE_MENU));
+ 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);
+
return;
}
@@ -130,9 +143,37 @@ get_label (IndicatorObject * io)
static GtkImage *
get_icon (IndicatorObject * io)
{
- GtkImage * status_image = GTK_IMAGE(gtk_image_new_from_icon_name("system-shutdown-panel", GTK_ICON_SIZE_MENU));
- gtk_widget_show(GTK_WIDGET(status_image));
- return status_image;
+ gtk_widget_show(GTK_WIDGET(INDICATOR_SESSION(io)->status_image));
+ return INDICATOR_SESSION(io)->status_image;
+}
+
+/* Builds an item with a hip little logged in icon. */
+static gboolean
+new_user_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
+{
+ GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new());
+ GtkWidget * hbox = gtk_hbox_new(FALSE, 0);
+
+ 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);
+ }
+
+ gtk_container_add(GTK_CONTAINER(gmi), hbox);
+ gtk_widget_show(hbox);
+
+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
+
+ return TRUE;
}
/* Indicator based function to get the menu for the whole
@@ -141,7 +182,106 @@ get_icon (IndicatorObject * io)
static GtkMenu *
get_menu (IndicatorObject * io)
{
- return GTK_MENU(dbusmenu_gtkmenu_new(INDICATOR_SESSION_DBUS_NAME, INDICATOR_SESSION_DBUS_OBJECT));
+ return GTK_MENU(INDICATOR_SESSION(io)->menu);
}
+static void
+switch_property_change (DbusmenuMenuitem * item, const gchar * property, const GValue * value, 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;
+
+ /* 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 (value == NULL || g_value_get_string(value) == NULL || g_value_get_string(value)[0] == '\0') {
+ finalstring = _("Switch User...");
+ set_ellipsize = FALSE;
+ }
+
+ if (finalstring == NULL) {
+ const gchar * username = g_value_get_string(value);
+ 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_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);
+
+ /* 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);
+ }
+ }
+
+ return;
+}
+
+static const gchar * dbusmenu_item_data = "dbusmenu-item";
+
+/* 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)
+{
+ DbusmenuGtkClient * client = DBUSMENU_GTKCLIENT(user_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_value(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)
+{
+ 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);
+
+ 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_value(newitem, MENU_SWITCH_USER), client);
+
+ return TRUE;
+}