Change to the linux kernel coding style
[wmaker-crm.git] / src / session.c
dissimilarity index 85%
index 1c801c8..90f5040 100644 (file)
-/* session.c - session state handling and R6 style session management
- *
- *  Copyright (c) 1998-2003 Dan Pascu
- *  Copyright (c) 1998-2003 Alfredo Kojima
- *
- *  Window Maker window manager
- *
- *  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.
- */
-
-
-/*
- *
- * If defined(XSMP_ENABLED) and session manager is running then
- *     do normal stuff
- * else
- *     do pre-R6 session management stuff (save window state and relaunch)
- *
- * When doing a checkpoint:
- *
- * = Without XSMP
- * Open "Stop"/status Dialog
- * Send SAVE_YOURSELF to clients and wait for reply
- * Save restart info
- * Save state of clients
- *
- * = With XSMP
- * Send checkpoint request to sm
- *
- * When exiting:
- * -------------
- *
- * = Without XSMP
- *
- * Open "Exit Now"/status Dialog
- * Send SAVE_YOURSELF to clients and wait for reply
- * Save restart info
- * Save state of clients
- * Send DELETE to all clients
- * When no more clients are left or user hit "Exit Now", exit
- *
- * = With XSMP
- *
- * Send Shutdown request to session manager
- * if SaveYourself message received, save state of clients
- * if the Die message is received, exit.
- */
-
-#include "wconfig.h"
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-#ifdef XSMP_ENABLED
-#include <X11/SM/SMlib.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <time.h>
-
-
-#include "WindowMaker.h"
-#include "screen.h"
-#include "window.h"
-#include "client.h"
-#include "session.h"
-#include "wcore.h"
-#include "framewin.h"
-#include "workspace.h"
-#include "funcs.h"
-#include "properties.h"
-#include "application.h"
-#include "appicon.h"
-
-
-#include "dock.h"
-
-
-#include <WINGs/WUtil.h>
-
-/** Global **/
-
-extern Atom _XA_WM_SAVE_YOURSELF;
-
-extern Time LastTimestamp;
-
-#ifdef XSMP_ENABLED
-
-extern int wScreenCount;
-
-/* requested for SaveYourselfPhase2 */
-static Bool sWaitingPhase2 = False;
-
-static SmcConn sSMCConn = NULL;
-
-static WMHandlerID sSMInputHandler = NULL;
-
-/* our SM client ID */
-static char *sClientID = NULL;
-#endif
-
-
-static WMPropList *sApplications = NULL;
-static WMPropList *sCommand;
-static WMPropList *sName;
-static WMPropList *sHost;
-static WMPropList *sWorkspace;
-static WMPropList *sShaded;
-static WMPropList *sMiniaturized;
-static WMPropList *sHidden;
-static WMPropList *sGeometry;
-static WMPropList *sShortcutMask;
-
-static WMPropList *sDock;
-
-static WMPropList *sYes, *sNo;
-
-
-static void
-make_keys()
-{
-    if (sApplications!=NULL)
-        return;
-
-    sApplications = WMCreatePLString("Applications");
-    sCommand = WMCreatePLString("Command");
-    sName = WMCreatePLString("Name");
-    sHost = WMCreatePLString("Host");
-    sWorkspace = WMCreatePLString("Workspace");
-    sShaded = WMCreatePLString("Shaded");
-    sMiniaturized = WMCreatePLString("Miniaturized");
-    sHidden = WMCreatePLString("Hidden");
-    sGeometry = WMCreatePLString("Geometry");
-    sDock = WMCreatePLString("Dock");
-    sShortcutMask = WMCreatePLString("ShortcutMask");
-
-    sYes = WMCreatePLString("Yes");
-    sNo = WMCreatePLString("No");
-}
-
-
-
-static int
-getBool(WMPropList *value)
-{
-    char *val;
-
-    if (!WMIsPLString(value)) {
-        return 0;
-    }
-    if (!(val = WMGetFromPLString(value))) {
-        return 0;
-    }
-
-    if ((val[1]=='\0' && (val[0]=='y' || val[0]=='Y'))
-        || strcasecmp(val, "YES")==0) {
-
-        return 1;
-    } else if ((val[1]=='\0' && (val[0]=='n' || val[0]=='N'))
-               || strcasecmp(val, "NO")==0) {
-        return 0;
-    } else {
-        int i;
-        if (sscanf(val, "%i", &i)==1) {
-            return (i!=0);
-        } else {
-            wwarning(_("can't convert \"%s\" to boolean"), val);
-            return 0;
-        }
-    }
-}
-
-
-static unsigned
-getInt(WMPropList *value)
-{
-    char *val;
-    unsigned n;
-
-    if (!WMIsPLString(value))
-        return 0;
-    val = WMGetFromPLString(value);
-    if (!val)
-        return 0;
-    if (sscanf(val, "%u", &n) != 1)
-        return 0;
-
-    return n;
-}
-
-
-
-static WMPropList*
-makeWindowState(WWindow *wwin, WApplication *wapp)
-{
-    WScreen *scr = wwin->screen_ptr;
-    Window win;
-    int i;
-    unsigned mask;
-    char *class, *instance, *command=NULL, buffer[512];
-    WMPropList *win_state, *cmd, *name, *workspace;
-    WMPropList *shaded, *miniaturized, *hidden, *geometry;
-    WMPropList *dock, *shortcut;
-
-    if (wwin->orig_main_window!=None && wwin->orig_main_window!=wwin->client_win)
-        win = wwin->orig_main_window;
-    else
-        win = wwin->client_win;
-
-    command = GetCommandForWindow(win);
-    if (!command)
-        return NULL;
-
-    if (PropGetWMClass(win, &class, &instance)) {
-        if (class && instance)
-            snprintf(buffer, sizeof(buffer), "%s.%s", instance, class);
-        else if (instance)
-            snprintf(buffer, sizeof(buffer), "%s", instance);
-        else if (class)
-            snprintf(buffer, sizeof(buffer), ".%s", class);
-        else
-            snprintf(buffer, sizeof(buffer), ".");
-
-        name = WMCreatePLString(buffer);
-        cmd = WMCreatePLString(command);
-        /*sprintf(buffer, "%d", wwin->frame->workspace+1);
-         workspace = WMCreatePLString(buffer);*/
-        workspace = WMCreatePLString(scr->workspaces[wwin->frame->workspace]->name);
-        shaded = wwin->flags.shaded ? sYes : sNo;
-        miniaturized = wwin->flags.miniaturized ? sYes : sNo;
-        hidden = wwin->flags.hidden ? sYes : sNo;
-        snprintf(buffer, sizeof(buffer), "%ix%i+%i+%i",
-                 wwin->client.width, wwin->client.height,
-                 wwin->frame_x, wwin->frame_y);
-        geometry = WMCreatePLString(buffer);
-
-        for (mask = 0, i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
-            if (scr->shortcutWindows[i] != NULL &&
-                WMGetFirstInArray(scr->shortcutWindows[i], wwin) != WANotFound) {
-                mask |= 1<<i;
-            }
-        }
-
-        snprintf(buffer, sizeof(buffer), "%u", mask);
-        shortcut = WMCreatePLString(buffer);
-
-        win_state = WMCreatePLDictionary(sName, name,
-                                         sCommand, cmd,
-                                         sWorkspace, workspace,
-                                         sShaded, shaded,
-                                         sMiniaturized, miniaturized,
-                                         sHidden, hidden,
-                                         sShortcutMask, shortcut,
-                                         sGeometry, geometry,
-                                         NULL);
-
-        WMReleasePropList(name);
-        WMReleasePropList(cmd);
-        WMReleasePropList(workspace);
-        WMReleasePropList(geometry);
-        WMReleasePropList(shortcut);
-        if (wapp && wapp->app_icon && wapp->app_icon->dock) {
-            int i;
-            char *name;
-            if (wapp->app_icon->dock == scr->dock) {
-                name="Dock";
-            } else {
-                for(i=0; i<scr->workspace_count; i++)
-                    if(scr->workspaces[i]->clip == wapp->app_icon->dock)
-                        break;
-                assert(i < scr->workspace_count);
-                /*n = i+1;*/
-                name = scr->workspaces[i]->name;
-            }
-            dock = WMCreatePLString(name);
-            WMPutInPLDictionary(win_state, sDock, dock);
-            WMReleasePropList(dock);
-        }
-    } else {
-        win_state = NULL;
-    }
-
-    if (instance) XFree(instance);
-    if (class) XFree(class);
-    if (command) wfree(command);
-
-    return win_state;
-}
-
-
-void
-wSessionSaveState(WScreen *scr)
-{
-    WWindow *wwin = scr->focused_window;
-    WMPropList *win_info, *wks;
-    WMPropList *list=NULL;
-    WMArray *wapp_list=NULL;
-
-
-    make_keys();
-
-    if (!scr->session_state) {
-        scr->session_state = WMCreatePLDictionary(NULL, NULL);
-        if (!scr->session_state)
-            return;
-    }
-
-    list = WMCreatePLArray(NULL);
-
-    wapp_list = WMCreateArray(16);
-
-    while (wwin) {
-        WApplication *wapp=wApplicationOf(wwin->main_window);
-        Window appId = wwin->orig_main_window;
-
-        if ((wwin->transient_for==None
-             || wwin->transient_for==wwin->screen_ptr->root_win)
-            && WMGetFirstInArray(wapp_list, (void*)appId)==WANotFound
-            && !WFLAGP(wwin, dont_save_session)) {
-            /* A entry for this application was not yet saved. Save one. */
-            if ((win_info = makeWindowState(wwin, wapp))!=NULL) {
-                WMAddToPLArray(list, win_info);
-                WMReleasePropList(win_info);
-                /* If we were succesful in saving the info for this window
-                 * add the application the window belongs to, to the
-                 * application list, so no multiple entries for the same
-                 * application are saved.
-                 */
-                WMAddToArray(wapp_list, (void*)appId);
-            }
-        }
-        wwin = wwin->prev;
-    }
-    WMRemoveFromPLDictionary(scr->session_state, sApplications);
-    WMPutInPLDictionary(scr->session_state, sApplications, list);
-    WMReleasePropList(list);
-
-    wks = WMCreatePLString(scr->workspaces[scr->current_workspace]->name);
-    WMPutInPLDictionary(scr->session_state, sWorkspace, wks);
-    WMReleasePropList(wks);
-
-    WMFreeArray(wapp_list);
-}
-
-
-void
-wSessionClearState(WScreen *scr)
-{
-    make_keys();
-
-    if (!scr->session_state)
-        return;
-
-    WMRemoveFromPLDictionary(scr->session_state, sApplications);
-    WMRemoveFromPLDictionary(scr->session_state, sWorkspace);
-}
-
-
-static pid_t
-execCommand(WScreen *scr, char *command, char *host)
-{
-    pid_t pid;
-    char **argv;
-    int argc;
-
-    wtokensplit(command, &argv, &argc);
-
-    if (!argc) {
-        return 0;
-    }
-
-    if ((pid=fork())==0) {
-        char **args;
-        int i;
-
-        SetupEnvironment(scr);
-
-        args = malloc(sizeof(char*)*(argc+1));
-        if (!args)
-            exit(111);
-        for (i=0; i<argc; i++) {
-            args[i] = argv[i];
-        }
-        args[argc] = NULL;
-        execvp(argv[0], args);
-        exit(111);
-    }
-    while (argc > 0)
-        wfree(argv[--argc]);
-    wfree(argv);
-    return pid;
-}
-
-
-static WSavedState*
-getWindowState(WScreen *scr, WMPropList *win_state)
-{
-    WSavedState *state = wmalloc(sizeof(WSavedState));
-    WMPropList *value;
-    char *tmp;
-    unsigned mask;
-    int i;
-
-    memset(state, 0, sizeof(WSavedState));
-    state->workspace = -1;
-    value = WMGetFromPLDictionary(win_state, sWorkspace);
-    if (value && WMIsPLString(value)) {
-        tmp = WMGetFromPLString(value);
-        if (sscanf(tmp, "%i", &state->workspace)!=1) {
-            state->workspace = -1;
-            for (i=0; i < scr->workspace_count; i++) {
-                if (strcmp(scr->workspaces[i]->name, tmp)==0) {
-                    state->workspace = i;
-                    break;
-                }
-            }
-        } else {
-            state->workspace--;
-        }
-    }
-    if ((value = WMGetFromPLDictionary(win_state, sShaded))!=NULL)
-        state->shaded = getBool(value);
-    if ((value = WMGetFromPLDictionary(win_state, sMiniaturized))!=NULL)
-        state->miniaturized = getBool(value);
-    if ((value = WMGetFromPLDictionary(win_state, sHidden))!=NULL)
-        state->hidden = getBool(value);
-    if ((value = WMGetFromPLDictionary(win_state, sShortcutMask))!=NULL) {
-        mask = getInt(value);
-        state->window_shortcuts = mask;
-    }
-
-    value = WMGetFromPLDictionary(win_state, sGeometry);
-    if (value && WMIsPLString(value)) {
-        if (!(sscanf(WMGetFromPLString(value), "%ix%i+%i+%i",
-                     &state->w, &state->h, &state->x, &state->y)==4 &&
-              (state->w>0 && state->h>0))) {
-            state->w = 0;
-            state->h = 0;
-        }
-    }
-
-    return state;
-}
-
-
-#define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
-
-void
-wSessionRestoreState(WScreen *scr)
-{
-    WSavedState *state;
-    char *instance, *class, *command, *host;
-    WMPropList *win_info, *apps, *cmd, *value;
-    pid_t pid;
-    int i, count;
-    WDock *dock;
-    WAppIcon *btn=NULL;
-    int j, n, found;
-    char *tmp;
-
-    make_keys();
-
-    if (!scr->session_state)
-        return;
-
-    WMPLSetCaseSensitive(True);
-
-    apps = WMGetFromPLDictionary(scr->session_state, sApplications);
-    if (!apps)
-        return;
-
-    count = WMGetPropListItemCount(apps);
-    if (count==0)
-        return;
-
-    for (i=0; i<count; i++) {
-        win_info = WMGetFromPLArray(apps, i);
-
-        cmd = WMGetFromPLDictionary(win_info, sCommand);
-        if (!cmd || !WMIsPLString(cmd) || !(command = WMGetFromPLString(cmd))) {
-            continue;
-        }
-
-        value = WMGetFromPLDictionary(win_info, sName);
-        if (!value)
-            continue;
-
-        ParseWindowName(value, &instance, &class, "session");
-        if (!instance && !class)
-            continue;
-
-        value = WMGetFromPLDictionary(win_info, sHost);
-        if (value && WMIsPLString(value))
-            host = WMGetFromPLString(value);
-        else
-            host = NULL;
-
-        state = getWindowState(scr, win_info);
-
-        dock = NULL;
-        value = WMGetFromPLDictionary(win_info, sDock);
-        if (value && WMIsPLString(value) && (tmp = WMGetFromPLString(value))!=NULL) {
-            if (sscanf(tmp, "%i", &n)!=1) {
-                if (!strcasecmp(tmp, "DOCK")) {
-                    dock = scr->dock;
-                } else {
-                    for (j=0; j < scr->workspace_count; j++) {
-                        if (strcmp(scr->workspaces[j]->name, tmp)==0) {
-                            dock = scr->workspaces[j]->clip;
-                            break;
-                        }
-                    }
-                }
-            } else {
-                if (n == 0) {
-                    dock = scr->dock;
-                } else if (n>0 && n<=scr->workspace_count) {
-                    dock = scr->workspaces[n-1]->clip;
-                }
-            }
-        }
-
-        found = 0;
-        if (dock!=NULL) {
-            for (j=0; j<dock->max_icons; j++) {
-                btn = dock->icon_array[j];
-                if (btn && SAME(instance, btn->wm_instance) &&
-                    SAME(class, btn->wm_class) &&
-                    SAME(command, btn->command) &&
-                    !btn->launching) {
-                    found = 1;
-                    break;
-                }
-            }
-        }
-
-        if (found) {
-            wDockLaunchWithState(dock, btn, state);
-        } else if ((pid = execCommand(scr, command, host)) > 0) {
-            wWindowAddSavedState(instance, class, command, pid, state);
-        } else {
-            wfree(state);
-        }
-
-        if (instance) wfree(instance);
-        if (class) wfree(class);
-    }
-    /* clean up */
-    WMPLSetCaseSensitive(False);
-}
-
-
-void
-wSessionRestoreLastWorkspace(WScreen *scr)
-{
-    WMPropList *wks;
-    int w, i;
-    char *tmp;
-
-    make_keys();
-
-    if (!scr->session_state)
-        return;
-
-    WMPLSetCaseSensitive(True);
-
-    wks = WMGetFromPLDictionary(scr->session_state, sWorkspace);
-    if (!wks || !WMIsPLString(wks))
-        return;
-
-    tmp = WMGetFromPLString(wks);
-
-    /* clean up */
-    WMPLSetCaseSensitive(False);
-
-    if (sscanf(tmp, "%i", &w)!=1) {
-        w = -1;
-        for (i=0; i < scr->workspace_count; i++) {
-            if (strcmp(scr->workspaces[i]->name, tmp)==0) {
-                w = i;
-                break;
-            }
-        }
-    } else {
-        w--;
-    }
-
-    if (w!=scr->current_workspace && w<scr->workspace_count) {
-        wWorkspaceChange(scr, w);
-    }
-}
-
-
-static void
-clearWaitingAckState(WScreen *scr)
-{
-    WWindow *wwin;
-    WApplication *wapp;
-
-    for (wwin = scr->focused_window; wwin != NULL; wwin = wwin->prev) {
-        wwin->flags.waiting_save_ack = 0;
-        if (wwin->main_window != None) {
-            wapp = wApplicationOf(wwin->main_window);
-            if (wapp)
-                wapp->main_window_desc->flags.waiting_save_ack = 0;
-        }
-    }
-}
-
-
-void
-wSessionSaveClients(WScreen *scr)
-{
-
-}
-
-
-/*
- * With XSMP, this job is done by smproxy
- */
-void
-wSessionSendSaveYourself(WScreen *scr)
-{
-    WWindow *wwin;
-    int count;
-
-    /* freeze client interaction with clients */
-    XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync,
-                  CurrentTime);
-    XGrabPointer(dpy, scr->root_win, False, ButtonPressMask|ButtonReleaseMask,
-                 GrabModeAsync, GrabModeAsync, scr->root_win, None,
-                 CurrentTime);
-
-    clearWaitingAckState(scr);
-
-    count = 0;
-
-    /* first send SAVE_YOURSELF for everybody */
-    for (wwin = scr->focused_window; wwin != NULL; wwin = wwin->prev) {
-        WWindow *mainWin;
-
-        mainWin = wWindowFor(wwin->main_window);
-
-        if (mainWin) {
-            /* if the client is a multi-window client, only send message
-             * to the main window */
-            wwin = mainWin;
-        }
-
-        /* make sure the SAVE_YOURSELF flag is up-to-date */
-        PropGetProtocols(wwin->client_win, &wwin->protocols);
-
-        if (wwin->protocols.SAVE_YOURSELF) {
-            if (!wwin->flags.waiting_save_ack) {
-                wClientSendProtocol(wwin, _XA_WM_SAVE_YOURSELF, LastTimestamp);
-
-                wwin->flags.waiting_save_ack = 1;
-                count++;
-            }
-        } else {
-            wwin->flags.waiting_save_ack = 0;
-        }
-    }
-
-    /* then wait for acknowledge */
-    while (count > 0) {
-
-    }
-
-    XUngrabPointer(dpy, CurrentTime);
-    XUngrabKeyboard(dpy, CurrentTime);
-    XFlush(dpy);
-}
-
-
-#ifdef XSMP_ENABLED
-/*
- * With full session management support, the part of WMState
- * that store client window state will become obsolete (maybe we can reuse
- *                                                     the old code too),
- * but we still need to store state info like the dock and workspaces.
- * It is better to keep dock/wspace info in WMState because the user
- * might want to keep the dock configuration while not wanting to
- * resume a previously saved session.
- * So, wmaker specific state info can be saved in
- * ~/GNUstep/Library/WindowMaker/statename.state
- * Its better to not put it in the defaults directory because:
- * - its not a defaults file (having domain names like wmaker0089504baa
- * in the defaults directory wouldn't be very neat)
- * - this state file is not meant to be edited by users
- *
- * The old session code will become obsolete. When wmaker is
- * compiled with R6 sm support compiled in, it'll be better to
- * use a totally rewritten state saving code, but we can keep
- * the current code for when XSMP_ENABLED is not compiled in.
- *
- * This will be confusing to old users (well get lots of "SAVE_SESSION broke!"
- * messages), but it'll be better.
- *
- * -readme
- */
-
-
-static char*
-getWindowRole(Window window)
-{
-    XTextProperty prop;
-    static Atom atom = 0;
-
-    if (!atom)
-        atom = XInternAtom(dpy, "WM_WINDOW_ROLE", False);
-
-    if (XGetTextProperty(dpy, window, &prop, atom)) {
-        if (prop.encoding == XA_STRING && prop.format == 8 && prop.nitems > 0)
-            return prop.value;
-    }
-
-    return NULL;
-}
-
-
-/*
- *
- * Saved Info:
- *
- * WM_WINDOW_ROLE
- *
- * WM_CLASS.instance
- * WM_CLASS.class
- * WM_NAME
- * WM_COMMAND
- *
- * geometry
- * state = (miniaturized, shaded, etc)
- * attribute
- * workspace #
- * app state = (which dock, hidden)
- * window shortcut #
- */
-
-static WMPropList*
-makeAppState(WWindow *wwin)
-{
-    WApplication *wapp;
-    WMPropList *state;
-    WScreen *scr = wwin->screen_ptr;
-
-    state = WMCreatePLArray(NULL, NULL);
-
-    wapp = wApplicationOf(wwin->main_window);
-
-    if (wapp) {
-        if (wapp->app_icon && wapp->app_icon->dock) {
-
-            if (wapp->app_icon->dock == scr->dock) {
-                WMAddToPLArray(state, WMCreatePLString("Dock"));
-            } else {
-                int i;
-
-                for(i=0; i<scr->workspace_count; i++)
-                    if(scr->workspaces[i]->clip == wapp->app_icon->dock)
-                        break;
-
-                assert(i < scr->workspace_count);
-
-                WMAddToPLArray(state,
-                               WMCreatePLString(scr->workspaces[i]->name));
-            }
-        }
-
-        WMAddToPLArray(state, WMCreatePLString(wapp->hidden ? "1" : "0"));
-    }
-
-    return state;
-}
-
-
-
-Bool
-wSessionGetStateFor(WWindow *wwin, WSessionData *state)
-{
-    char *str;
-    WMPropList *slist;
-    WMPropList *elem;
-    WMPropList *value;
-    int index = 0;
-
-    index = 3;
-
-    /* geometry */
-    value = WMGetFromPLArray(slist, index++);
-    str = WMGetFromPLString(value);
-
-    sscanf(str, "%i %i %i %i %i %i", &state->x, &state->y,
-           &state->width, &state->height,
-           &state->user_changed_width, &state->user_changed_height);
-
-
-    /* state */
-    value = WMGetFromPLArray(slist, index++);
-    str = WMGetFromPLString(value);
-
-    sscanf(str, "%i %i %i", &state->miniaturized, &state->shaded,
-           &state->maximized);
-
-
-    /* attributes */
-    value = WMGetFromPLArray(slist, index++);
-    str = WMGetFromPLString(value);
-
-    getAttributeState(str, &state->mflags, &state->flags);
-
-
-    /* workspace */
-    value = WMGetFromPLArray(slist, index++);
-    str = WMGetFromPLString(value);
-
-    sscanf(str, "%i", &state->workspace);
-
-
-    /* app state (repeated for all windows of the app) */
-    value = WMGetFromPLArray(slist, index++);
-    str = WMGetFromPLString(value);
-
-    /* ???? */
-
-    /* shortcuts */
-    value = WMGetFromPLArray(slist, index++);
-    str = WMGetFromPLString(value);
-
-    sscanf(str, "%i", &state->shortcuts);
-}
-
-
-
-static WMPropList*
-makeAttributeState(WWindow *wwin)
-{
-    unsigned int data1, data2;
-    char buffer[256];
-
-#define W_FLAG(wwin, FLAG)     ((wwin)->defined_user_flags.FLAG \
-    ? (wwin)->user_flags.FLAG : -1)
-
-    snprintf(buffer, sizeof(buffer),
-             "%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
-             W_FLAG(no_titlebar),
-             W_FLAG(no_resizable),
-             W_FLAG(no_closable),
-             W_FLAG(no_miniaturizable),
-             W_FLAG(no_resizebar),
-             W_FLAG(no_close_button),
-             W_FLAG(no_miniaturize_button),
-             /*
-              W_FLAG(broken_close),
-              W_FLAG(kill_close),
-              */
-             W_FLAG(no_shadeable),
-             W_FLAG(omnipresent),
-             W_FLAG(skip_window_list),
-             W_FLAG(floating),
-             W_FLAG(sunken),
-             W_FLAG(no_bind_keys),
-             W_FLAG(no_bind_mouse),
-             W_FLAG(no_hide_others),
-             W_FLAG(no_appicon),
-             W_FLAG(dont_move_off),
-             W_FLAG(no_focusable),
-             W_FLAG(always_user_icon),
-             W_FLAG(start_miniaturized),
-             W_FLAG(start_hidden),
-             W_FLAG(start_maximized),
-             W_FLAG(dont_save_session),
-             W_FLAG(emulate_appicon));
-
-    return WMCreatePLString(buffer);
-}
-
-
-static void
-appendStringInArray(WMPropList *array, char *str)
-{
-    WMPropList *val;
-
-    val = WMCreatePLString(str);
-    WMAddToPLArray(array, val);
-    WMReleasePropList(val);
-}
-
-
-static WMPropList*
-makeClientState(WWindow *wwin)
-{
-    WMPropList *state;
-    WMPropList *tmp;
-    char *str;
-    char buffer[512];
-    int i;
-    unsigned shortcuts;
-
-    state = WMCreatePLArray(NULL, NULL);
-
-    /* WM_WINDOW_ROLE */
-    str = getWindowRole(wwin->client_win);
-    if (!str)
-        appendStringInArray(state, "");
-    else {
-        appendStringInArray(state, str);
-        XFree(str);
-    }
-
-    /* WM_CLASS.instance */
-    appendStringInArray(state, wwin->wm_instance);
-
-    /* WM_CLASS.class */
-    appendStringInArray(state, wwin->wm_class);
-
-    /* WM_NAME */
-    if (wwin->flags.wm_name_changed)
-        appendStringInArray(state, "");
-    else
-        appendStringInArray(state, wwin->frame->name);
-
-    /* geometry */
-    snprintf(buffer, sizeof(buffer), "%i %i %i %i %i %i", wwin->frame_x, wwin->frame_y,
-             wwin->client.width, wwin->client.height,
-             wwin->flags.user_changed_width, wwin->flags.user_changed_height);
-    appendStringInArray(state, buffer);
-
-    /* state */
-    snprintf(buffer, sizeof(buffer), "%i %i %i", wwin->flags.miniaturized,
-             wwin->flags.shaded, wwin->flags.maximized);
-    appendStringInArray(state, buffer);
-
-    /* attributes */
-    tmp = makeAttributeState(wwin);
-    WMAddToPLArray(state, tmp);
-    WMReleasePropList(tmp);
-
-    /* workspace */
-    snprintf(buffer, sizeof(buffer), "%i", wwin->frame->workspace);
-    appendStringInArray(state, buffer);
-
-    /* app state (repeated for all windows of the app) */
-    tmp = makeAppState(wwin);
-    WMAddToPLArray(state, tmp);
-    WMReleasePropList(tmp);
-
-    /* shortcuts */
-    shortcuts = 0;
-    for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
-        if (scr->shortcutWindow[i] == wwin) {
-            shortcuts |= 1 << i;
-        }
-    }
-    snprintf(buffer, sizeof(buffer), "%ui", shortcuts);
-    appendStringInArray(tmp, buffer);
-
-    return state;
-}
-
-
-static void
-smSaveYourselfPhase2Proc(SmcConn smc_conn, SmPointer client_data)
-{
-    SmProp props[4];
-    SmPropValue prop1val, prop2val, prop3val, prop4val;
-    char **argv = (char**)client_data;
-    int argc;
-    int i, j;
-    Bool ok = False;
-    char *statefile = NULL;
-    char *prefix;
-    Bool gsPrefix = False;
-    char *discardCmd = NULL;
-    time_t t;
-    WMPropList *state, *plState;
-    int len;
-
-#ifdef DEBUG1
-    puts("received SaveYourselfPhase2 SM message");
-#endif
-
-    /* save session state */
-
-    /* the file that will contain the state */
-    prefix = getenv("SM_SAVE_DIR");
-    if (!prefix) {
-        prefix = wusergnusteppath();
-        if (prefix)
-            gsPrefix = True;
-    }
-    if (!prefix) {
-        prefix = getenv("HOME");
-    }
-    if (!prefix)
-        prefix = ".";
-
-    len = strlen(prefix)+64;
-    statefile = malloc(len);
-    if (!statefile) {
-        wwarning(_("out of memory while saving session state"));
-        goto fail;
-    }
-
-    t = time();
-    i = 0;
-    do {
-        if (gsPrefix)
-            snprintf(statefile, len, "%s/Library/WindowMaker/wmaker.%l%i.state",
-                     prefix, t, i);
-        else
-            snprintf(statefile, len, "%s/wmaker.%l%i.state", prefix, t, i);
-        i++;
-    } while (access(F_OK, statefile)!=-1);
-
-    /* save the states of all windows we're managing */
-    state = WMCreatePLArray(NULL, NULL);
-
-    /*
-     * Format:
-     *
-     * state_file ::= dictionary with version_info ; state
-     * version_info ::= 'version' = '1';
-     * state ::= 'state' = array of screen_info
-     * screen_info ::= array of (screen number, window_info, window_info, ...)
-     * window_info ::=
-     */
-    for (i=0; i<wScreenCount; i++) {
-        WScreen *scr;
-        WWindow *wwin;
-        char buf[32];
-        WMPropList *pscreen;
-
-        scr = wScreenWithNumber(i);
-
-        snprintf(buf, sizeof(buf), "%i", scr->screen);
-        pscreen = WMCreatePLArray(WMCreatePLString(buf), NULL);
-
-        wwin = scr->focused_window;
-        while (wwin) {
-            WMPropList *pwindow;
-
-            pwindow = makeClientState(wwin);
-            WMAddToPLArray(pscreen, pwindow);
-
-            wwin = wwin->prev;
-        }
-
-        WMAddToPLArray(state, pscreen);
-    }
-
-    plState = WMCreatePLDictionary(WMCreatePLString("Version"),
-                                   WMCreatePLString("1.0"),
-                                   WMCreatePLString("Screens"),
-                                   state, NULL);
-
-    WMWritePropListToFile(plState, statefile, False);
-
-    WMReleasePropList(plState);
-
-    /* set the remaining properties that we didn't set at
-     * startup time */
-
-    for (argc=0, i=0; argv[i]!=NULL; i++) {
-        if (strcmp(argv[i], "-clientid")==0
-            || strcmp(argv[i], "-restore")==0) {
-            i++;
-        } else {
-            argc++;
-        }
-    }
-
-    prop[0].name = SmRestartCommand;
-    prop[0].type = SmLISTofARRAY8;
-    prop[0].vals = malloc(sizeof(SmPropValue)*(argc+4));
-    prop[0].num_vals = argc+4;
-
-    prop[1].name = SmCloneCommand;
-    prop[1].type = SmLISTofARRAY8;
-    prop[1].vals = malloc(sizeof(SmPropValue)*(argc));
-    prop[1].num_vals = argc;
-
-    if (!prop[0].vals || !prop[1].vals) {
-        wwarning(_("end of memory while saving session state"));
-        goto fail;
-    }
-
-    for (j=0, i=0; i<argc+4; i++) {
-        if (strcmp(argv[i], "-clientid")==0
-            || strcmp(argv[i], "-restore")==0) {
-            i++;
-        } else {
-            prop[0].vals[j].value = argv[i];
-            prop[0].vals[j].length = strlen(argv[i]);
-            prop[1].vals[j].value = argv[i];
-            prop[1].vals[j].length = strlen(argv[i]);
-            j++;
-        }
-    }
-    prop[0].vals[j].value = "-clientid";
-    prop[0].vals[j].length = 9;
-    j++;
-    prop[0].vals[j].value = sClientID;
-    prop[0].vals[j].length = strlen(sClientID);
-    j++;
-    prop[0].vals[j].value = "-restore";
-    prop[0].vals[j].length = 11;
-    j++;
-    prop[0].vals[j].value = statefile;
-    prop[0].vals[j].length = strlen(statefile);
-
-    {
-        int len = strlen(statefile)+8;
-
-        discardCmd = malloc(len);
-        if (!discardCmd)
-            goto fail;
-        snprintf(discardCmd, len, "rm %s", statefile);
-    }
-    prop[2].name = SmDiscardCommand;
-    prop[2].type = SmARRAY8;
-    prop[2].vals[0] = discardCmd;
-    prop[2].num_vals = 1;
-
-    SmcSetProperties(sSMCConn, 3, prop);
-
-    ok = True;
-fail:
-    SmcSaveYourselfDone(smc_conn, ok);
-
-    if (prop[0].vals)
-        wfree(prop[0].vals);
-    if (prop[1].vals)
-        wfree(prop[1].vals);
-    if (discardCmd)
-        wfree(discardCmd);
-
-    if (!ok) {
-        remove(statefile);
-    }
-    if (statefile)
-        wfree(statefile);
-}
-
-
-static void
-smSaveYourselfProc(SmcConn smc_conn, SmPointer client_data, int save_type,
-                   Bool shutdown, int interact_style, Bool fast)
-{
-#ifdef DEBUG1
-    puts("received SaveYourself SM message");
-#endif
-
-    if (!SmcRequestSaveYourselfPhase2(smc_conn, smSaveYourselfPhase2Proc,
-                                      client_data)) {
-
-        SmcSaveYourselfDone(smc_conn, False);
-        sWaitingPhase2 = False;
-    } else {
-#ifdef DEBUG1
-        puts("successfull request of SYS phase 2");
-#endif
-        sWaitingPhase2 = True;
-    }
-}
-
-
-static void
-smDieProc(SmcConn smc_conn, SmPointer client_data)
-{
-#ifdef DEBUG1
-    puts("received Die SM message");
-#endif
-
-    wSessionDisconnectManager();
-
-    Shutdown(WSExitMode, True);
-}
-
-
-
-static void
-smSaveCompleteProc(SmcConn smc_conn)
-{
-    /* it means that we can resume doing things that can change our state */
-#ifdef DEBUG1
-    puts("received SaveComplete SM message");
-#endif
-}
-
-
-static void
-smShutdownCancelledProc(SmcConn smc_conn, SmPointer client_data)
-{
-    if (sWaitingPhase2) {
-
-        sWaitingPhase2 = False;
-
-        SmcSaveYourselfDone(smc_conn, False);
-    }
-}
-
-
-static void
-iceMessageProc(int fd, int mask, void *clientData)
-{
-    IceConn iceConn = (IceConn)clientData;
-
-    IceProcessMessages(iceConn, NULL, NULL);
-}
-
-
-static void
-iceIOErrorHandler(IceConnection ice_conn)
-{
-    /* This is not fatal but can mean the session manager exited.
-     * If the session manager exited normally we would get a
-     * Die message, so this probably means an abnormal exit.
-     * If the sm was the last client of session, then we'll die
-     * anyway, otherwise we can continue doing our stuff.
-     */
-    wwarning(_("connection to the session manager was lost"));
-    wSessionDisconnectManager();
-}
-
-
-void
-wSessionConnectManager(char **argv, int argc)
-{
-    IceConn iceConn;
-    char *previous_id = NULL;
-    char buffer[256];
-    SmcCallbacks callbacks;
-    unsigned long mask;
-    char uid[32];
-    char pid[32];
-    SmProp props[4];
-    SmPropValue prop1val, prop2val, prop3val, prop4val;
-    char restartStyle;
-    int i;
-
-    mask = SmcSaveYourselfProcMask|SmcDieProcMask|SmcSaveCompleteProcMask
-        |SmcShutdownCancelledProcMask;
-
-    callbacks.save_yourself.callback = smSaveYourselfProc;
-    callbacks.save_yourself.client_data = argv;
-
-    callbacks.die.callback = smDieProc;
-    callbacks.die.client_data = NULL;
-
-    callbacks.save_complete.callback = smSaveCompleteProc;
-    callbacks.save_complete.client_data = NULL;
-
-    callbacks.shutdown_cancelled.callback = smShutdownCancelledProc;
-    callbacks.shutdown_cancelled.client_data = NULL;
-
-    for (i=0; i<argc; i++) {
-        if (strcmp(argv[i], "-clientid")==0) {
-            previous_id = argv[i+1];
-            break;
-        }
-    }
-
-    /* connect to the session manager */
-    sSMCConn = SmcOpenConnection(NULL, NULL, SmProtoMajor, SmProtoMinor,
-                                 mask, &callbacks, previous_id,
-                                 &sClientID, 255, buffer);
-    if (!sSMCConn) {
-        return;
-    }
-#ifdef DEBUG1
-    puts("connected to the session manager");
-#endif
-
-    /*    IceSetIOErrorHandler(iceIOErrorHandler);*/
-
-    /* check for session manager clients */
-    iceConn = SmcGetIceConnection(smcConn);
-
-    if (fcntl(IceConnectionNumber(iceConn), F_SETFD, FD_CLOEXEC) < 0) {
-        wsyserror("error setting close-on-exec flag for ICE connection");
-    }
-
-    sSMInputHandler = WMAddInputHandler(IceConnectionNumber(iceConn),
-                                        WIReadMask, iceMessageProc, iceConn);
-
-    /* setup information about ourselves */
-
-    /* program name */
-    prop1val.value = argv[0];
-    prop1val.length = strlen(argv[0]);
-    prop[0].name = SmProgram;
-    prop[0].type = SmARRAY8;
-    prop[0].num_vals = 1;
-    prop[0].vals = &prop1val;
-
-    /* The XSMP doc from X11R6.1 says it contains the user name,
-     * but every client implementation I saw places the uid # */
-    snprintf(uid, sizeof(uid), "%i", getuid());
-    prop2val.value = uid;
-    prop2val.length = strlen(uid);
-    prop[1].name = SmUserID;
-    prop[1].type = SmARRAY8;
-    prop[1].num_vals = 1;
-    prop[1].vals = &prop2val;
-
-    /* Restart style. We should restart only if we were running when
-     * the previous session finished. */
-    restartStyle = SmRestartIfRunning;
-    prop3val.value = &restartStyle;
-    prop3val.length = 1;
-    prop[2].name = SmRestartStyleHint;
-    prop[2].type = SmCARD8;
-    prop[2].num_vals = 1;
-    prop[2].vals = &prop3val;
-
-    /* Our PID. Not required but might be usefull */
-    snprintf(pid, sizeof(pid), "%i", getpid());
-    prop4val.value = pid;
-    prop4val.length = strlen(pid);
-    prop[3].name = SmProcessID;
-    prop[3].type = SmARRAY8;
-    prop[3].num_vals = 1;
-    prop[3].vals = &prop4val;
-
-    /* we'll set the rest of the hints later */
-
-    SmcSetProperties(sSMCConn, 4, props);
-
-}
-
-
-void
-wSessionDisconnectManager(void)
-{
-    if (sSMCConn) {
-        WMDeleteInputHandler(sSMInputHandler);
-        sSMInputHandler = NULL;
-
-        SmcCloseConnection(sSMCConn, 0, NULL);
-        sSMCConn = NULL;
-    }
-}
-
-void
-wSessionRequestShutdown(void)
-{
-    /* request a shutdown to the session manager */
-    if (sSMCConn)
-        SmcRequestSaveYourself(sSMCConn, SmSaveBoth, True, SmInteractStyleAny,
-                               False, True);
-}
-
-
-Bool
-wSessionIsManaged(void)
-{
-    return sSMCConn!=NULL;
-}
-
-#endif /* !XSMP_ENABLED */
-
+/* session.c - session state handling and R6 style session management
+ *
+ *  Copyright (c) 1998-2003 Dan Pascu
+ *  Copyright (c) 1998-2003 Alfredo Kojima
+ *
+ *  Window Maker window manager
+ *
+ *  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.
+ */
+
+/*
+ *
+ * If defined(XSMP_ENABLED) and session manager is running then
+ *     do normal stuff
+ * else
+ *     do pre-R6 session management stuff (save window state and relaunch)
+ *
+ * When doing a checkpoint:
+ *
+ * = Without XSMP
+ * Open "Stop"/status Dialog
+ * Send SAVE_YOURSELF to clients and wait for reply
+ * Save restart info
+ * Save state of clients
+ *
+ * = With XSMP
+ * Send checkpoint request to sm
+ *
+ * When exiting:
+ * -------------
+ *
+ * = Without XSMP
+ *
+ * Open "Exit Now"/status Dialog
+ * Send SAVE_YOURSELF to clients and wait for reply
+ * Save restart info
+ * Save state of clients
+ * Send DELETE to all clients
+ * When no more clients are left or user hit "Exit Now", exit
+ *
+ * = With XSMP
+ *
+ * Send Shutdown request to session manager
+ * if SaveYourself message received, save state of clients
+ * if the Die message is received, exit.
+ */
+
+#include "wconfig.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#ifdef XSMP_ENABLED
+#include <X11/SM/SMlib.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "WindowMaker.h"
+#include "screen.h"
+#include "window.h"
+#include "client.h"
+#include "session.h"
+#include "wcore.h"
+#include "framewin.h"
+#include "workspace.h"
+#include "funcs.h"
+#include "properties.h"
+#include "application.h"
+#include "appicon.h"
+
+#include "dock.h"
+
+#include <WINGs/WUtil.h>
+
+/** Global **/
+
+extern Atom _XA_WM_SAVE_YOURSELF;
+
+extern Time LastTimestamp;
+
+#ifdef XSMP_ENABLED
+
+extern int wScreenCount;
+
+/* requested for SaveYourselfPhase2 */
+static Bool sWaitingPhase2 = False;
+
+static SmcConn sSMCConn = NULL;
+
+static WMHandlerID sSMInputHandler = NULL;
+
+/* our SM client ID */
+static char *sClientID = NULL;
+#endif
+
+static WMPropList *sApplications = NULL;
+static WMPropList *sCommand;
+static WMPropList *sName;
+static WMPropList *sHost;
+static WMPropList *sWorkspace;
+static WMPropList *sShaded;
+static WMPropList *sMiniaturized;
+static WMPropList *sHidden;
+static WMPropList *sGeometry;
+static WMPropList *sShortcutMask;
+
+static WMPropList *sDock;
+
+static WMPropList *sYes, *sNo;
+
+static void make_keys()
+{
+       if (sApplications != NULL)
+               return;
+
+       sApplications = WMCreatePLString("Applications");
+       sCommand = WMCreatePLString("Command");
+       sName = WMCreatePLString("Name");
+       sHost = WMCreatePLString("Host");
+       sWorkspace = WMCreatePLString("Workspace");
+       sShaded = WMCreatePLString("Shaded");
+       sMiniaturized = WMCreatePLString("Miniaturized");
+       sHidden = WMCreatePLString("Hidden");
+       sGeometry = WMCreatePLString("Geometry");
+       sDock = WMCreatePLString("Dock");
+       sShortcutMask = WMCreatePLString("ShortcutMask");
+
+       sYes = WMCreatePLString("Yes");
+       sNo = WMCreatePLString("No");
+}
+
+static int getBool(WMPropList * value)
+{
+       char *val;
+
+       if (!WMIsPLString(value)) {
+               return 0;
+       }
+       if (!(val = WMGetFromPLString(value))) {
+               return 0;
+       }
+
+       if ((val[1] == '\0' && (val[0] == 'y' || val[0] == 'Y'))
+           || strcasecmp(val, "YES") == 0) {
+
+               return 1;
+       } else if ((val[1] == '\0' && (val[0] == 'n' || val[0] == 'N'))
+                  || strcasecmp(val, "NO") == 0) {
+               return 0;
+       } else {
+               int i;
+               if (sscanf(val, "%i", &i) == 1) {
+                       return (i != 0);
+               } else {
+                       wwarning(_("can't convert \"%s\" to boolean"), val);
+                       return 0;
+               }
+       }
+}
+
+static unsigned getInt(WMPropList * value)
+{
+       char *val;
+       unsigned n;
+
+       if (!WMIsPLString(value))
+               return 0;
+       val = WMGetFromPLString(value);
+       if (!val)
+               return 0;
+       if (sscanf(val, "%u", &n) != 1)
+               return 0;
+
+       return n;
+}
+
+static WMPropList *makeWindowState(WWindow * wwin, WApplication * wapp)
+{
+       WScreen *scr = wwin->screen_ptr;
+       Window win;
+       int i;
+       unsigned mask;
+       char *class, *instance, *command = NULL, buffer[512];
+       WMPropList *win_state, *cmd, *name, *workspace;
+       WMPropList *shaded, *miniaturized, *hidden, *geometry;
+       WMPropList *dock, *shortcut;
+
+       if (wwin->orig_main_window != None && wwin->orig_main_window != wwin->client_win)
+               win = wwin->orig_main_window;
+       else
+               win = wwin->client_win;
+
+       command = GetCommandForWindow(win);
+       if (!command)
+               return NULL;
+
+       if (PropGetWMClass(win, &class, &instance)) {
+               if (class && instance)
+                       snprintf(buffer, sizeof(buffer), "%s.%s", instance, class);
+               else if (instance)
+                       snprintf(buffer, sizeof(buffer), "%s", instance);
+               else if (class)
+                       snprintf(buffer, sizeof(buffer), ".%s", class);
+               else
+                       snprintf(buffer, sizeof(buffer), ".");
+
+               name = WMCreatePLString(buffer);
+               cmd = WMCreatePLString(command);
+               /*sprintf(buffer, "%d", wwin->frame->workspace+1);
+                  workspace = WMCreatePLString(buffer); */
+               workspace = WMCreatePLString(scr->workspaces[wwin->frame->workspace]->name);
+               shaded = wwin->flags.shaded ? sYes : sNo;
+               miniaturized = wwin->flags.miniaturized ? sYes : sNo;
+               hidden = wwin->flags.hidden ? sYes : sNo;
+               snprintf(buffer, sizeof(buffer), "%ix%i+%i+%i",
+                        wwin->client.width, wwin->client.height, wwin->frame_x, wwin->frame_y);
+               geometry = WMCreatePLString(buffer);
+
+               for (mask = 0, i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
+                       if (scr->shortcutWindows[i] != NULL &&
+                           WMGetFirstInArray(scr->shortcutWindows[i], wwin) != WANotFound) {
+                               mask |= 1 << i;
+                       }
+               }
+
+               snprintf(buffer, sizeof(buffer), "%u", mask);
+               shortcut = WMCreatePLString(buffer);
+
+               win_state = WMCreatePLDictionary(sName, name,
+                                                sCommand, cmd,
+                                                sWorkspace, workspace,
+                                                sShaded, shaded,
+                                                sMiniaturized, miniaturized,
+                                                sHidden, hidden,
+                                                sShortcutMask, shortcut, sGeometry, geometry, NULL);
+
+               WMReleasePropList(name);
+               WMReleasePropList(cmd);
+               WMReleasePropList(workspace);
+               WMReleasePropList(geometry);
+               WMReleasePropList(shortcut);
+               if (wapp && wapp->app_icon && wapp->app_icon->dock) {
+                       int i;
+                       char *name;
+                       if (wapp->app_icon->dock == scr->dock) {
+                               name = "Dock";
+                       } else {
+                               for (i = 0; i < scr->workspace_count; i++)
+                                       if (scr->workspaces[i]->clip == wapp->app_icon->dock)
+                                               break;
+                               assert(i < scr->workspace_count);
+                               /*n = i+1; */
+                               name = scr->workspaces[i]->name;
+                       }
+                       dock = WMCreatePLString(name);
+                       WMPutInPLDictionary(win_state, sDock, dock);
+                       WMReleasePropList(dock);
+               }
+       } else {
+               win_state = NULL;
+       }
+
+       if (instance)
+               XFree(instance);
+       if (class)
+               XFree(class);
+       if (command)
+               wfree(command);
+
+       return win_state;
+}
+
+void wSessionSaveState(WScreen * scr)
+{
+       WWindow *wwin = scr->focused_window;
+       WMPropList *win_info, *wks;
+       WMPropList *list = NULL;
+       WMArray *wapp_list = NULL;
+
+       make_keys();
+
+       if (!scr->session_state) {
+               scr->session_state = WMCreatePLDictionary(NULL, NULL);
+               if (!scr->session_state)
+                       return;
+       }
+
+       list = WMCreatePLArray(NULL);
+
+       wapp_list = WMCreateArray(16);
+
+       while (wwin) {
+               WApplication *wapp = wApplicationOf(wwin->main_window);
+               Window appId = wwin->orig_main_window;
+
+               if ((wwin->transient_for == None || wwin->transient_for == wwin->screen_ptr->root_win)
+                   && WMGetFirstInArray(wapp_list, (void *)appId) == WANotFound
+                   && !WFLAGP(wwin, dont_save_session)) {
+                       /* A entry for this application was not yet saved. Save one. */
+                       if ((win_info = makeWindowState(wwin, wapp)) != NULL) {
+                               WMAddToPLArray(list, win_info);
+                               WMReleasePropList(win_info);
+                               /* If we were succesful in saving the info for this window
+                                * add the application the window belongs to, to the
+                                * application list, so no multiple entries for the same
+                                * application are saved.
+                                */
+                               WMAddToArray(wapp_list, (void *)appId);
+                       }
+               }
+               wwin = wwin->prev;
+       }
+       WMRemoveFromPLDictionary(scr->session_state, sApplications);
+       WMPutInPLDictionary(scr->session_state, sApplications, list);
+       WMReleasePropList(list);
+
+       wks = WMCreatePLString(scr->workspaces[scr->current_workspace]->name);
+       WMPutInPLDictionary(scr->session_state, sWorkspace, wks);
+       WMReleasePropList(wks);
+
+       WMFreeArray(wapp_list);
+}
+
+void wSessionClearState(WScreen * scr)
+{
+       make_keys();
+
+       if (!scr->session_state)
+               return;
+
+       WMRemoveFromPLDictionary(scr->session_state, sApplications);
+       WMRemoveFromPLDictionary(scr->session_state, sWorkspace);
+}
+
+static pid_t execCommand(WScreen * scr, char *command, char *host)
+{
+       pid_t pid;
+       char **argv;
+       int argc;
+
+       wtokensplit(command, &argv, &argc);
+
+       if (!argc) {
+               return 0;
+       }
+
+       if ((pid = fork()) == 0) {
+               char **args;
+               int i;
+
+               SetupEnvironment(scr);
+
+               args = malloc(sizeof(char *) * (argc + 1));
+               if (!args)
+                       exit(111);
+               for (i = 0; i < argc; i++) {
+                       args[i] = argv[i];
+               }
+               args[argc] = NULL;
+               execvp(argv[0], args);
+               exit(111);
+       }
+       while (argc > 0)
+               wfree(argv[--argc]);
+       wfree(argv);
+       return pid;
+}
+
+static WSavedState *getWindowState(WScreen * scr, WMPropList * win_state)
+{
+       WSavedState *state = wmalloc(sizeof(WSavedState));
+       WMPropList *value;
+       char *tmp;
+       unsigned mask;
+       int i;
+
+       memset(state, 0, sizeof(WSavedState));
+       state->workspace = -1;
+       value = WMGetFromPLDictionary(win_state, sWorkspace);
+       if (value && WMIsPLString(value)) {
+               tmp = WMGetFromPLString(value);
+               if (sscanf(tmp, "%i", &state->workspace) != 1) {
+                       state->workspace = -1;
+                       for (i = 0; i < scr->workspace_count; i++) {
+                               if (strcmp(scr->workspaces[i]->name, tmp) == 0) {
+                                       state->workspace = i;
+                                       break;
+                               }
+                       }
+               } else {
+                       state->workspace--;
+               }
+       }
+       if ((value = WMGetFromPLDictionary(win_state, sShaded)) != NULL)
+               state->shaded = getBool(value);
+       if ((value = WMGetFromPLDictionary(win_state, sMiniaturized)) != NULL)
+               state->miniaturized = getBool(value);
+       if ((value = WMGetFromPLDictionary(win_state, sHidden)) != NULL)
+               state->hidden = getBool(value);
+       if ((value = WMGetFromPLDictionary(win_state, sShortcutMask)) != NULL) {
+               mask = getInt(value);
+               state->window_shortcuts = mask;
+       }
+
+       value = WMGetFromPLDictionary(win_state, sGeometry);
+       if (value && WMIsPLString(value)) {
+               if (!(sscanf(WMGetFromPLString(value), "%ix%i+%i+%i",
+                            &state->w, &state->h, &state->x, &state->y) == 4 && (state->w > 0 && state->h > 0))) {
+                       state->w = 0;
+                       state->h = 0;
+               }
+       }
+
+       return state;
+}
+
+#define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
+
+void wSessionRestoreState(WScreen * scr)
+{
+       WSavedState *state;
+       char *instance, *class, *command, *host;
+       WMPropList *win_info, *apps, *cmd, *value;
+       pid_t pid;
+       int i, count;
+       WDock *dock;
+       WAppIcon *btn = NULL;
+       int j, n, found;
+       char *tmp;
+
+       make_keys();
+
+       if (!scr->session_state)
+               return;
+
+       WMPLSetCaseSensitive(True);
+
+       apps = WMGetFromPLDictionary(scr->session_state, sApplications);
+       if (!apps)
+               return;
+
+       count = WMGetPropListItemCount(apps);
+       if (count == 0)
+               return;
+
+       for (i = 0; i < count; i++) {
+               win_info = WMGetFromPLArray(apps, i);
+
+               cmd = WMGetFromPLDictionary(win_info, sCommand);
+               if (!cmd || !WMIsPLString(cmd) || !(command = WMGetFromPLString(cmd))) {
+                       continue;
+               }
+
+               value = WMGetFromPLDictionary(win_info, sName);
+               if (!value)
+                       continue;
+
+               ParseWindowName(value, &instance, &class, "session");
+               if (!instance && !class)
+                       continue;
+
+               value = WMGetFromPLDictionary(win_info, sHost);
+               if (value && WMIsPLString(value))
+                       host = WMGetFromPLString(value);
+               else
+                       host = NULL;
+
+               state = getWindowState(scr, win_info);
+
+               dock = NULL;
+               value = WMGetFromPLDictionary(win_info, sDock);
+               if (value && WMIsPLString(value) && (tmp = WMGetFromPLString(value)) != NULL) {
+                       if (sscanf(tmp, "%i", &n) != 1) {
+                               if (!strcasecmp(tmp, "DOCK")) {
+                                       dock = scr->dock;
+                               } else {
+                                       for (j = 0; j < scr->workspace_count; j++) {
+                                               if (strcmp(scr->workspaces[j]->name, tmp) == 0) {
+                                                       dock = scr->workspaces[j]->clip;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       } else {
+                               if (n == 0) {
+                                       dock = scr->dock;
+                               } else if (n > 0 && n <= scr->workspace_count) {
+                                       dock = scr->workspaces[n - 1]->clip;
+                               }
+                       }
+               }
+
+               found = 0;
+               if (dock != NULL) {
+                       for (j = 0; j < dock->max_icons; j++) {
+                               btn = dock->icon_array[j];
+                               if (btn && SAME(instance, btn->wm_instance) &&
+                                   SAME(class, btn->wm_class) && SAME(command, btn->command) && !btn->launching) {
+                                       found = 1;
+                                       break;
+                               }
+                       }
+               }
+
+               if (found) {
+                       wDockLaunchWithState(dock, btn, state);
+               } else if ((pid = execCommand(scr, command, host)) > 0) {
+                       wWindowAddSavedState(instance, class, command, pid, state);
+               } else {
+                       wfree(state);
+               }
+
+               if (instance)
+                       wfree(instance);
+               if (class)
+                       wfree(class);
+       }
+       /* clean up */
+       WMPLSetCaseSensitive(False);
+}
+
+void wSessionRestoreLastWorkspace(WScreen * scr)
+{
+       WMPropList *wks;
+       int w, i;
+       char *tmp;
+
+       make_keys();
+
+       if (!scr->session_state)
+               return;
+
+       WMPLSetCaseSensitive(True);
+
+       wks = WMGetFromPLDictionary(scr->session_state, sWorkspace);
+       if (!wks || !WMIsPLString(wks))
+               return;
+
+       tmp = WMGetFromPLString(wks);
+
+       /* clean up */
+       WMPLSetCaseSensitive(False);
+
+       if (sscanf(tmp, "%i", &w) != 1) {
+               w = -1;
+               for (i = 0; i < scr->workspace_count; i++) {
+                       if (strcmp(scr->workspaces[i]->name, tmp) == 0) {
+                               w = i;
+                               break;
+                       }
+               }
+       } else {
+               w--;
+       }
+
+       if (w != scr->current_workspace && w < scr->workspace_count) {
+               wWorkspaceChange(scr, w);
+       }
+}
+
+static void clearWaitingAckState(WScreen * scr)
+{
+       WWindow *wwin;
+       WApplication *wapp;
+
+       for (wwin = scr->focused_window; wwin != NULL; wwin = wwin->prev) {
+               wwin->flags.waiting_save_ack = 0;
+               if (wwin->main_window != None) {
+                       wapp = wApplicationOf(wwin->main_window);
+                       if (wapp)
+                               wapp->main_window_desc->flags.waiting_save_ack = 0;
+               }
+       }
+}
+
+void wSessionSaveClients(WScreen * scr)
+{
+
+}
+
+/*
+ * With XSMP, this job is done by smproxy
+ */
+void wSessionSendSaveYourself(WScreen * scr)
+{
+       WWindow *wwin;
+       int count;
+
+       /* freeze client interaction with clients */
+       XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
+       XGrabPointer(dpy, scr->root_win, False, ButtonPressMask | ButtonReleaseMask,
+                    GrabModeAsync, GrabModeAsync, scr->root_win, None, CurrentTime);
+
+       clearWaitingAckState(scr);
+
+       count = 0;
+
+       /* first send SAVE_YOURSELF for everybody */
+       for (wwin = scr->focused_window; wwin != NULL; wwin = wwin->prev) {
+               WWindow *mainWin;
+
+               mainWin = wWindowFor(wwin->main_window);
+
+               if (mainWin) {
+                       /* if the client is a multi-window client, only send message
+                        * to the main window */
+                       wwin = mainWin;
+               }
+
+               /* make sure the SAVE_YOURSELF flag is up-to-date */
+               PropGetProtocols(wwin->client_win, &wwin->protocols);
+
+               if (wwin->protocols.SAVE_YOURSELF) {
+                       if (!wwin->flags.waiting_save_ack) {
+                               wClientSendProtocol(wwin, _XA_WM_SAVE_YOURSELF, LastTimestamp);
+
+                               wwin->flags.waiting_save_ack = 1;
+                               count++;
+                       }
+               } else {
+                       wwin->flags.waiting_save_ack = 0;
+               }
+       }
+
+       /* then wait for acknowledge */
+       while (count > 0) {
+
+       }
+
+       XUngrabPointer(dpy, CurrentTime);
+       XUngrabKeyboard(dpy, CurrentTime);
+       XFlush(dpy);
+}
+
+#ifdef XSMP_ENABLED
+/*
+ * With full session management support, the part of WMState
+ * that store client window state will become obsolete (maybe we can reuse
+ *                                                     the old code too),
+ * but we still need to store state info like the dock and workspaces.
+ * It is better to keep dock/wspace info in WMState because the user
+ * might want to keep the dock configuration while not wanting to
+ * resume a previously saved session.
+ * So, wmaker specific state info can be saved in
+ * ~/GNUstep/Library/WindowMaker/statename.state
+ * Its better to not put it in the defaults directory because:
+ * - its not a defaults file (having domain names like wmaker0089504baa
+ * in the defaults directory wouldn't be very neat)
+ * - this state file is not meant to be edited by users
+ *
+ * The old session code will become obsolete. When wmaker is
+ * compiled with R6 sm support compiled in, it'll be better to
+ * use a totally rewritten state saving code, but we can keep
+ * the current code for when XSMP_ENABLED is not compiled in.
+ *
+ * This will be confusing to old users (well get lots of "SAVE_SESSION broke!"
+ * messages), but it'll be better.
+ *
+ * -readme
+ */
+
+static char *getWindowRole(Window window)
+{
+       XTextProperty prop;
+       static Atom atom = 0;
+
+       if (!atom)
+               atom = XInternAtom(dpy, "WM_WINDOW_ROLE", False);
+
+       if (XGetTextProperty(dpy, window, &prop, atom)) {
+               if (prop.encoding == XA_STRING && prop.format == 8 && prop.nitems > 0)
+                       return prop.value;
+       }
+
+       return NULL;
+}
+
+/*
+ *
+ * Saved Info:
+ *
+ * WM_WINDOW_ROLE
+ *
+ * WM_CLASS.instance
+ * WM_CLASS.class
+ * WM_NAME
+ * WM_COMMAND
+ *
+ * geometry
+ * state = (miniaturized, shaded, etc)
+ * attribute
+ * workspace #
+ * app state = (which dock, hidden)
+ * window shortcut #
+ */
+
+static WMPropList *makeAppState(WWindow * wwin)
+{
+       WApplication *wapp;
+       WMPropList *state;
+       WScreen *scr = wwin->screen_ptr;
+
+       state = WMCreatePLArray(NULL, NULL);
+
+       wapp = wApplicationOf(wwin->main_window);
+
+       if (wapp) {
+               if (wapp->app_icon && wapp->app_icon->dock) {
+
+                       if (wapp->app_icon->dock == scr->dock) {
+                               WMAddToPLArray(state, WMCreatePLString("Dock"));
+                       } else {
+                               int i;
+
+                               for (i = 0; i < scr->workspace_count; i++)
+                                       if (scr->workspaces[i]->clip == wapp->app_icon->dock)
+                                               break;
+
+                               assert(i < scr->workspace_count);
+
+                               WMAddToPLArray(state, WMCreatePLString(scr->workspaces[i]->name));
+                       }
+               }
+
+               WMAddToPLArray(state, WMCreatePLString(wapp->hidden ? "1" : "0"));
+       }
+
+       return state;
+}
+
+Bool wSessionGetStateFor(WWindow * wwin, WSessionData * state)
+{
+       char *str;
+       WMPropList *slist;
+       WMPropList *elem;
+       WMPropList *value;
+       int index = 0;
+
+       index = 3;
+
+       /* geometry */
+       value = WMGetFromPLArray(slist, index++);
+       str = WMGetFromPLString(value);
+
+       sscanf(str, "%i %i %i %i %i %i", &state->x, &state->y,
+              &state->width, &state->height, &state->user_changed_width, &state->user_changed_height);
+
+       /* state */
+       value = WMGetFromPLArray(slist, index++);
+       str = WMGetFromPLString(value);
+
+       sscanf(str, "%i %i %i", &state->miniaturized, &state->shaded, &state->maximized);
+
+       /* attributes */
+       value = WMGetFromPLArray(slist, index++);
+       str = WMGetFromPLString(value);
+
+       getAttributeState(str, &state->mflags, &state->flags);
+
+       /* workspace */
+       value = WMGetFromPLArray(slist, index++);
+       str = WMGetFromPLString(value);
+
+       sscanf(str, "%i", &state->workspace);
+
+       /* app state (repeated for all windows of the app) */
+       value = WMGetFromPLArray(slist, index++);
+       str = WMGetFromPLString(value);
+
+       /* ???? */
+
+       /* shortcuts */
+       value = WMGetFromPLArray(slist, index++);
+       str = WMGetFromPLString(value);
+
+       sscanf(str, "%i", &state->shortcuts);
+}
+
+static WMPropList *makeAttributeState(WWindow * wwin)
+{
+       unsigned int data1, data2;
+       char buffer[256];
+
+#define W_FLAG(wwin, FLAG)     ((wwin)->defined_user_flags.FLAG \
+    ? (wwin)->user_flags.FLAG : -1)
+
+       snprintf(buffer, sizeof(buffer),
+                "%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
+                W_FLAG(no_titlebar),
+                W_FLAG(no_resizable),
+                W_FLAG(no_closable),
+                W_FLAG(no_miniaturizable),
+                W_FLAG(no_resizebar), W_FLAG(no_close_button), W_FLAG(no_miniaturize_button),
+                /*
+                   W_FLAG(broken_close),
+                   W_FLAG(kill_close),
+                 */
+                W_FLAG(no_shadeable),
+                W_FLAG(omnipresent),
+                W_FLAG(skip_window_list),
+                W_FLAG(floating),
+                W_FLAG(sunken),
+                W_FLAG(no_bind_keys),
+                W_FLAG(no_bind_mouse),
+                W_FLAG(no_hide_others),
+                W_FLAG(no_appicon),
+                W_FLAG(dont_move_off),
+                W_FLAG(no_focusable),
+                W_FLAG(always_user_icon),
+                W_FLAG(start_miniaturized),
+                W_FLAG(start_hidden),
+                W_FLAG(start_maximized), W_FLAG(dont_save_session), W_FLAG(emulate_appicon));
+
+       return WMCreatePLString(buffer);
+}
+
+static void appendStringInArray(WMPropList * array, char *str)
+{
+       WMPropList *val;
+
+       val = WMCreatePLString(str);
+       WMAddToPLArray(array, val);
+       WMReleasePropList(val);
+}
+
+static WMPropList *makeClientState(WWindow * wwin)
+{
+       WMPropList *state;
+       WMPropList *tmp;
+       char *str;
+       char buffer[512];
+       int i;
+       unsigned shortcuts;
+
+       state = WMCreatePLArray(NULL, NULL);
+
+       /* WM_WINDOW_ROLE */
+       str = getWindowRole(wwin->client_win);
+       if (!str)
+               appendStringInArray(state, "");
+       else {
+               appendStringInArray(state, str);
+               XFree(str);
+       }
+
+       /* WM_CLASS.instance */
+       appendStringInArray(state, wwin->wm_instance);
+
+       /* WM_CLASS.class */
+       appendStringInArray(state, wwin->wm_class);
+
+       /* WM_NAME */
+       if (wwin->flags.wm_name_changed)
+               appendStringInArray(state, "");
+       else
+               appendStringInArray(state, wwin->frame->name);
+
+       /* geometry */
+       snprintf(buffer, sizeof(buffer), "%i %i %i %i %i %i", wwin->frame_x, wwin->frame_y,
+                wwin->client.width, wwin->client.height,
+                wwin->flags.user_changed_width, wwin->flags.user_changed_height);
+       appendStringInArray(state, buffer);
+
+       /* state */
+       snprintf(buffer, sizeof(buffer), "%i %i %i", wwin->flags.miniaturized,
+                wwin->flags.shaded, wwin->flags.maximized);
+       appendStringInArray(state, buffer);
+
+       /* attributes */
+       tmp = makeAttributeState(wwin);
+       WMAddToPLArray(state, tmp);
+       WMReleasePropList(tmp);
+
+       /* workspace */
+       snprintf(buffer, sizeof(buffer), "%i", wwin->frame->workspace);
+       appendStringInArray(state, buffer);
+
+       /* app state (repeated for all windows of the app) */
+       tmp = makeAppState(wwin);
+       WMAddToPLArray(state, tmp);
+       WMReleasePropList(tmp);
+
+       /* shortcuts */
+       shortcuts = 0;
+       for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
+               if (scr->shortcutWindow[i] == wwin) {
+                       shortcuts |= 1 << i;
+               }
+       }
+       snprintf(buffer, sizeof(buffer), "%ui", shortcuts);
+       appendStringInArray(tmp, buffer);
+
+       return state;
+}
+
+static void smSaveYourselfPhase2Proc(SmcConn smc_conn, SmPointer client_data)
+{
+       SmProp props[4];
+       SmPropValue prop1val, prop2val, prop3val, prop4val;
+       char **argv = (char **)client_data;
+       int argc;
+       int i, j;
+       Bool ok = False;
+       char *statefile = NULL;
+       char *prefix;
+       Bool gsPrefix = False;
+       char *discardCmd = NULL;
+       time_t t;
+       WMPropList *state, *plState;
+       int len;
+
+#ifdef DEBUG1
+       puts("received SaveYourselfPhase2 SM message");
+#endif
+
+       /* save session state */
+
+       /* the file that will contain the state */
+       prefix = getenv("SM_SAVE_DIR");
+       if (!prefix) {
+               prefix = wusergnusteppath();
+               if (prefix)
+                       gsPrefix = True;
+       }
+       if (!prefix) {
+               prefix = getenv("HOME");
+       }
+       if (!prefix)
+               prefix = ".";
+
+       len = strlen(prefix) + 64;
+       statefile = malloc(len);
+       if (!statefile) {
+               wwarning(_("out of memory while saving session state"));
+               goto fail;
+       }
+
+       t = time();
+       i = 0;
+       do {
+               if (gsPrefix)
+                       snprintf(statefile, len, "%s/Library/WindowMaker/wmaker.%l%i.state", prefix, t, i);
+               else
+                       snprintf(statefile, len, "%s/wmaker.%l%i.state", prefix, t, i);
+               i++;
+       } while (access(F_OK, statefile) != -1);
+
+       /* save the states of all windows we're managing */
+       state = WMCreatePLArray(NULL, NULL);
+
+       /*
+        * Format:
+        *
+        * state_file ::= dictionary with version_info ; state
+        * version_info ::= 'version' = '1';
+        * state ::= 'state' = array of screen_info
+        * screen_info ::= array of (screen number, window_info, window_info, ...)
+        * window_info ::=
+        */
+       for (i = 0; i < wScreenCount; i++) {
+               WScreen *scr;
+               WWindow *wwin;
+               char buf[32];
+               WMPropList *pscreen;
+
+               scr = wScreenWithNumber(i);
+
+               snprintf(buf, sizeof(buf), "%i", scr->screen);
+               pscreen = WMCreatePLArray(WMCreatePLString(buf), NULL);
+
+               wwin = scr->focused_window;
+               while (wwin) {
+                       WMPropList *pwindow;
+
+                       pwindow = makeClientState(wwin);
+                       WMAddToPLArray(pscreen, pwindow);
+
+                       wwin = wwin->prev;
+               }
+
+               WMAddToPLArray(state, pscreen);
+       }
+
+       plState = WMCreatePLDictionary(WMCreatePLString("Version"),
+                                      WMCreatePLString("1.0"), WMCreatePLString("Screens"), state, NULL);
+
+       WMWritePropListToFile(plState, statefile, False);
+
+       WMReleasePropList(plState);
+
+       /* set the remaining properties that we didn't set at
+        * startup time */
+
+       for (argc = 0, i = 0; argv[i] != NULL; i++) {
+               if (strcmp(argv[i], "-clientid") == 0 || strcmp(argv[i], "-restore") == 0) {
+                       i++;
+               } else {
+                       argc++;
+               }
+       }
+
+       prop[0].name = SmRestartCommand;
+       prop[0].type = SmLISTofARRAY8;
+       prop[0].vals = malloc(sizeof(SmPropValue) * (argc + 4));
+       prop[0].num_vals = argc + 4;
+
+       prop[1].name = SmCloneCommand;
+       prop[1].type = SmLISTofARRAY8;
+       prop[1].vals = malloc(sizeof(SmPropValue) * (argc));
+       prop[1].num_vals = argc;
+
+       if (!prop[0].vals || !prop[1].vals) {
+               wwarning(_("end of memory while saving session state"));
+               goto fail;
+       }
+
+       for (j = 0, i = 0; i < argc + 4; i++) {
+               if (strcmp(argv[i], "-clientid") == 0 || strcmp(argv[i], "-restore") == 0) {
+                       i++;
+               } else {
+                       prop[0].vals[j].value = argv[i];
+                       prop[0].vals[j].length = strlen(argv[i]);
+                       prop[1].vals[j].value = argv[i];
+                       prop[1].vals[j].length = strlen(argv[i]);
+                       j++;
+               }
+       }
+       prop[0].vals[j].value = "-clientid";
+       prop[0].vals[j].length = 9;
+       j++;
+       prop[0].vals[j].value = sClientID;
+       prop[0].vals[j].length = strlen(sClientID);
+       j++;
+       prop[0].vals[j].value = "-restore";
+       prop[0].vals[j].length = 11;
+       j++;
+       prop[0].vals[j].value = statefile;
+       prop[0].vals[j].length = strlen(statefile);
+
+       {
+               int len = strlen(statefile) + 8;
+
+               discardCmd = malloc(len);
+               if (!discardCmd)
+                       goto fail;
+               snprintf(discardCmd, len, "rm %s", statefile);
+       }
+       prop[2].name = SmDiscardCommand;
+       prop[2].type = SmARRAY8;
+       prop[2].vals[0] = discardCmd;
+       prop[2].num_vals = 1;
+
+       SmcSetProperties(sSMCConn, 3, prop);
+
+       ok = True;
+ fail:
+       SmcSaveYourselfDone(smc_conn, ok);
+
+       if (prop[0].vals)
+               wfree(prop[0].vals);
+       if (prop[1].vals)
+               wfree(prop[1].vals);
+       if (discardCmd)
+               wfree(discardCmd);
+
+       if (!ok) {
+               remove(statefile);
+       }
+       if (statefile)
+               wfree(statefile);
+}
+
+static void
+smSaveYourselfProc(SmcConn smc_conn, SmPointer client_data, int save_type,
+                  Bool shutdown, int interact_style, Bool fast)
+{
+#ifdef DEBUG1
+       puts("received SaveYourself SM message");
+#endif
+
+       if (!SmcRequestSaveYourselfPhase2(smc_conn, smSaveYourselfPhase2Proc, client_data)) {
+
+               SmcSaveYourselfDone(smc_conn, False);
+               sWaitingPhase2 = False;
+       } else {
+#ifdef DEBUG1
+               puts("successfull request of SYS phase 2");
+#endif
+               sWaitingPhase2 = True;
+       }
+}
+
+static void smDieProc(SmcConn smc_conn, SmPointer client_data)
+{
+#ifdef DEBUG1
+       puts("received Die SM message");
+#endif
+
+       wSessionDisconnectManager();
+
+       Shutdown(WSExitMode, True);
+}
+
+static void smSaveCompleteProc(SmcConn smc_conn)
+{
+       /* it means that we can resume doing things that can change our state */
+#ifdef DEBUG1
+       puts("received SaveComplete SM message");
+#endif
+}
+
+static void smShutdownCancelledProc(SmcConn smc_conn, SmPointer client_data)
+{
+       if (sWaitingPhase2) {
+
+               sWaitingPhase2 = False;
+
+               SmcSaveYourselfDone(smc_conn, False);
+       }
+}
+
+static void iceMessageProc(int fd, int mask, void *clientData)
+{
+       IceConn iceConn = (IceConn) clientData;
+
+       IceProcessMessages(iceConn, NULL, NULL);
+}
+
+static void iceIOErrorHandler(IceConnection ice_conn)
+{
+       /* This is not fatal but can mean the session manager exited.
+        * If the session manager exited normally we would get a
+        * Die message, so this probably means an abnormal exit.
+        * If the sm was the last client of session, then we'll die
+        * anyway, otherwise we can continue doing our stuff.
+        */
+       wwarning(_("connection to the session manager was lost"));
+       wSessionDisconnectManager();
+}
+
+void wSessionConnectManager(char **argv, int argc)
+{
+       IceConn iceConn;
+       char *previous_id = NULL;
+       char buffer[256];
+       SmcCallbacks callbacks;
+       unsigned long mask;
+       char uid[32];
+       char pid[32];
+       SmProp props[4];
+       SmPropValue prop1val, prop2val, prop3val, prop4val;
+       char restartStyle;
+       int i;
+
+       mask = SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
+
+       callbacks.save_yourself.callback = smSaveYourselfProc;
+       callbacks.save_yourself.client_data = argv;
+
+       callbacks.die.callback = smDieProc;
+       callbacks.die.client_data = NULL;
+
+       callbacks.save_complete.callback = smSaveCompleteProc;
+       callbacks.save_complete.client_data = NULL;
+
+       callbacks.shutdown_cancelled.callback = smShutdownCancelledProc;
+       callbacks.shutdown_cancelled.client_data = NULL;
+
+       for (i = 0; i < argc; i++) {
+               if (strcmp(argv[i], "-clientid") == 0) {
+                       previous_id = argv[i + 1];
+                       break;
+               }
+       }
+
+       /* connect to the session manager */
+       sSMCConn = SmcOpenConnection(NULL, NULL, SmProtoMajor, SmProtoMinor,
+                                    mask, &callbacks, previous_id, &sClientID, 255, buffer);
+       if (!sSMCConn) {
+               return;
+       }
+#ifdef DEBUG1
+       puts("connected to the session manager");
+#endif
+
+       /*    IceSetIOErrorHandler(iceIOErrorHandler); */
+
+       /* check for session manager clients */
+       iceConn = SmcGetIceConnection(smcConn);
+
+       if (fcntl(IceConnectionNumber(iceConn), F_SETFD, FD_CLOEXEC) < 0) {
+               wsyserror("error setting close-on-exec flag for ICE connection");
+       }
+
+       sSMInputHandler = WMAddInputHandler(IceConnectionNumber(iceConn), WIReadMask, iceMessageProc, iceConn);
+
+       /* setup information about ourselves */
+
+       /* program name */
+       prop1val.value = argv[0];
+       prop1val.length = strlen(argv[0]);
+       prop[0].name = SmProgram;
+       prop[0].type = SmARRAY8;
+       prop[0].num_vals = 1;
+       prop[0].vals = &prop1val;
+
+       /* The XSMP doc from X11R6.1 says it contains the user name,
+        * but every client implementation I saw places the uid # */
+       snprintf(uid, sizeof(uid), "%i", getuid());
+       prop2val.value = uid;
+       prop2val.length = strlen(uid);
+       prop[1].name = SmUserID;
+       prop[1].type = SmARRAY8;
+       prop[1].num_vals = 1;
+       prop[1].vals = &prop2val;
+
+       /* Restart style. We should restart only if we were running when
+        * the previous session finished. */
+       restartStyle = SmRestartIfRunning;
+       prop3val.value = &restartStyle;
+       prop3val.length = 1;
+       prop[2].name = SmRestartStyleHint;
+       prop[2].type = SmCARD8;
+       prop[2].num_vals = 1;
+       prop[2].vals = &prop3val;
+
+       /* Our PID. Not required but might be usefull */
+       snprintf(pid, sizeof(pid), "%i", getpid());
+       prop4val.value = pid;
+       prop4val.length = strlen(pid);
+       prop[3].name = SmProcessID;
+       prop[3].type = SmARRAY8;
+       prop[3].num_vals = 1;
+       prop[3].vals = &prop4val;
+
+       /* we'll set the rest of the hints later */
+
+       SmcSetProperties(sSMCConn, 4, props);
+
+}
+
+void wSessionDisconnectManager(void)
+{
+       if (sSMCConn) {
+               WMDeleteInputHandler(sSMInputHandler);
+               sSMInputHandler = NULL;
+
+               SmcCloseConnection(sSMCConn, 0, NULL);
+               sSMCConn = NULL;
+       }
+}
+
+void wSessionRequestShutdown(void)
+{
+       /* request a shutdown to the session manager */
+       if (sSMCConn)
+               SmcRequestSaveYourself(sSMCConn, SmSaveBoth, True, SmInteractStyleAny, False, True);
+}
+
+Bool wSessionIsManaged(void)
+{
+       return sSMCConn != NULL;
+}
+
+#endif                         /* !XSMP_ENABLED */