Merge branch 'wmdrawer' into next
[wmaker-crm.git] / src / misc.c
blob32d5659d60764e7208b0e03507b5d5d542cb0b42
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 <stdarg.h>
32 #include <pwd.h>
33 #include <math.h>
34 #include <time.h>
36 #include <X11/XKBlib.h>
38 #include <WINGs/WUtil.h>
39 #include <wraster.h>
41 #include "WindowMaker.h"
42 #include "GNUstep.h"
43 #include "screen.h"
44 #include "wcore.h"
45 #include "window.h"
46 #include "framewin.h"
47 #include "funcs.h"
48 #include "dialog.h"
49 #include "xutil.h"
50 #include "xmodifier.h"
52 /**** global variables *****/
53 extern WPreferences wPreferences;
54 #define ICON_SIZE wPreferences.icon_size
56 /* XFetchName Wrapper */
57 Bool wFetchName(Display *dpy, Window win, char **winname)
59 XTextProperty text_prop;
60 char **list;
61 int num;
63 if (XGetWMName(dpy, win, &text_prop)) {
64 if (text_prop.value && text_prop.nitems > 0) {
65 if (text_prop.encoding == XA_STRING) {
66 *winname = wstrdup((char *)text_prop.value);
67 XFree(text_prop.value);
68 } else {
69 text_prop.nitems = strlen((char *)text_prop.value);
70 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
71 Success && num > 0 && *list) {
72 XFree(text_prop.value);
73 *winname = wstrdup(*list);
74 XFreeStringList(list);
75 } else {
76 *winname = wstrdup((char *)text_prop.value);
77 XFree(text_prop.value);
80 } else {
81 /* the title is set, but it was set to none */
82 *winname = wstrdup("");
84 return True;
85 } else {
86 /* the hint is probably not set */
87 *winname = NULL;
89 return False;
93 /* XGetIconName Wrapper */
94 Bool wGetIconName(Display *dpy, Window win, char **iconname)
96 XTextProperty text_prop;
97 char **list;
98 int num;
100 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value && text_prop.nitems > 0) {
101 if (text_prop.encoding == XA_STRING)
102 *iconname = (char *)text_prop.value;
103 else {
104 text_prop.nitems = strlen((char *)text_prop.value);
105 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success && num > 0 && *list) {
106 XFree(text_prop.value);
107 *iconname = wstrdup(*list);
108 XFreeStringList(list);
109 } else
110 *iconname = (char *)text_prop.value;
112 return True;
114 *iconname = NULL;
115 return False;
118 static void eatExpose(void)
120 XEvent event, foo;
122 /* compress all expose events into a single one */
124 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
125 /* ignore other exposure events for this window */
126 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask, &foo)) ;
127 /* eat exposes for other windows */
128 eatExpose();
130 event.xexpose.count = 0;
131 XPutBackEvent(dpy, &event);
135 void move_window(Window win, int from_x, int from_y, int to_x, int to_y)
137 #ifdef ANIMATIONS
138 if (wPreferences.no_animations)
139 XMoveWindow(dpy, win, to_x, to_y);
140 else
141 SlideWindow(win, from_x, from_y, to_x, to_y);
142 #else
143 XMoveWindow(dpy, win, to_x, to_y);
144 #endif
147 void SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
149 Window *wins[1] = { &win };
150 SlideWindows(wins, 1, from_x, from_y, to_x, to_y);
153 /* wins is an array of Window, sorted from left to right, the first is
154 * going to be moved from (from_x,from_y) to (to_x,to_y) and the
155 * following windows are going to be offset by (ICON_SIZE*i,0) */
156 void SlideWindows(Window *wins[], int n, int from_x, int from_y, int to_x, int to_y)
158 time_t time0 = time(NULL);
159 float dx, dy, x = from_x, y = from_y, sx, sy, px, py;
160 int dx_is_bigger = 0;
161 int slide_delay, slide_steps, slide_slowdown;
162 int i;
164 /* animation parameters */
165 static struct {
166 int delay;
167 int steps;
168 int slowdown;
169 } apars[5] = {
170 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
171 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
172 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
173 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
174 {ICON_SLIDE_DELAY_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}
177 slide_slowdown = apars[(int)wPreferences.icon_slide_speed].slowdown;
178 slide_steps = apars[(int)wPreferences.icon_slide_speed].steps;
179 slide_delay = apars[(int)wPreferences.icon_slide_speed].delay;
181 dx = (float)(to_x - from_x);
182 dy = (float)(to_y - from_y);
183 sx = (dx == 0 ? 0 : fabs(dx) / dx);
184 sy = (dy == 0 ? 0 : fabs(dy) / dy);
186 if (fabs(dx) > fabs(dy)) {
187 dx_is_bigger = 1;
190 if (dx_is_bigger) {
191 px = dx / slide_slowdown;
192 if (px < slide_steps && px > 0)
193 px = slide_steps;
194 else if (px > -slide_steps && px < 0)
195 px = -slide_steps;
196 py = (sx == 0 ? 0 : px * dy / dx);
197 } else {
198 py = dy / slide_slowdown;
199 if (py < slide_steps && py > 0)
200 py = slide_steps;
201 else if (py > -slide_steps && py < 0)
202 py = -slide_steps;
203 px = (sy == 0 ? 0 : py * dx / dy);
206 while (x != to_x || y != to_y) {
207 x += px;
208 y += py;
209 if ((px < 0 && (int)x < to_x) || (px > 0 && (int)x > to_x))
210 x = (float)to_x;
211 if ((py < 0 && (int)y < to_y) || (py > 0 && (int)y > to_y))
212 y = (float)to_y;
214 if (dx_is_bigger) {
215 px = px * (1.0 - 1 / (float)slide_slowdown);
216 if (px < slide_steps && px > 0)
217 px = slide_steps;
218 else if (px > -slide_steps && px < 0)
219 px = -slide_steps;
220 py = (sx == 0 ? 0 : px * dy / dx);
221 } else {
222 py = py * (1.0 - 1 / (float)slide_slowdown);
223 if (py < slide_steps && py > 0)
224 py = slide_steps;
225 else if (py > -slide_steps && py < 0)
226 py = -slide_steps;
227 px = (sy == 0 ? 0 : py * dx / dy);
230 for (i = 0; i < n; i++) {
231 XMoveWindow(dpy, *wins[i], (int)x + i * ICON_SIZE, (int)y);
233 XFlush(dpy);
234 if (slide_delay > 0) {
235 wusleep(slide_delay * 1000L);
236 } else {
237 wusleep(10);
239 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
240 break;
242 for (i = 0; i < n; i++) {
243 XMoveWindow(dpy, *wins[i], to_x + i * ICON_SIZE, to_y);
246 XSync(dpy, 0);
247 /* compress expose events */
248 eatExpose();
251 char *ShrinkString(WMFont * font, char *string, int width)
253 int w, w1 = 0;
254 int p;
255 char *pos;
256 char *text;
257 int p1, p2, t;
259 p = strlen(string);
260 w = WMWidthOfString(font, string, p);
261 text = wmalloc(strlen(string) + 8);
262 strcpy(text, string);
263 if (w <= width)
264 return text;
266 pos = strchr(text, ' ');
267 if (!pos)
268 pos = strchr(text, ':');
270 if (pos) {
271 *pos = 0;
272 p = strlen(text);
273 w1 = WMWidthOfString(font, text, p);
274 if (w1 > width) {
275 w1 = 0;
276 p = 0;
277 *pos = ' ';
278 *text = 0;
279 } else {
280 *pos = 0;
281 width -= w1;
282 p++;
284 string += p;
285 p = strlen(string);
286 } else {
287 *text = 0;
289 strcat(text, "...");
290 width -= WMWidthOfString(font, "...", 3);
291 pos = string;
292 p1 = 0;
293 p2 = p;
294 t = (p2 - p1) / 2;
295 while (p2 > p1 && p1 != t) {
296 w = WMWidthOfString(font, &string[p - t], t);
297 if (w > width) {
298 p2 = t;
299 t = p1 + (p2 - p1) / 2;
300 } else if (w < width) {
301 p1 = t;
302 t = p1 + (p2 - p1) / 2;
303 } else
304 p2 = p1 = t;
306 strcat(text, &string[p - p1]);
308 return text;
311 char *FindImage(char *paths, char *file)
313 char *tmp, *path = NULL;
315 tmp = strrchr(file, ':');
316 if (tmp) {
317 *tmp = 0;
318 path = wfindfile(paths, file);
319 *tmp = ':';
321 if (!tmp || !path)
322 path = wfindfile(paths, file);
324 return path;
327 static void timeoutHandler(void *data)
329 *(int *)data = 1;
332 static char *getTextSelection(WScreen * screen, Atom selection)
334 int buffer = -1;
336 switch (selection) {
337 case XA_CUT_BUFFER0:
338 buffer = 0;
339 break;
340 case XA_CUT_BUFFER1:
341 buffer = 1;
342 break;
343 case XA_CUT_BUFFER2:
344 buffer = 2;
345 break;
346 case XA_CUT_BUFFER3:
347 buffer = 3;
348 break;
349 case XA_CUT_BUFFER4:
350 buffer = 4;
351 break;
352 case XA_CUT_BUFFER5:
353 buffer = 5;
354 break;
355 case XA_CUT_BUFFER6:
356 buffer = 6;
357 break;
358 case XA_CUT_BUFFER7:
359 buffer = 7;
360 break;
362 if (buffer >= 0) {
363 char *data;
364 int size;
366 data = XFetchBuffer(dpy, &size, buffer);
368 return data;
369 } else {
370 char *data;
371 int bits;
372 Atom rtype;
373 unsigned long len, bytes;
374 WMHandlerID timer;
375 int timeout = 0;
376 XEvent ev;
377 static Atom clipboard = 0;
379 if (!clipboard)
380 clipboard = XInternAtom(dpy, "CLIPBOARD", False);
382 XDeleteProperty(dpy, screen->info_window, clipboard);
384 XConvertSelection(dpy, selection, XA_STRING, clipboard, screen->info_window, CurrentTime);
386 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
388 while (!XCheckTypedWindowEvent(dpy, screen->info_window, SelectionNotify, &ev) && !timeout) ;
390 if (!timeout) {
391 WMDeleteTimerHandler(timer);
392 } else {
393 wwarning("selection retrieval timed out");
394 return NULL;
397 /* nobody owns the selection or the current owner has
398 * nothing to do with what we need */
399 if (ev.xselection.property == None) {
400 return NULL;
403 if (XGetWindowProperty(dpy, screen->info_window,
404 clipboard, 0, 1024,
405 False, XA_STRING, &rtype, &bits, &len,
406 &bytes, (unsigned char **)&data) != Success) {
407 return NULL;
409 if (rtype != XA_STRING || bits != 8) {
410 wwarning("invalid data in text selection");
411 if (data)
412 XFree(data);
413 return NULL;
415 return data;
419 static char *getselection(WScreen * scr)
421 char *tmp;
423 tmp = getTextSelection(scr, XA_PRIMARY);
424 if (!tmp)
425 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
426 return tmp;
429 static char*
430 parseuserinputpart(char *line, int *ptr, char *endchars)
432 int depth = 0, begin;
433 char *value = NULL;
434 begin = ++*ptr;
436 while(line[*ptr] != '\0') {
437 if(line[*ptr] == '(') {
438 ++depth;
439 } else if(depth > 0 && line[*ptr] == ')') {
440 --depth;
441 } else if(depth == 0 && strchr(endchars, line[*ptr]) != NULL) {
442 value = wmalloc(*ptr - begin + 1);
443 strncpy(value, line + begin, *ptr - begin);
444 value[*ptr - begin] = '\0';
445 break;
447 ++*ptr;
450 return value;
453 static char*
454 getuserinput(WScreen *scr, char *line, int *ptr, Bool advanced)
456 char *ret = NULL, *title = NULL, *prompt = NULL, *name = NULL;
457 int rv;
459 if(line[*ptr] == '(')
460 title = parseuserinputpart(line, ptr, ",)");
461 if(title != NULL && line[*ptr] == ',')
462 prompt = parseuserinputpart(line, ptr, ",)");
463 if(prompt != NULL && line[*ptr] == ',')
464 name = parseuserinputpart(line, ptr, ")");
466 if(advanced)
467 rv = wAdvancedInputDialog(scr,
468 title ? _(title):_("Program Arguments"),
469 prompt ? _(prompt):_("Enter command arguments:"),
470 name, &ret);
471 else
472 rv = wInputDialog(scr,
473 title ? _(title):_("Program Arguments"),
474 prompt ? _(prompt):_("Enter command arguments:"),
475 &ret);
477 if(title) wfree(title);
478 if(prompt) wfree(prompt);
479 if(name) wfree(name);
481 return rv ? ret : NULL;
484 #define S_NORMAL 0
485 #define S_ESCAPE 1
486 #define S_OPTION 2
489 * state input new-state output
490 * NORMAL % OPTION <nil>
491 * NORMAL \ ESCAPE <nil>
492 * NORMAL etc. NORMAL <input>
493 * ESCAPE any NORMAL <input>
494 * OPTION s NORMAL <selection buffer>
495 * OPTION w NORMAL <selected window id>
496 * OPTION a NORMAL <input text>
497 * OPTION d NORMAL <OffiX DND selection object>
498 * OPTION W NORMAL <current workspace>
499 * OPTION etc. NORMAL %<input>
501 #define TMPBUFSIZE 64
502 char *ExpandOptions(WScreen * scr, char *cmdline)
504 int ptr, optr, state, len, olen;
505 char *out, *nout;
506 char *selection = NULL;
507 char *user_input = NULL;
508 #ifdef XDND
509 char *dropped_thing = NULL;
510 #endif
511 char tmpbuf[TMPBUFSIZE];
512 int slen;
514 len = strlen(cmdline);
515 olen = len + 1;
516 out = malloc(olen);
517 if (!out) {
518 wwarning(_("out of memory during expansion of \"%s\""), cmdline);
519 return NULL;
521 *out = 0;
522 ptr = 0; /* input line pointer */
523 optr = 0; /* output line pointer */
524 state = S_NORMAL;
525 while (ptr < len) {
526 switch (state) {
527 case S_NORMAL:
528 switch (cmdline[ptr]) {
529 case '\\':
530 state = S_ESCAPE;
531 break;
532 case '%':
533 state = S_OPTION;
534 break;
535 default:
536 state = S_NORMAL;
537 out[optr++] = cmdline[ptr];
538 break;
540 break;
541 case S_ESCAPE:
542 switch (cmdline[ptr]) {
543 case 'n':
544 out[optr++] = 10;
545 break;
547 case 'r':
548 out[optr++] = 13;
549 break;
551 case 't':
552 out[optr++] = 9;
553 break;
555 default:
556 out[optr++] = cmdline[ptr];
558 state = S_NORMAL;
559 break;
560 case S_OPTION:
561 state = S_NORMAL;
562 switch (cmdline[ptr]) {
563 case 'w':
564 if (scr->focused_window && scr->focused_window->flags.focused) {
565 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
566 (unsigned int)scr->focused_window->client_win);
567 slen = strlen(tmpbuf);
568 olen += slen;
569 nout = realloc(out, olen);
570 if (!nout) {
571 wwarning(_("out of memory during expansion of \"%%w\""));
572 goto error;
574 out = nout;
575 strcat(out, tmpbuf);
576 optr += slen;
577 } else {
578 out[optr++] = ' ';
580 break;
582 case 'W':
583 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", (unsigned int)scr->current_workspace + 1);
584 slen = strlen(tmpbuf);
585 olen += slen;
586 nout = realloc(out, olen);
587 if (!nout) {
588 wwarning(_("out of memory during expansion of \"%%W\""));
589 goto error;
591 out = nout;
592 strcat(out, tmpbuf);
593 optr += slen;
594 break;
596 case 'a':
597 case 'A':
598 ptr++;
599 user_input = getuserinput(scr, cmdline, &ptr, cmdline[ptr-1] == 'A');
600 if (user_input) {
601 slen = strlen(user_input);
602 olen += slen;
603 nout = realloc(out, olen);
604 if (!nout) {
605 wwarning(_("out of memory during expansion of \"%%a\""));
606 goto error;
608 out = nout;
609 strcat(out, user_input);
610 optr += slen;
611 } else {
612 /* Not an error, but user has Canceled the dialog box.
613 * This will make the command to not be performed. */
614 goto error;
616 break;
618 #ifdef XDND
619 case 'd':
620 if (scr->xdestring) {
621 dropped_thing = wstrdup(scr->xdestring);
623 if (!dropped_thing) {
624 dropped_thing = get_dnd_selection(scr);
626 if (!dropped_thing) {
627 scr->flags.dnd_data_convertion_status = 1;
628 goto error;
630 slen = strlen(dropped_thing);
631 olen += slen;
632 nout = realloc(out, olen);
633 if (!nout) {
634 wwarning(_("out of memory during expansion of \"%%d\""));
635 goto error;
637 out = nout;
638 strcat(out, dropped_thing);
639 optr += slen;
640 break;
641 #endif /* XDND */
643 case 's':
644 if (!selection) {
645 selection = getselection(scr);
647 if (!selection) {
648 wwarning(_("selection not available"));
649 goto error;
651 slen = strlen(selection);
652 olen += slen;
653 nout = realloc(out, olen);
654 if (!nout) {
655 wwarning(_("out of memory during expansion of \"%%s\""));
656 goto error;
658 out = nout;
659 strcat(out, selection);
660 optr += slen;
661 break;
663 default:
664 out[optr++] = '%';
665 out[optr++] = cmdline[ptr];
667 break;
669 out[optr] = 0;
670 ptr++;
672 if (selection)
673 XFree(selection);
674 return out;
676 error:
677 wfree(out);
678 if (selection)
679 XFree(selection);
680 return NULL;
683 void ParseWindowName(WMPropList * value, char **winstance, char **wclass, char *where)
685 char *name;
687 *winstance = *wclass = NULL;
689 if (!WMIsPLString(value)) {
690 wwarning(_("bad window name value in %s state info"), where);
691 return;
694 name = WMGetFromPLString(value);
695 if (!name || strlen(name) == 0) {
696 wwarning(_("bad window name value in %s state info"), where);
697 return;
700 UnescapeWM_CLASS(name, winstance, wclass);
703 #if 0
704 static char *keysymToString(KeySym keysym, unsigned int state)
706 XKeyEvent kev;
707 char *buf = wmalloc(20);
708 int count;
710 kev.display = dpy;
711 kev.type = KeyPress;
712 kev.send_event = False;
713 kev.window = DefaultRootWindow(dpy);
714 kev.root = DefaultRootWindow(dpy);
715 kev.same_screen = True;
716 kev.subwindow = kev.root;
717 kev.serial = 0x12344321;
718 kev.time = CurrentTime;
719 kev.state = state;
720 kev.keycode = XKeysymToKeycode(dpy, keysym);
721 count = XLookupString(&kev, buf, 19, NULL, NULL);
722 buf[count] = 0;
724 return buf;
726 #endif
728 char *GetShortcutString(char *text)
730 char *buffer = NULL;
731 char *k;
732 int modmask = 0;
733 /* KeySym ksym; */
734 int control = 0;
735 char *tmp;
737 tmp = text = wstrdup(text);
739 /* get modifiers */
740 while ((k = strchr(text, '+')) != NULL) {
741 int mod;
743 *k = 0;
744 mod = wXModifierFromKey(text);
745 if (mod < 0) {
746 return wstrdup("bug");
749 modmask |= mod;
751 if (strcasecmp(text, "Meta") == 0) {
752 buffer = wstrappend(buffer, "M+");
753 } else if (strcasecmp(text, "Alt") == 0) {
754 buffer = wstrappend(buffer, "A+");
755 } else if (strcasecmp(text, "Shift") == 0) {
756 buffer = wstrappend(buffer, "Sh+");
757 } else if (strcasecmp(text, "Mod1") == 0) {
758 buffer = wstrappend(buffer, "M1+");
759 } else if (strcasecmp(text, "Mod2") == 0) {
760 buffer = wstrappend(buffer, "M2+");
761 } else if (strcasecmp(text, "Mod3") == 0) {
762 buffer = wstrappend(buffer, "M3+");
763 } else if (strcasecmp(text, "Mod4") == 0) {
764 buffer = wstrappend(buffer, "M4+");
765 } else if (strcasecmp(text, "Mod5") == 0) {
766 buffer = wstrappend(buffer, "M5+");
767 } else if (strcasecmp(text, "Control") == 0) {
768 control = 1;
769 } else {
770 buffer = wstrappend(buffer, text);
772 text = k + 1;
775 if (control) {
776 buffer = wstrappend(buffer, "^");
778 buffer = wstrappend(buffer, text);
780 /* get key */
781 /* ksym = XStringToKeysym(text);
782 tmp = keysymToString(ksym, modmask);
783 puts(tmp);
784 buffer = wstrappend(buffer, tmp);
786 wfree(tmp);
788 return buffer;
791 char *GetShortcutKey(WShortKey key)
793 char *tmp = NULL;
794 char *k = XKeysymToString(XkbKeycodeToKeysym(dpy, key.keycode, 0, 0));
795 if (!k) return NULL;
797 char **m = wPreferences.modifier_labels;
798 if (key.modifier & ControlMask) tmp = wstrappend(tmp, m[1] ? m[1] : "Ctrl+");
799 if (key.modifier & ShiftMask) tmp = wstrappend(tmp, m[0] ? m[0] : "Shift+");
800 if (key.modifier & Mod1Mask) tmp = wstrappend(tmp, m[2] ? m[2] : "Mod1+");
801 if (key.modifier & Mod2Mask) tmp = wstrappend(tmp, m[3] ? m[3] : "Mod2+");
802 if (key.modifier & Mod3Mask) tmp = wstrappend(tmp, m[4] ? m[4] : "Mod3+");
803 if (key.modifier & Mod4Mask) tmp = wstrappend(tmp, m[5] ? m[5] : "Mod4+");
804 if (key.modifier & Mod5Mask) tmp = wstrappend(tmp, m[6] ? m[6] : "Mod5+");
805 tmp = wstrappend(tmp, k);
807 return GetShortcutString(tmp);
810 char *EscapeWM_CLASS(char *name, char *class)
812 char *ret;
813 char *ename = NULL, *eclass = NULL;
814 int i, j, l;
816 if (!name && !class)
817 return NULL;
819 if (name) {
820 l = strlen(name);
821 ename = wmalloc(l * 2 + 1);
822 j = 0;
823 for (i = 0; i < l; i++) {
824 if (name[i] == '\\') {
825 ename[j++] = '\\';
826 } else if (name[i] == '.') {
827 ename[j++] = '\\';
829 ename[j++] = name[i];
831 ename[j] = 0;
833 if (class) {
834 l = strlen(class);
835 eclass = wmalloc(l * 2 + 1);
836 j = 0;
837 for (i = 0; i < l; i++) {
838 if (class[i] == '\\') {
839 eclass[j++] = '\\';
840 } else if (class[i] == '.') {
841 eclass[j++] = '\\';
843 eclass[j++] = class[i];
845 eclass[j] = 0;
848 if (ename && eclass) {
849 int len = strlen(ename) + strlen(eclass) + 4;
850 ret = wmalloc(len);
851 snprintf(ret, len, "%s.%s", ename, eclass);
852 wfree(ename);
853 wfree(eclass);
854 } else if (ename) {
855 ret = wstrdup(ename);
856 wfree(ename);
857 } else {
858 ret = wstrdup(eclass);
859 wfree(eclass);
862 return ret;
865 void UnescapeWM_CLASS(char *str, char **name, char **class)
867 int i, j, k, dot;
869 j = strlen(str);
870 *name = wmalloc(j);
871 **name = 0;
872 *class = wmalloc(j);
873 **class = 0;
875 /* separate string in 2 parts */
876 dot = -1;
877 for (i = 0; i < j; i++) {
878 if (str[i] == '\\') {
879 i++;
880 continue;
881 } else if (str[i] == '.') {
882 dot = i;
883 break;
887 /* unescape strings */
888 for (i = 0, k = 0; i < dot; i++) {
889 if (str[i] == '\\') {
890 continue;
891 } else {
892 (*name)[k++] = str[i];
895 (*name)[k] = 0;
897 for (i = dot + 1, k = 0; i < j; i++) {
898 if (str[i] == '\\') {
899 continue;
900 } else {
901 (*class)[k++] = str[i];
904 (*class)[k] = 0;
906 if (!*name) {
907 wfree(*name);
908 *name = NULL;
910 if (!*class) {
911 wfree(*class);
912 *class = NULL;
916 void SendHelperMessage(WScreen * scr, char type, int workspace, char *msg)
918 char *buffer;
919 int len;
920 int i;
921 char buf[16];
923 if (!scr->flags.backimage_helper_launched) {
924 return;
927 len = (msg ? strlen(msg) : 0) + (workspace >= 0 ? 4 : 0) + 1;
928 buffer = wmalloc(len + 5);
929 snprintf(buf, sizeof(buf), "%4i", len);
930 memcpy(buffer, buf, 4);
931 buffer[4] = type;
932 i = 5;
933 if (workspace >= 0) {
934 snprintf(buf, sizeof(buf), "%4i", workspace);
935 memcpy(&buffer[i], buf, 4);
936 i += 4;
937 buffer[i] = 0;
939 if (msg)
940 strcpy(&buffer[i], msg);
942 if (write(scr->helper_fd, buffer, len + 4) < 0) {
943 werror(_("could not send message to background image helper"));
945 wfree(buffer);
948 Bool UpdateDomainFile(WDDomain * domain)
950 struct stat stbuf;
951 char path[PATH_MAX];
952 WMPropList *shared_dict, *dict;
953 Bool result, freeDict = False;
955 dict = domain->dictionary;
956 if (WMIsPLDictionary(domain->dictionary)) {
957 /* retrieve global system dictionary */
958 snprintf(path, sizeof(path), "%s/WindowMaker/%s", SYSCONFDIR, domain->domain_name);
959 if (stat(path, &stbuf) >= 0) {
960 shared_dict = WMReadPropListFromFile(path);
961 if (shared_dict) {
962 if (WMIsPLDictionary(shared_dict)) {
963 freeDict = True;
964 dict = WMDeepCopyPropList(domain->dictionary);
965 WMSubtractPLDictionaries(dict, shared_dict, True);
967 WMReleasePropList(shared_dict);
972 result = WMWritePropListToFile(dict, domain->path);
974 if (freeDict) {
975 WMReleasePropList(dict);
978 return result;
981 char *StrConcatDot(char *a, char *b)
983 int len;
984 char *str;
986 if (!a)
987 a = "";
988 if (!b)
989 b = "";
991 len = strlen(a) + strlen(b) + 4;
992 str = wmalloc(len);
994 snprintf(str, len, "%s.%s", a, b);
996 return str;
999 static char *getCommandForWindow(Window win, int elements)
1001 char **argv, *command = NULL;
1002 int argc;
1004 if (XGetCommand(dpy, win, &argv, &argc)) {
1005 if (argc > 0 && argv != NULL) {
1006 if (elements == 0)
1007 elements = argc;
1008 command = wtokenjoin(argv, WMIN(argc, elements));
1009 if (command[0] == 0) {
1010 wfree(command);
1011 command = NULL;
1014 if (argv) {
1015 XFreeStringList(argv);
1019 return command;
1022 /* Free result when done */
1023 char *GetCommandForWindow(Window win)
1025 return getCommandForWindow(win, 0);