/*****************************************************************************/ /** Copyright 1988 by Evans & Sutherland Computer Corporation, **/ /** Salt Lake City, Utah **/ /** Portions Copyright 1989 by the Massachusetts Institute of Technology **/ /** Cambridge, Massachusetts **/ /** **/ /** All Rights Reserved **/ /** **/ /** Permission to use, copy, modify, and distribute this software and **/ /** its documentation for any purpose and without fee is hereby **/ /** granted, provided that the above copyright notice appear in all **/ /** copies and that both that copyright notice and this permis- **/ /** sion notice appear in supporting documentation, and that the **/ /** names of Evans & Sutherland and M.I.T. not be used in advertising **/ /** in publicity pertaining to distribution of the software without **/ /** specific, written prior permission. **/ /** **/ /** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/ /** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/ /** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/ /** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/ /** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ /** OR PERFORMANCE OF THIS SOFTWARE. **/ /*****************************************************************************/ /* * [ ctwm ] * * Copyright 1992 Claude Lecommandeur. * * Permission to use, copy, modify and distribute this software [ctwm] and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting documen- * tation, and that the name of Claude Lecommandeur not be used in adverti- * sing or publicity pertaining to distribution of the software without * specific, written prior permission. Claude Lecommandeur make no represen- * tations about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. * * Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO * EVENT SHALL Claude Lecommandeur BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Author: Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ] */ /********************************************************************* * * This module has been modified by * Matthew McNeill (21 Mar 1997) - University of Durham (UK) * for the support of the X Session Management Protocol * ********************************************************************* * * Copyright (c) 1996-1997 The University of Durham, UK - * Department of Computer Science. * All rights reserved. * * Permission is hereby granted, without written agreement and without * licence or royalty fees, to use, copy, modify, and distribute this * software and its documentation, provided that usage, copying, modification * or distribution is not for direct commercial advantage and that the * above copyright notice and the following two paragraphs appear in * all copies of this software. To use, copy, modify or distribute this * software and its documentation otherwise requires a fee and/or specific * permission. * * IN NO EVENT SHALL THE UNIVERSITY OF DURHAM BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * DURHAM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF DURHAM SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF DURHAM HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * ********************************************************************/ /********************************************************************** * * $XConsortium: session.c,v 1.18 95/01/04 22:28:37 mor Exp $ * * Session support for the X11R6 XSMP (X Session Management Protocol) * * 95/01/04 Ralph Mor, X Consortium Initial Version. * * Do the necessary modification to be integrated in ctwm. * Can no longer be used for the standard twm. * * 21 Mar 1997 Matthew McNeill, Durham University Modified Version. * **********************************************************************/ #include #ifndef X_NOT_POSIX #ifdef _POSIX_SOURCE #include #else #define _POSIX_SOURCE #include #undef _POSIX_SOURCE #endif #endif /* X_NOT_POSIX */ #ifndef PATH_MAX #include #ifndef PATH_MAX #ifdef MAXPATHLEN #define PATH_MAX MAXPATHLEN #else #define PATH_MAX 1024 #endif #endif #endif /* PATH_MAX */ #include #include #include #include #include "twm.h" #include "icons.h" #include "screen.h" #include "session.h" SmcConn smcConn = NULL; XtInputId iceInputId; char *twm_clientId; TWMWinConfigEntry *winConfigHead = NULL; Bool gotFirstSave = 0; Bool sent_save_done = 0; #define SAVEFILE_VERSION 2 /*===[ Get Client SM_CLIENT_ID ]=============================================*/ char *GetClientID (Window window) /* This function returns the value of the session manager client ID property * given a valid window handle. If no such property exists on a window then * null is returned */ { char *client_id = NULL; Window client_leader; XTextProperty tp; Atom actual_type; int actual_format; unsigned long nitems; unsigned long bytes_after; Window *prop = NULL; if (XGetWindowProperty (dpy, window, _XA_WM_CLIENT_LEADER, 0L, 1L, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, (unsigned char **)&prop) == Success) { if (actual_type == XA_WINDOW && actual_format == 32 && nitems == 1 && bytes_after == 0) { client_leader = *prop; if (XGetTextProperty (dpy, client_leader, &tp, _XA_SM_CLIENT_ID)) { if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0) client_id = (char *) tp.value; } } if (prop) XFree (prop); } return client_id; } /*===[ Get Window Role ]=====================================================*/ char *GetWindowRole (Window window) /* this function returns the WM_WINDOW_ROLE property of a window */ { XTextProperty tp; if (XGetTextProperty (dpy, window, &tp, _XA_WM_WINDOW_ROLE)) { if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0) return ((char *) tp.value); } return NULL; } /*===[ Various file write procedures ]=======================================*/ static int write_byte (FILE *file, unsigned char b) { if (fwrite ((char *) &b, 1, 1, file) != 1) return 0; return 1; } /*---------------------------------------------------------------------------*/ static int write_ushort (FILE *file, unsigned short s) { unsigned char file_short[2]; file_short[0] = (s & (unsigned)0xff00) >> 8; file_short[1] = s & 0xff; if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) return 0; return 1; } /*---------------------------------------------------------------------------*/ static int write_short (FILE *file, short s) { unsigned char file_short[2]; file_short[0] = (s & (unsigned)0xff00) >> 8; file_short[1] = s & 0xff; if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) return 0; return 1; } /*---------------------------------------------------------------------------* * Matthew McNeill Feb 1997 - required to save the occupation state as an * integer. */ static int write_int (FILE *file, int i) { unsigned char file_int[4]; file_int[0] = (i & (unsigned)0xff000000) >> 24; file_int[1] = (i & (unsigned)0x00ff0000) >> 16; file_int[2] = (i & (unsigned)0x0000ff00) >> 8; file_int[3] = (i & (unsigned)0x000000ff); if (fwrite ((char *) file_int, (int) sizeof (file_int), 1, file) != 1) return 0; return 1; } /*---------------------------------------------------------------------------*/ static int write_counted_string (FILE *file, char *string) { if (string) { unsigned char count = strlen (string); if (write_byte (file, count) == 0) return 0; if (fwrite (string, (int) sizeof (char), (int) count, file) != count) return 0; } else { if (write_byte (file, 0) == 0) return 0; } return 1; } /*===[ various file read procedures ]========================================*/ static int read_byte (FILE *file, unsigned char *bp) { if (fread ((char *) bp, 1, 1, file) != 1) return 0; return 1; } /*---------------------------------------------------------------------------*/ static int read_ushort (FILE *file, unsigned short *shortp) { unsigned char file_short[2]; if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) return 0; *shortp = file_short[0] * 256 + file_short[1]; return 1; } /*---------------------------------------------------------------------------*/ static int read_short (FILE *file, short *shortp) { unsigned char file_short[2]; if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) return 0; *shortp = file_short[0] * 256 + file_short[1]; return 1; } /*---------------------------------------------------------------------------* * Matthew McNeill Feb 1997 - required to save the occupation state as an * integer. */ static int read_int (FILE *file, int *intp) { unsigned char file_int[4]; if (fread ((char *) file_int, (int) sizeof (file_int), 1, file) != 1) return 0; *intp = (((int) file_int[0]) << 24) & 0xff000000; *intp += (((int) file_int[1]) << 16) & 0x00ff0000; *intp += (((int) file_int[2]) << 8) & 0x0000ff00; *intp += ((int) file_int[3]); return 1; } /*---------------------------------------------------------------------------*/ static int read_counted_string (FILE *file, char **stringp) { unsigned char len; char *data; if (read_byte (file, &len) == 0) return 0; if (len == 0) { data = 0; } else { data = malloc ((unsigned) len + 1); if (!data) return 0; if (fread (data, (int) sizeof (char), (int) len, file) != len) { free (data); return 0; } data[len] = '\0'; } *stringp = data; return 1; } /*===[ Definition of a window config entry ]=================================== * * An entry in the saved window config file looks like this: * * FIELD BYTES * ----- ---- * SM_CLIENT_ID ID len 1 (may be 0) * SM_CLIENT_ID LIST of bytes (may be NULL) * * WM_WINDOW_ROLE length 1 (may be 0) * WM_WINDOW_ROLE LIST of bytes (may be NULL) * * if no WM_WINDOW_ROLE (length = 0) * * WM_CLASS "res name" length 1 * WM_CLASS "res name" LIST of bytes * WM_CLASS "res class" length 1 * WM_CLASS "res class" LIST of bytes * WM_NAME length 1 (0 if name changed) * WM_NAME LIST of bytes * WM_COMMAND arg count 1 (0 if no SM_CLIENT_ID) * For each arg in WM_COMMAND * arg length 1 * arg LIST of bytes * * Iconified bool 1 * Icon info present bool 1 * * if icon info present * icon x 2 * icon y 2 * * Geom x 2 * Geom y 2 * Geom width 2 * Geom height 2 * * Width ever changed by user 1 * Height ever changed by user 1 * * ------------------[ Matthew McNeill Feb 1997 ]---------------------------- * * Workspace Occupation 4 * */ /*===[ Write Window Config Entry to file ]===================================*/ int WriteWinConfigEntry (FILE *configFile, TwmWindow *theWindow, char *clientId, char *windowRole) /* this function writes a window configuration entry of a given window to * the given configuration file */ { char **wm_command; int wm_command_count, i; /* ...unless the config file says otherwise. */ if (LookInList (Scr == NULL ? ScreenList [0]->DontSave : Scr->DontSave, theWindow->full_name, &theWindow->class)) return 1; if (!write_counted_string (configFile, clientId)) return 0; if (!write_counted_string (configFile, windowRole)) return 0; if (!windowRole) { if (!write_counted_string (configFile, theWindow->class.res_name)) return 0; if (!write_counted_string (configFile, theWindow->class.res_class)) return 0; if (theWindow->nameChanged) { /* * If WM_NAME changed on this window, we can't use it as * a criteria for looking up window configurations. See the * longer explanation in the GetWindowConfig() function below. */ if (!write_counted_string (configFile, NULL)) return 0; } else { if (!write_counted_string (configFile, theWindow->name)) return 0; } wm_command = NULL; wm_command_count = 0; XGetCommand (dpy, theWindow->w, &wm_command, &wm_command_count); if (clientId || !wm_command || wm_command_count == 0) { if (!write_byte (configFile, 0)) return 0; } else { if (!write_byte (configFile, (char) wm_command_count)) return 0; for (i = 0; i < wm_command_count; i++) if (!write_counted_string (configFile, wm_command[i])) return 0; XFreeStringList (wm_command); } } /* ===================[ Matthew McNeill Feb 1997 ]========================= * * there has been a structural change to TwmWindow in ctwm. The Icon information * is in a sub-structure now. The presence of icon information is not indicative * of its current state. There is a new boolean condition for this (isicon) */ if (!write_byte (configFile, theWindow->isicon ? 1 : 0)) return 0; /* iconified */ /* ===================[ Matthew McNeill Feb 1997 ]========================= * * there has been a structural change to TwmWindow in ctwm. The Icon information * is in a sub-structure now, if there is no icon, this sub-structure does * not exist and the attempted access (below) causes a core dump. * we need to check that the structure exists before trying to access it */ if (theWindow->icon) { if (!write_byte (configFile, theWindow->icon->w ? 1 : 0)) return 0; /* icon info exists */ if (theWindow->icon->w) { int icon_x, icon_y; XGetGeometry (dpy, theWindow->icon->w, &JunkRoot, &icon_x, &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth); if (!write_short (configFile, (short) icon_x)) return 0; if (!write_short (configFile, (short) icon_y)) return 0; } } else { if (!write_byte (configFile, 0)) return 0; /* icon does not have any information */ } /* ======================================================================= */ if (!write_short (configFile, (short) theWindow->frame_x)) return 0; if (!write_short (configFile, (short) theWindow->frame_y)) return 0; if (!write_ushort (configFile, (unsigned short) theWindow->attr.width)) return 0; if (!write_ushort (configFile, (unsigned short) theWindow->attr.height)) return 0; if (!write_byte (configFile, theWindow->widthEverChangedByUser ? 1 : 0)) return 0; if (!write_byte (configFile, theWindow->heightEverChangedByUser ? 1 : 0)) return 0; /* ===================[ Matthew McNeill Feb 1997 ]=======================* * write an extra piece of information to the file, this is the occupation * number and is a bit field of the workspaces occupied by the client. */ if (!write_int (configFile, theWindow->occupation)) return 0; /* ======================================================================*/ return 1; } /*===[ Read Window Configuration Entry ]=====================================*/ int ReadWinConfigEntry (FILE *configFile, unsigned short version, TWMWinConfigEntry **pentry) /* this function reads the next window configuration entry from the given file * else it returns FALSE if none exists or there is a problem */ { TWMWinConfigEntry *entry; unsigned char byte; int i; *pentry = entry = (TWMWinConfigEntry *) malloc ( sizeof (TWMWinConfigEntry)); if (!*pentry) return 0; entry->tag = 0; entry->client_id = NULL; entry->window_role = NULL; entry->class.res_name = NULL; entry->class.res_class = NULL; entry->wm_name = NULL; entry->wm_command = NULL; entry->wm_command_count = 0; if (!read_counted_string (configFile, &entry->client_id)) goto give_up; if (!read_counted_string (configFile, &entry->window_role)) goto give_up; if (!entry->window_role) { if (!read_counted_string (configFile, &entry->class.res_name)) goto give_up; if (!read_counted_string (configFile, &entry->class.res_class)) goto give_up; if (!read_counted_string (configFile, &entry->wm_name)) goto give_up; if (!read_byte (configFile, &byte)) goto give_up; entry->wm_command_count = byte; if (entry->wm_command_count == 0) entry->wm_command = NULL; else { entry->wm_command = (char **) malloc (entry->wm_command_count * sizeof (char *)); if (!entry->wm_command) goto give_up; for (i = 0; i < entry->wm_command_count; i++) if (!read_counted_string (configFile, &entry->wm_command[i])) goto give_up; } } if (!read_byte (configFile, &byte)) goto give_up; entry->iconified = byte; if (!read_byte (configFile, &byte)) goto give_up; entry->icon_info_present = byte; if (entry->icon_info_present) { if (!read_short (configFile, (short *) &entry->icon_x)) goto give_up; if (!read_short (configFile, (short *) &entry->icon_y)) goto give_up; } if (!read_short (configFile, (short *) &entry->x)) goto give_up; if (!read_short (configFile, (short *) &entry->y)) goto give_up; if (!read_ushort (configFile, &entry->width)) goto give_up; if (!read_ushort (configFile, &entry->height)) goto give_up; if (version > 1) { if (!read_byte (configFile, &byte)) goto give_up; entry->width_ever_changed_by_user = byte; if (!read_byte (configFile, &byte)) goto give_up; entry->height_ever_changed_by_user = byte; } else { entry->width_ever_changed_by_user = False; entry->height_ever_changed_by_user = False; } /* ===================[ Matthew McNeill Feb 1997 ]======================= * * read in the occupation information to restore the windows to the * correct workspaces. */ if (!read_int (configFile, &entry->occupation)) goto give_up; /* ====================================================================== */ return 1; give_up: if (entry->client_id) free (entry->client_id); if (entry->window_role) free (entry->window_role); if (entry->class.res_name) free (entry->class.res_name); if (entry->class.res_class) free (entry->class.res_class); if (entry->wm_name) free (entry->wm_name); if (entry->wm_command_count) { for (i = 0; i < entry->wm_command_count; i++) if (entry->wm_command[i]) free (entry->wm_command[i]); } if (entry->wm_command) free ((char *) entry->wm_command); free ((char *) entry); *pentry = NULL; return 0; } /*===[ Read In Win Config File ]=============================================*/ void ReadWinConfigFile (char *filename) /* this function reads the window configuration file and stores the information * in a data structure which is returned */ { FILE *configFile; TWMWinConfigEntry *entry; int done = 0; unsigned short version; configFile = fopen (filename, "rb"); if (!configFile) return; if (!read_ushort (configFile, &version) || version > SAVEFILE_VERSION) { done = 1; } while (!done) { if (ReadWinConfigEntry (configFile, version, &entry)) { entry->next = winConfigHead; winConfigHead = entry; } else done = 1; } fclose (configFile); } /*===[ Get Window Configuration ]============================================* * Matthew McNeill Feb 1997 - added extra parameter (occupation) to return * restored occupation of the window */ int GetWindowConfig (TwmWindow *theWindow, short *x, short *y, unsigned short *width, unsigned short *height, Bool *iconified, Bool *icon_info_present, short *icon_x, short *icon_y, Bool *width_ever_changed_by_user, Bool *height_ever_changed_by_user, int *occupation) /* <== [ Matthew McNeill Feb 1997 ] == */ /* This function attempts to extract all the relevant information from the * given window and return values via the rest of the parameters to the * function */ { char *clientId, *windowRole; TWMWinConfigEntry *ptr; int found = 0; ptr = winConfigHead; if (!ptr) return 0; clientId = GetClientID (theWindow->w); windowRole = GetWindowRole (theWindow->w); while (ptr && !found) { int client_id_match = (!clientId && !ptr->client_id) || (clientId && ptr->client_id && strcmp (clientId, ptr->client_id) == 0); if (!ptr->tag && client_id_match) { if (windowRole || ptr->window_role) { found = (windowRole && ptr->window_role && strcmp (windowRole, ptr->window_role) == 0); } else { /* * Compare WM_CLASS + only compare WM_NAME if the * WM_NAME in the saved file is non-NULL. If the * WM_NAME in the saved file is NULL, this means that * the client changed the value of WM_NAME during the * session, and we can not use it as a criteria for * our search. For example, with xmh, at save time * the window name might be "xmh: folderY". However, * if xmh does not properly restore state when it is * restarted, the initial window name might be * "xmh: folderX". This would cause the window manager * to fail in finding the saved window configuration. * The best we can do is ignore WM_NAME if its value * changed in the previous session. */ if (strcmp (theWindow->class.res_name, ptr->class.res_name) == 0 && strcmp (theWindow->class.res_class, ptr->class.res_class) == 0 && (ptr->wm_name == NULL || strcmp (theWindow->name, ptr->wm_name) == 0)) { if (clientId) { /* * If a client ID was present, we should not check * WM_COMMAND because Xt will put a -xtsessionID arg * on the command line. */ found = 1; } else { /* * For non-XSMP clients, also check WM_COMMAND. */ char **wm_command = NULL; int wm_command_count = 0, i; XGetCommand (dpy, theWindow->w, &wm_command, &wm_command_count); if (wm_command_count == ptr->wm_command_count) { for (i = 0; i < wm_command_count; i++) if (strcmp (wm_command[i], ptr->wm_command[i]) != 0) break; if (i == wm_command_count) found = 1; } } } } } if (!found) ptr = ptr->next; } if (found) { *x = ptr->x; *y = ptr->y; *width = ptr->width; *height = ptr->height; *iconified = ptr->iconified; *icon_info_present = ptr->icon_info_present; *width_ever_changed_by_user = ptr->width_ever_changed_by_user; *height_ever_changed_by_user = ptr->height_ever_changed_by_user; if (*icon_info_present) { *icon_x = ptr->icon_x; *icon_y = ptr->icon_y; } *occupation = ptr->occupation; /* <== [ Matthew McNeill Feb 1997 ] == */ ptr->tag = 1; } else *iconified = 0; if (clientId) XFree (clientId); if (windowRole) XFree (windowRole); return found; } /*===[ Unique Filename Generator ]===========================================*/ static FILE *unique_file (char **filename, char *path, char *prefix) /* this function attempts to allocate a temporary file to store the * information of the windows */ { int fd; char tmp[PATH_MAX], template[PATH_MAX]; FILE *fp; snprintf(tmp, sizeof(tmp), "%s/%sXXXXXX", path, prefix); #ifndef HAVE_MKSTEMP do { if (fd == -1) strcpy(template, tmp); if ((mktemp(template) == NULL) || (template[0] == '\0')) return NULL; fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600); } while ((fd == -1) && (errno == EEXIST || errno == EINTR)); #else { int omask = umask(077); fd = mkstemp(tmp); umask(omask); } if (fd == -1) return NULL; #endif if ((fp = fdopen(fd, "wb")) == NULL) close(fd); *filename = strdup(template); return fp; } /*===[ SAVE WINDOW INFORMATION ]=============================================*/ #ifndef PATH_MAX # define PATH_MAX 1023 #endif void SaveYourselfPhase2CB (SmcConn smcCon, SmPointer clientData) /* this is where all the work is done in saving the state of the windows. * it is not done in Phase One because phase one is used for the other clients * to make sure that all the property information on their windows is correct * and up to date */ { int scrnum; ScreenInfo *theScreen; TwmWindow *theWindow; char *clientId, *windowRole; FILE *configFile = NULL; char *path; char *filename = NULL; Bool success = False; SmProp prop1, prop2, prop3, *props[3]; SmPropValue prop1val, prop2val, prop3val; char discardCommand[PATH_MAX + 4]; int numVals, i; static int first_time = 1; if (first_time) { char userId[20]; char hint = SmRestartIfRunning; prop1.name = SmProgram; prop1.type = SmARRAY8; prop1.num_vals = 1; prop1.vals = &prop1val; prop1val.value = Argv[0]; prop1val.length = strlen (Argv[0]); sprintf (userId, "%d", getuid()); prop2.name = SmUserID; prop2.type = SmARRAY8; prop2.num_vals = 1; prop2.vals = &prop2val; prop2val.value = (SmPointer) userId; prop2val.length = strlen (userId); prop3.name = SmRestartStyleHint; prop3.type = SmCARD8; prop3.num_vals = 1; prop3.vals = &prop3val; prop3val.value = (SmPointer) &hint; prop3val.length = 1; props[0] = &prop1; props[1] = &prop2; props[2] = &prop3; SmcSetProperties (smcCon, 3, props); first_time = 0; } path = getenv ("SM_SAVE_DIR"); if (!path) { path = getenv ("HOME"); if (!path) path = "."; } /*==============[ Matthew McNeill Feb 1997 ]==============* * changed the unique name to CTWM rather than TWM * this is tidier and more functional and prevents * TWM picking up CTWM config files. The format is * no longer the same since the new format supports * virtaul workspaces. *========================================================*/ if ((configFile = unique_file (&filename, path, ".ctwm")) == NULL) goto bad; if (!write_ushort (configFile, SAVEFILE_VERSION)) goto bad; success = True; for (scrnum = 0; scrnum < NumScreens && success; scrnum++) { if (ScreenList[scrnum] != NULL) { theScreen = ScreenList[scrnum]; theWindow = theScreen->FirstWindow; while (theWindow && success) { clientId = GetClientID (theWindow->w); windowRole = GetWindowRole (theWindow->w); if (!WriteWinConfigEntry (configFile, theWindow, clientId, windowRole)) success = False; if (clientId) XFree (clientId); if (windowRole) XFree (windowRole); theWindow = theWindow->next; } } } prop1.name = SmRestartCommand; prop1.type = SmLISTofARRAY8; prop1.vals = (SmPropValue *) malloc ( (Argc + 4) * sizeof (SmPropValue)); if (!prop1.vals) { success = False; goto bad; } numVals = 0; for (i = 0; i < Argc; i++) { if (strcmp (Argv[i], "-clientId") == 0 || strcmp (Argv[i], "-restore") == 0) { i++; } else { prop1.vals[numVals].value = (SmPointer) Argv[i]; prop1.vals[numVals++].length = strlen (Argv[i]); } } prop1.vals[numVals].value = (SmPointer) "-clientId"; prop1.vals[numVals++].length = 9; prop1.vals[numVals].value = (SmPointer) twm_clientId; prop1.vals[numVals++].length = strlen (twm_clientId); prop1.vals[numVals].value = (SmPointer) "-restore"; prop1.vals[numVals++].length = 8; prop1.vals[numVals].value = (SmPointer) filename; prop1.vals[numVals++].length = strlen (filename); prop1.num_vals = numVals; sprintf (discardCommand, "rm %s", filename); prop2.name = SmDiscardCommand; prop2.type = SmARRAY8; prop2.num_vals = 1; prop2.vals = &prop2val; prop2val.value = (SmPointer) discardCommand; prop2val.length = strlen (discardCommand); props[0] = &prop1; props[1] = &prop2; SmcSetProperties (smcCon, 2, props); free ((char *) prop1.vals); bad: SmcSaveYourselfDone (smcCon, success); sent_save_done = 1; if (configFile) fclose (configFile); if (filename) free (filename); } /*===[ Save Yourself SM CallBack ]===========================================*/ void SaveYourselfCB (SmcConn smcCon, SmPointer clientData, int saveType, Bool shutdown, int interactStyle, Bool fast) /* this procedure is called by the session manager when requesting the * window manager to save its status, ie all the window configurations */ { if (!SmcRequestSaveYourselfPhase2 (smcCon, SaveYourselfPhase2CB, NULL)) { SmcSaveYourselfDone (smcCon, False); sent_save_done = 1; } else sent_save_done = 0; } /*===[ Die SM Call Back ]====================================================*/ void DieCB (SmcConn smcCon, SmPointer clientData) /* this procedure is called by the session manager when requesting that the * application shut istelf down */ { SmcCloseConnection (smcCon, 0, NULL); XtRemoveInput (iceInputId); Done(0); } /*===[ Save Complete SM Call Back ]==========================================*/ void SaveCompleteCB (SmcConn smcCon, SmPointer clientData) /* This function is called to say that the save has been completed and that * the program can continue its operation */ { ; } /*===[ Shutdown Cancelled SM Call Back ]=====================================*/ void ShutdownCancelledCB (SmcConn smcCon, SmPointer clientData) { if (!sent_save_done) { SmcSaveYourselfDone (smcCon, False); sent_save_done = 1; } } /*===[ Process ICE Message ]=================================================*/ void ProcessIceMsgProc (XtPointer client_data, int *source, XtInputId *id) { IceConn ice_conn = (IceConn) client_data; IceProcessMessages (ice_conn, NULL, NULL); } /*===[ Connect To Session Manager ]==========================================*/ void ConnectToSessionManager (char *previous_id) /* This procedure attempts to connect to the session manager and setup the * interclent exchange via the Call Backs */ { char errorMsg[256]; unsigned long mask; SmcCallbacks callbacks; IceConn iceConn; mask = SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask; callbacks.save_yourself.callback = SaveYourselfCB; callbacks.save_yourself.client_data = (SmPointer) NULL; callbacks.die.callback = DieCB; callbacks.die.client_data = (SmPointer) NULL; callbacks.save_complete.callback = SaveCompleteCB; callbacks.save_complete.client_data = (SmPointer) NULL; callbacks.shutdown_cancelled.callback = ShutdownCancelledCB; callbacks.shutdown_cancelled.client_data = (SmPointer) NULL; smcConn = SmcOpenConnection ( NULL, /* use SESSION_MANAGER env */ (SmPointer) appContext, SmProtoMajor, SmProtoMinor, mask, &callbacks, previous_id, &twm_clientId, 256, errorMsg); if (smcConn == NULL) { #ifdef DEBUG /* == [ Matthew McNeill Feb 1997 ] == */ fprintf (stderr, "%s : Connection to session manager failed. (%s)",ProgramName, errorMsg); #endif return; } iceConn = SmcGetIceConnection (smcConn); iceInputId = XtAppAddInput ( appContext, IceConnectionNumber (iceConn), (XtPointer) XtInputReadMask, ProcessIceMsgProc, (XtPointer) iceConn); }