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 }