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