This is a very basic implementation of setting wallpaper
from within Awesome. It uses libX11 and imlib2, thus everything
works out of the box.
The public function is set_wallpaper(), which currently just
scales it to full screen.

Signed-off-by: Arvydas Sidorenko <[email protected]>
---
 CMakeLists.txt |    1 +
 wallpaper.c    |  261 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 wallpaper.h    |   32 +++++++
 3 files changed, 294 insertions(+), 0 deletions(-)
 create mode 100644 wallpaper.c
 create mode 100644 wallpaper.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index e9f8aa2..3bf1059 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -56,6 +56,7 @@ set(AWE_SRCS
     ${SOURCE_DIR}/stack.c
     ${SOURCE_DIR}/strut.c
     ${SOURCE_DIR}/systray.c
+    ${SOURCE_DIR}/wallpaper.c
     ${SOURCE_DIR}/xwindow.c
     ${SOURCE_DIR}/common/atoms.c
     ${SOURCE_DIR}/common/backtrace.c
diff --git a/wallpaper.c b/wallpaper.c
new file mode 100644
index 0000000..e8abf1b
--- /dev/null
+++ b/wallpaper.c
@@ -0,0 +1,261 @@
+/*
+ * wallpaper.c - wallpaper manager
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <Imlib2.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "wallpaper.h"
+#include "common/xutil.h"
+
+struct wallpaper {
+    /* libX11 */
+    Display *dpy;
+    GC gc;
+    Pixmap pix;
+    Pixmap tmp_pix;
+
+    /* imlib2 */
+    Imlib_Image img;
+    Imlib_Image offscreen;
+
+    int x;
+    int y;
+
+    const char *file;
+    int width;
+    int height;
+};
+
+static bool img_file_valid(const char *file)
+{
+    struct stat filestat;
+
+    if (!file || strlen(file) == 0)
+        return false;
+
+    if (stat(file, &filestat)) {
+        warn("cannot get wallpaper stats");
+        return false;
+    }
+
+    if (!S_ISREG(filestat.st_mode)) {
+        warn("not a regular file");
+        return false;
+    }
+
+    if (access(file, R_OK)) {
+        warn("wallpaper not readable");
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * Opens a display and creates black graphics context to paint 
+ * the wallpaper on. 
+ */
+static bool init_root_display(struct wallpaper *w)
+{
+    Screen *screen;
+    Window root;
+    int scr, width, height, depth;
+    XGCValues gcv;
+
+    if (!w)
+        return false;
+
+    w->dpy = XOpenDisplay(NULL);
+    if (!w->dpy) {
+        warn("unable to open display");
+        return false;
+    }
+
+    scr = DefaultScreen(w->dpy);
+    screen = ScreenOfDisplay(w->dpy, scr);
+    root = RootWindow(w->dpy, scr);
+    width = screen->width;
+    height = screen->height;
+    depth = DefaultDepth(w->dpy, scr);
+    assert(width > 0 && height > 0);
+    w->pix = XCreatePixmap(w->dpy, root, width, height, depth);
+
+    gcv.foreground = gcv.background = WhitePixel(w->dpy, scr);
+    w->gc = XCreateGC(w->dpy, w->pix, 0 /* mask */, &gcv);
+    XFillRectangle(w->dpy, w->pix, w->gc, 0 /* x */, 0 /* y */, width, height);
+
+    return true;
+}
+
+/**
+ * Draws the wallpaper on the imlib2 off-screen buffer. 
+ */
+static bool draw_offscreen_wallpaper(struct wallpaper *w)
+{
+    Screen *scr;
+
+    scr = ScreenOfDisplay(w->dpy, DefaultScreen(w->dpy));
+
+    imlib_context_set_display(w->dpy);
+    imlib_context_set_visual(DefaultVisual(w->dpy, DefaultScreen(w->dpy)));
+    w->img = imlib_load_image_immediately(w->file);
+    if (!w->img) {
+        warn("cannot load wallpaper");
+        return false;
+    }
+
+    imlib_context_set_image(w->img);
+    w->width = imlib_image_get_width();
+    w->height = imlib_image_get_height();
+    w->offscreen = imlib_create_image(scr->width, scr->height);
+    imlib_context_set_image(w->offscreen);
+    /* In scale mode keeps the edges smooth */
+    imlib_context_set_anti_alias(1);
+    /* In case a given image file quality sucks, this will make
+     * it considerably better */
+    imlib_context_set_dither(1);
+    imlib_context_set_blend(1);
+
+    /* Do the drawing */
+    /* TODO: here the coordinates and scaling should depend on wallpaper_mode 
*/
+    imlib_blend_image_onto_image(w->img,
+                                 0 /* alpha */,
+                                 0 /* src_x */,
+                                 0 /* src_y */,
+                                 w->width, w->height,
+                                 0 /* dst_x */,
+                                 0 /* dst_y */,
+                                 scr->width, scr->height);
+    return true;
+}
+
+static bool show_wallpaper(struct wallpaper *w)
+{
+    Screen *scr;
+    Window root;
+    Pixmap pix_mask = None;
+    int screen;
+
+    screen = DefaultScreen(w->dpy);
+    root = RootWindow(w->dpy, screen);
+    scr = ScreenOfDisplay(w->dpy, screen);
+
+    imlib_context_set_drawable(root);
+    imlib_render_pixmaps_for_whole_image_at_size(&w->tmp_pix, &pix_mask,
+                                                 scr->width, scr->height);
+    if (pix_mask) {
+        XFreePixmap(w->dpy, pix_mask);
+        pix_mask = None;
+    }
+
+    if (!w->tmp_pix)
+        return false;
+
+    XSetTile(w->dpy, w->gc, w->tmp_pix);
+    XSetTSOrigin(w->dpy, w->gc, w->x, w->y);
+    XSetFillStyle(w->dpy, w->gc, FillTiled);
+    XFillRectangle(w->dpy, w->pix, w->gc, w->x, w->y, scr->width, scr->height);
+    XSetWindowBackgroundPixmap(w->dpy, root, w->pix);
+    XClearWindow(w->dpy, root);
+    XFlush(w->dpy);
+
+    return true;
+}
+
+static bool enable_pseudo_transparency(struct wallpaper *w)
+{
+    Atom root_atom, esetroot_atom, root_atom_type, esetroot_atom_type;
+    int format;
+    unsigned long length, after;
+    unsigned char *data_root, *data_esetroot;
+    Window root;
+    int scr;
+
+    scr = DefaultScreen(w->dpy);
+    root = RootWindow(w->dpy, scr);
+
+    /* Clients access root window background using _XROOTPMAP_ID and
+     * ESETROOT_PMAP_ID properties. What we do is first check if they 
+     * already exist. If so, XKillClient and then proceed setting 
+     * the properties to point the new pixmap. */ 
+    root_atom = XInternAtom(w->dpy, "_XROOTPMAP_ID", True);
+    esetroot_atom = XInternAtom(w->dpy, "ESETROOT_PMAP_ID", True);
+    if (root_atom != None && esetroot_atom != None) {
+        XGetWindowProperty(w->dpy, root, root_atom, 0L, 1L, False, 
AnyPropertyType,
+                           &root_atom_type, &format, &length, &after, 
&data_root);
+        XGetWindowProperty(w->dpy, root, esetroot_atom, 0L, 1L, False, 
AnyPropertyType,
+                           &esetroot_atom_type, &format, &length, &after, 
&data_esetroot);
+        if (root_atom_type == XA_PIXMAP && esetroot_atom_type == XA_PIXMAP &&
+            *((Pixmap *) data_root) == *((Pixmap *) esetroot_atom)) {
+                XKillClient(w->dpy, *((Pixmap *)data_esetroot));
+        }
+    }
+
+    root_atom = XInternAtom(w->dpy, "_XROOTPMAP_ID", False);
+    esetroot_atom = XInternAtom(w->dpy, "ESETROOT_PMAP_ID", False);
+
+    if (root_atom == None || esetroot_atom == None) {
+        warn("pixmap atom creation failed");
+        return false;
+    }
+
+    XChangeProperty(w->dpy, root, root_atom, XA_PIXMAP, 32, PropModeReplace,
+                    (unsigned char *)&w->pix, 1);
+    XChangeProperty(w->dpy, root, esetroot_atom, XA_PIXMAP, 32, 
PropModeReplace,
+                    (unsigned char *)&w->pix, 1);
+    XSetCloseDownMode(w->dpy, RetainPermanent);
+
+    return true;
+}
+
+bool set_wallpaper(const char *file, enum wallpaper_mode mode)
+{
+    struct wallpaper w;
+    
+    if (!img_file_valid(file)) {
+        warn("invalid wallpaper file");
+        return false;
+    }
+    w.file = file;
+    w.x = 0;
+    w.y = 0;
+
+    if (!init_root_display(&w)) {
+        warn("unable to initialize root display");
+        return false;
+    }
+    /* The X11 display is ready - do imlib2 magic now */
+    if (!draw_offscreen_wallpaper(&w)) {
+        warn("error drawing the wallpaper");
+        return false;
+    }
+    if (!show_wallpaper(&w)) {
+        warn("error dumping to screen");
+        return false;
+    }
+
+    enable_pseudo_transparency(&w);
+    XFlush(w.dpy);
+    XCloseDisplay(w.dpy);
+
+    return true;
+}
diff --git a/wallpaper.h b/wallpaper.h
new file mode 100644
index 0000000..f5ab9dc
--- /dev/null
+++ b/wallpaper.h
@@ -0,0 +1,32 @@
+/*
+ * wallpaper.h - wallpaper manager header
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef AWESOME_WALLPAPER_H
+#define AWESOME_WALLPAPER_H
+
+#include <stdbool.h>
+
+enum wallpaper_mode {
+    WALLPAPER_CENTER,
+    WALLPAPER_SCALE
+};
+
+bool set_wallpaper(const char *file, enum wallpaper_mode mode);
+
+#endif // AWESOME_WALLPAPER_H
-- 
1.7.8.6


-- 
To unsubscribe, send mail to [email protected].

Reply via email to