swpanel: Start with the first window when all are minimized
[wmaker-crm.git] / src / misc.c
blob2cf4af7b1ea3a75bf59a1d042d5093d1cacd6d98
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
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 * USA.
21 #include "wconfig.h"
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/Xatom.h>
26 #include <sys/stat.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <stdarg.h>
32 #include <pwd.h>
33 #include <math.h>
34 #include <time.h>
36 #include <WINGs/WUtil.h>
37 #include <wraster.h>
39 #include "WindowMaker.h"
40 #include "GNUstep.h"
41 #include "screen.h"
42 #include "wcore.h"
43 #include "window.h"
44 #include "framewin.h"
45 #include "funcs.h"
46 #include "defaults.h"
47 #include "dialog.h"
48 #include "xutil.h"
49 #include "xmodifier.h"
51 /**** global variables *****/
53 extern WPreferences wPreferences;
55 extern Time LastTimestamp;
57 #ifdef USECPP
58 static void putdef(char *line, char *name, char *value)
60 if (!value) {
61 wwarning(_("could not define value for %s for cpp"), name);
62 return;
64 strcat(line, name);
65 strcat(line, value);
68 static void putidef(char *line, char *name, int value)
70 char tmp[64];
71 snprintf(tmp, sizeof(tmp), "%i", value);
72 strcat(line, name);
73 strcat(line, tmp);
76 static char *username()
78 char *tmp;
80 tmp = getlogin();
81 if (!tmp) {
82 struct passwd *user;
84 user = getpwuid(getuid());
85 if (!user) {
86 wsyserror(_("could not get password entry for UID %i"), getuid());
87 return NULL;
89 if (!user->pw_name) {
90 return NULL;
91 } else {
92 return user->pw_name;
95 return tmp;
98 char *MakeCPPArgs(char *path)
100 int i;
101 char buffer[MAXLINE], *buf, *line;
102 Visual *visual;
103 char *tmp;
105 line = wmalloc(MAXLINE);
106 *line = 0;
107 i = 1;
108 if ((buf = getenv("HOSTNAME")) != NULL) {
109 if (buf[0] == '(') {
110 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"), buf);
111 } else
112 putdef(line, " -DHOST=", buf);
113 } else if ((buf = getenv("HOST")) != NULL) {
114 if (buf[0] == '(') {
115 wwarning(_("your machine is misconfigured. HOST is set to %s"), buf);
116 } else
117 putdef(line, " -DHOST=", buf);
119 buf = username();
120 if (buf)
121 putdef(line, " -DUSER=", buf);
122 putidef(line, " -DUID=", getuid());
123 buf = XDisplayName(DisplayString(dpy));
124 putdef(line, " -DDISPLAY=", buf);
125 putdef(line, " -DWM_VERSION=", VERSION);
127 visual = DefaultVisual(dpy, DefaultScreen(dpy));
128 putidef(line, " -DVISUAL=", visual->class);
130 putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy)));
132 putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy)));
133 putidef(line, " -DSCR_HEIGHT=", HeightOfScreen(DefaultScreenOfDisplay(dpy)));
135 /* put the dir where the menu is being read from to the
136 * search path */
137 if (path) {
138 tmp = wstrdup(path);
139 buf = strchr(tmp + 1, ' ');
140 if (buf) {
141 *buf = 0;
143 buf = strrchr(tmp, '/');
144 if (buf) {
145 *buf = 0; /* trunc filename */
146 putdef(line, " -I", tmp);
148 wfree(tmp);
151 /* this should be done just once, but it works this way */
152 strcpy(buffer, DEF_CONFIG_PATHS);
153 buf = strtok(buffer, ":");
155 do {
156 char fullpath[MAXLINE];
158 if (buf[0] != '~') {
159 strcpy(fullpath, buf);
160 } else {
161 char *wgethomedir();
162 /* home is statically allocated. Don't free it! */
163 char *home = wgethomedir();
165 strcpy(fullpath, home);
166 strcat(fullpath, &(buf[1]));
169 putdef(line, " -I", fullpath);
171 } while ((buf = strtok(NULL, ":")) != NULL);
173 #undef arg
174 #ifdef DEBUG
175 puts("CPP ARGS");
176 puts(line);
177 #endif
178 return line;
180 #endif /* USECPP */
182 #if 0
184 * Is win2 below win1?
186 static Bool isBelow(WWindow * win1, WWindow * win2)
188 int i;
189 WCoreWindow *tmp;
191 tmp = win1->frame->core->stacking->under;
192 while (tmp) {
193 if (tmp == win2->frame->core)
194 return True;
195 tmp = tmp->stacking->under;
198 for (i = win1->frame->core->stacking->window_level - 1; i >= 0; i--) {
199 tmp = win1->screen_ptr->stacking_list[i];
200 while (tmp) {
201 if (tmp == win2->frame->core)
202 return True;
203 tmp = tmp->stacking->under;
206 return True;
208 #endif
211 * XFetchName Wrapper
214 Bool wFetchName(dpy, win, winname)
215 Display *dpy;
216 Window win;
217 char **winname;
219 XTextProperty text_prop;
220 char **list;
221 int num;
223 if (XGetWMName(dpy, win, &text_prop)) {
224 if (text_prop.value && text_prop.nitems > 0) {
225 if (text_prop.encoding == XA_STRING) {
226 *winname = wstrdup((char *)text_prop.value);
227 XFree(text_prop.value);
228 } else {
229 text_prop.nitems = strlen((char *)text_prop.value);
230 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
231 Success && num > 0 && *list) {
232 XFree(text_prop.value);
233 *winname = wstrdup(*list);
234 XFreeStringList(list);
235 } else {
236 *winname = wstrdup((char *)text_prop.value);
237 XFree(text_prop.value);
240 } else {
241 /* the title is set, but it was set to none */
242 *winname = wstrdup("");
244 return True;
245 } else {
246 /* the hint is probably not set */
247 *winname = NULL;
249 return False;
254 * XGetIconName Wrapper
258 Bool wGetIconName(dpy, win, iconname)
259 Display *dpy;
260 Window win;
261 char **iconname;
263 XTextProperty text_prop;
264 char **list;
265 int num;
267 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value && text_prop.nitems > 0) {
268 if (text_prop.encoding == XA_STRING)
269 *iconname = (char *)text_prop.value;
270 else {
271 text_prop.nitems = strlen((char *)text_prop.value);
272 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success && num > 0 && *list) {
273 XFree(text_prop.value);
274 *iconname = wstrdup(*list);
275 XFreeStringList(list);
276 } else
277 *iconname = (char *)text_prop.value;
279 return True;
281 *iconname = NULL;
282 return False;
285 static void eatExpose()
287 XEvent event, foo;
289 /* compress all expose events into a single one */
291 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
292 /* ignore other exposure events for this window */
293 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask, &foo)) ;
294 /* eat exposes for other windows */
295 eatExpose();
297 event.xexpose.count = 0;
298 XPutBackEvent(dpy, &event);
302 void SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
304 time_t time0 = time(NULL);
305 float dx, dy, x = from_x, y = from_y, sx, sy, px, py;
306 int dx_is_bigger = 0;
308 /* animation parameters */
309 static struct {
310 int delay;
311 int steps;
312 int slowdown;
313 } apars[5] = {
315 ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF}, {
316 ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F}, {
317 ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M}, {
318 ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S}, {
319 ICON_SLIDE_DELAY_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}};
321 dx = (float)(to_x - from_x);
322 dy = (float)(to_y - from_y);
323 sx = (dx == 0 ? 0 : fabs(dx) / dx);
324 sy = (dy == 0 ? 0 : fabs(dy) / dy);
326 if (fabs(dx) > fabs(dy)) {
327 dx_is_bigger = 1;
330 if (dx_is_bigger) {
331 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
332 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
333 px = apars[(int)wPreferences.icon_slide_speed].steps;
334 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
335 px = -apars[(int)wPreferences.icon_slide_speed].steps;
336 py = (sx == 0 ? 0 : px * dy / dx);
337 } else {
338 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
339 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
340 py = apars[(int)wPreferences.icon_slide_speed].steps;
341 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
342 py = -apars[(int)wPreferences.icon_slide_speed].steps;
343 px = (sy == 0 ? 0 : py * dx / dy);
346 while (x != to_x || y != to_y) {
347 x += px;
348 y += py;
349 if ((px < 0 && (int)x < to_x) || (px > 0 && (int)x > to_x))
350 x = (float)to_x;
351 if ((py < 0 && (int)y < to_y) || (py > 0 && (int)y > to_y))
352 y = (float)to_y;
354 if (dx_is_bigger) {
355 px = px * (1.0 - 1 / (float)apars[(int)wPreferences.icon_slide_speed].slowdown);
356 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
357 px = apars[(int)wPreferences.icon_slide_speed].steps;
358 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
359 px = -apars[(int)wPreferences.icon_slide_speed].steps;
360 py = (sx == 0 ? 0 : px * dy / dx);
361 } else {
362 py = py * (1.0 - 1 / (float)apars[(int)wPreferences.icon_slide_speed].slowdown);
363 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
364 py = apars[(int)wPreferences.icon_slide_speed].steps;
365 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
366 py = -apars[(int)wPreferences.icon_slide_speed].steps;
367 px = (sy == 0 ? 0 : py * dx / dy);
370 XMoveWindow(dpy, win, (int)x, (int)y);
371 XFlush(dpy);
372 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
373 wusleep(apars[(int)wPreferences.icon_slide_speed].delay * 1000L);
374 } else {
375 wusleep(10);
377 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
378 break;
380 XMoveWindow(dpy, win, to_x, to_y);
382 XSync(dpy, 0);
383 /* compress expose events */
384 eatExpose();
387 char *ShrinkString(WMFont * font, char *string, int width)
389 int w, w1 = 0;
390 int p;
391 char *pos;
392 char *text;
393 int p1, p2, t;
395 p = strlen(string);
396 w = WMWidthOfString(font, string, p);
397 text = wmalloc(strlen(string) + 8);
398 strcpy(text, string);
399 if (w <= width)
400 return text;
402 pos = strchr(text, ' ');
403 if (!pos)
404 pos = strchr(text, ':');
406 if (pos) {
407 *pos = 0;
408 p = strlen(text);
409 w1 = WMWidthOfString(font, text, p);
410 if (w1 > width) {
411 w1 = 0;
412 p = 0;
413 *pos = ' ';
414 *text = 0;
415 } else {
416 *pos = 0;
417 width -= w1;
418 p++;
420 string += p;
421 p = strlen(string);
422 } else {
423 *text = 0;
425 strcat(text, "...");
426 width -= WMWidthOfString(font, "...", 3);
427 pos = string;
428 p1 = 0;
429 p2 = p;
430 t = (p2 - p1) / 2;
431 while (p2 > p1 && p1 != t) {
432 w = WMWidthOfString(font, &string[p - t], t);
433 if (w > width) {
434 p2 = t;
435 t = p1 + (p2 - p1) / 2;
436 } else if (w < width) {
437 p1 = t;
438 t = p1 + (p2 - p1) / 2;
439 } else
440 p2 = p1 = t;
442 strcat(text, &string[p - p1]);
444 return text;
447 char *FindImage(char *paths, char *file)
449 char *tmp, *path;
451 tmp = strrchr(file, ':');
452 if (tmp) {
453 *tmp = 0;
454 path = wfindfile(paths, file);
455 *tmp = ':';
457 if (!tmp || !path) {
458 path = wfindfile(paths, file);
461 return path;
464 static void timeoutHandler(void *data)
466 *(int *)data = 1;
469 static char *getTextSelection(WScreen * screen, Atom selection)
471 int buffer = -1;
473 switch (selection) {
474 case XA_CUT_BUFFER0:
475 buffer = 0;
476 break;
477 case XA_CUT_BUFFER1:
478 buffer = 1;
479 break;
480 case XA_CUT_BUFFER2:
481 buffer = 2;
482 break;
483 case XA_CUT_BUFFER3:
484 buffer = 3;
485 break;
486 case XA_CUT_BUFFER4:
487 buffer = 4;
488 break;
489 case XA_CUT_BUFFER5:
490 buffer = 5;
491 break;
492 case XA_CUT_BUFFER6:
493 buffer = 6;
494 break;
495 case XA_CUT_BUFFER7:
496 buffer = 7;
497 break;
499 if (buffer >= 0) {
500 char *data;
501 int size;
503 data = XFetchBuffer(dpy, &size, buffer);
505 return data;
506 } else {
507 char *data;
508 int bits;
509 Atom rtype;
510 unsigned long len, bytes;
511 WMHandlerID timer;
512 int timeout = 0;
513 XEvent ev;
514 static Atom clipboard = 0;
516 if (!clipboard)
517 clipboard = XInternAtom(dpy, "CLIPBOARD", False);
519 XDeleteProperty(dpy, screen->info_window, clipboard);
521 XConvertSelection(dpy, selection, XA_STRING, clipboard, screen->info_window, CurrentTime);
523 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
525 while (!XCheckTypedWindowEvent(dpy, screen->info_window, SelectionNotify, &ev) && !timeout) ;
527 if (!timeout) {
528 WMDeleteTimerHandler(timer);
529 } else {
530 wwarning("selection retrieval timed out");
531 return NULL;
534 /* nobody owns the selection or the current owner has
535 * nothing to do with what we need */
536 if (ev.xselection.property == None) {
537 return NULL;
540 if (XGetWindowProperty(dpy, screen->info_window,
541 clipboard, 0, 1024,
542 False, XA_STRING, &rtype, &bits, &len,
543 &bytes, (unsigned char **)&data) != Success) {
544 return NULL;
546 if (rtype != XA_STRING || bits != 8) {
547 wwarning("invalid data in text selection");
548 if (data)
549 XFree(data);
550 return NULL;
552 return data;
556 static char *getselection(WScreen * scr)
558 char *tmp;
560 tmp = getTextSelection(scr, XA_PRIMARY);
561 if (!tmp)
562 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
563 return tmp;
566 static char *getuserinput(WScreen * scr, char *line, int *ptr)
568 char *ret;
569 char *title;
570 char *prompt;
571 int j, state;
572 int begin = 0;
573 #define BUFSIZE 512
574 char tbuffer[BUFSIZE], pbuffer[BUFSIZE];
576 title = _("Program Arguments");
577 prompt = _("Enter command arguments:");
578 ret = NULL;
580 #define _STARTING 0
581 #define _TITLE 1
582 #define _PROMPT 2
583 #define _DONE 3
585 state = _STARTING;
586 j = 0;
587 for (; line[*ptr] != 0 && state != _DONE; (*ptr)++) {
588 switch (state) {
589 case _STARTING:
590 if (line[*ptr] == '(') {
591 state = _TITLE;
592 begin = *ptr + 1;
593 } else {
594 state = _DONE;
596 break;
598 case _TITLE:
599 if (j <= 0 && line[*ptr] == ',') {
601 j = 0;
602 if (*ptr > begin) {
603 strncpy(tbuffer, &line[begin], WMIN(*ptr - begin, BUFSIZE));
604 tbuffer[WMIN(*ptr - begin, BUFSIZE)] = 0;
605 title = (char *)tbuffer;
607 begin = *ptr + 1;
608 state = _PROMPT;
610 } else if (j <= 0 && line[*ptr] == ')') {
612 if (*ptr > begin) {
613 strncpy(tbuffer, &line[begin], WMIN(*ptr - begin, BUFSIZE));
614 tbuffer[WMIN(*ptr - begin, BUFSIZE)] = 0;
615 title = (char *)tbuffer;
617 state = _DONE;
619 } else if (line[*ptr] == '(') {
620 j++;
621 } else if (line[*ptr] == ')') {
622 j--;
625 break;
627 case _PROMPT:
628 if (line[*ptr] == ')' && j == 0) {
630 if (*ptr - begin > 1) {
631 strncpy(pbuffer, &line[begin], WMIN(*ptr - begin, BUFSIZE));
632 pbuffer[WMIN(*ptr - begin, BUFSIZE)] = 0;
633 prompt = (char *)pbuffer;
635 state = _DONE;
636 } else if (line[*ptr] == '(')
637 j++;
638 else if (line[*ptr] == ')')
639 j--;
640 break;
643 (*ptr)--;
644 #undef _STARTING
645 #undef _TITLE
646 #undef _PROMPT
647 #undef _DONE
649 if (!wInputDialog(scr, title, prompt, &ret))
650 return NULL;
651 else
652 return ret;
655 #define S_NORMAL 0
656 #define S_ESCAPE 1
657 #define S_OPTION 2
660 * state input new-state output
661 * NORMAL % OPTION <nil>
662 * NORMAL \ ESCAPE <nil>
663 * NORMAL etc. NORMAL <input>
664 * ESCAPE any NORMAL <input>
665 * OPTION s NORMAL <selection buffer>
666 * OPTION w NORMAL <selected window id>
667 * OPTION a NORMAL <input text>
668 * OPTION d NORMAL <OffiX DND selection object>
669 * OPTION W NORMAL <current workspace>
670 * OPTION etc. NORMAL %<input>
672 #define TMPBUFSIZE 64
673 char *ExpandOptions(WScreen * scr, char *cmdline)
675 int ptr, optr, state, len, olen;
676 char *out, *nout;
677 char *selection = NULL;
678 char *user_input = NULL;
679 #ifdef XDND
680 char *dropped_thing = NULL;
681 #endif
682 char tmpbuf[TMPBUFSIZE];
683 int slen;
685 len = strlen(cmdline);
686 olen = len + 1;
687 out = malloc(olen);
688 if (!out) {
689 wwarning(_("out of memory during expansion of \"%s\""));
690 return NULL;
692 *out = 0;
693 ptr = 0; /* input line pointer */
694 optr = 0; /* output line pointer */
695 state = S_NORMAL;
696 while (ptr < len) {
697 switch (state) {
698 case S_NORMAL:
699 switch (cmdline[ptr]) {
700 case '\\':
701 state = S_ESCAPE;
702 break;
703 case '%':
704 state = S_OPTION;
705 break;
706 default:
707 state = S_NORMAL;
708 out[optr++] = cmdline[ptr];
709 break;
711 break;
712 case S_ESCAPE:
713 switch (cmdline[ptr]) {
714 case 'n':
715 out[optr++] = 10;
716 break;
718 case 'r':
719 out[optr++] = 13;
720 break;
722 case 't':
723 out[optr++] = 9;
724 break;
726 default:
727 out[optr++] = cmdline[ptr];
729 state = S_NORMAL;
730 break;
731 case S_OPTION:
732 state = S_NORMAL;
733 switch (cmdline[ptr]) {
734 case 'w':
735 if (scr->focused_window && scr->focused_window->flags.focused) {
736 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
737 (unsigned int)scr->focused_window->client_win);
738 slen = strlen(tmpbuf);
739 olen += slen;
740 nout = realloc(out, olen);
741 if (!nout) {
742 wwarning(_("out of memory during expansion of \"%w\""));
743 goto error;
745 out = nout;
746 strcat(out, tmpbuf);
747 optr += slen;
748 } else {
749 out[optr++] = ' ';
751 break;
753 case 'W':
754 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", (unsigned int)scr->current_workspace + 1);
755 slen = strlen(tmpbuf);
756 olen += slen;
757 nout = realloc(out, olen);
758 if (!nout) {
759 wwarning(_("out of memory during expansion of \"%W\""));
760 goto error;
762 out = nout;
763 strcat(out, tmpbuf);
764 optr += slen;
765 break;
767 case 'a':
768 ptr++;
769 user_input = getuserinput(scr, cmdline, &ptr);
770 if (user_input) {
771 slen = strlen(user_input);
772 olen += slen;
773 nout = realloc(out, olen);
774 if (!nout) {
775 wwarning(_("out of memory during expansion of \"%a\""));
776 goto error;
778 out = nout;
779 strcat(out, user_input);
780 optr += slen;
781 } else {
782 /* Not an error, but user has Canceled the dialog box.
783 * This will make the command to not be performed. */
784 goto error;
786 break;
788 #ifdef XDND
789 case 'd':
790 if (scr->xdestring) {
791 dropped_thing = wstrdup(scr->xdestring);
793 if (!dropped_thing) {
794 dropped_thing = get_dnd_selection(scr);
796 if (!dropped_thing) {
797 scr->flags.dnd_data_convertion_status = 1;
798 goto error;
800 slen = strlen(dropped_thing);
801 olen += slen;
802 nout = realloc(out, olen);
803 if (!nout) {
804 wwarning(_("out of memory during expansion of \"%d\""));
805 goto error;
807 out = nout;
808 strcat(out, dropped_thing);
809 optr += slen;
810 break;
811 #endif /* XDND */
813 case 's':
814 if (!selection) {
815 selection = getselection(scr);
817 if (!selection) {
818 wwarning(_("selection not available"));
819 goto error;
821 slen = strlen(selection);
822 olen += slen;
823 nout = realloc(out, olen);
824 if (!nout) {
825 wwarning(_("out of memory during expansion of \"%s\""));
826 goto error;
828 out = nout;
829 strcat(out, selection);
830 optr += slen;
831 break;
833 default:
834 out[optr++] = '%';
835 out[optr++] = cmdline[ptr];
837 break;
839 out[optr] = 0;
840 ptr++;
842 if (selection)
843 XFree(selection);
844 return out;
846 error:
847 wfree(out);
848 if (selection)
849 XFree(selection);
850 return NULL;
853 void ParseWindowName(WMPropList * value, char **winstance, char **wclass, char *where)
855 char *name;
857 *winstance = *wclass = NULL;
859 if (!WMIsPLString(value)) {
860 wwarning(_("bad window name value in %s state info"), where);
861 return;
864 name = WMGetFromPLString(value);
865 if (!name || strlen(name) == 0) {
866 wwarning(_("bad window name value in %s state info"), where);
867 return;
870 UnescapeWM_CLASS(name, winstance, wclass);
873 #if 0
874 static char *keysymToString(KeySym keysym, unsigned int state)
876 XKeyEvent kev;
877 char *buf = wmalloc(20);
878 int count;
880 kev.display = dpy;
881 kev.type = KeyPress;
882 kev.send_event = False;
883 kev.window = DefaultRootWindow(dpy);
884 kev.root = DefaultRootWindow(dpy);
885 kev.same_screen = True;
886 kev.subwindow = kev.root;
887 kev.serial = 0x12344321;
888 kev.time = CurrentTime;
889 kev.state = state;
890 kev.keycode = XKeysymToKeycode(dpy, keysym);
891 count = XLookupString(&kev, buf, 19, NULL, NULL);
892 buf[count] = 0;
894 return buf;
896 #endif
898 char *GetShortcutString(char *text)
900 char *buffer = NULL;
901 char *k;
902 int modmask = 0;
903 /* KeySym ksym; */
904 int control = 0;
905 char *tmp;
907 tmp = text = wstrdup(text);
909 /* get modifiers */
910 while ((k = strchr(text, '+')) != NULL) {
911 int mod;
913 *k = 0;
914 mod = wXModifierFromKey(text);
915 if (mod < 0) {
916 return wstrdup("bug");
919 modmask |= mod;
921 if (strcasecmp(text, "Meta") == 0) {
922 buffer = wstrappend(buffer, "M+");
923 } else if (strcasecmp(text, "Alt") == 0) {
924 buffer = wstrappend(buffer, "A+");
925 } else if (strcasecmp(text, "Shift") == 0) {
926 buffer = wstrappend(buffer, "Sh+");
927 } else if (strcasecmp(text, "Mod1") == 0) {
928 buffer = wstrappend(buffer, "M1+");
929 } else if (strcasecmp(text, "Mod2") == 0) {
930 buffer = wstrappend(buffer, "M2+");
931 } else if (strcasecmp(text, "Mod3") == 0) {
932 buffer = wstrappend(buffer, "M3+");
933 } else if (strcasecmp(text, "Mod4") == 0) {
934 buffer = wstrappend(buffer, "M4+");
935 } else if (strcasecmp(text, "Mod5") == 0) {
936 buffer = wstrappend(buffer, "M5+");
937 } else if (strcasecmp(text, "Control") == 0) {
938 control = 1;
939 } else {
940 buffer = wstrappend(buffer, text);
942 text = k + 1;
945 if (control) {
946 buffer = wstrappend(buffer, "^");
948 buffer = wstrappend(buffer, text);
950 /* get key */
951 /* ksym = XStringToKeysym(text);
952 tmp = keysymToString(ksym, modmask);
953 puts(tmp);
954 buffer = wstrappend(buffer, tmp);
956 wfree(tmp);
958 return buffer;
961 char *EscapeWM_CLASS(char *name, char *class)
963 char *ret;
964 char *ename = NULL, *eclass = NULL;
965 int i, j, l;
967 if (!name && !class)
968 return NULL;
970 if (name) {
971 l = strlen(name);
972 ename = wmalloc(l * 2 + 1);
973 j = 0;
974 for (i = 0; i < l; i++) {
975 if (name[i] == '\\') {
976 ename[j++] = '\\';
977 } else if (name[i] == '.') {
978 ename[j++] = '\\';
980 ename[j++] = name[i];
982 ename[j] = 0;
984 if (class) {
985 l = strlen(class);
986 eclass = wmalloc(l * 2 + 1);
987 j = 0;
988 for (i = 0; i < l; i++) {
989 if (class[i] == '\\') {
990 eclass[j++] = '\\';
991 } else if (class[i] == '.') {
992 eclass[j++] = '\\';
994 eclass[j++] = class[i];
996 eclass[j] = 0;
999 if (ename && eclass) {
1000 int len = strlen(ename) + strlen(eclass) + 4;
1001 ret = wmalloc(len);
1002 snprintf(ret, len, "%s.%s", ename, eclass);
1003 wfree(ename);
1004 wfree(eclass);
1005 } else if (ename) {
1006 ret = wstrdup(ename);
1007 wfree(ename);
1008 } else {
1009 ret = wstrdup(eclass);
1010 wfree(eclass);
1013 return ret;
1016 void UnescapeWM_CLASS(char *str, char **name, char **class)
1018 int i, j, k, dot;
1020 j = strlen(str);
1021 *name = wmalloc(j);
1022 **name = 0;
1023 *class = wmalloc(j);
1024 **class = 0;
1026 /* separate string in 2 parts */
1027 dot = -1;
1028 for (i = 0; i < j; i++) {
1029 if (str[i] == '\\') {
1030 i++;
1031 continue;
1032 } else if (str[i] == '.') {
1033 dot = i;
1034 break;
1038 /* unescape strings */
1039 for (i = 0, k = 0; i < dot; i++) {
1040 if (str[i] == '\\') {
1041 continue;
1042 } else {
1043 (*name)[k++] = str[i];
1046 (*name)[k] = 0;
1048 for (i = dot + 1, k = 0; i < j; i++) {
1049 if (str[i] == '\\') {
1050 continue;
1051 } else {
1052 (*class)[k++] = str[i];
1055 (*class)[k] = 0;
1057 if (!*name) {
1058 wfree(*name);
1059 *name = NULL;
1061 if (!*class) {
1062 wfree(*class);
1063 *class = NULL;
1067 void SendHelperMessage(WScreen * scr, char type, int workspace, char *msg)
1069 char *buffer;
1070 int len;
1071 int i;
1072 char buf[16];
1074 if (!scr->flags.backimage_helper_launched) {
1075 return;
1078 len = (msg ? strlen(msg) : 0) + (workspace >= 0 ? 4 : 0) + 1;
1079 buffer = wmalloc(len + 5);
1080 snprintf(buf, sizeof(buf), "%4i", len);
1081 memcpy(buffer, buf, 4);
1082 buffer[4] = type;
1083 i = 5;
1084 if (workspace >= 0) {
1085 snprintf(buf, sizeof(buf), "%4i", workspace);
1086 memcpy(&buffer[i], buf, 4);
1087 i += 4;
1088 buffer[i] = 0;
1090 if (msg)
1091 strcpy(&buffer[i], msg);
1093 if (write(scr->helper_fd, buffer, len + 4) < 0) {
1094 wsyserror(_("could not send message to background image helper"));
1096 wfree(buffer);
1099 Bool UpdateDomainFile(WDDomain * domain)
1101 struct stat stbuf;
1102 char path[PATH_MAX];
1103 WMPropList *shared_dict, *dict;
1104 Bool result, freeDict = False;
1106 dict = domain->dictionary;
1107 if (WMIsPLDictionary(domain->dictionary)) {
1108 /* retrieve global system dictionary */
1109 snprintf(path, sizeof(path), "%s/WindowMaker/%s", SYSCONFDIR, domain->domain_name);
1110 if (stat(path, &stbuf) >= 0) {
1111 shared_dict = WMReadPropListFromFile(path);
1112 if (shared_dict) {
1113 if (WMIsPLDictionary(shared_dict)) {
1114 freeDict = True;
1115 dict = WMDeepCopyPropList(domain->dictionary);
1116 WMSubtractPLDictionaries(dict, shared_dict, True);
1118 WMReleasePropList(shared_dict);
1123 result = WMWritePropListToFile(dict, domain->path, True);
1125 if (freeDict) {
1126 WMReleasePropList(dict);
1129 return result;
1132 char *StrConcatDot(char *a, char *b)
1134 int len;
1135 char *str;
1137 if (!a)
1138 a = "";
1139 if (!b)
1140 b = "";
1142 len = strlen(a) + strlen(b) + 4;
1143 str = wmalloc(len);
1145 snprintf(str, len, "%s.%s", a, b);
1147 return str;
1150 #define MAX_CMD_SIZE 4096
1152 Bool GetCommandForPid(int pid, char ***argv, int *argc)
1154 static char buf[MAX_CMD_SIZE];
1155 FILE *fPtr;
1156 int count, i, j;
1157 Bool ok = False;
1159 sprintf(buf, "/proc/%d/cmdline", pid);
1160 fPtr = fopen(buf, "r");
1161 if (fPtr) {
1162 count = read(fileno(fPtr), buf, MAX_CMD_SIZE);
1163 if (count > 0) {
1164 buf[count - 1] = 0;
1165 for (i = 0, *argc = 0; i < count; i++) {
1166 if (buf[i] == 0) {
1167 (*argc)++;
1170 if ((*argc) == 0) {
1171 *argv = NULL;
1172 ok = False;
1173 } else {
1174 *argv = (char **)wmalloc(sizeof(char *) * (*argc));
1175 (*argv)[0] = buf;
1176 for (i = 0, j = 1; i < count; i++) {
1177 if (buf[i] != 0)
1178 continue;
1179 if (i < count - 1) {
1180 (*argv)[j++] = &buf[i + 1];
1182 if (j == *argc) {
1183 break;
1186 ok = True;
1189 fclose(fPtr);
1192 return ok;
1195 static char *getCommandForWindow(Window win, int elements)
1197 char **argv, *command = NULL;
1198 int argc;
1200 if (XGetCommand(dpy, win, &argv, &argc)) {
1201 if (argc > 0 && argv != NULL) {
1202 if (elements == 0)
1203 elements = argc;
1204 command = wtokenjoin(argv, WMIN(argc, elements));
1205 if (command[0] == 0) {
1206 wfree(command);
1207 command = NULL;
1210 if (argv) {
1211 XFreeStringList(argv);
1215 return command;
1218 /* Free result when done */
1219 char *GetCommandForWindow(Window win)
1221 return getCommandForWindow(win, 0);
1224 /* Free result when done */
1225 char *GetProgramNameForWindow(Window win)
1227 return getCommandForWindow(win, 1);