fixed memory leaks and crash with deminiaturization
[wmaker-crm.git] / src / misc.c
blob627cfed76c38b5c4f7e895a24a197cf17b88ae77
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997, 1998 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 <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 sprintf(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 free(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 */
206 WWindow*
207 NextToFocusAfter(WWindow *wwin)
209 WWindow *tmp = wwin->prev;
211 while (tmp) {
212 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
213 return tmp;
215 tmp = tmp->prev;
218 tmp = wwin;
219 /* start over from the beginning of the list */
220 while (tmp->next)
221 tmp = tmp->next;
223 while (tmp && tmp != wwin) {
224 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
225 return tmp;
227 tmp = tmp->prev;
230 return wwin;
234 WWindow*
235 NextToFocusBefore(WWindow *wwin)
237 WWindow *tmp = wwin->next;
239 while (tmp) {
240 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
241 return tmp;
243 tmp = tmp->next;
246 /* start over from the beginning of the list */
247 tmp = wwin;
248 while (tmp->prev)
249 tmp = tmp->prev;
251 while (tmp && tmp != wwin) {
252 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
254 return tmp;
256 tmp = tmp->next;
259 return wwin;
263 #if 0
265 * Is win2 below win1?
267 static Bool
268 isBelow(WWindow *win1, WWindow *win2)
270 int i;
271 WCoreWindow *tmp;
273 tmp = win1->frame->core->stacking->under;
274 while (tmp) {
275 if (tmp == win2->frame->core)
276 return True;
277 tmp = tmp->stacking->under;
280 for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
281 tmp = win1->screen_ptr->stacking_list[i];
282 while (tmp) {
283 if (tmp == win2->frame->core)
284 return True;
285 tmp = tmp->stacking->under;
288 return True;
290 #endif
295 * XFetchName Wrapper
298 Bool wFetchName(dpy, win, winname)
299 Display *dpy;
300 Window win;
301 char **winname;
303 XTextProperty text_prop;
304 char **list;
305 int num;
307 if (XGetWMName(dpy, win, &text_prop)) {
308 if (text_prop.value && text_prop.nitems > 0) {
309 if (text_prop.encoding == XA_STRING) {
310 *winname = wstrdup((char *)text_prop.value);
311 XFree(text_prop.value);
312 } else {
313 text_prop.nitems = strlen((char *)text_prop.value);
314 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
315 Success && num > 0 && *list) {
316 XFree(text_prop.value);
317 *winname = wstrdup(*list);
318 XFreeStringList(list);
319 } else {
320 *winname = wstrdup((char *)text_prop.value);
321 XFree(text_prop.value);
324 } else {
325 /* the title is set, but it was set to none */
326 *winname = wstrdup("");
328 return True;
329 } else {
330 /* the hint is probably not set */
331 *winname = NULL;
333 return False;
338 * XGetIconName Wrapper
342 Bool wGetIconName(dpy, win, iconname)
343 Display *dpy;
344 Window win;
345 char **iconname;
347 XTextProperty text_prop;
348 char **list;
349 int num;
351 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
352 && text_prop.nitems > 0) {
353 if (text_prop.encoding == XA_STRING)
354 *iconname = (char *)text_prop.value;
355 else {
356 text_prop.nitems = strlen((char *)text_prop.value);
357 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
358 Success && num > 0 && *list) {
359 XFree(text_prop.value);
360 *iconname = wstrdup(*list);
361 XFreeStringList(list);
362 } else
363 *iconname = (char *)text_prop.value;
365 return True;
367 *iconname = NULL;
368 return False;
372 static void
373 eatExpose()
375 XEvent event, foo;
377 /* compress all expose events into a single one */
379 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
380 /* ignore other exposure events for this window */
381 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
382 &foo));
383 /* eat exposes for other windows */
384 eatExpose();
386 event.xexpose.count = 0;
387 XPutBackEvent(dpy, &event);
392 void
393 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
395 time_t time0 = time(NULL);
396 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
397 int dx_is_bigger=0;
399 /* animation parameters */
400 static struct {
401 int delay;
402 int steps;
403 int slowdown;
404 } apars[5] = {
405 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
406 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
407 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
408 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
409 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
413 dx = (float)(to_x-from_x);
414 dy = (float)(to_y-from_y);
415 sx = (dx == 0 ? 0 : fabs(dx)/dx);
416 sy = (dy == 0 ? 0 : fabs(dy)/dy);
418 if (fabs(dx) > fabs(dy)) {
419 dx_is_bigger = 1;
422 if (dx_is_bigger) {
423 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
424 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
425 px = apars[(int)wPreferences.icon_slide_speed].steps;
426 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
427 px = -apars[(int)wPreferences.icon_slide_speed].steps;
428 py = (sx == 0 ? 0 : px*dy/dx);
429 } else {
430 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
431 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
432 py = apars[(int)wPreferences.icon_slide_speed].steps;
433 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
434 py = -apars[(int)wPreferences.icon_slide_speed].steps;
435 px = (sy == 0 ? 0 : py*dx/dy);
438 while (x != to_x || y != to_y) {
439 x += px;
440 y += py;
441 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
442 x = (float)to_x;
443 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
444 y = (float)to_y;
446 if (dx_is_bigger) {
447 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
448 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
449 px = apars[(int)wPreferences.icon_slide_speed].steps;
450 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
451 px = -apars[(int)wPreferences.icon_slide_speed].steps;
452 py = (sx == 0 ? 0 : px*dy/dx);
453 } else {
454 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
455 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
456 py = apars[(int)wPreferences.icon_slide_speed].steps;
457 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
458 py = -apars[(int)wPreferences.icon_slide_speed].steps;
459 px = (sy == 0 ? 0 : py*dx/dy);
462 XMoveWindow(dpy, win, (int)x, (int)y);
463 XFlush(dpy);
464 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
465 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
467 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
468 break;
470 XMoveWindow(dpy, win, to_x, to_y);
472 XSync(dpy, 0);
473 /* compress expose events */
474 eatExpose();
478 char*
479 ShrinkString(WMFont *font, char *string, int width)
481 int w, w1=0;
482 int p;
483 char *pos;
484 char *text;
485 int p1, p2, t;
487 if (wPreferences.multi_byte_text)
488 return wstrdup(string);
490 p = strlen(string);
491 w = WMWidthOfString(font, string, p);
492 text = wmalloc(strlen(string)+8);
493 strcpy(text, string);
494 if (w<=width)
495 return text;
497 pos = strchr(text, ' ');
498 if (!pos)
499 pos = strchr(text, ':');
501 if (pos) {
502 *pos = 0;
503 p = strlen(text);
504 w1 = WMWidthOfString(font, text, p);
505 if (w1 > width) {
506 w1 = 0;
507 p = 0;
508 *pos = ' ';
509 *text = 0;
510 } else {
511 *pos = 0;
512 width -= w1;
513 p++;
515 string += p;
516 p=strlen(string);
517 } else {
518 *text=0;
520 strcat(text, "...");
521 width -= WMWidthOfString(font, "...", 3);
523 pos = string;
524 p1=0;
525 p2=p;
526 t = (p2-p1)/2;
527 while (p2>p1 && p1!=t) {
528 w = WMWidthOfString(font, &string[p-t], t);
529 if (w>width) {
530 p2 = t;
531 t = p1+(p2-p1)/2;
532 } else if (w<width) {
533 p1 = t;
534 t = p1+(p2-p1)/2;
535 } else
536 p2=p1=t;
538 strcat(text, &string[p-p1]);
540 return text;
544 char*
545 FindImage(char *paths, char *file)
547 char *tmp, *path;
549 tmp = strrchr(file, ':');
550 if (tmp) {
551 *tmp = 0;
552 path = wfindfile(paths, file);
553 *tmp = ':';
555 if (!tmp || !path) {
556 path = wfindfile(paths, file);
559 return path;
563 char*
564 FlattenStringList(char **list, int count)
566 int i, j;
567 char *flat_string, *wspace;
569 j = 0;
570 for (i=0; i<count; i++) {
571 if (list[i]!=NULL && list[i][0]!=0) {
572 j += strlen(list[i]);
573 if (strpbrk(list[i], " \t"))
574 j += 2;
578 flat_string = malloc(j+count+1);
579 if (!flat_string) {
580 return NULL;
583 *flat_string = 0;
584 for (i=0; i<count; i++) {
585 if (list[i]!=NULL && list[i][0]!=0) {
586 if (i>0)
587 strcat(flat_string, " ");
588 wspace = strpbrk(list[i], " \t");
589 if (wspace)
590 strcat(flat_string, "\"");
591 strcat(flat_string, list[i]);
592 if (wspace)
593 strcat(flat_string, "\"");
597 return flat_string;
603 *----------------------------------------------------------------------
604 * ParseCommand --
605 * Divides a command line into a argv/argc pair.
606 *----------------------------------------------------------------------
608 #define PRC_ALPHA 0
609 #define PRC_BLANK 1
610 #define PRC_ESCAPE 2
611 #define PRC_DQUOTE 3
612 #define PRC_EOS 4
613 #define PRC_SQUOTE 5
615 typedef struct {
616 short nstate;
617 short output;
618 } DFA;
621 static DFA mtable[9][6] = {
622 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
623 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
624 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
625 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
626 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
627 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
628 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
629 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
630 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
633 char*
634 next_token(char *word, char **next)
636 char *ptr;
637 char *ret, *t;
638 int state, ctype;
640 t = ret = wmalloc(strlen(word)+1);
641 ptr = word;
643 state = 0;
644 *t = 0;
645 while (1) {
646 if (*ptr==0)
647 ctype = PRC_EOS;
648 else if (*ptr=='\\')
649 ctype = PRC_ESCAPE;
650 else if (*ptr=='"')
651 ctype = PRC_DQUOTE;
652 else if (*ptr=='\'')
653 ctype = PRC_SQUOTE;
654 else if (*ptr==' ' || *ptr=='\t')
655 ctype = PRC_BLANK;
656 else
657 ctype = PRC_ALPHA;
659 if (mtable[state][ctype].output) {
660 *t = *ptr; t++;
661 *t = 0;
663 state = mtable[state][ctype].nstate;
664 ptr++;
665 if (mtable[state][0].output<0) {
666 break;
670 if (*ret==0)
671 t = NULL;
672 else
673 t = wstrdup(ret);
675 free(ret);
677 if (ctype==PRC_EOS)
678 *next = NULL;
679 else
680 *next = ptr;
682 return t;
686 void
687 ParseCommand(char *command, char ***argv, int *argc)
689 WMBag *bag = WMCreateBag(4);
690 char *token, *line;
691 int count, j;
693 line = command;
694 do {
695 token = next_token(line, &line);
696 if (token) {
697 WMPutInBag(bag, token);
699 } while (token!=NULL && line!=NULL);
701 count = WMGetBagItemCount(bag);
702 *argv = wmalloc(sizeof(char*)*count);
703 for (j = 0; j < count; j++) {
704 (*argv)[j] = WMGetFromBag(bag, j);
706 *argc = count;
708 WMFreeBag(bag);
711 #if 0
712 static void
713 timeup(void *foo)
715 *(int*)foo=1;
717 #endif
718 static char*
719 getselection(WScreen *scr)
721 char *tmp;
722 extern char *W_GetTextSelection(); /* in WINGs */
724 tmp = W_GetTextSelection(scr->wmscreen, XA_PRIMARY);
725 if (!tmp)
726 tmp = W_GetTextSelection(scr->wmscreen, XA_CUT_BUFFER0);
727 return tmp;
729 #if 0
730 XEvent event;
731 int timeover=0;
732 WMHandlerID *id;
734 #ifdef DEBUG
735 puts("getting selection");
736 #endif
737 RequestSelection(dpy, scr->no_focus_win, LastTimestamp);
738 /* timeout on 1 sec. */
739 id = WMAddTimerHandler(1000, timeup, &timeover);
740 while (!timeover) {
741 WMNextEvent(dpy, &event);
742 if (event.type == SelectionNotify
743 && event.xany.window==scr->no_focus_win) {
744 WMDeleteTimerHandler(id);
745 #ifdef DEBUG
746 puts("selection ok");
747 #endif
748 return GetSelection(dpy, scr->no_focus_win);
749 } else {
750 WMHandleEvent(&event);
753 wwarning(_("selection timed-out"));
754 return NULL;
755 #endif
759 static char*
760 getuserinput(WScreen *scr, char *line, int *ptr)
762 char *ret;
763 char *title;
764 char *prompt;
765 int j, state;
766 int begin = 0;
767 char tbuffer[256], pbuffer[256];
769 title = _("Program Arguments");
770 prompt = _("Enter command arguments:");
771 ret = NULL;
773 #define _STARTING 0
774 #define _TITLE 1
775 #define _PROMPT 2
776 #define _DONE 3
778 state = _STARTING;
779 j = 0;
780 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
781 switch (state) {
782 case _STARTING:
783 if (line[*ptr]=='(') {
784 state = _TITLE;
785 begin = *ptr+1;
786 } else {
787 state = _DONE;
789 break;
791 case _TITLE:
792 if (j <= 0 && line[*ptr]==',') {
794 j = 0;
795 if (*ptr > begin) {
796 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
797 tbuffer[WMIN(*ptr-begin, 255)] = 0;
798 title = (char*)tbuffer;
800 begin = *ptr+1;
801 state = _PROMPT;
803 } else if (j <= 0 && line[*ptr]==')') {
805 if (*ptr > begin) {
806 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
807 tbuffer[WMIN(*ptr-begin, 255)] = 0;
808 title = (char*)tbuffer;
810 state = _DONE;
812 } else if (line[*ptr]=='(') {
813 j++;
814 } else if (line[*ptr]==')') {
815 j--;
818 break;
820 case _PROMPT:
821 if (line[*ptr]==')' && j==0) {
823 if (*ptr-begin > 1) {
824 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255));
825 pbuffer[WMIN(*ptr-begin, 255)] = 0;
826 prompt = (char*)pbuffer;
828 state = _DONE;
829 } else if (line[*ptr]=='(')
830 j++;
831 else if (line[*ptr]==')')
832 j--;
833 break;
836 (*ptr)--;
837 #undef _STARTING
838 #undef _TITLE
839 #undef _PROMPT
840 #undef _DONE
842 if (!wInputDialog(scr, title, prompt, &ret))
843 return NULL;
844 else
845 return ret;
849 #ifdef OFFIX_DND
850 static char*
851 get_dnd_selection(WScreen *scr)
853 XTextProperty text_ret;
854 int result;
855 char **list;
856 char *flat_string;
857 int count;
859 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
861 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
862 || text_ret.format==0 || text_ret.nitems == 0) {
863 wwarning(_("unable to get dropped data from DND drop"));
864 return NULL;
867 XTextPropertyToStringList(&text_ret, &list, &count);
869 if (!list || count<1) {
870 XFree(text_ret.value);
871 wwarning(_("error getting dropped data from DND drop"));
872 return NULL;
875 flat_string = FlattenStringList(list, count);
876 if (!flat_string) {
877 wwarning(_("out of memory while getting data from DND drop"));
880 XFreeStringList(list);
881 XFree(text_ret.value);
882 return flat_string;
884 #endif /* OFFIX_DND */
887 #define S_NORMAL 0
888 #define S_ESCAPE 1
889 #define S_OPTION 2
892 * state input new-state output
893 * NORMAL % OPTION <nil>
894 * NORMAL \ ESCAPE <nil>
895 * NORMAL etc. NORMAL <input>
896 * ESCAPE any NORMAL <input>
897 * OPTION s NORMAL <selection buffer>
898 * OPTION w NORMAL <selected window id>
899 * OPTION a NORMAL <input text>
900 * OPTION d NORMAL <OffiX DND selection object>
901 * OPTION W NORMAL <current workspace>
902 * OPTION etc. NORMAL %<input>
904 #define TMPBUFSIZE 64
905 char*
906 ExpandOptions(WScreen *scr, char *cmdline)
908 int ptr, optr, state, len, olen;
909 char *out, *nout;
910 char *selection=NULL;
911 char *user_input=NULL;
912 #if defined(OFFIX_DND) || defined(XDND)
913 char *dropped_thing=NULL;
914 #endif
915 char tmpbuf[TMPBUFSIZE];
916 int slen;
918 len = strlen(cmdline);
919 olen = len+1;
920 out = malloc(olen);
921 if (!out) {
922 wwarning(_("out of memory during expansion of \"%s\""));
923 return NULL;
925 *out = 0;
926 ptr = 0; /* input line pointer */
927 optr = 0; /* output line pointer */
928 state = S_NORMAL;
929 while (ptr < len) {
930 switch (state) {
931 case S_NORMAL:
932 switch (cmdline[ptr]) {
933 case '\\':
934 state = S_ESCAPE;
935 break;
936 case '%':
937 state = S_OPTION;
938 break;
939 default:
940 state = S_NORMAL;
941 out[optr++]=cmdline[ptr];
942 break;
944 break;
945 case S_ESCAPE:
946 switch (cmdline[ptr]) {
947 case 'n':
948 out[optr++]=10;
949 break;
951 case 'r':
952 out[optr++]=13;
953 break;
955 case 't':
956 out[optr++]=9;
957 break;
959 default:
960 out[optr++]=cmdline[ptr];
962 state = S_NORMAL;
963 break;
964 case S_OPTION:
965 state = S_NORMAL;
966 switch (cmdline[ptr]) {
967 case 'w':
968 if (scr->focused_window
969 && scr->focused_window->flags.focused) {
970 sprintf(tmpbuf, "0x%x",
971 (unsigned int)scr->focused_window->client_win);
972 slen = strlen(tmpbuf);
973 olen += slen;
974 nout = realloc(out,olen);
975 if (!nout) {
976 wwarning(_("out of memory during expansion of \"%w\""));
977 goto error;
979 out = nout;
980 strcat(out,tmpbuf);
981 optr+=slen;
982 } else {
983 out[optr++]=' ';
985 break;
987 case 'W':
988 sprintf(tmpbuf, "0x%x",
989 (unsigned int)scr->current_workspace + 1);
990 slen = strlen(tmpbuf);
991 olen += slen;
992 nout = realloc(out,olen);
993 if (!nout) {
994 wwarning(_("out of memory during expansion of \"%W\""));
995 goto error;
997 out = nout;
998 strcat(out,tmpbuf);
999 optr+=slen;
1000 break;
1002 case 'a':
1003 ptr++;
1004 user_input = getuserinput(scr, cmdline, &ptr);
1005 if (user_input) {
1006 slen = strlen(user_input);
1007 olen += slen;
1008 nout = realloc(out,olen);
1009 if (!nout) {
1010 wwarning(_("out of memory during expansion of \"%a\""));
1011 goto error;
1013 out = nout;
1014 strcat(out,user_input);
1015 optr+=slen;
1016 } else {
1017 /* Not an error, but user has Canceled the dialog box.
1018 * This will make the command to not be performed. */
1019 goto error;
1021 break;
1023 #if defined(OFFIX_DND) || defined(XDND)
1024 case 'd':
1025 #ifdef XDND
1026 if(scr->xdestring) {
1027 dropped_thing = wstrdup(scr->xdestring);
1029 #endif
1030 if (!dropped_thing) {
1031 dropped_thing = get_dnd_selection(scr);
1033 if (!dropped_thing) {
1034 scr->flags.dnd_data_convertion_status = 1;
1035 goto error;
1037 slen = strlen(dropped_thing);
1038 olen += slen;
1039 nout = realloc(out,olen);
1040 if (!nout) {
1041 wwarning(_("out of memory during expansion of \"%d\""));
1042 goto error;
1044 out = nout;
1045 strcat(out,dropped_thing);
1046 optr+=slen;
1047 break;
1048 #endif /* OFFIX_DND */
1050 case 's':
1051 if (!selection) {
1052 selection = getselection(scr);
1054 if (!selection) {
1055 wwarning(_("selection not available"));
1056 goto error;
1058 slen = strlen(selection);
1059 olen += slen;
1060 nout = realloc(out,olen);
1061 if (!nout) {
1062 wwarning(_("out of memory during expansion of \"%s\""));
1063 goto error;
1065 out = nout;
1066 strcat(out,selection);
1067 optr+=slen;
1068 break;
1069 default:
1070 out[optr++]='%';
1071 out[optr++]=cmdline[ptr];
1073 break;
1075 out[optr]=0;
1076 ptr++;
1078 if (selection)
1079 XFree(selection);
1080 return out;
1082 error:
1083 free(out);
1084 if (selection)
1085 XFree(selection);
1086 return NULL;
1090 /* We don't care for upper/lower case in comparing the keys; so we
1091 have to define our own comparison function here */
1092 BOOL
1093 StringCompareHook(proplist_t pl1, proplist_t pl2)
1095 char *str1, *str2;
1097 str1 = PLGetString(pl1);
1098 str2 = PLGetString(pl2);
1100 if (strcasecmp(str1, str2)==0)
1101 return YES;
1102 else
1103 return NO;
1107 /* feof doesn't seem to work on pipes */
1109 IsEof(FILE * stream)
1111 static struct stat stinfo;
1113 fstat(fileno(stream), &stinfo);
1114 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1115 feof(stream));
1119 void
1120 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1122 char *name;
1124 *winstance = *wclass = NULL;
1126 if (!PLIsString(value)) {
1127 wwarning(_("bad window name value in %s state info"), where);
1128 return;
1131 name = PLGetString(value);
1132 if (!name || strlen(name)==0) {
1133 wwarning(_("bad window name value in %s state info"), where);
1134 return;
1137 UnescapeWM_CLASS(name, winstance, wclass);
1141 #if 0
1142 static char*
1143 keysymToString(KeySym keysym, unsigned int state)
1145 XKeyEvent kev;
1146 char *buf = wmalloc(20);
1147 int count;
1149 kev.display = dpy;
1150 kev.type = KeyPress;
1151 kev.send_event = False;
1152 kev.window = DefaultRootWindow(dpy);
1153 kev.root = DefaultRootWindow(dpy);
1154 kev.same_screen = True;
1155 kev.subwindow = kev.root;
1156 kev.serial = 0x12344321;
1157 kev.time = CurrentTime;
1158 kev.state = state;
1159 kev.keycode = XKeysymToKeycode(dpy, keysym);
1160 count = XLookupString(&kev, buf, 19, NULL, NULL);
1161 buf[count] = 0;
1163 return buf;
1165 #endif
1167 static char *
1168 appendrealloc(char *a, char *b)
1170 if (a == NULL)
1171 return wstrdup(b);
1172 else {
1173 char *c = wstrappend(a, b);
1174 free(a);
1175 return c;
1180 char*
1181 GetShortcutString(char *text)
1183 char *buffer = NULL;
1184 char *k;
1185 int modmask = 0;
1186 /* KeySym ksym;*/
1187 int control = 0;
1188 char *tmp;
1190 tmp = text = wstrdup(text);
1192 /* get modifiers */
1193 while ((k = strchr(text, '+'))!=NULL) {
1194 int mod;
1196 *k = 0;
1197 mod = wXModifierFromKey(text);
1198 if (mod<0) {
1199 return wstrdup("bug");
1202 modmask |= mod;
1204 if (strcasecmp(text, "Meta")==0) {
1205 buffer = appendrealloc(buffer, "M+");
1206 } else if (strcasecmp(text, "Alt")==0) {
1207 buffer = appendrealloc(buffer, "A+");
1208 } else if (strcasecmp(text, "Shift")==0) {
1209 buffer = appendrealloc(buffer, "Sh+");
1210 } else if (strcasecmp(text, "Mod1")==0) {
1211 buffer = appendrealloc(buffer, "M1+");
1212 } else if (strcasecmp(text, "Mod2")==0) {
1213 buffer = appendrealloc(buffer, "M2+");
1214 } else if (strcasecmp(text, "Mod3")==0) {
1215 buffer = appendrealloc(buffer, "M3+");
1216 } else if (strcasecmp(text, "Mod4")==0) {
1217 buffer = appendrealloc(buffer, "M4+");
1218 } else if (strcasecmp(text, "Mod5")==0) {
1219 buffer = appendrealloc(buffer, "M5+");
1220 } else if (strcasecmp(text, "Control")==0) {
1221 control = 1;
1222 } else {
1223 buffer = appendrealloc(buffer, text);
1225 text = k+1;
1228 if (control) {
1229 buffer = appendrealloc(buffer, "^");
1231 buffer = appendrealloc(buffer, text);
1233 /* get key */
1234 /* ksym = XStringToKeysym(text);
1235 tmp = keysymToString(ksym, modmask);
1236 puts(tmp);
1237 buffer = wstrappend(buffer, tmp);
1239 free(tmp);
1241 return buffer;
1245 char*
1246 EscapeWM_CLASS(char *name, char *class)
1248 char *ret;
1249 char *ename = NULL, *eclass = NULL;
1250 int i, j, l;
1252 if (!name && !class)
1253 return NULL;
1255 if (name) {
1256 l = strlen(name);
1257 ename = wmalloc(l*2);
1258 j = 0;
1259 for (i=0; i<l; i++) {
1260 if (name[i]=='\\') {
1261 ename[j++] = '\\';
1262 } else if (name[i]=='.') {
1263 ename[j++] = '\\';
1265 ename[j++] = name[i];
1267 ename[j] = 0;
1269 if (class) {
1270 l = strlen(class);
1271 eclass = wmalloc(l*2);
1272 j = 0;
1273 for (i=0; i<l; i++) {
1274 if (class[i]=='\\') {
1275 eclass[j++] = '\\';
1276 } else if (class[i]=='.') {
1277 eclass[j++] = '\\';
1279 eclass[j++] = class[i];
1281 eclass[j] = 0;
1284 if (ename && eclass) {
1285 ret = wmalloc(strlen(ename)+strlen(eclass)+4);
1286 sprintf(ret, "%s.%s", ename, eclass);
1287 free(ename);
1288 free(eclass);
1289 } else if (ename) {
1290 ret = wstrdup(ename);
1291 free(ename);
1292 } else {
1293 ret = wstrdup(eclass);
1294 free(eclass);
1297 return ret;
1301 void
1302 UnescapeWM_CLASS(char *str, char **name, char **class)
1304 int i, j, k, dot;
1305 Bool esc;
1307 j = strlen(str);
1308 *name = wmalloc(j);
1309 **name = 0;
1310 *class = wmalloc(j);
1311 **class = 0;
1313 /* separate string in 2 parts */
1314 esc = False;
1315 dot = 0;
1316 for (i = 0; i < j; i++) {
1317 if (!esc) {
1318 if (str[i]=='\\') {
1319 esc = True;
1320 } else if (str[i]=='.') {
1321 dot = i;
1322 break;
1324 } else {
1325 esc = False;
1329 /* unescape strings */
1330 esc = False;
1331 k = 0;
1332 for (i = 0; i < dot; i++) {
1333 if (!esc) {
1334 if (str[i]=='\\') {
1335 esc = True;
1336 } else {
1337 (*name)[k++] = str[i];
1339 } else {
1340 (*name)[k++] = str[i];
1341 esc = False;
1344 (*name)[k] = 0;
1346 esc = False;
1347 k = 0;
1348 for (i = dot+1; i<j; i++) {
1349 if (!esc) {
1350 if (str[i]=='\\') {
1351 esc = True;
1352 } else {
1353 (*class)[k++] = str[i];
1355 } else {
1356 esc = False;
1359 (*class)[k] = 0;
1361 if (!*name) {
1362 free(*name);
1363 *name = NULL;
1365 if (!*class) {
1366 free(*class);
1367 *class = NULL;
1373 void
1374 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1376 unsigned char *buffer;
1377 int len;
1378 int i;
1379 char buf[16];
1381 if (!scr->flags.backimage_helper_launched) {
1382 return;
1385 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1386 buffer = wmalloc(len+5);
1387 sprintf(buf, "%4i", len);
1388 memcpy(buffer, buf, 4);
1389 buffer[4] = type;
1390 i = 5;
1391 if (workspace >= 0) {
1392 sprintf(buf, "%4i", workspace);
1393 memcpy(&buffer[i], buf, 4);
1394 i += 4;
1395 buffer[i] = 0;
1397 if (msg)
1398 strcpy(&buffer[i], msg);
1400 if (write(scr->helper_fd, buffer, len+4) < 0) {
1401 wsyserror(_("could not send message to background image helper"));
1403 free(buffer);