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

Proposed by Andrew P.
Status: Merged
Merged at revision: 316
Proposed branch: lp:~kalgasnik/lightdm-gtk-greeter/background-transition
Merge into: lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/trunk
Diff against target: 1452 lines (+646/-224)
5 files modified
src/Makefile.am (+3/-2)
src/greeterbackground.c (+543/-167)
src/greeterbackground.h (+5/-5)
src/lightdm-gtk-greeter.c (+95/-44)
src/lightdm-gtk-greeter.glade (+0/-6)
To merge this branch: bzr merge lp:~kalgasnik/lightdm-gtk-greeter/background-transition
Reviewer Review Type Date Requested Status
Simon Steinbeiß Approve
Review via email: mp+241082@code.launchpad.net

Description of the change

Add transition to backgrounds change.

1. Transition function: easy-in-out
2. Animation: drawing new background with different alpha over old background
3. Duration: 500ms
4. Delay before changing to user's background: 250ms

At first I thought to make all these things configurable, but someone can say that it is too much.
"transition-duration" is enough.

Enabled by default, I'm not sure that it is good idea.

To post a comment you must log in.
Revision history for this message
Andrew P. (kalgasnik) wrote :

There is one bug related to this branch: https://bugs.launchpad.net/ubuntu/+source/lightdm-gtk-greeter/+bug/1394639/comments/8

I can't confirm it so I can't fix it. I'm not even sure that trunk version is not effected.

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

Can you provide some examples for the configuration in this case?

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

[greeter]
# 500 by default, 0 to disable transition effect
transition-duration = <duration-in-ms>

# Transition function, "none" to disable transition effect
# "easy-in-out" by default
transition-type = easy-in-out|linear|none

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

When I try this on my laptop, there does not seem to be a transition...

transition-duration=1000
transition-type=easy-in-out

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

Maybe you have user-background = false or identical default and user's backgrounds.
It must looks like http://youtu.be/hVtoEtG-OXE

Oh, "easy" -> "ease", my inglish is not so well. But it isn't the source of the problem.

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

I've checked out your branch (mostly testing, not code review) and it works just fine! Nice work on that and sorry it took so long.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Makefile.am'
2--- src/Makefile.am 2014-08-20 23:23:59 +0000
3+++ src/Makefile.am 2014-12-10 07:59:47 +0000
4@@ -41,7 +41,8 @@
5 $(LIBX11_LIBS) \
6 $(LIBINDICATOR_LIBS) \
7 $(LIBIDO_LIBS) \
8- $(LIBXKLAVIER_LIBS)
9+ $(LIBXKLAVIER_LIBS)\
10+ -lm
11
12 if MAINTAINER_MODE
13
14@@ -65,4 +66,4 @@
15 EXTRA_DIST = \
16 lightdm-gtk-greeter.glade \
17 lightdm-gtk-greeter-fallback.css \
18- lightdm-gtk-greeter-application.css
19\ No newline at end of file
20+ lightdm-gtk-greeter-application.css
21
22=== modified file 'src/greeterbackground.c'
23--- src/greeterbackground.c 2014-08-31 17:45:52 +0000
24+++ src/greeterbackground.c 2014-12-10 07:59:47 +0000
25@@ -1,4 +1,5 @@
26
27+#include <math.h>
28 #include <cairo-xlib.h>
29 #include <gtk/gtk.h>
30 #include <gdk/gdkx.h>
31@@ -14,6 +15,8 @@
32 BACKGROUND_TYPE_INVALID,
33 /* Do not use this monitor */
34 BACKGROUND_TYPE_SKIP,
35+ /* Do not override window background */
36+ BACKGROUND_TYPE_DEFAULT,
37 /* Solid color */
38 BACKGROUND_TYPE_COLOR,
39 /* Path to image and scaling mode */
40@@ -22,6 +25,7 @@
41 } BackgroundType;
42
43 static const gchar* BACKGROUND_TYPE_SKIP_VALUE = "#skip";
44+static const gchar* BACKGROUND_TYPE_DEFAULT_VALUE = "#default";
45
46 typedef enum
47 {
48@@ -34,6 +38,9 @@
49
50 static const gchar* SCALING_MODE_PREFIXES[] = {"#source:", "#zoomed:", "#stretched:", NULL};
51
52+typedef gdouble (*TransitionFunction)(gdouble x);
53+typedef void (*TransitionDraw)(gconstpointer monitor, cairo_t* cr);
54+
55 /* Background configuration (parsed from background=... option).
56 Used to fill <Background> */
57 typedef struct
58@@ -50,18 +57,32 @@
59 } options;
60 } BackgroundConfig;
61
62+/* Transition configuration
63+ Used to as part of <MonitorConfig> and <Monitor> */
64+typedef struct
65+{
66+ /* Transition duration, in ms */
67+ glong duration;
68+ TransitionFunction func;
69+ /* Function to draw monitor background */
70+ TransitionDraw draw;
71+} TransitionConfig;
72+
73 /* Store monitor configuration */
74 typedef struct
75 {
76 BackgroundConfig bg;
77 gboolean user_bg;
78 gboolean laptop;
79+
80+ TransitionConfig transition;
81 } MonitorConfig;
82
83 /* Actual drawing information attached to monitor.
84 * Used to separate configured monitor background and user background. */
85 typedef struct
86 {
87+ gint ref_count;
88 BackgroundType type;
89 union
90 {
91@@ -80,14 +101,29 @@
92 gulong window_draw_handler_id;
93
94 /* Configured background */
95- Background background_configured;
96- /* Background used to display user-background */
97- Background background_custom;
98+ Background* background_configured;
99 /* Current monitor background: &background_configured or &background_custom
100 * Monitors with type = BACKGROUND_TYPE_SKIP have background = NULL */
101- const Background* background;
102+ Background* background;
103+
104+ struct
105+ {
106+ TransitionConfig config;
107+
108+ /* Old background, stage == 0.0 */
109+ Background* from;
110+ /* New background, stage == 1.0 */
111+ Background* to;
112+
113+ guint timer_id;
114+ gint64 started;
115+ /* Current stage */
116+ gdouble stage;
117+ } transition;
118 } Monitor;
119
120+static const Monitor INVALID_MONITOR_STRUCT = {0};
121+
122 struct _GreeterBackground
123 {
124 GObject parent_instance;
125@@ -141,6 +177,9 @@
126 gboolean follow_cursor;
127 /* Use cursor position to determinate initial active monitor */
128 gboolean follow_cursor_to_init;
129+
130+ /* Name => transition function, inited in set_monitor_config() */
131+ GHashTable* transition_types;
132 };
133
134 enum
135@@ -151,20 +190,6 @@
136
137 static guint background_signals[BACKGROUND_SIGNAL_LAST] = {0};
138
139-static const MonitorConfig DEFAULT_MONITOR_CONFIG =
140-{
141- .bg =
142- {
143- .type = BACKGROUND_TYPE_COLOR,
144- .options =
145- {
146- .color = {.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0}
147- }
148- },
149- .user_bg = TRUE,
150- .laptop = FALSE
151-};
152-
153 static const gchar* DBUS_UPOWER_NAME = "org.freedesktop.UPower";
154 static const gchar* DBUS_UPOWER_PATH = "/org/freedesktop/UPower";
155 static const gchar* DBUS_UPOWER_INTERFACE = "org.freedesktop.UPower";
156@@ -177,15 +202,13 @@
157
158 void greeter_background_set_active_monitor_config (GreeterBackground* background,
159 const gchar* value);
160-void greeter_background_set_default_config (GreeterBackground* background,
161- const gchar* bg,
162- gboolean user_bg,
163- gboolean laptop);
164 void greeter_background_set_monitor_config (GreeterBackground* background,
165 const gchar* name,
166- const gchar* bg,
167+ const gchar* bg, /* NULL to use fallback value */
168 gboolean user_bg, gboolean user_bg_used,
169- gboolean laptop, gboolean laptop_used);
170+ gboolean laptop, gboolean laptop_used,
171+ gint transition_duration, /* -1 to use fallback value */
172+ const gchar* transition_type); /* NULL to use fallback value */
173 void greeter_background_remove_monitor_config (GreeterBackground* background,
174 const gchar* name);
175 gchar** greeter_background_get_configured_monitors (GreeterBackground* background);
176@@ -212,6 +235,8 @@
177 GreeterBackground* background);
178 static void greeter_background_monitors_changed_cb (GdkScreen* screen,
179 GreeterBackground* background);
180+static void greeter_background_child_destroyed_cb (GtkWidget* child,
181+ GreeterBackground* background);
182
183 /* struct BackgroundConfig */
184 static gboolean background_config_initialize (BackgroundConfig* config,
185@@ -227,17 +252,28 @@
186 MonitorConfig* dest);
187
188 /* struct Background */
189-static gboolean background_initialize (Background* bg,
190- const BackgroundConfig* config,
191+static Background* background_new (const BackgroundConfig* config,
192 const Monitor* monitor,
193 GHashTable* images_cache);
194+static Background* background_ref (Background* bg);
195+static void background_unref (Background** bg);
196 static void background_finalize (Background* bg);
197
198 /* struct Monitor */
199 static void monitor_finalize (Monitor* info);
200 static void monitor_set_background (Monitor* monitor,
201- const Background* background);
202+ Background* background);
203+static void monitor_start_transition (Monitor* monitor,
204+ Background* from,
205+ Background* to);
206+static void monitor_stop_transition (Monitor* monitor);
207+static gboolean monitor_transition_cb (GtkWidget *widget,
208+ GdkFrameClock* frame_clock,
209+ Monitor* monitor);
210+static void monitor_transition_draw_alpha (const Monitor* monitor,
211+ cairo_t* cr);
212 static void monitor_draw_background (const Monitor* monitor,
213+ const Background* background,
214 cairo_t* cr);
215 static gboolean monitor_window_draw_cb (GtkWidget* widget,
216 cairo_t* cr,
217@@ -259,7 +295,32 @@
218 Pixmap xpixmap);
219 static void set_surface_as_root (GdkScreen* screen,
220 cairo_surface_t* surface);
221-
222+static gdouble transition_func_linear (gdouble x);
223+static gdouble transition_func_easy_in_out (gdouble x);
224+
225+/* Implemented in lightdm-gtk-greeter.c */
226+gpointer greeter_save_focus(GtkWidget* widget);
227+void greeter_restore_focus(const gpointer saved_data);
228+
229+static const MonitorConfig DEFAULT_MONITOR_CONFIG =
230+{
231+ .bg =
232+ {
233+ .type = BACKGROUND_TYPE_COLOR,
234+ .options =
235+ {
236+ .color = {.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0}
237+ }
238+ },
239+ .user_bg = TRUE,
240+ .laptop = FALSE,
241+ .transition =
242+ {
243+ .duration = 500,
244+ .func = transition_func_easy_in_out,
245+ .draw = (TransitionDraw)monitor_transition_draw_alpha
246+ }
247+};
248
249 /* Implementation */
250
251@@ -302,11 +363,14 @@
252 self->priv->laptop_lid_closed = FALSE;
253 }
254
255-GreeterBackground*
256+GreeterBackground*
257 greeter_background_new(GtkWidget* child)
258 {
259+ g_return_val_if_fail(child != NULL, NULL);
260+
261 GreeterBackground* background = GREETER_BACKGROUND(g_object_new(greeter_background_get_type(), NULL));
262 background->priv->child = child;
263+ g_signal_connect(background->priv->child, "destroy", G_CALLBACK(greeter_background_child_destroyed_cb), background);
264 return background;
265 }
266
267@@ -346,42 +410,55 @@
268 }
269
270 void
271-greeter_background_set_default_config(GreeterBackground* background,
272- const gchar* bg,
273- gboolean user_bg,
274- gboolean laptop)
275-{
276- g_return_if_fail(GREETER_IS_BACKGROUND(background));
277- GreeterBackgroundPrivate* priv = background->priv;
278-
279- if(priv->default_config)
280- monitor_config_free(priv->default_config);
281-
282- priv->default_config = g_new0(MonitorConfig, 1);
283- if(!background_config_initialize(&priv->default_config->bg, bg))
284- background_config_copy(&DEFAULT_MONITOR_CONFIG.bg, &priv->default_config->bg);
285- priv->default_config->user_bg = user_bg;
286- priv->default_config->laptop = laptop;
287-}
288-
289-void
290 greeter_background_set_monitor_config(GreeterBackground* background,
291 const gchar* name,
292 const gchar* bg,
293 gboolean user_bg, gboolean user_bg_used,
294- gboolean laptop, gboolean laptop_used)
295+ gboolean laptop, gboolean laptop_used,
296+ gint transition_duration,
297+ const gchar* transition_type)
298 {
299 g_return_if_fail(GREETER_IS_BACKGROUND(background));
300 GreeterBackgroundPrivate* priv = background->priv;
301
302 MonitorConfig* config = g_new0(MonitorConfig, 1);
303
304+ const MonitorConfig* FALLBACK = (g_strcmp0(name, GREETER_BACKGROUND_DEFAULT) == 0) ? &DEFAULT_MONITOR_CONFIG : priv->default_config;
305+
306 if(!background_config_initialize(&config->bg, bg))
307- background_config_copy(&priv->default_config->bg, &config->bg);
308- config->user_bg = user_bg_used ? user_bg : priv->default_config->user_bg;
309- config->laptop = laptop_used ? laptop : priv->default_config->laptop;
310-
311- g_hash_table_insert(priv->configs, g_strdup(name), config);
312+ background_config_copy(&FALLBACK->bg, &config->bg);
313+ config->user_bg = user_bg_used ? user_bg : FALLBACK->user_bg;
314+ config->laptop = laptop_used ? laptop : FALLBACK->laptop;
315+ config->transition.duration = transition_duration >= 0 ? transition_duration : FALLBACK->transition.duration;
316+ config->transition.draw = FALLBACK->transition.draw;
317+
318+ if(transition_type)
319+ {
320+ if(!priv->transition_types)
321+ {
322+ priv->transition_types = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
323+ g_hash_table_insert(priv->transition_types, g_strdup("none"), NULL);
324+ g_hash_table_insert(priv->transition_types, g_strdup("linear"), transition_func_linear);
325+ g_hash_table_insert(priv->transition_types, g_strdup("easy-in-out"), transition_func_easy_in_out);
326+ }
327+ if(!g_hash_table_lookup_extended(priv->transition_types, transition_type, NULL, (gpointer*)&config->transition.func))
328+ {
329+ g_warning("[Background] Invalid transition type for '%s' monitor: '%s'. Using fallback value.",
330+ name, transition_type);
331+ config->transition.func = FALLBACK->transition.func;
332+ }
333+ }
334+ else
335+ config->transition.func = FALLBACK->transition.func;
336+
337+ if(FALLBACK == priv->default_config)
338+ g_hash_table_insert(priv->configs, g_strdup(name), config);
339+ else
340+ {
341+ if(priv->default_config)
342+ monitor_config_free(priv->default_config);
343+ priv->default_config = config;
344+ }
345 }
346
347 void
348@@ -418,12 +495,9 @@
349 g_return_if_fail(GREETER_IS_BACKGROUND(background));
350 g_return_if_fail(GDK_IS_SCREEN(screen));
351
352- g_debug("Connecting to screen");
353+ g_debug("[Background] Connecting to screen: %p", screen);
354
355 GreeterBackgroundPrivate* priv = background->priv;
356- gulong screen_monitors_changed_handler_id = (priv->screen == screen) ? priv->screen_monitors_changed_handler_id : 0;
357- if(screen_monitors_changed_handler_id)
358- priv->screen_monitors_changed_handler_id = 0;
359
360 if(priv->screen)
361 greeter_background_disconnect(background);
362@@ -433,6 +507,8 @@
363 priv->monitors = g_new0(Monitor, priv->monitors_size);
364 priv->monitors_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
365
366+ g_debug("[Background] Monitors found: %" G_GSIZE_FORMAT, priv->monitors_size);
367+
368 /* Used to track situation when all monitors marked as "#skip" */
369 Monitor* first_not_skipped_monitor = NULL;
370
371@@ -449,25 +525,28 @@
372
373 const gchar* printable_name = monitor->name ? monitor->name : "<unknown>";
374
375- if(!greeter_background_find_monitor_data(background, priv->configs, monitor, (gpointer*)&config))
376- {
377- g_debug("No configuration options for monitor %s #%d, using default", printable_name, i);
378- config = priv->default_config;
379- }
380-
381 gdk_screen_get_monitor_geometry(screen, i, &monitor->geometry);
382
383- g_debug("Monitor: %s #%d (%dx%d at %dx%d)%s", printable_name, i,
384+ g_debug("[Background] Monitor: %s #%d (%dx%d at %dx%d)%s", printable_name, i,
385 monitor->geometry.width, monitor->geometry.height,
386 monitor->geometry.x, monitor->geometry.y,
387 (i == gdk_screen_get_primary_monitor(screen)) ? " primary" : "");
388
389+ if(!greeter_background_find_monitor_data(background, priv->configs, monitor, (gpointer*)&config))
390+ {
391+ g_debug("[Background] No configuration options for monitor %s #%d, using default", printable_name, i);
392+ config = priv->default_config;
393+ }
394+
395 /* Force last skipped monitor to be active monitor, if there is no other choice */
396 if(config->bg.type == BACKGROUND_TYPE_SKIP)
397 {
398 if(i < priv->monitors_size - 1 || first_not_skipped_monitor)
399+ {
400+ g_debug("[Background] Skipping monitor %s #%d", printable_name, i);
401 continue;
402- g_debug("Monitor %s #%d can not be skipped, using default configuration for it", printable_name, i);
403+ }
404+ g_debug("[Background] Monitor %s #%d can not be skipped, using default configuration for it", printable_name, i);
405 if(priv->default_config->bg.type != BACKGROUND_TYPE_SKIP)
406 config = priv->default_config;
407 else
408@@ -489,6 +568,12 @@
409 monitor->window_draw_handler_id = g_signal_connect(G_OBJECT(monitor->window), "draw",
410 G_CALLBACK(monitor_window_draw_cb),
411 monitor);
412+
413+ gchar* window_name = monitor->name ? g_strdup_printf("monitor-%s", monitor->name) : g_strdup_printf("monitor-%d", i);
414+ gtk_widget_set_name(GTK_WIDGET(monitor->window), window_name);
415+ gtk_style_context_add_class(gtk_widget_get_style_context(GTK_WIDGET(monitor->window)), "lightdm-gtk-greeter");
416+ g_free(window_name);
417+
418 GSList* item;
419 for(item = priv->accel_groups; item != NULL; item = g_slist_next(item))
420 gtk_window_add_accel_group(monitor->window, item->data);
421@@ -503,9 +588,13 @@
422 if(config->laptop)
423 priv->laptop_monitors = g_slist_prepend(priv->laptop_monitors, monitor);
424
425- if(!background_initialize(&monitor->background_configured, &config->bg, monitor, images_cache))
426- background_initialize(&monitor->background_configured, &DEFAULT_MONITOR_CONFIG.bg, monitor, images_cache);
427- monitor_set_background(monitor, &monitor->background_configured);
428+ monitor->background_configured = background_new(&config->bg, monitor, images_cache);
429+ if(!monitor->background_configured)
430+ monitor->background_configured = background_new(&DEFAULT_MONITOR_CONFIG.bg, monitor, images_cache);
431+ monitor_set_background(monitor, monitor->background_configured);
432+
433+ if(config->transition.duration && config->transition.func)
434+ monitor->transition.config = config->transition;
435
436 if(monitor->name)
437 g_hash_table_insert(priv->monitors_map, g_strdup(monitor->name), monitor);
438@@ -528,18 +617,19 @@
439 if(greeter_background_monitor_enabled(background, monitor) &&
440 x >= monitor->geometry.x && x < monitor->geometry.x + monitor->geometry.width &&
441 y >= monitor->geometry.y && y < monitor->geometry.y + monitor->geometry.height)
442+ {
443+ g_debug("[Background] Pointer position will be used to set active monitor: %dx%d", x, y);
444 greeter_background_set_active_monitor(background, monitor);
445+ break;
446+ }
447 }
448 }
449 if(!priv->active_monitor)
450 greeter_background_set_active_monitor(background, NULL);
451
452- if(screen_monitors_changed_handler_id)
453- priv->screen_monitors_changed_handler_id = screen_monitors_changed_handler_id;
454- else
455- priv->screen_monitors_changed_handler_id = g_signal_connect(G_OBJECT(screen), "monitors-changed",
456- G_CALLBACK(greeter_background_monitors_changed_cb),
457- background);
458+ priv->screen_monitors_changed_handler_id = g_signal_connect(G_OBJECT(screen), "monitors-changed",
459+ G_CALLBACK(greeter_background_monitors_changed_cb),
460+ background);
461 }
462
463 void
464@@ -548,12 +638,11 @@
465 g_return_if_fail(GREETER_IS_BACKGROUND(background));
466 GreeterBackgroundPrivate* priv = background->priv;
467
468- priv->screen = NULL;
469- priv->active_monitor = NULL;
470-
471 if(priv->screen_monitors_changed_handler_id)
472 g_signal_handler_disconnect(priv->screen, priv->screen_monitors_changed_handler_id);
473 priv->screen_monitors_changed_handler_id = 0;
474+ priv->screen = NULL;
475+ priv->active_monitor = NULL;
476
477 gint i;
478 for(i = 0; i < priv->monitors_size; ++i)
479@@ -610,6 +699,8 @@
480 const Monitor* monitor = g_hash_table_lookup(priv->monitors_map, iter->data);
481 if(monitor && monitor->background && greeter_background_monitor_enabled(background, monitor))
482 active = monitor;
483+ if(active)
484+ g_debug("[Background] Active monitor is not specified, using first enabled monitor from 'active-monitor' list");
485 }
486
487 /* All monitors listed in active-monitor-config are disabled (or option is empty) */
488@@ -617,9 +708,13 @@
489 /* Using primary monitor */
490 if(!active)
491 {
492- active = &priv->monitors[gdk_screen_get_primary_monitor(priv->screen)];
493+ gint num = gdk_screen_get_primary_monitor(priv->screen);
494+ g_return_if_fail(num < priv->monitors_size);
495+ active = &priv->monitors[num];
496 if(!active->background || !greeter_background_monitor_enabled(background, active))
497 active = NULL;
498+ if(active)
499+ g_debug("[Background] Active monitor is not specified, using primary monitor");
500 }
501
502 /* Fallback: first enabled and/or not skipped monitor (screen always have one) */
503@@ -639,7 +734,25 @@
504 }
505 if(!active)
506 active = first_not_skipped;
507- }
508+ if(active)
509+ g_debug("[Background] Active monitor is not specified, using first enabled monitor");
510+ }
511+
512+ if(!active && priv->laptop_monitors)
513+ {
514+ active = priv->laptop_monitors->data;
515+ g_debug("[Background] Active monitor is not specified, using laptop monitor");
516+ }
517+ }
518+
519+ if(!active)
520+ {
521+ if(priv->active_monitor)
522+ g_warning("[Background] Active monitor is not specified, failed to identify. Active monitor stays the same: %s #%d",
523+ priv->active_monitor->name, priv->active_monitor->number);
524+ else
525+ g_warning("[Background] Active monitor is not specified, failed to identify. Active monitor stays the same: <not defined>");
526+ return;
527 }
528
529 if(active == priv->active_monitor)
530@@ -647,12 +760,25 @@
531
532 priv->active_monitor = active;
533
534- GtkWidget* old_parent = gtk_widget_get_parent(priv->child);
535- if(old_parent)
536- gtk_container_remove(GTK_CONTAINER(old_parent), priv->child);
537- gtk_container_add(GTK_CONTAINER(active->window), priv->child);
538-
539- g_debug("Active monitor changed to: %s #%d", active->name, active->number);
540+ g_return_if_fail(priv->active_monitor != NULL);
541+
542+ if(priv->child)
543+ {
544+ GtkWidget* old_parent = gtk_widget_get_parent(priv->child);
545+ gpointer focus = greeter_save_focus(priv->child);
546+
547+ if(old_parent)
548+ gtk_container_remove(GTK_CONTAINER(old_parent), priv->child);
549+ gtk_container_add(GTK_CONTAINER(active->window), priv->child);
550+
551+ gtk_window_present(active->window);
552+ greeter_restore_focus(focus);
553+ g_free(focus);
554+ }
555+ else
556+ g_warning("[Background] Child widget is destroyed or not defined");
557+
558+ g_debug("[Background] Active monitor changed to: %s #%d", active->name, active->number);
559 g_signal_emit(background, background_signals[BACKGROUND_SIGNAL_ACTIVE_MONITOR_CHANGED], 0);
560
561 gint x, y;
562@@ -691,7 +817,7 @@
563 static void
564 greeter_background_try_init_dbus(GreeterBackground* background)
565 {
566- g_debug("Creating DBus proxy");
567+ g_debug("[Background] Creating DBus proxy");
568 GError* error = NULL;
569 GreeterBackgroundPrivate* priv = background->priv;
570
571@@ -710,7 +836,7 @@
572 if(!priv->laptop_upower_proxy)
573 {
574 if(error)
575- g_warning("Failed to create dbus proxy: %s", error->message);
576+ g_warning("[Background] Failed to create dbus proxy: %s", error->message);
577 g_clear_error(&error);
578 return;
579 }
580@@ -719,7 +845,7 @@
581 gboolean lid_present = g_variant_get_boolean(variant);
582 g_variant_unref(variant);
583
584- g_debug("UPower.%s property value: %d", DBUS_UPOWER_PROP_LID_IS_PRESENT, lid_present);
585+ g_debug("[Background] UPower.%s property value: %d", DBUS_UPOWER_PROP_LID_IS_PRESENT, lid_present);
586
587 if(!lid_present)
588 greeter_background_stop_dbus(background);
589@@ -769,13 +895,21 @@
590 if(new_state == priv->laptop_lid_closed)
591 return;
592
593- g_debug("UPower: lid state changed to '%s'", priv->laptop_lid_closed ? "closed" : "opened");
594-
595 priv->laptop_lid_closed = new_state;
596+ g_debug("[Background] UPower: lid state changed to '%s'", priv->laptop_lid_closed ? "closed" : "opened");
597+
598 if(priv->laptop_monitors)
599 {
600- if(!priv->follow_cursor || (new_state && priv->laptop_monitors->data == priv->active_monitor))
601- greeter_background_set_active_monitor(background, NULL);
602+ if(priv->laptop_lid_closed)
603+ {
604+ if(g_slist_find(priv->laptop_monitors, priv->active_monitor))
605+ greeter_background_set_active_monitor(background, NULL);
606+ }
607+ else
608+ {
609+ if(!priv->follow_cursor)
610+ greeter_background_set_active_monitor(background, NULL);
611+ }
612 }
613 }
614
615@@ -787,6 +921,13 @@
616 greeter_background_connect(background, screen);
617 }
618
619+static void
620+greeter_background_child_destroyed_cb(GtkWidget* child,
621+ GreeterBackground* background)
622+{
623+ background->priv->child = NULL;
624+}
625+
626 void
627 greeter_background_set_custom_background(GreeterBackground* background,
628 const gchar* value)
629@@ -809,13 +950,19 @@
630 {
631 Monitor *monitor = iter->data;
632
633- background_finalize(&monitor->background_custom);
634- if(config.type != BACKGROUND_TYPE_INVALID &&
635- background_initialize(&monitor->background_custom, &config, monitor, images_cache))
636- monitor_set_background(monitor, &monitor->background_custom);
637+ /* Old background_custom (if used) will be unrefed in monitor_set_background() */
638+ Background* bg = NULL;
639+ if(config.type != BACKGROUND_TYPE_INVALID)
640+ bg = background_new(&config, monitor, images_cache);
641+ if(bg)
642+ {
643+ monitor_set_background(monitor, bg);
644+ background_unref(&bg);
645+ }
646 else
647- monitor_set_background(monitor, &monitor->background_configured);
648+ monitor_set_background(monitor, monitor->background_configured);
649 }
650+
651 if(images_cache)
652 g_hash_table_unref(images_cache);
653 if(config.type != BACKGROUND_TYPE_INVALID)
654@@ -831,18 +978,43 @@
655 cairo_surface_t* surface = create_root_surface(priv->screen);
656 cairo_t* cr = cairo_create(surface);
657 gsize i;
658-
659- for(i = 0; i <= priv->monitors_size; ++i)
660+ gdouble child_opacity;
661+
662+ const GdkRGBA ROOT_COLOR = {1.0, 1.0, 1.0, 1.0};
663+ gdk_cairo_set_source_rgba(cr, &ROOT_COLOR);
664+ cairo_paint(cr);
665+
666+ for(i = 0; i < priv->monitors_size; ++i)
667 {
668 const Monitor* monitor = &priv->monitors[i];
669- if(monitor == priv->active_monitor || !monitor->background)
670+ if(!monitor->background)
671 continue;
672- if(i == priv->monitors_size)
673- monitor = priv->active_monitor;
674+
675+ #ifdef XROOT_DRAW_BACKGROUND_DIRECTLY
676+ /* Old method: can't draw default GtkWindow background */
677 cairo_save(cr);
678 cairo_translate(cr, monitor->geometry.x, monitor->geometry.y);
679- monitor_draw_background(monitor, cr);
680+ monitor_draw_background(monitor, monitor->background, cr);
681 cairo_restore(cr);
682+ #else
683+ /* New - can draw anything, but looks tricky a bit */
684+ child_opacity = gtk_widget_get_opacity(priv->child);
685+ if(monitor == priv->active_monitor)
686+ {
687+ gtk_widget_set_opacity(priv->child, 0.0);
688+ gdk_window_process_updates(gtk_widget_get_window(GTK_WIDGET(priv->child)), FALSE);
689+ }
690+
691+ gdk_cairo_set_source_window(cr, gtk_widget_get_window(GTK_WIDGET(monitor->window)),
692+ monitor->geometry.x, monitor->geometry.y);
693+ cairo_paint(cr);
694+
695+ if(monitor == priv->active_monitor)
696+ {
697+ gtk_widget_set_opacity(priv->child, child_opacity);
698+ gdk_window_process_updates(gtk_widget_get_window(GTK_WIDGET(priv->child)), FALSE);
699+ }
700+ #endif
701 }
702 set_surface_as_root(priv->screen, surface);
703
704@@ -887,6 +1059,8 @@
705 return FALSE;
706 if(g_strcmp0(value, BACKGROUND_TYPE_SKIP_VALUE) == 0)
707 config->type = BACKGROUND_TYPE_SKIP;
708+ else if(g_strcmp0(value, BACKGROUND_TYPE_DEFAULT_VALUE) == 0)
709+ config->type = BACKGROUND_TYPE_DEFAULT;
710 else if(gdk_rgba_parse(&config->options.color, value))
711 config->type = BACKGROUND_TYPE_COLOR;
712 else
713@@ -904,7 +1078,7 @@
714 config->options.image.mode = SCALING_MODE_ZOOMED;
715
716 config->options.image.path = g_strdup(value);
717- config->type = BACKGROUND_TYPE_IMAGE;
718+ config->type = BACKGROUND_TYPE_IMAGE;
719 }
720 return TRUE;
721 }
722@@ -912,8 +1086,19 @@
723 static void
724 background_config_finalize(BackgroundConfig* config)
725 {
726- if(config->type == BACKGROUND_TYPE_IMAGE)
727- g_free(config->options.image.path);
728+ switch(config->type)
729+ {
730+ case BACKGROUND_TYPE_IMAGE:
731+ g_free(config->options.image.path);
732+ break;
733+ case BACKGROUND_TYPE_COLOR:
734+ case BACKGROUND_TYPE_DEFAULT:
735+ case BACKGROUND_TYPE_SKIP:
736+ break;
737+ case BACKGROUND_TYPE_INVALID:
738+ g_return_if_reached();
739+ }
740+
741 config->type = BACKGROUND_TYPE_INVALID;
742 }
743
744@@ -922,8 +1107,19 @@
745 BackgroundConfig* dest)
746 {
747 *dest = *source;
748- if(source->type == BACKGROUND_TYPE_IMAGE)
749- dest->options.image.path = g_strdup(source->options.image.path);
750+
751+ switch(dest->type)
752+ {
753+ case BACKGROUND_TYPE_IMAGE:
754+ dest->options.image.path = g_strdup(source->options.image.path);
755+ break;
756+ case BACKGROUND_TYPE_COLOR:
757+ case BACKGROUND_TYPE_DEFAULT:
758+ case BACKGROUND_TYPE_SKIP:
759+ break;
760+ case BACKGROUND_TYPE_INVALID:
761+ g_return_if_reached();
762+ }
763 }
764
765 static void
766@@ -941,84 +1137,238 @@
767 background_config_copy(&source->bg, &dest->bg);
768 dest->user_bg = source->user_bg;
769 dest->laptop = source->laptop;
770+ dest->transition = source->transition;
771 return dest;
772 }
773
774-static gboolean
775-background_initialize(Background* bg,
776- const BackgroundConfig* config,
777- const Monitor* monitor,
778- GHashTable* images_cache)
779-{
780- if(config->type == BACKGROUND_TYPE_IMAGE)
781- {
782- GdkPixbuf* pixbuf = scale_image_file(config->options.image.path,
783- config->options.image.mode,
784- monitor->geometry.width, monitor->geometry.height,
785- images_cache);
786- if(!pixbuf)
787- {
788- g_warning("Failed to read wallpaper: %s", config->options.image.path);
789- return FALSE;
790- }
791- bg->options.image = pixbuf;
792- }
793- else if(config->type == BACKGROUND_TYPE_COLOR)
794- bg->options.color = config->options.color;
795- else
796- return FALSE;
797- bg->type = config->type;
798- return TRUE;
799+static Background*
800+background_new(const BackgroundConfig* config,
801+ const Monitor* monitor,
802+ GHashTable* images_cache)
803+{
804+ Background bg = {0};
805+
806+ switch(config->type)
807+ {
808+ case BACKGROUND_TYPE_IMAGE:
809+ bg.options.image = scale_image_file(config->options.image.path, config->options.image.mode,
810+ monitor->geometry.width, monitor->geometry.height,
811+ images_cache);
812+ if(!bg.options.image)
813+ {
814+ g_warning("[Background] Failed to read wallpaper: %s", config->options.image.path);
815+ return NULL;
816+ }
817+ break;
818+ case BACKGROUND_TYPE_COLOR:
819+ bg.options.color = config->options.color;
820+ break;
821+ case BACKGROUND_TYPE_DEFAULT:
822+ break;
823+ case BACKGROUND_TYPE_SKIP:
824+ case BACKGROUND_TYPE_INVALID:
825+ g_return_val_if_reached(NULL);
826+ }
827+
828+ bg.type = config->type;
829+ bg.ref_count = 1;
830+
831+ Background* result = g_new(Background, 1);
832+ *result = bg;
833+ return result;
834+}
835+
836+static Background*
837+background_ref(Background* bg)
838+{
839+ bg->ref_count++;
840+ return bg;
841+}
842+
843+static void
844+background_unref(Background** bg)
845+{
846+ if(!*bg)
847+ return;
848+ (*bg)->ref_count--;
849+ if((*bg)->ref_count == 0)
850+ {
851+ background_finalize(*bg);
852+ *bg = NULL;
853+ }
854 }
855
856 static void
857 background_finalize(Background* bg)
858 {
859- if(bg->type == BACKGROUND_TYPE_IMAGE)
860- g_clear_object(&bg->options.image);
861+ switch(bg->type)
862+ {
863+ case BACKGROUND_TYPE_IMAGE:
864+ g_clear_object(&bg->options.image);
865+ break;
866+ case BACKGROUND_TYPE_COLOR:
867+ case BACKGROUND_TYPE_DEFAULT:
868+ break;
869+ case BACKGROUND_TYPE_SKIP:
870+ case BACKGROUND_TYPE_INVALID:
871+ g_return_if_reached();
872+ }
873+
874 bg->type = BACKGROUND_TYPE_INVALID;
875 }
876
877 static void
878 monitor_set_background(Monitor* monitor,
879- const Background* background)
880-{
881- monitor->background = background;
882- gtk_widget_queue_draw(GTK_WIDGET(monitor->window));
883+ Background* background)
884+{
885+ if(monitor->background == background)
886+ return;
887+ monitor_stop_transition(monitor);
888+
889+ switch(background->type)
890+ {
891+ case BACKGROUND_TYPE_IMAGE:
892+ case BACKGROUND_TYPE_COLOR:
893+ gtk_widget_set_app_paintable(GTK_WIDGET(monitor->window), TRUE);
894+ if(monitor->transition.config.duration > 0 && monitor->background &&
895+ monitor->background->type != BACKGROUND_TYPE_DEFAULT)
896+ monitor_start_transition(monitor, monitor->background, background);
897+ break;
898+ case BACKGROUND_TYPE_DEFAULT:
899+ gtk_widget_set_app_paintable(GTK_WIDGET(monitor->window), FALSE);
900+ break;
901+ case BACKGROUND_TYPE_SKIP:
902+ case BACKGROUND_TYPE_INVALID:
903+ g_return_val_if_reached(NULL);
904+ }
905+
906+ background_unref(&monitor->background);
907+ monitor->background = background_ref(background);
908+ gtk_widget_queue_draw(GTK_WIDGET(monitor->window));
909+}
910+
911+static void
912+monitor_start_transition(Monitor* monitor,
913+ Background* from,
914+ Background* to)
915+{
916+ monitor_stop_transition(monitor);
917+
918+ monitor->transition.from = background_ref(from);
919+ monitor->transition.to = background_ref(to);
920+
921+ monitor->transition.started = g_get_monotonic_time();
922+ monitor->transition.timer_id = gtk_widget_add_tick_callback(GTK_WIDGET(monitor->window),
923+ (GtkTickCallback)monitor_transition_cb,
924+ monitor,
925+ NULL);
926+ monitor->transition.stage = 0;
927+}
928+
929+static void
930+monitor_stop_transition(Monitor* monitor)
931+{
932+ if(!monitor->transition.timer_id)
933+ return;
934+ gtk_widget_remove_tick_callback(GTK_WIDGET(monitor->window), monitor->transition.timer_id);
935+ monitor->transition.timer_id = 0;
936+ monitor->transition.started = 0;
937+ monitor->transition.stage = 0;
938+ background_unref(&monitor->transition.to);
939+ background_unref(&monitor->transition.from);
940+}
941+
942+static gboolean
943+monitor_transition_cb(GtkWidget *widget,
944+ GdkFrameClock* frame_clock,
945+ Monitor* monitor)
946+{
947+ if(!monitor->transition.timer_id)
948+ return G_SOURCE_REMOVE;
949+
950+ gint64 span = g_get_monotonic_time() - monitor->transition.started;
951+ gdouble x = CLAMP(span/monitor->transition.config.duration/1000.0, 0.0, 1.0);
952+ monitor->transition.stage = monitor->transition.config.func(x);
953+
954+ if(x >= 1.0)
955+ monitor_stop_transition(monitor);
956+
957+ gtk_widget_queue_draw(GTK_WIDGET(monitor->window));
958+ return x >= 1.0 ? G_SOURCE_REMOVE : G_SOURCE_CONTINUE;
959+}
960+
961+static void
962+monitor_transition_draw_alpha(const Monitor* monitor,
963+ cairo_t* cr)
964+{
965+ monitor_draw_background(monitor, monitor->transition.from, cr);
966+
967+ cairo_push_group(cr);
968+ monitor_draw_background(monitor, monitor->transition.to, cr);
969+ cairo_pop_group_to_source(cr);
970+
971+ cairo_pattern_t* alpha_pattern = cairo_pattern_create_rgba(0.0, 0.0, 0.0, monitor->transition.stage);
972+ cairo_mask(cr, alpha_pattern);
973+ cairo_pattern_destroy(alpha_pattern);
974 }
975
976 static void
977 monitor_finalize(Monitor* monitor)
978 {
979- background_finalize(&monitor->background_configured);
980- background_finalize(&monitor->background_custom);
981- g_free(monitor->name);
982+ if(monitor->transition.config.duration)
983+ {
984+ monitor_stop_transition(monitor);
985+ if(monitor->transition.timer_id)
986+ g_source_remove(monitor->transition.timer_id);
987+ monitor->transition.config.duration = 0;
988+ }
989+
990 if(monitor->window_draw_handler_id)
991 g_signal_handler_disconnect(monitor->window, monitor->window_draw_handler_id);
992+
993+ background_unref(&monitor->background_configured);
994+ background_unref(&monitor->background);
995+
996 if(monitor->window)
997+ {
998+ GtkWidget* child = gtk_bin_get_child(GTK_BIN(monitor->window));
999+ if(child) /* remove greeter widget to avoid "destroy" signal */
1000+ gtk_container_remove(GTK_CONTAINER(monitor->window), child);
1001 gtk_widget_destroy(GTK_WIDGET(monitor->window));
1002- monitor->name = NULL;
1003- monitor->window = NULL;
1004- monitor->window_draw_handler_id = 0;
1005+ }
1006+
1007+ g_free(monitor->name);
1008+
1009+ *monitor = INVALID_MONITOR_STRUCT;
1010 }
1011
1012 static void
1013 monitor_draw_background(const Monitor* monitor,
1014+ const Background* background,
1015 cairo_t* cr)
1016 {
1017 g_return_if_fail(monitor != NULL);
1018- g_return_if_fail(monitor->background != NULL);
1019+ g_return_if_fail(background != NULL);
1020
1021- if(monitor->background->type == BACKGROUND_TYPE_IMAGE && monitor->background->options.image)
1022- {
1023- gdk_cairo_set_source_pixbuf(cr, monitor->background->options.image, 0, 0);
1024- cairo_paint(cr);
1025- }
1026- else if(monitor->background->type == BACKGROUND_TYPE_COLOR)
1027- {
1028- cairo_rectangle(cr, 0, 0, monitor->geometry.width, monitor->geometry.height);
1029- gdk_cairo_set_source_rgba(cr, &monitor->background->options.color);
1030- cairo_fill(cr);
1031+ switch(background->type)
1032+ {
1033+ case BACKGROUND_TYPE_IMAGE:
1034+ if(background->options.image)
1035+ {
1036+ gdk_cairo_set_source_pixbuf(cr, background->options.image, 0, 0);
1037+ cairo_paint(cr);
1038+ }
1039+ break;
1040+ case BACKGROUND_TYPE_COLOR:
1041+ cairo_rectangle(cr, 0, 0, monitor->geometry.width, monitor->geometry.height);
1042+ gdk_cairo_set_source_rgba(cr, &background->options.color);
1043+ cairo_fill(cr);
1044+ break;
1045+ case BACKGROUND_TYPE_DEFAULT:
1046+ break;
1047+ case BACKGROUND_TYPE_SKIP:
1048+ case BACKGROUND_TYPE_INVALID:
1049+ g_return_if_reached();
1050 }
1051 }
1052
1053@@ -1027,8 +1377,14 @@
1054 cairo_t* cr,
1055 const Monitor* monitor)
1056 {
1057- if(monitor->background)
1058- monitor_draw_background(monitor, cr);
1059+ if(!monitor->background)
1060+ return FALSE;
1061+
1062+ if(monitor->transition.started)
1063+ monitor->transition.config.draw(monitor, cr);
1064+ else
1065+ monitor_draw_background(monitor, monitor->background, cr);
1066+
1067 return FALSE;
1068 }
1069
1070@@ -1051,35 +1407,43 @@
1071 {
1072 gchar* key = NULL;
1073 GdkPixbuf* pixbuf = NULL;
1074+
1075 if(cache)
1076 {
1077 key = g_strdup_printf("%s\n%d %dx%d", path, mode, width, height);
1078- if (g_hash_table_lookup_extended(cache, key, NULL, (gpointer*)&pixbuf))
1079+ if(g_hash_table_lookup_extended(cache, key, NULL, (gpointer*)&pixbuf))
1080+ {
1081+ g_free(key);
1082 return GDK_PIXBUF(g_object_ref(pixbuf));
1083+ }
1084 }
1085
1086- if (!cache || !g_hash_table_lookup_extended(cache, path, NULL, (gpointer*)&pixbuf))
1087+ if(!cache || !g_hash_table_lookup_extended(cache, path, NULL, (gpointer*)&pixbuf))
1088 {
1089 GError *error = NULL;
1090 pixbuf = gdk_pixbuf_new_from_file(path, &error);
1091 if(error)
1092 {
1093- g_warning("Failed to load background: %s", error->message);
1094+ g_warning("[Background] Failed to load background: %s", error->message);
1095 g_clear_error(&error);
1096 }
1097 else if(cache)
1098- g_hash_table_insert(cache, g_strdup(path), g_object_ref (pixbuf));
1099+ g_hash_table_insert(cache, g_strdup(path), g_object_ref(pixbuf));
1100 }
1101+ else
1102+ pixbuf = g_object_ref(pixbuf);
1103
1104 if(pixbuf)
1105 {
1106 GdkPixbuf* scaled = scale_image(pixbuf, mode, width, height);
1107- if (cache)
1108+ if(cache)
1109 g_hash_table_insert(cache, g_strdup(key), g_object_ref(scaled));
1110 g_object_unref(pixbuf);
1111 pixbuf = scaled;
1112 }
1113
1114+ g_free(key);
1115+
1116 return pixbuf;
1117 }
1118
1119@@ -1142,7 +1506,7 @@
1120 display = XOpenDisplay (gdk_display_get_name (gdk_screen_get_display (screen)));
1121 if (!display)
1122 {
1123- g_warning ("Failed to create root pixmap");
1124+ g_warning("[Background] Failed to create root pixmap");
1125 return NULL;
1126 }
1127
1128@@ -1165,7 +1529,7 @@
1129 Display* display,
1130 Pixmap xpixmap)
1131 {
1132-
1133+
1134 Window xroot = RootWindow (display, gdk_screen_get_number (screen));
1135 char *atom_names[] = {"_XROOTPMAP_ID", "ESETROOT_PMAP_ID"};
1136 Atom atoms[G_N_ELEMENTS(atom_names)] = {0};
1137@@ -1214,7 +1578,7 @@
1138 */
1139 if (!XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), False, atoms) ||
1140 atoms[0] == None || atoms[1] == None) {
1141- g_warning("Could not create atoms needed to set root pixmap id/properties.\n");
1142+ g_warning("[Background] Could not create atoms needed to set root pixmap id/properties.\n");
1143 return;
1144 }
1145
1146@@ -1261,3 +1625,15 @@
1147 XFlush (display);
1148 XUngrabServer (display);
1149 }
1150+
1151+static gdouble
1152+transition_func_linear(gdouble x)
1153+{
1154+ return x;
1155+}
1156+
1157+static gdouble
1158+transition_func_easy_in_out(gdouble x)
1159+{
1160+ return (1 - cos(M_PI*x))/2;
1161+}
1162
1163=== modified file 'src/greeterbackground.h'
1164--- src/greeterbackground.h 2014-08-31 17:45:52 +0000
1165+++ src/greeterbackground.h 2014-12-10 07:59:47 +0000
1166@@ -12,6 +12,8 @@
1167 #define GREETER_IS_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GREETER_BACKGROUND_TYPE))
1168 #define GREETER_IS_BACKGROUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GREETER_BACKGROUND_TYPE))
1169
1170+#define GREETER_BACKGROUND_DEFAULT "*"
1171+
1172 typedef struct _GreeterBackground GreeterBackground;
1173 typedef struct _GreeterBackgroundClass GreeterBackgroundClass;
1174
1175@@ -20,15 +22,13 @@
1176 GreeterBackground* greeter_background_new (GtkWidget* child);
1177 void greeter_background_set_active_monitor_config (GreeterBackground* background,
1178 const gchar* value);
1179-void greeter_background_set_default_config (GreeterBackground* background,
1180- const gchar* bg,
1181- gboolean user_bg,
1182- gboolean laptop);
1183 void greeter_background_set_monitor_config (GreeterBackground* background,
1184 const gchar* name,
1185 const gchar* bg,
1186 gboolean user_bg, gboolean user_bg_used,
1187- gboolean laptop, gboolean laptop_used);
1188+ gboolean laptop, gboolean laptop_used,
1189+ gint transition_duration,
1190+ const gchar* transition_func);
1191 void greeter_background_remove_monitor_config (GreeterBackground* background,
1192 const gchar* name);
1193 gchar** greeter_background_get_configured_monitors (GreeterBackground* background);
1194
1195=== modified file 'src/lightdm-gtk-greeter.c'
1196--- src/lightdm-gtk-greeter.c 2014-09-01 07:58:56 +0000
1197+++ src/lightdm-gtk-greeter.c 2014-12-10 07:59:47 +0000
1198@@ -127,9 +127,6 @@
1199 static const WindowPosition KEYBOARD_POSITION = {.x = { 50, +1, TRUE, 0}, .y = { 0, -1, FALSE, +1}, .use_size = TRUE,
1200 .width = {50, 0, TRUE, 0}, .height = {25, 0, TRUE, 0}};
1201
1202-/* Configuration */
1203-static gboolean key_file_get_boolean_extended (GKeyFile *key_file, const gchar *group_name, const gchar *key, gboolean default_value);
1204-
1205 /* Clock */
1206 static gchar *clock_format;
1207 static gboolean clock_timeout_thread (void);
1208@@ -183,6 +180,7 @@
1209 static int timeout, interval, prefer_blanking, allow_exposures;
1210
1211 /* Handling monitors backgrounds */
1212+static const gint USER_BACKGROUND_DELAY = 250;
1213 static GreeterBackground *greeter_background;
1214
1215 /* Authentication state */
1216@@ -285,6 +283,42 @@
1217 void restart_cb (GtkWidget *widget, LightDMGreeter *greeter);
1218 void shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter);
1219
1220+gpointer greeter_save_focus(GtkWidget* widget);
1221+void greeter_restore_focus(const gpointer saved_data);
1222+
1223+struct SavedFocusData
1224+{
1225+ GtkWidget *widget;
1226+ gint editable_pos;
1227+};
1228+
1229+gpointer
1230+greeter_save_focus(GtkWidget* widget)
1231+{
1232+ GtkWidget *window = gtk_widget_get_toplevel(widget);
1233+ if (!GTK_IS_WINDOW (window))
1234+ return NULL;
1235+
1236+ struct SavedFocusData *data = g_new0 (struct SavedFocusData, 1);
1237+ data->widget = gtk_window_get_focus (GTK_WINDOW (window));
1238+ data->editable_pos = GTK_IS_EDITABLE(data->widget) ? gtk_editable_get_position (GTK_EDITABLE (data->widget)) : -1;
1239+
1240+ return data;
1241+}
1242+
1243+void
1244+greeter_restore_focus(const gpointer saved_data)
1245+{
1246+ if (!saved_data)
1247+ return;
1248+
1249+ struct SavedFocusData *data = saved_data;
1250+ if (GTK_IS_WIDGET (data->widget))
1251+ gtk_widget_grab_focus (data->widget);
1252+ if (GTK_IS_EDITABLE(data->widget) && data->editable_pos > -1)
1253+ gtk_editable_set_position(GTK_EDITABLE(data->widget), data->editable_pos);
1254+}
1255+
1256 /* State file */
1257
1258 static void
1259@@ -536,21 +570,6 @@
1260 return TRUE;
1261 }
1262
1263-/* Configuration */
1264-
1265-static gboolean
1266-key_file_get_boolean_extended (GKeyFile *key_file, const gchar *group_name, const gchar *key, gboolean default_value)
1267-{
1268- GError* error = NULL;
1269- gboolean result = g_key_file_get_boolean (key_file, group_name, key, &error);
1270- if (error)
1271- {
1272- g_clear_error (&error);
1273- return default_value;
1274- }
1275- return result;
1276-}
1277-
1278 /* Clock */
1279
1280 static gboolean
1281@@ -1771,24 +1790,47 @@
1282 gtk_button_set_label (login_button, _("Unlock"));
1283 else
1284 gtk_button_set_label (login_button, _("Log In"));
1285- gtk_widget_set_can_default (GTK_WIDGET (login_button), TRUE);
1286- gtk_widget_grab_default (GTK_WIDGET (login_button));
1287 /* and disable the session and language widgets */
1288 gtk_widget_set_sensitive (GTK_WIDGET (session_menuitem), !logged_in);
1289 gtk_widget_set_sensitive (GTK_WIDGET (language_menuitem), !logged_in);
1290 }
1291
1292+static guint set_user_background_delayed_id = 0;
1293+
1294+static gboolean
1295+set_user_background_delayed_cb (const gchar *value)
1296+{
1297+ greeter_background_set_custom_background (greeter_background, value);
1298+ set_user_background_delayed_id = 0;
1299+ return G_SOURCE_REMOVE;
1300+}
1301+
1302 static void
1303-set_user_background (const gchar *username)
1304+set_user_background (const gchar *user_name)
1305 {
1306- const gchar *path = NULL;
1307- if (username)
1308+ const gchar *value = NULL;
1309+ if (user_name)
1310 {
1311- LightDMUser *user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
1312+ LightDMUser *user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), user_name);
1313 if (user)
1314- path = lightdm_user_get_background (user);
1315- }
1316- greeter_background_set_custom_background (greeter_background, path);
1317+ value = lightdm_user_get_background (user);
1318+ }
1319+
1320+ if (set_user_background_delayed_id)
1321+ {
1322+ g_source_remove (set_user_background_delayed_id);
1323+ set_user_background_delayed_id = 0;
1324+ }
1325+
1326+ if (!value)
1327+ greeter_background_set_custom_background (greeter_background, NULL);
1328+ else
1329+ {
1330+ /* Small delay before changing background */
1331+ set_user_background_delayed_id = g_timeout_add_full (G_PRIORITY_DEFAULT, USER_BACKGROUND_DELAY,
1332+ (GSourceFunc)set_user_background_delayed_cb,
1333+ g_strdup (value), g_free);
1334+ }
1335 }
1336
1337 static void
1338@@ -2852,36 +2894,45 @@
1339 greeter_background_set_active_monitor_config (greeter_background, value ? value : "#cursor");
1340 g_free (value);
1341
1342- value = g_key_file_get_value (config, "greeter", "background", NULL);
1343- greeter_background_set_default_config (greeter_background, value,
1344- key_file_get_boolean_extended (config, "greeter", "user-background", TRUE),
1345- key_file_get_boolean_extended (config, "greeter", "laptop", FALSE));
1346- g_free (value);
1347-
1348 const gchar *CONFIG_MONITOR_PREFIX = "monitor:";
1349 gchar **config_group;
1350 gchar **config_groups = g_key_file_get_groups (config, NULL);
1351 for (config_group = config_groups; *config_group; ++config_group)
1352 {
1353- if (!g_str_has_prefix (*config_group, CONFIG_MONITOR_PREFIX))
1354- continue;
1355- const gchar *name = *config_group + sizeof (CONFIG_MONITOR_PREFIX);
1356- while (*name && g_ascii_isspace (*name))
1357- ++name;
1358+ gchar *name_to_free = NULL;
1359+ const gchar *name = *config_group;
1360+
1361+ if (g_strcmp0 (*config_group, "greeter") != 0)
1362+ {
1363+ if (!g_str_has_prefix (name, CONFIG_MONITOR_PREFIX))
1364+ continue;
1365+ name = *config_group + sizeof (CONFIG_MONITOR_PREFIX);
1366+ while (*name && g_ascii_isspace (*name))
1367+ ++name;
1368+ }
1369+ else
1370+ name = name_to_free = g_strdup (GREETER_BACKGROUND_DEFAULT);
1371+
1372 g_debug ("Monitor configuration found: '%s'", name);
1373
1374- GError *user_bg_error = NULL, *laptop_error = NULL;
1375+ GError *user_bg_error = NULL, *laptop_error = NULL, *duration_error = NULL;
1376 gboolean user_bg = g_key_file_get_boolean (config, *config_group, "user-background", &user_bg_error);
1377 gboolean laptop = g_key_file_get_boolean (config, *config_group, "laptop", &laptop_error);
1378- value = g_key_file_get_value (config, *config_group, "background", NULL);
1379+ gchar *background = g_key_file_get_value (config, *config_group, "background", NULL);
1380+ gchar *tr_type = g_key_file_get_string (config, *config_group, "transition-type", NULL);
1381+ gint tr_duration = g_key_file_get_integer (config, *config_group, "transition-duration", &duration_error);
1382
1383- greeter_background_set_monitor_config (greeter_background, name, value,
1384+ greeter_background_set_monitor_config (greeter_background, name, background,
1385 user_bg, user_bg_error == NULL,
1386- laptop, laptop_error == NULL);
1387+ laptop, laptop_error == NULL,
1388+ duration_error == NULL ? tr_duration : -1,
1389+ tr_type);
1390
1391- g_free (value);
1392+ g_free (tr_type);
1393+ g_free (background);
1394+ g_free (name_to_free);
1395+ g_clear_error (&user_bg_error);
1396 g_clear_error (&laptop_error);
1397- g_clear_error (&user_bg_error);
1398 }
1399 g_strfreev (config_groups);
1400
1401
1402=== modified file 'src/lightdm-gtk-greeter.glade'
1403--- src/lightdm-gtk-greeter.glade 2014-09-24 17:41:33 +0000
1404+++ src/lightdm-gtk-greeter.glade 2014-12-10 07:59:47 +0000
1405@@ -282,7 +282,6 @@
1406 <property name="name">cancel_button</property>
1407 <property name="visible">True</property>
1408 <property name="can_focus">True</property>
1409- <property name="receives_default">True</property>
1410 <signal name="clicked" handler="power_button_clicked_cb" swapped="no"/>
1411 </object>
1412 <packing>
1413@@ -297,7 +296,6 @@
1414 <property name="name">power_ok_button</property>
1415 <property name="visible">True</property>
1416 <property name="can_focus">True</property>
1417- <property name="receives_default">True</property>
1418 <signal name="clicked" handler="power_button_clicked_cb" swapped="no"/>
1419 </object>
1420 <packing>
1421@@ -432,7 +430,6 @@
1422 <object class="GtkEntry" id="username_entry">
1423 <property name="name">prompt_entry</property>
1424 <property name="can_focus">True</property>
1425- <property name="no_show_all">True</property>
1426 <property name="hexpand">True</property>
1427 <property name="invisible_char">•</property>
1428 <property name="placeholder_text" translatable="yes">Enter your username</property>
1429@@ -480,7 +477,6 @@
1430 <child>
1431 <object class="GtkInfoBar" id="greeter_infobar">
1432 <property name="name">greeter_infobar</property>
1433- <property name="app_paintable">True</property>
1434 <property name="can_focus">False</property>
1435 <child internal-child="action_area">
1436 <object class="GtkButtonBox" id="infobar-action_area">
1437@@ -545,7 +541,6 @@
1438 <property name="name">cancel_button</property>
1439 <property name="visible">True</property>
1440 <property name="can_focus">True</property>
1441- <property name="receives_default">True</property>
1442 <signal name="clicked" handler="cancel_cb" swapped="no"/>
1443 </object>
1444 <packing>
1445@@ -560,7 +555,6 @@
1446 <property name="name">login_button</property>
1447 <property name="visible">True</property>
1448 <property name="can_focus">True</property>
1449- <property name="receives_default">True</property>
1450 <signal name="clicked" handler="login_cb" swapped="no"/>
1451 </object>
1452 <packing>

Subscribers

People subscribed via source and target branches