- fixed possible crash bug because a variable allocated on stack was
[wmaker-crm.git] / src / misc.c
blob46bebf8cc9aab3be8f81ae0e54ec995002ee768e
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>
40 #include "WindowMaker.h"
41 #include "GNUstep.h"
42 #include "screen.h"
43 #include "wcore.h"
44 #include "window.h"
45 #include "framewin.h"
46 #include "funcs.h"
47 #include "defaults.h"
48 #include "dialog.h"
49 #include "xutil.h"
50 #include "xmodifier.h"
53 /**** global variables *****/
55 extern WPreferences wPreferences;
57 extern Time LastTimestamp;
60 #ifdef USECPP
61 static void
62 putdef(char *line, char *name, char *value)
64 if (!value) {
65 wwarning(_("could not define value for %s for cpp"), name);
66 return;
68 strcat(line, name);
69 strcat(line, value);
74 static void
75 putidef(char *line, char *name, int value)
77 char tmp[64];
78 snprintf(tmp, sizeof(tmp), "%i", value);
79 strcat(line, name);
80 strcat(line, tmp);
84 static char*
85 username()
87 char *tmp;
89 tmp = getlogin();
90 if (!tmp) {
91 struct passwd *user;
93 user = getpwuid(getuid());
94 if (!user) {
95 wsyserror(_("could not get password entry for UID %i"), getuid());
96 return NULL;
98 if (!user->pw_name) {
99 return NULL;
100 } else {
101 return user->pw_name;
104 return tmp;
107 char *
108 MakeCPPArgs(char *path)
110 int i;
111 char buffer[MAXLINE], *buf, *line;
112 Visual *visual;
113 char *tmp;
115 line = wmalloc(MAXLINE);
116 *line = 0;
117 i=1;
118 if ((buf=getenv("HOSTNAME"))!=NULL) {
119 if (buf[0]=='(') {
120 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"),
121 buf);
122 } else
123 putdef(line, " -DHOST=", buf);
124 } else if ((buf=getenv("HOST"))!=NULL) {
125 if (buf[0]=='(') {
126 wwarning(_("your machine is misconfigured. HOST is set to %s"),
127 buf);
128 } else
129 putdef(line, " -DHOST=", buf);
131 buf = username();
132 if (buf)
133 putdef(line, " -DUSER=", buf);
134 putidef(line, " -DUID=", getuid());
135 buf = XDisplayName(DisplayString(dpy));
136 putdef(line, " -DDISPLAY=", buf);
137 putdef(line, " -DWM_VERSION=", VERSION);
139 visual = DefaultVisual(dpy, DefaultScreen(dpy));
140 putidef(line, " -DVISUAL=", visual->class);
142 putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy)));
144 putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy)));
145 putidef(line, " -DSCR_HEIGHT=",
146 HeightOfScreen(DefaultScreenOfDisplay(dpy)));
148 /* put the dir where the menu is being read from to the
149 * search path */
150 if (path) {
151 tmp = wstrdup(path);
152 buf = strchr(tmp+1, ' ');
153 if (buf) {
154 *buf = 0;
156 buf = strrchr(tmp, '/');
157 if (buf) {
158 *buf = 0; /* trunc filename */
159 putdef(line, " -I", tmp);
161 wfree(tmp);
165 /* this should be done just once, but it works this way */
166 strcpy(buffer, DEF_CONFIG_PATHS);
167 buf = strtok(buffer, ":");
169 do {
170 char fullpath[MAXLINE];
172 if (buf[0]!='~') {
173 strcpy(fullpath, buf);
174 } else {
175 char * wgethomedir();
176 /* home is statically allocated. Don't free it! */
177 char *home = wgethomedir();
179 strcpy(fullpath, home);
180 strcat(fullpath, &(buf[1]));
183 putdef(line, " -I", fullpath);
185 } while ((buf = strtok(NULL, ":"))!=NULL);
187 #undef arg
188 #ifdef DEBUG
189 puts("CPP ARGS");
190 puts(line);
191 #endif
192 return line;
194 #endif /* USECPP */
199 #if 0
201 * Is win2 below win1?
203 static Bool
204 isBelow(WWindow *win1, WWindow *win2)
206 int i;
207 WCoreWindow *tmp;
209 tmp = win1->frame->core->stacking->under;
210 while (tmp) {
211 if (tmp == win2->frame->core)
212 return True;
213 tmp = tmp->stacking->under;
216 for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
217 tmp = win1->screen_ptr->stacking_list[i];
218 while (tmp) {
219 if (tmp == win2->frame->core)
220 return True;
221 tmp = tmp->stacking->under;
224 return True;
226 #endif
231 * XFetchName Wrapper
234 Bool
235 wFetchName(dpy, win, winname)
236 Display *dpy;
237 Window win;
238 char **winname;
240 XTextProperty text_prop;
241 char **list;
242 int num;
244 if (XGetWMName(dpy, win, &text_prop)) {
245 if (text_prop.value && text_prop.nitems > 0) {
246 if (text_prop.encoding == XA_STRING) {
247 *winname = wstrdup((char *)text_prop.value);
248 XFree(text_prop.value);
249 } else {
250 text_prop.nitems = strlen((char *)text_prop.value);
251 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
252 Success && num > 0 && *list) {
253 XFree(text_prop.value);
254 *winname = wstrdup(*list);
255 XFreeStringList(list);
256 } else {
257 *winname = wstrdup((char *)text_prop.value);
258 XFree(text_prop.value);
261 } else {
262 /* the title is set, but it was set to none */
263 *winname = wstrdup("");
265 return True;
266 } else {
267 /* the hint is probably not set */
268 *winname = NULL;
270 return False;
275 * XGetIconName Wrapper
279 Bool
280 wGetIconName(dpy, win, iconname)
281 Display *dpy;
282 Window win;
283 char **iconname;
285 XTextProperty text_prop;
286 char **list;
287 int num;
289 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
290 && text_prop.nitems > 0) {
291 if (text_prop.encoding == XA_STRING)
292 *iconname = (char *)text_prop.value;
293 else {
294 text_prop.nitems = strlen((char *)text_prop.value);
295 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
296 Success && num > 0 && *list) {
297 XFree(text_prop.value);
298 *iconname = wstrdup(*list);
299 XFreeStringList(list);
300 } else
301 *iconname = (char *)text_prop.value;
303 return True;
305 *iconname = NULL;
306 return False;
310 static void
311 eatExpose()
313 XEvent event, foo;
315 /* compress all expose events into a single one */
317 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
318 /* ignore other exposure events for this window */
319 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
320 &foo));
321 /* eat exposes for other windows */
322 eatExpose();
324 event.xexpose.count = 0;
325 XPutBackEvent(dpy, &event);
330 void
331 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
333 time_t time0 = time(NULL);
334 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
335 int dx_is_bigger=0;
337 /* animation parameters */
338 static struct {
339 int delay;
340 int steps;
341 int slowdown;
342 } apars[5] = {
343 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
344 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
345 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
346 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
347 {ICON_SLIDE_DELAY_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}};
351 dx = (float)(to_x-from_x);
352 dy = (float)(to_y-from_y);
353 sx = (dx == 0 ? 0 : fabs(dx)/dx);
354 sy = (dy == 0 ? 0 : fabs(dy)/dy);
356 if (fabs(dx) > fabs(dy)) {
357 dx_is_bigger = 1;
360 if (dx_is_bigger) {
361 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
362 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
363 px = apars[(int)wPreferences.icon_slide_speed].steps;
364 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
365 px = -apars[(int)wPreferences.icon_slide_speed].steps;
366 py = (sx == 0 ? 0 : px*dy/dx);
367 } else {
368 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
369 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
370 py = apars[(int)wPreferences.icon_slide_speed].steps;
371 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
372 py = -apars[(int)wPreferences.icon_slide_speed].steps;
373 px = (sy == 0 ? 0 : py*dx/dy);
376 while (x != to_x || y != to_y) {
377 x += px;
378 y += py;
379 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
380 x = (float)to_x;
381 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
382 y = (float)to_y;
384 if (dx_is_bigger) {
385 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
386 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
387 px = apars[(int)wPreferences.icon_slide_speed].steps;
388 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
389 px = -apars[(int)wPreferences.icon_slide_speed].steps;
390 py = (sx == 0 ? 0 : px*dy/dx);
391 } else {
392 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
393 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
394 py = apars[(int)wPreferences.icon_slide_speed].steps;
395 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
396 py = -apars[(int)wPreferences.icon_slide_speed].steps;
397 px = (sy == 0 ? 0 : py*dx/dy);
400 XMoveWindow(dpy, win, (int)x, (int)y);
401 XFlush(dpy);
402 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
403 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
404 } else {
405 wusleep(10);
407 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
408 break;
410 XMoveWindow(dpy, win, to_x, to_y);
412 XSync(dpy, 0);
413 /* compress expose events */
414 eatExpose();
418 char*
419 ShrinkString(WMFont *font, char *string, int width)
421 int w, w1=0;
422 int p;
423 char *pos;
424 char *text;
425 int p1, p2, t;
427 p = strlen(string);
428 w = WMWidthOfString(font, string, p);
429 text = wmalloc(strlen(string)+8);
430 strcpy(text, string);
431 if (w<=width)
432 return text;
434 pos = strchr(text, ' ');
435 if (!pos)
436 pos = strchr(text, ':');
438 if (pos) {
439 *pos = 0;
440 p = strlen(text);
441 w1 = WMWidthOfString(font, text, p);
442 if (w1 > width) {
443 w1 = 0;
444 p = 0;
445 *pos = ' ';
446 *text = 0;
447 } else {
448 *pos = 0;
449 width -= w1;
450 p++;
452 string += p;
453 p=strlen(string);
454 } else {
455 *text=0;
457 strcat(text, "...");
458 width -= WMWidthOfString(font, "...", 3);
459 pos = string;
460 p1=0;
461 p2=p;
462 t = (p2-p1)/2;
463 while (p2>p1 && p1!=t) {
464 w = WMWidthOfString(font, &string[p-t], t);
465 if (w>width) {
466 p2 = t;
467 t = p1+(p2-p1)/2;
468 } else if (w<width) {
469 p1 = t;
470 t = p1+(p2-p1)/2;
471 } else
472 p2=p1=t;
474 strcat(text, &string[p-p1]);
476 return text;
480 char*
481 FindImage(char *paths, char *file)
483 char *tmp, *path;
485 tmp = strrchr(file, ':');
486 if (tmp) {
487 *tmp = 0;
488 path = wfindfile(paths, file);
489 *tmp = ':';
491 if (!tmp || !path) {
492 path = wfindfile(paths, file);
495 return path;
499 static void
500 timeoutHandler(void *data)
502 *(int*)data = 1;
506 static char*
507 getTextSelection(WScreen *screen, Atom selection)
509 int buffer = -1;
511 switch (selection) {
512 case XA_CUT_BUFFER0:
513 buffer = 0;
514 break;
515 case XA_CUT_BUFFER1:
516 buffer = 1;
517 break;
518 case XA_CUT_BUFFER2:
519 buffer = 2;
520 break;
521 case XA_CUT_BUFFER3:
522 buffer = 3;
523 break;
524 case XA_CUT_BUFFER4:
525 buffer = 4;
526 break;
527 case XA_CUT_BUFFER5:
528 buffer = 5;
529 break;
530 case XA_CUT_BUFFER6:
531 buffer = 6;
532 break;
533 case XA_CUT_BUFFER7:
534 buffer = 7;
535 break;
537 if (buffer >= 0) {
538 char *data;
539 int size;
541 data = XFetchBuffer(dpy, &size, buffer);
543 return data;
544 } else {
545 char *data;
546 int bits;
547 Atom rtype;
548 unsigned long len, bytes;
549 WMHandlerID timer;
550 int timeout = 0;
551 XEvent ev;
552 static Atom clipboard = 0;
554 if (!clipboard)
555 clipboard = XInternAtom(dpy, "CLIPBOARD", False);
557 XDeleteProperty(dpy, screen->info_window, clipboard);
559 XConvertSelection(dpy, selection, XA_STRING,
560 clipboard, screen->info_window,
561 CurrentTime);
563 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
565 while (!XCheckTypedWindowEvent(dpy, screen->info_window,
566 SelectionNotify, &ev) && !timeout);
568 if (!timeout) {
569 WMDeleteTimerHandler(timer);
570 } else {
571 wwarning("selection retrieval timed out");
572 return NULL;
575 /* nobody owns the selection or the current owner has
576 * nothing to do with what we need */
577 if (ev.xselection.property == None) {
578 return NULL;
581 if (XGetWindowProperty(dpy, screen->info_window,
582 clipboard, 0, 1024,
583 False, XA_STRING, &rtype, &bits, &len,
584 &bytes, (unsigned char**)&data)!=Success) {
585 return NULL;
587 if (rtype!=XA_STRING || bits!=8) {
588 wwarning("invalid data in text selection");
589 if (data)
590 XFree(data);
591 return NULL;
593 return data;
597 static char*
598 getselection(WScreen *scr)
600 char *tmp;
602 tmp = getTextSelection(scr, XA_PRIMARY);
603 if (!tmp)
604 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
605 return tmp;
609 static char*
610 getuserinput(WScreen *scr, char *line, int *ptr)
612 char *ret;
613 char *title;
614 char *prompt;
615 int j, state;
616 int begin = 0;
617 #define BUFSIZE 512
618 char tbuffer[BUFSIZE], pbuffer[BUFSIZE];
621 title = _("Program Arguments");
622 prompt = _("Enter command arguments:");
623 ret = NULL;
625 #define _STARTING 0
626 #define _TITLE 1
627 #define _PROMPT 2
628 #define _DONE 3
630 state = _STARTING;
631 j = 0;
632 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
633 switch (state) {
634 case _STARTING:
635 if (line[*ptr]=='(') {
636 state = _TITLE;
637 begin = *ptr+1;
638 } else {
639 state = _DONE;
641 break;
643 case _TITLE:
644 if (j <= 0 && line[*ptr]==',') {
646 j = 0;
647 if (*ptr > begin) {
648 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE));
649 tbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0;
650 title = (char*)tbuffer;
652 begin = *ptr+1;
653 state = _PROMPT;
655 } else if (j <= 0 && line[*ptr]==')') {
657 if (*ptr > begin) {
658 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE));
659 tbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0;
660 title = (char*)tbuffer;
662 state = _DONE;
664 } else if (line[*ptr]=='(') {
665 j++;
666 } else if (line[*ptr]==')') {
667 j--;
670 break;
672 case _PROMPT:
673 if (line[*ptr]==')' && j==0) {
675 if (*ptr-begin > 1) {
676 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE));
677 pbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0;
678 prompt = (char*)pbuffer;
680 state = _DONE;
681 } else if (line[*ptr]=='(')
682 j++;
683 else if (line[*ptr]==')')
684 j--;
685 break;
688 (*ptr)--;
689 #undef _STARTING
690 #undef _TITLE
691 #undef _PROMPT
692 #undef _DONE
694 if (!wInputDialog(scr, title, prompt, &ret))
695 return NULL;
696 else
697 return ret;
701 #define S_NORMAL 0
702 #define S_ESCAPE 1
703 #define S_OPTION 2
706 * state input new-state output
707 * NORMAL % OPTION <nil>
708 * NORMAL \ ESCAPE <nil>
709 * NORMAL etc. NORMAL <input>
710 * ESCAPE any NORMAL <input>
711 * OPTION s NORMAL <selection buffer>
712 * OPTION w NORMAL <selected window id>
713 * OPTION a NORMAL <input text>
714 * OPTION d NORMAL <OffiX DND selection object>
715 * OPTION W NORMAL <current workspace>
716 * OPTION etc. NORMAL %<input>
718 #define TMPBUFSIZE 64
719 char*
720 ExpandOptions(WScreen *scr, char *cmdline)
722 int ptr, optr, state, len, olen;
723 char *out, *nout;
724 char *selection=NULL;
725 char *user_input=NULL;
726 #ifdef XDND
727 char *dropped_thing=NULL;
728 #endif
729 char tmpbuf[TMPBUFSIZE];
730 int slen;
732 len = strlen(cmdline);
733 olen = len+1;
734 out = malloc(olen);
735 if (!out) {
736 wwarning(_("out of memory during expansion of \"%s\""));
737 return NULL;
739 *out = 0;
740 ptr = 0; /* input line pointer */
741 optr = 0; /* output line pointer */
742 state = S_NORMAL;
743 while (ptr < len) {
744 switch (state) {
745 case S_NORMAL:
746 switch (cmdline[ptr]) {
747 case '\\':
748 state = S_ESCAPE;
749 break;
750 case '%':
751 state = S_OPTION;
752 break;
753 default:
754 state = S_NORMAL;
755 out[optr++]=cmdline[ptr];
756 break;
758 break;
759 case S_ESCAPE:
760 switch (cmdline[ptr]) {
761 case 'n':
762 out[optr++]=10;
763 break;
765 case 'r':
766 out[optr++]=13;
767 break;
769 case 't':
770 out[optr++]=9;
771 break;
773 default:
774 out[optr++]=cmdline[ptr];
776 state = S_NORMAL;
777 break;
778 case S_OPTION:
779 state = S_NORMAL;
780 switch (cmdline[ptr]) {
781 case 'w':
782 if (scr->focused_window
783 && scr->focused_window->flags.focused) {
784 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
785 (unsigned int)scr->focused_window->client_win);
786 slen = strlen(tmpbuf);
787 olen += slen;
788 nout = realloc(out,olen);
789 if (!nout) {
790 wwarning(_("out of memory during expansion of \"%w\""));
791 goto error;
793 out = nout;
794 strcat(out,tmpbuf);
795 optr+=slen;
796 } else {
797 out[optr++]=' ';
799 break;
801 case 'W':
802 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
803 (unsigned int)scr->current_workspace + 1);
804 slen = strlen(tmpbuf);
805 olen += slen;
806 nout = realloc(out,olen);
807 if (!nout) {
808 wwarning(_("out of memory during expansion of \"%W\""));
809 goto error;
811 out = nout;
812 strcat(out,tmpbuf);
813 optr+=slen;
814 break;
816 case 'a':
817 ptr++;
818 user_input = getuserinput(scr, cmdline, &ptr);
819 if (user_input) {
820 slen = strlen(user_input);
821 olen += slen;
822 nout = realloc(out,olen);
823 if (!nout) {
824 wwarning(_("out of memory during expansion of \"%a\""));
825 goto error;
827 out = nout;
828 strcat(out,user_input);
829 optr+=slen;
830 } else {
831 /* Not an error, but user has Canceled the dialog box.
832 * This will make the command to not be performed. */
833 goto error;
835 break;
837 #ifdef XDND
838 case 'd':
839 if(scr->xdestring) {
840 dropped_thing = wstrdup(scr->xdestring);
842 if (!dropped_thing) {
843 dropped_thing = get_dnd_selection(scr);
845 if (!dropped_thing) {
846 scr->flags.dnd_data_convertion_status = 1;
847 goto error;
849 slen = strlen(dropped_thing);
850 olen += slen;
851 nout = realloc(out,olen);
852 if (!nout) {
853 wwarning(_("out of memory during expansion of \"%d\""));
854 goto error;
856 out = nout;
857 strcat(out,dropped_thing);
858 optr+=slen;
859 break;
860 #endif /* XDND */
862 case 's':
863 if (!selection) {
864 selection = getselection(scr);
866 if (!selection) {
867 wwarning(_("selection not available"));
868 goto error;
870 slen = strlen(selection);
871 olen += slen;
872 nout = realloc(out,olen);
873 if (!nout) {
874 wwarning(_("out of memory during expansion of \"%s\""));
875 goto error;
877 out = nout;
878 strcat(out,selection);
879 optr+=slen;
880 break;
882 default:
883 out[optr++]='%';
884 out[optr++]=cmdline[ptr];
886 break;
888 out[optr]=0;
889 ptr++;
891 if (selection)
892 XFree(selection);
893 return out;
895 error:
896 wfree(out);
897 if (selection)
898 XFree(selection);
899 return NULL;
903 void
904 ParseWindowName(WMPropList *value, char **winstance, char **wclass, char *where)
906 char *name;
908 *winstance = *wclass = NULL;
910 if (!WMIsPLString(value)) {
911 wwarning(_("bad window name value in %s state info"), where);
912 return;
915 name = WMGetFromPLString(value);
916 if (!name || strlen(name)==0) {
917 wwarning(_("bad window name value in %s state info"), where);
918 return;
921 UnescapeWM_CLASS(name, winstance, wclass);
925 #if 0
926 static char*
927 keysymToString(KeySym keysym, unsigned int state)
929 XKeyEvent kev;
930 char *buf = wmalloc(20);
931 int count;
933 kev.display = dpy;
934 kev.type = KeyPress;
935 kev.send_event = False;
936 kev.window = DefaultRootWindow(dpy);
937 kev.root = DefaultRootWindow(dpy);
938 kev.same_screen = True;
939 kev.subwindow = kev.root;
940 kev.serial = 0x12344321;
941 kev.time = CurrentTime;
942 kev.state = state;
943 kev.keycode = XKeysymToKeycode(dpy, keysym);
944 count = XLookupString(&kev, buf, 19, NULL, NULL);
945 buf[count] = 0;
947 return buf;
949 #endif
952 char*
953 GetShortcutString(char *text)
955 char *buffer = NULL;
956 char *k;
957 int modmask = 0;
958 /* KeySym ksym;*/
959 int control = 0;
960 char *tmp;
962 tmp = text = wstrdup(text);
964 /* get modifiers */
965 while ((k = strchr(text, '+'))!=NULL) {
966 int mod;
968 *k = 0;
969 mod = wXModifierFromKey(text);
970 if (mod<0) {
971 return wstrdup("bug");
974 modmask |= mod;
976 if (strcasecmp(text, "Meta")==0) {
977 buffer = wstrappend(buffer, "M+");
978 } else if (strcasecmp(text, "Alt")==0) {
979 buffer = wstrappend(buffer, "A+");
980 } else if (strcasecmp(text, "Shift")==0) {
981 buffer = wstrappend(buffer, "Sh+");
982 } else if (strcasecmp(text, "Mod1")==0) {
983 buffer = wstrappend(buffer, "M1+");
984 } else if (strcasecmp(text, "Mod2")==0) {
985 buffer = wstrappend(buffer, "M2+");
986 } else if (strcasecmp(text, "Mod3")==0) {
987 buffer = wstrappend(buffer, "M3+");
988 } else if (strcasecmp(text, "Mod4")==0) {
989 buffer = wstrappend(buffer, "M4+");
990 } else if (strcasecmp(text, "Mod5")==0) {
991 buffer = wstrappend(buffer, "M5+");
992 } else if (strcasecmp(text, "Control")==0) {
993 control = 1;
994 } else {
995 buffer = wstrappend(buffer, text);
997 text = k+1;
1000 if (control) {
1001 buffer = wstrappend(buffer, "^");
1003 buffer = wstrappend(buffer, text);
1005 /* get key */
1006 /* ksym = XStringToKeysym(text);
1007 tmp = keysymToString(ksym, modmask);
1008 puts(tmp);
1009 buffer = wstrappend(buffer, tmp);
1011 wfree(tmp);
1013 return buffer;
1017 char*
1018 EscapeWM_CLASS(char *name, char *class)
1020 char *ret;
1021 char *ename = NULL, *eclass = NULL;
1022 int i, j, l;
1024 if (!name && !class)
1025 return NULL;
1027 if (name) {
1028 l = strlen(name);
1029 ename = wmalloc(l*2+1);
1030 j = 0;
1031 for (i=0; i<l; i++) {
1032 if (name[i]=='\\') {
1033 ename[j++] = '\\';
1034 } else if (name[i]=='.') {
1035 ename[j++] = '\\';
1037 ename[j++] = name[i];
1039 ename[j] = 0;
1041 if (class) {
1042 l = strlen(class);
1043 eclass = wmalloc(l*2+1);
1044 j = 0;
1045 for (i=0; i<l; i++) {
1046 if (class[i]=='\\') {
1047 eclass[j++] = '\\';
1048 } else if (class[i]=='.') {
1049 eclass[j++] = '\\';
1051 eclass[j++] = class[i];
1053 eclass[j] = 0;
1056 if (ename && eclass) {
1057 int len = strlen(ename)+strlen(eclass)+4;
1058 ret = wmalloc(len);
1059 snprintf(ret, len, "%s.%s", ename, eclass);
1060 wfree(ename);
1061 wfree(eclass);
1062 } else if (ename) {
1063 ret = wstrdup(ename);
1064 wfree(ename);
1065 } else {
1066 ret = wstrdup(eclass);
1067 wfree(eclass);
1070 return ret;
1074 void
1075 UnescapeWM_CLASS(char *str, char **name, char **class)
1077 int i, j, k, dot;
1079 j = strlen(str);
1080 *name = wmalloc(j);
1081 **name = 0;
1082 *class = wmalloc(j);
1083 **class = 0;
1085 /* separate string in 2 parts */
1086 dot = -1;
1087 for (i = 0; i < j; i++) {
1088 if (str[i]=='\\') {
1089 i++;
1090 continue;
1091 } else if (str[i]=='.') {
1092 dot = i;
1093 break;
1097 /* unescape strings */
1098 for (i=0, k=0; i < dot; i++) {
1099 if (str[i]=='\\') {
1100 continue;
1101 } else {
1102 (*name)[k++] = str[i];
1105 (*name)[k] = 0;
1107 for (i=dot+1, k=0; i<j; i++) {
1108 if (str[i]=='\\') {
1109 continue;
1110 } else {
1111 (*class)[k++] = str[i];
1114 (*class)[k] = 0;
1116 if (!*name) {
1117 wfree(*name);
1118 *name = NULL;
1120 if (!*class) {
1121 wfree(*class);
1122 *class = NULL;
1128 void
1129 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1131 unsigned char *buffer;
1132 int len;
1133 int i;
1134 char buf[16];
1136 if (!scr->flags.backimage_helper_launched) {
1137 return;
1140 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1141 buffer = wmalloc(len+5);
1142 snprintf(buf, len, "%4i", len);
1143 memcpy(buffer, buf, 4);
1144 buffer[4] = type;
1145 i = 5;
1146 if (workspace >= 0) {
1147 snprintf(buf, sizeof(buf), "%4i", workspace);
1148 memcpy(&buffer[i], buf, 4);
1149 i += 4;
1150 buffer[i] = 0;
1152 if (msg)
1153 strcpy(&buffer[i], msg);
1155 if (write(scr->helper_fd, buffer, len+4) < 0) {
1156 wsyserror(_("could not send message to background image helper"));
1158 wfree(buffer);
1162 Bool
1163 UpdateDomainFile(WDDomain *domain)
1165 struct stat stbuf;
1166 char path[PATH_MAX];
1167 WMPropList *shared_dict, *dict;
1168 Bool result, freeDict = False;
1170 dict = domain->dictionary;
1171 if (WMIsPLDictionary(domain->dictionary)) {
1172 /* retrieve global system dictionary */
1173 snprintf(path, sizeof(path), "%s/WindowMaker/%s",
1174 SYSCONFDIR, domain->domain_name);
1175 if (stat(path, &stbuf) >= 0) {
1176 shared_dict = WMReadPropListFromFile(path);
1177 if (shared_dict) {
1178 if (WMIsPLDictionary(shared_dict)) {
1179 freeDict = True;
1180 dict = WMDeepCopyPropList(domain->dictionary);
1181 WMSubtractPLDictionaries(dict, shared_dict, True);
1183 WMReleasePropList(shared_dict);
1188 result = WMWritePropListToFile(dict, domain->path, True);
1190 if (freeDict) {
1191 WMReleasePropList(dict);
1194 return result;
1198 char*
1199 StrConcatDot(char *a, char *b)
1201 int len;
1202 char *str;
1204 if (!a)
1205 a = "";
1206 if (!b)
1207 b = "";
1209 len = strlen(a)+strlen(b)+4;
1210 str = wmalloc(len);
1212 snprintf(str, len, "%s.%s", a, b);
1214 return str;
1218 #define MAX_CMD_SIZE 4096
1220 Bool
1221 GetCommandForPid(int pid, char ***argv, int *argc)
1223 static char buf[MAX_CMD_SIZE];
1224 FILE *fPtr;
1225 int count, i, j;
1226 Bool ok= False;
1228 sprintf(buf, "/proc/%d/cmdline", pid);
1229 fPtr = fopen(buf, "r");
1230 if (fPtr) {
1231 count = read(fileno(fPtr), buf, MAX_CMD_SIZE);
1232 if (count > 0) {
1233 buf[count-1] = 0;
1234 for (i=0, *argc=0; i<count; i++) {
1235 if (buf[i] == 0) {
1236 (*argc)++;
1239 if ((*argc) == 0) {
1240 *argv = NULL;
1241 ok= False;
1242 } else {
1243 *argv = (char**) wmalloc(sizeof(char*) * (*argc));
1244 (*argv)[0] = buf;
1245 for (i=0, j=1; i<count; i++) {
1246 if (buf[i] != 0)
1247 continue;
1248 if (i < count-1) {
1249 (*argv)[j++] = &buf[i+1];
1251 if (j == *argc) {
1252 break;
1255 ok= True;
1258 fclose(fPtr);
1261 return ok;
1265 static char*
1266 getCommandForWindow(Window win, int elements)
1268 char **argv, *command = NULL;
1269 int argc;
1271 if (XGetCommand(dpy, win, &argv, &argc)) {
1272 if (argc > 0 && argv != NULL) {
1273 if (elements==0)
1274 elements = argc;
1275 command = wtokenjoin(argv, WMIN(argc, elements));
1276 if (command[0] == 0) {
1277 wfree(command);
1278 command = NULL;
1281 if (argv) {
1282 XFreeStringList(argv);
1286 return command;
1290 /* Free result when done */
1291 char*
1292 GetCommandForWindow(Window win)
1294 return getCommandForWindow(win, 0);
1298 /* Free result when done */
1299 char*
1300 GetProgramNameForWindow(Window win)
1302 return getCommandForWindow(win, 1);