From 567e53c67cb712d8b83bd137309ec9343f523caf Mon Sep 17 00:00:00 2001 From: kojima Date: Mon, 3 Apr 2000 06:08:31 +0000 Subject: [PATCH] added drag and drop --- WINGs/README | 12 +-- WINGs/WINGs.h | 18 +++- WINGs/WINGsP.h | 4 +- WINGs/dragdestination.c | 17 ++- WINGs/dragsource.c | 125 +++++++++++++++-------- WINGs/wtest.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 383 insertions(+), 60 deletions(-) diff --git a/WINGs/README b/WINGs/README index 8cc0e698..d3751322 100644 --- a/WINGs/README +++ b/WINGs/README @@ -56,22 +56,19 @@ Widgets provided by WINGs: - slider - scrollable view - color well -- split view (only 2 subviews) +- split view - tabbed view - progress indicator +- selection (make pasteboard like?) +- drag&drop + - input box - file panel - color panel - alert panel - font panel -Planned: --------- - -- selection (pasteboard like) -- drag&drop - If you think you can code the following, please do. They are needed by WPrefs.app, but the number of other things I have to do is huge. @@ -84,7 +81,6 @@ Wish list: (I don't have the know-how or time to do them) - text (with support for RTF) - matrix (like NSMatrix) -- splitviews with more than 2 subviews - font manager (like NSFontManager) - finish other wigets - optimize list scrolling (XCopyArea() the area that's already drawn) diff --git a/WINGs/WINGs.h b/WINGs/WINGs.h index aa15b5c4..e7fca903 100644 --- a/WINGs/WINGs.h +++ b/WINGs/WINGs.h @@ -612,11 +612,21 @@ Bool WMRequestSelection(WMView *view, Atom selection, Atom target, /* ....................................................................... */ -/* -void WMDragImageFromView(WMView *view, WMPixmap *image, WMPoint atLocation, - WMSize mouseOffset, XEvent *event, Bool slideBack); -*/ +void WMSetViewDragSourceProcs(WMView *view, WMDragSourceProcs *procs); + +void WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], + WMPoint atLocation, WMSize mouseOffset, XEvent *event, + Bool slideBack); + +void WMRegisterViewForDraggedTypes(WMView *view, char *acceptedTypes[]); + +void WMUnregisterViewDraggedTypes(WMView *view); + +void WMSetViewDragDestinationProcs(WMView *view, WMDragDestinationProcs *procs); + + +WMPoint WMGetDraggingInfoImageLocation(WMDraggingInfo *info); /* ....................................................................... */ diff --git a/WINGs/WINGsP.h b/WINGs/WINGsP.h index 1f1c3aed..40aa741a 100644 --- a/WINGs/WINGsP.h +++ b/WINGs/WINGsP.h @@ -100,7 +100,9 @@ struct W_DraggingInfo { unsigned sourceOperation; WMPixmap *image; WMPoint imageLocation; - + + char **types; + Time timestamp; int protocolVersion; diff --git a/WINGs/dragdestination.c b/WINGs/dragdestination.c index fec01831..ecb13cb2 100644 --- a/WINGs/dragdestination.c +++ b/WINGs/dragdestination.c @@ -23,8 +23,8 @@ static void realizedObserver(void *self, WMNotification *notif) { WMView *view = (WMView*)WMGetNotificationObject(notif); - - XChangeProperty(W_VIEW_SCREEN(view)->display, W_VIEW_DRAWABLE(view), + + XChangeProperty(W_VIEW_SCREEN(view)->display, W_VIEW_DRAWABLE(view), W_VIEW_SCREEN(view)->xdndAwareAtom, XA_ATOM, 32, PropModeReplace, (unsigned char*)&XDNDversion, 1); @@ -48,10 +48,11 @@ W_SetXdndAwareProperty(WMScreen *scr, WMView *view, Atom *types, int typeCount) XA_ATOM, 32, PropModeReplace, (unsigned char*)&XDNDversion, 1); } else { - WMAddNotificationObserver(realizedObserver, view, - WMViewRealizedNotification, + WMAddNotificationObserver(realizedObserver, /* just use as an id */ - view->dragDestinationProcs); + &view->dragDestinationProcs, + WMViewRealizedNotification, + view); } } } @@ -161,3 +162,9 @@ WMSetViewDragDestinationProcs(WMView *view, WMDragDestinationProcs *procs) + + +WMPoint WMGetDraggingInfoImageLocation(WMDraggingInfo *info) +{ + return info->imageLocation; +} diff --git a/WINGs/dragsource.c b/WINGs/dragsource.c index 742cdd3b..a7f589c2 100644 --- a/WINGs/dragsource.c +++ b/WINGs/dragsource.c @@ -1,8 +1,17 @@ +#include "../src/config.h" +#include +#include #include + +#ifdef SHAPE +#include +#endif + #include + #include "WINGsP.h" @@ -22,6 +31,27 @@ static Bool _XErrorOccured = False; +static unsigned defDraggingSourceOperation(WMView *self, Bool local) +{ + return WDOperationCopy; +} + + +static void defBeganDragImage(WMView *self, WMPixmap *image, WMPoint point) +{ +} + + +static void defEndedDragImage(WMView *self, WMPixmap *image, WMPoint point, + Bool deposited) +{ +} + +static WMData* defFetchDragData(WMView *self, char *type) +{ + return NULL; +} + void WMSetViewDragSourceProcs(WMView *view, WMDragSourceProcs *procs) @@ -31,8 +61,19 @@ WMSetViewDragSourceProcs(WMView *view, WMDragSourceProcs *procs) view->dragSourceProcs = wmalloc(sizeof(WMDragSourceProcs)); *view->dragSourceProcs = *procs; - - /* XXX fill in non-implemented stuffs */ + + if (procs->draggingSourceOperation == NULL) { + view->dragSourceProcs->draggingSourceOperation = defDraggingSourceOperation; + } + if (procs->beganDragImage == NULL) { + view->dragSourceProcs->beganDragImage = defBeganDragImage; + } + if (procs->endedDragImage == NULL) { + view->dragSourceProcs->endedDragImage = defEndedDragImage; + } + if (procs->fetchDragData == NULL) { + view->dragSourceProcs->fetchDragData = defFetchDragData; + } } @@ -90,7 +131,7 @@ makeDragIcon(WMScreen *scr, WMPixmap *pixmap) #ifdef SHAPE if (mask) { - XShapeCombineMask(dpy, scr->balloon->window, ShapeBounding, 0, 0, mask, + XShapeCombineMask(scr->display, window, ShapeBounding, 0, 0, mask, ShapeSet); } #endif @@ -147,15 +188,16 @@ findChildInWindow(Display *dpy, Window toplevel, int x, int y) && attr.map_state == IsViewable && x >= attr.x && y >= attr.y && x < attr.x + attr.width && y < attr.y + attr.height) { - Window child; + Window child, tmp; - child = findChildInWindow(dpy, children[i], - x - attr.x, y - attr.y); + tmp = children[i]; + + child = findChildInWindow(dpy, tmp, x - attr.x, y - attr.y); XFree(children); if (child == None) - return toplevel; + return tmp; else return child; } @@ -172,11 +214,12 @@ findViewInToplevel(Display *dpy, Window toplevel, int x, int y) Window child; child = findChildInWindow(dpy, toplevel, x, y); - - if (child != None) + + if (child != None) { return W_GetViewForXWindow(dpy, child); - else + } else { return NULL; + } } @@ -385,29 +428,26 @@ translateCoordinates(WMScreen *scr, Window target, int fromX, int fromY, static void -updateDraggingInfo(WMScreen *scr, WMDraggingInfo *info, +updateDraggingInfo(WMScreen *scr, WMDraggingInfo *info, WMSize offset, 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->imageLocation.x = event->xmotion.x_root-offset.width; + info->imageLocation.y = event->xmotion.y_root-offset.height; info->location.x = event->xmotion.x_root; info->location.y = event->xmotion.y_root; - info->timestamp = event->xmotion.time; +/* 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->imageLocation.x = event->xbutton.x_root-offset.width; + info->imageLocation.y = event->xbutton.y_root-offset.height; info->location.x = event->xbutton.x_root; info->location.y = event->xbutton.y_root; - info->timestamp = event->xbutton.time; +/* info->timestamp = event->xbutton.time;*/ } toplevel = findToplevelUnderDragPointer(scr, @@ -500,6 +540,7 @@ selectionLost(WMView *view, Atom selection, void *cdata) { if (W_VIEW_SCREEN(view)->dragSourceView == view) { wwarning("DND selection lost during drag operation..."); + W_VIEW_SCREEN(view)->dragSourceView = NULL; } } @@ -573,7 +614,6 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], Display *dpy = scr->display; Window icon; XEvent ev; - WMSize size; WMRect rect = {{0,0},{0,0}}; int ostate = -1; int state; @@ -591,7 +631,8 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], }; - wassertr(scr->dragSourceView == NULL); + if (scr->dragSourceView != NULL) + return; wassertr(view->dragSourceProcs != NULL); @@ -600,12 +641,9 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], 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); + XMoveWindow(dpy, icon, atLocation.x, atLocation.y); XMapRaised(dpy, icon); @@ -621,8 +659,8 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], dragInfo.destinationWindow = dragInfo.sourceWindow; - dragInfo.location.x = event->xmotion.x_root; - dragInfo.location.y = event->xmotion.y_root; + dragInfo.location.x = atLocation.x + mouseOffset.width; + dragInfo.location.y = atLocation.y + mouseOffset.height; dragInfo.imageLocation = atLocation; @@ -665,7 +703,7 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], oldDragInfo = dragInfo; - updateDraggingInfo(scr, &dragInfo, &ev, icon); + updateDraggingInfo(scr, &dragInfo, mouseOffset, &ev, icon); XMoveWindow(dpy, icon, dragInfo.imageLocation.x, dragInfo.imageLocation.y); @@ -720,11 +758,15 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], oldDragInfo = dragInfo; - updateDraggingInfo(scr, &dragInfo, &ev, icon); + updateDraggingInfo(scr, &dragInfo, mouseOffset, &ev, icon); XMoveWindow(dpy, icon, dragInfo.imageLocation.x, dragInfo.imageLocation.y); + if (state == 4 || state == 1) { + dragInfo.destinationWindow = None; + dragInfo.destView = NULL; + } processMotion(scr, &dragInfo, &oldDragInfo, &rect, action); dragInfo.timestamp = ev.xbutton.time; @@ -1042,10 +1084,12 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) source = scr->dragInfo.sourceWindow; oldView = scr->dragInfo.destView; - if (event->message_type == scr->xdndFinishedAtom) { WMView *view = scr->dragSourceView; + WMDeleteSelectionHandler(view, scr->xdndSelectionAtom, + scr->dragInfo.timestamp); + if (view->dragSourceProcs->endedDragImage != NULL) { view->dragSourceProcs->endedDragImage(view, scr->dragInfo.image, @@ -1055,14 +1099,10 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) scr->dragSourceView = NULL; - WMDeleteSelectionHandler(view, scr->xdndSelectionAtom, - scr->dragInfo.timestamp); - return; } - if (event->message_type == scr->xdndEnterAtom) { Window foo, bar; @@ -1099,14 +1139,16 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) newView = findViewInToplevel(scr->display, - scr->dragInfo.destinationWindow, - x, y); + scr->dragInfo.destinationWindow, + x, y); } else if (event->message_type == scr->xdndPositionAtom && scr->dragInfo.sourceWindow == event->data.l[0]) { scr->dragInfo.location.x = event->data.l[2] >> 16; scr->dragInfo.location.y = event->data.l[2] & 0xffff; + + scr->dragInfo.imageLocation = scr->dragInfo.location; if (scr->dragInfo.protocolVersion >= 1) { scr->dragInfo.timestamp = event->data.l[3]; @@ -1135,8 +1177,9 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) && scr->dragInfo.sourceWindow == event->data.l[0]) { /* drop */ - what = WDrop; - + if (oldView != NULL) + what = WDrop; + } else { return; } @@ -1148,7 +1191,7 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) if (what == WNothing) { if (IS_DROPPABLE(newView)) { - if (oldView == NULL) { /* entered */ + if (!IS_DROPPABLE(oldView)) { /* entered */ what = WEnter; } else if (oldView == newView) { /* updated */ what = WUpdate; @@ -1156,7 +1199,7 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) what = WCross; } } else { - if (oldView != NULL) { + if (IS_DROPPABLE(oldView)) { what = WLeave; } else { /* just send rejection msg */ diff --git a/WINGs/wtest.c b/WINGs/wtest.c index 0d9b1680..4d97b02d 100644 --- a/WINGs/wtest.c +++ b/WINGs/wtest.c @@ -667,6 +667,267 @@ testSplitView(WMScreen *scr) WMMapWidget(win); } + +/*******************************************************************/ + +#include +#include +#include + + +typedef struct { + int x, y; + Bool mouseDown; + char *filename; +} DNDStuff; + +WMPixmap* +getImage(WMScreen *scr, char *file) +{ + char buffer[1000]; + WMPixmap *pix; + + sprintf(buffer, "../WindowMaker/Icons/%s", file); + pix = WMCreatePixmapFromFile(scr, buffer); + + return pix; +} + + + + +static void iconMouseStuff(XEvent *event, void *cdata) +{ + WMLabel *label = (WMLabel*)cdata; + DNDStuff *stuff = WMGetHangedData(label); + WMPoint where; + + switch (event->type) { + case ButtonPress: + stuff->x = event->xbutton.x_root; + stuff->y = event->xbutton.y_root; + stuff->mouseDown = True; + break; + case ButtonRelease: + stuff->mouseDown = False; + break; + case MotionNotify: + if (!stuff->mouseDown) + break; + + if (abs(stuff->x - event->xmotion.x_root)>4 + || abs(stuff->y - event->xmotion.y_root)>4) { + + where = WMGetViewScreenPosition(WMWidgetView(label)); + + WMDragImageFromView(WMWidgetView(label), + WMGetLabelImage(label), + NULL, /* XXX */ + where, + wmksize(event->xmotion.x, event->xmotion.y), + event, True); + } + break; + } +} + + +static void endedDragImage(WMView *self, WMPixmap *image, WMPoint point, + Bool deposited) +{ + DNDStuff *stuff = WMGetHangedData(WMWidgetOfView(self)); + + if (deposited) { + WMDestroyWidget(WMWidgetOfView(self)); + } + + stuff->mouseDown = False; +} + + +static WMData* fetchDragData(WMView *self, char *type) +{ + DNDStuff *stuff = WMGetHangedData(WMWidgetOfView(self)); + + return WMCreateDataWithBytes(stuff->filename, strlen(stuff->filename)+1); +} + + +WMDragSourceProcs dragSourceProcs = { + NULL, + NULL, + endedDragImage, + fetchDragData +}; + + +/************************/ + + +unsigned draggingEntered(WMView *self, WMDraggingInfo *info) +{ + return WDOperationCopy; +} + + +unsigned draggingUpdated(WMView *self, WMDraggingInfo *info) +{ + return WDOperationCopy; +} + + /* + void (*draggingExited)(WMView *self, WMDraggingInfo *info); + */ +char *prepareForDragOperation(WMView *self, WMDraggingInfo *info) +{ + return "application/X-WINGs-Bla"; +} + + +WMLabel *makeDraggableLabel(WMWidget *w, char *file, int x, int y); + +Bool performDragOperation(WMView *self, WMDraggingInfo *info, + WMData *data) +{ + char *file = (char*)WMDataBytes(data); + WMPoint pos; + + pos = WMGetDraggingInfoImageLocation(info); + + if (file!=NULL) { + WMLabel *label; + WMPoint pos2 = WMGetViewScreenPosition(self); + + + label = makeDraggableLabel(WMWidgetOfView(self), file, + pos.x-pos2.x, pos.y-pos2.y); + WMRealizeWidget(label); + WMMapWidget(label); + } + + + return True; +} + + +void concludeDragOperation(WMView *self, WMDraggingInfo *info) +{ + puts("concluded"); + +} + + + +WMDragDestinationProcs dragDestProcs = { + draggingEntered, + draggingUpdated, + NULL, + prepareForDragOperation, + performDragOperation, + concludeDragOperation +}; + + + + +WMLabel* +makeDraggableLabel(WMWidget *w, char *file, int x, int y) +{ + DNDStuff *stuff; + WMLabel *label; + WMPixmap *image = getImage(WMWidgetScreen(w), file); + + stuff = wmalloc(sizeof(DNDStuff)); + stuff->mouseDown = False; + + stuff->filename = wstrdup(file); + + label = WMCreateLabel(w); + WMResizeWidget(label, 48, 48); + WMMoveWidget(label, x, y); + + WMSetViewDragSourceProcs(WMWidgetView(label), &dragSourceProcs); + + WMHangData(label, stuff); + + WMCreateEventHandler(WMWidgetView(label), + ButtonPressMask|ButtonReleaseMask|ButtonMotionMask, + iconMouseStuff, label); + + + WMSetLabelImagePosition(label, WIPImageOnly); + WMSetLabelImage(label, image); + WMReleasePixmap(image); + + return label; +} + + + +void testDragAndDrop(WMScreen *scr) +{ + WMWindow *win; + WMFrame *frame; + WMLabel *label; + int i, j; + DIR *dir; + struct dirent *ent; + char *types[] = { + "application/X-WINGs-Bla", + NULL + }; + + windowCount++; + + win = WMCreateWindow(scr, "dragDrop"); + WMResizeWidget(win, 300, 300); + WMSetWindowCloseAction(win, closeAction, NULL); + WMSetWindowTitle(win, "Drag and Drop"); + + + frame = WMCreateFrame(win); + WMSetFrameRelief(frame, WRSunken); + WMResizeWidget(frame, 250, 250); + WMMoveWidget(frame, 25, 25); + + WMRegisterViewForDraggedTypes(WMWidgetView(frame), types); + WMSetViewDragDestinationProcs(WMWidgetView(frame), &dragDestProcs); + + dir = opendir("../WindowMaker/Icons"); + if (!dir) { + perror("../WindowMaker/Icons"); + return; + } + + for (i = 0, j=0; j < 8; i++) { + ent = readdir(dir); + if (!ent) + break; + + if (strstr(ent->d_name, ".xpm")==NULL) { + continue; + } + + label = makeDraggableLabel(frame, ent->d_name,4+(j/4)*64, 4+(j%4)*64); + + j++; + } + + closedir(dir); + + WMMapSubwidgets(frame); + + WMMapSubwidgets(win); + WMRealizeWidget(win); + WMMapWidget(win); +} + + + + + +/*******************************************************************/ + #include "WUtil.h" @@ -718,9 +979,13 @@ int main(int argc, char **argv) * Put the testSomething() function you want to test here. */ + + testDragAndDrop(scr); + testDragAndDrop(scr); - testColorWell(scr); #if 0 + testColorWell(scr); + testTabView(scr); testFontPanel(scr); -- 2.11.4.GIT