1 /* $TOG: fileCB.c /main/13 1999/11/08 08:23:14 mgreess $ */
2 /**********************************<+>*************************************
3 ***************************************************************************
7 ** Project: DT dtpad, a memo maker type editor based on the Dt Editor
13 ** This file contains the callbacks for the "File" menu items.
14 ** There's some hair here, due to the nested nature of some of
15 ** the dialogs. The "New, "Open" and "Exit" callbacks can cause
16 ** the opening of a do-you-wish-to-save dialog, and we have to
17 ** remember how we got there. This is done through the use
18 ** of the pendingFileFunc field of the Editor struct.
20 *******************************************************************
21 ** (c) Copyright Hewlett-Packard Company, 1991. All rights are
22 ** reserved. Copying or other reproduction of this program
23 ** except for archival purposes is prohibited without prior
24 ** written consent of Hewlett-Packard Company.
25 ********************************************************************
27 ********************************************************************
28 ** (c) Copyright 1993, 1994 Hewlett-Packard Company
29 ** (c) Copyright 1993, 1994 International Business Machines Corp.
30 ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
31 ** (c) Copyright 1993, 1994 Novell, Inc.
32 ********************************************************************
35 **************************************************************************
36 **********************************<+>*************************************/
37 #include <Dt/DtpadM.h>
38 #include <Dt/Action.h>
42 extern int numActivePads; /* declared in main.c */
45 /************************************************************************
46 * Forward Declarations
47 ************************************************************************/
48 static void FileDoXpPrint(
51 static void FileOpenOkCB(
55 static void IncludeFile(
59 static Boolean SaveUnsaved(
61 void (*callingFunc)() );
62 static Boolean FileExitWP(
63 XtPointer client_data);
66 /************************************************************************
67 * FileCascadingCB - callback assigned to "File" menu to determine
68 * whether Save button in menu is labeled "Save" or "Save (needed)".
69 ************************************************************************/
77 Editor *pPad = (Editor *)client_data;
80 if (DtEditorCheckForUnsavedChanges(pPad->editor)) {
81 XtSetArg(al[0], XmNlabelString, pPad->fileStuff.saveNeededBtnLabel);
83 XtSetArg(al[0], XmNlabelString, pPad->fileStuff.saveBtnLabel);
85 XtSetValues(pPad->fileStuff.fileWidgets.saveBtn, al, 1);
90 /************************************************************************
91 * FileNewCB - callback assigned to "File" menu "New" button which
92 * saves the current text if it hasn't been saved and then calls
93 * LoadFile(). Since pPad->fileStuff.fileName is NULL, LoadFile
94 * sets the contents to "" rather than loading a file.
95 ************************************************************************/
103 Editor *pPad = (Editor *)client_data;
105 if (SaveUnsaved(pPad, FileNewCB)) {
109 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
110 TTmediaReply(pPad); /* reply/close ToolTalk media request */
113 if (pPad->fileStuff.fileName != (char *)NULL) {
114 XtFree(pPad->fileStuff.fileName);
115 pPad->fileStuff.fileName = (char *)NULL;
117 _DtTurnOnHourGlass(pPad->app_shell);
118 LoadFile(pPad, NULL);
119 ChangeMainWindowTitle(pPad);
120 _DtTurnOffHourGlass(pPad->app_shell);
124 /************************************************************************
125 * FileOpenCB - callback assigned to "File" menu "Open..." button
126 ************************************************************************/
134 Editor *pPad = (Editor *)client_data;
135 FileStuff *pStuff = &pPad->fileStuff;
137 if (SaveUnsaved(pPad, FileOpenCB)) {
141 /* ToolTalk media requests are replied to (and closed) in FileOpenOkCB */
143 /* -----> set FSB title passed GetFileName */
144 if(pStuff->openTitle == (XmString)NULL) {
147 strcpy(buf, DialogTitle(pPad));
148 strcat(buf, (char *)GETMESSAGE(4, 1, "Open a File"));
149 pStuff->openTitle = XmStringCreateLocalized(buf);
152 /* -----> obtain the name of the file to open (via a Xm file selection box)
153 * and load its contents (via FileOpenOkCB) to the Editor widget */
154 pStuff->pendingFileFunc = FileOpenOkCB; /* FSB XmNokCallback */
155 pStuff->pendingFileHelpFunc = HelpOpenDialogCB; /* FSB XmNhelpCallback */
156 GetFileName(pPad, pStuff->openTitle, OPEN);
160 /************************************************************************
161 * FileIncludeCB - callback assigned to "File" menu "Include..." button
162 ************************************************************************/
170 Editor *pPad = (Editor *)client_data;
171 FileStuff *pStuff = &pPad->fileStuff;
173 if (pStuff->includeTitle == (XmString)NULL) {
176 strcpy(buf, DialogTitle(pPad));
177 strcat(buf, (char *)GETMESSAGE(4, 3, "Include a File"));
178 pStuff->includeTitle = XmStringCreateLocalized(buf);
180 pPad->fileStuff.pendingFileFunc = IncludeFile;
181 pPad->fileStuff.pendingFileHelpFunc = HelpIncludeDialogCB;
182 GetFileName(pPad, pStuff->includeTitle, INCLUDE);
186 /************************************************************************
187 * FileSaveCB - callback assigned to "File" menu "Save" button and to the
188 * AskIfSave dialog's "OK" button (which is displayed when there are
189 * unsaved changes when switching to a new file/buffer).
192 ************************************************************************/
199 Editor *pPad = (Editor *)client_data;
201 DtEditorErrorCode errorCode;
202 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
203 pPad->fileStuff.saveWithNewlines == True;
206 if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName) { /* filename? */
207 /* -----> if called directly from [Save] menu and word wrap is on,
208 * display Save dialog so that saveWithNewlines can be set */
209 if (pPad->xrdb.wordWrap &&
210 !pPad->fileStuff.pendingFileFunc && !pPad->ttSaveReq.contract) {
212 pPad->fileStuff.pendingFileFunc = FileSaveCB;
215 _DtTurnOnHourGlass(pPad->app_shell);
216 errorCode = DtEditorSaveContentsToFile(
218 pPad->fileStuff.fileName,
219 True, /* overwrite existing file */
220 addNewlines, /* replace soft line feeds? */
221 True); /* mark contents as saved */
222 _DtTurnOffHourGlass(pPad->app_shell);
223 if (errorCode != DtEDITOR_NO_ERRORS) {
224 PostSaveError(pPad, pPad->fileStuff.fileName, errorCode);
225 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
226 TTfailPendingSave(pPad);
229 if (pPad->ttEditReq.contract) {
230 /* ZZZ -----> Create and send Saved notice */
231 m = ttdt_file_notice(
232 pPad->ttEditReq.contract, /* context */
234 TT_SESSION, /* Tt_scope */
235 pPad->fileStuff.fileName, /* msg file name */
236 True); /* send & destroy */
238 if (pPad->ttSaveReq.contract) {
239 if (! pPad->ttEditReq.contract) {
240 TTfailPendingSave(pPad);
242 tt_message_reply(pPad->ttSaveReq.contract);
243 tttk_message_destroy(pPad->ttSaveReq.contract);
246 } else { /* no fileName associated with current text */
247 if (pPad->ttEditReq.contract) {
248 if (pPad->ttEditReq.contents) {
249 if (TTmediaDepositContents(pPad) != 0) {
250 if (pPad->fileStuff.pendingFileFunc == FileExitCB) {
251 TTfailPendingQuit(pPad);
253 TTfailPendingSave(pPad);
254 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
255 return; /* deposit failed */
257 } else { /* TT request without fileName and contents */
258 FileSaveAsCB(w, client_data, call_data);
261 if (pPad->ttSaveReq.contract) {
262 tt_message_reply(pPad->ttSaveReq.contract);
263 tttk_message_destroy(pPad->ttSaveReq.contract);
265 } else { /* non-TT request and no file name */
266 if (pPad->ttSaveReq.contract) {
267 TTfailPendingSave(pPad);
269 FileSaveAsCB(w, client_data, call_data);
275 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void (*)())NULL) {
276 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
277 if (pFunc != FileSaveCB) {
278 (*pFunc)(w, client_data, call_data);
285 /************************************************************************
286 * FileSaveAsCB - callback assigned to "File" menu "SaveAs..." button
287 ************************************************************************/
294 Editor *pPad = (Editor *)client_data;
295 SaveAs *pSaveAs = &pPad->fileStuff.fileWidgets.saveAs;
298 if (!pSaveAs->saveAs_form) {
299 CreateSaveAsDialog(pPad);
300 XtManageChild (pSaveAs->saveAs_form);
302 * XXX - Should be dealing with the FSB instead of the text field directly.
303 * Also, should be setting an XmString, rather than a char *
305 textField = XmFileSelectionBoxGetChild(
306 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
308 XmTextFieldSetString(textField, "");
310 XtManageChild (pSaveAs->saveAs_form);
311 textField = XmFileSelectionBoxGetChild(
312 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
316 SetSaveAsDirAndFile(pPad); /* seed the SaveAs FSB dir and file fields */
318 /* Force the focus to the text field */
319 XmProcessTraversal(textField, XmTRAVERSE_CURRENT);
320 XSync(pPad->display, 0);
322 _DtTurnOffHourGlass(pPad->app_shell);
326 extern Boolean ActionDBInitialized; /* declared in main.c */
329 /************************************************************************
330 * PrintActionCB - callback assigned to "File" menu "Print" button
331 ************************************************************************/
335 DtActionInvocationID actionID,
336 XtPointer client_data,
337 DtActionArg *actionArgp,
339 DtActionStatus actionStatus)
341 Editor *pPad = (Editor *) client_data;
342 switch ((DtActionStatus) actionStatus) {
343 case DtACTION_INVOKED:
344 case DtACTION_STATUS_UPDATE:
347 case DtACTION_FAILED:
348 case DtACTION_CANCELED:
350 /* XtSetSensitive(pPad->app_shell, True); */
351 _DtTurnOffHourGlass(pPad->app_shell);
357 /************************************************************************
358 * FilePrintCB - callback assigned to "File" menu "Print" button
359 ************************************************************************/
367 Editor *pPad = (Editor *) client_data;
368 DtActionArg *actionArgp = (DtActionArg *) XtCalloc(2,sizeof(DtActionArg));
369 DtActionInvocationID actionID;
370 char *pr_name = (char *) NULL, *user_name;
371 DtEditorErrorCode errorCode;
373 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
374 pPad->fileStuff.saveWithNewlines == True;
376 _DtTurnOnHourGlass(pPad->app_shell);
377 /* -----> Disallow keyboard, button, motion, window enter/leave & focus
378 * events till print (dialog) action is done
379 * XtSetSensitive(pPad->app_shell, False);
382 /* -----> Get a place to temporarily write the text */
383 if ((pr_name = GetTempFile()) == (char *)NULL) {
384 _DtTurnOffHourGlass(pPad->app_shell);
385 Warning(pPad, ((char *)
386 GETMESSAGE(4, 5, "Unable to create a temporary file.")), XmDIALOG_ERROR);
390 /* -----> Write the contents to the temp file */
391 errorCode = DtEditorSaveContentsToFile(
394 True, /* overwrite existing file */
395 addNewlines, /* replace soft line feeds? */
396 False); /* don't mark contents as saved */
397 if (errorCode != SUCCESS) { /* this should never occur */
398 _DtTurnOffHourGlass(pPad->app_shell);
399 PostSaveError(pPad, pr_name, errorCode);
403 /* -----> Load the action database */
404 if (! ActionDBInitialized) {
405 StartDbUpdate( (XtPointer) NULL );
406 /* register interest in Action DB changes (for printing) */
407 DtDbReloadNotify( StartDbUpdate, (XtPointer) NULL );
410 /* -----> Determine the name the user will see in the Print dialog */
411 if (pPad->ttEditReq.contract &&
412 (pPad->ttEditReq.docName && *pPad->ttEditReq.docName)) {
413 user_name = strdup(pPad->ttEditReq.docName);
414 } else if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName) {
415 user_name = strdup(pPad->fileStuff.fileName);
417 user_name = strdup(UNNAMED_TITLE_P);
420 /* ----> Setup the action arguments - one for the filename as known by
421 * the user (Arg_1) and one for the temporary print file (Arg_2).
422 * PRINT_DTPAD_TEMPFILE does something like:
423 * /usr/dt/bin/dtlp -u %(String)Arg_2% -e %(File)Arg_1%
424 * dtlp displays a dialog to gather lp paramters and then prints
425 * the file. The -e says to remove the temporary file after it
426 * it has been passed to lp. */
427 actionArgp[0].argClass = DtACTION_FILE;
428 actionArgp[0].u.file.name = pr_name;
429 actionArgp[1].argClass = DtACTION_FILE;
430 actionArgp[1].u.file.name = user_name;
432 /* XXX - Try this after everything's working - don't directly output to
433 * a temp file but to a buffer and pass the buffer to the action
434 * and let the action automatically create/remove the temp file.
435 * This'll require a new action w/o -e.
436 * actionArgp[0].argClass = DtACTION_BUFFER;
437 * actionArgp[0].u.buffer.bp = (void *) buffer;
438 * actionArgp[0].u.buffer.size = strlen(buffer;
439 * actionArgp[0].u.buffer.type = TEXT;
440 * actionArgp[0].u.buffer.writable = False;
443 /* XXX - Also, may want to set XtNsensitive to False on pPad->app_shell
444 * and turn it back on in PrintActionCB() when it receives a
445 * DtACTION_DONE status */
446 /* ----> Invoke the print action */
447 actionID = DtActionInvoke(pPad->app_shell,
448 "PRINT_DTPAD_TEMPFILE", /* action */
449 actionArgp, 2, /* action arguments & count */
450 (char *) NULL, /* terminal options */
451 (char *) NULL, /* execution host */
452 (char *) NULL, /* context dir */
453 False, /* no "use indicator" */
454 PrintActionCB, /* action callback */
455 (XtPointer) pPad); /* callback client data */
460 /* _DtTurnOffHourGlass(pPad->app_shell); this is done in PrintActionCB */
466 /************************************************************************
467 * FileDoXpPrint - procedure doing the work of the XpPrint callbacks
468 ************************************************************************/
470 static void FileDoXpPrint(Editor *pPad, Boolean silent)
474 DtActionArg *actionArgp = (DtActionArg *) XtCalloc(2,sizeof(DtActionArg));
475 DtActionInvocationID actionID;
476 DtEditorErrorCode errorCode;
478 char *pr_name = (char *) NULL, *user_name;
480 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
481 pPad->fileStuff.saveWithNewlines == True;
483 _DtTurnOnHourGlass(pPad->app_shell);
484 /* -----> Disallow keyboard, button, motion, window enter/leave & focus
485 * events till print (dialog) action is done
486 * XtSetSensitive(pPad->app_shell, False);
489 /* -----> Get a place to temporarily write the text */
490 if ((pr_name = GetTempFile()) == (char *)NULL) {
491 _DtTurnOffHourGlass(pPad->app_shell);
492 Warning(pPad, ((char *)
493 GETMESSAGE(4, 5, "Unable to create a temporary file.")), XmDIALOG_ERROR);
497 /* -----> Write the contents to the temp file */
498 errorCode = DtEditorSaveContentsToFile(
501 True, /* overwrite existing file */
502 addNewlines, /* replace soft line feeds? */
503 False); /* don't mark contents as saved */
504 if (errorCode != SUCCESS) { /* this should never occur */
505 _DtTurnOffHourGlass(pPad->app_shell);
506 PostSaveError(pPad, pr_name, errorCode);
510 /* -----> Determine the name the user will see in the Print dialog */
511 if (pPad->ttEditReq.contract &&
512 (pPad->ttEditReq.docName && *pPad->ttEditReq.docName)) {
513 user_name = strdup(pPad->ttEditReq.docName);
514 } else if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName) {
515 user_name = strdup(pPad->fileStuff.fileName);
517 user_name = strdup(UNNAMED_TITLE_P);
520 /* ----> XPPRINT: Create and execute a print job. */
521 pJob = PrintJobCreate(user_name, pr_name, silent, pPad);
522 PrintJobExecute(pJob);
527 _DtTurnOffHourGlass(pPad->app_shell);
530 /************************************************************************
531 * FileXpPrintCB - callback assigned to "File" menu "Print..." button
532 ************************************************************************/
540 Editor *pPad = (Editor *) client_data;
541 FileDoXpPrint(pPad, FALSE);
545 /************************************************************************
546 * FileExitCB - callback assigned to "File" menu "Close" button
547 ************************************************************************/
555 Editor *pPad = (Editor *)client_data;
557 if (SaveUnsaved(pPad, FileExitCB)) {
559 * If SaveUnsaved() returns True, don't close the window at this
562 * 1) a dialog has been posted which needs to be responded to
563 * (and pendingFileFunc has been set to FileExitCB so that
564 * this function will be resumed after the response) or
565 * 2) an error has occurred (in which case we abort the exit operation,
566 * failing the TTDT_QUIT request if it initiated the exit).
568 if (pPad->fileStuff.pendingFileFunc != FileExitCB) { /* error occurred */
569 TTfailPendingQuit(pPad);
574 if (pPad->numPendingTasks > 0)
579 GETMESSAGE(14, 20, "Close pending: waiting for task to terminate ...");
580 SetStatusMessage(pPad, msg);
582 if (pPad->fileExitWorkprocID == 0)
583 pPad->fileExitWorkprocID = XtAppAddWorkProc(
588 FileExitWP((XtPointer) pPad);
592 /************************************************************************
593 * FileExitWP - workproc called from FileExitCB
594 ************************************************************************/
597 FileExitWP(XtPointer client_data)
599 Editor *pPad = (Editor *)client_data;
602 if (pPad->numPendingTasks > 0)
605 if (pPad->fileExitWorkprocID != 0)
607 XtRemoveWorkProc(pPad->fileExitWorkprocID);
608 pPad->fileExitWorkprocID = 0;
611 if (pPad->ttQuitReq.contract) { /* reply to ToolTalk Quit request */
612 status = tt_message_reply(pPad->ttQuitReq.contract);
613 status = tttk_message_destroy(pPad->ttQuitReq.contract);
616 if (pPad->ttEditReq.contract) {
617 TTmediaReply(pPad); /* reply/close ToolTalk Edit/Display request */
620 if (pPad->xrdb.standAlone) {
621 exit(pPad->confirmStuff.confirmationStatus);
626 UnmanageAllDialogs(pPad);
627 XtSetMappedWhenManaged(pPad->app_shell, False);
628 XmImUnregister(pPad->editor);
629 XtPopdown(pPad->app_shell);
630 XWithdrawWindow(pPad->display, XtWindow(pPad->app_shell),
631 XDefaultScreen(pPad->display));
632 XFlush(pPad->display);
634 /* -----> Send "DONE" notice if dealing with a requestor dtpad */
635 /* if (!pPad->ttEditReq.contract && pPad->xrdb.blocking) { */
636 /* char numBuf[10]; */
637 /* sprintf(numBuf, "%d", pPad->confirmStuff.confirmationStatus); */
638 /* _DtSendSuccessNotification( */
640 /* (DtString) NULL, */
641 /* (DtString) DTPAD_DONE, */
642 /* pPad->blockChannel, numBuf, NULL); */
645 if (numActivePads == 0 && pPad->xrdb.exitOnLastClose) {
646 exit(pPad->confirmStuff.confirmationStatus);
650 * If we're going to remain around, clean up Pad for its next use.
651 * This speeds up opening a cached Pad at the expense of cycles at
652 * close time. Perception is reality.
655 /* -----> clear ToolTalk message info */
656 TTresetQuitArgs(pPad);
657 pPad->ttEditReq.contract = 0;
658 if (pPad->ttEditReq.msg_id != (char *)NULL) {
659 XtFree(pPad->ttEditReq.msg_id);
660 pPad->ttEditReq.msg_id = (char *)NULL;
662 if (pPad->ttEditReq.vtype != (char *)NULL) {
663 XtFree(pPad->ttEditReq.vtype);
664 pPad->ttEditReq.vtype = (char *)NULL;
666 if (pPad->ttEditReq.fileName != (char *)NULL) {
667 XtFree(pPad->ttEditReq.fileName);
668 pPad->ttEditReq.fileName = (char *)NULL;
670 if (pPad->ttEditReq.docName != (char *)NULL) {
671 XtFree(pPad->ttEditReq.docName);
672 pPad->ttEditReq.docName = (char *)NULL;
674 if (pPad->ttEditReq.savePattern) {
675 tt_pattern_destroy(pPad->ttEditReq.savePattern);
676 pPad->ttEditReq.savePattern = NULL;
679 if (pPad->dialogTitle != (char *)NULL) {
680 XtFree(pPad->dialogTitle);
681 pPad->dialogTitle = NULL;
684 pPad->saveRestore = False;
686 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
687 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
688 pPad->fileStuff.fileExists = False;
689 pPad->fileStuff.saveWithNewlines = True;
690 pPad->fileStuff.readOnly = False;
691 if (pPad->fileStuff.fileName != (char *) NULL) {
692 XtFree(pPad->fileStuff.fileName);
693 pPad->fileStuff.fileName = (char *) NULL;
695 if (pPad->fileStuff.netfile != (char *) NULL) {
696 tt_free(pPad->fileStuff.netfile);
697 pPad->fileStuff.netfile = (char *) NULL;
700 /* -----> Clear contents, undo, find/change, format and message area */
701 DtEditorReset(pPad->editor);
703 /* -----> Reset resources to server's initial resource state */
704 RestoreInitialServerResources(pPad);
706 /* -----> Set iconic state to false */
707 pPad->iconic = False;
709 /* -----> Set app shell geo (pixels), resize hints, position & size hints */
712 /* -----> Clear director "seed" in SaveAs FSB */
713 if (pPad->fileStuff.fileWidgets.saveAs.saveAs_form != (Widget)NULL) {
714 Widget textField = XmFileSelectionBoxGetChild(
715 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
717 XmTextFieldSetString(textField, "");
724 /************************************************************************
725 * oldFileExitCB - callback assigned to "File" menu "Close" button
726 ************************************************************************/
734 Editor *pPad = (Editor *)client_data;
737 if (SaveUnsaved(pPad, FileExitCB)) {
739 * If SaveUnsaved() returns True, don't close the window at this
742 * 1) a dialog has been posted which needs to be responded to
743 * (and pendingFileFunc has been set to FileExitCB so that
744 * this function will be resumed after the response) or
745 * 2) an error has occurred (in which case we abort the exit operation,
746 * failing the TTDT_QUIT request if it initiated the exit).
748 if (pPad->fileStuff.pendingFileFunc != FileExitCB) { /* error occurred */
749 TTfailPendingQuit(pPad);
754 if (pPad->ttQuitReq.contract) { /* reply to ToolTalk Quit request */
755 status = tt_message_reply(pPad->ttQuitReq.contract);
756 status = tttk_message_destroy(pPad->ttQuitReq.contract);
759 if (pPad->ttEditReq.contract) {
760 TTmediaReply(pPad); /* reply/close ToolTalk Edit/Display request */
763 if (pPad->xrdb.standAlone) {
764 exit(pPad->confirmStuff.confirmationStatus);
769 UnmanageAllDialogs(pPad);
770 XtSetMappedWhenManaged(pPad->app_shell, False);
771 XmImUnregister(pPad->editor);
772 XtPopdown(pPad->app_shell);
773 XWithdrawWindow(pPad->display, XtWindow(pPad->app_shell),
774 XDefaultScreen(pPad->display));
775 XFlush(pPad->display);
777 /* -----> Send "DONE" notice if dealing with a requestor dtpad */
778 /* if (!pPad->ttEditReq.contract && pPad->xrdb.blocking) { */
779 /* char numBuf[10]; */
780 /* sprintf(numBuf, "%d", pPad->confirmStuff.confirmationStatus); */
781 /* _DtSendSuccessNotification( */
783 /* (DtString) NULL, */
784 /* (DtString) DTPAD_DONE, */
785 /* pPad->blockChannel, numBuf, NULL); */
788 if (numActivePads == 0 && pPad->xrdb.exitOnLastClose) {
789 exit(pPad->confirmStuff.confirmationStatus);
793 * If we're going to remain around, clean up Pad for its next use.
794 * This speeds up opening a cached Pad at the expense of cycles at
795 * close time. Perception is reality.
798 /* -----> clear ToolTalk message info */
799 TTresetQuitArgs(pPad);
800 pPad->ttEditReq.contract = 0;
801 if (pPad->ttEditReq.msg_id != (char *)NULL) {
802 XtFree(pPad->ttEditReq.msg_id);
803 pPad->ttEditReq.msg_id = (char *)NULL;
805 if (pPad->ttEditReq.vtype != (char *)NULL) {
806 XtFree(pPad->ttEditReq.vtype);
807 pPad->ttEditReq.vtype = (char *)NULL;
809 if (pPad->ttEditReq.fileName != (char *)NULL) {
810 XtFree(pPad->ttEditReq.fileName);
811 pPad->ttEditReq.fileName = (char *)NULL;
813 if (pPad->ttEditReq.docName != (char *)NULL) {
814 XtFree(pPad->ttEditReq.docName);
815 pPad->ttEditReq.docName = (char *)NULL;
817 if (pPad->ttEditReq.savePattern) {
818 tt_pattern_destroy(pPad->ttEditReq.savePattern);
819 pPad->ttEditReq.savePattern = NULL;
822 if (pPad->dialogTitle != (char *)NULL) {
823 XtFree(pPad->dialogTitle);
826 pPad->saveRestore = False;
828 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
829 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
830 pPad->fileStuff.fileExists = False;
831 pPad->fileStuff.saveWithNewlines = True;
832 pPad->fileStuff.readOnly = False;
833 if (pPad->fileStuff.fileName != (char *) NULL) {
834 XtFree(pPad->fileStuff.fileName);
835 pPad->fileStuff.fileName = (char *) NULL;
837 if (pPad->fileStuff.netfile != (char *) NULL) {
838 tt_free(pPad->fileStuff.netfile);
839 pPad->fileStuff.netfile = (char *) NULL;
842 /* -----> Clear contents, undo, find/change, format and message area */
843 DtEditorReset(pPad->editor);
845 /* -----> Reset resources to server's initial resource state */
846 RestoreInitialServerResources(pPad);
848 /* -----> Set iconic state to false */
849 pPad->iconic = False;
851 /* -----> Set app shell geo (pixels), resize hints, position & size hints */
854 /* -----> Clear director "seed" in SaveAs FSB */
855 if (pPad->fileStuff.fileWidgets.saveAs.saveAs_form != (Widget)NULL) {
856 Widget textField = XmFileSelectionBoxGetChild(
857 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
859 XmTextFieldSetString(textField, "");
864 /************************************************************************
865 * NoSaveCB - callback associated with the [No] button in the "Save changes
866 * to <file>?" PromptDialog created by CreateSaveWarning().
867 ************************************************************************/
874 Editor *pPad = (Editor *)client_data;
877 XtUnmanageChild(pPad->fileStuff.fileWidgets.select.save_warning);
880 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void(*)()) NULL) {
881 /* -----> don't clear the pending function if it calls SaveUnsaved() */
882 if (pPad->fileStuff.pendingFileFunc != FileNewCB &&
883 pPad->fileStuff.pendingFileFunc != FileOpenCB &&
884 pPad->fileStuff.pendingFileFunc != FileExitCB) {
885 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
887 if (pFunc != FileSaveCB) {
888 (*pFunc)(w, client_data, call_data);
894 /************************************************************************
895 * CancelFileSelectCB -
896 ************************************************************************/
904 Editor *pPad = (Editor *)client_data;
906 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
907 pPad->fileStuff.pendingFileHelpFunc = (void(*)()) NULL;
909 /* popdown the file selection box */
911 _DtTurnOffHourGlass(w);
912 _DtTurnOffHourGlass(pPad->app_shell);
916 /************************************************************************
917 * FileOpenOkCB - saves the name of a file to be opened and its directory,
918 * and then loads its contents into the DtEditor widget.
920 * This callback is assigned to the "Ok" button of the File
921 * Selection Box displayed by the callback, FileOpenCB() assigned
922 * to the "File" menu "Open" button.
923 ************************************************************************/
930 Editor *pPad = (Editor *)client_data;
931 FileStuff *pStuff = &pPad->fileStuff;
932 XmFileSelectionBoxCallbackStruct *cb = (XmFileSelectionBoxCallbackStruct *)
934 char *name = (char *) XtMalloc( sizeof(char) * cb->length + 1 );
937 _DtTurnOnHourGlass(pPad->app_shell);
938 _DtTurnOnHourGlass(w);
940 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
941 TTmediaReply(pPad); /* reply/close ToolTalk media request */
944 /* -----> Get the name of the directory and file.
945 * XXX - Eventually, it makes sense to store the name/etc. as an XmString
946 * rather than convert everything to a string. This will mean
947 * changing the pPad.fileName type.
948 * Additionally, we can get quit saving the text field ID and
949 * deal only with the FSB. */
951 name = (char *) _XmStringUngenerate(cb->value, NULL,
952 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
954 if (pStuff->fileName != (char *)NULL) {
955 XtFree(pStuff->fileName);
957 pStuff->fileName = name;
958 ExtractAndStoreDir(pPad, name, OPEN); /* store pPad->fileStuff.pathDir */
960 LoadFile(pPad, NULL); /* this is always successful */
961 ChangeMainWindowTitle(pPad);
963 CancelFileSelectCB(w, client_data, call_data);
967 /************************************************************************
968 * IncludeFile - obtains the name of a file to include (via a Xm FSB),
969 * parses the name and then
970 * inserts the file contents into the Dt Editor Widget (via LoadFile).
972 * This callback is assigned to the "Ok" button of the
973 * File Selection Box displayed by the callback,
974 * FileIncludeCB() assigned to the "File" menu "Include" button.
975 ************************************************************************/
982 Editor *pPad = (Editor *)client_data;
983 XmFileSelectionBoxCallbackStruct *cb = (XmFileSelectionBoxCallbackStruct *)
985 char *name = (char *) XtMalloc( sizeof(char) * cb->length + 1 );
988 _DtTurnOnHourGlass(pPad->app_shell);
989 _DtTurnOnHourGlass(w);
992 * Get the name of the file
994 * Eventually, it makes sense to store the name/etc. as an XmString
995 * rather than convert everything to a string. This will mean
996 * changing the pPad.fileName type.
997 * Additionally, we can get quit saving the text field ID and
998 * deal only with the FSB.
1001 name = (char *) _XmStringUngenerate(cb->value, NULL,
1002 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
1004 ExtractAndStoreDir(pPad, name, INCLUDE); /* store pPad->fileStuff.pathDir */
1006 LoadFile(pPad, name);
1007 ChangeMainWindowTitle(pPad);
1008 CancelFileSelectCB(w, client_data, call_data);
1009 if (name != (char *)NULL)
1014 /************************************************************************
1015 * SaveUnsaved - allows unsaved changes to be saved to the current file
1016 * or buffer. If the AskIfSave dialog is posted, sets the global
1017 * pendingFileFunc to the callingFunc so that the calling function
1018 * can be reentered to finish its processing.
1020 * Returns True if the calling function should not continue due to:
1022 * 1) some error condition (e.g. the file couldn't be saved), or
1023 * 2) a dialog has been posted which needs to be responded to
1024 * (pPad->fileStuff.pendingFileFunc will be set to the calling
1025 * function which may again be executed via a callback set on
1026 * the posted dialog)
1028 ************************************************************************/
1032 void (*callingFunc)() )
1034 Boolean addNewlines;
1038 * If there are unsaved changes, ask the user if they wish to
1039 * write them out. If saveOnClose is True, then just write it.
1041 if (DtEditorCheckForUnsavedChanges(pPad->editor)) {
1043 /* -----> If handling a "silent" TTDT_QUIT request, don't AskIfSave
1044 * and don't save any unsaved changes (TTDT_SAVE does this) */
1045 if (callingFunc == FileExitCB &&
1046 pPad->ttQuitReq.contract && pPad->ttQuitReq.silent) {
1047 if (pPad->ttQuitReq.force) {
1048 return False; /* close edit window */
1050 return True; /* don't close edit window */
1054 pPad->ttEditReq.returnBufContents = True;
1056 if ((pPad->xrdb.saveOnClose) &&
1057 (pPad->fileStuff.fileName && *pPad->fileStuff.fileName)) {
1058 DtEditorErrorCode errorCode;
1059 addNewlines = pPad->xrdb.wordWrap == True &&
1060 pPad->fileStuff.saveWithNewlines == True;
1061 _DtTurnOnHourGlass(pPad->app_shell);
1062 errorCode = DtEditorSaveContentsToFile(
1064 pPad->fileStuff.fileName,
1065 True, /* overwrite existing file */
1066 addNewlines, /* replace soft line feeds? */
1067 True); /* mark contents as saved */
1068 _DtTurnOffHourGlass(pPad->app_shell);
1069 if (errorCode != SUCCESS) {
1070 PostSaveError(pPad, pPad->fileStuff.fileName, errorCode);
1071 if (callingFunc == FileExitCB) {
1072 /* Set saveOnClose to False to force user to explicitly
1073 * choose to not save changes in order to exit. */
1074 pPad->xrdb.saveOnClose = False;
1076 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1077 return True; /* don't finish calling func */
1079 if (pPad->ttEditReq.contract) {
1080 /* ZZZ -----> Create and send Saved notice */
1081 m = ttdt_file_notice(
1082 pPad->ttEditReq.contract, /* context */
1083 TTDT_SAVED, /* op */
1084 TT_SESSION, /* Tt_scope */
1085 pPad->fileStuff.fileName, /* msg file name */
1086 True); /* send & destroy */
1090 if (callingFunc == pPad->fileStuff.pendingFileFunc) {
1091 /* We've already did AskIfSave but the user responded
1092 * "No" so lets not keep asking (NoSaveCB does not clear
1093 * pPad->fileStuff.pendingFileFunc). */
1094 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1095 pPad->ttEditReq.returnBufContents = False;
1097 /* AskIfSave assigns either FileSaveAsCB or FileSaveCB to the
1098 * the o.k. dialog button that it posts. These callbacks
1099 * execute pPad->fileStuff.pendingFileFunc when done. */
1100 pPad->fileStuff.pendingFileFunc = callingFunc;
1102 return True; /* don't finish calling func */
1105 } else { /* no unsaved contents */
1106 pPad->ttEditReq.returnBufContents = False;
1109 return False; /* finish calling funct */
1113 /************************************************************************
1115 ************************************************************************/
1120 XtPointer client_data,
1121 XtPointer call_data)
1123 Editor *pPad = (Editor *)client_data;
1125 if (w == pPad->fileStuff.fileWidgets.saveAs.toggleWidgets.with_newl ||
1126 w == pPad->fileStuff.fileWidgets.select.toggleWidgets.with_newl)
1127 pPad->fileStuff.saveWithNewlines = True;
1129 pPad->fileStuff.saveWithNewlines = False;
1133 /************************************************************************
1134 * SaveAsOkCB - save the file
1135 ************************************************************************/
1139 caddr_t client_data,
1142 Editor *pPad = (Editor *)client_data;
1143 SaveAs *pSaveAs = &pPad->fileStuff.fileWidgets.saveAs;
1145 Widget textField = XmFileSelectionBoxGetChild(
1146 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
1148 DtEditorErrorCode errorCode;
1150 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
1151 pPad->fileStuff.saveWithNewlines == True;
1152 Boolean overWrite, markSaved;
1153 XmFileSelectionBoxCallbackStruct *cb = (XmFileSelectionBoxCallbackStruct *)
1155 char *name = (char *) XtMalloc( sizeof(char) * cb->length + 1 );
1158 _DtTurnOnHourGlass(pPad->app_shell);
1159 _DtTurnOnHourGlass(pSaveAs->saveAs_form);
1161 /* -----> Get the "save as" file name */
1163 name = (char *) _XmStringUngenerate(cb->value, NULL,
1164 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
1166 pPad->fileStuff.savingName = name;
1167 ExtractAndStoreDir(pPad, name, OPEN); /* store pPad->fileStuff.pathDir */
1170 * Normally, we would first try writing without overwriting the file
1171 * in which case we would get an error if the file pre-exists and we
1172 * would post a dialog asking the user if they wished to overwrite it.
1173 * However, if the name of the file to save is the same as the file
1174 * being edited, the user opened the file and knows that it exists.
1175 * In this case we would overwrite it without presenting the overwrite
1178 if (strcmp(pPad->fileStuff.fileName, pPad->fileStuff.savingName) == 0) {
1179 overWrite = True; /* overwrite */
1181 overWrite = False; /* don't overwrite yet */
1184 /* -----> Don't mark the current contents as saved if saved to a
1185 * file different than the (to be) current file */
1186 if (! pPad->xrdb.nameChange &&
1187 pPad->fileStuff.fileName && /* allow for -noNameChange w/o a fileName */
1194 errorCode = DtEditorSaveContentsToFile(
1196 pPad->fileStuff.savingName,
1198 addNewlines, /* replace soft line feeds? */
1199 markSaved); /* mark contents as saved? */
1200 if (errorCode == DtEDITOR_WRITABLE_FILE) { /* file exists & not overwriting */
1201 PostAlreadyExistsDlg(pPad); /* save handled in AlrdyExistsOkCB */
1202 XtUnmanageChild (pSaveAs->saveAs_form);
1203 _DtTurnOffHourGlass(pSaveAs->saveAs_form);
1204 _DtTurnOffHourGlass(pPad->app_shell);
1207 if (errorCode != SUCCESS) {
1208 PostSaveError(pPad, pPad->fileStuff.savingName, errorCode);
1209 XtFree(pPad->fileStuff.savingName);
1210 pPad->fileStuff.savingName = (char *)NULL;
1211 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1213 if (pPad->ttEditReq.contract) {
1214 /* ZZZ -----> Create and send Saved notice */
1215 m = ttdt_file_notice(
1216 pPad->ttEditReq.contract, /* context */
1217 TTDT_SAVED, /* op */
1218 TT_SESSION, /* Tt_scope */
1219 pPad->fileStuff.savingName, /* msg file name */
1220 True); /* send & destroy */
1223 if (pPad->xrdb.nameChange == True) {
1224 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
1225 pPad->ttEditReq.returnBufContents = False; /* drop chgs w/o notice */
1226 TTmediaReply(pPad); /* reply/close ToolTalk media request */
1228 XtFree(pPad->fileStuff.fileName);
1229 pPad->fileStuff.fileName = pPad->fileStuff.savingName;
1230 ChangeMainWindowTitle(pPad);
1235 XtUnmanageChild (pSaveAs->saveAs_form);
1236 _DtTurnOffHourGlass(pSaveAs->saveAs_form);
1237 _DtTurnOffHourGlass(pPad->app_shell);
1238 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void (*)())NULL) {
1239 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1240 (*pFunc)(w, client_data, call_data);
1245 /************************************************************************
1246 * AlrdyExistsOkCB - the ok callback for a saveAs of a file which already
1247 * exists. Specifically, this routine:
1249 * - saves the current text to the file specified by
1250 * pPad->fileStuff.savingName
1251 * - if appropriate, resets the name of the current file
1252 * (pPad->fileStuff.fileName) to pPad->fileStuff.savingName and
1253 * frees pPad->fileStuff.savingName
1254 * - executes pPad->fileStuff.pendingFileFunc if specified
1256 ************************************************************************/
1260 caddr_t client_data,
1263 Editor *pPad = (Editor *)client_data;
1265 DtEditorErrorCode errorCode;
1266 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
1267 pPad->fileStuff.saveWithNewlines == True;
1271 _DtTurnOnHourGlass(pPad->app_shell);
1272 _DtTurnOnHourGlass(w);
1274 /* -----> Don't mark the current contents as saved if saved to a
1275 * file different than the (to be) current file */
1276 if (! pPad->xrdb.nameChange &&
1277 pPad->fileStuff.fileName && /* allow for -noNameChange w/o a fileName */
1278 (strcmp(pPad->fileStuff.fileName, pPad->fileStuff.savingName) != 0)) {
1284 errorCode = DtEditorSaveContentsToFile(
1286 pPad->fileStuff.savingName,
1287 True, /* overwrite existing file */
1288 addNewlines, /* replace soft line feeds? */
1289 markSaved); /* mark contents as saved? */
1291 XtUnmanageChild (w);
1292 _DtTurnOffHourGlass(w);
1293 _DtTurnOffHourGlass(pPad->app_shell);
1295 if (errorCode == SUCCESS) {
1296 if (pPad->ttEditReq.contract) {
1297 /* ZZZ -----> Create and send Saved notice */
1298 m = ttdt_file_notice(
1299 pPad->ttEditReq.contract, /* context */
1300 TTDT_SAVED, /* op */
1301 TT_SESSION, /* Tt_scope */
1302 pPad->fileStuff.savingName, /* msg file name */
1303 True); /* send & destroy */
1305 if (pPad->xrdb.nameChange == True) {
1306 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
1307 pPad->ttEditReq.returnBufContents = False; /* drop chgs w/o notice */
1308 TTmediaReply(pPad); /* reply/close ToolTalk media request */
1310 XtFree(pPad->fileStuff.fileName);
1311 pPad->fileStuff.fileName = pPad->fileStuff.savingName;
1312 ChangeMainWindowTitle(pPad);
1315 PostSaveError(pPad, pPad->fileStuff.savingName, errorCode);
1317 if (pPad->fileStuff.savingName != pPad->fileStuff.fileName)
1318 XtFree(pPad->fileStuff.savingName);
1319 pPad->fileStuff.savingName = (char *)NULL;
1321 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void (*)())NULL) {
1322 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1323 (*pFunc)(w, client_data, call_data);
1328 /************************************************************************
1329 * SaveAsCancelCB - Unmanage the SaveAs dialog
1330 ************************************************************************/
1335 caddr_t client_data,
1338 Editor *pPad = (Editor *) client_data;
1340 XtUnmanageChild ((Widget) pPad->fileStuff.fileWidgets.saveAs.saveAs_form);
1341 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
1342 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
1346 /************************************************************************
1347 * AlrdyExistsCancelCB - Unmanage the AlreadyExists dialog
1348 ************************************************************************/
1351 AlrdyExistsCancelCB(
1353 caddr_t client_data,
1356 Editor *pPad = (Editor *)client_data;
1357 XtUnmanageChild ((Widget) pPad->fileStuff.fileWidgets.saveAs.alrdy_exist);
1358 XtFree(pPad->fileStuff.savingName);
1359 pPad->fileStuff.savingName = (char *) NULL;
1360 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
1361 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
1365 /************************************************************************
1366 * AskIfSaveCancelCB -
1367 ************************************************************************/
1372 caddr_t client_data,
1375 Editor *pPad = (Editor *)client_data;
1377 XtUnmanageChild ((Widget) pPad->fileStuff.fileWidgets.select.save_warning);
1378 if (pPad->fileStuff.pendingFileFunc == FileExitCB) {
1379 TTfailPendingQuit(pPad);
1381 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
1382 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;