/* * Copyright 1988 by Evans & Sutherland Computer Corporation, * Salt Lake City, Utah * Portions Copyright 1989 by the Massachusetts Institute of Technology * Cambridge, Massachusetts * * Copyright 1992 Claude Lecommandeur. */ /********************************************************************* * * 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 "ctwm.h" #include #include #include #include // For umask #include // PATH_MAX #include #include "ctwm_atoms.h" #include "ctwm_shutdown.h" #include "icons.h" #include "list.h" #include "screen.h" #include "session.h" SmcConn smcConn = NULL; static XtInputId iceInputId; static char *twm_clientId; static TWMWinConfigEntry *winConfigHead = NULL; static bool sent_save_done = false; static void SaveYourselfCB(SmcConn smcCon, SmPointer clientData, int saveType, Bool shutdown, int interactStyle, Bool fast); static char *GetClientID(Window window); static char *GetWindowRole(Window window); static int WriteWinConfigEntry(FILE *configFile, TwmWindow *theWindow, char *clientId, char *windowRole); static int ReadWinConfigEntry(FILE *configFile, unsigned short version, TWMWinConfigEntry **pentry); static void SaveYourselfPhase2CB(SmcConn smcCon, SmPointer clientData); static void DieCB(SmcConn smcCon, SmPointer clientData); static void SaveCompleteCB(SmcConn smcCon, SmPointer clientData); static void ShutdownCancelledCB(SmcConn smcCon, SmPointer clientData); static void ProcessIceMsgProc(XtPointer client_data, int *source, XtInputId *id); #define SAVEFILE_VERSION 2 /*===[ Get Client SM_CLIENT_ID ]=============================================*/ static 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 ]=====================================================*/ static 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 ]===================================*/ static 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->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 ]=====================================*/ static int ReadWinConfigEntry(FILE *configFile, unsigned short version, TWMWinConfigEntry **pentry) /* this function reads the next window configuration entry from the given file * else it returns 0 if none exists or there is a problem */ { TWMWinConfigEntry *entry; unsigned char byte; int i; *pentry = entry = calloc(1, sizeof(TWMWinConfigEntry)); if(!*pentry) { return 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 = calloc(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 && entry->wm_command) { for(i = 0; i < entry->wm_command_count; i++) if(entry->wm_command[i]) { free(entry->wm_command[i]); } } if(entry->wm_command) { free(entry->wm_command); } free(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 char *unique_filename(char *path, char *prefix, int *fd) /* this function attempts to allocate a temporary filename to store the * information of the windows */ { #ifdef MISSING_MKSTEMP char *name; while(1) { name = (char *) tempnam(path, prefix); *fd = open(name, O_CREAT | O_EXCL); if(*fd >= 0) { return name; } free(name); } #else char *tempFile; mode_t prev_umask; asprintf(&tempFile, "%s/%sXXXXXX", path, prefix); prev_umask = umask(077); *fd = mkstemp(tempFile); umask(prev_umask); if(*fd >= 0) { return tempFile; } else { free(tempFile); return NULL; } #endif } /*===[ SAVE WINDOW INFORMATION ]=============================================*/ #ifndef PATH_MAX # define PATH_MAX 1023 #endif static 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; int configFd; 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((filename = unique_filename(path, ".ctwm", &configFd)) == NULL) { goto bad; } if(!(configFile = fdopen(configFd, "wb"))) { /* wb = write binary */ 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 = calloc((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(prop1.vals); bad: SmcSaveYourselfDone(smcCon, success); sent_save_done = true; if(configFile) { fclose(configFile); } if(filename) { free(filename); } } /*===[ Save Yourself SM CallBack ]===========================================*/ static 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 = true; } else { sent_save_done = false; } } /*===[ Die SM Call Back ]====================================================*/ static 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); DoShutdown(); } /*===[ Save Complete SM Call Back ]==========================================*/ static 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 ]=====================================*/ static void ShutdownCancelledCB(SmcConn smcCon, SmPointer clientData) { if(!sent_save_done) { SmcSaveYourselfDone(smcCon, False); sent_save_done = true; } } /*===[ Process ICE Message ]=================================================*/ static 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); } void shutdown_session(void) { if(smcConn) { SmcCloseConnection(smcConn, 0, NULL); } }