more dnd changes
[wmaker-crm.git] / src / misc.c
blob524a4eb0e7176b4b84c5664fdbbfabe8e8607da6
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 */
205 #if 0
207 * Is win2 below win1?
209 static Bool
210 isBelow(WWindow *win1, WWindow *win2)
212 int i;
213 WCoreWindow *tmp;
215 tmp = win1->frame->core->stacking->under;
216 while (tmp) {
217 if (tmp == win2->frame->core)
218 return True;
219 tmp = tmp->stacking->under;
222 for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
223 tmp = win1->screen_ptr->stacking_list[i];
224 while (tmp) {
225 if (tmp == win2->frame->core)
226 return True;
227 tmp = tmp->stacking->under;
230 return True;
232 #endif
237 * XFetchName Wrapper
240 Bool wFetchName(dpy, win, winname)
241 Display *dpy;
242 Window win;
243 char **winname;
245 XTextProperty text_prop;
246 char **list;
247 int num;
249 if (XGetWMName(dpy, win, &text_prop)) {
250 if (text_prop.value && text_prop.nitems > 0) {
251 if (text_prop.encoding == XA_STRING) {
252 *winname = wstrdup((char *)text_prop.value);
253 XFree(text_prop.value);
254 } else {
255 text_prop.nitems = strlen((char *)text_prop.value);
256 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
257 Success && num > 0 && *list) {
258 XFree(text_prop.value);
259 *winname = wstrdup(*list);
260 XFreeStringList(list);
261 } else {
262 *winname = wstrdup((char *)text_prop.value);
263 XFree(text_prop.value);
266 } else {
267 /* the title is set, but it was set to none */
268 *winname = wstrdup("");
270 return True;
271 } else {
272 /* the hint is probably not set */
273 *winname = NULL;
275 return False;
280 * XGetIconName Wrapper
284 Bool wGetIconName(dpy, win, iconname)
285 Display *dpy;
286 Window win;
287 char **iconname;
289 XTextProperty text_prop;
290 char **list;
291 int num;
293 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
294 && text_prop.nitems > 0) {
295 if (text_prop.encoding == XA_STRING)
296 *iconname = (char *)text_prop.value;
297 else {
298 text_prop.nitems = strlen((char *)text_prop.value);
299 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
300 Success && num > 0 && *list) {
301 XFree(text_prop.value);
302 *iconname = wstrdup(*list);
303 XFreeStringList(list);
304 } else
305 *iconname = (char *)text_prop.value;
307 return True;
309 *iconname = NULL;
310 return False;
314 static void
315 eatExpose()
317 XEvent event, foo;
319 /* compress all expose events into a single one */
321 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
322 /* ignore other exposure events for this window */
323 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
324 &foo));
325 /* eat exposes for other windows */
326 eatExpose();
328 event.xexpose.count = 0;
329 XPutBackEvent(dpy, &event);
334 void
335 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
337 time_t time0 = time(NULL);
338 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
339 int dx_is_bigger=0;
341 /* animation parameters */
342 static struct {
343 int delay;
344 int steps;
345 int slowdown;
346 } apars[5] = {
347 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
348 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
349 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
350 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
351 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
355 dx = (float)(to_x-from_x);
356 dy = (float)(to_y-from_y);
357 sx = (dx == 0 ? 0 : fabs(dx)/dx);
358 sy = (dy == 0 ? 0 : fabs(dy)/dy);
360 if (fabs(dx) > fabs(dy)) {
361 dx_is_bigger = 1;
364 if (dx_is_bigger) {
365 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
366 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
367 px = apars[(int)wPreferences.icon_slide_speed].steps;
368 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
369 px = -apars[(int)wPreferences.icon_slide_speed].steps;
370 py = (sx == 0 ? 0 : px*dy/dx);
371 } else {
372 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
373 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
374 py = apars[(int)wPreferences.icon_slide_speed].steps;
375 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
376 py = -apars[(int)wPreferences.icon_slide_speed].steps;
377 px = (sy == 0 ? 0 : py*dx/dy);
380 while (x != to_x || y != to_y) {
381 x += px;
382 y += py;
383 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
384 x = (float)to_x;
385 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
386 y = (float)to_y;
388 if (dx_is_bigger) {
389 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
390 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
391 px = apars[(int)wPreferences.icon_slide_speed].steps;
392 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
393 px = -apars[(int)wPreferences.icon_slide_speed].steps;
394 py = (sx == 0 ? 0 : px*dy/dx);
395 } else {
396 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
397 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
398 py = apars[(int)wPreferences.icon_slide_speed].steps;
399 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
400 py = -apars[(int)wPreferences.icon_slide_speed].steps;
401 px = (sy == 0 ? 0 : py*dx/dy);
404 XMoveWindow(dpy, win, (int)x, (int)y);
405 XFlush(dpy);
406 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
407 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
409 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
410 break;
412 XMoveWindow(dpy, win, to_x, to_y);
414 XSync(dpy, 0);
415 /* compress expose events */
416 eatExpose();
420 char*
421 ShrinkString(WMFont *font, char *string, int width)
423 int w, w1=0;
424 int p;
425 char *pos;
426 char *text;
427 int p1, p2, t;
429 if (wPreferences.multi_byte_text)
430 return wstrdup(string);
432 p = strlen(string);
433 w = WMWidthOfString(font, string, p);
434 text = wmalloc(strlen(string)+8);
435 strcpy(text, string);
436 if (w<=width)
437 return text;
439 pos = strchr(text, ' ');
440 if (!pos)
441 pos = strchr(text, ':');
443 if (pos) {
444 *pos = 0;
445 p = strlen(text);
446 w1 = WMWidthOfString(font, text, p);
447 if (w1 > width) {
448 w1 = 0;
449 p = 0;
450 *pos = ' ';
451 *text = 0;
452 } else {
453 *pos = 0;
454 width -= w1;
455 p++;
457 string += p;
458 p=strlen(string);
459 } else {
460 *text=0;
462 strcat(text, "...");
463 width -= WMWidthOfString(font, "...", 3);
465 pos = string;
466 p1=0;
467 p2=p;
468 t = (p2-p1)/2;
469 while (p2>p1 && p1!=t) {
470 w = WMWidthOfString(font, &string[p-t], t);
471 if (w>width) {
472 p2 = t;
473 t = p1+(p2-p1)/2;
474 } else if (w<width) {
475 p1 = t;
476 t = p1+(p2-p1)/2;
477 } else
478 p2=p1=t;
480 strcat(text, &string[p-p1]);
482 return text;
486 char*
487 FindImage(char *paths, char *file)
489 char *tmp, *path;
491 tmp = strrchr(file, ':');
492 if (tmp) {
493 *tmp = 0;
494 path = wfindfile(paths, file);
495 *tmp = ':';
497 if (!tmp || !path) {
498 path = wfindfile(paths, file);
501 return path;
505 char*
506 FlattenStringList(char **list, int count)
508 int i, j;
509 char *flat_string, *wspace;
511 j = 0;
512 for (i=0; i<count; i++) {
513 if (list[i]!=NULL && list[i][0]!=0) {
514 j += strlen(list[i]);
515 if (strpbrk(list[i], " \t"))
516 j += 2;
520 flat_string = malloc(j+count+1);
521 if (!flat_string) {
522 return NULL;
525 *flat_string = 0;
526 for (i=0; i<count; i++) {
527 if (list[i]!=NULL && list[i][0]!=0) {
528 if (i>0)
529 strcat(flat_string, " ");
530 wspace = strpbrk(list[i], " \t");
531 if (wspace)
532 strcat(flat_string, "\"");
533 strcat(flat_string, list[i]);
534 if (wspace)
535 strcat(flat_string, "\"");
539 return flat_string;
545 *----------------------------------------------------------------------
546 * ParseCommand --
547 * Divides a command line into a argv/argc pair.
548 *----------------------------------------------------------------------
550 #define PRC_ALPHA 0
551 #define PRC_BLANK 1
552 #define PRC_ESCAPE 2
553 #define PRC_DQUOTE 3
554 #define PRC_EOS 4
555 #define PRC_SQUOTE 5
557 typedef struct {
558 short nstate;
559 short output;
560 } DFA;
563 static DFA mtable[9][6] = {
564 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
565 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
566 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
567 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
568 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
569 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
570 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
571 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
572 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
575 char*
576 next_token(char *word, char **next)
578 char *ptr;
579 char *ret, *t;
580 int state, ctype;
582 t = ret = wmalloc(strlen(word)+1);
583 ptr = word;
585 state = 0;
586 *t = 0;
587 while (1) {
588 if (*ptr==0)
589 ctype = PRC_EOS;
590 else if (*ptr=='\\')
591 ctype = PRC_ESCAPE;
592 else if (*ptr=='"')
593 ctype = PRC_DQUOTE;
594 else if (*ptr=='\'')
595 ctype = PRC_SQUOTE;
596 else if (*ptr==' ' || *ptr=='\t')
597 ctype = PRC_BLANK;
598 else
599 ctype = PRC_ALPHA;
601 if (mtable[state][ctype].output) {
602 *t = *ptr; t++;
603 *t = 0;
605 state = mtable[state][ctype].nstate;
606 ptr++;
607 if (mtable[state][0].output<0) {
608 break;
612 if (*ret==0)
613 t = NULL;
614 else
615 t = wstrdup(ret);
617 free(ret);
619 if (ctype==PRC_EOS)
620 *next = NULL;
621 else
622 *next = ptr;
624 return t;
628 void
629 ParseCommand(char *command, char ***argv, int *argc)
631 WMBag *bag = WMCreateBag(4);
632 char *token, *line;
633 int count, j;
635 line = command;
636 do {
637 token = next_token(line, &line);
638 if (token) {
639 WMPutInBag(bag, token);
641 } while (token!=NULL && line!=NULL);
643 count = WMGetBagItemCount(bag);
644 *argv = wmalloc(sizeof(char*)*count);
645 for (j = 0; j < count; j++) {
646 (*argv)[j] = WMGetFromBag(bag, j);
648 *argc = count;
650 WMFreeBag(bag);
654 static void
655 timeoutHandler(void *data)
657 *(int*)data = 1;
661 static char*
662 getTextSelection(WScreen *screen, Atom selection)
664 int buffer = -1;
666 switch (selection) {
667 case XA_CUT_BUFFER0:
668 buffer = 0;
669 break;
670 case XA_CUT_BUFFER1:
671 buffer = 1;
672 break;
673 case XA_CUT_BUFFER2:
674 buffer = 2;
675 break;
676 case XA_CUT_BUFFER3:
677 buffer = 3;
678 break;
679 case XA_CUT_BUFFER4:
680 buffer = 4;
681 break;
682 case XA_CUT_BUFFER5:
683 buffer = 5;
684 break;
685 case XA_CUT_BUFFER6:
686 buffer = 6;
687 break;
688 case XA_CUT_BUFFER7:
689 buffer = 7;
690 break;
692 if (buffer >= 0) {
693 char *data;
694 int size;
696 data = XFetchBuffer(dpy, &size, buffer);
698 return data;
699 } else {
700 char *data;
701 int bits;
702 Atom rtype;
703 unsigned long len, bytes;
704 WMHandlerID timer;
705 int timeout = 0;
706 XEvent ev;
707 static Atom clipboard = 0;
709 if (!clipboard)
710 clipboard = XInternAtom(dpy, "CLIPBOARD", False);
712 XDeleteProperty(dpy, screen->info_window, clipboard);
714 XConvertSelection(dpy, selection, XA_STRING,
715 clipboard, screen->info_window,
716 CurrentTime);
718 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
720 while (!XCheckTypedWindowEvent(dpy, screen->info_window,
721 SelectionNotify, &ev) && !timeout);
723 if (!timeout) {
724 WMDeleteTimerHandler(timer);
725 } else {
726 wwarning("selection retrieval timed out");
727 return NULL;
730 /* nobody owns the selection or the current owner has
731 * nothing to do with what we need */
732 if (ev.xselection.property == None) {
733 return NULL;
736 if (XGetWindowProperty(dpy, screen->info_window,
737 clipboard, 0, 1024,
738 False, XA_STRING, &rtype, &bits, &len,
739 &bytes, (unsigned char**)&data)!=Success) {
740 return NULL;
742 if (rtype!=XA_STRING || bits!=8) {
743 wwarning("invalid data in text selection");
744 if (data)
745 XFree(data);
746 return NULL;
748 return data;
752 static char*
753 getselection(WScreen *scr)
755 char *tmp;
757 tmp = getTextSelection(scr, XA_PRIMARY);
758 if (!tmp)
759 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
760 return tmp;
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;
1075 default:
1076 out[optr++]='%';
1077 out[optr++]=cmdline[ptr];
1079 break;
1081 out[optr]=0;
1082 ptr++;
1084 if (selection)
1085 XFree(selection);
1086 return out;
1088 error:
1089 free(out);
1090 if (selection)
1091 XFree(selection);
1092 return NULL;
1096 /* We don't care for upper/lower case in comparing the keys; so we
1097 have to define our own comparison function here */
1098 BOOL
1099 StringCompareHook(proplist_t pl1, proplist_t pl2)
1101 char *str1, *str2;
1103 str1 = PLGetString(pl1);
1104 str2 = PLGetString(pl2);
1106 if (strcasecmp(str1, str2)==0)
1107 return YES;
1108 else
1109 return NO;
1113 /* feof doesn't seem to work on pipes */
1115 IsEof(FILE * stream)
1117 static struct stat stinfo;
1119 fstat(fileno(stream), &stinfo);
1120 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1121 feof(stream));
1125 void
1126 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1128 char *name;
1130 *winstance = *wclass = NULL;
1132 if (!PLIsString(value)) {
1133 wwarning(_("bad window name value in %s state info"), where);
1134 return;
1137 name = PLGetString(value);
1138 if (!name || strlen(name)==0) {
1139 wwarning(_("bad window name value in %s state info"), where);
1140 return;
1143 UnescapeWM_CLASS(name, winstance, wclass);
1147 #if 0
1148 static char*
1149 keysymToString(KeySym keysym, unsigned int state)
1151 XKeyEvent kev;
1152 char *buf = wmalloc(20);
1153 int count;
1155 kev.display = dpy;
1156 kev.type = KeyPress;
1157 kev.send_event = False;
1158 kev.window = DefaultRootWindow(dpy);
1159 kev.root = DefaultRootWindow(dpy);
1160 kev.same_screen = True;
1161 kev.subwindow = kev.root;
1162 kev.serial = 0x12344321;
1163 kev.time = CurrentTime;
1164 kev.state = state;
1165 kev.keycode = XKeysymToKeycode(dpy, keysym);
1166 count = XLookupString(&kev, buf, 19, NULL, NULL);
1167 buf[count] = 0;
1169 return buf;
1171 #endif
1173 static char *
1174 appendrealloc(char *a, char *b)
1176 if (a == NULL)
1177 return wstrdup(b);
1178 else {
1179 char *c = wstrappend(a, b);
1180 free(a);
1181 return c;
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 = appendrealloc(buffer, "M+");
1212 } else if (strcasecmp(text, "Alt")==0) {
1213 buffer = appendrealloc(buffer, "A+");
1214 } else if (strcasecmp(text, "Shift")==0) {
1215 buffer = appendrealloc(buffer, "Sh+");
1216 } else if (strcasecmp(text, "Mod1")==0) {
1217 buffer = appendrealloc(buffer, "M1+");
1218 } else if (strcasecmp(text, "Mod2")==0) {
1219 buffer = appendrealloc(buffer, "M2+");
1220 } else if (strcasecmp(text, "Mod3")==0) {
1221 buffer = appendrealloc(buffer, "M3+");
1222 } else if (strcasecmp(text, "Mod4")==0) {
1223 buffer = appendrealloc(buffer, "M4+");
1224 } else if (strcasecmp(text, "Mod5")==0) {
1225 buffer = appendrealloc(buffer, "M5+");
1226 } else if (strcasecmp(text, "Control")==0) {
1227 control = 1;
1228 } else {
1229 buffer = appendrealloc(buffer, text);
1231 text = k+1;
1234 if (control) {
1235 buffer = appendrealloc(buffer, "^");
1237 buffer = appendrealloc(buffer, text);
1239 /* get key */
1240 /* ksym = XStringToKeysym(text);
1241 tmp = keysymToString(ksym, modmask);
1242 puts(tmp);
1243 buffer = wstrappend(buffer, tmp);
1245 free(tmp);
1247 return buffer;
1251 char*
1252 EscapeWM_CLASS(char *name, char *class)
1254 char *ret;
1255 char *ename = NULL, *eclass = NULL;
1256 int i, j, l;
1258 if (!name && !class)
1259 return NULL;
1261 if (name) {
1262 l = strlen(name);
1263 ename = wmalloc(l*2);
1264 j = 0;
1265 for (i=0; i<l; i++) {
1266 if (name[i]=='\\') {
1267 ename[j++] = '\\';
1268 } else if (name[i]=='.') {
1269 ename[j++] = '\\';
1271 ename[j++] = name[i];
1273 ename[j] = 0;
1275 if (class) {
1276 l = strlen(class);
1277 eclass = wmalloc(l*2);
1278 j = 0;
1279 for (i=0; i<l; i++) {
1280 if (class[i]=='\\') {
1281 eclass[j++] = '\\';
1282 } else if (class[i]=='.') {
1283 eclass[j++] = '\\';
1285 eclass[j++] = class[i];
1287 eclass[j] = 0;
1290 if (ename && eclass) {
1291 ret = wmalloc(strlen(ename)+strlen(eclass)+4);
1292 sprintf(ret, "%s.%s", ename, eclass);
1293 free(ename);
1294 free(eclass);
1295 } else if (ename) {
1296 ret = wstrdup(ename);
1297 free(ename);
1298 } else {
1299 ret = wstrdup(eclass);
1300 free(eclass);
1303 return ret;
1307 void
1308 UnescapeWM_CLASS(char *str, char **name, char **class)
1310 int i, j, k, dot;
1311 Bool esc;
1313 j = strlen(str);
1314 *name = wmalloc(j);
1315 **name = 0;
1316 *class = wmalloc(j);
1317 **class = 0;
1319 /* separate string in 2 parts */
1320 esc = False;
1321 dot = 0;
1322 for (i = 0; i < j; i++) {
1323 if (!esc) {
1324 if (str[i]=='\\') {
1325 esc = True;
1326 } else if (str[i]=='.') {
1327 dot = i;
1328 break;
1330 } else {
1331 esc = False;
1335 /* unescape strings */
1336 esc = False;
1337 k = 0;
1338 for (i = 0; i < dot; i++) {
1339 if (!esc) {
1340 if (str[i]=='\\') {
1341 esc = True;
1342 } else {
1343 (*name)[k++] = str[i];
1345 } else {
1346 (*name)[k++] = str[i];
1347 esc = False;
1350 (*name)[k] = 0;
1352 esc = False;
1353 k = 0;
1354 for (i = dot+1; i<j; i++) {
1355 if (!esc) {
1356 if (str[i]=='\\') {
1357 esc = True;
1358 } else {
1359 (*class)[k++] = str[i];
1361 } else {
1362 esc = False;
1365 (*class)[k] = 0;
1367 if (!*name) {
1368 free(*name);
1369 *name = NULL;
1371 if (!*class) {
1372 free(*class);
1373 *class = NULL;
1379 void
1380 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1382 unsigned char *buffer;
1383 int len;
1384 int i;
1385 char buf[16];
1387 if (!scr->flags.backimage_helper_launched) {
1388 return;
1391 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1392 buffer = wmalloc(len+5);
1393 sprintf(buf, "%4i", len);
1394 memcpy(buffer, buf, 4);
1395 buffer[4] = type;
1396 i = 5;
1397 if (workspace >= 0) {
1398 sprintf(buf, "%4i", workspace);
1399 memcpy(&buffer[i], buf, 4);
1400 i += 4;
1401 buffer[i] = 0;
1403 if (msg)
1404 strcpy(&buffer[i], msg);
1406 if (write(scr->helper_fd, buffer, len+4) < 0) {
1407 wsyserror(_("could not send message to background image helper"));
1409 free(buffer);