Add history to some dialog boxes
[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 #include <libintl.h>
36
37 #include <WINGs/WUtil.h>
38 #include <wraster.h>
39
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"
51
52 /**** global variables *****/
53
54 extern WPreferences wPreferences;
55
56 extern Time LastTimestamp;
57
58 #ifdef USECPP
59 static void putdef(char *line, char *name, char *value)
60 {
61         if (!value) {
62                 wwarning(_("could not define value for %s for cpp"), name);
63                 return;
64         }
65         strcat(line, name);
66         strcat(line, value);
67 }
68
69 static void putidef(char *line, char *name, int value)
70 {
71         char tmp[64];
72         snprintf(tmp, sizeof(tmp), "%i", value);
73         strcat(line, name);
74         strcat(line, tmp);
75 }
76
77 static char *username()
78 {
79         char *tmp;
80
81         tmp = getlogin();
82         if (!tmp) {
83                 struct passwd *user;
84
85                 user = getpwuid(getuid());
86                 if (!user) {
87                         wsyserror(_("could not get password entry for UID %i"), getuid());
88                         return NULL;
89                 }
90                 if (!user->pw_name) {
91                         return NULL;
92                 } else {
93                         return user->pw_name;
94                 }
95         }
96         return tmp;
97 }
98
99 char *MakeCPPArgs(char *path)
100 {
101         int i;
102         char buffer[MAXLINE], *buf, *line;
103         Visual *visual;
104         char *tmp;
105
106         line = wmalloc(MAXLINE);
107         *line = 0;
108         i = 1;
109         if ((buf = getenv("HOSTNAME")) != NULL) {
110                 if (buf[0] == '(') {
111                         wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"), buf);
112                 } else
113                         putdef(line, " -DHOST=", buf);
114         } else if ((buf = getenv("HOST")) != NULL) {
115                 if (buf[0] == '(') {
116                         wwarning(_("your machine is misconfigured. HOST is set to %s"), buf);
117                 } else
118                         putdef(line, " -DHOST=", buf);
119         }
120         buf = username();
121         if (buf)
122                 putdef(line, " -DUSER=", buf);
123         putidef(line, " -DUID=", getuid());
124         buf = XDisplayName(DisplayString(dpy));
125         putdef(line, " -DDISPLAY=", buf);
126         putdef(line, " -DWM_VERSION=", VERSION);
127
128         visual = DefaultVisual(dpy, DefaultScreen(dpy));
129         putidef(line, " -DVISUAL=", visual->class);
130
131         putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy)));
132
133         putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy)));
134         putidef(line, " -DSCR_HEIGHT=", HeightOfScreen(DefaultScreenOfDisplay(dpy)));
135
136         /* put the dir where the menu is being read from to the
137          * search path */
138         if (path) {
139                 tmp = wstrdup(path);
140                 buf = strchr(tmp + 1, ' ');
141                 if (buf) {
142                         *buf = 0;
143                 }
144                 buf = strrchr(tmp, '/');
145                 if (buf) {
146                         *buf = 0;       /* trunc filename */
147                         putdef(line, " -I", tmp);
148                 }
149                 wfree(tmp);
150         }
151
152         /* this should be done just once, but it works this way */
153         strcpy(buffer, DEF_CONFIG_PATHS);
154         buf = strtok(buffer, ":");
155
156         do {
157                 char fullpath[MAXLINE];
158
159                 if (buf[0] != '~') {
160                         strcpy(fullpath, buf);
161                 } else {
162                         char *wgethomedir();
163                         /* home is statically allocated. Don't free it! */
164                         char *home = wgethomedir();
165
166                         strcpy(fullpath, home);
167                         strcat(fullpath, &(buf[1]));
168                 }
169
170                 putdef(line, " -I", fullpath);
171
172         } while ((buf = strtok(NULL, ":")) != NULL);
173
174 #undef arg
175 #ifdef DEBUG
176         puts("CPP ARGS");
177         puts(line);
178 #endif
179         return line;
180 }
181 #endif                          /* USECPP */
182
183 #if 0
184 /*
185  * Is win2 below win1?
186  */
187 static Bool isBelow(WWindow * win1, WWindow * win2)
188 {
189         int i;
190         WCoreWindow *tmp;
191
192         tmp = win1->frame->core->stacking->under;
193         while (tmp) {
194                 if (tmp == win2->frame->core)
195                         return True;
196                 tmp = tmp->stacking->under;
197         }
198
199         for (i = win1->frame->core->stacking->window_level - 1; i >= 0; i--) {
200                 tmp = win1->screen_ptr->stacking_list[i];
201                 while (tmp) {
202                         if (tmp == win2->frame->core)
203                                 return True;
204                         tmp = tmp->stacking->under;
205                 }
206         }
207         return True;
208 }
209 #endif
210
211 /*
212  *  XFetchName Wrapper
213  *
214  */
215 Bool wFetchName(dpy, win, winname)
216 Display *dpy;
217 Window win;
218 char **winname;
219 {
220         XTextProperty text_prop;
221         char **list;
222         int num;
223
224         if (XGetWMName(dpy, win, &text_prop)) {
225                 if (text_prop.value && text_prop.nitems > 0) {
226                         if (text_prop.encoding == XA_STRING) {
227                                 *winname = wstrdup((char *)text_prop.value);
228                                 XFree(text_prop.value);
229                         } else {
230                                 text_prop.nitems = strlen((char *)text_prop.value);
231                                 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
232                                     Success && num > 0 && *list) {
233                                         XFree(text_prop.value);
234                                         *winname = wstrdup(*list);
235                                         XFreeStringList(list);
236                                 } else {
237                                         *winname = wstrdup((char *)text_prop.value);
238                                         XFree(text_prop.value);
239                                 }
240                         }
241                 } else {
242                         /* the title is set, but it was set to none */
243                         *winname = wstrdup("");
244                 }
245                 return True;
246         } else {
247                 /* the hint is probably not set */
248                 *winname = NULL;
249
250                 return False;
251         }
252 }
253
254 /*
255  *  XGetIconName Wrapper
256  *
257  */
258
259 Bool wGetIconName(dpy, win, iconname)
260 Display *dpy;
261 Window win;
262 char **iconname;
263 {
264         XTextProperty text_prop;
265         char **list;
266         int num;
267
268         if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value && text_prop.nitems > 0) {
269                 if (text_prop.encoding == XA_STRING)
270                         *iconname = (char *)text_prop.value;
271                 else {
272                         text_prop.nitems = strlen((char *)text_prop.value);
273                         if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success && num > 0 && *list) {
274                                 XFree(text_prop.value);
275                                 *iconname = wstrdup(*list);
276                                 XFreeStringList(list);
277                         } else
278                                 *iconname = (char *)text_prop.value;
279                 }
280                 return True;
281         }
282         *iconname = NULL;
283         return False;
284 }
285
286 static void eatExpose()
287 {
288         XEvent event, foo;
289
290         /* compress all expose events into a single one */
291
292         if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
293                 /* ignore other exposure events for this window */
294                 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask, &foo)) ;
295                 /* eat exposes for other windows */
296                 eatExpose();
297
298                 event.xexpose.count = 0;
299                 XPutBackEvent(dpy, &event);
300         }
301 }
302
303 void SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
304 {
305         time_t time0 = time(NULL);
306         float dx, dy, x = from_x, y = from_y, sx, sy, px, py;
307         int dx_is_bigger = 0;
308
309         /* animation parameters */
310         static struct {
311                 int delay;
312                 int steps;
313                 int slowdown;
314         } apars[5] = {
315                 {
316                 ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF}, {
317                 ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F}, {
318                 ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M}, {
319                 ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S}, {
320         ICON_SLIDE_DELAY_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}};
321
322         dx = (float)(to_x - from_x);
323         dy = (float)(to_y - from_y);
324         sx = (dx == 0 ? 0 : fabs(dx) / dx);
325         sy = (dy == 0 ? 0 : fabs(dy) / dy);
326
327         if (fabs(dx) > fabs(dy)) {
328                 dx_is_bigger = 1;
329         }
330
331         if (dx_is_bigger) {
332                 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
333                 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
334                         px = apars[(int)wPreferences.icon_slide_speed].steps;
335                 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
336                         px = -apars[(int)wPreferences.icon_slide_speed].steps;
337                 py = (sx == 0 ? 0 : px * dy / dx);
338         } else {
339                 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
340                 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
341                         py = apars[(int)wPreferences.icon_slide_speed].steps;
342                 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
343                         py = -apars[(int)wPreferences.icon_slide_speed].steps;
344                 px = (sy == 0 ? 0 : py * dx / dy);
345         }
346
347         while (x != to_x || y != to_y) {
348                 x += px;
349                 y += py;
350                 if ((px < 0 && (int)x < to_x) || (px > 0 && (int)x > to_x))
351                         x = (float)to_x;
352                 if ((py < 0 && (int)y < to_y) || (py > 0 && (int)y > to_y))
353                         y = (float)to_y;
354
355                 if (dx_is_bigger) {
356                         px = px * (1.0 - 1 / (float)apars[(int)wPreferences.icon_slide_speed].slowdown);
357                         if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
358                                 px = apars[(int)wPreferences.icon_slide_speed].steps;
359                         else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
360                                 px = -apars[(int)wPreferences.icon_slide_speed].steps;
361                         py = (sx == 0 ? 0 : px * dy / dx);
362                 } else {
363                         py = py * (1.0 - 1 / (float)apars[(int)wPreferences.icon_slide_speed].slowdown);
364                         if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
365                                 py = apars[(int)wPreferences.icon_slide_speed].steps;
366                         else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
367                                 py = -apars[(int)wPreferences.icon_slide_speed].steps;
368                         px = (sy == 0 ? 0 : py * dx / dy);
369                 }
370
371                 XMoveWindow(dpy, win, (int)x, (int)y);
372                 XFlush(dpy);
373                 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
374                         wusleep(apars[(int)wPreferences.icon_slide_speed].delay * 1000L);
375                 } else {
376                         wusleep(10);
377                 }
378                 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
379                         break;
380         }
381         XMoveWindow(dpy, win, to_x, to_y);
382
383         XSync(dpy, 0);
384         /* compress expose events */
385         eatExpose();
386 }
387
388 char *ShrinkString(WMFont * font, char *string, int width)
389 {
390         int w, w1 = 0;
391         int p;
392         char *pos;
393         char *text;
394         int p1, p2, t;
395
396         p = strlen(string);
397         w = WMWidthOfString(font, string, p);
398         text = wmalloc(strlen(string) + 8);
399         strcpy(text, string);
400         if (w <= width)
401                 return text;
402
403         pos = strchr(text, ' ');
404         if (!pos)
405                 pos = strchr(text, ':');
406
407         if (pos) {
408                 *pos = 0;
409                 p = strlen(text);
410                 w1 = WMWidthOfString(font, text, p);
411                 if (w1 > width) {
412                         w1 = 0;
413                         p = 0;
414                         *pos = ' ';
415                         *text = 0;
416                 } else {
417                         *pos = 0;
418                         width -= w1;
419                         p++;
420                 }
421                 string += p;
422                 p = strlen(string);
423         } else {
424                 *text = 0;
425         }
426         strcat(text, "...");
427         width -= WMWidthOfString(font, "...", 3);
428         pos = string;
429         p1 = 0;
430         p2 = p;
431         t = (p2 - p1) / 2;
432         while (p2 > p1 && p1 != t) {
433                 w = WMWidthOfString(font, &string[p - t], t);
434                 if (w > width) {
435                         p2 = t;
436                         t = p1 + (p2 - p1) / 2;
437                 } else if (w < width) {
438                         p1 = t;
439                         t = p1 + (p2 - p1) / 2;
440                 } else
441                         p2 = p1 = t;
442         }
443         strcat(text, &string[p - p1]);
444
445         return text;
446 }
447
448 char *FindImage(char *paths, char *file)
449 {
450         char *tmp, *path;
451
452         tmp = strrchr(file, ':');
453         if (tmp) {
454                 *tmp = 0;
455                 path = wfindfile(paths, file);
456                 *tmp = ':';
457         }
458         if (!tmp || !path) {
459                 path = wfindfile(paths, file);
460         }
461
462         return path;
463 }
464
465 static void timeoutHandler(void *data)
466 {
467         *(int *)data = 1;
468 }
469
470 static char *getTextSelection(WScreen * screen, Atom selection)
471 {
472         int buffer = -1;
473
474         switch (selection) {
475         case XA_CUT_BUFFER0:
476                 buffer = 0;
477                 break;
478         case XA_CUT_BUFFER1:
479                 buffer = 1;
480                 break;
481         case XA_CUT_BUFFER2:
482                 buffer = 2;
483                 break;
484         case XA_CUT_BUFFER3:
485                 buffer = 3;
486                 break;
487         case XA_CUT_BUFFER4:
488                 buffer = 4;
489                 break;
490         case XA_CUT_BUFFER5:
491                 buffer = 5;
492                 break;
493         case XA_CUT_BUFFER6:
494                 buffer = 6;
495                 break;
496         case XA_CUT_BUFFER7:
497                 buffer = 7;
498                 break;
499         }
500         if (buffer >= 0) {
501                 char *data;
502                 int size;
503
504                 data = XFetchBuffer(dpy, &size, buffer);
505
506                 return data;
507         } else {
508                 char *data;
509                 int bits;
510                 Atom rtype;
511                 unsigned long len, bytes;
512                 WMHandlerID timer;
513                 int timeout = 0;
514                 XEvent ev;
515                 static Atom clipboard = 0;
516
517                 if (!clipboard)
518                         clipboard = XInternAtom(dpy, "CLIPBOARD", False);
519
520                 XDeleteProperty(dpy, screen->info_window, clipboard);
521
522                 XConvertSelection(dpy, selection, XA_STRING, clipboard, screen->info_window, CurrentTime);
523
524                 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
525
526                 while (!XCheckTypedWindowEvent(dpy, screen->info_window, SelectionNotify, &ev) && !timeout) ;
527
528                 if (!timeout) {
529                         WMDeleteTimerHandler(timer);
530                 } else {
531                         wwarning("selection retrieval timed out");
532                         return NULL;
533                 }
534
535                 /* nobody owns the selection or the current owner has
536                  * nothing to do with what we need */
537                 if (ev.xselection.property == None) {
538                         return NULL;
539                 }
540
541                 if (XGetWindowProperty(dpy, screen->info_window,
542                                        clipboard, 0, 1024,
543                                        False, XA_STRING, &rtype, &bits, &len,
544                                        &bytes, (unsigned char **)&data) != Success) {
545                         return NULL;
546                 }
547                 if (rtype != XA_STRING || bits != 8) {
548                         wwarning("invalid data in text selection");
549                         if (data)
550                                 XFree(data);
551                         return NULL;
552                 }
553                 return data;
554         }
555 }
556
557 static char *getselection(WScreen * scr)
558 {
559         char *tmp;
560
561         tmp = getTextSelection(scr, XA_PRIMARY);
562         if (!tmp)
563                 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
564         return tmp;
565 }
566
567 static char*
568 parseuserinputpart(char *line, int *ptr, char *endchars)
569 {
570         int depth = 0, begin;
571         char *value = NULL;
572         begin = ++*ptr;
573
574         while(line[*ptr] != '\0') {
575                 if(line[*ptr] == '(') {
576                         ++depth;
577                 } else if(depth > 0 && line[*ptr] == ')') {
578                         --depth;
579                 } else if(depth == 0 && strchr(endchars, line[*ptr]) != NULL) {
580                         value = wmalloc(*ptr - begin + 1);
581                         strncpy(value, line + begin, *ptr - begin);
582                         value[*ptr - begin] = '\0';
583                         break;
584                 }
585                 ++*ptr;
586         }
587
588         return value;
589 }
590
591 static char*
592 getuserinput(WScreen *scr, char *line, int *ptr, Bool advanced)
593 {
594     char *ret = NULL, *title = NULL, *prompt = NULL, *name = NULL;
595     int rv;
596
597     if(line[*ptr] == '(')
598         title = parseuserinputpart(line, ptr, ",)");
599     if(title != NULL && line[*ptr] == ',')
600         prompt = parseuserinputpart(line, ptr, ",)");
601     if(prompt != NULL && line[*ptr] == ',')
602         name = parseuserinputpart(line, ptr, ")");
603
604     if(advanced)
605         rv = wAdvancedInputDialog(scr,
606                 title ? gettext(title):_("Program Arguments"),
607                 prompt ? gettext(prompt):_("Enter command arguments:"),
608                 name, &ret);
609     else
610         rv = wInputDialog(scr,
611                 title ? gettext(title):_("Program Arguments"),
612                 prompt ? gettext(prompt):_("Enter command arguments:"),
613                 &ret);
614
615     if(title) wfree(title);
616     if(prompt) wfree(prompt);
617     if(name) wfree(name);
618
619     return rv ? ret : NULL;
620 }
621
622 #define S_NORMAL 0
623 #define S_ESCAPE 1
624 #define S_OPTION 2
625
626 /*
627  * state        input   new-state       output
628  * NORMAL       %       OPTION          <nil>
629  * NORMAL       \       ESCAPE          <nil>
630  * NORMAL       etc.    NORMAL          <input>
631  * ESCAPE       any     NORMAL          <input>
632  * OPTION       s       NORMAL          <selection buffer>
633  * OPTION       w       NORMAL          <selected window id>
634  * OPTION       a       NORMAL          <input text>
635  * OPTION       d       NORMAL          <OffiX DND selection object>
636  * OPTION       W       NORMAL          <current workspace>
637  * OPTION       etc.    NORMAL          %<input>
638  */
639 #define TMPBUFSIZE 64
640 char *ExpandOptions(WScreen * scr, char *cmdline)
641 {
642         int ptr, optr, state, len, olen;
643         char *out, *nout;
644         char *selection = NULL;
645         char *user_input = NULL;
646 #ifdef XDND
647         char *dropped_thing = NULL;
648 #endif
649         char tmpbuf[TMPBUFSIZE];
650         int slen;
651
652         len = strlen(cmdline);
653         olen = len + 1;
654         out = malloc(olen);
655         if (!out) {
656                 wwarning(_("out of memory during expansion of \"%s\""));
657                 return NULL;
658         }
659         *out = 0;
660         ptr = 0;                /* input line pointer */
661         optr = 0;               /* output line pointer */
662         state = S_NORMAL;
663         while (ptr < len) {
664                 switch (state) {
665                 case S_NORMAL:
666                         switch (cmdline[ptr]) {
667                         case '\\':
668                                 state = S_ESCAPE;
669                                 break;
670                         case '%':
671                                 state = S_OPTION;
672                                 break;
673                         default:
674                                 state = S_NORMAL;
675                                 out[optr++] = cmdline[ptr];
676                                 break;
677                         }
678                         break;
679                 case S_ESCAPE:
680                         switch (cmdline[ptr]) {
681                         case 'n':
682                                 out[optr++] = 10;
683                                 break;
684
685                         case 'r':
686                                 out[optr++] = 13;
687                                 break;
688
689                         case 't':
690                                 out[optr++] = 9;
691                                 break;
692
693                         default:
694                                 out[optr++] = cmdline[ptr];
695                         }
696                         state = S_NORMAL;
697                         break;
698                 case S_OPTION:
699                         state = S_NORMAL;
700                         switch (cmdline[ptr]) {
701                         case 'w':
702                                 if (scr->focused_window && scr->focused_window->flags.focused) {
703                                         snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
704                                                  (unsigned int)scr->focused_window->client_win);
705                                         slen = strlen(tmpbuf);
706                                         olen += slen;
707                                         nout = realloc(out, olen);
708                                         if (!nout) {
709                                                 wwarning(_("out of memory during expansion of \"%w\""));
710                                                 goto error;
711                                         }
712                                         out = nout;
713                                         strcat(out, tmpbuf);
714                                         optr += slen;
715                                 } else {
716                                         out[optr++] = ' ';
717                                 }
718                                 break;
719
720                         case 'W':
721                                 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", (unsigned int)scr->current_workspace + 1);
722                                 slen = strlen(tmpbuf);
723                                 olen += slen;
724                                 nout = realloc(out, olen);
725                                 if (!nout) {
726                                         wwarning(_("out of memory during expansion of \"%W\""));
727                                         goto error;
728                                 }
729                                 out = nout;
730                                 strcat(out, tmpbuf);
731                                 optr += slen;
732                                 break;
733
734                         case 'a':
735                         case 'A':
736                                 ptr++;
737                                 user_input = getuserinput(scr, cmdline, &ptr, cmdline[ptr-1] == 'A');
738                                 if (user_input) {
739                                         slen = strlen(user_input);
740                                         olen += slen;
741                                         nout = realloc(out, olen);
742                                         if (!nout) {
743                                                 wwarning(_("out of memory during expansion of \"%a\""));
744                                                 goto error;
745                                         }
746                                         out = nout;
747                                         strcat(out, user_input);
748                                         optr += slen;
749                                 } else {
750                                         /* Not an error, but user has Canceled the dialog box.
751                                          * This will make the command to not be performed. */
752                                         goto error;
753                                 }
754                                 break;
755
756 #ifdef XDND
757                         case 'd':
758                                 if (scr->xdestring) {
759                                         dropped_thing = wstrdup(scr->xdestring);
760                                 }
761                                 if (!dropped_thing) {
762                                         dropped_thing = get_dnd_selection(scr);
763                                 }
764                                 if (!dropped_thing) {
765                                         scr->flags.dnd_data_convertion_status = 1;
766                                         goto error;
767                                 }
768                                 slen = strlen(dropped_thing);
769                                 olen += slen;
770                                 nout = realloc(out, olen);
771                                 if (!nout) {
772                                         wwarning(_("out of memory during expansion of \"%d\""));
773                                         goto error;
774                                 }
775                                 out = nout;
776                                 strcat(out, dropped_thing);
777                                 optr += slen;
778                                 break;
779 #endif                          /* XDND */
780
781                         case 's':
782                                 if (!selection) {
783                                         selection = getselection(scr);
784                                 }
785                                 if (!selection) {
786                                         wwarning(_("selection not available"));
787                                         goto error;
788                                 }
789                                 slen = strlen(selection);
790                                 olen += slen;
791                                 nout = realloc(out, olen);
792                                 if (!nout) {
793                                         wwarning(_("out of memory during expansion of \"%s\""));
794                                         goto error;
795                                 }
796                                 out = nout;
797                                 strcat(out, selection);
798                                 optr += slen;
799                                 break;
800
801                         default:
802                                 out[optr++] = '%';
803                                 out[optr++] = cmdline[ptr];
804                         }
805                         break;
806                 }
807                 out[optr] = 0;
808                 ptr++;
809         }
810         if (selection)
811                 XFree(selection);
812         return out;
813
814  error:
815         wfree(out);
816         if (selection)
817                 XFree(selection);
818         return NULL;
819 }
820
821 void ParseWindowName(WMPropList * value, char **winstance, char **wclass, char *where)
822 {
823         char *name;
824
825         *winstance = *wclass = NULL;
826
827         if (!WMIsPLString(value)) {
828                 wwarning(_("bad window name value in %s state info"), where);
829                 return;
830         }
831
832         name = WMGetFromPLString(value);
833         if (!name || strlen(name) == 0) {
834                 wwarning(_("bad window name value in %s state info"), where);
835                 return;
836         }
837
838         UnescapeWM_CLASS(name, winstance, wclass);
839 }
840
841 #if 0
842 static char *keysymToString(KeySym keysym, unsigned int state)
843 {
844         XKeyEvent kev;
845         char *buf = wmalloc(20);
846         int count;
847
848         kev.display = dpy;
849         kev.type = KeyPress;
850         kev.send_event = False;
851         kev.window = DefaultRootWindow(dpy);
852         kev.root = DefaultRootWindow(dpy);
853         kev.same_screen = True;
854         kev.subwindow = kev.root;
855         kev.serial = 0x12344321;
856         kev.time = CurrentTime;
857         kev.state = state;
858         kev.keycode = XKeysymToKeycode(dpy, keysym);
859         count = XLookupString(&kev, buf, 19, NULL, NULL);
860         buf[count] = 0;
861
862         return buf;
863 }
864 #endif
865
866 char *GetShortcutString(char *text)
867 {
868         char *buffer = NULL;
869         char *k;
870         int modmask = 0;
871         /*    KeySym ksym; */
872         int control = 0;
873         char *tmp;
874
875         tmp = text = wstrdup(text);
876
877         /* get modifiers */
878         while ((k = strchr(text, '+')) != NULL) {
879                 int mod;
880
881                 *k = 0;
882                 mod = wXModifierFromKey(text);
883                 if (mod < 0) {
884                         return wstrdup("bug");
885                 }
886
887                 modmask |= mod;
888
889                 if (strcasecmp(text, "Meta") == 0) {
890                         buffer = wstrappend(buffer, "M+");
891                 } else if (strcasecmp(text, "Alt") == 0) {
892                         buffer = wstrappend(buffer, "A+");
893                 } else if (strcasecmp(text, "Shift") == 0) {
894                         buffer = wstrappend(buffer, "Sh+");
895                 } else if (strcasecmp(text, "Mod1") == 0) {
896                         buffer = wstrappend(buffer, "M1+");
897                 } else if (strcasecmp(text, "Mod2") == 0) {
898                         buffer = wstrappend(buffer, "M2+");
899                 } else if (strcasecmp(text, "Mod3") == 0) {
900                         buffer = wstrappend(buffer, "M3+");
901                 } else if (strcasecmp(text, "Mod4") == 0) {
902                         buffer = wstrappend(buffer, "M4+");
903                 } else if (strcasecmp(text, "Mod5") == 0) {
904                         buffer = wstrappend(buffer, "M5+");
905                 } else if (strcasecmp(text, "Control") == 0) {
906                         control = 1;
907                 } else {
908                         buffer = wstrappend(buffer, text);
909                 }
910                 text = k + 1;
911         }
912
913         if (control) {
914                 buffer = wstrappend(buffer, "^");
915         }
916         buffer = wstrappend(buffer, text);
917
918         /* get key */
919         /*    ksym = XStringToKeysym(text);
920            tmp = keysymToString(ksym, modmask);
921            puts(tmp);
922            buffer = wstrappend(buffer, tmp);
923          */
924         wfree(tmp);
925
926         return buffer;
927 }
928
929 char *EscapeWM_CLASS(char *name, char *class)
930 {
931         char *ret;
932         char *ename = NULL, *eclass = NULL;
933         int i, j, l;
934
935         if (!name && !class)
936                 return NULL;
937
938         if (name) {
939                 l = strlen(name);
940                 ename = wmalloc(l * 2 + 1);
941                 j = 0;
942                 for (i = 0; i < l; i++) {
943                         if (name[i] == '\\') {
944                                 ename[j++] = '\\';
945                         } else if (name[i] == '.') {
946                                 ename[j++] = '\\';
947                         }
948                         ename[j++] = name[i];
949                 }
950                 ename[j] = 0;
951         }
952         if (class) {
953                 l = strlen(class);
954                 eclass = wmalloc(l * 2 + 1);
955                 j = 0;
956                 for (i = 0; i < l; i++) {
957                         if (class[i] == '\\') {
958                                 eclass[j++] = '\\';
959                         } else if (class[i] == '.') {
960                                 eclass[j++] = '\\';
961                         }
962                         eclass[j++] = class[i];
963                 }
964                 eclass[j] = 0;
965         }
966
967         if (ename && eclass) {
968                 int len = strlen(ename) + strlen(eclass) + 4;
969                 ret = wmalloc(len);
970                 snprintf(ret, len, "%s.%s", ename, eclass);
971                 wfree(ename);
972                 wfree(eclass);
973         } else if (ename) {
974                 ret = wstrdup(ename);
975                 wfree(ename);
976         } else {
977                 ret = wstrdup(eclass);
978                 wfree(eclass);
979         }
980
981         return ret;
982 }
983
984 void UnescapeWM_CLASS(char *str, char **name, char **class)
985 {
986         int i, j, k, dot;
987
988         j = strlen(str);
989         *name = wmalloc(j);
990         **name = 0;
991         *class = wmalloc(j);
992         **class = 0;
993
994         /* separate string in 2 parts */
995         dot = -1;
996         for (i = 0; i < j; i++) {
997                 if (str[i] == '\\') {
998                         i++;
999                         continue;
1000                 } else if (str[i] == '.') {
1001                         dot = i;
1002                         break;
1003                 }
1004         }
1005
1006         /* unescape strings */
1007         for (i = 0, k = 0; i < dot; i++) {
1008                 if (str[i] == '\\') {
1009                         continue;
1010                 } else {
1011                         (*name)[k++] = str[i];
1012                 }
1013         }
1014         (*name)[k] = 0;
1015
1016         for (i = dot + 1, k = 0; i < j; i++) {
1017                 if (str[i] == '\\') {
1018                         continue;
1019                 } else {
1020                         (*class)[k++] = str[i];
1021                 }
1022         }
1023         (*class)[k] = 0;
1024
1025         if (!*name) {
1026                 wfree(*name);
1027                 *name = NULL;
1028         }
1029         if (!*class) {
1030                 wfree(*class);
1031                 *class = NULL;
1032         }
1033 }
1034
1035 void SendHelperMessage(WScreen * scr, char type, int workspace, char *msg)
1036 {
1037         char *buffer;
1038         int len;
1039         int i;
1040         char buf[16];
1041
1042         if (!scr->flags.backimage_helper_launched) {
1043                 return;
1044         }
1045
1046         len = (msg ? strlen(msg) : 0) + (workspace >= 0 ? 4 : 0) + 1;
1047         buffer = wmalloc(len + 5);
1048         snprintf(buf, sizeof(buf), "%4i", len);
1049         memcpy(buffer, buf, 4);
1050         buffer[4] = type;
1051         i = 5;
1052         if (workspace >= 0) {
1053                 snprintf(buf, sizeof(buf), "%4i", workspace);
1054                 memcpy(&buffer[i], buf, 4);
1055                 i += 4;
1056                 buffer[i] = 0;
1057         }
1058         if (msg)
1059                 strcpy(&buffer[i], msg);
1060
1061         if (write(scr->helper_fd, buffer, len + 4) < 0) {
1062                 wsyserror(_("could not send message to background image helper"));
1063         }
1064         wfree(buffer);
1065 }
1066
1067 Bool UpdateDomainFile(WDDomain * domain)
1068 {
1069         struct stat stbuf;
1070         char path[PATH_MAX];
1071         WMPropList *shared_dict, *dict;
1072         Bool result, freeDict = False;
1073
1074         dict = domain->dictionary;
1075         if (WMIsPLDictionary(domain->dictionary)) {
1076                 /* retrieve global system dictionary */
1077                 snprintf(path, sizeof(path), "%s/WindowMaker/%s", SYSCONFDIR, domain->domain_name);
1078                 if (stat(path, &stbuf) >= 0) {
1079                         shared_dict = WMReadPropListFromFile(path);
1080                         if (shared_dict) {
1081                                 if (WMIsPLDictionary(shared_dict)) {
1082                                         freeDict = True;
1083                                         dict = WMDeepCopyPropList(domain->dictionary);
1084                                         WMSubtractPLDictionaries(dict, shared_dict, True);
1085                                 }
1086                                 WMReleasePropList(shared_dict);
1087                         }
1088                 }
1089         }
1090
1091         result = WMWritePropListToFile(dict, domain->path, True);
1092
1093         if (freeDict) {
1094                 WMReleasePropList(dict);
1095         }
1096
1097         return result;
1098 }
1099
1100 char *StrConcatDot(char *a, char *b)
1101 {
1102         int len;
1103         char *str;
1104
1105         if (!a)
1106                 a = "";
1107         if (!b)
1108                 b = "";
1109
1110         len = strlen(a) + strlen(b) + 4;
1111         str = wmalloc(len);
1112
1113         snprintf(str, len, "%s.%s", a, b);
1114
1115         return str;
1116 }
1117
1118 #define MAX_CMD_SIZE 4096
1119
1120 Bool GetCommandForPid(int pid, char ***argv, int *argc)
1121 {
1122         static char buf[MAX_CMD_SIZE];
1123         FILE *fPtr;
1124         int count, i, j;
1125         Bool ok = False;
1126
1127         sprintf(buf, "/proc/%d/cmdline", pid);
1128         fPtr = fopen(buf, "r");
1129         if (fPtr) {
1130                 count = read(fileno(fPtr), buf, MAX_CMD_SIZE);
1131                 if (count > 0) {
1132                         buf[count - 1] = 0;
1133                         for (i = 0, *argc = 0; i < count; i++) {
1134                                 if (buf[i] == 0) {
1135                                         (*argc)++;
1136                                 }
1137                         }
1138                         if ((*argc) == 0) {
1139                                 *argv = NULL;
1140                                 ok = False;
1141                         } else {
1142                                 *argv = (char **)wmalloc(sizeof(char *) * (*argc));
1143                                 (*argv)[0] = buf;
1144                                 for (i = 0, j = 1; i < count; i++) {
1145                                         if (buf[i] != 0)
1146                                                 continue;
1147                                         if (i < count - 1) {
1148                                                 (*argv)[j++] = &buf[i + 1];
1149                                         }
1150                                         if (j == *argc) {
1151                                                 break;
1152                                         }
1153                                 }
1154                                 ok = True;
1155                         }
1156                 }
1157                 fclose(fPtr);
1158         }
1159
1160         return ok;
1161 }
1162
1163 static char *getCommandForWindow(Window win, int elements)
1164 {
1165         char **argv, *command = NULL;
1166         int argc;
1167
1168         if (XGetCommand(dpy, win, &argv, &argc)) {
1169                 if (argc > 0 && argv != NULL) {
1170                         if (elements == 0)
1171                                 elements = argc;
1172                         command = wtokenjoin(argv, WMIN(argc, elements));
1173                         if (command[0] == 0) {
1174                                 wfree(command);
1175                                 command = NULL;
1176                         }
1177                 }
1178                 if (argv) {
1179                         XFreeStringList(argv);
1180                 }
1181         }
1182
1183         return command;
1184 }
1185
1186 /* Free result when done */
1187 char *GetCommandForWindow(Window win)
1188 {
1189         return getCommandForWindow(win, 0);
1190 }
1191
1192 /* Free result when done */
1193 char *GetProgramNameForWindow(Window win)
1194 {
1195         return getCommandForWindow(win, 1);
1196 }