- Fixed crashing bug in menu.c
[wmaker-crm.git] / src / misc.c
blobf27e1bf5631e8f8241aca05cd5c52c5942cb9d30
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.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 * USA.
21 #include "wconfig.h"
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/Xatom.h>
26 #include <sys/stat.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <stdarg.h>
32 #include <pwd.h>
33 #include <math.h>
34 #include <time.h>
36 #include <WINGs/WUtil.h>
37 #include <wraster.h>
40 #include "WindowMaker.h"
41 #include "GNUstep.h"
42 #include "screen.h"
43 #include "wcore.h"
44 #include "window.h"
45 #include "framewin.h"
46 #include "funcs.h"
47 #include "defaults.h"
48 #include "dialog.h"
49 #include "xutil.h"
50 #include "xmodifier.h"
53 /**** global variables *****/
55 extern char *DisplayName;
57 extern WPreferences wPreferences;
59 extern Time LastTimestamp;
61 #ifdef OFFIX_DND
62 extern Atom _XA_DND_SELECTION;
63 #endif
66 #ifdef USECPP
67 static void
68 putdef(char *line, char *name, char *value)
70 if (!value) {
71 wwarning(_("could not define value for %s for cpp"), name);
72 return;
74 strcat(line, name);
75 strcat(line, value);
80 static void
81 putidef(char *line, char *name, int value)
83 char tmp[64];
84 snprintf(tmp, sizeof(tmp), "%i", value);
85 strcat(line, name);
86 strcat(line, tmp);
90 static char*
91 username()
93 char *tmp;
95 tmp = getlogin();
96 if (!tmp) {
97 struct passwd *user;
99 user = getpwuid(getuid());
100 if (!user) {
101 wsyserror(_("could not get password entry for UID %i"), getuid());
102 return NULL;
104 if (!user->pw_name) {
105 return NULL;
106 } else {
107 return user->pw_name;
110 return tmp;
113 char *
114 MakeCPPArgs(char *path)
116 int i;
117 char buffer[MAXLINE], *buf, *line;
118 Visual *visual;
119 char *tmp;
121 line = wmalloc(MAXLINE);
122 *line = 0;
123 i=1;
124 if ((buf=getenv("HOSTNAME"))!=NULL) {
125 if (buf[0]=='(') {
126 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"),
127 buf);
128 } else
129 putdef(line, " -DHOST=", buf);
130 } else if ((buf=getenv("HOST"))!=NULL) {
131 if (buf[0]=='(') {
132 wwarning(_("your machine is misconfigured. HOST is set to %s"),
133 buf);
134 } else
135 putdef(line, " -DHOST=", buf);
137 buf = username();
138 if (buf)
139 putdef(line, " -DUSER=", buf);
140 putidef(line, " -DUID=", getuid());
141 buf = XDisplayName(DisplayString(dpy));
142 putdef(line, " -DDISPLAY=", buf);
143 putdef(line, " -DWM_VERSION=", VERSION);
145 visual = DefaultVisual(dpy, DefaultScreen(dpy));
146 putidef(line, " -DVISUAL=", visual->class);
148 putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy)));
150 putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy)));
151 putidef(line, " -DSCR_HEIGHT=",
152 HeightOfScreen(DefaultScreenOfDisplay(dpy)));
154 /* put the dir where the menu is being read from to the
155 * search path */
156 if (path) {
157 tmp = wstrdup(path);
158 buf = strchr(tmp+1, ' ');
159 if (buf) {
160 *buf = 0;
162 buf = strrchr(tmp, '/');
163 if (buf) {
164 *buf = 0; /* trunc filename */
165 putdef(line, " -I", tmp);
167 wfree(tmp);
171 /* this should be done just once, but it works this way */
172 strcpy(buffer, DEF_CONFIG_PATHS);
173 buf = strtok(buffer, ":");
175 do {
176 char fullpath[MAXLINE];
178 if (buf[0]!='~') {
179 strcpy(fullpath, buf);
180 } else {
181 char * wgethomedir();
182 /* home is statically allocated. Don't free it! */
183 char *home = wgethomedir();
185 strcpy(fullpath, home);
186 strcat(fullpath, &(buf[1]));
189 putdef(line, " -I", fullpath);
191 } while ((buf = strtok(NULL, ":"))!=NULL);
193 #undef arg
194 #ifdef DEBUG
195 puts("CPP ARGS");
196 puts(line);
197 #endif
198 return line;
200 #endif /* USECPP */
205 #if 0
207 * Is win2 below win1?
209 static Bool
210 isBelow(WWindow *win1, WWindow *win2)
212 int i;
213 WCoreWindow *tmp;
215 tmp = win1->frame->core->stacking->under;
216 while (tmp) {
217 if (tmp == win2->frame->core)
218 return True;
219 tmp = tmp->stacking->under;
222 for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
223 tmp = win1->screen_ptr->stacking_list[i];
224 while (tmp) {
225 if (tmp == win2->frame->core)
226 return True;
227 tmp = tmp->stacking->under;
230 return True;
232 #endif
237 * XFetchName Wrapper
240 Bool
241 wFetchName(dpy, win, winname)
242 Display *dpy;
243 Window win;
244 char **winname;
246 XTextProperty text_prop;
247 char **list;
248 int num;
250 if (XGetWMName(dpy, win, &text_prop)) {
251 if (text_prop.value && text_prop.nitems > 0) {
252 if (text_prop.encoding == XA_STRING) {
253 *winname = wstrdup((char *)text_prop.value);
254 XFree(text_prop.value);
255 } else {
256 text_prop.nitems = strlen((char *)text_prop.value);
257 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
258 Success && num > 0 && *list) {
259 XFree(text_prop.value);
260 *winname = wstrdup(*list);
261 XFreeStringList(list);
262 } else {
263 *winname = wstrdup((char *)text_prop.value);
264 XFree(text_prop.value);
267 } else {
268 /* the title is set, but it was set to none */
269 *winname = wstrdup("");
271 return True;
272 } else {
273 /* the hint is probably not set */
274 *winname = NULL;
276 return False;
281 * XGetIconName Wrapper
285 Bool
286 wGetIconName(dpy, win, iconname)
287 Display *dpy;
288 Window win;
289 char **iconname;
291 XTextProperty text_prop;
292 char **list;
293 int num;
295 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
296 && text_prop.nitems > 0) {
297 if (text_prop.encoding == XA_STRING)
298 *iconname = (char *)text_prop.value;
299 else {
300 text_prop.nitems = strlen((char *)text_prop.value);
301 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
302 Success && num > 0 && *list) {
303 XFree(text_prop.value);
304 *iconname = wstrdup(*list);
305 XFreeStringList(list);
306 } else
307 *iconname = (char *)text_prop.value;
309 return True;
311 *iconname = NULL;
312 return False;
316 static void
317 eatExpose()
319 XEvent event, foo;
321 /* compress all expose events into a single one */
323 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
324 /* ignore other exposure events for this window */
325 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
326 &foo));
327 /* eat exposes for other windows */
328 eatExpose();
330 event.xexpose.count = 0;
331 XPutBackEvent(dpy, &event);
336 void
337 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
339 time_t time0 = time(NULL);
340 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
341 int dx_is_bigger=0;
343 /* animation parameters */
344 static struct {
345 int delay;
346 int steps;
347 int slowdown;
348 } apars[5] = {
349 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
350 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
351 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
352 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
353 {ICON_SLIDE_DELAY_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}};
357 dx = (float)(to_x-from_x);
358 dy = (float)(to_y-from_y);
359 sx = (dx == 0 ? 0 : fabs(dx)/dx);
360 sy = (dy == 0 ? 0 : fabs(dy)/dy);
362 if (fabs(dx) > fabs(dy)) {
363 dx_is_bigger = 1;
366 if (dx_is_bigger) {
367 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
368 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
369 px = apars[(int)wPreferences.icon_slide_speed].steps;
370 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
371 px = -apars[(int)wPreferences.icon_slide_speed].steps;
372 py = (sx == 0 ? 0 : px*dy/dx);
373 } else {
374 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
375 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
376 py = apars[(int)wPreferences.icon_slide_speed].steps;
377 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
378 py = -apars[(int)wPreferences.icon_slide_speed].steps;
379 px = (sy == 0 ? 0 : py*dx/dy);
382 while (x != to_x || y != to_y) {
383 x += px;
384 y += py;
385 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
386 x = (float)to_x;
387 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
388 y = (float)to_y;
390 if (dx_is_bigger) {
391 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
392 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
393 px = apars[(int)wPreferences.icon_slide_speed].steps;
394 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
395 px = -apars[(int)wPreferences.icon_slide_speed].steps;
396 py = (sx == 0 ? 0 : px*dy/dx);
397 } else {
398 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
399 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
400 py = apars[(int)wPreferences.icon_slide_speed].steps;
401 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
402 py = -apars[(int)wPreferences.icon_slide_speed].steps;
403 px = (sy == 0 ? 0 : py*dx/dy);
406 XMoveWindow(dpy, win, (int)x, (int)y);
407 XFlush(dpy);
408 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
409 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
410 } else {
411 wusleep(10);
413 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
414 break;
416 XMoveWindow(dpy, win, to_x, to_y);
418 XSync(dpy, 0);
419 /* compress expose events */
420 eatExpose();
424 char*
425 ShrinkString(WMFont *font, char *string, int width)
427 int w, w1=0;
428 int p;
429 char *pos;
430 char *text;
431 int p1, p2, t;
433 if (wPreferences.multi_byte_text)
434 return wstrdup(string);
436 p = strlen(string);
437 w = WMWidthOfString(font, string, p);
438 text = wmalloc(strlen(string)+8);
439 strcpy(text, string);
440 if (w<=width)
441 return text;
443 pos = strchr(text, ' ');
444 if (!pos)
445 pos = strchr(text, ':');
447 if (pos) {
448 *pos = 0;
449 p = strlen(text);
450 w1 = WMWidthOfString(font, text, p);
451 if (w1 > width) {
452 w1 = 0;
453 p = 0;
454 *pos = ' ';
455 *text = 0;
456 } else {
457 *pos = 0;
458 width -= w1;
459 p++;
461 string += p;
462 p=strlen(string);
463 } else {
464 *text=0;
466 strcat(text, "...");
467 width -= WMWidthOfString(font, "...", 3);
468 pos = string;
469 p1=0;
470 p2=p;
471 t = (p2-p1)/2;
472 while (p2>p1 && p1!=t) {
473 w = WMWidthOfString(font, &string[p-t], t);
474 if (w>width) {
475 p2 = t;
476 t = p1+(p2-p1)/2;
477 } else if (w<width) {
478 p1 = t;
479 t = p1+(p2-p1)/2;
480 } else
481 p2=p1=t;
483 strcat(text, &string[p-p1]);
485 return text;
489 char*
490 FindImage(char *paths, char *file)
492 char *tmp, *path;
494 tmp = strrchr(file, ':');
495 if (tmp) {
496 *tmp = 0;
497 path = wfindfile(paths, file);
498 *tmp = ':';
500 if (!tmp || !path) {
501 path = wfindfile(paths, file);
504 return path;
508 static void
509 timeoutHandler(void *data)
511 *(int*)data = 1;
515 static char*
516 getTextSelection(WScreen *screen, Atom selection)
518 int buffer = -1;
520 switch (selection) {
521 case XA_CUT_BUFFER0:
522 buffer = 0;
523 break;
524 case XA_CUT_BUFFER1:
525 buffer = 1;
526 break;
527 case XA_CUT_BUFFER2:
528 buffer = 2;
529 break;
530 case XA_CUT_BUFFER3:
531 buffer = 3;
532 break;
533 case XA_CUT_BUFFER4:
534 buffer = 4;
535 break;
536 case XA_CUT_BUFFER5:
537 buffer = 5;
538 break;
539 case XA_CUT_BUFFER6:
540 buffer = 6;
541 break;
542 case XA_CUT_BUFFER7:
543 buffer = 7;
544 break;
546 if (buffer >= 0) {
547 char *data;
548 int size;
550 data = XFetchBuffer(dpy, &size, buffer);
552 return data;
553 } else {
554 char *data;
555 int bits;
556 Atom rtype;
557 unsigned long len, bytes;
558 WMHandlerID timer;
559 int timeout = 0;
560 XEvent ev;
561 static Atom clipboard = 0;
563 if (!clipboard)
564 clipboard = XInternAtom(dpy, "CLIPBOARD", False);
566 XDeleteProperty(dpy, screen->info_window, clipboard);
568 XConvertSelection(dpy, selection, XA_STRING,
569 clipboard, screen->info_window,
570 CurrentTime);
572 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
574 while (!XCheckTypedWindowEvent(dpy, screen->info_window,
575 SelectionNotify, &ev) && !timeout);
577 if (!timeout) {
578 WMDeleteTimerHandler(timer);
579 } else {
580 wwarning("selection retrieval timed out");
581 return NULL;
584 /* nobody owns the selection or the current owner has
585 * nothing to do with what we need */
586 if (ev.xselection.property == None) {
587 return NULL;
590 if (XGetWindowProperty(dpy, screen->info_window,
591 clipboard, 0, 1024,
592 False, XA_STRING, &rtype, &bits, &len,
593 &bytes, (unsigned char**)&data)!=Success) {
594 return NULL;
596 if (rtype!=XA_STRING || bits!=8) {
597 wwarning("invalid data in text selection");
598 if (data)
599 XFree(data);
600 return NULL;
602 return data;
606 static char*
607 getselection(WScreen *scr)
609 char *tmp;
611 tmp = getTextSelection(scr, XA_PRIMARY);
612 if (!tmp)
613 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
614 return tmp;
618 static char*
619 getuserinput(WScreen *scr, char *line, int *ptr)
621 char *ret;
622 char *title;
623 char *prompt;
624 int j, state;
625 int begin = 0;
626 #define BUFSIZE 512
627 char tbuffer[BUFSIZE], pbuffer[BUFSIZE];
630 title = _("Program Arguments");
631 prompt = _("Enter command arguments:");
632 ret = NULL;
634 #define _STARTING 0
635 #define _TITLE 1
636 #define _PROMPT 2
637 #define _DONE 3
639 state = _STARTING;
640 j = 0;
641 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
642 switch (state) {
643 case _STARTING:
644 if (line[*ptr]=='(') {
645 state = _TITLE;
646 begin = *ptr+1;
647 } else {
648 state = _DONE;
650 break;
652 case _TITLE:
653 if (j <= 0 && line[*ptr]==',') {
655 j = 0;
656 if (*ptr > begin) {
657 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE));
658 tbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0;
659 title = (char*)tbuffer;
661 begin = *ptr+1;
662 state = _PROMPT;
664 } else if (j <= 0 && line[*ptr]==')') {
666 if (*ptr > begin) {
667 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE));
668 tbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0;
669 title = (char*)tbuffer;
671 state = _DONE;
673 } else if (line[*ptr]=='(') {
674 j++;
675 } else if (line[*ptr]==')') {
676 j--;
679 break;
681 case _PROMPT:
682 if (line[*ptr]==')' && j==0) {
684 if (*ptr-begin > 1) {
685 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE));
686 pbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0;
687 prompt = (char*)pbuffer;
689 state = _DONE;
690 } else if (line[*ptr]=='(')
691 j++;
692 else if (line[*ptr]==')')
693 j--;
694 break;
697 (*ptr)--;
698 #undef _STARTING
699 #undef _TITLE
700 #undef _PROMPT
701 #undef _DONE
703 if (!wInputDialog(scr, title, prompt, &ret))
704 return NULL;
705 else
706 return ret;
710 #ifdef OFFIX_DND
711 static char*
712 get_dnd_selection(WScreen *scr)
714 XTextProperty text_ret;
715 int result;
716 char **list;
717 char *flat_string;
718 int count;
720 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
722 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
723 || text_ret.format==0 || text_ret.nitems == 0) {
724 wwarning(_("unable to get dropped data from DND drop"));
725 return NULL;
728 XTextPropertyToStringList(&text_ret, &list, &count);
730 if (!list || count<1) {
731 XFree(text_ret.value);
732 wwarning(_("error getting dropped data from DND drop"));
733 return NULL;
736 flat_string = wtokenjoin(list, count);
737 if (!flat_string) {
738 wwarning(_("out of memory while getting data from DND drop"));
741 XFreeStringList(list);
742 XFree(text_ret.value);
743 return flat_string;
745 #endif /* OFFIX_DND */
748 #define S_NORMAL 0
749 #define S_ESCAPE 1
750 #define S_OPTION 2
753 * state input new-state output
754 * NORMAL % OPTION <nil>
755 * NORMAL \ ESCAPE <nil>
756 * NORMAL etc. NORMAL <input>
757 * ESCAPE any NORMAL <input>
758 * OPTION s NORMAL <selection buffer>
759 * OPTION w NORMAL <selected window id>
760 * OPTION a NORMAL <input text>
761 * OPTION d NORMAL <OffiX DND selection object>
762 * OPTION W NORMAL <current workspace>
763 * OPTION etc. NORMAL %<input>
765 #define TMPBUFSIZE 64
766 char*
767 ExpandOptions(WScreen *scr, char *cmdline)
769 int ptr, optr, state, len, olen;
770 char *out, *nout;
771 char *selection=NULL;
772 char *user_input=NULL;
773 #if defined(OFFIX_DND) || defined(XDND)
774 char *dropped_thing=NULL;
775 #endif
776 char tmpbuf[TMPBUFSIZE];
777 int slen;
779 len = strlen(cmdline);
780 olen = len+1;
781 out = malloc(olen);
782 if (!out) {
783 wwarning(_("out of memory during expansion of \"%s\""));
784 return NULL;
786 *out = 0;
787 ptr = 0; /* input line pointer */
788 optr = 0; /* output line pointer */
789 state = S_NORMAL;
790 while (ptr < len) {
791 switch (state) {
792 case S_NORMAL:
793 switch (cmdline[ptr]) {
794 case '\\':
795 state = S_ESCAPE;
796 break;
797 case '%':
798 state = S_OPTION;
799 break;
800 default:
801 state = S_NORMAL;
802 out[optr++]=cmdline[ptr];
803 break;
805 break;
806 case S_ESCAPE:
807 switch (cmdline[ptr]) {
808 case 'n':
809 out[optr++]=10;
810 break;
812 case 'r':
813 out[optr++]=13;
814 break;
816 case 't':
817 out[optr++]=9;
818 break;
820 default:
821 out[optr++]=cmdline[ptr];
823 state = S_NORMAL;
824 break;
825 case S_OPTION:
826 state = S_NORMAL;
827 switch (cmdline[ptr]) {
828 case 'w':
829 if (scr->focused_window
830 && scr->focused_window->flags.focused) {
831 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
832 (unsigned int)scr->focused_window->client_win);
833 slen = strlen(tmpbuf);
834 olen += slen;
835 nout = realloc(out,olen);
836 if (!nout) {
837 wwarning(_("out of memory during expansion of \"%w\""));
838 goto error;
840 out = nout;
841 strcat(out,tmpbuf);
842 optr+=slen;
843 } else {
844 out[optr++]=' ';
846 break;
848 case 'W':
849 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
850 (unsigned int)scr->current_workspace + 1);
851 slen = strlen(tmpbuf);
852 olen += slen;
853 nout = realloc(out,olen);
854 if (!nout) {
855 wwarning(_("out of memory during expansion of \"%W\""));
856 goto error;
858 out = nout;
859 strcat(out,tmpbuf);
860 optr+=slen;
861 break;
863 case 'a':
864 ptr++;
865 user_input = getuserinput(scr, cmdline, &ptr);
866 if (user_input) {
867 slen = strlen(user_input);
868 olen += slen;
869 nout = realloc(out,olen);
870 if (!nout) {
871 wwarning(_("out of memory during expansion of \"%a\""));
872 goto error;
874 out = nout;
875 strcat(out,user_input);
876 optr+=slen;
877 } else {
878 /* Not an error, but user has Canceled the dialog box.
879 * This will make the command to not be performed. */
880 goto error;
882 break;
884 #if defined(OFFIX_DND) || defined(XDND)
885 case 'd':
886 #ifdef XDND
887 if(scr->xdestring) {
888 dropped_thing = wstrdup(scr->xdestring);
890 #endif
891 if (!dropped_thing) {
892 dropped_thing = get_dnd_selection(scr);
894 if (!dropped_thing) {
895 scr->flags.dnd_data_convertion_status = 1;
896 goto error;
898 slen = strlen(dropped_thing);
899 olen += slen;
900 nout = realloc(out,olen);
901 if (!nout) {
902 wwarning(_("out of memory during expansion of \"%d\""));
903 goto error;
905 out = nout;
906 strcat(out,dropped_thing);
907 optr+=slen;
908 break;
909 #endif /* OFFIX_DND */
911 case 's':
912 if (!selection) {
913 selection = getselection(scr);
915 if (!selection) {
916 wwarning(_("selection not available"));
917 goto error;
919 slen = strlen(selection);
920 olen += slen;
921 nout = realloc(out,olen);
922 if (!nout) {
923 wwarning(_("out of memory during expansion of \"%s\""));
924 goto error;
926 out = nout;
927 strcat(out,selection);
928 optr+=slen;
929 break;
931 default:
932 out[optr++]='%';
933 out[optr++]=cmdline[ptr];
935 break;
937 out[optr]=0;
938 ptr++;
940 if (selection)
941 XFree(selection);
942 return out;
944 error:
945 wfree(out);
946 if (selection)
947 XFree(selection);
948 return NULL;
952 /* feof doesn't seem to work on pipes */
954 IsEof(FILE * stream)
956 static struct stat stinfo;
958 fstat(fileno(stream), &stinfo);
959 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
960 feof(stream));
964 void
965 ParseWindowName(WMPropList *value, char **winstance, char **wclass, char *where)
967 char *name;
969 *winstance = *wclass = NULL;
971 if (!WMIsPLString(value)) {
972 wwarning(_("bad window name value in %s state info"), where);
973 return;
976 name = WMGetFromPLString(value);
977 if (!name || strlen(name)==0) {
978 wwarning(_("bad window name value in %s state info"), where);
979 return;
982 UnescapeWM_CLASS(name, winstance, wclass);
986 #if 0
987 static char*
988 keysymToString(KeySym keysym, unsigned int state)
990 XKeyEvent kev;
991 char *buf = wmalloc(20);
992 int count;
994 kev.display = dpy;
995 kev.type = KeyPress;
996 kev.send_event = False;
997 kev.window = DefaultRootWindow(dpy);
998 kev.root = DefaultRootWindow(dpy);
999 kev.same_screen = True;
1000 kev.subwindow = kev.root;
1001 kev.serial = 0x12344321;
1002 kev.time = CurrentTime;
1003 kev.state = state;
1004 kev.keycode = XKeysymToKeycode(dpy, keysym);
1005 count = XLookupString(&kev, buf, 19, NULL, NULL);
1006 buf[count] = 0;
1008 return buf;
1010 #endif
1013 char*
1014 GetShortcutString(char *text)
1016 char *buffer = NULL;
1017 char *k;
1018 int modmask = 0;
1019 /* KeySym ksym;*/
1020 int control = 0;
1021 char *tmp;
1023 tmp = text = wstrdup(text);
1025 /* get modifiers */
1026 while ((k = strchr(text, '+'))!=NULL) {
1027 int mod;
1029 *k = 0;
1030 mod = wXModifierFromKey(text);
1031 if (mod<0) {
1032 return wstrdup("bug");
1035 modmask |= mod;
1037 if (strcasecmp(text, "Meta")==0) {
1038 buffer = wstrappend(buffer, "M+");
1039 } else if (strcasecmp(text, "Alt")==0) {
1040 buffer = wstrappend(buffer, "A+");
1041 } else if (strcasecmp(text, "Shift")==0) {
1042 buffer = wstrappend(buffer, "Sh+");
1043 } else if (strcasecmp(text, "Mod1")==0) {
1044 buffer = wstrappend(buffer, "M1+");
1045 } else if (strcasecmp(text, "Mod2")==0) {
1046 buffer = wstrappend(buffer, "M2+");
1047 } else if (strcasecmp(text, "Mod3")==0) {
1048 buffer = wstrappend(buffer, "M3+");
1049 } else if (strcasecmp(text, "Mod4")==0) {
1050 buffer = wstrappend(buffer, "M4+");
1051 } else if (strcasecmp(text, "Mod5")==0) {
1052 buffer = wstrappend(buffer, "M5+");
1053 } else if (strcasecmp(text, "Control")==0) {
1054 control = 1;
1055 } else {
1056 buffer = wstrappend(buffer, text);
1058 text = k+1;
1061 if (control) {
1062 buffer = wstrappend(buffer, "^");
1064 buffer = wstrappend(buffer, text);
1066 /* get key */
1067 /* ksym = XStringToKeysym(text);
1068 tmp = keysymToString(ksym, modmask);
1069 puts(tmp);
1070 buffer = wstrappend(buffer, tmp);
1072 wfree(tmp);
1074 return buffer;
1078 char*
1079 EscapeWM_CLASS(char *name, char *class)
1081 char *ret;
1082 char *ename = NULL, *eclass = NULL;
1083 int i, j, l;
1085 if (!name && !class)
1086 return NULL;
1088 if (name) {
1089 l = strlen(name);
1090 ename = wmalloc(l*2+1);
1091 j = 0;
1092 for (i=0; i<l; i++) {
1093 if (name[i]=='\\') {
1094 ename[j++] = '\\';
1095 } else if (name[i]=='.') {
1096 ename[j++] = '\\';
1098 ename[j++] = name[i];
1100 ename[j] = 0;
1102 if (class) {
1103 l = strlen(class);
1104 eclass = wmalloc(l*2+1);
1105 j = 0;
1106 for (i=0; i<l; i++) {
1107 if (class[i]=='\\') {
1108 eclass[j++] = '\\';
1109 } else if (class[i]=='.') {
1110 eclass[j++] = '\\';
1112 eclass[j++] = class[i];
1114 eclass[j] = 0;
1117 if (ename && eclass) {
1118 int len = strlen(ename)+strlen(eclass)+4;
1119 ret = wmalloc(len);
1120 snprintf(ret, len, "%s.%s", ename, eclass);
1121 wfree(ename);
1122 wfree(eclass);
1123 } else if (ename) {
1124 ret = wstrdup(ename);
1125 wfree(ename);
1126 } else {
1127 ret = wstrdup(eclass);
1128 wfree(eclass);
1131 return ret;
1135 void
1136 UnescapeWM_CLASS(char *str, char **name, char **class)
1138 int i, j, k, dot;
1139 Bool esc;
1141 j = strlen(str);
1142 *name = wmalloc(j);
1143 **name = 0;
1144 *class = wmalloc(j);
1145 **class = 0;
1147 /* separate string in 2 parts */
1148 esc = False;
1149 dot = 0;
1150 for (i = 0; i < j; i++) {
1151 if (!esc) {
1152 if (str[i]=='\\') {
1153 esc = True;
1154 } else if (str[i]=='.') {
1155 dot = i;
1156 break;
1158 } else {
1159 esc = False;
1163 /* unescape strings */
1164 esc = False;
1165 k = 0;
1166 for (i = 0; i < dot; i++) {
1167 if (!esc) {
1168 if (str[i]=='\\') {
1169 esc = True;
1170 } else {
1171 (*name)[k++] = str[i];
1173 } else {
1174 (*name)[k++] = str[i];
1175 esc = False;
1178 (*name)[k] = 0;
1180 esc = False;
1181 k = 0;
1182 for (i = dot+1; i<j; i++) {
1183 if (!esc) {
1184 if (str[i]=='\\') {
1185 esc = True;
1186 } else {
1187 (*class)[k++] = str[i];
1189 } else {
1190 esc = False;
1193 (*class)[k] = 0;
1195 if (!*name) {
1196 wfree(*name);
1197 *name = NULL;
1199 if (!*class) {
1200 wfree(*class);
1201 *class = NULL;
1207 void
1208 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1210 unsigned char *buffer;
1211 int len;
1212 int i;
1213 char buf[16];
1215 if (!scr->flags.backimage_helper_launched) {
1216 return;
1219 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1220 buffer = wmalloc(len+5);
1221 snprintf(buf, len, "%4i", len);
1222 memcpy(buffer, buf, 4);
1223 buffer[4] = type;
1224 i = 5;
1225 if (workspace >= 0) {
1226 snprintf(buf, sizeof(buf), "%4i", workspace);
1227 memcpy(&buffer[i], buf, 4);
1228 i += 4;
1229 buffer[i] = 0;
1231 if (msg)
1232 strcpy(&buffer[i], msg);
1234 if (write(scr->helper_fd, buffer, len+4) < 0) {
1235 wsyserror(_("could not send message to background image helper"));
1237 wfree(buffer);
1241 Bool
1242 UpdateDomainFile(WDDomain *domain)
1244 struct stat stbuf;
1245 char path[PATH_MAX];
1246 WMPropList *shared_dict, *dict;
1247 Bool result, freeDict = False;
1249 dict = domain->dictionary;
1250 if (WMIsPLDictionary(domain->dictionary)) {
1251 /* retrieve global system dictionary */
1252 snprintf(path, sizeof(path), "%s/WindowMaker/%s",
1253 SYSCONFDIR, domain->domain_name);
1254 if (stat(path, &stbuf) >= 0) {
1255 shared_dict = WMReadPropListFromFile(path);
1256 if (shared_dict) {
1257 if (WMIsPLDictionary(shared_dict)) {
1258 freeDict = True;
1259 dict = WMDeepCopyPropList(domain->dictionary);
1260 WMSubtractPLDictionaries(dict, shared_dict, True);
1262 WMReleasePropList(shared_dict);
1267 result = WMWritePropListToFile(dict, domain->path, True);
1269 if (freeDict) {
1270 WMReleasePropList(dict);
1273 return result;
1278 char*
1279 StrConcatDot(char *a, char *b)
1281 int len;
1282 char *str;
1284 if (!a)
1285 a = "";
1286 if (!b)
1287 b = "";
1289 len = strlen(a)+strlen(b)+4;
1290 str = wmalloc(len);
1292 snprintf(str, len, "%s.%s", a, b);
1294 return str;