remove currentDesktop from server request but allow -do macros on new Untitled
[nedit-bw.git] / drag-move.patch
blob5cfd2d00a8a71f8d3aa9a73d2aa254b8915bec3a
1 ---
4 ---
7 ---
9 source/Makefile.common | 1
10 source/menu.c | 2
11 source/preferences.c | 39 ++
12 source/preferences.h | 6
13 source/tabDragDrop.c | 682 +++++++++++++++++++++++++++++++++++++++++++++++++
14 source/tabDragDrop.h | 37 ++
15 source/window.c | 17 +
16 source/window.h | 1
17 8 files changed, 783 insertions(+), 2 deletions(-)
19 diff --quilt old/source/Makefile.common new/source/Makefile.common
20 --- old/source/Makefile.common
21 +++ new/source/Makefile.common
22 @@ -11,6 +11,7 @@ OBJS = nedit.o file.o menu.o window.o se
23 OBJS += hooks.o
24 OBJS += patternMatch.o patternMatchData.o
25 OBJS += ternary_search_tree.o dictionary.o
26 +OBJS += tabDragDrop.o
28 XLTLIB = ../Xlt/libXlt.a
29 XMLLIB = ../Microline/XmL/libXmL.a
30 diff --quilt old/source/menu.c new/source/menu.c
31 --- old/source/menu.c
32 +++ new/source/menu.c
33 @@ -55,6 +55,7 @@ static const char CVSID[] = "$Id: menu.c
34 #include "windowTitle.h"
35 #include "regularExp.h"
36 #include "hooks.h"
37 +#include "tabDragDrop.h"
38 #include "../util/getfiles.h"
39 #include "../util/DialogF.h"
40 #include "../util/misc.h"
41 @@ -605,6 +606,7 @@ static XtActionsRec Actions[] = {
42 {"set_em_tab_dist", setEmTabDistAP},
43 {"set_use_tabs", setUseTabsAP},
44 {"set_fonts", setFontsAP},
45 + {"begin_tab_drag", beginTabDragAP},
46 {"set_language_mode", setLanguageModeAP}
49 diff --quilt old/source/preferences.c new/source/preferences.c
50 --- old/source/preferences.c
51 +++ new/source/preferences.c
52 @@ -318,6 +318,9 @@ static struct prefData {
53 XFontStruct *italicFontStruct;
54 XFontStruct *boldItalicFontStruct;
55 int sortTabs; /* sort tabs alphabetically */
56 + int dragDropTabs; /* enable drag&drop for tabs */
57 + int dragDropTabsCursor; /* enable nice cursor for tabs drag&drop */
58 + int dragDropTabsAnimation; /* enable drag&drop animation */
59 int repositionDialogs; /* w. to reposition dialogs under the pointer */
60 int autoScroll; /* w. to autoscroll near top/bottom of screen */
61 int autoScrollVPadding; /* how close to get before autoscrolling */
62 @@ -1011,6 +1014,12 @@ static PrefDescripRec PrefDescrip[] = {
63 &PrefData.iSearchLine, NULL, True},
64 {"sortTabs", "SortTabs", PREF_BOOLEAN, "False",
65 &PrefData.sortTabs, NULL, True},
66 + {"dragDropTabs", "DragDropTabs", PREF_BOOLEAN, "False",
67 + &PrefData.dragDropTabs, NULL, True},
68 + {"dragDropTabsCursor", "DragDropTabsCursor", PREF_BOOLEAN, "False",
69 + &PrefData.dragDropTabsCursor, NULL, True},
70 + {"dragDropTabsAnimation", "DragDropTabsAnimation", PREF_BOOLEAN, "False",
71 + &PrefData.dragDropTabsAnimation, NULL, True},
72 {"tabBar", "TabBar", PREF_BOOLEAN, "True",
73 &PrefData.tabBar, NULL, True},
74 {"tabBarHideOne", "TabBarHideOne", PREF_BOOLEAN, "True",
75 @@ -1861,6 +1870,36 @@ int GetPrefSortTabs(void)
76 return PrefData.sortTabs;
79 +void SetPerfDragDropTabs(int state)
81 + setIntPref(&PrefData.dragDropTabs, state);
84 +int GetPerfDragDropTabs(void)
86 + return PrefData.dragDropTabs;
89 +void SetPerfDragDropTabsCursor(int state)
91 + setIntPref(&PrefData.dragDropTabsCursor, state);
94 +int GetPerfDragDropTabsCursor(void)
96 + return PrefData.dragDropTabsCursor;
99 +void SetPerfDragDropTabsAnimation(int state)
101 + setIntPref(&PrefData.dragDropTabsAnimation, state);
104 +int GetPerfDragDropTabsAnimation(void)
106 + return PrefData.dragDropTabsAnimation;
109 void SetPrefTabBar(int state)
111 setIntPref(&PrefData.tabBar, state);
112 diff --quilt old/source/preferences.h new/source/preferences.h
113 --- old/source/preferences.h
114 +++ new/source/preferences.h
115 @@ -75,6 +75,12 @@ void SetPrefTabBar(int state);
116 int GetPrefTabBar(void);
117 void SetPrefSortTabs(int state);
118 int GetPrefSortTabs(void);
119 +void SetPerfDragDropTabs(int state);
120 +int GetPerfDragDropTabs(void);
121 +void SetPerfDragDropTabsCursor(int state);
122 +int GetPerfDragDropTabsCursor(void);
123 +void SetPerfDragDropTabsAnimation(int state);
124 +int GetPerfDragDropTabsAnimation(void);
125 void SetPrefTabBarHideOne(int state);
126 int GetPrefTabBarHideOne(void);
127 void SetPrefGlobalTabNavigate(int state);
128 diff --quilt /dev/null new/source/tabDragDrop.c
129 --- /dev/null
130 +++ new/source/tabDragDrop.c
131 @@ -0,0 +1,682 @@
132 +/* $Id: tabDragDrop.c,v 1.25 2004/08/20 19:33:21 n8gray Exp $ */
133 +/*******************************************************************************
134 +* *
135 +* tabDragDrop.c -- Nirvana Editor Tab Drag&Drop implementation file *
136 +* *
137 +* Copyright 2008 The NEdit Developers *
138 +* *
139 +* This is free software; you can redistribute it and/or modify it under the *
140 +* terms of the GNU General Public License as published by the Free Software *
141 +* Foundation; either version 2 of the License, or (at your option) any later *
142 +* version. In addition, you may distribute version of this program linked to *
143 +* Motif or Open Motif. See README for details. *
144 +* *
145 +* This software is distributed in the hope that it will be useful, but WITHOUT *
146 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
147 +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
148 +* for more details. *
149 +* *
150 +* You should have received a copy of the GNU General Public License along with *
151 +* software; if not, write to the Free Software Foundation, Inc., 59 Temple *
152 +* Place, Suite 330, Boston, MA 02111-1307 USA *
153 +* *
154 +* Nirvana Text Editor *
155 +* Nov 11, 2008 *
156 +* *
157 +*******************************************************************************/
159 +#include "tabDragDrop.h"
160 +#include "window.h"
161 +#include "preferences.h"
163 +#include <Xm/DragDrop.h>
164 +#include <Xm/PushB.h>
165 +#include <Xm/Print.h> /* for XmRedisplayWidget */
167 +#include "../Microline/XmL/Folder.h"
169 +#include <stdlib.h>
170 +#include <limits.h>
172 +enum tabSide {LEFT_TAB_SIDE, RIGHT_TAB_SIDE};
174 +static void moveTab(WindowInfo *move, WindowInfo *target, enum tabSide side);
175 +static void dropStart(Widget w, XtPointer client_data, XtPointer call_data);
176 +static Pixmap getMaskPixmap(Pixmap tabPixmap, int pixWidth, int pixHeigth);
177 +static void createTabDragCursor(Widget tabWidget, Widget dragContext);
178 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
179 +static void moveTabProc(XtPointer clientData, XtIntervalId *id);
180 +static void moveTab(WindowInfo *src, WindowInfo *target, enum tabSide side );
181 +static enum tabSide tabSideNeighborAdjustmentNum(int from, int to, enum tabSide tabSide);
182 +static enum tabSide tabSideNeighborAdjustment(Widget widget, enum tabSide tabSide);
183 +static enum tabSide getDropTabSide(Widget widget, int x);
184 +static Widget getTabBarWidget(Widget widget);
185 +static void getClosestTab(Widget w, int x, Widget *closestTab, enum tabSide *tabSide);
186 +static void redrawTabBarProc(XtPointer clientData, XtIntervalId *id);
187 +static void tabDragProc(Widget widget, XtPointer client_data, XtPointer call_data);
188 +static void tabDropProc(Widget widget, XtPointer client_data, XtPointer call_data);
189 +void registerDropSite(Widget widget);
190 +void addTabDragAction(Widget widget);
193 +static struct DragDropTabInfo {
194 + WindowInfo *draggedWindow, *droppedWindow;
195 + enum tabSide sideToDropTab;
196 + int redrawTabBar;
197 + int lastInsertionPoint;
198 +} ddtInfo = {NULL, NULL, RIGHT_TAB_SIDE, 0, -10000};
201 +static struct DragIconInfo {
202 + Pixmap tabPixmap, tabMaskPixmap;
203 + Widget dragIcon;
204 +} diInfo = {0, 0, NULL};
208 +** check if drop was successful (it's unsuccessful if we're dropping from another instance).
210 +static void dropStart(Widget w, XtPointer client_data, XtPointer call_data)
212 + XmDropStartCallback start = (XmDropStartCallback)call_data;
214 + if (start->dropSiteStatus == XmDROP_SITE_INVALID) {
215 + ddtInfo.draggedWindow = NULL;
220 +** creates a mask pixmap for the tab pixmap (tries to delete ugly corners etc)
222 +static Pixmap getMaskPixmap(Pixmap tabPixmap, int pixWidth, int pixHeigth)
224 + XImage *image = 0, *image2 = 0;
225 + Pixmap tabMaskPixmap = 0;
227 + if (!tabPixmap || !pixWidth || !pixHeigth) {
228 + return 0;
231 + tabMaskPixmap = XCreatePixmap(TheDisplay, tabPixmap, pixWidth, pixHeigth, 1);
232 + if (!tabMaskPixmap) {
233 + return 0;
236 + image = XGetImage(TheDisplay, tabPixmap, 0,0, pixWidth, pixHeigth, -1, XYPixmap);
237 + if (!image) {
238 + goto FAILED;
241 + image2 = XGetImage(TheDisplay, tabMaskPixmap, 0,0, pixWidth, pixHeigth, -1, XYPixmap);
242 + if (!image2) {
243 + goto FAILED;
246 + /* now let's try to eat tab's corners */
248 + const unsigned long topLeftPixel = XGetPixel(image, 0, 0);
249 + int x = 0, y = 0;
251 + for (y = 0; y < pixHeigth; ++y) {
252 + for (x = 0; x < pixWidth; ++x) {
253 + XPutPixel(image2, x, y, 1);
257 + /* eat top left corner */
258 + for (y = 0; y < pixHeigth; ++y) {
259 + x = 0;
260 + if (XGetPixel(image, x, y) != topLeftPixel) {
261 + break;
263 + for ( ; x < pixWidth && XGetPixel(image, x, y) == topLeftPixel; ++x) {
264 + XPutPixel(image2, x, y, 0);
268 + if (y == pixHeigth || x == pixWidth) {
269 + goto FAILED; /* ate the whole: something is wrong - no mask */
272 + /* eat top right corner */
273 + for (y = 0; y < pixHeigth; ++y) {
274 + x = pixWidth - 1;
275 + if (XGetPixel(image, x, y) != topLeftPixel) {
276 + break;
278 + for ( ; x > 0 && XGetPixel(image, x, y) == topLeftPixel; --x) {
279 + XPutPixel(image2, x, y, 0);
282 + if (y == 0 || x == 0) {
283 + goto FAILED; /* ate the whole: something is wrong - no mask */
286 + /* ok, done with making the mask image, let's put the result to the mask pixmap */
288 + GC gc = XCreateGC(TheDisplay, tabMaskPixmap, 0, 0);
289 + XPutImage(TheDisplay, tabMaskPixmap, gc, image2, 0,0, 0,0, pixWidth, pixHeigth);
290 + XFreeGC(TheDisplay, gc);
293 + goto DONE;
295 +FAILED:
296 + if (tabMaskPixmap) {
297 + XFreePixmap(TheDisplay, tabMaskPixmap);
299 + tabMaskPixmap = 0;
301 +DONE:
302 + if (image2) {
303 + XDestroyImage(image2);
305 + if (image) {
306 + XDestroyImage(image);
309 + return tabMaskPixmap;
313 +** creates a drag cursor and puts it in drag context, if successful.
315 +static void createTabDragCursor(Widget tabWidget, Widget dragContext)
317 + Arg dropIconArgs[10];
318 + int n;
319 + const Widget tabBarWidget = XtParent(XtParent(tabWidget));
321 + /* get tab pixmap dimensions */
322 + int offset, pixWidth, pixHeigth ;
323 + XWindowAttributes attrs;
324 + XGetWindowAttributes(TheDisplay, XtWindow(tabWidget), &attrs);
326 + offset = attrs.y;
327 + pixWidth = attrs.width + offset * 2 + attrs.border_width * 2;
328 + pixHeigth = attrs.height + offset + attrs.border_width * 2;
330 + /* make a pixmap */
331 + if (diInfo.tabPixmap) {
332 + XFreePixmap(TheDisplay, diInfo.tabPixmap);
334 + diInfo.tabPixmap = XCreatePixmap(TheDisplay, XtWindow(tabBarWidget),
335 + pixWidth, pixHeigth, attrs.depth);
337 + /* copy tab contents */
339 + GC gc = XCreateGC(TheDisplay, diInfo.tabPixmap, 0, 0);
340 + XCopyArea(TheDisplay, XtWindow(tabBarWidget), diInfo.tabPixmap, gc,
341 + attrs.x-offset, attrs.y-offset,
342 + pixWidth, pixHeigth,
343 + 0, 0);
344 + XFreeGC(TheDisplay, gc);
347 + /* make a mask pixmap */
349 + Pixmap tabMaskPixmap = getMaskPixmap(diInfo.tabPixmap, pixWidth, pixHeigth);
350 + if (tabMaskPixmap) {
351 + if (diInfo.tabMaskPixmap) {
352 + XFreePixmap(TheDisplay, diInfo.tabMaskPixmap);
354 + diInfo.tabMaskPixmap = tabMaskPixmap;
358 + /* create a drag icon */
359 + n = 0;
360 + XtSetArg(dropIconArgs[n], XmNpixmap, diInfo.tabPixmap); n++;
361 + XtSetArg(dropIconArgs[n], XmNdepth, attrs.depth); n++;
362 + XtSetArg(dropIconArgs[n], XmNwidth, pixWidth); n++;
363 + XtSetArg(dropIconArgs[n], XmNheight, pixHeigth); n++;
364 + XtSetArg(dropIconArgs[n], XmNhotX, pixWidth / 2); n++;
365 + XtSetArg(dropIconArgs[n], XmNhotY, pixHeigth / 2); n++;
366 + XtSetArg(dropIconArgs[n], XmNattachment, XmATTACH_HOT); n++;
368 + if (diInfo.tabMaskPixmap) {
369 + XtSetArg(dropIconArgs[n], XmNmask, diInfo.tabMaskPixmap); n++;
372 + if (n > 10) {
373 + abort(); /* check if args array length is enough */
376 + if (!diInfo.dragIcon)
378 + /* create drag icon widget */
379 + Widget topLevelWidget = NULL, x = tabWidget;
380 + while ( (x = XtParent(x)) ) { /* the assigment intended here */
381 + topLevelWidget = x;
383 + diInfo.dragIcon = XmCreateDragIcon(topLevelWidget, "tabDragIcon", dropIconArgs, n);
384 + } else {
385 + XtSetValues(diInfo.dragIcon, dropIconArgs, n);
388 + XtVaSetValues(dragContext, XmNsourcePixmapIcon, diInfo.dragIcon, NULL);
389 + XtVaSetValues(dragContext, XmNblendModel, XmBLEND_JUST_SOURCE, NULL);
393 +** action procedure to support drag-n-drop of tabs for moving
394 +** documents.
396 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
398 + Widget dragContext;
400 + if (!GetPerfDragDropTabs()) {
401 + return;
404 + dragContext = XmGetDragContext(w, event->xbutton.time);
405 + XtAddCallback(dragContext, XmNdropStartCallback, dropStart, NULL);
407 + if (GetPerfDragDropTabsCursor()) {
408 + createTabDragCursor(w, dragContext);
411 + /* set the drag window pointer to the tab that is being dragged */
412 + ddtInfo.draggedWindow = TabToWindow(w);
416 +** timer routine that takes care of moving tabs.
418 +static void moveTabProc(XtPointer clientData, XtIntervalId *id)
420 + if (ddtInfo.droppedWindow->shell != ddtInfo.draggedWindow->shell) {
421 + WindowInfo *cloneWin = MoveDocument(ddtInfo.droppedWindow, ddtInfo.draggedWindow);
422 + if (!GetPrefSortTabs()) {
423 + moveTab(cloneWin, ddtInfo.droppedWindow, ddtInfo.sideToDropTab);
425 + } else if (!GetPrefSortTabs()) {
426 + moveTab(ddtInfo.draggedWindow, ddtInfo.droppedWindow, ddtInfo.sideToDropTab);
428 + /* it's important to keep this pointer NULL when there is no
429 + dragging, because the drop can happen from another instance
430 + of NEdit, that will lead to crash */
431 + ddtInfo.draggedWindow = NULL;
435 +** move a tab to one position to the right of another tab.
437 +static void moveTab(WindowInfo *src, WindowInfo *target, enum tabSide side )
439 + int tabCount, i;
440 + WidgetList tabList;
441 + WindowInfo *win;
442 + int srcPos, targetPos;
444 + if (src == target || src->shell != target->shell) {
445 + return;
448 + srcPos = getTabPosition(src->tab);
449 + targetPos = getTabPosition(target->tab);
451 + switch (side) {
452 + case RIGHT_TAB_SIDE:
453 + if (targetPos == srcPos - 1) {
454 + return; /* we are already on the right side */
456 + break;
458 + case LEFT_TAB_SIDE:
459 + if (targetPos == srcPos + 1) {
460 + return; /* we are already on the left side */
462 + break;
465 + if (side == LEFT_TAB_SIDE) {
466 + --targetPos;
469 + XtVaGetValues(target->tabBar, XmNtabWidgetList, &tabList,
470 + XmNtabCount, &tabCount, NULL);
471 + if (srcPos < targetPos) {
472 + /* clockwise rotate, target-tab inclusive */
473 + for (i = srcPos; i < targetPos; i++) {
474 + win = TabToWindow(tabList[i + 1]);
475 + win->tab = tabList[i];
476 + RefreshTabState(win);
478 + src->tab = tabList[targetPos];
479 + RefreshTabState(src);
480 + } else {
481 + /* anti-clockwise rotate */
482 + for (i = srcPos; i > targetPos + 1; i--) {
483 + win = TabToWindow(tabList[i - 1]);
484 + win->tab = tabList[i];
485 + RefreshTabState(win);
487 + src->tab = tabList[targetPos + 1];
488 + RefreshTabState(src);
493 +** "neighbor swap"
494 +** If we're moving a tab to its neighbor, it means we want to swap it,
495 +** no matter which side of the neighbor the tab was dropped to.
497 +static enum tabSide tabSideNeighborAdjustmentNum(int from, int to, enum tabSide tabSide)
499 + if (from == to + 1 || from == to) {
500 + return LEFT_TAB_SIDE;
501 + } else if (from == to - 1) {
502 + return RIGHT_TAB_SIDE;
503 + } else {
504 + return tabSide;
509 +** "neighbor swap"
510 +** If we're moving a tab to its neighbor, it means we want to swap it,
511 +** no matter which side of the neighbor the tab was dropped to.
513 +static enum tabSide tabSideNeighborAdjustment(Widget widget, enum tabSide tabSide)
515 + WindowInfo *windowUnder = 0;
516 + if ( ! XtIsSubclass(widget, xmPushButtonWidgetClass) ) {
517 + return LEFT_TAB_SIDE;
520 + windowUnder = TabToWindow(widget);
522 + /* adjust only if we're moving in the same window */
523 + if (ddtInfo.draggedWindow->shell != windowUnder->shell) {
524 + return tabSide;
527 + return
528 + tabSideNeighborAdjustmentNum(
529 + getTabPosition(ddtInfo.draggedWindow->tab),
530 + getTabPosition(windowUnder->tab),
531 + tabSide
532 + );
536 +** Returns side of the tab from mouse cursor (taking "neighbor swap" into account).
539 +static enum tabSide getDropTabSide(Widget widget, int x)
541 + Dimension tabWidth, left;
542 + if ( ! XtIsSubclass(widget, xmPushButtonWidgetClass) ) {
543 + return LEFT_TAB_SIDE;
545 + XtVaGetValues(widget, XmNwidth, &tabWidth, NULL);
546 + left = x < tabWidth / 2;
547 + return tabSideNeighborAdjustment(widget, left ? LEFT_TAB_SIDE : RIGHT_TAB_SIDE);
551 +** returns tab bar widget for a widget (tab bar or tab).
553 +static Widget getTabBarWidget(Widget widget)
555 + if (XtClass(widget) == xmlFolderWidgetClass) {
556 + return widget;
557 + } else if (XtIsSubclass(widget, xmPushButtonWidgetClass)) {
558 + return XtParent(widget);
559 + } else {
560 + return NULL;
565 +** returns tab and side for a widget (tab bar or tab) and mouse cursor.
567 +static void getClosestTab(Widget w, int x, Widget *closestTab, enum tabSide *tabSide)
569 + const Widget tabBar = getTabBarWidget(w);
570 + if (tabBar == w) {
571 + int numChildren = 0;
572 + Widget *children = 0;
573 + int diff = INT_MAX;
574 + int firstTab = 1;
575 + int i = 0;
577 + XtVaGetValues(tabBar, XmNnumChildren, &numChildren, XmNchildren, &children, NULL);
579 + for (; i<numChildren; ++i) {
580 + if ( XtIsSubclass(children[i], xmPushButtonWidgetClass) ) {
581 + XWindowAttributes attrs;
582 + XGetWindowAttributes(TheDisplay, XtWindow(children[i]), &attrs);
584 + const int distanceToTabCenterSigned = x - (attrs.x+attrs.width/2);
585 + const int distanceToTabCenter = abs(distanceToTabCenterSigned);
586 + if (firstTab || distanceToTabCenter < diff) {
587 + firstTab = 0;
588 + diff = distanceToTabCenter;
589 + *closestTab = children[i];
590 + *tabSide = tabSideNeighborAdjustment(*closestTab,
591 + distanceToTabCenterSigned < 0 ? LEFT_TAB_SIDE : RIGHT_TAB_SIDE);
596 + } else {
597 + *closestTab = w;
598 + *tabSide = getDropTabSide(w, x);
603 +** timer procedure to redraw the tab bar (i.e. to remove insertion site).
604 +** When we can receive DROP_SITE_LEAVE for tab bar and then DROP_SITE_ENTER
605 +** for tab (and vice versa) - in this case we don't want to redraw, to avoid
606 +** flickering. But in the moment when we received DROP_SITE_LEAVE we don't
607 +** know will there be the corresponding DROP_SITE_ENTER, so let it for timer.
609 +static void redrawTabBarProc(XtPointer clientData, XtIntervalId *id)
611 + if (ddtInfo.redrawTabBar) {
612 + Widget tabBar = (Widget)clientData;
613 + XmRedisplayWidget(tabBar);
614 + ddtInfo.lastInsertionPoint = -10000;
619 +** while dragging, display where the tab will be insterted when dropped.
621 +static void tabDragProc(Widget widget, XtPointer client_data,
622 + XtPointer call_data)
624 + static Widget lastTabBar = 0;
625 + Widget tabBar = 0, tab = 0;
626 + enum tabSide tabSide;
627 + int spacing = 0;
628 + int offset, pixWidth, pixHeigth, x, y;
629 + XWindowAttributes attrs;
630 + XmDragProcCallback dragData = (XmDragProcCallback) call_data;
632 + if (!ddtInfo.draggedWindow) {
633 + dragData->dropSiteStatus = XmDROP_SITE_INVALID;
634 + dragData->operation = XmDROP_NOOP;
635 + return;
636 + } else {
637 + dragData->dropSiteStatus = XmDROP_SITE_VALID;
638 + dragData->operation = XmDROP_MOVE;
641 + tabBar = getTabBarWidget(widget);
642 + if (!tabBar) {
643 + return;
646 + if (dragData->reason == XmCR_DROP_SITE_LEAVE_MESSAGE) {
647 + ddtInfo.redrawTabBar = 1;
648 + XtAppAddTimeOut(XtWidgetToApplicationContext(widget), 0,
649 + redrawTabBarProc, tabBar);
650 + return;
653 + ddtInfo.redrawTabBar = 0; /* for redrawTabBarProc: don't redraw tab bar, we'll take care */
655 + /* get target tab and side */
656 + tab = widget;
658 + getClosestTab(widget, dragData->x, &tab, &tabSide);
660 + /* calculate position and dimensions for the insertion site */
661 + XtVaGetValues(tabBar, XmNspacing, &spacing, NULL);
663 + XGetWindowAttributes(TheDisplay, XtWindow(tab), &attrs);
665 + offset = attrs.y;
666 + pixWidth = spacing > 5 ? spacing : 5;
667 + pixHeigth = attrs.height + offset + attrs.border_width * 2;
668 + x = tabSide == LEFT_TAB_SIDE
669 + ? attrs.x - offset - pixWidth / 2 - (spacing - spacing / 2)
670 + : attrs.x + offset - pixWidth / 2 + spacing / 2 + attrs.border_width * 2 + attrs.width;
671 + y = attrs.y-offset;
673 + /* adjust position, otherwise insertion site won't be visible */
674 + if (spacing) {
675 + if (x <= 0) {
676 + x += pixWidth / 2;
677 + } else {
678 + XWindowAttributes tabBarAttrs;
679 + XGetWindowAttributes(TheDisplay, XtWindow(tabBar), &tabBarAttrs);
680 + if (x >= tabBarAttrs.width) {
681 + x -= pixWidth / 2;
686 + /* check if the insertion site changed */
687 + if (ddtInfo.lastInsertionPoint == x && lastTabBar == tabBar) {
688 + return;
691 + XmRedisplayWidget(tabBar);
692 + ddtInfo.lastInsertionPoint = x;
693 + lastTabBar = tabBar;
695 + /* copy inverted image of the insertion site */
697 + XGCValues gcVals = {};
698 + GC gc1 = XCreateGC(TheDisplay, XtWindow(tabBar), 0, &gcVals);
700 + gcVals.function = GXnor;
701 + XChangeGC(TheDisplay, gc1, GCFunction, &gcVals);
703 + XCopyArea(TheDisplay, XtWindow(tabBar), XtWindow(tabBar), gc1,
704 + x, y,
705 + pixWidth, pixHeigth,
706 + x, y);
707 + XFreeGC(TheDisplay, gc1);
712 +** initiate document movement when tabs are dragged into
713 +** the text area, or another tab.
715 +static void tabDropProc(Widget widget, XtPointer client_data,
716 + XtPointer call_data)
718 + XmDropProcCallback dropData;
719 + Widget dc;
720 + Arg args[10];
721 + int n;
723 + dropData = (XmDropProcCallback) call_data;
724 + dc = dropData->dragContext;
726 + n = 0;
727 + if (!ddtInfo.draggedWindow) {
728 + dropData->dropSiteStatus = XmDROP_SITE_INVALID;
729 + dropData->operation = XmDROP_NOOP;
730 + XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
731 + XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
732 + XmDropTransferStart(dc, args, n);
733 + return;
734 + } else {
735 + dropData->dropSiteStatus = XmDROP_SITE_VALID;
736 + dropData->operation = XmDROP_MOVE;
737 + XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_SUCCESS); n++;
738 + XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
739 + XmDropTransferStart(dc, args, n);
742 + ddtInfo.sideToDropTab = RIGHT_TAB_SIDE;
744 + /* determine the target tab based on the drop-zone:
745 + 1. text area or another tab: it's the one,
746 + 2. tab bar gutter: the right-most tab. */
747 + if (XtIsSubclass(widget, xmPushButtonWidgetClass)
748 + || XtClass(widget) == xmlFolderWidgetClass) {
749 + Widget tabWidget = 0;
750 + getClosestTab(widget, dropData->x, &tabWidget, &ddtInfo.sideToDropTab);
751 + ddtInfo.droppedWindow = TabToWindow(tabWidget);
752 + } else {
753 + ddtInfo.droppedWindow = WidgetToWindow(widget);
756 + if (ddtInfo.droppedWindow != ddtInfo.draggedWindow) {
757 + /* moving document is a big operation, we delay it to avoid
758 + any potential conflicts with the toolkits */
759 + XtAppAddTimeOut(XtWidgetToApplicationContext(widget), 0,
760 + moveTabProc, NULL);
761 + } else {
762 + /* it's important to keep this pointer NULL when there is no
763 + dragging, because the drop can happen from another instance
764 + of NEdit, that will lead to crash */
765 + ddtInfo.draggedWindow = NULL;
770 +** register a widget as drop site for tabs, for the purpose
771 +** of moving tabs within and across windows.
773 +void registerDropSite(Widget widget)
775 +#ifndef LESSTIF_VERSION
776 + Arg args[15];
777 + int n = 0;
779 + if (XtIsSubclass(widget, compositeWidgetClass)) {
780 + XtSetArg(args[n], XmNdropSiteType, XmDROP_SITE_COMPOSITE);
781 + } else {
782 + XtSetArg(args[n], XmNdropSiteType, XmDROP_SITE_SIMPLE);
784 + n++;
786 + XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_NONE); n++;
787 + XtSetArg(args[n], XmNnumImportTargets, 0); n++;
788 + XtSetArg(args[n], XmNdropSiteOperations, XmDROP_MOVE); n++;
789 + XtSetArg(args[n], XmNdropProc, tabDropProc); n++;
790 + if (GetPerfDragDropTabsAnimation()) {
791 + XtSetArg(args[n], XmNdragProc, tabDragProc); n++;
793 + XmDropSiteRegister (widget, args, n);
794 +#endif /* LESSTIF_VERSION */
798 +** override translation for tab widget on drag [-and-drop].
800 +void addTabDragAction(Widget widget)
802 +#ifndef LESSTIF_VERSION
803 + static XtTranslations table = NULL;
805 + if (table == NULL) {
806 + const char *translations =
807 + "#override <Btn2Down>: ProcessDrag() begin_tab_drag()";
808 + table = XtParseTranslationTable(translations);
810 + XtOverrideTranslations(widget, table);
811 +#endif /* LESSTIF_VERSION */
814 diff --quilt /dev/null new/source/tabDragDrop.h
815 --- /dev/null
816 +++ new/source/tabDragDrop.h
817 @@ -0,0 +1,37 @@
818 +/* $Id: tabDragDrop.h,v 1.25 2004/08/20 19:33:21 n8gray Exp $ */
819 +/*******************************************************************************
820 +* *
821 +* tabDragDrop.h -- Nirvana Editor Tab Drag&Drop header file *
822 +* *
823 +* Copyright 2008 The NEdit Developers *
824 +* *
825 +* This is free software; you can redistribute it and/or modify it under the *
826 +* terms of the GNU General Public License as published by the Free Software *
827 +* Foundation; either version 2 of the License, or (at your option) any later *
828 +* version. In addition, you may distribute version of this program linked to *
829 +* Motif or Open Motif. See README for details. *
830 +* *
831 +* This software is distributed in the hope that it will be useful, but WITHOUT *
832 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
833 +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
834 +* for more details. *
835 +* *
836 +* You should have received a copy of the GNU General Public License along with *
837 +* software; if not, write to the Free Software Foundation, Inc., 59 Temple *
838 +* Place, Suite 330, Boston, MA 02111-1307 USA *
839 +* *
840 +* Nirvana Text Editor *
841 +* Nov 11, 2008 *
842 +* *
843 +*******************************************************************************/
845 +#ifndef NEDIT_TAB_DRAG_DROP_H_INCLUDED
846 +#define NEDIT_TAB_DRAG_DROP_H_INCLUDED
848 +#include <X11/Intrinsic.h>
850 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
851 +void registerDropSite(Widget widget);
852 +void addTabDragAction(Widget widget);
854 +#endif /* NEDIT_TAB_DRAG_DROP_H_INCLUDED */
855 diff --quilt old/source/window.c new/source/window.c
856 --- old/source/window.c
857 +++ new/source/window.c
858 @@ -53,6 +53,7 @@ static const char CVSID[] = "$Id: window
859 #include "nedit.bm"
860 #include "n.bm"
861 #include "windowTitle.h"
862 +#include "tabDragDrop.h"
863 #include "interpret.h"
864 #include "rangeset.h"
865 #include "hooks.h"
866 @@ -156,7 +157,6 @@ static WindowInfo *getNextTabWindow(Wind
867 int crossWin, int wrap);
868 static Widget addTab(Widget folder, const char *string);
869 static int compareWindowNames(const void *windowA, const void *windowB);
870 -static int getTabPosition(Widget tab);
871 static Widget manageToolBars(Widget toolBarsForm);
872 static void hideTearOffs(Widget menuPane);
873 static void CloseDocumentWindow(Widget w, WindowInfo *window, XtPointer callData);
874 @@ -614,6 +614,8 @@ WindowInfo *CreateWindow(const char *nam
876 window->tabMenuPane = CreateTabContextMenu(window->tabBar, window);
877 AddTabContextMenuAction(window->tabBar);
878 + if (GetPerfDragDropTabs())
879 + registerDropSite(window->tabBar);
881 /* create an unmanaged composite widget to get the folder
882 widget to hide the 3D shadow for the manager area.
883 @@ -879,6 +881,10 @@ static Widget addTab(Widget folder, cons
884 AddTabContextMenuAction(tab);
885 #endif /* LESSTIF_VERSION */
887 + if (GetPerfDragDropTabs()) {
888 + addTabDragAction(tab);
889 + registerDropSite(tab);
891 return tab;
894 @@ -2404,6 +2410,9 @@ static Widget createTextArea(Widget pare
895 operation and performance will be better without it) */
896 TextDMaintainAbsLineNum(((TextWidget)text)->text.textD, window->showStats);
898 + if (GetPerfDragDropTabs())
899 + registerDropSite(text);
901 return text;
904 @@ -3759,7 +3768,7 @@ static WindowInfo *getNextTabWindow(Wind
905 ** return the integer position of a tab in the tabbar it
906 ** belongs to, or -1 if there's an error, somehow.
908 -static int getTabPosition(Widget tab)
909 +int getTabPosition(Widget tab)
911 WidgetList tabList;
912 int i, tabCount;
913 @@ -3818,6 +3827,10 @@ void RefreshTabState(WindowInfo *win)
914 NULL);
915 XmStringFree(s1);
916 XmStringFree(tipString);
918 + /* set tab as active */
919 + if (IsTopDocument(win))
920 + XmLFolderSetActiveTab(win->tabBar, getTabPosition(win->tab), False);
924 diff --quilt old/source/window.h new/source/window.h
925 --- old/source/window.h
926 +++ new/source/window.h
927 @@ -65,6 +65,7 @@ int WidgetToPaneIndex(WindowInfo *window
928 void ClosePane(WindowInfo *window);
929 int GetShowTabBar(WindowInfo *window);
930 void ShowTabBar(WindowInfo *window, int state);
931 +int getTabPosition(Widget tab);
932 void ShowStatsLine(WindowInfo *window, int state);
933 void ShowISearchLine(WindowInfo *window, int state);
934 void TempShowISearch(WindowInfo *window, int state);