Change to the linux kernel coding style
[wmaker-crm.git] / src / misc.c
dissimilarity index 90%
index 72f32fd..2cf4af7 100644 (file)
-/*
- *  Window Maker window manager
- *
- *  Copyright (c) 1997-2003 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 <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xatom.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <pwd.h>
-#include <math.h>
-#include <time.h>
-
-#include <WINGs/WUtil.h>
-#include <wraster.h>
-
-
-#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"
-
-
-/**** global variables *****/
-
-extern WPreferences wPreferences;
-
-extern Time LastTimestamp;
-
-
-#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];
-    snprintf(tmp, sizeof(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;
-    char *tmp;
-
-    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)));
-
-    /* put the dir where the menu is being read from to the
-     * search path */
-    if (path) {
-        tmp = wstrdup(path);
-        buf = strchr(tmp+1, ' ');
-        if (buf) {
-            *buf = 0;
-        }
-        buf = strrchr(tmp, '/');
-        if (buf) {
-            *buf = 0; /* trunc filename */
-            putdef(line, " -I", tmp);
-        }
-        wfree(tmp);
-    }
-
-
-    /* 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 */
-
-
-
-
-#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;
-}
-
-
-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_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}};
-
-
-
-    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);
-        } else {
-            wusleep(10);
-        }
-        if (time(NULL) - time0 > MAX_ANIMATION_TIME)
-            break;
-    }
-    XMoveWindow(dpy, win, to_x, to_y);
-
-    XSync(dpy, 0);
-    /* compress expose events */
-    eatExpose();
-}
-
-
-char*
-ShrinkString(WMFont *font, char *string, int width)
-{
-    int w, w1=0;
-    int p;
-    char *pos;
-    char *text;
-    int p1, p2, t;
-
-    p = strlen(string);
-    w = WMWidthOfString(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 = WMWidthOfString(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 -= WMWidthOfString(font, "...", 3);
-    pos = string;
-    p1=0;
-    p2=p;
-    t = (p2-p1)/2;
-    while (p2>p1 && p1!=t) {
-        w = WMWidthOfString(font, &string[p-t], t);
-        if (w>width) {
-            p2 = t;
-            t = p1+(p2-p1)/2;
-        } else if (w<width) {
-            p1 = t;
-            t = p1+(p2-p1)/2;
-        } else
-            p2=p1=t;
-    }
-    strcat(text, &string[p-p1]);
-
-    return text;
-}
-
-
-char*
-FindImage(char *paths, char *file)
-{
-    char *tmp, *path;
-
-    tmp = strrchr(file, ':');
-    if (tmp) {
-        *tmp = 0;
-        path = wfindfile(paths, file);
-        *tmp = ':';
-    }
-    if (!tmp || !path) {
-        path = wfindfile(paths, file);
-    }
-
-    return path;
-}
-
-
-static void
-timeoutHandler(void *data)
-{
-    *(int*)data = 1;
-}
-
-
-static char*
-getTextSelection(WScreen *screen, Atom selection)
-{
-    int buffer = -1;
-
-    switch (selection) {
-    case XA_CUT_BUFFER0:
-        buffer = 0;
-        break;
-    case XA_CUT_BUFFER1:
-        buffer = 1;
-        break;
-    case XA_CUT_BUFFER2:
-        buffer = 2;
-        break;
-    case XA_CUT_BUFFER3:
-        buffer = 3;
-        break;
-    case XA_CUT_BUFFER4:
-        buffer = 4;
-        break;
-    case XA_CUT_BUFFER5:
-        buffer = 5;
-        break;
-    case XA_CUT_BUFFER6:
-        buffer = 6;
-        break;
-    case XA_CUT_BUFFER7:
-        buffer = 7;
-        break;
-    }
-    if (buffer >= 0) {
-        char *data;
-        int size;
-
-        data = XFetchBuffer(dpy, &size, buffer);
-
-        return data;
-    } else {
-        char *data;
-        int bits;
-        Atom rtype;
-        unsigned long len, bytes;
-        WMHandlerID timer;
-        int timeout = 0;
-        XEvent ev;
-        static Atom clipboard = 0;
-
-        if (!clipboard)
-            clipboard = XInternAtom(dpy, "CLIPBOARD", False);
-
-        XDeleteProperty(dpy, screen->info_window, clipboard);
-
-        XConvertSelection(dpy, selection, XA_STRING,
-                          clipboard, screen->info_window,
-                          CurrentTime);
-
-        timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
-
-        while (!XCheckTypedWindowEvent(dpy, screen->info_window,
-                                       SelectionNotify, &ev) && !timeout);
-
-        if (!timeout) {
-            WMDeleteTimerHandler(timer);
-        } else {
-            wwarning("selection retrieval timed out");
-            return NULL;
-        }
-
-        /* nobody owns the selection or the current owner has
-         * nothing to do with what we need */
-        if (ev.xselection.property == None) {
-            return NULL;
-        }
-
-        if (XGetWindowProperty(dpy, screen->info_window,
-                               clipboard, 0, 1024,
-                               False, XA_STRING, &rtype, &bits, &len,
-                               &bytes, (unsigned char**)&data)!=Success) {
-            return NULL;
-        }
-        if (rtype!=XA_STRING || bits!=8) {
-            wwarning("invalid data in text selection");
-            if (data)
-                XFree(data);
-            return NULL;
-        }
-        return data;
-    }
-}
-
-static char*
-getselection(WScreen *scr)
-{
-    char *tmp;
-
-    tmp = getTextSelection(scr, XA_PRIMARY);
-    if (!tmp)
-        tmp = getTextSelection(scr, XA_CUT_BUFFER0);
-    return tmp;
-}
-
-
-static char*
-getuserinput(WScreen *scr, char *line, int *ptr)
-{
-    char *ret;
-    char *title;
-    char *prompt;
-    int j, state;
-    int begin = 0;
-#define BUFSIZE 512
-    char tbuffer[BUFSIZE], pbuffer[BUFSIZE];
-
-
-    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, BUFSIZE));
-                    tbuffer[WMIN(*ptr-begin, BUFSIZE)] = 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, BUFSIZE));
-                    tbuffer[WMIN(*ptr-begin, BUFSIZE)] = 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, BUFSIZE));
-                    pbuffer[WMIN(*ptr-begin, BUFSIZE)] = 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;
-}
-
-
-#define S_NORMAL 0
-#define S_ESCAPE 1
-#define S_OPTION 2
-
-/*
- * state       input   new-state       output
- * NORMAL      %       OPTION          <nil>
- * NORMAL      \       ESCAPE          <nil>
- * NORMAL      etc.    NORMAL          <input>
- * ESCAPE      any     NORMAL          <input>
- * OPTION      s       NORMAL          <selection buffer>
- * OPTION      w       NORMAL          <selected window id>
- * OPTION      a       NORMAL          <input text>
- * OPTION      d       NORMAL          <OffiX DND selection object>
- * OPTION      W       NORMAL          <current workspace>
- * OPTION      etc.    NORMAL          %<input>
- */
-#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;
-#ifdef 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) {
-                    snprintf(tmpbuf, sizeof(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':
-                snprintf(tmpbuf, sizeof(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;
-
-#ifdef XDND
-            case 'd':
-                if(scr->xdestring) {
-                    dropped_thing = wstrdup(scr->xdestring);
-                }
-                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 /* XDND */
-
-            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:
-    wfree(out);
-    if (selection)
-        XFree(selection);
-    return NULL;
-}
-
-
-void
-ParseWindowName(WMPropList *value, char **winstance, char **wclass, char *where)
-{
-    char *name;
-
-    *winstance = *wclass = NULL;
-
-    if (!WMIsPLString(value)) {
-        wwarning(_("bad window name value in %s state info"), where);
-        return;
-    }
-
-    name = WMGetFromPLString(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);
-     */
-    wfree(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+1);
-        j = 0;
-        for (i=0; i<l; i++) {
-            if (name[i]=='\\') {
-                ename[j++] = '\\';
-            } else if (name[i]=='.') {
-                ename[j++] = '\\';
-            }
-            ename[j++] = name[i];
-        }
-        ename[j] = 0;
-    }
-    if (class) {
-        l = strlen(class);
-        eclass = wmalloc(l*2+1);
-        j = 0;
-        for (i=0; i<l; i++) {
-            if (class[i]=='\\') {
-                eclass[j++] = '\\';
-            } else if (class[i]=='.') {
-                eclass[j++] = '\\';
-            }
-            eclass[j++] = class[i];
-        }
-        eclass[j] = 0;
-    }
-
-    if (ename && eclass) {
-        int len = strlen(ename)+strlen(eclass)+4;
-        ret = wmalloc(len);
-        snprintf(ret, len, "%s.%s", ename, eclass);
-        wfree(ename);
-        wfree(eclass);
-    } else if (ename) {
-        ret = wstrdup(ename);
-        wfree(ename);
-    } else {
-        ret = wstrdup(eclass);
-        wfree(eclass);
-    }
-
-    return ret;
-}
-
-
-void
-UnescapeWM_CLASS(char *str, char **name, char **class)
-{
-    int i, j, k, dot;
-
-    j = strlen(str);
-    *name = wmalloc(j);
-    **name = 0;
-    *class = wmalloc(j);
-    **class = 0;
-
-    /* separate string in 2 parts */
-    dot = -1;
-    for (i = 0; i < j; i++) {
-        if (str[i]=='\\') {
-            i++;
-            continue;
-        } else if (str[i]=='.') {
-            dot = i;
-            break;
-        }
-    }
-
-    /* unescape strings */
-    for (i=0, k=0; i < dot; i++) {
-        if (str[i]=='\\') {
-            continue;
-        } else {
-            (*name)[k++] = str[i];
-        }
-    }
-    (*name)[k] = 0;
-
-    for (i=dot+1, k=0; i<j; i++) {
-        if (str[i]=='\\') {
-            continue;
-        } else {
-            (*class)[k++] = str[i];
-        }
-    }
-    (*class)[k] = 0;
-
-    if (!*name) {
-        wfree(*name);
-        *name = NULL;
-    }
-    if (!*class) {
-        wfree(*class);
-        *class = NULL;
-    }
-}
-
-
-
-void
-SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
-{
-    char *buffer;
-    int len;
-    int i;
-    char buf[16];
-
-    if (!scr->flags.backimage_helper_launched) {
-        return;
-    }
-
-    len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
-    buffer = wmalloc(len+5);
-    snprintf(buf, sizeof(buf), "%4i", len);
-    memcpy(buffer, buf, 4);
-    buffer[4] = type;
-    i = 5;
-    if (workspace >= 0) {
-        snprintf(buf, sizeof(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"));
-    }
-    wfree(buffer);
-}
-
-
-Bool
-UpdateDomainFile(WDDomain *domain)
-{
-    struct stat stbuf;
-    char path[PATH_MAX];
-    WMPropList *shared_dict, *dict;
-    Bool result, freeDict = False;
-
-    dict = domain->dictionary;
-    if (WMIsPLDictionary(domain->dictionary)) {
-        /* retrieve global system dictionary */
-        snprintf(path, sizeof(path), "%s/WindowMaker/%s",
-                 SYSCONFDIR, domain->domain_name);
-        if (stat(path, &stbuf) >= 0) {
-            shared_dict = WMReadPropListFromFile(path);
-            if (shared_dict) {
-                if (WMIsPLDictionary(shared_dict)) {
-                    freeDict = True;
-                    dict = WMDeepCopyPropList(domain->dictionary);
-                    WMSubtractPLDictionaries(dict, shared_dict, True);
-                }
-                WMReleasePropList(shared_dict);
-            }
-        }
-    }
-
-    result = WMWritePropListToFile(dict, domain->path, True);
-
-    if (freeDict) {
-        WMReleasePropList(dict);
-    }
-
-    return result;
-}
-
-
-char*
-StrConcatDot(char *a, char *b)
-{
-    int len;
-    char *str;
-
-    if (!a)
-        a = "";
-    if (!b)
-        b = "";
-
-    len = strlen(a)+strlen(b)+4;
-    str = wmalloc(len);
-
-    snprintf(str, len, "%s.%s", a, b);
-
-    return str;
-}
-
-
-#define MAX_CMD_SIZE 4096
-
-Bool
-GetCommandForPid(int pid, char ***argv, int *argc)
-{
-    static char buf[MAX_CMD_SIZE];
-    FILE *fPtr;
-    int count, i, j;
-    Bool ok= False;
-
-    sprintf(buf, "/proc/%d/cmdline", pid);
-    fPtr = fopen(buf, "r");
-    if (fPtr) {
-        count = read(fileno(fPtr), buf, MAX_CMD_SIZE);
-        if (count > 0) {
-            buf[count-1] = 0;
-            for (i=0, *argc=0; i<count; i++) {
-                if (buf[i] == 0) {
-                    (*argc)++;
-                }
-            }
-            if ((*argc) == 0) {
-                *argv = NULL;
-                ok= False;
-            } else {
-                *argv = (char**) wmalloc(sizeof(char*) * (*argc));
-                (*argv)[0] = buf;
-                for (i=0, j=1; i<count; i++) {
-                    if (buf[i] != 0)
-                      continue;
-                    if (i < count-1) {
-                        (*argv)[j++] = &buf[i+1];
-                    }
-                    if (j == *argc) {
-                        break;
-                    }
-                }
-                ok= True;
-            }
-        }
-        fclose(fPtr);
-    }
-
-    return ok;
-}
-
-
-static char*
-getCommandForWindow(Window win, int elements)
-{
-    char **argv, *command = NULL;
-    int argc;
-
-    if (XGetCommand(dpy, win, &argv, &argc)) {
-        if (argc > 0 && argv != NULL) {
-            if (elements==0)
-                elements = argc;
-            command = wtokenjoin(argv, WMIN(argc, elements));
-            if (command[0] == 0) {
-                wfree(command);
-                command = NULL;
-            }
-        }
-        if (argv) {
-            XFreeStringList(argv);
-        }
-    }
-
-    return command;
-}
-
-
-/* Free result when done */
-char*
-GetCommandForWindow(Window win)
-{
-    return getCommandForWindow(win, 0);
-}
-
-
-/* Free result when done */
-char*
-GetProgramNameForWindow(Window win)
-{
-    return getCommandForWindow(win, 1);
-}
-
-
+/*
+ *  Window Maker window manager
+ *
+ *  Copyright (c) 1997-2003 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 <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <pwd.h>
+#include <math.h>
+#include <time.h>
+
+#include <WINGs/WUtil.h>
+#include <wraster.h>
+
+#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"
+
+/**** global variables *****/
+
+extern WPreferences wPreferences;
+
+extern Time LastTimestamp;
+
+#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];
+       snprintf(tmp, sizeof(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;
+       char *tmp;
+
+       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)));
+
+       /* put the dir where the menu is being read from to the
+        * search path */
+       if (path) {
+               tmp = wstrdup(path);
+               buf = strchr(tmp + 1, ' ');
+               if (buf) {
+                       *buf = 0;
+               }
+               buf = strrchr(tmp, '/');
+               if (buf) {
+                       *buf = 0;       /* trunc filename */
+                       putdef(line, " -I", tmp);
+               }
+               wfree(tmp);
+       }
+
+       /* 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 */
+
+#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;
+}
+
+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_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}};
+
+       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);
+               } else {
+                       wusleep(10);
+               }
+               if (time(NULL) - time0 > MAX_ANIMATION_TIME)
+                       break;
+       }
+       XMoveWindow(dpy, win, to_x, to_y);
+
+       XSync(dpy, 0);
+       /* compress expose events */
+       eatExpose();
+}
+
+char *ShrinkString(WMFont * font, char *string, int width)
+{
+       int w, w1 = 0;
+       int p;
+       char *pos;
+       char *text;
+       int p1, p2, t;
+
+       p = strlen(string);
+       w = WMWidthOfString(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 = WMWidthOfString(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 -= WMWidthOfString(font, "...", 3);
+       pos = string;
+       p1 = 0;
+       p2 = p;
+       t = (p2 - p1) / 2;
+       while (p2 > p1 && p1 != t) {
+               w = WMWidthOfString(font, &string[p - t], t);
+               if (w > width) {
+                       p2 = t;
+                       t = p1 + (p2 - p1) / 2;
+               } else if (w < width) {
+                       p1 = t;
+                       t = p1 + (p2 - p1) / 2;
+               } else
+                       p2 = p1 = t;
+       }
+       strcat(text, &string[p - p1]);
+
+       return text;
+}
+
+char *FindImage(char *paths, char *file)
+{
+       char *tmp, *path;
+
+       tmp = strrchr(file, ':');
+       if (tmp) {
+               *tmp = 0;
+               path = wfindfile(paths, file);
+               *tmp = ':';
+       }
+       if (!tmp || !path) {
+               path = wfindfile(paths, file);
+       }
+
+       return path;
+}
+
+static void timeoutHandler(void *data)
+{
+       *(int *)data = 1;
+}
+
+static char *getTextSelection(WScreen * screen, Atom selection)
+{
+       int buffer = -1;
+
+       switch (selection) {
+       case XA_CUT_BUFFER0:
+               buffer = 0;
+               break;
+       case XA_CUT_BUFFER1:
+               buffer = 1;
+               break;
+       case XA_CUT_BUFFER2:
+               buffer = 2;
+               break;
+       case XA_CUT_BUFFER3:
+               buffer = 3;
+               break;
+       case XA_CUT_BUFFER4:
+               buffer = 4;
+               break;
+       case XA_CUT_BUFFER5:
+               buffer = 5;
+               break;
+       case XA_CUT_BUFFER6:
+               buffer = 6;
+               break;
+       case XA_CUT_BUFFER7:
+               buffer = 7;
+               break;
+       }
+       if (buffer >= 0) {
+               char *data;
+               int size;
+
+               data = XFetchBuffer(dpy, &size, buffer);
+
+               return data;
+       } else {
+               char *data;
+               int bits;
+               Atom rtype;
+               unsigned long len, bytes;
+               WMHandlerID timer;
+               int timeout = 0;
+               XEvent ev;
+               static Atom clipboard = 0;
+
+               if (!clipboard)
+                       clipboard = XInternAtom(dpy, "CLIPBOARD", False);
+
+               XDeleteProperty(dpy, screen->info_window, clipboard);
+
+               XConvertSelection(dpy, selection, XA_STRING, clipboard, screen->info_window, CurrentTime);
+
+               timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
+
+               while (!XCheckTypedWindowEvent(dpy, screen->info_window, SelectionNotify, &ev) && !timeout) ;
+
+               if (!timeout) {
+                       WMDeleteTimerHandler(timer);
+               } else {
+                       wwarning("selection retrieval timed out");
+                       return NULL;
+               }
+
+               /* nobody owns the selection or the current owner has
+                * nothing to do with what we need */
+               if (ev.xselection.property == None) {
+                       return NULL;
+               }
+
+               if (XGetWindowProperty(dpy, screen->info_window,
+                                      clipboard, 0, 1024,
+                                      False, XA_STRING, &rtype, &bits, &len,
+                                      &bytes, (unsigned char **)&data) != Success) {
+                       return NULL;
+               }
+               if (rtype != XA_STRING || bits != 8) {
+                       wwarning("invalid data in text selection");
+                       if (data)
+                               XFree(data);
+                       return NULL;
+               }
+               return data;
+       }
+}
+
+static char *getselection(WScreen * scr)
+{
+       char *tmp;
+
+       tmp = getTextSelection(scr, XA_PRIMARY);
+       if (!tmp)
+               tmp = getTextSelection(scr, XA_CUT_BUFFER0);
+       return tmp;
+}
+
+static char *getuserinput(WScreen * scr, char *line, int *ptr)
+{
+       char *ret;
+       char *title;
+       char *prompt;
+       int j, state;
+       int begin = 0;
+#define BUFSIZE 512
+       char tbuffer[BUFSIZE], pbuffer[BUFSIZE];
+
+       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, BUFSIZE));
+                                       tbuffer[WMIN(*ptr - begin, BUFSIZE)] = 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, BUFSIZE));
+                                       tbuffer[WMIN(*ptr - begin, BUFSIZE)] = 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, BUFSIZE));
+                                       pbuffer[WMIN(*ptr - begin, BUFSIZE)] = 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;
+}
+
+#define S_NORMAL 0
+#define S_ESCAPE 1
+#define S_OPTION 2
+
+/*
+ * state       input   new-state       output
+ * NORMAL      %       OPTION          <nil>
+ * NORMAL      \       ESCAPE          <nil>
+ * NORMAL      etc.    NORMAL          <input>
+ * ESCAPE      any     NORMAL          <input>
+ * OPTION      s       NORMAL          <selection buffer>
+ * OPTION      w       NORMAL          <selected window id>
+ * OPTION      a       NORMAL          <input text>
+ * OPTION      d       NORMAL          <OffiX DND selection object>
+ * OPTION      W       NORMAL          <current workspace>
+ * OPTION      etc.    NORMAL          %<input>
+ */
+#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;
+#ifdef 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) {
+                                       snprintf(tmpbuf, sizeof(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':
+                               snprintf(tmpbuf, sizeof(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;
+
+#ifdef XDND
+                       case 'd':
+                               if (scr->xdestring) {
+                                       dropped_thing = wstrdup(scr->xdestring);
+                               }
+                               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                         /* XDND */
+
+                       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:
+       wfree(out);
+       if (selection)
+               XFree(selection);
+       return NULL;
+}
+
+void ParseWindowName(WMPropList * value, char **winstance, char **wclass, char *where)
+{
+       char *name;
+
+       *winstance = *wclass = NULL;
+
+       if (!WMIsPLString(value)) {
+               wwarning(_("bad window name value in %s state info"), where);
+               return;
+       }
+
+       name = WMGetFromPLString(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);
+        */
+       wfree(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 + 1);
+               j = 0;
+               for (i = 0; i < l; i++) {
+                       if (name[i] == '\\') {
+                               ename[j++] = '\\';
+                       } else if (name[i] == '.') {
+                               ename[j++] = '\\';
+                       }
+                       ename[j++] = name[i];
+               }
+               ename[j] = 0;
+       }
+       if (class) {
+               l = strlen(class);
+               eclass = wmalloc(l * 2 + 1);
+               j = 0;
+               for (i = 0; i < l; i++) {
+                       if (class[i] == '\\') {
+                               eclass[j++] = '\\';
+                       } else if (class[i] == '.') {
+                               eclass[j++] = '\\';
+                       }
+                       eclass[j++] = class[i];
+               }
+               eclass[j] = 0;
+       }
+
+       if (ename && eclass) {
+               int len = strlen(ename) + strlen(eclass) + 4;
+               ret = wmalloc(len);
+               snprintf(ret, len, "%s.%s", ename, eclass);
+               wfree(ename);
+               wfree(eclass);
+       } else if (ename) {
+               ret = wstrdup(ename);
+               wfree(ename);
+       } else {
+               ret = wstrdup(eclass);
+               wfree(eclass);
+       }
+
+       return ret;
+}
+
+void UnescapeWM_CLASS(char *str, char **name, char **class)
+{
+       int i, j, k, dot;
+
+       j = strlen(str);
+       *name = wmalloc(j);
+       **name = 0;
+       *class = wmalloc(j);
+       **class = 0;
+
+       /* separate string in 2 parts */
+       dot = -1;
+       for (i = 0; i < j; i++) {
+               if (str[i] == '\\') {
+                       i++;
+                       continue;
+               } else if (str[i] == '.') {
+                       dot = i;
+                       break;
+               }
+       }
+
+       /* unescape strings */
+       for (i = 0, k = 0; i < dot; i++) {
+               if (str[i] == '\\') {
+                       continue;
+               } else {
+                       (*name)[k++] = str[i];
+               }
+       }
+       (*name)[k] = 0;
+
+       for (i = dot + 1, k = 0; i < j; i++) {
+               if (str[i] == '\\') {
+                       continue;
+               } else {
+                       (*class)[k++] = str[i];
+               }
+       }
+       (*class)[k] = 0;
+
+       if (!*name) {
+               wfree(*name);
+               *name = NULL;
+       }
+       if (!*class) {
+               wfree(*class);
+               *class = NULL;
+       }
+}
+
+void SendHelperMessage(WScreen * scr, char type, int workspace, char *msg)
+{
+       char *buffer;
+       int len;
+       int i;
+       char buf[16];
+
+       if (!scr->flags.backimage_helper_launched) {
+               return;
+       }
+
+       len = (msg ? strlen(msg) : 0) + (workspace >= 0 ? 4 : 0) + 1;
+       buffer = wmalloc(len + 5);
+       snprintf(buf, sizeof(buf), "%4i", len);
+       memcpy(buffer, buf, 4);
+       buffer[4] = type;
+       i = 5;
+       if (workspace >= 0) {
+               snprintf(buf, sizeof(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"));
+       }
+       wfree(buffer);
+}
+
+Bool UpdateDomainFile(WDDomain * domain)
+{
+       struct stat stbuf;
+       char path[PATH_MAX];
+       WMPropList *shared_dict, *dict;
+       Bool result, freeDict = False;
+
+       dict = domain->dictionary;
+       if (WMIsPLDictionary(domain->dictionary)) {
+               /* retrieve global system dictionary */
+               snprintf(path, sizeof(path), "%s/WindowMaker/%s", SYSCONFDIR, domain->domain_name);
+               if (stat(path, &stbuf) >= 0) {
+                       shared_dict = WMReadPropListFromFile(path);
+                       if (shared_dict) {
+                               if (WMIsPLDictionary(shared_dict)) {
+                                       freeDict = True;
+                                       dict = WMDeepCopyPropList(domain->dictionary);
+                                       WMSubtractPLDictionaries(dict, shared_dict, True);
+                               }
+                               WMReleasePropList(shared_dict);
+                       }
+               }
+       }
+
+       result = WMWritePropListToFile(dict, domain->path, True);
+
+       if (freeDict) {
+               WMReleasePropList(dict);
+       }
+
+       return result;
+}
+
+char *StrConcatDot(char *a, char *b)
+{
+       int len;
+       char *str;
+
+       if (!a)
+               a = "";
+       if (!b)
+               b = "";
+
+       len = strlen(a) + strlen(b) + 4;
+       str = wmalloc(len);
+
+       snprintf(str, len, "%s.%s", a, b);
+
+       return str;
+}
+
+#define MAX_CMD_SIZE 4096
+
+Bool GetCommandForPid(int pid, char ***argv, int *argc)
+{
+       static char buf[MAX_CMD_SIZE];
+       FILE *fPtr;
+       int count, i, j;
+       Bool ok = False;
+
+       sprintf(buf, "/proc/%d/cmdline", pid);
+       fPtr = fopen(buf, "r");
+       if (fPtr) {
+               count = read(fileno(fPtr), buf, MAX_CMD_SIZE);
+               if (count > 0) {
+                       buf[count - 1] = 0;
+                       for (i = 0, *argc = 0; i < count; i++) {
+                               if (buf[i] == 0) {
+                                       (*argc)++;
+                               }
+                       }
+                       if ((*argc) == 0) {
+                               *argv = NULL;
+                               ok = False;
+                       } else {
+                               *argv = (char **)wmalloc(sizeof(char *) * (*argc));
+                               (*argv)[0] = buf;
+                               for (i = 0, j = 1; i < count; i++) {
+                                       if (buf[i] != 0)
+                                               continue;
+                                       if (i < count - 1) {
+                                               (*argv)[j++] = &buf[i + 1];
+                                       }
+                                       if (j == *argc) {
+                                               break;
+                                       }
+                               }
+                               ok = True;
+                       }
+               }
+               fclose(fPtr);
+       }
+
+       return ok;
+}
+
+static char *getCommandForWindow(Window win, int elements)
+{
+       char **argv, *command = NULL;
+       int argc;
+
+       if (XGetCommand(dpy, win, &argv, &argc)) {
+               if (argc > 0 && argv != NULL) {
+                       if (elements == 0)
+                               elements = argc;
+                       command = wtokenjoin(argv, WMIN(argc, elements));
+                       if (command[0] == 0) {
+                               wfree(command);
+                               command = NULL;
+                       }
+               }
+               if (argv) {
+                       XFreeStringList(argv);
+               }
+       }
+
+       return command;
+}
+
+/* Free result when done */
+char *GetCommandForWindow(Window win)
+{
+       return getCommandForWindow(win, 0);
+}
+
+/* Free result when done */
+char *GetProgramNameForWindow(Window win)
+{
+       return getCommandForWindow(win, 1);
+}