WPrefs: Code formatting in TexturePanel.c; minimizes checkpatch.pl warnings.
[wmaker-crm.git] / src / misc.c
blob02aa40172f9bca23acead177b0010d7f8a27b148
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "wconfig.h"
22 #include <X11/Xlib.h>
23 #include <X11/Xutil.h>
24 #include <X11/Xatom.h>
25 #include <sys/stat.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <stdarg.h>
33 #include <pwd.h>
34 #include <math.h>
35 #include <time.h>
36 #include <errno.h>
38 #include <X11/XKBlib.h>
40 #include <WINGs/WUtil.h>
41 #include <wraster.h>
43 #include "window.h"
44 #include "misc.h"
45 #include "WindowMaker.h"
46 #include "GNUstep.h"
47 #include "screen.h"
48 #include "wcore.h"
49 #include "window.h"
50 #include "framewin.h"
51 #include "dialog.h"
52 #include "xutil.h"
53 #include "xmodifier.h"
54 #include "main.h"
55 #include "event.h"
58 #define ICON_SIZE wPreferences.icon_size
60 /**** Local prototypes *****/
61 static void UnescapeWM_CLASS(const char *str, char **name, char **class);
63 /* XFetchName Wrapper */
64 Bool wFetchName(Display *dpy, Window win, char **winname)
66 XTextProperty text_prop;
67 char **list;
68 int num;
70 if (XGetWMName(dpy, win, &text_prop)) {
71 if (text_prop.value && text_prop.nitems > 0) {
72 if (text_prop.encoding == XA_STRING) {
73 *winname = wstrdup((char *)text_prop.value);
74 XFree(text_prop.value);
75 } else {
76 text_prop.nitems = strlen((char *)text_prop.value);
77 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
78 Success && num > 0 && *list) {
79 XFree(text_prop.value);
80 *winname = wstrdup(*list);
81 XFreeStringList(list);
82 } else {
83 *winname = wstrdup((char *)text_prop.value);
84 XFree(text_prop.value);
87 } else {
88 /* the title is set, but it was set to none */
89 *winname = wstrdup("");
91 return True;
92 } else {
93 /* the hint is probably not set */
94 *winname = NULL;
96 return False;
100 /* XGetIconName Wrapper */
101 Bool wGetIconName(Display *dpy, Window win, char **iconname)
103 XTextProperty text_prop;
104 char **list;
105 int num;
107 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value && text_prop.nitems > 0) {
108 if (text_prop.encoding == XA_STRING)
109 *iconname = (char *)text_prop.value;
110 else {
111 text_prop.nitems = strlen((char *)text_prop.value);
112 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success && num > 0 && *list) {
113 XFree(text_prop.value);
114 *iconname = wstrdup(*list);
115 XFreeStringList(list);
116 } else
117 *iconname = (char *)text_prop.value;
119 return True;
121 *iconname = NULL;
122 return False;
125 static void eatExpose(void)
127 XEvent event, foo;
129 /* compress all expose events into a single one */
131 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
132 /* ignore other exposure events for this window */
133 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask, &foo)) ;
134 /* eat exposes for other windows */
135 eatExpose();
137 event.xexpose.count = 0;
138 XPutBackEvent(dpy, &event);
142 void move_window(Window win, int from_x, int from_y, int to_x, int to_y)
144 #ifdef USE_ANIMATIONS
145 if (wPreferences.no_animations)
146 XMoveWindow(dpy, win, to_x, to_y);
147 else
148 slide_window(win, from_x, from_y, to_x, to_y);
149 #else
150 XMoveWindow(dpy, win, to_x, to_y);
152 /* Tell the compiler it is normal that those parameters are not used in this case */
153 (void) from_x;
154 (void) from_y;
155 #endif
158 /* wins is an array of Window, sorted from left to right, the first is
159 * going to be moved from (from_x,from_y) to (to_x,to_y) and the
160 * following windows are going to be offset by (ICON_SIZE*i,0) */
161 void slide_windows(Window wins[], int n, int from_x, int from_y, int to_x, int to_y)
163 time_t time0 = time(NULL);
164 float dx, dy, x = from_x, y = from_y, px, py;
165 Bool is_dx_nul, is_dy_nul;
166 int dx_is_bigger = 0, dx_int, dy_int;
167 int slide_delay, slide_steps, slide_slowdown;
168 int i;
170 /* animation parameters */
171 static const struct {
172 int delay;
173 int steps;
174 int slowdown;
175 } apars[5] = {
176 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
177 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
178 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
179 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
180 {ICON_SLIDE_DELAY_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}
183 slide_slowdown = apars[(int)wPreferences.icon_slide_speed].slowdown;
184 slide_steps = apars[(int)wPreferences.icon_slide_speed].steps;
185 slide_delay = apars[(int)wPreferences.icon_slide_speed].delay;
187 dx_int = to_x - from_x;
188 dy_int = to_y - from_y;
189 is_dx_nul = (dx_int == 0);
190 is_dy_nul = (dy_int == 0);
191 dx = (float) dx_int;
192 dy = (float) dy_int;
194 if (abs(dx_int) > abs(dy_int)) {
195 dx_is_bigger = 1;
198 if (dx_is_bigger) {
199 px = dx / slide_slowdown;
200 if (px < slide_steps && px > 0)
201 px = slide_steps;
202 else if (px > -slide_steps && px < 0)
203 px = -slide_steps;
204 py = (is_dx_nul ? 0.0F : px * dy / dx);
205 } else {
206 py = dy / slide_slowdown;
207 if (py < slide_steps && py > 0)
208 py = slide_steps;
209 else if (py > -slide_steps && py < 0)
210 py = -slide_steps;
211 px = (is_dy_nul ? 0.0F : py * dx / dy);
214 while (((int)x) != to_x ||
215 ((int)y) != to_y) {
216 x += px;
217 y += py;
218 if ((px < 0 && (int)x < to_x) || (px > 0 && (int)x > to_x))
219 x = (float)to_x;
220 if ((py < 0 && (int)y < to_y) || (py > 0 && (int)y > to_y))
221 y = (float)to_y;
223 if (dx_is_bigger) {
224 px = px * (1.0F - 1 / (float)slide_slowdown);
225 if (px < slide_steps && px > 0)
226 px = slide_steps;
227 else if (px > -slide_steps && px < 0)
228 px = -slide_steps;
229 py = (is_dx_nul ? 0.0F : px * dy / dx);
230 } else {
231 py = py * (1.0F - 1 / (float)slide_slowdown);
232 if (py < slide_steps && py > 0)
233 py = slide_steps;
234 else if (py > -slide_steps && py < 0)
235 py = -slide_steps;
236 px = (is_dy_nul ? 0.0F : py * dx / dy);
239 for (i = 0; i < n; i++) {
240 XMoveWindow(dpy, wins[i], (int)x + i * ICON_SIZE, (int)y);
242 XFlush(dpy);
243 if (slide_delay > 0) {
244 wusleep(slide_delay * 1000L);
245 } else {
246 wusleep(1000L);
248 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
249 break;
251 for (i = 0; i < n; i++) {
252 XMoveWindow(dpy, wins[i], to_x + i * ICON_SIZE, to_y);
255 XSync(dpy, 0);
256 /* compress expose events */
257 eatExpose();
260 char *ShrinkString(WMFont *font, const char *string, int width)
262 int w, w1 = 0;
263 int p;
264 char *pos;
265 char *text;
266 int p1, p2, t;
268 p = strlen(string);
269 w = WMWidthOfString(font, string, p);
270 text = wmalloc(strlen(string) + 8);
271 strcpy(text, string);
272 if (w <= width)
273 return text;
275 pos = strchr(text, ' ');
276 if (!pos)
277 pos = strchr(text, ':');
279 if (pos) {
280 *pos = 0;
281 p = strlen(text);
282 w1 = WMWidthOfString(font, text, p);
283 if (w1 > width) {
284 p = 0;
285 *pos = ' ';
286 *text = 0;
287 } else {
288 *pos = 0;
289 width -= w1;
290 p++;
292 string += p;
293 p = strlen(string);
294 } else {
295 *text = 0;
297 strcat(text, "...");
298 width -= WMWidthOfString(font, "...", 3);
300 p1 = 0;
301 p2 = p;
302 t = (p2 - p1) / 2;
303 while (p2 > p1 && p1 != t) {
304 w = WMWidthOfString(font, &string[p - t], t);
305 if (w > width) {
306 p2 = t;
307 t = p1 + (p2 - p1) / 2;
308 } else if (w < width) {
309 p1 = t;
310 t = p1 + (p2 - p1) / 2;
311 } else
312 p2 = p1 = t;
314 strcat(text, &string[p - p1]);
316 return text;
319 char *FindImage(const char *paths, const char *file)
321 char *tmp, *path = NULL;
323 tmp = strrchr(file, ':');
324 if (tmp) {
325 *tmp = 0;
326 path = wfindfile(paths, file);
327 *tmp = ':';
329 if (!tmp || !path)
330 path = wfindfile(paths, file);
332 return path;
335 static void timeoutHandler(void *data)
337 *(int *)data = 1;
340 static char *getTextSelection(WScreen * screen, Atom selection)
342 int buffer = -1;
344 switch (selection) {
345 case XA_CUT_BUFFER0:
346 buffer = 0;
347 break;
348 case XA_CUT_BUFFER1:
349 buffer = 1;
350 break;
351 case XA_CUT_BUFFER2:
352 buffer = 2;
353 break;
354 case XA_CUT_BUFFER3:
355 buffer = 3;
356 break;
357 case XA_CUT_BUFFER4:
358 buffer = 4;
359 break;
360 case XA_CUT_BUFFER5:
361 buffer = 5;
362 break;
363 case XA_CUT_BUFFER6:
364 buffer = 6;
365 break;
366 case XA_CUT_BUFFER7:
367 buffer = 7;
368 break;
370 if (buffer >= 0) {
371 char *data;
372 int size;
374 data = XFetchBuffer(dpy, &size, buffer);
376 return data;
377 } else {
378 char *data;
379 int bits;
380 Atom rtype;
381 unsigned long len, bytes;
382 WMHandlerID timer;
383 int timeout = 0;
384 XEvent ev;
385 static Atom clipboard = 0;
387 if (!clipboard)
388 clipboard = XInternAtom(dpy, "CLIPBOARD", False);
390 XDeleteProperty(dpy, screen->info_window, clipboard);
392 XConvertSelection(dpy, selection, XA_STRING, clipboard, screen->info_window, CurrentTime);
394 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
396 while (!XCheckTypedWindowEvent(dpy, screen->info_window, SelectionNotify, &ev) && !timeout) ;
398 if (!timeout) {
399 WMDeleteTimerHandler(timer);
400 } else {
401 wwarning("selection retrieval timed out");
402 return NULL;
405 /* nobody owns the selection or the current owner has
406 * nothing to do with what we need */
407 if (ev.xselection.property == None) {
408 return NULL;
411 if (XGetWindowProperty(dpy, screen->info_window,
412 clipboard, 0, 1024,
413 False, XA_STRING, &rtype, &bits, &len,
414 &bytes, (unsigned char **)&data) != Success) {
415 return NULL;
417 if (rtype != XA_STRING || bits != 8) {
418 wwarning("invalid data in text selection");
419 if (data)
420 XFree(data);
421 return NULL;
423 return data;
427 static char *getselection(WScreen * scr)
429 char *tmp;
431 tmp = getTextSelection(scr, XA_PRIMARY);
432 if (!tmp)
433 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
434 return tmp;
437 static char*
438 parseuserinputpart(const char *line, int *ptr, const char *endchars)
440 int depth = 0, begin;
441 char *value = NULL;
442 begin = ++*ptr;
444 while(line[*ptr] != '\0') {
445 if(line[*ptr] == '(') {
446 ++depth;
447 } else if(depth > 0 && line[*ptr] == ')') {
448 --depth;
449 } else if(depth == 0 && strchr(endchars, line[*ptr]) != NULL) {
450 value = wmalloc(*ptr - begin + 1);
451 strncpy(value, line + begin, *ptr - begin);
452 value[*ptr - begin] = '\0';
453 break;
455 ++*ptr;
458 return value;
461 static char*
462 getuserinput(WScreen *scr, const char *line, int *ptr, Bool advanced)
464 char *ret = NULL, *title = NULL, *prompt = NULL, *name = NULL;
465 int rv;
467 if(line[*ptr] == '(')
468 title = parseuserinputpart(line, ptr, ",)");
469 if(title != NULL && line[*ptr] == ',')
470 prompt = parseuserinputpart(line, ptr, ",)");
471 if(prompt != NULL && line[*ptr] == ',')
472 name = parseuserinputpart(line, ptr, ")");
474 if(advanced)
475 rv = wAdvancedInputDialog(scr,
476 title ? _(title):_("Program Arguments"),
477 prompt ? _(prompt):_("Enter command arguments:"),
478 name, &ret);
479 else
480 rv = wInputDialog(scr,
481 title ? _(title):_("Program Arguments"),
482 prompt ? _(prompt):_("Enter command arguments:"),
483 &ret);
485 if(title) wfree(title);
486 if(prompt) wfree(prompt);
487 if(name) wfree(name);
489 return rv ? ret : NULL;
492 #define S_NORMAL 0
493 #define S_ESCAPE 1
494 #define S_OPTION 2
497 * state input new-state output
498 * NORMAL % OPTION <nil>
499 * NORMAL \ ESCAPE <nil>
500 * NORMAL etc. NORMAL <input>
501 * ESCAPE any NORMAL <input>
502 * OPTION s NORMAL <selection buffer>
503 * OPTION w NORMAL <selected window id>
504 * OPTION a NORMAL <input text>
505 * OPTION d NORMAL <OffiX DND selection object>
506 * OPTION W NORMAL <current workspace>
507 * OPTION etc. NORMAL %<input>
509 #define TMPBUFSIZE 64
510 char *ExpandOptions(WScreen *scr, const char *cmdline)
512 int ptr, optr, state, len, olen;
513 char *out, *nout;
514 char *selection = NULL;
515 char *user_input = NULL;
516 char tmpbuf[TMPBUFSIZE];
517 int slen;
519 len = strlen(cmdline);
520 olen = len + 1;
521 out = malloc(olen);
522 if (!out) {
523 wwarning(_("out of memory during expansion of \"%s\""), cmdline);
524 return NULL;
526 *out = 0;
527 ptr = 0; /* input line pointer */
528 optr = 0; /* output line pointer */
529 state = S_NORMAL;
530 while (ptr < len) {
531 switch (state) {
532 case S_NORMAL:
533 switch (cmdline[ptr]) {
534 case '\\':
535 state = S_ESCAPE;
536 break;
537 case '%':
538 state = S_OPTION;
539 break;
540 default:
541 state = S_NORMAL;
542 out[optr++] = cmdline[ptr];
543 break;
545 break;
546 case S_ESCAPE:
547 switch (cmdline[ptr]) {
548 case 'n':
549 out[optr++] = 10;
550 break;
552 case 'r':
553 out[optr++] = 13;
554 break;
556 case 't':
557 out[optr++] = 9;
558 break;
560 default:
561 out[optr++] = cmdline[ptr];
563 state = S_NORMAL;
564 break;
565 case S_OPTION:
566 state = S_NORMAL;
567 switch (cmdline[ptr]) {
568 case 'w':
569 if (scr->focused_window && scr->focused_window->flags.focused) {
570 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
571 (unsigned int)scr->focused_window->client_win);
572 slen = strlen(tmpbuf);
573 olen += slen;
574 nout = realloc(out, olen);
575 if (!nout) {
576 wwarning(_("out of memory during expansion of '%s' for command \"%s\""), "%w", cmdline);
577 goto error;
579 out = nout;
580 strcat(out, tmpbuf);
581 optr += slen;
582 } else {
583 out[optr++] = ' ';
585 break;
587 case 'W':
588 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", (unsigned int)scr->current_workspace + 1);
589 slen = strlen(tmpbuf);
590 olen += slen;
591 nout = realloc(out, olen);
592 if (!nout) {
593 wwarning(_("out of memory during expansion of '%s' for command \"%s\""), "%W", cmdline);
594 goto error;
596 out = nout;
597 strcat(out, tmpbuf);
598 optr += slen;
599 break;
601 case 'a':
602 case 'A':
603 ptr++;
604 user_input = getuserinput(scr, cmdline, &ptr, cmdline[ptr-1] == 'A');
605 if (user_input) {
606 slen = strlen(user_input);
607 olen += slen;
608 nout = realloc(out, olen);
609 if (!nout) {
610 wwarning(_("out of memory during expansion of '%s' for command \"%s\""), "%a", cmdline);
611 goto error;
613 out = nout;
614 strcat(out, user_input);
615 optr += slen;
616 } else {
617 /* Not an error, but user has Canceled the dialog box.
618 * This will make the command to not be performed. */
619 goto error;
621 break;
623 #ifdef USE_DOCK_XDND
624 case 'd':
625 if (!scr->xdestring) {
626 scr->flags.dnd_data_convertion_status = 1;
627 goto error;
629 slen = strlen(scr->xdestring);
630 olen += slen;
631 nout = realloc(out, olen);
632 if (!nout) {
633 wwarning(_("out of memory during expansion of '%s' for command \"%s\""), "%d", cmdline);
634 goto error;
636 out = nout;
637 strcat(out, scr->xdestring);
638 optr += slen;
639 break;
640 #endif /* USE_DOCK_XDND */
642 case 's':
643 if (!selection) {
644 selection = getselection(scr);
646 if (!selection) {
647 wwarning(_("selection not available"));
648 goto error;
650 slen = strlen(selection);
651 olen += slen;
652 nout = realloc(out, olen);
653 if (!nout) {
654 wwarning(_("out of memory during expansion of '%s' for command \"%s\""), "%s", cmdline);
655 goto error;
657 out = nout;
658 strcat(out, selection);
659 optr += slen;
660 break;
662 default:
663 out[optr++] = '%';
664 out[optr++] = cmdline[ptr];
666 break;
668 out[optr] = 0;
669 ptr++;
671 if (selection)
672 XFree(selection);
673 return out;
675 error:
676 wfree(out);
677 if (selection)
678 XFree(selection);
679 return NULL;
682 void ParseWindowName(WMPropList *value, char **winstance, char **wclass, const char *where)
684 char *name;
686 *winstance = *wclass = NULL;
688 if (!WMIsPLString(value)) {
689 wwarning(_("bad window name value in %s state info"), where);
690 return;
693 name = WMGetFromPLString(value);
694 if (!name || strlen(name) == 0) {
695 wwarning(_("bad window name value in %s state info"), where);
696 return;
699 UnescapeWM_CLASS(name, winstance, wclass);
702 #if 0
703 static char *keysymToString(KeySym keysym, unsigned int state)
705 XKeyEvent kev;
706 char *buf = wmalloc(20);
707 int count;
709 kev.display = dpy;
710 kev.type = KeyPress;
711 kev.send_event = False;
712 kev.window = DefaultRootWindow(dpy);
713 kev.root = DefaultRootWindow(dpy);
714 kev.same_screen = True;
715 kev.subwindow = kev.root;
716 kev.serial = 0x12344321;
717 kev.time = CurrentTime;
718 kev.state = state;
719 kev.keycode = XKeysymToKeycode(dpy, keysym);
720 count = XLookupString(&kev, buf, 19, NULL, NULL);
721 buf[count] = 0;
723 return buf;
725 #endif
727 char *GetShortcutString(const char *shortcut)
729 char *buffer = NULL;
730 char *k, *tmp, *text;
732 tmp = text = wstrdup(shortcut);
734 /* get modifiers */
735 while ((k = strchr(text, '+')) != NULL) {
736 int mod;
737 const char *lbl;
739 *k = 0;
740 mod = wXModifierFromKey(text);
741 if (mod < 0) {
742 return wstrdup("bug");
744 lbl = wXModifierToShortcutLabel(mod);
745 if (lbl)
746 buffer = wstrappend(buffer, lbl);
747 else
748 buffer = wstrappend(buffer, text);
749 text = k + 1;
752 buffer = wstrappend(buffer, text);
753 wfree(tmp);
755 return buffer;
758 char *GetShortcutKey(WShortKey key)
760 const char *key_name;
761 char buffer[256];
762 char *wr;
764 void append_string(const char *text)
766 const char *string = text;
768 while (*string) {
769 if (wr >= buffer + sizeof(buffer) - 1)
770 break;
771 *wr++ = *string++;
775 void append_modifier(int modifier_index, const char *fallback_name)
777 if (wPreferences.modifier_labels[modifier_index]) {
778 append_string(wPreferences.modifier_labels[modifier_index]);
779 } else {
780 append_string(fallback_name);
784 key_name = XKeysymToString(XkbKeycodeToKeysym(dpy, key.keycode, 0, 0));
785 if (!key_name)
786 return NULL;
788 wr = buffer;
789 if (key.modifier & ControlMask) append_modifier(1, "Control+");
790 if (key.modifier & ShiftMask) append_modifier(0, "Shift+");
791 if (key.modifier & Mod1Mask) append_modifier(2, "Mod1+");
792 if (key.modifier & Mod2Mask) append_modifier(3, "Mod2+");
793 if (key.modifier & Mod3Mask) append_modifier(4, "Mod3+");
794 if (key.modifier & Mod4Mask) append_modifier(5, "Mod4+");
795 if (key.modifier & Mod5Mask) append_modifier(6, "Mod5+");
796 append_string(key_name);
797 *wr = '\0';
799 return GetShortcutString(buffer);
802 char *EscapeWM_CLASS(const char *name, const char *class)
804 char *ret;
805 char *ename = NULL, *eclass = NULL;
806 int i, j, l;
808 if (!name && !class)
809 return NULL;
811 if (name) {
812 l = strlen(name);
813 ename = wmalloc(l * 2 + 1);
814 j = 0;
815 for (i = 0; i < l; i++) {
816 if (name[i] == '\\') {
817 ename[j++] = '\\';
818 } else if (name[i] == '.') {
819 ename[j++] = '\\';
821 ename[j++] = name[i];
823 ename[j] = 0;
825 if (class) {
826 l = strlen(class);
827 eclass = wmalloc(l * 2 + 1);
828 j = 0;
829 for (i = 0; i < l; i++) {
830 if (class[i] == '\\') {
831 eclass[j++] = '\\';
832 } else if (class[i] == '.') {
833 eclass[j++] = '\\';
835 eclass[j++] = class[i];
837 eclass[j] = 0;
840 if (ename && eclass) {
841 int len = strlen(ename) + strlen(eclass) + 4;
842 ret = wmalloc(len);
843 snprintf(ret, len, "%s.%s", ename, eclass);
844 wfree(ename);
845 wfree(eclass);
846 } else if (ename) {
847 ret = wstrdup(ename);
848 wfree(ename);
849 } else {
850 ret = wstrdup(eclass);
851 wfree(eclass);
854 return ret;
857 static void UnescapeWM_CLASS(const char *str, char **name, char **class)
859 int i, j, k, dot;
860 int length_of_name;
862 j = strlen(str);
864 /* separate string in 2 parts */
865 length_of_name = 0;
866 dot = -1;
867 for (i = 0; i < j; i++, length_of_name++) {
868 if (str[i] == '\\') {
869 i++;
870 continue;
871 } else if (str[i] == '.') {
872 dot = i;
873 break;
877 /* unescape the name */
878 if (length_of_name > 0) {
879 *name = wmalloc(length_of_name + 1);
880 for (i = 0, k = 0; i < dot; i++) {
881 if (str[i] != '\\')
882 (*name)[k++] = str[i];
884 (*name)[k] = '\0';
885 } else {
886 *name = NULL;
889 /* unescape the class */
890 if (dot < j-1) {
891 *class = wmalloc(j - (dot + 1) + 1);
892 for (i = dot + 1, k = 0; i < j; i++) {
893 if (str[i] != '\\')
894 (*class)[k++] = str[i];
896 (*class)[k] = 0;
897 } else {
898 *class = NULL;
902 static void track_bg_helper_death(pid_t pid, unsigned int status, void *client_data)
904 WScreen *scr = (WScreen *) client_data;
906 /* Parameter not used, but tell the compiler that it is ok */
907 (void) pid;
908 (void) status;
910 close(scr->helper_fd);
911 scr->helper_fd = 0;
912 scr->helper_pid = 0;
913 scr->flags.backimage_helper_launched = 0;
916 Bool start_bg_helper(WScreen *scr)
918 pid_t pid;
919 int filedes[2];
921 if (pipe(filedes) < 0) {
922 werror(_("%s failed, can't set workspace specific background image (%s)"),
923 "pipe()", strerror(errno));
924 return False;
927 pid = fork();
928 if (pid < 0) {
929 werror(_("%s failed, can't set workspace specific background image (%s)"),
930 "fork()", strerror(errno));
931 close(filedes[0]);
932 close(filedes[1]);
933 return False;
935 } else if (pid == 0) {
936 const char *dither;
938 /* We don't need this side of the pipe in the child process */
939 close(filedes[1]);
941 SetupEnvironment(scr);
943 close(STDIN_FILENO);
944 if (dup2(filedes[0], STDIN_FILENO) < 0) {
945 werror(_("%s failed, can't set workspace specific background image (%s)"),
946 "dup2()", strerror(errno));
947 exit(1);
949 close(filedes[0]);
951 dither = wPreferences.no_dithering ? "-m" : "-d";
952 if (wPreferences.smooth_workspace_back)
953 execlp("wmsetbg", "wmsetbg", "-helper", "-S", dither, NULL);
954 else
955 execlp("wmsetbg", "wmsetbg", "-helper", dither, NULL);
957 werror(_("could not execute \"%s\": %s"), "wmsetbg", strerror(errno));
958 exit(1);
960 } else {
961 /* We don't need this side of the pipe in the parent process */
962 close(filedes[0]);
964 if (fcntl(filedes[1], F_SETFD, FD_CLOEXEC) < 0)
965 wwarning(_("could not set close-on-exec flag for bg_helper's communication file handle (%s)"),
966 strerror(errno));
968 scr->helper_fd = filedes[1];
969 scr->helper_pid = pid;
970 scr->flags.backimage_helper_launched = 1;
972 wAddDeathHandler(pid, track_bg_helper_death, scr);
974 return True;
978 void SendHelperMessage(WScreen *scr, char type, int workspace, const char *msg)
980 char *buffer;
981 int len;
982 int i;
983 char buf[16];
985 if (!scr->flags.backimage_helper_launched) {
986 return;
989 len = (msg ? strlen(msg) : 0) + (workspace >= 0 ? 4 : 0) + 1;
990 buffer = wmalloc(len + 5);
991 snprintf(buf, sizeof(buf), "%4i", len);
992 memcpy(buffer, buf, 4);
993 buffer[4] = type;
994 i = 5;
995 if (workspace >= 0) {
996 snprintf(buf, sizeof(buf), "%4i", workspace);
997 memcpy(&buffer[i], buf, 4);
998 i += 4;
999 buffer[i] = 0;
1001 if (msg)
1002 strcpy(&buffer[i], msg);
1004 if (write(scr->helper_fd, buffer, len + 4) < 0) {
1005 werror(_("could not send message to background image helper"));
1007 wfree(buffer);
1010 Bool UpdateDomainFile(WDDomain * domain)
1012 struct stat stbuf;
1013 char path[PATH_MAX];
1014 WMPropList *shared_dict, *dict;
1015 Bool result, freeDict = False;
1017 dict = domain->dictionary;
1018 if (WMIsPLDictionary(domain->dictionary)) {
1019 /* retrieve global system dictionary */
1020 snprintf(path, sizeof(path), "%s/WindowMaker/%s", SYSCONFDIR, domain->domain_name);
1021 if (stat(path, &stbuf) >= 0) {
1022 shared_dict = WMReadPropListFromFile(path);
1023 if (shared_dict) {
1024 if (WMIsPLDictionary(shared_dict)) {
1025 freeDict = True;
1026 dict = WMDeepCopyPropList(domain->dictionary);
1027 WMSubtractPLDictionaries(dict, shared_dict, True);
1029 WMReleasePropList(shared_dict);
1034 result = WMWritePropListToFile(dict, domain->path);
1036 if (freeDict) {
1037 WMReleasePropList(dict);
1040 return result;
1043 char *StrConcatDot(const char *a, const char *b)
1045 int len;
1046 char *str;
1048 if (!a)
1049 a = "";
1050 if (!b)
1051 b = "";
1053 len = strlen(a) + strlen(b) + 4;
1054 str = wmalloc(len);
1056 snprintf(str, len, "%s.%s", a, b);
1058 return str;
1061 static char *getCommandForWindow(Window win, int elements)
1063 char **argv, *command = NULL;
1064 int argc;
1066 if (XGetCommand(dpy, win, &argv, &argc)) {
1067 if (argc > 0 && argv != NULL) {
1068 if (elements == 0)
1069 elements = argc;
1070 command = wtokenjoin(argv, WMIN(argc, elements));
1071 if (command[0] == 0) {
1072 wfree(command);
1073 command = NULL;
1076 if (argv) {
1077 XFreeStringList(argv);
1081 return command;
1084 /* Free result when done */
1085 char *GetCommandForWindow(Window win)
1087 return getCommandForWindow(win, 0);