updated selection stuff
[wmaker-crm.git] / src / misc.c
blob1abc2909c66089760ceecc21b186ebc2109ef1a3
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 */
206 WWindow*
207 NextToFocusAfter(WWindow *wwin)
209 WWindow *tmp = wwin->prev;
211 while (tmp) {
212 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
213 return tmp;
215 tmp = tmp->prev;
218 tmp = wwin;
219 /* start over from the beginning of the list */
220 while (tmp->next)
221 tmp = tmp->next;
223 while (tmp && tmp != wwin) {
224 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
225 return tmp;
227 tmp = tmp->prev;
230 return wwin;
234 WWindow*
235 NextToFocusBefore(WWindow *wwin)
237 WWindow *tmp = wwin->next;
239 while (tmp) {
240 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
241 return tmp;
243 tmp = tmp->next;
246 /* start over from the beginning of the list */
247 tmp = wwin;
248 while (tmp->prev)
249 tmp = tmp->prev;
251 while (tmp && tmp != wwin) {
252 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
254 return tmp;
256 tmp = tmp->next;
259 return wwin;
263 #if 0
265 * Is win2 below win1?
267 static Bool
268 isBelow(WWindow *win1, WWindow *win2)
270 int i;
271 WCoreWindow *tmp;
273 tmp = win1->frame->core->stacking->under;
274 while (tmp) {
275 if (tmp == win2->frame->core)
276 return True;
277 tmp = tmp->stacking->under;
280 for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
281 tmp = win1->screen_ptr->stacking_list[i];
282 while (tmp) {
283 if (tmp == win2->frame->core)
284 return True;
285 tmp = tmp->stacking->under;
288 return True;
290 #endif
295 * XFetchName Wrapper
298 Bool wFetchName(dpy, win, winname)
299 Display *dpy;
300 Window win;
301 char **winname;
303 XTextProperty text_prop;
304 char **list;
305 int num;
307 if (XGetWMName(dpy, win, &text_prop)) {
308 if (text_prop.value && text_prop.nitems > 0) {
309 if (text_prop.encoding == XA_STRING) {
310 *winname = wstrdup((char *)text_prop.value);
311 XFree(text_prop.value);
312 } else {
313 text_prop.nitems = strlen((char *)text_prop.value);
314 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
315 Success && num > 0 && *list) {
316 XFree(text_prop.value);
317 *winname = wstrdup(*list);
318 XFreeStringList(list);
319 } else {
320 *winname = wstrdup((char *)text_prop.value);
321 XFree(text_prop.value);
324 } else {
325 /* the title is set, but it was set to none */
326 *winname = wstrdup("");
328 return True;
329 } else {
330 /* the hint is probably not set */
331 *winname = NULL;
333 return False;
338 * XGetIconName Wrapper
342 Bool wGetIconName(dpy, win, iconname)
343 Display *dpy;
344 Window win;
345 char **iconname;
347 XTextProperty text_prop;
348 char **list;
349 int num;
351 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
352 && text_prop.nitems > 0) {
353 if (text_prop.encoding == XA_STRING)
354 *iconname = (char *)text_prop.value;
355 else {
356 text_prop.nitems = strlen((char *)text_prop.value);
357 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
358 Success && num > 0 && *list) {
359 XFree(text_prop.value);
360 *iconname = wstrdup(*list);
361 XFreeStringList(list);
362 } else
363 *iconname = (char *)text_prop.value;
365 return True;
367 *iconname = NULL;
368 return False;
372 static void
373 eatExpose()
375 XEvent event, foo;
377 /* compress all expose events into a single one */
379 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
380 /* ignore other exposure events for this window */
381 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
382 &foo));
383 /* eat exposes for other windows */
384 eatExpose();
386 event.xexpose.count = 0;
387 XPutBackEvent(dpy, &event);
392 void
393 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
395 time_t time0 = time(NULL);
396 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
397 int dx_is_bigger=0;
399 /* animation parameters */
400 static struct {
401 int delay;
402 int steps;
403 int slowdown;
404 } apars[5] = {
405 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
406 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
407 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
408 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
409 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
413 dx = (float)(to_x-from_x);
414 dy = (float)(to_y-from_y);
415 sx = (dx == 0 ? 0 : fabs(dx)/dx);
416 sy = (dy == 0 ? 0 : fabs(dy)/dy);
418 if (fabs(dx) > fabs(dy)) {
419 dx_is_bigger = 1;
422 if (dx_is_bigger) {
423 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
424 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
425 px = apars[(int)wPreferences.icon_slide_speed].steps;
426 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
427 px = -apars[(int)wPreferences.icon_slide_speed].steps;
428 py = (sx == 0 ? 0 : px*dy/dx);
429 } else {
430 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
431 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
432 py = apars[(int)wPreferences.icon_slide_speed].steps;
433 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
434 py = -apars[(int)wPreferences.icon_slide_speed].steps;
435 px = (sy == 0 ? 0 : py*dx/dy);
438 while (x != to_x || y != to_y) {
439 x += px;
440 y += py;
441 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
442 x = (float)to_x;
443 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
444 y = (float)to_y;
446 if (dx_is_bigger) {
447 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
448 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
449 px = apars[(int)wPreferences.icon_slide_speed].steps;
450 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
451 px = -apars[(int)wPreferences.icon_slide_speed].steps;
452 py = (sx == 0 ? 0 : px*dy/dx);
453 } else {
454 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
455 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
456 py = apars[(int)wPreferences.icon_slide_speed].steps;
457 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
458 py = -apars[(int)wPreferences.icon_slide_speed].steps;
459 px = (sy == 0 ? 0 : py*dx/dy);
462 XMoveWindow(dpy, win, (int)x, (int)y);
463 XFlush(dpy);
464 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
465 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
467 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
468 break;
470 XMoveWindow(dpy, win, to_x, to_y);
472 XSync(dpy, 0);
473 /* compress expose events */
474 eatExpose();
478 char*
479 ShrinkString(WMFont *font, char *string, int width)
481 int w, w1=0;
482 int p;
483 char *pos;
484 char *text;
485 int p1, p2, t;
487 if (wPreferences.multi_byte_text)
488 return wstrdup(string);
490 p = strlen(string);
491 w = WMWidthOfString(font, string, p);
492 text = wmalloc(strlen(string)+8);
493 strcpy(text, string);
494 if (w<=width)
495 return text;
497 pos = strchr(text, ' ');
498 if (!pos)
499 pos = strchr(text, ':');
501 if (pos) {
502 *pos = 0;
503 p = strlen(text);
504 w1 = WMWidthOfString(font, text, p);
505 if (w1 > width) {
506 w1 = 0;
507 p = 0;
508 *pos = ' ';
509 *text = 0;
510 } else {
511 *pos = 0;
512 width -= w1;
513 p++;
515 string += p;
516 p=strlen(string);
517 } else {
518 *text=0;
520 strcat(text, "...");
521 width -= WMWidthOfString(font, "...", 3);
523 pos = string;
524 p1=0;
525 p2=p;
526 t = (p2-p1)/2;
527 while (p2>p1 && p1!=t) {
528 w = WMWidthOfString(font, &string[p-t], t);
529 if (w>width) {
530 p2 = t;
531 t = p1+(p2-p1)/2;
532 } else if (w<width) {
533 p1 = t;
534 t = p1+(p2-p1)/2;
535 } else
536 p2=p1=t;
538 strcat(text, &string[p-p1]);
540 return text;
544 char*
545 FindImage(char *paths, char *file)
547 char *tmp, *path;
549 tmp = strrchr(file, ':');
550 if (tmp) {
551 *tmp = 0;
552 path = wfindfile(paths, file);
553 *tmp = ':';
555 if (!tmp || !path) {
556 path = wfindfile(paths, file);
559 return path;
563 char*
564 FlattenStringList(char **list, int count)
566 int i, j;
567 char *flat_string, *wspace;
569 j = 0;
570 for (i=0; i<count; i++) {
571 if (list[i]!=NULL && list[i][0]!=0) {
572 j += strlen(list[i]);
573 if (strpbrk(list[i], " \t"))
574 j += 2;
578 flat_string = malloc(j+count+1);
579 if (!flat_string) {
580 return NULL;
583 *flat_string = 0;
584 for (i=0; i<count; i++) {
585 if (list[i]!=NULL && list[i][0]!=0) {
586 if (i>0)
587 strcat(flat_string, " ");
588 wspace = strpbrk(list[i], " \t");
589 if (wspace)
590 strcat(flat_string, "\"");
591 strcat(flat_string, list[i]);
592 if (wspace)
593 strcat(flat_string, "\"");
597 return flat_string;
603 *----------------------------------------------------------------------
604 * ParseCommand --
605 * Divides a command line into a argv/argc pair.
606 *----------------------------------------------------------------------
608 #define PRC_ALPHA 0
609 #define PRC_BLANK 1
610 #define PRC_ESCAPE 2
611 #define PRC_DQUOTE 3
612 #define PRC_EOS 4
613 #define PRC_SQUOTE 5
615 typedef struct {
616 short nstate;
617 short output;
618 } DFA;
621 static DFA mtable[9][6] = {
622 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
623 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
624 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
625 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
626 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
627 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
628 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
629 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
630 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
633 char*
634 next_token(char *word, char **next)
636 char *ptr;
637 char *ret, *t;
638 int state, ctype;
640 t = ret = wmalloc(strlen(word)+1);
641 ptr = word;
643 state = 0;
644 *t = 0;
645 while (1) {
646 if (*ptr==0)
647 ctype = PRC_EOS;
648 else if (*ptr=='\\')
649 ctype = PRC_ESCAPE;
650 else if (*ptr=='"')
651 ctype = PRC_DQUOTE;
652 else if (*ptr=='\'')
653 ctype = PRC_SQUOTE;
654 else if (*ptr==' ' || *ptr=='\t')
655 ctype = PRC_BLANK;
656 else
657 ctype = PRC_ALPHA;
659 if (mtable[state][ctype].output) {
660 *t = *ptr; t++;
661 *t = 0;
663 state = mtable[state][ctype].nstate;
664 ptr++;
665 if (mtable[state][0].output<0) {
666 break;
670 if (*ret==0)
671 t = NULL;
672 else
673 t = wstrdup(ret);
675 free(ret);
677 if (ctype==PRC_EOS)
678 *next = NULL;
679 else
680 *next = ptr;
682 return t;
686 void
687 ParseCommand(char *command, char ***argv, int *argc)
689 WMBag *bag = WMCreateBag(4);
690 char *token, *line;
691 int count, j;
693 line = command;
694 do {
695 token = next_token(line, &line);
696 if (token) {
697 WMPutInBag(bag, token);
699 } while (token!=NULL && line!=NULL);
701 count = WMGetBagItemCount(bag);
702 *argv = wmalloc(sizeof(char*)*count);
703 for (j = 0; j < count; j++) {
704 (*argv)[j] = WMGetFromBag(bag, j);
706 *argc = count;
708 WMFreeBag(bag);
712 static void
713 timeoutHandler(void *data)
715 *(int*)data = 1;
719 static char*
720 getTextSelection(WScreen *screen, Atom selection)
722 int buffer = -1;
724 switch (selection) {
725 case XA_CUT_BUFFER0:
726 buffer = 0;
727 break;
728 case XA_CUT_BUFFER1:
729 buffer = 1;
730 break;
731 case XA_CUT_BUFFER2:
732 buffer = 2;
733 break;
734 case XA_CUT_BUFFER3:
735 buffer = 3;
736 break;
737 case XA_CUT_BUFFER4:
738 buffer = 4;
739 break;
740 case XA_CUT_BUFFER5:
741 buffer = 5;
742 break;
743 case XA_CUT_BUFFER6:
744 buffer = 6;
745 break;
746 case XA_CUT_BUFFER7:
747 buffer = 7;
748 break;
750 if (buffer >= 0) {
751 char *data;
752 int size;
754 data = XFetchBuffer(dpy, &size, buffer);
756 return data;
757 } else {
758 char *data;
759 int bits;
760 Atom rtype;
761 unsigned long len, bytes;
762 WMHandlerID timer;
763 int timeout = 0;
764 XEvent ev;
765 static Atom clipboard = 0;
767 if (!clipboard)
768 clipboard = XInternAtom(dpy, "CLIPBOARD", False);
770 XDeleteProperty(dpy, screen->info_window, clipboard);
772 XConvertSelection(dpy, selection, XA_STRING,
773 clipboard, screen->info_window,
774 CurrentTime);
776 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
778 while (!XCheckTypedWindowEvent(dpy, screen->info_window,
779 SelectionNotify, &ev) && !timeout);
781 if (!timeout) {
782 WMDeleteTimerHandler(timer);
783 } else {
784 wwarning("selection retrieval timed out");
785 return NULL;
788 /* nobody owns the selection or the current owner has
789 * nothing to do with what we need */
790 if (ev.xselection.property == None) {
791 return NULL;
794 if (XGetWindowProperty(dpy, screen->info_window,
795 clipboard, 0, 1024,
796 False, XA_STRING, &rtype, &bits, &len,
797 &bytes, (unsigned char**)&data)!=Success) {
798 return NULL;
800 if (rtype!=XA_STRING || bits!=8) {
801 wwarning("invalid data in text selection");
802 if (data)
803 XFree(data);
804 return NULL;
806 return data;
810 static char*
811 getselection(WScreen *scr)
813 char *tmp;
815 tmp = getTextSelection(scr, XA_PRIMARY);
816 if (!tmp)
817 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
818 return tmp;
822 static char*
823 getuserinput(WScreen *scr, char *line, int *ptr)
825 char *ret;
826 char *title;
827 char *prompt;
828 int j, state;
829 int begin = 0;
830 char tbuffer[256], pbuffer[256];
832 title = _("Program Arguments");
833 prompt = _("Enter command arguments:");
834 ret = NULL;
836 #define _STARTING 0
837 #define _TITLE 1
838 #define _PROMPT 2
839 #define _DONE 3
841 state = _STARTING;
842 j = 0;
843 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
844 switch (state) {
845 case _STARTING:
846 if (line[*ptr]=='(') {
847 state = _TITLE;
848 begin = *ptr+1;
849 } else {
850 state = _DONE;
852 break;
854 case _TITLE:
855 if (j <= 0 && line[*ptr]==',') {
857 j = 0;
858 if (*ptr > begin) {
859 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
860 tbuffer[WMIN(*ptr-begin, 255)] = 0;
861 title = (char*)tbuffer;
863 begin = *ptr+1;
864 state = _PROMPT;
866 } else if (j <= 0 && line[*ptr]==')') {
868 if (*ptr > begin) {
869 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
870 tbuffer[WMIN(*ptr-begin, 255)] = 0;
871 title = (char*)tbuffer;
873 state = _DONE;
875 } else if (line[*ptr]=='(') {
876 j++;
877 } else if (line[*ptr]==')') {
878 j--;
881 break;
883 case _PROMPT:
884 if (line[*ptr]==')' && j==0) {
886 if (*ptr-begin > 1) {
887 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255));
888 pbuffer[WMIN(*ptr-begin, 255)] = 0;
889 prompt = (char*)pbuffer;
891 state = _DONE;
892 } else if (line[*ptr]=='(')
893 j++;
894 else if (line[*ptr]==')')
895 j--;
896 break;
899 (*ptr)--;
900 #undef _STARTING
901 #undef _TITLE
902 #undef _PROMPT
903 #undef _DONE
905 if (!wInputDialog(scr, title, prompt, &ret))
906 return NULL;
907 else
908 return ret;
912 #ifdef OFFIX_DND
913 static char*
914 get_dnd_selection(WScreen *scr)
916 XTextProperty text_ret;
917 int result;
918 char **list;
919 char *flat_string;
920 int count;
922 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
924 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
925 || text_ret.format==0 || text_ret.nitems == 0) {
926 wwarning(_("unable to get dropped data from DND drop"));
927 return NULL;
930 XTextPropertyToStringList(&text_ret, &list, &count);
932 if (!list || count<1) {
933 XFree(text_ret.value);
934 wwarning(_("error getting dropped data from DND drop"));
935 return NULL;
938 flat_string = FlattenStringList(list, count);
939 if (!flat_string) {
940 wwarning(_("out of memory while getting data from DND drop"));
943 XFreeStringList(list);
944 XFree(text_ret.value);
945 return flat_string;
947 #endif /* OFFIX_DND */
950 #define S_NORMAL 0
951 #define S_ESCAPE 1
952 #define S_OPTION 2
955 * state input new-state output
956 * NORMAL % OPTION <nil>
957 * NORMAL \ ESCAPE <nil>
958 * NORMAL etc. NORMAL <input>
959 * ESCAPE any NORMAL <input>
960 * OPTION s NORMAL <selection buffer>
961 * OPTION w NORMAL <selected window id>
962 * OPTION a NORMAL <input text>
963 * OPTION d NORMAL <OffiX DND selection object>
964 * OPTION W NORMAL <current workspace>
965 * OPTION etc. NORMAL %<input>
967 #define TMPBUFSIZE 64
968 char*
969 ExpandOptions(WScreen *scr, char *cmdline)
971 int ptr, optr, state, len, olen;
972 char *out, *nout;
973 char *selection=NULL;
974 char *user_input=NULL;
975 #if defined(OFFIX_DND) || defined(XDND)
976 char *dropped_thing=NULL;
977 #endif
978 char tmpbuf[TMPBUFSIZE];
979 int slen;
981 len = strlen(cmdline);
982 olen = len+1;
983 out = malloc(olen);
984 if (!out) {
985 wwarning(_("out of memory during expansion of \"%s\""));
986 return NULL;
988 *out = 0;
989 ptr = 0; /* input line pointer */
990 optr = 0; /* output line pointer */
991 state = S_NORMAL;
992 while (ptr < len) {
993 switch (state) {
994 case S_NORMAL:
995 switch (cmdline[ptr]) {
996 case '\\':
997 state = S_ESCAPE;
998 break;
999 case '%':
1000 state = S_OPTION;
1001 break;
1002 default:
1003 state = S_NORMAL;
1004 out[optr++]=cmdline[ptr];
1005 break;
1007 break;
1008 case S_ESCAPE:
1009 switch (cmdline[ptr]) {
1010 case 'n':
1011 out[optr++]=10;
1012 break;
1014 case 'r':
1015 out[optr++]=13;
1016 break;
1018 case 't':
1019 out[optr++]=9;
1020 break;
1022 default:
1023 out[optr++]=cmdline[ptr];
1025 state = S_NORMAL;
1026 break;
1027 case S_OPTION:
1028 state = S_NORMAL;
1029 switch (cmdline[ptr]) {
1030 case 'w':
1031 if (scr->focused_window
1032 && scr->focused_window->flags.focused) {
1033 sprintf(tmpbuf, "0x%x",
1034 (unsigned int)scr->focused_window->client_win);
1035 slen = strlen(tmpbuf);
1036 olen += slen;
1037 nout = realloc(out,olen);
1038 if (!nout) {
1039 wwarning(_("out of memory during expansion of \"%w\""));
1040 goto error;
1042 out = nout;
1043 strcat(out,tmpbuf);
1044 optr+=slen;
1045 } else {
1046 out[optr++]=' ';
1048 break;
1050 case 'W':
1051 sprintf(tmpbuf, "0x%x",
1052 (unsigned int)scr->current_workspace + 1);
1053 slen = strlen(tmpbuf);
1054 olen += slen;
1055 nout = realloc(out,olen);
1056 if (!nout) {
1057 wwarning(_("out of memory during expansion of \"%W\""));
1058 goto error;
1060 out = nout;
1061 strcat(out,tmpbuf);
1062 optr+=slen;
1063 break;
1065 case 'a':
1066 ptr++;
1067 user_input = getuserinput(scr, cmdline, &ptr);
1068 if (user_input) {
1069 slen = strlen(user_input);
1070 olen += slen;
1071 nout = realloc(out,olen);
1072 if (!nout) {
1073 wwarning(_("out of memory during expansion of \"%a\""));
1074 goto error;
1076 out = nout;
1077 strcat(out,user_input);
1078 optr+=slen;
1079 } else {
1080 /* Not an error, but user has Canceled the dialog box.
1081 * This will make the command to not be performed. */
1082 goto error;
1084 break;
1086 #if defined(OFFIX_DND) || defined(XDND)
1087 case 'd':
1088 #ifdef XDND
1089 if(scr->xdestring) {
1090 dropped_thing = wstrdup(scr->xdestring);
1092 #endif
1093 if (!dropped_thing) {
1094 dropped_thing = get_dnd_selection(scr);
1096 if (!dropped_thing) {
1097 scr->flags.dnd_data_convertion_status = 1;
1098 goto error;
1100 slen = strlen(dropped_thing);
1101 olen += slen;
1102 nout = realloc(out,olen);
1103 if (!nout) {
1104 wwarning(_("out of memory during expansion of \"%d\""));
1105 goto error;
1107 out = nout;
1108 strcat(out,dropped_thing);
1109 optr+=slen;
1110 break;
1111 #endif /* OFFIX_DND */
1113 case 's':
1114 if (!selection) {
1115 selection = getselection(scr);
1117 if (!selection) {
1118 wwarning(_("selection not available"));
1119 goto error;
1121 slen = strlen(selection);
1122 olen += slen;
1123 nout = realloc(out,olen);
1124 if (!nout) {
1125 wwarning(_("out of memory during expansion of \"%s\""));
1126 goto error;
1128 out = nout;
1129 strcat(out,selection);
1130 optr+=slen;
1131 break;
1133 default:
1134 out[optr++]='%';
1135 out[optr++]=cmdline[ptr];
1137 break;
1139 out[optr]=0;
1140 ptr++;
1142 if (selection)
1143 XFree(selection);
1144 return out;
1146 error:
1147 free(out);
1148 if (selection)
1149 XFree(selection);
1150 return NULL;
1154 /* We don't care for upper/lower case in comparing the keys; so we
1155 have to define our own comparison function here */
1156 BOOL
1157 StringCompareHook(proplist_t pl1, proplist_t pl2)
1159 char *str1, *str2;
1161 str1 = PLGetString(pl1);
1162 str2 = PLGetString(pl2);
1164 if (strcasecmp(str1, str2)==0)
1165 return YES;
1166 else
1167 return NO;
1171 /* feof doesn't seem to work on pipes */
1173 IsEof(FILE * stream)
1175 static struct stat stinfo;
1177 fstat(fileno(stream), &stinfo);
1178 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1179 feof(stream));
1183 void
1184 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1186 char *name;
1188 *winstance = *wclass = NULL;
1190 if (!PLIsString(value)) {
1191 wwarning(_("bad window name value in %s state info"), where);
1192 return;
1195 name = PLGetString(value);
1196 if (!name || strlen(name)==0) {
1197 wwarning(_("bad window name value in %s state info"), where);
1198 return;
1201 UnescapeWM_CLASS(name, winstance, wclass);
1205 #if 0
1206 static char*
1207 keysymToString(KeySym keysym, unsigned int state)
1209 XKeyEvent kev;
1210 char *buf = wmalloc(20);
1211 int count;
1213 kev.display = dpy;
1214 kev.type = KeyPress;
1215 kev.send_event = False;
1216 kev.window = DefaultRootWindow(dpy);
1217 kev.root = DefaultRootWindow(dpy);
1218 kev.same_screen = True;
1219 kev.subwindow = kev.root;
1220 kev.serial = 0x12344321;
1221 kev.time = CurrentTime;
1222 kev.state = state;
1223 kev.keycode = XKeysymToKeycode(dpy, keysym);
1224 count = XLookupString(&kev, buf, 19, NULL, NULL);
1225 buf[count] = 0;
1227 return buf;
1229 #endif
1231 static char *
1232 appendrealloc(char *a, char *b)
1234 if (a == NULL)
1235 return wstrdup(b);
1236 else {
1237 char *c = wstrappend(a, b);
1238 free(a);
1239 return c;
1244 char*
1245 GetShortcutString(char *text)
1247 char *buffer = NULL;
1248 char *k;
1249 int modmask = 0;
1250 /* KeySym ksym;*/
1251 int control = 0;
1252 char *tmp;
1254 tmp = text = wstrdup(text);
1256 /* get modifiers */
1257 while ((k = strchr(text, '+'))!=NULL) {
1258 int mod;
1260 *k = 0;
1261 mod = wXModifierFromKey(text);
1262 if (mod<0) {
1263 return wstrdup("bug");
1266 modmask |= mod;
1268 if (strcasecmp(text, "Meta")==0) {
1269 buffer = appendrealloc(buffer, "M+");
1270 } else if (strcasecmp(text, "Alt")==0) {
1271 buffer = appendrealloc(buffer, "A+");
1272 } else if (strcasecmp(text, "Shift")==0) {
1273 buffer = appendrealloc(buffer, "Sh+");
1274 } else if (strcasecmp(text, "Mod1")==0) {
1275 buffer = appendrealloc(buffer, "M1+");
1276 } else if (strcasecmp(text, "Mod2")==0) {
1277 buffer = appendrealloc(buffer, "M2+");
1278 } else if (strcasecmp(text, "Mod3")==0) {
1279 buffer = appendrealloc(buffer, "M3+");
1280 } else if (strcasecmp(text, "Mod4")==0) {
1281 buffer = appendrealloc(buffer, "M4+");
1282 } else if (strcasecmp(text, "Mod5")==0) {
1283 buffer = appendrealloc(buffer, "M5+");
1284 } else if (strcasecmp(text, "Control")==0) {
1285 control = 1;
1286 } else {
1287 buffer = appendrealloc(buffer, text);
1289 text = k+1;
1292 if (control) {
1293 buffer = appendrealloc(buffer, "^");
1295 buffer = appendrealloc(buffer, text);
1297 /* get key */
1298 /* ksym = XStringToKeysym(text);
1299 tmp = keysymToString(ksym, modmask);
1300 puts(tmp);
1301 buffer = wstrappend(buffer, tmp);
1303 free(tmp);
1305 return buffer;
1309 char*
1310 EscapeWM_CLASS(char *name, char *class)
1312 char *ret;
1313 char *ename = NULL, *eclass = NULL;
1314 int i, j, l;
1316 if (!name && !class)
1317 return NULL;
1319 if (name) {
1320 l = strlen(name);
1321 ename = wmalloc(l*2);
1322 j = 0;
1323 for (i=0; i<l; i++) {
1324 if (name[i]=='\\') {
1325 ename[j++] = '\\';
1326 } else if (name[i]=='.') {
1327 ename[j++] = '\\';
1329 ename[j++] = name[i];
1331 ename[j] = 0;
1333 if (class) {
1334 l = strlen(class);
1335 eclass = wmalloc(l*2);
1336 j = 0;
1337 for (i=0; i<l; i++) {
1338 if (class[i]=='\\') {
1339 eclass[j++] = '\\';
1340 } else if (class[i]=='.') {
1341 eclass[j++] = '\\';
1343 eclass[j++] = class[i];
1345 eclass[j] = 0;
1348 if (ename && eclass) {
1349 ret = wmalloc(strlen(ename)+strlen(eclass)+4);
1350 sprintf(ret, "%s.%s", ename, eclass);
1351 free(ename);
1352 free(eclass);
1353 } else if (ename) {
1354 ret = wstrdup(ename);
1355 free(ename);
1356 } else {
1357 ret = wstrdup(eclass);
1358 free(eclass);
1361 return ret;
1365 void
1366 UnescapeWM_CLASS(char *str, char **name, char **class)
1368 int i, j, k, dot;
1369 Bool esc;
1371 j = strlen(str);
1372 *name = wmalloc(j);
1373 **name = 0;
1374 *class = wmalloc(j);
1375 **class = 0;
1377 /* separate string in 2 parts */
1378 esc = False;
1379 dot = 0;
1380 for (i = 0; i < j; i++) {
1381 if (!esc) {
1382 if (str[i]=='\\') {
1383 esc = True;
1384 } else if (str[i]=='.') {
1385 dot = i;
1386 break;
1388 } else {
1389 esc = False;
1393 /* unescape strings */
1394 esc = False;
1395 k = 0;
1396 for (i = 0; i < dot; i++) {
1397 if (!esc) {
1398 if (str[i]=='\\') {
1399 esc = True;
1400 } else {
1401 (*name)[k++] = str[i];
1403 } else {
1404 (*name)[k++] = str[i];
1405 esc = False;
1408 (*name)[k] = 0;
1410 esc = False;
1411 k = 0;
1412 for (i = dot+1; i<j; i++) {
1413 if (!esc) {
1414 if (str[i]=='\\') {
1415 esc = True;
1416 } else {
1417 (*class)[k++] = str[i];
1419 } else {
1420 esc = False;
1423 (*class)[k] = 0;
1425 if (!*name) {
1426 free(*name);
1427 *name = NULL;
1429 if (!*class) {
1430 free(*class);
1431 *class = NULL;
1437 void
1438 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1440 unsigned char *buffer;
1441 int len;
1442 int i;
1443 char buf[16];
1445 if (!scr->flags.backimage_helper_launched) {
1446 return;
1449 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1450 buffer = wmalloc(len+5);
1451 sprintf(buf, "%4i", len);
1452 memcpy(buffer, buf, 4);
1453 buffer[4] = type;
1454 i = 5;
1455 if (workspace >= 0) {
1456 sprintf(buf, "%4i", workspace);
1457 memcpy(&buffer[i], buf, 4);
1458 i += 4;
1459 buffer[i] = 0;
1461 if (msg)
1462 strcpy(&buffer[i], msg);
1464 if (write(scr->helper_fd, buffer, len+4) < 0) {
1465 wsyserror(_("could not send message to background image helper"));
1467 free(buffer);