diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:55 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:55 +0000 |
commit | c8ddd5d82a72167de6e0a544b55f9b03ab93053e (patch) | |
tree | 878ae3ddd67e48798427db3d709940a664801cd0 |
R6.6 is the Xorg base-lineXORG-MAIN
-rw-r--r-- | XSm.ad | 119 | ||||
-rw-r--r-- | auth.c | 254 | ||||
-rw-r--r-- | auth.h | 29 | ||||
-rw-r--r-- | choose.c | 841 | ||||
-rw-r--r-- | choose.h | 30 | ||||
-rw-r--r-- | globals.c | 88 | ||||
-rw-r--r-- | info.c | 1050 | ||||
-rw-r--r-- | info.h | 29 | ||||
-rw-r--r-- | list.c | 170 | ||||
-rw-r--r-- | list.h | 42 | ||||
-rw-r--r-- | lock.c | 176 | ||||
-rw-r--r-- | lock.h | 31 | ||||
-rw-r--r-- | log.c | 167 | ||||
-rw-r--r-- | log.h | 29 | ||||
-rw-r--r-- | mainwin.c | 135 | ||||
-rw-r--r-- | mainwin.h | 27 | ||||
-rw-r--r-- | misc.c | 157 | ||||
-rw-r--r-- | popup.c | 184 | ||||
-rw-r--r-- | popup.h | 31 | ||||
-rw-r--r-- | printhex.c | 81 | ||||
-rw-r--r-- | prop.c | 420 | ||||
-rw-r--r-- | prop.h | 34 | ||||
-rw-r--r-- | remote.c | 259 | ||||
-rw-r--r-- | restart.c | 624 | ||||
-rw-r--r-- | restart.h | 30 | ||||
-rw-r--r-- | save.c | 1529 | ||||
-rw-r--r-- | save.h | 35 | ||||
-rw-r--r-- | saveutil.c | 557 | ||||
-rw-r--r-- | saveutil.h | 29 | ||||
-rw-r--r-- | signals.c | 251 | ||||
-rw-r--r-- | system.xsm | 4 | ||||
-rw-r--r-- | xsm.c | 1397 | ||||
-rw-r--r-- | xsm.h | 194 | ||||
-rw-r--r-- | xsm.man | 343 | ||||
-rw-r--r-- | xtwatch.c | 124 | ||||
-rw-r--r-- | xtwatch.h | 27 |
36 files changed, 9527 insertions, 0 deletions
@@ -0,0 +1,119 @@ +! $Xorg: XSm.ad,v 1.3 2000/08/17 19:55:04 cpqbld Exp $ +*chooseSessionPopup*font: 12x24 +*chooseSessionLabel.label: Session Menu +*chooseSessionMessageLabel.label: Press button again to confirm, or hit Cancel... +*chooseSessionLoadButton.label: Load Session +*chooseSessionDeleteButton.label: Delete Session +*chooseSessionFailSafeButton.label: Default/Fail Safe +*chooseSessionCancelButton.label: Cancel +*chooseSessionBreakLockButton.label: Break Lock +*chooseSessionLoadButton.background: light steel blue +*chooseSessionDeleteButton.background: light steel blue +*chooseSessionBreakLockButton.background: light steel blue + +*chooseSessionFailSafeButton.background:light steel blue +*chooseSessionCancelButton.background: light steel blue + +*clientInfoButton.label: Client List +*logButton.label: Session Log +*checkPointButton.label: Checkpoint +*shutdownButton.label: Shutdown +*shutdownSave.label: With Checkpoint +*shutdownDontSave.label: Immediately + +*logPopup.title: Session Log +*logPopup.iconName: Session Log +*logOkButton.label: OK +*logText.width: 600 +*logText.height: 300 + +*clientInfoPopup.title: Client List +*clientInfoPopup.iconName: Client List +*noClientsLabel.label: There are no clients in the session +*viewPropButton.label: View Properties +*cloneButton.label: Clone +*killClientButton.label: Kill +*restartHintButton.label: Restart Hint +*restartIfRunning.label: If Running +*restartAnyway.label: Anyway +*restartImmediately.label: Immediately +*restartNever.label: Never + +*clientInfoDoneButton.label: Done +*manualRestartLabel.label: Restart the following non-session-aware clients... + +*clientPropTextWidget.width: 500 +*clientPropTextWidget.height: 300 +*clientPropDoneButton.label: Done + +*saveMessageLabel.label: Session name + +*saveTypeLabel.label: Save Type +*saveTypeNone.label: None +*saveTypeLocal.label: Local +*saveTypeGlobal.label: Global +*saveTypeBoth.label: Both + +*interactStyleLabel.label: Interact Style +*interactStyleNone.label: None +*interactStyleErrors.label: Errors +*interactStyleAny.label: Any + +*saveCancelButton.label: Cancel + +*helpSaveButton.label: Help +*helpSaveOkButton.label: OK + +*helpSaveText.label:\n\ +Save types\n\ +----------\n\ +Local - Applications should save enough information to\n\ + restore the state as seen by the user.\n\ + The save should not affect data seen by other users.\n\ +\n\ +Global - Applications should commit all of their data to\n\ + permanent, globally accessible storage.\n\ +\n\ +Both - Applications should commit their data to global\n\ + storage and also save state local to the user.\n\ +\n\n\ +Interaction styles\n\ +------------------\n\ +None - Don't allow user interaction\n\ +Errors - Allow user interaction only if an error occurs\n\ +Any - Allow user interaction for any reason\n\ +\n + +*nameInUsePopup.title: Warning +*nameInUseOverwriteButton.label: Overwrite + +*badSavePopup.title: Save Failure +*badSaveLabel.label: The following applications did not report\n\ +a successful save of their state: +*badSaveOkButton.label: OK +*badSaveCancelButton.label: Cancel Shutdown + +*chooseSessionListWidget.Translations: #override\n\ + <Key>Up: ChooseSessionUp()\n\ + <Key>KP_Up: ChooseSessionUp()\n\ + Ctrl<Key>P: ChooseSessionUp()\n\ + <Key>Down: ChooseSessionDown()\n\ + <Key>KP_Down: ChooseSessionDown()\n\ + Ctrl<Key>N: ChooseSessionDown()\n\ + <Btn1Down>: Set() ChooseSessionBtn1Down()\n + +*chooseSessionLoadButton.Accelerators: #override\n\ + <Btn1Down>(2+): set() notify() unset()\n\ + <Key>Return: set() notify() unset()\n\ + <Key>KP_Enter: set() notify() unset()\n + +*checkPointButton.Translations: #override\n\ + <Btn1Up>: notify() reset()\n +*shutdownButton.Translations: #override\n\ + <Btn1Up>: notify() reset()\n + +*saveOkButton.Accelerators: #override\n\ + <Key>Return: set() notify() unset()\n + +*badSaveOkButton.Accelerators: #override\n\ + <Key>Return: set() notify() unset()\n @@ -0,0 +1,254 @@ +/* $Xorg: auth.c,v 1.4 2001/02/09 02:05:59 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include "xsm.h" + +#include <X11/ICE/ICEutil.h> + +static char *addAuthFile = NULL; +static char *remAuthFile = NULL; + + + +/* + * Host Based Authentication Callback. This callback is invoked if + * the connecting client can't offer any authentication methods that + * we can accept. We can accept/reject based on the hostname. + */ + +Bool +HostBasedAuthProc (hostname) + +char *hostname; + +{ + return (0); /* For now, we don't support host based authentication */ +} + + + +/* + * We use temporary files which contain commands to add/remove entries from + * the .ICEauthority file. + */ + +static void +write_iceauth (addfp, removefp, entry) + +FILE *addfp; +FILE *removefp; +IceAuthDataEntry *entry; + +{ + fprintf (addfp, + "add %s \"\" %s %s ", + entry->protocol_name, + entry->network_id, + entry->auth_name); + fprintfhex (addfp, entry->auth_data_length, entry->auth_data); + fprintf (addfp, "\n"); + + fprintf (removefp, + "remove protoname=%s protodata=\"\" netid=%s authname=%s\n", + entry->protocol_name, + entry->network_id, + entry->auth_name); +} + + + +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 +} + + + + +/* + * Provide authentication data to clients that wish to connect + */ + +#define MAGIC_COOKIE_LEN 16 + +Status +SetAuthentication (count, listenObjs, authDataEntries) + +int count; +IceListenObj *listenObjs; +IceAuthDataEntry **authDataEntries; + +{ + FILE *addfp = NULL; + FILE *removefp = NULL; + char *path; + int original_umask; + char command[256]; + int i; + + original_umask = umask (0077); /* disallow non-owner access */ + + path = (char *) getenv ("SM_SAVE_DIR"); + if (!path) + { + path = (char *) getenv ("HOME"); + if (!path) + path = "."; + } + + if ((addAuthFile = unique_filename (path, ".xsm")) == NULL) + goto bad; + + if (!(addfp = fopen (addAuthFile, "w"))) + goto bad; + + if ((remAuthFile = unique_filename (path, ".xsm")) == NULL) + goto bad; + + if (!(removefp = fopen (remAuthFile, "w"))) + goto bad; + + if ((*authDataEntries = (IceAuthDataEntry *) XtMalloc ( + count * 2 * sizeof (IceAuthDataEntry))) == NULL) + goto bad; + + for (i = 0; i < count * 2; i += 2) + { + (*authDataEntries)[i].network_id = + IceGetListenConnectionString (listenObjs[i/2]); + (*authDataEntries)[i].protocol_name = "ICE"; + (*authDataEntries)[i].auth_name = "MIT-MAGIC-COOKIE-1"; + + (*authDataEntries)[i].auth_data = + IceGenerateMagicCookie (MAGIC_COOKIE_LEN); + (*authDataEntries)[i].auth_data_length = MAGIC_COOKIE_LEN; + + (*authDataEntries)[i+1].network_id = + IceGetListenConnectionString (listenObjs[i/2]); + (*authDataEntries)[i+1].protocol_name = "XSMP"; + (*authDataEntries)[i+1].auth_name = "MIT-MAGIC-COOKIE-1"; + + (*authDataEntries)[i+1].auth_data = + IceGenerateMagicCookie (MAGIC_COOKIE_LEN); + (*authDataEntries)[i+1].auth_data_length = MAGIC_COOKIE_LEN; + + write_iceauth (addfp, removefp, &(*authDataEntries)[i]); + write_iceauth (addfp, removefp, &(*authDataEntries)[i+1]); + + IceSetPaAuthData (2, &(*authDataEntries)[i]); + + IceSetHostBasedAuthProc (listenObjs[i/2], HostBasedAuthProc); + } + + fclose (addfp); + fclose (removefp); + + umask (original_umask); + + sprintf (command, "iceauth source %s", addAuthFile); + execute_system_command (command); + + unlink (addAuthFile); + + return (1); + + bad: + + if (addfp) + fclose (addfp); + + if (removefp) + fclose (removefp); + + if (addAuthFile) + { + unlink (addAuthFile); + free (addAuthFile); + } + if (remAuthFile) + { + unlink (remAuthFile); + free (remAuthFile); + } + + return (0); +} + + + +/* + * Free up authentication data. + */ + +void +FreeAuthenticationData (count, authDataEntries) + +int count; +IceAuthDataEntry *authDataEntries; + +{ + /* Each transport has entries for ICE and XSMP */ + + char command[256]; + int i; + + for (i = 0; i < count * 2; i++) + { + free (authDataEntries[i].network_id); + free (authDataEntries[i].auth_data); + } + + XtFree ((char *) authDataEntries); + + sprintf (command, "iceauth source %s", remAuthFile); + execute_system_command (command); + + unlink (remAuthFile); + + free (addAuthFile); + free (remAuthFile); +} @@ -0,0 +1,29 @@ +/* $Xorg: auth.h,v 1.4 2001/02/09 02:05:59 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +extern Status SetAuthentication (); +extern void FreeAuthenticationData (); +extern Bool HostBasedAuthProc (); diff --git a/choose.c b/choose.c new file mode 100644 index 0000000..4f1255c --- /dev/null +++ b/choose.c @@ -0,0 +1,841 @@ +/* $Xorg: choose.c,v 1.4 2001/02/09 02:05:59 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include "xsm.h" +#include "saveutil.h" +#include "lock.h" +#include <sys/types.h> + +#include <X11/Shell.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/List.h> +#include <X11/Xaw/Command.h> + +#ifndef X_NOT_POSIX +#include <dirent.h> +#else +#ifdef SYSV +#include <dirent.h> +#else +#ifdef USG +#include <dirent.h> +#else +#include <sys/dir.h> +#ifndef dirent +#define dirent direct +#endif +#endif +#endif +#endif + +static Pixel save_message_foreground; +static Pixel save_message_background; + +static int delete_session_phase = 0; +static int break_lock_phase = 0; + +Widget chooseSessionPopup; +Widget chooseSessionForm; +Widget chooseSessionLabel; +Widget chooseSessionListWidget; +Widget chooseSessionMessageLabel; +Widget chooseSessionLoadButton; +Widget chooseSessionDeleteButton; +Widget chooseSessionBreakLockButton; +Widget chooseSessionFailSafeButton; +Widget chooseSessionCancelButton; + + + +int +GetSessionNames (count_ret, short_names_ret, long_names_ret, locked_ret) + +int *count_ret; +String **short_names_ret; +String **long_names_ret; +Bool **locked_ret; + +{ + DIR *dir; + struct dirent *entry; + char *path; + int count; + + path = (char *) getenv ("SM_SAVE_DIR"); + if (!path) + { + path = (char *) getenv ("HOME"); + if (!path) + path = "."; + } + + *count_ret = 0; + *short_names_ret = NULL; + *locked_ret = NULL; + if (long_names_ret) + *long_names_ret = NULL; + + if ((dir = opendir (path)) == NULL) + return 0; + + count = 0; + + while ((entry = readdir (dir)) != NULL) + { + if (strncmp (entry->d_name, ".XSM-", 5) == 0) + count++; + } + + if (count == 0 || + ((*short_names_ret = (String *) XtMalloc ( + count * sizeof (String))) == NULL) || + (long_names_ret && (*long_names_ret = + (String *) XtMalloc (count * sizeof (String))) == NULL) || + ((*locked_ret = (Bool *) XtMalloc (count * sizeof (Bool))) == NULL)) + { + closedir (dir); + if (*short_names_ret) + XtFree ((char *) *short_names_ret); + if (long_names_ret && *long_names_ret) + XtFree ((char *) *long_names_ret); + return 0; + } + + rewinddir (dir); + + while ((entry = readdir (dir)) != NULL && *count_ret < count) + { + if (strncmp (entry->d_name, ".XSM-", 5) == 0) + { + char *name = (char *) entry->d_name + 5; + char *id = NULL; + Bool locked = CheckSessionLocked (name, long_names_ret, &id); + + (*short_names_ret)[*count_ret] = XtNewString (name); + (*locked_ret)[*count_ret] = locked; + + if (long_names_ret) + { + if (!locked) + { + (*long_names_ret)[*count_ret] = + (*short_names_ret)[*count_ret]; + } + else + { + char *host = ((char *) strchr (id, '/')) + 1; + char *colon = (char *) strchr (host, ':'); + + *colon = '\0'; + + (*long_names_ret)[*count_ret] = + XtMalloc (strlen (name) + strlen (host) + 14); + + sprintf ((*long_names_ret)[*count_ret], + "%s (locked at %s)", name, host); + *colon = ':'; + + XtFree (id); + } + } + + (*count_ret)++; + } + } + + closedir (dir); + + return 1; +} + + + +void +FreeSessionNames (count, namesShort, namesLong, lockFlags) + +int count; +String *namesShort; +String *namesLong; +Bool *lockFlags; + +{ + int i; + + for (i = 0; i < count; i++) + XtFree ((char *) namesShort[i]); + XtFree ((char *) namesShort); + + if (namesLong) + { + for (i = 0; i < count; i++) + if (lockFlags[i]) + XtFree ((char *) namesLong[i]); + XtFree ((char *) namesLong); + } + + XtFree ((char *) lockFlags); +} + + + +static void +SessionSelected (number, highlight) + +int number; +Bool highlight; + +{ + if (number >= 0) + { + Bool locked = sessionsLocked[number]; + + if (highlight) + XawListHighlight (chooseSessionListWidget, number); + + XtSetSensitive (chooseSessionLoadButton, !locked); + XtSetSensitive (chooseSessionDeleteButton, !locked); + XtSetSensitive (chooseSessionBreakLockButton, locked); + } + else + { + XtSetSensitive (chooseSessionLoadButton, False); + XtSetSensitive (chooseSessionDeleteButton, False); + XtSetSensitive (chooseSessionBreakLockButton, False); + } +} + + + +static void +AddSessionNames (count, names) + +int count; +String *names; + +{ + int i; + + XawListChange (chooseSessionListWidget, names, count, 0, True); + + /* + * Highlight the first unlocked session, if any. + */ + + for (i = 0; i < sessionNameCount; i++) + if (!sessionsLocked[i]) + break; + + SessionSelected (i < sessionNameCount ? i : -1, True); +} + + + +void +ChooseWindowStructureNotifyXtHandler (w, closure, event, continue_to_dispatch) + +Widget w; +XtPointer closure; +XEvent *event; +Boolean *continue_to_dispatch; + +{ + if (event->type == MapNotify) + { + /* + * Set the input focus to the choose window and direct all keyboard + * events to the list widget. This way, the user can make selections + * using the keyboard. + */ + + XtSetKeyboardFocus (chooseSessionPopup, chooseSessionListWidget); + + XSetInputFocus (XtDisplay (topLevel), XtWindow (chooseSessionPopup), + RevertToPointerRoot, CurrentTime); + + XSync (XtDisplay (topLevel), 0); + + XtRemoveEventHandler (chooseSessionPopup, StructureNotifyMask, False, + ChooseWindowStructureNotifyXtHandler, NULL); + } +} + + +void +ChooseSession () + +{ + Dimension width, height; + Position x, y; + + + /* + * Add the session names to the list + */ + + AddSessionNames (sessionNameCount, sessionNamesLong); + + + /* + * Center popup containing choice of sessions + */ + + XtRealizeWidget (chooseSessionPopup); + + XtVaGetValues (chooseSessionPopup, + XtNwidth, &width, + XtNheight, &height, + NULL); + + x = (Position)(WidthOfScreen (XtScreen (topLevel)) - width) / 2; + y = (Position)(HeightOfScreen (XtScreen (topLevel)) - height) / 3; + + XtVaSetValues (chooseSessionPopup, + XtNx, x, + XtNy, y, + NULL); + + XtVaSetValues (chooseSessionListWidget, + XtNlongest, width, + NULL); + + XtVaSetValues (chooseSessionLabel, + XtNwidth, width, + NULL); + + XtVaGetValues (chooseSessionMessageLabel, + XtNforeground, &save_message_foreground, + XtNbackground, &save_message_background, + NULL); + + XtVaSetValues (chooseSessionMessageLabel, + XtNwidth, width, + XtNforeground, save_message_background, + NULL); + + /* + * Wait for a map notify on the popup, then set input focus. + */ + + XtAddEventHandler (chooseSessionPopup, StructureNotifyMask, False, + ChooseWindowStructureNotifyXtHandler, NULL); + + XtPopup (chooseSessionPopup, XtGrabNone); +} + + + +static void +CheckDeleteCancel () + +{ + if (delete_session_phase > 0) + { + XtVaSetValues (chooseSessionMessageLabel, + XtNforeground, save_message_background, + NULL); + + delete_session_phase = 0; + } +} + + +static void +CheckBreakLockCancel () + +{ + if (break_lock_phase > 0) + { + XtVaSetValues (chooseSessionMessageLabel, + XtNforeground, save_message_background, + NULL); + + break_lock_phase = 0; + } +} + + + +static void +ChooseSessionUp (w, event, params, numParams) + +Widget w; +XEvent *event; +String *params; +Cardinal *numParams; + +{ + XawListReturnStruct *current; + + CheckDeleteCancel (); + CheckBreakLockCancel (); + + current = XawListShowCurrent (chooseSessionListWidget); + if (current->list_index > 0) + SessionSelected (current->list_index - 1, True); + XtFree ((char *) current); +} + + +static void +ChooseSessionDown (w, event, params, numParams) + +Widget w; +XEvent *event; +String *params; +Cardinal *numParams; + +{ + XawListReturnStruct *current; + + CheckDeleteCancel (); + CheckBreakLockCancel (); + + current = XawListShowCurrent (chooseSessionListWidget); + if (current->list_index < sessionNameCount - 1) + SessionSelected (current->list_index + 1, True); + XtFree ((char *) current); +} + + + +static void +ChooseSessionBtn1Down (w, event, params, numParams) + +Widget w; +XEvent *event; +String *params; +Cardinal *numParams; + +{ + XawListReturnStruct *current; + + CheckDeleteCancel (); + CheckBreakLockCancel (); + + current = XawListShowCurrent (chooseSessionListWidget); + SessionSelected (current->list_index, False /* already highlighted */); + XtFree ((char *) current); +} + + + +static void +ChooseSessionLoadXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + XawListReturnStruct *current; + + CheckDeleteCancel (); + CheckBreakLockCancel (); + + current = XawListShowCurrent (chooseSessionListWidget); + + if (!current || !current->string || *(current->string) == '\0') + { + if (current) + XtFree ((char *) current); +#ifdef XKB + XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_BadValue); +#else + XBell (XtDisplay (topLevel), 0); +#endif + return; + } + + /* + * Pop down choice of sessions and start the specified session. + */ + + XtPopdown (chooseSessionPopup); + + if (session_name) + XtFree (session_name); + + session_name = XtNewString (current->string); + + XtFree ((char *) current); + + FreeSessionNames (sessionNameCount, + sessionNamesShort, sessionNamesLong, sessionsLocked); + + + /* + * Start the session, looking for .XSM-<session name> startup file. + */ + + if (!StartSession (session_name, False)) + UnableToLockSession (session_name); +} + + + +static void +ChooseSessionDeleteXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + XawListReturnStruct *current; + int longest; + char *name; + + CheckBreakLockCancel (); + + current = XawListShowCurrent (chooseSessionListWidget); + + if (!current || !(name = current->string) || *name == '\0') + { + if (current) + XtFree ((char *) current); +#ifdef XKB + XkbStdBell(XtDisplay(w),XtWindow(w),0,XkbBI_BadValue); +#else + XBell (XtDisplay (topLevel), 0); +#endif + return; + } + + delete_session_phase++; + + if (delete_session_phase == 1) + { + XtVaSetValues (chooseSessionMessageLabel, + XtNforeground, save_message_foreground, + NULL); + +#ifdef XKB + XkbStdBell(XtDisplay(w),XtWindow(w),0,XkbBI_BadValue); +#else + XBell (XtDisplay (topLevel), 0); +#endif + } + else + { + XtVaSetValues (chooseSessionMessageLabel, + XtNforeground, save_message_background, + NULL); + + if (DeleteSession (name)) + { + int i, j; + + for (i = 0; i < sessionNameCount; i++) + { + if (strcmp (sessionNamesLong[i], name) == 0) + { + XtFree ((char *) sessionNamesShort[i]); + + if (sessionsLocked[i]) + XtFree ((char *) sessionNamesLong[i]); + + for (j = i; j < sessionNameCount - 1; j++) + { + sessionNamesLong[j] = sessionNamesLong[j + 1]; + sessionNamesShort[j] = sessionNamesShort[j + 1]; + sessionsLocked[j] = sessionsLocked[j + 1]; + } + sessionNameCount--; + break; + } + } + + if (sessionNameCount == 0) + { + XtSetSensitive (chooseSessionLoadButton, 0); + XtSetSensitive (chooseSessionDeleteButton, 0); + XtUnmanageChild (chooseSessionListWidget); + } + else + { + XtVaGetValues (chooseSessionListWidget, + XtNlongest, &longest, + NULL); + + XawListChange (chooseSessionListWidget, + sessionNamesLong, sessionNameCount, longest, True); + + SessionSelected (-1, False); + } + } + + delete_session_phase = 0; + } + + XtFree ((char *) current); +} + + + +static void +ChooseSessionBreakLockXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + XawListReturnStruct *current; + char *name; + + CheckDeleteCancel (); + + current = XawListShowCurrent (chooseSessionListWidget); + + if (!current || !(name = current->string) || *name == '\0') + { + if (current) + XtFree ((char *) current); +#ifdef XKB + XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_BadValue); +#else + XBell (XtDisplay (topLevel), 0); +#endif + return; + } + + break_lock_phase++; + + if (break_lock_phase == 1) + { + XtVaSetValues (chooseSessionMessageLabel, + XtNforeground, save_message_foreground, + NULL); + +#ifdef XKB + XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_BadValue); +#else + XBell (XtDisplay (topLevel), 0); +#endif + } + else + { + char *id; + int longest; + + XtVaSetValues (chooseSessionMessageLabel, + XtNforeground, save_message_background, + NULL); + + name = sessionNamesShort[current->list_index]; + + id = GetLockId (name); + + UnlockSession (name); + + sessionsLocked[current->list_index] = False; + XtFree ((char *) sessionNamesLong[current->list_index]); + sessionNamesLong[current->list_index] = + sessionNamesShort[current->list_index]; + + XtVaGetValues (chooseSessionListWidget, + XtNlongest, &longest, + NULL); + + XawListChange (chooseSessionListWidget, + sessionNamesLong, sessionNameCount, longest, True); + + SessionSelected (current->list_index, True); + + break_lock_phase = 0; + } + + XtFree ((char *) current); +} + + + +static void +ChooseSessionFailSafeXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + /* + * Pop down choice of sessions, and start the fail safe session. + */ + + CheckDeleteCancel (); + CheckBreakLockCancel (); + + XtPopdown (chooseSessionPopup); + + if (session_name) + XtFree (session_name); + + session_name = XtNewString (FAILSAFE_SESSION_NAME); + + FreeSessionNames (sessionNameCount, + sessionNamesShort, sessionNamesLong, sessionsLocked); + + + /* + * We don't need to check return value of StartSession in this case, + * because we are using the default session, and StartSession will + * not try to lock the session at this time. It will try to lock + * it as soon as the user gives the session a name. + */ + + StartSession (session_name, + True /* Use ~/.xsmstartup if found, else system.xsm */); +} + + + +static void +ChooseSessionCancelXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + if (delete_session_phase > 0 || break_lock_phase > 0) + { + XtVaSetValues (chooseSessionMessageLabel, + XtNforeground, save_message_background, + NULL); + + delete_session_phase = 0; + break_lock_phase = 0; + } + else + EndSession (2); +} + + + +void +create_choose_session_popup () + +{ + static XtActionsRec choose_actions[] = { + {"ChooseSessionUp", ChooseSessionUp}, + {"ChooseSessionDown", ChooseSessionDown}, + {"ChooseSessionBtn1Down", ChooseSessionBtn1Down} + }; + + /* + * Pop up for choosing session at startup + */ + + chooseSessionPopup = XtVaCreatePopupShell ( + "chooseSessionPopup", transientShellWidgetClass, topLevel, + XtNallowShellResize, True, + NULL); + + + chooseSessionForm = XtVaCreateManagedWidget ( + "chooseSessionForm", formWidgetClass, chooseSessionPopup, + NULL); + + + chooseSessionLabel = XtVaCreateManagedWidget ( + "chooseSessionLabel", labelWidgetClass, chooseSessionForm, + XtNfromHoriz, NULL, + XtNfromVert, NULL, + XtNborderWidth, 0, + XtNresizable, True, + XtNjustify, XtJustifyCenter, + NULL); + + chooseSessionListWidget = XtVaCreateManagedWidget ( + "chooseSessionListWidget", listWidgetClass, chooseSessionForm, + XtNresizable, True, + XtNdefaultColumns, 1, + XtNforceColumns, True, + XtNfromHoriz, NULL, + XtNfromVert, chooseSessionLabel, + XtNvertDistance, 25, + NULL); + + chooseSessionMessageLabel = XtVaCreateManagedWidget ( + "chooseSessionMessageLabel", labelWidgetClass, chooseSessionForm, + XtNfromHoriz, NULL, + XtNfromVert, chooseSessionListWidget, + XtNborderWidth, 0, + XtNresizable, True, + XtNjustify, XtJustifyCenter, + NULL); + + chooseSessionLoadButton = XtVaCreateManagedWidget ( + "chooseSessionLoadButton", commandWidgetClass, chooseSessionForm, + XtNfromHoriz, NULL, + XtNfromVert, chooseSessionMessageLabel, + NULL); + + XtAddCallback (chooseSessionLoadButton, XtNcallback, + ChooseSessionLoadXtProc, 0); + + chooseSessionDeleteButton = XtVaCreateManagedWidget ( + "chooseSessionDeleteButton", commandWidgetClass, chooseSessionForm, + XtNfromHoriz, chooseSessionLoadButton, + XtNfromVert, chooseSessionMessageLabel, + NULL); + + XtAddCallback (chooseSessionDeleteButton, XtNcallback, + ChooseSessionDeleteXtProc, 0); + + chooseSessionBreakLockButton = XtVaCreateManagedWidget ( + "chooseSessionBreakLockButton", + commandWidgetClass, chooseSessionForm, + XtNfromHoriz, chooseSessionDeleteButton, + XtNfromVert, chooseSessionMessageLabel, + NULL); + + XtAddCallback (chooseSessionBreakLockButton, XtNcallback, + ChooseSessionBreakLockXtProc, 0); + + chooseSessionFailSafeButton = XtVaCreateManagedWidget ( + "chooseSessionFailSafeButton", commandWidgetClass, chooseSessionForm, + XtNfromHoriz, chooseSessionBreakLockButton, + XtNfromVert, chooseSessionMessageLabel, + NULL); + + XtAddCallback (chooseSessionFailSafeButton, XtNcallback, + ChooseSessionFailSafeXtProc, 0); + + + chooseSessionCancelButton = XtVaCreateManagedWidget ( + "chooseSessionCancelButton", commandWidgetClass, chooseSessionForm, + XtNfromHoriz, chooseSessionFailSafeButton, + XtNfromVert, chooseSessionMessageLabel, + NULL); + + XtAddCallback (chooseSessionCancelButton, XtNcallback, + ChooseSessionCancelXtProc, 0); + + XtAppAddActions (appContext, choose_actions, XtNumber (choose_actions)); + + XtInstallAllAccelerators (chooseSessionListWidget, chooseSessionPopup); +} diff --git a/choose.h b/choose.h new file mode 100644 index 0000000..6816839 --- /dev/null +++ b/choose.h @@ -0,0 +1,30 @@ +/* $Xorg: choose.h,v 1.4 2001/02/09 02:05:59 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +extern void create_choose_session_popup (); +extern int GetSessionNames (); +extern void FreeSessionNames (); +extern void ChooseSession (); diff --git a/globals.c b/globals.c new file mode 100644 index 0000000..4c6d1cd --- /dev/null +++ b/globals.c @@ -0,0 +1,88 @@ +/* $Xorg: globals.c,v 1.4 2001/02/09 02:05:59 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include <X11/ICE/ICEutil.h> + +int Argc; +char **Argv; + +List *RunningList; +List *PendingList; +List *RestartAnywayList; +List *RestartImmedList; + +List *WaitForSaveDoneList; +List *FailedSaveList; +List *WaitForInteractList; +List *WaitForPhase2List; + +Bool wantShutdown = False; +Bool shutdownInProgress = False; +Bool phase2InProgress = False; +Bool saveInProgress = False; +Bool shutdownCancelled = False; + +Bool verbose = False; + +char *sm_id = NULL; + +char *networkIds = NULL; +char *session_name = NULL; + +IceAuthDataEntry *authDataEntries = NULL; +int numTransports = 0; + +Bool client_info_visible = False; +Bool client_prop_visible = False; +Bool client_log_visible = False; + +String *clientListNames = NULL; +ClientRec **clientListRecs = NULL; +int numClientListNames = 0; + +int current_client_selected; + +int sessionNameCount = 0; +String *sessionNamesShort = NULL; +String *sessionNamesLong = NULL; +Bool *sessionsLocked = NULL; + +int num_clients_in_last_session = -1; + +char **non_session_aware_clients = NULL; +int non_session_aware_count = 0; + +char *display_env = NULL, *non_local_display_env = NULL; +char *session_env = NULL, *non_local_session_env = NULL; +char *audio_env = NULL; + +Bool need_to_name_session = False; + +Bool remote_allowed; + +XtAppContext appContext; +Widget topLevel; + @@ -0,0 +1,1050 @@ +/* $Xorg: info.c,v 1.5 2001/02/09 02:05:59 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include "xsm.h" +#include "restart.h" +#include "popup.h" + +#include <X11/Shell.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/List.h> +#include <X11/Xaw/Command.h> +#include <X11/Xaw/SimpleMenu.h> +#include <X11/Xaw/MenuButton.h> +#include <X11/Xaw/SmeBSB.h> +#include <X11/Xaw/AsciiText.h> + +static Pixmap checkBitmap; + +Widget clientInfoPopup; +Widget clientInfoForm; +Widget viewPropButton; +Widget cloneButton; +Widget killClientButton; +Widget clientInfoDoneButton; +Widget restartHintButton; +Widget restartHintMenu; +Widget restartIfRunning; +Widget restartAnyway; +Widget restartImmediately; +Widget restartNever; +Widget clientListWidget; +Widget noClientsLabel; +Widget manualRestartLabel; +Widget manualRestartCommands; + +Widget clientPropPopup; +Widget clientPropForm; +Widget clientPropDoneButton; +Widget clientPropTextWidget; + + + +void +ShowHint (client) + +ClientRec *client; + +{ + static Widget active = NULL; + int hint = client->restartHint; + + if (active) + XtVaSetValues (active, XtNleftBitmap, None, NULL); + + if (hint == SmRestartIfRunning) + active = restartIfRunning; + else if (hint == SmRestartAnyway) + active = restartAnyway; + else if (hint == SmRestartImmediately) + active = restartImmediately; + else if (hint == SmRestartNever) + active = restartNever; + + XtVaSetValues (active, XtNleftBitmap, checkBitmap, NULL); +} + + + +typedef struct { + char *bufStart; + char *bufPtr; + int bufSize; + int bytesLeft; +} Buffer; + +#define BUF_START_SIZE 1024 +#define BUF_GROW_SIZE 256 + + +static void +AppendStr (buffer, str) + +Buffer *buffer; +char *str; + +{ + int len = strlen (str); + + if ((buffer->bytesLeft - 1) < len) + { + int newBufSize = buffer->bufSize + len + BUF_GROW_SIZE; + char *newbuf = (char *) malloc (newBufSize); + int bytesUsed = buffer->bufPtr - buffer->bufStart; + memcpy (newbuf, buffer->bufStart, bytesUsed); + newbuf[bytesUsed] = '\0'; + free (buffer->bufStart); + buffer->bufStart = newbuf; + buffer->bufPtr = newbuf + bytesUsed; + buffer->bufSize = newBufSize; + buffer->bytesLeft = newBufSize - bytesUsed; + } + + strcat (buffer->bufPtr, str); + buffer->bufPtr += len; + buffer->bytesLeft -= len; +} + + +void +DisplayProps (client) + +ClientRec *client; + +{ + int index; + List *pl, *pj, *vl; + PropValue *pval; + Buffer buffer; + static int first_time = 1; + + for (index = 0; index < numClientListNames; index++) + if (clientListRecs[index] == client) + break; + + if (index >= numClientListNames) + return; + + buffer.bufStart = buffer.bufPtr = (char *) malloc (BUF_START_SIZE); + buffer.bufSize = buffer.bytesLeft = BUF_START_SIZE; + buffer.bufStart[0] = '\0'; + + if (ListCount (client->props) > 0) + { + char number[10]; + char *ptr; + + AppendStr (&buffer, "*** ID = "); + AppendStr (&buffer, client->clientId); + AppendStr (&buffer, " ***\n\n"); + + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + { + Prop *pprop = (Prop *) pl->thing; + + AppendStr (&buffer, "Name: "); + AppendStr (&buffer, pprop->name); + AppendStr (&buffer, "\n"); + AppendStr (&buffer, "Type: "); + AppendStr (&buffer, pprop->type); + AppendStr (&buffer, "\n"); + AppendStr (&buffer, "Num values: "); + sprintf (number, "%d", ListCount (pprop->values)); + AppendStr (&buffer, number); + AppendStr (&buffer, "\n"); + + if (strcmp (pprop->type, SmCARD8) == 0) + { + char *card8; + int value; + + vl = ListFirst (pprop->values); + pval = (PropValue *) vl->thing; + + card8 = pval->value; + value = *card8; + + AppendStr (&buffer, "Value 1: "); + sprintf (number, "%d", value); + AppendStr (&buffer, number); + + if (strcmp (pprop->name, SmRestartStyleHint) == 0) + { + if (value == SmRestartAnyway) + AppendStr (&buffer, " (Restart Anyway)"); + else if (value == SmRestartImmediately) + AppendStr (&buffer, " (Restart Immediately)"); + else if (value == SmRestartNever) + AppendStr (&buffer, " (Restart Never)"); + else + AppendStr (&buffer, " (Restart If Running)"); + } + + AppendStr (&buffer, "\n"); + } + else + { + int propnum = 0; + + for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj)) + { + propnum++; + + pval = (PropValue *) pj->thing; + AppendStr (&buffer, "Value "); + sprintf (number, "%d", propnum); + AppendStr (&buffer, number); + AppendStr (&buffer, ": "); + AppendStr (&buffer, (char *) pval->value); + AppendStr (&buffer, "\n"); + } + } + + AppendStr (&buffer, "\n"); + } + + XtVaSetValues (clientPropTextWidget, + XtNstring, buffer.bufStart, + NULL); + + sprintf (buffer.bufStart, + "SM Properties : %s", clientListNames[index]); + + ptr = Strstr (buffer.bufStart, ") Restart"); + if (ptr) *(ptr + 1) = '\0'; + + XtVaSetValues (clientPropPopup, + XtNtitle, buffer.bufStart, + XtNiconName, buffer.bufStart, + NULL); + + if (client_prop_visible) + { + /* Make sure it is visible */ + + XMapRaised (XtDisplay (topLevel), XtWindow (clientPropPopup)); + } + else + { + PopupPopup (mainWindow, clientPropPopup, + False, first_time, 50, 150, "DelPropWinAction()"); + + client_prop_visible = 1; + + if (first_time) + first_time = 0; + } + } + + free (buffer.bufStart); +} + + + +static void +ClientListXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + XawListReturnStruct *current = (XawListReturnStruct *) callData; + ClientRec *client; + + if (!current || current->list_index < 0) + return; + + client = clientListRecs[current->list_index]; + ShowHint (client); + current_client_selected = current->list_index; + if (client_prop_visible) + DisplayProps (client); +} + + + + +static void +ViewPropXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + ClientRec *client; + XawListReturnStruct *current; + + current = XawListShowCurrent (clientListWidget); + + if (!current || current->list_index < 0) + { + if (current) + XtFree ((char *) current); + return; + } + + client = clientListRecs[current->list_index]; + DisplayProps (client); + XtFree ((char *) current); +} + + + +static void +CloneXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + ClientRec *client; + XawListReturnStruct *current; + + current = XawListShowCurrent (clientListWidget); + + if (!current || current->list_index < 0) + { + if (current) + XtFree ((char *) current); + return; + } + + client = clientListRecs[current->list_index]; + + if (client) + Clone (client, False /* don't use saved state */); + + XtFree ((char *) current); +} + + + +static void +KillClientXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + ClientRec *client; + XawListReturnStruct *current; + + current = XawListShowCurrent (clientListWidget); + + if (!current || current->list_index < 0) + { + if (current) + XtFree ((char *) current); + return; + } + + client = clientListRecs[current->list_index]; + + SmsDie (client->smsConn); + + XtFree ((char *) current); +} + + + +static void +listDoneXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + XtPopdown (clientInfoPopup); + client_info_visible = 0; +} + + + +char * +GetProgramName (fullname) + +char *fullname; + +{ + char *lastSlash = NULL; + int i; + + for (i = 0; i < (int) strlen (fullname); i++) + if (fullname[i] == '/') + lastSlash = &fullname[i]; + + if (lastSlash) + return (lastSlash + 1); + else + return (fullname); +} + + + +void +UpdateClientList () + +{ + ClientRec *client; + char *progName, *hostname, *tmp1, *tmp2; + String clientInfo; + int maxlen1, maxlen2; + char extraBuf1[80], extraBuf2[80]; + char *restart_service_prop; + List *cl, *pl; + int i, k; + static int reenable_asap = 0; + + if (clientListNames) + { + /* + * Free the previous list of names. Xaw doesn't make a copy of + * our list, so we need to keep it around. + */ + + for (i = 0; i < numClientListNames; i++) + XtFree (clientListNames[i]); + + XtFree ((char *) clientListNames); + + clientListNames = NULL; + } + + if (clientListRecs) + { + /* + * Free the mapping of client names to client records + */ + + XtFree ((char *) clientListRecs); + clientListRecs = NULL; + } + + maxlen1 = maxlen2 = 0; + numClientListNames = 0; + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + progName = NULL; + restart_service_prop = NULL; + + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + { + Prop *pprop = (Prop *) pl->thing; + List *vl = ListFirst (pprop->values); + if (vl != NULL) + { + PropValue *pval = (PropValue *) vl->thing; + + if (strcmp (pprop->name, SmProgram) == 0) + { + progName = GetProgramName ((char *) pval->value); + + if ((int) strlen (progName) > maxlen1) + maxlen1 = strlen (progName); + } + else if (strcmp (pprop->name, "_XC_RestartService") == 0) + { + restart_service_prop = (char *) pval->value; + } + } + } + + if (!progName) + continue; + + if (restart_service_prop) + tmp1 = restart_service_prop; + else if (client->clientHostname) + tmp1 = client->clientHostname; + else + continue; + + if ((tmp2 = (char *) strchr (tmp1, '/')) == NULL) + hostname = tmp1; + else + hostname = tmp2 + 1; + + if ((int) strlen (hostname) > maxlen2) + maxlen2 = strlen (hostname); + + numClientListNames++; + } + + if (numClientListNames == 0) + { + XtSetSensitive (viewPropButton, 0); + XtSetSensitive (cloneButton, 0); + XtSetSensitive (killClientButton, 0); + XtSetSensitive (restartHintButton, 0); + + XtUnmanageChild (clientListWidget); + XtManageChild (noClientsLabel); + + reenable_asap = 1; + + return; + } + + if (reenable_asap) + { + XtSetSensitive (viewPropButton, 1); + XtSetSensitive (cloneButton, 1); + XtSetSensitive (killClientButton, 1); + XtSetSensitive (restartHintButton, 1); + + XtUnmanageChild (noClientsLabel); + XtManageChild (clientListWidget); + + reenable_asap = 0; + } + + clientListNames = (String *) XtMalloc ( + numClientListNames * sizeof (String)); + clientListRecs = (ClientRec **) XtMalloc ( + numClientListNames * sizeof (ClientRec *)); + + i = 0; + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + ClientRec *client = (ClientRec *) cl->thing; + int extra1, extra2; + char *hint; + + progName = NULL; + restart_service_prop = NULL; + + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + { + Prop *pprop = (Prop *) pl->thing; + List *vl = ListFirst (pprop->values); + + if (vl != NULL) + { + PropValue *pval = (PropValue *) vl->thing; + if (strcmp (pprop->name, SmProgram) == 0) + { + progName = GetProgramName ((char *) pval->value); + } + else if (strcmp (pprop->name, "_XC_RestartService") == 0) + { + restart_service_prop = (char *) pval->value; + } + } + } + + if (!progName) + continue; + + if (restart_service_prop) + tmp1 = restart_service_prop; + else if (client->clientHostname) + tmp1 = client->clientHostname; + else + continue; + + if ((tmp2 = (char *) strchr (tmp1, '/')) == NULL) + hostname = tmp1; + else + hostname = tmp2 + 1; + + extra1 = maxlen1 - strlen (progName) + 5; + extra2 = maxlen2 - strlen (hostname); + + if (client->restartHint == SmRestartIfRunning) + hint = "Restart If Running"; + else if (client->restartHint == SmRestartAnyway) + hint = "Restart Anyway"; + else if (client->restartHint == SmRestartImmediately) + hint = "Restart Immediately"; + else if (client->restartHint == SmRestartNever) + hint = "Restart Never"; + else + hint = ""; + + clientInfo = (String) XtMalloc (strlen (progName) + + extra1 + extra2 + 3 + strlen (hostname) + 3 + strlen (hint) + 1); + + for (k = 0; k < extra1; k++) + extraBuf1[k] = ' '; + extraBuf1[extra1] = '\0'; + + for (k = 0; k < extra2; k++) + extraBuf2[k] = ' '; + extraBuf2[extra2] = '\0'; + + sprintf (clientInfo, "%s%s (%s%s) %s", progName, extraBuf1, + hostname, extraBuf2, hint); + + clientListRecs[i] = client; + clientListNames[i++] = clientInfo; + } + + XawListChange (clientListWidget, + clientListNames, numClientListNames, 0, True); +} + + + +static void +RestartHintXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + XawListReturnStruct *current; + ClientRec *client; + Widget active; + int found = 0; + List *pl; + char hint; + + current = XawListShowCurrent (clientListWidget); + + if (!current || current->list_index < 0) + { + if (current) + XtFree ((char *) current); + return; + } + + client = clientListRecs[current->list_index]; + + active = XawSimpleMenuGetActiveEntry (restartHintMenu); + + if (active == restartIfRunning) + hint = SmRestartIfRunning; + else if (active == restartAnyway) + hint = SmRestartAnyway; + else if (active == restartImmediately) + hint = SmRestartImmediately; + else if (active == restartNever) + hint = SmRestartNever; + else + { + XtFree ((char *) current); + return; + } + + client->restartHint = hint; + + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + { + Prop *pprop = (Prop *) pl->thing; + + if (strcmp (SmRestartStyleHint, pprop->name) == 0) + { + List *vl = ListFirst (pprop->values); + PropValue *pval = (PropValue *) vl->thing; + + *((char *) (pval->value)) = hint; + found = 1; + break; + } + } + + if (!found) + { + SmProp prop; + SmPropValue propval; + + prop.name = SmRestartStyleHint; + prop.type = SmCARD8; + prop.num_vals = 1; + prop.vals = &propval; + propval.value = (SmPointer) &hint; + propval.length = 1; + + SetProperty (client, &prop, False /* don't free it */); + } + + UpdateClientList (); + XawListHighlight (clientListWidget, current_client_selected); + ShowHint (client); + + if (client_prop_visible && clientListRecs && + clientListRecs[current_client_selected] == client) + { + DisplayProps (client); + } + + XtFree ((char *) current); +} + + + +static void +clientPropDoneXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + XtPopdown (clientPropPopup); + client_prop_visible = 0; +} + + + +void +ClientInfoStructureNotifyXtHandler (w, closure, event, continue_to_dispatch) + +Widget w; +XtPointer closure; +XEvent *event; +Boolean *continue_to_dispatch; + +{ + if (event->type == MapNotify) + { + UpdateClientList (); + + if (current_client_selected >= 0) + XawListHighlight (clientListWidget, current_client_selected); + + XtRemoveEventHandler (clientInfoPopup, StructureNotifyMask, False, + ClientInfoStructureNotifyXtHandler, NULL); + } +} + + + +void +ClientInfoXtProc (w, client_data, callData) + Widget w; + XtPointer client_data; + XtPointer callData; + +{ + static int first_time = 1; + + if (client_info_visible) + { + /* Make sure it is visible */ + + XMapRaised (XtDisplay (topLevel), XtWindow (clientInfoPopup)); + } + else + { + UpdateClientList (); + + if (clientListRecs && clientListRecs[0]) + { + current_client_selected = 0; + XawListHighlight (clientListWidget, 0); + ShowHint (clientListRecs[0]); + if (client_prop_visible) + DisplayProps (clientListRecs[0]); + } + else + current_client_selected = -1; + + if (first_time && num_clients_in_last_session > 0 && + num_clients_in_last_session != numClientListNames) + { + XtAddEventHandler (clientInfoPopup, StructureNotifyMask, False, + ClientInfoStructureNotifyXtHandler, NULL); + } + + PopupPopup (mainWindow, clientInfoPopup, + False, first_time, 100, 50, "DelClientInfoWinAction()"); + + client_info_visible = 1; + + if (first_time) + first_time = 0; + } +} + + +#define CHECK_WIDTH 9 +#define CHECK_HEIGHT 8 + +static unsigned char check_bits[] = { + 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00, + 0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00 +}; + + + +static void +DelClientInfoWinAction (w, event, params, num_params) + +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; + +{ + XtCallCallbacks (clientInfoDoneButton, XtNcallback, NULL); +} + + + +static void +DelPropWinAction (w, event, params, num_params) + +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; + +{ + XtCallCallbacks (clientPropDoneButton, XtNcallback, NULL); +} + + + +void +create_client_info_popup () + +{ + /* + * Install actions for WM_DELETE_WINDOW + */ + + static XtActionsRec actions[] = { + {"DelClientInfoWinAction", DelClientInfoWinAction}, + {"DelPropWinAction", DelPropWinAction} + }; + + XtAppAddActions (appContext, actions, XtNumber (actions)); + + + /* + * Make checkmark bitmap + */ + + checkBitmap = XCreateBitmapFromData ( + XtDisplay (topLevel), RootWindowOfScreen (XtScreen (topLevel)), + (char *) check_bits, CHECK_WIDTH, CHECK_HEIGHT); + + + /* + * Pop up for List Clients button. + */ + + clientInfoPopup = XtVaCreatePopupShell ( + "clientInfoPopup", topLevelShellWidgetClass, topLevel, + XtNallowShellResize, True, + NULL); + + + clientInfoForm = XtVaCreateManagedWidget ( + "clientInfoForm", formWidgetClass, clientInfoPopup, + NULL); + + viewPropButton = XtVaCreateManagedWidget ( + "viewPropButton", commandWidgetClass, clientInfoForm, + XtNfromHoriz, NULL, + XtNfromVert, NULL, + XtNtop, XawChainTop, + XtNbottom, XawChainTop, + XtNleft, XawChainLeft, + XtNright, XawChainLeft, + NULL); + + XtAddCallback (viewPropButton, XtNcallback, ViewPropXtProc, 0); + + + cloneButton = XtVaCreateManagedWidget ( + "cloneButton", commandWidgetClass, clientInfoForm, + XtNfromHoriz, viewPropButton, + XtNfromVert, NULL, + XtNtop, XawChainTop, + XtNbottom, XawChainTop, + XtNleft, XawChainLeft, + XtNright, XawChainLeft, + NULL); + + XtAddCallback (cloneButton, XtNcallback, CloneXtProc, 0); + + + killClientButton = XtVaCreateManagedWidget ( + "killClientButton", commandWidgetClass, clientInfoForm, + XtNfromHoriz, cloneButton, + XtNfromVert, NULL, + XtNtop, XawChainTop, + XtNbottom, XawChainTop, + XtNleft, XawChainLeft, + XtNright, XawChainLeft, + NULL); + + XtAddCallback (killClientButton, XtNcallback, KillClientXtProc, 0); + + + restartHintButton = XtVaCreateManagedWidget ( + "restartHintButton", menuButtonWidgetClass, clientInfoForm, + XtNmenuName, "restartHintMenu", + XtNfromHoriz, killClientButton, + XtNfromVert, NULL, + XtNtop, XawChainTop, + XtNbottom, XawChainTop, + XtNleft, XawChainLeft, + XtNright, XawChainLeft, + NULL); + + restartHintMenu = XtVaCreatePopupShell ( + "restartHintMenu", simpleMenuWidgetClass, clientInfoForm, + NULL); + + restartIfRunning = XtVaCreateManagedWidget ( + "restartIfRunning", smeBSBObjectClass, restartHintMenu, + XtNleftMargin, 18, + NULL); + + restartAnyway = XtVaCreateManagedWidget ( + "restartAnyway", smeBSBObjectClass, restartHintMenu, + XtNleftMargin, 18, + NULL); + + restartImmediately = XtVaCreateManagedWidget ( + "restartImmediately", smeBSBObjectClass, restartHintMenu, + XtNleftMargin, 18, + NULL); + + restartNever = XtVaCreateManagedWidget ( + "restartNever", smeBSBObjectClass, restartHintMenu, + XtNleftMargin, 18, + NULL); + + XtAddCallback (restartIfRunning, XtNcallback, RestartHintXtProc, 0); + XtAddCallback (restartAnyway, XtNcallback, RestartHintXtProc, 0); + XtAddCallback (restartImmediately, XtNcallback, RestartHintXtProc, 0); + XtAddCallback (restartNever, XtNcallback, RestartHintXtProc, 0); + + + clientInfoDoneButton = XtVaCreateManagedWidget ( + "clientInfoDoneButton", commandWidgetClass, clientInfoForm, + XtNfromHoriz, restartHintButton, + XtNfromVert, NULL, + XtNtop, XawChainTop, + XtNbottom, XawChainTop, + XtNleft, XawChainLeft, + XtNright, XawChainLeft, + NULL); + + XtAddCallback (clientInfoDoneButton, XtNcallback, listDoneXtProc, 0); + + + clientListWidget = XtVaCreateManagedWidget ( + "clientListWidget", listWidgetClass, clientInfoForm, + XtNdefaultColumns, 1, + XtNforceColumns, True, + XtNfromHoriz, NULL, + XtNfromVert, viewPropButton, + XtNresizable, True, + XtNtop, XawChainTop, + XtNbottom, XawChainTop, + NULL); + + XtAddCallback (clientListWidget, XtNcallback, ClientListXtProc, 0); + + noClientsLabel = XtVaCreateWidget ( + "noClientsLabel", labelWidgetClass, clientInfoForm, + XtNfromHoriz, NULL, + XtNfromVert, viewPropButton, + XtNborderWidth, 0, + XtNtop, XawChainTop, + XtNbottom, XawChainTop, + NULL); + + manualRestartLabel = XtVaCreateManagedWidget ( + "manualRestartLabel", labelWidgetClass, clientInfoForm, + XtNfromHoriz, NULL, + XtNfromVert, clientListWidget, + XtNborderWidth, 0, + XtNvertDistance, 20, + XtNtop, XawChainBottom, + XtNbottom, XawChainBottom, + XtNleft, XawChainLeft, + XtNright, XawChainLeft, + NULL); + + manualRestartCommands = XtVaCreateManagedWidget ( + "manualRestartCommands", asciiTextWidgetClass, clientInfoForm, + XtNfromHoriz, NULL, + XtNfromVert, manualRestartLabel, + XtNeditType, XawtextEdit, + XtNresizable, True, + XtNresize, XawtextResizeWidth, + XtNscrollVertical, XawtextScrollAlways, + XtNwidth, 350, + XtNheight, 100, + XtNtop, XawChainBottom, + XtNbottom, XawChainBottom, + NULL); + + /* + * Pop up for viewing client properties + */ + + clientPropPopup = XtVaCreatePopupShell ( + "clientPropPopup", topLevelShellWidgetClass, topLevel, + XtNallowShellResize, True, + NULL); + + + clientPropForm = XtVaCreateManagedWidget ( + "clientPropForm", formWidgetClass, clientPropPopup, + NULL); + + clientPropDoneButton = XtVaCreateManagedWidget ( + "clientPropDoneButton", commandWidgetClass, clientPropForm, + XtNfromHoriz, NULL, + XtNfromVert, NULL, + XtNtop, XawChainTop, + XtNbottom, XawChainTop, + XtNleft, XawChainLeft, + XtNright, XawChainLeft, + NULL); + + XtAddCallback (clientPropDoneButton, XtNcallback, clientPropDoneXtProc, 0); + + + clientPropTextWidget = XtVaCreateManagedWidget ( + "clientPropTextWidget", asciiTextWidgetClass, clientPropForm, + XtNfromHoriz, NULL, + XtNfromVert, clientPropDoneButton, + XtNeditType, XawtextRead, + XtNdisplayCaret, False, + XtNscrollVertical, XawtextScrollWhenNeeded, + XtNscrollHorizontal, XawtextScrollWhenNeeded, + XtNresizable, True, + XtNtop, XawChainTop, + XtNbottom, XawChainBottom, + NULL); +} @@ -0,0 +1,29 @@ +/* $Xorg: info.h,v 1.4 2001/02/09 02:05:59 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +extern void create_client_info_popup (); +extern void UpdateClientList (); +extern void ClientInfoXtProc (); @@ -0,0 +1,170 @@ +/* $Xorg: list.c,v 1.4 2001/02/09 02:05:59 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include "xsm.h" + +List * +ListInit() +{ + List *l; + + l = (List *)XtMalloc(sizeof *l); + if(!l) return l; + l->next = l; + l->prev = l; + l->thing = NULL; + return l; +} + +List * +ListFirst(l) +List *l; +{ + if(l->next->thing) return l->next; + else return NULL; +} + +List * +ListNext(l) +List *l; +{ + if(l->next->thing) return l->next; + else return NULL; +} + +void +ListFreeAll(l) +List *l; +{ + char *thing; + List *next; + + next = l->next; + do { + l = next; + next = l->next; + thing = l->thing; + XtFree((char *)l); + } while(thing); +} + +void +ListFreeAllButHead(l) +List *l; +{ + List *p, *next; + + p = ListFirst(l); + + while (p) + { + next = ListNext (p); + XtFree((char *) p); + p = next; + } + + l->next = l; + l->prev = l; +} + +List * +ListAddFirst(l, v) +List *l; +char *v; +{ + List *e; + + e = (List *)XtMalloc(sizeof *e); + if(!e) return NULL; + + e->thing = v; + e->prev = l; + e->next = e->prev->next; + e->prev->next = e; + e->next->prev = e; + + return e; +} + +List * +ListAddLast(l, v) +List *l; +char *v; +{ + List *e; + + e = (List *)XtMalloc(sizeof *e); + if(!e) return NULL; + + e->thing = v; + e->next = l; + e->prev = e->next->prev; + e->prev->next = e; + e->next->prev = e; + + return e; +} + +void +ListFreeOne(e) +List *e; +{ + e->next->prev = e->prev; + e->prev->next = e->next; + XtFree((char *)e); +} + + +Status +ListSearchAndFreeOne(l,thing) +List *l; +char *thing; +{ + List *p; + + for (p = ListFirst (l); p; p = ListNext (p)) + if (((char *) p->thing) == (char *) thing) + { + ListFreeOne (p); + return (1); + } + + return (0); +} + + +int +ListCount(l) +List *l; +{ + int i; + List *e; + + i = 0; + for(e = ListFirst(l); e; e = ListNext(e)) i++; + + return i; +} @@ -0,0 +1,42 @@ +/* $Xorg: list.h,v 1.4 2001/02/09 02:05:59 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +typedef struct _List { + struct _List *prev; + struct _List *next; + char *thing; +} List; + +extern List *ListInit(); +extern List *ListFirst(); +extern List *ListNext(); +extern void ListFreeAll(); +extern void ListFreeAllButHead(); +extern void ListFreeOne(); +extern Status ListSearchAndFreeOne(); +extern List *ListAddFirst(); +extern List *ListAddLast(); +extern int ListCount(); @@ -0,0 +1,176 @@ +/* $Xorg: lock.c,v 1.4 2001/02/09 02:05:59 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. +******************************************************************************/ + +#include "xsm.h" +#include <sys/types.h> + + +static char * +GetPath () + +{ + char *path = (char *) getenv ("SM_SAVE_DIR"); + + if (!path) + { + path = (char *) getenv ("HOME"); + if (!path) + path = "."; + } + + return (path); +} + + +Status +LockSession (session_name, write_id) + +char *session_name; +Bool write_id; + +{ + char *path; + char lock_file[PATH_MAX]; + char temp_lock_file[PATH_MAX]; + Status status; + int fd; + + path = GetPath (); + + sprintf (lock_file, "%s/.XSMlock-%s", path, session_name); + sprintf (temp_lock_file, "%s/.XSMtlock-%s", path, session_name); + + if ((fd = creat (temp_lock_file, 0444)) < 0) + return (0); + + if (write_id && + (write (fd, networkIds, strlen (networkIds)) != strlen (networkIds)) || + (write (fd, "\n", 1) != 1)) + { + close (fd); + return (0); + } + + close (fd); + + status = 1; + + if (link (temp_lock_file, lock_file) < 0) + status = 0; + + if (unlink (temp_lock_file) < 0) + status = 0; + + return (status); +} + + +void +UnlockSession (session_name) + +char *session_name; + +{ + char *path; + char lock_file[PATH_MAX]; + + path = GetPath (); + + sprintf (lock_file, "%s/.XSMlock-%s", path, session_name); + + unlink (lock_file); +} + + +char * +GetLockId (session_name) + +char *session_name; + +{ + char *path; + FILE *fp; + char lock_file[PATH_MAX]; + char buf[256]; + char *ret; + + path = GetPath (); + + sprintf (lock_file, "%s/.XSMlock-%s", path, session_name); + + if ((fp = fopen (lock_file, "r")) == NULL) + { + return (NULL); + } + + buf[0] = '\0'; + fscanf (fp, "%s\n", buf); + ret = XtNewString (buf); + + fclose (fp); + + return (ret); +} + + +Bool +CheckSessionLocked (session_name, get_id, id_ret) + +char *session_name; +Bool get_id; +char **id_ret; + +{ + if (get_id) + *id_ret = GetLockId (session_name); + + if (!LockSession (session_name, False)) + return (1); + + UnlockSession (session_name); + return (0); +} + + +void +UnableToLockSession (session_name) + +char *session_name; + +{ + /* + * We should popup a dialog here giving error. + */ + +#ifdef XKB + XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_Failure); +#else + XBell (XtDisplay (topLevel), 0); +#endif + sleep (2); + + ChooseSession (); +} @@ -0,0 +1,31 @@ +/* $Xorg: lock.h,v 1.4 2001/02/09 02:06:01 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. +******************************************************************************/ + +extern Status LockSession (); +extern void UnlockSession (); +extern char *GetLockId (); +extern Bool CheckSessionLocked (); +extern void UnableToLockSession (); @@ -0,0 +1,167 @@ +/* $Xorg: log.c,v 1.4 2001/02/09 02:06:01 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. +******************************************************************************/ + +#include "xsm.h" +#include "save.h" +#include "popup.h" + +#include <X11/Shell.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/Command.h> +#include <X11/Xaw/AsciiText.h> + +Widget logPopup; +Widget logForm; +Widget logText; +Widget logOkButton; + + + +void +DisplayLogXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + static int first_time = 1; + + if (client_log_visible) + { + /* Make sure it is visible */ + + XMapRaised (XtDisplay (topLevel), XtWindow (logPopup)); + } + else + { + PopupPopup (mainWindow, logPopup, + False, first_time, 50, 50, "DelLogWinAction()"); + + client_log_visible = 1; + + if (first_time) + first_time = 0; + } +} + + + +static void +logOkXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + XtPopdown (logPopup); + client_log_visible = 0; +} + + + +void +add_log_text (str) + +char *str; + +{ + XawTextPosition pos = XawTextGetInsertionPoint (logText); + XawTextBlock text; + + text.firstPos = 0; + text.length = strlen (str); + text.ptr = str; + text.format = XawFmt8Bit; + + XawTextReplace (logText, pos, pos, &text); +} + + + +static void +DelLogWinAction (w, event, params, num_params) + +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; + +{ + XtCallCallbacks (logOkButton, XtNcallback, NULL); +} + + + +void +create_log_popup () + +{ + /* + * Pop up for session log + */ + + static XtActionsRec actions[] = { + {"DelLogWinAction", DelLogWinAction} + }; + + XtAppAddActions (appContext, actions, XtNumber (actions)); + + logPopup = XtVaCreatePopupShell ("logPopup", + topLevelShellWidgetClass, topLevel, + XtNallowShellResize, True, + NULL); + + logForm = XtVaCreateManagedWidget ( + "logForm", formWidgetClass, logPopup, + NULL); + + logText = XtVaCreateManagedWidget ( + "logText", asciiTextWidgetClass, logForm, + XtNfromHoriz, NULL, + XtNfromVert, NULL, + XtNeditType, XawtextAppend, + XtNdisplayCaret, False, + XtNscrollVertical, XawtextScrollAlways, + XtNscrollHorizontal, XawtextScrollWhenNeeded, + XtNresizable, True, + XtNtop, XawChainTop, + XtNbottom, XawChainBottom, + NULL); + + logOkButton = XtVaCreateManagedWidget ( + "logOkButton", commandWidgetClass, logForm, + XtNfromHoriz, NULL, + XtNfromVert, logText, + XtNtop, XawChainBottom, + XtNbottom, XawChainBottom, + XtNleft, XawChainLeft, + XtNright, XawChainLeft, + NULL); + + XtAddCallback (logOkButton, XtNcallback, logOkXtProc, 0); +} @@ -0,0 +1,29 @@ +/* $Xorg: log.h,v 1.4 2001/02/09 02:06:01 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. +******************************************************************************/ + +extern void DisplayLogXtProc (); +extern void create_log_popup (); +extern void add_log_text (); diff --git a/mainwin.c b/mainwin.c new file mode 100644 index 0000000..ac317d6 --- /dev/null +++ b/mainwin.c @@ -0,0 +1,135 @@ +/* $Xorg: mainwin.c,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include "xsm.h" +#include "info.h" +#include "save.h" +#include "log.h" + +#include <X11/Shell.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/Command.h> +#include <X11/Xaw/SimpleMenu.h> +#include <X11/Xaw/MenuButton.h> +#include <X11/Xaw/SmeBSB.h> + +Widget mainWindow; +Widget clientInfoButton; +Widget logButton; +Widget checkPointButton; +Widget shutdownButton; +Widget shutdownMenu; +Widget shutdownSave; +Widget shutdownDontSave; + + + +static void +DelMainWinAction (w, event, params, num_params) + +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; + +{ + XtCallCallbacks (shutdownSave, XtNcallback, NULL); +} + + + +void +create_main_window () + +{ + /* + * Main window + */ + + static XtActionsRec actions[] = { + {"DelMainWinAction", DelMainWinAction} + }; + + mainWindow = XtVaCreateManagedWidget ( + "mainWindow", formWidgetClass, topLevel, + NULL); + + clientInfoButton = XtVaCreateManagedWidget ( + "clientInfoButton", commandWidgetClass, mainWindow, + XtNfromHoriz, NULL, + XtNfromVert, NULL, + XtNresizable, True, + XtNjustify, XtJustifyLeft, + NULL); + + XtAddCallback (clientInfoButton, XtNcallback, ClientInfoXtProc, 0); + + logButton = XtVaCreateManagedWidget ( + "logButton", commandWidgetClass, mainWindow, + XtNfromHoriz, clientInfoButton, + XtNfromVert, NULL, + XtNresizable, True, + XtNjustify, XtJustifyLeft, + NULL); + + XtAddCallback (logButton, XtNcallback, DisplayLogXtProc, 0); + + checkPointButton = XtVaCreateManagedWidget ( + "checkPointButton", commandWidgetClass, mainWindow, + XtNfromHoriz, NULL, + XtNfromVert, clientInfoButton, + XtNresizable, True, + XtNjustify, XtJustifyLeft, + NULL); + + XtAddCallback (checkPointButton, XtNcallback, CheckPointXtProc, 0); + + shutdownButton = XtVaCreateManagedWidget ( + "shutdownButton", menuButtonWidgetClass, mainWindow, + XtNmenuName, "shutdownMenu", + XtNfromHoriz, checkPointButton, + XtNfromVert, clientInfoButton, + XtNresizable, True, + XtNjustify, XtJustifyLeft, + NULL); + + shutdownMenu = XtVaCreatePopupShell ( + "shutdownMenu", simpleMenuWidgetClass, mainWindow, + NULL); + + shutdownSave = XtVaCreateManagedWidget ( + "shutdownSave", smeBSBObjectClass, shutdownMenu, + NULL); + + shutdownDontSave = XtVaCreateManagedWidget ( + "shutdownDontSave", smeBSBObjectClass, shutdownMenu, + NULL); + + XtAddCallback (shutdownSave, XtNcallback, ShutdownSaveXtProc, 0); + XtAddCallback (shutdownDontSave, XtNcallback, ShutdownDontSaveXtProc, 0); + + XtAppAddActions (appContext, actions, XtNumber (actions)); +} diff --git a/mainwin.h b/mainwin.h new file mode 100644 index 0000000..54063b9 --- /dev/null +++ b/mainwin.h @@ -0,0 +1,27 @@ +/* $Xorg: mainwin.h,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +extern void create_main_window (); @@ -0,0 +1,157 @@ +/* $Xorg: misc.c,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include "xsm.h" + + +#ifdef NOPUTENV +/* + * define our own putenv() if the system doesn't have one. + * putenv(s): place s (a string of the form "NAME=value") in + * the environment; replacing any existing NAME. s is placed in + * environment, so if you change s, the environment changes (like + * putenv on a sun). Binding removed if you putenv something else + * called NAME. + */ +int +putenv(s) + char *s; +{ + char *v; + int varlen, idx; + extern char **environ; + char **newenv; + static int virgin = 1; /* true while "environ" is a virgin */ + + v = strchr(s, '='); + if(v == 0) + return 0; /* punt if it's not of the right form */ + varlen = (v + 1) - s; + + for (idx = 0; environ[idx] != 0; idx++) { + if (strncmp(environ[idx], s, varlen) == 0) { + if(v[1] != 0) { /* true if there's a value */ + environ[idx] = s; + return 0; + } else { + do { + environ[idx] = environ[idx+1]; + } while(environ[++idx] != 0); + return 0; + } + } + } + + /* add to environment (unless no value; then just return) */ + if(v[1] == 0) + return 0; + if(virgin) { + register i; + + newenv = (char **) XtMalloc((unsigned) ((idx + 2) * sizeof(char*))); + if(newenv == 0) + return -1; + for(i = idx-1; i >= 0; --i) + newenv[i] = environ[i]; + virgin = 0; /* you're not a virgin anymore, sweety */ + } else { + newenv = (char **) realloc((char *) environ, + (unsigned) ((idx + 2) * sizeof(char*))); + if (newenv == 0) + return -1; + } + + environ = newenv; + environ[idx] = s; + environ[idx+1] = 0; + + return 0; +} + +#endif /* NOPUTENV */ + + + +strbw (a, b) + +char *a; +char *b; + +{ + return !strncmp (a, b, strlen (b)); +} + + + +#ifdef X_NOT_STDC_ENV + +char *Strstr (s1, s2) + +char *s1; +char *s2; + +{ + int n1, n2; + + n1 = strlen (s1); + n2 = strlen (s2); + + for (; n1 >= n2; s1++, n1--) + { + if (!strncmp (s1, s2, n2)) + return s1; + } + + return NULL; +} + +#endif + + + +#if defined(sun) && defined(SVR4) +int System (s) + char *s; +{ + int pid, status; + if ((pid = fork ()) == 0) { + (void) setpgrp(); + execl ("/bin/sh", "sh", "-c", s, 0); + } else + waitpid (pid, &status, 0); + return status; +} +#endif + + + +nomem () + +{ + fprintf (stderr, "Insufficient memory.\n"); + exit (255); +} + @@ -0,0 +1,184 @@ +/* $Xorg: popup.c,v 1.4 2001/02/09 02:06:01 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. + +*/ + +#include "xsm.h" +#include <X11/Shell.h> + + +void +PopupPopup (parent, popup, transient, first_time, + offset_x, offset_y, delAction) + +Widget parent; +Widget popup; +Bool transient; +Bool first_time; +int offset_x; +int offset_y; +String delAction; + +{ + if (!transient && !first_time) + { + /* + * For non-transient windows, if this isn't the first time + * it's being popped up, just pop it up in the old position. + */ + + XtPopup (popup, XtGrabNone); + return; + } + else + { + Position parent_x, parent_y; + Position root_x, root_y; + Position popup_x, popup_y; + Dimension parent_width, parent_height, parent_border; + Dimension popup_width, popup_height, popup_border; + char geom[16]; + Bool repos = 0; + + /* + * The window we pop up must be visible on the screen. We first + * try to position it at the desired location (relative to the + * parent widget). Once we are able to compute the popup's + * geometry (after it's realized), we can determine if we need + * to reposition it. + */ + + XtVaGetValues (parent, + XtNx, &parent_x, + XtNy, &parent_y, + XtNwidth, &parent_width, + XtNheight, &parent_height, + XtNborderWidth, &parent_border, + NULL); + + XtTranslateCoords (parent, parent_x, parent_y, &root_x, &root_y); + + popup_x = root_x + offset_x; + popup_y = root_y + offset_y; + + if (transient) + { + XtVaSetValues (popup, + XtNx, popup_x, + XtNy, popup_y, + NULL); + } + else + { + sprintf (geom, "+%d+%d", popup_x, popup_y); + + XtVaSetValues (popup, + XtNgeometry, geom, + NULL); + } + + if (first_time) + { + /* + * Realize it for the first time + */ + + XtRealizeWidget (popup); + + + /* + * Set support for WM_DELETE_WINDOW + */ + + (void) SetWM_DELETE_WINDOW (popup, delAction); + } + + /* + * Now make sure it's visible. + */ + + XtVaGetValues (popup, + XtNwidth, &popup_width, + XtNheight, &popup_height, + XtNborderWidth, &popup_border, + NULL); + + popup_border <<= 1; + + if ((int) (popup_x + popup_width + popup_border) > + WidthOfScreen (XtScreen (topLevel))) + { + popup_x = WidthOfScreen (XtScreen (topLevel)) - + popup_width - popup_border - parent_width - parent_border; + + repos = 1; + } + + if ((int) (popup_y + popup_height + popup_border) > + HeightOfScreen (XtScreen (topLevel))) + { + popup_y = HeightOfScreen (XtScreen (topLevel)) - + popup_height - popup_border - parent_height - parent_border; + + repos = 1; + } + + if (repos) + { + if (transient) + { + XtVaSetValues (popup, + XtNx, popup_x, + XtNy, popup_y, + NULL); + } + else + { + /* + * The only way we can reposition a non-transient + * is by unrealizing it, setting the position, then + * doing a realize. + */ + + XtUnrealizeWidget (popup); + + sprintf (geom, "+%d+%d", popup_x, popup_y); + + XtVaSetValues (popup, + XtNgeometry, geom, + NULL); + + XtRealizeWidget (popup); + + (void) SetWM_DELETE_WINDOW (popup, delAction); + } + } + + XtPopup (popup, XtGrabNone); + } +} @@ -0,0 +1,31 @@ +/* $Xorg: popup.h,v 1.4 2001/02/09 02:06:01 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. + +*/ + +extern void PopupPopup (); diff --git a/printhex.c b/printhex.c new file mode 100644 index 0000000..b411f9e --- /dev/null +++ b/printhex.c @@ -0,0 +1,81 @@ +/* $Xorg: printhex.c,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include <stdio.h> + +static char *hex_table[] = { /* for printing hex digits */ + "00", "01", "02", "03", "04", "05", "06", "07", + "08", "09", "0a", "0b", "0c", "0d", "0e", "0f", + "10", "11", "12", "13", "14", "15", "16", "17", + "18", "19", "1a", "1b", "1c", "1d", "1e", "1f", + "20", "21", "22", "23", "24", "25", "26", "27", + "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", + "30", "31", "32", "33", "34", "35", "36", "37", + "38", "39", "3a", "3b", "3c", "3d", "3e", "3f", + "40", "41", "42", "43", "44", "45", "46", "47", + "48", "49", "4a", "4b", "4c", "4d", "4e", "4f", + "50", "51", "52", "53", "54", "55", "56", "57", + "58", "59", "5a", "5b", "5c", "5d", "5e", "5f", + "60", "61", "62", "63", "64", "65", "66", "67", + "68", "69", "6a", "6b", "6c", "6d", "6e", "6f", + "70", "71", "72", "73", "74", "75", "76", "77", + "78", "79", "7a", "7b", "7c", "7d", "7e", "7f", + "80", "81", "82", "83", "84", "85", "86", "87", + "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", + "90", "91", "92", "93", "94", "95", "96", "97", + "98", "99", "9a", "9b", "9c", "9d", "9e", "9f", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af", + "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", + "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf", + "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", + "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf", + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", + "d8", "d9", "da", "db", "dc", "dd", "de", "df", + "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", + "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff", +}; + + +void +fprintfhex (fp, len, cp) + +register FILE *fp; +unsigned int len; +char *cp; + +{ + unsigned char *ucp = (unsigned char *) cp; + + for (; len > 0; len--, ucp++) + { + register char *s = hex_table[*ucp]; + putc (s[0], fp); + putc (s[1], fp); + } +} @@ -0,0 +1,420 @@ +/* $Xorg: prop.c,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include "xsm.h" + +extern Widget clientListWidget; + + +void +FreePropValues (propValues) + +List *propValues; + +{ + List *pv; + PropValue *pval; + + for (pv = ListFirst (propValues); pv; pv = ListNext (pv)) + { + pval = (PropValue *) pv->thing; + XtFree ((char *) pval->value); + XtFree ((char *) pval); + } + + ListFreeAll (propValues); +} + + + +void +FreeProp (prop) + +Prop *prop; + +{ + FreePropValues (prop->values); + XtFree (prop->name); + XtFree (prop->type); + XtFree ((char *) prop); +} + + + +void +SetInitialProperties (client, props) + +ClientRec *client; +List *props; + +{ + List *pl; + + if (verbose) + printf("Setting initial properties for %s\n", client->clientId); + + if (client->props) + { + /* + * The only way client->props could be non-NULL is if the list + * was initialized, but nothing was added yet. So we just free + * the head of the list. + */ + + XtFree ((char *) client->props); + } + + client->props = props; + + for (pl = ListFirst (props); pl; pl = ListNext (pl)) + { + Prop *pprop; + PropValue *pval; + List *vl; + + pprop = (Prop *) pl->thing; + + if (strcmp (pprop->name, SmDiscardCommand) == 0) + { + if (client->discardCommand) + XtFree (client->discardCommand); + + vl = ListFirst (pprop->values); + pval = (PropValue *) vl->thing; + + client->discardCommand = (char *) XtNewString ( + (char *) pval->value); + } + else if (strcmp (pprop->name, SmRestartStyleHint) == 0) + { + int hint; + + vl = ListFirst (pprop->values); + pval = (PropValue *) vl->thing; + + hint = (int) *((char *) (pval->value)); + + if (hint == SmRestartIfRunning || hint == SmRestartAnyway || + hint == SmRestartImmediately || hint == SmRestartNever) + { + client->restartHint = hint; + } + } + } +} + + + +void +SetProperty (client, theProp, freeIt) + +ClientRec *client; +SmProp *theProp; +Bool freeIt; + +{ + List *pl; + Prop *pprop = NULL; + int found = 0, i; + + /* + * If the property exists, delete the property values. We can + * re-use the actual property header. + */ + + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + { + pprop = (Prop *) pl->thing; + + if (strcmp (theProp->name, pprop->name) == 0 && + strcmp (theProp->type, pprop->type) == 0) + { + FreePropValues (pprop->values); + found = 1; + break; + } + } + + + /* + * Add the new property + */ + + if (!found) + { + pprop = (Prop *) XtMalloc (sizeof (Prop)); + pprop->name = XtNewString (theProp->name); + pprop->type = XtNewString (theProp->type); + } + + pprop->values = ListInit (); + + for (i = 0; i < theProp->num_vals; i++) + { + PropValue *pval = (PropValue *) XtMalloc (sizeof (PropValue)); + + pval->length = theProp->vals[i].length; + pval->value = (XtPointer) XtMalloc (theProp->vals[i].length + 1); + memcpy (pval->value, theProp->vals[i].value, theProp->vals[i].length); + ((char *) pval->value)[theProp->vals[i].length] = '\0'; + + ListAddLast (pprop->values, (char *) pval); + } + + if (pl) + pl->thing = (char *) pprop; + else + ListAddLast (client->props, (char *) pprop); + + if (strcmp (theProp->name, SmDiscardCommand) == 0) + { + if (saveInProgress) + { + /* + * We are in the middle of a save yourself. We save the + * discard command we get now, and make it the current discard + * command when the save is over. + */ + + if (client->saveDiscardCommand) + XtFree (client->saveDiscardCommand); + client->saveDiscardCommand = + (char *) XtNewString (theProp->vals[0].value); + + client->receivedDiscardCommand = True; + } + else + { + if (client->discardCommand) + XtFree (client->discardCommand); + client->discardCommand = + (char *) XtNewString (theProp->vals[0].value); + } + } + else if (strcmp (theProp->name, SmRestartStyleHint) == 0) + { + int hint = (int) *((char *) (theProp->vals[0].value)); + + if (hint == SmRestartIfRunning || hint == SmRestartAnyway || + hint == SmRestartImmediately || hint == SmRestartNever) + { + client->restartHint = hint; + } + } + + if (freeIt) + SmFreeProperty (theProp); +} + + + +void +DeleteProperty (client, propname) + +ClientRec *client; +char *propname; + +{ + List *pl; + + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + { + Prop *pprop = (Prop *) pl->thing; + + if (strcmp (pprop->name, propname) == 0) + { + FreeProp (pprop); + ListFreeOne (pl); + + if (strcmp (propname, SmDiscardCommand) == 0) + { + if (client->discardCommand) + { + XtFree (client->discardCommand); + client->discardCommand = NULL; + } + + if (client->saveDiscardCommand) + { + XtFree (client->saveDiscardCommand); + client->saveDiscardCommand = NULL; + } + } + break; + } + } +} + + + +void +SetPropertiesProc (smsConn, managerData, numProps, props) + +SmsConn smsConn; +SmPointer managerData; +int numProps; +SmProp **props; + +{ + ClientRec *client = (ClientRec *) managerData; + int updateList, i; + + if (verbose) + { + printf ("Client Id = %s, received SET PROPERTIES ", client->clientId); + printf ("[Num props = %d]\n", numProps); + } + + updateList = (ListCount (client->props) == 0) && + numProps > 0 && client_info_visible; + + for (i = 0; i < numProps; i++) + { + SetProperty (client, props[i], True /* free it */); + } + + free ((char *) props); + + if (updateList) + { + /* + * We have enough info from the client to display it in our list. + */ + + UpdateClientList (); + XawListHighlight (clientListWidget, current_client_selected); + } + else if (client_prop_visible && clientListRecs && + clientListRecs[current_client_selected] == client) + { + DisplayProps (client); + } +} + + + +void +DeletePropertiesProc (smsConn, managerData, numProps, propNames) + +SmsConn smsConn; +SmPointer managerData; +int numProps; +char **propNames; + +{ + ClientRec *client = (ClientRec *) managerData; + int i; + + if (verbose) { + printf ("Client Id = %s, received DELETE PROPERTIES ", + client->clientId); + printf ("[Num props = %d]\n", numProps); + } + + for (i = 0; i < numProps; i++) + { + if (verbose) + printf (" Name: %s\n", propNames[i]); + + DeleteProperty (client, propNames[i]); + + free (propNames[i]); + } + + free ((char *) propNames); +} + + + +void +GetPropertiesProc (smsConn, managerData) + +SmsConn smsConn; +SmPointer managerData; + +{ + ClientRec *client = (ClientRec *) managerData; + SmProp **propsRet, *propRet; + SmPropValue *propValRet; + Prop *pprop; + PropValue *pval; + List *pl, *pj; + int numProps; + int index, i; + + if (verbose) + { + printf ("Client Id = %s, received GET PROPERTIES\n", client->clientId); + printf ("\n"); + } + + /* + * Unfortunately, we store the properties in a format different + * from the one required by SMlib. + */ + + numProps = ListCount (client->props); + propsRet = (SmProp **) XtMalloc (numProps * sizeof (SmProp *)); + + index = 0; + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + { + propsRet[index] = propRet = (SmProp *) XtMalloc (sizeof (SmProp)); + + pprop = (Prop *) pl->thing; + + propRet->name = XtNewString (pprop->name); + propRet->type = XtNewString (pprop->type); + propRet->num_vals = ListCount (pprop->values); + propRet->vals = propValRet = (SmPropValue *) XtMalloc ( + propRet->num_vals * sizeof (SmPropValue)); + + for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj)) + { + pval = (PropValue *) pj->thing; + + propValRet->length = pval->length; + propValRet->value = (SmPointer) XtMalloc (pval->length); + memcpy (propValRet->value, pval->value, pval->length); + + propValRet++; + } + + index++; + } + + SmsReturnProperties (smsConn, numProps, propsRet); + + if (verbose) + { + printf ("Client Id = %s, sent PROPERTIES REPLY [Num props = %d]\n", + client->clientId, numProps); + } + + for (i = 0; i < numProps; i++) + SmFreeProperty (propsRet[i]); + XtFree ((char *) propsRet); +} @@ -0,0 +1,34 @@ +/* $Xorg: prop.h,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +extern void FreePropValues (); +extern void FreeProp (); +extern void SetInitialProperties (); +extern void SetProperty (); +extern void DeleteProperty (); +extern void SetPropertiesProc (); +extern void DeletePropertiesProc (); +extern void GetPropertiesProc (); diff --git a/remote.c b/remote.c new file mode 100644 index 0000000..0b20bcc --- /dev/null +++ b/remote.c @@ -0,0 +1,259 @@ +/* $Xorg: remote.c,v 1.5 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +/* + * We use the rstart protocol to restart clients on remote machines. + */ + +#include "xsm.h" + +#include <X11/ICE/ICEutil.h> + +static char *format_rstart_env(); + +extern IceAuthDataEntry *authDataEntries; +extern int numTransports; +extern void fprintfhex (); + + +void +remote_start (restart_protocol, restart_machine, program, args, cwd, env, + non_local_display_env, non_local_session_env) + +char *restart_protocol; +char *restart_machine; +char *program; +char **args; +char *cwd; +char **env; +char *non_local_display_env; +char *non_local_session_env; + +{ + FILE *fp; + int pipefd[2]; + char msg[256]; + int i; + + if (strcmp (restart_protocol, "rstart-rsh") != 0) + { + if (verbose) + printf ("Only rstart-rsh remote execution protocol supported.\n"); + return; + } + + if (!restart_machine) + { + if (verbose) + printf ("Bad remote machine specified for remote execute.\n"); + return; + } + + if (verbose) + printf ("Attempting to restart remote client on %s\n", + restart_machine); + + if (pipe (pipefd) < 0) + { + sprintf (msg, "%s: pipe() error during remote start of %s", + Argv[0], program); + add_log_text (msg); + perror (msg); + } + else + { + switch(fork()) + { + case -1: + + sprintf (msg, "%s: fork() error during remote start of %s", + Argv[0], program); + add_log_text (msg); + perror (msg); + break; + + case 0: /* kid */ + + close (pipefd[1]); + close (0); + dup (pipefd[0]); + close (pipefd[0]); + + execlp (RSHCMD, restart_machine, "rstartd", (char *) 0); + + sprintf (msg, + "%s: execlp() of rstartd failed for remote start of %s", + Argv[0], program); + perror (msg); + /* + * TODO : We would like to send this log information to the + * log window in the parent. This would require using the + * pipe between the parent and child. The child would + * set close-on-exec. If the exec succeeds, the pipe will + * be closed. If it fails, the child can write a message + * to the parent. + */ + _exit(255); + + default: /* parent */ + + close (pipefd[0]); + fp = (FILE *) fdopen (pipefd[1], "w"); + + fprintf (fp, "CONTEXT X\n"); + fprintf (fp, "DIR %s\n", cwd); + fprintf (fp, "DETACH\n"); + + if (env) + { + /* + * The application saved its environment. + */ + + for (i = 0; env[i]; i++) + { + /* + * rstart requires that any spaces, backslashes, or + * non-printable characters inside of a string be + * represented by octal escape sequences. + */ + + char *temp = format_rstart_env (env[i]); + fprintf (fp, "MISC X %s\n", temp); + if (temp != env[i]) + XtFree (temp); + } + } + else + { + /* + * The application did not save its environment. + * The default PATH set up by rstart may not contain + * the program we want to restart. We play it safe + * and pass xsm's PATH. This will most likely contain + * the path we need. + */ + + char *path = (char *) getenv ("PATH"); + + if (path) + fprintf (fp, "MISC X PATH=%s\n", path); + } + + fprintf (fp, "MISC X %s\n", non_local_display_env); + fprintf (fp, "MISC X %s\n", non_local_session_env); + + /* + * Pass the authentication data. + * Each transport has auth data for ICE and XSMP. + * Don't pass local auth data. + */ + + for (i = 0; i < numTransports * 2; i++) + { + if (Strstr (authDataEntries[i].network_id, "local/")) + continue; + + fprintf (fp, "AUTH ICE %s \"\" %s %s ", + authDataEntries[i].protocol_name, + authDataEntries[i].network_id, + authDataEntries[i].auth_name); + + fprintfhex (fp, + authDataEntries[i].auth_data_length, + authDataEntries[i].auth_data); + + fprintf (fp, "\n"); + } + + /* + * And execute the program + */ + + fprintf (fp, "EXEC %s %s", program, program); + for (i = 1; args[i]; i++) + fprintf (fp, " %s", args[i]); + fprintf (fp, "\n\n"); + fclose (fp); + break; + } + } +} + + + +/* + * rstart requires that any spaces/backslashes/non-printable characters + * inside of a string be represented by octal escape sequences. + */ + +static char * +format_rstart_env (str) + +char *str; + +{ + int escape_count = 0, i; + char *temp = str; + + while (*temp != '\0') + { + if (!isgraph (*temp) || *temp == '\\') + escape_count++; + temp++; + } + + if (escape_count == 0) + return (str); + else + { + int len = strlen (str) + 1 + (escape_count * 3); + char *ret = (char *) XtMalloc (len); + char *ptr = ret; + + temp = str; + while (*temp != '\0') + { + if (!isgraph (*temp) || *temp == '\\') + { + char octal[3]; + sprintf (octal, "%o", *temp); + *(ptr++) = '\\'; + for (i = 0; i < (3 - (int) strlen (octal)); i++) + *(ptr++) = '0'; + strcpy (ptr, octal); + ptr += strlen (octal); + } + else + *(ptr++) = *temp; + + temp++; + } + + *ptr = '\0'; + return (ret); + } +} diff --git a/restart.c b/restart.c new file mode 100644 index 0000000..daff7eb --- /dev/null +++ b/restart.c @@ -0,0 +1,624 @@ +/* $Xorg: restart.c,v 1.5 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include "xsm.h" +#include "log.h" + +extern void remote_start (); + + +/* + * Until XSMP provides a better way to know which clients are "managers", + * we have to hard code the list. + */ + +Bool +CheckIsManager (program) + +char *program; + +{ + return (strcmp (program, "twm") == 0); +} + + + +/* + * GetRestartInfo() will determine which method should be used to + * restart a client. + * + * 'restart_service_prop' is a property set by the client, or NULL. + * The format is "remote_start_protocol/remote_start_data". An + * example is "rstart-rsh/hostname". This is a non-standard property, + * which is the whole reason we need this function in order to determine + * the restart method. The proxy uses this property to over-ride the + * 'client_host_name' from the ICE connection (the proxy is connected to + * the SM via a local connection, but the proxy may be acting as a proxy + * for a remote client). + * + * 'client_host_name' is the connection info obtained from the ICE + * connection. It's format is "transport/host_info". An example + * is "tcp/machine:port". + * + * If 'restart_service_prop' is NULL, we use 'client_host_name' to + * determine the restart method. If the transport is "local", we + * do a local restart. Otherwise, we use the default "rstart-rsh" method. + * + * If 'restart_service_prop' is non-NULL, we check the remote_start_protocol + * field. "local" means a local restart. Currently, the only remote + * protocol we recognize is "rstart-rsh". If the remote protocol is + * "rstart-rsh" but the hostname in the 'restart_service_prop' matches + * 'client_host_name', we do a local restart. + * + * On return, set the run_local flag, restart_protocol and restart_machine. + */ + +void +GetRestartInfo (restart_service_prop, client_host_name, + run_local, restart_protocol, restart_machine) + +char *restart_service_prop; +char *client_host_name; +Bool *run_local; +char **restart_protocol; +char **restart_machine; + +{ + char hostnamebuf[80]; + char *temp; + + *run_local = False; + *restart_protocol = NULL; + *restart_machine = NULL; + + if (restart_service_prop) + { + gethostname (hostnamebuf, sizeof hostnamebuf); + + if ((temp = (char *) strchr ( + restart_service_prop, '/')) == NULL) + { + *restart_protocol = (char *) XtNewString ("rstart-rsh"); + *restart_machine = (char *) XtNewString (restart_service_prop); + } + else + { + *restart_protocol = (char *) XtNewString (restart_service_prop); + (*restart_protocol)[temp - restart_service_prop] = '\0'; + *restart_machine = (char *) XtNewString (temp + 1); + } + + if (strcmp (*restart_machine, hostnamebuf) == 0 || + strcmp (*restart_protocol, "local") == 0) + { + *run_local = True; + } + } + else + { + if (strncmp (client_host_name, "tcp/", 4) != 0 && + strncmp (client_host_name, "decnet/", 7) != 0) + { + *run_local = True; + } + else + { + *restart_protocol = (char *) XtNewString ("rstart-rsh"); + + if ((temp = (char *) strchr ( + client_host_name, '/')) == NULL) + { + *restart_machine = (char *) XtNewString (client_host_name); + } + else + { + *restart_machine = (char *) XtNewString (temp + 1); + } + } + } +} + + + +/* + * Restart clients. The flag indicates RESTART_MANAGERS or + * RESTART_REST_OF_CLIENTS. + */ + +Status +Restart (flag) + +int flag; + +{ + List *cl, *pl, *vl; + PendingClient *c; + Prop *prop; + char *cwd; + char *program; + char **args; + char **env; + char **pp; + int cnt; + extern char **environ; + char *p; + char *restart_service_prop; + char *restart_protocol; + char *restart_machine; + Bool run_local; + Bool is_manager; + Bool ran_manager = 0; + + for(cl = ListFirst(PendingList); cl; cl = ListNext(cl)) { + c = (PendingClient *)cl->thing; + + if (verbose) { + printf("Restarting id '%s'...\n", c->clientId); + printf("Host = %s\n", c->clientHostname); + } + cwd = "."; + env = NULL; + program=NULL; + args=NULL; + restart_service_prop=NULL; + + is_manager = 0; + + for(pl = ListFirst(c->props); pl; pl = ListNext(pl)) { + prop = (Prop *)pl->thing; + if(!strcmp(prop->name, SmProgram)) { + vl = ListFirst(prop->values); + if(vl) program = ((PropValue *)vl->thing)->value; + if (CheckIsManager (program)) + is_manager = 1; + } else if(!strcmp(prop->name, SmCurrentDirectory)) { + vl = ListFirst(prop->values); + if(vl) cwd = ((PropValue *)vl->thing)->value; + } else if(!strcmp(prop->name, "_XC_RestartService")) { + vl = ListFirst(prop->values); + if(vl) restart_service_prop = + ((PropValue *)vl->thing)->value; + } else if(!strcmp(prop->name, SmRestartCommand)) { + cnt = ListCount(prop->values); + args = (char **)XtMalloc((cnt+1) * sizeof(char *)); + pp = args; + for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) { + *pp++ = ((PropValue *)vl->thing)->value; + } + *pp = NULL; + } else if(!strcmp(prop->name, SmEnvironment)) { + cnt = ListCount(prop->values); + env = (char **)XtMalloc((cnt+3+1) * sizeof(char *)); + pp = env; + for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) { + p = ((PropValue *)vl->thing)->value; + if((display_env && strbw(p, "DISPLAY=")) + || (session_env && strbw(p, "SESSION_MANAGER=")) + || (audio_env && strbw(p, "AUDIOSERVER=")) + ) continue; + *pp++ = p; + } + if(display_env) *pp++ = display_env; + if(session_env) *pp++ = session_env; + if(audio_env) *pp++ = audio_env; + *pp = NULL; + } + } + + if(program && args) { + char logtext[256]; + + if ((flag == RESTART_MANAGERS && !is_manager) || + (flag == RESTART_REST_OF_CLIENTS && is_manager)) + { + if(args) XtFree((char *)args); + if(env) XtFree((char *)env); + continue; + } + + if (flag == RESTART_MANAGERS && is_manager) + ran_manager = 1; + + if (verbose) { + printf("\t%s\n", program); + printf("\t"); + for(pp = args; *pp; pp++) printf("%s ", *pp); + printf("\n"); + } + + GetRestartInfo (restart_service_prop, c->clientHostname, + &run_local, &restart_protocol, &restart_machine); + + if (run_local) + { + /* + * The client is being restarted on the local machine. + */ + + sprintf (logtext, "Restarting locally : "); + for (pp = args; *pp; pp++) + { + strcat (logtext, *pp); + strcat (logtext, " "); + } + + strcat (logtext, "\n"); + add_log_text (logtext); + + switch(fork()) { + case -1: + sprintf (logtext, + "%s: Can't fork() %s", Argv[0], program); + add_log_text (logtext); + perror (logtext); + break; + case 0: /* kid */ + chdir(cwd); + if(env) environ = env; + execvp(program, args); + sprintf (logtext, "%s: Can't execvp() %s", + Argv[0], program); + perror (logtext); + /* + * TODO : We would like to send this log information to the + * log window in the parent. This would require opening + * a pipe between the parent and child. The child would + * set close-on-exec. If the exec succeeds, the pipe will + * be closed. If it fails, the child can write a message + * to the parent. + */ + _exit(255); + default: /* parent */ + break; + } + } + else if (!remote_allowed) + { + fprintf(stderr, + "Can't remote start client ID '%s': only local supported\n", + c->clientId); + } + else + { + /* + * The client is being restarted on a remote machine. + */ + + sprintf (logtext, "Restarting remotely on %s : ", + restart_machine); + for (pp = args; *pp; pp++) + { + strcat (logtext, *pp); + strcat (logtext, " "); + } + strcat (logtext, "\n"); + add_log_text (logtext); + + remote_start (restart_protocol, restart_machine, + program, args, cwd, env, + non_local_display_env, non_local_session_env); + } + + if (restart_protocol) + XtFree (restart_protocol); + + if (restart_machine) + XtFree (restart_machine); + + } else { + fprintf(stderr, "Can't restart ID '%s': no program or no args\n", + c->clientId); + } + if(args) XtFree((char *)args); + if(env) XtFree((char *)env); + } + + if (flag == RESTART_MANAGERS && !ran_manager) + return (0); + else + return (1); +} + + + +/* + * Clone a client + */ + +void +Clone (client, useSavedState) + +ClientRec *client; +Bool useSavedState; + +{ + char *cwd; + char *program; + char **args; + char **env; + char **pp; + extern char **environ; + char *p; + char *restart_service_prop; + char *restart_protocol; + char *restart_machine; + Bool run_local; + List *pl, *pj; + + if (verbose) + { + printf ("Cloning id '%s', useSavedState = %d...\n", + client->clientId, useSavedState); + printf ("Host = %s\n", client->clientHostname); + } + + cwd = "."; + env = NULL; + program = NULL; + args = NULL; + restart_service_prop = NULL; + + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + { + Prop *pprop = (Prop *) pl->thing; + List *vl = ListFirst (pprop->values); + PropValue *pval = (PropValue *) vl->thing; + + if (strcmp (pprop->name, SmProgram) == 0) + program = (char *) pval->value; + else if (strcmp (pprop->name, SmCurrentDirectory) == 0) + cwd = (char *) pval->value; + else if (strcmp (pprop->name, "_XC_RestartService") == 0) + restart_service_prop = (char *) pval->value; + else if ( + (!useSavedState && strcmp (pprop->name, SmCloneCommand) == 0) || + (useSavedState && strcmp (pprop->name, SmRestartCommand) == 0)) + { + args = (char **) XtMalloc ( + (ListCount (pprop->values) + 1) * sizeof (char *)); + + pp = args; + + for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj)) + { + pval = (PropValue *) pj->thing; + *pp++ = (char *) pval->value; + } + *pp = NULL; + } + else if (strcmp (pprop->name, SmEnvironment) == 0) + { + env = (char **) XtMalloc ( + (ListCount (pprop->values) + 3 + 1) * sizeof (char *)); + pp = env; + + for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj)) + { + pval = (PropValue *) pj->thing; + p = (char *) pval->value; + + if ((display_env && strbw (p, "DISPLAY=")) + || (session_env && strbw (p, "SESSION_MANAGER=")) + || (audio_env && strbw (p, "AUDIOSERVER="))) + continue; + + *pp++ = p; + } + + if (display_env) + *pp++ = display_env; + if (session_env) + *pp++ = session_env; + if (audio_env) + *pp++ = audio_env; + + *pp = NULL; + } + } + + if (program && args) + { + if (verbose) + { + printf("\t%s\n", program); + printf("\t"); + for (pp = args; *pp; pp++) + printf ("%s ", *pp); + printf("\n"); + } + + GetRestartInfo (restart_service_prop, client->clientHostname, + &run_local, &restart_protocol, &restart_machine); + + if (run_local) + { + /* + * The client is being cloned on the local machine. + */ + + char msg[256]; + + switch(fork()) { + case -1: + sprintf (msg, "%s: Can't fork() %s", Argv[0], program); + add_log_text (msg); + perror (msg); + break; + case 0: /* kid */ + chdir(cwd); + if(env) environ = env; + execvp(program, args); + sprintf (msg, "%s: Can't execvp() %s", Argv[0], program); + perror (msg); + /* + * TODO : We would like to send this log information to the + * log window in the parent. This would require opening + * a pipe between the parent and child. The child would + * set close-on-exec. If the exec succeeds, the pipe will + * be closed. If it fails, the child can write a message + * to the parent. + */ + _exit(255); + default: /* parent */ + break; + } + } + else if (!remote_allowed) + { + fprintf(stderr, + "Can't remote clone client ID '%s': only local supported\n", + client->clientId); + } + else + { + /* + * The client is being cloned on a remote machine. + */ + + remote_start (restart_protocol, restart_machine, + program, args, cwd, env, + non_local_display_env, non_local_session_env); + } + + if (restart_protocol) + XtFree (restart_protocol); + + if (restart_machine) + XtFree (restart_machine); + + } + else + { +#ifdef XKB + XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_Failure); +#else + XBell (XtDisplay (topLevel), 0); +#endif + + fprintf(stderr, "Can't restart ID '%s': no program or no args\n", + client->clientId); + } + + if (args) + XtFree ((char *)args); + if (env) + XtFree ((char *)env); +} + + + +void +StartDefaultApps () + +{ + FILE *f; + char *buf, *p, *home, filename[128]; + int buflen, len; + + /* + * First try ~/.xsmstartup, then system.xsm + */ + + home = (char *) getenv ("HOME"); + if (!home) + home = "."; + sprintf (filename, "%s/.xsmstartup", home); + + f = fopen (filename, "r"); + + if (!f) + { + f = fopen (SYSTEM_INIT_FILE, "r"); + if (!f) + { + printf ("Could not find default apps file. Make sure you did\n"); + printf ("a 'make install' in the xsm build directory.\n"); + exit (1); + } + } + + buf = NULL; + buflen = 0; + + while (getline(&buf, &buflen, f)) + { + char logtext[256]; + + if (buf[0] == '!') + continue; /* a comment */ + + if ((p = strchr (buf, '\n'))) + *p = '\0'; + + sprintf (logtext, "Starting locally : %s\n", buf); + add_log_text (logtext); + + len = strlen (buf); + + buf[len] = '&'; + buf[len+1] = '\0'; + + /* let the shell parse the stupid args */ + + execute_system_command (buf); + } + + if (buf) + free (buf); +} + + + +void +StartNonSessionAwareApps () + +{ + char logtext[256]; + int i; + + for (i = 0; i < non_session_aware_count; i++) + { + /* + * Let the shell parse the stupid args. We need to add an "&" + * at the end of the command. We previously allocated an extra + * byte for this. + */ + + sprintf (logtext, "Restarting locally : %s\n", + non_session_aware_clients[i]); + add_log_text (logtext); + + strcat (non_session_aware_clients[i], "&"); + execute_system_command (non_session_aware_clients[i]); + free ((char *) non_session_aware_clients[i]); + } + + if (non_session_aware_clients) + { + free ((char *) non_session_aware_clients); + non_session_aware_clients = NULL; + } +} diff --git a/restart.h b/restart.h new file mode 100644 index 0000000..6dcf553 --- /dev/null +++ b/restart.h @@ -0,0 +1,30 @@ +/* $Xorg: restart.h,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +extern void StartDefaultApps (); +extern void StartNonSessionAwareApps (); +extern Status Restart (); +extern void Clone (); @@ -0,0 +1,1529 @@ +/* $Xorg: save.c,v 1.5 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include "xsm.h" +#include "save.h" +#include "saveutil.h" +#include "popup.h" + +#include <X11/Shell.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/List.h> +#include <X11/Xaw/Command.h> +#include <X11/Xaw/Toggle.h> +#include <X11/Xaw/AsciiText.h> + + +Widget savePopup; +Widget saveForm; +Widget saveMessageLabel; +Widget saveName; +Widget saveTypeLabel; +Widget saveTypeGlobal; +Widget saveTypeLocal; +Widget saveTypeBoth; +Widget interactStyleLabel; +Widget interactStyleNone; +Widget interactStyleErrors; +Widget interactStyleAny; +Widget saveOkButton; +Widget helpSaveButton; +Widget saveCancelButton; +Widget helpPopup; +Widget helpForm; +Widget helpSaveText; +Widget helpSaveOkButton; +Widget nameInUsePopup; +Widget nameInUseForm; +Widget nameInUseLabel; +Widget nameInUseOverwriteButton; +Widget nameInUseCancelButton; +Widget badSavePopup; +Widget badSaveForm; +Widget badSaveLabel; +Widget badSaveOkButton; +Widget badSaveCancelButton; +Widget badSaveListWidget; + +extern Widget clientInfoPopup; +extern Widget clientPropPopup; +extern Widget nameSessionPopup; + +extern int checkpoint_from_signal; + +static int saveTypeData[] = { + SmSaveLocal, + SmSaveGlobal, + SmSaveBoth +}; + +static int interactStyleData[] = { + SmInteractStyleNone, + SmInteractStyleErrors, + SmInteractStyleAny +}; + +static String *failedNames = NULL; +static int numFailedNames = 0; + +static Bool help_visible = False; + +static String name_in_use = NULL; +static Bool name_locked = False; + +void SetSaveSensitivity (); + + +static void +MakeCurrentSession (new_name, name_changed) + +String new_name; +Bool name_changed; + +{ + char title[256]; + List *cl; + + if (session_name) + { + /* + * In the old session, for any client that was not restarted by the + * session manager (previous ID was NULL), if we did not issue a + * checkpoint to this client after the initial startup, remove the + * client's checkpoint file using the discard command. + */ + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + ClientRec *client = (ClientRec *) cl->thing; + + if (!client->restarted && + !client->userIssuedCheckpoint && + client->discardCommand) + { + execute_system_command (client->discardCommand); + XtFree (client->discardCommand); + client->discardCommand = NULL; + } + } + + /* + * Unlock the old session. + */ + + if (!need_to_name_session) + UnlockSession (session_name); + } + + if (name_changed) + { + if (session_name) + XtFree (session_name); + + session_name = XtNewString (new_name); + } + + LockSession (session_name, True); + + sprintf (title, "xsm: %s", session_name); + + XtVaSetValues (topLevel, + XtNtitle, title, + NULL); + + set_session_save_file_name (session_name); + + + /* + * For each client, set the DiscardCommand ptr to NULL. + * This is so when we do a checkpoint with the new session + * name, we don't wipe out the checkpoint files needed by + * the previous session. We also set the userIssuedCheckpoint + * flag to false for each client in the new session. + */ + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + ClientRec *client = (ClientRec *) cl->thing; + + client->userIssuedCheckpoint = False; + + if (client->discardCommand) + { + XtFree (client->discardCommand); + client->discardCommand = NULL; + } + } + + need_to_name_session = False; +} + + + + +#define NAME_OK 0 +#define NAME_EMPTY 1 +#define NAME_EXISTS 2 +#define NAME_LOCKED 3 + +static int +GetSaveName (nameRet) + +String *nameRet; + +{ + String new_name = NULL; + Bool name_changed; + + /* + * Get the name of the session for the save + */ + + XtVaGetValues (saveName, + XtNstring, &new_name, + NULL); + + *nameRet = new_name; + + if (!new_name || *new_name == '\0') + return (NAME_EMPTY); + + /* + * See if this is a new session. If not return. + */ + + name_changed = !session_name || + (session_name && strcmp (session_name, new_name) != 0); + + if (!need_to_name_session && !name_changed) + return (NAME_OK); + + + /* + * Make sure the session name is unique. + */ + + if (GetSessionNames (&sessionNameCount, + &sessionNamesShort, NULL, &sessionsLocked)) + { + int i, no_good = 0, locked = 0; + + for (i = 0; i < sessionNameCount; i++) + if (strcmp (new_name, sessionNamesShort[i]) == 0) + { + no_good = 1; + locked = sessionsLocked[i]; + break; + } + + FreeSessionNames (sessionNameCount, + sessionNamesShort, NULL, sessionsLocked); + + if (no_good) + return (locked ? NAME_LOCKED : NAME_EXISTS); + } + + MakeCurrentSession (new_name, name_changed); + + return (NAME_OK); +} + + +static void +GetSaveOptions (saveType, interactStyle, fast) + +int *saveType; +int *interactStyle; +Bool *fast; + +{ + XtPointer ptr; + + if (help_visible) + { + XtPopdown (helpPopup); + help_visible = 0; + } + + ptr = XawToggleGetCurrent (saveTypeLocal /* just 1 of the group */); + *saveType = *((int *) ptr); + + ptr = XawToggleGetCurrent (interactStyleNone /* just 1 of the group */); + *interactStyle = *((int *) ptr); + + *fast = False; +} + + + +DoSave (saveType, interactStyle, fast) + +int saveType; +int interactStyle; +Bool fast; + +{ + ClientRec *client; + List *cl; + char *_saveType; + char *_shutdown; + char *_interactStyle; + + if (saveType == SmSaveLocal) + _saveType = "Local"; + else if (saveType == SmSaveGlobal) + _saveType = "Global"; + else + _saveType = "Both"; + + if (wantShutdown) + _shutdown = "True"; + else + _shutdown = "False"; + + if (interactStyle == SmInteractStyleNone) + _interactStyle = "None"; + else if (interactStyle == SmInteractStyleErrors) + _interactStyle = "Errors"; + else + _interactStyle = "Any"; + + SetSaveSensitivity (False); + + saveInProgress = True; + + shutdownCancelled = False; + phase2InProgress = False; + + if (ListCount (RunningList) == 0) + FinishUpSave (); + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + SmsSaveYourself (client->smsConn, + saveType, wantShutdown, interactStyle, fast); + + ListAddLast (WaitForSaveDoneList, (char *) client); + + client->userIssuedCheckpoint = True; + client->receivedDiscardCommand = False; + + if (verbose) + { + printf ("Client Id = %s, sent SAVE YOURSELF [", client->clientId); + printf ("Save Type = %s, Shutdown = %s, ", _saveType, _shutdown); + printf ("Interact Style = %s, Fast = False]\n", _interactStyle); + } + } + + if (verbose) + { + printf ("\n"); + printf ("Sent SAVE YOURSELF to all clients. Waiting for\n"); + printf ("SAVE YOURSELF DONE, INTERACT REQUEST, or\n"); + printf ("SAVE YOURSELF PHASE 2 REQUEST from each client.\n"); + printf ("\n"); + } +} + + + +static void +SaveOkAction (w, event, params, num_params) + +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; + +{ + XtCallCallbacks (saveOkButton, XtNcallback, NULL); +} + + + +static void +DelSaveWinAction (w, event, params, num_params) + +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; + +{ + XtCallCallbacks (saveCancelButton, XtNcallback, NULL); +} + + + +static void +DelNameInUseWinAction (w, event, params, num_params) + +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; + +{ + XtCallCallbacks (nameInUseCancelButton, XtNcallback, NULL); +} + + + +static void +DelBadSaveWinAction (w, event, params, num_params) + +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; + +{ + if (XtIsManaged (badSaveCancelButton)) + XtCallCallbacks (badSaveCancelButton, XtNcallback, NULL); + else + XtCallCallbacks (badSaveOkButton, XtNcallback, NULL); +} + + + +static void +DelSaveHelpWinAction (w, event, params, num_params) + +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; + +{ + XtCallCallbacks (helpSaveOkButton, XtNcallback, NULL); +} + + + +static void +SaveOkXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + String name = NULL; + char label[256]; + int status; + static int first_time = 1; + int saveType; + int interactStyle; + Bool fast; + + if ((status = GetSaveName (&name)) != NAME_OK) + { +#ifdef XKB + XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_BadValue); +#else + XBell (XtDisplay (topLevel), 0); +#endif + + if (status == NAME_EXISTS || status == NAME_LOCKED) + { + name_in_use = name; + + if (status == NAME_LOCKED) + { + name_locked = True; + + sprintf (label, "Another session by the name '%s' is active.\nChoose another name for the session.", name); + + XtUnmanageChild (nameInUseOverwriteButton); + + XtVaSetValues (nameInUseCancelButton, + XtNlabel, "OK", + XtNfromHoriz, NULL, + NULL); + } + else + { + name_locked = False; + + sprintf (label, "Another session by the name '%s' already exists.\nWould you like to overwrite it?", name); + + XtManageChild (nameInUseOverwriteButton); + + XtVaSetValues (nameInUseCancelButton, + XtNlabel, "Cancel", + XtNfromHoriz, nameInUseOverwriteButton, + NULL); + } + + XtVaSetValues (nameInUseLabel, + XtNlabel, label, + NULL); + + XtPopdown (savePopup); + + PopupPopup (mainWindow, nameInUsePopup, + True, first_time, 25, 100, "DelNameInUseWinAction()"); + + if (first_time) + first_time = 0; + } + + return; + } + + GetSaveOptions (&saveType, &interactStyle, &fast); + DoSave (saveType, interactStyle, fast); +} + + + +void +LetClientInteract (cl) + +List *cl; + +{ + ClientRec *client = (ClientRec *) cl->thing; + + SmsInteract (client->smsConn); + + ListSearchAndFreeOne (WaitForInteractList, (char *) client); + + if (verbose) + { + printf ("Client Id = %s, sent INTERACT\n", client->clientId); + } +} + + + +void +StartPhase2 () + +{ + List *cl; + + if (verbose) + { + printf ("\n"); + printf ("Starting PHASE 2 of SAVE YOURSELF\n"); + printf ("\n"); + } + + for (cl = ListFirst (WaitForPhase2List); cl; cl = ListNext (cl)) + { + ClientRec *client = (ClientRec *) cl->thing; + + SmsSaveYourselfPhase2 (client->smsConn); + + if (verbose) + { + printf ("Client Id = %s, sent SAVE YOURSELF PHASE 2", + client->clientId); + } + } + + ListFreeAllButHead (WaitForPhase2List); + + phase2InProgress = True; +} + + +void +FinishUpSave () + +{ + ClientRec *client; + List *cl; + + if (verbose) + { + printf ("\n"); + printf ("All clients issued SAVE YOURSELF DONE\n"); + printf ("\n"); + } + + saveInProgress = False; + phase2InProgress = False; + + /* + * Now execute discard commands + */ + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + if (!client->receivedDiscardCommand) + continue; + + if (client->discardCommand) + { + execute_system_command (client->discardCommand); + XtFree (client->discardCommand); + client->discardCommand = NULL; + } + + if (client->saveDiscardCommand) + { + client->discardCommand = client->saveDiscardCommand; + client->saveDiscardCommand = NULL; + } + } + + + /* + * Write the save file + */ + + WriteSave (sm_id); + + + if (wantShutdown && shutdownCancelled) + { + shutdownCancelled = False; + } + else if (wantShutdown) + { + if (ListCount (RunningList) == 0) + EndSession (0); + + shutdownInProgress = True; + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + SmsDie (client->smsConn); + + if (verbose) + { + printf ("Client Id = %s, sent DIE\n", client->clientId); + } + } + } + else + { + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + SmsSaveComplete (client->smsConn); + + if (verbose) + { + printf ("Client Id = %s, sent SAVE COMPLETE\n", + client->clientId); + } + } + } + + if (!shutdownInProgress) + { + XtPopdown (savePopup); + SetAllSensitive (1); + if (checkpoint_from_signal) + checkpoint_from_signal = False; + } +} + + + +static void +SaveCancelXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + XtPopdown (savePopup); + + if (help_visible) + { + XtPopdown (helpPopup); + help_visible = 0; + } + + SetAllSensitive (1); +} + + + +/* + * Add toggle button + */ + +static Widget +AddToggle (widgetName, parent, state, radioGroup, radioData, + fromHoriz, fromVert) + +char *widgetName; +Widget parent; +int state; +Widget radioGroup; +XtPointer radioData; +Widget fromHoriz; +Widget fromVert; + +{ + Widget toggle; + + toggle = XtVaCreateManagedWidget ( + widgetName, toggleWidgetClass, parent, + XtNstate, state, + XtNradioGroup, radioGroup, + XtNradioData, radioData, + XtNfromHoriz, fromHoriz, + XtNfromVert, fromVert, + NULL); + + return (toggle); +} + + + +void +SetSaveSensitivity (on) + +Bool on; + +{ + XtSetSensitive (savePopup, on); + +#if 0 + /* + * When we turn of sensitivity in the save dialog, we want to keep + * the cancel button sensitive (so the user can cancel in case of + * a problem). Unfortunately, we can not turn off the sensitivity on + * the save popup, and then just turn on sensitivity for the cancel + * button. We must do each widget individually. + */ + + XtSetSensitive (saveTypeLabel, on); + XtSetSensitive (saveTypeGlobal, on); + XtSetSensitive (saveTypeLocal, on); + XtSetSensitive (saveTypeBoth, on); + XtSetSensitive (interactStyleLabel, on); + XtSetSensitive (interactStyleNone, on); + XtSetSensitive (interactStyleErrors, on); + XtSetSensitive (interactStyleAny, on); + XtSetSensitive (saveOkButton, on); +#endif +} + + + +void +SavePopupStructureNotifyXtHandler (w, closure, event, continue_to_dispatch) + +Widget w; +XtPointer closure; +XEvent *event; +Boolean *continue_to_dispatch; + +{ + if (event->type == MapNotify) + { + /* + * Now that the Save Dialog is back up, we can do the save. + */ + + int saveType; + int interactStyle; + Bool fast; + + if (name_locked) + { + /* Force shutdown */ + } + + DeleteSession (name_in_use); + + MakeCurrentSession (name_in_use, True); + + name_in_use = NULL; + + GetSaveOptions (&saveType, &interactStyle, &fast); + DoSave (saveType, interactStyle, fast); + + XtRemoveEventHandler (savePopup, StructureNotifyMask, False, + SavePopupStructureNotifyXtHandler, NULL); + } +} + + + +static void +NameInUseOverwriteXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + if (name_locked) + { + /* force shutdown not implemented yet */ + + return; + } + + XtPopdown (nameInUsePopup); + + /* + * We want to popup the Save dialog again. In order to avoid a race + * condition with the BadSave handler trying to pop down the Save Dialog, + * we wait for the MapNotify on the Save dialog, and then do the save. + */ + + XtAddEventHandler (savePopup, StructureNotifyMask, False, + SavePopupStructureNotifyXtHandler, NULL); + + XtPopup (savePopup, XtGrabNone); +} + + + +static void +NameInUseCancelXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + XtPopdown (nameInUsePopup); + XtPopup (savePopup, XtGrabNone); + + name_in_use = NULL; +} + + + +static void +BadSaveOkXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + ListFreeAllButHead (FailedSaveList); + XtPopdown (badSavePopup); + FinishUpSave (); +} + + + +static void +BadSaveCancelXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + ListFreeAllButHead (FailedSaveList); + XtPopdown (badSavePopup); + + if (wantShutdown) + { + List *cl; + + shutdownCancelled = True; + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + ClientRec *client = (ClientRec *) cl->thing; + + SmsShutdownCancelled (client->smsConn); + + if (verbose) + { + printf ("Client Id = %s, sent SHUTDOWN CANCELLED\n", + client->clientId); + } + } + } + + FinishUpSave (); +} + + + +static void +BadSaveListXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + +} + + + +static void +HelpSaveXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + static int first_time = 1; + + if (help_visible) + { + /* Make sure it is visible */ + + XMapRaised (XtDisplay (topLevel), XtWindow (helpPopup)); + } + else + { + PopupPopup (savePopup, helpPopup, + True, first_time, 50, 50, "DelSaveHelpWinAction()"); + + help_visible = 1; + + if (first_time) + first_time = 0; + } +} + + + +static void +HelpSaveOkXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + XtPopdown (helpPopup); + help_visible = 0; +} + + + +void +create_save_popup () + +{ + XtTranslations translations; + + static XtActionsRec actions[] = { + {"SaveOkAction", SaveOkAction}, + {"DelSaveWinAction", DelSaveWinAction}, + {"DelNameInUseWinAction", DelNameInUseWinAction}, + {"DelBadSaveWinAction", DelBadSaveWinAction}, + {"DelSaveHelpWinAction", DelSaveHelpWinAction} + }; + + + /* + * Pop up for Save Yourself button. + */ + + savePopup = XtVaCreatePopupShell ( + "savePopup", transientShellWidgetClass, topLevel, + XtNallowShellResize, True, + NULL); + + saveForm = XtCreateManagedWidget ( + "saveForm", formWidgetClass, savePopup, NULL, 0); + + saveMessageLabel = XtVaCreateManagedWidget ( + "saveMessageLabel", labelWidgetClass, saveForm, + XtNfromHoriz, NULL, + XtNfromVert, NULL, + XtNborderWidth, 0, + NULL); + + saveName = XtVaCreateManagedWidget ( + "saveName", asciiTextWidgetClass, saveForm, + XtNfromVert, NULL, + XtNeditType, XawtextEdit, + XtNresizable, True, + XtNresize, XawtextResizeWidth, + NULL); + + saveTypeLabel = XtVaCreateManagedWidget ( + "saveTypeLabel", labelWidgetClass, saveForm, + XtNfromHoriz, NULL, + XtNfromVert, saveMessageLabel, + XtNborderWidth, 0, + XtNvertDistance, 20, + NULL); + + saveTypeLocal = AddToggle ( + "saveTypeLocal", /* widgetName */ + saveForm, /* parent */ + 0, /* state */ + NULL, /* radioGroup */ + (XtPointer) &saveTypeData[0], /* radioData */ + saveTypeLabel, /* fromHoriz */ + saveMessageLabel /* fromVert */ + ); + + saveTypeGlobal = AddToggle ( + "saveTypeGlobal", /* widgetName */ + saveForm, /* parent */ + 0, /* state */ + saveTypeLocal, /* radioGroup */ + (XtPointer) &saveTypeData[1], /* radioData */ + saveTypeLocal, /* fromHoriz */ + saveMessageLabel /* fromVert */ + ); + + saveTypeBoth = AddToggle ( + "saveTypeBoth", /* widgetName */ + saveForm, /* parent */ + 1, /* state */ + saveTypeLocal, /* radioGroup */ + (XtPointer) &saveTypeData[2], /* radioData */ + saveTypeGlobal, /* fromHoriz */ + saveMessageLabel /* fromVert */ + ); + + + XtVaSetValues (saveName, XtNfromHoriz, saveTypeLabel, NULL); + XtVaSetValues (saveTypeLocal, XtNvertDistance, 20, NULL); + XtVaSetValues (saveTypeGlobal, XtNvertDistance, 20, NULL); + XtVaSetValues (saveTypeBoth, XtNvertDistance, 20, NULL); + + interactStyleLabel = XtVaCreateManagedWidget ( + "interactStyleLabel", labelWidgetClass, saveForm, + XtNfromHoriz, NULL, + XtNfromVert, saveTypeLabel, + XtNborderWidth, 0, + NULL); + + interactStyleNone = AddToggle ( + "interactStyleNone", /* widgetName */ + saveForm, /* parent */ + 0, /* state */ + NULL, /* radioGroup */ + (XtPointer) &interactStyleData[0], /* radioData */ + saveTypeLabel, /* fromHoriz */ + saveTypeLabel /* fromVert */ + ); + + interactStyleErrors = AddToggle ( + "interactStyleErrors", /* widgetName */ + saveForm, /* parent */ + 0, /* state */ + interactStyleNone, /* radioGroup */ + (XtPointer) &interactStyleData[1], /* radioData */ + interactStyleNone, /* fromHoriz */ + saveTypeLabel /* fromVert */ + ); + + interactStyleAny = AddToggle ( + "interactStyleAny", /* widgetName */ + saveForm, /* parent */ + 1, /* state */ + interactStyleNone, /* radioGroup */ + (XtPointer) &interactStyleData[2], /* radioData */ + interactStyleErrors, /* fromHoriz */ + saveTypeLabel /* fromVert */ + ); + + + saveOkButton = XtVaCreateManagedWidget ( + "saveOkButton", commandWidgetClass, saveForm, + XtNfromHoriz, NULL, + XtNfromVert, interactStyleLabel, + XtNvertDistance, 20, + XtNresizable, True, + NULL); + + XtAddCallback (saveOkButton, XtNcallback, SaveOkXtProc, 0); + + + helpSaveButton = XtVaCreateManagedWidget ( + "helpSaveButton", commandWidgetClass, saveForm, + XtNfromHoriz, saveOkButton, + XtNfromVert, interactStyleLabel, + XtNvertDistance, 20, + NULL); + + XtAddCallback (helpSaveButton, XtNcallback, HelpSaveXtProc, 0); + + + saveCancelButton = XtVaCreateManagedWidget ( + "saveCancelButton", commandWidgetClass, saveForm, + XtNfromHoriz, helpSaveButton, + XtNfromVert, interactStyleLabel, + XtNvertDistance, 20, + NULL); + + XtAddCallback (saveCancelButton, XtNcallback, SaveCancelXtProc, 0); + + XtSetKeyboardFocus (saveForm, saveName); + + XtAppAddActions (appContext, actions, XtNumber (actions)); + + translations = XtParseTranslationTable + ("<Key>Return: SaveOkAction()\n"); + XtOverrideTranslations(saveName, translations); + + XtInstallAllAccelerators (saveForm, saveForm); + + + /* + * Pop up when user tries to save the session under an + * already used name. + */ + + nameInUsePopup = XtVaCreatePopupShell ( + "nameInUsePopup", transientShellWidgetClass, topLevel, + XtNallowShellResize, True, + NULL); + + + nameInUseForm = XtVaCreateManagedWidget ( + "nameInUseForm", formWidgetClass, nameInUsePopup, + NULL); + + nameInUseLabel = XtVaCreateManagedWidget ( + "nameInUseLabel", labelWidgetClass, nameInUseForm, + XtNresizable, True, + XtNfromHoriz, NULL, + XtNfromVert, NULL, + XtNborderWidth, 0, + XtNtop, XawChainTop, + XtNbottom, XawChainTop, + NULL); + + nameInUseOverwriteButton = XtVaCreateManagedWidget ( + "nameInUseOverwriteButton", commandWidgetClass, nameInUseForm, + XtNfromHoriz, NULL, + XtNfromVert, nameInUseLabel, + XtNtop, XawChainBottom, + XtNbottom, XawChainBottom, + NULL); + + XtAddCallback (nameInUseOverwriteButton, XtNcallback, + NameInUseOverwriteXtProc, 0); + + + nameInUseCancelButton = XtVaCreateManagedWidget ( + "nameInUseCancelButton", commandWidgetClass, nameInUseForm, + XtNresizable, True, + XtNfromHoriz, nameInUseOverwriteButton, + XtNfromVert, nameInUseLabel, + XtNtop, XawChainBottom, + XtNbottom, XawChainBottom, + NULL); + + XtAddCallback (nameInUseCancelButton, XtNcallback, + NameInUseCancelXtProc, 0); + + + /* + * Pop up for help. + */ + + helpPopup = XtVaCreatePopupShell ( + "helpPopup", transientShellWidgetClass, topLevel, + NULL); + + + helpForm = XtVaCreateManagedWidget ( + "helpForm", formWidgetClass, helpPopup, + NULL); + + helpSaveText = XtVaCreateManagedWidget ( + "helpSaveText", labelWidgetClass, helpForm, + XtNfromHoriz, NULL, + XtNfromVert, NULL, + XtNtop, XawChainTop, + XtNbottom, XawChainTop, + NULL); + + helpSaveOkButton = XtVaCreateManagedWidget ( + "helpSaveOkButton", commandWidgetClass, helpForm, + XtNfromHoriz, NULL, + XtNfromVert, helpSaveText, + XtNtop, XawChainBottom, + XtNbottom, XawChainBottom, + XtNvertDistance, 20, + NULL); + + XtAddCallback (helpSaveOkButton, XtNcallback, + HelpSaveOkXtProc, 0); + + + /* + * Pop up when not all clients returned SaveSuccess + */ + + badSavePopup = XtVaCreatePopupShell ( + "badSavePopup", transientShellWidgetClass, topLevel, + XtNallowShellResize, True, + NULL); + + + badSaveForm = XtVaCreateManagedWidget ( + "badSaveForm", formWidgetClass, badSavePopup, + NULL); + + badSaveLabel = XtVaCreateManagedWidget ( + "badSaveLabel", labelWidgetClass, badSaveForm, + XtNfromHoriz, NULL, + XtNfromVert, NULL, + XtNborderWidth, 0, + XtNtop, XawChainTop, + XtNbottom, XawChainTop, + NULL); + + badSaveListWidget = XtVaCreateManagedWidget ( + "badSaveListWidget", listWidgetClass, badSaveForm, + XtNresizable, True, + XtNdefaultColumns, 1, + XtNforceColumns, True, + XtNfromHoriz, NULL, + XtNfromVert, badSaveLabel, + XtNtop, XawChainTop, + XtNbottom, XawChainBottom, + NULL); + + XtAddCallback (badSaveListWidget, XtNcallback, BadSaveListXtProc, 0); + + badSaveOkButton = XtVaCreateManagedWidget ( + "badSaveOkButton", commandWidgetClass, badSaveForm, + XtNfromHoriz, NULL, + XtNfromVert, badSaveListWidget, + XtNtop, XawChainBottom, + XtNbottom, XawChainBottom, + NULL); + + XtAddCallback (badSaveOkButton, XtNcallback, BadSaveOkXtProc, 0); + + + badSaveCancelButton = XtVaCreateManagedWidget ( + "badSaveCancelButton", commandWidgetClass, badSaveForm, + XtNfromHoriz, badSaveOkButton, + XtNfromVert, badSaveListWidget, + XtNtop, XawChainBottom, + XtNbottom, XawChainBottom, + NULL); + + XtAddCallback (badSaveCancelButton, XtNcallback, BadSaveCancelXtProc, 0); + + XtInstallAllAccelerators (badSaveForm, badSaveForm); +} + + + +void +PopupSaveDialog () + +{ + static int first_time = 1; + + XtSetSensitive (mainWindow, 0); + XtSetSensitive (clientInfoPopup, 0); + XtSetSensitive (clientPropPopup, 0); + + XawToggleSetCurrent (saveTypeBoth, + (XtPointer) &saveTypeData[2]); + XawToggleSetCurrent (interactStyleAny, + (XtPointer) &interactStyleData[2]); + + XtVaSetValues (savePopup, + XtNtitle, wantShutdown ? "Shutdown" : "Checkpoint", + NULL); + + XtVaSetValues (saveName, + XtNstring, need_to_name_session ? "" : session_name, + NULL); + + XtVaSetValues (saveOkButton, + XtNlabel, wantShutdown ? "Shutdown" : "Checkpoint", + NULL); + + PopupPopup (mainWindow, savePopup, + True, first_time, 25, 100, "DelSaveWinAction()"); + + if (first_time) + first_time = 0; +} + + + + +void +CheckPointXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + wantShutdown = False; + PopupSaveDialog (); +} + + + + +void +ShutdownSaveXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + wantShutdown = True; + PopupSaveDialog (); +} + + + +void +PopupBadSave () + +{ + ClientRec *client; + char *progName, *hostname, *tmp1, *tmp2; + String clientInfo; + int maxlen1, maxlen2; + char extraBuf1[80], extraBuf2[80]; + char *restart_service_prop; + List *cl, *pl; + int i, k; + static int first_time = 1; + + if (failedNames) + { + /* + * Free the previous list of names. Xaw doesn't make a copy of + * our list, so we need to keep it around. + */ + + for (i = 0; i < numFailedNames; i++) + XtFree (failedNames[i]); + + XtFree ((char *) failedNames); + + failedNames = NULL; + } + + maxlen1 = maxlen2 = 0; + numFailedNames = 0; + + for (cl = ListFirst (FailedSaveList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + progName = NULL; + restart_service_prop = NULL; + + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + { + Prop *pprop = (Prop *) pl->thing; + List *vl = ListFirst (pprop->values); + PropValue *pval = (PropValue *) vl->thing; + + if (strcmp (pprop->name, SmProgram) == 0) + { + progName = (char *) GetProgramName ((char *) pval->value); + + if ((int) strlen (progName) > maxlen1) + maxlen1 = strlen (progName); + } + else if (strcmp (pprop->name, "_XC_RestartService") == 0) + { + restart_service_prop = (char *) pval->value; + } + } + + if (!progName) + continue; + + if (restart_service_prop) + tmp1 = restart_service_prop; + else if (client->clientHostname) + tmp1 = client->clientHostname; + else + continue; + + if ((tmp2 = (char *) strchr (tmp1, '/')) == NULL) + hostname = tmp1; + else + hostname = tmp2 + 1; + + if ((int) strlen (hostname) > maxlen2) + maxlen2 = strlen (hostname); + + numFailedNames++; + } + + failedNames = (String *) XtMalloc ( + numFailedNames * sizeof (String)); + + i = 0; + for (cl = ListFirst (FailedSaveList); cl; cl = ListNext (cl)) + { + ClientRec *client = (ClientRec *) cl->thing; + int extra1, extra2; + + progName = NULL; + restart_service_prop = NULL; + + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + { + Prop *pprop = (Prop *) pl->thing; + List *vl = ListFirst (pprop->values); + PropValue *pval = (PropValue *) vl->thing; + + if (strcmp (pprop->name, SmProgram) == 0) + { + progName = (char *) GetProgramName ((char *) pval->value); + } + else if (strcmp (pprop->name, "_XC_RestartService") == 0) + { + restart_service_prop = (char *) pval->value; + } + } + + if (!progName) + continue; + + if (restart_service_prop) + tmp1 = restart_service_prop; + else if (client->clientHostname) + tmp1 = client->clientHostname; + else + continue; + + if ((tmp2 = (char *) strchr (tmp1, '/')) == NULL) + hostname = tmp1; + else + hostname = tmp2 + 1; + + extra1 = maxlen1 - strlen (progName) + 5; + extra2 = maxlen2 - strlen (hostname); + + clientInfo = (String) XtMalloc (strlen (progName) + + extra1 + extra2 + 3 + strlen (hostname) + 1); + + for (k = 0; k < extra1; k++) + extraBuf1[k] = ' '; + extraBuf1[extra1] = '\0'; + + for (k = 0; k < extra2; k++) + extraBuf2[k] = ' '; + extraBuf2[extra2] = '\0'; + + sprintf (clientInfo, "%s%s (%s%s)", progName, extraBuf1, + hostname, extraBuf2); + + failedNames[i++] = clientInfo; + + if (client->freeAfterBadSavePopup) + { + FreeClient (client, True /* free props */); + } + } + + XawListChange (badSaveListWidget, + failedNames, numFailedNames, 0, True); + + XtPopdown (savePopup); + + if (wantShutdown && !shutdownCancelled) + XtManageChild (badSaveCancelButton); + else + XtUnmanageChild (badSaveCancelButton); + + PopupPopup (mainWindow, badSavePopup, + True, first_time, 25, 100, "DelBadSaveWinAction()"); + + if (first_time) + first_time = 0; +} + + + +void +ShutdownDontSaveXtProc (w, client_data, callData) + +Widget w; +XtPointer client_data; +XtPointer callData; + +{ + List *cl; + ClientRec *client; + + if (ListCount (RunningList) == 0) + EndSession (0); + + /* + * For any client that was not restarted by the session + * manager (previous ID was NULL), if we did not issue a + * checkpoint to this client, remove the client's checkpoint + * file using the discard command. + */ + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + if (!client->restarted && + !client->userIssuedCheckpoint && + client->discardCommand) + { + execute_system_command (client->discardCommand); + XtFree (client->discardCommand); + client->discardCommand = NULL; + } + } + + shutdownInProgress = True; + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + SmsDie (client->smsConn); + + if (verbose) + { + printf ("Client Id = %s, sent DIE\n", client->clientId); + } + } +} @@ -0,0 +1,35 @@ +/* $Xorg: save.h,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +extern void create_save_popup (); +extern void SetSaveSensitivity (); +extern void PopupSaveDialog (); +extern void CheckPointXtProc (); +extern void ShutdownSaveXtProc (); +extern void ShutdownDontSaveXtProc (); +extern void LetClientInteract (); +extern void StartPhase2 (); +extern void FinishUpSave (); diff --git a/saveutil.c b/saveutil.c new file mode 100644 index 0000000..04ab6bf --- /dev/null +++ b/saveutil.c @@ -0,0 +1,557 @@ +/* $Xorg: saveutil.c,v 1.5 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include "xsm.h" + +char session_save_file[PATH_MAX]; +Bool getline(); + +extern Widget manualRestartCommands; + + +void +set_session_save_file_name (session_name) + +char *session_name; + +{ + char *p; + + p = (char *) getenv ("SM_SAVE_DIR"); + if (!p) + { + p = (char *) getenv ("HOME"); + if (!p) + p = "."; + } + + strcpy (session_save_file, p); + strcat (session_save_file, "/.XSM-"); + strcat (session_save_file, session_name); +} + + + +int +ReadSave(session_name, sm_id) + +char *session_name; +char **sm_id; + +{ + char *buf; + int buflen; + char *p; + PendingClient *c; + Prop *prop; + PropValue *val; + FILE *f; + int state, i; + int version_number; + + f = fopen(session_save_file, "r"); + if(!f) { + if (verbose) + printf("No session save file.\n"); + *sm_id = NULL; + return 0; + } + if (verbose) + printf("Reading session save file...\n"); + + buf = NULL; + buflen = 0; + + /* Read version # */ + getline(&buf, &buflen, f); + if((p = strchr(buf, '\n'))) *p = '\0'; + version_number = atoi (buf); + if (version_number > SAVEFILE_VERSION) + { + if (verbose) + printf("Unsupported version number of session save file.\n"); + *sm_id = NULL; + if (buf) + free (buf); + return 0; + } + + /* Read SM's id */ + getline(&buf, &buflen, f); + if((p = strchr(buf, '\n'))) *p = '\0'; + *sm_id = XtNewString(buf); + + /* Read number of clients running in the last session */ + if (version_number >= 2) + { + getline(&buf, &buflen, f); + if((p = strchr(buf, '\n'))) *p = '\0'; + num_clients_in_last_session = atoi (buf); + } + + state = 0; + while(getline(&buf, &buflen, f)) { + if((p = strchr(buf, '\n'))) *p = '\0'; + for(p = buf; *p && isspace(*p); p++) /* LOOP */; + if(*p == '#') continue; + + if(!*p) + { + if (version_number >= 3 && + ListCount (PendingList) == num_clients_in_last_session) + { + state = 5; + break; + } + else + { + state = 0; + continue; + } + } + + if(!isspace(buf[0])) { + switch(state) { + case 0: + c = (PendingClient *)XtMalloc(sizeof *c); + if(!c) nomem(); + + c->clientId = XtNewString(p); + c->clientHostname = NULL; /* set in next state */ + + c->props = ListInit(); + if(!c->props) nomem(); + + if(!ListAddLast(PendingList, (char *)c)) nomem(); + + state = 1; + break; + + case 1: + c->clientHostname = XtNewString(p); + state = 2; + break; + + case 2: + case 4: + prop = (Prop *)XtMalloc(sizeof *prop); + if(!prop) nomem(); + + prop->name = XtNewString(p); + prop->values = ListInit(); + if(!prop->values) nomem(); + + prop->type = NULL; + + if(!ListAddLast(c->props, (char *)prop)) nomem(); + + state = 3; + break; + + case 3: + prop->type = XtNewString(p); + state = 4; + break; + + default: + fprintf(stderr, "state %d\n", state); + fprintf(stderr, + "Corrupt save file line ignored:\n%s\n", buf); + continue; + } + } else { + if (state != 4) { + fprintf(stderr, "Corrupt save file line ignored:\n%s\n", buf); + continue; + } + val = (PropValue *)XtMalloc(sizeof *val); + if(!val) nomem(); + + if (strcmp (prop->type, SmCARD8) == 0) + { + val->length = 1; + val->value = (XtPointer) XtMalloc (1); + *((char *)(val->value)) = atoi (p); + } + else + { + val->length = strlen(p); + val->value = XtNewString(p); + } + + if(!ListAddLast(prop->values, (char *)val)) nomem(); + } + } + + /* Read commands for non-session aware clients */ + + if (state == 5) + { + String strbuf; + int bufsize = 0; + + getline(&buf, &buflen, f); + if((p = strchr(buf, '\n'))) *p = '\0'; + non_session_aware_count = atoi (buf); + + if (non_session_aware_count > 0) + { + non_session_aware_clients = (char **) malloc ( + non_session_aware_count * sizeof (char *)); + + for (i = 0; i < non_session_aware_count; i++) + { + getline(&buf, &buflen, f); + if((p = strchr(buf, '\n'))) *p = '\0'; + non_session_aware_clients[i] = (char *) malloc ( + strlen (buf) + 2); + strcpy (non_session_aware_clients[i], buf); + bufsize += (strlen (buf) + 1); + } + + strbuf = (String) malloc (bufsize + 1); + strbuf[0] = '\0'; + + for (i = 0; i < non_session_aware_count; i++) + { + strcat (strbuf, non_session_aware_clients[i]); + strcat (strbuf, "\n"); + } + + XtVaSetValues (manualRestartCommands, + XtNstring, strbuf, + NULL); + + free ((char *) strbuf); + } + } + + fclose(f); + + if (buf) + free (buf); + + return 1; +} + + + +static void +SaveClient (f, client) + +FILE *f; +ClientRec *client; + +{ + List *pl; + + fprintf (f, "%s\n", client->clientId); + fprintf (f, "%s\n", client->clientHostname); + + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + { + Prop *pprop = (Prop *) pl->thing; + List *pj, *vl; + PropValue *pval; + + fprintf (f, "%s\n", pprop->name); + fprintf (f, "%s\n", pprop->type); + + if (strcmp (pprop->type, SmCARD8) == 0) + { + char *card8; + int value; + + vl = ListFirst (pprop->values); + pval = (PropValue *) vl->thing; + + card8 = pval->value; + value = *card8; + fprintf(f, "\t%d\n", value); + } + else + { + for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj)) + { + pval = (PropValue *) pj->thing; + fprintf (f, "\t%s\n", pval->value); + } + } + } + + fprintf (f, "\n"); +} + + + +void +WriteSave (sm_id) + +char *sm_id; + +{ + ClientRec *client; + FILE *f; + List *cl; + String commands; + char *p, *c; + int count; + + f = fopen (session_save_file, "w"); + + if (!f) + { + char msg[256]; + + sprintf (msg, "%s: Error creating session save file %s", + Argv[0], session_save_file); + add_log_text (msg); + perror (msg); + } + else + { + fprintf (f, "%d\n", SAVEFILE_VERSION); + fprintf (f, "%s\n", sm_id); + + count = 0; + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + if (client->restartHint != SmRestartNever) + count++; + } + count += ListCount (RestartAnywayList); + + fprintf (f, "%d\n", count); + if (count == 0) + fprintf (f, "\n"); + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + if (client->restartHint == SmRestartNever) + continue; + + SaveClient (f, client); + } + + for (cl = ListFirst (RestartAnywayList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + SaveClient (f, client); + } + + + /* Save the non-session aware clients */ + + XtVaGetValues (manualRestartCommands, + XtNstring, &commands, + NULL); + + p = c = commands; + count = 0; + + while (*p) + { + if (*p == '\n') + { + if (p != c) + count++; + c = p + 1; + } + p++; + } + if (p != c) + count++; + + fprintf (f, "%d\n", count); + + p = c = commands; + + while (*p) + { + if (*p == '\n') + { + if (p != c) + { + *p = '\0'; + fprintf (f, "%s\n", c); + *p = '\n'; + } + c = p + 1; + } + p++; + } + + if (p != c) + fprintf (f, "%s\n", c); + + fclose (f); + } +} + + + +Status +DeleteSession (session_name) + +char *session_name; + +{ + char *buf; + int buflen; + char *p, *dir; + FILE *f; + int state; + int foundDiscard; + char filename[256]; + int version_number; + + dir = (char *) getenv ("SM_SAVE_DIR"); + if (!dir) + { + dir = (char *) getenv ("HOME"); + if (!dir) + dir = "."; + } + + sprintf (filename, "%s/.XSM-%s", dir, session_name); + + f = fopen(filename, "r"); + if(!f) { + return (0); + } + + buf = NULL; + buflen = 0; + + /* Read version # */ + getline(&buf, &buflen, f); + if((p = strchr(buf, '\n'))) *p = '\0'; + version_number = atoi (buf); + if (version_number > SAVEFILE_VERSION) + { + if (verbose) + printf("Can't delete session save file - incompatible version.\n"); + if (buf) + free (buf); + return (0); + } + + /* Skip SM's id */ + getline(&buf, &buflen, f); + + /* Skip number of clients running in the last session */ + if (version_number >= 2) + getline(&buf, &buflen, f); + + state = 0; + foundDiscard = 0; + while(getline(&buf, &buflen, f)) { + if((p = strchr(buf, '\n'))) *p = '\0'; + for(p = buf; *p && isspace(*p); p++) /* LOOP */; + if(*p == '#') continue; + + if(!*p) { + state = 0; + foundDiscard = 0; + continue; + } + + if(!isspace(buf[0])) { + switch(state) { + case 0: + state = 1; + break; + + case 1: + state = 2; + break; + + case 2: + case 4: + if (strcmp (p, SmDiscardCommand) == 0) + foundDiscard = 1; + state = 3; + break; + + case 3: + state = 4; + break; + + default: + continue; + } + } else { + if (state != 4) { + continue; + } + if (foundDiscard) + { + execute_system_command (p); /* Discard Command */ + foundDiscard = 0; + } + } + } + + fclose(f); + + if (buf) + free (buf); + + return ((unlink (filename) == -1) ? 0 : 1); +} + + + +Bool +getline(pbuf, plen, f) +char **pbuf; +int *plen; +FILE *f; +{ + int c; + int i; + + i = 0; + while(1) { + if(i+2 > *plen) { + if(*plen) *plen *= 2; + else *plen = BUFSIZ; + if(*pbuf) *pbuf = (char *) realloc(*pbuf, *plen + 1); + else *pbuf = (char *) malloc(*plen + 1); + } + c = getc(f); + if(c == EOF) break; + (*pbuf)[i++] = c; + if(c == '\n') break; + } + (*pbuf)[i] = '\0'; + return i; +} diff --git a/saveutil.h b/saveutil.h new file mode 100644 index 0000000..4d8cc64 --- /dev/null +++ b/saveutil.h @@ -0,0 +1,29 @@ +/* $Xorg: saveutil.h,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +extern int ReadSave (); +extern void WriteSave (); +extern Status DeleteSession (); diff --git a/signals.c b/signals.c new file mode 100644 index 0000000..ec73792 --- /dev/null +++ b/signals.c @@ -0,0 +1,251 @@ +/* $Xorg: signals.c,v 1.4 2001/02/09 02:06:01 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. +******************************************************************************/ + +#include <X11/Xos.h> +#include <X11/Xfuncs.h> + +#include <X11/SM/SMlib.h> + +#ifdef USG +#ifndef __TYPES__ +#include <sys/types.h> /* forgot to protect it... */ +#define __TYPES__ +#endif /* __TYPES__ */ +#else +#if defined(_POSIX_SOURCE) && defined(MOTOROLA) +#undef _POSIX_SOURCE +#include <sys/types.h> +#define _POSIX_SOURCE +#else +#include <sys/types.h> +#endif +#endif /* USG */ + +#ifdef X_POSIX_C_SOURCE +#define _POSIX_C_SOURCE X_POSIX_C_SOURCE +#include <signal.h> +#include <sys/wait.h> +#undef _POSIX_C_SOURCE +#else +#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) +#include <signal.h> +#include <sys/wait.h> +#else +#define _POSIX_SOURCE +#include <signal.h> +#include <sys/wait.h> +#undef _POSIX_SOURCE +#endif +#endif + +#if defined(X_NOT_POSIX) && defined(SIGNALRETURNSINT) +#define SIGVAL int +#else +#define SIGVAL void +#endif + +#ifndef X_NOT_POSIX +#define USE_POSIX_WAIT +#endif + +#if defined(linux) || defined(SYSV) +#define USE_SYSV_SIGNALS +#endif + +#if defined(SCO) || defined(ISC) +#undef SIGTSTP /* defined, but not the BSD way */ +#endif + +#if defined(X_NOT_POSIX) && defined(SYSV) +#define SIGNALS_RESET_WHEN_CAUGHT +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int checkpoint_from_signal = 0; + +extern Bool wantShutdown; + + +SIGVAL (*Signal (sig, handler))() + int sig; + SIGVAL (*handler)(); +{ +#ifndef X_NOT_POSIX + struct sigaction sigact, osigact; + sigact.sa_handler = handler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction(sig, &sigact, &osigact); + return osigact.sa_handler; +#else + return signal(sig, handler); +#endif +} + + +void +sig_child_handler () + +{ + int pid; + +#if !defined(USE_POSIX_WAIT) && (defined(USE_SYSV_SIGNALS) && \ + (defined(CRAY) || !defined(SIGTSTP))) + wait (NULL); +#endif + +#ifdef SIGNALS_RESET_WHEN_CAUGHT + Signal (SIGCHLD, sig_child_handler); +#endif + + /* + * The wait() above must come before re-establishing the signal handler. + * In between this time, a new child might have died. If we can do + * a non-blocking wait, we can check for this race condition. If we + * don't have non-blocking wait, we lose. + */ + + do + { +#ifdef USE_POSIX_WAIT + pid = waitpid (-1, NULL, WNOHANG); +#else +#if defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) + /* cannot do non-blocking wait */ + pid = 0; +#else + union wait status; + + pid = wait3 (&status, WNOHANG, (struct rusage *)NULL); +#endif +#endif /* USE_POSIX_WAIT else */ + } + while (pid > 0); +} + + +void +sig_term_handler () + +{ + wantShutdown = 1; + checkpoint_from_signal = 1; + DoSave (SmSaveLocal, SmInteractStyleNone, 1 /* fast */); +} + + +void +sig_usr1_handler () + +{ + wantShutdown = 0; + checkpoint_from_signal = 1; + DoSave (SmSaveLocal, SmInteractStyleNone, 0 /* fast */); +} + + + +void +register_signals () + +{ + /* + * Ignore SIGPIPE + */ + + Signal (SIGPIPE, SIG_IGN); + + + /* + * If child process dies, call our handler + */ + + Signal (SIGCHLD, sig_child_handler); + + + /* + * If we get a SIGTERM, do shutdown, fast, local, no interact + */ + + Signal (SIGTERM, sig_term_handler); + + + /* + * If we get a SIGUSR1, do checkpoint, local, no interact + */ + + Signal (SIGUSR1, sig_usr1_handler); +} + + + +int +execute_system_command (s) + +char *s; + +{ + int stat; + +#ifdef X_NOT_POSIX + /* + * Non-POSIX system() uses wait(). We must disable our sig child + * handler because if it catches the signal, system() will block + * forever in wait(). + */ + + int pid; + + Signal (SIGCHLD, SIG_IGN); +#endif + + stat = system (s); + +#ifdef X_NOT_POSIX + /* + * Re-enable our sig child handler. We might have missed some signals, + * so do non-blocking waits until there are no signals left. + */ + + Signal (SIGCHLD, sig_child_handler); + +#if !(defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP))) + do + { + union wait status; + + pid = wait3 (&status, WNOHANG, (struct rusage *)NULL); + } while (pid > 0); +#endif +#endif /* X_NOT_POSIX */ + + return (stat); +} + + diff --git a/system.xsm b/system.xsm new file mode 100644 index 0000000..7b9beff --- /dev/null +++ b/system.xsm @@ -0,0 +1,4 @@ +! $Xorg: system.xsm,v 1.3 2000/08/17 19:55:06 cpqbld Exp $ +twm +smproxy +xterm @@ -0,0 +1,1397 @@ +/* $Xorg: xsm.c,v 1.7 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +/* + * X Session Manager. + * + * Authors: + * Ralph Mor, X Consortium + * Jordan Brown, Quarterdeck Office Systems + */ + +#include "xsm.h" +#include "globals.c" +#include "xtwatch.h" +#include "prop.h" +#include "choose.h" +#include "mainwin.h" +#include "info.h" +#include "log.h" +#include "save.h" +#include "auth.h" +#include "restart.h" +#include "saveutil.h" +#include "lock.h" + +#include <X11/Shell.h> +#include <X11/Xatom.h> + +Atom wmStateAtom; +Atom wmDeleteAtom; +static char *cmd_line_display = NULL; + +/* + * Forward declarations + */ + +Status StartSession (); +void NewConnectionXtProc (); +Status NewClientProc (); +void InstallIOErrorHandler (); +static void CloseListeners(void); + +/* + * Extern declarations + */ + +extern Widget clientInfoPopup; +extern Widget clientPropPopup; +extern Widget clientInfoButton; +extern Widget logButton; +extern Widget checkPointButton; +extern Widget shutdownButton; +extern Widget clientListWidget; +extern Widget savePopup; + +extern int checkpoint_from_signal; + +static IceListenObj *listenObjs; + + +/* + * Main program + */ + +main (argc, argv) + +int argc; +char **argv; + +{ + char *p; + char errormsg[256]; + static char environment_name[] = "SESSION_MANAGER"; + int success, found_command_line_name, i; + + Argc = argc; + Argv = argv; + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'd': /* -display */ + if (++i >= argc) goto usage; + cmd_line_display = (char *) XtNewString (argv[i]); + continue; + + case 's': /* -session */ + if (++i >= argc) goto usage; + session_name = XtNewString (argv[i]); + continue; + + case 'v': /* -verbose */ + verbose = 1; + continue; + } + } + + usage: + fprintf (stderr, + "usage: xsm [-display display] [-session session_name] [-verbose]\n"); + exit (1); + } + + topLevel = XtVaAppInitialize (&appContext, "XSm", NULL, 0, + &argc, argv, NULL, + XtNmappedWhenManaged, False, + XtNwindowRole, "xsm main window", + NULL); + + wmStateAtom = XInternAtom ( + XtDisplay (topLevel), "WM_STATE", False); + wmDeleteAtom = XInternAtom ( + XtDisplay (topLevel), "WM_DELETE_WINDOW", False); + + register_signals (); + + + /* + * Install an IO error handler. For an explanation, + * see the comments for InstallIOErrorHandler(). + */ + + InstallIOErrorHandler (); + + + /* + * Init SM lib + */ + + if (!SmsInitialize ("SAMPLE-SM", "1.0", + NewClientProc, NULL, + HostBasedAuthProc, 256, errormsg)) + { + fprintf (stderr, "%s\n", errormsg); + exit (1); + } + + if (!IceListenForConnections (&numTransports, &listenObjs, + 256, errormsg)) + { + fprintf (stderr, "%s\n", errormsg); + exit (1); + } + + atexit(CloseListeners); + + if (!SetAuthentication (numTransports, listenObjs, &authDataEntries)) + { + fprintf (stderr, "Could not set authorization\n"); + exit (1); + } + + InitWatchProcs (appContext); + + for (i = 0; i < numTransports; i++) + { + XtAppAddInput (appContext, + IceGetListenConnectionNumber (listenObjs[i]), + (XtPointer) XtInputReadMask, + NewConnectionXtProc, (XtPointer) listenObjs[i]); + } + + /* the sizeof includes the \0, so we don't need to count the '=' */ + networkIds = IceComposeNetworkIdList (numTransports, listenObjs); + p = (char *) XtMalloc((sizeof environment_name) + strlen(networkIds) + 1); + if(!p) nomem(); + sprintf(p, "%s=%s", environment_name, networkIds); + putenv(p); + + if (cmd_line_display) + { + /* + * If a display was passed on the command line, set the DISPLAY + * environment in this process so all applications started by + * the session manager will run on the specified display. + */ + + p = (char *) XtMalloc(8 + strlen(cmd_line_display) + 1); + sprintf(p, "DISPLAY=%s", cmd_line_display); + putenv(p); + } + + if (verbose) + printf ("setenv %s %s\n", environment_name, networkIds); + + create_choose_session_popup (); + create_main_window (); + create_client_info_popup (); + create_save_popup (); + create_log_popup (); + + + /* + * Initalize all lists + */ + + RunningList = ListInit(); + if(!RunningList) nomem(); + + PendingList = ListInit(); + if(!PendingList) nomem(); + + RestartAnywayList = ListInit(); + if(!RestartAnywayList) nomem(); + + RestartImmedList = ListInit(); + if(!RestartImmedList) nomem(); + + WaitForSaveDoneList = ListInit(); + if (!WaitForSaveDoneList) nomem(); + + FailedSaveList = ListInit(); + if (!FailedSaveList) nomem(); + + WaitForInteractList = ListInit(); + if (!WaitForInteractList) nomem(); + + WaitForPhase2List = ListInit(); + if (!WaitForPhase2List) nomem(); + + + /* + * Get list of session names. If a session name was found on the + * command line, and it is in the list of session names we got, then + * use that session name. If there were no session names found, then + * use the default session name. Otherwise, present a list of session + * names for the user to choose from. + */ + + success = GetSessionNames (&sessionNameCount, + &sessionNamesShort, &sessionNamesLong, &sessionsLocked); + + found_command_line_name = 0; + if (success && session_name) + { + for (i = 0; i < sessionNameCount; i++) + if (strcmp (session_name, sessionNamesShort[i]) == 0) + { + found_command_line_name = 1; + + if (sessionsLocked[i]) + { + fprintf (stderr, "Session '%s' is locked\n", session_name); + exit (1); + } + + break; + } + } + + if (!success || found_command_line_name) + { + FreeSessionNames (sessionNameCount, + sessionNamesShort, sessionNamesLong, sessionsLocked); + + if (!found_command_line_name) + session_name = XtNewString (DEFAULT_SESSION_NAME); + + if (!StartSession (session_name, !found_command_line_name)) + UnableToLockSession (session_name); + } + else + { + ChooseSession (); + } + + + /* + * Main loop + */ + + XtAppMainLoop (appContext); +} + + + +void +PropertyChangeXtHandler (w, closure, event, continue_to_dispatch) + +Widget w; +XtPointer closure; +XEvent *event; +Boolean *continue_to_dispatch; + +{ + if (w == topLevel && event->type == PropertyNotify && + event->xproperty.atom == wmStateAtom) + { + XtRemoveEventHandler (topLevel, PropertyChangeMask, False, + PropertyChangeXtHandler, NULL); + + /* + * Restart the rest of the session aware clients. + */ + + Restart (RESTART_REST_OF_CLIENTS); + + + /* + * Start apps that aren't session aware that were specified + * by the user. + */ + + StartNonSessionAwareApps (); + } +} + + + +void +SetWM_DELETE_WINDOW (widget, delAction) + +Widget widget; +String delAction; + +{ + char translation[64]; + + sprintf (translation, "<Message>WM_PROTOCOLS: %s", delAction); + XtOverrideTranslations (widget, XtParseTranslationTable (translation)); + + XSetWMProtocols (XtDisplay(widget), XtWindow (widget), + &wmDeleteAtom, 1); +} + + + +void +GetEnvironment () + +{ + static char envDISPLAY[]="DISPLAY"; + static char envSESSION_MANAGER[]="SESSION_MANAGER"; + static char envAUDIOSERVER[]="AUDIOSERVER"; + char *p, *temp; + + remote_allowed = 1; + + display_env = NULL; + if((p = cmd_line_display) || (p = (char *) getenv(envDISPLAY))) { + display_env = (char *) XtMalloc(strlen(envDISPLAY)+1+strlen(p)+1); + if(!display_env) nomem(); + sprintf(display_env, "%s=%s", envDISPLAY, p); + + /* + * When we restart a remote client, we have to make sure the + * display environment we give it has the SM's hostname. + */ + + if ((temp = strchr (p, '/')) == 0) + temp = p; + else + temp++; + + if (*temp != ':') + { + /* we have a host name */ + + non_local_display_env = (char *) XtMalloc ( + strlen (display_env) + 1); + if (!non_local_display_env) nomem(); + + strcpy (non_local_display_env, display_env); + } + else + { + char hostnamebuf[256]; + + gethostname (hostnamebuf, sizeof hostnamebuf); + non_local_display_env = (char *) XtMalloc ( + strlen (envDISPLAY) + 1 + + strlen (hostnamebuf) + strlen (temp) + 1); + if (!non_local_display_env) nomem(); + sprintf(non_local_display_env, "%s=%s%s", + envDISPLAY, hostnamebuf, temp); + } + } + + session_env = NULL; + if((p = (char *) getenv(envSESSION_MANAGER))) { + session_env = (char *) XtMalloc( + strlen(envSESSION_MANAGER)+1+strlen(p)+1); + if(!session_env) nomem(); + sprintf(session_env, "%s=%s", envSESSION_MANAGER, p); + + /* + * When we restart a remote client, we have to make sure the + * session environment does not have the SM's local connection port. + */ + + non_local_session_env = (char *) XtMalloc (strlen (session_env) + 1); + if (!non_local_session_env) nomem(); + strcpy (non_local_session_env, session_env); + + if ((temp = Strstr (non_local_session_env, "local/")) != NULL) + { + char *delim = strchr (temp, ','); + if (delim == NULL) + { + if (temp == non_local_session_env + + strlen (envSESSION_MANAGER) + 1) + { + *temp = '\0'; + remote_allowed = 0; + } + else + *(temp - 1) = '\0'; + } + else + { + int bytes = strlen (delim + 1); + memmove (temp, delim + 1, bytes); + *(temp + bytes) = '\0'; + } + } + } + + audio_env = NULL; + if((p = (char *) getenv(envAUDIOSERVER))) { + audio_env = (char *) XtMalloc(strlen(envAUDIOSERVER)+1+strlen(p)+1); + if(!audio_env) nomem(); + sprintf(audio_env, "%s=%s", envAUDIOSERVER, p); + } +} + + + +Status +StartSession (name, use_default) + +char *name; +Bool use_default; + +{ + int database_read = 0; + Dimension width; + char title[256]; + + + /* + * If we're not using the default session, lock it. + * If using the default session, it will be locked as + * soon as the user assigns the session a name. + */ + + if (!use_default && !LockSession (name, True)) + return (0); + + + /* + * Get important environment variables. + */ + + GetEnvironment (); + + + /* + * Set the main window's title to the session name. + */ + + sprintf (title, "xsm: %s", name); + + XtVaSetValues (topLevel, + XtNtitle, title, /* session name */ + NULL); + + XtRealizeWidget (topLevel); + + + /* + * Set WM_DELETE_WINDOW support on main window. If the user tries + * to delete the main window, the shutdown prompt will come up. + */ + + SetWM_DELETE_WINDOW (topLevel, "DelMainWinAction()"); + + + /* + * Read the session save file. Make sure the session manager + * has an SM_CLIENT_ID, so that other managers (like the WM) can + * identify it. + */ + + set_session_save_file_name (name); + + if (use_default) + need_to_name_session = True; + else + { + database_read = ReadSave (name, &sm_id); + need_to_name_session = !database_read; + } + + if (!sm_id) + { + sm_id = SmsGenerateClientID (NULL); + if (!sm_id) return (0); + } + XChangeProperty (XtDisplay (topLevel), XtWindow (topLevel), + XInternAtom (XtDisplay (topLevel), "SM_CLIENT_ID", False), + XA_STRING, 8, PropModeReplace, + (unsigned char *) sm_id, strlen (sm_id)); + + + /* + * Adjust some label widths + */ + + XtVaGetValues (clientInfoButton, + XtNwidth, &width, + NULL); + + XtVaSetValues (checkPointButton, + XtNwidth, width, + NULL); + + XtVaGetValues (logButton, + XtNwidth, &width, + NULL); + + XtVaSetValues (shutdownButton, + XtNwidth, width, + NULL); + + + XtMapWidget (topLevel); + + + if (!database_read) + { + /* + * Start default apps (e.g. twm, smproxy) + */ + + StartDefaultApps (); + } + else + { + /* + * Restart window manager first. When the session manager + * gets a WM_STATE stored on its top level window, we know + * the window manager is running. At that time, we can start + * the rest of the applications. + */ + + XtAddEventHandler (topLevel, PropertyChangeMask, False, + PropertyChangeXtHandler, NULL); + + if (!Restart (RESTART_MANAGERS)) + { + XtRemoveEventHandler (topLevel, PropertyChangeMask, False, + PropertyChangeXtHandler, NULL); + + /* + * Restart the rest of the session aware clients. + */ + + Restart (RESTART_REST_OF_CLIENTS); + + /* + * Start apps that aren't session aware that were specified + * by the user. + */ + + StartNonSessionAwareApps (); + } + } + + return (1); +} + + + +EndSession (status) + +int status; + +{ + if (verbose) + printf ("\nSESSION MANAGER GOING AWAY!\n"); + + FreeAuthenticationData (numTransports, authDataEntries); + + if (session_name) + { + UnlockSession (session_name); + XtFree (session_name); + } + + if (display_env) + XtFree (display_env); + if (session_env) + XtFree (session_env); + if (cmd_line_display) + XtFree (cmd_line_display); + if (non_local_display_env) + XtFree (non_local_display_env); + if (non_local_session_env) + XtFree (non_local_session_env); + if (audio_env) + XtFree (audio_env); + if (networkIds) + free (networkIds); + + exit (status); +} + + + +void +FreeClient (client, freeProps) + +ClientRec *client; +Bool freeProps; + +{ + if (freeProps) + { + List *pl; + + for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) + FreeProp ((Prop *) pl->thing); + + ListFreeAll (client->props); + } + + if (client->clientId) + free (client->clientId); /* malloc'd by SMlib */ + if (client->clientHostname) + free (client->clientHostname); /* malloc'd by SMlib */ + + if (client->discardCommand) + XtFree (client->discardCommand); + if (client->saveDiscardCommand) + XtFree (client->saveDiscardCommand); + + XtFree ((char *) client); +} + + + +/* + * Session Manager callbacks + */ + +Status +RegisterClientProc (smsConn, managerData, previousId) + +SmsConn smsConn; +SmPointer managerData; +char *previousId; + +{ + ClientRec *client = (ClientRec *) managerData; + char *id; + List *cl; + int send_save; + + if (verbose) + { + printf ( + "On IceConn fd = %d, received REGISTER CLIENT [Previous Id = %s]\n", + IceConnectionNumber (client->ice_conn), + previousId ? previousId : "NULL"); + printf ("\n"); + } + + if (!previousId) + { + id = SmsGenerateClientID (smsConn); + send_save = 1; + } + else + { + int found_match = 0; + send_save = 1; + + for (cl = ListFirst (PendingList); cl; cl = ListNext (cl)) + { + PendingClient *pendClient = (PendingClient *) cl->thing; + + if (!strcmp (pendClient->clientId, previousId)) + { + SetInitialProperties (client, pendClient->props); + XtFree (pendClient->clientId); + XtFree (pendClient->clientHostname); + XtFree ((char *) pendClient); + ListFreeOne (cl); + found_match = 1; + send_save = 0; + break; + } + } + + if (!found_match) + { + for (cl = ListFirst (RestartAnywayList); cl; cl = ListNext (cl)) + { + ClientRec *rClient = (ClientRec *) cl->thing; + + if (!strcmp (rClient->clientId, previousId)) + { + SetInitialProperties (client, rClient->props); + FreeClient (rClient, False /* don't free props */); + ListFreeOne (cl); + found_match = 1; + send_save = 0; + break; + } + } + } + + if (!found_match) + { + for (cl = ListFirst (RestartImmedList); cl; cl = ListNext (cl)) + { + ClientRec *rClient = (ClientRec *) cl->thing; + + if (!strcmp (rClient->clientId, previousId)) + { + SetInitialProperties (client, rClient->props); + FreeClient (rClient, False /* don't free props */); + ListFreeOne (cl); + found_match = 1; + send_save = 0; + break; + } + } + } + + if (!found_match) + { + /* + * previous-id was bogus: return bad status and the client + * should re-register with a NULL previous-id + */ + + free (previousId); + return (0); + } + else + { + id = previousId; + } + } + + SmsRegisterClientReply (smsConn, id); + + if (verbose) + { + printf ( + "On IceConn fd = %d, sent REGISTER CLIENT REPLY [Client Id = %s]\n", + IceConnectionNumber (client->ice_conn), id); + printf ("\n"); + } + + client->clientId = id; + client->clientHostname = SmsClientHostName (smsConn); + client->restarted = (previousId != NULL); + + if (send_save) + { + SmsSaveYourself (smsConn, SmSaveLocal, + False, SmInteractStyleNone, False); + } + else if (client_info_visible) + { + /* We already have all required client info */ + + UpdateClientList (); + XawListHighlight (clientListWidget, current_client_selected); + } + + return (1); +} + + + +static Bool +OkToEnterInteractPhase () + +{ + return ((ListCount (WaitForInteractList) + + ListCount (WaitForPhase2List)) == ListCount (WaitForSaveDoneList)); +} + + + +void +InteractRequestProc (smsConn, managerData, dialogType) + +SmsConn smsConn; +SmPointer managerData; +int dialogType; + +{ + ClientRec *client = (ClientRec *) managerData; + + if (verbose) + { + printf ("Client Id = %s, received INTERACT REQUEST [Dialog Type = ", + client->clientId); + if (dialogType == SmDialogError) + printf ("Error]\n"); + else if (dialogType == SmDialogNormal) + printf ("Normal]\n"); + else + printf ("Error in SMlib: should have checked for bad value]\n"); + } + + ListAddLast (WaitForInteractList, (char *) client); + + if (OkToEnterInteractPhase ()) + { + LetClientInteract (ListFirst (WaitForInteractList)); + } +} + + + +void +InteractDoneProc (smsConn, managerData, cancelShutdown) + SmsConn smsConn; + SmPointer managerData; + Bool cancelShutdown; + +{ + ClientRec *client = (ClientRec *) managerData; + List *cl; + + if (verbose) + { + printf ( + "Client Id = %s, received INTERACT DONE [Cancel Shutdown = %s]\n", + client->clientId, cancelShutdown ? "True" : "False"); + } + + if (cancelShutdown) + { + ListFreeAllButHead (WaitForInteractList); + ListFreeAllButHead (WaitForPhase2List); + } + + if (cancelShutdown) + { + if (shutdownCancelled) + { + /* Shutdown was already cancelled */ + return; + } + + shutdownCancelled = True; + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + client = (ClientRec *) cl->thing; + + SmsShutdownCancelled (client->smsConn); + + if (verbose) + { + printf ("Client Id = %s, sent SHUTDOWN CANCELLED\n", + client->clientId); + } + } + } + else + { + if ((cl = ListFirst (WaitForInteractList)) != NULL) + { + LetClientInteract (cl); + } + else + { + if (verbose) + { + printf ("\n"); + printf ("Done interacting with all clients.\n"); + printf ("\n"); + } + + if (ListCount (WaitForPhase2List) > 0) + { + StartPhase2 (); + } + } + } +} + + + +void +SaveYourselfReqProc (smsConn, managerData, saveType, + shutdown, interactStyle, fast, global) + +SmsConn smsConn; +SmPointer managerData; +int saveType; +Bool shutdown; +int interactStyle; +Bool fast; +Bool global; + +{ + if (verbose) + printf("SAVE YOURSELF REQUEST not supported!\n"); +} + + + +static Bool +OkToEnterPhase2 () + +{ + return (ListCount (WaitForPhase2List) == ListCount (WaitForSaveDoneList)); +} + + + +void +SaveYourselfPhase2ReqProc (smsConn, managerData) + +SmsConn smsConn; +SmPointer managerData; + +{ + ClientRec *client = (ClientRec *) managerData; + + if (verbose) + { + printf ("Client Id = %s, received SAVE YOURSELF PHASE 2 REQUEST\n", + client->clientId); + } + + if (!saveInProgress) + { + /* + * If we are not in the middle of a checkpoint (ie. we just + * started the client and sent the initial save yourself), just + * send the save yourself phase2 now. + */ + + SmsSaveYourselfPhase2 (client->smsConn); + } + else + { + ListAddLast (WaitForPhase2List, (char *) client); + + if (ListCount (WaitForInteractList) > 0 && OkToEnterInteractPhase ()) + { + LetClientInteract (ListFirst (WaitForInteractList)); + } + else if (OkToEnterPhase2 ()) + { + StartPhase2 (); + } + } +} + + + +void +SaveYourselfDoneProc (smsConn, managerData, success) + SmsConn smsConn; + SmPointer managerData; + Bool success; + +{ + ClientRec *client = (ClientRec *) managerData; + + if (verbose) + { + printf("Client Id = %s, received SAVE YOURSELF DONE [Success = %s]\n", + client->clientId, success ? "True" : "False"); + } + + if (!ListSearchAndFreeOne (WaitForSaveDoneList, (char *) client)) + return; + + if (!success) + { + ListAddLast (FailedSaveList, (char *) client); + } + + if (ListCount (WaitForSaveDoneList) == 0) + { + if (ListCount (FailedSaveList) > 0 && !checkpoint_from_signal) + PopupBadSave (); + else + FinishUpSave (); + } + else if (ListCount (WaitForInteractList) > 0 && OkToEnterInteractPhase ()) + { + LetClientInteract (ListFirst (WaitForInteractList)); + } + else if (ListCount (WaitForPhase2List) > 0 && OkToEnterPhase2 ()) + { + StartPhase2 (); + } +} + + + +void +CloseDownClient (client) + +ClientRec *client; + +{ + int index_deleted; + + if (verbose) { + printf ("ICE Connection closed, IceConn fd = %d\n", + IceConnectionNumber (client->ice_conn)); + printf ("\n"); + } + + SmsCleanUp (client->smsConn); + IceSetShutdownNegotiation (client->ice_conn, False); + IceCloseConnection (client->ice_conn); + + client->ice_conn = NULL; + client->smsConn = NULL; + + if (!shutdownInProgress && client_info_visible) + { + for (index_deleted = 0; + index_deleted < numClientListNames; index_deleted++) + { + if (clientListRecs[index_deleted] == client) + break; + } + } + + ListSearchAndFreeOne (RunningList, (char *) client); + + if (saveInProgress) + { + Status delStatus = ListSearchAndFreeOne ( + WaitForSaveDoneList, (char *) client); + + if (delStatus) + { + ListAddLast (FailedSaveList, (char *) client); + client->freeAfterBadSavePopup = True; + } + + ListSearchAndFreeOne (WaitForInteractList, (char *) client); + ListSearchAndFreeOne (WaitForPhase2List, (char *) client); + + if (delStatus && ListCount (WaitForSaveDoneList) == 0) + { + if (ListCount (FailedSaveList) > 0 && !checkpoint_from_signal) + PopupBadSave (); + else + FinishUpSave (); + } + else if (ListCount (WaitForInteractList) > 0 && + OkToEnterInteractPhase ()) + { + LetClientInteract (ListFirst (WaitForInteractList)); + } + else if (!phase2InProgress && + ListCount (WaitForPhase2List) > 0 && OkToEnterPhase2 ()) + { + StartPhase2 (); + } + } + + if (client->restartHint == SmRestartImmediately && !shutdownInProgress) + { + Clone (client, True /* use saved state */); + + ListAddLast (RestartImmedList, (char *) client); + } + else if (client->restartHint == SmRestartAnyway) + { + ListAddLast (RestartAnywayList, (char *) client); + } + else if (!client->freeAfterBadSavePopup) + { + FreeClient (client, True /* free props */); + } + + if (shutdownInProgress) + { + if (ListCount (RunningList) == 0) + EndSession (0); + } + else if (client_info_visible) + { + UpdateClientList (); + + if (current_client_selected == index_deleted) + { + if (current_client_selected == numClientListNames) + current_client_selected--; + + if (current_client_selected >= 0) + { + XawListHighlight (clientListWidget, current_client_selected); + ShowHint (clientListRecs[current_client_selected]); + if (client_prop_visible) + { + DisplayProps (clientListRecs[current_client_selected]); + } + } + } + else + { + if (index_deleted < current_client_selected) + current_client_selected--; + XawListHighlight (clientListWidget, current_client_selected); + } + } +} + + + + +void +CloseConnectionProc (smsConn, managerData, count, reasonMsgs) + SmsConn smsConn; + SmPointer managerData; + int count; + char **reasonMsgs; + +{ + ClientRec *client = (ClientRec *) managerData; + + if (verbose) + { + int i; + + printf ("Client Id = %s, received CONNECTION CLOSED\n", + client->clientId); + + for (i = 0; i < count; i++) + printf (" Reason string %d: %s\n", i + 1, reasonMsgs[i]); + printf ("\n"); + } + + SmFreeReasons (count, reasonMsgs); + + CloseDownClient (client); +} + + + +Status +NewClientProc (smsConn, managerData, maskRet, callbacksRet, failureReasonRet) + +SmsConn smsConn; +SmPointer managerData; +unsigned long *maskRet; +SmsCallbacks *callbacksRet; +char **failureReasonRet; + +{ + ClientRec *newClient = (ClientRec *) XtMalloc (sizeof (ClientRec)); + + *maskRet = 0; + + if (!newClient) + { + char *str = "Memory allocation failed"; + + if ((*failureReasonRet = (char *) XtMalloc (strlen (str) + 1)) != NULL) + strcpy (*failureReasonRet, str); + + return (0); + } + + newClient->smsConn = smsConn; + newClient->ice_conn = SmsGetIceConnection (smsConn); + newClient->clientId = NULL; + newClient->clientHostname = NULL; + newClient->restarted = False; /* wait till RegisterClient for true value */ + newClient->userIssuedCheckpoint = False; + newClient->receivedDiscardCommand = False; + newClient->freeAfterBadSavePopup = False; + newClient->props = ListInit (); + newClient->discardCommand = NULL; + newClient->saveDiscardCommand = NULL; + newClient->restartHint = SmRestartIfRunning; + + ListAddLast (RunningList, (char *) newClient); + + if (verbose) { + printf("On IceConn fd = %d, client set up session mngmt protocol\n\n", + IceConnectionNumber (newClient->ice_conn)); + } + + /* + * Set up session manager callbacks. + */ + + *maskRet |= SmsRegisterClientProcMask; + callbacksRet->register_client.callback = RegisterClientProc; + callbacksRet->register_client.manager_data = (SmPointer) newClient; + + *maskRet |= SmsInteractRequestProcMask; + callbacksRet->interact_request.callback = InteractRequestProc; + callbacksRet->interact_request.manager_data = (SmPointer) newClient; + + *maskRet |= SmsInteractDoneProcMask; + callbacksRet->interact_done.callback = InteractDoneProc; + callbacksRet->interact_done.manager_data = (SmPointer) newClient; + + *maskRet |= SmsSaveYourselfRequestProcMask; + callbacksRet->save_yourself_request.callback = SaveYourselfReqProc; + callbacksRet->save_yourself_request.manager_data = (SmPointer) newClient; + + *maskRet |= SmsSaveYourselfP2RequestProcMask; + callbacksRet->save_yourself_phase2_request.callback = + SaveYourselfPhase2ReqProc; + callbacksRet->save_yourself_phase2_request.manager_data = + (SmPointer) newClient; + + *maskRet |= SmsSaveYourselfDoneProcMask; + callbacksRet->save_yourself_done.callback = SaveYourselfDoneProc; + callbacksRet->save_yourself_done.manager_data = (SmPointer) newClient; + + *maskRet |= SmsCloseConnectionProcMask; + callbacksRet->close_connection.callback = CloseConnectionProc; + callbacksRet->close_connection.manager_data = (SmPointer) newClient; + + *maskRet |= SmsSetPropertiesProcMask; + callbacksRet->set_properties.callback = SetPropertiesProc; + callbacksRet->set_properties.manager_data = (SmPointer) newClient; + + *maskRet |= SmsDeletePropertiesProcMask; + callbacksRet->delete_properties.callback = DeletePropertiesProc; + callbacksRet->delete_properties.manager_data = (SmPointer) newClient; + + *maskRet |= SmsGetPropertiesProcMask; + callbacksRet->get_properties.callback = GetPropertiesProc; + callbacksRet->get_properties.manager_data = (SmPointer) newClient; + + return (1); +} + + + +/* + * Xt callback invoked when a client attempts to connect. + */ + +void +NewConnectionXtProc (client_data, source, id) + +XtPointer client_data; +int *source; +XtInputId *id; + +{ + IceConn ice_conn; + char *connstr; + IceAcceptStatus status; + + if (shutdownInProgress) + { + /* + * Don't accept new connections if we are in the middle + * of a shutdown. + */ + + return; + } + + ice_conn = IceAcceptConnection((IceListenObj) client_data, &status); + if (! ice_conn) { + if (verbose) + printf ("IceAcceptConnection failed\n"); + } else { + IceConnectStatus cstatus; + + while ((cstatus = IceConnectionStatus (ice_conn))==IceConnectPending) { + XtAppProcessEvent (appContext, XtIMAll); + } + + if (cstatus == IceConnectAccepted) { + if (verbose) { + printf ("ICE Connection opened by client, IceConn fd = %d, ", + IceConnectionNumber (ice_conn)); + connstr = IceConnectionString (ice_conn); + printf ("Accept at networkId %s\n", connstr); + free (connstr); + printf ("\n"); + } + } else { + if (verbose) + { + if (cstatus == IceConnectIOError) + printf ("IO error opening ICE Connection!\n"); + else + printf ("ICE Connection rejected!\n"); + } + + IceCloseConnection (ice_conn); + } + } +} + + + +SetAllSensitive (on) + +Bool on; + +{ + XtSetSensitive (mainWindow, on); + SetSaveSensitivity (on); + XtSetSensitive (clientInfoPopup, on); + XtSetSensitive (clientPropPopup, on); + + if (on && current_client_selected >= 0) + XawListHighlight (clientListWidget, current_client_selected); +} + + + +/* + * The real way to handle IO errors is to check the return status + * of IceProcessMessages. xsm properly does this. + * + * Unfortunately, a design flaw exists in the ICE library in which + * a default IO error handler is invoked if no IO error handler is + * installed. This default handler exits. We must avoid this. + * + * To get around this problem, we install an IO error handler that + * does a little magic. Since a previous IO handler might have been + * installed, when we install our IO error handler, we do a little + * trick to get both the previous IO error handler and the default + * IO error handler. When our IO error handler is called, if the + * previous handler is not the default handler, we call it. This + * way, everyone's IO error handler gets called except the stupid + * default one which does an exit! + */ + +static IceIOErrorHandler prev_handler; + +void +MyIoErrorHandler (ice_conn) + +IceConn ice_conn; + +{ + if (prev_handler) + (*prev_handler) (ice_conn); +} + +void +InstallIOErrorHandler () + +{ + IceIOErrorHandler default_handler; + + prev_handler = IceSetIOErrorHandler (NULL); + default_handler = IceSetIOErrorHandler (MyIoErrorHandler); + if (prev_handler == default_handler) + prev_handler = NULL; +} + +static void +CloseListeners(void) + +{ + IceFreeListenObjs (numTransports, listenObjs); +} + @@ -0,0 +1,194 @@ +/* $Xorg: xsm.h,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include <X11/Xos.h> +#include <X11/Xfuncs.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 */ + +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE +#include <stdio.h> +#undef _POSIX_SOURCE +#else +#include <stdio.h> +#endif + +#include <ctype.h> +#ifndef X_NOT_STDC_ENV +#include <stdlib.h> +#endif + +#include <X11/StringDefs.h> +#include <X11/Intrinsic.h> + +#include <X11/SM/SMlib.h> + +#include "list.h" + +/* + * Each time the format of the sm's save file changes, bump up + * the version. + */ + +#define SAVEFILE_VERSION 3 + +#define DEFAULT_SESSION_NAME "Default" +#define FAILSAFE_SESSION_NAME "Fail Safe" + +#define RESTART_MANAGERS 1 +#define RESTART_REST_OF_CLIENTS 2 + +typedef struct _ClientRec { + SmsConn smsConn; + IceConn ice_conn; + char *clientId; + char *clientHostname; + List *props; + char *discardCommand; + char *saveDiscardCommand; + + unsigned int restarted : 1; + unsigned int userIssuedCheckpoint : 1; + unsigned int restartHint : 2; + unsigned int receivedDiscardCommand : 1; + unsigned int freeAfterBadSavePopup : 1; + +} ClientRec; + +typedef struct _PendingClient { + char *clientId; + char *clientHostname; + List *props; +} PendingClient; + +typedef struct _Prop { + char *name; + char *type; + List *values; +} Prop; + +typedef struct _PropValue { + XtPointer value; + int length; +} PropValue; + + +extern int Argc; +extern char **Argv; + +extern char *display_env, *non_local_display_env; +extern char *session_env, *non_local_session_env; +extern char *audio_env; + +extern Bool need_to_name_session; + +extern Bool remote_allowed; + +extern Bool verbose; + +extern char *sm_id; + +extern char *networkIds; +extern char *session_name; + +extern List *RunningList; +extern List *PendingList; +extern List *RestartAnywayList; +extern List *RestartImmedList; + +extern List *WaitForSaveDoneList; +extern List *FailedSaveList; +extern List *WaitForInteractList; +extern List *WaitForPhase2List; + +extern Bool client_info_visible; +extern Bool client_prop_visible; +extern Bool client_log_visible; +extern String *clientListNames; +extern ClientRec **clientListRecs; +extern int numClientListNames; +extern int current_client_selected; + +extern Bool shutdownInProgress; +extern Bool phase2InProgress; +extern Bool saveInProgress; +extern Bool shutdownCancelled; +extern Bool wantShutdown; + +extern int sessionNameCount; +extern String *sessionNamesShort; +extern String *sessionNamesLong; +extern Bool *sessionsLocked; + +extern int num_clients_in_last_session; + +extern char **non_session_aware_clients; +extern int non_session_aware_count; + +extern XtAppContext appContext; +extern Widget topLevel; +extern Widget mainWindow; + +extern void fprintfhex (); + +#ifndef X_NOT_STDC_ENV +#define Strstr strstr +#else +extern char *Strstr(); +#endif + +/* Fix ISC brain damage. When using gcc fdopen isn't declared in <stdio.h>. */ +#if defined(ISC) && __STDC__ +extern FILE *fdopen(int, char const *); +#endif + +#if defined(sun) && defined(SVR4) +extern int System(); +#define system(s) System(s) +#endif + +#ifdef XKB +#include <X11/extensions/XKBbells.h> +#endif @@ -0,0 +1,343 @@ +.\" $Xorg: xsm.man,v 1.4 2001/02/09 02:06:01 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. +.TH XSM 1 "Release 6.4" "X Version 11" +.SH NAME +xsm \- X Session Manager +.SH SYNOPSIS +.B xsm +[-display display] [-session sessionName] [-verbose] +.SH DESCRIPTION +.PP +\fIxsm\fP is a session manager. A session is a group of applications, each +of which has a particular state. \fIxsm\fP allows you to create arbitrary +sessions - for example, you might have a "light" session, a "development" +session, or an "xterminal" session. Each session can have its own set of +applications. Within a session, you can perform a "checkpoint" to save +application state, or a "shutdown" to save state and exit the session. When +you log back in to the system, you can load a specific session, and you can +delete sessions you no longer want to keep. +.br +.sp +Some session managers simply allow you to manually specify a list of +applications to be started in a session. \fIxsm\fP is more powerful +because it lets you run applications and have them automatically become +part of the session. On a simple level, \fIxsm\fP is useful because it +gives you this ability to easily define which applications are in a session. +The true power of \fIxsm\fP, however, can be taken advantage of when more +and more applications learn to save and restore their state. +.SH OPTIONS +.TP 8 +.B \-display \fIdisplay\fP +Causes \fIxsm\fP to connect to the specified X display. +.TP 8 +.B \-session \fIsessionName\fP +Causes \fIxsm\fP to load the specified session, bypassing the session menu. +.TP 8 +.B \-verbose +Turns on debugging information. +.SH SETUP +.SS .xsession file +Using \fIxsm\fP requires a change to your \fI.xsession\fP file: +.PP +The last program executed by your \fI.xsession\fP file should +be \fIxsm\fP. With this configuration, when the user chooses to shut +down the session using \fIxsm\fP, the session will truly be over. +.PP +Since the goal of the session manager is to restart clients when +logging into a session, your .xsession file, in general, should not directly +start up applications. Rather, the applications should be started within +a session. When \fIxsm\fP shuts down the session, \fIxsm\fP will know to +restart these applications. Note however that there are some types of +applications that are not "session aware". \fIxsm\fP allows you to +manually add these applications to your session (see the section titled +\fIClient List\fP). +.PP +.SS SM_SAVE_DIR environment variable +If the \fISM_SAVE_DIR\fP environment variable is defined, \fIxsm\fP will +save all configuration files in this directory. Otherwise, they will be +stored in the user's home directory. Session aware applications are also +encouraged to save their checkpoint files in the \fISM_SAVE_DIR\fP directory, +although the user should not depend on this convention. +.PP +.SS Default Startup Applications +The first time \fIxsm\fP is started, it will need to locate a list of +applications to start up. For example, this list might include a window +manager, a session management proxy, and an xterm. \fIxsm\fP will first +look for the file \fI.xsmstartup\fP in the user's home directory. If that +file does not exists, it will look for the \fIsystem.xsm\fP file that was +set up at installation time. Note that \fIxsm\fP provides a "fail safe" +option when the user chooses a session to start up. The fail safe option +simply loads the default applications described above. +.PP +Each line in the startup file should contain a command to start an application. +A sample startup file might look this: +.PP +<start of file> +.br +twm +.br +smproxy +.br +xterm +.br +<end of file> +.PP +.SH STARTING A SESSION +When \fIxsm\fP starts up, it first checks to see if the user previously +saved any sessions. If no saved sessions exist, \fIxsm\fP starts up a set +of default applications (as described above in the section titled +\fIDefault Startup Applications\fP). If at least one session exists, a +session menu is presented. The \fB[-session sessionName]\fR option forces the +specified session to be loaded, bypassing the session menu. +.SS The session menu +The session menu presents the user with a list of sessions to choose from. +The user can change the currently selected session with the mouse, or by +using the up and down arrows on the keyboard. Note that sessions which are +locked (i.e. running on a different display) can not be loaded or deleted. +.PP +The following operations can be performed from the session menu: +.PP +.TP 22 +.B Load Session +Pressing this button will load the currently selected session. Alternatively, +hitting the Return key will also load the currently selected session, or the +user can double click a session from the list. +.TP 22 +.B Delete Session +This operation will delete the currently selected session, along with all +of the application checkpoint files associated with the session. After +pressing this button, the user will be asked to press the button a second +time in order to confirm the operation. +.TP 22 +.B Default/Fail Safe +\fIxsm\fP will start up a set of default applications (as described above +in the section titled \fIDefault Startup Applications\fP). This is useful +when the user wants to start a fresh session, or if the session configuration +files were corrupted and the user wants a "fail safe" session. +.TP 22 +.B Cancel +Pressing this button will cause \fIxsm\fP to exit. It can also be used to +cancel a "Delete Session" operation. +.PP +.SH CONTROLLING A SESSION +After \fIxsm\fP determines which session to load, it brings up its main +window, then starts up all applications that are part of +the session. The title bar for the session manager's main window will +contain the name of the session that was loaded. +.PP +The following options are available from \fIxsm\fP's main window: +.TP 18 +.B Client List +Pressing this button brings up a window containing a list of all clients that +are in the current session. For each client, the host machine that the client +is running on is presented. As clients are added and removed from the session, +this list is updated to reflect the changes. The user is able to control how +these clients are restarted (see below). +.br +.sp +By pressing the \fBView Properties\fR +button, the user can view the session management properties associated with +the currently selected client. +.br +.sp +By pressing the \fBClone\fR button, the user can start a copy of the selected +application. +.br +.sp +By pressing the \fBKill Client\fR button, the user can remove a client from +the session. +.br +.sp +By selecting a restart hint from the \fBRestart Hint\fR menu, the user can +control the restarting of a client. The following hints are available: +.br +.sp +.B \- +The \fBRestart If Running\fR hint indicates that the client should be +restarted in the next session if it is connected to the session manager at +the end of the current session. +.br +.sp +.B \- +The \fBRestart Anyway\fR hint indicates that the client should be restarted +in the next session even if it exits before the current session is terminated. +.br +.sp +.B \- +The \fBRestart Immediately\fR hint is similar to the \fBRestart Anyway\fR hint, +but in addition, the client is meant to run continuously. If the client exits, +the session manager will try to restart it in the current session. +.br +.sp +.B \- +The \fBRestart Never\fR hint indicates that the client should not be restarted +in the next session. +.br +.sp +Note that all X applications may not be "session aware". Applications that +are not session aware are ones that do not support the X Session Management +Protocol or they can not be detected by the Session Management Proxy (see the +section titled \fITHE PROXY\fP). \fIxsm\fP allows the user to manually add +such applications to the session. The bottom of the \fIClient List\fP window +contains a text entry field in which application commands can be typed in. +Each command should go on its own line. This information will be saved with +the session at checkpoint or shutdown time. When the session is restarted, +\fIxsm\fP will restart these applications in addition to the regular "session +aware" applications. +.br +.sp +Pressing the \fBDone\fR button removes the \fBClient List\fR window. +.TP 18 +.B Session Log... +The Session Log window presents useful information about the session. For +example, when a session is restarted, all of the restart commands will be +displayed in the log window. +.TP 18 +.B Checkpoint +By performing a checkpoint, all applications that are in the session are +asked to save their state. Not every application will save its complete +state, but at a minimum, the session manager is guaranteed that it will +receive the command required to restart the application (along with all +command line options). A window manager participating in the session +should guarantee that the applications will come back up with the same +window configurations. +.br +.sp +If the session being checkpointed was never assigned a name, the user will +be required to specify a session name. Otherwise, the user can perform the +checkpoint using the current session name, or a new session name can be +specified. If the session name specified already exists, the user will be +given the opportunity to specify a different name or to overwrite the +already existing session. Note that a session which is locked can not be +overwritten. +.br +.sp +When performing a checkpoint, the user must specify a \fBSave Type\fR +which informs the applications in the session how much state they should save. +.br +.sp +The \fBLocal\fR +type indicates that the application should save enough information to restore +the state as seen by the user. It should not affect the state as seen by +other users. For example, an editor would create a temporary file containing +the contents of its editing buffer, the location of the cursor, etc... +.br +.sp +The \fBGlobal\fR +type indicates that the application should commit all of its data to +permanent, globally accessible storage. For example, the editor would +simply save the edited file. +.br +.sp +The \fBBoth\fR +type indicates that the application should do both of these. For example, +the editor would save the edited file, then create a temporary file with +information such as the location of the cursor, etc... +.br +.sp +In addition to the \fBSave Type\fR, the user must specify an +\fBInteract Style\fR. +.br +.sp +The \fBNone\fR type indicates that the application should not interact with +the user while saving state. +.br +.sp +The \fBErrors\fR type indicates that the application may interact with +the user only if an error condition arises. +.br +.sp +The \fBAny\fR type indicates that the application may interact with +the user for any purpose. Note that \fIxsm\fP will only allow one +application to interact with the user at a time. +.br +.sp +.sp +After the checkpoint is completed, \fIxsm\fP will, if necessary, display a +window containing the list of applications which did not report a successful +save of state. +.TP 18 +.B Shutdown +A shutdown provides all of the options found in a checkpoint, but in addition, +can cause the session to exit. Note that if the interaction style is +\fBErrors\fR or \fBAny\fR, the user may cancel the shutdown. The user may +also cancel the shutdown if any of the applications report an +unsuccessful save of state. +.br +.sp +The user may choose to shutdown the session with our without performing a +checkpoint. +.PP +.SH HOW \fIXSM\fP RESPONDS TO SIGNALS +\fIxsm\fP will respond to a SIGTERM signal by performing a shutdown with +the following options: fast, no interaction, save type local. This allows +the user's session to be saved when the system is being shutdown. It can +also be used to perform a remote shutdown of a session. +.br +.sp +\fIxsm\fP will respond to a SIGUSR1 signal by performing a checkpoint with +the following options: no interaction, save type local. This signal can be +used to perform a remote checkpoint of a session. +.PP +.SH THE PROXY +Since not all applications have been ported to support the X Session +Management Protocol, a proxy service exists to allow "old" clients to +work with the session manager. In order for the proxy to detect an +application joining a session, one of the following must be true: +.br +.sp +- The application maps a top level window containing the +\fBWM_CLIENT_LEADER\fR property. This property provides a pointer to +the client leader window which contains the \fBWM_CLASS\fR, \fBWM_NAME\fR, +\fBWM_COMMAND\fR, and \fBWM_CLIENT_MACHINE\fR properties. +.br +.sp +or ... +.br +.sp +- The application maps a top level window which does not contain the +\fBWM_CLIENT_LEADER\fR property. However, this top level window +contains the \fBWM_CLASS\fR, \fBWM_NAME\fR, \fBWM_COMMAND\fR, and +\fBWM_CLIENT_MACHINE\fR properties. +.PP +An application that support the \fBWM_SAVE_YOURSELF\fR protocol will receive +a \fBWM_SAVE_YOURSELF\fR client message each time the session manager issues +a checkpoint or shutdown. This allows the application to save state. If +an application does not support the \fBWM_SAVE_YOURSELF\fR protocol, then +the proxy will provide enough information to the session manager to restart +the application (using \fBWM_COMMAND\fR), but no state will be restored. +.PP +.SH REMOTE APPLICATIONS +\fIxsm\fP requires a remote execution protocol in order to restart +applications on remote machines. Currently, \fIxsm\fP supports the +\fIrstart\fP protocol. In order to restart an application on remote +machine \fBX\fR, machine \fBX\fR must have \fIrstart\fP installed. In +the future, additional remote execution protocols may be supported. +.SH SEE ALSO +smproxy(1), rstart(1) +.SH AUTHORS +Ralph Mor, X Consortium +.br +Jordan Brown, Quarterdeck Office Systems diff --git a/xtwatch.c b/xtwatch.c new file mode 100644 index 0000000..4a42e27 --- /dev/null +++ b/xtwatch.c @@ -0,0 +1,124 @@ +/* $Xorg: xtwatch.c,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +#include <X11/ICE/ICElib.h> +#include <X11/Intrinsic.h> +#include "xsm.h" + +extern void CloseDownClient (); + + + +Status +InitWatchProcs (appContext) + +XtAppContext appContext; + +{ + void _XtIceWatchProc (); + + return (IceAddConnectionWatch (_XtIceWatchProc, (IcePointer) appContext)); +} + + +void +_XtIceWatchProc (ice_conn, client_data, opening, watch_data) + +IceConn ice_conn; +IcePointer client_data; +Bool opening; +IcePointer *watch_data; + +{ + if (opening) + { + XtAppContext appContext = (XtAppContext) client_data; + void _XtProcessIceMsgProc (); + + *watch_data = (IcePointer) XtAppAddInput ( + appContext, + IceConnectionNumber (ice_conn), + (XtPointer) XtInputReadMask, + _XtProcessIceMsgProc, + (XtPointer) ice_conn); + } + else + { + XtRemoveInput ((XtInputId) *watch_data); + } +} + + +void +_XtProcessIceMsgProc (client_data, source, id) + +XtPointer client_data; +int *source; +XtInputId *id; + +{ + IceConn ice_conn = (IceConn) client_data; + IceProcessMessagesStatus status; + + status = IceProcessMessages (ice_conn, NULL, NULL); + + if (status == IceProcessMessagesIOError) + { + List *cl; + int found = 0; + + if (verbose) + { + printf ("IO error on connection (fd = %d)\n", + IceConnectionNumber (ice_conn)); + printf ("\n"); + } + + for (cl = ListFirst (RunningList); cl; cl = ListNext (cl)) + { + ClientRec *client = (ClientRec *) cl->thing; + + if (client->ice_conn == ice_conn) + { + CloseDownClient (client); + found = 1; + break; + } + } + + if (!found) + { + /* + * The client must have disconnected before it was added + * to the session manager's running list (i.e. before the + * NewClientProc callback was invoked). + */ + + IceSetShutdownNegotiation (ice_conn, False); + IceCloseConnection (ice_conn); + } + } +} diff --git a/xtwatch.h b/xtwatch.h new file mode 100644 index 0000000..4ee3b00 --- /dev/null +++ b/xtwatch.h @@ -0,0 +1,27 @@ +/* $Xorg: xtwatch.h,v 1.4 2001/02/09 02:06:01 xorgcvs Exp $ */ +/****************************************************************************** + +Copyright 1993, 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. +******************************************************************************/ + +extern Status InitWatchProcs (); |