renamed dprintf to dbprintf
[wmaker-crm.git] / src / misc.c
blobfa0a2c1941ad79fcd86773f2e310e163bc8f0c31
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 tmp = wstrdup(path);
157 buf = strrchr(tmp, '/');
158 if (buf) *buf = 0; /* trunc filename */
159 putdef(line, " -I", tmp);
160 free(tmp);
163 /* this should be done just once, but it works this way */
164 strcpy(buffer, DEF_CONFIG_PATHS);
165 buf = strtok(buffer, ":");
167 do {
168 char fullpath[MAXLINE];
170 if (buf[0]!='~') {
171 strcpy(fullpath, buf);
172 } else {
173 char * wgethomedir();
174 /* home is statically allocated. Don't free it! */
175 char *home = wgethomedir();
177 strcpy(fullpath, home);
178 strcat(fullpath, &(buf[1]));
181 putdef(line, " -I", fullpath);
183 } while ((buf = strtok(NULL, ":"))!=NULL);
185 #undef arg
186 #ifdef DEBUG
187 puts("CPP ARGS");
188 puts(line);
189 #endif
190 return line;
192 #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 && (!WFLAGP(tmp, skip_window_list)|| 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 (!WFLAGP(tmp, skip_window_list) || tmp->flags.internal_window)) {
242 if (max->client_win < tmp->client_win)
243 max = tmp;
244 if (tmp->client_win < wwin->client_win
245 && (!closest
246 || (wwin->client_win - tmp->client_win) < d)) {
247 closest = tmp;
248 d = wwin->client_win - tmp->client_win;
251 tmp = tmp->prev;
253 if (!closest||closest==wwin)
254 return max;
255 return closest;
260 #if 0
262 * Is win2 below win1?
264 static Bool
265 isBelow(WWindow *win1, WWindow *win2)
267 int i;
268 WCoreWindow *tmp;
270 tmp = win1->frame->core->stacking->under;
271 while (tmp) {
272 if (tmp == win2->frame->core)
273 return True;
274 tmp = tmp->stacking->under;
277 for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
278 tmp = win1->screen_ptr->stacking_list[i];
279 while (tmp) {
280 if (tmp == win2->frame->core)
281 return True;
282 tmp = tmp->stacking->under;
285 return True;
287 #endif
292 * XFetchName Wrapper
295 Bool wFetchName(dpy, win, winname)
296 Display *dpy;
297 Window win;
298 char **winname;
300 XTextProperty text_prop;
301 char **list;
302 int num;
304 if (XGetWMName(dpy, win, &text_prop)) {
305 if (text_prop.value && text_prop.nitems > 0) {
306 if (text_prop.encoding == XA_STRING) {
307 *winname = wstrdup((char *)text_prop.value);
308 XFree(text_prop.value);
309 } else {
310 text_prop.nitems = strlen((char *)text_prop.value);
311 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
312 Success && num > 0 && *list) {
313 XFree(text_prop.value);
314 *winname = wstrdup(*list);
315 XFreeStringList(list);
316 } else {
317 *winname = wstrdup((char *)text_prop.value);
318 XFree(text_prop.value);
321 } else {
322 /* the title is set, but it was set to none */
323 *winname = wstrdup("");
325 return True;
326 } else {
327 /* the hint is probably not set */
328 *winname = NULL;
330 return False;
335 * XGetIconName Wrapper
339 Bool wGetIconName(dpy, win, iconname)
340 Display *dpy;
341 Window win;
342 char **iconname;
344 XTextProperty text_prop;
345 char **list;
346 int num;
348 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
349 && text_prop.nitems > 0) {
350 if (text_prop.encoding == XA_STRING)
351 *iconname = (char *)text_prop.value;
352 else {
353 text_prop.nitems = strlen((char *)text_prop.value);
354 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
355 Success && num > 0 && *list) {
356 XFree(text_prop.value);
357 *iconname = wstrdup(*list);
358 XFreeStringList(list);
359 } else
360 *iconname = (char *)text_prop.value;
362 return True;
364 *iconname = NULL;
365 return False;
369 static void
370 eatExpose()
372 XEvent event, foo;
374 /* compress all expose events into a single one */
376 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
377 /* ignore other exposure events for this window */
378 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
379 &foo));
380 /* eat exposes for other windows */
381 eatExpose();
383 event.xexpose.count = 0;
384 XPutBackEvent(dpy, &event);
389 void
390 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
392 time_t time0 = time(NULL);
393 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
394 int dx_is_bigger=0;
396 /* animation parameters */
397 static struct {
398 int delay;
399 int steps;
400 int slowdown;
401 } apars[5] = {
402 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
403 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
404 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
405 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
406 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
410 dx = (float)(to_x-from_x);
411 dy = (float)(to_y-from_y);
412 sx = (dx == 0 ? 0 : fabs(dx)/dx);
413 sy = (dy == 0 ? 0 : fabs(dy)/dy);
415 if (fabs(dx) > fabs(dy)) {
416 dx_is_bigger = 1;
419 if (dx_is_bigger) {
420 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
421 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
422 px = apars[(int)wPreferences.icon_slide_speed].steps;
423 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
424 px = -apars[(int)wPreferences.icon_slide_speed].steps;
425 py = (sx == 0 ? 0 : px*dy/dx);
426 } else {
427 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
428 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
429 py = apars[(int)wPreferences.icon_slide_speed].steps;
430 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
431 py = -apars[(int)wPreferences.icon_slide_speed].steps;
432 px = (sy == 0 ? 0 : py*dx/dy);
435 while (x != to_x || y != to_y) {
436 x += px;
437 y += py;
438 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
439 x = (float)to_x;
440 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
441 y = (float)to_y;
443 if (dx_is_bigger) {
444 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
445 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
446 px = apars[(int)wPreferences.icon_slide_speed].steps;
447 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
448 px = -apars[(int)wPreferences.icon_slide_speed].steps;
449 py = (sx == 0 ? 0 : px*dy/dx);
450 } else {
451 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
452 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
453 py = apars[(int)wPreferences.icon_slide_speed].steps;
454 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
455 py = -apars[(int)wPreferences.icon_slide_speed].steps;
456 px = (sy == 0 ? 0 : py*dx/dy);
459 XMoveWindow(dpy, win, (int)x, (int)y);
460 XFlush(dpy);
461 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
462 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
464 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
465 break;
467 XMoveWindow(dpy, win, to_x, to_y);
469 XSync(dpy, 0);
470 /* compress expose events */
471 eatExpose();
475 char*
476 ShrinkString(WMFont *font, char *string, int width)
478 int w, w1=0;
479 int p;
480 char *pos;
481 char *text;
482 int p1, p2, t;
484 if (wPreferences.multi_byte_text)
485 return wstrdup(string);
487 p = strlen(string);
488 w = WMWidthOfString(font, string, p);
489 text = wmalloc(strlen(string)+8);
490 strcpy(text, string);
491 if (w<=width)
492 return text;
494 pos = strchr(text, ' ');
495 if (!pos)
496 pos = strchr(text, ':');
498 if (pos) {
499 *pos = 0;
500 p = strlen(text);
501 w1 = WMWidthOfString(font, text, p);
502 if (w1 > width) {
503 w1 = 0;
504 p = 0;
505 *pos = ' ';
506 *text = 0;
507 } else {
508 *pos = 0;
509 width -= w1;
510 p++;
512 string += p;
513 p=strlen(string);
514 } else {
515 *text=0;
517 strcat(text, "...");
518 width -= WMWidthOfString(font, "...", 3);
520 pos = string;
521 p1=0;
522 p2=p;
523 t = (p2-p1)/2;
524 while (p2>p1 && p1!=t) {
525 w = WMWidthOfString(font, &string[p-t], t);
526 if (w>width) {
527 p2 = t;
528 t = p1+(p2-p1)/2;
529 } else if (w<width) {
530 p1 = t;
531 t = p1+(p2-p1)/2;
532 } else
533 p2=p1=t;
535 strcat(text, &string[p-p1]);
537 return text;
541 char*
542 FindImage(char *paths, char *file)
544 char *tmp, *path;
546 tmp = strrchr(file, ':');
547 if (tmp) {
548 *tmp = 0;
549 path = wfindfile(paths, file);
550 *tmp = ':';
552 if (!tmp || !path) {
553 path = wfindfile(paths, file);
556 return path;
560 char*
561 FlattenStringList(char **list, int count)
563 int i, j;
564 char *flat_string, *wspace;
566 j = 0;
567 for (i=0; i<count; i++) {
568 if (list[i]!=NULL && list[i][0]!=0) {
569 j += strlen(list[i]);
570 if (strpbrk(list[i], " \t"))
571 j += 2;
575 flat_string = malloc(j+count+1);
576 if (!flat_string) {
577 return NULL;
580 *flat_string = 0;
581 for (i=0; i<count; i++) {
582 if (list[i]!=NULL && list[i][0]!=0) {
583 if (i>0)
584 strcat(flat_string, " ");
585 wspace = strpbrk(list[i], " \t");
586 if (wspace)
587 strcat(flat_string, "\"");
588 strcat(flat_string, list[i]);
589 if (wspace)
590 strcat(flat_string, "\"");
594 return flat_string;
600 *----------------------------------------------------------------------
601 * ParseCommand --
602 * Divides a command line into a argv/argc pair.
603 *----------------------------------------------------------------------
605 #define PRC_ALPHA 0
606 #define PRC_BLANK 1
607 #define PRC_ESCAPE 2
608 #define PRC_DQUOTE 3
609 #define PRC_EOS 4
610 #define PRC_SQUOTE 5
612 typedef struct {
613 short nstate;
614 short output;
615 } DFA;
618 static DFA mtable[9][6] = {
619 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
620 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
621 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
622 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
623 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
624 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
625 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
626 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
627 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
630 char*
631 next_token(char *word, char **next)
633 char *ptr;
634 char *ret, *t;
635 int state, ctype;
637 t = ret = wmalloc(strlen(word)+1);
638 ptr = word;
640 state = 0;
641 *t = 0;
642 while (1) {
643 if (*ptr==0)
644 ctype = PRC_EOS;
645 else if (*ptr=='\\')
646 ctype = PRC_ESCAPE;
647 else if (*ptr=='"')
648 ctype = PRC_DQUOTE;
649 else if (*ptr=='\'')
650 ctype = PRC_SQUOTE;
651 else if (*ptr==' ' || *ptr=='\t')
652 ctype = PRC_BLANK;
653 else
654 ctype = PRC_ALPHA;
656 if (mtable[state][ctype].output) {
657 *t = *ptr; t++;
658 *t = 0;
660 state = mtable[state][ctype].nstate;
661 ptr++;
662 if (mtable[state][0].output<0) {
663 break;
667 if (*ret==0)
668 t = NULL;
669 else
670 t = wstrdup(ret);
672 free(ret);
674 if (ctype==PRC_EOS)
675 *next = NULL;
676 else
677 *next = ptr;
679 return t;
683 void
684 ParseCommand(char *command, char ***argv, int *argc)
686 WMBag *bag = WMCreateBag(4);
687 char *token, *line;
688 int count, j;
690 line = command;
691 do {
692 token = next_token(line, &line);
693 if (token) {
694 WMPutInBag(bag, token);
696 } while (token!=NULL && line!=NULL);
698 count = WMGetBagItemCount(bag);
699 *argv = wmalloc(sizeof(char*)*count);
700 for (j = 0; j < count; j++) {
701 (*argv)[j] = WMGetFromBag(bag, j);
703 *argc = count;
705 WMFreeBag(bag);
708 #if 0
709 static void
710 timeup(void *foo)
712 *(int*)foo=1;
714 #endif
715 static char*
716 getselection(WScreen *scr)
718 char *tmp;
719 extern char *W_GetTextSelection(); /* in WINGs */
721 tmp = W_GetTextSelection(scr->wmscreen, XA_PRIMARY);
722 if (!tmp)
723 tmp = W_GetTextSelection(scr->wmscreen, XA_CUT_BUFFER0);
724 return tmp;
726 #if 0
727 XEvent event;
728 int timeover=0;
729 WMHandlerID *id;
731 #ifdef DEBUG
732 puts("getting selection");
733 #endif
734 RequestSelection(dpy, scr->no_focus_win, LastTimestamp);
735 /* timeout on 1 sec. */
736 id = WMAddTimerHandler(1000, timeup, &timeover);
737 while (!timeover) {
738 WMNextEvent(dpy, &event);
739 if (event.type == SelectionNotify
740 && event.xany.window==scr->no_focus_win) {
741 WMDeleteTimerHandler(id);
742 #ifdef DEBUG
743 puts("selection ok");
744 #endif
745 return GetSelection(dpy, scr->no_focus_win);
746 } else {
747 WMHandleEvent(&event);
750 wwarning(_("selection timed-out"));
751 return NULL;
752 #endif
756 static char*
757 getuserinput(WScreen *scr, char *line, int *ptr)
759 char *ret;
760 char *title;
761 char *prompt;
762 int j, state;
763 int begin = 0;
764 char tbuffer[256], pbuffer[256];
766 title = _("Program Arguments");
767 prompt = _("Enter command arguments:");
768 ret = NULL;
770 #define _STARTING 0
771 #define _TITLE 1
772 #define _PROMPT 2
773 #define _DONE 3
775 state = _STARTING;
776 j = 0;
777 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
778 switch (state) {
779 case _STARTING:
780 if (line[*ptr]=='(') {
781 state = _TITLE;
782 begin = *ptr+1;
783 } else {
784 state = _DONE;
786 break;
788 case _TITLE:
789 if (j <= 0 && line[*ptr]==',') {
791 j = 0;
792 if (*ptr > begin) {
793 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
794 tbuffer[WMIN(*ptr-begin, 255)] = 0;
795 title = (char*)tbuffer;
797 begin = *ptr+1;
798 state = _PROMPT;
800 } else if (j <= 0 && line[*ptr]==')') {
802 if (*ptr > begin) {
803 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
804 tbuffer[WMIN(*ptr-begin, 255)] = 0;
805 title = (char*)tbuffer;
807 state = _DONE;
809 } else if (line[*ptr]=='(') {
810 j++;
811 } else if (line[*ptr]==')') {
812 j--;
815 break;
817 case _PROMPT:
818 if (line[*ptr]==')' && j==0) {
820 if (*ptr-begin > 1) {
821 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255));
822 pbuffer[WMIN(*ptr-begin, 255)] = 0;
823 prompt = (char*)pbuffer;
825 state = _DONE;
826 } else if (line[*ptr]=='(')
827 j++;
828 else if (line[*ptr]==')')
829 j--;
830 break;
833 (*ptr)--;
834 #undef _STARTING
835 #undef _TITLE
836 #undef _PROMPT
837 #undef _DONE
839 if (!wInputDialog(scr, title, prompt, &ret))
840 return NULL;
841 else
842 return ret;
846 #ifdef OFFIX_DND
847 static char*
848 get_dnd_selection(WScreen *scr)
850 XTextProperty text_ret;
851 int result;
852 char **list;
853 char *flat_string;
854 int count;
856 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
858 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
859 || text_ret.format==0 || text_ret.nitems == 0) {
860 wwarning(_("unable to get dropped data from DND drop"));
861 return NULL;
864 XTextPropertyToStringList(&text_ret, &list, &count);
866 if (!list || count<1) {
867 XFree(text_ret.value);
868 wwarning(_("error getting dropped data from DND drop"));
869 return NULL;
872 flat_string = FlattenStringList(list, count);
873 if (!flat_string) {
874 wwarning(_("out of memory while getting data from DND drop"));
877 XFreeStringList(list);
878 XFree(text_ret.value);
879 return flat_string;
881 #endif /* OFFIX_DND */
884 #define S_NORMAL 0
885 #define S_ESCAPE 1
886 #define S_OPTION 2
889 * state input new-state output
890 * NORMAL % OPTION <nil>
891 * NORMAL \ ESCAPE <nil>
892 * NORMAL etc. NORMAL <input>
893 * ESCAPE any NORMAL <input>
894 * OPTION s NORMAL <selection buffer>
895 * OPTION w NORMAL <selected window id>
896 * OPTION a NORMAL <input text>
897 * OPTION d NORMAL <OffiX DND selection object>
898 * OPTION W NORMAL <current workspace>
899 * OPTION etc. NORMAL %<input>
901 #define TMPBUFSIZE 64
902 char*
903 ExpandOptions(WScreen *scr, char *cmdline)
905 int ptr, optr, state, len, olen;
906 char *out, *nout;
907 char *selection=NULL;
908 char *user_input=NULL;
909 #if defined(OFFIX_DND) || defined(XDND)
910 char *dropped_thing=NULL;
911 #endif
912 char tmpbuf[TMPBUFSIZE];
913 int slen;
915 len = strlen(cmdline);
916 olen = len+1;
917 out = malloc(olen);
918 if (!out) {
919 wwarning(_("out of memory during expansion of \"%s\""));
920 return NULL;
922 *out = 0;
923 ptr = 0; /* input line pointer */
924 optr = 0; /* output line pointer */
925 state = S_NORMAL;
926 while (ptr < len) {
927 switch (state) {
928 case S_NORMAL:
929 switch (cmdline[ptr]) {
930 case '\\':
931 state = S_ESCAPE;
932 break;
933 case '%':
934 state = S_OPTION;
935 break;
936 default:
937 state = S_NORMAL;
938 out[optr++]=cmdline[ptr];
939 break;
941 break;
942 case S_ESCAPE:
943 switch (cmdline[ptr]) {
944 case 'n':
945 out[optr++]=10;
946 break;
948 case 'r':
949 out[optr++]=13;
950 break;
952 case 't':
953 out[optr++]=9;
954 break;
956 default:
957 out[optr++]=cmdline[ptr];
959 state = S_NORMAL;
960 break;
961 case S_OPTION:
962 state = S_NORMAL;
963 switch (cmdline[ptr]) {
964 case 'w':
965 if (scr->focused_window
966 && scr->focused_window->flags.focused) {
967 sprintf(tmpbuf, "0x%x",
968 (unsigned int)scr->focused_window->client_win);
969 slen = strlen(tmpbuf);
970 olen += slen;
971 nout = realloc(out,olen);
972 if (!nout) {
973 wwarning(_("out of memory during expansion of \"%w\""));
974 goto error;
976 out = nout;
977 strcat(out,tmpbuf);
978 optr+=slen;
979 } else {
980 out[optr++]=' ';
982 break;
984 case 'W':
985 sprintf(tmpbuf, "0x%x",
986 (unsigned int)scr->current_workspace + 1);
987 slen = strlen(tmpbuf);
988 olen += slen;
989 nout = realloc(out,olen);
990 if (!nout) {
991 wwarning(_("out of memory during expansion of \"%W\""));
992 goto error;
994 out = nout;
995 strcat(out,tmpbuf);
996 optr+=slen;
997 break;
999 case 'a':
1000 ptr++;
1001 user_input = getuserinput(scr, cmdline, &ptr);
1002 if (user_input) {
1003 slen = strlen(user_input);
1004 olen += slen;
1005 nout = realloc(out,olen);
1006 if (!nout) {
1007 wwarning(_("out of memory during expansion of \"%a\""));
1008 goto error;
1010 out = nout;
1011 strcat(out,user_input);
1012 optr+=slen;
1013 } else {
1014 /* Not an error, but user has Canceled the dialog box.
1015 * This will make the command to not be performed. */
1016 goto error;
1018 break;
1020 #if defined(OFFIX_DND) || defined(XDND)
1021 case 'd':
1022 #ifdef XDND
1023 if(scr->xdestring) {
1024 dropped_thing = wstrdup(scr->xdestring);
1026 #endif
1027 if (!dropped_thing) {
1028 dropped_thing = get_dnd_selection(scr);
1030 if (!dropped_thing) {
1031 scr->flags.dnd_data_convertion_status = 1;
1032 goto error;
1034 slen = strlen(dropped_thing);
1035 olen += slen;
1036 nout = realloc(out,olen);
1037 if (!nout) {
1038 wwarning(_("out of memory during expansion of \"%d\""));
1039 goto error;
1041 out = nout;
1042 strcat(out,dropped_thing);
1043 optr+=slen;
1044 break;
1045 #endif /* OFFIX_DND */
1047 case 's':
1048 if (!selection) {
1049 selection = getselection(scr);
1051 if (!selection) {
1052 wwarning(_("selection not available"));
1053 goto error;
1055 slen = strlen(selection);
1056 olen += slen;
1057 nout = realloc(out,olen);
1058 if (!nout) {
1059 wwarning(_("out of memory during expansion of \"%s\""));
1060 goto error;
1062 out = nout;
1063 strcat(out,selection);
1064 optr+=slen;
1065 break;
1066 default:
1067 out[optr++]='%';
1068 out[optr++]=cmdline[ptr];
1070 break;
1072 out[optr]=0;
1073 ptr++;
1075 if (selection)
1076 XFree(selection);
1077 return out;
1079 error:
1080 free(out);
1081 if (selection)
1082 XFree(selection);
1083 return NULL;
1087 /* We don't care for upper/lower case in comparing the keys; so we
1088 have to define our own comparison function here */
1089 BOOL
1090 StringCompareHook(proplist_t pl1, proplist_t pl2)
1092 char *str1, *str2;
1094 str1 = PLGetString(pl1);
1095 str2 = PLGetString(pl2);
1097 if (strcasecmp(str1, str2)==0)
1098 return YES;
1099 else
1100 return NO;
1104 /* feof doesn't seem to work on pipes */
1106 IsEof(FILE * stream)
1108 static struct stat stinfo;
1110 fstat(fileno(stream), &stinfo);
1111 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1112 feof(stream));
1116 void
1117 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1119 char *name;
1121 *winstance = *wclass = NULL;
1123 if (!PLIsString(value)) {
1124 wwarning(_("bad window name value in %s state info"), where);
1125 return;
1128 name = PLGetString(value);
1129 if (!name || strlen(name)==0) {
1130 wwarning(_("bad window name value in %s state info"), where);
1131 return;
1134 UnescapeWM_CLASS(name, winstance, wclass);
1138 #if 0
1139 static char*
1140 keysymToString(KeySym keysym, unsigned int state)
1142 XKeyEvent kev;
1143 char *buf = wmalloc(20);
1144 int count;
1146 kev.display = dpy;
1147 kev.type = KeyPress;
1148 kev.send_event = False;
1149 kev.window = DefaultRootWindow(dpy);
1150 kev.root = DefaultRootWindow(dpy);
1151 kev.same_screen = True;
1152 kev.subwindow = kev.root;
1153 kev.serial = 0x12344321;
1154 kev.time = CurrentTime;
1155 kev.state = state;
1156 kev.keycode = XKeysymToKeycode(dpy, keysym);
1157 count = XLookupString(&kev, buf, 19, NULL, NULL);
1158 buf[count] = 0;
1160 return buf;
1162 #endif
1164 char*
1165 GetShortcutString(char *text)
1167 char *buffer = NULL;
1168 char *k;
1169 int modmask = 0;
1170 /* KeySym ksym;*/
1171 int control = 0;
1172 char *tmp;
1174 tmp = text = wstrdup(text);
1176 /* get modifiers */
1177 while ((k = strchr(text, '+'))!=NULL) {
1178 int mod;
1180 *k = 0;
1181 mod = wXModifierFromKey(text);
1182 if (mod<0) {
1183 return wstrdup("bug");
1186 modmask |= mod;
1188 if (strcasecmp(text, "Meta")==0) {
1189 buffer = wstrappend(buffer, "M+");
1190 } else if (strcasecmp(text, "Alt")==0) {
1191 buffer = wstrappend(buffer, "A+");
1192 } else if (strcasecmp(text, "Shift")==0) {
1193 buffer = wstrappend(buffer, "Sh+");
1194 } else if (strcasecmp(text, "Mod1")==0) {
1195 buffer = wstrappend(buffer, "M1+");
1196 } else if (strcasecmp(text, "Mod2")==0) {
1197 buffer = wstrappend(buffer, "M2+");
1198 } else if (strcasecmp(text, "Mod3")==0) {
1199 buffer = wstrappend(buffer, "M3+");
1200 } else if (strcasecmp(text, "Mod4")==0) {
1201 buffer = wstrappend(buffer, "M4+");
1202 } else if (strcasecmp(text, "Mod5")==0) {
1203 buffer = wstrappend(buffer, "M5+");
1204 } else if (strcasecmp(text, "Control")==0) {
1205 control = 1;
1206 } else {
1207 buffer = wstrappend(buffer, text);
1209 text = k+1;
1212 if (control) {
1213 buffer = wstrappend(buffer, "^");
1215 buffer = wstrappend(buffer, text);
1217 /* get key */
1218 /* ksym = XStringToKeysym(text);
1219 tmp = keysymToString(ksym, modmask);
1220 puts(tmp);
1221 buffer = wstrappend(buffer, tmp);
1223 free(tmp);
1225 return buffer;
1229 char*
1230 EscapeWM_CLASS(char *name, char *class)
1232 char *ret;
1233 char *ename = NULL, *eclass = NULL;
1234 int i, j, l;
1236 if (!name && !class)
1237 return NULL;
1239 if (name) {
1240 l = strlen(name);
1241 ename = wmalloc(l*2);
1242 j = 0;
1243 for (i=0; i<l; i++) {
1244 if (name[i]=='\\') {
1245 ename[j++] = '\\';
1246 } else if (name[i]=='.') {
1247 ename[j++] = '\\';
1249 ename[j++] = name[i];
1251 ename[j] = 0;
1253 if (class) {
1254 l = strlen(class);
1255 eclass = wmalloc(l*2);
1256 j = 0;
1257 for (i=0; i<l; i++) {
1258 if (class[i]=='\\') {
1259 eclass[j++] = '\\';
1260 } else if (class[i]=='.') {
1261 eclass[j++] = '\\';
1263 eclass[j++] = class[i];
1265 eclass[j] = 0;
1268 if (ename && eclass) {
1269 ret = wmalloc(strlen(ename)+strlen(eclass)+4);
1270 sprintf(ret, "%s.%s", ename, eclass);
1271 free(ename);
1272 free(eclass);
1273 } else if (ename) {
1274 ret = wstrdup(ename);
1275 free(ename);
1276 } else {
1277 ret = wstrdup(eclass);
1278 free(eclass);
1281 return ret;
1285 void
1286 UnescapeWM_CLASS(char *str, char **name, char **class)
1288 int i, j, k, dot;
1289 Bool esc;
1291 j = strlen(str);
1292 *name = wmalloc(j);
1293 **name = 0;
1294 *class = wmalloc(j);
1295 **class = 0;
1297 /* separate string in 2 parts */
1298 esc = False;
1299 dot = 0;
1300 for (i = 0; i < j; i++) {
1301 if (!esc) {
1302 if (str[i]=='\\') {
1303 esc = True;
1304 } else if (str[i]=='.') {
1305 dot = i;
1306 break;
1308 } else {
1309 esc = False;
1313 /* unescape strings */
1314 esc = False;
1315 k = 0;
1316 for (i = 0; i < dot; i++) {
1317 if (!esc) {
1318 if (str[i]=='\\') {
1319 esc = True;
1320 } else {
1321 (*name)[k++] = str[i];
1323 } else {
1324 (*name)[k++] = str[i];
1325 esc = False;
1328 (*name)[k] = 0;
1330 esc = False;
1331 k = 0;
1332 for (i = dot+1; i<j; i++) {
1333 if (!esc) {
1334 if (str[i]=='\\') {
1335 esc = True;
1336 } else {
1337 (*class)[k++] = str[i];
1339 } else {
1340 esc = False;
1343 (*class)[k] = 0;
1345 if (!*name) {
1346 free(*name);
1347 *name = NULL;
1349 if (!*class) {
1350 free(*class);
1351 *class = NULL;
1357 void
1358 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1360 unsigned char *buffer;
1361 int len;
1362 int i;
1363 char buf[16];
1365 if (!scr->flags.backimage_helper_launched) {
1366 return;
1369 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1370 buffer = wmalloc(len+5);
1371 sprintf(buf, "%4i", len);
1372 memcpy(buffer, buf, 4);
1373 buffer[4] = type;
1374 i = 5;
1375 if (workspace >= 0) {
1376 sprintf(buf, "%4i", workspace);
1377 memcpy(&buffer[i], buf, 4);
1378 i += 4;
1379 buffer[i] = 0;
1381 if (msg)
1382 strcpy(&buffer[i], msg);
1384 if (write(scr->helper_fd, buffer, len+4) < 0) {
1385 wsyserror(_("could not send message to background image helper"));
1387 free(buffer);
1392 typedef struct {
1393 WScreen *scr;
1394 char *command;
1395 } _tuple;
1398 static void
1399 shellCommandHandler(pid_t pid, unsigned char status, _tuple *data)
1401 if (status == 127) {
1402 char *buffer;
1404 buffer = wstrappend(_("Could not execute command: "), data->command);
1406 wMessageDialog(data->scr, _("Error"), buffer, _("OK"), NULL, NULL);
1407 free(buffer);
1408 } else if (status != 127) {
1410 printf("%s: %i\n", data->command, status);
1414 free(data->command);
1415 free(data);
1419 void
1420 ExecuteShellCommand(WScreen *scr, char *command)
1422 static char *shell = NULL;
1423 pid_t pid;
1426 * This have a problem: if the shell is tcsh (not sure about others)
1427 * and ~/.tcshrc have /bin/stty erase ^H somewhere on it, the shell
1428 * will block and the command will not be executed.
1429 if (!shell) {
1430 shell = getenv("SHELL");
1431 if (!shell)
1432 shell = "/bin/sh";
1435 shell = "/bin/sh";
1437 pid = fork();
1439 if (pid==0) {
1441 SetupEnvironment(scr);
1443 #ifdef HAVE_SETPGID
1444 setpgid(0, 0);
1445 #endif
1446 execl(shell, shell, "-c", command, NULL);
1447 wsyserror("could not execute %s -c %s", shell, command);
1448 Exit(-1);
1449 } else if (pid < 0) {
1450 wsyserror("cannot fork a new process");
1451 } else {
1452 _tuple *data = wmalloc(sizeof(_tuple));
1454 data->scr = scr;
1455 data->command = wstrdup(command);
1457 wAddDeathHandler(pid, (WDeathHandler*)shellCommandHandler, data);
1465 void dbprintf(char *format, ...)
1467 va_list args;
1469 va_start(args, format);
1470 vprintf(format, args);
1471 fflush(stdout);
1472 va_end(args);
1477 void dbputs(char *text)
1479 puts(text);
1480 fflush(stdout);