Release 6 Public Patch #08 X Consortium To apply this patch: cd to the top of the source tree (to the directory containing the "xc" and "contrib" subdirectories) and do: patch -p -s < ThisFile Patch will work silently unless an error occurs. You will likely get the following warning messages, which can be ignored: mkdir: xc: File exists mkdir: xc/programs: File exists If you want to watch patch do its thing, leave out the "-s" argument to patch. This patch creates the following new files: xc/programs/smproxy/Imakefile xc/programs/smproxy/smproxy.c xc/programs/smproxy/save.c xc/programs/smproxy/smproxy.h xc/programs/smproxy/smproxy.man xc/programs/twm/session.c xc/workInProgress/xsm/saveutil.c xc/workInProgress/xsm/XSm.ad xc/workInProgress/xsm/system.xsm xc/workInProgress/xsm/log.c xc/workInProgress/xsm/log.h xc/workInProgress/xsm/choose.c xc/workInProgress/xsm/choose.h xc/workInProgress/xsm/info.c xc/workInProgress/xsm/info.h xc/workInProgress/xsm/mainwin.c xc/workInProgress/xsm/mainwin.h xc/workInProgress/xsm/prop.c xc/workInProgress/xsm/save.h xc/workInProgress/xsm/auth.h xc/workInProgress/xsm/globals.c xc/workInProgress/xsm/restart.h xc/workInProgress/xsm/xtwatch.h xc/workInProgress/xsm/saveutil.h xc/workInProgress/xsm/signals.c xc/workInProgress/xsm/prop.h xc/workInProgress/xsm/lock.c xc/workInProgress/xsm/lock.h xc/workInProgress/xsm/README xc/workInProgress/xsm/popup.h xc/workInProgress/xsm/popup.c If you are using a symbolic link tree, you will need to create new links. Finally, to rebuild, cd to the "xc" subdirectory and do: make Everything >& every.log Then, to actually install the new executables and the xsm app defaults file, do: make install This patch updates session management support in R6: - The X Session Manager (xsm) has been enhanced significantly since the initial R6 release. xsm allows you to have arbitrary sessions, each with 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. See the xsm man page for more information about the new session manager. xsm is still in the workInProgress portion of R6. - A new session manager proxy (smproxy) exists so that X applications that do not support R6 session management can be part of an R6 session. - The twm window manager has been modified to be session aware. It is responsible for saving and restoring all application window positions and sizes. - xmh has been modified to be session aware. xmh will now ask the user to commit changes during a checkpoint or shutdown. In addition, this patch contains the following fixes: Xt: SetValues on SessionShell/joinSession misses SM_CLIENT_ID ICElib: must set close-on-exec for ICE for ICE file descriptors iceauth : problem with remove command Prereq: public-patch-7 *** - Tue Jan 24 13:05:44 1995 --- xc/bug-report Tue Jan 24 13:05:44 1995 *************** *** 3,9 **** VERSION: ! R6, public-patch-7 [X Consortium public patches edit this line to indicate the patch level] CLIENT MACHINE and OPERATING SYSTEM: --- 3,9 ---- VERSION: ! R6, public-patch-8 [X Consortium public patches edit this line to indicate the patch level] CLIENT MACHINE and OPERATING SYSTEM: *** - Tue Jan 24 15:33:44 1995 --- xc/lib/Xt/Shell.c Tue Jan 24 15:33:43 1995 *************** *** 1,4 **** ! /* $XConsortium: Shell.c,v 1.167 94/09/02 16:16:48 kaleb Exp $ */ /*********************************************************** Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts --- 1,4 ---- ! /* $XConsortium: Shell.c,v 1.168 95/01/06 21:14:23 converse Exp $ */ /*********************************************************** Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts *************** *** 1269,1274 **** --- 1269,1287 ---- _SetTransientForHint((TransientShellWidget)w, False); } + static Widget GetClientLeader(w) + Widget w; + { + while ((! XtIsWMShell(w) || ! ((WMShellWidget)w)->wm.client_leader) + && w->core.parent) + w = w->core.parent; + + /* ASSERT: w is a WMshell with client_leader set, or w has no parent */ + + if (XtIsWMShell(w) && ((WMShellWidget)w)->wm.client_leader) + w = ((WMShellWidget)w)->wm.client_leader; + return w; + } static void EvaluateWMHints(w) WMShellWidget w; *************** *** 1479,1493 **** } UNLOCK_PROCESS; ! p = (Widget) w; ! while ((! XtIsWMShell(p) || ! ((WMShellWidget)p)->wm.client_leader) ! && p->core.parent) ! p = p->core.parent; ! ! /* ASSERT: p is a WMshell with client_leader set, or p has no parent */ ! ! if (((WMShellWidget)p)->wm.client_leader) ! p = ((WMShellWidget)p)->wm.client_leader; if (XtWindow(p)) XChangeProperty(XtDisplay((Widget)w), XtWindow((Widget)w), XInternAtom(XtDisplay((Widget)w), --- 1492,1498 ---- } UNLOCK_PROCESS; ! p = GetClientLeader((Widget)w); if (XtWindow(p)) XChangeProperty(XtDisplay((Widget)w), XtWindow((Widget)w), XInternAtom(XtDisplay((Widget)w), *************** *** 2247,2252 **** --- 2252,2268 ---- XA_WM_TRANSIENT_FOR); } + if (nwmshell->wm.client_leader != owmshell->wm.client_leader + && XtWindow(new) && !nwmshell->shell.override_redirect) { + Widget leader = GetClientLeader(new); + if (XtWindow(leader)) + XChangeProperty(XtDisplay(new), XtWindow(new), + XInternAtom(XtDisplay(new), + "WM_CLIENT_LEADER", False), + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(leader->core.window), 1); + } + if (nwmshell->wm.window_role != owmshell->wm.window_role) { XtFree(owmshell->wm.window_role); if (set_prop && nwmshell->wm.window_role) { *************** *** 2481,2486 **** --- 2497,2523 ---- (cw->session.connection && !nw->session.connection)) StopManagingSession(nw, nw->session.connection); + if (cw->wm.client_leader != nw->wm.client_leader || + cw->session.session_id != nw->session.session_id) { + Widget leader; + if (cw->session.session_id) { + leader = GetClientLeader(current); + if (XtWindow(leader)) + XDeleteProperty(XtDisplay(leader), XtWindow(leader), + XInternAtom(XtDisplay(leader), "SM_CLIENT_ID", + False)); + } + if (nw->session.session_id) { + leader = GetClientLeader(new); + if (XtWindow(leader)) + XChangeProperty(XtDisplay(leader), XtWindow(leader), + XInternAtom(XtDisplay(leader), "SM_CLIENT_ID", + False), + XA_STRING, 8, PropModeReplace, + (unsigned char *) nw->session.session_id, + strlen(nw->session.session_id)); + } + } return False; } *** - Wed Jan 18 12:19:16 1995 --- xc/lib/ICE/accept.c Wed Jan 18 12:19:16 1995 *************** *** 1,4 **** ! /* $XConsortium: accept.c,v 1.23 94/04/17 20:15:30 mor Exp $ */ /****************************************************************************** --- 1,4 ---- ! /* $XConsortium: accept.c,v 1.24 94/12/20 17:50:13 mor Exp $ */ /****************************************************************************** *************** *** 57,62 **** --- 57,69 ---- *statusRet = IceAcceptFailure; return (NULL); } + + + /* + * Set close-on-exec so that programs that fork() don't get confused. + */ + + _IceTransSetOption (newconn, TRANS_CLOSEONEXEC, 1); /* *** - Wed Jan 18 12:19:18 1995 --- xc/lib/ICE/connect.c Wed Jan 18 12:19:18 1995 *************** *** 1,4 **** ! /* $XConsortium: connect.c,v 1.30 94/04/17 20:15:31 mor Exp $ */ /****************************************************************************** --- 1,4 ---- ! /* $XConsortium: connect.c,v 1.31 94/12/20 17:50:13 mor Exp $ */ /****************************************************************************** *************** *** 178,183 **** --- 178,190 ---- strncpy (errorStringRet, "Could not open network socket", errorLength); return (NULL); } + + /* + * Set close-on-exec so that programs that fork() don't get confused. + */ + + _IceTransSetOption (iceConn->trans_conn, TRANS_CLOSEONEXEC, 1); + iceConn->connection_status = IceConnectPending; iceConn->io_ok = True; *** - Wed Jan 18 12:19:21 1995 --- xc/lib/ICE/iceauth.c Wed Jan 18 12:19:21 1995 *************** *** 1,4 **** ! /* $XConsortium: iceauth.c,v 1.20 94/04/17 20:15:34 mor Exp $ */ /****************************************************************************** --- 1,4 ---- ! /* $XConsortium: iceauth.c,v 1.21 94/12/20 16:49:58 mor Exp $ */ /****************************************************************************** *************** *** 221,227 **** IcePaAuthStatus stat; if (authDataLen == length && ! binaryEqual (authData, data, authDataLen)) { stat = IcePaAuthAccepted; } --- 221,227 ---- IcePaAuthStatus stat; if (authDataLen == length && ! binaryEqual ((char *) authData, data, authDataLen)) { stat = IcePaAuthAccepted; } *** - Wed Jan 18 12:37:37 1995 --- xc/programs/iceauth/process.c Wed Jan 18 12:37:37 1995 *************** *** 1,5 **** /* ! * $XConsortium: process.c,v 1.4 94/04/17 20:39:56 mor Exp $ * * Copyright (c) 1989 X Consortium --- 1,5 ---- /* ! * $XConsortium: process.c,v 1.7 94/12/16 22:21:15 gildea Exp $ * * Copyright (c) 1989 X Consortium *************** *** 610,628 **** return 0; } ! static int write_auth_file (tmpnam) ! char *tmpnam; { FILE *fp; AuthList *list; ! strcpy (tmpnam, iceauth_filename); ! strcat (tmpnam, "-n"); /* for new */ ! (void) unlink (tmpnam); ! fp = fopen (tmpnam, "wb"); /* umask is still set to 0077 */ if (!fp) { fprintf (stderr, "%s: unable to open tmp file \"%s\"\n", ! ProgramName, tmpnam); return -1; } --- 610,628 ---- return 0; } ! static int write_auth_file (tmp_nam) ! char *tmp_nam; { FILE *fp; AuthList *list; ! strcpy (tmp_nam, iceauth_filename); ! strcat (tmp_nam, "-n"); /* for new */ ! (void) unlink (tmp_nam); ! fp = fopen (tmp_nam, "wb"); /* umask is still set to 0077 */ if (!fp) { fprintf (stderr, "%s: unable to open tmp file \"%s\"\n", ! ProgramName, tmp_nam); return -1; } *************** *** 635,641 **** int auth_finalize () { ! char tmpnam[1024]; /* large filename size */ if (iceauth_modified) { if (dieing) { --- 635,641 ---- int auth_finalize () { ! char temp_name[1024]; /* large filename size */ if (iceauth_modified) { if (dieing) { *************** *** 653,675 **** ignore_locks ? "Ignoring locks and writing" : "Writing", iceauth_filename); } ! tmpnam[0] = '\0'; ! if (write_auth_file (tmpnam) == -1) { fprintf (stderr, "%s: unable to write authority file %s\n", ! ProgramName, tmpnam); } else { (void) unlink (iceauth_filename); #ifdef WIN32 ! if (rename(tmpnam, iceauth_filename) == -1) { #else ! if (link (tmpnam, iceauth_filename) == -1) { #endif fprintf (stderr, "%s: unable to link authority file %s, use %s\n", ! ProgramName, iceauth_filename, tmpnam); } else { ! (void) unlink (tmpnam); } } } --- 653,676 ---- ignore_locks ? "Ignoring locks and writing" : "Writing", iceauth_filename); } ! temp_name[0] = '\0'; ! if (write_auth_file (temp_name) == -1) { fprintf (stderr, "%s: unable to write authority file %s\n", ! ProgramName, temp_name); } else { (void) unlink (iceauth_filename); #ifdef WIN32 ! if (rename(temp_name, iceauth_filename) == -1) #else ! if (link (temp_name, iceauth_filename) == -1) #endif + { fprintf (stderr, "%s: unable to link authority file %s, use %s\n", ! ProgramName, iceauth_filename, temp_name); } else { ! (void) unlink (temp_name); } } } *************** *** 782,802 **** } ! static int match_auth (a, b) register IceAuthFileEntry *a, *b; { ! return (strcmp (a->protocol_name, b->protocol_name) == 0 && strcmp (a->network_id, b->network_id) == 0 && ! strcmp (a->auth_name, b->auth_name) == 0); } ! static int merge_entries (firstp, second, nnewp, nreplp) AuthList **firstp, *second; ! int *nnewp, *nreplp; { AuthList *a, *b, *first, *tail; ! int n = 0, nnew = 0, nrepl = 0; if (!second) return 0; --- 783,814 ---- } ! static int match_auth (a, b, authDataSame) register IceAuthFileEntry *a, *b; + int *authDataSame; { ! int match = strcmp (a->protocol_name, b->protocol_name) == 0 && strcmp (a->network_id, b->network_id) == 0 && ! strcmp (a->auth_name, b->auth_name) == 0; ! ! if (match) ! { ! *authDataSame = (a->auth_data_length == b->auth_data_length && ! binaryEqual (a->auth_data, b->auth_data, a->auth_data_length)); ! } ! else ! *authDataSame = 0; ! ! return (match); } ! static int merge_entries (firstp, second, nnewp, nreplp, ndupp) AuthList **firstp, *second; ! int *nnewp, *nreplp, *ndupp; { AuthList *a, *b, *first, *tail; ! int n = 0, nnew = 0, nrepl = 0, ndup = 0; if (!second) return 0; *************** *** 805,810 **** --- 817,823 ---- for (tail = *firstp, n = 1; tail->next; n++, tail = tail->next) ; *nnewp = n; *nreplp = 0; + *ndupp = 0; return n; } *************** *** 822,857 **** */ for (b = second; b; ) { AuthList *next = b->next; /* in case we free it */ a = first; for (;;) { ! if (match_auth (a->auth, b->auth)) { /* found a duplicate */ ! AuthList tmp; /* swap it in for old one */ ! tmp = *a; ! *a = *b; ! *b = tmp; ! a->next = b->next; ! IceFreeAuthFileEntry (b->auth); ! free ((char *) b); ! b = NULL; ! tail->next = next; ! nrepl++; ! nnew--; ! break; } if (a == tail) break; /* if have looked at left side */ a = a->next; } ! if (b) { /* if we didn't remove it */ tail = b; /* bump end of first list */ } b = next; ! n++; ! nnew++; } *nnewp = nnew; *nreplp = nrepl; return n; } --- 835,891 ---- */ for (b = second; b; ) { AuthList *next = b->next; /* in case we free it */ + int duplicate; + duplicate = 0; a = first; for (;;) { ! int authDataSame; ! if (match_auth (a->auth, b->auth, &authDataSame)) { ! if (authDataSame) ! { ! /* found a complete duplicate, ignore */ ! duplicate = 1; ! break; ! } ! else ! { ! /* found a duplicate, but auth data differs */ ! ! AuthList tmp; /* swap it in for old one */ ! tmp = *a; ! *a = *b; ! *b = tmp; ! a->next = b->next; ! IceFreeAuthFileEntry (b->auth); ! free ((char *) b); ! b = NULL; ! tail->next = next; ! nrepl++; ! nnew--; ! break; ! } } if (a == tail) break; /* if have looked at left side */ a = a->next; } ! if (!duplicate && b) { /* if we didn't remove it */ tail = b; /* bump end of first list */ } b = next; ! ! if (duplicate) ! ndup++; ! else ! { ! n++; ! nnew++; ! } } *nnewp = nnew; *nreplp = nrepl; + *ndupp = ndup; return n; } *************** *** 885,892 **** protoname = argv[i] + 10; else if (!strncmp ("protodata=", argv[i], 10)) protodata = argv[i] + 10; ! else if (!strncmp ("netid=", argv[i], 8)) ! netid = argv[i] + 8; else if (!strncmp ("authname=", argv[i], 9)) authname = argv[i] + 9; } --- 919,926 ---- protoname = argv[i] + 10; else if (!strncmp ("protodata=", argv[i], 10)) protodata = argv[i] + 10; ! else if (!strncmp ("netid=", argv[i], 6)) ! netid = argv[i] + 6; else if (!strncmp ("authname=", argv[i], 9)) authname = argv[i] + 9; } *************** *** 1090,1096 **** int i; int errors = 0; AuthList *head, *tail, *listhead, *listtail; ! int nentries, nnew, nrepl; if (argc < 2) { prefix (inputfilename, lineno); --- 1124,1130 ---- int i; int errors = 0; AuthList *head, *tail, *listhead, *listtail; ! int nentries, nnew, nrepl, ndup; if (argc < 2) { prefix (inputfilename, lineno); *************** *** 1131,1137 **** * if we have new entries, merge them in (freeing any duplicates) */ if (listhead) { ! nentries = merge_entries (&iceauth_head, listhead, &nnew, &nrepl); if (verbose) printf ("%d entries read in: %d new, %d replacement%s\n", nentries, nnew, nrepl, nrepl != 1 ? "s" : ""); --- 1165,1172 ---- * if we have new entries, merge them in (freeing any duplicates) */ if (listhead) { ! nentries = merge_entries (&iceauth_head, listhead, ! &nnew, &nrepl, &ndup); if (verbose) printf ("%d entries read in: %d new, %d replacement%s\n", nentries, nnew, nrepl, nrepl != 1 ? "s" : ""); *************** *** 1194,1200 **** int argc; char **argv; { ! int n, nnew, nrepl; char *protoname; char *protodata_hex; char *protodata = NULL; /* not required */ --- 1229,1235 ---- int argc; char **argv; { ! int n, nnew, nrepl, ndup; char *protoname; char *protodata_hex; char *protodata = NULL; /* not required */ *************** *** 1205,1210 **** --- 1240,1246 ---- int protodata_len, authdata_len; IceAuthFileEntry *auth; AuthList *list; + int status = 0; if (argc != 6 || !argv[1] || !argv[2] || !argv[3] || !argv[4] || !argv[5]) *************** *** 1313,1334 **** * merge it in; note that merge will deal with allocation */ ! n = merge_entries (&iceauth_head, list, &nnew, &nrepl); ! if (n <= 0) { prefix (inputfilename, lineno); ! fprintf (stderr, "unable to merge in added record\n"); goto cant_add; } - iceauth_modified = True; - return 0; add_bad_malloc: prefix (inputfilename, lineno); fprintf (stderr, "unable to allocate memory to add an entry\n"); --- 1349,1380 ---- * merge it in; note that merge will deal with allocation */ ! n = merge_entries (&iceauth_head, list, &nnew, &nrepl, &ndup); ! if (n > 0) ! iceauth_modified = True; ! else { prefix (inputfilename, lineno); ! if (ndup > 0) ! { ! status = 0; ! fprintf (stderr, "no records added - all duplicate\n"); ! } ! else ! { ! status = 1; ! fprintf (stderr, "unable to merge in added record\n"); ! } goto cant_add; } return 0; add_bad_malloc: + status = 1; prefix (inputfilename, lineno); fprintf (stderr, "unable to allocate memory to add an entry\n"); *************** *** 1353,1359 **** free ((char *) auth); } ! return 1; } /* --- 1399,1405 ---- free ((char *) auth); } ! return status; } /* *** - Wed Jan 18 13:24:47 1995 --- xc/programs/rstart/server.c Wed Jan 18 13:24:47 1995 *************** *** 1,4 **** ! /* $XConsortium: server.c,v 1.10 94/03/29 19:47:53 rws Exp $ */ /************************************************************************/ /* Copyright (c) 1993 Quarterdeck Office Systems */ --- 1,4 ---- ! /* $XConsortium: server.c,v 1.12 94/12/30 18:48:43 mor Exp $ */ /************************************************************************/ /* Copyright (c) 1993 Quarterdeck Office Systems */ *************** *** 124,130 **** setbuf(stdin, NULL); printf( ! "%s: Ready: version 0.5, Feb 03 1994 X11R6beta jbrown@qdeck.com\n", myname); fflush(stdout); --- 124,130 ---- setbuf(stdin, NULL); printf( ! "%s: Ready: version 1.0, May 02 1994 X11R6\n", myname); fflush(stdout); *************** *** 187,193 **** int *pargc; char ***pargv; { ! char buf[BUFSIZ]; char *p; int c; char **pa; --- 187,193 ---- int *pargc; char ***pargv; { ! char buf[2048]; char *p; int c; char **pa; *** - Wed Dec 31 19:00:00 1969 --- xc/programs/Imakefile Wed Jan 18 14:49:19 1995 *************** *** 1,4 **** ! XCOMM $XConsortium: Imakefile,v 1.68 94/04/07 15:10:02 rws Exp $ #define IHaveSubdirs #define PassCDebugFlags CDEBUGFLAGS="$(CDEBUGFLAGS)" --- 1,4 ---- ! XCOMM $XConsortium: Imakefile,v 1.69 94/07/06 16:26:01 mor Exp $ #define IHaveSubdirs #define PassCDebugFlags CDEBUGFLAGS="$(CDEBUGFLAGS)" *************** *** 20,26 **** SUBDIRS = \ appres bdftopcf bitmap editres fsinfo fslsfonts fstobdf iceauth \ ! mkfontdir oclock $(RGBDIR) rstart twm x11perf xauth xclipboard xclock \ xcmsdb xconsole xdm xdpyinfo xfd $(XFSDIR) xhost xieperf \ $(XINIDIR) $(XKBCOMP) xkill xlogo xlsatoms xlsclients xlsfonts \ xmag xmh xmodmap xprop xrdb xrefresh xset xsetroot xstdcmap xterm \ --- 20,27 ---- SUBDIRS = \ appres bdftopcf bitmap editres fsinfo fslsfonts fstobdf iceauth \ ! mkfontdir oclock $(RGBDIR) rstart smproxy \ ! twm x11perf xauth xclipboard xclock \ xcmsdb xconsole xdm xdpyinfo xfd $(XFSDIR) xhost xieperf \ $(XINIDIR) $(XKBCOMP) xkill xlogo xlsatoms xlsclients xlsfonts \ xmag xmh xmodmap xprop xrdb xrefresh xset xsetroot xstdcmap xterm \ *** /dev/null Wed Jan 18 12:43:03 1995 --- xc/programs/smproxy/Imakefile Wed Jan 18 12:43:03 1995 *************** *** 0 **** --- 1,7 ---- + XCOMM $XConsortium: Imakefile,v 1.2 94/07/06 16:26:46 mor Exp $ + DEPLIBS = $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB) + LOCAL_LIBRARIES = $(XMULIB) $(XTOOLLIB) $(XLIB) + SRCS = smproxy.c save.c + OBJS = smproxy.o save.o + + ComplexProgramTarget(smproxy) *** /dev/null Wed Jan 18 12:43:04 1995 --- xc/programs/smproxy/smproxy.c Wed Jan 18 12:43:04 1995 *************** *** 0 **** --- 1,1315 ---- + /* $XConsortium: smproxy.c,v 1.28 95/01/04 22:28:03 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + + Author: Ralph Mor, X Consortium + ******************************************************************************/ + + #include "smproxy.h" + + XtAppContext appContext; + Display *disp; + Window root; + + Atom wmProtocolsAtom; + Atom wmSaveYourselfAtom; + Atom wmStateAtom; + Atom smClientIdAtom; + Atom wmClientLeaderAtom; + + Bool debug = 0; + + SmcConn proxy_smcConn; + XtInputId proxy_iceInputId; + char *proxy_clientId = NULL; + + WinInfo *win_head = NULL; + + int proxy_count = 0; + int die_count = 0; + + Bool ok_to_die = 0; + + Bool caught_error = 0; + + Bool sent_save_done = 0; + + int Argc; + char **Argv; + + + + Bool + HasSaveYourself (window) + + Window window; + + { + Atom *protocols; + int numProtocols; + int i, found; + + protocols = NULL; + + if (XGetWMProtocols (disp, window, &protocols, &numProtocols) != True) + return (False); + + found = 0; + + if (protocols != NULL) + { + for (i = 0; i < numProtocols; i++) + if (protocols[i] == wmSaveYourselfAtom) + found = 1; + + XFree (protocols); + } + + return (found); + } + + + + Bool + HasXSMPsupport (window) + + Window window; + + { + XTextProperty tp; + Bool hasIt = 0; + + if (XGetTextProperty (disp, window, &tp, smClientIdAtom)) + { + if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0) + hasIt = 1; + + if (tp.value) + XFree ((char *) tp.value); + } + + return (hasIt); + } + + + + WinInfo * + GetClientLeader (winptr) + + WinInfo *winptr; + + { + Atom actual_type; + int actual_format; + unsigned long nitems, bytesafter; + unsigned long *datap = NULL; + WinInfo *leader_winptr = NULL; + Bool failure = 0; + + if (XGetWindowProperty (disp, winptr->window, wmClientLeaderAtom, + 0L, 1L, False, AnyPropertyType, &actual_type, &actual_format, + &nitems, &bytesafter, (unsigned char **) &datap) == Success) + { + if (actual_type == XA_WINDOW && actual_format == 32 && + nitems == 1 && bytesafter == 0) + { + Window leader_win = *((Window *) datap); + + if (!LookupWindow (leader_win, &leader_winptr, NULL)) + failure = 1; + } + + if (datap) + XFree (datap); + } + + if (failure) + { + /* The client leader was defined, but we couldn't find the window */ + + return (NULL); + } + else if (leader_winptr) + { + /* We found the real client leader */ + + return (leader_winptr); + } + else + { + /* There is no client leader defined, return this window */ + + return (winptr); + } + } + + + + char * + CheckFullyQuantifiedName (name, newstring) + + char *name; + int *newstring; + + { + /* + * Due to a bug in Xlib (for hpux in particular), some clients + * will have a WM_CLIENT_MACHINE that is not fully quantified. + * For example, we might get "excon" instead of "excon.x.org". + * This really stinks. The best we can do is tag on our own + * domain name. + */ + + if (strchr (name, '.') != NULL) + { + *newstring = 0; + return (name); + } + else + { + char hostnamebuf[80]; + char *firstDot; + + gethostname (hostnamebuf, sizeof hostnamebuf); + firstDot = strchr (hostnamebuf, '.'); + + if (!firstDot) + { + *newstring = 0; + return (name); + } + else + { + int bytes = strlen (name) + strlen (firstDot + 1) + 2; + char *newptr; + + newptr = (char *) malloc (bytes); + sprintf (newptr, "%s.%s", name, firstDot + 1); + + *newstring = 1; + return (newptr); + } + } + } + + + + void FinishSaveYourself (winInfo, has_WM_SAVEYOURSELF) + + WinInfo *winInfo; + Bool has_WM_SAVEYOURSELF; + + { + SmProp prop1, prop2, prop3, *props[3]; + SmPropValue prop1val, prop2val, prop3val; + int i; + + if (!winInfo->got_first_save_yourself) + { + char userId[20], restartService[80]; + char *fullyQuantifiedName; + int newstring; + + prop1.name = SmProgram; + prop1.type = SmARRAY8; + prop1.num_vals = 1; + prop1.vals = &prop1val; + prop1val.value = (SmPointer) winInfo->wm_command[0]; + prop1val.length = strlen (winInfo->wm_command[0]); + + sprintf (userId, "%d", getuid()); + prop2.name = SmUserID; + prop2.type = SmARRAY8; + prop2.num_vals = 1; + prop2.vals = &prop2val; + prop2val.value = (SmPointer) userId; + prop2val.length = strlen (userId); + + fullyQuantifiedName = CheckFullyQuantifiedName ( + (char *) winInfo->wm_client_machine.value, &newstring); + sprintf (restartService, "rstart-rsh/%s", fullyQuantifiedName); + if (newstring) + free (fullyQuantifiedName); + + prop3.name = "_XC_RestartService"; + prop3.type = SmLISTofARRAY8; + prop3.num_vals = 1; + prop3.vals = &prop3val; + prop3val.value = (SmPointer) restartService; + prop3val.length = strlen (restartService); + + props[0] = &prop1; + props[1] = &prop2; + props[2] = &prop3; + + SmcSetProperties (winInfo->smc_conn, 3, props); + + winInfo->got_first_save_yourself = 1; + } + + prop1.name = SmRestartCommand; + prop1.type = SmLISTofARRAY8; + prop1.num_vals = winInfo->wm_command_count; + + prop1.vals = (SmPropValue *) malloc ( + winInfo->wm_command_count * sizeof (SmPropValue)); + + if (!prop1.vals) + { + SmcSaveYourselfDone (winInfo->smc_conn, False); + return; + } + + for (i = 0; i < winInfo->wm_command_count; i++) + { + prop1.vals[i].value = (SmPointer) winInfo->wm_command[i]; + prop1.vals[i].length = strlen (winInfo->wm_command[i]); + } + + prop2.name = SmCloneCommand; + prop2.type = SmLISTofARRAY8; + prop2.num_vals = winInfo->wm_command_count; + prop2.vals = prop1.vals; + + props[0] = &prop1; + props[1] = &prop2; + + SmcSetProperties (winInfo->smc_conn, 2, props); + + free ((char *) prop1.vals); + + /* + * If the client doesn't support WM_SAVE_YOURSELF, we should + * return failure for the save, since we really don't know if + * the application needed to save state. + */ + + SmcSaveYourselfDone (winInfo->smc_conn, has_WM_SAVEYOURSELF); + } + + + + void + SaveYourselfCB (smcConn, clientData, saveType, shutdown, interactStyle, fast) + + SmcConn smcConn; + SmPointer clientData; + int saveType; + Bool shutdown; + int interactStyle; + Bool fast; + + { + WinInfo *winInfo = (WinInfo *) clientData; + + if (!winInfo->has_save_yourself) + { + FinishSaveYourself (winInfo, False); + } + else + { + XClientMessageEvent saveYourselfMessage; + + + /* Send WM_SAVE_YOURSELF */ + + saveYourselfMessage.type = ClientMessage; + saveYourselfMessage.window = winInfo->window; + saveYourselfMessage.message_type = wmProtocolsAtom; + saveYourselfMessage.format = 32; + saveYourselfMessage.data.l[0] = wmSaveYourselfAtom; + saveYourselfMessage.data.l[1] = CurrentTime; + + if (XSendEvent (disp, winInfo->window, False, NoEventMask, + (XEvent *) &saveYourselfMessage)) + { + winInfo->waiting_for_update = 1; + + if (debug) + { + printf ("Sent SAVE YOURSELF to 0x%x\n", winInfo->window); + printf ("\n"); + } + } + else + { + if (debug) + { + printf ("Failed to send SAVE YOURSELF to 0x%x\n", + winInfo->window); + printf ("\n"); + } + } + } + } + + + + void + DieCB (smcConn, clientData) + + SmcConn smcConn; + SmPointer clientData; + + { + WinInfo *winInfo = (WinInfo *) clientData; + + SmcCloseConnection (winInfo->smc_conn, 0, NULL); + winInfo->smc_conn = NULL; + XtRemoveInput (winInfo->input_id); + + /* Now tell the client to die */ + + if (debug) + printf ("Trying to kill 0x%x\n", winInfo->window); + + XSync (disp, 0); + XKillClient (disp, winInfo->window); + XSync (disp, 0); + + + /* + * Proxy must exit when all clients die, and the proxy itself + * must have received a Die. + */ + + die_count++; + + if (die_count == proxy_count && ok_to_die) + { + exit (0); + } + } + + + + void + SaveCompleteCB (smcConn, clientData) + + SmcConn smcConn; + SmPointer clientData; + + { + /* + * Nothing to do here. + */ + } + + + + void + ShutdownCancelledCB (smcConn, clientData) + + SmcConn smcConn; + SmPointer clientData; + + { + /* + * Since we did not request to interact or request save yourself + * phase 2, we know we already sent the save yourself done, so + * there is nothing to do here. + */ + } + + + + void + ProcessIceMsgProc (client_data, source, id) + + XtPointer client_data; + int *source; + XtInputId *id; + + { + IceConn ice_conn = (IceConn) client_data; + + IceProcessMessages (ice_conn, NULL, NULL); + } + + + + void + NullIceErrorHandler (iceConn, swap, + offendingMinorOpcode, offendingSequence, errorClass, severity, values) + + IceConn iceConn; + Bool swap; + int offendingMinorOpcode; + unsigned long offendingSequence; + int errorClass; + int severity; + IcePointer values; + + { + return; + } + + + void + ConnectClientToSM (winInfo) + + WinInfo *winInfo; + + { + char errorMsg[256]; + unsigned long mask; + SmcCallbacks callbacks; + IceConn ice_conn; + char *prevId; + + mask = SmcSaveYourselfProcMask | SmcDieProcMask | + SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask; + + callbacks.save_yourself.callback = SaveYourselfCB; + callbacks.save_yourself.client_data = (SmPointer) winInfo; + + callbacks.die.callback = DieCB; + callbacks.die.client_data = (SmPointer) winInfo; + + callbacks.save_complete.callback = SaveCompleteCB; + callbacks.save_complete.client_data = (SmPointer) winInfo; + + callbacks.shutdown_cancelled.callback = ShutdownCancelledCB; + callbacks.shutdown_cancelled.client_data = (SmPointer) winInfo; + + prevId = LookupClientID (winInfo); + + /* + * In case a protocol error occurs when opening the connection, + * (e.g. an authentication error), we set a null error handler + * before the open, then restore the default handler after the open. + */ + + IceSetErrorHandler (NullIceErrorHandler); + + winInfo->smc_conn = SmcOpenConnection ( + NULL, /* use SESSION_MANAGER env */ + (SmPointer) winInfo, /* force a new connection */ + SmProtoMajor, + SmProtoMinor, + mask, + &callbacks, + prevId, + &winInfo->client_id, + 256, errorMsg); + + IceSetErrorHandler (NULL); + + if (winInfo->smc_conn == NULL) + return; + + ice_conn = SmcGetIceConnection (winInfo->smc_conn); + + winInfo->input_id = XtAppAddInput ( + appContext, + IceConnectionNumber (ice_conn), + (XtPointer) XtInputReadMask, + ProcessIceMsgProc, + (XtPointer) ice_conn); + + if (debug) + { + printf ("Connected to SM, window = 0x%x\n", winInfo->window); + printf ("\n"); + } + + proxy_count++; + } + + + + int + MyErrorHandler (display, event) + + Display *display; + XErrorEvent *event; + + { + caught_error = 1; + } + + + + Bool + LookupWindow (window, ptr_ret, prev_ptr_ret) + + Window window; + WinInfo **ptr_ret; + WinInfo **prev_ptr_ret; + + { + WinInfo *ptr, *prev; + + ptr = win_head; + prev = NULL; + + while (ptr) + { + if (ptr->window == window) + break; + else + { + prev = ptr; + ptr = ptr->next; + } + } + + if (ptr) + { + if (ptr_ret) + *ptr_ret = ptr; + if (prev_ptr_ret) + *prev_ptr_ret = prev; + return (1); + } + else + return (0); + } + + + + WinInfo * + AddNewWindow (window) + + Window window; + + { + WinInfo *newptr; + + if (LookupWindow (window, NULL, NULL)) + return (NULL); + + newptr = (WinInfo *) malloc (sizeof (WinInfo)); + + if (newptr == NULL) + return (NULL); + + newptr->next = win_head; + win_head = newptr; + + newptr->window = window; + newptr->smc_conn = NULL; + newptr->tested_for_sm_client_id = 0; + newptr->client_id = NULL; + newptr->wm_command = NULL; + newptr->wm_command_count = 0; + newptr->class.res_name = NULL; + newptr->class.res_class = NULL; + newptr->wm_name = NULL; + newptr->wm_client_machine.value = NULL; + newptr->wm_client_machine.nitems = 0; + newptr->has_save_yourself = 0; + newptr->waiting_for_update = 0; + newptr->got_first_save_yourself = 0; + + return (newptr); + } + + + + void + RemoveWindow (winptr) + + WinInfo *winptr; + + { + WinInfo *ptr, *prev; + + if (LookupWindow (winptr->window, &ptr, &prev)) + { + if (prev == NULL) + win_head = ptr->next; + else + prev->next = ptr->next; + + if (ptr->client_id) + free (ptr->client_id); + + if (ptr->wm_command) + XFreeStringList (ptr->wm_command); + + if (ptr->wm_name) + XFree (ptr->wm_name); + + if (ptr->wm_client_machine.value) + XFree (ptr->wm_client_machine.value); + + if (ptr->class.res_name) + XFree (ptr->class.res_name); + + if (ptr->class.res_class) + XFree (ptr->class.res_class); + + free ((char *) ptr); + } + } + + + + void + Got_WM_STATE (winptr) + + WinInfo *winptr; + + { + WinInfo *leader_winptr; + + /* + * If we already got WM_STATE and tested for SM_CLIENT_ID, we + * shouldn't do it again. + */ + + if (winptr->tested_for_sm_client_id) + { + return; + } + + + /* + * Set a null error handler, in case this window goes away + * behind our back. + */ + + caught_error = 0; + XSetErrorHandler (MyErrorHandler); + + + /* + * Get the client leader window. + */ + + leader_winptr = GetClientLeader (winptr); + + if (caught_error) + { + caught_error = 0; + RemoveWindow (winptr); + XSetErrorHandler (NULL); + return; + } + + + /* + * If we already checked for SM_CLIENT_ID on the client leader + * window, don't do it again. + */ + + if (!leader_winptr || leader_winptr->tested_for_sm_client_id) + { + caught_error = 0; + XSetErrorHandler (NULL); + return; + } + + leader_winptr->tested_for_sm_client_id = 1; + + if (!HasXSMPsupport (leader_winptr->window)) + { + XFetchName (disp, leader_winptr->window, &leader_winptr->wm_name); + + XGetCommand (disp, leader_winptr->window, + &leader_winptr->wm_command, + &leader_winptr->wm_command_count); + + XGetClassHint (disp, leader_winptr->window, &leader_winptr->class); + + XGetWMClientMachine (disp, leader_winptr->window, + &leader_winptr->wm_client_machine); + + if (leader_winptr->wm_name != NULL && + leader_winptr->wm_command != NULL && + leader_winptr->wm_command_count > 0 && + leader_winptr->class.res_name != NULL && + leader_winptr->class.res_class != NULL && + leader_winptr->wm_client_machine.value != NULL && + leader_winptr->wm_client_machine.nitems != 0) + { + leader_winptr->has_save_yourself = + HasSaveYourself (leader_winptr->window); + + ConnectClientToSM (leader_winptr); + } + } + + XSync (disp, 0); + XSetErrorHandler (NULL); + + if (caught_error) + { + caught_error = 0; + RemoveWindow (leader_winptr); + } + } + + + + void + HandleCreate (event) + + XCreateWindowEvent *event; + + { + Atom actual_type; + int actual_format; + unsigned long nitems, bytesafter; + unsigned long *datap = NULL; + WinInfo *winptr; + Bool got_wm_state = 0; + + /* + * We are waiting for all proxy connections to close so we can die. + * Don't handle new connections. + */ + + if (ok_to_die) + return; + + + /* + * Add the new window + */ + + if ((winptr = AddNewWindow (event->window)) == NULL) + return; + + + /* + * Right after the window was created, it might have been destroyed, + * so the following Xlib calls might fail. Need to catch the error + * by installing an error handler. + */ + + caught_error = 0; + XSetErrorHandler (MyErrorHandler); + + + /* + * Select for Property Notify on the window so we can determine + * when WM_STATE is defined. To avoid a race condition, we must + * do this _before_ we check for WM_STATE right now. + * + * Select for Substructure Notify so we can determine when the + * window is destroyed. + */ + + XSelectInput (disp, event->window, + SubstructureNotifyMask | PropertyChangeMask); + + + /* + * WM_STATE may already be there. Check now. + */ + + if (XGetWindowProperty (disp, event->window, wmStateAtom, + 0L, 2L, False, AnyPropertyType, + &actual_type, &actual_format, &nitems, &bytesafter, + (unsigned char **) &datap) == Success && datap) + { + if (nitems > 0) + got_wm_state = 1; + + if (datap) + XFree ((char *) datap); + } + + XSync (disp, 0); + XSetErrorHandler (NULL); + + if (caught_error) + { + caught_error = 0; + RemoveWindow (winptr); + } + else if (got_wm_state) + { + Got_WM_STATE (winptr); + } + } + + + + void + HandleDestroy (event) + + XDestroyWindowEvent *event; + + { + WinInfo *winptr; + + if (LookupWindow (event->window, &winptr, NULL)) + { + if (winptr->smc_conn) + { + SmcCloseConnection (winptr->smc_conn, 0, NULL); + XtRemoveInput (winptr->input_id); + proxy_count--; + } + + if (debug) + { + printf ("Removed window (window = 0x%x)\n", winptr->window); + printf ("\n"); + } + + RemoveWindow (winptr); + } + } + + + + void + HandleUpdate (event) + + XPropertyEvent *event; + + { + Window window = event->window; + WinInfo *winptr; + + if (!LookupWindow (window, &winptr, NULL)) + return; + + if (event->atom == wmStateAtom) + { + Got_WM_STATE (winptr); + } + else if (event->atom == XA_WM_COMMAND && winptr->waiting_for_update) + { + /* Finish off the Save Yourself */ + + if (winptr->wm_command) + { + XFreeStringList (winptr->wm_command); + winptr->wm_command = NULL; + winptr->wm_command_count = 0; + } + + XGetCommand (disp, window, + &winptr->wm_command, + &winptr->wm_command_count); + + winptr->waiting_for_update = 0; + FinishSaveYourself (winptr, True); + } + } + + + + void + ProxySaveYourselfPhase2CB (smcConn, clientData) + + SmcConn smcConn; + SmPointer clientData; + + { + char *filename; + Bool success = True; + SmProp prop1, prop2, prop3, *props[3]; + SmPropValue prop1val, prop2val, prop3val; + char discardCommand[80]; + int numVals, i; + WinInfo *winptr; + static int first_time = 1; + + if (first_time) + { + char userId[20]; + char hint = SmRestartIfRunning; + + prop1.name = SmProgram; + prop1.type = SmARRAY8; + prop1.num_vals = 1; + prop1.vals = &prop1val; + prop1val.value = Argv[0]; + prop1val.length = strlen (Argv[0]); + + sprintf (userId, "%d", getuid()); + prop2.name = SmUserID; + prop2.type = SmARRAY8; + prop2.num_vals = 1; + prop2.vals = &prop2val; + prop2val.value = (SmPointer) userId; + prop2val.length = strlen (userId); + + prop3.name = SmRestartStyleHint; + prop3.type = SmCARD8; + prop3.num_vals = 1; + prop3.vals = &prop3val; + prop3val.value = (SmPointer) &hint; + prop3val.length = 1; + + props[0] = &prop1; + props[1] = &prop2; + props[2] = &prop3; + + SmcSetProperties (smcConn, 3, props); + + first_time = 0; + } + + if ((filename = WriteProxyFile ()) == NULL) + { + success = False; + goto finishUp; + } + + prop1.name = SmRestartCommand; + prop1.type = SmLISTofARRAY8; + + prop1.vals = (SmPropValue *) malloc ( + (Argc + 4) * sizeof (SmPropValue)); + + if (!prop1.vals) + { + success = False; + goto finishUp; + } + + numVals = 0; + + for (i = 0; i < Argc; i++) + { + if (strcmp (Argv[i], "-clientId") == 0 || + strcmp (Argv[i], "-restore") == 0) + { + i++; + } + else + { + prop1.vals[numVals].value = (SmPointer) Argv[i]; + prop1.vals[numVals++].length = strlen (Argv[i]); + } + } + + prop1.vals[numVals].value = (SmPointer) "-clientId"; + prop1.vals[numVals++].length = 9; + + prop1.vals[numVals].value = (SmPointer) proxy_clientId; + prop1.vals[numVals++].length = strlen (proxy_clientId); + + prop1.vals[numVals].value = (SmPointer) "-restore"; + prop1.vals[numVals++].length = 8; + + prop1.vals[numVals].value = (SmPointer) filename; + prop1.vals[numVals++].length = strlen (filename); + + prop1.num_vals = numVals; + + + sprintf (discardCommand, "rm %s", filename); + prop2.name = SmDiscardCommand; + prop2.type = SmARRAY8; + prop2.num_vals = 1; + prop2.vals = &prop2val; + prop2val.value = (SmPointer) discardCommand; + prop2val.length = strlen (discardCommand); + + props[0] = &prop1; + props[1] = &prop2; + + SmcSetProperties (smcConn, 2, props); + free ((char *) prop1.vals); + + finishUp: + + SmcSaveYourselfDone (smcConn, success); + sent_save_done = 1; + + if (filename) + free (filename); + } + + + + void + ProxySaveYourselfCB (smcConn, clientData, saveType, + shutdown, interactStyle, fast) + + SmcConn smcConn; + SmPointer clientData; + int saveType; + Bool shutdown; + int interactStyle; + Bool fast; + + { + /* + * We want the proxy to respond to the Save Yourself after all + * the regular XSMP clients have finished with the save (and possibly + * interacted with the user). + */ + + if (!SmcRequestSaveYourselfPhase2 (smcConn, + ProxySaveYourselfPhase2CB, NULL)) + { + SmcSaveYourselfDone (smcConn, False); + sent_save_done = 1; + } + else + sent_save_done = 0; + } + + + + void + ProxyDieCB (smcConn, clientData) + + SmcConn smcConn; + SmPointer clientData; + + { + SmcCloseConnection (proxy_smcConn, 0, NULL); + XtRemoveInput (proxy_iceInputId); + + if (die_count == proxy_count) + exit (0); + else + ok_to_die = 1; + } + + + + void + ProxySaveCompleteCB (smcConn, clientData) + + SmcConn smcConn; + SmPointer clientData; + + { + ; + } + + + + void + ProxyShutdownCancelledCB (smcConn, clientData) + + SmcConn smcConn; + SmPointer clientData; + + { + if (!sent_save_done) + { + SmcSaveYourselfDone (smcConn, False); + sent_save_done = 1; + } + } + + + + Status + ConnectProxyToSM (previous_id) + + char *previous_id; + + { + char errorMsg[256]; + unsigned long mask; + SmcCallbacks callbacks; + IceConn iceConn; + + mask = SmcSaveYourselfProcMask | SmcDieProcMask | + SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask; + + callbacks.save_yourself.callback = ProxySaveYourselfCB; + callbacks.save_yourself.client_data = (SmPointer) NULL; + + callbacks.die.callback = ProxyDieCB; + callbacks.die.client_data = (SmPointer) NULL; + + callbacks.save_complete.callback = ProxySaveCompleteCB; + callbacks.save_complete.client_data = (SmPointer) NULL; + + callbacks.shutdown_cancelled.callback = ProxyShutdownCancelledCB; + callbacks.shutdown_cancelled.client_data = (SmPointer) NULL; + + proxy_smcConn = SmcOpenConnection ( + NULL, /* use SESSION_MANAGER env */ + (SmPointer) appContext, + SmProtoMajor, + SmProtoMinor, + mask, + &callbacks, + previous_id, + &proxy_clientId, + 256, errorMsg); + + if (proxy_smcConn == NULL) + return (0); + + iceConn = SmcGetIceConnection (proxy_smcConn); + + proxy_iceInputId = XtAppAddInput ( + appContext, + IceConnectionNumber (iceConn), + (XtPointer) XtInputReadMask, + ProcessIceMsgProc, + (XtPointer) iceConn); + + return (1); + } + + + + void + CheckForExistingWindows () + + { + Window dontCare1, dontCare2, *children, client_window; + unsigned int nchildren, i; + XCreateWindowEvent event; + + /* + * We query the root tree for all windows created thus far. + * Note that at any moment after XQueryTree is called, a + * window may be deleted. So we must take extra care to make + * sure a window really exists. + */ + + XQueryTree (disp, root, &dontCare1, &dontCare2, &children, &nchildren); + + for (i = 0; i < nchildren; i++) + { + event.window = children[i]; + + HandleCreate (&event); + + caught_error = 0; + XSetErrorHandler (MyErrorHandler); + + client_window = XmuClientWindow (disp, children[i]); + + XSetErrorHandler (NULL); + + if (!caught_error && client_window != children[i]) + { + event.window = client_window; + HandleCreate (&event); + } + } + } + + + + main (argc, argv) + + int argc; + char **argv; + + { + char *restore_filename = NULL; + char *client_id = NULL; + int i, zero = 0; + + Argc = argc; + Argv = argv; + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'd': /* -debug */ + debug = 1; + continue; + + case 'c': /* -clientId */ + if (++i >= argc) goto usage; + client_id = argv[i]; + continue; + + case 'r': /* -restore */ + if (++i >= argc) goto usage; + restore_filename = argv[i]; + continue; + } + } + + usage: + + fprintf (stderr, + "usage: %s [-clientId id] [-restore file] [-debug]\n", argv[0]); + exit (1); + } + + + XtToolkitInitialize (); + appContext = XtCreateApplicationContext (); + + if (!(disp = XtOpenDisplay (appContext, NULL, "SM-PROXY", "SM-PROXY", + NULL, 0, &zero, NULL))) + { + fprintf (stderr, "smproxy: unable to open display\n"); + exit (1); + } + + if (restore_filename) + ReadProxyFile (restore_filename); + + if (!ConnectProxyToSM (client_id)) + { + fprintf (stderr, "smproxy: unable to connect to session manager\n"); + exit (1); + } + + root = DefaultRootWindow (disp); + + wmProtocolsAtom = XInternAtom (disp, "WM_PROTOCOLS", False); + wmSaveYourselfAtom = XInternAtom (disp, "WM_SAVE_YOURSELF", False); + wmStateAtom = XInternAtom (disp, "WM_STATE", False); + smClientIdAtom = XInternAtom (disp, "SM_CLIENT_ID", False); + wmClientLeaderAtom = XInternAtom (disp, "WM_CLIENT_LEADER", False); + + XSelectInput (disp, root, SubstructureNotifyMask | PropertyChangeMask); + + CheckForExistingWindows (); + + while (1) + { + XEvent event; + + XtAppNextEvent (appContext, &event); + + switch (event.type) + { + case CreateNotify: + HandleCreate (&event.xcreatewindow); + break; + + case DestroyNotify: + HandleDestroy (&event.xdestroywindow); + break; + + case PropertyNotify: + HandleUpdate (&event.xproperty); + break; + + default: + XtDispatchEvent (&event); + break; + } + } + } *** /dev/null Wed Jan 18 12:43:06 1995 --- xc/programs/smproxy/save.c Wed Jan 18 12:43:05 1995 *************** *** 0 **** --- 1,466 ---- + /* $XConsortium: save.c,v 1.5 94/12/30 15:38:08 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + + Author: Ralph Mor, X Consortium + ******************************************************************************/ + + #include "smproxy.h" + + typedef struct ProxyFileEntry + { + struct ProxyFileEntry *next; + int tag; + char *client_id; + XClassHint class; + char *wm_name; + int wm_command_count; + char **wm_command; + } ProxyFileEntry; + + ProxyFileEntry *proxyFileHead = NULL; + + extern WinInfo *win_head; + + + + static int + write_byte (file, b) + + FILE *file; + unsigned char b; + + { + if (fwrite ((char *) &b, 1, 1, file) != 1) + return 0; + return 1; + } + + + static int + write_short (file, s) + + FILE *file; + unsigned short s; + + { + unsigned char file_short[2]; + + file_short[0] = (s & (unsigned)0xff00) >> 8; + file_short[1] = s & 0xff; + if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) + return 0; + return 1; + } + + + static int + write_counted_string (file, string) + + FILE *file; + char *string; + + { + if (string) + { + unsigned char count = strlen (string); + + if (write_byte (file, count) == 0) + return 0; + if (fwrite (string, (int) sizeof (char), (int) count, file) != count) + return 0; + } + else + { + if (write_byte (file, 0) == 0) + return 0; + } + + return 1; + } + + + + static int + read_byte (file, bp) + + FILE *file; + unsigned char *bp; + + { + if (fread ((char *) bp, 1, 1, file) != 1) + return 0; + return 1; + } + + + static int + read_short (file, shortp) + + FILE *file; + unsigned short *shortp; + + { + unsigned char file_short[2]; + + if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) + return 0; + *shortp = file_short[0] * 256 + file_short[1]; + return 1; + } + + + static int + read_counted_string (file, stringp) + + FILE *file; + char **stringp; + + { + unsigned char len; + char *data; + + if (read_byte (file, &len) == 0) + return 0; + if (len == 0) { + data = 0; + } else { + data = (char *) malloc ((unsigned) len + 1); + if (!data) + return 0; + if (fread (data, (int) sizeof (char), (int) len, file) != len) { + free (data); + return 0; + } + data[len] = '\0'; + } + *stringp = data; + return 1; + } + + + + /* + * An entry in the .smproxy file looks like this: + * + * FIELD BYTES + * ----- ---- + * client ID len 1 + * client ID LIST of bytes + * WM_CLASS "res name" length 1 + * WM_CLASS "res name" LIST of bytes + * WM_CLASS "res class" length 1 + * WM_CLASS "res class" LIST of bytes + * WM_NAME length 1 + * WM_NAME LIST of bytes + * WM_COMMAND arg count 1 + * For each arg in WM_COMMAND + * arg length 1 + * arg LIST of bytes + */ + + int + WriteProxyFileEntry (proxyFile, theWindow) + + FILE *proxyFile; + WinInfo *theWindow; + + { + int i; + + if (!write_counted_string (proxyFile, theWindow->client_id)) + return 0; + if (!write_counted_string (proxyFile, theWindow->class.res_name)) + return 0; + if (!write_counted_string (proxyFile, theWindow->class.res_class)) + return 0; + if (!write_counted_string (proxyFile, theWindow->wm_name)) + return 0; + + if (!theWindow->wm_command || theWindow->wm_command_count == 0) + { + if (!write_byte (proxyFile, 0)) + return 0; + } + else + { + if (!write_byte (proxyFile, (char) theWindow->wm_command_count)) + return 0; + for (i = 0; i < theWindow->wm_command_count; i++) + if (!write_counted_string (proxyFile, theWindow->wm_command[i])) + return 0; + } + + return 1; + } + + + int + ReadProxyFileEntry (proxyFile, pentry) + + FILE *proxyFile; + ProxyFileEntry **pentry; + + { + ProxyFileEntry *entry; + char byte; + int i; + + *pentry = entry = (ProxyFileEntry *) malloc ( + sizeof (ProxyFileEntry)); + if (!*pentry) + return 0; + + entry->tag = 0; + entry->client_id = NULL; + entry->class.res_name = NULL; + entry->class.res_class = NULL; + entry->wm_name = NULL; + entry->wm_command = NULL; + entry->wm_command_count = 0; + + if (!read_counted_string (proxyFile, &entry->client_id)) + goto give_up; + if (!read_counted_string (proxyFile, &entry->class.res_name)) + goto give_up; + if (!read_counted_string (proxyFile, &entry->class.res_class)) + goto give_up; + if (!read_counted_string (proxyFile, &entry->wm_name)) + goto give_up; + + if (!read_byte (proxyFile, &byte)) + goto give_up; + entry->wm_command_count = byte; + + if (entry->wm_command_count == 0) + entry->wm_command = NULL; + else + { + entry->wm_command = (char **) malloc (entry->wm_command_count * + sizeof (char *)); + + if (!entry->wm_command) + goto give_up; + + for (i = 0; i < entry->wm_command_count; i++) + if (!read_counted_string (proxyFile, &entry->wm_command[i])) + goto give_up; + } + + return 1; + + give_up: + + if (entry->client_id) + free (entry->client_id); + if (entry->class.res_name) + free (entry->class.res_name); + if (entry->class.res_class) + free (entry->class.res_class); + if (entry->wm_name) + free (entry->wm_name); + if (entry->wm_command_count) + { + for (i = 0; i < entry->wm_command_count; i++) + if (entry->wm_command[i]) + free (entry->wm_command[i]); + } + if (entry->wm_command) + free ((char *) entry->wm_command); + + free ((char *) entry); + *pentry = NULL; + + return 0; + } + + + void + ReadProxyFile (filename) + + char *filename; + + { + FILE *proxyFile; + ProxyFileEntry *entry; + int done = 0; + unsigned short version; + + proxyFile = fopen (filename, "rb"); + if (!proxyFile) + return; + + if (!read_short (proxyFile, &version) || + version > SAVEFILE_VERSION) + { + done = 1; + } + + while (!done) + { + if (ReadProxyFileEntry (proxyFile, &entry)) + { + entry->next = proxyFileHead; + proxyFileHead = entry; + } + else + done = 1; + } + + fclose (proxyFile); + } + + + + 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 + } + + + + char * + WriteProxyFile () + + { + FILE *proxyFile = NULL; + char *filename = NULL; + char *path; + WinInfo *winptr; + Bool success = False; + + path = getenv ("SM_SAVE_DIR"); + if (!path) + { + path = getenv ("HOME"); + if (!path) + path = "."; + } + + if ((filename = unique_filename (path, ".prx")) == NULL) + goto bad; + + if (!(proxyFile = fopen (filename, "wb"))) + goto bad; + + if (!write_short (proxyFile, SAVEFILE_VERSION)) + goto bad; + + success = True; + winptr = win_head; + + while (winptr && success) + { + if (winptr->client_id) + if (!WriteProxyFileEntry (proxyFile, winptr)) + { + success = False; + break; + } + + winptr = winptr->next; + } + + bad: + + if (proxyFile) + fclose (proxyFile); + + if (success) + return (filename); + else + { + if (filename) + free (filename); + return (NULL); + } + } + + + + char * + LookupClientID (theWindow) + + WinInfo *theWindow; + + { + ProxyFileEntry *ptr; + int found = 0; + + ptr = proxyFileHead; + while (ptr && !found) + { + if (!ptr->tag && + strcmp (theWindow->class.res_name, ptr->class.res_name) == 0 && + strcmp (theWindow->class.res_class, ptr->class.res_class) == 0 && + strcmp (theWindow->wm_name, ptr->wm_name) == 0) + { + int i; + + if (theWindow->wm_command_count == ptr->wm_command_count) + { + for (i = 0; i < theWindow->wm_command_count; i++) + if (strcmp (theWindow->wm_command[i], + ptr->wm_command[i]) != 0) + break; + + if (i == theWindow->wm_command_count) + found = 1; + } + } + + if (!found) + ptr = ptr->next; + } + + if (found) + { + ptr->tag = 1; + return (ptr->client_id); + } + else + return NULL; + } *** /dev/null Wed Jan 18 12:43:07 1995 --- xc/programs/smproxy/smproxy.h Wed Jan 18 12:43:07 1995 *************** *** 0 **** --- 1,102 ---- + /* $XConsortium: smproxy.h,v 1.7 94/12/27 18:47:54 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + + Author: Ralph Mor, X Consortium + ******************************************************************************/ + + #include + #include + + #include + #include + #include + #include + #include + + #ifndef _POSIX_SOURCE + #define _POSIX_SOURCE + #include + #undef _POSIX_SOURCE + #else + #include + #endif + + #ifndef X_NOT_STDC_ENV + #include + #else + extern char *malloc(), *calloc(), *realloc(), *getenv(); + extern void free(); + #endif + + #ifndef X_NOT_POSIX + #ifdef _POSIX_SOURCE + #include + #else + #define _POSIX_SOURCE + #include + #undef _POSIX_SOURCE + #endif + #endif /* X_NOT_POSIX */ + #ifndef PATH_MAX + #include + #ifndef PATH_MAX + #ifdef MAXPATHLEN + #define PATH_MAX MAXPATHLEN + #else + #define PATH_MAX 1024 + #endif + #endif + #endif /* PATH_MAX */ + + + typedef struct WinInfo { + Window window; + SmcConn smc_conn; + XtInputId input_id; + char *client_id; + char **wm_command; + int wm_command_count; + XClassHint class; + char *wm_name; + XTextProperty wm_client_machine; + struct WinInfo *next; + + unsigned int tested_for_sm_client_id : 1; + unsigned int has_save_yourself : 1; + unsigned int waiting_for_update : 1; + unsigned int got_first_save_yourself : 1; + + } WinInfo; + + + extern int WriteProxyFileEntry (); + extern int ReadProxyFileEntry (); + extern void ReadProxyFile (); + extern char *WriteProxyFile (); + extern char *LookupClientID (); + + + #define SAVEFILE_VERSION 1 *** /dev/null Wed Jan 18 12:43:08 1995 --- xc/programs/smproxy/smproxy.man Wed Jan 18 12:43:08 1995 *************** *** 0 **** --- 1,74 ---- + .\" $XConsortium: smproxy.man,v 1.1 94/12/27 18:46:38 mor Exp $ + .\" Copyright (c) 1994 X Consortium + .\" + .\" Permission is hereby granted, free of charge, to any person obtaining + .\" a copy of this software and associated documentation files (the + .\" "Software"), to deal in the Software without restriction, including + .\" without limitation the rights to use, copy, modify, merge, publish, + .\" distribute, sublicense, and/or sell copies of the Software, and to + .\" permit persons to whom the Software is furnished to do so, subject to + .\" the following conditions: + .\" + .\" 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 X CONSORTIUM 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 X Consortium 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 X Consortium. + .TH XSM 1 "Release 6" "X Version 11" + .SH NAME + smproxy \- Session Manager Proxy + .SH SYNOPSIS + .B smproxy + [-clientId id] [-restore saveFile] + .SH OPTIONS + .TP 8 + .B \-clientId \fIid\fP + Specifies the session ID used by \fIsmproxy\fP in the previous session. + .TP 8 + .B \-restore \fIsaveFile\fP + Specifies the file used by \fIsmproxy\fP to save state in the previous session. + .SH DESCRIPTION + .PP + \fIsmproxy\fP allows X applications that do not support X11R6 session + management to participate in an X11R6 session. + .br + .sp + In order for \fIsmproxy\fP to act as a proxy for an X application, 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. + .SH SEE ALSO + xsm(1) + .SH AUTHOR + Ralph Mor, X Consortium + *** - Wed Jan 18 12:45:50 1995 --- xc/programs/twm/twm.c Wed Jan 18 12:45:50 1995 *************** *** 53,59 **** /*********************************************************************** * ! * $XConsortium: twm.c,v 1.130 94/04/17 20:38:23 kaleb Exp $ * * twm - "Tom's Window Manager" * --- 53,59 ---- /*********************************************************************** * ! * $XConsortium: twm.c,v 1.135 94/12/27 20:52:15 mor Exp $ * * twm - "Tom's Window Manager" * *************** *** 77,82 **** --- 77,85 ---- #include "iconmgr.h" #include #include + #include + + XtAppContext appContext; /* Xt application context */ Display *dpy; /* which display are we talking to */ Window ResizeWindow; /* the window we are resizing */ *************** *** 137,146 **** extern void assign_var_savecolor(); ! Atom TwmAtoms[8]; /* don't change the order of these strings */ ! static char* atom_names[8] = { "_MIT_PRIORITY_COLORS", "WM_CHANGE_STATE", "WM_STATE", --- 140,149 ---- extern void assign_var_savecolor(); ! Atom TwmAtoms[11]; /* don't change the order of these strings */ ! static char* atom_names[11] = { "_MIT_PRIORITY_COLORS", "WM_CHANGE_STATE", "WM_STATE", *************** *** 148,154 **** "WM_PROTOCOLS", "WM_TAKE_FOCUS", "WM_SAVE_YOURSELF", ! "WM_DELETE_WINDOW" }; /*********************************************************************** * --- 151,161 ---- "WM_PROTOCOLS", "WM_TAKE_FOCUS", "WM_SAVE_YOURSELF", ! "WM_DELETE_WINDOW", ! "SM_CLIENT_ID", ! "WM_CLIENT_LEADER", ! "WM_WINDOW_ROLE" ! }; /*********************************************************************** * *************** *** 171,176 **** --- 178,186 ---- XSetWindowAttributes attributes; /* attributes for create windows */ int numManaged, firstscrn, lastscrn, scrnum; extern ColormapWindow *CreateColormapWindow(); + int zero = 0; + char *restore_filename = NULL; + char *client_id = NULL; ProgramName = argv[0]; Argc = argc; *************** *** 194,199 **** --- 204,217 ---- case 'v': /* -verbose */ PrintErrorMessages = True; continue; + case 'c': /* -clientId */ + if (++i >= argc) goto usage; + client_id = argv[i]; + continue; + case 'r': /* -restore */ + if (++i >= argc) goto usage; + restore_filename = argv[i]; + continue; case 'q': /* -quiet */ PrintErrorMessages = False; continue; *************** *** 201,207 **** } usage: fprintf (stderr, ! "usage: %s [-display dpy] [-f file] [-s] [-q] [-v]\n", ProgramName); exit (1); } --- 219,225 ---- } usage: fprintf (stderr, ! "usage: %s [-display dpy] [-f file] [-s] [-q] [-v] [-clientId id] [-restore file]\n", ProgramName); exit (1); } *************** *** 225,231 **** NoClass.res_name = NoName; NoClass.res_class = NoName; ! if (!(dpy = XOpenDisplay(display_name))) { fprintf (stderr, "%s: unable to open display \"%s\"\n", ProgramName, XDisplayName(display_name)); exit (1); --- 243,253 ---- NoClass.res_name = NoName; NoClass.res_class = NoName; ! XtToolkitInitialize (); ! appContext = XtCreateApplicationContext (); ! ! if (!(dpy = XtOpenDisplay (appContext, display_name, "twm", "twm", ! NULL, 0, &zero, NULL))) { fprintf (stderr, "%s: unable to open display \"%s\"\n", ProgramName, XDisplayName(display_name)); exit (1); *************** *** 238,243 **** --- 260,268 ---- exit (1); } + if (restore_filename) + ReadWinConfigFile (restore_filename); + HasShape = XShapeQueryExtension (dpy, &ShapeEventBase, &ShapeErrorBase); HasSync = XSyncQueryExtension(dpy, &SyncEventBase, &SyncErrorBase); TwmContext = XUniqueContext(); *************** *** 551,556 **** --- 576,583 ---- ProgramName); exit (1); } + + (void) ConnectToSessionManager (client_id); RestartPreviousState = False; HandlingEvents = TRUE; *** - Wed Jan 18 12:45:58 1995 --- xc/programs/twm/twm.h Wed Jan 18 12:45:58 1995 *************** *** 55,61 **** /*********************************************************************** * ! * $XConsortium: twm.h,v 1.77 94/04/17 20:38:24 kaleb Exp $ * * twm include file * --- 55,61 ---- /*********************************************************************** * ! * $XConsortium: twm.h,v 1.84 94/12/27 19:05:22 mor Exp $ * * twm include file * *************** *** 71,82 **** #include #include #include #ifndef WithdrawnState #define WithdrawnState 0 #endif - typedef unsigned long Pixel; #define PIXEL_ALREADY_TYPEDEFED /* for Xmu/Drawing.h */ #ifdef SIGNALRETURNSINT --- 71,83 ---- #include #include #include + #include + #include #ifndef WithdrawnState #define WithdrawnState 0 #endif #define PIXEL_ALREADY_TYPEDEFED /* for Xmu/Drawing.h */ #ifdef SIGNALRETURNSINT *************** *** 306,313 **** --- 307,343 ---- Bool cursor_valid; int curs_x, curs_y; } ring; + + Bool nameChanged; /* did WM_NAME ever change? */ + + /* did the user ever change the width/height? {yes, no, or unknown} */ + + Bool widthEverChangedByUser; + Bool heightEverChangedByUser; + } TwmWindow; + + typedef struct TWMWinConfigEntry + { + struct TWMWinConfigEntry *next; + int tag; + char *client_id; + char *window_role; + XClassHint class; + char *wm_name; + int wm_command_count; + char **wm_command; + short x, y; + unsigned short width, height; + short icon_x, icon_y; + Bool iconified; + Bool icon_info_present; + Bool width_ever_changed_by_user; + Bool height_ever_changed_by_user; + } TWMWinConfigEntry; + + #define DoesWmTakeFocus (1L << 0) #define DoesWmSaveYourself (1L << 1) #define DoesWmDeleteWindow (1L << 2) *************** *** 333,338 **** --- 363,369 ---- void ComputeWindowTitleOffsets(), ComputeTitleLocation(); extern char *ProgramName; extern Display *dpy; + extern XtAppContext appContext; extern Window ResizeWindow; /* the window we are resizing */ extern int HasShape; /* this server supports Shape extension */ extern int HasSync; /* this server supports SYNC extension */ *************** *** 390,394 **** --- 421,428 ---- #define _XA_WM_TAKE_FOCUS TwmAtoms[5] #define _XA_WM_SAVE_YOURSELF TwmAtoms[6] #define _XA_WM_DELETE_WINDOW TwmAtoms[7] + #define _XA_SM_CLIENT_ID TwmAtoms[8] + #define _XA_WM_CLIENT_LEADER TwmAtoms[9] + #define _XA_WM_WINDOW_ROLE TwmAtoms[10] #endif /* _TWM_ */ *** - Wed Jan 18 12:46:14 1995 --- xc/programs/twm/add_window.c Wed Jan 18 12:46:13 1995 *************** *** 53,59 **** /********************************************************************** * ! * $XConsortium: add_window.c,v 1.156 94/04/17 20:38:03 dave Exp $ * * Add a new window, put the titlbar and other stuff around * the window --- 53,59 ---- /********************************************************************** * ! * $XConsortium: add_window.c,v 1.164 94/12/27 19:16:56 mor Exp $ * * Add a new window, put the titlbar and other stuff around * the window *************** *** 169,174 **** --- 169,181 ---- int gravx, gravy; /* gravity signs for positioning */ int namelen; int bw2; + short saved_x, saved_y, restore_icon_x, restore_icon_y; + unsigned short saved_width, saved_height; + Bool restore_iconified = 0; + Bool restore_icon_info_present = 0; + int restoredFromPrevSession; + Bool width_ever_changed_by_user; + Bool height_ever_changed_by_user; #ifdef DEBUG fprintf(stderr, "AddWindow: w = 0x%x\n", w); *************** *** 189,201 **** --- 196,239 ---- tmp_win->cmaps.number_cwins = 0; XSelectInput(dpy, tmp_win->w, PropertyChangeMask); + XGetWindowAttributes(dpy, tmp_win->w, &tmp_win->attr); + XFetchName(dpy, tmp_win->w, &tmp_win->name); tmp_win->class = NoClass; XGetClassHint(dpy, tmp_win->w, &tmp_win->class); FetchWmProtocols (tmp_win); FetchWmColormapWindows (tmp_win); + if (GetWindowConfig (tmp_win, + &saved_x, &saved_y, &saved_width, &saved_height, + &restore_iconified, &restore_icon_info_present, + &restore_icon_x, &restore_icon_y, + &width_ever_changed_by_user, &height_ever_changed_by_user)) + { + tmp_win->attr.x = saved_x; + tmp_win->attr.y = saved_y; + + tmp_win->widthEverChangedByUser = width_ever_changed_by_user; + tmp_win->heightEverChangedByUser = height_ever_changed_by_user; + + if (width_ever_changed_by_user) + tmp_win->attr.width = saved_width; + + if (height_ever_changed_by_user) + tmp_win->attr.height = saved_height; + + restoredFromPrevSession = 1; + } + else + { + tmp_win->widthEverChangedByUser = False; + tmp_win->heightEverChangedByUser = False; + + restoredFromPrevSession = 0; + } + + /* * do initial clip; should look at window gravity */ *************** *** 205,210 **** --- 243,265 ---- tmp_win->attr.height = Scr->MaxWindowHeight; tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w); + + if (tmp_win->wmhints) + { + if (restore_iconified) + { + tmp_win->wmhints->initial_state = IconicState; + tmp_win->wmhints->flags |= StateHint; + } + + if (restore_icon_info_present) + { + tmp_win->wmhints->icon_x = restore_icon_x; + tmp_win->wmhints->icon_y = restore_icon_y; + tmp_win->wmhints->flags |= IconPositionHint; + } + } + if (tmp_win->wmhints && (tmp_win->wmhints->flags & WindowGroupHint)) tmp_win->group = tmp_win->wmhints->window_group; else *************** *** 217,222 **** --- 272,278 ---- tmp_win->transient = Transient(tmp_win->w, &tmp_win->transientfor); + tmp_win->nameChanged = 0; if (tmp_win->name == NULL) tmp_win->name = NoName; if (tmp_win->class.res_name == NULL) *************** *** 320,326 **** } GetWindowSizeHints (tmp_win); ! GetGravityOffsets (tmp_win, &gravx, &gravy); /* * Don't bother user if: --- 376,395 ---- } GetWindowSizeHints (tmp_win); ! ! if (restoredFromPrevSession) ! { ! /* ! * When restoring window positions from the previous session, ! * we always use NorthWest gravity. ! */ ! ! gravx = gravy = -1; ! } ! else ! { ! GetGravityOffsets (tmp_win, &gravx, &gravy); ! } /* * Don't bother user if: *************** *** 343,349 **** /* * do any prompting for position */ ! if (HandlingEvents && ask_user) { if (Scr->RandomPlacement) { /* just stick it somewhere */ if ((PlaceX + tmp_win->attr.width) > Scr->MyDisplayWidth) PlaceX = 50; --- 412,418 ---- /* * do any prompting for position */ ! if (HandlingEvents && ask_user && !restoredFromPrevSession) { if (Scr->RandomPlacement) { /* just stick it somewhere */ if ((PlaceX + tmp_win->attr.width) > Scr->MyDisplayWidth) PlaceX = 50; *** - Wed Jan 18 12:46:17 1995 --- xc/programs/twm/resize.c Wed Jan 18 12:46:17 1995 *************** *** 53,59 **** /*********************************************************************** * ! * $XConsortium: resize.c,v 1.81 94/04/17 20:38:21 dave Exp $ * * window resizing borrowed from the "wm" window manager * --- 53,59 ---- /*********************************************************************** * ! * $XConsortium: resize.c,v 1.82 94/12/27 19:07:15 mor Exp $ * * window resizing borrowed from the "wm" window manager * *************** *** 900,905 **** --- 900,911 ---- XConfigureWindow(dpy, tmp_win->title_w, xwcm, &xwc); } + + if (tmp_win->attr.width != w) + tmp_win->widthEverChangedByUser = True; + + if (tmp_win->attr.height != (h - tmp_win->title_height)) + tmp_win->heightEverChangedByUser = True; tmp_win->attr.width = w; tmp_win->attr.height = h - tmp_win->title_height; *** - Wed Jan 18 12:46:19 1995 --- xc/programs/twm/menus.c Wed Jan 18 12:46:19 1995 *************** *** 53,59 **** /*********************************************************************** * ! * $XConsortium: menus.c,v 1.196 94/05/12 16:55:46 kaleb Exp $ * * twm menu code * --- 53,59 ---- /*********************************************************************** * ! * $XConsortium: menus.c,v 1.197 94/08/10 19:57:54 mor Exp $ * * twm menu code * *************** *** 76,81 **** --- 76,82 ---- #include #include "version.h" #include + #include extern XEvent Event; *************** *** 1427,1438 **** --- 1428,1445 ---- break; case F_RESTART: + { + extern SmcConn smcConn; + XSync (dpy, 0); Reborder (eventp->xbutton.time); XSync (dpy, 0); + if (smcConn) + SmcCloseConnection (smcConn, 0, NULL); execvp(*Argv, Argv); fprintf (stderr, "%s: unable to restart: %s\n", ProgramName, *Argv); break; + } case F_UPICONMGR: case F_DOWNICONMGR: *** - Wed Jan 18 12:46:25 1995 --- xc/programs/twm/events.c Wed Jan 18 12:46:24 1995 *************** *** 53,59 **** /*********************************************************************** * ! * $XConsortium: events.c,v 1.187 94/04/17 20:38:07 rws Exp $ * * twm event handling * --- 53,59 ---- /*********************************************************************** * ! * $XConsortium: events.c,v 1.190 94/07/21 17:46:35 mor Exp $ * * twm event handling * *************** *** 366,373 **** InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL); } WindowMoved = FALSE; ! XNextEvent(dpy, &Event); ! (void) DispatchEvent (); } } --- 366,376 ---- InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL); } WindowMoved = FALSE; ! XtAppNextEvent(appContext, &Event); ! if (Event.type>= 0 && Event.type < MAX_X_EVENT) ! (void) DispatchEvent (); ! else ! XtDispatchEvent (&Event); } } *************** *** 811,816 **** --- 814,821 ---- Tmp_win->full_name = prop; Tmp_win->name = prop; + Tmp_win->nameChanged = 1; + Tmp_win->name_width = XTextWidth (Scr->TitleBarFont.font, Tmp_win->name, strlen (Tmp_win->name)); *************** *** 1292,1297 **** --- 1297,1305 ---- if (Tmp_win->titlebuttons) /* 10 */ free ((char *) Tmp_win->titlebuttons); remove_window_from_ring (Tmp_win); /* 11 */ + + if (UnHighLight_win == Tmp_win) + UnHighLight_win = NULL; free((char *)Tmp_win); } *** - Wed Jan 18 12:46:32 1995 --- xc/programs/twm/Imakefile Wed Jan 18 12:46:32 1995 *************** *** 1,18 **** ! XCOMM $XConsortium: Imakefile,v 1.40 93/08/25 16:48:37 rws Exp $ YFLAGS = -d ! DEPLIBS = $(DEPXMULIB) $(DEPXLIB) ! LOCAL_LIBRARIES = $(XMULIB) $(XLIB) ! LINTLIBS = $(LINTXMU) $(LINTXLIB) DEFINES = $(SIGNAL_DEFINES) SRCS = gram.c lex.c deftwmrc.c add_window.c gc.c list.c twm.c \ parse.c menus.c events.c resize.c util.c version.c iconmgr.c \ ! cursor.c icons.c OBJS = gram.o lex.o deftwmrc.o add_window.o gc.o list.o twm.o \ parse.o menus.o events.o resize.o util.o version.o iconmgr.o \ ! cursor.o icons.o all:: --- 1,18 ---- ! XCOMM $XConsortium: Imakefile,v 1.41 94/07/06 16:15:19 mor Exp $ YFLAGS = -d ! DEPLIBS = $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB) ! LOCAL_LIBRARIES = $(XMULIB) $(XTOOLLIB) $(XLIB) ! LINTLIBS = $(LINTXMU) $(LINTXTOOLLIB) $(LINTXLIB) DEFINES = $(SIGNAL_DEFINES) SRCS = gram.c lex.c deftwmrc.c add_window.c gc.c list.c twm.c \ parse.c menus.c events.c resize.c util.c version.c iconmgr.c \ ! cursor.c icons.c session.c OBJS = gram.o lex.o deftwmrc.o add_window.o gc.o list.o twm.o \ parse.o menus.o events.o resize.o util.o version.o iconmgr.o \ ! cursor.o icons.o session.o all:: *** /dev/null Wed Jan 18 12:46:35 1995 --- xc/programs/twm/session.c Wed Jan 18 12:46:35 1995 *************** *** 0 **** --- 1,1057 ---- + /* $XConsortium: session.c,v 1.18 95/01/04 22:28:37 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + + Author: Ralph Mor, X Consortium + ******************************************************************************/ + + #include + + #ifndef X_NOT_POSIX + #ifdef _POSIX_SOURCE + #include + #else + #define _POSIX_SOURCE + #include + #undef _POSIX_SOURCE + #endif + #endif /* X_NOT_POSIX */ + #ifndef PATH_MAX + #include + #ifndef PATH_MAX + #ifdef MAXPATHLEN + #define PATH_MAX MAXPATHLEN + #else + #define PATH_MAX 1024 + #endif + #endif + #endif /* PATH_MAX */ + + #include + #include + #include + #include + #include "twm.h" + #include "screen.h" + + SmcConn smcConn = NULL; + XtInputId iceInputId; + char *twm_clientId; + TWMWinConfigEntry *winConfigHead = NULL; + Bool gotFirstSave = 0; + Bool sent_save_done = 0; + + #define SAVEFILE_VERSION 2 + + + + char * + GetClientID (window) + + Window window; + + { + char *client_id = NULL; + Window client_leader; + XTextProperty tp; + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long nbytes; + unsigned long bytes_after; + unsigned char *prop = NULL; + + if (XGetWindowProperty (dpy, window, _XA_WM_CLIENT_LEADER, + 0L, 1L, False, AnyPropertyType, &actual_type, &actual_format, + &nitems, &bytes_after, &prop) == Success) + { + if (actual_type == XA_WINDOW && actual_format == 32 && + nitems == 1 && bytes_after == 0) + { + client_leader = *((Window *) prop); + + if (XGetTextProperty (dpy, client_leader, &tp, _XA_SM_CLIENT_ID)) + { + if (tp.encoding == XA_STRING && + tp.format == 8 && tp.nitems != 0) + client_id = (char *) tp.value; + } + } + + if (prop) + XFree (prop); + } + + return client_id; + } + + + + char * + GetWindowRole (window) + + Window window; + + { + XTextProperty tp; + + if (XGetTextProperty (dpy, window, &tp, _XA_WM_WINDOW_ROLE)) + { + if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0) + return ((char *) tp.value); + } + + return NULL; + } + + + + int + write_byte (file, b) + + FILE *file; + unsigned char b; + + { + if (fwrite ((char *) &b, 1, 1, file) != 1) + return 0; + return 1; + } + + + int + write_ushort (file, s) + + FILE *file; + unsigned short s; + + { + unsigned char file_short[2]; + + file_short[0] = (s & (unsigned)0xff00) >> 8; + file_short[1] = s & 0xff; + if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) + return 0; + return 1; + } + + + int + write_short (file, s) + + FILE *file; + short s; + + { + unsigned char file_short[2]; + + file_short[0] = (s & (unsigned)0xff00) >> 8; + file_short[1] = s & 0xff; + if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) + return 0; + return 1; + } + + + int + write_counted_string (file, string) + + FILE *file; + char *string; + + { + if (string) + { + unsigned char count = strlen (string); + + if (write_byte (file, count) == 0) + return 0; + if (fwrite (string, (int) sizeof (char), (int) count, file) != count) + return 0; + } + else + { + if (write_byte (file, 0) == 0) + return 0; + } + + return 1; + } + + + + int + read_byte (file, bp) + + FILE *file; + unsigned char *bp; + + { + if (fread ((char *) bp, 1, 1, file) != 1) + return 0; + return 1; + } + + + int + read_ushort (file, shortp) + + FILE *file; + unsigned short *shortp; + + { + unsigned char file_short[2]; + + if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) + return 0; + *shortp = file_short[0] * 256 + file_short[1]; + return 1; + } + + + int + read_short (file, shortp) + + FILE *file; + short *shortp; + + { + unsigned char file_short[2]; + + if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) + return 0; + *shortp = file_short[0] * 256 + file_short[1]; + return 1; + } + + + int + read_counted_string (file, stringp) + + FILE *file; + char **stringp; + + { + unsigned char len; + char *data; + + if (read_byte (file, &len) == 0) + return 0; + if (len == 0) { + data = 0; + } else { + data = malloc ((unsigned) len + 1); + if (!data) + return 0; + if (fread (data, (int) sizeof (char), (int) len, file) != len) { + free (data); + return 0; + } + data[len] = '\0'; + } + *stringp = data; + return 1; + } + + + + /* + * An entry in the saved window config file looks like this: + * + * FIELD BYTES + * ----- ---- + * SM_CLIENT_ID ID len 1 (may be 0) + * SM_CLIENT_ID LIST of bytes (may be NULL) + * + * WM_WINDOW_ROLE length 1 (may be 0) + * WM_WINDOW_ROLE LIST of bytes (may be NULL) + * + * if no WM_WINDOW_ROLE (length = 0) + * + * WM_CLASS "res name" length 1 + * WM_CLASS "res name" LIST of bytes + * WM_CLASS "res class" length 1 + * WM_CLASS "res class" LIST of bytes + * WM_NAME length 1 (0 if name changed) + * WM_NAME LIST of bytes + * WM_COMMAND arg count 1 (0 if no SM_CLIENT_ID) + * For each arg in WM_COMMAND + * arg length 1 + * arg LIST of bytes + * + * Iconified bool 1 + * Icon info present bool 1 + * + * if icon info present + * icon x 2 + * icon y 2 + * + * Geom x 2 + * Geom y 2 + * Geom width 2 + * Geom height 2 + * + * Width ever changed by user 1 + * Height ever changed by user 1 + */ + + int + WriteWinConfigEntry (configFile, theWindow, clientId, windowRole) + + FILE *configFile; + TwmWindow *theWindow; + char *clientId; + char *windowRole; + + { + char **wm_command; + int wm_command_count, i; + + if (!write_counted_string (configFile, clientId)) + return 0; + + if (!write_counted_string (configFile, windowRole)) + return 0; + + if (!windowRole) + { + if (!write_counted_string (configFile, theWindow->class.res_name)) + return 0; + if (!write_counted_string (configFile, theWindow->class.res_class)) + return 0; + if (theWindow->nameChanged) + { + /* + * If WM_NAME changed on this window, we can't use it as + * a criteria for looking up window configurations. See the + * longer explanation in the GetWindowConfig() function below. + */ + + if (!write_counted_string (configFile, NULL)) + return 0; + } + else + { + if (!write_counted_string (configFile, theWindow->name)) + return 0; + } + + wm_command = NULL; + wm_command_count = 0; + XGetCommand (dpy, theWindow->w, &wm_command, &wm_command_count); + + if (clientId || !wm_command || wm_command_count == 0) + { + if (!write_byte (configFile, 0)) + return 0; + } + else + { + if (!write_byte (configFile, (char) wm_command_count)) + return 0; + for (i = 0; i < wm_command_count; i++) + if (!write_counted_string (configFile, wm_command[i])) + return 0; + XFreeStringList (wm_command); + } + } + + if (!write_byte (configFile, theWindow->icon ? 1 : 0)) /* iconified */ + return 0; + + if (!write_byte (configFile, theWindow->icon_w ? 1 : 0)) /* icon exists */ + return 0; + + if (theWindow->icon_w) + { + int icon_x, icon_y; + + XGetGeometry (dpy, theWindow->icon_w, &JunkRoot, &icon_x, + &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth); + + if (!write_short (configFile, (short) icon_x)) + return 0; + if (!write_short (configFile, (short) icon_y)) + return 0; + } + + if (!write_short (configFile, (short) theWindow->frame_x)) + return 0; + if (!write_short (configFile, (short) theWindow->frame_y)) + return 0; + if (!write_ushort (configFile, (unsigned short) theWindow->attr.width)) + return 0; + if (!write_ushort (configFile, (unsigned short) theWindow->attr.height)) + return 0; + + if (!write_byte (configFile, theWindow->widthEverChangedByUser ? 1 : 0)) + return 0; + + if (!write_byte (configFile, theWindow->heightEverChangedByUser ? 1 : 0)) + return 0; + + return 1; + } + + + int + ReadWinConfigEntry (configFile, version, pentry) + + FILE *configFile; + unsigned short version; + TWMWinConfigEntry **pentry; + + { + TWMWinConfigEntry *entry; + unsigned char byte; + int i; + + *pentry = entry = (TWMWinConfigEntry *) malloc ( + sizeof (TWMWinConfigEntry)); + if (!*pentry) + return 0; + + entry->tag = 0; + entry->client_id = NULL; + entry->window_role = NULL; + entry->class.res_name = NULL; + entry->class.res_class = NULL; + entry->wm_name = NULL; + entry->wm_command = NULL; + entry->wm_command_count = 0; + + if (!read_counted_string (configFile, &entry->client_id)) + goto give_up; + + if (!read_counted_string (configFile, &entry->window_role)) + goto give_up; + + if (!entry->window_role) + { + if (!read_counted_string (configFile, &entry->class.res_name)) + goto give_up; + if (!read_counted_string (configFile, &entry->class.res_class)) + goto give_up; + if (!read_counted_string (configFile, &entry->wm_name)) + goto give_up; + + if (!read_byte (configFile, &byte)) + goto give_up; + entry->wm_command_count = byte; + + if (entry->wm_command_count == 0) + entry->wm_command = NULL; + else + { + entry->wm_command = (char **) malloc (entry->wm_command_count * + sizeof (char *)); + + if (!entry->wm_command) + goto give_up; + + for (i = 0; i < entry->wm_command_count; i++) + if (!read_counted_string (configFile, &entry->wm_command[i])) + goto give_up; + } + } + + if (!read_byte (configFile, &byte)) + goto give_up; + entry->iconified = byte; + + if (!read_byte (configFile, &byte)) + goto give_up; + entry->icon_info_present = byte; + + if (entry->icon_info_present) + { + if (!read_short (configFile, (short *) &entry->icon_x)) + goto give_up; + if (!read_short (configFile, (short *) &entry->icon_y)) + goto give_up; + } + + if (!read_short (configFile, (short *) &entry->x)) + goto give_up; + if (!read_short (configFile, (short *) &entry->y)) + goto give_up; + if (!read_ushort (configFile, &entry->width)) + goto give_up; + if (!read_ushort (configFile, &entry->height)) + goto give_up; + + if (version > 1) + { + if (!read_byte (configFile, &byte)) + goto give_up; + entry->width_ever_changed_by_user = byte; + + if (!read_byte (configFile, &byte)) + goto give_up; + entry->height_ever_changed_by_user = byte; + } + else + { + entry->width_ever_changed_by_user = False; + entry->height_ever_changed_by_user = False; + } + + return 1; + + give_up: + + if (entry->client_id) + free (entry->client_id); + if (entry->window_role) + free (entry->window_role); + if (entry->class.res_name) + free (entry->class.res_name); + if (entry->class.res_class) + free (entry->class.res_class); + if (entry->wm_name) + free (entry->wm_name); + if (entry->wm_command_count) + { + for (i = 0; i < entry->wm_command_count; i++) + if (entry->wm_command[i]) + free (entry->wm_command[i]); + } + if (entry->wm_command) + free ((char *) entry->wm_command); + + free ((char *) entry); + *pentry = NULL; + + return 0; + } + + + void + ReadWinConfigFile (filename) + + char *filename; + + { + FILE *configFile; + TWMWinConfigEntry *entry; + int done = 0; + unsigned short version; + + configFile = fopen (filename, "rb"); + if (!configFile) + return; + + if (!read_ushort (configFile, &version) || + version > SAVEFILE_VERSION) + { + done = 1; + } + + while (!done) + { + if (ReadWinConfigEntry (configFile, version, &entry)) + { + entry->next = winConfigHead; + winConfigHead = entry; + } + else + done = 1; + } + + fclose (configFile); + } + + + + int + GetWindowConfig (theWindow, x, y, width, height, + iconified, icon_info_present, icon_x, icon_y, + width_ever_changed_by_user, height_ever_changed_by_user) + + TwmWindow *theWindow; + short *x, *y; + unsigned short *width, *height; + Bool *iconified; + Bool *icon_info_present; + short *icon_x, *icon_y; + Bool *width_ever_changed_by_user; + Bool *height_ever_changed_by_user; + + { + char *clientId, *windowRole; + TWMWinConfigEntry *ptr; + int found = 0; + + ptr = winConfigHead; + + if (!ptr) + return 0; + + clientId = GetClientID (theWindow->w); + windowRole = GetWindowRole (theWindow->w); + + while (ptr && !found) + { + int client_id_match = (!clientId && !ptr->client_id) || + (clientId && ptr->client_id && + strcmp (clientId, ptr->client_id) == 0); + + if (!ptr->tag && client_id_match) + { + if (windowRole || ptr->window_role) + { + found = (windowRole && ptr->window_role && + strcmp (windowRole, ptr->window_role) == 0); + } + else + { + /* + * Compare WM_CLASS + only compare WM_NAME if the + * WM_NAME in the saved file is non-NULL. If the + * WM_NAME in the saved file is NULL, this means that + * the client changed the value of WM_NAME during the + * session, and we can not use it as a criteria for + * our search. For example, with xmh, at save time + * the window name might be "xmh: folderY". However, + * if xmh does not properly restore state when it is + * restarted, the initial window name might be + * "xmh: folderX". This would cause the window manager + * to fail in finding the saved window configuration. + * The best we can do is ignore WM_NAME if its value + * changed in the previous session. + */ + + if (strcmp (theWindow->class.res_name, + ptr->class.res_name) == 0 && + strcmp (theWindow->class.res_class, + ptr->class.res_class) == 0 && + (ptr->wm_name == NULL || + strcmp (theWindow->name, ptr->wm_name) == 0)) + { + if (clientId) + { + /* + * If a client ID was present, we should not check + * WM_COMMAND because Xt will put a -xtsessionID arg + * on the command line. + */ + + found = 1; + } + else + { + /* + * For non-XSMP clients, also check WM_COMMAND. + */ + + char **wm_command = NULL; + int wm_command_count = 0, i; + + XGetCommand (dpy, theWindow->w, + &wm_command, &wm_command_count); + + if (wm_command_count == ptr->wm_command_count) + { + for (i = 0; i < wm_command_count; i++) + if (strcmp (wm_command[i], + ptr->wm_command[i]) != 0) + break; + + if (i == wm_command_count) + found = 1; + } + } + } + } + } + + if (!found) + ptr = ptr->next; + } + + if (found) + { + *x = ptr->x; + *y = ptr->y; + *width = ptr->width; + *height = ptr->height; + *iconified = ptr->iconified; + *icon_info_present = ptr->icon_info_present; + *width_ever_changed_by_user = ptr->width_ever_changed_by_user; + *height_ever_changed_by_user = ptr->height_ever_changed_by_user; + + if (*icon_info_present) + { + *icon_x = ptr->icon_x; + *icon_y = ptr->icon_y; + } + ptr->tag = 1; + } + else + *iconified = 0; + + if (clientId) + XFree (clientId); + + if (windowRole) + XFree (windowRole); + + return found; + } + + + + static char * + unique_filename (path, prefix) + + char *path; + char *prefix; + + { + #ifndef X_NOT_POSIX + return ((char *) tempnam (path, prefix)); + #else + char tempFile[PATH_MAX]; + char *tmp; + + sprintf (tempFile, "%s/%sXXXXXX", path, prefix); + tmp = (char *) mktemp (tempFile); + if (tmp) + { + char *ptr = (char *) malloc (strlen (tmp) + 1); + strcpy (ptr, tmp); + return (ptr); + } + else + return (NULL); + #endif + } + + + + void + SaveYourselfPhase2CB (smcConn, clientData) + + SmcConn smcConn; + SmPointer clientData; + + { + int scrnum; + ScreenInfo *theScreen; + TwmWindow *theWindow; + char *clientId, *windowRole; + FILE *configFile = NULL; + char *path; + char *filename = NULL; + Bool success = False; + SmProp prop1, prop2, prop3, *props[3]; + SmPropValue prop1val, prop2val, prop3val; + char discardCommand[80]; + int numVals, i; + char yes = 1; + static int first_time = 1; + + if (first_time) + { + char userId[20]; + char hint = SmRestartIfRunning; + + prop1.name = SmProgram; + prop1.type = SmARRAY8; + prop1.num_vals = 1; + prop1.vals = &prop1val; + prop1val.value = Argv[0]; + prop1val.length = strlen (Argv[0]); + + sprintf (userId, "%d", getuid()); + prop2.name = SmUserID; + prop2.type = SmARRAY8; + prop2.num_vals = 1; + prop2.vals = &prop2val; + prop2val.value = (SmPointer) userId; + prop2val.length = strlen (userId); + + prop3.name = SmRestartStyleHint; + prop3.type = SmCARD8; + prop3.num_vals = 1; + prop3.vals = &prop3val; + prop3val.value = (SmPointer) &hint; + prop3val.length = 1; + + props[0] = &prop1; + props[1] = &prop2; + props[2] = &prop3; + + SmcSetProperties (smcConn, 3, props); + + first_time = 0; + } + + path = getenv ("SM_SAVE_DIR"); + if (!path) + { + path = getenv ("HOME"); + if (!path) + path = "."; + } + + if ((filename = unique_filename (path, ".twm")) == NULL) + goto bad; + + if (!(configFile = fopen (filename, "wb"))) + goto bad; + + if (!write_ushort (configFile, SAVEFILE_VERSION)) + goto bad; + + success = True; + + for (scrnum = 0; scrnum < NumScreens && success; scrnum++) + { + if (ScreenList[scrnum] != NULL) + { + theScreen = ScreenList[scrnum]; + theWindow = theScreen->TwmRoot.next; + + while (theWindow && success) + { + clientId = GetClientID (theWindow->w); + windowRole = GetWindowRole (theWindow->w); + + if (!WriteWinConfigEntry (configFile, theWindow, + clientId, windowRole)) + success = False; + + if (clientId) + XFree (clientId); + + if (windowRole) + XFree (windowRole); + + theWindow = theWindow->next; + } + } + } + + prop1.name = SmRestartCommand; + prop1.type = SmLISTofARRAY8; + + prop1.vals = (SmPropValue *) malloc ( + (Argc + 4) * sizeof (SmPropValue)); + + if (!prop1.vals) + { + success = False; + goto bad; + } + + numVals = 0; + + for (i = 0; i < Argc; i++) + { + if (strcmp (Argv[i], "-clientId") == 0 || + strcmp (Argv[i], "-restore") == 0) + { + i++; + } + else + { + prop1.vals[numVals].value = (SmPointer) Argv[i]; + prop1.vals[numVals++].length = strlen (Argv[i]); + } + } + + prop1.vals[numVals].value = (SmPointer) "-clientId"; + prop1.vals[numVals++].length = 9; + + prop1.vals[numVals].value = (SmPointer) twm_clientId; + prop1.vals[numVals++].length = strlen (twm_clientId); + + prop1.vals[numVals].value = (SmPointer) "-restore"; + prop1.vals[numVals++].length = 8; + + prop1.vals[numVals].value = (SmPointer) filename; + prop1.vals[numVals++].length = strlen (filename); + + prop1.num_vals = numVals; + + sprintf (discardCommand, "rm %s", filename); + prop2.name = SmDiscardCommand; + prop2.type = SmARRAY8; + prop2.num_vals = 1; + prop2.vals = &prop2val; + prop2val.value = (SmPointer) discardCommand; + prop2val.length = strlen (discardCommand); + + props[0] = &prop1; + props[1] = &prop2; + + SmcSetProperties (smcConn, 2, props); + free ((char *) prop1.vals); + + bad: + SmcSaveYourselfDone (smcConn, success); + sent_save_done = 1; + + if (configFile) + fclose (configFile); + + if (filename) + free (filename); + } + + + + void + SaveYourselfCB (smcConn, clientData, saveType, shutdown, interactStyle, fast) + + SmcConn smcConn; + SmPointer clientData; + int saveType; + Bool shutdown; + int interactStyle; + Bool fast; + + { + if (!SmcRequestSaveYourselfPhase2 (smcConn, SaveYourselfPhase2CB, NULL)) + { + SmcSaveYourselfDone (smcConn, False); + sent_save_done = 1; + } + else + sent_save_done = 0; + } + + + + void + DieCB (smcConn, clientData) + + SmcConn smcConn; + SmPointer clientData; + + { + SmcCloseConnection (smcConn, 0, NULL); + XtRemoveInput (iceInputId); + Done(); + } + + + + void + SaveCompleteCB (smcConn, clientData) + + SmcConn smcConn; + SmPointer clientData; + + { + ; + } + + + + void + ShutdownCancelledCB (smcConn, clientData) + + SmcConn smcConn; + SmPointer clientData; + + { + if (!sent_save_done) + { + SmcSaveYourselfDone (smcConn, False); + sent_save_done = 1; + } + } + + + + void + ProcessIceMsgProc (client_data, source, id) + + XtPointer client_data; + int *source; + XtInputId *id; + + { + IceConn ice_conn = (IceConn) client_data; + + IceProcessMessages (ice_conn, NULL, NULL); + } + + + + void + ConnectToSessionManager (previous_id) + + char *previous_id; + + { + char errorMsg[256]; + unsigned long mask; + SmcCallbacks callbacks; + IceConn iceConn; + + mask = SmcSaveYourselfProcMask | SmcDieProcMask | + SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask; + + callbacks.save_yourself.callback = SaveYourselfCB; + callbacks.save_yourself.client_data = (SmPointer) NULL; + + callbacks.die.callback = DieCB; + callbacks.die.client_data = (SmPointer) NULL; + + callbacks.save_complete.callback = SaveCompleteCB; + callbacks.save_complete.client_data = (SmPointer) NULL; + + callbacks.shutdown_cancelled.callback = ShutdownCancelledCB; + callbacks.shutdown_cancelled.client_data = (SmPointer) NULL; + + smcConn = SmcOpenConnection ( + NULL, /* use SESSION_MANAGER env */ + (SmPointer) appContext, + SmProtoMajor, + SmProtoMinor, + mask, + &callbacks, + previous_id, + &twm_clientId, + 256, errorMsg); + + if (smcConn == NULL) + return; + + iceConn = SmcGetIceConnection (smcConn); + + iceInputId = XtAppAddInput ( + appContext, + IceConnectionNumber (iceConn), + (XtPointer) XtInputReadMask, + ProcessIceMsgProc, + (XtPointer) iceConn); + } + + + *** - Wed Jan 25 10:00:44 1995 --- xc/programs/xmh/main.c Wed Jan 25 10:00:43 1995 *************** *** 1,4 **** ! /* $XConsortium: main.c,v 2.28 91/07/22 21:50:02 converse Exp $ * * * COPYRIGHT 1987, 1989 --- 1,4 ---- ! /* $XConsortium: main.c,v 2.30 95/01/25 14:33:57 swick Exp $ * * * COPYRIGHT 1987, 1989 *** - Tue Jan 24 15:34:07 1995 --- xc/programs/xmh/folder.c Tue Jan 24 15:34:07 1995 *************** *** 1,5 **** /* ! * $XConsortium: folder.c,v 2.42 93/12/06 15:19:14 kaleb Exp $ * * * COPYRIGHT 1987, 1989 --- 1,5 ---- /* ! * $XConsortium: folder.c,v 2.44 94/08/29 20:25:49 swick Exp $ * * * COPYRIGHT 1987, 1989 *************** *** 98,108 **** --- 98,110 ---- * CmdSetSequence(toc, "cur", MakeSingleMsgList(toc->curmsg)); * } */ + #ifdef DEBUG_CLEANUP XtDestroyWidget(scrn->parent); ExitLoop = TRUE; return; #else + XtVaSetValues(scrn->parent, XtNjoinSession, (XtArgVal)False, NULL); XtUnmapWidget(scrn->parent); XtDestroyApplicationContext (XtWidgetToApplicationContext(scrn->parent)); *************** *** 974,979 **** --- 976,1183 ---- case STpick: DestroyScrn(scrn); break; + } + } + } + + + typedef struct _InteractMsgTokenRec { + Scrn scrn; + XtCheckpointToken cp_token; + } InteractMsgTokenRec, *InteractMsgToken; + + static void CommitMsgChanges(w, client_data, call_data) + Widget w; /* unused */ + XtPointer client_data; /* InteractMsgToken */ + XtPointer call_data; + { + Cardinal zero = 0; + InteractMsgToken iToken = (InteractMsgToken) client_data; + + XmhSave(iToken->scrn->parent, (XEvent*)NULL, (String*)NULL, &zero); + + if (MsgChanged(iToken->scrn->msg)) + iToken->cp_token->save_success = False; + + XtSessionReturnToken(iToken->cp_token); + XtFree((XtPointer)iToken); + } + + static void CancelMsgChanges(w, client_data, call_data) + Widget w; /* unused */ + XtPointer client_data; /* InteractMsgToken */ + XtPointer call_data; + { + InteractMsgToken iToken = (InteractMsgToken) client_data; + + /* don't change any msg state now; this is only a checkpoint + * and the session might be continuing. */ + + MsgCheckPoint(iToken->scrn->msg); + + XtSessionReturnToken(iToken->cp_token); + XtFree((XtPointer)iToken); + } + + static void CommitMsgInteract(w, client_data, call_data) + Widget w; /* unused */ + XtPointer client_data; /* Scrn */ + XtPointer call_data; /* XtCheckpointToken */ + { + Scrn scrn = (Scrn) client_data; + XtCheckpointToken cpToken = (XtCheckpointToken) call_data; + char str[300]; + InteractMsgToken iToken; + static XtCallbackRec yes_callbacks[] = { + {CommitMsgChanges, (XtPointer) NULL}, + {(XtCallbackProc) NULL, (XtPointer) NULL} + }; + + static XtCallbackRec no_callbacks[] = { + {CancelMsgChanges, (XtPointer) NULL}, + {(XtCallbackProc) NULL, (XtPointer) NULL} + }; + + if (cpToken->interact_style != SmInteractStyleAny + || cpToken->cancel_shutdown) { + XtSessionReturnToken(cpToken); + return; + } + + iToken = XtNew(InteractMsgTokenRec); + + iToken->scrn = scrn; + iToken->cp_token = cpToken; + + yes_callbacks[0].closure = no_callbacks[0].closure = (XtPointer) iToken; + + (void)sprintf(str,"Save changes to message %s?", MsgName(scrn->msg)); + + /* %%% should add cancel button */ + PopupConfirm(scrn->parent, str, yes_callbacks, no_callbacks); + } + + + typedef struct _InteractTocTokenRec { + Toc toc; + XtCheckpointToken cp_token; + } InteractTocTokenRec, *InteractTocToken; + + static void CommitTocChanges(w, client_data, call_data) + Widget w; /* unused */ + XtPointer client_data; /* InteractTocToken */ + XtPointer call_data; + { + InteractTocToken iToken = (InteractTocToken) client_data; + + TocCommitChanges(w, (XtPointer) iToken->toc, (XtPointer) NULL); + + XtSessionReturnToken(iToken->cp_token); + XtFree((XtPointer)iToken); + } + + static void CancelTocChanges(w, client_data, call_data) + Widget w; /* unused */ + XtPointer client_data; /* InteractTocToken */ + XtPointer call_data; + { + InteractTocToken iToken = (InteractTocToken) client_data; + + /* don't change any folder or msg state now; this is only + * a checkpoint and the session might be continuing. */ + + XtSessionReturnToken(iToken->cp_token); + XtFree((XtPointer)iToken); + } + + static void CommitTocInteract(w, client_data, call_data) + Widget w; /* unused */ + XtPointer client_data; /* Toc */ + XtPointer call_data; /* XtCheckpointToken */ + { + Toc toc = (Toc) client_data; + XtCheckpointToken cpToken = (XtCheckpointToken) call_data; + char str[300]; + Widget tocwidget; + int i; + InteractTocToken iToken; + static XtCallbackRec yes_callbacks[] = { + {CommitTocChanges, (XtPointer) NULL}, + {(XtCallbackProc) NULL, (XtPointer) NULL} + }; + + static XtCallbackRec no_callbacks[] = { + {CancelTocChanges, (XtPointer) NULL}, + {(XtCallbackProc) NULL, (XtPointer) NULL} + }; + + if (cpToken->interact_style != SmInteractStyleAny + || cpToken->cancel_shutdown) { + XtSessionReturnToken(cpToken); + return; + } + + iToken = XtNew(InteractTocTokenRec); + + iToken->toc = toc; + iToken->cp_token = cpToken; + + yes_callbacks[0].closure = no_callbacks[0].closure = (XtPointer) iToken; + + (void)sprintf(str,"Commit all changes to %s folder?", toc->foldername); + + tocwidget = NULL; + for (i=0; i < toc->num_scrns; i++) + if (toc->scrn[i]->mapped) { + tocwidget = toc->scrn[i]->tocwidget; + break; + } + + /* %%% should add cancel button */ + PopupConfirm(tocwidget, str, yes_callbacks, no_callbacks); + } + + /* Callback for Session Manager SaveYourself */ + + /*ARGSUSED*/ + void DoSaveYourself(w, client_data, call_data) + Widget w; /* unused; s/b toplevel */ + XtPointer client_data; /* unused */ + XtPointer call_data; /* XtCheckpointToken */ + { + XtCheckpointToken cpToken = (XtCheckpointToken)call_data; + + { /* confirm any uncommitted msg changes */ + int i; + for (i=0 ; imsg)) { + if (cpToken->interact_style == SmInteractStyleAny) + XtAddCallback(toplevel, XtNinteractCallback, + CommitMsgInteract, (XtPointer)scrnList[i]); + else { + Cardinal zero = 0; + XmhSave(scrnList[i]->parent, (XEvent*)NULL, + (String*)NULL, &zero); + if (MsgChanged(scrnList[i]->msg)) { + MsgCheckPoint(scrnList[i]->msg); + cpToken->save_success = False; + } + } + } + } + } + + { /* confirm any uncommitted folder changes */ + int i; + for (i = 0; i < numFolders; i++) { + if (TocHasChanges(folderList[i])) { + if (cpToken->interact_style == SmInteractStyleAny) + XtAddCallback(toplevel, XtNinteractCallback, + CommitTocInteract, (XtPointer)folderList[i]); + else + TocCommitChanges(w, (XtPointer)folderList[i], + (XtPointer) NULL); + } } } } *** - Tue Jan 24 15:34:08 1995 --- xc/programs/xmh/externs.h Tue Jan 24 15:34:08 1995 *************** *** 1,5 **** /* ! * $XConsortium: externs.h,v 2.39 93/09/20 17:52:05 hersh Exp $ * * * COPYRIGHT 1987, 1989 --- 1,5 ---- /* ! * $XConsortium: externs.h,v 2.40 94/08/26 18:07:47 swick Exp $ * * * COPYRIGHT 1987, 1989 *************** *** 56,61 **** --- 56,62 ---- extern void DoOpenFolderInNewWindow (/* Widget, XtPointer, XtPointer */); extern void DoCreateFolder (/* Widget, XtPointer, XtPointer */); extern void DoDeleteFolder (/* Widget, XtPointer, XtPointer */); + extern void DoSaveYourself (/* Widget, XtPointer, XtPointer */); extern void Push (/* Stack, char* */); extern char * Pop (/* Stack */); *************** *** 70,75 **** --- 71,77 ---- /* from msg.c */ extern Widget CreateFileSource (/* Widget, String, Boolean */); + extern char* MsgName (/* Msg */); /* from popup.c */ *************** *** 91,96 **** --- 93,102 ---- extern void DestroyScrn (/* Scrn */); extern void MapScrn (/* Scrn */); extern Scrn ScrnFromWidget (/* Widget */); + + /* from toc.c */ + + extern Boolean TocHasChanges (/* Toc */); /* from tocfuncs.c */ *** - Tue Jan 24 15:34:09 1995 --- xc/programs/xmh/tocutil.h Tue Jan 24 15:34:09 1995 *************** *** 1,4 **** ! /* $XConsortium: tocutil.h,v 2.6 89/12/10 17:30:14 converse Exp $ */ /* * COPYRIGHT 1987 * DIGITAL EQUIPMENT CORPORATION --- 1,4 ---- ! /* $XConsortium: tocutil.h,v 2.7 95/01/09 16:52:53 swick Exp $ */ /* * COPYRIGHT 1987 * DIGITAL EQUIPMENT CORPORATION *************** *** 38,44 **** extern void TURefigureWhatsVisible (/* Toc */); extern void TULoadTocFile (/* Toc */); extern void TUSaveTocFile (/* Toc */); ! extern void TUEnsureScanIsValidAndOpen (/* Toc */); extern void TURefigureTocPositions (/* Toc */); extern void TUGetFullFolderInfo (/* Toc */); extern Msg TUAppendToc (/* Toc, char * */); --- 38,44 ---- extern void TURefigureWhatsVisible (/* Toc */); extern void TULoadTocFile (/* Toc */); extern void TUSaveTocFile (/* Toc */); ! extern void TUEnsureScanIsValidAndOpen (/* Toc, delay */); extern void TURefigureTocPositions (/* Toc */); extern void TUGetFullFolderInfo (/* Toc */); extern Msg TUAppendToc (/* Toc, char * */); *** - Tue Jan 24 15:34:20 1995 --- xc/programs/xmh/msg.c Tue Jan 24 15:34:20 1995 *************** *** 1,5 **** /* ! * $XConsortium: msg.c,v 2.51 93/09/20 17:52:07 hersh Exp $ * * * COPYRIGHT 1987, 1989 --- 1,5 ---- /* ! * $XConsortium: msg.c,v 2.54 95/01/05 18:28:30 swick Exp $ * * * COPYRIGHT 1987, 1989 *************** *** 77,83 **** /* Return the user-viewable name of the given message. */ ! static char *NameOfMsg(msg) Msg msg; { static char result[100]; --- 77,83 ---- /* Return the user-viewable name of the given message. */ ! char *MsgName(msg) Msg msg; { static char result[100]; *************** *** 97,103 **** msg = scrn->msg; if (msg == NULL) (void) strcpy(str, app_resources.banner); else { ! (void) strcpy(str, NameOfMsg(msg)); switch (msg->fate) { case Fdelete: (void) strcat(str, " -> *Delete*"); --- 97,103 ---- msg = scrn->msg; if (msg == NULL) (void) strcpy(str, app_resources.banner); else { ! (void) strcpy(str, MsgName(msg)); switch (msg->fate) { case Fdelete: (void) strcat(str, " -> *Delete*"); *************** *** 300,307 **** XawTextSetSource(scrn->viewwidget, PNullSource, (XawTextPosition) 0); ResetMsgLabel(scrn); EnableProperButtons(scrn); ! if (scrn->kind != STtocAndView) StoreWindowName(scrn, progName); } else { msg->num_scrns++; msg->scrn = (Scrn *) XtRealloc((char *)msg->scrn, --- 300,309 ---- XawTextSetSource(scrn->viewwidget, PNullSource, (XawTextPosition) 0); ResetMsgLabel(scrn); EnableProperButtons(scrn); ! if (scrn->kind != STtocAndView && scrn->kind != STcomp) { StoreWindowName(scrn, progName); + DestroyScrn(scrn); + } } else { msg->num_scrns++; msg->scrn = (Scrn *) XtRealloc((char *)msg->scrn, *************** *** 314,320 **** RedisplayMsg(scrn); EnableProperButtons(scrn); if (scrn->kind != STtocAndView) ! StoreWindowName(scrn, NameOfMsg(msg)); } } --- 316,322 ---- RedisplayMsg(scrn); EnableProperButtons(scrn); if (scrn->kind != STtocAndView) ! StoreWindowName(scrn, MsgName(msg)); } } *************** *** 356,362 **** char str[100]; (void) sprintf(str, "Are you sure you want to remove changes to %s?", ! NameOfMsg(msg)); yes_callbacks[0].callback = ConfirmedNoScrn; yes_callbacks[0].closure = (XtPointer) msg; --- 358,364 ---- char str[100]; (void) sprintf(str, "Are you sure you want to remove changes to %s?", ! MsgName(msg)); yes_callbacks[0].callback = ConfirmedNoScrn; yes_callbacks[0].closure = (XtPointer) msg; *************** *** 389,395 **** cb_data->scrn = scrn; (void)sprintf(str, "Are you sure you want to remove changes to %s?", ! NameOfMsg(scrn->msg)); yes_callbacks[0].callback = ConfirmedWithScrn; yes_callbacks[0].closure = (XtPointer) cb_data; yes_callbacks[1].callback = confirms[0].callback; --- 391,397 ---- cb_data->scrn = scrn; (void)sprintf(str, "Are you sure you want to remove changes to %s?", ! MsgName(scrn->msg)); yes_callbacks[0].callback = ConfirmedWithScrn; yes_callbacks[0].closure = (XtPointer) cb_data; yes_callbacks[1].callback = confirms[0].callback; *** - Tue Jan 24 15:34:23 1995 --- xc/programs/xmh/screen.c Tue Jan 24 15:34:23 1995 *************** *** 1,5 **** /* ! * $XConsortium: screen.c,v 2.62 91/07/22 21:23:25 converse Exp $ * * * COPYRIGHT 1987, 1989 --- 1,5 ---- /* ! * $XConsortium: screen.c,v 2.65 95/01/06 16:39:19 swick Exp $ * * * COPYRIGHT 1987, 1989 *************** *** 370,376 **** (void) XSetWMProtocols(XtDisplay(scrn->parent), XtWindow(scrn->parent), protocolList, XtNumber(protocolList)); } ! scrn->mapped = (numScrns == 1); return scrn; } --- 370,376 ---- (void) XSetWMProtocols(XtDisplay(scrn->parent), XtWindow(scrn->parent), protocolList, XtNumber(protocolList)); } ! scrn->mapped = False; return scrn; } *************** *** 424,431 **** Widget w; { register int i; ! while (w && (XtClass(w) != applicationShellWidgetClass) && ! (XtClass(w) != topLevelShellWidgetClass)) w = XtParent(w); if (w) { for (i=0 ; iscrn = (Scrn *) XtRealloc((char *) toc->scrn, (unsigned)toc->num_scrns*sizeof(Scrn)); toc->scrn[toc->num_scrns - 1] = scrn; ! TUEnsureScanIsValidAndOpen(toc); TUResetTocLabel(scrn); if (app_resources.prefix_wm_and_icon_name) { char wm_name[64]; --- 438,444 ---- toc->scrn = (Scrn *) XtRealloc((char *) toc->scrn, (unsigned)toc->num_scrns*sizeof(Scrn)); toc->scrn[toc->num_scrns - 1] = scrn; ! TUEnsureScanIsValidAndOpen(toc, True); TUResetTocLabel(scrn); if (app_resources.prefix_wm_and_icon_name) { char wm_name[64]; *************** *** 761,767 **** { Msg msg; static int looping = False; ! TUEnsureScanIsValidAndOpen(toc); msg = TUAppendToc(toc, "#### empty\n"); if (FileExists(MsgFileName(msg))) { if (looping++) Punt( "Cannot correct scan file" ); --- 761,767 ---- { Msg msg; static int looping = False; ! TUEnsureScanIsValidAndOpen(toc, False); msg = TUAppendToc(toc, "#### empty\n"); if (FileExists(MsgFileName(msg))) { if (looping++) Punt( "Cannot correct scan file" ); *************** *** 851,856 **** --- 851,867 ---- } + Boolean TocHasChanges(toc) + Toc toc; + { + int i; + for (i=0 ; inummsgs ; i++) + if (toc->msgs[i]->fate != Fignore) return True; + + return False; + } + + /* Throw out all changes to this toc, and close all views of msgs in it. Requires confirmation by the user. */ *************** *** 879,885 **** XtCallbackList cancels; { register int i; - int found = False; static XtCallbackRec yes_callbacks[] = { {TocCataclysmOkay, (XtPointer) NULL}, {(XtCallbackProc) NULL, (XtPointer) NULL}, --- 890,895 ---- *************** *** 889,901 **** if (! toc) return 0; ! for (i=0 ; inummsgs && !found ; i++) ! if (toc->msgs[i]->fate != Fignore) found = True; ! ! if (found) { char str[300]; Widget tocwidget; - int i; (void)sprintf(str,"Are you sure you want to remove all changes to %s?", toc->foldername); --- 899,907 ---- if (! toc) return 0; ! if (TocHasChanges(toc)) { char str[300]; Widget tocwidget; (void)sprintf(str,"Are you sure you want to remove all changes to %s?", toc->foldername); *** - Tue Jan 24 15:34:39 1995 --- xc/programs/xmh/tocutil.c Tue Jan 24 15:34:38 1995 *************** *** 1,5 **** /* ! * $XConsortium: tocutil.c,v 2.58 93/09/20 17:51:59 hersh Exp $ * * * COPYRIGHT 1987, 1989 --- 1,5 ---- /* ! * $XConsortium: tocutil.c,v 2.60 95/01/09 16:52:53 swick Exp $ * * * COPYRIGHT 1987, 1989 *************** *** 501,507 **** if (fid < 0 && toc->length != toc->origlength) fid = myopen(toc->scanfile, O_RDWR, 0666); if (fid >= 0) { ! #if defined(SYSV) && (defined(SYSV386) || defined(MOTOROLA)) (void) ftruncate_emu(fid, toc->length, toc->scanfile); #else (void) ftruncate(fid, toc->length); --- 501,507 ---- if (fid < 0 && toc->length != toc->origlength) fid = myopen(toc->scanfile, O_RDWR, 0666); if (fid >= 0) { ! #if defined(SYSV) && (defined(i386) || defined(MOTOROLA)) (void) ftruncate_emu(fid, toc->length, toc->scanfile); #else (void) ftruncate(fid, toc->length); *************** *** 514,534 **** } ! void TUEnsureScanIsValidAndOpen(toc) Toc toc; { if (toc) { TUGetFullFolderInfo(toc); if (TUScanFileOutOfDate(toc)) { ! if (toc->source) { ! XtFree((char *) toc->source); ! toc->source = NULL; } - TUScanFileForToc(toc); } if (toc->source == NULL) TULoadTocFile(toc); - toc->validity = valid; } } --- 514,562 ---- } ! static Boolean UpdateScanFile(client_data) ! XtPointer client_data; /* Toc */ ! { ! Toc toc = (Toc)client_data; ! int i; ! ! if (app_resources.block_events_on_busy) ShowBusyCursor(); ! ! TUScanFileForToc(toc); ! TULoadTocFile(toc); ! ! for (i=0 ; inum_scrns ; i++) ! TURedisplayToc(toc->scrn[i]); ! ! if (app_resources.block_events_on_busy) UnshowBusyCursor(); ! ! return True; ! } ! ! ! void TUEnsureScanIsValidAndOpen(toc, delay) Toc toc; + Boolean delay; { if (toc) { TUGetFullFolderInfo(toc); if (TUScanFileOutOfDate(toc)) { ! if (!delay) ! UpdateScanFile((XtPointer)toc); ! else { ! /* this is a hack to get the screen mapped before ! * spawning the subprocess (and blocking). ! * Need to make sure the scanfile exists at this point. ! */ ! int fid = myopen(toc->scanfile, O_RDWR|O_CREAT, 0666); ! (void) myclose(fid); ! XtAppAddWorkProc(XtWidgetToApplicationContext(toplevel), ! UpdateScanFile, ! (XtPointer)toc); } } if (toc->source == NULL) TULoadTocFile(toc); } } *** - Wed Jan 25 10:00:46 1995 --- xc/programs/xmh/init.c Wed Jan 25 10:00:45 1995 *************** *** 1,5 **** /* ! * $XConsortium: init.c,v 2.73 93/10/07 15:23:05 gildea Exp $ * * * COPYRIGHT 1987, 1989 --- 1,5 ---- /* ! * $XConsortium: init.c,v 2.80 95/01/25 14:33:57 swick Exp $ * * * COPYRIGHT 1987, 1989 *************** *** 243,254 **** --- 243,272 ---- } + /*ARGSUSED*/ + static void _Die(w, client_data, call_data) + Widget w; /* == toplevel */ + XtPointer client_data; /* unused */ + XtPointer call_data; /* unused */ + { + int i; + + for (i=0; imapped) + XtUnmapWidget(scrnList[i]->parent); + + XtDestroyApplicationContext(XtWidgetToApplicationContext(w)); + exit(0); + } + + /* All the start-up initialization goes here. */ InitializeWorld(argc, argv) int argc; char **argv; { + extern char** environ; /* POSIX doesn't specify a .h for this */ int l; FILEPTR fid; char str[500], str2[500], *ptr; *************** *** 346,366 **** static Arg shell_args[] = { {XtNinput, (XtArgVal)True}, }; ptr = strrchr(argv[0], '/'); if (ptr) progName = ptr + 1; else progName = argv[0]; ! toplevel = XtAppInitialize(&app, "Xmh", table, XtNumber(table), ! &argc, argv, FallbackResources, ! NULL, (Cardinal)0); if (argc > 1) Syntax(progName); XSetIOErrorHandler(_IOErrorHandler); - XtSetValues(toplevel, shell_args, XtNumber(shell_args)); - theDisplay = XtDisplay(toplevel); homeDir = XtNewString(getenv("HOME")); --- 364,387 ---- static Arg shell_args[] = { {XtNinput, (XtArgVal)True}, + {XtNjoinSession, (XtArgVal)False}, /* join is delayed to end of init */ + {XtNenvironment, NULL}, /* set dynamically below */ + {XtNmappedWhenManaged, (XtArgVal)False} }; ptr = strrchr(argv[0], '/'); if (ptr) progName = ptr + 1; else progName = argv[0]; ! shell_args[2].value = (XtArgVal)environ; ! toplevel = XtOpenApplication(&app, "Xmh", table, XtNumber(table), ! &argc, argv, FallbackResources, ! sessionShellWidgetClass, ! shell_args, XtNumber(shell_args)); if (argc > 1) Syntax(progName); XSetIOErrorHandler(_IOErrorHandler); theDisplay = XtDisplay(toplevel); homeDir = XtNewString(getenv("HOME")); *************** *** 469,474 **** --- 490,498 ---- protocolList[1] = wm_save_yourself = XInternAtom(XtDisplay(toplevel), "WM_SAVE_YOURSELF", False); + XtAddCallback(toplevel, XtNsaveCallback, DoSaveYourself, (XtPointer)NULL); + XtAddCallback(toplevel, XtNdieCallback, _Die, (XtPointer)NULL); + MenuItemBitmap = XCreateBitmapFromData( XtDisplay(toplevel), RootWindowOfScreen( XtScreen(toplevel)), *************** *** 489,494 **** --- 513,520 ---- TocSetScrn(InitialFolder, scrn); DEBUG("done.\n"); + + XtVaSetValues(toplevel, XtNjoinSession, (XtArgVal)True, NULL); MapScrn(scrn); } *** - Tue Jan 24 15:34:56 1995 --- xc/programs/xmh/version.h Tue Jan 24 15:34:56 1995 *************** *** 1,4 **** ! /* $XConsortium: version.h,v 1.2 94/04/17 20:24:05 gildea Exp $ */ /* Copyright (c) 1993 X Consortium --- 1,4 ---- ! /* $XConsortium: version.h,v 1.4 95/01/10 21:59:40 swick Exp $ */ /* Copyright (c) 1993 X Consortium *************** *** 29,32 **** */ ! #define XMH_VERSION "xmh X Consortium R6" --- 29,32 ---- */ ! #define XMH_VERSION "xmh X Consortium R6 +fix-08" *** - Wed Jan 18 13:28:39 1995 --- xc/workInProgress/xsm/list.c Wed Jan 18 13:28:39 1995 *************** *** 1,4 **** ! /* $XConsortium: list.c,v 1.4 94/04/17 21:15:15 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium --- 1,4 ---- ! /* $XConsortium: list.c,v 1.7 94/12/16 17:27:27 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium *************** *** 25,44 **** in this Software without prior written authorization from the X Consortium. ******************************************************************************/ ! #include ! #include ! #ifndef X_NOT_STDC_ENV ! #include ! #endif ! ! #include "list.h" List * ListInit() { List *l; ! l = (List *)malloc(sizeof *l); if(!l) return l; l->next = l; l->prev = l; --- 25,38 ---- in this Software without prior written authorization from the X Consortium. ******************************************************************************/ ! #include "xsm.h" List * ListInit() { List *l; ! l = (List *)XtMalloc(sizeof *l); if(!l) return l; l->next = l; l->prev = l; *************** *** 66,72 **** ListFreeAll(l) List *l; { ! void *thing; List *next; next = l->next; --- 60,66 ---- ListFreeAll(l) List *l; { ! char *thing; List *next; next = l->next; *************** *** 74,91 **** l = next; next = l->next; thing = l->thing; ! free(l); } while(thing); } List * ListAddFirst(l, v) List *l; ! void *v; { List *e; ! e = (List *)malloc(sizeof *e); if(!e) return NULL; e->thing = v; --- 68,104 ---- 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; *************** *** 100,110 **** List * ListAddLast(l, v) List *l; ! void *v; { List *e; ! e = (List *)malloc(sizeof *e); if(!e) return NULL; e->thing = v; --- 113,123 ---- List * ListAddLast(l, v) List *l; ! char *v; { List *e; ! e = (List *)XtMalloc(sizeof *e); if(!e) return NULL; e->thing = v; *************** *** 122,129 **** { e->next->prev = e->prev; e->prev->next = e->next; ! free((char *)e); } int ListCount(l) --- 135,161 ---- { 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) *** - Wed Jan 18 13:28:41 1995 --- xc/workInProgress/xsm/list.h Wed Jan 18 13:28:41 1995 *************** *** 1,4 **** ! /* $XConsortium: list.h,v 1.3 94/04/17 21:15:16 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium --- 1,4 ---- ! /* $XConsortium: list.h,v 1.6 94/12/16 17:27:47 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium *************** *** 28,52 **** typedef struct _List { struct _List *prev; struct _List *next; ! void *thing; } List; - #if 0 - extern List *ListInit(); - extern List *ListFirst(List *); - extern List *ListNext(List *); - extern void ListFreeAll(List *); - extern void ListFreeOne(List *); - extern List *ListAddFirst(List *, void *); - extern List *ListAddLast(List *, void *); - extern int ListCount(List *); - #else extern List *ListInit(); extern List *ListFirst(); extern List *ListNext(); extern void ListFreeAll(); extern void ListFreeOne(); extern List *ListAddFirst(); extern List *ListAddLast(); extern int ListCount(); - #endif --- 28,43 ---- 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(); *** - Wed Jan 18 13:28:43 1995 --- xc/workInProgress/xsm/xsm.c Wed Jan 18 13:28:42 1995 *************** *** 1,4 **** ! /* $XConsortium: xsm.c,v 1.35 94/04/17 21:15:19 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium --- 1,4 ---- ! /* $XConsortium: xsm.c,v 1.75 95/01/03 17:23:56 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium *************** *** 28,1586 **** /* * X Session Manager. * ! * Written by Ralph Mor, X Consortium. ! * and Jordan Brown, Quarterdeck Office Systems ! * ! * This program needs a fair amount of work to make it robust. ! * As it stands now, it serves as a useful test for session management. */ #include "xsm.h" ! #include ! AppResources app_resources; ! #define Offset(field) XtOffsetOf(struct _AppResources, field) ! static XtResource resources [] = { ! {"verbose", "Verbose", XtRBoolean, sizeof(Boolean), ! Offset(verbose), XtRImmediate, (XtPointer) False}, ! {"debug", "Debug", XtRBoolean, sizeof(Boolean), ! Offset(debug), XtRImmediate, (XtPointer) False} ! }; ! #undef Offset ! static XrmOptionDescRec options[] = { ! {"-verbose", "*verbose", XrmoptionNoArg, "TRUE"}, ! {"-quiet", "*verbose", XrmoptionNoArg, "FALSE"}, ! {"-debug", "*debug", XrmoptionNoArg, "TRUE"}, ! }; - List *PendingList; - ClientRec *ClientList = NULL; - int numClients = 0; - int pingCount = 0; - int saveDoneCount = 0; - int interactCount = 0; - Bool shutdownInProgress = False; - Bool shutdownCancelled = False; - jmp_buf JumpHere; ! IceAuthDataEntry *authDataEntries = NULL; ! int numTransports = 0; ! int saveTypeData[] = {SmSaveGlobal, ! SmSaveLocal, ! SmSaveBoth}; ! Bool shutdownData[] = {1, 0}; ! int interactStyleData[] = {SmInteractStyleNone, ! SmInteractStyleErrors, ! SmInteractStyleAny}; ! Bool fastData[] = {1, 0}; ! XtAppContext appContext; ! Widget topLevel; ! Widget mainWindow; ! Widget listButton; ! Widget saveButton; ! Widget propButton; ! Widget pingButton; ! Widget startButton; ! Widget savePopup; ! Widget saveForm; ! Widget saveTypeLabel; ! Widget saveTypeGlobal; ! Widget saveTypeLocal; ! Widget saveTypeBoth; - Widget shutdownLabel; - Widget shutdownYes; - Widget shutdownNo; ! Widget interactStyleLabel; ! Widget interactStyleNone; ! Widget interactStyleErrors; ! Widget interactStyleAny; ! Widget fastLabel; ! Widget fastYes; ! Widget fastNo; - Widget saveOkButton; - Widget saveCancelButton; ! Widget shutdownPopup; ! Widget shutdownDialog; ! Widget shutdownOkButton; ! Widget shutdownCancelButton; ! void FreeClientInfo (); ! extern Status InitWatchProcs (); ! extern void restart_everything (); ! extern void read_save (); ! extern void write_save (); ! extern Bool HostBasedProc (); ! extern Status set_auth (); ! extern void free_auth (); ! ! print_prop(prop) ! SmProp *prop; ! { ! int j; ! printf (" Name: %s\n", prop->name); ! printf (" Type: %s\n", prop->type); ! printf (" Num values: %d\n", prop->num_vals); ! if (strcmp(prop->type, SmCARD8) == 0) { ! char *card8 = prop->vals->value; ! int value = *card8; ! printf (" Value 1:\t%d\n", value); ! } else { ! for (j = 0; j < prop->num_vals; j++) { ! printf (" Value %d: %s\n", j + 1, ! (char *) prop->vals[j].value); ! } } - printf ("\n"); - } ! ! exit_sm () ! { ! if (app_resources.verbose) ! printf ("\nSESSION MANAGER GOING AWAY!\n"); ! free_auth (numTransports, authDataEntries); ! exit (0); ! } ! ! SetInitialProperties(client, pendclient) ! ClientRec *client; ! PendingClient *pendclient; ! { ! int idx; ! SmProp *prop; ! SmPropValue *val; ! List *pl; ! List *vl; ! PendingProp *pprop; ! PendingValue *pval; ! ! if (app_resources.verbose) ! printf("Setting initial properties for %s\n", client->clientId); ! ! idx = 0; ! for(pl = ListFirst(pendclient->props); pl; pl = ListNext(pl)) { ! pprop = (PendingProp *)pl->thing; ! prop = (SmProp *)malloc(sizeof *prop); ! client->props[idx] = prop; ! prop->name = pprop->name; ! prop->type = pprop->type; ! prop->num_vals = ListCount(pprop->values); ! prop->vals = ! (SmPropValue *)malloc(prop->num_vals * sizeof(SmPropValue)); ! val = prop->vals; ! for(vl = ListFirst(pprop->values); vl; vl = ListNext(vl)) { ! pval = (PendingValue *)vl->thing; ! val->value = pval->value; ! val->length = pval->length; ! val++; ! } ! ListFreeAll(pprop->values); ! free(pprop); ! idx++; ! } ! client->numProps = idx; ! ! ListFreeAll(pendclient->props); ! XtFree(pendclient->clientId); ! free(pendclient); ! } ! ! /* ! * Session Manager callbacks ! */ ! Status ! RegisterClientProc (smsConn, managerData, previousId) ! SmsConn smsConn; ! SmPointer managerData; ! char *previousId; ! { ! ClientRec *client = (ClientRec *) managerData; ! char *id; ! List *cl; ! if (app_resources.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 = (char *)malloc (strlen (previousId) + 1); ! strcpy (id, previousId); ! } ! else ! id = SmsGenerateClientID (smsConn); ! SmsRegisterClientReply (smsConn, id); ! client->clientId = id; ! client->clientHostname = SmsClientHostName (smsConn); - if (app_resources.verbose) { - printf ( - "On IceConn fd = %d, sent REGISTER CLIENT REPLY [Client Id = %s]\n", - IceConnectionNumber (client->ice_conn), id); - printf ("\n"); - } ! if(previousId) { ! for(cl = ListFirst(PendingList); cl; cl = ListNext(cl)) { ! if(!strcmp(((PendingClient *)cl->thing)->clientId, previousId)) { ! SetInitialProperties(client, (PendingClient *)cl->thing); ! ListFreeOne(cl); ! break; ! } ! } ! free (previousId); ! } else { ! SmsSaveYourself(smsConn, SmSaveLocal, False, SmInteractStyleNone, ! False); ! } ! return (1); ! } ! ! void ! InteractRequestProc (smsConn, managerData, dialogType) ! SmsConn smsConn; ! SmPointer managerData; ! int dialogType; ! { ! ClientRec *client = (ClientRec *) managerData; ! if (app_resources.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"); } ! client->interactPending = True; ! interactCount++; } void ! InteractDoneProc (smsConn, managerData, cancelShutdown) ! SmsConn smsConn; ! SmPointer managerData; ! Bool cancelShutdown; { ! ClientRec *client = (ClientRec *) managerData; ! if (app_resources.verbose) { ! printf ( ! "Client Id = %s, received INTERACT DONE [Cancel Shutdown = %s]\n", ! client->clientId, cancelShutdown ? "True" : "False"); ! } ! client->interactPending = False; ! if (cancelShutdown && !shutdownCancelled) { ! shutdownCancelled = True; ! for (client = ClientList; client; client = client->next) { ! SmsShutdownCancelled (client->smsConn); ! if (app_resources.verbose) ! printf ("Client Id = %s, sent SHUTDOWN CANCELLED\n", ! client->clientId); ! } } } void ! SaveYourselfReqProc (smsConn, managerData, saveType, ! shutdown, interactStyle, fast, global) ! SmsConn smsConn; ! SmPointer managerData; ! int saveType; ! Bool shutdown; ! int interactStyle; ! Bool fast; ! Bool global; { ! if (app_resources.verbose) ! printf("SAVE YOURSELF REQUEST not supported!\n"); } void ! SaveYourselfDoneProc (smsConn, managerData, success) ! SmsConn smsConn; ! SmPointer managerData; ! Bool success; { ! ClientRec *client = (ClientRec *) managerData; ! ! if (app_resources.verbose) ! printf("Client Id = %s, received SAVE YOURSELF DONE [Success = %s]\n", ! client->clientId, success ? "True" : "False"); ! if (shutdownCancelled && client->interactPending) ! client->interactPending = False; ! saveDoneCount++; ! } ! ! void ! CloseConnectionProc (smsConn, managerData, count, reasonMsgs) ! SmsConn smsConn; ! SmPointer managerData; ! int count; ! char **reasonMsgs; ! { ! ClientRec *client = (ClientRec *) managerData; ! ClientRec *next = client->next; ! ClientRec *ptr; ! int i; ! ! if (app_resources.verbose) { ! 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); ! SmsCleanUp (smsConn); ! if (app_resources.verbose) { ! printf ("ICE Connection closed, IceConn fd = %d\n", ! IceConnectionNumber (client->ice_conn)); ! printf ("\n"); } ! IceSetShutdownNegotiation (client->ice_conn, False); ! IceCloseConnection (client->ice_conn); ! if (client == ClientList) ! { ! FreeClientInfo (client); ! ClientList = next; ! } ! else ! { ! ptr = ClientList; ! while (ptr && ptr->next != client) ! ptr = ptr->next; ! if (ptr->next == client) { ! FreeClientInfo (client); ! ptr->next = next; } } ! numClients--; ! ! if (shutdownInProgress && numClients == 0) ! { ! exit_sm (); } } ! void ! SetProperty(client, prop) ! ClientRec *client; ! SmProp *prop; ! { ! int idx, j; ! for (j = 0; j < client->numProps; j++) ! if (strcmp (prop->name, client->props[j]->name) == 0) ! { ! SmFreeProperty (client->props[j]); ! break; ! } ! if (j < client->numProps) ! idx = j; ! else ! { ! idx = client->numProps; ! client->numProps++; - if (client->numProps > MAX_PROPS) - return; - } ! client->props[idx] = prop; ! } - - void - DeleteProperty(client, propname) - ClientRec *client; - char *propname; - { - int j; ! for (j = 0; j < client->numProps; j++) ! if (strcmp (propname, client->props[j]->name) == 0) ! { ! SmFreeProperty (client->props[j]); ! if (j < client->numProps - 1) ! client->props[j] = client->props[client->numProps - 1]; - client->numProps--; - break; - } - } ! ! void ! SetPropertiesProc (smsConn, managerData, numProps, props) ! ! SmsConn smsConn; ! SmPointer managerData; ! int numProps; ! SmProp **props; ! ! { ! ClientRec *client = (ClientRec *) managerData; ! int i; ! ! if (app_resources.verbose) { ! printf ("Client Id = %s, received SET PROPERTIES ", client->clientId); ! printf ("[Num props = %d]\n", numProps); ! } ! ! for (i = 0; i < numProps; i++) { ! if(app_resources.verbose) ! print_prop(props[i]); ! SetProperty(client, props[i]); ! } ! free ((char *) props); ! } ! ! ! ! void ! DeletePropertiesProc (smsConn, managerData, numProps, propNames) ! ! SmsConn smsConn; ! SmPointer managerData; ! int numProps; ! char ** propNames; ! { ! ClientRec *client = (ClientRec *) managerData; ! int i; ! if (app_resources.verbose) { ! printf ("Client Id = %s, received DELETE PROPERTIES ", ! client->clientId); ! printf ("[Num props = %d]\n", numProps); ! } - for (i = 0; i < numProps; i++) { - if(app_resources.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; ! int i; ! if (app_resources.verbose) { ! printf ("Client Id = %s, received GET PROPERTIES\n", client->clientId); ! printf ("\n"); ! for (i = 0; i < client->numProps; i++) { ! print_prop(client->props[i]); ! } ! printf ("\n"); } ! SmsReturnProperties (smsConn, client->numProps, client->props); ! ! if (app_resources.verbose) { ! printf ("Client Id = %s, sent PROPERTIES REPLY [Num props = %d]\n", ! client->clientId, client->numProps); ! } ! } ! ! void ! PingReplyProc (ice_conn, client_data) ! IceConn ice_conn; ! IcePointer client_data; ! { ! ClientRec *client = (ClientRec *) client_data; ! printf ("Client Id = %s, received PING REPLY\n", client->clientId); ! pingCount--; ! } ! ! Status ! NewClientProc (smsConn, managerData, maskRet, callbacksRet, failureReasonRet) ! SmsConn smsConn; ! SmPointer managerData; ! unsigned long *maskRet; ! SmsCallbacks *callbacksRet; ! char **failureReasonRet; - { - ClientRec *newClient = (ClientRec *) malloc (sizeof (ClientRec)); - *maskRet = 0; ! if (!newClient) { ! char *str = "Memory allocation failed"; ! ! if ((*failureReasonRet = (char *) malloc (strlen (str) + 1)) != NULL) ! strcpy (*failureReasonRet, str); ! return (0); } ! newClient->smsConn = smsConn; ! newClient->ice_conn = SmsGetIceConnection (smsConn); ! newClient->clientId = NULL; ! newClient->clientHostname = NULL; ! newClient->interactPending = False; ! newClient->numProps = 0; ! newClient->next = ClientList; ! ClientList = newClient; ! numClients++; ! if (app_resources.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 |= 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 callbacks ! */ ! void ! ListClientsXtProc (w, client_data, callData) ! Widget w; ! XtPointer client_data; ! XtPointer callData; { ! ClientRec *client = ClientList; ! printf ("\n"); ! if (client == NULL) { ! printf ("There are no clients registered with the SM\n"); ! } else { ! printf ("The following client IDs are registered with the SM:\n"); ! printf ("\n"); ! } ! while (client) { ! printf (" Host = %s, ID = %s\n", ! client->clientHostname, client->clientId); ! client = client->next; } ! printf ("\n"); } void ! SaveYourselfXtProc (w, client_data, callData) ! Widget w; ! XtPointer client_data; ! XtPointer callData; { ! Position x, y, rootx, rooty; ! XtVaGetValues (mainWindow, XtNx, &x, XtNy, &y, NULL); ! XtTranslateCoords (mainWindow, x, y, &rootx, &rooty); ! if (ClientList == NULL) ! { ! XtMoveWidget (shutdownPopup, rootx, rooty); ! XtPopup (shutdownPopup, XtGrabNone); } - else - { - XawToggleSetCurrent (saveTypeBoth, - (XtPointer) &saveTypeData[2]); - XawToggleSetCurrent (shutdownNo, - (XtPointer) &shutdownData[1]); - XawToggleSetCurrent (interactStyleAny, - (XtPointer) &interactStyleData[2]); - XawToggleSetCurrent (fastNo, - (XtPointer) &fastData[1]); ! XtMoveWidget (savePopup, rootx, rooty); ! XtPopup (savePopup, XtGrabNone); ! } ! XtSetSensitive (mainWindow, 0); } ! void ! SaveOkXtProc (w, client_data, callData) ! ! Widget w; ! XtPointer client_data; ! XtPointer callData; ! ! { ! ClientRec *client; ! XtPointer ptr; ! int saveType; ! Bool shutdown; ! int interactStyle; ! Bool fast; ! char *_saveType; ! char *_shutdown; ! char *_interactStyle; ! char *_fast; ! ! ptr = XawToggleGetCurrent (saveTypeGlobal /* just 1 of the group */); ! saveType = *((int *) ptr); ! ! ptr = XawToggleGetCurrent (shutdownYes /* just 1 of the group */); ! shutdown = *((Bool *) ptr); ! ! ptr = XawToggleGetCurrent (interactStyleNone /* just 1 of the group */); ! interactStyle = *((int *) ptr); ! ! ptr = XawToggleGetCurrent (fastYes /* just 1 of the group */); ! fast = *((Bool *) ptr); ! ! if (saveType == SmSaveGlobal) ! _saveType = "Global"; ! else if (saveType == SmSaveLocal) ! _saveType = "Local"; ! else ! _saveType = "Both"; ! ! if (shutdown) ! _shutdown = "True"; ! else ! _shutdown = "False"; ! if (interactStyle == SmInteractStyleNone) ! _interactStyle = "None"; ! else if (interactStyle == SmInteractStyleErrors) ! _interactStyle = "Errors"; ! else ! _interactStyle = "Any"; ! if (fast) ! _fast = "True"; ! else ! _fast = "False"; ! XtSetSensitive (savePopup, 0); ! for (client = ClientList; client; client = client->next) { ! SmsSaveYourself (client->smsConn, ! saveType, shutdown, interactStyle, fast); ! ! if (app_resources.verbose) { ! printf ("Client Id = %s, sent SAVE YOURSELF [", client->clientId); ! printf ("Save Type = %s, Shutdown = %s, ", _saveType, _shutdown); ! printf ("Interact Style = %s, Fast = %s]\n", ! _interactStyle, _fast); ! } ! } ! if (app_resources.verbose) { ! printf ("\n"); ! printf ("Sent SAVE YOURSELF to all clients. Waiting for\n"); ! printf ("SAVE YOURSELF DONE or INTERACT REQUEST from each client.\n"); printf ("\n"); } ! saveDoneCount = 0; ! interactCount = 0; ! ! while (saveDoneCount + interactCount < numClients) { ! XtAppProcessEvent (appContext, XtIMAll); } ! if (app_resources.verbose) { ! printf ("\n"); ! printf ("Received %d SAVE YOURSELF DONEs, %d INTERACT REQUESTS\n", ! saveDoneCount, interactCount); ! } ! if (interactCount == 0 && saveDoneCount != numClients) { ! if (app_resources.verbose) { ! printf ("\n"); ! printf ("INTERNAL ERROR IN PSEUDO-SM! EXITING!\n"); } - exit (1); - } ! if (interactCount > 0) { ! ! if (app_resources.verbose) ! printf ("\n"); ! client = ClientList; ! while (client) { ! if (shutdownCancelled) { ! break; ! } ! else if (client->interactPending) { ! SmsInteract (client->smsConn); ! if (app_resources.verbose) { ! printf ("Client Id = %s, sent INTERACT\n", ! client->clientId); ! } ! while (client->interactPending) { ! XtAppProcessEvent (appContext, XtIMAll); } } - client = client->next; - } - - if (app_resources.verbose) { - if (shutdownCancelled) - printf ("\nThe shutdown was cancelled by a user\n\n"); - else - printf ("\nDone interacting with all clients\n\n"); } - } ! while (saveDoneCount < numClients) { ! XtAppProcessEvent (appContext, XtIMAll); ! } ! if (app_resources.verbose) ! printf ("\nAll clients issued SAVE YOURSELF DONE\n\n"); ! write_save(); ! if (shutdown && shutdownCancelled) { ! shutdownCancelled = False; ! } else if (shutdown) { ! shutdownInProgress = True; ! client = ClientList; ! while (client) { ! SmsDie (client->smsConn); ! if (app_resources.verbose) ! printf ("Client Id = %s, sent DIE\n", client->clientId); ! client = client->next; } ! } else { ! client = ClientList; ! while (client) { ! SmsSaveComplete (client->smsConn); ! if (app_resources.verbose) ! printf ("Client Id = %s, sent SAVE COMPLETE\n", ! client->clientId); ! client = client->next; } } ! if (!shutdownInProgress) { ! XtPopdown (savePopup); ! XtSetSensitive (savePopup, 1); ! XtSetSensitive (mainWindow, 1); ! } ! } ! ! ! ! void ! SaveCancelXtProc (w, client_data, callData) ! ! Widget w; ! XtPointer client_data; ! XtPointer callData; ! { ! XtPopdown (savePopup); ! XtSetSensitive (mainWindow, 1); ! } ! ! void ! ShutdownOkXtProc (w, client_data, callData) ! Widget w; ! XtPointer client_data; ! XtPointer callData; ! { ! write_save(); ! exit_sm (); } ! void ! ShutdownCancelXtProc (w, client_data, callData) ! ! Widget w; ! XtPointer client_data; ! XtPointer callData; { ! XtPopdown (shutdownPopup); ! XtSetSensitive (mainWindow, 1); } void ! ListPropXtProc (w, client_data, callData) ! Widget w; ! XtPointer client_data; ! XtPointer callData; { ! ClientRec *client = ClientList; ! if (client == NULL) { ! printf ("There are no clients registered with the SM\n"); ! return; } ! while (client) { ! if (client->numProps == 0) { ! printf("Client Id = %s, no properties are set\n", ! client->clientId); ! } else { ! int i; ! printf ("Client Id = %s, the following properties are set:\n", ! client->clientId); ! for (i = 0; i < client->numProps; i++) ! print_prop(client->props[i]); ! } ! client = client->next; } } void ! StartXtProc (w, client_data, callData) ! ! Widget w; ! XtPointer client_data; ! XtPointer callData; { ! switch(fork()) { ! case -1: ! perror("fork"); ! break; ! case 0: ! execlp("xsmclient", "xsmclient", (char *)NULL); ! perror("xsmclient"); ! _exit(255); ! default: ! break; } - } ! ! void ! PingXtProc (w, client_data, callData) ! Widget w; ! XtPointer client_data; ! XtPointer callData; ! { ! ClientRec *client = ClientList; ! pingCount = 0; ! printf ("\n"); ! if (client == NULL ) { ! printf ("There are no clients registered with the SM\n"); ! printf ("\n"); ! return; } - while (client) { - IcePing (client->ice_conn, PingReplyProc, (IcePointer) client); - pingCount++; - printf ("Client Id = %s, sent PING\n", client->clientId); - client = client->next; - } - printf ("\n"); - while (pingCount > 0) - XtAppProcessEvent(appContext, XtIMAll); - printf ("\n"); } - /* - * 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; ! ! ice_conn = IceAcceptConnection((IceListenObj) client_data, &status); ! if (! ice_conn) { ! if (app_resources.verbose) ! printf ("IceAcceptConnection failed\n"); ! } else { ! IceConnectStatus cstatus; - while ((cstatus = IceConnectionStatus (ice_conn))==IceConnectPending) { - XtAppProcessEvent (appContext, XtIMAll); - } ! if (cstatus == IceConnectAccepted) { ! if (app_resources.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 (app_resources.verbose) ! { ! if (cstatus == IceConnectIOError) ! printf ("IO error opening ICE Connection!\n"); ! else ! printf ("ICE Connection rejected!\n"); ! } ! IceCloseConnection (ice_conn); ! } ! } } - /* - * Install IO error handler. This will detect clients that break their - * connection with the SM unexpectidly. - */ - void ! myIOErrorHandler (ice_conn) ! IceConn ice_conn; { ! if (ClientList == NULL) { /* ! * The client must have disconnected before the ICE connection ! * became valid. Example: ICE authentication failed. */ ! ! IceSetShutdownNegotiation (ice_conn, False); ! IceCloseConnection (ice_conn); } else { ! ClientRec *ptr = ClientList; ! ClientRec *prev = NULL; ! ! while (ptr && ptr->ice_conn != ice_conn) { ! prev = ptr; ! ptr = ptr->next; } ! ! if (!ptr) { ! fprintf (stderr, "Internal error; couldn't find ice_conn\n"); ! exit (1); } else ! { ! if (prev == NULL) ! ClientList = ptr->next; ! else ! prev->next = ptr->next; - SmsCleanUp (ptr->smsConn); - FreeClientInfo (ptr); - - if (app_resources.verbose) - { - printf ("ICE Connection terminated (fd = %d)\n", - IceConnectionNumber (ice_conn)); - printf ("\n"); - } ! IceSetShutdownNegotiation (ice_conn, False); ! IceCloseConnection (ice_conn); ! numClients--; ! if (shutdownInProgress && numClients == 0) ! { ! exit_sm (); ! } } } ! /* ! * We can't return. Must do a long jump. Make sure any ! * popups are uppopped. ! */ ! XtPopdown (shutdownPopup); ! XtPopdown (savePopup); ! XtSetSensitive (shutdownPopup, 1); ! XtSetSensitive (savePopup, 1); ! XtSetSensitive (mainWindow, 1); ! longjmp (JumpHere, 1); ! } ! ! /* ! * Add toggle button ! */ ! Widget ! AddToggle (widgetName, parent, label, state, radioGroup, radioData, ! fromHoriz, fromVert) ! ! char *widgetName; ! Widget parent; ! char *label; ! int state; ! Widget radioGroup; ! XtPointer radioData; ! Widget fromHoriz; ! Widget fromVert; ! ! { ! Widget toggle; ! XtTranslations translations; ! ! toggle = XtVaCreateManagedWidget ( ! widgetName, toggleWidgetClass, parent, ! XtNlabel, label, ! XtNstate, state, ! XtNradioGroup, radioGroup, ! XtNradioData, radioData, ! XtNfromHoriz, fromHoriz, ! XtNfromVert, fromVert, ! NULL); ! translations = XtParseTranslationTable (",:set()\n"); ! XtOverrideTranslations (toggle, translations); ! return (toggle); } void ! FreeClientInfo (client) ! ! ClientRec *client; { ! if (client) { int i; ! XtFree (client->clientId); ! XtFree (client->clientHostname); ! ! for (i = 0; i < client->numProps; i++) ! SmFreeProperty (client->props[i]); ! free ((char *) client); } - } ! static void Syntax(call) ! char *call; ! { ! (void) fprintf(stderr, "usage: %s [-verbose] [-quiet]\n", call); ! exit(2); } ! main(argc, argv) ! int argc; ! char **argv; { ! IceListenObj *listenObjs; ! char *networkIds; ! int i; ! char *p; ! char * progName; ! char errormsg[256]; ! static char environment_name[] = "SESSION_MANAGER"; ! umask (0077); /* disallow non-owner access */ ! p = strrchr(argv[0], '/'); ! progName = (p ? p + 1 : argv[0]); ! topLevel = XtVaAppInitialize (&appContext, "SAMPLE-SM", options, ! XtNumber(options), &argc, argv, NULL, ! XtNjoinSession, 0, /* We are the SM */ ! NULL); ! ! if (argc > 1) Syntax(progName); ! XtGetApplicationResources(topLevel, (XtPointer) &app_resources, ! resources, XtNumber(resources), NULL, 0); ! ! /* ! * Set my own IO error handler. ! */ ! IceSetIOErrorHandler (myIOErrorHandler); ! /* ! * Ignore SIGPIPE ! */ ! signal (SIGPIPE, SIG_IGN); /* ! * Init SM lib */ ! /* if these are errors they should write to stderr or an error file. */ ! if (!SmsInitialize ("SAMPLE-SM", "1.0", ! NewClientProc, NULL, ! HostBasedProc, 256, errormsg)) ! { ! printf ("%s\n", errormsg); ! exit (1); ! } ! ! if (!IceListenForConnections (&numTransports, &listenObjs, ! 256, errormsg)) ! { ! printf ("%s\n", errormsg); ! exit (1); ! } ! if (!set_auth (numTransports, listenObjs, &authDataEntries)) ! { ! printf ("Could not set authorization\n"); ! exit (1); ! } ! InitWatchProcs (appContext); ! mainWindow = XtCreateManagedWidget ( ! "mainWindow", boxWidgetClass, topLevel, NULL, 0); ! listButton = XtVaCreateManagedWidget ( ! "listButton", commandWidgetClass, mainWindow, ! XtNlabel, "List all registered clients", ! NULL); ! XtAddCallback (listButton, XtNcallback, ListClientsXtProc, 0); ! saveButton = XtVaCreateManagedWidget ( ! "saveButton", commandWidgetClass, mainWindow, ! XtNlabel, "Save Yourself with option to Shutdown", ! NULL); ! XtAddCallback (saveButton, XtNcallback, SaveYourselfXtProc, 0); ! if (app_resources.debug) ! { ! propButton = XtVaCreateManagedWidget ( ! "propButton", commandWidgetClass, mainWindow, ! XtNlabel, "List properties of each client", ! NULL); ! XtAddCallback (propButton, XtNcallback, ListPropXtProc, 0); ! } ! pingButton = XtVaCreateManagedWidget ( ! "pingButton", commandWidgetClass, mainWindow, ! XtNlabel, "Ping all clients", ! NULL); - XtAddCallback (pingButton, XtNcallback, PingXtProc, 0); ! startButton = XtVaCreateManagedWidget ( ! "startButton", commandWidgetClass, mainWindow, ! XtNlabel, "Start a new xsmclient", ! NULL); ! XtAddCallback (startButton, XtNcallback, StartXtProc, 0); ! /* ! * Pop up for Save Yourself button. ! */ ! savePopup = XtVaCreatePopupShell ( ! "savePopup", transientShellWidgetClass, topLevel, ! XtNtitle, "Save Yourself Parameters", ! NULL); ! ! saveForm = XtCreateManagedWidget ( ! "saveForm", formWidgetClass, savePopup, NULL, 0); ! saveTypeLabel = XtVaCreateManagedWidget ( ! "saveTypeLabel", labelWidgetClass, saveForm, ! XtNlabel, "Save Type ", ! XtNfromHoriz, NULL, ! XtNfromVert, NULL, ! XtNborderWidth, 0, ! NULL); ! saveTypeGlobal = AddToggle ( ! "saveTypeGlobal", /* widgetName */ ! saveForm, /* parent */ ! "Global", /* label */ ! 0, /* state */ ! NULL, /* radioGroup */ ! (XtPointer) &saveTypeData[0], /* radioData */ ! saveTypeLabel, /* fromHoriz */ ! NULL /* fromVert */ ! ); ! ! saveTypeLocal = AddToggle ( ! "saveTypeLocal", /* widgetName */ ! saveForm, /* parent */ ! "Local", /* label */ ! 0, /* state */ ! saveTypeGlobal, /* radioGroup */ ! (XtPointer) &saveTypeData[1], /* radioData */ ! saveTypeGlobal, /* fromHoriz */ ! NULL /* fromVert */ ! ); ! ! saveTypeBoth = AddToggle ( ! "saveTypeBoth", /* widgetName */ ! saveForm, /* parent */ ! "Both", /* label */ ! 1, /* state */ ! saveTypeGlobal, /* radioGroup */ ! (XtPointer) &saveTypeData[2], /* radioData */ ! saveTypeLocal, /* fromHoriz */ ! NULL /* fromVert */ ! ); ! ! ! shutdownLabel = XtVaCreateManagedWidget ( ! "shutdownLabel", labelWidgetClass, saveForm, ! XtNlabel, "Shutdown?", ! XtNfromHoriz, NULL, ! XtNfromVert, saveTypeLabel, ! XtNborderWidth, 0, ! NULL); ! shutdownYes = AddToggle ( ! "shutdownYes", /* widgetName */ ! saveForm, /* parent */ ! "Yes", /* label */ ! 0, /* state */ ! NULL, /* radioGroup */ ! (XtPointer) &shutdownData[0], /* radioData */ ! saveTypeLabel, /* fromHoriz */ ! saveTypeLabel /* fromVert */ ! ); ! ! shutdownNo = AddToggle ( ! "shutdownNo", /* widgetName */ ! saveForm, /* parent */ ! "No", /* label */ ! 1, /* state */ ! shutdownYes, /* radioGroup */ ! (XtPointer) &shutdownData[1], /* radioData */ ! shutdownYes, /* fromHoriz */ ! saveTypeLabel /* fromVert */ ! ); ! ! ! interactStyleLabel = XtVaCreateManagedWidget ( ! "interactStyleLabel", labelWidgetClass, saveForm, ! XtNlabel, "Interact Style", ! XtNfromHoriz, NULL, ! XtNfromVert, shutdownLabel, ! XtNborderWidth, 0, ! NULL); ! interactStyleNone = AddToggle ( ! "interactStyleNone", /* widgetName */ ! saveForm, /* parent */ ! "None", /* label */ ! 0, /* state */ ! NULL, /* radioGroup */ ! (XtPointer) &interactStyleData[0], /* radioData */ ! saveTypeLabel, /* fromHoriz */ ! shutdownLabel /* fromVert */ ! ); ! ! interactStyleErrors = AddToggle ( ! "interactStyleErrors", /* widgetName */ ! saveForm, /* parent */ ! "Errors", /* label */ ! 0, /* state */ ! interactStyleNone, /* radioGroup */ ! (XtPointer) &interactStyleData[1], /* radioData */ ! interactStyleNone, /* fromHoriz */ ! shutdownLabel /* fromVert */ ! ); ! ! interactStyleAny = AddToggle ( ! "interactStyleAny", /* widgetName */ ! saveForm, /* parent */ ! "Any", /* label */ ! 1, /* state */ ! interactStyleNone, /* radioGroup */ ! (XtPointer) &interactStyleData[2], /* radioData */ ! interactStyleErrors, /* fromHoriz */ ! shutdownLabel /* fromVert */ ! ); ! ! ! fastLabel = XtVaCreateManagedWidget ( ! "fastLabel", labelWidgetClass, saveForm, ! XtNlabel, "Fast?", ! XtNfromHoriz, NULL, ! XtNfromVert, interactStyleLabel, ! XtNborderWidth, 0, ! NULL); ! fastYes = AddToggle ( ! "fastYes", /* widgetName */ ! saveForm, /* parent */ ! "Yes", /* label */ ! 0, /* state */ ! NULL, /* radioGroup */ ! (XtPointer) &fastData[0], /* radioData */ ! saveTypeLabel, /* fromHoriz */ ! interactStyleLabel /* fromVert */ ! ); ! ! fastNo = AddToggle ( ! "fastNo", /* widgetName */ ! saveForm, /* parent */ ! "No", /* label */ ! 1, /* state */ ! fastYes, /* radioGroup */ ! (XtPointer) &fastData[1], /* radioData */ ! fastYes, /* fromHoriz */ ! interactStyleLabel /* fromVert */ ! ); ! ! ! saveOkButton = XtVaCreateManagedWidget ( ! "saveOkButton", commandWidgetClass, saveForm, ! XtNlabel, "OK", ! XtNfromHoriz, NULL, ! XtNfromVert, fastLabel, ! XtNvertDistance, 30, ! NULL); ! ! XtAddCallback (saveOkButton, XtNcallback, SaveOkXtProc, 0); - saveCancelButton = XtVaCreateManagedWidget ( - "saveCancelButton", commandWidgetClass, saveForm, - XtNlabel, "Cancel", - XtNfromHoriz, saveOkButton, - XtNfromVert, fastLabel, - XtNvertDistance, 30, - NULL); ! XtAddCallback (saveCancelButton, XtNcallback, SaveCancelXtProc, 0); ! /* ! * Pop up Shutdown confirmation. ! */ ! shutdownPopup = XtVaCreatePopupShell ("shutdownPopup", ! transientShellWidgetClass, topLevel, ! XtNtitle, "Shutdown Prompt", NULL); ! ! shutdownDialog = XtVaCreateManagedWidget ("shutdownDialog", ! dialogWidgetClass, shutdownPopup, ! XtNlabel, "There are no active clients. OK to shutdown?", ! NULL); - shutdownOkButton = XtVaCreateManagedWidget ("shutdownOkButton", - commandWidgetClass, shutdownDialog, XtNlabel, "OK", NULL); - - XtAddCallback (shutdownOkButton, XtNcallback, ShutdownOkXtProc, 0); ! shutdownCancelButton = XtVaCreateManagedWidget ("shutdownCancelButton", ! commandWidgetClass, shutdownDialog, XtNlabel, "Cancel", NULL); ! XtAddCallback (shutdownCancelButton, XtNcallback, ShutdownCancelXtProc, 0); ! /* ! * Realize top level. ! */ ! XtRealizeWidget (topLevel); ! ! 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 *) malloc((sizeof environment_name) + strlen(networkIds) + 1); ! if(!p) nomem(); ! sprintf(p, "%s=%s", environment_name, networkIds); ! putenv(p); ! if (app_resources.verbose || app_resources.debug) ! printf ("setenv %s %s\n", environment_name, networkIds); ! read_save(); ! restart_everything(); - if (app_resources.verbose) - printf ("Waiting for connections...\n"); ! free (networkIds); ! setjmp (JumpHere); ! XtAppMainLoop (appContext); ! } --- 28,1406 ---- /* * 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 ! #include ! ! #if defined(X_POSIX_C_SOURCE) ! #define _POSIX_C_SOURCE X_POSIX_C_SOURCE ! #include ! #undef _POSIX_C_SOURCE ! #elif defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) ! #include ! #else ! #define _POSIX_SOURCE ! #include ! #undef _POSIX_SOURCE ! #endif ! ! jmp_buf JumpHere; ! Atom wmStateAtom; ! Atom wmDeleteAtom; ! static char *cmd_line_display = NULL; ! ! /* ! * Forward declarations ! */ ! Status StartSession (); ! void NewConnectionXtProc (); ! Status NewClientProc (); ! void IoErrorHandler (); ! /* ! * 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; ! ! /* ! * Main program ! */ ! main (argc, argv) ! int argc; ! char **argv; ! { ! IceListenObj *listenObjs; ! 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 (); ! /* ! * Set my own IO error handler. ! */ ! IceSetIOErrorHandler (IoErrorHandler); ! /* ! * 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); ! } + 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 + */ ! setjmp (JumpHere); ! 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, "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); ! 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) + PopupBadSave (); else ! FinishUpSave (); ! } ! else if (ListCount (WaitForInteractList) > 0 && OkToEnterInteractPhase ()) ! { ! LetClientInteract (ListFirst (WaitForInteractList)); ! } ! else if (ListCount (WaitForPhase2List) > 0 && OkToEnterPhase2 ()) ! { ! StartPhase2 (); ! } ! } ! ! static 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) ! 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); ! } ! ! /* ! * Install IO error handler. This will detect clients that break their ! * connection with the SM unexpectidly. ! */ ! void ! IoErrorHandler (ice_conn) + IceConn ice_conn; ! { ! 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); ! } ! /* ! * We can't return. Must do a long jump. ! */ ! ! longjmp (JumpHere, 1); ! } *** - Wed Jan 18 13:28:54 1995 --- xc/workInProgress/xsm/Imakefile Wed Jan 18 13:28:54 1995 *************** *** 1,4 **** ! XCOMM $XConsortium: Imakefile,v 1.7 94/02/22 15:42:37 mor Exp $ #if !defined(RshCmd) #if SystemV #ifdef HPArchitecture --- 1,4 ---- ! XCOMM $XConsortium: Imakefile,v 1.16 94/12/27 17:42:37 mor Exp $ #if !defined(RshCmd) #if SystemV #ifdef HPArchitecture *************** *** 16,26 **** DEPLIBS = XawClientDepLibs LOCAL_LIBRARIES = XawClientLibs ! SRCS1 = auth.c list.c misc.c printhex.c remote.c restart.c save.c \ ! xsm.c xtwatch.c ! OBJS1 = auth.o list.o misc.o printhex.o remote.o restart.o save.o \ ! xsm.o xtwatch.o PROGS1 = xsm --- 16,28 ---- DEPLIBS = XawClientDepLibs LOCAL_LIBRARIES = XawClientLibs ! SRCS1 = auth.c choose.c info.c list.c lock.c log.c \ ! mainwin.c misc.c popup.c printhex.c prop.c remote.c \ ! restart.c save.c saveutil.c signals.c xsm.c xtwatch.c ! OBJS1 = auth.o choose.o info.o list.o lock.o log.o \ ! mainwin.o misc.o popup.o printhex.o prop.o remote.o \ ! restart.o save.o saveutil.o signals.o xsm.o xtwatch.o PROGS1 = xsm *************** *** 38,40 **** --- 40,46 ---- #if !HasPutenv SpecialCObjectRule(misc,NullParameter,-DNOPUTENV) #endif + SpecialCObjectRule(restart,$(_NOOP_),'-DSYSTEM_INIT_FILE="'$(XSMDIR)'/system.xsm"') + SpecialCObjectRule(signals,NullParameter,$(SIGNAL_DEFINES)) + InstallNonExecFile(system.xsm,$(XSMDIR)) + InstallAppDefaults(XSm) *** /dev/null Wed Jan 18 13:28:56 1995 --- xc/workInProgress/xsm/saveutil.c Wed Jan 18 13:28:55 1995 *************** *** 0 **** --- 1,558 ---- + /* $XConsortium: saveutil.c,v 1.31 95/01/03 17:23:35 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + #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; + } *** - Wed Jan 25 11:12:04 1995 --- xc/workInProgress/xsm/xsm.man Wed Jan 25 11:12:03 1995 *************** *** 1,4 **** ! .\" $XConsortium: xsm.man,v 1.2 94/04/18 18:24:31 rws Exp $ .\" Copyright (c) 1994 X Consortium .\" .\" Permission is hereby granted, free of charge, to any person obtaining --- 1,4 ---- ! .\" $XConsortium: xsm.man,v 1.11 95/01/04 18:26:53 mor Exp $ .\" Copyright (c) 1994 X Consortium .\" .\" Permission is hereby granted, free of charge, to any person obtaining *************** *** 26,37 **** .\" from the X Consortium. .TH XSM 1 "Release 6" "X Version 11" .SH NAME ! xsm \- X session manager .SH SYNOPSIS .B xsm ! [ TBD ] .SH DESCRIPTION .PP ! The \fIxsm\fP program is a simple session manager. ! .SH AUTHOR Ralph Mor, X Consortium --- 26,334 ---- .\" from the X Consortium. .TH XSM 1 "Release 6" "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 ! ! .br ! twm ! .br ! smproxy ! .br ! xterm ! .br ! ! .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 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 *** - Wed Jan 18 13:29:00 1995 --- xc/workInProgress/xsm/save.c Wed Jan 18 13:28:59 1995 *************** *** 1,4 **** ! /* $XConsortium: save.c,v 1.4 94/04/17 21:15:18 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium --- 1,4 ---- ! /* $XConsortium: save.c,v 1.19 94/12/30 16:51:59 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium *************** *** 26,214 **** ******************************************************************************/ #include "xsm.h" ! extern List *PendingList; ! extern ClientRec *ClientList; ! char session_save_file[PATH_MAX]; ! static Bool getline(); ! void ! read_save() ! { ! char *buf; ! int buflen; ! char *p; ! char *q; ! PendingClient *c; ! PendingProp *prop; ! PendingValue *val; ! FILE *f; ! int state; ! ! PendingList = ListInit(); ! if(!PendingList) nomem(); ! ! p = (char *) getenv("HOME"); ! if(!p) p = "."; ! strcpy(session_save_file, p); ! strcat(session_save_file, "/.SM-save"); ! ! f = fopen(session_save_file, "r"); ! if(!f) { ! if (app_resources.verbose) ! printf("No session save file.\n"); return; } - if (app_resources.verbose) - printf("Reading session save file...\n"); ! buf = NULL; ! buflen = 0; ! 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) { ! state = 0; ! continue; } ! if(!isspace(buf[0])) { ! switch(state) { ! case 0: ! c = (PendingClient *)malloc(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, (void *)c)) nomem(); ! state = 1; ! break; ! case 1: ! c->clientHostname = XtNewString(p); ! state = 2; ! break; ! case 2: ! case 4: ! prop = (PendingProp *)malloc(sizeof *prop); ! if(!prop) nomem(); ! prop->name = XtNewString(p); ! prop->values = ListInit(); ! if(!prop->values) nomem(); ! prop->type = NULL; ! if(!ListAddLast(c->props, (void *)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 = (PendingValue *)malloc(sizeof *val); ! if(!val) nomem(); ! val->length = strlen(p); ! /* NEEDSWORK: Binary data */ ! val->value = XtNewString(p); ! if(!ListAddLast(prop->values, (void *)val)) nomem(); } } ! fclose(f); } void ! write_save() { - FILE *f; ClientRec *client; ! SmProp *prop; ! int i, j; ! f = fopen(session_save_file, "w"); ! if(!f) { ! perror("open session save file for write"); ! } else { ! for(client = ClientList; client; client = client->next) ! { ! fprintf(f, "%s\n", client->clientId); ! fprintf(f, "%s\n", client->clientHostname); ! for(i = 0; i < client->numProps; i++) { ! prop = client->props[i]; ! fprintf(f, "%s\n", prop->name); ! fprintf(f, "%s\n", prop->type); ! if (strcmp (prop->type, SmCARD8) == 0) ! { ! char *card8 = prop->vals->value; ! int value = *card8; ! fprintf(f, "\t%d\n", value); ! } ! else ! { ! for(j = 0; j < prop->num_vals; j++) ! fprintf(f, "\t%s\n", prop->vals[j].value); ! } ! } ! fprintf(f, "\n"); ! } ! fclose(f); } } ! static 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); ! else *pbuf = (char *) malloc(*plen); ! } ! c = getc(f); ! if(c == EOF) break; ! (*pbuf)[i++] = c; ! if(c == '\n') break; } ! (*pbuf)[i] = '\0'; ! return i; } --- 26,1493 ---- ******************************************************************************/ #include "xsm.h" + #include "save.h" + #include "saveutil.h" + #include "popup.h" + + #include + #include + #include + #include + #include + #include ! ! 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; ! ! 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; ! ! 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 ! DoSave () ! ! { ! ClientRec *client; ! XtPointer ptr; ! List *cl; ! int saveType; ! int interactStyle; ! Bool fast = False; ! char *_saveType; ! char *_shutdown; ! char *_interactStyle; ! ! 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); ! ! 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; ! ! if ((status = GetSaveName (&name)) != NAME_OK) ! { ! XBell (XtDisplay (topLevel), 0); ! ! 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; } ! DoSave (); ! } ! ! ! 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); ! } ! } ! ! ! ! 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. ! */ ! ! if (name_locked) ! { ! /* Force shutdown */ } + + DeleteSession (name_in_use); + + MakeCurrentSession (name_in_use, True); + + name_in_use = NULL; + + DoSave (); + + 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) ! { ! 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 ! ("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); ! } ! } } *** - Wed Jan 18 13:29:05 1995 --- xc/workInProgress/xsm/restart.c Wed Jan 18 13:29:04 1995 *************** *** 1,4 **** ! /* $XConsortium: restart.c,v 1.5 94/05/12 11:59:01 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium --- 1,4 ---- ! /* $XConsortium: restart.c,v 1.25 95/01/03 17:30:37 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium *************** *** 26,149 **** ******************************************************************************/ #include "xsm.h" - extern List *PendingList; extern void remote_start (); ! void ! restart_everything() { ! List *cl; ! List *pl; ! List *vl; ! PendingClient *c; ! PendingProp *prop; ! PendingValue *v; ! char *cwd; ! char *program; ! char **args; ! char **env; ! char **pp; ! int cnt; ! extern char **environ; ! char *p, *temp; ! static char envDISPLAY[]="DISPLAY"; ! static char envSESSION_MANAGER[]="SESSION_MANAGER"; ! static char envAUDIOSERVER[]="AUDIOSERVER"; ! char *display_env, *non_local_display_env; ! char *session_env, *non_local_session_env; ! char *audio_env; ! int remote_allowed = 1; ! ! display_env = NULL; ! if(p = (char *) getenv(envDISPLAY)) { ! display_env = (char *) malloc(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 *) malloc (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 *) malloc (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 *) malloc( ! 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 *) malloc (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 *) malloc(strlen(envAUDIOSERVER)+1+strlen(p)+1); ! if(!audio_env) nomem(); ! sprintf(audio_env, "%s=%s", envAUDIOSERVER, p); ! } for(cl = ListFirst(PendingList); cl; cl = ListNext(cl)) { c = (PendingClient *)cl->thing; ! if (app_resources.verbose) { printf("Restarting id '%s'...\n", c->clientId); printf("Host = %s\n", c->clientHostname); } --- 26,182 ---- ******************************************************************************/ #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); } *************** *** 151,179 **** env = NULL; program=NULL; args=NULL; for(pl = ListFirst(c->props); pl; pl = ListNext(pl)) { ! prop = (PendingProp *)pl->thing; ! if(!strcmp(prop->name, "Program")) { vl = ListFirst(prop->values); ! if(vl) program = ((PendingValue *)vl->thing)->value; ! } else if(!strcmp(prop->name, "CurrentDirectory")) { vl = ListFirst(prop->values); ! if(vl) cwd = ((PendingValue *)vl->thing)->value; ! } else if(!strcmp(prop->name, "RestartCommand")) { cnt = ListCount(prop->values); ! args = (char **)malloc((cnt+1) * sizeof(char *)); pp = args; for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) { ! *pp++ = ((PendingValue *)vl->thing)->value; } *pp = NULL; ! } else if(!strcmp(prop->name, "Environment")) { cnt = ListCount(prop->values); ! env = (char **)malloc((cnt+3+1) * sizeof(char *)); pp = env; for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) { ! p = ((PendingValue *)vl->thing)->value; if((display_env && strbw(p, "DISPLAY=")) || (session_env && strbw(p, "SESSION_MANAGER=")) || (audio_env && strbw(p, "AUDIOSERVER=")) --- 184,221 ---- 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=")) *************** *** 188,216 **** } if(program && args) { ! if (app_resources.verbose) { printf("\t%s\n", program); printf("\t"); for(pp = args; *pp; pp++) printf("%s ", *pp); printf("\n"); } ! if (strncmp(c->clientHostname, "tcp/", 4) != 0 && ! strncmp(c->clientHostname, "decnet/", 7) != 0) { /* * The client is being restarted on the local machine. */ switch(fork()) { case -1: ! perror("fork"); break; case 0: /* kid */ chdir(cwd); if(env) environ = env; execvp(program, args); ! perror("execve"); _exit(255); default: /* parent */ break; --- 230,296 ---- } 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; *************** *** 228,246 **** * The client is being restarted on a remote machine. */ ! remote_start (c->clientHostname, program, args, cwd, env, non_local_display_env, non_local_session_env); } } else { fprintf(stderr, "Can't restart ID '%s': no program or no args\n", c->clientId); } ! if(args) free((char *)args); ! if(env) free((char *)env); } - if(display_env) free(display_env); - if(session_env) free(session_env); - if(non_local_display_env) free(non_local_display_env); - if(non_local_session_env) free(non_local_session_env); - if(audio_env) free(audio_env); } --- 308,621 ---- * 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 ! { ! XBell (XtDisplay (topLevel), 0); ! ! 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; } } *** - Wed Jan 18 13:29:08 1995 --- xc/workInProgress/xsm/auth.c Wed Jan 18 13:29:07 1995 *************** *** 1,4 **** ! /* $XConsortium: auth.c,v 1.5 94/04/17 21:15:15 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium --- 1,4 ---- ! /* $XConsortium: auth.c,v 1.12 94/12/30 16:09:14 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium *************** *** 27,32 **** --- 27,38 ---- #include "xsm.h" + #include + + static char *addAuthFile = NULL; + static char *remAuthFile = NULL; + + /* * Host Based Authentication Callback. This callback is invoked if *************** *** 35,41 **** */ Bool ! HostBasedProc (hostname) char *hostname; --- 41,47 ---- */ Bool ! HostBasedAuthProc (hostname) char *hostname; *************** *** 75,80 **** --- 81,115 ---- + 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 */ *************** *** 82,106 **** #define MAGIC_COOKIE_LEN 16 Status ! set_auth (count, listenObjs, authDataEntries) int count; IceListenObj *listenObjs; IceAuthDataEntry **authDataEntries; { ! FILE *addfp; ! FILE *removefp; int i; ! if (!(addfp = fopen (".xsm-add-auth", "w"))) ! return (0); ! if (!(removefp = fopen (".xsm-rem-auth", "w"))) ! return (0); ! *authDataEntries = (IceAuthDataEntry *) malloc ( ! count * 2 * sizeof (IceAuthDataEntry)); for (i = 0; i < count * 2; i += 2) { --- 117,161 ---- #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) { *************** *** 127,141 **** IceSetPaAuthData (2, &(*authDataEntries)[i]); ! IceSetHostBasedAuthProc (listenObjs[i/2], HostBasedProc); } fclose (addfp); fclose (removefp); ! system ("iceauth source .xsm-add-auth"); return (1); } --- 182,222 ---- 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); } *************** *** 145,151 **** */ void ! free_auth (count, authDataEntries) int count; IceAuthDataEntry *authDataEntries; --- 226,232 ---- */ void ! FreeAuthenticationData (count, authDataEntries) int count; IceAuthDataEntry *authDataEntries; *************** *** 153,158 **** --- 234,240 ---- { /* Each transport has entries for ICE and XSMP */ + char command[256]; int i; for (i = 0; i < count * 2; i++) *************** *** 161,167 **** free (authDataEntries[i].auth_data); } ! free ((char *) authDataEntries); ! system ("iceauth source .xsm-rem-auth"); } --- 243,255 ---- free (authDataEntries[i].auth_data); } ! XtFree ((char *) authDataEntries); ! ! sprintf (command, "iceauth source %s", remAuthFile); ! execute_system_command (command); ! ! unlink (remAuthFile); ! free (addAuthFile); ! free (remAuthFile); } *** - Wed Jan 18 13:29:09 1995 --- xc/workInProgress/xsm/remote.c Wed Jan 18 13:29:09 1995 *************** *** 1,4 **** ! /* $XConsortium: remote.c,v 1.5 94/05/02 11:30:58 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium --- 1,4 ---- ! /* $XConsortium: remote.c,v 1.15 95/01/03 17:26:52 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium *************** *** 31,37 **** #include "xsm.h" ! static char *spaces_to_octal(); extern IceAuthDataEntry *authDataEntries; extern int numTransports; --- 31,39 ---- #include "xsm.h" ! #include ! ! static char *format_rstart_env(); extern IceAuthDataEntry *authDataEntries; extern int numTransports; *************** *** 39,48 **** void ! remote_start (client_host, program, args, cwd, env, non_local_display_env, non_local_session_env) ! char *client_host; char *program; char **args; char *cwd; --- 41,51 ---- 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; *************** *** 52,75 **** { FILE *fp; - char *hostname; - char *tmp; int pipefd[2]; int i; ! if ((tmp = (char *) strchr (client_host, '/')) == NULL) ! hostname = client_host; ! else ! hostname = tmp + 1; ! if (app_resources.verbose) { ! printf ("Attempting to restart remote client on %s\n", hostname); } if (pipe (pipefd) < 0) { ! perror ("pipe error"); } else { --- 55,89 ---- { FILE *fp; int pipefd[2]; + extern char **environ; + 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 { *************** *** 77,83 **** { case -1: ! perror("fork"); break; case 0: /* kid */ --- 91,100 ---- { 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 */ *************** *** 87,120 **** dup (pipefd[0]); close (pipefd[0]); ! execlp (RSHCMD, hostname, "rstartd", (char *) 0); ! perror("Failed to start remote client with rstart protocol"); _exit(255); default: /* parent */ close (pipefd[0]); ! fp = fdopen (pipefd[1], "w"); fprintf (fp, "CONTEXT X\n"); fprintf (fp, "DIR %s\n", cwd); if (env) for (i = 0; env[i]; i++) { /* ! * There may be spaces inside some of the environment ! * values, and rstartd will barf on spaces. Need ! * to replace space characters with their equivalent ! * octal escape sequences. */ ! char *temp = spaces_to_octal (env[i]); fprintf (fp, "MISC X %s\n", temp); if (temp != env[i]) ! free (temp); } fprintf (fp, "MISC X %s\n", non_local_display_env); fprintf (fp, "MISC X %s\n", non_local_session_env); --- 104,169 ---- 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); *************** *** 159,202 **** /* ! * rstart requires that any spaces inside of a string be represented by ! * octal escape sequences. */ static char * ! spaces_to_octal (str) char *str; { ! int space_count = 0; char *temp = str; while (*temp != '\0') { ! if (*temp == ' ') ! space_count++; temp++; } ! if (space_count == 0) return (str); else { ! int len = strlen (str) + 1 + (space_count * 4); ! char *ret = (char *) malloc (len); char *ptr = ret; temp = str; while (*temp != '\0') { ! if (*temp != ' ') ! *(ptr++) = *temp; ! else { ! ptr[0] = '\\'; ptr[1] = '0'; ptr[2] = '4'; ptr[3] = '0'; ! ptr += 4; } temp++; } --- 208,257 ---- /* ! * 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++; } *** - Wed Jan 18 13:29:11 1995 --- xc/workInProgress/xsm/misc.c Wed Jan 18 13:29:11 1995 *************** *** 1,4 **** ! /* $XConsortium: misc.c,v 1.3 94/04/17 21:15:16 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium --- 1,4 ---- ! /* $XConsortium: misc.c,v 1.5 94/12/16 17:32:02 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium *************** *** 72,78 **** if(virgin) { register i; ! newenv = (char **) malloc((unsigned) ((idx + 2) * sizeof(char*))); if(newenv == 0) return -1; for(i = idx-1; i >= 0; --i) --- 72,78 ---- if(virgin) { register i; ! newenv = (char **) XtMalloc((unsigned) ((idx + 2) * sizeof(char*))); if(newenv == 0) return -1; for(i = idx-1; i >= 0; --i) *************** *** 129,134 **** --- 129,150 ---- 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 *** - Wed Jan 18 13:29:14 1995 --- xc/workInProgress/xsm/xsm.h Wed Jan 18 13:29:14 1995 *************** *** 1,4 **** ! /* $XConsortium: xsm.h,v 1.5 94/04/17 21:15:20 rws Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium --- 1,4 ---- ! /* $XConsortium: xsm.h,v 1.36 95/01/03 17:22:47 mor Exp $ */ /****************************************************************************** Copyright (c) 1993 X Consortium *************** *** 25,53 **** in this Software without prior written authorization from the X Consortium. ******************************************************************************/ ! #include ! #include ! #include ! #include ! #include ! #include #include ! #ifndef _POSIX_SOURCE #define _POSIX_SOURCE ! #include #undef _POSIX_SOURCE - #else - #include - #endif - #include - #include - #include - #include - #ifndef X_NOT_STDC_ENV - #include #endif ! #include ! #include #include #ifndef PATH_MAX #ifdef MAXPATHLEN --- 25,43 ---- in this Software without prior written authorization from the X Consortium. ******************************************************************************/ ! #include #include ! ! #ifndef X_NOT_POSIX ! #ifdef _POSIX_SOURCE ! #include ! #else #define _POSIX_SOURCE ! #include #undef _POSIX_SOURCE #endif ! #endif /* X_NOT_POSIX */ ! #ifndef PATH_MAX #include #ifndef PATH_MAX #ifdef MAXPATHLEN *************** *** 56,81 **** #define PATH_MAX 1024 #endif #endif ! #include ! /* Fix ISC brain damage. When using gcc fdopen isn't declared in . */ ! #if defined(SYSV) && defined(SYSV386) && defined(__STDC__) && defined(ISC) ! extern FILE *fdopen(int, char const *); #endif #include "list.h" ! #define MAX_PROPS 50 typedef struct _ClientRec { SmsConn smsConn; IceConn ice_conn; char *clientId; char *clientHostname; ! Bool interactPending; ! int numProps; ! SmProp * props[MAX_PROPS]; ! struct _ClientRec *next; } ClientRec; typedef struct _PendingClient { --- 46,101 ---- #define PATH_MAX 1024 #endif #endif ! #endif /* PATH_MAX */ ! #ifndef _POSIX_SOURCE ! #define _POSIX_SOURCE ! #include ! #undef _POSIX_SOURCE ! #else ! #include #endif + #include + #ifndef X_NOT_STDC_ENV + #include + #endif + + #include + #include + + #include + #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 { *************** *** 84,107 **** List *props; } PendingClient; ! typedef struct _PendingProp { char *name; char *type; List *values; ! } PendingProp; ! typedef struct _PendingValue { XtPointer value; int length; ! } PendingValue; ! typedef struct _AppResources { ! Boolean verbose; ! Boolean debug; ! } AppResources; ! extern AppResources app_resources; extern void fprintfhex (); --- 104,176 ---- 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 (); *************** *** 111,114 **** extern char *Strstr(); #endif ! extern strbw (); --- 180,191 ---- extern char *Strstr(); #endif ! /* Fix ISC brain damage. When using gcc fdopen isn't declared in . */ ! #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 *** /dev/null Wed Jan 18 13:29:17 1995 --- xc/workInProgress/xsm/XSm.ad Wed Jan 18 13:29:16 1995 *************** *** 0 **** --- 1,111 ---- + ! $XConsortium: XSm.ad,v 1.26 94/12/30 16:14:48 mor Exp $ + *chooseSessionPopup*font: 12x24 + *chooseSessionLabel.label: Session Menu + *chooseSessionMessageLabel.label: Press button again to confirm... + *chooseSessionLoadButton.label: Load Session + *chooseSessionDeleteButton.label: Delete Session + *chooseSessionFailSafeButton.label: Default/Fail Safe + *chooseSessionCancelButton.label: Cancel + + *chooseSessionLoadButton.background: light steel blue + *chooseSessionDeleteButton.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 + *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\ + Up: ChooseSessionUp()\n\ + Down: ChooseSessionDown()\n\ + : Set() ChooseSessionBtn1Down()\n + + *chooseSessionLoadButton.Accelerators: #override\n\ + (2+): set() notify() unset()\n\ + Return: set() notify() unset()\n + + *checkPointButton.Translations: #override\n\ + : notify() reset()\n + *shutdownButton.Translations: #override\n\ + : notify() reset()\n + + *saveOkButton.Accelerators: #override\n\ + Return: set() notify() unset()\n + + *badSaveOkButton.Accelerators: #override\n\ + Return: set() notify() unset()\n *** /dev/null Wed Jan 18 13:29:18 1995 --- xc/workInProgress/xsm/system.xsm Wed Jan 18 13:29:18 1995 *************** *** 0 **** --- 1,4 ---- + ! $XConsortium: system.xsm,v 1.5 94/12/27 17:57:25 mor Exp $ + twm + smproxy + xterm *** /dev/null Wed Jan 18 13:29:19 1995 --- xc/workInProgress/xsm/log.c Wed Jan 18 13:29:19 1995 *************** *** 0 **** --- 1,162 ---- + /* $XConsortium: log.c,v 1.3 94/12/27 17:44:30 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + #include "xsm.h" + #include "save.h" + #include "popup.h" + + #include + #include + #include + #include + + 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) + { + 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); + } *** /dev/null Wed Jan 18 13:29:20 1995 --- xc/workInProgress/xsm/log.h Wed Jan 18 13:29:20 1995 *************** *** 0 **** --- 1,30 ---- + /* $XConsortium: log.h,v 1.1 94/12/12 20:09:50 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + extern void DisplayLogXtProc (); + extern void create_log_popup (); + extern void add_log_text (); *** /dev/null Wed Jan 18 13:29:21 1995 --- xc/workInProgress/xsm/choose.c Wed Jan 18 13:29:21 1995 *************** *** 0 **** --- 1,701 ---- + /* $XConsortium: choose.c,v 1.22 94/12/30 15:50:31 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + #include "xsm.h" + #include "saveutil.h" + #include "lock.h" + #include + + #include + #include + #include + #include + + #ifndef X_NOT_POSIX + #include + #else + #ifdef SYSV + #include + #else + #ifdef USG + #include + #else + #include + #ifndef dirent + #define dirent direct + #endif + #endif + #endif + #endif + + static Pixel save_message_foreground; + static Pixel save_message_background; + + static int delete_phase = 0; + + Widget chooseSessionPopup; + Widget chooseSessionForm; + Widget chooseSessionLabel; + Widget chooseSessionListWidget; + Widget chooseSessionMessageLabel; + Widget chooseSessionLoadButton; + Widget chooseSessionDeleteButton; + #if 0 + Widget chooseSessionForceShutdownButton; + #endif + 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; + + { + Bool locked = sessionsLocked[number]; + + if (highlight) + XawListHighlight (chooseSessionListWidget, number); + + XtSetSensitive (chooseSessionLoadButton, !locked); + XtSetSensitive (chooseSessionDeleteButton, !locked); + #if 0 + XtSetSensitive (chooseSessionForceShutdownButton, locked); + #endif + } + + + + static void + AddSessionNames (count, names) + + int count; + String *names; + + { + XawListChange (chooseSessionListWidget, names, count, 0, True); + SessionSelected (0, 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 + ChooseSessionUp (w, event, params, numParams) + + Widget w; + XEvent *event; + String *params; + Cardinal *numParams; + + { + XawListReturnStruct *current; + + 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; + + 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; + + 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; + + current = XawListShowCurrent (chooseSessionListWidget); + + if (!current || !current->string || *(current->string) == '\0') + { + if (current) + XtFree ((char *) current); + XBell (XtDisplay (topLevel), 0); + 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- 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; + + current = XawListShowCurrent (chooseSessionListWidget); + + if (!current || !(name = current->string) || *name == '\0') + { + if (current) + XtFree ((char *) current); + XBell (XtDisplay (topLevel), 0); + return; + } + + delete_phase++; + + if (delete_phase == 1) + { + XtVaSetValues (chooseSessionMessageLabel, + XtNforeground, save_message_foreground, + NULL); + + XBell (XtDisplay (topLevel), 0); + } + 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); + } + } + + delete_phase = 0; + } + + XtFree ((char *) current); + } + + + + #if 0 + static void + ChooseSessionForceShutdownXtProc (w, client_data, callData) + + Widget w; + XtPointer client_data; + XtPointer callData; + + { + XBell (XtDisplay (topLevel), 0); + } + #endif + + + + 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. + */ + + 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_phase > 0) + { + XtVaSetValues (chooseSessionMessageLabel, + XtNforeground, save_message_background, + NULL); + + delete_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); + + #if 0 + chooseSessionForceShutdownButton = XtVaCreateManagedWidget ( + "chooseSessionForceShutdownButton", + commandWidgetClass, chooseSessionForm, + XtNfromHoriz, chooseSessionDeleteButton, + XtNfromVert, chooseSessionMessageLabel, + NULL); + + XtAddCallback (chooseSessionForceShutdownButton, XtNcallback, + ChooseSessionForceShutdownXtProc, 0); + #endif + + chooseSessionFailSafeButton = XtVaCreateManagedWidget ( + "chooseSessionFailSafeButton", commandWidgetClass, chooseSessionForm, + XtNfromHoriz, chooseSessionDeleteButton, + 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); + } *** /dev/null Wed Jan 18 13:29:22 1995 --- xc/workInProgress/xsm/choose.h Wed Jan 18 13:29:22 1995 *************** *** 0 **** --- 1,31 ---- + /* $XConsortium: choose.h,v 1.4 94/07/15 14:12:58 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + extern void create_choose_session_popup (); + extern int GetSessionNames (); + extern void FreeSessionNames (); + extern void ChooseSession (); *** /dev/null Wed Jan 18 13:29:24 1995 --- xc/workInProgress/xsm/info.c Wed Jan 18 13:29:23 1995 *************** *** 0 **** --- 1,1032 ---- + /* $XConsortium: info.c,v 1.25 95/01/03 18:35:35 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + #include "xsm.h" + #include "restart.h" + #include "popup.h" + + #include + #include + #include + #include + #include + #include + #include + #include + + 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) + { + 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); + 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); + 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) + { + 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); + } *** /dev/null Wed Jan 18 13:29:25 1995 --- xc/workInProgress/xsm/info.h Wed Jan 18 13:29:24 1995 *************** *** 0 **** --- 1,30 ---- + /* $XConsortium: info.h,v 1.1 94/07/07 16:47:38 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + extern void create_client_info_popup (); + extern void UpdateClientList (); + extern void ClientInfoXtProc (); *** /dev/null Wed Jan 18 13:29:26 1995 --- xc/workInProgress/xsm/mainwin.c Wed Jan 18 13:29:25 1995 *************** *** 0 **** --- 1,136 ---- + /* $XConsortium: mainwin.c,v 1.8 94/12/27 17:43:10 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + #include "xsm.h" + #include "info.h" + #include "save.h" + #include "log.h" + + #include + #include + #include + #include + #include + #include + + 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)); + } *** /dev/null Wed Jan 18 13:29:27 1995 --- xc/workInProgress/xsm/mainwin.h Wed Jan 18 13:29:26 1995 *************** *** 0 **** --- 1,28 ---- + /* $XConsortium: mainwin.h,v 1.1 94/07/07 16:47:40 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + extern void create_main_window (); *** /dev/null Wed Jan 18 13:29:28 1995 --- xc/workInProgress/xsm/prop.c Wed Jan 18 13:29:27 1995 *************** *** 0 **** --- 1,421 ---- + /* $XConsortium: prop.c,v 1.6 94/12/16 17:30:38 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + #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); + } *** /dev/null Wed Jan 18 13:29:29 1995 --- xc/workInProgress/xsm/save.h Wed Jan 18 13:29:28 1995 *************** *** 0 **** --- 1,36 ---- + /* $XConsortium: save.h,v 1.4 94/08/30 17:22:36 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + 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 (); *** /dev/null Wed Jan 18 13:29:30 1995 --- xc/workInProgress/xsm/auth.h Wed Jan 18 13:29:29 1995 *************** *** 0 **** --- 1,30 ---- + /* $XConsortium: auth.h,v 1.1 94/07/08 14:06:36 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + extern Status SetAuthentication (); + extern void FreeAuthenticationData (); + extern Bool HostBasedAuthProc (); *** /dev/null Wed Jan 18 13:29:31 1995 --- xc/workInProgress/xsm/globals.c Wed Jan 18 13:29:30 1995 *************** *** 0 **** --- 1,89 ---- + /* $XConsortium: globals.c,v 1.22 95/01/03 17:22:38 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + #include + + 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; + *** /dev/null Wed Jan 18 13:29:31 1995 --- xc/workInProgress/xsm/restart.h Wed Jan 18 13:29:31 1995 *************** *** 0 **** --- 1,31 ---- + /* $XConsortium: restart.h,v 1.4 94/11/14 15:32:28 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + extern void StartDefaultApps (); + extern void StartNonSessionAwareApps (); + extern Status Restart (); + extern void Clone (); *** /dev/null Wed Jan 18 13:29:32 1995 --- xc/workInProgress/xsm/xtwatch.h Wed Jan 18 13:29:32 1995 *************** *** 0 **** --- 1,28 ---- + /* $XConsortium: xtwatch.h,v 1.1 94/07/08 14:06:58 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + extern Status InitWatchProcs (); *** /dev/null Wed Jan 18 13:29:33 1995 --- xc/workInProgress/xsm/saveutil.h Wed Jan 18 13:29:33 1995 *************** *** 0 **** --- 1,30 ---- + /* $XConsortium: saveutil.h,v 1.3 94/12/12 20:01:02 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + extern int ReadSave (); + extern void WriteSave (); + extern Status DeleteSession (); *** /dev/null Wed Jan 18 13:29:34 1995 --- xc/workInProgress/xsm/signals.c Wed Jan 18 13:29:34 1995 *************** *** 0 **** --- 1,213 ---- + /* $XConsortium: signals.c,v 1.1 94/12/16 17:47:12 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + #include + #include + + #ifdef USG + #ifndef __TYPES__ + #include /* forgot to protect it... */ + #define __TYPES__ + #endif /* __TYPES__ */ + #else + #if defined(_POSIX_SOURCE) && defined(MOTOROLA) + #undef _POSIX_SOURCE + #include + #define _POSIX_SOURCE + #else + #include + #endif + #endif /* USG */ + + #ifdef X_POSIX_C_SOURCE + #define _POSIX_C_SOURCE X_POSIX_C_SOURCE + #include + #include + #undef _POSIX_C_SOURCE + #else + #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) + #include + #include + #else + #define _POSIX_SOURCE + #include + #include + #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 + + + + 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 + register_signals () + + { + /* + * Ignore SIGPIPE + */ + + Signal (SIGPIPE, SIG_IGN); + + + /* + * If child process dies, call our handler + */ + + Signal (SIGCHLD, sig_child_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); + } + + *** /dev/null Wed Jan 18 13:29:35 1995 --- xc/workInProgress/xsm/prop.h Wed Jan 18 13:29:35 1995 *************** *** 0 **** --- 1,35 ---- + /* $XConsortium: prop.h,v 1.1 94/08/17 19:25:52 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1993 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + extern void FreePropValues (); + extern void FreeProp (); + extern void SetInitialProperties (); + extern void SetProperty (); + extern void DeleteProperty (); + extern void SetPropertiesProc (); + extern void DeletePropertiesProc (); + extern void GetPropertiesProc (); *** /dev/null Wed Jan 18 13:29:36 1995 --- xc/workInProgress/xsm/lock.c Wed Jan 18 13:29:36 1995 *************** *** 0 **** --- 1,162 ---- + /* $XConsortium: lock.c,v 1.4 94/12/16 17:32:57 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + #include "xsm.h" + #include + + + 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)) + { + 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); + } + + + Bool + CheckSessionLocked (session_name, get_id, id_ret) + + char *session_name; + Bool get_id; + char **id_ret; + + { + if (get_id) + { + char *path; + FILE *fp; + char lock_file[PATH_MAX]; + char buf[256]; + + path = GetPath (); + + sprintf (lock_file, "%s/.XSMlock-%s", path, session_name); + + if ((fp = fopen (lock_file, "r")) == NULL) + { + *id_ret = NULL; + return (0); + } + + buf[0] = '\0'; + fscanf (fp, "%s\n", buf); + *id_ret = XtNewString (buf); + + fclose (fp); + } + + 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. + */ + + XBell (XtDisplay (topLevel), 0); + sleep (2); + + ChooseSession (); + } *** /dev/null Wed Jan 18 13:29:37 1995 --- xc/workInProgress/xsm/lock.h Wed Jan 18 13:29:37 1995 *************** *** 0 **** --- 1,31 ---- + /* $XConsortium: lock.h,v 1.1 94/12/06 14:44:18 mor Exp $ */ + /****************************************************************************** + + Copyright (c) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + 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 + X CONSORTIUM 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 X Consortium 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 X Consortium. + ******************************************************************************/ + + extern Status LockSession (); + extern void UnlockSession (); + extern Bool CheckSessionLocked (); + extern void UnableToLockSession (); *** /dev/null Wed Jan 18 13:29:38 1995 --- xc/workInProgress/xsm/README Wed Jan 18 13:29:38 1995 *************** *** 0 **** --- 1,90 ---- + $XConsortium: README,v 1.5 95/01/04 18:26:53 mor Exp $ + + README file for the X Session Manager (xsm) + ------------------------------------------- + + xsm is a session manager. A session is a group of applications, each + of which has a particular state. xsm 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. + + Some session managers simply allow you to manually specify a list of + applications to be started in a session. xsm is more powerful because it + lets you run applications and have them automatically become part of the + session. On a simple level, xsm is useful because it gives you this ability + to easily define which applications are in a session. The true power of + xsm, however, can be taken advantage of when more and more applications + learn to save and restore their state. + + This README file discusses the necessary steps you must take to run xsm. To + learn more about the details of xsm's functionality, read the xsm man page. + + Before building xsm, you should make sure you have the following libraries + built on your system with all fix-trackers patches applied: + + libICE - the Inter Client Exchange Library + libSM - the Session Management Library + libXt - the X Toolkit with support for session management + + To build these libraries, you would change your current directory to + lib/ICE, lib/SM, or lib/Xt and do the following: + + make Makefile + make includes + make depend + make + + + Once you are sure all of the required libraries are built, you are ready + to build xsm. + + Change your current directory to workInProgress + + make Makefiles SUBDIRS=xsm + cd xsm + make includes + make depend + make install + + + Before you can run xsm, you must make sure that the following programs are + built and installed on your system with all fix-trackers patches applied: + + smproxy - the session manager proxy for applications that don't support + R6 style session management + iceauth - handles storing/retrieving ICE authentication information + rstart - allows xsm to start applications on remote machines + twm - window manager that support R6 style session management - takes + care of saving window configurations in a session + + To build and install these programs, you would change your current directory + to programs/smproxy, programs/iceauth, programs/rstart, or programs/twm and + do the following: + + make Makefile + make includes + make depend + make install + + + Note that to install rstart, you will need to have root privileges because + the program must be installed in a system wide default path. + + *** rstart and iceauth should be installed on each machine that you expect + to run applications on that will be part of your session *** + + Also note that twm is the default window manager that xsm starts up. If you + would like to use a different window manager, follow the instructions in the + xsm man page for defining the default startup applications. Be aware that if + the window manager you choose has not been modified to support R6 style + session management, window configurations will not be saved in your sessions. + + Once again, for more information about actually using xsm, please read the + xsm man page. + + To learn more about making your applications "session aware", consult the + X Toolkit Intrinsics documentation. *** /dev/null Wed Jan 18 13:29:39 1995 --- xc/workInProgress/xsm/popup.h Wed Jan 18 13:29:39 1995 *************** *** 0 **** --- 1,33 ---- + /* $XConsortium: popup.h,v 1.1 94/12/27 17:59:58 mor Exp $ */ + + /* + + Copyright (c) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + 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 X CONSORTIUM 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 X Consortium 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 X Consortium. + + */ + + extern void PopupPopup (); *** /dev/null Wed Jan 18 13:29:40 1995 --- xc/workInProgress/xsm/popup.c Wed Jan 18 13:29:40 1995 *************** *** 0 **** --- 1,186 ---- + /* $XConsortium: popup.c,v 1.2 94/12/27 19:28:16 mor Exp $ */ + + /* + + Copyright (c) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + 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 X CONSORTIUM 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 X Consortium 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 X Consortium. + + */ + + #include "xsm.h" + #include + + + 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); + } + }