Code update for Window Maker version 0.50.0
[wmaker-crm.git] / src / misc.c
blob2ad83acfe1249672d5c2bb12fd0d051c30a10889
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 i, j, k, state;
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 (i = 0; line[i]==0 && state!=_DONE; i++) {
800 switch (state) {
801 case _STARTING:
802 if (line[i]=='(') {
803 state = _TITLE;
804 } else {
805 state = _DONE;
807 break;
809 case _TITLE:
810 if (j <= 0 && line[i]==',') {
812 j = 0;
813 if (i > 1) {
814 strncpy(tbuffer, &line[1], WMIN(i, 255));
815 tbuffer[WMIN(i, 255)] = 0;
816 title = (char*)tbuffer;
818 k = i+1;
819 state = _PROMPT;
821 } else if (j <= 0 && line[i]==')') {
823 if (i > 1) {
824 strncpy(tbuffer, &line[1], WMIN(i, 255));
825 tbuffer[WMIN(i, 255)] = 0;
826 title = (char*)tbuffer;
828 state = _DONE;
830 } else if (line[i]=='(')
831 j++;
832 else if (line[i]==')')
833 j--;
835 break;
837 case _PROMPT:
838 if (line[i]==')' && j==0) {
840 if (i-k > 1) {
841 strncpy(pbuffer, &line[k], WMIN(i-k, 255));
842 pbuffer[WMIN(i-k, 255)] = 0;
843 title = (char*)pbuffer;
845 state = _DONE;
846 } else if (line[i]=='(')
847 j++;
848 else if (line[i]==')')
849 j--;
850 break;
853 #undef _STARTING
854 #undef _TITLE
855 #undef _PROMPT
856 #undef _DONE
858 if (!wInputDialog(scr, title, prompt, &ret))
859 return NULL;
860 else
861 return ret;
865 #ifdef OFFIX_DND
866 static char*
867 get_dnd_selection(WScreen *scr)
869 XTextProperty text_ret;
870 int result;
871 char **list;
872 char *flat_string;
873 int count;
875 #ifdef XDE_DND
876 if(scr->xdestring) {
877 return (wstrdup(scr->xdestring));
879 #endif
880 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
882 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
883 || text_ret.format==0 || text_ret.nitems == 0) {
884 wwarning(_("unable to get dropped data from DND drop"));
885 return NULL;
888 XTextPropertyToStringList(&text_ret, &list, &count);
890 if (!list || count<1) {
891 XFree(text_ret.value);
892 wwarning(_("error getting dropped data from DND drop"));
893 return NULL;
896 flat_string = FlattenStringList(list, count);
897 if (!flat_string) {
898 wwarning(_("out of memory while getting data from DND drop"));
901 XFreeStringList(list);
902 XFree(text_ret.value);
903 return flat_string;
905 #endif /* OFFIX_DND */
908 #define S_NORMAL 0
909 #define S_ESCAPE 1
910 #define S_OPTION 2
913 * state input new-state output
914 * NORMAL % OPTION <nil>
915 * NORMAL \ ESCAPE <nil>
916 * NORMAL etc. NORMAL <input>
917 * ESCAPE any NORMAL <input>
918 * OPTION s NORMAL <selection buffer>
919 * OPTION w NORMAL <selected window id>
920 * OPTION a NORMAL <input text>
921 * OPTION d NORMAL <OffiX DND selection object>
922 * OPTION etc. NORMAL %<input>
924 #define TMPBUFSIZE 64
925 char*
926 ExpandOptions(WScreen *scr, char *cmdline)
928 int ptr, optr, state, len, olen;
929 char *out, *nout;
930 char *selection=NULL;
931 char *user_input=NULL;
932 #ifdef OFFIX_DND
933 char *dropped_thing=NULL;
934 #endif
935 char tmpbuf[TMPBUFSIZE];
936 int slen;
938 len = strlen(cmdline);
939 olen = len+1;
940 out = malloc(olen);
941 if (!out) {
942 wwarning(_("out of memory during expansion of \"%s\""));
943 return NULL;
945 *out = 0;
946 ptr = 0; /* input line pointer */
947 optr = 0; /* output line pointer */
948 state = S_NORMAL;
949 while (ptr < len) {
950 switch (state) {
951 case S_NORMAL:
952 switch (cmdline[ptr]) {
953 case '\\':
954 state = S_ESCAPE;
955 break;
956 case '%':
957 state = S_OPTION;
958 break;
959 default:
960 state = S_NORMAL;
961 out[optr++]=cmdline[ptr];
962 break;
964 break;
965 case S_ESCAPE:
966 switch (cmdline[ptr]) {
967 case 'n':
968 out[optr++]=10;
969 break;
971 case 'r':
972 out[optr++]=13;
973 break;
975 case 't':
976 out[optr++]=9;
977 break;
979 default:
980 out[optr++]=cmdline[ptr];
982 state = S_NORMAL;
983 break;
984 case S_OPTION:
985 state = S_NORMAL;
986 switch (cmdline[ptr]) {
987 case 'w':
988 if (scr->focused_window
989 && scr->focused_window->flags.focused) {
990 sprintf(tmpbuf, "0x%x",
991 (unsigned int)scr->focused_window->client_win);
992 slen = strlen(tmpbuf);
993 olen += slen;
994 nout = realloc(out,olen);
995 if (!nout) {
996 wwarning(_("out of memory during expansion of \"%w\""));
997 goto error;
999 out = nout;
1000 strcat(out,tmpbuf);
1001 optr+=slen;
1002 } else {
1003 out[optr++]=' ';
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 #ifdef OFFIX_DND
1029 case 'd':
1030 if (!dropped_thing) {
1031 dropped_thing = get_dnd_selection(scr);
1033 if (!dropped_thing) {
1034 scr->flags.dnd_data_convertion_status = 1;
1035 goto error;
1037 slen = strlen(dropped_thing);
1038 olen += slen;
1039 nout = realloc(out,olen);
1040 if (!nout) {
1041 wwarning(_("out of memory during expansion of \"%d\""));
1042 goto error;
1044 out = nout;
1045 strcat(out,dropped_thing);
1046 optr+=slen;
1047 break;
1048 #endif /* OFFIX_DND */
1050 case 's':
1051 if (!selection) {
1052 selection = getselection(scr);
1054 if (!selection) {
1055 wwarning(_("selection not available"));
1056 goto error;
1058 slen = strlen(selection);
1059 olen += slen;
1060 nout = realloc(out,olen);
1061 if (!nout) {
1062 wwarning(_("out of memory during expansion of \"%s\""));
1063 goto error;
1065 out = nout;
1066 strcat(out,selection);
1067 optr+=slen;
1068 break;
1069 default:
1070 out[optr++]='%';
1071 out[optr++]=cmdline[ptr];
1073 break;
1075 out[optr]=0;
1076 ptr++;
1078 if (selection)
1079 XFree(selection);
1080 return out;
1082 error:
1083 free(out);
1084 if (selection)
1085 XFree(selection);
1086 return NULL;
1090 /* We don't care for upper/lower case in comparing the keys; so we
1091 have to define our own comparison function here */
1092 BOOL
1093 StringCompareHook(proplist_t pl1, proplist_t pl2)
1095 char *str1, *str2;
1097 str1 = PLGetString(pl1);
1098 str2 = PLGetString(pl2);
1100 if (strcasecmp(str1, str2)==0)
1101 return YES;
1102 else
1103 return NO;
1107 /* feof doesn't seem to work on pipes */
1109 IsEof(FILE * stream)
1111 static struct stat stinfo;
1113 fstat(fileno(stream), &stinfo);
1114 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1115 feof(stream));
1119 void
1120 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1122 char *name;
1124 *winstance = *wclass = NULL;
1126 if (!PLIsString(value)) {
1127 wwarning(_("bad window name value in %s state info"), where);
1128 return;
1131 name = PLGetString(value);
1132 if (!name || strlen(name)==0) {
1133 wwarning(_("bad window name value in %s state info"), where);
1134 return;
1137 UnescapeWM_CLASS(name, winstance, wclass);
1141 #if 0
1142 static char*
1143 keysymToString(KeySym keysym, unsigned int state)
1145 XKeyEvent kev;
1146 char *buf = wmalloc(20);
1147 int count;
1149 kev.display = dpy;
1150 kev.type = KeyPress;
1151 kev.send_event = False;
1152 kev.window = DefaultRootWindow(dpy);
1153 kev.root = DefaultRootWindow(dpy);
1154 kev.same_screen = True;
1155 kev.subwindow = kev.root;
1156 kev.serial = 0x12344321;
1157 kev.time = CurrentTime;
1158 kev.state = state;
1159 kev.keycode = XKeysymToKeycode(dpy, keysym);
1160 count = XLookupString(&kev, buf, 19, NULL, NULL);
1161 buf[count] = 0;
1163 return buf;
1165 #endif
1167 char*
1168 GetShortcutString(char *text)
1170 char *buffer = NULL;
1171 char *k;
1172 int modmask = 0;
1173 /* KeySym ksym;*/
1174 int control = 0;
1175 char *tmp;
1177 tmp = text = wstrdup(text);
1179 /* get modifiers */
1180 while ((k = strchr(text, '+'))!=NULL) {
1181 int mod;
1183 *k = 0;
1184 mod = wXModifierFromKey(text);
1185 if (mod<0) {
1186 return wstrdup("bug");
1189 modmask |= mod;
1191 if (strcasecmp(text, "Meta")==0) {
1192 buffer = wstrappend(buffer, "M+");
1193 } else if (strcasecmp(text, "Alt")==0) {
1194 buffer = wstrappend(buffer, "A+");
1195 } else if (strcasecmp(text, "Shift")==0) {
1196 buffer = wstrappend(buffer, "Sh+");
1197 } else if (strcasecmp(text, "Mod1")==0) {
1198 buffer = wstrappend(buffer, "M1+");
1199 } else if (strcasecmp(text, "Mod2")==0) {
1200 buffer = wstrappend(buffer, "M2+");
1201 } else if (strcasecmp(text, "Mod3")==0) {
1202 buffer = wstrappend(buffer, "M3+");
1203 } else if (strcasecmp(text, "Mod4")==0) {
1204 buffer = wstrappend(buffer, "M4+");
1205 } else if (strcasecmp(text, "Mod5")==0) {
1206 buffer = wstrappend(buffer, "M5+");
1207 } else if (strcasecmp(text, "Control")==0) {
1208 control = 1;
1209 } else {
1210 buffer = wstrappend(buffer, text);
1212 text = k+1;
1215 if (control) {
1216 buffer = wstrappend(buffer, "^");
1218 buffer = wstrappend(buffer, text);
1220 /* get key */
1221 /* ksym = XStringToKeysym(text);
1222 tmp = keysymToString(ksym, modmask);
1223 puts(tmp);
1224 buffer = wstrappend(buffer, tmp);
1226 free(tmp);
1228 return buffer;
1232 char*
1233 EscapeWM_CLASS(char *name, char *class)
1235 char *ret;
1236 char *ename = NULL, *eclass = NULL;
1237 int i, j, l;
1239 if (!name && !class)
1240 return NULL;
1242 if (name) {
1243 l = strlen(name);
1244 ename = wmalloc(l*2);
1245 j = 0;
1246 for (i=0; i<l; i++) {
1247 if (name[i]=='\\') {
1248 ename[j++] = '\\';
1249 } else if (name[i]=='.') {
1250 ename[j++] = '\\';
1252 ename[j++] = name[i];
1254 ename[j] = 0;
1256 if (class) {
1257 l = strlen(class);
1258 eclass = wmalloc(l*2);
1259 j = 0;
1260 for (i=0; i<l; i++) {
1261 if (class[i]=='\\') {
1262 eclass[j++] = '\\';
1263 } else if (class[i]=='.') {
1264 eclass[j++] = '\\';
1266 eclass[j++] = class[i];
1268 eclass[j] = 0;
1271 if (ename && eclass) {
1272 ret = wmalloc(strlen(ename)+strlen(eclass)+4);
1273 sprintf(ret, "%s.%s", ename, eclass);
1274 free(ename);
1275 free(eclass);
1276 } else if (ename) {
1277 ret = wstrdup(ename);
1278 free(ename);
1279 } else {
1280 ret = wstrdup(eclass);
1281 free(eclass);
1284 return ret;
1288 void
1289 UnescapeWM_CLASS(char *str, char **name, char **class)
1291 int i, j, k, dot;
1292 Bool esc;
1294 j = strlen(str);
1295 *name = wmalloc(j);
1296 **name = 0;
1297 *class = wmalloc(j);
1298 **class = 0;
1300 /* separate string in 2 parts */
1301 esc = False;
1302 dot = 0;
1303 for (i = 0; i < j; i++) {
1304 if (!esc) {
1305 if (str[i]=='\\') {
1306 esc = True;
1307 } else if (str[i]=='.') {
1308 dot = i;
1309 break;
1311 } else {
1312 esc = False;
1316 /* unescape strings */
1317 esc = False;
1318 k = 0;
1319 for (i = 0; i < dot; i++) {
1320 if (!esc) {
1321 if (str[i]=='\\') {
1322 esc = True;
1323 } else {
1324 (*name)[k++] = str[i];
1326 } else {
1327 esc = False;
1330 (*name)[k] = 0;
1332 esc = False;
1333 k = 0;
1334 for (i = dot+1; i<j; i++) {
1335 if (!esc) {
1336 if (str[i]=='\\') {
1337 esc = True;
1338 } else {
1339 (*class)[k++] = str[i];
1341 } else {
1342 esc = False;
1345 (*class)[k] = 0;
1347 if (!*name) {
1348 free(*name);
1349 *name = NULL;
1351 if (!*class) {
1352 free(*class);
1353 *class = NULL;
1359 void
1360 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1362 unsigned char *buffer;
1363 int len;
1364 int i;
1365 char buf[16];
1367 if (!scr->flags.backimage_helper_launched) {
1368 return;
1371 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1372 buffer = wmalloc(len+5);
1373 sprintf(buf, "%4i", len);
1374 memcpy(buffer, buf, 4);
1375 buffer[4] = type;
1376 i = 5;
1377 if (workspace >= 0) {
1378 sprintf(buf, "%4i", workspace);
1379 memcpy(&buffer[i], buf, 4);
1380 i += 4;
1381 buffer[i] = 0;
1383 if (msg)
1384 strcpy(&buffer[i], msg);
1386 if (write(scr->helper_fd, buffer, len+4) < 0) {
1387 wsyserror(_("could not send message to background image helper"));
1389 free(buffer);
1393 void
1394 ExecuteShellCommand(WScreen *scr, char *command)
1396 static char *shell = NULL;
1397 pid_t pid;
1400 * This have a problem: if the shell is tcsh (not sure about others)
1401 * and ~/.tcshrc have /bin/stty erase ^H somewhere on it, the shell
1402 * will block and the command will not be executed.
1403 if (!shell) {
1404 shell = getenv("SHELL");
1405 if (!shell)
1406 shell = "/bin/sh";
1409 shell = "/bin/sh";
1411 pid = fork();
1412 if (pid==0) {
1414 SetupEnvironment(scr);
1416 #ifdef HAVE_SETPGID
1417 setpgid(0, 0);
1418 #endif
1419 execl(shell, shell, "-c", command, NULL);
1420 wsyserror("could not execute %s -c %s", shell, command);
1421 Exit(-1);
1422 } else if (pid < 0) {
1423 wsyserror("cannot fork a new process");