1 static const char CVSID
[] = "$Id: window.c,v 1.204 2008/03/03 22:32:24 tringali Exp $";
2 /*******************************************************************************
4 * window.c -- Nirvana Editor window creation/deletion *
6 * Copyright (C) 1999 Mark Edel *
8 * This is free software; you can redistribute it and/or modify it under the *
9 * terms of the GNU General Public License as published by the Free Software *
10 * Foundation; either version 2 of the License, or (at your option) any later *
11 * version. In addition, you may distribute version of this program linked to *
12 * Motif or Open Motif. See README for details. *
14 * This software is distributed in the hope that it will be useful, but WITHOUT *
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
19 * You should have received a copy of the GNU General Public License along with *
20 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
21 * Place, Suite 330, Boston, MA 02111-1307 USA *
23 * Nirvana Text Editor *
26 * Written by Mark Edel *
28 *******************************************************************************/
31 #include "../config.h"
45 #include "preferences.h"
46 #include "selection.h"
50 #include "highlight.h"
51 #include "smartIndent.h"
55 #include "windowTitle.h"
56 #include "interpret.h"
58 #include "../util/clearcase.h"
59 #include "../util/misc.h"
60 #include "../util/fileUtils.h"
61 #include "../util/utils.h"
62 #include "../util/fileUtils.h"
63 #include "../util/DialogF.h"
64 #include "../Xlt/BubbleButtonP.h"
65 #include "../Microline/XmL/Folder.h"
72 #include "../util/VMSparam.h"
75 #include <sys/param.h>
77 #include "../util/clearcase.h"
87 #include <X11/Intrinsic.h>
88 #include <X11/Shell.h>
89 #include <X11/Xatom.h>
92 #include <Xm/PanedW.h>
93 #include <Xm/PanedWP.h>
94 #include <Xm/RowColumnP.h>
95 #include <Xm/Separator.h>
97 #include <Xm/ToggleB.h>
100 #include <Xm/Frame.h>
101 #include <Xm/Label.h>
102 #include <Xm/SelectioB.h>
104 #include <Xm/Protocols.h>
105 #include <Xm/ScrolledW.h>
106 #include <Xm/ScrollBar.h>
107 #include <Xm/PrimitiveP.h>
108 #include <Xm/Frame.h>
109 #include <Xm/CascadeB.h>
111 #include <X11/Xmu/Editres.h>
112 /* extern void _XEditResCheckMessages(); */
116 #include "../debug.h"
119 /* Initial minimum height of a pane. Just a fallback in case setPaneMinHeight
120 (which may break in a future release) is not available */
121 #define PANE_MIN_HEIGHT 39
123 /* Thickness of 3D border around statistics and/or incremental search areas
124 below the main menu bar */
125 #define STAT_SHADOW_THICKNESS 1
127 /* bitmap data for the close-tab button */
128 #define close_width 11
129 #define close_height 11
130 static unsigned char close_bits
[] = {
131 0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0xdc, 0x01, 0xf8, 0x00, 0x70, 0x00,
132 0xf8, 0x00, 0xdc, 0x01, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00};
134 /* bitmap data for the isearch-find button */
135 #define isrcFind_width 11
136 #define isrcFind_height 11
137 static unsigned char isrcFind_bits
[] = {
138 0xe0, 0x01, 0x10, 0x02, 0xc8, 0x04, 0x08, 0x04, 0x08, 0x04, 0x00, 0x04,
139 0x18, 0x02, 0xdc, 0x01, 0x0e, 0x00, 0x07, 0x00, 0x03, 0x00};
141 /* bitmap data for the isearch-clear button */
142 #define isrcClear_width 11
143 #define isrcClear_height 11
144 static unsigned char isrcClear_bits
[] = {
145 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x84, 0x01, 0xc4, 0x00, 0x64, 0x00,
146 0xc4, 0x00, 0x84, 0x01, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00};
148 extern void _XmDismissTearOff(Widget
, XtPointer
, XtPointer
);
150 static void hideTooltip(Widget tab
);
151 static Pixmap
createBitmapWithDepth(Widget w
, char *data
, unsigned int width
,
152 unsigned int height
);
153 static WindowInfo
*getNextTabWindow(WindowInfo
*window
, int direction
,
154 int crossWin
, int wrap
);
155 static Widget
addTab(Widget folder
, const char *string
);
156 static int compareWindowNames(const void *windowA
, const void *windowB
);
157 static int getTabPosition(Widget tab
);
158 static Widget
manageToolBars(Widget toolBarsForm
);
159 static void hideTearOffs(Widget menuPane
);
160 static void CloseDocumentWindow(Widget w
, WindowInfo
*window
, XtPointer callData
);
161 static void closeTabCB(Widget w
, Widget mainWin
, caddr_t callData
);
162 static void raiseTabCB(Widget w
, XtPointer clientData
, XtPointer callData
);
163 static Widget
createTextArea(Widget parent
, WindowInfo
*window
, int rows
,
164 int cols
, int emTabDist
, char *delimiters
, int wrapMargin
,
166 static void showStats(WindowInfo
*window
, int state
);
167 static void showISearch(WindowInfo
*window
, int state
);
168 static void showStatsForm(WindowInfo
*window
);
169 static void addToWindowList(WindowInfo
*window
);
170 static void removeFromWindowList(WindowInfo
*window
);
171 static void focusCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
172 static void modifiedCB(int pos
, int nInserted
, int nDeleted
, int nRestyled
,
173 const char *deletedText
, void *cbArg
);
174 static void movedCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
175 static void dragStartCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
176 static void dragEndCB(Widget w
, WindowInfo
*window
, dragEndCBStruct
*callData
);
177 static void closeCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
178 static void saveYourselfCB(Widget w
, Widget appShell
, XtPointer callData
);
179 static void setPaneDesiredHeight(Widget w
, int height
);
180 static void setPaneMinHeight(Widget w
, int min
);
181 static void addWindowIcon(Widget shell
);
182 static void wmSizeUpdateProc(XtPointer clientData
, XtIntervalId
*id
);
183 static void getGeometryString(WindowInfo
*window
, char *geomString
);
185 static void patchRowCol(Widget w
);
186 static void patchedRemoveChild(Widget child
);
188 static void refreshMenuBar(WindowInfo
*window
);
189 static void cloneDocument(WindowInfo
*window
, WindowInfo
*orgWin
);
190 static void cloneTextPanes(WindowInfo
*window
, WindowInfo
*orgWin
);
191 static UndoInfo
*cloneUndoItems(UndoInfo
*orgList
);
192 static Widget
containingPane(Widget w
);
194 static WindowInfo
*inFocusDocument
= NULL
; /* where we are now */
195 static WindowInfo
*lastFocusDocument
= NULL
; /* where we came from */
196 static int DoneWithMoveDocumentDialog
;
197 static int updateLineNumDisp(WindowInfo
* window
);
198 static int updateGutterWidth(WindowInfo
* window
);
199 static void deleteDocument(WindowInfo
*window
);
200 static void cancelTimeOut(XtIntervalId
*timer
);
202 /* From Xt, Shell.c, "BIGSIZE" */
203 static const Dimension XT_IGNORE_PPOSITION
= 32767;
206 ** Create a new editor window
208 WindowInfo
*CreateWindow(const char *name
, char *geometry
, int iconic
)
210 Widget winShell
, mainWin
, menuBar
, pane
, text
, stats
, statsAreaForm
;
211 Widget closeTabBtn
, tabForm
, form
;
217 XmFontList statsFontList
;
219 char newGeometry
[MAX_GEOM_STRING_LEN
];
220 unsigned int rows
, cols
;
221 int x
= 0, y
= 0, bitmask
, showTabBar
, state
;
223 static Pixmap isrcFind
= 0;
224 static Pixmap isrcClear
= 0;
225 static Pixmap closeTabPixmap
= 0;
227 /* Allocate some memory for the new window data structure */
228 window
= (WindowInfo
*)XtMalloc(sizeof(WindowInfo
));
230 /* initialize window structure */
231 /* + Schwarzenberg: should a
232 memset(window, 0, sizeof(WindowInfo));
235 window
->replaceDlog
= NULL
;
236 window
->replaceText
= NULL
;
237 window
->replaceWithText
= NULL
;
238 window
->replaceWordToggle
= NULL
;
239 window
->replaceCaseToggle
= NULL
;
240 window
->replaceRegexToggle
= NULL
;
241 window
->findDlog
= NULL
;
242 window
->findText
= NULL
;
243 window
->findWordToggle
= NULL
;
244 window
->findCaseToggle
= NULL
;
245 window
->findRegexToggle
= NULL
;
246 window
->replaceMultiFileDlog
= NULL
;
247 window
->replaceMultiFilePathBtn
= NULL
;
248 window
->replaceMultiFileList
= NULL
;
249 window
->multiFileReplSelected
= FALSE
;
250 window
->multiFileBusy
= FALSE
;
251 window
->writableWindows
= NULL
;
252 window
->nWritableWindows
= 0;
253 window
->fileChanged
= FALSE
;
254 window
->fileMode
= 0;
257 window
->filenameSet
= FALSE
;
258 window
->fileFormat
= UNIX_FILE_FORMAT
;
259 window
->lastModTime
= 0;
260 window
->fileMissing
= True
;
261 strcpy(window
->filename
, name
);
265 window
->autoSaveCharCount
= 0;
266 window
->autoSaveOpCount
= 0;
267 window
->undoOpCount
= 0;
268 window
->undoMemUsed
= 0;
269 CLEAR_ALL_LOCKS(window
->lockReasons
);
270 window
->indentStyle
= GetPrefAutoIndent(PLAIN_LANGUAGE_MODE
);
271 window
->autoSave
= GetPrefAutoSave();
272 window
->saveOldVersion
= GetPrefSaveOldVersion();
273 window
->wrapMode
= GetPrefWrap(PLAIN_LANGUAGE_MODE
);
274 window
->overstrike
= False
;
275 window
->showMatchingStyle
= GetPrefShowMatching();
276 window
->matchSyntaxBased
= GetPrefMatchSyntaxBased();
277 window
->showStats
= GetPrefStatsLine();
278 window
->showISearchLine
= GetPrefISearchLine();
279 window
->showLineNumbers
= GetPrefLineNums();
280 window
->highlightSyntax
= GetPrefHighlightSyntax();
281 window
->backlightCharTypes
= NULL
;
282 window
->backlightChars
= GetPrefBacklightChars();
283 if (window
->backlightChars
) {
284 char *cTypes
= GetPrefBacklightCharTypes();
285 if (cTypes
&& window
->backlightChars
) {
286 if ((window
->backlightCharTypes
= XtMalloc(strlen(cTypes
) + 1)))
287 strcpy(window
->backlightCharTypes
, cTypes
);
290 window
->modeMessageDisplayed
= FALSE
;
291 window
->modeMessage
= NULL
;
292 window
->ignoreModify
= FALSE
;
293 window
->windowMenuValid
= FALSE
;
294 window
->flashTimeoutID
= 0;
295 window
->fileClosedAtom
= None
;
296 window
->wasSelected
= FALSE
;
298 strcpy(window
->fontName
, GetPrefFontName());
299 strcpy(window
->italicFontName
, GetPrefItalicFontName());
300 strcpy(window
->boldFontName
, GetPrefBoldFontName());
301 strcpy(window
->boldItalicFontName
, GetPrefBoldItalicFontName());
302 window
->colorDialog
= NULL
;
303 window
->fontList
= GetPrefFontList();
304 window
->italicFontStruct
= GetPrefItalicFont();
305 window
->boldFontStruct
= GetPrefBoldFont();
306 window
->boldItalicFontStruct
= GetPrefBoldItalicFont();
307 window
->fontDialog
= NULL
;
309 window
->markTimeoutID
= 0;
310 window
->highlightData
= NULL
;
311 window
->shellCmdData
= NULL
;
312 window
->macroCmdData
= NULL
;
313 window
->smartIndentData
= NULL
;
314 window
->languageMode
= PLAIN_LANGUAGE_MODE
;
315 window
->iSearchHistIndex
= 0;
316 window
->iSearchStartPos
= -1;
317 window
->replaceLastRegexCase
= TRUE
;
318 window
->replaceLastLiteralCase
= FALSE
;
319 window
->iSearchLastRegexCase
= TRUE
;
320 window
->iSearchLastLiteralCase
= FALSE
;
321 window
->findLastRegexCase
= TRUE
;
322 window
->findLastLiteralCase
= FALSE
;
327 /* If window geometry was specified, split it apart into a window position
328 component and a window size component. Create a new geometry string
329 containing the position component only. Rows and cols are stripped off
330 because we can't easily calculate the size in pixels from them until the
331 whole window is put together. Note that the preference resource is only
332 for clueless users who decide to specify the standard X geometry
333 application resource, which is pretty useless because width and height
334 are the same as the rows and cols preferences, and specifying a window
335 location will force all the windows to pile on top of one another */
336 if (geometry
== NULL
|| geometry
[0] == '\0')
337 geometry
= GetPrefGeometry();
338 if (geometry
== NULL
|| geometry
[0] == '\0') {
339 rows
= GetPrefRows();
340 cols
= GetPrefCols();
341 newGeometry
[0] = '\0';
343 bitmask
= XParseGeometry(geometry
, &x
, &y
, &cols
, &rows
);
345 fprintf(stderr
, "Bad window geometry specified: %s\n", geometry
);
347 if (!(bitmask
& WidthValue
))
348 cols
= GetPrefCols();
349 if (!(bitmask
& HeightValue
))
350 rows
= GetPrefRows();
352 CreateGeometryString(newGeometry
, x
, y
, 0, 0,
353 bitmask
& ~(WidthValue
| HeightValue
));
356 /* Create a new toplevel shell to hold the window */
358 XtSetArg(al
[ac
], XmNtitle
, name
); ac
++;
359 XtSetArg(al
[ac
], XmNdeleteResponse
, XmDO_NOTHING
); ac
++;
361 if (strncmp(name
, "Untitled", 8) == 0) {
362 XtSetArg(al
[ac
], XmNiconName
, APP_NAME
); ac
++;
364 XtSetArg(al
[ac
], XmNiconName
, name
); ac
++;
367 XtSetArg(al
[ac
], XmNiconName
, name
); ac
++;
369 XtSetArg(al
[ac
], XmNgeometry
, newGeometry
[0]=='\0'?NULL
:newGeometry
); ac
++;
370 XtSetArg(al
[ac
], XmNinitialState
,
371 iconic
? IconicState
: NormalState
); ac
++;
373 if (newGeometry
[0] == '\0')
375 /* Workaround to make Xt ignore Motif's bad PPosition size changes. Even
376 though we try to remove the PPosition in RealizeWithoutForcingPosition,
377 it is not sufficient. Motif will recompute the size hints some point
378 later and put PPosition back! If the window is mapped after that time,
379 then the window will again wind up at 0, 0. So, XEmacs does this, and
382 Alternate approach, relying on ShellP.h:
384 ((WMShellWidget)winShell)->shell.client_specified &= ~_XtShellPPositionOK;
387 XtSetArg(al
[ac
], XtNx
, XT_IGNORE_PPOSITION
); ac
++;
388 XtSetArg(al
[ac
], XtNy
, XT_IGNORE_PPOSITION
); ac
++;
391 winShell
= CreateWidget(TheAppShell
, "textShell",
392 topLevelShellWidgetClass
, al
, ac
);
393 window
->shell
= winShell
;
396 XtAddEventHandler (winShell
, (EventMask
)0, True
,
397 (XtEventHandler
)_XEditResCheckMessages
, NULL
);
401 addWindowIcon(winShell
);
404 /* Create a MainWindow to manage the menubar and text area, set the
405 userData resource to be used by WidgetToWindow to recover the
406 window pointer from the widget id of any of the window's widgets */
407 XtSetArg(al
[ac
], XmNuserData
, window
); ac
++;
408 mainWin
= XmCreateMainWindow(winShell
, "main", al
, ac
);
409 window
->mainWin
= mainWin
;
410 XtManageChild(mainWin
);
412 /* The statsAreaForm holds the stats line and the I-Search line. */
413 statsAreaForm
= XtVaCreateWidget("statsAreaForm",
414 xmFormWidgetClass
, mainWin
,
415 XmNmarginWidth
, STAT_SHADOW_THICKNESS
,
416 XmNmarginHeight
, STAT_SHADOW_THICKNESS
,
417 /* XmNautoUnmanage, False, */
420 /* NOTE: due to a bug in openmotif 2.1.30, NEdit used to crash when
421 the i-search bar was active, and the i-search text widget was focussed,
422 and the window's width was resized to nearly zero.
423 In theory, it is possible to avoid this by imposing a minimum
424 width constraint on the nedit windows, but that width would have to
425 be at least 30 characters, which is probably unacceptable.
426 Amazingly, adding a top offset of 1 pixel to the toggle buttons of
427 the i-search bar, while keeping the the top offset of the text widget
428 to 0 seems to avoid avoid the crash. */
430 window
->iSearchForm
= XtVaCreateWidget("iSearchForm",
431 xmFormWidgetClass
, statsAreaForm
,
432 XmNshadowThickness
, 0,
433 XmNleftAttachment
, XmATTACH_FORM
,
434 XmNleftOffset
, STAT_SHADOW_THICKNESS
,
435 XmNtopAttachment
, XmATTACH_FORM
,
436 XmNtopOffset
, STAT_SHADOW_THICKNESS
,
437 XmNrightAttachment
, XmATTACH_FORM
,
438 XmNrightOffset
, STAT_SHADOW_THICKNESS
,
439 XmNbottomOffset
, STAT_SHADOW_THICKNESS
, NULL
);
440 if(window
->showISearchLine
)
441 XtManageChild(window
->iSearchForm
);
443 /* Disable keyboard traversal of the find, clear and toggle buttons. We
444 were doing this previously by forcing the keyboard focus back to the
445 text widget whenever a toggle changed. That causes an ugly focus flash
446 on screen. It's better just not to go there in the first place.
447 Plus, if the user really wants traversal, it's an X resource so it
448 can be enabled without too much pain and suffering. */
451 isrcFind
= createBitmapWithDepth(window
->iSearchForm
,
452 (char *)isrcFind_bits
, isrcFind_width
, isrcFind_height
);
454 window
->iSearchFindButton
= XtVaCreateManagedWidget("iSearchFindButton",
455 xmPushButtonWidgetClass
, window
->iSearchForm
,
456 XmNlabelString
, s1
=XmStringCreateSimple("Find"),
457 XmNlabelType
, XmPIXMAP
,
458 XmNlabelPixmap
, isrcFind
,
459 XmNtraversalOn
, False
,
462 XmNleftAttachment
, XmATTACH_FORM
,
463 /* XmNleftOffset, 3, */
465 XmNtopAttachment
, XmATTACH_FORM
,
467 XmNbottomAttachment
, XmATTACH_FORM
,
472 window
->iSearchCaseToggle
= XtVaCreateManagedWidget("iSearchCaseToggle",
473 xmToggleButtonWidgetClass
, window
->iSearchForm
,
474 XmNlabelString
, s1
=XmStringCreateSimple("Case"),
475 XmNset
, GetPrefSearch() == SEARCH_CASE_SENSE
476 || GetPrefSearch() == SEARCH_REGEX
477 || GetPrefSearch() == SEARCH_CASE_SENSE_WORD
,
478 XmNtopAttachment
, XmATTACH_FORM
,
479 XmNbottomAttachment
, XmATTACH_FORM
,
480 XmNtopOffset
, 1, /* see openmotif note above */
481 XmNrightAttachment
, XmATTACH_FORM
,
483 XmNtraversalOn
, False
,
487 window
->iSearchRegexToggle
= XtVaCreateManagedWidget("iSearchREToggle",
488 xmToggleButtonWidgetClass
, window
->iSearchForm
,
489 XmNlabelString
, s1
=XmStringCreateSimple("RegExp"),
490 XmNset
, GetPrefSearch() == SEARCH_REGEX_NOCASE
491 || GetPrefSearch() == SEARCH_REGEX
,
492 XmNtopAttachment
, XmATTACH_FORM
,
493 XmNbottomAttachment
, XmATTACH_FORM
,
494 XmNtopOffset
, 1, /* see openmotif note above */
495 XmNrightAttachment
, XmATTACH_WIDGET
,
496 XmNrightWidget
, window
->iSearchCaseToggle
,
498 XmNtraversalOn
, False
,
502 window
->iSearchRevToggle
= XtVaCreateManagedWidget("iSearchRevToggle",
503 xmToggleButtonWidgetClass
, window
->iSearchForm
,
504 XmNlabelString
, s1
=XmStringCreateSimple("Rev"),
506 XmNtopAttachment
, XmATTACH_FORM
,
507 XmNbottomAttachment
, XmATTACH_FORM
,
508 XmNtopOffset
, 1, /* see openmotif note above */
509 XmNrightAttachment
, XmATTACH_WIDGET
,
510 XmNrightWidget
, window
->iSearchRegexToggle
,
512 XmNtraversalOn
, False
,
516 if (isrcClear
== 0) {
517 isrcClear
= createBitmapWithDepth(window
->iSearchForm
,
518 (char *)isrcClear_bits
, isrcClear_width
, isrcClear_height
);
520 window
->iSearchClearButton
= XtVaCreateManagedWidget("iSearchClearButton",
521 xmPushButtonWidgetClass
, window
->iSearchForm
,
522 XmNlabelString
, s1
=XmStringCreateSimple("<x"),
523 XmNlabelType
, XmPIXMAP
,
524 XmNlabelPixmap
, isrcClear
,
525 XmNtraversalOn
, False
,
528 XmNrightAttachment
, XmATTACH_WIDGET
,
529 XmNrightWidget
, window
->iSearchRevToggle
,
531 XmNtopAttachment
, XmATTACH_FORM
,
533 XmNbottomAttachment
, XmATTACH_FORM
,
538 window
->iSearchText
= XtVaCreateManagedWidget("iSearchText",
539 xmTextWidgetClass
, window
->iSearchForm
,
541 XmNnavigationType
, XmEXCLUSIVE_TAB_GROUP
,
542 XmNleftAttachment
, XmATTACH_WIDGET
,
543 XmNleftWidget
, window
->iSearchFindButton
,
544 XmNrightAttachment
, XmATTACH_WIDGET
,
545 XmNrightWidget
, window
->iSearchClearButton
,
546 /* XmNrightOffset, 5, */
547 XmNtopAttachment
, XmATTACH_FORM
,
548 XmNtopOffset
, 0, /* see openmotif note above */
549 XmNbottomAttachment
, XmATTACH_FORM
,
550 XmNbottomOffset
, 0, NULL
);
551 RemapDeleteKey(window
->iSearchText
);
553 SetISearchTextCallbacks(window
);
555 /* create the a form to house the tab bar and close-tab button */
556 tabForm
= XtVaCreateWidget("tabForm",
557 xmFormWidgetClass
, statsAreaForm
,
562 XmNleftAttachment
, XmATTACH_FORM
,
563 XmNrightAttachment
, XmATTACH_FORM
,
564 XmNshadowThickness
, 0, NULL
);
566 /* button to close top document */
567 if (closeTabPixmap
== 0) {
568 closeTabPixmap
= createBitmapWithDepth(tabForm
,
569 (char *)close_bits
, close_width
, close_height
);
571 closeTabBtn
= XtVaCreateManagedWidget("closeTabBtn",
572 xmPushButtonWidgetClass
, tabForm
,
575 XmNhighlightThickness
, 0,
576 XmNlabelType
, XmPIXMAP
,
577 XmNlabelPixmap
, closeTabPixmap
,
578 XmNshadowThickness
, 1,
579 XmNtraversalOn
, False
,
580 XmNrightAttachment
, XmATTACH_FORM
,
582 XmNbottomAttachment
, XmATTACH_FORM
,
585 XtAddCallback(closeTabBtn
, XmNactivateCallback
, (XtCallbackProc
)closeTabCB
,
588 /* create the tab bar */
589 window
->tabBar
= XtVaCreateManagedWidget("tabBar",
590 xmlFolderWidgetClass
, tabForm
,
591 XmNresizePolicy
, XmRESIZE_PACK
,
592 XmNleftAttachment
, XmATTACH_FORM
,
594 XmNrightAttachment
, XmATTACH_WIDGET
,
595 XmNrightWidget
, closeTabBtn
,
597 XmNbottomAttachment
, XmATTACH_FORM
,
599 XmNtopAttachment
, XmATTACH_FORM
,
602 window
->tabMenuPane
= CreateTabContextMenu(window
->tabBar
, window
);
603 AddTabContextMenuAction(window
->tabBar
);
605 /* create an unmanaged composite widget to get the folder
606 widget to hide the 3D shadow for the manager area.
607 Note: this works only on the patched XmLFolder widget */
608 form
= XtVaCreateWidget("form",
609 xmFormWidgetClass
, window
->tabBar
,
614 XtAddCallback(window
->tabBar
, XmNactivateCallback
,
617 window
->tab
= addTab(window
->tabBar
, name
);
619 /* A form to hold the stats line text and line/col widgets */
620 window
->statsLineForm
= XtVaCreateWidget("statsLineForm",
621 xmFormWidgetClass
, statsAreaForm
,
622 XmNshadowThickness
, 0,
623 XmNtopAttachment
, window
->showISearchLine
?
624 XmATTACH_WIDGET
: XmATTACH_FORM
,
625 XmNtopWidget
, window
->iSearchForm
,
626 XmNrightAttachment
, XmATTACH_FORM
,
627 XmNleftAttachment
, XmATTACH_FORM
,
628 XmNbottomAttachment
, XmATTACH_FORM
,
629 XmNresizable
, False
, /* */
632 /* A separate display of the line/column number */
633 window
->statsLineColNo
= XtVaCreateManagedWidget("statsLineColNo",
634 xmLabelWidgetClass
, window
->statsLineForm
,
635 XmNlabelString
, s1
=XmStringCreateSimple("L: --- C: ---"),
636 XmNshadowThickness
, 0,
638 XmNtraversalOn
, False
,
639 XmNtopAttachment
, XmATTACH_FORM
,
640 XmNrightAttachment
, XmATTACH_FORM
,
641 XmNbottomAttachment
, XmATTACH_FORM
, /* */
645 /* Create file statistics display area. Using a text widget rather than
646 a label solves a layout problem with the main window, which messes up
647 if the label is too long (we would need a resize callback to control
648 the length when the window changed size), and allows users to select
649 file names and line numbers. Colors are copied from parent
650 widget, because many users and some system defaults color text
651 backgrounds differently from other widgets. */
652 XtVaGetValues(window
->statsLineForm
, XmNbackground
, &bgpix
, NULL
);
653 XtVaGetValues(window
->statsLineForm
, XmNforeground
, &fgpix
, NULL
);
654 stats
= XtVaCreateManagedWidget("statsLine",
655 xmTextWidgetClass
, window
->statsLineForm
,
656 XmNbackground
, bgpix
,
657 XmNforeground
, fgpix
,
658 XmNshadowThickness
, 0,
659 XmNhighlightColor
, bgpix
,
660 XmNhighlightThickness
, 0, /* must be zero, for OM (2.1.30) to
661 aligns tatsLineColNo & statsLine */
662 XmNmarginHeight
, 1, /* == statsLineColNo.marginHeight - 1,
663 to align with statsLineColNo */
664 XmNscrollHorizontal
, False
,
665 XmNeditMode
, XmSINGLE_LINE_EDIT
,
667 XmNtraversalOn
, False
,
668 XmNcursorPositionVisible
, False
,
669 XmNtopAttachment
, XmATTACH_OPPOSITE_WIDGET
, /* */
670 XmNtopWidget
, window
->statsLineColNo
,
671 XmNleftAttachment
, XmATTACH_FORM
,
672 XmNrightAttachment
, XmATTACH_WIDGET
,
673 XmNrightWidget
, window
->statsLineColNo
,
674 XmNbottomAttachment
, XmATTACH_OPPOSITE_WIDGET
, /* */
675 XmNbottomWidget
, window
->statsLineColNo
,
678 window
->statsLine
= stats
;
680 /* Give the statsLine the same font as the statsLineColNo */
681 XtVaGetValues(window
->statsLineColNo
, XmNfontList
, &statsFontList
, NULL
);
682 XtVaSetValues(window
->statsLine
, XmNfontList
, statsFontList
, NULL
);
684 /* Manage the statsLineForm */
685 if(window
->showStats
)
686 XtManageChild(window
->statsLineForm
);
688 /* If the fontList was NULL, use the magical default provided by Motif,
689 since it must have worked if we've gotten this far */
690 if (window
->fontList
== NULL
)
691 XtVaGetValues(stats
, XmNfontList
, &window
->fontList
, NULL
);
693 /* Create the menu bar */
694 menuBar
= CreateMenuBar(mainWin
, window
);
695 window
->menuBar
= menuBar
;
696 XtManageChild(menuBar
);
698 /* Create paned window to manage split pane behavior */
699 pane
= XtVaCreateManagedWidget("pane", xmPanedWindowWidgetClass
, mainWin
,
700 XmNseparatorOn
, False
,
701 XmNspacing
, 3, XmNsashIndent
, -2, NULL
);
702 window
->splitPane
= pane
;
703 XmMainWindowSetAreas(mainWin
, menuBar
, statsAreaForm
, NULL
, NULL
, pane
);
705 /* Store a copy of document/window pointer in text pane to support
706 action procedures. See also WidgetToWindow() for info. */
707 XtVaSetValues(pane
, XmNuserData
, window
, NULL
);
709 /* Patch around Motif's most idiotic "feature", that its menu accelerators
710 recognize Caps Lock and Num Lock as modifiers, and don't trigger if
712 AccelLockBugPatch(pane
, window
->menuBar
);
714 /* Create the first, and most permanent text area (other panes may
715 be added & removed, but this one will never be removed */
716 text
= createTextArea(pane
, window
, rows
,cols
,
717 GetPrefEmTabDist(PLAIN_LANGUAGE_MODE
), GetPrefDelimiters(),
718 GetPrefWrapMargin(), window
->showLineNumbers
?MIN_LINE_NUM_COLS
:0);
720 window
->textArea
= text
;
721 window
->lastFocus
= text
;
723 /* Set the initial colors from the globals. */
725 GetPrefColorName(TEXT_FG_COLOR
),
726 GetPrefColorName(TEXT_BG_COLOR
),
727 GetPrefColorName(SELECT_FG_COLOR
),
728 GetPrefColorName(SELECT_BG_COLOR
),
729 GetPrefColorName(HILITE_FG_COLOR
),
730 GetPrefColorName(HILITE_BG_COLOR
),
731 GetPrefColorName(LINENO_FG_COLOR
),
732 GetPrefColorName(CURSOR_FG_COLOR
));
734 /* Create the right button popup menu (note: order is important here,
735 since the translation for popping up this menu was probably already
736 added in createTextArea, but CreateBGMenu requires window->textArea
737 to be set so it can attach the menu to it (because menu shells are
738 finicky about the kinds of widgets they are attached to)) */
739 window
->bgMenuPane
= CreateBGMenu(window
);
741 /* cache user menus: init. user background menu cache */
742 InitUserBGMenuCache(&window
->userBGMenuCache
);
744 /* Create the text buffer rather than using the one created automatically
745 with the text area widget. This is done so the syntax highlighting
746 modify callback can be called to synchronize the style buffer BEFORE
747 the text display's callback is called upon to display a modification */
748 window
->buffer
= BufCreate();
749 BufAddModifyCB(window
->buffer
, SyntaxHighlightModifyCB
, window
);
751 /* Attach the buffer to the text widget, and add callbacks for modify */
752 TextSetBuffer(text
, window
->buffer
);
753 BufAddModifyCB(window
->buffer
, modifiedCB
, window
);
755 /* Designate the permanent text area as the owner for selections */
756 HandleXSelections(text
);
758 /* Set the requested hardware tab distance and useTabs in the text buffer */
759 BufSetTabDistance(window
->buffer
, GetPrefTabDist(PLAIN_LANGUAGE_MODE
));
760 window
->buffer
->useTabs
= GetPrefInsertTabs();
762 /* add the window to the global window list, update the Windows menus */
763 addToWindowList(window
);
764 InvalidateWindowMenus();
766 showTabBar
= GetShowTabBar(window
);
768 XtManageChild(tabForm
);
770 manageToolBars(statsAreaForm
);
772 if (showTabBar
|| window
->showISearchLine
||
774 XtManageChild(statsAreaForm
);
776 /* realize all of the widgets in the new window */
777 RealizeWithoutForcingPosition(winShell
);
778 XmProcessTraversal(text
, XmTRAVERSE_CURRENT
);
780 /* Make close command in window menu gracefully prompt for close */
781 AddMotifCloseCallback(winShell
, (XtCallbackProc
)closeCB
, window
);
783 /* Make window resizing work in nice character heights */
784 UpdateWMSizeHints(window
);
786 /* Set the minimum pane height for the initial text pane */
787 UpdateMinPaneHeights(window
);
789 /* create dialogs shared by all documents in a window */
790 CreateFindDlog(window
->shell
, window
);
791 CreateReplaceDlog(window
->shell
, window
);
792 CreateReplaceMultiFileDlog(window
);
794 /* dim/undim Attach_Tab menu items */
795 state
= NDocuments(window
) < NWindows();
796 for(win
=WindowList
; win
; win
=win
->next
) {
797 if (IsTopDocument(win
)) {
798 XtSetSensitive(win
->moveDocumentItem
, state
);
799 XtSetSensitive(win
->contextMoveDocumentItem
, state
);
807 ** ButtonPress event handler for tabs.
809 static void tabClickEH(Widget w
, XtPointer clientData
, XEvent
*event
)
811 /* hide the tooltip when user clicks with any button. */
812 if (BubbleButton_Timer(w
)) {
813 XtRemoveTimeOut(BubbleButton_Timer(w
));
814 BubbleButton_Timer(w
) = (XtIntervalId
)NULL
;
822 ** add a tab to the tab bar for the new document.
824 static Widget
addTab(Widget folder
, const char *string
)
826 Widget tooltipLabel
, tab
;
829 s1
= XmStringCreateSimple((char *)string
);
830 tab
= XtVaCreateManagedWidget("tab",
831 xrwsBubbleButtonWidgetClass
, folder
,
832 /* XmNmarginWidth, <default@nedit.c>, */
833 /* XmNmarginHeight, <default@nedit.c>, */
834 /* XmNalignment, <default@nedit.c>, */
836 XltNbubbleString
, s1
,
837 XltNshowBubble
, GetPrefToolTips(),
838 XltNautoParkBubble
, True
,
839 XltNslidingBubble
, False
,
841 /* XltNbubbleDuration, 8000,*/
845 /* there's things to do as user click on the tab */
846 XtAddEventHandler(tab
, ButtonPressMask
, False
,
847 (XtEventHandler
)tabClickEH
, (XtPointer
)0);
849 /* BubbleButton simply use reversed video for tooltips,
850 we try to use the 'standard' color */
851 tooltipLabel
= XtNameToWidget(tab
, "*BubbleLabel");
852 XtVaSetValues(tooltipLabel
,
853 XmNbackground
, AllocateColor(tab
, GetPrefTooltipBgColor()),
854 XmNforeground
, AllocateColor(tab
, NEDIT_DEFAULT_FG
),
857 /* put borders around tooltip. BubbleButton use
858 transientShellWidgetClass as tooltip shell, which
859 came without borders */
860 XtVaSetValues(XtParent(tooltipLabel
), XmNborderWidth
, 1, NULL
);
862 #ifdef LESSTIF_VERSION
863 /* If we don't do this, no popup when right-click on tabs */
864 AddTabContextMenuAction(tab
);
865 #endif /* LESSTIF_VERSION */
871 ** Comparison function for sorting windows by title.
872 ** Windows are sorted by alphabetically by filename and then
873 ** alphabetically by path.
875 static int compareWindowNames(const void *windowA
, const void *windowB
)
878 const WindowInfo
*a
= *((WindowInfo
**)windowA
);
879 const WindowInfo
*b
= *((WindowInfo
**)windowB
);
881 rc
= strcmp(a
->filename
, b
->filename
);
884 rc
= strcmp(a
->path
, b
->path
);
889 ** Sort tabs in the tab bar alphabetically, if demanded so.
891 void SortTabBar(WindowInfo
*window
)
894 WindowInfo
**windows
;
896 int i
, j
, nDoc
, tabCount
;
898 if (!GetPrefSortTabs())
901 /* need more than one tab to sort */
902 nDoc
= NDocuments(window
);
906 /* first sort the documents */
907 windows
= (WindowInfo
**)XtMalloc(sizeof(WindowInfo
*) * nDoc
);
908 for (w
=WindowList
, i
=0; w
!=NULL
; w
=w
->next
) {
909 if (window
->shell
== w
->shell
)
912 qsort(windows
, nDoc
, sizeof(WindowInfo
*), compareWindowNames
);
914 /* assign tabs to documents in sorted order */
915 XtVaGetValues(window
->tabBar
, XmNtabWidgetList
, &tabList
,
916 XmNtabCount
, &tabCount
, NULL
);
918 for (i
=0, j
=0; i
<tabCount
&& j
<nDoc
; i
++) {
919 if (tabList
[i
]->core
.being_destroyed
)
922 /* set tab as active */
923 if (IsTopDocument(windows
[j
]))
924 XmLFolderSetActiveTab(window
->tabBar
, i
, False
);
926 windows
[j
]->tab
= tabList
[i
];
927 RefreshTabState(windows
[j
]);
931 XtFree((char *)windows
);
935 ** find which document a tab belongs to
937 WindowInfo
*TabToWindow(Widget tab
)
940 for (win
=WindowList
; win
; win
=win
->next
) {
949 ** Close a document, or an editor window
951 void CloseWindow(WindowInfo
*window
)
953 int keepWindow
, state
;
954 char name
[MAXPATHLEN
];
955 WindowInfo
*win
, *topBuf
= NULL
, *nextBuf
= NULL
;
957 /* Free smart indent macro programs */
958 EndSmartIndent(window
);
960 /* Clean up macro references to the doomed window. If a macro is
961 executing, stop it. If macro is calling this (closing its own
962 window), leave the window alive until the macro completes */
963 keepWindow
= !MacroWindowCloseActions(window
);
966 /* Kill shell sub-process and free related memory */
967 AbortShellCommand(window
);
970 /* Unload the default tips files for this language mode if necessary */
971 UnloadLanguageModeTipsFile(window
);
973 /* If a window is closed while it is on the multi-file replace dialog
974 list of any other window (or even the same one), we must update those
975 lists or we end up with dangling references. Normally, there can
976 be only one of those dialogs at the same time (application modal),
977 but LessTif doesn't even (always) honor application modalness, so
978 there can be more than one dialog. */
979 RemoveFromMultiReplaceDialog(window
);
981 /* Destroy the file closed property for this file */
982 DeleteFileClosedProperty(window
);
984 /* Remove any possibly pending callback which might fire after the
986 cancelTimeOut(&window
->flashTimeoutID
);
987 cancelTimeOut(&window
->markTimeoutID
);
989 /* if this is the last window, or must be kept alive temporarily because
990 it's running the macro calling us, don't close it, make it Untitled */
991 if (keepWindow
|| (WindowList
== window
&& window
->next
== NULL
)) {
992 window
->filename
[0] = '\0';
993 UniqueUntitledName(name
);
994 CLEAR_ALL_LOCKS(window
->lockReasons
);
995 window
->fileMode
= 0;
998 strcpy(window
->filename
, name
);
999 strcpy(window
->path
, "");
1000 window
->ignoreModify
= TRUE
;
1001 BufSetAll(window
->buffer
, "");
1002 window
->ignoreModify
= FALSE
;
1004 window
->filenameSet
= FALSE
;
1005 window
->fileMissing
= TRUE
;
1006 window
->fileChanged
= FALSE
;
1007 window
->fileFormat
= UNIX_FILE_FORMAT
;
1008 window
->lastModTime
= 0;
1012 StopHighlighting(window
);
1013 EndSmartIndent(window
);
1014 UpdateWindowTitle(window
);
1015 UpdateWindowReadOnly(window
);
1016 XtSetSensitive(window
->closeItem
, FALSE
);
1017 XtSetSensitive(window
->readOnlyItem
, TRUE
);
1018 XmToggleButtonSetState(window
->readOnlyItem
, FALSE
, FALSE
);
1019 ClearUndoList(window
);
1020 ClearRedoList(window
);
1021 XmTextSetString(window
->statsLine
, ""); /* resets scroll pos of stats
1022 line from long file names */
1023 UpdateStatsLine(window
);
1024 DetermineLanguageMode(window
, True
);
1025 RefreshTabState(window
);
1026 updateLineNumDisp(window
);
1030 /* Free syntax highlighting patterns, if any. w/o redisplaying */
1031 FreeHighlightingData(window
);
1033 /* remove the buffer modification callbacks so the buffer will be
1034 deallocated when the last text widget is destroyed */
1035 BufRemoveModifyCB(window
->buffer
, modifiedCB
, window
);
1036 BufRemoveModifyCB(window
->buffer
, SyntaxHighlightModifyCB
, window
);
1039 patchRowCol(window
->menuBar
);
1042 /* free the undo and redo lists */
1043 ClearUndoList(window
);
1044 ClearRedoList(window
);
1046 /* close the document/window */
1047 if (NDocuments(window
) > 1) {
1048 if (MacroRunWindow() && MacroRunWindow() != window
1049 && MacroRunWindow()->shell
== window
->shell
) {
1050 nextBuf
= MacroRunWindow();
1051 RaiseDocument(nextBuf
);
1052 } else if (IsTopDocument(window
)) {
1053 /* need to find a successor before closing a top document */
1054 nextBuf
= getNextTabWindow(window
, 1, 0, 0);
1055 RaiseDocument(nextBuf
);
1057 topBuf
= GetTopDocument(window
->shell
);
1061 /* remove the window from the global window list, update window menus */
1062 removeFromWindowList(window
);
1063 InvalidateWindowMenus();
1064 CheckCloseDim(); /* Close of window running a macro may have been disabled. */
1066 /* remove the tab of the closing document from tab bar */
1067 XtDestroyWidget(window
->tab
);
1069 /* refresh tab bar after closing a document */
1071 ShowWindowTabBar(nextBuf
);
1072 updateLineNumDisp(nextBuf
);
1073 } else if (topBuf
) {
1074 ShowWindowTabBar(topBuf
);
1075 updateLineNumDisp(topBuf
);
1078 /* dim/undim Detach_Tab menu items */
1079 win
= nextBuf
? nextBuf
: topBuf
;
1081 state
= NDocuments(win
) > 1;
1082 XtSetSensitive(win
->detachDocumentItem
, state
);
1083 XtSetSensitive(win
->contextDetachDocumentItem
, state
);
1086 /* dim/undim Attach_Tab menu items */
1087 state
= NDocuments(WindowList
) < NWindows();
1088 for(win
=WindowList
; win
; win
=win
->next
) {
1089 if (IsTopDocument(win
)) {
1090 XtSetSensitive(win
->moveDocumentItem
, state
);
1091 XtSetSensitive(win
->contextMoveDocumentItem
, state
);
1095 /* free background menu cache for document */
1096 FreeUserBGMenuCache(&window
->userBGMenuCache
);
1098 /* destroy the document's pane, or the window */
1099 if (nextBuf
|| topBuf
) {
1100 deleteDocument(window
);
1103 /* free user menu cache for window */
1104 FreeUserMenuCache(window
->userMenuCache
);
1106 /* remove and deallocate all of the widgets associated with window */
1107 XtFree(window
->backlightCharTypes
); /* we made a copy earlier on */
1108 CloseAllPopupsFor(window
->shell
);
1109 XtDestroyWidget(window
->shell
);
1112 /* deallocate the window data structure */
1113 XtFree((char*)window
);
1117 ** check if tab bar is to be shown on this window
1119 int GetShowTabBar(WindowInfo
*window
)
1121 if (!GetPrefTabBar())
1123 else if (NDocuments(window
) == 1)
1124 return !GetPrefTabBarHideOne();
1129 void ShowWindowTabBar(WindowInfo
*window
)
1131 if (GetPrefTabBar()) {
1132 if (GetPrefTabBarHideOne())
1133 ShowTabBar(window
, NDocuments(window
)>1);
1135 ShowTabBar(window
, True
);
1138 ShowTabBar(window
, False
);
1142 ** Check if there is already a window open for a given file
1144 WindowInfo
*FindWindowWithFile(const char *name
, const char *path
)
1148 /* I don't think this algorithm will work on vms so I am
1149 disabling it for now */
1151 if (!GetPrefHonorSymlinks())
1153 char fullname
[MAXPATHLEN
+ 1];
1154 struct stat attribute
;
1156 strncpy(fullname
, path
, MAXPATHLEN
);
1157 strncat(fullname
, name
, MAXPATHLEN
);
1158 fullname
[MAXPATHLEN
] = '\0';
1160 if (0 == stat(fullname
, &attribute
)) {
1161 for (window
= WindowList
; window
!= NULL
; window
= window
->next
) {
1162 if (attribute
.st_dev
== window
->device
1163 && attribute
.st_ino
== window
->inode
) {
1167 } /* else: Not an error condition, just a new file. Continue to check
1168 whether the filename is already in use for an unsaved document. */
1172 for (window
= WindowList
; window
!= NULL
; window
= window
->next
) {
1173 if (!strcmp(window
->filename
, name
) && !strcmp(window
->path
, path
)) {
1181 ** Add another independently scrollable pane to the current document,
1182 ** splitting the pane which currently has keyboard focus.
1184 void SplitPane(WindowInfo
*window
)
1186 short paneHeights
[MAX_PANES
+1];
1187 int insertPositions
[MAX_PANES
+1], topLines
[MAX_PANES
+1];
1188 int horizOffsets
[MAX_PANES
+1];
1189 int i
, focusPane
, emTabDist
, wrapMargin
, lineNumCols
, totalHeight
=0;
1192 textDisp
*textD
, *newTextD
;
1194 /* Don't create new panes if we're already at the limit */
1195 if (window
->nPanes
>= MAX_PANES
)
1198 /* Record the current heights, scroll positions, and insert positions
1199 of the existing panes, keyboard focus */
1201 for (i
=0; i
<=window
->nPanes
; i
++) {
1202 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1203 insertPositions
[i
] = TextGetCursorPos(text
);
1204 XtVaGetValues(containingPane(text
),XmNheight
,&paneHeights
[i
],NULL
);
1205 totalHeight
+= paneHeights
[i
];
1206 TextGetScroll(text
, &topLines
[i
], &horizOffsets
[i
]);
1207 if (text
== window
->lastFocus
)
1211 /* Unmanage & remanage the panedWindow so it recalculates pane heights */
1212 XtUnmanageChild(window
->splitPane
);
1214 /* Create a text widget to add to the pane and set its buffer and
1215 highlight data to be the same as the other panes in the document */
1216 XtVaGetValues(window
->textArea
, textNemulateTabs
, &emTabDist
,
1217 textNwordDelimiters
, &delimiters
, textNwrapMargin
, &wrapMargin
,
1218 textNlineNumCols
, &lineNumCols
, NULL
);
1219 text
= createTextArea(window
->splitPane
, window
, 1, 1, emTabDist
,
1220 delimiters
, wrapMargin
, lineNumCols
);
1222 TextSetBuffer(text
, window
->buffer
);
1223 if (window
->highlightData
!= NULL
)
1224 AttachHighlightToWidget(text
, window
);
1225 if (window
->backlightChars
)
1227 XtVaSetValues(text
, textNbacklightCharTypes
,
1228 window
->backlightCharTypes
, NULL
);
1230 XtManageChild(text
);
1231 window
->textPanes
[window
->nPanes
++] = text
;
1233 /* Fix up the colors */
1234 textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
1235 newTextD
= ((TextWidget
)text
)->text
.textD
;
1237 XmNforeground
, textD
->fgPixel
,
1238 XmNbackground
, textD
->bgPixel
,
1240 TextDSetColors( newTextD
, textD
->fgPixel
, textD
->bgPixel
,
1241 textD
->selectFGPixel
, textD
->selectBGPixel
, textD
->highlightFGPixel
,
1242 textD
->highlightBGPixel
, textD
->lineNumFGPixel
,
1243 textD
->cursorFGPixel
);
1245 /* Set the minimum pane height in the new pane */
1246 UpdateMinPaneHeights(window
);
1248 /* adjust the heights, scroll positions, etc., to split the focus pane */
1249 for (i
=window
->nPanes
; i
>focusPane
; i
--) {
1250 insertPositions
[i
] = insertPositions
[i
-1];
1251 paneHeights
[i
] = paneHeights
[i
-1];
1252 topLines
[i
] = topLines
[i
-1];
1253 horizOffsets
[i
] = horizOffsets
[i
-1];
1255 paneHeights
[focusPane
] = paneHeights
[focusPane
]/2;
1256 paneHeights
[focusPane
+1] = paneHeights
[focusPane
];
1258 for (i
=0; i
<=window
->nPanes
; i
++) {
1259 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1260 setPaneDesiredHeight(containingPane(text
), paneHeights
[i
]);
1263 /* Re-manage panedWindow to recalculate pane heights & reset selection */
1264 if (IsTopDocument(window
))
1265 XtManageChild(window
->splitPane
);
1267 /* Reset all of the heights, scroll positions, etc. */
1268 for (i
=0; i
<=window
->nPanes
; i
++) {
1269 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1270 TextSetCursorPos(text
, insertPositions
[i
]);
1271 TextSetScroll(text
, topLines
[i
], horizOffsets
[i
]);
1272 setPaneDesiredHeight(containingPane(text
),
1273 totalHeight
/(window
->nPanes
+1));
1275 XmProcessTraversal(window
->lastFocus
, XmTRAVERSE_CURRENT
);
1277 /* Update the window manager size hints after the sizes of the panes have
1278 been set (the widget heights are not yet readable here, but they will
1279 be by the time the event loop gets around to running this timer proc) */
1280 XtAppAddTimeOut(XtWidgetToApplicationContext(window
->shell
), 0,
1281 wmSizeUpdateProc
, window
);
1284 Widget
GetPaneByIndex(WindowInfo
*window
, int paneIndex
)
1287 if (paneIndex
>= 0 && paneIndex
<= window
->nPanes
) {
1288 text
= (paneIndex
== 0) ? window
->textArea
: window
->textPanes
[paneIndex
- 1];
1293 int WidgetToPaneIndex(WindowInfo
*window
, Widget w
)
1299 for (i
= 0; i
<= window
->nPanes
; ++i
) {
1300 text
= (i
== 0) ? window
->textArea
: window
->textPanes
[i
- 1];
1309 ** Close the window pane that last had the keyboard focus. (Actually, close
1310 ** the bottom pane and make it look like pane which had focus was closed)
1312 void ClosePane(WindowInfo
*window
)
1314 short paneHeights
[MAX_PANES
+1];
1315 int insertPositions
[MAX_PANES
+1], topLines
[MAX_PANES
+1];
1316 int horizOffsets
[MAX_PANES
+1];
1320 /* Don't delete the last pane */
1321 if (window
->nPanes
<= 0)
1324 /* Record the current heights, scroll positions, and insert positions
1325 of the existing panes, and the keyboard focus */
1327 for (i
=0; i
<=window
->nPanes
; i
++) {
1328 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1329 insertPositions
[i
] = TextGetCursorPos(text
);
1330 XtVaGetValues(containingPane(text
),
1331 XmNheight
, &paneHeights
[i
], NULL
);
1332 TextGetScroll(text
, &topLines
[i
], &horizOffsets
[i
]);
1333 if (text
== window
->lastFocus
)
1337 /* Unmanage & remanage the panedWindow so it recalculates pane heights */
1338 XtUnmanageChild(window
->splitPane
);
1340 /* Destroy last pane, and make sure lastFocus points to an existing pane.
1341 Workaround for OM 2.1.30: text widget must be unmanaged for
1342 xmPanedWindowWidget to calculate the correct pane heights for
1343 the remaining panes, simply detroying it didn't seem enough */
1345 XtUnmanageChild(containingPane(window
->textPanes
[window
->nPanes
]));
1346 XtDestroyWidget(containingPane(window
->textPanes
[window
->nPanes
]));
1348 if (window
->nPanes
== 0)
1349 window
->lastFocus
= window
->textArea
;
1350 else if (focusPane
> window
->nPanes
)
1351 window
->lastFocus
= window
->textPanes
[window
->nPanes
-1];
1353 /* adjust the heights, scroll positions, etc., to make it look
1354 like the pane with the input focus was closed */
1355 for (i
=focusPane
; i
<=window
->nPanes
; i
++) {
1356 insertPositions
[i
] = insertPositions
[i
+1];
1357 paneHeights
[i
] = paneHeights
[i
+1];
1358 topLines
[i
] = topLines
[i
+1];
1359 horizOffsets
[i
] = horizOffsets
[i
+1];
1362 /* set the desired heights and re-manage the paned window so it will
1363 recalculate pane heights */
1364 for (i
=0; i
<=window
->nPanes
; i
++) {
1365 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1366 setPaneDesiredHeight(containingPane(text
), paneHeights
[i
]);
1369 if (IsTopDocument(window
))
1370 XtManageChild(window
->splitPane
);
1372 /* Reset all of the scroll positions, insert positions, etc. */
1373 for (i
=0; i
<=window
->nPanes
; i
++) {
1374 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1375 TextSetCursorPos(text
, insertPositions
[i
]);
1376 TextSetScroll(text
, topLines
[i
], horizOffsets
[i
]);
1378 XmProcessTraversal(window
->lastFocus
, XmTRAVERSE_CURRENT
);
1380 /* Update the window manager size hints after the sizes of the panes have
1381 been set (the widget heights are not yet readable here, but they will
1382 be by the time the event loop gets around to running this timer proc) */
1383 XtAppAddTimeOut(XtWidgetToApplicationContext(window
->shell
), 0,
1384 wmSizeUpdateProc
, window
);
1388 ** Turn on and off the display of line numbers
1390 void ShowLineNumbers(WindowInfo
*window
, int state
)
1394 unsigned reqCols
= 0;
1395 Dimension windowWidth
;
1397 textDisp
*textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
1399 if (window
->showLineNumbers
== state
)
1401 window
->showLineNumbers
= state
;
1403 /* Just setting window->showLineNumbers is sufficient to tell
1404 updateLineNumDisp() to expand the line number areas and the window
1405 size for the number of lines required. To hide the line number
1406 display, set the width to zero, and contract the window width. */
1408 reqCols
= updateLineNumDisp(window
);
1410 XtVaGetValues(window
->shell
, XmNwidth
, &windowWidth
, NULL
);
1411 XtVaGetValues(window
->textArea
,
1412 textNmarginWidth
, &marginWidth
, NULL
);
1413 XtVaSetValues(window
->shell
, XmNwidth
,
1414 windowWidth
- textD
->left
+ marginWidth
, NULL
);
1416 for (i
=0; i
<=window
->nPanes
; i
++) {
1417 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1418 XtVaSetValues(text
, textNlineNumCols
, 0, NULL
);
1422 /* line numbers panel is shell-level, hence other
1423 tabbed documents in the window should synch */
1424 for (win
=WindowList
; win
; win
=win
->next
) {
1425 if (win
->shell
!= window
->shell
|| win
== window
)
1428 win
->showLineNumbers
= state
;
1430 for (i
=0; i
<=win
->nPanes
; i
++) {
1431 text
= i
==0 ? win
->textArea
: win
->textPanes
[i
-1];
1432 /* reqCols should really be cast here, but into what? XmRInt? */
1433 XtVaSetValues(text
, textNlineNumCols
, reqCols
, NULL
);
1437 /* Tell WM that the non-expandable part of the window has changed size */
1438 UpdateWMSizeHints(window
);
1441 void SetTabDist(WindowInfo
*window
, int tabDist
)
1443 if (window
->buffer
->tabDist
!= tabDist
) {
1444 int saveCursorPositions
[MAX_PANES
+ 1];
1445 int saveVScrollPositions
[MAX_PANES
+ 1];
1446 int saveHScrollPositions
[MAX_PANES
+ 1];
1449 window
->ignoreModify
= True
;
1451 for (paneIndex
= 0; paneIndex
<= window
->nPanes
; ++paneIndex
) {
1452 Widget w
= GetPaneByIndex(window
, paneIndex
);
1453 textDisp
*textD
= ((TextWidget
)w
)->text
.textD
;
1455 TextGetScroll(w
, &saveVScrollPositions
[paneIndex
], &saveHScrollPositions
[paneIndex
]);
1456 saveCursorPositions
[paneIndex
] = TextGetCursorPos(w
);
1457 textD
->modifyingTabDist
= 1;
1460 BufSetTabDistance(window
->buffer
, tabDist
);
1462 for (paneIndex
= 0; paneIndex
<= window
->nPanes
; ++paneIndex
) {
1463 Widget w
= GetPaneByIndex(window
, paneIndex
);
1464 textDisp
*textD
= ((TextWidget
)w
)->text
.textD
;
1466 textD
->modifyingTabDist
= 0;
1467 TextSetCursorPos(w
, saveCursorPositions
[paneIndex
]);
1468 TextSetScroll(w
, saveVScrollPositions
[paneIndex
], saveHScrollPositions
[paneIndex
]);
1471 window
->ignoreModify
= False
;
1475 void SetEmTabDist(WindowInfo
*window
, int emTabDist
)
1479 XtVaSetValues(window
->textArea
, textNemulateTabs
, emTabDist
, NULL
);
1480 for (i
= 0; i
< window
->nPanes
; ++i
) {
1481 XtVaSetValues(window
->textPanes
[i
], textNemulateTabs
, emTabDist
, NULL
);
1486 ** Turn on and off the display of the statistics line
1488 void ShowStatsLine(WindowInfo
*window
, int state
)
1494 /* In continuous wrap mode, text widgets must be told to keep track of
1495 the top line number in absolute (non-wrapped) lines, because it can
1496 be a costly calculation, and is only needed for displaying line
1497 numbers, either in the stats line, or along the left margin */
1498 for (i
=0; i
<=window
->nPanes
; i
++) {
1499 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1500 TextDMaintainAbsLineNum(((TextWidget
)text
)->text
.textD
, state
);
1502 window
->showStats
= state
;
1503 showStats(window
, state
);
1505 /* i-search line is shell-level, hence other tabbed
1506 documents in the window should synch */
1507 for (win
=WindowList
; win
; win
=win
->next
) {
1508 if (win
->shell
!= window
->shell
|| win
== window
)
1510 win
->showStats
= state
;
1515 ** Displays and undisplays the statistics line (regardless of settings of
1516 ** window->showStats or window->modeMessageDisplayed)
1518 static void showStats(WindowInfo
*window
, int state
)
1521 XtManageChild(window
->statsLineForm
);
1522 showStatsForm(window
);
1524 XtUnmanageChild(window
->statsLineForm
);
1525 showStatsForm(window
);
1528 /* Tell WM that the non-expandable part of the window has changed size */
1529 /* Already done in showStatsForm */
1530 /* UpdateWMSizeHints(window); */
1535 static void showTabBar(WindowInfo
*window
, int state
)
1538 XtManageChild(XtParent(window
->tabBar
));
1539 showStatsForm(window
);
1541 XtUnmanageChild(XtParent(window
->tabBar
));
1542 showStatsForm(window
);
1548 void ShowTabBar(WindowInfo
*window
, int state
)
1550 if (XtIsManaged(XtParent(window
->tabBar
)) == state
)
1552 showTabBar(window
, state
);
1556 ** Turn on and off the continuing display of the incremental search line
1557 ** (when off, it is popped up and down as needed via TempShowISearch)
1559 void ShowISearchLine(WindowInfo
*window
, int state
)
1563 if (window
->showISearchLine
== state
)
1565 window
->showISearchLine
= state
;
1566 showISearch(window
, state
);
1568 /* i-search line is shell-level, hence other tabbed
1569 documents in the window should synch */
1570 for (win
=WindowList
; win
; win
=win
->next
) {
1571 if (win
->shell
!= window
->shell
|| win
== window
)
1573 win
->showISearchLine
= state
;
1578 ** Temporarily show and hide the incremental search line if the line is not
1581 void TempShowISearch(WindowInfo
*window
, int state
)
1583 if (window
->showISearchLine
)
1585 if (XtIsManaged(window
->iSearchForm
) != state
)
1586 showISearch(window
, state
);
1590 ** Put up or pop-down the incremental search line regardless of settings
1591 ** of showISearchLine or TempShowISearch
1593 static void showISearch(WindowInfo
*window
, int state
)
1596 XtManageChild(window
->iSearchForm
);
1597 showStatsForm(window
);
1599 XtUnmanageChild(window
->iSearchForm
);
1600 showStatsForm(window
);
1603 /* Tell WM that the non-expandable part of the window has changed size */
1604 /* This is already done in showStatsForm */
1605 /* UpdateWMSizeHints(window); */
1609 ** Show or hide the extra display area under the main menu bar which
1610 ** optionally contains the status line and the incremental search bar
1612 static void showStatsForm(WindowInfo
*window
)
1614 Widget statsAreaForm
= XtParent(window
->statsLineForm
);
1615 Widget mainW
= XtParent(statsAreaForm
);
1617 /* The very silly use of XmNcommandWindowLocation and XmNshowSeparator
1618 below are to kick the main window widget to position and remove the
1619 status line when it is managed and unmanaged. At some Motif version
1620 level, the showSeparator trick backfires and leaves the separator
1621 shown, but fortunately the dynamic behavior is fixed, too so the
1622 workaround is no longer necessary, either. (... the version where
1623 this occurs may be earlier than 2.1. If the stats line shows
1624 double thickness shadows in earlier Motif versions, the #if XmVersion
1625 directive should be moved back to that earlier version) */
1626 if (manageToolBars(statsAreaForm
)) {
1627 XtUnmanageChild(statsAreaForm
); /*... will this fix Solaris 7??? */
1628 XtVaSetValues(mainW
, XmNcommandWindowLocation
,
1629 XmCOMMAND_ABOVE_WORKSPACE
, NULL
);
1630 #if XmVersion < 2001
1631 XtVaSetValues(mainW
, XmNshowSeparator
, True
, NULL
);
1633 XtManageChild(statsAreaForm
);
1634 XtVaSetValues(mainW
, XmNshowSeparator
, False
, NULL
);
1635 UpdateStatsLine(window
);
1637 XtUnmanageChild(statsAreaForm
);
1638 XtVaSetValues(mainW
, XmNcommandWindowLocation
,
1639 XmCOMMAND_BELOW_WORKSPACE
, NULL
);
1642 /* Tell WM that the non-expandable part of the window has changed size */
1643 UpdateWMSizeHints(window
);
1647 ** Display a special message in the stats line (show the stats line if it
1648 ** is not currently shown).
1650 void SetModeMessage(WindowInfo
*window
, const char *message
)
1652 /* this document may be hidden (not on top) or later made hidden,
1653 so we save a copy of the mode message, so we can restore the
1654 statsline when the document is raised to top again */
1655 window
->modeMessageDisplayed
= True
;
1656 XtFree(window
->modeMessage
);
1657 window
->modeMessage
= XtNewString(message
);
1659 if (!IsTopDocument(window
))
1662 XmTextSetString(window
->statsLine
, (char*)message
);
1664 * Don't invoke the stats line again, if stats line is already displayed.
1666 if (!window
->showStats
)
1667 showStats(window
, True
);
1671 ** Clear special statistics line message set in SetModeMessage, returns
1672 ** the statistics line to its original state as set in window->showStats
1674 void ClearModeMessage(WindowInfo
*window
)
1676 if (!window
->modeMessageDisplayed
)
1679 window
->modeMessageDisplayed
= False
;
1680 XtFree(window
->modeMessage
);
1681 window
->modeMessage
= NULL
;
1683 if (!IsTopDocument(window
))
1687 * Remove the stats line only if indicated by it's window state.
1689 if (!window
->showStats
)
1690 showStats(window
, False
);
1691 UpdateStatsLine(window
);
1695 ** Count the windows
1702 for (win
=WindowList
, n
=0; win
!=NULL
; win
=win
->next
, n
++);
1707 ** Set autoindent state to one of NO_AUTO_INDENT, AUTO_INDENT, or SMART_INDENT.
1709 void SetAutoIndent(WindowInfo
*window
, int state
)
1711 int autoIndent
= state
== AUTO_INDENT
, smartIndent
= state
== SMART_INDENT
;
1714 if (window
->indentStyle
== SMART_INDENT
&& !smartIndent
)
1715 EndSmartIndent(window
);
1716 else if (smartIndent
&& window
->indentStyle
!= SMART_INDENT
)
1717 BeginSmartIndent(window
, True
);
1718 window
->indentStyle
= state
;
1719 XtVaSetValues(window
->textArea
, textNautoIndent
, autoIndent
,
1720 textNsmartIndent
, smartIndent
, NULL
);
1721 for (i
=0; i
<window
->nPanes
; i
++)
1722 XtVaSetValues(window
->textPanes
[i
], textNautoIndent
, autoIndent
,
1723 textNsmartIndent
, smartIndent
, NULL
);
1724 if (IsTopDocument(window
)) {
1725 XmToggleButtonSetState(window
->smartIndentItem
, smartIndent
, False
);
1726 XmToggleButtonSetState(window
->autoIndentItem
, autoIndent
, False
);
1727 XmToggleButtonSetState(window
->autoIndentOffItem
,
1728 state
== NO_AUTO_INDENT
, False
);
1733 ** Set showMatching state to one of NO_FLASH, FLASH_DELIMIT or FLASH_RANGE.
1734 ** Update the menu to reflect the change of state.
1736 void SetShowMatching(WindowInfo
*window
, int state
)
1738 window
->showMatchingStyle
= state
;
1739 if (IsTopDocument(window
)) {
1740 XmToggleButtonSetState(window
->showMatchingOffItem
,
1741 state
== NO_FLASH
, False
);
1742 XmToggleButtonSetState(window
->showMatchingDelimitItem
,
1743 state
== FLASH_DELIMIT
, False
);
1744 XmToggleButtonSetState(window
->showMatchingRangeItem
,
1745 state
== FLASH_RANGE
, False
);
1750 ** Update the "New (in X)" menu item to reflect the preferences
1752 void UpdateNewOppositeMenu(WindowInfo
*window
, int openInTab
)
1756 XtVaSetValues(window
->newOppositeItem
,
1757 XmNlabelString
, lbl
=XmStringCreateSimple("New Window"),
1758 XmNmnemonic
, 'W', NULL
);
1760 XtVaSetValues(window
->newOppositeItem
,
1761 XmNlabelString
, lbl
=XmStringCreateSimple("New Tab"),
1762 XmNmnemonic
, 'T', NULL
);
1767 ** Set the fonts for "window" from a font name, and updates the display.
1768 ** Also updates window->fontList which is used for statistics line.
1770 ** Note that this leaks memory and server resources. In previous NEdit
1771 ** versions, fontLists were carefully tracked and freed, but X and Motif
1772 ** have some kind of timing problem when widgets are distroyed, such that
1773 ** fonts may not be freed immediately after widget destruction with 100%
1774 ** safety. Rather than kludge around this with timerProcs, I have chosen
1775 ** to create new fontLists only when the user explicitly changes the font
1776 ** (which shouldn't happen much in normal NEdit operation), and skip the
1777 ** futile effort of freeing them.
1779 void SetFonts(WindowInfo
*window
, const char *fontName
, const char *italicName
,
1780 const char *boldName
, const char *boldItalicName
)
1782 XFontStruct
*font
, *oldFont
;
1783 int i
, oldFontWidth
, oldFontHeight
, fontWidth
, fontHeight
;
1784 int borderWidth
, borderHeight
, marginWidth
, marginHeight
;
1785 int primaryChanged
, highlightChanged
= False
;
1786 Dimension oldWindowWidth
, oldWindowHeight
, oldTextWidth
, oldTextHeight
;
1787 Dimension textHeight
, newWindowWidth
, newWindowHeight
;
1788 textDisp
*textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
1790 /* Check which fonts have changed */
1791 primaryChanged
= strcmp(fontName
, window
->fontName
);
1792 if (strcmp(italicName
, window
->italicFontName
)) highlightChanged
= True
;
1793 if (strcmp(boldName
, window
->boldFontName
)) highlightChanged
= True
;
1794 if (strcmp(boldItalicName
, window
->boldItalicFontName
))
1795 highlightChanged
= True
;
1796 if (!primaryChanged
&& !highlightChanged
)
1799 /* Get information about the current window sizing, to be used to
1800 determine the correct window size after the font is changed */
1801 XtVaGetValues(window
->shell
, XmNwidth
, &oldWindowWidth
, XmNheight
,
1802 &oldWindowHeight
, NULL
);
1803 XtVaGetValues(window
->textArea
, XmNheight
, &textHeight
,
1804 textNmarginHeight
, &marginHeight
, textNmarginWidth
,
1805 &marginWidth
, textNfont
, &oldFont
, NULL
);
1806 oldTextWidth
= textD
->width
+ textD
->lineNumWidth
;
1807 oldTextHeight
= textHeight
- 2*marginHeight
;
1808 for (i
=0; i
<window
->nPanes
; i
++) {
1809 XtVaGetValues(window
->textPanes
[i
], XmNheight
, &textHeight
, NULL
);
1810 oldTextHeight
+= textHeight
- 2*marginHeight
;
1812 borderWidth
= oldWindowWidth
- oldTextWidth
;
1813 borderHeight
= oldWindowHeight
- oldTextHeight
;
1814 oldFontWidth
= oldFont
->max_bounds
.width
;
1815 oldFontHeight
= textD
->ascent
+ textD
->descent
;
1818 /* Change the fonts in the window data structure. If the primary font
1819 didn't work, use Motif's fallback mechanism by stealing it from the
1820 statistics line. Highlight fonts are allowed to be NULL, which
1821 is interpreted as "use the primary font" */
1822 if (primaryChanged
) {
1823 strcpy(window
->fontName
, fontName
);
1824 font
= XLoadQueryFont(TheDisplay
, fontName
);
1826 XtVaGetValues(window
->statsLine
, XmNfontList
, &window
->fontList
,
1829 window
->fontList
= XmFontListCreate(font
, XmSTRING_DEFAULT_CHARSET
);
1831 if (highlightChanged
) {
1832 strcpy(window
->italicFontName
, italicName
);
1833 window
->italicFontStruct
= XLoadQueryFont(TheDisplay
, italicName
);
1834 strcpy(window
->boldFontName
, boldName
);
1835 window
->boldFontStruct
= XLoadQueryFont(TheDisplay
, boldName
);
1836 strcpy(window
->boldItalicFontName
, boldItalicName
);
1837 window
->boldItalicFontStruct
= XLoadQueryFont(TheDisplay
, boldItalicName
);
1840 /* Change the primary font in all the widgets */
1841 if (primaryChanged
) {
1842 font
= GetDefaultFontStruct(window
->fontList
);
1843 XtVaSetValues(window
->textArea
, textNfont
, font
, NULL
);
1844 for (i
=0; i
<window
->nPanes
; i
++)
1845 XtVaSetValues(window
->textPanes
[i
], textNfont
, font
, NULL
);
1848 /* Change the highlight fonts, even if they didn't change, because
1849 primary font is read through the style table for syntax highlighting */
1850 if (window
->highlightData
!= NULL
)
1851 UpdateHighlightStyles(window
);
1853 /* Change the window manager size hints.
1854 Note: this has to be done _before_ we set the new sizes. ICCCM2
1855 compliant window managers (such as fvwm2) would otherwise resize
1856 the window twice: once because of the new sizes requested, and once
1857 because of the new size increments, resulting in an overshoot. */
1858 UpdateWMSizeHints(window
);
1860 /* Use the information from the old window to re-size the window to a
1861 size appropriate for the new font, but only do so if there's only
1862 _one_ document in the window, in order to avoid growing-window bug */
1863 if (NDocuments(window
) == 1) {
1864 fontWidth
= GetDefaultFontStruct(window
->fontList
)->max_bounds
.width
;
1865 fontHeight
= textD
->ascent
+ textD
->descent
;
1866 newWindowWidth
= (oldTextWidth
*fontWidth
) / oldFontWidth
+ borderWidth
;
1867 newWindowHeight
= (oldTextHeight
*fontHeight
) / oldFontHeight
+
1869 XtVaSetValues(window
->shell
, XmNwidth
, newWindowWidth
, XmNheight
,
1870 newWindowHeight
, NULL
);
1873 /* Change the minimum pane height */
1874 UpdateMinPaneHeights(window
);
1877 void SetColors(WindowInfo
*window
, const char *textFg
, const char *textBg
,
1878 const char *selectFg
, const char *selectBg
, const char *hiliteFg
,
1879 const char *hiliteBg
, const char *lineNoFg
, const char *cursorFg
)
1882 Pixel textFgPix
= AllocColor( window
->textArea
, textFg
,
1883 &dummy
, &dummy
, &dummy
),
1884 textBgPix
= AllocColor( window
->textArea
, textBg
,
1885 &dummy
, &dummy
, &dummy
),
1886 selectFgPix
= AllocColor( window
->textArea
, selectFg
,
1887 &dummy
, &dummy
, &dummy
),
1888 selectBgPix
= AllocColor( window
->textArea
, selectBg
,
1889 &dummy
, &dummy
, &dummy
),
1890 hiliteFgPix
= AllocColor( window
->textArea
, hiliteFg
,
1891 &dummy
, &dummy
, &dummy
),
1892 hiliteBgPix
= AllocColor( window
->textArea
, hiliteBg
,
1893 &dummy
, &dummy
, &dummy
),
1894 lineNoFgPix
= AllocColor( window
->textArea
, lineNoFg
,
1895 &dummy
, &dummy
, &dummy
),
1896 cursorFgPix
= AllocColor( window
->textArea
, cursorFg
,
1897 &dummy
, &dummy
, &dummy
);
1900 /* Update the main pane */
1901 XtVaSetValues(window
->textArea
,
1902 XmNforeground
, textFgPix
,
1903 XmNbackground
, textBgPix
,
1905 textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
1906 TextDSetColors( textD
, textFgPix
, textBgPix
, selectFgPix
, selectBgPix
,
1907 hiliteFgPix
, hiliteBgPix
, lineNoFgPix
, cursorFgPix
);
1908 /* Update any additional panes */
1909 for (i
=0; i
<window
->nPanes
; i
++) {
1910 XtVaSetValues(window
->textPanes
[i
],
1911 XmNforeground
, textFgPix
,
1912 XmNbackground
, textBgPix
,
1914 textD
= ((TextWidget
)window
->textPanes
[i
])->text
.textD
;
1915 TextDSetColors( textD
, textFgPix
, textBgPix
, selectFgPix
, selectBgPix
,
1916 hiliteFgPix
, hiliteBgPix
, lineNoFgPix
, cursorFgPix
);
1919 /* Redo any syntax highlighting */
1920 if (window
->highlightData
!= NULL
)
1921 UpdateHighlightStyles(window
);
1925 ** Set insert/overstrike mode
1927 void SetOverstrike(WindowInfo
*window
, int overstrike
)
1931 XtVaSetValues(window
->textArea
, textNoverstrike
, overstrike
, NULL
);
1932 for (i
=0; i
<window
->nPanes
; i
++)
1933 XtVaSetValues(window
->textPanes
[i
], textNoverstrike
, overstrike
, NULL
);
1934 window
->overstrike
= overstrike
;
1938 ** Select auto-wrap mode, one of NO_WRAP, NEWLINE_WRAP, or CONTINUOUS_WRAP
1940 void SetAutoWrap(WindowInfo
*window
, int state
)
1943 int autoWrap
= state
== NEWLINE_WRAP
, contWrap
= state
== CONTINUOUS_WRAP
;
1945 XtVaSetValues(window
->textArea
, textNautoWrap
, autoWrap
,
1946 textNcontinuousWrap
, contWrap
, NULL
);
1947 for (i
=0; i
<window
->nPanes
; i
++)
1948 XtVaSetValues(window
->textPanes
[i
], textNautoWrap
, autoWrap
,
1949 textNcontinuousWrap
, contWrap
, NULL
);
1950 window
->wrapMode
= state
;
1952 if (IsTopDocument(window
)) {
1953 XmToggleButtonSetState(window
->newlineWrapItem
, autoWrap
, False
);
1954 XmToggleButtonSetState(window
->continuousWrapItem
, contWrap
, False
);
1955 XmToggleButtonSetState(window
->noWrapItem
, state
== NO_WRAP
, False
);
1960 ** Set the auto-scroll margin
1962 void SetAutoScroll(WindowInfo
*window
, int margin
)
1966 XtVaSetValues(window
->textArea
, textNcursorVPadding
, margin
, NULL
);
1967 for (i
=0; i
<window
->nPanes
; i
++)
1968 XtVaSetValues(window
->textPanes
[i
], textNcursorVPadding
, margin
, NULL
);
1972 ** Recover the window pointer from any widget in the window, by searching
1973 ** up the widget hierarcy for the top level container widget where the
1974 ** window pointer is stored in the userData field. In a tabbed window,
1975 ** this is the window pointer of the top (active) document, which is
1976 ** returned if w is 'shell-level' widget - menus, find/replace dialogs, etc.
1978 ** To support action routine in tabbed windows, a copy of the window
1979 ** pointer is also store in the splitPane widget.
1981 WindowInfo
*WidgetToWindow(Widget w
)
1983 WindowInfo
*window
= NULL
;
1987 /* return window pointer of document */
1988 if (XtClass(w
) == xmPanedWindowWidgetClass
)
1991 if (XtClass(w
) == topLevelShellWidgetClass
) {
1994 /* there should be only 1 child for the shell -
1995 the main window widget */
1996 XtVaGetValues(w
, XmNchildren
, &items
, NULL
);
2001 parent
= XtParent(w
);
2005 /* make sure it is not a dialog shell */
2006 if (XtClass(parent
) == topLevelShellWidgetClass
&&
2013 XtVaGetValues(w
, XmNuserData
, &window
, NULL
);
2019 ** Change the window appearance and the window data structure to show
2020 ** that the file it contains has been modified
2022 void SetWindowModified(WindowInfo
*window
, int modified
)
2024 if (window
->fileChanged
== FALSE
&& modified
== TRUE
) {
2025 SetSensitive(window
, window
->closeItem
, TRUE
);
2026 window
->fileChanged
= TRUE
;
2027 UpdateWindowTitle(window
);
2028 RefreshTabState(window
);
2029 } else if (window
->fileChanged
== TRUE
&& modified
== FALSE
) {
2030 window
->fileChanged
= FALSE
;
2031 UpdateWindowTitle(window
);
2032 RefreshTabState(window
);
2037 ** Update the window title to reflect the filename, read-only, and modified
2038 ** status of the window data structure
2040 void UpdateWindowTitle(const WindowInfo
*window
)
2042 char *iconTitle
, *title
;
2044 if (!IsTopDocument(window
))
2047 title
= FormatWindowTitle(window
->filename
,
2052 GetClearCaseViewTag(),
2054 GetPrefServerName(),
2056 window
->filenameSet
,
2057 window
->lockReasons
,
2058 window
->fileChanged
,
2059 GetPrefTitleFormat());
2061 iconTitle
= XtMalloc(strlen(window
->filename
) + 2); /* strlen("*")+1 */
2063 strcpy(iconTitle
, window
->filename
);
2064 if (window
->fileChanged
)
2065 strcat(iconTitle
, "*");
2066 XtVaSetValues(window
->shell
, XmNtitle
, title
, XmNiconName
, iconTitle
, NULL
);
2068 /* If there's a find or replace dialog up in "Keep Up" mode, with a
2069 file name in the title, update it too */
2070 if (window
->findDlog
&& XmToggleButtonGetState(window
->findKeepBtn
)) {
2071 sprintf(title
, "Find (in %s)", window
->filename
);
2072 XtVaSetValues(XtParent(window
->findDlog
), XmNtitle
, title
, NULL
);
2074 if (window
->replaceDlog
&& XmToggleButtonGetState(window
->replaceKeepBtn
)) {
2075 sprintf(title
, "Replace (in %s)", window
->filename
);
2076 XtVaSetValues(XtParent(window
->replaceDlog
), XmNtitle
, title
, NULL
);
2080 /* Update the Windows menus with the new name */
2081 InvalidateWindowMenus();
2085 ** Update the read-only state of the text area(s) in the window, and
2086 ** the ReadOnly toggle button in the File menu to agree with the state in
2087 ** the window data structure.
2089 void UpdateWindowReadOnly(WindowInfo
*window
)
2093 if (!IsTopDocument(window
))
2096 state
= IS_ANY_LOCKED(window
->lockReasons
);
2097 XtVaSetValues(window
->textArea
, textNreadOnly
, state
, NULL
);
2098 for (i
=0; i
<window
->nPanes
; i
++)
2099 XtVaSetValues(window
->textPanes
[i
], textNreadOnly
, state
, NULL
);
2100 XmToggleButtonSetState(window
->readOnlyItem
, state
, FALSE
);
2101 XtSetSensitive(window
->readOnlyItem
,
2102 !IS_ANY_LOCKED_IGNORING_USER(window
->lockReasons
));
2106 ** Find the start and end of a single line selection. Hides rectangular
2107 ** selection issues for older routines which use selections that won't
2110 int GetSimpleSelection(textBuffer
*buf
, int *left
, int *right
)
2112 int selStart
, selEnd
, isRect
, rectStart
, rectEnd
, lineStart
;
2114 /* get the character to match and its position from the selection, or
2115 the character before the insert point if nothing is selected.
2116 Give up if too many characters are selected */
2117 if (!BufGetSelectionPos(buf
, &selStart
, &selEnd
, &isRect
,
2118 &rectStart
, &rectEnd
))
2121 lineStart
= BufStartOfLine(buf
, selStart
);
2122 selStart
= BufCountForwardDispChars(buf
, lineStart
, rectStart
);
2123 selEnd
= BufCountForwardDispChars(buf
, lineStart
, rectEnd
);
2131 ** If the selection (or cursor position if there's no selection) is not
2132 ** fully shown, scroll to bring it in to view. Note that as written,
2133 ** this won't work well with multi-line selections. Modest re-write
2134 ** of the horizontal scrolling part would be quite easy to make it work
2135 ** well with rectangular selections.
2137 void MakeSelectionVisible(WindowInfo
*window
, Widget textPane
)
2139 int left
, right
, isRect
, rectStart
, rectEnd
, horizOffset
;
2140 int scrollOffset
, leftX
, rightX
, y
, rows
, margin
;
2141 int topLineNum
, lastLineNum
, rightLineNum
, leftLineNum
, linesToScroll
;
2142 textDisp
*textD
= ((TextWidget
)textPane
)->text
.textD
;
2143 int topChar
= TextFirstVisiblePos(textPane
);
2144 int lastChar
= TextLastVisiblePos(textPane
);
2148 /* find out where the selection is */
2149 if (!BufGetSelectionPos(window
->buffer
, &left
, &right
, &isRect
,
2150 &rectStart
, &rectEnd
)) {
2151 left
= right
= TextGetCursorPos(textPane
);
2155 /* Check vertical positioning unless the selection is already shown or
2156 already covers the display. If the end of the selection is below
2157 bottom, scroll it in to view until the end selection is scrollOffset
2158 lines from the bottom of the display or the start of the selection
2159 scrollOffset lines from the top. Calculate a pleasing distance from the
2160 top or bottom of the window, to scroll the selection to (if scrolling is
2161 necessary), around 1/3 of the height of the window */
2162 if (!((left
>= topChar
&& right
<= lastChar
) ||
2163 (left
<= topChar
&& right
>= lastChar
))) {
2164 XtVaGetValues(textPane
, textNrows
, &rows
, NULL
);
2165 scrollOffset
= rows
/3;
2166 TextGetScroll(textPane
, &topLineNum
, &horizOffset
);
2167 if (right
> lastChar
) {
2168 /* End of sel. is below bottom of screen */
2169 leftLineNum
= topLineNum
+
2170 TextDCountLines(textD
, topChar
, left
, False
);
2171 targetLineNum
= topLineNum
+ scrollOffset
;
2172 if (leftLineNum
>= targetLineNum
) {
2173 /* Start of sel. is not between top & target */
2174 linesToScroll
= TextDCountLines(textD
, lastChar
, right
, False
) +
2176 if (leftLineNum
- linesToScroll
< targetLineNum
)
2177 linesToScroll
= leftLineNum
- targetLineNum
;
2178 /* Scroll start of selection to the target line */
2179 TextSetScroll(textPane
, topLineNum
+linesToScroll
, horizOffset
);
2181 } else if (left
< topChar
) {
2182 /* Start of sel. is above top of screen */
2183 lastLineNum
= topLineNum
+ rows
;
2184 rightLineNum
= lastLineNum
-
2185 TextDCountLines(textD
, right
, lastChar
, False
);
2186 targetLineNum
= lastLineNum
- scrollOffset
;
2187 if (rightLineNum
<= targetLineNum
) {
2188 /* End of sel. is not between bottom & target */
2189 linesToScroll
= TextDCountLines(textD
, left
, topChar
, False
) +
2191 if (rightLineNum
+ linesToScroll
> targetLineNum
)
2192 linesToScroll
= targetLineNum
- rightLineNum
;
2193 /* Scroll end of selection to the target line */
2194 TextSetScroll(textPane
, topLineNum
-linesToScroll
, horizOffset
);
2199 /* If either end of the selection off screen horizontally, try to bring it
2200 in view, by making sure both end-points are visible. Using only end
2201 points of a multi-line selection is not a great idea, and disaster for
2202 rectangular selections, so this part of the routine should be re-written
2203 if it is to be used much with either. Note also that this is a second
2204 scrolling operation, causing the display to jump twice. It's done after
2205 vertical scrolling to take advantage of TextPosToXY which requires it's
2206 reqested position to be vertically on screen) */
2207 if ( TextPosToXY(textPane
, left
, &leftX
, &y
) &&
2208 TextPosToXY(textPane
, right
, &rightX
, &y
) && leftX
<= rightX
) {
2209 TextGetScroll(textPane
, &topLineNum
, &horizOffset
);
2210 XtVaGetValues(textPane
, XmNwidth
, &width
, textNmarginWidth
, &margin
,
2212 if (leftX
< margin
+ textD
->lineNumLeft
+ textD
->lineNumWidth
)
2214 margin
+ textD
->lineNumLeft
+ textD
->lineNumWidth
- leftX
;
2215 else if (rightX
> width
- margin
)
2216 horizOffset
+= rightX
- (width
- margin
);
2217 TextSetScroll(textPane
, topLineNum
, horizOffset
);
2220 /* make sure that the statistics line is up to date */
2221 UpdateStatsLine(window
);
2224 static Widget
createTextArea(Widget parent
, WindowInfo
*window
, int rows
,
2225 int cols
, int emTabDist
, char *delimiters
, int wrapMargin
,
2228 Widget text
, sw
, hScrollBar
, vScrollBar
, frame
;
2230 /* Create a text widget inside of a scrolled window widget */
2231 sw
= XtVaCreateManagedWidget("scrolledW", xmScrolledWindowWidgetClass
,
2232 parent
, XmNpaneMaximum
, SHRT_MAX
,
2233 XmNpaneMinimum
, PANE_MIN_HEIGHT
, XmNhighlightThickness
, 0, NULL
);
2234 hScrollBar
= XtVaCreateManagedWidget("textHorScrollBar",
2235 xmScrollBarWidgetClass
, sw
, XmNorientation
, XmHORIZONTAL
,
2236 XmNrepeatDelay
, 10, NULL
);
2237 vScrollBar
= XtVaCreateManagedWidget("textVertScrollBar",
2238 xmScrollBarWidgetClass
, sw
, XmNorientation
, XmVERTICAL
,
2239 XmNrepeatDelay
, 10, NULL
);
2240 frame
= XtVaCreateManagedWidget("textFrame", xmFrameWidgetClass
, sw
,
2241 XmNshadowType
, XmSHADOW_IN
, NULL
);
2242 text
= XtVaCreateManagedWidget("text", textWidgetClass
, frame
,
2243 textNbacklightCharTypes
, window
->backlightCharTypes
,
2244 textNrows
, rows
, textNcolumns
, cols
,
2245 textNlineNumCols
, lineNumCols
,
2246 textNemulateTabs
, emTabDist
,
2247 textNfont
, GetDefaultFontStruct(window
->fontList
),
2248 textNhScrollBar
, hScrollBar
, textNvScrollBar
, vScrollBar
,
2249 textNreadOnly
, IS_ANY_LOCKED(window
->lockReasons
),
2250 textNwordDelimiters
, delimiters
,
2251 textNwrapMargin
, wrapMargin
,
2252 textNautoIndent
, window
->indentStyle
== AUTO_INDENT
,
2253 textNsmartIndent
, window
->indentStyle
== SMART_INDENT
,
2254 textNautoWrap
, window
->wrapMode
== NEWLINE_WRAP
,
2255 textNcontinuousWrap
, window
->wrapMode
== CONTINUOUS_WRAP
,
2256 textNoverstrike
, window
->overstrike
,
2257 textNhidePointer
, (Boolean
) GetPrefTypingHidesPointer(),
2258 textNcursorVPadding
, GetVerticalAutoScroll(),
2261 XtVaSetValues(sw
, XmNworkWindow
, frame
, XmNhorizontalScrollBar
,
2262 hScrollBar
, XmNverticalScrollBar
, vScrollBar
, NULL
);
2264 /* add focus, drag, cursor tracking, and smart indent callbacks */
2265 XtAddCallback(text
, textNfocusCallback
, (XtCallbackProc
)focusCB
, window
);
2266 XtAddCallback(text
, textNcursorMovementCallback
, (XtCallbackProc
)movedCB
,
2268 XtAddCallback(text
, textNdragStartCallback
, (XtCallbackProc
)dragStartCB
,
2270 XtAddCallback(text
, textNdragEndCallback
, (XtCallbackProc
)dragEndCB
,
2272 XtAddCallback(text
, textNsmartIndentCallback
, SmartIndentCB
, window
);
2274 /* This makes sure the text area initially has a the insert point shown
2275 ... (check if still true with the nedit text widget, probably not) */
2276 XmAddTabGroup(containingPane(text
));
2278 /* compensate for Motif delete/backspace problem */
2279 RemapDeleteKey(text
);
2281 /* Augment translation table for right button popup menu */
2282 AddBGMenuAction(text
);
2284 /* If absolute line numbers will be needed for display in the statistics
2285 line, tell the widget to maintain them (otherwise, it's a costly
2286 operation and performance will be better without it) */
2287 TextDMaintainAbsLineNum(((TextWidget
)text
)->text
.textD
, window
->showStats
);
2292 static void movedCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2294 TextWidget textWidget
= (TextWidget
) w
;
2296 if (window
->ignoreModify
)
2299 /* update line and column nubers in statistics line */
2300 UpdateStatsLine(window
);
2302 /* Check the character before the cursor for matchable characters */
2303 FlashMatching(window
, w
);
2305 /* Check for changes to read-only status and/or file modifications */
2306 CheckForChangesToFile(window
);
2308 /* This callback is not only called for focussed panes, but for newly
2309 created panes as well. So make sure that the cursor is left alone
2310 for unfocussed panes.
2311 TextWidget have no state per se about focus, so we use the related
2312 ID for the blink procedure. */
2313 if (0 != textWidget
->text
.cursorBlinkProcID
)
2315 /* Start blinking the caret again. */
2316 ResetCursorBlink(textWidget
, False
);
2320 static void modifiedCB(int pos
, int nInserted
, int nDeleted
, int nRestyled
,
2321 const char *deletedText
, void *cbArg
)
2323 WindowInfo
*window
= (WindowInfo
*)cbArg
;
2324 int selected
= window
->buffer
->primary
.selected
;
2326 /* update the table of bookmarks */
2327 if (!window
->ignoreModify
) {
2328 UpdateMarkTable(window
, pos
, nInserted
, nDeleted
);
2331 /* Check and dim/undim selection related menu items */
2332 if ((window
->wasSelected
&& !selected
) ||
2333 (!window
->wasSelected
&& selected
)) {
2334 window
->wasSelected
= selected
;
2336 /* do not refresh shell-level items (window, menu-bar etc)
2337 when motifying non-top document */
2338 if (IsTopDocument(window
)) {
2339 XtSetSensitive(window
->printSelItem
, selected
);
2340 XtSetSensitive(window
->cutItem
, selected
);
2341 XtSetSensitive(window
->copyItem
, selected
);
2342 XtSetSensitive(window
->delItem
, selected
);
2343 /* Note we don't change the selection for items like
2344 "Open Selected" and "Find Selected". That's because
2345 it works on selections in external applications.
2346 Desensitizing it if there's no NEdit selection
2347 disables this feature. */
2349 XtSetSensitive(window
->filterItem
, selected
);
2352 DimSelectionDepUserMenuItems(window
, selected
);
2353 if (window
->replaceDlog
!= NULL
&& XtIsManaged(window
->replaceDlog
))
2355 UpdateReplaceActionButtons(window
);
2360 /* When the program needs to make a change to a text area without without
2361 recording it for undo or marking file as changed it sets ignoreModify */
2362 if (window
->ignoreModify
|| (nDeleted
== 0 && nInserted
== 0))
2365 /* Make sure line number display is sufficient for new data */
2366 updateLineNumDisp(window
);
2368 /* Save information for undoing this operation (this call also counts
2369 characters and editing operations for triggering autosave */
2370 SaveUndoInformation(window
, pos
, nInserted
, nDeleted
, deletedText
);
2372 /* Trigger automatic backup if operation or character limits reached */
2373 if (window
->autoSave
&&
2374 (window
->autoSaveCharCount
> AUTOSAVE_CHAR_LIMIT
||
2375 window
->autoSaveOpCount
> AUTOSAVE_OP_LIMIT
)) {
2376 WriteBackupFile(window
);
2377 window
->autoSaveCharCount
= 0;
2378 window
->autoSaveOpCount
= 0;
2381 /* Indicate that the window has now been modified */
2382 SetWindowModified(window
, TRUE
);
2384 /* Update # of bytes, and line and col statistics */
2385 UpdateStatsLine(window
);
2387 /* Check if external changes have been made to file and warn user */
2388 CheckForChangesToFile(window
);
2391 static void focusCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2393 /* record which window pane last had the keyboard focus */
2394 window
->lastFocus
= w
;
2396 /* update line number statistic to reflect current focus pane */
2397 UpdateStatsLine(window
);
2399 /* finish off the current incremental search */
2402 /* Check for changes to read-only status and/or file modifications */
2403 CheckForChangesToFile(window
);
2406 static void dragStartCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2408 /* don't record all of the intermediate drag steps for undo */
2409 window
->ignoreModify
= True
;
2412 static void dragEndCB(Widget w
, WindowInfo
*window
, dragEndCBStruct
*callData
)
2414 /* restore recording of undo information */
2415 window
->ignoreModify
= False
;
2417 /* Do nothing if drag operation was canceled */
2418 if (callData
->nCharsInserted
== 0)
2421 /* Save information for undoing this operation not saved while
2422 undo recording was off */
2423 modifiedCB(callData
->startPos
, callData
->nCharsInserted
,
2424 callData
->nCharsDeleted
, 0, callData
->deletedText
, window
);
2427 static void closeCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2429 window
= WidgetToWindow(w
);
2430 if (!WindowCanBeClosed(window
)) {
2434 CloseDocumentWindow(w
, window
, callData
);
2437 #ifndef NO_SESSION_RESTART
2438 static void saveYourselfCB(Widget w
, Widget appShell
, XtPointer callData
)
2440 WindowInfo
*win
, *topWin
, **revWindowList
;
2441 char geometry
[MAX_GEOM_STRING_LEN
];
2442 int argc
= 0, maxArgc
, nWindows
, i
;
2444 int wasIconic
= False
;
2446 WidgetList children
;
2448 /* Allocate memory for an argument list and for a reversed list of
2449 windows. The window list is reversed for IRIX 4DWM and any other
2450 window/session manager combination which uses window creation
2451 order for re-associating stored geometry information with
2452 new windows created by a restored application */
2453 maxArgc
= 4; /* nedit -server -svrname name */
2455 for (win
=WindowList
; win
!=NULL
; win
=win
->next
) {
2456 maxArgc
+= 5; /* -iconic -group -geometry WxH+x+y filename */
2459 argv
= (char **)XtMalloc(maxArgc
*sizeof(char *));
2460 revWindowList
= (WindowInfo
**)XtMalloc(sizeof(WindowInfo
*)*nWindows
);
2461 for (win
=WindowList
, i
=nWindows
-1; win
!=NULL
; win
=win
->next
, i
--)
2462 revWindowList
[i
] = win
;
2464 /* Create command line arguments for restoring each window in the list */
2465 argv
[argc
++] = XtNewString(ArgV0
);
2467 argv
[argc
++] = XtNewString("-server");
2468 if (GetPrefServerName()[0] != '\0') {
2469 argv
[argc
++] = XtNewString("-svrname");
2470 argv
[argc
++] = XtNewString(GetPrefServerName());
2474 /* editor windows are popup-shell children of top-level appShell */
2475 XtVaGetValues(appShell
, XmNchildren
, &children
,
2476 XmNnumChildren
, &nItems
, NULL
);
2478 for (n
=nItems
-1; n
>=0; n
--) {
2482 if (strcmp(XtName(children
[n
]), "textShell") ||
2483 ((topWin
= WidgetToWindow(children
[n
])) == NULL
))
2484 continue; /* skip non-editor windows */
2486 /* create a group for each window */
2487 getGeometryString(topWin
, geometry
);
2488 argv
[argc
++] = XtNewString("-group");
2489 argv
[argc
++] = XtNewString("-geometry");
2490 argv
[argc
++] = XtNewString(geometry
);
2491 if (IsIconic(topWin
)) {
2492 argv
[argc
++] = XtNewString("-iconic");
2494 } else if (wasIconic
) {
2495 argv
[argc
++] = XtNewString("-noiconic");
2499 /* add filename of each tab in window... */
2500 XtVaGetValues(topWin
->tabBar
, XmNtabWidgetList
, &tabs
,
2501 XmNtabCount
, &tabCount
, NULL
);
2503 for (i
=0; i
< tabCount
; i
++) {
2504 win
= TabToWindow(tabs
[i
]);
2505 if (win
->filenameSet
) {
2507 argv
[argc
] = XtMalloc(strlen(win
->path
) +
2508 strlen(win
->filename
) + 1);
2509 sprintf(argv
[argc
++], "%s%s", win
->path
, win
->filename
);
2514 XtFree((char *)revWindowList
);
2516 /* Set the window's WM_COMMAND property to the created command line */
2517 XSetCommand(TheDisplay
, XtWindow(appShell
), argv
, argc
);
2518 for (i
=0; i
<argc
; i
++)
2520 XtFree((char *)argv
);
2523 void AttachSessionMgrHandler(Widget appShell
)
2525 static Atom wmpAtom
, syAtom
= 0;
2527 /* Add wm protocol callback for making nedit restartable by session
2528 managers. Doesn't yet handle multiple-desktops or iconifying right. */
2530 wmpAtom
= XmInternAtom(TheDisplay
, "WM_PROTOCOLS", FALSE
);
2531 syAtom
= XmInternAtom(TheDisplay
, "WM_SAVE_YOURSELF", FALSE
);
2533 XmAddProtocolCallback(appShell
, wmpAtom
, syAtom
,
2534 (XtCallbackProc
)saveYourselfCB
, (XtPointer
)appShell
);
2536 #endif /* NO_SESSION_RESTART */
2539 ** Returns true if window is iconic (as determined by the WM_STATE property
2540 ** on the shell window. I think this is the most reliable way to tell,
2541 ** but if someone has a better idea please send me a note).
2543 int IsIconic(WindowInfo
*window
)
2545 unsigned long *property
= NULL
;
2546 unsigned long nItems
;
2547 unsigned long leftover
;
2548 static Atom wmStateAtom
= 0;
2553 if (wmStateAtom
== 0)
2554 wmStateAtom
= XInternAtom(XtDisplay(window
->shell
), "WM_STATE", False
);
2555 if (XGetWindowProperty(XtDisplay(window
->shell
), XtWindow(window
->shell
),
2556 wmStateAtom
, 0L, 1L, False
, wmStateAtom
, &actualType
, &actualFormat
,
2557 &nItems
, &leftover
, (unsigned char **)&property
) != Success
||
2558 nItems
!= 1 || property
== NULL
)
2560 result
= *property
== IconicState
;
2561 XtFree((char *)property
);
2566 ** Add a window to the the window list.
2568 static void addToWindowList(WindowInfo
*window
)
2573 WindowList
= window
;
2574 window
->next
= temp
;
2578 ** Remove a window from the list of windows
2580 static void removeFromWindowList(WindowInfo
*window
)
2584 if (WindowList
== window
)
2585 WindowList
= window
->next
;
2587 for (temp
= WindowList
; temp
!= NULL
; temp
= temp
->next
) {
2588 if (temp
->next
== window
) {
2589 temp
->next
= window
->next
;
2597 ** Set the new gutter width in the window. Sadly, the only way to do this is
2598 ** to set it on every single document, so we have to iterate over them.
2600 ** (Iteration taken from NDocuments(); is there a better way to do it?)
2602 static int updateGutterWidth(WindowInfo
* window
)
2604 WindowInfo
* document
;
2605 int reqCols
= MIN_LINE_NUM_COLS
;
2606 int newColsDiff
= 0;
2609 for (document
= WindowList
; NULL
!= document
; document
= document
->next
) {
2610 if (document
->shell
== window
->shell
) {
2611 /* We found ourselves a document from this window. */
2612 int lineNumCols
, tmpReqCols
;
2613 textDisp
*textD
= ((TextWidget
) document
->textArea
)->text
.textD
;
2615 XtVaGetValues(document
->textArea
,
2616 textNlineNumCols
, &lineNumCols
,
2619 /* Is the width of the line number area sufficient to display all the
2620 line numbers in the file? If not, expand line number field, and the
2623 if (lineNumCols
> maxCols
) {
2624 maxCols
= lineNumCols
;
2627 tmpReqCols
= textD
->nBufferLines
< 1
2629 : (int) log10((double) textD
->nBufferLines
+ 1) + 1;
2631 if (tmpReqCols
> reqCols
) {
2632 reqCols
= tmpReqCols
;
2637 if (reqCols
!= maxCols
) {
2639 Dimension windowWidth
;
2642 newColsDiff
= reqCols
- maxCols
;
2644 XtVaGetValues(window
->textArea
, textNfont
, &fs
, NULL
);
2645 fontWidth
= fs
->max_bounds
.width
;
2647 XtVaGetValues(window
->shell
, XmNwidth
, &windowWidth
, NULL
);
2648 XtVaSetValues(window
->shell
,
2649 XmNwidth
, (Dimension
) windowWidth
+ (newColsDiff
* fontWidth
),
2652 UpdateWMSizeHints(window
);
2655 for (document
= WindowList
; NULL
!= document
; document
= document
->next
) {
2656 if (document
->shell
== window
->shell
) {
2661 XtVaGetValues(document
->textArea
,
2662 textNlineNumCols
, &lineNumCols
, NULL
);
2664 if (lineNumCols
== reqCols
) {
2668 /* Update all panes of this document. */
2669 for (i
= 0; i
<= document
->nPanes
; i
++) {
2670 text
= 0==i
? document
->textArea
: document
->textPanes
[i
-1];
2671 XtVaSetValues(text
, textNlineNumCols
, reqCols
, NULL
);
2680 ** If necessary, enlarges the window and line number display area to make
2681 ** room for numbers.
2683 static int updateLineNumDisp(WindowInfo
* window
)
2685 if (!window
->showLineNumbers
) {
2689 /* Decide how wide the line number field has to be to display all
2690 possible line numbers */
2691 return updateGutterWidth(window
);
2695 ** Update the optional statistics line.
2697 void UpdateStatsLine(WindowInfo
*window
)
2699 int line
, pos
, colNum
;
2700 char *string
, *format
, slinecol
[32];
2701 Widget statW
= window
->statsLine
;
2702 XmString xmslinecol
;
2704 char *sleft
, *smid
, *sright
;
2707 if (!IsTopDocument(window
))
2710 /* This routine is called for each character typed, so its performance
2711 affects overall editor perfomance. Only update if the line is on. */
2712 if (!window
->showStats
)
2715 /* Compose the string to display. If line # isn't available, leave it off */
2716 pos
= TextGetCursorPos(window
->lastFocus
);
2717 string
= XtMalloc(strlen(window
->filename
) + strlen(window
->path
) + 45);
2718 format
= window
->fileFormat
== DOS_FILE_FORMAT
? " DOS" :
2719 (window
->fileFormat
== MAC_FILE_FORMAT
? " Mac" : "");
2720 if (!TextPosToLineAndCol(window
->lastFocus
, pos
, &line
, &colNum
)) {
2721 sprintf(string
, "%s%s%s %d bytes", window
->path
, window
->filename
,
2722 format
, window
->buffer
->length
);
2723 sprintf(slinecol
, "L: --- C: ---");
2725 sprintf(slinecol
, "L: %d C: %d", line
, colNum
);
2726 if (window
->showLineNumbers
)
2727 sprintf(string
, "%s%s%s byte %d of %d", window
->path
,
2728 window
->filename
, format
, pos
,
2729 window
->buffer
->length
);
2731 sprintf(string
, "%s%s%s %d bytes", window
->path
,
2732 window
->filename
, format
, window
->buffer
->length
);
2735 /* Update the line/column number */
2736 xmslinecol
= XmStringCreateSimple(slinecol
);
2737 XtVaSetValues( window
->statsLineColNo
,
2738 XmNlabelString
, xmslinecol
, NULL
);
2739 XmStringFree(xmslinecol
);
2741 /* Don't clobber the line if there's a special message being displayed */
2742 if (!window
->modeMessageDisplayed
) {
2743 /* Change the text in the stats line */
2745 /* don't show full pathname, just dir and filename (+ byte info) */
2746 smid
= strchr(string
, '/');
2747 if ( smid
!= NULL
) {
2749 sright
= strrchr(string
, '/');
2750 while (strcmp(smid
, sright
)) {
2752 smid
= strchr(sleft
+ 1, '/');
2754 XmTextReplace(statW
, 0, XmTextGetLastPosition(statW
), sleft
+ 1);
2756 XmTextReplace(statW
, 0, XmTextGetLastPosition(statW
), string
);
2758 XmTextReplace(statW
, 0, XmTextGetLastPosition(statW
), string
);
2763 /* Update the line/col display */
2764 xmslinecol
= XmStringCreateSimple(slinecol
);
2765 XtVaSetValues(window
->statsLineColNo
,
2766 XmNlabelString
, xmslinecol
, NULL
);
2767 XmStringFree(xmslinecol
);
2770 static Boolean currentlyBusy
= False
;
2771 static long busyStartTime
= 0;
2772 static Boolean modeMessageSet
= False
;
2775 * Auxiliary function for measuring elapsed time during busy waits.
2777 static long getRelTimeInTenthsOfSeconds()
2780 struct timeval current
;
2781 gettimeofday(¤t
, NULL
);
2782 return (current
.tv_sec
*10 + current
.tv_usec
/100000) & 0xFFFFFFFL
;
2786 return (current
*10) & 0xFFFFFFFL
;
2790 void AllWindowsBusy(const char *message
)
2796 busyStartTime
= getRelTimeInTenthsOfSeconds();
2797 modeMessageSet
= False
;
2799 for (w
=WindowList
; w
!=NULL
; w
=w
->next
)
2801 /* We don't the display message here yet, but defer it for
2802 a while. If the wait is short, we don't want
2803 to have it flash on and off the screen. However,
2804 we can't use a time since in generally we are in
2805 a tight loop and only processing exposure events, so it's
2806 up to the caller to make sure that this routine is called
2807 at regular intervals.
2809 BeginWait(w
->shell
);
2811 } else if (!modeMessageSet
&& message
&&
2812 getRelTimeInTenthsOfSeconds() - busyStartTime
> 10) {
2813 /* Show the mode message when we've been busy for more than a second */
2814 for (w
=WindowList
; w
!=NULL
; w
=w
->next
) {
2815 SetModeMessage(w
, message
);
2817 modeMessageSet
= True
;
2819 BusyWait(WindowList
->shell
);
2821 currentlyBusy
= True
;
2824 void AllWindowsUnbusy(void)
2828 for (w
=WindowList
; w
!=NULL
; w
=w
->next
)
2830 ClearModeMessage(w
);
2834 currentlyBusy
= False
;
2835 modeMessageSet
= False
;
2840 ** Paned windows are impossible to adjust after they are created, which makes
2841 ** them nearly useless for NEdit (or any application which needs to dynamically
2842 ** adjust the panes) unless you tweek some private data to overwrite the
2843 ** desired and minimum pane heights which were set at creation time. These
2844 ** will probably break in a future release of Motif because of dependence on
2847 static void setPaneDesiredHeight(Widget w
, int height
)
2849 ((XmPanedWindowConstraintPtr
)w
->core
.constraints
)->panedw
.dheight
= height
;
2851 static void setPaneMinHeight(Widget w
, int min
)
2853 ((XmPanedWindowConstraintPtr
)w
->core
.constraints
)->panedw
.min
= min
;
2857 ** Update the window manager's size hints. These tell it the increments in
2858 ** which it is allowed to resize the window. While this isn't particularly
2859 ** important for NEdit (since it can tolerate any window size), setting these
2860 ** hints also makes the resize indicator show the window size in characters
2861 ** rather than pixels, which is very helpful to users.
2863 void UpdateWMSizeHints(WindowInfo
*window
)
2865 Dimension shellWidth
, shellHeight
, textHeight
, hScrollBarHeight
;
2866 int marginHeight
, marginWidth
, totalHeight
, nCols
, nRows
;
2868 int i
, baseWidth
, baseHeight
, fontHeight
, fontWidth
;
2870 textDisp
*textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
2872 /* Find the dimensions of a single character of the text font */
2873 XtVaGetValues(window
->textArea
, textNfont
, &fs
, NULL
);
2874 fontHeight
= textD
->ascent
+ textD
->descent
;
2875 fontWidth
= fs
->max_bounds
.width
;
2877 /* Find the base (non-expandable) width and height of the editor window.
2880 To workaround the shrinking-window bug on some WM such as Metacity,
2881 which caused the window to shrink as we switch between documents
2882 using different font sizes on the documents in the same window, the
2883 base width, and similarly the base height, is ajusted such that:
2884 shellWidth = baseWidth + cols * textWidth
2885 There are two issues with this workaround:
2886 1. the right most characters may appear partially obsure
2887 2. the Col x Row info reported by the WM will be based on the fully
2890 XtVaGetValues(window
->textArea
, XmNheight
, &textHeight
,
2891 textNmarginHeight
, &marginHeight
, textNmarginWidth
, &marginWidth
,
2893 totalHeight
= textHeight
- 2*marginHeight
;
2894 for (i
=0; i
<window
->nPanes
; i
++) {
2895 XtVaGetValues(window
->textPanes
[i
], XmNheight
, &textHeight
,
2896 textNhScrollBar
, &hScrollBar
, NULL
);
2897 totalHeight
+= textHeight
- 2*marginHeight
;
2898 if (!XtIsManaged(hScrollBar
)) {
2899 XtVaGetValues(hScrollBar
, XmNheight
, &hScrollBarHeight
, NULL
);
2900 totalHeight
-= hScrollBarHeight
;
2904 XtVaGetValues(window
->shell
, XmNwidth
, &shellWidth
,
2905 XmNheight
, &shellHeight
, NULL
);
2906 nCols
= textD
->width
/ fontWidth
;
2907 nRows
= totalHeight
/ fontHeight
;
2908 baseWidth
= shellWidth
- nCols
* fontWidth
;
2909 baseHeight
= shellHeight
- nRows
* fontHeight
;
2911 /* Set the size hints in the shell widget */
2912 XtVaSetValues(window
->shell
, XmNwidthInc
, fs
->max_bounds
.width
,
2913 XmNheightInc
, fontHeight
,
2914 XmNbaseWidth
, baseWidth
, XmNbaseHeight
, baseHeight
,
2915 XmNminWidth
, baseWidth
+ fontWidth
,
2916 XmNminHeight
, baseHeight
+ (1+window
->nPanes
) * fontHeight
, NULL
);
2918 /* Motif will keep placing this on the shell every time we change it,
2919 so it needs to be undone every single time. This only seems to
2920 happen on mult-head dispalys on screens 1 and higher. */
2922 RemovePPositionHint(window
->shell
);
2926 ** Update the minimum allowable height for a split pane after a change
2927 ** to font or margin height.
2929 void UpdateMinPaneHeights(WindowInfo
*window
)
2931 textDisp
*textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
2932 Dimension hsbHeight
, swMarginHeight
,frameShadowHeight
;
2933 int i
, marginHeight
, minPaneHeight
;
2936 /* find the minimum allowable size for a pane */
2937 XtVaGetValues(window
->textArea
, textNhScrollBar
, &hScrollBar
, NULL
);
2938 XtVaGetValues(containingPane(window
->textArea
),
2939 XmNscrolledWindowMarginHeight
, &swMarginHeight
, NULL
);
2940 XtVaGetValues(XtParent(window
->textArea
),
2941 XmNshadowThickness
, &frameShadowHeight
, NULL
);
2942 XtVaGetValues(window
->textArea
, textNmarginHeight
, &marginHeight
, NULL
);
2943 XtVaGetValues(hScrollBar
, XmNheight
, &hsbHeight
, NULL
);
2944 minPaneHeight
= textD
->ascent
+ textD
->descent
+ marginHeight
*2 +
2945 swMarginHeight
*2 + hsbHeight
+ 2*frameShadowHeight
;
2947 /* Set it in all of the widgets in the window */
2948 setPaneMinHeight(containingPane(window
->textArea
), minPaneHeight
);
2949 for (i
=0; i
<window
->nPanes
; i
++)
2950 setPaneMinHeight(containingPane(window
->textPanes
[i
]),
2954 /* Add an icon to an applicaction shell widget. addWindowIcon adds a large
2955 ** (primary window) icon, AddSmallIcon adds a small (secondary window) icon.
2957 ** Note: I would prefer that these were not hardwired, but yhere is something
2958 ** weird about the XmNiconPixmap resource that prevents it from being set
2959 ** from the defaults in the application resource database.
2961 static void addWindowIcon(Widget shell
)
2963 static Pixmap iconPixmap
= 0, maskPixmap
= 0;
2965 if (iconPixmap
== 0) {
2966 iconPixmap
= XCreateBitmapFromData(TheDisplay
,
2967 RootWindowOfScreen(XtScreen(shell
)), (char *)iconBits
,
2968 iconBitmapWidth
, iconBitmapHeight
);
2969 maskPixmap
= XCreateBitmapFromData(TheDisplay
,
2970 RootWindowOfScreen(XtScreen(shell
)), (char *)maskBits
,
2971 iconBitmapWidth
, iconBitmapHeight
);
2973 XtVaSetValues(shell
, XmNiconPixmap
, iconPixmap
, XmNiconMask
, maskPixmap
,
2976 void AddSmallIcon(Widget shell
)
2978 static Pixmap iconPixmap
= 0, maskPixmap
= 0;
2980 if (iconPixmap
== 0) {
2981 iconPixmap
= XCreateBitmapFromData(TheDisplay
,
2982 RootWindowOfScreen(XtScreen(shell
)), (char *)n_bits
,
2984 maskPixmap
= XCreateBitmapFromData(TheDisplay
,
2985 RootWindowOfScreen(XtScreen(shell
)), (char *)n_mask
,
2988 XtVaSetValues(shell
, XmNiconPixmap
, iconPixmap
,
2989 XmNiconMask
, maskPixmap
, NULL
);
2993 ** Create pixmap per the widget's color depth setting.
2995 ** This fixes a BadMatch (X_CopyArea) error due to mismatching of
2996 ** color depth between the bitmap (depth of 1) and the screen,
2997 ** specifically on when linked to LessTif v1.2 (release 0.93.18
2998 ** & 0.93.94 tested). LessTif v2.x showed no such problem.
3000 static Pixmap
createBitmapWithDepth(Widget w
, char *data
, unsigned int width
,
3001 unsigned int height
)
3007 XtVaGetValues (w
, XmNforeground
, &fg
, XmNbackground
, &bg
,
3008 XmNdepth
, &depth
, NULL
);
3009 pixmap
= XCreatePixmapFromBitmapData(XtDisplay(w
),
3010 RootWindowOfScreen(XtScreen(w
)), (char *)data
,
3011 width
, height
, fg
, bg
, depth
);
3017 ** Save the position and size of a window as an X standard geometry string.
3018 ** A string of at least MAX_GEOMETRY_STRING_LEN characters should be
3019 ** provided in the argument "geomString" to receive the result.
3021 static void getGeometryString(WindowInfo
*window
, char *geomString
)
3023 int x
, y
, fontWidth
, fontHeight
, baseWidth
, baseHeight
;
3024 unsigned int width
, height
, dummyW
, dummyH
, bw
, depth
, nChild
;
3025 Window parent
, root
, *child
, w
= XtWindow(window
->shell
);
3026 Display
*dpy
= XtDisplay(window
->shell
);
3028 /* Find the width and height from the window of the shell */
3029 XGetGeometry(dpy
, w
, &root
, &x
, &y
, &width
, &height
, &bw
, &depth
);
3031 /* Find the top left corner (x and y) of the window decorations. (This
3032 is what's required in the geometry string to restore the window to it's
3033 original position, since the window manager re-parents the window to
3034 add it's title bar and menus, and moves the requested window down and
3035 to the left.) The position is found by traversing the window hier-
3036 archy back to the window to the last parent before the root window */
3038 XQueryTree(dpy
, w
, &root
, &parent
, &child
, &nChild
);
3039 XFree((char*)child
);
3044 XGetGeometry(dpy
, w
, &root
, &x
, &y
, &dummyW
, &dummyH
, &bw
, &depth
);
3046 /* Use window manager size hints (set by UpdateWMSizeHints) to
3047 translate the width and height into characters, as opposed to pixels */
3048 XtVaGetValues(window
->shell
, XmNwidthInc
, &fontWidth
,
3049 XmNheightInc
, &fontHeight
, XmNbaseWidth
, &baseWidth
,
3050 XmNbaseHeight
, &baseHeight
, NULL
);
3051 width
= (width
-baseWidth
) / fontWidth
;
3052 height
= (height
-baseHeight
) / fontHeight
;
3054 /* Write the string */
3055 CreateGeometryString(geomString
, x
, y
, width
, height
,
3056 XValue
| YValue
| WidthValue
| HeightValue
);
3060 ** Xt timer procedure for updating size hints. The new sizes of objects in
3061 ** the window are not ready immediately after adding or removing panes. This
3062 ** is a timer routine to be invoked with a timeout of 0 to give the event
3063 ** loop a chance to finish processing the size changes before reading them
3064 ** out for setting the window manager size hints.
3066 static void wmSizeUpdateProc(XtPointer clientData
, XtIntervalId
*id
)
3068 UpdateWMSizeHints((WindowInfo
*)clientData
);
3073 ** There is a bad memory reference in the delete_child method of the
3074 ** RowColumn widget in some Motif versions (so far, just Solaris with Motif
3075 ** 1.2.3) which appears durring the phase 2 destroy of the widget. This
3076 ** patch replaces the method with a call to the Composite widget's
3077 ** delete_child method. The composite delete_child method handles part,
3078 ** but not all of what would have been done by the original method, meaning
3079 ** that this is dangerous and should be used sparingly. Note that
3080 ** patchRowCol is called only in CloseWindow, before the widget is about to
3081 ** be destroyed, and only on systems where the bug has been observed
3083 static void patchRowCol(Widget w
)
3085 ((XmRowColumnClassRec
*)XtClass(w
))->composite_class
.delete_child
=
3088 static void patchedRemoveChild(Widget child
)
3090 /* Call composite class method instead of broken row col delete_child
3092 (*((CompositeWidgetClass
)compositeWidgetClass
)->composite_class
.
3093 delete_child
) (child
);
3095 #endif /* ROWCOLPATCH */
3098 ** Set the backlight character class string
3100 void SetBacklightChars(WindowInfo
*window
, char *applyBacklightTypes
)
3103 int is_applied
= XmToggleButtonGetState(window
->backlightCharsItem
) ? 1 : 0;
3104 int do_apply
= applyBacklightTypes
? 1 : 0;
3106 window
->backlightChars
= do_apply
;
3108 XtFree(window
->backlightCharTypes
);
3109 if (window
->backlightChars
&&
3110 (window
->backlightCharTypes
= XtMalloc(strlen(applyBacklightTypes
)+1)))
3111 strcpy(window
->backlightCharTypes
, applyBacklightTypes
);
3113 window
->backlightCharTypes
= NULL
;
3115 XtVaSetValues(window
->textArea
,
3116 textNbacklightCharTypes
, window
->backlightCharTypes
, NULL
);
3117 for (i
=0; i
<window
->nPanes
; i
++)
3118 XtVaSetValues(window
->textPanes
[i
],
3119 textNbacklightCharTypes
, window
->backlightCharTypes
, NULL
);
3120 if (is_applied
!= do_apply
)
3121 SetToggleButtonState(window
, window
->backlightCharsItem
, do_apply
, False
);
3125 ** perform generic management on the children (toolbars) of toolBarsForm,
3126 ** a.k.a. statsForm, by setting the form attachment of the managed child
3127 ** widgets per their position/order.
3129 ** You can optionally create separator after a toolbar widget with it's
3130 ** widget name set to "TOOLBAR_SEP", which will appear below the toolbar
3131 ** widget. These seperators will then be managed automatically by this
3132 ** routine along with the toolbars they 'attached' to.
3134 ** It also takes care of the attachment offset settings of the child
3135 ** widgets to keep the border lines of the parent form displayed, so
3136 ** you don't have set them before hand.
3138 ** Note: XtManage/XtUnmange the target child (toolbar) before calling this
3141 ** Returns the last toolbar widget managed.
3144 static Widget
manageToolBars(Widget toolBarsForm
)
3146 Widget topWidget
= NULL
;
3147 WidgetList children
;
3150 XtVaGetValues(toolBarsForm
, XmNchildren
, &children
,
3151 XmNnumChildren
, &nItems
, NULL
);
3153 for (n
=0; n
<nItems
; n
++) {
3154 Widget tbar
= children
[n
];
3156 if (XtIsManaged(tbar
)) {
3158 XtVaSetValues(tbar
, XmNtopAttachment
, XmATTACH_WIDGET
,
3159 XmNtopWidget
, topWidget
,
3160 XmNbottomAttachment
, XmATTACH_NONE
,
3161 XmNleftOffset
, STAT_SHADOW_THICKNESS
,
3162 XmNrightOffset
, STAT_SHADOW_THICKNESS
,
3166 /* the very first toolbar on top */
3167 XtVaSetValues(tbar
, XmNtopAttachment
, XmATTACH_FORM
,
3168 XmNbottomAttachment
, XmATTACH_NONE
,
3169 XmNleftOffset
, STAT_SHADOW_THICKNESS
,
3170 XmNtopOffset
, STAT_SHADOW_THICKNESS
,
3171 XmNrightOffset
, STAT_SHADOW_THICKNESS
,
3177 /* if the next widget is a separator, turn it on */
3178 if (n
+1<nItems
&& !strcmp(XtName(children
[n
+1]), "TOOLBAR_SEP")) {
3179 XtManageChild(children
[n
+1]);
3183 /* Remove top attachment to widget to avoid circular dependency.
3184 Attach bottom to form so that when the widget is redisplayed
3185 later, it will trigger the parent form to resize properly as
3186 if the widget is being inserted */
3187 XtVaSetValues(tbar
, XmNtopAttachment
, XmATTACH_NONE
,
3188 XmNbottomAttachment
, XmATTACH_FORM
, NULL
);
3190 /* if the next widget is a separator, turn it off */
3191 if (n
+1<nItems
&& !strcmp(XtName(children
[n
+1]), "TOOLBAR_SEP")) {
3192 XtUnmanageChild(children
[n
+1]);
3198 if (strcmp(XtName(topWidget
), "TOOLBAR_SEP")) {
3199 XtVaSetValues(topWidget
,
3200 XmNbottomAttachment
, XmATTACH_FORM
,
3201 XmNbottomOffset
, STAT_SHADOW_THICKNESS
,
3205 /* is a separator */
3207 XtVaGetValues(topWidget
, XmNtopWidget
, &wgt
, NULL
);
3209 /* don't need sep below bottom-most toolbar */
3210 XtUnmanageChild(topWidget
);
3212 XmNbottomAttachment
, XmATTACH_FORM
,
3213 XmNbottomOffset
, STAT_SHADOW_THICKNESS
,
3222 ** Calculate the dimension of the text area, in terms of rows & cols,
3223 ** as if there's only one single text pane in the window.
3225 static void getTextPaneDimension(WindowInfo
*window
, int *nRows
, int *nCols
)
3228 Dimension hScrollBarHeight
, paneHeight
;
3229 int marginHeight
, marginWidth
, totalHeight
, fontHeight
;
3230 textDisp
*textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
3232 /* width is the same for panes */
3233 XtVaGetValues(window
->textArea
, textNcolumns
, nCols
, NULL
);
3235 /* we have to work out the height, as the text area may have been split */
3236 XtVaGetValues(window
->textArea
, textNhScrollBar
, &hScrollBar
,
3237 textNmarginHeight
, &marginHeight
, textNmarginWidth
, &marginWidth
,
3239 XtVaGetValues(hScrollBar
, XmNheight
, &hScrollBarHeight
, NULL
);
3240 XtVaGetValues(window
->splitPane
, XmNheight
, &paneHeight
, NULL
);
3241 totalHeight
= paneHeight
- 2*marginHeight
-hScrollBarHeight
;
3242 fontHeight
= textD
->ascent
+ textD
->descent
;
3243 *nRows
= totalHeight
/fontHeight
;
3247 ** Create a new document in the shell window.
3248 ** Document are created in 'background' so that the user
3249 ** menus, ie. the Macro/Shell/BG menus, will not be updated
3250 ** unnecessarily; hence speeding up the process of opening
3253 WindowInfo
* CreateDocument(WindowInfo
* shellWindow
, const char* name
)
3259 /* Allocate some memory for the new window data structure */
3260 window
= (WindowInfo
*)XtMalloc(sizeof(WindowInfo
));
3262 /* inherit settings and later reset those required */
3263 memcpy(window
, shellWindow
, sizeof(WindowInfo
));
3266 /* share these dialog items with parent shell */
3267 window
->replaceDlog
= NULL
;
3268 window
->replaceText
= NULL
;
3269 window
->replaceWithText
= NULL
;
3270 window
->replaceWordToggle
= NULL
;
3271 window
->replaceCaseToggle
= NULL
;
3272 window
->replaceRegexToggle
= NULL
;
3273 window
->findDlog
= NULL
;
3274 window
->findText
= NULL
;
3275 window
->findWordToggle
= NULL
;
3276 window
->findCaseToggle
= NULL
;
3277 window
->findRegexToggle
= NULL
;
3278 window
->replaceMultiFileDlog
= NULL
;
3279 window
->replaceMultiFilePathBtn
= NULL
;
3280 window
->replaceMultiFileList
= NULL
;
3281 window
->showLineNumbers
= GetPrefLineNums();
3282 window
->showStats
= GetPrefStatsLine();
3283 window
->showISearchLine
= GetPrefISearchLine();
3286 window
->multiFileReplSelected
= FALSE
;
3287 window
->multiFileBusy
= FALSE
;
3288 window
->writableWindows
= NULL
;
3289 window
->nWritableWindows
= 0;
3290 window
->fileChanged
= FALSE
;
3291 window
->fileMissing
= True
;
3292 window
->fileMode
= 0;
3293 window
->fileUid
= 0;
3294 window
->fileGid
= 0;
3295 window
->filenameSet
= FALSE
;
3296 window
->fileFormat
= UNIX_FILE_FORMAT
;
3297 window
->lastModTime
= 0;
3298 strcpy(window
->filename
, name
);
3299 window
->undo
= NULL
;
3300 window
->redo
= NULL
;
3302 window
->autoSaveCharCount
= 0;
3303 window
->autoSaveOpCount
= 0;
3304 window
->undoOpCount
= 0;
3305 window
->undoMemUsed
= 0;
3306 CLEAR_ALL_LOCKS(window
->lockReasons
);
3307 window
->indentStyle
= GetPrefAutoIndent(PLAIN_LANGUAGE_MODE
);
3308 window
->autoSave
= GetPrefAutoSave();
3309 window
->saveOldVersion
= GetPrefSaveOldVersion();
3310 window
->wrapMode
= GetPrefWrap(PLAIN_LANGUAGE_MODE
);
3311 window
->overstrike
= False
;
3312 window
->showMatchingStyle
= GetPrefShowMatching();
3313 window
->matchSyntaxBased
= GetPrefMatchSyntaxBased();
3314 window
->highlightSyntax
= GetPrefHighlightSyntax();
3315 window
->backlightCharTypes
= NULL
;
3316 window
->backlightChars
= GetPrefBacklightChars();
3317 if (window
->backlightChars
) {
3318 char *cTypes
= GetPrefBacklightCharTypes();
3319 if (cTypes
&& window
->backlightChars
) {
3320 if ((window
->backlightCharTypes
= XtMalloc(strlen(cTypes
) + 1)))
3321 strcpy(window
->backlightCharTypes
, cTypes
);
3324 window
->modeMessageDisplayed
= FALSE
;
3325 window
->modeMessage
= NULL
;
3326 window
->ignoreModify
= FALSE
;
3327 window
->windowMenuValid
= FALSE
;
3328 window
->flashTimeoutID
= 0;
3329 window
->fileClosedAtom
= None
;
3330 window
->wasSelected
= FALSE
;
3331 strcpy(window
->fontName
, GetPrefFontName());
3332 strcpy(window
->italicFontName
, GetPrefItalicFontName());
3333 strcpy(window
->boldFontName
, GetPrefBoldFontName());
3334 strcpy(window
->boldItalicFontName
, GetPrefBoldItalicFontName());
3335 window
->colorDialog
= NULL
;
3336 window
->fontList
= GetPrefFontList();
3337 window
->italicFontStruct
= GetPrefItalicFont();
3338 window
->boldFontStruct
= GetPrefBoldFont();
3339 window
->boldItalicFontStruct
= GetPrefBoldItalicFont();
3340 window
->fontDialog
= NULL
;
3342 window
->markTimeoutID
= 0;
3343 window
->highlightData
= NULL
;
3344 window
->shellCmdData
= NULL
;
3345 window
->macroCmdData
= NULL
;
3346 window
->smartIndentData
= NULL
;
3347 window
->languageMode
= PLAIN_LANGUAGE_MODE
;
3348 window
->iSearchHistIndex
= 0;
3349 window
->iSearchStartPos
= -1;
3350 window
->replaceLastRegexCase
= TRUE
;
3351 window
->replaceLastLiteralCase
= FALSE
;
3352 window
->iSearchLastRegexCase
= TRUE
;
3353 window
->iSearchLastLiteralCase
= FALSE
;
3354 window
->findLastRegexCase
= TRUE
;
3355 window
->findLastLiteralCase
= FALSE
;
3357 window
->bgMenuUndoItem
= NULL
;
3358 window
->bgMenuRedoItem
= NULL
;
3362 if (window
->fontList
== NULL
)
3363 XtVaGetValues(shellWindow
->statsLine
, XmNfontList
,
3364 &window
->fontList
,NULL
);
3366 getTextPaneDimension(shellWindow
, &nRows
, &nCols
);
3368 /* Create pane that actaully holds the new document. As
3369 document is created in 'background', we need to hide
3370 it. If we leave it unmanaged without setting it to
3371 the XmNworkWindow of the mainWin, due to a unknown
3372 bug in Motif where splitpane's scrollWindow child
3373 somehow came up with a height taller than the splitpane,
3374 the bottom part of the text editing widget is obstructed
3375 when later brought up by RaiseDocument(). So we first
3376 manage it hidden, then unmanage it and reset XmNworkWindow,
3377 then let RaiseDocument() show it later. */
3378 pane
= XtVaCreateWidget("pane",
3379 xmPanedWindowWidgetClass
, window
->mainWin
,
3380 XmNmarginWidth
, 0, XmNmarginHeight
, 0, XmNseparatorOn
, False
,
3381 XmNspacing
, 3, XmNsashIndent
, -2,
3382 XmNmappedWhenManaged
, False
,
3384 XtVaSetValues(window
->mainWin
, XmNworkWindow
, pane
, NULL
);
3385 XtManageChild(pane
);
3386 window
->splitPane
= pane
;
3388 /* Store a copy of document/window pointer in text pane to support
3389 action procedures. See also WidgetToWindow() for info. */
3390 XtVaSetValues(pane
, XmNuserData
, window
, NULL
);
3392 /* Patch around Motif's most idiotic "feature", that its menu accelerators
3393 recognize Caps Lock and Num Lock as modifiers, and don't trigger if
3395 AccelLockBugPatch(pane
, window
->menuBar
);
3397 /* Create the first, and most permanent text area (other panes may
3398 be added & removed, but this one will never be removed */
3399 text
= createTextArea(pane
, window
, nRows
, nCols
,
3400 GetPrefEmTabDist(PLAIN_LANGUAGE_MODE
), GetPrefDelimiters(),
3401 GetPrefWrapMargin(), window
->showLineNumbers
?MIN_LINE_NUM_COLS
:0);
3402 XtManageChild(text
);
3403 window
->textArea
= text
;
3404 window
->lastFocus
= text
;
3406 /* Set the initial colors from the globals. */
3408 GetPrefColorName(TEXT_FG_COLOR
),
3409 GetPrefColorName(TEXT_BG_COLOR
),
3410 GetPrefColorName(SELECT_FG_COLOR
),
3411 GetPrefColorName(SELECT_BG_COLOR
),
3412 GetPrefColorName(HILITE_FG_COLOR
),
3413 GetPrefColorName(HILITE_BG_COLOR
),
3414 GetPrefColorName(LINENO_FG_COLOR
),
3415 GetPrefColorName(CURSOR_FG_COLOR
));
3417 /* Create the right button popup menu (note: order is important here,
3418 since the translation for popping up this menu was probably already
3419 added in createTextArea, but CreateBGMenu requires window->textArea
3420 to be set so it can attach the menu to it (because menu shells are
3421 finicky about the kinds of widgets they are attached to)) */
3422 window
->bgMenuPane
= CreateBGMenu(window
);
3424 /* cache user menus: init. user background menu cache */
3425 InitUserBGMenuCache(&window
->userBGMenuCache
);
3427 /* Create the text buffer rather than using the one created automatically
3428 with the text area widget. This is done so the syntax highlighting
3429 modify callback can be called to synchronize the style buffer BEFORE
3430 the text display's callback is called upon to display a modification */
3431 window
->buffer
= BufCreate();
3432 BufAddModifyCB(window
->buffer
, SyntaxHighlightModifyCB
, window
);
3434 /* Attach the buffer to the text widget, and add callbacks for modify */
3435 TextSetBuffer(text
, window
->buffer
);
3436 BufAddModifyCB(window
->buffer
, modifiedCB
, window
);
3438 /* Designate the permanent text area as the owner for selections */
3439 HandleXSelections(text
);
3441 /* Set the requested hardware tab distance and useTabs in the text buffer */
3442 BufSetTabDistance(window
->buffer
, GetPrefTabDist(PLAIN_LANGUAGE_MODE
));
3443 window
->buffer
->useTabs
= GetPrefInsertTabs();
3444 window
->tab
= addTab(window
->tabBar
, name
);
3446 /* add the window to the global window list, update the Windows menus */
3447 InvalidateWindowMenus();
3448 addToWindowList(window
);
3450 #ifdef LESSTIF_VERSION
3451 /* FIXME: Temporary workaround for disappearing-text-window bug
3452 when linking to Lesstif.
3454 After changes is made to statsAreaForm (parent of statsline,
3455 i-search line and tab bar) widget such as enabling/disabling
3456 the statsline, the XmForm widget enclosing the text widget
3457 somehow refused to resize to fit the text widget. Resizing
3458 the shell window or making changes [again] to the statsAreaForm
3459 appeared to bring out the text widget, though doesn't fix it for
3460 the subsequently added documents. Here we try to do the latter
3461 for all new documents created. */
3462 if (XtIsManaged(XtParent(window
->statsLineForm
))) {
3463 XtUnmanageChild(XtParent(window
->statsLineForm
));
3464 XtManageChild(XtParent(window
->statsLineForm
));
3466 #endif /* LESSTIF_VERSION */
3468 /* return the shell ownership to previous tabbed doc */
3469 XtVaSetValues(window
->mainWin
, XmNworkWindow
, shellWindow
->splitPane
, NULL
);
3470 XLowerWindow(TheDisplay
, XtWindow(window
->splitPane
));
3471 XtUnmanageChild(window
->splitPane
);
3472 XtVaSetValues(window
->splitPane
, XmNmappedWhenManaged
, True
, NULL
);
3478 ** return the next/previous docment on the tab list.
3480 ** If <wrap> is true then the next tab of the rightmost tab will be the
3481 ** second tab from the right, and the the previous tab of the leftmost
3482 ** tab will be the second from the left. This is useful for getting
3483 ** the next tab after a tab detaches/closes and you don't want to wrap around.
3485 static WindowInfo
*getNextTabWindow(WindowInfo
*window
, int direction
,
3486 int crossWin
, int wrap
)
3488 WidgetList tabList
, tabs
;
3490 int tabCount
, tabTotalCount
;
3491 int tabPos
, nextPos
;
3493 int nBuf
= crossWin
? NWindows() : NDocuments(window
);
3498 /* get the list of tabs */
3499 tabs
= (WidgetList
)XtMalloc(sizeof(Widget
) * nBuf
);
3503 WidgetList children
;
3505 XtVaGetValues(TheAppShell
, XmNchildren
, &children
,
3506 XmNnumChildren
, &nItems
, NULL
);
3508 /* get list of tabs in all windows */
3509 for (n
=0; n
<nItems
; n
++) {
3510 if (strcmp(XtName(children
[n
]), "textShell") ||
3511 ((win
= WidgetToWindow(children
[n
])) == NULL
))
3512 continue; /* skip non-text-editor windows */
3514 XtVaGetValues(win
->tabBar
, XmNtabWidgetList
, &tabList
,
3515 XmNtabCount
, &tabCount
, NULL
);
3517 for (i
=0; i
< tabCount
; i
++) {
3518 tabs
[tabTotalCount
++] = tabList
[i
];
3523 /* get list of tabs in this window */
3524 XtVaGetValues(window
->tabBar
, XmNtabWidgetList
, &tabList
,
3525 XmNtabCount
, &tabCount
, NULL
);
3527 for (i
=0; i
< tabCount
; i
++) {
3528 if (TabToWindow(tabList
[i
])) /* make sure tab is valid */
3529 tabs
[tabTotalCount
++] = tabList
[i
];
3533 /* find the position of the tab in the tablist */
3535 for (n
=0; n
<tabTotalCount
; n
++) {
3536 if (tabs
[n
] == window
->tab
) {
3542 /* calculate index position of next tab */
3543 nextPos
= tabPos
+ direction
;
3544 if (nextPos
>= nBuf
) {
3549 } else if (nextPos
< 0) {
3556 /* return the document where the next tab belongs to */
3557 win
= TabToWindow(tabs
[nextPos
]);
3558 XtFree((char *)tabs
);
3563 ** return the integer position of a tab in the tabbar it
3564 ** belongs to, or -1 if there's an error, somehow.
3566 static int getTabPosition(Widget tab
)
3570 Widget tabBar
= XtParent(tab
);
3572 XtVaGetValues(tabBar
, XmNtabWidgetList
, &tabList
,
3573 XmNtabCount
, &tabCount
, NULL
);
3575 for (i
=0; i
< tabCount
; i
++) {
3576 if (tab
== tabList
[i
])
3580 return -1; /* something is wrong! */
3584 ** update the tab label, etc. of a tab, per the states of it's document.
3586 void RefreshTabState(WindowInfo
*win
)
3588 XmString s1
, tipString
;
3589 char labelString
[MAXPATHLEN
];
3590 char *tag
= XmFONTLIST_DEFAULT_TAG
;
3591 unsigned char alignment
;
3593 /* Set tab label to document's filename. Position of
3594 "*" (modified) will change per label alignment setting */
3595 XtVaGetValues(win
->tab
, XmNalignment
, &alignment
, NULL
);
3596 if (alignment
!= XmALIGNMENT_END
) {
3597 sprintf(labelString
, "%s%s",
3598 win
->fileChanged
? "*" : "",
3601 sprintf(labelString
, "%s%s",
3603 win
->fileChanged
? "*" : "");
3606 /* Make the top document stand out a little more */
3607 if (IsTopDocument(win
))
3610 s1
= XmStringCreateLtoR(labelString
, tag
);
3612 if (GetPrefShowPathInWindowsMenu() && win
->filenameSet
) {
3613 strcat(labelString
, " - ");
3614 strcat(labelString
, win
->path
);
3616 tipString
=XmStringCreateSimple(labelString
);
3618 XtVaSetValues(win
->tab
,
3619 XltNbubbleString
, tipString
,
3623 XmStringFree(tipString
);
3627 ** close all the documents in a window
3629 int CloseAllDocumentInWindow(WindowInfo
*window
)
3633 if (NDocuments(window
) == 1) {
3634 /* only one document in the window */
3635 return CloseFileAndWindow(window
, PROMPT_SBC_DIALOG_RESPONSE
);
3638 Widget winShell
= window
->shell
;
3639 WindowInfo
*topDocument
;
3641 /* close all _modified_ documents belong to this window */
3642 for (win
= WindowList
; win
; ) {
3643 if (win
->shell
== winShell
&& win
->fileChanged
) {
3644 WindowInfo
*next
= win
->next
;
3645 if (!CloseFileAndWindow(win
, PROMPT_SBC_DIALOG_RESPONSE
))
3653 /* see there's still documents left in the window */
3654 for (win
= WindowList
; win
; win
=win
->next
)
3655 if (win
->shell
== winShell
)
3659 topDocument
= GetTopDocument(winShell
);
3661 /* close all non-top documents belong to this window */
3662 for (win
= WindowList
; win
; ) {
3663 if (win
->shell
== winShell
&& win
!= topDocument
) {
3664 WindowInfo
*next
= win
->next
;
3665 if (!CloseFileAndWindow(win
, PROMPT_SBC_DIALOG_RESPONSE
))
3673 /* close the last document and its window */
3674 if (!CloseFileAndWindow(topDocument
, PROMPT_SBC_DIALOG_RESPONSE
))
3682 static void CloseDocumentWindow(Widget w
, WindowInfo
*window
, XtPointer callData
)
3684 int nDocuments
= NDocuments(window
);
3686 if (nDocuments
== NWindows()) {
3687 /* this is only window, then exit */
3688 XtCallActionProc(WindowList
->lastFocus
, "exit",
3689 ((XmAnyCallbackStruct
*)callData
)->event
, NULL
, 0);
3692 if (nDocuments
== 1) {
3693 CloseFileAndWindow(window
, PROMPT_SBC_DIALOG_RESPONSE
);
3697 if (GetPrefWarnExit())
3698 resp
= DialogF(DF_QUES
, window
->shell
, 2, "Close Window",
3699 "Close ALL documents in this window?", "Close", "Cancel");
3702 CloseAllDocumentInWindow(window
);
3708 ** Refresh the menu entries per the settings of the
3711 void RefreshMenuToggleStates(WindowInfo
*window
)
3715 if (!IsTopDocument(window
))
3719 XtSetSensitive(window
->printSelItem
, window
->wasSelected
);
3722 XtSetSensitive(window
->undoItem
, window
->undo
!= NULL
);
3723 XtSetSensitive(window
->redoItem
, window
->redo
!= NULL
);
3724 XtSetSensitive(window
->printSelItem
, window
->wasSelected
);
3725 XtSetSensitive(window
->cutItem
, window
->wasSelected
);
3726 XtSetSensitive(window
->copyItem
, window
->wasSelected
);
3727 XtSetSensitive(window
->delItem
, window
->wasSelected
);
3729 /* Preferences menu */
3730 XmToggleButtonSetState(window
->statsLineItem
, window
->showStats
, False
);
3731 XmToggleButtonSetState(window
->iSearchLineItem
, window
->showISearchLine
, False
);
3732 XmToggleButtonSetState(window
->lineNumsItem
, window
->showLineNumbers
, False
);
3733 XmToggleButtonSetState(window
->highlightItem
, window
->highlightSyntax
, False
);
3734 XtSetSensitive(window
->highlightItem
, window
->languageMode
!= PLAIN_LANGUAGE_MODE
);
3735 XmToggleButtonSetState(window
->backlightCharsItem
, window
->backlightChars
, False
);
3737 XmToggleButtonSetState(window
->saveLastItem
, window
->saveOldVersion
, False
);
3739 XmToggleButtonSetState(window
->autoSaveItem
, window
->autoSave
, False
);
3740 XmToggleButtonSetState(window
->overtypeModeItem
, window
->overstrike
, False
);
3741 XmToggleButtonSetState(window
->matchSyntaxBasedItem
, window
->matchSyntaxBased
, False
);
3742 XmToggleButtonSetState(window
->readOnlyItem
, IS_USER_LOCKED(window
->lockReasons
), False
);
3744 XtSetSensitive(window
->smartIndentItem
,
3745 SmartIndentMacrosAvailable(LanguageModeName(window
->languageMode
)));
3747 SetAutoIndent(window
, window
->indentStyle
);
3748 SetAutoWrap(window
, window
->wrapMode
);
3749 SetShowMatching(window
, window
->showMatchingStyle
);
3750 SetLanguageMode(window
, window
->languageMode
, FALSE
);
3753 XtSetSensitive(window
->splitPaneItem
, window
->nPanes
< MAX_PANES
);
3754 XtSetSensitive(window
->closePaneItem
, window
->nPanes
> 0);
3755 XtSetSensitive(window
->detachDocumentItem
, NDocuments(window
)>1);
3756 XtSetSensitive(window
->contextDetachDocumentItem
, NDocuments(window
)>1);
3758 for (win
=WindowList
; win
; win
=win
->next
)
3759 if (win
->shell
!= window
->shell
)
3761 XtSetSensitive(window
->moveDocumentItem
, win
!= NULL
);
3765 ** Refresh the various settings/state of the shell window per the
3766 ** settings of the top document.
3768 static void refreshMenuBar(WindowInfo
*window
)
3770 RefreshMenuToggleStates(window
);
3772 /* Add/remove language specific menu items */
3773 UpdateUserMenus(window
);
3775 /* refresh selection-sensitive menus */
3776 DimSelectionDepUserMenuItems(window
, window
->wasSelected
);
3780 ** remember the last document.
3782 WindowInfo
*MarkLastDocument(WindowInfo
*window
)
3784 WindowInfo
*prev
= lastFocusDocument
;
3787 lastFocusDocument
= window
;
3793 ** remember the active (top) document.
3795 WindowInfo
*MarkActiveDocument(WindowInfo
*window
)
3797 WindowInfo
*prev
= inFocusDocument
;
3800 inFocusDocument
= window
;
3806 ** Bring up the next window by tab order
3808 void NextDocument(WindowInfo
*window
)
3812 if (WindowList
->next
== NULL
)
3815 win
= getNextTabWindow(window
, 1, GetPrefGlobalTabNavigate(), 1);
3819 if (window
->shell
== win
->shell
)
3822 RaiseFocusDocumentWindow(win
, True
);
3826 ** Bring up the previous window by tab order
3828 void PreviousDocument(WindowInfo
*window
)
3832 if (WindowList
->next
== NULL
)
3835 win
= getNextTabWindow(window
, -1, GetPrefGlobalTabNavigate(), 1);
3839 if (window
->shell
== win
->shell
)
3842 RaiseFocusDocumentWindow(win
, True
);
3846 ** Bring up the last active window
3848 void LastDocument(WindowInfo
*window
)
3852 for(win
= WindowList
; win
; win
=win
->next
)
3853 if (lastFocusDocument
== win
)
3859 if (window
->shell
== win
->shell
)
3862 RaiseFocusDocumentWindow(win
, True
);
3867 ** make sure window is alive is kicking
3869 int IsValidWindow(WindowInfo
*window
)
3873 for(win
= WindowList
; win
; win
=win
->next
)
3882 ** raise the document and its shell window and focus depending on pref.
3884 void RaiseDocumentWindow(WindowInfo
*window
)
3889 RaiseDocument(window
);
3890 RaiseShellWindow(window
->shell
, GetPrefFocusOnRaise());
3894 ** raise the document and its shell window and optionally focus.
3896 void RaiseFocusDocumentWindow(WindowInfo
*window
, Boolean focus
)
3901 RaiseDocument(window
);
3902 RaiseShellWindow(window
->shell
, focus
);
3906 ** Redisplay menu tearoffs previously hid by hideTearOffs()
3908 static void redisplayTearOffs(Widget menuPane
)
3910 WidgetList itemList
;
3915 /* redisplay all submenu tearoffs */
3916 XtVaGetValues(menuPane
, XmNchildren
, &itemList
,
3917 XmNnumChildren
, &nItems
, NULL
);
3918 for (n
=0; n
<(int)nItems
; n
++) {
3919 if (XtClass(itemList
[n
]) == xmCascadeButtonWidgetClass
) {
3920 XtVaGetValues(itemList
[n
], XmNsubMenuId
, &subMenuID
, NULL
);
3921 redisplayTearOffs(subMenuID
);
3925 /* redisplay tearoff for this menu */
3926 if (!XmIsMenuShell(XtParent(menuPane
)))
3927 ShowHiddenTearOff(menuPane
);
3931 ** hide all the tearoffs spawned from this menu.
3932 ** It works recursively to close the tearoffs of the submenus
3934 static void hideTearOffs(Widget menuPane
)
3936 WidgetList itemList
;
3941 /* hide all submenu tearoffs */
3942 XtVaGetValues(menuPane
, XmNchildren
, &itemList
,
3943 XmNnumChildren
, &nItems
, NULL
);
3944 for (n
=0; n
<(int)nItems
; n
++) {
3945 if (XtClass(itemList
[n
]) == xmCascadeButtonWidgetClass
) {
3946 XtVaGetValues(itemList
[n
], XmNsubMenuId
, &subMenuID
, NULL
);
3947 hideTearOffs(subMenuID
);
3951 /* hide tearoff for this menu */
3952 if (!XmIsMenuShell(XtParent(menuPane
)))
3953 XtUnmapWidget(XtParent(menuPane
));
3957 ** Raise a tabbed document within its shell window.
3959 ** NB: use RaiseDocumentWindow() to raise the doc and
3960 ** its shell window.
3962 void RaiseDocument(WindowInfo
*window
)
3964 WindowInfo
*win
, *lastwin
;
3966 if (!window
|| !WindowList
)
3969 lastwin
= MarkActiveDocument(window
);
3970 if (lastwin
!= window
&& IsValidWindow(lastwin
))
3971 MarkLastDocument(lastwin
);
3973 /* document already on top? */
3974 XtVaGetValues(window
->mainWin
, XmNuserData
, &win
, NULL
);
3978 /* set the document as top document */
3979 XtVaSetValues(window
->mainWin
, XmNuserData
, window
, NULL
);
3981 /* show the new top document */
3982 XtVaSetValues(window
->mainWin
, XmNworkWindow
, window
->splitPane
, NULL
);
3983 XtManageChild(window
->splitPane
);
3984 XRaiseWindow(TheDisplay
, XtWindow(window
->splitPane
));
3986 /* Turn on syntax highlight that might have been deferred.
3987 NB: this must be done after setting the document as
3988 XmNworkWindow and managed, else the parent shell
3989 window may shrink on some window-managers such as
3990 metacity, due to changes made in UpdateWMSizeHints().*/
3991 if (window
->highlightSyntax
&& window
->highlightData
==NULL
)
3992 StartHighlighting(window
, False
);
3994 /* put away the bg menu tearoffs of last active document */
3995 hideTearOffs(win
->bgMenuPane
);
3997 /* restore the bg menu tearoffs of active document */
3998 redisplayTearOffs(window
->bgMenuPane
);
4000 /* set tab as active */
4001 XmLFolderSetActiveTab(window
->tabBar
,
4002 getTabPosition(window
->tab
), False
);
4004 /* set keyboard focus. Must be done before unmanaging previous
4005 top document, else lastFocus will be reset to textArea */
4006 XmProcessTraversal(window
->lastFocus
, XmTRAVERSE_CURRENT
);
4008 /* we only manage the top document, else the next time a document
4009 is raised again, it's textpane might not resize properly.
4010 Also, somehow (bug?) XtUnmanageChild() doesn't hide the
4011 splitPane, which obscure lower part of the statsform when
4012 we toggle its components, so we need to put the document at
4014 XLowerWindow(TheDisplay
, XtWindow(win
->splitPane
));
4015 XtUnmanageChild(win
->splitPane
);
4016 RefreshTabState(win
);
4018 /* now refresh window state/info. RefreshWindowStates()
4019 has a lot of work to do, so we update the screen first so
4020 the document appears to switch swiftly. */
4021 XmUpdateDisplay(window
->splitPane
);
4022 RefreshWindowStates(window
);
4023 RefreshTabState(window
);
4025 /* put away the bg menu tearoffs of last active document */
4026 hideTearOffs(win
->bgMenuPane
);
4028 /* restore the bg menu tearoffs of active document */
4029 redisplayTearOffs(window
->bgMenuPane
);
4031 /* Make sure that the "In Selection" button tracks the presence of a
4032 selection and that the window inherits the proper search scope. */
4033 if (window
->replaceDlog
!= NULL
&& XtIsManaged(window
->replaceDlog
))
4035 #ifdef REPLACE_SCOPE
4036 window
->replaceScope
= win
->replaceScope
;
4038 UpdateReplaceActionButtons(window
);
4041 UpdateWMSizeHints(window
);
4044 WindowInfo
* GetTopDocument(Widget w
)
4046 WindowInfo
*window
= WidgetToWindow(w
);
4048 return WidgetToWindow(window
->shell
);
4051 Boolean
IsTopDocument(const WindowInfo
*window
)
4053 return window
== GetTopDocument(window
->shell
)? True
: False
;
4056 static void deleteDocument(WindowInfo
*window
)
4058 if (NULL
== window
) {
4062 XtDestroyWidget(window
->splitPane
);
4066 ** return the number of documents owned by this shell window
4068 int NDocuments(WindowInfo
*window
)
4073 for (win
= WindowList
; win
; win
= win
->next
) {
4074 if (win
->shell
== window
->shell
)
4082 ** refresh window state for this document
4084 void RefreshWindowStates(WindowInfo
*window
)
4086 if (!IsTopDocument(window
))
4089 if (window
->modeMessageDisplayed
)
4090 XmTextSetString(window
->statsLine
, window
->modeMessage
);
4092 UpdateStatsLine(window
);
4093 UpdateWindowReadOnly(window
);
4094 UpdateWindowTitle(window
);
4096 /* show/hide statsline as needed */
4097 if (window
->modeMessageDisplayed
&& !XtIsManaged(window
->statsLineForm
)) {
4098 /* turn on statline to display mode message */
4099 showStats(window
, True
);
4101 else if (window
->showStats
&& !XtIsManaged(window
->statsLineForm
)) {
4102 /* turn on statsline since it is enabled */
4103 showStats(window
, True
);
4105 else if (!window
->showStats
&& !window
->modeMessageDisplayed
&&
4106 XtIsManaged(window
->statsLineForm
)) {
4107 /* turn off statsline since there's nothing to show */
4108 showStats(window
, False
);
4111 /* signal if macro/shell is running */
4112 if (window
->shellCmdData
|| window
->macroCmdData
)
4113 BeginWait(window
->shell
);
4115 EndWait(window
->shell
);
4117 /* we need to force the statsline to reveal itself */
4118 if (XtIsManaged(window
->statsLineForm
)) {
4119 XmTextSetCursorPosition(window
->statsLine
, 0); /* start of line */
4120 XmTextSetCursorPosition(window
->statsLine
, 9000); /* end of line */
4123 XmUpdateDisplay(window
->statsLine
);
4124 refreshMenuBar(window
);
4126 updateLineNumDisp(window
);
4129 static void cloneTextPanes(WindowInfo
*window
, WindowInfo
*orgWin
)
4131 short paneHeights
[MAX_PANES
+1];
4132 int insertPositions
[MAX_PANES
+1], topLines
[MAX_PANES
+1];
4133 int horizOffsets
[MAX_PANES
+1];
4134 int i
, focusPane
, emTabDist
, wrapMargin
, lineNumCols
, totalHeight
=0;
4138 textDisp
*textD
, *newTextD
;
4140 /* transfer the primary selection */
4141 memcpy(&sel
, &orgWin
->buffer
->primary
, sizeof(selection
));
4144 if (sel
.rectangular
)
4145 BufRectSelect(window
->buffer
, sel
.start
, sel
.end
,
4146 sel
.rectStart
, sel
.rectEnd
);
4148 BufSelect(window
->buffer
, sel
.start
, sel
.end
);
4150 BufUnselect(window
->buffer
);
4152 /* Record the current heights, scroll positions, and insert positions
4153 of the existing panes, keyboard focus */
4155 for (i
=0; i
<=orgWin
->nPanes
; i
++) {
4156 text
= i
==0 ? orgWin
->textArea
: orgWin
->textPanes
[i
-1];
4157 insertPositions
[i
] = TextGetCursorPos(text
);
4158 XtVaGetValues(containingPane(text
), XmNheight
, &paneHeights
[i
], NULL
);
4159 totalHeight
+= paneHeights
[i
];
4160 TextGetScroll(text
, &topLines
[i
], &horizOffsets
[i
]);
4161 if (text
== orgWin
->lastFocus
)
4165 window
->nPanes
= orgWin
->nPanes
;
4167 /* Copy some parameters */
4168 XtVaGetValues(orgWin
->textArea
, textNemulateTabs
, &emTabDist
,
4169 textNwordDelimiters
, &delimiters
, textNwrapMargin
, &wrapMargin
,
4171 lineNumCols
= orgWin
->showLineNumbers
? MIN_LINE_NUM_COLS
: 0;
4172 XtVaSetValues(window
->textArea
, textNemulateTabs
, emTabDist
,
4173 textNwordDelimiters
, delimiters
, textNwrapMargin
, wrapMargin
,
4174 textNlineNumCols
, lineNumCols
, NULL
);
4177 /* clone split panes, if any */
4178 textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
4179 if (window
->nPanes
) {
4180 /* Unmanage & remanage the panedWindow so it recalculates pane
4182 XtUnmanageChild(window
->splitPane
);
4184 /* Create a text widget to add to the pane and set its buffer and
4185 highlight data to be the same as the other panes in the orgWin */
4187 for(i
=0; i
<orgWin
->nPanes
; i
++) {
4188 text
= createTextArea(window
->splitPane
, window
, 1, 1, emTabDist
,
4189 delimiters
, wrapMargin
, lineNumCols
);
4190 TextSetBuffer(text
, window
->buffer
);
4192 if (window
->highlightData
!= NULL
)
4193 AttachHighlightToWidget(text
, window
);
4194 XtManageChild(text
);
4195 window
->textPanes
[i
] = text
;
4197 /* Fix up the colors */
4198 newTextD
= ((TextWidget
)text
)->text
.textD
;
4199 XtVaSetValues(text
, XmNforeground
, textD
->fgPixel
,
4200 XmNbackground
, textD
->bgPixel
, NULL
);
4201 TextDSetColors(newTextD
, textD
->fgPixel
, textD
->bgPixel
,
4202 textD
->selectFGPixel
, textD
->selectBGPixel
,
4203 textD
->highlightFGPixel
,textD
->highlightBGPixel
,
4204 textD
->lineNumFGPixel
, textD
->cursorFGPixel
);
4207 /* Set the minimum pane height in the new pane */
4208 UpdateMinPaneHeights(window
);
4210 for (i
=0; i
<=window
->nPanes
; i
++) {
4211 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
4212 setPaneDesiredHeight(containingPane(text
), paneHeights
[i
]);
4215 /* Re-manage panedWindow to recalculate pane heights & reset selection */
4216 XtManageChild(window
->splitPane
);
4219 /* Reset all of the heights, scroll positions, etc. */
4220 for (i
=0; i
<=window
->nPanes
; i
++) {
4223 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
4224 TextSetCursorPos(text
, insertPositions
[i
]);
4225 TextSetScroll(text
, topLines
[i
], horizOffsets
[i
]);
4227 /* dim the cursor */
4228 textD
= ((TextWidget
)text
)->text
.textD
;
4229 TextDSetCursorStyle(textD
, DIM_CURSOR
);
4230 TextDUnblankCursor(textD
);
4233 /* set the focus pane */
4234 for (i
=0; i
<=window
->nPanes
; i
++) {
4235 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
4236 if(i
== focusPane
) {
4237 window
->lastFocus
= text
;
4238 XmProcessTraversal(text
, XmTRAVERSE_CURRENT
);
4243 /* Update the window manager size hints after the sizes of the panes have
4244 been set (the widget heights are not yet readable here, but they will
4245 be by the time the event loop gets around to running this timer proc) */
4246 XtAppAddTimeOut(XtWidgetToApplicationContext(window
->shell
), 0,
4247 wmSizeUpdateProc
, window
);
4251 ** clone a document's states and settings into the other.
4253 static void cloneDocument(WindowInfo
*window
, WindowInfo
*orgWin
)
4255 const char *orgDocument
;
4259 strcpy(window
->path
, orgWin
->path
);
4260 strcpy(window
->filename
, orgWin
->filename
);
4262 ShowLineNumbers(window
, orgWin
->showLineNumbers
);
4264 window
->ignoreModify
= True
;
4266 /* copy the text buffer */
4267 orgDocument
= BufAsString(orgWin
->buffer
);
4268 BufSetAll(window
->buffer
, orgDocument
);
4270 /* copy the tab preferences (here!) */
4271 BufSetTabDistance(window
->buffer
, orgWin
->buffer
->tabDist
);
4272 window
->buffer
->useTabs
= orgWin
->buffer
->useTabs
;
4273 XtVaGetValues(orgWin
->textArea
, textNemulateTabs
, &emTabDist
, NULL
);
4274 SetEmTabDist(window
, emTabDist
);
4276 window
->ignoreModify
= False
;
4278 /* transfer text fonts */
4279 params
[0] = orgWin
->fontName
;
4280 params
[1] = orgWin
->italicFontName
;
4281 params
[2] = orgWin
->boldFontName
;
4282 params
[3] = orgWin
->boldItalicFontName
;
4283 XtCallActionProc(window
->textArea
, "set_fonts", NULL
, params
, 4);
4285 SetBacklightChars(window
, orgWin
->backlightCharTypes
);
4287 /* Clone rangeset info.
4290 Cloning of rangesets must be done before syntax highlighting,
4291 else the rangesets do not be highlighted (colored) properly
4292 if syntax highlighting is on.
4294 window
->buffer
->rangesetTable
=
4295 RangesetTableClone(orgWin
->buffer
->rangesetTable
, window
->buffer
);
4297 /* Syntax highlighting */
4298 window
->languageMode
= orgWin
->languageMode
;
4299 window
->highlightSyntax
= orgWin
->highlightSyntax
;
4300 if (window
->highlightSyntax
)
4301 StartHighlighting(window
, False
);
4303 /* copy states of original document */
4304 window
->filenameSet
= orgWin
->filenameSet
;
4305 window
->fileFormat
= orgWin
->fileFormat
;
4306 window
->lastModTime
= orgWin
->lastModTime
;
4307 window
->fileChanged
= orgWin
->fileChanged
;
4308 window
->fileMissing
= orgWin
->fileMissing
;
4309 window
->lockReasons
= orgWin
->lockReasons
;
4310 window
->autoSaveCharCount
= orgWin
->autoSaveCharCount
;
4311 window
->autoSaveOpCount
= orgWin
->autoSaveOpCount
;
4312 window
->undoOpCount
= orgWin
->undoOpCount
;
4313 window
->undoMemUsed
= orgWin
->undoMemUsed
;
4314 window
->lockReasons
= orgWin
->lockReasons
;
4315 window
->autoSave
= orgWin
->autoSave
;
4316 window
->saveOldVersion
= orgWin
->saveOldVersion
;
4317 window
->wrapMode
= orgWin
->wrapMode
;
4318 SetOverstrike(window
, orgWin
->overstrike
);
4319 window
->showMatchingStyle
= orgWin
->showMatchingStyle
;
4320 window
->matchSyntaxBased
= orgWin
->matchSyntaxBased
;
4322 window
->showStats
= orgWin
->showStats
;
4323 window
->showISearchLine
= orgWin
->showISearchLine
;
4324 window
->showLineNumbers
= orgWin
->showLineNumbers
;
4325 window
->modeMessageDisplayed
= orgWin
->modeMessageDisplayed
;
4326 window
->ignoreModify
= orgWin
->ignoreModify
;
4327 window
->windowMenuValid
= orgWin
->windowMenuValid
;
4328 window
->flashTimeoutID
= orgWin
->flashTimeoutID
;
4329 window
->wasSelected
= orgWin
->wasSelected
;
4330 strcpy(window
->fontName
, orgWin
->fontName
);
4331 strcpy(window
->italicFontName
, orgWin
->italicFontName
);
4332 strcpy(window
->boldFontName
, orgWin
->boldFontName
);
4333 strcpy(window
->boldItalicFontName
, orgWin
->boldItalicFontName
);
4334 window
->fontList
= orgWin
->fontList
;
4335 window
->italicFontStruct
= orgWin
->italicFontStruct
;
4336 window
->boldFontStruct
= orgWin
->boldFontStruct
;
4337 window
->boldItalicFontStruct
= orgWin
->boldItalicFontStruct
;
4338 window
->markTimeoutID
= orgWin
->markTimeoutID
;
4339 window
->highlightData
= orgWin
->highlightData
;
4340 window
->shellCmdData
= orgWin
->shellCmdData
;
4341 window
->macroCmdData
= orgWin
->macroCmdData
;
4342 window
->smartIndentData
= orgWin
->smartIndentData
;
4344 window
->iSearchHistIndex
= orgWin
->iSearchHistIndex
;
4345 window
->iSearchStartPos
= orgWin
->iSearchStartPos
;
4346 window
->replaceLastRegexCase
= orgWin
->replaceLastRegexCase
;
4347 window
->replaceLastLiteralCase
= orgWin
->replaceLastLiteralCase
;
4348 window
->iSearchLastRegexCase
= orgWin
->iSearchLastRegexCase
;
4349 window
->iSearchLastLiteralCase
= orgWin
->iSearchLastLiteralCase
;
4350 window
->findLastRegexCase
= orgWin
->findLastRegexCase
;
4351 window
->findLastLiteralCase
= orgWin
->findLastLiteralCase
;
4352 window
->device
= orgWin
->device
;
4353 window
->inode
= orgWin
->inode
;
4354 window
->fileClosedAtom
= orgWin
->fileClosedAtom
;
4355 orgWin
->fileClosedAtom
= None
;
4357 /* copy the text/split panes settings, cursor pos & selection */
4358 cloneTextPanes(window
, orgWin
);
4360 /* copy undo & redo list */
4361 window
->undo
= cloneUndoItems(orgWin
->undo
);
4362 window
->redo
= cloneUndoItems(orgWin
->redo
);
4364 /* copy bookmarks */
4365 window
->nMarks
= orgWin
->nMarks
;
4366 memcpy(&window
->markTable
, &orgWin
->markTable
,
4367 sizeof(Bookmark
)*window
->nMarks
);
4369 /* kick start the auto-indent engine */
4370 window
->indentStyle
= NO_AUTO_INDENT
;
4371 SetAutoIndent(window
, orgWin
->indentStyle
);
4373 /* synchronize window state to this document */
4374 RefreshWindowStates(window
);
4377 static UndoInfo
*cloneUndoItems(UndoInfo
*orgList
)
4379 UndoInfo
*head
= NULL
, *undo
, *clone
, *last
= NULL
;
4381 for (undo
= orgList
; undo
; undo
= undo
->next
) {
4382 clone
= (UndoInfo
*)XtMalloc(sizeof(UndoInfo
));
4383 memcpy(clone
, undo
, sizeof(UndoInfo
));
4385 if (undo
->oldText
) {
4386 clone
->oldText
= XtMalloc(strlen(undo
->oldText
)+1);
4387 strcpy(clone
->oldText
, undo
->oldText
);
4403 ** spin off the document to a new window
4405 WindowInfo
*DetachDocument(WindowInfo
*window
)
4407 WindowInfo
*win
= NULL
, *cloneWin
;
4409 if (NDocuments(window
) < 2)
4412 /* raise another document in the same shell window if the window
4413 being detached is the top document */
4414 if (IsTopDocument(window
)) {
4415 win
= getNextTabWindow(window
, 1, 0, 0);
4419 /* Create a new window */
4420 cloneWin
= CreateWindow(window
->filename
, NULL
, False
);
4422 /* CreateWindow() simply adds the new window's pointer to the
4423 head of WindowList. We need to adjust the detached window's
4424 pointer, so that macro functions such as focus_window("last")
4425 will travel across the documents per the sequence they're
4426 opened. The new doc will appear to replace it's former self
4427 as the old doc is closed. */
4428 WindowList
= cloneWin
->next
;
4429 cloneWin
->next
= window
->next
;
4430 window
->next
= cloneWin
;
4432 /* these settings should follow the detached document.
4433 must be done before cloning window, else the height
4434 of split panes may not come out correctly */
4435 ShowISearchLine(cloneWin
, window
->showISearchLine
);
4436 ShowStatsLine(cloneWin
, window
->showStats
);
4438 /* clone the document & its pref settings */
4439 cloneDocument(cloneWin
, window
);
4441 /* remove the document from the old window */
4442 window
->fileChanged
= False
;
4443 CloseFileAndWindow(window
, NO_SBC_DIALOG_RESPONSE
);
4445 /* refresh former host window */
4447 RefreshWindowStates(win
);
4450 /* this should keep the new document window fresh */
4451 RefreshWindowStates(cloneWin
);
4452 RefreshTabState(cloneWin
);
4453 SortTabBar(cloneWin
);
4459 ** Move document to an other window.
4461 ** the moving document will receive certain window settings from
4462 ** its new host, i.e. the window size, stats and isearch lines.
4464 WindowInfo
*MoveDocument(WindowInfo
*toWindow
, WindowInfo
*window
)
4466 WindowInfo
*win
= NULL
, *cloneWin
;
4468 /* prepare to move document */
4469 if (NDocuments(window
) < 2) {
4470 /* hide the window to make it look like we are moving */
4471 XtUnmapWidget(window
->shell
);
4473 else if (IsTopDocument(window
)) {
4474 /* raise another document to replace the document being moved */
4475 win
= getNextTabWindow(window
, 1, 0, 0);
4479 /* relocate the document to target window */
4480 cloneWin
= CreateDocument(toWindow
, window
->filename
);
4481 ShowTabBar(cloneWin
, GetShowTabBar(cloneWin
));
4482 cloneDocument(cloneWin
, window
);
4484 /* CreateDocument() simply adds the new window's pointer to the
4485 head of WindowList. We need to adjust the detached window's
4486 pointer, so that macro functions such as focus_window("last")
4487 will travel across the documents per the sequence they're
4488 opened. The new doc will appear to replace it's former self
4489 as the old doc is closed. */
4490 WindowList
= cloneWin
->next
;
4491 cloneWin
->next
= window
->next
;
4492 window
->next
= cloneWin
;
4494 /* remove the document from the old window */
4495 window
->fileChanged
= False
;
4496 CloseFileAndWindow(window
, NO_SBC_DIALOG_RESPONSE
);
4498 /* some menu states might have changed when deleting document */
4500 RefreshWindowStates(win
);
4502 /* this should keep the new document window fresh */
4503 RaiseDocumentWindow(cloneWin
);
4504 RefreshTabState(cloneWin
);
4505 SortTabBar(cloneWin
);
4510 static void moveDocumentCB(Widget dialog
, WindowInfo
*window
,
4511 XtPointer call_data
)
4513 XmSelectionBoxCallbackStruct
*cbs
= (XmSelectionBoxCallbackStruct
*) call_data
;
4514 DoneWithMoveDocumentDialog
= cbs
->reason
;
4518 ** present dialog for selecting a target window to move this document
4519 ** into. Do nothing if there is only one shell window opened.
4521 void MoveDocumentDialog(WindowInfo
*window
)
4523 WindowInfo
*win
, *targetWin
, **shellWinList
;
4524 int i
, nList
=0, nWindows
=0, ac
;
4525 char tmpStr
[MAXPATHLEN
+50];
4526 Widget parent
, dialog
, listBox
, moveAllOption
;
4527 XmString
*list
= NULL
;
4528 XmString popupTitle
, s1
;
4530 int *position_list
, position_count
;
4532 /* get the list of available shell windows, not counting
4533 the document to be moved */
4534 nWindows
= NWindows();
4535 list
= (XmStringTable
) XtMalloc(nWindows
* sizeof(XmString
*));
4536 shellWinList
= (WindowInfo
**) XtMalloc(nWindows
* sizeof(WindowInfo
*));
4538 for (win
=WindowList
; win
; win
=win
->next
) {
4539 if (!IsTopDocument(win
) || win
->shell
== window
->shell
)
4542 sprintf(tmpStr
, "%s%s",
4543 win
->filenameSet
? win
->path
: "", win
->filename
);
4545 list
[nList
] = XmStringCreateSimple(tmpStr
);
4546 shellWinList
[nList
] = win
;
4550 /* stop here if there's no other window to move to */
4552 XtFree((char *)list
);
4553 XtFree((char *)shellWinList
);
4557 /* create the dialog */
4558 parent
= window
->shell
;
4559 popupTitle
= XmStringCreateSimple("Move Document");
4560 sprintf(tmpStr
, "Move %s into window of", window
->filename
);
4561 s1
= XmStringCreateSimple(tmpStr
);
4563 XtSetArg(csdargs
[ac
], XmNdialogStyle
, XmDIALOG_FULL_APPLICATION_MODAL
); ac
++;
4564 XtSetArg(csdargs
[ac
], XmNdialogTitle
, popupTitle
); ac
++;
4565 XtSetArg(csdargs
[ac
], XmNlistLabelString
, s1
); ac
++;
4566 XtSetArg(csdargs
[ac
], XmNlistItems
, list
); ac
++;
4567 XtSetArg(csdargs
[ac
], XmNlistItemCount
, nList
); ac
++;
4568 XtSetArg(csdargs
[ac
], XmNvisibleItemCount
, 12); ac
++;
4569 XtSetArg(csdargs
[ac
], XmNautoUnmanage
, False
); ac
++;
4570 dialog
= CreateSelectionDialog(parent
,"moveDocument",csdargs
,ac
);
4571 XtUnmanageChild(XmSelectionBoxGetChild(dialog
, XmDIALOG_TEXT
));
4572 XtUnmanageChild(XmSelectionBoxGetChild(dialog
, XmDIALOG_HELP_BUTTON
));
4573 XtUnmanageChild(XmSelectionBoxGetChild(dialog
, XmDIALOG_SELECTION_LABEL
));
4574 XtAddCallback(dialog
, XmNokCallback
, (XtCallbackProc
)moveDocumentCB
, window
);
4575 XtAddCallback(dialog
, XmNapplyCallback
, (XtCallbackProc
)moveDocumentCB
, window
);
4576 XtAddCallback(dialog
, XmNcancelCallback
, (XtCallbackProc
)moveDocumentCB
, window
);
4578 XmStringFree(popupTitle
);
4580 /* free the window list */
4581 for (i
=0; i
<nList
; i
++)
4582 XmStringFree(list
[i
]);
4583 XtFree((char *)list
);
4585 /* create the option box for moving all documents */
4586 s1
= MKSTRING("Move all documents in this window");
4587 moveAllOption
= XtVaCreateWidget("moveAll",
4588 xmToggleButtonWidgetClass
, dialog
,
4590 XmNalignment
, XmALIGNMENT_BEGINNING
,
4594 if (NDocuments(window
) >1)
4595 XtManageChild(moveAllOption
);
4597 /* disable option if only one document in the window */
4598 XtUnmanageChild(XmSelectionBoxGetChild(dialog
, XmDIALOG_APPLY_BUTTON
));
4600 s1
= MKSTRING("Move");
4601 XtVaSetValues (dialog
, XmNokLabelString
, s1
, NULL
);
4604 /* default to the first window on the list */
4605 listBox
= XmSelectionBoxGetChild(dialog
, XmDIALOG_LIST
);
4606 XmListSelectPos(listBox
, 1, True
);
4608 /* show the dialog */
4609 DoneWithMoveDocumentDialog
= 0;
4610 ManageDialogCenteredOnPointer(dialog
);
4611 while (!DoneWithMoveDocumentDialog
)
4612 XtAppProcessEvent(XtWidgetToApplicationContext(parent
), XtIMAll
);
4614 /* get the window to move document into */
4615 XmListGetSelectedPos(listBox
, &position_list
, &position_count
);
4616 targetWin
= shellWinList
[position_list
[0]-1];
4617 XtFree((char *)position_list
);
4619 /* now move document(s) */
4620 if (DoneWithMoveDocumentDialog
== XmCR_OK
) {
4621 /* move top document */
4622 if (XmToggleButtonGetState(moveAllOption
)) {
4623 /* move all documents */
4624 for (win
= WindowList
; win
; ) {
4625 if (win
!= window
&& win
->shell
== window
->shell
) {
4626 WindowInfo
*next
= win
->next
;
4627 MoveDocument(targetWin
, win
);
4634 /* invoking document is the last to move */
4635 MoveDocument(targetWin
, window
);
4638 MoveDocument(targetWin
, window
);
4642 XtFree((char *)shellWinList
);
4643 XtDestroyWidget(dialog
);
4646 static void hideTooltip(Widget tab
)
4648 Widget tooltip
= XtNameToWidget(tab
, "*BubbleShell");
4654 static void closeTabProc(XtPointer clientData
, XtIntervalId
*id
)
4656 CloseFileAndWindow((WindowInfo
*)clientData
, PROMPT_SBC_DIALOG_RESPONSE
);
4660 ** callback to close-tab button.
4662 static void closeTabCB(Widget w
, Widget mainWin
, caddr_t callData
)
4664 /* FIXME: XtRemoveActionHook() related coredump
4666 An unknown bug seems to be associated with the XtRemoveActionHook()
4667 call in FinishLearn(), which resulted in coredump if a tab was
4668 closed, in the middle of keystrokes learning, by clicking on the
4671 As evident to our accusation, the coredump may be surpressed by
4672 simply commenting out the XtRemoveActionHook() call. The bug was
4673 consistent on both Motif and Lesstif on various platforms.
4675 Closing the tab through either the "Close" menu or its accel key,
4676 however, was without any trouble.
4678 While its actual mechanism is not well understood, we somehow
4679 managed to workaround the bug by delaying the action of closing
4680 the tab. For now. */
4681 XtAppAddTimeOut(XtWidgetToApplicationContext(w
), 0,
4682 closeTabProc
, GetTopDocument(mainWin
));
4686 ** callback to clicks on a tab to raise it's document.
4688 static void raiseTabCB(Widget w
, XtPointer clientData
, XtPointer callData
)
4690 XmLFolderCallbackStruct
*cbs
= (XmLFolderCallbackStruct
*)callData
;
4694 XtVaGetValues(w
, XmNtabWidgetList
, &tabList
, NULL
);
4695 tab
= tabList
[cbs
->pos
];
4696 RaiseDocument(TabToWindow(tab
));
4699 static Widget
containingPane(Widget w
)
4701 /* The containing pane used to simply be the first parent, but with
4702 the introduction of an XmFrame, it's the grandparent. */
4703 return XtParent(XtParent(w
));
4706 static void cancelTimeOut(XtIntervalId
*timer
)
4710 XtRemoveTimeOut(*timer
);
4716 ** set/clear toggle menu state if the calling document is on top.
4718 void SetToggleButtonState(WindowInfo
*window
, Widget w
, Boolean state
,
4721 if (IsTopDocument(window
)) {
4722 XmToggleButtonSetState(w
, state
, notify
);
4727 ** set/clear menu sensitivity if the calling document is on top.
4729 void SetSensitive(WindowInfo
*window
, Widget w
, Boolean sensitive
)
4731 if (IsTopDocument(window
)) {
4732 XtSetSensitive(w
, sensitive
);
4737 ** Remove redundant expose events on tab bar.
4739 void CleanUpTabBarExposeQueue(WindowInfo
*window
)
4748 /* remove redundant expose events on tab bar */
4750 while (XCheckTypedWindowEvent(TheDisplay
, XtWindow(window
->tabBar
),
4754 /* now we can update tabbar */
4757 ev
.display
= TheDisplay
;
4758 ev
.window
= XtWindow(window
->tabBar
);
4761 ev
.width
= XtWidth(window
->tabBar
);
4762 ev
.height
= XtHeight(window
->tabBar
);
4764 XSendEvent(TheDisplay
, XtWindow(window
->tabBar
), False
,
4765 ExposureMask
, (XEvent
*)&ev
);