Merge lp:~a-j-buxton/lightdm-gtk-greeter/background-fixes into lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/trunk

Proposed by Alistair Buxton
Status: Merged
Merged at revision: 151
Proposed branch: lp:~a-j-buxton/lightdm-gtk-greeter/background-fixes
Merge into: lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/trunk
Diff against target: 326 lines (+141/-37)
1 file modified
src/lightdm-gtk-greeter.c (+141/-37)
To merge this branch: bzr merge lp:~a-j-buxton/lightdm-gtk-greeter/background-fixes
Reviewer Review Type Date Requested Status
LightDM Gtk+ Greeter Development Team Pending
Review via email: mp+197237@code.launchpad.net

Commit message

This series of patches fixes various problems in the background handling code, including client connection leaks and pixmap leaks arising from misuse of RetainPermanent and the root atom conventions for setting the display background.

Description of the change

This series of patches fixes various problems in the background handling code, including client connection leaks and pixmap leaks arising from misuse of RetainPermanent and the root atom conventions for setting the display background.

Some of the fixes are taken from Gnome/MATE (which is where this code originated, but has since been improved.)

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/lightdm-gtk-greeter.c'
2--- src/lightdm-gtk-greeter.c 2013-11-29 16:15:05 +0000
3+++ src/lightdm-gtk-greeter.c 2013-11-29 16:16:51 +0000
4@@ -21,6 +21,8 @@
5 #include <gtk/gtk.h>
6 #include <glib/gi18n.h>
7 #include <cairo-xlib.h>
8+#include <X11/Xlib.h>
9+#include <X11/Xatom.h>
10 #include <gdk-pixbuf/gdk-pixbuf.h>
11 #include <gdk/gdkx.h>
12 #include <glib.h>
13@@ -438,10 +440,10 @@
14 gtk_widget_set_sensitive (GTK_WIDGET (language_menu), !logged_in);
15 }
16
17-static void set_background (GdkPixbuf *new_bg, gboolean is_locked);
18+static void set_background (GdkPixbuf *new_bg);
19
20 static void
21-set_user_background (const gchar *username, gboolean is_locked)
22+set_user_background (const gchar *username)
23 {
24 LightDMUser *user;
25 const gchar *path;
26@@ -463,7 +465,7 @@
27 }
28 }
29
30- set_background (bg, is_locked);
31+ set_background (bg);
32 if (bg)
33 g_object_unref (bg);
34 }
35@@ -873,7 +875,6 @@
36 {
37 GtkTreeModel *model;
38 GtkTreeIter iter;
39- gboolean is_locked;
40
41 model = gtk_combo_box_get_model (user_combo);
42
43@@ -895,8 +896,7 @@
44 }
45
46 set_login_button_label (greeter, user);
47- is_locked = lightdm_greeter_get_lock_hint (greeter);
48- set_user_background (user, is_locked);
49+ set_user_background (user);
50 set_user_image (user);
51 gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), user);
52 start_authentication (user);
53@@ -1329,12 +1329,10 @@
54 gchar *last_user;
55 const gchar *selected_user;
56 gboolean logged_in = FALSE;
57- gboolean is_locked = FALSE;
58
59 g_signal_connect (lightdm_user_list_get_instance (), "user-added", G_CALLBACK (user_added_cb), greeter);
60 g_signal_connect (lightdm_user_list_get_instance (), "user-changed", G_CALLBACK (user_changed_cb), greeter);
61 g_signal_connect (lightdm_user_list_get_instance (), "user-removed", G_CALLBACK (user_removed_cb), NULL);
62- is_locked = lightdm_greeter_get_lock_hint (greeter);
63 model = gtk_combo_box_get_model (user_combo);
64 items = lightdm_user_list_get_users (lightdm_user_list_get_instance ());
65 for (item = items; item; item = item->next)
66@@ -1394,7 +1392,7 @@
67 {
68 gtk_combo_box_set_active_iter (user_combo, &iter);
69 set_login_button_label (greeter, selected_user);
70- set_user_background (selected_user, is_locked);
71+ set_user_background (selected_user);
72 set_user_image (selected_user);
73 gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), selected_user);
74 start_authentication (selected_user);
75@@ -1408,7 +1406,7 @@
76 gtk_tree_model_get (model, &iter, 0, &name, -1);
77 gtk_combo_box_set_active_iter (user_combo, &iter);
78 set_login_button_label (greeter, name);
79- set_user_background (name, is_locked);
80+ set_user_background (name);
81 set_user_image (name);
82 gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), name);
83 start_authentication (name);
84@@ -1420,8 +1418,11 @@
85 g_free (last_user);
86 }
87
88+/* The following code for setting a RetainPermanent background pixmap was taken
89+ originally from Gnome, with some fixes from MATE. see:
90+ https://github.com/mate-desktop/mate-desktop/blob/master/libmate-desktop/mate-bg.c */
91 static cairo_surface_t *
92-create_root_surface (GdkScreen *screen, gboolean is_locked)
93+create_root_surface (GdkScreen *screen)
94 {
95 gint number, width, height;
96 Display *display;
97@@ -1441,10 +1442,6 @@
98 return NULL;
99 }
100
101- /* Force the screen to remain blank in case the session was just locked to reduce VT-switching flickering and to make the greeter behave a bit more like a screensaver than a mere unlock-dialog */
102- if (is_locked)
103- XForceScreenSaver(display,ScreenSaverActive);
104-
105 XSetCloseDownMode (display, RetainPermanent);
106 pixmap = XCreatePixmap (display, RootWindow (display, number), width, height, DefaultDepth (display, number));
107 XCloseDisplay (display);
108@@ -1455,17 +1452,114 @@
109 GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)),
110 width, height);
111
112- /* Use this pixmap for the background */
113- XSetWindowBackgroundPixmap (GDK_SCREEN_XDISPLAY (screen),
114- RootWindow (GDK_SCREEN_XDISPLAY (screen), number),
115- cairo_xlib_surface_get_drawable (surface));
116-
117-
118 return surface;
119 }
120
121-static void
122-set_background (GdkPixbuf *new_bg, gboolean is_locked)
123+/* Sets the "ESETROOT_PMAP_ID" property to later be used to free the pixmap,
124+*/
125+static void
126+set_root_pixmap_id (GdkScreen *screen,
127+ Display *display,
128+ Pixmap xpixmap)
129+{
130+ Window xroot = RootWindow (display, gdk_screen_get_number (screen));
131+ char *atom_names[] = {"_XROOTPMAP_ID", "ESETROOT_PMAP_ID"};
132+ Atom atoms[G_N_ELEMENTS(atom_names)] = {0};
133+
134+ Atom type;
135+ int format;
136+ unsigned long nitems, after;
137+ unsigned char *data_root, *data_esetroot;
138+
139+ /* Get atoms for both properties in an array, only if they exist.
140+ * This method is to avoid multiple round-trips to Xserver
141+ */
142+ if (XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), True, atoms) &&
143+ atoms[0] != None && atoms[1] != None)
144+ {
145+
146+ XGetWindowProperty (display, xroot, atoms[0], 0L, 1L, False, AnyPropertyType,
147+ &type, &format, &nitems, &after, &data_root);
148+ if (data_root && type == XA_PIXMAP && format == 32 && nitems == 1)
149+ {
150+ XGetWindowProperty (display, xroot, atoms[1], 0L, 1L, False, AnyPropertyType,
151+ &type, &format, &nitems, &after, &data_esetroot);
152+ if (data_esetroot && type == XA_PIXMAP && format == 32 && nitems == 1)
153+ {
154+ Pixmap xrootpmap = *((Pixmap *) data_root);
155+ Pixmap esetrootpmap = *((Pixmap *) data_esetroot);
156+ XFree (data_root);
157+ XFree (data_esetroot);
158+
159+ gdk_error_trap_push ();
160+ if (xrootpmap && xrootpmap == esetrootpmap) {
161+ XKillClient (display, xrootpmap);
162+ }
163+ if (esetrootpmap && esetrootpmap != xrootpmap) {
164+ XKillClient (display, esetrootpmap);
165+ }
166+
167+ XSync (display, False);
168+
169+ gdk_error_trap_pop_ignored ();
170+ }
171+ }
172+ }
173+
174+ /* Get atoms for both properties in an array, create them if needed.
175+ * This method is to avoid multiple round-trips to Xserver
176+ */
177+ if (!XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), False, atoms) ||
178+ atoms[0] == None || atoms[1] == None) {
179+ g_warning("Could not create atoms needed to set root pixmap id/properties.\n");
180+ return;
181+ }
182+
183+ /* Set new _XROOTMAP_ID and ESETROOT_PMAP_ID properties */
184+ XChangeProperty (display, xroot, atoms[0], XA_PIXMAP, 32,
185+ PropModeReplace, (unsigned char *) &xpixmap, 1);
186+
187+ XChangeProperty (display, xroot, atoms[1], XA_PIXMAP, 32,
188+ PropModeReplace, (unsigned char *) &xpixmap, 1);
189+}
190+
191+/**
192+* set_surface_as_root:
193+* @screen: the #GdkScreen to change root background on
194+* @surface: the #cairo_surface_t to set root background from.
195+* Must be an xlib surface backing a pixmap.
196+*
197+* Set the root pixmap, and properties pointing to it. We
198+* do this atomically with a server grab to make sure that
199+* we won't leak the pixmap if somebody else it setting
200+* it at the same time. (This assumes that they follow the
201+* same conventions we do). @surface should come from a call
202+* to create_root_surface().
203+**/
204+static void
205+set_surface_as_root (GdkScreen *screen, cairo_surface_t *surface)
206+{
207+ g_return_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB);
208+
209+ /* Desktop background pixmap should be created from dummy X client since most
210+ * applications will try to kill it with XKillClient later when changing pixmap
211+ */
212+ Display *display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
213+ Pixmap pixmap_id = cairo_xlib_surface_get_drawable (surface);
214+ Window xroot = RootWindow (display, gdk_screen_get_number (screen));
215+
216+ XGrabServer (display);
217+
218+ XSetWindowBackgroundPixmap (display, xroot, pixmap_id);
219+ set_root_pixmap_id (screen, display, pixmap_id);
220+ XClearWindow (display, xroot);
221+
222+ XFlush (display);
223+ XUngrabServer (display);
224+}
225+
226+static void
227+set_background (GdkPixbuf *new_bg)
228 {
229 GdkRectangle monitor_geometry;
230 GdkPixbuf *bg = NULL;
231@@ -1486,7 +1580,7 @@
232 int monitor;
233
234 screen = gdk_display_get_screen (gdk_display_get_default (), i);
235- surface = create_root_surface (screen, is_locked);
236+ surface = create_root_surface (screen);
237 c = cairo_create (surface);
238
239 for (monitor = 0; monitor < gdk_screen_get_n_monitors (screen); monitor++)
240@@ -1497,27 +1591,32 @@
241 {
242 p_width = gdk_pixbuf_get_width(bg);
243 p_height = gdk_pixbuf_get_height(bg);
244-
245+
246 scale = (double)monitor_geometry.width/p_width;
247 height = p_height * scale;
248 width = monitor_geometry.width;
249-
250+
251 if (height < monitor_geometry.height)
252 {
253 scale = (double)monitor_geometry.height/p_height;
254 height = monitor_geometry.height;
255 width = p_width * scale;
256 }
257-
258-
259+
260 GdkPixbuf *p = gdk_pixbuf_scale_simple (bg, width,
261 height, GDK_INTERP_BILINEAR);
262 if (width > monitor_geometry.width)
263 {
264- p = gdk_pixbuf_new_subpixbuf(p, (width-monitor_geometry.width)/2, 0, monitor_geometry.width, monitor_geometry.height);
265- }
266- if (!gdk_pixbuf_get_has_alpha (p))
267- p = gdk_pixbuf_add_alpha (p, FALSE, 255, 255, 255);
268+ GdkPixbuf *tmp = gdk_pixbuf_new_subpixbuf(p, (width-monitor_geometry.width)/2, 0, monitor_geometry.width, monitor_geometry.height);
269+ g_object_unref (p);
270+ p = tmp;
271+ }
272+ if (!gdk_pixbuf_get_has_alpha (p))
273+ {
274+ GdkPixbuf *tmp = gdk_pixbuf_add_alpha (p, FALSE, 255, 255, 255);
275+ g_object_unref (p);
276+ p = tmp;
277+ }
278 gdk_cairo_set_source_pixbuf (c, p, monitor_geometry.x, monitor_geometry.y);
279 g_object_unref (p);
280 }
281@@ -1534,7 +1633,8 @@
282
283 /* Refresh background */
284 gdk_flush ();
285- XClearWindow (GDK_SCREEN_XDISPLAY (screen), RootWindow (GDK_SCREEN_XDISPLAY (screen), i));
286+ set_surface_as_root(screen, surface);
287+ cairo_surface_destroy(surface);
288 }
289 }
290
291@@ -1600,7 +1700,6 @@
292 GdkColor background_color;
293 #endif
294 GError *error = NULL;
295- gboolean is_locked = FALSE;
296 #ifdef HAVE_LIBINDICATOR
297 gchar **whitelist;
298 GDir *dir;
299@@ -1692,9 +1791,9 @@
300 }
301 g_free (value);
302
303- /* Set the background */
304- is_locked = lightdm_greeter_get_lock_hint (greeter);
305- set_background (NULL, is_locked);
306+ /* Force the screen to remain blank in case the session was just locked to reduce VT-switching flickering and to make the greeter behave a bit more like a screensaver than a mere unlock-dialog */
307+ if (lightdm_greeter_get_lock_hint (greeter))
308+ XForceScreenSaver(gdk_x11_display_get_xdisplay(gdk_display_get_default ()),ScreenSaverActive);
309
310 /* Set GTK+ settings */
311 value = g_key_file_get_value (config, "greeter", "theme-name", NULL);
312@@ -1985,9 +2084,14 @@
313 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (user_combo), renderer, "weight", 2);
314
315 if (lightdm_greeter_get_hide_users_hint (greeter))
316+ {
317+ /* Set the background to default */
318+ set_background (NULL);
319 start_authentication ("*other");
320+ }
321 else
322 {
323+ /* This also sets the background to user's */
324 load_user_list ();
325 gtk_widget_hide (GTK_WIDGET (cancel_button));
326 gtk_widget_show (GTK_WIDGET (user_combo));

Subscribers

People subscribed via source and target branches