From 60a247f271e3722bdbe1e0353a2c10ec3cdc876c Mon Sep 17 00:00:00 2001 From: kojima Date: Mon, 3 Apr 2000 03:10:20 +0000 Subject: [PATCH] drag and drop! selection code rewrite! textfield with new selection code! etc etc --- WINGs/WINGs.h | 64 ++-- WINGs/WINGsP.h | 18 +- WINGs/WUtil.h | 10 +- WINGs/data.c | 78 ++++- WINGs/dragdestination.c | 61 +++- WINGs/dragsource.c | 506 +++++++++++++++++---------- WINGs/selection.c | 883 +++++++++++++++++++++++++----------------------- WINGs/wcolorwell.c | 343 +++++++------------ WINGs/widgets.c | 49 ++- WINGs/wtabview.c | 2 +- WINGs/wtextfield.c | 286 +++++++++------- WINGs/wview.c | 4 + 12 files changed, 1300 insertions(+), 1004 deletions(-) rewrite WINGs/selection.c (72%) diff --git a/WINGs/WINGs.h b/WINGs/WINGs.h index 9d3d515a..aa15b5c4 100644 --- a/WINGs/WINGs.h +++ b/WINGs/WINGs.h @@ -7,7 +7,7 @@ #include #include -#define WINGS_H_VERSION 991003 +#define WINGS_H_VERSION 20000402 #ifdef __cplusplus @@ -170,7 +170,7 @@ typedef enum { WTNoTabsBevelBorder, WTNoTabsLineBorder, WTNoTabsNoBorder -} WMTabViewTypes; +} WMTabViewType; /* text movement types */ @@ -192,6 +192,18 @@ enum { WMDeleteTextEvent }; + +/* drag operations */ +typedef enum { + WDOperationNone, + WDOperationCopy, + WDOperationMove, + WDOperationLink, + WDOperationAsk, + WDOperationPrivate +} WMDragOperationType; + + typedef enum { WMGrayModeColorPanel = 1, WMRGBModeColorPanel = 2, @@ -392,8 +404,6 @@ typedef void WMCallback(void *data); /* delegate method like stuff */ -typedef void WMFreeDataProc(void *data); - typedef void WMListDrawProc(WMList *lPtr, int index, Drawable d, char *text, int state, WMRect *rect); @@ -409,15 +419,6 @@ typedef void WMSplitViewConstrainProc(WMSplitView *sPtr, int dividerIndex, typedef WMWidget *WMMatrixCreateCellProc(WMMatrix *mPtr); -typedef Bool WMConvertSelectionProc(WMWidget *w, Atom selection, Atom target, - Atom *type, void **value, unsigned *length, - int *format); - -typedef void WMLoseSelectionProc(WMWidget *w, Atom selection); - -typedef void WMSelectionDoneProc(WMWidget *w, Atom selection, Atom target); - - typedef struct WMBrowserDelegate { @@ -474,6 +475,22 @@ typedef struct WMTabViewDelegate { + +typedef void WMSelectionCallback(WMView *view, Atom selection, Atom target, + Time timestamp, void *cdata, WMData *data); + + +typedef struct WMSelectionProcs { + WMData* (*convertSelection)(WMView *view, Atom selection, Atom target, + void *cdata, Atom *type); + void (*selectionLost)(WMView *view, Atom selection, void *cdata); + void (*selectionDone)(WMView *view, Atom selection, Atom target, + void *cdata); +} WMSelectionProcs; + + + + typedef struct W_DraggingInfo WMDraggingInfo; @@ -482,7 +499,7 @@ typedef struct W_DragSourceProcs { 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); + WMData* (*fetchDragData)(WMView *self, char *type); /* Bool (*ignoreModifierKeysWhileDragging)(WMView *view);*/ } WMDragSourceProcs; @@ -492,8 +509,9 @@ 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); + char *(*prepareForDragOperation)(WMView *self, WMDraggingInfo *info); + Bool (*performDragOperation)(WMView *self, WMDraggingInfo *info, + WMData *data); void (*concludeDragOperation)(WMView *self, WMDraggingInfo *info); } WMDragDestinationProcs; @@ -581,12 +599,16 @@ WMHandlerID WMAddInputHandler(int fd, int condition, WMInputProc *proc, void WMDeleteInputHandler(WMHandlerID handlerID); -Bool WMCreateSelectionHandler(WMWidget *w, Atom selection, Time timestamp, - WMConvertSelectionProc *convProc, - WMLoseSelectionProc *loseProc, - WMSelectionDoneProc *doneProc); -void WMDeleteSelectionHandler(WMWidget *widget, Atom selection); + +Bool WMCreateSelectionHandler(WMView *view, Atom selection, Time timestamp, + WMSelectionProcs *procs, void *cdata); + +void WMDeleteSelectionHandler(WMView *view, Atom selection, Time timestamp); + +Bool WMRequestSelection(WMView *view, Atom selection, Atom target, + Time timestamp, WMSelectionCallback *callback, + void *cdata); /* ....................................................................... */ diff --git a/WINGs/WINGsP.h b/WINGs/WINGsP.h index 33137027..1f1c3aed 100644 --- a/WINGs/WINGsP.h +++ b/WINGs/WINGsP.h @@ -8,7 +8,7 @@ #include "WINGs.h" -#if WINGS_H_VERSION < 991003 +#if WINGS_H_VERSION < 20000402 #error There_is_an_old_WINGs.h_file_somewhere_in_your_system._Please_remove_it. #endif @@ -104,10 +104,11 @@ struct W_DraggingInfo { Time timestamp; int protocolVersion; - + + /* should be treated as internal data */ + WMView *sourceView; WMView *destView; - /* only valid if in the same app.. should be treated as internal data */ }; @@ -155,6 +156,7 @@ typedef struct W_Screen { Pixmap stipple; + struct W_View *dragSourceView; struct W_DraggingInfo dragInfo; /* colors */ @@ -262,7 +264,13 @@ typedef struct W_Screen { Atom xdndFinishedAtom; Atom xdndTypeListAtom; Atom xdndStatusAtom; - + + Atom xdndActionCopy; + Atom xdndActionMove; + Atom xdndActionLink; + Atom xdndActionAsk; + Atom xdndActionPrivate; + Atom wmStateAtom; /* WM_STATE */ /* stuff for detecting double-clicks */ @@ -485,8 +493,6 @@ void W_RedisplayView(WMView *view); Bool W_ApplicationInitialized(void); -char *W_GetTextSelection(WMScreen *scr, Atom selection); - void W_HandleSelectionEvent(XEvent *event); void W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event); diff --git a/WINGs/WUtil.h b/WINGs/WUtil.h index 9a9dbd0a..4d803adf 100644 --- a/WINGs/WUtil.h +++ b/WINGs/WUtil.h @@ -117,6 +117,10 @@ typedef struct W_Host WMHost; typedef struct W_Connection WMConnection; + +typedef void WMFreeDataProc(void *data); + + typedef struct { int position; @@ -438,6 +442,10 @@ WMData* WMCreateDataWithBytes(void *bytes, unsigned length); WMData* WMCreateDataWithBytesNoCopy(void *bytes, unsigned length); + +WMData* WMCreateDataWithBytesAndDestructor(void *bytes, unsigned length, + WMFreeDataProc *destructor); + WMData* WMCreateDataWithData(WMData *aData); WMData* WMRetainData(WMData *aData); @@ -470,8 +478,6 @@ Bool WMIsDataEqualToData(WMData *aData, WMData *anotherData); unsigned WMGetDataLength(WMData *aData); -unsigned WMGetDataHash(WMData *aData); - /* Adding data */ void WMAppendDataBytes(WMData *aData, void *bytes, unsigned length); diff --git a/WINGs/data.c b/WINGs/data.c index 38bf11f2..4f6206cf 100644 --- a/WINGs/data.c +++ b/WINGs/data.c @@ -30,6 +30,8 @@ typedef struct W_Data { unsigned growth; /* How much to grow */ void *bytes; /* Actual data */ unsigned retainCount; + WMFreeDataProc *destructor; + int format; /* 0, 8, 16 or 32 */ unsigned freeData:1; /* whether the data should be released */ } W_Data; @@ -54,6 +56,8 @@ WMCreateDataWithCapacity(unsigned capacity) /*FOLD00*/ aData->length = 0; aData->retainCount = 1; aData->freeData = 1; + aData->format = 0; + aData->destructor = NULL; return aData; } @@ -99,6 +103,28 @@ WMCreateDataWithBytesNoCopy(void *bytes, unsigned length) /*FOLD00*/ aData->bytes = bytes; aData->retainCount = 1; aData->freeData = 0; + aData->format = 0; + aData->destructor = NULL; + + return aData; +} + + +WMData* +WMCreateDataWithBytesAndDestructor(void *bytes, unsigned length, + WMFreeDataProc *destructor) +{ + WMData *aData; + + aData = (WMData*)wmalloc(sizeof(WMData)); + aData->length = length; + aData->capacity = length; + aData->growth = length/2 > 0 ? length/2 : 1; + aData->bytes = bytes; + aData->retainCount = 1; + aData->freeData = 0; + aData->format = 0; + aData->destructor = destructor; return aData; } @@ -107,10 +133,16 @@ WMCreateDataWithBytesNoCopy(void *bytes, unsigned length) /*FOLD00*/ WMData* WMCreateDataWithData(WMData *aData) /*FOLD00*/ { - if (aData->length > 0) - return WMCreateDataWithBytes(aData->bytes, aData->length); - else - return WMCreateDataWithCapacity(0); + WMData *newData; + if (aData->length > 0) { + newData = WMCreateDataWithBytes(aData->bytes, aData->length); + } else { + newData = WMCreateDataWithCapacity(0); + } + newData->destructor = aData->destructor; + newData->format = aData->format; + + return newData; } @@ -128,8 +160,12 @@ WMReleaseData(WMData *aData) /*FOLD00*/ aData->retainCount--; if (aData->retainCount > 0) return; - if (aData->bytes && aData->freeData) - wfree(aData->bytes); + if (aData->bytes && aData->freeData) { + if (aData->destructor != NULL) + aData->destructor(aData->bytes); + else + wfree(aData->bytes); + } wfree(aData); } @@ -158,7 +194,7 @@ WMSetDataLength(WMData *aData, unsigned length) /*FOLD00*/ WMSetDataCapacity(aData, length); } if (length > aData->length) { - unsigned char *dataBytes = (unsigned char *)aData->bytes; + unsigned char *dataBytes = (unsigned char *)aData->bytes; memset(dataBytes + aData->length, 0, length - aData->length); } @@ -167,6 +203,13 @@ WMSetDataLength(WMData *aData, unsigned length) /*FOLD00*/ void +WMSetDataFormat(WMData *aData, unsigned format) +{ + aData->format = format; +} + + +void WMIncreaseDataLengthBy(WMData *aData, unsigned extraLength) /*FOLD00*/ { WMSetDataLength(aData, aData->length + extraLength); @@ -191,6 +234,13 @@ WMGetDataBytes(WMData *aData, void *buffer) /*FOLD00*/ } +unsigned +WMGetDataFormat(WMData *aData) +{ + return aData->format; +} + + void WMGetDataBytesWithLength(WMData *aData, void *buffer, unsigned length) /*FOLD00*/ { @@ -217,13 +267,18 @@ WMData* WMGetSubdataWithRange(WMData *aData, WMRange aRange) /*FOLD00*/ { void *buffer; + WMData *newData; /* return an empty subdata instead if aRange.count is 0 ? */ wassertrv(aRange.count > 0, NULL); buffer = wmalloc(aRange.count); WMGetDataBytesWithRange(aData, buffer, aRange); - return WMCreateDataWithBytesNoCopy(buffer, aRange.count); + newData = WMCreateDataWithBytesNoCopy(buffer, aRange.count); + newData->destructor = aData->destructor; + newData->format = aData->format; + + return newData; } @@ -249,13 +304,6 @@ WMGetDataLength(WMData *aData) /*FOLD00*/ } -unsigned -WMGetDataHash(WMData *aData) /*FOLD00*/ -{ - return aData->length; -} - - /* Adding data */ void WMAppendDataBytes(WMData *aData, void *bytes, unsigned length) /*FOLD00*/ diff --git a/WINGs/dragdestination.c b/WINGs/dragdestination.c index 06f55eaf..fec01831 100644 --- a/WINGs/dragdestination.c +++ b/WINGs/dragdestination.c @@ -58,14 +58,6 @@ W_SetXdndAwareProperty(WMScreen *scr, WMView *view, Atom *types, int typeCount) - -WMData* -WMGetDroppedData(WMView *view, WMDraggingInfo *info) -{ - return NULL; -} - - void WMRegisterViewForDraggedTypes(WMView *view, char *acceptedTypes[]) { @@ -100,6 +92,38 @@ WMUnregisterViewDraggedTypes(WMView *view) /***********************************************************************/ + +static unsigned defDraggingEntered(WMView *self, WMDraggingInfo *info) +{ + return WDOperationNone; +} + +static unsigned defDraggingUpdated(WMView *self, WMDraggingInfo *info) +{ + return WDOperationNone; +} + +static void defDraggingExited(WMView *self, WMDraggingInfo *info) +{ +} + +static char* defPrepareForDragOperation(WMView *self, WMDraggingInfo *info) +{ + return NULL; +} + +static Bool defPerformDragOperation(WMView *self, WMDraggingInfo *info, + WMData *data) +{ + return False; +} + +static void defConcludeDragOperation(WMView *self, WMDraggingInfo *info) +{ +} + + + void WMSetViewDragDestinationProcs(WMView *view, WMDragDestinationProcs *procs) { @@ -110,6 +134,27 @@ WMSetViewDragDestinationProcs(WMView *view, WMDragDestinationProcs *procs) *view->dragDestinationProcs = *procs; /*XXX fill in non-implemented stuffs */ + if (procs->draggingEntered == NULL) { + view->dragDestinationProcs->draggingEntered = defDraggingEntered; + } + if (procs->draggingUpdated == NULL) { + view->dragDestinationProcs->draggingUpdated = defDraggingUpdated; + } + if (procs->draggingExited == NULL) { + view->dragDestinationProcs->draggingExited = defDraggingExited; + } + if (procs->prepareForDragOperation == NULL) { + view->dragDestinationProcs->prepareForDragOperation = + defPrepareForDragOperation; + } + if (procs->performDragOperation == NULL) { + view->dragDestinationProcs->performDragOperation = + defPerformDragOperation; + } + if (procs->concludeDragOperation == NULL) { + view->dragDestinationProcs->concludeDragOperation = + defConcludeDragOperation; + } } diff --git a/WINGs/dragsource.c b/WINGs/dragsource.c index 1fdf7ba8..742cdd3b 100644 --- a/WINGs/dragsource.c +++ b/WINGs/dragsource.c @@ -8,13 +8,16 @@ -#define SPIT(a) puts(a) +#define SPIT(a) #define IS_DROPPABLE(view) (view!=NULL && view->droppableTypes!=NULL && \ view->dragDestinationProcs!=NULL) +static Atom operationToAction(WMScreen *scr, WMDragOperationType operation); +static WMDragOperationType actionToOperation(WMScreen *scr, Atom action); + static Bool _XErrorOccured = False; @@ -317,13 +320,7 @@ sendClientMessage(Display *dpy, Window win, Atom message, static unsigned notifyPosition(WMScreen *scr, WMDraggingInfo *info) { - unsigned operation; - - switch (info->sourceOperation) { - default: - operation = None; - break; - } + Atom action = operationToAction(scr, info->sourceOperation); sendClientMessage(scr->display, info->destinationWindow, scr->xdndPositionAtom, @@ -331,7 +328,7 @@ notifyPosition(WMScreen *scr, WMDraggingInfo *info) 0, /* reserved */ info->location.x<<16|info->location.y, info->timestamp, - operation/* operation */); + action/* operation */); return 0; } @@ -418,34 +415,6 @@ updateDraggingInfo(WMScreen *scr, WMDraggingInfo *info, 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; - } - */ } @@ -503,36 +472,57 @@ processMotion(WMScreen *scr, WMDraggingInfo *info, WMDraggingInfo *oldInfo, rect->size.width = 0; } } +} + + + +static WMData* +convertSelection(WMView *view, Atom selection, Atom target, + void *cdata, Atom *type) +{ + WMScreen *scr = W_VIEW_SCREEN(view); + WMData *data; + char *typeName = XGetAtomName(scr->display, target); + + *type = target; + + data = view->dragSourceProcs->fetchDragData(view, typeName); + + if (typeName != NULL) + XFree(typeName); + + return data; +} + + +static void +selectionLost(WMView *view, Atom selection, void *cdata) +{ + if (W_VIEW_SCREEN(view)->dragSourceView == view) { + wwarning("DND selection lost during drag operation..."); + } +} + + +static void +selectionDone(WMView *view, Atom selection, Atom target, void *cdata) +{ - /* 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; + _XErrorOccured = 2; } /* @@ -594,9 +584,15 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], WMDraggingInfo dragInfo; WMDraggingInfo oldDragInfo; WMHandlerID timer = NULL; - WMData *draggedData = NULL; + static WMSelectionProcs handler = { + convertSelection, + selectionLost, + selectionDone + }; + wassertr(scr->dragSourceView == NULL); + wassertr(view->dragSourceProcs != NULL); @@ -614,9 +610,13 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], /* init dragging info */ + + scr->dragSourceView = view; + memset(&dragInfo, 0, sizeof(WMDraggingInfo)); memset(&oldDragInfo, 0, sizeof(WMDraggingInfo)); dragInfo.image = image; + dragInfo.sourceView = view; dragInfo.sourceWindow = W_VIEW_DRAWABLE(W_TopLevelOfView(view)); dragInfo.destinationWindow = dragInfo.sourceWindow; @@ -636,9 +636,14 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], _XErrorOccured = False; - /* XXX: take ownership of XdndSelection */ + /* take ownership of XdndSelection */ + if (!WMCreateSelectionHandler(view, scr->xdndSelectionAtom, + event->xmotion.time, + &handler, NULL)) { + wwarning("could not get ownership or DND selection"); + return; + } - if (view->dragSourceProcs->beganDragImage != NULL) { view->dragSourceProcs->beganDragImage(view, image, atLocation); } @@ -665,9 +670,8 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], XMoveWindow(dpy, icon, dragInfo.imageLocation.x, dragInfo.imageLocation.y); - if (state != 2) { - processMotion(scr, &dragInfo, &oldDragInfo, &rect, action); - } + processMotion(scr, &dragInfo, &oldDragInfo, &rect, action); + protectBlock(False); /* XXXif entered a different destination, check the operation */ @@ -675,6 +679,7 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], switch (state) { case 1: if (oldDragInfo.destinationWindow != None + && oldDragInfo.destinationWindow != scr->rootWin && (dragInfo.destinationWindow == None || dragInfo.destinationWindow == scr->rootWin)) { /* left the droppable window */ @@ -684,7 +689,9 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], break; case 2: - if (dragInfo.destinationWindow != None) { + if (dragInfo.destinationWindow != None + && dragInfo.destinationWindow != scr->rootWin) { + state = 1; action = -1; } @@ -693,6 +700,7 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], case 3: case 4: if (oldDragInfo.destinationWindow != None + && oldDragInfo.destinationWindow != scr->rootWin && (dragInfo.destinationWindow == None || dragInfo.destinationWindow == scr->rootWin)) { /* left the droppable window */ @@ -713,12 +721,13 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], oldDragInfo = dragInfo; updateDraggingInfo(scr, &dragInfo, &ev, icon); - + XMoveWindow(dpy, icon, dragInfo.imageLocation.x, dragInfo.imageLocation.y); - processMotion(scr, &dragInfo, &oldDragInfo, &rect, - action); + processMotion(scr, &dragInfo, &oldDragInfo, &rect, action); + + dragInfo.timestamp = ev.xbutton.time; protectBlock(False); @@ -741,20 +750,13 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], } 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) { + && ev.xclient.data.l[0] == dragInfo.destinationWindow) { if (ev.xclient.data.l[1] & 1) { - puts("got accept msg"); + SPIT("got accept msg"); /* will accept drop */ switch (state) { case 1: @@ -770,13 +772,9 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], state = 6; break; } - if (ev.xclient.data.l[4] == None) { - action = 0; - } else { - action = ev.xclient.data.l[4];/*XXX*/ - } + action = actionToOperation(scr, ev.xclient.data.l[4]); } else { - puts("got reject msg"); + SPIT("got reject msg"); switch (state) { case 1: case 3: @@ -825,7 +823,6 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], } if (ostate != state) { - printf("state changed to %i\n", state); if (state == 3) { XRecolorCursor(dpy, scr->defaultCursor, &green, &back); } else if (ostate == 3) { @@ -834,10 +831,13 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], ostate = state; } } - + if (timer) { WMDeleteTimerHandler(timer); timer = NULL; + } else if (_XErrorOccured) { + /* got a timeout, send leave */ + notifyDragLeave(scr, &dragInfo); } XUngrabPointer(dpy, CurrentTime); @@ -859,23 +859,18 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[], 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); - } + scr->dragSourceView = NULL; + WMDeleteSelectionHandler(view, scr->xdndSelectionAtom, + event->xmotion.time); + if (slideBack) { slideWindow(dpy, icon, dragInfo.imageLocation.x, dragInfo.imageLocation.y, @@ -900,7 +895,66 @@ cancelled: +static Atom +operationToAction(WMScreen *scr, WMDragOperationType operation) +{ + switch (operation) { + case WDOperationNone: + return None; + + case WDOperationCopy: + return scr->xdndActionCopy; + + case WDOperationMove: + return scr->xdndActionMove; + + case WDOperationLink: + return scr->xdndActionLink; + + case WDOperationAsk: + return scr->xdndActionAsk; + + case WDOperationPrivate: + return scr->xdndActionPrivate; + + default: + return None; + } +} + +static WMDragOperationType +actionToOperation(WMScreen *scr, Atom action) +{ + if (action == scr->xdndActionCopy) { + return WDOperationCopy; + + } else if (action == scr->xdndActionMove) { + return WDOperationMove; + + } else if (action == scr->xdndActionLink) { + return WDOperationLink; + + } else if (action == scr->xdndActionAsk) { + return WDOperationAsk; + + } else if (action == scr->xdndActionPrivate) { + return WDOperationPrivate; + + } else if (action == None) { + + return WDOperationCopy; + } else { + char *tmp = XGetAtomName(scr->display, action); + + wwarning("unknown XDND action %s from 0x%x", tmp, + (unsigned)scr->dragInfo.sourceWindow); + XFree(tmp); + + return WDOperationCopy; + } +} + @@ -934,21 +988,87 @@ getTypeList(Window window, XClientMessageEvent *event) } + +#define DISPATCH(view, func, info) (view)->dragDestinationProcs->func(view, info) + + + +static void +receivedData(WMView *view, Atom selection, Atom target, + Time timestamp, void *cdata, WMData *data) +{ + WMScreen *scr = W_VIEW_SCREEN(view); + WMDraggingInfo *info = (WMDraggingInfo*)cdata; + Bool res; + + res = view->dragDestinationProcs->performDragOperation(view, info, data); + + if (res) { + DISPATCH(view, concludeDragOperation, info); + } + + /* send finished message */ + sendClientMessage(scr->display, info->sourceWindow, + scr->xdndFinishedAtom, + info->destinationWindow, + 0, 0, 0, 0); + + memset(&scr->dragInfo, 0, sizeof(WMDraggingInfo)); +} + + + void W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) { -#if 0 WMScreen *scr = W_VIEW_SCREEN(toplevel); - WMView *oldView = NULL, *newView = NULL; + WMView *oldView = NULL; + WMView *newView = NULL; unsigned operation = 0; int x, y; + enum { + WNothing, + WEnter, + WLeave, + WCross, /* leave one and enter another */ + WUpdate, + WDrop + }; + Window source; + int what = WNothing; + Bool sendStatus = False; + + + source = scr->dragInfo.sourceWindow; + oldView = scr->dragInfo.destView; + + + if (event->message_type == scr->xdndFinishedAtom) { + WMView *view = scr->dragSourceView; + + if (view->dragSourceProcs->endedDragImage != NULL) { + view->dragSourceProcs->endedDragImage(view, + scr->dragInfo.image, + scr->dragInfo.imageLocation, + True); + } + + scr->dragSourceView = NULL; + + WMDeleteSelectionHandler(view, scr->xdndSelectionAtom, + scr->dragInfo.timestamp); + + return; + } + + + if (event->message_type == scr->xdndEnterAtom) { Window foo, bar; int bla; unsigned ble; - puts("entered"); - + if (scr->dragInfo.sourceWindow != None) { puts("received Enter event in bad order"); } @@ -956,14 +1076,14 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) memset(&scr->dragInfo, 0, sizeof(WMDraggingInfo)); - if ((event->data.l[0] >> 24) > XDND_VERSION) { + if ((event->data.l[1] >> 24) > XDND_VERSION) { wwarning("received drag & drop request with unsupported version %i", - (event->data.l[0] >> 24)); + (event->data.l[1] >> 24)); return; } scr->dragInfo.protocolVersion = event->data.l[1] >> 24; - scr->dragInfo.sourceWindow = event->data.l[0]; + scr->dragInfo.sourceWindow = source = event->data.l[0]; scr->dragInfo.destinationWindow = event->window; /* XXX */ @@ -981,103 +1101,147 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) newView = findViewInToplevel(scr->display, scr->dragInfo.destinationWindow, x, y); - - if (IS_DROPPABLE(view)) { - - scr->dragInfo.destinationView = view; - - operation = - view->dragDestinationProcs->draggingEntered(view, - &scr->dragInfo); - } - if (operation > 0) { - Atom action; - - switch (operation) { - default: - action = 0; - break; - } - - sendClientMessage(scr->display, scr->dragInfo.sourceWindow, - scr->xdndStatusAtom, - scr->dragInfo.destinationWindow, - 1, 0, 0, action); - } } 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; - + if (scr->dragInfo.protocolVersion >= 1) { scr->dragInfo.timestamp = event->data.l[3]; - scr->dragInfo.sourceOperation = event->data.l[4]; + scr->dragInfo.sourceOperation = actionToOperation(scr, + event->data.l[4]); + } else { scr->dragInfo.timestamp = CurrentTime; - scr->dragInfo.sourceOperation = 0; /*XXX*/ + scr->dragInfo.sourceOperation = WDOperationCopy; } translateCoordinates(scr, scr->dragInfo.destinationWindow, scr->dragInfo.location.x, scr->dragInfo.location.y, &x, &y); - view = findViewInToplevel(scr->display, - scr->dragInfo.destinationWindow, - x, y); - - if (scr->dragInfo.destinationView != view) { - WMView *oldVIew = scr->dragInfo.destinationView; - - oldView->dragDestinationProcs->draggingExited(oldView, - &scr->dragInfo); - - scr->dragInfo.destinationView = NULL; - } + newView = findViewInToplevel(scr->display, + scr->dragInfo.destinationWindow, + x, y); + } else if (event->message_type == scr->xdndLeaveAtom + && scr->dragInfo.sourceWindow == event->data.l[0]) { - if (IS_DROPPABLE(view)) { - - - operation = - view->dragDestinationProcs->draggingUpdated(view, - &scr->dragInfo); - } + memset(&scr->dragInfo, 0, sizeof(WMDraggingInfo)); + + } else if (event->message_type == scr->xdndDropAtom + && scr->dragInfo.sourceWindow == event->data.l[0]) { + + /* drop */ + what = WDrop; - if (operation == 0) { - sendClientMessage(scr->display, scr->dragInfo.sourceWindow, - scr->xdndStatusAtom, - scr->dragInfo.destinationWindow, - 0, 0, 0, None); + } else { + return; + } + + + /* + * Now map the XDND events to WINGs events. + */ + + if (what == WNothing) { + if (IS_DROPPABLE(newView)) { + if (oldView == NULL) { /* entered */ + what = WEnter; + } else if (oldView == newView) { /* updated */ + what = WUpdate; + } else { + what = WCross; + } } else { - Atom action; - - switch (operation) { - default: - action = 0; - break; + if (oldView != NULL) { + what = WLeave; + } else { + /* just send rejection msg */ + sendStatus = True; } - - sendClientMessage(scr->display, scr->dragInfo.sourceWindow, - scr->xdndStatusAtom, - scr->dragInfo.destinationWindow, - 1, 0, 0, action); } - - } else if (event->message_type == scr->xdndLeaveAtom - && scr->dragInfo.sourceWindow == event->data.l[0]) { + } + + + + switch (what) { - void (*draggingExited)(WMView *self, WMDraggingInfo *info); + case WEnter: + scr->dragInfo.destView = newView; + operation = DISPATCH(newView, draggingEntered, &scr->dragInfo); + sendStatus = True; + break; - puts("leave"); - } else if (event->message_type == scr->xdndDropAtom - && scr->dragInfo.sourceWindow == event->data.l[0]) { + case WLeave: + scr->dragInfo.destView = NULL; + DISPATCH(oldView, draggingExited, &scr->dragInfo); + sendStatus = True; + operation = WDOperationNone; + break; + + case WCross: + DISPATCH(oldView, draggingExited, &scr->dragInfo); + scr->dragInfo.destView = newView; + operation = DISPATCH(newView, draggingEntered, &scr->dragInfo); + sendStatus = True; + break; + case WUpdate: + operation = DISPATCH(oldView, draggingUpdated, &scr->dragInfo); + sendStatus = True; + break; + case WDrop: + { + char *type; + + type = DISPATCH(oldView, prepareForDragOperation, &scr->dragInfo); + + if (type != NULL) { + if (!WMRequestSelection(scr->dragInfo.destView, + scr->xdndSelectionAtom, + XInternAtom(scr->display, type, False), + scr->dragInfo.timestamp, + receivedData, &scr->dragInfo)) { + wwarning("could not request data for dropped data"); + + /* send finished message */ + sendClientMessage(scr->display, source, + scr->xdndFinishedAtom, + scr->dragInfo.destinationWindow, + 0, 0, 0, 0); + } + } else { + /* send finished message */ + sendClientMessage(scr->display, source, + scr->xdndFinishedAtom, + scr->dragInfo.destinationWindow, + 0, 0, 0, 0); + } + } + break; - puts("drop"); + default: + break; + } + + + + if (sendStatus) { + Atom action; + + action = operationToAction(scr, operation); + + sendClientMessage(scr->display, source, + scr->xdndStatusAtom, + scr->dragInfo.destinationWindow, + action != None ? 1 : 0, 0, 0, action); } -#endif } + + + diff --git a/WINGs/selection.c b/WINGs/selection.c dissimilarity index 72% index a4f3395c..c707fc0f 100644 --- a/WINGs/selection.c +++ b/WINGs/selection.c @@ -1,422 +1,461 @@ - - -#include - -#include - -#include "WINGsP.h" - -#define MAX_PROPERTY_SIZE 8*1024 - - -typedef struct SelectionHandler { - WMWidget *widget; - Atom selection; - Time timestamp; - WMConvertSelectionProc *convProc; - WMLoseSelectionProc *loseProc; - WMSelectionDoneProc *doneProc; - - struct { - unsigned delete_pending:1; - unsigned done_pending:1; - } flags; - - struct SelectionHandler *next; -} SelectionHandler; - - -static SelectionHandler *selHandlers = NULL; - - -void -WMDeleteSelectionHandler(WMWidget *widget, Atom selection) -{ - SelectionHandler *handler, *tmp; - Display *dpy = WMWidgetScreen(widget)->display; - Window win = WMWidgetXID(widget); - Time timestamp; - - if (!selHandlers) - return; - - tmp = selHandlers; - - if (tmp->widget == widget) { - - if (tmp->flags.done_pending) { - tmp->flags.delete_pending = 1; - return; - } - selHandlers = tmp->next; - timestamp = tmp->timestamp; - wfree(tmp); - } else { - while (tmp->next) { - if (tmp->next->widget == widget) { - - if (tmp->next->flags.done_pending) { - tmp->next->flags.delete_pending = 1; - return; - } - handler = tmp->next; - tmp->next = handler->next; - timestamp = handler->timestamp; - wfree(handler); - break; - } - tmp = tmp->next; - } - } - - XGrabServer(dpy); - if (XGetSelectionOwner(dpy, selection) == win) { - XSetSelectionOwner(dpy, selection, None, timestamp); - } - XUngrabServer(dpy); -} - - -static Bool gotError = 0; -/* -static int -errorHandler(XErrorEvent *error) -{ - return 0; -} -*/ - -static Bool -writeSelection(Display *dpy, Window requestor, Atom property, Atom type, - void *value, long length, int format) -{ -/* - printf("write to %x: %s\n", requestor, XGetAtomName(dpy, property)); -*/ - gotError = False; - -#ifndef __sgi - if (!XChangeProperty(dpy, requestor, property, type, format, - PropModeReplace, value, length)) - return False; -#else - /* in sgi seems this seems to return void */ - XChangeProperty(dpy, requestor, property, type, format, - PropModeReplace, value, length); -#endif - - XFlush(dpy); - - return !gotError; -} - - -static void -notifySelection(XEvent *event, Atom prop) -{ - XEvent ev; -/* - printf("envent to %x\n", event->xselectionrequest.requestor); -*/ - ev.xselection.type = SelectionNotify; - ev.xselection.serial = 0; - ev.xselection.send_event = True; - ev.xselection.display = event->xselectionrequest.display; - ev.xselection.requestor = event->xselectionrequest.requestor; - ev.xselection.target = event->xselectionrequest.target; - ev.xselection.selection = event->xselectionrequest.selection; - ev.xselection.property = prop; - ev.xselection.time = event->xselectionrequest.time; - - XSendEvent(event->xany.display, event->xselectionrequest.requestor, - False, 0, &ev); - XFlush(event->xany.display); -} - - -void -W_HandleSelectionEvent(XEvent *event) -{ - SelectionHandler *handler; - - handler = selHandlers; - - while (handler) { - if (WMWidgetXID(handler->widget)==event->xany.window -/* && handler->selection == event->selection*/) { - - switch (event->type) { - case SelectionClear: - if (handler->loseProc) - (*handler->loseProc)(handler->widget, handler->selection); - break; - - case SelectionRequest: - if (handler->convProc) { - Atom atom; - void *data; - unsigned length; - int format; - Atom prop; - - /* they're requesting for something old */ - if (event->xselectionrequest.time < handler->timestamp - && event->xselectionrequest.time != CurrentTime) { - - notifySelection(event, None); - break; - } - - handler->flags.done_pending = 1; - - if (!(*handler->convProc)(handler->widget, - handler->selection, - event->xselectionrequest.target, - &atom, &data, &length, &format)) { - - notifySelection(event, None); - break; - } - - - prop = event->xselectionrequest.property; - /* obsolete clients that don't set the property field */ - if (prop == None) - prop = event->xselectionrequest.target; - - if (!writeSelection(event->xselectionrequest.display, - event->xselectionrequest.requestor, - prop, atom, data, length, format)) { - - wfree(data); - notifySelection(event, None); - break; - } - wfree(data); - - notifySelection(event, prop); - - if (handler->doneProc) { - (*handler->doneProc)(handler->widget, - handler->selection, - event->xselectionrequest.target); - } - - handler->flags.done_pending = 0; - - /* in case the handler was deleted from some - * callback */ - if (handler->flags.delete_pending) { - WMDeleteSelectionHandler(handler->widget, - handler->selection); - } - } - break; - - case SelectionNotify: - - break; - } - } - - handler = handler->next; - } -} - - - - -Bool -WMCreateSelectionHandler(WMWidget *w, Atom selection, Time timestamp, - WMConvertSelectionProc *convProc, - WMLoseSelectionProc *loseProc, - WMSelectionDoneProc *doneProc) -{ - SelectionHandler *handler, *tmp; - Display *dpy = WMWidgetScreen(w)->display; - - XSetSelectionOwner(dpy, selection, WMWidgetXID(w), timestamp); - if (XGetSelectionOwner(dpy, selection) != WMWidgetXID(w)) - return False; - - handler = malloc(sizeof(SelectionHandler)); - if (!handler) - return False; - - handler->widget = w; - handler->selection = selection; - handler->timestamp = timestamp; - handler->convProc = convProc; - handler->loseProc = loseProc; - handler->doneProc = doneProc; - memset(&handler->flags, 0, sizeof(handler->flags)); - - if (!selHandlers) { - /* first in the queue */ - handler->next = selHandlers; - selHandlers = handler; - } else { - tmp = selHandlers; - while (tmp->next) { - tmp = tmp->next; - } - handler->next = tmp->next; - tmp->next = handler; - } - - return True; -} - - - - -static void -timeoutHandler(void *data) -{ - *(int*)data = 1; -} - - -static Bool -getInternalSelection(WMScreen *scr, Atom selection, Atom target, - void **data, unsigned *length) -{ - Window owner; - SelectionHandler *handler; - - /* - * Check if the selection is owned by this application and if so, - * do the conversion directly. - */ - - *data = NULL; - - owner = XGetSelectionOwner(scr->display, selection); - if (!owner) - return False; - - handler = selHandlers; - - while (handler) { - if (WMWidgetXID(handler->widget) == owner - /* && handler->selection == event->selection*/) { - break; - } - handler = handler->next; - } - - if (!handler) - return False; - - if (handler->convProc) { - Atom atom; - int format; - - if (!(*handler->convProc)(handler->widget, handler->selection, - target, &atom, data, length, &format)) { - return True; - } - - if (handler->doneProc) { - (*handler->doneProc)(handler->widget, handler->selection, target); - } - } - - return True; -} - - -char* -W_GetTextSelection(WMScreen *scr, Atom selection) -{ - int buffer = -1; - - switch (selection) { - case XA_CUT_BUFFER0: - buffer = 0; - break; - case XA_CUT_BUFFER1: - buffer = 1; - break; - case XA_CUT_BUFFER2: - buffer = 2; - break; - case XA_CUT_BUFFER3: - buffer = 3; - break; - case XA_CUT_BUFFER4: - buffer = 4; - break; - case XA_CUT_BUFFER5: - buffer = 5; - break; - case XA_CUT_BUFFER6: - buffer = 6; - break; - case XA_CUT_BUFFER7: - buffer = 7; - break; - } - if (buffer >= 0) { - char *data; - int size; - - data = XFetchBuffer(scr->display, &size, buffer); - - return data; - } else { - char *data; - int bits; - Atom rtype; - unsigned long len, bytes; - WMHandlerID timer; - int timeout = 0; - XEvent ev; - unsigned length; - - XDeleteProperty(scr->display, scr->groupLeader, scr->clipboardAtom); - - if (getInternalSelection(scr, selection, XA_STRING, (void**)&data, - &length)) { - - return data; - } - - XConvertSelection(scr->display, selection, XA_STRING, - scr->clipboardAtom, scr->groupLeader, - scr->lastEventTime); - - timer = WMAddTimerHandler(1000, timeoutHandler, &timeout); - - while (!XCheckTypedWindowEvent(scr->display, scr->groupLeader, - SelectionNotify, &ev) && !timeout); - - if (!timeout) { - WMDeleteTimerHandler(timer); - } else { - wwarning("selection retrieval timed out"); - return NULL; - } - - /* nobody owns the selection or the current owner has - * nothing to do with what we need */ - if (ev.xselection.property == None) { - return NULL; - } - - if (XGetWindowProperty(scr->display, scr->groupLeader, - scr->clipboardAtom, 0, MAX_PROPERTY_SIZE, - False, XA_STRING, &rtype, &bits, &len, - &bytes, (unsigned char**)&data)!=Success) { - return NULL; - } - if (rtype!=XA_STRING || bits!=8) { - wwarning("invalid data in text selection"); - if (data) - XFree(data); - return NULL; - } - return data; - } -} - + + +#include + +#include + +#include "WINGsP.h" + +#define MAX_PROPERTY_SIZE 8*1024 + + +typedef struct SelectionHandler { + WMView *view; + Atom selection; + Time timestamp; + WMSelectionProcs procs; + void *data; + + struct { + unsigned delete_pending:1; + unsigned done_pending:1; + } flags; +} SelectionHandler; + + +typedef struct SelectionCallback { + WMView *view; + Atom selection; + Atom target; + Time timestamp; + WMSelectionCallback *callback; + void *data; + + struct { + unsigned delete_pending:1; + unsigned done_pending:1; + } flags; +} SelectionCallback; + + +WMBag *selCallbacks = NULL; + +WMBag *selHandlers = NULL; + + +void +WMDeleteSelectionHandler(WMView *view, Atom selection, Time timestamp) +{ + SelectionHandler *handler; + Display *dpy = W_VIEW_SCREEN(view)->display; + Window win = W_VIEW_DRAWABLE(view); + WMBagIterator iter; + + if (!selHandlers) + return; + + + WM_ITERATE_BAG(selHandlers, handler, iter) { + if (handler->view == view + && (handler->selection == selection || selection == None) + && (handler->timestamp == timestamp || timestamp == CurrentTime)) { + + if (handler->flags.done_pending) { + handler->flags.delete_pending = 1; + return; + } + WMRemoveFromBag(selHandlers, handler); + wfree(handler); + break; + } + } + + XGrabServer(dpy); + if (XGetSelectionOwner(dpy, selection) == win) { + XSetSelectionOwner(dpy, selection, None, timestamp); + } + XUngrabServer(dpy); +} + + + +void +WMDeleteSelectionCallback(WMView *view, Atom selection, Time timestamp) +{ + SelectionCallback *handler; + WMBagIterator iter; + + if (!selCallbacks) + return; + + WM_ITERATE_BAG(selCallbacks, handler, iter) { + if (handler->view == view + && (handler->selection == selection || selection == 0) + && (handler->timestamp == timestamp || timestamp == CurrentTime)) { + + if (handler->flags.done_pending) { + handler->flags.delete_pending = 1; + return; + } + WMRemoveFromBag(selCallbacks, handler); + wfree(handler); + break; + } + } +} + + + +static Bool gotError = 0; +/* +static int +errorHandler(XErrorEvent *error) +{ + return 0; +} +*/ + +static Bool +writeSelection(Display *dpy, Window requestor, Atom property, Atom type, + WMData *data) +{ + int format; + + format = WMGetDataFormat(data); + if (format == 0) + format = 8; + +/* + printf("write to %x: %s\n", requestor, XGetAtomName(dpy, property)); +*/ + gotError = False; + +#ifndef __sgi + if (!XChangeProperty(dpy, requestor, property, type, format, + PropModeReplace, WMDataBytes(data), + WMGetDataLength(data))) + return False; +#else + /* in sgi seems this seems to return void */ + XChangeProperty(dpy, requestor, property, type, format, + PropModeReplace, WMDataBytes(data), WMGetDataLength(data)); +#endif + + XFlush(dpy); + + return !gotError; +} + + +static void +notifySelection(XEvent *event, Atom prop) +{ + XEvent ev; +/* + printf("envent to %x\n", event->xselectionrequest.requestor); +*/ + ev.xselection.type = SelectionNotify; + ev.xselection.serial = 0; + ev.xselection.send_event = True; + ev.xselection.display = event->xselectionrequest.display; + ev.xselection.requestor = event->xselectionrequest.requestor; + ev.xselection.target = event->xselectionrequest.target; + ev.xselection.selection = event->xselectionrequest.selection; + ev.xselection.property = prop; + ev.xselection.time = event->xselectionrequest.time; + + XSendEvent(event->xany.display, event->xselectionrequest.requestor, + False, 0, &ev); + XFlush(event->xany.display); +} + + + +static void +deleteHandlers(WMBagIterator iter) +{ + SelectionHandler *handler; + + if (iter == NULL) + handler = WMBagFirst(selHandlers, &iter); + else + handler = WMBagNext(selHandlers, &iter); + + if (handler == NULL) + return; + + deleteHandlers(iter); + + if (handler->flags.delete_pending) { + WMDeleteSelectionHandler(handler->view, handler->selection, + handler->timestamp); + } +} + + + +static void +handleRequestEvent(XEvent *event) +{ + SelectionHandler *handler; + WMBagIterator iter; + Bool handledRequest = False; + + WM_ITERATE_BAG(selHandlers, handler, iter) { + + switch (event->type) { + case SelectionClear: + if (W_VIEW_DRAWABLE(handler->view) + != event->xselectionclear.window) { + break; + } + + handler->flags.done_pending = 1; + if (handler->procs.selectionLost) + handler->procs.selectionLost(handler->view, + handler->selection, + handler->data); + handler->flags.done_pending = 0; + handler->flags.delete_pending = 1; + break; + + case SelectionRequest: + if (W_VIEW_DRAWABLE(handler->view) + != event->xselectionrequest.owner) { + break; + } + + if (handler->procs.convertSelection != NULL + && handler->selection == event->xselectionrequest.selection) { + Atom atom; + WMData *data; + Atom prop; + + /* they're requesting for something old.. maybe another handler + * can handle it */ + if (event->xselectionrequest.time < handler->timestamp + && event->xselectionrequest.time != CurrentTime) { + break; + } + + handler->flags.done_pending = 1; + + data = handler->procs.convertSelection(handler->view, + handler->selection, + event->xselectionrequest.target, + handler->data, + &atom); + if (data == NULL) { + break; + } + + handledRequest = True; + + + prop = event->xselectionrequest.property; + /* obsolete clients that don't set the property field */ + if (prop == None) + prop = event->xselectionrequest.target; + + if (!writeSelection(event->xselectionrequest.display, + event->xselectionrequest.requestor, + prop, atom, data)) { + WMReleaseData(data); + notifySelection(event, None); + break; + } + WMReleaseData(data); + + notifySelection(event, prop); + + if (handler->procs.selectionDone != NULL) { + handler->procs.selectionDone(handler->view, + handler->selection, + event->xselectionrequest.target, + handler->data); + } + + handler->flags.done_pending = 0; + + if (!handledRequest) { + notifySelection(event, None); + } + } + break; + } + } + + deleteHandlers(NULL); +} + + + +static void +deleteCallbacks(WMBagIterator iter) +{ + SelectionCallback *handler; + + if (iter == NULL) + handler = WMBagFirst(selCallbacks, &iter); + else + handler = WMBagNext(selCallbacks, &iter); + + if (handler == NULL) + return; + + deleteCallbacks(iter); + + if (handler->flags.delete_pending) { + WMDeleteSelectionCallback(handler->view, handler->selection, + handler->timestamp); + } +} + + + + +static WMData* +getSelectionData(Display *dpy, Window win, Atom where) +{ + WMData *wdata; + unsigned char *data; + Atom rtype; + unsigned bits; + unsigned long len, bytes; + + + if (XGetWindowProperty(dpy, win, where, 0, MAX_PROPERTY_SIZE, + False, AnyPropertyType, &rtype, &bits, &len, + &bytes, &data)!=Success) { + return NULL; + } + + wdata = WMCreateDataWithBytesAndDestructor(data, len, + (WMFreeDataProc*)XFree); + if (wdata == NULL) { + return NULL; + } + WMSetDataFormat(wdata, bits); + + return wdata; +} + + +static void +handleNotifyEvent(XEvent *event) +{ + SelectionCallback *handler; + WMBagIterator iter; + WMData *data; + + WM_ITERATE_BAG(selCallbacks, handler, iter) { + + if (W_VIEW_DRAWABLE(handler->view) != event->xselection.requestor + && handler->selection == event->xselection.selection) { + continue; + } + handler->flags.done_pending = 1; + + if (event->xselection.property == None) { + data = NULL; + } else { + data = getSelectionData(event->xselection.display, + event->xselection.requestor, + event->xselection.property); + } + + (*handler->callback)(handler->view, handler->selection, + handler->target, handler->timestamp, + handler->data, data); + + if (data != NULL) { + WMReleaseData(data); + } + handler->flags.done_pending = 0; + handler->flags.delete_pending = 1; + } + deleteCallbacks(NULL); +} + + + +void +W_HandleSelectionEvent(XEvent *event) +{ + if (event->type == SelectionNotify) { + handleNotifyEvent(event); + } else { + handleRequestEvent(event); + } +} + + + + +Bool +WMCreateSelectionHandler(WMView *view, Atom selection, Time timestamp, + WMSelectionProcs *procs, void *cdata) +{ + SelectionHandler *handler; + Display *dpy = W_VIEW_SCREEN(view)->display; + + XSetSelectionOwner(dpy, selection, W_VIEW_DRAWABLE(view), timestamp); + if (XGetSelectionOwner(dpy, selection) != W_VIEW_DRAWABLE(view)) + return False; + + handler = malloc(sizeof(SelectionHandler)); + if (handler == NULL) + return False; + + handler->view = view; + handler->selection = selection; + handler->timestamp = timestamp; + handler->procs = *procs; + handler->data = cdata; + memset(&handler->flags, 0, sizeof(handler->flags)); + + if (selHandlers == NULL) { + selHandlers = WMCreateTreeBag(); + } + + WMPutInBag(selHandlers, handler); + + return True; +} + + + +Bool +WMRequestSelection(WMView *view, Atom selection, Atom target, Time timestamp, + WMSelectionCallback *callback, void *cdata) +{ + SelectionCallback *handler; + + if (XGetSelectionOwner(W_VIEW_SCREEN(view)->display, selection) == None) + return False; + + handler = wmalloc(sizeof(SelectionCallback)); + + handler->view = view; + handler->selection = selection; + handler->target = target; + handler->timestamp = timestamp; + handler->callback = callback; + handler->data = cdata; + memset(&handler->flags, 0, sizeof(handler->flags)); + + if (selCallbacks == NULL) { + selCallbacks = WMCreateTreeBag(); + } + + WMPutInBag(selCallbacks, handler); + + if (!XConvertSelection(W_VIEW_SCREEN(view)->display, selection, target, + W_VIEW_SCREEN(view)->clipboardAtom, + W_VIEW_DRAWABLE(view), timestamp)) { + return False; + } + + return True; +} + diff --git a/WINGs/wcolorwell.c b/WINGs/wcolorwell.c index fb7b3356..0205272c 100644 --- a/WINGs/wcolorwell.c +++ b/WINGs/wcolorwell.c @@ -46,18 +46,42 @@ 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 WMData* fetchDragData(WMView *self, char *type); + +static WMDragSourceProcs _DragSourceProcs = { + draggingSourceOperation, + NULL, + NULL, + fetchDragData }; -#endif + + +static unsigned draggingEntered(WMView *self, WMDraggingInfo *info); +static unsigned draggingUpdated(WMView *self, WMDraggingInfo *info); +static void draggingExited(WMView *self, WMDraggingInfo *info); +static char *prepareForDragOperation(WMView *self, WMDraggingInfo *info); +static Bool performDragOperation(WMView *self, WMDraggingInfo *info, + WMData *data); +static void concludeDragOperation(WMView *self, WMDraggingInfo *info); + +static WMDragDestinationProcs _DragDestinationProcs = { + draggingEntered, + draggingUpdated, + draggingExited, + prepareForDragOperation, + performDragOperation, + concludeDragOperation +}; + #define DEFAULT_WIDTH 60 #define DEFAULT_HEIGHT 30 @@ -168,7 +192,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 +309,40 @@ 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); + return WDOperationCopy; } -static void -slideView(WMView *view, int srcX, int srcY, int dstX, int dstY) +static WMData* +fetchDragData(WMView *self, char *type) { - double x, y, dx, dy; - int i; - - srcX -= 8; - srcY -= 8; - dstX -= 8; - dstY -= 8; + char *color = WMGetColorRGBDescription(((WMColorWell*)self->self)->color); + WMData *data; - x = srcX; - y = srcY; + data = WMCreateDataWithBytes(color, strlen(color)+1); - 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; - } -} - - - -static Window -findChildInWindow(Display *dpy, Window toplevel, int x, int y) -{ - Window foo, bar; - Window *children; - unsigned nchildren; - int i; + free(color); - 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; + return data; } -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 +365,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 +424,53 @@ destroyColorWell(ColorWell *cPtr) wfree(cPtr); } + + +static unsigned +draggingEntered(WMView *self, WMDraggingInfo *info) +{ + return WDOperationCopy; +} + + +static unsigned +draggingUpdated(WMView *self, WMDraggingInfo *info) +{ + return WDOperationCopy; +} + + +static void +draggingExited(WMView *self, WMDraggingInfo *info) +{ + +} + + +static char* +prepareForDragOperation(WMView *self, WMDraggingInfo *info) +{ + return "application/X-color"; +} + + +static Bool +performDragOperation(WMView *self, WMDraggingInfo *info, WMData *data) +{ + char *colorName = WMDataBytes(data); + WMColor *color; + + color = WMCreateNamedColor(W_VIEW_SCREEN(self), colorName, True); + + WMSetColorWellColor(self->self, color); + + WMReleaseColor(color); + + return True; +} + + +static void +concludeDragOperation(WMView *self, WMDraggingInfo *info) +{ +} diff --git a/WINGs/widgets.c b/WINGs/widgets.c index 53e71b56..61b242f0 100644 --- a/WINGs/widgets.c +++ b/WINGs/widgets.c @@ -559,10 +559,16 @@ WMCreateScreenWithRContext(Display *display, int screen, RContext *context) "XdndDrop", "XdndFinished", "XdndTypeList", + "XdndActionCopy", + "XdndActionMove", + "XdndActionLink", + "XdndActionAsk", + "XdndActionPrivate", "XdndStatus", "WM_STATE" }; Atom atoms[sizeof(atomNames)/sizeof(char*)]; + int i = 0; if (!initialized) { @@ -766,26 +772,33 @@ WMCreateScreenWithRContext(Display *display, int screen, RContext *context) } } #endif - - scrPtr->attribsAtom = atoms[0]; - - scrPtr->deleteWindowAtom = atoms[1]; - scrPtr->protocolsAtom = atoms[2]; + i = 0; + scrPtr->attribsAtom = atoms[i++]; + + scrPtr->deleteWindowAtom = atoms[i++]; + + scrPtr->protocolsAtom = atoms[i++]; - 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->clipboardAtom = atoms[i++]; + + scrPtr->xdndAwareAtom = atoms[i++]; + scrPtr->xdndSelectionAtom = atoms[i++]; + scrPtr->xdndEnterAtom = atoms[i++]; + scrPtr->xdndLeaveAtom = atoms[i++]; + scrPtr->xdndPositionAtom = atoms[i++]; + scrPtr->xdndDropAtom = atoms[i++]; + scrPtr->xdndFinishedAtom = atoms[i++]; + scrPtr->xdndTypeListAtom = atoms[i++]; + scrPtr->xdndStatusAtom = atoms[i++]; + + scrPtr->xdndActionCopy = atoms[i++]; + scrPtr->xdndActionMove = atoms[i++]; + scrPtr->xdndActionLink = atoms[i++]; + scrPtr->xdndActionAsk = atoms[i++]; + scrPtr->xdndActionPrivate = atoms[i++]; + + scrPtr->wmStateAtom = atoms[i++]; scrPtr->rootView = W_CreateRootView(scrPtr); diff --git a/WINGs/wtabview.c b/WINGs/wtabview.c index e46afd48..5aa97c0c 100644 --- a/WINGs/wtabview.c +++ b/WINGs/wtabview.c @@ -28,7 +28,7 @@ typedef struct W_TabView { struct { WMReliefType relief:4; WMTitlePosition titlePosition:4; - WMTabViewTypes type:2; + WMTabViewType type:2; unsigned tabbed:1; unsigned dontFitAll:1; diff --git a/WINGs/wtextfield.c b/WINGs/wtextfield.c index c0634d83..52d23e81 100644 --- a/WINGs/wtextfield.c +++ b/WINGs/wtextfield.c @@ -64,6 +64,11 @@ typedef struct W_TextField { unsigned int secure:1; /* password entry style */ unsigned int pointerGrabbed:1; + + unsigned int ownsSelection:1; + + unsigned int waitingSelection:1; /* requested selection, but + * didnt get yet */ /**/ unsigned int notIllegalMovement:1; @@ -116,6 +121,20 @@ struct W_ViewDelegate _TextFieldViewDelegate = { }; + +static void lostHandler(WMView *view, Atom selection, void *cdata); + +static WMData *requestHandler(WMView *view, Atom selection, Atom target, + void *cdata, Atom *type); + + +static WMSelectionProcs selectionHandler = { + requestHandler, + lostHandler, + NULL +}; + + #define TEXT_WIDTH(tPtr, start) (WMWidthOfString((tPtr)->font, \ &((tPtr)->text[(start)]), (tPtr)->textLen - (start) + 1)) @@ -210,73 +229,73 @@ decrToFit(TextField *tPtr) #undef TEXT_WIDTH #undef TEXT_WIDTH2 -static Bool -requestHandler(WMWidget *w, Atom selection, Atom target, Atom *type, - void **value, unsigned *length, int *format) + + +static WMData* +requestHandler(WMView *view, Atom selection, Atom target, void *cdata, + Atom *type) { - TextField *tPtr = w; + TextField *tPtr = view->self; int count; Display *dpy = tPtr->view->screen->display; Atom _TARGETS; - char *text; - text = XGetAtomName(tPtr->view->screen->display,target); - XFree(text); - text = XGetAtomName(tPtr->view->screen->display,selection); - XFree(text); - - *format = 32; - *length = 0; - *value = NULL; + Atom TEXT = XInternAtom(dpy, "TEXT", False); + Atom COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", False); + WMData *data; + count = tPtr->selection.count < 0 ? tPtr->selection.position + tPtr->selection.count : tPtr->selection.position; - if (target == XA_STRING || - target == XInternAtom(dpy, "TEXT", False) || - target == XInternAtom(dpy, "COMPOUND_TEXT", False)) { - *value = wstrdup(&(tPtr->text[count])); - *length = abs(tPtr->selection.count); - *format = 8; + if (target == XA_STRING || target == TEXT || target == COMPOUND_TEXT) { + + data = WMCreateDataWithBytes(&(tPtr->text[count]), + abs(tPtr->selection.count)); + WMSetDataFormat(data, 8); *type = target; - return True; + + return data; } _TARGETS = XInternAtom(dpy, "TARGETS", False); if (target == _TARGETS) { - int *ptr; + Atom *ptr; - *length = 4; - ptr = *value = (char *) wmalloc(4 * sizeof(Atom)); + ptr = wmalloc(4 * sizeof(Atom)); ptr[0] = _TARGETS; ptr[1] = XA_STRING; - ptr[2] = XInternAtom(dpy, "TEXT", False); - ptr[3] = XInternAtom(dpy, "COMPOUND_TEXT", False); + ptr[2] = TEXT; + ptr[3] = COMPOUND_TEXT; + + data = WMCreateDataWithBytes(ptr, 4*4); + WMSetDataFormat(data, 32); + *type = target; - return True; + return data; } - /* - *target = XA_PRIMARY; - */ - return False; + + return NULL; } static void -lostHandler(WMWidget *w, Atom selection) +lostHandler(WMView *view, Atom selection, void *cdata) { - TextField *tPtr = (WMTextField*)w; + TextField *tPtr = (WMTextField*)view->self; + tPtr->flags.ownsSelection = 0; tPtr->selection.count = 0; paintTextField(tPtr); } + static void _notification(void *observerData, WMNotification *notification) { WMTextField *to = (WMTextField*)observerData; WMTextField *tw = (WMTextField*)WMGetNotificationClientData(notification); - if (to != tw) lostHandler(to, 0); + if (to != tw) lostHandler(to->view, XA_PRIMARY, NULL); } WMTextField* @@ -327,8 +346,6 @@ WMCreateTextField(WMWidget *parent) |ButtonReleaseMask|ButtonPressMask|KeyPressMask|Button1MotionMask, handleTextFieldActionEvents, tPtr); - WMCreateSelectionHandler(tPtr, XA_PRIMARY, CurrentTime, requestHandler, - lostHandler, NULL); WMAddNotificationObserver(_notification, tPtr, "_lostOwnership", tPtr); @@ -1185,20 +1202,17 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event) if (!cancelSelection) { if (tPtr->selection.count != tPtr->cursorPosition - tPtr->selection.position) { - WMNotification *notif; tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position; - XSetSelectionOwner(tPtr->view->screen->display, - XA_PRIMARY, tPtr->view->window, - event->xbutton.time); - notif = WMCreateNotification("_lostOwnership", NULL, tPtr); - WMPostNotification(notif); - WMReleaseNotification(notif); + WMPostNotificationName("_lostOwnership", NULL, tPtr); refresh = 1; } } else { + + lostHandler(tPtr->view, XA_PRIMARY, NULL); + if (tPtr->selection.count) { tPtr->selection.count = 0; refresh = 1; @@ -1264,21 +1278,56 @@ pointToCursorPosition(TextField *tPtr, int x) } + +static void +pasteText(WMView *view, Atom selection, Atom target, Time timestamp, + void *cdata, WMData *data) +{ + TextField *tPtr = (TextField*)view->self; + char *str; + + tPtr->flags.waitingSelection = 0; + + if (data != NULL) { + str = (char*)WMDataBytes(data); + + WMInsertTextFieldText(tPtr, str, tPtr->cursorPosition); + NOTIFY(tPtr, didChange, WMTextDidChangeNotification, + (void*)WMInsertTextEvent); + } else { + int n; + + str = XFetchBuffer(tPtr->view->screen->display, &n, 0); + + if (str != NULL) { + str[n] = 0; + WMInsertTextFieldText(tPtr, str, tPtr->cursorPosition); + XFree(str); + NOTIFY(tPtr, didChange, WMTextDidChangeNotification, + (void*)WMInsertTextEvent); + } + } +} + + static void handleTextFieldActionEvents(XEvent *event, void *data) { TextField *tPtr = (TextField*)data; static int move = 0; static Time lastButtonReleasedEvent = 0; + Display *dpy = event->xany.display; CHECK_CLASS(data, WC_TextField); switch (event->type) { case KeyPress: + if (tPtr->flags.waitingSelection) { + return; + } if (tPtr->flags.enabled && tPtr->flags.focused) { handleTextFieldKeyPress(tPtr, event); - XGrabPointer(WMScreenDisplay(W_VIEW(tPtr)->screen), - W_VIEW(tPtr)->window, False, + XGrabPointer(dpy, W_VIEW(tPtr)->window, False, PointerMotionMask|ButtonPressMask|ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, W_VIEW(tPtr)->screen->invisibleCursor, @@ -1291,7 +1340,10 @@ handleTextFieldActionEvents(XEvent *event, void *data) if (tPtr->flags.pointerGrabbed) { tPtr->flags.pointerGrabbed = 0; - XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr)->screen), CurrentTime); + XUngrabPointer(dpy, CurrentTime); + } + if (tPtr->flags.waitingSelection) { + return; } if (tPtr->flags.enabled && (event->xmotion.state & Button1Mask)) { @@ -1309,40 +1361,35 @@ handleTextFieldActionEvents(XEvent *event, void *data) tPtr->viewPosition--; } - /*if (!tPtr->selection.count) { - tPtr->selection.position = tPtr->cursorPosition; - }*/ - tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xmotion.x); tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position; - /*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count);*/ - /* - printf("notify %d %d\n",event->xmotion.x,tPtr->usableWidth); - */ + if (tPtr->selection.count != 0) { + if (!tPtr->flags.ownsSelection) { + WMCreateSelectionHandler(tPtr->view, + XA_PRIMARY, + event->xbutton.time, + &selectionHandler, NULL); + tPtr->flags.ownsSelection = 1; + } + } paintCursor(tPtr); paintTextField(tPtr); } - if (move) { - XSetSelectionOwner(tPtr->view->screen->display, - XA_PRIMARY, tPtr->view->window, event->xmotion.time); - { - WMNotification *notif = WMCreateNotification("_lostOwnership", - NULL,tPtr); - WMPostNotification(notif); - WMReleaseNotification(notif); - } - } break; case ButtonPress: if (tPtr->flags.pointerGrabbed) { tPtr->flags.pointerGrabbed = 0; - XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr)->screen), CurrentTime); + XUngrabPointer(dpy, CurrentTime); + break; + } + + if (tPtr->flags.waitingSelection) { break; } @@ -1353,26 +1400,18 @@ handleTextFieldActionEvents(XEvent *event, void *data) textWidth = WMWidthOfString(tPtr->font, tPtr->text, tPtr->textLen); if (tPtr->flags.enabled && !tPtr->flags.focused) { WMSetFocusToWidget(tPtr); + } else if (tPtr->flags.focused) { tPtr->selection.position = tPtr->cursorPosition; tPtr->selection.count = 0; } - if(textWidth < tPtr->usableWidth){ + if(textWidth < tPtr->usableWidth) { tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xbutton.x - tPtr->usableWidth + textWidth); - } - else tPtr->cursorPosition = pointToCursorPosition(tPtr, + } else tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xbutton.x); - /* - tPtr->cursorPosition = pointToCursorPosition(tPtr, - event->xbutton.x); - tPtr->cursorPosition += tPtr->usableWidth - textWidth; - } - tPtr->cursorPosition = pointToCursorPosition(tPtr, - event->xbutton.x); - */ paintTextField(tPtr); break; @@ -1382,7 +1421,8 @@ handleTextFieldActionEvents(XEvent *event, void *data) tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xbutton.x); paintTextField(tPtr); - } else if (tPtr->flags.focused) { + } else if (tPtr->flags.focused + && event->xbutton.button == Button1) { tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xbutton.x); tPtr->selection.position = tPtr->cursorPosition; @@ -1391,51 +1431,71 @@ handleTextFieldActionEvents(XEvent *event, void *data) } if (event->xbutton.button == Button2 && tPtr->flags.enabled) { char *text; + int n; - text = W_GetTextSelection(tPtr->view->screen, XA_PRIMARY); - - if (!text) { - text = W_GetTextSelection(tPtr->view->screen, - tPtr->view->screen->clipboardAtom); - } - if (!text) { - text = W_GetTextSelection(tPtr->view->screen, - XA_CUT_BUFFER0); - } - if (text) { - WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition); - XFree(text); - NOTIFY(tPtr, didChange, WMTextDidChangeNotification, - (void*)WMInsertTextEvent); - } + if (!WMRequestSelection(tPtr->view, XA_PRIMARY, XA_STRING, + event->xbutton.time, + pasteText, NULL)) { + text = XFetchBuffer(tPtr->view->screen->display, &n, 0); + + if (text) { + text[n] = 0; + WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition); + XFree(text); + NOTIFY(tPtr, didChange, WMTextDidChangeNotification, + (void*)WMInsertTextEvent); + } + } else { + tPtr->flags.waitingSelection = 1; + } } break; + default: + break; } break; - case ButtonRelease: - if (tPtr->flags.pointerGrabbed) { - tPtr->flags.pointerGrabbed = 0; - XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr)->screen), CurrentTime); - } + case ButtonRelease: + if (tPtr->flags.pointerGrabbed) { + tPtr->flags.pointerGrabbed = 0; + XUngrabPointer(dpy, CurrentTime); + } + if (tPtr->flags.waitingSelection) { + break; + } + + if (tPtr->selection.count != 0) { + int start, count; + XRotateBuffers(dpy, 1); + + count = abs(tPtr->selection.count); + if (tPtr->selection.count < 0) + start = tPtr->selection.position - count; + else + start = tPtr->selection.position; + + XStoreBuffer(dpy, &tPtr->text[start], count, 0); + } - move = 0; + move = 0; - if (event->xbutton.time - lastButtonReleasedEvent - <= WINGsConfiguration.doubleClickDelay) { - tPtr->selection.position = 0; - tPtr->selection.count = tPtr->textLen; - paintTextField(tPtr); - XSetSelectionOwner(tPtr->view->screen->display, - XA_PRIMARY, tPtr->view->window, event->xbutton.time); - { - WMNotification *notif = WMCreateNotification("_lostOwnership", - NULL,tPtr); - WMPostNotification(notif); - WMReleaseNotification(notif); - } + if (event->xbutton.time - lastButtonReleasedEvent + <= WINGsConfiguration.doubleClickDelay) { + tPtr->selection.position = 0; + tPtr->selection.count = tPtr->textLen; + paintTextField(tPtr); + + if (!tPtr->flags.ownsSelection) { + WMCreateSelectionHandler(tPtr->view, + XA_PRIMARY, + event->xbutton.time, + &selectionHandler, NULL); + tPtr->flags.ownsSelection = 1; } - lastButtonReleasedEvent = event->xbutton.time; + + WMPostNotificationName("_lostOwnership", NULL, tPtr); + } + lastButtonReleasedEvent = event->xbutton.time; break; } @@ -1451,7 +1511,7 @@ destroyTextField(TextField *tPtr) #endif WMReleaseFont(tPtr->font); - WMDeleteSelectionHandler(tPtr, XA_PRIMARY); + WMDeleteSelectionHandler(tPtr->view, XA_PRIMARY, CurrentTime); WMRemoveNotificationObserver(tPtr); if (tPtr->text) diff --git a/WINGs/wview.c b/WINGs/wview.c index 0d7b5fcc..67c485fc 100644 --- a/WINGs/wview.c +++ b/WINGs/wview.c @@ -411,6 +411,10 @@ destroyView(W_View *view) if (view->dragDestinationProcs) wfree(view->dragDestinationProcs); + + if (scr->dragInfo.destView == view) { + scr->dragInfo.destView = NULL; + } #endif wfree(view); } -- 2.11.4.GIT