2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
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>
64 extern int numActivePads; /* declared in main.c */
67 /************************************************************************
68 * Forward Declarations
69 ************************************************************************/
70 static void FileDoXpPrint(
73 static void FileOpenOkCB(
77 static void IncludeFile(
81 static Boolean SaveUnsaved(
83 void (*callingFunc)() );
84 static Boolean FileExitWP(
85 XtPointer client_data);
88 /************************************************************************
89 * FileCascadingCB - callback assigned to "File" menu to determine
90 * whether Save button in menu is labeled "Save" or "Save (needed)".
91 ************************************************************************/
99 Editor *pPad = (Editor *)client_data;
102 if (DtEditorCheckForUnsavedChanges(pPad->editor)) {
103 XtSetArg(al[0], XmNlabelString, pPad->fileStuff.saveNeededBtnLabel);
105 XtSetArg(al[0], XmNlabelString, pPad->fileStuff.saveBtnLabel);
107 XtSetValues(pPad->fileStuff.fileWidgets.saveBtn, al, 1);
112 /************************************************************************
113 * FileNewCB - callback assigned to "File" menu "New" button which
114 * saves the current text if it hasn't been saved and then calls
115 * LoadFile(). Since pPad->fileStuff.fileName is NULL, LoadFile
116 * sets the contents to "" rather than loading a file.
117 ************************************************************************/
125 Editor *pPad = (Editor *)client_data;
127 if (SaveUnsaved(pPad, FileNewCB)) {
131 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
132 TTmediaReply(pPad); /* reply/close ToolTalk media request */
135 if (pPad->fileStuff.fileName != (char *)NULL) {
136 XtFree(pPad->fileStuff.fileName);
137 pPad->fileStuff.fileName = (char *)NULL;
139 _DtTurnOnHourGlass(pPad->app_shell);
140 LoadFile(pPad, NULL);
141 ChangeMainWindowTitle(pPad);
142 _DtTurnOffHourGlass(pPad->app_shell);
146 /************************************************************************
147 * FileOpenCB - callback assigned to "File" menu "Open..." button
148 ************************************************************************/
156 Editor *pPad = (Editor *)client_data;
157 FileStuff *pStuff = &pPad->fileStuff;
159 if (SaveUnsaved(pPad, FileOpenCB)) {
163 /* ToolTalk media requests are replied to (and closed) in FileOpenOkCB */
165 /* -----> set FSB title passed GetFileName */
166 if(pStuff->openTitle == (XmString)NULL) {
169 strcpy(buf, DialogTitle(pPad));
170 strcat(buf, (char *)GETMESSAGE(4, 1, "Open a File"));
171 pStuff->openTitle = XmStringCreateLocalized(buf);
174 /* -----> obtain the name of the file to open (via a Xm file selection box)
175 * and load its contents (via FileOpenOkCB) to the Editor widget */
176 pStuff->pendingFileFunc = FileOpenOkCB; /* FSB XmNokCallback */
177 pStuff->pendingFileHelpFunc = HelpOpenDialogCB; /* FSB XmNhelpCallback */
178 GetFileName(pPad, pStuff->openTitle, OPEN);
182 /************************************************************************
183 * FileIncludeCB - callback assigned to "File" menu "Include..." button
184 ************************************************************************/
192 Editor *pPad = (Editor *)client_data;
193 FileStuff *pStuff = &pPad->fileStuff;
195 if (pStuff->includeTitle == (XmString)NULL) {
198 strcpy(buf, DialogTitle(pPad));
199 strcat(buf, (char *)GETMESSAGE(4, 3, "Include a File"));
200 pStuff->includeTitle = XmStringCreateLocalized(buf);
202 pPad->fileStuff.pendingFileFunc = IncludeFile;
203 pPad->fileStuff.pendingFileHelpFunc = HelpIncludeDialogCB;
204 GetFileName(pPad, pStuff->includeTitle, INCLUDE);
208 /************************************************************************
209 * FileSaveCB - callback assigned to "File" menu "Save" button and to the
210 * AskIfSave dialog's "OK" button (which is displayed when there are
211 * unsaved changes when switching to a new file/buffer).
214 ************************************************************************/
221 Editor *pPad = (Editor *)client_data;
223 DtEditorErrorCode errorCode;
224 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
225 pPad->fileStuff.saveWithNewlines == True;
228 if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName) { /* filename? */
229 /* -----> if called directly from [Save] menu and word wrap is on,
230 * display Save dialog so that saveWithNewlines can be set */
231 if (pPad->xrdb.wordWrap &&
232 !pPad->fileStuff.pendingFileFunc && !pPad->ttSaveReq.contract) {
234 pPad->fileStuff.pendingFileFunc = FileSaveCB;
237 _DtTurnOnHourGlass(pPad->app_shell);
238 errorCode = DtEditorSaveContentsToFile(
240 pPad->fileStuff.fileName,
241 True, /* overwrite existing file */
242 addNewlines, /* replace soft line feeds? */
243 True); /* mark contents as saved */
244 _DtTurnOffHourGlass(pPad->app_shell);
245 if (errorCode != DtEDITOR_NO_ERRORS) {
246 PostSaveError(pPad, pPad->fileStuff.fileName, errorCode);
247 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
248 TTfailPendingSave(pPad);
251 if (pPad->ttEditReq.contract) {
252 /* ZZZ -----> Create and send Saved notice */
253 m = ttdt_file_notice(
254 pPad->ttEditReq.contract, /* context */
256 TT_SESSION, /* Tt_scope */
257 pPad->fileStuff.fileName, /* msg file name */
258 True); /* send & destroy */
260 if (pPad->ttSaveReq.contract) {
261 if (! pPad->ttEditReq.contract) {
262 TTfailPendingSave(pPad);
264 tt_message_reply(pPad->ttSaveReq.contract);
265 tttk_message_destroy(pPad->ttSaveReq.contract);
268 } else { /* no fileName associated with current text */
269 if (pPad->ttEditReq.contract) {
270 if (pPad->ttEditReq.contents) {
271 if (TTmediaDepositContents(pPad) != 0) {
272 if (pPad->fileStuff.pendingFileFunc == FileExitCB) {
273 TTfailPendingQuit(pPad);
275 TTfailPendingSave(pPad);
276 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
277 return; /* deposit failed */
279 } else { /* TT request without fileName and contents */
280 FileSaveAsCB(w, client_data, call_data);
283 if (pPad->ttSaveReq.contract) {
284 tt_message_reply(pPad->ttSaveReq.contract);
285 tttk_message_destroy(pPad->ttSaveReq.contract);
287 } else { /* non-TT request and no file name */
288 if (pPad->ttSaveReq.contract) {
289 TTfailPendingSave(pPad);
291 FileSaveAsCB(w, client_data, call_data);
297 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void (*)())NULL) {
298 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
299 if (pFunc != FileSaveCB) {
300 (*pFunc)(w, client_data, call_data);
307 /************************************************************************
308 * FileSaveAsCB - callback assigned to "File" menu "SaveAs..." button
309 ************************************************************************/
316 Editor *pPad = (Editor *)client_data;
317 SaveAs *pSaveAs = &pPad->fileStuff.fileWidgets.saveAs;
320 if (!pSaveAs->saveAs_form) {
321 CreateSaveAsDialog(pPad);
322 XtManageChild (pSaveAs->saveAs_form);
324 * XXX - Should be dealing with the FSB instead of the text field directly.
325 * Also, should be setting an XmString, rather than a char *
327 textField = XmFileSelectionBoxGetChild(
328 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
330 XmTextFieldSetString(textField, "");
332 XtManageChild (pSaveAs->saveAs_form);
333 textField = XmFileSelectionBoxGetChild(
334 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
338 SetSaveAsDirAndFile(pPad); /* seed the SaveAs FSB dir and file fields */
340 /* Force the focus to the text field */
341 XmProcessTraversal(textField, XmTRAVERSE_CURRENT);
342 XSync(pPad->display, 0);
344 _DtTurnOffHourGlass(pPad->app_shell);
348 extern Boolean ActionDBInitialized; /* declared in main.c */
351 /************************************************************************
352 * PrintActionCB - callback assigned to "File" menu "Print" button
353 ************************************************************************/
357 DtActionInvocationID actionID,
358 XtPointer client_data,
359 DtActionArg *actionArgp,
361 DtActionStatus actionStatus)
363 Editor *pPad = (Editor *) client_data;
364 switch ((DtActionStatus) actionStatus) {
365 case DtACTION_INVOKED:
366 case DtACTION_STATUS_UPDATE:
369 case DtACTION_FAILED:
370 case DtACTION_CANCELED:
372 /* XtSetSensitive(pPad->app_shell, True); */
373 _DtTurnOffHourGlass(pPad->app_shell);
379 /************************************************************************
380 * FilePrintCB - callback assigned to "File" menu "Print" button
381 ************************************************************************/
389 Editor *pPad = (Editor *) client_data;
390 DtActionArg *actionArgp = (DtActionArg *) XtCalloc(2,sizeof(DtActionArg));
391 DtActionInvocationID actionID;
392 char *pr_name = (char *) NULL, *user_name;
393 DtEditorErrorCode errorCode;
395 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
396 pPad->fileStuff.saveWithNewlines == True;
398 _DtTurnOnHourGlass(pPad->app_shell);
399 /* -----> Disallow keyboard, button, motion, window enter/leave & focus
400 * events till print (dialog) action is done
401 * XtSetSensitive(pPad->app_shell, False);
404 /* -----> Get a place to temporarily write the text */
405 if ((pr_name = GetTempFile()) == (char *)NULL) {
406 _DtTurnOffHourGlass(pPad->app_shell);
407 Warning(pPad, ((char *)
408 GETMESSAGE(4, 5, "Unable to create a temporary file.")), XmDIALOG_ERROR);
412 /* -----> Write the contents to the temp file */
413 errorCode = DtEditorSaveContentsToFile(
416 True, /* overwrite existing file */
417 addNewlines, /* replace soft line feeds? */
418 False); /* don't mark contents as saved */
419 if (errorCode != SUCCESS) { /* this should never occur */
420 _DtTurnOffHourGlass(pPad->app_shell);
421 PostSaveError(pPad, pr_name, errorCode);
425 /* -----> Load the action database */
426 if (! ActionDBInitialized) {
427 StartDbUpdate( (XtPointer) NULL );
428 /* register interest in Action DB changes (for printing) */
429 DtDbReloadNotify( StartDbUpdate, (XtPointer) NULL );
432 /* -----> Determine the name the user will see in the Print dialog */
433 if (pPad->ttEditReq.contract &&
434 (pPad->ttEditReq.docName && *pPad->ttEditReq.docName)) {
435 user_name = strdup(pPad->ttEditReq.docName);
436 } else if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName) {
437 user_name = strdup(pPad->fileStuff.fileName);
439 user_name = strdup(UNNAMED_TITLE_P);
442 /* ----> Setup the action arguments - one for the filename as known by
443 * the user (Arg_1) and one for the temporary print file (Arg_2).
444 * PRINT_DTPAD_TEMPFILE does something like:
445 * /usr/dt/bin/dtlp -u %(String)Arg_2% -e %(File)Arg_1%
446 * dtlp displays a dialog to gather lp paramters and then prints
447 * the file. The -e says to remove the temporary file after it
448 * it has been passed to lp. */
449 actionArgp[0].argClass = DtACTION_FILE;
450 actionArgp[0].u.file.name = pr_name;
451 actionArgp[1].argClass = DtACTION_FILE;
452 actionArgp[1].u.file.name = user_name;
454 /* XXX - Try this after everything's working - don't directly output to
455 * a temp file but to a buffer and pass the buffer to the action
456 * and let the action automatically create/remove the temp file.
457 * This'll require a new action w/o -e.
458 * actionArgp[0].argClass = DtACTION_BUFFER;
459 * actionArgp[0].u.buffer.bp = (void *) buffer;
460 * actionArgp[0].u.buffer.size = strlen(buffer;
461 * actionArgp[0].u.buffer.type = TEXT;
462 * actionArgp[0].u.buffer.writable = False;
465 /* XXX - Also, may want to set XtNsensitive to False on pPad->app_shell
466 * and turn it back on in PrintActionCB() when it receives a
467 * DtACTION_DONE status */
468 /* ----> Invoke the print action */
469 actionID = DtActionInvoke(pPad->app_shell,
470 "PRINT_DTPAD_TEMPFILE", /* action */
471 actionArgp, 2, /* action arguments & count */
472 (char *) NULL, /* terminal options */
473 (char *) NULL, /* execution host */
474 (char *) NULL, /* context dir */
475 False, /* no "use indicator" */
476 PrintActionCB, /* action callback */
477 (XtPointer) pPad); /* callback client data */
482 /* _DtTurnOffHourGlass(pPad->app_shell); this is done in PrintActionCB */
488 /************************************************************************
489 * FileDoXpPrint - procedure doing the work of the XpPrint callbacks
490 ************************************************************************/
492 static void FileDoXpPrint(Editor *pPad, Boolean silent)
496 DtActionArg *actionArgp = (DtActionArg *) XtCalloc(2,sizeof(DtActionArg));
497 DtActionInvocationID actionID;
498 DtEditorErrorCode errorCode;
500 char *pr_name = (char *) NULL, *user_name;
502 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
503 pPad->fileStuff.saveWithNewlines == True;
505 _DtTurnOnHourGlass(pPad->app_shell);
506 /* -----> Disallow keyboard, button, motion, window enter/leave & focus
507 * events till print (dialog) action is done
508 * XtSetSensitive(pPad->app_shell, False);
511 /* -----> Get a place to temporarily write the text */
512 if ((pr_name = GetTempFile()) == (char *)NULL) {
513 _DtTurnOffHourGlass(pPad->app_shell);
514 Warning(pPad, ((char *)
515 GETMESSAGE(4, 5, "Unable to create a temporary file.")), XmDIALOG_ERROR);
519 /* -----> Write the contents to the temp file */
520 errorCode = DtEditorSaveContentsToFile(
523 True, /* overwrite existing file */
524 addNewlines, /* replace soft line feeds? */
525 False); /* don't mark contents as saved */
526 if (errorCode != SUCCESS) { /* this should never occur */
527 _DtTurnOffHourGlass(pPad->app_shell);
528 PostSaveError(pPad, pr_name, errorCode);
532 /* -----> Determine the name the user will see in the Print dialog */
533 if (pPad->ttEditReq.contract &&
534 (pPad->ttEditReq.docName && *pPad->ttEditReq.docName)) {
535 user_name = strdup(pPad->ttEditReq.docName);
536 } else if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName) {
537 user_name = strdup(pPad->fileStuff.fileName);
539 user_name = strdup(UNNAMED_TITLE_P);
542 /* ----> XPPRINT: Create and execute a print job. */
543 pJob = PrintJobCreate(user_name, pr_name, silent, pPad);
544 PrintJobExecute(pJob);
549 _DtTurnOffHourGlass(pPad->app_shell);
552 /************************************************************************
553 * FileXpPrintCB - callback assigned to "File" menu "Print..." button
554 ************************************************************************/
562 Editor *pPad = (Editor *) client_data;
563 FileDoXpPrint(pPad, FALSE);
567 /************************************************************************
568 * FileExitCB - callback assigned to "File" menu "Close" button
569 ************************************************************************/
577 Editor *pPad = (Editor *)client_data;
579 if (SaveUnsaved(pPad, FileExitCB)) {
581 * If SaveUnsaved() returns True, don't close the window at this
584 * 1) a dialog has been posted which needs to be responded to
585 * (and pendingFileFunc has been set to FileExitCB so that
586 * this function will be resumed after the response) or
587 * 2) an error has occurred (in which case we abort the exit operation,
588 * failing the TTDT_QUIT request if it initiated the exit).
590 if (pPad->fileStuff.pendingFileFunc != FileExitCB) { /* error occurred */
591 TTfailPendingQuit(pPad);
596 if (pPad->numPendingTasks > 0)
601 GETMESSAGE(14, 20, "Close pending: waiting for task to terminate ...");
602 SetStatusMessage(pPad, msg);
604 if (pPad->fileExitWorkprocID == 0)
605 pPad->fileExitWorkprocID = XtAppAddWorkProc(
610 FileExitWP((XtPointer) pPad);
614 /************************************************************************
615 * FileExitWP - workproc called from FileExitCB
616 ************************************************************************/
619 FileExitWP(XtPointer client_data)
621 Editor *pPad = (Editor *)client_data;
624 if (pPad->numPendingTasks > 0)
627 if (pPad->fileExitWorkprocID != 0)
629 XtRemoveWorkProc(pPad->fileExitWorkprocID);
630 pPad->fileExitWorkprocID = 0;
633 if (pPad->ttQuitReq.contract) { /* reply to ToolTalk Quit request */
634 status = tt_message_reply(pPad->ttQuitReq.contract);
635 status = tttk_message_destroy(pPad->ttQuitReq.contract);
638 if (pPad->ttEditReq.contract) {
639 TTmediaReply(pPad); /* reply/close ToolTalk Edit/Display request */
642 if (pPad->xrdb.standAlone) {
643 exit(pPad->confirmStuff.confirmationStatus);
648 UnmanageAllDialogs(pPad);
649 XtSetMappedWhenManaged(pPad->app_shell, False);
650 XmImUnregister(pPad->editor);
651 XtPopdown(pPad->app_shell);
652 XWithdrawWindow(pPad->display, XtWindow(pPad->app_shell),
653 XDefaultScreen(pPad->display));
654 XFlush(pPad->display);
656 /* -----> Send "DONE" notice if dealing with a requestor dtpad */
657 /* if (!pPad->ttEditReq.contract && pPad->xrdb.blocking) { */
658 /* char numBuf[10]; */
659 /* sprintf(numBuf, "%d", pPad->confirmStuff.confirmationStatus); */
660 /* _DtSendSuccessNotification( */
662 /* (DtString) NULL, */
663 /* (DtString) DTPAD_DONE, */
664 /* pPad->blockChannel, numBuf, NULL); */
667 if (numActivePads == 0 && pPad->xrdb.exitOnLastClose) {
668 exit(pPad->confirmStuff.confirmationStatus);
672 * If we're going to remain around, clean up Pad for its next use.
673 * This speeds up opening a cached Pad at the expense of cycles at
674 * close time. Perception is reality.
677 /* -----> clear ToolTalk message info */
678 TTresetQuitArgs(pPad);
679 pPad->ttEditReq.contract = 0;
680 if (pPad->ttEditReq.msg_id != (char *)NULL) {
681 XtFree(pPad->ttEditReq.msg_id);
682 pPad->ttEditReq.msg_id = (char *)NULL;
684 if (pPad->ttEditReq.vtype != (char *)NULL) {
685 XtFree(pPad->ttEditReq.vtype);
686 pPad->ttEditReq.vtype = (char *)NULL;
688 if (pPad->ttEditReq.fileName != (char *)NULL) {
689 XtFree(pPad->ttEditReq.fileName);
690 pPad->ttEditReq.fileName = (char *)NULL;
692 if (pPad->ttEditReq.docName != (char *)NULL) {
693 XtFree(pPad->ttEditReq.docName);
694 pPad->ttEditReq.docName = (char *)NULL;
696 if (pPad->ttEditReq.savePattern) {
697 tt_pattern_destroy(pPad->ttEditReq.savePattern);
698 pPad->ttEditReq.savePattern = NULL;
701 if (pPad->dialogTitle != (char *)NULL) {
702 XtFree(pPad->dialogTitle);
703 pPad->dialogTitle = NULL;
706 pPad->saveRestore = False;
708 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
709 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
710 pPad->fileStuff.fileExists = False;
711 pPad->fileStuff.saveWithNewlines = True;
712 pPad->fileStuff.readOnly = False;
713 if (pPad->fileStuff.fileName != (char *) NULL) {
714 XtFree(pPad->fileStuff.fileName);
715 pPad->fileStuff.fileName = (char *) NULL;
717 if (pPad->fileStuff.netfile != (char *) NULL) {
718 tt_free(pPad->fileStuff.netfile);
719 pPad->fileStuff.netfile = (char *) NULL;
722 /* -----> Clear contents, undo, find/change, format and message area */
723 DtEditorReset(pPad->editor);
725 /* -----> Reset resources to server's initial resource state */
726 RestoreInitialServerResources(pPad);
728 /* -----> Set iconic state to false */
729 pPad->iconic = False;
731 /* -----> Set app shell geo (pixels), resize hints, position & size hints */
734 /* -----> Clear director "seed" in SaveAs FSB */
735 if (pPad->fileStuff.fileWidgets.saveAs.saveAs_form != (Widget)NULL) {
736 Widget textField = XmFileSelectionBoxGetChild(
737 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
739 XmTextFieldSetString(textField, "");
746 /************************************************************************
747 * oldFileExitCB - callback assigned to "File" menu "Close" button
748 ************************************************************************/
756 Editor *pPad = (Editor *)client_data;
759 if (SaveUnsaved(pPad, FileExitCB)) {
761 * If SaveUnsaved() returns True, don't close the window at this
764 * 1) a dialog has been posted which needs to be responded to
765 * (and pendingFileFunc has been set to FileExitCB so that
766 * this function will be resumed after the response) or
767 * 2) an error has occurred (in which case we abort the exit operation,
768 * failing the TTDT_QUIT request if it initiated the exit).
770 if (pPad->fileStuff.pendingFileFunc != FileExitCB) { /* error occurred */
771 TTfailPendingQuit(pPad);
776 if (pPad->ttQuitReq.contract) { /* reply to ToolTalk Quit request */
777 status = tt_message_reply(pPad->ttQuitReq.contract);
778 status = tttk_message_destroy(pPad->ttQuitReq.contract);
781 if (pPad->ttEditReq.contract) {
782 TTmediaReply(pPad); /* reply/close ToolTalk Edit/Display request */
785 if (pPad->xrdb.standAlone) {
786 exit(pPad->confirmStuff.confirmationStatus);
791 UnmanageAllDialogs(pPad);
792 XtSetMappedWhenManaged(pPad->app_shell, False);
793 XmImUnregister(pPad->editor);
794 XtPopdown(pPad->app_shell);
795 XWithdrawWindow(pPad->display, XtWindow(pPad->app_shell),
796 XDefaultScreen(pPad->display));
797 XFlush(pPad->display);
799 /* -----> Send "DONE" notice if dealing with a requestor dtpad */
800 /* if (!pPad->ttEditReq.contract && pPad->xrdb.blocking) { */
801 /* char numBuf[10]; */
802 /* sprintf(numBuf, "%d", pPad->confirmStuff.confirmationStatus); */
803 /* _DtSendSuccessNotification( */
805 /* (DtString) NULL, */
806 /* (DtString) DTPAD_DONE, */
807 /* pPad->blockChannel, numBuf, NULL); */
810 if (numActivePads == 0 && pPad->xrdb.exitOnLastClose) {
811 exit(pPad->confirmStuff.confirmationStatus);
815 * If we're going to remain around, clean up Pad for its next use.
816 * This speeds up opening a cached Pad at the expense of cycles at
817 * close time. Perception is reality.
820 /* -----> clear ToolTalk message info */
821 TTresetQuitArgs(pPad);
822 pPad->ttEditReq.contract = 0;
823 if (pPad->ttEditReq.msg_id != (char *)NULL) {
824 XtFree(pPad->ttEditReq.msg_id);
825 pPad->ttEditReq.msg_id = (char *)NULL;
827 if (pPad->ttEditReq.vtype != (char *)NULL) {
828 XtFree(pPad->ttEditReq.vtype);
829 pPad->ttEditReq.vtype = (char *)NULL;
831 if (pPad->ttEditReq.fileName != (char *)NULL) {
832 XtFree(pPad->ttEditReq.fileName);
833 pPad->ttEditReq.fileName = (char *)NULL;
835 if (pPad->ttEditReq.docName != (char *)NULL) {
836 XtFree(pPad->ttEditReq.docName);
837 pPad->ttEditReq.docName = (char *)NULL;
839 if (pPad->ttEditReq.savePattern) {
840 tt_pattern_destroy(pPad->ttEditReq.savePattern);
841 pPad->ttEditReq.savePattern = NULL;
844 if (pPad->dialogTitle != (char *)NULL) {
845 XtFree(pPad->dialogTitle);
848 pPad->saveRestore = False;
850 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
851 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
852 pPad->fileStuff.fileExists = False;
853 pPad->fileStuff.saveWithNewlines = True;
854 pPad->fileStuff.readOnly = False;
855 if (pPad->fileStuff.fileName != (char *) NULL) {
856 XtFree(pPad->fileStuff.fileName);
857 pPad->fileStuff.fileName = (char *) NULL;
859 if (pPad->fileStuff.netfile != (char *) NULL) {
860 tt_free(pPad->fileStuff.netfile);
861 pPad->fileStuff.netfile = (char *) NULL;
864 /* -----> Clear contents, undo, find/change, format and message area */
865 DtEditorReset(pPad->editor);
867 /* -----> Reset resources to server's initial resource state */
868 RestoreInitialServerResources(pPad);
870 /* -----> Set iconic state to false */
871 pPad->iconic = False;
873 /* -----> Set app shell geo (pixels), resize hints, position & size hints */
876 /* -----> Clear director "seed" in SaveAs FSB */
877 if (pPad->fileStuff.fileWidgets.saveAs.saveAs_form != (Widget)NULL) {
878 Widget textField = XmFileSelectionBoxGetChild(
879 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
881 XmTextFieldSetString(textField, "");
886 /************************************************************************
887 * NoSaveCB - callback associated with the [No] button in the "Save changes
888 * to <file>?" PromptDialog created by CreateSaveWarning().
889 ************************************************************************/
896 Editor *pPad = (Editor *)client_data;
899 XtUnmanageChild(pPad->fileStuff.fileWidgets.select.save_warning);
902 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void(*)()) NULL) {
903 /* -----> don't clear the pending function if it calls SaveUnsaved() */
904 if (pPad->fileStuff.pendingFileFunc != FileNewCB &&
905 pPad->fileStuff.pendingFileFunc != FileOpenCB &&
906 pPad->fileStuff.pendingFileFunc != FileExitCB) {
907 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
909 if (pFunc != FileSaveCB) {
910 (*pFunc)(w, client_data, call_data);
916 /************************************************************************
917 * CancelFileSelectCB -
918 ************************************************************************/
926 Editor *pPad = (Editor *)client_data;
928 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
929 pPad->fileStuff.pendingFileHelpFunc = (void(*)()) NULL;
931 /* popdown the file selection box */
933 _DtTurnOffHourGlass(w);
934 _DtTurnOffHourGlass(pPad->app_shell);
938 /************************************************************************
939 * FileOpenOkCB - saves the name of a file to be opened and its directory,
940 * and then loads its contents into the DtEditor widget.
942 * This callback is assigned to the "Ok" button of the File
943 * Selection Box displayed by the callback, FileOpenCB() assigned
944 * to the "File" menu "Open" button.
945 ************************************************************************/
952 Editor *pPad = (Editor *)client_data;
953 FileStuff *pStuff = &pPad->fileStuff;
954 XmFileSelectionBoxCallbackStruct *cb = (XmFileSelectionBoxCallbackStruct *)
956 char *name = (char *) XtMalloc( sizeof(char) * cb->length + 1 );
959 _DtTurnOnHourGlass(pPad->app_shell);
960 _DtTurnOnHourGlass(w);
962 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
963 TTmediaReply(pPad); /* reply/close ToolTalk media request */
966 /* -----> Get the name of the directory and file.
967 * XXX - Eventually, it makes sense to store the name/etc. as an XmString
968 * rather than convert everything to a string. This will mean
969 * changing the pPad.fileName type.
970 * Additionally, we can get quit saving the text field ID and
971 * deal only with the FSB. */
973 name = (char *) _XmStringUngenerate(cb->value, NULL,
974 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
976 if (pStuff->fileName != (char *)NULL) {
977 XtFree(pStuff->fileName);
979 pStuff->fileName = name;
980 ExtractAndStoreDir(pPad, name, OPEN); /* store pPad->fileStuff.pathDir */
982 LoadFile(pPad, NULL); /* this is always successful */
983 ChangeMainWindowTitle(pPad);
985 CancelFileSelectCB(w, client_data, call_data);
989 /************************************************************************
990 * IncludeFile - obtains the name of a file to include (via a Xm FSB),
991 * parses the name and then
992 * inserts the file contents into the Dt Editor Widget (via LoadFile).
994 * This callback is assigned to the "Ok" button of the
995 * File Selection Box displayed by the callback,
996 * FileIncludeCB() assigned to the "File" menu "Include" button.
997 ************************************************************************/
1001 caddr_t client_data,
1004 Editor *pPad = (Editor *)client_data;
1005 XmFileSelectionBoxCallbackStruct *cb = (XmFileSelectionBoxCallbackStruct *)
1007 char *name = (char *) XtMalloc( sizeof(char) * cb->length + 1 );
1010 _DtTurnOnHourGlass(pPad->app_shell);
1011 _DtTurnOnHourGlass(w);
1014 * Get the name of the file
1016 * Eventually, it makes sense to store the name/etc. as an XmString
1017 * rather than convert everything to a string. This will mean
1018 * changing the pPad.fileName type.
1019 * Additionally, we can get quit saving the text field ID and
1020 * deal only with the FSB.
1023 name = (char *) _XmStringUngenerate(cb->value, NULL,
1024 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
1026 ExtractAndStoreDir(pPad, name, INCLUDE); /* store pPad->fileStuff.pathDir */
1028 LoadFile(pPad, name);
1029 ChangeMainWindowTitle(pPad);
1030 CancelFileSelectCB(w, client_data, call_data);
1031 if (name != (char *)NULL)
1036 /************************************************************************
1037 * SaveUnsaved - allows unsaved changes to be saved to the current file
1038 * or buffer. If the AskIfSave dialog is posted, sets the global
1039 * pendingFileFunc to the callingFunc so that the calling function
1040 * can be reentered to finish its processing.
1042 * Returns True if the calling function should not continue due to:
1044 * 1) some error condition (e.g. the file couldn't be saved), or
1045 * 2) a dialog has been posted which needs to be responded to
1046 * (pPad->fileStuff.pendingFileFunc will be set to the calling
1047 * function which may again be executed via a callback set on
1048 * the posted dialog)
1050 ************************************************************************/
1054 void (*callingFunc)() )
1056 Boolean addNewlines;
1060 * If there are unsaved changes, ask the user if they wish to
1061 * write them out. If saveOnClose is True, then just write it.
1063 if (DtEditorCheckForUnsavedChanges(pPad->editor)) {
1065 /* -----> If handling a "silent" TTDT_QUIT request, don't AskIfSave
1066 * and don't save any unsaved changes (TTDT_SAVE does this) */
1067 if (callingFunc == FileExitCB &&
1068 pPad->ttQuitReq.contract && pPad->ttQuitReq.silent) {
1069 if (pPad->ttQuitReq.force) {
1070 return False; /* close edit window */
1072 return True; /* don't close edit window */
1076 pPad->ttEditReq.returnBufContents = True;
1078 if ((pPad->xrdb.saveOnClose) &&
1079 (pPad->fileStuff.fileName && *pPad->fileStuff.fileName)) {
1080 DtEditorErrorCode errorCode;
1081 addNewlines = pPad->xrdb.wordWrap == True &&
1082 pPad->fileStuff.saveWithNewlines == True;
1083 _DtTurnOnHourGlass(pPad->app_shell);
1084 errorCode = DtEditorSaveContentsToFile(
1086 pPad->fileStuff.fileName,
1087 True, /* overwrite existing file */
1088 addNewlines, /* replace soft line feeds? */
1089 True); /* mark contents as saved */
1090 _DtTurnOffHourGlass(pPad->app_shell);
1091 if (errorCode != SUCCESS) {
1092 PostSaveError(pPad, pPad->fileStuff.fileName, errorCode);
1093 if (callingFunc == FileExitCB) {
1094 /* Set saveOnClose to False to force user to explicitly
1095 * choose to not save changes in order to exit. */
1096 pPad->xrdb.saveOnClose = False;
1098 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1099 return True; /* don't finish calling func */
1101 if (pPad->ttEditReq.contract) {
1102 /* ZZZ -----> Create and send Saved notice */
1103 m = ttdt_file_notice(
1104 pPad->ttEditReq.contract, /* context */
1105 TTDT_SAVED, /* op */
1106 TT_SESSION, /* Tt_scope */
1107 pPad->fileStuff.fileName, /* msg file name */
1108 True); /* send & destroy */
1112 if (callingFunc == pPad->fileStuff.pendingFileFunc) {
1113 /* We've already did AskIfSave but the user responded
1114 * "No" so lets not keep asking (NoSaveCB does not clear
1115 * pPad->fileStuff.pendingFileFunc). */
1116 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1117 pPad->ttEditReq.returnBufContents = False;
1119 /* AskIfSave assigns either FileSaveAsCB or FileSaveCB to the
1120 * the o.k. dialog button that it posts. These callbacks
1121 * execute pPad->fileStuff.pendingFileFunc when done. */
1122 pPad->fileStuff.pendingFileFunc = callingFunc;
1124 return True; /* don't finish calling func */
1127 } else { /* no unsaved contents */
1128 pPad->ttEditReq.returnBufContents = False;
1131 return False; /* finish calling funct */
1135 /************************************************************************
1137 ************************************************************************/
1142 XtPointer client_data,
1143 XtPointer call_data)
1145 Editor *pPad = (Editor *)client_data;
1147 if (w == pPad->fileStuff.fileWidgets.saveAs.toggleWidgets.with_newl ||
1148 w == pPad->fileStuff.fileWidgets.select.toggleWidgets.with_newl)
1149 pPad->fileStuff.saveWithNewlines = True;
1151 pPad->fileStuff.saveWithNewlines = False;
1155 /************************************************************************
1156 * SaveAsOkCB - save the file
1157 ************************************************************************/
1161 caddr_t client_data,
1164 Editor *pPad = (Editor *)client_data;
1165 SaveAs *pSaveAs = &pPad->fileStuff.fileWidgets.saveAs;
1167 Widget textField = XmFileSelectionBoxGetChild(
1168 pPad->fileStuff.fileWidgets.saveAs.saveAs_form,
1170 DtEditorErrorCode errorCode;
1172 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
1173 pPad->fileStuff.saveWithNewlines == True;
1174 Boolean overWrite, markSaved;
1175 XmFileSelectionBoxCallbackStruct *cb = (XmFileSelectionBoxCallbackStruct *)
1177 char *name = (char *) XtMalloc( sizeof(char) * cb->length + 1 );
1180 _DtTurnOnHourGlass(pPad->app_shell);
1181 _DtTurnOnHourGlass(pSaveAs->saveAs_form);
1183 /* -----> Get the "save as" file name */
1185 name = (char *) _XmStringUngenerate(cb->value, NULL,
1186 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
1188 pPad->fileStuff.savingName = name;
1189 ExtractAndStoreDir(pPad, name, OPEN); /* store pPad->fileStuff.pathDir */
1192 * Normally, we would first try writing without overwriting the file
1193 * in which case we would get an error if the file pre-exists and we
1194 * would post a dialog asking the user if they wished to overwrite it.
1195 * However, if the name of the file to save is the same as the file
1196 * being edited, the user opened the file and knows that it exists.
1197 * In this case we would overwrite it without presenting the overwrite
1200 if (strcmp(pPad->fileStuff.fileName, pPad->fileStuff.savingName) == 0) {
1201 overWrite = True; /* overwrite */
1203 overWrite = False; /* don't overwrite yet */
1206 /* -----> Don't mark the current contents as saved if saved to a
1207 * file different than the (to be) current file */
1208 if (! pPad->xrdb.nameChange &&
1209 pPad->fileStuff.fileName && /* allow for -noNameChange w/o a fileName */
1216 errorCode = DtEditorSaveContentsToFile(
1218 pPad->fileStuff.savingName,
1220 addNewlines, /* replace soft line feeds? */
1221 markSaved); /* mark contents as saved? */
1222 if (errorCode == DtEDITOR_WRITABLE_FILE) { /* file exists & not overwriting */
1223 PostAlreadyExistsDlg(pPad); /* save handled in AlrdyExistsOkCB */
1224 XtUnmanageChild (pSaveAs->saveAs_form);
1225 _DtTurnOffHourGlass(pSaveAs->saveAs_form);
1226 _DtTurnOffHourGlass(pPad->app_shell);
1229 if (errorCode != SUCCESS) {
1230 PostSaveError(pPad, pPad->fileStuff.savingName, errorCode);
1231 XtFree(pPad->fileStuff.savingName);
1232 pPad->fileStuff.savingName = (char *)NULL;
1233 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1235 if (pPad->ttEditReq.contract) {
1236 /* ZZZ -----> Create and send Saved notice */
1237 m = ttdt_file_notice(
1238 pPad->ttEditReq.contract, /* context */
1239 TTDT_SAVED, /* op */
1240 TT_SESSION, /* Tt_scope */
1241 pPad->fileStuff.savingName, /* msg file name */
1242 True); /* send & destroy */
1245 if (pPad->xrdb.nameChange == True) {
1246 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
1247 pPad->ttEditReq.returnBufContents = False; /* drop chgs w/o notice */
1248 TTmediaReply(pPad); /* reply/close ToolTalk media request */
1250 XtFree(pPad->fileStuff.fileName);
1251 pPad->fileStuff.fileName = pPad->fileStuff.savingName;
1252 ChangeMainWindowTitle(pPad);
1257 XtUnmanageChild (pSaveAs->saveAs_form);
1258 _DtTurnOffHourGlass(pSaveAs->saveAs_form);
1259 _DtTurnOffHourGlass(pPad->app_shell);
1260 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void (*)())NULL) {
1261 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1262 (*pFunc)(w, client_data, call_data);
1267 /************************************************************************
1268 * AlrdyExistsOkCB - the ok callback for a saveAs of a file which already
1269 * exists. Specifically, this routine:
1271 * - saves the current text to the file specified by
1272 * pPad->fileStuff.savingName
1273 * - if appropriate, resets the name of the current file
1274 * (pPad->fileStuff.fileName) to pPad->fileStuff.savingName and
1275 * frees pPad->fileStuff.savingName
1276 * - executes pPad->fileStuff.pendingFileFunc if specified
1278 ************************************************************************/
1282 caddr_t client_data,
1285 Editor *pPad = (Editor *)client_data;
1287 DtEditorErrorCode errorCode;
1288 Boolean addNewlines = pPad->xrdb.wordWrap == True &&
1289 pPad->fileStuff.saveWithNewlines == True;
1293 _DtTurnOnHourGlass(pPad->app_shell);
1294 _DtTurnOnHourGlass(w);
1296 /* -----> Don't mark the current contents as saved if saved to a
1297 * file different than the (to be) current file */
1298 if (! pPad->xrdb.nameChange &&
1299 pPad->fileStuff.fileName && /* allow for -noNameChange w/o a fileName */
1300 (strcmp(pPad->fileStuff.fileName, pPad->fileStuff.savingName) != 0)) {
1306 errorCode = DtEditorSaveContentsToFile(
1308 pPad->fileStuff.savingName,
1309 True, /* overwrite existing file */
1310 addNewlines, /* replace soft line feeds? */
1311 markSaved); /* mark contents as saved? */
1313 XtUnmanageChild (w);
1314 _DtTurnOffHourGlass(w);
1315 _DtTurnOffHourGlass(pPad->app_shell);
1317 if (errorCode == SUCCESS) {
1318 if (pPad->ttEditReq.contract) {
1319 /* ZZZ -----> Create and send Saved notice */
1320 m = ttdt_file_notice(
1321 pPad->ttEditReq.contract, /* context */
1322 TTDT_SAVED, /* op */
1323 TT_SESSION, /* Tt_scope */
1324 pPad->fileStuff.savingName, /* msg file name */
1325 True); /* send & destroy */
1327 if (pPad->xrdb.nameChange == True) {
1328 if (pPad->ttEditReq.contract && pPad->ttEditReq.op != TTME_INSTANTIATE) {
1329 pPad->ttEditReq.returnBufContents = False; /* drop chgs w/o notice */
1330 TTmediaReply(pPad); /* reply/close ToolTalk media request */
1332 XtFree(pPad->fileStuff.fileName);
1333 pPad->fileStuff.fileName = pPad->fileStuff.savingName;
1334 ChangeMainWindowTitle(pPad);
1337 PostSaveError(pPad, pPad->fileStuff.savingName, errorCode);
1339 if (pPad->fileStuff.savingName != pPad->fileStuff.fileName)
1340 XtFree(pPad->fileStuff.savingName);
1341 pPad->fileStuff.savingName = (char *)NULL;
1343 if ((pFunc = pPad->fileStuff.pendingFileFunc) != (void (*)())NULL) {
1344 pPad->fileStuff.pendingFileFunc = (void(*)()) NULL;
1345 (*pFunc)(w, client_data, call_data);
1350 /************************************************************************
1351 * SaveAsCancelCB - Unmanage the SaveAs dialog
1352 ************************************************************************/
1357 caddr_t client_data,
1360 Editor *pPad = (Editor *) client_data;
1362 XtUnmanageChild ((Widget) pPad->fileStuff.fileWidgets.saveAs.saveAs_form);
1363 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
1364 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
1368 /************************************************************************
1369 * AlrdyExistsCancelCB - Unmanage the AlreadyExists dialog
1370 ************************************************************************/
1373 AlrdyExistsCancelCB(
1375 caddr_t client_data,
1378 Editor *pPad = (Editor *)client_data;
1379 XtUnmanageChild ((Widget) pPad->fileStuff.fileWidgets.saveAs.alrdy_exist);
1380 XtFree(pPad->fileStuff.savingName);
1381 pPad->fileStuff.savingName = (char *) NULL;
1382 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
1383 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;
1387 /************************************************************************
1388 * AskIfSaveCancelCB -
1389 ************************************************************************/
1394 caddr_t client_data,
1397 Editor *pPad = (Editor *)client_data;
1399 XtUnmanageChild ((Widget) pPad->fileStuff.fileWidgets.select.save_warning);
1400 if (pPad->fileStuff.pendingFileFunc == FileExitCB) {
1401 TTfailPendingQuit(pPad);
1403 pPad->fileStuff.pendingFileFunc = (void (*)())NULL;
1404 pPad->fileStuff.pendingFileHelpFunc = (void (*)())NULL;