fixed many bugs, removed linked list
[wmaker-crm.git] / src / misc.c
blob682533bd0a965c933838182a79bf41f1686a3981
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;
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 */
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 && (!WFLAGP(tmp, skip_window_list)|| tmp->flags.internal_window)) {
209 if (min->client_win > tmp->client_win)
210 min = tmp;
211 if (tmp->client_win > wwin->client_win
212 && (!closest
213 || (tmp->client_win - wwin->client_win) < d)) {
214 closest = tmp;
215 d = tmp->client_win - wwin->client_win;
218 tmp = tmp->prev;
220 if (!closest||closest==wwin)
221 return min;
222 return closest;
226 WWindow*
227 PrevFocusWindow(WScreen *scr)
229 WWindow *tmp, *wwin, *closest, *max;
230 Window d;
232 if (!(wwin = scr->focused_window))
233 return NULL;
234 tmp = wwin->prev;
235 closest = NULL;
236 max = wwin;
237 d = 0xffffffff;
238 while (tmp) {
239 if (wWindowCanReceiveFocus(tmp) &&
240 (!WFLAGP(tmp, skip_window_list) || tmp->flags.internal_window)) {
241 if (max->client_win < tmp->client_win)
242 max = tmp;
243 if (tmp->client_win < wwin->client_win
244 && (!closest
245 || (wwin->client_win - tmp->client_win) < d)) {
246 closest = tmp;
247 d = wwin->client_win - tmp->client_win;
250 tmp = tmp->prev;
252 if (!closest||closest==wwin)
253 return max;
254 return closest;
259 #if 0
261 * Is win2 below win1?
263 static Bool
264 isBelow(WWindow *win1, WWindow *win2)
266 int i;
267 WCoreWindow *tmp;
269 tmp = win1->frame->core->stacking->under;
270 while (tmp) {
271 if (tmp == win2->frame->core)
272 return True;
273 tmp = tmp->stacking->under;
276 for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
277 tmp = win1->screen_ptr->stacking_list[i];
278 while (tmp) {
279 if (tmp == win2->frame->core)
280 return True;
281 tmp = tmp->stacking->under;
284 return True;
286 #endif
291 * XFetchName Wrapper
294 Bool wFetchName(dpy, win, winname)
295 Display *dpy;
296 Window win;
297 char **winname;
299 XTextProperty text_prop;
300 char **list;
301 int num;
303 if (XGetWMName(dpy, win, &text_prop)) {
304 if (text_prop.value && text_prop.nitems > 0) {
305 if (text_prop.encoding == XA_STRING) {
306 *winname = wstrdup((char *)text_prop.value);
307 XFree(text_prop.value);
308 } else {
309 text_prop.nitems = strlen((char *)text_prop.value);
310 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
311 Success && num > 0 && *list) {
312 XFree(text_prop.value);
313 *winname = wstrdup(*list);
314 XFreeStringList(list);
315 } else {
316 *winname = wstrdup((char *)text_prop.value);
317 XFree(text_prop.value);
320 } else {
321 /* the title is set, but it was set to none */
322 *winname = wstrdup("");
324 return True;
325 } else {
326 /* the hint is probably not set */
327 *winname = NULL;
329 return False;
334 * XGetIconName Wrapper
338 Bool wGetIconName(dpy, win, iconname)
339 Display *dpy;
340 Window win;
341 char **iconname;
343 XTextProperty text_prop;
344 char **list;
345 int num;
347 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
348 && text_prop.nitems > 0) {
349 if (text_prop.encoding == XA_STRING)
350 *iconname = (char *)text_prop.value;
351 else {
352 text_prop.nitems = strlen((char *)text_prop.value);
353 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
354 Success && num > 0 && *list) {
355 XFree(text_prop.value);
356 *iconname = wstrdup(*list);
357 XFreeStringList(list);
358 } else
359 *iconname = (char *)text_prop.value;
361 return True;
363 *iconname = NULL;
364 return False;
368 static void
369 eatExpose()
371 XEvent event, foo;
373 /* compress all expose events into a single one */
375 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
376 /* ignore other exposure events for this window */
377 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
378 &foo));
379 /* eat exposes for other windows */
380 eatExpose();
382 event.xexpose.count = 0;
383 XPutBackEvent(dpy, &event);
388 void
389 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
391 time_t time0 = time(NULL);
392 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
393 int dx_is_bigger=0;
395 /* animation parameters */
396 static struct {
397 int delay;
398 int steps;
399 int slowdown;
400 } apars[5] = {
401 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
402 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
403 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
404 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
405 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
409 dx = (float)(to_x-from_x);
410 dy = (float)(to_y-from_y);
411 sx = (dx == 0 ? 0 : fabs(dx)/dx);
412 sy = (dy == 0 ? 0 : fabs(dy)/dy);
414 if (fabs(dx) > fabs(dy)) {
415 dx_is_bigger = 1;
418 if (dx_is_bigger) {
419 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
420 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
421 px = apars[(int)wPreferences.icon_slide_speed].steps;
422 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
423 px = -apars[(int)wPreferences.icon_slide_speed].steps;
424 py = (sx == 0 ? 0 : px*dy/dx);
425 } else {
426 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
427 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
428 py = apars[(int)wPreferences.icon_slide_speed].steps;
429 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
430 py = -apars[(int)wPreferences.icon_slide_speed].steps;
431 px = (sy == 0 ? 0 : py*dx/dy);
434 while (x != to_x || y != to_y) {
435 x += px;
436 y += py;
437 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
438 x = (float)to_x;
439 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
440 y = (float)to_y;
442 if (dx_is_bigger) {
443 px = px * (1.0 - 1/(float)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 = py * (1.0 - 1/(float)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 XMoveWindow(dpy, win, (int)x, (int)y);
459 XFlush(dpy);
460 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
461 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
463 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
464 break;
466 XMoveWindow(dpy, win, to_x, to_y);
468 XSync(dpy, 0);
469 /* compress expose events */
470 eatExpose();
474 char*
475 ShrinkString(WMFont *font, char *string, int width)
477 int w, w1=0;
478 int p;
479 char *pos;
480 char *text;
481 int p1, p2, t;
483 if (wPreferences.multi_byte_text)
484 return wstrdup(string);
486 p = strlen(string);
487 w = WMWidthOfString(font, string, p);
488 text = wmalloc(strlen(string)+8);
489 strcpy(text, string);
490 if (w<=width)
491 return text;
493 pos = strchr(text, ' ');
494 if (!pos)
495 pos = strchr(text, ':');
497 if (pos) {
498 *pos = 0;
499 p = strlen(text);
500 w1 = WMWidthOfString(font, text, p);
501 if (w1 > width) {
502 w1 = 0;
503 p = 0;
504 *pos = ' ';
505 *text = 0;
506 } else {
507 *pos = 0;
508 width -= w1;
509 p++;
511 string += p;
512 p=strlen(string);
513 } else {
514 *text=0;
516 strcat(text, "...");
517 width -= WMWidthOfString(font, "...", 3);
519 pos = string;
520 p1=0;
521 p2=p;
522 t = (p2-p1)/2;
523 while (p2>p1 && p1!=t) {
524 w = WMWidthOfString(font, &string[p-t], t);
525 if (w>width) {
526 p2 = t;
527 t = p1+(p2-p1)/2;
528 } else if (w<width) {
529 p1 = t;
530 t = p1+(p2-p1)/2;
531 } else
532 p2=p1=t;
534 strcat(text, &string[p-p1]);
536 return text;
540 char*
541 FindImage(char *paths, char *file)
543 char *tmp, *path;
545 tmp = strrchr(file, ':');
546 if (tmp) {
547 *tmp = 0;
548 path = wfindfile(paths, file);
549 *tmp = ':';
551 if (!tmp || !path) {
552 path = wfindfile(paths, file);
555 return path;
559 char*
560 FlattenStringList(char **list, int count)
562 int i, j;
563 char *flat_string, *wspace;
565 j = 0;
566 for (i=0; i<count; i++) {
567 if (list[i]!=NULL && list[i][0]!=0) {
568 j += strlen(list[i]);
569 if (strpbrk(list[i], " \t"))
570 j += 2;
574 flat_string = malloc(j+count+1);
575 if (!flat_string) {
576 return NULL;
579 *flat_string = 0;
580 for (i=0; i<count; i++) {
581 if (list[i]!=NULL && list[i][0]!=0) {
582 if (i>0)
583 strcat(flat_string, " ");
584 wspace = strpbrk(list[i], " \t");
585 if (wspace)
586 strcat(flat_string, "\"");
587 strcat(flat_string, list[i]);
588 if (wspace)
589 strcat(flat_string, "\"");
593 return flat_string;
599 *----------------------------------------------------------------------
600 * ParseCommand --
601 * Divides a command line into a argv/argc pair.
602 *----------------------------------------------------------------------
604 #define PRC_ALPHA 0
605 #define PRC_BLANK 1
606 #define PRC_ESCAPE 2
607 #define PRC_DQUOTE 3
608 #define PRC_EOS 4
609 #define PRC_SQUOTE 5
611 typedef struct {
612 short nstate;
613 short output;
614 } DFA;
617 static DFA mtable[9][6] = {
618 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
619 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
620 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
621 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
622 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
623 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
624 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
625 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
626 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
629 char*
630 next_token(char *word, char **next)
632 char *ptr;
633 char *ret, *t;
634 int state, ctype;
636 t = ret = wmalloc(strlen(word)+1);
637 ptr = word;
639 state = 0;
640 *t = 0;
641 while (1) {
642 if (*ptr==0)
643 ctype = PRC_EOS;
644 else if (*ptr=='\\')
645 ctype = PRC_ESCAPE;
646 else if (*ptr=='"')
647 ctype = PRC_DQUOTE;
648 else if (*ptr=='\'')
649 ctype = PRC_SQUOTE;
650 else if (*ptr==' ' || *ptr=='\t')
651 ctype = PRC_BLANK;
652 else
653 ctype = PRC_ALPHA;
655 if (mtable[state][ctype].output) {
656 *t = *ptr; t++;
657 *t = 0;
659 state = mtable[state][ctype].nstate;
660 ptr++;
661 if (mtable[state][0].output<0) {
662 break;
666 if (*ret==0)
667 t = NULL;
668 else
669 t = wstrdup(ret);
671 free(ret);
673 if (ctype==PRC_EOS)
674 *next = NULL;
675 else
676 *next = ptr;
678 return t;
682 void
683 ParseCommand(char *command, char ***argv, int *argc)
685 WMBag *bag = WMCreateBag(4);
686 char *token, *line;
687 int count, j;
689 line = command;
690 do {
691 token = next_token(line, &line);
692 if (token) {
693 WMPutInBag(bag, token);
695 } while (token!=NULL && line!=NULL);
697 count = WMGetBagItemCount(bag);
698 *argv = wmalloc(sizeof(char*)*count);
699 for (j = 0; j < count; j++) {
700 (*argv)[j] = WMGetFromBag(bag, j);
702 *argc = count;
704 WMFreeBag(bag);
707 #if 0
708 static void
709 timeup(void *foo)
711 *(int*)foo=1;
713 #endif
714 static char*
715 getselection(WScreen *scr)
717 char *tmp;
718 extern char *W_GetTextSelection(); /* in WINGs */
720 tmp = W_GetTextSelection(scr->wmscreen, XA_PRIMARY);
721 if (!tmp)
722 tmp = W_GetTextSelection(scr->wmscreen, XA_CUT_BUFFER0);
723 return tmp;
725 #if 0
726 XEvent event;
727 int timeover=0;
728 WMHandlerID *id;
730 #ifdef DEBUG
731 puts("getting selection");
732 #endif
733 RequestSelection(dpy, scr->no_focus_win, LastTimestamp);
734 /* timeout on 1 sec. */
735 id = WMAddTimerHandler(1000, timeup, &timeover);
736 while (!timeover) {
737 WMNextEvent(dpy, &event);
738 if (event.type == SelectionNotify
739 && event.xany.window==scr->no_focus_win) {
740 WMDeleteTimerHandler(id);
741 #ifdef DEBUG
742 puts("selection ok");
743 #endif
744 return GetSelection(dpy, scr->no_focus_win);
745 } else {
746 WMHandleEvent(&event);
749 wwarning(_("selection timed-out"));
750 return NULL;
751 #endif
755 static char*
756 getuserinput(WScreen *scr, char *line, int *ptr)
758 char *ret;
759 char *title;
760 char *prompt;
761 int j, state;
762 int begin = 0;
763 char tbuffer[256], pbuffer[256];
765 title = _("Program Arguments");
766 prompt = _("Enter command arguments:");
767 ret = NULL;
769 #define _STARTING 0
770 #define _TITLE 1
771 #define _PROMPT 2
772 #define _DONE 3
774 state = _STARTING;
775 j = 0;
776 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
777 switch (state) {
778 case _STARTING:
779 if (line[*ptr]=='(') {
780 state = _TITLE;
781 begin = *ptr+1;
782 } else {
783 state = _DONE;
785 break;
787 case _TITLE:
788 if (j <= 0 && line[*ptr]==',') {
790 j = 0;
791 if (*ptr > begin) {
792 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
793 tbuffer[WMIN(*ptr-begin, 255)] = 0;
794 title = (char*)tbuffer;
796 begin = *ptr+1;
797 state = _PROMPT;
799 } else if (j <= 0 && line[*ptr]==')') {
801 if (*ptr > begin) {
802 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
803 tbuffer[WMIN(*ptr-begin, 255)] = 0;
804 title = (char*)tbuffer;
806 state = _DONE;
808 } else if (line[*ptr]=='(') {
809 j++;
810 } else if (line[*ptr]==')') {
811 j--;
814 break;
816 case _PROMPT:
817 if (line[*ptr]==')' && j==0) {
819 if (*ptr-begin > 1) {
820 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255));
821 pbuffer[WMIN(*ptr-begin, 255)] = 0;
822 prompt = (char*)pbuffer;
824 state = _DONE;
825 } else if (line[*ptr]=='(')
826 j++;
827 else if (line[*ptr]==')')
828 j--;
829 break;
832 (*ptr)--;
833 #undef _STARTING
834 #undef _TITLE
835 #undef _PROMPT
836 #undef _DONE
838 if (!wInputDialog(scr, title, prompt, &ret))
839 return NULL;
840 else
841 return ret;
845 #ifdef OFFIX_DND
846 static char*
847 get_dnd_selection(WScreen *scr)
849 XTextProperty text_ret;
850 int result;
851 char **list;
852 char *flat_string;
853 int count;
855 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
857 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
858 || text_ret.format==0 || text_ret.nitems == 0) {
859 wwarning(_("unable to get dropped data from DND drop"));
860 return NULL;
863 XTextPropertyToStringList(&text_ret, &list, &count);
865 if (!list || count<1) {
866 XFree(text_ret.value);
867 wwarning(_("error getting dropped data from DND drop"));
868 return NULL;
871 flat_string = FlattenStringList(list, count);
872 if (!flat_string) {
873 wwarning(_("out of memory while getting data from DND drop"));
876 XFreeStringList(list);
877 XFree(text_ret.value);
878 return flat_string;
880 #endif /* OFFIX_DND */
883 #define S_NORMAL 0
884 #define S_ESCAPE 1
885 #define S_OPTION 2
888 * state input new-state output
889 * NORMAL % OPTION <nil>
890 * NORMAL \ ESCAPE <nil>
891 * NORMAL etc. NORMAL <input>
892 * ESCAPE any NORMAL <input>
893 * OPTION s NORMAL <selection buffer>
894 * OPTION w NORMAL <selected window id>
895 * OPTION a NORMAL <input text>
896 * OPTION d NORMAL <OffiX DND selection object>
897 * OPTION W NORMAL <current workspace>
898 * OPTION etc. NORMAL %<input>
900 #define TMPBUFSIZE 64
901 char*
902 ExpandOptions(WScreen *scr, char *cmdline)
904 int ptr, optr, state, len, olen;
905 char *out, *nout;
906 char *selection=NULL;
907 char *user_input=NULL;
908 #if defined(OFFIX_DND) || defined(XDND)
909 char *dropped_thing=NULL;
910 #endif
911 char tmpbuf[TMPBUFSIZE];
912 int slen;
914 len = strlen(cmdline);
915 olen = len+1;
916 out = malloc(olen);
917 if (!out) {
918 wwarning(_("out of memory during expansion of \"%s\""));
919 return NULL;
921 *out = 0;
922 ptr = 0; /* input line pointer */
923 optr = 0; /* output line pointer */
924 state = S_NORMAL;
925 while (ptr < len) {
926 switch (state) {
927 case S_NORMAL:
928 switch (cmdline[ptr]) {
929 case '\\':
930 state = S_ESCAPE;
931 break;
932 case '%':
933 state = S_OPTION;
934 break;
935 default:
936 state = S_NORMAL;
937 out[optr++]=cmdline[ptr];
938 break;
940 break;
941 case S_ESCAPE:
942 switch (cmdline[ptr]) {
943 case 'n':
944 out[optr++]=10;
945 break;
947 case 'r':
948 out[optr++]=13;
949 break;
951 case 't':
952 out[optr++]=9;
953 break;
955 default:
956 out[optr++]=cmdline[ptr];
958 state = S_NORMAL;
959 break;
960 case S_OPTION:
961 state = S_NORMAL;
962 switch (cmdline[ptr]) {
963 case 'w':
964 if (scr->focused_window
965 && scr->focused_window->flags.focused) {
966 sprintf(tmpbuf, "0x%x",
967 (unsigned int)scr->focused_window->client_win);
968 slen = strlen(tmpbuf);
969 olen += slen;
970 nout = realloc(out,olen);
971 if (!nout) {
972 wwarning(_("out of memory during expansion of \"%w\""));
973 goto error;
975 out = nout;
976 strcat(out,tmpbuf);
977 optr+=slen;
978 } else {
979 out[optr++]=' ';
981 break;
983 case 'W':
984 sprintf(tmpbuf, "0x%x",
985 (unsigned int)scr->current_workspace + 1);
986 slen = strlen(tmpbuf);
987 olen += slen;
988 nout = realloc(out,olen);
989 if (!nout) {
990 wwarning(_("out of memory during expansion of \"%W\""));
991 goto error;
993 out = nout;
994 strcat(out,tmpbuf);
995 optr+=slen;
996 break;
998 case 'a':
999 ptr++;
1000 user_input = getuserinput(scr, cmdline, &ptr);
1001 if (user_input) {
1002 slen = strlen(user_input);
1003 olen += slen;
1004 nout = realloc(out,olen);
1005 if (!nout) {
1006 wwarning(_("out of memory during expansion of \"%a\""));
1007 goto error;
1009 out = nout;
1010 strcat(out,user_input);
1011 optr+=slen;
1012 } else {
1013 /* Not an error, but user has Canceled the dialog box.
1014 * This will make the command to not be performed. */
1015 goto error;
1017 break;
1019 #if defined(OFFIX_DND) || defined(XDND)
1020 case 'd':
1021 #ifdef XDND
1022 if(scr->xdestring) {
1023 dropped_thing = wstrdup(scr->xdestring);
1025 #endif
1026 if (!dropped_thing) {
1027 dropped_thing = get_dnd_selection(scr);
1029 if (!dropped_thing) {
1030 scr->flags.dnd_data_convertion_status = 1;
1031 goto error;
1033 slen = strlen(dropped_thing);
1034 olen += slen;
1035 nout = realloc(out,olen);
1036 if (!nout) {
1037 wwarning(_("out of memory during expansion of \"%d\""));
1038 goto error;
1040 out = nout;
1041 strcat(out,dropped_thing);
1042 optr+=slen;
1043 break;
1044 #endif /* OFFIX_DND */
1046 case 's':
1047 if (!selection) {
1048 selection = getselection(scr);
1050 if (!selection) {
1051 wwarning(_("selection not available"));
1052 goto error;
1054 slen = strlen(selection);
1055 olen += slen;
1056 nout = realloc(out,olen);
1057 if (!nout) {
1058 wwarning(_("out of memory during expansion of \"%s\""));
1059 goto error;
1061 out = nout;
1062 strcat(out,selection);
1063 optr+=slen;
1064 break;
1065 default:
1066 out[optr++]='%';
1067 out[optr++]=cmdline[ptr];
1069 break;
1071 out[optr]=0;
1072 ptr++;
1074 if (selection)
1075 XFree(selection);
1076 return out;
1078 error:
1079 free(out);
1080 if (selection)
1081 XFree(selection);
1082 return NULL;
1086 /* We don't care for upper/lower case in comparing the keys; so we
1087 have to define our own comparison function here */
1088 BOOL
1089 StringCompareHook(proplist_t pl1, proplist_t pl2)
1091 char *str1, *str2;
1093 str1 = PLGetString(pl1);
1094 str2 = PLGetString(pl2);
1096 if (strcasecmp(str1, str2)==0)
1097 return YES;
1098 else
1099 return NO;
1103 /* feof doesn't seem to work on pipes */
1105 IsEof(FILE * stream)
1107 static struct stat stinfo;
1109 fstat(fileno(stream), &stinfo);
1110 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1111 feof(stream));
1115 void
1116 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1118 char *name;
1120 *winstance = *wclass = NULL;
1122 if (!PLIsString(value)) {
1123 wwarning(_("bad window name value in %s state info"), where);
1124 return;
1127 name = PLGetString(value);
1128 if (!name || strlen(name)==0) {
1129 wwarning(_("bad window name value in %s state info"), where);
1130 return;
1133 UnescapeWM_CLASS(name, winstance, wclass);
1137 #if 0
1138 static char*
1139 keysymToString(KeySym keysym, unsigned int state)
1141 XKeyEvent kev;
1142 char *buf = wmalloc(20);
1143 int count;
1145 kev.display = dpy;
1146 kev.type = KeyPress;
1147 kev.send_event = False;
1148 kev.window = DefaultRootWindow(dpy);
1149 kev.root = DefaultRootWindow(dpy);
1150 kev.same_screen = True;
1151 kev.subwindow = kev.root;
1152 kev.serial = 0x12344321;
1153 kev.time = CurrentTime;
1154 kev.state = state;
1155 kev.keycode = XKeysymToKeycode(dpy, keysym);
1156 count = XLookupString(&kev, buf, 19, NULL, NULL);
1157 buf[count] = 0;
1159 return buf;
1161 #endif
1163 char*
1164 GetShortcutString(char *text)
1166 char *buffer = NULL;
1167 char *k;
1168 int modmask = 0;
1169 /* KeySym ksym;*/
1170 int control = 0;
1171 char *tmp;
1173 tmp = text = wstrdup(text);
1175 /* get modifiers */
1176 while ((k = strchr(text, '+'))!=NULL) {
1177 int mod;
1179 *k = 0;
1180 mod = wXModifierFromKey(text);
1181 if (mod<0) {
1182 return wstrdup("bug");
1185 modmask |= mod;
1187 if (strcasecmp(text, "Meta")==0) {
1188 buffer = wstrappend(buffer, "M+");
1189 } else if (strcasecmp(text, "Alt")==0) {
1190 buffer = wstrappend(buffer, "A+");
1191 } else if (strcasecmp(text, "Shift")==0) {
1192 buffer = wstrappend(buffer, "Sh+");
1193 } else if (strcasecmp(text, "Mod1")==0) {
1194 buffer = wstrappend(buffer, "M1+");
1195 } else if (strcasecmp(text, "Mod2")==0) {
1196 buffer = wstrappend(buffer, "M2+");
1197 } else if (strcasecmp(text, "Mod3")==0) {
1198 buffer = wstrappend(buffer, "M3+");
1199 } else if (strcasecmp(text, "Mod4")==0) {
1200 buffer = wstrappend(buffer, "M4+");
1201 } else if (strcasecmp(text, "Mod5")==0) {
1202 buffer = wstrappend(buffer, "M5+");
1203 } else if (strcasecmp(text, "Control")==0) {
1204 control = 1;
1205 } else {
1206 buffer = wstrappend(buffer, text);
1208 text = k+1;
1211 if (control) {
1212 buffer = wstrappend(buffer, "^");
1214 buffer = wstrappend(buffer, text);
1216 /* get key */
1217 /* ksym = XStringToKeysym(text);
1218 tmp = keysymToString(ksym, modmask);
1219 puts(tmp);
1220 buffer = wstrappend(buffer, tmp);
1222 free(tmp);
1224 return buffer;
1228 char*
1229 EscapeWM_CLASS(char *name, char *class)
1231 char *ret;
1232 char *ename = NULL, *eclass = NULL;
1233 int i, j, l;
1235 if (!name && !class)
1236 return NULL;
1238 if (name) {
1239 l = strlen(name);
1240 ename = wmalloc(l*2);
1241 j = 0;
1242 for (i=0; i<l; i++) {
1243 if (name[i]=='\\') {
1244 ename[j++] = '\\';
1245 } else if (name[i]=='.') {
1246 ename[j++] = '\\';
1248 ename[j++] = name[i];
1250 ename[j] = 0;
1252 if (class) {
1253 l = strlen(class);
1254 eclass = wmalloc(l*2);
1255 j = 0;
1256 for (i=0; i<l; i++) {
1257 if (class[i]=='\\') {
1258 eclass[j++] = '\\';
1259 } else if (class[i]=='.') {
1260 eclass[j++] = '\\';
1262 eclass[j++] = class[i];
1264 eclass[j] = 0;
1267 if (ename && eclass) {
1268 ret = wmalloc(strlen(ename)+strlen(eclass)+4);
1269 sprintf(ret, "%s.%s", ename, eclass);
1270 free(ename);
1271 free(eclass);
1272 } else if (ename) {
1273 ret = wstrdup(ename);
1274 free(ename);
1275 } else {
1276 ret = wstrdup(eclass);
1277 free(eclass);
1280 return ret;
1284 void
1285 UnescapeWM_CLASS(char *str, char **name, char **class)
1287 int i, j, k, dot;
1288 Bool esc;
1290 j = strlen(str);
1291 *name = wmalloc(j);
1292 **name = 0;
1293 *class = wmalloc(j);
1294 **class = 0;
1296 /* separate string in 2 parts */
1297 esc = False;
1298 dot = 0;
1299 for (i = 0; i < j; i++) {
1300 if (!esc) {
1301 if (str[i]=='\\') {
1302 esc = True;
1303 } else if (str[i]=='.') {
1304 dot = i;
1305 break;
1307 } else {
1308 esc = False;
1312 /* unescape strings */
1313 esc = False;
1314 k = 0;
1315 for (i = 0; i < dot; i++) {
1316 if (!esc) {
1317 if (str[i]=='\\') {
1318 esc = True;
1319 } else {
1320 (*name)[k++] = str[i];
1322 } else {
1323 (*name)[k++] = str[i];
1324 esc = False;
1327 (*name)[k] = 0;
1329 esc = False;
1330 k = 0;
1331 for (i = dot+1; i<j; i++) {
1332 if (!esc) {
1333 if (str[i]=='\\') {
1334 esc = True;
1335 } else {
1336 (*class)[k++] = str[i];
1338 } else {
1339 esc = False;
1342 (*class)[k] = 0;
1344 if (!*name) {
1345 free(*name);
1346 *name = NULL;
1348 if (!*class) {
1349 free(*class);
1350 *class = NULL;
1356 void
1357 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1359 unsigned char *buffer;
1360 int len;
1361 int i;
1362 char buf[16];
1364 if (!scr->flags.backimage_helper_launched) {
1365 return;
1368 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1369 buffer = wmalloc(len+5);
1370 sprintf(buf, "%4i", len);
1371 memcpy(buffer, buf, 4);
1372 buffer[4] = type;
1373 i = 5;
1374 if (workspace >= 0) {
1375 sprintf(buf, "%4i", workspace);
1376 memcpy(&buffer[i], buf, 4);
1377 i += 4;
1378 buffer[i] = 0;
1380 if (msg)
1381 strcpy(&buffer[i], msg);
1383 if (write(scr->helper_fd, buffer, len+4) < 0) {
1384 wsyserror(_("could not send message to background image helper"));
1386 free(buffer);
1391 typedef struct {
1392 WScreen *scr;
1393 char *command;
1394 } _tuple;
1397 static void
1398 shellCommandHandler(pid_t pid, unsigned char status, _tuple *data)
1400 if (status == 127) {
1401 char *buffer;
1403 buffer = wstrappend(_("Could not execute command: "), data->command);
1405 wMessageDialog(data->scr, _("Error"), buffer, _("OK"), NULL, NULL);
1406 free(buffer);
1407 } else if (status != 127) {
1409 printf("%s: %i\n", data->command, status);
1413 free(data->command);
1414 free(data);
1418 void
1419 ExecuteShellCommand(WScreen *scr, char *command)
1421 static char *shell = NULL;
1422 pid_t pid;
1425 * This have a problem: if the shell is tcsh (not sure about others)
1426 * and ~/.tcshrc have /bin/stty erase ^H somewhere on it, the shell
1427 * will block and the command will not be executed.
1428 if (!shell) {
1429 shell = getenv("SHELL");
1430 if (!shell)
1431 shell = "/bin/sh";
1434 shell = "/bin/sh";
1436 pid = fork();
1438 if (pid==0) {
1440 SetupEnvironment(scr);
1442 #ifdef HAVE_SETPGID
1443 setpgid(0, 0);
1444 #endif
1445 execl(shell, shell, "-c", command, NULL);
1446 wsyserror("could not execute %s -c %s", shell, command);
1447 Exit(-1);
1448 } else if (pid < 0) {
1449 wsyserror("cannot fork a new process");
1450 } else {
1451 _tuple *data = wmalloc(sizeof(_tuple));
1453 data->scr = scr;
1454 data->command = wstrdup(command);
1456 wAddDeathHandler(pid, (WDeathHandler*)shellCommandHandler, data);
1464 void dprintf(char *format, ...)
1466 va_list args;
1468 va_start(args, format);
1469 vprintf(format, args);
1470 fflush(stdout);
1471 va_end(args);
1476 void dputs(char *text)
1478 puts(text);
1479 fflush(stdout);