update drag-move to v1.5-beta
[nedit-bw.git] / drag-move.patch
blob5a9d03fd2abccafb9babc54ae30c35f4ccd064ba
1 ---
4 ---
6 source/Makefile.common | 3
7 source/menu.c | 2
8 source/preferences.c | 39 +++
9 source/preferences.h | 6
10 source/tabDragDrop.c | 615 +++++++++++++++++++++++++++++++++++++++++++++++++
11 source/tabDragDrop.h | 37 ++
12 source/window.c | 20 +
13 source/window.h | 1
14 8 files changed, 719 insertions(+), 4 deletions(-)
16 diff --quilt old/source/Makefile.common new/source/Makefile.common
17 --- old/source/Makefile.common
18 +++ new/source/Makefile.common
19 @@ -9,7 +9,8 @@ OBJS = nedit.o file.o menu.o window.o se
20 highlightData.o interpret.o parse.o smartIndent.o regexConvert.o \
21 rbTree.o windowTitle.o calltips.o server_common.o rangeset.o \
22 patternMatch.o patternMatchData.o \
23 - ternary_search_tree.o dictionary.o
24 + ternary_search_tree.o dictionary.o \
25 + tabDragDrop.o
27 XLTLIB = ../Xlt/libXlt.a
28 XMLLIB = ../Microline/XmL/libXmL.a
29 diff --quilt old/source/menu.c new/source/menu.c
30 --- old/source/menu.c
31 +++ new/source/menu.c
32 @@ -54,6 +54,7 @@ static const char CVSID[] = "$Id: menu.c
33 #include "smartIndent.h"
34 #include "windowTitle.h"
35 #include "regularExp.h"
36 +#include "tabDragDrop.h"
37 #include "../util/getfiles.h"
38 #include "../util/DialogF.h"
39 #include "../util/misc.h"
40 @@ -604,6 +605,7 @@ static XtActionsRec Actions[] = {
41 {"set_em_tab_dist", setEmTabDistAP},
42 {"set_use_tabs", setUseTabsAP},
43 {"set_fonts", setFontsAP},
44 + {"begin_tab_drag", beginTabDragAP},
45 {"set_language_mode", setLanguageModeAP}
48 diff --quilt old/source/preferences.c new/source/preferences.c
49 --- old/source/preferences.c
50 +++ new/source/preferences.c
51 @@ -320,6 +320,9 @@ static struct prefData {
52 XFontStruct *italicFontStruct;
53 XFontStruct *boldItalicFontStruct;
54 int sortTabs; /* sort tabs alphabetically */
55 + int dragDropTabs; /* enable drag&drop for tabs */
56 + int dragDropTabsCursor; /* enable nice cursor for tabs drag&drop */
57 + int dragDropTabsAnimation; /* enable drag&drop animation */
58 int repositionDialogs; /* w. to reposition dialogs under the pointer */
59 int autoScroll; /* w. to autoscroll near top/bottom of screen */
60 int autoScrollVPadding; /* how close to get before autoscrolling */
61 @@ -1013,6 +1016,12 @@ static PrefDescripRec PrefDescrip[] = {
62 &PrefData.iSearchLine, NULL, True},
63 {"sortTabs", "SortTabs", PREF_BOOLEAN, "False",
64 &PrefData.sortTabs, NULL, True},
65 + {"dragDropTabs", "DragDropTabs", PREF_BOOLEAN, "False",
66 + &PrefData.dragDropTabs, NULL, True},
67 + {"dragDropTabsCursor", "DragDropTabsCursor", PREF_BOOLEAN, "False",
68 + &PrefData.dragDropTabsCursor, NULL, True},
69 + {"dragDropTabsAnimation", "DragDropTabsAnimation", PREF_BOOLEAN, "False",
70 + &PrefData.dragDropTabsAnimation, NULL, True},
71 {"tabBar", "TabBar", PREF_BOOLEAN, "True",
72 &PrefData.tabBar, NULL, True},
73 {"tabBarHideOne", "TabBarHideOne", PREF_BOOLEAN, "True",
74 @@ -1863,6 +1872,36 @@ int GetPrefSortTabs(void)
75 return PrefData.sortTabs;
78 +void SetPerfDragDropTabs(int state)
80 + setIntPref(&PrefData.dragDropTabs, state);
83 +int GetPerfDragDropTabs(void)
85 + return PrefData.dragDropTabs;
88 +void SetPerfDragDropTabsCursor(int state)
90 + setIntPref(&PrefData.dragDropTabsCursor, state);
93 +int GetPerfDragDropTabsCursor(void)
95 + return PrefData.dragDropTabsCursor;
98 +void SetPerfDragDropTabsAnimation(int state)
100 + setIntPref(&PrefData.dragDropTabsAnimation, state);
103 +int GetPerfDragDropTabsAnimation(void)
105 + return PrefData.dragDropTabsAnimation;
108 void SetPrefTabBar(int state)
110 setIntPref(&PrefData.tabBar, state);
111 diff --quilt old/source/preferences.h new/source/preferences.h
112 --- old/source/preferences.h
113 +++ new/source/preferences.h
114 @@ -75,6 +75,12 @@ void SetPrefTabBar(int state);
115 int GetPrefTabBar(void);
116 void SetPrefSortTabs(int state);
117 int GetPrefSortTabs(void);
118 +void SetPerfDragDropTabs(int state);
119 +int GetPerfDragDropTabs(void);
120 +void SetPerfDragDropTabsCursor(int state);
121 +int GetPerfDragDropTabsCursor(void);
122 +void SetPerfDragDropTabsAnimation(int state);
123 +int GetPerfDragDropTabsAnimation(void);
124 void SetPrefTabBarHideOne(int state);
125 int GetPrefTabBarHideOne(void);
126 void SetPrefGlobalTabNavigate(int state);
127 diff --quilt /dev/null new/source/tabDragDrop.c
128 --- /dev/null
129 +++ new/source/tabDragDrop.c
130 @@ -0,0 +1,615 @@
131 +/* $Id: tabDragDrop.c,v 1.25 2004/08/20 19:33:21 n8gray Exp $ */
132 +/*******************************************************************************
133 +* *
134 +* tabDragDrop.c -- Nirvana Editor Tab Drag&Drop implementation file *
135 +* *
136 +* Copyright 2008 The NEdit Developers *
137 +* *
138 +* This is free software; you can redistribute it and/or modify it under the *
139 +* terms of the GNU General Public License as published by the Free Software *
140 +* Foundation; either version 2 of the License, or (at your option) any later *
141 +* version. In addition, you may distribute version of this program linked to *
142 +* Motif or Open Motif. See README for details. *
143 +* *
144 +* This software is distributed in the hope that it will be useful, but WITHOUT *
145 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
146 +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
147 +* for more details. *
148 +* *
149 +* You should have received a copy of the GNU General Public License along with *
150 +* software; if not, write to the Free Software Foundation, Inc., 59 Temple *
151 +* Place, Suite 330, Boston, MA 02111-1307 USA *
152 +* *
153 +* Nirvana Text Editor *
154 +* Nov 11, 2008 *
155 +* *
156 +*******************************************************************************/
158 +#include "tabDragDrop.h"
159 +#include "window.h"
160 +#include "preferences.h"
162 +#include <Xm/DragDrop.h>
163 +#include <Xm/PushB.h>
164 +#include <Xm/Print.h> /* for XmRedisplayWidget */
166 +#include "../Microline/XmL/Folder.h"
168 +#include <stdlib.h>
169 +#include <limits.h>
171 +enum tabSide { LEFT_TAB_SIDE, RIGHT_TAB_SIDE };
173 +static void moveTab(WindowInfo *move, WindowInfo *target, enum tabSide side);
174 +static void dropStart(Widget w, XtPointer client_data, XtPointer call_data);
175 +static Pixmap getMaskPixmap(Pixmap tabPixmap, int pixWidth, int pixHeigth);
176 +static void createTabDragCursor(Widget tabWidget, Widget dragContext);
177 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
178 +static void moveTabProc(XtPointer clientData, XtIntervalId *id);
179 +static void moveTab(WindowInfo *src, WindowInfo *target, enum tabSide side );
180 +static enum tabSide tabSideNeighborAdjustment(Widget widget, enum tabSide tabSide);
181 +static enum tabSide getDropTabSide(Widget widget, int x);
182 +static Widget getTabBarWidget(Widget widget);
183 +static void getClosestTab(Widget w, int x, Widget* closestTab, enum tabSide* tabSide);
184 +static void redrawTabBarProc(XtPointer clientData, XtIntervalId *id);
185 +static void tabDragProc(Widget widget, XtPointer client_data, XtPointer call_data);
186 +static void tabDropProc(Widget widget, XtPointer client_data, XtPointer call_data);
187 +void registerDropSite(Widget widget);
188 +void addTabDragAction(Widget widget);
191 +static struct DragDropTabInfo {
192 + WindowInfo *draggedWindow, *droppedWindow;
193 + enum tabSide sideToDropTab;
194 + int redrawTabBar;
195 + int lastInsertionPoint;
196 +} ddtInfo = {NULL, NULL, RIGHT_TAB_SIDE, 0, -10000};
199 +static struct DragIconInfo {
200 + Pixmap tabPixmap, tabMaskPixmap;
201 + Widget dragIcon;
202 +} diInfo = {0, 0, NULL};
206 +** check if drop was successful (it's unsuccessful if we're dropping from another instance).
208 +static void dropStart(Widget w, XtPointer client_data,
209 + XtPointer call_data)
211 + XmDropStartCallback start = (XmDropStartCallback)call_data;
213 + if (start->dropSiteStatus == XmDROP_SITE_INVALID)
214 + ddtInfo.draggedWindow = NULL;
218 +** creates a mask pixmap for the tab pixmap (tries to delete ugly corners etc)
220 +static Pixmap getMaskPixmap(Pixmap tabPixmap, int pixWidth, int pixHeigth)
222 + if (!tabPixmap || !pixWidth || !pixHeigth)
223 + return 0;
225 + Pixmap tabMaskPixmap = XCreatePixmap(TheDisplay, tabPixmap, pixWidth, pixHeigth, 1);
226 + if (!tabMaskPixmap) return 0;
228 + XImage *image=0, *image2=0;
229 + image = XGetImage(TheDisplay, tabPixmap, 0,0, pixWidth, pixHeigth, -1,XYPixmap);
230 + if (!image) goto FAILED;
232 + const unsigned long topLeftPixel = XGetPixel(image, 0, 0);
234 + image2 = XGetImage(TheDisplay, tabMaskPixmap, 0,0, pixWidth, pixHeigth, -1,XYPixmap);
235 + if (!image2) goto FAILED;
237 + /* now let's try to eat tab's corners */
238 + int x=0, y=0;
239 + for (y=0; y<pixHeigth; ++y)
240 + for (x=0; x<pixWidth; ++x)
241 + XPutPixel(image2, x, y, 1);
243 + /* eat top left corner */
244 + for (y=0; y<pixHeigth; ++y)
246 + x=0;
247 + if (XGetPixel(image, x, y) != topLeftPixel) break;
248 + for ( ; x<pixWidth && XGetPixel(image, x, y) == topLeftPixel; ++x)
249 + XPutPixel(image2, x, y, 0);
252 + if (y==pixHeigth || x==pixWidth) goto FAILED; /* ate the whole: something is wrong - no mask */
254 + /* eat top right corner */
255 + for (y=0; y<pixHeigth; ++y)
257 + x=pixWidth-1;
258 + if (XGetPixel(image, x, y) != topLeftPixel) break;
259 + for ( ; x>0 && XGetPixel(image, x, y) == topLeftPixel; --x)
260 + XPutPixel(image2, x, y, 0);
262 + if (y==0 || x==0) goto FAILED; /* ate the whole: something is wrong - no mask */
264 + /* ok, done with making the mask image, let's put the result to the mask pixmap */
265 + GC gc = XCreateGC(TheDisplay, tabMaskPixmap, 0, 0);
266 + XPutImage(TheDisplay, tabMaskPixmap, gc, image2, 0,0, 0,0, pixWidth, pixHeigth);
267 + XFreeGC(TheDisplay, gc);
268 + goto DONE;
270 +FAILED:
271 + if (tabMaskPixmap) XFreePixmap(TheDisplay, tabMaskPixmap);
272 + tabMaskPixmap = 0;
274 +DONE:
275 + if (image2) XDestroyImage(image2);
276 + if (image) XDestroyImage(image);
278 + return tabMaskPixmap;
282 +** creates a drag cursor and puts it in drag context, if successful.
284 +static void createTabDragCursor(Widget tabWidget, Widget dragContext)
286 + const Widget tabBarWidget = XtParent(XtParent(tabWidget));
288 + /* get tab pixmap dimensions */
289 + XWindowAttributes attrs;
290 + XGetWindowAttributes(TheDisplay, XtWindow(tabWidget), &attrs);
292 + const int offset = attrs.y;
293 + const int pixWidth = attrs.width + offset*2 + attrs.border_width*2;
294 + const int pixHeigth = attrs.height + offset + attrs.border_width*2;
296 + /* make a pixmap */
297 + if (diInfo.tabPixmap) XFreePixmap(TheDisplay, diInfo.tabPixmap);
298 + diInfo.tabPixmap = XCreatePixmap(TheDisplay, XtWindow(tabBarWidget),
299 + pixWidth, pixHeigth, attrs.depth);
301 + GC gc = XCreateGC(TheDisplay, diInfo.tabPixmap, 0, 0);
302 + XCopyArea(TheDisplay, XtWindow(tabBarWidget), diInfo.tabPixmap, gc,
303 + attrs.x-offset, attrs.y-offset,
304 + pixWidth, pixHeigth,
305 + 0, 0);
306 + XFreeGC(TheDisplay, gc);
308 + /* make a mask pixmap */
309 + Pixmap tabMaskPixmap = getMaskPixmap(diInfo.tabPixmap, pixWidth, pixHeigth);
310 + if (tabMaskPixmap) {
311 + if (diInfo.tabMaskPixmap) XFreePixmap(TheDisplay, diInfo.tabMaskPixmap);
312 + diInfo.tabMaskPixmap = tabMaskPixmap;
315 + /* create a drag icon */
316 + Arg dropIconArgs[10];
317 + int n = 0;
318 + XtSetArg(dropIconArgs[n], XmNpixmap, diInfo.tabPixmap); n++;
319 + XtSetArg(dropIconArgs[n], XmNdepth, attrs.depth); n++;
320 + XtSetArg(dropIconArgs[n], XmNwidth, pixWidth); n++;
321 + XtSetArg(dropIconArgs[n], XmNheight, pixHeigth); n++;
322 + XtSetArg(dropIconArgs[n], XmNhotX, pixWidth/2); n++;
323 + XtSetArg(dropIconArgs[n], XmNhotY, pixHeigth/2); n++;
324 + XtSetArg(dropIconArgs[n], XmNattachment, XmATTACH_HOT); n++;
326 + if (diInfo.tabMaskPixmap) {
327 + XtSetArg(dropIconArgs[n], XmNmask, diInfo.tabMaskPixmap); n++;
330 + if (n>10) abort(); /* check if args array length is enough */
332 + if ( ! diInfo.dragIcon )
334 + /* create drag icon widget */
335 + Widget topLevelWidget = NULL, x = tabWidget;
336 + while ( (x = XtParent(x)) )
337 + topLevelWidget = x;
338 + diInfo.dragIcon = XmCreateDragIcon(topLevelWidget, "tabDragIcon", dropIconArgs, n);
340 + else
341 + XtSetValues(diInfo.dragIcon, dropIconArgs, n);
343 + XtVaSetValues(dragContext, XmNsourcePixmapIcon, diInfo.dragIcon, NULL);
344 + XtVaSetValues(dragContext, XmNblendModel, XmBLEND_JUST_SOURCE, NULL);
348 +** action procedure to support drag-n-drop of tabs for moving
349 +** documents.
351 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
353 + if (!GetPerfDragDropTabs())
354 + return;
356 + Widget dragContext;
358 + dragContext = XmGetDragContext(w, event->xbutton.time);
359 + XtAddCallback(dragContext, XmNdropStartCallback, dropStart, NULL);
361 + if (GetPerfDragDropTabsCursor())
362 + createTabDragCursor(w, dragContext);
364 + /* set the drag window pointer to the tab that is being dragged */
365 + ddtInfo.draggedWindow = TabToWindow(w);
369 +** timer routine that takes care of moving tabs.
371 +static void moveTabProc(XtPointer clientData, XtIntervalId *id)
373 + if (ddtInfo.droppedWindow->shell != ddtInfo.draggedWindow->shell) {
374 + WindowInfo *cloneWin = MoveDocument(ddtInfo.droppedWindow, ddtInfo.draggedWindow);
375 + if (!GetPrefSortTabs())
376 + moveTab(cloneWin, ddtInfo.droppedWindow, ddtInfo.sideToDropTab);
378 + else if (!GetPrefSortTabs()) {
379 + moveTab(ddtInfo.draggedWindow, ddtInfo.droppedWindow, ddtInfo.sideToDropTab);
381 + /* it's important to keep this pointer NULL when there is no
382 + dragging, because the drop can happen from another instance
383 + of NEdit, that will lead to crash */
384 + ddtInfo.draggedWindow = NULL;
388 +** move a tab to one position to the right of another tab.
390 +static void moveTab(WindowInfo *src, WindowInfo *target, enum tabSide side )
392 + int tabCount, i;
393 + WidgetList tabList;
394 + WindowInfo *win;
395 + int srcPos, targetPos;
397 + if (src == target || src->shell != target->shell)
398 + return;
400 + srcPos = getTabPosition(src->tab);
401 + targetPos = getTabPosition(target->tab);
403 + switch (side) {
404 + case RIGHT_TAB_SIDE:
405 + if (targetPos == srcPos-1)
406 + return; /* we are already on the right side */
407 + break;
408 + case LEFT_TAB_SIDE:
409 + if (targetPos == srcPos+1)
410 + return; /* we are already on the left side */
411 + break;
414 + if (side == LEFT_TAB_SIDE)
415 + --targetPos;
417 + XtVaGetValues(target->tabBar, XmNtabWidgetList, &tabList,
418 + XmNtabCount, &tabCount, NULL);
419 + if (srcPos < targetPos) {
420 + /* clockwise rotate, target-tab inclusive */
421 + for (i=srcPos; i<targetPos; i++) {
422 + win = TabToWindow(tabList[i+1]);
423 + win->tab = tabList[i];
424 + RefreshTabState(win);
426 + src->tab = tabList[targetPos];
427 + RefreshTabState(src);
429 + else {
430 + /* anti-clockwise rotate */
431 + for (i=srcPos; i>targetPos+1; i--) {
432 + win = TabToWindow(tabList[i-1]);
433 + win->tab = tabList[i];
434 + RefreshTabState(win);
436 + src->tab = tabList[targetPos+1];
437 + RefreshTabState(src);
442 +** "neighbor swap"
443 +** If we're moving a tab to its neighbor, it means we want to swap it,
444 +** no matter which side of the neighbor the tab was dropped to.
446 +static enum tabSide tabSideNeighborAdjustment(Widget widget, enum tabSide tabSide)
448 + if ( ! XtIsSubclass(widget, xmPushButtonWidgetClass) )
449 + return LEFT_TAB_SIDE;
451 + WindowInfo* windowUnder = TabToWindow(widget);
453 + /* adjust only if we're moving in the same window */
454 + if (ddtInfo.draggedWindow->shell != windowUnder->shell)
455 + return tabSide;
457 + const int from = getTabPosition(ddtInfo.draggedWindow->tab);
458 + const int to = getTabPosition(windowUnder->tab);
460 + if (from == to+1 || from == to) {
461 + return LEFT_TAB_SIDE;
463 + else if (from == to-1) {
464 + return RIGHT_TAB_SIDE;
466 + else
467 + return tabSide;
472 +** Returns side of the tab from mouse cursor (taking "neighbor swap" into account).
475 +static enum tabSide getDropTabSide(Widget widget, int x)
477 + if ( ! XtIsSubclass(widget, xmPushButtonWidgetClass) )
478 + return LEFT_TAB_SIDE;
479 + Dimension tabWidth;
480 + XtVaGetValues(widget, XmNwidth, &tabWidth, NULL);
481 + const int left = x < tabWidth/2;
482 + return tabSideNeighborAdjustment(widget, left ? LEFT_TAB_SIDE : RIGHT_TAB_SIDE);
486 +** returns tab bar widget for a widget (tab bar or tab).
488 +static Widget getTabBarWidget(Widget widget)
490 + if (XtClass(widget) == xmlFolderWidgetClass)
491 + return widget;
492 + else if (XtIsSubclass(widget, xmPushButtonWidgetClass))
493 + return XtParent(widget);
494 + else
495 + return NULL;
499 +** returns tab and side for a widget (tab bar or tab) and mouse cursor.
501 +static void getClosestTab(Widget w, int x, Widget* closestTab, enum tabSide* tabSide)
503 + const Widget tabBar = getTabBarWidget(w);
504 + if (tabBar == w) {
505 + int numChildren = 0;
506 + Widget* children = 0;
507 + XtVaGetValues(tabBar, XmNnumChildren, &numChildren, XmNchildren, &children, NULL);
509 + int diff = INT_MAX;
510 + int firstTab = 1;
511 + int i=0;
512 + for (; i<numChildren; ++i)
514 + if ( XtIsSubclass(children[i], xmPushButtonWidgetClass) )
516 + XWindowAttributes attrs;
517 + XGetWindowAttributes(TheDisplay, XtWindow(children[i]), &attrs);
518 + const int distanceToTabCenterSigned = x - (attrs.x+attrs.width/2);
519 + const int distanceToTabCenter = abs(distanceToTabCenterSigned);
520 + if (firstTab || distanceToTabCenter < diff) {
521 + firstTab = 0;
522 + diff = distanceToTabCenter;
523 + *closestTab = children[i];
524 + *tabSide = tabSideNeighborAdjustment(*closestTab,
525 + distanceToTabCenterSigned < 0 ? LEFT_TAB_SIDE : RIGHT_TAB_SIDE);
530 + else {
531 + *closestTab = w;
532 + *tabSide = getDropTabSide(w, x);
537 +** timer procedure to redraw the tab bar (i.e. to remove insertion site).
538 +** When we can receive DROP_SITE_LEAVE for tab bar and then DROP_SITE_ENTER
539 +** for tab (and vice versa) - in this case we don't want to redraw, to avoid
540 +** flickering. But in the moment when we received DROP_SITE_LEAVE we don't
541 +** know will there be the corresponding DROP_SITE_ENTER, so let it for timer.
543 +static void redrawTabBarProc(XtPointer clientData, XtIntervalId *id)
545 + if (ddtInfo.redrawTabBar)
547 + Widget tabBar = (Widget)clientData;
548 + XmRedisplayWidget(tabBar);
549 + ddtInfo.lastInsertionPoint = -10000;
554 +** while dragging, display where the tab will be insterted when dropped.
556 +static void tabDragProc(Widget widget, XtPointer client_data,
557 + XtPointer call_data)
559 + static Widget lastTabBar=0;
560 + XmDragProcCallback dragData = (XmDragProcCallback) call_data;
561 + if (!ddtInfo.draggedWindow)
563 + dragData->dropSiteStatus = XmDROP_SITE_INVALID;
564 + dragData->operation = XmDROP_NOOP;
565 + return;
567 + else
569 + dragData->dropSiteStatus = XmDROP_SITE_VALID;
570 + dragData->operation = XmDROP_MOVE;
573 + Widget tabBar = getTabBarWidget(widget);
574 + if (!tabBar)
575 + return;
577 + if (dragData->reason == XmCR_DROP_SITE_LEAVE_MESSAGE)
579 + ddtInfo.redrawTabBar = 1;
580 + XtAppAddTimeOut(XtWidgetToApplicationContext(widget), 0,
581 + redrawTabBarProc, tabBar);
582 + return;
585 + ddtInfo.redrawTabBar = 0; /* for redrawTabBarProc: don't redraw tab bar, we'll take care */
587 + /* get target tab and side */
588 + Widget tab = widget;
589 + enum tabSide tabSide;
591 + getClosestTab(widget, dragData->x, &tab, &tabSide);
593 + /* calculate position and dimensions for the insertion site */
594 + int spacing = 0;
595 + XtVaGetValues(tabBar, XmNspacing, &spacing, NULL);
597 + XWindowAttributes attrs;
598 + XGetWindowAttributes(TheDisplay, XtWindow(tab), &attrs);
600 + const int offset = attrs.y;
601 + const int pixWidth = spacing > 5 ? spacing : 5;
602 + const int pixHeigth = attrs.height + offset + attrs.border_width*2;
603 + int x = tabSide == LEFT_TAB_SIDE
604 + ? attrs.x - offset - pixWidth/2 - (spacing-spacing/2)
605 + : attrs.x + offset - pixWidth/2 + spacing/2 + attrs.border_width*2 + attrs.width;
606 + const int y = attrs.y-offset;
608 + /* adjust position, otherwise insertion site won't be visible */
609 + if (spacing) {
610 + if (x <= 0)
611 + x += pixWidth/2;
612 + else {
613 + XWindowAttributes tabBarAttrs;
614 + XGetWindowAttributes(TheDisplay, XtWindow(tabBar), &tabBarAttrs);
615 + if (x >= tabBarAttrs.width) x -= pixWidth/2;
619 + /* check if the insertion site changed */
620 + if (ddtInfo.lastInsertionPoint == x && lastTabBar == tabBar)
621 + return;
623 + XmRedisplayWidget(tabBar);
624 + ddtInfo.lastInsertionPoint = x;
625 + lastTabBar = tabBar;
627 + /* copy inverted image of the insertion site*/
628 + XGCValues gcVals = {};
629 + GC gc1 = XCreateGC(TheDisplay, XtWindow(tabBar), 0, &gcVals);
630 + gcVals.function = GXnor;
631 + XChangeGC(TheDisplay, gc1, GCFunction, &gcVals);
633 + XCopyArea(TheDisplay, XtWindow(tabBar), XtWindow(tabBar), gc1,
634 + x, y,
635 + pixWidth, pixHeigth,
636 + x, y);
637 + XFreeGC(TheDisplay, gc1);
641 +** initiate document movement when tabs are dragged into
642 +** the text area, or another tab.
644 +static void tabDropProc(Widget widget, XtPointer client_data,
645 + XtPointer call_data)
647 + XmDropProcCallback dropData;
648 + Arg args[10];
649 + int n;
650 + Widget dc;
652 + dropData = (XmDropProcCallback) call_data;
653 + dc = dropData->dragContext;
655 + n = 0;
656 + if (!ddtInfo.draggedWindow)
658 + dropData->dropSiteStatus = XmDROP_SITE_INVALID;
659 + dropData->operation = XmDROP_NOOP;
660 + XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
661 + XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
662 + XmDropTransferStart(dc, args, n);
663 + return;
665 + else
667 + dropData->dropSiteStatus = XmDROP_SITE_VALID;
668 + dropData->operation = XmDROP_MOVE;
669 + XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_SUCCESS); n++;
670 + XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
671 + XmDropTransferStart(dc, args, n);
674 + ddtInfo.sideToDropTab = RIGHT_TAB_SIDE;
676 + /* determine the target tab based on the drop-zone:
677 + 1. text area or another tab: it's the one,
678 + 2. tab bar gutter: the right-most tab. */
679 + if (XtIsSubclass(widget, xmPushButtonWidgetClass)
680 + || XtClass(widget) == xmlFolderWidgetClass) {
681 + Widget tabWidget = 0;
682 + getClosestTab(widget, dropData->x, &tabWidget, &ddtInfo.sideToDropTab);
683 + ddtInfo.droppedWindow = TabToWindow(tabWidget);
685 + else
686 + ddtInfo.droppedWindow = WidgetToWindow(widget);
688 + if (ddtInfo.droppedWindow != ddtInfo.draggedWindow) {
689 + /* moving document is a big operation, we delay it to avoid
690 + any potential conflicts with the toolkits */
691 + XtAppAddTimeOut(XtWidgetToApplicationContext(widget), 0,
692 + moveTabProc, NULL);
694 + else {
695 + /* it's important to keep this pointer NULL when there is no
696 + dragging, because the drop can happen from another instance
697 + of NEdit, that will lead to crash */
698 + ddtInfo.draggedWindow = NULL;
703 +** register a widget as drop site for tabs, for the purpose
704 +** of moving tabs within and across windows.
706 +void registerDropSite(Widget widget)
708 +#ifndef LESSTIF_VERSION
709 + Arg args[15];
710 + int n = 0;
712 + if (XtIsSubclass(widget, compositeWidgetClass))
713 + XtSetArg(args[n], XmNdropSiteType, XmDROP_SITE_COMPOSITE);
714 + else
715 + XtSetArg(args[n], XmNdropSiteType, XmDROP_SITE_SIMPLE);
716 + n++;
718 + XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_NONE); n++;
719 + XtSetArg(args[n], XmNnumImportTargets, 0); n++;
720 + XtSetArg(args[n], XmNdropSiteOperations, XmDROP_MOVE); n++;
721 + XtSetArg(args[n], XmNdropProc, tabDropProc); n++;
722 + if (GetPerfDragDropTabsAnimation()) {
723 + XtSetArg(args[n], XmNdragProc, tabDragProc); n++;
725 + XmDropSiteRegister (widget, args, n);
726 +#endif /* LESSTIF_VERSION */
730 +** override translation for tab widget on drag [-and-drop].
732 +void addTabDragAction(Widget widget)
734 +#ifndef LESSTIF_VERSION
735 + static XtTranslations table = NULL;
737 + if (table == NULL) {
738 + char *translations =
739 + "#override <Btn2Down>: ProcessDrag() begin_tab_drag()";
740 + table = XtParseTranslationTable(translations);
742 + XtOverrideTranslations(widget, table);
743 +#endif /* LESSTIF_VERSION */
746 diff --quilt /dev/null new/source/tabDragDrop.h
747 --- /dev/null
748 +++ new/source/tabDragDrop.h
749 @@ -0,0 +1,37 @@
750 +/* $Id: tabDragDrop.h,v 1.25 2004/08/20 19:33:21 n8gray Exp $ */
751 +/*******************************************************************************
752 +* *
753 +* tabDragDrop.h -- Nirvana Editor Tab Drag&Drop header file *
754 +* *
755 +* Copyright 2008 The NEdit Developers *
756 +* *
757 +* This is free software; you can redistribute it and/or modify it under the *
758 +* terms of the GNU General Public License as published by the Free Software *
759 +* Foundation; either version 2 of the License, or (at your option) any later *
760 +* version. In addition, you may distribute version of this program linked to *
761 +* Motif or Open Motif. See README for details. *
762 +* *
763 +* This software is distributed in the hope that it will be useful, but WITHOUT *
764 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
765 +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
766 +* for more details. *
767 +* *
768 +* You should have received a copy of the GNU General Public License along with *
769 +* software; if not, write to the Free Software Foundation, Inc., 59 Temple *
770 +* Place, Suite 330, Boston, MA 02111-1307 USA *
771 +* *
772 +* Nirvana Text Editor *
773 +* Nov 11, 2008 *
774 +* *
775 +*******************************************************************************/
777 +#ifndef NEDIT_TAB_DRAG_DROP_H_INCLUDED
778 +#define NEDIT_TAB_DRAG_DROP_H_INCLUDED
780 +#include <X11/Intrinsic.h>
782 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
783 +void registerDropSite(Widget widget);
784 +void addTabDragAction(Widget widget);
786 +#endif /* NEDIT_TAB_DRAG_DROP_H_INCLUDED */
787 diff --quilt old/source/window.c new/source/window.c
788 --- old/source/window.c
789 +++ new/source/window.c
790 @@ -53,6 +53,7 @@ static const char CVSID[] = "$Id: window
791 #include "nedit.bm"
792 #include "n.bm"
793 #include "windowTitle.h"
794 +#include "tabDragDrop.h"
795 #include "interpret.h"
796 #include "rangeset.h"
797 #include "patternMatchData.h"
798 @@ -155,7 +156,6 @@ static WindowInfo *getNextTabWindow(Wind
799 int crossWin, int wrap);
800 static Widget addTab(Widget folder, const char *string);
801 static int compareWindowNames(const void *windowA, const void *windowB);
802 -static int getTabPosition(Widget tab);
803 static Widget manageToolBars(Widget toolBarsForm);
804 static void hideTearOffs(Widget menuPane);
805 static void CloseDocumentWindow(Widget w, WindowInfo *window, XtPointer callData);
806 @@ -613,6 +613,8 @@ WindowInfo *CreateWindow(const char *nam
808 window->tabMenuPane = CreateTabContextMenu(window->tabBar, window);
809 AddTabContextMenuAction(window->tabBar);
810 + if (GetPerfDragDropTabs())
811 + registerDropSite(window->tabBar);
813 /* create an unmanaged composite widget to get the folder
814 widget to hide the 3D shadow for the manager area.
815 @@ -878,6 +880,10 @@ static Widget addTab(Widget folder, cons
816 AddTabContextMenuAction(tab);
817 #endif /* LESSTIF_VERSION */
819 + if (GetPerfDragDropTabs()) {
820 + addTabDragAction(tab);
821 + registerDropSite(tab);
823 return tab;
826 @@ -2404,6 +2410,9 @@ static Widget createTextArea(Widget pare
827 operation and performance will be better without it) */
828 TextDMaintainAbsLineNum(((TextWidget)text)->text.textD, window->showStats);
830 + if (GetPerfDragDropTabs())
831 + registerDropSite(text);
833 return text;
836 @@ -3767,7 +3776,7 @@ static WindowInfo *getNextTabWindow(Wind
837 ** return the integer position of a tab in the tabbar it
838 ** belongs to, or -1 if there's an error, somehow.
840 -static int getTabPosition(Widget tab)
841 +int getTabPosition(Widget tab)
843 WidgetList tabList;
844 int i, tabCount;
845 @@ -3826,6 +3835,10 @@ void RefreshTabState(WindowInfo *win)
846 NULL);
847 XmStringFree(s1);
848 XmStringFree(tipString);
850 + /* set tab as active */
851 + if (IsTopDocument(win))
852 + XmLFolderSetActiveTab(win->tabBar, getTabPosition(win->tab), False);
856 @@ -4784,7 +4797,8 @@ WindowInfo *MoveDocument(WindowInfo *toW
857 /* this should keep the new document window fresh */
858 RaiseDocumentWindow(cloneWin);
859 RefreshTabState(cloneWin);
860 - SortTabBar(cloneWin);
861 + if (GetPrefSortTabs())
862 + SortTabBar(cloneWin);
864 return cloneWin;
866 diff --quilt old/source/window.h new/source/window.h
867 --- old/source/window.h
868 +++ new/source/window.h
869 @@ -65,6 +65,7 @@ int WidgetToPaneIndex(WindowInfo *window
870 void ClosePane(WindowInfo *window);
871 int GetShowTabBar(WindowInfo *window);
872 void ShowTabBar(WindowInfo *window, int state);
873 +int getTabPosition(Widget tab);
874 void ShowStatsLine(WindowInfo *window, int state);
875 void ShowISearchLine(WindowInfo *window, int state);
876 void TempShowISearch(WindowInfo *window, int state);