changes related to plugin system & drawstring
[wmaker-crm.git] / src / misc.c
blob8dedb270d7853bb836d80609a82f104ce6fc6a28
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"
51 #include "plugin.h"
54 /**** global variables *****/
56 extern char *DisplayName;
58 extern WPreferences wPreferences;
60 extern Time LastTimestamp;
62 #ifdef OFFIX_DND
63 extern Atom _XA_DND_SELECTION;
64 #endif
67 #ifdef USECPP
68 static void
69 putdef(char *line, char *name, char *value)
71 if (!value) {
72 wwarning(_("could not define value for %s for cpp"), name);
73 return;
75 strcat(line, name);
76 strcat(line, value);
81 static void
82 putidef(char *line, char *name, int value)
84 char tmp[64];
85 sprintf(tmp, "%i", value);
86 strcat(line, name);
87 strcat(line, tmp);
91 static char*
92 username()
94 char *tmp;
96 tmp = getlogin();
97 if (!tmp) {
98 struct passwd *user;
100 user = getpwuid(getuid());
101 if (!user) {
102 wsyserror(_("could not get password entry for UID %i"), getuid());
103 return NULL;
105 if (!user->pw_name) {
106 return NULL;
107 } else {
108 return user->pw_name;
111 return tmp;
114 char *
115 MakeCPPArgs(char *path)
117 int i;
118 char buffer[MAXLINE], *buf, *line;
119 Visual *visual;
120 char *tmp;
122 line = wmalloc(MAXLINE);
123 *line = 0;
124 i=1;
125 if ((buf=getenv("HOSTNAME"))!=NULL) {
126 if (buf[0]=='(') {
127 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"),
128 buf);
129 } else
130 putdef(line, " -DHOST=", buf);
131 } else if ((buf=getenv("HOST"))!=NULL) {
132 if (buf[0]=='(') {
133 wwarning(_("your machine is misconfigured. HOST is set to %s"),
134 buf);
135 } else
136 putdef(line, " -DHOST=", buf);
138 buf = username();
139 if (buf)
140 putdef(line, " -DUSER=", buf);
141 putidef(line, " -DUID=", getuid());
142 buf = XDisplayName(DisplayString(dpy));
143 putdef(line, " -DDISPLAY=", buf);
144 putdef(line, " -DWM_VERSION=", VERSION);
146 visual = DefaultVisual(dpy, DefaultScreen(dpy));
147 putidef(line, " -DVISUAL=", visual->class);
149 putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy)));
151 putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy)));
152 putidef(line, " -DSCR_HEIGHT=",
153 HeightOfScreen(DefaultScreenOfDisplay(dpy)));
155 /* put the dir where the menu is being read from to the
156 * search path */
157 if (path) {
158 tmp = wstrdup(path);
159 buf = strchr(tmp+1, ' ');
160 if (buf) {
161 *buf = 0;
163 buf = strrchr(tmp, '/');
164 if (buf) {
165 *buf = 0; /* trunc filename */
166 putdef(line, " -I", tmp);
168 wfree(tmp);
172 /* this should be done just once, but it works this way */
173 strcpy(buffer, DEF_CONFIG_PATHS);
174 buf = strtok(buffer, ":");
176 do {
177 char fullpath[MAXLINE];
179 if (buf[0]!='~') {
180 strcpy(fullpath, buf);
181 } else {
182 char * wgethomedir();
183 /* home is statically allocated. Don't free it! */
184 char *home = wgethomedir();
186 strcpy(fullpath, home);
187 strcat(fullpath, &(buf[1]));
190 putdef(line, " -I", fullpath);
192 } while ((buf = strtok(NULL, ":"))!=NULL);
194 #undef arg
195 #ifdef DEBUG
196 puts("CPP ARGS");
197 puts(line);
198 #endif
199 return line;
201 #endif /* USECPP */
206 #if 0
208 * Is win2 below win1?
210 static Bool
211 isBelow(WWindow *win1, WWindow *win2)
213 int i;
214 WCoreWindow *tmp;
216 tmp = win1->frame->core->stacking->under;
217 while (tmp) {
218 if (tmp == win2->frame->core)
219 return True;
220 tmp = tmp->stacking->under;
223 for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
224 tmp = win1->screen_ptr->stacking_list[i];
225 while (tmp) {
226 if (tmp == win2->frame->core)
227 return True;
228 tmp = tmp->stacking->under;
231 return True;
233 #endif
238 * XFetchName Wrapper
241 Bool
242 wFetchName(dpy, win, winname)
243 Display *dpy;
244 Window win;
245 char **winname;
247 XTextProperty text_prop;
248 char **list;
249 int num;
251 if (XGetWMName(dpy, win, &text_prop)) {
252 if (text_prop.value && text_prop.nitems > 0) {
253 if (text_prop.encoding == XA_STRING) {
254 *winname = wstrdup((char *)text_prop.value);
255 XFree(text_prop.value);
256 } else {
257 text_prop.nitems = strlen((char *)text_prop.value);
258 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
259 Success && num > 0 && *list) {
260 XFree(text_prop.value);
261 *winname = wstrdup(*list);
262 XFreeStringList(list);
263 } else {
264 *winname = wstrdup((char *)text_prop.value);
265 XFree(text_prop.value);
268 } else {
269 /* the title is set, but it was set to none */
270 *winname = wstrdup("");
272 return True;
273 } else {
274 /* the hint is probably not set */
275 *winname = NULL;
277 return False;
282 * XGetIconName Wrapper
286 Bool
287 wGetIconName(dpy, win, iconname)
288 Display *dpy;
289 Window win;
290 char **iconname;
292 XTextProperty text_prop;
293 char **list;
294 int num;
296 if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
297 && text_prop.nitems > 0) {
298 if (text_prop.encoding == XA_STRING)
299 *iconname = (char *)text_prop.value;
300 else {
301 text_prop.nitems = strlen((char *)text_prop.value);
302 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
303 Success && num > 0 && *list) {
304 XFree(text_prop.value);
305 *iconname = wstrdup(*list);
306 XFreeStringList(list);
307 } else
308 *iconname = (char *)text_prop.value;
310 return True;
312 *iconname = NULL;
313 return False;
317 static void
318 eatExpose()
320 XEvent event, foo;
322 /* compress all expose events into a single one */
324 if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
325 /* ignore other exposure events for this window */
326 while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
327 &foo));
328 /* eat exposes for other windows */
329 eatExpose();
331 event.xexpose.count = 0;
332 XPutBackEvent(dpy, &event);
337 void
338 SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
340 time_t time0 = time(NULL);
341 float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
342 int dx_is_bigger=0;
344 /* animation parameters */
345 static struct {
346 int delay;
347 int steps;
348 int slowdown;
349 } apars[5] = {
350 {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
351 {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
352 {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
353 {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
354 {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
358 dx = (float)(to_x-from_x);
359 dy = (float)(to_y-from_y);
360 sx = (dx == 0 ? 0 : fabs(dx)/dx);
361 sy = (dy == 0 ? 0 : fabs(dy)/dy);
363 if (fabs(dx) > fabs(dy)) {
364 dx_is_bigger = 1;
367 if (dx_is_bigger) {
368 px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
369 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
370 px = apars[(int)wPreferences.icon_slide_speed].steps;
371 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
372 px = -apars[(int)wPreferences.icon_slide_speed].steps;
373 py = (sx == 0 ? 0 : px*dy/dx);
374 } else {
375 py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
376 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
377 py = apars[(int)wPreferences.icon_slide_speed].steps;
378 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
379 py = -apars[(int)wPreferences.icon_slide_speed].steps;
380 px = (sy == 0 ? 0 : py*dx/dy);
383 while (x != to_x || y != to_y) {
384 x += px;
385 y += py;
386 if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
387 x = (float)to_x;
388 if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
389 y = (float)to_y;
391 if (dx_is_bigger) {
392 px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
393 if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
394 px = apars[(int)wPreferences.icon_slide_speed].steps;
395 else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
396 px = -apars[(int)wPreferences.icon_slide_speed].steps;
397 py = (sx == 0 ? 0 : px*dy/dx);
398 } else {
399 py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
400 if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
401 py = apars[(int)wPreferences.icon_slide_speed].steps;
402 else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
403 py = -apars[(int)wPreferences.icon_slide_speed].steps;
404 px = (sy == 0 ? 0 : py*dx/dy);
407 XMoveWindow(dpy, win, (int)x, (int)y);
408 XFlush(dpy);
409 if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
410 wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
412 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
413 break;
415 XMoveWindow(dpy, win, to_x, to_y);
417 XSync(dpy, 0);
418 /* compress expose events */
419 eatExpose();
423 char*
424 #ifdef DRAWSTRING_PLUGIN
425 ShrinkString(WMFont *font, char *string, int width, WFunction *func)
426 #else
427 ShrinkString(WMFont *font, char *string, int width)
428 #endif
430 int w, w1=0;
431 int p;
432 char *pos;
433 char *text;
434 int p1, p2, t;
435 #ifdef DRAWSTRING_PLUGIN
436 WPluginData *pd;
437 #endif
439 if (wPreferences.multi_byte_text)
440 return wstrdup(string);
442 p = strlen(string);
443 #ifdef DRAWSTRING_PLUGIN
444 if (func) {
445 pd = wPluginPackData(1, func->data);
446 func->proc.widthOfString[W_DSPROC_WIDTHOFSTRING](
447 string, strlen(string), pd, &w, NULL, NULL);
448 } else w = WMWidthOfString(font, string, p);
449 #else
450 w = WMWidthOfString(font, string, p);
451 #endif
452 text = wmalloc(strlen(string)+8);
453 strcpy(text, string);
454 if (w<=width)
455 #ifdef DRAWSTRING_PLUGIN
457 if (func) wfree(pd);
458 return text;
460 #else
461 return text;
462 #endif
464 pos = strchr(text, ' ');
465 if (!pos)
466 pos = strchr(text, ':');
468 if (pos) {
469 *pos = 0;
470 p = strlen(text);
471 #ifdef DRAWSTRING_PLUGIN
472 if (func) {
473 func->proc.widthOfString[W_DSPROC_WIDTHOFSTRING](
474 text, strlen(text), pd, &w1, NULL, NULL);
475 } else w1 = WMWidthOfString(font, text, p);
476 #else
477 w1 = WMWidthOfString(font, text, p);
478 #endif
479 if (w1 > width) {
480 w1 = 0;
481 p = 0;
482 *pos = ' ';
483 *text = 0;
484 } else {
485 *pos = 0;
486 width -= w1;
487 p++;
489 string += p;
490 p=strlen(string);
491 } else {
492 *text=0;
494 strcat(text, "...");
495 #ifdef DRAWSTRING_PLUGIN
496 if (func) {
497 func->proc.widthOfString[W_DSPROC_WIDTHOFSTRING](
498 "...", 3, pd, &w1, NULL, NULL);
499 } else w1 = WMWidthOfString(font, "...", 3);
500 width -= w1;
501 #else
502 width -= WMWidthOfString(font, "...", 3);
503 #endif
504 pos = string;
505 p1=0;
506 p2=p;
507 t = (p2-p1)/2;
508 while (p2>p1 && p1!=t) {
509 #ifdef DRAWSTRING_PLUGIN
510 if (func) {
511 func->proc.widthOfString[W_DSPROC_WIDTHOFSTRING](
512 &string[p-t], t, pd, &w, NULL, NULL);
513 } else w = WMWidthOfString(font, &string[p-t], t);
514 #else
515 w = WMWidthOfString(font, &string[p-t], t);
516 #endif
517 if (w>width) {
518 p2 = t;
519 t = p1+(p2-p1)/2;
520 } else if (w<width) {
521 p1 = t;
522 t = p1+(p2-p1)/2;
523 } else
524 p2=p1=t;
526 #ifdef DRAWSTRING_PLUGIN
527 if (func) wfree(pd);
528 #endif
529 strcat(text, &string[p-p1]);
531 return text;
535 char*
536 FindImage(char *paths, char *file)
538 char *tmp, *path;
540 tmp = strrchr(file, ':');
541 if (tmp) {
542 *tmp = 0;
543 path = wfindfile(paths, file);
544 *tmp = ':';
546 if (!tmp || !path) {
547 path = wfindfile(paths, file);
550 return path;
554 static void
555 timeoutHandler(void *data)
557 *(int*)data = 1;
561 static char*
562 getTextSelection(WScreen *screen, Atom selection)
564 int buffer = -1;
566 switch (selection) {
567 case XA_CUT_BUFFER0:
568 buffer = 0;
569 break;
570 case XA_CUT_BUFFER1:
571 buffer = 1;
572 break;
573 case XA_CUT_BUFFER2:
574 buffer = 2;
575 break;
576 case XA_CUT_BUFFER3:
577 buffer = 3;
578 break;
579 case XA_CUT_BUFFER4:
580 buffer = 4;
581 break;
582 case XA_CUT_BUFFER5:
583 buffer = 5;
584 break;
585 case XA_CUT_BUFFER6:
586 buffer = 6;
587 break;
588 case XA_CUT_BUFFER7:
589 buffer = 7;
590 break;
592 if (buffer >= 0) {
593 char *data;
594 int size;
596 data = XFetchBuffer(dpy, &size, buffer);
598 return data;
599 } else {
600 char *data;
601 int bits;
602 Atom rtype;
603 unsigned long len, bytes;
604 WMHandlerID timer;
605 int timeout = 0;
606 XEvent ev;
607 static Atom clipboard = 0;
609 if (!clipboard)
610 clipboard = XInternAtom(dpy, "CLIPBOARD", False);
612 XDeleteProperty(dpy, screen->info_window, clipboard);
614 XConvertSelection(dpy, selection, XA_STRING,
615 clipboard, screen->info_window,
616 CurrentTime);
618 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
620 while (!XCheckTypedWindowEvent(dpy, screen->info_window,
621 SelectionNotify, &ev) && !timeout);
623 if (!timeout) {
624 WMDeleteTimerHandler(timer);
625 } else {
626 wwarning("selection retrieval timed out");
627 return NULL;
630 /* nobody owns the selection or the current owner has
631 * nothing to do with what we need */
632 if (ev.xselection.property == None) {
633 return NULL;
636 if (XGetWindowProperty(dpy, screen->info_window,
637 clipboard, 0, 1024,
638 False, XA_STRING, &rtype, &bits, &len,
639 &bytes, (unsigned char**)&data)!=Success) {
640 return NULL;
642 if (rtype!=XA_STRING || bits!=8) {
643 wwarning("invalid data in text selection");
644 if (data)
645 XFree(data);
646 return NULL;
648 return data;
652 static char*
653 getselection(WScreen *scr)
655 char *tmp;
657 tmp = getTextSelection(scr, XA_PRIMARY);
658 if (!tmp)
659 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
660 return tmp;
664 static char*
665 getuserinput(WScreen *scr, char *line, int *ptr)
667 char *ret;
668 char *title;
669 char *prompt;
670 int j, state;
671 int begin = 0;
672 char tbuffer[256], pbuffer[256];
674 title = _("Program Arguments");
675 prompt = _("Enter command arguments:");
676 ret = NULL;
678 #define _STARTING 0
679 #define _TITLE 1
680 #define _PROMPT 2
681 #define _DONE 3
683 state = _STARTING;
684 j = 0;
685 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
686 switch (state) {
687 case _STARTING:
688 if (line[*ptr]=='(') {
689 state = _TITLE;
690 begin = *ptr+1;
691 } else {
692 state = _DONE;
694 break;
696 case _TITLE:
697 if (j <= 0 && line[*ptr]==',') {
699 j = 0;
700 if (*ptr > begin) {
701 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
702 tbuffer[WMIN(*ptr-begin, 255)] = 0;
703 title = (char*)tbuffer;
705 begin = *ptr+1;
706 state = _PROMPT;
708 } else if (j <= 0 && line[*ptr]==')') {
710 if (*ptr > begin) {
711 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
712 tbuffer[WMIN(*ptr-begin, 255)] = 0;
713 title = (char*)tbuffer;
715 state = _DONE;
717 } else if (line[*ptr]=='(') {
718 j++;
719 } else if (line[*ptr]==')') {
720 j--;
723 break;
725 case _PROMPT:
726 if (line[*ptr]==')' && j==0) {
728 if (*ptr-begin > 1) {
729 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255));
730 pbuffer[WMIN(*ptr-begin, 255)] = 0;
731 prompt = (char*)pbuffer;
733 state = _DONE;
734 } else if (line[*ptr]=='(')
735 j++;
736 else if (line[*ptr]==')')
737 j--;
738 break;
741 (*ptr)--;
742 #undef _STARTING
743 #undef _TITLE
744 #undef _PROMPT
745 #undef _DONE
747 if (!wInputDialog(scr, title, prompt, &ret))
748 return NULL;
749 else
750 return ret;
754 #ifdef OFFIX_DND
755 static char*
756 get_dnd_selection(WScreen *scr)
758 XTextProperty text_ret;
759 int result;
760 char **list;
761 char *flat_string;
762 int count;
764 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
766 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
767 || text_ret.format==0 || text_ret.nitems == 0) {
768 wwarning(_("unable to get dropped data from DND drop"));
769 return NULL;
772 XTextPropertyToStringList(&text_ret, &list, &count);
774 if (!list || count<1) {
775 XFree(text_ret.value);
776 wwarning(_("error getting dropped data from DND drop"));
777 return NULL;
780 flat_string = wtokenjoin(list, count);
781 if (!flat_string) {
782 wwarning(_("out of memory while getting data from DND drop"));
785 XFreeStringList(list);
786 XFree(text_ret.value);
787 return flat_string;
789 #endif /* OFFIX_DND */
792 #define S_NORMAL 0
793 #define S_ESCAPE 1
794 #define S_OPTION 2
797 * state input new-state output
798 * NORMAL % OPTION <nil>
799 * NORMAL \ ESCAPE <nil>
800 * NORMAL etc. NORMAL <input>
801 * ESCAPE any NORMAL <input>
802 * OPTION s NORMAL <selection buffer>
803 * OPTION w NORMAL <selected window id>
804 * OPTION a NORMAL <input text>
805 * OPTION d NORMAL <OffiX DND selection object>
806 * OPTION W NORMAL <current workspace>
807 * OPTION etc. NORMAL %<input>
809 #define TMPBUFSIZE 64
810 char*
811 ExpandOptions(WScreen *scr, char *cmdline)
813 int ptr, optr, state, len, olen;
814 char *out, *nout;
815 char *selection=NULL;
816 char *user_input=NULL;
817 #if defined(OFFIX_DND) || defined(XDND)
818 char *dropped_thing=NULL;
819 #endif
820 char tmpbuf[TMPBUFSIZE];
821 int slen;
823 len = strlen(cmdline);
824 olen = len+1;
825 out = malloc(olen);
826 if (!out) {
827 wwarning(_("out of memory during expansion of \"%s\""));
828 return NULL;
830 *out = 0;
831 ptr = 0; /* input line pointer */
832 optr = 0; /* output line pointer */
833 state = S_NORMAL;
834 while (ptr < len) {
835 switch (state) {
836 case S_NORMAL:
837 switch (cmdline[ptr]) {
838 case '\\':
839 state = S_ESCAPE;
840 break;
841 case '%':
842 state = S_OPTION;
843 break;
844 default:
845 state = S_NORMAL;
846 out[optr++]=cmdline[ptr];
847 break;
849 break;
850 case S_ESCAPE:
851 switch (cmdline[ptr]) {
852 case 'n':
853 out[optr++]=10;
854 break;
856 case 'r':
857 out[optr++]=13;
858 break;
860 case 't':
861 out[optr++]=9;
862 break;
864 default:
865 out[optr++]=cmdline[ptr];
867 state = S_NORMAL;
868 break;
869 case S_OPTION:
870 state = S_NORMAL;
871 switch (cmdline[ptr]) {
872 case 'w':
873 if (scr->focused_window
874 && scr->focused_window->flags.focused) {
875 sprintf(tmpbuf, "0x%x",
876 (unsigned int)scr->focused_window->client_win);
877 slen = strlen(tmpbuf);
878 olen += slen;
879 nout = realloc(out,olen);
880 if (!nout) {
881 wwarning(_("out of memory during expansion of \"%w\""));
882 goto error;
884 out = nout;
885 strcat(out,tmpbuf);
886 optr+=slen;
887 } else {
888 out[optr++]=' ';
890 break;
892 case 'W':
893 sprintf(tmpbuf, "0x%x",
894 (unsigned int)scr->current_workspace + 1);
895 slen = strlen(tmpbuf);
896 olen += slen;
897 nout = realloc(out,olen);
898 if (!nout) {
899 wwarning(_("out of memory during expansion of \"%W\""));
900 goto error;
902 out = nout;
903 strcat(out,tmpbuf);
904 optr+=slen;
905 break;
907 case 'a':
908 ptr++;
909 user_input = getuserinput(scr, cmdline, &ptr);
910 if (user_input) {
911 slen = strlen(user_input);
912 olen += slen;
913 nout = realloc(out,olen);
914 if (!nout) {
915 wwarning(_("out of memory during expansion of \"%a\""));
916 goto error;
918 out = nout;
919 strcat(out,user_input);
920 optr+=slen;
921 } else {
922 /* Not an error, but user has Canceled the dialog box.
923 * This will make the command to not be performed. */
924 goto error;
926 break;
928 #if defined(OFFIX_DND) || defined(XDND)
929 case 'd':
930 #ifdef XDND
931 if(scr->xdestring) {
932 dropped_thing = wstrdup(scr->xdestring);
934 #endif
935 if (!dropped_thing) {
936 dropped_thing = get_dnd_selection(scr);
938 if (!dropped_thing) {
939 scr->flags.dnd_data_convertion_status = 1;
940 goto error;
942 slen = strlen(dropped_thing);
943 olen += slen;
944 nout = realloc(out,olen);
945 if (!nout) {
946 wwarning(_("out of memory during expansion of \"%d\""));
947 goto error;
949 out = nout;
950 strcat(out,dropped_thing);
951 optr+=slen;
952 break;
953 #endif /* OFFIX_DND */
955 case 's':
956 if (!selection) {
957 selection = getselection(scr);
959 if (!selection) {
960 wwarning(_("selection not available"));
961 goto error;
963 slen = strlen(selection);
964 olen += slen;
965 nout = realloc(out,olen);
966 if (!nout) {
967 wwarning(_("out of memory during expansion of \"%s\""));
968 goto error;
970 out = nout;
971 strcat(out,selection);
972 optr+=slen;
973 break;
975 default:
976 out[optr++]='%';
977 out[optr++]=cmdline[ptr];
979 break;
981 out[optr]=0;
982 ptr++;
984 if (selection)
985 XFree(selection);
986 return out;
988 error:
989 wfree(out);
990 if (selection)
991 XFree(selection);
992 return NULL;
996 /* We don't care for upper/lower case in comparing the keys; so we
997 have to define our own comparison function here */
998 BOOL
999 StringCompareHook(proplist_t pl1, proplist_t pl2)
1001 char *str1, *str2;
1003 str1 = PLGetString(pl1);
1004 str2 = PLGetString(pl2);
1006 if (strcasecmp(str1, str2)==0)
1007 return YES;
1008 else
1009 return NO;
1013 /* feof doesn't seem to work on pipes */
1015 IsEof(FILE * stream)
1017 static struct stat stinfo;
1019 fstat(fileno(stream), &stinfo);
1020 return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) ||
1021 feof(stream));
1025 void
1026 ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
1028 char *name;
1030 *winstance = *wclass = NULL;
1032 if (!PLIsString(value)) {
1033 wwarning(_("bad window name value in %s state info"), where);
1034 return;
1037 name = PLGetString(value);
1038 if (!name || strlen(name)==0) {
1039 wwarning(_("bad window name value in %s state info"), where);
1040 return;
1043 UnescapeWM_CLASS(name, winstance, wclass);
1047 #if 0
1048 static char*
1049 keysymToString(KeySym keysym, unsigned int state)
1051 XKeyEvent kev;
1052 char *buf = wmalloc(20);
1053 int count;
1055 kev.display = dpy;
1056 kev.type = KeyPress;
1057 kev.send_event = False;
1058 kev.window = DefaultRootWindow(dpy);
1059 kev.root = DefaultRootWindow(dpy);
1060 kev.same_screen = True;
1061 kev.subwindow = kev.root;
1062 kev.serial = 0x12344321;
1063 kev.time = CurrentTime;
1064 kev.state = state;
1065 kev.keycode = XKeysymToKeycode(dpy, keysym);
1066 count = XLookupString(&kev, buf, 19, NULL, NULL);
1067 buf[count] = 0;
1069 return buf;
1071 #endif
1074 char*
1075 GetShortcutString(char *text)
1077 char *buffer = NULL;
1078 char *k;
1079 int modmask = 0;
1080 /* KeySym ksym;*/
1081 int control = 0;
1082 char *tmp;
1084 tmp = text = wstrdup(text);
1086 /* get modifiers */
1087 while ((k = strchr(text, '+'))!=NULL) {
1088 int mod;
1090 *k = 0;
1091 mod = wXModifierFromKey(text);
1092 if (mod<0) {
1093 return wstrdup("bug");
1096 modmask |= mod;
1098 if (strcasecmp(text, "Meta")==0) {
1099 buffer = wstrappend(buffer, "M+");
1100 } else if (strcasecmp(text, "Alt")==0) {
1101 buffer = wstrappend(buffer, "A+");
1102 } else if (strcasecmp(text, "Shift")==0) {
1103 buffer = wstrappend(buffer, "Sh+");
1104 } else if (strcasecmp(text, "Mod1")==0) {
1105 buffer = wstrappend(buffer, "M1+");
1106 } else if (strcasecmp(text, "Mod2")==0) {
1107 buffer = wstrappend(buffer, "M2+");
1108 } else if (strcasecmp(text, "Mod3")==0) {
1109 buffer = wstrappend(buffer, "M3+");
1110 } else if (strcasecmp(text, "Mod4")==0) {
1111 buffer = wstrappend(buffer, "M4+");
1112 } else if (strcasecmp(text, "Mod5")==0) {
1113 buffer = wstrappend(buffer, "M5+");
1114 } else if (strcasecmp(text, "Control")==0) {
1115 control = 1;
1116 } else {
1117 buffer = wstrappend(buffer, text);
1119 text = k+1;
1122 if (control) {
1123 buffer = wstrappend(buffer, "^");
1125 buffer = wstrappend(buffer, text);
1127 /* get key */
1128 /* ksym = XStringToKeysym(text);
1129 tmp = keysymToString(ksym, modmask);
1130 puts(tmp);
1131 buffer = wstrappend(buffer, tmp);
1133 wfree(tmp);
1135 return buffer;
1139 char*
1140 EscapeWM_CLASS(char *name, char *class)
1142 char *ret;
1143 char *ename = NULL, *eclass = NULL;
1144 int i, j, l;
1146 if (!name && !class)
1147 return NULL;
1149 if (name) {
1150 l = strlen(name);
1151 ename = wmalloc(l*2);
1152 j = 0;
1153 for (i=0; i<l; i++) {
1154 if (name[i]=='\\') {
1155 ename[j++] = '\\';
1156 } else if (name[i]=='.') {
1157 ename[j++] = '\\';
1159 ename[j++] = name[i];
1161 ename[j] = 0;
1163 if (class) {
1164 l = strlen(class);
1165 eclass = wmalloc(l*2);
1166 j = 0;
1167 for (i=0; i<l; i++) {
1168 if (class[i]=='\\') {
1169 eclass[j++] = '\\';
1170 } else if (class[i]=='.') {
1171 eclass[j++] = '\\';
1173 eclass[j++] = class[i];
1175 eclass[j] = 0;
1178 if (ename && eclass) {
1179 ret = wmalloc(strlen(ename)+strlen(eclass)+4);
1180 sprintf(ret, "%s.%s", ename, eclass);
1181 wfree(ename);
1182 wfree(eclass);
1183 } else if (ename) {
1184 ret = wstrdup(ename);
1185 wfree(ename);
1186 } else {
1187 ret = wstrdup(eclass);
1188 wfree(eclass);
1191 return ret;
1195 void
1196 UnescapeWM_CLASS(char *str, char **name, char **class)
1198 int i, j, k, dot;
1199 Bool esc;
1201 j = strlen(str);
1202 *name = wmalloc(j);
1203 **name = 0;
1204 *class = wmalloc(j);
1205 **class = 0;
1207 /* separate string in 2 parts */
1208 esc = False;
1209 dot = 0;
1210 for (i = 0; i < j; i++) {
1211 if (!esc) {
1212 if (str[i]=='\\') {
1213 esc = True;
1214 } else if (str[i]=='.') {
1215 dot = i;
1216 break;
1218 } else {
1219 esc = False;
1223 /* unescape strings */
1224 esc = False;
1225 k = 0;
1226 for (i = 0; i < dot; i++) {
1227 if (!esc) {
1228 if (str[i]=='\\') {
1229 esc = True;
1230 } else {
1231 (*name)[k++] = str[i];
1233 } else {
1234 (*name)[k++] = str[i];
1235 esc = False;
1238 (*name)[k] = 0;
1240 esc = False;
1241 k = 0;
1242 for (i = dot+1; i<j; i++) {
1243 if (!esc) {
1244 if (str[i]=='\\') {
1245 esc = True;
1246 } else {
1247 (*class)[k++] = str[i];
1249 } else {
1250 esc = False;
1253 (*class)[k] = 0;
1255 if (!*name) {
1256 wfree(*name);
1257 *name = NULL;
1259 if (!*class) {
1260 wfree(*class);
1261 *class = NULL;
1267 void
1268 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1270 unsigned char *buffer;
1271 int len;
1272 int i;
1273 char buf[16];
1275 if (!scr->flags.backimage_helper_launched) {
1276 return;
1279 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1280 buffer = wmalloc(len+5);
1281 sprintf(buf, "%4i", len);
1282 memcpy(buffer, buf, 4);
1283 buffer[4] = type;
1284 i = 5;
1285 if (workspace >= 0) {
1286 sprintf(buf, "%4i", workspace);
1287 memcpy(&buffer[i], buf, 4);
1288 i += 4;
1289 buffer[i] = 0;
1291 if (msg)
1292 strcpy(&buffer[i], msg);
1294 if (write(scr->helper_fd, buffer, len+4) < 0) {
1295 wsyserror(_("could not send message to background image helper"));
1297 wfree(buffer);