Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtmail / dtmail / WMSaveSession.C
1 /*
2  *      $TOG: WMSaveSession.C /main/16 1998/12/09 18:29:33 mgreess $
3  *
4  *      @(#)WMSaveSession.C     1.12 23 May 1995
5  *
6  *      RESTRICTED CONFIDENTIAL INFORMATION:
7  *
8  *      The information in this document is subject to special
9  *      restrictions in a confidential disclosure agreement between
10  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
11  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
12  *      Sun's specific written approval.  This document and all copies
13  *      and derivative works thereof must be returned or destroyed at
14  *      Sun's request.
15  *
16  *      Copyright 1993, 1994, 1995 Sun Microsystems, Inc.  All rights reserved.
17  *
18  */
19
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <time.h>
23 #include <sys/param.h>
24 #include <sys/stat.h>
25
26 #include <Dt/DtPStrings.h>
27 #include <Dt/Session.h>
28 #include <Xm/Xm.h>
29 #include <Xm/Protocols.h>
30 #include <Xm/MainW.h>
31
32 #include <DtMail/IO.hh>                    // SafeAccess...
33 #include <RoamApp.h>
34 #include <RoamMenuWindow.h>
35 #include <SendMsgDialog.h>
36
37 #include <Dt/Session.h>
38 #include <Dt/DtNlUtils.h>
39 #include <Dt/Wsm.h>
40 #include <Dt/WsmP.h>
41
42
43 #define INBOX   "INBOX"
44
45 // For debugging only
46 #ifdef LOG_SESSION
47
48 char logfile[MAXPATHLEN+1];
49 int  logfile_initd = 0;
50
51 #define LOG_CLOSEFILEPTR(log)   if (log) fclose(log);
52 #define LOG_DEFINEFILEPTR(log)  FILE *log = NULL;
53 #define LOG_FPRINTF(log, args)  if (log) fprintf args;
54 #define LOG_GETFILENAME(lfn) \
55     sprintf(lfn, "%s/%s/dtmail.log", getenv("HOME"), DtPERSONAL_TMP_DIRECTORY);
56 #define LOG_OPENFILEPTR(log) \
57     if (! logfile_initd) \
58     { \
59         logfile_initd = 1; \
60         LOG_GETFILENAME(logfile); \
61     } \
62     if (! (log = fopen(logfile,"a+"))) \
63       perror(logfile);
64
65 #else
66
67 #define LOG_CLOSEFILEPTR(log)
68 #define LOG_DEFINEFILEPTR(log)
69 #define LOG_FPRINTF(log, args)
70 #define LOG_GETFILENAME(lfn)
71 #define LOG_OPENFILEPTR(log)
72
73 #endif
74
75
76 // Data struct to hold the iconic state of a window.
77 typedef struct _WmState
78 {
79     int         state;
80     Window      icon;
81 } WmState;
82
83
84 /*
85  * Initializes the Mailer for XSMP by registering save and die callbacks
86  * on the session shell.
87  */
88 void 
89 RoamApp::initSession(void)
90 {
91     LOG_DEFINEFILEPTR(log);
92     LOG_OPENFILEPTR(log);
93
94 #ifdef LOG_SESSION
95 #define MAXLOGSZ        10000
96     struct stat sbuf;
97     time_t      tloc;
98
99     // If the size of the logfile exceeds a max size, truncate it.
100     if (stat(logfile, &sbuf) == 0)
101       if (sbuf.st_size > MAXLOGSZ)
102         truncate(logfile, 0);
103
104     (void) time(&tloc);
105 #endif
106     
107     session_fp = NULL;
108     XtAddCallback(_w, XtNsaveCallback, smpSaveSessionCB, (XtPointer) this);
109     XtAddCallback(_w, XtNdieCallback, smpDieCB, (XtPointer) this);
110
111     LOG_FPRINTF(log, (log,"Session Initialized at: %s\n", ctime(&tloc)));
112     LOG_CLOSEFILEPTR(log);
113 }
114
115 /*
116  * This method takes a file name and computes the full pathname 
117  * using Dt services and then opens the session file pointed
118  * to by pathname.
119  */
120 void
121 RoamApp::openSessionFile(char *filename)
122 {
123     struct stat s;
124     char *pathname = NULL;
125
126     if (filename == NULL)
127       return;
128     
129     session_fp = NULL;
130
131     LOG_DEFINEFILEPTR(log);
132     LOG_OPENFILEPTR(log);
133
134     // If the session file is an absolute path, just use it.
135     if (filename[0] == '/')
136       pathname = strdup(filename);
137     else if (DtSessionRestorePath(_w, &pathname, filename) == FALSE)
138     {
139         LOG_FPRINTF(log, (log,"DtSessionRestorePath Failed on: %s\n",filename));
140         LOG_CLOSEFILEPTR(log);
141         return;
142     }
143
144     // Sometimes the session file can be empty.
145     // This can cause dtmail to exist as a zombie process on login.
146     // To prevent that, we stat the session file and if necessary,
147     // set the session_fp to NULL.
148     SafeStat(pathname, &s);
149     if (s.st_size == 0)
150       session_fp = NULL;
151     else
152     {
153         if (!(session_fp = fopen(pathname, "r")))
154         {
155             perror(pathname);
156             session_fp = NULL;
157         }
158     }
159
160     LOG_FPRINTF(log, (log,"Opened session file: %s\n",pathname));
161     LOG_CLOSEFILEPTR(log);
162     if (pathname != NULL)
163       XtFree((char *)pathname);
164 }
165
166 /*
167  * This methods parses the -session argument and
168  * returns the name of the session file if present.
169  */
170 char *RoamApp::parseSessionArg(int *argc, char **argv)
171 {
172     LOG_DEFINEFILEPTR(log);
173     char *filename = NULL;
174
175     if (*argc<3)
176       return NULL;
177     
178     LOG_OPENFILEPTR(log);
179
180     for(int i=0; i<*argc; i++)
181     {
182         LOG_FPRINTF(log, (log,"restart argv[%d]: %s\n",i, argv[i]));
183         if (!strcmp(argv[i], "-session"))
184         {
185             if (i<*argc-1)
186             {
187                 filename = argv[i+1];
188                 for (int j=i+2; j < *argc; )
189                   argv[i++] = argv[j++]; 
190                 *argc -= 2;
191             }
192             break;
193         }
194     }
195     
196     LOG_CLOSEFILEPTR(log);
197     return filename;
198 }
199
200 /*
201  *  This method implements the restore operation for RoamApp.
202  *  Creates and initializes a RoamMenuWindow or SendMsgDialog
203  *  for each MainWindow in the session file.
204  */
205 void 
206 RoamApp::restoreSession(void)
207 {
208     char buf[MAXPATHLEN+1];
209
210     if (! session_fp)
211       _exit(0);
212     
213     _mailview = NULL;
214     for(;;)
215     {
216         if (fscanf(session_fp,"%s",buf) == EOF)
217           break;
218         
219         switch (buf[0])
220         {
221           case 'R':
222           {
223             RoamMenuWindow      *rmw = NULL;
224             
225             rmw = RoamMenuWindow::restoreSession(buf);
226             if(_mailview == NULL)
227             {
228                 dtmail_mapped = 1;
229                 _mailview = rmw;
230             }  
231             break;
232           }
233           case 'S':
234             SendMsgDialog::restoreSession(buf);
235             break;
236           default:
237           {
238             LOG_DEFINEFILEPTR(log);
239             LOG_OPENFILEPTR(log);
240             LOG_FPRINTF(log, (log, "%s contains neither an R or an S", buf));
241             LOG_CLOSEFILEPTR(log);
242             break;      
243           }
244         }
245     }
246
247
248 /*
249  * This method implements the SmSaveLocal SaveYourself XSMP operation for the
250  * RoamApp object:
251  *   1. Gets a session file name from Dt services and opens the session file. 
252  *   2. Invokes a saveSessionLocal on each top level window.
253  *   3. Updates the WM_COMMAND property. 
254  */
255 void 
256 RoamApp::smpSaveSessionLocal(void)
257 {
258     char *pathname = NULL, *filename = NULL;
259     char **save_argv = NULL;
260     int save_argc = 0;
261     char **argv = NULL;
262     int argc = 0;
263     
264     if (! DtSessionSavePath(_w, &pathname, &filename))
265       return;
266     
267     if (! (session_fp = fopen(pathname, "w+")))
268     {
269         perror(pathname);
270         XtFree((char *)pathname);
271         XtFree((char *)filename);
272         session_fp = NULL;
273         return;
274     }
275     chmod(pathname, S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP);
276     
277     for(int i = 0; i<_numWindows; i++)
278       _windows[i]->smpSaveSessionLocal();
279     
280     fclose(session_fp);
281     session_fp = NULL;
282     
283     XtVaGetValues(_w, XtNrestartCommand, &argv, NULL);
284
285 #if 0
286     for (i=0; NULL != argv[i]; i++) {}
287     save_argv = (char**) XtMalloc((i+3)*sizeof(char*));
288     for (save_argc=0; save_argc<i; save_argc++)
289       save_argv[save_argc] = argv[save_argc];
290 #else
291     save_argc = 0;
292     save_argv = (char**) XtMalloc(3*sizeof(char*));
293     save_argv[save_argc++] = argv[0];
294 #endif
295     save_argv[save_argc++] = "-session";
296     save_argv[save_argc++] = filename;
297     save_argv[save_argc] = NULL;
298     
299     LOG_DEFINEFILEPTR(log);
300     LOG_OPENFILEPTR(log);
301     for (int j=0; j<save_argc; j++)
302     {
303         LOG_FPRINTF(log, (log, "WM_COMMAND[%d]: %s\n",j,save_argv[j]));
304     }
305     LOG_CLOSEFILEPTR(log);
306     
307     XtVaSetValues(_w, XtNrestartCommand, save_argv, NULL);
308     /* There should be no code after this */
309 }
310
311 /*
312  *
313  */
314 int
315 RoamApp::smpSaveSessionGlobal(void)
316 {
317     int cancel;
318
319     for(int i = 0; i<_numWindows; i++)
320       if (_windows[i]->smpSaveSessionGlobal())
321         cancel = 1;
322     
323     return cancel;
324 }
325
326 /*
327  * Restores a RoamMenuWindow from a RoamMenuWindow::SaveSessionLocal string.
328  */
329 RoamMenuWindow *
330 RoamMenuWindow::restoreSession(char *buf)
331 {
332     RoamMenuWindow *rmw = NULL;
333     char *workspaces = new char[256];
334     int iconic = 0; 
335     int x = 0, y = 0; 
336     int width = 0, height = 0;
337     char *ptr;
338     Atom *workspace_atoms = NULL;
339     int num_workspaces = 0;
340
341     LOG_DEFINEFILEPTR(log);
342     LOG_OPENFILEPTR(log);
343     
344     if (!strncmp(buf,"RoamMenu", 8))
345     { 
346         FILE    *fp = theRoamApp.sessionFile();
347
348         LOG_FPRINTF(log, (log, "Is a RMW"));
349         if (fscanf(
350                 fp, "%s%s%d%d%d%d%d",
351                 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
352         {
353             fscanf(fp,"[\n]",buf);
354             LOG_CLOSEFILEPTR(log);
355             return NULL;
356         }
357
358         LOG_FPRINTF(log, (log, "Restore: RoamMenu %s %s %d %d %d %d %d\n",
359                           buf,workspaces,iconic,x,y,width,height));
360                 
361         if (0 == strncmp(buf, INBOX, strlen(INBOX)))
362         {
363             DtMail::Session     *d_session;
364             DtMailEnv           error;
365             DtMailObjectSpace   space;
366             char                *inboxname;
367                     
368             d_session = theRoamApp.session()->session();
369             d_session->queryImpl(error,
370                                 d_session->getDefaultImpl(error),
371                                 DtMailCapabilityInboxName,
372                                 &space,
373                                 &inboxname);
374
375             strncpy(buf, inboxname, MAXPATHLEN);
376             buf[MAXPATHLEN] = '\0';
377             if (NULL != inboxname)
378               free(inboxname);
379         }
380
381         rmw =  new RoamMenuWindow(buf);
382         rmw->initialize();
383
384         // Use the appropriate DtWsm* method to restore the window
385         // to the workspace it belonged to.
386         // A problem though: the DtWsm* methods require the widget
387         // to be realized.  We normally realize the window only when
388         // we call manage.  If we call manage now, the window will
389         // pop up in the default workspace and then *move* to the
390         // appropriate workspace later.  To avoid this, we realize,
391         // but not manage, the widget, call the DtWsm* method,
392         // and then manage the widget.  This will cause the window
393         // to appear only in the appropriate workspace.
394         Widget bw = rmw->baseWidget();
395         XtRealizeWidget(bw);
396         XmUpdateDisplay(bw);
397
398         // If the arguments are all valid, use them.
399         // Else let the values in app-defaults take over.
400         if (((iconic == 0) || (iconic == 1)) &&
401             x >= 0 &&
402             y >= 0 &&
403             width > 0 &&
404             height > 0)
405         {
406             XtVaSetValues(bw,
407                         XtNinitialState, 
408                         (iconic ? IconicState: NormalState), 
409                         XtNx, (Position)x, XtNy, (Position)y, 
410                         XtNwidth, (Dimension)width, XtNheight, 
411                         (Dimension)height, NULL);
412   
413             if (workspaces)
414             {
415                 do
416                 {
417                     ptr = strchr (workspaces, '*');
418                     if (ptr != NULL) *ptr = NULL;
419                                 
420                     workspace_atoms = (Atom*) XtRealloc(
421                                         (char*) workspace_atoms, 
422                                         sizeof(Atom) * (num_workspaces+1));
423
424                     workspace_atoms[num_workspaces] = 
425                       XmInternAtom (XtDisplay(bw), workspaces, True);
426                                         
427                     num_workspaces++;
428
429                     if (ptr != NULL)
430                     {
431                         *ptr = '*';
432                         workspaces = ptr + 1;
433                     }
434                 } while (ptr != NULL);
435
436                 DtWsmSetWorkspacesOccupied(
437                                         XtDisplay(bw),
438                                         XtWindow (bw),
439                                         workspace_atoms,
440                                         num_workspaces);
441
442                 XtFree((char*) workspace_atoms);
443                 workspace_atoms = NULL;
444                           
445             }
446                 
447         }
448
449         // Manage the RMW now.  This will cause the window
450         // to appear in the correct workspace.
451         rmw->manage();
452     }
453
454     LOG_CLOSEFILEPTR(log);
455     return rmw;
456 }
457
458 /*
459  * This method implements the save yourself operation for
460  * RoamMenuWindow object. The steps involved are:
461  *      1. Get the session file pointer from theRoamApp.
462  *      2. Get the iconic state, mail folder, x, y, width, height and 
463  *         save it. 
464  */
465 void
466 RoamMenuWindow::smpSaveSessionLocal(void)
467 {
468     WmState     *iconic_state = NULL;
469     FILE        *fp = theRoamApp.sessionFile();
470     Display     *display = theRoamApp.display();
471     int         initialstate = 0;
472     Atom        wm_state, actual_type;
473     unsigned long nitems, leftover;
474     int         actual_format;
475     Atom        *ws_presence = NULL;
476     char        *workspace_name=NULL;
477     unsigned long num_workspaces = 0;
478     char        *all_workspace_names;
479     char        *mailboxname;
480     
481     if (fp == NULL)
482       return;
483     
484     _mailbox->save();
485     wm_state = XmInternAtom(display, "WM_STATE", False);
486     XGetWindowProperty(
487                 display,XtWindow(_w), wm_state, 0L,
488                 (long)BUFSIZ, False, wm_state, &actual_type,
489                 &actual_format, &nitems, &leftover,
490                 (unsigned char **) &iconic_state);
491     
492     initialstate = (iconic_state->state == IconicState ? 1: 0);
493
494     // Get the workspaces this window is present.
495     if (DtWsmGetWorkspacesOccupied(
496                                 display, XtWindow(_w),
497                                 &ws_presence, &num_workspaces) == Success)
498     {
499          for (int j = 0; j < num_workspaces; j++)
500          {
501             workspace_name = XGetAtomName (display, ws_presence[j]);
502             if (j == 0)
503             {
504                 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
505                 strcpy(all_workspace_names, (char*) workspace_name);
506             }
507             else {
508                 (void) strcat(all_workspace_names, "*");
509                 (void) strcat(all_workspace_names, workspace_name);
510             }
511             
512             XtFree ((char *) workspace_name);
513          }
514
515          XFree((char *)ws_presence);
516       }
517
518     if (_inbox)
519       mailboxname = INBOX;
520     else
521       mailboxname = _mailbox_fullpath;
522
523     (void) fprintf(
524                 fp, "RoamMenu %s %s %d %d %d %d %d\n",
525                 mailboxname,
526                 all_workspace_names, initialstate,
527                 (int)_x, (int)_y, 
528                 (int)_width, (int)_height);
529
530     LOG_DEFINEFILEPTR(log);
531     LOG_OPENFILEPTR(log);
532     LOG_FPRINTF(log, (log, "Save: RoamMenu %s %s %s %d %d %d %d %d\n",
533                       XtName(_w), mailboxname,
534                       all_workspace_names, initialstate,
535                       (int)_x, (int)_y,
536                       (int)_width, (int)_height));
537     LOG_CLOSEFILEPTR(log);
538 }
539
540 /*
541  *
542  */
543 int
544 RoamMenuWindow::smpSaveSessionGlobal(void)
545 {
546     return queryExpunge();
547 }
548
549 void
550 SendMsgDialog::restoreSession(char *buf)
551 {
552     char *workspaces = new char[256];
553     int iconic = 0; 
554     int x = 0, y = 0; 
555     int width = 0, height = 0;
556     char *ptr = NULL;
557     Atom *workspace_atoms = NULL;
558     int num_workspaces=0;
559     SendMsgDialog *smd = NULL;
560
561     LOG_DEFINEFILEPTR(log);
562     LOG_OPENFILEPTR(log);
563
564     if (!strncmp(buf,"SendMsg", 7))
565     {
566         FILE    *fp = theRoamApp.sessionFile();
567
568         LOG_FPRINTF(log, (log, "Is a SMD"));
569
570         if (fscanf(
571                 fp, "%s%s%d%d%d%d%d",
572                 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
573         {
574             fscanf(fp,"[\n]",buf);
575             LOG_CLOSEFILEPTR(log);
576             return;
577         }
578
579         LOG_FPRINTF(log, (log, "Restore: SendMsg %s %s %d %d %d %d %d\n",
580                           buf,workspaces,iconic,x,y,width,height));
581                 
582         smd =  theCompose.getWin();
583         smd->loadDeadLetter(buf);
584
585         // Use the appropriate DtWsm* method to restore the window
586         // to the workspace it belonged to.
587         // A problem though: the DtWsm* methods require the widget
588         // to be realized.  We normally realize the window only when
589         // we call manage.  If we call manage now, the window will
590         // pop up in the default workspace and then *move* to the
591         // appropriate workspace later.  To avoid this, we realize,
592         // but not manage, the widget, call the DtWsm* method,
593         // and then manage the widget.  This will cause the window
594         // to appear only in the appropriate workspace.
595         Widget bw = smd->baseWidget();
596         XtRealizeWidget(bw);
597         XmUpdateDisplay(bw);
598
599                 
600         // If the values are valid, use them.
601         // Else let the ones in the app-defaults take over.
602         if (((iconic == 0) || (iconic == 1)) &&
603             x >= 0 &&
604             y >= 0 &&
605             width > 0 &&
606             height > 0)
607         {
608             XtVaSetValues(bw,
609                         XtNinitialState, 
610                         (iconic ? IconicState: NormalState), 
611                         XtNx, (Position)x, XtNy, (Position)y, 
612                         XtNwidth, (Dimension)width, XtNheight, 
613                         (Dimension)height, NULL);
614             if (workspaces)
615             {
616                 do
617                 {
618                     ptr = strchr(workspaces, '*');
619                     if (ptr != NULL) *ptr = NULL;
620                                 
621                     workspace_atoms = (Atom*) XtRealloc(
622                                         (char*) workspace_atoms, 
623                                         sizeof(Atom)*(num_workspaces+1));
624
625                     workspace_atoms[num_workspaces] = 
626                       XmInternAtom(XtDisplay(bw), workspaces, True);
627
628                     num_workspaces++;
629
630                     if (ptr != NULL)
631                     {
632                         *ptr = '*';
633                         workspaces = ptr + 1;
634                     }
635                 } while (ptr != NULL);
636
637                 DtWsmSetWorkspacesOccupied(
638                                         XtDisplay(bw),
639                                         XtWindow (bw),
640                                         workspace_atoms,
641                                         num_workspaces);
642
643                 XtFree((char*) workspace_atoms);
644                 workspace_atoms = NULL;
645             }
646         }
647
648         // Manage the SMD now.  This will cause the window
649         // to appear in the correct workspace.
650         smd->manage();
651     }
652     
653     LOG_CLOSEFILEPTR(log);
654 }
655
656 /*
657  * This method implements the save yourself operation for
658  * SendMsgDialog object. The steps involved are:
659  *      1. Get the session file pointer from theRoamApp.
660  *      2. Get the iconic state, mail folder, x, y, width, height and 
661  *         save it. 
662  */
663 void
664 SendMsgDialog::smpSaveSessionLocal(void)
665 {
666     WmState     *iconic_state = NULL;
667     FILE        *fp = theRoamApp.sessionFile();
668     Display     *display = theRoamApp.display();
669     int         initialstate = 0;
670     Atom        wm_state, actual_type;
671     unsigned long nitems, leftover;
672     int         actual_format;
673     Position    x=0, y=0;
674     Dimension   width = 0, height = 0;
675     Atom        *ws_presence = NULL;
676     char        *workspace_name = NULL;
677     unsigned long num_workspaces = 0;
678     char        *all_workspace_names;
679     char        *save_filename;
680     int j;
681
682     
683     if(fp == NULL)
684         return;
685     
686     // If tthe SMD is not being used, return.
687     if (!_msgHandle)
688         return;
689     
690     // Create a dead letter if this one is currently in use
691     if ((save_filename = tempnam(_auto_save_path, "session")) == NULL) 
692     {
693         for (int suffix = 1; ; suffix++) {
694             save_filename = (char*) malloc((size_t) MAXPATHLEN + 1);
695             sprintf(save_filename, "%s/session.%d", _auto_save_path, suffix);
696             if (SafeAccess(save_filename, F_OK) != 0)
697               break;
698         }
699     }
700     doAutoSave(save_filename);
701     
702     wm_state = XmInternAtom(display, "WM_STATE", False);
703     XGetWindowProperty(
704                 display, XtWindow(_w), wm_state, 0L,
705                 (long)BUFSIZ, False, wm_state, &actual_type,
706                 &actual_format, &nitems, &leftover,
707                 (unsigned char **) &iconic_state);
708     
709     initialstate = (iconic_state->state == IconicState ? 1: 0);
710
711     // Get the workspaces this window is present.
712     if (DtWsmGetWorkspacesOccupied(
713                                 display, XtWindow (_w),
714                                 &ws_presence, &num_workspaces) == Success)
715     {
716         for (j = 0; j < num_workspaces; j++)
717         {
718             workspace_name = XGetAtomName (display, ws_presence[j]);
719             if (j == 0)
720             {
721                 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
722                 strcpy(all_workspace_names, (char*) workspace_name);
723             }
724             else
725             {
726                 (void) strcat(all_workspace_names, "*");
727                 (void) strcat(all_workspace_names, workspace_name);
728             }
729             
730             XtFree((char*) workspace_name);
731         }
732
733          XFree((char *)ws_presence);
734     }
735
736     XtVaGetValues(
737                 _w,
738                 XtNx, &x,
739                 XtNy, &y,
740                 XtNwidth, &width,
741                 XtNheight, &height,
742                 NULL);
743
744     (void) fprintf(
745                 fp,"SendMsg %s %s %d %d %d %d %d\n",
746                 save_filename,
747                 all_workspace_names, initialstate,
748                 (int)x, (int)y, 
749                 (int)width, (int)height);
750
751     LOG_DEFINEFILEPTR(log);
752     LOG_OPENFILEPTR(log);
753     LOG_FPRINTF(log, (log, "Save: SendMsg %s %s %s %d %d %d %d %d\n",
754                       XtName(_w), save_filename,
755                       all_workspace_names, initialstate,
756                       (int)x, (int)y,
757                       (int)width, (int)height));
758     LOG_CLOSEFILEPTR(log);
759     
760     free(save_filename);
761 }
762
763 /*
764  *
765  */
766 int
767 SendMsgDialog::smpSaveSessionGlobal(void)
768 {
769     if (checkDirty())
770     {
771         if (isIconified())
772             MainWindow::manage();
773
774         // Enquire if user really wants this window to go away
775         Boolean really_quit = handleQuitDialog();
776         if (! really_quit)
777           return 1;
778         
779         _takeDown = TRUE;
780         quit();
781     }
782     return 0;
783 }
784
785 /*
786  *  Session Shell save callback.
787  */
788 void 
789 RoamApp::smpSaveSessionCB(Widget , XtPointer client, XtPointer call)
790 {
791     RoamApp             *roamapp = (RoamApp*) client;
792     XtCheckpointToken   cpToken = (XtCheckpointToken) call;
793
794     if (! roamapp->_firstSaveYourselfArrived)
795     {
796         // Skip the first one since things aren't ready yet.
797         roamapp->_firstSaveYourselfArrived = TRUE;
798         return;
799     }
800
801     if (cpToken->cancel_shutdown)
802     {
803         roamapp->unsetQuitQuickly();
804         roamapp->unsetQuitSilently();
805         return;
806     }
807
808     if (cpToken->save_type == SmSaveLocal ||
809         cpToken->save_type == SmSaveBoth)
810       roamapp->smpSaveSessionLocal();
811     
812     if (cpToken->shutdown)
813     {
814         if (cpToken->fast)
815           roamapp->setQuitQuickly();
816
817         if (cpToken->interact_style == SmInteractStyleNone ||
818             cpToken->interact_style == SmInteractStyleErrors)
819           roamapp->setQuitSilently();
820         else if (! cpToken->fast)
821           XtAddCallback(
822                         roamapp->baseWidget(),
823                         XtNinteractCallback, smpInteractCB,
824                         (XtPointer) roamapp);
825     }
826 }
827
828 /*
829  *  Session Shell die callback.
830  */
831 void 
832 RoamApp::smpDieCB(Widget, XtPointer client, XtPointer)
833 {
834     RoamApp *roamapp = (RoamApp*) client;
835     roamapp->closeAllWindows();
836 }
837
838 /*
839  *  Session Shell interact callback.
840  */
841 void 
842 RoamApp::smpInteractCB(Widget, XtPointer client, XtPointer call)
843 {
844     RoamApp *roamapp = (RoamApp*) client;
845     XtCheckpointToken   cpToken = (XtCheckpointToken) call;
846
847     if (cpToken->save_type == SmSaveGlobal ||
848         cpToken->save_type == SmSaveBoth)
849       cpToken->cancel_shutdown = roamapp->smpSaveSessionGlobal();
850 }