1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 12:28:22 +01:00

drag and drop!

selection code rewrite!
textfield with new selection code!
etc etc
This commit is contained in:
kojima
2000-04-03 03:10:20 +00:00
parent a5f7e65111
commit 60a247f271
12 changed files with 1184 additions and 888 deletions

View File

@@ -7,7 +7,7 @@
#include <WUtil.h>
#include <X11/Xlib.h>
#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);
/* ....................................................................... */

View File

@@ -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
@@ -105,9 +105,10 @@ struct W_DraggingInfo {
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 */
@@ -263,6 +265,12 @@ typedef struct W_Screen {
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);

View File

@@ -118,6 +118,10 @@ typedef struct W_Connection WMConnection;
typedef void WMFreeDataProc(void *data);
typedef struct {
int position;
int count;
@@ -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);

View File

@@ -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);
}
@@ -166,6 +202,13 @@ WMSetDataLength(WMData *aData, unsigned length) /*FOLD00*/
}
void
WMSetDataFormat(WMData *aData, unsigned format)
{
aData->format = format;
}
void
WMIncreaseDataLengthBy(WMData *aData, unsigned extraLength) /*FOLD00*/
{
@@ -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*/

View File

@@ -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;
}
}

View File

@@ -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;
}
}
/* 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 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)
{
}
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,8 +636,13 @@ 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 */
@@ -717,8 +725,9 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
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) {
@@ -838,6 +835,9 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
if (timer) {
WMDeleteTimerHandler(timer);
timer = NULL;
} else if (_XErrorOccured) {
/* got a timeout, send leave */
notifyDragLeave(scr, &dragInfo);
}
XUngrabPointer(dpy, CurrentTime);
@@ -859,22 +859,17 @@ 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,
@@ -900,6 +895,65 @@ 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,20 +988,86 @@ 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 */
@@ -982,29 +1102,6 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event)
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]) {
@@ -1013,71 +1110,138 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event)
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;
}
if (IS_DROPPABLE(view)) {
operation =
view->dragDestinationProcs->draggingUpdated(view,
&scr->dragInfo);
}
if (operation == 0) {
sendClientMessage(scr->display, scr->dragInfo.sourceWindow,
scr->xdndStatusAtom,
scr->dragInfo.destinationWindow,
0, 0, 0, None);
} else {
Atom action;
switch (operation) {
default:
action = 0;
break;
}
sendClientMessage(scr->display, scr->dragInfo.sourceWindow,
scr->xdndStatusAtom,
scr->dragInfo.destinationWindow,
1, 0, 0, action);
}
newView = findViewInToplevel(scr->display,
scr->dragInfo.destinationWindow,
x, y);
} else if (event->message_type == scr->xdndLeaveAtom
&& scr->dragInfo.sourceWindow == event->data.l[0]) {
void (*draggingExited)(WMView *self, WMDraggingInfo *info);
memset(&scr->dragInfo, 0, sizeof(WMDraggingInfo));
puts("leave");
} else if (event->message_type == scr->xdndDropAtom
&& scr->dragInfo.sourceWindow == event->data.l[0]) {
/* drop */
what = WDrop;
puts("drop");
} 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 {
if (oldView != NULL) {
what = WLeave;
} else {
/* just send rejection msg */
sendStatus = True;
}
}
}
switch (what) {
case WEnter:
scr->dragInfo.destView = newView;
operation = DISPATCH(newView, draggingEntered, &scr->dragInfo);
sendStatus = True;
break;
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;
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
}

View File

@@ -10,62 +10,63 @@
typedef struct SelectionHandler {
WMWidget *widget;
WMView *view;
Atom selection;
Time timestamp;
WMConvertSelectionProc *convProc;
WMLoseSelectionProc *loseProc;
WMSelectionDoneProc *doneProc;
WMSelectionProcs procs;
void *data;
struct {
unsigned delete_pending:1;
unsigned done_pending:1;
} flags;
struct SelectionHandler *next;
} SelectionHandler;
static SelectionHandler *selHandlers = NULL;
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(WMWidget *widget, Atom selection)
WMDeleteSelectionHandler(WMView *view, Atom selection, Time timestamp)
{
SelectionHandler *handler, *tmp;
Display *dpy = WMWidgetScreen(widget)->display;
Window win = WMWidgetXID(widget);
Time timestamp;
SelectionHandler *handler;
Display *dpy = W_VIEW_SCREEN(view)->display;
Window win = W_VIEW_DRAWABLE(view);
WMBagIterator iter;
if (!selHandlers)
return;
tmp = selHandlers;
if (tmp->widget == widget) {
WM_ITERATE_BAG(selHandlers, handler, iter) {
if (handler->view == view
&& (handler->selection == selection || selection == None)
&& (handler->timestamp == timestamp || timestamp == CurrentTime)) {
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;
if (handler->flags.done_pending) {
handler->flags.delete_pending = 1;
return;
}
WMRemoveFromBag(selHandlers, handler);
wfree(handler);
break;
}
}
@@ -77,6 +78,34 @@ WMDeleteSelectionHandler(WMWidget *widget, Atom selection)
}
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
@@ -88,8 +117,14 @@ errorHandler(XErrorEvent *error)
static Bool
writeSelection(Display *dpy, Window requestor, Atom property, Atom type,
void *value, long length, int format)
WMData *data)
{
int format;
format = WMGetDataFormat(data);
if (format == 0)
format = 8;
/*
printf("write to %x: %s\n", requestor, XGetAtomName(dpy, property));
*/
@@ -97,12 +132,13 @@ writeSelection(Display *dpy, Window requestor, Atom property, Atom type,
#ifndef __sgi
if (!XChangeProperty(dpy, requestor, property, type, format,
PropModeReplace, value, length))
PropModeReplace, WMDataBytes(data),
WMGetDataLength(data)))
return False;
#else
/* in sgi seems this seems to return void */
XChangeProperty(dpy, requestor, property, type, format,
PropModeReplace, value, length);
PropModeReplace, WMDataBytes(data), WMGetDataLength(data));
#endif
XFlush(dpy);
@@ -134,92 +170,222 @@ notifySelection(XEvent *event, Atom prop)
}
void
W_HandleSelectionEvent(XEvent *event)
static void
deleteHandlers(WMBagIterator iter)
{
SelectionHandler *handler;
handler = selHandlers;
if (iter == NULL)
handler = WMBagFirst(selHandlers, &iter);
else
handler = WMBagNext(selHandlers, &iter);
while (handler) {
if (WMWidgetXID(handler->widget)==event->xany.window
/* && handler->selection == event->selection*/) {
if (handler == NULL)
return;
switch (event->type) {
case SelectionClear:
if (handler->loseProc)
(*handler->loseProc)(handler->widget, handler->selection);
break;
deleteHandlers(iter);
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;
}
if (handler->flags.delete_pending) {
WMDeleteSelectionHandler(handler->view, handler->selection,
handler->timestamp);
}
}
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)) {
static void
handleRequestEvent(XEvent *event)
{
SelectionHandler *handler;
WMBagIterator iter;
Bool handledRequest = False;
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:
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 = handler->next;
(*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);
}
}
@@ -227,196 +393,69 @@ W_HandleSelectionEvent(XEvent *event)
Bool
WMCreateSelectionHandler(WMWidget *w, Atom selection, Time timestamp,
WMConvertSelectionProc *convProc,
WMLoseSelectionProc *loseProc,
WMSelectionDoneProc *doneProc)
WMCreateSelectionHandler(WMView *view, Atom selection, Time timestamp,
WMSelectionProcs *procs, void *cdata)
{
SelectionHandler *handler, *tmp;
Display *dpy = WMWidgetScreen(w)->display;
SelectionHandler *handler;
Display *dpy = W_VIEW_SCREEN(view)->display;
XSetSelectionOwner(dpy, selection, WMWidgetXID(w), timestamp);
if (XGetSelectionOwner(dpy, selection) != WMWidgetXID(w))
XSetSelectionOwner(dpy, selection, W_VIEW_DRAWABLE(view), timestamp);
if (XGetSelectionOwner(dpy, selection) != W_VIEW_DRAWABLE(view))
return False;
handler = malloc(sizeof(SelectionHandler));
if (!handler)
if (handler == NULL)
return False;
handler->widget = w;
handler->view = view;
handler->selection = selection;
handler->timestamp = timestamp;
handler->convProc = convProc;
handler->loseProc = loseProc;
handler->doneProc = doneProc;
handler->procs = *procs;
handler->data = cdata;
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;
if (selHandlers == NULL) {
selHandlers = WMCreateTreeBag();
}
WMPutInBag(selHandlers, handler);
return True;
}
static void
timeoutHandler(void *data)
Bool
WMRequestSelection(WMView *view, Atom selection, Atom target, Time timestamp,
WMSelectionCallback *callback, void *cdata)
{
*(int*)data = 1;
}
SelectionCallback *handler;
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)
if (XGetSelectionOwner(W_VIEW_SCREEN(view)->display, selection) == None)
return False;
handler = selHandlers;
handler = wmalloc(sizeof(SelectionCallback));
while (handler) {
if (WMWidgetXID(handler->widget) == owner
/* && handler->selection == event->selection*/) {
break;
}
handler = handler->next;
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();
}
if (!handler)
WMPutInBag(selCallbacks, handler);
if (!XConvertSelection(W_VIEW_SCREEN(view)->display, selection, target,
W_VIEW_SCREEN(view)->clipboardAtom,
W_VIEW_DRAWABLE(view), timestamp)) {
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;
}
}

View File

@@ -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
@@ -169,6 +193,15 @@ 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,6 +309,27 @@ handleEvents(XEvent *event, void *data)
}
static unsigned
draggingSourceOperation(WMView *self, Bool local)
{
return WDOperationCopy;
}
static WMData*
fetchDragData(WMView *self, char *type)
{
char *color = WMGetColorRGBDescription(((WMColorWell*)self->self)->color);
WMData *data;
data = WMCreateDataWithBytes(color, strlen(color)+1);
free(color);
return data;
}
static WMPixmap*
makeDragPixmap(WMColorWell *cPtr)
{
@@ -292,221 +346,6 @@ makeDragPixmap(WMColorWell *cPtr)
}
static void
slideView(WMView *view, int srcX, int srcY, int dstX, int dstY)
{
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;
}
}
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 Window
findWindowUnderDragPointer(WMScreen *scr, int x, int y, Window iconWindow)
{
Window foo, bar;
Window *children;
unsigned nchildren;
int i;
if (!XQueryTree(scr->display, scr->rootWin, &foo, &bar,
&children, &nchildren) || children == NULL) {
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;
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);
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);
}
static void
handleDragEvents(XEvent *event, void *data)
{
@@ -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);
* */
WMDragImageFromView(cPtr->view, pixmap, types,
wmkpoint(event->xmotion.x_root,
event->xmotion.y_root),
offs, event, True);
dragColor(cPtr, event, pixmap);
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)
{
}

View File

@@ -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) {
@@ -767,25 +773,32 @@ WMCreateScreenWithRContext(Display *display, int screen, RContext *context)
}
#endif
scrPtr->attribsAtom = atoms[0];
i = 0;
scrPtr->attribsAtom = atoms[i++];
scrPtr->deleteWindowAtom = atoms[1];
scrPtr->deleteWindowAtom = atoms[i++];
scrPtr->protocolsAtom = atoms[2];
scrPtr->protocolsAtom = atoms[i++];
scrPtr->clipboardAtom = atoms[3];
scrPtr->clipboardAtom = atoms[i++];
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->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->wmStateAtom = atoms[13];
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);

View File

@@ -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;

View File

@@ -65,6 +65,11 @@ typedef struct W_TextField {
unsigned int pointerGrabbed:1;
unsigned int ownsSelection:1;
unsigned int waitingSelection:1; /* requested selection, but
* didnt get yet */
/**/
unsigned int notIllegalMovement:1;
} flags;
@@ -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);
Atom TEXT = XInternAtom(dpy, "TEXT", False);
Atom COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", False);
WMData *data;
*format = 32;
*length = 0;
*value = NULL;
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 (!WMRequestSelection(tPtr->view, XA_PRIMARY, XA_STRING,
event->xbutton.time,
pasteText, NULL)) {
text = XFetchBuffer(tPtr->view->screen->display, &n, 0);
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 (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;
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;
}
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);
}
}
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)

View File

@@ -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);
}