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>
40 #include "WindowMaker.h"
50 #include "xmodifier.h"
53 /**** global variables *****/
55 extern char *DisplayName
;
57 extern WPreferences wPreferences
;
59 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
;
121 line
= wmalloc(MAXLINE
);
124 if ((buf
=getenv("HOSTNAME"))!=NULL
) {
126 wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"),
129 putdef(line
, " -DHOST=", buf
);
130 } else if ((buf
=getenv("HOST"))!=NULL
) {
132 wwarning(_("your machine is misconfigured. HOST is set to %s"),
135 putdef(line
, " -DHOST=", 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
158 buf
= strchr(tmp
+1, ' ');
162 buf
= strrchr(tmp
, '/');
164 *buf
= 0; /* trunc filename */
165 putdef(line
, " -I", tmp
);
171 /* this should be done just once, but it works this way */
172 strcpy(buffer
, DEF_CONFIG_PATHS
);
173 buf
= strtok(buffer
, ":");
176 char fullpath
[MAXLINE
];
179 strcpy(fullpath
, buf
);
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
);
207 NextToFocusAfter(WWindow
*wwin
)
209 WWindow
*tmp
= wwin
->prev
;
212 if (wWindowCanReceiveFocus(tmp
) && !WFLAGP(tmp
, skip_window_list
)) {
219 /* start over from the beginning of the list */
223 while (tmp
&& tmp
!= wwin
) {
224 if (wWindowCanReceiveFocus(tmp
) && !WFLAGP(tmp
, skip_window_list
)) {
235 NextToFocusBefore(WWindow
*wwin
)
237 WWindow
*tmp
= wwin
->next
;
240 if (wWindowCanReceiveFocus(tmp
) && !WFLAGP(tmp
, skip_window_list
)) {
246 /* start over from the beginning of the list */
251 while (tmp
&& tmp
!= wwin
) {
252 if (wWindowCanReceiveFocus(tmp
) && !WFLAGP(tmp
, skip_window_list
)) {
265 * Is win2 below win1?
268 isBelow(WWindow
*win1
, WWindow
*win2
)
273 tmp
= win1
->frame
->core
->stacking
->under
;
275 if (tmp
== win2
->frame
->core
)
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
];
283 if (tmp
== win2
->frame
->core
)
285 tmp
= tmp
->stacking
->under
;
298 Bool
wFetchName(dpy
, win
, winname
)
303 XTextProperty text_prop
;
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
);
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
);
320 *winname
= wstrdup((char *)text_prop
.value
);
321 XFree(text_prop
.value
);
325 /* the title is set, but it was set to none */
326 *winname
= wstrdup("");
330 /* the hint is probably not set */
338 * XGetIconName Wrapper
342 Bool
wGetIconName(dpy
, win
, iconname
)
347 XTextProperty text_prop
;
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
;
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
);
363 *iconname
= (char *)text_prop
.value
;
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
,
383 /* eat exposes for other windows */
386 event
.xexpose
.count
= 0;
387 XPutBackEvent(dpy
, &event
);
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
;
399 /* animation parameters */
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
)) {
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
);
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
) {
441 if ((px
<0 && (int)x
< to_x
) || (px
>0 && (int)x
> to_x
))
443 if ((py
<0 && (int)y
< to_y
) || (py
>0 && (int)y
> to_y
))
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
);
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
);
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
)
470 XMoveWindow(dpy
, win
, to_x
, to_y
);
473 /* compress expose events */
479 ShrinkString(WMFont
*font
, char *string
, int width
)
487 if (wPreferences
.multi_byte_text
)
488 return wstrdup(string
);
491 w
= WMWidthOfString(font
, string
, p
);
492 text
= wmalloc(strlen(string
)+8);
493 strcpy(text
, string
);
497 pos
= strchr(text
, ' ');
499 pos
= strchr(text
, ':');
504 w1
= WMWidthOfString(font
, text
, p
);
521 width
-= WMWidthOfString(font
, "...", 3);
527 while (p2
>p1
&& p1
!=t
) {
528 w
= WMWidthOfString(font
, &string
[p
-t
], t
);
532 } else if (w
<width
) {
538 strcat(text
, &string
[p
-p1
]);
545 FindImage(char *paths
, char *file
)
549 tmp
= strrchr(file
, ':');
552 path
= wfindfile(paths
, file
);
556 path
= wfindfile(paths
, file
);
564 FlattenStringList(char **list
, int count
)
567 char *flat_string
, *wspace
;
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"))
578 flat_string
= malloc(j
+count
+1);
584 for (i
=0; i
<count
; i
++) {
585 if (list
[i
]!=NULL
&& list
[i
][0]!=0) {
587 strcat(flat_string
, " ");
588 wspace
= strpbrk(list
[i
], " \t");
590 strcat(flat_string
, "\"");
591 strcat(flat_string
, list
[i
]);
593 strcat(flat_string
, "\"");
603 *----------------------------------------------------------------------
605 * Divides a command line into a argv/argc pair.
606 *----------------------------------------------------------------------
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 */
634 next_token(char *word
, char **next
)
640 t
= ret
= wmalloc(strlen(word
)+1);
654 else if (*ptr
==' ' || *ptr
=='\t')
659 if (mtable
[state
][ctype
].output
) {
663 state
= mtable
[state
][ctype
].nstate
;
665 if (mtable
[state
][0].output
<0) {
687 ParseCommand(char *command
, char ***argv
, int *argc
)
689 WMBag
*bag
= WMCreateBag(4);
695 token
= next_token(line
, &line
);
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
);
713 timeoutHandler(void *data
)
720 getTextSelection(WScreen
*screen
, Atom selection
)
754 data
= XFetchBuffer(dpy
, &size
, buffer
);
761 unsigned long len
, bytes
;
765 static Atom clipboard
= 0;
768 clipboard
= XInternAtom(dpy
, "CLIPBOARD", False
);
770 XDeleteProperty(dpy
, screen
->info_window
, clipboard
);
772 XConvertSelection(dpy
, selection
, XA_STRING
,
773 clipboard
, screen
->info_window
,
776 timer
= WMAddTimerHandler(1000, timeoutHandler
, &timeout
);
778 while (!XCheckTypedWindowEvent(dpy
, screen
->info_window
,
779 SelectionNotify
, &ev
) && !timeout
);
782 WMDeleteTimerHandler(timer
);
784 wwarning("selection retrieval timed out");
788 /* nobody owns the selection or the current owner has
789 * nothing to do with what we need */
790 if (ev
.xselection
.property
== None
) {
794 if (XGetWindowProperty(dpy
, screen
->info_window
,
796 False
, XA_STRING
, &rtype
, &bits
, &len
,
797 &bytes
, (unsigned char**)&data
)!=Success
) {
800 if (rtype
!=XA_STRING
|| bits
!=8) {
801 wwarning("invalid data in text selection");
811 getselection(WScreen
*scr
)
815 tmp
= getTextSelection(scr
, XA_PRIMARY
);
817 tmp
= getTextSelection(scr
, XA_CUT_BUFFER0
);
823 getuserinput(WScreen
*scr
, char *line
, int *ptr
)
830 char tbuffer
[256], pbuffer
[256];
832 title
= _("Program Arguments");
833 prompt
= _("Enter command arguments:");
843 for (; line
[*ptr
]!=0 && state
!=_DONE
; (*ptr
)++) {
846 if (line
[*ptr
]=='(') {
855 if (j
<= 0 && line
[*ptr
]==',') {
859 strncpy(tbuffer
, &line
[begin
], WMIN(*ptr
-begin
, 255));
860 tbuffer
[WMIN(*ptr
-begin
, 255)] = 0;
861 title
= (char*)tbuffer
;
866 } else if (j
<= 0 && line
[*ptr
]==')') {
869 strncpy(tbuffer
, &line
[begin
], WMIN(*ptr
-begin
, 255));
870 tbuffer
[WMIN(*ptr
-begin
, 255)] = 0;
871 title
= (char*)tbuffer
;
875 } else if (line
[*ptr
]=='(') {
877 } else if (line
[*ptr
]==')') {
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
;
892 } else if (line
[*ptr
]=='(')
894 else if (line
[*ptr
]==')')
905 if (!wInputDialog(scr
, title
, prompt
, &ret
))
914 get_dnd_selection(WScreen
*scr
)
916 XTextProperty text_ret
;
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"));
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"));
938 flat_string
= FlattenStringList(list
, count
);
940 wwarning(_("out of memory while getting data from DND drop"));
943 XFreeStringList(list
);
944 XFree(text_ret
.value
);
947 #endif /* OFFIX_DND */
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
969 ExpandOptions(WScreen
*scr
, char *cmdline
)
971 int ptr
, optr
, state
, len
, olen
;
973 char *selection
=NULL
;
974 char *user_input
=NULL
;
975 #if defined(OFFIX_DND) || defined(XDND)
976 char *dropped_thing
=NULL
;
978 char tmpbuf
[TMPBUFSIZE
];
981 len
= strlen(cmdline
);
985 wwarning(_("out of memory during expansion of \"%s\""));
989 ptr
= 0; /* input line pointer */
990 optr
= 0; /* output line pointer */
995 switch (cmdline
[ptr
]) {
1004 out
[optr
++]=cmdline
[ptr
];
1009 switch (cmdline
[ptr
]) {
1023 out
[optr
++]=cmdline
[ptr
];
1029 switch (cmdline
[ptr
]) {
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
);
1037 nout
= realloc(out
,olen
);
1039 wwarning(_("out of memory during expansion of \"%w\""));
1051 sprintf(tmpbuf
, "0x%x",
1052 (unsigned int)scr
->current_workspace
+ 1);
1053 slen
= strlen(tmpbuf
);
1055 nout
= realloc(out
,olen
);
1057 wwarning(_("out of memory during expansion of \"%W\""));
1067 user_input
= getuserinput(scr
, cmdline
, &ptr
);
1069 slen
= strlen(user_input
);
1071 nout
= realloc(out
,olen
);
1073 wwarning(_("out of memory during expansion of \"%a\""));
1077 strcat(out
,user_input
);
1080 /* Not an error, but user has Canceled the dialog box.
1081 * This will make the command to not be performed. */
1086 #if defined(OFFIX_DND) || defined(XDND)
1089 if(scr
->xdestring
) {
1090 dropped_thing
= wstrdup(scr
->xdestring
);
1093 if (!dropped_thing
) {
1094 dropped_thing
= get_dnd_selection(scr
);
1096 if (!dropped_thing
) {
1097 scr
->flags
.dnd_data_convertion_status
= 1;
1100 slen
= strlen(dropped_thing
);
1102 nout
= realloc(out
,olen
);
1104 wwarning(_("out of memory during expansion of \"%d\""));
1108 strcat(out
,dropped_thing
);
1111 #endif /* OFFIX_DND */
1115 selection
= getselection(scr
);
1118 wwarning(_("selection not available"));
1121 slen
= strlen(selection
);
1123 nout
= realloc(out
,olen
);
1125 wwarning(_("out of memory during expansion of \"%s\""));
1129 strcat(out
,selection
);
1135 out
[optr
++]=cmdline
[ptr
];
1154 /* We don't care for upper/lower case in comparing the keys; so we
1155 have to define our own comparison function here */
1157 StringCompareHook(proplist_t pl1
, proplist_t pl2
)
1161 str1
= PLGetString(pl1
);
1162 str2
= PLGetString(pl2
);
1164 if (strcasecmp(str1
, str2
)==0)
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) ||
1184 ParseWindowName(proplist_t value
, char **winstance
, char **wclass
, char *where
)
1188 *winstance
= *wclass
= NULL
;
1190 if (!PLIsString(value
)) {
1191 wwarning(_("bad window name value in %s state info"), where
);
1195 name
= PLGetString(value
);
1196 if (!name
|| strlen(name
)==0) {
1197 wwarning(_("bad window name value in %s state info"), where
);
1201 UnescapeWM_CLASS(name
, winstance
, wclass
);
1207 keysymToString(KeySym keysym
, unsigned int state
)
1210 char *buf
= wmalloc(20);
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
;
1223 kev
.keycode
= XKeysymToKeycode(dpy
, keysym
);
1224 count
= XLookupString(&kev
, buf
, 19, NULL
, NULL
);
1232 appendrealloc(char *a
, char *b
)
1237 char *c
= wstrappend(a
, b
);
1245 GetShortcutString(char *text
)
1247 char *buffer
= NULL
;
1254 tmp
= text
= wstrdup(text
);
1257 while ((k
= strchr(text
, '+'))!=NULL
) {
1261 mod
= wXModifierFromKey(text
);
1263 return wstrdup("bug");
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) {
1287 buffer
= appendrealloc(buffer
, text
);
1293 buffer
= appendrealloc(buffer
, "^");
1295 buffer
= appendrealloc(buffer
, text
);
1298 /* ksym = XStringToKeysym(text);
1299 tmp = keysymToString(ksym, modmask);
1301 buffer = wstrappend(buffer, tmp);
1310 EscapeWM_CLASS(char *name
, char *class)
1313 char *ename
= NULL
, *eclass
= NULL
;
1316 if (!name
&& !class)
1321 ename
= wmalloc(l
*2);
1323 for (i
=0; i
<l
; i
++) {
1324 if (name
[i
]=='\\') {
1326 } else if (name
[i
]=='.') {
1329 ename
[j
++] = name
[i
];
1335 eclass
= wmalloc(l
*2);
1337 for (i
=0; i
<l
; i
++) {
1338 if (class[i
]=='\\') {
1340 } else if (class[i
]=='.') {
1343 eclass
[j
++] = class[i
];
1348 if (ename
&& eclass
) {
1349 ret
= wmalloc(strlen(ename
)+strlen(eclass
)+4);
1350 sprintf(ret
, "%s.%s", ename
, eclass
);
1354 ret
= wstrdup(ename
);
1357 ret
= wstrdup(eclass
);
1366 UnescapeWM_CLASS(char *str
, char **name
, char **class)
1374 *class = wmalloc(j
);
1377 /* separate string in 2 parts */
1380 for (i
= 0; i
< j
; i
++) {
1384 } else if (str
[i
]=='.') {
1393 /* unescape strings */
1396 for (i
= 0; i
< dot
; i
++) {
1401 (*name
)[k
++] = str
[i
];
1404 (*name
)[k
++] = str
[i
];
1412 for (i
= dot
+1; i
<j
; i
++) {
1417 (*class)[k
++] = str
[i
];
1438 SendHelperMessage(WScreen
*scr
, char type
, int workspace
, char *msg
)
1440 unsigned char *buffer
;
1445 if (!scr
->flags
.backimage_helper_launched
) {
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);
1455 if (workspace
>= 0) {
1456 sprintf(buf
, "%4i", workspace
);
1457 memcpy(&buffer
[i
], buf
, 4);
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"));