added nana stuff
[wmaker-crm.git] / src / misc.c
blobb90dcdd9a9bee182302587dafe7cc326a83c3c78
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 if (path) {
157 tmp = wstrdup(path);
158 buf = strchr(tmp+1, ' ');
159 if (buf) {
160 *buf = 0;
162 buf = strrchr(tmp, '/');
163 if (buf) {
164 *buf = 0; /* trunc filename */
165 putdef(line, " -I", tmp);
167 free(tmp);
171 /* this should be done just once, but it works this way */
172 strcpy(buffer, DEF_CONFIG_PATHS);
173 buf = strtok(buffer, ":");
175 do {
176 char fullpath[MAXLINE];
178 if (buf[0]!='~') {
179 strcpy(fullpath, buf);
180 } else {
181 char * wgethomedir();
182 /* home is statically allocated. Don't free it! */
183 char *home = wgethomedir();
185 strcpy(fullpath, home);
186 strcat(fullpath, &(buf[1]));
189 putdef(line, " -I", fullpath);
191 } while ((buf = strtok(NULL, ":"))!=NULL);
193 #undef arg
194 #ifdef DEBUG
195 puts("CPP ARGS");
196 puts(line);
197 #endif
198 return line;
200 #endif /* USECPP */
203 WWindow*
204 NextFocusWindow(WScreen *scr)
206 WWindow *tmp, *wwin, *closest, *min;
207 Window d;
209 if (!(wwin = scr->focused_window))
210 return NULL;
211 tmp = wwin->prev;
212 closest = NULL;
213 min = wwin;
214 d = 0xffffffff;
215 while (tmp) {
216 if (wWindowCanReceiveFocus(tmp)
217 && (!WFLAGP(tmp, skip_window_list)|| tmp->flags.internal_window)) {
218 if (min->client_win > tmp->client_win)
219 min = tmp;
220 if (tmp->client_win > wwin->client_win
221 && (!closest
222 || (tmp->client_win - wwin->client_win) < d)) {
223 closest = tmp;
224 d = tmp->client_win - wwin->client_win;
227 tmp = tmp->prev;
229 if (!closest||closest==wwin)
230 return min;
231 return closest;
235 WWindow*
236 PrevFocusWindow(WScreen *scr)
238 WWindow *tmp, *wwin, *closest, *max;
239 Window d;
241 if (!(wwin = scr->focused_window))
242 return NULL;
243 tmp = wwin->prev;
244 closest = NULL;
245 max = wwin;
246 d = 0xffffffff;
247 while (tmp) {
248 if (wWindowCanReceiveFocus(tmp) &&
249 (!WFLAGP(tmp, skip_window_list) || tmp->flags.internal_window)) {
250 if (max->client_win < tmp->client_win)
251 max = tmp;
252 if (tmp->client_win < wwin->client_win
253 && (!closest
254 || (wwin->client_win - tmp->client_win) < d)) {
255 closest = tmp;
256 d = wwin->client_win - tmp->client_win;
259 tmp = tmp->prev;
261 if (!closest||closest==wwin)
262 return max;
263 return closest;
268 #if 0
270 * Is win2 below win1?
272 static Bool
273 isBelow(WWindow *win1, WWindow *win2)
275 int i;
276 WCoreWindow *tmp;
278 tmp = win1->frame->core->stacking->under;
279 while (tmp) {
280 if (tmp == win2->frame->core)
281 return True;
282 tmp = tmp->stacking->under;
285 for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
286 tmp = win1->screen_ptr->stacking_list[i];
287 while (tmp) {
288 if (tmp == win2->frame->core)
289 return True;
290 tmp = tmp->stacking->under;
293 return True;
295 #endif
300 * XFetchName Wrapper
303 Bool wFetchName(dpy, win, winname)
304 Display *dpy;
305 Window win;
306 char **winname;
308 XTextProperty text_prop;
309 char **list;
310 int num;
312 if (XGetWMName(dpy, win, &text_prop)) {
313 if (text_prop.value && text_prop.nitems > 0) {
314 if (text_prop.encoding == XA_STRING) {
315 *winname = wstrdup((char *)text_prop.value);
316 XFree(text_prop.value);
317 } else {
318 text_prop.nitems = strlen((char *)text_prop.value);
319 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
320 Success && num > 0 && *list) {
321 XFree(text_prop.value);
322 *winname = wstrdup(*list);
323 XFreeStringList(list);
324 } else {
325 *winname = wstrdup((char *)text_prop.value);
326 XFree(text_prop.value);
329 } else {
330 /* the title is set, but it was set to none */
331 *winname = wstrdup("");
333 return True;
334 } else {
335 /* the hint is probably not set */
336 *winname = NULL;
338 return False;
343 * XGetIconName Wrapper
347 Bool wGetIconName(dpy, win, iconname)
348 Display *dpy;
349 Window win;
350 char **iconname;
352 XTextProperty text_prop;
353 char **list;
354 int num;
356 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
357 && text_prop.nitems > 0) {
358 if (text_prop.encoding == XA_STRING)
359 *iconname = (char *)text_prop.value;
360 else {
361 text_prop.nitems = strlen((char *)text_prop.value);
362 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
363 Success && num > 0 && *list) {
364 XFree(text_prop.value);
365 *iconname = wstrdup(*list);
366 XFreeStringList(list);
367 } else
368 *iconname = (char *)text_prop.value;
370 return True;
372 *iconname = NULL;
373 return False;
377 static void
378 eatExpose()
380 XEvent event, foo;
382 /* compress all expose events into a single one */
384 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
385 /* ignore other exposure events for this window */
386 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
387 &foo));
388 /* eat exposes for other windows */
389 eatExpose();
391 event.xexpose.count = 0;
392 XPutBackEvent(dpy, &event);
397 void
398 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
400 time_t time0 = time(NULL);
401 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
402 int dx_is_bigger=0;
404 /* animation parameters */
405 static struct {
406 int delay;
407 int steps;
408 int slowdown;
409 } apars[5] = {
410 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
411 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
412 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
413 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
414 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
418 dx = (float)(to_x-from_x);
419 dy = (float)(to_y-from_y);
420 sx = (dx == 0 ? 0 : fabs(dx)/dx);
421 sy = (dy == 0 ? 0 : fabs(dy)/dy);
423 if (fabs(dx) > fabs(dy)) {
424 dx_is_bigger = 1;
427 if (dx_is_bigger) {
428 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
429 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
430 px = apars[(int)wPreferences.icon_slide_speed].steps;
431 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
432 px = -apars[(int)wPreferences.icon_slide_speed].steps;
433 py = (sx == 0 ? 0 : px*dy/dx);
434 } else {
435 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
436 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
437 py = apars[(int)wPreferences.icon_slide_speed].steps;
438 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
439 py = -apars[(int)wPreferences.icon_slide_speed].steps;
440 px = (sy == 0 ? 0 : py*dx/dy);
443 while (x != to_x || y != to_y) {
444 x += px;
445 y += py;
446 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
447 x = (float)to_x;
448 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
449 y = (float)to_y;
451 if (dx_is_bigger) {
452 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
453 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
454 px = apars[(int)wPreferences.icon_slide_speed].steps;
455 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
456 px = -apars[(int)wPreferences.icon_slide_speed].steps;
457 py = (sx == 0 ? 0 : px*dy/dx);
458 } else {
459 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
460 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
461 py = apars[(int)wPreferences.icon_slide_speed].steps;
462 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
463 py = -apars[(int)wPreferences.icon_slide_speed].steps;
464 px = (sy == 0 ? 0 : py*dx/dy);
467 XMoveWindow(dpy, win, (int)x, (int)y);
468 XFlush(dpy);
469 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
470 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
472 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
473 break;
475 XMoveWindow(dpy, win, to_x, to_y);
477 XSync(dpy, 0);
478 /* compress expose events */
479 eatExpose();
483 char*
484 ShrinkString(WMFont *font, char *string, int width)
486 int w, w1=0;
487 int p;
488 char *pos;
489 char *text;
490 int p1, p2, t;
492 if (wPreferences.multi_byte_text)
493 return wstrdup(string);
495 p = strlen(string);
496 w = WMWidthOfString(font, string, p);
497 text = wmalloc(strlen(string)+8);
498 strcpy(text, string);
499 if (w<=width)
500 return text;
502 pos = strchr(text, ' ');
503 if (!pos)
504 pos = strchr(text, ':');
506 if (pos) {
507 *pos = 0;
508 p = strlen(text);
509 w1 = WMWidthOfString(font, text, p);
510 if (w1 > width) {
511 w1 = 0;
512 p = 0;
513 *pos = ' ';
514 *text = 0;
515 } else {
516 *pos = 0;
517 width -= w1;
518 p++;
520 string += p;
521 p=strlen(string);
522 } else {
523 *text=0;
525 strcat(text, "...");
526 width -= WMWidthOfString(font, "...", 3);
528 pos = string;
529 p1=0;
530 p2=p;
531 t = (p2-p1)/2;
532 while (p2>p1 && p1!=t) {
533 w = WMWidthOfString(font, &string[p-t], t);
534 if (w>width) {
535 p2 = t;
536 t = p1+(p2-p1)/2;
537 } else if (w<width) {
538 p1 = t;
539 t = p1+(p2-p1)/2;
540 } else
541 p2=p1=t;
543 strcat(text, &string[p-p1]);
545 return text;
549 char*
550 FindImage(char *paths, char *file)
552 char *tmp, *path;
554 tmp = strrchr(file, ':');
555 if (tmp) {
556 *tmp = 0;
557 path = wfindfile(paths, file);
558 *tmp = ':';
560 if (!tmp || !path) {
561 path = wfindfile(paths, file);
564 return path;
568 char*
569 FlattenStringList(char **list, int count)
571 int i, j;
572 char *flat_string, *wspace;
574 j = 0;
575 for (i=0; i<count; i++) {
576 if (list[i]!=NULL && list[i][0]!=0) {
577 j += strlen(list[i]);
578 if (strpbrk(list[i], " \t"))
579 j += 2;
583 flat_string = malloc(j+count+1);
584 if (!flat_string) {
585 return NULL;
588 *flat_string = 0;
589 for (i=0; i<count; i++) {
590 if (list[i]!=NULL && list[i][0]!=0) {
591 if (i>0)
592 strcat(flat_string, " ");
593 wspace = strpbrk(list[i], " \t");
594 if (wspace)
595 strcat(flat_string, "\"");
596 strcat(flat_string, list[i]);
597 if (wspace)
598 strcat(flat_string, "\"");
602 return flat_string;
608 *----------------------------------------------------------------------
609 * ParseCommand --
610 * Divides a command line into a argv/argc pair.
611 *----------------------------------------------------------------------
613 #define PRC_ALPHA 0
614 #define PRC_BLANK 1
615 #define PRC_ESCAPE 2
616 #define PRC_DQUOTE 3
617 #define PRC_EOS 4
618 #define PRC_SQUOTE 5
620 typedef struct {
621 short nstate;
622 short output;
623 } DFA;
626 static DFA mtable[9][6] = {
627 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
628 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
629 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
630 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
631 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
632 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
633 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
634 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
635 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
638 char*
639 next_token(char *word, char **next)
641 char *ptr;
642 char *ret, *t;
643 int state, ctype;
645 t = ret = wmalloc(strlen(word)+1);
646 ptr = word;
648 state = 0;
649 *t = 0;
650 while (1) {
651 if (*ptr==0)
652 ctype = PRC_EOS;
653 else if (*ptr=='\\')
654 ctype = PRC_ESCAPE;
655 else if (*ptr=='"')
656 ctype = PRC_DQUOTE;
657 else if (*ptr=='\'')
658 ctype = PRC_SQUOTE;
659 else if (*ptr==' ' || *ptr=='\t')
660 ctype = PRC_BLANK;
661 else
662 ctype = PRC_ALPHA;
664 if (mtable[state][ctype].output) {
665 *t = *ptr; t++;
666 *t = 0;
668 state = mtable[state][ctype].nstate;
669 ptr++;
670 if (mtable[state][0].output<0) {
671 break;
675 if (*ret==0)
676 t = NULL;
677 else
678 t = wstrdup(ret);
680 free(ret);
682 if (ctype==PRC_EOS)
683 *next = NULL;
684 else
685 *next = ptr;
687 return t;
691 void
692 ParseCommand(char *command, char ***argv, int *argc)
694 WMBag *bag = WMCreateBag(4);
695 char *token, *line;
696 int count, j;
698 line = command;
699 do {
700 token = next_token(line, &line);
701 if (token) {
702 WMPutInBag(bag, token);
704 } while (token!=NULL && line!=NULL);
706 count = WMGetBagItemCount(bag);
707 *argv = wmalloc(sizeof(char*)*count);
708 for (j = 0; j < count; j++) {
709 (*argv)[j] = WMGetFromBag(bag, j);
711 *argc = count;
713 WMFreeBag(bag);
716 #if 0
717 static void
718 timeup(void *foo)
720 *(int*)foo=1;
722 #endif
723 static char*
724 getselection(WScreen *scr)
726 char *tmp;
727 extern char *W_GetTextSelection(); /* in WINGs */
729 tmp = W_GetTextSelection(scr->wmscreen, XA_PRIMARY);
730 if (!tmp)
731 tmp = W_GetTextSelection(scr->wmscreen, XA_CUT_BUFFER0);
732 return tmp;
734 #if 0
735 XEvent event;
736 int timeover=0;
737 WMHandlerID *id;
739 #ifdef DEBUG
740 puts("getting selection");
741 #endif
742 RequestSelection(dpy, scr->no_focus_win, LastTimestamp);
743 /* timeout on 1 sec. */
744 id = WMAddTimerHandler(1000, timeup, &timeover);
745 while (!timeover) {
746 WMNextEvent(dpy, &event);
747 if (event.type == SelectionNotify
748 && event.xany.window==scr->no_focus_win) {
749 WMDeleteTimerHandler(id);
750 #ifdef DEBUG
751 puts("selection ok");
752 #endif
753 return GetSelection(dpy, scr->no_focus_win);
754 } else {
755 WMHandleEvent(&event);
758 wwarning(_("selection timed-out"));
759 return NULL;
760 #endif
764 static char*
765 getuserinput(WScreen *scr, char *line, int *ptr)
767 char *ret;
768 char *title;
769 char *prompt;
770 int j, state;
771 int begin = 0;
772 char tbuffer[256], pbuffer[256];
774 title = _("Program Arguments");
775 prompt = _("Enter command arguments:");
776 ret = NULL;
778 #define _STARTING 0
779 #define _TITLE 1
780 #define _PROMPT 2
781 #define _DONE 3
783 state = _STARTING;
784 j = 0;
785 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
786 switch (state) {
787 case _STARTING:
788 if (line[*ptr]=='(') {
789 state = _TITLE;
790 begin = *ptr+1;
791 } else {
792 state = _DONE;
794 break;
796 case _TITLE:
797 if (j <= 0 && line[*ptr]==',') {
799 j = 0;
800 if (*ptr > begin) {
801 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
802 tbuffer[WMIN(*ptr-begin, 255)] = 0;
803 title = (char*)tbuffer;
805 begin = *ptr+1;
806 state = _PROMPT;
808 } else if (j <= 0 && line[*ptr]==')') {
810 if (*ptr > begin) {
811 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
812 tbuffer[WMIN(*ptr-begin, 255)] = 0;
813 title = (char*)tbuffer;
815 state = _DONE;
817 } else if (line[*ptr]=='(') {
818 j++;
819 } else if (line[*ptr]==')') {
820 j--;
823 break;
825 case _PROMPT:
826 if (line[*ptr]==')' && j==0) {
828 if (*ptr-begin > 1) {
829 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255));
830 pbuffer[WMIN(*ptr-begin, 255)] = 0;
831 prompt = (char*)pbuffer;
833 state = _DONE;
834 } else if (line[*ptr]=='(')
835 j++;
836 else if (line[*ptr]==')')
837 j--;
838 break;
841 (*ptr)--;
842 #undef _STARTING
843 #undef _TITLE
844 #undef _PROMPT
845 #undef _DONE
847 if (!wInputDialog(scr, title, prompt, &ret))
848 return NULL;
849 else
850 return ret;
854 #ifdef OFFIX_DND
855 static char*
856 get_dnd_selection(WScreen *scr)
858 XTextProperty text_ret;
859 int result;
860 char **list;
861 char *flat_string;
862 int count;
864 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
866 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
867 || text_ret.format==0 || text_ret.nitems == 0) {
868 wwarning(_("unable to get dropped data from DND drop"));
869 return NULL;
872 XTextPropertyToStringList(&text_ret, &list, &count);
874 if (!list || count<1) {
875 XFree(text_ret.value);
876 wwarning(_("error getting dropped data from DND drop"));
877 return NULL;
880 flat_string = FlattenStringList(list, count);
881 if (!flat_string) {
882 wwarning(_("out of memory while getting data from DND drop"));
885 XFreeStringList(list);
886 XFree(text_ret.value);
887 return flat_string;
889 #endif /* OFFIX_DND */
892 #define S_NORMAL 0
893 #define S_ESCAPE 1
894 #define S_OPTION 2
897 * state input new-state output
898 * NORMAL % OPTION <nil>
899 * NORMAL \ ESCAPE <nil>
900 * NORMAL etc. NORMAL <input>
901 * ESCAPE any NORMAL <input>
902 * OPTION s NORMAL <selection buffer>
903 * OPTION w NORMAL <selected window id>
904 * OPTION a NORMAL <input text>
905 * OPTION d NORMAL <OffiX DND selection object>
906 * OPTION W NORMAL <current workspace>
907 * OPTION etc. NORMAL %<input>
909 #define TMPBUFSIZE 64
910 char*
911 ExpandOptions(WScreen *scr, char *cmdline)
913 int ptr, optr, state, len, olen;
914 char *out, *nout;
915 char *selection=NULL;
916 char *user_input=NULL;
917 #if defined(OFFIX_DND) || defined(XDND)
918 char *dropped_thing=NULL;
919 #endif
920 char tmpbuf[TMPBUFSIZE];
921 int slen;
923 len = strlen(cmdline);
924 olen = len+1;
925 out = malloc(olen);
926 if (!out) {
927 wwarning(_("out of memory during expansion of \"%s\""));
928 return NULL;
930 *out = 0;
931 ptr = 0; /* input line pointer */
932 optr = 0; /* output line pointer */
933 state = S_NORMAL;
934 while (ptr < len) {
935 switch (state) {
936 case S_NORMAL:
937 switch (cmdline[ptr]) {
938 case '\\':
939 state = S_ESCAPE;
940 break;
941 case '%':
942 state = S_OPTION;
943 break;
944 default:
945 state = S_NORMAL;
946 out[optr++]=cmdline[ptr];
947 break;
949 break;
950 case S_ESCAPE:
951 switch (cmdline[ptr]) {
952 case 'n':
953 out[optr++]=10;
954 break;
956 case 'r':
957 out[optr++]=13;
958 break;
960 case 't':
961 out[optr++]=9;
962 break;
964 default:
965 out[optr++]=cmdline[ptr];
967 state = S_NORMAL;
968 break;
969 case S_OPTION:
970 state = S_NORMAL;
971 switch (cmdline[ptr]) {
972 case 'w':
973 if (scr->focused_window
974 && scr->focused_window->flags.focused) {
975 sprintf(tmpbuf, "0x%x",
976 (unsigned int)scr->focused_window->client_win);
977 slen = strlen(tmpbuf);
978 olen += slen;
979 nout = realloc(out,olen);
980 if (!nout) {
981 wwarning(_("out of memory during expansion of \"%w\""));
982 goto error;
984 out = nout;
985 strcat(out,tmpbuf);
986 optr+=slen;
987 } else {
988 out[optr++]=' ';
990 break;
992 case 'W':
993 sprintf(tmpbuf, "0x%x",
994 (unsigned int)scr->current_workspace + 1);
995 slen = strlen(tmpbuf);
996 olen += slen;
997 nout = realloc(out,olen);
998 if (!nout) {
999 wwarning(_("out of memory during expansion of \"%W\""));
1000 goto error;
1002 out = nout;
1003 strcat(out,tmpbuf);
1004 optr+=slen;
1005 break;
1007 case 'a':
1008 ptr++;
1009 user_input = getuserinput(scr, cmdline, &ptr);
1010 if (user_input) {
1011 slen = strlen(user_input);
1012 olen += slen;
1013 nout = realloc(out,olen);
1014 if (!nout) {
1015 wwarning(_("out of memory during expansion of \"%a\""));
1016 goto error;
1018 out = nout;
1019 strcat(out,user_input);
1020 optr+=slen;
1021 } else {
1022 /* Not an error, but user has Canceled the dialog box.
1023 * This will make the command to not be performed. */
1024 goto error;
1026 break;
1028 #if defined(OFFIX_DND) || defined(XDND)
1029 case 'd':
1030 #ifdef XDND
1031 if(scr->xdestring) {
1032 dropped_thing = wstrdup(scr->xdestring);
1034 #endif
1035 if (!dropped_thing) {
1036 dropped_thing = get_dnd_selection(scr);
1038 if (!dropped_thing) {
1039 scr->flags.dnd_data_convertion_status = 1;
1040 goto error;
1042 slen = strlen(dropped_thing);
1043 olen += slen;
1044 nout = realloc(out,olen);
1045 if (!nout) {
1046 wwarning(_("out of memory during expansion of \"%d\""));
1047 goto error;
1049 out = nout;
1050 strcat(out,dropped_thing);
1051 optr+=slen;
1052 break;
1053 #endif /* OFFIX_DND */
1055 case 's':
1056 if (!selection) {
1057 selection = getselection(scr);
1059 if (!selection) {
1060 wwarning(_("selection not available"));
1061 goto error;
1063 slen = strlen(selection);
1064 olen += slen;
1065 nout = realloc(out,olen);
1066 if (!nout) {
1067 wwarning(_("out of memory during expansion of \"%s\""));
1068 goto error;
1070 out = nout;
1071 strcat(out,selection);
1072 optr+=slen;
1073 break;
1074 default:
1075 out[optr++]='%';
1076 out[optr++]=cmdline[ptr];
1078 break;
1080 out[optr]=0;
1081 ptr++;
1083 if (selection)
1084 XFree(selection);
1085 return out;
1087 error:
1088 free(out);
1089 if (selection)
1090 XFree(selection);
1091 return NULL;
1095 /* We don't care for upper/lower case in comparing the keys; so we
1096 have to define our own comparison function here */
1097 BOOL
1098 StringCompareHook(proplist_t pl1, proplist_t pl2)
1100 char *str1, *str2;
1102 str1 = PLGetString(pl1);
1103 str2 = PLGetString(pl2);
1105 if (strcasecmp(str1, str2)==0)
1106 return YES;
1107 else
1108 return NO;
1112 /* feof doesn't seem to work on pipes */
1114 IsEof(FILE * stream)
1116 static struct stat stinfo;
1118 fstat(fileno(stream), &stinfo);
1119 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1120 feof(stream));
1124 void
1125 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1127 char *name;
1129 *winstance = *wclass = NULL;
1131 if (!PLIsString(value)) {
1132 wwarning(_("bad window name value in %s state info"), where);
1133 return;
1136 name = PLGetString(value);
1137 if (!name || strlen(name)==0) {
1138 wwarning(_("bad window name value in %s state info"), where);
1139 return;
1142 UnescapeWM_CLASS(name, winstance, wclass);
1146 #if 0
1147 static char*
1148 keysymToString(KeySym keysym, unsigned int state)
1150 XKeyEvent kev;
1151 char *buf = wmalloc(20);
1152 int count;
1154 kev.display = dpy;
1155 kev.type = KeyPress;
1156 kev.send_event = False;
1157 kev.window = DefaultRootWindow(dpy);
1158 kev.root = DefaultRootWindow(dpy);
1159 kev.same_screen = True;
1160 kev.subwindow = kev.root;
1161 kev.serial = 0x12344321;
1162 kev.time = CurrentTime;
1163 kev.state = state;
1164 kev.keycode = XKeysymToKeycode(dpy, keysym);
1165 count = XLookupString(&kev, buf, 19, NULL, NULL);
1166 buf[count] = 0;
1168 return buf;
1170 #endif
1172 char*
1173 GetShortcutString(char *text)
1175 char *buffer = NULL;
1176 char *k;
1177 int modmask = 0;
1178 /* KeySym ksym;*/
1179 int control = 0;
1180 char *tmp;
1182 tmp = text = wstrdup(text);
1184 /* get modifiers */
1185 while ((k = strchr(text, '+'))!=NULL) {
1186 int mod;
1188 *k = 0;
1189 mod = wXModifierFromKey(text);
1190 if (mod<0) {
1191 return wstrdup("bug");
1194 modmask |= mod;
1196 if (strcasecmp(text, "Meta")==0) {
1197 buffer = wstrappend(buffer, "M+");
1198 } else if (strcasecmp(text, "Alt")==0) {
1199 buffer = wstrappend(buffer, "A+");
1200 } else if (strcasecmp(text, "Shift")==0) {
1201 buffer = wstrappend(buffer, "Sh+");
1202 } else if (strcasecmp(text, "Mod1")==0) {
1203 buffer = wstrappend(buffer, "M1+");
1204 } else if (strcasecmp(text, "Mod2")==0) {
1205 buffer = wstrappend(buffer, "M2+");
1206 } else if (strcasecmp(text, "Mod3")==0) {
1207 buffer = wstrappend(buffer, "M3+");
1208 } else if (strcasecmp(text, "Mod4")==0) {
1209 buffer = wstrappend(buffer, "M4+");
1210 } else if (strcasecmp(text, "Mod5")==0) {
1211 buffer = wstrappend(buffer, "M5+");
1212 } else if (strcasecmp(text, "Control")==0) {
1213 control = 1;
1214 } else {
1215 buffer = wstrappend(buffer, text);
1217 text = k+1;
1220 if (control) {
1221 buffer = wstrappend(buffer, "^");
1223 buffer = wstrappend(buffer, text);
1225 /* get key */
1226 /* ksym = XStringToKeysym(text);
1227 tmp = keysymToString(ksym, modmask);
1228 puts(tmp);
1229 buffer = wstrappend(buffer, tmp);
1231 free(tmp);
1233 return buffer;
1237 char*
1238 EscapeWM_CLASS(char *name, char *class)
1240 char *ret;
1241 char *ename = NULL, *eclass = NULL;
1242 int i, j, l;
1244 if (!name && !class)
1245 return NULL;
1247 if (name) {
1248 l = strlen(name);
1249 ename = wmalloc(l*2);
1250 j = 0;
1251 for (i=0; i<l; i++) {
1252 if (name[i]=='\\') {
1253 ename[j++] = '\\';
1254 } else if (name[i]=='.') {
1255 ename[j++] = '\\';
1257 ename[j++] = name[i];
1259 ename[j] = 0;
1261 if (class) {
1262 l = strlen(class);
1263 eclass = wmalloc(l*2);
1264 j = 0;
1265 for (i=0; i<l; i++) {
1266 if (class[i]=='\\') {
1267 eclass[j++] = '\\';
1268 } else if (class[i]=='.') {
1269 eclass[j++] = '\\';
1271 eclass[j++] = class[i];
1273 eclass[j] = 0;
1276 if (ename && eclass) {
1277 ret = wmalloc(strlen(ename)+strlen(eclass)+4);
1278 sprintf(ret, "%s.%s", ename, eclass);
1279 free(ename);
1280 free(eclass);
1281 } else if (ename) {
1282 ret = wstrdup(ename);
1283 free(ename);
1284 } else {
1285 ret = wstrdup(eclass);
1286 free(eclass);
1289 return ret;
1293 void
1294 UnescapeWM_CLASS(char *str, char **name, char **class)
1296 int i, j, k, dot;
1297 Bool esc;
1299 j = strlen(str);
1300 *name = wmalloc(j);
1301 **name = 0;
1302 *class = wmalloc(j);
1303 **class = 0;
1305 /* separate string in 2 parts */
1306 esc = False;
1307 dot = 0;
1308 for (i = 0; i < j; i++) {
1309 if (!esc) {
1310 if (str[i]=='\\') {
1311 esc = True;
1312 } else if (str[i]=='.') {
1313 dot = i;
1314 break;
1316 } else {
1317 esc = False;
1321 /* unescape strings */
1322 esc = False;
1323 k = 0;
1324 for (i = 0; i < dot; i++) {
1325 if (!esc) {
1326 if (str[i]=='\\') {
1327 esc = True;
1328 } else {
1329 (*name)[k++] = str[i];
1331 } else {
1332 (*name)[k++] = str[i];
1333 esc = False;
1336 (*name)[k] = 0;
1338 esc = False;
1339 k = 0;
1340 for (i = dot+1; i<j; i++) {
1341 if (!esc) {
1342 if (str[i]=='\\') {
1343 esc = True;
1344 } else {
1345 (*class)[k++] = str[i];
1347 } else {
1348 esc = False;
1351 (*class)[k] = 0;
1353 if (!*name) {
1354 free(*name);
1355 *name = NULL;
1357 if (!*class) {
1358 free(*class);
1359 *class = NULL;
1365 void
1366 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1368 unsigned char *buffer;
1369 int len;
1370 int i;
1371 char buf[16];
1373 if (!scr->flags.backimage_helper_launched) {
1374 return;
1377 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1378 buffer = wmalloc(len+5);
1379 sprintf(buf, "%4i", len);
1380 memcpy(buffer, buf, 4);
1381 buffer[4] = type;
1382 i = 5;
1383 if (workspace >= 0) {
1384 sprintf(buf, "%4i", workspace);
1385 memcpy(&buffer[i], buf, 4);
1386 i += 4;
1387 buffer[i] = 0;
1389 if (msg)
1390 strcpy(&buffer[i], msg);
1392 if (write(scr->helper_fd, buffer, len+4) < 0) {
1393 wsyserror(_("could not send message to background image helper"));
1395 free(buffer);