lightdm-gtk-greeter-team team mailing list archive
-
lightdm-gtk-greeter-team team
-
Mailing list archive
-
Message #00649
[Merge] lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/panel-items-options into lp:lightdm-gtk-greeter
Andrew P. has proposed merging lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/panel-items-options into lp:lightdm-gtk-greeter.
Requested reviews:
LightDM Gtk+ Greeter Development Team (lightdm-gtk-greeter-team)
For more details, see:
https://code.launchpad.net/~lightdm-gtk-greeter-team/lightdm-gtk-greeter/panel-items-options/+merge/239666
Moving all panel related code to GreeterMenuBar. Reviewing all indicators related code. Can cause some new bugs.
Greeter control panel items with set of greeter_menu_bar_set_item_{text|image|tooltip} functions and know nothing about actual items appearance.
Each panel item can be customized. format:
indicators = itemA: option1=value1, option2=value2; itemB: ...
Common options:
text = any text
Add label to item. Using option without value just add label and do not override indicator text if it's present. http://imgur.com/a/Xtuhs#7
markup = any text
Replace "text" option value and mark it as markup.
"~power: markup=value" is equivalent to "~power: text=value, markup"
http://imgur.com/a/Xtuhs#4
image = /path/to/file or #icon-name
Logic is identical to "text"
http://imgur.com/a/Xtuhs#5
fallback-image = /path/to/file or #icon-name
What image to use if set_item_image failed (default image for "~session" indicator).
layout = text|image|text|image|image-text
Specify child widgets order for item.
http://imgur.com/a/Xtuhs#6
~power item options:
hide-disbale=true|false (using without value is equivalent to "true")
Hide disabled actions instead of changing sensitivity.
http://imgur.com/a/Xtuhs#3
~clock options:
clock-format = format
Replacement for "clock-format" key.
Another changes:
Valid "scrolled" signal for IndicatorObject
Clock font weight move to CSS
Using g_date_time_format() instead of strftime()
Some GreeterBackground fixes
"show-indicators" is not supported now
--
https://code.launchpad.net/~lightdm-gtk-greeter-team/lightdm-gtk-greeter/panel-items-options/+merge/239666
Your team LightDM Gtk+ Greeter Development Team is requested to review the proposed merge of lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/panel-items-options into lp:lightdm-gtk-greeter.
=== modified file 'configure.ac'
--- configure.ac 2014-08-10 12:48:13 +0000
+++ configure.ac 2014-10-26 18:59:04 +0000
@@ -95,6 +95,15 @@
AC_DEFINE([START_INDICATOR_SERVICES], [], [Try to start indicator-services])
])
+AC_ARG_ENABLE([at-spi],
+ AC_HELP_STRING([--enable-at-spi], [Try to start at-spi launcher])
+ AC_HELP_STRING([--disable-at-spi], [Do not start at-spi launcher]),
+ [], [enable_at_spi=no])
+
+AS_IF([test "x$enable_at_spi" != "xno"], [
+ AC_DEFINE([START_AT_SPI], [], [Try to start at-spi launcher])
+])
+
AC_ARG_WITH([libxklavier], AS_HELP_STRING([--with-libxklavier], [Use libxklavier to manage layouts (instead of LightDM API)]))
AS_IF([test "x$with_libxklavier" = "xyes"],
=== modified file 'data/lightdm-gtk-greeter.conf'
--- data/lightdm-gtk-greeter.conf 2014-08-09 17:31:35 +0000
+++ data/lightdm-gtk-greeter.conf 2014-10-26 18:59:04 +0000
@@ -9,8 +9,7 @@
# xft-dpi = Resolution for Xft in dots per inch (e.g. 96)
# xft-hintstyle = What degree of hinting to use (none, slight, medium, or hintfull)
# xft-rgba = Type of subpixel antialiasing (none, rgb, bgr, vrgb or vbgr)
-# show-indicators = semi-colon ";" separated list of allowed indicator modules. Built-in indicators include "~a11y", "~language", "~session", "~power". Unity indicators can be represented by short name (e.g. "sound", "power"), service file name, or absolute path
-# show-clock (true or false)
+# indicators = semi-colon ";" separated list of allowed indicator modules. Built-in indicators include "~a11y", "~language", "~session", "~power". Unity indicators can be represented by short name (e.g. "sound", "power"), service file name, or absolute path
# clock-format = strftime-format string, e.g. %H:%M
# keyboard = command to launch on-screen keyboard (e.g. onboard)
# reader = command to launch screen reader (e.g. orca)
@@ -20,12 +19,21 @@
# hide-user-image = true|false, false by default
# screensaver-timeout = Timeout (in seconds) until the screen blanks when the greeter is called as lockscreen
#
+# Extended "indicators" syntax:
+# indicators = indicatorA: option1=value, option2=value, ...; indicatorB: option1=value, ...; ...
+# Common options:
+# layout = text|image|text-image|image-text
+# text = any text
+# image = path or #icon-name
+# expand = true|false
+# align = start|center|end
+#
# Template for monitor configuration:
-# [monitor: name]
-# background = overrides default value
-# user-background = overrides default value
-# laptop = true|false, false by default. Marks monitor as laptop display.
-#
+# [monitor: name]
+# background = overrides default value
+# user-background = overrides default value
+# laptop = true|false, false by default. Marks monitor as laptop display.
+#
[greeter]
#background=
#user-background=
@@ -36,8 +44,7 @@
#xft-dpi=
#xft-hintstyle=
#xft-rgba=
-#show-indicators=
-#show-clock=
+#indicators=
#clock-format=
#keyboard=
#reader=
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2014-08-20 23:23:59 +0000
+++ src/Makefile.am 2014-10-26 18:59:04 +0000
@@ -3,7 +3,9 @@
lightdm_gtk_greeter_built_sources = \
lightdm-gtk-greeter-ui.h \
lightdm-gtk-greeter-css-fallback.h \
- lightdm-gtk-greeter-css-application.h
+ lightdm-gtk-greeter-css-application.h \
+ greetermarshalers.h \
+ greetermarshalers.c
lightdm_gtk_greeter_SOURCES = \
$(lightdm_gtk_greeter_built_sources) \
@@ -54,6 +56,13 @@
lightdm-gtk-greeter-css-application.h: $(srcdir)/lightdm-gtk-greeter-application.css Makefile
$(AM_V_GEN) exo-csource --static --name=lightdm_gtk_greeter_css_application $< >$@
+greetermarshalers.h: $(srcdir)/greetermarshalers.list Makefile
+ $(AM_V_GEN) glib-genmarshal --prefix=greeter_marshal --header $< >$@
+
+greetermarshalers.c: $(srcdir)/greetermarshalers.list Makefile
+ $(AM_V_GEN) echo '#include "greetermarshalers.h"' >$@
+ $(AM_V_GEN) glib-genmarshal --prefix=greeter_marshal --body $< >>$@
+
DISTCLEANFILES = \
$(lightdm_gtk_greeter_built_sources)
@@ -65,4 +74,4 @@
EXTRA_DIST = \
lightdm-gtk-greeter.glade \
lightdm-gtk-greeter-fallback.css \
- lightdm-gtk-greeter-application.css
\ No newline at end of file
+ lightdm-gtk-greeter-application.css
=== modified file 'src/greeterbackground.c'
--- src/greeterbackground.c 2014-08-31 17:45:52 +0000
+++ src/greeterbackground.c 2014-10-26 18:59:04 +0000
@@ -212,6 +212,8 @@
GreeterBackground* background);
static void greeter_background_monitors_changed_cb (GdkScreen* screen,
GreeterBackground* background);
+static void greeter_background_child_destroyed_cb (GtkWidget* child,
+ GreeterBackground* background);
/* struct BackgroundConfig */
static gboolean background_config_initialize (BackgroundConfig* config,
@@ -269,7 +271,7 @@
GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
background_signals[BACKGROUND_SIGNAL_ACTIVE_MONITOR_CHANGED] =
- g_signal_new("active-monitor-changed",
+ g_signal_new(GREETER_BACKGROUND_SIGNAL_ACTIVE_MONITOR_CHANGED,
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_FIRST,
0, /* class_offset */
@@ -302,11 +304,14 @@
self->priv->laptop_lid_closed = FALSE;
}
-GreeterBackground*
+GreeterBackground*
greeter_background_new(GtkWidget* child)
{
+ g_return_val_if_fail(child != NULL, NULL);
+
GreeterBackground* background = GREETER_BACKGROUND(g_object_new(greeter_background_get_type(), NULL));
background->priv->child = child;
+ g_signal_connect(background->priv->child, "destroy", G_CALLBACK(greeter_background_child_destroyed_cb), background);
return background;
}
@@ -418,12 +423,9 @@
g_return_if_fail(GREETER_IS_BACKGROUND(background));
g_return_if_fail(GDK_IS_SCREEN(screen));
- g_debug("Connecting to screen");
+ g_debug("[Background] Connecting to screen");
GreeterBackgroundPrivate* priv = background->priv;
- gulong screen_monitors_changed_handler_id = (priv->screen == screen) ? priv->screen_monitors_changed_handler_id : 0;
- if(screen_monitors_changed_handler_id)
- priv->screen_monitors_changed_handler_id = 0;
if(priv->screen)
greeter_background_disconnect(background);
@@ -451,13 +453,13 @@
if(!greeter_background_find_monitor_data(background, priv->configs, monitor, (gpointer*)&config))
{
- g_debug("No configuration options for monitor %s #%d, using default", printable_name, i);
+ g_debug("[Background] No configuration options for monitor %s #%d, using default", printable_name, i);
config = priv->default_config;
}
gdk_screen_get_monitor_geometry(screen, i, &monitor->geometry);
- g_debug("Monitor: %s #%d (%dx%d at %dx%d)%s", printable_name, i,
+ g_debug("[Background] Monitor: %s #%d (%dx%d at %dx%d)%s", printable_name, i,
monitor->geometry.width, monitor->geometry.height,
monitor->geometry.x, monitor->geometry.y,
(i == gdk_screen_get_primary_monitor(screen)) ? " primary" : "");
@@ -467,7 +469,7 @@
{
if(i < priv->monitors_size - 1 || first_not_skipped_monitor)
continue;
- g_debug("Monitor %s #%d can not be skipped, using default configuration for it", printable_name, i);
+ g_debug("[Background] Monitor %s #%d can not be skipped, using default configuration for it", printable_name, i);
if(priv->default_config->bg.type != BACKGROUND_TYPE_SKIP)
config = priv->default_config;
else
@@ -534,12 +536,9 @@
if(!priv->active_monitor)
greeter_background_set_active_monitor(background, NULL);
- if(screen_monitors_changed_handler_id)
- priv->screen_monitors_changed_handler_id = screen_monitors_changed_handler_id;
- else
- priv->screen_monitors_changed_handler_id = g_signal_connect(G_OBJECT(screen), "monitors-changed",
- G_CALLBACK(greeter_background_monitors_changed_cb),
- background);
+ priv->screen_monitors_changed_handler_id = g_signal_connect(G_OBJECT(screen), "monitors-changed",
+ G_CALLBACK(greeter_background_monitors_changed_cb),
+ background);
}
void
@@ -548,13 +547,13 @@
g_return_if_fail(GREETER_IS_BACKGROUND(background));
GreeterBackgroundPrivate* priv = background->priv;
- priv->screen = NULL;
- priv->active_monitor = NULL;
-
if(priv->screen_monitors_changed_handler_id)
g_signal_handler_disconnect(priv->screen, priv->screen_monitors_changed_handler_id);
priv->screen_monitors_changed_handler_id = 0;
+ priv->screen = NULL;
+ priv->active_monitor = NULL;
+
gint i;
for(i = 0; i < priv->monitors_size; ++i)
monitor_finalize(&priv->monitors[i]);
@@ -647,12 +646,17 @@
priv->active_monitor = active;
- GtkWidget* old_parent = gtk_widget_get_parent(priv->child);
- if(old_parent)
- gtk_container_remove(GTK_CONTAINER(old_parent), priv->child);
- gtk_container_add(GTK_CONTAINER(active->window), priv->child);
+ if(priv->child)
+ {
+ GtkWidget* old_parent = gtk_widget_get_parent(priv->child);
+ if(old_parent)
+ gtk_container_remove(GTK_CONTAINER(old_parent), priv->child);
+ gtk_container_add(GTK_CONTAINER(active->window), priv->child);
+ }
+ else
+ g_warning("[Background] Child widget is not defined or destroyed");
- g_debug("Active monitor changed to: %s #%d", active->name, active->number);
+ g_debug("[Background] Active monitor changed to: %s #%d", active->name, active->number);
g_signal_emit(background, background_signals[BACKGROUND_SIGNAL_ACTIVE_MONITOR_CHANGED], 0);
gint x, y;
@@ -691,7 +695,7 @@
static void
greeter_background_try_init_dbus(GreeterBackground* background)
{
- g_debug("Creating DBus proxy");
+ g_debug("[Background] Creating DBus proxy");
GError* error = NULL;
GreeterBackgroundPrivate* priv = background->priv;
@@ -710,7 +714,7 @@
if(!priv->laptop_upower_proxy)
{
if(error)
- g_warning("Failed to create dbus proxy: %s", error->message);
+ g_warning("[Background] Failed to create dbus proxy: %s", error->message);
g_clear_error(&error);
return;
}
@@ -719,7 +723,7 @@
gboolean lid_present = g_variant_get_boolean(variant);
g_variant_unref(variant);
- g_debug("UPower.%s property value: %d", DBUS_UPOWER_PROP_LID_IS_PRESENT, lid_present);
+ g_debug("[Background] UPower.%s property value: %d", DBUS_UPOWER_PROP_LID_IS_PRESENT, lid_present);
if(!lid_present)
greeter_background_stop_dbus(background);
@@ -769,7 +773,7 @@
if(new_state == priv->laptop_lid_closed)
return;
- g_debug("UPower: lid state changed to '%s'", priv->laptop_lid_closed ? "closed" : "opened");
+ g_debug("[Background] UPower: lid state changed to '%s'", priv->laptop_lid_closed ? "closed" : "opened");
priv->laptop_lid_closed = new_state;
if(priv->laptop_monitors)
@@ -787,6 +791,13 @@
greeter_background_connect(background, screen);
}
+static void
+greeter_background_child_destroyed_cb(GtkWidget* child,
+ GreeterBackground* background)
+{
+ background->priv->child = NULL;
+}
+
void
greeter_background_set_custom_background(GreeterBackground* background,
const gchar* value)
@@ -904,7 +915,7 @@
config->options.image.mode = SCALING_MODE_ZOOMED;
config->options.image.path = g_strdup(value);
- config->type = BACKGROUND_TYPE_IMAGE;
+ config->type = BACKGROUND_TYPE_IMAGE;
}
return TRUE;
}
@@ -958,7 +969,7 @@
images_cache);
if(!pixbuf)
{
- g_warning("Failed to read wallpaper: %s", config->options.image.path);
+ g_warning("[Background] Failed to read wallpaper: %s", config->options.image.path);
return FALSE;
}
bg->options.image = pixbuf;
@@ -996,7 +1007,13 @@
if(monitor->window_draw_handler_id)
g_signal_handler_disconnect(monitor->window, monitor->window_draw_handler_id);
if(monitor->window)
+ {
+ GtkWidget* child = gtk_bin_get_child(GTK_BIN(monitor->window));
+ if(child)
+ /* remove greeter widget to avoid "destroy" signal */
+ gtk_container_remove(GTK_CONTAINER(monitor->window), child);
gtk_widget_destroy(GTK_WIDGET(monitor->window));
+ }
monitor->name = NULL;
monitor->window = NULL;
monitor->window_draw_handler_id = 0;
@@ -1055,7 +1072,10 @@
{
key = g_strdup_printf("%s\n%d %dx%d", path, mode, width, height);
if (g_hash_table_lookup_extended(cache, key, NULL, (gpointer*)&pixbuf))
+ {
+ g_free(key);
return GDK_PIXBUF(g_object_ref(pixbuf));
+ }
}
if (!cache || !g_hash_table_lookup_extended(cache, path, NULL, (gpointer*)&pixbuf))
@@ -1064,21 +1084,24 @@
pixbuf = gdk_pixbuf_new_from_file(path, &error);
if(error)
{
- g_warning("Failed to load background: %s", error->message);
+ g_warning("[Background] Failed to load background: %s", error->message);
g_clear_error(&error);
}
else if(cache)
- g_hash_table_insert(cache, g_strdup(path), g_object_ref (pixbuf));
+ g_hash_table_insert(cache, g_strdup(path), g_object_ref(pixbuf));
}
+ else
+ pixbuf = g_object_ref(pixbuf);
if(pixbuf)
{
GdkPixbuf* scaled = scale_image(pixbuf, mode, width, height);
- if (cache)
+ if(cache)
g_hash_table_insert(cache, g_strdup(key), g_object_ref(scaled));
g_object_unref(pixbuf);
pixbuf = scaled;
}
+ g_free(key);
return pixbuf;
}
@@ -1142,7 +1165,7 @@
display = XOpenDisplay (gdk_display_get_name (gdk_screen_get_display (screen)));
if (!display)
{
- g_warning ("Failed to create root pixmap");
+ g_warning("[Background] Failed to create root pixmap");
return NULL;
}
@@ -1165,7 +1188,7 @@
Display* display,
Pixmap xpixmap)
{
-
+
Window xroot = RootWindow (display, gdk_screen_get_number (screen));
char *atom_names[] = {"_XROOTPMAP_ID", "ESETROOT_PMAP_ID"};
Atom atoms[G_N_ELEMENTS(atom_names)] = {0};
@@ -1214,7 +1237,7 @@
*/
if (!XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), False, atoms) ||
atoms[0] == None || atoms[1] == None) {
- g_warning("Could not create atoms needed to set root pixmap id/properties.\n");
+ g_warning("[Background] Could not create atoms needed to set root pixmap id/properties.\n");
return;
}
=== modified file 'src/greeterbackground.h'
--- src/greeterbackground.h 2014-08-31 17:45:52 +0000
+++ src/greeterbackground.h 2014-10-26 18:59:04 +0000
@@ -12,6 +12,8 @@
#define GREETER_IS_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GREETER_BACKGROUND_TYPE))
#define GREETER_IS_BACKGROUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GREETER_BACKGROUND_TYPE))
+#define GREETER_BACKGROUND_SIGNAL_ACTIVE_MONITOR_CHANGED "active-monitor-changed"
+
typedef struct _GreeterBackground GreeterBackground;
typedef struct _GreeterBackgroundClass GreeterBackgroundClass;
@@ -34,6 +36,7 @@
gchar** greeter_background_get_configured_monitors (GreeterBackground* background);
void greeter_background_connect (GreeterBackground* background,
GdkScreen* screen);
+void greeter_background_disconnect (GreeterBackground* background);
void greeter_background_set_custom_background (GreeterBackground* background,
const gchar* path);
void greeter_background_save_xroot (GreeterBackground* background);
=== added file 'src/greetermarshalers.list'
--- src/greetermarshalers.list 1970-01-01 00:00:00 +0000
+++ src/greetermarshalers.list 2014-10-26 18:59:04 +0000
@@ -0,0 +1,28 @@
+# see glib-genmarshal(1) for a detailed description of the file format,
+# possible parameter types are:
+# VOID indicates no return type, or no extra
+# parameters. if VOID is used as the parameter
+# list, no additional parameters may be present.
+# BOOLEAN for boolean types (gboolean)
+# CHAR for signed char types (gchar)
+# UCHAR for unsigned char types (guchar)
+# INT for signed integer types (gint)
+# UINT for unsigned integer types (guint)
+# LONG for signed long integer types (glong)
+# ULONG for unsigned long integer types (gulong)
+# ENUM for enumeration types (gint)
+# FLAGS for flag enumeration types (guint)
+# FLOAT for single-precision float types (gfloat)
+# DOUBLE for double-precision float types (gdouble)
+# STRING for string types (gchar*)
+# BOXED for boxed (anonymous but reference counted) types (GBoxed*)
+# POINTER for anonymous pointer types (gpointer)
+# PARAM for GParamSpec or derived types (GParamSpec*)
+# OBJECT for GObject or derived types (GObject*)
+# NONE deprecated alias for VOID
+# BOOL deprecated alias for BOOLEAN
+#
+# GreeterMenuBar: item unknown-item(name, options)
+OBJECT: STRING, POINTER
+# GreeterMenuBar: applied unknown-item-option(item, item-name, option-name, option-value)
+BOOLEAN: OBJECT, STRING, STRING, STRING
=== modified file 'src/greetermenubar.c'
--- src/greetermenubar.c 2014-08-10 12:48:13 +0000
+++ src/greetermenubar.c 2014-10-26 18:59:04 +0000
@@ -1,39 +1,674 @@
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
#include <gtk/gtk.h>
+
+#ifdef HAVE_LIBINDICATOR
+#include <libindicator/indicator-object.h>
+#ifdef HAVE_LIBINDICATOR_NG
+#include <libindicator/indicator-ng.h>
+#endif
+#endif
+
+#include "src/greetermarshalers.h"
+
#include "greetermenubar.h"
-static void greeter_menu_bar_size_allocate(GtkWidget* widget, GtkAllocation* allocation);
-
-G_DEFINE_TYPE(GreeterMenuBar, greeter_menu_bar, GTK_TYPE_MENU_BAR);
+struct _GreeterMenuBar
+{
+ GtkMenuBar parent_instance;
+ struct _GreeterMenuBarPrivate* priv;
+};
+
+struct _GreeterMenuBarClass
+{
+ GtkMenuBarClass parent_class;
+};
+
+/* Styles */
+static const gchar* ITEM_STYLE_COMMON = "panel-item";
+static const gchar* ITEM_STYLE_HOVERED = "panel-item-hovered";
+static const gchar* ITEM_STYLE_INDICATOR = "panel-item-indicator";
+static const gchar* ITEM_STYLE_TEXT = "panel-item-text";
+static const gchar* ITEM_STYLE_SEPARATOR = "panel-item-separator";
+static const gchar* ITEM_STYLE_SPACER = "panel-item-spacer";
+
+/* Common options */
+static const gchar* ITEM_OPTION_NAME = "name";
+static const gchar* ITEM_OPTION_LAYOUT = "layout";
+static const gchar* ITEM_OPTION_TEXT = "text";
+static const gchar* ITEM_OPTION_IMAGE = "image";
+static const gchar* ITEM_OPTION_FALLBACK_IMAGE = "fallback-image";
+static const gchar* ITEM_OPTION_TOOLTIP = "tooltip";
+static const gchar* ITEM_OPTION_MARKUP = "markup";
+static const gchar* ITEM_OPTION_EXPAND = "expand";
+static const gchar* ITEM_OPTION_ALIGN = "align";
+
+#ifdef HAVE_LIBINDICATOR
+static const gchar* COMMON_OPTIONS_KEY = "*";
+#endif
+
+typedef enum
+{
+ ITEM_LAYOUT_INVALID = 0x00,
+ ITEM_LAYOUT_TEXT = 0x01,
+ ITEM_LAYOUT_IMAGE = 0x02,
+ ITEM_LAYOUT_REVERSED = 0x04,
+ ITEM_LAYOUT_NO_CHILDREN = 0x08, /* Special layout for separators and spacers */
+} ItemLayout;
+
+typedef struct
+{
+ GreeterMenuBar*menubar;
+
+ gint position;
+ ItemLayout layout;
+ const gchar* css_style;
+
+ GtkWidget* widget;
+ GtkWidget* label_widget;
+ GtkWidget* image_widget;
+
+ gboolean protect_label;
+ gboolean protect_image;
+ gboolean protect_tooltip;
+ gboolean label_markup;
+
+ gchar* fallback_image;
+
+ #ifdef HAVE_LIBINDICATOR
+ struct
+ {
+ IndicatorObject* object;
+ IndicatorObjectEntry* entry;
+ } indicator;
+ #endif
+} ChildInfo;
+
+#ifdef HAVE_LIBINDICATOR
+typedef struct
+{
+ GreeterMenuBar* menubar;
+
+ IndicatorObject* object;
+ GHashTable* entries; /* <IndicatorObjectEntry*> => <ChildInfo*> */
+ GHashTable* options;
+
+ gint position;
+} IndicatorInfo;
+#endif
+
+typedef struct _GreeterMenuBarPrivate
+{
+ GHashTable* children; /* <GtkMenuItem*> => <ChildInfo*> */
+ GHashTable* common_options; /* Set of <const gchar*>, used to pass only unknown options to "unknown-item-option" handler */
+ gboolean items_visibility;
+
+ #ifdef HAVE_LIBINDICATOR
+ struct
+ {
+ GHashTable* list; /* <IndicatorObject*> => <IndicatorInfo*> */
+ gboolean inited;
+ } indicators;
+ #endif
+} GreeterMenuBarPrivate;
+
+enum
+{
+ ITEMS_VISIBILITY_CHANGED_SIGNAL,
+ UNKNOWN_ITEM_SIGNAL,
+ UNKNOWN_ITEM_OPTION_SIGNAL,
+ LAST_SIGNAL
+};
+
+static guint menubar_signals[LAST_SIGNAL] = { 0 };
+
+typedef struct
+{
+ GreeterMenuBar* menubar;
+ ChildInfo* child_info;
+ const gchar* child_name;
+} UnknownOptionCallbackData;
+
+static void greeter_menu_bar_destroy (GtkWidget* widget);
+static void greeter_menu_bar_size_allocate (GtkWidget* widget,
+ GtkAllocation* allocation);
+static void greeter_menu_bar_remove (GtkContainer* container,
+ GtkWidget* widget);
+
+static void greeter_menu_bar_add_item (GreeterMenuBar* menubar,
+ ChildInfo* child,
+ GHashTable* options);
+static void greeter_menu_bar_item_visibility_changed(GreeterMenuBar* menubar,
+ ChildInfo* child_info);
+static void greeter_menu_bar_unknown_option_cb (const gchar* option,
+ const gchar* value,
+ UnknownOptionCallbackData* data);
+static void item_set_text (ChildInfo* child,
+ const gchar* value);
+static void item_set_image (ChildInfo* child,
+ const gchar* value);
+static void item_set_tooltip (ChildInfo* child,
+ const gchar* value);
+static gboolean item_enter_notify_cb (GtkWidget* widget,
+ GdkEvent* event,
+ gpointer enter);
+#ifdef HAVE_LIBINDICATOR
+static void greeter_menu_bar_add_indicator_entry (GreeterMenuBar* menubar,
+ IndicatorInfo* indicator_info,
+ IndicatorObjectEntry* entry);
+static void greeter_menu_bar_remove_indicator_entry (GreeterMenuBar* menubar,
+ IndicatorInfo* indicator_info,
+ IndicatorObjectEntry* entry);
+static gboolean indicator_item_scrolled_cb (GtkWidget* menuitem,
+ GdkEventScroll* event,
+ ChildInfo* child_info);
+static void indicator_item_activated_cb (GtkWidget* menuitem,
+ ChildInfo* child_info);
+static void indicator_entry_visibility_cb (GtkWidget* widget,
+ ChildInfo* child_info);
+static void indicator_entry_sensitivity_cb (GObject* obj,
+ GParamSpec* pspec,
+ ChildInfo* child_info);
+static void indicator_entry_added_cb (IndicatorObject* io,
+ IndicatorObjectEntry* entry,
+ IndicatorInfo* indicator_info);
+static void indicator_entry_removed_cb (IndicatorObject* io,
+ IndicatorObjectEntry* entry,
+ IndicatorInfo* indicator_info);
+static void indicator_entry_menu_show_cb (IndicatorObject* io,
+ IndicatorObjectEntry* entry,
+ guint32 timestamp,
+ IndicatorInfo* indicator_info);
+#endif
+
+static void child_info_free (ChildInfo* info);
+#ifdef HAVE_LIBINDICATOR
+static void indicator_info_free (IndicatorInfo* info);
+#endif
+
+static gint sort_minimal_size (gconstpointer a,
+ gconstpointer b,
+ GtkRequestedSize* sizes);
+static gchar* get_indicators_string_token (const gchar* s,
+ const gchar* delimiters,
+ const gchar** end);
+static gboolean item_is_visible (GtkMenuItem* menuitem,
+ ChildInfo* child_info,
+ gpointer user_data);
+static void remove_widget_from_container (GtkWidget* widget,
+ GtkContainer* container);
+
+G_DEFINE_TYPE_WITH_PRIVATE(GreeterMenuBar, greeter_menu_bar, GTK_TYPE_MENU_BAR);
+
+/* Implementation */
+
+gboolean
+greeter_set_image_from_string(GtkImage* image,
+ const gchar* value,
+ GtkIconSize size)
+{
+ if(!value)
+ return FALSE;
+
+ if(value[0] == '#')
+ {
+ GtkIconTheme* theme = gtk_icon_theme_get_default();
+ const gchar* icon = &value[1];
+ gchar* fallback = NULL;
+
+ if(!gtk_icon_theme_has_icon(theme, icon))
+ {
+ if(g_str_has_suffix(icon, "-symbolic"))
+ {
+ gchar *fallback = g_strndup(icon, strlen(icon) - strlen("-symbolic"));
+ icon = gtk_icon_theme_has_icon(theme, fallback) ? fallback : NULL;
+ }
+ else
+ icon = NULL;
+ }
+
+ if(!icon)
+ g_debug("Current theme does not contain '%s' icon", &value[1]);
+
+ gtk_image_set_from_icon_name(image, icon ? icon : "error", size);
+ g_free(fallback);
+ return icon != NULL;
+ }
+
+ GError* error = NULL;
+ gint width = 16, height = 16;
+ gtk_icon_size_lookup(size, &width, &height);
+
+ GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_scale(value, width, height, TRUE, &error);
+ if(pixbuf)
+ {
+ gtk_image_set_from_pixbuf(image, pixbuf);
+ g_object_unref(pixbuf);
+ }
+ else
+ {
+ gtk_image_set_from_icon_name(image, "error", size);
+ g_warning("Failed to load image: %s", error->message);
+ g_clear_error(&error);
+ }
+
+ return pixbuf != NULL;
+}
+
+void
+greeter_set_env(const gchar* key,
+ const gchar* value)
+{
+ g_setenv(key, value, TRUE);
+
+ GDBusProxy* proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ NULL, NULL);
+
+ GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add(builder, "{ss}", key, value);
+ GVariant* result = g_dbus_proxy_call_sync(proxy, "UpdateActivationEnvironment", g_variant_new("(a{ss})", builder),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL);
+ g_variant_unref(result);
+ g_variant_builder_unref(builder);
+ g_object_unref(proxy);
+}
+
+gboolean
+greeter_str_to_bool(const gchar* value)
+{
+ return g_strcmp0(value, "true") == 0 || g_strcmp0(value, "1") == 0;
+}
static void
greeter_menu_bar_class_init(GreeterMenuBarClass* klass)
{
+ GObjectClass* object_class = G_OBJECT_CLASS(klass);
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
+ GtkContainerClass* container_class = GTK_CONTAINER_CLASS(klass);
+
+ widget_class->destroy = greeter_menu_bar_destroy;
widget_class->size_allocate = greeter_menu_bar_size_allocate;
+ container_class->remove = greeter_menu_bar_remove;
+
+ menubar_signals[ITEMS_VISIBILITY_CHANGED_SIGNAL] =
+ g_signal_new(GREETER_MENU_BAR_SIGNAL_ITEMS_VISIBILITY_CHANGED,
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, /* class_offset */
+ NULL /* accumulator */, NULL /* accu_data */,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+ menubar_signals[UNKNOWN_ITEM_SIGNAL] =
+ g_signal_new(GREETER_MENU_BAR_SIGNAL_UNKNOWN_ITEM,
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, /* class_offset */
+ NULL /* accumulator */, NULL /* accu_data */,
+ greeter_marshal_OBJECT__STRING_POINTER,
+ G_TYPE_OBJECT /* new menuitem or NULL */, 2,
+ G_TYPE_STRING /* name */,
+ G_TYPE_POINTER /* options */);
+
+ menubar_signals[UNKNOWN_ITEM_OPTION_SIGNAL] =
+ g_signal_new(GREETER_MENU_BAR_SIGNAL_UNKNOWN_ITEM_OPTION,
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, /* class_offset */
+ NULL /* accumulator */, NULL /* accu_data */,
+ greeter_marshal_BOOLEAN__OBJECT_STRING_STRING_STRING,
+ G_TYPE_BOOLEAN /* success */, 4,
+ G_TYPE_OBJECT /* menuitem */,
+ G_TYPE_STRING /* item name */,
+ G_TYPE_STRING /* option name */,
+ G_TYPE_STRING /* option value */);
}
static void
-greeter_menu_bar_init(GreeterMenuBar* square)
+greeter_menu_bar_init(GreeterMenuBar* self)
{
-
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, GREETER_MENU_BAR_TYPE, GreeterMenuBarPrivate);
+
+ self->priv->children = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)child_info_free);
+ #ifdef HAVE_LIBINDICATOR
+ self->priv->indicators.list = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)indicator_info_free);
+ #endif
+
+ GHashTable* common_options = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
+ self->priv->common_options = common_options;
+ g_hash_table_add(common_options, (gpointer)ITEM_OPTION_NAME);
+ g_hash_table_add(common_options, (gpointer)ITEM_OPTION_LAYOUT);
+ g_hash_table_add(common_options, (gpointer)ITEM_OPTION_TEXT);
+ g_hash_table_add(common_options, (gpointer)ITEM_OPTION_IMAGE);
+ g_hash_table_add(common_options, (gpointer)ITEM_OPTION_FALLBACK_IMAGE);
+ g_hash_table_add(common_options, (gpointer)ITEM_OPTION_TOOLTIP);
+ g_hash_table_add(common_options, (gpointer)ITEM_OPTION_MARKUP);
+ g_hash_table_add(common_options, (gpointer)ITEM_OPTION_EXPAND);
+ g_hash_table_add(common_options, (gpointer)ITEM_OPTION_ALIGN);
}
-GtkWidget*
+GtkWidget*
greeter_menu_bar_new()
{
return GTK_WIDGET(g_object_new(greeter_menu_bar_get_type(), NULL));
}
-static gint
-sort_minimal_size(gconstpointer a, gconstpointer b, GtkRequestedSize* sizes)
-{
- gint a_size = sizes[GPOINTER_TO_INT(a)].natural_size;
- gint b_size = sizes[GPOINTER_TO_INT(b)].natural_size;
- return a_size == b_size ? 0 : a_size > b_size ? -1 : +1;
-}
-
-static void
-greeter_menu_bar_size_allocate(GtkWidget* widget, GtkAllocation* allocation)
+void
+greeter_menu_bar_load_from_string(GreeterMenuBar* menubar,
+ const gchar* str)
+{
+ g_return_if_fail(GREETER_IS_MENU_BAR(menubar));
+
+ GSList* indicators = NULL; /* list of <GHashTable*> options */
+
+ gtk_container_foreach(GTK_CONTAINER(menubar), (GtkCallback)remove_widget_from_container, menubar);
+
+ if(!str)
+ return;
+
+ while(*str)
+ {
+ gchar* name = get_indicators_string_token(str, ":;", &str);
+ if(!name)
+ continue;
+
+ GHashTable *options = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ indicators = g_slist_prepend(indicators, options);
+
+ g_hash_table_insert(options, g_strdup(ITEM_OPTION_NAME), name);
+
+ if(*str == ':')
+ {
+ do
+ {
+ gchar* option = get_indicators_string_token(++str, "=,;", &str);
+ gchar* value = (*str == '=') ? get_indicators_string_token(++str, ",;", &str) : NULL;
+ g_hash_table_insert(options, option, value);
+ } while(*str == ',');
+ }
+ if(*str)
+ ++str;
+ }
+
+ gint child_position = 0;
+ GSList* indicators_iter;
+
+ for(indicators_iter = indicators; indicators_iter; indicators_iter = g_slist_next(indicators_iter))
+ {
+ GHashTable* options = indicators_iter->data;
+ const gchar* name = g_hash_table_lookup(options, ITEM_OPTION_NAME);
+ if(!name || strlen(name) == 0)
+ continue;
+
+ if(name[0] == '~')
+ {
+ ChildInfo* child_info = g_new0(ChildInfo, 1);
+
+ /* Built-in indicators */
+ if(g_strcmp0(name, "~separator") == 0)
+ {
+ child_info->widget = gtk_separator_menu_item_new();
+ child_info->layout = ITEM_LAYOUT_NO_CHILDREN;
+ child_info->css_style = ITEM_STYLE_SEPARATOR;
+
+ GtkWidget* separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
+ gtk_widget_show(separator);
+ gtk_container_add(GTK_CONTAINER(child_info->widget), separator);
+ }
+ else if(g_strcmp0(name, "~spacer") == 0)
+ {
+ child_info->widget = gtk_separator_menu_item_new();
+ child_info->layout = ITEM_LAYOUT_NO_CHILDREN;
+ child_info->css_style = ITEM_STYLE_SPACER;
+
+ gtk_menu_item_set_label(GTK_MENU_ITEM(child_info->widget), "");
+ gtk_widget_set_hexpand(child_info->widget, TRUE);
+ }
+ else if(name[1] == '~' || g_strcmp0(name, "~text") == 0)
+ {
+ child_info->widget = gtk_separator_menu_item_new();
+ child_info->layout = ITEM_LAYOUT_TEXT;
+ child_info->css_style = ITEM_STYLE_TEXT;
+
+ if(name[1] == '~' && !g_hash_table_lookup_extended(options, ITEM_OPTION_TEXT, NULL, NULL))
+ g_hash_table_insert(options, g_strdup(ITEM_OPTION_TEXT), g_strdup(&name[2]));
+ }
+ else
+ {
+ g_signal_emit(menubar, menubar_signals[UNKNOWN_ITEM_SIGNAL], 0, name, options, &child_info->widget);
+ if(child_info->widget)
+ {
+ child_info->layout = ITEM_LAYOUT_TEXT;
+ child_info->css_style = ITEM_STYLE_INDICATOR;
+ }
+ }
+
+ if(child_info->widget)
+ {
+ child_info->position = child_position;
+ greeter_menu_bar_add_item(menubar, child_info, options);
+ }
+ else
+ {
+ child_info_free(child_info);
+ g_warning("[Panel] Unknown builtin item: '%s'", name);
+ }
+ }
+ #ifdef HAVE_LIBINDICATOR
+ else
+ {
+ GreeterMenuBarPrivate* priv = menubar->priv;
+ gchar* path = NULL;
+ IndicatorObject* io = NULL;
+
+ if(!priv->indicators.inited)
+ {
+ /* Set indicators to run with reduced functionality */
+ greeter_set_env("INDICATOR_GREETER_MODE", "1");
+ /* Don't allow virtual file systems? */
+ greeter_set_env("GIO_USE_VFS", "local");
+ greeter_set_env("GVFS_DISABLE_FUSE", "1");
+
+ priv->indicators.inited = TRUE;
+ }
+
+ if(g_path_is_absolute(name))
+ { /* library with absolute path */
+ io = indicator_object_new_from_file(name);
+ }
+ else if(g_str_has_suffix(name, G_MODULE_SUFFIX))
+ { /* library */
+ path = g_build_filename(INDICATOR_DIR, name, NULL);
+ io = indicator_object_new_from_file(path);
+ }
+ #ifdef HAVE_LIBINDICATOR_NG
+ else
+ { /* service file */
+ if(strchr(name, '.'))
+ path = g_strdup_printf("%s/%s", UNITY_INDICATOR_DIR, name);
+ else
+ path = g_strdup_printf("%s/com.canonical.indicator.%s", UNITY_INDICATOR_DIR, name);
+ io = INDICATOR_OBJECT(indicator_ng_new_for_profile(path, "desktop_greeter", NULL));
+ }
+ #endif
+
+ if(io)
+ {
+ IndicatorInfo* indicator_info = g_new0(IndicatorInfo, 1);
+ indicator_info->menubar = menubar;
+ indicator_info->object = io;
+ indicator_info->position = child_position;
+ indicator_info->options = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_hash_table_unref);
+ indicator_info->entries = g_hash_table_new(g_direct_hash, g_direct_equal);
+
+ g_hash_table_insert(priv->indicators.list, io, indicator_info);
+
+ GHashTableIter options_iter;
+ const gchar* option;
+ const gchar* value;
+
+ /* Parsing options: option[/entry-name] = value */
+ g_hash_table_iter_init(&options_iter, options);
+ while(g_hash_table_iter_next(&options_iter, (gpointer*)&option, (gpointer*)&value))
+ {
+ GHashTable* entry_options = NULL;
+
+ const gchar* delim = strchr(option, '/');
+ const gchar* entry_name = (delim && strlen(delim) > 1) ? &delim[1] : COMMON_OPTIONS_KEY;
+ gchar* option_name = delim ? g_strndup(option, delim - option) : g_strdup(option);
+
+ if(!g_hash_table_lookup_extended(indicator_info->options, entry_name, NULL, (gpointer*)&entry_options))
+ {
+ entry_options = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ g_hash_table_insert(indicator_info->options, g_strdup(entry_name), entry_options);
+ }
+
+ g_hash_table_insert(entry_options, option_name, g_strdup(value));
+ }
+
+ /* Add common options to custom */
+ GHashTable* common_options = g_hash_table_lookup(indicator_info->options, COMMON_OPTIONS_KEY);
+ if(common_options && g_hash_table_size(indicator_info->options) > 1)
+ {
+ GHashTableIter entries_iter;
+ GHashTable* entry_options;
+ const gchar* entry_name;
+
+ g_hash_table_iter_init(&entries_iter, indicator_info->options);
+ while(g_hash_table_iter_next(&entries_iter, (gpointer*)&entry_name, (gpointer*)&entry_options))
+ {
+ if(entry_options == common_options)
+ continue;
+
+ const gchar* name;
+ const gchar* value;
+ g_hash_table_iter_init(&options_iter, common_options);
+ while(g_hash_table_iter_next(&options_iter,(gpointer*)&name, (gpointer*)&value))
+ {
+ if(!g_hash_table_lookup_extended(entry_options, name, NULL, NULL))
+ g_hash_table_insert(entry_options, g_strdup(name), g_strdup(value));
+ }
+ }
+ }
+
+ g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED, G_CALLBACK(indicator_entry_added_cb), indicator_info);
+ g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED, G_CALLBACK(indicator_entry_removed_cb), indicator_info);
+ g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_MENU_SHOW, G_CALLBACK(indicator_entry_menu_show_cb), indicator_info);
+
+ GList* entries = indicator_object_get_entries(io);
+ GList* entries_iter;
+ for(entries_iter = entries; entries_iter; entries_iter = g_list_next(entries_iter))
+ greeter_menu_bar_add_indicator_entry(menubar, indicator_info, entries_iter->data);
+ g_list_free(entries);
+ }
+ else
+ {
+ g_warning("[Panel] Indicator '%s': failed to load", name);
+ }
+
+ g_free(path);
+ }
+ #else
+ else
+ g_warning("[Panel] Invalid indicator: '%s' (this build do not have libindicator support)", name);
+ #endif
+ child_position++;
+ }
+ g_slist_free_full(indicators, (GDestroyNotify)g_hash_table_unref);
+}
+
+const gchar*
+greeter_menu_bar_get_item_text(GreeterMenuBar* menubar,
+ GtkWidget* menuitem)
+{
+ g_return_if_fail(GREETER_IS_MENU_BAR(menubar));
+
+ ChildInfo* child_info = g_hash_table_lookup(menubar->priv->children, menuitem);
+
+ if(child_info && child_info->label_widget)
+ return gtk_label_get_label(GTK_LABEL(child_info->label_widget));
+ return NULL;
+}
+
+void
+greeter_menu_bar_set_item_text(GreeterMenuBar* menubar,
+ GtkWidget* menuitem,
+ const gchar* value)
+{
+ g_return_if_fail(GREETER_IS_MENU_BAR(menubar));
+
+ ChildInfo* child_info = g_hash_table_lookup(menubar->priv->children, menuitem);
+
+ if(child_info)
+ item_set_text(child_info, value);
+}
+
+void
+greeter_menu_bar_set_item_image(GreeterMenuBar* menubar,
+ GtkWidget* menuitem,
+ const gchar* value)
+{
+ g_return_if_fail(GREETER_IS_MENU_BAR(menubar));
+
+ ChildInfo* child_info = g_hash_table_lookup(menubar->priv->children, menuitem);
+
+ if(child_info)
+ item_set_image(child_info, value);
+}
+
+void
+greeter_menu_bar_set_item_tooltip(GreeterMenuBar* menubar,
+ GtkWidget* menuitem,
+ const gchar* value)
+{
+ g_return_if_fail(GREETER_IS_MENU_BAR(menubar));
+
+ ChildInfo* child_info = g_hash_table_lookup(menubar->priv->children, menuitem);
+
+ if(child_info)
+ item_set_tooltip(child_info, value);
+}
+
+gboolean
+greeter_menu_bar_item_have_text(GreeterMenuBar* menubar,
+ GtkWidget* menuitem)
+{
+ g_return_if_fail(GREETER_IS_MENU_BAR(menubar));
+
+ ChildInfo* child_info = g_hash_table_lookup(menubar->priv->children, menuitem);
+
+ return child_info ? child_info->label_widget != NULL : FALSE;
+}
+
+gboolean
+greeter_menu_bar_item_have_image(GreeterMenuBar* menubar,
+ GtkWidget* menuitem)
+{
+ g_return_if_fail(GREETER_IS_MENU_BAR(menubar));
+
+ ChildInfo* child_info = g_hash_table_lookup(menubar->priv->children, menuitem);
+
+ return child_info ? child_info->image_widget != NULL : FALSE;
+}
+
+static void
+greeter_menu_bar_destroy(GtkWidget* widget)
+{
+ GTK_WIDGET_CLASS(greeter_menu_bar_parent_class)->destroy(widget);
+}
+
+static void
+greeter_menu_bar_size_allocate(GtkWidget* widget,
+ GtkAllocation* allocation)
{
GList* item;
GList* shell_children;
@@ -80,14 +715,14 @@
gtk_style_context_get_padding(context, flags, &border);
gtk_widget_style_get(widget, "shadow-type", &shadow_type, NULL);
- remaining_space.x = (border_width + border.left);
- remaining_space.y = (border_width + border.top);
+ remaining_space.x = border_width + border.left;
+ remaining_space.y = border_width + border.top;
remaining_space.width = allocation->width -
2 * border_width - border.left - border.right;
remaining_space.height = allocation->height -
2 * border_width - border.top - border.bottom;
- if (shadow_type != GTK_SHADOW_NONE)
+ if(shadow_type != GTK_SHADOW_NONE)
{
gtk_style_context_get_border(context, flags, &border);
@@ -103,7 +738,7 @@
for(item = shell_children; item; item = g_list_next(item))
{
- if (!gtk_widget_get_visible(item->data))
+ if(!gtk_widget_get_visible(item->data))
continue;
request->data = item->data;
@@ -167,7 +802,7 @@
request->natural_size += dsize;
}
}
-
+
gint i;
for(i = 0; i < visible_count; i++)
{
@@ -176,7 +811,7 @@
child_allocation.width = request->natural_size;
remaining_space.width -= request->natural_size;
- if (ltr)
+ if(ltr)
remaining_space.x += request->natural_size;
else
child_allocation.x += remaining_space.width;
@@ -186,3 +821,564 @@
}
g_list_free(shell_children);
}
+
+static void
+greeter_menu_bar_remove(GtkContainer* container,
+ GtkWidget* widget)
+{
+ g_hash_table_remove(GREETER_MENU_BAR(container)->priv->children, widget);
+ GTK_CONTAINER_CLASS(greeter_menu_bar_parent_class)->remove(container, widget);
+}
+
+static void
+greeter_menu_bar_add_item(GreeterMenuBar* menubar,
+ ChildInfo* child,
+ GHashTable* options)
+{
+ GreeterMenuBarPrivate* priv = menubar->priv;
+
+ const gchar* name = g_hash_table_lookup(options, ITEM_OPTION_NAME);
+
+ g_debug("[Panel] New item added: %s", name);
+
+ /* Styling */
+ gtk_style_context_add_class(gtk_widget_get_style_context(child->widget), ITEM_STYLE_COMMON);
+ gtk_style_context_add_class(gtk_widget_get_style_context(child->widget), child->css_style);
+
+ /* Hover effect */
+ if(child->layout != ITEM_LAYOUT_NO_CHILDREN)
+ {
+ g_signal_connect(G_OBJECT(child->widget), "enter-notify-event",
+ G_CALLBACK(item_enter_notify_cb), GINT_TO_POINTER(TRUE));
+ g_signal_connect(G_OBJECT(child->widget), "leave-notify-event",
+ G_CALLBACK(item_enter_notify_cb), GINT_TO_POINTER(FALSE));
+ }
+ /* Options */
+ const gchar* value;
+
+ /* "markup" option. Value: any text. Without value: use "text" as markup */
+ if(g_hash_table_lookup_extended(options, ITEM_OPTION_MARKUP, NULL, (gpointer*)&value))
+ {
+ child->label_markup = TRUE;
+ if(value)
+ g_hash_table_insert(options, g_strdup(ITEM_OPTION_TEXT), g_strdup(value));
+ }
+
+ /* "layout" option. Values: image|text|image-text|text-mage */
+ if(child->layout != ITEM_LAYOUT_NO_CHILDREN)
+ {
+ value = g_hash_table_lookup(options, ITEM_OPTION_LAYOUT);
+ if(value)
+ {
+ struct
+ {
+ const gchar* name;
+ ItemLayout layout;
+ }
+ *layout_struct,
+ VALUES[] =
+ {
+ {"text", ITEM_LAYOUT_TEXT},
+ {"image", ITEM_LAYOUT_IMAGE},
+ {"text-image", ITEM_LAYOUT_TEXT | ITEM_LAYOUT_IMAGE},
+ {"image-text", ITEM_LAYOUT_TEXT | ITEM_LAYOUT_IMAGE | ITEM_LAYOUT_REVERSED},
+ {NULL, ITEM_LAYOUT_INVALID}
+ };
+
+ for(layout_struct = VALUES; layout_struct->name; ++layout_struct)
+ if(g_strcmp0(layout_struct->name, value) == 0)
+ {
+ child->layout = layout_struct->layout;
+ break;
+ }
+ if(!layout_struct->name)
+ g_warning("[Panel] Invalid value for '%s' option: '%s'", ITEM_OPTION_LAYOUT, value);
+ }
+
+ /* Use "text" and "image" options to set up layout */
+ if(g_hash_table_contains(options, ITEM_OPTION_TEXT))
+ child->layout |= ITEM_LAYOUT_TEXT;
+ if(g_hash_table_contains(options, ITEM_OPTION_IMAGE))
+ child->layout |= ITEM_LAYOUT_IMAGE;
+
+ if(child->layout != ITEM_LAYOUT_INVALID)
+ {
+ GtkWidget* item_child = gtk_bin_get_child(GTK_BIN(child->widget));
+ if(item_child)
+ gtk_container_remove(GTK_CONTAINER(child->widget), item_child);
+
+ GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4));
+
+ if(child->layout & ITEM_LAYOUT_TEXT)
+ {
+ if(!child->label_widget || g_hash_table_lookup(options, ITEM_OPTION_TEXT))
+ {
+ child->label_widget = gtk_label_new(NULL);
+ gtk_widget_show(child->label_widget);
+ }
+ if(child->layout & ITEM_LAYOUT_REVERSED)
+ gtk_box_pack_end(box, child->label_widget, FALSE, TRUE, 0);
+ else
+ gtk_box_pack_start(box, child->label_widget, FALSE, TRUE, 0);
+ }
+
+ if(child->layout & ITEM_LAYOUT_IMAGE)
+ {
+ if(!child->image_widget || g_hash_table_lookup(options, ITEM_OPTION_IMAGE))
+ {
+ child->image_widget = gtk_image_new();
+ gtk_widget_show(child->image_widget);
+ }
+ gtk_box_pack_end(box, child->image_widget, FALSE, TRUE, 0);
+ }
+
+ gtk_widget_set_halign(GTK_WIDGET(box), GTK_ALIGN_CENTER);
+ gtk_widget_show(GTK_WIDGET(box));
+ gtk_container_add(GTK_CONTAINER(child->widget), GTK_WIDGET(box));
+ }
+ }
+
+ /* "text" option. Value: any text */
+ value = g_hash_table_lookup(options, ITEM_OPTION_TEXT);
+ if(value)
+ {
+ item_set_text(child, value);
+ child->protect_label = TRUE;
+ }
+
+ /* "fallback-image" option. Value: #icon-name or /path/to/file */
+ child->fallback_image = g_strdup(g_hash_table_lookup(options, ITEM_OPTION_FALLBACK_IMAGE));
+
+ /* "image" option. Value: #icon-name or /path/to/file */
+ value = g_hash_table_lookup(options, ITEM_OPTION_IMAGE);
+ if(value)
+ {
+ item_set_image(child, value);
+ child->protect_image = TRUE;
+ }
+ else
+ item_set_image(child, NULL);
+
+ /* "tooltip" option. Value: any text */
+ value = g_hash_table_lookup(options, ITEM_OPTION_TOOLTIP);
+ if(value)
+ {
+ item_set_tooltip(child, value);
+ child->protect_tooltip = TRUE;
+ }
+
+ /* "expand" option. Values: true|false. Short form value: true */
+ if(g_hash_table_lookup_extended(options, ITEM_OPTION_EXPAND, NULL, (gpointer*)&value))
+ gtk_widget_set_hexpand(child->widget, !value || greeter_str_to_bool(value));
+
+ /* "align" option. Values: start|center|end */
+ value = g_hash_table_lookup(options, ITEM_OPTION_ALIGN);
+ if(value)
+ {
+ GtkAlign align;
+ if(g_strcmp0(value, "start") == 0)
+ align = GTK_ALIGN_START;
+ else if(g_strcmp0(value, "center") == 0)
+ align = GTK_ALIGN_CENTER;
+ else if(g_strcmp0(value, "end") == 0)
+ align = GTK_ALIGN_END;
+ else
+ {
+ g_warning("[Panel] Invalid value for '%s' option: '%s'", ITEM_OPTION_ALIGN, value);
+ value = NULL;
+ }
+ if(value)
+ gtk_widget_set_halign(child->widget, align);
+ }
+
+ /* Custom options */
+ {
+ UnknownOptionCallbackData data =
+ {
+ .menubar = menubar,
+ .child_info = child,
+ .child_name = name,
+ };
+ g_hash_table_foreach(options, (GHFunc)greeter_menu_bar_unknown_option_cb, &data);
+ }
+
+ g_hash_table_insert(priv->children, child->widget, child);
+ gtk_widget_show(child->widget);
+
+ gint insert_pos = 0;
+ GList* items = gtk_container_get_children(GTK_CONTAINER(menubar));
+ GList* item;
+ for(item = items; item; item = g_list_next(item))
+ {
+ ChildInfo* item_info = g_hash_table_lookup(priv->children, item->data);
+ if(item_info && child->position < item_info->position)
+ break;
+ insert_pos++;
+ }
+ g_list_free(items);
+
+ gtk_menu_shell_insert(GTK_MENU_SHELL(menubar), child->widget, insert_pos);
+ greeter_menu_bar_item_visibility_changed(menubar, child);
+}
+
+static void
+greeter_menu_bar_item_visibility_changed(GreeterMenuBar* menubar,
+ ChildInfo* child_info)
+{
+ gboolean visible = FALSE;
+
+ #ifdef HAVE_LIBINDICATOR
+ if(child_info->indicator.entry)
+ {
+ /* Visibility controlled by IndicatorObject, so we watch for label and image visibility changes */
+ if(child_info->indicator.entry->label)
+ visible = visible || gtk_widget_get_visible(GTK_WIDGET(child_info->indicator.entry->label));
+ if(child_info->indicator.entry->image && !visible)
+ visible = visible || gtk_widget_get_visible(GTK_WIDGET(child_info->indicator.entry->image));
+ gtk_widget_set_visible(child_info->widget, visible);
+ }
+ else
+ #endif
+ {
+ /* Controlled by program, watch for menu item visibility changes */
+ visible = gtk_widget_get_visible(child_info->widget);
+ }
+
+ if(!visible)
+ visible = g_hash_table_find(menubar->priv->children, (GHRFunc)item_is_visible, NULL) != NULL;
+
+ if(visible != menubar->priv->items_visibility)
+ {
+ menubar->priv->items_visibility = visible;
+ g_signal_emit(menubar, menubar_signals[ITEMS_VISIBILITY_CHANGED_SIGNAL], 0, visible);
+ }
+}
+
+static void
+greeter_menu_bar_unknown_option_cb(const gchar* option,
+ const gchar* value,
+ UnknownOptionCallbackData* data)
+{
+ if(!g_hash_table_contains(data->menubar->priv->common_options, option))
+ {
+ gboolean result = FALSE;
+ g_signal_emit(data->menubar, menubar_signals[UNKNOWN_ITEM_OPTION_SIGNAL], 0,
+ data->child_info->widget, data->child_name, option, value, &result);
+ if(!result)
+ g_warning("[Panel] Unknown option or invalid value for '%s' item: '%s' = '%s'", data->child_name, option, value);
+ }
+}
+
+static void
+item_set_text(ChildInfo* child,
+ const gchar* value)
+{
+ if(child->label_widget && !child->protect_label)
+ {
+ if(child->label_markup)
+ gtk_label_set_markup(GTK_LABEL(child->label_widget), value);
+ else
+ gtk_label_set_label(GTK_LABEL(child->label_widget), value);
+ }
+}
+
+static void
+item_set_image(ChildInfo* child,
+ const gchar* value)
+{
+ if(child->image_widget && !child->protect_image)
+ {
+ if(!value || !greeter_set_image_from_string(GTK_IMAGE(child->image_widget), value, GTK_ICON_SIZE_MENU))
+ if(child->fallback_image && g_strcmp0(value, child->fallback_image) != 0)
+ greeter_set_image_from_string(GTK_IMAGE(child->image_widget), child->fallback_image, GTK_ICON_SIZE_MENU);
+ }
+}
+
+static void
+item_set_tooltip(ChildInfo* child,
+ const gchar* value)
+{
+ if(!child->protect_tooltip)
+ gtk_widget_set_tooltip_text(GTK_WIDGET(child->widget), value);
+}
+
+static gboolean
+item_enter_notify_cb(GtkWidget* widget,
+ GdkEvent* event,
+ gpointer enter)
+{
+ GtkStyleContext* context = gtk_widget_get_style_context(widget);
+ if(GPOINTER_TO_INT(enter))
+ gtk_style_context_add_class(context, ITEM_STYLE_HOVERED);
+ else
+ gtk_style_context_remove_class(context, ITEM_STYLE_HOVERED);
+ return FALSE;
+}
+
+#ifdef HAVE_LIBINDICATOR
+static void
+greeter_menu_bar_add_indicator_entry(GreeterMenuBar* menubar,
+ IndicatorInfo* indicator_info,
+ IndicatorObjectEntry* entry)
+{
+ ChildInfo* child_info = g_new0(ChildInfo, 1);
+
+ g_debug("[Panel] Adding new IndicatorObjectEntry: %s", entry->name_hint);
+
+ child_info->menubar = indicator_info->menubar;
+ child_info->widget = gtk_menu_item_new();
+ child_info->position = indicator_info->position;
+ child_info->css_style = ITEM_STYLE_INDICATOR;
+ child_info->layout = ITEM_LAYOUT_TEXT | ITEM_LAYOUT_IMAGE;
+ child_info->indicator.object = indicator_info->object;
+ child_info->indicator.entry = entry;
+
+ g_hash_table_insert(indicator_info->entries, entry, child_info);
+
+ gtk_widget_add_events(child_info->widget, GDK_SCROLL_MASK);
+ g_signal_connect(child_info->widget, "activate", G_CALLBACK(indicator_item_activated_cb), child_info);
+ g_signal_connect(child_info->widget, "scroll-event", G_CALLBACK(indicator_item_scrolled_cb), child_info);
+
+ if(entry->label)
+ {
+ g_object_connect(entry->label,
+ "signal::show", G_CALLBACK(indicator_entry_visibility_cb), child_info,
+ "signal::hide", G_CALLBACK(indicator_entry_visibility_cb), child_info,
+ "signal::notify::sensitive", G_CALLBACK(indicator_entry_sensitivity_cb), child_info,
+ NULL);
+ child_info->label_widget = GTK_WIDGET(entry->label);
+ }
+
+ if(entry->image)
+ {
+ g_object_connect(entry->image,
+ "signal::show", G_CALLBACK(indicator_entry_visibility_cb), child_info,
+ "signal::hide", G_CALLBACK(indicator_entry_visibility_cb), child_info,
+ "signal::notify::sensitive", G_CALLBACK(indicator_entry_sensitivity_cb), child_info,
+ NULL);
+ child_info->image_widget = GTK_WIDGET(entry->image);
+ }
+
+ if(entry->menu)
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(child_info->widget), GTK_WIDGET(entry->menu));
+
+ GHashTable* entry_options = g_hash_table_lookup(indicator_info->options, entry->name_hint);
+ if(!entry_options)
+ entry_options = g_hash_table_lookup(indicator_info->options, COMMON_OPTIONS_KEY);
+
+ greeter_menu_bar_add_item(indicator_info->menubar, child_info, entry_options);
+}
+
+static void
+greeter_menu_bar_remove_indicator_entry(GreeterMenuBar* menubar,
+ IndicatorInfo* indicator_info,
+ IndicatorObjectEntry* entry)
+{
+ ChildInfo* child_info = g_hash_table_lookup(indicator_info->entries, entry);
+
+ g_debug("[Panel] Removing IndicatorObjectEntry: %s", entry->name_hint);
+
+ if(child_info)
+ {
+ if(entry->label)
+ g_object_disconnect(entry->label,
+ "any-signal", G_CALLBACK(indicator_entry_visibility_cb), child_info,
+ "any-signal", G_CALLBACK(indicator_entry_sensitivity_cb), child_info,
+ NULL);
+ if(entry->image)
+ g_object_disconnect(entry->image,
+ "any-signal", G_CALLBACK(indicator_entry_visibility_cb), child_info,
+ "any-signal", G_CALLBACK(indicator_entry_sensitivity_cb), child_info,
+ NULL);
+
+ g_hash_table_remove(indicator_info->entries, entry);
+ gtk_widget_destroy(child_info->widget);
+ }
+}
+
+static gboolean
+indicator_item_scrolled_cb(GtkWidget* menuitem,
+ GdkEventScroll* event,
+ ChildInfo* child_info)
+{
+ g_return_val_if_fail(child_info != NULL, FALSE);
+ g_return_val_if_fail(child_info->indicator.object && child_info->indicator.entry, FALSE);
+
+ g_signal_emit_by_name(child_info->indicator.object, INDICATOR_OBJECT_SIGNAL_ENTRY_SCROLLED, child_info->indicator.entry, 1, event->direction);
+ return FALSE;
+}
+
+static void
+indicator_item_activated_cb(GtkWidget* menuitem,
+ ChildInfo* child_info)
+{
+ g_return_val_if_fail(child_info != NULL, FALSE);
+ g_return_val_if_fail(child_info->indicator.object && child_info->indicator.entry, FALSE);
+
+ indicator_object_entry_activate(child_info->indicator.object, child_info->indicator.entry, gtk_get_current_event_time());
+}
+
+static void
+indicator_entry_visibility_cb(GtkWidget* widget,
+ ChildInfo* child_info)
+{
+ g_return_val_if_fail(child_info != NULL, FALSE);
+
+ greeter_menu_bar_item_visibility_changed(child_info->menubar, child_info);
+}
+
+static void
+indicator_entry_sensitivity_cb(GObject* obj,
+ GParamSpec* pspec,
+ ChildInfo* child_info)
+{
+ g_return_val_if_fail(child_info != NULL, FALSE);
+
+ gboolean sensitive = FALSE;
+ if(child_info->indicator.entry->label)
+ sensitive = sensitive || gtk_widget_get_sensitive(GTK_WIDGET(child_info->indicator.entry->label));
+ if(child_info->indicator.entry->image && !sensitive)
+ sensitive = sensitive || gtk_widget_get_sensitive(GTK_WIDGET(child_info->indicator.entry->image));
+ gtk_widget_set_sensitive(child_info->widget, sensitive);
+}
+
+static void
+indicator_entry_added_cb(IndicatorObject* io,
+ IndicatorObjectEntry* entry,
+ IndicatorInfo* indicator_info)
+{
+ greeter_menu_bar_add_indicator_entry(indicator_info->menubar, indicator_info, entry);
+}
+
+static void
+indicator_entry_removed_cb(IndicatorObject* io,
+ IndicatorObjectEntry* entry,
+ IndicatorInfo* indicator_info)
+{
+ greeter_menu_bar_remove_indicator_entry(indicator_info->menubar, indicator_info, entry);
+}
+
+static void
+indicator_entry_menu_show_cb(IndicatorObject* io,
+ IndicatorObjectEntry* entry,
+ guint32 timestamp,
+ IndicatorInfo* indicator_info)
+{
+ if(!entry)
+ {
+ /* Close any open menus instead of opening one */
+ GList *items = indicator_object_get_entries(io);
+ GList *item;
+ for(item = items; item; item = g_list_next(item))
+ {
+ entry = item->data;
+ gtk_menu_popdown(entry->menu);
+ }
+ g_list_free(items);
+
+ /* And tell the menuitem to exit activation mode too */
+ gtk_menu_shell_cancel(GTK_MENU_SHELL(indicator_info->menubar));
+ }
+}
+
+#endif
+
+static void
+child_info_free(ChildInfo* info)
+{
+ g_free(info->fallback_image);
+ info->fallback_image = NULL;
+}
+
+#ifdef HAVE_LIBINDICATOR
+static void
+indicator_info_free(IndicatorInfo* info)
+{
+ g_hash_table_unref(info->options);
+ g_hash_table_unref(info->entries);
+ info->options = NULL;
+ info->entries = NULL;
+}
+#endif
+
+static gint
+sort_minimal_size(gconstpointer a,
+ gconstpointer b,
+ GtkRequestedSize* sizes)
+{
+ gint a_size = sizes[GPOINTER_TO_INT(a)].natural_size;
+ gint b_size = sizes[GPOINTER_TO_INT(b)].natural_size;
+ return a_size == b_size ? 0 : a_size > b_size ? -1 : +1;
+}
+
+static gchar*
+get_indicators_string_token(const gchar* s,
+ const gchar* delimiters,
+ const gchar** end)
+{
+ GString *token = g_string_new(NULL);
+ gboolean quoted = FALSE;
+
+ /* strip at left */
+ while(*s && g_ascii_isspace(*s))
+ ++s;
+
+ const gchar *p = s;
+
+ for(p = s; *p; ++p)
+ {
+ if(*p == '"')
+ {
+ if(p > s && *(p-1) == '\\')
+ {
+ g_string_append_len(token, s, p - s - 1);
+ g_string_append_c(token, '"');
+ }
+ else
+ {
+ g_string_append_len(token, s, p - s);
+ quoted = !quoted;
+ }
+ s = p + 1;
+ }
+ else if(!quoted && strchr(delimiters, *p))
+ break;
+ }
+
+ *end = p;
+
+ if(quoted)
+ {
+ g_string_free(token, TRUE);
+ return NULL;
+ }
+
+ /* strip at right */
+ const gchar *q = p - 1;
+ while(s < q && g_ascii_isspace(*q))
+ --q;
+ if(q != p)
+ p = q + 1;
+
+ g_string_append_len(token, s, p - s);
+ gchar *result = token->str;
+ g_string_free(token, FALSE);
+
+ return result;
+}
+
+static gboolean
+item_is_visible(GtkMenuItem* menuitem,
+ ChildInfo* child_info,
+ gpointer user_data)
+{
+ if(child_info->layout != ITEM_LAYOUT_NO_CHILDREN)
+ return gtk_widget_get_visible(child_info->widget);
+ return FALSE;
+}
+
+static void
+remove_widget_from_container(GtkWidget* widget, GtkContainer* container)
+{
+ gtk_container_remove(container, widget);
+}
=== modified file 'src/greetermenubar.h'
--- src/greetermenubar.h 2014-08-10 12:48:13 +0000
+++ src/greetermenubar.h 2014-10-26 18:59:04 +0000
@@ -8,25 +8,54 @@
#define GREETER_MENU_BAR_TYPE (greeter_menu_bar_get_type())
#define GREETER_MENU_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GREETER_MENU_BAR_TYPE, GreeterMenuBar))
-#define GREETER_MENU_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GREETER_MENU_BAR_TYPE, GreeterMenuBarClass))
+#define GREETER_MENU_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GREETER_MENU_BAR_TYPE, GreeterMenuBarClass))
#define GREETER_IS_MENU_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GREETER_MENU_BAR_TYPE))
-#define GREETER_IS_MENU_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GREETER_MENU_BAR_TYPE))
+#define GREETER_IS_MENU_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GREETER_MENU_BAR_TYPE))
+
+#define GREETER_MENU_BAR_SIGNAL_ITEMS_VISIBILITY_CHANGED "items-visibility-changed"
+#define GREETER_MENU_BAR_SIGNAL_UNKNOWN_ITEM "unknown-item"
+#define GREETER_MENU_BAR_SIGNAL_UNKNOWN_ITEM_OPTION "unknown-item-option"
typedef struct _GreeterMenuBar GreeterMenuBar;
typedef struct _GreeterMenuBarClass GreeterMenuBarClass;
-struct _GreeterMenuBar
-{
- GtkMenuBar parent_instance;
-};
-
-struct _GreeterMenuBarClass
-{
- GtkMenuBarClass parent_class;
-};
-
-GType greeter_menu_bar_get_type(void) G_GNUC_CONST;
-GtkWidget *greeter_menu_bar_new(void);
+typedef GtkWidget* (*GMBUnknownItemCallback) (const gchar* name,
+ gchar*** options,
+ gpointer user_data);
+
+typedef gboolean (*GMBUnknownOptionCallback) (GtkWidget* menuitem,
+ const gchar* name,
+ const gchar* option,
+ const gchar* value,
+ gpointer user_data);
+
+GType greeter_menu_bar_get_type (void) G_GNUC_CONST;
+GtkWidget *greeter_menu_bar_new (void);
+
+void greeter_menu_bar_load_from_string (GreeterMenuBar* menubar,
+ const gchar* str);
+const gchar* greeter_menu_bar_get_item_text (GreeterMenuBar* menubar,
+ GtkWidget* menuitem);
+void greeter_menu_bar_set_item_text (GreeterMenuBar* menubar,
+ GtkWidget* menuitem,
+ const gchar* value);
+void greeter_menu_bar_set_item_image (GreeterMenuBar* menubar,
+ GtkWidget* menuitem,
+ const gchar* value);
+void greeter_menu_bar_set_item_tooltip (GreeterMenuBar* menubar,
+ GtkWidget* menuitem,
+ const gchar* value);
+gboolean greeter_menu_bar_item_have_text (GreeterMenuBar* menubar,
+ GtkWidget* menuitem);
+gboolean greeter_menu_bar_item_have_image (GreeterMenuBar* menubar,
+ GtkWidget* menuitem);
+
+gboolean greeter_set_image_from_string (GtkImage* image,
+ const gchar* value,
+ GtkIconSize size);
+void greeter_set_env (const gchar* key,
+ const gchar* value);
+gboolean greeter_str_to_bool (const gchar* value);
G_END_DECLS
=== modified file 'src/lightdm-gtk-greeter-fallback.css'
--- src/lightdm-gtk-greeter-fallback.css 2014-05-22 19:52:34 +0000
+++ src/lightdm-gtk-greeter-fallback.css 2014-10-26 18:59:04 +0000
@@ -1,12 +1,17 @@
-#layout_menuitem>GtkLabel
+#layout_menuitem>GtkContainer>GtkLabel
{
- border: 1px solid alpha(@menu_fg_color, 0.8);
- border-radius: 0.5em;
- padding: 0px 0.25em;
- background: alpha(@menu_fg_color, 0.2);
+ border: 1px solid alpha(@menu_fg_color, 0.8);
+ border-radius: 0.5em;
+ padding: 0px 0.25em;
+ background: alpha(@menu_fg_color, 0.2);
}
#layout_menuitem
{
- padding: 1px;
+ padding: 1px;
+}
+
+#clock_menuitem
+{
+ font-weight: bold;
}
=== modified file 'src/lightdm-gtk-greeter.c'
--- src/lightdm-gtk-greeter.c 2014-09-01 07:58:56 +0000
+++ src/lightdm-gtk-greeter.c 2014-10-26 18:59:04 +0000
@@ -29,13 +29,6 @@
#include <gtk/gtkx.h>
#include <glib/gslist.h>
-#ifdef HAVE_LIBINDICATOR
-#include <libindicator/indicator-object.h>
-#ifdef HAVE_LIBINDICATOR_NG
-#include <libindicator/indicator-ng.h>
-#endif
-#endif
-
#ifdef HAVE_LIBIDO
/* Some indicators need ido library */
#include <libido/libido.h>
@@ -62,7 +55,7 @@
static void save_state_file (void);
/* Screen window */
-static GtkOverlay *screen_overlay;
+static GtkOverlay *screen_overlay;
/* Login window */
static GtkWidget *login_window;
@@ -74,12 +67,12 @@
static GtkButton *cancel_button, *login_button;
/* Panel */
-static GtkWidget *panel_window, *menubar;
+static GtkWidget *panel_window;
+static GreeterMenuBar *menubar;
static GtkWidget *power_menuitem, *session_menuitem, *language_menuitem, *a11y_menuitem,
*layout_menuitem, *clock_menuitem, *host_menuitem;
static GtkWidget *suspend_menuitem, *hibernate_menuitem, *restart_menuitem, *shutdown_menuitem;
static GtkWidget *contrast_menuitem, *font_menuitem, *keyboard_menuitem, *reader_menuitem;
-static GtkWidget *clock_label, *session_badge;
static GtkMenu *session_menu, *language_menu, *layout_menu;
/* Power window */
@@ -88,13 +81,23 @@
static GtkLabel *power_title, *power_text;
static GtkImage *power_icon;
-static const gchar *POWER_WINDOW_DATA_LOOP = "power-window-loop"; /* <GMainLoop*> */
-static const gchar *POWER_WINDOW_DATA_RESPONSE = "power-window-response"; /* <GtkResponseType> */
+static const gchar *POWER_OPTION_HIDE_DISABLED = "hide-disabled";
+static const gchar *POWER_DATA_HIDE_DISABLED = "power-hide-disabled"; /* <gboolean> hide disabled items, attached to power_menuitem */
+static const gchar *POWER_WINDOW_DATA_LOOP = "power-window-loop"; /* <GMainLoop*> */
+static const gchar *POWER_WINDOW_DATA_RESPONSE = "power-window-response"; /* <GtkResponseType> */
static gboolean show_power_prompt (const gchar *action, const gchar* icon, const gchar* title, const gchar* message);
void power_button_clicked_cb (GtkButton *button, gpointer user_data);
gboolean power_window_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
+static gboolean sigterm_cb (gpointer user_data);
+
+/* List of processes to kill at exit */
+GSList *spawned_pids; /* list of <GPid> */
+
+gboolean spawn_and_remember (gchar **argv, GError **perror);
+static void close_pid_cb (gpointer pid_as_pointer);
+
/* Handling window position */
typedef struct
{
@@ -110,7 +113,7 @@
typedef struct
{
DimensionPosition x, y;
- /* Flag to use width and height fileds */
+ /* Flag to use width and height fields */
gboolean use_size;
DimensionPosition width, height;
} WindowPosition;
@@ -131,8 +134,9 @@
static gboolean key_file_get_boolean_extended (GKeyFile *key_file, const gchar *group_name, const gchar *key, gboolean default_value);
/* Clock */
+static const gchar *CLOCK_OPTION_CLOCK_FORMAT = "clock-format";
static gchar *clock_format;
-static gboolean clock_timeout_thread (void);
+static gboolean clock_timeout_cb (gpointer user_data);
/* Message label */
static gboolean message_label_is_empty (void);
@@ -167,18 +171,51 @@
static void a11y_menuitem_toggled_cb (GtkCheckMenuItem *item, const gchar* name);
/* Session */
+static const gchar *SESSION_DATA_KEY = "session-key"; /* <gchar*> session name, attached to submenu items */
static gchar *current_session;
static gboolean is_valid_session (GList* items, const gchar* session);
static gchar* get_session (void);
static void set_session (const gchar *session);
void session_selected_cb (GtkMenuItem *menuitem, gpointer user_data);
-/* Sesion language */
+/* Session language */
+static const gchar *LANGUAGE_DATA_CODE = "language-code"; /* <gchar*> e.g. "de_DE.UTF-8", attached to submenu items */
static gchar *current_language;
static gchar* get_language (void);
static void set_language (const gchar *language);
void language_selected_cb (GtkMenuItem *menuitem, gpointer user_data);
+/* Layout indicator */
+static const gchar *LAYOUT_DATA_LABEL = "layout-label"; /* <gchar*> e.g. "English (US)" */
+static void layout_selected_cb (GtkCheckMenuItem *menuitem, gpointer user_data);
+static void update_layouts_menu (void);
+static void update_layouts_menu_state (void);
+#ifdef HAVE_LIBXKLAVIER
+static XklEngine *xkl_engine;
+static const gchar *LAYOUT_DATA_GROUP = "layout-group"; /* <gchar*> */
+static void xkl_state_changed_cb (XklEngine *engine, XklEngineStateChange change, gint group, gboolean restore, gpointer user_data);
+static void xkl_config_changed_cb (XklEngine *engine, gpointer user_data);
+static GdkFilterReturn xkl_xevent_filter (GdkXEvent *xev, GdkEvent *event, gpointer data);
+#else
+static const gchar *LAYOUT_DATA_NAME = "layout-name"; /* <gchar*> */
+#endif
+
+/* a11y indicator */
+static gchar *default_font_name,
+ *default_theme_name,
+ *default_icon_theme_name;
+void a11y_font_cb (GtkCheckMenuItem *item, gpointer user_data);
+void a11y_contrast_cb (GtkCheckMenuItem *item, gpointer user_data);
+void a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data);
+void a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data);
+
+/* Power indciator */
+void power_menuitem_activate_cb (GtkWidget *menuitem, gpointer userdata);
+void suspend_cb (GtkWidget *widget, LightDMGreeter *greeter);
+void hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter);
+void restart_cb (GtkWidget *widget, LightDMGreeter *greeter);
+void shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter);
+
/* Screensaver values */
static int timeout, interval, prefer_blanking, allow_exposures;
@@ -209,81 +246,63 @@
/* Panel and indicators */
-typedef enum
-{
- PANEL_ITEM_INDICATOR,
- PANEL_ITEM_SPACER,
- PANEL_ITEM_SEPARATOR,
- PANEL_ITEM_TEXT
-} GreeterPanelItemType;
-
-static const gchar *PANEL_ITEM_STYLE = "panel-item";
-static const gchar *PANEL_ITEM_STYLE_HOVERED = "panel-item-hovered";
-static const gchar *PANEL_ITEM_STYLES[] =
-{
- "panel-item-indicator",
- "panel-item-spacer",
- "panel-item-separator",
- "panel-item-text"
-};
-
-static const gchar *PANEL_ITEM_DATA_INDEX = "panel-item-data-index";
-
-#ifdef HAVE_LIBINDICATOR
-static const gchar *INDICATOR_ITEM_DATA_OBJECT = "indicator-item-data-object"; /* <IndicatorObject*> */
-static const gchar *INDICATOR_ITEM_DATA_ENTRY = "indicator-item-data-entry"; /* <IndicatorObjectEntry*> */
-static const gchar *INDICATOR_ITEM_DATA_BOX = "indicator-item-data-box"; /* <GtkBox*> */
-static const gchar *INDICATOR_DATA_MENUITEMS = "indicator-data-menuitems"; /* <GHashTable*> */
-#endif
-
-static const gchar *LANGUAGE_DATA_CODE = "language-code"; /* <gchar*> e.g. "de_DE.UTF-8" */
-static const gchar *SESSION_DATA_KEY = "session-key"; /* <gchar*> session name */
-
-/* Layout indicator */
-#ifdef HAVE_LIBXKLAVIER
-static XklEngine *xkl_engine;
-static const gchar *LAYOUT_DATA_GROUP = "layout-group"; /* <gchar*> */
-#else
-static const gchar *LAYOUT_DATA_NAME = "layout-name"; /* <gchar*> */
-#endif
-static const gchar *LAYOUT_DATA_LABEL = "layout-label"; /* <gchar*> e.g. "English (US)" */
-
-static gboolean panel_item_enter_notify_cb (GtkWidget *widget, GdkEvent *event, gpointer enter);
-static void panel_add_item (GtkWidget *widget, gint index, GreeterPanelItemType item_type);
-static gboolean menu_item_accel_closure_cb (GtkAccelGroup *accel_group, GObject *acceleratable, guint keyval, GdkModifierType modifier, gpointer data);
-/* Maybe unnecessary (in future) trick to enable accelerators for hidden/detached menu items */
-static void reassign_menu_item_accel (GtkWidget *item);
-
-#ifdef START_INDICATOR_SERVICES
-static void init_indicators (GKeyFile* config, GPid* indicator_pid, GPid* spi_pid);
-#else
-static void init_indicators (GKeyFile* config);
-#endif
-
-static void layout_selected_cb (GtkCheckMenuItem *menuitem, gpointer user_data);
-static void update_layouts_menu (void);
-static void update_layouts_menu_state (void);
-#ifdef HAVE_LIBXKLAVIER
-static void xkl_state_changed_cb (XklEngine *engine, XklEngineStateChange change, gint group, gboolean restore, gpointer user_data);
-static void xkl_config_changed_cb (XklEngine *engine, gpointer user_data);
-static GdkFilterReturn xkl_xevent_filter (GdkXEvent *xev, GdkEvent *event, gpointer data);
-#endif
-
-/* a11y indicator */
-static gchar *default_font_name,
- *default_theme_name,
- *default_icon_theme_name;
-void a11y_font_cb (GtkCheckMenuItem *item);
-void a11y_contrast_cb (GtkCheckMenuItem *item);
-void a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data);
-void a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data);
-
-/* Power indciator */
-static void power_menu_cb (GtkWidget *menuitem, gpointer userdata);
-void suspend_cb (GtkWidget *widget, LightDMGreeter *greeter);
-void hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter);
-void restart_cb (GtkWidget *widget, LightDMGreeter *greeter);
-void shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter);
+typedef struct
+{
+ const gchar *name;
+ GtkWidget *menuitem;
+ gboolean used;
+ const gchar *options[10];
+} BuiltinPanelItemInfo;
+
+static GHashTable *panel_builtin_items;
+
+static void panel_init (GKeyFile *config);
+static void panel_items_visibility_cb (GreeterMenuBar *menubar, gboolean visible, gpointer user_data);
+static void panel_reassing_item_accel_cb (GtkMenuItem *menuitem);
+static void panel_reassing_item_accel_table_cb (const gchar *name, const BuiltinPanelItemInfo *info);
+static gboolean panel_item_accel_closure_cb (GtkAccelGroup *accel_group, GObject *acceleratable, guint keyval,
+ GdkModifierType modifier, GtkMenuItem *menuitem);
+static GtkWidget *panel_unknown_item_cb (GreeterMenuBar *menubar, const gchar *name, GHashTable *options, gpointer user_data);
+static gboolean panel_unknown_item_option_cb (GreeterMenuBar *menubar, GtkWidget *menuitem, const gchar *name,
+ const gchar *option, const gchar *value, gpointer user_data);
+
+
+static gboolean
+sigterm_cb (gpointer user_data)
+{
+ g_debug ("SIGTERM signal");
+
+ g_slist_free_full (spawned_pids, close_pid_cb);
+ spawned_pids = NULL;
+
+ gtk_main_quit ();
+
+ if (screen_overlay)
+ gtk_widget_destroy (GTK_WIDGET (screen_overlay));
+ screen_overlay = NULL;
+
+ if (greeter_background)
+ greeter_background_disconnect (greeter_background);
+
+ return G_SOURCE_REMOVE;
+}
+
+gboolean
+spawn_and_remember (gchar **argv, GError **perror)
+{
+ GPid pid = 0;
+ gboolean result = g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &pid, perror);
+ if (result)
+ spawned_pids = g_slist_prepend (spawned_pids, GINT_TO_POINTER (pid));
+ return result;
+}
+
+static void close_pid_cb (gpointer pid_as_pointer)
+{
+ GPid pid = GPOINTER_TO_INT (pid_as_pointer);
+ kill (pid, SIGTERM);
+ waitpid (pid, NULL, 0);
+}
/* State file */
@@ -554,22 +573,22 @@
/* Clock */
static gboolean
-clock_timeout_thread (void)
+clock_timeout_cb (gpointer user_data)
{
- time_t rawtime;
- struct tm * timeinfo;
- gchar time_str[50];
- gchar *markup;
-
- time (&rawtime);
- timeinfo = localtime (&rawtime);
-
- strftime (time_str, 50, clock_format, timeinfo);
- markup = g_markup_printf_escaped ("<b>%s</b>", time_str);
- if (g_strcmp0 (markup, gtk_label_get_label (GTK_LABEL (clock_label))) != 0)
- gtk_label_set_markup (GTK_LABEL (clock_label), markup);
- g_free (markup);
-
+ GDateTime *now = g_date_time_new_now_local ();
+ gchar *label = g_date_time_format (now, clock_format);
+ g_date_time_unref (now);
+ if (!label)
+ {
+ g_warning ("[Clock] Failed to format time: %s", clock_format);
+ label = g_strdup_printf (_("[error] %s"), clock_format);
+ greeter_menu_bar_set_item_text (menubar, clock_menuitem, label);
+ g_free (label);
+ return FALSE;
+ }
+ if (g_strcmp0 (label, greeter_menu_bar_get_item_text (menubar, clock_menuitem)) != 0)
+ greeter_menu_bar_set_item_text (menubar, clock_menuitem, label);
+ g_free (label);
return TRUE;
}
@@ -854,23 +873,34 @@
if (g_strcmp0 (session, g_object_get_data (G_OBJECT (menu_iter->data), SESSION_DATA_KEY)) == 0)
{
/* Set menuitem-image to session-badge */
- GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
gchar* session_name = g_ascii_strdown (session, -1);
- gchar* icon_name = g_strdup_printf ("%s_badge-symbolic", session_name);
+ gchar* icon_name = g_strdup_printf ("#%s_badge-symbolic", session_name);
+ greeter_menu_bar_set_item_image (menubar, session_menuitem, icon_name);
+ greeter_menu_bar_set_item_text (menubar, session_menuitem, gtk_menu_item_get_label (GTK_MENU_ITEM (menu_iter->data)));
+ g_free (icon_name);
g_free (session_name);
- if (gtk_icon_theme_has_icon (icon_theme, icon_name))
- gtk_image_set_from_icon_name (GTK_IMAGE (session_badge), icon_name, GTK_ICON_SIZE_MENU);
- else
- gtk_image_set_from_icon_name (GTK_IMAGE (session_badge), "document-properties-symbolic", GTK_ICON_SIZE_MENU);
- g_free (icon_name);
break;
}
}
if (!menu_iter)
menu_iter = menu_items;
+ const gchar *tooltip = NULL;
+ gchar *tooltip_to_free = NULL;
+
if (menu_iter)
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_iter->data), TRUE);
+ {
+ gtk_check_menu_item_set_active (menu_iter->data, TRUE);
+
+ const gchar *label = gtk_menu_item_get_label (menu_iter->data);
+ if (g_strcmp0 (label, session) == 0)
+ tooltip = session;
+ else
+ tooltip = tooltip_to_free = g_strdup_printf ("%s (%s)", label, session);
+ }
+
+ greeter_menu_bar_set_item_tooltip (menubar, session_menuitem, tooltip);
+ g_free (tooltip_to_free);
}
g_free (current_session);
@@ -885,7 +915,6 @@
set_session (g_object_get_data (G_OBJECT (menuitem), SESSION_DATA_KEY));
}
-
/* Session language */
static gchar*
@@ -936,7 +965,7 @@
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_iter->data), TRUE);
g_free (current_language);
current_language = g_strdup (language);
- gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem),language);
+ greeter_menu_bar_set_item_text (menubar, language_menuitem, language);
return;
}
}
@@ -946,7 +975,7 @@
if (lightdm_get_language ())
{
default_language = lightdm_language_get_code (lightdm_get_language ());
- gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), default_language);
+ greeter_menu_bar_set_item_text (menubar, language_menuitem, default_language);
}
if (default_language && g_strcmp0 (default_language, language) != 0)
set_language (default_language);
@@ -957,7 +986,7 @@
{
if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_iter->data)))
{
- gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE)));
+ greeter_menu_bar_set_item_text (menubar, language_menuitem, g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE));
break;
}
}
@@ -1056,424 +1085,113 @@
/* Panel and indicators */
-static gboolean
-panel_item_enter_notify_cb (GtkWidget *widget, GdkEvent *event, gpointer enter)
-{
- GtkStyleContext *context = gtk_widget_get_style_context (widget);
- if (GPOINTER_TO_INT (enter))
- gtk_style_context_add_class (context, PANEL_ITEM_STYLE_HOVERED);
- else
- gtk_style_context_remove_class (context, PANEL_ITEM_STYLE_HOVERED);
- return FALSE;
-}
-
-static void
-panel_add_item (GtkWidget *widget, gint index, GreeterPanelItemType item_type)
-{
- gint insert_pos = 0;
- GList* items = gtk_container_get_children (GTK_CONTAINER (menubar));
- GList* item;
- for (item = items; item; item = item->next)
- {
- if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item->data), PANEL_ITEM_DATA_INDEX)) < index)
- break;
- insert_pos++;
- }
- g_list_free (items);
-
- gtk_style_context_add_class (gtk_widget_get_style_context (widget), PANEL_ITEM_STYLE);
- gtk_style_context_add_class (gtk_widget_get_style_context (widget), PANEL_ITEM_STYLES[item_type]);
- if (item_type == PANEL_ITEM_INDICATOR)
- {
- g_signal_connect (G_OBJECT (widget), "enter-notify-event",
- G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER (TRUE));
- g_signal_connect (G_OBJECT (widget), "leave-notify-event",
- G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER (FALSE));
- }
-
- gtk_widget_show (widget);
- gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), widget, insert_pos);
-}
-
-#ifdef HAVE_LIBINDICATOR
-static gboolean
-indicator_entry_scrolled_cb (GtkWidget *menuitem, GdkEventScroll *event, gpointer data)
-{
- IndicatorObject *io;
- IndicatorObjectEntry *entry;
-
- g_return_val_if_fail (GTK_IS_WIDGET (menuitem), FALSE);
-
- io = g_object_get_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_OBJECT);
- entry = g_object_get_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_ENTRY);
-
- g_return_val_if_fail (INDICATOR_IS_OBJECT (io), FALSE);
-
- g_signal_emit_by_name (io, "scroll", 1, event->direction);
- g_signal_emit_by_name (io, "scroll-entry", entry, 1, event->direction);
-
- return FALSE;
-}
-
-static void
-indicator_entry_activated_cb (GtkWidget *widget, gpointer user_data)
-{
- IndicatorObject *io;
- IndicatorObjectEntry *entry;
-
- g_return_if_fail (GTK_IS_WIDGET (widget));
-
- io = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_OBJECT);
- entry = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_ENTRY);
-
- g_return_if_fail (INDICATOR_IS_OBJECT (io));
-
- return indicator_object_entry_activate (io, entry, gtk_get_current_event_time ());
-}
-
-static GtkWidget*
-indicator_entry_create_menuitem (IndicatorObject *io, IndicatorObjectEntry *entry, GtkWidget *menubar)
-{
- GtkWidget *box, *menuitem;
- gint index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (io), PANEL_ITEM_DATA_INDEX));
- box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
- menuitem = gtk_menu_item_new ();
-
- gtk_widget_add_events (GTK_WIDGET (menuitem), GDK_SCROLL_MASK);
-
- g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_BOX, box);
- g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_OBJECT, io);
- g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_ENTRY, entry);
- g_object_set_data (G_OBJECT (menuitem), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (index));
-
- g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (indicator_entry_activated_cb), NULL);
- g_signal_connect (G_OBJECT (menuitem), "scroll-event", G_CALLBACK (indicator_entry_scrolled_cb), NULL);
-
- if (entry->image)
- gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (entry->image), FALSE, FALSE, 1);
-
- if (entry->label)
- gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (entry->label), FALSE, FALSE, 1);
-
- if (entry->menu)
- gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), GTK_WIDGET (entry->menu));
-
- gtk_container_add (GTK_CONTAINER (menuitem), box);
- gtk_widget_show (box);
- panel_add_item (menuitem, index, PANEL_ITEM_INDICATOR);
-
- return menuitem;
-}
-
-static void
-indicator_entry_added_cb (IndicatorObject *io, IndicatorObjectEntry *entry, gpointer user_data)
-{
- GHashTable *menuitem_lookup;
- GtkWidget *menuitem;
-
- /* if the menuitem doesn't already exist, create it now */
- menuitem_lookup = g_object_get_data (G_OBJECT (io), INDICATOR_DATA_MENUITEMS);
- g_return_if_fail (menuitem_lookup);
- menuitem = g_hash_table_lookup (menuitem_lookup, entry);
- if (!GTK_IS_WIDGET (menuitem))
- {
- menuitem = indicator_entry_create_menuitem (io, entry, GTK_WIDGET (user_data));
- g_hash_table_insert (menuitem_lookup, entry, menuitem);
- }
-
- gtk_widget_show (menuitem);
-}
-
-static void
-remove_indicator_entry_cb (GtkWidget *widget, gpointer userdata)
-{
- IndicatorObject *io;
- GHashTable *menuitem_lookup;
- GtkWidget *menuitem;
- gpointer entry;
-
- io = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_OBJECT);
- if (!INDICATOR_IS_OBJECT (io))
- return;
-
- entry = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_ENTRY);
- if (entry != userdata)
- return;
-
- menuitem_lookup = g_object_get_data (G_OBJECT (io), INDICATOR_DATA_MENUITEMS);
- g_return_if_fail (menuitem_lookup);
- menuitem = g_hash_table_lookup (menuitem_lookup, entry);
- if (GTK_IS_WIDGET (menuitem))
- gtk_widget_hide (menuitem);
-
- gtk_widget_destroy (widget);
-}
-
-static void
-indicator_entry_removed_cb (IndicatorObject *io, IndicatorObjectEntry *entry, gpointer user_data)
-{
- gtk_container_foreach (GTK_CONTAINER (user_data), remove_indicator_entry_cb, entry);
-}
-
-static void
-indicator_menu_show_cb (IndicatorObject *io, IndicatorObjectEntry *entry, guint32 timestamp, gpointer user_data)
-{
- IndicatorObjectEntry *entrydata;
- GtkWidget *menuitem;
- GList *entries, *lp;
-
- menuitem = GTK_WIDGET (user_data);
-
- if (!entry)
- {
- /* Close any open menus instead of opening one */
- entries = indicator_object_get_entries (io);
- for (lp = entries; lp; lp = g_list_next (entry))
- {
- entrydata = lp->data;
- gtk_menu_popdown (entrydata->menu);
- }
- g_list_free (entries);
-
- /* And tell the menuitem to exit activation mode too */
- gtk_menu_shell_cancel (GTK_MENU_SHELL (menuitem));
- }
-}
-
-static void
-greeter_set_env (const gchar* key, const gchar* value)
-{
- g_setenv (key, value, TRUE);
-
- GDBusProxy* proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
- G_DBUS_PROXY_FLAGS_NONE,
- NULL,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- NULL, NULL);
- GVariant *result;
- GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
- g_variant_builder_add (builder, "{ss}", key, value);
- result = g_dbus_proxy_call_sync (proxy, "UpdateActivationEnvironment", g_variant_new ("(a{ss})", builder),
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL);
- g_variant_unref (result);
- g_variant_builder_unref (builder);
- g_object_unref (proxy);
-}
-#endif
-
-static gboolean
-menu_item_accel_closure_cb (GtkAccelGroup *accel_group,
- GObject *acceleratable, guint keyval,
- GdkModifierType modifier, gpointer data)
-{
- gtk_menu_item_activate (data);
- return FALSE;
+static void
+panel_init (GKeyFile* config)
+{
+ const gchar *DEFAULT_LAYOUT =
+ "~host;"
+ "~spacer;"
+ "~clock;"
+ "~spacer;"
+ "~session;"
+ "~language;"
+ "~a11y;"
+ "~power";
+
+ gchar *key_value = g_key_file_get_string (config, "greeter", "indicators", NULL);
+
+ /* Do not remove our builtin items from menubar - load_from_string() will do it */
+ greeter_menu_bar_load_from_string(GREETER_MENU_BAR (menubar), key_value ? key_value : DEFAULT_LAYOUT);
+
+ g_free (key_value);
+
+ /* Accelerators for unused items */
+ g_hash_table_foreach (panel_builtin_items, (GHFunc)panel_reassing_item_accel_table_cb, NULL);
+}
+
+static void
+panel_items_visibility_cb (GreeterMenuBar *menubar, gboolean visible, gpointer user_data)
+{
+ gtk_widget_set_visible (panel_window, visible);
}
/* Maybe unnecessary (in future) trick to enable accelerators for hidden/detached menu items */
static void
-reassign_menu_item_accel (GtkWidget *item)
+panel_reassing_item_accel_cb (GtkMenuItem *menuitem)
{
GtkAccelKey key;
- const gchar *accel_path = gtk_menu_item_get_accel_path (GTK_MENU_ITEM (item));
+ const gchar *accel_path = gtk_menu_item_get_accel_path (menuitem);
if (accel_path && gtk_accel_map_lookup_entry (accel_path, &key))
{
- GClosure *closure = g_cclosure_new (G_CALLBACK (menu_item_accel_closure_cb), item, NULL);
- gtk_accel_group_connect (gtk_menu_get_accel_group (GTK_MENU (gtk_widget_get_parent (item))),
+ GClosure *closure = g_cclosure_new (G_CALLBACK (panel_item_accel_closure_cb), menuitem, NULL);
+ gtk_accel_group_connect (gtk_menu_get_accel_group (GTK_MENU (gtk_widget_get_parent (GTK_WIDGET (menuitem)))),
key.accel_key, key.accel_mods, key.accel_flags, closure);
g_closure_unref (closure);
}
- GtkWidget* submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (item));
+ GtkWidget* submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menuitem));
if (submenu)
- gtk_container_foreach (GTK_CONTAINER (submenu), (GtkCallback)reassign_menu_item_accel, NULL);
+ gtk_container_foreach (GTK_CONTAINER (submenu), (GtkCallback)panel_reassing_item_accel_cb, NULL);
}
static void
-#ifdef START_INDICATOR_SERVICES
-init_indicators (GKeyFile* config, GPid* indicator_pid, GPid* spi_pid)
-#else
-init_indicators (GKeyFile* config)
-#endif
-{
- gchar **names = NULL;
- gsize length = 0;
- guint i;
- GHashTable *builtin_items = NULL;
- GHashTableIter iter;
- gpointer iter_value;
- #ifdef HAVE_LIBINDICATOR
- gboolean inited = FALSE;
- #endif
- gboolean fallback = FALSE;
-
- const gchar *DEFAULT_LAYOUT[] = {"~host", "~spacer", "~clock", "~spacer",
- "~session", "~language", "~a11y", "~power", NULL};
-
-#ifdef START_INDICATOR_SERVICES
- GError *error = NULL;
- gchar *AT_SPI_CMD[] = {"/usr/lib/at-spi2-core/at-spi-bus-launcher", "--launch-immediately", NULL};
- gchar *INDICATORS_CMD[] = {"init", "--user", "--startup-event", "indicator-services-start", NULL};
-#endif
-
- if (g_key_file_has_key (config, "greeter", "indicators", NULL))
- { /* no option = default list, empty value = empty list */
- names = g_key_file_get_string_list (config, "greeter", "indicators", &length, NULL);
- }
- else if (g_key_file_has_key (config, "greeter", "show-indicators", NULL))
- { /* fallback mode: no option = empty value = default list */
- names = g_key_file_get_string_list (config, "greeter", "show-indicators", &length, NULL);
- if (length == 0)
- fallback = TRUE;
- }
-
- if (!names || fallback)
- {
- names = (gchar**)DEFAULT_LAYOUT;
- length = g_strv_length (names);
- }
-
- builtin_items = g_hash_table_new (g_str_hash, g_str_equal);
-
- g_hash_table_insert (builtin_items, "~power", power_menuitem);
- g_hash_table_insert (builtin_items, "~session", session_menuitem);
- g_hash_table_insert (builtin_items, "~language", language_menuitem);
- g_hash_table_insert (builtin_items, "~a11y", a11y_menuitem);
- g_hash_table_insert (builtin_items, "~layout", layout_menuitem);
- g_hash_table_insert (builtin_items, "~host", host_menuitem);
- g_hash_table_insert (builtin_items, "~clock", clock_menuitem);
-
- g_hash_table_iter_init (&iter, builtin_items);
- while (g_hash_table_iter_next (&iter, NULL, &iter_value))
- gtk_container_remove (GTK_CONTAINER (menubar), iter_value);
-
- for (i = 0; i < length; ++i)
- {
- if (names[i][0] == '~')
- { /* Built-in indicators */
- GreeterPanelItemType item_type = PANEL_ITEM_INDICATOR;
- if (g_hash_table_lookup_extended (builtin_items, names[i], NULL, &iter_value))
- g_hash_table_remove (builtin_items, (gconstpointer)names[i]);
- else if (g_strcmp0 (names[i], "~separator") == 0)
- {
- GtkWidget *separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
- item_type = PANEL_ITEM_SEPARATOR;
- iter_value = gtk_separator_menu_item_new ();
- gtk_widget_show (separator);
- gtk_container_add (iter_value, separator);
- }
- else if (g_strcmp0 (names[i], "~spacer") == 0)
- {
- item_type = PANEL_ITEM_SPACER;
- iter_value = gtk_separator_menu_item_new ();
- gtk_menu_item_set_label (iter_value, "");
- gtk_widget_set_hexpand (iter_value, TRUE);
- }
- else if (names[i][1] == '~')
- {
- item_type = PANEL_ITEM_TEXT;
- iter_value = gtk_separator_menu_item_new ();
- gtk_menu_item_set_label (iter_value, &names[i][2]);
- }
- else
- continue;
-
- g_object_set_data (G_OBJECT (iter_value), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (i));
- panel_add_item (iter_value, i, item_type);
- continue;
- }
-
- #ifdef HAVE_LIBINDICATOR
- gchar* path = NULL;
- IndicatorObject* io = NULL;
-
- if (!inited)
- {
- /* Set indicators to run with reduced functionality */
- greeter_set_env ("INDICATOR_GREETER_MODE", "1");
- /* Don't allow virtual file systems? */
- greeter_set_env ("GIO_USE_VFS", "local");
- greeter_set_env ("GVFS_DISABLE_FUSE", "1");
-
- #ifdef START_INDICATOR_SERVICES
- if (!g_spawn_async (NULL, AT_SPI_CMD, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, spi_pid, &error))
- g_warning ("Failed to run \"at-spi-bus-launcher\": %s", error->message);
- g_clear_error (&error);
-
- if (!g_spawn_async (NULL, INDICATORS_CMD, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, indicator_pid, &error))
- g_warning ("Failed to run \"indicator-services\": %s", error->message);
- g_clear_error (&error);
- #endif
- inited = TRUE;
- }
-
- if (g_path_is_absolute (names[i]))
- { /* library with absolute path */
- io = indicator_object_new_from_file (names[i]);
- }
- else if (g_str_has_suffix (names[i], G_MODULE_SUFFIX))
- { /* library */
- path = g_build_filename (INDICATOR_DIR, names[i], NULL);
- io = indicator_object_new_from_file (path);
- }
- #ifdef HAVE_LIBINDICATOR_NG
- else
- { /* service file */
- if (strchr (names[i], '.'))
- path = g_strdup_printf ("%s/%s", UNITY_INDICATOR_DIR, names[i]);
- else
- path = g_strdup_printf ("%s/com.canonical.indicator.%s", UNITY_INDICATOR_DIR, names[i]);
- io = INDICATOR_OBJECT (indicator_ng_new_for_profile (path, "desktop_greeter", NULL));
- }
- #endif
-
- if (io)
- {
- GList *entries, *lp;
-
- /* used to store/fetch menu entries */
- g_object_set_data_full (G_OBJECT (io), INDICATOR_DATA_MENUITEMS,
- g_hash_table_new (g_direct_hash, g_direct_equal),
- (GDestroyNotify) g_hash_table_destroy);
- g_object_set_data (G_OBJECT (io), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (i));
-
- g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,
- G_CALLBACK (indicator_entry_added_cb), menubar);
- g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED,
- G_CALLBACK (indicator_entry_removed_cb), menubar);
- g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_MENU_SHOW,
- G_CALLBACK (indicator_menu_show_cb), menubar);
-
- entries = indicator_object_get_entries (io);
- for (lp = entries; lp; lp = g_list_next (lp))
- indicator_entry_added_cb (io, lp->data, menubar);
- g_list_free (entries);
- }
- else
- {
- g_warning ("Indicator \"%s\": failed to load", names[i]);
- }
-
- g_free (path);
- #endif
- }
- if (names && names != (gchar**)DEFAULT_LAYOUT)
- g_strfreev (names);
-
- if (builtin_items)
- {
- g_hash_table_iter_init (&iter, builtin_items);
- while (g_hash_table_iter_next (&iter, NULL, &iter_value))
- {
- reassign_menu_item_accel (iter_value);
- gtk_widget_hide (iter_value);
- }
-
- g_hash_table_unref (builtin_items);
- }
+panel_reassing_item_accel_table_cb (const gchar *name, const BuiltinPanelItemInfo *info)
+{
+ if (!gtk_widget_get_parent (info->menuitem))
+ panel_reassing_item_accel_cb (GTK_MENU_ITEM (info->menuitem));
+}
+
+static gboolean
+panel_item_accel_closure_cb (GtkAccelGroup *accel_group, GObject *acceleratable, guint keyval,
+ GdkModifierType modifier, GtkMenuItem *menuitem)
+{
+ gtk_menu_item_activate (menuitem);
+ return FALSE;
+}
+
+static GtkWidget*
+panel_unknown_item_cb (GreeterMenuBar *menubar, const gchar *name, GHashTable *options, gpointer user_data)
+{
+ BuiltinPanelItemInfo *info = g_hash_table_lookup (panel_builtin_items, name);
+ if (!info || info->used)
+ return NULL;
+
+ const gchar **pair;
+ for (pair = info->options; *pair; pair += 2)
+ {
+ const gchar *option = pair[0];
+ const gchar *value = pair[1];
+
+ if (!g_hash_table_contains (options, option))
+ g_hash_table_insert (options, g_strdup (option), g_strdup (value));
+ }
+
+ info->used = TRUE;
+ return info->menuitem;
+}
+
+static gboolean
+panel_unknown_item_option_cb(GreeterMenuBar *menubar, GtkWidget *menuitem,
+ const gchar *name, const gchar *option, const gchar *value, gpointer user_data)
+{
+ if (menuitem == power_menuitem && g_strcmp0 (option, POWER_OPTION_HIDE_DISABLED) == 0)
+ {
+ if (!value || greeter_str_to_bool (value))
+ {
+ g_object_set_data (G_OBJECT (power_menuitem), POWER_DATA_HIDE_DISABLED, GINT_TO_POINTER (TRUE));
+ return TRUE;
+ }
+ }
+ else if (menuitem == clock_menuitem && g_strcmp0 (option, CLOCK_OPTION_CLOCK_FORMAT) == 0)
+ {
+ if (value)
+ {
+ clock_format = g_strdup (value);
+ return clock_format != NULL;
+ }
+ }
+ return FALSE;
}
/* Layout indicator */
@@ -1494,8 +1212,7 @@
if (g_strcmp0 (name, lightdm_layout_get_name (item->data)) == 0)
{
lightdm_set_layout (item->data);
- gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem),
- g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_LABEL));
+ greeter_menu_bar_set_item_text (menubar, layout_menuitem, g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_LABEL));
break;
}
}
@@ -1596,12 +1313,11 @@
if (menu_item)
{
- gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem),
- g_object_get_data (G_OBJECT (menu_item), LAYOUT_DATA_LABEL));
+ greeter_menu_bar_set_item_text (menubar, layout_menuitem, g_object_get_data (G_OBJECT (menu_item), LAYOUT_DATA_LABEL));
gtk_check_menu_item_set_active (menu_item, TRUE);
}
else
- gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), "??");
+ greeter_menu_bar_set_item_text (menubar, layout_menuitem, "??");
g_list_free (menu_items);
#else
LightDMLayout *layout = lightdm_get_layout ();
@@ -1615,8 +1331,7 @@
if (g_strcmp0 (name, g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_NAME)) == 0)
{
gtk_check_menu_item_set_active (menu_iter->data, TRUE);
- gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem),
- g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_LABEL));
+ greeter_menu_bar_set_item_text (menubar, layout_menuitem, g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_LABEL));
break;
}
}
@@ -1653,7 +1368,7 @@
/* a11y indciator */
void
-a11y_font_cb (GtkCheckMenuItem *item)
+a11y_font_cb (GtkCheckMenuItem *item, gpointer user_data)
{
if (gtk_check_menu_item_get_active (item))
{
@@ -1685,7 +1400,7 @@
}
void
-a11y_contrast_cb (GtkCheckMenuItem *item)
+a11y_contrast_cb (GtkCheckMenuItem *item, gpointer user_data)
{
if (gtk_check_menu_item_get_active (item))
{
@@ -1719,13 +1434,16 @@
/* Power indicator */
-static void
-power_menu_cb (GtkWidget *menuitem, gpointer userdata)
+void
+power_menuitem_activate_cb (GtkWidget *menuitem, gpointer userdata)
{
- gtk_widget_set_sensitive (suspend_menuitem, lightdm_get_can_suspend ());
- gtk_widget_set_sensitive (hibernate_menuitem, lightdm_get_can_hibernate ());
- gtk_widget_set_sensitive (restart_menuitem, lightdm_get_can_restart ());
- gtk_widget_set_sensitive (shutdown_menuitem, lightdm_get_can_shutdown ());
+ gboolean hide = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (power_menuitem), POWER_DATA_HIDE_DISABLED));
+ void (*set_state) (GtkWidget*, gboolean) = hide ? gtk_widget_set_visible : gtk_widget_set_sensitive;
+
+ set_state (suspend_menuitem, lightdm_get_can_suspend ());
+ set_state (hibernate_menuitem, lightdm_get_can_hibernate ());
+ set_state (restart_menuitem, lightdm_get_can_restart ());
+ set_state (shutdown_menuitem, lightdm_get_can_shutdown ());
}
void
@@ -2450,17 +2168,11 @@
GKeyFile *config;
GtkBuilder *builder;
const GList *items, *item;
- GtkWidget *image;
gchar *value, **values, *state_dir;
- GtkIconTheme *icon_theme;
GtkCssProvider *css_provider;
GError *error = NULL;
Display *display;
- #ifdef START_INDICATOR_SERVICES
- GPid indicator_pid = 0, spi_pid = 0;
- #endif
-
/* Prevent memory from being swapped out, as we are dealing with passwords */
mlockall (MCL_CURRENT | MCL_FUTURE);
@@ -2476,7 +2188,7 @@
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
- g_unix_signal_add (SIGTERM, (GSourceFunc)gtk_main_quit, NULL);
+ g_unix_signal_add (SIGTERM, sigterm_cb, NULL);
/* init gtk */
gtk_init (&argc, &argv);
@@ -2529,6 +2241,21 @@
XSetScreenSaver (display, screensaver_timeout, 0, ScreenSaverActive, DefaultExposures);
}
+ #ifdef START_INDICATOR_SERVICES
+ gchar *INDICATOR_SEVICES_CMD[] = {"init", "--user", "--startup-event", "indicator-services-start", NULL};
+ if (!spawn_and_remember (INDICATOR_SEVICES_CMD, &error))
+ g_warning ("Failed to run 'indicator-services': %s", error->message);
+ g_clear_error(&error);
+ #endif
+
+ #ifdef START_AT_SPI
+ gchar *AT_SPI_CMD[] = {"/usr/lib/at-spi2-core/at-spi-bus-launcher", "--launch-immediately", NULL};
+ g_setenv ("GTK_MODULES", "atk-bridge", TRUE);
+ if (!spawn_and_remember (AT_SPI_CMD, &error))
+ g_warning ("Failed to run 'at-spi-bus-launcher': %s", error->message);
+ g_clear_error (&error);
+ #endif
+
/* Set GTK+ settings */
value = g_key_file_get_value (config, "greeter", "theme-name", NULL);
if (value)
@@ -2604,7 +2331,7 @@
/* Panel window*/
panel_window = GTK_WIDGET (gtk_builder_get_object (builder, "panel_window"));
- menubar = GTK_WIDGET (gtk_builder_get_object (builder, "menubar"));
+ menubar = GREETER_MENU_BAR (gtk_builder_get_object (builder, "menubar"));
session_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "session_menuitem"));
session_menu = GTK_MENU (gtk_builder_get_object (builder, "session_menu"));
language_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "language_menuitem"));
@@ -2620,6 +2347,31 @@
clock_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "clock_menuitem"));
host_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "host_menuitem"));
+ panel_builtin_items = g_hash_table_new(g_str_hash, g_str_equal);
+
+ const BuiltinPanelItemInfo PANEL_BUILTIN_ITEMS[] =
+ {
+ {.name = "~power", .menuitem = power_menuitem, .options = {"layout", "image", "fallback-image", "#system-shutdown-symbolic", NULL}},
+ {.name = "~session", .menuitem = session_menuitem, .options = {"layout", "image", "fallback-image", "#document-properties-symbolic", NULL}},
+ {.name = "~language", .menuitem = language_menuitem, .options = {"layout", "text", NULL}},
+ {.name = "~a11y", .menuitem = a11y_menuitem, .options = {"layout", "image", "fallback-image", "#preferences-desktop-accessibility-symbolic", NULL}},
+ {.name = "~layout", .menuitem = layout_menuitem, .options = {"layout", "text", NULL}},
+ {.name = "~host", .menuitem = host_menuitem, .options = {"layout", "text", NULL}},
+ {.name = "~clock", .menuitem = clock_menuitem, .options = {"layout", "text", NULL}},
+ {.name = NULL}
+ };
+ const BuiltinPanelItemInfo *builtin_panel_item;
+
+ for (builtin_panel_item = PANEL_BUILTIN_ITEMS; builtin_panel_item->name; ++builtin_panel_item)
+ g_hash_table_insert (panel_builtin_items, (gpointer)builtin_panel_item->name, (gpointer)builtin_panel_item);
+
+ g_signal_connect (G_OBJECT (menubar),
+ GREETER_MENU_BAR_SIGNAL_ITEMS_VISIBILITY_CHANGED, G_CALLBACK (panel_items_visibility_cb), NULL);
+ g_signal_connect (G_OBJECT (menubar),
+ GREETER_MENU_BAR_SIGNAL_UNKNOWN_ITEM, G_CALLBACK (panel_unknown_item_cb), NULL);
+ g_signal_connect (G_OBJECT (menubar),
+ GREETER_MENU_BAR_SIGNAL_UNKNOWN_ITEM_OPTION, G_CALLBACK (panel_unknown_item_option_cb), NULL);
+
/* Power dialog */
power_window = GTK_WIDGET (gtk_builder_get_object (builder, "power_window"));
power_ok_button = GTK_BUTTON (gtk_builder_get_object (builder, "power_ok_button"));
@@ -2629,7 +2381,7 @@
power_icon = GTK_IMAGE (gtk_builder_get_object (builder, "power_icon"));
gtk_overlay_add_overlay (screen_overlay, login_window);
- gtk_overlay_add_overlay (screen_overlay, panel_window);
+ gtk_overlay_add_overlay (screen_overlay, panel_window); /* Hidden without indicators, see panel_item_visibility_changed () */
gtk_overlay_add_overlay (screen_overlay, power_window);
gtk_accel_map_add_entry ("<Login>/a11y/font", GDK_KEY_F1, 0);
@@ -2638,18 +2390,7 @@
gtk_accel_map_add_entry ("<Login>/a11y/reader", GDK_KEY_F4, 0);
gtk_accel_map_add_entry ("<Login>/power/shutdown", GDK_KEY_F4, GDK_MOD1_MASK);
-#ifdef START_INDICATOR_SERVICES
- init_indicators (config, &indicator_pid, &spi_pid);
-#else
- init_indicators (config);
-#endif
-
- /* Hide empty panel */
- GList *menubar_items = gtk_container_get_children (GTK_CONTAINER (menubar));
- if (!menubar_items)
- gtk_widget_hide (GTK_WIDGET (panel_window));
- else
- g_list_free (menubar_items);
+ panel_init (config);
if (g_key_file_get_boolean (config, "greeter", "hide-user-image", NULL))
{
@@ -2677,18 +2418,9 @@
}
}
- icon_theme = gtk_icon_theme_get_default ();
-
/* Session menu */
if (gtk_widget_get_visible (session_menuitem))
{
- if (gtk_icon_theme_has_icon (icon_theme, "document-properties-symbolic"))
- session_badge = gtk_image_new_from_icon_name ("document-properties-symbolic", GTK_ICON_SIZE_MENU);
- else
- session_badge = gtk_image_new_from_icon_name ("document-properties", GTK_ICON_SIZE_MENU);
- gtk_widget_show (session_badge);
- gtk_container_add (GTK_CONTAINER (session_menuitem), session_badge);
-
items = lightdm_get_sessions ();
GSList *sessions = NULL;
for (item = items; item; item = item->next)
@@ -2746,12 +2478,7 @@
/* a11y menu */
if (gtk_widget_get_visible (a11y_menuitem))
{
- if (gtk_icon_theme_has_icon (icon_theme, "preferences-desktop-accessibility-symbolic"))
- image = gtk_image_new_from_icon_name ("preferences-desktop-accessibility-symbolic", GTK_ICON_SIZE_MENU);
- else
- image = gtk_image_new_from_icon_name ("preferences-desktop-accessibility", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image);
- gtk_container_add (GTK_CONTAINER (a11y_menuitem), image);
+ /* Nothing special to do */
}
value = g_key_file_get_value (config, "greeter", "keyboard", NULL);
@@ -2768,19 +2495,10 @@
/* Power menu */
if (gtk_widget_get_visible (power_menuitem))
{
- if (gtk_icon_theme_has_icon (icon_theme, "system-shutdown-symbolic"))
- image = gtk_image_new_from_icon_name ("system-shutdown-symbolic", GTK_ICON_SIZE_MENU);
- else
- image = gtk_image_new_from_icon_name ("system-shutdown", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image);
- gtk_container_add (GTK_CONTAINER (power_menuitem), image);
-
- suspend_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "suspend_menuitem")));
- hibernate_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "hibernate_menuitem")));
- restart_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "restart_menuitem")));
- shutdown_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "shutdown_menuitem")));
-
- g_signal_connect (G_OBJECT (power_menuitem),"activate", G_CALLBACK (power_menu_cb), NULL);
+ suspend_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "suspend_menuitem"));
+ hibernate_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "hibernate_menuitem"));
+ restart_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "restart_menuitem"));
+ shutdown_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "shutdown_menuitem"));
}
/* Layout menu */
@@ -2814,19 +2532,17 @@
}
/* Host label */
- if (gtk_widget_get_visible (host_menuitem))
- gtk_menu_item_set_label (GTK_MENU_ITEM (host_menuitem), lightdm_get_hostname ());
+ greeter_menu_bar_set_item_text (menubar, host_menuitem, lightdm_get_hostname ());
/* Clock label */
if (gtk_widget_get_visible (clock_menuitem))
{
- gtk_menu_item_set_label (GTK_MENU_ITEM (clock_menuitem), "");
- clock_label = gtk_bin_get_child (GTK_BIN (clock_menuitem));
- clock_format = g_key_file_get_value (config, "greeter", "clock-format", NULL);
- if (!clock_format)
- clock_format = "%a, %H:%M";
- clock_timeout_thread ();
- gdk_threads_add_timeout (1000, (GSourceFunc) clock_timeout_thread, NULL);
+ if (!clock_format)
+ clock_format = g_key_file_get_value (config, "greeter", "clock-format", NULL);
+ if (!clock_format)
+ clock_format = g_strdup ("%a, %H:%M");
+ if (clock_timeout_cb (NULL))
+ gdk_threads_add_timeout (1000, clock_timeout_cb, NULL);
}
/* A bit of CSS */
@@ -2887,7 +2603,6 @@
greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "a11y_accelgroup")));
greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "power_accelgroup")));
-
greeter_background_connect (greeter_background, gdk_screen_get_default ());
if (lightdm_greeter_get_hide_users_hint (greeter))
@@ -2911,7 +2626,7 @@
gtk_widget_set_valign (panel_window, GTK_ALIGN_END);
g_free (value);
- if (a11y_keyboard_command)
+ if (a11y_keyboard_command && a11y_keyboard_command->widget)
g_object_set_data_full (G_OBJECT (a11y_keyboard_command->widget), WINDOW_DATA_POSITION,
key_file_get_position (config, "greeter", "keyboard-position", &KEYBOARD_POSITION), g_free);
@@ -2965,19 +2680,8 @@
gtk_main ();
-#ifdef START_INDICATOR_SERVICES
- if (indicator_pid)
- {
- kill (indicator_pid, SIGTERM);
- waitpid (indicator_pid, NULL, 0);
- }
-
- if (spi_pid)
- {
- kill (spi_pid, SIGTERM);
- waitpid (spi_pid, NULL, 0);
- }
-#endif
+ /* It's may be (and must be) already done in SIGTERM handler, anyway */
+ g_slist_free_full (spawned_pids, close_pid_cb);
return EXIT_SUCCESS;
}
=== modified file 'src/lightdm-gtk-greeter.glade'
--- src/lightdm-gtk-greeter.glade 2014-09-24 17:41:33 +0000
+++ src/lightdm-gtk-greeter.glade 2014-10-26 18:59:04 +0000
@@ -7,7 +7,6 @@
<object class="GtkAccelGroup" id="power_accelgroup"/>
<object class="GtkEventBox" id="panel_window">
<property name="name">panel_window</property>
- <property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<child>
@@ -22,6 +21,7 @@
<property name="name">power_menuitem</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <signal name="activate" handler="power_menuitem_activate_cb" swapped="no"/>
<child type="submenu">
<object class="GtkMenu" id="power_menu">
<property name="visible">True</property>
Follow ups