lightdm-gtk-greeter-team team mailing list archive
-
lightdm-gtk-greeter-team team
-
Mailing list archive
-
Message #00550
[Merge] lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/greeter-background into lp:lightdm-gtk-greeter
Andrew P. has proposed merging lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/greeter-background into lp:lightdm-gtk-greeter.
Requested reviews:
LightDM Gtk+ Greeter Development Team (lightdm-gtk-greeter-team)
Related bugs:
Bug #1273922 in LightDM GTK+ Greeter: "Greeter showed on laptop screen instead of external when laptop lid is closed"
https://bugs.launchpad.net/lightdm-gtk-greeter/+bug/1273922
Bug #1314603 in LightDM GTK+ Greeter: "Lightdm greeter on dual monitor system has bad-sized background"
https://bugs.launchpad.net/lightdm-gtk-greeter/+bug/1314603
Bug #1325719 in lightdm-gtk-greeter (Ubuntu): "Login screen wallaper doesn't fill screen"
https://bugs.launchpad.net/ubuntu/+source/lightdm-gtk-greeter/+bug/1325719
For more details, see:
https://code.launchpad.net/~lightdm-gtk-greeter-team/lightdm-gtk-greeter/greeter-background/+merge/225019
Using GreeterBackground class to manage backgrounds.
New syntax for options:
background=monitor_0_background[;monitor_1_background;%named_monitor:named_monitor_background;...]
Last value used for unlisted monitors.
user-background=monitor_0_value[;monitor_1_value;%named_monitor:named_monitor_value;...]
Last value used for unlisted monitors.
New option: active-monitor - used to set monitor for greeter windows.
active-monitor=monitor_name_1;#lid:monitor_name_2;...
#lid:monitor_name - mark "monitor_name" as laptop display. Greeter will be moved to another monitor from the list if lid is closed.
--
https://code.launchpad.net/~lightdm-gtk-greeter-team/lightdm-gtk-greeter/greeter-background/+merge/225019
Your team LightDM Gtk+ Greeter Development Team is requested to review the proposed merge of lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/greeter-background into lp:lightdm-gtk-greeter.
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2014-06-09 15:49:08 +0000
+++ src/Makefile.am 2014-06-30 14:34:14 +0000
@@ -8,6 +8,7 @@
lightdm_gtk_greeter_SOURCES = \
$(lightdm_gtk_greeter_built_sources) \
lightdm-gtk-greeter.c \
+ greeterbackground.c \
greetermenubar.c
AM_CPPFLAGS = \
=== added file 'src/greeterbackground.c'
--- src/greeterbackground.c 1970-01-01 00:00:00 +0000
+++ src/greeterbackground.c 2014-06-30 14:34:14 +0000
@@ -0,0 +1,1354 @@
+
+#include <cairo-xlib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <string.h>
+#include <X11/Xatom.h>
+
+#include "greeterbackground.h"
+
+
+typedef enum
+{
+ /* Broken/uninitialized configuration */
+ BACKGROUND_TYPE_INVALID,
+ /* Do not use this monitor */
+ BACKGROUND_TYPE_SKIP,
+ /* Solid color */
+ BACKGROUND_TYPE_COLOR,
+ /* Path to image and scaling mode */
+ BACKGROUND_TYPE_IMAGE
+} BackgroundType;
+
+static const gchar* BACKGROUND_TYPE_SKIP_VALUE = "#skip";
+
+typedef enum
+{
+ SCALING_MODE_SOURCE,
+ SCALING_MODE_ZOOMED,
+ SCALING_MODE_STRETCHED
+} ScalingMode;
+
+static const gchar* SCALING_MODE_PREFIXES[] = {"#source:", "#zoomed:", "#stretched:", NULL};
+
+/* Background configuration (parsed from background=... option).
+ Used to fill Background */
+typedef struct
+{
+ BackgroundType type;
+ union
+ {
+ #if GTK_CHECK_VERSION (3, 0, 0)
+ GdkRGBA color;
+ #else
+ GdkColor color;
+ #endif
+ struct
+ {
+ gchar *path;
+ ScalingMode mode;
+ } image;
+ } options;
+} BackgroundConfig;
+
+/* Actual drawing information attached to monitor */
+typedef struct
+{
+ BackgroundType type;
+ union
+ {
+ GdkPixbuf* image;
+ #if GTK_CHECK_VERSION (3, 0, 0)
+ GdkRGBA color;
+ #else
+ GdkColor color;
+ #endif
+ } options;
+} Background;
+
+typedef struct
+{
+ gint num;
+ const gchar* name; /* owned by priv->monitors_map */
+ GdkRectangle geometry;
+ GtkWindow* window;
+ gulong window_draw_handler_id;
+
+ const BackgroundConfig* config;
+ Background background_configured;
+ Background background_custom;
+ /* &background_configured or &background_custom */
+ const Background* background;
+} Monitor;
+
+struct _GreeterBackgroundPrivate
+{
+ GdkScreen* screen;
+ gulong screen_monitors_changed_handler_id;
+ /* one-window-gtk3-only
+ GtkWindow* greeter_widget;
+ */
+ GList* greeter_windows;
+ /* Monitor name => BackgroundConfig* */
+ GHashTable* monitors_config;
+ /* Default config for unknown (not in configs) monitors */
+ const BackgroundConfig* monitors_config_default;
+ Monitor* monitors;
+ gsize monitors_size;
+ GHashTable* monitors_map;
+
+ GList* active_monitors_config;
+ const Monitor* active_monitor;
+
+ /* Monitor name => user-background */
+ GHashTable* customized_monitors_config;
+ /* Default user-background value for unknown (not in customized_monitors_config) monitors */
+ gboolean customized_monitors_default;
+ /* List of Monitor* for current screen */
+ GList* customized_monitors;
+
+ /* Lid state handling */
+ GDBusProxy* upower_proxy;
+ gchar* lid_monitor_config;
+ const Monitor* lid_monitor;
+ gboolean lid_state;
+};
+
+enum
+{
+ BACKGROUND_PROP_0,
+ BACKGROUND_PROP_SCREEN,
+ BACKGROUND_PROP_WINDOWS,
+ BACKGROUND_PROP_CUSTOM_BACKGROUND,
+ BACKGROUND_PROP_BACKGROUND_CONFIG, /* background= */
+ BACKGROUND_PROP_CUSTOM_BACKGROUND_CONFIG, /* user-background= */
+ BACKGROUND_PROP_ACTIVE_MONITOR_CONFIG /* active-monitor= */
+};
+
+enum
+{
+ BACKGROUND_SIGNAL_ACTIVE_MONITOR_CHANGED,
+ BACKGROUND_SIGNAL_LAST
+};
+
+static guint background_signals[BACKGROUND_SIGNAL_LAST] = {0};
+
+static const BackgroundConfig DEFAULT_BACKGROUND_CONFIG =
+{
+ .type = BACKGROUND_TYPE_COLOR,
+ .options =
+ {
+ #if GTK_CHECK_VERSION (3, 0, 0)
+ .color = {.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0}
+ #else
+ .color = {.pixel = 0, .red = 0, .green = 0, .blue = 0}
+ #endif
+ }
+};
+
+static const gboolean DEFAULT_USER_BACKGROUND_CONFIG = TRUE;
+
+static const gchar* LAPTOP_MONITOR_PREFIX = "#lid:";
+
+static const gchar* DBUS_UPOWER_NAME = "org.freedesktop.UPower";
+static const gchar* DBUS_UPOWER_PATH = "/org/freedesktop/UPower";
+static const gchar* DBUS_UPOWER_INTERFACE = "org.freedesktop.UPower";
+static const gchar* DBUS_UPOWER_PROP_LID_IS_PRESENT = "LidIsPresent";
+static const gchar* DBUS_UPOWER_PROP_LID_IS_CLOSED = "LidIsClosed";
+
+G_DEFINE_TYPE_WITH_PRIVATE(GreeterBackground, greeter_background, G_TYPE_OBJECT);
+
+static void greeter_background_get_property (GObject* object,
+ guint prop_id,
+ GValue* value,
+ GParamSpec* pspec);
+static void greeter_background_set_property (GObject* object,
+
+ guint prop_id,
+ const GValue* value,
+ GParamSpec* pspec);
+void greeter_background_set_background_config (GreeterBackground* background,
+ const gchar* value);
+void greeter_background_set_custom_background_config(GreeterBackground* background,
+ const gchar* value);
+void greeter_background_set_active_monitor_config (GreeterBackground* background,
+ const gchar* value);
+
+void greeter_background_connect (GreeterBackground* background,
+ GdkScreen* screen);
+void greeter_background_disconnect (GreeterBackground* background);
+static void greeter_background_set_active_monitor (GreeterBackground* background,
+ const Monitor* active);
+static void greeter_background_try_init_dbus (GreeterBackground* background);
+static void greeter_background_stop_dbus (GreeterBackground* background);
+static gboolean greeter_background_monitor_enabled (GreeterBackground* background,
+ const Monitor* monitor);
+static void greeter_background_dbus_changed_cb (GDBusProxy* proxy,
+ GVariant* changed_properties,
+ const gchar* const* invalidated_properties,
+ GreeterBackground* background);
+static void greeter_background_monitors_changed_cb (GdkScreen* screen,
+ GreeterBackground* background);
+
+/* struct BackgroundConfig */
+static gboolean background_config_initialize (BackgroundConfig* config,
+ const gchar* value);
+static void background_config_finalize (BackgroundConfig* config);
+static void background_config_free (BackgroundConfig* config);
+static void background_config_copy (const BackgroundConfig* source,
+ BackgroundConfig* dest);
+
+/* struct Background */
+static gboolean background_initialize (Background* bg,
+ const BackgroundConfig* config,
+ const Monitor* monitor,
+ GHashTable* images_cache);
+static void background_finalize (Background* bg);
+
+/* struct Monitor */
+static void monitor_finalize (Monitor* info);
+static void monitor_set_background (Monitor* monitor,
+ const Background* background);
+static void monitor_draw_background (const Monitor* monitor,
+ cairo_t* cr);
+#if GTK_CHECK_VERSION(3, 0, 0)
+static gboolean monitor_window_draw_cb (GtkWidget* widget,
+ cairo_t* cr,
+ const Monitor* monitor);
+static gboolean monitor_subwindow_draw_cb (GtkWidget* widget,
+ cairo_t* cr,
+ GreeterBackground* background);
+#else
+static gboolean monitor_window_expose_cb (GtkWidget* widget,
+ GdkEventExpose *event,
+ const Monitor* monitor);
+#endif
+
+static gchar* parse_monitor_name_from_config (const gchar** value,
+ gint* num);
+static GdkPixbuf* scale_image_file (const gchar* path,
+ ScalingMode mode,
+ gint width, gint height,
+ GHashTable* cache);
+static GdkPixbuf* scale_image (GdkPixbuf* source,
+ ScalingMode mode,
+ gint width, gint height);
+static cairo_surface_t* create_root_surface (GdkScreen* screen);
+static void set_root_pixmap_id (GdkScreen* screen,
+ Display* display,
+ Pixmap xpixmap);
+static void set_surface_as_root (GdkScreen* screen,
+ cairo_surface_t* surface);
+
+
+/* Implementation */
+
+static void
+greeter_background_class_init(GreeterBackgroundClass* klass)
+{
+ GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->get_property = greeter_background_get_property;
+ gobject_class->set_property = greeter_background_set_property;
+
+ g_object_class_install_property(gobject_class, BACKGROUND_PROP_SCREEN,
+ g_param_spec_object("screen", "screen", "Screen",
+ GDK_TYPE_SCREEN, G_PARAM_READWRITE));
+ /*
+ g_object_class_install_property(gobject_class, BACKGROUND_PROP_GREETER_WIDGET,
+ g_param_spec_object("greeter-widget", "greeter-widget", "Greeter widget",
+ GTK_TYPE_WINDOW, G_PARAM_READWRITE));
+ */
+ g_object_class_install_property(gobject_class, BACKGROUND_PROP_WINDOWS,
+ g_param_spec_pointer("windows", "Windows", "Greeter windows",
+ G_PARAM_READWRITE));
+ g_object_class_install_property(gobject_class, BACKGROUND_PROP_CUSTOM_BACKGROUND,
+ g_param_spec_string("custom-background", "custom-background",
+ "Custom background", NULL, G_PARAM_WRITABLE));
+ g_object_class_install_property(gobject_class, BACKGROUND_PROP_BACKGROUND_CONFIG,
+ g_param_spec_string("background-config", "background-config",
+ "background= option", NULL, G_PARAM_WRITABLE));
+ g_object_class_install_property(gobject_class, BACKGROUND_PROP_CUSTOM_BACKGROUND_CONFIG,
+ g_param_spec_string("custom-background-config", "custom-background-config",
+ "user-background= option", NULL, G_PARAM_WRITABLE));
+ g_object_class_install_property(gobject_class, BACKGROUND_PROP_BACKGROUND_CONFIG,
+ g_param_spec_string("active-monitor-config", "active-monitor-config",
+ "active-monitor= option", NULL, G_PARAM_WRITABLE));
+
+ background_signals[BACKGROUND_SIGNAL_ACTIVE_MONITOR_CHANGED] =
+ g_signal_new("active-monitor-changed",
+ G_TYPE_FROM_CLASS(gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, /* class_offset */
+ NULL /* accumulator */, NULL /* accu_data */,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+greeter_background_init(GreeterBackground* self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, GREETER_BACKGROUND_TYPE, GreeterBackgroundPrivate);
+ self->priv->screen = NULL;
+ self->priv->screen_monitors_changed_handler_id = 0;
+ self->priv->greeter_windows = NULL;
+ self->priv->monitors_config = NULL;
+ self->priv->monitors_config_default = &DEFAULT_BACKGROUND_CONFIG;
+ self->priv->monitors = NULL;
+ self->priv->monitors_size = 0;
+ self->priv->monitors_map = NULL;
+ self->priv->customized_monitors_config = NULL;
+ self->priv->customized_monitors_default = DEFAULT_USER_BACKGROUND_CONFIG;
+ self->priv->customized_monitors = NULL;
+ self->priv->active_monitors_config = NULL;
+ self->priv->active_monitor = NULL;
+ self->priv->upower_proxy = NULL;
+ self->priv->lid_monitor_config = NULL;
+ self->priv->lid_monitor = NULL;
+}
+
+GreeterBackground*
+greeter_background_new(void)
+{
+ return GREETER_BACKGROUND(g_object_new(greeter_background_get_type(), NULL));
+}
+
+static void
+greeter_background_get_property(GObject* object,
+ guint prop_id,
+ GValue* value,
+ GParamSpec* pspec)
+{
+ GreeterBackground* background = GREETER_BACKGROUND(object);
+ switch(prop_id)
+ {
+ case BACKGROUND_PROP_SCREEN:
+ g_value_set_object(value, background->priv->screen);
+ break;
+ case BACKGROUND_PROP_WINDOWS:
+ g_value_set_pointer(value, background->priv->greeter_windows);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+greeter_background_set_property(GObject* object,
+ guint prop_id,
+ const GValue* value,
+ GParamSpec* pspec)
+{
+ GreeterBackground* background = GREETER_BACKGROUND(object);
+ switch(prop_id)
+ {
+ case BACKGROUND_PROP_SCREEN:
+ greeter_background_connect(background, GDK_SCREEN(g_value_get_object(value)));
+ break;
+ case BACKGROUND_PROP_CUSTOM_BACKGROUND:
+ greeter_background_set_custom_background(background, g_value_get_string(value));
+ break;
+ case BACKGROUND_PROP_BACKGROUND_CONFIG:
+ greeter_background_set_background_config(background, g_value_get_string(value));
+ break;
+ case BACKGROUND_PROP_CUSTOM_BACKGROUND_CONFIG:
+ greeter_background_set_custom_background_config(background, g_value_get_string(value));
+ break;
+ case BACKGROUND_PROP_ACTIVE_MONITOR_CONFIG:
+ greeter_background_set_active_monitor_config(background, g_value_get_string(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+void
+greeter_background_set_background_config(GreeterBackground* background,
+ const gchar* value)
+{
+ g_debug("%s: %s", __FUNCTION__, value);
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+ GreeterBackgroundPrivate* priv = background->priv;
+
+ if(priv->monitors_config)
+ g_hash_table_unref(priv->monitors_config);
+ priv->monitors_config = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)background_config_free);
+ priv->monitors_config_default = &DEFAULT_BACKGROUND_CONFIG;
+
+ if(!value || strlen(value) == 0)
+ return;
+
+ gchar** values = g_strsplit(value, ";", -1);
+ gchar** iter;
+ gint num = 0;
+ for(iter = values; *iter; ++iter)
+ {
+ const gchar* value = *iter;
+ gchar* name = parse_monitor_name_from_config(&value, &num);
+ BackgroundConfig* config = g_new0(BackgroundConfig, 1);
+
+ if(!background_config_initialize(config, value))
+ background_config_copy(priv->monitors_config_default, config);
+
+ priv->monitors_config_default = config;
+ g_hash_table_insert(priv->monitors_config, name, config);
+ }
+ g_strfreev(values);
+}
+
+void
+greeter_background_set_custom_background_config(GreeterBackground* background,
+ const gchar* value)
+{
+ g_debug("%s: %s", __FUNCTION__, value);
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+ GreeterBackgroundPrivate* priv = background->priv;
+
+ if(priv->customized_monitors_config)
+ g_hash_table_unref(priv->customized_monitors_config);
+ priv->customized_monitors_config = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+ priv->customized_monitors_default = DEFAULT_USER_BACKGROUND_CONFIG;
+
+ if(!value || strlen(value) == 0)
+ return;
+
+ gchar** values = g_strsplit(value, ";", -1);
+ gchar** iter;
+ gint num = 0;
+ for(iter = values; *iter; ++iter)
+ {
+ const gchar* value = *iter;
+ gchar* name = parse_monitor_name_from_config(&value, &num);
+ gboolean bool_value = g_ascii_strcasecmp(value, "true") == 0 || g_strcmp0(value, "1") == 0;
+ priv->customized_monitors_default = bool_value;
+ g_hash_table_insert(priv->customized_monitors_config, name, GINT_TO_POINTER(bool_value));
+ }
+ g_strfreev(values);
+}
+
+void
+greeter_background_set_active_monitor_config(GreeterBackground* background,
+ const gchar* value)
+{
+ g_debug("%s: %s", __FUNCTION__, value);
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+ GreeterBackgroundPrivate* priv = background->priv;
+
+ if(priv->active_monitors_config)
+ g_list_free_full(priv->active_monitors_config, g_free);
+ g_free(priv->lid_monitor_config);
+ priv->active_monitors_config = NULL;
+ /* Do not modify current state: priv->active_monitor = NULL; */
+ priv->lid_monitor_config = NULL;
+
+ if(!value || strlen(value) == 0)
+ return;
+
+ gchar** values = g_strsplit(value, ";", -1);
+ gchar** iter;
+
+ for(iter = values; *iter; ++iter)
+ {
+ const gchar* value = *iter;
+ if(g_str_has_prefix(value, LAPTOP_MONITOR_PREFIX))
+ {
+ value += strlen(LAPTOP_MONITOR_PREFIX);
+ if(!priv->lid_monitor_config) /* Use only first occurrence */
+ priv->lid_monitor_config = g_strdup(value);
+ }
+ priv->active_monitors_config = g_list_prepend(priv->active_monitors_config, g_strdup(value));
+ }
+ priv->active_monitors_config = g_list_reverse(priv->active_monitors_config);
+ g_strfreev(values);
+ g_debug("lid monitor: %s", priv->lid_monitor_config);
+}
+
+void
+greeter_background_connect(GreeterBackground* background,
+ GdkScreen* screen)
+{
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+ g_return_if_fail(GDK_IS_SCREEN(screen));
+ g_debug("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);
+
+ priv->screen = screen;
+ priv->monitors_size = gdk_screen_get_n_monitors(screen);
+ priv->monitors = g_new0(Monitor, priv->monitors_size);
+ priv->monitors_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+
+ /* Used to track situation when all monitors marked as "#skip" */
+ Monitor* first_not_skipped_monitor = NULL;
+
+ GHashTable* images_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ gint i;
+ for(i = 0; i < priv->monitors_size; ++i)
+ {
+ Monitor* monitor = &priv->monitors[i];
+ gchar* monitor_name = gdk_screen_get_monitor_plug_name(screen, i);
+ gchar* monitor_num_str = g_strdup_printf("%d", i);
+ const BackgroundConfig* config = monitor_name ? g_hash_table_lookup(priv->monitors_config, monitor_name) : NULL;
+
+ monitor->num = i;
+ monitor->name = monitor_name;
+
+ if(!config)
+ {
+ config = g_hash_table_lookup(priv->monitors_config, monitor_num_str);
+ if(!config)
+ {
+ g_debug("No configuration options for monitor %s #%d, using default", monitor_name, i);
+ config = priv->monitors_config_default;
+ }
+ }
+
+ gdk_screen_get_monitor_geometry(screen, i, &monitor->geometry);
+
+ g_debug("Monitor: %s #%d (%dx%d at %dx%d)%s",
+ monitor_name ? monitor_name : "<unknown>", i,
+ monitor->geometry.width, monitor->geometry.height,
+ monitor->geometry.x, monitor->geometry.y,
+ (i == gdk_screen_get_primary_monitor(screen)) ? " primary" : "");
+
+ /* Force last skipped monitor to be active monitor, if there is no other choice */
+ if(config->type == BACKGROUND_TYPE_SKIP)
+ {
+ if(i < priv->monitors_size - 1 || first_not_skipped_monitor)
+ continue;
+ config = &DEFAULT_BACKGROUND_CONFIG;
+ }
+
+ if(!first_not_skipped_monitor)
+ first_not_skipped_monitor = monitor;
+ monitor->config = config;
+ monitor->window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
+ gtk_window_set_type_hint(monitor->window, GDK_WINDOW_TYPE_HINT_DESKTOP);
+ gtk_window_set_keep_below(monitor->window, TRUE);
+ gtk_window_set_resizable(monitor->window, FALSE);
+ gtk_widget_set_app_paintable(GTK_WIDGET(monitor->window), TRUE);
+ gtk_window_set_screen(monitor->window, screen);
+ gtk_widget_set_size_request(GTK_WIDGET(monitor->window), monitor->geometry.width, monitor->geometry.height);
+ gtk_window_move(monitor->window, monitor->geometry.x, monitor->geometry.y);
+ gtk_widget_show(GTK_WIDGET(monitor->window));
+ #if GTK_CHECK_VERSION(3, 0, 0)
+ monitor->window_draw_handler_id = g_signal_connect(G_OBJECT(monitor->window), "draw",
+ G_CALLBACK(monitor_window_draw_cb),
+ monitor);
+ #else
+ monitor->window_draw_handler_id = g_signal_connect(G_OBJECT(monitor->window), "expose-event",
+ G_CALLBACK(monitor_window_expose_cb),
+ monitor);
+ #endif
+
+ if(priv->lid_monitor_config && (g_strcmp0(priv->lid_monitor_config, monitor_name) == 0 ||
+ g_strcmp0(priv->lid_monitor_config, monitor_num_str) == 0))
+ priv->lid_monitor = monitor;
+
+ gpointer customized = GINT_TO_POINTER(priv->customized_monitors_default);
+ if(priv->customized_monitors_config)
+ {
+ if(!monitor_name || !g_hash_table_lookup_extended(priv->customized_monitors_config, monitor_name, NULL, &customized))
+ g_hash_table_lookup_extended(priv->customized_monitors_config, monitor_num_str, NULL, &customized);
+ }
+
+ if(GPOINTER_TO_INT(customized))
+ priv->customized_monitors = g_list_prepend(priv->customized_monitors, monitor);
+
+ if(!background_initialize(&monitor->background_configured, monitor->config, monitor, images_cache))
+ background_initialize(&monitor->background_configured, &DEFAULT_BACKGROUND_CONFIG, monitor, images_cache);
+ monitor_set_background(monitor, &monitor->background_configured);
+
+ if(monitor_name)
+ g_hash_table_insert(priv->monitors_map, monitor_name, monitor);
+ g_hash_table_insert(priv->monitors_map, monitor_num_str, monitor);
+ }
+ g_hash_table_unref(images_cache);
+
+ if(priv->lid_monitor && !priv->upower_proxy)
+ greeter_background_try_init_dbus(background);
+ else if(!priv->lid_monitor)
+ greeter_background_stop_dbus(background);
+
+ 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);
+}
+
+void
+greeter_background_disconnect(GreeterBackground* background)
+{
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+
+ GreeterBackgroundPrivate* priv = background->priv;
+
+ gsize i;
+ for(i = 0; i < priv->monitors_size; ++i)
+ monitor_finalize(&priv->monitors[i]);
+ g_free(priv->monitors);
+ if(priv->monitors_map)
+ g_hash_table_unref(priv->monitors_map);
+ g_list_free(priv->customized_monitors);
+ if(priv->screen_monitors_changed_handler_id)
+ g_signal_handler_disconnect(priv->screen, priv->screen_monitors_changed_handler_id);
+
+ priv->screen = NULL;
+ priv->screen_monitors_changed_handler_id = 0;
+ priv->monitors = NULL;
+ priv->monitors_size = 0;
+ priv->monitors_map = NULL;
+ priv->customized_monitors = NULL;
+ priv->active_monitor = NULL;
+ priv->lid_monitor = NULL;
+}
+
+static void
+greeter_background_set_active_monitor(GreeterBackground* background,
+ const Monitor* active)
+{
+ GreeterBackgroundPrivate* priv = background->priv;
+
+ if(!active)
+ {
+ /* Normal way: at least one configured active monitor is not disabled */
+ GList* iter;
+ for(iter = priv->active_monitors_config; iter && !active; iter = g_list_next(iter))
+ {
+ const Monitor* monitor = g_hash_table_lookup(priv->monitors_map, iter->data);
+ if(monitor && monitor->config->type != BACKGROUND_TYPE_SKIP &&
+ greeter_background_monitor_enabled(background, monitor))
+ active = monitor;
+ }
+
+ /* All monitors listed in active-monitor-config are disabled (or option is empty) */
+
+ /* Using primary monitor */
+ if(!active)
+ {
+ active = &priv->monitors[gdk_screen_get_primary_monitor(priv->screen)];
+ if(active->config->type == BACKGROUND_TYPE_SKIP ||
+ !greeter_background_monitor_enabled(background, active))
+ active = NULL;
+ }
+
+ /* Fallback: first enabled and/or not skipped monitor (screen always have one) */
+ if(!active)
+ {
+ gint i;
+ const Monitor* first_not_skipped = NULL;
+ for(i = 0; i < priv->monitors_size && !active; ++i)
+ {
+ const Monitor* monitor = &priv->monitors[i];
+ if(monitor->config->type == BACKGROUND_TYPE_SKIP)
+ continue;
+ if(greeter_background_monitor_enabled(background, monitor))
+ active = monitor;
+ if(!first_not_skipped)
+ first_not_skipped = active;
+ }
+ if(!active)
+ active = first_not_skipped;
+ }
+ }
+
+ if(active == priv->active_monitor)
+ return;
+
+ priv->active_monitor = active;
+ g_debug("Active monitor changed: %s #%d", active->name, active->num);
+ g_signal_emit(background, background_signals[BACKGROUND_SIGNAL_ACTIVE_MONITOR_CHANGED], 0);
+
+ gint x, y;
+
+ GdkDisplay* display = gtk_widget_get_display(GTK_WIDGET(active->window));
+ #if GTK_CHECK_VERSION(3, 0, 0)
+ GdkDeviceManager* device_manager = gdk_display_get_device_manager(display);
+ GdkDevice* device = gdk_device_manager_get_client_pointer(device_manager);
+ gdk_device_get_position(device, NULL, &x, &y);
+ #else
+ gdk_display_get_pointer(display, NULL, &x, &y, NULL);
+ #endif
+
+ /* Do not center cursor if it is already inside active monitor */
+ if(x < active->geometry.x || x >= active->geometry.x + active->geometry.width ||
+ y < active->geometry.y || y >= active->geometry.y + active->geometry.height)
+ {
+ x = active->geometry.x + active->geometry.width/2;
+ y = active->geometry.y + active->geometry.height/2;
+ #if GTK_CHECK_VERSION(3, 0, 0)
+ gdk_device_warp(gdk_device_manager_get_client_pointer(device_manager), priv->screen, x, y);
+ #else
+ gdk_display_warp_pointer(display, priv->screen, x, y);
+ #endif
+ }
+
+ /* Toggle to bring active monitor background up */
+ gtk_widget_hide(GTK_WIDGET(active->window));
+ gtk_widget_show(GTK_WIDGET(active->window));
+
+ /* Update greeter windows */
+ GList* iter;
+ for(iter = priv->greeter_windows; iter; iter = g_list_next(iter))
+ {
+ gtk_window_set_screen(GTK_WINDOW(iter->data), priv->screen);
+ if(gtk_widget_get_visible(GTK_WIDGET(iter->data)))
+ { /* Toggle window visibility to place window above of any 'background' windows */
+ gtk_widget_hide(GTK_WIDGET(iter->data));
+ gtk_widget_show(GTK_WIDGET(iter->data));
+ gtk_widget_queue_resize(GTK_WIDGET(iter->data));
+ }
+ }
+}
+
+static void
+greeter_background_try_init_dbus(GreeterBackground* background)
+{
+ g_debug("Creating DBus proxy");
+ GError* error = NULL;
+ GreeterBackgroundPrivate* priv = background->priv;
+
+ if(priv->upower_proxy)
+ greeter_background_stop_dbus(background);
+
+ priv->upower_proxy = g_dbus_proxy_new_for_bus_sync(
+ G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL, /* interface info */
+ DBUS_UPOWER_NAME,
+ DBUS_UPOWER_PATH,
+ DBUS_UPOWER_INTERFACE,
+ NULL, /* cancellable */
+ &error);
+ if(!priv->upower_proxy)
+ {
+ if(error)
+ g_warning("Failed to create dbus proxy: %s", error->message);
+ g_clear_error(&error);
+ return;
+ }
+
+ GVariant* variant = g_dbus_proxy_get_cached_property(priv->upower_proxy, DBUS_UPOWER_PROP_LID_IS_PRESENT);
+ gboolean lid_present = g_variant_get_boolean(variant);
+ g_variant_unref(variant);
+
+ g_debug("%s property value: %d", DBUS_UPOWER_PROP_LID_IS_PRESENT, lid_present);
+
+ if(!lid_present)
+ greeter_background_stop_dbus(background);
+ else
+ {
+ variant = g_dbus_proxy_get_cached_property(priv->upower_proxy, DBUS_UPOWER_PROP_LID_IS_CLOSED);
+ priv->lid_state = !g_variant_get_boolean(variant);
+ g_variant_unref(variant);
+
+ g_signal_connect(priv->upower_proxy, "g-properties-changed",
+ G_CALLBACK(greeter_background_dbus_changed_cb), background);
+ }
+}
+
+static void
+greeter_background_stop_dbus(GreeterBackground* background)
+{
+ if(!background->priv->upower_proxy)
+ return;
+ g_object_unref(background->priv->upower_proxy);
+ background->priv->upower_proxy = NULL;
+}
+
+static gboolean
+greeter_background_monitor_enabled(GreeterBackground* background,
+ const Monitor* monitor)
+{
+ GreeterBackgroundPrivate* priv = background->priv;
+
+ if(priv->upower_proxy && priv->lid_monitor && priv->lid_monitor == monitor)
+ return priv->lid_state;
+ return TRUE;
+}
+
+static void
+greeter_background_dbus_changed_cb(GDBusProxy* proxy,
+ GVariant* changed_properties,
+ const gchar* const* invalidated_properties,
+ GreeterBackground* background)
+{
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+ GreeterBackgroundPrivate* priv = background->priv;
+
+ GVariant* variant = g_dbus_proxy_get_cached_property(priv->upower_proxy, DBUS_UPOWER_PROP_LID_IS_CLOSED);
+ gboolean new_state = !g_variant_get_boolean(variant);
+ g_variant_unref(variant);
+
+ if(new_state == priv->lid_state)
+ return;
+
+ g_debug("lid state changed: %s", priv->lid_state ? "opened" : "closed");
+
+ priv->lid_state = new_state;
+ if(priv->lid_monitor)
+ greeter_background_set_active_monitor(background, NULL);
+}
+
+static void
+greeter_background_monitors_changed_cb(GdkScreen* screen,
+ GreeterBackground* background)
+{
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+ greeter_background_connect(background, screen);
+}
+
+void greeter_background_add_subwindow(GreeterBackground* background,
+ GtkWindow* window)
+{
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+ g_return_if_fail(GTK_IS_WINDOW(window));
+
+ GreeterBackgroundPrivate* priv = background->priv;
+
+ if(!g_list_find(priv->greeter_windows, window))
+ {
+ priv->greeter_windows = g_list_prepend(priv->greeter_windows, window);
+ #if GTK_CHECK_VERSION (3, 0, 0)
+ g_signal_connect(G_OBJECT(window), "draw", G_CALLBACK(monitor_subwindow_draw_cb), background);
+ #endif
+ }
+
+ if(priv->screen)
+ gtk_window_set_screen(window, priv->screen);
+}
+
+void greeter_background_remove_subwindow(GreeterBackground* background,
+ GtkWindow* window)
+{
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+ g_return_if_fail(GTK_IS_WINDOW(window));
+
+ GreeterBackgroundPrivate* priv = background->priv;
+
+ GList* item = g_list_find(priv->greeter_windows, window);
+ if(item)
+ {
+ #if GTK_CHECK_VERSION (3, 0, 0)
+ g_object_disconnect(G_OBJECT(window),
+ "any-signal", G_CALLBACK(monitor_subwindow_draw_cb), background,
+ NULL);
+ #endif
+ priv->greeter_windows = g_list_delete_link(priv->greeter_windows, item);
+ }
+}
+
+void
+greeter_background_set_custom_background(GreeterBackground* background,
+ const gchar* value)
+{
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+
+ GreeterBackgroundPrivate* priv = background->priv;
+ if(!priv->customized_monitors)
+ return;
+
+ BackgroundConfig config;
+ background_config_initialize(&config, value);
+
+ GHashTable *images_cache = NULL;
+ if(config.type == BACKGROUND_TYPE_IMAGE)
+ images_cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
+
+ GList* iter;
+ for(iter = priv->customized_monitors; iter; iter = g_list_next(iter))
+ {
+ Monitor *monitor = iter->data;
+
+ background_finalize(&monitor->background_custom);
+ if(config.type != BACKGROUND_TYPE_INVALID &&
+ background_initialize(&monitor->background_custom, &config, monitor, images_cache))
+ monitor_set_background(monitor, &monitor->background_custom);
+ else
+ monitor_set_background(monitor, &monitor->background_configured);
+ }
+
+ if(images_cache)
+ g_hash_table_destroy(images_cache);
+ if(config.type != BACKGROUND_TYPE_INVALID)
+ background_config_finalize(&config);
+
+ for(iter = priv->greeter_windows; iter; iter = g_list_next(iter))
+ gtk_widget_queue_draw(GTK_WIDGET(iter->data));
+}
+
+void
+greeter_background_save_xroot(GreeterBackground* background)
+{
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+
+ GreeterBackgroundPrivate* priv = background->priv;
+ cairo_surface_t* surface = create_root_surface(priv->screen);
+ cairo_t* cr = cairo_create(surface);
+ gsize i;
+
+ for(i = 0; i <= priv->monitors_size; ++i)
+ {
+ const Monitor* monitor = &priv->monitors[i];
+ if(monitor == priv->active_monitor)
+ continue;
+ else if(i == priv->monitors_size)
+ monitor = priv->active_monitor;
+ cairo_save(cr);
+ cairo_translate(cr, monitor->geometry.x, monitor->geometry.y);
+ monitor_draw_background(monitor, cr);
+ cairo_restore(cr);
+ }
+ set_surface_as_root(priv->screen, surface);
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+}
+
+const GdkRectangle*
+greeter_background_get_active_monitor_geometry(GreeterBackground* background)
+{
+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
+ GreeterBackgroundPrivate* priv = background->priv;
+
+ return priv->active_monitor ? &priv->active_monitor->geometry : NULL;
+}
+
+static gboolean
+background_config_initialize(BackgroundConfig* config,
+ const gchar* value)
+{
+ config->type = BACKGROUND_TYPE_INVALID;
+ if(!value || strlen(value) == 0)
+ return FALSE;
+ if(g_strcmp0(value, BACKGROUND_TYPE_SKIP_VALUE) == 0)
+ config->type = BACKGROUND_TYPE_SKIP;
+ #if GTK_CHECK_VERSION (3, 0, 0)
+ else if(gdk_rgba_parse(&config->options.color, value))
+ #else
+ else if(gdk_color_parse(value, &config->options.color))
+ #endif
+ config->type = BACKGROUND_TYPE_COLOR;
+ else
+ {
+ const gchar** prefix = SCALING_MODE_PREFIXES;
+ while(*prefix && !g_str_has_prefix(value, *prefix))
+ ++prefix;
+
+ if(*prefix)
+ {
+ config->options.image.mode = (ScalingMode)(prefix - SCALING_MODE_PREFIXES);
+ value += strlen(*prefix);
+ }
+ else
+ config->options.image.mode = SCALING_MODE_ZOOMED;
+ config->options.image.path = g_strdup(value);
+ config->type = BACKGROUND_TYPE_IMAGE;
+ }
+ return TRUE;
+}
+
+static void
+background_config_finalize(BackgroundConfig* config)
+{
+ if(config->type == BACKGROUND_TYPE_IMAGE)
+ g_free(config->options.image.path);
+ config->type = BACKGROUND_TYPE_INVALID;
+}
+
+static void
+background_config_free(BackgroundConfig* config)
+{
+ background_config_finalize(config);
+ g_free(config);
+}
+
+static void
+background_config_copy(const BackgroundConfig* source,
+ BackgroundConfig* dest)
+{
+ dest->type = source->type;
+ if(source->type == BACKGROUND_TYPE_IMAGE)
+ dest->options.image.path = g_strdup(source->options.image.path);
+ else if(source->type == BACKGROUND_TYPE_COLOR)
+ dest->options.color = source->options.color;
+}
+
+static gboolean
+background_initialize(Background* bg,
+ const BackgroundConfig* config,
+ const Monitor* monitor,
+ GHashTable* images_cache)
+{
+ if(config->type == BACKGROUND_TYPE_IMAGE)
+ {
+ GdkPixbuf* pixbuf = scale_image_file(config->options.image.path,
+ config->options.image.mode,
+ monitor->geometry.width, monitor->geometry.height,
+ images_cache);
+ if(!pixbuf)
+ {
+ g_warning("Failed to read wallpaper: %s", config->options.image.path);
+ return FALSE;
+ }
+ bg->options.image = pixbuf;
+ }
+ else if(config->type == BACKGROUND_TYPE_COLOR)
+ bg->options.color = config->options.color;
+ else
+ return FALSE;
+ bg->type = config->type;
+ return TRUE;
+}
+
+static void
+background_finalize(Background* bg)
+{
+ if(bg->type == BACKGROUND_TYPE_IMAGE && bg->options.image)
+ g_object_unref(bg->options.image);
+ bg->type = BACKGROUND_TYPE_INVALID;
+}
+
+static void
+monitor_set_background(Monitor* monitor,
+ const Background* background)
+{
+ monitor->background = background;
+ gtk_widget_queue_draw(GTK_WIDGET(monitor->window));
+}
+
+static void
+monitor_finalize(Monitor* monitor)
+{
+ background_finalize(&monitor->background_configured);
+ background_finalize(&monitor->background_custom);
+ if(monitor->window_draw_handler_id)
+ g_signal_handler_disconnect(monitor->window, monitor->window_draw_handler_id);
+ if(monitor->window)
+ gtk_widget_destroy(GTK_WIDGET(monitor->window));
+ monitor->window = NULL;
+ monitor->window_draw_handler_id = 0;
+}
+
+static void
+monitor_draw_background(const Monitor* monitor,
+ cairo_t* cr)
+{
+ if(monitor->background->type == BACKGROUND_TYPE_IMAGE && monitor->background->options.image)
+ {
+ gdk_cairo_set_source_pixbuf(cr, monitor->background->options.image, 0, 0);
+ cairo_paint(cr);
+ }
+ else if(monitor->background->type == BACKGROUND_TYPE_COLOR)
+ {
+ cairo_rectangle(cr, 0, 0, monitor->geometry.width, monitor->geometry.height);
+ #if GTK_CHECK_VERSION (3, 0, 0)
+ gdk_cairo_set_source_rgba(cr, &monitor->background->options.color);
+ #else
+ gdk_cairo_set_source_color(cr, &monitor->background->options.color);
+ #endif
+ cairo_fill(cr);
+ }
+}
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+static gboolean
+monitor_window_draw_cb(GtkWidget* widget,
+ cairo_t* cr,
+ const Monitor* monitor)
+#else
+static gboolean
+monitor_window_expose_cb(GtkWidget* widget,
+ GdkEventExpose *event,
+ const Monitor* monitor)
+#endif
+{
+ if(monitor)
+ {
+ #if GTK_CHECK_VERSION (3, 0, 0)
+ monitor_draw_background(monitor, cr);
+ #else
+ cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget));
+ monitor_draw_background(monitor, cr);
+ cairo_destroy(cr);
+ #endif
+ }
+ return FALSE;
+}
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+static gboolean
+monitor_subwindow_draw_cb(GtkWidget* widget,
+ cairo_t* cr,
+ GreeterBackground* background)
+{
+ g_return_val_if_fail(GREETER_IS_BACKGROUND(background), FALSE);
+ if(background->priv->active_monitor)
+ {
+ const GdkRectangle* geometry = &background->priv->active_monitor->geometry;
+ gint x = 0, y = 0;
+ gtk_window_get_position(GTK_WINDOW(widget), &x, &y);
+
+ cairo_save(cr);
+ cairo_translate(cr, geometry->x - x, geometry->y - y);
+ monitor_draw_background(background->priv->active_monitor, cr);
+ cairo_restore(cr);
+ }
+ return FALSE;
+}
+#endif
+
+static gchar*
+parse_monitor_name_from_config(const gchar** value, gint* num)
+{
+ if(*value && g_str_has_prefix(*value, "%"))
+ {
+ gchar* delim = g_strstr_len(*value, -1, ":");
+ if(delim)
+ {
+ gchar* name = g_strndup(*value + 1, delim - *value - 1);
+ *value = delim + 1;
+ return name;
+ }
+ }
+ (*num)++;
+ return g_strdup_printf("%d", *num - 1);
+}
+
+static GdkPixbuf*
+scale_image_file(const gchar* path,
+ ScalingMode mode,
+ gint width, gint height,
+ GHashTable* cache)
+{
+ gchar* key = NULL;
+ GdkPixbuf* pixbuf = NULL;
+ if(cache)
+ {
+ key = g_strdup_printf("%s\n%d %dx%d", path, mode, width, height);
+ if (g_hash_table_lookup_extended(cache, key, NULL, (gpointer*)&pixbuf))
+ return GDK_PIXBUF(g_object_ref(pixbuf));
+ }
+
+ if (!cache || !g_hash_table_lookup_extended(cache, path, NULL, (gpointer*)&pixbuf))
+ {
+ GError *error = NULL;
+ pixbuf = gdk_pixbuf_new_from_file(path, &error);
+ if(error)
+ {
+ g_warning("Failed to load background: %s", error->message);
+ g_clear_error(&error);
+ }
+ if(cache)
+ g_hash_table_insert(cache, g_strdup (path), g_object_ref (pixbuf));
+ }
+
+ if(pixbuf)
+ {
+ GdkPixbuf* scaled = scale_image(pixbuf, mode, width, height);
+ if (cache)
+ g_hash_table_insert(cache, g_strdup(key), g_object_ref(scaled));
+ g_object_unref(pixbuf);
+ pixbuf = scaled;
+ }
+
+ return pixbuf;
+}
+
+static GdkPixbuf*
+scale_image(GdkPixbuf* source,
+ ScalingMode mode,
+ gint width, gint height)
+{
+ if(mode == SCALING_MODE_ZOOMED)
+ {
+ gint offset_x = 0;
+ gint offset_y = 0;
+ gint p_width = gdk_pixbuf_get_width(source);
+ gint p_height = gdk_pixbuf_get_height(source);
+ gdouble scale_x = (gdouble)width / p_width;
+ gdouble scale_y = (gdouble)height / p_height;
+
+ if(scale_x < scale_y)
+ {
+ scale_x = scale_y;
+ offset_x = (width - (p_width * scale_x)) / 2;
+ }
+ else
+ {
+ scale_y = scale_x;
+ offset_y = (height - (p_height * scale_y)) / 2;
+ }
+
+ GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE,
+ gdk_pixbuf_get_bits_per_sample (source),
+ width, height);
+ gdk_pixbuf_composite(source, pixbuf, 0, 0, width, height,
+ offset_x, offset_y, scale_x, scale_y, GDK_INTERP_BILINEAR, 0xFF);
+ return pixbuf;
+ }
+ else if(mode == SCALING_MODE_STRETCHED)
+ {
+ return gdk_pixbuf_scale_simple(source, width, height, GDK_INTERP_BILINEAR);
+ }
+ return GDK_PIXBUF(g_object_ref(source));
+}
+
+/* The following code for setting a RetainPermanent background pixmap was taken
+ originally from Gnome, with some fixes from MATE. see:
+ https://github.com/mate-desktop/mate-desktop/blob/master/libmate-desktop/mate-bg.c */
+static cairo_surface_t*
+create_root_surface(GdkScreen* screen)
+{
+ gint number, width, height;
+ Display *display;
+ Pixmap pixmap;
+ cairo_surface_t *surface;
+
+ number = gdk_screen_get_number (screen);
+ width = gdk_screen_get_width (screen);
+ height = gdk_screen_get_height (screen);
+
+ /* Open a new connection so with Retain Permanent so the pixmap remains when the greeter quits */
+ gdk_flush ();
+ display = XOpenDisplay (gdk_display_get_name (gdk_screen_get_display (screen)));
+ if (!display)
+ {
+ g_warning ("Failed to create root pixmap");
+ return NULL;
+ }
+
+ XSetCloseDownMode (display, RetainPermanent);
+ pixmap = XCreatePixmap (display, RootWindow (display, number), width, height, DefaultDepth (display, number));
+ XCloseDisplay (display);
+
+ /* Convert into a Cairo surface */
+ surface = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (screen),
+ pixmap,
+ GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)),
+ width, height);
+
+ return surface;
+}
+
+/* Sets the "ESETROOT_PMAP_ID" property to later be used to free the pixmap */
+static void
+set_root_pixmap_id(GdkScreen* screen,
+ Display* display,
+ Pixmap xpixmap)
+{
+
+ Window xroot = RootWindow (display, gdk_screen_get_number (screen));
+ char atom_name_xrootmap[] = "_XROOTPMAP_ID";
+ char atom_name_esetroot[] = "ESETROOT_PMAP_ID";
+ char *atom_names[] = {atom_name_xrootmap, atom_name_esetroot};
+ Atom atoms[G_N_ELEMENTS(atom_names)] = {0};
+
+ Atom type;
+ int format;
+ unsigned long nitems, after;
+ unsigned char *data_root, *data_esetroot;
+
+ /* Get atoms for both properties in an array, only if they exist.
+ * This method is to avoid multiple round-trips to Xserver
+ */
+ if (XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), True, atoms) &&
+ atoms[0] != None && atoms[1] != None)
+ {
+
+ XGetWindowProperty (display, xroot, atoms[0], 0L, 1L, False, AnyPropertyType,
+ &type, &format, &nitems, &after, &data_root);
+ if (data_root && type == XA_PIXMAP && format == 32 && nitems == 1)
+ {
+ XGetWindowProperty (display, xroot, atoms[1], 0L, 1L, False, AnyPropertyType,
+ &type, &format, &nitems, &after, &data_esetroot);
+ if (data_esetroot && type == XA_PIXMAP && format == 32 && nitems == 1)
+ {
+ Pixmap xrootpmap = *((Pixmap *) data_root);
+ Pixmap esetrootpmap = *((Pixmap *) data_esetroot);
+ XFree (data_root);
+ XFree (data_esetroot);
+
+ gdk_error_trap_push ();
+ if (xrootpmap && xrootpmap == esetrootpmap) {
+ XKillClient (display, xrootpmap);
+ }
+ if (esetrootpmap && esetrootpmap != xrootpmap) {
+ XKillClient (display, esetrootpmap);
+ }
+
+ XSync (display, False);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ gdk_error_trap_pop_ignored ();
+#else
+ gdk_error_trap_pop ();
+#endif
+ }
+ }
+ }
+
+ /* Get atoms for both properties in an array, create them if needed.
+ * This method is to avoid multiple round-trips to Xserver
+ */
+ 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");
+ return;
+ }
+
+ /* Set new _XROOTMAP_ID and ESETROOT_PMAP_ID properties */
+ XChangeProperty (display, xroot, atoms[0], XA_PIXMAP, 32,
+ PropModeReplace, (unsigned char *) &xpixmap, 1);
+
+ XChangeProperty (display, xroot, atoms[1], XA_PIXMAP, 32,
+ PropModeReplace, (unsigned char *) &xpixmap, 1);
+}
+
+/**
+* set_surface_as_root:
+* @screen: the #GdkScreen to change root background on
+* @surface: the #cairo_surface_t to set root background from.
+* Must be an xlib surface backing a pixmap.
+*
+* Set the root pixmap, and properties pointing to it. We
+* do this atomically with a server grab to make sure that
+* we won't leak the pixmap if somebody else it setting
+* it at the same time. (This assumes that they follow the
+* same conventions we do). @surface should come from a call
+* to create_root_surface().
+**/
+static void
+set_surface_as_root(GdkScreen* screen,
+ cairo_surface_t* surface)
+{
+ g_return_if_fail(cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB);
+
+ /* Desktop background pixmap should be created from dummy X client since most
+ * applications will try to kill it with XKillClient later when changing pixmap
+ */
+ Display *display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
+ Pixmap pixmap_id = cairo_xlib_surface_get_drawable (surface);
+ Window xroot = RootWindow (display, gdk_screen_get_number(screen));
+
+ XGrabServer (display);
+
+ XSetWindowBackgroundPixmap (display, xroot, pixmap_id);
+ set_root_pixmap_id (screen, display, pixmap_id);
+ XClearWindow (display, xroot);
+
+ XFlush (display);
+ XUngrabServer (display);
+}
=== added file 'src/greeterbackground.h'
--- src/greeterbackground.h 1970-01-01 00:00:00 +0000
+++ src/greeterbackground.h 2014-06-30 14:34:14 +0000
@@ -0,0 +1,52 @@
+#ifndef GREETER_BACKGROUND_H
+#define GREETER_BACKGROUND_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GREETER_BACKGROUND_TYPE (greeter_background_get_type())
+#define GREETER_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GREETER_BACKGROUND_TYPE, GreeterBackground))
+#define GREETER_BACKGROUND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GREETER_BACKGROUND_TYPE, GreeterBackgroundClass))
+#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))
+
+typedef struct _GreeterBackground GreeterBackground;
+typedef struct _GreeterBackgroundClass GreeterBackgroundClass;
+typedef struct _GreeterBackgroundPrivate GreeterBackgroundPrivate;
+
+struct _GreeterBackground
+{
+ GObject parent_instance;
+ struct _GreeterBackgroundPrivate* priv;
+};
+
+struct _GreeterBackgroundClass
+{
+ GObjectClass parent_class;
+};
+
+GType greeter_background_get_type(void) G_GNUC_CONST;
+
+GreeterBackground* greeter_background_new (void);
+void greeter_background_set_background_config (GreeterBackground* background,
+ const gchar* value);
+void greeter_background_set_custom_background_config(GreeterBackground* background,
+ const gchar* value);
+void greeter_background_set_active_monitor_config (GreeterBackground* background,
+ const gchar* value);
+void greeter_background_connect (GreeterBackground* background,
+ GdkScreen* screen);
+void greeter_background_add_subwindow (GreeterBackground* background,
+ GtkWindow* window);
+void greeter_background_remove_subwindow (GreeterBackground* background,
+ GtkWindow* window);
+void greeter_background_set_custom_background (GreeterBackground* background,
+ const gchar* path);
+void greeter_background_save_xroot (GreeterBackground* background);
+const GdkRectangle* greeter_background_get_active_monitor_geometry(GreeterBackground* background);
+
+G_END_DECLS
+
+#endif // GREETER_BACKGROUND_H
=== modified file 'src/lightdm-gtk-greeter.c'
--- src/lightdm-gtk-greeter.c 2014-06-09 15:49:08 +0000
+++ src/lightdm-gtk-greeter.c 2014-06-30 14:34:14 +0000
@@ -20,15 +20,11 @@
#include <glib-unix.h>
#include <locale.h>
+#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
-#include <cairo-xlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
-#include <X11/Xlib.h>
-#include <X11/Xatom.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gdk/gdkx.h>
#include <glib.h>
#if GTK_CHECK_VERSION (3, 0, 0)
#include <gtk/gtkx.h>
@@ -56,6 +52,7 @@
#include <lightdm.h>
#include "src/greetermenubar.h"
+#include "src/greeterbackground.h"
#include "src/lightdm-gtk-greeter-ui.h"
#if GTK_CHECK_VERSION (3, 0, 0)
@@ -69,8 +66,6 @@
/* Defaults */
static gchar *default_font_name, *default_theme_name, *default_icon_theme_name;
-static GdkPixbuf *default_background_pixbuf = NULL;
-static GdkPixbuf *background_pixbuf = NULL;
/* Panel Widgets */
static GtkWindow *panel_window;
@@ -99,8 +94,6 @@
/* Pending Questions */
static GSList *pending_questions = NULL;
-GSList *backgrounds = NULL;
-
/* Current choices */
static gchar *current_session;
static gchar *current_language;
@@ -108,11 +101,8 @@
/* Screensaver values */
int timeout, interval, prefer_blanking, allow_exposures;
-#if GTK_CHECK_VERSION (3, 0, 0)
-static GdkRGBA *default_background_color = NULL;
-#else
-static GdkColor *default_background_color = NULL;
-#endif
+static GreeterBackground *greeter_background;
+
static gboolean cancelling = FALSE, prompted = FALSE;
static gboolean prompt_active = FALSE, password_prompted = FALSE;
#if GTK_CHECK_VERSION (3, 0, 0)
@@ -146,14 +136,14 @@
DimensionPosition x, y;
} WindowPosition;
-static const WindowPosition CENTERED_WINDOW_POS = { .x = {50, +1, TRUE, 0}, .y = {50, +1, TRUE, 0} };
+static const WindowPosition WINDOW_POS_CENTER = {.x = {50, +1, TRUE, 0}, .y = {50, +1, TRUE, 0}};
+static const WindowPosition WINDOW_POS_TOP_LEFT = {.x = {0, +1, FALSE, -1}, .y = {0, +1, FALSE, -1}};
static WindowPosition main_window_pos;
+static WindowPosition panel_window_pos;
static GdkPixbuf* default_user_pixbuf = NULL;
static gchar* default_user_icon = "avatar-default";
-static gboolean use_user_background = TRUE;
-
static const gchar *LAYOUT_DATA_LABEL = "layout-label";
#ifdef HAVE_LIBXKLAVIER
static const gchar *LAYOUT_DATA_GROUP = "layout-group";
@@ -442,8 +432,9 @@
g_closure_unref (closure);
}
- gtk_container_foreach (GTK_CONTAINER (gtk_menu_item_get_submenu (GTK_MENU_ITEM (item))),
- (GtkCallback)reassign_menu_item_accel, NULL);
+ GtkWidget* submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (item));
+ if(submenu)
+ gtk_container_foreach (GTK_CONTAINER (submenu), (GtkCallback)reassign_menu_item_accel, NULL);
}
static void
@@ -817,34 +808,17 @@
gtk_widget_set_sensitive (GTK_WIDGET (language_menuitem), !logged_in);
}
-static void set_background (GdkPixbuf *new_bg);
-
static void
set_user_background (const gchar *username)
{
- LightDMUser *user;
- const gchar *path;
- GdkPixbuf *bg = NULL;
- GError *error = NULL;
-
- user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
- if (user)
+ const gchar *path = NULL;
+ if (username)
{
- path = lightdm_user_get_background (user);
- if (path)
- {
- bg = gdk_pixbuf_new_from_file (path, &error);
- if (!bg)
- {
- g_warning ("Failed to load user background: %s", error->message);
- g_clear_error (&error);
- }
- }
+ LightDMUser *user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
+ if (user)
+ path = lightdm_user_get_background (user);
}
-
- set_background (bg);
- if (bg)
- g_object_unref (bg);
+ greeter_background_set_custom_background(greeter_background, path);
}
static void
@@ -903,58 +877,39 @@
}
static void
-center_window (GtkWindow *window, GtkAllocation *unused, const WindowPosition *pos)
+center_window (GtkWindow *window, GtkAllocation *allocation, const WindowPosition *pos)
{
- GdkScreen *screen = gtk_window_get_screen (window);
- GtkAllocation allocation;
- GdkRectangle monitor_geometry;
-
- gdk_screen_get_monitor_geometry (screen, gdk_screen_get_primary_monitor (screen), &monitor_geometry);
- gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
- gtk_window_move (window,
- monitor_geometry.x + get_absolute_position (&pos->x, monitor_geometry.width, allocation.width),
- monitor_geometry.y + get_absolute_position (&pos->y, monitor_geometry.height, allocation.height));
-}
-
-#if GTK_CHECK_VERSION (3, 0, 0)
-/* Use the much simpler fake transparency by drawing the window background with Cairo for Gtk3 */
-static gboolean
-background_window_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data)
-{
- if (background_pixbuf)
- gdk_cairo_set_source_pixbuf (cr, background_pixbuf, 0, 0);
- else
- gdk_cairo_set_source_rgba (cr, default_background_color);
- cairo_paint (cr);
- return FALSE;
-}
-
-static gboolean
-login_window_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data)
-{
- GdkScreen *screen = gtk_window_get_screen (GTK_WINDOW(widget));
- GtkAllocation *allocation = g_new0 (GtkAllocation, 1);
- GdkRectangle monitor_geometry;
- gint x,y;
-
- if (background_pixbuf)
- {
- gdk_screen_get_monitor_geometry (screen, gdk_screen_get_primary_monitor (screen), &monitor_geometry);
- gtk_widget_get_allocation (widget, allocation);
- x = get_absolute_position (&main_window_pos.x, monitor_geometry.width, allocation->width);
- y = get_absolute_position (&main_window_pos.y, monitor_geometry.height, allocation->height);
- gdk_cairo_set_source_pixbuf (cr, background_pixbuf, monitor_geometry.x - x, monitor_geometry.y - y);
- }
- else
- gdk_cairo_set_source_rgba (cr, default_background_color);
-
- cairo_paint (cr);
-
- g_free (allocation);
- return FALSE;
-}
-
-#else
+ const GdkRectangle *monitor_geometry = greeter_background_get_active_monitor_geometry (greeter_background);
+ GtkAllocation *new_allocation = NULL;
+ if (!allocation)
+ {
+ allocation = new_allocation = g_new0 (GtkAllocation, 1);
+ gtk_widget_get_allocation (GTK_WIDGET (window), new_allocation);
+ }
+ if (monitor_geometry)
+ gtk_window_move (window,
+ monitor_geometry->x + get_absolute_position (&pos->x, monitor_geometry->width, allocation->width),
+ monitor_geometry->y + get_absolute_position (&pos->y, monitor_geometry->height, allocation->height));
+ g_free (new_allocation);
+}
+
+static void
+active_monitor_changed_cb(GreeterBackground* background, gpointer user_data)
+{
+ const GdkRectangle *monitor_geometry = greeter_background_get_active_monitor_geometry (greeter_background);
+ if (monitor_geometry)
+ {
+ GdkGeometry hints;
+ hints.min_width = monitor_geometry->width;
+ hints.max_width = monitor_geometry->width;
+ hints.min_height = -1;
+ hints.max_height = -1;
+ gtk_window_set_geometry_hints (panel_window, GTK_WIDGET(panel_window),
+ &hints, GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
+ }
+}
+
+#if !GTK_CHECK_VERSION (3, 0, 0)
static GdkRegion *
cairo_region_from_rectangle (gint width, gint height, gint radius)
{
@@ -1021,20 +976,6 @@
return TRUE;
}
-
-static gboolean
-background_window_expose (GtkWidget *widget,
- GdkEventExpose *event,
- gpointer user_data)
-{
- cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
- if (background_pixbuf)
- gdk_cairo_set_source_pixbuf (cr, background_pixbuf, 0, 0);
- else
- gdk_cairo_set_source_color (cr, default_background_color);
- cairo_paint (cr);
- return FALSE;
-}
#endif
static void
@@ -1164,6 +1105,8 @@
/* Remember last choice */
g_key_file_set_value (state, "greeter", "last-session", session);
+ greeter_background_save_xroot (greeter_background);
+
data = g_key_file_to_data (state, &data_length, &error);
if (error)
g_warning ("Failed to save state file: %s", error->message);
@@ -1370,8 +1313,7 @@
}
set_login_button_label (greeter, username);
- if (use_user_background)
- set_user_background (username);
+ set_user_background (username);
set_user_image (username);
user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
if (user)
@@ -1655,22 +1597,22 @@
gtk_style_context_add_class(GTK_STYLE_CONTEXT(gtk_widget_get_style_context(GTK_WIDGET(dialog))), "lightdm-gtk-greeter");
#endif
gtk_widget_set_name(dialog, dialog_name);
-#if GTK_CHECK_VERSION (3, 0, 0)
- g_signal_connect (G_OBJECT (dialog), "draw", G_CALLBACK (login_window_draw), NULL);
-#else
+ gtk_container_set_border_width(GTK_CONTAINER (dialog), 18);
+#if !GTK_CHECK_VERSION (3, 0, 0)
g_signal_connect (G_OBJECT (dialog), "size-allocate", G_CALLBACK (login_window_size_allocate), NULL);
#endif
- gtk_container_set_border_width(GTK_CONTAINER (dialog), 18);
-
+ greeter_background_add_subwindow(greeter_background, GTK_WINDOW (dialog));
/* Hide the login window and show the dialog */
gtk_widget_hide (GTK_WIDGET (login_window));
gtk_widget_show_all (dialog);
- center_window (GTK_WINDOW (dialog), NULL, &CENTERED_WINDOW_POS);
+ center_window (GTK_WINDOW (dialog), NULL, &WINDOW_POS_CENTER);
result = gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK;
+ greeter_background_remove_subwindow(greeter_background, GTK_WINDOW (dialog));
gtk_widget_destroy (dialog);
gtk_widget_show (GTK_WIDGET (login_window));
+ gtk_widget_queue_resize(GTK_WIDGET (login_window));
return result;
}
@@ -2001,253 +1943,6 @@
g_free (last_user);
}
-/* The following code for setting a RetainPermanent background pixmap was taken
- originally from Gnome, with some fixes from MATE. see:
- https://github.com/mate-desktop/mate-desktop/blob/master/libmate-desktop/mate-bg.c */
-static cairo_surface_t *
-create_root_surface (GdkScreen *screen)
-{
- gint number, width, height;
- Display *display;
- Pixmap pixmap;
- cairo_surface_t *surface;
-
- number = gdk_screen_get_number (screen);
- width = gdk_screen_get_width (screen);
- height = gdk_screen_get_height (screen);
-
- /* Open a new connection so with Retain Permanent so the pixmap remains when the greeter quits */
- gdk_flush ();
- display = XOpenDisplay (gdk_display_get_name (gdk_screen_get_display (screen)));
- if (!display)
- {
- g_warning ("Failed to create root pixmap");
- return NULL;
- }
-
- XSetCloseDownMode (display, RetainPermanent);
- pixmap = XCreatePixmap (display, RootWindow (display, number), width, height, DefaultDepth (display, number));
- XCloseDisplay (display);
-
- /* Convert into a Cairo surface */
- surface = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (screen),
- pixmap,
- GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)),
- width, height);
-
- return surface;
-}
-
-/* Sets the "ESETROOT_PMAP_ID" property to later be used to free the pixmap,
-*/
-static void
-set_root_pixmap_id (GdkScreen *screen,
- 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};
-
- Atom type;
- int format;
- unsigned long nitems, after;
- unsigned char *data_root, *data_esetroot;
-
- /* Get atoms for both properties in an array, only if they exist.
- * This method is to avoid multiple round-trips to Xserver
- */
- if (XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), True, atoms) &&
- atoms[0] != None && atoms[1] != None)
- {
-
- XGetWindowProperty (display, xroot, atoms[0], 0L, 1L, False, AnyPropertyType,
- &type, &format, &nitems, &after, &data_root);
- if (data_root && type == XA_PIXMAP && format == 32 && nitems == 1)
- {
- XGetWindowProperty (display, xroot, atoms[1], 0L, 1L, False, AnyPropertyType,
- &type, &format, &nitems, &after, &data_esetroot);
- if (data_esetroot && type == XA_PIXMAP && format == 32 && nitems == 1)
- {
- Pixmap xrootpmap = *((Pixmap *) data_root);
- Pixmap esetrootpmap = *((Pixmap *) data_esetroot);
- XFree (data_root);
- XFree (data_esetroot);
-
- gdk_error_trap_push ();
- if (xrootpmap && xrootpmap == esetrootpmap) {
- XKillClient (display, xrootpmap);
- }
- if (esetrootpmap && esetrootpmap != xrootpmap) {
- XKillClient (display, esetrootpmap);
- }
-
- XSync (display, False);
-#if GTK_CHECK_VERSION (3, 0, 0)
- gdk_error_trap_pop_ignored ();
-#else
- gdk_error_trap_pop ();
-#endif
-
- }
- }
- }
-
- /* Get atoms for both properties in an array, create them if needed.
- * This method is to avoid multiple round-trips to Xserver
- */
- 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");
- return;
- }
-
- /* Set new _XROOTMAP_ID and ESETROOT_PMAP_ID properties */
- XChangeProperty (display, xroot, atoms[0], XA_PIXMAP, 32,
- PropModeReplace, (unsigned char *) &xpixmap, 1);
-
- XChangeProperty (display, xroot, atoms[1], XA_PIXMAP, 32,
- PropModeReplace, (unsigned char *) &xpixmap, 1);
-}
-
-/**
-* set_surface_as_root:
-* @screen: the #GdkScreen to change root background on
-* @surface: the #cairo_surface_t to set root background from.
-* Must be an xlib surface backing a pixmap.
-*
-* Set the root pixmap, and properties pointing to it. We
-* do this atomically with a server grab to make sure that
-* we won't leak the pixmap if somebody else it setting
-* it at the same time. (This assumes that they follow the
-* same conventions we do). @surface should come from a call
-* to create_root_surface().
-**/
-static void
-set_surface_as_root (GdkScreen *screen, cairo_surface_t *surface)
-{
- g_return_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB);
-
- /* Desktop background pixmap should be created from dummy X client since most
- * applications will try to kill it with XKillClient later when changing pixmap
- */
- Display *display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
- Pixmap pixmap_id = cairo_xlib_surface_get_drawable (surface);
- Window xroot = RootWindow (display, gdk_screen_get_number (screen));
-
- XGrabServer (display);
-
- XSetWindowBackgroundPixmap (display, xroot, pixmap_id);
- set_root_pixmap_id (screen, display, pixmap_id);
- XClearWindow (display, xroot);
-
- XFlush (display);
- XUngrabServer (display);
-}
-
-static void
-set_background (GdkPixbuf *new_bg)
-{
- GdkRectangle monitor_geometry;
- GdkPixbuf *bg = NULL, *p = NULL;
- GSList *iter;
- gint i, p_height, p_width, offset_x, offset_y;
- gdouble scale_x, scale_y, scale;
- GdkInterpType interp_type;
- gint num_screens = 1;
-
- if (new_bg)
- bg = new_bg;
- else
- bg = default_background_pixbuf;
-
- #if GDK_VERSION_CUR_STABLE < G_ENCODE_VERSION(3, 10)
- num_screens = gdk_display_get_n_screens (gdk_display_get_default ());
- #endif
-
- /* Set the background */
- for (i = 0; i < num_screens; i++)
- {
- GdkScreen *screen;
- cairo_surface_t *surface;
- cairo_t *c;
- gint monitor;
-
- screen = gdk_display_get_screen (gdk_display_get_default (), i);
- surface = create_root_surface (screen);
- c = cairo_create (surface);
-
- for (monitor = 0; monitor < gdk_screen_get_n_monitors (screen); monitor++)
- {
- gdk_screen_get_monitor_geometry (screen, monitor, &monitor_geometry);
-
- if (bg)
- {
- p_width = gdk_pixbuf_get_width (bg);
- p_height = gdk_pixbuf_get_height (bg);
-
- scale_x = (gdouble)monitor_geometry.width / p_width;
- scale_y = (gdouble)monitor_geometry.height / p_height;
-
- if (scale_x < scale_y)
- {
- scale = scale_y;
- offset_x = (monitor_geometry.width - (p_width * scale)) / 2;
- offset_y = 0;
- }
- else
- {
- scale = scale_x;
- offset_x = 0;
- offset_y = (monitor_geometry.height - (p_height * scale)) / 2;
- }
-
- p = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, gdk_pixbuf_get_bits_per_sample (bg),
- monitor_geometry.width, monitor_geometry.height);
-
- /* Set interpolation type */
- if (monitor_geometry.width == p_width && monitor_geometry.height == p_height)
- interp_type = GDK_INTERP_NEAREST;
- else
- interp_type = GDK_INTERP_BILINEAR;
-
- /* Zoom the background pixbuf to fit the screen */
- gdk_pixbuf_composite (bg, p, 0, 0, monitor_geometry.width, monitor_geometry.height,
- offset_x, offset_y, scale, scale, interp_type, 255);
-
- gdk_cairo_set_source_pixbuf (c, p, monitor_geometry.x, monitor_geometry.y);
-
- /* Make the background pixbuf globally accessible so it can be reused for fake transparency */
- if (background_pixbuf)
- g_object_unref (background_pixbuf);
-
- background_pixbuf = p;
- }
- else
- {
-#if GTK_CHECK_VERSION (3, 0, 0)
- gdk_cairo_set_source_rgba (c, default_background_color);
-#else
- gdk_cairo_set_source_color (c, default_background_color);
-#endif
- background_pixbuf = NULL;
- }
- cairo_paint (c);
- iter = g_slist_nth (backgrounds, monitor);
- gtk_widget_queue_draw (GTK_WIDGET (iter->data));
- }
-
- cairo_destroy (c);
-
- /* Refresh background */
- gdk_flush ();
- set_surface_as_root (screen, surface);
- cairo_surface_destroy (surface);
- }
- gtk_widget_queue_draw (GTK_WIDGET (login_window));
- gtk_widget_queue_draw (GTK_WIDGET (panel_window));
-}
-
static gboolean
clock_timeout_thread (void)
{
@@ -2536,20 +2231,11 @@
GtkWidget *image, *infobar_compat, *content_area;
gchar *value, *state_dir;
#if GTK_CHECK_VERSION (3, 0, 0)
- GdkRGBA background_color;
GtkIconTheme *icon_theme;
GtkCssProvider *css_provider;
-#else
- GdkColor background_color;
#endif
GError *error = NULL;
- /* Background windows */
- gint monitor, scr;
- gint numScreens = 1;
- GdkScreen *screen;
- GtkWidget *window;
-
Display* display;
#ifdef START_INDICATOR_SERVICES
@@ -2611,47 +2297,6 @@
/* Set default cursor */
gdk_window_set_cursor (gdk_get_default_root_window (), gdk_cursor_new (GDK_LEFT_PTR));
- /* Load background */
- value = g_key_file_get_value (config, "greeter", "background", NULL);
- if (!value)
- value = g_strdup ("#000000");
-#if GTK_CHECK_VERSION (3, 0, 0)
- if (!gdk_rgba_parse (&background_color, value))
-#else
- if (!gdk_color_parse (value, &background_color))
-#endif
- {
- gchar *path;
- GError *error = NULL;
-
- if (g_path_is_absolute (value))
- path = g_strdup (value);
- else
- path = g_build_filename (GREETER_DATA_DIR, value, NULL);
-
- g_debug ("Loading background %s", path);
- default_background_pixbuf = gdk_pixbuf_new_from_file (path, &error);
- if (!default_background_pixbuf)
- g_warning ("Failed to load background: %s", error->message);
- g_clear_error (&error);
- g_free (path);
- }
- else
- {
- g_debug ("Using background color %s", value);
-#if GTK_CHECK_VERSION (3, 0, 0)
- default_background_color = gdk_rgba_copy (&background_color);
-#else
- default_background_color = gdk_color_copy (&background_color);
-#endif
- }
- g_free (value);
-
- use_user_background = g_key_file_get_boolean(config, "greeter", "user-background", &error);
- if (error)
- use_user_background = TRUE;
- g_clear_error(&error);
-
/* Make the greeter behave a bit more like a screensaver if used as un/lock-screen by blanking the screen */
gchar* end_ptr = NULL;
int screensaver_timeout = 60;
@@ -2739,7 +2384,6 @@
#if GTK_CHECK_VERSION (3, 0, 0)
gtk_style_context_add_class(GTK_STYLE_CONTEXT(gtk_widget_get_style_context(GTK_WIDGET(panel_window))), "lightdm-gtk-greeter");
gtk_style_context_add_class(GTK_STYLE_CONTEXT(gtk_widget_get_style_context(GTK_WIDGET(panel_window))), GTK_STYLE_CLASS_MENUBAR);
- g_signal_connect (G_OBJECT (panel_window), "draw", G_CALLBACK (background_window_draw), NULL);
#endif
menubar = GTK_WIDGET (gtk_builder_get_object (builder, "menubar"));
@@ -2750,6 +2394,10 @@
username_entry = GTK_ENTRY (gtk_builder_get_object (builder, "username_entry"));
password_entry = GTK_ENTRY (gtk_builder_get_object (builder, "password_entry"));
+#if !GTK_CHECK_VERSION (3, 0, 0)
+ g_signal_connect (G_OBJECT (login_window), "size-allocate", G_CALLBACK (login_window_size_allocate), NULL);
+#endif
+
/* Add InfoBar via code for GTK+2 compatability */
infobar_compat = GTK_WIDGET(gtk_builder_get_object(builder, "infobar_compat"));
info_bar = GTK_INFO_BAR (gtk_info_bar_new());
@@ -2768,12 +2416,6 @@
cancel_button = GTK_BUTTON (gtk_builder_get_object (builder, "cancel_button"));
login_button = GTK_BUTTON (gtk_builder_get_object (builder, "login_button"));
-#if GTK_CHECK_VERSION (3, 0, 0)
- g_signal_connect (G_OBJECT (login_window), "draw", G_CALLBACK (login_window_draw), NULL);
-#else
- g_signal_connect (G_OBJECT (login_window), "size-allocate", G_CALLBACK (login_window_size_allocate), NULL);
-#endif
-
/* To maintain compatability with GTK+2, set special properties here */
#if GTK_CHECK_VERSION (3, 0, 0)
gtk_style_context_add_class(GTK_STYLE_CONTEXT(gtk_widget_get_style_context(GTK_WIDGET(login_window))), "lightdm-gtk-greeter");
@@ -2853,7 +2495,7 @@
{
LightDMSession *session = item->data;
GtkWidget *radiomenuitem;
-
+
radiomenuitem = gtk_radio_menu_item_new_with_label (sessions, lightdm_session_get_name (session));
g_object_set_data (G_OBJECT (radiomenuitem), "session-key", (gpointer) lightdm_session_get_key (session));
sessions = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radiomenuitem));
@@ -2986,6 +2628,7 @@
#if GTK_CHECK_VERSION (3, 0, 0)
/* A bit of CSS */
+ GdkRGBA lightdm_gtk_greeter_override_defaults;
css_provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_application, lightdm_gtk_greeter_css_application_length, NULL);
gtk_style_context_add_provider_for_screen(gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider),
@@ -2994,77 +2637,53 @@
guint fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_APPLICATION;
if (gtk_style_context_lookup_color (gtk_widget_get_style_context (GTK_WIDGET (login_window)),
"lightdm-gtk-greeter-override-defaults",
- &background_color))
+ &lightdm_gtk_greeter_override_defaults))
fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_FALLBACK;
gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_fallback, lightdm_gtk_greeter_css_fallback_length, NULL);
gtk_style_context_add_provider_for_screen(gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider),
fallback_css_priority);
#endif
+ /* Background */
+ greeter_background = greeter_background_new ();
+ g_signal_connect (G_OBJECT (greeter_background), "active-monitor-changed", G_CALLBACK(active_monitor_changed_cb), NULL);
+
+ value = g_key_file_get_value (config, "greeter", "background", NULL);
+ greeter_background_set_background_config (greeter_background, value);
+ g_free (value);
+
+ value = g_key_file_get_value (config, "greeter", "user-background", NULL);
+ greeter_background_set_custom_background_config (greeter_background, value);
+ g_free (value);
+
+ value = g_key_file_get_value (config, "greeter", "active-monitor", NULL);
+ greeter_background_set_active_monitor_config (greeter_background, value);
+ g_free (value);
+
+ greeter_background_add_subwindow (greeter_background, login_window);
+ greeter_background_add_subwindow (greeter_background, panel_window);
+ greeter_background_connect (greeter_background, gdk_screen_get_default ());
+
/* Users combobox */
renderer = gtk_cell_renderer_text_new();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (user_combo), renderer, TRUE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (user_combo), renderer, "text", 1);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (user_combo), renderer, "weight", 2);
- #if GDK_VERSION_CUR_STABLE < G_ENCODE_VERSION(3, 10)
- numScreens = gdk_display_get_n_screens (gdk_display_get_default());
- #endif
-
- /* Set up the background images */
- for (scr = 0; scr < numScreens; scr++)
- {
- screen = gdk_display_get_screen (gdk_display_get_default (), scr);
- for (monitor = 0; monitor < gdk_screen_get_n_monitors (screen); monitor++)
- {
- gdk_screen_get_monitor_geometry (screen, monitor, &monitor_geometry);
-
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DESKTOP);
-#if GTK_CHECK_VERSION (3, 0, 0)
- gtk_widget_override_background_color(GTK_WIDGET(window), GTK_STATE_FLAG_NORMAL, &background_color);
-#else
- gtk_widget_modify_bg(GTK_WIDGET(window), GTK_STATE_NORMAL, &background_color);
-#endif
- gtk_window_set_screen(GTK_WINDOW(window), screen);
- gtk_window_set_keep_below(GTK_WINDOW(window), TRUE);
- gtk_widget_set_size_request(window, monitor_geometry.width, monitor_geometry.height);
- gtk_window_set_resizable (GTK_WINDOW(window), FALSE);
- gtk_widget_set_app_paintable (GTK_WIDGET(window), TRUE);
- gtk_window_move (GTK_WINDOW(window), monitor_geometry.x, monitor_geometry.y);
-
- backgrounds = g_slist_prepend(backgrounds, window);
- gtk_widget_show (window);
-#if GTK_CHECK_VERSION (3, 0, 0)
- g_signal_connect (G_OBJECT (window), "draw", G_CALLBACK (background_window_draw), NULL);
-#else
- g_signal_connect (G_OBJECT (window), "expose-event", G_CALLBACK (background_window_expose), NULL);
-#endif
- gtk_widget_queue_draw (GTK_WIDGET(window));
- }
- }
- backgrounds = g_slist_reverse(backgrounds);
-
if (lightdm_greeter_get_hide_users_hint (greeter))
{
- /* Set the background to default */
- set_background (NULL);
set_user_image (NULL);
start_authentication ("*other");
}
else
{
- if (!use_user_background)
- set_background (NULL);
- /* This also sets the background to user's */
load_user_list ();
gtk_widget_hide (GTK_WIDGET (cancel_button));
gtk_widget_show (GTK_WIDGET (user_combo));
}
- /* Window position */
- /* Default: x-center, y-center */
- main_window_pos = CENTERED_WINDOW_POS;
+ /* Windows positions */
+ main_window_pos = WINDOW_POS_CENTER;
value = g_key_file_get_value (config, "greeter", "position", NULL);
if (value)
{
@@ -3080,21 +2699,17 @@
g_free (value);
}
+ panel_window_pos = WINDOW_POS_TOP_LEFT;
gtk_builder_connect_signals(builder, greeter);
+ gtk_widget_show (GTK_WIDGET (panel_window));
+ center_window (panel_window, NULL, &panel_window_pos);
+ g_signal_connect (GTK_WIDGET (panel_window), "size-allocate", G_CALLBACK (center_window), &panel_window_pos);
+
gtk_widget_show (GTK_WIDGET (login_window));
- center_window (login_window, NULL, &main_window_pos);
+ center_window (login_window, NULL, &main_window_pos);
g_signal_connect (GTK_WIDGET (login_window), "size-allocate", G_CALLBACK (center_window), &main_window_pos);
-
- gtk_widget_show (GTK_WIDGET (panel_window));
- GtkAllocation allocation;
- gtk_widget_get_allocation (GTK_WIDGET (panel_window), &allocation);
- gdk_screen_get_monitor_geometry (gdk_screen_get_default (), gdk_screen_get_primary_monitor (gdk_screen_get_default ()), &monitor_geometry);
- gtk_window_resize (panel_window, monitor_geometry.width, allocation.height);
- gtk_window_move (panel_window, monitor_geometry.x, monitor_geometry.y);
-
- gtk_widget_show (GTK_WIDGET (login_window));
gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME);
if (a11y_keyboard_command)
@@ -3143,16 +2758,5 @@
}
#endif
- if (background_pixbuf)
- g_object_unref (background_pixbuf);
- if (default_background_pixbuf)
- g_object_unref (default_background_pixbuf);
- if (default_background_color)
-#if GTK_CHECK_VERSION (3, 0, 0)
- gdk_rgba_free (default_background_color);
-#else
- gdk_color_free (default_background_color);
-#endif
-
return EXIT_SUCCESS;
}
Follow ups