Merge lp:~kalgasnik/lightdm-gtk-greeter/background-transition into lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/trunk
- background-transition
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Simon Steinbeiß | Approve | ||
Review via email: mp+241082@code.launchpad.net |
Commit message
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-
Enabled by default, I'm not sure that it is good idea.
Andrew P. (kalgasnik) wrote : | # |
Sean Davis (bluesabre) wrote : | # |
Can you provide some examples for the configuration in this case?
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-
Sean Davis (bluesabre) wrote : | # |
When I try this on my laptop, there does not seem to be a transition...
transition-
transition-
Andrew P. (kalgasnik) wrote : | # |
Maybe you have user-background = false or identical default and user's backgrounds.
It must looks like http://
Oh, "easy" -> "ease", my inglish is not so well. But it isn't the source of the problem.
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.
Preview Diff
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> |
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.