1 /*
2 
3  * Esetroot -- Set the root pixmap.  This program enables non-Enlightenment
4  *             users to use Eterm's support for pseudotransparency.
5  *
6  * Written by Nat Friedman <ndf@mit.edu> with modifications by Gerald Britton
7  * <gbritton@mit.edu> and Michael Jennings <mej@eterm.org>
8  *
9  */
10 
11 static const char cvs_ident[] = "$Id: Esetroot.c 51650 2010-08-26 01:34:13Z lucas $";
12 
13 #include "../config.h"
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #ifdef HAVE_UNISTD_H
18 # include <unistd.h>
19 #endif
20 #include <errno.h>
21 #include <libast.h>
22 
23 #ifdef PIXMAP_SUPPORT
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <X11/Xatom.h>
27 #include <X11/Xos.h>
28 #include <Imlib2.h>
29 
30 void set_pixmap_property(Pixmap p);
31 
32 Display *Xdisplay;
33 Screen *scr;
34 Window Xroot;
35 int screen;
36 unsigned char debug = 0;
37 
38 #define Xdepth	 (DefaultDepth(Xdisplay, screen))
39 
40 void
set_pixmap_property(Pixmap p)41 set_pixmap_property(Pixmap p)
42 {
43 
44     Atom prop_root, prop_esetroot, type;
45     int format;
46     unsigned long length, after;
47     unsigned char *data_root, *data_esetroot;
48 
49     prop_root = XInternAtom(Xdisplay, "_XROOTPMAP_ID", True);
50     prop_esetroot = XInternAtom(Xdisplay, "ESETROOT_PMAP_ID", True);
51 
52     if (debug) {
53         fprintf(stderr, "%s:%d:  set_pixmap_property(0x%08x):  prop_root == 0x%08x, prop_esetroot == 0x%08x\n", __FILE__, __LINE__,
54                 (unsigned int) p, (unsigned int) prop_root, (unsigned int) prop_esetroot);
55     }
56     if (prop_root != None && prop_esetroot != None) {
57         XGetWindowProperty(Xdisplay, Xroot, prop_root, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data_root);
58         if (type == XA_PIXMAP) {
59             XGetWindowProperty(Xdisplay, Xroot, prop_esetroot, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after,
60                                &data_esetroot);
61             if (data_root && data_esetroot) {
62                 if (debug) {
63                     fprintf(stderr, "%s:%d:  set_pixmap_property(0x%08x):  data_root == 0x%08x, data_esetroot == 0x%08x\n",
64                             __FILE__, __LINE__, (unsigned int) p, (unsigned int) *((Pixmap *) data_root),
65                             (unsigned int) *((Pixmap *) data_esetroot));
66                 }
67                 if (type == XA_PIXMAP && *((Pixmap *) data_root) == *((Pixmap *) data_esetroot)) {
68                     if (debug) {
69                         fprintf(stderr, "%s:%d:  set_pixmap_property(0x%08x):  XKillClient() is being called.\n", __FILE__,
70                                 __LINE__, (unsigned int) p);
71                     }
72                     XKillClient(Xdisplay, *((Pixmap *) data_root));
73                 }
74             }
75         }
76     }
77     /* This will locate the property, creating it if it doesn't exist */
78     prop_root = XInternAtom(Xdisplay, "_XROOTPMAP_ID", False);
79     prop_esetroot = XInternAtom(Xdisplay, "ESETROOT_PMAP_ID", False);
80 
81     /* The call above should have created it.  If that failed, we can't continue. */
82     if (prop_root == None || prop_esetroot == None) {
83         fprintf(stderr, "Esetroot:  creation of pixmap property failed.\n");
84         exit(1);
85     }
86     XChangeProperty(Xdisplay, Xroot, prop_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &p, 1);
87     XChangeProperty(Xdisplay, Xroot, prop_esetroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &p, 1);
88     if (debug) {
89         fprintf(stderr, "%s:%d:  set_pixmap_property(0x%08x):  _XROOTPMAP_ID and ESETROOT_PMAP_ID set to 0x%08x.\n", __FILE__,
90                 __LINE__, (unsigned int) p, (unsigned int) p);
91     }
92     XSetCloseDownMode(Xdisplay, RetainPermanent);
93     XFlush(Xdisplay);
94 }
95 #endif
96 
97 int
main(int argc,char * argv[])98 main(int argc, char *argv[])
99 {
100 #ifdef PIXMAP_SUPPORT
101     unsigned char scale = 0, center = 0, fit = 0, mirror = 0;
102     char *displayname = NULL, *fname = NULL, *bgcolor = NULL;
103     Imlib_Image im;
104     Pixmap p = None, temp_pmap = None, m = None;
105     register unsigned char i;
106     GC gc;
107     XGCValues gcv;
108     XColor xcolor;
109     int w, h, x, y;
110 
111     if (argc < 2) {
112         fprintf(stderr, "%s [-display <display_name>] [-bgcolor <color>] [-scale] [-center] [-fit] [-mirror] pixmap\n", *argv);
113         fprintf(stderr, "\t Short options are also recognized (-d, -b, -s, -c, -f, and -m)\n");
114         exit(0);
115     }
116     for (i = 1; i < argc; i++) {
117         if (*argv[i] != '-') {
118             break;
119         }
120         if (argv[i][1] == 'd') {
121             displayname = argv[++i];
122         } else if (argv[i][1] == 'b') {
123             bgcolor = argv[++i];
124         } else if (argv[i][1] == 's') {
125             scale = 1;
126         } else if (argv[i][1] == 'c') {
127             center = 1;
128         } else if (argv[i][1] == 'f') {
129             fit = 1;
130         } else if (argv[i][1] == 'm') {
131             mirror = 1;
132         } else if (argv[i][1] == 'x') {
133             fprintf(stderr, "Debugging activated.\n");
134             debug = 1;
135         } else {
136             fprintf(stderr, "%s:  Unrecognized option \'%c\'\n\n", *argv, argv[i][1]);
137             fprintf(stderr, "%s [-display <display_name>] [-bgcolor <color>] [-scale] [-center] [-fit] [-mirror] pixmap\n", *argv);
138             fprintf(stderr, "\t Short options are also recognized (-d, -b, -s, -c, -f, and -m)\n");
139             exit(2);
140         }
141     }
142 
143     fname = argv[i];
144     if (scale) {
145         center = 0;
146         mirror = 0;
147     }
148 
149     if (debug) {
150         fprintf(stderr, "%s:%d:  Display name is \"%s\"\n", __FILE__, __LINE__, displayname ? displayname : "(nil)");
151         fprintf(stderr, "%s:%d:  Background color name is \"%s\"\n", __FILE__, __LINE__, bgcolor ? bgcolor : "(nil)");
152         fprintf(stderr, "%s:%d:  Image will be %s\n", __FILE__, __LINE__,
153                 scale ? "scaled" : (center ? "centered" : (fit ? "fit" : "tiled")));
154         fprintf(stderr, "%s:%d:  Image file is %s\n", __FILE__, __LINE__, fname ? fname : "(nil)");
155     }
156     if (!displayname) {
157         displayname = getenv("DISPLAY");
158         if (debug) {
159             fprintf(stderr, "%s:%d:  Display name set to %s via getenv(\"DISPLAY\")\n", __FILE__, __LINE__,
160                     displayname ? displayname : "(nil)");
161         }
162     }
163     if (!displayname) {
164         displayname = ":0.0";
165         if (debug) {
166             fprintf(stderr, "%s:%d:  Display name defaulted to %s\n", __FILE__, __LINE__, displayname ? displayname : "(nil)");
167         }
168     }
169     if ((Xdisplay = XOpenDisplay(displayname)) == 0) {
170         fprintf(stderr, "%s:  Unable to open display %s\n", *argv, displayname);
171         exit(1);
172     }
173     screen = DefaultScreen(Xdisplay);
174     Xroot = RootWindow(Xdisplay, screen);
175     scr = ScreenOfDisplay(Xdisplay, screen);
176     if (debug) {
177         fprintf(stderr, "%s:%d:  Chose screen %d\n", __FILE__, __LINE__, screen);
178         fprintf(stderr, "%s:%d:  Root window is 0x%08x\n", __FILE__, __LINE__, (unsigned int) Xroot);
179         fprintf(stderr, "%s:%d:  Found screen information at %8p\n", __FILE__, __LINE__, scr);
180     }
181     imlib_context_set_display(Xdisplay);
182     imlib_context_set_visual(DefaultVisual(Xdisplay, DefaultScreen(Xdisplay)));
183     im = imlib_load_image_immediately(fname);
184     if (!im) {
185         fprintf(stderr, "%s:  Unable to load image file \"%s\".\n", *argv, fname);
186         exit(1);
187     } else if (debug) {
188         fprintf(stderr, "%s:%d:  The Imlib Image is at %8p\n", __FILE__, __LINE__, im);
189     }
190     imlib_context_set_image(im);
191     if (scale) {
192         w = scr->width;
193         h = scr->height;
194     } else if (mirror) {
195         w = imlib_image_get_width() * 2;
196         h = imlib_image_get_height() * 2;
197     } else {
198         w = imlib_image_get_width();
199         h = imlib_image_get_height();
200     }
201     if (fit) {
202         double x_ratio, y_ratio;
203 
204         x_ratio = ((double) scr->width) / ((double) w);
205         y_ratio = ((double) scr->height) / ((double) h);
206         if (x_ratio > y_ratio) {
207             x_ratio = y_ratio;
208         }
209         w = (int) (w * x_ratio);
210         h = (int) (h * x_ratio);
211     }
212 
213     p = XCreatePixmap(Xdisplay, Xroot, scr->width, scr->height, Xdepth);
214     gcv.foreground = gcv.background = BlackPixel(Xdisplay, screen);
215     if (bgcolor && XParseColor(Xdisplay, DefaultColormap(Xdisplay, screen), bgcolor, &xcolor)
216         && XAllocColor(Xdisplay, DefaultColormap(Xdisplay, screen), &xcolor)) {
217         gcv.foreground = gcv.background = xcolor.pixel;
218     }
219     gc = XCreateGC(Xdisplay, p, (GCForeground | GCBackground), &gcv);
220     if (scale) {
221         XFillRectangle(Xdisplay, p, gc, 0, 0, w, h);
222     }
223     if (center || fit) {
224         XFillRectangle(Xdisplay, p, gc, 0, 0, scr->width, scr->height);
225         x = (scr->width - w) >> 1;
226         y = (scr->height - h) >> 1;
227     } else {
228         x = 0;
229         y = 0;
230     }
231     if (debug) {
232         fprintf(stderr, "%s:%d:  Assigned width and height for rendering as %dx%d\n", __FILE__, __LINE__, w, h);
233         fprintf(stderr, "%s:%d:  Created %dx%d+%d+%d pixmap 0x%08x\n", __FILE__, __LINE__, scr->width, scr->height, x, y,
234                 (unsigned int) p);
235         fprintf(stderr, "%s:%d:  Applied Graphics Context %8p to pixmap.\n", __FILE__, __LINE__, gc);
236     }
237     imlib_context_set_anti_alias(1);
238     imlib_context_set_dither(1);
239     imlib_context_set_blend(0);
240     if (mirror) {
241         temp_pmap = XCreatePixmap(Xdisplay, Xroot, w, h, Xdepth);
242         imlib_context_set_drawable(temp_pmap);
243         imlib_render_image_on_drawable(0, 0);
244         imlib_image_flip_horizontal();
245         imlib_render_image_on_drawable(imlib_image_get_width(), 0);
246         imlib_image_flip_vertical();
247         imlib_render_image_on_drawable(imlib_image_get_width(), imlib_image_get_height());
248         imlib_image_flip_horizontal();
249         imlib_render_image_on_drawable(0, imlib_image_get_height());
250     } else {
251         imlib_context_set_drawable(Xroot);
252         imlib_render_pixmaps_for_whole_image_at_size(&temp_pmap, &m, w, h);
253     }
254     if (debug) {
255         fprintf(stderr, "%s:%d:  Rendered at %dx%d onto pixmap 0x%08x\n", __FILE__, __LINE__, w, h, (unsigned int) temp_pmap);
256     }
257     if (temp_pmap != None) {
258         if (m) {
259             XFreePixmap(Xdisplay, m);
260             m = None;
261         }
262         XSetTile(Xdisplay, gc, temp_pmap);
263         XSetTSOrigin(Xdisplay, gc, x, y);
264         XSetFillStyle(Xdisplay, gc, FillTiled);
265         if (center || fit) {
266             XFillRectangle(Xdisplay, p, gc, x, y, w, h);
267         } else {
268             XFillRectangle(Xdisplay, p, gc, x, y, scr->width, scr->height);
269         }
270         XGrabServer(Xdisplay);
271         set_pixmap_property(p);
272         XSetWindowBackgroundPixmap(Xdisplay, Xroot, p);
273         XClearWindow(Xdisplay, Xroot);
274         XUngrabServer(Xdisplay);
275         XFlush(Xdisplay);
276     }
277 #else
278     USE_VAR(argc);
279     USE_VAR(argv);
280     fprintf(stderr, "Eterm was built without pixmap support, so Esetroot is fairly useless.  Sorry.\n");
281 #endif
282     return 0;
283 }
284