fixed font bug in WINGs
[wmaker-crm.git] / src / misc.c
blobe4b2612a27affa383a0ee51e964b73f752377d79
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 = strrchr(tmp, '/');
159 if (buf) *buf = 0; /* trunc filename */
160 putdef(line, " -I", tmp);
161 free(tmp);
165 /* this should be done just once, but it works this way */
166 strcpy(buffer, DEF_CONFIG_PATHS);
167 buf = strtok(buffer, ":");
169 do {
170 char fullpath[MAXLINE];
172 if (buf[0]!='~') {
173 strcpy(fullpath, buf);
174 } else {
175 char * wgethomedir();
176 /* home is statically allocated. Don't free it! */
177 char *home = wgethomedir();
179 strcpy(fullpath, home);
180 strcat(fullpath, &(buf[1]));
183 putdef(line, " -I", fullpath);
185 } while ((buf = strtok(NULL, ":"))!=NULL);
187 #undef arg
188 #ifdef DEBUG
189 puts("CPP ARGS");
190 puts(line);
191 #endif
192 return line;
194 #endif /* USECPP */
197 WWindow*
198 NextFocusWindow(WScreen *scr)
200 WWindow *tmp, *wwin, *closest, *min;
201 Window d;
203 if (!(wwin = scr->focused_window))
204 return NULL;
205 tmp = wwin->prev;
206 closest = NULL;
207 min = wwin;
208 d = 0xffffffff;
209 while (tmp) {
210 if (wWindowCanReceiveFocus(tmp)
211 && (!WFLAGP(tmp, skip_window_list)|| tmp->flags.internal_window)) {
212 if (min->client_win > tmp->client_win)
213 min = tmp;
214 if (tmp->client_win > wwin->client_win
215 && (!closest
216 || (tmp->client_win - wwin->client_win) < d)) {
217 closest = tmp;
218 d = tmp->client_win - wwin->client_win;
221 tmp = tmp->prev;
223 if (!closest||closest==wwin)
224 return min;
225 return closest;
229 WWindow*
230 PrevFocusWindow(WScreen *scr)
232 WWindow *tmp, *wwin, *closest, *max;
233 Window d;
235 if (!(wwin = scr->focused_window))
236 return NULL;
237 tmp = wwin->prev;
238 closest = NULL;
239 max = wwin;
240 d = 0xffffffff;
241 while (tmp) {
242 if (wWindowCanReceiveFocus(tmp) &&
243 (!WFLAGP(tmp, skip_window_list) || 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->core->stacking->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 static void
372 eatExpose()
374 XEvent event, foo;
376 /* compress all expose events into a single one */
378 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
379 /* ignore other exposure events for this window */
380 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
381 &foo));
382 /* eat exposes for other windows */
383 eatExpose();
385 event.xexpose.count = 0;
386 XPutBackEvent(dpy, &event);
391 void
392 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
394 time_t time0 = time(NULL);
395 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
396 int dx_is_bigger=0;
398 /* animation parameters */
399 static struct {
400 int delay;
401 int steps;
402 int slowdown;
403 } apars[5] = {
404 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
405 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
406 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
407 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
408 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
412 dx = (float)(to_x-from_x);
413 dy = (float)(to_y-from_y);
414 sx = (dx == 0 ? 0 : fabs(dx)/dx);
415 sy = (dy == 0 ? 0 : fabs(dy)/dy);
417 if (fabs(dx) > fabs(dy)) {
418 dx_is_bigger = 1;
421 if (dx_is_bigger) {
422 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
423 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
424 px = apars[(int)wPreferences.icon_slide_speed].steps;
425 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
426 px = -apars[(int)wPreferences.icon_slide_speed].steps;
427 py = (sx == 0 ? 0 : px*dy/dx);
428 } else {
429 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
430 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
431 py = apars[(int)wPreferences.icon_slide_speed].steps;
432 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
433 py = -apars[(int)wPreferences.icon_slide_speed].steps;
434 px = (sy == 0 ? 0 : py*dx/dy);
437 while (x != to_x || y != to_y) {
438 x += px;
439 y += py;
440 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
441 x = (float)to_x;
442 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
443 y = (float)to_y;
445 if (dx_is_bigger) {
446 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
447 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
448 px = apars[(int)wPreferences.icon_slide_speed].steps;
449 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
450 px = -apars[(int)wPreferences.icon_slide_speed].steps;
451 py = (sx == 0 ? 0 : px*dy/dx);
452 } else {
453 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
454 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
455 py = apars[(int)wPreferences.icon_slide_speed].steps;
456 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
457 py = -apars[(int)wPreferences.icon_slide_speed].steps;
458 px = (sy == 0 ? 0 : py*dx/dy);
461 XMoveWindow(dpy, win, (int)x, (int)y);
462 XFlush(dpy);
463 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
464 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
466 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
467 break;
469 XMoveWindow(dpy, win, to_x, to_y);
471 XSync(dpy, 0);
472 /* compress expose events */
473 eatExpose();
477 char*
478 ShrinkString(WMFont *font, char *string, int width)
480 int w, w1=0;
481 int p;
482 char *pos;
483 char *text;
484 int p1, p2, t;
486 if (wPreferences.multi_byte_text)
487 return wstrdup(string);
489 p = strlen(string);
490 w = WMWidthOfString(font, string, p);
491 text = wmalloc(strlen(string)+8);
492 strcpy(text, string);
493 if (w<=width)
494 return text;
496 pos = strchr(text, ' ');
497 if (!pos)
498 pos = strchr(text, ':');
500 if (pos) {
501 *pos = 0;
502 p = strlen(text);
503 w1 = WMWidthOfString(font, text, p);
504 if (w1 > width) {
505 w1 = 0;
506 p = 0;
507 *pos = ' ';
508 *text = 0;
509 } else {
510 *pos = 0;
511 width -= w1;
512 p++;
514 string += p;
515 p=strlen(string);
516 } else {
517 *text=0;
519 strcat(text, "...");
520 width -= WMWidthOfString(font, "...", 3);
522 pos = string;
523 p1=0;
524 p2=p;
525 t = (p2-p1)/2;
526 while (p2>p1 && p1!=t) {
527 w = WMWidthOfString(font, &string[p-t], t);
528 if (w>width) {
529 p2 = t;
530 t = p1+(p2-p1)/2;
531 } else if (w<width) {
532 p1 = t;
533 t = p1+(p2-p1)/2;
534 } else
535 p2=p1=t;
537 strcat(text, &string[p-p1]);
539 return text;
543 char*
544 FindImage(char *paths, char *file)
546 char *tmp, *path;
548 tmp = strrchr(file, ':');
549 if (tmp) {
550 *tmp = 0;
551 path = wfindfile(paths, file);
552 *tmp = ':';
554 if (!tmp || !path) {
555 path = wfindfile(paths, file);
558 return path;
562 char*
563 FlattenStringList(char **list, int count)
565 int i, j;
566 char *flat_string, *wspace;
568 j = 0;
569 for (i=0; i<count; i++) {
570 if (list[i]!=NULL && list[i][0]!=0) {
571 j += strlen(list[i]);
572 if (strpbrk(list[i], " \t"))
573 j += 2;
577 flat_string = malloc(j+count+1);
578 if (!flat_string) {
579 return NULL;
582 *flat_string = 0;
583 for (i=0; i<count; i++) {
584 if (list[i]!=NULL && list[i][0]!=0) {
585 if (i>0)
586 strcat(flat_string, " ");
587 wspace = strpbrk(list[i], " \t");
588 if (wspace)
589 strcat(flat_string, "\"");
590 strcat(flat_string, list[i]);
591 if (wspace)
592 strcat(flat_string, "\"");
596 return flat_string;
602 *----------------------------------------------------------------------
603 * ParseCommand --
604 * Divides a command line into a argv/argc pair.
605 *----------------------------------------------------------------------
607 #define PRC_ALPHA 0
608 #define PRC_BLANK 1
609 #define PRC_ESCAPE 2
610 #define PRC_DQUOTE 3
611 #define PRC_EOS 4
612 #define PRC_SQUOTE 5
614 typedef struct {
615 short nstate;
616 short output;
617 } DFA;
620 static DFA mtable[9][6] = {
621 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
622 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
623 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
624 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
625 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
626 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
627 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
628 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
629 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
632 char*
633 next_token(char *word, char **next)
635 char *ptr;
636 char *ret, *t;
637 int state, ctype;
639 t = ret = wmalloc(strlen(word)+1);
640 ptr = word;
642 state = 0;
643 *t = 0;
644 while (1) {
645 if (*ptr==0)
646 ctype = PRC_EOS;
647 else if (*ptr=='\\')
648 ctype = PRC_ESCAPE;
649 else if (*ptr=='"')
650 ctype = PRC_DQUOTE;
651 else if (*ptr=='\'')
652 ctype = PRC_SQUOTE;
653 else if (*ptr==' ' || *ptr=='\t')
654 ctype = PRC_BLANK;
655 else
656 ctype = PRC_ALPHA;
658 if (mtable[state][ctype].output) {
659 *t = *ptr; t++;
660 *t = 0;
662 state = mtable[state][ctype].nstate;
663 ptr++;
664 if (mtable[state][0].output<0) {
665 break;
669 if (*ret==0)
670 t = NULL;
671 else
672 t = wstrdup(ret);
674 free(ret);
676 if (ctype==PRC_EOS)
677 *next = NULL;
678 else
679 *next = ptr;
681 return t;
685 void
686 ParseCommand(char *command, char ***argv, int *argc)
688 WMBag *bag = WMCreateBag(4);
689 char *token, *line;
690 int count, j;
692 line = command;
693 do {
694 token = next_token(line, &line);
695 if (token) {
696 WMPutInBag(bag, token);
698 } while (token!=NULL && line!=NULL);
700 count = WMGetBagItemCount(bag);
701 *argv = wmalloc(sizeof(char*)*count);
702 for (j = 0; j < count; j++) {
703 (*argv)[j] = WMGetFromBag(bag, j);
705 *argc = count;
707 WMFreeBag(bag);
710 #if 0
711 static void
712 timeup(void *foo)
714 *(int*)foo=1;
716 #endif
717 static char*
718 getselection(WScreen *scr)
720 char *tmp;
721 extern char *W_GetTextSelection(); /* in WINGs */
723 tmp = W_GetTextSelection(scr->wmscreen, XA_PRIMARY);
724 if (!tmp)
725 tmp = W_GetTextSelection(scr->wmscreen, XA_CUT_BUFFER0);
726 return tmp;
728 #if 0
729 XEvent event;
730 int timeover=0;
731 WMHandlerID *id;
733 #ifdef DEBUG
734 puts("getting selection");
735 #endif
736 RequestSelection(dpy, scr->no_focus_win, LastTimestamp);
737 /* timeout on 1 sec. */
738 id = WMAddTimerHandler(1000, timeup, &timeover);
739 while (!timeover) {
740 WMNextEvent(dpy, &event);
741 if (event.type == SelectionNotify
742 && event.xany.window==scr->no_focus_win) {
743 WMDeleteTimerHandler(id);
744 #ifdef DEBUG
745 puts("selection ok");
746 #endif
747 return GetSelection(dpy, scr->no_focus_win);
748 } else {
749 WMHandleEvent(&event);
752 wwarning(_("selection timed-out"));
753 return NULL;
754 #endif
758 static char*
759 getuserinput(WScreen *scr, char *line, int *ptr)
761 char *ret;
762 char *title;
763 char *prompt;
764 int j, state;
765 int begin = 0;
766 char tbuffer[256], pbuffer[256];
768 title = _("Program Arguments");
769 prompt = _("Enter command arguments:");
770 ret = NULL;
772 #define _STARTING 0
773 #define _TITLE 1
774 #define _PROMPT 2
775 #define _DONE 3
777 state = _STARTING;
778 j = 0;
779 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
780 switch (state) {
781 case _STARTING:
782 if (line[*ptr]=='(') {
783 state = _TITLE;
784 begin = *ptr+1;
785 } else {
786 state = _DONE;
788 break;
790 case _TITLE:
791 if (j <= 0 && line[*ptr]==',') {
793 j = 0;
794 if (*ptr > begin) {
795 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
796 tbuffer[WMIN(*ptr-begin, 255)] = 0;
797 title = (char*)tbuffer;
799 begin = *ptr+1;
800 state = _PROMPT;
802 } else if (j <= 0 && line[*ptr]==')') {
804 if (*ptr > begin) {
805 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
806 tbuffer[WMIN(*ptr-begin, 255)] = 0;
807 title = (char*)tbuffer;
809 state = _DONE;
811 } else if (line[*ptr]=='(') {
812 j++;
813 } else if (line[*ptr]==')') {
814 j--;
817 break;
819 case _PROMPT:
820 if (line[*ptr]==')' && j==0) {
822 if (*ptr-begin > 1) {
823 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255));
824 pbuffer[WMIN(*ptr-begin, 255)] = 0;
825 prompt = (char*)pbuffer;
827 state = _DONE;
828 } else if (line[*ptr]=='(')
829 j++;
830 else if (line[*ptr]==')')
831 j--;
832 break;
835 (*ptr)--;
836 #undef _STARTING
837 #undef _TITLE
838 #undef _PROMPT
839 #undef _DONE
841 if (!wInputDialog(scr, title, prompt, &ret))
842 return NULL;
843 else
844 return ret;
848 #ifdef OFFIX_DND
849 static char*
850 get_dnd_selection(WScreen *scr)
852 XTextProperty text_ret;
853 int result;
854 char **list;
855 char *flat_string;
856 int count;
858 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
860 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
861 || text_ret.format==0 || text_ret.nitems == 0) {
862 wwarning(_("unable to get dropped data from DND drop"));
863 return NULL;
866 XTextPropertyToStringList(&text_ret, &list, &count);
868 if (!list || count<1) {
869 XFree(text_ret.value);
870 wwarning(_("error getting dropped data from DND drop"));
871 return NULL;
874 flat_string = FlattenStringList(list, count);
875 if (!flat_string) {
876 wwarning(_("out of memory while getting data from DND drop"));
879 XFreeStringList(list);
880 XFree(text_ret.value);
881 return flat_string;
883 #endif /* OFFIX_DND */
886 #define S_NORMAL 0
887 #define S_ESCAPE 1
888 #define S_OPTION 2
891 * state input new-state output
892 * NORMAL % OPTION <nil>
893 * NORMAL \ ESCAPE <nil>
894 * NORMAL etc. NORMAL <input>
895 * ESCAPE any NORMAL <input>
896 * OPTION s NORMAL <selection buffer>
897 * OPTION w NORMAL <selected window id>
898 * OPTION a NORMAL <input text>
899 * OPTION d NORMAL <OffiX DND selection object>
900 * OPTION W NORMAL <current workspace>
901 * OPTION etc. NORMAL %<input>
903 #define TMPBUFSIZE 64
904 char*
905 ExpandOptions(WScreen *scr, char *cmdline)
907 int ptr, optr, state, len, olen;
908 char *out, *nout;
909 char *selection=NULL;
910 char *user_input=NULL;
911 #if defined(OFFIX_DND) || defined(XDND)
912 char *dropped_thing=NULL;
913 #endif
914 char tmpbuf[TMPBUFSIZE];
915 int slen;
917 len = strlen(cmdline);
918 olen = len+1;
919 out = malloc(olen);
920 if (!out) {
921 wwarning(_("out of memory during expansion of \"%s\""));
922 return NULL;
924 *out = 0;
925 ptr = 0; /* input line pointer */
926 optr = 0; /* output line pointer */
927 state = S_NORMAL;
928 while (ptr < len) {
929 switch (state) {
930 case S_NORMAL:
931 switch (cmdline[ptr]) {
932 case '\\':
933 state = S_ESCAPE;
934 break;
935 case '%':
936 state = S_OPTION;
937 break;
938 default:
939 state = S_NORMAL;
940 out[optr++]=cmdline[ptr];
941 break;
943 break;
944 case S_ESCAPE:
945 switch (cmdline[ptr]) {
946 case 'n':
947 out[optr++]=10;
948 break;
950 case 'r':
951 out[optr++]=13;
952 break;
954 case 't':
955 out[optr++]=9;
956 break;
958 default:
959 out[optr++]=cmdline[ptr];
961 state = S_NORMAL;
962 break;
963 case S_OPTION:
964 state = S_NORMAL;
965 switch (cmdline[ptr]) {
966 case 'w':
967 if (scr->focused_window
968 && scr->focused_window->flags.focused) {
969 sprintf(tmpbuf, "0x%x",
970 (unsigned int)scr->focused_window->client_win);
971 slen = strlen(tmpbuf);
972 olen += slen;
973 nout = realloc(out,olen);
974 if (!nout) {
975 wwarning(_("out of memory during expansion of \"%w\""));
976 goto error;
978 out = nout;
979 strcat(out,tmpbuf);
980 optr+=slen;
981 } else {
982 out[optr++]=' ';
984 break;
986 case 'W':
987 sprintf(tmpbuf, "0x%x",
988 (unsigned int)scr->current_workspace + 1);
989 slen = strlen(tmpbuf);
990 olen += slen;
991 nout = realloc(out,olen);
992 if (!nout) {
993 wwarning(_("out of memory during expansion of \"%W\""));
994 goto error;
996 out = nout;
997 strcat(out,tmpbuf);
998 optr+=slen;
999 break;
1001 case 'a':
1002 ptr++;
1003 user_input = getuserinput(scr, cmdline, &ptr);
1004 if (user_input) {
1005 slen = strlen(user_input);
1006 olen += slen;
1007 nout = realloc(out,olen);
1008 if (!nout) {
1009 wwarning(_("out of memory during expansion of \"%a\""));
1010 goto error;
1012 out = nout;
1013 strcat(out,user_input);
1014 optr+=slen;
1015 } else {
1016 /* Not an error, but user has Canceled the dialog box.
1017 * This will make the command to not be performed. */
1018 goto error;
1020 break;
1022 #if defined(OFFIX_DND) || defined(XDND)
1023 case 'd':
1024 #ifdef XDND
1025 if(scr->xdestring) {
1026 dropped_thing = wstrdup(scr->xdestring);
1028 #endif
1029 if (!dropped_thing) {
1030 dropped_thing = get_dnd_selection(scr);
1032 if (!dropped_thing) {
1033 scr->flags.dnd_data_convertion_status = 1;
1034 goto error;
1036 slen = strlen(dropped_thing);
1037 olen += slen;
1038 nout = realloc(out,olen);
1039 if (!nout) {
1040 wwarning(_("out of memory during expansion of \"%d\""));
1041 goto error;
1043 out = nout;
1044 strcat(out,dropped_thing);
1045 optr+=slen;
1046 break;
1047 #endif /* OFFIX_DND */
1049 case 's':
1050 if (!selection) {
1051 selection = getselection(scr);
1053 if (!selection) {
1054 wwarning(_("selection not available"));
1055 goto error;
1057 slen = strlen(selection);
1058 olen += slen;
1059 nout = realloc(out,olen);
1060 if (!nout) {
1061 wwarning(_("out of memory during expansion of \"%s\""));
1062 goto error;
1064 out = nout;
1065 strcat(out,selection);
1066 optr+=slen;
1067 break;
1068 default:
1069 out[optr++]='%';
1070 out[optr++]=cmdline[ptr];
1072 break;
1074 out[optr]=0;
1075 ptr++;
1077 if (selection)
1078 XFree(selection);
1079 return out;
1081 error:
1082 free(out);
1083 if (selection)
1084 XFree(selection);
1085 return NULL;
1089 /* We don't care for upper/lower case in comparing the keys; so we
1090 have to define our own comparison function here */
1091 BOOL
1092 StringCompareHook(proplist_t pl1, proplist_t pl2)
1094 char *str1, *str2;
1096 str1 = PLGetString(pl1);
1097 str2 = PLGetString(pl2);
1099 if (strcasecmp(str1, str2)==0)
1100 return YES;
1101 else
1102 return NO;
1106 /* feof doesn't seem to work on pipes */
1108 IsEof(FILE * stream)
1110 static struct stat stinfo;
1112 fstat(fileno(stream), &stinfo);
1113 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1114 feof(stream));
1118 void
1119 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1121 char *name;
1123 *winstance = *wclass = NULL;
1125 if (!PLIsString(value)) {
1126 wwarning(_("bad window name value in %s state info"), where);
1127 return;
1130 name = PLGetString(value);
1131 if (!name || strlen(name)==0) {
1132 wwarning(_("bad window name value in %s state info"), where);
1133 return;
1136 UnescapeWM_CLASS(name, winstance, wclass);
1140 #if 0
1141 static char*
1142 keysymToString(KeySym keysym, unsigned int state)
1144 XKeyEvent kev;
1145 char *buf = wmalloc(20);
1146 int count;
1148 kev.display = dpy;
1149 kev.type = KeyPress;
1150 kev.send_event = False;
1151 kev.window = DefaultRootWindow(dpy);
1152 kev.root = DefaultRootWindow(dpy);
1153 kev.same_screen = True;
1154 kev.subwindow = kev.root;
1155 kev.serial = 0x12344321;
1156 kev.time = CurrentTime;
1157 kev.state = state;
1158 kev.keycode = XKeysymToKeycode(dpy, keysym);
1159 count = XLookupString(&kev, buf, 19, NULL, NULL);
1160 buf[count] = 0;
1162 return buf;
1164 #endif
1166 char*
1167 GetShortcutString(char *text)
1169 char *buffer = NULL;
1170 char *k;
1171 int modmask = 0;
1172 /* KeySym ksym;*/
1173 int control = 0;
1174 char *tmp;
1176 tmp = text = wstrdup(text);
1178 /* get modifiers */
1179 while ((k = strchr(text, '+'))!=NULL) {
1180 int mod;
1182 *k = 0;
1183 mod = wXModifierFromKey(text);
1184 if (mod<0) {
1185 return wstrdup("bug");
1188 modmask |= mod;
1190 if (strcasecmp(text, "Meta")==0) {
1191 buffer = wstrappend(buffer, "M+");
1192 } else if (strcasecmp(text, "Alt")==0) {
1193 buffer = wstrappend(buffer, "A+");
1194 } else if (strcasecmp(text, "Shift")==0) {
1195 buffer = wstrappend(buffer, "Sh+");
1196 } else if (strcasecmp(text, "Mod1")==0) {
1197 buffer = wstrappend(buffer, "M1+");
1198 } else if (strcasecmp(text, "Mod2")==0) {
1199 buffer = wstrappend(buffer, "M2+");
1200 } else if (strcasecmp(text, "Mod3")==0) {
1201 buffer = wstrappend(buffer, "M3+");
1202 } else if (strcasecmp(text, "Mod4")==0) {
1203 buffer = wstrappend(buffer, "M4+");
1204 } else if (strcasecmp(text, "Mod5")==0) {
1205 buffer = wstrappend(buffer, "M5+");
1206 } else if (strcasecmp(text, "Control")==0) {
1207 control = 1;
1208 } else {
1209 buffer = wstrappend(buffer, text);
1211 text = k+1;
1214 if (control) {
1215 buffer = wstrappend(buffer, "^");
1217 buffer = wstrappend(buffer, text);
1219 /* get key */
1220 /* ksym = XStringToKeysym(text);
1221 tmp = keysymToString(ksym, modmask);
1222 puts(tmp);
1223 buffer = wstrappend(buffer, tmp);
1225 free(tmp);
1227 return buffer;
1231 char*
1232 EscapeWM_CLASS(char *name, char *class)
1234 char *ret;
1235 char *ename = NULL, *eclass = NULL;
1236 int i, j, l;
1238 if (!name && !class)
1239 return NULL;
1241 if (name) {
1242 l = strlen(name);
1243 ename = wmalloc(l*2);
1244 j = 0;
1245 for (i=0; i<l; i++) {
1246 if (name[i]=='\\') {
1247 ename[j++] = '\\';
1248 } else if (name[i]=='.') {
1249 ename[j++] = '\\';
1251 ename[j++] = name[i];
1253 ename[j] = 0;
1255 if (class) {
1256 l = strlen(class);
1257 eclass = wmalloc(l*2);
1258 j = 0;
1259 for (i=0; i<l; i++) {
1260 if (class[i]=='\\') {
1261 eclass[j++] = '\\';
1262 } else if (class[i]=='.') {
1263 eclass[j++] = '\\';
1265 eclass[j++] = class[i];
1267 eclass[j] = 0;
1270 if (ename && eclass) {
1271 ret = wmalloc(strlen(ename)+strlen(eclass)+4);
1272 sprintf(ret, "%s.%s", ename, eclass);
1273 free(ename);
1274 free(eclass);
1275 } else if (ename) {
1276 ret = wstrdup(ename);
1277 free(ename);
1278 } else {
1279 ret = wstrdup(eclass);
1280 free(eclass);
1283 return ret;
1287 void
1288 UnescapeWM_CLASS(char *str, char **name, char **class)
1290 int i, j, k, dot;
1291 Bool esc;
1293 j = strlen(str);
1294 *name = wmalloc(j);
1295 **name = 0;
1296 *class = wmalloc(j);
1297 **class = 0;
1299 /* separate string in 2 parts */
1300 esc = False;
1301 dot = 0;
1302 for (i = 0; i < j; i++) {
1303 if (!esc) {
1304 if (str[i]=='\\') {
1305 esc = True;
1306 } else if (str[i]=='.') {
1307 dot = i;
1308 break;
1310 } else {
1311 esc = False;
1315 /* unescape strings */
1316 esc = False;
1317 k = 0;
1318 for (i = 0; i < dot; i++) {
1319 if (!esc) {
1320 if (str[i]=='\\') {
1321 esc = True;
1322 } else {
1323 (*name)[k++] = str[i];
1325 } else {
1326 (*name)[k++] = str[i];
1327 esc = False;
1330 (*name)[k] = 0;
1332 esc = False;
1333 k = 0;
1334 for (i = dot+1; i<j; i++) {
1335 if (!esc) {
1336 if (str[i]=='\\') {
1337 esc = True;
1338 } else {
1339 (*class)[k++] = str[i];
1341 } else {
1342 esc = False;
1345 (*class)[k] = 0;
1347 if (!*name) {
1348 free(*name);
1349 *name = NULL;
1351 if (!*class) {
1352 free(*class);
1353 *class = NULL;
1359 void
1360 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1362 unsigned char *buffer;
1363 int len;
1364 int i;
1365 char buf[16];
1367 if (!scr->flags.backimage_helper_launched) {
1368 return;
1371 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1372 buffer = wmalloc(len+5);
1373 sprintf(buf, "%4i", len);
1374 memcpy(buffer, buf, 4);
1375 buffer[4] = type;
1376 i = 5;
1377 if (workspace >= 0) {
1378 sprintf(buf, "%4i", workspace);
1379 memcpy(&buffer[i], buf, 4);
1380 i += 4;
1381 buffer[i] = 0;
1383 if (msg)
1384 strcpy(&buffer[i], msg);
1386 if (write(scr->helper_fd, buffer, len+4) < 0) {
1387 wsyserror(_("could not send message to background image helper"));
1389 free(buffer);
1394 typedef struct {
1395 WScreen *scr;
1396 char *command;
1397 } _tuple;
1400 static void
1401 shellCommandHandler(pid_t pid, unsigned char status, _tuple *data)
1403 if (status == 127) {
1404 char *buffer;
1406 buffer = wstrappend(_("Could not execute command: "), data->command);
1408 wMessageDialog(data->scr, _("Error"), buffer, _("OK"), NULL, NULL);
1409 free(buffer);
1410 } else if (status != 127) {
1412 printf("%s: %i\n", data->command, status);
1416 free(data->command);
1417 free(data);
1421 void
1422 ExecuteShellCommand(WScreen *scr, char *command)
1424 static char *shell = NULL;
1425 pid_t pid;
1428 * This have a problem: if the shell is tcsh (not sure about others)
1429 * and ~/.tcshrc have /bin/stty erase ^H somewhere on it, the shell
1430 * will block and the command will not be executed.
1431 if (!shell) {
1432 shell = getenv("SHELL");
1433 if (!shell)
1434 shell = "/bin/sh";
1437 shell = "/bin/sh";
1439 pid = fork();
1441 if (pid==0) {
1443 SetupEnvironment(scr);
1445 #ifdef HAVE_SETPGID
1446 setpgid(0, 0);
1447 #endif
1448 execl(shell, shell, "-c", command, NULL);
1449 wsyserror("could not execute %s -c %s", shell, command);
1450 Exit(-1);
1451 } else if (pid < 0) {
1452 wsyserror("cannot fork a new process");
1453 } else {
1454 _tuple *data = wmalloc(sizeof(_tuple));
1456 data->scr = scr;
1457 data->command = wstrdup(command);
1459 wAddDeathHandler(pid, (WDeathHandler*)shellCommandHandler, data);
1467 void dbprintf(char *format, ...)
1469 va_list args;
1471 va_start(args, format);
1472 vprintf(format, args);
1473 fflush(stdout);
1474 va_end(args);
1479 void dbputs(char *text)
1481 puts(text);
1482 fflush(stdout);