changed indentation to use spaces only
[wmaker-crm.git] / src / misc.c
blob63ef2ba567d1d8c6aa5b4c7fa6be73a82d6b1dc2
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
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 <WINGs/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 WPreferences wPreferences;
57 extern Time LastTimestamp;
59 #ifdef OFFIX_DND
60 extern Atom _XA_DND_SELECTION;
61 #endif
64 #ifdef USECPP
65 static void
66 putdef(char *line, char *name, char *value)
68 if (!value) {
69 wwarning(_("could not define value for %s for cpp"), name);
70 return;
72 strcat(line, name);
73 strcat(line, value);
78 static void
79 putidef(char *line, char *name, int value)
81 char tmp[64];
82 snprintf(tmp, sizeof(tmp), "%i", value);
83 strcat(line, name);
84 strcat(line, tmp);
88 static char*
89 username()
91 char *tmp;
93 tmp = getlogin();
94 if (!tmp) {
95 struct passwd *user;
97 user = getpwuid(getuid());
98 if (!user) {
99 wsyserror(_("could not get password entry for UID %i"), getuid());
100 return NULL;
102 if (!user->pw_name) {
103 return NULL;
104 } else {
105 return user->pw_name;
108 return tmp;
111 char *
112 MakeCPPArgs(char *path)
114 int i;
115 char buffer[MAXLINE], *buf, *line;
116 Visual *visual;
117 char *tmp;
119 line = wmalloc(MAXLINE);
120 *line = 0;
121 i=1;
122 if ((buf=getenv("HOSTNAME"))!=NULL) {
123 if (buf[0]=='(') {
124 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"),
125 buf);
126 } else
127 putdef(line, " -DHOST=", buf);
128 } else if ((buf=getenv("HOST"))!=NULL) {
129 if (buf[0]=='(') {
130 wwarning(_("your machine is misconfigured. HOST is set to %s"),
131 buf);
132 } else
133 putdef(line, " -DHOST=", buf);
135 buf = username();
136 if (buf)
137 putdef(line, " -DUSER=", buf);
138 putidef(line, " -DUID=", getuid());
139 buf = XDisplayName(DisplayString(dpy));
140 putdef(line, " -DDISPLAY=", buf);
141 putdef(line, " -DWM_VERSION=", VERSION);
143 visual = DefaultVisual(dpy, DefaultScreen(dpy));
144 putidef(line, " -DVISUAL=", visual->class);
146 putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy)));
148 putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy)));
149 putidef(line, " -DSCR_HEIGHT=",
150 HeightOfScreen(DefaultScreenOfDisplay(dpy)));
152 /* put the dir where the menu is being read from to the
153 * search path */
154 if (path) {
155 tmp = wstrdup(path);
156 buf = strchr(tmp+1, ' ');
157 if (buf) {
158 *buf = 0;
160 buf = strrchr(tmp, '/');
161 if (buf) {
162 *buf = 0; /* trunc filename */
163 putdef(line, " -I", tmp);
165 wfree(tmp);
169 /* this should be done just once, but it works this way */
170 strcpy(buffer, DEF_CONFIG_PATHS);
171 buf = strtok(buffer, ":");
173 do {
174 char fullpath[MAXLINE];
176 if (buf[0]!='~') {
177 strcpy(fullpath, buf);
178 } else {
179 char * wgethomedir();
180 /* home is statically allocated. Don't free it! */
181 char *home = wgethomedir();
183 strcpy(fullpath, home);
184 strcat(fullpath, &(buf[1]));
187 putdef(line, " -I", fullpath);
189 } while ((buf = strtok(NULL, ":"))!=NULL);
191 #undef arg
192 #ifdef DEBUG
193 puts("CPP ARGS");
194 puts(line);
195 #endif
196 return line;
198 #endif /* USECPP */
203 #if 0
205 * Is win2 below win1?
207 static Bool
208 isBelow(WWindow *win1, WWindow *win2)
210 int i;
211 WCoreWindow *tmp;
213 tmp = win1->frame->core->stacking->under;
214 while (tmp) {
215 if (tmp == win2->frame->core)
216 return True;
217 tmp = tmp->stacking->under;
220 for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
221 tmp = win1->screen_ptr->stacking_list[i];
222 while (tmp) {
223 if (tmp == win2->frame->core)
224 return True;
225 tmp = tmp->stacking->under;
228 return True;
230 #endif
235 * XFetchName Wrapper
238 Bool
239 wFetchName(dpy, win, winname)
240 Display *dpy;
241 Window win;
242 char **winname;
244 XTextProperty text_prop;
245 char **list;
246 int num;
248 if (XGetWMName(dpy, win, &text_prop)) {
249 if (text_prop.value && text_prop.nitems > 0) {
250 if (text_prop.encoding == XA_STRING) {
251 *winname = wstrdup((char *)text_prop.value);
252 XFree(text_prop.value);
253 } else {
254 text_prop.nitems = strlen((char *)text_prop.value);
255 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
256 Success && num > 0 && *list) {
257 XFree(text_prop.value);
258 *winname = wstrdup(*list);
259 XFreeStringList(list);
260 } else {
261 *winname = wstrdup((char *)text_prop.value);
262 XFree(text_prop.value);
265 } else {
266 /* the title is set, but it was set to none */
267 *winname = wstrdup("");
269 return True;
270 } else {
271 /* the hint is probably not set */
272 *winname = NULL;
274 return False;
279 * XGetIconName Wrapper
283 Bool
284 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_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}};
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);
408 } else {
409 wusleep(10);
411 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
412 break;
414 XMoveWindow(dpy, win, to_x, to_y);
416 XSync(dpy, 0);
417 /* compress expose events */
418 eatExpose();
422 char*
423 ShrinkString(WMFont *font, char *string, int width)
425 int w, w1=0;
426 int p;
427 char *pos;
428 char *text;
429 int p1, p2, t;
431 if (wPreferences.multi_byte_text)
432 return wstrdup(string);
434 p = strlen(string);
435 w = WMWidthOfString(font, string, p);
436 text = wmalloc(strlen(string)+8);
437 strcpy(text, string);
438 if (w<=width)
439 return text;
441 pos = strchr(text, ' ');
442 if (!pos)
443 pos = strchr(text, ':');
445 if (pos) {
446 *pos = 0;
447 p = strlen(text);
448 w1 = WMWidthOfString(font, text, p);
449 if (w1 > width) {
450 w1 = 0;
451 p = 0;
452 *pos = ' ';
453 *text = 0;
454 } else {
455 *pos = 0;
456 width -= w1;
457 p++;
459 string += p;
460 p=strlen(string);
461 } else {
462 *text=0;
464 strcat(text, "...");
465 width -= WMWidthOfString(font, "...", 3);
466 pos = string;
467 p1=0;
468 p2=p;
469 t = (p2-p1)/2;
470 while (p2>p1 && p1!=t) {
471 w = WMWidthOfString(font, &string[p-t], t);
472 if (w>width) {
473 p2 = t;
474 t = p1+(p2-p1)/2;
475 } else if (w<width) {
476 p1 = t;
477 t = p1+(p2-p1)/2;
478 } else
479 p2=p1=t;
481 strcat(text, &string[p-p1]);
483 return text;
487 char*
488 FindImage(char *paths, char *file)
490 char *tmp, *path;
492 tmp = strrchr(file, ':');
493 if (tmp) {
494 *tmp = 0;
495 path = wfindfile(paths, file);
496 *tmp = ':';
498 if (!tmp || !path) {
499 path = wfindfile(paths, file);
502 return path;
506 static void
507 timeoutHandler(void *data)
509 *(int*)data = 1;
513 static char*
514 getTextSelection(WScreen *screen, Atom selection)
516 int buffer = -1;
518 switch (selection) {
519 case XA_CUT_BUFFER0:
520 buffer = 0;
521 break;
522 case XA_CUT_BUFFER1:
523 buffer = 1;
524 break;
525 case XA_CUT_BUFFER2:
526 buffer = 2;
527 break;
528 case XA_CUT_BUFFER3:
529 buffer = 3;
530 break;
531 case XA_CUT_BUFFER4:
532 buffer = 4;
533 break;
534 case XA_CUT_BUFFER5:
535 buffer = 5;
536 break;
537 case XA_CUT_BUFFER6:
538 buffer = 6;
539 break;
540 case XA_CUT_BUFFER7:
541 buffer = 7;
542 break;
544 if (buffer >= 0) {
545 char *data;
546 int size;
548 data = XFetchBuffer(dpy, &size, buffer);
550 return data;
551 } else {
552 char *data;
553 int bits;
554 Atom rtype;
555 unsigned long len, bytes;
556 WMHandlerID timer;
557 int timeout = 0;
558 XEvent ev;
559 static Atom clipboard = 0;
561 if (!clipboard)
562 clipboard = XInternAtom(dpy, "CLIPBOARD", False);
564 XDeleteProperty(dpy, screen->info_window, clipboard);
566 XConvertSelection(dpy, selection, XA_STRING,
567 clipboard, screen->info_window,
568 CurrentTime);
570 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
572 while (!XCheckTypedWindowEvent(dpy, screen->info_window,
573 SelectionNotify, &ev) && !timeout);
575 if (!timeout) {
576 WMDeleteTimerHandler(timer);
577 } else {
578 wwarning("selection retrieval timed out");
579 return NULL;
582 /* nobody owns the selection or the current owner has
583 * nothing to do with what we need */
584 if (ev.xselection.property == None) {
585 return NULL;
588 if (XGetWindowProperty(dpy, screen->info_window,
589 clipboard, 0, 1024,
590 False, XA_STRING, &rtype, &bits, &len,
591 &bytes, (unsigned char**)&data)!=Success) {
592 return NULL;
594 if (rtype!=XA_STRING || bits!=8) {
595 wwarning("invalid data in text selection");
596 if (data)
597 XFree(data);
598 return NULL;
600 return data;
604 static char*
605 getselection(WScreen *scr)
607 char *tmp;
609 tmp = getTextSelection(scr, XA_PRIMARY);
610 if (!tmp)
611 tmp = getTextSelection(scr, XA_CUT_BUFFER0);
612 return tmp;
616 static char*
617 getuserinput(WScreen *scr, char *line, int *ptr)
619 char *ret;
620 char *title;
621 char *prompt;
622 int j, state;
623 int begin = 0;
624 #define BUFSIZE 512
625 char tbuffer[BUFSIZE], pbuffer[BUFSIZE];
628 title = _("Program Arguments");
629 prompt = _("Enter command arguments:");
630 ret = NULL;
632 #define _STARTING 0
633 #define _TITLE 1
634 #define _PROMPT 2
635 #define _DONE 3
637 state = _STARTING;
638 j = 0;
639 for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
640 switch (state) {
641 case _STARTING:
642 if (line[*ptr]=='(') {
643 state = _TITLE;
644 begin = *ptr+1;
645 } else {
646 state = _DONE;
648 break;
650 case _TITLE:
651 if (j <= 0 && line[*ptr]==',') {
653 j = 0;
654 if (*ptr > begin) {
655 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE));
656 tbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0;
657 title = (char*)tbuffer;
659 begin = *ptr+1;
660 state = _PROMPT;
662 } else if (j <= 0 && line[*ptr]==')') {
664 if (*ptr > begin) {
665 strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE));
666 tbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0;
667 title = (char*)tbuffer;
669 state = _DONE;
671 } else if (line[*ptr]=='(') {
672 j++;
673 } else if (line[*ptr]==')') {
674 j--;
677 break;
679 case _PROMPT:
680 if (line[*ptr]==')' && j==0) {
682 if (*ptr-begin > 1) {
683 strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE));
684 pbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0;
685 prompt = (char*)pbuffer;
687 state = _DONE;
688 } else if (line[*ptr]=='(')
689 j++;
690 else if (line[*ptr]==')')
691 j--;
692 break;
695 (*ptr)--;
696 #undef _STARTING
697 #undef _TITLE
698 #undef _PROMPT
699 #undef _DONE
701 if (!wInputDialog(scr, title, prompt, &ret))
702 return NULL;
703 else
704 return ret;
708 #ifdef OFFIX_DND
709 static char*
710 get_dnd_selection(WScreen *scr)
712 XTextProperty text_ret;
713 int result;
714 char **list;
715 char *flat_string;
716 int count;
718 result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
720 if (result==0 || text_ret.value==NULL || text_ret.encoding==None
721 || text_ret.format==0 || text_ret.nitems == 0) {
722 wwarning(_("unable to get dropped data from DND drop"));
723 return NULL;
726 XTextPropertyToStringList(&text_ret, &list, &count);
728 if (!list || count<1) {
729 XFree(text_ret.value);
730 wwarning(_("error getting dropped data from DND drop"));
731 return NULL;
734 flat_string = wtokenjoin(list, count);
735 if (!flat_string) {
736 wwarning(_("out of memory while getting data from DND drop"));
739 XFreeStringList(list);
740 XFree(text_ret.value);
741 return flat_string;
743 #endif /* OFFIX_DND */
746 #define S_NORMAL 0
747 #define S_ESCAPE 1
748 #define S_OPTION 2
751 * state input new-state output
752 * NORMAL % OPTION <nil>
753 * NORMAL \ ESCAPE <nil>
754 * NORMAL etc. NORMAL <input>
755 * ESCAPE any NORMAL <input>
756 * OPTION s NORMAL <selection buffer>
757 * OPTION w NORMAL <selected window id>
758 * OPTION a NORMAL <input text>
759 * OPTION d NORMAL <OffiX DND selection object>
760 * OPTION W NORMAL <current workspace>
761 * OPTION etc. NORMAL %<input>
763 #define TMPBUFSIZE 64
764 char*
765 ExpandOptions(WScreen *scr, char *cmdline)
767 int ptr, optr, state, len, olen;
768 char *out, *nout;
769 char *selection=NULL;
770 char *user_input=NULL;
771 #if defined(OFFIX_DND) || defined(XDND)
772 char *dropped_thing=NULL;
773 #endif
774 char tmpbuf[TMPBUFSIZE];
775 int slen;
777 len = strlen(cmdline);
778 olen = len+1;
779 out = malloc(olen);
780 if (!out) {
781 wwarning(_("out of memory during expansion of \"%s\""));
782 return NULL;
784 *out = 0;
785 ptr = 0; /* input line pointer */
786 optr = 0; /* output line pointer */
787 state = S_NORMAL;
788 while (ptr < len) {
789 switch (state) {
790 case S_NORMAL:
791 switch (cmdline[ptr]) {
792 case '\\':
793 state = S_ESCAPE;
794 break;
795 case '%':
796 state = S_OPTION;
797 break;
798 default:
799 state = S_NORMAL;
800 out[optr++]=cmdline[ptr];
801 break;
803 break;
804 case S_ESCAPE:
805 switch (cmdline[ptr]) {
806 case 'n':
807 out[optr++]=10;
808 break;
810 case 'r':
811 out[optr++]=13;
812 break;
814 case 't':
815 out[optr++]=9;
816 break;
818 default:
819 out[optr++]=cmdline[ptr];
821 state = S_NORMAL;
822 break;
823 case S_OPTION:
824 state = S_NORMAL;
825 switch (cmdline[ptr]) {
826 case 'w':
827 if (scr->focused_window
828 && scr->focused_window->flags.focused) {
829 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
830 (unsigned int)scr->focused_window->client_win);
831 slen = strlen(tmpbuf);
832 olen += slen;
833 nout = realloc(out,olen);
834 if (!nout) {
835 wwarning(_("out of memory during expansion of \"%w\""));
836 goto error;
838 out = nout;
839 strcat(out,tmpbuf);
840 optr+=slen;
841 } else {
842 out[optr++]=' ';
844 break;
846 case 'W':
847 snprintf(tmpbuf, sizeof(tmpbuf), "0x%x",
848 (unsigned int)scr->current_workspace + 1);
849 slen = strlen(tmpbuf);
850 olen += slen;
851 nout = realloc(out,olen);
852 if (!nout) {
853 wwarning(_("out of memory during expansion of \"%W\""));
854 goto error;
856 out = nout;
857 strcat(out,tmpbuf);
858 optr+=slen;
859 break;
861 case 'a':
862 ptr++;
863 user_input = getuserinput(scr, cmdline, &ptr);
864 if (user_input) {
865 slen = strlen(user_input);
866 olen += slen;
867 nout = realloc(out,olen);
868 if (!nout) {
869 wwarning(_("out of memory during expansion of \"%a\""));
870 goto error;
872 out = nout;
873 strcat(out,user_input);
874 optr+=slen;
875 } else {
876 /* Not an error, but user has Canceled the dialog box.
877 * This will make the command to not be performed. */
878 goto error;
880 break;
882 #if defined(OFFIX_DND) || defined(XDND)
883 case 'd':
884 #ifdef XDND
885 if(scr->xdestring) {
886 dropped_thing = wstrdup(scr->xdestring);
888 #endif
889 if (!dropped_thing) {
890 dropped_thing = get_dnd_selection(scr);
892 if (!dropped_thing) {
893 scr->flags.dnd_data_convertion_status = 1;
894 goto error;
896 slen = strlen(dropped_thing);
897 olen += slen;
898 nout = realloc(out,olen);
899 if (!nout) {
900 wwarning(_("out of memory during expansion of \"%d\""));
901 goto error;
903 out = nout;
904 strcat(out,dropped_thing);
905 optr+=slen;
906 break;
907 #endif /* OFFIX_DND */
909 case 's':
910 if (!selection) {
911 selection = getselection(scr);
913 if (!selection) {
914 wwarning(_("selection not available"));
915 goto error;
917 slen = strlen(selection);
918 olen += slen;
919 nout = realloc(out,olen);
920 if (!nout) {
921 wwarning(_("out of memory during expansion of \"%s\""));
922 goto error;
924 out = nout;
925 strcat(out,selection);
926 optr+=slen;
927 break;
929 default:
930 out[optr++]='%';
931 out[optr++]=cmdline[ptr];
933 break;
935 out[optr]=0;
936 ptr++;
938 if (selection)
939 XFree(selection);
940 return out;
942 error:
943 wfree(out);
944 if (selection)
945 XFree(selection);
946 return NULL;
950 void
951 ParseWindowName(WMPropList *value, char **winstance, char **wclass, char *where)
953 char *name;
955 *winstance = *wclass = NULL;
957 if (!WMIsPLString(value)) {
958 wwarning(_("bad window name value in %s state info"), where);
959 return;
962 name = WMGetFromPLString(value);
963 if (!name || strlen(name)==0) {
964 wwarning(_("bad window name value in %s state info"), where);
965 return;
968 UnescapeWM_CLASS(name, winstance, wclass);
972 #if 0
973 static char*
974 keysymToString(KeySym keysym, unsigned int state)
976 XKeyEvent kev;
977 char *buf = wmalloc(20);
978 int count;
980 kev.display = dpy;
981 kev.type = KeyPress;
982 kev.send_event = False;
983 kev.window = DefaultRootWindow(dpy);
984 kev.root = DefaultRootWindow(dpy);
985 kev.same_screen = True;
986 kev.subwindow = kev.root;
987 kev.serial = 0x12344321;
988 kev.time = CurrentTime;
989 kev.state = state;
990 kev.keycode = XKeysymToKeycode(dpy, keysym);
991 count = XLookupString(&kev, buf, 19, NULL, NULL);
992 buf[count] = 0;
994 return buf;
996 #endif
999 char*
1000 GetShortcutString(char *text)
1002 char *buffer = NULL;
1003 char *k;
1004 int modmask = 0;
1005 /* KeySym ksym;*/
1006 int control = 0;
1007 char *tmp;
1009 tmp = text = wstrdup(text);
1011 /* get modifiers */
1012 while ((k = strchr(text, '+'))!=NULL) {
1013 int mod;
1015 *k = 0;
1016 mod = wXModifierFromKey(text);
1017 if (mod<0) {
1018 return wstrdup("bug");
1021 modmask |= mod;
1023 if (strcasecmp(text, "Meta")==0) {
1024 buffer = wstrappend(buffer, "M+");
1025 } else if (strcasecmp(text, "Alt")==0) {
1026 buffer = wstrappend(buffer, "A+");
1027 } else if (strcasecmp(text, "Shift")==0) {
1028 buffer = wstrappend(buffer, "Sh+");
1029 } else if (strcasecmp(text, "Mod1")==0) {
1030 buffer = wstrappend(buffer, "M1+");
1031 } else if (strcasecmp(text, "Mod2")==0) {
1032 buffer = wstrappend(buffer, "M2+");
1033 } else if (strcasecmp(text, "Mod3")==0) {
1034 buffer = wstrappend(buffer, "M3+");
1035 } else if (strcasecmp(text, "Mod4")==0) {
1036 buffer = wstrappend(buffer, "M4+");
1037 } else if (strcasecmp(text, "Mod5")==0) {
1038 buffer = wstrappend(buffer, "M5+");
1039 } else if (strcasecmp(text, "Control")==0) {
1040 control = 1;
1041 } else {
1042 buffer = wstrappend(buffer, text);
1044 text = k+1;
1047 if (control) {
1048 buffer = wstrappend(buffer, "^");
1050 buffer = wstrappend(buffer, text);
1052 /* get key */
1053 /* ksym = XStringToKeysym(text);
1054 tmp = keysymToString(ksym, modmask);
1055 puts(tmp);
1056 buffer = wstrappend(buffer, tmp);
1058 wfree(tmp);
1060 return buffer;
1064 char*
1065 EscapeWM_CLASS(char *name, char *class)
1067 char *ret;
1068 char *ename = NULL, *eclass = NULL;
1069 int i, j, l;
1071 if (!name && !class)
1072 return NULL;
1074 if (name) {
1075 l = strlen(name);
1076 ename = wmalloc(l*2+1);
1077 j = 0;
1078 for (i=0; i<l; i++) {
1079 if (name[i]=='\\') {
1080 ename[j++] = '\\';
1081 } else if (name[i]=='.') {
1082 ename[j++] = '\\';
1084 ename[j++] = name[i];
1086 ename[j] = 0;
1088 if (class) {
1089 l = strlen(class);
1090 eclass = wmalloc(l*2+1);
1091 j = 0;
1092 for (i=0; i<l; i++) {
1093 if (class[i]=='\\') {
1094 eclass[j++] = '\\';
1095 } else if (class[i]=='.') {
1096 eclass[j++] = '\\';
1098 eclass[j++] = class[i];
1100 eclass[j] = 0;
1103 if (ename && eclass) {
1104 int len = strlen(ename)+strlen(eclass)+4;
1105 ret = wmalloc(len);
1106 snprintf(ret, len, "%s.%s", ename, eclass);
1107 wfree(ename);
1108 wfree(eclass);
1109 } else if (ename) {
1110 ret = wstrdup(ename);
1111 wfree(ename);
1112 } else {
1113 ret = wstrdup(eclass);
1114 wfree(eclass);
1117 return ret;
1121 void
1122 UnescapeWM_CLASS(char *str, char **name, char **class)
1124 int i, j, k, dot;
1126 j = strlen(str);
1127 *name = wmalloc(j);
1128 **name = 0;
1129 *class = wmalloc(j);
1130 **class = 0;
1132 /* separate string in 2 parts */
1133 dot = -1;
1134 for (i = 0; i < j; i++) {
1135 if (str[i]=='\\') {
1136 i++;
1137 continue;
1138 } else if (str[i]=='.') {
1139 dot = i;
1140 break;
1144 /* unescape strings */
1145 for (i=0, k=0; i < dot; i++) {
1146 if (str[i]=='\\') {
1147 continue;
1148 } else {
1149 (*name)[k++] = str[i];
1152 (*name)[k] = 0;
1154 for (i=dot+1, k=0; i<j; i++) {
1155 if (str[i]=='\\') {
1156 continue;
1157 } else {
1158 (*class)[k++] = str[i];
1161 (*class)[k] = 0;
1163 if (!*name) {
1164 wfree(*name);
1165 *name = NULL;
1167 if (!*class) {
1168 wfree(*class);
1169 *class = NULL;
1175 void
1176 SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
1178 unsigned char *buffer;
1179 int len;
1180 int i;
1181 char buf[16];
1183 if (!scr->flags.backimage_helper_launched) {
1184 return;
1187 len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
1188 buffer = wmalloc(len+5);
1189 snprintf(buf, len, "%4i", len);
1190 memcpy(buffer, buf, 4);
1191 buffer[4] = type;
1192 i = 5;
1193 if (workspace >= 0) {
1194 snprintf(buf, sizeof(buf), "%4i", workspace);
1195 memcpy(&buffer[i], buf, 4);
1196 i += 4;
1197 buffer[i] = 0;
1199 if (msg)
1200 strcpy(&buffer[i], msg);
1202 if (write(scr->helper_fd, buffer, len+4) < 0) {
1203 wsyserror(_("could not send message to background image helper"));
1205 wfree(buffer);
1209 Bool
1210 UpdateDomainFile(WDDomain *domain)
1212 struct stat stbuf;
1213 char path[PATH_MAX];
1214 WMPropList *shared_dict, *dict;
1215 Bool result, freeDict = False;
1217 dict = domain->dictionary;
1218 if (WMIsPLDictionary(domain->dictionary)) {
1219 /* retrieve global system dictionary */
1220 snprintf(path, sizeof(path), "%s/WindowMaker/%s",
1221 SYSCONFDIR, domain->domain_name);
1222 if (stat(path, &stbuf) >= 0) {
1223 shared_dict = WMReadPropListFromFile(path);
1224 if (shared_dict) {
1225 if (WMIsPLDictionary(shared_dict)) {
1226 freeDict = True;
1227 dict = WMDeepCopyPropList(domain->dictionary);
1228 WMSubtractPLDictionaries(dict, shared_dict, True);
1230 WMReleasePropList(shared_dict);
1235 result = WMWritePropListToFile(dict, domain->path, True);
1237 if (freeDict) {
1238 WMReleasePropList(dict);
1241 return result;
1245 char*
1246 StrConcatDot(char *a, char *b)
1248 int len;
1249 char *str;
1251 if (!a)
1252 a = "";
1253 if (!b)
1254 b = "";
1256 len = strlen(a)+strlen(b)+4;
1257 str = wmalloc(len);
1259 snprintf(str, len, "%s.%s", a, b);
1261 return str;
1265 #ifndef NETWM_HINTS
1267 static Atom net_wm_pid = None;
1270 GetPidForWindow(Window win)
1272 Atom type_ret;
1273 int fmt_ret;
1274 unsigned long nitems_ret;
1275 unsigned long bytes_after_ret;
1276 long *data = 0;
1277 int pid;
1279 if (net_wm_pid == None) {
1280 net_wm_pid = XInternAtom(dpy, "_NET_WM_PID", False);
1283 if (XGetWindowProperty(dpy, win, net_wm_pid, 0, 1, False,
1284 XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret,
1285 &bytes_after_ret,
1286 (unsigned char**)&data)==Success && data) {
1288 pid = *data;
1289 XFree(data);
1290 } else {
1291 pid = 0;
1294 return pid;
1297 #endif
1300 Bool
1301 GetCommandForPid(int pid, char ***argv, int *argc)
1303 char buf[1024];
1304 FILE *fPtr;
1305 int count, i, j;
1307 sprintf(buf, "/proc/%d/cmdline", pid);
1308 fPtr = fopen(buf, "r");
1309 if (fPtr) {
1310 count = read(fileno(fPtr), buf, 1024);
1311 if (count > 0) {
1312 buf[count] = 0;
1313 for (i=0, *argc=0; i<count; i++) {
1314 if (buf[i] == 0) {
1315 (*argc)++;
1318 if ((*argc) == 0) {
1319 *argv = NULL;
1320 return False;
1322 *argv = (char**) wmalloc(sizeof(char*) * (*argc));
1323 (*argv)[0] = buf;
1324 for (i=0, j=1; i<count; i++) {
1325 if (buf[i] != 0)
1326 continue;
1327 if (i < count-1) {
1328 (*argv)[j++] = &buf[i+1];
1332 return True;
1335 fclose(fPtr);
1338 return False;
1342 static char*
1343 getCommandForWindow(Window win, int elements)
1345 char **argv, *command = NULL;
1346 int argc;
1348 if (XGetCommand(dpy, win, &argv, &argc)) {
1349 if (argc > 0 && argv != NULL) {
1350 if (elements==0)
1351 elements = argc;
1352 command = wtokenjoin(argv, WMIN(argc, elements));
1353 if (command[0] == 0) {
1354 wfree(command);
1355 command = NULL;
1358 if (argv) {
1359 XFreeStringList(argv);
1363 return command;
1367 /* Free result when done */
1368 char*
1369 GetCommandForWindow(Window win)
1371 return getCommandForWindow(win, 0);
1375 /* Free result when done */
1376 char*
1377 GetProgramNameForWindow(Window win)
1379 return getCommandForWindow(win, 1);