Variable last_workspace moved to workspace object in global namespace
[wmaker-crm.git] / src / misc.c
blob27a6ab26a88dd00d261b59afda94125a151f6d1f
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"
54 #define ICON_SIZE wPreferences.icon_size
56 /**** Local prototypes *****/
57 static void UnescapeWM_CLASS(const char *str, char **name, char **class);
59 /* XFetchName Wrapper */
60 Bool wFetchName(Display *dpy, Window win, char **winname)
62 XTextProperty text_prop;
63 char **list;
64 int num;
66 if (XGetWMName(dpy, win, &text_prop)) {
67 if (text_prop.value && text_prop.nitems > 0) {
68 if (text_prop.encoding == XA_STRING) {
69 *winname = wstrdup((char *)text_prop.value);
70 XFree(text_prop.value);
71 } else {
72 text_prop.nitems = strlen((char *)text_prop.value);
73 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
74 Success && num > 0 && *list) {
75 XFree(text_prop.value);
76 *winname = wstrdup(*list);
77 XFreeStringList(list);
78 } else {
79 *winname = wstrdup((char *)text_prop.value);
80 XFree(text_prop.value);
83 } else {
84 /* the title is set, but it was set to none */
85 *winname = wstrdup("");
87 return True;
88 } else {
89 /* the hint is probably not set */
90 *winname = NULL;
92 return False;
96 /* XGetIconName Wrapper */
97 Bool wGetIconName(Display *dpy, Window win, char **iconname)
99 XTextProperty text_prop;
100 char **list;
101 int num;
103 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value && text_prop.nitems > 0) {
104 if (text_prop.encoding == XA_STRING)
105 *iconname = (char *)text_prop.value;
106 else {
107 text_prop.nitems = strlen((char *)text_prop.value);
108 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success && num > 0 && *list) {
109 XFree(text_prop.value);
110 *iconname = wstrdup(*list);
111 XFreeStringList(list);
112 } else
113 *iconname = (char *)text_prop.value;
115 return True;
117 *iconname = NULL;
118 return False;
121 static void eatExpose(void)
123 XEvent event, foo;
125 /* compress all expose events into a single one */
127 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
128 /* ignore other exposure events for this window */
129 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask, &foo)) ;
130 /* eat exposes for other windows */
131 eatExpose();
133 event.xexpose.count = 0;
134 XPutBackEvent(dpy, &event);
138 void move_window(Window win, int from_x, int from_y, int to_x, int to_y)
140 #ifdef ANIMATIONS
141 if (wPreferences.no_animations)
142 XMoveWindow(dpy, win, to_x, to_y);
143 else
144 SlideWindow(win, from_x, from_y, to_x, to_y);
145 #else
146 XMoveWindow(dpy, win, to_x, to_y);
147 #endif
150 void SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
152 Window *wins[1] = { &win };
153 SlideWindows(wins, 1, from_x, from_y, to_x, to_y);
156 /* wins is an array of Window, sorted from left to right, the first is
157 * going to be moved from (from_x,from_y) to (to_x,to_y) and the
158 * following windows are going to be offset by (ICON_SIZE*i,0) */
159 void SlideWindows(Window *wins[], int n, int from_x, int from_y, int to_x, int to_y)
161 time_t time0 = time(NULL);
162 float dx, dy, x = from_x, y = from_y, px, py;
163 Bool is_dx_nul, is_dy_nul;
164 int dx_is_bigger = 0, dx_int, dy_int;
165 int slide_delay, slide_steps, slide_slowdown;
166 int i;
168 /* animation parameters */
169 static const struct {
170 int delay;
171 int steps;
172 int slowdown;
173 } apars[5] = {
174 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
175 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
176 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
177 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
178 {ICON_SLIDE_DELAY_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}
181 slide_slowdown = apars[(int)wPreferences.icon_slide_speed].slowdown;
182 slide_steps = apars[(int)wPreferences.icon_slide_speed].steps;
183 slide_delay = apars[(int)wPreferences.icon_slide_speed].delay;
185 dx_int = to_x - from_x;
186 dy_int = to_y - from_y;
187 is_dx_nul = (dx_int == 0);
188 is_dy_nul = (dy_int == 0);
189 dx = (float) dx_int;
190 dy = (float) dy_int;
192 if (abs(dx_int) > abs(dy_int)) {
193 dx_is_bigger = 1;
196 if (dx_is_bigger) {
197 px = dx / slide_slowdown;
198 if (px < slide_steps && px > 0)
199 px = slide_steps;
200 else if (px > -slide_steps && px < 0)
201 px = -slide_steps;
202 py = (is_dx_nul ? 0.0 : px * dy / dx);
203 } else {
204 py = dy / slide_slowdown;
205 if (py < slide_steps && py > 0)
206 py = slide_steps;
207 else if (py > -slide_steps && py < 0)
208 py = -slide_steps;
209 px = (is_dy_nul ? 0.0 : py * dx / dy);
212 while (((int)x) != to_x ||
213 ((int)y) != to_y) {
214 x += px;
215 y += py;
216 if ((px < 0 && (int)x < to_x) || (px > 0 && (int)x > to_x))
217 x = (float)to_x;
218 if ((py < 0 && (int)y < to_y) || (py > 0 && (int)y > to_y))
219 y = (float)to_y;
221 if (dx_is_bigger) {
222 px = px * (1.0 - 1 / (float)slide_slowdown);
223 if (px < slide_steps && px > 0)
224 px = slide_steps;
225 else if (px > -slide_steps && px < 0)
226 px = -slide_steps;
227 py = (is_dx_nul ? 0.0 : px * dy / dx);
228 } else {
229 py = py * (1.0 - 1 / (float)slide_slowdown);
230 if (py < slide_steps && py > 0)
231 py = slide_steps;
232 else if (py > -slide_steps && py < 0)
233 py = -slide_steps;
234 px = (is_dy_nul ? 0.0 : py * dx / dy);
237 for (i = 0; i < n; i++) {
238 XMoveWindow(dpy, *wins[i], (int)x + i * ICON_SIZE, (int)y);
240 XFlush(dpy);
241 if (slide_delay > 0) {
242 wusleep(slide_delay * 1000L);
243 } else {
244 wusleep(10);
246 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
247 break;
249 for (i = 0; i < n; i++) {
250 XMoveWindow(dpy, *wins[i], to_x + i * ICON_SIZE, to_y);
253 XSync(dpy, 0);
254 /* compress expose events */
255 eatExpose();
258 char *ShrinkString(WMFont *font, const char *string, int width)
260 int w, w1 = 0;
261 int p;
262 char *pos;
263 char *text;
264 int p1, p2, t;
266 p = strlen(string);
267 w = WMWidthOfString(font, string, p);
268 text = wmalloc(strlen(string) + 8);
269 strcpy(text, string);
270 if (w <= width)
271 return text;
273 pos = strchr(text, ' ');
274 if (!pos)
275 pos = strchr(text, ':');
277 if (pos) {
278 *pos = 0;
279 p = strlen(text);
280 w1 = WMWidthOfString(font, text, p);
281 if (w1 > width) {
282 w1 = 0;
283 p = 0;
284 *pos = ' ';
285 *text = 0;
286 } else {
287 *pos = 0;
288 width -= w1;
289 p++;
291 string += p;
292 p = strlen(string);
293 } else {
294 *text = 0;
296 strcat(text, "...");
297 width -= WMWidthOfString(font, "...", 3);
299 p1 = 0;
300 p2 = p;
301 t = (p2 - p1) / 2;
302 while (p2 > p1 && p1 != t) {
303 w = WMWidthOfString(font, &string[p - t], t);
304 if (w > width) {
305 p2 = t;
306 t = p1 + (p2 - p1) / 2;
307 } else if (w < width) {
308 p1 = t;
309 t = p1 + (p2 - p1) / 2;
310 } else
311 p2 = p1 = t;
313 strcat(text, &string[p - p1]);
315 return text;
318 char *FindImage(const char *paths, const char *file)
320 char *tmp, *path = NULL;
322 tmp = strrchr(file, ':');
323 if (tmp) {
324 *tmp = 0;
325 path = wfindfile(paths, file);
326 *tmp = ':';
328 if (!tmp || !path)
329 path = wfindfile(paths, file);
331 return path;
334 static void timeoutHandler(void *data)
336 *(int *)data = 1;
339 static char *getTextSelection(WScreen * screen, Atom selection)
341 int buffer = -1;
343 switch (selection) {
344 case XA_CUT_BUFFER0:
345 buffer = 0;
346 break;
347 case XA_CUT_BUFFER1:
348 buffer = 1;
349 break;
350 case XA_CUT_BUFFER2:
351 buffer = 2;
352 break;
353 case XA_CUT_BUFFER3:
354 buffer = 3;
355 break;
356 case XA_CUT_BUFFER4:
357 buffer = 4;
358 break;
359 case XA_CUT_BUFFER5:
360 buffer = 5;
361 break;
362 case XA_CUT_BUFFER6:
363 buffer = 6;
364 break;
365 case XA_CUT_BUFFER7:
366 buffer = 7;
367 break;
369 if (buffer >= 0) {
370 char *data;
371 int size;
373 data = XFetchBuffer(dpy, &size, buffer);
375 return data;
376 } else {
377 char *data;
378 int bits;
379 Atom rtype;
380 unsigned long len, bytes;
381 WMHandlerID timer;
382 int timeout = 0;
383 XEvent ev;
384 static Atom clipboard = 0;
386 if (!clipboard)
387 clipboard = XInternAtom(dpy, "CLIPBOARD", False);
389 XDeleteProperty(dpy, screen->info_window, clipboard);
391 XConvertSelection(dpy, selection, XA_STRING, clipboard, screen->info_window, CurrentTime);
393 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
395 while (!XCheckTypedWindowEvent(dpy, screen->info_window, SelectionNotify, &ev) && !timeout) ;
397 if (!timeout) {
398 WMDeleteTimerHandler(timer);
399 } else {
400 wwarning("selection retrieval timed out");
401 return NULL;
404 /* nobody owns the selection or the current owner has
405 * nothing to do with what we need */
406 if (ev.xselection.property == None) {
407 return NULL;
410 if (XGetWindowProperty(dpy, screen->info_window,
411 clipboard, 0, 1024,
412 False, XA_STRING, &rtype, &bits, &len,
413 &bytes, (unsigned char **)&data) != Success) {
414 return NULL;
416 if (rtype != XA_STRING || bits != 8) {
417 wwarning("invalid data in text selection");
418 if (data)
419 XFree(data);
420 return NULL;
422 return data;
426 static char *getselection(WScreen * scr)
428 char *tmp;
430 tmp = getTextSelection(scr, XA_PRIMARY);
431 if (!tmp)
432 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
433 return tmp;
436 static char*
437 parseuserinputpart(const char *line, int *ptr, const char *endchars)
439 int depth = 0, begin;
440 char *value = NULL;
441 begin = ++*ptr;
443 while(line[*ptr] != '\0') {
444 if(line[*ptr] == '(') {
445 ++depth;
446 } else if(depth > 0 && line[*ptr] == ')') {
447 --depth;
448 } else if(depth == 0 && strchr(endchars, line[*ptr]) != NULL) {
449 value = wmalloc(*ptr - begin + 1);
450 strncpy(value, line + begin, *ptr - begin);
451 value[*ptr - begin] = '\0';
452 break;
454 ++*ptr;
457 return value;
460 static char*
461 getuserinput(WScreen *scr, const char *line, int *ptr, Bool advanced)
463 char *ret = NULL, *title = NULL, *prompt = NULL, *name = NULL;
464 int rv;
466 if(line[*ptr] == '(')
467 title = parseuserinputpart(line, ptr, ",)");
468 if(title != NULL && line[*ptr] == ',')
469 prompt = parseuserinputpart(line, ptr, ",)");
470 if(prompt != NULL && line[*ptr] == ',')
471 name = parseuserinputpart(line, ptr, ")");
473 if(advanced)
474 rv = wAdvancedInputDialog(scr,
475 title ? _(title):_("Program Arguments"),
476 prompt ? _(prompt):_("Enter command arguments:"),
477 name, &ret);
478 else
479 rv = wInputDialog(scr,
480 title ? _(title):_("Program Arguments"),
481 prompt ? _(prompt):_("Enter command arguments:"),
482 &ret);
484 if(title) wfree(title);
485 if(prompt) wfree(prompt);
486 if(name) wfree(name);
488 return rv ? ret : NULL;
491 #define S_NORMAL 0
492 #define S_ESCAPE 1
493 #define S_OPTION 2
496 * state input new-state output
497 * NORMAL % OPTION <nil>
498 * NORMAL \ ESCAPE <nil>
499 * NORMAL etc. NORMAL <input>
500 * ESCAPE any NORMAL <input>
501 * OPTION s NORMAL <selection buffer>
502 * OPTION w NORMAL <selected window id>
503 * OPTION a NORMAL <input text>
504 * OPTION d NORMAL <OffiX DND selection object>
505 * OPTION W NORMAL <current workspace>
506 * OPTION etc. NORMAL %<input>
508 #define TMPBUFSIZE 64
509 char *ExpandOptions(WScreen *scr, const char *cmdline)
511 int ptr, optr, state, len, olen;
512 char *out, *nout;
513 char *selection = NULL;
514 char *user_input = NULL;
515 #ifdef XDND
516 char *dropped_thing = NULL;
517 #endif
518 char tmpbuf[TMPBUFSIZE];
519 int slen;
521 len = strlen(cmdline);
522 olen = len + 1;
523 out = malloc(olen);
524 if (!out) {
525 wwarning(_("out of memory during expansion of \"%s\""), cmdline);
526 return NULL;
528 *out = 0;
529 ptr = 0; /* input line pointer */
530 optr = 0; /* output line pointer */
531 state = S_NORMAL;
532 while (ptr < len) {
533 switch (state) {
534 case S_NORMAL:
535 switch (cmdline[ptr]) {
536 case '\\':
537 state = S_ESCAPE;
538 break;
539 case '%':
540 state = S_OPTION;
541 break;
542 default:
543 state = S_NORMAL;
544 out[optr++] = cmdline[ptr];
545 break;
547 break;
548 case S_ESCAPE:
549 switch (cmdline[ptr]) {
550 case 'n':
551 out[optr++] = 10;
552 break;
554 case 'r':
555 out[optr++] = 13;
556 break;
558 case 't':
559 out[optr++] = 9;
560 break;
562 default:
563 out[optr++] = cmdline[ptr];
565 state = S_NORMAL;
566 break;
567 case S_OPTION:
568 state = S_NORMAL;
569 switch (cmdline[ptr]) {
570 case 'w':
571 if (scr->focused_window && scr->focused_window->flags.focused) {
572 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
573 (unsigned int)scr->focused_window->client_win);
574 slen = strlen(tmpbuf);
575 olen += slen;
576 nout = realloc(out, olen);
577 if (!nout) {
578 wwarning(_("out of memory during expansion of \"%%w\""));
579 goto error;
581 out = nout;
582 strcat(out, tmpbuf);
583 optr += slen;
584 } else {
585 out[optr++] = ' ';
587 break;
589 case 'W':
590 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", (unsigned int)scr->current_workspace + 1);
591 slen = strlen(tmpbuf);
592 olen += slen;
593 nout = realloc(out, olen);
594 if (!nout) {
595 wwarning(_("out of memory during expansion of \"%%W\""));
596 goto error;
598 out = nout;
599 strcat(out, tmpbuf);
600 optr += slen;
601 break;
603 case 'a':
604 case 'A':
605 ptr++;
606 user_input = getuserinput(scr, cmdline, &ptr, cmdline[ptr-1] == 'A');
607 if (user_input) {
608 slen = strlen(user_input);
609 olen += slen;
610 nout = realloc(out, olen);
611 if (!nout) {
612 wwarning(_("out of memory during expansion of \"%%a\""));
613 goto error;
615 out = nout;
616 strcat(out, user_input);
617 optr += slen;
618 } else {
619 /* Not an error, but user has Canceled the dialog box.
620 * This will make the command to not be performed. */
621 goto error;
623 break;
625 #ifdef XDND
626 case 'd':
627 if (scr->xdestring) {
628 dropped_thing = wstrdup(scr->xdestring);
630 if (!dropped_thing) {
631 dropped_thing = get_dnd_selection(scr);
633 if (!dropped_thing) {
634 scr->flags.dnd_data_convertion_status = 1;
635 goto error;
637 slen = strlen(dropped_thing);
638 olen += slen;
639 nout = realloc(out, olen);
640 if (!nout) {
641 wwarning(_("out of memory during expansion of \"%%d\""));
642 goto error;
644 out = nout;
645 strcat(out, dropped_thing);
646 optr += slen;
647 break;
648 #endif /* XDND */
650 case 's':
651 if (!selection) {
652 selection = getselection(scr);
654 if (!selection) {
655 wwarning(_("selection not available"));
656 goto error;
658 slen = strlen(selection);
659 olen += slen;
660 nout = realloc(out, olen);
661 if (!nout) {
662 wwarning(_("out of memory during expansion of \"%%s\""));
663 goto error;
665 out = nout;
666 strcat(out, selection);
667 optr += slen;
668 break;
670 default:
671 out[optr++] = '%';
672 out[optr++] = cmdline[ptr];
674 break;
676 out[optr] = 0;
677 ptr++;
679 if (selection)
680 XFree(selection);
681 return out;
683 error:
684 wfree(out);
685 if (selection)
686 XFree(selection);
687 return NULL;
690 void ParseWindowName(WMPropList *value, char **winstance, char **wclass, const char *where)
692 char *name;
694 *winstance = *wclass = NULL;
696 if (!WMIsPLString(value)) {
697 wwarning(_("bad window name value in %s state info"), where);
698 return;
701 name = WMGetFromPLString(value);
702 if (!name || strlen(name) == 0) {
703 wwarning(_("bad window name value in %s state info"), where);
704 return;
707 UnescapeWM_CLASS(name, winstance, wclass);
710 #if 0
711 static char *keysymToString(KeySym keysym, unsigned int state)
713 XKeyEvent kev;
714 char *buf = wmalloc(20);
715 int count;
717 kev.display = dpy;
718 kev.type = KeyPress;
719 kev.send_event = False;
720 kev.window = DefaultRootWindow(dpy);
721 kev.root = DefaultRootWindow(dpy);
722 kev.same_screen = True;
723 kev.subwindow = kev.root;
724 kev.serial = 0x12344321;
725 kev.time = CurrentTime;
726 kev.state = state;
727 kev.keycode = XKeysymToKeycode(dpy, keysym);
728 count = XLookupString(&kev, buf, 19, NULL, NULL);
729 buf[count] = 0;
731 return buf;
733 #endif
735 char *GetShortcutString(const char *shortcut)
737 char *buffer = NULL;
738 char *k;
739 int modmask = 0;
740 /* KeySym ksym; */
741 int control = 0;
742 char *tmp, *text;
744 tmp = text = wstrdup(shortcut);
746 /* get modifiers */
747 while ((k = strchr(text, '+')) != NULL) {
748 int mod;
750 *k = 0;
751 mod = wXModifierFromKey(text);
752 if (mod < 0) {
753 return wstrdup("bug");
756 modmask |= mod;
758 if (strcasecmp(text, "Meta") == 0) {
759 buffer = wstrappend(buffer, "M+");
760 } else if (strcasecmp(text, "Alt") == 0) {
761 buffer = wstrappend(buffer, "A+");
762 } else if (strcasecmp(text, "Shift") == 0) {
763 buffer = wstrappend(buffer, "Sh+");
764 } else if (strcasecmp(text, "Mod1") == 0) {
765 buffer = wstrappend(buffer, "M1+");
766 } else if (strcasecmp(text, "Mod2") == 0) {
767 buffer = wstrappend(buffer, "M2+");
768 } else if (strcasecmp(text, "Mod3") == 0) {
769 buffer = wstrappend(buffer, "M3+");
770 } else if (strcasecmp(text, "Mod4") == 0) {
771 buffer = wstrappend(buffer, "M4+");
772 } else if (strcasecmp(text, "Mod5") == 0) {
773 buffer = wstrappend(buffer, "M5+");
774 } else if (strcasecmp(text, "Control") == 0) {
775 control = 1;
776 } else {
777 buffer = wstrappend(buffer, text);
779 text = k + 1;
782 if (control) {
783 buffer = wstrappend(buffer, "^");
785 buffer = wstrappend(buffer, text);
787 /* get key */
788 /* ksym = XStringToKeysym(text);
789 tmp = keysymToString(ksym, modmask);
790 puts(tmp);
791 buffer = wstrappend(buffer, tmp);
793 wfree(tmp);
795 return buffer;
798 char *GetShortcutKey(WShortKey key)
800 char *tmp = NULL;
801 char *k = XKeysymToString(XkbKeycodeToKeysym(dpy, key.keycode, 0, 0));
802 if (!k) return NULL;
804 char **m = wPreferences.modifier_labels;
805 if (key.modifier & ControlMask) tmp = wstrappend(tmp, m[1] ? m[1] : "Ctrl+");
806 if (key.modifier & ShiftMask) tmp = wstrappend(tmp, m[0] ? m[0] : "Shift+");
807 if (key.modifier & Mod1Mask) tmp = wstrappend(tmp, m[2] ? m[2] : "Mod1+");
808 if (key.modifier & Mod2Mask) tmp = wstrappend(tmp, m[3] ? m[3] : "Mod2+");
809 if (key.modifier & Mod3Mask) tmp = wstrappend(tmp, m[4] ? m[4] : "Mod3+");
810 if (key.modifier & Mod4Mask) tmp = wstrappend(tmp, m[5] ? m[5] : "Mod4+");
811 if (key.modifier & Mod5Mask) tmp = wstrappend(tmp, m[6] ? m[6] : "Mod5+");
812 tmp = wstrappend(tmp, k);
814 return GetShortcutString(tmp);
817 char *EscapeWM_CLASS(const char *name, const char *class)
819 char *ret;
820 char *ename = NULL, *eclass = NULL;
821 int i, j, l;
823 if (!name && !class)
824 return NULL;
826 if (name) {
827 l = strlen(name);
828 ename = wmalloc(l * 2 + 1);
829 j = 0;
830 for (i = 0; i < l; i++) {
831 if (name[i] == '\\') {
832 ename[j++] = '\\';
833 } else if (name[i] == '.') {
834 ename[j++] = '\\';
836 ename[j++] = name[i];
838 ename[j] = 0;
840 if (class) {
841 l = strlen(class);
842 eclass = wmalloc(l * 2 + 1);
843 j = 0;
844 for (i = 0; i < l; i++) {
845 if (class[i] == '\\') {
846 eclass[j++] = '\\';
847 } else if (class[i] == '.') {
848 eclass[j++] = '\\';
850 eclass[j++] = class[i];
852 eclass[j] = 0;
855 if (ename && eclass) {
856 int len = strlen(ename) + strlen(eclass) + 4;
857 ret = wmalloc(len);
858 snprintf(ret, len, "%s.%s", ename, eclass);
859 wfree(ename);
860 wfree(eclass);
861 } else if (ename) {
862 ret = wstrdup(ename);
863 wfree(ename);
864 } else {
865 ret = wstrdup(eclass);
866 wfree(eclass);
869 return ret;
872 static void UnescapeWM_CLASS(const char *str, char **name, char **class)
874 int i, j, k, dot;
876 j = strlen(str);
877 *name = wmalloc(j);
878 **name = 0;
879 *class = wmalloc(j);
880 **class = 0;
882 /* separate string in 2 parts */
883 dot = -1;
884 for (i = 0; i < j; i++) {
885 if (str[i] == '\\') {
886 i++;
887 continue;
888 } else if (str[i] == '.') {
889 dot = i;
890 break;
894 /* unescape strings */
895 for (i = 0, k = 0; i < dot; i++) {
896 if (str[i] == '\\') {
897 continue;
898 } else {
899 (*name)[k++] = str[i];
902 (*name)[k] = 0;
904 for (i = dot + 1, k = 0; i < j; i++) {
905 if (str[i] == '\\') {
906 continue;
907 } else {
908 (*class)[k++] = str[i];
911 (*class)[k] = 0;
913 if (!*name) {
914 wfree(*name);
915 *name = NULL;
917 if (!*class) {
918 wfree(*class);
919 *class = NULL;
923 void SendHelperMessage(WScreen *scr, char type, int workspace, const char *msg)
925 char *buffer;
926 int len;
927 int i;
928 char buf[16];
930 if (!scr->flags.backimage_helper_launched) {
931 return;
934 len = (msg ? strlen(msg) : 0) + (workspace >= 0 ? 4 : 0) + 1;
935 buffer = wmalloc(len + 5);
936 snprintf(buf, sizeof(buf), "%4i", len);
937 memcpy(buffer, buf, 4);
938 buffer[4] = type;
939 i = 5;
940 if (workspace >= 0) {
941 snprintf(buf, sizeof(buf), "%4i", workspace);
942 memcpy(&buffer[i], buf, 4);
943 i += 4;
944 buffer[i] = 0;
946 if (msg)
947 strcpy(&buffer[i], msg);
949 if (write(scr->helper_fd, buffer, len + 4) < 0) {
950 werror(_("could not send message to background image helper"));
952 wfree(buffer);
955 Bool UpdateDomainFile(WDDomain * domain)
957 struct stat stbuf;
958 char path[PATH_MAX];
959 WMPropList *shared_dict, *dict;
960 Bool result, freeDict = False;
962 dict = domain->dictionary;
963 if (WMIsPLDictionary(domain->dictionary)) {
964 /* retrieve global system dictionary */
965 snprintf(path, sizeof(path), "%s/WindowMaker/%s", SYSCONFDIR, domain->domain_name);
966 if (stat(path, &stbuf) >= 0) {
967 shared_dict = WMReadPropListFromFile(path);
968 if (shared_dict) {
969 if (WMIsPLDictionary(shared_dict)) {
970 freeDict = True;
971 dict = WMDeepCopyPropList(domain->dictionary);
972 WMSubtractPLDictionaries(dict, shared_dict, True);
974 WMReleasePropList(shared_dict);
979 result = WMWritePropListToFile(dict, domain->path);
981 if (freeDict) {
982 WMReleasePropList(dict);
985 return result;
988 char *StrConcatDot(const char *a, const char *b)
990 int len;
991 char *str;
993 if (!a)
994 a = "";
995 if (!b)
996 b = "";
998 len = strlen(a) + strlen(b) + 4;
999 str = wmalloc(len);
1001 snprintf(str, len, "%s.%s", a, b);
1003 return str;
1006 static char *getCommandForWindow(Window win, int elements)
1008 char **argv, *command = NULL;
1009 int argc;
1011 if (XGetCommand(dpy, win, &argv, &argc)) {
1012 if (argc > 0 && argv != NULL) {
1013 if (elements == 0)
1014 elements = argc;
1015 command = wtokenjoin(argv, WMIN(argc, elements));
1016 if (command[0] == 0) {
1017 wfree(command);
1018 command = NULL;
1021 if (argv) {
1022 XFreeStringList(argv);
1026 return command;
1029 /* Free result when done */
1030 char *GetCommandForWindow(Window win)
1032 return getCommandForWindow(win, 0);