1 static const char CVSID
[] = "$Id: nedit.c,v 1.101 2012/10/25 14:10:25 tringali Exp $";
2 /*******************************************************************************
4 * nedit.c -- Nirvana Editor main program *
6 * Copyright (C) 1999 Mark Edel *
8 * This is free software; you can redistribute it and/or modify it under the *
9 * terms of the GNU General Public License as published by the Free Software *
10 * Foundation; either version 2 of the License, or (at your option) any later *
11 * version. In addition, you may distribute versions of this program linked to *
12 * Motif or Open Motif. See README for details. *
14 * This software is distributed in the hope that it will be useful, but WITHOUT *
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
19 * You should have received a copy of the GNU General Public License along with *
20 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
21 * Place, Suite 330, Boston, MA 02111-1307 USA *
23 * Nirvana Text Editor *
26 * Written by Mark Edel *
30 * 8/18/93 - Mark Edel & Joy Kyriakopulos - Ported to VMS *
32 *******************************************************************************/
35 #include "../config.h"
39 /* #include "textBuf.h" */
41 #include "preferences.h"
42 #include "regularExp.h"
43 #include "selection.h"
48 #include "interpret.h"
51 #include "../util/misc.h"
52 #include "../util/printUtils.h"
53 #include "../util/fileUtils.h"
54 #include "../util/getfiles.h"
55 #include "../util/motif.h"
65 #include <X11/Xlocale.h>
70 #include <X11/Intrinsic.h>
75 #include <Xm/RepType.h>
80 #include "../util/VMSparam.h"
81 #include "../util/VMSUtils.h"
85 #include <sys/param.h>
93 static void nextArg(int argc
, char **argv
, int *argIndex
);
94 static int checkDoMacroArg(const char *macro
);
95 static String
neditLanguageProc(Display
*dpy
, String xnl
, XtPointer closure
);
96 static void maskArgvKeywords(int argc
, char **argv
, const char **maskArgs
);
97 static void unmaskArgvKeywords(int argc
, char **argv
, const char **maskArgs
);
98 static void fixupBrokenXKeysymDB(void);
99 static void patchResourcesForVisual(void);
100 static void patchResourcesForKDEbug(void);
101 static void patchLocaleForMotif(void);
102 static unsigned char* sanitizeVirtualKeyBindings(void);
103 static int sortAlphabetical(const void* k1
, const void* k2
);
104 static int virtKeyBindingsAreInvalid(const unsigned char* bindings
);
105 static void restoreInsaneVirtualKeyBindings(unsigned char* bindings
);
106 static void noWarningFilter(String
);
107 static void showWarningFilter(String
);
109 WindowInfo
*WindowList
= NULL
;
110 Display
*TheDisplay
= NULL
;
112 Boolean IsServer
= False
;
115 /* Reasons for choice of default font qualifications:
117 iso8859 appears to be necessary for newer versions of XFree86 that
118 default to Unicode encoding, which doesn't quite work with Motif.
119 Otherwise Motif puts up garbage (square blocks).
121 (This of course, is a stupid default because there are far more iso8859
122 apps than Unicode apps. But the X folks insist it's a client bug. Hah.)
124 RedHat 7.3 won't default to '-1' for an encoding, if left with a *,
125 and so reverts to "fixed". Yech. */
127 #define NEDIT_DEFAULT_FONT "-*-helvetica-medium-r-normal-*-*-120-*-*-*-*-iso8859-1," \
128 "-*-helvetica-bold-r-normal-*-*-120-*-*-*-*-iso8859-1=BOLD," \
129 "-*-helvetica-medium-o-normal-*-*-120-*-*-*-*-iso8859-1=ITALIC"
131 #define NEDIT_FIXED_FONT "-*-courier-medium-r-normal-*-*-120-*-*-*-*-iso8859-1," \
132 "-*-courier-bold-r-normal-*-*-120-*-*-*-*-iso8859-1=BOLD," \
133 "-*-courier-medium-o-normal-*-*-120-*-*-*-*-iso8859-1=ITALIC"
135 #define NEDIT_DEFAULT_BG "#b3b3b3"
137 #define NEDIT_TEXT_TRANSLATIONS "#override\\n" \
138 "Ctrl~Alt~Meta<KeyPress>v: paste-clipboard()\\n" \
139 "Ctrl~Alt~Meta<KeyPress>c: copy-clipboard()\\n" \
140 "Ctrl~Alt~Meta<KeyPress>x: cut-clipboard()\\n" \
141 "Ctrl~Alt~Meta<KeyPress>u: delete-to-start-of-line()\\n"
143 static char *fallbackResources
[] = {
144 /* Try to avoid Motif's horrificly ugly default colors and fonts,
145 if the user's environment provides no usable defaults. We try
146 to choose a Windows-y default color setting here. Editable text
147 fields are forced to a fixed-pitch font for usability.
149 By using the VendorShell fontList resources, Motif automatically
150 groups the fonts into the right classes. It's then easier for
151 the user or environment to override this sensibly:
153 nedit -xrm '*textFontList: myfont'
155 This is broken in recent versions of LessTif.
157 If using OpenMotif 2.3.3 or better, support XFT fonts. XFT is
158 claimed supported in OpenMotif 2.3.0, but doesn't work very well,
159 as insensitive text buttons are blank. That bug is fixed in 2.3.3.
162 #if (XmVersion >= 2003 && XmUPDATE_LEVEL >= 3 && USE_XFT == 1)
163 "*buttonRenderTable: defaultRT",
164 "*labelRenderTable: defaultRT",
165 "*textRenderTable: fixedRT",
166 "*defaultRT.fontType: FONT_IS_XFT",
167 "*defaultRT.fontName: Sans",
168 "*defaultRT.fontSize: 9",
169 "*fixedRT.fontType: FONT_IS_XFT",
170 "*fixedRT.fontName: Monospace",
171 "*fixedRT.fontSize: 9",
172 #elif LESSTIF_VERSION
173 "*FontList: " NEDIT_DEFAULT_FONT
,
174 "*XmText.FontList: " NEDIT_FIXED_FONT
,
175 "*XmTextField.FontList: " NEDIT_FIXED_FONT
,
176 "*XmList.FontList: " NEDIT_FIXED_FONT
,
177 "*XmFileSelectionBox*XmList.FontList: " NEDIT_FIXED_FONT
,
179 "*buttonFontList: " NEDIT_DEFAULT_FONT
,
180 "*labelFontList: " NEDIT_DEFAULT_FONT
,
181 "*textFontList: " NEDIT_FIXED_FONT
,
184 "*background: " NEDIT_DEFAULT_BG
,
185 "*foreground: " NEDIT_DEFAULT_FG
,
186 "*XmText.foreground: " NEDIT_DEFAULT_FG
,
187 "*XmText.background: " NEDIT_DEFAULT_TEXT_BG
,
188 "*XmList.foreground: " NEDIT_DEFAULT_FG
,
189 "*XmList.background: " NEDIT_DEFAULT_TEXT_BG
,
190 "*XmTextField.foreground: " NEDIT_DEFAULT_FG
,
191 "*XmTextField.background: " NEDIT_DEFAULT_TEXT_BG
,
193 /* Use baseTranslations as per Xt Programmer's Manual, 10.2.12 */
194 "*XmText.baseTranslations: " NEDIT_TEXT_TRANSLATIONS
,
195 "*XmTextField.baseTranslations: " NEDIT_TEXT_TRANSLATIONS
,
197 "*XmLFolder.highlightThickness: 0",
198 "*XmLFolder.shadowThickness: 1",
199 "*XmLFolder.maxTabWidth: 150",
200 "*XmLFolder.traversalOn: False",
201 "*XmLFolder.inactiveForeground: #666" ,
202 "*tab.alignment: XmALIGNMENT_BEGINNING",
203 "*tab.marginWidth: 0",
204 "*tab.marginHeight: 1",
206 /* Prevent the file selection box from acting stupid. */
207 "*XmFileSelectionBox.resizePolicy: XmRESIZE_NONE",
208 "*XmFileSelectionBox.textAccelerators:",
209 "*XmFileSelectionBox.pathMode: XmPATH_MODE_RELATIVE",
210 "*XmFileSelectionBox.width: 500",
211 "*XmFileSelectionBox.height: 400",
213 /* NEdit-specific widgets. Theses things should probably be manually
214 jammed into the database, rather than fallbacks. We really want
215 the accelerators to be there even if someone creates an app-defaults
216 file against our wishes. */
218 "*text.lineNumForeground: " NEDIT_DEFAULT_LINENO_FG
,
219 "*text.background: " NEDIT_DEFAULT_TEXT_BG
,
220 "*text.foreground: " NEDIT_DEFAULT_FG
,
221 "*text.highlightForeground: " NEDIT_DEFAULT_HI_FG
,
222 "*text.highlightBackground: " NEDIT_DEFAULT_HI_BG
,
223 "*textFrame.shadowThickness: 1",
224 "*menuBar.marginHeight: 0",
225 "*menuBar.shadowThickness: 1",
226 "*pane.sashHeight: 11",
227 "*pane.sashWidth: 11",
228 "*pane.marginWidth: 0",
229 "*pane.marginHeight: 0",
230 "*scrolledW*spacing: 0",
231 "*text.selectionArrayCount: 3",
232 "*helpText.background: " NEDIT_DEFAULT_HELP_BG
,
233 "*helpText.foreground: " NEDIT_DEFAULT_HELP_FG
,
234 "*helpText.selectBackground: " NEDIT_DEFAULT_BG
,
235 "*statsLine.background: " NEDIT_DEFAULT_BG
,
236 "*statsLine.FontList: " NEDIT_DEFAULT_FONT
,
237 "*calltip.background: LemonChiffon1",
238 "*calltip.foreground: black",
239 "*iSearchForm*highlightThickness: 1",
240 "*fileMenu.tearOffModel: XmTEAR_OFF_ENABLED",
241 "*editMenu.tearOffModel: XmTEAR_OFF_ENABLED",
242 "*searchMenu.tearOffModel: XmTEAR_OFF_ENABLED",
243 "*preferencesMenu.tearOffModel: XmTEAR_OFF_ENABLED",
244 "*windowsMenu.tearOffModel: XmTEAR_OFF_ENABLED",
245 "*shellMenu.tearOffModel: XmTEAR_OFF_ENABLED",
246 "*macroMenu.tearOffModel: XmTEAR_OFF_ENABLED",
247 "*helpMenu.tearOffModel: XmTEAR_OFF_ENABLED",
248 "*fileMenu.mnemonic: F",
249 "*fileMenu.new.accelerator: Ctrl<Key>n",
250 "*fileMenu.new.acceleratorText: Ctrl+N",
251 "*fileMenu.newOpposite.accelerator: Shift Ctrl<Key>n",
252 "*fileMenu.newOpposite.acceleratorText: Shift+Ctrl+N",
253 "*fileMenu.open.accelerator: Ctrl<Key>o",
254 "*fileMenu.open.acceleratorText: Ctrl+O",
255 "*fileMenu.openSelected.accelerator: Ctrl<Key>y",
256 "*fileMenu.openSelected.acceleratorText: Ctrl+Y",
257 "*fileMenu.close.accelerator: Ctrl<Key>w",
258 "*fileMenu.close.acceleratorText: Ctrl+W",
259 "*fileMenu.save.accelerator: Ctrl<Key>s",
260 "*fileMenu.save.acceleratorText: Ctrl+S",
261 "*fileMenu.includeFile.accelerator: Alt<Key>i",
262 "*fileMenu.includeFile.acceleratorText: Alt+I",
263 "*fileMenu.print.accelerator: Ctrl<Key>p",
264 "*fileMenu.print.acceleratorText: Ctrl+P",
265 "*fileMenu.exit.accelerator: Ctrl<Key>q",
266 "*fileMenu.exit.acceleratorText: Ctrl+Q",
267 "*editMenu.mnemonic: E",
268 "*editMenu.undo.accelerator: Ctrl<Key>z",
269 "*editMenu.undo.acceleratorText: Ctrl+Z",
270 "*editMenu.redo.accelerator: Shift Ctrl<Key>z",
271 "*editMenu.redo.acceleratorText: Shift+Ctrl+Z",
272 /* Clipboard accelerators prevent the use of the clipboard in iSearch's
273 XmText, so they are left out. Their job is done by translations in
274 the main text widget, so the acceleratorText is still kept. */
275 "*editMenu.cut.acceleratorText: Ctrl+X",
276 "*editMenu.copy.acceleratorText: Ctrl+C",
277 "*editMenu.paste.acceleratorText: Ctrl+V",
278 "*editMenu.pasteColumn.accelerator: Shift Ctrl<Key>v",
279 "*editMenu.pasteColumn.acceleratorText: Ctrl+Shift+V",
280 "*editMenu.delete.acceleratorText: Del",
281 "*editMenu.selectAll.accelerator: Ctrl<Key>a",
282 "*editMenu.selectAll.acceleratorText: Ctrl+A",
283 "*editMenu.shiftLeft.accelerator: Ctrl<Key>9",
284 "*editMenu.shiftLeft.acceleratorText: [Shift]Ctrl+9",
285 "*editMenu.shiftLeftShift.accelerator: Shift Ctrl<Key>9",
286 "*editMenu.shiftRight.accelerator: Ctrl<Key>0",
287 "*editMenu.shiftRight.acceleratorText: [Shift]Ctrl+0",
288 "*editMenu.shiftRightShift.accelerator: Shift Ctrl<Key>0",
289 "*editMenu.upperCase.accelerator: Ctrl<Key>6",
290 "*editMenu.upperCase.acceleratorText: Ctrl+6",
291 "*editMenu.lowerCase.accelerator: Shift Ctrl<Key>6",
292 "*editMenu.lowerCase.acceleratorText: Shift+Ctrl+6",
293 "*editMenu.fillParagraph.accelerator: Ctrl<Key>j",
294 "*editMenu.fillParagraph.acceleratorText: Ctrl+J",
295 "*editMenu.insertFormFeed.accelerator: Alt Ctrl<Key>l",
296 "*editMenu.insertFormFeed.acceleratorText: Alt+Ctrl+L",
297 "*editMenu.insertCtrlCode.accelerator: Alt Ctrl<Key>i",
298 "*editMenu.insertCtrlCode.acceleratorText: Alt+Ctrl+I",
299 "*searchMenu.mnemonic: S",
300 "*searchMenu.find.accelerator: Ctrl<Key>f",
301 "*searchMenu.find.acceleratorText: [Shift]Ctrl+F",
302 "*searchMenu.findShift.accelerator: Shift Ctrl<Key>f",
303 "*searchMenu.findAgain.accelerator: Ctrl<Key>g",
304 "*searchMenu.findAgain.acceleratorText: [Shift]Ctrl+G",
305 "*searchMenu.findAgainShift.accelerator: Shift Ctrl<Key>g",
306 "*searchMenu.findSelection.accelerator: Ctrl<Key>h",
307 "*searchMenu.findSelection.acceleratorText: [Shift]Ctrl+H",
308 "*searchMenu.findSelectionShift.accelerator: Shift Ctrl<Key>h",
309 "*searchMenu.findIncremental.accelerator: Ctrl<Key>i",
310 "*searchMenu.findIncrementalShift.accelerator: Shift Ctrl<Key>i",
311 "*searchMenu.findIncremental.acceleratorText: [Shift]Ctrl+I",
312 "*searchMenu.replace.accelerator: Ctrl<Key>r",
313 "*searchMenu.replace.acceleratorText: [Shift]Ctrl+R",
314 "*searchMenu.replaceShift.accelerator: Shift Ctrl<Key>r",
315 "*searchMenu.findReplace.accelerator: Ctrl<Key>r",
316 "*searchMenu.findReplace.acceleratorText: [Shift]Ctrl+R",
317 "*searchMenu.findReplaceShift.accelerator: Shift Ctrl<Key>r",
318 "*searchMenu.replaceFindAgain.accelerator: Ctrl<Key>t",
319 "*searchMenu.replaceFindAgain.acceleratorText: [Shift]Ctrl+T",
320 "*searchMenu.replaceFindAgainShift.accelerator: Shift Ctrl<Key>t",
321 "*searchMenu.replaceAgain.accelerator: Alt<Key>t",
322 "*searchMenu.replaceAgain.acceleratorText: [Shift]Alt+T",
323 "*searchMenu.replaceAgainShift.accelerator: Shift Alt<Key>t",
324 "*searchMenu.gotoLineNumber.accelerator: Ctrl<Key>l",
325 "*searchMenu.gotoLineNumber.acceleratorText: Ctrl+L",
326 "*searchMenu.gotoSelected.accelerator: Ctrl<Key>e",
327 "*searchMenu.gotoSelected.acceleratorText: Ctrl+E",
328 "*searchMenu.mark.accelerator: Alt<Key>m",
329 "*searchMenu.mark.acceleratorText: Alt+M a-z",
330 "*searchMenu.gotoMark.accelerator: Alt<Key>g",
331 "*searchMenu.gotoMark.acceleratorText: [Shift]Alt+G a-z",
332 "*searchMenu.gotoMarkShift.accelerator: Shift Alt<Key>g",
333 "*searchMenu.gotoMatching.accelerator: Ctrl<Key>m",
334 "*searchMenu.gotoMatching.acceleratorText: [Shift]Ctrl+M",
335 "*searchMenu.gotoMatchingShift.accelerator: Shift Ctrl<Key>m",
336 "*searchMenu.findDefinition.accelerator: Ctrl<Key>d",
337 "*searchMenu.findDefinition.acceleratorText: Ctrl+D",
338 "*searchMenu.showCalltip.accelerator: Ctrl<Key>apostrophe",
339 "*searchMenu.showCalltip.acceleratorText: Ctrl+'",
340 "*preferencesMenu.mnemonic: P",
341 "*preferencesMenu.statisticsLine.accelerator: Alt<Key>a",
342 "*preferencesMenu.statisticsLine.acceleratorText: Alt+A",
343 "*preferencesMenu.overtype.acceleratorText: Insert",
344 "*shellMenu.mnemonic: l",
345 "*shellMenu.filterSelection.accelerator: Alt<Key>r",
346 "*shellMenu.filterSelection.acceleratorText: Alt+R",
347 "*shellMenu.executeCommand.accelerator: Alt<Key>x",
348 "*shellMenu.executeCommand.acceleratorText: Alt+X",
349 "*shellMenu.executeCommandLine.accelerator: Ctrl<Key>KP_Enter",
350 "*shellMenu.executeCommandLine.acceleratorText: Ctrl+KP Enter",
351 "*shellMenu.cancelShellCommand.accelerator: Ctrl<Key>period",
352 "*shellMenu.cancelShellCommand.acceleratorText: Ctrl+.",
353 "*macroMenu.mnemonic: c",
354 "*macroMenu.learnKeystrokes.accelerator: Alt<Key>k",
355 "*macroMenu.learnKeystrokes.acceleratorText: Alt+K",
356 "*macroMenu.finishLearn.accelerator: Alt<Key>k",
357 "*macroMenu.finishLearn.acceleratorText: Alt+K",
358 "*macroMenu.cancelLearn.accelerator: Ctrl<Key>period",
359 "*macroMenu.cancelLearn.acceleratorText: Ctrl+.",
360 "*macroMenu.replayKeystrokes.accelerator: Ctrl<Key>k",
361 "*macroMenu.replayKeystrokes.acceleratorText: Ctrl+K",
362 "*macroMenu.repeat.accelerator: Ctrl<Key>comma",
363 "*macroMenu.repeat.acceleratorText: Ctrl+,",
364 "*windowsMenu.mnemonic: W",
365 "*windowsMenu.splitPane.accelerator: Ctrl<Key>2",
366 "*windowsMenu.splitPane.acceleratorText: Ctrl+2",
367 "*windowsMenu.closePane.accelerator: Ctrl<Key>1",
368 "*windowsMenu.closePane.acceleratorText: Ctrl+1",
369 "*helpMenu.mnemonic: H",
370 "nedit.help.helpForm.sw.helpText*baseTranslations: #override\
371 <Key>Tab:help-focus-buttons()\\n\
372 <Key>Return:help-button-action(\"close\")\\n\
373 Ctrl<Key>F:help-button-action(\"find\")\\n\
374 Ctrl<Key>G:help-button-action(\"findAgain\")\\n\
375 <KeyPress>osfCancel:help-button-action(\"close\")\\n\
376 ~Meta~Ctrl~Shift<Btn1Down>:\
377 grab-focus() help-hyperlink()\\n\
378 ~Meta~Ctrl~Shift<Btn1Up>:\
379 help-hyperlink(\"current\", \"process-cancel\", \"extend-end\")\\n\
380 ~Meta~Ctrl~Shift<Btn2Down>:\
381 process-bdrag() help-hyperlink()\\n\
382 ~Meta~Ctrl~Shift<Btn2Up>:\
383 help-hyperlink(\"new\", \"process-cancel\", \"copy-to\")",
387 static const char cmdLineHelp
[] =
389 "Usage: nedit [-read] [-create] [-line n | +n] [-server] [-do command]\n\
390 [-tags file] [-tabs n] [-wrap] [-nowrap] [-autowrap]\n\
391 [-autoindent] [-noautoindent] [-autosave] [-noautosave]\n\
392 [-lm languagemode] [-rows n] [-columns n] [-font font]\n\
393 [-geometry geometry] [-iconic] [-noiconic] [-svrname name]\n\
394 [-display [host]:server[.screen] [-xrm resourcestring]\n\
395 [-import file] [-background color] [-foreground color]\n\
396 [-tabbed] [-untabbed] [-group] [-V|-version] [-h|-help]\n\
399 "[Sorry, no on-line help available.]\n"; /* Why is that ? */
402 int main(int argc
, char **argv
)
404 int i
, lineNum
, nRead
, fileSpecified
= FALSE
, editFlags
= CREATE
;
405 int gotoLine
= False
, macroFileRead
= False
, opts
= True
;
406 int iconic
=False
, tabbed
= -1, group
= 0, isTabbed
;
407 char *toDoCommand
= NULL
, *geometry
= NULL
, *langMode
= NULL
;
408 char filename
[MAXPATHLEN
], pathname
[MAXPATHLEN
];
409 XtAppContext context
;
411 WindowInfo
*window
= NULL
, *lastFile
= NULL
;
412 static const char *protectedKeywords
[] = {"-iconic", "-icon", "-geometry",
413 "-g", "-rv", "-reverse", "-bd", "-bordercolor", "-borderwidth",
414 "-bw", "-title", NULL
};
415 unsigned char* invalidBindings
= NULL
;
417 /* Warn user if this has been compiled wrong. */
418 enum MotifStability stability
= GetMotifStability();
419 if (stability
== MotifKnownBad
) {
420 fputs("nedit: WARNING: This version of NEdit is built incorrectly, and will be unstable.\n"
421 "nedit: Please get a stable version of NEdit from http://www.nedit.org.\n",
425 /* Save the command which was used to invoke nedit for restart command */
428 /* Set locale for C library, X, and Motif input functions.
429 Reverts to "C" if requested locale not available. */
430 XtSetLanguageProc(NULL
, neditLanguageProc
, NULL
);
432 /* Initialize X toolkit (does not open display yet) */
433 XtToolkitInitialize();
434 context
= XtCreateApplicationContext();
436 /* Set up a warning handler to trap obnoxious Xt grab warnings */
437 SuppressPassiveGrabWarnings();
439 /* Set up a handler to suppress X warning messages by default */
440 XtAppSetWarningHandler(context
, noWarningFilter
);
442 /* Set up default resources if no app-defaults file is found */
443 XtAppSetFallbackResources(context
, fallbackResources
);
445 #if XmVersion >= 1002
446 /* Allow users to change tear off menus with X resources */
447 XmRepTypeInstallTearOffModelConverter();
451 /* Convert the command line to Unix style (This is not an ideal solution) */
452 ConvertVMSCommandLine(&argc
, &argv
);
455 /* expand wildcards if necessary */
456 _wildcard(&argc
, &argv
);
459 /* Read the preferences file and command line into a database */
460 prefDB
= CreateNEditPrefDB(&argc
, argv
);
462 /* Open the display and read X database and remaining command line args.
463 XtOpenDisplay must be allowed to process some of the resource arguments
464 with its inaccessible internal option table, but others, like -geometry
465 and -iconic are per-window and it should not be allowed to consume them,
466 so we temporarily masked them out. */
467 maskArgvKeywords(argc
, argv
, protectedKeywords
);
468 /* X.Org 6.8 and above add support for ARGB visuals (with alpha-channel),
469 typically with a 32-bit color depth. By default, NEdit uses the visual
470 with the largest color depth. However, both OpenMotif and Lesstif
471 cannot handle ARGB visuals (crashes, weird display effects, ...), so
472 NEdit should avoid selecting such a visual.
473 Unfortunatly, there appears to be no reliable way to identify
474 ARGB visuals that doesn't require some of the recent X.Org
475 extensions. Luckily, the X.Org developers have provided a mechanism
476 that can hide these problematic visuals from the application. This can
477 be achieved by setting the XLIB_SKIP_ARGB_VISUALS environment variable.
478 Users can set this variable before starting NEdit, but it is much
479 more convenient that NEdit takes care of this. This must be done before
480 the display is opened (empirically verified). */
481 putenv("XLIB_SKIP_ARGB_VISUALS=1");
482 TheDisplay
= XtOpenDisplay (context
, NULL
, APP_NAME
, APP_CLASS
,
483 NULL
, 0, &argc
, argv
);
484 unmaskArgvKeywords(argc
, argv
, protectedKeywords
);
486 /* Respond to -V or -version even if there is no display */
487 for (i
= 1; i
< argc
&& strcmp(argv
[i
], "--"); i
++)
489 if (0 == strcmp(argv
[i
], "-V") || 0 == strcmp(argv
[i
], "-version"))
495 fputs ("NEdit: Can't open display\n", stderr
);
499 /* Must be done before creating widgets */
500 fixupBrokenXKeysymDB();
501 patchResourcesForVisual();
502 patchResourcesForKDEbug();
504 /* Initialize global symbols and subroutines used in the macro language */
506 RegisterMacroSubroutines();
508 /* Store preferences from the command line and .nedit file,
509 and set the appropriate preferences */
510 RestoreNEditPrefs(prefDB
, XtDatabase(TheDisplay
));
512 /* Intercept syntactically invalid virtual key bindings BEFORE we
513 create any shells. */
514 invalidBindings
= sanitizeVirtualKeyBindings();
516 /* Create a hidden application shell that is the parent of all the
517 main editor windows. Realize it so it the window can act as
519 TheAppShell
= CreateShellWithBestVis(APP_NAME
,
521 applicationShellWidgetClass
,
526 /* Restore the original bindings ASAP such that other apps are not affected. */
527 restoreInsaneVirtualKeyBindings(invalidBindings
);
529 XtSetMappedWhenManaged(TheAppShell
, False
);
530 XtRealizeWidget(TheAppShell
);
532 #ifndef NO_SESSION_RESTART
533 AttachSessionMgrHandler(TheAppShell
);
536 /* More preference stuff */
537 LoadPrintPreferences(XtDatabase(TheDisplay
), APP_NAME
, APP_CLASS
, True
);
538 SetDeleteRemap(GetPrefMapDelete());
539 SetPointerCenteredDialogs(GetPrefRepositionDialogs());
540 SetGetEFTextFieldRemoval(!GetPrefStdOpenDialog());
542 /* Set up action procedures for menu item commands */
543 InstallMenuActions(context
);
545 /* Add Actions for following hyperlinks in the help window */
546 InstallHelpLinkActions(context
);
547 /* Add actions for mouse wheel support in scrolled windows (except text
549 InstallMouseWheelActions(context
);
551 /* Install word delimiters for regular expression matching */
552 SetREDefaultWordDelimiters(GetPrefDelimiters());
554 /* Read the nedit dynamic database of files for the Open Previous
555 command (and eventually other information as well) */
558 /* Process -import command line argument before others which might
559 open windows (loading preferences doesn't update menu settings,
560 which would then be out of sync with the real preference settings) */
561 for (i
=1; i
<argc
; i
++) {
562 if(!strcmp(argv
[i
], "--")) {
563 break; /* treat all remaining arguments as filenames */
564 } else if (!strcmp(argv
[i
], "-import")) {
565 nextArg(argc
, argv
, &i
);
566 ImportPrefFile(argv
[i
], False
);
567 } else if (!strcmp(argv
[i
], "-importold")) {
568 nextArg(argc
, argv
, &i
);
569 ImportPrefFile(argv
[i
], True
);
573 /* Load the default tags file. Don't complain if it doesn't load, the tag
574 file resource is intended to be set and forgotten. Running nedit in a
575 directory without a tags should not cause it to spew out errors. */
576 if (*GetPrefTagFile() != '\0') {
577 AddTagsFile(GetPrefTagFile(), TAG
);
580 if (strcmp(GetPrefServerName(), "") != 0) {
584 /* Process any command line arguments (-tags, -do, -read, -create,
585 +<line_number>, -line, -server, and files to edit) not already
586 processed by RestoreNEditPrefs. */
587 fileSpecified
= FALSE
;
588 for (i
=1; i
<argc
; i
++) {
589 if (opts
&& !strcmp(argv
[i
], "--")) {
590 opts
= False
; /* treat all remaining arguments as filenames */
592 } else if (opts
&& !strcmp(argv
[i
], "-tags")) {
593 nextArg(argc
, argv
, &i
);
594 if (!AddTagsFile(argv
[i
], TAG
))
595 fprintf(stderr
, "NEdit: Unable to load tags file\n");
596 } else if (opts
&& !strcmp(argv
[i
], "-do")) {
597 nextArg(argc
, argv
, &i
);
598 if (checkDoMacroArg(argv
[i
]))
599 toDoCommand
= argv
[i
];
600 } else if (opts
&& !strcmp(argv
[i
], "-read")) {
601 editFlags
|= PREF_READ_ONLY
;
602 } else if (opts
&& !strcmp(argv
[i
], "-create")) {
603 editFlags
|= SUPPRESS_CREATE_WARN
;
604 } else if (opts
&& !strcmp(argv
[i
], "-tabbed")) {
606 group
= 0; /* override -group option */
607 } else if (opts
&& !strcmp(argv
[i
], "-untabbed")) {
609 group
= 0; /* override -group option */
610 } else if (opts
&& !strcmp(argv
[i
], "-group")) {
611 group
= 2; /* 2: start new group, 1: in group */
612 } else if (opts
&& !strcmp(argv
[i
], "-line")) {
613 nextArg(argc
, argv
, &i
);
614 nRead
= sscanf(argv
[i
], "%d", &lineNum
);
616 fprintf(stderr
, "NEdit: argument to line should be a number\n");
619 } else if (opts
&& (*argv
[i
] == '+')) {
620 nRead
= sscanf((argv
[i
]+1), "%d", &lineNum
);
622 fprintf(stderr
, "NEdit: argument to + should be a number\n");
625 } else if (opts
&& !strcmp(argv
[i
], "-server")) {
627 } else if (opts
&& !strcmp(argv
[i
], "-xwarn")) {
628 XtAppSetWarningHandler(context
, showWarningFilter
);
629 } else if (opts
&& (!strcmp(argv
[i
], "-iconic") ||
630 !strcmp(argv
[i
], "-icon"))) {
632 } else if (opts
&& !strcmp(argv
[i
], "-noiconic")) {
634 } else if (opts
&& (!strcmp(argv
[i
], "-geometry") ||
635 !strcmp(argv
[i
], "-g"))) {
636 nextArg(argc
, argv
, &i
);
638 } else if (opts
&& !strcmp(argv
[i
], "-lm")) {
639 nextArg(argc
, argv
, &i
);
641 } else if (opts
&& !strcmp(argv
[i
], "-import")) {
642 nextArg(argc
, argv
, &i
); /* already processed, skip */
643 } else if (opts
&& (!strcmp(argv
[i
], "-V") ||
644 !strcmp(argv
[i
], "-version"))) {
647 } else if (opts
&& (!strcmp(argv
[i
], "-h") ||
648 !strcmp(argv
[i
], "-help"))) {
649 fprintf(stderr
, "%s", cmdLineHelp
);
651 } else if (opts
&& (*argv
[i
] == '-')) {
655 fprintf(stderr
, "nedit: Unrecognized option %s\n%s", argv
[i
],
661 char **nameList
= NULL
;
662 /* Use VMS's LIB$FILESCAN for filename in argv[i] to process */
663 /* wildcards and to obtain a full VMS file specification */
664 numFiles
= VMSFileScan(argv
[i
], &nameList
, NULL
, INCLUDE_FNF
);
665 /* for each expanded file name do: */
666 for (j
= 0; j
< numFiles
; ++j
) {
667 if (ParseFilename(nameList
[j
], filename
, pathname
) == 0) {
668 /* determine if file is to be openned in new tab, by
669 factoring the options -group, -tabbed & -untabbed */
671 isTabbed
= 0; /* start a new window for new group */
672 group
= 1; /* next file will be within group */
673 } else if (group
== 1) {
674 isTabbed
= 1; /* new tab for file in group */
675 } else { /* not in group */
676 isTabbed
= tabbed
==-1? GetPrefOpenInTab() : tabbed
;
679 /* Files are opened in background to improve opening speed
680 by defering certain time consuiming task such as syntax
681 highlighting. At the end of the file-opening loop, the
682 last file opened will be raised to restore those deferred
683 items. The current file may also be raised if there're
684 macros to execute on. */
685 window
= EditExistingFile(WindowList
, filename
, pathname
,
686 editFlags
, geometry
, iconic
, langMode
, isTabbed
,
688 fileSpecified
= TRUE
;
691 CleanUpTabBarExposeQueue(window
);
693 /* raise the last file of previous window */
694 if (lastFile
&& window
->shell
!= lastFile
->shell
) {
695 CleanUpTabBarExposeQueue(lastFile
);
696 RaiseDocument(lastFile
);
699 if (!macroFileRead
) {
700 ReadMacroInitFile(WindowList
);
701 macroFileRead
= True
;
704 SelectNumberedLine(window
, lineNum
);
705 if (toDoCommand
!= NULL
) {
706 DoMacro(window
, toDoCommand
, "-do macro");
708 if (!IsValidWindow(window
))
709 window
= NULL
; /* window closed by macro */
710 if (lastFile
&& !IsValidWindow(lastFile
))
711 lastFile
= NULL
; /* window closed by macro */
715 /* register last opened file for later use */
719 fprintf(stderr
, "nedit: file name too long: %s\n", nameList
[j
]);
723 if (nameList
!= NULL
)
726 if (ParseFilename(argv
[i
], filename
, pathname
) == 0 ) {
727 /* determine if file is to be openned in new tab, by
728 factoring the options -group, -tabbed & -untabbed */
730 isTabbed
= 0; /* start a new window for new group */
731 group
= 1; /* next file will be within group */
732 } else if (group
== 1) {
733 isTabbed
= 1; /* new tab for file in group */
734 } else { /* not in group */
735 isTabbed
= tabbed
==-1? GetPrefOpenInTab() : tabbed
;
738 /* Files are opened in background to improve opening speed
739 by defering certain time consuiming task such as syntax
740 highlighting. At the end of the file-opening loop, the
741 last file opened will be raised to restore those deferred
742 items. The current file may also be raised if there're
743 macros to execute on. */
744 window
= EditExistingFile(WindowList
, filename
, pathname
,
745 editFlags
, geometry
, iconic
, langMode
, isTabbed
, True
);
746 fileSpecified
= TRUE
;
748 CleanUpTabBarExposeQueue(window
);
750 /* raise the last tab of previous window */
751 if (lastFile
&& window
->shell
!= lastFile
->shell
) {
752 CleanUpTabBarExposeQueue(lastFile
);
753 RaiseDocument(lastFile
);
756 if (!macroFileRead
) {
757 ReadMacroInitFile(WindowList
);
758 macroFileRead
= True
;
761 SelectNumberedLine(window
, lineNum
);
762 if (toDoCommand
!= NULL
) {
763 DoMacro(window
, toDoCommand
, "-do macro");
765 if (!IsValidWindow(window
))
766 window
= NULL
; /* window closed by macro */
767 if (lastFile
&& !IsValidWindow(lastFile
))
768 lastFile
= NULL
; /* window closed by macro */
772 /* register last opened file for later use */
776 fprintf(stderr
, "nedit: file name too long: %s\n", argv
[i
]);
785 /* Raise the last file opened */
787 CleanUpTabBarExposeQueue(lastFile
);
788 RaiseDocument(lastFile
);
792 /* If no file to edit was specified, open a window to edit "Untitled" */
793 if (!fileSpecified
) {
794 EditNewFile(NULL
, geometry
, iconic
, langMode
, NULL
);
795 ReadMacroInitFile(WindowList
);
797 if (toDoCommand
!= NULL
)
798 DoMacro(WindowList
, toDoCommand
, "-do macro");
801 /* Begin remembering last command invoked for "Repeat" menu item */
802 AddLastCommandActionHook(context
);
804 /* Set up communication port and write ~/.nedit_server_process file */
806 InitServerCommunication();
808 /* Process events. */
810 ServerMainLoop(context
);
812 XtAppMainLoop(context
);
814 /* Not reached but this keeps some picky compilers happy */
818 static void nextArg(int argc
, char **argv
, int *argIndex
)
820 if (*argIndex
+ 1 >= argc
) {
822 *argv
[*argIndex
] = '/';
824 fprintf(stderr
, "NEdit: %s requires an argument\n%s", argv
[*argIndex
],
832 ** Return True if -do macro is valid, otherwise write an error on stderr
834 static int checkDoMacroArg(const char *macro
)
837 char *errMsg
, *stoppedAt
, *tMacro
;
840 /* Add a terminating newline (which command line users are likely to omit
841 since they are typically invoking a single routine) */
842 macroLen
= strlen(macro
);
843 tMacro
= XtMalloc(strlen(macro
)+2);
844 strncpy(tMacro
, macro
, macroLen
);
845 tMacro
[macroLen
] = '\n';
846 tMacro
[macroLen
+1] = '\0';
848 /* Do a test parse */
849 prog
= ParseMacro(tMacro
, &errMsg
, &stoppedAt
);
852 ParseError(NULL
, tMacro
, stoppedAt
, "argument to -do", errMsg
);
860 ** maskArgvKeywords and unmaskArgvKeywords mangle selected keywords by
861 ** replacing the '-' with a space, for the purpose of hiding them from
862 ** XtOpenDisplay's option processing. Why this silly scheme? XtOpenDisplay
863 ** really needs to see command line arguments, particularly -display, but
864 ** there's no way to change the option processing table it uses, to keep
865 ** it from consuming arguments which are meant to apply per-window, like
866 ** -geometry and -iconic.
868 static void maskArgvKeywords(int argc
, char **argv
, const char **maskArgs
)
872 for (i
=1; i
<argc
; i
++)
873 for (k
=0; maskArgs
[k
]!=NULL
; k
++)
874 if (!strcmp(argv
[i
], maskArgs
[k
]))
879 static void unmaskArgvKeywords(int argc
, char **argv
, const char **maskArgs
)
883 for (i
=1; i
<argc
; i
++)
884 for (k
=0; maskArgs
[k
]!=NULL
; k
++)
885 if (argv
[i
][0]==' ' && !strcmp(&argv
[i
][1], &maskArgs
[k
][1]))
891 ** Some Linux distros ship with XKEYSYMDB set to a bogus filename which
892 ** breaks all Motif applications. Ignore that, and let X fall back on the
893 ** default which is far more likely to work.
895 static void fixupBrokenXKeysymDB(void)
897 const char *keysym
= getenv("XKEYSYMDB");
899 if (keysym
!= NULL
&& access(keysym
, F_OK
) != 0)
904 ** If we're not using the default visual, then some default resources in
905 ** the database (colors) are not valid, because they are indexes into the
906 ** default colormap. If we used them blindly, then we'd get "random"
907 ** unreadable colors. So we inspect the resource list, and use the
908 ** fallback "grey" color instead if this is the case.
910 static void patchResourcesForVisual(void)
916 Boolean usingDefaultVisual
;
922 db
= XtDatabase(TheDisplay
);
924 usingDefaultVisual
= FindBestVisual(TheDisplay
,
931 if (!usingDefaultVisual
)
933 #ifndef LESSTIF_VERSION
935 For non-Lesstif versions, we have to put non-default visuals etc.
936 in the resource data base to make sure that all (shell) widgets
937 inherit them, especially Motif's own shells (eg, drag icons).
939 For Lesstif, this doesn't work, but luckily, Lesstif handles
940 non-default visuals etc. properly for its own shells and
941 we can take care of things for our shells (eg, call tips) through
942 our shell creation wrappers in misc.c.
946 value
.addr
= (XPointer
)&visual
;
947 value
.size
= sizeof(visual
);
948 XrmPutResource(&db
, "*visual", "Visual", &value
);
949 value
.addr
= (XPointer
)&map
;
950 value
.size
= sizeof(map
);
951 XrmPutResource(&db
, "*colormap", "Colormap", &value
);
952 value
.addr
= (XPointer
)&depth
;
953 value
.size
= sizeof(depth
);
954 XrmPutResource(&db
, "*depth", "Int", &value
);
956 /* Drag-and-drop visuals do not work well when using a different
957 visual. One some systems, you'll just get a funny-looking icon
958 (maybe all-black) but on other systems it crashes with a BadMatch
959 error. This appears to be an OSF Motif bug. It would be nicer
960 to just disable the visual itself, instead of the entire drag
963 Update: this is no longer necessary since all problems with
964 non-default visuals should now be solved.
966 XrmPutStringResource(&db, "*dragInitiatorProtocolStyle", "DRAG_NONE");
970 for (i
= 1; i
< XtNumber(fallbackResources
); ++i
)
972 Cardinal resIndex
= i
- 1;
974 if (strstr(fallbackResources
[resIndex
], "*background:") ||
975 strstr(fallbackResources
[resIndex
], "*foreground:"))
977 /* Qualify by application name to prevent them from being
978 converted against the wrong colormap. */
979 char buf
[1024] = "*" APP_NAME
;
980 strcat(buf
, fallbackResources
[resIndex
]);
981 XrmPutLineResource(&db
, buf
);
988 ** Several KDE version (2.x and 3.x) ship with a template application-default
989 ** file for NEdit in which several strings have to be substituted in order to
990 ** make it a valid .ad file. However, for some reason (a KDE bug?), the
991 ** template sometimes ends up in the resource db unmodified, such that several
992 ** invalid entries are present. This function checks for the presence of such
993 ** invalid entries and silently replaces them with NEdit's default values where
994 ** necessary. Without this, NEdit will typically write several warnings to
995 ** the terminal (Cannot convert string "FONTLIST" to type FontStruct etc) and
996 ** fall back on some really ugly colors and fonts.
998 static void patchResourcesForKDEbug(void)
1001 * These are the resources found the Nedit.ad template shipped with KDE 3.0.
1003 static const char* buggyResources
[][3] = {
1004 { "*fontList", "FONTLIST", NEDIT_DEFAULT_FONT
},
1005 { "*XmText.background", "BACKGROUND", NEDIT_DEFAULT_TEXT_BG
},
1006 { "*XmText.foreground", "FOREGROUND", NEDIT_DEFAULT_FG
},
1007 { "*XmTextField.background", "BACKGROUND", NEDIT_DEFAULT_TEXT_BG
},
1008 { "*XmTextField.foreground", "FOREGROUND", NEDIT_DEFAULT_FG
},
1009 { "*XmList.background", "BACKGROUND", NEDIT_DEFAULT_TEXT_BG
},
1010 { "*XmList.foreground", "FOREGROUND", NEDIT_DEFAULT_FG
},
1011 { "*helpText.background", "BACKGROUND", NEDIT_DEFAULT_HELP_BG
},
1012 { "*helpText.foreground", "FOREGROUND", NEDIT_DEFAULT_HELP_FG
},
1013 { "*background", "BACKGROUND", NEDIT_DEFAULT_BG
},
1014 { "*foreground", "FOREGROUND", NEDIT_DEFAULT_FG
, },
1015 { "*selectColor", "BACKGROUND", NEDIT_DEFAULT_SEL_BG
},
1016 { "*highlightColor", "BACKGROUND", NEDIT_DEFAULT_HI_BG
},
1017 { "*text.background", "WINDOW_BACKGROUND", NEDIT_DEFAULT_TEXT_BG
},
1018 { "*text.foreground", "WINDOW_FOREGROUND", NEDIT_DEFAULT_FG
},
1019 { "*text.selectBackground", "SELECT_BACKGROUND", NEDIT_DEFAULT_SEL_BG
},
1020 { "*text.selectForeground", "SELECT_FOREGROUND", NEDIT_DEFAULT_SEL_FG
},
1021 { "*text.cursorForeground", "WINDOW_FOREGROUND", NEDIT_DEFAULT_CURSOR_FG
},
1022 /* { "*remapDeleteKey", "False", }, OK */
1023 /* { "!*text.heavyCursor", "True" }, OK */
1024 /* { "!*BlinkRate", "0" }, OK */
1025 /* { "*shell", "/bin/sh" }, OK */
1026 { "*statsLine.background", "BACKGROUND", NEDIT_DEFAULT_BG
},
1027 { "*statsLine.foreground", "FOREGROUND", NEDIT_DEFAULT_FG
},
1028 { NULL
, NULL
, NULL
} };
1035 db
= XtDatabase(TheDisplay
);
1038 while (buggyResources
[i
][0])
1040 const char* resource
= buggyResources
[i
][0];
1041 const char* buggyValue
= buggyResources
[i
][1];
1042 const char* defaultValue
= buggyResources
[i
][2];
1043 char name
[128] = APP_NAME
;
1044 char class[128] = APP_CLASS
;
1048 strcat(name
, resource
);
1049 strcat(class, resource
); /* Is this ok ? */
1051 if (XrmGetResource(db
, name
, class, &type
, &resValue
) &&
1052 !strcmp(type
, XmRString
))
1054 /* Buggy value? Replace by the default. */
1055 if (!strcmp(resValue
.addr
, buggyValue
))
1057 XrmPutStringResource(&db
, &name
[0], (char*)defaultValue
);
1065 ** It seems OSF Motif cannot handle locales with UTF-8 at the end, crashing
1066 ** in various places. The easiest one to find is to open the File Open
1067 ** dialog box. So we lop off UTF-8 if it's there and continue. Newer
1068 ** versions of Linux distros (e.g., RedHat 8) set the default language to
1069 ** to have "UTF-8" at the end, so users were seeing these crashes.
1071 ** LessTif and OpenMotif 2.3 don't appear to have this problem.
1073 ** Some versions OpenMotif 2.2.3 don't have this problem, but there's
1074 ** no way to tell which.
1077 static void patchLocaleForMotif(void)
1079 #if !(defined(LESSTIF_VERSION) || XmVersion >= 2003)
1081 char ctypebuf
[1024];
1084 /* We have to check LC_CTYPE specifically here, because the system
1085 might specify different locales for different categories (why
1086 anyone would want to do this is beyond me). As far as I can
1087 tell, only LC_CTYPE causes OSF Motif to crash. If it turns out
1088 others do, we'll have to iterate over a list of locale cateogries
1089 and patch every one of them. */
1091 ctype
= setlocale(LC_CTYPE
, NULL
);
1096 strncpy(ctypebuf
, ctype
, sizeof ctypebuf
);
1098 if ((utf_start
= strstr(ctypebuf
, ".utf8")) ||
1099 (utf_start
= strstr(ctypebuf
, ".UTF-8")))
1101 *utf_start
= '\0'; /* Samurai chop */
1102 setlocale(LC_CTYPE
, ctypebuf
);
1109 ** Same as the default X language procedure, except we check if Motif can
1110 ** handle the locale as well.
1113 static String
neditLanguageProc(Display
*dpy
, String xnl
, XtPointer closure
)
1115 /* "xnl" will be set if the user passes in a new language via the
1116 "-xnllanguage" flag. If it's empty, then setlocale will get
1117 the default locale by some system-dependent means (usually,
1118 reading some environment variables). */
1120 if (! setlocale(LC_ALL
, xnl
)) {
1121 XtWarning("locale not supported by C library, locale unchanged");
1124 patchLocaleForMotif();
1126 if (! XSupportsLocale()) {
1127 XtWarning("locale not supported by Xlib, locale set to C");
1128 setlocale(LC_ALL
, "C");
1130 if (! XSetLocaleModifiers(""))
1131 XtWarning("X locale modifiers not supported, using default");
1133 return setlocale(LC_ALL
, NULL
); /* re-query in case overwritten */
1136 static int sortAlphabetical(const void* k1
, const void* k2
)
1138 const char* key1
= *(const char**)k1
;
1139 const char* key2
= *(const char**)k2
;
1140 return strcmp(key1
, key2
);
1144 * Checks whether a given virtual key binding string is invalid.
1145 * A binding is considered invalid if there are duplicate key entries.
1147 static int virtKeyBindingsAreInvalid(const unsigned char* bindings
)
1149 int maxCount
= 1, i
, count
;
1150 const char *pos
= (const char*)bindings
;
1155 /* First count the number of bindings; bindings are separated by \n
1156 strings. The number of bindings equals the number of \n + 1.
1157 Beware of leading and trailing \n; the number is actually an
1158 upper bound on the number of entries. */
1159 while ((pos
= strstr(pos
, "\n")))
1166 return False
; /* One binding is always ok */
1168 keys
= (char**)malloc(maxCount
*sizeof(char*));
1169 copy
= XtNewString((const char*)bindings
);
1174 while (i
<maxCount
&& pos2
&& *pos2
)
1176 while (isspace((int) *pos2
) || *pos2
== '\n') ++pos2
;
1178 if (*pos2
== '!') /* Ignore comment lines */
1180 pos2
= strstr(pos2
, "\n");
1181 continue; /* Go to the next line */
1188 pos3
= strstr(pos2
, ":");
1191 *pos3
++ = 0; /* Cut the string and jump to the next entry */
1194 pos2
= strstr(pos2
, "\n");
1202 return False
; /* No conflict */
1205 /* Sort the keys and look for duplicates */
1206 qsort((void*)keys
, count
, sizeof(const char*), sortAlphabetical
);
1207 for (i
=1; i
<count
; ++i
)
1209 if (!strcmp(keys
[i
-1], keys
[i
]))
1211 /* Duplicate detected */
1223 * Optionally sanitizes the Motif default virtual key bindings.
1224 * Some applications install invalid bindings (attached to the root window),
1225 * which cause certain keys to malfunction in NEdit.
1226 * Through an X-resource, users can choose whether they want
1227 * - to always keep the existing bindings
1228 * - to override the bindings only if they are invalid
1229 * - to always override the existing bindings.
1232 static Atom virtKeyAtom
;
1234 static unsigned char* sanitizeVirtualKeyBindings(void)
1236 int overrideBindings
= GetPrefOverrideVirtKeyBindings();
1238 const char *virtKeyPropName
= "_MOTIF_DEFAULT_BINDINGS";
1241 unsigned long dummyULong
, nItems
;
1242 unsigned char *insaneVirtKeyBindings
= NULL
;
1244 if (overrideBindings
== VIRT_KEY_OVERRIDE_NEVER
) return NULL
;
1246 virtKeyAtom
= XInternAtom(TheDisplay
, virtKeyPropName
, False
);
1247 rootWindow
= RootWindow(TheDisplay
, DefaultScreen(TheDisplay
));
1249 /* Remove the property, if it exists; we'll restore it later again */
1250 if (XGetWindowProperty(TheDisplay
, rootWindow
, virtKeyAtom
, 0, INT_MAX
,
1251 True
, XA_STRING
, &dummyAtom
, &getFmt
, &nItems
,
1252 &dummyULong
, &insaneVirtKeyBindings
) != Success
1255 return NULL
; /* No binding yet; nothing to do */
1258 if (overrideBindings
== VIRT_KEY_OVERRIDE_AUTO
)
1260 if (!virtKeyBindingsAreInvalid(insaneVirtKeyBindings
))
1262 /* Restore the property immediately; it seems valid */
1263 XChangeProperty(TheDisplay
, rootWindow
, virtKeyAtom
, XA_STRING
, 8,
1264 PropModeReplace
, insaneVirtKeyBindings
,
1265 strlen((const char*)insaneVirtKeyBindings
));
1266 XFree((char*)insaneVirtKeyBindings
);
1267 return NULL
; /* Prevent restoration */
1270 return insaneVirtKeyBindings
;
1274 * NEdit should not mess with the bindings installed by other apps, so we
1275 * just restore whatever was installed, if necessary
1277 static void restoreInsaneVirtualKeyBindings(unsigned char *insaneVirtKeyBindings
)
1279 if (insaneVirtKeyBindings
)
1281 Window rootWindow
= RootWindow(TheDisplay
, DefaultScreen(TheDisplay
));
1282 /* Restore the root window atom, such that we don't affect
1284 XChangeProperty(TheDisplay
, rootWindow
, virtKeyAtom
, XA_STRING
, 8,
1285 PropModeReplace
, insaneVirtKeyBindings
,
1286 strlen((const char*)insaneVirtKeyBindings
));
1287 XFree((char*)insaneVirtKeyBindings
);
1292 ** Warning handler that suppresses harmless but annoying warnings generated
1293 ** by non-production Lesstif versions.
1295 static void showWarningFilter(String message
)
1297 const char* bogusMessages
[] = {
1298 #ifdef LESSTIF_VERSION
1299 "XmFontListCreate() is an obsolete function!",
1300 "No type converter registered for 'String' to 'PathMode' conversion.",
1301 "XtRemoveGrab asked to remove a widget not on the list",
1305 const char **bogusMessage
= &bogusMessages
[0];
1307 while (*bogusMessage
) {
1308 size_t bogusLen
= strlen(*bogusMessage
);
1309 if (strncmp(message
, *bogusMessage
, bogusLen
) == 0) {
1310 #ifdef DEBUG_LESSTIF_WARNINGS
1311 /* Developers may want to see which messages are suppressed. */
1312 fprintf(stderr
, "[SUPPRESSED] %s\n", message
);
1319 /* An unknown message. Keep it. */
1320 fprintf(stderr
, "%s\n", message
);
1323 static void noWarningFilter(String message
)