/* * Window Maker window manager * * Copyright (c) 1997, 1998 Alfredo K. Kojima * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include "wconfig.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "WindowMaker.h" #include "GNUstep.h" #include "screen.h" #include "wcore.h" #include "window.h" #include "framewin.h" #include "funcs.h" #include "defaults.h" #include "dialog.h" #include "xutil.h" #include "xmodifier.h" #include "list.h" /**** global variables *****/ extern char *DisplayName; extern WPreferences wPreferences; extern Time LastTimestamp; #ifdef OFFIX_DND extern Atom _XA_DND_SELECTION; #endif #ifdef USECPP static void putdef(char *line, char *name, char *value) { if (!value) { wwarning(_("could not define value for %s for cpp"), name); return; } strcat(line, name); strcat(line, value); } static void putidef(char *line, char *name, int value) { char tmp[64]; sprintf(tmp, "%i", value); strcat(line, name); strcat(line, tmp); } static char* username() { char *tmp; tmp = getlogin(); if (!tmp) { struct passwd *user; user = getpwuid(getuid()); if (!user) { wsyserror(_("could not get password entry for UID %i"), getuid()); return NULL; } if (!user->pw_name) { return NULL; } else { return user->pw_name; } } return tmp; } char * MakeCPPArgs(char *path) { int i; char buffer[MAXLINE], *buf, *line; Visual *visual; line = wmalloc(MAXLINE); *line = 0; i=1; if ((buf=getenv("HOSTNAME"))!=NULL) { if (buf[0]=='(') { wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"), buf); } else putdef(line, " -DHOST=", buf); } else if ((buf=getenv("HOST"))!=NULL) { if (buf[0]=='(') { wwarning(_("your machine is misconfigured. HOST is set to %s"), buf); } else putdef(line, " -DHOST=", buf); } buf = username(); if (buf) putdef(line, " -DUSER=", buf); putidef(line, " -DUID=", getuid()); buf = XDisplayName(DisplayString(dpy)); putdef(line, " -DDISPLAY=", buf); putdef(line, " -DWM_VERSION=", VERSION); visual = DefaultVisual(dpy, DefaultScreen(dpy)); putidef(line, " -DVISUAL=", visual->class); putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy))); putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy))); putidef(line, " -DSCR_HEIGHT=", HeightOfScreen(DefaultScreenOfDisplay(dpy))); #if 0 strcpy(buffer, path); buf = strrchr(buffer, '/'); if (buf) *buf = 0; /* trunc filename */ putdef(line, " -I", buffer); #endif /* this should be done just once, but it works this way */ strcpy(buffer, DEF_CONFIG_PATHS); buf = strtok(buffer, ":"); do { char fullpath[MAXLINE]; if (buf[0]!='~') { strcpy(fullpath, buf); } else { char * wgethomedir(); /* home is statically allocated. Don't free it! */ char *home = wgethomedir(); strcpy(fullpath, home); strcat(fullpath, &(buf[1])); } putdef(line, " -I", fullpath); } while ((buf = strtok(NULL, ":"))!=NULL); #undef arg #ifdef DEBUG puts("CPP ARGS"); puts(line); #endif return line; } #endif /* USECPP */ WWindow* NextFocusWindow(WScreen *scr) { WWindow *tmp, *wwin, *closest, *min; Window d; if (!(wwin = scr->focused_window)) return NULL; tmp = wwin->prev; closest = NULL; min = wwin; d = 0xffffffff; while (tmp) { if (wWindowCanReceiveFocus(tmp) && (!WFLAGP(tmp, skip_window_list)|| tmp->flags.internal_window)) { if (min->client_win > tmp->client_win) min = tmp; if (tmp->client_win > wwin->client_win && (!closest || (tmp->client_win - wwin->client_win) < d)) { closest = tmp; d = tmp->client_win - wwin->client_win; } } tmp = tmp->prev; } if (!closest||closest==wwin) return min; return closest; } WWindow* PrevFocusWindow(WScreen *scr) { WWindow *tmp, *wwin, *closest, *max; Window d; if (!(wwin = scr->focused_window)) return NULL; tmp = wwin->prev; closest = NULL; max = wwin; d = 0xffffffff; while (tmp) { if (wWindowCanReceiveFocus(tmp) && (!WFLAGP(tmp, skip_window_list) || tmp->flags.internal_window)) { if (max->client_win < tmp->client_win) max = tmp; if (tmp->client_win < wwin->client_win && (!closest || (wwin->client_win - tmp->client_win) < d)) { closest = tmp; d = wwin->client_win - tmp->client_win; } } tmp = tmp->prev; } if (!closest||closest==wwin) return max; return closest; } #if 0 /* * Is win2 below win1? */ static Bool isBelow(WWindow *win1, WWindow *win2) { int i; WCoreWindow *tmp; tmp = win1->frame->core->stacking->under; while (tmp) { if (tmp == win2->frame->core) return True; tmp = tmp->stacking->under; } for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) { tmp = win1->screen_ptr->stacking_list[i]; while (tmp) { if (tmp == win2->frame->core) return True; tmp = tmp->stacking->under; } } return True; } #endif /* * XFetchName Wrapper * */ Bool wFetchName(dpy, win, winname) Display *dpy; Window win; char **winname; { XTextProperty text_prop; char **list; int num; if (XGetWMName(dpy, win, &text_prop)) { if (text_prop.value && text_prop.nitems > 0) { if (text_prop.encoding == XA_STRING) { *winname = wstrdup((char *)text_prop.value); XFree(text_prop.value); } else { text_prop.nitems = strlen((char *)text_prop.value); if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success && num > 0 && *list) { XFree(text_prop.value); *winname = wstrdup(*list); XFreeStringList(list); } else { *winname = wstrdup((char *)text_prop.value); XFree(text_prop.value); } } } else { /* the title is set, but it was set to none */ *winname = wstrdup(""); } return True; } else { /* the hint is probably not set */ *winname = NULL; return False; } } /* * XGetIconName Wrapper * */ Bool wGetIconName(dpy, win, iconname) Display *dpy; Window win; char **iconname; { XTextProperty text_prop; char **list; int num; if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value && text_prop.nitems > 0) { if (text_prop.encoding == XA_STRING) *iconname = (char *)text_prop.value; else { text_prop.nitems = strlen((char *)text_prop.value); if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success && num > 0 && *list) { XFree(text_prop.value); *iconname = wstrdup(*list); XFreeStringList(list); } else *iconname = (char *)text_prop.value; } return True; } *iconname = NULL; return False; } #if 0 #ifdef I18N_MB void wTextWidth(XFontSet font, char *text, int length) { XRectangle rect; XRectangle AIXsucks; XmbTextExtents(font, text, length, &AIXsucks, &rec); return rect.width; } #else void wTextWidth(XFontStruct *font, char *text, int length) { return XTextWidth(font, text, length); } #endif #endif static void eatExpose() { XEvent event, foo; /* compress all expose events into a single one */ if (XCheckMaskEvent(dpy, ExposureMask, &event)) { /* ignore other exposure events for this window */ while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask, &foo)); /* eat exposes for other windows */ eatExpose(); event.xexpose.count = 0; XPutBackEvent(dpy, &event); } } void SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y) { time_t time0 = time(NULL); float dx, dy, x=from_x, y=from_y, sx, sy, px, py; int dx_is_bigger=0; /* animation parameters */ static struct { int delay; int steps; int slowdown; } apars[5] = { {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF}, {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F}, {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M}, {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S}, {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}}; dx = (float)(to_x-from_x); dy = (float)(to_y-from_y); sx = (dx == 0 ? 0 : fabs(dx)/dx); sy = (dy == 0 ? 0 : fabs(dy)/dy); if (fabs(dx) > fabs(dy)) { dx_is_bigger = 1; } if (dx_is_bigger) { px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown; if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0) px = apars[(int)wPreferences.icon_slide_speed].steps; else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0) px = -apars[(int)wPreferences.icon_slide_speed].steps; py = (sx == 0 ? 0 : px*dy/dx); } else { py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown; if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0) py = apars[(int)wPreferences.icon_slide_speed].steps; else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0) py = -apars[(int)wPreferences.icon_slide_speed].steps; px = (sy == 0 ? 0 : py*dx/dy); } while (x != to_x || y != to_y) { x += px; y += py; if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x)) x = (float)to_x; if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y)) y = (float)to_y; if (dx_is_bigger) { px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown); if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0) px = apars[(int)wPreferences.icon_slide_speed].steps; else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0) px = -apars[(int)wPreferences.icon_slide_speed].steps; py = (sx == 0 ? 0 : px*dy/dx); } else { py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown); if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0) py = apars[(int)wPreferences.icon_slide_speed].steps; else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0) py = -apars[(int)wPreferences.icon_slide_speed].steps; px = (sy == 0 ? 0 : py*dx/dy); } XMoveWindow(dpy, win, (int)x, (int)y); XFlush(dpy); if (apars[(int)wPreferences.icon_slide_speed].delay > 0) { wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L); } if (time(NULL) - time0 > MAX_ANIMATION_TIME) break; } XMoveWindow(dpy, win, to_x, to_y); XSync(dpy, 0); /* compress expose events */ eatExpose(); } char* ShrinkString(WFont *font, char *string, int width) { #ifndef I18N_MB int w, w1=0; int p; char *pos; char *text; int p1, p2, t; #endif #ifdef I18N_MB return wstrdup(string); #else p = strlen(string); w = wTextWidth(font->font, string, p); text = wmalloc(strlen(string)+8); strcpy(text, string); if (w<=width) return text; pos = strchr(text, ' '); if (!pos) pos = strchr(text, ':'); if (pos) { *pos = 0; p = strlen(text); w1=wTextWidth(font->font, text, p); if (w1>width) { w1 = 0; p = 0; *pos = ' '; *text = 0; } else { *pos = 0; width -= w1; p++; } string += p; p=strlen(string); } else { *text=0; } strcat(text, "..."); width -= wTextWidth(font->font, "...", 3); pos = string; p1=0; p2=p; t = (p2-p1)/2; while (p2>p1 && p1!=t) { w = wTextWidth(font->font, &string[p-t], t); if (w>width) { p2 = t; t = p1+(p2-p1)/2; } else if (w0) strcat(flat_string, " "); wspace = strpbrk(list[i], " \t"); if (wspace) strcat(flat_string, "\""); strcat(flat_string, list[i]); if (wspace) strcat(flat_string, "\""); } } return flat_string; } /* *---------------------------------------------------------------------- * ParseCommand -- * Divides a command line into a argv/argc pair. *---------------------------------------------------------------------- */ #define PRC_ALPHA 0 #define PRC_BLANK 1 #define PRC_ESCAPE 2 #define PRC_DQUOTE 3 #define PRC_EOS 4 #define PRC_SQUOTE 5 typedef struct { short nstate; short output; } DFA; static DFA mtable[9][6] = { {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}}, {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}}, {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}}, {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}}, {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}}, {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */ {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}}, {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}}, {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */ }; char* next_token(char *word, char **next) { char *ptr; char *ret, *t; int state, ctype; t = ret = wmalloc(strlen(word)+1); ptr = word; state = 0; *t = 0; while (1) { if (*ptr==0) ctype = PRC_EOS; else if (*ptr=='\\') ctype = PRC_ESCAPE; else if (*ptr=='"') ctype = PRC_DQUOTE; else if (*ptr=='\'') ctype = PRC_SQUOTE; else if (*ptr==' ' || *ptr=='\t') ctype = PRC_BLANK; else ctype = PRC_ALPHA; if (mtable[state][ctype].output) { *t = *ptr; t++; *t = 0; } state = mtable[state][ctype].nstate; ptr++; if (mtable[state][0].output<0) { break; } } if (*ret==0) t = NULL; else t = wstrdup(ret); free(ret); if (ctype==PRC_EOS) *next = NULL; else *next = ptr; return t; } void ParseCommand(char *command, char ***argv, int *argc) { LinkedList *list = NULL; char *token, *line; int count, i; line = command; do { token = next_token(line, &line); if (token) { list = list_cons(token, list); } } while (token!=NULL && line!=NULL); count = list_length(list); *argv = wmalloc(sizeof(char*)*count); i = count; while (list!=NULL) { (*argv)[--i] = list->head; list_remove_head(&list); } *argc = count; } #if 0 static void timeup(void *foo) { *(int*)foo=1; } #endif static char* getselection(WScreen *scr) { char *tmp; extern char *W_GetTextSelection(); /* in WINGs */ tmp = W_GetTextSelection(scr->wmscreen, XA_PRIMARY); if (!tmp) tmp = W_GetTextSelection(scr->wmscreen, XA_CUT_BUFFER0); return tmp; #if 0 XEvent event; int timeover=0; WMHandlerID *id; #ifdef DEBUG puts("getting selection"); #endif RequestSelection(dpy, scr->no_focus_win, LastTimestamp); /* timeout on 1 sec. */ id = WMAddTimerHandler(1000, timeup, &timeover); while (!timeover) { WMNextEvent(dpy, &event); if (event.type == SelectionNotify && event.xany.window==scr->no_focus_win) { WMDeleteTimerHandler(id); #ifdef DEBUG puts("selection ok"); #endif return GetSelection(dpy, scr->no_focus_win); } else { WMHandleEvent(&event); } } wwarning(_("selection timed-out")); return NULL; #endif } static char* getuserinput(WScreen *scr, char *line, int *ptr) { char *ret; char *title; char *prompt; int j, state; int begin = 0; char tbuffer[256], pbuffer[256]; title = _("Program Arguments"); prompt = _("Enter command arguments:"); ret = NULL; #define _STARTING 0 #define _TITLE 1 #define _PROMPT 2 #define _DONE 3 state = _STARTING; j = 0; for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) { switch (state) { case _STARTING: if (line[*ptr]=='(') { state = _TITLE; begin = *ptr+1; } else { state = _DONE; } break; case _TITLE: if (j <= 0 && line[*ptr]==',') { j = 0; if (*ptr > begin) { strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255)); tbuffer[WMIN(*ptr-begin, 255)] = 0; title = (char*)tbuffer; } begin = *ptr+1; state = _PROMPT; } else if (j <= 0 && line[*ptr]==')') { if (*ptr > begin) { strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255)); tbuffer[WMIN(*ptr-begin, 255)] = 0; title = (char*)tbuffer; } state = _DONE; } else if (line[*ptr]=='(') { j++; } else if (line[*ptr]==')') { j--; } break; case _PROMPT: if (line[*ptr]==')' && j==0) { if (*ptr-begin > 1) { strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255)); pbuffer[WMIN(*ptr-begin, 255)] = 0; prompt = (char*)pbuffer; } state = _DONE; } else if (line[*ptr]=='(') j++; else if (line[*ptr]==')') j--; break; } } (*ptr)--; #undef _STARTING #undef _TITLE #undef _PROMPT #undef _DONE if (!wInputDialog(scr, title, prompt, &ret)) return NULL; else return ret; } #ifdef OFFIX_DND static char* get_dnd_selection(WScreen *scr) { XTextProperty text_ret; int result; char **list; char *flat_string; int count; result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION); if (result==0 || text_ret.value==NULL || text_ret.encoding==None || text_ret.format==0 || text_ret.nitems == 0) { wwarning(_("unable to get dropped data from DND drop")); return NULL; } XTextPropertyToStringList(&text_ret, &list, &count); if (!list || count<1) { XFree(text_ret.value); wwarning(_("error getting dropped data from DND drop")); return NULL; } flat_string = FlattenStringList(list, count); if (!flat_string) { wwarning(_("out of memory while getting data from DND drop")); } XFreeStringList(list); XFree(text_ret.value); return flat_string; } #endif /* OFFIX_DND */ #define S_NORMAL 0 #define S_ESCAPE 1 #define S_OPTION 2 /* * state input new-state output * NORMAL % OPTION * NORMAL \ ESCAPE * NORMAL etc. NORMAL * ESCAPE any NORMAL * OPTION s NORMAL * OPTION w NORMAL * OPTION a NORMAL * OPTION d NORMAL * OPTION W NORMAL * OPTION etc. NORMAL % */ #define TMPBUFSIZE 64 char* ExpandOptions(WScreen *scr, char *cmdline) { int ptr, optr, state, len, olen; char *out, *nout; char *selection=NULL; char *user_input=NULL; #if defined(OFFIX_DND) || defined(XDND) char *dropped_thing=NULL; #endif char tmpbuf[TMPBUFSIZE]; int slen; len = strlen(cmdline); olen = len+1; out = malloc(olen); if (!out) { wwarning(_("out of memory during expansion of \"%s\"")); return NULL; } *out = 0; ptr = 0; /* input line pointer */ optr = 0; /* output line pointer */ state = S_NORMAL; while (ptr < len) { switch (state) { case S_NORMAL: switch (cmdline[ptr]) { case '\\': state = S_ESCAPE; break; case '%': state = S_OPTION; break; default: state = S_NORMAL; out[optr++]=cmdline[ptr]; break; } break; case S_ESCAPE: switch (cmdline[ptr]) { case 'n': out[optr++]=10; break; case 'r': out[optr++]=13; break; case 't': out[optr++]=9; break; default: out[optr++]=cmdline[ptr]; } state = S_NORMAL; break; case S_OPTION: state = S_NORMAL; switch (cmdline[ptr]) { case 'w': if (scr->focused_window && scr->focused_window->flags.focused) { sprintf(tmpbuf, "0x%x", (unsigned int)scr->focused_window->client_win); slen = strlen(tmpbuf); olen += slen; nout = realloc(out,olen); if (!nout) { wwarning(_("out of memory during expansion of \"%w\"")); goto error; } out = nout; strcat(out,tmpbuf); optr+=slen; } else { out[optr++]=' '; } break; case 'W': sprintf(tmpbuf, "0x%x", (unsigned int)scr->current_workspace + 1); slen = strlen(tmpbuf); olen += slen; nout = realloc(out,olen); if (!nout) { wwarning(_("out of memory during expansion of \"%W\"")); goto error; } out = nout; strcat(out,tmpbuf); optr+=slen; break; case 'a': ptr++; user_input = getuserinput(scr, cmdline, &ptr); if (user_input) { slen = strlen(user_input); olen += slen; nout = realloc(out,olen); if (!nout) { wwarning(_("out of memory during expansion of \"%a\"")); goto error; } out = nout; strcat(out,user_input); optr+=slen; } else { /* Not an error, but user has Canceled the dialog box. * This will make the command to not be performed. */ goto error; } break; #if defined(OFFIX_DND) || defined(XDND) case 'd': #ifdef XDND if(scr->xdestring) { dropped_thing = wstrdup(scr->xdestring); } #endif if (!dropped_thing) { dropped_thing = get_dnd_selection(scr); } if (!dropped_thing) { scr->flags.dnd_data_convertion_status = 1; goto error; } slen = strlen(dropped_thing); olen += slen; nout = realloc(out,olen); if (!nout) { wwarning(_("out of memory during expansion of \"%d\"")); goto error; } out = nout; strcat(out,dropped_thing); optr+=slen; break; #endif /* OFFIX_DND */ case 's': if (!selection) { selection = getselection(scr); } if (!selection) { wwarning(_("selection not available")); goto error; } slen = strlen(selection); olen += slen; nout = realloc(out,olen); if (!nout) { wwarning(_("out of memory during expansion of \"%s\"")); goto error; } out = nout; strcat(out,selection); optr+=slen; break; default: out[optr++]='%'; out[optr++]=cmdline[ptr]; } break; } out[optr]=0; ptr++; } if (selection) XFree(selection); return out; error: free(out); if (selection) XFree(selection); return NULL; } /* We don't care for upper/lower case in comparing the keys; so we have to define our own comparison function here */ BOOL StringCompareHook(proplist_t pl1, proplist_t pl2) { char *str1, *str2; str1 = PLGetString(pl1); str2 = PLGetString(pl2); if (strcasecmp(str1, str2)==0) return YES; else return NO; } /* feof doesn't seem to work on pipes */ int IsEof(FILE * stream) { static struct stat stinfo; fstat(fileno(stream), &stinfo); return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) || feof(stream)); } void ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where) { char *name; *winstance = *wclass = NULL; if (!PLIsString(value)) { wwarning(_("bad window name value in %s state info"), where); return; } name = PLGetString(value); if (!name || strlen(name)==0) { wwarning(_("bad window name value in %s state info"), where); return; } UnescapeWM_CLASS(name, winstance, wclass); } #if 0 static char* keysymToString(KeySym keysym, unsigned int state) { XKeyEvent kev; char *buf = wmalloc(20); int count; kev.display = dpy; kev.type = KeyPress; kev.send_event = False; kev.window = DefaultRootWindow(dpy); kev.root = DefaultRootWindow(dpy); kev.same_screen = True; kev.subwindow = kev.root; kev.serial = 0x12344321; kev.time = CurrentTime; kev.state = state; kev.keycode = XKeysymToKeycode(dpy, keysym); count = XLookupString(&kev, buf, 19, NULL, NULL); buf[count] = 0; return buf; } #endif char* GetShortcutString(char *text) { char *buffer = NULL; char *k; int modmask = 0; /* KeySym ksym;*/ int control = 0; char *tmp; tmp = text = wstrdup(text); /* get modifiers */ while ((k = strchr(text, '+'))!=NULL) { int mod; *k = 0; mod = wXModifierFromKey(text); if (mod<0) { return wstrdup("bug"); } modmask |= mod; if (strcasecmp(text, "Meta")==0) { buffer = wstrappend(buffer, "M+"); } else if (strcasecmp(text, "Alt")==0) { buffer = wstrappend(buffer, "A+"); } else if (strcasecmp(text, "Shift")==0) { buffer = wstrappend(buffer, "Sh+"); } else if (strcasecmp(text, "Mod1")==0) { buffer = wstrappend(buffer, "M1+"); } else if (strcasecmp(text, "Mod2")==0) { buffer = wstrappend(buffer, "M2+"); } else if (strcasecmp(text, "Mod3")==0) { buffer = wstrappend(buffer, "M3+"); } else if (strcasecmp(text, "Mod4")==0) { buffer = wstrappend(buffer, "M4+"); } else if (strcasecmp(text, "Mod5")==0) { buffer = wstrappend(buffer, "M5+"); } else if (strcasecmp(text, "Control")==0) { control = 1; } else { buffer = wstrappend(buffer, text); } text = k+1; } if (control) { buffer = wstrappend(buffer, "^"); } buffer = wstrappend(buffer, text); /* get key */ /* ksym = XStringToKeysym(text); tmp = keysymToString(ksym, modmask); puts(tmp); buffer = wstrappend(buffer, tmp); */ free(tmp); return buffer; } char* EscapeWM_CLASS(char *name, char *class) { char *ret; char *ename = NULL, *eclass = NULL; int i, j, l; if (!name && !class) return NULL; if (name) { l = strlen(name); ename = wmalloc(l*2); j = 0; for (i=0; iflags.backimage_helper_launched) { return; } len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ; buffer = wmalloc(len+5); sprintf(buf, "%4i", len); memcpy(buffer, buf, 4); buffer[4] = type; i = 5; if (workspace >= 0) { sprintf(buf, "%4i", workspace); memcpy(&buffer[i], buf, 4); i += 4; buffer[i] = 0; } if (msg) strcpy(&buffer[i], msg); if (write(scr->helper_fd, buffer, len+4) < 0) { wsyserror(_("could not send message to background image helper")); } free(buffer); } void ExecuteShellCommand(WScreen *scr, char *command) { static char *shell = NULL; pid_t pid; /* * This have a problem: if the shell is tcsh (not sure about others) * and ~/.tcshrc have /bin/stty erase ^H somewhere on it, the shell * will block and the command will not be executed. if (!shell) { shell = getenv("SHELL"); if (!shell) shell = "/bin/sh"; } */ shell = "/bin/sh"; pid = fork(); if (pid==0) { SetupEnvironment(scr); #ifdef HAVE_SETPGID setpgid(0, 0); #endif execl(shell, shell, "-c", command, NULL); wsyserror("could not execute %s -c %s", shell, command); Exit(-1); } else if (pid < 0) { wsyserror("cannot fork a new process"); } }