From 6672180d77defa668092e6bfe15c8873d707a7df Mon Sep 17 00:00:00 2001 From: kojima Date: Tue, 28 Mar 2000 02:30:13 +0000 Subject: [PATCH] removed listbag added tree bag started drag & drop --- WINGs/ChangeLog | 8 + WINGs/Makefile.am | 6 +- WINGs/Makefile.in | 31 +- WINGs/Resources/Makefile.in | 13 +- WINGs/WINGs.h | 27 ++ WINGs/WINGsP.h | 68 ++- WINGs/WUtil.h | 81 +++- WINGs/bagarray.c | 114 +++-- WINGs/baglist.c | 43 +- WINGs/bagtree.c | 838 ++++++++++++++++++++++++++++++++++ WINGs/data.c | 5 +- WINGs/dragdestination.c | 118 +++++ WINGs/dragsource.c | 1042 +++++++++++++++++++++++++++++++++++++++++++ WINGs/wcolorwell.c | 372 ++++++--------- WINGs/wevent.c | 29 +- WINGs/widgets.c | 44 +- WINGs/wtest.c | 3 +- WINGs/wview.c | 31 +- 18 files changed, 2493 insertions(+), 380 deletions(-) create mode 100644 WINGs/bagtree.c create mode 100644 WINGs/dragdestination.c create mode 100644 WINGs/dragsource.c diff --git a/WINGs/ChangeLog b/WINGs/ChangeLog index c9fe2db0..629731e3 100644 --- a/WINGs/ChangeLog +++ b/WINGs/ChangeLog @@ -1,6 +1,14 @@ changes since wmaker 0.61.1: ............................ +- WARNING: semantic of bags has changed! + An index assigned to an item will always keep that index unless + you insert an item before it. + + For example: + bag = WMCreateBag(); + WMSetInBag(bag, 10, "bla"); + That code will put "bla" in index 10, instead of 0, as it used to be. - fixed WMInsertInBag(). It ignored index, and always put the new item at end. - added WMSaveUserDefaults(). - rewrote WMPopUpButton to use WMMenuItem diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index ba05ecc2..36777cb1 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -60,6 +60,8 @@ libWINGs_a_SOURCES = \ WINGs.h \ WINGsP.h \ configuration.c \ + dragdestination.c \ + dragsource.c \ international.c \ notification.c \ selection.c \ @@ -97,7 +99,7 @@ libWINGs_a_SOURCES = \ error.c \ findfile.c \ bagarray.c \ - baglist.c \ + bagtree.c \ connection.c \ data.c \ hashtable.c \ @@ -110,7 +112,7 @@ libWUtil_a_SOURCES = \ WINGs.h \ WINGsP.h \ bagarray.c \ - baglist.c \ + bagtree.c \ connection.c \ data.c \ host.c \ diff --git a/WINGs/Makefile.in b/WINGs/Makefile.in index 69297986..afba8d0a 100644 --- a/WINGs/Makefile.in +++ b/WINGs/Makefile.in @@ -69,6 +69,7 @@ GFXLIBS = @GFXLIBS@ HEADER_SEARCH_PATH = @HEADER_SEARCH_PATH@ ICONEXT = @ICONEXT@ INTLIBS = @INTLIBS@ +LD = @LD@ LIBPL = @LIBPL@ LIBRARY_SEARCH_PATH = @LIBRARY_SEARCH_PATH@ LIBTOOL = @LIBTOOL@ @@ -78,6 +79,7 @@ MAKEINFO = @MAKEINFO@ MOFILES = @MOFILES@ NETLIBS = @NETLIBS@ NLSDIR = @NLSDIR@ +NM = @NM@ OBJDUMP = @OBJDUMP@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ @@ -144,10 +146,10 @@ connect_LDADD = libWUtil.a @LIBRARY_SEARCH_PATH@ @NETLIBS@ @LIBPL@ EXTRA_DIST = logo.xpm BUGS # wbutton.c -libWINGs_a_SOURCES = WINGs.h WINGsP.h configuration.c international.c notification.c selection.c userdefaults.c wapplication.c wappresource.c wballoon.c wbrowser.c wbutton.c wcolor.c wcolorpanel.c wcolorwell.c wevent.c wfilepanel.c wframe.c wfont.c wfontpanel.c widgets.c wlabel.c wlist.c wmenuitem.c wmisc.c wpanel.c wpixmap.c wpopupbutton.c wprogressindicator.c wscroller.c wscrollview.c wslider.c wsplitview.c wtabview.c wtextfield.c wwindow.c wview.c error.c findfile.c bagarray.c baglist.c connection.c data.c hashtable.c host.c memory.c usleep.c +libWINGs_a_SOURCES = WINGs.h WINGsP.h configuration.c dragdestination.c dragsource.c international.c notification.c selection.c userdefaults.c wapplication.c wappresource.c wballoon.c wbrowser.c wbutton.c wcolor.c wcolorpanel.c wcolorwell.c wevent.c wfilepanel.c wframe.c wfont.c wfontpanel.c widgets.c wlabel.c wlist.c wmenuitem.c wmisc.c wpanel.c wpixmap.c wpopupbutton.c wprogressindicator.c wscroller.c wscrollview.c wslider.c wsplitview.c wtabview.c wtextfield.c wwindow.c wview.c error.c findfile.c bagarray.c bagtree.c connection.c data.c hashtable.c host.c memory.c usleep.c -libWUtil_a_SOURCES = WINGs.h WINGsP.h bagarray.c baglist.c connection.c data.c host.c international.c notification.c userdefaults.c wapplication.c wutil.c error.c findfile.c hashtable.c memory.c usleep.c +libWUtil_a_SOURCES = WINGs.h WINGsP.h bagarray.c bagtree.c connection.c data.c host.c international.c notification.c userdefaults.c wapplication.c wutil.c error.c findfile.c hashtable.c memory.c usleep.c INCLUDES = -I$(top_srcdir)/wrlib -I$(top_srcdir)/src -DRESOURCE_PATH=\"$(datadir)/WINGs\" @HEADER_SEARCH_PATH@ -DDEBUG @@ -166,16 +168,17 @@ X_CFLAGS = @X_CFLAGS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ libWINGs_a_LIBADD = -libWINGs_a_OBJECTS = configuration.o international.o notification.o \ -selection.o userdefaults.o wapplication.o wappresource.o wballoon.o \ -wbrowser.o wbutton.o wcolor.o wcolorpanel.o wcolorwell.o wevent.o \ -wfilepanel.o wframe.o wfont.o wfontpanel.o widgets.o wlabel.o wlist.o \ -wmenuitem.o wmisc.o wpanel.o wpixmap.o wpopupbutton.o \ -wprogressindicator.o wscroller.o wscrollview.o wslider.o wsplitview.o \ -wtabview.o wtextfield.o wwindow.o wview.o error.o findfile.o bagarray.o \ -baglist.o connection.o data.o hashtable.o host.o memory.o usleep.o +libWINGs_a_OBJECTS = configuration.o dragdestination.o dragsource.o \ +international.o notification.o selection.o userdefaults.o \ +wapplication.o wappresource.o wballoon.o wbrowser.o wbutton.o wcolor.o \ +wcolorpanel.o wcolorwell.o wevent.o wfilepanel.o wframe.o wfont.o \ +wfontpanel.o widgets.o wlabel.o wlist.o wmenuitem.o wmisc.o wpanel.o \ +wpixmap.o wpopupbutton.o wprogressindicator.o wscroller.o wscrollview.o \ +wslider.o wsplitview.o wtabview.o wtextfield.o wwindow.o wview.o \ +error.o findfile.o bagarray.o bagtree.o connection.o data.o hashtable.o \ +host.o memory.o usleep.o libWUtil_a_LIBADD = -libWUtil_a_OBJECTS = bagarray.o baglist.o connection.o data.o host.o \ +libWUtil_a_OBJECTS = bagarray.o bagtree.o connection.o data.o host.o \ international.o notification.o userdefaults.o wapplication.o wutil.o \ error.o findfile.o hashtable.o memory.o usleep.o AR = ar @@ -217,7 +220,7 @@ DIST_COMMON = README ChangeLog Makefile.am Makefile.in TODO DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) -TAR = tar +TAR = gtar GZIP_ENV = --best SOURCES = $(libWINGs_a_SOURCES) $(libWUtil_a_SOURCES) $(wtest_SOURCES) $(wmquery_SOURCES) $(wmfile_SOURCES) $(fontl_SOURCES) $(testmywidget_SOURCES) $(testcolorpanel_SOURCES) $(connect_SOURCES) OBJECTS = $(libWINGs_a_OBJECTS) $(libWUtil_a_OBJECTS) $(wtest_OBJECTS) $(wmquery_OBJECTS) $(wmfile_OBJECTS) $(fontl_OBJECTS) $(testmywidget_OBJECTS) $(testcolorpanel_OBJECTS) $(connect_OBJECTS) @@ -226,7 +229,7 @@ all: all-redirect .SUFFIXES: .SUFFIXES: .S .c .lo .o .s $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) - cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps WINGs/Makefile + cd $(top_srcdir) && $(AUTOMAKE) --gnu WINGs/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ @@ -481,7 +484,7 @@ distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ - cp -pr $$d/$$file $(distdir)/$$file; \ + cp -pr $$/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ diff --git a/WINGs/Resources/Makefile.in b/WINGs/Resources/Makefile.in index fad136be..92132fad 100644 --- a/WINGs/Resources/Makefile.in +++ b/WINGs/Resources/Makefile.in @@ -107,14 +107,14 @@ DIST_COMMON = Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) -TAR = tar +TAR = gtar GZIP_ENV = --best all: all-redirect .SUFFIXES: $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) - cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps WINGs/Resources/Makefile + cd $(top_srcdir) && $(AUTOMAKE) --gnu WINGs/Resources/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status @@ -146,10 +146,15 @@ distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) subdir = WINGs/Resources distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu WINGs/Resources/Makefile @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ - cp -pr $$d/$$file $(distdir)/$$file; \ + cp -pr $$/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ diff --git a/WINGs/WINGs.h b/WINGs/WINGs.h index 400a4e73..9d3d515a 100644 --- a/WINGs/WINGs.h +++ b/WINGs/WINGs.h @@ -474,6 +474,31 @@ typedef struct WMTabViewDelegate { +typedef struct W_DraggingInfo WMDraggingInfo; + + +typedef struct W_DragSourceProcs { + unsigned (*draggingSourceOperation)(WMView *self, Bool local); + void (*beganDragImage)(WMView *self, WMPixmap *image, WMPoint point); + void (*endedDragImage)(WMView *self, WMPixmap *image, WMPoint point, + Bool deposited); + WMData* (*fetchDragData)(WMView *self, char *type, Bool local); +/* Bool (*ignoreModifierKeysWhileDragging)(WMView *view);*/ +} WMDragSourceProcs; + + + +typedef struct W_DragDestinationProcs { + unsigned (*draggingEntered)(WMView *self, WMDraggingInfo *info); + unsigned (*draggingUpdated)(WMView *self, WMDraggingInfo *info); + void (*draggingExited)(WMView *self, WMDraggingInfo *info); + Bool (*prepareForDragOperation)(WMView *self, WMDraggingInfo *info); + Bool (*performDragOperation)(WMView *self, WMDraggingInfo *info); + void (*concludeDragOperation)(WMView *self, WMDraggingInfo *info); +} WMDragDestinationProcs; + + + /* ...................................................................... */ @@ -727,6 +752,8 @@ WMSize WMGetViewSize(WMView *view); WMPoint WMGetViewPosition(WMView *view); +WMPoint WMGetViewScreenPosition(WMView *view); + WMWidget *WMWidgetOfView(WMView *view); /* notifications */ diff --git a/WINGs/WINGsP.h b/WINGs/WINGsP.h index 57bced92..a66fc0b4 100644 --- a/WINGs/WINGsP.h +++ b/WINGs/WINGsP.h @@ -24,7 +24,7 @@ extern "C" { #define DOUBLE_BUFFER - + #define WC_UserWidget 128 @@ -32,22 +32,11 @@ extern "C" { #define SCROLLER_WIDTH 20 -/* internal messages */ -#define WM_UPDATE_COLORWELL 130 - - -#define WM_USER_MESSAGE 1024 - - -#define SETUP_INTERNAL_MESSAGE(event, scrPtr) \ - event.xclient.type=ClientMessage;\ - event.xclient.display=scrPtr->display;\ - event.xclient.send_event=False;\ - event.xclient.serial=0;\ - event.xclient.format=32;\ - event.xclient.message_type=scrPtr->internalMessage; - + + +#define XDND_VERSION 4 + typedef struct W_Application { char *applicationName; int argc; @@ -101,6 +90,27 @@ typedef struct W_FocusInfo { } W_FocusInfo; + +struct W_DraggingInfo { + Window destinationWindow; + Window sourceWindow; + + WMPoint location; + + unsigned sourceOperation; + WMPixmap *image; + WMPoint imageLocation; + + Time timestamp; + + int protocolVersion; + + /* only valid if in the same app.. should be treated as internal data */ +// WMView *destination; +// WMView *source; +}; + + typedef struct W_Screen { Display *display; int screen; @@ -145,6 +155,8 @@ typedef struct W_Screen { Pixmap stipple; + struct W_DraggingInfo dragInfo; + /* colors */ W_Color *white; W_Color *black; @@ -232,17 +244,26 @@ typedef struct W_Screen { Cursor textCursor; Cursor invisibleCursor; - - Atom internalMessage; /* for ClientMessage */ Atom attribsAtom; /* GNUstepWindowAttributes */ Atom deleteWindowAtom; /* WM_DELETE_WINDOW */ Atom protocolsAtom; /* _XA_WM_PROTOCOLS */ - + Atom clipboardAtom; /* CLIPBOARD */ + Atom xdndAwareAtom; /* XdndAware */ + Atom xdndSelectionAtom; + Atom xdndEnterAtom; + Atom xdndLeaveAtom; + Atom xdndPositionAtom; + Atom xdndDropAtom; + Atom xdndFinishedAtom; + Atom xdndTypeListAtom; + Atom xdndStatusAtom; + + Atom wmStateAtom; /* WM_STATE */ /* stuff for detecting double-clicks */ Time lastClickTime; /* time of last mousedown event */ @@ -302,11 +323,12 @@ typedef struct W_View { WMColor *backColor; -#if 0 + + Atom *droppableTypes; struct W_DragSourceProcs *dragSourceProcs; struct W_DragDestinationProcs *dragDestinationProcs; int helpContext; -#endif + struct { unsigned int realized:1; @@ -329,6 +351,7 @@ typedef struct W_View { unsigned int pendingRelease3:1; unsigned int pendingRelease4:1; unsigned int pendingRelease5:1; + unsigned int xdndHintSet:1; } flags; int refCount; @@ -442,8 +465,6 @@ void W_BroadcastMessage(W_View *targetParent, XEvent *event); void W_DispatchMessage(W_View *target, XEvent *event); -Bool W_CheckInternalMessage(W_Screen *scr, XClientMessageEvent *cev, int event); - void W_SetFocusOfToplevel(W_View *toplevel, W_View *view); W_View *W_FocusedViewOfToplevel(W_View *view); @@ -468,6 +489,7 @@ char *W_GetTextSelection(WMScreen *scr, Atom selection); void W_HandleSelectionEvent(XEvent *event); +void W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event); void W_FlushASAPNotificationQueue(); diff --git a/WINGs/WUtil.h b/WINGs/WUtil.h index d1bc88e9..1630b9b4 100644 --- a/WINGs/WUtil.h +++ b/WINGs/WUtil.h @@ -2,7 +2,7 @@ #define _WUTIL_H_ #include - +#include #include /* SunOS 4.x Blargh.... */ @@ -10,7 +10,6 @@ #define NULL ((void*)0) #endif - /* * Warning: proplist.h #defines BOOL which will clash with the * typedef BOOL in Xmd.h @@ -102,6 +101,12 @@ typedef enum { } WMConnectionState; + +enum { + WBNotFound = INT_MAX /* element was not found in bag */ +}; + + typedef struct W_Bag WMBag; typedef struct W_Data WMData; typedef struct W_HashTable WMHashTable; @@ -139,6 +144,8 @@ typedef struct { void (*releaseKey)(const void *); } WMHashTableCallbacks; + +typedef void *WMBagIterator; typedef struct W_BagFunctions { int (*getItemCount)(WMBag *self); @@ -151,15 +158,17 @@ typedef struct W_BagFunctions { int (*firstInBag)(WMBag *bag, void *item); int (*countInBag)(WMBag *bag, void *item); void *(*replaceInBag)(WMBag *bag, int index, void *item); - void (*sortBag)(WMBag *bag, int (*comparer)(const void*, const void*)); + int (*sortBag)(WMBag *bag, int (*comparer)(const void*, const void*)); void (*emptyBag)(WMBag *bag); void (*freeBag)(WMBag *bag); - WMBag *(*mapBag)(WMBag *bag, void * (*function)(void*)); + void (*mapBag)(WMBag *bag, void (*function)(void*, void*), void *data); int (*findInBag)(WMBag *bag, int (*match)(void*)); - void *(*first)(WMBag *bag, void **ptr); - void *(*last)(WMBag *bag, void **ptr); - void *(*next)(WMBag *bag, void **ptr); - void *(*previous)(WMBag *bag, void **ptr); + void *(*first)(WMBag *bag, WMBagIterator *ptr); + void *(*last)(WMBag *bag, WMBagIterator *ptr); + void *(*next)(WMBag *bag, WMBagIterator *ptr); + void *(*previous)(WMBag *bag, WMBagIterator *ptr); + void *(*iteratorAtIndex)(WMBag *bag, int index, WMBagIterator *ptr); + int (*indexForIterator)(WMBag *bag, WMBagIterator ptr); } W_BagFunctions; @@ -305,14 +314,44 @@ extern const WMHashTableCallbacks WMStringPointerHashCallbacks; /*......................................................................*/ -WMBag* WMCreateArrayBag(int size); -WMBag* WMCreateArrayBagWithDestructor(int size, void (*destructor)(void*)); - - -WMBag *WMCreateListBag(void); -WMBag *WMCreateListBagWithDestructor(void (*destructor)(void*)); +/* + * Array bags use an array to store the elements. + * Item indexes may be any integer number. + * + * Pros: + * Fast [O(1)] access to elements + * Fast [O(1)] push/pop + * + * Cons: + * A little slower [O(n)] for insertion/deletion of elements that + * arent in the end + * Element indexes with large difference will cause large holes + */ +#if 0 +WMBag* WMCreateArrayBag(int initialSize); +WMBag* WMCreateArrayBagWithDestructor(int initialSize, + void (*destructor)(void*)); +#endif +/* + * Tree bags use a red-black tree for storage. + * Item indexes may be any integer number. + * + * Pros: + * O(lg n) insertion/deletion/search + * Good for large numbers of elements with sparse indexes + * + * Cons: + * O(lg n) insertion/deletion/search + * Slow for storing small numbers of elements + */ +WMBag *WMCreateTreeBag(void); +WMBag *WMCreateTreeBagWithDestructor(void (*destructor)(void*)); -#define WMCreateBag(size) WMCreateArrayBag(size) + +#define WMCreateArrayBag(a) WMCreateTreeBag() +#define WMCreateArrayBagWithDestructor(a,d) WMCreateTreeBagWithDestructor(d) + +#define WMCreateBag(size) WMCreateTreeBag() #define WMGetBagItemCount(bag) bag->func.getItemCount(bag) @@ -321,7 +360,8 @@ WMBag *WMCreateListBagWithDestructor(void (*destructor)(void*)); #define WMPutInBag(bag, item) bag->func.putInBag(bag, item) #define WMInsertInBag(bag, index, item) bag->func.insertInBag(bag, index, item) - + +/* this is slow */ #define WMRemoveFromBag(bag, item) bag->func.removeFromBag(bag, item) #define WMDeleteFromBag(bag, index) bag->func.deleteFromBag(bag, index) @@ -331,6 +371,7 @@ WMBag *WMCreateListBagWithDestructor(void (*destructor)(void*)); #define WMCountInBag(bag, item) bag->func.countInBag(bag, item) #define WMReplaceInBag(bag, index, item) bag->func.replaceInBag(bag, index, item) +#define WMSetInBag(bag, index, item) bag->func.replaceInBag(bag, index, item) /* comparer must return: * < 0 if a < b @@ -342,8 +383,8 @@ WMBag *WMCreateListBagWithDestructor(void (*destructor)(void*)); #define WMEmptyBag(bag) bag->func.emptyBag(bag) #define WMFreeBag(bag) bag->func.freeBag(bag) - -#define WMMapBag(bag, function) bag->func.mapBag(bag, function) + +#define WMMapBag(bag, function, cdata) bag->func.mapBag(bag, function, cdata) #define WMGetFirstInBag(bag, item) bag->func.firstInBag(bag, item) @@ -359,6 +400,10 @@ WMBag *WMCreateListBagWithDestructor(void (*destructor)(void*)); #define WMBagPrevious(bag, ptr) bag->func.previous(bag, ptr) +#define WMBagIteratorAtIndex(bag, index, ptr) bag->func.iteratorAtIndex(bag, index, ptr) + +#define WMBagIndexForIterator(bag, ptr) bag->func.indexForIterator(bag, ptr) + /*-------------------------------------------------------------------------*/ diff --git a/WINGs/bagarray.c b/WINGs/bagarray.c index 6f746bab..1d521bcc 100644 --- a/WINGs/bagarray.c +++ b/WINGs/bagarray.c @@ -13,6 +13,10 @@ typedef struct W_ArrayBag { void **items; int size; int count; + + int base; + int first; + int last; } W_ArrayBag; @@ -26,15 +30,17 @@ static void* getFromBag(WMBag *bag, int index); static int firstInBag(WMBag *bag, void *item); static int countInBag(WMBag *bag, void *item); static void* replaceInBag(WMBag *bag, int index, void *item); -static void sortBag(WMBag *bag, int (*comparer)(const void*, const void*)); +static int sortBag(WMBag *bag, int (*comparer)(const void*, const void*)); static void emptyBag(WMBag *bag); static void freeBag(WMBag *bag); -static WMBag* mapBag(WMBag *bag, void *(*function)(void *)); -static int findInBag(WMBag *bag, int (*match)(void*)); +static void mapBag(WMBag *bag, void (*function)(void*, void*), void *data); +static int findInBag(WMBag *bag, int (*match)(void*)); static void* first(WMBag *bag, void **ptr); static void* last(WMBag *bag, void **ptr); static void* next(WMBag *bag, void **ptr); static void* previous(WMBag *bag, void **ptr); +static void* iteratorAtIndex(WMBag *bag, int index, WMBagIterator *ptr); +static int indexForIterator(WMBag *bag, WMBagIterator ptr); static W_BagFunctions arrayFunctions = { @@ -56,21 +62,26 @@ static W_BagFunctions arrayFunctions = { first, last, next, - previous + previous, + iteratorAtIndex, + indexForIterator }; #define ARRAY ((W_ArrayBag*)bag->data) +#define I2O(a, i) ((a)->base + i) + + WMBag* -WMCreateArrayBagWithDestructor(int size, void (*destructor)(void*)) +WMCreateArrayBagWithDestructor(int initialSize, void (*destructor)(void*)) { WMBag *bag; W_ArrayBag *array; + int size; - wassertrv(size > 0, NULL); - + bag = wmalloc(sizeof(WMBag)); array = wmalloc(sizeof(W_ArrayBag)); @@ -80,6 +91,9 @@ WMCreateArrayBagWithDestructor(int size, void (*destructor)(void*)) array->items = wmalloc(sizeof(void*) * size); array->size = size; array->count = 0; + array->first = 0; + array->last = 0; + array->base = 0; bag->func = arrayFunctions; @@ -90,9 +104,9 @@ WMCreateArrayBagWithDestructor(int size, void (*destructor)(void*)) WMBag* -WMCreateArrayBag(int size) +WMCreateArrayBag(int initialSize) { - return WMCreateArrayBagWithDestructor(size, NULL); + return WMCreateArrayBagWithDestructor(initialSize, NULL); } @@ -106,20 +120,18 @@ getItemCount(WMBag *bag) static int appendBag(WMBag *bag, WMBag *appendedBag) { - W_ArrayBag *array1 = ARRAY; - W_ArrayBag *array2 = (W_ArrayBag*)appendedBag->data; + W_ArrayBag *array = (W_ArrayBag*)appendedBag->data; + int ok; + int i; - if (array1->count + array2->count >= array1->size) { - array1->items = - wrealloc(array1->items, sizeof(void*) * (array1->size+array2->count)); - array1->size += array2->count; + for (i = array->first; i <= array->last; i++) { + if (array->items[array->base+i]) { + ok = putInBag(bag, array->items[array->base+i]); + if (!ok) + return 0; + } } - - memcpy(array1->items + array1->count, array2->items, - sizeof(void*) * array2->count); - array1->count += array2->count; - return 1; } @@ -128,7 +140,7 @@ appendBag(WMBag *bag, WMBag *appendedBag) static int putInBag(WMBag *bag, void *item) { - return insertInBag(bag, ARRAY->count, item); + return insertInBag(bag, ARRAY->last+1, item); } @@ -138,19 +150,29 @@ insertInBag(WMBag *bag, int index, void *item) { W_ArrayBag *array = ARRAY; - if (array->count == array->size) { - array->size += 16; + if (I2O(array, index) >= array->size) { + array->size = WMAX(array->size + 16, I2O(array, index)); array->items = wrealloc(array->items, sizeof(void*) * array->size); + memset(array->items + I2O(array, array->last), 0, + sizeof(void*) * (array->size - I2O(array, array->last))); } - - if (index >= 0 && index < array->count) { - memmove(&array->items[index+1], &array->items[index], - (array->count - index) * sizeof(void*)); + + if (index > array->last) { + array->last = index; + } else if (index >= array->first) { + memmove(array->items + I2O(array, index), + array->items + (I2O(array, index) + 1), sizeof(void*)); + array->last++; } else { - /* If index is invalid, place it at end */ - index = array->count; + memmove(array->items, + array->items + (abs(index) - array->base), + sizeof(void*) * (abs(index) - array->base)); + memset(array->items, 0, sizeof(void*) * (abs(index) - array->base)); + array->first = index; + array->base = abs(index); } - array->items[index] = item; + + array->items[array->base + index] = item; array->count++; return 1; @@ -261,10 +283,11 @@ replaceInBag(WMBag *bag, int index, void *item) } -static void +static int sortBag(WMBag *bag, int (*comparer)(const void*, const void*)) { qsort(ARRAY->items, ARRAY->count, sizeof(void*), comparer); + return 1; } @@ -294,20 +317,15 @@ freeBag(WMBag *bag) } -static WMBag* -mapBag(WMBag *bag, void *(*function)(void *)) +static void +mapBag(WMBag *bag, void (*function)(void *, void *), void *clientData) { int i; - void *data; - WMBag *new = WMCreateArrayBagWithDestructor(ARRAY->size, bag->destructor); - for (i = 0; i < ARRAY->count; i++) { - data = (*function)(ARRAY->items[i]); - if (data) - putInBag(new, data); + for (i = 0; i < ARRAY->last; i++) { + if (ARRAY->items[i]) + (*function)(ARRAY->items[i], clientData); } - - return new; } @@ -316,7 +334,7 @@ findInBag(WMBag *bag, int (*match)(void*)) { int i; - for (i = 0; i < ARRAY->count; i++) { + for (i = 0; i < ARRAY->last; i++) { if ((*match)(ARRAY->items[i])) return i; } @@ -384,3 +402,15 @@ previous(WMBag *bag, void **ptr) } + +static void* +iteratorAtIndex(WMBag *bag, int index, WMBagIterator *ptr) +{ +} + + +static int +indexForIterator(WMBag *bag, WMBagIterator ptr) +{ + +} diff --git a/WINGs/baglist.c b/WINGs/baglist.c index 9c7b6285..09f26e9a 100644 --- a/WINGs/baglist.c +++ b/WINGs/baglist.c @@ -12,6 +12,7 @@ typedef struct W_Item { struct W_Item *next; struct W_Item *prev; void *data; + int index; } W_Item; @@ -23,9 +24,6 @@ typedef struct W_ListBag { - - - static int getItemCount(WMBag *self); static int appendBag(WMBag *self, WMBag *bag); static int putInBag(WMBag *self, void *item); @@ -39,12 +37,15 @@ static void *replaceInBag(WMBag *bag, int index, void *item); static void sortBag(WMBag *bag, int (*comparer)(const void*, const void*)); static void emptyBag(WMBag *bag); static void freeBag(WMBag *bag); -static WMBag *mapBag(WMBag *bag, void * (*function)(void*)); +static void mapBag(WMBag *bag, void (*function)(void*, void*), void *data); static int findInBag(WMBag *bag, int (*match)(void*));; -static void *first(WMBag *bag, void **ptr); -static void *last(WMBag *bag, void **ptr); -static void *next(WMBag *bag, void **ptr); -static void *previous(WMBag *bag, void **ptr); +static void *first(WMBag *bag, WMBagIterator *ptr); +static void *last(WMBag *bag, WMBagIterator *ptr); +static void *next(WMBag *bag, WMBagIterator *ptr); +static void *previous(WMBag *bag, WMBagIterator *ptr); +static void *iteratorAtIndex(WMBag *bag, int index, WMBagIterator *ptr); +static int indexForIterator(WMBag *bag, WMBagIterator ptr); + static W_BagFunctions bagFunctions = { getItemCount, @@ -65,7 +66,9 @@ static W_BagFunctions bagFunctions = { first, last, next, - previous + previous, + iteratorAtIndex, + indexForIterator }; @@ -353,14 +356,14 @@ static void freeBag(WMBag *self) } -static WMBag *mapBag(WMBag *self, void * (*function)(void*)) +static WMBag *mapBag(WMBag *self, void * (*function)(void*, void*), void *data) { WMBag *bag = WMCreateListBagWithDestructor(self->destructor); W_Item *ptr = SELF->first; while (ptr) { - if ((*function)(ptr->data)) - putInBag(bag, ptr->data); + (*function)(ptr->data, data); + ptr = ptr->next; } return bag; @@ -386,7 +389,7 @@ static int findInBag(WMBag *self, int (*match)(void*)) -static void *first(WMBag *self, void **ptr) +static void *first(WMBag *self, WMBagIterator *ptr) { *ptr = SELF->first; @@ -398,7 +401,7 @@ static void *first(WMBag *self, void **ptr) -static void *last(WMBag *self, void **ptr) +static void *last(WMBag *self, WMBagIterator *ptr) { *ptr = SELF->last; @@ -410,7 +413,7 @@ static void *last(WMBag *self, void **ptr) -static void *next(WMBag *bag, void **ptr) +static void *next(WMBag *bag, WMBagIterator *ptr) { W_Item *item = *(W_Item**)ptr; @@ -424,7 +427,7 @@ static void *next(WMBag *bag, void **ptr) -static void *previous(WMBag *bag, void **ptr) +static void *previous(WMBag *bag, WMBagIterator *ptr) { W_Item *item = *(W_Item**)ptr; @@ -438,4 +441,12 @@ static void *previous(WMBag *bag, void **ptr) +static void *iteratorAtIndex(WMBag *bag, int index, WMBagIterator *ptr) +{ +} + + +static int indexForIterator(WMBag *bag, WMBagIterator ptr) +{ +} diff --git a/WINGs/bagtree.c b/WINGs/bagtree.c new file mode 100644 index 00000000..0f330489 --- /dev/null +++ b/WINGs/bagtree.c @@ -0,0 +1,838 @@ + + + + +#include +#include + +#include "WUtil.h" + + +typedef struct W_Node { + struct W_Node *parent; + struct W_Node *left; + struct W_Node *right; + int color; + + void *data; + int index; +} W_Node; + + +typedef struct W_TreeBag { + W_Node *root; + + W_Node *nil; /* sentinel */ + + int count; +} W_TreeBag; + + + +static int getItemCount(WMBag *self); +static int appendBag(WMBag *self, WMBag *bag); +static int putInBag(WMBag *self, void *item); +static int insertInBag(WMBag *self, int index, void *item); +static int removeFromBag(WMBag *bag, void *item); +static int deleteFromBag(WMBag *bag, int index); +static void *getFromBag(WMBag *bag, int index); +static int countInBag(WMBag *bag, void *item); +static int firstInBag(WMBag *bag, void *item); +static void *replaceInBag(WMBag *bag, int index, void *item); +static int sortBag(WMBag *bag, int (*comparer)(const void*, const void*)); +static void emptyBag(WMBag *bag); +static void freeBag(WMBag *bag); +static void mapBag(WMBag *bag, void (*function)(void*, void*), void *data); +static int findInBag(WMBag *bag, int (*match)(void*));; +static void *first(WMBag *bag, WMBagIterator *ptr); +static void *last(WMBag *bag, WMBagIterator *ptr); +static void *next(WMBag *bag, WMBagIterator *ptr); +static void *previous(WMBag *bag, WMBagIterator *ptr); +static void *iteratorAtIndex(WMBag *bag, int index, WMBagIterator *ptr); +static int indexForIterator(WMBag *bag, WMBagIterator ptr); + + +static W_BagFunctions bagFunctions = { + getItemCount, + appendBag, + putInBag, + insertInBag, + removeFromBag, + deleteFromBag, + getFromBag, + firstInBag, + countInBag, + replaceInBag, + sortBag, + emptyBag, + freeBag, + mapBag, + findInBag, + first, + last, + next, + previous, + iteratorAtIndex, + indexForIterator +}; + + + + +#define IS_LEFT(node) (node == node->parent->left) +#define IS_RIGHT(node) (node == node->parent->right) + + + +static void leftRotate(W_TreeBag *tree, W_Node *node) +{ + W_Node *node2; + + node2 = node->right; + node->right = node2->left; + + node2->left->parent = node; + + node2->parent = node->parent; + + if (node->parent == tree->nil) { + tree->root = node2; + } else { + if (IS_LEFT(node)) { + node->parent->left = node2; + } else { + node->parent->right = node2; + } + } + node2->left = node; + node->parent = node2; +} + + + +static void rightRotate(W_TreeBag *tree, W_Node *node) +{ + W_Node *node2; + + node2 = node->left; + node->left = node2->right; + + node2->right->parent = node; + + node2->parent = node->parent; + + if (node->parent == tree->nil) { + tree->root = node2; + } else { + if (IS_LEFT(node)) { + node->parent->left = node2; + } else { + node->parent->right = node2; + } + } + node2->right = node; + node->parent = node2; +} + + + +static void treeInsert(W_TreeBag *tree, W_Node *node) +{ + W_Node *y = tree->nil; + W_Node *x = tree->root; + + while (x != tree->nil) { + y = x; + if (node->index < x->index) + x = x->left; + else + x = x->right; + } + node->parent = y; + if (y == tree->nil) + tree->root = node; + else if (node->index < y->index) + y->left = node; + else + y->right = node; +} + + +static void rbTreeInsert(W_TreeBag *tree, W_Node *node) +{ + W_Node *y; + + treeInsert(tree, node); + + node->color = 'R'; + + while (node != tree->root && node->parent->color == 'R') { + if (IS_LEFT(node->parent)) { + y = node->parent->parent->right; + + if (y->color == 'R') { + + node->parent->color = 'B'; + y->color = 'B'; + node->parent->parent->color = 'R'; + node = node->parent->parent; + + } else { + if (IS_RIGHT(node)) { + node = node->parent; + leftRotate(tree, node); + } + node->parent->color = 'B'; + node->parent->parent->color = 'R'; + rightRotate(tree, node->parent->parent); + } + } else { + y = node->parent->parent->left; + + if (y->color == 'R') { + + node->parent->color = 'B'; + y->color = 'B'; + node->parent->parent->color = 'R'; + node = node->parent->parent; + + } else { + if (IS_LEFT(node)) { + node = node->parent; + rightRotate(tree, node); + } + node->parent->color = 'B'; + node->parent->parent->color = 'R'; + leftRotate(tree, node->parent->parent); + } + } + } + tree->root->color = 'B'; +} + + + +static void rbDeleteFixup(W_TreeBag *tree, W_Node *node) +{ + W_Node *w; + + while (node != tree->root && node->color == 'B') { + if (IS_LEFT(node)) { + w = node->parent->right; + if (w->color == 'R') { + w->color = 'B'; + node->parent->color = 'R'; + leftRotate(tree, node->parent); + w = node->parent->right; + } + if (w->left->color == 'B' && w->right->color == 'B') { + w->color = 'R'; + node = node->parent; + } else { + if (w->right->color == 'B') { + w->left->color = 'B'; + w->color = 'R'; + rightRotate(tree, w); + w = node->parent->right; + } + w->color = node->parent->color; + node->parent->color = 'B'; + w->right->color = 'B'; + leftRotate(tree, node->parent); + node = tree->root; + } + } else { + w = node->parent->left; + if (w->color == 'R') { + w->color = 'B'; + node->parent->color = 'R'; + leftRotate(tree, node->parent); + w = node->parent->left; + } + if (w->left->color == 'B' && w->right->color == 'B') { + w->color = 'R'; + node = node->parent; + } else { + if (w->left->color == 'B') { + w->right->color = 'B'; + w->color = 'R'; + rightRotate(tree, w); + w = node->parent->left; + } + w->color = node->parent->color; + node->parent->color = 'B'; + w->left->color = 'B'; + leftRotate(tree, node->parent); + node = tree->root; + } + } + } + node->color = 'B'; +} + + +static W_Node *treeMinimum(W_Node *node, W_Node *nil) +{ + while (node->left != nil) + node = node->left; + return node; +} + + +static W_Node *treeMaximum(W_Node *node, W_Node *nil) +{ + while (node->right != nil) + node = node->right; + return node; +} + + +static W_Node *treeSuccessor(W_Node *node, W_Node *nil) +{ + W_Node *y; + + if (node->right != nil) { + return treeMinimum(node->right, nil); + } + y = node->parent; + while (y != nil && node == y->right) { + node = y; + y = y->parent; + } + return y; +} + + +static W_Node *treePredecessor(W_Node *node, W_Node *nil) +{ + W_Node *y; + + if (node->left != nil) { + return treeMaximum(node->left, nil); + } + y = node->parent; + while (y != nil && node == y->left) { + node = y; + y = y->parent; + } + return y; +} + + +static W_Node *rbTreeDelete(W_TreeBag *tree, W_Node *node) +{ + W_Node *nil = tree->nil; + W_Node *x, *y; + + if (node->left == nil || node->right == nil) { + y = node; + } else { + y = treeSuccessor(node, nil); + } + + if (y->left != nil) { + x = y->left; + } else { + x = y->right; + } + + x->parent = y->parent; + + if (y->parent == nil) { + tree->root = x; + } else { + if (IS_LEFT(y)) { + y->parent->left = x; + } else { + y->parent->right = x; + } + } + if (y != node) { + node->index = y->index; + node->data = y->data; + } + if (y->color == 'B') { + rbDeleteFixup(tree, x); + } + + return y; +} + + + +static W_Node *treeSearch(W_Node *root, W_Node *nil, int index) +{ + if (root == nil || root->index == index) { + return root; + } + + if (index < root->index) { + return treeSearch(root->left, nil, index); + } else { + return treeSearch(root->right, nil, index); + } +} + + +static W_Node *treeFind(W_Node *root, W_Node *nil, void *data) +{ + W_Node *tmp; + + if (root == nil || root->data == data) + return root; + + tmp = treeFind(root->left, nil, data); + if (tmp != nil) + return tmp; + + tmp = treeFind(root->right, nil, data); + + return tmp; +} + + + + + +#if 0 +static char buf[512]; + +static void printNodes(W_Node *node, W_Node *nil, int depth) +{ + if (node == nil) { + return; + } + + printNodes(node->left, nil, depth+1); + + memset(buf, ' ', depth*2); + buf[depth*2] = 0; + if (IS_LEFT(node)) + printf("%s/(%2i\n", buf, node->index); + else + printf("%s\\(%2i\n", buf, node->index); + + printNodes(node->right, nil, depth+1); +} + + +void PrintTree(WMBag *bag) +{ + W_TreeBag *tree = (W_TreeBag*)bag->data; + + printNodes(tree->root, tree->nil, 0); +} +#endif + + + + +#define SELF ((W_TreeBag*)self->data) + +WMBag *WMCreateTreeBag(void) +{ + return WMCreateTreeBagWithDestructor(NULL); +} + + +WMBag *WMCreateTreeBagWithDestructor(void (*destructor)(void*)) +{ + WMBag *bag; + W_TreeBag *tree; + + bag = wmalloc(sizeof(WMBag)); + + bag->data = tree = wmalloc(sizeof(W_TreeBag)); + memset(tree, 0, sizeof(W_TreeBag)); + + tree->nil = wmalloc(sizeof(W_Node)); + memset(tree->nil, 0, sizeof(W_Node)); + tree->nil->left = tree->nil->right = tree->nil->parent = tree->nil; + tree->nil->index = WBNotFound; + + tree->root = tree->nil; + + bag->destructor = destructor; + + bag->func = bagFunctions; + + return bag; +} + + +static int getItemCount(WMBag *self) +{ + return SELF->count; +} + + +static int appendBag(WMBag *self, WMBag *bag) +{ + WMBagIterator ptr; + void *data; + + for (data = first(bag, &ptr); data != NULL; data = next(bag, &ptr)) { + if (!putInBag(self, data)) + return 0; + } + + return 1; +} + + +static int putInBag(WMBag *self, void *item) +{ + W_Node *ptr; + + ptr = wmalloc(sizeof(W_Node)); + + ptr->data = item; + ptr->index = SELF->count; + ptr->left = SELF->nil; + ptr->right = SELF->nil; + ptr->parent = SELF->nil; + + rbTreeInsert(SELF, ptr); + + SELF->count++; + + return 1; +} + + +static int insertInBag(WMBag *self, int index, void *item) +{ + W_Node *ptr; + + ptr = wmalloc(sizeof(W_Node)); + + ptr->data = item; + ptr->index = index; + ptr->left = SELF->nil; + ptr->right = SELF->nil; + ptr->parent = SELF->nil; + + rbTreeInsert(SELF, ptr); + + while ((ptr = treeSuccessor(ptr, SELF->nil))) { + ptr->index++; + } + + + SELF->count++; + + return 1; +} + + + +static int removeFromBag(WMBag *self, void *item) +{ + W_Node *ptr = treeFind(SELF->root, SELF->nil, item); + + if (ptr != SELF->nil) { + + SELF->count--; + + ptr = rbTreeDelete(SELF, ptr); + free(ptr); + + return 1; + } else { + return 0; + } +} + + +static int deleteFromBag(WMBag *self, int index) +{ + W_Node *ptr = treeSearch(SELF->root, SELF->nil, index); + + if (ptr != SELF->nil) { + + SELF->count--; + + ptr = rbTreeDelete(SELF, ptr); + free(ptr); + + return 1; + } else { + return 0; + } +} + + +static void *getFromBag(WMBag *self, int index) +{ + W_Node *node; + + if (SELF->count>0) + assert(SELF->root != SELF->nil); + + node = treeSearch(SELF->root, SELF->nil, index); + if (node != SELF->nil) + return node->data; + else + return NULL; +} + + + +static int firstInBag(WMBag *self, void *item) +{ + W_Node *node; + + node = treeFind(SELF->root, SELF->nil, item); + if (node != SELF->nil) + return node->index; + else + return WBNotFound; +} + + + +static int treeCount(W_Node *root, W_Node *nil, void *item) +{ + int count = 0; + + if (root == nil) + return 0; + + if (root->data == item) + count++; + + if (root->left != nil) + count += treeCount(root->left, nil, item); + + if (root->right != nil) + count += treeCount(root->right, nil, item); + + return count; +} + + + +static int countInBag(WMBag *self, void *item) +{ + return treeCount(SELF->root, SELF->nil, item); +} + + +static void *replaceInBag(WMBag *self, int index, void *item) +{ + W_Node *ptr = treeSearch(SELF->root, SELF->nil, index); + void *old = NULL; + + if (item == NULL) { + SELF->count--; + + ptr = rbTreeDelete(SELF, ptr); + free(ptr); + } else if (ptr != SELF->nil) { + old = ptr->data; + ptr->data = item; + } else { + insertInBag(self, index, item); + } + + return old; +} + + + +static int sortBag(WMBag *self, int (*comparer)(const void*, const void*)) +{ + assert(0&&"not implemented"); + + return 0; +} + + + + +static void deleteTree(WMBag *self, W_Node *node) +{ + if (node == SELF->nil) + return; + + deleteTree(self, node->left); + + if (self->destructor) + self->destructor(node->data); + + deleteTree(self, node->right); + + free(node); +} + + +static void emptyBag(WMBag *self) +{ + deleteTree(self, SELF->root); + SELF->root = SELF->nil; + SELF->count = 0; +} + + +static void freeBag(WMBag *self) +{ + emptyBag(self); + + free(self); +} + + + +static void mapTree(W_TreeBag *tree, W_Node *node, + void (*function)(void*, void*), void *data) +{ + if (node == tree->nil) + return; + + mapTree(tree, node->left, function, data); + + (*function)(node->data, data); + + mapTree(tree, node->right, function, data); +} + + +static void mapBag(WMBag *self, void (*function)(void*, void*), void *data) +{ + mapTree(SELF, SELF->root, function, data); +} + + + +static int findInTree(W_TreeBag *tree, W_Node *node, int (*function)(void*)) +{ + int index; + + if (node == tree->nil) + return WBNotFound; + + index = findInTree(tree, node->left, function); + if (index != WBNotFound) + return index; + + if ((*function)(node->data)) { + return node->index; + } + + return findInTree(tree, node->right, function); +} + + +static int findInBag(WMBag *self, int (*match)(void*)) +{ + return findInTree(SELF, SELF->root, match); +} + + + + +static void *first(WMBag *self, WMBagIterator *ptr) +{ + W_Node *node; + + node = treeMinimum(SELF->root, SELF->nil); + + if (node == SELF->nil) { + *ptr = NULL; + + return NULL; + } else { + *ptr = node; + + return node->data; + } +} + + + +static void *last(WMBag *self, WMBagIterator *ptr) +{ + + W_Node *node; + + node = treeMaximum(SELF->root, SELF->nil); + + if (node == SELF->nil) { + *ptr = NULL; + + return NULL; + } else { + *ptr = node; + + return node->data; + } +} + + + +static void *next(WMBag *self, WMBagIterator *ptr) +{ + W_Node *node; + + if (*ptr == NULL) + return NULL; + + node = treeSuccessor(*ptr, SELF->nil); + + if (node == SELF->nil) { + *ptr = NULL; + + return NULL; + } else { + *ptr = node; + + return node->data; + } +} + + + +static void *previous(WMBag *self, WMBagIterator *ptr) +{ + W_Node *node; + + if (*ptr == NULL) + return NULL; + + node = treePredecessor(*ptr, SELF->nil); + + + if (node == SELF->nil) { + *ptr = NULL; + + return NULL; + } else { + *ptr = node; + + return node->data; + } +} + + + +static void *iteratorAtIndex(WMBag *self, int index, WMBagIterator *ptr) +{ + W_Node *node; + + node = treeSearch(SELF->root, SELF->nil, index); + + if (node == SELF->nil) { + *ptr = NULL; + return NULL; + } else { + *ptr = node; + return node->data; + } +} + + +static int indexForIterator(WMBag *bag, WMBagIterator ptr) +{ + return ((W_Node*)ptr)->index; +} + diff --git a/WINGs/data.c b/WINGs/data.c index db505ca8..eb5beb0a 100644 --- a/WINGs/data.c +++ b/WINGs/data.c @@ -30,6 +30,7 @@ typedef struct W_Data { unsigned growth; /* How much to grow */ void *bytes; /* Actual data */ unsigned retainCount; + unsigned freeData:1; /* whether the data should be released */ } W_Data; @@ -52,6 +53,7 @@ WMCreateDataWithCapacity(unsigned capacity) /*FOLD00*/ aData->growth = capacity/2 > 0 ? capacity/2 : 1; aData->length = 0; aData->retainCount = 1; + aData->freeData = 1; return aData; } @@ -96,6 +98,7 @@ WMCreateDataWithBytesNoCopy(void *bytes, unsigned length) /*FOLD00*/ aData->growth = length/2 > 0 ? length/2 : 1; aData->bytes = bytes; aData->retainCount = 1; + aData->freeData = 0; return aData; } @@ -125,7 +128,7 @@ WMReleaseData(WMData *aData) /*FOLD00*/ aData->retainCount--; if (aData->retainCount > 0) return; - if (aData->bytes) + if (aData->bytes && aData->freeData) wfree(aData->bytes); wfree(aData); } diff --git a/WINGs/dragdestination.c b/WINGs/dragdestination.c new file mode 100644 index 00000000..06f55eaf --- /dev/null +++ b/WINGs/dragdestination.c @@ -0,0 +1,118 @@ + + +#include + +#include "WINGsP.h" + + +/* dropping */ + +typedef struct W_DNDTargetInfo { + /* data types accepted for drops */ + Atom *dropTypes; + int dropTypeCount; + + +} DNDTargetInfo; + + +static Atom XDNDversion = XDND_VERSION; + + +static void +realizedObserver(void *self, WMNotification *notif) +{ + WMView *view = (WMView*)WMGetNotificationObject(notif); + + XChangeProperty(W_VIEW_SCREEN(view)->display, W_VIEW_DRAWABLE(view), + W_VIEW_SCREEN(view)->xdndAwareAtom, + XA_ATOM, 32, PropModeReplace, + (unsigned char*)&XDNDversion, 1); + + WMRemoveNotificationObserver(self); +} + + +void +W_SetXdndAwareProperty(WMScreen *scr, WMView *view, Atom *types, int typeCount) +{ + Display *dpy = scr->display; + + view = W_TopLevelOfView(view); + + if (!view->flags.xdndHintSet) { + view->flags.xdndHintSet = 1; + + if (view->flags.realized) { + XChangeProperty(dpy, W_VIEW_DRAWABLE(view), scr->xdndAwareAtom, + XA_ATOM, 32, PropModeReplace, + (unsigned char*)&XDNDversion, 1); + } else { + WMAddNotificationObserver(realizedObserver, view, + WMViewRealizedNotification, + /* just use as an id */ + view->dragDestinationProcs); + } + } +} + + + + +WMData* +WMGetDroppedData(WMView *view, WMDraggingInfo *info) +{ + return NULL; +} + + +void +WMRegisterViewForDraggedTypes(WMView *view, char *acceptedTypes[]) +{ + Atom *types; + int typeCount; + int i; + + typeCount = 0; + while (acceptedTypes[typeCount++]); + + types = wmalloc(sizeof(Atom)*(typeCount+1)); + + for (i = 0; i < typeCount; i++) { + types[i] = XInternAtom(W_VIEW_SCREEN(view)->display, + acceptedTypes[i], False); + } + types[i] = 0; + + view->droppableTypes = types; + + W_SetXdndAwareProperty(W_VIEW_SCREEN(view), view, types, typeCount); +} + + +void +WMUnregisterViewDraggedTypes(WMView *view) +{ + if (view->droppableTypes != NULL) + free(view->droppableTypes); + view->droppableTypes = NULL; +} + +/***********************************************************************/ + +void +WMSetViewDragDestinationProcs(WMView *view, WMDragDestinationProcs *procs) +{ + if (view->dragDestinationProcs == NULL) { + free(view->dragDestinationProcs); + view->dragDestinationProcs = wmalloc(sizeof(WMDragDestinationProcs)); + } + *view->dragDestinationProcs = *procs; + + /*XXX fill in non-implemented stuffs */ +} + + + + + diff --git a/WINGs/dragsource.c b/WINGs/dragsource.c new file mode 100644 index 00000000..6b12bba6 --- /dev/null +++ b/WINGs/dragsource.c @@ -0,0 +1,1042 @@ + + +#include +#include + +#include "WINGsP.h" + + + + +#define SPIT(a) puts(a) + + +#define IS_DROPPABLE(view) (view!=NULL && view->droppableTypes!=NULL && \ + view->dragDestinationProcs!=NULL) + + +static Bool _XErrorOccured = False; + + + + +void +WMSetViewDragSourceProcs(WMView *view, WMDragSourceProcs *procs) +{ + if (view->dragSourceProcs) + free(view->dragSourceProcs); + view->dragSourceProcs = wmalloc(sizeof(WMDragSourceProcs)); + + *view->dragSourceProcs = *procs; + + /* XXX fill in non-implemented stuffs */ +} + + +/***********************************************************************/ + + +static int +handleXError(Display *dpy, XErrorEvent *ev) +{ + _XErrorOccured = True; + + return 1; +} + + +static void +protectBlock(Bool begin) +{ + static void *oldHandler = NULL; + + if (begin) { + oldHandler = XSetErrorHandler(handleXError); + } else { + XSetErrorHandler(oldHandler); + } +} + + + + +static Window +makeDragIcon(WMScreen *scr, WMPixmap *pixmap) +{ + Window window; + WMSize size; + unsigned long flags; + XSetWindowAttributes attribs; + Pixmap pix, mask; + + if (!pixmap) { + pixmap = scr->defaultObjectIcon; + } + size = WMGetPixmapSize(pixmap); + pix = pixmap->pixmap; + mask = pixmap->mask; + + flags = CWSaveUnder|CWBackPixmap|CWOverrideRedirect|CWColormap; + attribs.save_under = True; + attribs.background_pixmap = pix; + attribs.override_redirect = True; + attribs.colormap = scr->colormap; + window = XCreateWindow(scr->display, scr->rootWin, 0, 0, size.width, + size.height, 0, scr->depth, InputOutput, + scr->visual, flags, &attribs); + +#ifdef SHAPE + if (mask) { + XShapeCombineMask(dpy, scr->balloon->window, ShapeBounding, 0, 0, mask, + ShapeSet); + } +#endif + + return window; +} + + +static void +slideWindow(Display *dpy, Window win, int srcX, int srcY, int dstX, int dstY) +{ + double x, y, dx, dy; + int i; + int iterations; + + iterations = WMIN(25, WMAX(abs(dstX-srcX), abs(dstY-srcY))); + + x = srcX; + y = srcY; + + dx = (double)(dstX-srcX)/iterations; + dy = (double)(dstY-srcY)/iterations; + + for (i = 0; i <= iterations; i++) { + XMoveWindow(dpy, win, x, y); + XFlush(dpy); + + wusleep(800); + + x += dx; + y += dy; + } +} + + +static Window +findChildInWindow(Display *dpy, Window toplevel, int x, int y) +{ + Window foo, bar; + Window *children; + unsigned nchildren; + int i; + + if (!XQueryTree(dpy, toplevel, &foo, &bar, + &children, &nchildren) || children == NULL) { + return None; + } + + /* first window that contains the point is the one */ + for (i = nchildren-1; i >= 0; i--) { + XWindowAttributes attr; + + if (XGetWindowAttributes(dpy, children[i], &attr) + && attr.map_state == IsViewable + && x >= attr.x && y >= attr.y + && x < attr.x + attr.width && y < attr.y + attr.height) { + Window child; + + child = findChildInWindow(dpy, children[i], + x - attr.x, y - attr.y); + + XFree(children); + + if (!child) + return toplevel; + else + return child; + } + } + + XFree(children); + return None; +} + + +static WMView* +findViewInToplevel(Display *dpy, Window toplevel, int x, int y) +{ + Window child; + + child = findChildInWindow(dpy, toplevel, x, y); + + if (child != None) + return W_GetViewForXWindow(dpy, child); + else + return NULL; +} + + + +static Window +lookForToplevel(WMScreen *scr, Window window, Bool *isAware) +{ + Window toplevel = None; + Atom *atoms; + int j, count; + + *isAware = False; + + atoms = XListProperties(scr->display, window, &count); + for (j = 0; j < count; j++) { + if (atoms[j] == scr->wmStateAtom) { + toplevel = window; + } else if (atoms[j] == scr->xdndAwareAtom) { + *isAware = True; + } + } + if (atoms) + XFree(atoms); + + if (toplevel == None) { + Window *children; + Window foo, bar; + unsigned nchildren; + + if (!XQueryTree(scr->display, window, &foo, &bar, + &children, &nchildren) || children == NULL) { + return None; + } + + for (j = 0; j < nchildren; j++) { + toplevel = lookForToplevel(scr, children[j], isAware); + if (toplevel != None) + break; + } + + XFree(children); + + + } + + return toplevel; +} + + + +static Window +findToplevelUnderDragPointer(WMScreen *scr, int x, int y, Window iconWindow) +{ + Window foo, bar; + Window *children; + unsigned nchildren; + Bool overSomething = False; + int i; + + if (!XQueryTree(scr->display, scr->rootWin, &foo, &bar, + &children, &nchildren) || children == NULL) { + SPIT("couldnt query tree!"); + return None; + } + + /* try to find the window below the iconWindow by traversing + * the whole window list */ + + /* first find the position of the iconWindow */ + for (i = nchildren-1; i >= 0; i--) { + if (children[i] == iconWindow) { + i--; + break; + } + } + if (i <= 0) { + XFree(children); + return scr->rootWin; + } + + /* first window that contains the point is the one */ + for (; i >= 0; i--) { + XWindowAttributes attr; + + if (XGetWindowAttributes(scr->display, children[i], &attr) + && attr.map_state == IsViewable + && x >= attr.x && y >= attr.y + && x < attr.x + attr.width && y < attr.y + attr.height) { + Window toplevel; + Bool isaware; + + overSomething = True; + + toplevel = lookForToplevel(scr, children[i], &isaware); + + XFree(children); + + if (isaware) + return toplevel; + else + return None; + } + } + + XFree(children); + if (!overSomething) + return scr->rootWin; + else + return None; +} + + + + + + +static void +sendClientMessage(Display *dpy, Window win, Atom message, + unsigned data1, unsigned data2, unsigned data3, + unsigned data4, unsigned data5) +{ + XEvent ev; + + ev.type = ClientMessage; + ev.xclient.message_type = message; + ev.xclient.format = 32; + ev.xclient.window = win; + ev.xclient.data.l[0] = data1; + ev.xclient.data.l[1] = data2; + ev.xclient.data.l[2] = data3; + ev.xclient.data.l[3] = data4; + ev.xclient.data.l[4] = data5; + + XSendEvent(dpy, win, False, 0, &ev); + XFlush(dpy); +} + + + + +static unsigned +notifyPosition(WMScreen *scr, WMDraggingInfo *info) +{ + unsigned operation; + + switch (info->sourceOperation) { + default: + operation = None; + break; + } + + sendClientMessage(scr->display, info->destinationWindow, + scr->xdndPositionAtom, + info->sourceWindow, + 0, /* reserved */ + info->location.x<<16|info->location.y, + info->timestamp, + operation/* operation */); + + return 0; +} + + + +static void +notifyDrop(WMScreen *scr, WMDraggingInfo *info) +{ + sendClientMessage(scr->display, info->destinationWindow, + scr->xdndDropAtom, + info->sourceWindow, + 0, /* reserved */ + info->timestamp, + 0, 0); +} + + + +static void +notifyDragLeave(WMScreen *scr, WMDraggingInfo *info) +{ + sendClientMessage(scr->display, info->destinationWindow, + scr->xdndLeaveAtom, + info->sourceWindow, 0, 0, 0, 0); +} + + + +static unsigned +notifyDragEnter(WMScreen *scr, WMDraggingInfo *info) +{ + unsigned d; + + d = XDND_VERSION << 24; + + sendClientMessage(scr->display, info->destinationWindow, + scr->xdndEnterAtom, + info->sourceWindow, d, 0, 0, 0); + + return 0; +} + + + +static void +updateDraggingInfo(WMScreen *scr, WMDraggingInfo *info, + XEvent *event, Window iconWindow) +{ + Window toplevel; + WMSize size; + + size = WMGetPixmapSize(info->image); + + if (event->type == MotionNotify) { + info->imageLocation.x = event->xmotion.x_root-(int)size.width/2; + info->imageLocation.y = event->xmotion.y_root-(int)size.height/2; + + info->location.x = event->xmotion.x_root; + info->location.y = event->xmotion.y_root; + info->timestamp = event->xmotion.time; + + } else if (event->type == ButtonRelease) { + info->imageLocation.x = event->xbutton.x_root-(int)size.width/2; + info->imageLocation.y = event->xbutton.y_root-(int)size.height/2; + + info->location.x = event->xbutton.x_root; + info->location.y = event->xbutton.y_root; + info->timestamp = event->xbutton.time; + } + + toplevel = findToplevelUnderDragPointer(scr, + info->location.x, + info->location.y, + iconWindow); + info->destinationWindow = toplevel; + /* + if (toplevel == None) { + info->destinationWindow = None; + } else if (toplevel == scr->rootWin) { + info->destinationWindow = scr->rootWin; + } else { + Window child; + int x, y; + + XTranslateCoordinates(scr->display, scr->rootWin, toplevel, + info->location.x, info->location.y, + &x, &y, &child); + + child = findChildInWindow(scr->display, toplevel, x, y); + + if (child != None) { + info->destination = W_GetViewForXWindow(scr->display, child); + if (info->destination->droppableTypes == NULL) { + info->destination = NULL; + } else if (info->destination->dragDestinationProcs == NULL) { + info->destination = NULL; + } + } else { + info->destination = NULL; + } + info->destinationWindow = toplevel; + } + */ +} + + + + +static void +processMotion(WMScreen *scr, WMDraggingInfo *info, WMDraggingInfo *oldInfo, + WMRect *rect, unsigned currentAction) +{ + unsigned action; + + if (info->destinationWindow == None) { /* entered an unsupporeted window */ + + if (oldInfo->destinationWindow != None + && oldInfo->destinationWindow != scr->rootWin) { + SPIT("left window"); + + notifyDragLeave(scr, oldInfo); + } + + } else if (info->destinationWindow == scr->rootWin) { + + if (oldInfo->destinationWindow != None + && oldInfo->destinationWindow != scr->rootWin) { + SPIT("left window to root"); + + notifyDragLeave(scr, oldInfo); + } else { + /* nothing */ + } + + } else if (oldInfo->destinationWindow != info->destinationWindow) { + + if (oldInfo->destinationWindow != None + && oldInfo->destinationWindow != scr->rootWin) { + notifyDragLeave(scr, oldInfo); + SPIT("crossed"); + } else { + SPIT("entered window"); + } + + action = notifyDragEnter(scr, info); + + } else { + +#define LEFT_RECT(r, X, Y) (X < r->pos.x || Y < r->pos.y \ + || X >= r->pos.x + r->size.width \ + || Y >= r->pos.y + r->size.height) + + if (rect->size.width == 0 || + (LEFT_RECT(rect, info->location.x, info->location.y))) { + + action = notifyPosition(scr, info); + + rect->size.width = 0; + } + } + + /* little trick to simulate XdndStatus for local dnd */ + /* + if (bla && action != currentAction) { + XEvent ev; + + ev.type = ClientMessage; + ev.xclient.display = scr->display; + ev.xclient.message_type = scr->xdndStatusAtom; + ev.xclient.format = 32; + ev.xclient.window = info->destinationWindow; + ev.xclient.data.l[0] = info->sourceWindow; + ev.xclient.data.l[1] = (action ? 1 : 0); + ev.xclient.data.l[2] = 0; + ev.xclient.data.l[3] = 0; + ev.xclient.data.l[4] = action; + + XPutBackEvent(scr->display, &ev); + }*/ +} + + + + +static void +timeoutCallback(void *data) +{ + wwarning("drag & drop timed out while waiting for response from 0x%x\n", + (unsigned)data); + _XErrorOccured = 1; +} + +/* + * State Machine For Drag Source: + * ------------------------------ + * Events + * State Call Mtn Ent Lea Crs BUp StA StR Fin TO + * 0) idle 1bu - - - - - - - - - + * 1) drag over target - 1au - 2cu 1cbu 5fu 3 4 1w - + * 2) drag over nothing - 2 1bu - - 0 - - 2w - + * 3) drag targ+accept - 3u - 2cu 1cbu 6f 3 4w 0z - + * 4) drag targ+reject - 4u - 2cu 1cbu 0 3w 4 0z - + * 5) waiting status - 5X 5X 5X 5X - 6f 0 0z 0w + * 6) dropped - - - - - - - - 0 0w + * + * Events: + * Call - called WMDragImageFromView() + * Mtn - Motion + * Ent - Enter droppable window + * Lea - Leave droppable window (or rectangle) + * Crs - Leave droppable window (or rectangle) and enter another + * BUp - Button Released + * StA - XdndStatus client msg with Accept drop + * StR - XdndStatus client msg with Reject drop + * Fin - XdndFinish client msg + * TO - timeout + * + * Actions: + * a - send update message + * b - send enter message + * c - send leave message + * d - release drag section info + * e - send drop message + * f - setup timeout + * u - update dragInfo + * + * X - ignore + * w - warn about unexpected reply + * z - abort operation.. unexpected reply + * - shouldnt happen + */ +void +WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], + WMPoint atLocation, WMSize mouseOffset, XEvent *event, + Bool slideBack) +{ + WMScreen *scr = view->screen; + Display *dpy = scr->display; + Window icon; + XEvent ev; + WMSize size; + WMRect rect = {{0,0},{0,0}}; + int ostate = -1; + int state; + int action = -1; + XColor black = {0, 0,0,0, DoRed|DoGreen|DoBlue}; + XColor green = {0x0045b045, 0x4500,0xb000,0x4500, DoRed|DoGreen|DoBlue}; + XColor back = {0, 0xffff,0xffff,0xffff, DoRed|DoGreen|DoBlue}; + WMDraggingInfo dragInfo; + WMDraggingInfo oldDragInfo; + WMHandlerID timer = NULL; + WMData *draggedData = NULL; + + + wassertr(view->dragSourceProcs != NULL); + + + /* prepare icon to be dragged */ + if (image == NULL) + image = scr->defaultObjectIcon; + + size = WMGetPixmapSize(image); + + icon = makeDragIcon(scr, image); + + XMoveWindow(dpy, icon, event->xmotion.x_root-(int)size.width/2, + event->xmotion.y_root-(int)size.height/2); + XMapRaised(dpy, icon); + + + /* init dragging info */ + memset(&dragInfo, 0, sizeof(WMDraggingInfo)); + memset(&oldDragInfo, 0, sizeof(WMDraggingInfo)); + dragInfo.image = image; + dragInfo.sourceWindow = W_VIEW_DRAWABLE(W_TopLevelOfView(view)); + + dragInfo.destinationWindow = dragInfo.sourceWindow; + + dragInfo.location.x = event->xmotion.x_root; + dragInfo.location.y = event->xmotion.y_root; + dragInfo.imageLocation = atLocation; + + + /* start pointer grab */ + XGrabPointer(dpy, scr->rootWin, False, + ButtonPressMask|ButtonReleaseMask|ButtonMotionMask, + GrabModeSync, GrabModeAsync, None, scr->defaultCursor, + CurrentTime); + + XFlush(dpy); + + _XErrorOccured = False; + + /* XXX: take ownership of XdndSelection */ + + + if (view->dragSourceProcs->beganDragImage != NULL) { + view->dragSourceProcs->beganDragImage(view, image, atLocation); + } + + processMotion(scr, &dragInfo, &oldDragInfo, &rect, action); + + state = 1; + + while (state != 6 && state != 0 && !_XErrorOccured) { + XAllowEvents(dpy, SyncPointer, CurrentTime); + WMNextEvent(dpy, &ev); + + switch (ev.type) { + case MotionNotify: + if (state >= 1 && state <= 4) { + while (XCheckTypedEvent(dpy, MotionNotify, &ev)) ; + + protectBlock(True); + + oldDragInfo = dragInfo; + + updateDraggingInfo(scr, &dragInfo, &ev, icon); + + XMoveWindow(dpy, icon, dragInfo.imageLocation.x, + dragInfo.imageLocation.y); + + if (state != 2) { + processMotion(scr, &dragInfo, &oldDragInfo, &rect, action); + } + protectBlock(False); + + /* XXXif entered a different destination, check the operation */ + + switch (state) { + case 1: + if (oldDragInfo.destinationWindow != None + && (dragInfo.destinationWindow == None + || dragInfo.destinationWindow == scr->rootWin)) { + /* left the droppable window */ + state = 2; + action = -1; + } + break; + + case 2: + if (dragInfo.destinationWindow != None) { + state = 1; + action = -1; + } + break; + + case 3: + case 4: + if (oldDragInfo.destinationWindow != None + && (dragInfo.destinationWindow == None + || dragInfo.destinationWindow == scr->rootWin)) { + /* left the droppable window */ + state = 2; + action = -1; + } + break; + } + } + break; + + + case ButtonRelease: + /* if (state >= 1 && state <= 4) */ { + + protectBlock(True); + + oldDragInfo = dragInfo; + + updateDraggingInfo(scr, &dragInfo, &ev, icon); + + XMoveWindow(dpy, icon, dragInfo.imageLocation.x, + dragInfo.imageLocation.y); + + processMotion(scr, &dragInfo, &oldDragInfo, &rect, + action); + + protectBlock(False); + + switch (state) { + case 1: + state = 5; + timer = WMAddTimerHandler(3000, timeoutCallback, + (void*)dragInfo.destinationWindow); + break; + case 2: + state = 0; + break; + case 3: + state = 6; + break; + case 4: + state = 0; + break; + } + } + break; + + + case SelectionRequest: + + draggedData = NULL; + + break; + + case ClientMessage: + if ((state == 1 || state == 3 || state == 4 || state == 5) + && ev.xclient.message_type == scr->xdndStatusAtom + && ev.xclient.window == dragInfo.destinationWindow) { + + if (ev.xclient.data.l[1] & 1) { + puts("got accept msg"); + /* will accept drop */ + switch (state) { + case 1: + case 3: + case 4: + state = 3; + break; + case 5: + if (timer) { + WMDeleteTimerHandler(timer); + timer = NULL; + } + state = 6; + break; + } + if (ev.xclient.data.l[4] == None) { + action = 0; + } else { + action = ev.xclient.data.l[4];/*XXX*/ + } + } else { + puts("got reject msg"); + switch (state) { + case 1: + case 3: + case 4: + state = 4; + break; + case 5: + state = 0; + if (timer) { + WMDeleteTimerHandler(timer); + timer = NULL; + } + break; + } + action = 0; + } + + if (ev.xclient.data.l[1] & (1<<1)) { + rect.pos.x = ev.xclient.data.l[2] >> 16; + rect.pos.y = ev.xclient.data.l[2] & 0xffff; + rect.size.width = ev.xclient.data.l[3] >> 16; + rect.size.height = ev.xclient.data.l[3] & 0xffff; + } else { + rect.size.width = 0; + } + + } else if ((state >= 1 && state <= 5) + && ev.xclient.message_type == scr->xdndFinishedAtom + && ev.xclient.window == dragInfo.destinationWindow) { + + wwarning("drag source received unexpected XdndFinished message from %x", + (unsigned)dragInfo.destinationWindow); + + if (state == 3 || state == 4 || state == 5) { + state = 0; + if (timer) { + WMDeleteTimerHandler(timer); + timer = NULL; + } + } + } + + default: + WMHandleEvent(&ev); + break; + } + + if (ostate != state) { + printf("state changed to %i\n", state); + if (state == 3) { + XRecolorCursor(dpy, scr->defaultCursor, &green, &back); + } else if (ostate == 3) { + XRecolorCursor(dpy, scr->defaultCursor, &black, &back); + } + ostate = state; + } + } + + if (timer) { + WMDeleteTimerHandler(timer); + timer = NULL; + } + + XUngrabPointer(dpy, CurrentTime); + + SPIT("exited main loop"); + + if (_XErrorOccured || state != 6) { + goto cancelled; + } + + assert(dragInfo.destinationWindow != None); + + protectBlock(True); + notifyDrop(scr, &dragInfo); + protectBlock(False); + + if (_XErrorOccured) + goto cancelled; + + + SPIT("dropped"); + /* wait for Finished message and SelectionRequest if not a local drop */ + + + + XDestroyWindow(dpy, icon); + if (view->dragSourceProcs->endedDragImage != NULL) { + view->dragSourceProcs->endedDragImage(view, image, + dragInfo.imageLocation, + True); + } + return; + +cancelled: + if (draggedData) { + WMReleaseData(draggedData); + } + + if (slideBack) { + slideWindow(dpy, icon, + dragInfo.imageLocation.x, dragInfo.imageLocation.y, + atLocation.x, atLocation.y); + } + XDestroyWindow(dpy, icon); + if (view->dragSourceProcs->endedDragImage != NULL) { + view->dragSourceProcs->endedDragImage(view, image, + dragInfo.imageLocation, + False); + } +} + + + + + + + + + + + + + + + + + + +static Atom* +getTypeList(Window window, XClientMessageEvent *event) +{ + int i = 0; + Atom *types = NULL; + + if (event->data.l[1] & 1) { /* > 3 types */ + + } else { + types = wmalloc(4 * sizeof(Atom)); + if (event->data.l[2] != None) + types[i++] = event->data.l[2]; + if (event->data.l[3] != None) + types[i++] = event->data.l[3]; + if (event->data.l[4] != None) + types[i++] = event->data.l[4]; + types[i] = NULL; + } + + if (types[0] == NULL) { + wwarning("received invalid drag & drop type list"); + //XXX return; + } + + return types; +} + + + +void +W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) +{ + WMScreen *scr = W_VIEW_SCREEN(toplevel); + WMView *view; + int operation; + + if (event->message_type == scr->xdndEnterAtom) { + Atom *types; + Window foo, bar; + int bla; + unsigned ble; + puts("entered"); + + if (scr->dragInfo.sourceWindow != None) { + puts("received Enter event in bad order"); + } + + memset(&scr->dragInfo, 0, sizeof(WMDraggingInfo)); + + + if ((event->data.l[0] >> 24) > XDND_VERSION) { + wwarning("received drag & drop request with unsupported version %i", + (event->data.l[0] >> 24)); + return; + } + + info.protocolVersion = event->data.l[0] >> 24; + + info.sourceWindow = event->data.l[0]; + info.destinationWindow = event->window; + + /* XXX */ + info.image = NULL; + + XQueryPointer(scr->display, scr->rootWin, &foo, &bar, + &event->location.x, &event->location.y, + &bla, &bla, &ble); + + view = findViewInToplevel(scr->display, + scr->dragInfo.destinationWindow, + scr->dragInfo.location.x, + scr->dragInfo.location.y); + + if (IS_DROPPABLE(view)) { + operation = + view->dragDestinationProcs->draggingEntered(view, + &scr->dragInfo); + } else { + operation = 0; + } + + + } else if (event->message_type == scr->xdndPositionAtom + && scr->dragInfo.sourceWindow == event->data.l[0]) { + unsigned operation = 0; + + scr->dragInfo.location.x = event->data.l[2] >> 16; + scr->dragInfo.location.y = event->data.l[2] 0xffff; + + if (scr->dragInfo.protocolVersion >= 1) { + scr->dragInfo.timestamp = event->data.l[3]; + scr->dragInfo.sourceOperation = event->data.l[4]; + } else { + scr->dragInfo.timestamp = CurrentTime; + scr->dragInfo.sourceOperation = 0; /*XXX*/ + } + + child = findChildInWindow(scr->display, scr->dragInfo.destinationWindow, + scr->dragInfo.location.x, + scr->dragInfo.location.y); + if (child != None) { + view = W_GetViewForXWindow(scr->display, child); + } else { + view = NULL; + } + + if (IS_DROPPABLE(view)) { + operation = + view->dragDestinationProcs->draggingUpdated(view, + &scr->dragInfo); + } + + if (operation == 0) { + sendClientMessage(scr->display, scr->xdndStatusAtom, + scr->dragInfo.sourceWindow, + scr->dragInfo.destinationWindow, + 0, 0, 0, None); + } else { + Atom action; + + switch (operation) { + default: + action =; + break; + } + + sendClientMessage(scr->display, scr->xdndStatusAtom, + scr->dragInfo.sourceWindow, + scr->dragInfo.destinationWindow, + 1, 0, 0, action); + } + + puts("position"); + } else if (event->message_type == scr->xdndLeaveAtom + && scr->dragInfo.sourceWindow == event->data.l[0]) { + + puts("leave"); + } else if (event->message_type == scr->xdndDropAtom + && scr->dragInfo.sourceWindow == event->data.l[0]) { + + puts("drop"); + } +} + diff --git a/WINGs/wcolorwell.c b/WINGs/wcolorwell.c index 7e9e0df8..d5a2091d 100644 --- a/WINGs/wcolorwell.c +++ b/WINGs/wcolorwell.c @@ -46,18 +46,43 @@ static void willResizeColorWell(); W_ViewDelegate _ColorWellViewDelegate = { NULL, - NULL, - NULL, - NULL, - willResizeColorWell + NULL, + NULL, + NULL, + willResizeColorWell }; -#if 0 -static WMDragSourceProcs dragProcs = { - +static unsigned draggingSourceOperation(WMView *self, Bool local); +static void beganDragImage(WMView *self, WMPixmap *image, WMPoint point); +static void endedDragImage(WMView *self, WMPixmap *image, WMPoint point, + Bool deposited); + + +static WMDragSourceProcs _DragSourceProcs = { + draggingSourceOperation, + beganDragImage, + endedDragImage, + NULL +}; + + +static unsigned draggingEntered(WMView *self, WMDraggingInfo *info); +static unsigned draggingUpdated(WMView *self, WMDraggingInfo *info); +static void draggingExited(WMView *self, WMDraggingInfo *info); +static Bool prepareForDragOperation(WMView *self, WMDraggingInfo *info); +static Bool performDragOperation(WMView *self, WMDraggingInfo *info); +static void concludeDragOperation(WMView *self, WMDraggingInfo *info); + +static WMDragDestinationProcs _DragDestinationProcs = { + draggingEntered, + draggingUpdated, + draggingExited, + prepareForDragOperation, + performDragOperation, + concludeDragOperation }; -#endif + #define DEFAULT_WIDTH 60 #define DEFAULT_HEIGHT 30 @@ -168,7 +193,16 @@ WMCreateColorWell(WMWidget *parent) WMAddNotificationObserver(colorChangedObserver, cPtr, WMColorPanelColorChangedNotification, NULL); + + // WMSetViewDragSourceProcs(cPtr->view, &_DragSourceProcs); + // WMSetViewDragDestinationProcs(cPtr->view, &_DragDestinationProcs); + { + char *types[2] = {"application/X-color", NULL}; + + //WMRegisterViewForDraggedTypes(cPtr->view, types); + } + return cPtr; } @@ -276,234 +310,45 @@ handleEvents(XEvent *event, void *data) } -static WMPixmap* -makeDragPixmap(WMColorWell *cPtr) +static unsigned +draggingSourceOperation(WMView *self, Bool local) { - WMScreen *scr = cPtr->view->screen; - Pixmap pix; - - pix = XCreatePixmap(scr->display, W_DRAWABLE(scr), 16, 16, scr->depth); - - XFillRectangle(scr->display, pix, WMColorGC(cPtr->color), 0, 0, 15, 15); - - XDrawRectangle(scr->display, pix, WMColorGC(scr->black), 0, 0, 15, 15); - - return WMCreatePixmapFromXPixmaps(scr, pix, None, 16, 16, scr->depth); + puts("DRAG SOURCE"); + return 0; } -static void -slideView(WMView *view, int srcX, int srcY, int dstX, int dstY) +static void +beganDragImage(WMView *self, WMPixmap *image, WMPoint point) { - double x, y, dx, dy; - int i; - - srcX -= 8; - srcY -= 8; - dstX -= 8; - dstY -= 8; - - x = srcX; - y = srcY; - - dx = (double)(dstX-srcX)/20.0; - dy = (double)(dstY-srcY)/20.0; - - for (i = 0; i < 20; i++) { - W_MoveView(view, x, y); - XFlush(view->screen->display); - - x += dx; - y += dy; - } + puts("BEGAN DRAG"); } - -static Window -findChildInWindow(Display *dpy, Window toplevel, int x, int y) +static void +endedDragImage(WMView *self, WMPixmap *image, WMPoint point, Bool deposited) { - Window foo, bar; - Window *children; - unsigned nchildren; - int i; - - if (!XQueryTree(dpy, toplevel, &foo, &bar, - &children, &nchildren) || children == NULL) { - return None; - } - - /* first window that contains the point is the one */ - for (i = nchildren-1; i >= 0; i--) { - XWindowAttributes attr; - - if (XGetWindowAttributes(dpy, children[i], &attr) - && attr.map_state == IsViewable - && x >= attr.x && y >= attr.y - && x < attr.x + attr.width && y < attr.y + attr.height) { - Window child; - - child = findChildInWindow(dpy, children[i], - x - attr.x, y - attr.y); - - XFree(children); - - if (!child) - return toplevel; - else - return child; - } - } - - XFree(children); - return None; + if (deposited) + puts("ENDED DRAG SUCCESS"); + else + puts("ENDED DRAG CANCEL"); } + -static Window -findWindowUnderDragPointer(WMScreen *scr, int x, int y, Window iconWindow) +static WMPixmap* +makeDragPixmap(WMColorWell *cPtr) { - Window foo, bar; - Window *children; - unsigned nchildren; - int i; - - if (!XQueryTree(scr->display, scr->rootWin, &foo, &bar, - &children, &nchildren) || children == NULL) { - return None; - } + WMScreen *scr = cPtr->view->screen; + Pixmap pix; - /* try to find the window below the iconWindow by traversing - * the whole window list */ + pix = XCreatePixmap(scr->display, W_DRAWABLE(scr), 16, 16, scr->depth); - /* first find the position of the iconWindow */ - for (i = nchildren-1; i >= 0; i--) { - if (children[i] == iconWindow) { - i--; - break; - } - } - if (i <= 0) { - XFree(children); - return scr->rootWin; - } - - /* first window that contains the point is the one */ - for (; i >= 0; i--) { - XWindowAttributes attr; - Window child; - - if (XGetWindowAttributes(scr->display, children[i], &attr) - && attr.map_state == IsViewable - && x >= attr.x && y >= attr.y - && x < attr.x + attr.width && y < attr.y + attr.height - && (child = findChildInWindow(scr->display, children[i], - x - attr.x, y - attr.y))) { - XFree(children); - return child; - } - } - - XFree(children); - return None; -} - - - -static void -dragColor(ColorWell *cPtr, XEvent *event, WMPixmap *image) -{ - WMView *dragView; - WMScreen *scr = cPtr->view->screen; - Display *dpy = scr->display; - XColor black = {0, 0,0,0, DoRed|DoGreen|DoBlue}; - XColor green = {0x0045b045, 0x4500,0xb000,0x4500, DoRed|DoGreen|DoBlue}; - XColor back = {0, 0xffff,0xffff,0xffff, DoRed|DoGreen|DoBlue}; - Bool done = False; - WMColorWell *activeWell = NULL; - - dragView = W_CreateTopView(scr); - - W_ResizeView(dragView, 16, 16); - dragView->attribFlags |= CWOverrideRedirect | CWSaveUnder; - dragView->attribs.event_mask = StructureNotifyMask; - dragView->attribs.override_redirect = True; - dragView->attribs.save_under = True; - - W_MoveView(dragView, event->xmotion.x_root-8, event->xmotion.y_root-8); - - W_RealizeView(dragView); - - W_MapView(dragView); - - XSetWindowBackgroundPixmap(dpy, dragView->window, WMGetPixmapXID(image)); - XClearWindow(dpy, dragView->window); + XFillRectangle(scr->display, pix, WMColorGC(cPtr->color), 0, 0, 15, 15); - - XGrabPointer(dpy, scr->rootWin, True, - ButtonMotionMask|ButtonReleaseMask, - GrabModeSync, GrabModeAsync, - scr->rootWin, scr->defaultCursor, CurrentTime); - - while (!done) { - XEvent ev; - WMView *view; - Window win; - - XAllowEvents(dpy, SyncPointer, CurrentTime); - WMNextEvent(dpy, &ev); - - switch (ev.type) { - case ButtonRelease: - if (activeWell != NULL) { - WMSetColorWellColor(activeWell, cPtr->color); - WMPostNotificationName(WMColorWellDidChangeNotification, - activeWell, NULL); - } else { - slideView(dragView, ev.xbutton.x_root, ev.xbutton.y_root, - event->xmotion.x_root, event->xmotion.y_root); - } - - done = True; - break; - - case MotionNotify: - while (XCheckTypedEvent(dpy, MotionNotify, &ev)) ; - - W_MoveView(dragView, ev.xmotion.x_root-8, ev.xmotion.y_root-8); - - win = findWindowUnderDragPointer(scr, ev.xmotion.x_root, - ev.xmotion.y_root, - dragView->window); - - if (win != None && win != scr->rootWin) { - view = W_GetViewForXWindow(dpy, win); - } else { - view = NULL; - } - - if (view && view->self && W_CLASS(view->self) == WC_ColorWell - && view->self != activeWell && view->self != cPtr) { - - activeWell = view->self; - XRecolorCursor(dpy, scr->defaultCursor, &green, &back); - - } else if (!view || view->self != activeWell) { - - XRecolorCursor(dpy, scr->defaultCursor, &black, &back); - activeWell = NULL; - } - break; - - default: - WMHandleEvent(&ev); - break; - } - } - XUngrabPointer(dpy, CurrentTime); - XRecolorCursor(dpy, scr->defaultCursor, &black, &back); - - W_DestroyView(dragView); + XDrawRectangle(scr->display, pix, WMColorGC(scr->black), 0, 0, 15, 15); + + return WMCreatePixmapFromXPixmaps(scr, pix, None, 16, 16, scr->depth); } @@ -526,17 +371,17 @@ handleDragEvents(XEvent *event, void *data) || abs(cPtr->ipoint.y - event->xmotion.y) > 4) { WMSize offs; WMPixmap *pixmap; + char *types[2] = {"application/X-color", NULL}; offs.width = 2; offs.height = 2; pixmap = makeDragPixmap(cPtr); - - /* - WMDragImageFromView(cPtr->view, pixmap, cPtr->view->pos, - offs, event, True); - * */ - - dragColor(cPtr, event, pixmap); +/* + WMDragImageFromView(cPtr->view, pixmap, types, + wmkpoint(event->xmotion.x_root, + event->xmotion.y_root), + offs, event, True); + */ WMReleasePixmap(pixmap); } @@ -585,3 +430,76 @@ destroyColorWell(ColorWell *cPtr) wfree(cPtr); } + + +static unsigned +draggingEntered(WMView *self, WMDraggingInfo *info) +{ + WMPoint point = WMGetViewScreenPosition(self); + + printf("%i %i || %i %i %i %i\n", info->location.x, info->location.y, + point.x, point.y, W_VIEW_WIDTH(self), W_VIEW_HEIGHT(self)); + + if (info->location.x >= point.x + && info->location.y >= point.y + && info->location.x < point.x + W_VIEW_WIDTH(self) + && info->location.y < point.y + W_VIEW_HEIGHT(self)) { + /* self */ + puts("ENTERED 0"); + return 0; + } else { + puts("ENTERED 1"); + return 1; + } +} + + +static unsigned +draggingUpdated(WMView *self, WMDraggingInfo *info) +{ + + WMPoint point = WMGetViewScreenPosition(self); + + puts("UPDATED"); + if (info->location.x >= point.x + && info->location.y >= point.y + && info->location.x < point.x + W_VIEW_WIDTH(self) + && info->location.y < point.y + W_VIEW_WIDTH(self)) { + return 0; + } else { + return 1; + } +} + + +static void +draggingExited(WMView *self, WMDraggingInfo *info) +{ + puts("EXITED"); +} + + +static Bool +prepareForDragOperation(WMView *self, WMDraggingInfo *info) +{ + puts("PREPARING"); + return True; +} + + +static Bool +performDragOperation(WMView *self, WMDraggingInfo *info) +{ + WMData *data; + + // data = WMGetDroppedData(self); + puts("DROPPED"); + return True; +} + + +static void +concludeDragOperation(WMView *self, WMDraggingInfo *info) +{ + puts("FINISHED"); +} diff --git a/WINGs/wevent.c b/WINGs/wevent.c index 894a9e4f..96716063 100644 --- a/WINGs/wevent.c +++ b/WINGs/wevent.c @@ -304,7 +304,7 @@ checkIdleHandlers() { IdleHandler *handler; WMBag *handlerCopy; - int i, n; + WMBagIterator iter; if (!idleHandler || WMGetBagItemCount(idleHandler)==0) { W_FlushIdleNotificationQueue(); @@ -312,15 +312,14 @@ checkIdleHandlers() return (idleHandler!=NULL && WMGetBagItemCount(idleHandler)>0); } - n = WMGetBagItemCount(idleHandler); - handlerCopy = WMCreateBag(n); - for (i=0; icallback)(handler->clientData); @@ -586,6 +585,10 @@ WMHandleEvent(XEvent *event) || event->type == SelectionRequest) { /* handle selection related events */ W_HandleSelectionEvent(event); + + } else if (event->type == ClientMessage) { + + //W_HandleDNDClientMessage(toplevel, &event->xclient); } /* if it's a key event, redispatch it to the focused control */ @@ -640,12 +643,12 @@ WMHandleEvent(XEvent *event) W_RetainView(toplevel); hPtr = view->handlerList; - + while (hPtr!=NULL) { W_EventHandler *tmp; tmp = hPtr->nextHandler; - + if ((hPtr->eventMask & mask)) { (*hPtr->proc)(event, hPtr->clientData); } @@ -654,14 +657,14 @@ WMHandleEvent(XEvent *event) } /* pass the event to the top level window of the widget */ - if (view->parent!=NULL) { + if (view->parent != NULL) { vPtr = view; - while (vPtr->parent!=NULL) + while (vPtr->parent != NULL) vPtr = vPtr->parent; hPtr = vPtr->handlerList; - while (hPtr!=NULL) { + while (hPtr != NULL) { if (hPtr->eventMask & mask) { (*hPtr->proc)(event, hPtr->clientData); diff --git a/WINGs/widgets.c b/WINGs/widgets.c index 89c67aa4..823dd9d2 100644 --- a/WINGs/widgets.c +++ b/WINGs/widgets.c @@ -546,6 +546,23 @@ WMCreateScreenWithRContext(Display *display, int screen, RContext *context) XGCValues gcv; Pixmap stipple; static int initialized = 0; + static char *atomNames[] = { + "_GNUSTEP_WM_ATTR", + "WM_DELETE_WINDOW", + "WM_PROTOCOLS", + "CLIPBOARD", + "XdndAware", + "XdndSelection", + "XdndEnter", + "XdndLeave", + "XdndPosition", + "XdndDrop", + "XdndFinished", + "XdndTypeList", + "XdndStatus", + "WM_STATE" + }; + Atom atoms[sizeof(atomNames)/sizeof(char*)]; if (!initialized) { @@ -738,16 +755,29 @@ WMCreateScreenWithRContext(Display *display, int screen, RContext *context) XFreePixmap(display, blank); } - scrPtr->internalMessage = XInternAtom(display, "_WINGS_MESSAGE", False); - - scrPtr->attribsAtom = XInternAtom(display, "_GNUSTEP_WM_ATTR", False); + XInternAtoms(display, atomNames, sizeof(atomNames)/sizeof(char*), False, + atoms); - scrPtr->deleteWindowAtom = XInternAtom(display, "WM_DELETE_WINDOW", False); - - scrPtr->protocolsAtom = XInternAtom(display, "WM_PROTOCOLS", False); + scrPtr->attribsAtom = atoms[0]; - scrPtr->clipboardAtom = XInternAtom(display, "CLIPBOARD", False); + scrPtr->deleteWindowAtom = atoms[1]; + + scrPtr->protocolsAtom = atoms[2]; + scrPtr->clipboardAtom = atoms[3]; + + scrPtr->xdndAwareAtom = atoms[4]; + scrPtr->xdndSelectionAtom = atoms[5]; + scrPtr->xdndEnterAtom = atoms[6]; + scrPtr->xdndLeaveAtom = atoms[7]; + scrPtr->xdndPositionAtom = atoms[8]; + scrPtr->xdndDropAtom = atoms[9]; + scrPtr->xdndFinishedAtom = atoms[10]; + scrPtr->xdndTypeListAtom = atoms[11]; + scrPtr->xdndStatusAtom = atoms[12]; + + scrPtr->wmStateAtom = atoms[13]; + scrPtr->rootView = W_CreateRootView(scrPtr); diff --git a/WINGs/wtest.c b/WINGs/wtest.c index a7192e8c..0d9b1680 100644 --- a/WINGs/wtest.c +++ b/WINGs/wtest.c @@ -718,10 +718,11 @@ int main(int argc, char **argv) * Put the testSomething() function you want to test here. */ - testTabView(scr); testColorWell(scr); #if 0 + testTabView(scr); + testFontPanel(scr); testSplitView(scr); diff --git a/WINGs/wview.c b/WINGs/wview.c index 78343f07..15ad177a 100644 --- a/WINGs/wview.c +++ b/WINGs/wview.c @@ -229,18 +229,6 @@ W_RealizeView(W_View *view) } - -Bool -W_CheckInternalMessage(W_Screen *scr, XClientMessageEvent *cev, int event) -{ - if (cev->message_type == scr->internalMessage - && cev->format == 32 && cev->data.l[1] == event) - return True; - else - return False; -} - - void W_ReparentView(W_View *view, W_View *newParent, int x, int y) { @@ -414,6 +402,9 @@ destroyView(W_View *view) unparentView(view); W_CleanUpEvents(view); + + // WMUnregisterViewDraggedTypes(view); + #if 0 if (view->dragSourceProcs) wfree(view->dragSourceProcs); @@ -659,3 +650,19 @@ WMViewXID(WMView *view) return view->window; } + +WMPoint +WMGetViewScreenPosition(WMView *view) +{ + WMScreen *scr = W_VIEW_SCREEN(view); + Window foo; + int x, y; + + XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(view), + scr->rootWin, 0, 0, &x, &y, &foo); + + return wmkpoint(x, y); +} + + + -- 2.11.4.GIT