0.51.1 pre snapshot. Be careful, it may be buggy. It fixes some bugs though.
[wmaker-crm.git] / src / misc.c
blob03aef1f2437c22236bdc8cbb661cfff47c5ccfaf
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;
59 #ifdef OFFIX_DND
60 extern Atom _XA_DND_SELECTION;
61 #endif
64 #ifdef USECPP
65 static void
66 putdef(char *line, char *name, char *value)
68 if (!value) {
69 wwarning(_("could not define value for %s for cpp"), name);
70 return;
72 strcat(line, name);
73 strcat(line, value);
78 static void
79 putidef(char *line, char *name, int value)
81 char tmp[64];
82 sprintf(tmp, "%i", value);
83 strcat(line, name);
84 strcat(line, tmp);
88 static char*
89 username()
91 char *tmp;
93 tmp = getlogin();
94 if (!tmp) {
95 struct passwd *user;
97 user = getpwuid(getuid());
98 if (!user) {
99 wsyserror(_("could not get password entry for UID %i"), getuid());
100 return NULL;
102 if (!user->pw_name) {
103 return NULL;
104 } else {
105 return user->pw_name;
108 return tmp;
111 char *
112 MakeCPPArgs(char *path)
114 int i;
115 char buffer[MAXLINE], *buf, *line;
116 Visual *visual;
118 line = wmalloc(MAXLINE);
119 *line = 0;
120 i=1;
121 if ((buf=getenv("HOSTNAME"))!=NULL) {
122 if (buf[0]=='(') {
123 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"),
124 buf);
125 } else
126 putdef(line, " -DHOST=", buf);
127 } else if ((buf=getenv("HOST"))!=NULL) {
128 if (buf[0]=='(') {
129 wwarning(_("your machine is misconfigured. HOST is set to %s"),
130 buf);
131 } else
132 putdef(line, " -DHOST=", buf);
134 buf = username();
135 if (buf)
136 putdef(line, " -DUSER=", buf);
137 putidef(line, " -DUID=", getuid());
138 buf = XDisplayName(DisplayString(dpy));
139 putdef(line, " -DDISPLAY=", buf);
140 putdef(line, " -DWM_VERSION=", VERSION);
142 visual = DefaultVisual(dpy, DefaultScreen(dpy));
143 putidef(line, " -DVISUAL=", visual->class);
145 putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy)));
147 putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy)));
148 putidef(line, " -DSCR_HEIGHT=",
149 HeightOfScreen(DefaultScreenOfDisplay(dpy)));
151 #if 0
152 strcpy(buffer, path);
153 buf = strrchr(buffer, '/');
154 if (buf) *buf = 0; /* trunc filename */
155 putdef(line, " -I", buffer);
156 #endif
160 /* this should be done just once, but it works this way */
161 strcpy(buffer, DEF_CONFIG_PATHS);
162 buf = strtok(buffer, ":");
164 do {
165 char fullpath[MAXLINE];
167 if (buf[0]!='~') {
168 strcpy(fullpath, buf);
169 } else {
170 char * wgethomedir();
171 /* home is statically allocated. Don't free it! */
172 char *home = wgethomedir();
174 strcpy(fullpath, home);
175 strcat(fullpath, &(buf[1]));
178 putdef(line, " -I", fullpath);
180 } while ((buf = strtok(NULL, ":"))!=NULL);
182 #undef arg
183 #ifdef DEBUG
184 puts("CPP ARGS");
185 puts(line);
186 #endif
187 return line;
189 #endif /* USECPP */
192 WWindow*
193 NextFocusWindow(WScreen *scr)
195 WWindow *tmp, *wwin, *closest, *min;
196 Window d;
198 if (!(wwin = scr->focused_window))
199 return NULL;
200 tmp = wwin->prev;
201 closest = NULL;
202 min = wwin;
203 d = 0xffffffff;
204 while (tmp) {
205 if (wWindowCanReceiveFocus(tmp)
206 && (!WFLAGP(tmp, skip_window_list)|| tmp->flags.internal_window)) {
207 if (min->client_win > tmp->client_win)
208 min = tmp;
209 if (tmp->client_win > wwin->client_win
210 && (!closest
211 || (tmp->client_win - wwin->client_win) < d)) {
212 closest = tmp;
213 d = tmp->client_win - wwin->client_win;
216 tmp = tmp->prev;
218 if (!closest||closest==wwin)
219 return min;
220 return closest;
224 WWindow*
225 PrevFocusWindow(WScreen *scr)
227 WWindow *tmp, *wwin, *closest, *max;
228 Window d;
230 if (!(wwin = scr->focused_window))
231 return NULL;
232 tmp = wwin->prev;
233 closest = NULL;
234 max = wwin;
235 d = 0xffffffff;
236 while (tmp) {
237 if (wWindowCanReceiveFocus(tmp) &&
238 (!WFLAGP(tmp, skip_window_list) || tmp->flags.internal_window)) {
239 if (max->client_win < tmp->client_win)
240 max = tmp;
241 if (tmp->client_win < wwin->client_win
242 && (!closest
243 || (wwin->client_win - tmp->client_win) < d)) {
244 closest = tmp;
245 d = wwin->client_win - tmp->client_win;
248 tmp = tmp->prev;
250 if (!closest||closest==wwin)
251 return max;
252 return closest;
257 #if 0
259 * Is win2 below win1?
261 static Bool
262 isBelow(WWindow *win1, WWindow *win2)
264 int i;
265 WCoreWindow *tmp;
267 tmp = win1->frame->core->stacking->under;
268 while (tmp) {
269 if (tmp == win2->frame->core)
270 return True;
271 tmp = tmp->stacking->under;
274 for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
275 tmp = win1->screen_ptr->stacking_list[i];
276 while (tmp) {
277 if (tmp == win2->frame->core)
278 return True;
279 tmp = tmp->stacking->under;
282 return True;
284 #endif
289 * XFetchName Wrapper
292 Bool wFetchName(dpy, win, winname)
293 Display *dpy;
294 Window win;
295 char **winname;
297 XTextProperty text_prop;
298 char **list;
299 int num;
301 if (XGetWMName(dpy, win, &text_prop)) {
302 if (text_prop.value && text_prop.nitems > 0) {
303 if (text_prop.encoding == XA_STRING) {
304 *winname = wstrdup((char *)text_prop.value);
305 XFree(text_prop.value);
306 } else {
307 text_prop.nitems = strlen((char *)text_prop.value);
308 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
309 Success && num > 0 && *list) {
310 XFree(text_prop.value);
311 *winname = wstrdup(*list);
312 XFreeStringList(list);
313 } else {
314 *winname = wstrdup((char *)text_prop.value);
315 XFree(text_prop.value);
318 } else {
319 /* the title is set, but it was set to none */
320 *winname = wstrdup("");
322 return True;
323 } else {
324 /* the hint is probably not set */
325 *winname = NULL;
327 return False;
332 * XGetIconName Wrapper
336 Bool wGetIconName(dpy, win, iconname)
337 Display *dpy;
338 Window win;
339 char **iconname;
341 XTextProperty text_prop;
342 char **list;
343 int num;
345 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
346 && text_prop.nitems > 0) {
347 if (text_prop.encoding == XA_STRING)
348 *iconname = (char *)text_prop.value;
349 else {
350 text_prop.nitems = strlen((char *)text_prop.value);
351 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
352 Success && num > 0 && *list) {
353 XFree(text_prop.value);
354 *iconname = wstrdup(*list);
355 XFreeStringList(list);
356 } else
357 *iconname = (char *)text_prop.value;
359 return True;
361 *iconname = NULL;
362 return False;
366 #if 0
367 #ifdef I18N_MB
368 void
369 wTextWidth(XFontSet font, char *text, int length)
371 XRectangle rect;
372 XRectangle AIXsucks;
374 XmbTextExtents(font, text, length, &AIXsucks, &rec);
376 return rect.width;
378 #else
379 void
380 wTextWidth(XFontStruct *font, char *text, int length)
382 return XTextWidth(font, text, length);
384 #endif
385 #endif
387 static void
388 eatExpose()
390 XEvent event, foo;
392 /* compress all expose events into a single one */
394 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
395 /* ignore other exposure events for this window */
396 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
397 &foo));
398 /* eat exposes for other windows */
399 eatExpose();
401 event.xexpose.count = 0;
402 XPutBackEvent(dpy, &event);
407 void
408 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
410 time_t time0 = time(NULL);
411 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
412 int dx_is_bigger=0;
414 /* animation parameters */
415 static struct {
416 int delay;
417 int steps;
418 int slowdown;
419 } apars[5] = {
420 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
421 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
422 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
423 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
424 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
428 dx = (float)(to_x-from_x);
429 dy = (float)(to_y-from_y);
430 sx = (dx == 0 ? 0 : fabs(dx)/dx);
431 sy = (dy == 0 ? 0 : fabs(dy)/dy);
433 if (fabs(dx) > fabs(dy)) {
434 dx_is_bigger = 1;
437 if (dx_is_bigger) {
438 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
439 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
440 px = apars[(int)wPreferences.icon_slide_speed].steps;
441 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
442 px = -apars[(int)wPreferences.icon_slide_speed].steps;
443 py = (sx == 0 ? 0 : px*dy/dx);
444 } else {
445 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
446 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
447 py = apars[(int)wPreferences.icon_slide_speed].steps;
448 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
449 py = -apars[(int)wPreferences.icon_slide_speed].steps;
450 px = (sy == 0 ? 0 : py*dx/dy);
453 while (x != to_x || y != to_y) {
454 x += px;
455 y += py;
456 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
457 x = (float)to_x;
458 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
459 y = (float)to_y;
461 if (dx_is_bigger) {
462 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
463 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
464 px = apars[(int)wPreferences.icon_slide_speed].steps;
465 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
466 px = -apars[(int)wPreferences.icon_slide_speed].steps;
467 py = (sx == 0 ? 0 : px*dy/dx);
468 } else {
469 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
470 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
471 py = apars[(int)wPreferences.icon_slide_speed].steps;
472 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
473 py = -apars[(int)wPreferences.icon_slide_speed].steps;
474 px = (sy == 0 ? 0 : py*dx/dy);
477 XMoveWindow(dpy, win, (int)x, (int)y);
478 XFlush(dpy);
479 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
480 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
482 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
483 break;
485 XMoveWindow(dpy, win, to_x, to_y);
487 XSync(dpy, 0);
488 /* compress expose events */
489 eatExpose();
493 char*
494 ShrinkString(WFont *font, char *string, int width)
496 #ifndef I18N_MB
497 int w, w1=0;
498 int p;
499 char *pos;
500 char *text;
501 int p1, p2, t;
502 #endif
504 #ifdef I18N_MB
505 return wstrdup(string);
506 #else
507 p = strlen(string);
508 w = wTextWidth(font->font, string, p);
509 text = wmalloc(strlen(string)+8);
510 strcpy(text, string);
511 if (w<=width)
512 return text;
514 pos = strchr(text, ' ');
515 if (!pos)
516 pos = strchr(text, ':');
518 if (pos) {
519 *pos = 0;
520 p = strlen(text);
521 w1=wTextWidth(font->font, text, p);
522 if (w1>width) {
523 w1 = 0;
524 p = 0;
525 *pos = ' ';
526 *text = 0;
527 } else {
528 *pos = 0;
529 width -= w1;
530 p++;
532 string += p;
533 p=strlen(string);
534 } else {
535 *text=0;
537 strcat(text, "...");
538 width -= wTextWidth(font->font, "...", 3);
540 pos = string;
541 p1=0;
542 p2=p;
543 t = (p2-p1)/2;
544 while (p2>p1 && p1!=t) {
545 w = wTextWidth(font->font, &string[p-t], t);
546 if (w>width) {
547 p2 = t;
548 t = p1+(p2-p1)/2;
549 } else if (w<width) {
550 p1 = t;
551 t = p1+(p2-p1)/2;
552 } else
553 p2=p1=t;
555 strcat(text, &string[p-p1]);
556 return text;
557 #endif /* I18N_MB */
561 char*
562 FindImage(char *paths, char *file)
564 char *tmp, *path;
566 tmp = strrchr(file, ':');
567 if (tmp) {
568 *tmp = 0;
569 path = wfindfile(paths, file);
570 *tmp = ':';
572 if (!tmp || !path) {
573 path = wfindfile(paths, file);
576 return path;
580 char*
581 FlattenStringList(char **list, int count)
583 int i, j;
584 char *flat_string, *wspace;
586 j = 0;
587 for (i=0; i<count; i++) {
588 if (list[i]!=NULL && list[i][0]!=0) {
589 j += strlen(list[i]);
590 if (strpbrk(list[i], " \t"))
591 j += 2;
595 flat_string = malloc(j+count+1);
596 if (!flat_string) {
597 return NULL;
600 *flat_string = 0;
601 for (i=0; i<count; i++) {
602 if (list[i]!=NULL && list[i][0]!=0) {
603 if (i>0)
604 strcat(flat_string, " ");
605 wspace = strpbrk(list[i], " \t");
606 if (wspace)
607 strcat(flat_string, "\"");
608 strcat(flat_string, list[i]);
609 if (wspace)
610 strcat(flat_string, "\"");
614 return flat_string;
620 *----------------------------------------------------------------------
621 * ParseCommand --
622 * Divides a command line into a argv/argc pair.
623 *----------------------------------------------------------------------
625 #define PRC_ALPHA 0
626 #define PRC_BLANK 1
627 #define PRC_ESCAPE 2
628 #define PRC_DQUOTE 3
629 #define PRC_EOS 4
630 #define PRC_SQUOTE 5
632 typedef struct {
633 short nstate;
634 short output;
635 } DFA;
638 static DFA mtable[9][6] = {
639 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
640 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
641 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
642 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
643 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
644 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
645 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
646 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
647 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
650 char*
651 next_token(char *word, char **next)
653 char *ptr;
654 char *ret, *t;
655 int state, ctype;
657 t = ret = wmalloc(strlen(word)+1);
658 ptr = word;
660 state = 0;
661 *t = 0;
662 while (1) {
663 if (*ptr==0)
664 ctype = PRC_EOS;
665 else if (*ptr=='\\')
666 ctype = PRC_ESCAPE;
667 else if (*ptr=='"')
668 ctype = PRC_DQUOTE;
669 else if (*ptr=='\'')
670 ctype = PRC_SQUOTE;
671 else if (*ptr==' ' || *ptr=='\t')
672 ctype = PRC_BLANK;
673 else
674 ctype = PRC_ALPHA;
676 if (mtable[state][ctype].output) {
677 *t = *ptr; t++;
678 *t = 0;
680 state = mtable[state][ctype].nstate;
681 ptr++;
682 if (mtable[state][0].output<0) {
683 break;
687 if (*ret==0)
688 t = NULL;
689 else
690 t = wstrdup(ret);
692 free(ret);
694 if (ctype==PRC_EOS)
695 *next = NULL;
696 else
697 *next = ptr;
699 return t;
703 void
704 ParseCommand(char *command, char ***argv, int *argc)
706 LinkedList *list = NULL;
707 char *token, *line;
708 int count, i;
710 line = command;
711 do {
712 token = next_token(line, &line);
713 if (token) {
714 list = list_cons(token, list);
716 } while (token!=NULL && line!=NULL);
718 count = list_length(list);
719 *argv = wmalloc(sizeof(char*)*count);
720 i = count;
721 while (list!=NULL) {
722 (*argv)[--i] = list->head;
723 list_remove_head(&list);
725 *argc = count;
728 #if 0
729 static void
730 timeup(void *foo)
732 *(int*)foo=1;
734 #endif
735 static char*
736 getselection(WScreen *scr)
738 char *tmp;
739 extern char *W_GetTextSelection(); /* in WINGs */
741 tmp = W_GetTextSelection(scr->wmscreen, XA_PRIMARY);
742 if (!tmp)
743 tmp = W_GetTextSelection(scr->wmscreen, XA_CUT_BUFFER0);
744 return tmp;
746 #if 0
747 XEvent event;
748 int timeover=0;
749 WMHandlerID *id;
751 #ifdef DEBUG
752 puts("getting selection");
753 #endif
754 RequestSelection(dpy, scr->no_focus_win, LastTimestamp);
755 /* timeout on 1 sec. */
756 id = WMAddTimerHandler(1000, timeup, &timeover);
757 while (!timeover) {
758 WMNextEvent(dpy, &event);
759 if (event.type == SelectionNotify
760 && event.xany.window==scr->no_focus_win) {
761 WMDeleteTimerHandler(id);
762 #ifdef DEBUG
763 puts("selection ok");
764 #endif
765 return GetSelection(dpy, scr->no_focus_win);
766 } else {
767 WMHandleEvent(&event);
770 wwarning(_("selection timed-out"));
771 return NULL;
772 #endif
776 static char*
777 getuserinput(WScreen *scr, char *line, int *ptr)
779 char *ret;
780 char *title;
781 char *prompt;
782 int j, state;
783 int begin;
784 char tbuffer[256], pbuffer[256];
786 title = _("Program Arguments");
787 prompt = _("Enter command arguments:");
788 ret = NULL;
790 #define _STARTING 0
791 #define _TITLE 1
792 #define _PROMPT 2
793 #define _DONE 3
795 state = _STARTING;
796 j = 0;
797 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
798 switch (state) {
799 case _STARTING:
800 if (line[*ptr]=='(') {
801 state = _TITLE;
802 begin = *ptr+1;
803 } else {
804 state = _DONE;
806 break;
808 case _TITLE:
809 if (j <= 0 && line[*ptr]==',') {
811 j = 0;
812 if (*ptr > begin) {
813 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
814 tbuffer[WMIN(*ptr-begin, 255)] = 0;
815 title = (char*)tbuffer;
817 begin = *ptr+1;
818 state = _PROMPT;
820 } else if (j <= 0 && line[*ptr]==')') {
822 if (*ptr > begin) {
823 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
824 tbuffer[WMIN(*ptr-begin, 255)] = 0;
825 title = (char*)tbuffer;
827 state = _DONE;
829 } else if (line[*ptr]=='(') {
830 j++;
831 } else if (line[*ptr]==')') {
832 j--;
835 break;
837 case _PROMPT:
838 if (line[*ptr]==')' && j==0) {
840 if (*ptr-begin > 1) {
841 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255));
842 pbuffer[WMIN(*ptr-begin, 255)] = 0;
843 prompt = (char*)pbuffer;
845 state = _DONE;
846 } else if (line[*ptr]=='(')
847 j++;
848 else if (line[*ptr]==')')
849 j--;
850 break;
853 (*ptr)--;
854 #undef _STARTING
855 #undef _TITLE
856 #undef _PROMPT
857 #undef _DONE
859 if (!wInputDialog(scr, title, prompt, &ret))
860 return NULL;
861 else
862 return ret;
866 #ifdef OFFIX_DND
867 static char*
868 get_dnd_selection(WScreen *scr)
870 XTextProperty text_ret;
871 int result;
872 char **list;
873 char *flat_string;
874 int count;
876 #ifdef XDE_DND
877 if(scr->xdestring) {
878 return (wstrdup(scr->xdestring));
880 #endif
881 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
883 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
884 || text_ret.format==0 || text_ret.nitems == 0) {
885 wwarning(_("unable to get dropped data from DND drop"));
886 return NULL;
889 XTextPropertyToStringList(&text_ret, &list, &count);
891 if (!list || count<1) {
892 XFree(text_ret.value);
893 wwarning(_("error getting dropped data from DND drop"));
894 return NULL;
897 flat_string = FlattenStringList(list, count);
898 if (!flat_string) {
899 wwarning(_("out of memory while getting data from DND drop"));
902 XFreeStringList(list);
903 XFree(text_ret.value);
904 return flat_string;
906 #endif /* OFFIX_DND */
909 #define S_NORMAL 0
910 #define S_ESCAPE 1
911 #define S_OPTION 2
914 * state input new-state output
915 * NORMAL % OPTION <nil>
916 * NORMAL \ ESCAPE <nil>
917 * NORMAL etc. NORMAL <input>
918 * ESCAPE any NORMAL <input>
919 * OPTION s NORMAL <selection buffer>
920 * OPTION w NORMAL <selected window id>
921 * OPTION a NORMAL <input text>
922 * OPTION d NORMAL <OffiX DND selection object>
923 * OPTION W NORMAL <current workspace>
924 * OPTION etc. NORMAL %<input>
926 #define TMPBUFSIZE 64
927 char*
928 ExpandOptions(WScreen *scr, char *cmdline)
930 int ptr, optr, state, len, olen;
931 char *out, *nout;
932 char *selection=NULL;
933 char *user_input=NULL;
934 #ifdef OFFIX_DND
935 char *dropped_thing=NULL;
936 #endif
937 char tmpbuf[TMPBUFSIZE];
938 int slen;
940 len = strlen(cmdline);
941 olen = len+1;
942 out = malloc(olen);
943 if (!out) {
944 wwarning(_("out of memory during expansion of \"%s\""));
945 return NULL;
947 *out = 0;
948 ptr = 0; /* input line pointer */
949 optr = 0; /* output line pointer */
950 state = S_NORMAL;
951 while (ptr < len) {
952 switch (state) {
953 case S_NORMAL:
954 switch (cmdline[ptr]) {
955 case '\\':
956 state = S_ESCAPE;
957 break;
958 case '%':
959 state = S_OPTION;
960 break;
961 default:
962 state = S_NORMAL;
963 out[optr++]=cmdline[ptr];
964 break;
966 break;
967 case S_ESCAPE:
968 switch (cmdline[ptr]) {
969 case 'n':
970 out[optr++]=10;
971 break;
973 case 'r':
974 out[optr++]=13;
975 break;
977 case 't':
978 out[optr++]=9;
979 break;
981 default:
982 out[optr++]=cmdline[ptr];
984 state = S_NORMAL;
985 break;
986 case S_OPTION:
987 state = S_NORMAL;
988 switch (cmdline[ptr]) {
989 case 'w':
990 if (scr->focused_window
991 && scr->focused_window->flags.focused) {
992 sprintf(tmpbuf, "0x%x",
993 (unsigned int)scr->focused_window->client_win);
994 slen = strlen(tmpbuf);
995 olen += slen;
996 nout = realloc(out,olen);
997 if (!nout) {
998 wwarning(_("out of memory during expansion of \"%w\""));
999 goto error;
1001 out = nout;
1002 strcat(out,tmpbuf);
1003 optr+=slen;
1004 } else {
1005 out[optr++]=' ';
1007 break;
1009 case 'W':
1010 sprintf(tmpbuf, "0x%x",
1011 (unsigned int)scr->current_workspace);
1012 slen = strlen(tmpbuf);
1013 olen += slen;
1014 nout = realloc(out,olen);
1015 if (!nout) {
1016 wwarning(_("out of memory during expansion of \"%W\""));
1017 goto error;
1019 out = nout;
1020 strcat(out,tmpbuf);
1021 optr+=slen;
1022 break;
1024 case 'a':
1025 ptr++;
1026 user_input = getuserinput(scr, cmdline, &ptr);
1027 if (user_input) {
1028 slen = strlen(user_input);
1029 olen += slen;
1030 nout = realloc(out,olen);
1031 if (!nout) {
1032 wwarning(_("out of memory during expansion of \"%a\""));
1033 goto error;
1035 out = nout;
1036 strcat(out,user_input);
1037 optr+=slen;
1038 } else {
1039 /* Not an error, but user has Canceled the dialog box.
1040 * This will make the command to not be performed. */
1041 goto error;
1043 break;
1045 #ifdef OFFIX_DND
1046 case 'd':
1047 if (!dropped_thing) {
1048 dropped_thing = get_dnd_selection(scr);
1050 if (!dropped_thing) {
1051 scr->flags.dnd_data_convertion_status = 1;
1052 goto error;
1054 slen = strlen(dropped_thing);
1055 olen += slen;
1056 nout = realloc(out,olen);
1057 if (!nout) {
1058 wwarning(_("out of memory during expansion of \"%d\""));
1059 goto error;
1061 out = nout;
1062 strcat(out,dropped_thing);
1063 optr+=slen;
1064 break;
1065 #endif /* OFFIX_DND */
1067 case 's':
1068 if (!selection) {
1069 selection = getselection(scr);
1071 if (!selection) {
1072 wwarning(_("selection not available"));
1073 goto error;
1075 slen = strlen(selection);
1076 olen += slen;
1077 nout = realloc(out,olen);
1078 if (!nout) {
1079 wwarning(_("out of memory during expansion of \"%s\""));
1080 goto error;
1082 out = nout;
1083 strcat(out,selection);
1084 optr+=slen;
1085 break;
1086 default:
1087 out[optr++]='%';
1088 out[optr++]=cmdline[ptr];
1090 break;
1092 out[optr]=0;
1093 ptr++;
1095 if (selection)
1096 XFree(selection);
1097 return out;
1099 error:
1100 free(out);
1101 if (selection)
1102 XFree(selection);
1103 return NULL;
1107 /* We don't care for upper/lower case in comparing the keys; so we
1108 have to define our own comparison function here */
1109 BOOL
1110 StringCompareHook(proplist_t pl1, proplist_t pl2)
1112 char *str1, *str2;
1114 str1 = PLGetString(pl1);
1115 str2 = PLGetString(pl2);
1117 if (strcasecmp(str1, str2)==0)
1118 return YES;
1119 else
1120 return NO;
1124 /* feof doesn't seem to work on pipes */
1126 IsEof(FILE * stream)
1128 static struct stat stinfo;
1130 fstat(fileno(stream), &stinfo);
1131 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1132 feof(stream));
1136 void
1137 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1139 char *name;
1141 *winstance = *wclass = NULL;
1143 if (!PLIsString(value)) {
1144 wwarning(_("bad window name value in %s state info"), where);
1145 return;
1148 name = PLGetString(value);
1149 if (!name || strlen(name)==0) {
1150 wwarning(_("bad window name value in %s state info"), where);
1151 return;
1154 UnescapeWM_CLASS(name, winstance, wclass);
1158 #if 0
1159 static char*
1160 keysymToString(KeySym keysym, unsigned int state)
1162 XKeyEvent kev;
1163 char *buf = wmalloc(20);
1164 int count;
1166 kev.display = dpy;
1167 kev.type = KeyPress;
1168 kev.send_event = False;
1169 kev.window = DefaultRootWindow(dpy);
1170 kev.root = DefaultRootWindow(dpy);
1171 kev.same_screen = True;
1172 kev.subwindow = kev.root;
1173 kev.serial = 0x12344321;
1174 kev.time = CurrentTime;
1175 kev.state = state;
1176 kev.keycode = XKeysymToKeycode(dpy, keysym);
1177 count = XLookupString(&kev, buf, 19, NULL, NULL);
1178 buf[count] = 0;
1180 return buf;
1182 #endif
1184 char*
1185 GetShortcutString(char *text)
1187 char *buffer = NULL;
1188 char *k;
1189 int modmask = 0;
1190 /* KeySym ksym;*/
1191 int control = 0;
1192 char *tmp;
1194 tmp = text = wstrdup(text);
1196 /* get modifiers */
1197 while ((k = strchr(text, '+'))!=NULL) {
1198 int mod;
1200 *k = 0;
1201 mod = wXModifierFromKey(text);
1202 if (mod<0) {
1203 return wstrdup("bug");
1206 modmask |= mod;
1208 if (strcasecmp(text, "Meta")==0) {
1209 buffer = wstrappend(buffer, "M+");
1210 } else if (strcasecmp(text, "Alt")==0) {
1211 buffer = wstrappend(buffer, "A+");
1212 } else if (strcasecmp(text, "Shift")==0) {
1213 buffer = wstrappend(buffer, "Sh+");
1214 } else if (strcasecmp(text, "Mod1")==0) {
1215 buffer = wstrappend(buffer, "M1+");
1216 } else if (strcasecmp(text, "Mod2")==0) {
1217 buffer = wstrappend(buffer, "M2+");
1218 } else if (strcasecmp(text, "Mod3")==0) {
1219 buffer = wstrappend(buffer, "M3+");
1220 } else if (strcasecmp(text, "Mod4")==0) {
1221 buffer = wstrappend(buffer, "M4+");
1222 } else if (strcasecmp(text, "Mod5")==0) {
1223 buffer = wstrappend(buffer, "M5+");
1224 } else if (strcasecmp(text, "Control")==0) {
1225 control = 1;
1226 } else {
1227 buffer = wstrappend(buffer, text);
1229 text = k+1;
1232 if (control) {
1233 buffer = wstrappend(buffer, "^");
1235 buffer = wstrappend(buffer, text);
1237 /* get key */
1238 /* ksym = XStringToKeysym(text);
1239 tmp = keysymToString(ksym, modmask);
1240 puts(tmp);
1241 buffer = wstrappend(buffer, tmp);
1243 free(tmp);
1245 return buffer;
1249 char*
1250 EscapeWM_CLASS(char *name, char *class)
1252 char *ret;
1253 char *ename = NULL, *eclass = NULL;
1254 int i, j, l;
1256 if (!name && !class)
1257 return NULL;
1259 if (name) {
1260 l = strlen(name);
1261 ename = wmalloc(l*2);
1262 j = 0;
1263 for (i=0; i<l; i++) {
1264 if (name[i]=='\\') {
1265 ename[j++] = '\\';
1266 } else if (name[i]=='.') {
1267 ename[j++] = '\\';
1269 ename[j++] = name[i];
1271 ename[j] = 0;
1273 if (class) {
1274 l = strlen(class);
1275 eclass = wmalloc(l*2);
1276 j = 0;
1277 for (i=0; i<l; i++) {
1278 if (class[i]=='\\') {
1279 eclass[j++] = '\\';
1280 } else if (class[i]=='.') {
1281 eclass[j++] = '\\';
1283 eclass[j++] = class[i];
1285 eclass[j] = 0;
1288 if (ename && eclass) {
1289 ret = wmalloc(strlen(ename)+strlen(eclass)+4);
1290 sprintf(ret, "%s.%s", ename, eclass);
1291 free(ename);
1292 free(eclass);
1293 } else if (ename) {
1294 ret = wstrdup(ename);
1295 free(ename);
1296 } else {
1297 ret = wstrdup(eclass);
1298 free(eclass);
1301 return ret;
1305 void
1306 UnescapeWM_CLASS(char *str, char **name, char **class)
1308 int i, j, k, dot;
1309 Bool esc;
1311 j = strlen(str);
1312 *name = wmalloc(j);
1313 **name = 0;
1314 *class = wmalloc(j);
1315 **class = 0;
1317 /* separate string in 2 parts */
1318 esc = False;
1319 dot = 0;
1320 for (i = 0; i < j; i++) {
1321 if (!esc) {
1322 if (str[i]=='\\') {
1323 esc = True;
1324 } else if (str[i]=='.') {
1325 dot = i;
1326 break;
1328 } else {
1329 esc = False;
1333 /* unescape strings */
1334 esc = False;
1335 k = 0;
1336 for (i = 0; i < dot; i++) {
1337 if (!esc) {
1338 if (str[i]=='\\') {
1339 esc = True;
1340 } else {
1341 (*name)[k++] = str[i];
1343 } else {
1344 (*name)[k++] = str[i];
1345 esc = False;
1348 (*name)[k] = 0;
1350 esc = False;
1351 k = 0;
1352 for (i = dot+1; i<j; i++) {
1353 if (!esc) {
1354 if (str[i]=='\\') {
1355 esc = True;
1356 } else {
1357 (*class)[k++] = str[i];
1359 } else {
1360 esc = False;
1363 (*class)[k] = 0;
1365 if (!*name) {
1366 free(*name);
1367 *name = NULL;
1369 if (!*class) {
1370 free(*class);
1371 *class = NULL;
1377 void
1378 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1380 unsigned char *buffer;
1381 int len;
1382 int i;
1383 char buf[16];
1385 if (!scr->flags.backimage_helper_launched) {
1386 return;
1389 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1390 buffer = wmalloc(len+5);
1391 sprintf(buf, "%4i", len);
1392 memcpy(buffer, buf, 4);
1393 buffer[4] = type;
1394 i = 5;
1395 if (workspace >= 0) {
1396 sprintf(buf, "%4i", workspace);
1397 memcpy(&buffer[i], buf, 4);
1398 i += 4;
1399 buffer[i] = 0;
1401 if (msg)
1402 strcpy(&buffer[i], msg);
1404 if (write(scr->helper_fd, buffer, len+4) < 0) {
1405 wsyserror(_("could not send message to background image helper"));
1407 free(buffer);
1411 void
1412 ExecuteShellCommand(WScreen *scr, char *command)
1414 static char *shell = NULL;
1415 pid_t pid;
1418 * This have a problem: if the shell is tcsh (not sure about others)
1419 * and ~/.tcshrc have /bin/stty erase ^H somewhere on it, the shell
1420 * will block and the command will not be executed.
1421 if (!shell) {
1422 shell = getenv("SHELL");
1423 if (!shell)
1424 shell = "/bin/sh";
1427 shell = "/bin/sh";
1429 pid = fork();
1430 if (pid==0) {
1432 SetupEnvironment(scr);
1434 #ifdef HAVE_SETPGID
1435 setpgid(0, 0);
1436 #endif
1437 execl(shell, shell, "-c", command, NULL);
1438 wsyserror("could not execute %s -c %s", shell, command);
1439 Exit(-1);
1440 } else if (pid < 0) {
1441 wsyserror("cannot fork a new process");