Merge lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/greeter-background into lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/trunk

Proposed by Andrew P.
Status: Merged
Merged at revision: 295
Proposed branch: lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/greeter-background
Merge into: lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/trunk
Diff against target: 2318 lines (+1554/-486) (has conflicts)
5 files modified
data/lightdm-gtk-greeter.conf (+3/-0)
src/Makefile.am (+1/-0)
src/greeterbackground.c (+1369/-0)
src/greeterbackground.h (+48/-0)
src/lightdm-gtk-greeter.c (+133/-486)
Text conflict in src/lightdm-gtk-greeter.c
To merge this branch: bzr merge lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/greeter-background
Reviewer Review Type Date Requested Status
Sean Davis Approve
Review via email: mp+225019@code.launchpad.net

Description of the change

Using GreeterBackground class to manage backgrounds.

[greeter]
# Sets monitor to display greeter windows.
# Special value - "#cursor".
active-monitor=monitor_name_1;monitor_name_2;...

# Default settings
background=...
user-background=...

# [monitor: name] or [monitor: number]
[monitor: VGA-0]
# Individual settings
background=...
user-background=...

[monitor: LVDS]
# Mark monitor as laptop display.
# Greeter will be moved to another monitor from the list
# (or first available) if lid is closed. false by default.
laptop=true

To post a comment you must log in.
294. By Andrew P.

"active-monitor" property: "#lid" tag has been replaced with "lid-monitor" property; new value - "#cursor"

295. By Andrew P.

Individual monitors configurations moved to separate sections ([monitor: name])

296. By Andrew P.

Fixed: possible crash with background=#skip (monitor->background == NULL in this case)

297. By Andrew P.

Fixed: lid state event

Revision history for this message
Simon Steinbeiß (ochosi) wrote :

I've tested the latest changes in the branch. While it generally seems to work fine, it all depends on whether the user has set up his monitors correctly in Xorg. E.g. my work machine defaults to cloning/mirroring the outputs, so whatever I set in the greeters conf-file, I get a rather garbled output.

I'm wondering whether we shouldn't just handle the display layout within the greeter instead of relying on Xorg's default setup.

Also: how would the user change the default Xorg layout (without xorg.conf) easily for the greeter? (You mentioned xrandr before, but that's only within a user-session so it wouldn't affect the greeter, right?)

Revision history for this message
Simon Steinbeiß (ochosi) wrote :

Ok, found the xrandr script for lightdm now.

As I said, this is far too complicated for the average user, I guess we should handle it ourselves by copy-pasting some code from e.g. xfce's display dialog/settings daemon.

(I guess that's the edge Ubuntu has over us with having gnome/unity-settings-daemon running in the greeter session already...)

Revision history for this message
Simon Steinbeiß (ochosi) wrote :

Another update: after setting up the script, the branch does everything it promises. Awesome work! Especially the #cursor option is great and I'm thinking we should use it by default.

However, the whole thing of initially setting up the displays should somehow be simplified.

Revision history for this message
Andrew P. (kalgasnik) wrote :

Sorry for so long response.

The best place for setting up displays (IMHO, of course) - "apply system-wide" button in xfce4-display-settings. It is the first place where average user will search for such settings.

Revision history for this message
Sean Davis (bluesabre) wrote :

I think it would be best if the greeter handled some basic monitor management. I'll think of some basic scenarios and simple code to add this in. In the meantime, this branch is approved for merging.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/lightdm-gtk-greeter.conf'
2--- data/lightdm-gtk-greeter.conf 2014-02-09 20:03:35 +0000
3+++ data/lightdm-gtk-greeter.conf 2014-07-14 10:10:41 +0000
4@@ -1,5 +1,7 @@
5 #
6 # background = Background file to use, either an image path or a color (e.g. #772953)
7+# active-monitor = Monitor to display greeter window (name or number). Use #cursor value to display greeter at monitor with cursor.
8+# user-background = Display user background (if available), true or false. true by default.
9 # theme-name = GTK+ theme to use
10 # icon-theme-name = Icon theme to use
11 # font-name = Font to use
12@@ -17,6 +19,7 @@
13 #
14 [greeter]
15 #background=
16+#user-background=
17 #theme-name=
18 #icon-theme-name=
19 #font-name=
20
21=== modified file 'src/Makefile.am'
22--- src/Makefile.am 2014-06-09 15:49:08 +0000
23+++ src/Makefile.am 2014-07-14 10:10:41 +0000
24@@ -8,6 +8,7 @@
25 lightdm_gtk_greeter_SOURCES = \
26 $(lightdm_gtk_greeter_built_sources) \
27 lightdm-gtk-greeter.c \
28+ greeterbackground.c \
29 greetermenubar.c
30
31 AM_CPPFLAGS = \
32
33=== added file 'src/greeterbackground.c'
34--- src/greeterbackground.c 1970-01-01 00:00:00 +0000
35+++ src/greeterbackground.c 2014-07-14 10:10:41 +0000
36@@ -0,0 +1,1369 @@
37+
38+#include <cairo-xlib.h>
39+#include <gtk/gtk.h>
40+#include <gdk/gdkx.h>
41+#include <gdk-pixbuf/gdk-pixbuf.h>
42+#include <string.h>
43+#include <X11/Xatom.h>
44+
45+#include "greeterbackground.h"
46+
47+typedef enum
48+{
49+ /* Broken/uninitialized configuration */
50+ BACKGROUND_TYPE_INVALID,
51+ /* Do not use this monitor */
52+ BACKGROUND_TYPE_SKIP,
53+ /* Solid color */
54+ BACKGROUND_TYPE_COLOR,
55+ /* Path to image and scaling mode */
56+ BACKGROUND_TYPE_IMAGE
57+ /* Maybe other types (e.g. gradient) */
58+} BackgroundType;
59+
60+static const gchar* BACKGROUND_TYPE_SKIP_VALUE = "#skip";
61+
62+typedef enum
63+{
64+ /* It is not really useful, used for debugging */
65+ SCALING_MODE_SOURCE,
66+ /* Default mode for values without mode prefix */
67+ SCALING_MODE_ZOOMED,
68+ SCALING_MODE_STRETCHED
69+} ScalingMode;
70+
71+static const gchar* SCALING_MODE_PREFIXES[] = {"#source:", "#zoomed:", "#stretched:", NULL};
72+
73+/* Background configuration (parsed from background=... option).
74+ Used to fill <Background> */
75+typedef struct
76+{
77+ BackgroundType type;
78+ union
79+ {
80+ #if GTK_CHECK_VERSION (3, 0, 0)
81+ GdkRGBA color;
82+ #else
83+ GdkColor color;
84+ #endif
85+ struct
86+ {
87+ gchar *path;
88+ ScalingMode mode;
89+ } image;
90+ } options;
91+} BackgroundConfig;
92+
93+/* Store monitor configuration */
94+typedef struct
95+{
96+ BackgroundConfig bg;
97+ gboolean user_bg;
98+ gboolean laptop;
99+} MonitorConfig;
100+
101+/* Actual drawing information attached to monitor.
102+ * Used to separate configured monitor background and user background. */
103+typedef struct
104+{
105+ BackgroundType type;
106+ union
107+ {
108+ GdkPixbuf* image;
109+ #if GTK_CHECK_VERSION (3, 0, 0)
110+ GdkRGBA color;
111+ #else
112+ GdkColor color;
113+ #endif
114+ } options;
115+} Background;
116+
117+typedef struct
118+{
119+ GreeterBackground* object;
120+ gint number;
121+ gchar* name;
122+ GdkRectangle geometry;
123+ GtkWindow* window;
124+ gulong window_draw_handler_id;
125+
126+ /* Configured background */
127+ Background background_configured;
128+ /* Background used to display user-background */
129+ Background background_custom;
130+ /* Current monitor background: &background_configured or &background_custom
131+ * Monitors with type = BACKGROUND_TYPE_SKIP have background = NULL */
132+ const Background* background;
133+} Monitor;
134+
135+struct _GreeterBackground
136+{
137+ GObject parent_instance;
138+ struct _GreeterBackgroundPrivate* priv;
139+};
140+
141+struct _GreeterBackgroundClass
142+{
143+ GObjectClass parent_class;
144+};
145+
146+typedef struct _GreeterBackgroundPrivate GreeterBackgroundPrivate;
147+
148+struct _GreeterBackgroundPrivate
149+{
150+ GdkScreen* screen;
151+ gulong screen_monitors_changed_handler_id;
152+ /* one-window-gtk3-only
153+ GtkWindow* greeter_widget;
154+ */
155+ GSList* greeter_windows;
156+
157+ /* Mapping monitor name <gchar*> to its config <MonitorConfig*> */
158+ GHashTable* configs;
159+ /* Default config for unlisted monitors */
160+ MonitorConfig* default_config;
161+
162+ /* Array of configured monitors for current screen */
163+ Monitor* monitors;
164+ gsize monitors_size;
165+ /* Name => <Monitor*>, "Number" => <Monitor*> */
166+ GHashTable* monitors_map;
167+
168+ GList* active_monitors_config;
169+ const Monitor* active_monitor;
170+
171+ /* List of monitors <Monitor*> with user-background=true*/
172+ GSList* customized_monitors;
173+
174+ /* List of monitors <Monitor*> with laptop=true */
175+ GSList* laptop_monitors;
176+ /* DBus proxy to catch lid state changing */
177+ GDBusProxy* laptop_upower_proxy;
178+ /* Cached lid state */
179+ gboolean laptop_lid_closed;
180+
181+ /* Use cursor position to determinate current active monitor (dynamic) */
182+ gboolean follow_cursor;
183+ /* Use cursor position to determinate initial active monitor */
184+ gboolean follow_cursor_to_init;
185+};
186+
187+enum
188+{
189+ BACKGROUND_SIGNAL_ACTIVE_MONITOR_CHANGED,
190+ BACKGROUND_SIGNAL_LAST
191+};
192+
193+static guint background_signals[BACKGROUND_SIGNAL_LAST] = {0};
194+
195+static const MonitorConfig DEFAULT_MONITOR_CONFIG =
196+{
197+ .bg =
198+ {
199+ .type = BACKGROUND_TYPE_COLOR,
200+ .options =
201+ {
202+ #if GTK_CHECK_VERSION (3, 0, 0)
203+ .color = {.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0}
204+ #else
205+ .color = {.pixel = 0, .red = 0, .green = 0, .blue = 0}
206+ #endif
207+ }
208+ },
209+ .user_bg = TRUE,
210+ .laptop = FALSE
211+};
212+
213+static const gchar* DBUS_UPOWER_NAME = "org.freedesktop.UPower";
214+static const gchar* DBUS_UPOWER_PATH = "/org/freedesktop/UPower";
215+static const gchar* DBUS_UPOWER_INTERFACE = "org.freedesktop.UPower";
216+static const gchar* DBUS_UPOWER_PROP_LID_IS_PRESENT = "LidIsPresent";
217+static const gchar* DBUS_UPOWER_PROP_LID_IS_CLOSED = "LidIsClosed";
218+
219+static const gchar* ACTIVE_MONITOR_CURSOR_TAG = "#cursor";
220+
221+G_DEFINE_TYPE_WITH_PRIVATE(GreeterBackground, greeter_background, G_TYPE_OBJECT);
222+
223+void greeter_background_set_active_monitor_config (GreeterBackground* background,
224+ const gchar* value);
225+void greeter_background_set_default_config (GreeterBackground* background,
226+ const gchar* bg,
227+ gboolean user_bg,
228+ gboolean laptop);
229+void greeter_background_set_monitor_config (GreeterBackground* background,
230+ const gchar* name,
231+ const gchar* bg,
232+ gboolean user_bg, gboolean user_bg_used,
233+ gboolean laptop, gboolean laptop_used);
234+void greeter_background_remove_monitor_config (GreeterBackground* background,
235+ const gchar* name);
236+gchar** greeter_background_get_configured_monitors (GreeterBackground* background);
237+void greeter_background_connect (GreeterBackground* background,
238+ GdkScreen* screen);
239+void greeter_background_disconnect (GreeterBackground* background);
240+static gboolean greeter_background_find_monitor_data(GreeterBackground* background,
241+ GHashTable* table,
242+ const Monitor* monitor,
243+ gpointer* data);
244+static void greeter_background_set_active_monitor (GreeterBackground* background,
245+ const Monitor* active);
246+static void greeter_background_get_cursor_position (GreeterBackground* background,
247+ gint* x, gint* y);
248+static void greeter_background_set_cursor_position (GreeterBackground* background,
249+ gint x, gint y);
250+static void greeter_background_try_init_dbus (GreeterBackground* background);
251+static void greeter_background_stop_dbus (GreeterBackground* background);
252+static gboolean greeter_background_monitor_enabled (GreeterBackground* background,
253+ const Monitor* monitor);
254+static void greeter_background_dbus_changed_cb (GDBusProxy* proxy,
255+ GVariant* changed_properties,
256+ const gchar* const* invalidated_properties,
257+ GreeterBackground* background);
258+static void greeter_background_monitors_changed_cb (GdkScreen* screen,
259+ GreeterBackground* background);
260+
261+/* struct BackgroundConfig */
262+static gboolean background_config_initialize (BackgroundConfig* config,
263+ const gchar* value);
264+static void background_config_finalize (BackgroundConfig* config);
265+static void background_config_copy (const BackgroundConfig* source,
266+ BackgroundConfig* dest);
267+
268+/* struct MonitorConfig */
269+static void monitor_config_free (MonitorConfig* config);
270+/* Copy source config to dest, return dest. Allocate memory if dest == NULL. */
271+static MonitorConfig* monitor_config_copy (const MonitorConfig* source,
272+ MonitorConfig* dest);
273+
274+/* struct Background */
275+static gboolean background_initialize (Background* bg,
276+ const BackgroundConfig* config,
277+ const Monitor* monitor,
278+ GHashTable* images_cache);
279+static void background_finalize (Background* bg);
280+
281+/* struct Monitor */
282+static void monitor_finalize (Monitor* info);
283+static void monitor_set_background (Monitor* monitor,
284+ const Background* background);
285+static void monitor_draw_background (const Monitor* monitor,
286+ cairo_t* cr);
287+#if GTK_CHECK_VERSION(3, 0, 0)
288+static gboolean monitor_window_draw_cb (GtkWidget* widget,
289+ cairo_t* cr,
290+ const Monitor* monitor);
291+static gboolean monitor_subwindow_draw_cb (GtkWidget* widget,
292+ cairo_t* cr,
293+ GreeterBackground* background);
294+#else
295+static gboolean monitor_window_expose_cb (GtkWidget* widget,
296+ GdkEventExpose *event,
297+ const Monitor* monitor);
298+#endif
299+static gboolean monitor_window_enter_notify_cb (GtkWidget* widget,
300+ GdkEventCrossing* event,
301+ const Monitor* monitor);
302+
303+static GdkPixbuf* scale_image_file (const gchar* path,
304+ ScalingMode mode,
305+ gint width, gint height,
306+ GHashTable* cache);
307+static GdkPixbuf* scale_image (GdkPixbuf* source,
308+ ScalingMode mode,
309+ gint width, gint height);
310+static cairo_surface_t* create_root_surface (GdkScreen* screen);
311+static void set_root_pixmap_id (GdkScreen* screen,
312+ Display* display,
313+ Pixmap xpixmap);
314+static void set_surface_as_root (GdkScreen* screen,
315+ cairo_surface_t* surface);
316+
317+
318+/* Implementation */
319+
320+static void
321+greeter_background_class_init(GreeterBackgroundClass* klass)
322+{
323+ GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
324+
325+ background_signals[BACKGROUND_SIGNAL_ACTIVE_MONITOR_CHANGED] =
326+ g_signal_new("active-monitor-changed",
327+ G_TYPE_FROM_CLASS(gobject_class),
328+ G_SIGNAL_RUN_FIRST,
329+ 0, /* class_offset */
330+ NULL /* accumulator */, NULL /* accu_data */,
331+ g_cclosure_marshal_VOID__VOID,
332+ G_TYPE_NONE, 0);
333+}
334+
335+static void
336+greeter_background_init(GreeterBackground* self)
337+{
338+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, GREETER_BACKGROUND_TYPE, GreeterBackgroundPrivate);
339+ self->priv->screen = NULL;
340+ self->priv->screen_monitors_changed_handler_id = 0;
341+ self->priv->greeter_windows = NULL;
342+
343+ self->priv->configs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)monitor_config_free);
344+ self->priv->default_config = monitor_config_copy(&DEFAULT_MONITOR_CONFIG, NULL);
345+
346+ self->priv->monitors = NULL;
347+ self->priv->monitors_size = 0;
348+ self->priv->monitors_map = NULL;
349+
350+ self->priv->customized_monitors = NULL;
351+ self->priv->active_monitors_config = NULL;
352+ self->priv->active_monitor = NULL;
353+
354+ self->priv->laptop_monitors = NULL;
355+ self->priv->laptop_upower_proxy = NULL;
356+ self->priv->laptop_lid_closed = FALSE;
357+}
358+
359+GreeterBackground*
360+greeter_background_new(void)
361+{
362+ return GREETER_BACKGROUND(g_object_new(greeter_background_get_type(), NULL));
363+}
364+
365+void
366+greeter_background_set_active_monitor_config(GreeterBackground* background,
367+ const gchar* value)
368+{
369+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
370+ GreeterBackgroundPrivate* priv = background->priv;
371+
372+ g_list_free_full(priv->active_monitors_config, g_free);
373+ priv->active_monitors_config = NULL;
374+
375+ priv->follow_cursor = FALSE;
376+ priv->follow_cursor_to_init = FALSE;
377+
378+ if(!value || !*value)
379+ return;
380+
381+ gchar** iter;
382+ gchar** values = g_strsplit(value, ";", -1);
383+
384+ for(iter = values; *iter; ++iter)
385+ {
386+ const gchar* value = *iter;
387+ if(g_strcmp0(value, ACTIVE_MONITOR_CURSOR_TAG) == 0)
388+ {
389+ priv->follow_cursor = TRUE;
390+ priv->follow_cursor_to_init = (priv->active_monitors_config == NULL);
391+ }
392+ else
393+ priv->active_monitors_config = g_list_prepend(priv->active_monitors_config, g_strdup(value));
394+ }
395+ g_strfreev(values);
396+
397+ priv->active_monitors_config = g_list_reverse(priv->active_monitors_config);
398+}
399+
400+void
401+greeter_background_set_default_config(GreeterBackground* background,
402+ const gchar* bg,
403+ gboolean user_bg,
404+ gboolean laptop)
405+{
406+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
407+ GreeterBackgroundPrivate* priv = background->priv;
408+
409+ if(priv->default_config)
410+ monitor_config_free(priv->default_config);
411+
412+ priv->default_config = g_new0(MonitorConfig, 1);
413+ if(!background_config_initialize(&priv->default_config->bg, bg))
414+ background_config_copy(&DEFAULT_MONITOR_CONFIG.bg, &priv->default_config->bg);
415+ priv->default_config->user_bg = user_bg;
416+ priv->default_config->laptop = laptop;
417+}
418+
419+void
420+greeter_background_set_monitor_config(GreeterBackground* background,
421+ const gchar* name,
422+ const gchar* bg,
423+ gboolean user_bg, gboolean user_bg_used,
424+ gboolean laptop, gboolean laptop_used)
425+{
426+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
427+ GreeterBackgroundPrivate* priv = background->priv;
428+
429+ MonitorConfig* config = g_new0(MonitorConfig, 1);
430+
431+ if(!background_config_initialize(&config->bg, bg))
432+ background_config_copy(&priv->default_config->bg, &config->bg);
433+ config->user_bg = user_bg_used ? user_bg : priv->default_config->user_bg;
434+ config->laptop = laptop_used ? laptop : priv->default_config->laptop;
435+
436+ g_hash_table_insert(priv->configs, g_strdup(name), config);
437+}
438+
439+void
440+greeter_background_remove_monitor_config(GreeterBackground* background,
441+ const gchar* name)
442+{
443+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
444+ g_hash_table_remove(background->priv->configs, name);
445+}
446+
447+gchar**
448+greeter_background_get_configured_monitors(GreeterBackground* background)
449+{
450+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
451+ GreeterBackgroundPrivate* priv = background->priv;
452+
453+ gint n = g_hash_table_size(priv->configs);
454+ gchar** names = g_new(gchar*, n + 1);
455+ names[n--] = NULL;
456+
457+ gpointer key;
458+ GHashTableIter iter;
459+ g_hash_table_iter_init(&iter, priv->configs);
460+ while(g_hash_table_iter_next(&iter, &key, NULL))
461+ names[n--] = g_strdup(key);
462+
463+ return names;
464+}
465+
466+void
467+greeter_background_connect(GreeterBackground* background,
468+ GdkScreen* screen)
469+{
470+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
471+ g_return_if_fail(GDK_IS_SCREEN(screen));
472+
473+ g_debug("Connecting to screen");
474+
475+ GreeterBackgroundPrivate* priv = background->priv;
476+ gulong screen_monitors_changed_handler_id = (priv->screen == screen) ? priv->screen_monitors_changed_handler_id : 0;
477+ if(screen_monitors_changed_handler_id)
478+ priv->screen_monitors_changed_handler_id = 0;
479+
480+ if(priv->screen)
481+ greeter_background_disconnect(background);
482+
483+ priv->screen = screen;
484+ priv->monitors_size = gdk_screen_get_n_monitors(screen);
485+ priv->monitors = g_new0(Monitor, priv->monitors_size);
486+ priv->monitors_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
487+
488+ /* Used to track situation when all monitors marked as "#skip" */
489+ Monitor* first_not_skipped_monitor = NULL;
490+
491+ GHashTable* images_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
492+ gint i;
493+ for(i = 0; i < priv->monitors_size; ++i)
494+ {
495+ const MonitorConfig* config;
496+ Monitor* monitor = &priv->monitors[i];
497+
498+ monitor->object = background;
499+ monitor->name = g_strdup(gdk_screen_get_monitor_plug_name(screen, i));
500+ monitor->number = i;
501+
502+ const gchar* printable_name = monitor->name ? monitor->name : "<unknown>";
503+
504+ if(!greeter_background_find_monitor_data(background, priv->configs, monitor, (gpointer*)&config))
505+ {
506+ g_debug("No configuration options for monitor %s #%d, using default", printable_name, i);
507+ config = priv->default_config;
508+ }
509+
510+ gdk_screen_get_monitor_geometry(screen, i, &monitor->geometry);
511+
512+ g_debug("Monitor: %s #%d (%dx%d at %dx%d)%s", printable_name, i,
513+ monitor->geometry.width, monitor->geometry.height,
514+ monitor->geometry.x, monitor->geometry.y,
515+ (i == gdk_screen_get_primary_monitor(screen)) ? " primary" : "");
516+
517+ /* Force last skipped monitor to be active monitor, if there is no other choice */
518+ if(config->bg.type == BACKGROUND_TYPE_SKIP)
519+ {
520+ if(i < priv->monitors_size - 1 || first_not_skipped_monitor)
521+ continue;
522+ g_debug("Monitor %s #%d can not be skipped, using default configuration for it", printable_name, i);
523+ if(priv->default_config->bg.type != BACKGROUND_TYPE_SKIP)
524+ config = priv->default_config;
525+ else
526+ config = &DEFAULT_MONITOR_CONFIG;
527+ }
528+
529+ if(!first_not_skipped_monitor)
530+ first_not_skipped_monitor = monitor;
531+
532+ monitor->window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
533+ gtk_window_set_type_hint(monitor->window, GDK_WINDOW_TYPE_HINT_DESKTOP);
534+ gtk_window_set_keep_below(monitor->window, TRUE);
535+ gtk_window_set_resizable(monitor->window, FALSE);
536+ gtk_widget_set_app_paintable(GTK_WIDGET(monitor->window), TRUE);
537+ gtk_window_set_screen(monitor->window, screen);
538+ gtk_widget_set_size_request(GTK_WIDGET(monitor->window), monitor->geometry.width, monitor->geometry.height);
539+ gtk_window_move(monitor->window, monitor->geometry.x, monitor->geometry.y);
540+ gtk_widget_show(GTK_WIDGET(monitor->window));
541+ #if GTK_CHECK_VERSION(3, 0, 0)
542+ monitor->window_draw_handler_id = g_signal_connect(G_OBJECT(monitor->window), "draw",
543+ G_CALLBACK(monitor_window_draw_cb),
544+ monitor);
545+ #else
546+ monitor->window_draw_handler_id = g_signal_connect(G_OBJECT(monitor->window), "expose-event",
547+ G_CALLBACK(monitor_window_expose_cb),
548+ monitor);
549+ #endif
550+ if(priv->follow_cursor)
551+ g_signal_connect(G_OBJECT(monitor->window), "enter-notify-event",
552+ G_CALLBACK(monitor_window_enter_notify_cb), monitor);
553+
554+ if(config->user_bg)
555+ priv->customized_monitors = g_slist_prepend(priv->customized_monitors, monitor);
556+
557+ if(config->laptop)
558+ priv->laptop_monitors = g_slist_prepend(priv->laptop_monitors, monitor);
559+
560+ if(!background_initialize(&monitor->background_configured, &config->bg, monitor, images_cache))
561+ background_initialize(&monitor->background_configured, &DEFAULT_MONITOR_CONFIG.bg, monitor, images_cache);
562+ monitor_set_background(monitor, &monitor->background_configured);
563+
564+ if(monitor->name)
565+ g_hash_table_insert(priv->monitors_map, g_strdup(monitor->name), monitor);
566+ g_hash_table_insert(priv->monitors_map, g_strdup_printf("%d", i), monitor);
567+ }
568+ g_hash_table_unref(images_cache);
569+
570+ if(priv->laptop_monitors && !priv->laptop_upower_proxy)
571+ greeter_background_try_init_dbus(background);
572+ else if(!priv->laptop_monitors)
573+ greeter_background_stop_dbus(background);
574+
575+ if(priv->follow_cursor_to_init)
576+ {
577+ gint x, y;
578+ greeter_background_get_cursor_position(background, &x, &y);
579+ for(i = 0; i < priv->monitors_size && !priv->active_monitor; ++i)
580+ {
581+ const Monitor* monitor = &priv->monitors[i];
582+ if(greeter_background_monitor_enabled(background, monitor) &&
583+ x >= monitor->geometry.x && x < monitor->geometry.x + monitor->geometry.width &&
584+ y >= monitor->geometry.y && y < monitor->geometry.y + monitor->geometry.height)
585+ greeter_background_set_active_monitor(background, monitor);
586+ }
587+ }
588+ if(!priv->active_monitor)
589+ greeter_background_set_active_monitor(background, NULL);
590+
591+ if(screen_monitors_changed_handler_id)
592+ priv->screen_monitors_changed_handler_id = screen_monitors_changed_handler_id;
593+ else
594+ priv->screen_monitors_changed_handler_id = g_signal_connect(G_OBJECT(screen), "monitors-changed",
595+ G_CALLBACK(greeter_background_monitors_changed_cb),
596+ background);
597+}
598+
599+void
600+greeter_background_disconnect(GreeterBackground* background)
601+{
602+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
603+ GreeterBackgroundPrivate* priv = background->priv;
604+
605+ priv->screen = NULL;
606+ priv->active_monitor = NULL;
607+
608+ if(priv->screen_monitors_changed_handler_id)
609+ g_signal_handler_disconnect(priv->screen, priv->screen_monitors_changed_handler_id);
610+ priv->screen_monitors_changed_handler_id = 0;
611+
612+ gint i;
613+ for(i = 0; i < priv->monitors_size; ++i)
614+ monitor_finalize(&priv->monitors[i]);
615+ g_free(priv->monitors);
616+ priv->monitors = NULL;
617+ priv->monitors_size = 0;
618+
619+ g_hash_table_unref(priv->monitors_map);
620+ priv->monitors_map = NULL;
621+ g_slist_free(priv->customized_monitors);
622+ priv->customized_monitors = NULL;
623+ g_slist_free(priv->laptop_monitors);
624+ priv->laptop_monitors = NULL;
625+}
626+
627+/* Moved to separate function to simplify needless and unnecessary syntax expansion in future (regex) */
628+static gboolean
629+greeter_background_find_monitor_data(GreeterBackground* background,
630+ GHashTable* table,
631+ const Monitor* monitor,
632+ gpointer* data)
633+{
634+ if(!monitor->name || !g_hash_table_lookup_extended(table, monitor->name, NULL, data))
635+ {
636+ gchar* num_str = g_strdup_printf("%d", monitor->number);
637+ gboolean result = g_hash_table_lookup_extended(table, num_str, NULL, data);
638+ g_free(num_str);
639+ return result;
640+ }
641+ return TRUE;
642+}
643+
644+static void
645+greeter_background_set_active_monitor(GreeterBackground* background,
646+ const Monitor* active)
647+{
648+ GreeterBackgroundPrivate* priv = background->priv;
649+
650+ if(active && !active->background)
651+ {
652+ if(priv->active_monitor)
653+ return;
654+ active = NULL;
655+ }
656+
657+ /* Auto */
658+ if(!active)
659+ {
660+ /* Normal way: at least one configured active monitor is not disabled */
661+ GList* iter;
662+ for(iter = priv->active_monitors_config; iter && !active; iter = g_list_next(iter))
663+ {
664+ const Monitor* monitor = g_hash_table_lookup(priv->monitors_map, iter->data);
665+ if(monitor && monitor->background && greeter_background_monitor_enabled(background, monitor))
666+ active = monitor;
667+ }
668+
669+ /* All monitors listed in active-monitor-config are disabled (or option is empty) */
670+
671+ /* Using primary monitor */
672+ if(!active)
673+ {
674+ active = &priv->monitors[gdk_screen_get_primary_monitor(priv->screen)];
675+ if(!active->background || !greeter_background_monitor_enabled(background, active))
676+ active = NULL;
677+ }
678+
679+ /* Fallback: first enabled and/or not skipped monitor (screen always have one) */
680+ if(!active)
681+ {
682+ gint i;
683+ const Monitor* first_not_skipped = NULL;
684+ for(i = 0; i < priv->monitors_size && !active; ++i)
685+ {
686+ const Monitor* monitor = &priv->monitors[i];
687+ if(!monitor->background)
688+ continue;
689+ if(greeter_background_monitor_enabled(background, monitor))
690+ active = monitor;
691+ if(!first_not_skipped)
692+ first_not_skipped = active;
693+ }
694+ if(!active)
695+ active = first_not_skipped;
696+ }
697+ }
698+
699+ if(active == priv->active_monitor)
700+ return;
701+
702+ priv->active_monitor = active;
703+ g_debug("Active monitor changed to: %s #%d", active->name, active->number);
704+ g_signal_emit(background, background_signals[BACKGROUND_SIGNAL_ACTIVE_MONITOR_CHANGED], 0);
705+
706+ gint x, y;
707+ greeter_background_get_cursor_position(background, &x, &y);
708+ /* Do not center cursor if it is already inside active monitor */
709+ if(x < active->geometry.x || x >= active->geometry.x + active->geometry.width ||
710+ y < active->geometry.y || y >= active->geometry.y + active->geometry.height)
711+ greeter_background_set_cursor_position(background,
712+ active->geometry.x + active->geometry.width/2,
713+ active->geometry.y + active->geometry.height/2);
714+
715+ /* Update greeter windows */
716+ GSList* iter;
717+ for(iter = priv->greeter_windows; iter; iter = g_slist_next(iter))
718+ {
719+ gtk_window_set_screen(GTK_WINDOW(iter->data), priv->screen);
720+ if(gtk_widget_get_visible(GTK_WIDGET(iter->data)))
721+ { /* Toggle window visibility to place window above of any 'background' windows */
722+ gtk_widget_hide(GTK_WIDGET(iter->data));
723+ gtk_widget_show(GTK_WIDGET(iter->data));
724+ gtk_widget_queue_resize(GTK_WIDGET(iter->data));
725+ }
726+ }
727+}
728+
729+static void
730+greeter_background_get_cursor_position(GreeterBackground* background,
731+ gint* x, gint* y)
732+{
733+ GreeterBackgroundPrivate* priv = background->priv;
734+
735+ GdkDisplay* display = gdk_screen_get_display(priv->screen);
736+ #if GTK_CHECK_VERSION(3, 0, 0)
737+ GdkDeviceManager* device_manager = gdk_display_get_device_manager(display);
738+ GdkDevice* device = gdk_device_manager_get_client_pointer(device_manager);
739+ gdk_device_get_position(device, NULL, x, y);
740+ #else
741+ gdk_display_get_pointer(display, NULL, x, y, NULL);
742+ #endif
743+}
744+
745+static void
746+greeter_background_set_cursor_position(GreeterBackground* background,
747+ gint x, gint y)
748+{
749+ GreeterBackgroundPrivate* priv = background->priv;
750+
751+ GdkDisplay* display = gdk_screen_get_display(priv->screen);
752+ #if GTK_CHECK_VERSION(3, 0, 0)
753+ GdkDeviceManager* device_manager = gdk_display_get_device_manager(display);
754+ gdk_device_warp(gdk_device_manager_get_client_pointer(device_manager), priv->screen, x, y);
755+ #else
756+ gdk_display_warp_pointer(display, priv->screen, x, y);
757+ #endif
758+}
759+
760+static void
761+greeter_background_try_init_dbus(GreeterBackground* background)
762+{
763+ g_debug("Creating DBus proxy");
764+ GError* error = NULL;
765+ GreeterBackgroundPrivate* priv = background->priv;
766+
767+ if(priv->laptop_upower_proxy)
768+ greeter_background_stop_dbus(background);
769+
770+ priv->laptop_upower_proxy = g_dbus_proxy_new_for_bus_sync(
771+ G_BUS_TYPE_SYSTEM,
772+ G_DBUS_PROXY_FLAGS_NONE,
773+ NULL, /* interface info */
774+ DBUS_UPOWER_NAME,
775+ DBUS_UPOWER_PATH,
776+ DBUS_UPOWER_INTERFACE,
777+ NULL, /* cancellable */
778+ &error);
779+ if(!priv->laptop_upower_proxy)
780+ {
781+ if(error)
782+ g_warning("Failed to create dbus proxy: %s", error->message);
783+ g_clear_error(&error);
784+ return;
785+ }
786+
787+ GVariant* variant = g_dbus_proxy_get_cached_property(priv->laptop_upower_proxy, DBUS_UPOWER_PROP_LID_IS_PRESENT);
788+ gboolean lid_present = g_variant_get_boolean(variant);
789+ g_variant_unref(variant);
790+
791+ g_debug("UPower.%s property value: %d", DBUS_UPOWER_PROP_LID_IS_PRESENT, lid_present);
792+
793+ if(!lid_present)
794+ greeter_background_stop_dbus(background);
795+ else
796+ {
797+ variant = g_dbus_proxy_get_cached_property(priv->laptop_upower_proxy, DBUS_UPOWER_PROP_LID_IS_CLOSED);
798+ priv->laptop_lid_closed = g_variant_get_boolean(variant);
799+ g_variant_unref(variant);
800+
801+ g_signal_connect(priv->laptop_upower_proxy, "g-properties-changed",
802+ G_CALLBACK(greeter_background_dbus_changed_cb), background);
803+ }
804+}
805+
806+static void
807+greeter_background_stop_dbus(GreeterBackground* background)
808+{
809+ if(!background->priv->laptop_upower_proxy)
810+ return;
811+ g_clear_object(&background->priv->laptop_upower_proxy);
812+}
813+
814+static gboolean
815+greeter_background_monitor_enabled(GreeterBackground* background,
816+ const Monitor* monitor)
817+{
818+ GreeterBackgroundPrivate* priv = background->priv;
819+
820+ if(priv->laptop_upower_proxy && g_slist_find(priv->laptop_monitors, monitor))
821+ return !priv->laptop_lid_closed;
822+ return TRUE;
823+}
824+
825+static void
826+greeter_background_dbus_changed_cb(GDBusProxy* proxy,
827+ GVariant* changed_properties,
828+ const gchar* const* invalidated_properties,
829+ GreeterBackground* background)
830+{
831+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
832+ GreeterBackgroundPrivate* priv = background->priv;
833+
834+ GVariant* variant = g_dbus_proxy_get_cached_property(priv->laptop_upower_proxy, DBUS_UPOWER_PROP_LID_IS_CLOSED);
835+ gboolean new_state = g_variant_get_boolean(variant);
836+ g_variant_unref(variant);
837+
838+ if(new_state == priv->laptop_lid_closed)
839+ return;
840+
841+ g_debug("UPower: lid state changed to '%s'", priv->laptop_lid_closed ? "closed" : "opened");
842+
843+ priv->laptop_lid_closed = new_state;
844+ if(priv->laptop_monitors)
845+ {
846+ if(!priv->follow_cursor || (new_state && priv->laptop_monitors->data == priv->active_monitor))
847+ greeter_background_set_active_monitor(background, NULL);
848+ }
849+}
850+
851+static void
852+greeter_background_monitors_changed_cb(GdkScreen* screen,
853+ GreeterBackground* background)
854+{
855+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
856+ greeter_background_connect(background, screen);
857+}
858+
859+void greeter_background_add_subwindow(GreeterBackground* background,
860+ GtkWindow* window)
861+{
862+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
863+ g_return_if_fail(GTK_IS_WINDOW(window));
864+
865+ GreeterBackgroundPrivate* priv = background->priv;
866+
867+ if(!g_slist_find(priv->greeter_windows, window))
868+ {
869+ priv->greeter_windows = g_slist_prepend(priv->greeter_windows, window);
870+ #if GTK_CHECK_VERSION (3, 0, 0)
871+ g_signal_connect(G_OBJECT(window), "draw", G_CALLBACK(monitor_subwindow_draw_cb), background);
872+ #endif
873+ }
874+
875+ if(priv->screen)
876+ gtk_window_set_screen(window, priv->screen);
877+}
878+
879+void greeter_background_remove_subwindow(GreeterBackground* background,
880+ GtkWindow* window)
881+{
882+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
883+ g_return_if_fail(GTK_IS_WINDOW(window));
884+
885+ GreeterBackgroundPrivate* priv = background->priv;
886+
887+ GSList* item = g_slist_find(priv->greeter_windows, window);
888+ if(item)
889+ {
890+ #if GTK_CHECK_VERSION (3, 0, 0)
891+ g_object_disconnect(G_OBJECT(window),
892+ "any-signal", G_CALLBACK(monitor_subwindow_draw_cb), background,
893+ NULL);
894+ #endif
895+ priv->greeter_windows = g_slist_delete_link(priv->greeter_windows, item);
896+ }
897+}
898+
899+void
900+greeter_background_set_custom_background(GreeterBackground* background,
901+ const gchar* value)
902+{
903+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
904+
905+ GreeterBackgroundPrivate* priv = background->priv;
906+ if(!priv->customized_monitors)
907+ return;
908+
909+ BackgroundConfig config;
910+ background_config_initialize(&config, value);
911+
912+ GHashTable *images_cache = NULL;
913+ if(config.type == BACKGROUND_TYPE_IMAGE)
914+ images_cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
915+
916+ GSList* iter;
917+ for(iter = priv->customized_monitors; iter; iter = g_slist_next(iter))
918+ {
919+ Monitor *monitor = iter->data;
920+
921+ background_finalize(&monitor->background_custom);
922+ if(config.type != BACKGROUND_TYPE_INVALID &&
923+ background_initialize(&monitor->background_custom, &config, monitor, images_cache))
924+ monitor_set_background(monitor, &monitor->background_custom);
925+ else
926+ monitor_set_background(monitor, &monitor->background_configured);
927+ }
928+ if(images_cache)
929+ g_hash_table_unref(images_cache);
930+ if(config.type != BACKGROUND_TYPE_INVALID)
931+ background_config_finalize(&config);
932+
933+ for(iter = priv->greeter_windows; iter; iter = g_slist_next(iter))
934+ gtk_widget_queue_draw(GTK_WIDGET(iter->data));
935+}
936+
937+void
938+greeter_background_save_xroot(GreeterBackground* background)
939+{
940+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
941+
942+ GreeterBackgroundPrivate* priv = background->priv;
943+ cairo_surface_t* surface = create_root_surface(priv->screen);
944+ cairo_t* cr = cairo_create(surface);
945+ gsize i;
946+
947+ for(i = 0; i <= priv->monitors_size; ++i)
948+ {
949+ const Monitor* monitor = &priv->monitors[i];
950+ if(monitor == priv->active_monitor || !monitor->background)
951+ continue;
952+ if(i == priv->monitors_size)
953+ monitor = priv->active_monitor;
954+ cairo_save(cr);
955+ cairo_translate(cr, monitor->geometry.x, monitor->geometry.y);
956+ monitor_draw_background(monitor, cr);
957+ cairo_restore(cr);
958+ }
959+ set_surface_as_root(priv->screen, surface);
960+
961+ cairo_destroy(cr);
962+ cairo_surface_destroy(surface);
963+}
964+
965+const GdkRectangle*
966+greeter_background_get_active_monitor_geometry(GreeterBackground* background)
967+{
968+ g_return_if_fail(GREETER_IS_BACKGROUND(background));
969+ GreeterBackgroundPrivate* priv = background->priv;
970+
971+ return priv->active_monitor ? &priv->active_monitor->geometry : NULL;
972+}
973+
974+static gboolean
975+background_config_initialize(BackgroundConfig* config,
976+ const gchar* value)
977+{
978+ config->type = BACKGROUND_TYPE_INVALID;
979+ if(!value || strlen(value) == 0)
980+ return FALSE;
981+ if(g_strcmp0(value, BACKGROUND_TYPE_SKIP_VALUE) == 0)
982+ config->type = BACKGROUND_TYPE_SKIP;
983+ #if GTK_CHECK_VERSION (3, 0, 0)
984+ else if(gdk_rgba_parse(&config->options.color, value))
985+ #else
986+ else if(gdk_color_parse(value, &config->options.color))
987+ #endif
988+ config->type = BACKGROUND_TYPE_COLOR;
989+ else
990+ {
991+ const gchar** prefix = SCALING_MODE_PREFIXES;
992+ while(*prefix && !g_str_has_prefix(value, *prefix))
993+ ++prefix;
994+
995+ if(*prefix)
996+ {
997+ config->options.image.mode = (ScalingMode)(prefix - SCALING_MODE_PREFIXES);
998+ value += strlen(*prefix);
999+ }
1000+ else
1001+ config->options.image.mode = SCALING_MODE_ZOOMED;
1002+
1003+ config->options.image.path = g_strdup(value);
1004+ config->type = BACKGROUND_TYPE_IMAGE;
1005+ }
1006+ return TRUE;
1007+}
1008+
1009+static void
1010+background_config_finalize(BackgroundConfig* config)
1011+{
1012+ if(config->type == BACKGROUND_TYPE_IMAGE)
1013+ g_free(config->options.image.path);
1014+ config->type = BACKGROUND_TYPE_INVALID;
1015+}
1016+
1017+static void
1018+background_config_copy(const BackgroundConfig* source,
1019+ BackgroundConfig* dest)
1020+{
1021+ *dest = *source;
1022+ if(source->type == BACKGROUND_TYPE_IMAGE)
1023+ dest->options.image.path = g_strdup(source->options.image.path);
1024+}
1025+
1026+static void
1027+monitor_config_free(MonitorConfig* config)
1028+{
1029+ background_config_finalize(&config->bg);
1030+ g_free(config);
1031+}
1032+
1033+static MonitorConfig* monitor_config_copy(const MonitorConfig* source,
1034+ MonitorConfig* dest)
1035+{
1036+ if(!dest)
1037+ dest = g_new0(MonitorConfig, 1);
1038+ background_config_copy(&source->bg, &dest->bg);
1039+ dest->user_bg = source->user_bg;
1040+ dest->laptop = source->laptop;
1041+ return dest;
1042+}
1043+
1044+static gboolean
1045+background_initialize(Background* bg,
1046+ const BackgroundConfig* config,
1047+ const Monitor* monitor,
1048+ GHashTable* images_cache)
1049+{
1050+ if(config->type == BACKGROUND_TYPE_IMAGE)
1051+ {
1052+ GdkPixbuf* pixbuf = scale_image_file(config->options.image.path,
1053+ config->options.image.mode,
1054+ monitor->geometry.width, monitor->geometry.height,
1055+ images_cache);
1056+ if(!pixbuf)
1057+ {
1058+ g_warning("Failed to read wallpaper: %s", config->options.image.path);
1059+ return FALSE;
1060+ }
1061+ bg->options.image = pixbuf;
1062+ }
1063+ else if(config->type == BACKGROUND_TYPE_COLOR)
1064+ bg->options.color = config->options.color;
1065+ else
1066+ return FALSE;
1067+ bg->type = config->type;
1068+ return TRUE;
1069+}
1070+
1071+static void
1072+background_finalize(Background* bg)
1073+{
1074+ if(bg->type == BACKGROUND_TYPE_IMAGE)
1075+ g_clear_object(&bg->options.image);
1076+ bg->type = BACKGROUND_TYPE_INVALID;
1077+}
1078+
1079+static void
1080+monitor_set_background(Monitor* monitor,
1081+ const Background* background)
1082+{
1083+ monitor->background = background;
1084+ gtk_widget_queue_draw(GTK_WIDGET(monitor->window));
1085+}
1086+
1087+static void
1088+monitor_finalize(Monitor* monitor)
1089+{
1090+ background_finalize(&monitor->background_configured);
1091+ background_finalize(&monitor->background_custom);
1092+ g_free(monitor->name);
1093+ if(monitor->window_draw_handler_id)
1094+ g_signal_handler_disconnect(monitor->window, monitor->window_draw_handler_id);
1095+ if(monitor->window)
1096+ gtk_widget_destroy(GTK_WIDGET(monitor->window));
1097+ monitor->name = NULL;
1098+ monitor->window = NULL;
1099+ monitor->window_draw_handler_id = 0;
1100+}
1101+
1102+static void
1103+monitor_draw_background(const Monitor* monitor,
1104+ cairo_t* cr)
1105+{
1106+ g_return_if_fail(monitor != NULL);
1107+ g_return_if_fail(monitor->background != NULL);
1108+
1109+ if(monitor->background->type == BACKGROUND_TYPE_IMAGE && monitor->background->options.image)
1110+ {
1111+ gdk_cairo_set_source_pixbuf(cr, monitor->background->options.image, 0, 0);
1112+ cairo_paint(cr);
1113+ }
1114+ else if(monitor->background->type == BACKGROUND_TYPE_COLOR)
1115+ {
1116+ cairo_rectangle(cr, 0, 0, monitor->geometry.width, monitor->geometry.height);
1117+ #if GTK_CHECK_VERSION (3, 0, 0)
1118+ gdk_cairo_set_source_rgba(cr, &monitor->background->options.color);
1119+ #else
1120+ gdk_cairo_set_source_color(cr, &monitor->background->options.color);
1121+ #endif
1122+ cairo_fill(cr);
1123+ }
1124+}
1125+
1126+#if GTK_CHECK_VERSION (3, 0, 0)
1127+static gboolean
1128+monitor_window_draw_cb(GtkWidget* widget,
1129+ cairo_t* cr,
1130+ const Monitor* monitor)
1131+#else
1132+static gboolean
1133+monitor_window_expose_cb(GtkWidget* widget,
1134+ GdkEventExpose *event,
1135+ const Monitor* monitor)
1136+#endif
1137+{
1138+ if(monitor->background)
1139+ {
1140+ #if GTK_CHECK_VERSION (3, 0, 0)
1141+ monitor_draw_background(monitor, cr);
1142+ #else
1143+ cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget));
1144+ monitor_draw_background(monitor, cr);
1145+ cairo_destroy(cr);
1146+ #endif
1147+ }
1148+ return FALSE;
1149+}
1150+
1151+#if GTK_CHECK_VERSION (3, 0, 0)
1152+static gboolean
1153+monitor_subwindow_draw_cb(GtkWidget* widget,
1154+ cairo_t* cr,
1155+ GreeterBackground* background)
1156+{
1157+ g_return_val_if_fail(GREETER_IS_BACKGROUND(background), FALSE);
1158+ if(background->priv->active_monitor)
1159+ {
1160+ const GdkRectangle* geometry = &background->priv->active_monitor->geometry;
1161+ gint x = 0, y = 0;
1162+ gtk_window_get_position(GTK_WINDOW(widget), &x, &y);
1163+
1164+ cairo_save(cr);
1165+ cairo_translate(cr, geometry->x - x, geometry->y - y);
1166+ monitor_draw_background(background->priv->active_monitor, cr);
1167+ cairo_restore(cr);
1168+ }
1169+ return FALSE;
1170+}
1171+#endif
1172+
1173+static gboolean
1174+monitor_window_enter_notify_cb(GtkWidget* widget,
1175+ GdkEventCrossing* event,
1176+ const Monitor* monitor)
1177+{
1178+ if(monitor->object->priv->active_monitor != monitor &&
1179+ greeter_background_monitor_enabled(monitor->object, monitor))
1180+ greeter_background_set_active_monitor(monitor->object, monitor);
1181+ return FALSE;
1182+}
1183+
1184+static GdkPixbuf*
1185+scale_image_file(const gchar* path,
1186+ ScalingMode mode,
1187+ gint width, gint height,
1188+ GHashTable* cache)
1189+{
1190+ gchar* key = NULL;
1191+ GdkPixbuf* pixbuf = NULL;
1192+ if(cache)
1193+ {
1194+ key = g_strdup_printf("%s\n%d %dx%d", path, mode, width, height);
1195+ if (g_hash_table_lookup_extended(cache, key, NULL, (gpointer*)&pixbuf))
1196+ return GDK_PIXBUF(g_object_ref(pixbuf));
1197+ }
1198+
1199+ if (!cache || !g_hash_table_lookup_extended(cache, path, NULL, (gpointer*)&pixbuf))
1200+ {
1201+ GError *error = NULL;
1202+ pixbuf = gdk_pixbuf_new_from_file(path, &error);
1203+ if(error)
1204+ {
1205+ g_warning("Failed to load background: %s", error->message);
1206+ g_clear_error(&error);
1207+ }
1208+ else if(cache)
1209+ g_hash_table_insert(cache, g_strdup(path), g_object_ref (pixbuf));
1210+ }
1211+
1212+ if(pixbuf)
1213+ {
1214+ GdkPixbuf* scaled = scale_image(pixbuf, mode, width, height);
1215+ if (cache)
1216+ g_hash_table_insert(cache, g_strdup(key), g_object_ref(scaled));
1217+ g_object_unref(pixbuf);
1218+ pixbuf = scaled;
1219+ }
1220+
1221+ return pixbuf;
1222+}
1223+
1224+static GdkPixbuf*
1225+scale_image(GdkPixbuf* source,
1226+ ScalingMode mode,
1227+ gint width, gint height)
1228+{
1229+ if(mode == SCALING_MODE_ZOOMED)
1230+ {
1231+ gint offset_x = 0;
1232+ gint offset_y = 0;
1233+ gint p_width = gdk_pixbuf_get_width(source);
1234+ gint p_height = gdk_pixbuf_get_height(source);
1235+ gdouble scale_x = (gdouble)width / p_width;
1236+ gdouble scale_y = (gdouble)height / p_height;
1237+
1238+ if(scale_x < scale_y)
1239+ {
1240+ scale_x = scale_y;
1241+ offset_x = (width - (p_width * scale_x)) / 2;
1242+ }
1243+ else
1244+ {
1245+ scale_y = scale_x;
1246+ offset_y = (height - (p_height * scale_y)) / 2;
1247+ }
1248+
1249+ GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE,
1250+ gdk_pixbuf_get_bits_per_sample (source),
1251+ width, height);
1252+ gdk_pixbuf_composite(source, pixbuf, 0, 0, width, height,
1253+ offset_x, offset_y, scale_x, scale_y, GDK_INTERP_BILINEAR, 0xFF);
1254+ return pixbuf;
1255+ }
1256+ else if(mode == SCALING_MODE_STRETCHED)
1257+ {
1258+ return gdk_pixbuf_scale_simple(source, width, height, GDK_INTERP_BILINEAR);
1259+ }
1260+ return GDK_PIXBUF(g_object_ref(source));
1261+}
1262+
1263+/* The following code for setting a RetainPermanent background pixmap was taken
1264+ originally from Gnome, with some fixes from MATE. see:
1265+ https://github.com/mate-desktop/mate-desktop/blob/master/libmate-desktop/mate-bg.c */
1266+static cairo_surface_t*
1267+create_root_surface(GdkScreen* screen)
1268+{
1269+ gint number, width, height;
1270+ Display *display;
1271+ Pixmap pixmap;
1272+ cairo_surface_t *surface;
1273+
1274+ number = gdk_screen_get_number (screen);
1275+ width = gdk_screen_get_width (screen);
1276+ height = gdk_screen_get_height (screen);
1277+
1278+ /* Open a new connection so with Retain Permanent so the pixmap remains when the greeter quits */
1279+ gdk_flush ();
1280+ display = XOpenDisplay (gdk_display_get_name (gdk_screen_get_display (screen)));
1281+ if (!display)
1282+ {
1283+ g_warning ("Failed to create root pixmap");
1284+ return NULL;
1285+ }
1286+
1287+ XSetCloseDownMode (display, RetainPermanent);
1288+ pixmap = XCreatePixmap (display, RootWindow (display, number), width, height, DefaultDepth (display, number));
1289+ XCloseDisplay (display);
1290+
1291+ /* Convert into a Cairo surface */
1292+ surface = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (screen),
1293+ pixmap,
1294+ GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)),
1295+ width, height);
1296+
1297+ return surface;
1298+}
1299+
1300+/* Sets the "ESETROOT_PMAP_ID" property to later be used to free the pixmap */
1301+static void
1302+set_root_pixmap_id(GdkScreen* screen,
1303+ Display* display,
1304+ Pixmap xpixmap)
1305+{
1306+
1307+ Window xroot = RootWindow (display, gdk_screen_get_number (screen));
1308+ char *atom_names[] = {"_XROOTPMAP_ID", "ESETROOT_PMAP_ID"};
1309+ Atom atoms[G_N_ELEMENTS(atom_names)] = {0};
1310+
1311+ Atom type;
1312+ int format;
1313+ unsigned long nitems, after;
1314+ unsigned char *data_root, *data_esetroot;
1315+
1316+ /* Get atoms for both properties in an array, only if they exist.
1317+ * This method is to avoid multiple round-trips to Xserver
1318+ */
1319+ if (XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), True, atoms) &&
1320+ atoms[0] != None && atoms[1] != None)
1321+ {
1322+
1323+ XGetWindowProperty (display, xroot, atoms[0], 0L, 1L, False, AnyPropertyType,
1324+ &type, &format, &nitems, &after, &data_root);
1325+ if (data_root && type == XA_PIXMAP && format == 32 && nitems == 1)
1326+ {
1327+ XGetWindowProperty (display, xroot, atoms[1], 0L, 1L, False, AnyPropertyType,
1328+ &type, &format, &nitems, &after, &data_esetroot);
1329+ if (data_esetroot && type == XA_PIXMAP && format == 32 && nitems == 1)
1330+ {
1331+ Pixmap xrootpmap = *((Pixmap *) data_root);
1332+ Pixmap esetrootpmap = *((Pixmap *) data_esetroot);
1333+ XFree (data_root);
1334+ XFree (data_esetroot);
1335+
1336+ gdk_error_trap_push ();
1337+ if (xrootpmap && xrootpmap == esetrootpmap) {
1338+ XKillClient (display, xrootpmap);
1339+ }
1340+ if (esetrootpmap && esetrootpmap != xrootpmap) {
1341+ XKillClient (display, esetrootpmap);
1342+ }
1343+
1344+ XSync (display, False);
1345+#if GTK_CHECK_VERSION (3, 0, 0)
1346+ gdk_error_trap_pop_ignored ();
1347+#else
1348+ gdk_error_trap_pop ();
1349+#endif
1350+ }
1351+ }
1352+ }
1353+
1354+ /* Get atoms for both properties in an array, create them if needed.
1355+ * This method is to avoid multiple round-trips to Xserver
1356+ */
1357+ if (!XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), False, atoms) ||
1358+ atoms[0] == None || atoms[1] == None) {
1359+ g_warning("Could not create atoms needed to set root pixmap id/properties.\n");
1360+ return;
1361+ }
1362+
1363+ /* Set new _XROOTMAP_ID and ESETROOT_PMAP_ID properties */
1364+ XChangeProperty (display, xroot, atoms[0], XA_PIXMAP, 32,
1365+ PropModeReplace, (unsigned char *) &xpixmap, 1);
1366+
1367+ XChangeProperty (display, xroot, atoms[1], XA_PIXMAP, 32,
1368+ PropModeReplace, (unsigned char *) &xpixmap, 1);
1369+}
1370+
1371+/**
1372+* set_surface_as_root:
1373+* @screen: the #GdkScreen to change root background on
1374+* @surface: the #cairo_surface_t to set root background from.
1375+* Must be an xlib surface backing a pixmap.
1376+*
1377+* Set the root pixmap, and properties pointing to it. We
1378+* do this atomically with a server grab to make sure that
1379+* we won't leak the pixmap if somebody else it setting
1380+* it at the same time. (This assumes that they follow the
1381+* same conventions we do). @surface should come from a call
1382+* to create_root_surface().
1383+**/
1384+static void
1385+set_surface_as_root(GdkScreen* screen,
1386+ cairo_surface_t* surface)
1387+{
1388+ g_return_if_fail(cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB);
1389+
1390+ /* Desktop background pixmap should be created from dummy X client since most
1391+ * applications will try to kill it with XKillClient later when changing pixmap
1392+ */
1393+ Display *display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
1394+ Pixmap pixmap_id = cairo_xlib_surface_get_drawable (surface);
1395+ Window xroot = RootWindow (display, gdk_screen_get_number(screen));
1396+
1397+ XGrabServer (display);
1398+
1399+ XSetWindowBackgroundPixmap (display, xroot, pixmap_id);
1400+ set_root_pixmap_id (screen, display, pixmap_id);
1401+ XClearWindow (display, xroot);
1402+
1403+ XFlush (display);
1404+ XUngrabServer (display);
1405+}
1406
1407=== added file 'src/greeterbackground.h'
1408--- src/greeterbackground.h 1970-01-01 00:00:00 +0000
1409+++ src/greeterbackground.h 2014-07-14 10:10:41 +0000
1410@@ -0,0 +1,48 @@
1411+#ifndef GREETER_BACKGROUND_H
1412+#define GREETER_BACKGROUND_H
1413+
1414+#include <glib-object.h>
1415+#include <gtk/gtk.h>
1416+
1417+G_BEGIN_DECLS
1418+
1419+#define GREETER_BACKGROUND_TYPE (greeter_background_get_type())
1420+#define GREETER_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GREETER_BACKGROUND_TYPE, GreeterBackground))
1421+#define GREETER_BACKGROUND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GREETER_BACKGROUND_TYPE, GreeterBackgroundClass))
1422+#define GREETER_IS_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GREETER_BACKGROUND_TYPE))
1423+#define GREETER_IS_BACKGROUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GREETER_BACKGROUND_TYPE))
1424+
1425+typedef struct _GreeterBackground GreeterBackground;
1426+typedef struct _GreeterBackgroundClass GreeterBackgroundClass;
1427+
1428+GType greeter_background_get_type(void) G_GNUC_CONST;
1429+
1430+GreeterBackground* greeter_background_new (void);
1431+void greeter_background_set_active_monitor_config (GreeterBackground* background,
1432+ const gchar* value);
1433+void greeter_background_set_default_config (GreeterBackground* background,
1434+ const gchar* bg,
1435+ gboolean user_bg,
1436+ gboolean laptop);
1437+void greeter_background_set_monitor_config (GreeterBackground* background,
1438+ const gchar* name,
1439+ const gchar* bg,
1440+ gboolean user_bg, gboolean user_bg_used,
1441+ gboolean laptop, gboolean laptop_used);
1442+void greeter_background_remove_monitor_config (GreeterBackground* background,
1443+ const gchar* name);
1444+gchar** greeter_background_get_configured_monitors (GreeterBackground* background);
1445+void greeter_background_connect (GreeterBackground* background,
1446+ GdkScreen* screen);
1447+void greeter_background_add_subwindow (GreeterBackground* background,
1448+ GtkWindow* window);
1449+void greeter_background_remove_subwindow (GreeterBackground* background,
1450+ GtkWindow* window);
1451+void greeter_background_set_custom_background (GreeterBackground* background,
1452+ const gchar* path);
1453+void greeter_background_save_xroot (GreeterBackground* background);
1454+const GdkRectangle* greeter_background_get_active_monitor_geometry(GreeterBackground* background);
1455+
1456+G_END_DECLS
1457+
1458+#endif // GREETER_BACKGROUND_H
1459
1460=== modified file 'src/lightdm-gtk-greeter.c'
1461--- src/lightdm-gtk-greeter.c 2014-07-12 14:07:13 +0000
1462+++ src/lightdm-gtk-greeter.c 2014-07-14 10:10:41 +0000
1463@@ -20,15 +20,11 @@
1464 #include <glib-unix.h>
1465
1466 #include <locale.h>
1467+#include <gdk/gdkx.h>
1468 #include <gtk/gtk.h>
1469 #include <glib/gi18n.h>
1470-#include <cairo-xlib.h>
1471 #include <sys/mman.h>
1472 #include <sys/wait.h>
1473-#include <X11/Xlib.h>
1474-#include <X11/Xatom.h>
1475-#include <gdk-pixbuf/gdk-pixbuf.h>
1476-#include <gdk/gdkx.h>
1477 #include <glib.h>
1478 #if GTK_CHECK_VERSION (3, 0, 0)
1479 #include <gtk/gtkx.h>
1480@@ -56,6 +52,7 @@
1481 #include <lightdm.h>
1482
1483 #include "src/greetermenubar.h"
1484+#include "src/greeterbackground.h"
1485 #include "src/lightdm-gtk-greeter-ui.h"
1486
1487 #if GTK_CHECK_VERSION (3, 0, 0)
1488@@ -69,8 +66,6 @@
1489
1490 /* Defaults */
1491 static gchar *default_font_name, *default_theme_name, *default_icon_theme_name;
1492-static GdkPixbuf *default_background_pixbuf = NULL;
1493-static GdkPixbuf *background_pixbuf = NULL;
1494
1495 /* Panel Widgets */
1496 static GtkWindow *panel_window;
1497@@ -99,8 +94,6 @@
1498 /* Pending Questions */
1499 static GSList *pending_questions = NULL;
1500
1501-GSList *backgrounds = NULL;
1502-
1503 /* Current choices */
1504 static gchar *current_session;
1505 static gchar *current_language;
1506@@ -108,11 +101,8 @@
1507 /* Screensaver values */
1508 int timeout, interval, prefer_blanking, allow_exposures;
1509
1510-#if GTK_CHECK_VERSION (3, 0, 0)
1511-static GdkRGBA *default_background_color = NULL;
1512-#else
1513-static GdkColor *default_background_color = NULL;
1514-#endif
1515+static GreeterBackground *greeter_background;
1516+
1517 static gboolean cancelling = FALSE, prompted = FALSE;
1518 static gboolean prompt_active = FALSE, password_prompted = FALSE;
1519 #if GTK_CHECK_VERSION (3, 0, 0)
1520@@ -146,16 +136,21 @@
1521 DimensionPosition x, y;
1522 } WindowPosition;
1523
1524-static const WindowPosition CENTERED_WINDOW_POS = { .x = {50, +1, TRUE, 0}, .y = {50, +1, TRUE, 0} };
1525+static const WindowPosition WINDOW_POS_CENTER = {.x = {50, +1, TRUE, 0}, .y = {50, +1, TRUE, 0}};
1526+static const WindowPosition WINDOW_POS_TOP_LEFT = {.x = {0, +1, FALSE, -1}, .y = {0, +1, FALSE, -1}};
1527 static WindowPosition main_window_pos;
1528+static WindowPosition panel_window_pos;
1529
1530 static GdkPixbuf* default_user_pixbuf = NULL;
1531 static gchar* default_user_icon = "avatar-default";
1532
1533+<<<<<<< TREE
1534 static gboolean use_user_background = TRUE;
1535
1536 static const gchar *LANGUAGE_DATA_CODE = "language-code";
1537 static const gchar *SESSION_DATA_KEY = "session-key";
1538+=======
1539+>>>>>>> MERGE-SOURCE
1540 static const gchar *LAYOUT_DATA_LABEL = "layout-label";
1541 #ifdef HAVE_LIBXKLAVIER
1542 static const gchar *LAYOUT_DATA_GROUP = "layout-group";
1543@@ -197,6 +192,19 @@
1544 static const gchar *INDICATOR_DATA_MENUITEMS = "indicator-data-menuitems";
1545 #endif
1546
1547+static gboolean
1548+key_file_get_boolean_extended (GKeyFile *key_file, const gchar *group_name, const gchar *key, gboolean default_value)
1549+{
1550+ GError* error = NULL;
1551+ gboolean result = g_key_file_get_boolean (key_file, group_name, key, &error);
1552+ if (error)
1553+ {
1554+ g_clear_error (&error);
1555+ return default_value;
1556+ }
1557+ return result;
1558+}
1559+
1560 static void
1561 pam_message_finalize (PAMConversationMessage *message)
1562 {
1563@@ -444,8 +452,9 @@
1564 g_closure_unref (closure);
1565 }
1566
1567- gtk_container_foreach (GTK_CONTAINER (gtk_menu_item_get_submenu (GTK_MENU_ITEM (item))),
1568- (GtkCallback)reassign_menu_item_accel, NULL);
1569+ GtkWidget* submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (item));
1570+ if(submenu)
1571+ gtk_container_foreach (GTK_CONTAINER (submenu), (GtkCallback)reassign_menu_item_accel, NULL);
1572 }
1573
1574 static void
1575@@ -828,34 +837,17 @@
1576 gtk_widget_set_sensitive (GTK_WIDGET (language_menuitem), !logged_in);
1577 }
1578
1579-static void set_background (GdkPixbuf *new_bg);
1580-
1581 static void
1582 set_user_background (const gchar *username)
1583 {
1584- LightDMUser *user;
1585- const gchar *path;
1586- GdkPixbuf *bg = NULL;
1587- GError *error = NULL;
1588-
1589- user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
1590- if (user)
1591+ const gchar *path = NULL;
1592+ if (username)
1593 {
1594- path = lightdm_user_get_background (user);
1595- if (path)
1596- {
1597- bg = gdk_pixbuf_new_from_file (path, &error);
1598- if (!bg)
1599- {
1600- g_warning ("Failed to load user background: %s", error->message);
1601- g_clear_error (&error);
1602- }
1603- }
1604+ LightDMUser *user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
1605+ if (user)
1606+ path = lightdm_user_get_background (user);
1607 }
1608-
1609- set_background (bg);
1610- if (bg)
1611- g_object_unref (bg);
1612+ greeter_background_set_custom_background(greeter_background, path);
1613 }
1614
1615 static void
1616@@ -914,58 +906,39 @@
1617 }
1618
1619 static void
1620-center_window (GtkWindow *window, GtkAllocation *unused, const WindowPosition *pos)
1621+center_window (GtkWindow *window, GtkAllocation *allocation, const WindowPosition *pos)
1622 {
1623- GdkScreen *screen = gtk_window_get_screen (window);
1624- GtkAllocation allocation;
1625- GdkRectangle monitor_geometry;
1626-
1627- gdk_screen_get_monitor_geometry (screen, gdk_screen_get_primary_monitor (screen), &monitor_geometry);
1628- gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
1629- gtk_window_move (window,
1630- monitor_geometry.x + get_absolute_position (&pos->x, monitor_geometry.width, allocation.width),
1631- monitor_geometry.y + get_absolute_position (&pos->y, monitor_geometry.height, allocation.height));
1632-}
1633-
1634-#if GTK_CHECK_VERSION (3, 0, 0)
1635-/* Use the much simpler fake transparency by drawing the window background with Cairo for Gtk3 */
1636-static gboolean
1637-background_window_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data)
1638-{
1639- if (background_pixbuf)
1640- gdk_cairo_set_source_pixbuf (cr, background_pixbuf, 0, 0);
1641- else
1642- gdk_cairo_set_source_rgba (cr, default_background_color);
1643- cairo_paint (cr);
1644- return FALSE;
1645-}
1646-
1647-static gboolean
1648-login_window_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data)
1649-{
1650- GdkScreen *screen = gtk_window_get_screen (GTK_WINDOW(widget));
1651- GtkAllocation *allocation = g_new0 (GtkAllocation, 1);
1652- GdkRectangle monitor_geometry;
1653- gint x,y;
1654-
1655- if (background_pixbuf)
1656- {
1657- gdk_screen_get_monitor_geometry (screen, gdk_screen_get_primary_monitor (screen), &monitor_geometry);
1658- gtk_widget_get_allocation (widget, allocation);
1659- x = get_absolute_position (&main_window_pos.x, monitor_geometry.width, allocation->width);
1660- y = get_absolute_position (&main_window_pos.y, monitor_geometry.height, allocation->height);
1661- gdk_cairo_set_source_pixbuf (cr, background_pixbuf, monitor_geometry.x - x, monitor_geometry.y - y);
1662- }
1663- else
1664- gdk_cairo_set_source_rgba (cr, default_background_color);
1665-
1666- cairo_paint (cr);
1667-
1668- g_free (allocation);
1669- return FALSE;
1670-}
1671-
1672-#else
1673+ const GdkRectangle *monitor_geometry = greeter_background_get_active_monitor_geometry (greeter_background);
1674+ GtkAllocation *new_allocation = NULL;
1675+ if (!allocation)
1676+ {
1677+ allocation = new_allocation = g_new0 (GtkAllocation, 1);
1678+ gtk_widget_get_allocation (GTK_WIDGET (window), new_allocation);
1679+ }
1680+ if (monitor_geometry)
1681+ gtk_window_move (window,
1682+ monitor_geometry->x + get_absolute_position (&pos->x, monitor_geometry->width, allocation->width),
1683+ monitor_geometry->y + get_absolute_position (&pos->y, monitor_geometry->height, allocation->height));
1684+ g_free (new_allocation);
1685+}
1686+
1687+static void
1688+active_monitor_changed_cb(GreeterBackground* background, gpointer user_data)
1689+{
1690+ const GdkRectangle *monitor_geometry = greeter_background_get_active_monitor_geometry (greeter_background);
1691+ if (monitor_geometry)
1692+ {
1693+ GdkGeometry hints;
1694+ hints.min_width = monitor_geometry->width;
1695+ hints.max_width = monitor_geometry->width;
1696+ hints.min_height = -1;
1697+ hints.max_height = -1;
1698+ gtk_window_set_geometry_hints (panel_window, GTK_WIDGET(panel_window),
1699+ &hints, GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
1700+ }
1701+}
1702+
1703+#if !GTK_CHECK_VERSION (3, 0, 0)
1704 static GdkRegion *
1705 cairo_region_from_rectangle (gint width, gint height, gint radius)
1706 {
1707@@ -1032,20 +1005,6 @@
1708
1709 return TRUE;
1710 }
1711-
1712-static gboolean
1713-background_window_expose (GtkWidget *widget,
1714- GdkEventExpose *event,
1715- gpointer user_data)
1716-{
1717- cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
1718- if (background_pixbuf)
1719- gdk_cairo_set_source_pixbuf (cr, background_pixbuf, 0, 0);
1720- else
1721- gdk_cairo_set_source_color (cr, default_background_color);
1722- cairo_paint (cr);
1723- return FALSE;
1724-}
1725 #endif
1726
1727 static void
1728@@ -1175,6 +1134,8 @@
1729 /* Remember last choice */
1730 g_key_file_set_value (state, "greeter", "last-session", session);
1731
1732+ greeter_background_save_xroot (greeter_background);
1733+
1734 data = g_key_file_to_data (state, &data_length, &error);
1735 if (error)
1736 g_warning ("Failed to save state file: %s", error->message);
1737@@ -1386,8 +1347,7 @@
1738 }
1739
1740 set_login_button_label (greeter, username);
1741- if (use_user_background)
1742- set_user_background (username);
1743+ set_user_background (username);
1744 set_user_image (username);
1745 user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
1746 if (user)
1747@@ -1707,22 +1667,22 @@
1748 gtk_style_context_add_class(GTK_STYLE_CONTEXT(gtk_widget_get_style_context(GTK_WIDGET(dialog))), "lightdm-gtk-greeter");
1749 #endif
1750 gtk_widget_set_name(dialog, dialog_name);
1751-#if GTK_CHECK_VERSION (3, 0, 0)
1752- g_signal_connect (G_OBJECT (dialog), "draw", G_CALLBACK (login_window_draw), NULL);
1753-#else
1754+ gtk_container_set_border_width(GTK_CONTAINER (dialog), 18);
1755+#if !GTK_CHECK_VERSION (3, 0, 0)
1756 g_signal_connect (G_OBJECT (dialog), "size-allocate", G_CALLBACK (login_window_size_allocate), NULL);
1757 #endif
1758- gtk_container_set_border_width(GTK_CONTAINER (dialog), 18);
1759-
1760+ greeter_background_add_subwindow(greeter_background, GTK_WINDOW (dialog));
1761 /* Hide the login window and show the dialog */
1762 gtk_widget_hide (GTK_WIDGET (login_window));
1763 gtk_widget_show_all (dialog);
1764- center_window (GTK_WINDOW (dialog), NULL, &CENTERED_WINDOW_POS);
1765+ center_window (GTK_WINDOW (dialog), NULL, &WINDOW_POS_CENTER);
1766
1767 result = gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK;
1768
1769+ greeter_background_remove_subwindow(greeter_background, GTK_WINDOW (dialog));
1770 gtk_widget_destroy (dialog);
1771 gtk_widget_show (GTK_WIDGET (login_window));
1772+ gtk_widget_queue_resize(GTK_WIDGET (login_window));
1773
1774 return result;
1775 }
1776@@ -2051,253 +2011,6 @@
1777 g_free (last_user);
1778 }
1779
1780-/* The following code for setting a RetainPermanent background pixmap was taken
1781- originally from Gnome, with some fixes from MATE. see:
1782- https://github.com/mate-desktop/mate-desktop/blob/master/libmate-desktop/mate-bg.c */
1783-static cairo_surface_t *
1784-create_root_surface (GdkScreen *screen)
1785-{
1786- gint number, width, height;
1787- Display *display;
1788- Pixmap pixmap;
1789- cairo_surface_t *surface;
1790-
1791- number = gdk_screen_get_number (screen);
1792- width = gdk_screen_get_width (screen);
1793- height = gdk_screen_get_height (screen);
1794-
1795- /* Open a new connection so with Retain Permanent so the pixmap remains when the greeter quits */
1796- gdk_flush ();
1797- display = XOpenDisplay (gdk_display_get_name (gdk_screen_get_display (screen)));
1798- if (!display)
1799- {
1800- g_warning ("Failed to create root pixmap");
1801- return NULL;
1802- }
1803-
1804- XSetCloseDownMode (display, RetainPermanent);
1805- pixmap = XCreatePixmap (display, RootWindow (display, number), width, height, DefaultDepth (display, number));
1806- XCloseDisplay (display);
1807-
1808- /* Convert into a Cairo surface */
1809- surface = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (screen),
1810- pixmap,
1811- GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)),
1812- width, height);
1813-
1814- return surface;
1815-}
1816-
1817-/* Sets the "ESETROOT_PMAP_ID" property to later be used to free the pixmap,
1818-*/
1819-static void
1820-set_root_pixmap_id (GdkScreen *screen,
1821- Display *display,
1822- Pixmap xpixmap)
1823-{
1824- Window xroot = RootWindow (display, gdk_screen_get_number (screen));
1825- char *atom_names[] = {"_XROOTPMAP_ID", "ESETROOT_PMAP_ID"};
1826- Atom atoms[G_N_ELEMENTS(atom_names)] = {0};
1827-
1828- Atom type;
1829- int format;
1830- unsigned long nitems, after;
1831- unsigned char *data_root, *data_esetroot;
1832-
1833- /* Get atoms for both properties in an array, only if they exist.
1834- * This method is to avoid multiple round-trips to Xserver
1835- */
1836- if (XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), True, atoms) &&
1837- atoms[0] != None && atoms[1] != None)
1838- {
1839-
1840- XGetWindowProperty (display, xroot, atoms[0], 0L, 1L, False, AnyPropertyType,
1841- &type, &format, &nitems, &after, &data_root);
1842- if (data_root && type == XA_PIXMAP && format == 32 && nitems == 1)
1843- {
1844- XGetWindowProperty (display, xroot, atoms[1], 0L, 1L, False, AnyPropertyType,
1845- &type, &format, &nitems, &after, &data_esetroot);
1846- if (data_esetroot && type == XA_PIXMAP && format == 32 && nitems == 1)
1847- {
1848- Pixmap xrootpmap = *((Pixmap *) data_root);
1849- Pixmap esetrootpmap = *((Pixmap *) data_esetroot);
1850- XFree (data_root);
1851- XFree (data_esetroot);
1852-
1853- gdk_error_trap_push ();
1854- if (xrootpmap && xrootpmap == esetrootpmap) {
1855- XKillClient (display, xrootpmap);
1856- }
1857- if (esetrootpmap && esetrootpmap != xrootpmap) {
1858- XKillClient (display, esetrootpmap);
1859- }
1860-
1861- XSync (display, False);
1862-#if GTK_CHECK_VERSION (3, 0, 0)
1863- gdk_error_trap_pop_ignored ();
1864-#else
1865- gdk_error_trap_pop ();
1866-#endif
1867-
1868- }
1869- }
1870- }
1871-
1872- /* Get atoms for both properties in an array, create them if needed.
1873- * This method is to avoid multiple round-trips to Xserver
1874- */
1875- if (!XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), False, atoms) ||
1876- atoms[0] == None || atoms[1] == None) {
1877- g_warning("Could not create atoms needed to set root pixmap id/properties.\n");
1878- return;
1879- }
1880-
1881- /* Set new _XROOTMAP_ID and ESETROOT_PMAP_ID properties */
1882- XChangeProperty (display, xroot, atoms[0], XA_PIXMAP, 32,
1883- PropModeReplace, (unsigned char *) &xpixmap, 1);
1884-
1885- XChangeProperty (display, xroot, atoms[1], XA_PIXMAP, 32,
1886- PropModeReplace, (unsigned char *) &xpixmap, 1);
1887-}
1888-
1889-/**
1890-* set_surface_as_root:
1891-* @screen: the #GdkScreen to change root background on
1892-* @surface: the #cairo_surface_t to set root background from.
1893-* Must be an xlib surface backing a pixmap.
1894-*
1895-* Set the root pixmap, and properties pointing to it. We
1896-* do this atomically with a server grab to make sure that
1897-* we won't leak the pixmap if somebody else it setting
1898-* it at the same time. (This assumes that they follow the
1899-* same conventions we do). @surface should come from a call
1900-* to create_root_surface().
1901-**/
1902-static void
1903-set_surface_as_root (GdkScreen *screen, cairo_surface_t *surface)
1904-{
1905- g_return_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB);
1906-
1907- /* Desktop background pixmap should be created from dummy X client since most
1908- * applications will try to kill it with XKillClient later when changing pixmap
1909- */
1910- Display *display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
1911- Pixmap pixmap_id = cairo_xlib_surface_get_drawable (surface);
1912- Window xroot = RootWindow (display, gdk_screen_get_number (screen));
1913-
1914- XGrabServer (display);
1915-
1916- XSetWindowBackgroundPixmap (display, xroot, pixmap_id);
1917- set_root_pixmap_id (screen, display, pixmap_id);
1918- XClearWindow (display, xroot);
1919-
1920- XFlush (display);
1921- XUngrabServer (display);
1922-}
1923-
1924-static void
1925-set_background (GdkPixbuf *new_bg)
1926-{
1927- GdkRectangle monitor_geometry;
1928- GdkPixbuf *bg = NULL, *p = NULL;
1929- GSList *iter;
1930- gint i, p_height, p_width, offset_x, offset_y;
1931- gdouble scale_x, scale_y, scale;
1932- GdkInterpType interp_type;
1933- gint num_screens = 1;
1934-
1935- if (new_bg)
1936- bg = new_bg;
1937- else
1938- bg = default_background_pixbuf;
1939-
1940- #if GDK_VERSION_CUR_STABLE < G_ENCODE_VERSION(3, 10)
1941- num_screens = gdk_display_get_n_screens (gdk_display_get_default ());
1942- #endif
1943-
1944- /* Set the background */
1945- for (i = 0; i < num_screens; i++)
1946- {
1947- GdkScreen *screen;
1948- cairo_surface_t *surface;
1949- cairo_t *c;
1950- gint monitor;
1951-
1952- screen = gdk_display_get_screen (gdk_display_get_default (), i);
1953- surface = create_root_surface (screen);
1954- c = cairo_create (surface);
1955-
1956- for (monitor = 0; monitor < gdk_screen_get_n_monitors (screen); monitor++)
1957- {
1958- gdk_screen_get_monitor_geometry (screen, monitor, &monitor_geometry);
1959-
1960- if (bg)
1961- {
1962- p_width = gdk_pixbuf_get_width (bg);
1963- p_height = gdk_pixbuf_get_height (bg);
1964-
1965- scale_x = (gdouble)monitor_geometry.width / p_width;
1966- scale_y = (gdouble)monitor_geometry.height / p_height;
1967-
1968- if (scale_x < scale_y)
1969- {
1970- scale = scale_y;
1971- offset_x = (monitor_geometry.width - (p_width * scale)) / 2;
1972- offset_y = 0;
1973- }
1974- else
1975- {
1976- scale = scale_x;
1977- offset_x = 0;
1978- offset_y = (monitor_geometry.height - (p_height * scale)) / 2;
1979- }
1980-
1981- p = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, gdk_pixbuf_get_bits_per_sample (bg),
1982- monitor_geometry.width, monitor_geometry.height);
1983-
1984- /* Set interpolation type */
1985- if (monitor_geometry.width == p_width && monitor_geometry.height == p_height)
1986- interp_type = GDK_INTERP_NEAREST;
1987- else
1988- interp_type = GDK_INTERP_BILINEAR;
1989-
1990- /* Zoom the background pixbuf to fit the screen */
1991- gdk_pixbuf_composite (bg, p, 0, 0, monitor_geometry.width, monitor_geometry.height,
1992- offset_x, offset_y, scale, scale, interp_type, 255);
1993-
1994- gdk_cairo_set_source_pixbuf (c, p, monitor_geometry.x, monitor_geometry.y);
1995-
1996- /* Make the background pixbuf globally accessible so it can be reused for fake transparency */
1997- if (background_pixbuf)
1998- g_object_unref (background_pixbuf);
1999-
2000- background_pixbuf = p;
2001- }
2002- else
2003- {
2004-#if GTK_CHECK_VERSION (3, 0, 0)
2005- gdk_cairo_set_source_rgba (c, default_background_color);
2006-#else
2007- gdk_cairo_set_source_color (c, default_background_color);
2008-#endif
2009- background_pixbuf = NULL;
2010- }
2011- cairo_paint (c);
2012- iter = g_slist_nth (backgrounds, monitor);
2013- gtk_widget_queue_draw (GTK_WIDGET (iter->data));
2014- }
2015-
2016- cairo_destroy (c);
2017-
2018- /* Refresh background */
2019- gdk_flush ();
2020- set_surface_as_root (screen, surface);
2021- cairo_surface_destroy (surface);
2022- }
2023- gtk_widget_queue_draw (GTK_WIDGET (login_window));
2024- gtk_widget_queue_draw (GTK_WIDGET (panel_window));
2025-}
2026-
2027 static gboolean
2028 clock_timeout_thread (void)
2029 {
2030@@ -2586,20 +2299,11 @@
2031 GtkWidget *image, *infobar_compat, *content_area;
2032 gchar *value, *state_dir;
2033 #if GTK_CHECK_VERSION (3, 0, 0)
2034- GdkRGBA background_color;
2035 GtkIconTheme *icon_theme;
2036 GtkCssProvider *css_provider;
2037-#else
2038- GdkColor background_color;
2039 #endif
2040 GError *error = NULL;
2041
2042- /* Background windows */
2043- gint monitor, scr;
2044- gint numScreens = 1;
2045- GdkScreen *screen;
2046- GtkWidget *window;
2047-
2048 Display* display;
2049
2050 #ifdef START_INDICATOR_SERVICES
2051@@ -2661,47 +2365,6 @@
2052 /* Set default cursor */
2053 gdk_window_set_cursor (gdk_get_default_root_window (), gdk_cursor_new (GDK_LEFT_PTR));
2054
2055- /* Load background */
2056- value = g_key_file_get_value (config, "greeter", "background", NULL);
2057- if (!value)
2058- value = g_strdup ("#000000");
2059-#if GTK_CHECK_VERSION (3, 0, 0)
2060- if (!gdk_rgba_parse (&background_color, value))
2061-#else
2062- if (!gdk_color_parse (value, &background_color))
2063-#endif
2064- {
2065- gchar *path;
2066- GError *error = NULL;
2067-
2068- if (g_path_is_absolute (value))
2069- path = g_strdup (value);
2070- else
2071- path = g_build_filename (GREETER_DATA_DIR, value, NULL);
2072-
2073- g_debug ("Loading background %s", path);
2074- default_background_pixbuf = gdk_pixbuf_new_from_file (path, &error);
2075- if (!default_background_pixbuf)
2076- g_warning ("Failed to load background: %s", error->message);
2077- g_clear_error (&error);
2078- g_free (path);
2079- }
2080- else
2081- {
2082- g_debug ("Using background color %s", value);
2083-#if GTK_CHECK_VERSION (3, 0, 0)
2084- default_background_color = gdk_rgba_copy (&background_color);
2085-#else
2086- default_background_color = gdk_color_copy (&background_color);
2087-#endif
2088- }
2089- g_free (value);
2090-
2091- use_user_background = g_key_file_get_boolean(config, "greeter", "user-background", &error);
2092- if (error)
2093- use_user_background = TRUE;
2094- g_clear_error(&error);
2095-
2096 /* Make the greeter behave a bit more like a screensaver if used as un/lock-screen by blanking the screen */
2097 gchar* end_ptr = NULL;
2098 int screensaver_timeout = 60;
2099@@ -2789,7 +2452,6 @@
2100 #if GTK_CHECK_VERSION (3, 0, 0)
2101 gtk_style_context_add_class(GTK_STYLE_CONTEXT(gtk_widget_get_style_context(GTK_WIDGET(panel_window))), "lightdm-gtk-greeter");
2102 gtk_style_context_add_class(GTK_STYLE_CONTEXT(gtk_widget_get_style_context(GTK_WIDGET(panel_window))), GTK_STYLE_CLASS_MENUBAR);
2103- g_signal_connect (G_OBJECT (panel_window), "draw", G_CALLBACK (background_window_draw), NULL);
2104 #endif
2105 menubar = GTK_WIDGET (gtk_builder_get_object (builder, "menubar"));
2106
2107@@ -2800,6 +2462,10 @@
2108 username_entry = GTK_ENTRY (gtk_builder_get_object (builder, "username_entry"));
2109 password_entry = GTK_ENTRY (gtk_builder_get_object (builder, "password_entry"));
2110
2111+#if !GTK_CHECK_VERSION (3, 0, 0)
2112+ g_signal_connect (G_OBJECT (login_window), "size-allocate", G_CALLBACK (login_window_size_allocate), NULL);
2113+#endif
2114+
2115 /* Add InfoBar via code for GTK+2 compatability */
2116 infobar_compat = GTK_WIDGET(gtk_builder_get_object(builder, "infobar_compat"));
2117 info_bar = GTK_INFO_BAR (gtk_info_bar_new());
2118@@ -2817,12 +2483,6 @@
2119 cancel_button = GTK_BUTTON (gtk_builder_get_object (builder, "cancel_button"));
2120 login_button = GTK_BUTTON (gtk_builder_get_object (builder, "login_button"));
2121
2122-#if GTK_CHECK_VERSION (3, 0, 0)
2123- g_signal_connect (G_OBJECT (login_window), "draw", G_CALLBACK (login_window_draw), NULL);
2124-#else
2125- g_signal_connect (G_OBJECT (login_window), "size-allocate", G_CALLBACK (login_window_size_allocate), NULL);
2126-#endif
2127-
2128 /* To maintain compatability with GTK+2, set special properties here */
2129 #if GTK_CHECK_VERSION (3, 0, 0)
2130 gtk_style_context_add_class(GTK_STYLE_CONTEXT(gtk_widget_get_style_context(GTK_WIDGET(login_window))), "lightdm-gtk-greeter");
2131@@ -2902,7 +2562,7 @@
2132 {
2133 LightDMSession *session = item->data;
2134 GtkWidget *radiomenuitem;
2135-
2136+
2137 radiomenuitem = gtk_radio_menu_item_new_with_label (sessions, lightdm_session_get_name (session));
2138 g_object_set_data (G_OBJECT (radiomenuitem), SESSION_DATA_KEY, (gpointer) lightdm_session_get_key (session));
2139 sessions = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radiomenuitem));
2140@@ -3035,6 +2695,7 @@
2141
2142 #if GTK_CHECK_VERSION (3, 0, 0)
2143 /* A bit of CSS */
2144+ GdkRGBA lightdm_gtk_greeter_override_defaults;
2145 css_provider = gtk_css_provider_new ();
2146 gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_application, lightdm_gtk_greeter_css_application_length, NULL);
2147 gtk_style_context_add_provider_for_screen(gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider),
2148@@ -3043,77 +2704,78 @@
2149 guint fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_APPLICATION;
2150 if (gtk_style_context_lookup_color (gtk_widget_get_style_context (GTK_WIDGET (login_window)),
2151 "lightdm-gtk-greeter-override-defaults",
2152- &background_color))
2153+ &lightdm_gtk_greeter_override_defaults))
2154 fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_FALLBACK;
2155 gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_fallback, lightdm_gtk_greeter_css_fallback_length, NULL);
2156 gtk_style_context_add_provider_for_screen(gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider),
2157 fallback_css_priority);
2158 #endif
2159
2160+ /* Background */
2161+ greeter_background = greeter_background_new ();
2162+
2163+ value = g_key_file_get_value (config, "greeter", "active-monitor", NULL);
2164+ greeter_background_set_active_monitor_config (greeter_background, value ? value : "#cursor");
2165+ g_free (value);
2166+
2167+ value = g_key_file_get_value (config, "greeter", "background", NULL);
2168+ greeter_background_set_default_config (greeter_background, value,
2169+ key_file_get_boolean_extended (config, "greeter", "user-background", TRUE),
2170+ key_file_get_boolean_extended (config, "greeter", "laptop", FALSE));
2171+ g_free (value);
2172+
2173+ const gchar *CONFIG_MONITOR_PREFIX = "monitor:";
2174+ gchar **config_group;
2175+ gchar **config_groups = g_key_file_get_groups (config, NULL);
2176+ for (config_group = config_groups; *config_group; ++config_group)
2177+ {
2178+ if(!g_str_has_prefix (*config_group, CONFIG_MONITOR_PREFIX))
2179+ continue;
2180+ const gchar *name = *config_group + sizeof(CONFIG_MONITOR_PREFIX);
2181+ while (*name && g_ascii_isspace (*name))
2182+ ++name;
2183+ g_debug ("Monitor configuration found: '%s'", name);
2184+
2185+ GError *user_bg_error = NULL, *laptop_error = NULL;
2186+ gboolean user_bg = g_key_file_get_boolean (config, *config_group, "user-background", &user_bg_error);
2187+ gboolean laptop = g_key_file_get_boolean (config, *config_group, "laptop", &laptop_error);
2188+ value = g_key_file_get_value (config, *config_group, "background", NULL);
2189+
2190+ greeter_background_set_monitor_config (greeter_background, name, value,
2191+ user_bg, user_bg_error == NULL,
2192+ laptop, laptop_error == NULL);
2193+
2194+ g_free (value);
2195+ g_clear_error (&laptop_error);
2196+ g_clear_error (&user_bg_error);
2197+ }
2198+ g_strfreev (config_groups);
2199+
2200+ g_signal_connect (G_OBJECT (greeter_background), "active-monitor-changed", G_CALLBACK(active_monitor_changed_cb), NULL);
2201+ greeter_background_add_subwindow (greeter_background, login_window);
2202+ greeter_background_add_subwindow (greeter_background, panel_window);
2203+ greeter_background_connect (greeter_background, gdk_screen_get_default ());
2204+
2205 /* Users combobox */
2206 renderer = gtk_cell_renderer_text_new();
2207 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (user_combo), renderer, TRUE);
2208 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (user_combo), renderer, "text", 1);
2209 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (user_combo), renderer, "weight", 2);
2210
2211- #if GDK_VERSION_CUR_STABLE < G_ENCODE_VERSION(3, 10)
2212- numScreens = gdk_display_get_n_screens (gdk_display_get_default());
2213- #endif
2214-
2215- /* Set up the background images */
2216- for (scr = 0; scr < numScreens; scr++)
2217- {
2218- screen = gdk_display_get_screen (gdk_display_get_default (), scr);
2219- for (monitor = 0; monitor < gdk_screen_get_n_monitors (screen); monitor++)
2220- {
2221- gdk_screen_get_monitor_geometry (screen, monitor, &monitor_geometry);
2222-
2223- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2224- gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DESKTOP);
2225-#if GTK_CHECK_VERSION (3, 0, 0)
2226- gtk_widget_override_background_color(GTK_WIDGET(window), GTK_STATE_FLAG_NORMAL, &background_color);
2227-#else
2228- gtk_widget_modify_bg(GTK_WIDGET(window), GTK_STATE_NORMAL, &background_color);
2229-#endif
2230- gtk_window_set_screen(GTK_WINDOW(window), screen);
2231- gtk_window_set_keep_below(GTK_WINDOW(window), TRUE);
2232- gtk_widget_set_size_request(window, monitor_geometry.width, monitor_geometry.height);
2233- gtk_window_set_resizable (GTK_WINDOW(window), FALSE);
2234- gtk_widget_set_app_paintable (GTK_WIDGET(window), TRUE);
2235- gtk_window_move (GTK_WINDOW(window), monitor_geometry.x, monitor_geometry.y);
2236-
2237- backgrounds = g_slist_prepend(backgrounds, window);
2238- gtk_widget_show (window);
2239-#if GTK_CHECK_VERSION (3, 0, 0)
2240- g_signal_connect (G_OBJECT (window), "draw", G_CALLBACK (background_window_draw), NULL);
2241-#else
2242- g_signal_connect (G_OBJECT (window), "expose-event", G_CALLBACK (background_window_expose), NULL);
2243-#endif
2244- gtk_widget_queue_draw (GTK_WIDGET(window));
2245- }
2246- }
2247- backgrounds = g_slist_reverse(backgrounds);
2248-
2249 if (lightdm_greeter_get_hide_users_hint (greeter))
2250 {
2251- /* Set the background to default */
2252- set_background (NULL);
2253 set_user_image (NULL);
2254 start_authentication ("*other");
2255 }
2256 else
2257 {
2258- if (!use_user_background)
2259- set_background (NULL);
2260- /* This also sets the background to user's */
2261 load_user_list ();
2262 gtk_widget_hide (GTK_WIDGET (cancel_button));
2263 gtk_widget_show (GTK_WIDGET (user_combo));
2264 }
2265
2266- /* Window position */
2267- /* Default: x-center, y-center */
2268- main_window_pos = CENTERED_WINDOW_POS;
2269+ /* Windows positions */
2270+ main_window_pos = WINDOW_POS_CENTER;
2271 value = g_key_file_get_value (config, "greeter", "position", NULL);
2272 if (value)
2273 {
2274@@ -3129,21 +2791,17 @@
2275
2276 g_free (value);
2277 }
2278+ panel_window_pos = WINDOW_POS_TOP_LEFT;
2279
2280 gtk_builder_connect_signals(builder, greeter);
2281
2282+ gtk_widget_show (GTK_WIDGET (panel_window));
2283+ center_window (panel_window, NULL, &panel_window_pos);
2284+ g_signal_connect (GTK_WIDGET (panel_window), "size-allocate", G_CALLBACK (center_window), &panel_window_pos);
2285+
2286 gtk_widget_show (GTK_WIDGET (login_window));
2287- center_window (login_window, NULL, &main_window_pos);
2288+ center_window (login_window, NULL, &main_window_pos);
2289 g_signal_connect (GTK_WIDGET (login_window), "size-allocate", G_CALLBACK (center_window), &main_window_pos);
2290-
2291- gtk_widget_show (GTK_WIDGET (panel_window));
2292- GtkAllocation allocation;
2293- gtk_widget_get_allocation (GTK_WIDGET (panel_window), &allocation);
2294- gdk_screen_get_monitor_geometry (gdk_screen_get_default (), gdk_screen_get_primary_monitor (gdk_screen_get_default ()), &monitor_geometry);
2295- gtk_window_resize (panel_window, monitor_geometry.width, allocation.height);
2296- gtk_window_move (panel_window, monitor_geometry.x, monitor_geometry.y);
2297-
2298- gtk_widget_show (GTK_WIDGET (login_window));
2299 gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME);
2300
2301 if (a11y_keyboard_command)
2302@@ -3192,16 +2850,5 @@
2303 }
2304 #endif
2305
2306- if (background_pixbuf)
2307- g_object_unref (background_pixbuf);
2308- if (default_background_pixbuf)
2309- g_object_unref (default_background_pixbuf);
2310- if (default_background_color)
2311-#if GTK_CHECK_VERSION (3, 0, 0)
2312- gdk_rgba_free (default_background_color);
2313-#else
2314- gdk_color_free (default_background_color);
2315-#endif
2316-
2317 return EXIT_SUCCESS;
2318 }

Subscribers

People subscribed via source and target branches