New file misc.h
[wmaker-crm.git] / src / misc.c
blobef3560834aab8326c21024f31da4fb2f62f1b381
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 "misc.h"
42 #include "WindowMaker.h"
43 #include "GNUstep.h"
44 #include "screen.h"
45 #include "wcore.h"
46 #include "window.h"
47 #include "framewin.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 /**** Local prototypes *****/
57 static void UnescapeWM_CLASS(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, sx, sy, px, py;
163 int dx_is_bigger = 0;
164 int slide_delay, slide_steps, slide_slowdown;
165 int i;
167 /* animation parameters */
168 static struct {
169 int delay;
170 int steps;
171 int slowdown;
172 } apars[5] = {
173 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
174 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
175 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
176 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
177 {ICON_SLIDE_DELAY_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}
180 slide_slowdown = apars[(int)wPreferences.icon_slide_speed].slowdown;
181 slide_steps = apars[(int)wPreferences.icon_slide_speed].steps;
182 slide_delay = apars[(int)wPreferences.icon_slide_speed].delay;
184 dx = (float)(to_x - from_x);
185 dy = (float)(to_y - from_y);
186 sx = (dx == 0 ? 0 : fabs(dx) / dx);
187 sy = (dy == 0 ? 0 : fabs(dy) / dy);
189 if (fabs(dx) > fabs(dy)) {
190 dx_is_bigger = 1;
193 if (dx_is_bigger) {
194 px = dx / slide_slowdown;
195 if (px < slide_steps && px > 0)
196 px = slide_steps;
197 else if (px > -slide_steps && px < 0)
198 px = -slide_steps;
199 py = (sx == 0 ? 0 : px * dy / dx);
200 } else {
201 py = dy / slide_slowdown;
202 if (py < slide_steps && py > 0)
203 py = slide_steps;
204 else if (py > -slide_steps && py < 0)
205 py = -slide_steps;
206 px = (sy == 0 ? 0 : py * dx / dy);
209 while (x != to_x || y != to_y) {
210 x += px;
211 y += py;
212 if ((px < 0 && (int)x < to_x) || (px > 0 && (int)x > to_x))
213 x = (float)to_x;
214 if ((py < 0 && (int)y < to_y) || (py > 0 && (int)y > to_y))
215 y = (float)to_y;
217 if (dx_is_bigger) {
218 px = px * (1.0 - 1 / (float)slide_slowdown);
219 if (px < slide_steps && px > 0)
220 px = slide_steps;
221 else if (px > -slide_steps && px < 0)
222 px = -slide_steps;
223 py = (sx == 0 ? 0 : px * dy / dx);
224 } else {
225 py = py * (1.0 - 1 / (float)slide_slowdown);
226 if (py < slide_steps && py > 0)
227 py = slide_steps;
228 else if (py > -slide_steps && py < 0)
229 py = -slide_steps;
230 px = (sy == 0 ? 0 : py * dx / dy);
233 for (i = 0; i < n; i++) {
234 XMoveWindow(dpy, *wins[i], (int)x + i * ICON_SIZE, (int)y);
236 XFlush(dpy);
237 if (slide_delay > 0) {
238 wusleep(slide_delay * 1000L);
239 } else {
240 wusleep(10);
242 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
243 break;
245 for (i = 0; i < n; i++) {
246 XMoveWindow(dpy, *wins[i], to_x + i * ICON_SIZE, to_y);
249 XSync(dpy, 0);
250 /* compress expose events */
251 eatExpose();
254 char *ShrinkString(WMFont * font, char *string, int width)
256 int w, w1 = 0;
257 int p;
258 char *pos;
259 char *text;
260 int p1, p2, t;
262 p = strlen(string);
263 w = WMWidthOfString(font, string, p);
264 text = wmalloc(strlen(string) + 8);
265 strcpy(text, string);
266 if (w <= width)
267 return text;
269 pos = strchr(text, ' ');
270 if (!pos)
271 pos = strchr(text, ':');
273 if (pos) {
274 *pos = 0;
275 p = strlen(text);
276 w1 = WMWidthOfString(font, text, p);
277 if (w1 > width) {
278 w1 = 0;
279 p = 0;
280 *pos = ' ';
281 *text = 0;
282 } else {
283 *pos = 0;
284 width -= w1;
285 p++;
287 string += p;
288 p = strlen(string);
289 } else {
290 *text = 0;
292 strcat(text, "...");
293 width -= WMWidthOfString(font, "...", 3);
294 pos = string;
295 p1 = 0;
296 p2 = p;
297 t = (p2 - p1) / 2;
298 while (p2 > p1 && p1 != t) {
299 w = WMWidthOfString(font, &string[p - t], t);
300 if (w > width) {
301 p2 = t;
302 t = p1 + (p2 - p1) / 2;
303 } else if (w < width) {
304 p1 = t;
305 t = p1 + (p2 - p1) / 2;
306 } else
307 p2 = p1 = t;
309 strcat(text, &string[p - p1]);
311 return text;
314 char *FindImage(char *paths, char *file)
316 char *tmp, *path = NULL;
318 tmp = strrchr(file, ':');
319 if (tmp) {
320 *tmp = 0;
321 path = wfindfile(paths, file);
322 *tmp = ':';
324 if (!tmp || !path)
325 path = wfindfile(paths, file);
327 return path;
330 static void timeoutHandler(void *data)
332 *(int *)data = 1;
335 static char *getTextSelection(WScreen * screen, Atom selection)
337 int buffer = -1;
339 switch (selection) {
340 case XA_CUT_BUFFER0:
341 buffer = 0;
342 break;
343 case XA_CUT_BUFFER1:
344 buffer = 1;
345 break;
346 case XA_CUT_BUFFER2:
347 buffer = 2;
348 break;
349 case XA_CUT_BUFFER3:
350 buffer = 3;
351 break;
352 case XA_CUT_BUFFER4:
353 buffer = 4;
354 break;
355 case XA_CUT_BUFFER5:
356 buffer = 5;
357 break;
358 case XA_CUT_BUFFER6:
359 buffer = 6;
360 break;
361 case XA_CUT_BUFFER7:
362 buffer = 7;
363 break;
365 if (buffer >= 0) {
366 char *data;
367 int size;
369 data = XFetchBuffer(dpy, &size, buffer);
371 return data;
372 } else {
373 char *data;
374 int bits;
375 Atom rtype;
376 unsigned long len, bytes;
377 WMHandlerID timer;
378 int timeout = 0;
379 XEvent ev;
380 static Atom clipboard = 0;
382 if (!clipboard)
383 clipboard = XInternAtom(dpy, "CLIPBOARD", False);
385 XDeleteProperty(dpy, screen->info_window, clipboard);
387 XConvertSelection(dpy, selection, XA_STRING, clipboard, screen->info_window, CurrentTime);
389 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
391 while (!XCheckTypedWindowEvent(dpy, screen->info_window, SelectionNotify, &ev) && !timeout) ;
393 if (!timeout) {
394 WMDeleteTimerHandler(timer);
395 } else {
396 wwarning("selection retrieval timed out");
397 return NULL;
400 /* nobody owns the selection or the current owner has
401 * nothing to do with what we need */
402 if (ev.xselection.property == None) {
403 return NULL;
406 if (XGetWindowProperty(dpy, screen->info_window,
407 clipboard, 0, 1024,
408 False, XA_STRING, &rtype, &bits, &len,
409 &bytes, (unsigned char **)&data) != Success) {
410 return NULL;
412 if (rtype != XA_STRING || bits != 8) {
413 wwarning("invalid data in text selection");
414 if (data)
415 XFree(data);
416 return NULL;
418 return data;
422 static char *getselection(WScreen * scr)
424 char *tmp;
426 tmp = getTextSelection(scr, XA_PRIMARY);
427 if (!tmp)
428 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
429 return tmp;
432 static char*
433 parseuserinputpart(char *line, int *ptr, char *endchars)
435 int depth = 0, begin;
436 char *value = NULL;
437 begin = ++*ptr;
439 while(line[*ptr] != '\0') {
440 if(line[*ptr] == '(') {
441 ++depth;
442 } else if(depth > 0 && line[*ptr] == ')') {
443 --depth;
444 } else if(depth == 0 && strchr(endchars, line[*ptr]) != NULL) {
445 value = wmalloc(*ptr - begin + 1);
446 strncpy(value, line + begin, *ptr - begin);
447 value[*ptr - begin] = '\0';
448 break;
450 ++*ptr;
453 return value;
456 static char*
457 getuserinput(WScreen *scr, char *line, int *ptr, Bool advanced)
459 char *ret = NULL, *title = NULL, *prompt = NULL, *name = NULL;
460 int rv;
462 if(line[*ptr] == '(')
463 title = parseuserinputpart(line, ptr, ",)");
464 if(title != NULL && line[*ptr] == ',')
465 prompt = parseuserinputpart(line, ptr, ",)");
466 if(prompt != NULL && line[*ptr] == ',')
467 name = parseuserinputpart(line, ptr, ")");
469 if(advanced)
470 rv = wAdvancedInputDialog(scr,
471 title ? _(title):_("Program Arguments"),
472 prompt ? _(prompt):_("Enter command arguments:"),
473 name, &ret);
474 else
475 rv = wInputDialog(scr,
476 title ? _(title):_("Program Arguments"),
477 prompt ? _(prompt):_("Enter command arguments:"),
478 &ret);
480 if(title) wfree(title);
481 if(prompt) wfree(prompt);
482 if(name) wfree(name);
484 return rv ? ret : NULL;
487 #define S_NORMAL 0
488 #define S_ESCAPE 1
489 #define S_OPTION 2
492 * state input new-state output
493 * NORMAL % OPTION <nil>
494 * NORMAL \ ESCAPE <nil>
495 * NORMAL etc. NORMAL <input>
496 * ESCAPE any NORMAL <input>
497 * OPTION s NORMAL <selection buffer>
498 * OPTION w NORMAL <selected window id>
499 * OPTION a NORMAL <input text>
500 * OPTION d NORMAL <OffiX DND selection object>
501 * OPTION W NORMAL <current workspace>
502 * OPTION etc. NORMAL %<input>
504 #define TMPBUFSIZE 64
505 char *ExpandOptions(WScreen * scr, char *cmdline)
507 int ptr, optr, state, len, olen;
508 char *out, *nout;
509 char *selection = NULL;
510 char *user_input = NULL;
511 #ifdef XDND
512 char *dropped_thing = NULL;
513 #endif
514 char tmpbuf[TMPBUFSIZE];
515 int slen;
517 len = strlen(cmdline);
518 olen = len + 1;
519 out = malloc(olen);
520 if (!out) {
521 wwarning(_("out of memory during expansion of \"%s\""), cmdline);
522 return NULL;
524 *out = 0;
525 ptr = 0; /* input line pointer */
526 optr = 0; /* output line pointer */
527 state = S_NORMAL;
528 while (ptr < len) {
529 switch (state) {
530 case S_NORMAL:
531 switch (cmdline[ptr]) {
532 case '\\':
533 state = S_ESCAPE;
534 break;
535 case '%':
536 state = S_OPTION;
537 break;
538 default:
539 state = S_NORMAL;
540 out[optr++] = cmdline[ptr];
541 break;
543 break;
544 case S_ESCAPE:
545 switch (cmdline[ptr]) {
546 case 'n':
547 out[optr++] = 10;
548 break;
550 case 'r':
551 out[optr++] = 13;
552 break;
554 case 't':
555 out[optr++] = 9;
556 break;
558 default:
559 out[optr++] = cmdline[ptr];
561 state = S_NORMAL;
562 break;
563 case S_OPTION:
564 state = S_NORMAL;
565 switch (cmdline[ptr]) {
566 case 'w':
567 if (scr->focused_window && scr->focused_window->flags.focused) {
568 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
569 (unsigned int)scr->focused_window->client_win);
570 slen = strlen(tmpbuf);
571 olen += slen;
572 nout = realloc(out, olen);
573 if (!nout) {
574 wwarning(_("out of memory during expansion of \"%%w\""));
575 goto error;
577 out = nout;
578 strcat(out, tmpbuf);
579 optr += slen;
580 } else {
581 out[optr++] = ' ';
583 break;
585 case 'W':
586 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", (unsigned int)scr->current_workspace + 1);
587 slen = strlen(tmpbuf);
588 olen += slen;
589 nout = realloc(out, olen);
590 if (!nout) {
591 wwarning(_("out of memory during expansion of \"%%W\""));
592 goto error;
594 out = nout;
595 strcat(out, tmpbuf);
596 optr += slen;
597 break;
599 case 'a':
600 case 'A':
601 ptr++;
602 user_input = getuserinput(scr, cmdline, &ptr, cmdline[ptr-1] == 'A');
603 if (user_input) {
604 slen = strlen(user_input);
605 olen += slen;
606 nout = realloc(out, olen);
607 if (!nout) {
608 wwarning(_("out of memory during expansion of \"%%a\""));
609 goto error;
611 out = nout;
612 strcat(out, user_input);
613 optr += slen;
614 } else {
615 /* Not an error, but user has Canceled the dialog box.
616 * This will make the command to not be performed. */
617 goto error;
619 break;
621 #ifdef XDND
622 case 'd':
623 if (scr->xdestring) {
624 dropped_thing = wstrdup(scr->xdestring);
626 if (!dropped_thing) {
627 dropped_thing = get_dnd_selection(scr);
629 if (!dropped_thing) {
630 scr->flags.dnd_data_convertion_status = 1;
631 goto error;
633 slen = strlen(dropped_thing);
634 olen += slen;
635 nout = realloc(out, olen);
636 if (!nout) {
637 wwarning(_("out of memory during expansion of \"%%d\""));
638 goto error;
640 out = nout;
641 strcat(out, dropped_thing);
642 optr += slen;
643 break;
644 #endif /* XDND */
646 case 's':
647 if (!selection) {
648 selection = getselection(scr);
650 if (!selection) {
651 wwarning(_("selection not available"));
652 goto error;
654 slen = strlen(selection);
655 olen += slen;
656 nout = realloc(out, olen);
657 if (!nout) {
658 wwarning(_("out of memory during expansion of \"%%s\""));
659 goto error;
661 out = nout;
662 strcat(out, selection);
663 optr += slen;
664 break;
666 default:
667 out[optr++] = '%';
668 out[optr++] = cmdline[ptr];
670 break;
672 out[optr] = 0;
673 ptr++;
675 if (selection)
676 XFree(selection);
677 return out;
679 error:
680 wfree(out);
681 if (selection)
682 XFree(selection);
683 return NULL;
686 void ParseWindowName(WMPropList * value, char **winstance, char **wclass, char *where)
688 char *name;
690 *winstance = *wclass = NULL;
692 if (!WMIsPLString(value)) {
693 wwarning(_("bad window name value in %s state info"), where);
694 return;
697 name = WMGetFromPLString(value);
698 if (!name || strlen(name) == 0) {
699 wwarning(_("bad window name value in %s state info"), where);
700 return;
703 UnescapeWM_CLASS(name, winstance, wclass);
706 #if 0
707 static char *keysymToString(KeySym keysym, unsigned int state)
709 XKeyEvent kev;
710 char *buf = wmalloc(20);
711 int count;
713 kev.display = dpy;
714 kev.type = KeyPress;
715 kev.send_event = False;
716 kev.window = DefaultRootWindow(dpy);
717 kev.root = DefaultRootWindow(dpy);
718 kev.same_screen = True;
719 kev.subwindow = kev.root;
720 kev.serial = 0x12344321;
721 kev.time = CurrentTime;
722 kev.state = state;
723 kev.keycode = XKeysymToKeycode(dpy, keysym);
724 count = XLookupString(&kev, buf, 19, NULL, NULL);
725 buf[count] = 0;
727 return buf;
729 #endif
731 char *GetShortcutString(char *text)
733 char *buffer = NULL;
734 char *k;
735 int modmask = 0;
736 /* KeySym ksym; */
737 int control = 0;
738 char *tmp;
740 tmp = text = wstrdup(text);
742 /* get modifiers */
743 while ((k = strchr(text, '+')) != NULL) {
744 int mod;
746 *k = 0;
747 mod = wXModifierFromKey(text);
748 if (mod < 0) {
749 return wstrdup("bug");
752 modmask |= mod;
754 if (strcasecmp(text, "Meta") == 0) {
755 buffer = wstrappend(buffer, "M+");
756 } else if (strcasecmp(text, "Alt") == 0) {
757 buffer = wstrappend(buffer, "A+");
758 } else if (strcasecmp(text, "Shift") == 0) {
759 buffer = wstrappend(buffer, "Sh+");
760 } else if (strcasecmp(text, "Mod1") == 0) {
761 buffer = wstrappend(buffer, "M1+");
762 } else if (strcasecmp(text, "Mod2") == 0) {
763 buffer = wstrappend(buffer, "M2+");
764 } else if (strcasecmp(text, "Mod3") == 0) {
765 buffer = wstrappend(buffer, "M3+");
766 } else if (strcasecmp(text, "Mod4") == 0) {
767 buffer = wstrappend(buffer, "M4+");
768 } else if (strcasecmp(text, "Mod5") == 0) {
769 buffer = wstrappend(buffer, "M5+");
770 } else if (strcasecmp(text, "Control") == 0) {
771 control = 1;
772 } else {
773 buffer = wstrappend(buffer, text);
775 text = k + 1;
778 if (control) {
779 buffer = wstrappend(buffer, "^");
781 buffer = wstrappend(buffer, text);
783 /* get key */
784 /* ksym = XStringToKeysym(text);
785 tmp = keysymToString(ksym, modmask);
786 puts(tmp);
787 buffer = wstrappend(buffer, tmp);
789 wfree(tmp);
791 return buffer;
794 char *GetShortcutKey(WShortKey key)
796 char *tmp = NULL;
797 char *k = XKeysymToString(XkbKeycodeToKeysym(dpy, key.keycode, 0, 0));
798 if (!k) return NULL;
800 char **m = wPreferences.modifier_labels;
801 if (key.modifier & ControlMask) tmp = wstrappend(tmp, m[1] ? m[1] : "Ctrl+");
802 if (key.modifier & ShiftMask) tmp = wstrappend(tmp, m[0] ? m[0] : "Shift+");
803 if (key.modifier & Mod1Mask) tmp = wstrappend(tmp, m[2] ? m[2] : "Mod1+");
804 if (key.modifier & Mod2Mask) tmp = wstrappend(tmp, m[3] ? m[3] : "Mod2+");
805 if (key.modifier & Mod3Mask) tmp = wstrappend(tmp, m[4] ? m[4] : "Mod3+");
806 if (key.modifier & Mod4Mask) tmp = wstrappend(tmp, m[5] ? m[5] : "Mod4+");
807 if (key.modifier & Mod5Mask) tmp = wstrappend(tmp, m[6] ? m[6] : "Mod5+");
808 tmp = wstrappend(tmp, k);
810 return GetShortcutString(tmp);
813 char *EscapeWM_CLASS(char *name, char *class)
815 char *ret;
816 char *ename = NULL, *eclass = NULL;
817 int i, j, l;
819 if (!name && !class)
820 return NULL;
822 if (name) {
823 l = strlen(name);
824 ename = wmalloc(l * 2 + 1);
825 j = 0;
826 for (i = 0; i < l; i++) {
827 if (name[i] == '\\') {
828 ename[j++] = '\\';
829 } else if (name[i] == '.') {
830 ename[j++] = '\\';
832 ename[j++] = name[i];
834 ename[j] = 0;
836 if (class) {
837 l = strlen(class);
838 eclass = wmalloc(l * 2 + 1);
839 j = 0;
840 for (i = 0; i < l; i++) {
841 if (class[i] == '\\') {
842 eclass[j++] = '\\';
843 } else if (class[i] == '.') {
844 eclass[j++] = '\\';
846 eclass[j++] = class[i];
848 eclass[j] = 0;
851 if (ename && eclass) {
852 int len = strlen(ename) + strlen(eclass) + 4;
853 ret = wmalloc(len);
854 snprintf(ret, len, "%s.%s", ename, eclass);
855 wfree(ename);
856 wfree(eclass);
857 } else if (ename) {
858 ret = wstrdup(ename);
859 wfree(ename);
860 } else {
861 ret = wstrdup(eclass);
862 wfree(eclass);
865 return ret;
868 static void UnescapeWM_CLASS(char *str, char **name, char **class)
870 int i, j, k, dot;
872 j = strlen(str);
873 *name = wmalloc(j);
874 **name = 0;
875 *class = wmalloc(j);
876 **class = 0;
878 /* separate string in 2 parts */
879 dot = -1;
880 for (i = 0; i < j; i++) {
881 if (str[i] == '\\') {
882 i++;
883 continue;
884 } else if (str[i] == '.') {
885 dot = i;
886 break;
890 /* unescape strings */
891 for (i = 0, k = 0; i < dot; i++) {
892 if (str[i] == '\\') {
893 continue;
894 } else {
895 (*name)[k++] = str[i];
898 (*name)[k] = 0;
900 for (i = dot + 1, k = 0; i < j; i++) {
901 if (str[i] == '\\') {
902 continue;
903 } else {
904 (*class)[k++] = str[i];
907 (*class)[k] = 0;
909 if (!*name) {
910 wfree(*name);
911 *name = NULL;
913 if (!*class) {
914 wfree(*class);
915 *class = NULL;
919 void SendHelperMessage(WScreen * scr, char type, int workspace, char *msg)
921 char *buffer;
922 int len;
923 int i;
924 char buf[16];
926 if (!scr->flags.backimage_helper_launched) {
927 return;
930 len = (msg ? strlen(msg) : 0) + (workspace >= 0 ? 4 : 0) + 1;
931 buffer = wmalloc(len + 5);
932 snprintf(buf, sizeof(buf), "%4i", len);
933 memcpy(buffer, buf, 4);
934 buffer[4] = type;
935 i = 5;
936 if (workspace >= 0) {
937 snprintf(buf, sizeof(buf), "%4i", workspace);
938 memcpy(&buffer[i], buf, 4);
939 i += 4;
940 buffer[i] = 0;
942 if (msg)
943 strcpy(&buffer[i], msg);
945 if (write(scr->helper_fd, buffer, len + 4) < 0) {
946 werror(_("could not send message to background image helper"));
948 wfree(buffer);
951 Bool UpdateDomainFile(WDDomain * domain)
953 struct stat stbuf;
954 char path[PATH_MAX];
955 WMPropList *shared_dict, *dict;
956 Bool result, freeDict = False;
958 dict = domain->dictionary;
959 if (WMIsPLDictionary(domain->dictionary)) {
960 /* retrieve global system dictionary */
961 snprintf(path, sizeof(path), "%s/WindowMaker/%s", SYSCONFDIR, domain->domain_name);
962 if (stat(path, &stbuf) >= 0) {
963 shared_dict = WMReadPropListFromFile(path);
964 if (shared_dict) {
965 if (WMIsPLDictionary(shared_dict)) {
966 freeDict = True;
967 dict = WMDeepCopyPropList(domain->dictionary);
968 WMSubtractPLDictionaries(dict, shared_dict, True);
970 WMReleasePropList(shared_dict);
975 result = WMWritePropListToFile(dict, domain->path);
977 if (freeDict) {
978 WMReleasePropList(dict);
981 return result;
984 char *StrConcatDot(char *a, char *b)
986 int len;
987 char *str;
989 if (!a)
990 a = "";
991 if (!b)
992 b = "";
994 len = strlen(a) + strlen(b) + 4;
995 str = wmalloc(len);
997 snprintf(str, len, "%s.%s", a, b);
999 return str;
1002 static char *getCommandForWindow(Window win, int elements)
1004 char **argv, *command = NULL;
1005 int argc;
1007 if (XGetCommand(dpy, win, &argv, &argc)) {
1008 if (argc > 0 && argv != NULL) {
1009 if (elements == 0)
1010 elements = argc;
1011 command = wtokenjoin(argv, WMIN(argc, elements));
1012 if (command[0] == 0) {
1013 wfree(command);
1014 command = NULL;
1017 if (argv) {
1018 XFreeStringList(argv);
1022 return command;
1025 /* Free result when done */
1026 char *GetCommandForWindow(Window win)
1028 return getCommandForWindow(win, 0);