]> icculus.org git repositories - mikachu/openbox.git/blob - util/bsetroot.cc
allow the user to specify the modmask used to mouse events on windows
[mikachu/openbox.git] / util / bsetroot.cc
1 // -*- mode++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // bsetroot.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #ifdef    HAVE_CONFIG_H
25 #  include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 extern "C" {
29 #ifdef HAVE_STDLIB_H
30 #  include <stdlib.h>
31 #endif // HAVE_STDLIB_H
32
33 #ifdef HAVE_STRING_H
34 #  include <string.h>
35 #endif // HAVE_STRING_H
36
37 #ifdef    HAVE_STDIO_H
38 #  include <stdio.h>
39 #endif // HAVE_STDIO_H
40 }
41
42 #include <cctype>
43
44 #include "../src/i18n.hh"
45 #include "../src/GCCache.hh"
46 #include "../src/Texture.hh"
47 #include "../src/Util.hh"
48 #include "bsetroot.hh"
49
50
51 I18n i18n;
52
53 bsetroot::bsetroot(int argc, char **argv, char *dpy_name)
54   : BaseDisplay(argv[0], dpy_name) {
55
56   bool mod = False, sol = False, grd = False;
57   int mod_x = 0, mod_y = 0;
58
59   for (int i = 1; i < argc; i++) {
60     if (! strcmp("-help", argv[i])) {
61       usage();
62     } else if ((! strcmp("-fg", argv[i])) ||
63                (! strcmp("-foreground", argv[i])) ||
64                (! strcmp("-from", argv[i]))) {
65       if ((++i) >= argc) usage(1);
66
67       fore = argv[i];
68     } else if ((! strcmp("-bg", argv[i])) ||
69                (! strcmp("-background", argv[i])) ||
70                (! strcmp("-to", argv[i]))) {
71       if ((++i) >= argc) usage(1);
72
73       back = argv[i];
74     } else if (! strcmp("-solid", argv[i])) {
75       if ((++i) >= argc) usage(1);
76
77       fore = argv[i];
78       sol = True;
79     } else if (! strcmp("-mod", argv[i])) {
80       if ((++i) >= argc) usage();
81
82       mod_x = atoi(argv[i]);
83
84       if ((++i) >= argc) usage();
85
86       mod_y = atoi(argv[i]);
87
88       if (mod_x < 1) mod_x = 1;
89       if (mod_y < 1) mod_y = 1;
90
91       mod = True;
92     } else if (! strcmp("-gradient", argv[i])) {
93       if ((++i) >= argc) usage();
94
95       grad = argv[i];
96       grd = True;
97     } else if (! strcmp("-display", argv[i])) {
98       // -display passed through tests ealier... we just skip it now
99       i++;
100     } else {
101       usage();
102     }
103   }
104
105   if ((mod + sol + grd) != True) {
106     fprintf(stderr,
107             i18n(bsetrootSet, bsetrootMustSpecify,
108                  "%s: error: must specify one of: -solid, -mod, -gradient\n"),
109             getApplicationName());
110
111     usage(2);
112   }
113
114   img_ctrl = new BImageControl*[getNumberOfScreens()];
115   for (unsigned int s = 0; s < getNumberOfScreens(); ++s)
116     img_ctrl[s] = new BImageControl(this, getScreenInfo(s), True);
117
118   if (sol && ! fore.empty())
119     solid();
120   else if (mod && mod_x && mod_y && ! (fore.empty() || back.empty()))
121     modula(mod_x, mod_y);
122   else if (grd && ! (grad.empty() || fore.empty() || back.empty()))
123     gradient();
124   else usage();
125 }
126
127
128 bsetroot::~bsetroot(void) {
129   XSetCloseDownMode(getXDisplay(), RetainPermanent);
130
131   XKillClient(getXDisplay(), AllTemporary);
132
133   std::for_each(img_ctrl, img_ctrl + getNumberOfScreens(), PointerAssassin());
134
135   delete [] img_ctrl;
136 }
137
138
139 // adapted from wmsetbg
140 void bsetroot::setPixmapProperty(int screen, Pixmap pixmap) {
141   static Atom rootpmap_id = None, esetroot_id = None;
142   Atom type;
143   int format;
144   unsigned long length, after;
145   unsigned char *data;
146   const ScreenInfo *screen_info = getScreenInfo(screen);
147
148   if (rootpmap_id == None) {
149     rootpmap_id = XInternAtom(getXDisplay(), "_XROOTPMAP_ID", False);
150     esetroot_id = XInternAtom(getXDisplay(), "ESETROOT_PMAP_ID", False);
151   }
152
153   XGrabServer(getXDisplay());
154
155   /* Clear out the old pixmap */
156   XGetWindowProperty(getXDisplay(), screen_info->getRootWindow(),
157                      rootpmap_id, 0L, 1L, False, AnyPropertyType,
158                      &type, &format, &length, &after, &data);
159
160   if ((type == XA_PIXMAP) && (format == 32) && (length == 1)) {
161     unsigned char* data_esetroot = 0;
162     XGetWindowProperty(getXDisplay(), screen_info->getRootWindow(),
163                        esetroot_id, 0L, 1L, False, AnyPropertyType,
164                        &type, &format, &length, &after, &data_esetroot);
165     if (data && data_esetroot && *((Pixmap *) data)) {
166       XKillClient(getXDisplay(), *((Pixmap *) data));
167       XSync(getXDisplay(), False);
168       XFree(data_esetroot);
169     }
170     XFree(data);
171   }
172
173   if (pixmap) {
174     XChangeProperty(getXDisplay(), screen_info->getRootWindow(),
175                     rootpmap_id, XA_PIXMAP, 32, PropModeReplace,
176                     (unsigned char *) &pixmap, 1);
177     XChangeProperty(getXDisplay(), screen_info->getRootWindow(),
178                     esetroot_id, XA_PIXMAP, 32, PropModeReplace,
179                     (unsigned char *) &pixmap, 1);
180   } else {
181     XDeleteProperty(getXDisplay(), screen_info->getRootWindow(),
182                     rootpmap_id);
183     XDeleteProperty(getXDisplay(), screen_info->getRootWindow(),
184                     esetroot_id);
185   }
186
187   XUngrabServer(getXDisplay());
188   XFlush(getXDisplay());
189 }
190
191
192 // adapted from wmsetbg
193 Pixmap bsetroot::duplicatePixmap(int screen, Pixmap pixmap,
194                                  int width, int height) {
195   XSync(getXDisplay(), False);
196
197   Pixmap copyP = XCreatePixmap(getXDisplay(),
198                                getScreenInfo(screen)->getRootWindow(),
199                                width, height,
200                                DefaultDepth(getXDisplay(), screen));
201   XCopyArea(getXDisplay(), pixmap, copyP, DefaultGC(getXDisplay(), screen),
202             0, 0, width, height, 0, 0);
203   XSync(getXDisplay(), False);
204
205   return copyP;
206 }
207
208
209 void bsetroot::solid(void) {
210   for (unsigned int screen = 0; screen < getNumberOfScreens(); screen++) {
211     BColor c(fore, this, screen);
212     const ScreenInfo *screen_info = getScreenInfo(screen);
213
214     XSetWindowBackground(getXDisplay(), screen_info->getRootWindow(),
215                          c.pixel());
216     XClearWindow(getXDisplay(), screen_info->getRootWindow());
217
218     Pixmap pixmap = XCreatePixmap(getXDisplay(),
219                                   screen_info->getRootWindow(),
220                                   8, 8, DefaultDepth(getXDisplay(), screen));
221     BPen pen(c);
222     XFillRectangle(getXDisplay(), pixmap, pen.gc(), 0, 0, 8, 8);
223
224     setPixmapProperty(screen, duplicatePixmap(screen, pixmap, 8, 8));
225
226     XFreePixmap(getXDisplay(), pixmap);
227   }
228 }
229
230
231 void bsetroot::modula(int x, int y) {
232   char data[32];
233   long pattern;
234
235   unsigned int screen, i;
236
237   for (pattern = 0, screen = 0; screen < getNumberOfScreens(); screen++) {
238     for (i = 0; i < 16; i++) {
239       pattern <<= 1;
240       if ((i % x) == 0)
241         pattern |= 0x0001;
242     }
243
244     for (i = 0; i < 16; i++) {
245       if ((i %  y) == 0) {
246         data[(i * 2)] = static_cast<char>(0xff);
247         data[(i * 2) + 1] = static_cast<char>(0xff);
248       } else {
249         data[(i * 2)] = pattern & 0xff;
250         data[(i * 2) + 1] = (pattern >> 8) & 0xff;
251       }
252     }
253
254     BColor f(fore, this, screen), b(back, this, screen);
255     GC gc;
256     Pixmap bitmap;
257     const ScreenInfo *screen_info = getScreenInfo(screen);
258
259     bitmap =
260       XCreateBitmapFromData(getXDisplay(),
261                             screen_info->getRootWindow(), data,
262                             16, 16);
263
264     XGCValues gcv;
265     gcv.foreground = f.pixel();
266     gcv.background = b.pixel();
267
268     gc = XCreateGC(getXDisplay(), screen_info->getRootWindow(),
269                    GCForeground | GCBackground, &gcv);
270
271     Pixmap pixmap = XCreatePixmap(getXDisplay(),
272                                   screen_info->getRootWindow(),
273                                   16, 16, screen_info->getDepth());
274
275     XCopyPlane(getXDisplay(), bitmap, pixmap, gc,
276                0, 0, 16, 16, 0, 0, 1l);
277     XSetWindowBackgroundPixmap(getXDisplay(),
278                                screen_info->getRootWindow(),
279                                pixmap);
280     XClearWindow(getXDisplay(), screen_info->getRootWindow());
281
282     setPixmapProperty(screen,
283                       duplicatePixmap(screen, pixmap, 16, 16));
284
285     XFreeGC(getXDisplay(), gc);
286     XFreePixmap(getXDisplay(), bitmap);
287
288     if (! (screen_info->getVisual()->c_class & 1))
289       XFreePixmap(getXDisplay(), pixmap);
290   }
291 }
292
293
294 void bsetroot::gradient(void) {
295   /*
296     we have to be sure that neither raised nor sunken is specified otherwise
297     odd looking borders appear.  So we convert to lowercase then look for
298     'raised' or 'sunken' in the description and erase them.  To be paranoid
299     the search is done in a loop.
300   */
301   std::string descr;
302   descr.reserve(grad.size());
303
304   std::string::const_iterator it = grad.begin(), end = grad.end();
305   for (; it != end; ++it)
306     descr += std::tolower(*it);
307
308   std::string::size_type pos;
309   while ((pos = descr.find("raised")) != std::string::npos)
310     descr.erase(pos, 6); // 6 is strlen raised
311
312   while ((pos = descr.find("sunken")) != std::string::npos)
313     descr.erase(pos, 6);
314
315   // now add on 'flat' to prevent the bevels from being added
316   descr += "flat";
317
318   for (unsigned int screen = 0; screen < getNumberOfScreens(); screen++) {
319     BTexture texture(descr, this, screen, img_ctrl[screen]);
320     const ScreenInfo *screen_info = getScreenInfo(screen);
321
322     texture.setColor(BColor(fore, this, screen));
323     texture.setColorTo(BColor(back, this, screen));
324
325     Pixmap pixmap =
326       img_ctrl[screen]->renderImage(screen_info->getWidth(),
327                                     screen_info->getHeight(),
328                                     texture);
329
330     XSetWindowBackgroundPixmap(getXDisplay(),
331                                screen_info->getRootWindow(),
332                                pixmap);
333     XClearWindow(getXDisplay(), screen_info->getRootWindow());
334
335     setPixmapProperty(screen,
336                       duplicatePixmap(screen, pixmap,
337                                       screen_info->getWidth(),
338                                       screen_info->getHeight()));
339
340     if (! (screen_info->getVisual()->c_class & 1)) {
341       img_ctrl[screen]->removeImage(pixmap);
342     }
343   }
344 }
345
346
347 void bsetroot::usage(int exit_code) {
348     fprintf(stderr,
349             i18n(bsetrootSet, bsetrootUsage,
350                  "%s 2.0\n\n"
351                  "Copyright (c) 1997-2000, 2002 Bradley T Hughes\n"
352                  "Copyright (c) 2001-2002 Sean 'Shaleh' Perry\n\n"
353                  "  -display <string>        display connection\n"
354                  "  -mod <x> <y>             modula pattern\n"
355                  "  -foreground, -fg <color> modula foreground color\n"
356                  "  -background, -bg <color> modula background color\n\n"
357                  "  -gradient <texture>      gradient texture\n"
358                  "  -from <color>            gradient start color\n"
359                  "  -to <color>              gradient end color\n\n"
360                  "  -solid <color>           solid color\n\n"
361                  "  -help                    print this help text and exit\n"),
362             getApplicationName());
363
364     exit(exit_code);
365 }
366
367 int main(int argc, char **argv) {
368   char *display_name = (char *) 0;
369
370   i18n.openCatalog("openbox.cat");
371
372   for (int i = 1; i < argc; i++) {
373     if (! strcmp(argv[i], "-display")) {
374       // check for -display option
375
376       if ((++i) >= argc) {
377         fprintf(stderr, i18n(mainSet, mainDISPLAYRequiresArg,
378                              "error: '-display' requires an argument\n"));
379
380         ::exit(1);
381       }
382
383       display_name = argv[i];
384     }
385   }
386
387   bsetroot app(argc, argv, display_name);
388
389   return 0;
390 }