bug fix for balloons and some other minor things
[wmaker-crm.git] / src / misc.c
blob0c2fea81a2c50c57d4ade753f1176de801be1e10
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997, 1998 Alfredo K. Kojima
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 * USA.
21 #include "wconfig.h"
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/Xatom.h>
26 #include <sys/stat.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <pwd.h>
32 #include <math.h>
33 #include <time.h>
35 #include <WUtil.h>
36 #include <wraster.h>
39 #include "WindowMaker.h"
40 #include "GNUstep.h"
41 #include "screen.h"
42 #include "wcore.h"
43 #include "window.h"
44 #include "framewin.h"
45 #include "funcs.h"
46 #include "defaults.h"
47 #include "dialog.h"
48 #include "xutil.h"
49 #include "xmodifier.h"
51 #include "list.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 #if 0
369 #ifdef I18N_MB
370 void
371 wTextWidth(XFontSet font, char *text, int length)
373 XRectangle rect;
374 XRectangle AIXsucks;
376 XmbTextExtents(font, text, length, &AIXsucks, &rec);
378 return rect.width;
380 #else
381 void
382 wTextWidth(XFontStruct *font, char *text, int length)
384 return XTextWidth(font, text, length);
386 #endif
387 #endif
389 static void
390 eatExpose()
392 XEvent event, foo;
394 /* compress all expose events into a single one */
396 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
397 /* ignore other exposure events for this window */
398 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
399 &foo));
400 /* eat exposes for other windows */
401 eatExpose();
403 event.xexpose.count = 0;
404 XPutBackEvent(dpy, &event);
409 void
410 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
412 time_t time0 = time(NULL);
413 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
414 int dx_is_bigger=0;
416 /* animation parameters */
417 static struct {
418 int delay;
419 int steps;
420 int slowdown;
421 } apars[5] = {
422 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
423 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
424 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
425 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
426 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
430 dx = (float)(to_x-from_x);
431 dy = (float)(to_y-from_y);
432 sx = (dx == 0 ? 0 : fabs(dx)/dx);
433 sy = (dy == 0 ? 0 : fabs(dy)/dy);
435 if (fabs(dx) > fabs(dy)) {
436 dx_is_bigger = 1;
439 if (dx_is_bigger) {
440 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
441 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
442 px = apars[(int)wPreferences.icon_slide_speed].steps;
443 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
444 px = -apars[(int)wPreferences.icon_slide_speed].steps;
445 py = (sx == 0 ? 0 : px*dy/dx);
446 } else {
447 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
448 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
449 py = apars[(int)wPreferences.icon_slide_speed].steps;
450 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
451 py = -apars[(int)wPreferences.icon_slide_speed].steps;
452 px = (sy == 0 ? 0 : py*dx/dy);
455 while (x != to_x || y != to_y) {
456 x += px;
457 y += py;
458 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
459 x = (float)to_x;
460 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
461 y = (float)to_y;
463 if (dx_is_bigger) {
464 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
465 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
466 px = apars[(int)wPreferences.icon_slide_speed].steps;
467 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
468 px = -apars[(int)wPreferences.icon_slide_speed].steps;
469 py = (sx == 0 ? 0 : px*dy/dx);
470 } else {
471 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
472 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
473 py = apars[(int)wPreferences.icon_slide_speed].steps;
474 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
475 py = -apars[(int)wPreferences.icon_slide_speed].steps;
476 px = (sy == 0 ? 0 : py*dx/dy);
479 XMoveWindow(dpy, win, (int)x, (int)y);
480 XFlush(dpy);
481 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
482 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
484 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
485 break;
487 XMoveWindow(dpy, win, to_x, to_y);
489 XSync(dpy, 0);
490 /* compress expose events */
491 eatExpose();
495 char*
496 ShrinkString(WFont *font, char *string, int width)
498 #ifndef I18N_MB
499 int w, w1=0;
500 int p;
501 char *pos;
502 char *text;
503 int p1, p2, t;
504 #endif
506 #ifdef I18N_MB
507 return wstrdup(string);
508 #else
509 p = strlen(string);
510 w = wTextWidth(font->font, string, p);
511 text = wmalloc(strlen(string)+8);
512 strcpy(text, string);
513 if (w<=width)
514 return text;
516 pos = strchr(text, ' ');
517 if (!pos)
518 pos = strchr(text, ':');
520 if (pos) {
521 *pos = 0;
522 p = strlen(text);
523 w1=wTextWidth(font->font, text, p);
524 if (w1>width) {
525 w1 = 0;
526 p = 0;
527 *pos = ' ';
528 *text = 0;
529 } else {
530 *pos = 0;
531 width -= w1;
532 p++;
534 string += p;
535 p=strlen(string);
536 } else {
537 *text=0;
539 strcat(text, "...");
540 width -= wTextWidth(font->font, "...", 3);
542 pos = string;
543 p1=0;
544 p2=p;
545 t = (p2-p1)/2;
546 while (p2>p1 && p1!=t) {
547 w = wTextWidth(font->font, &string[p-t], t);
548 if (w>width) {
549 p2 = t;
550 t = p1+(p2-p1)/2;
551 } else if (w<width) {
552 p1 = t;
553 t = p1+(p2-p1)/2;
554 } else
555 p2=p1=t;
557 strcat(text, &string[p-p1]);
558 return text;
559 #endif /* I18N_MB */
563 char*
564 FindImage(char *paths, char *file)
566 char *tmp, *path;
568 tmp = strrchr(file, ':');
569 if (tmp) {
570 *tmp = 0;
571 path = wfindfile(paths, file);
572 *tmp = ':';
574 if (!tmp || !path) {
575 path = wfindfile(paths, file);
578 return path;
582 char*
583 FlattenStringList(char **list, int count)
585 int i, j;
586 char *flat_string, *wspace;
588 j = 0;
589 for (i=0; i<count; i++) {
590 if (list[i]!=NULL && list[i][0]!=0) {
591 j += strlen(list[i]);
592 if (strpbrk(list[i], " \t"))
593 j += 2;
597 flat_string = malloc(j+count+1);
598 if (!flat_string) {
599 return NULL;
602 *flat_string = 0;
603 for (i=0; i<count; i++) {
604 if (list[i]!=NULL && list[i][0]!=0) {
605 if (i>0)
606 strcat(flat_string, " ");
607 wspace = strpbrk(list[i], " \t");
608 if (wspace)
609 strcat(flat_string, "\"");
610 strcat(flat_string, list[i]);
611 if (wspace)
612 strcat(flat_string, "\"");
616 return flat_string;
622 *----------------------------------------------------------------------
623 * ParseCommand --
624 * Divides a command line into a argv/argc pair.
625 *----------------------------------------------------------------------
627 #define PRC_ALPHA 0
628 #define PRC_BLANK 1
629 #define PRC_ESCAPE 2
630 #define PRC_DQUOTE 3
631 #define PRC_EOS 4
632 #define PRC_SQUOTE 5
634 typedef struct {
635 short nstate;
636 short output;
637 } DFA;
640 static DFA mtable[9][6] = {
641 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
642 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
643 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
644 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
645 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
646 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
647 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
648 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
649 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
652 char*
653 next_token(char *word, char **next)
655 char *ptr;
656 char *ret, *t;
657 int state, ctype;
659 t = ret = wmalloc(strlen(word)+1);
660 ptr = word;
662 state = 0;
663 *t = 0;
664 while (1) {
665 if (*ptr==0)
666 ctype = PRC_EOS;
667 else if (*ptr=='\\')
668 ctype = PRC_ESCAPE;
669 else if (*ptr=='"')
670 ctype = PRC_DQUOTE;
671 else if (*ptr=='\'')
672 ctype = PRC_SQUOTE;
673 else if (*ptr==' ' || *ptr=='\t')
674 ctype = PRC_BLANK;
675 else
676 ctype = PRC_ALPHA;
678 if (mtable[state][ctype].output) {
679 *t = *ptr; t++;
680 *t = 0;
682 state = mtable[state][ctype].nstate;
683 ptr++;
684 if (mtable[state][0].output<0) {
685 break;
689 if (*ret==0)
690 t = NULL;
691 else
692 t = wstrdup(ret);
694 free(ret);
696 if (ctype==PRC_EOS)
697 *next = NULL;
698 else
699 *next = ptr;
701 return t;
705 void
706 ParseCommand(char *command, char ***argv, int *argc)
708 LinkedList *list = NULL;
709 char *token, *line;
710 int count, i;
712 line = command;
713 do {
714 token = next_token(line, &line);
715 if (token) {
716 list = list_cons(token, list);
718 } while (token!=NULL && line!=NULL);
720 count = list_length(list);
721 *argv = wmalloc(sizeof(char*)*count);
722 i = count;
723 while (list!=NULL) {
724 (*argv)[--i] = list->head;
725 list_remove_head(&list);
727 *argc = count;
730 #if 0
731 static void
732 timeup(void *foo)
734 *(int*)foo=1;
736 #endif
737 static char*
738 getselection(WScreen *scr)
740 char *tmp;
741 extern char *W_GetTextSelection(); /* in WINGs */
743 tmp = W_GetTextSelection(scr->wmscreen, XA_PRIMARY);
744 if (!tmp)
745 tmp = W_GetTextSelection(scr->wmscreen, XA_CUT_BUFFER0);
746 return tmp;
748 #if 0
749 XEvent event;
750 int timeover=0;
751 WMHandlerID *id;
753 #ifdef DEBUG
754 puts("getting selection");
755 #endif
756 RequestSelection(dpy, scr->no_focus_win, LastTimestamp);
757 /* timeout on 1 sec. */
758 id = WMAddTimerHandler(1000, timeup, &timeover);
759 while (!timeover) {
760 WMNextEvent(dpy, &event);
761 if (event.type == SelectionNotify
762 && event.xany.window==scr->no_focus_win) {
763 WMDeleteTimerHandler(id);
764 #ifdef DEBUG
765 puts("selection ok");
766 #endif
767 return GetSelection(dpy, scr->no_focus_win);
768 } else {
769 WMHandleEvent(&event);
772 wwarning(_("selection timed-out"));
773 return NULL;
774 #endif
778 static char*
779 getuserinput(WScreen *scr, char *line, int *ptr)
781 char *ret;
782 char *title;
783 char *prompt;
784 int j, state;
785 int begin = 0;
786 char tbuffer[256], pbuffer[256];
788 title = _("Program Arguments");
789 prompt = _("Enter command arguments:");
790 ret = NULL;
792 #define _STARTING 0
793 #define _TITLE 1
794 #define _PROMPT 2
795 #define _DONE 3
797 state = _STARTING;
798 j = 0;
799 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
800 switch (state) {
801 case _STARTING:
802 if (line[*ptr]=='(') {
803 state = _TITLE;
804 begin = *ptr+1;
805 } else {
806 state = _DONE;
808 break;
810 case _TITLE:
811 if (j <= 0 && line[*ptr]==',') {
813 j = 0;
814 if (*ptr > begin) {
815 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
816 tbuffer[WMIN(*ptr-begin, 255)] = 0;
817 title = (char*)tbuffer;
819 begin = *ptr+1;
820 state = _PROMPT;
822 } else if (j <= 0 && line[*ptr]==')') {
824 if (*ptr > begin) {
825 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
826 tbuffer[WMIN(*ptr-begin, 255)] = 0;
827 title = (char*)tbuffer;
829 state = _DONE;
831 } else if (line[*ptr]=='(') {
832 j++;
833 } else if (line[*ptr]==')') {
834 j--;
837 break;
839 case _PROMPT:
840 if (line[*ptr]==')' && j==0) {
842 if (*ptr-begin > 1) {
843 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255));
844 pbuffer[WMIN(*ptr-begin, 255)] = 0;
845 prompt = (char*)pbuffer;
847 state = _DONE;
848 } else if (line[*ptr]=='(')
849 j++;
850 else if (line[*ptr]==')')
851 j--;
852 break;
855 (*ptr)--;
856 #undef _STARTING
857 #undef _TITLE
858 #undef _PROMPT
859 #undef _DONE
861 if (!wInputDialog(scr, title, prompt, &ret))
862 return NULL;
863 else
864 return ret;
868 #ifdef OFFIX_DND
869 static char*
870 get_dnd_selection(WScreen *scr)
872 XTextProperty text_ret;
873 int result;
874 char **list;
875 char *flat_string;
876 int count;
878 #ifdef XDE_DND
879 if(scr->xdestring) {
880 return (wstrdup(scr->xdestring));
882 #endif
883 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
885 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
886 || text_ret.format==0 || text_ret.nitems == 0) {
887 wwarning(_("unable to get dropped data from DND drop"));
888 return NULL;
891 XTextPropertyToStringList(&text_ret, &list, &count);
893 if (!list || count<1) {
894 XFree(text_ret.value);
895 wwarning(_("error getting dropped data from DND drop"));
896 return NULL;
899 flat_string = FlattenStringList(list, count);
900 if (!flat_string) {
901 wwarning(_("out of memory while getting data from DND drop"));
904 XFreeStringList(list);
905 XFree(text_ret.value);
906 return flat_string;
908 #endif /* OFFIX_DND */
911 #define S_NORMAL 0
912 #define S_ESCAPE 1
913 #define S_OPTION 2
916 * state input new-state output
917 * NORMAL % OPTION <nil>
918 * NORMAL \ ESCAPE <nil>
919 * NORMAL etc. NORMAL <input>
920 * ESCAPE any NORMAL <input>
921 * OPTION s NORMAL <selection buffer>
922 * OPTION w NORMAL <selected window id>
923 * OPTION a NORMAL <input text>
924 * OPTION d NORMAL <OffiX DND selection object>
925 * OPTION W NORMAL <current workspace>
926 * OPTION etc. NORMAL %<input>
928 #define TMPBUFSIZE 64
929 char*
930 ExpandOptions(WScreen *scr, char *cmdline)
932 int ptr, optr, state, len, olen;
933 char *out, *nout;
934 char *selection=NULL;
935 char *user_input=NULL;
936 #ifdef OFFIX_DND
937 char *dropped_thing=NULL;
938 #endif
939 char tmpbuf[TMPBUFSIZE];
940 int slen;
942 len = strlen(cmdline);
943 olen = len+1;
944 out = malloc(olen);
945 if (!out) {
946 wwarning(_("out of memory during expansion of \"%s\""));
947 return NULL;
949 *out = 0;
950 ptr = 0; /* input line pointer */
951 optr = 0; /* output line pointer */
952 state = S_NORMAL;
953 while (ptr < len) {
954 switch (state) {
955 case S_NORMAL:
956 switch (cmdline[ptr]) {
957 case '\\':
958 state = S_ESCAPE;
959 break;
960 case '%':
961 state = S_OPTION;
962 break;
963 default:
964 state = S_NORMAL;
965 out[optr++]=cmdline[ptr];
966 break;
968 break;
969 case S_ESCAPE:
970 switch (cmdline[ptr]) {
971 case 'n':
972 out[optr++]=10;
973 break;
975 case 'r':
976 out[optr++]=13;
977 break;
979 case 't':
980 out[optr++]=9;
981 break;
983 default:
984 out[optr++]=cmdline[ptr];
986 state = S_NORMAL;
987 break;
988 case S_OPTION:
989 state = S_NORMAL;
990 switch (cmdline[ptr]) {
991 case 'w':
992 if (scr->focused_window
993 && scr->focused_window->flags.focused) {
994 sprintf(tmpbuf, "0x%x",
995 (unsigned int)scr->focused_window->client_win);
996 slen = strlen(tmpbuf);
997 olen += slen;
998 nout = realloc(out,olen);
999 if (!nout) {
1000 wwarning(_("out of memory during expansion of \"%w\""));
1001 goto error;
1003 out = nout;
1004 strcat(out,tmpbuf);
1005 optr+=slen;
1006 } else {
1007 out[optr++]=' ';
1009 break;
1011 case 'W':
1012 sprintf(tmpbuf, "0x%x",
1013 (unsigned int)scr->current_workspace + 1);
1014 slen = strlen(tmpbuf);
1015 olen += slen;
1016 nout = realloc(out,olen);
1017 if (!nout) {
1018 wwarning(_("out of memory during expansion of \"%W\""));
1019 goto error;
1021 out = nout;
1022 strcat(out,tmpbuf);
1023 optr+=slen;
1024 break;
1026 case 'a':
1027 ptr++;
1028 user_input = getuserinput(scr, cmdline, &ptr);
1029 if (user_input) {
1030 slen = strlen(user_input);
1031 olen += slen;
1032 nout = realloc(out,olen);
1033 if (!nout) {
1034 wwarning(_("out of memory during expansion of \"%a\""));
1035 goto error;
1037 out = nout;
1038 strcat(out,user_input);
1039 optr+=slen;
1040 } else {
1041 /* Not an error, but user has Canceled the dialog box.
1042 * This will make the command to not be performed. */
1043 goto error;
1045 break;
1047 #ifdef OFFIX_DND
1048 case 'd':
1049 if (!dropped_thing) {
1050 dropped_thing = get_dnd_selection(scr);
1052 if (!dropped_thing) {
1053 scr->flags.dnd_data_convertion_status = 1;
1054 goto error;
1056 slen = strlen(dropped_thing);
1057 olen += slen;
1058 nout = realloc(out,olen);
1059 if (!nout) {
1060 wwarning(_("out of memory during expansion of \"%d\""));
1061 goto error;
1063 out = nout;
1064 strcat(out,dropped_thing);
1065 optr+=slen;
1066 break;
1067 #endif /* OFFIX_DND */
1069 case 's':
1070 if (!selection) {
1071 selection = getselection(scr);
1073 if (!selection) {
1074 wwarning(_("selection not available"));
1075 goto error;
1077 slen = strlen(selection);
1078 olen += slen;
1079 nout = realloc(out,olen);
1080 if (!nout) {
1081 wwarning(_("out of memory during expansion of \"%s\""));
1082 goto error;
1084 out = nout;
1085 strcat(out,selection);
1086 optr+=slen;
1087 break;
1088 default:
1089 out[optr++]='%';
1090 out[optr++]=cmdline[ptr];
1092 break;
1094 out[optr]=0;
1095 ptr++;
1097 if (selection)
1098 XFree(selection);
1099 return out;
1101 error:
1102 free(out);
1103 if (selection)
1104 XFree(selection);
1105 return NULL;
1109 /* We don't care for upper/lower case in comparing the keys; so we
1110 have to define our own comparison function here */
1111 BOOL
1112 StringCompareHook(proplist_t pl1, proplist_t pl2)
1114 char *str1, *str2;
1116 str1 = PLGetString(pl1);
1117 str2 = PLGetString(pl2);
1119 if (strcasecmp(str1, str2)==0)
1120 return YES;
1121 else
1122 return NO;
1126 /* feof doesn't seem to work on pipes */
1128 IsEof(FILE * stream)
1130 static struct stat stinfo;
1132 fstat(fileno(stream), &stinfo);
1133 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1134 feof(stream));
1138 void
1139 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1141 char *name;
1143 *winstance = *wclass = NULL;
1145 if (!PLIsString(value)) {
1146 wwarning(_("bad window name value in %s state info"), where);
1147 return;
1150 name = PLGetString(value);
1151 if (!name || strlen(name)==0) {
1152 wwarning(_("bad window name value in %s state info"), where);
1153 return;
1156 UnescapeWM_CLASS(name, winstance, wclass);
1160 #if 0
1161 static char*
1162 keysymToString(KeySym keysym, unsigned int state)
1164 XKeyEvent kev;
1165 char *buf = wmalloc(20);
1166 int count;
1168 kev.display = dpy;
1169 kev.type = KeyPress;
1170 kev.send_event = False;
1171 kev.window = DefaultRootWindow(dpy);
1172 kev.root = DefaultRootWindow(dpy);
1173 kev.same_screen = True;
1174 kev.subwindow = kev.root;
1175 kev.serial = 0x12344321;
1176 kev.time = CurrentTime;
1177 kev.state = state;
1178 kev.keycode = XKeysymToKeycode(dpy, keysym);
1179 count = XLookupString(&kev, buf, 19, NULL, NULL);
1180 buf[count] = 0;
1182 return buf;
1184 #endif
1186 char*
1187 GetShortcutString(char *text)
1189 char *buffer = NULL;
1190 char *k;
1191 int modmask = 0;
1192 /* KeySym ksym;*/
1193 int control = 0;
1194 char *tmp;
1196 tmp = text = wstrdup(text);
1198 /* get modifiers */
1199 while ((k = strchr(text, '+'))!=NULL) {
1200 int mod;
1202 *k = 0;
1203 mod = wXModifierFromKey(text);
1204 if (mod<0) {
1205 return wstrdup("bug");
1208 modmask |= mod;
1210 if (strcasecmp(text, "Meta")==0) {
1211 buffer = wstrappend(buffer, "M+");
1212 } else if (strcasecmp(text, "Alt")==0) {
1213 buffer = wstrappend(buffer, "A+");
1214 } else if (strcasecmp(text, "Shift")==0) {
1215 buffer = wstrappend(buffer, "Sh+");
1216 } else if (strcasecmp(text, "Mod1")==0) {
1217 buffer = wstrappend(buffer, "M1+");
1218 } else if (strcasecmp(text, "Mod2")==0) {
1219 buffer = wstrappend(buffer, "M2+");
1220 } else if (strcasecmp(text, "Mod3")==0) {
1221 buffer = wstrappend(buffer, "M3+");
1222 } else if (strcasecmp(text, "Mod4")==0) {
1223 buffer = wstrappend(buffer, "M4+");
1224 } else if (strcasecmp(text, "Mod5")==0) {
1225 buffer = wstrappend(buffer, "M5+");
1226 } else if (strcasecmp(text, "Control")==0) {
1227 control = 1;
1228 } else {
1229 buffer = wstrappend(buffer, text);
1231 text = k+1;
1234 if (control) {
1235 buffer = wstrappend(buffer, "^");
1237 buffer = wstrappend(buffer, text);
1239 /* get key */
1240 /* ksym = XStringToKeysym(text);
1241 tmp = keysymToString(ksym, modmask);
1242 puts(tmp);
1243 buffer = wstrappend(buffer, tmp);
1245 free(tmp);
1247 return buffer;
1251 char*
1252 EscapeWM_CLASS(char *name, char *class)
1254 char *ret;
1255 char *ename = NULL, *eclass = NULL;
1256 int i, j, l;
1258 if (!name && !class)
1259 return NULL;
1261 if (name) {
1262 l = strlen(name);
1263 ename = wmalloc(l*2);
1264 j = 0;
1265 for (i=0; i<l; i++) {
1266 if (name[i]=='\\') {
1267 ename[j++] = '\\';
1268 } else if (name[i]=='.') {
1269 ename[j++] = '\\';
1271 ename[j++] = name[i];
1273 ename[j] = 0;
1275 if (class) {
1276 l = strlen(class);
1277 eclass = wmalloc(l*2);
1278 j = 0;
1279 for (i=0; i<l; i++) {
1280 if (class[i]=='\\') {
1281 eclass[j++] = '\\';
1282 } else if (class[i]=='.') {
1283 eclass[j++] = '\\';
1285 eclass[j++] = class[i];
1287 eclass[j] = 0;
1290 if (ename && eclass) {
1291 ret = wmalloc(strlen(ename)+strlen(eclass)+4);
1292 sprintf(ret, "%s.%s", ename, eclass);
1293 free(ename);
1294 free(eclass);
1295 } else if (ename) {
1296 ret = wstrdup(ename);
1297 free(ename);
1298 } else {
1299 ret = wstrdup(eclass);
1300 free(eclass);
1303 return ret;
1307 void
1308 UnescapeWM_CLASS(char *str, char **name, char **class)
1310 int i, j, k, dot;
1311 Bool esc;
1313 j = strlen(str);
1314 *name = wmalloc(j);
1315 **name = 0;
1316 *class = wmalloc(j);
1317 **class = 0;
1319 /* separate string in 2 parts */
1320 esc = False;
1321 dot = 0;
1322 for (i = 0; i < j; i++) {
1323 if (!esc) {
1324 if (str[i]=='\\') {
1325 esc = True;
1326 } else if (str[i]=='.') {
1327 dot = i;
1328 break;
1330 } else {
1331 esc = False;
1335 /* unescape strings */
1336 esc = False;
1337 k = 0;
1338 for (i = 0; i < dot; i++) {
1339 if (!esc) {
1340 if (str[i]=='\\') {
1341 esc = True;
1342 } else {
1343 (*name)[k++] = str[i];
1345 } else {
1346 (*name)[k++] = str[i];
1347 esc = False;
1350 (*name)[k] = 0;
1352 esc = False;
1353 k = 0;
1354 for (i = dot+1; i<j; i++) {
1355 if (!esc) {
1356 if (str[i]=='\\') {
1357 esc = True;
1358 } else {
1359 (*class)[k++] = str[i];
1361 } else {
1362 esc = False;
1365 (*class)[k] = 0;
1367 if (!*name) {
1368 free(*name);
1369 *name = NULL;
1371 if (!*class) {
1372 free(*class);
1373 *class = NULL;
1379 void
1380 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1382 unsigned char *buffer;
1383 int len;
1384 int i;
1385 char buf[16];
1387 if (!scr->flags.backimage_helper_launched) {
1388 return;
1391 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1392 buffer = wmalloc(len+5);
1393 sprintf(buf, "%4i", len);
1394 memcpy(buffer, buf, 4);
1395 buffer[4] = type;
1396 i = 5;
1397 if (workspace >= 0) {
1398 sprintf(buf, "%4i", workspace);
1399 memcpy(&buffer[i], buf, 4);
1400 i += 4;
1401 buffer[i] = 0;
1403 if (msg)
1404 strcpy(&buffer[i], msg);
1406 if (write(scr->helper_fd, buffer, len+4) < 0) {
1407 wsyserror(_("could not send message to background image helper"));
1409 free(buffer);
1413 void
1414 ExecuteShellCommand(WScreen *scr, char *command)
1416 static char *shell = NULL;
1417 pid_t pid;
1420 * This have a problem: if the shell is tcsh (not sure about others)
1421 * and ~/.tcshrc have /bin/stty erase ^H somewhere on it, the shell
1422 * will block and the command will not be executed.
1423 if (!shell) {
1424 shell = getenv("SHELL");
1425 if (!shell)
1426 shell = "/bin/sh";
1429 shell = "/bin/sh";
1431 pid = fork();
1432 if (pid==0) {
1434 SetupEnvironment(scr);
1436 #ifdef HAVE_SETPGID
1437 setpgid(0, 0);
1438 #endif
1439 execl(shell, shell, "-c", command, NULL);
1440 wsyserror("could not execute %s -c %s", shell, command);
1441 Exit(-1);
1442 } else if (pid < 0) {
1443 wsyserror("cannot fork a new process");