Merge commit 'origin'
[nedit-bw.git] / macro_hooks.patch
blobd1263f98b092f1d4622f8640a25898b0a6b1b430
1 From: Thorsten Haude <yoo@vranx.de>
2 Subject: macro hooks
4 The following hooks are present:
6 * pre_open_hook
7 * post_open_hook
8 * pre_save_hook
9 * post_save_hook
10 * cursor_moved_hook
11 * modified_hook
12 * focus_hook
13 * losing_focus_hook
15 ---
17 doc/help.etx | 46 ++++++++++++++++++++++++++++++
18 source/Makefile.dependencies | 6 +--
19 source/file.c | 18 +++++++++++
20 source/highlightData.c | 1
21 source/macro.c | 63 ++++++++++++++++++++++++++++++++++++++++-
22 source/macro.h | 3 +
23 source/menu.c | 28 +++++++++++++++++-
24 source/nedit.c | 24 +++++----------
25 source/nedit.h | 1
26 source/selection.c | 65 ++++++++++++++++++++++++++++++++++---------
27 source/window.c | 28 ++++++++++++++++++
28 11 files changed, 247 insertions(+), 36 deletions(-)
30 diff --quilt old/doc/help.etx new/doc/help.etx
31 --- old/doc/help.etx
32 +++ new/doc/help.etx
33 @@ -3748,6 +3748,51 @@ Action Routines
34 To be attached to a key-press event, inserts the character
35 equivalent of the key pressed.
38 +Hooks
39 +-----
41 + Hooks are macro routines which are called at specific points in NEdit's
42 + execution. You can use hooks to tie in user-defined functionality at these
43 + points.
45 + No hooks are provided. To use a hook, simply define a macro function with
46 + the name of the hook. The next time the hook will catch, the macro function
47 + is called.
49 + You don't have to provide any hook. If a certain hook does not exist, it is
50 + simply skipped.
52 +**pre_open_hook(~filename~)**
53 + Called before NEdit opens a file using a certain name. The parameter is
54 + the filename NEdit intends to open.
56 + Return a string to use instead of the original filename. Return 0 to tell
57 + NEdit to use the original filename.
59 +**post_open_hook()**
60 + Called when an existing file is opened.
62 +**pre_save_hook()**
63 + Called before a file will be save saved.
65 + Return a string to use this as the file name.
67 +**post_save_hook()**
68 + Called after an file was saved.
70 +**cursor_moved_hook()**
71 + Called when the was cursor moved.
73 +**modified_hook()**
74 + Called when the text buffer changed.
76 +**focus_hook()**
77 + Called when a document gets the input focus.
79 +**losing_focus_hook()**
80 + Called before a document lost the input focus.
82 ----------------------------------------------------------------------
84 Customizing
85 @@ -6036,6 +6081,7 @@ Problems/Defects
86 .. Menu: Rangesets # rangeset
87 .. Menu: Highlighting Information # hiliteInfo
88 .. Menu: Action Routines # actions
89 +.. Menu: H_o_oks # hooks
91 .. Menu: Customizing # customizing
92 .. Menu: Customizing NEdit # customize
93 diff --quilt old/source/Makefile.dependencies new/source/Makefile.dependencies
94 --- old/source/Makefile.dependencies
95 +++ new/source/Makefile.dependencies
96 @@ -4,7 +4,7 @@ calltips.o: calltips.c text.h textBuf.h
97 file.o: file.c file.h nedit.h textBuf.h text.h window.h preferences.h \
98 undo.h menu.h tags.h server.h ../util/misc.h ../util/DialogF.h \
99 ../util/fileUtils.h ../util/getfiles.h ../util/printUtils.h \
100 - ../util/utils.h
101 + ../util/utils.h macro.h
102 help.o: help.c help.h help_topic.h textBuf.h text.h textP.h textDisp.h \
103 textSel.h nedit.h search.h window.h preferences.h help_data.h file.h \
104 highlight.h ../util/misc.h ../util/DialogF.h ../util/system.h
105 @@ -41,7 +41,7 @@ preferences.o: preferences.c preferences
106 help_topic.h regularExp.h smartIndent.h windowTitle.h server.h tags.h \
107 ../util/prefFile.h ../util/misc.h ../util/DialogF.h \
108 ../util/managedList.h ../util/fontsel.h ../util/fileUtils.h \
109 - ../util/utils.h ../util/clearcase.h
110 + ../util/utils.h ../util/clearcase.h macro.h
111 rangeset.o: rangeset.c textBuf.h textDisp.h rangeset.h
112 rbTree.o: rbTree.c rbTree.h
113 regexConvert.o: regexConvert.c regexConvert.h
114 @@ -50,7 +50,7 @@ search.o: search.c search.h nedit.h text
115 server.h window.h preferences.h file.h highlight.h ../util/DialogF.h \
116 ../util/misc.h
117 selection.o: selection.c selection.h nedit.h textBuf.h text.h file.h \
118 - window.h menu.h server.h ../util/DialogF.h ../util/fileUtils.h
119 + window.h menu.h server.h ../util/DialogF.h ../util/fileUtils.h macro.h
120 server.o: server.c server.h window.h nedit.h textBuf.h file.h selection.h \
121 macro.h menu.h preferences.h server_common.h ../util/fileUtils.h \
122 ../util/utils.h
123 diff --quilt old/source/file.c new/source/file.c
124 --- old/source/file.c
125 +++ new/source/file.c
126 @@ -41,6 +41,7 @@ static const char CVSID[] = "$Id: file.c
127 #include "tags.h"
128 #include "server.h"
129 #include "interpret.h"
130 +#include "macro.h"
131 #include "../util/misc.h"
132 #include "../util/DialogF.h"
133 #include "../util/fileUtils.h"
134 @@ -272,6 +273,8 @@ WindowInfo *EditExistingFile(WindowInfo
135 AddRelTagsFile(GetPrefTagFile(), path, TAG);
136 AddToPrevOpenMenu(fullname);
138 + MacroApplyHook(window, "post_open_hook", 0, NULL, NULL);
140 return window;
143 @@ -932,6 +935,18 @@ static int doSave(WindowInfo *window)
144 struct stat statbuf;
145 FILE *fp;
146 int fileLen, result;
147 + DataValue hookResult = {NO_TAG,{0}};
148 + Boolean success;
150 + /* call the "pre_save_hook", if the macro returns a string, interpret this
151 + as the new filename */
152 + success = MacroApplyHook(window, "pre_save_hook", 0, NULL, &hookResult);
153 + if (success && hookResult.tag == STRING_TAG) {
154 + if (ParseFilename(hookResult.val.str.rep,
155 + window->filename, window->path)) {
156 + return FALSE;
160 /* Get the full name of the file */
161 strcpy(fullname, window->path);
162 @@ -1069,6 +1084,9 @@ static int doSave(WindowInfo *window)
163 window->inode = 0;
166 + /* call "post_save_hook" */
167 + MacroApplyHook(window, "post_save_hook", 0, NULL, NULL);
169 return TRUE;
172 diff --quilt old/source/highlightData.c new/source/highlightData.c
173 --- old/source/highlightData.c
174 +++ new/source/highlightData.c
175 @@ -554,6 +554,7 @@ static char *DefaultPatternSets[] = {
176 Built-in Subrs:\"<(?:args|append_file|beep|call|calltip|clipboard_to_string|dialog|filename_dialog|focus_window|get_character|get_pattern_(by_name|at_pos)|get_range|get_selection|get_style_(by_name|at_pos)|getenv|highlight_calltip_line|kill_calltip|length|list_dialog|max|min|n_args|rangeset_(?:add|create|destroy|get_by_name|includes|info|invert|range|set_color|set_mode|set_name|subtract)|read_file|replace_in_string|replace_range|replace_selection|replace_substring|search|search_string|select|select_rectangle|set_cursor_pos|shell_command|split|string_compare|string_dialog|string_to_clipboard|substring|t_print|tolower|toupper|valid_number|write_file)(?=\\s*\\()\":::Subroutine::\n\
177 Menu Actions:\"<(?:new(?:_tab|_opposite)?|open|open-dialog|open_dialog|open-selected|open_selected|close|save|save-as|save_as|save-as-dialog|save_as_dialog|revert-to-saved|revert_to_saved|revert_to_saved_dialog|include-file|include_file|include-file-dialog|include_file_dialog|load-macro-file|load_macro_file|load-macro-file-dialog|load_macro_file_dialog|load-tags-file|load_tags_file|load-tags-file-dialog|load_tags_file_dialog|unload_tags_file|load_tips_file|load_tips_file_dialog|unload_tips_file|print|print-selection|print_selection|exit|undo|redo|delete|select-all|select_all|shift-left|shift_left|shift-left-by-tab|shift_left_by_tab|shift-right|shift_right|shift-right-by-tab|shift_right_by_tab|find|find-dialog|find_dialog|find-again|find_again|find-selection|find_selection|find_incremental|start_incremental_find|replace|replace-dialog|replace_dialog|replace-all|replace_all|replace-in-selection|replace_in_selection|replace-again|replace_again|replace_find|replace_find_same|replace_find_again|goto-line-number|goto_line_number|goto-line-number-dialog|goto_line_number_dialog|goto-selected|goto_selected|mark|mark-dialog|mark_dialog|goto-mark|goto_mark|goto-mark-dialog|goto_mark_dialog|match|select_to_matching|goto_matching|find-definition|find_definition|show_tip|split-pane|split_pane|close-pane|close_pane|detach_document(?:_dialog)?|move_document_dialog|(?:next|previous|last)_document|uppercase|lowercase|fill-paragraph|fill_paragraph|control-code-dialog|control_code_dialog|filter-selection-dialog|filter_selection_dialog|filter-selection|filter_selection|execute-command|execute_command|execute-command-dialog|execute_command_dialog|execute-command-line|execute_command_line|shell-menu-command|shell_menu_command|macro-menu-command|macro_menu_command|bg_menu_command|post_window_bg_menu|post_tab_context_menu|beginning-of-selection|beginning_of_selection|end-of-selection|end_of_selection|repeat_macro|repeat_dialog|raise_window|focus_pane|set_statistics_line|set_incremental_search_line|set_show_line_numbers|set_auto_indent|set_wrap_text|set_wrap_margin|set_highlight_syntax|set_make_backup_copy|set_incremental_backup|set_show_matching|set_match_syntax_based|set_overtype_mode|set_locked|set_tab_dist|set_em_tab_dist|set_use_tabs|set_fonts|set_language_mode)(?=\\s*\\()\":::Subroutine::\n\
178 Text Actions:\"<(?:self-insert|self_insert|grab-focus|grab_focus|extend-adjust|extend_adjust|extend-start|extend_start|extend-end|extend_end|secondary-adjust|secondary_adjust|secondary-or-drag-adjust|secondary_or_drag_adjust|secondary-start|secondary_start|secondary-or-drag-start|secondary_or_drag_start|process-bdrag|process_bdrag|move-destination|move_destination|move-to|move_to|move-to-or-end-drag|move_to_or_end_drag|end_drag|copy-to|copy_to|copy-to-or-end-drag|copy_to_or_end_drag|exchange|process-cancel|process_cancel|paste-clipboard|paste_clipboard|copy-clipboard|copy_clipboard|cut-clipboard|cut_clipboard|copy-primary|copy_primary|cut-primary|cut_primary|newline|newline-and-indent|newline_and_indent|newline-no-indent|newline_no_indent|delete-selection|delete_selection|delete-previous-character|delete_previous_character|delete-next-character|delete_next_character|delete-previous-word|delete_previous_word|delete-next-word|delete_next_word|delete-to-start-of-line|delete_to_start_of_line|delete-to-end-of-line|delete_to_end_of_line|forward-character|forward_character|backward-character|backward_character|key-select|key_select|process-up|process_up|process-down|process_down|process-shift-up|process_shift_up|process-shift-down|process_shift_down|process-home|process_home|forward-word|forward_word|backward-word|backward_word|forward-paragraph|forward_paragraph|backward-paragraph|backward_paragraph|beginning-of-line|beginning_of_line|end-of-line|end_of_line|beginning-of-file|beginning_of_file|end-of-file|end_of_file|next-page|next_page|previous-page|previous_page|page-left|page_left|page-right|page_right|toggle-overstrike|toggle_overstrike|scroll-up|scroll_up|scroll-down|scroll_down|scroll_left|scroll_right|scroll-to-line|scroll_to_line|select-all|select_all|deselect-all|deselect_all|focusIn|focusOut|process-return|process_return|process-tab|process_tab|insert-string|insert_string|mouse_pan)(?=\\s*\\()\":::Subroutine::\n\
179 + Macro Hooks:\"<(?:(?:pre|post)_(?:open|save)|cursor_moved|modified|(?:losing_)?focus)_hook(?=\\s*\\()\":::Subroutine1::\n\
180 Keyword:\"<(?:break|continue|define|delete|do|else|for|if|in|return|while)>\":::Keyword::\n\
181 Braces:\"[{}\\[\\]]\":::Keyword::\n\
182 Global Variable:\"\\$[A-Za-z0-9_]+\":::Identifier1::\n\
183 diff --quilt old/source/macro.c new/source/macro.c
184 --- old/source/macro.c
185 +++ new/source/macro.c
186 @@ -1213,8 +1213,10 @@ void SafeGC(void)
187 WindowInfo *win;
189 for (win=WindowList; win!=NULL; win=win->next)
190 - if (win->macroCmdData != NULL || InSmartIndentMacros(win))
191 - return;
192 + if (win->macroCmdData != NULL
193 + || InSmartIndentMacros(win)
194 + || win->inMacroHook)
195 + return;
196 GarbageCollectStrings();
199 @@ -6021,3 +6023,60 @@ static int readStringArg(DataValue dv, c
200 *errMsg = "%s called with unknown object";
201 return False;
205 +** call a macro function, if it exists, with the given arguments and store
206 +** the return value in resultDV.
208 +** Currently, only non-preemtable macros are supported.
210 +Boolean MacroApplyHook(WindowInfo *document, const char *hook, int argc,
211 + DataValue *argv, DataValue *resultDV)
213 + Symbol *hookSymbol;
214 + Boolean succ = False;
216 + hookSymbol = LookupSymbol(hook);
217 + if (NULL != hookSymbol && MACRO_FUNCTION_SYM == hookSymbol->type) {
218 + Program *hookProg = hookSymbol->value.val.prog;
219 + RestartData *restartData;
220 + DataValue dummyResultDV;
221 + DataValue *resultDVPtr = &dummyResultDV;
222 + int status;
223 + char *errMsg;
225 + /* ExecuteMacro() can't be called with a NULL resultDV, therefore the
226 + dummyResultDV */
227 + if (resultDV) {
228 + resultDVPtr = resultDV;
231 + /* prevent calling the GC */
232 + document->inMacroHook++;
234 + status = ExecuteMacro(document, hookProg, argc, argv,
235 + resultDVPtr, &restartData, &errMsg);
237 + while (MACRO_TIME_LIMIT == status) {
238 + status = ContinueMacro(restartData, resultDVPtr, &errMsg);
241 + document->inMacroHook--;
243 + /* call the GC only if the caller of this function is not interested
244 + in any result, else it may happen, that strings and arrays are swept
245 + away by the GC. */
246 + if (NULL == resultDV) {
247 + SafeGC();
250 + if (MACRO_PREEMPT == status || MACRO_ERROR == status) {
251 + fprintf(stderr, "nedit: \"%s\" error: %s\n", hook, (MACRO_ERROR == status) ? errMsg : "No dialogs");
252 + } else {
253 + /* Macro is done here without errors */
254 + succ = True;
258 + return succ;
260 diff --quilt old/source/macro.h new/source/macro.h
261 --- old/source/macro.h
262 +++ new/source/macro.h
263 @@ -73,5 +73,8 @@ int CheckMacroString(Widget dialogParent
264 char *GetReplayMacro(void);
265 void ReadMacroInitFile(WindowInfo *window);
266 void ReturnShellCommandOutput(WindowInfo *window, const char *outText, int status);
267 +struct DataValueTag;
268 +Boolean MacroApplyHook(WindowInfo *document, const char *hook, int argc,
269 + struct DataValueTag *argv, struct DataValueTag *resultDV);
271 #endif /* NEDIT_MACRO_H_INCLUDED */
272 diff --quilt old/source/menu.c new/source/menu.c
273 --- old/source/menu.c
274 +++ new/source/menu.c
275 @@ -2849,19 +2849,43 @@ static void openAP(Widget w, XEvent *eve
277 WindowInfo *window = WidgetToWindow(w);
278 char filename[MAXPATHLEN], pathname[MAXPATHLEN];
279 + DataValue fileNameArg;
280 + DataValue resultDV = {NO_TAG, {0}};
281 + Boolean hook_successful = False;
282 + char *fileNameToOpen;
284 if (*nArgs == 0) {
285 fprintf(stderr, "nedit: open action requires file argument\n");
286 return;
288 - if (0 != ParseFilename(args[0], filename, pathname)
290 + /* call "pre_open_hook", use the returned string as the filename to open.
291 + The macro is not executed in the new window. */
292 + fileNameArg.tag = STRING_TAG;
293 + AllocNStringNCpy(&fileNameArg.val.str, args[0], MAXPATHLEN);
294 + hook_successful = MacroApplyHook(window, "pre_open_hook",
295 + 1, &fileNameArg, &resultDV);
297 + if (hook_successful && resultDV.tag == STRING_TAG) {
298 + fileNameToOpen = resultDV.val.str.rep;
299 + } else {
300 + fileNameToOpen = args[0];
303 + if (0 != ParseFilename(fileNameToOpen, filename, pathname)
304 || strlen(filename) + strlen(pathname) > MAXPATHLEN - 1) {
305 fprintf(stderr, "nedit: invalid file name for open action: %s\n",
306 - args[0]);
307 + fileNameToOpen);
308 return;
311 + /* we call the GC, because the "pre_open_hook" argument and possible
312 + return value are strings */
313 + SafeGC();
315 EditExistingFile(window, filename, pathname, 0, NULL, False,
316 NULL, GetPrefOpenInTab(), False);
318 CheckCloseDim();
321 diff --quilt old/source/nedit.c new/source/nedit.c
322 --- old/source/nedit.c
323 +++ new/source/nedit.c
324 @@ -388,7 +388,7 @@ static const char cmdLineHelp[] =
325 int main(int argc, char **argv)
327 int i, lineNum, nRead, fileSpecified = FALSE, editFlags = CREATE;
328 - int gotoLine = False, macroFileRead = False, opts = True;
329 + int gotoLine = False, opts = True;
330 int iconic=False, tabbed = -1, group = 0, isTabbed;
331 char *toDoCommand = NULL, *geometry = NULL, *langMode = NULL;
332 char filename[MAXPATHLEN], pathname[MAXPATHLEN];
333 @@ -567,6 +567,10 @@ int main(int argc, char **argv)
334 IsServer = True;
337 + EditNewFile(NULL, geometry, iconic, langMode, NULL);
338 + ReadMacroInitFile(WindowList);
339 + CheckCloseDim();
341 /* Process any command line arguments (-tags, -do, -read, -create,
342 +<line_number>, -line, -server, and files to edit) not already
343 processed by RestoreNEditPrefs. */
344 @@ -682,10 +686,6 @@ int main(int argc, char **argv)
345 RaiseDocument(lastFile);
348 - if (!macroFileRead) {
349 - ReadMacroInitFile(WindowList);
350 - macroFileRead = True;
352 if (gotoLine)
353 SelectNumberedLine(window, lineNum);
354 if (toDoCommand != NULL) {
355 @@ -739,10 +739,6 @@ int main(int argc, char **argv)
356 RaiseDocument(lastFile);
359 - if (!macroFileRead) {
360 - ReadMacroInitFile(WindowList);
361 - macroFileRead = True;
363 if (gotoLine)
364 SelectNumberedLine(window, lineNum);
365 if (toDoCommand != NULL) {
366 @@ -775,13 +771,9 @@ int main(int argc, char **argv)
368 CheckCloseDim();
370 - /* If no file to edit was specified, open a window to edit "Untitled" */
371 - if (!fileSpecified) {
372 - EditNewFile(NULL, geometry, iconic, langMode, NULL);
373 - ReadMacroInitFile(WindowList);
374 - CheckCloseDim();
375 - if (toDoCommand != NULL)
376 - DoMacro(WindowList, toDoCommand, "-do macro");
377 + /* If no file to edit was specified, do at least the -do macro */
378 + if (!fileSpecified && toDoCommand != NULL) {
379 + DoMacro(WindowList, toDoCommand, "-do macro");
382 /* Begin remembering last command invoked for "Repeat" menu item */
383 diff --quilt old/source/nedit.h new/source/nedit.h
384 --- old/source/nedit.h
385 +++ new/source/nedit.h
386 @@ -566,6 +566,7 @@ typedef struct _WindowInfo {
387 UserBGMenuCache userBGMenuCache; /* shell & macro menu are shared over all
388 "tabbed" documents, while each document
389 has its own background menu. */
390 + int inMacroHook; /* to protect GC in MacroApplyHook() */
391 } WindowInfo;
393 extern WindowInfo *WindowList;
394 diff --quilt old/source/selection.c new/source/selection.c
395 --- old/source/selection.c
396 +++ new/source/selection.c
397 @@ -38,6 +38,8 @@ static const char CVSID[] = "$Id: select
398 #include "menu.h"
399 #include "preferences.h"
400 #include "server.h"
401 +#include "interpret.h"
402 +#include "macro.h"
403 #include "../util/DialogF.h"
404 #include "../util/fileUtils.h"
406 @@ -338,14 +340,32 @@ static void fileCB(Widget widget, Window
407 _XmOSGetDirEntries(pathname, filename, XmFILE_ANY_TYPE, False, True,
408 &nameList, &nFiles, &maxFiles);
409 for (i=0; i<nFiles; i++) {
410 - if (ParseFilename(nameList[i], filename, pathname) != 0) {
411 - XBell(TheDisplay, 0);
413 - else {
414 - EditExistingFile(window, filename, pathname, 0,
415 - NULL, False, NULL, GetPrefOpenInTab(), False);
417 + DataValue fileNameArg;
418 + DataValue resultDV = {NO_TAG, {0}};
419 + Boolean hook_successful = False;
420 + char *fileNameToOpen;
422 + fileNameArg.tag = STRING_TAG;
423 + AllocNStringNCpy(&fileNameArg.val.str, nameList[i],
424 + MAXPATHLEN);
425 + hook_successful = MacroApplyHook(window, "pre_open_hook",
426 + 1, &fileNameArg, &resultDV);
428 + if (hook_successful && resultDV.tag == STRING_TAG) {
429 + fileNameToOpen = resultDV.val.str.rep;
430 + } else {
431 + fileNameToOpen = nameList[i];
434 + if (ParseFilename(fileNameToOpen, filename, pathname) != 0) {
435 + XBell(TheDisplay, 0);
436 + } else {
437 + EditExistingFile(GetPrefOpenInTab() ? window : NULL, filename,
438 + pathname, 0, NULL, False, NULL, GetPrefOpenInTab(),
439 + False);
442 + SafeGC();
443 for (i=0; i<nFiles; i++) {
444 XtFree(nameList[i]);
446 @@ -357,13 +377,32 @@ static void fileCB(Widget widget, Window
448 glob(nameText, GLOB_NOCHECK, NULL, &globbuf);
449 for (i=0; i<(int)globbuf.gl_pathc; i++) {
450 - if (ParseFilename(globbuf.gl_pathv[i], filename, pathname) != 0)
451 - XBell(TheDisplay, 0);
452 - else
453 - EditExistingFile(GetPrefOpenInTab()? window : NULL,
454 - filename, pathname, 0, NULL, False, NULL,
455 - GetPrefOpenInTab(), False);
456 + DataValue fileNameArg;
457 + DataValue resultDV = {NO_TAG, {0}};
458 + Boolean hook_successful = False;
459 + char *fileNameToOpen;
461 + fileNameArg.tag = STRING_TAG;
462 + AllocNStringNCpy(&fileNameArg.val.str, globbuf.gl_pathv[i],
463 + MAXPATHLEN);
464 + hook_successful = MacroApplyHook(window, "pre_open_hook",
465 + 1, &fileNameArg, &resultDV);
467 + if (hook_successful && resultDV.tag == STRING_TAG) {
468 + fileNameToOpen = resultDV.val.str.rep;
469 + } else {
470 + fileNameToOpen = globbuf.gl_pathv[i];
473 + if (ParseFilename(fileNameToOpen, filename, pathname) != 0) {
474 + XBell(TheDisplay, 0);
475 + } else {
476 + EditExistingFile(GetPrefOpenInTab() ? window : NULL, filename,
477 + pathname, 0, NULL, False, NULL, GetPrefOpenInTab(),
478 + False);
481 + SafeGC();
482 globfree(&globbuf);
484 #endif
485 diff --quilt old/source/window.c new/source/window.c
486 --- old/source/window.c
487 +++ new/source/window.c
488 @@ -169,6 +169,7 @@ static void showStatsForm(WindowInfo *wi
489 static void addToWindowList(WindowInfo *window);
490 static void removeFromWindowList(WindowInfo *window);
491 static void focusCB(Widget w, WindowInfo *window, XtPointer callData);
492 +static void losingFocusCB(Widget w, WindowInfo *window, XtPointer callData);
493 static void modifiedCB(int pos, int nInserted, int nDeleted, int nRestyled,
494 const char *deletedText, void *cbArg);
495 static void movedCB(Widget w, WindowInfo *window, XtPointer callData);
496 @@ -325,6 +326,7 @@ WindowInfo *CreateWindow(const char *nam
497 window->tab = NULL;
498 window->device = 0;
499 window->inode = 0;
500 + window->inMacroHook = 0;
502 /* If window geometry was specified, split it apart into a window position
503 component and a window size component. Create a new geometry string
504 @@ -1029,6 +1031,10 @@ void CloseWindow(WindowInfo *window)
505 return;
508 + if (window->inMacroHook) {
509 + fprintf(stderr, "nedit: warning closing window while in MacroHook\n");
512 /* Free syntax highlighting patterns, if any. w/o redisplaying */
513 FreeHighlightingData(window);
515 @@ -2321,6 +2327,8 @@ static Widget createTextArea(Widget pare
517 /* add focus, drag, cursor tracking, and smart indent callbacks */
518 XtAddCallback(text, textNfocusCallback, (XtCallbackProc)focusCB, window);
519 + XtAddCallback(text, textNlosingFocusCallback,
520 + (XtCallbackProc)losingFocusCB, window);
521 XtAddCallback(text, textNcursorMovementCallback, (XtCallbackProc)movedCB,
522 window);
523 XtAddCallback(text, textNdragStartCallback, (XtCallbackProc)dragStartCB,
524 @@ -2373,6 +2381,10 @@ static void movedCB(Widget w, WindowInfo
525 /* Start blinking the caret again. */
526 ResetCursorBlink(textWidget, False);
529 + /* thats a hight frequency hook, should never force a preemptable
530 + context */
531 + MacroApplyHook(window, "cursor_moved_hook", 0, NULL, NULL);
534 static void modifiedCB(int pos, int nInserted, int nDeleted, int nRestyled,
535 @@ -2444,6 +2456,10 @@ static void modifiedCB(int pos, int nIns
537 /* Check if external changes have been made to file and warn user */
538 CheckForChangesToFile(window);
540 + /* thats a hight frequency hook, should never force a preemptable
541 + context */
542 + MacroApplyHook(window, "modified_hook", 0, NULL, NULL);
545 static void focusCB(Widget w, WindowInfo *window, XtPointer callData)
546 @@ -2459,6 +2475,17 @@ static void focusCB(Widget w, WindowInfo
548 /* Check for changes to read-only status and/or file modifications */
549 CheckForChangesToFile(window);
551 + /* thats a hight frequency hook, should never force a preemptable
552 + context */
553 + MacroApplyHook(window, "focus_hook", 0, NULL, NULL);
556 +static void losingFocusCB(Widget w, WindowInfo *window, XtPointer callData)
558 + /* thats a hight frequency hook, should never force a preemptable
559 + context */
560 + MacroApplyHook(window, "losing_focus_hook", 0, NULL, NULL);
563 static void dragStartCB(Widget w, WindowInfo *window, XtPointer callData)
564 @@ -3466,6 +3493,7 @@ WindowInfo* CreateDocument(WindowInfo* s
565 window->bgMenuRedoItem = NULL;
566 window->device = 0;
567 window->inode = 0;
568 + window->inMacroHook = 0;
570 if (window->fontList == NULL)
571 XtVaGetValues(shellWindow->statsLine, XmNfontList,