1 static const char CVSID
[] = "$Id: window.c,v 1.91 2003/12/28 17:25:32 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 *
13 * This software is distributed in the hope that it will be useful, but WITHOUT *
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
18 * You should have received a copy of the GNU General Public License along with *
19 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
20 * Place, Suite 330, Boston, MA 02111-1307 USA *
22 * Nirvana Text Editor *
25 * Written by Mark Edel *
27 *******************************************************************************/
30 #include "../config.h"
44 #include "preferences.h"
45 #include "selection.h"
49 #include "highlight.h"
50 #include "smartIndent.h"
54 #include "windowTitle.h"
55 #include "interpret.h"
56 #include "../util/clearcase.h"
57 #include "../util/misc.h"
58 #include "../util/fileUtils.h"
59 #include "../util/utils.h"
60 #include "../util/fileUtils.h"
61 #include "../util/DialogF.h"
62 #include "../Xlt/BubbleButton.h"
63 #include "../Microline/XmL/Folder.h"
69 #include "../util/VMSparam.h"
72 #include <sys/param.h>
74 #include "../util/clearcase.h"
84 #include <X11/Intrinsic.h>
85 #include <X11/Shell.h>
86 #include <X11/Xatom.h>
89 #include <Xm/PanedW.h>
90 #include <Xm/PanedWP.h>
91 #include <Xm/RowColumnP.h>
92 #include <Xm/Separator.h>
94 #include <Xm/ToggleB.h>
99 #include <Xm/SelectioB.h>
101 #include <Xm/Protocols.h>
102 #include <Xm/ScrolledW.h>
103 #include <Xm/ScrollBar.h>
104 #include <Xm/PrimitiveP.h>
105 #include <Xm/Frame.h>
107 #include <X11/Xmu/Editres.h>
108 /* extern void _XEditResCheckMessages(); */
112 #include "../debug.h"
115 /* Initial minimum height of a pane. Just a fallback in case setPaneMinHeight
116 (which may break in a future release) is not available */
117 #define PANE_MIN_HEIGHT 39
119 /* Thickness of 3D border around statistics and/or incremental search areas
120 below the main menu bar */
121 #define STAT_SHADOW_THICKNESS 1
123 /* buffer tabs configuration */
124 #define MIN_TAB_SLOTS 3
126 /* bitmap data for the close-tab button */
127 #define close_width 11
128 #define close_height 11
129 static unsigned char close_bits
[] = {
130 0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0xdc, 0x01, 0xf8, 0x00, 0x70, 0x00,
131 0xf8, 0x00, 0xdc, 0x01, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00};
133 static WindowInfo
*getNextTabWindow(WindowInfo
*window
, int direction
,
135 static Widget
addBufferTab(Widget folder
, WindowInfo
*window
, const char *string
);
136 static int getTabPosition(Widget tab
);
137 static void setTabCloseButtonImage(Widget button
);
138 static Widget
manageToolBars(Widget toolBarsForm
);
139 static void CloseBufferWindow(Widget w
, WindowInfo
*window
, XtPointer callData
);
140 static void closeTabCB(Widget w
, Widget mainWin
, caddr_t callData
);
141 static void clickTabCB(Widget w
, XtPointer
*clientData
, XtPointer callData
);
142 static void raiseTabCB(Widget w
, XtPointer
*clientData
, XtPointer callData
);
143 static Widget
createTextArea(Widget parent
, WindowInfo
*window
, int rows
,
144 int cols
, int emTabDist
, char *delimiters
, int wrapMargin
,
146 static void showStats(WindowInfo
*window
, int state
);
147 static void showISearch(WindowInfo
*window
, int state
);
148 static void showStatsForm(WindowInfo
*window
, int state
);
149 static void addToWindowList(WindowInfo
*window
);
150 static void removeFromWindowList(WindowInfo
*window
);
151 static void focusCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
152 static void modifiedCB(int pos
, int nInserted
, int nDeleted
, int nRestyled
,
153 char *deletedText
, void *cbArg
);
154 static void movedCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
155 static void dragStartCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
156 static void dragEndCB(Widget w
, WindowInfo
*window
, dragEndCBStruct
*callData
);
157 static void closeCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
158 static void saveYourselfCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
159 static void setPaneDesiredHeight(Widget w
, int height
);
160 static void setPaneMinHeight(Widget w
, int min
);
161 static void addWindowIcon(Widget shell
);
162 static void wmSizeUpdateProc(XtPointer clientData
, XtIntervalId
*id
);
163 static void getGeometryString(WindowInfo
*window
, char *geomString
);
165 static void patchRowCol(Widget w
);
166 static void patchedRemoveChild(Widget child
);
168 static unsigned char* sanitizeVirtualKeyBindings();
169 static int sortAlphabetical(const void* k1
, const void* k2
);
170 static int virtKeyBindingsAreInvalid(const unsigned char* bindings
);
171 static void restoreInsaneVirtualKeyBindings(unsigned char* bindings
);
172 static void setBufferSharedPref(WindowInfo
*window
, WindowInfo
*lastwin
);
173 static void refreshBufferMenuBar(WindowInfo
*window
);
174 static void cloneBuffer(WindowInfo
*window
, WindowInfo
*orgWin
);
175 static void cloneTextPane(WindowInfo
*window
, WindowInfo
*orgWin
);
176 static UndoInfo
*cloneUndoItems(UndoInfo
*orgList
);
177 static Widget
containingPane(Widget w
);
179 static WindowInfo
*focusInBuffer
= NULL
; /* where we are now */
180 static WindowInfo
*lastBuffer
= NULL
; /* where we came from */
181 static int DoneWithAttachBufferDialog
;
185 ** Create a new editor window
187 WindowInfo
*CreateWindow(const char *name
, char *geometry
, int iconic
)
189 Widget winShell
, mainWin
, menuBar
, pane
, text
, stats
, statsAreaForm
;
190 Widget iSearchLabel
, closeTabBtn
, tabForm
, form
;
198 char sgi_title
[MAXPATHLEN
+ 14 + SGI_WINDOW_TITLE_LEN
] = SGI_WINDOW_TITLE
;
200 char newGeometry
[MAX_GEOM_STRING_LEN
];
201 unsigned int rows
, cols
;
203 static Atom wmpAtom
, syAtom
= 0;
204 static int firstTime
= True
;
205 unsigned char* invalidBindings
= NULL
;
207 int fontWidth
, tabWidth
;
212 invalidBindings
= sanitizeVirtualKeyBindings();
216 /* Allocate some memory for the new window data structure */
217 window
= (WindowInfo
*)XtMalloc(sizeof(WindowInfo
));
219 /* initialize window structure */
220 /* + Schwarzenberg: should a
221 memset(window, 0, sizeof(WindowInfo));
224 window
->replaceDlog
= NULL
;
225 window
->replaceText
= NULL
;
226 window
->replaceWithText
= NULL
;
227 window
->replaceWordToggle
= NULL
;
228 window
->replaceCaseToggle
= NULL
;
229 window
->replaceRegexToggle
= NULL
;
230 window
->findDlog
= NULL
;
231 window
->findText
= NULL
;
232 window
->findWordToggle
= NULL
;
233 window
->findCaseToggle
= NULL
;
234 window
->findRegexToggle
= NULL
;
235 window
->replaceMultiFileDlog
= NULL
;
236 window
->replaceMultiFilePathBtn
= NULL
;
237 window
->replaceMultiFileList
= NULL
;
238 window
->multiFileReplSelected
= FALSE
;
239 window
->multiFileBusy
= FALSE
;
240 window
->writableWindows
= NULL
;
241 window
->nWritableWindows
= 0;
242 window
->fileChanged
= FALSE
;
243 window
->fileMode
= 0;
244 window
->filenameSet
= FALSE
;
245 window
->fileFormat
= UNIX_FILE_FORMAT
;
246 window
->lastModTime
= 0;
247 window
->fileMissing
= True
;
248 strcpy(window
->filename
, name
);
252 window
->autoSaveCharCount
= 0;
253 window
->autoSaveOpCount
= 0;
254 window
->undoOpCount
= 0;
255 window
->undoMemUsed
= 0;
256 CLEAR_ALL_LOCKS(window
->lockReasons
);
257 window
->indentStyle
= GetPrefAutoIndent(PLAIN_LANGUAGE_MODE
);
258 window
->autoSave
= GetPrefAutoSave();
259 window
->saveOldVersion
= GetPrefSaveOldVersion();
260 window
->wrapMode
= GetPrefWrap(PLAIN_LANGUAGE_MODE
);
261 window
->overstrike
= False
;
262 window
->showMatchingStyle
= GetPrefShowMatching();
263 window
->matchSyntaxBased
= GetPrefMatchSyntaxBased();
264 window
->showTabBar
= GetPrefTabBar() ? (GetPrefTabBarHideOne()? 0:1) : 0;
265 window
->showStats
= GetPrefStatsLine();
266 window
->showISearchLine
= GetPrefISearchLine();
267 window
->showLineNumbers
= GetPrefLineNums();
268 window
->highlightSyntax
= GetPrefHighlightSyntax();
269 window
->backlightCharTypes
= NULL
;
270 window
->backlightChars
= GetPrefBacklightChars();
271 if (window
->backlightChars
) {
272 char *cTypes
= GetPrefBacklightCharTypes();
273 if (cTypes
&& window
->backlightChars
) {
274 if ((window
->backlightCharTypes
= XtMalloc(strlen(cTypes
) + 1)))
275 strcpy(window
->backlightCharTypes
, cTypes
);
278 window
->modeMessageDisplayed
= FALSE
;
279 window
->ignoreModify
= FALSE
;
280 window
->windowMenuValid
= FALSE
;
281 window
->prevOpenMenuValid
= FALSE
;
282 window
->flashTimeoutID
= 0;
283 window
->fileClosedAtom
= None
;
284 window
->wasSelected
= FALSE
;
286 strcpy(window
->fontName
, GetPrefFontName());
287 strcpy(window
->italicFontName
, GetPrefItalicFontName());
288 strcpy(window
->boldFontName
, GetPrefBoldFontName());
289 strcpy(window
->boldItalicFontName
, GetPrefBoldItalicFontName());
290 window
->colorDialog
= NULL
;
291 window
->fontList
= GetPrefFontList();
292 window
->italicFontStruct
= GetPrefItalicFont();
293 window
->boldFontStruct
= GetPrefBoldFont();
294 window
->boldItalicFontStruct
= GetPrefBoldItalicFont();
295 window
->fontDialog
= NULL
;
297 window
->markTimeoutID
= 0;
298 window
->highlightData
= NULL
;
299 window
->shellCmdData
= NULL
;
300 window
->macroCmdData
= NULL
;
301 window
->smartIndentData
= NULL
;
302 window
->languageMode
= PLAIN_LANGUAGE_MODE
;
303 window
->iSearchHistIndex
= 0;
304 window
->iSearchStartPos
= -1;
305 window
->replaceLastRegexCase
= TRUE
;
306 window
->replaceLastLiteralCase
= FALSE
;
307 window
->iSearchLastRegexCase
= TRUE
;
308 window
->iSearchLastLiteralCase
= FALSE
;
309 window
->findLastRegexCase
= TRUE
;
310 window
->findLastLiteralCase
= FALSE
;
311 window
->bufferTab
= NULL
;
313 /* If window geometry was specified, split it apart into a window position
314 component and a window size component. Create a new geometry string
315 containing the position component only. Rows and cols are stripped off
316 because we can't easily calculate the size in pixels from them until the
317 whole window is put together. Note that the preference resource is only
318 for clueless users who decide to specify the standard X geometry
319 application resource, which is pretty useless because width and height
320 are the same as the rows and cols preferences, and specifying a window
321 location will force all the windows to pile on top of one another */
322 if (geometry
== NULL
|| geometry
[0] == '\0')
323 geometry
= GetPrefGeometry();
324 if (geometry
== NULL
|| geometry
[0] == '\0') {
325 rows
= GetPrefRows();
326 cols
= GetPrefCols();
327 newGeometry
[0] = '\0';
329 bitmask
= XParseGeometry(geometry
, &x
, &y
, &cols
, &rows
);
331 fprintf(stderr
, "Bad window geometry specified: %s\n", geometry
);
333 if (!(bitmask
& WidthValue
))
334 cols
= GetPrefCols();
335 if (!(bitmask
& HeightValue
))
336 rows
= GetPrefRows();
338 CreateGeometryString(newGeometry
, x
, y
, 0, 0,
339 bitmask
& ~(WidthValue
| HeightValue
));
342 /* Create a new toplevel shell to hold the window */
345 strcat(sgi_title
, name
);
346 XtSetArg(al
[ac
], XmNtitle
, sgi_title
); ac
++;
347 XtSetArg(al
[ac
], XmNdeleteResponse
, XmDO_NOTHING
); ac
++;
348 if (strncmp(name
, "Untitled", 8) == 0) {
349 XtSetArg(al
[ac
], XmNiconName
, APP_NAME
); ac
++;
351 XtSetArg(al
[ac
], XmNiconName
, name
); ac
++;
354 XtSetArg(al
[ac
], XmNtitle
, name
); ac
++;
355 XtSetArg(al
[ac
], XmNdeleteResponse
, XmDO_NOTHING
); ac
++;
356 XtSetArg(al
[ac
], XmNiconName
, name
); ac
++;
358 XtSetArg(al
[ac
], XmNgeometry
, newGeometry
[0]=='\0'?NULL
:newGeometry
); ac
++;
359 XtSetArg(al
[ac
], XmNinitialState
,
360 iconic
? IconicState
: NormalState
); ac
++;
362 winShell
= CreateWidget(TheAppShell
, "textShell",
363 topLevelShellWidgetClass
, al
, ac
);
364 window
->shell
= winShell
;
367 XtAddEventHandler (winShell
, (EventMask
)0, True
,
368 (XtEventHandler
)_XEditResCheckMessages
, NULL
);
372 addWindowIcon(winShell
);
375 /* Create a MainWindow to manage the menubar and text area, set the
376 userData resource to be used by WidgetToWindow to recover the
377 window pointer from the widget id of any of the window's widgets */
378 XtSetArg(al
[ac
], XmNuserData
, window
); ac
++;
379 mainWin
= XmCreateMainWindow(winShell
, "main", al
, ac
);
380 window
->mainWin
= mainWin
;
381 XtManageChild(mainWin
);
383 /* The statsAreaForm holds the stats line and the I-Search line. */
384 statsAreaForm
= XtVaCreateWidget("statsAreaForm",
385 xmFormWidgetClass
, mainWin
,
386 XmNmarginWidth
, STAT_SHADOW_THICKNESS
,
387 XmNmarginHeight
, STAT_SHADOW_THICKNESS
,
388 /* XmNautoUnmanage, False, */
390 if (window
->showTabBar
|| window
->showISearchLine
||
392 XtManageChild(statsAreaForm
);
394 /* NOTE: due to a bug in openmotif 2.1.30, NEdit used to crash when
395 the i-search bar was active, and the i-search text widget was focussed,
396 and the window's width was resized to nearly zero.
397 In theory, it is possible to avoid this by imposing a minimum
398 width constraint on the nedit windows, but that width would have to
399 be at least 30 characters, which is probably unacceptable.
400 Amazingly, adding a top offset of 1 pixel to the toggle buttons of
401 the i-search bar, while keeping the the top offset of the text widget
402 to 0 seems to avoid avoid the crash. */
404 window
->iSearchForm
= XtVaCreateWidget("iSearchForm",
405 xmFormWidgetClass
, statsAreaForm
,
406 XmNshadowThickness
, 0,
407 XmNleftAttachment
, XmATTACH_FORM
,
408 XmNleftOffset
, STAT_SHADOW_THICKNESS
,
409 XmNtopAttachment
, XmATTACH_FORM
,
410 XmNtopOffset
, STAT_SHADOW_THICKNESS
,
411 XmNrightAttachment
, XmATTACH_FORM
,
412 XmNrightOffset
, STAT_SHADOW_THICKNESS
,
413 XmNbottomOffset
, STAT_SHADOW_THICKNESS
, NULL
);
414 if(window
->showISearchLine
)
415 XtManageChild(window
->iSearchForm
);
416 iSearchLabel
= XtVaCreateManagedWidget("iSearchLabel",
417 xmLabelWidgetClass
, window
->iSearchForm
,
418 XmNlabelString
, s1
=XmStringCreateSimple("Find:"),
420 XmNleftAttachment
, XmATTACH_FORM
,
422 XmNtopAttachment
, XmATTACH_FORM
,
423 XmNtopOffset
, 1, /* see openmotif note above, for aligment
424 with toggle buttons below */
425 XmNbottomAttachment
, XmATTACH_FORM
, NULL
);
428 /* Disable keyboard traversal of the toggle buttons. We were doing
429 this previously by forcing the keyboard focus back to the text
430 widget whenever a toggle changed. That causes an ugly focus flash
431 on screen. It's better just not to go there in the first place.
432 Plus, if the user really wants traversal, it's an X resource so it
433 can be enabled without too much pain and suffering. */
435 window
->iSearchCaseToggle
= XtVaCreateManagedWidget("iSearchCaseToggle",
436 xmToggleButtonWidgetClass
, window
->iSearchForm
,
437 XmNlabelString
, s1
=XmStringCreateSimple("Case"),
438 XmNset
, GetPrefSearch() == SEARCH_CASE_SENSE
439 || GetPrefSearch() == SEARCH_REGEX
440 || GetPrefSearch() == SEARCH_CASE_SENSE_WORD
,
441 XmNtopAttachment
, XmATTACH_FORM
,
442 XmNbottomAttachment
, XmATTACH_FORM
,
443 XmNtopOffset
, 1, /* see openmotif note above */
444 XmNrightAttachment
, XmATTACH_FORM
,
446 XmNtraversalOn
, False
,
450 window
->iSearchRegexToggle
= XtVaCreateManagedWidget("iSearchREToggle",
451 xmToggleButtonWidgetClass
, window
->iSearchForm
,
452 XmNlabelString
, s1
=XmStringCreateSimple("RegExp"),
453 XmNset
, GetPrefSearch() == SEARCH_REGEX_NOCASE
454 || GetPrefSearch() == SEARCH_REGEX
,
455 XmNtopAttachment
, XmATTACH_FORM
,
456 XmNbottomAttachment
, XmATTACH_FORM
,
457 XmNtopOffset
, 1, /* see openmotif note above */
458 XmNrightAttachment
, XmATTACH_WIDGET
,
459 XmNrightWidget
, window
->iSearchCaseToggle
,
461 XmNtraversalOn
, False
,
465 window
->iSearchRevToggle
= XtVaCreateManagedWidget("iSearchRevToggle",
466 xmToggleButtonWidgetClass
, window
->iSearchForm
,
467 XmNlabelString
, s1
=XmStringCreateSimple("Rev"),
469 XmNtopAttachment
, XmATTACH_FORM
,
470 XmNbottomAttachment
, XmATTACH_FORM
,
471 XmNtopOffset
, 1, /* see openmotif note above */
472 XmNrightAttachment
, XmATTACH_WIDGET
,
473 XmNrightWidget
, window
->iSearchRegexToggle
,
475 XmNtraversalOn
, False
,
479 window
->iSearchText
= XtVaCreateManagedWidget("iSearchText",
480 xmTextWidgetClass
, window
->iSearchForm
,
482 XmNnavigationType
, XmEXCLUSIVE_TAB_GROUP
,
483 XmNleftAttachment
, XmATTACH_WIDGET
,
484 XmNleftWidget
, iSearchLabel
,
485 XmNrightAttachment
, XmATTACH_WIDGET
,
486 XmNrightWidget
, window
->iSearchRevToggle
,
488 XmNtopAttachment
, XmATTACH_FORM
,
489 XmNtopOffset
, 0, /* see openmotif note above */
490 XmNbottomAttachment
, XmATTACH_FORM
,
491 XmNbottomOffset
, 0, NULL
);
492 RemapDeleteKey(window
->iSearchText
);
494 SetISearchTextCallbacks(window
);
496 /* create the buffer tab bar */
497 tabForm
= XtVaCreateWidget("tabForm",
498 xmFormWidgetClass
, statsAreaForm
,
503 XmNleftAttachment
, XmATTACH_FORM
,
504 XmNrightAttachment
, XmATTACH_FORM
,
505 XmNshadowThickness
, 0, NULL
);
507 /* button to close top buffer */
508 closeTabBtn
= XtVaCreateManagedWidget("closeTabBtn",
509 xmPushButtonWidgetClass
, tabForm
,
512 XmNhighlightThickness
, 0,
513 XmNlabelType
, XmPIXMAP
,
514 XmNshadowThickness
, 1,
515 XmNtraversalOn
, False
,
516 XmNrightAttachment
, XmATTACH_FORM
,
518 XmNbottomAttachment
, XmATTACH_FORM
,
522 XtAddCallback(closeTabBtn
, XmNactivateCallback
, (XtCallbackProc
)closeTabCB
,
524 setTabCloseButtonImage(closeTabBtn
);
526 window
->bufferTabBar
= XtVaCreateManagedWidget("tabBar",
527 xmlFolderWidgetClass
, tabForm
,
528 XmNresizePolicy
, XmRESIZE_PACK
,
529 XmNleftAttachment
, XmATTACH_FORM
,
531 XmNrightAttachment
, XmATTACH_WIDGET
,
532 XmNrightWidget
, closeTabBtn
,
534 XmNbottomAttachment
, XmATTACH_FORM
,
536 XmNtopAttachment
, XmATTACH_FORM
,
539 /* create an unmanaged composite widget to get the folder
540 widget to hide the 3D shadow for the manager area.
541 Note: this works only on the patched XmLFolder widget */
542 form
= XtVaCreateWidget("form",
543 xmFormWidgetClass
, window
->bufferTabBar
,
548 XtAddCallback(window
->bufferTabBar
, XmNactivateCallback
,
549 (XtCallbackProc
)raiseTabCB
, NULL
);
551 window
->bufferTab
= addBufferTab(window
->bufferTabBar
, window
, name
);
553 /* set minimum space for filename on tabs */
554 XtVaGetValues(window
->bufferTab
, XmNfontList
, &fontList
, NULL
);
555 fs
= GetDefaultFontStruct(fontList
);
556 fontWidth
= (fs
->min_bounds
.width
+ fs
->max_bounds
.width
)/2;
557 tabWidth
= fontWidth
* 20 + 5;
560 XtVaSetValues(window
->bufferTabBar
, XmNmaxTabWidth
, tabWidth
, NULL
);
562 if (window
->showTabBar
)
563 XtManageChild(tabForm
);
565 /* put a separating line below the tab bar */
566 XtVaCreateManagedWidget("TOOLBAR_SEP", xmSeparatorWidgetClass
,
568 XmNseparatorType
, XmSHADOW_ETCHED_IN
,
570 XmNleftAttachment
, XmATTACH_FORM
,
571 XmNrightAttachment
, XmATTACH_FORM
,
574 /* A form to hold the stats line text and line/col widgets */
575 window
->statsLineForm
= XtVaCreateWidget("statsLineForm",
576 xmFormWidgetClass
, statsAreaForm
,
577 XmNshadowThickness
, 0,
578 XmNtopAttachment
, window
->showISearchLine
?
579 XmATTACH_WIDGET
: XmATTACH_FORM
,
580 XmNtopWidget
, window
->iSearchForm
,
581 XmNrightAttachment
, XmATTACH_FORM
,
582 XmNleftAttachment
, XmATTACH_FORM
,
583 XmNbottomAttachment
, XmATTACH_FORM
,
584 XmNresizable
, False
, /* */
587 /* A separate display of the line/column number */
588 window
->statsLineColNo
= XtVaCreateManagedWidget("statsLineColNo",
589 xmLabelWidgetClass
, window
->statsLineForm
,
590 XmNlabelString
, s1
=XmStringCreateSimple("L: --- C: ---"),
591 XmNshadowThickness
, 0,
593 XmNtraversalOn
, False
,
594 XmNtopAttachment
, XmATTACH_FORM
,
595 XmNrightAttachment
, XmATTACH_FORM
,
596 XmNbottomAttachment
, XmATTACH_FORM
, /* */
600 /* Create file statistics display area. Using a text widget rather than
601 a label solves a layout problem with the main window, which messes up
602 if the label is too long (we would need a resize callback to control
603 the length when the window changed size), and allows users to select
604 file names and line numbers. Colors are copied from parent
605 widget, because many users and some system defaults color text
606 backgrounds differently from other widgets. */
607 XtVaGetValues(statsAreaForm
, XmNbackground
, &bgpix
, NULL
);
608 XtVaGetValues(statsAreaForm
, XmNforeground
, &fgpix
, NULL
);
609 stats
= XtVaCreateManagedWidget("statsLine",
610 xmTextWidgetClass
, window
->statsLineForm
,
611 XmNbackground
, bgpix
,
612 XmNforeground
, fgpix
,
613 XmNshadowThickness
, 0,
614 XmNhighlightColor
, bgpix
,
615 XmNhighlightThickness
, 0, /* must be zero, for OM (2.1.30) to
616 aligns tatsLineColNo & statsLine */
617 XmNmarginHeight
, 1, /* == statsLineColNo.marginHeight - 1,
618 to align with statsLineColNo */
619 XmNscrollHorizontal
, False
,
620 XmNeditMode
, XmSINGLE_LINE_EDIT
,
622 XmNtraversalOn
, False
,
623 XmNcursorPositionVisible
, False
,
624 XmNtopAttachment
, XmATTACH_OPPOSITE_WIDGET
, /* */
625 XmNtopWidget
, window
->statsLineColNo
,
626 XmNleftAttachment
, XmATTACH_FORM
,
627 XmNrightAttachment
, XmATTACH_WIDGET
,
628 XmNrightWidget
, window
->statsLineColNo
,
629 XmNbottomAttachment
, XmATTACH_OPPOSITE_WIDGET
, /* */
630 XmNbottomWidget
, window
->statsLineColNo
,
633 window
->statsLine
= stats
;
635 /* Manage the statsLineForm */
636 if(window
->showStats
)
637 XtManageChild(window
->statsLineForm
);
639 /* If the fontList was NULL, use the magical default provided by Motif,
640 since it must have worked if we've gotten this far */
641 if (window
->fontList
== NULL
)
642 XtVaGetValues(stats
, XmNfontList
, &window
->fontList
, NULL
);
644 manageToolBars(statsAreaForm
);
646 /* Create the menu bar */
647 menuBar
= CreateMenuBar(mainWin
, window
);
648 window
->menuBar
= menuBar
;
649 XtManageChild(menuBar
);
651 /* Create paned window to manage split window behavior */
652 pane
= XtVaCreateManagedWidget("pane", xmPanedWindowWidgetClass
, mainWin
,
653 XmNseparatorOn
, False
,
654 XmNspacing
, 3, XmNsashIndent
, -2, NULL
);
655 window
->splitPane
= pane
;
656 XmMainWindowSetAreas(mainWin
, menuBar
, statsAreaForm
, NULL
, NULL
, pane
);
658 /* buffer/window info should associate with text pane */
659 XtVaSetValues(pane
, XmNuserData
, window
, NULL
);
661 /* Patch around Motif's most idiotic "feature", that its menu accelerators
662 recognize Caps Lock and Num Lock as modifiers, and don't trigger if
664 AccelLockBugPatch(pane
, window
->menuBar
);
666 /* Create the first, and most permanent text area (other panes may
667 be added & removed, but this one will never be removed */
668 text
= createTextArea(pane
, window
, rows
,cols
,
669 GetPrefEmTabDist(PLAIN_LANGUAGE_MODE
), GetPrefDelimiters(),
670 GetPrefWrapMargin(), window
->showLineNumbers
?MIN_LINE_NUM_COLS
:0);
672 window
->textArea
= text
;
673 window
->lastFocus
= text
;
675 /* Set the initial colors from the globals. */
677 GetPrefColorName(TEXT_FG_COLOR
),
678 GetPrefColorName(TEXT_BG_COLOR
),
679 GetPrefColorName(SELECT_FG_COLOR
),
680 GetPrefColorName(SELECT_BG_COLOR
),
681 GetPrefColorName(HILITE_FG_COLOR
),
682 GetPrefColorName(HILITE_BG_COLOR
),
683 GetPrefColorName(LINENO_FG_COLOR
),
684 GetPrefColorName(CURSOR_FG_COLOR
));
686 /* Create the right button popup menu (note: order is important here,
687 since the translation for popping up this menu was probably already
688 added in createTextArea, but CreateBGMenu requires window->textArea
689 to be set so it can attach the menu to it (because menu shells are
690 finicky about the kinds of widgets they are attached to)) */
691 window
->bgMenuPane
= CreateBGMenu(window
);
693 /* Create the text buffer rather than using the one created automatically
694 with the text area widget. This is done so the syntax highlighting
695 modify callback can be called to synchronize the style buffer BEFORE
696 the text display's callback is called upon to display a modification */
697 window
->buffer
= BufCreate();
698 BufAddModifyCB(window
->buffer
, SyntaxHighlightModifyCB
, window
);
700 /* Attach the buffer to the text widget, and add callbacks for modify */
701 TextSetBuffer(text
, window
->buffer
);
702 BufAddModifyCB(window
->buffer
, modifiedCB
, window
);
704 /* Designate the permanent text area as the owner for selections */
705 HandleXSelections(text
);
707 /* Set the requested hardware tab distance and useTabs in the text buffer */
708 BufSetTabDistance(window
->buffer
, GetPrefTabDist(PLAIN_LANGUAGE_MODE
));
709 window
->buffer
->useTabs
= GetPrefInsertTabs();
711 /* add the window to the global window list, update the Windows menus */
712 addToWindowList(window
);
713 InvalidateWindowMenus();
715 /* realize all of the widgets in the new window */
716 RealizeWithoutForcingPosition(winShell
);
717 XmProcessTraversal(text
, XmTRAVERSE_CURRENT
);
719 /* Make close command in window menu gracefully prompt for close */
720 AddMotifCloseCallback(winShell
, (XtCallbackProc
)closeCB
, window
);
722 #ifndef NO_SESSION_RESTART
723 /* Add wm protocol callback for making nedit restartable by session
724 managers. Doesn't yet handle multiple-desktops or iconifying right. */
726 wmpAtom
= XmInternAtom(TheDisplay
, "WM_PROTOCOLS", FALSE
);
727 syAtom
= XmInternAtom(TheDisplay
, "WM_SAVE_YOURSELF", FALSE
);
729 XmAddProtocolCallback(winShell
, wmpAtom
, syAtom
,
730 (XtCallbackProc
)saveYourselfCB
, (XtPointer
)window
);
733 /* Make window resizing work in nice character heights */
734 UpdateWMSizeHints(window
);
736 /* Set the minimum pane height for the initial text pane */
737 UpdateMinPaneHeights(window
);
739 restoreInsaneVirtualKeyBindings(invalidBindings
);
741 /* create persistant dialog upfront, shared by all buffers
742 in a common shell window */
743 CreateFindDlog(window
->shell
, window
);
744 CreateReplaceDlog(window
->shell
, window
);
745 CreateReplaceMultiFileDlog(window
);
747 /* tell the world there's a new window to move in */
748 if (GetPrefBufferMode()) {
749 for(win
=WindowList
; win
; win
=win
->next
) {
750 if (IsTopBuffer(win
))
751 XtSetSensitive(win
->attachBufferItem
,
752 NBuffers(window
) < NWindows());
760 ** add a new tab to the tab bar, where the [new] buffer belongs.
762 static Widget
addBufferTab(Widget folder
, WindowInfo
*window
, const char *string
)
764 Widget tooltipLabel
, tab
;
767 s1
= XmStringCreateSimple((char *)string
);
768 tab
= XtVaCreateManagedWidget("tab",
769 xrwsBubbleButtonWidgetClass
, folder
,
772 XmNalignment
, XmALIGNMENT_BEGINNING
,
774 XltNbubbleString
, s1
,
775 XltNshowBubble
, GetPrefToolTips(),
776 XltNautoParkBubble
, True
,
777 XltNslidingBubble
, False
,
779 /* XltNbubbleDuration, 8000,*/
783 XtAddCallback(tab
, XmNactivateCallback
,
784 (XtCallbackProc
)clickTabCB
, NULL
);
786 /* BubbleButton simply use reversed video for tooltips,
787 we try to use the 'standard' color */
788 tooltipLabel
= XtNameToWidget(tab
, "*BubbleLabel");
789 XtVaSetValues(tooltipLabel
,
790 XmNbackground
, AllocateColor(tab
, GetPrefTooltipBgColor()),
791 XmNforeground
, AllocateColor(tab
, NEDIT_DEFAULT_FG
),
794 /* put borders around tooltip. BubbleButton use
795 transientShellWidgetClass as tooltip shell, which
796 came without borders */
797 XtVaSetValues(XtParent(tooltipLabel
), XmNborderWidth
, 1, NULL
);
803 ** return the tab next to the closing tab.
805 ** tab close left to right (Mozilla 1.1 behavior), i.e
806 ** the 'right-hand' tab get the new seat, unless the
807 ** closing buffer is the right-most tab
809 static WindowInfo
*replacementBuffer(WindowInfo
*window
)
811 int n
, tabPos
, nextPos
;
812 WindowInfo
**winList
, *win
;
813 int nBuf
= NBuffers(window
);
818 winList
= (WindowInfo
**)XtMalloc(sizeof(WindowInfo
*) * nBuf
);
820 for (win
=WindowList
; win
&& n
>=0; win
=win
->next
) {
821 if (win
->shell
== window
->shell
)
825 for (n
=0; n
<nBuf
; n
++) {
826 if (winList
[n
] == window
) {
832 nextPos
= tabPos
== nBuf
-1? tabPos
-1 : tabPos
+1;
833 win
= winList
[nextPos
];
834 XtFree((char*) winList
);
839 * find which buffer/window a tab belongs to
841 WindowInfo
*TabToWindow(Widget tab
)
844 for (win
=WindowList
; win
; win
=win
->next
) {
845 if (win
->bufferTab
== tab
)
853 ** Close an editor window
855 void CloseWindow(WindowInfo
*window
)
858 char name
[MAXPATHLEN
];
859 WindowInfo
*win
, *topBuf
= NULL
, *nextBuf
= NULL
;
861 /* turn off the tear-off menus for Shell & Macro to
862 minimized visual disturbance if these menus get
863 updated somehow, especial when CloseWindow() is
864 called from within macros. */
865 if (IsTopBuffer(window
)) {
866 if (!XmIsMenuShell(XtParent(window
->macroMenuPane
)))
867 XtPopdown(XtParent(window
->macroMenuPane
));
869 if (!XmIsMenuShell(XtParent(window
->shellMenuPane
)))
870 XtPopdown(XtParent(window
->shellMenuPane
));
873 /* Free smart indent macro programs */
874 EndSmartIndent(window
);
876 /* Clean up macro references to the doomed window. If a macro is
877 executing, stop it. If macro is calling this (closing its own
878 window), leave the window alive until the macro completes */
879 keepWindow
= !MacroWindowCloseActions(window
);
882 /* Kill shell sub-process and free related memory */
883 AbortShellCommand(window
);
886 /* Unload the default tips files for this language mode if necessary */
887 UnloadLanguageModeTipsFile(window
);
889 /* If a window is closed while it is on the multi-file replace dialog
890 list of any other window (or even the same one), we must update those
891 lists or we end up with dangling references. Normally, there can
892 be only one of those dialogs at the same time (application modal),
893 but LessTif doesn't even (always) honor application modalness, so
894 there can be more than one dialog. */
895 RemoveFromMultiReplaceDialog(window
);
897 /* Destroy the file closed property for this file */
898 DeleteFileClosedProperty(window
);
900 /* if this is the last window, or must be kept alive temporarily because
901 it's running the macro calling us, don't close it, make it Untitled */
902 if (keepWindow
|| (WindowList
== window
&& window
->next
== NULL
)) {
903 window
->filename
[0] = '\0';
904 UniqueUntitledName(name
);
905 CLEAR_ALL_LOCKS(window
->lockReasons
);
906 window
->fileMode
= 0;
907 strcpy(window
->filename
, name
);
908 strcpy(window
->path
, "");
909 window
->ignoreModify
= TRUE
;
910 BufSetAll(window
->buffer
, "");
911 window
->ignoreModify
= FALSE
;
913 window
->filenameSet
= FALSE
;
914 window
->fileMissing
= TRUE
;
915 window
->fileChanged
= FALSE
;
916 window
->fileFormat
= UNIX_FILE_FORMAT
;
917 window
->lastModTime
= 0;
918 StopHighlighting(window
);
919 EndSmartIndent(window
);
920 UpdateWindowTitle(window
);
921 UpdateWindowReadOnly(window
);
922 XtSetSensitive(window
->closeItem
, FALSE
);
923 XtSetSensitive(window
->readOnlyItem
, TRUE
);
924 XmToggleButtonSetState(window
->readOnlyItem
, FALSE
, FALSE
);
925 ClearUndoList(window
);
926 ClearRedoList(window
);
927 XmTextSetString(window
->statsLine
, ""); /* resets scroll pos of stats
928 line from long file names */
929 UpdateStatsLine(window
);
930 DetermineLanguageMode(window
, True
);
931 RefreshTabState(window
);
935 /* Free syntax highlighting patterns, if any. w/o redisplaying */
936 FreeHighlightingData(window
);
938 /* remove the buffer modification callbacks so the buffer will be
939 deallocated when the last text widget is destroyed */
940 BufRemoveModifyCB(window
->buffer
, modifiedCB
, window
);
941 BufRemoveModifyCB(window
->buffer
, SyntaxHighlightModifyCB
, window
);
944 patchRowCol(window
->menuBar
);
947 /* free the undo and redo lists */
948 ClearUndoList(window
);
949 ClearRedoList(window
);
951 /* close window, or buffer */
952 if (NBuffers(window
) > 1) {
953 if (MacroRunWindow() && MacroRunWindow() != window
&&
954 MacroRunWindow()->shell
== window
->shell
) {
955 nextBuf
= MacroRunWindow();
957 else if (IsTopBuffer(window
)) {
958 /* if this is the active buffer, then we need
959 to find its successor */
960 nextBuf
= replacementBuffer(window
);
963 topBuf
= GetTopBuffer(window
->shell
);
966 /* remove the window from the global window list, update window menus */
967 removeFromWindowList(window
);
968 InvalidateWindowMenus();
970 /* remove tab from tab bar */
971 XtDestroyWidget(window
->bufferTab
);
974 /* show the replacement buffer */
975 RaiseBuffer(nextBuf
);
976 ShowWindowTabBar(nextBuf
);
979 /* refresh tabbar after deleting a non-top buffer */
980 ShowWindowTabBar(topBuf
);
983 /* tell the world there's one less window to move in */
984 if (GetPrefBufferMode()) {
985 for(win
=WindowList
; win
; win
=win
->next
) {
986 if (IsTopBuffer(win
))
987 XtSetSensitive(win
->attachBufferItem
,
988 NBuffers(WindowList
) < NWindows());
992 /* destroy the buffer pane, or window */
993 if (nextBuf
|| topBuf
) {
994 DeleteBuffer(window
);
997 /* remove and deallocate all of the widgets associated with window */
998 XtFree(window
->backlightCharTypes
); /* we made a copy earlier on */
999 XtDestroyWidget(window
->shell
);
1002 /* deallocate the window data structure */
1003 XtFree((char *)window
);
1006 void ShowWindowTabBar(WindowInfo
*window
)
1008 if (GetPrefTabBar()) {
1009 if (GetPrefTabBarHideOne())
1010 ShowBufferTabBar(window
, NBuffers(window
)>1);
1012 ShowBufferTabBar(window
, True
);
1015 ShowBufferTabBar(window
, False
);
1019 ** Check if there is already a window open for a given file
1021 WindowInfo
*FindWindowWithFile(const char *name
, const char *path
)
1025 for (w
=WindowList
; w
!=NULL
; w
=w
->next
) {
1026 if (!strcmp(w
->filename
, name
) && !strcmp(w
->path
, path
)) {
1034 ** Add another independently scrollable window pane to the current window,
1035 ** splitting the pane which currently has keyboard focus.
1037 void SplitWindow(WindowInfo
*window
)
1039 short paneHeights
[MAX_PANES
+1];
1040 int insertPositions
[MAX_PANES
+1], topLines
[MAX_PANES
+1];
1041 int horizOffsets
[MAX_PANES
+1];
1042 int i
, focusPane
, emTabDist
, wrapMargin
, lineNumCols
, totalHeight
=0;
1045 textDisp
*textD
, *newTextD
;
1047 /* Don't create new panes if we're already at the limit */
1048 if (window
->nPanes
>= MAX_PANES
)
1051 /* Record the current heights, scroll positions, and insert positions
1052 of the existing panes, keyboard focus */
1054 for (i
=0; i
<=window
->nPanes
; i
++) {
1055 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1056 insertPositions
[i
] = TextGetCursorPos(text
);
1057 XtVaGetValues(containingPane(text
),XmNheight
,&paneHeights
[i
],NULL
);
1058 totalHeight
+= paneHeights
[i
];
1059 TextGetScroll(text
, &topLines
[i
], &horizOffsets
[i
]);
1060 if (text
== window
->lastFocus
)
1064 /* Unmanage & remanage the panedWindow so it recalculates pane heights */
1065 XtUnmanageChild(window
->splitPane
);
1067 /* Create a text widget to add to the pane and set its buffer and
1068 highlight data to be the same as the other panes in the window */
1069 XtVaGetValues(window
->textArea
, textNemulateTabs
, &emTabDist
,
1070 textNwordDelimiters
, &delimiters
, textNwrapMargin
, &wrapMargin
,
1071 textNlineNumCols
, &lineNumCols
, NULL
);
1072 text
= createTextArea(window
->splitPane
, window
, 1, 1, emTabDist
,
1073 delimiters
, wrapMargin
, lineNumCols
);
1074 TextSetBuffer(text
, window
->buffer
);
1075 if (window
->highlightData
!= NULL
)
1076 AttachHighlightToWidget(text
, window
);
1077 if (window
->backlightChars
)
1079 XtVaSetValues(text
, textNbacklightCharTypes
,
1080 window
->backlightCharTypes
, 0);
1082 XtManageChild(text
);
1083 window
->textPanes
[window
->nPanes
++] = text
;
1085 /* Fix up the colors */
1086 textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
1087 newTextD
= ((TextWidget
)text
)->text
.textD
;
1089 XmNforeground
, textD
->fgPixel
,
1090 XmNbackground
, textD
->bgPixel
,
1092 TextDSetColors( newTextD
, textD
->fgPixel
, textD
->bgPixel
,
1093 textD
->selectFGPixel
, textD
->selectBGPixel
, textD
->highlightFGPixel
,
1094 textD
->highlightBGPixel
, textD
->lineNumFGPixel
,
1095 textD
->cursorFGPixel
);
1097 /* Set the minimum pane height in the new pane */
1098 UpdateMinPaneHeights(window
);
1100 /* adjust the heights, scroll positions, etc., to split the focus pane */
1101 for (i
=window
->nPanes
; i
>focusPane
; i
--) {
1102 insertPositions
[i
] = insertPositions
[i
-1];
1103 paneHeights
[i
] = paneHeights
[i
-1];
1104 topLines
[i
] = topLines
[i
-1];
1105 horizOffsets
[i
] = horizOffsets
[i
-1];
1107 paneHeights
[focusPane
] = paneHeights
[focusPane
]/2;
1108 paneHeights
[focusPane
+1] = paneHeights
[focusPane
];
1110 for (i
=0; i
<=window
->nPanes
; i
++) {
1111 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1112 setPaneDesiredHeight(containingPane(text
), paneHeights
[i
]);
1115 /* Re-manage panedWindow to recalculate pane heights & reset selection */
1116 if (IsTopBuffer(window
))
1117 XtManageChild(window
->splitPane
);
1119 /* Reset all of the heights, scroll positions, etc. */
1120 for (i
=0; i
<=window
->nPanes
; i
++) {
1121 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1122 TextSetCursorPos(text
, insertPositions
[i
]);
1123 TextSetScroll(text
, topLines
[i
], horizOffsets
[i
]);
1124 setPaneDesiredHeight(containingPane(text
),
1125 totalHeight
/(window
->nPanes
+1));
1127 XmProcessTraversal(window
->lastFocus
, XmTRAVERSE_CURRENT
);
1129 /* Update the window manager size hints after the sizes of the panes have
1130 been set (the widget heights are not yet readable here, but they will
1131 be by the time the event loop gets around to running this timer proc) */
1132 XtAppAddTimeOut(XtWidgetToApplicationContext(window
->shell
), 0,
1133 wmSizeUpdateProc
, window
);
1136 Widget
GetPaneByIndex(WindowInfo
*window
, int paneIndex
)
1139 if (paneIndex
>= 0 && paneIndex
<= window
->nPanes
) {
1140 text
= (paneIndex
== 0) ? window
->textArea
: window
->textPanes
[paneIndex
- 1];
1145 int WidgetToPaneIndex(WindowInfo
*window
, Widget w
)
1151 for (i
= 0; i
<= window
->nPanes
; ++i
) {
1152 text
= (i
== 0) ? window
->textArea
: window
->textPanes
[i
- 1];
1161 ** Close the window pane that last had the keyboard focus. (Actually, close
1162 ** the bottom pane and make it look like pane which had focus was closed)
1164 void ClosePane(WindowInfo
*window
)
1166 short paneHeights
[MAX_PANES
+1];
1167 int insertPositions
[MAX_PANES
+1], topLines
[MAX_PANES
+1];
1168 int horizOffsets
[MAX_PANES
+1];
1169 int i
, focusPane
,totalHeight
=0;
1172 /* Don't delete the last pane */
1173 if (window
->nPanes
<= 0)
1176 /* Record the current heights, scroll positions, and insert positions
1177 of the existing panes, and the keyboard focus */
1179 for (i
=0; i
<=window
->nPanes
; i
++) {
1180 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1181 insertPositions
[i
] = TextGetCursorPos(text
);
1182 XtVaGetValues(containingPane(text
),
1183 XmNheight
, &paneHeights
[i
], NULL
);
1184 totalHeight
+= paneHeights
[i
];
1185 TextGetScroll(text
, &topLines
[i
], &horizOffsets
[i
]);
1186 if (text
== window
->lastFocus
)
1190 /* Unmanage & remanage the panedWindow so it recalculates pane heights */
1191 XtUnmanageChild(window
->splitPane
);
1193 /* Destroy last pane, and make sure lastFocus points to an existing pane.
1194 Workaround for OM 2.1.30: text widget must be unmanaged for
1195 xmPanedWindowWidget to calculate the correct pane heights for
1196 the remaining panes, simply detroying it didn't seem enough */
1198 XtUnmanageChild(containingPane(window
->textPanes
[window
->nPanes
]));
1199 XtDestroyWidget(containingPane(window
->textPanes
[window
->nPanes
]));
1201 if (window
->nPanes
== 0)
1202 window
->lastFocus
= window
->textArea
;
1203 else if (focusPane
> window
->nPanes
)
1204 window
->lastFocus
= window
->textPanes
[window
->nPanes
-1];
1206 /* adjust the heights, scroll positions, etc., to make it look
1207 like the pane with the input focus was closed */
1208 for (i
=focusPane
; i
<=window
->nPanes
; i
++) {
1209 insertPositions
[i
] = insertPositions
[i
+1];
1210 paneHeights
[i
] = paneHeights
[i
+1];
1211 topLines
[i
] = topLines
[i
+1];
1212 horizOffsets
[i
] = horizOffsets
[i
+1];
1215 /* set the desired heights and re-manage the paned window so it will
1216 recalculate pane heights */
1217 for (i
=0; i
<=window
->nPanes
; i
++) {
1218 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1219 setPaneDesiredHeight(containingPane(text
), paneHeights
[i
]);
1222 if (IsTopBuffer(window
))
1223 XtManageChild(window
->splitPane
);
1225 /* Reset all of the scroll positions, insert positions, etc. */
1226 for (i
=0; i
<=window
->nPanes
; i
++) {
1227 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1228 TextSetCursorPos(text
, insertPositions
[i
]);
1229 TextSetScroll(text
, topLines
[i
], horizOffsets
[i
]);
1231 XmProcessTraversal(window
->lastFocus
, XmTRAVERSE_CURRENT
);
1233 /* Update the window manager size hints after the sizes of the panes have
1234 been set (the widget heights are not yet readable here, but they will
1235 be by the time the event loop gets around to running this timer proc) */
1236 XtAppAddTimeOut(XtWidgetToApplicationContext(window
->shell
), 0,
1237 wmSizeUpdateProc
, window
);
1241 ** Turn on and off the display of line numbers
1243 void ShowLineNumbers(WindowInfo
*window
, int state
)
1247 Dimension windowWidth
;
1248 textDisp
*textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
1250 if (window
->showLineNumbers
== state
)
1252 window
->showLineNumbers
= state
;
1254 /* Just setting window->showLineNumbers is sufficient to tell
1255 UpdateLineNumDisp to expand the line number areas and the window
1256 size for the number of lines required. To hide the line number
1257 display, set the width to zero, and contract the window width. */
1259 UpdateLineNumDisp(window
);
1261 XtVaGetValues(window
->shell
, XmNwidth
, &windowWidth
, NULL
);
1262 XtVaGetValues(window
->textArea
, textNmarginWidth
, &marginWidth
, NULL
);
1263 XtVaSetValues(window
->shell
, XmNwidth
,
1264 windowWidth
- textD
->left
+ marginWidth
, NULL
);
1265 for (i
=0; i
<=window
->nPanes
; i
++) {
1266 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1267 XtVaSetValues(text
, textNlineNumCols
, 0, NULL
);
1271 /* Tell WM that the non-expandable part of the window has changed size */
1272 UpdateWMSizeHints(window
);
1275 void SetTabDist(WindowInfo
*window
, int tabDist
)
1277 if (window
->buffer
->tabDist
!= tabDist
) {
1278 int saveCursorPositions
[MAX_PANES
+ 1];
1279 int saveVScrollPositions
[MAX_PANES
+ 1];
1280 int saveHScrollPositions
[MAX_PANES
+ 1];
1283 window
->ignoreModify
= True
;
1285 for (paneIndex
= 0; paneIndex
<= window
->nPanes
; ++paneIndex
) {
1286 Widget w
= GetPaneByIndex(window
, paneIndex
);
1287 textDisp
*textD
= ((TextWidget
)w
)->text
.textD
;
1289 TextGetScroll(w
, &saveVScrollPositions
[paneIndex
], &saveHScrollPositions
[paneIndex
]);
1290 saveCursorPositions
[paneIndex
] = TextGetCursorPos(w
);
1291 textD
->modifyingTabDist
= 1;
1294 BufSetTabDistance(window
->buffer
, tabDist
);
1296 for (paneIndex
= 0; paneIndex
<= window
->nPanes
; ++paneIndex
) {
1297 Widget w
= GetPaneByIndex(window
, paneIndex
);
1298 textDisp
*textD
= ((TextWidget
)w
)->text
.textD
;
1300 textD
->modifyingTabDist
= 0;
1301 TextSetCursorPos(w
, saveCursorPositions
[paneIndex
]);
1302 TextSetScroll(w
, saveVScrollPositions
[paneIndex
], saveHScrollPositions
[paneIndex
]);
1305 window
->ignoreModify
= False
;
1309 void SetEmTabDist(WindowInfo
*window
, int emTabDist
)
1313 XtVaSetValues(window
->textArea
, textNemulateTabs
, emTabDist
, NULL
);
1314 for (i
= 0; i
< window
->nPanes
; ++i
) {
1315 XtVaSetValues(window
->textPanes
[i
], textNemulateTabs
, emTabDist
, NULL
);
1320 ** Turn on and off the display of the statistics line
1322 void ShowStatsLine(WindowInfo
*window
, int state
)
1327 /* In continuous wrap mode, text widgets must be told to keep track of
1328 the top line number in absolute (non-wrapped) lines, because it can
1329 be a costly calculation, and is only needed for displaying line
1330 numbers, either in the stats line, or along the left margin */
1331 for (i
=0; i
<=window
->nPanes
; i
++) {
1332 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
1333 TextDMaintainAbsLineNum(((TextWidget
)text
)->text
.textD
, state
);
1335 window
->showStats
= state
;
1336 showStats(window
, state
);
1340 ** Displays and undisplays the statistics line (regardless of settings of
1341 ** window->showStats or window->modeMessageDisplayed)
1343 static void showStats(WindowInfo
*window
, int state
)
1346 XtManageChild(window
->statsLineForm
);
1347 showStatsForm(window
, True
);
1349 XtUnmanageChild(window
->statsLineForm
);
1350 showStatsForm(window
, window
->showISearchLine
);
1353 /* Tell WM that the non-expandable part of the window has changed size */
1354 /* Already done in showStatsForm */
1355 /* UpdateWMSizeHints(window); */
1360 static void showTabBar(WindowInfo
*window
, int state
)
1363 XtManageChild(XtParent(window
->bufferTabBar
));
1364 showStatsForm(window
, True
);
1366 XtUnmanageChild(XtParent(window
->bufferTabBar
));
1367 showStatsForm(window
, False
);
1373 void ShowBufferTabBar(WindowInfo
*window
, int state
)
1375 if (XtIsManaged(XtParent(window
->bufferTabBar
)) == state
)
1377 window
->showTabBar
= state
;
1378 showTabBar(window
, state
);
1382 ** Turn on and off the continuing display of the incremental search line
1383 ** (when off, it is popped up and down as needed via TempShowISearch)
1385 void ShowISearchLine(WindowInfo
*window
, int state
)
1387 if (window
->showISearchLine
== state
)
1389 window
->showISearchLine
= state
;
1390 showISearch(window
, state
);
1394 ** Temporarily show and hide the incremental search line if the line is not
1397 void TempShowISearch(WindowInfo
*window
, int state
)
1399 if (window
->showISearchLine
)
1401 if (XtIsManaged(window
->iSearchForm
) != state
)
1402 showISearch(window
, state
);
1406 ** Put up or pop-down the incremental search line regardless of settings
1407 ** of showISearchLine or TempShowISearch
1409 static void showISearch(WindowInfo
*window
, int state
)
1412 XtManageChild(window
->iSearchForm
);
1413 showStatsForm(window
, True
);
1415 XtUnmanageChild(window
->iSearchForm
);
1416 showStatsForm(window
, window
->showStats
||
1417 window
->modeMessageDisplayed
);
1420 /* Tell WM that the non-expandable part of the window has changed size */
1421 /* This is already done in showStatsForm */
1422 /* UpdateWMSizeHints(window); */
1426 ** Show or hide the extra display area under the main menu bar which
1427 ** optionally contains the status line and the incremental search bar
1429 static void showStatsForm(WindowInfo
*window
, int state
)
1431 Widget statsAreaForm
= XtParent(window
->statsLineForm
);
1432 Widget mainW
= XtParent(statsAreaForm
);
1434 /* The very silly use of XmNcommandWindowLocation and XmNshowSeparator
1435 below are to kick the main window widget to position and remove the
1436 status line when it is managed and unmanaged. At some Motif version
1437 level, the showSeparator trick backfires and leaves the separator
1438 shown, but fortunately the dynamic behavior is fixed, too so the
1439 workaround is no longer necessary, either. (... the version where
1440 this occurs may be earlier than 2.1. If the stats line shows
1441 double thickness shadows in earlier Motif versions, the #if XmVersion
1442 directive should be moved back to that earlier version) */
1443 if (manageToolBars(statsAreaForm
)) {
1444 XtUnmanageChild(statsAreaForm
); /*... will this fix Solaris 7??? */
1445 XtVaSetValues(mainW
, XmNcommandWindowLocation
,
1446 XmCOMMAND_ABOVE_WORKSPACE
, NULL
);
1447 #if XmVersion < 2001
1448 XtVaSetValues(mainW
, XmNshowSeparator
, True
, NULL
);
1450 XtManageChild(statsAreaForm
);
1451 XtVaSetValues(mainW
, XmNshowSeparator
, False
, NULL
);
1452 UpdateStatsLine(window
);
1454 XtUnmanageChild(statsAreaForm
);
1455 XtVaSetValues(mainW
, XmNcommandWindowLocation
,
1456 XmCOMMAND_BELOW_WORKSPACE
, NULL
);
1459 /* Tell WM that the non-expandable part of the window has changed size */
1460 UpdateWMSizeHints(window
);
1464 ** Display a special message in the stats line (show the stats line if it
1465 ** is not currently shown).
1467 void SetModeMessage(WindowInfo
*window
, const char *message
)
1469 if (!IsTopBuffer(window
))
1472 window
->modeMessageDisplayed
= True
;
1473 XmTextSetString(window
->statsLine
, (char*)message
);
1475 * Don't invoke the stats line again, if stats line is already displayed.
1477 if (!window
->showStats
)
1478 showStats(window
, True
);
1482 ** Clear special statistics line message set in SetModeMessage, returns
1483 ** the statistics line to its original state as set in window->showStats
1485 void ClearModeMessage(WindowInfo
*window
)
1487 if (!IsTopBuffer(window
))
1490 window
->modeMessageDisplayed
= False
;
1492 * Remove the stats line only if indicated by it's window state.
1494 if (!window
->showStats
)
1495 showStats(window
, False
);
1496 UpdateStatsLine(window
);
1500 ** Count the windows
1507 for (win
=WindowList
, n
=0; win
!=NULL
; win
=win
->next
, n
++);
1512 ** Set autoindent state to one of NO_AUTO_INDENT, AUTO_INDENT, or SMART_INDENT.
1514 void SetAutoIndent(WindowInfo
*window
, int state
)
1516 int autoIndent
= state
== AUTO_INDENT
, smartIndent
= state
== SMART_INDENT
;
1519 if (window
->indentStyle
== SMART_INDENT
&& !smartIndent
)
1520 EndSmartIndent(window
);
1521 else if (smartIndent
&& window
->indentStyle
!= SMART_INDENT
)
1522 BeginSmartIndent(window
, True
);
1523 window
->indentStyle
= state
;
1524 XtVaSetValues(window
->textArea
, textNautoIndent
, autoIndent
,
1525 textNsmartIndent
, smartIndent
, NULL
);
1526 for (i
=0; i
<window
->nPanes
; i
++)
1527 XtVaSetValues(window
->textPanes
[i
], textNautoIndent
, autoIndent
,
1528 textNsmartIndent
, smartIndent
, NULL
);
1529 XmToggleButtonSetState(window
->smartIndentItem
, smartIndent
, False
);
1530 XmToggleButtonSetState(window
->autoIndentItem
, autoIndent
, False
);
1531 XmToggleButtonSetState(window
->autoIndentOffItem
, state
== NO_AUTO_INDENT
,
1536 ** Set showMatching state to one of NO_FLASH, FLASH_DELIMIT or FLASH_RANGE.
1537 ** Update the menu to reflect the change of state.
1539 void SetShowMatching(WindowInfo
*window
, int state
)
1541 window
->showMatchingStyle
= state
;
1542 XmToggleButtonSetState(window
->showMatchingOffItem
,
1543 state
== NO_FLASH
, False
);
1544 XmToggleButtonSetState(window
->showMatchingDelimitItem
,
1545 state
== FLASH_DELIMIT
, False
);
1546 XmToggleButtonSetState(window
->showMatchingRangeItem
,
1547 state
== FLASH_RANGE
, False
);
1551 ** Set the fonts for "window" from a font name, and updates the display.
1552 ** Also updates window->fontList which is used for statistics line.
1554 ** Note that this leaks memory and server resources. In previous NEdit
1555 ** versions, fontLists were carefully tracked and freed, but X and Motif
1556 ** have some kind of timing problem when widgets are distroyed, such that
1557 ** fonts may not be freed immediately after widget destruction with 100%
1558 ** safety. Rather than kludge around this with timerProcs, I have chosen
1559 ** to create new fontLists only when the user explicitly changes the font
1560 ** (which shouldn't happen much in normal NEdit operation), and skip the
1561 ** futile effort of freeing them.
1563 void SetFonts(WindowInfo
*window
, const char *fontName
, const char *italicName
,
1564 const char *boldName
, const char *boldItalicName
)
1566 XFontStruct
*font
, *oldFont
;
1567 int i
, oldFontWidth
, oldFontHeight
, fontWidth
, fontHeight
;
1568 int borderWidth
, borderHeight
, marginWidth
, marginHeight
;
1569 int primaryChanged
, highlightChanged
= False
;
1570 Dimension oldWindowWidth
, oldWindowHeight
, oldTextWidth
, oldTextHeight
;
1571 Dimension textHeight
, newWindowWidth
, newWindowHeight
;
1572 textDisp
*textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
1574 /* Check which fonts have changed */
1575 primaryChanged
= strcmp(fontName
, window
->fontName
);
1576 if (strcmp(italicName
, window
->italicFontName
)) highlightChanged
= True
;
1577 if (strcmp(boldName
, window
->boldFontName
)) highlightChanged
= True
;
1578 if (strcmp(boldItalicName
, window
->boldItalicFontName
))
1579 highlightChanged
= True
;
1580 if (!primaryChanged
&& !highlightChanged
)
1583 /* Get information about the current window sizing, to be used to
1584 determine the correct window size after the font is changed */
1585 XtVaGetValues(window
->shell
, XmNwidth
, &oldWindowWidth
, XmNheight
,
1586 &oldWindowHeight
, NULL
);
1587 XtVaGetValues(window
->textArea
, XmNheight
, &textHeight
,
1588 textNmarginHeight
, &marginHeight
, textNmarginWidth
,
1589 &marginWidth
, textNfont
, &oldFont
, NULL
);
1590 oldTextWidth
= textD
->width
+ textD
->lineNumWidth
;
1591 oldTextHeight
= textHeight
- 2*marginHeight
;
1592 for (i
=0; i
<window
->nPanes
; i
++) {
1593 XtVaGetValues(window
->textPanes
[i
], XmNheight
, &textHeight
, NULL
);
1594 oldTextHeight
+= textHeight
- 2*marginHeight
;
1596 borderWidth
= oldWindowWidth
- oldTextWidth
;
1597 borderHeight
= oldWindowHeight
- oldTextHeight
;
1598 oldFontWidth
= oldFont
->max_bounds
.width
;
1599 oldFontHeight
= textD
->ascent
+ textD
->descent
;
1602 /* Change the fonts in the window data structure. If the primary font
1603 didn't work, use Motif's fallback mechanism by stealing it from the
1604 statistics line. Highlight fonts are allowed to be NULL, which
1605 is interpreted as "use the primary font" */
1606 if (primaryChanged
) {
1607 strcpy(window
->fontName
, fontName
);
1608 font
= XLoadQueryFont(TheDisplay
, fontName
);
1610 XtVaGetValues(window
->statsLine
, XmNfontList
, &window
->fontList
,
1613 window
->fontList
= XmFontListCreate(font
, XmSTRING_DEFAULT_CHARSET
);
1615 if (highlightChanged
) {
1616 strcpy(window
->italicFontName
, italicName
);
1617 window
->italicFontStruct
= XLoadQueryFont(TheDisplay
, italicName
);
1618 strcpy(window
->boldFontName
, boldName
);
1619 window
->boldFontStruct
= XLoadQueryFont(TheDisplay
, boldName
);
1620 strcpy(window
->boldItalicFontName
, boldItalicName
);
1621 window
->boldItalicFontStruct
= XLoadQueryFont(TheDisplay
, boldItalicName
);
1624 /* Change the primary font in all the widgets */
1625 if (primaryChanged
) {
1626 font
= GetDefaultFontStruct(window
->fontList
);
1627 XtVaSetValues(window
->textArea
, textNfont
, font
, NULL
);
1628 for (i
=0; i
<window
->nPanes
; i
++)
1629 XtVaSetValues(window
->textPanes
[i
], textNfont
, font
, NULL
);
1632 /* Change the highlight fonts, even if they didn't change, because
1633 primary font is read through the style table for syntax highlighting */
1634 if (window
->highlightData
!= NULL
)
1635 UpdateHighlightStyles(window
);
1637 /* Change the window manager size hints.
1638 Note: this has to be done _before_ we set the new sizes. ICCCM2
1639 compliant window managers (such as fvwm2) would otherwise resize
1640 the window twice: once because of the new sizes requested, and once
1641 because of the new size increments, resulting in an overshoot. */
1642 UpdateWMSizeHints(window
);
1644 /* Use the information from the old window to re-size the window to a
1645 size appropriate for the new font */
1646 fontWidth
= GetDefaultFontStruct(window
->fontList
)->max_bounds
.width
;
1647 fontHeight
= textD
->ascent
+ textD
->descent
;
1648 newWindowWidth
= (oldTextWidth
*fontWidth
) / oldFontWidth
+ borderWidth
;
1649 newWindowHeight
= (oldTextHeight
*fontHeight
) / oldFontHeight
+ borderHeight
;
1650 XtVaSetValues(window
->shell
, XmNwidth
, newWindowWidth
, XmNheight
,
1651 newWindowHeight
, NULL
);
1653 /* Change the minimum pane height */
1654 UpdateMinPaneHeights(window
);
1657 void SetColors(WindowInfo
*window
, const char *textFg
, const char *textBg
,
1658 const char *selectFg
, const char *selectBg
, const char *hiliteFg
,
1659 const char *hiliteBg
, const char *lineNoFg
, const char *cursorFg
)
1662 Pixel textFgPix
= AllocColor( window
->textArea
, textFg
,
1663 &dummy
, &dummy
, &dummy
),
1664 textBgPix
= AllocColor( window
->textArea
, textBg
,
1665 &dummy
, &dummy
, &dummy
),
1666 selectFgPix
= AllocColor( window
->textArea
, selectFg
,
1667 &dummy
, &dummy
, &dummy
),
1668 selectBgPix
= AllocColor( window
->textArea
, selectBg
,
1669 &dummy
, &dummy
, &dummy
),
1670 hiliteFgPix
= AllocColor( window
->textArea
, hiliteFg
,
1671 &dummy
, &dummy
, &dummy
),
1672 hiliteBgPix
= AllocColor( window
->textArea
, hiliteBg
,
1673 &dummy
, &dummy
, &dummy
),
1674 lineNoFgPix
= AllocColor( window
->textArea
, lineNoFg
,
1675 &dummy
, &dummy
, &dummy
),
1676 cursorFgPix
= AllocColor( window
->textArea
, cursorFg
,
1677 &dummy
, &dummy
, &dummy
);
1680 /* Update the main pane */
1681 XtVaSetValues(window
->textArea
,
1682 XmNforeground
, textFgPix
,
1683 XmNbackground
, textBgPix
,
1685 textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
1686 TextDSetColors( textD
, textFgPix
, textBgPix
, selectFgPix
, selectBgPix
,
1687 hiliteFgPix
, hiliteBgPix
, lineNoFgPix
, cursorFgPix
);
1688 /* Update any additional panes */
1689 for (i
=0; i
<window
->nPanes
; i
++) {
1690 XtVaSetValues(window
->textPanes
[i
],
1691 XmNforeground
, textFgPix
,
1692 XmNbackground
, textBgPix
,
1694 textD
= ((TextWidget
)window
->textPanes
[i
])->text
.textD
;
1695 TextDSetColors( textD
, textFgPix
, textBgPix
, selectFgPix
, selectBgPix
,
1696 hiliteFgPix
, hiliteBgPix
, lineNoFgPix
, cursorFgPix
);
1699 /* Redo any syntax highlighting */
1700 if (window
->highlightData
!= NULL
)
1701 UpdateHighlightStyles(window
);
1705 ** Set insert/overstrike mode
1707 void SetOverstrike(WindowInfo
*window
, int overstrike
)
1711 XtVaSetValues(window
->textArea
, textNoverstrike
, overstrike
, NULL
);
1712 for (i
=0; i
<window
->nPanes
; i
++)
1713 XtVaSetValues(window
->textPanes
[i
], textNoverstrike
, overstrike
, NULL
);
1714 window
->overstrike
= overstrike
;
1718 ** Select auto-wrap mode, one of NO_WRAP, NEWLINE_WRAP, or CONTINUOUS_WRAP
1720 void SetAutoWrap(WindowInfo
*window
, int state
)
1723 int autoWrap
= state
== NEWLINE_WRAP
, contWrap
= state
== CONTINUOUS_WRAP
;
1725 XtVaSetValues(window
->textArea
, textNautoWrap
, autoWrap
,
1726 textNcontinuousWrap
, contWrap
, NULL
);
1727 for (i
=0; i
<window
->nPanes
; i
++)
1728 XtVaSetValues(window
->textPanes
[i
], textNautoWrap
, autoWrap
,
1729 textNcontinuousWrap
, contWrap
, NULL
);
1730 window
->wrapMode
= state
;
1732 XmToggleButtonSetState(window
->newlineWrapItem
, autoWrap
, False
);
1733 XmToggleButtonSetState(window
->continuousWrapItem
, contWrap
, False
);
1734 XmToggleButtonSetState(window
->noWrapItem
, state
== NO_WRAP
, False
);
1738 ** Set the wrap margin (0 == wrap at right edge of window)
1740 void SetWrapMargin(WindowInfo
*window
, int margin
)
1744 XtVaSetValues(window
->textArea
, textNwrapMargin
, margin
, NULL
);
1745 for (i
=0; i
<window
->nPanes
; i
++)
1746 XtVaSetValues(window
->textPanes
[i
], textNwrapMargin
, margin
, NULL
);
1750 ** Recover the window pointer from any widget in the window, by searching
1751 ** up the widget hierarcy for the top level container widget where the window
1752 ** pointer is stored in the userData field. In buffer mode, this is the window
1753 ** pointer of the top (active) buffer, which is returned if w is 'shell-level'
1754 ** widget - menus, find/replace dialogs, etc.
1756 ** To support action routine in buffer mode, a copy of the window pointer
1757 ** is also store in the splitPane widget.
1759 WindowInfo
*WidgetToWindow(Widget w
)
1761 WindowInfo
*window
= NULL
;
1765 /* return window pointer of buffer */
1766 if (XtClass(w
) == xmPanedWindowWidgetClass
)
1769 if (XtClass(w
) == topLevelShellWidgetClass
) {
1772 /* there should be only 1 child for the shell -
1773 the main window widget */
1774 XtVaGetValues(w
, XmNchildren
, &items
, NULL
);
1779 parent
= XtParent(w
);
1783 /* make sure it is not a dialog shell */
1784 if (XtClass(parent
) == topLevelShellWidgetClass
&&
1791 XtVaGetValues(w
, XmNuserData
, &window
, NULL
);
1797 ** Change the window appearance and the window data structure to show
1798 ** that the file it contains has been modified
1800 void SetWindowModified(WindowInfo
*window
, int modified
)
1802 if (window
->fileChanged
== FALSE
&& modified
== TRUE
) {
1803 XtSetSensitive(window
->closeItem
, TRUE
);
1804 window
->fileChanged
= TRUE
;
1805 UpdateWindowTitle(window
);
1806 RefreshTabState(window
);
1807 } else if (window
->fileChanged
== TRUE
&& modified
== FALSE
) {
1808 window
->fileChanged
= FALSE
;
1809 UpdateWindowTitle(window
);
1810 RefreshTabState(window
);
1815 ** Update the window title to reflect the filename, read-only, and modified
1816 ** status of the window data structure
1818 void UpdateWindowTitle(const WindowInfo
*window
)
1820 char *iconTitle
, *title
;
1822 if (!IsTopBuffer((WindowInfo
*)window
))
1825 title
= FormatWindowTitle(window
->filename
,
1830 GetClearCaseViewTag(),
1832 GetPrefServerName(),
1834 window
->filenameSet
,
1835 window
->lockReasons
,
1836 window
->fileChanged
,
1837 GetPrefTitleFormat());
1839 iconTitle
= XtMalloc(strlen(window
->filename
) + 2); /* strlen("*")+1 */
1841 strcpy(iconTitle
, window
->filename
);
1842 if (window
->fileChanged
)
1843 strcat(iconTitle
, "*");
1844 XtVaSetValues(window
->shell
, XmNtitle
, title
, XmNiconName
, iconTitle
, NULL
);
1846 /* If there's a find or replace dialog up in "Keep Up" mode, with a
1847 file name in the title, update it too */
1848 if (window
->findDlog
&& XmToggleButtonGetState(window
->findKeepBtn
)) {
1849 sprintf(title
, "Find (in %s)", window
->filename
);
1850 XtVaSetValues(XtParent(window
->findDlog
), XmNtitle
, title
, NULL
);
1852 if (window
->replaceDlog
&& XmToggleButtonGetState(window
->replaceKeepBtn
)) {
1853 sprintf(title
, "Replace (in %s)", window
->filename
);
1854 XtVaSetValues(XtParent(window
->replaceDlog
), XmNtitle
, title
, NULL
);
1858 /* Update the Windows menus with the new name */
1859 InvalidateWindowMenus();
1863 ** Update the read-only state of the text area(s) in the window, and
1864 ** the ReadOnly toggle button in the File menu to agree with the state in
1865 ** the window data structure.
1867 void UpdateWindowReadOnly(WindowInfo
*window
)
1871 if (!IsTopBuffer(window
))
1874 state
= IS_ANY_LOCKED(window
->lockReasons
);
1875 XtVaSetValues(window
->textArea
, textNreadOnly
, state
, NULL
);
1876 for (i
=0; i
<window
->nPanes
; i
++)
1877 XtVaSetValues(window
->textPanes
[i
], textNreadOnly
, state
, NULL
);
1878 XmToggleButtonSetState(window
->readOnlyItem
, state
, FALSE
);
1879 XtSetSensitive(window
->readOnlyItem
,
1880 !IS_ANY_LOCKED_IGNORING_USER(window
->lockReasons
));
1884 ** Get the start and end of the current selection. This routine is obsolete
1885 ** because it ignores rectangular selections, and reads from the widget
1886 ** instead of the buffer. Use BufGetSelectionPos.
1888 int GetSelection(Widget widget
, int *left
, int *right
)
1890 return GetSimpleSelection(TextGetBuffer(widget
), left
, right
);
1894 ** Find the start and end of a single line selection. Hides rectangular
1895 ** selection issues for older routines which use selections that won't
1898 int GetSimpleSelection(textBuffer
*buf
, int *left
, int *right
)
1900 int selStart
, selEnd
, isRect
, rectStart
, rectEnd
, lineStart
;
1902 /* get the character to match and its position from the selection, or
1903 the character before the insert point if nothing is selected.
1904 Give up if too many characters are selected */
1905 if (!BufGetSelectionPos(buf
, &selStart
, &selEnd
, &isRect
,
1906 &rectStart
, &rectEnd
))
1909 lineStart
= BufStartOfLine(buf
, selStart
);
1910 selStart
= BufCountForwardDispChars(buf
, lineStart
, rectStart
);
1911 selEnd
= BufCountForwardDispChars(buf
, lineStart
, rectEnd
);
1919 ** Returns a range of text from a text widget (this routine is obsolete,
1920 ** get text from the buffer instead). Memory is allocated with
1921 ** XtMalloc and caller should free it.
1923 char *GetTextRange(Widget widget
, int left
, int right
)
1925 return BufGetRange(TextGetBuffer(widget
), left
, right
);
1929 ** If the selection (or cursor position if there's no selection) is not
1930 ** fully shown, scroll to bring it in to view. Note that as written,
1931 ** this won't work well with multi-line selections. Modest re-write
1932 ** of the horizontal scrolling part would be quite easy to make it work
1933 ** well with rectangular selections.
1935 void MakeSelectionVisible(WindowInfo
*window
, Widget textPane
)
1937 int left
, right
, isRect
, rectStart
, rectEnd
, horizOffset
;
1938 int scrollOffset
, leftX
, rightX
, y
, rows
, margin
;
1939 int topLineNum
, lastLineNum
, rightLineNum
, leftLineNum
, linesToScroll
;
1940 textDisp
*textD
= ((TextWidget
)textPane
)->text
.textD
;
1941 int topChar
= TextFirstVisiblePos(textPane
);
1942 int lastChar
= TextLastVisiblePos(textPane
);
1946 /* find out where the selection is */
1947 if (!BufGetSelectionPos(window
->buffer
, &left
, &right
, &isRect
,
1948 &rectStart
, &rectEnd
)) {
1949 left
= right
= TextGetCursorPos(textPane
);
1953 /* Check vertical positioning unless the selection is already shown or
1954 already covers the display. If the end of the selection is below
1955 bottom, scroll it in to view until the end selection is scrollOffset
1956 lines from the bottom of the display or the start of the selection
1957 scrollOffset lines from the top. Calculate a pleasing distance from the
1958 top or bottom of the window, to scroll the selection to (if scrolling is
1959 necessary), around 1/3 of the height of the window */
1960 if (!((left
>= topChar
&& right
<= lastChar
) ||
1961 (left
<= topChar
&& right
>= lastChar
))) {
1962 XtVaGetValues(textPane
, textNrows
, &rows
, NULL
);
1963 scrollOffset
= rows
/3;
1964 TextGetScroll(textPane
, &topLineNum
, &horizOffset
);
1965 if (right
> lastChar
) {
1966 /* End of sel. is below bottom of screen */
1967 leftLineNum
= topLineNum
+
1968 TextDCountLines(textD
, topChar
, left
, False
);
1969 targetLineNum
= topLineNum
+ scrollOffset
;
1970 if (leftLineNum
>= targetLineNum
) {
1971 /* Start of sel. is not between top & target */
1972 linesToScroll
= TextDCountLines(textD
, lastChar
, right
, False
) +
1974 if (leftLineNum
- linesToScroll
< targetLineNum
)
1975 linesToScroll
= leftLineNum
- targetLineNum
;
1976 /* Scroll start of selection to the target line */
1977 TextSetScroll(textPane
, topLineNum
+linesToScroll
, horizOffset
);
1979 } else if (left
< topChar
) {
1980 /* Start of sel. is above top of screen */
1981 lastLineNum
= topLineNum
+ rows
;
1982 rightLineNum
= lastLineNum
-
1983 TextDCountLines(textD
, right
, lastChar
, False
);
1984 targetLineNum
= lastLineNum
- scrollOffset
;
1985 if (rightLineNum
<= targetLineNum
) {
1986 /* End of sel. is not between bottom & target */
1987 linesToScroll
= TextDCountLines(textD
, left
, topChar
, False
) +
1989 if (rightLineNum
+ linesToScroll
> targetLineNum
)
1990 linesToScroll
= targetLineNum
- rightLineNum
;
1991 /* Scroll end of selection to the target line */
1992 TextSetScroll(textPane
, topLineNum
-linesToScroll
, horizOffset
);
1997 /* If either end of the selection off screen horizontally, try to bring it
1998 in view, by making sure both end-points are visible. Using only end
1999 points of a multi-line selection is not a great idea, and disaster for
2000 rectangular selections, so this part of the routine should be re-written
2001 if it is to be used much with either. Note also that this is a second
2002 scrolling operation, causing the display to jump twice. It's done after
2003 vertical scrolling to take advantage of TextPosToXY which requires it's
2004 reqested position to be vertically on screen) */
2005 if ( TextPosToXY(textPane
, left
, &leftX
, &y
) &&
2006 TextPosToXY(textPane
, right
, &rightX
, &y
) && leftX
<= rightX
) {
2007 TextGetScroll(textPane
, &topLineNum
, &horizOffset
);
2008 XtVaGetValues(textPane
, XmNwidth
, &width
, textNmarginWidth
, &margin
,
2010 if (leftX
< margin
+ textD
->lineNumLeft
+ textD
->lineNumWidth
)
2012 margin
+ textD
->lineNumLeft
+ textD
->lineNumWidth
- leftX
;
2013 else if (rightX
> width
- margin
)
2014 horizOffset
+= rightX
- (width
- margin
);
2015 TextSetScroll(textPane
, topLineNum
, horizOffset
);
2018 /* make sure that the statistics line is up to date */
2019 UpdateStatsLine(window
);
2022 static Widget
createTextArea(Widget parent
, WindowInfo
*window
, int rows
,
2023 int cols
, int emTabDist
, char *delimiters
, int wrapMargin
,
2026 Widget text
, sw
, hScrollBar
, vScrollBar
, frame
;
2028 /* Create a text widget inside of a scrolled window widget */
2029 sw
= XtVaCreateManagedWidget("scrolledW", xmScrolledWindowWidgetClass
,
2030 parent
, XmNpaneMaximum
, SHRT_MAX
,
2031 XmNpaneMinimum
, PANE_MIN_HEIGHT
, XmNhighlightThickness
, 0, NULL
);
2032 hScrollBar
= XtVaCreateManagedWidget("textHorScrollBar",
2033 xmScrollBarWidgetClass
, sw
, XmNorientation
, XmHORIZONTAL
,
2034 XmNrepeatDelay
, 10, NULL
);
2035 vScrollBar
= XtVaCreateManagedWidget("textVertScrollBar",
2036 xmScrollBarWidgetClass
, sw
, XmNorientation
, XmVERTICAL
,
2037 XmNrepeatDelay
, 10, NULL
);
2038 frame
= XtVaCreateManagedWidget("textFrame", xmFrameWidgetClass
, sw
,
2039 XmNshadowType
, XmSHADOW_IN
, NULL
);
2040 text
= XtVaCreateManagedWidget("text", textWidgetClass
, frame
,
2041 textNbacklightCharTypes
, window
->backlightCharTypes
,
2042 textNrows
, rows
, textNcolumns
, cols
,
2043 textNlineNumCols
, lineNumCols
,
2044 textNemulateTabs
, emTabDist
,
2045 textNfont
, GetDefaultFontStruct(window
->fontList
),
2046 textNhScrollBar
, hScrollBar
, textNvScrollBar
, vScrollBar
,
2047 textNreadOnly
, IS_ANY_LOCKED(window
->lockReasons
),
2048 textNwordDelimiters
, delimiters
,
2049 textNwrapMargin
, wrapMargin
,
2050 textNautoIndent
, window
->indentStyle
== AUTO_INDENT
,
2051 textNsmartIndent
, window
->indentStyle
== SMART_INDENT
,
2052 textNautoWrap
, window
->wrapMode
== NEWLINE_WRAP
,
2053 textNcontinuousWrap
, window
->wrapMode
== CONTINUOUS_WRAP
,
2054 textNoverstrike
, window
->overstrike
,
2055 textNhidePointer
, (Boolean
) GetPrefTypingHidesPointer(),
2058 XtVaSetValues(sw
, XmNworkWindow
, frame
, XmNhorizontalScrollBar
,
2059 hScrollBar
, XmNverticalScrollBar
, vScrollBar
, NULL
);
2061 /* add focus, drag, cursor tracking, and smart indent callbacks */
2062 XtAddCallback(text
, textNfocusCallback
, (XtCallbackProc
)focusCB
, window
);
2063 XtAddCallback(text
, textNcursorMovementCallback
, (XtCallbackProc
)movedCB
,
2065 XtAddCallback(text
, textNdragStartCallback
, (XtCallbackProc
)dragStartCB
,
2067 XtAddCallback(text
, textNdragEndCallback
, (XtCallbackProc
)dragEndCB
,
2069 XtAddCallback(text
, textNsmartIndentCallback
, SmartIndentCB
, window
);
2071 /* This makes sure the text area initially has a the insert point shown
2072 ... (check if still true with the nedit text widget, probably not) */
2073 XmAddTabGroup(containingPane(text
));
2075 /* compensate for Motif delete/backspace problem */
2076 RemapDeleteKey(text
);
2078 /* Augment translation table for right button popup menu */
2079 AddBGMenuAction(text
);
2081 /* If absolute line numbers will be needed for display in the statistics
2082 line, tell the widget to maintain them (otherwise, it's a costly
2083 operation and performance will be better without it) */
2084 TextDMaintainAbsLineNum(((TextWidget
)text
)->text
.textD
, window
->showStats
);
2089 static void movedCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2091 if (window
->ignoreModify
)
2094 /* update line and column nubers in statistics line */
2095 UpdateStatsLine(window
);
2097 /* Check the character before the cursor for matchable characters */
2098 FlashMatching(window
, w
);
2100 /* Check for changes to read-only status and/or file modifications */
2101 CheckForChangesToFile(window
);
2104 static void modifiedCB(int pos
, int nInserted
, int nDeleted
, int nRestyled
,
2105 char *deletedText
, void *cbArg
)
2107 WindowInfo
*window
= (WindowInfo
*)cbArg
;
2108 int selected
= window
->buffer
->primary
.selected
;
2110 /* update the table of bookmarks */
2111 if (!window
->ignoreModify
) {
2112 UpdateMarkTable(window
, pos
, nInserted
, nDeleted
);
2115 /* Check and dim/undim selection related menu items */
2116 if ((window
->wasSelected
&& !selected
) ||
2117 (!window
->wasSelected
&& selected
)) {
2118 window
->wasSelected
= selected
;
2120 /* buffers may share a common shell window, menu-bar etc.
2121 we don't do much if things happen to the hidden ones */
2122 if (IsTopBuffer(window
)) {
2123 XtSetSensitive(window
->printSelItem
, selected
);
2124 XtSetSensitive(window
->cutItem
, selected
);
2125 XtSetSensitive(window
->copyItem
, selected
);
2126 XtSetSensitive(window
->delItem
, selected
);
2127 /* Note we don't change the selection for items like
2128 "Open Selected" and "Find Selected". That's because
2129 it works on selections in external applications.
2130 Desensitizing it if there's no NEdit selection
2131 disables this feature. */
2133 XtSetSensitive(window
->filterItem
, selected
);
2136 DimSelectionDepUserMenuItems(window
, selected
);
2137 if (window
->replaceDlog
!= NULL
)
2139 UpdateReplaceActionButtons(window
);
2144 /* Make sure line number display is sufficient for new data */
2145 UpdateLineNumDisp(window
);
2147 /* When the program needs to make a change to a text area without without
2148 recording it for undo or marking file as changed it sets ignoreModify */
2149 if (window
->ignoreModify
|| (nDeleted
== 0 && nInserted
== 0))
2152 /* Save information for undoing this operation (this call also counts
2153 characters and editing operations for triggering autosave */
2154 SaveUndoInformation(window
, pos
, nInserted
, nDeleted
, deletedText
);
2156 /* Trigger automatic backup if operation or character limits reached */
2157 if (window
->autoSave
&&
2158 (window
->autoSaveCharCount
> AUTOSAVE_CHAR_LIMIT
||
2159 window
->autoSaveOpCount
> AUTOSAVE_OP_LIMIT
)) {
2160 WriteBackupFile(window
);
2161 window
->autoSaveCharCount
= 0;
2162 window
->autoSaveOpCount
= 0;
2165 /* Indicate that the window has now been modified */
2166 SetWindowModified(window
, TRUE
);
2168 /* Update # of bytes, and line and col statistics */
2169 UpdateStatsLine(window
);
2171 /* Check if external changes have been made to file and warn user */
2172 CheckForChangesToFile(window
);
2175 static void focusCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2177 /* record which window pane last had the keyboard focus */
2178 window
->lastFocus
= w
;
2180 /* update line number statistic to reflect current focus pane */
2181 UpdateStatsLine(window
);
2183 /* finish off the current incremental search */
2186 /* Check for changes to read-only status and/or file modifications */
2187 CheckForChangesToFile(window
);
2190 static void dragStartCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2192 /* don't record all of the intermediate drag steps for undo */
2193 window
->ignoreModify
= True
;
2196 static void dragEndCB(Widget w
, WindowInfo
*window
, dragEndCBStruct
*callData
)
2198 /* restore recording of undo information */
2199 window
->ignoreModify
= False
;
2201 /* Do nothing if drag operation was canceled */
2202 if (callData
->nCharsInserted
== 0)
2205 /* Save information for undoing this operation not saved while
2206 undo recording was off */
2207 modifiedCB(callData
->startPos
, callData
->nCharsInserted
,
2208 callData
->nCharsDeleted
, 0, callData
->deletedText
, window
);
2211 static void closeCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2213 window
= WidgetToWindow(w
);
2215 if (GetPrefBufferMode()) {
2216 /* in window-buffer mode, we now have only one app window,
2217 to close is to quit */
2218 CloseBufferWindow(w
, window
, callData
);
2221 /* close this window */
2222 if (WindowList
->next
== NULL
) {
2223 if (!CheckPrefsChangesSaved(window
->shell
))
2225 if (!WindowList
->fileChanged
)
2227 if (CloseFileAndWindow(window
, PROMPT_SBC_DIALOG_RESPONSE
))
2230 CloseFileAndWindow(window
, PROMPT_SBC_DIALOG_RESPONSE
);
2234 static void saveYourselfCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2236 WindowInfo
*win
, **revWindowList
;
2237 char geometry
[MAX_GEOM_STRING_LEN
];
2238 int argc
= 0, maxArgc
, nWindows
, i
;
2240 int wasIconic
= False
;
2242 window
= WidgetToWindow(w
);
2244 /* Only post a restart command on the first window in the window list so
2245 session manager can restart the whole set of windows in one executable,
2246 rather than one nedit per file. Even if the restart command is not on
2247 this window, the protocol demands that we set the window's WM_COMMAND
2248 property in response to the "save yourself" message */
2249 if (window
!= WindowList
) {
2250 XSetCommand(TheDisplay
, XtWindow(window
->shell
), NULL
, 0);
2254 /* Allocate memory for an argument list and for a reversed list of
2255 windows. The window list is reversed for IRIX 4DWM and any other
2256 window/session manager combination which uses window creation
2257 order for re-associating stored geometry information with
2258 new windows created by a restored application */
2261 for (win
=WindowList
; win
!=NULL
; win
=win
->next
) {
2265 argv
= (char **)XtMalloc(maxArgc
*sizeof(char *));
2266 revWindowList
= (WindowInfo
**)XtMalloc(sizeof(WindowInfo
*)*nWindows
);
2267 for (win
=WindowList
, i
=nWindows
-1; win
!=NULL
; win
=win
->next
, i
--)
2268 revWindowList
[i
] = win
;
2270 /* Create command line arguments for restoring each window in the list */
2271 argv
[argc
++] = XtNewString(ArgV0
);
2273 argv
[argc
++] = XtNewString("-server");
2274 if (GetPrefServerName()[0] != '\0') {
2275 argv
[argc
++] = XtNewString("-svrname");
2276 argv
[argc
++] = XtNewString(GetPrefServerName());
2279 for (i
=0; i
<nWindows
; i
++) {
2280 win
= revWindowList
[i
];
2281 getGeometryString(win
, geometry
);
2282 argv
[argc
++] = XtNewString("-geometry");
2283 argv
[argc
++] = XtNewString(geometry
);
2284 if (IsIconic(win
)) {
2285 argv
[argc
++] = XtNewString("-iconic");
2287 } else if (wasIconic
) {
2288 argv
[argc
++] = XtNewString("-noiconic");
2291 if (win
->filenameSet
) {
2292 argv
[argc
] = XtMalloc(strlen(win
->path
) +
2293 strlen(win
->filename
) + 1);
2294 sprintf(argv
[argc
++], "%s%s", win
->path
, win
->filename
);
2297 XtFree((char *)revWindowList
);
2299 /* Set the window's WM_COMMAND property to the created command line */
2300 XSetCommand(TheDisplay
, XtWindow(window
->shell
), argv
, argc
);
2301 for (i
=0; i
<argc
; i
++)
2303 XtFree((char *)argv
);
2307 ** Returns true if window is iconic (as determined by the WM_STATE property
2308 ** on the shell window. I think this is the most reliable way to tell,
2309 ** but if someone has a better idea please send me a note).
2311 int IsIconic(WindowInfo
*window
)
2313 unsigned long *property
= NULL
;
2314 unsigned long nItems
;
2315 unsigned long leftover
;
2316 static Atom wmStateAtom
= 0;
2321 if (wmStateAtom
== 0)
2322 wmStateAtom
= XInternAtom (XtDisplay(window
->shell
), "WM_STATE", False
);
2323 if (XGetWindowProperty(XtDisplay(window
->shell
), XtWindow(window
->shell
),
2324 wmStateAtom
, 0L, 1L, False
, wmStateAtom
, &actualType
, &actualFormat
,
2325 &nItems
, &leftover
, (unsigned char **)&property
) != Success
||
2326 nItems
!= 1 || property
== NULL
)
2328 result
= *property
== IconicState
;
2329 XtFree((char *)property
);
2334 ** Add a window to the the window list.
2336 static void addToWindowList(WindowInfo
*window
)
2341 WindowList
= window
;
2342 window
->next
= temp
;
2346 ** Remove a window from the list of windows
2348 static void removeFromWindowList(WindowInfo
*window
)
2352 if (WindowList
== window
)
2353 WindowList
= window
->next
;
2355 for (temp
= WindowList
; temp
!= NULL
; temp
= temp
->next
) {
2356 if (temp
->next
== window
) {
2357 temp
->next
= window
->next
;
2365 ** If necessary, enlarges the window and line number display area
2366 ** to make room for numbers.
2368 void UpdateLineNumDisp(WindowInfo
*window
)
2370 Dimension windowWidth
;
2371 int i
, fontWidth
, reqCols
, lineNumCols
;
2372 int oldWidth
, newWidth
, marginWidth
;
2374 textDisp
*textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
2376 if (!window
->showLineNumbers
)
2379 /* Decide how wide the line number field has to be to display all
2380 possible line numbers */
2381 reqCols
= textD
->nBufferLines
<1 ? 1 : log10((double)textD
->nBufferLines
)+1;
2382 if (reqCols
< MIN_LINE_NUM_COLS
)
2383 reqCols
= MIN_LINE_NUM_COLS
;
2385 /* Is the width of the line number area sufficient to display all the
2386 line numbers in the file? If not, expand line number field, and the
2388 XtVaGetValues(window
->textArea
, textNlineNumCols
, &lineNumCols
,
2389 textNmarginWidth
, &marginWidth
, NULL
);
2390 if (lineNumCols
< reqCols
) {
2391 fontWidth
= textD
->fontStruct
->max_bounds
.width
;
2392 oldWidth
= textD
->left
- marginWidth
;
2393 newWidth
= reqCols
* fontWidth
+ marginWidth
;
2394 XtVaGetValues(window
->shell
, XmNwidth
, &windowWidth
, NULL
);
2395 XtVaSetValues(window
->shell
, XmNwidth
,
2396 windowWidth
+ newWidth
-oldWidth
, NULL
);
2397 UpdateWMSizeHints(window
);
2398 for (i
=0; i
<=window
->nPanes
; i
++) {
2399 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
2400 XtVaSetValues(text
, textNlineNumCols
, reqCols
, NULL
);
2406 ** Update the optional statistics line.
2408 void UpdateStatsLine(WindowInfo
*window
)
2410 int line
, pos
, colNum
;
2411 char *string
, *format
, slinecol
[32];
2412 Widget statW
= window
->statsLine
;
2413 XmString xmslinecol
;
2415 char *sleft
, *smid
, *sright
;
2418 if (!IsTopBuffer(window
))
2421 /* This routine is called for each character typed, so its performance
2422 affects overall editor perfomance. Only update if the line is on. */
2423 if (!window
->showStats
)
2426 /* Compose the string to display. If line # isn't available, leave it off */
2427 pos
= TextGetCursorPos(window
->lastFocus
);
2428 string
= XtMalloc(strlen(window
->filename
) + strlen(window
->path
) + 45);
2429 format
= window
->fileFormat
== DOS_FILE_FORMAT
? " DOS" :
2430 (window
->fileFormat
== MAC_FILE_FORMAT
? " Mac" : "");
2431 if (!TextPosToLineAndCol(window
->lastFocus
, pos
, &line
, &colNum
)) {
2432 sprintf(string
, "%s%s%s %d bytes", window
->path
, window
->filename
,
2433 format
, window
->buffer
->length
);
2434 sprintf(slinecol
, "L: --- C: ---");
2436 sprintf(slinecol
, "L: %d C: %d", line
, colNum
);
2437 if (window
->showLineNumbers
)
2438 sprintf(string
, "%s%s%s byte %d of %d", window
->path
,
2439 window
->filename
, format
, pos
,
2440 window
->buffer
->length
);
2442 sprintf(string
, "%s%s%s %d bytes", window
->path
,
2443 window
->filename
, format
, window
->buffer
->length
);
2446 /* Update the line/column number */
2447 xmslinecol
= XmStringCreateSimple(slinecol
);
2448 XtVaSetValues( window
->statsLineColNo
,
2449 XmNlabelString
, xmslinecol
, NULL
);
2450 XmStringFree(xmslinecol
);
2452 /* Don't clobber the line if there's a special message being displayed */
2453 if (!window
->modeMessageDisplayed
) {
2454 /* Change the text in the stats line */
2456 /* don't show full pathname, just dir and filename (+ byte info) */
2457 smid
= strchr(string
, '/');
2458 if ( smid
!= NULL
) {
2460 sright
= strrchr(string
, '/');
2461 while (strcmp(smid
, sright
)) {
2463 smid
= strchr(sleft
+ 1, '/');
2465 XmTextReplace(statW
, 0, XmTextGetLastPosition(statW
), sleft
+ 1);
2467 XmTextReplace(statW
, 0, XmTextGetLastPosition(statW
), string
);
2469 XmTextReplace(statW
, 0, XmTextGetLastPosition(statW
), string
);
2474 /* Update the line/col display */
2475 xmslinecol
= XmStringCreateSimple(slinecol
);
2476 XtVaSetValues(window
->statsLineColNo
,
2477 XmNlabelString
, xmslinecol
, NULL
);
2478 XmStringFree(xmslinecol
);
2481 static Boolean currentlyBusy
= False
;
2482 static long busyStartTime
= 0;
2483 static Boolean modeMessageSet
= False
;
2486 * Auxiliary function for measuring elapsed time during busy waits.
2488 static long getRelTimeInTenthsOfSeconds()
2491 struct timeval current
;
2492 gettimeofday(¤t
, NULL
);
2493 return (current
.tv_sec
*10 + current
.tv_usec
/100000) & 0xFFFFFFFL
;
2497 return (current
*10) & 0xFFFFFFFL
;
2501 void AllWindowsBusy(const char *message
)
2507 busyStartTime
= getRelTimeInTenthsOfSeconds();
2508 modeMessageSet
= False
;
2510 for (w
=WindowList
; w
!=NULL
; w
=w
->next
)
2512 /* We don't the display message here yet, but defer it for
2513 a while. If the wait is short, we don't want
2514 to have it flash on and off the screen. However,
2515 we can't use a time since in generally we are in
2516 a tight loop and only processing exposure events, so it's
2517 up to the caller to make sure that this routine is called
2518 at regular intervals.
2520 BeginWait(w
->shell
);
2522 } else if (!modeMessageSet
&& message
&&
2523 getRelTimeInTenthsOfSeconds() - busyStartTime
> 10) {
2524 /* Show the mode message when we've been busy for more than a second */
2525 for (w
=WindowList
; w
!=NULL
; w
=w
->next
) {
2526 SetModeMessage(w
, message
);
2528 modeMessageSet
= True
;
2530 BusyWait(WindowList
->shell
);
2532 currentlyBusy
= True
;
2535 void AllWindowsUnbusy(void)
2539 for (w
=WindowList
; w
!=NULL
; w
=w
->next
)
2541 /* ClearModeMessage(w); */
2545 currentlyBusy
= False
;
2546 modeMessageSet
= False
;
2551 ** Paned windows are impossible to adjust after they are created, which makes
2552 ** them nearly useless for NEdit (or any application which needs to dynamically
2553 ** adjust the panes) unless you tweek some private data to overwrite the
2554 ** desired and minimum pane heights which were set at creation time. These
2555 ** will probably break in a future release of Motif because of dependence on
2558 static void setPaneDesiredHeight(Widget w
, int height
)
2560 ((XmPanedWindowConstraintPtr
)w
->core
.constraints
)->panedw
.dheight
= height
;
2562 static void setPaneMinHeight(Widget w
, int min
)
2564 ((XmPanedWindowConstraintPtr
)w
->core
.constraints
)->panedw
.min
= min
;
2568 ** Update the window manager's size hints. These tell it the increments in
2569 ** which it is allowed to resize the window. While this isn't particularly
2570 ** important for NEdit (since it can tolerate any window size), setting these
2571 ** hints also makes the resize indicator show the window size in characters
2572 ** rather than pixels, which is very helpful to users.
2574 void UpdateWMSizeHints(WindowInfo
*window
)
2576 Dimension shellWidth
, shellHeight
, textHeight
, hScrollBarHeight
;
2577 int marginHeight
, marginWidth
, totalHeight
;
2579 int i
, baseWidth
, baseHeight
, fontHeight
, fontWidth
;
2581 textDisp
*textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
2583 /* Find the base (non-expandable) width and height of the editor window */
2584 XtVaGetValues(window
->textArea
, XmNheight
, &textHeight
,
2585 textNmarginHeight
, &marginHeight
, textNmarginWidth
, &marginWidth
,
2587 totalHeight
= textHeight
- 2*marginHeight
;
2588 for (i
=0; i
<window
->nPanes
; i
++) {
2589 XtVaGetValues(window
->textPanes
[i
], XmNheight
, &textHeight
,
2590 textNhScrollBar
, &hScrollBar
, NULL
);
2591 totalHeight
+= textHeight
- 2*marginHeight
;
2592 if (!XtIsManaged(hScrollBar
)) {
2593 XtVaGetValues(hScrollBar
, XmNheight
, &hScrollBarHeight
, NULL
);
2594 totalHeight
-= hScrollBarHeight
;
2597 XtVaGetValues(window
->shell
, XmNwidth
, &shellWidth
,
2598 XmNheight
, &shellHeight
, NULL
);
2599 baseWidth
= shellWidth
- textD
->width
;
2600 baseHeight
= shellHeight
- totalHeight
;
2602 /* Find the dimensions of a single character of the text font */
2603 XtVaGetValues(window
->textArea
, textNfont
, &fs
, NULL
);
2604 fontHeight
= textD
->ascent
+ textD
->descent
;
2605 fontWidth
= fs
->max_bounds
.width
;
2607 /* Set the size hints in the shell widget */
2608 XtVaSetValues(window
->shell
, XmNwidthInc
, fs
->max_bounds
.width
,
2609 XmNheightInc
, fontHeight
,
2610 XmNbaseWidth
, baseWidth
, XmNbaseHeight
, baseHeight
,
2611 XmNminWidth
, baseWidth
+ fontWidth
,
2612 XmNminHeight
, baseHeight
+ (1+window
->nPanes
) * fontHeight
, NULL
);
2616 ** Update the minimum allowable height for a split window pane after a change
2617 ** to font or margin height.
2619 void UpdateMinPaneHeights(WindowInfo
*window
)
2621 textDisp
*textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
2622 Dimension hsbHeight
, swMarginHeight
,frameShadowHeight
;
2623 int i
, marginHeight
, minPaneHeight
;
2626 /* find the minimum allowable size for a pane */
2627 XtVaGetValues(window
->textArea
, textNhScrollBar
, &hScrollBar
, NULL
);
2628 XtVaGetValues(containingPane(window
->textArea
),
2629 XmNscrolledWindowMarginHeight
, &swMarginHeight
, NULL
);
2630 XtVaGetValues(XtParent(window
->textArea
),
2631 XmNshadowThickness
, &frameShadowHeight
, NULL
);
2632 XtVaGetValues(window
->textArea
, textNmarginHeight
, &marginHeight
, NULL
);
2633 XtVaGetValues(hScrollBar
, XmNheight
, &hsbHeight
, NULL
);
2634 minPaneHeight
= textD
->ascent
+ textD
->descent
+ marginHeight
*2 +
2635 swMarginHeight
*2 + hsbHeight
+ 2*frameShadowHeight
;
2637 /* Set it in all of the widgets in the window */
2638 setPaneMinHeight(containingPane(window
->textArea
), minPaneHeight
);
2639 for (i
=0; i
<window
->nPanes
; i
++)
2640 setPaneMinHeight(containingPane(window
->textPanes
[i
]),
2644 /* Add an icon to an applicaction shell widget. addWindowIcon adds a large
2645 ** (primary window) icon, AddSmallIcon adds a small (secondary window) icon.
2647 ** Note: I would prefer that these were not hardwired, but yhere is something
2648 ** weird about the XmNiconPixmap resource that prevents it from being set
2649 ** from the defaults in the application resource database.
2651 static void addWindowIcon(Widget shell
)
2653 static Pixmap iconPixmap
= 0, maskPixmap
= 0;
2655 if (iconPixmap
== 0) {
2656 iconPixmap
= XCreateBitmapFromData(TheDisplay
,
2657 RootWindowOfScreen(XtScreen(shell
)), (char *)iconBits
,
2658 iconBitmapWidth
, iconBitmapHeight
);
2659 maskPixmap
= XCreateBitmapFromData(TheDisplay
,
2660 RootWindowOfScreen(XtScreen(shell
)), (char *)maskBits
,
2661 iconBitmapWidth
, iconBitmapHeight
);
2663 XtVaSetValues(shell
, XmNiconPixmap
, iconPixmap
, XmNiconMask
, maskPixmap
,
2666 void AddSmallIcon(Widget shell
)
2668 static Pixmap iconPixmap
= 0, maskPixmap
= 0;
2670 if (iconPixmap
== 0) {
2671 iconPixmap
= XCreateBitmapFromData(TheDisplay
,
2672 RootWindowOfScreen(XtScreen(shell
)), (char *)n_bits
,
2674 maskPixmap
= XCreateBitmapFromData(TheDisplay
,
2675 RootWindowOfScreen(XtScreen(shell
)), (char *)n_mask
,
2678 XtVaSetValues(shell
, XmNiconPixmap
, iconPixmap
,
2679 XmNiconMask
, maskPixmap
, NULL
);
2682 static void setTabCloseButtonImage(Widget button
)
2684 static Pixmap pixmap
= 0;
2690 /* create pixmap per the color depth setting. This fixes a
2691 BadMatch (X_CopyArea) error due to mismatching of color
2692 depth between the bitmap (depth of 1) and the screen,
2693 specifically on when linked to LessTif (0.93.x) on
2695 XtVaGetValues (button
, XmNforeground
, &fg
, XmNbackground
, &bg
,
2696 XmNdepth
, &depth
, NULL
);
2697 pixmap
= XCreatePixmapFromBitmapData(TheDisplay
,
2698 RootWindowOfScreen(XtScreen(button
)), (char *)close_bits
,
2699 close_width
, close_height
, fg
, bg
, depth
);
2702 XtVaSetValues(button
, XmNlabelPixmap
, pixmap
, NULL
);
2706 ** Save the position and size of a window as an X standard geometry string.
2707 ** A string of at least MAX_GEOMETRY_STRING_LEN characters should be
2708 ** provided in the argument "geomString" to receive the result.
2710 static void getGeometryString(WindowInfo
*window
, char *geomString
)
2712 int x
, y
, fontWidth
, fontHeight
, baseWidth
, baseHeight
;
2713 unsigned int width
, height
, dummyW
, dummyH
, bw
, depth
, nChild
;
2714 Window parent
, root
, *child
, w
= XtWindow(window
->shell
);
2715 Display
*dpy
= XtDisplay(window
->shell
);
2717 /* Find the width and height from the window of the shell */
2718 XGetGeometry(dpy
, w
, &root
, &x
, &y
, &width
, &height
, &bw
, &depth
);
2720 /* Find the top left corner (x and y) of the window decorations. (This
2721 is what's required in the geometry string to restore the window to it's
2722 original position, since the window manager re-parents the window to
2723 add it's title bar and menus, and moves the requested window down and
2724 to the left.) The position is found by traversing the window hier-
2725 archy back to the window to the last parent before the root window */
2727 XQueryTree(dpy
, w
, &root
, &parent
, &child
, &nChild
);
2728 XFree((char*)child
);
2733 XGetGeometry(dpy
, w
, &root
, &x
, &y
, &dummyW
, &dummyH
, &bw
, &depth
);
2735 /* Use window manager size hints (set by UpdateWMSizeHints) to
2736 translate the width and height into characters, as opposed to pixels */
2737 XtVaGetValues(window
->shell
, XmNwidthInc
, &fontWidth
,
2738 XmNheightInc
, &fontHeight
, XmNbaseWidth
, &baseWidth
,
2739 XmNbaseHeight
, &baseHeight
, NULL
);
2740 width
= (width
-baseWidth
) / fontWidth
;
2741 height
= (height
-baseHeight
) / fontHeight
;
2743 /* Write the string */
2744 CreateGeometryString(geomString
, x
, y
, width
, height
,
2745 XValue
| YValue
| WidthValue
| HeightValue
);
2749 ** Xt timer procedure for updating size hints. The new sizes of objects in
2750 ** the window are not ready immediately after adding or removing panes. This
2751 ** is a timer routine to be invoked with a timeout of 0 to give the event
2752 ** loop a chance to finish processing the size changes before reading them
2753 ** out for setting the window manager size hints.
2755 static void wmSizeUpdateProc(XtPointer clientData
, XtIntervalId
*id
)
2757 UpdateWMSizeHints((WindowInfo
*)clientData
);
2762 ** There is a bad memory reference in the delete_child method of the
2763 ** RowColumn widget in some Motif versions (so far, just Solaris with Motif
2764 ** 1.2.3) which appears durring the phase 2 destroy of the widget. This
2765 ** patch replaces the method with a call to the Composite widget's
2766 ** delete_child method. The composite delete_child method handles part,
2767 ** but not all of what would have been done by the original method, meaning
2768 ** that this is dangerous and should be used sparingly. Note that
2769 ** patchRowCol is called only in CloseWindow, before the widget is about to
2770 ** be destroyed, and only on systems where the bug has been observed
2772 static void patchRowCol(Widget w
)
2774 ((XmRowColumnClassRec
*)XtClass(w
))->composite_class
.delete_child
=
2777 static void patchedRemoveChild(Widget child
)
2779 /* Call composite class method instead of broken row col delete_child
2781 (*((CompositeWidgetClass
)compositeWidgetClass
)->composite_class
.
2782 delete_child
) (child
);
2784 #endif /* ROWCOLPATCH */
2787 ** Set the backlight character class string
2789 void SetBacklightChars(WindowInfo
*window
, char *applyBacklightTypes
)
2792 int is_applied
= XmToggleButtonGetState(window
->backlightCharsItem
) ? 1 : 0;
2793 int do_apply
= applyBacklightTypes
? 1 : 0;
2795 window
->backlightChars
= do_apply
;
2797 XtFree(window
->backlightCharTypes
);
2798 if (window
->backlightChars
&&
2799 (window
->backlightCharTypes
= XtMalloc(strlen(applyBacklightTypes
)+1)))
2800 strcpy(window
->backlightCharTypes
, applyBacklightTypes
);
2802 window
->backlightCharTypes
= NULL
;
2804 XtVaSetValues(window
->textArea
,
2805 textNbacklightCharTypes
, window
->backlightCharTypes
, 0);
2806 for (i
=0; i
<window
->nPanes
; i
++)
2807 XtVaSetValues(window
->textPanes
[i
],
2808 textNbacklightCharTypes
, window
->backlightCharTypes
, 0);
2809 if (is_applied
!= do_apply
)
2810 XmToggleButtonSetState(window
->backlightCharsItem
, do_apply
, False
);
2813 static int sortAlphabetical(const void* k1
, const void* k2
)
2815 const char* key1
= *(const char**)k1
;
2816 const char* key2
= *(const char**)k2
;
2817 return strcmp(key1
, key2
);
2821 * Checks whether a given virtual key binding string is invalid.
2822 * A binding is considered invalid if there are duplicate key entries.
2824 static int virtKeyBindingsAreInvalid(const unsigned char* bindings
)
2826 int maxCount
= 1, i
, count
;
2827 const char *pos
= (const char*)bindings
;
2831 /* First count the number of bindings; bindings are separated by \n
2832 strings. The number of bindings equals the number of \n + 1.
2833 Beware of leading and trailing \n; the number is actually an
2834 upper bound on the number of entries. */
2835 while ((pos
= strstr(pos
, "\n"))) { ++pos
; ++maxCount
; }
2837 if (maxCount
== 1) return False
; /* One binding is always ok */
2839 keys
= (char**)malloc(maxCount
*sizeof(char*));
2840 copy
= XtNewString((const char*)bindings
);
2845 while (i
<maxCount
&& pos2
&& *pos2
)
2847 while (isspace((int) *pos2
) || *pos2
== '\n') ++pos2
;
2849 if (*pos2
== '!') /* Ignore comment lines */
2851 pos2
= strstr(pos2
, "\n");
2852 continue; /* Go to the next line */
2859 pos3
= strstr(pos2
, ":");
2862 *pos3
++ = 0; /* Cut the string and jump to the next entry */
2865 pos2
= strstr(pos2
, "\n");
2873 return False
; /* No conflict */
2876 /* Sort the keys and look for duplicates */
2877 qsort((void*)keys
, count
, sizeof(const char*), sortAlphabetical
);
2878 for (i
=1; i
<count
; ++i
)
2880 if (!strcmp(keys
[i
-1], keys
[i
]))
2882 /* Duplicate detected */
2894 * Optionally sanitizes the Motif default virtual key bindings.
2895 * Some applications install invalid bindings (attached to the root window),
2896 * which cause certain keys to malfunction in NEdit.
2897 * Through an X-resource, users can choose whether they want
2898 * - to always keep the existing bindings
2899 * - to override the bindings only if they are invalid
2900 * - to always override the existing bindings.
2903 static Atom virtKeyAtom
;
2905 static unsigned char* sanitizeVirtualKeyBindings()
2907 int overrideBindings
= GetPrefOverrideVirtKeyBindings();
2909 const char *virtKeyPropName
= "_MOTIF_DEFAULT_BINDINGS";
2912 unsigned long dummyULong
, nItems
;
2913 unsigned char *insaneVirtKeyBindings
= NULL
;
2915 if (overrideBindings
== VIRT_KEY_OVERRIDE_NEVER
) return NULL
;
2917 virtKeyAtom
= XInternAtom(TheDisplay
, virtKeyPropName
, False
);
2918 rootWindow
= RootWindow(TheDisplay
, DefaultScreen(TheDisplay
));
2920 /* Remove the property, if it exists; we'll restore it later again */
2921 if (XGetWindowProperty(TheDisplay
, rootWindow
, virtKeyAtom
, 0, INT_MAX
,
2922 True
, XA_STRING
, &dummyAtom
, &getFmt
, &nItems
,
2923 &dummyULong
, &insaneVirtKeyBindings
) != Success
2926 return NULL
; /* No binding yet; nothing to do */
2929 if (overrideBindings
== VIRT_KEY_OVERRIDE_AUTO
)
2931 if (!virtKeyBindingsAreInvalid(insaneVirtKeyBindings
))
2933 /* Restore the property immediately; it seems valid */
2934 XChangeProperty(TheDisplay
, rootWindow
, virtKeyAtom
, XA_STRING
, 8,
2935 PropModeReplace
, insaneVirtKeyBindings
,
2936 strlen((const char*)insaneVirtKeyBindings
));
2937 XFree((char*)insaneVirtKeyBindings
);
2938 return NULL
; /* Prevent restoration */
2941 return insaneVirtKeyBindings
;
2945 * NEdit should not mess with the bindings installed by other apps, so we
2946 * just restore whatever was installed, if necessary
2948 static void restoreInsaneVirtualKeyBindings(unsigned char *insaneVirtKeyBindings
)
2950 if (insaneVirtKeyBindings
)
2952 Window rootWindow
= RootWindow(TheDisplay
, DefaultScreen(TheDisplay
));
2953 /* Restore the root window atom, such that we don't affect
2955 XChangeProperty(TheDisplay
, rootWindow
, virtKeyAtom
, XA_STRING
, 8,
2956 PropModeReplace
, insaneVirtKeyBindings
,
2957 strlen((const char*)insaneVirtKeyBindings
));
2958 XFree((char*)insaneVirtKeyBindings
);
2963 ** perform generic management on the children (toolbars) of toolBarsForm,
2964 ** a.k.a. statsForm, by setting the form attachment of the managed child
2965 ** widgets per their position/order.
2967 ** You can optionally create separator after a toolbar widget with it's
2968 ** widget name set to "TOOLBAR_SEP", which will appear below the toolbar
2969 ** widget. These seperators will then be managed automatically by this
2970 ** routine along with the toolbars they 'attached' to.
2972 ** It also takes care of the attachment offset settings of the child
2973 ** widgets to keep the border lines of the parent form displayed, so
2974 ** you don't have set them before hand.
2976 ** Note: XtManage/XtUnmange the target child (toolbar) before calling this
2979 ** Returns the last toolbar widget managed.
2982 static Widget
manageToolBars(Widget toolBarsForm
)
2984 Widget topWidget
= NULL
;
2985 WidgetList children
;
2988 XtVaGetValues(toolBarsForm
, XmNchildren
, &children
,
2989 XmNnumChildren
, &nItems
, NULL
);
2991 for (n
=0; n
<nItems
; n
++) {
2992 Widget tbar
= children
[n
];
2994 if (XtIsManaged(tbar
)) {
2996 XtVaSetValues(tbar
, XmNtopAttachment
, XmATTACH_WIDGET
,
2997 XmNtopWidget
, topWidget
,
2998 XmNbottomAttachment
, XmATTACH_NONE
,
2999 XmNleftOffset
, STAT_SHADOW_THICKNESS
,
3000 XmNrightOffset
, STAT_SHADOW_THICKNESS
,
3004 /* the very first toolbar on top */
3005 XtVaSetValues(tbar
, XmNtopAttachment
, XmATTACH_FORM
,
3006 XmNbottomAttachment
, XmATTACH_NONE
,
3007 XmNleftOffset
, STAT_SHADOW_THICKNESS
,
3008 XmNtopOffset
, STAT_SHADOW_THICKNESS
,
3009 XmNrightOffset
, STAT_SHADOW_THICKNESS
,
3015 /* if the next widget is a separator, turn it on */
3016 if (n
+1<nItems
&& !strcmp(XtName(children
[n
+1]), "TOOLBAR_SEP")) {
3017 XtManageChild(children
[n
+1]);
3021 /* Remove top attachment to widget to avoid circular dependency.
3022 Attach bottom to form so that when the widget is redisplayed
3023 later, it will trigger the parent form to resize properly as
3024 if the widget is being inserted */
3025 XtVaSetValues(tbar
, XmNtopAttachment
, XmATTACH_NONE
,
3026 XmNbottomAttachment
, XmATTACH_FORM
, NULL
);
3028 /* if the next widget is a separator, turn it off */
3029 if (n
+1<nItems
&& !strcmp(XtName(children
[n
+1]), "TOOLBAR_SEP")) {
3030 XtUnmanageChild(children
[n
+1]);
3036 if (strcmp(XtName(topWidget
), "TOOLBAR_SEP")) {
3037 XtVaSetValues(topWidget
,
3038 XmNbottomAttachment
, XmATTACH_FORM
,
3039 XmNbottomOffset
, STAT_SHADOW_THICKNESS
,
3043 /* is a separator */
3045 XtVaGetValues(topWidget
, XmNtopWidget
, &wgt
, NULL
);
3047 /* don't need sep below bottom-most toolbar */
3048 XtUnmanageChild(topWidget
);
3050 XmNbottomAttachment
, XmATTACH_FORM
,
3051 XmNbottomOffset
, STAT_SHADOW_THICKNESS
,
3060 ** Calculate the dimension of the text area, in terms of rows & cols,
3061 ** as if there's only one single text pane in the window.
3063 static void getTextPaneDimension(WindowInfo
*window
, int *nRows
, int *nCols
)
3066 Dimension hScrollBarHeight
, paneHeight
;
3067 int marginHeight
, marginWidth
, totalHeight
, fontHeight
;
3068 textDisp
*textD
= ((TextWidget
)window
->textArea
)->text
.textD
;
3070 /* width is the same for panes */
3071 XtVaGetValues(window
->textArea
, textNcolumns
, nCols
, NULL
);
3073 /* we have to work out the height, as the text area may have been split */
3074 XtVaGetValues(window
->textArea
, textNhScrollBar
, &hScrollBar
,
3075 textNmarginHeight
, &marginHeight
, textNmarginWidth
, &marginWidth
,
3077 XtVaGetValues(hScrollBar
, XmNheight
, &hScrollBarHeight
, NULL
);
3078 XtVaGetValues(window
->splitPane
, XmNheight
, &paneHeight
, NULL
);
3079 totalHeight
= paneHeight
- 2*marginHeight
-hScrollBarHeight
;
3080 fontHeight
= textD
->ascent
+ textD
->descent
;
3081 *nRows
= totalHeight
/fontHeight
;
3085 ** Create a new buffer in the shell window
3087 WindowInfo
*CreateBuffer(WindowInfo
*shellWindow
, const char *name
,
3088 char *geometry
, int iconic
)
3095 char sgi_title
[MAXPATHLEN
+ 14 + SGI_WINDOW_TITLE_LEN
] = SGI_WINDOW_TITLE
;
3098 /* Allocate some memory for the new window data structure */
3099 window
= (WindowInfo
*)XtMalloc(sizeof(WindowInfo
));
3100 memcpy(window
, shellWindow
, sizeof(WindowInfo
));
3102 /* initialize window structure */
3103 /* + Schwarzenberg: should a
3104 memset(window, 0, sizeof(WindowInfo));
3108 /* share these dialog items with parent shell */
3109 window
->replaceDlog
= NULL
;
3110 window
->replaceText
= NULL
;
3111 window
->replaceWithText
= NULL
;
3112 window
->replaceWordToggle
= NULL
;
3113 window
->replaceCaseToggle
= NULL
;
3114 window
->replaceRegexToggle
= NULL
;
3115 window
->findDlog
= NULL
;
3116 window
->findText
= NULL
;
3117 window
->findWordToggle
= NULL
;
3118 window
->findCaseToggle
= NULL
;
3119 window
->findRegexToggle
= NULL
;
3120 window
->replaceMultiFileDlog
= NULL
;
3121 window
->replaceMultiFilePathBtn
= NULL
;
3122 window
->replaceMultiFileList
= NULL
;
3124 window
->multiFileReplSelected
= FALSE
;
3125 window
->multiFileBusy
= FALSE
;
3126 window
->writableWindows
= NULL
;
3127 window
->nWritableWindows
= 0;
3128 window
->fileChanged
= FALSE
;
3129 window
->fileMissing
= True
;
3130 window
->fileMode
= 0;
3131 window
->filenameSet
= FALSE
;
3132 window
->fileFormat
= UNIX_FILE_FORMAT
;
3133 window
->lastModTime
= 0;
3134 strcpy(window
->filename
, name
);
3135 window
->undo
= NULL
;
3136 window
->redo
= NULL
;
3138 window
->autoSaveCharCount
= 0;
3139 window
->autoSaveOpCount
= 0;
3140 window
->undoOpCount
= 0;
3141 window
->undoMemUsed
= 0;
3142 CLEAR_ALL_LOCKS(window
->lockReasons
);
3143 window
->indentStyle
= GetPrefAutoIndent(PLAIN_LANGUAGE_MODE
);
3144 window
->autoSave
= GetPrefAutoSave();
3145 window
->saveOldVersion
= GetPrefSaveOldVersion();
3146 window
->wrapMode
= GetPrefWrap(PLAIN_LANGUAGE_MODE
);
3147 window
->overstrike
= False
;
3148 window
->showMatchingStyle
= GetPrefShowMatching();
3149 window
->matchSyntaxBased
= GetPrefMatchSyntaxBased();
3150 window
->showStats
= GetPrefStatsLine();
3151 window
->showISearchLine
= GetPrefISearchLine();
3152 window
->showLineNumbers
= GetPrefLineNums();
3153 window
->highlightSyntax
= GetPrefHighlightSyntax();
3154 window
->backlightCharTypes
= NULL
;
3155 window
->backlightChars
= GetPrefBacklightChars();
3156 if (window
->backlightChars
) {
3157 char *cTypes
= GetPrefBacklightCharTypes();
3158 if (cTypes
&& window
->backlightChars
) {
3159 if ((window
->backlightCharTypes
= XtMalloc(strlen(cTypes
) + 1)))
3160 strcpy(window
->backlightCharTypes
, cTypes
);
3163 window
->modeMessageDisplayed
= FALSE
;
3164 window
->ignoreModify
= FALSE
;
3165 window
->windowMenuValid
= FALSE
;
3166 window
->prevOpenMenuValid
= FALSE
;
3167 window
->flashTimeoutID
= 0;
3168 window
->wasSelected
= FALSE
;
3169 strcpy(window
->fontName
, GetPrefFontName());
3170 strcpy(window
->italicFontName
, GetPrefItalicFontName());
3171 strcpy(window
->boldFontName
, GetPrefBoldFontName());
3172 strcpy(window
->boldItalicFontName
, GetPrefBoldItalicFontName());
3173 window
->colorDialog
= NULL
;
3174 window
->fontList
= GetPrefFontList();
3175 window
->italicFontStruct
= GetPrefItalicFont();
3176 window
->boldFontStruct
= GetPrefBoldFont();
3177 window
->boldItalicFontStruct
= GetPrefBoldItalicFont();
3178 window
->fontDialog
= NULL
;
3180 window
->markTimeoutID
= 0;
3181 window
->highlightData
= NULL
;
3182 window
->shellCmdData
= NULL
;
3183 window
->macroCmdData
= NULL
;
3184 window
->smartIndentData
= NULL
;
3185 window
->languageMode
= PLAIN_LANGUAGE_MODE
;
3186 window
->iSearchHistIndex
= 0;
3187 window
->iSearchStartPos
= -1;
3188 window
->replaceLastRegexCase
= TRUE
;
3189 window
->replaceLastLiteralCase
= FALSE
;
3190 window
->iSearchLastRegexCase
= TRUE
;
3191 window
->iSearchLastLiteralCase
= FALSE
;
3192 window
->findLastRegexCase
= TRUE
;
3193 window
->findLastLiteralCase
= FALSE
;
3194 window
->bufferTab
= NULL
;
3196 if (window
->fontList
== NULL
)
3197 XtVaGetValues(shellWindow
->statsLine
, XmNfontList
,
3198 &window
->fontList
,NULL
);
3200 getTextPaneDimension(shellWindow
, &nRows
, &nCols
);
3202 /* Create pane for new buffer. We defer mapping the pane widget
3203 to reduce flickers caused by its resizing when the text area
3205 pane
= XtVaCreateWidget("pane",
3206 xmPanedWindowWidgetClass
, window
->mainWin
,
3207 XmNmarginWidth
, 0, XmNmarginHeight
, 0, XmNseparatorOn
, False
,
3208 XmNspacing
, 3, XmNsashIndent
, -2,
3209 XmNmappedWhenManaged
, False
,
3211 XtVaSetValues(window
->mainWin
, XmNworkWindow
, pane
, NULL
);
3212 XtManageChild(pane
);
3213 window
->splitPane
= pane
;
3215 /* buffer/window info should associate with text pane */
3216 XtVaSetValues(pane
, XmNuserData
, window
, NULL
);
3218 /* Patch around Motif's most idiotic "feature", that its menu accelerators
3219 recognize Caps Lock and Num Lock as modifiers, and don't trigger if
3221 AccelLockBugPatch(pane
, window
->menuBar
);
3223 /* Create the first, and most permanent text area (other panes may
3224 be added & removed, but this one will never be removed */
3225 text
= createTextArea(pane
, window
, nRows
, nCols
,
3226 GetPrefEmTabDist(PLAIN_LANGUAGE_MODE
), GetPrefDelimiters(),
3227 GetPrefWrapMargin(), window
->showLineNumbers
?MIN_LINE_NUM_COLS
:0);
3228 XtManageChild(text
);
3229 window
->textArea
= text
;
3230 window
->lastFocus
= text
;
3232 /* Set the initial colors from the globals. */
3234 GetPrefColorName(TEXT_FG_COLOR
),
3235 GetPrefColorName(TEXT_BG_COLOR
),
3236 GetPrefColorName(SELECT_FG_COLOR
),
3237 GetPrefColorName(SELECT_BG_COLOR
),
3238 GetPrefColorName(HILITE_FG_COLOR
),
3239 GetPrefColorName(HILITE_BG_COLOR
),
3240 GetPrefColorName(LINENO_FG_COLOR
),
3241 GetPrefColorName(CURSOR_FG_COLOR
));
3243 /* map the new buffer pane but keep it hidden */
3244 XLowerWindow(TheDisplay
, XtWindow(pane
));
3247 /* Create the right button popup menu (note: order is important here,
3248 since the translation for popping up this menu was probably already
3249 added in createTextArea, but CreateBGMenu requires window->textArea
3250 to be set so it can attach the menu to it (because menu shells are
3251 finicky about the kinds of widgets they are attached to)) */
3252 window
->bgMenuPane
= CreateBGMenu(window
);
3254 /* Create the text buffer rather than using the one created automatically
3255 with the text area widget. This is done so the syntax highlighting
3256 modify callback can be called to synchronize the style buffer BEFORE
3257 the text display's callback is called upon to display a modification */
3258 window
->buffer
= BufCreate();
3259 BufAddModifyCB(window
->buffer
, SyntaxHighlightModifyCB
, window
);
3261 /* Attach the buffer to the text widget, and add callbacks for modify */
3262 TextSetBuffer(text
, window
->buffer
);
3263 BufAddModifyCB(window
->buffer
, modifiedCB
, window
);
3265 /* Designate the permanent text area as the owner for selections */
3266 HandleXSelections(text
);
3268 /* Set the requested hardware tab distance and useTabs in the text buffer */
3269 BufSetTabDistance(window
->buffer
, GetPrefTabDist(PLAIN_LANGUAGE_MODE
));
3270 window
->buffer
->useTabs
= GetPrefInsertTabs();
3272 /* add the window to the global window list, update the Windows menus */
3273 InvalidateWindowMenus();
3274 addToWindowList(window
);
3276 window
->bufferTab
= addBufferTab(window
->bufferTabBar
, window
, name
);
3277 ShowBufferTabBar(window
, GetPrefTabBar());
3282 ** return the next window/buffer on the tab list.
3284 static WindowInfo
*getNextTabWindow(WindowInfo
*window
, int direction
,
3287 int n
, tabPos
, nextPos
;
3288 WindowInfo
**winList
, *win
;
3289 int nBuf
= crossWin
? NWindows() : NBuffers(window
);
3294 winList
= (WindowInfo
**)XtMalloc(sizeof(WindowInfo
*) * nBuf
);
3296 for (win
=WindowList
; win
&& n
>=0; win
=win
->next
) {
3299 else if (win
->shell
== window
->shell
)
3303 for (n
=0; n
<nBuf
; n
++) {
3304 if (winList
[n
] == window
) {
3310 /* calculate index position of next tab */
3311 nextPos
= tabPos
+ direction
;
3312 if (nextPos
>= nBuf
)
3314 else if (nextPos
< 0)
3317 /* find which window next tab belongs to */
3318 win
= winList
[nextPos
];
3319 XtFree((char *)winList
);
3324 ** return the integer position of a tab in the tabbar it
3325 ** belongs to, or -1 if there's an error, somehow.
3327 static int getTabPosition(Widget tab
)
3331 Widget tabBar
= XtParent(tab
);
3333 XtVaGetValues(tabBar
, XmNtabWidgetList
, &tabList
,
3334 XmNtabCount
, &tabCount
, NULL
);
3336 for (i
=0; i
< tabCount
; i
++) {
3337 if (tab
== tabList
[i
])
3341 return -1; /* something is wrong! */
3345 ** update the tab label, etc. of a tab per the states of it's buffer.
3347 void RefreshTabState(WindowInfo
*win
)
3349 XmString s1
, tipString
;
3350 char labelString
[MAXPATHLEN
];
3352 sprintf(labelString
, "%s%s", win
->fileChanged
? "*" : "",
3354 s1
=XmStringCreateSimple(labelString
);
3356 if (GetPrefShowPathInWindowsMenu() && win
->filenameSet
) {
3357 strcat(labelString
, " - ");
3358 strcat(labelString
, win
->path
);
3360 tipString
=XmStringCreateSimple(labelString
);
3362 XtVaSetValues(win
->bufferTab
,
3363 XltNbubbleString
, tipString
,
3367 XmStringFree(tipString
);
3371 ** close all the buffers in a shell window
3373 int CloseAllBufferInWindow(WindowInfo
*window
)
3377 if (NBuffers(window
) == 1) {
3378 /* the only buffer in the window */
3379 return CloseFileAndWindow(window
, PROMPT_SBC_DIALOG_RESPONSE
);
3382 Widget winShell
= window
->shell
;
3383 WindowInfo
*topBuffer
;
3385 /* close all _modified_ buffers belong to this window */
3386 for (win
= WindowList
; win
; ) {
3387 if (win
->shell
== winShell
&& win
->fileChanged
) {
3388 WindowInfo
*next
= win
->next
;
3389 if (!CloseFileAndWindow(win
, PROMPT_SBC_DIALOG_RESPONSE
))
3397 /* see there's still buffers left in the window */
3398 for (win
= WindowList
; win
; win
=win
->next
)
3399 if (win
->shell
== winShell
)
3403 topBuffer
= GetTopBuffer(winShell
);
3405 /* close all non-top buffers belong to this window */
3406 for (win
= WindowList
; win
; ) {
3407 if (win
->shell
== winShell
&& win
!= topBuffer
) {
3408 WindowInfo
*next
= win
->next
;
3409 if (!CloseFileAndWindow(win
, PROMPT_SBC_DIALOG_RESPONSE
))
3417 /* close the last buffer and its window */
3418 if (!CloseFileAndWindow(topBuffer
, PROMPT_SBC_DIALOG_RESPONSE
))
3426 static void CloseBufferWindow(Widget w
, WindowInfo
*window
, XtPointer callData
)
3428 int nBuffers
= NBuffers(window
);
3430 if (nBuffers
== NWindows()) {
3431 /* this is only window, then exit */
3432 XtCallActionProc(WindowList
->lastFocus
, "exit",
3433 ((XmAnyCallbackStruct
*)callData
)->event
, NULL
, 0);
3436 if (nBuffers
== 1) {
3437 CloseFileAndWindow(window
, PROMPT_SBC_DIALOG_RESPONSE
);
3440 int resp
= DialogF(DF_QUES
, window
->shell
, 2, "Close Window",
3441 "Close ALL buffers in this window?", "Close", "Cancel");
3444 CloseAllBufferInWindow(window
);
3449 static void cloneTextPane(WindowInfo
*window
, WindowInfo
*orgWin
)
3451 short paneHeights
[MAX_PANES
+1];
3452 int insertPositions
[MAX_PANES
+1], topLines
[MAX_PANES
+1];
3453 int horizOffsets
[MAX_PANES
+1];
3454 int i
, focusPane
, emTabDist
, wrapMargin
, lineNumCols
, totalHeight
=0;
3459 /* old window must disown hilite data */
3460 orgWin
->highlightData
= NULL
;
3462 /* transfer the primary selection */
3463 memcpy(&sel
, &orgWin
->buffer
->primary
, sizeof(selection
));
3466 if (sel
.rectangular
)
3467 BufRectSelect(window
->buffer
, sel
.start
, sel
.end
,
3468 sel
.rectStart
, sel
.rectEnd
);
3470 BufSelect(window
->buffer
, sel
.start
, sel
.end
);
3472 BufUnselect(window
->buffer
);
3474 /* Record the current heights, scroll positions, and insert positions
3475 of the existing panes, keyboard focus */
3477 for (i
=0; i
<=orgWin
->nPanes
; i
++) {
3478 text
= i
==0 ? orgWin
->textArea
: orgWin
->textPanes
[i
-1];
3479 insertPositions
[i
] = TextGetCursorPos(text
);
3480 XtVaGetValues(XtParent(text
), XmNheight
, &paneHeights
[i
], NULL
);
3481 totalHeight
+= paneHeights
[i
];
3482 TextGetScroll(text
, &topLines
[i
], &horizOffsets
[i
]);
3483 if (text
== orgWin
->lastFocus
)
3487 window
->nPanes
= orgWin
->nPanes
;
3489 /* clone split panes, if any */
3490 if (window
->nPanes
) {
3491 /* Unmanage & remanage the panedWindow so it recalculates pane heights */
3492 XtUnmanageChild(window
->splitPane
);
3494 /* Create a text widget to add to the pane and set its buffer and
3495 highlight data to be the same as the other panes in the orgWin */
3496 XtVaGetValues(orgWin
->textArea
, textNemulateTabs
, &emTabDist
,
3497 textNwordDelimiters
, &delimiters
, textNwrapMargin
, &wrapMargin
,
3498 textNlineNumCols
, &lineNumCols
, NULL
);
3500 for(i
=0; i
<orgWin
->nPanes
; i
++) {
3501 text
= createTextArea(window
->splitPane
, window
, 1, 1, emTabDist
,
3502 delimiters
, wrapMargin
, lineNumCols
);
3503 TextSetBuffer(text
, window
->buffer
);
3505 if (window
->highlightData
!= NULL
)
3506 AttachHighlightToWidget(text
, window
);
3507 XtManageChild(text
);
3508 window
->textPanes
[i
] = text
;
3511 /* Set the minimum pane height in the new pane */
3512 UpdateMinPaneHeights(window
);
3514 for (i
=0; i
<=window
->nPanes
; i
++) {
3515 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
3516 setPaneDesiredHeight(containingPane(text
), paneHeights
[i
]);
3519 /* Re-manage panedWindow to recalculate pane heights & reset selection */
3520 XtManageChild(window
->splitPane
);
3523 /* Reset all of the heights, scroll positions, etc. */
3524 for (i
=0; i
<=window
->nPanes
; i
++) {
3527 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
3528 TextSetCursorPos(text
, insertPositions
[i
]);
3529 TextSetScroll(text
, topLines
[i
], horizOffsets
[i
]);
3531 /* dim the cursor */
3532 textD
= ((TextWidget
)text
)->text
.textD
;
3533 TextDSetCursorStyle(textD
, DIM_CURSOR
);
3534 TextDUnblankCursor(textD
);
3537 /* set the focus pane */
3538 for (i
=0; i
<=window
->nPanes
; i
++) {
3539 text
= i
==0 ? window
->textArea
: window
->textPanes
[i
-1];
3540 if(i
== focusPane
) {
3541 window
->lastFocus
= text
;
3542 XmProcessTraversal(text
, XmTRAVERSE_CURRENT
);
3547 /* Update the window manager size hints after the sizes of the panes have
3548 been set (the widget heights are not yet readable here, but they will
3549 be by the time the event loop gets around to running this timer proc) */
3550 XtAppAddTimeOut(XtWidgetToApplicationContext(window
->shell
), 0,
3551 wmSizeUpdateProc
, window
);
3555 ** Refresh the menu entries per the settings of the
3556 ** top/active buffer.
3558 void RefreshMenuToggleStates(WindowInfo
*window
)
3563 XtSetSensitive(window
->printSelItem
, window
->wasSelected
);
3566 XtSetSensitive(window
->undoItem
, window
->undo
!= NULL
);
3567 XtSetSensitive(window
->redoItem
, window
->redo
!= NULL
);
3568 XtSetSensitive(window
->printSelItem
, window
->wasSelected
);
3569 XtSetSensitive(window
->cutItem
, window
->wasSelected
);
3570 XtSetSensitive(window
->copyItem
, window
->wasSelected
);
3571 XtSetSensitive(window
->delItem
, window
->wasSelected
);
3573 /* Preferences menu */
3574 XmToggleButtonSetState(window
->statsLineItem
, window
->showStats
, False
);
3575 XmToggleButtonSetState(window
->iSearchLineItem
, window
->showISearchLine
, False
);
3576 XmToggleButtonSetState(window
->lineNumsItem
, window
->showLineNumbers
, False
);
3577 XmToggleButtonSetState(window
->highlightItem
, window
->highlightSyntax
, False
);
3578 XtSetSensitive(window
->highlightItem
, window
->languageMode
!= PLAIN_LANGUAGE_MODE
);
3579 XmToggleButtonSetState(window
->backlightCharsItem
, window
->backlightChars
, False
);
3580 XmToggleButtonSetState(window
->saveLastItem
, window
->saveOldVersion
, False
);
3581 XmToggleButtonSetState(window
->autoSaveItem
, window
->autoSave
, False
);
3582 XmToggleButtonSetState(window
->overtypeModeItem
, window
->overstrike
, False
);
3583 XmToggleButtonSetState(window
->matchSyntaxBasedItem
, window
->matchSyntaxBased
, False
);
3584 XmToggleButtonSetState(window
->readOnlyItem
, IS_USER_LOCKED(window
->lockReasons
), False
);
3586 XtSetSensitive(window
->smartIndentItem
,
3587 SmartIndentMacrosAvailable(LanguageModeName(window
->languageMode
)));
3589 SetAutoIndent(window
, window
->indentStyle
);
3590 SetAutoWrap(window
, window
->wrapMode
);
3591 SetShowMatching(window
, window
->showMatchingStyle
);
3592 SetLanguageMode(window
, window
->languageMode
, FALSE
);
3595 XtSetSensitive(window
->splitWindowItem
, window
->nPanes
< MAX_PANES
);
3596 XtSetSensitive(window
->closePaneItem
, window
->nPanes
> 0);
3597 XtSetSensitive(window
->detachBufferItem
, NBuffers(window
)>1);
3599 for (win
=WindowList
; win
; win
=win
->next
)
3600 if (win
->shell
!= window
->shell
)
3602 XtSetSensitive(window
->attachBufferItem
, win
!= NULL
);
3606 ** Refresh the various settings/state of the shell window per the
3607 ** settings of the top/active buffer.
3609 static void refreshBufferMenuBar(WindowInfo
*window
)
3611 RefreshMenuToggleStates(window
);
3613 /* Add/remove language specific menu items */
3615 UpdateShellMenu(window
);
3617 UpdateMacroMenu(window
);
3618 UpdateBGMenu(window
);
3620 /* refresh selection-sensitive menus */
3621 DimSelectionDepUserMenuItems(window
, window
->wasSelected
);
3624 static void setBufferSharedPref(WindowInfo
*window
, WindowInfo
*lastwin
)
3626 window
->showTabBar
= lastwin
->showTabBar
;
3627 window
->showStats
= lastwin
->showStats
;
3628 window
->showISearchLine
= lastwin
->showISearchLine
;
3632 ** remember the last active buffer
3634 WindowInfo
*MarkLastBuffer(WindowInfo
*window
)
3636 WindowInfo
*prev
= lastBuffer
;
3639 lastBuffer
= window
;
3645 ** remember the active buffer
3647 WindowInfo
*MarkActiveBuffer(WindowInfo
*window
)
3649 WindowInfo
*prev
= focusInBuffer
;
3652 focusInBuffer
= window
;
3658 ** Bring up the next window by tab order
3660 void NextBuffer(WindowInfo
*window
)
3664 if (WindowList
->next
== NULL
)
3667 win
= getNextTabWindow(window
, 1, GetPrefGlobalTabNavigate());
3669 if (window
->shell
== win
->shell
)
3672 RaiseBufferWindow(win
);
3676 ** Bring up the previous window by tab order
3678 void PreviousBuffer(WindowInfo
*window
)
3682 if (WindowList
->next
== NULL
)
3685 win
= getNextTabWindow(window
, -1, GetPrefGlobalTabNavigate());
3687 if (window
->shell
== win
->shell
)
3690 RaiseBufferWindow(win
);
3694 ** Bring up the last active window
3696 void ToggleBuffer(WindowInfo
*window
)
3700 for(win
= WindowList
; win
; win
=win
->next
)
3701 if (lastBuffer
== win
)
3707 if (window
->shell
== win
->shell
)
3710 RaiseBufferWindow(win
);
3715 ** make sure window is alive is kicking
3717 int IsValidWindow(WindowInfo
*window
)
3721 for(win
= WindowList
; win
; win
=win
->next
)
3730 ** raise the buffer and its shell window
3732 void RaiseBufferWindow(WindowInfo
*window
)
3734 RaiseBuffer(window
);
3735 RaiseShellWindow(window
->shell
);
3739 ** raise the buffer in its shell window
3741 void RaiseBuffer(WindowInfo
*window
)
3743 WindowInfo
*win
, *lastwin
;
3745 if (!GetPrefBufferMode())
3748 lastwin
= MarkActiveBuffer(window
);
3749 if (lastwin
!= window
&& IsValidWindow(lastwin
))
3750 MarkLastBuffer(lastwin
);
3752 if (!GetPrefBufferMode() || !window
|| !WindowList
)
3755 /* buffer already active? */
3756 XtVaGetValues(window
->mainWin
, XmNuserData
, &win
, NULL
);
3761 /* refresh shared menu items */
3762 setBufferSharedPref(window
, win
);
3764 /* set the buffer as active */
3765 XtVaSetValues(window
->mainWin
, XmNuserData
, window
, NULL
);
3767 /* show the new top buffer */
3768 XtVaSetValues(window
->mainWin
, XmNworkWindow
, window
->splitPane
, NULL
);
3769 XtManageChild(window
->splitPane
);
3770 XRaiseWindow(TheDisplay
, XtWindow(window
->splitPane
));
3772 /* set tab as active */
3773 XmLFolderSetActiveTab(window
->bufferTabBar
,
3774 getTabPosition(window
->bufferTab
), False
);
3776 /* set keyboard focus. Must be done before unmanaging previous
3777 top buffer, else lastFocus will be reset to textArea */
3778 XmProcessTraversal(window
->lastFocus
, XmTRAVERSE_CURRENT
);
3780 /* we only manage the top buffer, else the next time a buffer
3781 is raised again, it's textpane might not resize properly.
3782 Also, somehow (bug?) XtUnmanageChild() doesn't hide the
3783 splitPane, which obscure lower part of the statsform where
3784 we toggle its components, so we need to put the buffer at
3786 XLowerWindow(TheDisplay
, XtWindow(win
->splitPane
));
3787 XtUnmanageChild(win
->splitPane
);
3789 /* now refresh window state/info. RefreshBufferWindowState()
3790 has a lot of work to do, so we update the screen first so
3791 the buffers appear to switch immediately */
3792 XmUpdateDisplay(window
->splitPane
);
3793 RefreshBufferWindowState(window
);
3796 WindowInfo
* GetTopBuffer(Widget w
)
3798 WindowInfo
*window
= WidgetToWindow(w
);
3800 return WidgetToWindow(window
->shell
);
3803 Boolean
IsTopBuffer(const WindowInfo
*window
)
3805 return window
== GetTopBuffer(window
->shell
)? True
: False
;
3808 void DeleteBuffer(WindowInfo
*window
)
3810 if (!GetPrefBufferMode() || !window
)
3813 XtDestroyWidget(window
->splitPane
);
3817 ** clone a buffer into the other.
3819 static void cloneBuffer(WindowInfo
*window
, WindowInfo
*orgWin
)
3824 strcpy(window
->path
, orgWin
->path
);
3825 strcpy(window
->filename
, orgWin
->filename
);
3827 ShowLineNumbers(window
, orgWin
->showLineNumbers
);
3829 /* copy the buffer */
3830 window
->ignoreModify
= True
;
3831 orgBuffer
= BufGetAll(orgWin
->buffer
);
3832 BufSetAll(window
->buffer
, orgBuffer
);
3833 window
->ignoreModify
= False
;
3836 /* transfer text fonts */
3837 params
[0] = orgWin
->fontName
;
3838 params
[1] = orgWin
->italicFontName
;
3839 params
[2] = orgWin
->boldFontName
;
3840 params
[3] = orgWin
->boldItalicFontName
;
3841 XtCallActionProc(window
->textArea
, "set_fonts", NULL
, params
, 4);
3843 SetBacklightChars(window
, orgWin
->backlightCharTypes
);
3845 /* recycle the hilite data */
3846 window
->languageMode
= orgWin
->languageMode
;
3847 window
->highlightData
= orgWin
->highlightData
;
3848 if (window
->highlightData
!= NULL
)
3849 AttachHighlightToWidget(window
->textArea
, window
);
3851 /* clone original buffer's states */
3852 window
->filenameSet
= orgWin
->filenameSet
;
3853 window
->fileFormat
= orgWin
->fileFormat
;
3854 window
->lastModTime
= orgWin
->lastModTime
;
3855 window
->fileChanged
= orgWin
->fileChanged
;
3856 window
->fileMissing
= orgWin
->fileMissing
;
3857 window
->lockReasons
= orgWin
->lockReasons
;
3858 window
->nPanes
= orgWin
->nPanes
;
3859 window
->autoSaveCharCount
= orgWin
->autoSaveCharCount
;
3860 window
->autoSaveOpCount
= orgWin
->autoSaveOpCount
;
3861 window
->undoOpCount
= orgWin
->undoOpCount
;
3862 window
->undoMemUsed
= orgWin
->undoMemUsed
;
3863 window
->lockReasons
= orgWin
->lockReasons
;
3864 window
->autoSave
= orgWin
->autoSave
;
3865 window
->saveOldVersion
= orgWin
->saveOldVersion
;
3866 window
->wrapMode
= orgWin
->wrapMode
;
3867 window
->overstrike
= orgWin
->overstrike
;
3868 window
->showMatchingStyle
= orgWin
->showMatchingStyle
;
3869 window
->matchSyntaxBased
= orgWin
->matchSyntaxBased
;
3870 window
->highlightSyntax
= orgWin
->highlightSyntax
;
3872 window
->showStats
= orgWin
->showStats
;
3873 window
->showISearchLine
= orgWin
->showISearchLine
;
3874 window
->showLineNumbers
= orgWin
->showLineNumbers
;
3875 window
->modeMessageDisplayed
= orgWin
->modeMessageDisplayed
;
3876 window
->ignoreModify
= orgWin
->ignoreModify
;
3877 window
->windowMenuValid
= orgWin
->windowMenuValid
;
3878 window
->prevOpenMenuValid
= orgWin
->prevOpenMenuValid
;
3879 window
->flashTimeoutID
= orgWin
->flashTimeoutID
;
3880 window
->wasSelected
= orgWin
->wasSelected
;
3881 strcpy(window
->fontName
, orgWin
->fontName
);
3882 strcpy(window
->italicFontName
, orgWin
->italicFontName
);
3883 strcpy(window
->boldFontName
, orgWin
->boldFontName
);
3884 strcpy(window
->boldItalicFontName
, orgWin
->boldItalicFontName
);
3885 window
->fontList
= orgWin
->fontList
;
3886 window
->italicFontStruct
= orgWin
->italicFontStruct
;
3887 window
->boldFontStruct
= orgWin
->boldFontStruct
;
3888 window
->boldItalicFontStruct
= orgWin
->boldItalicFontStruct
;
3889 window
->nMarks
= orgWin
->nMarks
;
3890 window
->markTimeoutID
= orgWin
->markTimeoutID
;
3891 window
->highlightData
= orgWin
->highlightData
;
3892 window
->shellCmdData
= orgWin
->shellCmdData
;
3893 window
->macroCmdData
= orgWin
->macroCmdData
;
3894 window
->smartIndentData
= orgWin
->smartIndentData
;
3896 window
->iSearchHistIndex
= orgWin
->iSearchHistIndex
;
3897 window
->iSearchStartPos
= orgWin
->iSearchStartPos
;
3898 window
->replaceLastRegexCase
= orgWin
->replaceLastRegexCase
;
3899 window
->replaceLastLiteralCase
= orgWin
->replaceLastLiteralCase
;
3900 window
->iSearchLastRegexCase
= orgWin
->iSearchLastRegexCase
;
3901 window
->iSearchLastLiteralCase
= orgWin
->iSearchLastLiteralCase
;
3902 window
->findLastRegexCase
= orgWin
->findLastRegexCase
;
3903 window
->findLastLiteralCase
= orgWin
->findLastLiteralCase
;
3905 /* copy the text/split panes settings, cursor pos & selection */
3906 cloneTextPane(window
, orgWin
);
3908 /* copy undo & redo list */
3909 window
->undo
= cloneUndoItems(orgWin
->undo
);
3910 window
->redo
= cloneUndoItems(orgWin
->redo
);
3912 /* kick start the auto-indent engine */
3913 window
->indentStyle
= NO_AUTO_INDENT
;
3914 SetAutoIndent(window
, orgWin
->indentStyle
);
3916 /* synchronize window state to this buffer */
3917 RefreshBufferWindowState(window
);
3920 static UndoInfo
*cloneUndoItems(UndoInfo
*orgList
)
3922 UndoInfo
*head
= NULL
, *undo
, *clone
, *last
= NULL
;
3924 for (undo
= orgList
; undo
; undo
= undo
->next
) {
3925 clone
= (UndoInfo
*)XtMalloc(sizeof(UndoInfo
));
3926 memcpy(clone
, undo
, sizeof(UndoInfo
));
3928 if (undo
->oldText
) {
3929 clone
->oldText
= XtMalloc(strlen(undo
->oldText
)+1);
3930 strcpy(clone
->oldText
, undo
->oldText
);
3946 ** return number of buffers own by this shell window
3948 int NBuffers(WindowInfo
*window
)
3953 if (!GetPrefBufferMode())
3956 for (win
= WindowList
; win
; win
= win
->next
) {
3957 if (win
->shell
== window
->shell
)
3965 ** refresh window state for this buffer
3967 void RefreshBufferWindowState(WindowInfo
*window
)
3969 if (!GetPrefBufferMode() || !IsTopBuffer(window
))
3972 UpdateStatsLine(window
);
3973 UpdateWindowReadOnly(window
);
3974 UpdateWindowTitle(window
);
3976 /* we need to force the statsline to reveal itself */
3977 XmTextSetCursorPosition(window
->statsLine
, 0); /* start of line */
3978 XmTextSetCursorPosition(window
->statsLine
, 9000); /* end of line */
3980 XmUpdateDisplay(window
->statsLine
);
3981 refreshBufferMenuBar(window
);
3985 ** spin off the buffer to a new window
3987 WindowInfo
*DetachBuffer(WindowInfo
*window
)
3989 WindowInfo
*win
, *cloneWin
;
3990 char *dim
, geometry
[MAX_GEOM_STRING_LEN
];
3992 if (NBuffers(window
) < 2)
3995 /* raise another buffer in the same shell window */
3996 win
= replacementBuffer(window
);
3999 /* create new window in roughly the size of original window,
4000 to reduce flicker when the window is resized later */
4001 getGeometryString(window
, geometry
);
4002 dim
= strtok(geometry
, "+-");
4003 cloneWin
= CreateWindow(window
->filename
, dim
, False
);
4005 /* these settings should follow the detached buffer.
4006 must be done before cloning window, else the height
4007 of split panes may not come out correctly */
4008 ShowISearchLine(cloneWin
, window
->showISearchLine
);
4009 ShowStatsLine(cloneWin
, window
->showStats
);
4011 /* clone the buffer & its pref settings */
4012 cloneBuffer(cloneWin
, window
);
4014 /* remove the buffer from the old window */
4015 window
->fileChanged
= False
;
4016 CloseFileAndWindow(window
, NO_SBC_DIALOG_RESPONSE
);
4018 /* some menu states might have changed when deleting buffer */
4019 RefreshBufferWindowState(win
);
4021 /* this should keep the new buffer window fresh */
4022 RefreshBufferWindowState(cloneWin
);
4023 RefreshTabState(cloneWin
);
4029 ** attach (move) a buffer to an other window.
4031 ** the attaching buffer will inherit the window settings from
4032 ** its new hosts, i.e. the window size, stats and isearch lines.
4034 WindowInfo
*AttachBuffer(WindowInfo
*toWindow
, WindowInfo
*window
)
4036 WindowInfo
*win
, *cloneWin
;
4038 /* raise another buffer in the window of attaching buffer */
4039 for (win
= WindowList
; win
; win
= win
->next
) {
4040 if (win
->shell
== window
->shell
&& window
!= win
)
4047 XtUnmapWidget(window
->shell
);
4049 /* relocate the buffer to target window */
4050 cloneWin
= CreateBuffer(toWindow
, window
->filename
, NULL
, False
);
4051 cloneBuffer(cloneWin
, window
);
4053 /* remove the buffer from the old window */
4054 window
->fileChanged
= False
;
4055 CloseFileAndWindow(window
, NO_SBC_DIALOG_RESPONSE
);
4057 /* some menu states might have changed when deleting buffer */
4059 RefreshBufferWindowState(win
);
4062 /* this should keep the new buffer window fresh */
4063 RaiseBufferWindow(cloneWin
);
4064 RefreshTabState(cloneWin
);
4069 static void attachBufferCB(Widget dialog
, WindowInfo
*parentWin
,
4070 XtPointer call_data
)
4072 XmSelectionBoxCallbackStruct
*cbs
= (XmSelectionBoxCallbackStruct
*) call_data
;
4073 DoneWithAttachBufferDialog
= cbs
->reason
;
4077 ** present dialog to selecting target window for attaching
4078 ** buffers. Return immediately if there is only one shell window.
4080 void AttachBufferDialog(Widget parent
)
4082 WindowInfo
*parentWin
= WidgetToWindow(parent
);
4083 WindowInfo
*win
, *attachWin
, **shellWinList
;
4084 int i
, nList
=0, nWindows
=0, ac
;
4085 char tmpStr
[MAXPATHLEN
+50];
4086 Widget dialog
, listBox
, attachAllOption
;
4087 XmString
*list
= NULL
;
4088 XmString popupTitle
, s1
;
4090 int *position_list
, position_count
;
4092 /* create the window list */
4093 nWindows
= NWindows();
4094 list
= (XmStringTable
) XtMalloc(nWindows
* sizeof(XmString
*));
4095 shellWinList
= (WindowInfo
**) XtMalloc(nWindows
* sizeof(WindowInfo
*));
4097 for (win
=WindowList
; win
; win
=win
->next
) {
4098 if (win
->shell
== parentWin
->shell
)
4101 if (!IsTopBuffer(win
))
4104 sprintf(tmpStr
, "%s%s",
4105 win
->filenameSet
? win
->path
: "", win
->filename
);
4107 list
[nList
] = XmStringCreateSimple(tmpStr
);
4108 shellWinList
[nList
] = win
;
4113 XtFree((char *)list
);
4117 sprintf(tmpStr
, "Attach %s to:", parentWin
->filename
);
4118 popupTitle
= XmStringCreateSimple(tmpStr
);
4120 XtSetArg(csdargs
[ac
], XmNdialogStyle
, XmDIALOG_FULL_APPLICATION_MODAL
); ac
++;
4121 XtSetArg(csdargs
[ac
], XmNlistLabelString
, popupTitle
); ac
++;
4122 XtSetArg(csdargs
[ac
], XmNlistItems
, list
); ac
++;
4123 XtSetArg(csdargs
[ac
], XmNlistItemCount
, nList
); ac
++;
4124 XtSetArg(csdargs
[ac
], XmNvisibleItemCount
, 12); ac
++;
4125 XtSetArg(csdargs
[ac
], XmNautoUnmanage
, False
); ac
++;
4126 dialog
= CreateSelectionDialog(parent
,"attachBuffer",csdargs
,ac
);
4127 XtUnmanageChild(XmSelectionBoxGetChild(dialog
, XmDIALOG_TEXT
));
4128 XtUnmanageChild(XmSelectionBoxGetChild(dialog
, XmDIALOG_HELP_BUTTON
));
4129 XtUnmanageChild(XmSelectionBoxGetChild(dialog
, XmDIALOG_SELECTION_LABEL
));
4130 XtAddCallback(dialog
, XmNokCallback
, (XtCallbackProc
)attachBufferCB
, parentWin
);
4131 XtAddCallback(dialog
, XmNapplyCallback
, (XtCallbackProc
)attachBufferCB
, parentWin
);
4132 XtAddCallback(dialog
, XmNcancelCallback
, (XtCallbackProc
)attachBufferCB
, parentWin
);
4133 XmStringFree(popupTitle
);
4135 /* free the window list */
4136 for (i
=0; i
<nList
; i
++)
4137 XmStringFree(list
[i
]);
4138 XtFree((char *)list
);
4140 /* create the option box for attaching all buffers */
4141 s1
= MKSTRING("Attach all buffers in window");
4142 attachAllOption
= XtVaCreateWidget("attachAll",
4143 xmToggleButtonWidgetClass
, dialog
,
4145 XmNalignment
, XmALIGNMENT_BEGINNING
,
4149 if (NBuffers(parentWin
) >1)
4150 XtManageChild(attachAllOption
);
4152 /* only one buffer in the window */
4153 XtUnmanageChild(XmSelectionBoxGetChild(dialog
, XmDIALOG_APPLY_BUTTON
));
4155 s1
= MKSTRING("Attach");
4156 XtVaSetValues (dialog
, XmNokLabelString
, s1
, NULL
);
4159 /* default to the first window on the list */
4160 listBox
= XmSelectionBoxGetChild(dialog
, XmDIALOG_LIST
);
4161 XmListSelectPos(listBox
, 1, True
);
4162 /* show the dialog */
4163 DoneWithAttachBufferDialog
= 0;
4164 ManageDialogCenteredOnPointer(dialog
);
4165 while (!DoneWithAttachBufferDialog
)
4166 XtAppProcessEvent(XtWidgetToApplicationContext(parent
), XtIMAll
);
4168 /* get window to attach buffer */
4169 XmListGetSelectedPos(listBox
, &position_list
, &position_count
);
4170 attachWin
= shellWinList
[position_list
[0]-1];
4171 XtFree((char *)position_list
);
4173 /* now attach buffer(s) */
4174 if (DoneWithAttachBufferDialog
== XmCR_OK
) {
4175 /* attach top (active) buffer */
4176 if (XmToggleButtonGetState(attachAllOption
)) {
4177 /* attach all buffers */
4178 for (win
= WindowList
; win
; ) {
4179 if (win
!= parentWin
&& win
->shell
== parentWin
->shell
) {
4180 WindowInfo
*next
= win
->next
;
4181 AttachBuffer(attachWin
, win
);
4188 /* top buffer is last to attach */
4189 AttachBuffer(attachWin
, parentWin
);
4192 AttachBuffer(attachWin
, parentWin
);
4196 XtFree((char *)shellWinList
);
4197 XtDestroyWidget(dialog
);
4200 static void hideTooltip(Widget tab
)
4202 Widget tooltip
= XtNameToWidget(tab
, "*BubbleShell");
4209 ** callback to close-tab button.
4211 static void closeTabCB(Widget w
, Widget mainWin
, caddr_t callData
)
4213 CloseFileAndWindow(GetTopBuffer(mainWin
), PROMPT_SBC_DIALOG_RESPONSE
);
4217 ** callback to tab (button).
4219 static void clickTabCB(Widget w
, XtPointer
*clientData
, XtPointer callData
)
4225 ** callback to tab (tabbar) that raise the buffer.
4227 static void raiseTabCB(Widget w
, XtPointer
*clientData
, XtPointer callData
)
4229 XmLFolderCallbackStruct
*cbs
= (XmLFolderCallbackStruct
*)callData
;
4233 XtVaGetValues(w
, XmNtabWidgetList
, &tabList
, NULL
);
4234 tab
= tabList
[cbs
->pos
];
4235 RaiseBuffer(TabToWindow(tab
));
4238 static Widget
containingPane(Widget w
)
4240 /* The containing pane used to simply be the first parent, but with
4241 the introduction of an XmFrame, it's the grandparent. */
4242 return XtParent(XtParent(w
));