Initial revision
[wmaker-crm.git] / src / misc.c
blobd7bfeff0d5ef429b8a41faeee707e5abb0c3bc92
1 /*
2 * WindowMaker 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>
34 #include <wraster.h>
36 #include "WindowMaker.h"
37 #include "GNUstep.h"
38 #include "screen.h"
39 #include "wcore.h"
40 #include "window.h"
41 #include "framewin.h"
42 #include "funcs.h"
43 #include "defaults.h"
44 #include "dialog.h"
45 #include "xutil.h"
46 #include "xmodifier.h"
48 #include "list.h"
50 /**** global variables *****/
52 extern char *DisplayName;
54 extern WPreferences wPreferences;
56 extern Time LastTimestamp;
60 #ifdef OFFIX_DND
61 extern Atom _XA_DND_SELECTION;
62 #endif
65 #ifdef USECPP
66 static void
67 putdef(char *line, char *name, char *value)
69 if (!value) {
70 wwarning(_("could not define value for %s for cpp"), name);
71 return;
73 strcat(line, name);
74 strcat(line, value);
79 static void
80 putidef(char *line, char *name, int value)
82 char tmp[64];
83 sprintf(tmp, "%i", value);
84 strcat(line, name);
85 strcat(line, tmp);
89 static char*
90 username()
92 char *tmp;
94 tmp = getlogin();
95 if (!tmp) {
96 struct passwd *user;
98 user = getpwuid(getuid());
99 if (!user) {
100 wsyserror(_("could not get password entry for UID %i"), getuid());
101 return NULL;
103 if (!user->pw_name) {
104 return NULL;
105 } else {
106 return user->pw_name;
109 return tmp;
112 char *
113 MakeCPPArgs(char *path)
115 int i;
116 char buffer[MAXLINE], *buf, *line;
117 Visual *visual;
119 line = wmalloc(MAXLINE);
120 *line = 0;
121 i=1;
122 if ((buf=getenv("HOSTNAME"))!=NULL) {
123 if (buf[0]=='(') {
124 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"),
125 buf);
126 } else
127 putdef(line, " -DHOST=", buf);
128 } else if ((buf=getenv("HOST"))!=NULL) {
129 if (buf[0]=='(') {
130 wwarning(_("your machine is misconfigured. HOST is set to %s"),
131 buf);
132 } else
133 putdef(line, " -DHOST=", buf);
135 buf = username();
136 if (buf)
137 putdef(line, " -DUSER=", buf);
138 putidef(line, " -DUID=", getuid());
139 buf = XDisplayName(DisplayString(dpy));
140 putdef(line, " -DDISPLAY=", buf);
141 putdef(line, " -DWM_VERSION=", VERSION);
143 visual = DefaultVisual(dpy, DefaultScreen(dpy));
144 putidef(line, " -DVISUAL=", visual->class);
146 putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy)));
148 putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy)));
149 putidef(line, " -DSCR_HEIGHT=",
150 HeightOfScreen(DefaultScreenOfDisplay(dpy)));
152 #if 0
153 strcpy(buffer, path);
154 buf = strrchr(buffer, '/');
155 if (buf) *buf = 0; /* trunc filename */
156 putdef(line, " -I", buffer);
157 #endif
161 /* this should be done just once, but it works this way */
162 strcpy(buffer, DEF_CONFIG_PATHS);
163 buf = strtok(buffer, ":");
165 do {
166 char fullpath[MAXLINE];
168 if (buf[0]!='~') {
169 strcpy(fullpath, buf);
170 } else {
171 char * wgethomedir();
172 /* home is statically allocated. Don't free it! */
173 char *home = wgethomedir();
175 strcpy(fullpath, home);
176 strcat(fullpath, &(buf[1]));
179 putdef(line, " -I", fullpath);
181 } while ((buf = strtok(NULL, ":"))!=NULL);
183 #undef arg
184 #ifdef DEBUG
185 puts("CPP ARGS");
186 puts(line);
187 #endif
188 return line;
190 #endif /* USECPP */
194 WWindow*
195 NextFocusWindow(WScreen *scr)
197 WWindow *tmp, *wwin, *closest, *min;
198 Window d;
200 if (!(wwin = scr->focused_window))
201 return NULL;
202 tmp = wwin->prev;
203 closest = NULL;
204 min = wwin;
205 d = 0xffffffff;
206 while (tmp) {
207 if (wWindowCanReceiveFocus(tmp)
208 && (!tmp->window_flags.skip_window_list
209 || tmp->flags.internal_window)) {
210 if (min->client_win > tmp->client_win)
211 min = tmp;
212 if (tmp->client_win > wwin->client_win
213 && (!closest
214 || (tmp->client_win - wwin->client_win) < d)) {
215 closest = tmp;
216 d = tmp->client_win - wwin->client_win;
219 tmp = tmp->prev;
221 if (!closest||closest==wwin)
222 return min;
223 return closest;
227 WWindow*
228 PrevFocusWindow(WScreen *scr)
230 WWindow *tmp, *wwin, *closest, *max;
231 Window d;
233 if (!(wwin = scr->focused_window))
234 return NULL;
235 tmp = wwin->prev;
236 closest = NULL;
237 max = wwin;
238 d = 0xffffffff;
239 while (tmp) {
240 if (wWindowCanReceiveFocus(tmp) &&
241 (!tmp->window_flags.skip_window_list
242 || tmp->flags.internal_window)) {
243 if (max->client_win < tmp->client_win)
244 max = tmp;
245 if (tmp->client_win < wwin->client_win
246 && (!closest
247 || (wwin->client_win - tmp->client_win) < d)) {
248 closest = tmp;
249 d = wwin->client_win - tmp->client_win;
252 tmp = tmp->prev;
254 if (!closest||closest==wwin)
255 return max;
256 return closest;
261 #if 0
263 * Is win2 below win1?
265 static Bool
266 isBelow(WWindow *win1, WWindow *win2)
268 int i;
269 WCoreWindow *tmp;
271 tmp = win1->frame->core->stacking->under;
272 while (tmp) {
273 if (tmp == win2->frame->core)
274 return True;
275 tmp = tmp->stacking->under;
278 for (i=win1->frame->window_level-1; i>=0; i--) {
279 tmp = win1->screen_ptr->stacking_list[i];
280 while (tmp) {
281 if (tmp == win2->frame->core)
282 return True;
283 tmp = tmp->stacking->under;
286 return True;
288 #endif
293 * XFetchName Wrapper
296 Bool wFetchName(dpy, win, winname)
297 Display *dpy;
298 Window win;
299 char **winname;
301 XTextProperty text_prop;
302 char **list;
303 int num;
305 if (XGetWMName(dpy, win, &text_prop)) {
306 if (text_prop.value && text_prop.nitems > 0) {
307 if (text_prop.encoding == XA_STRING) {
308 *winname = wstrdup((char *)text_prop.value);
309 XFree(text_prop.value);
310 } else {
311 text_prop.nitems = strlen((char *)text_prop.value);
312 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
313 Success && num > 0 && *list) {
314 XFree(text_prop.value);
315 *winname = wstrdup(*list);
316 XFreeStringList(list);
317 } else {
318 *winname = wstrdup((char *)text_prop.value);
319 XFree(text_prop.value);
322 } else {
323 /* the title is set, but it was set to none */
324 *winname = wstrdup("");
326 return True;
327 } else {
328 /* the hint is probably not set */
329 *winname = NULL;
331 return False;
336 * XGetIconName Wrapper
340 Bool wGetIconName(dpy, win, iconname)
341 Display *dpy;
342 Window win;
343 char **iconname;
345 XTextProperty text_prop;
346 char **list;
347 int num;
349 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
350 && text_prop.nitems > 0) {
351 if (text_prop.encoding == XA_STRING)
352 *iconname = (char *)text_prop.value;
353 else {
354 text_prop.nitems = strlen((char *)text_prop.value);
355 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
356 Success && num > 0 && *list) {
357 XFree(text_prop.value);
358 *iconname = wstrdup(*list);
359 XFreeStringList(list);
360 } else
361 *iconname = (char *)text_prop.value;
363 return True;
365 *iconname = NULL;
366 return False;
370 #if 0
371 #ifdef I18N_MB
372 void
373 wTextWidth(XFontSet font, char *text, int length)
375 XRectangle rect;
376 XRectangle AIXsucks;
378 XmbTextExtents(font, text, length, &AIXsucks, &rec);
380 return rect.width;
382 #else
383 void
384 wTextWidth(XFontStruct *font, char *text, int length)
386 return XTextWidth(font, text, length);
388 #endif
389 #endif
391 static void
392 eatExpose()
394 XEvent event, foo;
396 /* compress all expose events into a single one */
398 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
399 /* ignore other exposure events for this window */
400 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
401 &foo));
402 /* eat exposes for other windows */
403 eatExpose();
405 event.xexpose.count = 0;
406 XPutBackEvent(dpy, &event);
411 void
412 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
414 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
415 int dx_is_bigger=0;
416 /* animation parameters */
417 static struct {
418 int delay;
419 int steps;
420 int slowdown;
421 } apars[5] = {
422 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
423 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
424 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
425 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
426 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
430 dx = (float)(to_x-from_x);
431 dy = (float)(to_y-from_y);
432 sx = (dx == 0 ? 0 : fabs(dx)/dx);
433 sy = (dy == 0 ? 0 : fabs(dy)/dy);
435 if (fabs(dx) > fabs(dy)) {
436 dx_is_bigger = 1;
439 if (dx_is_bigger) {
440 px = dx / apars[wPreferences.icon_slide_speed].slowdown;
441 if (px < apars[wPreferences.icon_slide_speed].steps && px > 0)
442 px = apars[wPreferences.icon_slide_speed].steps;
443 else if (px > -apars[wPreferences.icon_slide_speed].steps && px < 0)
444 px = -apars[wPreferences.icon_slide_speed].steps;
445 py = (sx == 0 ? 0 : px*dy/dx);
446 } else {
447 py = dy / apars[wPreferences.icon_slide_speed].slowdown;
448 if (py < apars[wPreferences.icon_slide_speed].steps && py > 0)
449 py = apars[wPreferences.icon_slide_speed].steps;
450 else if (py > -apars[wPreferences.icon_slide_speed].steps && py < 0)
451 py = -apars[wPreferences.icon_slide_speed].steps;
452 px = (sy == 0 ? 0 : py*dx/dy);
455 while (x != to_x || y != to_y) {
456 x += px;
457 y += py;
458 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
459 x = (float)to_x;
460 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
461 y = (float)to_y;
463 if (dx_is_bigger) {
464 px = px * (1.0 - 1/(float)apars[wPreferences.icon_slide_speed].slowdown);
465 if (px < apars[wPreferences.icon_slide_speed].steps && px > 0)
466 px = apars[wPreferences.icon_slide_speed].steps;
467 else if (px > -apars[wPreferences.icon_slide_speed].steps && px < 0)
468 px = -apars[wPreferences.icon_slide_speed].steps;
469 py = (sx == 0 ? 0 : px*dy/dx);
470 } else {
471 py = py * (1.0 - 1/(float)apars[wPreferences.icon_slide_speed].slowdown);
472 if (py < apars[wPreferences.icon_slide_speed].steps && py > 0)
473 py = apars[wPreferences.icon_slide_speed].steps;
474 else if (py > -apars[wPreferences.icon_slide_speed].steps && py < 0)
475 py = -apars[wPreferences.icon_slide_speed].steps;
476 px = (sy == 0 ? 0 : py*dx/dy);
479 XMoveWindow(dpy, win, (int)x, (int)y);
480 XFlush(dpy);
481 if (apars[wPreferences.icon_slide_speed].delay > 0) {
482 wusleep(apars[wPreferences.icon_slide_speed].delay*1000L);
485 XMoveWindow(dpy, win, to_x, to_y);
487 XSync(dpy, 0);
488 /* compress expose events */
489 eatExpose();
493 char*
494 ShrinkString(WFont *font, char *string, int width)
496 #ifndef I18N_MB
497 int w, w1=0;
498 int p;
499 char *pos;
500 char *text;
501 int p1, p2, t;
502 #endif
504 #ifdef I18N_MB
505 return wstrdup(string);
506 #else
507 p = strlen(string);
508 w = wTextWidth(font->font, string, p);
509 text = wmalloc(strlen(string)+8);
510 strcpy(text, string);
511 if (w<=width)
512 return text;
514 pos = strchr(text, ' ');
515 if (!pos)
516 pos = strchr(text, ':');
518 if (pos) {
519 *pos = 0;
520 p = strlen(text);
521 w1=wTextWidth(font->font, text, p);
522 if (w1>width) {
523 w1 = 0;
524 p = 0;
525 *pos = ' ';
526 *text = 0;
527 } else {
528 *pos = 0;
529 width -= w1;
530 p++;
532 string += p;
533 p=strlen(string);
534 } else {
535 *text=0;
537 strcat(text, "...");
538 width -= wTextWidth(font->font, "...", 3);
540 pos = string;
541 p1=0;
542 p2=p;
543 t = (p2-p1)/2;
544 while (p2>p1 && p1!=t) {
545 w = wTextWidth(font->font, &string[p-t], t);
546 if (w>width) {
547 p2 = t;
548 t = p1+(p2-p1)/2;
549 } else if (w<width) {
550 p1 = t;
551 t = p1+(p2-p1)/2;
552 } else
553 p2=p1=t;
555 strcat(text, &string[p-p1]);
556 return text;
557 #endif /* I18N_MB */
561 char*
562 FindImage(char **paths, char *file)
564 char *tmp, *path;
566 tmp = strrchr(file, ':');
567 if (tmp) {
568 *tmp = 0;
569 path = wfindfileinlist(paths, file);
570 *tmp = ':';
572 if (!tmp || !path) {
573 path = wfindfileinlist(paths, file);
575 return path;
579 char*
580 FlattenStringList(char **list, int count)
582 int i, j;
583 char *flat_string, *wspace;
585 j = 0;
586 for (i=0; i<count; i++) {
587 if (list[i]!=NULL && list[i][0]!=0) {
588 j += strlen(list[i]);
589 if (strpbrk(list[i], " \t"))
590 j += 2;
594 flat_string = malloc(j+count+1);
595 if (!flat_string) {
596 return NULL;
599 strcpy(flat_string, list[0]);
600 for (i=1; i<count; i++) {
601 if (list[i]!=NULL && list[i][0]!=0) {
602 strcat(flat_string, " ");
603 wspace = strpbrk(list[i], " \t");
604 if (wspace)
605 strcat(flat_string, "\"");
606 strcat(flat_string, list[i]);
607 if (wspace)
608 strcat(flat_string, "\"");
612 return flat_string;
618 *----------------------------------------------------------------------
619 * ParseCommand --
620 * Divides a command line into a argv/argc pair.
621 *----------------------------------------------------------------------
623 #define PRC_ALPHA 0
624 #define PRC_BLANK 1
625 #define PRC_ESCAPE 2
626 #define PRC_DQUOTE 3
627 #define PRC_EOS 4
628 #define PRC_SQUOTE 5
630 typedef struct {
631 short nstate;
632 short output;
633 } DFA;
636 static DFA mtable[9][6] = {
637 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
638 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
639 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
640 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
641 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
642 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
643 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
644 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
645 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
648 char*
649 next_token(char *word, char **next)
651 char *ptr;
652 char *ret, *t;
653 int state, ctype;
655 t = ret = wmalloc(strlen(word)+1);
656 ptr = word;
658 state = 0;
659 *t = 0;
660 while (1) {
661 if (*ptr==0)
662 ctype = PRC_EOS;
663 else if (*ptr=='\\')
664 ctype = PRC_ESCAPE;
665 else if (*ptr=='"')
666 ctype = PRC_DQUOTE;
667 else if (*ptr=='\'')
668 ctype = PRC_SQUOTE;
669 else if (*ptr==' ' || *ptr=='\t')
670 ctype = PRC_BLANK;
671 else
672 ctype = PRC_ALPHA;
674 if (mtable[state][ctype].output) {
675 *t = *ptr; t++;
676 *t = 0;
678 state = mtable[state][ctype].nstate;
679 ptr++;
680 if (mtable[state][0].output<0) {
681 break;
685 if (*ret==0)
686 t = NULL;
687 else
688 t = wstrdup(ret);
690 free(ret);
692 if (ctype==PRC_EOS)
693 *next = NULL;
694 else
695 *next = ptr;
697 return t;
701 void
702 ParseCommand(char *command, char ***argv, int *argc)
704 LinkedList *list = NULL;
705 char *token, *line;
706 int count, i;
708 line = command;
709 do {
710 token = next_token(line, &line);
711 if (token) {
712 list = list_cons(token, list);
714 } while (token!=NULL && line!=NULL);
716 count = list_length(list);
717 *argv = wmalloc(sizeof(char*)*count);
718 i = count;
719 while (list!=NULL) {
720 (*argv)[--i] = list->head;
721 list_remove_head(&list);
723 *argc = count;
727 static void
728 timeup(void *foo)
730 *(int*)foo=1;
733 static char*
734 getselection(WScreen *scr)
736 XEvent event;
737 int timeover=0;
738 WMHandlerID *id;
740 #ifdef DEBUG
741 puts("getting selection");
742 #endif
743 RequestSelection(dpy, scr->no_focus_win, LastTimestamp);
744 /* timeout on 1 sec. */
745 id = WMAddTimerHandler(1000, timeup, &timeover);
746 while (!timeover) {
747 WMNextEvent(dpy, &event);
748 if (event.type == SelectionNotify
749 && event.xany.window==scr->no_focus_win) {
750 WMDeleteTimerHandler(id);
751 #ifdef DEBUG
752 puts("selection ok");
753 #endif
754 return GetSelection(dpy, scr->no_focus_win);
755 } else {
756 WMHandleEvent(&event);
759 wwarning(_("selection timed-out"));
760 return NULL;
764 static char*
765 getuserinput(WScreen *scr, char *line, int *ptr)
767 char *ret;
768 char *tmp;
769 int i;
770 char buffer[256];
772 if (line[*ptr]!='(') {
773 tmp = _("Program Arguments");
774 } else {
775 i = 0;
776 while (line[*ptr]!=0 && line[*ptr]!=')') {
777 (*ptr)++;
778 if (line[*ptr]!='\\') {
779 buffer[i++] = line[*ptr];
780 } else {
781 (*ptr)++;
782 if (line[*ptr]==0)
783 break;
786 if (i>0)
787 buffer[i-1] = 0;
788 tmp = (char*)buffer;
791 ret = NULL;
792 if (wInputDialog(scr, tmp, _("Enter command arguments:"), &ret)!= WDB_OK)
793 return NULL;
794 else
795 return ret;
799 #ifdef OFFIX_DND
800 static char*
801 get_dnd_selection(WScreen *scr)
803 XTextProperty text_ret;
804 int result;
805 char **list;
806 char *flat_string;
807 int count;
809 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
811 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
812 || text_ret.format==0 || text_ret.nitems == 0) {
813 wwarning(_("unable to get dropped data from DND drop"));
814 return NULL;
817 XTextPropertyToStringList(&text_ret, &list, &count);
819 if (!list || count<1) {
820 XFree(text_ret.value);
821 wwarning(_("error getting dropped data from DND drop"));
822 return NULL;
825 flat_string = FlattenStringList(list, count);
826 if (!flat_string) {
827 wwarning(_("out of memory while getting data from DND drop"));
830 XFreeStringList(list);
831 XFree(text_ret.value);
832 return flat_string;
834 #endif /* OFFIX_DND */
837 #define S_NORMAL 0
838 #define S_ESCAPE 1
839 #define S_OPTION 2
842 * state input new-state output
843 * NORMAL % OPTION <nil>
844 * NORMAL \ ESCAPE <nil>
845 * NORMAL etc. NORMAL <input>
846 * ESCAPE any NORMAL <input>
847 * OPTION s NORMAL <selection buffer>
848 * OPTION w NORMAL <selected window id>
849 * OPTION a NORMAL <input text>
850 * OPTION d NORMAL <OffiX DND selection object>
851 * OPTION etc. NORMAL %<input>
853 #define TMPBUFSIZE 64
854 char*
855 ExpandOptions(WScreen *scr, char *cmdline)
857 int ptr, optr, state, len, olen;
858 char *out, *nout;
859 char *selection=NULL;
860 char *user_input=NULL;
861 #ifdef OFFIX_DND
862 char *dropped_thing=NULL;
863 #endif
864 char tmpbuf[TMPBUFSIZE];
865 int slen;
867 len = strlen(cmdline);
868 olen = len+1;
869 out = malloc(olen);
870 if (!out) {
871 wwarning(_("out of memory during expansion of \"%s\""));
872 return NULL;
874 *out = 0;
875 ptr = 0; /* input line pointer */
876 optr = 0; /* output line pointer */
877 state = S_NORMAL;
878 while (ptr < len) {
879 switch (state) {
880 case S_NORMAL:
881 switch (cmdline[ptr]) {
882 case '\\':
883 state = S_ESCAPE;
884 break;
885 case '%':
886 state = S_OPTION;
887 break;
888 default:
889 state = S_NORMAL;
890 out[optr++]=cmdline[ptr];
891 break;
893 break;
894 case S_ESCAPE:
895 switch (cmdline[ptr]) {
896 case 'n':
897 out[optr++]=10;
898 break;
900 case 'r':
901 out[optr++]=13;
902 break;
904 case 't':
905 out[optr++]=9;
906 break;
908 default:
909 out[optr++]=cmdline[ptr];
911 state = S_NORMAL;
912 break;
913 case S_OPTION:
914 state = S_NORMAL;
915 switch (cmdline[ptr]) {
916 case 'w':
917 if (scr->focused_window
918 && scr->focused_window->flags.focused) {
919 sprintf(tmpbuf, "0x%x",
920 (unsigned int)scr->focused_window->client_win);
921 slen = strlen(tmpbuf);
922 olen += slen;
923 nout = realloc(out,olen);
924 if (!nout) {
925 wwarning(_("out of memory during expansion of \"%w\""));
926 goto error;
928 out = nout;
929 strcat(out,tmpbuf);
930 optr+=slen;
931 } else {
932 out[optr++]=' ';
934 break;
936 case 'a':
937 ptr++;
938 user_input = getuserinput(scr, cmdline, &ptr);
939 if (user_input) {
940 slen = strlen(user_input);
941 olen += slen;
942 nout = realloc(out,olen);
943 if (!nout) {
944 wwarning(_("out of memory during expansion of \"%a\""));
945 goto error;
947 out = nout;
948 strcat(out,user_input);
949 optr+=slen;
951 break;
953 #ifdef OFFIX_DND
954 case 'd':
955 if (!dropped_thing) {
956 dropped_thing = get_dnd_selection(scr);
958 if (!dropped_thing) {
959 scr->flags.dnd_data_convertion_status = 1;
960 goto error;
962 slen = strlen(dropped_thing);
963 olen += slen;
964 nout = realloc(out,olen);
965 if (!nout) {
966 wwarning(_("out of memory during expansion of \"%d\""));
967 goto error;
969 out = nout;
970 strcat(out,dropped_thing);
971 optr+=slen;
972 break;
973 #endif /* OFFIX_DND */
975 case 's':
976 if (!selection) {
977 if (!XGetSelectionOwner(dpy, XA_PRIMARY)) {
978 wwarning(_("selection not available"));
979 goto error;
981 selection = getselection(scr);
983 if (!selection) {
984 goto error;
986 slen = strlen(selection);
987 olen += slen;
988 nout = realloc(out,olen);
989 if (!nout) {
990 wwarning(_("out of memory during expansion of \"%s\""));
991 goto error;
993 out = nout;
994 strcat(out,selection);
995 optr+=slen;
996 break;
997 default:
998 out[optr++]='%';
999 out[optr++]=cmdline[ptr];
1001 break;
1003 out[optr]=0;
1004 ptr++;
1006 if (selection)
1007 XFree(selection);
1008 return out;
1010 error:
1011 free(out);
1012 if (selection)
1013 XFree(selection);
1014 return NULL;
1018 /* We don't care for upper/lower case in comparing the keys; so we
1019 have to define our own comparison function here */
1020 BOOL
1021 StringCompareHook(proplist_t pl1, proplist_t pl2)
1023 char *str1, *str2;
1025 str1 = PLGetString(pl1);
1026 str2 = PLGetString(pl2);
1028 if (strcasecmp(str1, str2)==0)
1029 return YES;
1030 else
1031 return NO;
1035 /* feof doesn't seem to work on pipes */
1037 IsEof(FILE * stream)
1039 static struct stat stinfo;
1041 fstat(fileno(stream), &stinfo);
1042 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1043 feof(stream));
1047 void
1048 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1050 char *name;
1051 char *dot;
1053 *winstance = *wclass = NULL;
1055 if (!PLIsString(value)) {
1056 wwarning(_("bad window name value in %s state info"), where);
1057 return;
1060 name = PLGetString(value);
1061 if (!name || strlen(name)==0) {
1062 wwarning(_("bad window name value in %s state info"), where);
1063 return;
1066 dot = strchr(name, '.');
1067 if (dot==name) {
1068 *wclass = wstrdup(&name[1]);
1069 *winstance = NULL;
1070 } else if (!dot) {
1071 *winstance = wstrdup(name);
1072 *wclass = NULL;
1073 } else {
1074 *dot = 0;
1075 *winstance = wstrdup(name);
1076 *dot = '.'; /* restore old string */
1077 *wclass = wstrdup(&dot[1]);
1082 #if 0
1083 static char*
1084 keysymToString(KeySym keysym, unsigned int state)
1086 XKeyEvent kev;
1087 char *buf = wmalloc(20);
1088 int count;
1090 kev.display = dpy;
1091 kev.type = KeyPress;
1092 kev.send_event = False;
1093 kev.window = DefaultRootWindow(dpy);
1094 kev.root = DefaultRootWindow(dpy);
1095 kev.same_screen = True;
1096 kev.subwindow = kev.root;
1097 kev.serial = 0x12344321;
1098 kev.time = CurrentTime;
1099 kev.state = state;
1100 kev.keycode = XKeysymToKeycode(dpy, keysym);
1101 count = XLookupString(&kev, buf, 19, NULL, NULL);
1102 buf[count] = 0;
1104 return buf;
1106 #endif
1108 char*
1109 GetShortcutString(char *text)
1111 char *buffer = NULL;
1112 char *k;
1113 int modmask = 0;
1114 /* KeySym ksym;*/
1115 int control = 0;
1116 char *tmp;
1118 tmp = text = wstrdup(text);
1120 /* get modifiers */
1121 while ((k = strchr(text, '+'))!=NULL) {
1122 int mod;
1124 *k = 0;
1125 mod = wXModifierFromKey(text);
1126 if (mod<0) {
1127 return wstrdup("bug");
1130 modmask |= mod;
1132 if (strcasecmp(text, "Meta")==0) {
1133 buffer = wstrappend(buffer, "M+");
1134 } else if (strcasecmp(text, "Alt")==0) {
1135 buffer = wstrappend(buffer, "A+");
1136 } else if (strcasecmp(text, "Shift")==0) {
1137 buffer = wstrappend(buffer, "Sh+");
1138 } else if (strcasecmp(text, "Mod1")==0) {
1139 buffer = wstrappend(buffer, "M1+");
1140 } else if (strcasecmp(text, "Mod2")==0) {
1141 buffer = wstrappend(buffer, "M2+");
1142 } else if (strcasecmp(text, "Mod3")==0) {
1143 buffer = wstrappend(buffer, "M3+");
1144 } else if (strcasecmp(text, "Mod4")==0) {
1145 buffer = wstrappend(buffer, "M4+");
1146 } else if (strcasecmp(text, "Mod5")==0) {
1147 buffer = wstrappend(buffer, "M5+");
1148 } else if (strcasecmp(text, "Control")==0) {
1149 control = 1;
1150 } else {
1151 buffer = wstrappend(buffer, text);
1153 text = k+1;
1156 if (control) {
1157 buffer = wstrappend(buffer, "^");
1159 buffer = wstrappend(buffer, text);
1161 /* get key */
1162 /* ksym = XStringToKeysym(text);
1163 tmp = keysymToString(ksym, modmask);
1164 puts(tmp);
1165 buffer = wstrappend(buffer, tmp);
1167 free(tmp);
1169 return buffer;