~lightdm-gtk-greeter-team/lightdm-gtk-greeter/trunk

« back to all changes in this revision

Viewing changes to src/lightdm-gtk-greeter.c

  • Committer: Sean Davis
  • Date: 2013-11-29 16:18:17 UTC
  • mfrom: (146.1.5 lightdm-gtk-greeter)
  • Revision ID: smd.seandavis@gmail.com-20131129161817-qnv759t8iaq0ll90
Merge background-fixes branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
#include <gtk/gtk.h>
22
22
#include <glib/gi18n.h>
23
23
#include <cairo-xlib.h>
 
24
#include <X11/Xlib.h>
 
25
#include <X11/Xatom.h>
24
26
#include <gdk-pixbuf/gdk-pixbuf.h>
25
27
#include <gdk/gdkx.h>
26
28
#include <glib.h>
438
440
    gtk_widget_set_sensitive (GTK_WIDGET (language_menu), !logged_in);
439
441
}
440
442
 
441
 
static void set_background (GdkPixbuf *new_bg, gboolean is_locked);
 
443
static void set_background (GdkPixbuf *new_bg);
442
444
 
443
445
static void
444
 
set_user_background (const gchar *username, gboolean is_locked)
 
446
set_user_background (const gchar *username)
445
447
{
446
448
    LightDMUser *user;
447
449
    const gchar *path;
463
465
        }
464
466
    }
465
467
 
466
 
    set_background (bg, is_locked);
 
468
    set_background (bg);
467
469
    if (bg)
468
470
        g_object_unref (bg);
469
471
}
873
875
{
874
876
    GtkTreeModel *model;
875
877
    GtkTreeIter iter;
876
 
    gboolean is_locked;
877
878
 
878
879
    model = gtk_combo_box_get_model (user_combo);
879
880
 
895
896
        }
896
897
 
897
898
        set_login_button_label (greeter, user);
898
 
        is_locked = lightdm_greeter_get_lock_hint (greeter);
899
 
        set_user_background (user, is_locked);
 
899
        set_user_background (user);
900
900
        set_user_image (user);
901
901
        gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), user);
902
902
        start_authentication (user);
1329
1329
    gchar *last_user;
1330
1330
    const gchar *selected_user;
1331
1331
    gboolean logged_in = FALSE;
1332
 
    gboolean is_locked = FALSE;
1333
1332
 
1334
1333
    g_signal_connect (lightdm_user_list_get_instance (), "user-added", G_CALLBACK (user_added_cb), greeter);
1335
1334
    g_signal_connect (lightdm_user_list_get_instance (), "user-changed", G_CALLBACK (user_changed_cb), greeter);
1336
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
1336
    model = gtk_combo_box_get_model (user_combo);
1339
1337
    items = lightdm_user_list_get_users (lightdm_user_list_get_instance ());
1340
1338
    for (item = items; item; item = item->next)
1394
1392
                {
1395
1393
                    gtk_combo_box_set_active_iter (user_combo, &iter);
1396
1394
                    set_login_button_label (greeter, selected_user);
1397
 
                    set_user_background (selected_user, is_locked);
 
1395
                    set_user_background (selected_user);
1398
1396
                    set_user_image (selected_user);
1399
1397
                    gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), selected_user);
1400
1398
                    start_authentication (selected_user);
1408
1406
            gtk_tree_model_get (model, &iter, 0, &name, -1);
1409
1407
            gtk_combo_box_set_active_iter (user_combo, &iter);
1410
1408
            set_login_button_label (greeter, name);
1411
 
            set_user_background (name, is_locked);
 
1409
            set_user_background (name);
1412
1410
            set_user_image (name);
1413
1411
            gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), name);
1414
1412
            start_authentication (name);
1420
1418
    g_free (last_user);
1421
1419
}
1422
1420
 
 
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 */
1423
1424
static cairo_surface_t *
1424
 
create_root_surface (GdkScreen *screen, gboolean is_locked)
 
1425
create_root_surface (GdkScreen *screen)
1425
1426
{
1426
1427
    gint number, width, height;
1427
1428
    Display *display;
1441
1442
        return NULL;
1442
1443
    }
1443
1444
 
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
1445
    XSetCloseDownMode (display, RetainPermanent);
1449
1446
    pixmap = XCreatePixmap (display, RootWindow (display, number), width, height, DefaultDepth (display, number));
1450
1447
    XCloseDisplay (display);
1455
1452
                                         GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)),
1456
1453
                                         width, height);
1457
1454
 
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
1455
    return surface;
1465
1456
}
1466
1457
 
1467
 
static void
1468
 
set_background (GdkPixbuf *new_bg, gboolean is_locked)
 
1458
/* Sets the "ESETROOT_PMAP_ID" property to later be used to free the pixmap,
 
1459
*/
 
1460
static void
 
1461
set_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
**/
 
1539
static void
 
1540
set_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
 
 
1561
static void
 
1562
set_background (GdkPixbuf *new_bg)
1469
1563
{
1470
1564
    GdkRectangle monitor_geometry;
1471
1565
    GdkPixbuf *bg = NULL;
1486
1580
        int monitor;
1487
1581
 
1488
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
1584
        c = cairo_create (surface);
1491
1585
 
1492
1586
        for (monitor = 0; monitor < gdk_screen_get_n_monitors (screen); monitor++)
1497
1591
            {
1498
1592
                p_width = gdk_pixbuf_get_width(bg);
1499
1593
                p_height = gdk_pixbuf_get_height(bg);
1500
 
                
 
1594
 
1501
1595
                scale = (double)monitor_geometry.width/p_width;
1502
1596
                height = p_height * scale;
1503
1597
                width = monitor_geometry.width;
1504
 
                
 
1598
 
1505
1599
                if (height < monitor_geometry.height)
1506
1600
                {
1507
1601
                    scale = (double)monitor_geometry.height/p_height;
1508
1602
                    height = monitor_geometry.height;
1509
1603
                    width = p_width * scale;
1510
1604
                }
1511
 
                
1512
 
                
 
1605
 
1513
1606
                GdkPixbuf *p = gdk_pixbuf_scale_simple (bg, width,
1514
1607
                                                        height, GDK_INTERP_BILINEAR);
1515
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);
1518
 
                }
1519
 
        if (!gdk_pixbuf_get_has_alpha (p))
1520
 
            p = gdk_pixbuf_add_alpha (p, FALSE, 255, 255, 255);
 
1610
                    GdkPixbuf *tmp = gdk_pixbuf_new_subpixbuf(p, (width-monitor_geometry.width)/2, 0, monitor_geometry.width, monitor_geometry.height);
 
1611
                    g_object_unref (p);
 
1612
                    p = tmp;
 
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
1620
                gdk_cairo_set_source_pixbuf (c, p, monitor_geometry.x, monitor_geometry.y);
1522
1621
                g_object_unref (p);
1523
1622
            }
1534
1633
 
1535
1634
        /* Refresh background */
1536
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
}
1540
1640
 
1600
1700
    GdkColor background_color;
1601
1701
#endif
1602
1702
    GError *error = NULL;
1603
 
    gboolean is_locked = FALSE;
1604
1703
#ifdef HAVE_LIBINDICATOR
1605
1704
    gchar **whitelist;
1606
1705
    GDir *dir;
1692
1791
    }
1693
1792
    g_free (value);
1694
1793
 
1695
 
    /* Set the background */
1696
 
    is_locked = lightdm_greeter_get_lock_hint (greeter);
1697
 
    set_background (NULL, is_locked);
 
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 */
 
1795
    if (lightdm_greeter_get_lock_hint (greeter))
 
1796
        XForceScreenSaver(gdk_x11_display_get_xdisplay(gdk_display_get_default ()),ScreenSaverActive);
1698
1797
 
1699
1798
    /* Set GTK+ settings */
1700
1799
    value = g_key_file_get_value (config, "greeter", "theme-name", NULL);
1985
2084
    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (user_combo), renderer, "weight", 2);
1986
2085
 
1987
2086
    if (lightdm_greeter_get_hide_users_hint (greeter))
 
2087
    {
 
2088
        /* Set the background to default */
 
2089
        set_background (NULL);
1988
2090
        start_authentication ("*other");
 
2091
    }
1989
2092
    else
1990
2093
    {
 
2094
        /* This also sets the background to user's */
1991
2095
        load_user_list ();
1992
2096
        gtk_widget_hide (GTK_WIDGET (cancel_button));
1993
2097
        gtk_widget_show (GTK_WIDGET (user_combo));