wmail: fixed use-after-free.
[dockapps.git] / wmsupermon / dockapp.c
blob805ab285fd465424c3121a44d73cf6d71c97cacb
1 /*
2 * 2006 - changes by Sergei Golubchik
3 * + set window title, better wm hints
4 * + multi-window support
5 */
7 /*
8 * Copyright (c) 1999 Alfredo K. Kojima
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
24 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 #include "dockapp.h"
31 #include <string.h>
32 #include <X11/extensions/shape.h>
33 #include <X11/Xlib.h>
34 #include <X11/Xatom.h>
35 #include <sys/time.h>
36 #include <sys/types.h>
37 #include <unistd.h>
40 static char *progName = NULL;
41 static unsigned d_width, d_height;
42 static DACallbacks d_callbacks = {NULL, NULL, NULL, NULL, NULL, NULL};
43 static int d_iswmaker = 0;
44 static int d_timeout = 0;
46 Display *DADisplay = NULL;
48 static unsigned char*
49 PropGetCheckProperty(Display *dpy, Window window, Atom hint, Atom type,
50 int format, int count, int *retCount)
52 Atom type_ret;
53 int fmt_ret;
54 unsigned long nitems_ret;
55 unsigned long bytes_after_ret;
56 unsigned char *data;
57 int tmp;
59 if (count <= 0)
60 tmp = 0xffffff;
61 else
62 tmp = count;
64 if (XGetWindowProperty(dpy, window, hint, 0, tmp, False, type,
65 &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
66 (unsigned char **)&data)!=Success || !data)
67 return NULL;
69 if ((type!=AnyPropertyType && type!=type_ret)
70 || (count > 0 && nitems_ret != count)
71 || (format != 0 && format != fmt_ret)) {
72 XFree(data);
73 return NULL;
76 if (retCount)
77 *retCount = nitems_ret;
79 return data;
83 static Bool
84 iswmaker(Display *dpy)
86 Atom *data;
87 Atom atom;
88 Atom noticeboard;
89 int i, count;
91 atom = XInternAtom(dpy, "_WINDOWMAKER_WM_PROTOCOLS", False);
92 noticeboard = XInternAtom(dpy, "_WINDOWMAKER_NOTICEBOARD", False);
94 data = (Atom*)PropGetCheckProperty(dpy, DefaultRootWindow(dpy), atom,
95 XA_ATOM, 32, -1, &count);
97 if (!data)
98 return False;
100 for (i = 0; i < count; i++) {
101 if (data[i] == noticeboard) {
102 Window *win;
103 void *d;
105 XFree(data);
107 win = (Window*)PropGetCheckProperty(dpy, DefaultRootWindow(dpy),
108 noticeboard, XA_WINDOW, 32, -1,
109 &count);
111 if (!win) {
112 return False;
115 d = PropGetCheckProperty(dpy, *win, noticeboard, XA_WINDOW, 32, 1,
116 NULL);
117 if (d) {
118 XFree(d);
120 return True;
122 return False;
126 XFree(data);
128 /* not 100% sure */
129 return True;
134 void
135 DAInitialize(char *display, char *name, unsigned width, unsigned height,
136 int argc, char **argv, Window *out)
138 XClassHint *chint;
139 XWMHints *hints;
140 XTextProperty wname;
141 Window DAWindow, DALeader;
143 d_width = width;
144 d_height = height;
146 progName = argv[0];
148 if (!DADisplay)
149 DADisplay = XOpenDisplay(display);
150 if (!DADisplay) {
151 printf("%s: could not open display %s!\n", progName,
152 XDisplayName(display));
154 exit(1);
157 d_iswmaker = iswmaker(DADisplay);
159 DAWindow = XCreateSimpleWindow(DADisplay, DefaultRootWindow(DADisplay),
160 0, 0, width, height, 0, 0, 0);
161 DALeader = XCreateSimpleWindow(DADisplay, DefaultRootWindow(DADisplay),
162 0, 0, 1, 1, 0, 0, 0);
164 chint = XAllocClassHint();
165 if (!chint) {
166 printf("%s: cant allocate memory for class hints!\n", progName);
167 exit(1);
169 chint->res_class = name;
170 chint->res_name = strrchr(argv[0], '/');
171 if (!chint->res_name)
172 chint->res_name = argv[0];
173 else
174 chint->res_name++;
176 XSetClassHint(DADisplay, DAWindow, chint);
177 XSetClassHint(DADisplay, DALeader, chint);
178 XFree(chint);
180 hints = XAllocWMHints();
181 if (!hints) {
182 printf("%s: cant allocate memory for hints!\n", progName);
183 exit(1);
185 hints->flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
186 hints->initial_state = WithdrawnState;
187 hints->window_group = DALeader;
188 hints->icon_window = DAWindow;
190 XSetWMHints(DADisplay, DALeader, hints);
191 XSetWMHints(DADisplay, DAWindow, hints);
193 XSetCommand(DADisplay, DALeader, argv, argc);
194 XSetCommand(DADisplay, DAWindow, argv, argc);
196 if (XStringListToTextProperty(&name, 1, &wname) == 0) {
197 fprintf(stderr, "%s: can't allocate window name\n", name);
198 exit(1);
201 XSetWMName(DADisplay, DALeader, &wname);
202 XSetWMName(DADisplay, DAWindow, &wname);
203 XFlush(DADisplay);
205 *out++=DAWindow;
206 *out++=DALeader;
210 void
211 DASetShape(Window *window, Pixmap shapeMask)
213 XShapeCombineMask(DADisplay, *window, ShapeBounding, 0, 0, shapeMask,
214 ShapeSet);
215 XFlush(DADisplay);
219 void
220 DASetPixmap(Window *window, Pixmap pixmap)
222 XSetWindowBackgroundPixmap(DADisplay, *window, pixmap);
223 XClearWindow(DADisplay, *window);
224 XFlush(DADisplay);
228 Pixmap
229 DAMakePixmap(Window *window)
231 Pixmap p;
233 p = XCreatePixmap(DADisplay, *window, d_width, d_height,
234 DefaultDepth(DADisplay, DefaultScreen(DADisplay)));
236 return p;
241 Bool
242 DAMakePixmapFromData(Window *window, char **data, Pixmap *pixmap, Pixmap *mask,
243 unsigned *width, unsigned *height)
245 Pixmap unused;
246 if (!mask)
247 mask=&unused;
249 XpmAttributes xpmat;
251 xpmat.valuemask = XpmCloseness;
252 xpmat.closeness = 40000;
254 if (XpmCreatePixmapFromData(DADisplay, *window, data, pixmap, mask,
255 &xpmat)!=0) {
256 return False;
259 *width = xpmat.width;
260 *height = xpmat.height;
262 return True;
266 void
267 DAShow(Window *window)
269 XMapRaised(DADisplay, window[d_iswmaker]);
271 XFlush(DADisplay);
275 void
276 DASetCallbacks(Window *window, DACallbacks *callbacks)
278 long mask = 0;
280 d_callbacks = *callbacks;
282 if (callbacks->buttonPress)
283 mask |= ButtonPressMask;
285 if (callbacks->buttonRelease)
286 mask |= ButtonReleaseMask;
288 XSelectInput(DADisplay, *window, mask);
289 XFlush(DADisplay);
293 Bool
294 DAProcessEvent(Window *window, XEvent *event)
296 if (event->xany.window != window[0] && event->xany.window != window[1])
297 return False;
299 switch (event->type) {
300 case DestroyNotify:
301 if (d_callbacks.destroy) {
302 (*d_callbacks.destroy)(window[0]);
304 exit(0);
305 break;
307 case ButtonPress:
308 if (d_callbacks.buttonPress) {
309 (*d_callbacks.buttonPress)(window[0], event->xbutton.button, event->xbutton.state,
310 event->xbutton.x, event->xbutton.y);
312 break;
314 case ButtonRelease:
315 if (d_callbacks.buttonRelease) {
316 (*d_callbacks.buttonRelease)(window[0], event->xbutton.button, event->xbutton.state,
317 event->xbutton.x, event->xbutton.y);
319 break;
321 case MotionNotify:
322 if (d_callbacks.motion) {
323 (*d_callbacks.motion)(window[0], event->xbutton.x, event->xbutton.y);
325 break;
327 case EnterNotify:
328 if (d_callbacks.enter) {
329 (*d_callbacks.enter)(window[0]);
331 break;
333 case LeaveNotify:
334 if (d_callbacks.leave) {
335 (*d_callbacks.leave)(window[0]);
337 break;
339 default:
340 return False;
341 break;
344 return True;
348 void
349 DAEventLoop(Window *window)
351 XEvent ev;
353 for (;;) {
354 if (d_timeout >= 0) {
355 if (!DANextEventOrTimeout(&ev, d_timeout)) {
356 if (d_callbacks.timeout)
357 (*d_callbacks.timeout)(window[0]);
358 continue;
360 } else {
361 XNextEvent(DADisplay, &ev);
363 DAProcessEvent(window, &ev);
368 static DAProgramOption defaultOptions[]= {
369 {"-h", "--help", "shows this help text and exit", DONone, False,
370 {NULL}},
371 {"-v", "--version", "shows program version and exit", DONone, False,
372 {NULL}}
376 static void
377 printHelp(char *prog, char *description, DAProgramOption *options,
378 int count)
380 int j;
382 printf("Usage: %s [OPTIONS]\n", prog);
383 if (description)
384 puts(description);
386 for (j = 0; j < count + 2; j++) {
387 char blank[35];
388 int c;
389 int i;
391 if (j >= count) {
392 options = defaultOptions;
393 i = j - count;
394 } else {
395 i = j;
398 if (options[i].shortForm && options[i].longForm)
399 c = printf(" %s, %s", options[i].shortForm, options[i].longForm);
400 else if (options[i].shortForm)
401 c = printf(" %s", options[i].shortForm);
402 else if (options[i].longForm)
403 c = printf(" %s", options[i].longForm);
404 else
405 continue;
407 if (options[i].type != DONone) {
408 switch (options[i].type) {
409 case DOInteger:
410 c += printf(" <integer>");
411 break;
412 case DOString:
413 c += printf(" <string>");
414 break;
415 case DONatural:
416 c+= printf(" <number>");
417 break;
421 memset(blank, ' ', 30);
422 if (c > 29)
423 c = 1;
424 blank[30-c] = 0;
425 printf("%s %s\n", blank, options[i].description);
430 void
431 DAParseArguments(int argc, char **argv, DAProgramOption *options,
432 int count, char *programDescription, char *versionDescription)
434 int i, j;
435 int found = 0;
437 for (i = 1; i < argc; i++) {
438 if (strcmp(argv[i], "-h")==0 || strcmp(argv[i], "--help")==0) {
440 printHelp(argv[0], programDescription, options, count);
441 exit(0);
443 } else if (strcmp(argv[i],"-v")==0 || strcmp(argv[i], "--version")==0) {
445 puts(versionDescription);
446 exit(0);
450 found = 0;
451 for (j = 0; j < count; j++) {
452 if ((options[j].shortForm
453 && strcmp(options[j].shortForm, argv[i])==0)
455 (options[j].longForm
456 && strcmp(options[j].longForm, argv[i])==0)) {
458 found = 1;
460 options[j].used = True;
462 if (options[j].type == DONone)
463 break;
465 i++;
466 if (i >= argc) {
467 printf("%s: missing argument for option '%s'\n", argv[0],
468 argv[i-1]);
469 exit(1);
472 switch (options[j].type) {
473 case DOInteger:
475 int integer;
477 if (sscanf(argv[i], "%i", &integer)!=1) {
478 printf("%s: error parsing argument for option %s\n",
479 argv[0], argv[i-1]);
480 exit(1);
482 *options[j].value.integer = integer;
484 break;
485 case DONatural:
487 int integer;
489 if (sscanf(argv[i], "%i", &integer)!=1) {
490 printf("%s: error parsing argument for option %s\n",
491 argv[0], argv[i-1]);
492 exit(1);
494 if (integer < 0) {
495 printf("%s: argument %s must be >= 0\n",
496 argv[0], argv[i-1]);
497 exit(1);
499 *options[j].value.integer = integer;
501 break;
502 case DOString:
503 *options[j].value.string = argv[i];
504 break;
506 break;
509 if (!found) {
510 printf("%s: unrecognized option '%s'\n", argv[0], argv[i]);
511 printHelp(argv[0], programDescription, options, count);
512 exit(1);
518 unsigned long
519 DAGetColor(char *colorName)
521 XColor color;
523 if (!XParseColor(DADisplay,
524 DefaultColormap(DADisplay, DefaultScreen(DADisplay)),
525 colorName, &color)) {
526 printf("%s: could not parse color %s\n", progName, colorName);
527 exit(1);
530 if (!XAllocColor(DADisplay, DefaultColormap(DADisplay, DefaultScreen(DADisplay)),
531 &color)) {
532 printf("%s: could not allocate color %s. Using black\n", progName, colorName);
533 return BlackPixel(DADisplay, DefaultScreen(DADisplay));
536 return color.pixel;
540 void
541 DASetTimeout(int milliseconds)
543 d_timeout = milliseconds;
548 Bool
549 DANextEventOrTimeout(XEvent *event, unsigned long millisec)
551 struct timeval timeout;
552 fd_set rset;
554 XSync(DADisplay, False);
555 if (XPending(DADisplay)) {
556 XNextEvent(DADisplay, event);
557 return True;
560 timeout.tv_sec = millisec/1000;
561 timeout.tv_usec = (millisec%1000)*10;
563 FD_ZERO(&rset);
564 FD_SET(ConnectionNumber(DADisplay), &rset);
566 if (select(ConnectionNumber(DADisplay)+1, &rset, NULL, NULL,
567 &timeout) > 0) {
568 XNextEvent(DADisplay, event);
569 return True;
571 return False;