Updating to version 0.20.2
[wmaker-crm.git] / src / misc.c
blob03158bbac4b42d9e461daaffacdd09669ec1533b
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 <pwd.h>
32 #include <math.h>
33 #include <time.h>
35 #include <wraster.h>
37 #include "WindowMaker.h"
38 #include "GNUstep.h"
39 #include "screen.h"
40 #include "wcore.h"
41 #include "window.h"
42 #include "framewin.h"
43 #include "funcs.h"
44 #include "defaults.h"
45 #include "dialog.h"
46 #include "xutil.h"
47 #include "xmodifier.h"
49 #include "list.h"
51 /**** global variables *****/
53 extern char *DisplayName;
55 extern WPreferences wPreferences;
57 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;
120 line = wmalloc(MAXLINE);
121 *line = 0;
122 i=1;
123 if ((buf=getenv("HOSTNAME"))!=NULL) {
124 if (buf[0]=='(') {
125 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"),
126 buf);
127 } else
128 putdef(line, " -DHOST=", buf);
129 } else if ((buf=getenv("HOST"))!=NULL) {
130 if (buf[0]=='(') {
131 wwarning(_("your machine is misconfigured. HOST is set to %s"),
132 buf);
133 } else
134 putdef(line, " -DHOST=", buf);
136 buf = username();
137 if (buf)
138 putdef(line, " -DUSER=", buf);
139 putidef(line, " -DUID=", getuid());
140 buf = XDisplayName(DisplayString(dpy));
141 putdef(line, " -DDISPLAY=", buf);
142 putdef(line, " -DWM_VERSION=", VERSION);
144 visual = DefaultVisual(dpy, DefaultScreen(dpy));
145 putidef(line, " -DVISUAL=", visual->class);
147 putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy)));
149 putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy)));
150 putidef(line, " -DSCR_HEIGHT=",
151 HeightOfScreen(DefaultScreenOfDisplay(dpy)));
153 #if 0
154 strcpy(buffer, path);
155 buf = strrchr(buffer, '/');
156 if (buf) *buf = 0; /* trunc filename */
157 putdef(line, " -I", buffer);
158 #endif
162 /* this should be done just once, but it works this way */
163 strcpy(buffer, DEF_CONFIG_PATHS);
164 buf = strtok(buffer, ":");
166 do {
167 char fullpath[MAXLINE];
169 if (buf[0]!='~') {
170 strcpy(fullpath, buf);
171 } else {
172 char * wgethomedir();
173 /* home is statically allocated. Don't free it! */
174 char *home = wgethomedir();
176 strcpy(fullpath, home);
177 strcat(fullpath, &(buf[1]));
180 putdef(line, " -I", fullpath);
182 } while ((buf = strtok(NULL, ":"))!=NULL);
184 #undef arg
185 #ifdef DEBUG
186 puts("CPP ARGS");
187 puts(line);
188 #endif
189 return line;
191 #endif /* USECPP */
195 WWindow*
196 NextFocusWindow(WScreen *scr)
198 WWindow *tmp, *wwin, *closest, *min;
199 Window d;
201 if (!(wwin = scr->focused_window))
202 return NULL;
203 tmp = wwin->prev;
204 closest = NULL;
205 min = wwin;
206 d = 0xffffffff;
207 while (tmp) {
208 if (wWindowCanReceiveFocus(tmp)
209 && (!tmp->window_flags.skip_window_list
210 || tmp->flags.internal_window)) {
211 if (min->client_win > tmp->client_win)
212 min = tmp;
213 if (tmp->client_win > wwin->client_win
214 && (!closest
215 || (tmp->client_win - wwin->client_win) < d)) {
216 closest = tmp;
217 d = tmp->client_win - wwin->client_win;
220 tmp = tmp->prev;
222 if (!closest||closest==wwin)
223 return min;
224 return closest;
228 WWindow*
229 PrevFocusWindow(WScreen *scr)
231 WWindow *tmp, *wwin, *closest, *max;
232 Window d;
234 if (!(wwin = scr->focused_window))
235 return NULL;
236 tmp = wwin->prev;
237 closest = NULL;
238 max = wwin;
239 d = 0xffffffff;
240 while (tmp) {
241 if (wWindowCanReceiveFocus(tmp) &&
242 (!tmp->window_flags.skip_window_list
243 || tmp->flags.internal_window)) {
244 if (max->client_win < tmp->client_win)
245 max = tmp;
246 if (tmp->client_win < wwin->client_win
247 && (!closest
248 || (wwin->client_win - tmp->client_win) < d)) {
249 closest = tmp;
250 d = wwin->client_win - tmp->client_win;
253 tmp = tmp->prev;
255 if (!closest||closest==wwin)
256 return max;
257 return closest;
262 #if 0
264 * Is win2 below win1?
266 static Bool
267 isBelow(WWindow *win1, WWindow *win2)
269 int i;
270 WCoreWindow *tmp;
272 tmp = win1->frame->core->stacking->under;
273 while (tmp) {
274 if (tmp == win2->frame->core)
275 return True;
276 tmp = tmp->stacking->under;
279 for (i=win1->frame->window_level-1; i>=0; i--) {
280 tmp = win1->screen_ptr->stacking_list[i];
281 while (tmp) {
282 if (tmp == win2->frame->core)
283 return True;
284 tmp = tmp->stacking->under;
287 return True;
289 #endif
294 * XFetchName Wrapper
297 Bool wFetchName(dpy, win, winname)
298 Display *dpy;
299 Window win;
300 char **winname;
302 XTextProperty text_prop;
303 char **list;
304 int num;
306 if (XGetWMName(dpy, win, &text_prop)) {
307 if (text_prop.value && text_prop.nitems > 0) {
308 if (text_prop.encoding == XA_STRING) {
309 *winname = wstrdup((char *)text_prop.value);
310 XFree(text_prop.value);
311 } else {
312 text_prop.nitems = strlen((char *)text_prop.value);
313 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
314 Success && num > 0 && *list) {
315 XFree(text_prop.value);
316 *winname = wstrdup(*list);
317 XFreeStringList(list);
318 } else {
319 *winname = wstrdup((char *)text_prop.value);
320 XFree(text_prop.value);
323 } else {
324 /* the title is set, but it was set to none */
325 *winname = wstrdup("");
327 return True;
328 } else {
329 /* the hint is probably not set */
330 *winname = NULL;
332 return False;
337 * XGetIconName Wrapper
341 Bool wGetIconName(dpy, win, iconname)
342 Display *dpy;
343 Window win;
344 char **iconname;
346 XTextProperty text_prop;
347 char **list;
348 int num;
350 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
351 && text_prop.nitems > 0) {
352 if (text_prop.encoding == XA_STRING)
353 *iconname = (char *)text_prop.value;
354 else {
355 text_prop.nitems = strlen((char *)text_prop.value);
356 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
357 Success && num > 0 && *list) {
358 XFree(text_prop.value);
359 *iconname = wstrdup(*list);
360 XFreeStringList(list);
361 } else
362 *iconname = (char *)text_prop.value;
364 return True;
366 *iconname = NULL;
367 return False;
371 #if 0
372 #ifdef I18N_MB
373 void
374 wTextWidth(XFontSet font, char *text, int length)
376 XRectangle rect;
377 XRectangle AIXsucks;
379 XmbTextExtents(font, text, length, &AIXsucks, &rec);
381 return rect.width;
383 #else
384 void
385 wTextWidth(XFontStruct *font, char *text, int length)
387 return XTextWidth(font, text, length);
389 #endif
390 #endif
392 static void
393 eatExpose()
395 XEvent event, foo;
397 /* compress all expose events into a single one */
399 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
400 /* ignore other exposure events for this window */
401 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
402 &foo));
403 /* eat exposes for other windows */
404 eatExpose();
406 event.xexpose.count = 0;
407 XPutBackEvent(dpy, &event);
412 void
413 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
415 time_t time0 = time(NULL);
416 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
417 int dx_is_bigger=0;
419 /* animation parameters */
420 static struct {
421 int delay;
422 int steps;
423 int slowdown;
424 } apars[5] = {
425 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
426 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
427 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
428 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
429 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
433 dx = (float)(to_x-from_x);
434 dy = (float)(to_y-from_y);
435 sx = (dx == 0 ? 0 : fabs(dx)/dx);
436 sy = (dy == 0 ? 0 : fabs(dy)/dy);
438 if (fabs(dx) > fabs(dy)) {
439 dx_is_bigger = 1;
442 if (dx_is_bigger) {
443 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
444 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
445 px = apars[(int)wPreferences.icon_slide_speed].steps;
446 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
447 px = -apars[(int)wPreferences.icon_slide_speed].steps;
448 py = (sx == 0 ? 0 : px*dy/dx);
449 } else {
450 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
451 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
452 py = apars[(int)wPreferences.icon_slide_speed].steps;
453 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
454 py = -apars[(int)wPreferences.icon_slide_speed].steps;
455 px = (sy == 0 ? 0 : py*dx/dy);
458 while (x != to_x || y != to_y) {
459 x += px;
460 y += py;
461 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
462 x = (float)to_x;
463 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
464 y = (float)to_y;
466 if (dx_is_bigger) {
467 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
468 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
469 px = apars[(int)wPreferences.icon_slide_speed].steps;
470 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
471 px = -apars[(int)wPreferences.icon_slide_speed].steps;
472 py = (sx == 0 ? 0 : px*dy/dx);
473 } else {
474 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
475 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
476 py = apars[(int)wPreferences.icon_slide_speed].steps;
477 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
478 py = -apars[(int)wPreferences.icon_slide_speed].steps;
479 px = (sy == 0 ? 0 : py*dx/dy);
482 XMoveWindow(dpy, win, (int)x, (int)y);
483 XFlush(dpy);
484 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
485 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
487 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
488 break;
490 XMoveWindow(dpy, win, to_x, to_y);
492 XSync(dpy, 0);
493 /* compress expose events */
494 eatExpose();
498 char*
499 ShrinkString(WFont *font, char *string, int width)
501 #ifndef I18N_MB
502 int w, w1=0;
503 int p;
504 char *pos;
505 char *text;
506 int p1, p2, t;
507 #endif
509 #ifdef I18N_MB
510 return wstrdup(string);
511 #else
512 p = strlen(string);
513 w = wTextWidth(font->font, string, p);
514 text = wmalloc(strlen(string)+8);
515 strcpy(text, string);
516 if (w<=width)
517 return text;
519 pos = strchr(text, ' ');
520 if (!pos)
521 pos = strchr(text, ':');
523 if (pos) {
524 *pos = 0;
525 p = strlen(text);
526 w1=wTextWidth(font->font, text, p);
527 if (w1>width) {
528 w1 = 0;
529 p = 0;
530 *pos = ' ';
531 *text = 0;
532 } else {
533 *pos = 0;
534 width -= w1;
535 p++;
537 string += p;
538 p=strlen(string);
539 } else {
540 *text=0;
542 strcat(text, "...");
543 width -= wTextWidth(font->font, "...", 3);
545 pos = string;
546 p1=0;
547 p2=p;
548 t = (p2-p1)/2;
549 while (p2>p1 && p1!=t) {
550 w = wTextWidth(font->font, &string[p-t], t);
551 if (w>width) {
552 p2 = t;
553 t = p1+(p2-p1)/2;
554 } else if (w<width) {
555 p1 = t;
556 t = p1+(p2-p1)/2;
557 } else
558 p2=p1=t;
560 strcat(text, &string[p-p1]);
561 return text;
562 #endif /* I18N_MB */
566 char*
567 FindImage(char **paths, char *file)
569 char *tmp, *path;
571 tmp = strrchr(file, ':');
572 if (tmp) {
573 *tmp = 0;
574 path = wfindfileinlist(paths, file);
575 *tmp = ':';
577 if (!tmp || !path) {
578 path = wfindfileinlist(paths, file);
580 return path;
584 char*
585 FlattenStringList(char **list, int count)
587 int i, j;
588 char *flat_string, *wspace;
590 j = 0;
591 for (i=0; i<count; i++) {
592 if (list[i]!=NULL && list[i][0]!=0) {
593 j += strlen(list[i]);
594 if (strpbrk(list[i], " \t"))
595 j += 2;
599 flat_string = malloc(j+count+1);
600 if (!flat_string) {
601 return NULL;
604 strcpy(flat_string, list[0]);
605 for (i=1; i<count; i++) {
606 if (list[i]!=NULL && list[i][0]!=0) {
607 strcat(flat_string, " ");
608 wspace = strpbrk(list[i], " \t");
609 if (wspace)
610 strcat(flat_string, "\"");
611 strcat(flat_string, list[i]);
612 if (wspace)
613 strcat(flat_string, "\"");
617 return flat_string;
623 *----------------------------------------------------------------------
624 * ParseCommand --
625 * Divides a command line into a argv/argc pair.
626 *----------------------------------------------------------------------
628 #define PRC_ALPHA 0
629 #define PRC_BLANK 1
630 #define PRC_ESCAPE 2
631 #define PRC_DQUOTE 3
632 #define PRC_EOS 4
633 #define PRC_SQUOTE 5
635 typedef struct {
636 short nstate;
637 short output;
638 } DFA;
641 static DFA mtable[9][6] = {
642 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
643 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
644 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
645 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
646 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
647 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
648 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
649 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
650 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
653 char*
654 next_token(char *word, char **next)
656 char *ptr;
657 char *ret, *t;
658 int state, ctype;
660 t = ret = wmalloc(strlen(word)+1);
661 ptr = word;
663 state = 0;
664 *t = 0;
665 while (1) {
666 if (*ptr==0)
667 ctype = PRC_EOS;
668 else if (*ptr=='\\')
669 ctype = PRC_ESCAPE;
670 else if (*ptr=='"')
671 ctype = PRC_DQUOTE;
672 else if (*ptr=='\'')
673 ctype = PRC_SQUOTE;
674 else if (*ptr==' ' || *ptr=='\t')
675 ctype = PRC_BLANK;
676 else
677 ctype = PRC_ALPHA;
679 if (mtable[state][ctype].output) {
680 *t = *ptr; t++;
681 *t = 0;
683 state = mtable[state][ctype].nstate;
684 ptr++;
685 if (mtable[state][0].output<0) {
686 break;
690 if (*ret==0)
691 t = NULL;
692 else
693 t = wstrdup(ret);
695 free(ret);
697 if (ctype==PRC_EOS)
698 *next = NULL;
699 else
700 *next = ptr;
702 return t;
706 void
707 ParseCommand(char *command, char ***argv, int *argc)
709 LinkedList *list = NULL;
710 char *token, *line;
711 int count, i;
713 line = command;
714 do {
715 token = next_token(line, &line);
716 if (token) {
717 list = list_cons(token, list);
719 } while (token!=NULL && line!=NULL);
721 count = list_length(list);
722 *argv = wmalloc(sizeof(char*)*count);
723 i = count;
724 while (list!=NULL) {
725 (*argv)[--i] = list->head;
726 list_remove_head(&list);
728 *argc = count;
731 #if 0
732 static void
733 timeup(void *foo)
735 *(int*)foo=1;
737 #endif
738 static char*
739 getselection(WScreen *scr)
741 char *tmp;
742 extern char *W_GetTextSelection(); /* in WINGs */
744 tmp = W_GetTextSelection(scr->wmscreen, XA_PRIMARY);
745 if (!tmp)
746 tmp = W_GetTextSelection(scr->wmscreen, XA_CUT_BUFFER0);
747 return tmp;
749 #if 0
750 XEvent event;
751 int timeover=0;
752 WMHandlerID *id;
754 #ifdef DEBUG
755 puts("getting selection");
756 #endif
757 RequestSelection(dpy, scr->no_focus_win, LastTimestamp);
758 /* timeout on 1 sec. */
759 id = WMAddTimerHandler(1000, timeup, &timeover);
760 while (!timeover) {
761 WMNextEvent(dpy, &event);
762 if (event.type == SelectionNotify
763 && event.xany.window==scr->no_focus_win) {
764 WMDeleteTimerHandler(id);
765 #ifdef DEBUG
766 puts("selection ok");
767 #endif
768 return GetSelection(dpy, scr->no_focus_win);
769 } else {
770 WMHandleEvent(&event);
773 wwarning(_("selection timed-out"));
774 return NULL;
775 #endif
779 static char*
780 getuserinput(WScreen *scr, char *line, int *ptr)
782 char *ret;
783 char *tmp;
784 int i;
785 char buffer[256];
787 if (line[*ptr]!='(') {
788 tmp = _("Program Arguments");
789 } else {
790 i = 0;
791 while (line[*ptr]!=0 && line[*ptr]!=')') {
792 (*ptr)++;
793 if (line[*ptr]!='\\') {
794 buffer[i++] = line[*ptr];
795 } else {
796 (*ptr)++;
797 if (line[*ptr]==0)
798 break;
801 if (i>0)
802 buffer[i-1] = 0;
803 tmp = (char*)buffer;
806 ret = NULL;
807 if (wInputDialog(scr, tmp, _("Enter command arguments:"), &ret)!= WDB_OK)
808 return NULL;
809 else
810 return ret;
814 #ifdef OFFIX_DND
815 static char*
816 get_dnd_selection(WScreen *scr)
818 XTextProperty text_ret;
819 int result;
820 char **list;
821 char *flat_string;
822 int count;
824 #ifdef XDE_DND
825 if(scr->xdestring) {
826 return (wstrdup(scr->xdestring));
828 #endif
829 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
831 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
832 || text_ret.format==0 || text_ret.nitems == 0) {
833 wwarning(_("unable to get dropped data from DND drop"));
834 return NULL;
837 XTextPropertyToStringList(&text_ret, &list, &count);
839 if (!list || count<1) {
840 XFree(text_ret.value);
841 wwarning(_("error getting dropped data from DND drop"));
842 return NULL;
845 flat_string = FlattenStringList(list, count);
846 if (!flat_string) {
847 wwarning(_("out of memory while getting data from DND drop"));
850 XFreeStringList(list);
851 XFree(text_ret.value);
852 return flat_string;
854 #endif /* OFFIX_DND */
857 #define S_NORMAL 0
858 #define S_ESCAPE 1
859 #define S_OPTION 2
862 * state input new-state output
863 * NORMAL % OPTION <nil>
864 * NORMAL \ ESCAPE <nil>
865 * NORMAL etc. NORMAL <input>
866 * ESCAPE any NORMAL <input>
867 * OPTION s NORMAL <selection buffer>
868 * OPTION w NORMAL <selected window id>
869 * OPTION a NORMAL <input text>
870 * OPTION d NORMAL <OffiX DND selection object>
871 * OPTION etc. NORMAL %<input>
873 #define TMPBUFSIZE 64
874 char*
875 ExpandOptions(WScreen *scr, char *cmdline)
877 int ptr, optr, state, len, olen;
878 char *out, *nout;
879 char *selection=NULL;
880 char *user_input=NULL;
881 #ifdef OFFIX_DND
882 char *dropped_thing=NULL;
883 #endif
884 char tmpbuf[TMPBUFSIZE];
885 int slen;
887 len = strlen(cmdline);
888 olen = len+1;
889 out = malloc(olen);
890 if (!out) {
891 wwarning(_("out of memory during expansion of \"%s\""));
892 return NULL;
894 *out = 0;
895 ptr = 0; /* input line pointer */
896 optr = 0; /* output line pointer */
897 state = S_NORMAL;
898 while (ptr < len) {
899 switch (state) {
900 case S_NORMAL:
901 switch (cmdline[ptr]) {
902 case '\\':
903 state = S_ESCAPE;
904 break;
905 case '%':
906 state = S_OPTION;
907 break;
908 default:
909 state = S_NORMAL;
910 out[optr++]=cmdline[ptr];
911 break;
913 break;
914 case S_ESCAPE:
915 switch (cmdline[ptr]) {
916 case 'n':
917 out[optr++]=10;
918 break;
920 case 'r':
921 out[optr++]=13;
922 break;
924 case 't':
925 out[optr++]=9;
926 break;
928 default:
929 out[optr++]=cmdline[ptr];
931 state = S_NORMAL;
932 break;
933 case S_OPTION:
934 state = S_NORMAL;
935 switch (cmdline[ptr]) {
936 case 'w':
937 if (scr->focused_window
938 && scr->focused_window->flags.focused) {
939 sprintf(tmpbuf, "0x%x",
940 (unsigned int)scr->focused_window->client_win);
941 slen = strlen(tmpbuf);
942 olen += slen;
943 nout = realloc(out,olen);
944 if (!nout) {
945 wwarning(_("out of memory during expansion of \"%w\""));
946 goto error;
948 out = nout;
949 strcat(out,tmpbuf);
950 optr+=slen;
951 } else {
952 out[optr++]=' ';
954 break;
956 case 'a':
957 ptr++;
958 user_input = getuserinput(scr, cmdline, &ptr);
959 if (user_input) {
960 slen = strlen(user_input);
961 olen += slen;
962 nout = realloc(out,olen);
963 if (!nout) {
964 wwarning(_("out of memory during expansion of \"%a\""));
965 goto error;
967 out = nout;
968 strcat(out,user_input);
969 optr+=slen;
970 } else {
971 /* Not an error, but user has Canceled the dialog box.
972 * This will make the command to not be performed. */
973 goto error;
975 break;
977 #ifdef OFFIX_DND
978 case 'd':
979 if (!dropped_thing) {
980 dropped_thing = get_dnd_selection(scr);
982 if (!dropped_thing) {
983 scr->flags.dnd_data_convertion_status = 1;
984 goto error;
986 slen = strlen(dropped_thing);
987 olen += slen;
988 nout = realloc(out,olen);
989 if (!nout) {
990 wwarning(_("out of memory during expansion of \"%d\""));
991 goto error;
993 out = nout;
994 strcat(out,dropped_thing);
995 optr+=slen;
996 break;
997 #endif /* OFFIX_DND */
999 case 's':
1000 if (!selection) {
1001 selection = getselection(scr);
1003 if (!selection) {
1004 wwarning(_("selection not available"));
1005 goto error;
1007 slen = strlen(selection);
1008 olen += slen;
1009 nout = realloc(out,olen);
1010 if (!nout) {
1011 wwarning(_("out of memory during expansion of \"%s\""));
1012 goto error;
1014 out = nout;
1015 strcat(out,selection);
1016 optr+=slen;
1017 break;
1018 default:
1019 out[optr++]='%';
1020 out[optr++]=cmdline[ptr];
1022 break;
1024 out[optr]=0;
1025 ptr++;
1027 if (selection)
1028 XFree(selection);
1029 return out;
1031 error:
1032 free(out);
1033 if (selection)
1034 XFree(selection);
1035 return NULL;
1039 /* We don't care for upper/lower case in comparing the keys; so we
1040 have to define our own comparison function here */
1041 BOOL
1042 StringCompareHook(proplist_t pl1, proplist_t pl2)
1044 char *str1, *str2;
1046 str1 = PLGetString(pl1);
1047 str2 = PLGetString(pl2);
1049 if (strcasecmp(str1, str2)==0)
1050 return YES;
1051 else
1052 return NO;
1056 /* feof doesn't seem to work on pipes */
1058 IsEof(FILE * stream)
1060 static struct stat stinfo;
1062 fstat(fileno(stream), &stinfo);
1063 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1064 feof(stream));
1068 void
1069 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1071 char *name;
1072 char *dot;
1074 *winstance = *wclass = NULL;
1076 if (!PLIsString(value)) {
1077 wwarning(_("bad window name value in %s state info"), where);
1078 return;
1081 name = PLGetString(value);
1082 if (!name || strlen(name)==0) {
1083 wwarning(_("bad window name value in %s state info"), where);
1084 return;
1087 dot = strchr(name, '.');
1088 if (dot==name) {
1089 *wclass = wstrdup(&name[1]);
1090 *winstance = NULL;
1091 } else if (!dot) {
1092 *winstance = wstrdup(name);
1093 *wclass = NULL;
1094 } else {
1095 *dot = 0;
1096 *winstance = wstrdup(name);
1097 *dot = '.'; /* restore old string */
1098 *wclass = wstrdup(&dot[1]);
1103 #if 0
1104 static char*
1105 keysymToString(KeySym keysym, unsigned int state)
1107 XKeyEvent kev;
1108 char *buf = wmalloc(20);
1109 int count;
1111 kev.display = dpy;
1112 kev.type = KeyPress;
1113 kev.send_event = False;
1114 kev.window = DefaultRootWindow(dpy);
1115 kev.root = DefaultRootWindow(dpy);
1116 kev.same_screen = True;
1117 kev.subwindow = kev.root;
1118 kev.serial = 0x12344321;
1119 kev.time = CurrentTime;
1120 kev.state = state;
1121 kev.keycode = XKeysymToKeycode(dpy, keysym);
1122 count = XLookupString(&kev, buf, 19, NULL, NULL);
1123 buf[count] = 0;
1125 return buf;
1127 #endif
1129 char*
1130 GetShortcutString(char *text)
1132 char *buffer = NULL;
1133 char *k;
1134 int modmask = 0;
1135 /* KeySym ksym;*/
1136 int control = 0;
1137 char *tmp;
1139 tmp = text = wstrdup(text);
1141 /* get modifiers */
1142 while ((k = strchr(text, '+'))!=NULL) {
1143 int mod;
1145 *k = 0;
1146 mod = wXModifierFromKey(text);
1147 if (mod<0) {
1148 return wstrdup("bug");
1151 modmask |= mod;
1153 if (strcasecmp(text, "Meta")==0) {
1154 buffer = wstrappend(buffer, "M+");
1155 } else if (strcasecmp(text, "Alt")==0) {
1156 buffer = wstrappend(buffer, "A+");
1157 } else if (strcasecmp(text, "Shift")==0) {
1158 buffer = wstrappend(buffer, "Sh+");
1159 } else if (strcasecmp(text, "Mod1")==0) {
1160 buffer = wstrappend(buffer, "M1+");
1161 } else if (strcasecmp(text, "Mod2")==0) {
1162 buffer = wstrappend(buffer, "M2+");
1163 } else if (strcasecmp(text, "Mod3")==0) {
1164 buffer = wstrappend(buffer, "M3+");
1165 } else if (strcasecmp(text, "Mod4")==0) {
1166 buffer = wstrappend(buffer, "M4+");
1167 } else if (strcasecmp(text, "Mod5")==0) {
1168 buffer = wstrappend(buffer, "M5+");
1169 } else if (strcasecmp(text, "Control")==0) {
1170 control = 1;
1171 } else {
1172 buffer = wstrappend(buffer, text);
1174 text = k+1;
1177 if (control) {
1178 buffer = wstrappend(buffer, "^");
1180 buffer = wstrappend(buffer, text);
1182 /* get key */
1183 /* ksym = XStringToKeysym(text);
1184 tmp = keysymToString(ksym, modmask);
1185 puts(tmp);
1186 buffer = wstrappend(buffer, tmp);
1188 free(tmp);
1190 return buffer;