c3f55deeda94a2b6a5d657914e9bcde0340eaabd
[wmaker-crm.git] / src / misc.c
blobc3f55deeda94a2b6a5d657914e9bcde0340eaabd
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 "window.h"
42 #include "misc.h"
43 #include "WindowMaker.h"
44 #include "GNUstep.h"
45 #include "screen.h"
46 #include "wcore.h"
47 #include "window.h"
48 #include "framewin.h"
49 #include "dialog.h"
50 #include "xutil.h"
51 #include "xmodifier.h"
53 /**** global variables *****/
54 extern WPreferences wPreferences;
55 #define ICON_SIZE wPreferences.icon_size
57 /**** Local prototypes *****/
58 static void UnescapeWM_CLASS(char *str, char **name, char **class);
60 /* XFetchName Wrapper */
61 Bool wFetchName(Display *dpy, Window win, char **winname)
63 XTextProperty text_prop;
64 char **list;
65 int num;
67 if (XGetWMName(dpy, win, &text_prop)) {
68 if (text_prop.value && text_prop.nitems > 0) {
69 if (text_prop.encoding == XA_STRING) {
70 *winname = wstrdup((char *)text_prop.value);
71 XFree(text_prop.value);
72 } else {
73 text_prop.nitems = strlen((char *)text_prop.value);
74 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
75 Success && num > 0 && *list) {
76 XFree(text_prop.value);
77 *winname = wstrdup(*list);
78 XFreeStringList(list);
79 } else {
80 *winname = wstrdup((char *)text_prop.value);
81 XFree(text_prop.value);
84 } else {
85 /* the title is set, but it was set to none */
86 *winname = wstrdup("");
88 return True;
89 } else {
90 /* the hint is probably not set */
91 *winname = NULL;
93 return False;
97 /* XGetIconName Wrapper */
98 Bool wGetIconName(Display *dpy, Window win, char **iconname)
100 XTextProperty text_prop;
101 char **list;
102 int num;
104 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value && text_prop.nitems > 0) {
105 if (text_prop.encoding == XA_STRING)
106 *iconname = (char *)text_prop.value;
107 else {
108 text_prop.nitems = strlen((char *)text_prop.value);
109 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success && num > 0 && *list) {
110 XFree(text_prop.value);
111 *iconname = wstrdup(*list);
112 XFreeStringList(list);
113 } else
114 *iconname = (char *)text_prop.value;
116 return True;
118 *iconname = NULL;
119 return False;
122 static void eatExpose(void)
124 XEvent event, foo;
126 /* compress all expose events into a single one */
128 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
129 /* ignore other exposure events for this window */
130 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask, &foo)) ;
131 /* eat exposes for other windows */
132 eatExpose();
134 event.xexpose.count = 0;
135 XPutBackEvent(dpy, &event);
139 void move_window(Window win, int from_x, int from_y, int to_x, int to_y)
141 #ifdef ANIMATIONS
142 if (wPreferences.no_animations)
143 XMoveWindow(dpy, win, to_x, to_y);
144 else
145 SlideWindow(win, from_x, from_y, to_x, to_y);
146 #else
147 XMoveWindow(dpy, win, to_x, to_y);
148 #endif
151 void SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
153 Window *wins[1] = { &win };
154 SlideWindows(wins, 1, from_x, from_y, to_x, to_y);
157 /* wins is an array of Window, sorted from left to right, the first is
158 * going to be moved from (from_x,from_y) to (to_x,to_y) and the
159 * following windows are going to be offset by (ICON_SIZE*i,0) */
160 void SlideWindows(Window *wins[], int n, int from_x, int from_y, int to_x, int to_y)
162 time_t time0 = time(NULL);
163 float dx, dy, x = from_x, y = from_y, px, py;
164 Bool is_dx_nul, is_dy_nul;
165 int dx_is_bigger = 0, dx_int, dy_int;
166 int slide_delay, slide_steps, slide_slowdown;
167 int i;
169 /* animation parameters */
170 static struct {
171 int delay;
172 int steps;
173 int slowdown;
174 } apars[5] = {
175 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
176 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
177 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
178 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
179 {ICON_SLIDE_DELAY_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}
182 slide_slowdown = apars[(int)wPreferences.icon_slide_speed].slowdown;
183 slide_steps = apars[(int)wPreferences.icon_slide_speed].steps;
184 slide_delay = apars[(int)wPreferences.icon_slide_speed].delay;
186 dx_int = to_x - from_x;
187 dy_int = to_y - from_y;
188 is_dx_nul = (dx_int == 0);
189 is_dy_nul = (dy_int == 0);
190 dx = (float) dx_int;
191 dy = (float) dy_int;
193 if (fabs(dx) > fabs(dy)) {
194 dx_is_bigger = 1;
197 if (dx_is_bigger) {
198 px = dx / slide_slowdown;
199 if (px < slide_steps && px > 0)
200 px = slide_steps;
201 else if (px > -slide_steps && px < 0)
202 px = -slide_steps;
203 py = (is_dx_nul ? 0.0 : px * dy / dx);
204 } else {
205 py = dy / slide_slowdown;
206 if (py < slide_steps && py > 0)
207 py = slide_steps;
208 else if (py > -slide_steps && py < 0)
209 py = -slide_steps;
210 px = (is_dy_nul ? 0.0 : py * dx / dy);
213 while (((int)x) != to_x ||
214 ((int)y) != to_y) {
215 x += px;
216 y += py;
217 if ((px < 0 && (int)x < to_x) || (px > 0 && (int)x > to_x))
218 x = (float)to_x;
219 if ((py < 0 && (int)y < to_y) || (py > 0 && (int)y > to_y))
220 y = (float)to_y;
222 if (dx_is_bigger) {
223 px = px * (1.0 - 1 / (float)slide_slowdown);
224 if (px < slide_steps && px > 0)
225 px = slide_steps;
226 else if (px > -slide_steps && px < 0)
227 px = -slide_steps;
228 py = (is_dx_nul ? 0.0 : px * dy / dx);
229 } else {
230 py = py * (1.0 - 1 / (float)slide_slowdown);
231 if (py < slide_steps && py > 0)
232 py = slide_steps;
233 else if (py > -slide_steps && py < 0)
234 py = -slide_steps;
235 px = (is_dy_nul ? 0.0 : py * dx / dy);
238 for (i = 0; i < n; i++) {
239 XMoveWindow(dpy, *wins[i], (int)x + i * ICON_SIZE, (int)y);
241 XFlush(dpy);
242 if (slide_delay > 0) {
243 wusleep(slide_delay * 1000L);
244 } else {
245 wusleep(10);
247 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
248 break;
250 for (i = 0; i < n; i++) {
251 XMoveWindow(dpy, *wins[i], to_x + i * ICON_SIZE, to_y);
254 XSync(dpy, 0);
255 /* compress expose events */
256 eatExpose();
259 char *ShrinkString(WMFont *font, const char *string, int width)
261 int w, w1 = 0;
262 int p;
263 char *pos;
264 char *text;
265 int p1, p2, t;
267 p = strlen(string);
268 w = WMWidthOfString(font, string, p);
269 text = wmalloc(strlen(string) + 8);
270 strcpy(text, string);
271 if (w <= width)
272 return text;
274 pos = strchr(text, ' ');
275 if (!pos)
276 pos = strchr(text, ':');
278 if (pos) {
279 *pos = 0;
280 p = strlen(text);
281 w1 = WMWidthOfString(font, text, p);
282 if (w1 > width) {
283 w1 = 0;
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(char *paths, 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(char *line, int *ptr, 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, 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, char *cmdline)
512 int ptr, optr, state, len, olen;
513 char *out, *nout;
514 char *selection = NULL;
515 char *user_input = NULL;
516 #ifdef XDND
517 char *dropped_thing = NULL;
518 #endif
519 char tmpbuf[TMPBUFSIZE];
520 int slen;
522 len = strlen(cmdline);
523 olen = len + 1;
524 out = malloc(olen);
525 if (!out) {
526 wwarning(_("out of memory during expansion of \"%s\""), cmdline);
527 return NULL;
529 *out = 0;
530 ptr = 0; /* input line pointer */
531 optr = 0; /* output line pointer */
532 state = S_NORMAL;
533 while (ptr < len) {
534 switch (state) {
535 case S_NORMAL:
536 switch (cmdline[ptr]) {
537 case '\\':
538 state = S_ESCAPE;
539 break;
540 case '%':
541 state = S_OPTION;
542 break;
543 default:
544 state = S_NORMAL;
545 out[optr++] = cmdline[ptr];
546 break;
548 break;
549 case S_ESCAPE:
550 switch (cmdline[ptr]) {
551 case 'n':
552 out[optr++] = 10;
553 break;
555 case 'r':
556 out[optr++] = 13;
557 break;
559 case 't':
560 out[optr++] = 9;
561 break;
563 default:
564 out[optr++] = cmdline[ptr];
566 state = S_NORMAL;
567 break;
568 case S_OPTION:
569 state = S_NORMAL;
570 switch (cmdline[ptr]) {
571 case 'w':
572 if (scr->focused_window && scr->focused_window->flags.focused) {
573 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
574 (unsigned int)scr->focused_window->client_win);
575 slen = strlen(tmpbuf);
576 olen += slen;
577 nout = realloc(out, olen);
578 if (!nout) {
579 wwarning(_("out of memory during expansion of \"%%w\""));
580 goto error;
582 out = nout;
583 strcat(out, tmpbuf);
584 optr += slen;
585 } else {
586 out[optr++] = ' ';
588 break;
590 case 'W':
591 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", (unsigned int)scr->current_workspace + 1);
592 slen = strlen(tmpbuf);
593 olen += slen;
594 nout = realloc(out, olen);
595 if (!nout) {
596 wwarning(_("out of memory during expansion of \"%%W\""));
597 goto error;
599 out = nout;
600 strcat(out, tmpbuf);
601 optr += slen;
602 break;
604 case 'a':
605 case 'A':
606 ptr++;
607 user_input = getuserinput(scr, cmdline, &ptr, cmdline[ptr-1] == 'A');
608 if (user_input) {
609 slen = strlen(user_input);
610 olen += slen;
611 nout = realloc(out, olen);
612 if (!nout) {
613 wwarning(_("out of memory during expansion of \"%%a\""));
614 goto error;
616 out = nout;
617 strcat(out, user_input);
618 optr += slen;
619 } else {
620 /* Not an error, but user has Canceled the dialog box.
621 * This will make the command to not be performed. */
622 goto error;
624 break;
626 #ifdef XDND
627 case 'd':
628 if (scr->xdestring) {
629 dropped_thing = wstrdup(scr->xdestring);
631 if (!dropped_thing) {
632 dropped_thing = get_dnd_selection(scr);
634 if (!dropped_thing) {
635 scr->flags.dnd_data_convertion_status = 1;
636 goto error;
638 slen = strlen(dropped_thing);
639 olen += slen;
640 nout = realloc(out, olen);
641 if (!nout) {
642 wwarning(_("out of memory during expansion of \"%%d\""));
643 goto error;
645 out = nout;
646 strcat(out, dropped_thing);
647 optr += slen;
648 break;
649 #endif /* XDND */
651 case 's':
652 if (!selection) {
653 selection = getselection(scr);
655 if (!selection) {
656 wwarning(_("selection not available"));
657 goto error;
659 slen = strlen(selection);
660 olen += slen;
661 nout = realloc(out, olen);
662 if (!nout) {
663 wwarning(_("out of memory during expansion of \"%%s\""));
664 goto error;
666 out = nout;
667 strcat(out, selection);
668 optr += slen;
669 break;
671 default:
672 out[optr++] = '%';
673 out[optr++] = cmdline[ptr];
675 break;
677 out[optr] = 0;
678 ptr++;
680 if (selection)
681 XFree(selection);
682 return out;
684 error:
685 wfree(out);
686 if (selection)
687 XFree(selection);
688 return NULL;
691 void ParseWindowName(WMPropList * value, char **winstance, char **wclass, char *where)
693 char *name;
695 *winstance = *wclass = NULL;
697 if (!WMIsPLString(value)) {
698 wwarning(_("bad window name value in %s state info"), where);
699 return;
702 name = WMGetFromPLString(value);
703 if (!name || strlen(name) == 0) {
704 wwarning(_("bad window name value in %s state info"), where);
705 return;
708 UnescapeWM_CLASS(name, winstance, wclass);
711 #if 0
712 static char *keysymToString(KeySym keysym, unsigned int state)
714 XKeyEvent kev;
715 char *buf = wmalloc(20);
716 int count;
718 kev.display = dpy;
719 kev.type = KeyPress;
720 kev.send_event = False;
721 kev.window = DefaultRootWindow(dpy);
722 kev.root = DefaultRootWindow(dpy);
723 kev.same_screen = True;
724 kev.subwindow = kev.root;
725 kev.serial = 0x12344321;
726 kev.time = CurrentTime;
727 kev.state = state;
728 kev.keycode = XKeysymToKeycode(dpy, keysym);
729 count = XLookupString(&kev, buf, 19, NULL, NULL);
730 buf[count] = 0;
732 return buf;
734 #endif
736 char *GetShortcutString(const char *shortcut)
738 char *buffer = NULL;
739 char *k;
740 int modmask = 0;
741 /* KeySym ksym; */
742 int control = 0;
743 char *tmp, *text;
745 tmp = text = wstrdup(shortcut);
747 /* get modifiers */
748 while ((k = strchr(text, '+')) != NULL) {
749 int mod;
751 *k = 0;
752 mod = wXModifierFromKey(text);
753 if (mod < 0) {
754 return wstrdup("bug");
757 modmask |= mod;
759 if (strcasecmp(text, "Meta") == 0) {
760 buffer = wstrappend(buffer, "M+");
761 } else if (strcasecmp(text, "Alt") == 0) {
762 buffer = wstrappend(buffer, "A+");
763 } else if (strcasecmp(text, "Shift") == 0) {
764 buffer = wstrappend(buffer, "Sh+");
765 } else if (strcasecmp(text, "Mod1") == 0) {
766 buffer = wstrappend(buffer, "M1+");
767 } else if (strcasecmp(text, "Mod2") == 0) {
768 buffer = wstrappend(buffer, "M2+");
769 } else if (strcasecmp(text, "Mod3") == 0) {
770 buffer = wstrappend(buffer, "M3+");
771 } else if (strcasecmp(text, "Mod4") == 0) {
772 buffer = wstrappend(buffer, "M4+");
773 } else if (strcasecmp(text, "Mod5") == 0) {
774 buffer = wstrappend(buffer, "M5+");
775 } else if (strcasecmp(text, "Control") == 0) {
776 control = 1;
777 } else {
778 buffer = wstrappend(buffer, text);
780 text = k + 1;
783 if (control) {
784 buffer = wstrappend(buffer, "^");
786 buffer = wstrappend(buffer, text);
788 /* get key */
789 /* ksym = XStringToKeysym(text);
790 tmp = keysymToString(ksym, modmask);
791 puts(tmp);
792 buffer = wstrappend(buffer, tmp);
794 wfree(tmp);
796 return buffer;
799 char *GetShortcutKey(WShortKey key)
801 char *tmp = NULL;
802 char *k = XKeysymToString(XkbKeycodeToKeysym(dpy, key.keycode, 0, 0));
803 if (!k) return NULL;
805 char **m = wPreferences.modifier_labels;
806 if (key.modifier & ControlMask) tmp = wstrappend(tmp, m[1] ? m[1] : "Ctrl+");
807 if (key.modifier & ShiftMask) tmp = wstrappend(tmp, m[0] ? m[0] : "Shift+");
808 if (key.modifier & Mod1Mask) tmp = wstrappend(tmp, m[2] ? m[2] : "Mod1+");
809 if (key.modifier & Mod2Mask) tmp = wstrappend(tmp, m[3] ? m[3] : "Mod2+");
810 if (key.modifier & Mod3Mask) tmp = wstrappend(tmp, m[4] ? m[4] : "Mod3+");
811 if (key.modifier & Mod4Mask) tmp = wstrappend(tmp, m[5] ? m[5] : "Mod4+");
812 if (key.modifier & Mod5Mask) tmp = wstrappend(tmp, m[6] ? m[6] : "Mod5+");
813 tmp = wstrappend(tmp, k);
815 return GetShortcutString(tmp);
818 char *EscapeWM_CLASS(char *name, char *class)
820 char *ret;
821 char *ename = NULL, *eclass = NULL;
822 int i, j, l;
824 if (!name && !class)
825 return NULL;
827 if (name) {
828 l = strlen(name);
829 ename = wmalloc(l * 2 + 1);
830 j = 0;
831 for (i = 0; i < l; i++) {
832 if (name[i] == '\\') {
833 ename[j++] = '\\';
834 } else if (name[i] == '.') {
835 ename[j++] = '\\';
837 ename[j++] = name[i];
839 ename[j] = 0;
841 if (class) {
842 l = strlen(class);
843 eclass = wmalloc(l * 2 + 1);
844 j = 0;
845 for (i = 0; i < l; i++) {
846 if (class[i] == '\\') {
847 eclass[j++] = '\\';
848 } else if (class[i] == '.') {
849 eclass[j++] = '\\';
851 eclass[j++] = class[i];
853 eclass[j] = 0;
856 if (ename && eclass) {
857 int len = strlen(ename) + strlen(eclass) + 4;
858 ret = wmalloc(len);
859 snprintf(ret, len, "%s.%s", ename, eclass);
860 wfree(ename);
861 wfree(eclass);
862 } else if (ename) {
863 ret = wstrdup(ename);
864 wfree(ename);
865 } else {
866 ret = wstrdup(eclass);
867 wfree(eclass);
870 return ret;
873 static void UnescapeWM_CLASS(char *str, char **name, char **class)
875 int i, j, k, dot;
877 j = strlen(str);
878 *name = wmalloc(j);
879 **name = 0;
880 *class = wmalloc(j);
881 **class = 0;
883 /* separate string in 2 parts */
884 dot = -1;
885 for (i = 0; i < j; i++) {
886 if (str[i] == '\\') {
887 i++;
888 continue;
889 } else if (str[i] == '.') {
890 dot = i;
891 break;
895 /* unescape strings */
896 for (i = 0, k = 0; i < dot; i++) {
897 if (str[i] == '\\') {
898 continue;
899 } else {
900 (*name)[k++] = str[i];
903 (*name)[k] = 0;
905 for (i = dot + 1, k = 0; i < j; i++) {
906 if (str[i] == '\\') {
907 continue;
908 } else {
909 (*class)[k++] = str[i];
912 (*class)[k] = 0;
914 if (!*name) {
915 wfree(*name);
916 *name = NULL;
918 if (!*class) {
919 wfree(*class);
920 *class = NULL;
924 void SendHelperMessage(WScreen * scr, char type, int workspace, char *msg)
926 char *buffer;
927 int len;
928 int i;
929 char buf[16];
931 if (!scr->flags.backimage_helper_launched) {
932 return;
935 len = (msg ? strlen(msg) : 0) + (workspace >= 0 ? 4 : 0) + 1;
936 buffer = wmalloc(len + 5);
937 snprintf(buf, sizeof(buf), "%4i", len);
938 memcpy(buffer, buf, 4);
939 buffer[4] = type;
940 i = 5;
941 if (workspace >= 0) {
942 snprintf(buf, sizeof(buf), "%4i", workspace);
943 memcpy(&buffer[i], buf, 4);
944 i += 4;
945 buffer[i] = 0;
947 if (msg)
948 strcpy(&buffer[i], msg);
950 if (write(scr->helper_fd, buffer, len + 4) < 0) {
951 werror(_("could not send message to background image helper"));
953 wfree(buffer);
956 Bool UpdateDomainFile(WDDomain * domain)
958 struct stat stbuf;
959 char path[PATH_MAX];
960 WMPropList *shared_dict, *dict;
961 Bool result, freeDict = False;
963 dict = domain->dictionary;
964 if (WMIsPLDictionary(domain->dictionary)) {
965 /* retrieve global system dictionary */
966 snprintf(path, sizeof(path), "%s/WindowMaker/%s", SYSCONFDIR, domain->domain_name);
967 if (stat(path, &stbuf) >= 0) {
968 shared_dict = WMReadPropListFromFile(path);
969 if (shared_dict) {
970 if (WMIsPLDictionary(shared_dict)) {
971 freeDict = True;
972 dict = WMDeepCopyPropList(domain->dictionary);
973 WMSubtractPLDictionaries(dict, shared_dict, True);
975 WMReleasePropList(shared_dict);
980 result = WMWritePropListToFile(dict, domain->path);
982 if (freeDict) {
983 WMReleasePropList(dict);
986 return result;
989 char *StrConcatDot(char *a, char *b)
991 int len;
992 char *str;
994 if (!a)
995 a = "";
996 if (!b)
997 b = "";
999 len = strlen(a) + strlen(b) + 4;
1000 str = wmalloc(len);
1002 snprintf(str, len, "%s.%s", a, b);
1004 return str;
1007 static char *getCommandForWindow(Window win, int elements)
1009 char **argv, *command = NULL;
1010 int argc;
1012 if (XGetCommand(dpy, win, &argv, &argc)) {
1013 if (argc > 0 && argv != NULL) {
1014 if (elements == 0)
1015 elements = argc;
1016 command = wtokenjoin(argv, WMIN(argc, elements));
1017 if (command[0] == 0) {
1018 wfree(command);
1019 command = NULL;
1022 if (argv) {
1023 XFreeStringList(argv);
1027 return command;
1030 /* Free result when done */
1031 char *GetCommandForWindow(Window win)
1033 return getCommandForWindow(win, 0);