2 * $TOG: WMSaveSession.C /main/16 1998/12/09 18:29:33 mgreess $
4 * @(#)WMSaveSession.C 1.12 23 May 1995
6 * RESTRICTED CONFIDENTIAL INFORMATION:
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
16 * Copyright 1993, 1994, 1995 Sun Microsystems, Inc. All rights reserved.
23 #include <sys/param.h>
26 #include <Dt/DtPStrings.h>
27 #include <Dt/Session.h>
29 #include <Xm/Protocols.h>
32 #include <DtMail/IO.hh> // SafeAccess...
34 #include <RoamMenuWindow.h>
35 #include <SendMsgDialog.h>
37 #include <Dt/Session.h>
38 #include <Dt/DtNlUtils.h>
48 char logfile[MAXPATHLEN+1];
49 int logfile_initd = 0;
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) \
60 LOG_GETFILENAME(logfile); \
62 if (! (log = fopen(logfile,"a+"))) \
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)
76 // Data struct to hold the iconic state of a window.
77 typedef struct _WmState
85 * Initializes the Mailer for XSMP by registering save and die callbacks
86 * on the session shell.
89 RoamApp::initSession(void)
91 LOG_DEFINEFILEPTR(log);
95 #define MAXLOGSZ 10000
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);
108 XtAddCallback(_w, XtNsaveCallback, smpSaveSessionCB, (XtPointer) this);
109 XtAddCallback(_w, XtNdieCallback, smpDieCB, (XtPointer) this);
111 LOG_FPRINTF(log, (log,"Session Initialized at: %s\n", ctime(&tloc)));
112 LOG_CLOSEFILEPTR(log);
116 * This method takes a file name and computes the full pathname
117 * using Dt services and then opens the session file pointed
121 RoamApp::openSessionFile(char *filename)
124 char *pathname = NULL;
126 if (filename == NULL)
131 LOG_DEFINEFILEPTR(log);
132 LOG_OPENFILEPTR(log);
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)
139 LOG_FPRINTF(log, (log,"DtSessionRestorePath Failed on: %s\n",filename));
140 LOG_CLOSEFILEPTR(log);
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);
153 if (!(session_fp = fopen(pathname, "r")))
160 LOG_FPRINTF(log, (log,"Opened session file: %s\n",pathname));
161 LOG_CLOSEFILEPTR(log);
162 if (pathname != NULL)
163 XtFree((char *)pathname);
167 * This methods parses the -session argument and
168 * returns the name of the session file if present.
170 char *RoamApp::parseSessionArg(int *argc, char **argv)
172 LOG_DEFINEFILEPTR(log);
173 char *filename = NULL;
178 LOG_OPENFILEPTR(log);
180 for(int i=0; i<*argc; i++)
182 LOG_FPRINTF(log, (log,"restart argv[%d]: %s\n",i, argv[i]));
183 if (!strcmp(argv[i], "-session"))
187 filename = argv[i+1];
188 for (int j=i+2; j < *argc; )
189 argv[i++] = argv[j++];
196 LOG_CLOSEFILEPTR(log);
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.
206 RoamApp::restoreSession(void)
208 char buf[MAXPATHLEN+1];
216 if (fscanf(session_fp,"%s",buf) == EOF)
223 RoamMenuWindow *rmw = NULL;
225 rmw = RoamMenuWindow::restoreSession(buf);
226 if(_mailview == NULL)
234 SendMsgDialog::restoreSession(buf);
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);
249 * This method implements the SmSaveLocal SaveYourself XSMP operation for the
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.
256 RoamApp::smpSaveSessionLocal(void)
258 char *pathname = NULL, *filename = NULL;
259 char **save_argv = NULL;
264 if (! DtSessionSavePath(_w, &pathname, &filename))
267 if (! (session_fp = fopen(pathname, "w+")))
270 XtFree((char *)pathname);
271 XtFree((char *)filename);
275 chmod(pathname, S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP);
277 for(int i = 0; i<_numWindows; i++)
278 _windows[i]->smpSaveSessionLocal();
283 XtVaGetValues(_w, XtNrestartCommand, &argv, NULL);
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];
292 save_argv = (char**) XtMalloc(3*sizeof(char*));
293 save_argv[save_argc++] = argv[0];
295 save_argv[save_argc++] = "-session";
296 save_argv[save_argc++] = filename;
297 save_argv[save_argc] = NULL;
299 LOG_DEFINEFILEPTR(log);
300 LOG_OPENFILEPTR(log);
301 for (int j=0; j<save_argc; j++)
303 LOG_FPRINTF(log, (log, "WM_COMMAND[%d]: %s\n",j,save_argv[j]));
305 LOG_CLOSEFILEPTR(log);
307 XtVaSetValues(_w, XtNrestartCommand, save_argv, NULL);
308 /* There should be no code after this */
315 RoamApp::smpSaveSessionGlobal(void)
319 for(int i = 0; i<_numWindows; i++)
320 if (_windows[i]->smpSaveSessionGlobal())
327 * Restores a RoamMenuWindow from a RoamMenuWindow::SaveSessionLocal string.
330 RoamMenuWindow::restoreSession(char *buf)
332 RoamMenuWindow *rmw = NULL;
333 char *workspaces = new char[256];
336 int width = 0, height = 0;
338 Atom *workspace_atoms = NULL;
339 int num_workspaces = 0;
341 LOG_DEFINEFILEPTR(log);
342 LOG_OPENFILEPTR(log);
344 if (!strncmp(buf,"RoamMenu", 8))
346 FILE *fp = theRoamApp.sessionFile();
348 LOG_FPRINTF(log, (log, "Is a RMW"));
350 fp, "%s%s%d%d%d%d%d",
351 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
353 fscanf(fp,"[\n]",buf);
354 LOG_CLOSEFILEPTR(log);
358 LOG_FPRINTF(log, (log, "Restore: RoamMenu %s %s %d %d %d %d %d\n",
359 buf,workspaces,iconic,x,y,width,height));
361 if (0 == strncmp(buf, INBOX, strlen(INBOX)))
363 DtMail::Session *d_session;
365 DtMailObjectSpace space;
368 d_session = theRoamApp.session()->session();
369 d_session->queryImpl(error,
370 d_session->getDefaultImpl(error),
371 DtMailCapabilityInboxName,
375 strncpy(buf, inboxname, MAXPATHLEN);
376 buf[MAXPATHLEN] = '\0';
377 if (NULL != inboxname)
381 rmw = new RoamMenuWindow(buf);
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();
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)) &&
408 (iconic ? IconicState: NormalState),
409 XtNx, (Position)x, XtNy, (Position)y,
410 XtNwidth, (Dimension)width, XtNheight,
411 (Dimension)height, NULL);
417 ptr = strchr (workspaces, '*');
418 if (ptr != NULL) *ptr = NULL;
420 workspace_atoms = (Atom*) XtRealloc(
421 (char*) workspace_atoms,
422 sizeof(Atom) * (num_workspaces+1));
424 workspace_atoms[num_workspaces] =
425 XmInternAtom (XtDisplay(bw), workspaces, True);
432 workspaces = ptr + 1;
434 } while (ptr != NULL);
436 DtWsmSetWorkspacesOccupied(
442 XtFree((char*) workspace_atoms);
443 workspace_atoms = NULL;
449 // Manage the RMW now. This will cause the window
450 // to appear in the correct workspace.
454 LOG_CLOSEFILEPTR(log);
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
466 RoamMenuWindow::smpSaveSessionLocal(void)
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;
475 Atom *ws_presence = NULL;
476 char *workspace_name=NULL;
477 unsigned long num_workspaces = 0;
478 char *all_workspace_names;
485 wm_state = XmInternAtom(display, "WM_STATE", False);
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);
492 initialstate = (iconic_state->state == IconicState ? 1: 0);
494 // Get the workspaces this window is present.
495 if (DtWsmGetWorkspacesOccupied(
496 display, XtWindow(_w),
497 &ws_presence, &num_workspaces) == Success)
499 for (int j = 0; j < num_workspaces; j++)
501 workspace_name = XGetAtomName (display, ws_presence[j]);
504 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
505 strcpy(all_workspace_names, (char*) workspace_name);
508 (void) strcat(all_workspace_names, "*");
509 (void) strcat(all_workspace_names, workspace_name);
512 XtFree ((char *) workspace_name);
515 XFree((char *)ws_presence);
521 mailboxname = _mailbox_fullpath;
524 fp, "RoamMenu %s %s %d %d %d %d %d\n",
526 all_workspace_names, initialstate,
528 (int)_width, (int)_height);
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,
536 (int)_width, (int)_height));
537 LOG_CLOSEFILEPTR(log);
544 RoamMenuWindow::smpSaveSessionGlobal(void)
546 return queryExpunge();
550 SendMsgDialog::restoreSession(char *buf)
552 char *workspaces = new char[256];
555 int width = 0, height = 0;
557 Atom *workspace_atoms = NULL;
558 int num_workspaces=0;
559 SendMsgDialog *smd = NULL;
561 LOG_DEFINEFILEPTR(log);
562 LOG_OPENFILEPTR(log);
564 if (!strncmp(buf,"SendMsg", 7))
566 FILE *fp = theRoamApp.sessionFile();
568 LOG_FPRINTF(log, (log, "Is a SMD"));
571 fp, "%s%s%d%d%d%d%d",
572 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
574 fscanf(fp,"[\n]",buf);
575 LOG_CLOSEFILEPTR(log);
579 LOG_FPRINTF(log, (log, "Restore: SendMsg %s %s %d %d %d %d %d\n",
580 buf,workspaces,iconic,x,y,width,height));
582 smd = theCompose.getWin();
583 smd->loadDeadLetter(buf);
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();
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)) &&
610 (iconic ? IconicState: NormalState),
611 XtNx, (Position)x, XtNy, (Position)y,
612 XtNwidth, (Dimension)width, XtNheight,
613 (Dimension)height, NULL);
618 ptr = strchr(workspaces, '*');
619 if (ptr != NULL) *ptr = NULL;
621 workspace_atoms = (Atom*) XtRealloc(
622 (char*) workspace_atoms,
623 sizeof(Atom)*(num_workspaces+1));
625 workspace_atoms[num_workspaces] =
626 XmInternAtom(XtDisplay(bw), workspaces, True);
633 workspaces = ptr + 1;
635 } while (ptr != NULL);
637 DtWsmSetWorkspacesOccupied(
643 XtFree((char*) workspace_atoms);
644 workspace_atoms = NULL;
648 // Manage the SMD now. This will cause the window
649 // to appear in the correct workspace.
653 LOG_CLOSEFILEPTR(log);
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
664 SendMsgDialog::smpSaveSessionLocal(void)
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;
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;
686 // If tthe SMD is not being used, return.
690 // Create a dead letter if this one is currently in use
691 if ((save_filename = tempnam(_auto_save_path, "session")) == NULL)
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)
700 doAutoSave(save_filename);
702 wm_state = XmInternAtom(display, "WM_STATE", False);
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);
709 initialstate = (iconic_state->state == IconicState ? 1: 0);
711 // Get the workspaces this window is present.
712 if (DtWsmGetWorkspacesOccupied(
713 display, XtWindow (_w),
714 &ws_presence, &num_workspaces) == Success)
716 for (j = 0; j < num_workspaces; j++)
718 workspace_name = XGetAtomName (display, ws_presence[j]);
721 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
722 strcpy(all_workspace_names, (char*) workspace_name);
726 (void) strcat(all_workspace_names, "*");
727 (void) strcat(all_workspace_names, workspace_name);
730 XtFree((char*) workspace_name);
733 XFree((char *)ws_presence);
745 fp,"SendMsg %s %s %d %d %d %d %d\n",
747 all_workspace_names, initialstate,
749 (int)width, (int)height);
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,
757 (int)width, (int)height));
758 LOG_CLOSEFILEPTR(log);
767 SendMsgDialog::smpSaveSessionGlobal(void)
772 MainWindow::manage();
774 // Enquire if user really wants this window to go away
775 Boolean really_quit = handleQuitDialog();
786 * Session Shell save callback.
789 RoamApp::smpSaveSessionCB(Widget , XtPointer client, XtPointer call)
791 RoamApp *roamapp = (RoamApp*) client;
792 XtCheckpointToken cpToken = (XtCheckpointToken) call;
794 if (! roamapp->_firstSaveYourselfArrived)
796 // Skip the first one since things aren't ready yet.
797 roamapp->_firstSaveYourselfArrived = TRUE;
801 if (cpToken->cancel_shutdown)
803 roamapp->unsetQuitQuickly();
804 roamapp->unsetQuitSilently();
808 if (cpToken->save_type == SmSaveLocal ||
809 cpToken->save_type == SmSaveBoth)
810 roamapp->smpSaveSessionLocal();
812 if (cpToken->shutdown)
815 roamapp->setQuitQuickly();
817 if (cpToken->interact_style == SmInteractStyleNone ||
818 cpToken->interact_style == SmInteractStyleErrors)
819 roamapp->setQuitSilently();
820 else if (! cpToken->fast)
822 roamapp->baseWidget(),
823 XtNinteractCallback, smpInteractCB,
824 (XtPointer) roamapp);
829 * Session Shell die callback.
832 RoamApp::smpDieCB(Widget, XtPointer client, XtPointer)
834 RoamApp *roamapp = (RoamApp*) client;
835 roamapp->closeAllWindows();
839 * Session Shell interact callback.
842 RoamApp::smpInteractCB(Widget, XtPointer client, XtPointer call)
844 RoamApp *roamapp = (RoamApp*) client;
845 XtCheckpointToken cpToken = (XtCheckpointToken) call;
847 if (cpToken->save_type == SmSaveGlobal ||
848 cpToken->save_type == SmSaveBoth)
849 cpToken->cancel_shutdown = roamapp->smpSaveSessionGlobal();