Update for 0.51.0
[wmaker-crm.git] / src / misc.c
blob1751891faa2ac794fa40936943246881b66842cc
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 <wraster.h>
37 #include "WindowMaker.h"
38 #include "GNUstep.h"
39 #include "screen.h"
40 #include "wcore.h"
41 #include "window.h"
42 #include "framewin.h"
43 #include "funcs.h"
44 #include "defaults.h"
45 #include "dialog.h"
46 #include "xutil.h"
47 #include "xmodifier.h"
49 #include "list.h"
51 /**** global variables *****/
53 extern char *DisplayName;
55 extern WPreferences wPreferences;
57 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 */
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 #if 0
370 #ifdef I18N_MB
371 void
372 wTextWidth(XFontSet font, char *text, int length)
374 XRectangle rect;
375 XRectangle AIXsucks;
377 XmbTextExtents(font, text, length, &AIXsucks, &rec);
379 return rect.width;
381 #else
382 void
383 wTextWidth(XFontStruct *font, char *text, int length)
385 return XTextWidth(font, text, length);
387 #endif
388 #endif
390 static void
391 eatExpose()
393 XEvent event, foo;
395 /* compress all expose events into a single one */
397 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
398 /* ignore other exposure events for this window */
399 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
400 &foo));
401 /* eat exposes for other windows */
402 eatExpose();
404 event.xexpose.count = 0;
405 XPutBackEvent(dpy, &event);
410 void
411 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
413 time_t time0 = time(NULL);
414 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
415 int dx_is_bigger=0;
417 /* animation parameters */
418 static struct {
419 int delay;
420 int steps;
421 int slowdown;
422 } apars[5] = {
423 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
424 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
425 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
426 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
427 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
431 dx = (float)(to_x-from_x);
432 dy = (float)(to_y-from_y);
433 sx = (dx == 0 ? 0 : fabs(dx)/dx);
434 sy = (dy == 0 ? 0 : fabs(dy)/dy);
436 if (fabs(dx) > fabs(dy)) {
437 dx_is_bigger = 1;
440 if (dx_is_bigger) {
441 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
442 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
443 px = apars[(int)wPreferences.icon_slide_speed].steps;
444 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
445 px = -apars[(int)wPreferences.icon_slide_speed].steps;
446 py = (sx == 0 ? 0 : px*dy/dx);
447 } else {
448 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
449 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
450 py = apars[(int)wPreferences.icon_slide_speed].steps;
451 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
452 py = -apars[(int)wPreferences.icon_slide_speed].steps;
453 px = (sy == 0 ? 0 : py*dx/dy);
456 while (x != to_x || y != to_y) {
457 x += px;
458 y += py;
459 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
460 x = (float)to_x;
461 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
462 y = (float)to_y;
464 if (dx_is_bigger) {
465 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
466 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
467 px = apars[(int)wPreferences.icon_slide_speed].steps;
468 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
469 px = -apars[(int)wPreferences.icon_slide_speed].steps;
470 py = (sx == 0 ? 0 : px*dy/dx);
471 } else {
472 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
473 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
474 py = apars[(int)wPreferences.icon_slide_speed].steps;
475 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
476 py = -apars[(int)wPreferences.icon_slide_speed].steps;
477 px = (sy == 0 ? 0 : py*dx/dy);
480 XMoveWindow(dpy, win, (int)x, (int)y);
481 XFlush(dpy);
482 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
483 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
485 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
486 break;
488 XMoveWindow(dpy, win, to_x, to_y);
490 XSync(dpy, 0);
491 /* compress expose events */
492 eatExpose();
496 char*
497 ShrinkString(WFont *font, char *string, int width)
499 #ifndef I18N_MB
500 int w, w1=0;
501 int p;
502 char *pos;
503 char *text;
504 int p1, p2, t;
505 #endif
507 #ifdef I18N_MB
508 return wstrdup(string);
509 #else
510 p = strlen(string);
511 w = wTextWidth(font->font, string, p);
512 text = wmalloc(strlen(string)+8);
513 strcpy(text, string);
514 if (w<=width)
515 return text;
517 pos = strchr(text, ' ');
518 if (!pos)
519 pos = strchr(text, ':');
521 if (pos) {
522 *pos = 0;
523 p = strlen(text);
524 w1=wTextWidth(font->font, text, p);
525 if (w1>width) {
526 w1 = 0;
527 p = 0;
528 *pos = ' ';
529 *text = 0;
530 } else {
531 *pos = 0;
532 width -= w1;
533 p++;
535 string += p;
536 p=strlen(string);
537 } else {
538 *text=0;
540 strcat(text, "...");
541 width -= wTextWidth(font->font, "...", 3);
543 pos = string;
544 p1=0;
545 p2=p;
546 t = (p2-p1)/2;
547 while (p2>p1 && p1!=t) {
548 w = wTextWidth(font->font, &string[p-t], t);
549 if (w>width) {
550 p2 = t;
551 t = p1+(p2-p1)/2;
552 } else if (w<width) {
553 p1 = t;
554 t = p1+(p2-p1)/2;
555 } else
556 p2=p1=t;
558 strcat(text, &string[p-p1]);
559 return text;
560 #endif /* I18N_MB */
564 char*
565 FindImage(char *paths, char *file)
567 char *tmp, *path;
569 tmp = strrchr(file, ':');
570 if (tmp) {
571 *tmp = 0;
572 path = wfindfile(paths, file);
573 *tmp = ':';
575 if (!tmp || !path) {
576 path = wfindfile(paths, file);
579 return path;
583 char*
584 FlattenStringList(char **list, int count)
586 int i, j;
587 char *flat_string, *wspace;
589 j = 0;
590 for (i=0; i<count; i++) {
591 if (list[i]!=NULL && list[i][0]!=0) {
592 j += strlen(list[i]);
593 if (strpbrk(list[i], " \t"))
594 j += 2;
598 flat_string = malloc(j+count+1);
599 if (!flat_string) {
600 return NULL;
603 *flat_string = 0;
604 for (i=0; i<count; i++) {
605 if (list[i]!=NULL && list[i][0]!=0) {
606 if (i>0)
607 strcat(flat_string, " ");
608 wspace = strpbrk(list[i], " \t");
609 if (wspace)
610 strcat(flat_string, "\"");
611 strcat(flat_string, list[i]);
612 if (wspace)
613 strcat(flat_string, "\"");
617 return flat_string;
623 *----------------------------------------------------------------------
624 * ParseCommand --
625 * Divides a command line into a argv/argc pair.
626 *----------------------------------------------------------------------
628 #define PRC_ALPHA 0
629 #define PRC_BLANK 1
630 #define PRC_ESCAPE 2
631 #define PRC_DQUOTE 3
632 #define PRC_EOS 4
633 #define PRC_SQUOTE 5
635 typedef struct {
636 short nstate;
637 short output;
638 } DFA;
641 static DFA mtable[9][6] = {
642 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
643 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
644 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
645 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
646 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
647 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
648 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
649 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
650 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
653 char*
654 next_token(char *word, char **next)
656 char *ptr;
657 char *ret, *t;
658 int state, ctype;
660 t = ret = wmalloc(strlen(word)+1);
661 ptr = word;
663 state = 0;
664 *t = 0;
665 while (1) {
666 if (*ptr==0)
667 ctype = PRC_EOS;
668 else if (*ptr=='\\')
669 ctype = PRC_ESCAPE;
670 else if (*ptr=='"')
671 ctype = PRC_DQUOTE;
672 else if (*ptr=='\'')
673 ctype = PRC_SQUOTE;
674 else if (*ptr==' ' || *ptr=='\t')
675 ctype = PRC_BLANK;
676 else
677 ctype = PRC_ALPHA;
679 if (mtable[state][ctype].output) {
680 *t = *ptr; t++;
681 *t = 0;
683 state = mtable[state][ctype].nstate;
684 ptr++;
685 if (mtable[state][0].output<0) {
686 break;
690 if (*ret==0)
691 t = NULL;
692 else
693 t = wstrdup(ret);
695 free(ret);
697 if (ctype==PRC_EOS)
698 *next = NULL;
699 else
700 *next = ptr;
702 return t;
706 void
707 ParseCommand(char *command, char ***argv, int *argc)
709 LinkedList *list = NULL;
710 char *token, *line;
711 int count, i;
713 line = command;
714 do {
715 token = next_token(line, &line);
716 if (token) {
717 list = list_cons(token, list);
719 } while (token!=NULL && line!=NULL);
721 count = list_length(list);
722 *argv = wmalloc(sizeof(char*)*count);
723 i = count;
724 while (list!=NULL) {
725 (*argv)[--i] = list->head;
726 list_remove_head(&list);
728 *argc = count;
731 #if 0
732 static void
733 timeup(void *foo)
735 *(int*)foo=1;
737 #endif
738 static char*
739 getselection(WScreen *scr)
741 char *tmp;
742 extern char *W_GetTextSelection(); /* in WINGs */
744 tmp = W_GetTextSelection(scr->wmscreen, XA_PRIMARY);
745 if (!tmp)
746 tmp = W_GetTextSelection(scr->wmscreen, XA_CUT_BUFFER0);
747 return tmp;
749 #if 0
750 XEvent event;
751 int timeover=0;
752 WMHandlerID *id;
754 #ifdef DEBUG
755 puts("getting selection");
756 #endif
757 RequestSelection(dpy, scr->no_focus_win, LastTimestamp);
758 /* timeout on 1 sec. */
759 id = WMAddTimerHandler(1000, timeup, &timeover);
760 while (!timeover) {
761 WMNextEvent(dpy, &event);
762 if (event.type == SelectionNotify
763 && event.xany.window==scr->no_focus_win) {
764 WMDeleteTimerHandler(id);
765 #ifdef DEBUG
766 puts("selection ok");
767 #endif
768 return GetSelection(dpy, scr->no_focus_win);
769 } else {
770 WMHandleEvent(&event);
773 wwarning(_("selection timed-out"));
774 return NULL;
775 #endif
779 static char*
780 getuserinput(WScreen *scr, char *line, int *ptr)
782 char *ret;
783 char *title;
784 char *prompt;
785 int j, state;
786 int begin;
787 char tbuffer[256], pbuffer[256];
789 title = _("Program Arguments");
790 prompt = _("Enter command arguments:");
791 ret = NULL;
793 #define _STARTING 0
794 #define _TITLE 1
795 #define _PROMPT 2
796 #define _DONE 3
798 state = _STARTING;
799 j = 0;
800 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
801 switch (state) {
802 case _STARTING:
803 if (line[*ptr]=='(') {
804 state = _TITLE;
805 begin = *ptr+1;
806 } else {
807 state = _DONE;
809 break;
811 case _TITLE:
812 if (j <= 0 && line[*ptr]==',') {
814 j = 0;
815 if (*ptr > begin) {
816 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
817 tbuffer[WMIN(*ptr-begin, 255)] = 0;
818 title = (char*)tbuffer;
820 begin = *ptr+1;
821 state = _PROMPT;
823 } else if (j <= 0 && line[*ptr]==')') {
825 if (*ptr > begin) {
826 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
827 tbuffer[WMIN(*ptr-begin, 255)] = 0;
828 title = (char*)tbuffer;
830 state = _DONE;
832 } else if (line[*ptr]=='(') {
833 j++;
834 } else if (line[*ptr]==')') {
835 j--;
838 break;
840 case _PROMPT:
841 if (line[*ptr]==')' && j==0) {
843 if (*ptr-begin > 1) {
844 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255));
845 pbuffer[WMIN(*ptr-begin, 255)] = 0;
846 prompt = (char*)pbuffer;
848 state = _DONE;
849 } else if (line[*ptr]=='(')
850 j++;
851 else if (line[*ptr]==')')
852 j--;
853 break;
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);
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 esc = False;
1349 (*name)[k] = 0;
1351 esc = False;
1352 k = 0;
1353 for (i = dot+1; i<j; i++) {
1354 if (!esc) {
1355 if (str[i]=='\\') {
1356 esc = True;
1357 } else {
1358 (*class)[k++] = str[i];
1360 } else {
1361 esc = False;
1364 (*class)[k] = 0;
1366 if (!*name) {
1367 free(*name);
1368 *name = NULL;
1370 if (!*class) {
1371 free(*class);
1372 *class = NULL;
1378 void
1379 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1381 unsigned char *buffer;
1382 int len;
1383 int i;
1384 char buf[16];
1386 if (!scr->flags.backimage_helper_launched) {
1387 return;
1390 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1391 buffer = wmalloc(len+5);
1392 sprintf(buf, "%4i", len);
1393 memcpy(buffer, buf, 4);
1394 buffer[4] = type;
1395 i = 5;
1396 if (workspace >= 0) {
1397 sprintf(buf, "%4i", workspace);
1398 memcpy(&buffer[i], buf, 4);
1399 i += 4;
1400 buffer[i] = 0;
1402 if (msg)
1403 strcpy(&buffer[i], msg);
1405 if (write(scr->helper_fd, buffer, len+4) < 0) {
1406 wsyserror(_("could not send message to background image helper"));
1408 free(buffer);
1412 void
1413 ExecuteShellCommand(WScreen *scr, char *command)
1415 static char *shell = NULL;
1416 pid_t pid;
1419 * This have a problem: if the shell is tcsh (not sure about others)
1420 * and ~/.tcshrc have /bin/stty erase ^H somewhere on it, the shell
1421 * will block and the command will not be executed.
1422 if (!shell) {
1423 shell = getenv("SHELL");
1424 if (!shell)
1425 shell = "/bin/sh";
1428 shell = "/bin/sh";
1430 pid = fork();
1431 if (pid==0) {
1433 SetupEnvironment(scr);
1435 #ifdef HAVE_SETPGID
1436 setpgid(0, 0);
1437 #endif
1438 execl(shell, shell, "-c", command, NULL);
1439 wsyserror("could not execute %s -c %s", shell, command);
1440 Exit(-1);
1441 } else if (pid < 0) {
1442 wsyserror("cannot fork a new process");