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
23 /* $TOG: fileCB.c /main/13 1999/11/08 08:23:14 mgreess $ */
24 /**********************************<+>*************************************
25 ***************************************************************************
29 ** Project: DT dtpad, a memo maker type editor based on the Dt Editor
35 ** This file contains the callbacks for the "File" menu items.
36 ** There's some hair here, due to the nested nature of some of
37 ** the dialogs. The "New, "Open" and "Exit" callbacks can cause
38 ** the opening of a do-you-wish-to-save dialog, and we have to
39 ** remember how we got there. This is done through the use
40 ** of the pendingFileFunc field of the Editor struct.
42 *******************************************************************
43 ** (c) Copyright Hewlett-Packard Company, 1991. All rights are
44 ** reserved. Copying or other reproduction of this program
45 ** except for archival purposes is prohibited without prior
46 ** written consent of Hewlett-Packard Company.
47 ********************************************************************
49 ********************************************************************
50 ** (c) Copyright 1993, 1994 Hewlett-Packard Company
51 ** (c) Copyright 1993, 1994 International Business Machines Corp.
52 ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
53 ** (c) Copyright 1993, 1994 Novell, Inc.
54 ********************************************************************
57 **************************************************************************
58 **********************************<+>*************************************/
59 #include <Dt/DtpadM.h>
60 #include <Dt/Action.h>
62 #include <Xm/XmPrivate.h> /* _XmStringUngenerate */
66 extern int numActivePads; /* declared in main.c */
69 /************************************************************************
70 * Forward Declarations
71 ************************************************************************/
72 static void FileDoXpPrint(
75 static void FileOpenOkCB(
79 static void IncludeFile(
83 static Boolean SaveUnsaved(
85 void (*callingFunc)() );
86 static Boolean FileExitWP(
87 XtPointer client_data);
90 /************************************************************************
91 * FileCascadingCB - callback assigned to "File" menu to determine
92 * whether Save button in menu is labeled "Save" or "Save (needed)".
93 ************************************************************************/
101 Editor *pPad = (Editor *)client_data;
104 if (DtEditorCheckForUnsavedChanges(pPad->editor)) {
105 XtSetArg(al[0], XmNlabelString, pPad->fileStuff.saveNeededBtnLabel);
107 XtSetArg(al[0], XmNlabelString, pPad->fileStuff.saveBtnLabel);
109 XtSetValues(pPad->fileStuff.fileWidgets.saveBtn, al, 1);
114 /************************************************************************
115 * FileNewCB - callback assigned to "File" menu "New" button which
116 * saves the current text if it hasn't been saved and then calls
117 * LoadFile(). Since pPad->fileStuff.fileName is NULL, LoadFile
118 * sets the contents to "" rather than loading a file.
119 ************************************************************************/
127 Editor *pPad = (Editor *)client_data;
129 if (SaveUnsaved(pPad, FileNewCB)) {
133 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
134 TTmediaReply(pPad); /* reply/close ToolTalk media request */
137 if (pPad->fileStuff.fileName != (char *)NULL) {
138 XtFree(pPad->fileStuff.fileName);
139 pPad->fileStuff.fileName = (char *)NULL;
141 _DtTurnOnHourGlass(pPad->app_shell);
142 LoadFile(pPad, NULL);
143 ChangeMainWindowTitle(pPad);
144 _DtTurnOffHourGlass(pPad->app_shell);
148 /************************************************************************
149 * FileOpenCB - callback assigned to "File" menu "Open..." button
150 ************************************************************************/
158 Editor *pPad = (Editor *)client_data;
159 FileStuff *pStuff = &pPad->fileStuff;
161 if (SaveUnsaved(pPad, FileOpenCB)) {
165 /* ToolTalk media requests are replied to (and closed) in FileOpenOkCB */
167 /* -----> set FSB title passed GetFileName */
168 if(pStuff->openTitle == (XmString)NULL) {
171 strcpy(buf, DialogTitle(pPad));
172 strcat(buf, (char *)GETMESSAGE(4, 1, "Open a File"));
173 pStuff->openTitle = XmStringCreateLocalized(buf);
176 /* -----> obtain the name of the file to open (via a Xm file selection box)
177 * and load its contents (via FileOpenOkCB) to the Editor widget */
178 pStuff->pendingFileFunc = FileOpenOkCB; /* FSB XmNokCallback */
179 pStuff->pendingFileHelpFunc = HelpOpenDialogCB; /* FSB XmNhelpCallback */
180 GetFileName(pPad, pStuff->openTitle, OPEN);
184 /************************************************************************
185 * FileIncludeCB - callback assigned to "File" menu "Include..." button
186 ************************************************************************/
194 Editor *pPad = (Editor *)client_data;
195 FileStuff *pStuff = &pPad->fileStuff;
197 if (pStuff->includeTitle == (XmString)NULL) {
200 strcpy(buf, DialogTitle(pPad));
201 strcat(buf, (char *)GETMESSAGE(4, 3, "Include a File"));
202 pStuff->includeTitle = XmStringCreateLocalized(buf);
204 pPad->fileStuff.pendingFileFunc = IncludeFile;
205 pPad->fileStuff.pendingFileHelpFunc = HelpIncludeDialogCB;
206 GetFileName(pPad, pStuff->includeTitle, INCLUDE);
210 /************************************************************************
211 * FileSaveCB - callback assigned to "File" menu "Save" button and to the
212 * AskIfSave dialog's "OK" button (which is displayed when there are
213 * unsaved changes when switching to a new file/buffer).
216 ************************************************************************/
223 Editor *pPad = (Editor *)client_data;
225 DtEditorErrorCode errorCode;
226 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
227 pPad->fileStuff.saveWithNewlines == True;
230 if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName) { /* filename? */
231 /* -----> if called directly from [Save] menu and word wrap is on,
232 * display Save dialog so that saveWithNewlines can be set */
233 if (pPad->xrdb.wordWrap &&
234 !pPad->fileStuff.pendingFileFunc && !pPad->ttSaveReq.contract) {
236 pPad->fileStuff.pendingFileFunc = FileSaveCB;
239 _DtTurnOnHourGlass(pPad->app_shell);
240 errorCode = DtEditorSaveContentsToFile(
242 pPad->fileStuff.fileName,
243 True, /* overwrite existing file */
244 addNewlines, /* replace soft line feeds? */
245 True); /* mark contents as saved */
246 _DtTurnOffHourGlass(pPad->app_shell);
247 if (errorCode != DtEDITOR_NO_ERRORS) {
248 PostSaveError(pPad, pPad->fileStuff.fileName, errorCode);
249 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
250 TTfailPendingSave(pPad);
253 if (pPad->ttEditReq.contract) {
254 /* ZZZ -----> Create and send Saved notice */
255 m = ttdt_file_notice(
256 pPad->ttEditReq.contract, /* context */
258 TT_SESSION, /* Tt_scope */
259 pPad->fileStuff.fileName, /* msg file name */
260 True); /* send & destroy */
262 if (pPad->ttSaveReq.contract) {
263 if (! pPad->ttEditReq.contract) {
264 TTfailPendingSave(pPad);
266 tt_message_reply(pPad->ttSaveReq.contract);
267 tttk_message_destroy(pPad->ttSaveReq.contract);
270 } else { /* no fileName associated with current text */
271 if (pPad->ttEditReq.contract) {
272 if (pPad->ttEditReq.contents) {
273 if (TTmediaDepositContents(pPad) != 0) {
274 if (pPad->fileStuff.pendingFileFunc == FileExitCB) {
275 TTfailPendingQuit(pPad);
277 TTfailPendingSave(pPad);
278 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
279 return; /* deposit failed */
281 } else { /* TT request without fileName and contents */
282 FileSaveAsCB(w, client_data, call_data);
285 if (pPad->ttSaveReq.contract) {
286 tt_message_reply(pPad->ttSaveReq.contract);
287 tttk_message_destroy(pPad->ttSaveReq.contract);
289 } else { /* non-TT request and no file name */
290 if (pPad->ttSaveReq.contract) {
291 TTfailPendingSave(pPad);
293 FileSaveAsCB(w, client_data, call_data);
299 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void (*)())NULL) {
300 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
301 if (pFunc != FileSaveCB) {
302 (*pFunc)(w, client_data, call_data);
309 /************************************************************************
310 * FileSaveAsCB - callback assigned to "File" menu "SaveAs..." button
311 ************************************************************************/
318 Editor *pPad = (Editor *)client_data;
319 SaveAs *pSaveAs = &pPad->fileStuff.fileWidgets.saveAs;
322 if (!pSaveAs->saveAs_form) {
323 CreateSaveAsDialog(pPad);
324 XtManageChild (pSaveAs->saveAs_form);
326 * XXX - Should be dealing with the FSB instead of the text field directly.
327 * Also, should be setting an XmString, rather than a char *
329 textField = XmFileSelectionBoxGetChild(
330 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
332 XmTextFieldSetString(textField, "");
334 XtManageChild (pSaveAs->saveAs_form);
335 textField = XmFileSelectionBoxGetChild(
336 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
340 SetSaveAsDirAndFile(pPad); /* seed the SaveAs FSB dir and file fields */
342 /* Force the focus to the text field */
343 XmProcessTraversal(textField, XmTRAVERSE_CURRENT);
344 XSync(pPad->display, 0);
346 _DtTurnOffHourGlass(pPad->app_shell);
350 extern Boolean ActionDBInitialized; /* declared in main.c */
353 /************************************************************************
354 * PrintActionCB - callback assigned to "File" menu "Print" button
355 ************************************************************************/
359 DtActionInvocationID actionID,
360 XtPointer client_data,
361 DtActionArg *actionArgp,
363 DtActionStatus actionStatus)
365 Editor *pPad = (Editor *) client_data;
366 switch ((DtActionStatus) actionStatus) {
367 case DtACTION_INVOKED:
368 case DtACTION_STATUS_UPDATE:
371 case DtACTION_FAILED:
372 case DtACTION_CANCELED:
374 /* XtSetSensitive(pPad->app_shell, True); */
375 _DtTurnOffHourGlass(pPad->app_shell);
381 /************************************************************************
382 * FilePrintCB - callback assigned to "File" menu "Print" button
383 ************************************************************************/
391 Editor *pPad = (Editor *) client_data;
392 DtActionArg *actionArgp = (DtActionArg *) XtCalloc(2,sizeof(DtActionArg));
393 DtActionInvocationID actionID;
394 char *pr_name = (char *) NULL, *user_name;
395 DtEditorErrorCode errorCode;
397 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
398 pPad->fileStuff.saveWithNewlines == True;
400 _DtTurnOnHourGlass(pPad->app_shell);
401 /* -----> Disallow keyboard, button, motion, window enter/leave & focus
402 * events till print (dialog) action is done
403 * XtSetSensitive(pPad->app_shell, False);
406 /* -----> Get a place to temporarily write the text */
407 if ((pr_name = GetTempFile()) == (char *)NULL) {
408 _DtTurnOffHourGlass(pPad->app_shell);
409 Warning(pPad, ((char *)
410 GETMESSAGE(4, 5, "Unable to create a temporary file.")), XmDIALOG_ERROR);
414 /* -----> Write the contents to the temp file */
415 errorCode = DtEditorSaveContentsToFile(
418 True, /* overwrite existing file */
419 addNewlines, /* replace soft line feeds? */
420 False); /* don't mark contents as saved */
421 if (errorCode != SUCCESS) { /* this should never occur */
422 _DtTurnOffHourGlass(pPad->app_shell);
423 PostSaveError(pPad, pr_name, errorCode);
427 /* -----> Load the action database */
428 if (! ActionDBInitialized) {
429 StartDbUpdate( (XtPointer) NULL );
430 /* register interest in Action DB changes (for printing) */
431 DtDbReloadNotify( StartDbUpdate, (XtPointer) NULL );
434 /* -----> Determine the name the user will see in the Print dialog */
435 if (pPad->ttEditReq.contract &&
436 (pPad->ttEditReq.docName && *pPad->ttEditReq.docName)) {
437 user_name = strdup(pPad->ttEditReq.docName);
438 } else if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName) {
439 user_name = strdup(pPad->fileStuff.fileName);
441 user_name = strdup(UNNAMED_TITLE_P);
444 /* ----> Setup the action arguments - one for the filename as known by
445 * the user (Arg_1) and one for the temporary print file (Arg_2).
446 * PRINT_DTPAD_TEMPFILE does something like:
447 * /usr/dt/bin/dtlp -u %(String)Arg_2% -e %(File)Arg_1%
448 * dtlp displays a dialog to gather lp paramters and then prints
449 * the file. The -e says to remove the temporary file after it
450 * it has been passed to lp. */
451 actionArgp[0].argClass = DtACTION_FILE;
452 actionArgp[0].u.file.name = pr_name;
453 actionArgp[1].argClass = DtACTION_FILE;
454 actionArgp[1].u.file.name = user_name;
456 /* XXX - Try this after everything's working - don't directly output to
457 * a temp file but to a buffer and pass the buffer to the action
458 * and let the action automatically create/remove the temp file.
459 * This'll require a new action w/o -e.
460 * actionArgp[0].argClass = DtACTION_BUFFER;
461 * actionArgp[0].u.buffer.bp = (void *) buffer;
462 * actionArgp[0].u.buffer.size = strlen(buffer;
463 * actionArgp[0].u.buffer.type = TEXT;
464 * actionArgp[0].u.buffer.writable = False;
467 /* XXX - Also, may want to set XtNsensitive to False on pPad->app_shell
468 * and turn it back on in PrintActionCB() when it receives a
469 * DtACTION_DONE status */
470 /* ----> Invoke the print action */
471 actionID = DtActionInvoke(pPad->app_shell,
472 "PRINT_DTPAD_TEMPFILE", /* action */
473 actionArgp, 2, /* action arguments & count */
474 (char *) NULL, /* terminal options */
475 (char *) NULL, /* execution host */
476 (char *) NULL, /* context dir */
477 False, /* no "use indicator" */
478 PrintActionCB, /* action callback */
479 (XtPointer) pPad); /* callback client data */
484 /* _DtTurnOffHourGlass(pPad->app_shell); this is done in PrintActionCB */
490 /************************************************************************
491 * FileDoXpPrint - procedure doing the work of the XpPrint callbacks
492 ************************************************************************/
494 static void FileDoXpPrint(Editor *pPad, Boolean silent)
498 DtActionArg *actionArgp = (DtActionArg *) XtCalloc(2,sizeof(DtActionArg));
499 DtActionInvocationID actionID;
500 DtEditorErrorCode errorCode;
502 char *pr_name = (char *) NULL, *user_name;
504 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
505 pPad->fileStuff.saveWithNewlines == True;
507 _DtTurnOnHourGlass(pPad->app_shell);
508 /* -----> Disallow keyboard, button, motion, window enter/leave & focus
509 * events till print (dialog) action is done
510 * XtSetSensitive(pPad->app_shell, False);
513 /* -----> Get a place to temporarily write the text */
514 if ((pr_name = GetTempFile()) == (char *)NULL) {
515 _DtTurnOffHourGlass(pPad->app_shell);
516 Warning(pPad, ((char *)
517 GETMESSAGE(4, 5, "Unable to create a temporary file.")), XmDIALOG_ERROR);
521 /* -----> Write the contents to the temp file */
522 errorCode = DtEditorSaveContentsToFile(
525 True, /* overwrite existing file */
526 addNewlines, /* replace soft line feeds? */
527 False); /* don't mark contents as saved */
528 if (errorCode != SUCCESS) { /* this should never occur */
529 _DtTurnOffHourGlass(pPad->app_shell);
530 PostSaveError(pPad, pr_name, errorCode);
534 /* -----> Determine the name the user will see in the Print dialog */
535 if (pPad->ttEditReq.contract &&
536 (pPad->ttEditReq.docName && *pPad->ttEditReq.docName)) {
537 user_name = strdup(pPad->ttEditReq.docName);
538 } else if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName) {
539 user_name = strdup(pPad->fileStuff.fileName);
541 user_name = strdup(UNNAMED_TITLE_P);
544 /* ----> XPPRINT: Create and execute a print job. */
545 pJob = PrintJobCreate(user_name, pr_name, silent, pPad);
546 PrintJobExecute(pJob);
551 _DtTurnOffHourGlass(pPad->app_shell);
554 /************************************************************************
555 * FileXpPrintCB - callback assigned to "File" menu "Print..." button
556 ************************************************************************/
564 Editor *pPad = (Editor *) client_data;
565 FileDoXpPrint(pPad, FALSE);
569 /************************************************************************
570 * FileExitCB - callback assigned to "File" menu "Close" button
571 ************************************************************************/
579 Editor *pPad = (Editor *)client_data;
581 if (SaveUnsaved(pPad, FileExitCB)) {
583 * If SaveUnsaved() returns True, don't close the window at this
586 * 1) a dialog has been posted which needs to be responded to
587 * (and pendingFileFunc has been set to FileExitCB so that
588 * this function will be resumed after the response) or
589 * 2) an error has occurred (in which case we abort the exit operation,
590 * failing the TTDT_QUIT request if it initiated the exit).
592 if (pPad->fileStuff.pendingFileFunc != FileExitCB) { /* error occurred */
593 TTfailPendingQuit(pPad);
598 if (pPad->numPendingTasks > 0)
603 GETMESSAGE(14, 20, "Close pending: waiting for task to terminate ...");
604 SetStatusMessage(pPad, msg);
606 if (pPad->fileExitWorkprocID == 0)
607 pPad->fileExitWorkprocID = XtAppAddWorkProc(
612 FileExitWP((XtPointer) pPad);
616 /************************************************************************
617 * FileExitWP - workproc called from FileExitCB
618 ************************************************************************/
621 FileExitWP(XtPointer client_data)
623 Editor *pPad = (Editor *)client_data;
626 if (pPad->numPendingTasks > 0)
629 if (pPad->fileExitWorkprocID != 0)
631 XtRemoveWorkProc(pPad->fileExitWorkprocID);
632 pPad->fileExitWorkprocID = 0;
635 if (pPad->ttQuitReq.contract) { /* reply to ToolTalk Quit request */
636 status = tt_message_reply(pPad->ttQuitReq.contract);
637 status = tttk_message_destroy(pPad->ttQuitReq.contract);
640 if (pPad->ttEditReq.contract) {
641 TTmediaReply(pPad); /* reply/close ToolTalk Edit/Display request */
644 if (pPad->xrdb.standAlone) {
645 exit(pPad->confirmStuff.confirmationStatus);
650 UnmanageAllDialogs(pPad);
651 XtSetMappedWhenManaged(pPad->app_shell, False);
652 XmImUnregister(pPad->editor);
653 XtPopdown(pPad->app_shell);
654 XWithdrawWindow(pPad->display, XtWindow(pPad->app_shell),
655 XDefaultScreen(pPad->display));
656 XFlush(pPad->display);
658 /* -----> Send "DONE" notice if dealing with a requestor dtpad */
659 /* if (!pPad->ttEditReq.contract && pPad->xrdb.blocking) { */
660 /* char numBuf[10]; */
661 /* sprintf(numBuf, "%d", pPad->confirmStuff.confirmationStatus); */
662 /* _DtSendSuccessNotification( */
664 /* (DtString) NULL, */
665 /* (DtString) DTPAD_DONE, */
666 /* pPad->blockChannel, numBuf, NULL); */
669 if (numActivePads == 0 && pPad->xrdb.exitOnLastClose) {
670 exit(pPad->confirmStuff.confirmationStatus);
674 * If we're going to remain around, clean up Pad for its next use.
675 * This speeds up opening a cached Pad at the expense of cycles at
676 * close time. Perception is reality.
679 /* -----> clear ToolTalk message info */
680 TTresetQuitArgs(pPad);
681 pPad->ttEditReq.contract = 0;
682 if (pPad->ttEditReq.msg_id != (char *)NULL) {
683 XtFree(pPad->ttEditReq.msg_id);
684 pPad->ttEditReq.msg_id = (char *)NULL;
686 if (pPad->ttEditReq.vtype != (char *)NULL) {
687 XtFree(pPad->ttEditReq.vtype);
688 pPad->ttEditReq.vtype = (char *)NULL;
690 if (pPad->ttEditReq.fileName != (char *)NULL) {
691 XtFree(pPad->ttEditReq.fileName);
692 pPad->ttEditReq.fileName = (char *)NULL;
694 if (pPad->ttEditReq.docName != (char *)NULL) {
695 XtFree(pPad->ttEditReq.docName);
696 pPad->ttEditReq.docName = (char *)NULL;
698 if (pPad->ttEditReq.savePattern) {
699 tt_pattern_destroy(pPad->ttEditReq.savePattern);
700 pPad->ttEditReq.savePattern = NULL;
703 if (pPad->dialogTitle != (char *)NULL) {
704 XtFree(pPad->dialogTitle);
705 pPad->dialogTitle = NULL;
708 pPad->saveRestore = False;
710 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
711 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
712 pPad->fileStuff.fileExists = False;
713 pPad->fileStuff.saveWithNewlines = True;
714 pPad->fileStuff.readOnly = False;
715 if (pPad->fileStuff.fileName != (char *) NULL) {
716 XtFree(pPad->fileStuff.fileName);
717 pPad->fileStuff.fileName = (char *) NULL;
719 if (pPad->fileStuff.netfile != (char *) NULL) {
720 tt_free(pPad->fileStuff.netfile);
721 pPad->fileStuff.netfile = (char *) NULL;
724 /* -----> Clear contents, undo, find/change, format and message area */
725 DtEditorReset(pPad->editor);
727 /* -----> Reset resources to server's initial resource state */
728 RestoreInitialServerResources(pPad);
730 /* -----> Set iconic state to false */
731 pPad->iconic = False;
733 /* -----> Set app shell geo (pixels), resize hints, position & size hints */
736 /* -----> Clear director "seed" in SaveAs FSB */
737 if (pPad->fileStuff.fileWidgets.saveAs.saveAs_form != (Widget)NULL) {
738 Widget textField = XmFileSelectionBoxGetChild(
739 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
741 XmTextFieldSetString(textField, "");
748 /************************************************************************
749 * oldFileExitCB - callback assigned to "File" menu "Close" button
750 ************************************************************************/
758 Editor *pPad = (Editor *)client_data;
761 if (SaveUnsaved(pPad, FileExitCB)) {
763 * If SaveUnsaved() returns True, don't close the window at this
766 * 1) a dialog has been posted which needs to be responded to
767 * (and pendingFileFunc has been set to FileExitCB so that
768 * this function will be resumed after the response) or
769 * 2) an error has occurred (in which case we abort the exit operation,
770 * failing the TTDT_QUIT request if it initiated the exit).
772 if (pPad->fileStuff.pendingFileFunc != FileExitCB) { /* error occurred */
773 TTfailPendingQuit(pPad);
778 if (pPad->ttQuitReq.contract) { /* reply to ToolTalk Quit request */
779 status = tt_message_reply(pPad->ttQuitReq.contract);
780 status = tttk_message_destroy(pPad->ttQuitReq.contract);
783 if (pPad->ttEditReq.contract) {
784 TTmediaReply(pPad); /* reply/close ToolTalk Edit/Display request */
787 if (pPad->xrdb.standAlone) {
788 exit(pPad->confirmStuff.confirmationStatus);
793 UnmanageAllDialogs(pPad);
794 XtSetMappedWhenManaged(pPad->app_shell, False);
795 XmImUnregister(pPad->editor);
796 XtPopdown(pPad->app_shell);
797 XWithdrawWindow(pPad->display, XtWindow(pPad->app_shell),
798 XDefaultScreen(pPad->display));
799 XFlush(pPad->display);
801 /* -----> Send "DONE" notice if dealing with a requestor dtpad */
802 /* if (!pPad->ttEditReq.contract && pPad->xrdb.blocking) { */
803 /* char numBuf[10]; */
804 /* sprintf(numBuf, "%d", pPad->confirmStuff.confirmationStatus); */
805 /* _DtSendSuccessNotification( */
807 /* (DtString) NULL, */
808 /* (DtString) DTPAD_DONE, */
809 /* pPad->blockChannel, numBuf, NULL); */
812 if (numActivePads == 0 && pPad->xrdb.exitOnLastClose) {
813 exit(pPad->confirmStuff.confirmationStatus);
817 * If we're going to remain around, clean up Pad for its next use.
818 * This speeds up opening a cached Pad at the expense of cycles at
819 * close time. Perception is reality.
822 /* -----> clear ToolTalk message info */
823 TTresetQuitArgs(pPad);
824 pPad->ttEditReq.contract = 0;
825 if (pPad->ttEditReq.msg_id != (char *)NULL) {
826 XtFree(pPad->ttEditReq.msg_id);
827 pPad->ttEditReq.msg_id = (char *)NULL;
829 if (pPad->ttEditReq.vtype != (char *)NULL) {
830 XtFree(pPad->ttEditReq.vtype);
831 pPad->ttEditReq.vtype = (char *)NULL;
833 if (pPad->ttEditReq.fileName != (char *)NULL) {
834 XtFree(pPad->ttEditReq.fileName);
835 pPad->ttEditReq.fileName = (char *)NULL;
837 if (pPad->ttEditReq.docName != (char *)NULL) {
838 XtFree(pPad->ttEditReq.docName);
839 pPad->ttEditReq.docName = (char *)NULL;
841 if (pPad->ttEditReq.savePattern) {
842 tt_pattern_destroy(pPad->ttEditReq.savePattern);
843 pPad->ttEditReq.savePattern = NULL;
846 if (pPad->dialogTitle != (char *)NULL) {
847 XtFree(pPad->dialogTitle);
850 pPad->saveRestore = False;
852 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
853 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
854 pPad->fileStuff.fileExists = False;
855 pPad->fileStuff.saveWithNewlines = True;
856 pPad->fileStuff.readOnly = False;
857 if (pPad->fileStuff.fileName != (char *) NULL) {
858 XtFree(pPad->fileStuff.fileName);
859 pPad->fileStuff.fileName = (char *) NULL;
861 if (pPad->fileStuff.netfile != (char *) NULL) {
862 tt_free(pPad->fileStuff.netfile);
863 pPad->fileStuff.netfile = (char *) NULL;
866 /* -----> Clear contents, undo, find/change, format and message area */
867 DtEditorReset(pPad->editor);
869 /* -----> Reset resources to server's initial resource state */
870 RestoreInitialServerResources(pPad);
872 /* -----> Set iconic state to false */
873 pPad->iconic = False;
875 /* -----> Set app shell geo (pixels), resize hints, position & size hints */
878 /* -----> Clear director "seed" in SaveAs FSB */
879 if (pPad->fileStuff.fileWidgets.saveAs.saveAs_form != (Widget)NULL) {
880 Widget textField = XmFileSelectionBoxGetChild(
881 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
883 XmTextFieldSetString(textField, "");
888 /************************************************************************
889 * NoSaveCB - callback associated with the [No] button in the "Save changes
890 * to <file>?" PromptDialog created by CreateSaveWarning().
891 ************************************************************************/
898 Editor *pPad = (Editor *)client_data;
901 XtUnmanageChild(pPad->fileStuff.fileWidgets.select.save_warning);
904 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void(*)()) NULL) {
905 /* -----> don't clear the pending function if it calls SaveUnsaved() */
906 if (pPad->fileStuff.pendingFileFunc != FileNewCB &&
907 pPad->fileStuff.pendingFileFunc != FileOpenCB &&
908 pPad->fileStuff.pendingFileFunc != FileExitCB) {
909 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
911 if (pFunc != FileSaveCB) {
912 (*pFunc)(w, client_data, call_data);
918 /************************************************************************
919 * CancelFileSelectCB -
920 ************************************************************************/
928 Editor *pPad = (Editor *)client_data;
930 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
931 pPad->fileStuff.pendingFileHelpFunc = (void(*)()) NULL;
933 /* popdown the file selection box */
935 _DtTurnOffHourGlass(w);
936 _DtTurnOffHourGlass(pPad->app_shell);
940 /************************************************************************
941 * FileOpenOkCB - saves the name of a file to be opened and its directory,
942 * and then loads its contents into the DtEditor widget.
944 * This callback is assigned to the "Ok" button of the File
945 * Selection Box displayed by the callback, FileOpenCB() assigned
946 * to the "File" menu "Open" button.
947 ************************************************************************/
954 Editor *pPad = (Editor *)client_data;
955 FileStuff *pStuff = &pPad->fileStuff;
956 XmFileSelectionBoxCallbackStruct *cb = (XmFileSelectionBoxCallbackStruct *)
958 char *name = (char *) XtMalloc( sizeof(char) * cb->length + 1 );
961 _DtTurnOnHourGlass(pPad->app_shell);
962 _DtTurnOnHourGlass(w);
964 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
965 TTmediaReply(pPad); /* reply/close ToolTalk media request */
968 /* -----> Get the name of the directory and file.
969 * XXX - Eventually, it makes sense to store the name/etc. as an XmString
970 * rather than convert everything to a string. This will mean
971 * changing the pPad.fileName type.
972 * Additionally, we can get quit saving the text field ID and
973 * deal only with the FSB. */
975 name = (char *) _XmStringUngenerate(cb->value, NULL,
976 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
978 if (pStuff->fileName != (char *)NULL) {
979 XtFree(pStuff->fileName);
981 pStuff->fileName = name;
982 ExtractAndStoreDir(pPad, name, OPEN); /* store pPad->fileStuff.pathDir */
984 LoadFile(pPad, NULL); /* this is always successful */
985 ChangeMainWindowTitle(pPad);
987 CancelFileSelectCB(w, client_data, call_data);
991 /************************************************************************
992 * IncludeFile - obtains the name of a file to include (via a Xm FSB),
993 * parses the name and then
994 * inserts the file contents into the Dt Editor Widget (via LoadFile).
996 * This callback is assigned to the "Ok" button of the
997 * File Selection Box displayed by the callback,
998 * FileIncludeCB() assigned to the "File" menu "Include" button.
999 ************************************************************************/
1003 caddr_t client_data,
1006 Editor *pPad = (Editor *)client_data;
1007 XmFileSelectionBoxCallbackStruct *cb = (XmFileSelectionBoxCallbackStruct *)
1009 char *name = (char *) XtMalloc( sizeof(char) * cb->length + 1 );
1012 _DtTurnOnHourGlass(pPad->app_shell);
1013 _DtTurnOnHourGlass(w);
1016 * Get the name of the file
1018 * Eventually, it makes sense to store the name/etc. as an XmString
1019 * rather than convert everything to a string. This will mean
1020 * changing the pPad.fileName type.
1021 * Additionally, we can get quit saving the text field ID and
1022 * deal only with the FSB.
1025 name = (char *) _XmStringUngenerate(cb->value, NULL,
1026 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
1028 ExtractAndStoreDir(pPad, name, INCLUDE); /* store pPad->fileStuff.pathDir */
1030 LoadFile(pPad, name);
1031 ChangeMainWindowTitle(pPad);
1032 CancelFileSelectCB(w, client_data, call_data);
1033 if (name != (char *)NULL)
1038 /************************************************************************
1039 * SaveUnsaved - allows unsaved changes to be saved to the current file
1040 * or buffer. If the AskIfSave dialog is posted, sets the global
1041 * pendingFileFunc to the callingFunc so that the calling function
1042 * can be reentered to finish its processing.
1044 * Returns True if the calling function should not continue due to:
1046 * 1) some error condition (e.g. the file couldn't be saved), or
1047 * 2) a dialog has been posted which needs to be responded to
1048 * (pPad->fileStuff.pendingFileFunc will be set to the calling
1049 * function which may again be executed via a callback set on
1050 * the posted dialog)
1052 ************************************************************************/
1056 void (*callingFunc)() )
1058 Boolean addNewlines;
1062 * If there are unsaved changes, ask the user if they wish to
1063 * write them out. If saveOnClose is True, then just write it.
1065 if (DtEditorCheckForUnsavedChanges(pPad->editor)) {
1067 /* -----> If handling a "silent" TTDT_QUIT request, don't AskIfSave
1068 * and don't save any unsaved changes (TTDT_SAVE does this) */
1069 if (callingFunc == FileExitCB &&
1070 pPad->ttQuitReq.contract && pPad->ttQuitReq.silent) {
1071 if (pPad->ttQuitReq.force) {
1072 return False; /* close edit window */
1074 return True; /* don't close edit window */
1078 pPad->ttEditReq.returnBufContents = True;
1080 if ((pPad->xrdb.saveOnClose) &&
1081 (pPad->fileStuff.fileName && *pPad->fileStuff.fileName)) {
1082 DtEditorErrorCode errorCode;
1083 addNewlines = pPad->xrdb.wordWrap == True &&
1084 pPad->fileStuff.saveWithNewlines == True;
1085 _DtTurnOnHourGlass(pPad->app_shell);
1086 errorCode = DtEditorSaveContentsToFile(
1088 pPad->fileStuff.fileName,
1089 True, /* overwrite existing file */
1090 addNewlines, /* replace soft line feeds? */
1091 True); /* mark contents as saved */
1092 _DtTurnOffHourGlass(pPad->app_shell);
1093 if (errorCode != SUCCESS) {
1094 PostSaveError(pPad, pPad->fileStuff.fileName, errorCode);
1095 if (callingFunc == FileExitCB) {
1096 /* Set saveOnClose to False to force user to explicitly
1097 * choose to not save changes in order to exit. */
1098 pPad->xrdb.saveOnClose = False;
1100 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1101 return True; /* don't finish calling func */
1103 if (pPad->ttEditReq.contract) {
1104 /* ZZZ -----> Create and send Saved notice */
1105 m = ttdt_file_notice(
1106 pPad->ttEditReq.contract, /* context */
1107 TTDT_SAVED, /* op */
1108 TT_SESSION, /* Tt_scope */
1109 pPad->fileStuff.fileName, /* msg file name */
1110 True); /* send & destroy */
1114 if (callingFunc == pPad->fileStuff.pendingFileFunc) {
1115 /* We've already did AskIfSave but the user responded
1116 * "No" so lets not keep asking (NoSaveCB does not clear
1117 * pPad->fileStuff.pendingFileFunc). */
1118 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1119 pPad->ttEditReq.returnBufContents = False;
1121 /* AskIfSave assigns either FileSaveAsCB or FileSaveCB to the
1122 * the o.k. dialog button that it posts. These callbacks
1123 * execute pPad->fileStuff.pendingFileFunc when done. */
1124 pPad->fileStuff.pendingFileFunc = callingFunc;
1126 return True; /* don't finish calling func */
1129 } else { /* no unsaved contents */
1130 pPad->ttEditReq.returnBufContents = False;
1133 return False; /* finish calling funct */
1137 /************************************************************************
1139 ************************************************************************/
1144 XtPointer client_data,
1145 XtPointer call_data)
1147 Editor *pPad = (Editor *)client_data;
1149 if (w == pPad->fileStuff.fileWidgets.saveAs.toggleWidgets.with_newl ||
1150 w == pPad->fileStuff.fileWidgets.select.toggleWidgets.with_newl)
1151 pPad->fileStuff.saveWithNewlines = True;
1153 pPad->fileStuff.saveWithNewlines = False;
1157 /************************************************************************
1158 * SaveAsOkCB - save the file
1159 ************************************************************************/
1163 caddr_t client_data,
1166 Editor *pPad = (Editor *)client_data;
1167 SaveAs *pSaveAs = &pPad->fileStuff.fileWidgets.saveAs;
1169 Widget textField = XmFileSelectionBoxGetChild(
1170 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
1172 DtEditorErrorCode errorCode;
1174 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
1175 pPad->fileStuff.saveWithNewlines == True;
1176 Boolean overWrite, markSaved;
1177 XmFileSelectionBoxCallbackStruct *cb = (XmFileSelectionBoxCallbackStruct *)
1179 char *name = (char *) XtMalloc( sizeof(char) * cb->length + 1 );
1182 _DtTurnOnHourGlass(pPad->app_shell);
1183 _DtTurnOnHourGlass(pSaveAs->saveAs_form);
1185 /* -----> Get the "save as" file name */
1187 name = (char *) _XmStringUngenerate(cb->value, NULL,
1188 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
1190 pPad->fileStuff.savingName = name;
1191 ExtractAndStoreDir(pPad, name, OPEN); /* store pPad->fileStuff.pathDir */
1194 * Normally, we would first try writing without overwriting the file
1195 * in which case we would get an error if the file pre-exists and we
1196 * would post a dialog asking the user if they wished to overwrite it.
1197 * However, if the name of the file to save is the same as the file
1198 * being edited, the user opened the file and knows that it exists.
1199 * In this case we would overwrite it without presenting the overwrite
1202 if (strcmp(pPad->fileStuff.fileName, pPad->fileStuff.savingName) == 0) {
1203 overWrite = True; /* overwrite */
1205 overWrite = False; /* don't overwrite yet */
1208 /* -----> Don't mark the current contents as saved if saved to a
1209 * file different than the (to be) current file */
1210 if (! pPad->xrdb.nameChange &&
1211 pPad->fileStuff.fileName && /* allow for -noNameChange w/o a fileName */
1218 errorCode = DtEditorSaveContentsToFile(
1220 pPad->fileStuff.savingName,
1222 addNewlines, /* replace soft line feeds? */
1223 markSaved); /* mark contents as saved? */
1224 if (errorCode == DtEDITOR_WRITABLE_FILE) { /* file exists & not overwriting */
1225 PostAlreadyExistsDlg(pPad); /* save handled in AlrdyExistsOkCB */
1226 XtUnmanageChild (pSaveAs->saveAs_form);
1227 _DtTurnOffHourGlass(pSaveAs->saveAs_form);
1228 _DtTurnOffHourGlass(pPad->app_shell);
1231 if (errorCode != SUCCESS) {
1232 PostSaveError(pPad, pPad->fileStuff.savingName, errorCode);
1233 XtFree(pPad->fileStuff.savingName);
1234 pPad->fileStuff.savingName = (char *)NULL;
1235 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1237 if (pPad->ttEditReq.contract) {
1238 /* ZZZ -----> Create and send Saved notice */
1239 m = ttdt_file_notice(
1240 pPad->ttEditReq.contract, /* context */
1241 TTDT_SAVED, /* op */
1242 TT_SESSION, /* Tt_scope */
1243 pPad->fileStuff.savingName, /* msg file name */
1244 True); /* send & destroy */
1247 if (pPad->xrdb.nameChange == True) {
1248 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
1249 pPad->ttEditReq.returnBufContents = False; /* drop chgs w/o notice */
1250 TTmediaReply(pPad); /* reply/close ToolTalk media request */
1252 XtFree(pPad->fileStuff.fileName);
1253 pPad->fileStuff.fileName = pPad->fileStuff.savingName;
1254 ChangeMainWindowTitle(pPad);
1259 XtUnmanageChild (pSaveAs->saveAs_form);
1260 _DtTurnOffHourGlass(pSaveAs->saveAs_form);
1261 _DtTurnOffHourGlass(pPad->app_shell);
1262 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void (*)())NULL) {
1263 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1264 (*pFunc)(w, client_data, call_data);
1269 /************************************************************************
1270 * AlrdyExistsOkCB - the ok callback for a saveAs of a file which already
1271 * exists. Specifically, this routine:
1273 * - saves the current text to the file specified by
1274 * pPad->fileStuff.savingName
1275 * - if appropriate, resets the name of the current file
1276 * (pPad->fileStuff.fileName) to pPad->fileStuff.savingName and
1277 * frees pPad->fileStuff.savingName
1278 * - executes pPad->fileStuff.pendingFileFunc if specified
1280 ************************************************************************/
1284 caddr_t client_data,
1287 Editor *pPad = (Editor *)client_data;
1289 DtEditorErrorCode errorCode;
1290 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
1291 pPad->fileStuff.saveWithNewlines == True;
1295 _DtTurnOnHourGlass(pPad->app_shell);
1296 _DtTurnOnHourGlass(w);
1298 /* -----> Don't mark the current contents as saved if saved to a
1299 * file different than the (to be) current file */
1300 if (! pPad->xrdb.nameChange &&
1301 pPad->fileStuff.fileName && /* allow for -noNameChange w/o a fileName */
1302 (strcmp(pPad->fileStuff.fileName, pPad->fileStuff.savingName) != 0)) {
1308 errorCode = DtEditorSaveContentsToFile(
1310 pPad->fileStuff.savingName,
1311 True, /* overwrite existing file */
1312 addNewlines, /* replace soft line feeds? */
1313 markSaved); /* mark contents as saved? */
1315 XtUnmanageChild (w);
1316 _DtTurnOffHourGlass(w);
1317 _DtTurnOffHourGlass(pPad->app_shell);
1319 if (errorCode == SUCCESS) {
1320 if (pPad->ttEditReq.contract) {
1321 /* ZZZ -----> Create and send Saved notice */
1322 m = ttdt_file_notice(
1323 pPad->ttEditReq.contract, /* context */
1324 TTDT_SAVED, /* op */
1325 TT_SESSION, /* Tt_scope */
1326 pPad->fileStuff.savingName, /* msg file name */
1327 True); /* send & destroy */
1329 if (pPad->xrdb.nameChange == True) {
1330 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
1331 pPad->ttEditReq.returnBufContents = False; /* drop chgs w/o notice */
1332 TTmediaReply(pPad); /* reply/close ToolTalk media request */
1334 XtFree(pPad->fileStuff.fileName);
1335 pPad->fileStuff.fileName = pPad->fileStuff.savingName;
1336 ChangeMainWindowTitle(pPad);
1339 PostSaveError(pPad, pPad->fileStuff.savingName, errorCode);
1341 if (pPad->fileStuff.savingName != pPad->fileStuff.fileName)
1342 XtFree(pPad->fileStuff.savingName);
1343 pPad->fileStuff.savingName = (char *)NULL;
1345 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void (*)())NULL) {
1346 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1347 (*pFunc)(w, client_data, call_data);
1352 /************************************************************************
1353 * SaveAsCancelCB - Unmanage the SaveAs dialog
1354 ************************************************************************/
1359 caddr_t client_data,
1362 Editor *pPad = (Editor *) client_data;
1364 XtUnmanageChild ((Widget) pPad->fileStuff.fileWidgets.saveAs.saveAs_form);
1365 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
1366 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
1370 /************************************************************************
1371 * AlrdyExistsCancelCB - Unmanage the AlreadyExists dialog
1372 ************************************************************************/
1375 AlrdyExistsCancelCB(
1377 caddr_t client_data,
1380 Editor *pPad = (Editor *)client_data;
1381 XtUnmanageChild ((Widget) pPad->fileStuff.fileWidgets.saveAs.alrdy_exist);
1382 XtFree(pPad->fileStuff.savingName);
1383 pPad->fileStuff.savingName = (char *) NULL;
1384 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
1385 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
1389 /************************************************************************
1390 * AskIfSaveCancelCB -
1391 ************************************************************************/
1396 caddr_t client_data,
1399 Editor *pPad = (Editor *)client_data;
1401 XtUnmanageChild ((Widget) pPad->fileStuff.fileWidgets.select.save_warning);
1402 if (pPad->fileStuff.pendingFileFunc == FileExitCB) {
1403 TTfailPendingQuit(pPad);
1405 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
1406 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;