save.c revision 99c4c48a
1/* $Xorg: save.c,v 1.5 2001/02/09 02:06:01 xorgcvs Exp $ */
2/******************************************************************************
3
4Copyright 1993, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25******************************************************************************/
26/* $XFree86: xc/programs/xsm/save.c,v 3.3 2001/01/17 23:46:30 dawes Exp $ */
27
28#include "xsm.h"
29#include "save.h"
30#include "saveutil.h"
31#include "popup.h"
32#include "info.h"
33#include "lock.h"
34#include "choose.h"
35
36#include <X11/Shell.h>
37#include <X11/Xaw/Form.h>
38#include <X11/Xaw/List.h>
39#include <X11/Xaw/Command.h>
40#include <X11/Xaw/Toggle.h>
41#include <X11/Xaw/AsciiText.h>
42
43
44static Widget savePopup;
45static Widget   saveForm;
46static Widget	   saveMessageLabel;
47static Widget	   saveName;
48static Widget	   saveTypeLabel;
49static Widget	   saveTypeGlobal;
50static Widget	   saveTypeLocal;
51static Widget	   saveTypeBoth;
52static Widget	   interactStyleLabel;
53static Widget	   interactStyleNone;
54static Widget	   interactStyleErrors;
55static Widget	   interactStyleAny;
56static Widget	   saveOkButton;
57static Widget     helpSaveButton;
58static Widget	   saveCancelButton;
59static Widget helpPopup;
60static Widget   helpForm;
61static Widget     helpSaveText;
62static Widget     helpSaveOkButton;
63static Widget nameInUsePopup;
64static Widget   nameInUseForm;
65static Widget	   nameInUseLabel;
66static Widget     nameInUseOverwriteButton;
67static Widget	   nameInUseCancelButton;
68static Widget badSavePopup;
69static Widget   badSaveForm;
70static Widget	   badSaveLabel;
71static Widget     badSaveOkButton;
72static Widget	   badSaveCancelButton;
73static Widget     badSaveListWidget;
74
75static int saveTypeData[] = {
76	SmSaveLocal,
77	SmSaveGlobal,
78	SmSaveBoth
79};
80
81static int interactStyleData[] = {
82	SmInteractStyleNone,
83	SmInteractStyleErrors,
84	SmInteractStyleAny
85};
86
87static String *failedNames = NULL;
88static int numFailedNames = 0;
89
90static Bool help_visible = False;
91
92static String name_in_use = NULL;
93static Bool name_locked = False;
94
95
96
97static void
98MakeCurrentSession(String new_name, Bool name_changed)
99{
100    char title[256];
101    List *cl;
102
103    if (session_name)
104    {
105	/*
106	 * In the old session, for any client that was not restarted by the
107	 * session manager (previous ID was NULL), if we did not issue a
108	 * checkpoint to this client after the initial startup, remove the
109	 * client's checkpoint file using the discard command.
110	 */
111
112	for (cl = ListFirst (RunningList); cl; cl = ListNext (cl))
113	{
114	    ClientRec *client = (ClientRec *) cl->thing;
115
116	    if (!client->restarted &&
117		!client->userIssuedCheckpoint &&
118		client->discardCommand)
119	    {
120		execute_system_command (client->discardCommand);
121		XtFree (client->discardCommand);
122		client->discardCommand = NULL;
123	    }
124	}
125
126	/*
127	 * Unlock the old session.
128	 */
129
130	if (!need_to_name_session)
131	    UnlockSession (session_name);
132    }
133
134    if (name_changed)
135    {
136	if (session_name)
137	    XtFree (session_name);
138
139	session_name = XtNewString (new_name);
140    }
141
142    LockSession (session_name, True);
143
144    snprintf (title, sizeof(title), "xsm: %s", session_name);
145
146    XtVaSetValues (topLevel,
147	XtNtitle, title,
148	NULL);
149
150    set_session_save_file_name (session_name);
151
152
153    /*
154     * For each client, set the DiscardCommand ptr to NULL.
155     * This is so when we do a checkpoint with the new session
156     * name, we don't wipe out the checkpoint files needed by
157     * the previous session.  We also set the userIssuedCheckpoint
158     * flag to false for each client in the new session.
159     */
160
161    for (cl = ListFirst (RunningList); cl; cl = ListNext (cl))
162    {
163	ClientRec *client = (ClientRec *) cl->thing;
164
165	client->userIssuedCheckpoint = False;
166
167	if (client->discardCommand)
168	{
169	    XtFree (client->discardCommand);
170	    client->discardCommand = NULL;
171	}
172    }
173
174    need_to_name_session = False;
175}
176
177
178
179
180#define NAME_OK     0
181#define NAME_EMPTY  1
182#define NAME_EXISTS 2
183#define NAME_LOCKED 3
184
185static int
186GetSaveName(String *nameRet)
187{
188    String new_name = NULL;
189    Bool name_changed;
190
191    /*
192     * Get the name of the session for the save
193     */
194
195    XtVaGetValues (saveName,
196	XtNstring, &new_name,
197	NULL);
198
199    *nameRet = new_name;
200
201    if (!new_name || *new_name == '\0')
202	return (NAME_EMPTY);
203
204    /*
205     * See if this is a new session.  If not return.
206     */
207
208    name_changed = !session_name ||
209	(session_name && strcmp (session_name, new_name) != 0);
210
211    if (!need_to_name_session && !name_changed)
212	return (NAME_OK);
213
214
215    /*
216     * Make sure the session name is unique.
217     */
218
219    if (GetSessionNames (&sessionNameCount,
220	&sessionNamesShort, NULL, &sessionsLocked))
221    {
222	int i, no_good = 0, locked = 0;
223
224	for (i = 0; i < sessionNameCount; i++)
225	    if (strcmp (new_name, sessionNamesShort[i]) == 0)
226	    {
227		no_good = 1;
228		locked = sessionsLocked[i];
229		break;
230	    }
231
232	FreeSessionNames (sessionNameCount,
233	    sessionNamesShort, NULL, sessionsLocked);
234
235	if (no_good)
236	    return (locked ? NAME_LOCKED : NAME_EXISTS);
237    }
238
239    MakeCurrentSession (new_name, name_changed);
240
241    return (NAME_OK);
242}
243
244
245static void
246GetSaveOptions(int *saveType, int *interactStyle, Bool *fast)
247{
248    XtPointer	ptr;
249
250    if (help_visible)
251    {
252	XtPopdown (helpPopup);
253	help_visible = 0;
254    }
255
256    ptr = XawToggleGetCurrent (saveTypeLocal /* just 1 of the group */);
257    *saveType = *((int *) ptr);
258
259    ptr = XawToggleGetCurrent (interactStyleNone /* just 1 of the group */);
260    *interactStyle = *((int *) ptr);
261
262    *fast = False;
263}
264
265
266
267void
268DoSave(int saveType, int interactStyle, Bool fast)
269{
270    ClientRec	*client;
271    List	*cl;
272    const char	*_saveType;
273    const char	*_shutdown;
274    const char	*_interactStyle;
275
276    if (saveType == SmSaveLocal)
277	_saveType = "Local";
278    else if (saveType == SmSaveGlobal)
279	_saveType = "Global";
280    else
281	_saveType = "Both";
282
283    if (wantShutdown)
284	_shutdown = "True";
285    else
286	_shutdown = "False";
287
288    if (interactStyle == SmInteractStyleNone)
289	_interactStyle = "None";
290    else if (interactStyle == SmInteractStyleErrors)
291	_interactStyle = "Errors";
292    else
293	_interactStyle = "Any";
294
295    SetSaveSensitivity (False);
296
297    saveInProgress = True;
298
299    shutdownCancelled = False;
300    phase2InProgress = False;
301
302    if (ListCount (RunningList) == 0)
303	FinishUpSave ();
304
305    for (cl = ListFirst (RunningList); cl; cl = ListNext (cl))
306    {
307	client = (ClientRec *) cl->thing;
308
309	SmsSaveYourself (client->smsConn,
310	    saveType, wantShutdown, interactStyle, fast);
311
312	ListAddLast (WaitForSaveDoneList, (char *) client);
313
314	client->userIssuedCheckpoint = True;
315	client->receivedDiscardCommand = False;
316
317	if (verbose)
318	{
319	    printf ("Client Id = %s, sent SAVE YOURSELF [", client->clientId);
320	    printf ("Save Type = %s, Shutdown = %s, ", _saveType, _shutdown);
321	    printf ("Interact Style = %s, Fast = False]\n", _interactStyle);
322	}
323    }
324
325    if (verbose)
326    {
327	printf ("\n");
328	printf ("Sent SAVE YOURSELF to all clients.  Waiting for\n");
329	printf ("SAVE YOURSELF DONE, INTERACT REQUEST, or\n");
330	printf ("SAVE YOURSELF PHASE 2 REQUEST from each client.\n");
331	printf ("\n");
332    }
333}
334
335
336
337static void
338SaveOkAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
339{
340    XtCallCallbacks (saveOkButton, XtNcallback, NULL);
341}
342
343
344
345static void
346DelSaveWinAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
347{
348    XtCallCallbacks (saveCancelButton, XtNcallback, NULL);
349}
350
351
352
353static void
354DelNameInUseWinAction(Widget w, XEvent *event, String *params,
355		      Cardinal *num_params)
356{
357    XtCallCallbacks (nameInUseCancelButton, XtNcallback, NULL);
358}
359
360
361
362static void
363DelBadSaveWinAction(Widget w, XEvent *event, String *params,
364		    Cardinal *num_params)
365{
366    if (XtIsManaged (badSaveCancelButton))
367	XtCallCallbacks (badSaveCancelButton, XtNcallback, NULL);
368    else
369	XtCallCallbacks (badSaveOkButton, XtNcallback, NULL);
370}
371
372
373
374static void
375DelSaveHelpWinAction(Widget w, XEvent *event, String *params,
376		     Cardinal *num_params)
377{
378    XtCallCallbacks (helpSaveOkButton, XtNcallback, NULL);
379}
380
381
382
383static void
384SaveOkXtProc(Widget w, XtPointer client_data, XtPointer callData)
385{
386    String name = NULL;
387    char label[256];
388    int	status;
389    static int first_time = 1;
390    int saveType;
391    int interactStyle;
392    Bool fast;
393
394    if ((status = GetSaveName (&name)) != NAME_OK)
395    {
396#ifdef XKB
397	XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_BadValue);
398#else
399	XBell (XtDisplay (topLevel), 0);
400#endif
401
402	if (status == NAME_EXISTS || status == NAME_LOCKED)
403	{
404	    name_in_use = name;
405
406	    if (status == NAME_LOCKED)
407	    {
408		name_locked = True;
409
410		snprintf (label, sizeof(label), "Another session by the name '%s' is active.\nChoose another name for the session.", name);
411
412		XtUnmanageChild (nameInUseOverwriteButton);
413
414		XtVaSetValues (nameInUseCancelButton,
415		    XtNlabel, "OK",
416		    XtNfromHoriz, NULL,
417		    NULL);
418	    }
419	    else
420	    {
421		name_locked = False;
422
423		snprintf (label, sizeof(label), "Another session by the name '%s' already exists.\nWould you like to overwrite it?", name);
424
425		XtManageChild (nameInUseOverwriteButton);
426
427		XtVaSetValues (nameInUseCancelButton,
428		    XtNlabel, "Cancel",
429		    XtNfromHoriz, nameInUseOverwriteButton,
430		    NULL);
431	    }
432
433	    XtVaSetValues (nameInUseLabel,
434		XtNlabel, label,
435		NULL);
436
437	    XtPopdown (savePopup);
438
439	    PopupPopup (mainWindow, nameInUsePopup,
440		True, first_time, 25, 100, "DelNameInUseWinAction()");
441
442	    if (first_time)
443		first_time = 0;
444	}
445
446	return;
447    }
448
449    GetSaveOptions (&saveType, &interactStyle, &fast);
450    DoSave (saveType, interactStyle, fast);
451}
452
453
454
455void
456LetClientInteract(List *cl)
457{
458    ClientRec *client = (ClientRec *) cl->thing;
459
460    SmsInteract (client->smsConn);
461
462    ListSearchAndFreeOne (WaitForInteractList, (char *) client);
463
464    if (verbose)
465    {
466	printf ("Client Id = %s, sent INTERACT\n", client->clientId);
467    }
468}
469
470
471
472void
473StartPhase2(void)
474{
475    List *cl;
476
477    if (verbose)
478    {
479	printf ("\n");
480	printf ("Starting PHASE 2 of SAVE YOURSELF\n");
481	printf ("\n");
482    }
483
484    for (cl = ListFirst (WaitForPhase2List); cl; cl = ListNext (cl))
485    {
486	ClientRec *client = (ClientRec *) cl->thing;
487
488	SmsSaveYourselfPhase2 (client->smsConn);
489
490	if (verbose)
491	{
492	    printf ("Client Id = %s, sent SAVE YOURSELF PHASE 2",
493		client->clientId);
494	}
495    }
496
497    ListFreeAllButHead (WaitForPhase2List);
498
499    phase2InProgress = True;
500}
501
502
503void
504FinishUpSave(void)
505{
506    ClientRec	*client;
507    List	*cl;
508
509    if (verbose)
510    {
511	printf ("\n");
512	printf ("All clients issued SAVE YOURSELF DONE\n");
513	printf ("\n");
514    }
515
516    saveInProgress = False;
517    phase2InProgress = False;
518
519    /*
520     * Now execute discard commands
521     */
522
523    for (cl = ListFirst (RunningList); cl; cl = ListNext (cl))
524    {
525	client = (ClientRec *) cl->thing;
526
527	if (!client->receivedDiscardCommand)
528	    continue;
529
530	if (client->discardCommand)
531	{
532	    execute_system_command (client->discardCommand);
533	    XtFree (client->discardCommand);
534	    client->discardCommand = NULL;
535	}
536
537	if (client->saveDiscardCommand)
538	{
539	    client->discardCommand = client->saveDiscardCommand;
540	    client->saveDiscardCommand = NULL;
541	}
542    }
543
544
545    /*
546     * Write the save file
547     */
548
549    WriteSave (sm_id);
550
551
552    if (wantShutdown && shutdownCancelled)
553    {
554	shutdownCancelled = False;
555    }
556    else if (wantShutdown)
557    {
558	if (ListCount (RunningList) == 0)
559	    EndSession (0);
560
561	shutdownInProgress = True;
562
563	for (cl = ListFirst (RunningList); cl; cl = ListNext (cl))
564	{
565	    client = (ClientRec *) cl->thing;
566
567	    SmsDie (client->smsConn);
568
569	    if (verbose)
570	    {
571		printf ("Client Id = %s, sent DIE\n", client->clientId);
572	    }
573	}
574    }
575    else
576    {
577	for (cl = ListFirst (RunningList); cl; cl = ListNext (cl))
578	{
579	    client = (ClientRec *) cl->thing;
580
581	    SmsSaveComplete (client->smsConn);
582
583	    if (verbose)
584	    {
585		printf ("Client Id = %s, sent SAVE COMPLETE\n",
586		    client->clientId);
587	    }
588	}
589    }
590
591    if (!shutdownInProgress)
592    {
593	XtPopdown (savePopup);
594	SetAllSensitive (1);
595	if (checkpoint_from_signal)
596	    checkpoint_from_signal = False;
597    }
598}
599
600
601
602static void
603SaveCancelXtProc(Widget w, XtPointer client_data, XtPointer callData)
604{
605    XtPopdown (savePopup);
606
607    if (help_visible)
608    {
609	XtPopdown (helpPopup);
610	help_visible = 0;
611    }
612
613    SetAllSensitive (1);
614}
615
616
617
618/*
619 * Add toggle button
620 */
621
622static Widget
623AddToggle(String widgetName, Widget parent, int state, Widget radioGroup,
624	  XtPointer radioData,  Widget fromHoriz, Widget fromVert)
625{
626    Widget toggle;
627
628    toggle = XtVaCreateManagedWidget (
629	widgetName, toggleWidgetClass, parent,
630        XtNstate, state,
631        XtNradioGroup, radioGroup,
632        XtNradioData, radioData,
633        XtNfromHoriz, fromHoriz,
634        XtNfromVert, fromVert,
635        NULL);
636
637    return (toggle);
638}
639
640
641
642void
643SetSaveSensitivity(Bool on)
644{
645    XtSetSensitive (savePopup, on);
646
647#if 0
648    /*
649     * When we turn of sensitivity in the save dialog, we want to keep
650     * the cancel button sensitive (so the user can cancel in case of
651     * a problem).  Unfortunately, we can not turn off the sensitivity on
652     * the save popup, and then just turn on sensitivity for the cancel
653     * button.  We must do each widget individually.
654     */
655
656    XtSetSensitive (saveTypeLabel, on);
657    XtSetSensitive (saveTypeGlobal, on);
658    XtSetSensitive (saveTypeLocal, on);
659    XtSetSensitive (saveTypeBoth, on);
660    XtSetSensitive (interactStyleLabel, on);
661    XtSetSensitive (interactStyleNone, on);
662    XtSetSensitive (interactStyleErrors, on);
663    XtSetSensitive (interactStyleAny, on);
664    XtSetSensitive (saveOkButton, on);
665#endif
666}
667
668
669
670void
671SavePopupStructureNotifyXtHandler(Widget w, XtPointer closure, XEvent *event,
672				  Boolean *continue_to_dispatch)
673{
674    if (event->type == MapNotify)
675    {
676	/*
677	 * Now that the Save Dialog is back up, we can do the save.
678	 */
679
680	int saveType;
681	int interactStyle;
682	Bool fast;
683
684	if (name_locked)
685	{
686	    /* Force shutdown */
687	}
688
689	DeleteSession (name_in_use);
690
691	MakeCurrentSession (name_in_use, True);
692
693	name_in_use = NULL;
694
695	GetSaveOptions (&saveType, &interactStyle, &fast);
696	DoSave (saveType, interactStyle, fast);
697
698	XtRemoveEventHandler (savePopup, StructureNotifyMask, False,
699	    SavePopupStructureNotifyXtHandler, NULL);
700    }
701}
702
703
704
705static void
706NameInUseOverwriteXtProc(Widget w, XtPointer client_data, XtPointer callData)
707{
708    if (name_locked)
709    {
710	/* force shutdown not implemented yet */
711
712	return;
713    }
714
715    XtPopdown (nameInUsePopup);
716
717    /*
718     * We want to popup the Save dialog again.  In order to avoid a race
719     * condition with the BadSave handler trying to pop down the Save Dialog,
720     * we wait for the MapNotify on the Save dialog, and then do the save.
721     */
722
723    XtAddEventHandler (savePopup, StructureNotifyMask, False,
724	SavePopupStructureNotifyXtHandler, NULL);
725
726    XtPopup (savePopup, XtGrabNone);
727}
728
729
730
731static void
732NameInUseCancelXtProc(Widget w, XtPointer client_data, XtPointer callData)
733{
734    XtPopdown (nameInUsePopup);
735    XtPopup (savePopup, XtGrabNone);
736
737    name_in_use = NULL;
738}
739
740
741
742static void
743BadSaveOkXtProc(Widget w, XtPointer client_data, XtPointer callData)
744{
745    ListFreeAllButHead (FailedSaveList);
746    XtPopdown (badSavePopup);
747    FinishUpSave ();
748}
749
750
751
752static void
753BadSaveCancelXtProc(Widget w, XtPointer client_data, XtPointer callData)
754{
755    ListFreeAllButHead (FailedSaveList);
756    XtPopdown (badSavePopup);
757
758    if (wantShutdown)
759    {
760	List *cl;
761
762	shutdownCancelled = True;
763
764	for (cl = ListFirst (RunningList); cl; cl = ListNext (cl))
765	{
766	    ClientRec *client = (ClientRec *) cl->thing;
767
768	    SmsShutdownCancelled (client->smsConn);
769
770	    if (verbose)
771	    {
772		printf ("Client Id = %s, sent SHUTDOWN CANCELLED\n",
773			client->clientId);
774	    }
775	}
776    }
777
778    FinishUpSave ();
779}
780
781
782
783static void
784BadSaveListXtProc(Widget w, XtPointer client_data, XtPointer callData)
785{
786
787}
788
789
790
791static void
792HelpSaveXtProc(Widget w, XtPointer client_data, XtPointer callData)
793{
794    static int first_time = 1;
795
796    if (help_visible)
797    {
798	/* Make sure it is visible */
799
800	XMapRaised (XtDisplay (topLevel), XtWindow (helpPopup));
801    }
802    else
803    {
804	PopupPopup (savePopup, helpPopup,
805	    True, first_time, 50, 50, "DelSaveHelpWinAction()");
806
807	help_visible = 1;
808
809	if (first_time)
810	    first_time = 0;
811    }
812}
813
814
815
816static void
817HelpSaveOkXtProc(Widget w, XtPointer client_data, XtPointer callData)
818{
819    XtPopdown (helpPopup);
820    help_visible = 0;
821}
822
823
824
825void
826create_save_popup(void)
827
828{
829    XtTranslations translations;
830
831    static XtActionsRec actions[] = {
832        {"SaveOkAction", SaveOkAction},
833        {"DelSaveWinAction", DelSaveWinAction},
834	{"DelNameInUseWinAction", DelNameInUseWinAction},
835	{"DelBadSaveWinAction", DelBadSaveWinAction},
836	{"DelSaveHelpWinAction", DelSaveHelpWinAction}
837    };
838
839
840    /*
841     * Pop up for Save Yourself button.
842     */
843
844    savePopup = XtVaCreatePopupShell (
845	"savePopup", transientShellWidgetClass, topLevel,
846	XtNallowShellResize, True,
847	NULL);
848
849    saveForm = XtCreateManagedWidget (
850	"saveForm", formWidgetClass, savePopup, NULL, 0);
851
852    saveMessageLabel = XtVaCreateManagedWidget (
853	"saveMessageLabel", labelWidgetClass, saveForm,
854        XtNfromHoriz, NULL,
855        XtNfromVert, NULL,
856        XtNborderWidth, 0,
857	NULL);
858
859    saveName = XtVaCreateManagedWidget (
860	"saveName", asciiTextWidgetClass, saveForm,
861        XtNfromVert, NULL,
862	XtNeditType, XawtextEdit,
863	XtNresizable, True,
864	XtNresize, XawtextResizeWidth,
865	NULL);
866
867    saveTypeLabel = XtVaCreateManagedWidget (
868	"saveTypeLabel", labelWidgetClass, saveForm,
869        XtNfromHoriz, NULL,
870        XtNfromVert, saveMessageLabel,
871        XtNborderWidth, 0,
872        XtNvertDistance, 20,
873	NULL);
874
875    saveTypeLocal = AddToggle (
876	"saveTypeLocal", 			/* widgetName */
877	saveForm,				/* parent */
878	0,					/* state */
879        NULL,					/* radioGroup */
880        (XtPointer) &saveTypeData[0],		/* radioData */
881        saveTypeLabel,				/* fromHoriz */
882        saveMessageLabel			/* fromVert */
883    );
884
885    saveTypeGlobal = AddToggle (
886	"saveTypeGlobal", 			/* widgetName */
887	saveForm,				/* parent */
888	0,					/* state */
889        saveTypeLocal,				/* radioGroup */
890        (XtPointer) &saveTypeData[1],		/* radioData */
891        saveTypeLocal,				/* fromHoriz */
892        saveMessageLabel			/* fromVert */
893    );
894
895    saveTypeBoth = AddToggle (
896	"saveTypeBoth", 			/* widgetName */
897	saveForm,				/* parent */
898	1,					/* state */
899        saveTypeLocal,				/* radioGroup */
900        (XtPointer) &saveTypeData[2],		/* radioData */
901        saveTypeGlobal,				/* fromHoriz */
902        saveMessageLabel			/* fromVert */
903    );
904
905
906    XtVaSetValues (saveName, XtNfromHoriz, saveTypeLabel, NULL);
907    XtVaSetValues (saveTypeLocal, XtNvertDistance, 20, NULL);
908    XtVaSetValues (saveTypeGlobal, XtNvertDistance, 20, NULL);
909    XtVaSetValues (saveTypeBoth, XtNvertDistance, 20, NULL);
910
911    interactStyleLabel = XtVaCreateManagedWidget (
912	"interactStyleLabel", labelWidgetClass, saveForm,
913        XtNfromHoriz, NULL,
914        XtNfromVert, saveTypeLabel,
915        XtNborderWidth, 0,
916	NULL);
917
918    interactStyleNone = AddToggle (
919	"interactStyleNone", 			/* widgetName */
920	saveForm,				/* parent */
921	0,					/* state */
922        NULL,					/* radioGroup */
923        (XtPointer) &interactStyleData[0],	/* radioData */
924        saveTypeLabel,				/* fromHoriz */
925        saveTypeLabel				/* fromVert */
926    );
927
928    interactStyleErrors = AddToggle (
929	"interactStyleErrors", 			/* widgetName */
930	saveForm,				/* parent */
931	0,					/* state */
932        interactStyleNone,			/* radioGroup */
933        (XtPointer) &interactStyleData[1],	/* radioData */
934        interactStyleNone,			/* fromHoriz */
935        saveTypeLabel				/* fromVert */
936    );
937
938    interactStyleAny = AddToggle (
939	"interactStyleAny", 			/* widgetName */
940	saveForm,				/* parent */
941	1,					/* state */
942        interactStyleNone,			/* radioGroup */
943        (XtPointer) &interactStyleData[2],	/* radioData */
944        interactStyleErrors,			/* fromHoriz */
945        saveTypeLabel				/* fromVert */
946    );
947
948
949    saveOkButton = XtVaCreateManagedWidget (
950	"saveOkButton",	commandWidgetClass, saveForm,
951        XtNfromHoriz, NULL,
952        XtNfromVert, interactStyleLabel,
953        XtNvertDistance, 20,
954	XtNresizable, True,
955        NULL);
956
957    XtAddCallback (saveOkButton, XtNcallback, SaveOkXtProc, NULL);
958
959
960    helpSaveButton = XtVaCreateManagedWidget (
961	"helpSaveButton", commandWidgetClass, saveForm,
962        XtNfromHoriz, saveOkButton,
963        XtNfromVert, interactStyleLabel,
964        XtNvertDistance, 20,
965	NULL);
966
967    XtAddCallback (helpSaveButton, XtNcallback, HelpSaveXtProc, NULL);
968
969
970    saveCancelButton = XtVaCreateManagedWidget (
971	"saveCancelButton", commandWidgetClass, saveForm,
972        XtNfromHoriz, helpSaveButton,
973        XtNfromVert, interactStyleLabel,
974        XtNvertDistance, 20,
975        NULL);
976
977    XtAddCallback (saveCancelButton, XtNcallback, SaveCancelXtProc, NULL);
978
979    XtSetKeyboardFocus (saveForm, saveName);
980
981    XtAppAddActions (appContext, actions, XtNumber (actions));
982
983    translations = XtParseTranslationTable
984	("<Key>Return: SaveOkAction()\n");
985    XtOverrideTranslations(saveName, translations);
986
987    XtInstallAllAccelerators (saveForm, saveForm);
988
989
990    /*
991     * Pop up when user tries to save the session under an
992     * already used name.
993     */
994
995    nameInUsePopup = XtVaCreatePopupShell (
996	"nameInUsePopup", transientShellWidgetClass, topLevel,
997	XtNallowShellResize, True,
998	NULL);
999
1000
1001    nameInUseForm = XtVaCreateManagedWidget (
1002	"nameInUseForm", formWidgetClass, nameInUsePopup,
1003	NULL);
1004
1005    nameInUseLabel = XtVaCreateManagedWidget (
1006	"nameInUseLabel", labelWidgetClass, nameInUseForm,
1007	XtNresizable, True,
1008        XtNfromHoriz, NULL,
1009        XtNfromVert, NULL,
1010        XtNborderWidth, 0,
1011	XtNtop, XawChainTop,
1012	XtNbottom, XawChainTop,
1013	NULL);
1014
1015    nameInUseOverwriteButton = XtVaCreateManagedWidget (
1016	"nameInUseOverwriteButton", commandWidgetClass, nameInUseForm,
1017        XtNfromHoriz, NULL,
1018        XtNfromVert, nameInUseLabel,
1019	XtNtop, XawChainBottom,
1020	XtNbottom, XawChainBottom,
1021        NULL);
1022
1023    XtAddCallback (nameInUseOverwriteButton, XtNcallback,
1024	NameInUseOverwriteXtProc, NULL);
1025
1026
1027    nameInUseCancelButton = XtVaCreateManagedWidget (
1028	"nameInUseCancelButton", commandWidgetClass, nameInUseForm,
1029	XtNresizable, True,
1030        XtNfromHoriz, nameInUseOverwriteButton,
1031        XtNfromVert, nameInUseLabel,
1032	XtNtop, XawChainBottom,
1033	XtNbottom, XawChainBottom,
1034        NULL);
1035
1036    XtAddCallback (nameInUseCancelButton, XtNcallback,
1037	NameInUseCancelXtProc, NULL);
1038
1039
1040    /*
1041     * Pop up for help.
1042     */
1043
1044    helpPopup = XtVaCreatePopupShell (
1045	"helpPopup", transientShellWidgetClass, topLevel,
1046	NULL);
1047
1048
1049    helpForm = XtVaCreateManagedWidget (
1050	"helpForm", formWidgetClass, helpPopup,
1051	NULL);
1052
1053    helpSaveText = XtVaCreateManagedWidget (
1054	"helpSaveText", labelWidgetClass, helpForm,
1055        XtNfromHoriz, NULL,
1056        XtNfromVert, NULL,
1057	XtNtop, XawChainTop,
1058	XtNbottom, XawChainTop,
1059	NULL);
1060
1061    helpSaveOkButton = XtVaCreateManagedWidget (
1062	"helpSaveOkButton", commandWidgetClass, helpForm,
1063        XtNfromHoriz, NULL,
1064        XtNfromVert, helpSaveText,
1065	XtNtop, XawChainBottom,
1066	XtNbottom, XawChainBottom,
1067        XtNvertDistance, 20,
1068        NULL);
1069
1070    XtAddCallback (helpSaveOkButton, XtNcallback,
1071	HelpSaveOkXtProc, NULL);
1072
1073
1074    /*
1075     * Pop up when not all clients returned SaveSuccess
1076     */
1077
1078    badSavePopup = XtVaCreatePopupShell (
1079	"badSavePopup", transientShellWidgetClass, topLevel,
1080	XtNallowShellResize, True,
1081	NULL);
1082
1083
1084    badSaveForm = XtVaCreateManagedWidget (
1085	"badSaveForm", formWidgetClass, badSavePopup,
1086	NULL);
1087
1088    badSaveLabel = XtVaCreateManagedWidget (
1089	"badSaveLabel", labelWidgetClass, badSaveForm,
1090        XtNfromHoriz, NULL,
1091        XtNfromVert, NULL,
1092        XtNborderWidth, 0,
1093	XtNtop, XawChainTop,
1094	XtNbottom, XawChainTop,
1095	NULL);
1096
1097    badSaveListWidget = XtVaCreateManagedWidget (
1098	"badSaveListWidget", listWidgetClass, badSaveForm,
1099	XtNresizable, True,
1100        XtNdefaultColumns, 1,
1101	XtNforceColumns, True,
1102        XtNfromHoriz, NULL,
1103        XtNfromVert, badSaveLabel,
1104	XtNtop, XawChainTop,
1105	XtNbottom, XawChainBottom,
1106	NULL);
1107
1108    XtAddCallback (badSaveListWidget, XtNcallback, BadSaveListXtProc, NULL);
1109
1110    badSaveOkButton = XtVaCreateManagedWidget (
1111	"badSaveOkButton", commandWidgetClass, badSaveForm,
1112        XtNfromHoriz, NULL,
1113        XtNfromVert, badSaveListWidget,
1114	XtNtop, XawChainBottom,
1115	XtNbottom, XawChainBottom,
1116        NULL);
1117
1118    XtAddCallback (badSaveOkButton, XtNcallback, BadSaveOkXtProc, NULL);
1119
1120
1121    badSaveCancelButton = XtVaCreateManagedWidget (
1122	"badSaveCancelButton", commandWidgetClass, badSaveForm,
1123        XtNfromHoriz, badSaveOkButton,
1124        XtNfromVert, badSaveListWidget,
1125	XtNtop, XawChainBottom,
1126	XtNbottom, XawChainBottom,
1127        NULL);
1128
1129    XtAddCallback (badSaveCancelButton, XtNcallback, BadSaveCancelXtProc, NULL);
1130
1131    XtInstallAllAccelerators (badSaveForm, badSaveForm);
1132}
1133
1134
1135
1136void
1137PopupSaveDialog(void)
1138
1139{
1140    static int first_time = 1;
1141
1142    XtSetSensitive (mainWindow, 0);
1143    XtSetSensitive (clientInfoPopup, 0);
1144    XtSetSensitive (clientPropPopup, 0);
1145
1146    XawToggleSetCurrent (saveTypeBoth,
1147	(XtPointer) &saveTypeData[2]);
1148    XawToggleSetCurrent (interactStyleAny,
1149	(XtPointer) &interactStyleData[2]);
1150
1151    XtVaSetValues (savePopup,
1152	XtNtitle, wantShutdown ? "Shutdown" : "Checkpoint",
1153	NULL);
1154
1155    XtVaSetValues (saveName,
1156	XtNstring, need_to_name_session ? "" : session_name,
1157	NULL);
1158
1159    XtVaSetValues (saveOkButton,
1160	XtNlabel, wantShutdown ? "Shutdown" : "Checkpoint",
1161	NULL);
1162
1163    PopupPopup (mainWindow, savePopup,
1164	True, first_time, 25, 100, "DelSaveWinAction()");
1165
1166    if (first_time)
1167	first_time = 0;
1168}
1169
1170
1171
1172
1173void
1174CheckPointXtProc(Widget w, XtPointer client_data, XtPointer callData)
1175{
1176    wantShutdown = False;
1177    PopupSaveDialog ();
1178}
1179
1180
1181
1182
1183void
1184ShutdownSaveXtProc(Widget w, XtPointer client_data, XtPointer callData)
1185{
1186    wantShutdown = True;
1187    PopupSaveDialog ();
1188}
1189
1190
1191
1192void
1193PopupBadSave(void)
1194
1195{
1196    ClientRec *client;
1197    char *progName, *hostname, *tmp1, *tmp2;
1198    char *clientInfo;
1199    int maxlen1, maxlen2;
1200    char extraBuf1[80], extraBuf2[80];
1201    char *restart_service_prop;
1202    List *cl, *pl;
1203    int i, k;
1204    static int first_time = 1;
1205
1206    if (failedNames)
1207    {
1208	/*
1209	 * Free the previous list of names.  Xaw doesn't make a copy of
1210	 * our list, so we need to keep it around.
1211	 */
1212
1213	for (i = 0; i < numFailedNames; i++)
1214	    XtFree ((char *) failedNames[i]);
1215
1216	XtFree ((char *) failedNames);
1217
1218	failedNames = NULL;
1219    }
1220
1221    maxlen1 = maxlen2 = 0;
1222    numFailedNames = 0;
1223
1224    for (cl = ListFirst (FailedSaveList); cl; cl = ListNext (cl))
1225    {
1226	client = (ClientRec *) cl->thing;
1227
1228	progName = NULL;
1229	restart_service_prop = NULL;
1230
1231	for (pl = ListFirst (client->props); pl; pl = ListNext (pl))
1232	{
1233	    Prop *pprop = (Prop *) pl->thing;
1234	    List *vl = ListFirst (pprop->values);
1235	    PropValue *pval = (PropValue *) vl->thing;
1236
1237	    if (strcmp (pprop->name, SmProgram) == 0)
1238	    {
1239		progName = GetProgramName ((char *) pval->value);
1240
1241		if ((int) strlen (progName) > maxlen1)
1242		    maxlen1 = strlen (progName);
1243	    }
1244	    else if (strcmp (pprop->name, "_XC_RestartService") == 0)
1245	    {
1246		restart_service_prop = (char *) pval->value;
1247	    }
1248	}
1249
1250	if (!progName)
1251	    continue;
1252
1253	if (restart_service_prop)
1254	    tmp1 = restart_service_prop;
1255	else if (client->clientHostname)
1256	    tmp1 = client->clientHostname;
1257	else
1258	    continue;
1259
1260	if ((tmp2 = (char *) strchr (tmp1, '/')) == NULL)
1261	    hostname = tmp1;
1262	else
1263	    hostname = tmp2 + 1;
1264
1265	if ((int) strlen (hostname) > maxlen2)
1266	    maxlen2 = strlen (hostname);
1267
1268	numFailedNames++;
1269    }
1270
1271    failedNames = (String *) XtMalloc (
1272	numFailedNames * sizeof (String));
1273
1274    i = 0;
1275    for (cl = ListFirst (FailedSaveList); cl; cl = ListNext (cl))
1276    {
1277	ClientRec *client = (ClientRec *) cl->thing;
1278	int extra1, extra2;
1279
1280	progName = NULL;
1281	restart_service_prop = NULL;
1282
1283	for (pl = ListFirst (client->props); pl; pl = ListNext (pl))
1284	{
1285	    Prop *pprop = (Prop *) pl->thing;
1286	    List *vl = ListFirst (pprop->values);
1287	    PropValue *pval = (PropValue *) vl->thing;
1288
1289	    if (strcmp (pprop->name, SmProgram) == 0)
1290	    {
1291		progName = GetProgramName ((char *) pval->value);
1292	    }
1293	    else if (strcmp (pprop->name, "_XC_RestartService") == 0)
1294	    {
1295		restart_service_prop = (char *) pval->value;
1296	    }
1297	}
1298
1299	if (!progName)
1300	    continue;
1301
1302	if (restart_service_prop)
1303	    tmp1 = restart_service_prop;
1304	else if (client->clientHostname)
1305	    tmp1 = client->clientHostname;
1306	else
1307	    continue;
1308
1309	if ((tmp2 = (char *) strchr (tmp1, '/')) == NULL)
1310	    hostname = tmp1;
1311	else
1312	    hostname = tmp2 + 1;
1313
1314	extra1 = maxlen1 - strlen (progName) + 5;
1315	extra2 = maxlen2 - strlen (hostname);
1316
1317	for (k = 0; k < extra1; k++)
1318	    extraBuf1[k] = ' ';
1319	extraBuf1[extra1] = '\0';
1320
1321	for (k = 0; k < extra2; k++)
1322	    extraBuf2[k] = ' ';
1323	extraBuf2[extra2] = '\0';
1324
1325	XtAsprintf (&clientInfo, "%s%s (%s%s)", progName, extraBuf1,
1326	    hostname, extraBuf2);
1327
1328	failedNames[i++] = clientInfo;
1329
1330	if (client->freeAfterBadSavePopup)
1331	{
1332	    FreeClient (client, True /* free props */);
1333	}
1334    }
1335
1336    XawListChange (badSaveListWidget,
1337	failedNames, numFailedNames, 0, True);
1338
1339    XtPopdown (savePopup);
1340
1341    if (wantShutdown && !shutdownCancelled)
1342	XtManageChild (badSaveCancelButton);
1343    else
1344	XtUnmanageChild (badSaveCancelButton);
1345
1346    PopupPopup (mainWindow, badSavePopup,
1347	True, first_time, 25, 100, "DelBadSaveWinAction()");
1348
1349    if (first_time)
1350	first_time = 0;
1351}
1352
1353
1354
1355void
1356ShutdownDontSaveXtProc(Widget w, XtPointer client_data, XtPointer callData)
1357{
1358    List	*cl;
1359    ClientRec 	*client;
1360
1361    if (ListCount (RunningList) == 0)
1362	EndSession (0);
1363
1364    /*
1365     * For any client that was not restarted by the session
1366     * manager (previous ID was NULL), if we did not issue a
1367     * checkpoint to this client, remove the client's checkpoint
1368     * file using the discard command.
1369     */
1370
1371    for (cl = ListFirst (RunningList); cl; cl = ListNext (cl))
1372    {
1373	client = (ClientRec *) cl->thing;
1374
1375	if (!client->restarted &&
1376	    !client->userIssuedCheckpoint &&
1377	    client->discardCommand)
1378	{
1379	    execute_system_command (client->discardCommand);
1380	    XtFree (client->discardCommand);
1381	    client->discardCommand = NULL;
1382	}
1383    }
1384
1385    shutdownInProgress = True;
1386
1387    for (cl = ListFirst (RunningList); cl; cl = ListNext (cl))
1388    {
1389	client = (ClientRec *) cl->thing;
1390
1391	SmsDie (client->smsConn);
1392
1393	if (verbose)
1394	{
1395	    printf ("Client Id = %s, sent DIE\n", client->clientId);
1396	}
1397    }
1398}
1399