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
=== modified file 'src/lightdm-gtk-greeter.c'
--- src/lightdm-gtk-greeter.c 2013-11-29 16:15:05 +0000
+++ src/lightdm-gtk-greeter.c 2013-11-29 16:16:51 +0000
@@ -21,6 +21,8 @@
21#include <gtk/gtk.h>21#include <gtk/gtk.h>
22#include <glib/gi18n.h>22#include <glib/gi18n.h>
23#include <cairo-xlib.h>23#include <cairo-xlib.h>
24#include <X11/Xlib.h>
25#include <X11/Xatom.h>
24#include <gdk-pixbuf/gdk-pixbuf.h>26#include <gdk-pixbuf/gdk-pixbuf.h>
25#include <gdk/gdkx.h>27#include <gdk/gdkx.h>
26#include <glib.h>28#include <glib.h>
@@ -438,10 +440,10 @@
438 gtk_widget_set_sensitive (GTK_WIDGET (language_menu), !logged_in);440 gtk_widget_set_sensitive (GTK_WIDGET (language_menu), !logged_in);
439}441}
440442
441static void set_background (GdkPixbuf *new_bg, gboolean is_locked);443static void set_background (GdkPixbuf *new_bg);
442444
443static void445static void
444set_user_background (const gchar *username, gboolean is_locked)446set_user_background (const gchar *username)
445{447{
446 LightDMUser *user;448 LightDMUser *user;
447 const gchar *path;449 const gchar *path;
@@ -463,7 +465,7 @@
463 }465 }
464 }466 }
465467
466 set_background (bg, is_locked);468 set_background (bg);
467 if (bg)469 if (bg)
468 g_object_unref (bg);470 g_object_unref (bg);
469}471}
@@ -873,7 +875,6 @@
873{875{
874 GtkTreeModel *model;876 GtkTreeModel *model;
875 GtkTreeIter iter;877 GtkTreeIter iter;
876 gboolean is_locked;
877878
878 model = gtk_combo_box_get_model (user_combo);879 model = gtk_combo_box_get_model (user_combo);
879880
@@ -895,8 +896,7 @@
895 }896 }
896897
897 set_login_button_label (greeter, user);898 set_login_button_label (greeter, user);
898 is_locked = lightdm_greeter_get_lock_hint (greeter);899 set_user_background (user);
899 set_user_background (user, is_locked);
900 set_user_image (user);900 set_user_image (user);
901 gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), user);901 gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), user);
902 start_authentication (user);902 start_authentication (user);
@@ -1329,12 +1329,10 @@
1329 gchar *last_user;1329 gchar *last_user;
1330 const gchar *selected_user;1330 const gchar *selected_user;
1331 gboolean logged_in = FALSE;1331 gboolean logged_in = FALSE;
1332 gboolean is_locked = FALSE;
13331332
1334 g_signal_connect (lightdm_user_list_get_instance (), "user-added", G_CALLBACK (user_added_cb), greeter);1333 g_signal_connect (lightdm_user_list_get_instance (), "user-added", G_CALLBACK (user_added_cb), greeter);
1335 g_signal_connect (lightdm_user_list_get_instance (), "user-changed", G_CALLBACK (user_changed_cb), greeter);1334 g_signal_connect (lightdm_user_list_get_instance (), "user-changed", G_CALLBACK (user_changed_cb), greeter);
1336 g_signal_connect (lightdm_user_list_get_instance (), "user-removed", G_CALLBACK (user_removed_cb), NULL);1335 g_signal_connect (lightdm_user_list_get_instance (), "user-removed", G_CALLBACK (user_removed_cb), NULL);
1337 is_locked = lightdm_greeter_get_lock_hint (greeter);
1338 model = gtk_combo_box_get_model (user_combo);1336 model = gtk_combo_box_get_model (user_combo);
1339 items = lightdm_user_list_get_users (lightdm_user_list_get_instance ());1337 items = lightdm_user_list_get_users (lightdm_user_list_get_instance ());
1340 for (item = items; item; item = item->next)1338 for (item = items; item; item = item->next)
@@ -1394,7 +1392,7 @@
1394 {1392 {
1395 gtk_combo_box_set_active_iter (user_combo, &iter);1393 gtk_combo_box_set_active_iter (user_combo, &iter);
1396 set_login_button_label (greeter, selected_user);1394 set_login_button_label (greeter, selected_user);
1397 set_user_background (selected_user, is_locked);1395 set_user_background (selected_user);
1398 set_user_image (selected_user);1396 set_user_image (selected_user);
1399 gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), selected_user);1397 gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), selected_user);
1400 start_authentication (selected_user);1398 start_authentication (selected_user);
@@ -1408,7 +1406,7 @@
1408 gtk_tree_model_get (model, &iter, 0, &name, -1);1406 gtk_tree_model_get (model, &iter, 0, &name, -1);
1409 gtk_combo_box_set_active_iter (user_combo, &iter);1407 gtk_combo_box_set_active_iter (user_combo, &iter);
1410 set_login_button_label (greeter, name);1408 set_login_button_label (greeter, name);
1411 set_user_background (name, is_locked);1409 set_user_background (name);
1412 set_user_image (name);1410 set_user_image (name);
1413 gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), name);1411 gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), name);
1414 start_authentication (name);1412 start_authentication (name);
@@ -1420,8 +1418,11 @@
1420 g_free (last_user);1418 g_free (last_user);
1421}1419}
14221420
1421/* The following code for setting a RetainPermanent background pixmap was taken
1422 originally from Gnome, with some fixes from MATE. see:
1423 https://github.com/mate-desktop/mate-desktop/blob/master/libmate-desktop/mate-bg.c */
1423static cairo_surface_t *1424static cairo_surface_t *
1424create_root_surface (GdkScreen *screen, gboolean is_locked)1425create_root_surface (GdkScreen *screen)
1425{1426{
1426 gint number, width, height;1427 gint number, width, height;
1427 Display *display;1428 Display *display;
@@ -1441,10 +1442,6 @@
1441 return NULL;1442 return NULL;
1442 }1443 }
14431444
1444 /* 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 */
1445 if (is_locked)
1446 XForceScreenSaver(display,ScreenSaverActive);
1447
1448 XSetCloseDownMode (display, RetainPermanent);1445 XSetCloseDownMode (display, RetainPermanent);
1449 pixmap = XCreatePixmap (display, RootWindow (display, number), width, height, DefaultDepth (display, number));1446 pixmap = XCreatePixmap (display, RootWindow (display, number), width, height, DefaultDepth (display, number));
1450 XCloseDisplay (display);1447 XCloseDisplay (display);
@@ -1455,17 +1452,114 @@
1455 GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)),1452 GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)),
1456 width, height);1453 width, height);
14571454
1458 /* Use this pixmap for the background */
1459 XSetWindowBackgroundPixmap (GDK_SCREEN_XDISPLAY (screen),
1460 RootWindow (GDK_SCREEN_XDISPLAY (screen), number),
1461 cairo_xlib_surface_get_drawable (surface));
1462
1463
1464 return surface;1455 return surface;
1465}1456}
14661457
1467static void1458/* Sets the "ESETROOT_PMAP_ID" property to later be used to free the pixmap,
1468set_background (GdkPixbuf *new_bg, gboolean is_locked)1459*/
1460static void
1461set_root_pixmap_id (GdkScreen *screen,
1462 Display *display,
1463 Pixmap xpixmap)
1464{
1465 Window xroot = RootWindow (display, gdk_screen_get_number (screen));
1466 char *atom_names[] = {"_XROOTPMAP_ID", "ESETROOT_PMAP_ID"};
1467 Atom atoms[G_N_ELEMENTS(atom_names)] = {0};
1468
1469 Atom type;
1470 int format;
1471 unsigned long nitems, after;
1472 unsigned char *data_root, *data_esetroot;
1473
1474 /* Get atoms for both properties in an array, only if they exist.
1475 * This method is to avoid multiple round-trips to Xserver
1476 */
1477 if (XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), True, atoms) &&
1478 atoms[0] != None && atoms[1] != None)
1479 {
1480
1481 XGetWindowProperty (display, xroot, atoms[0], 0L, 1L, False, AnyPropertyType,
1482 &type, &format, &nitems, &after, &data_root);
1483 if (data_root && type == XA_PIXMAP && format == 32 && nitems == 1)
1484 {
1485 XGetWindowProperty (display, xroot, atoms[1], 0L, 1L, False, AnyPropertyType,
1486 &type, &format, &nitems, &after, &data_esetroot);
1487 if (data_esetroot && type == XA_PIXMAP && format == 32 && nitems == 1)
1488 {
1489 Pixmap xrootpmap = *((Pixmap *) data_root);
1490 Pixmap esetrootpmap = *((Pixmap *) data_esetroot);
1491 XFree (data_root);
1492 XFree (data_esetroot);
1493
1494 gdk_error_trap_push ();
1495 if (xrootpmap && xrootpmap == esetrootpmap) {
1496 XKillClient (display, xrootpmap);
1497 }
1498 if (esetrootpmap && esetrootpmap != xrootpmap) {
1499 XKillClient (display, esetrootpmap);
1500 }
1501
1502 XSync (display, False);
1503
1504 gdk_error_trap_pop_ignored ();
1505 }
1506 }
1507 }
1508
1509 /* Get atoms for both properties in an array, create them if needed.
1510 * This method is to avoid multiple round-trips to Xserver
1511 */
1512 if (!XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names), False, atoms) ||
1513 atoms[0] == None || atoms[1] == None) {
1514 g_warning("Could not create atoms needed to set root pixmap id/properties.\n");
1515 return;
1516 }
1517
1518 /* Set new _XROOTMAP_ID and ESETROOT_PMAP_ID properties */
1519 XChangeProperty (display, xroot, atoms[0], XA_PIXMAP, 32,
1520 PropModeReplace, (unsigned char *) &xpixmap, 1);
1521
1522 XChangeProperty (display, xroot, atoms[1], XA_PIXMAP, 32,
1523 PropModeReplace, (unsigned char *) &xpixmap, 1);
1524}
1525
1526/**
1527* set_surface_as_root:
1528* @screen: the #GdkScreen to change root background on
1529* @surface: the #cairo_surface_t to set root background from.
1530* Must be an xlib surface backing a pixmap.
1531*
1532* Set the root pixmap, and properties pointing to it. We
1533* do this atomically with a server grab to make sure that
1534* we won't leak the pixmap if somebody else it setting
1535* it at the same time. (This assumes that they follow the
1536* same conventions we do). @surface should come from a call
1537* to create_root_surface().
1538**/
1539static void
1540set_surface_as_root (GdkScreen *screen, cairo_surface_t *surface)
1541{
1542 g_return_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB);
1543
1544 /* Desktop background pixmap should be created from dummy X client since most
1545 * applications will try to kill it with XKillClient later when changing pixmap
1546 */
1547 Display *display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
1548 Pixmap pixmap_id = cairo_xlib_surface_get_drawable (surface);
1549 Window xroot = RootWindow (display, gdk_screen_get_number (screen));
1550
1551 XGrabServer (display);
1552
1553 XSetWindowBackgroundPixmap (display, xroot, pixmap_id);
1554 set_root_pixmap_id (screen, display, pixmap_id);
1555 XClearWindow (display, xroot);
1556
1557 XFlush (display);
1558 XUngrabServer (display);
1559}
1560
1561static void
1562set_background (GdkPixbuf *new_bg)
1469{1563{
1470 GdkRectangle monitor_geometry;1564 GdkRectangle monitor_geometry;
1471 GdkPixbuf *bg = NULL;1565 GdkPixbuf *bg = NULL;
@@ -1486,7 +1580,7 @@
1486 int monitor;1580 int monitor;
14871581
1488 screen = gdk_display_get_screen (gdk_display_get_default (), i);1582 screen = gdk_display_get_screen (gdk_display_get_default (), i);
1489 surface = create_root_surface (screen, is_locked);1583 surface = create_root_surface (screen);
1490 c = cairo_create (surface);1584 c = cairo_create (surface);
14911585
1492 for (monitor = 0; monitor < gdk_screen_get_n_monitors (screen); monitor++)1586 for (monitor = 0; monitor < gdk_screen_get_n_monitors (screen); monitor++)
@@ -1497,27 +1591,32 @@
1497 {1591 {
1498 p_width = gdk_pixbuf_get_width(bg);1592 p_width = gdk_pixbuf_get_width(bg);
1499 p_height = gdk_pixbuf_get_height(bg);1593 p_height = gdk_pixbuf_get_height(bg);
1500 1594
1501 scale = (double)monitor_geometry.width/p_width;1595 scale = (double)monitor_geometry.width/p_width;
1502 height = p_height * scale;1596 height = p_height * scale;
1503 width = monitor_geometry.width;1597 width = monitor_geometry.width;
1504 1598
1505 if (height < monitor_geometry.height)1599 if (height < monitor_geometry.height)
1506 {1600 {
1507 scale = (double)monitor_geometry.height/p_height;1601 scale = (double)monitor_geometry.height/p_height;
1508 height = monitor_geometry.height;1602 height = monitor_geometry.height;
1509 width = p_width * scale;1603 width = p_width * scale;
1510 }1604 }
1511 1605
1512
1513 GdkPixbuf *p = gdk_pixbuf_scale_simple (bg, width,1606 GdkPixbuf *p = gdk_pixbuf_scale_simple (bg, width,
1514 height, GDK_INTERP_BILINEAR);1607 height, GDK_INTERP_BILINEAR);
1515 if (width > monitor_geometry.width)1608 if (width > monitor_geometry.width)
1516 {1609 {
1517 p = gdk_pixbuf_new_subpixbuf(p, (width-monitor_geometry.width)/2, 0, monitor_geometry.width, monitor_geometry.height);1610 GdkPixbuf *tmp = gdk_pixbuf_new_subpixbuf(p, (width-monitor_geometry.width)/2, 0, monitor_geometry.width, monitor_geometry.height);
1518 }1611 g_object_unref (p);
1519 if (!gdk_pixbuf_get_has_alpha (p))1612 p = tmp;
1520 p = gdk_pixbuf_add_alpha (p, FALSE, 255, 255, 255);1613 }
1614 if (!gdk_pixbuf_get_has_alpha (p))
1615 {
1616 GdkPixbuf *tmp = gdk_pixbuf_add_alpha (p, FALSE, 255, 255, 255);
1617 g_object_unref (p);
1618 p = tmp;
1619 }
1521 gdk_cairo_set_source_pixbuf (c, p, monitor_geometry.x, monitor_geometry.y);1620 gdk_cairo_set_source_pixbuf (c, p, monitor_geometry.x, monitor_geometry.y);
1522 g_object_unref (p);1621 g_object_unref (p);
1523 }1622 }
@@ -1534,7 +1633,8 @@
15341633
1535 /* Refresh background */1634 /* Refresh background */
1536 gdk_flush ();1635 gdk_flush ();
1537 XClearWindow (GDK_SCREEN_XDISPLAY (screen), RootWindow (GDK_SCREEN_XDISPLAY (screen), i));1636 set_surface_as_root(screen, surface);
1637 cairo_surface_destroy(surface);
1538 }1638 }
1539}1639}
15401640
@@ -1600,7 +1700,6 @@
1600 GdkColor background_color;1700 GdkColor background_color;
1601#endif1701#endif
1602 GError *error = NULL;1702 GError *error = NULL;
1603 gboolean is_locked = FALSE;
1604#ifdef HAVE_LIBINDICATOR1703#ifdef HAVE_LIBINDICATOR
1605 gchar **whitelist;1704 gchar **whitelist;
1606 GDir *dir;1705 GDir *dir;
@@ -1692,9 +1791,9 @@
1692 }1791 }
1693 g_free (value);1792 g_free (value);
16941793
1695 /* Set the background */1794 /* 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 */
1696 is_locked = lightdm_greeter_get_lock_hint (greeter);1795 if (lightdm_greeter_get_lock_hint (greeter))
1697 set_background (NULL, is_locked);1796 XForceScreenSaver(gdk_x11_display_get_xdisplay(gdk_display_get_default ()),ScreenSaverActive);
16981797
1699 /* Set GTK+ settings */1798 /* Set GTK+ settings */
1700 value = g_key_file_get_value (config, "greeter", "theme-name", NULL);1799 value = g_key_file_get_value (config, "greeter", "theme-name", NULL);
@@ -1985,9 +2084,14 @@
1985 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (user_combo), renderer, "weight", 2);2084 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (user_combo), renderer, "weight", 2);
19862085
1987 if (lightdm_greeter_get_hide_users_hint (greeter))2086 if (lightdm_greeter_get_hide_users_hint (greeter))
2087 {
2088 /* Set the background to default */
2089 set_background (NULL);
1988 start_authentication ("*other");2090 start_authentication ("*other");
2091 }
1989 else2092 else
1990 {2093 {
2094 /* This also sets the background to user's */
1991 load_user_list ();2095 load_user_list ();
1992 gtk_widget_hide (GTK_WIDGET (cancel_button));2096 gtk_widget_hide (GTK_WIDGET (cancel_button));
1993 gtk_widget_show (GTK_WIDGET (user_combo));2097 gtk_widget_show (GTK_WIDGET (user_combo));

Subscribers

People subscribed via source and target branches