Change to the linux kernel coding style
[wmaker-crm.git] / src / misc.c
1 /*
2  *  Window Maker window manager
3  *
4  *  Copyright (c) 1997-2003 Alfredo K. Kojima
5  *
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.
10  *
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.
15  *
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.
20  */
21 #include "wconfig.h"
22
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>
35
36 #include <WINGs/WUtil.h>
37 #include <wraster.h>
38
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"
50
51 /**** global variables *****/
52
53 extern WPreferences wPreferences;
54
55 extern Time LastTimestamp;
56
57 #ifdef USECPP
58 static void putdef(char *line, char *name, char *value)
59 {
60         if (!value) {
61                 wwarning(_("could not define value for %s for cpp"), name);
62                 return;
63         }
64         strcat(line, name);
65         strcat(line, value);
66 }
67
68 static void putidef(char *line, char *name, int value)
69 {
70         char tmp[64];
71         snprintf(tmp, sizeof(tmp), "%i", value);
72         strcat(line, name);
73         strcat(line, tmp);
74 }
75
76 static char *username()
77 {
78         char *tmp;
79
80         tmp = getlogin();
81         if (!tmp) {
82                 struct passwd *user;
83
84                 user = getpwuid(getuid());
85                 if (!user) {
86                         wsyserror(_("could not get password entry for UID %i"), getuid());
87                         return NULL;
88                 }
89                 if (!user->pw_name) {
90                         return NULL;
91                 } else {
92                         return user->pw_name;
93                 }
94         }
95         return tmp;
96 }
97
98 char *MakeCPPArgs(char *path)
99 {
100         int i;
101         char buffer[MAXLINE], *buf, *line;
102         Visual *visual;
103         char *tmp;
104
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);
118         }
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);
126
127         visual = DefaultVisual(dpy, DefaultScreen(dpy));
128         putidef(line, " -DVISUAL=", visual->class);
129
130         putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy)));
131
132         putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy)));
133         putidef(line, " -DSCR_HEIGHT=", HeightOfScreen(DefaultScreenOfDisplay(dpy)));
134
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;
142                 }
143                 buf = strrchr(tmp, '/');
144                 if (buf) {
145                         *buf = 0;       /* trunc filename */
146                         putdef(line, " -I", tmp);
147                 }
148                 wfree(tmp);
149         }
150
151         /* this should be done just once, but it works this way */
152         strcpy(buffer, DEF_CONFIG_PATHS);
153         buf = strtok(buffer, ":");
154
155         do {
156                 char fullpath[MAXLINE];
157
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();
164
165                         strcpy(fullpath, home);
166                         strcat(fullpath, &(buf[1]));
167                 }
168
169                 putdef(line, " -I", fullpath);
170
171         } while ((buf = strtok(NULL, ":")) != NULL);
172
173 #undef arg
174 #ifdef DEBUG
175         puts("CPP ARGS");
176         puts(line);
177 #endif
178         return line;
179 }
180 #endif                          /* USECPP */
181
182 #if 0
183 /*
184  * Is win2 below win1?
185  */
186 static Bool isBelow(WWindow * win1, WWindow * win2)
187 {
188         int i;
189         WCoreWindow *tmp;
190
191         tmp = win1->frame->core->stacking->under;
192         while (tmp) {
193                 if (tmp == win2->frame->core)
194                         return True;
195                 tmp = tmp->stacking->under;
196         }
197
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;
204                 }
205         }
206         return True;
207 }
208 #endif
209
210 /*
211  *  XFetchName Wrapper
212  *
213  */
214 Bool wFetchName(dpy, win, winname)
215 Display *dpy;
216 Window win;
217 char **winname;
218 {
219         XTextProperty text_prop;
220         char **list;
221         int num;
222
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);
238                                 }
239                         }
240                 } else {
241                         /* the title is set, but it was set to none */
242                         *winname = wstrdup("");
243                 }
244                 return True;
245         } else {
246                 /* the hint is probably not set */
247                 *winname = NULL;
248
249                 return False;
250         }
251 }
252
253 /*
254  *  XGetIconName Wrapper
255  *
256  */
257
258 Bool wGetIconName(dpy, win, iconname)
259 Display *dpy;
260 Window win;
261 char **iconname;
262 {
263         XTextProperty text_prop;
264         char **list;
265         int num;
266
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;
278                 }
279                 return True;
280         }
281         *iconname = NULL;
282         return False;
283 }
284
285 static void eatExpose()
286 {
287         XEvent event, foo;
288
289         /* compress all expose events into a single one */
290
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();
296
297                 event.xexpose.count = 0;
298                 XPutBackEvent(dpy, &event);
299         }
300 }
301
302 void SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
303 {
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;
307
308         /* animation parameters */
309         static struct {
310                 int delay;
311                 int steps;
312                 int slowdown;
313         } apars[5] = {
314                 {
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}};
320
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);
325
326         if (fabs(dx) > fabs(dy)) {
327                 dx_is_bigger = 1;
328         }
329
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);
344         }
345
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;
353
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);
368                 }
369
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);
376                 }
377                 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
378                         break;
379         }
380         XMoveWindow(dpy, win, to_x, to_y);
381
382         XSync(dpy, 0);
383         /* compress expose events */
384         eatExpose();
385 }
386
387 char *ShrinkString(WMFont * font, char *string, int width)
388 {
389         int w, w1 = 0;
390         int p;
391         char *pos;
392         char *text;
393         int p1, p2, t;
394
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;
401
402         pos = strchr(text, ' ');
403         if (!pos)
404                 pos = strchr(text, ':');
405
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++;
419                 }
420                 string += p;
421                 p = strlen(string);
422         } else {
423                 *text = 0;
424         }
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;
441         }
442         strcat(text, &string[p - p1]);
443
444         return text;
445 }
446
447 char *FindImage(char *paths, char *file)
448 {
449         char *tmp, *path;
450
451         tmp = strrchr(file, ':');
452         if (tmp) {
453                 *tmp = 0;
454                 path = wfindfile(paths, file);
455                 *tmp = ':';
456         }
457         if (!tmp || !path) {
458                 path = wfindfile(paths, file);
459         }
460
461         return path;
462 }
463
464 static void timeoutHandler(void *data)
465 {
466         *(int *)data = 1;
467 }
468
469 static char *getTextSelection(WScreen * screen, Atom selection)
470 {
471         int buffer = -1;
472
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;
498         }
499         if (buffer >= 0) {
500                 char *data;
501                 int size;
502
503                 data = XFetchBuffer(dpy, &size, buffer);
504
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;
515
516                 if (!clipboard)
517                         clipboard = XInternAtom(dpy, "CLIPBOARD", False);
518
519                 XDeleteProperty(dpy, screen->info_window, clipboard);
520
521                 XConvertSelection(dpy, selection, XA_STRING, clipboard, screen->info_window, CurrentTime);
522
523                 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
524
525                 while (!XCheckTypedWindowEvent(dpy, screen->info_window, SelectionNotify, &ev) && !timeout) ;
526
527                 if (!timeout) {
528                         WMDeleteTimerHandler(timer);
529                 } else {
530                         wwarning("selection retrieval timed out");
531                         return NULL;
532                 }
533
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;
538                 }
539
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;
545                 }
546                 if (rtype != XA_STRING || bits != 8) {
547                         wwarning("invalid data in text selection");
548                         if (data)
549                                 XFree(data);
550                         return NULL;
551                 }
552                 return data;
553         }
554 }
555
556 static char *getselection(WScreen * scr)
557 {
558         char *tmp;
559
560         tmp = getTextSelection(scr, XA_PRIMARY);
561         if (!tmp)
562                 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
563         return tmp;
564 }
565
566 static char *getuserinput(WScreen * scr, char *line, int *ptr)
567 {
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];
575
576         title = _("Program Arguments");
577         prompt = _("Enter command arguments:");
578         ret = NULL;
579
580 #define _STARTING 0
581 #define _TITLE 1
582 #define _PROMPT 2
583 #define _DONE 3
584
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;
595                         }
596                         break;
597
598                 case _TITLE:
599                         if (j <= 0 && line[*ptr] == ',') {
600
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;
606                                 }
607                                 begin = *ptr + 1;
608                                 state = _PROMPT;
609
610                         } else if (j <= 0 && line[*ptr] == ')') {
611
612                                 if (*ptr > begin) {
613                                         strncpy(tbuffer, &line[begin], WMIN(*ptr - begin, BUFSIZE));
614                                         tbuffer[WMIN(*ptr - begin, BUFSIZE)] = 0;
615                                         title = (char *)tbuffer;
616                                 }
617                                 state = _DONE;
618
619                         } else if (line[*ptr] == '(') {
620                                 j++;
621                         } else if (line[*ptr] == ')') {
622                                 j--;
623                         }
624
625                         break;
626
627                 case _PROMPT:
628                         if (line[*ptr] == ')' && j == 0) {
629
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;
634                                 }
635                                 state = _DONE;
636                         } else if (line[*ptr] == '(')
637                                 j++;
638                         else if (line[*ptr] == ')')
639                                 j--;
640                         break;
641                 }
642         }
643         (*ptr)--;
644 #undef _STARTING
645 #undef _TITLE
646 #undef _PROMPT
647 #undef _DONE
648
649         if (!wInputDialog(scr, title, prompt, &ret))
650                 return NULL;
651         else
652                 return ret;
653 }
654
655 #define S_NORMAL 0
656 #define S_ESCAPE 1
657 #define S_OPTION 2
658
659 /*
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>
671  */
672 #define TMPBUFSIZE 64
673 char *ExpandOptions(WScreen * scr, char *cmdline)
674 {
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;
684
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;
691         }
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;
710                         }
711                         break;
712                 case S_ESCAPE:
713                         switch (cmdline[ptr]) {
714                         case 'n':
715                                 out[optr++] = 10;
716                                 break;
717
718                         case 'r':
719                                 out[optr++] = 13;
720                                 break;
721
722                         case 't':
723                                 out[optr++] = 9;
724                                 break;
725
726                         default:
727                                 out[optr++] = cmdline[ptr];
728                         }
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;
744                                         }
745                                         out = nout;
746                                         strcat(out, tmpbuf);
747                                         optr += slen;
748                                 } else {
749                                         out[optr++] = ' ';
750                                 }
751                                 break;
752
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;
761                                 }
762                                 out = nout;
763                                 strcat(out, tmpbuf);
764                                 optr += slen;
765                                 break;
766
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;
777                                         }
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;
785                                 }
786                                 break;
787
788 #ifdef XDND
789                         case 'd':
790                                 if (scr->xdestring) {
791                                         dropped_thing = wstrdup(scr->xdestring);
792                                 }
793                                 if (!dropped_thing) {
794                                         dropped_thing = get_dnd_selection(scr);
795                                 }
796                                 if (!dropped_thing) {
797                                         scr->flags.dnd_data_convertion_status = 1;
798                                         goto error;
799                                 }
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;
806                                 }
807                                 out = nout;
808                                 strcat(out, dropped_thing);
809                                 optr += slen;
810                                 break;
811 #endif                          /* XDND */
812
813                         case 's':
814                                 if (!selection) {
815                                         selection = getselection(scr);
816                                 }
817                                 if (!selection) {
818                                         wwarning(_("selection not available"));
819                                         goto error;
820                                 }
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;
827                                 }
828                                 out = nout;
829                                 strcat(out, selection);
830                                 optr += slen;
831                                 break;
832
833                         default:
834                                 out[optr++] = '%';
835                                 out[optr++] = cmdline[ptr];
836                         }
837                         break;
838                 }
839                 out[optr] = 0;
840                 ptr++;
841         }
842         if (selection)
843                 XFree(selection);
844         return out;
845
846  error:
847         wfree(out);
848         if (selection)
849                 XFree(selection);
850         return NULL;
851 }
852
853 void ParseWindowName(WMPropList * value, char **winstance, char **wclass, char *where)
854 {
855         char *name;
856
857         *winstance = *wclass = NULL;
858
859         if (!WMIsPLString(value)) {
860                 wwarning(_("bad window name value in %s state info"), where);
861                 return;
862         }
863
864         name = WMGetFromPLString(value);
865         if (!name || strlen(name) == 0) {
866                 wwarning(_("bad window name value in %s state info"), where);
867                 return;
868         }
869
870         UnescapeWM_CLASS(name, winstance, wclass);
871 }
872
873 #if 0
874 static char *keysymToString(KeySym keysym, unsigned int state)
875 {
876         XKeyEvent kev;
877         char *buf = wmalloc(20);
878         int count;
879
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;
893
894         return buf;
895 }
896 #endif
897
898 char *GetShortcutString(char *text)
899 {
900         char *buffer = NULL;
901         char *k;
902         int modmask = 0;
903         /*    KeySym ksym; */
904         int control = 0;
905         char *tmp;
906
907         tmp = text = wstrdup(text);
908
909         /* get modifiers */
910         while ((k = strchr(text, '+')) != NULL) {
911                 int mod;
912
913                 *k = 0;
914                 mod = wXModifierFromKey(text);
915                 if (mod < 0) {
916                         return wstrdup("bug");
917                 }
918
919                 modmask |= mod;
920
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);
941                 }
942                 text = k + 1;
943         }
944
945         if (control) {
946                 buffer = wstrappend(buffer, "^");
947         }
948         buffer = wstrappend(buffer, text);
949
950         /* get key */
951         /*    ksym = XStringToKeysym(text);
952            tmp = keysymToString(ksym, modmask);
953            puts(tmp);
954            buffer = wstrappend(buffer, tmp);
955          */
956         wfree(tmp);
957
958         return buffer;
959 }
960
961 char *EscapeWM_CLASS(char *name, char *class)
962 {
963         char *ret;
964         char *ename = NULL, *eclass = NULL;
965         int i, j, l;
966
967         if (!name && !class)
968                 return NULL;
969
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++] = '\\';
979                         }
980                         ename[j++] = name[i];
981                 }
982                 ename[j] = 0;
983         }
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++] = '\\';
993                         }
994                         eclass[j++] = class[i];
995                 }
996                 eclass[j] = 0;
997         }
998
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);
1011         }
1012
1013         return ret;
1014 }
1015
1016 void UnescapeWM_CLASS(char *str, char **name, char **class)
1017 {
1018         int i, j, k, dot;
1019
1020         j = strlen(str);
1021         *name = wmalloc(j);
1022         **name = 0;
1023         *class = wmalloc(j);
1024         **class = 0;
1025
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;
1035                 }
1036         }
1037
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];
1044                 }
1045         }
1046         (*name)[k] = 0;
1047
1048         for (i = dot + 1, k = 0; i < j; i++) {
1049                 if (str[i] == '\\') {
1050                         continue;
1051                 } else {
1052                         (*class)[k++] = str[i];
1053                 }
1054         }
1055         (*class)[k] = 0;
1056
1057         if (!*name) {
1058                 wfree(*name);
1059                 *name = NULL;
1060         }
1061         if (!*class) {
1062                 wfree(*class);
1063                 *class = NULL;
1064         }
1065 }
1066
1067 void SendHelperMessage(WScreen * scr, char type, int workspace, char *msg)
1068 {
1069         char *buffer;
1070         int len;
1071         int i;
1072         char buf[16];
1073
1074         if (!scr->flags.backimage_helper_launched) {
1075                 return;
1076         }
1077
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;
1089         }
1090         if (msg)
1091                 strcpy(&buffer[i], msg);
1092
1093         if (write(scr->helper_fd, buffer, len + 4) < 0) {
1094                 wsyserror(_("could not send message to background image helper"));
1095         }
1096         wfree(buffer);
1097 }
1098
1099 Bool UpdateDomainFile(WDDomain * domain)
1100 {
1101         struct stat stbuf;
1102         char path[PATH_MAX];
1103         WMPropList *shared_dict, *dict;
1104         Bool result, freeDict = False;
1105
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);
1117                                 }
1118                                 WMReleasePropList(shared_dict);
1119                         }
1120                 }
1121         }
1122
1123         result = WMWritePropListToFile(dict, domain->path, True);
1124
1125         if (freeDict) {
1126                 WMReleasePropList(dict);
1127         }
1128
1129         return result;
1130 }
1131
1132 char *StrConcatDot(char *a, char *b)
1133 {
1134         int len;
1135         char *str;
1136
1137         if (!a)
1138                 a = "";
1139         if (!b)
1140                 b = "";
1141
1142         len = strlen(a) + strlen(b) + 4;
1143         str = wmalloc(len);
1144
1145         snprintf(str, len, "%s.%s", a, b);
1146
1147         return str;
1148 }
1149
1150 #define MAX_CMD_SIZE 4096
1151
1152 Bool GetCommandForPid(int pid, char ***argv, int *argc)
1153 {
1154         static char buf[MAX_CMD_SIZE];
1155         FILE *fPtr;
1156         int count, i, j;
1157         Bool ok = False;
1158
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)++;
1168                                 }
1169                         }
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];
1181                                         }
1182                                         if (j == *argc) {
1183                                                 break;
1184                                         }
1185                                 }
1186                                 ok = True;
1187                         }
1188                 }
1189                 fclose(fPtr);
1190         }
1191
1192         return ok;
1193 }
1194
1195 static char *getCommandForWindow(Window win, int elements)
1196 {
1197         char **argv, *command = NULL;
1198         int argc;
1199
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;
1208                         }
1209                 }
1210                 if (argv) {
1211                         XFreeStringList(argv);
1212                 }
1213         }
1214
1215         return command;
1216 }
1217
1218 /* Free result when done */
1219 char *GetCommandForWindow(Window win)
1220 {
1221         return getCommandForWindow(win, 0);
1222 }
1223
1224 /* Free result when done */
1225 char *GetProgramNameForWindow(Window win)
1226 {
1227         return getCommandForWindow(win, 1);
1228 }