import saveSearchHistory v3
[nedit-bw.git] / drag-move.patch
blobddbc192672bd3d22ef39d33babf2f11440de1228
1 ---
3 source/Makefile.common | 3
4 source/menu.c | 2
5 source/preferences.c | 39 +++
6 source/preferences.h | 6
7 source/tabDragDrop.c | 610 +++++++++++++++++++++++++++++++++++++++++++++++++
8 source/tabDragDrop.h | 37 ++
9 source/window.c | 20 +
10 source/window.h | 1
11 8 files changed, 714 insertions(+), 4 deletions(-)
13 diff --quilt old/source/Makefile.common new/source/Makefile.common
14 --- old/source/Makefile.common
15 +++ new/source/Makefile.common
16 @@ -9,7 +9,8 @@ OBJS = nedit.o file.o menu.o window.o se
17 highlightData.o interpret.o parse.o smartIndent.o regexConvert.o \
18 rbTree.o windowTitle.o calltips.o server_common.o rangeset.o \
19 patternMatch.o patternMatchData.o \
20 - ternary_search_tree.o dictionary.o
21 + ternary_search_tree.o dictionary.o \
22 + tabDragDrop.o
24 XLTLIB = ../Xlt/libXlt.a
25 XMLLIB = ../Microline/XmL/libXmL.a
26 diff --quilt old/source/menu.c new/source/menu.c
27 --- old/source/menu.c
28 +++ new/source/menu.c
29 @@ -54,6 +54,7 @@ static const char CVSID[] = "$Id: menu.c
30 #include "smartIndent.h"
31 #include "windowTitle.h"
32 #include "regularExp.h"
33 +#include "tabDragDrop.h"
34 #include "../util/getfiles.h"
35 #include "../util/DialogF.h"
36 #include "../util/misc.h"
37 @@ -604,6 +605,7 @@ static XtActionsRec Actions[] = {
38 {"set_em_tab_dist", setEmTabDistAP},
39 {"set_use_tabs", setUseTabsAP},
40 {"set_fonts", setFontsAP},
41 + {"begin_tab_drag", beginTabDragAP},
42 {"set_language_mode", setLanguageModeAP}
45 diff --quilt old/source/preferences.c new/source/preferences.c
46 --- old/source/preferences.c
47 +++ new/source/preferences.c
48 @@ -320,6 +320,9 @@ static struct prefData {
49 XFontStruct *italicFontStruct;
50 XFontStruct *boldItalicFontStruct;
51 int sortTabs; /* sort tabs alphabetically */
52 + int dragDropTabs; /* enable drag&drop for tabs */
53 + int dragDropTabsCursor; /* enable nice cursor for tabs drag&drop */
54 + int dragDropTabsAnimation; /* enable drag&drop animation */
55 int repositionDialogs; /* w. to reposition dialogs under the pointer */
56 int autoScroll; /* w. to autoscroll near top/bottom of screen */
57 int autoScrollVPadding; /* how close to get before autoscrolling */
58 @@ -1013,6 +1016,12 @@ static PrefDescripRec PrefDescrip[] = {
59 &PrefData.iSearchLine, NULL, True},
60 {"sortTabs", "SortTabs", PREF_BOOLEAN, "False",
61 &PrefData.sortTabs, NULL, True},
62 + {"dragDropTabs", "DragDropTabs", PREF_BOOLEAN, "False",
63 + &PrefData.dragDropTabs, NULL, True},
64 + {"dragDropTabsCursor", "DragDropTabsCursor", PREF_BOOLEAN, "False",
65 + &PrefData.dragDropTabsCursor, NULL, True},
66 + {"dragDropTabsAnimation", "DragDropTabsAnimation", PREF_BOOLEAN, "False",
67 + &PrefData.dragDropTabsAnimation, NULL, True},
68 {"tabBar", "TabBar", PREF_BOOLEAN, "True",
69 &PrefData.tabBar, NULL, True},
70 {"tabBarHideOne", "TabBarHideOne", PREF_BOOLEAN, "True",
71 @@ -1863,6 +1872,36 @@ int GetPrefSortTabs(void)
72 return PrefData.sortTabs;
75 +void SetPerfDragDropTabs(int state)
77 + setIntPref(&PrefData.dragDropTabs, state);
80 +int GetPerfDragDropTabs(void)
82 + return PrefData.dragDropTabs;
85 +void SetPerfDragDropTabsCursor(int state)
87 + setIntPref(&PrefData.dragDropTabsCursor, state);
90 +int GetPerfDragDropTabsCursor(void)
92 + return PrefData.dragDropTabsCursor;
95 +void SetPerfDragDropTabsAnimation(int state)
97 + setIntPref(&PrefData.dragDropTabsAnimation, state);
100 +int GetPerfDragDropTabsAnimation(void)
102 + return PrefData.dragDropTabsAnimation;
105 void SetPrefTabBar(int state)
107 setIntPref(&PrefData.tabBar, state);
108 diff --quilt old/source/preferences.h new/source/preferences.h
109 --- old/source/preferences.h
110 +++ new/source/preferences.h
111 @@ -75,6 +75,12 @@ void SetPrefTabBar(int state);
112 int GetPrefTabBar(void);
113 void SetPrefSortTabs(int state);
114 int GetPrefSortTabs(void);
115 +void SetPerfDragDropTabs(int state);
116 +int GetPerfDragDropTabs(void);
117 +void SetPerfDragDropTabsCursor(int state);
118 +int GetPerfDragDropTabsCursor(void);
119 +void SetPerfDragDropTabsAnimation(int state);
120 +int GetPerfDragDropTabsAnimation(void);
121 void SetPrefTabBarHideOne(int state);
122 int GetPrefTabBarHideOne(void);
123 void SetPrefGlobalTabNavigate(int state);
124 diff --quilt /dev/null new/source/tabDragDrop.c
125 --- /dev/null
126 +++ new/source/tabDragDrop.c
127 @@ -0,0 +1,610 @@
128 +/* $Id: tabDragDrop.c,v 1.25 2004/08/20 19:33:21 n8gray Exp $ */
129 +/*******************************************************************************
130 +* *
131 +* tabDragDrop.c -- Nirvana Editor Tab Drag&Drop implementation file *
132 +* *
133 +* Copyright 2008 The NEdit Developers *
134 +* *
135 +* This is free software; you can redistribute it and/or modify it under the *
136 +* terms of the GNU General Public License as published by the Free Software *
137 +* Foundation; either version 2 of the License, or (at your option) any later *
138 +* version. In addition, you may distribute version of this program linked to *
139 +* Motif or Open Motif. See README for details. *
140 +* *
141 +* This software is distributed in the hope that it will be useful, but WITHOUT *
142 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
143 +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
144 +* for more details. *
145 +* *
146 +* You should have received a copy of the GNU General Public License along with *
147 +* software; if not, write to the Free Software Foundation, Inc., 59 Temple *
148 +* Place, Suite 330, Boston, MA 02111-1307 USA *
149 +* *
150 +* Nirvana Text Editor *
151 +* Nov 11, 2008 *
152 +* *
153 +*******************************************************************************/
155 +#include "tabDragDrop.h"
156 +#include "window.h"
158 +#include <Xm/DragDrop.h>
159 +#include <Xm/PushB.h>
161 +#include "../Microline/XmL/Folder.h"
163 +enum tabSide { LEFT_TAB_SIDE, RIGHT_TAB_SIDE };
165 +static void moveTab(WindowInfo *move, WindowInfo *target, enum tabSide side);
166 +static void dropStart(Widget w, XtPointer client_data, XtPointer call_data);
167 +static Pixmap getMaskPixmap(Pixmap tabPixmap, int pixWidth, int pixHeigth);
168 +static void createTabDragCursor(Widget tabWidget, Widget dragContext);
169 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
170 +static void moveTabProc(XtPointer clientData, XtIntervalId *id);
171 +static void moveTab(WindowInfo *src, WindowInfo *target, enum tabSide side );
172 +static enum tabSide tabSideNeighborAdjustment(Widget widget, enum tabSide tabSide);
173 +static enum tabSide getDropTabSide(Widget widget, int x);
174 +static Widget getTabBarWidget(Widget widget);
175 +static void getClosestTab(Widget w, int x, Widget* closestTab, enum tabSide* tabSide);
176 +static void redrawTabBarProc(XtPointer clientData, XtIntervalId *id);
177 +static void tabDragProc(Widget widget, XtPointer client_data, XtPointer call_data);
178 +static void tabDropProc(Widget widget, XtPointer client_data, XtPointer call_data);
179 +void registerDropSite(Widget widget);
180 +void addTabDragAction(Widget widget);
183 +static struct DragDropTabInfo {
184 + WindowInfo *draggedWindow, *droppedWindow;
185 + enum tabSide sideToDropTab;
186 + int redrawTabBar;
187 + int lastInsertionPoint;
188 +} ddtInfo = {NULL, NULL, RIGHT_TAB_SIDE, 0, -10000};
191 +static struct DragIconInfo {
192 + Pixmap tabPixmap, tabMaskPixmap;
193 + Widget dragIcon;
194 +} diInfo = {0, 0, NULL};
198 +** check if drop was successful (it's unsuccessful if we're dropping from another instance).
200 +static void dropStart(Widget w, XtPointer client_data,
201 + XtPointer call_data)
203 + XmDropStartCallback start = (XmDropStartCallback)call_data;
205 + if (start->dropSiteStatus == XmDROP_SITE_INVALID)
206 + ddtInfo.draggedWindow = NULL;
210 +** creates a mask pixmap for the tab pixmap (tries to delete ugly corners etc)
212 +static Pixmap getMaskPixmap(Pixmap tabPixmap, int pixWidth, int pixHeigth)
214 + if (!tabPixmap || !pixWidth || !pixHeigth)
215 + return 0;
217 + Pixmap tabMaskPixmap = XCreatePixmap(TheDisplay, tabPixmap, pixWidth, pixHeigth, 1);
218 + if (!tabMaskPixmap) return 0;
220 + XImage *image=0, *image2=0;
221 + int x,y;
222 + image = XGetImage(TheDisplay, tabPixmap, 0,0, pixWidth, pixHeigth, -1,XYPixmap);
223 + if (!image) goto FAILED;
225 + const unsigned long topLeftPixel = XGetPixel(image, 0, 0);
227 + image2 = XGetImage(TheDisplay, tabMaskPixmap, 0,0, pixWidth, pixHeigth, -1,XYPixmap);
228 + if (!image2) goto FAILED;
230 + /* now let's try to eat tab's corners */
231 + for (y=0; y<pixHeigth; ++y)
232 + for (x=0; x<pixWidth; ++x)
233 + XPutPixel(image2, x, y, 1);
235 + /* eat top left corner */
236 + for (y=0; y<pixHeigth; ++y)
238 + x=0;
239 + if (XGetPixel(image, x, y) != topLeftPixel) break;
240 + for ( ; x<pixWidth && XGetPixel(image, x, y) == topLeftPixel; ++x)
241 + XPutPixel(image2, x, y, 0);
244 + if (y==pixHeigth || x==pixWidth) goto FAILED; /* ate the whole: something is wrong - no mask */
246 + /* eat top right corner */
247 + for (y=0; y<pixHeigth; ++y)
249 + x=pixWidth-1;
250 + if (XGetPixel(image, x, y) != topLeftPixel) break;
251 + for ( ; x>0 && XGetPixel(image, x, y) == topLeftPixel; --x)
252 + XPutPixel(image2, x, y, 0);
254 + if (y==0 || x==0) goto FAILED; /* ate the whole: something is wrong - no mask */
256 + /* ok, done with making the mask image, let's put the result to the mask pixmap */
257 + GC gc = XCreateGC(TheDisplay, tabMaskPixmap, 0, 0);
258 + XPutImage(TheDisplay, tabMaskPixmap, gc, image2, 0,0, 0,0, pixWidth, pixHeigth);
259 + XFreeGC(TheDisplay, gc);
260 + goto DONE;
262 +FAILED:
263 + if (tabMaskPixmap) XFreePixmap(TheDisplay, tabMaskPixmap);
264 + tabMaskPixmap = 0;
266 +DONE:
267 + if (image2) XDestroyImage(image2);
268 + if (image) XDestroyImage(image);
270 + return tabMaskPixmap;
274 +** creates a drag cursor and puts it in drag context, if successful.
276 +static void createTabDragCursor(Widget tabWidget, Widget dragContext)
278 + const Widget tabBarWidget = XtParent(XtParent(tabWidget));
280 + /* get tab pixmap dimensions */
281 + XWindowAttributes attrs;
282 + XGetWindowAttributes(TheDisplay, XtWindow(tabWidget), &attrs);
284 + const int offset = attrs.y;
285 + const int pixWidth = attrs.width + offset*2 + attrs.border_width*2;
286 + const int pixHeigth = attrs.height + offset + attrs.border_width*2;
288 + /* make a pixmap */
289 + if (diInfo.tabPixmap) XFreePixmap(TheDisplay, diInfo.tabPixmap);
290 + diInfo.tabPixmap = XCreatePixmap(TheDisplay, XtWindow(tabBarWidget),
291 + pixWidth, pixHeigth, attrs.depth);
293 + GC gc = XCreateGC(TheDisplay, diInfo.tabPixmap, 0, 0);
294 + XCopyArea(TheDisplay, XtWindow(tabBarWidget), diInfo.tabPixmap, gc,
295 + attrs.x-offset, attrs.y-offset,
296 + pixWidth, pixHeigth,
297 + 0, 0);
298 + XFreeGC(TheDisplay, gc);
300 + /* make a mask pixmap */
301 + Pixmap tabMaskPixmap = getMaskPixmap(diInfo.tabPixmap, pixWidth, pixHeigth);
302 + if (tabMaskPixmap) {
303 + if (diInfo.tabMaskPixmap) XFreePixmap(TheDisplay, diInfo.tabMaskPixmap);
304 + diInfo.tabMaskPixmap = tabMaskPixmap;
307 + /* create a drag icon */
308 + Arg dropIconArgs[10];
309 + int n = 0;
310 + XtSetArg(dropIconArgs[n], XmNpixmap, diInfo.tabPixmap); n++;
311 + XtSetArg(dropIconArgs[n], XmNdepth, attrs.depth); n++;
312 + XtSetArg(dropIconArgs[n], XmNwidth, pixWidth); n++;
313 + XtSetArg(dropIconArgs[n], XmNheight, pixHeigth); n++;
314 + XtSetArg(dropIconArgs[n], XmNhotX, pixWidth/2); n++;
315 + XtSetArg(dropIconArgs[n], XmNhotY, pixHeigth/2); n++;
316 + XtSetArg(dropIconArgs[n], XmNattachment, XmATTACH_HOT); n++;
318 + if (diInfo.tabMaskPixmap) {
319 + XtSetArg(dropIconArgs[n], XmNmask, diInfo.tabMaskPixmap); n++;
322 + if (n>10) abort(); /* check if args array length is enough */
324 + if ( ! diInfo.dragIcon )
326 + /* create drag icon widget */
327 + Widget topLevelWidget = NULL, x = tabWidget;
328 + while (x = XtParent(x))
329 + topLevelWidget = x;
330 + diInfo.dragIcon = XmCreateDragIcon(topLevelWidget, "tabDragIcon", dropIconArgs, n);
332 + else
333 + XtSetValues(diInfo.dragIcon, dropIconArgs, n);
335 + XtVaSetValues(dragContext, XmNsourcePixmapIcon, diInfo.dragIcon, NULL);
336 + XtVaSetValues(dragContext, XmNblendModel, XmBLEND_JUST_SOURCE, NULL);
340 +** action procedure to support drag-n-drop of tabs for moving
341 +** documents.
343 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
345 + if (!GetPerfDragDropTabs())
346 + return;
348 + Widget dragContext;
350 + dragContext = XmGetDragContext(w, event->xbutton.time);
351 + XtAddCallback(dragContext, XmNdropStartCallback, dropStart, NULL);
353 + if (GetPerfDragDropTabsCursor())
354 + createTabDragCursor(w, dragContext);
356 + /* set the drag window pointer to the tab that is being dragged */
357 + ddtInfo.draggedWindow = TabToWindow(w);
361 +** timer routine that takes care of moving tabs.
363 +static void moveTabProc(XtPointer clientData, XtIntervalId *id)
365 + if (ddtInfo.droppedWindow->shell != ddtInfo.draggedWindow->shell) {
366 + WindowInfo *cloneWin = MoveDocument(ddtInfo.droppedWindow, ddtInfo.draggedWindow);
367 + if (!GetPrefSortTabs())
368 + moveTab(cloneWin, ddtInfo.droppedWindow, ddtInfo.sideToDropTab);
370 + else if (!GetPrefSortTabs()) {
371 + moveTab(ddtInfo.draggedWindow, ddtInfo.droppedWindow, ddtInfo.sideToDropTab);
373 + /* it's important to keep this pointer NULL when there is no
374 + dragging, because the drop can happen from another instance
375 + of NEdit, that will lead to crash */
376 + ddtInfo.draggedWindow = NULL;
380 +** move a tab to one position to the right of another tab.
382 +static void moveTab(WindowInfo *src, WindowInfo *target, enum tabSide side )
384 + int tabCount, i;
385 + WidgetList tabList;
386 + WindowInfo *win;
387 + int srcPos, targetPos;
389 + if (src == target || src->shell != target->shell)
390 + return;
392 + srcPos = getTabPosition(src->tab);
393 + targetPos = getTabPosition(target->tab);
395 + switch (side) {
396 + case RIGHT_TAB_SIDE:
397 + if (targetPos == srcPos-1)
398 + return; /* we are already on the right side */
399 + break;
400 + case LEFT_TAB_SIDE:
401 + if (targetPos == srcPos+1)
402 + return; /* we are already on the left side */
403 + break;
406 + if (side == LEFT_TAB_SIDE)
407 + --targetPos;
409 + XtVaGetValues(target->tabBar, XmNtabWidgetList, &tabList,
410 + XmNtabCount, &tabCount, NULL);
411 + if (srcPos < targetPos) {
412 + /* clockwise rotate, target-tab inclusive */
413 + for (i=srcPos; i<targetPos; i++) {
414 + win = TabToWindow(tabList[i+1]);
415 + win->tab = tabList[i];
416 + RefreshTabState(win);
418 + src->tab = tabList[targetPos];
419 + RefreshTabState(src);
421 + else {
422 + /* anti-clockwise rotate */
423 + for (i=srcPos; i>targetPos+1; i--) {
424 + win = TabToWindow(tabList[i-1]);
425 + win->tab = tabList[i];
426 + RefreshTabState(win);
428 + src->tab = tabList[targetPos+1];
429 + RefreshTabState(src);
434 +** "neighbor swap"
435 +** If we're moving a tab to its neighbor, it means we want to swap it,
436 +** no matter which side of the neighbor the tab was dropped to.
438 +static enum tabSide tabSideNeighborAdjustment(Widget widget, enum tabSide tabSide)
440 + if ( ! XtIsSubclass(widget, xmPushButtonWidgetClass) )
441 + return LEFT_TAB_SIDE;
443 + WindowInfo* windowUnder = TabToWindow(widget);
445 + /* adjust only if we're moving in the same window */
446 + if (ddtInfo.draggedWindow->shell != windowUnder->shell)
447 + return tabSide;
449 + const int from = getTabPosition(ddtInfo.draggedWindow->tab);
450 + const int to = getTabPosition(windowUnder->tab);
452 + if (from == to+1 || from == to) {
453 + return LEFT_TAB_SIDE;
455 + else if (from == to-1) {
456 + return RIGHT_TAB_SIDE;
458 + else
459 + return tabSide;
464 +** Returns side of the tab from mouse cursor (taking "neighbor swap" into account).
467 +static enum tabSide getDropTabSide(Widget widget, int x)
469 + if ( ! XtIsSubclass(widget, xmPushButtonWidgetClass) )
470 + return LEFT_TAB_SIDE;
471 + Dimension tabWidth;
472 + XtVaGetValues(widget, XmNwidth, &tabWidth, NULL);
473 + const int left = x < tabWidth/2;
474 + return tabSideNeighborAdjustment(widget, left ? LEFT_TAB_SIDE : RIGHT_TAB_SIDE);
478 +** returns tab bar widget for a widget (tab bar or tab).
480 +static Widget getTabBarWidget(Widget widget)
482 + if (XtClass(widget) == xmlFolderWidgetClass)
483 + return widget;
484 + else if (XtIsSubclass(widget, xmPushButtonWidgetClass))
485 + return XtParent(widget);
486 + else
487 + return NULL;
491 +** returns tab and side for a widget (tab bar or tab) and mouse cursor.
493 +static void getClosestTab(Widget w, int x, Widget* closestTab, enum tabSide* tabSide)
495 + const Widget tabBar = getTabBarWidget(w);
496 + if (tabBar == w) {
497 + int numChildren = 0;
498 + Widget* children = 0;
499 + XtVaGetValues(tabBar, XmNnumChildren, &numChildren, XmNchildren, &children, NULL);
501 + int diff;
502 + int firstTab = 1;
503 + int i=0;
504 + for (; i<numChildren; ++i)
506 + if ( XtIsSubclass(children[i], xmPushButtonWidgetClass) )
508 + XWindowAttributes attrs;
509 + XGetWindowAttributes(TheDisplay, XtWindow(children[i]), &attrs);
510 + const int distanceToTabCenterSigned = x - (attrs.x+attrs.width/2);
511 + const int distanceToTabCenter = abs(distanceToTabCenterSigned);
512 + if (firstTab || distanceToTabCenter < diff) {
513 + firstTab = 0;
514 + diff = distanceToTabCenter;
515 + *closestTab = children[i];
516 + *tabSide = tabSideNeighborAdjustment(*closestTab,
517 + distanceToTabCenterSigned < 0 ? LEFT_TAB_SIDE : RIGHT_TAB_SIDE);
522 + else {
523 + *closestTab = w;
524 + *tabSide = getDropTabSide(w, x);
529 +** timer procedure to redraw the tab bar (i.e. to remove insertion site).
530 +** When we can receive DROP_SITE_LEAVE for tab bar and then DROP_SITE_ENTER
531 +** for tab (and vice versa) - in this case we don't want to redraw, to avoid
532 +** flickering. But in the moment when we received DROP_SITE_LEAVE we don't
533 +** know will there be the corresponding DROP_SITE_ENTER, so let it for timer.
535 +static void redrawTabBarProc(XtPointer clientData, XtIntervalId *id)
537 + if (ddtInfo.redrawTabBar)
539 + Widget tabBar = (Widget)clientData;
540 + XmRedisplayWidget(tabBar);
541 + ddtInfo.lastInsertionPoint = -10000;
546 +** while dragging, display where the tab will be insterted when dropped.
548 +static void tabDragProc(Widget widget, XtPointer client_data,
549 + XtPointer call_data)
551 + static Widget lastTabBar=0;
552 + XmDragProcCallback dragData = (XmDragProcCallback) call_data;
553 + if (!ddtInfo.draggedWindow)
555 + dragData->dropSiteStatus = XmDROP_SITE_INVALID;
556 + dragData->operation = XmDROP_NOOP;
557 + return;
559 + else
561 + dragData->dropSiteStatus = XmDROP_SITE_VALID;
562 + dragData->operation = XmDROP_MOVE;
565 + Widget tabBar = getTabBarWidget(widget);
566 + if (!tabBar)
567 + return;
569 + if (dragData->reason == XmCR_DROP_SITE_LEAVE_MESSAGE)
571 + ddtInfo.redrawTabBar = 1;
572 + XtAppAddTimeOut(XtWidgetToApplicationContext(widget), 0,
573 + redrawTabBarProc, tabBar);
574 + return;
577 + ddtInfo.redrawTabBar = 0; /* for redrawTabBarProc: don't redraw tab bar, we'll take care */
579 + /* get target tab and side */
580 + Widget tab = widget;
581 + enum tabSide tabSide;
583 + getClosestTab(widget, dragData->x, &tab, &tabSide);
585 + /* calculate position and dimensions for the insertion site */
586 + int spacing = 0;
587 + XtVaGetValues(tabBar, XmNspacing, &spacing, 0);
589 + XWindowAttributes attrs;
590 + XGetWindowAttributes(TheDisplay, XtWindow(tab), &attrs);
592 + const int offset = attrs.y;
593 + const int pixWidth = spacing > 5 ? spacing : 5;
594 + const int pixHeigth = attrs.height + offset + attrs.border_width*2;
595 + int x = tabSide == LEFT_TAB_SIDE
596 + ? attrs.x - offset - pixWidth/2 - (spacing-spacing/2)
597 + : attrs.x + offset - pixWidth/2 + spacing/2 + attrs.border_width*2 + attrs.width;
598 + const int y = attrs.y-offset;
600 + /*adjust position, otherwise insertion site won't be visible */
601 + if (spacing) {
602 + if (x <= 0)
603 + x += pixWidth/2;
604 + else {
605 + XWindowAttributes tabBarAttrs;
606 + XGetWindowAttributes(TheDisplay, XtWindow(tabBar), &tabBarAttrs);
607 + if (x >= tabBarAttrs.width) x -= pixWidth/2;
611 + /* check if the insertion site changed */
612 + if (ddtInfo.lastInsertionPoint == x && lastTabBar == tabBar)
613 + return;
615 + XmRedisplayWidget(tabBar);
616 + ddtInfo.lastInsertionPoint = x;
617 + lastTabBar = tabBar;
619 + /* copy inverted image of the insertion site*/
620 + XGCValues gcVals = {};
621 + GC gc1 = XCreateGC(TheDisplay, XtWindow(tabBar), 0, &gcVals);
622 + gcVals.function = GXnor;
623 + XChangeGC(TheDisplay, gc1, GCFunction, &gcVals);
625 + XCopyArea(TheDisplay, XtWindow(tabBar), XtWindow(tabBar), gc1,
626 + x, y,
627 + pixWidth, pixHeigth,
628 + x, y);
629 + XFreeGC(TheDisplay, gc1);
633 +** initiate document movement when tabs are dragged into
634 +** the text area, or another tab.
636 +static void tabDropProc(Widget widget, XtPointer client_data,
637 + XtPointer call_data)
639 + XmDropProcCallback dropData;
640 + Arg args[10];
641 + int n;
642 + Widget dc;
644 + dropData = (XmDropProcCallback) call_data;
645 + dc = dropData->dragContext;
647 + n = 0;
648 + if (!ddtInfo.draggedWindow)
650 + dropData->dropSiteStatus = XmDROP_SITE_INVALID;
651 + dropData->operation = XmDROP_NOOP;
652 + XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
653 + XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
654 + XmDropTransferStart(dc, args, n);
655 + return;
657 + else
659 + dropData->dropSiteStatus = XmDROP_SITE_VALID;
660 + dropData->operation = XmDROP_MOVE;
661 + XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_SUCCESS); n++;
662 + XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
663 + XmDropTransferStart(dc, args, n);
666 + ddtInfo.sideToDropTab = RIGHT_TAB_SIDE;
668 + /* determine the target tab based on the drop-zone:
669 + 1. text area or another tab: it's the one,
670 + 2. tab bar gutter: the right-most tab. */
671 + if (XtIsSubclass(widget, xmPushButtonWidgetClass)
672 + || XtClass(widget) == xmlFolderWidgetClass) {
673 + Widget tabWidget = 0;
674 + getClosestTab(widget, dropData->x, &tabWidget, &ddtInfo.sideToDropTab);
675 + ddtInfo.droppedWindow = TabToWindow(tabWidget);
677 + else
678 + ddtInfo.droppedWindow = WidgetToWindow(widget);
680 + if (ddtInfo.droppedWindow != ddtInfo.draggedWindow) {
681 + /* moving document is a big operation, we delay it to avoid
682 + any potential conflicts with the toolkits */
683 + XtAppAddTimeOut(XtWidgetToApplicationContext(widget), 0,
684 + moveTabProc, NULL);
686 + else {
687 + /* it's important to keep this pointer NULL when there is no
688 + dragging, because the drop can happen from another instance
689 + of NEdit, that will lead to crash */
690 + ddtInfo.draggedWindow = NULL;
695 +** register a widget as drop site for tabs, for the purpose
696 +** of moving tabs within and across windows.
698 +void registerDropSite(Widget widget)
700 +#ifndef LESSTIF_VERSION
701 + Arg args[15];
702 + int n = 0;
704 + if (XtIsSubclass(widget, compositeWidgetClass))
705 + XtSetArg(args[n], XmNdropSiteType, XmDROP_SITE_COMPOSITE);
706 + else
707 + XtSetArg(args[n], XmNdropSiteType, XmDROP_SITE_SIMPLE);
708 + n++;
710 + XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_NONE); n++;
711 + XtSetArg(args[n], XmNnumImportTargets, 0); n++;
712 + XtSetArg(args[n], XmNdropSiteOperations, XmDROP_MOVE); n++;
713 + XtSetArg(args[n], XmNdropProc, tabDropProc); n++;
714 + if (GetPerfDragDropTabsAnimation()) {
715 + XtSetArg(args[n], XmNdragProc, tabDragProc); n++;
717 + XmDropSiteRegister (widget, args, n);
718 +#endif /* LESSTIF_VERSION */
722 +** override translation for tab widget on drag [-and-drop].
724 +void addTabDragAction(Widget widget)
726 +#ifndef LESSTIF_VERSION
727 + static XtTranslations table = NULL;
729 + if (table == NULL) {
730 + char *translations =
731 + "#override <Btn2Down>: ProcessDrag() begin_tab_drag()";
732 + table = XtParseTranslationTable(translations);
734 + XtOverrideTranslations(widget, table);
735 +#endif /* LESSTIF_VERSION */
738 diff --quilt /dev/null new/source/tabDragDrop.h
739 --- /dev/null
740 +++ new/source/tabDragDrop.h
741 @@ -0,0 +1,37 @@
742 +/* $Id: tabDragDrop.h,v 1.25 2004/08/20 19:33:21 n8gray Exp $ */
743 +/*******************************************************************************
744 +* *
745 +* tabDragDrop.h -- Nirvana Editor Tab Drag&Drop header file *
746 +* *
747 +* Copyright 2008 The NEdit Developers *
748 +* *
749 +* This is free software; you can redistribute it and/or modify it under the *
750 +* terms of the GNU General Public License as published by the Free Software *
751 +* Foundation; either version 2 of the License, or (at your option) any later *
752 +* version. In addition, you may distribute version of this program linked to *
753 +* Motif or Open Motif. See README for details. *
754 +* *
755 +* This software is distributed in the hope that it will be useful, but WITHOUT *
756 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
757 +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
758 +* for more details. *
759 +* *
760 +* You should have received a copy of the GNU General Public License along with *
761 +* software; if not, write to the Free Software Foundation, Inc., 59 Temple *
762 +* Place, Suite 330, Boston, MA 02111-1307 USA *
763 +* *
764 +* Nirvana Text Editor *
765 +* Nov 11, 2008 *
766 +* *
767 +*******************************************************************************/
769 +#ifndef NEDIT_TAB_DRAG_DROP_H_INCLUDED
770 +#define NEDIT_TAB_DRAG_DROP_H_INCLUDED
772 +#include <X11/Intrinsic.h>
774 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
775 +void registerDropSite(Widget widget);
776 +void addTabDragAction(Widget widget);
778 +#endif /* NEDIT_TAB_DRAG_DROP_H_INCLUDED */
779 diff --quilt old/source/window.c new/source/window.c
780 --- old/source/window.c
781 +++ new/source/window.c
782 @@ -53,6 +53,7 @@ static const char CVSID[] = "$Id: window
783 #include "nedit.bm"
784 #include "n.bm"
785 #include "windowTitle.h"
786 +#include "tabDragDrop.h"
787 #include "interpret.h"
788 #include "rangeset.h"
789 #include "patternMatchData.h"
790 @@ -155,7 +156,6 @@ static WindowInfo *getNextTabWindow(Wind
791 int crossWin, int wrap);
792 static Widget addTab(Widget folder, const char *string);
793 static int compareWindowNames(const void *windowA, const void *windowB);
794 -static int getTabPosition(Widget tab);
795 static Widget manageToolBars(Widget toolBarsForm);
796 static void hideTearOffs(Widget menuPane);
797 static void CloseDocumentWindow(Widget w, WindowInfo *window, XtPointer callData);
798 @@ -613,6 +613,8 @@ WindowInfo *CreateWindow(const char *nam
800 window->tabMenuPane = CreateTabContextMenu(window->tabBar, window);
801 AddTabContextMenuAction(window->tabBar);
802 + if (GetPerfDragDropTabs())
803 + registerDropSite(window->tabBar);
805 /* create an unmanaged composite widget to get the folder
806 widget to hide the 3D shadow for the manager area.
807 @@ -878,6 +880,10 @@ static Widget addTab(Widget folder, cons
808 AddTabContextMenuAction(tab);
809 #endif /* LESSTIF_VERSION */
811 + if (GetPerfDragDropTabs()) {
812 + addTabDragAction(tab);
813 + registerDropSite(tab);
815 return tab;
818 @@ -2404,6 +2410,9 @@ static Widget createTextArea(Widget pare
819 operation and performance will be better without it) */
820 TextDMaintainAbsLineNum(((TextWidget)text)->text.textD, window->showStats);
822 + if (GetPerfDragDropTabs())
823 + registerDropSite(text);
825 return text;
828 @@ -3767,7 +3776,7 @@ static WindowInfo *getNextTabWindow(Wind
829 ** return the integer position of a tab in the tabbar it
830 ** belongs to, or -1 if there's an error, somehow.
832 -static int getTabPosition(Widget tab)
833 +int getTabPosition(Widget tab)
835 WidgetList tabList;
836 int i, tabCount;
837 @@ -3826,6 +3835,10 @@ void RefreshTabState(WindowInfo *win)
838 NULL);
839 XmStringFree(s1);
840 XmStringFree(tipString);
842 + /* set tab as active */
843 + if (IsTopDocument(win))
844 + XmLFolderSetActiveTab(win->tabBar, getTabPosition(win->tab), False);
848 @@ -4784,7 +4797,8 @@ WindowInfo *MoveDocument(WindowInfo *toW
849 /* this should keep the new document window fresh */
850 RaiseDocumentWindow(cloneWin);
851 RefreshTabState(cloneWin);
852 - SortTabBar(cloneWin);
853 + if (GetPrefSortTabs())
854 + SortTabBar(cloneWin);
856 return cloneWin;
858 diff --quilt old/source/window.h new/source/window.h
859 --- old/source/window.h
860 +++ new/source/window.h
861 @@ -65,6 +65,7 @@ int WidgetToPaneIndex(WindowInfo *window
862 void ClosePane(WindowInfo *window);
863 int GetShowTabBar(WindowInfo *window);
864 void ShowTabBar(WindowInfo *window, int state);
865 +int getTabPosition(Widget tab);
866 void ShowStatsLine(WindowInfo *window, int state);
867 void ShowISearchLine(WindowInfo *window, int state);
868 void TempShowISearch(WindowInfo *window, int state);