Merge lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/greeter-background into lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/trunk
- greeter-background
- Merge into trunk
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 | ||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sean Davis | Approve | ||
Review via email: mp+225019@code.launchpad.net |
Commit message
Description of the change
Using GreeterBackground class to manage backgrounds.
[greeter]
# Sets monitor to display greeter windows.
# Special value - "#cursor".
active-
# 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
- 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
Simon Steinbeiß (ochosi) wrote : | # |
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-
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.
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-
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.
Preview Diff
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 | } |
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?)