2 * Window Maker window manager
4 * Copyright (c) 1997, 1998 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,
24 #include <X11/Xutil.h>
25 #include <X11/Xatom.h>
37 #include "WindowMaker.h"
47 #include "xmodifier.h"
51 /**** global variables *****/
53 extern char *DisplayName
;
55 extern WPreferences wPreferences
;
57 extern Time LastTimestamp
;
62 extern Atom _XA_DND_SELECTION
;
68 putdef(char *line
, char *name
, char *value
)
71 wwarning(_("could not define value for %s for cpp"), name
);
81 putidef(char *line
, char *name
, int value
)
84 sprintf(tmp
, "%i", value
);
99 user
= getpwuid(getuid());
101 wsyserror(_("could not get password entry for UID %i"), getuid());
104 if (!user
->pw_name
) {
107 return user
->pw_name
;
114 MakeCPPArgs(char *path
)
117 char buffer
[MAXLINE
], *buf
, *line
;
120 line
= wmalloc(MAXLINE
);
123 if ((buf
=getenv("HOSTNAME"))!=NULL
) {
125 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"),
128 putdef(line
, " -DHOST=", buf
);
129 } else if ((buf
=getenv("HOST"))!=NULL
) {
131 wwarning(_("your machine is misconfigured. HOST is set to %s"),
134 putdef(line
, " -DHOST=", buf
);
138 putdef(line
, " -DUSER=", buf
);
139 putidef(line
, " -DUID=", getuid());
140 buf
= XDisplayName(DisplayString(dpy
));
141 putdef(line
, " -DDISPLAY=", buf
);
142 putdef(line
, " -DWM_VERSION=", VERSION
);
144 visual
= DefaultVisual(dpy
, DefaultScreen(dpy
));
145 putidef(line
, " -DVISUAL=", visual
->class);
147 putidef(line
, " -DDEPTH=", DefaultDepth(dpy
, DefaultScreen(dpy
)));
149 putidef(line
, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy
)));
150 putidef(line
, " -DSCR_HEIGHT=",
151 HeightOfScreen(DefaultScreenOfDisplay(dpy
)));
154 strcpy(buffer
, path
);
155 buf
= strrchr(buffer
, '/');
156 if (buf
) *buf
= 0; /* trunc filename */
157 putdef(line
, " -I", buffer
);
162 /* this should be done just once, but it works this way */
163 strcpy(buffer
, DEF_CONFIG_PATHS
);
164 buf
= strtok(buffer
, ":");
167 char fullpath
[MAXLINE
];
170 strcpy(fullpath
, buf
);
172 char * wgethomedir();
173 /* home is statically allocated. Don't free it! */
174 char *home
= wgethomedir();
176 strcpy(fullpath
, home
);
177 strcat(fullpath
, &(buf
[1]));
180 putdef(line
, " -I", fullpath
);
182 } while ((buf
= strtok(NULL
, ":"))!=NULL
);
196 NextFocusWindow(WScreen
*scr
)
198 WWindow
*tmp
, *wwin
, *closest
, *min
;
201 if (!(wwin
= scr
->focused_window
))
208 if (wWindowCanReceiveFocus(tmp
)
209 && (!WFLAGP(tmp
, skip_window_list
)|| tmp
->flags
.internal_window
)) {
210 if (min
->client_win
> tmp
->client_win
)
212 if (tmp
->client_win
> wwin
->client_win
214 || (tmp
->client_win
- wwin
->client_win
) < d
)) {
216 d
= tmp
->client_win
- wwin
->client_win
;
221 if (!closest
||closest
==wwin
)
228 PrevFocusWindow(WScreen
*scr
)
230 WWindow
*tmp
, *wwin
, *closest
, *max
;
233 if (!(wwin
= scr
->focused_window
))
240 if (wWindowCanReceiveFocus(tmp
) &&
241 (!WFLAGP(tmp
, skip_window_list
) || tmp
->flags
.internal_window
)) {
242 if (max
->client_win
< tmp
->client_win
)
244 if (tmp
->client_win
< wwin
->client_win
246 || (wwin
->client_win
- tmp
->client_win
) < d
)) {
248 d
= wwin
->client_win
- tmp
->client_win
;
253 if (!closest
||closest
==wwin
)
262 * Is win2 below win1?
265 isBelow(WWindow
*win1
, WWindow
*win2
)
270 tmp
= win1
->frame
->core
->stacking
->under
;
272 if (tmp
== win2
->frame
->core
)
274 tmp
= tmp
->stacking
->under
;
277 for (i
=win1
->frame
->core
->stacking
->window_level
-1; i
>=0; i
--) {
278 tmp
= win1
->screen_ptr
->stacking_list
[i
];
280 if (tmp
== win2
->frame
->core
)
282 tmp
= tmp
->stacking
->under
;
295 Bool
wFetchName(dpy
, win
, winname
)
300 XTextProperty text_prop
;
304 if (XGetWMName(dpy
, win
, &text_prop
)) {
305 if (text_prop
.value
&& text_prop
.nitems
> 0) {
306 if (text_prop
.encoding
== XA_STRING
) {
307 *winname
= wstrdup((char *)text_prop
.value
);
308 XFree(text_prop
.value
);
310 text_prop
.nitems
= strlen((char *)text_prop
.value
);
311 if (XmbTextPropertyToTextList(dpy
, &text_prop
, &list
, &num
) >=
312 Success
&& num
> 0 && *list
) {
313 XFree(text_prop
.value
);
314 *winname
= wstrdup(*list
);
315 XFreeStringList(list
);
317 *winname
= wstrdup((char *)text_prop
.value
);
318 XFree(text_prop
.value
);
322 /* the title is set, but it was set to none */
323 *winname
= wstrdup("");
327 /* the hint is probably not set */
335 * XGetIconName Wrapper
339 Bool
wGetIconName(dpy
, win
, iconname
)
344 XTextProperty text_prop
;
348 if (XGetWMIconName(dpy
, win
, &text_prop
) != 0 && text_prop
.value
349 && text_prop
.nitems
> 0) {
350 if (text_prop
.encoding
== XA_STRING
)
351 *iconname
= (char *)text_prop
.value
;
353 text_prop
.nitems
= strlen((char *)text_prop
.value
);
354 if (XmbTextPropertyToTextList(dpy
, &text_prop
, &list
, &num
) >=
355 Success
&& num
> 0 && *list
) {
356 XFree(text_prop
.value
);
357 *iconname
= wstrdup(*list
);
358 XFreeStringList(list
);
360 *iconname
= (char *)text_prop
.value
;
372 wTextWidth(XFontSet font
, char *text
, int length
)
377 XmbTextExtents(font
, text
, length
, &AIXsucks
, &rec
);
383 wTextWidth(XFontStruct
*font
, char *text
, int length
)
385 return XTextWidth(font
, text
, length
);
395 /* compress all expose events into a single one */
397 if (XCheckMaskEvent(dpy
, ExposureMask
, &event
)) {
398 /* ignore other exposure events for this window */
399 while (XCheckWindowEvent(dpy
, event
.xexpose
.window
, ExposureMask
,
401 /* eat exposes for other windows */
404 event
.xexpose
.count
= 0;
405 XPutBackEvent(dpy
, &event
);
411 SlideWindow(Window win
, int from_x
, int from_y
, int to_x
, int to_y
)
413 time_t time0
= time(NULL
);
414 float dx
, dy
, x
=from_x
, y
=from_y
, sx
, sy
, px
, py
;
417 /* animation parameters */
423 {ICON_SLIDE_DELAY_UF
, ICON_SLIDE_STEPS_UF
, ICON_SLIDE_SLOWDOWN_UF
},
424 {ICON_SLIDE_DELAY_F
, ICON_SLIDE_STEPS_F
, ICON_SLIDE_SLOWDOWN_F
},
425 {ICON_SLIDE_DELAY_M
, ICON_SLIDE_STEPS_M
, ICON_SLIDE_SLOWDOWN_M
},
426 {ICON_SLIDE_DELAY_S
, ICON_SLIDE_STEPS_S
, ICON_SLIDE_SLOWDOWN_S
},
427 {ICON_SLIDE_DELAY_U
, ICON_SLIDE_STEPS_U
, ICON_SLIDE_SLOWDOWN_U
}};
431 dx
= (float)(to_x
-from_x
);
432 dy
= (float)(to_y
-from_y
);
433 sx
= (dx
== 0 ? 0 : fabs(dx
)/dx
);
434 sy
= (dy
== 0 ? 0 : fabs(dy
)/dy
);
436 if (fabs(dx
) > fabs(dy
)) {
441 px
= dx
/ apars
[(int)wPreferences
.icon_slide_speed
].slowdown
;
442 if (px
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
> 0)
443 px
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
444 else if (px
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
< 0)
445 px
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
446 py
= (sx
== 0 ? 0 : px
*dy
/dx
);
448 py
= dy
/ apars
[(int)wPreferences
.icon_slide_speed
].slowdown
;
449 if (py
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
> 0)
450 py
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
451 else if (py
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
< 0)
452 py
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
453 px
= (sy
== 0 ? 0 : py
*dx
/dy
);
456 while (x
!= to_x
|| y
!= to_y
) {
459 if ((px
<0 && (int)x
< to_x
) || (px
>0 && (int)x
> to_x
))
461 if ((py
<0 && (int)y
< to_y
) || (py
>0 && (int)y
> to_y
))
465 px
= px
* (1.0 - 1/(float)apars
[(int)wPreferences
.icon_slide_speed
].slowdown
);
466 if (px
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
> 0)
467 px
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
468 else if (px
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& px
< 0)
469 px
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
470 py
= (sx
== 0 ? 0 : px
*dy
/dx
);
472 py
= py
* (1.0 - 1/(float)apars
[(int)wPreferences
.icon_slide_speed
].slowdown
);
473 if (py
< apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
> 0)
474 py
= apars
[(int)wPreferences
.icon_slide_speed
].steps
;
475 else if (py
> -apars
[(int)wPreferences
.icon_slide_speed
].steps
&& py
< 0)
476 py
= -apars
[(int)wPreferences
.icon_slide_speed
].steps
;
477 px
= (sy
== 0 ? 0 : py
*dx
/dy
);
480 XMoveWindow(dpy
, win
, (int)x
, (int)y
);
482 if (apars
[(int)wPreferences
.icon_slide_speed
].delay
> 0) {
483 wusleep(apars
[(int)wPreferences
.icon_slide_speed
].delay
*1000L);
485 if (time(NULL
) - time0
> MAX_ANIMATION_TIME
)
488 XMoveWindow(dpy
, win
, to_x
, to_y
);
491 /* compress expose events */
497 ShrinkString(WFont
*font
, char *string
, int width
)
508 return wstrdup(string
);
511 w
= wTextWidth(font
->font
, string
, p
);
512 text
= wmalloc(strlen(string
)+8);
513 strcpy(text
, string
);
517 pos
= strchr(text
, ' ');
519 pos
= strchr(text
, ':');
524 w1
=wTextWidth(font
->font
, text
, p
);
541 width
-= wTextWidth(font
->font
, "...", 3);
547 while (p2
>p1
&& p1
!=t
) {
548 w
= wTextWidth(font
->font
, &string
[p
-t
], t
);
552 } else if (w
<width
) {
558 strcat(text
, &string
[p
-p1
]);
565 FindImage(char *paths
, char *file
)
569 tmp
= strrchr(file
, ':');
572 path
= wfindfile(paths
, file
);
576 path
= wfindfile(paths
, file
);
584 FlattenStringList(char **list
, int count
)
587 char *flat_string
, *wspace
;
590 for (i
=0; i
<count
; i
++) {
591 if (list
[i
]!=NULL
&& list
[i
][0]!=0) {
592 j
+= strlen(list
[i
]);
593 if (strpbrk(list
[i
], " \t"))
598 flat_string
= malloc(j
+count
+1);
604 for (i
=0; i
<count
; i
++) {
605 if (list
[i
]!=NULL
&& list
[i
][0]!=0) {
607 strcat(flat_string
, " ");
608 wspace
= strpbrk(list
[i
], " \t");
610 strcat(flat_string
, "\"");
611 strcat(flat_string
, list
[i
]);
613 strcat(flat_string
, "\"");
623 *----------------------------------------------------------------------
625 * Divides a command line into a argv/argc pair.
626 *----------------------------------------------------------------------
641 static DFA mtable
[9][6] = {
642 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
643 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
644 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
645 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
646 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
647 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
648 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
649 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
650 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
654 next_token(char *word
, char **next
)
660 t
= ret
= wmalloc(strlen(word
)+1);
674 else if (*ptr
==' ' || *ptr
=='\t')
679 if (mtable
[state
][ctype
].output
) {
683 state
= mtable
[state
][ctype
].nstate
;
685 if (mtable
[state
][0].output
<0) {
707 ParseCommand(char *command
, char ***argv
, int *argc
)
709 LinkedList
*list
= NULL
;
715 token
= next_token(line
, &line
);
717 list
= list_cons(token
, list
);
719 } while (token
!=NULL
&& line
!=NULL
);
721 count
= list_length(list
);
722 *argv
= wmalloc(sizeof(char*)*count
);
725 (*argv
)[--i
] = list
->head
;
726 list_remove_head(&list
);
739 getselection(WScreen
*scr
)
742 extern char *W_GetTextSelection(); /* in WINGs */
744 tmp
= W_GetTextSelection(scr
->wmscreen
, XA_PRIMARY
);
746 tmp
= W_GetTextSelection(scr
->wmscreen
, XA_CUT_BUFFER0
);
755 puts("getting selection");
757 RequestSelection(dpy
, scr
->no_focus_win
, LastTimestamp
);
758 /* timeout on 1 sec. */
759 id
= WMAddTimerHandler(1000, timeup
, &timeover
);
761 WMNextEvent(dpy
, &event
);
762 if (event
.type
== SelectionNotify
763 && event
.xany
.window
==scr
->no_focus_win
) {
764 WMDeleteTimerHandler(id
);
766 puts("selection ok");
768 return GetSelection(dpy
, scr
->no_focus_win
);
770 WMHandleEvent(&event
);
773 wwarning(_("selection timed-out"));
780 getuserinput(WScreen
*scr
, char *line
, int *ptr
)
786 char tbuffer
[256], pbuffer
[256];
788 title
= _("Program Arguments");
789 prompt
= _("Enter command arguments:");
799 for (; line
[*ptr
]==0 && state
!=_DONE
; *ptr
++) {
802 if (line
[*ptr
]=='(') {
810 if (j
<= 0 && line
[*ptr
]==',') {
814 strncpy(tbuffer
, &line
[1], WMIN(*ptr
, 255));
815 tbuffer
[WMIN(*ptr
, 255)] = 0;
816 title
= (char*)tbuffer
;
821 } else if (j
<= 0 && line
[*ptr
]==')') {
824 strncpy(tbuffer
, &line
[1], WMIN(*ptr
, 255));
825 tbuffer
[WMIN(*ptr
, 255)] = 0;
826 title
= (char*)tbuffer
;
830 } else if (line
[*ptr
]=='(')
832 else if (line
[*ptr
]==')')
838 if (line
[*ptr
]==')' && j
==0) {
841 strncpy(pbuffer
, &line
[k
], WMIN(*ptr
-k
, 255));
842 pbuffer
[WMIN(*ptr
-k
, 255)] = 0;
843 title
= (char*)pbuffer
;
846 } else if (line
[*ptr
]=='(')
848 else if (line
[*ptr
]==')')
858 if (!wInputDialog(scr
, title
, prompt
, &ret
))
867 get_dnd_selection(WScreen
*scr
)
869 XTextProperty text_ret
;
877 return (wstrdup(scr
->xdestring
));
880 result
=XGetTextProperty(dpy
, scr
->root_win
, &text_ret
, _XA_DND_SELECTION
);
882 if (result
==0 || text_ret
.value
==NULL
|| text_ret
.encoding
==None
883 || text_ret
.format
==0 || text_ret
.nitems
== 0) {
884 wwarning(_("unable to get dropped data from DND drop"));
888 XTextPropertyToStringList(&text_ret
, &list
, &count
);
890 if (!list
|| count
<1) {
891 XFree(text_ret
.value
);
892 wwarning(_("error getting dropped data from DND drop"));
896 flat_string
= FlattenStringList(list
, count
);
898 wwarning(_("out of memory while getting data from DND drop"));
901 XFreeStringList(list
);
902 XFree(text_ret
.value
);
905 #endif /* OFFIX_DND */
913 * state input new-state output
914 * NORMAL % OPTION <nil>
915 * NORMAL \ ESCAPE <nil>
916 * NORMAL etc. NORMAL <input>
917 * ESCAPE any NORMAL <input>
918 * OPTION s NORMAL <selection buffer>
919 * OPTION w NORMAL <selected window id>
920 * OPTION a NORMAL <input text>
921 * OPTION d NORMAL <OffiX DND selection object>
922 * OPTION etc. NORMAL %<input>
924 #define TMPBUFSIZE 64
926 ExpandOptions(WScreen
*scr
, char *cmdline
)
928 int ptr
, optr
, state
, len
, olen
;
930 char *selection
=NULL
;
931 char *user_input
=NULL
;
933 char *dropped_thing
=NULL
;
935 char tmpbuf
[TMPBUFSIZE
];
938 len
= strlen(cmdline
);
942 wwarning(_("out of memory during expansion of \"%s\""));
946 ptr
= 0; /* input line pointer */
947 optr
= 0; /* output line pointer */
952 switch (cmdline
[ptr
]) {
961 out
[optr
++]=cmdline
[ptr
];
966 switch (cmdline
[ptr
]) {
980 out
[optr
++]=cmdline
[ptr
];
986 switch (cmdline
[ptr
]) {
988 if (scr
->focused_window
989 && scr
->focused_window
->flags
.focused
) {
990 sprintf(tmpbuf
, "0x%x",
991 (unsigned int)scr
->focused_window
->client_win
);
992 slen
= strlen(tmpbuf
);
994 nout
= realloc(out
,olen
);
996 wwarning(_("out of memory during expansion of \"%w\""));
1009 user_input
= getuserinput(scr
, cmdline
, &ptr
);
1011 slen
= strlen(user_input
);
1013 nout
= realloc(out
,olen
);
1015 wwarning(_("out of memory during expansion of \"%a\""));
1019 strcat(out
,user_input
);
1022 /* Not an error, but user has Canceled the dialog box.
1023 * This will make the command to not be performed. */
1030 if (!dropped_thing
) {
1031 dropped_thing
= get_dnd_selection(scr
);
1033 if (!dropped_thing
) {
1034 scr
->flags
.dnd_data_convertion_status
= 1;
1037 slen
= strlen(dropped_thing
);
1039 nout
= realloc(out
,olen
);
1041 wwarning(_("out of memory during expansion of \"%d\""));
1045 strcat(out
,dropped_thing
);
1048 #endif /* OFFIX_DND */
1052 selection
= getselection(scr
);
1055 wwarning(_("selection not available"));
1058 slen
= strlen(selection
);
1060 nout
= realloc(out
,olen
);
1062 wwarning(_("out of memory during expansion of \"%s\""));
1066 strcat(out
,selection
);
1071 out
[optr
++]=cmdline
[ptr
];
1090 /* We don't care for upper/lower case in comparing the keys; so we
1091 have to define our own comparison function here */
1093 StringCompareHook(proplist_t pl1
, proplist_t pl2
)
1097 str1
= PLGetString(pl1
);
1098 str2
= PLGetString(pl2
);
1100 if (strcasecmp(str1
, str2
)==0)
1107 /* feof doesn't seem to work on pipes */
1109 IsEof(FILE * stream
)
1111 static struct stat stinfo
;
1113 fstat(fileno(stream
), &stinfo
);
1114 return ((S_ISFIFO(stinfo
.st_dev
) && stinfo
.st_size
== 0) ||
1120 ParseWindowName(proplist_t value
, char **winstance
, char **wclass
, char *where
)
1124 *winstance
= *wclass
= NULL
;
1126 if (!PLIsString(value
)) {
1127 wwarning(_("bad window name value in %s state info"), where
);
1131 name
= PLGetString(value
);
1132 if (!name
|| strlen(name
)==0) {
1133 wwarning(_("bad window name value in %s state info"), where
);
1137 UnescapeWM_CLASS(name
, winstance
, wclass
);
1143 keysymToString(KeySym keysym
, unsigned int state
)
1146 char *buf
= wmalloc(20);
1150 kev
.type
= KeyPress
;
1151 kev
.send_event
= False
;
1152 kev
.window
= DefaultRootWindow(dpy
);
1153 kev
.root
= DefaultRootWindow(dpy
);
1154 kev
.same_screen
= True
;
1155 kev
.subwindow
= kev
.root
;
1156 kev
.serial
= 0x12344321;
1157 kev
.time
= CurrentTime
;
1159 kev
.keycode
= XKeysymToKeycode(dpy
, keysym
);
1160 count
= XLookupString(&kev
, buf
, 19, NULL
, NULL
);
1168 GetShortcutString(char *text
)
1170 char *buffer
= NULL
;
1177 tmp
= text
= wstrdup(text
);
1180 while ((k
= strchr(text
, '+'))!=NULL
) {
1184 mod
= wXModifierFromKey(text
);
1186 return wstrdup("bug");
1191 if (strcasecmp(text
, "Meta")==0) {
1192 buffer
= wstrappend(buffer
, "M+");
1193 } else if (strcasecmp(text
, "Alt")==0) {
1194 buffer
= wstrappend(buffer
, "A+");
1195 } else if (strcasecmp(text
, "Shift")==0) {
1196 buffer
= wstrappend(buffer
, "Sh+");
1197 } else if (strcasecmp(text
, "Mod1")==0) {
1198 buffer
= wstrappend(buffer
, "M1+");
1199 } else if (strcasecmp(text
, "Mod2")==0) {
1200 buffer
= wstrappend(buffer
, "M2+");
1201 } else if (strcasecmp(text
, "Mod3")==0) {
1202 buffer
= wstrappend(buffer
, "M3+");
1203 } else if (strcasecmp(text
, "Mod4")==0) {
1204 buffer
= wstrappend(buffer
, "M4+");
1205 } else if (strcasecmp(text
, "Mod5")==0) {
1206 buffer
= wstrappend(buffer
, "M5+");
1207 } else if (strcasecmp(text
, "Control")==0) {
1210 buffer
= wstrappend(buffer
, text
);
1216 buffer
= wstrappend(buffer
, "^");
1218 buffer
= wstrappend(buffer
, text
);
1221 /* ksym = XStringToKeysym(text);
1222 tmp = keysymToString(ksym, modmask);
1224 buffer = wstrappend(buffer, tmp);
1233 EscapeWM_CLASS(char *name
, char *class)
1236 char *ename
= NULL
, *eclass
= NULL
;
1239 if (!name
&& !class)
1244 ename
= wmalloc(l
*2);
1246 for (i
=0; i
<l
; i
++) {
1247 if (name
[i
]=='\\') {
1249 } else if (name
[i
]=='.') {
1252 ename
[j
++] = name
[i
];
1258 eclass
= wmalloc(l
*2);
1260 for (i
=0; i
<l
; i
++) {
1261 if (class[i
]=='\\') {
1263 } else if (class[i
]=='.') {
1266 eclass
[j
++] = class[i
];
1271 if (ename
&& eclass
) {
1272 ret
= wmalloc(strlen(ename
)+strlen(eclass
)+4);
1273 sprintf(ret
, "%s.%s", ename
, eclass
);
1277 ret
= wstrdup(ename
);
1280 ret
= wstrdup(eclass
);
1289 UnescapeWM_CLASS(char *str
, char **name
, char **class)
1297 *class = wmalloc(j
);
1300 /* separate string in 2 parts */
1303 for (i
= 0; i
< j
; i
++) {
1307 } else if (str
[i
]=='.') {
1316 /* unescape strings */
1319 for (i
= 0; i
< dot
; i
++) {
1324 (*name
)[k
++] = str
[i
];
1334 for (i
= dot
+1; i
<j
; i
++) {
1339 (*class)[k
++] = str
[i
];
1360 SendHelperMessage(WScreen
*scr
, char type
, int workspace
, char *msg
)
1362 unsigned char *buffer
;
1367 if (!scr
->flags
.backimage_helper_launched
) {
1371 len
= (msg
? strlen(msg
) : 0) + (workspace
>=0 ? 4 : 0) + 1 ;
1372 buffer
= wmalloc(len
+5);
1373 sprintf(buf
, "%4i", len
);
1374 memcpy(buffer
, buf
, 4);
1377 if (workspace
>= 0) {
1378 sprintf(buf
, "%4i", workspace
);
1379 memcpy(&buffer
[i
], buf
, 4);
1384 strcpy(&buffer
[i
], msg
);
1386 if (write(scr
->helper_fd
, buffer
, len
+4) < 0) {
1387 wsyserror(_("could not send message to background image helper"));
1394 ExecuteShellCommand(WScreen
*scr
, char *command
)
1396 static char *shell
= NULL
;
1400 * This have a problem: if the shell is tcsh (not sure about others)
1401 * and ~/.tcshrc have /bin/stty erase ^H somewhere on it, the shell
1402 * will block and the command will not be executed.
1404 shell = getenv("SHELL");
1414 SetupEnvironment(scr
);
1419 execl(shell
, shell
, "-c", command
, NULL
);
1420 wsyserror("could not execute %s -c %s", shell
, command
);
1422 } else if (pid
< 0) {
1423 wsyserror("cannot fork a new process");