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 libraries 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 XtFree((char *)pathname);
188 * This methods parses the -session argument and
189 * returns the name of the session file if present.
191 char *RoamApp::parseSessionArg(int *argc, char **argv)
193 LOG_DEFINEFILEPTR(log);
194 char *filename = NULL;
199 LOG_OPENFILEPTR(log);
201 for(int i=0; i<*argc; i++)
203 LOG_FPRINTF(log, (log,"restart argv[%d]: %s\n",i, argv[i]));
204 if (!strcmp(argv[i], "-session"))
208 filename = argv[i+1];
209 for (int j=i+2; j < *argc; )
210 argv[i++] = argv[j++];
217 LOG_CLOSEFILEPTR(log);
222 * This method implements the restore operation for RoamApp.
223 * Creates and initializes a RoamMenuWindow or SendMsgDialog
224 * for each MainWindow in the session file.
227 RoamApp::restoreSession(void)
229 char buf[MAXPATHLEN+1];
237 if (fscanf(session_fp,"%s",buf) == EOF)
244 RoamMenuWindow *rmw = NULL;
246 rmw = RoamMenuWindow::restoreSession(buf);
247 if(_mailview == NULL)
255 SendMsgDialog::restoreSession(buf);
259 LOG_DEFINEFILEPTR(log);
260 LOG_OPENFILEPTR(log);
261 LOG_FPRINTF(log, (log, "%s contains neither an R or an S", buf));
262 LOG_CLOSEFILEPTR(log);
270 * This method implements the SmSaveLocal SaveYourself XSMP operation for the
272 * 1. Gets a session file name from Dt services and opens the session file.
273 * 2. Invokes a saveSessionLocal on each top level window.
274 * 3. Updates the WM_COMMAND property.
277 RoamApp::smpSaveSessionLocal(void)
279 char *pathname = NULL, *filename = NULL;
280 char **save_argv = NULL;
285 if (! DtSessionSavePath(_w, &pathname, &filename))
288 if (! (session_fp = fopen(pathname, "w+")))
291 XtFree((char *)pathname);
292 XtFree((char *)filename);
296 chmod(pathname, S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP);
298 for(int i = 0; i<_numWindows; i++)
299 _windows[i]->smpSaveSessionLocal();
304 XtVaGetValues(_w, XtNrestartCommand, &argv, NULL);
307 for (i=0; NULL != argv[i]; i++) {}
308 save_argv = (char**) XtMalloc((i+3)*sizeof(char*));
309 for (save_argc=0; save_argc<i; save_argc++)
310 save_argv[save_argc] = argv[save_argc];
313 save_argv = (char**) XtMalloc(3*sizeof(char*));
314 save_argv[save_argc++] = argv[0];
316 save_argv[save_argc++] = "-session";
317 save_argv[save_argc++] = filename;
318 save_argv[save_argc] = NULL;
320 LOG_DEFINEFILEPTR(log);
321 LOG_OPENFILEPTR(log);
322 for (int j=0; j<save_argc; j++)
324 LOG_FPRINTF(log, (log, "WM_COMMAND[%d]: %s\n",j,save_argv[j]));
326 LOG_CLOSEFILEPTR(log);
328 XtVaSetValues(_w, XtNrestartCommand, save_argv, NULL);
329 /* There should be no code after this */
336 RoamApp::smpSaveSessionGlobal(void)
340 for(int i = 0; i<_numWindows; i++)
341 if (_windows[i]->smpSaveSessionGlobal())
348 * Restores a RoamMenuWindow from a RoamMenuWindow::SaveSessionLocal string.
351 RoamMenuWindow::restoreSession(char *buf)
353 RoamMenuWindow *rmw = NULL;
354 char *workspaces = new char[256];
357 int width = 0, height = 0;
359 Atom *workspace_atoms = NULL;
360 int num_workspaces = 0;
362 LOG_DEFINEFILEPTR(log);
363 LOG_OPENFILEPTR(log);
365 if (!strncmp(buf,"RoamMenu", 8))
367 FILE *fp = theRoamApp.sessionFile();
369 LOG_FPRINTF(log, (log, "Is a RMW"));
371 fp, "%s%s%d%d%d%d%d",
372 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
374 fscanf(fp,"[\n]",buf);
375 LOG_CLOSEFILEPTR(log);
379 LOG_FPRINTF(log, (log, "Restore: RoamMenu %s %s %d %d %d %d %d\n",
380 buf,workspaces,iconic,x,y,width,height));
382 if (0 == strncmp(buf, INBOX, strlen(INBOX)))
384 DtMail::Session *d_session;
386 DtMailObjectSpace space;
389 d_session = theRoamApp.session()->session();
390 d_session->queryImpl(error,
391 d_session->getDefaultImpl(error),
392 DtMailCapabilityInboxName,
396 strncpy(buf, inboxname, MAXPATHLEN);
397 buf[MAXPATHLEN] = '\0';
398 if (NULL != inboxname)
402 rmw = new RoamMenuWindow(buf);
405 // Use the appropriate DtWsm* method to restore the window
406 // to the workspace it belonged to.
407 // A problem though: the DtWsm* methods require the widget
408 // to be realized. We normally realize the window only when
409 // we call manage. If we call manage now, the window will
410 // pop up in the default workspace and then *move* to the
411 // appropriate workspace later. To avoid this, we realize,
412 // but not manage, the widget, call the DtWsm* method,
413 // and then manage the widget. This will cause the window
414 // to appear only in the appropriate workspace.
415 Widget bw = rmw->baseWidget();
419 // If the arguments are all valid, use them.
420 // Else let the values in app-defaults take over.
421 if (((iconic == 0) || (iconic == 1)) &&
429 (iconic ? IconicState: NormalState),
430 XtNx, (Position)x, XtNy, (Position)y,
431 XtNwidth, (Dimension)width, XtNheight,
432 (Dimension)height, NULL);
438 ptr = strchr (workspaces, '*');
439 if (ptr != NULL) *ptr = 0;
441 workspace_atoms = (Atom*) XtRealloc(
442 (char*) workspace_atoms,
443 sizeof(Atom) * (num_workspaces+1));
445 workspace_atoms[num_workspaces] =
446 XmInternAtom (XtDisplay(bw), workspaces, True);
453 workspaces = ptr + 1;
455 } while (ptr != NULL);
457 DtWsmSetWorkspacesOccupied(
463 XtFree((char*) workspace_atoms);
464 workspace_atoms = NULL;
470 // Manage the RMW now. This will cause the window
471 // to appear in the correct workspace.
475 LOG_CLOSEFILEPTR(log);
480 * This method implements the save yourself operation for
481 * RoamMenuWindow object. The steps involved are:
482 * 1. Get the session file pointer from theRoamApp.
483 * 2. Get the iconic state, mail folder, x, y, width, height and
487 RoamMenuWindow::smpSaveSessionLocal(void)
489 WmState *iconic_state = NULL;
490 FILE *fp = theRoamApp.sessionFile();
491 Display *display = theRoamApp.display();
492 int initialstate = 0;
493 Atom wm_state, actual_type;
494 unsigned long nitems, leftover;
496 Atom *ws_presence = NULL;
497 char *workspace_name=NULL;
498 unsigned long num_workspaces = 0;
499 char *all_workspace_names;
506 wm_state = XmInternAtom(display, "WM_STATE", False);
508 display,XtWindow(_w), wm_state, 0L,
509 (long)BUFSIZ, False, wm_state, &actual_type,
510 &actual_format, &nitems, &leftover,
511 (unsigned char **) &iconic_state);
513 initialstate = (iconic_state->state == IconicState ? 1: 0);
515 // Get the workspaces this window is present.
516 if (DtWsmGetWorkspacesOccupied(
517 display, XtWindow(_w),
518 &ws_presence, &num_workspaces) == Success)
520 for (int j = 0; j < num_workspaces; j++)
522 workspace_name = XGetAtomName (display, ws_presence[j]);
525 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
526 strcpy(all_workspace_names, (char*) workspace_name);
529 (void) strcat(all_workspace_names, "*");
530 (void) strcat(all_workspace_names, workspace_name);
533 XtFree ((char *) workspace_name);
536 XFree((char *)ws_presence);
542 mailboxname = _mailbox_fullpath;
545 fp, "RoamMenu %s %s %d %d %d %d %d\n",
547 all_workspace_names, initialstate,
549 (int)_width, (int)_height);
551 LOG_DEFINEFILEPTR(log);
552 LOG_OPENFILEPTR(log);
553 LOG_FPRINTF(log, (log, "Save: RoamMenu %s %s %s %d %d %d %d %d\n",
554 XtName(_w), mailboxname,
555 all_workspace_names, initialstate,
557 (int)_width, (int)_height));
558 LOG_CLOSEFILEPTR(log);
565 RoamMenuWindow::smpSaveSessionGlobal(void)
567 return queryExpunge();
571 SendMsgDialog::restoreSession(char *buf)
573 char *workspaces = new char[256];
576 int width = 0, height = 0;
578 Atom *workspace_atoms = NULL;
579 int num_workspaces=0;
580 SendMsgDialog *smd = NULL;
582 LOG_DEFINEFILEPTR(log);
583 LOG_OPENFILEPTR(log);
585 if (!strncmp(buf,"SendMsg", 7))
587 FILE *fp = theRoamApp.sessionFile();
589 LOG_FPRINTF(log, (log, "Is a SMD"));
592 fp, "%s%s%d%d%d%d%d",
593 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
595 fscanf(fp,"[\n]",buf);
596 LOG_CLOSEFILEPTR(log);
600 LOG_FPRINTF(log, (log, "Restore: SendMsg %s %s %d %d %d %d %d\n",
601 buf,workspaces,iconic,x,y,width,height));
603 smd = theCompose.getWin();
604 smd->loadDeadLetter(buf);
606 // Use the appropriate DtWsm* method to restore the window
607 // to the workspace it belonged to.
608 // A problem though: the DtWsm* methods require the widget
609 // to be realized. We normally realize the window only when
610 // we call manage. If we call manage now, the window will
611 // pop up in the default workspace and then *move* to the
612 // appropriate workspace later. To avoid this, we realize,
613 // but not manage, the widget, call the DtWsm* method,
614 // and then manage the widget. This will cause the window
615 // to appear only in the appropriate workspace.
616 Widget bw = smd->baseWidget();
621 // If the values are valid, use them.
622 // Else let the ones in the app-defaults take over.
623 if (((iconic == 0) || (iconic == 1)) &&
631 (iconic ? IconicState: NormalState),
632 XtNx, (Position)x, XtNy, (Position)y,
633 XtNwidth, (Dimension)width, XtNheight,
634 (Dimension)height, NULL);
639 ptr = strchr(workspaces, '*');
640 if (ptr != NULL) *ptr = 0;
642 workspace_atoms = (Atom*) XtRealloc(
643 (char*) workspace_atoms,
644 sizeof(Atom)*(num_workspaces+1));
646 workspace_atoms[num_workspaces] =
647 XmInternAtom(XtDisplay(bw), workspaces, True);
654 workspaces = ptr + 1;
656 } while (ptr != NULL);
658 DtWsmSetWorkspacesOccupied(
664 XtFree((char*) workspace_atoms);
665 workspace_atoms = NULL;
669 // Manage the SMD now. This will cause the window
670 // to appear in the correct workspace.
674 LOG_CLOSEFILEPTR(log);
678 * This method implements the save yourself operation for
679 * SendMsgDialog object. The steps involved are:
680 * 1. Get the session file pointer from theRoamApp.
681 * 2. Get the iconic state, mail folder, x, y, width, height and
685 SendMsgDialog::smpSaveSessionLocal(void)
687 WmState *iconic_state = NULL;
688 FILE *fp = theRoamApp.sessionFile();
689 Display *display = theRoamApp.display();
690 int initialstate = 0;
691 Atom wm_state, actual_type;
692 unsigned long nitems, leftover;
695 Dimension width = 0, height = 0;
696 Atom *ws_presence = NULL;
697 char *workspace_name = NULL;
698 unsigned long num_workspaces = 0;
699 char *all_workspace_names;
707 // If tthe SMD is not being used, return.
711 // Create a dead letter if this one is currently in use
712 if ((save_filename = tempnam(_auto_save_path, "session")) == NULL)
714 for (int suffix = 1; ; suffix++) {
715 save_filename = (char*) malloc((size_t) MAXPATHLEN + 1);
716 sprintf(save_filename, "%s/session.%d", _auto_save_path, suffix);
717 if (SafeAccess(save_filename, F_OK) != 0)
721 doAutoSave(save_filename);
723 wm_state = XmInternAtom(display, "WM_STATE", False);
725 display, XtWindow(_w), wm_state, 0L,
726 (long)BUFSIZ, False, wm_state, &actual_type,
727 &actual_format, &nitems, &leftover,
728 (unsigned char **) &iconic_state);
730 initialstate = (iconic_state->state == IconicState ? 1: 0);
732 // Get the workspaces this window is present.
733 if (DtWsmGetWorkspacesOccupied(
734 display, XtWindow (_w),
735 &ws_presence, &num_workspaces) == Success)
737 for (j = 0; j < num_workspaces; j++)
739 workspace_name = XGetAtomName (display, ws_presence[j]);
742 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
743 strcpy(all_workspace_names, (char*) workspace_name);
747 (void) strcat(all_workspace_names, "*");
748 (void) strcat(all_workspace_names, workspace_name);
751 XtFree((char*) workspace_name);
754 XFree((char *)ws_presence);
766 fp,"SendMsg %s %s %d %d %d %d %d\n",
768 all_workspace_names, initialstate,
770 (int)width, (int)height);
772 LOG_DEFINEFILEPTR(log);
773 LOG_OPENFILEPTR(log);
774 LOG_FPRINTF(log, (log, "Save: SendMsg %s %s %s %d %d %d %d %d\n",
775 XtName(_w), save_filename,
776 all_workspace_names, initialstate,
778 (int)width, (int)height));
779 LOG_CLOSEFILEPTR(log);
788 SendMsgDialog::smpSaveSessionGlobal(void)
793 MainWindow::manage();
795 // Enquire if user really wants this window to go away
796 Boolean really_quit = handleQuitDialog();
807 * Session Shell save callback.
810 RoamApp::smpSaveSessionCB(Widget , XtPointer client, XtPointer call)
812 RoamApp *roamapp = (RoamApp*) client;
813 XtCheckpointToken cpToken = (XtCheckpointToken) call;
815 if (! roamapp->_firstSaveYourselfArrived)
817 // Skip the first one since things aren't ready yet.
818 roamapp->_firstSaveYourselfArrived = TRUE;
822 if (cpToken->cancel_shutdown)
824 roamapp->unsetQuitQuickly();
825 roamapp->unsetQuitSilently();
829 if (cpToken->save_type == SmSaveLocal ||
830 cpToken->save_type == SmSaveBoth)
831 roamapp->smpSaveSessionLocal();
833 if (cpToken->shutdown)
836 roamapp->setQuitQuickly();
838 if (cpToken->interact_style == SmInteractStyleNone ||
839 cpToken->interact_style == SmInteractStyleErrors)
840 roamapp->setQuitSilently();
841 else if (! cpToken->fast)
843 roamapp->baseWidget(),
844 XtNinteractCallback, smpInteractCB,
845 (XtPointer) roamapp);
850 * Session Shell die callback.
853 RoamApp::smpDieCB(Widget, XtPointer client, XtPointer)
855 RoamApp *roamapp = (RoamApp*) client;
856 roamapp->closeAllWindows();
860 * Session Shell interact callback.
863 RoamApp::smpInteractCB(Widget, XtPointer client, XtPointer call)
865 RoamApp *roamapp = (RoamApp*) client;
866 XtCheckpointToken cpToken = (XtCheckpointToken) call;
868 if (cpToken->save_type == SmSaveGlobal ||
869 cpToken->save_type == SmSaveBoth)
870 cpToken->cancel_shutdown = roamapp->smpSaveSessionGlobal();