diff options
Diffstat (limited to 'src/session.c')
-rw-r--r-- | src/session.c | 1054 |
1 files changed, 1054 insertions, 0 deletions
diff --git a/src/session.c b/src/session.c new file mode 100644 index 0000000..992f8f2 --- /dev/null +++ b/src/session.c @@ -0,0 +1,1054 @@ +/* $Xorg: session.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software 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 +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Author: Ralph Mor, X Consortium +******************************************************************************/ + +#include <X11/Xos.h> + +#ifndef X_NOT_POSIX +#ifdef _POSIX_SOURCE +#include <limits.h> +#else +#define _POSIX_SOURCE +#include <limits.h> +#undef _POSIX_SOURCE +#endif +#endif /* X_NOT_POSIX */ +#ifndef PATH_MAX +#include <sys/param.h> +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif +#endif /* PATH_MAX */ + +#include <X11/Xlib.h> +#include <X11/SM/SMlib.h> +#include <X11/Xatom.h> +#include <stdio.h> +#include "twm.h" +#include "screen.h" + +SmcConn smcConn = NULL; +XtInputId iceInputId; +char *twm_clientId; +TWMWinConfigEntry *winConfigHead = NULL; +Bool gotFirstSave = 0; +Bool sent_save_done = 0; + +#define SAVEFILE_VERSION 2 + + + +char * +GetClientID (window) + +Window window; + +{ + char *client_id = NULL; + Window client_leader; + XTextProperty tp; + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long bytes_after; + unsigned char *prop = NULL; + + if (XGetWindowProperty (dpy, window, _XA_WM_CLIENT_LEADER, + 0L, 1L, False, AnyPropertyType, &actual_type, &actual_format, + &nitems, &bytes_after, &prop) == Success) + { + if (actual_type == XA_WINDOW && actual_format == 32 && + nitems == 1 && bytes_after == 0) + { + client_leader = *((Window *) 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; +} + + + +char * +GetWindowRole (window) + +Window 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; +} + + + +int +write_byte (file, b) + +FILE *file; +unsigned char b; + +{ + if (fwrite ((char *) &b, 1, 1, file) != 1) + return 0; + return 1; +} + + +int +write_ushort (file, s) + +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; +} + + +int +write_short (file, s) + +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; +} + + +int +write_counted_string (file, 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; +} + + + +int +read_byte (file, bp) + +FILE *file; +unsigned char *bp; + +{ + if (fread ((char *) bp, 1, 1, file) != 1) + return 0; + return 1; +} + + +int +read_ushort (file, shortp) + +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; +} + + +int +read_short (file, shortp) + +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; +} + + +int +read_counted_string (file, stringp) + +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; +} + + + +/* + * 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 + */ + +int +WriteWinConfigEntry (configFile, theWindow, clientId, windowRole) + +FILE *configFile; +TwmWindow *theWindow; +char *clientId; +char *windowRole; + +{ + char **wm_command; + int wm_command_count, i; + + 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); + } + } + + if (!write_byte (configFile, theWindow->icon ? 1 : 0)) /* iconified */ + return 0; + + if (!write_byte (configFile, theWindow->icon_w ? 1 : 0)) /* icon exists */ + return 0; + + 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; + } + + 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; + + return 1; +} + + +int +ReadWinConfigEntry (configFile, version, pentry) + +FILE *configFile; +unsigned short version; +TWMWinConfigEntry **pentry; + +{ + 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; + } + + 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; +} + + +void +ReadWinConfigFile (filename) + +char *filename; + +{ + 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); +} + + + +int +GetWindowConfig (theWindow, x, y, width, height, + iconified, icon_info_present, icon_x, icon_y, + width_ever_changed_by_user, height_ever_changed_by_user) + +TwmWindow *theWindow; +short *x, *y; +unsigned short *width, *height; +Bool *iconified; +Bool *icon_info_present; +short *icon_x, *icon_y; +Bool *width_ever_changed_by_user; +Bool *height_ever_changed_by_user; + +{ + 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; + } + ptr->tag = 1; + } + else + *iconified = 0; + + if (clientId) + XFree (clientId); + + if (windowRole) + XFree (windowRole); + + return found; +} + + + +static char * +unique_filename (path, prefix) + +char *path; +char *prefix; + +{ +#ifndef X_NOT_POSIX + return ((char *) tempnam (path, prefix)); +#else + char tempFile[PATH_MAX]; + char *tmp; + + sprintf (tempFile, "%s/%sXXXXXX", path, prefix); + tmp = (char *) mktemp (tempFile); + if (tmp) + { + char *ptr = (char *) malloc (strlen (tmp) + 1); + strcpy (ptr, tmp); + return (ptr); + } + else + return (NULL); +#endif +} + + + +void +SaveYourselfPhase2CB (smcConn, clientData) + +SmcConn smcConn; +SmPointer clientData; + +{ + 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[80]; + 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 (smcConn, 3, props); + + first_time = 0; + } + + path = getenv ("SM_SAVE_DIR"); + if (!path) + { + path = getenv ("HOME"); + if (!path) + path = "."; + } + + if ((filename = unique_filename (path, ".twm")) == NULL) + goto bad; + + if (!(configFile = fopen (filename, "wb"))) + 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->TwmRoot.next; + + 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 (smcConn, 2, props); + free ((char *) prop1.vals); + + bad: + SmcSaveYourselfDone (smcConn, success); + sent_save_done = 1; + + if (configFile) + fclose (configFile); + + if (filename) + free (filename); +} + + + +void +SaveYourselfCB (smcConn, clientData, saveType, shutdown, interactStyle, fast) + +SmcConn smcConn; +SmPointer clientData; +int saveType; +Bool shutdown; +int interactStyle; +Bool fast; + +{ + if (!SmcRequestSaveYourselfPhase2 (smcConn, SaveYourselfPhase2CB, NULL)) + { + SmcSaveYourselfDone (smcConn, False); + sent_save_done = 1; + } + else + sent_save_done = 0; +} + + + +void +DieCB (smcConn, clientData) + +SmcConn smcConn; +SmPointer clientData; + +{ + SmcCloseConnection (smcConn, 0, NULL); + XtRemoveInput (iceInputId); + Done(); +} + + + +void +SaveCompleteCB (smcConn, clientData) + +SmcConn smcConn; +SmPointer clientData; + +{ + ; +} + + + +void +ShutdownCancelledCB (smcConn, clientData) + +SmcConn smcConn; +SmPointer clientData; + +{ + if (!sent_save_done) + { + SmcSaveYourselfDone (smcConn, False); + sent_save_done = 1; + } +} + + + +void +ProcessIceMsgProc (client_data, source, id) + +XtPointer client_data; +int *source; +XtInputId *id; + +{ + IceConn ice_conn = (IceConn) client_data; + + IceProcessMessages (ice_conn, NULL, NULL); +} + + + +void +ConnectToSessionManager (previous_id) + +char *previous_id; + +{ + 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) + return; + + iceConn = SmcGetIceConnection (smcConn); + + iceInputId = XtAppAddInput ( + appContext, + IceConnectionNumber (iceConn), + (XtPointer) XtInputReadMask, + ProcessIceMsgProc, + (XtPointer) iceConn); +} + + + |