/* wallpaper - Small application to set a desktop background on all displays. * Almost entirely stolen from lightdm. * * Copyright (C) 2011 Canonical Ltd. * Copyright (C) 2010-2011 Robert Ancell. * Author: Robert Ancell * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. See http://www.gnu.org/copyleft/gpl.html the full text of the * license. */ #include #include #include #include static cairo_surface_t * create_root_surface (GdkScreen *screen) { gint number, width, height; Display *display; Pixmap pixmap; cairo_surface_t *surface; number = gdk_screen_get_number (screen); width = gdk_screen_get_width (screen); height = gdk_screen_get_height (screen); /* Open a new connection so with Retain Permanent so the pixmap remains when the greeter quits */ gdk_flush (); display = XOpenDisplay (gdk_display_get_name (gdk_screen_get_display (screen))); if (!display) { g_warning ("Failed to create root pixmap"); return NULL; } XSetCloseDownMode (display, RetainPermanent); pixmap = XCreatePixmap (display, RootWindow (display, number), width, height, DefaultDepth (display, number)); XCloseDisplay (display); /* Convert into a Cairo surface */ surface = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (screen), pixmap, GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)), width, height); /* Use this pixmap for the background */ XSetWindowBackgroundPixmap (GDK_SCREEN_XDISPLAY (screen), RootWindow (GDK_SCREEN_XDISPLAY (screen), number), cairo_xlib_surface_get_drawable (surface)); return surface; } int main (int argc, char** argv) { GdkScreen *screen; int monitor; int i; GError *error = NULL; GdkPixbuf *background_pixbuf = NULL; GdkRectangle monitor_geometry; cairo_t *c; cairo_surface_t *surface; struct stat st; gtk_init (&argc, &argv); if (argc != 2 || stat(argv[1], &st) != 0) { g_error ("First parameter must be an existing background"); } background_pixbuf = gdk_pixbuf_new_from_file (argv[1], &error); if (!background_pixbuf) { g_error ("Failed to load background: %s", error->message); return 1; } g_clear_error (&error); for (i = 0; i < gdk_display_get_n_screens (gdk_display_get_default ()); i++) { screen = gdk_display_get_screen (gdk_display_get_default (), i); surface = create_root_surface (screen); c = cairo_create (surface); for (monitor = 0; monitor < gdk_screen_get_n_monitors (screen); monitor++) { gdk_screen_get_monitor_geometry (screen, monitor, &monitor_geometry); int img_w = gdk_pixbuf_get_width(background_pixbuf); int img_h = gdk_pixbuf_get_height(background_pixbuf); float monitor_aspect_ratio = (float) monitor_geometry.width / monitor_geometry.height; float img_aspect_ratio = (float) img_w / img_h; GdkPixbuf *subpixbuf = NULL; /* Crop image to fit the aspect ratio of monitor */ if (monitor_aspect_ratio > img_aspect_ratio) { /* cut areas in upper and bottom edge */ int cut_h = img_h - img_w / monitor_aspect_ratio; subpixbuf = gdk_pixbuf_new_subpixbuf (background_pixbuf, 0, cut_h/2, img_w, img_h-cut_h); } else if (monitor_aspect_ratio < img_aspect_ratio) { /* cut areas in left and right edge */ int cut_w = img_w - img_h * monitor_aspect_ratio; subpixbuf = gdk_pixbuf_new_subpixbuf (background_pixbuf, cut_w/2, 0, img_w-cut_w, img_h); } GdkPixbuf *pixbuf; if (subpixbuf != NULL) pixbuf = gdk_pixbuf_scale_simple (subpixbuf, monitor_geometry.width, monitor_geometry.height, GDK_INTERP_BILINEAR); else pixbuf = gdk_pixbuf_scale_simple (background_pixbuf, monitor_geometry.width, monitor_geometry.height, GDK_INTERP_BILINEAR); gdk_cairo_set_source_pixbuf (c, pixbuf, monitor_geometry.x, monitor_geometry.y); g_object_unref (pixbuf); if (subpixbuf) g_object_unref (subpixbuf); cairo_paint (c); } cairo_destroy (c); gdk_flush (); XClearWindow (GDK_SCREEN_XDISPLAY (screen), RootWindow (GDK_SCREEN_XDISPLAY (screen), i)); } gtk_main (); return 0; }