I have created a patch for Nedit 5.6 that changes the Ctrl+Tab[/Ctrl+Shift+Tab] tab switch behaviour to cycle through all multiple recently active tabs (by most recently active to least recently active[/vice versa]). These keyboard shortcuts are commonly used in modern text editors (e.g. MS Visual Studio). See https://sourceforge.net/p/nedit/patches/107
Limitations:
- The only issue I have detected while testing the patch occurred when tabs are closed in a particular fashion (recency/switch order is not guaranteed).
Usage:
- To utilise the patch, apply it to the nedit-5.6 source (eg nedit_5.6~cvs20081118.orig.tar.gz), then modify a .Xresources file (and place in $HOME). The .Xresources file should include the following:
NEdit*text.Translations: #override \ ~Shift Ctrl<KeyPress>Tab:switch_documents()\n\ ~Shift Ctrl<KeyRelease>Tab:switch_documents_null()\n\ ~Shift Ctrl<KeyRelease>:switch_documents_end()\n\ Shift Ctrl<KeyPress>Tab:switch_documents_reverse()\n\
Here is a summary of the changes;
menu.c; ~l105: #ifdef SWITCH_DOCUMENTS_PATCH void initialiseSwitchDocumentsListWrapper(); #endif ~l323: #ifdef SWITCH_DOCUMENTS_PATCH static void switchDocumentsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void switchDocumentsReverseAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void switchDocumentsEndAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void switchDocumentsNullAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); #endif ~l545: #ifdef SWITCH_DOCUMENTS_PATCH {"switch_documents", switchDocumentsAP}, {"switch_documents_reverse", switchDocumentsReverseAP}, {"switch_documents_end", switchDocumentsEndAP}, {"switch_documents_null", switchDocumentsNullAP}, #endif ~l615: #ifdef SWITCH_DOCUMENTS_PATCH void initialiseSwitchDocumentsListWrapper() { initialiseSwitchDocumentsList(); } #endif ~l3578: #ifdef SWITCH_DOCUMENTS_PATCH static void switchDocumentsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { switchDocuments(WidgetToWindow(w), SWITCH_DOCUMENTS_PATCH_DIRECTION_NORMAL); } static void switchDocumentsReverseAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { switchDocuments(WidgetToWindow(w), SWITCH_DOCUMENTS_PATCH_DIRECTION_REVERSE); } static void switchDocumentsEndAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { switchDocumentsEnd(WidgetToWindow(w)); } static void switchDocumentsNullAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { } #endif nedit.c; ~l414: #ifdef SWITCH_DOCUMENTS_PATCH initialiseSwitchDocumentsListWrapper(); #endif nedit.h; ~l48: #define SWITCH_DOCUMENTS_PATCH window.c; ~l197: #ifdef SWITCH_DOCUMENTS_PATCH typedef struct SwitchDocumentsListNode { int windowIDdebug; WindowInfo * focusDocument; struct SwitchDocumentsListNode* next; struct SwitchDocumentsListNode* previous; } SwitchDocumentsList; static SwitchDocumentsList* firstNodeInSwitchDocumentsList; static SwitchDocumentsList* activeNodeInSwitchDocumentsList; int switchDocumentsListTraverseDisableMarkActiveDocument; struct timeval switchDocumentsClockLastSave; int switchingDocumentsAtPresent; struct timeval getTimeNow() { struct timeval timenow; gettimeofday(&timenow, NULL); return timenow; } void printWindowList() { printf("*****printWindowList:******\n"); printf("firstNodeInSwitchDocumentsList = %d\n", firstNodeInSwitchDocumentsList->windowIDdebug); printf("activeNodeInSwitchDocumentsList = %d\n", activeNodeInSwitchDocumentsList->windowIDdebug); SwitchDocumentsList* currentNode = firstNodeInSwitchDocumentsList; WindowInfo *win; while(currentNode->next != NULL) { printf("\tcurrentNode = %d, currentNode pointer = %d\n", currentNode->windowIDdebug, currentNode->focusDocument); currentNode = currentNode->next; } } void initialiseSwitchDocumentsList() { switchDocumentsClockLastSave = getTimeNow(); firstNodeInSwitchDocumentsList = malloc(sizeof(SwitchDocumentsList)); firstNodeInSwitchDocumentsList->windowIDdebug = 0; firstNodeInSwitchDocumentsList->focusDocument = NULL; firstNodeInSwitchDocumentsList->next = NULL; firstNodeInSwitchDocumentsList->previous = NULL; activeNodeInSwitchDocumentsList = firstNodeInSwitchDocumentsList; switchDocumentsListTraverseDisableMarkActiveDocument = 0; switchingDocumentsAtPresent = 0; } SwitchDocumentsList* switchDocumentsGetLastNodeInList() { SwitchDocumentsList* currentNode = firstNodeInSwitchDocumentsList; SwitchDocumentsList* lastNodeInList = currentNode; while(currentNode->next != NULL) { lastNodeInList = currentNode; currentNode = currentNode->next; } return lastNodeInList; } SwitchDocumentsList* switchDocumentsListRemoveNode(SwitchDocumentsList* nodeToRemove) { if(nodeToRemove->next != NULL) { if(nodeToRemove->previous == NULL) {/*nodeToRemove is first node in list*/ nodeToRemove->next->previous = NULL; firstNodeInSwitchDocumentsList = nodeToRemove->next; } else {/*nodeToRemove is not first node in list*/ nodeToRemove->previous->next = nodeToRemove->next; nodeToRemove->next->previous = nodeToRemove->previous; } free(nodeToRemove); } else { printf("switchDocumentsListRemoveNode() error: removing dummy node is impossible: (nodeToRemove->next == NULL)\n"); exit(0); } SwitchDocumentsList* lastNodeInList = switchDocumentsGetLastNodeInList(); return lastNodeInList; /*update activeNodeInSwitchDocumentsList (restore to last document in list)*/ } SwitchDocumentsList* switchDocumentsListRemove(WindowInfo * focusDocument) { SwitchDocumentsList* currentNode = firstNodeInSwitchDocumentsList; SwitchDocumentsList* nodeToRemove = NULL; int foundNodeToRemove = 0; while(currentNode->next != NULL) { if(currentNode->focusDocument == focusDocument) { /*found node to remove*/ nodeToRemove = currentNode; foundNodeToRemove = 1; } currentNode = currentNode->next; } SwitchDocumentsList* lastNodeInList = currentNode; if(foundNodeToRemove) { lastNodeInList = switchDocumentsListRemoveNode(nodeToRemove); } else { } return lastNodeInList; } SwitchDocumentsList* switchDocumentsListAdd(WindowInfo * focusDocument) { switchDocumentsListRemove(focusDocument); /*remove previous instance if existent*/ SwitchDocumentsList* currentNode = firstNodeInSwitchDocumentsList; int lastNewWindowIDdebug = 0; while(currentNode->next != NULL) { lastNewWindowIDdebug = currentNode->windowIDdebug; currentNode = currentNode->next; } currentNode->windowIDdebug = lastNewWindowIDdebug+1; currentNode->focusDocument = focusDocument; SwitchDocumentsList* newNode = malloc(sizeof(SwitchDocumentsList)); newNode->focusDocument = NULL; newNode->next = NULL; newNode->previous = currentNode; currentNode->next = newNode; return currentNode; } #endif ~l946: #ifdef SWITCH_DOCUMENTS_PATCH activeNodeInSwitchDocumentsList = switchDocumentsListAdd(window); #endif ~l3949: #ifdef SWITCH_DOCUMENTS_PATCH if(switchDocumentsListTraverseDisableMarkActiveDocument == 0) { if(switchingDocumentsAtPresent == 1) {/*in strange case user is switching documents while creating a new window for example?*/ activeNodeInSwitchDocumentsList = switchDocumentsListAdd(activeNodeInSwitchDocumentsList->focusDocument); switchingDocumentsAtPresent = 0; } activeNodeInSwitchDocumentsList = switchDocumentsListAdd(inFocusDocument); } #endif ~l4025: #ifdef SWITCH_DOCUMENTS_PATCH void switchDocumentsEnd(WindowInfo *window) { if(switchingDocumentsAtPresent == 1) { activeNodeInSwitchDocumentsList = switchDocumentsListAdd(activeNodeInSwitchDocumentsList->focusDocument); switchingDocumentsAtPresent = 0; } } /* ** Switch through last active windows */ void switchDocuments(WindowInfo *window, int direction) { WindowInfo *win; if((activeNodeInSwitchDocumentsList->previous != NULL) || (activeNodeInSwitchDocumentsList->next->next != NULL)) { if(direction == SWITCH_DOCUMENTS_PATCH_DIRECTION_NORMAL) { if(activeNodeInSwitchDocumentsList->previous != NULL) { activeNodeInSwitchDocumentsList = activeNodeInSwitchDocumentsList->previous; } else {/*go around in circles...*/ activeNodeInSwitchDocumentsList = switchDocumentsGetLastNodeInList(); } } else if(direction != SWITCH_DOCUMENTS_PATCH_DIRECTION_NORMAL) { if(activeNodeInSwitchDocumentsList->next->next != NULL) { activeNodeInSwitchDocumentsList = activeNodeInSwitchDocumentsList->next; } else {/*go around in circles...*/ activeNodeInSwitchDocumentsList = firstNodeInSwitchDocumentsList; } } } switchingDocumentsAtPresent = 1; for(win = WindowList; win; win=win->next) if (activeNodeInSwitchDocumentsList->focusDocument == win) break; if (!win) return; switchDocumentsListTraverseDisableMarkActiveDocument = 1; if (window->shell == win->shell) RaiseDocument(win); else RaiseDocumentWindow(win); switchDocumentsListTraverseDisableMarkActiveDocument = 0; } #endif ~l4285: #ifdef SWITCH_DOCUMENTS_PATCH switchDocumentsListRemove(window); #endif window.h; ~l87: #ifdef SWITCH_DOCUMENTS_PATCH #define SWITCH_DOCUMENTS_PATCH_DIRECTION_NORMAL (1) #define SWITCH_DOCUMENTS_PATCH_DIRECTION_REVERSE (2) void switchDocuments(WindowInfo *window, int direction); void switchDocumentsEnd(WindowInfo *window); #endif
Patch against 5.7 release.
Patch against 5.7 Master 2020-11-05.