2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * $TOG: WMSaveSession.C /main/16 1998/12/09 18:29:33 mgreess $
26 * @(#)WMSaveSession.C 1.12 23 May 1995
28 * RESTRICTED CONFIDENTIAL INFORMATION:
30 * The information in this document is subject to special
31 * restrictions in a confidential disclosure agreement between
32 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
33 * document outside HP, IBM, Sun, USL, SCO, or Univel without
34 * Sun's specific written approval. This document and all copies
35 * and derivative works thereof must be returned or destroyed at
38 * Copyright 1993, 1994, 1995 Sun Microsystems, Inc. All rights reserved.
45 #include <sys/param.h>
48 #include <Dt/DtPStrings.h>
49 #include <Dt/Session.h>
51 #include <Xm/Protocols.h>
54 #include <DtMail/IO.hh> // SafeAccess...
56 #include <RoamMenuWindow.h>
57 #include <SendMsgDialog.h>
59 #include <Dt/Session.h>
60 #include <Dt/DtNlUtils.h>
70 char logfile[MAXPATHLEN+1];
71 int logfile_initd = 0;
73 #define LOG_CLOSEFILEPTR(log) if (log) fclose(log);
74 #define LOG_DEFINEFILEPTR(log) FILE *log = NULL;
75 #define LOG_FPRINTF(log, args) if (log) fprintf args;
76 #define LOG_GETFILENAME(lfn) \
77 sprintf(lfn, "%s/%s/dtmail.log", getenv("HOME"), DtPERSONAL_TMP_DIRECTORY);
78 #define LOG_OPENFILEPTR(log) \
79 if (! logfile_initd) \
82 LOG_GETFILENAME(logfile); \
84 if (! (log = fopen(logfile,"a+"))) \
89 #define LOG_CLOSEFILEPTR(log)
90 #define LOG_DEFINEFILEPTR(log)
91 #define LOG_FPRINTF(log, args)
92 #define LOG_GETFILENAME(lfn)
93 #define LOG_OPENFILEPTR(log)
98 // Data struct to hold the iconic state of a window.
99 typedef struct _WmState
107 * Initializes the Mailer for XSMP by registering save and die callbacks
108 * on the session shell.
111 RoamApp::initSession(void)
113 LOG_DEFINEFILEPTR(log);
114 LOG_OPENFILEPTR(log);
117 #define MAXLOGSZ 10000
121 // If the size of the logfile exceeds a max size, truncate it.
122 if (stat(logfile, &sbuf) == 0)
123 if (sbuf.st_size > MAXLOGSZ)
124 truncate(logfile, 0);
130 XtAddCallback(_w, XtNsaveCallback, smpSaveSessionCB, (XtPointer) this);
131 XtAddCallback(_w, XtNdieCallback, smpDieCB, (XtPointer) this);
133 LOG_FPRINTF(log, (log,"Session Initialized at: %s\n", ctime(&tloc)));
134 LOG_CLOSEFILEPTR(log);
138 * This method takes a file name and computes the full pathname
139 * using Dt services and then opens the session file pointed
143 RoamApp::openSessionFile(char *filename)
146 char *pathname = NULL;
148 if (filename == NULL)
153 LOG_DEFINEFILEPTR(log);
154 LOG_OPENFILEPTR(log);
156 // If the session file is an absolute path, just use it.
157 if (filename[0] == '/')
158 pathname = strdup(filename);
159 else if (DtSessionRestorePath(_w, &pathname, filename) == FALSE)
161 LOG_FPRINTF(log, (log,"DtSessionRestorePath Failed on: %s\n",filename));
162 LOG_CLOSEFILEPTR(log);
166 // Sometimes the session file can be empty.
167 // This can cause dtmail to exist as a zombie process on login.
168 // To prevent that, we stat the session file and if necessary,
169 // set the session_fp to NULL.
170 SafeStat(pathname, &s);
175 if (!(session_fp = fopen(pathname, "r")))
182 LOG_FPRINTF(log, (log,"Opened session file: %s\n",pathname));
183 LOG_CLOSEFILEPTR(log);
184 if (pathname != NULL)
185 XtFree((char *)pathname);
189 * This methods parses the -session argument and
190 * returns the name of the session file if present.
192 char *RoamApp::parseSessionArg(int *argc, char **argv)
194 LOG_DEFINEFILEPTR(log);
195 char *filename = NULL;
200 LOG_OPENFILEPTR(log);
202 for(int i=0; i<*argc; i++)
204 LOG_FPRINTF(log, (log,"restart argv[%d]: %s\n",i, argv[i]));
205 if (!strcmp(argv[i], "-session"))
209 filename = argv[i+1];
210 for (int j=i+2; j < *argc; )
211 argv[i++] = argv[j++];
218 LOG_CLOSEFILEPTR(log);
223 * This method implements the restore operation for RoamApp.
224 * Creates and initializes a RoamMenuWindow or SendMsgDialog
225 * for each MainWindow in the session file.
228 RoamApp::restoreSession(void)
230 char buf[MAXPATHLEN+1];
238 if (fscanf(session_fp,"%s",buf) == EOF)
245 RoamMenuWindow *rmw = NULL;
247 rmw = RoamMenuWindow::restoreSession(buf);
248 if(_mailview == NULL)
256 SendMsgDialog::restoreSession(buf);
260 LOG_DEFINEFILEPTR(log);
261 LOG_OPENFILEPTR(log);
262 LOG_FPRINTF(log, (log, "%s contains neither an R or an S", buf));
263 LOG_CLOSEFILEPTR(log);
271 * This method implements the SmSaveLocal SaveYourself XSMP operation for the
273 * 1. Gets a session file name from Dt services and opens the session file.
274 * 2. Invokes a saveSessionLocal on each top level window.
275 * 3. Updates the WM_COMMAND property.
278 RoamApp::smpSaveSessionLocal(void)
280 char *pathname = NULL, *filename = NULL;
281 char **save_argv = NULL;
286 if (! DtSessionSavePath(_w, &pathname, &filename))
289 if (! (session_fp = fopen(pathname, "w+")))
292 XtFree((char *)pathname);
293 XtFree((char *)filename);
297 chmod(pathname, S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP);
299 for(int i = 0; i<_numWindows; i++)
300 _windows[i]->smpSaveSessionLocal();
305 XtVaGetValues(_w, XtNrestartCommand, &argv, NULL);
308 for (i=0; NULL != argv[i]; i++) {}
309 save_argv = (char**) XtMalloc((i+3)*sizeof(char*));
310 for (save_argc=0; save_argc<i; save_argc++)
311 save_argv[save_argc] = argv[save_argc];
314 save_argv = (char**) XtMalloc(3*sizeof(char*));
315 save_argv[save_argc++] = argv[0];
317 save_argv[save_argc++] = "-session";
318 save_argv[save_argc++] = filename;
319 save_argv[save_argc] = NULL;
321 LOG_DEFINEFILEPTR(log);
322 LOG_OPENFILEPTR(log);
323 for (int j=0; j<save_argc; j++)
325 LOG_FPRINTF(log, (log, "WM_COMMAND[%d]: %s\n",j,save_argv[j]));
327 LOG_CLOSEFILEPTR(log);
329 XtVaSetValues(_w, XtNrestartCommand, save_argv, NULL);
330 /* There should be no code after this */
337 RoamApp::smpSaveSessionGlobal(void)
341 for(int i = 0; i<_numWindows; i++)
342 if (_windows[i]->smpSaveSessionGlobal())
349 * Restores a RoamMenuWindow from a RoamMenuWindow::SaveSessionLocal string.
352 RoamMenuWindow::restoreSession(char *buf)
354 RoamMenuWindow *rmw = NULL;
355 char *workspaces = new char[256];
358 int width = 0, height = 0;
360 Atom *workspace_atoms = NULL;
361 int num_workspaces = 0;
363 LOG_DEFINEFILEPTR(log);
364 LOG_OPENFILEPTR(log);
366 if (!strncmp(buf,"RoamMenu", 8))
368 FILE *fp = theRoamApp.sessionFile();
370 LOG_FPRINTF(log, (log, "Is a RMW"));
372 fp, "%s%s%d%d%d%d%d",
373 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
375 fscanf(fp,"[\n]",buf);
376 LOG_CLOSEFILEPTR(log);
380 LOG_FPRINTF(log, (log, "Restore: RoamMenu %s %s %d %d %d %d %d\n",
381 buf,workspaces,iconic,x,y,width,height));
383 if (0 == strncmp(buf, INBOX, strlen(INBOX)))
385 DtMail::Session *d_session;
387 DtMailObjectSpace space;
390 d_session = theRoamApp.session()->session();
391 d_session->queryImpl(error,
392 d_session->getDefaultImpl(error),
393 DtMailCapabilityInboxName,
397 strncpy(buf, inboxname, MAXPATHLEN);
398 buf[MAXPATHLEN] = '\0';
399 if (NULL != inboxname)
403 rmw = new RoamMenuWindow(buf);
406 // Use the appropriate DtWsm* method to restore the window
407 // to the workspace it belonged to.
408 // A problem though: the DtWsm* methods require the widget
409 // to be realized. We normally realize the window only when
410 // we call manage. If we call manage now, the window will
411 // pop up in the default workspace and then *move* to the
412 // appropriate workspace later. To avoid this, we realize,
413 // but not manage, the widget, call the DtWsm* method,
414 // and then manage the widget. This will cause the window
415 // to appear only in the appropriate workspace.
416 Widget bw = rmw->baseWidget();
420 // If the arguments are all valid, use them.
421 // Else let the values in app-defaults take over.
422 if (((iconic == 0) || (iconic == 1)) &&
430 (iconic ? IconicState: NormalState),
431 XtNx, (Position)x, XtNy, (Position)y,
432 XtNwidth, (Dimension)width, XtNheight,
433 (Dimension)height, NULL);
439 ptr = strchr (workspaces, '*');
440 if (ptr != NULL) *ptr = 0;
442 workspace_atoms = (Atom*) XtRealloc(
443 (char*) workspace_atoms,
444 sizeof(Atom) * (num_workspaces+1));
446 workspace_atoms[num_workspaces] =
447 XmInternAtom (XtDisplay(bw), workspaces, True);
454 workspaces = ptr + 1;
456 } while (ptr != NULL);
458 DtWsmSetWorkspacesOccupied(
464 XtFree((char*) workspace_atoms);
465 workspace_atoms = NULL;
471 // Manage the RMW now. This will cause the window
472 // to appear in the correct workspace.
476 LOG_CLOSEFILEPTR(log);
481 * This method implements the save yourself operation for
482 * RoamMenuWindow object. The steps involved are:
483 * 1. Get the session file pointer from theRoamApp.
484 * 2. Get the iconic state, mail folder, x, y, width, height and
488 RoamMenuWindow::smpSaveSessionLocal(void)
490 WmState *iconic_state = NULL;
491 FILE *fp = theRoamApp.sessionFile();
492 Display *display = theRoamApp.display();
493 int initialstate = 0;
494 Atom wm_state, actual_type;
495 unsigned long nitems, leftover;
497 Atom *ws_presence = NULL;
498 char *workspace_name=NULL;
499 unsigned long num_workspaces = 0;
500 char *all_workspace_names;
507 wm_state = XmInternAtom(display, "WM_STATE", False);
509 display,XtWindow(_w), wm_state, 0L,
510 (long)BUFSIZ, False, wm_state, &actual_type,
511 &actual_format, &nitems, &leftover,
512 (unsigned char **) &iconic_state);
514 initialstate = (iconic_state->state == IconicState ? 1: 0);
516 // Get the workspaces this window is present.
517 if (DtWsmGetWorkspacesOccupied(
518 display, XtWindow(_w),
519 &ws_presence, &num_workspaces) == Success)
521 for (int j = 0; j < num_workspaces; j++)
523 workspace_name = XGetAtomName (display, ws_presence[j]);
526 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
527 strcpy(all_workspace_names, (char*) workspace_name);
530 (void) strcat(all_workspace_names, "*");
531 (void) strcat(all_workspace_names, workspace_name);
534 XtFree ((char *) workspace_name);
537 XFree((char *)ws_presence);
543 mailboxname = _mailbox_fullpath;
546 fp, "RoamMenu %s %s %d %d %d %d %d\n",
548 all_workspace_names, initialstate,
550 (int)_width, (int)_height);
552 LOG_DEFINEFILEPTR(log);
553 LOG_OPENFILEPTR(log);
554 LOG_FPRINTF(log, (log, "Save: RoamMenu %s %s %s %d %d %d %d %d\n",
555 XtName(_w), mailboxname,
556 all_workspace_names, initialstate,
558 (int)_width, (int)_height));
559 LOG_CLOSEFILEPTR(log);
566 RoamMenuWindow::smpSaveSessionGlobal(void)
568 return queryExpunge();
572 SendMsgDialog::restoreSession(char *buf)
574 char *workspaces = new char[256];
577 int width = 0, height = 0;
579 Atom *workspace_atoms = NULL;
580 int num_workspaces=0;
581 SendMsgDialog *smd = NULL;
583 LOG_DEFINEFILEPTR(log);
584 LOG_OPENFILEPTR(log);
586 if (!strncmp(buf,"SendMsg", 7))
588 FILE *fp = theRoamApp.sessionFile();
590 LOG_FPRINTF(log, (log, "Is a SMD"));
593 fp, "%s%s%d%d%d%d%d",
594 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
596 fscanf(fp,"[\n]",buf);
597 LOG_CLOSEFILEPTR(log);
601 LOG_FPRINTF(log, (log, "Restore: SendMsg %s %s %d %d %d %d %d\n",
602 buf,workspaces,iconic,x,y,width,height));
604 smd = theCompose.getWin();
605 smd->loadDeadLetter(buf);
607 // Use the appropriate DtWsm* method to restore the window
608 // to the workspace it belonged to.
609 // A problem though: the DtWsm* methods require the widget
610 // to be realized. We normally realize the window only when
611 // we call manage. If we call manage now, the window will
612 // pop up in the default workspace and then *move* to the
613 // appropriate workspace later. To avoid this, we realize,
614 // but not manage, the widget, call the DtWsm* method,
615 // and then manage the widget. This will cause the window
616 // to appear only in the appropriate workspace.
617 Widget bw = smd->baseWidget();
622 // If the values are valid, use them.
623 // Else let the ones in the app-defaults take over.
624 if (((iconic == 0) || (iconic == 1)) &&
632 (iconic ? IconicState: NormalState),
633 XtNx, (Position)x, XtNy, (Position)y,
634 XtNwidth, (Dimension)width, XtNheight,
635 (Dimension)height, NULL);
640 ptr = strchr(workspaces, '*');
641 if (ptr != NULL) *ptr = 0;
643 workspace_atoms = (Atom*) XtRealloc(
644 (char*) workspace_atoms,
645 sizeof(Atom)*(num_workspaces+1));
647 workspace_atoms[num_workspaces] =
648 XmInternAtom(XtDisplay(bw), workspaces, True);
655 workspaces = ptr + 1;
657 } while (ptr != NULL);
659 DtWsmSetWorkspacesOccupied(
665 XtFree((char*) workspace_atoms);
666 workspace_atoms = NULL;
670 // Manage the SMD now. This will cause the window
671 // to appear in the correct workspace.
675 LOG_CLOSEFILEPTR(log);
679 * This method implements the save yourself operation for
680 * SendMsgDialog object. The steps involved are:
681 * 1. Get the session file pointer from theRoamApp.
682 * 2. Get the iconic state, mail folder, x, y, width, height and
686 SendMsgDialog::smpSaveSessionLocal(void)
688 WmState *iconic_state = NULL;
689 FILE *fp = theRoamApp.sessionFile();
690 Display *display = theRoamApp.display();
691 int initialstate = 0;
692 Atom wm_state, actual_type;
693 unsigned long nitems, leftover;
696 Dimension width = 0, height = 0;
697 Atom *ws_presence = NULL;
698 char *workspace_name = NULL;
699 unsigned long num_workspaces = 0;
700 char *all_workspace_names;
708 // If tthe SMD is not being used, return.
712 // Create a dead letter if this one is currently in use
713 if ((save_filename = tempnam(_auto_save_path, "session")) == NULL)
715 for (int suffix = 1; ; suffix++) {
716 save_filename = (char*) malloc((size_t) MAXPATHLEN + 1);
717 sprintf(save_filename, "%s/session.%d", _auto_save_path, suffix);
718 if (SafeAccess(save_filename, F_OK) != 0)
722 doAutoSave(save_filename);
724 wm_state = XmInternAtom(display, "WM_STATE", False);
726 display, XtWindow(_w), wm_state, 0L,
727 (long)BUFSIZ, False, wm_state, &actual_type,
728 &actual_format, &nitems, &leftover,
729 (unsigned char **) &iconic_state);
731 initialstate = (iconic_state->state == IconicState ? 1: 0);
733 // Get the workspaces this window is present.
734 if (DtWsmGetWorkspacesOccupied(
735 display, XtWindow (_w),
736 &ws_presence, &num_workspaces) == Success)
738 for (j = 0; j < num_workspaces; j++)
740 workspace_name = XGetAtomName (display, ws_presence[j]);
743 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
744 strcpy(all_workspace_names, (char*) workspace_name);
748 (void) strcat(all_workspace_names, "*");
749 (void) strcat(all_workspace_names, workspace_name);
752 XtFree((char*) workspace_name);
755 XFree((char *)ws_presence);
767 fp,"SendMsg %s %s %d %d %d %d %d\n",
769 all_workspace_names, initialstate,
771 (int)width, (int)height);
773 LOG_DEFINEFILEPTR(log);
774 LOG_OPENFILEPTR(log);
775 LOG_FPRINTF(log, (log, "Save: SendMsg %s %s %s %d %d %d %d %d\n",
776 XtName(_w), save_filename,
777 all_workspace_names, initialstate,
779 (int)width, (int)height));
780 LOG_CLOSEFILEPTR(log);
789 SendMsgDialog::smpSaveSessionGlobal(void)
794 MainWindow::manage();
796 // Enquire if user really wants this window to go away
797 Boolean really_quit = handleQuitDialog();
808 * Session Shell save callback.
811 RoamApp::smpSaveSessionCB(Widget , XtPointer client, XtPointer call)
813 RoamApp *roamapp = (RoamApp*) client;
814 XtCheckpointToken cpToken = (XtCheckpointToken) call;
816 if (! roamapp->_firstSaveYourselfArrived)
818 // Skip the first one since things aren't ready yet.
819 roamapp->_firstSaveYourselfArrived = TRUE;
823 if (cpToken->cancel_shutdown)
825 roamapp->unsetQuitQuickly();
826 roamapp->unsetQuitSilently();
830 if (cpToken->save_type == SmSaveLocal ||
831 cpToken->save_type == SmSaveBoth)
832 roamapp->smpSaveSessionLocal();
834 if (cpToken->shutdown)
837 roamapp->setQuitQuickly();
839 if (cpToken->interact_style == SmInteractStyleNone ||
840 cpToken->interact_style == SmInteractStyleErrors)
841 roamapp->setQuitSilently();
842 else if (! cpToken->fast)
844 roamapp->baseWidget(),
845 XtNinteractCallback, smpInteractCB,
846 (XtPointer) roamapp);
851 * Session Shell die callback.
854 RoamApp::smpDieCB(Widget, XtPointer client, XtPointer)
856 RoamApp *roamapp = (RoamApp*) client;
857 roamapp->closeAllWindows();
861 * Session Shell interact callback.
864 RoamApp::smpInteractCB(Widget, XtPointer client, XtPointer call)
866 RoamApp *roamapp = (RoamApp*) client;
867 XtCheckpointToken cpToken = (XtCheckpointToken) call;
869 if (cpToken->save_type == SmSaveGlobal ||
870 cpToken->save_type == SmSaveBoth)
871 cpToken->cancel_shutdown = roamapp->smpSaveSessionGlobal();