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