remove -U_FORTIFY_SOURCE
[nedit-bw.git] / drag-move.patch
blobcc0f258e4891e2895232e8ff392c37cd682a9139
1 ---
4 ---
7 ---
9 source/Makefile.common | 3
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, 784 insertions(+), 3 deletions(-)
19 diff --quilt old/source/Makefile.common new/source/Makefile.common
20 --- old/source/Makefile.common
21 +++ new/source/Makefile.common
22 @@ -9,7 +9,8 @@ OBJS = nedit.o file.o menu.o window.o se
23 highlightData.o interpret.o parse.o smartIndent.o regexConvert.o \
24 rbTree.o windowTitle.o calltips.o server_common.o rangeset.o \
25 patternMatch.o patternMatchData.o \
26 - ternary_search_tree.o dictionary.o
27 + ternary_search_tree.o dictionary.o \
28 + tabDragDrop.o
30 XLTLIB = ../Xlt/libXlt.a
31 XMLLIB = ../Microline/XmL/libXmL.a
32 diff --quilt old/source/menu.c new/source/menu.c
33 --- old/source/menu.c
34 +++ new/source/menu.c
35 @@ -54,6 +54,7 @@ static const char CVSID[] = "$Id: menu.c
36 #include "smartIndent.h"
37 #include "windowTitle.h"
38 #include "regularExp.h"
39 +#include "tabDragDrop.h"
40 #include "../util/getfiles.h"
41 #include "../util/DialogF.h"
42 #include "../util/misc.h"
43 @@ -604,6 +605,7 @@ static XtActionsRec Actions[] = {
44 {"set_em_tab_dist", setEmTabDistAP},
45 {"set_use_tabs", setUseTabsAP},
46 {"set_fonts", setFontsAP},
47 + {"begin_tab_drag", beginTabDragAP},
48 {"set_language_mode", setLanguageModeAP}
51 diff --quilt old/source/preferences.c new/source/preferences.c
52 --- old/source/preferences.c
53 +++ new/source/preferences.c
54 @@ -320,6 +320,9 @@ static struct prefData {
55 XFontStruct *italicFontStruct;
56 XFontStruct *boldItalicFontStruct;
57 int sortTabs; /* sort tabs alphabetically */
58 + int dragDropTabs; /* enable drag&drop for tabs */
59 + int dragDropTabsCursor; /* enable nice cursor for tabs drag&drop */
60 + int dragDropTabsAnimation; /* enable drag&drop animation */
61 int repositionDialogs; /* w. to reposition dialogs under the pointer */
62 int autoScroll; /* w. to autoscroll near top/bottom of screen */
63 int autoScrollVPadding; /* how close to get before autoscrolling */
64 @@ -1013,6 +1016,12 @@ static PrefDescripRec PrefDescrip[] = {
65 &PrefData.iSearchLine, NULL, True},
66 {"sortTabs", "SortTabs", PREF_BOOLEAN, "False",
67 &PrefData.sortTabs, NULL, True},
68 + {"dragDropTabs", "DragDropTabs", PREF_BOOLEAN, "False",
69 + &PrefData.dragDropTabs, NULL, True},
70 + {"dragDropTabsCursor", "DragDropTabsCursor", PREF_BOOLEAN, "False",
71 + &PrefData.dragDropTabsCursor, NULL, True},
72 + {"dragDropTabsAnimation", "DragDropTabsAnimation", PREF_BOOLEAN, "False",
73 + &PrefData.dragDropTabsAnimation, NULL, True},
74 {"tabBar", "TabBar", PREF_BOOLEAN, "True",
75 &PrefData.tabBar, NULL, True},
76 {"tabBarHideOne", "TabBarHideOne", PREF_BOOLEAN, "True",
77 @@ -1863,6 +1872,36 @@ int GetPrefSortTabs(void)
78 return PrefData.sortTabs;
81 +void SetPerfDragDropTabs(int state)
83 + setIntPref(&PrefData.dragDropTabs, state);
86 +int GetPerfDragDropTabs(void)
88 + return PrefData.dragDropTabs;
91 +void SetPerfDragDropTabsCursor(int state)
93 + setIntPref(&PrefData.dragDropTabsCursor, state);
96 +int GetPerfDragDropTabsCursor(void)
98 + return PrefData.dragDropTabsCursor;
101 +void SetPerfDragDropTabsAnimation(int state)
103 + setIntPref(&PrefData.dragDropTabsAnimation, state);
106 +int GetPerfDragDropTabsAnimation(void)
108 + return PrefData.dragDropTabsAnimation;
111 void SetPrefTabBar(int state)
113 setIntPref(&PrefData.tabBar, state);
114 diff --quilt old/source/preferences.h new/source/preferences.h
115 --- old/source/preferences.h
116 +++ new/source/preferences.h
117 @@ -75,6 +75,12 @@ void SetPrefTabBar(int state);
118 int GetPrefTabBar(void);
119 void SetPrefSortTabs(int state);
120 int GetPrefSortTabs(void);
121 +void SetPerfDragDropTabs(int state);
122 +int GetPerfDragDropTabs(void);
123 +void SetPerfDragDropTabsCursor(int state);
124 +int GetPerfDragDropTabsCursor(void);
125 +void SetPerfDragDropTabsAnimation(int state);
126 +int GetPerfDragDropTabsAnimation(void);
127 void SetPrefTabBarHideOne(int state);
128 int GetPrefTabBarHideOne(void);
129 void SetPrefGlobalTabNavigate(int state);
130 diff --quilt /dev/null new/source/tabDragDrop.c
131 --- /dev/null
132 +++ new/source/tabDragDrop.c
133 @@ -0,0 +1,682 @@
134 +/* $Id: tabDragDrop.c,v 1.25 2004/08/20 19:33:21 n8gray Exp $ */
135 +/*******************************************************************************
136 +* *
137 +* tabDragDrop.c -- Nirvana Editor Tab Drag&Drop implementation file *
138 +* *
139 +* Copyright 2008 The NEdit Developers *
140 +* *
141 +* This is free software; you can redistribute it and/or modify it under the *
142 +* terms of the GNU General Public License as published by the Free Software *
143 +* Foundation; either version 2 of the License, or (at your option) any later *
144 +* version. In addition, you may distribute version of this program linked to *
145 +* Motif or Open Motif. See README for details. *
146 +* *
147 +* This software is distributed in the hope that it will be useful, but WITHOUT *
148 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
149 +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
150 +* for more details. *
151 +* *
152 +* You should have received a copy of the GNU General Public License along with *
153 +* software; if not, write to the Free Software Foundation, Inc., 59 Temple *
154 +* Place, Suite 330, Boston, MA 02111-1307 USA *
155 +* *
156 +* Nirvana Text Editor *
157 +* Nov 11, 2008 *
158 +* *
159 +*******************************************************************************/
161 +#include "tabDragDrop.h"
162 +#include "window.h"
163 +#include "preferences.h"
165 +#include <Xm/DragDrop.h>
166 +#include <Xm/PushB.h>
167 +#include <Xm/Print.h> /* for XmRedisplayWidget */
169 +#include "../Microline/XmL/Folder.h"
171 +#include <stdlib.h>
172 +#include <limits.h>
174 +enum tabSide {LEFT_TAB_SIDE, RIGHT_TAB_SIDE};
176 +static void moveTab(WindowInfo *move, WindowInfo *target, enum tabSide side);
177 +static void dropStart(Widget w, XtPointer client_data, XtPointer call_data);
178 +static Pixmap getMaskPixmap(Pixmap tabPixmap, int pixWidth, int pixHeigth);
179 +static void createTabDragCursor(Widget tabWidget, Widget dragContext);
180 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
181 +static void moveTabProc(XtPointer clientData, XtIntervalId *id);
182 +static void moveTab(WindowInfo *src, WindowInfo *target, enum tabSide side );
183 +static enum tabSide tabSideNeighborAdjustmentNum(int from, int to, enum tabSide tabSide);
184 +static enum tabSide tabSideNeighborAdjustment(Widget widget, enum tabSide tabSide);
185 +static enum tabSide getDropTabSide(Widget widget, int x);
186 +static Widget getTabBarWidget(Widget widget);
187 +static void getClosestTab(Widget w, int x, Widget *closestTab, enum tabSide *tabSide);
188 +static void redrawTabBarProc(XtPointer clientData, XtIntervalId *id);
189 +static void tabDragProc(Widget widget, XtPointer client_data, XtPointer call_data);
190 +static void tabDropProc(Widget widget, XtPointer client_data, XtPointer call_data);
191 +void registerDropSite(Widget widget);
192 +void addTabDragAction(Widget widget);
195 +static struct DragDropTabInfo {
196 + WindowInfo *draggedWindow, *droppedWindow;
197 + enum tabSide sideToDropTab;
198 + int redrawTabBar;
199 + int lastInsertionPoint;
200 +} ddtInfo = {NULL, NULL, RIGHT_TAB_SIDE, 0, -10000};
203 +static struct DragIconInfo {
204 + Pixmap tabPixmap, tabMaskPixmap;
205 + Widget dragIcon;
206 +} diInfo = {0, 0, NULL};
210 +** check if drop was successful (it's unsuccessful if we're dropping from another instance).
212 +static void dropStart(Widget w, XtPointer client_data, XtPointer call_data)
214 + XmDropStartCallback start = (XmDropStartCallback)call_data;
216 + if (start->dropSiteStatus == XmDROP_SITE_INVALID) {
217 + ddtInfo.draggedWindow = NULL;
222 +** creates a mask pixmap for the tab pixmap (tries to delete ugly corners etc)
224 +static Pixmap getMaskPixmap(Pixmap tabPixmap, int pixWidth, int pixHeigth)
226 + XImage *image = 0, *image2 = 0;
227 + Pixmap tabMaskPixmap = 0;
229 + if (!tabPixmap || !pixWidth || !pixHeigth) {
230 + return 0;
233 + tabMaskPixmap = XCreatePixmap(TheDisplay, tabPixmap, pixWidth, pixHeigth, 1);
234 + if (!tabMaskPixmap) {
235 + return 0;
238 + image = XGetImage(TheDisplay, tabPixmap, 0,0, pixWidth, pixHeigth, -1, XYPixmap);
239 + if (!image) {
240 + goto FAILED;
243 + image2 = XGetImage(TheDisplay, tabMaskPixmap, 0,0, pixWidth, pixHeigth, -1, XYPixmap);
244 + if (!image2) {
245 + goto FAILED;
248 + /* now let's try to eat tab's corners */
250 + const unsigned long topLeftPixel = XGetPixel(image, 0, 0);
251 + int x = 0, y = 0;
253 + for (y = 0; y < pixHeigth; ++y) {
254 + for (x = 0; x < pixWidth; ++x) {
255 + XPutPixel(image2, x, y, 1);
259 + /* eat top left corner */
260 + for (y = 0; y < pixHeigth; ++y) {
261 + x = 0;
262 + if (XGetPixel(image, x, y) != topLeftPixel) {
263 + break;
265 + for ( ; x < pixWidth && XGetPixel(image, x, y) == topLeftPixel; ++x) {
266 + XPutPixel(image2, x, y, 0);
270 + if (y == pixHeigth || x == pixWidth) {
271 + goto FAILED; /* ate the whole: something is wrong - no mask */
274 + /* eat top right corner */
275 + for (y = 0; y < pixHeigth; ++y) {
276 + x = pixWidth - 1;
277 + if (XGetPixel(image, x, y) != topLeftPixel) {
278 + break;
280 + for ( ; x > 0 && XGetPixel(image, x, y) == topLeftPixel; --x) {
281 + XPutPixel(image2, x, y, 0);
284 + if (y == 0 || x == 0) {
285 + goto FAILED; /* ate the whole: something is wrong - no mask */
288 + /* ok, done with making the mask image, let's put the result to the mask pixmap */
290 + GC gc = XCreateGC(TheDisplay, tabMaskPixmap, 0, 0);
291 + XPutImage(TheDisplay, tabMaskPixmap, gc, image2, 0,0, 0,0, pixWidth, pixHeigth);
292 + XFreeGC(TheDisplay, gc);
295 + goto DONE;
297 +FAILED:
298 + if (tabMaskPixmap) {
299 + XFreePixmap(TheDisplay, tabMaskPixmap);
301 + tabMaskPixmap = 0;
303 +DONE:
304 + if (image2) {
305 + XDestroyImage(image2);
307 + if (image) {
308 + XDestroyImage(image);
311 + return tabMaskPixmap;
315 +** creates a drag cursor and puts it in drag context, if successful.
317 +static void createTabDragCursor(Widget tabWidget, Widget dragContext)
319 + Arg dropIconArgs[10];
320 + int n;
321 + const Widget tabBarWidget = XtParent(XtParent(tabWidget));
323 + /* get tab pixmap dimensions */
324 + int offset, pixWidth, pixHeigth ;
325 + XWindowAttributes attrs;
326 + XGetWindowAttributes(TheDisplay, XtWindow(tabWidget), &attrs);
328 + offset = attrs.y;
329 + pixWidth = attrs.width + offset * 2 + attrs.border_width * 2;
330 + pixHeigth = attrs.height + offset + attrs.border_width * 2;
332 + /* make a pixmap */
333 + if (diInfo.tabPixmap) {
334 + XFreePixmap(TheDisplay, diInfo.tabPixmap);
336 + diInfo.tabPixmap = XCreatePixmap(TheDisplay, XtWindow(tabBarWidget),
337 + pixWidth, pixHeigth, attrs.depth);
339 + /* copy tab contents */
341 + GC gc = XCreateGC(TheDisplay, diInfo.tabPixmap, 0, 0);
342 + XCopyArea(TheDisplay, XtWindow(tabBarWidget), diInfo.tabPixmap, gc,
343 + attrs.x-offset, attrs.y-offset,
344 + pixWidth, pixHeigth,
345 + 0, 0);
346 + XFreeGC(TheDisplay, gc);
349 + /* make a mask pixmap */
351 + Pixmap tabMaskPixmap = getMaskPixmap(diInfo.tabPixmap, pixWidth, pixHeigth);
352 + if (tabMaskPixmap) {
353 + if (diInfo.tabMaskPixmap) {
354 + XFreePixmap(TheDisplay, diInfo.tabMaskPixmap);
356 + diInfo.tabMaskPixmap = tabMaskPixmap;
360 + /* create a drag icon */
361 + n = 0;
362 + XtSetArg(dropIconArgs[n], XmNpixmap, diInfo.tabPixmap); n++;
363 + XtSetArg(dropIconArgs[n], XmNdepth, attrs.depth); n++;
364 + XtSetArg(dropIconArgs[n], XmNwidth, pixWidth); n++;
365 + XtSetArg(dropIconArgs[n], XmNheight, pixHeigth); n++;
366 + XtSetArg(dropIconArgs[n], XmNhotX, pixWidth / 2); n++;
367 + XtSetArg(dropIconArgs[n], XmNhotY, pixHeigth / 2); n++;
368 + XtSetArg(dropIconArgs[n], XmNattachment, XmATTACH_HOT); n++;
370 + if (diInfo.tabMaskPixmap) {
371 + XtSetArg(dropIconArgs[n], XmNmask, diInfo.tabMaskPixmap); n++;
374 + if (n > 10) {
375 + abort(); /* check if args array length is enough */
378 + if (!diInfo.dragIcon)
380 + /* create drag icon widget */
381 + Widget topLevelWidget = NULL, x = tabWidget;
382 + while ( (x = XtParent(x)) ) { /* the assigment intended here */
383 + topLevelWidget = x;
385 + diInfo.dragIcon = XmCreateDragIcon(topLevelWidget, "tabDragIcon", dropIconArgs, n);
386 + } else {
387 + XtSetValues(diInfo.dragIcon, dropIconArgs, n);
390 + XtVaSetValues(dragContext, XmNsourcePixmapIcon, diInfo.dragIcon, NULL);
391 + XtVaSetValues(dragContext, XmNblendModel, XmBLEND_JUST_SOURCE, NULL);
395 +** action procedure to support drag-n-drop of tabs for moving
396 +** documents.
398 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
400 + Widget dragContext;
402 + if (!GetPerfDragDropTabs()) {
403 + return;
406 + dragContext = XmGetDragContext(w, event->xbutton.time);
407 + XtAddCallback(dragContext, XmNdropStartCallback, dropStart, NULL);
409 + if (GetPerfDragDropTabsCursor()) {
410 + createTabDragCursor(w, dragContext);
413 + /* set the drag window pointer to the tab that is being dragged */
414 + ddtInfo.draggedWindow = TabToWindow(w);
418 +** timer routine that takes care of moving tabs.
420 +static void moveTabProc(XtPointer clientData, XtIntervalId *id)
422 + if (ddtInfo.droppedWindow->shell != ddtInfo.draggedWindow->shell) {
423 + WindowInfo *cloneWin = MoveDocument(ddtInfo.droppedWindow, ddtInfo.draggedWindow);
424 + if (!GetPrefSortTabs()) {
425 + moveTab(cloneWin, ddtInfo.droppedWindow, ddtInfo.sideToDropTab);
427 + } else if (!GetPrefSortTabs()) {
428 + moveTab(ddtInfo.draggedWindow, ddtInfo.droppedWindow, ddtInfo.sideToDropTab);
430 + /* it's important to keep this pointer NULL when there is no
431 + dragging, because the drop can happen from another instance
432 + of NEdit, that will lead to crash */
433 + ddtInfo.draggedWindow = NULL;
437 +** move a tab to one position to the right of another tab.
439 +static void moveTab(WindowInfo *src, WindowInfo *target, enum tabSide side )
441 + int tabCount, i;
442 + WidgetList tabList;
443 + WindowInfo *win;
444 + int srcPos, targetPos;
446 + if (src == target || src->shell != target->shell) {
447 + return;
450 + srcPos = getTabPosition(src->tab);
451 + targetPos = getTabPosition(target->tab);
453 + switch (side) {
454 + case RIGHT_TAB_SIDE:
455 + if (targetPos == srcPos - 1) {
456 + return; /* we are already on the right side */
458 + break;
460 + case LEFT_TAB_SIDE:
461 + if (targetPos == srcPos + 1) {
462 + return; /* we are already on the left side */
464 + break;
467 + if (side == LEFT_TAB_SIDE) {
468 + --targetPos;
471 + XtVaGetValues(target->tabBar, XmNtabWidgetList, &tabList,
472 + XmNtabCount, &tabCount, NULL);
473 + if (srcPos < targetPos) {
474 + /* clockwise rotate, target-tab inclusive */
475 + for (i = srcPos; i < targetPos; i++) {
476 + win = TabToWindow(tabList[i + 1]);
477 + win->tab = tabList[i];
478 + RefreshTabState(win);
480 + src->tab = tabList[targetPos];
481 + RefreshTabState(src);
482 + } else {
483 + /* anti-clockwise rotate */
484 + for (i = srcPos; i > targetPos + 1; i--) {
485 + win = TabToWindow(tabList[i - 1]);
486 + win->tab = tabList[i];
487 + RefreshTabState(win);
489 + src->tab = tabList[targetPos + 1];
490 + RefreshTabState(src);
495 +** "neighbor swap"
496 +** If we're moving a tab to its neighbor, it means we want to swap it,
497 +** no matter which side of the neighbor the tab was dropped to.
499 +static enum tabSide tabSideNeighborAdjustmentNum(int from, int to, enum tabSide tabSide)
501 + if (from == to + 1 || from == to) {
502 + return LEFT_TAB_SIDE;
503 + } else if (from == to - 1) {
504 + return RIGHT_TAB_SIDE;
505 + } else {
506 + return tabSide;
511 +** "neighbor swap"
512 +** If we're moving a tab to its neighbor, it means we want to swap it,
513 +** no matter which side of the neighbor the tab was dropped to.
515 +static enum tabSide tabSideNeighborAdjustment(Widget widget, enum tabSide tabSide)
517 + WindowInfo *windowUnder = 0;
518 + if ( ! XtIsSubclass(widget, xmPushButtonWidgetClass) ) {
519 + return LEFT_TAB_SIDE;
522 + windowUnder = TabToWindow(widget);
524 + /* adjust only if we're moving in the same window */
525 + if (ddtInfo.draggedWindow->shell != windowUnder->shell) {
526 + return tabSide;
529 + return
530 + tabSideNeighborAdjustmentNum(
531 + getTabPosition(ddtInfo.draggedWindow->tab),
532 + getTabPosition(windowUnder->tab),
533 + tabSide
534 + );
538 +** Returns side of the tab from mouse cursor (taking "neighbor swap" into account).
541 +static enum tabSide getDropTabSide(Widget widget, int x)
543 + Dimension tabWidth, left;
544 + if ( ! XtIsSubclass(widget, xmPushButtonWidgetClass) ) {
545 + return LEFT_TAB_SIDE;
547 + XtVaGetValues(widget, XmNwidth, &tabWidth, NULL);
548 + left = x < tabWidth / 2;
549 + return tabSideNeighborAdjustment(widget, left ? LEFT_TAB_SIDE : RIGHT_TAB_SIDE);
553 +** returns tab bar widget for a widget (tab bar or tab).
555 +static Widget getTabBarWidget(Widget widget)
557 + if (XtClass(widget) == xmlFolderWidgetClass) {
558 + return widget;
559 + } else if (XtIsSubclass(widget, xmPushButtonWidgetClass)) {
560 + return XtParent(widget);
561 + } else {
562 + return NULL;
567 +** returns tab and side for a widget (tab bar or tab) and mouse cursor.
569 +static void getClosestTab(Widget w, int x, Widget *closestTab, enum tabSide *tabSide)
571 + const Widget tabBar = getTabBarWidget(w);
572 + if (tabBar == w) {
573 + int numChildren = 0;
574 + Widget *children = 0;
575 + int diff = INT_MAX;
576 + int firstTab = 1;
577 + int i = 0;
579 + XtVaGetValues(tabBar, XmNnumChildren, &numChildren, XmNchildren, &children, NULL);
581 + for (; i<numChildren; ++i) {
582 + if ( XtIsSubclass(children[i], xmPushButtonWidgetClass) ) {
583 + XWindowAttributes attrs;
584 + XGetWindowAttributes(TheDisplay, XtWindow(children[i]), &attrs);
586 + const int distanceToTabCenterSigned = x - (attrs.x+attrs.width/2);
587 + const int distanceToTabCenter = abs(distanceToTabCenterSigned);
588 + if (firstTab || distanceToTabCenter < diff) {
589 + firstTab = 0;
590 + diff = distanceToTabCenter;
591 + *closestTab = children[i];
592 + *tabSide = tabSideNeighborAdjustment(*closestTab,
593 + distanceToTabCenterSigned < 0 ? LEFT_TAB_SIDE : RIGHT_TAB_SIDE);
598 + } else {
599 + *closestTab = w;
600 + *tabSide = getDropTabSide(w, x);
605 +** timer procedure to redraw the tab bar (i.e. to remove insertion site).
606 +** When we can receive DROP_SITE_LEAVE for tab bar and then DROP_SITE_ENTER
607 +** for tab (and vice versa) - in this case we don't want to redraw, to avoid
608 +** flickering. But in the moment when we received DROP_SITE_LEAVE we don't
609 +** know will there be the corresponding DROP_SITE_ENTER, so let it for timer.
611 +static void redrawTabBarProc(XtPointer clientData, XtIntervalId *id)
613 + if (ddtInfo.redrawTabBar) {
614 + Widget tabBar = (Widget)clientData;
615 + XmRedisplayWidget(tabBar);
616 + ddtInfo.lastInsertionPoint = -10000;
621 +** while dragging, display where the tab will be insterted when dropped.
623 +static void tabDragProc(Widget widget, XtPointer client_data,
624 + XtPointer call_data)
626 + static Widget lastTabBar = 0;
627 + Widget tabBar = 0, tab = 0;
628 + enum tabSide tabSide;
629 + int spacing = 0;
630 + int offset, pixWidth, pixHeigth, x, y;
631 + XWindowAttributes attrs;
632 + XmDragProcCallback dragData = (XmDragProcCallback) call_data;
634 + if (!ddtInfo.draggedWindow) {
635 + dragData->dropSiteStatus = XmDROP_SITE_INVALID;
636 + dragData->operation = XmDROP_NOOP;
637 + return;
638 + } else {
639 + dragData->dropSiteStatus = XmDROP_SITE_VALID;
640 + dragData->operation = XmDROP_MOVE;
643 + tabBar = getTabBarWidget(widget);
644 + if (!tabBar) {
645 + return;
648 + if (dragData->reason == XmCR_DROP_SITE_LEAVE_MESSAGE) {
649 + ddtInfo.redrawTabBar = 1;
650 + XtAppAddTimeOut(XtWidgetToApplicationContext(widget), 0,
651 + redrawTabBarProc, tabBar);
652 + return;
655 + ddtInfo.redrawTabBar = 0; /* for redrawTabBarProc: don't redraw tab bar, we'll take care */
657 + /* get target tab and side */
658 + tab = widget;
660 + getClosestTab(widget, dragData->x, &tab, &tabSide);
662 + /* calculate position and dimensions for the insertion site */
663 + XtVaGetValues(tabBar, XmNspacing, &spacing, NULL);
665 + XGetWindowAttributes(TheDisplay, XtWindow(tab), &attrs);
667 + offset = attrs.y;
668 + pixWidth = spacing > 5 ? spacing : 5;
669 + pixHeigth = attrs.height + offset + attrs.border_width * 2;
670 + x = tabSide == LEFT_TAB_SIDE
671 + ? attrs.x - offset - pixWidth / 2 - (spacing - spacing / 2)
672 + : attrs.x + offset - pixWidth / 2 + spacing / 2 + attrs.border_width * 2 + attrs.width;
673 + y = attrs.y-offset;
675 + /* adjust position, otherwise insertion site won't be visible */
676 + if (spacing) {
677 + if (x <= 0) {
678 + x += pixWidth / 2;
679 + } else {
680 + XWindowAttributes tabBarAttrs;
681 + XGetWindowAttributes(TheDisplay, XtWindow(tabBar), &tabBarAttrs);
682 + if (x >= tabBarAttrs.width) {
683 + x -= pixWidth / 2;
688 + /* check if the insertion site changed */
689 + if (ddtInfo.lastInsertionPoint == x && lastTabBar == tabBar) {
690 + return;
693 + XmRedisplayWidget(tabBar);
694 + ddtInfo.lastInsertionPoint = x;
695 + lastTabBar = tabBar;
697 + /* copy inverted image of the insertion site */
699 + XGCValues gcVals = {};
700 + GC gc1 = XCreateGC(TheDisplay, XtWindow(tabBar), 0, &gcVals);
702 + gcVals.function = GXnor;
703 + XChangeGC(TheDisplay, gc1, GCFunction, &gcVals);
705 + XCopyArea(TheDisplay, XtWindow(tabBar), XtWindow(tabBar), gc1,
706 + x, y,
707 + pixWidth, pixHeigth,
708 + x, y);
709 + XFreeGC(TheDisplay, gc1);
714 +** initiate document movement when tabs are dragged into
715 +** the text area, or another tab.
717 +static void tabDropProc(Widget widget, XtPointer client_data,
718 + XtPointer call_data)
720 + XmDropProcCallback dropData;
721 + Widget dc;
722 + Arg args[10];
723 + int n;
725 + dropData = (XmDropProcCallback) call_data;
726 + dc = dropData->dragContext;
728 + n = 0;
729 + if (!ddtInfo.draggedWindow) {
730 + dropData->dropSiteStatus = XmDROP_SITE_INVALID;
731 + dropData->operation = XmDROP_NOOP;
732 + XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
733 + XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
734 + XmDropTransferStart(dc, args, n);
735 + return;
736 + } else {
737 + dropData->dropSiteStatus = XmDROP_SITE_VALID;
738 + dropData->operation = XmDROP_MOVE;
739 + XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_SUCCESS); n++;
740 + XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
741 + XmDropTransferStart(dc, args, n);
744 + ddtInfo.sideToDropTab = RIGHT_TAB_SIDE;
746 + /* determine the target tab based on the drop-zone:
747 + 1. text area or another tab: it's the one,
748 + 2. tab bar gutter: the right-most tab. */
749 + if (XtIsSubclass(widget, xmPushButtonWidgetClass)
750 + || XtClass(widget) == xmlFolderWidgetClass) {
751 + Widget tabWidget = 0;
752 + getClosestTab(widget, dropData->x, &tabWidget, &ddtInfo.sideToDropTab);
753 + ddtInfo.droppedWindow = TabToWindow(tabWidget);
754 + } else {
755 + ddtInfo.droppedWindow = WidgetToWindow(widget);
758 + if (ddtInfo.droppedWindow != ddtInfo.draggedWindow) {
759 + /* moving document is a big operation, we delay it to avoid
760 + any potential conflicts with the toolkits */
761 + XtAppAddTimeOut(XtWidgetToApplicationContext(widget), 0,
762 + moveTabProc, NULL);
763 + } else {
764 + /* it's important to keep this pointer NULL when there is no
765 + dragging, because the drop can happen from another instance
766 + of NEdit, that will lead to crash */
767 + ddtInfo.draggedWindow = NULL;
772 +** register a widget as drop site for tabs, for the purpose
773 +** of moving tabs within and across windows.
775 +void registerDropSite(Widget widget)
777 +#ifndef LESSTIF_VERSION
778 + Arg args[15];
779 + int n = 0;
781 + if (XtIsSubclass(widget, compositeWidgetClass)) {
782 + XtSetArg(args[n], XmNdropSiteType, XmDROP_SITE_COMPOSITE);
783 + } else {
784 + XtSetArg(args[n], XmNdropSiteType, XmDROP_SITE_SIMPLE);
786 + n++;
788 + XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_NONE); n++;
789 + XtSetArg(args[n], XmNnumImportTargets, 0); n++;
790 + XtSetArg(args[n], XmNdropSiteOperations, XmDROP_MOVE); n++;
791 + XtSetArg(args[n], XmNdropProc, tabDropProc); n++;
792 + if (GetPerfDragDropTabsAnimation()) {
793 + XtSetArg(args[n], XmNdragProc, tabDragProc); n++;
795 + XmDropSiteRegister (widget, args, n);
796 +#endif /* LESSTIF_VERSION */
800 +** override translation for tab widget on drag [-and-drop].
802 +void addTabDragAction(Widget widget)
804 +#ifndef LESSTIF_VERSION
805 + static XtTranslations table = NULL;
807 + if (table == NULL) {
808 + const char *translations =
809 + "#override <Btn2Down>: ProcessDrag() begin_tab_drag()";
810 + table = XtParseTranslationTable(translations);
812 + XtOverrideTranslations(widget, table);
813 +#endif /* LESSTIF_VERSION */
816 diff --quilt /dev/null new/source/tabDragDrop.h
817 --- /dev/null
818 +++ new/source/tabDragDrop.h
819 @@ -0,0 +1,37 @@
820 +/* $Id: tabDragDrop.h,v 1.25 2004/08/20 19:33:21 n8gray Exp $ */
821 +/*******************************************************************************
822 +* *
823 +* tabDragDrop.h -- Nirvana Editor Tab Drag&Drop header file *
824 +* *
825 +* Copyright 2008 The NEdit Developers *
826 +* *
827 +* This is free software; you can redistribute it and/or modify it under the *
828 +* terms of the GNU General Public License as published by the Free Software *
829 +* Foundation; either version 2 of the License, or (at your option) any later *
830 +* version. In addition, you may distribute version of this program linked to *
831 +* Motif or Open Motif. See README for details. *
832 +* *
833 +* This software is distributed in the hope that it will be useful, but WITHOUT *
834 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
835 +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
836 +* for more details. *
837 +* *
838 +* You should have received a copy of the GNU General Public License along with *
839 +* software; if not, write to the Free Software Foundation, Inc., 59 Temple *
840 +* Place, Suite 330, Boston, MA 02111-1307 USA *
841 +* *
842 +* Nirvana Text Editor *
843 +* Nov 11, 2008 *
844 +* *
845 +*******************************************************************************/
847 +#ifndef NEDIT_TAB_DRAG_DROP_H_INCLUDED
848 +#define NEDIT_TAB_DRAG_DROP_H_INCLUDED
850 +#include <X11/Intrinsic.h>
852 +void beginTabDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
853 +void registerDropSite(Widget widget);
854 +void addTabDragAction(Widget widget);
856 +#endif /* NEDIT_TAB_DRAG_DROP_H_INCLUDED */
857 diff --quilt old/source/window.c new/source/window.c
858 --- old/source/window.c
859 +++ new/source/window.c
860 @@ -53,6 +53,7 @@ static const char CVSID[] = "$Id: window
861 #include "nedit.bm"
862 #include "n.bm"
863 #include "windowTitle.h"
864 +#include "tabDragDrop.h"
865 #include "interpret.h"
866 #include "rangeset.h"
867 #include "patternMatchData.h"
868 @@ -155,7 +156,6 @@ static WindowInfo *getNextTabWindow(Wind
869 int crossWin, int wrap);
870 static Widget addTab(Widget folder, const char *string);
871 static int compareWindowNames(const void *windowA, const void *windowB);
872 -static int getTabPosition(Widget tab);
873 static Widget manageToolBars(Widget toolBarsForm);
874 static void hideTearOffs(Widget menuPane);
875 static void CloseDocumentWindow(Widget w, WindowInfo *window, XtPointer callData);
876 @@ -613,6 +613,8 @@ WindowInfo *CreateWindow(const char *nam
878 window->tabMenuPane = CreateTabContextMenu(window->tabBar, window);
879 AddTabContextMenuAction(window->tabBar);
880 + if (GetPerfDragDropTabs())
881 + registerDropSite(window->tabBar);
883 /* create an unmanaged composite widget to get the folder
884 widget to hide the 3D shadow for the manager area.
885 @@ -878,6 +880,10 @@ static Widget addTab(Widget folder, cons
886 AddTabContextMenuAction(tab);
887 #endif /* LESSTIF_VERSION */
889 + if (GetPerfDragDropTabs()) {
890 + addTabDragAction(tab);
891 + registerDropSite(tab);
893 return tab;
896 @@ -2404,6 +2410,9 @@ static Widget createTextArea(Widget pare
897 operation and performance will be better without it) */
898 TextDMaintainAbsLineNum(((TextWidget)text)->text.textD, window->showStats);
900 + if (GetPerfDragDropTabs())
901 + registerDropSite(text);
903 return text;
906 @@ -3767,7 +3776,7 @@ static WindowInfo *getNextTabWindow(Wind
907 ** return the integer position of a tab in the tabbar it
908 ** belongs to, or -1 if there's an error, somehow.
910 -static int getTabPosition(Widget tab)
911 +int getTabPosition(Widget tab)
913 WidgetList tabList;
914 int i, tabCount;
915 @@ -3826,6 +3835,10 @@ void RefreshTabState(WindowInfo *win)
916 NULL);
917 XmStringFree(s1);
918 XmStringFree(tipString);
920 + /* set tab as active */
921 + if (IsTopDocument(win))
922 + XmLFolderSetActiveTab(win->tabBar, getTabPosition(win->tab), False);
926 diff --quilt old/source/window.h new/source/window.h
927 --- old/source/window.h
928 +++ new/source/window.h
929 @@ -65,6 +65,7 @@ int WidgetToPaneIndex(WindowInfo *window
930 void ClosePane(WindowInfo *window);
931 int GetShowTabBar(WindowInfo *window);
932 void ShowTabBar(WindowInfo *window, int state);
933 +int getTabPosition(Widget tab);
934 void ShowStatsLine(WindowInfo *window, int state);
935 void ShowISearchLine(WindowInfo *window, int state);
936 void TempShowISearch(WindowInfo *window, int state);