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 <WUtil.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#define WINGS_H_VERSION 991003 #define WINGS_H_VERSION 20000402
#ifdef __cplusplus #ifdef __cplusplus
@@ -170,7 +170,7 @@ typedef enum {
WTNoTabsBevelBorder, WTNoTabsBevelBorder,
WTNoTabsLineBorder, WTNoTabsLineBorder,
WTNoTabsNoBorder WTNoTabsNoBorder
} WMTabViewTypes; } WMTabViewType;
/* text movement types */ /* text movement types */
@@ -192,6 +192,18 @@ enum {
WMDeleteTextEvent WMDeleteTextEvent
}; };
/* drag operations */
typedef enum {
WDOperationNone,
WDOperationCopy,
WDOperationMove,
WDOperationLink,
WDOperationAsk,
WDOperationPrivate
} WMDragOperationType;
typedef enum { typedef enum {
WMGrayModeColorPanel = 1, WMGrayModeColorPanel = 1,
WMRGBModeColorPanel = 2, WMRGBModeColorPanel = 2,
@@ -392,8 +404,6 @@ typedef void WMCallback(void *data);
/* delegate method like stuff */ /* delegate method like stuff */
typedef void WMFreeDataProc(void *data);
typedef void WMListDrawProc(WMList *lPtr, int index, Drawable d, char *text, typedef void WMListDrawProc(WMList *lPtr, int index, Drawable d, char *text,
int state, WMRect *rect); int state, WMRect *rect);
@@ -409,15 +419,6 @@ typedef void WMSplitViewConstrainProc(WMSplitView *sPtr, int dividerIndex,
typedef WMWidget *WMMatrixCreateCellProc(WMMatrix *mPtr); 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 { 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; typedef struct W_DraggingInfo WMDraggingInfo;
@@ -482,7 +499,7 @@ typedef struct W_DragSourceProcs {
void (*beganDragImage)(WMView *self, WMPixmap *image, WMPoint point); void (*beganDragImage)(WMView *self, WMPixmap *image, WMPoint point);
void (*endedDragImage)(WMView *self, WMPixmap *image, WMPoint point, void (*endedDragImage)(WMView *self, WMPixmap *image, WMPoint point,
Bool deposited); Bool deposited);
WMData* (*fetchDragData)(WMView *self, char *type, Bool local); WMData* (*fetchDragData)(WMView *self, char *type);
/* Bool (*ignoreModifierKeysWhileDragging)(WMView *view);*/ /* Bool (*ignoreModifierKeysWhileDragging)(WMView *view);*/
} WMDragSourceProcs; } WMDragSourceProcs;
@@ -492,8 +509,9 @@ typedef struct W_DragDestinationProcs {
unsigned (*draggingEntered)(WMView *self, WMDraggingInfo *info); unsigned (*draggingEntered)(WMView *self, WMDraggingInfo *info);
unsigned (*draggingUpdated)(WMView *self, WMDraggingInfo *info); unsigned (*draggingUpdated)(WMView *self, WMDraggingInfo *info);
void (*draggingExited)(WMView *self, WMDraggingInfo *info); void (*draggingExited)(WMView *self, WMDraggingInfo *info);
Bool (*prepareForDragOperation)(WMView *self, WMDraggingInfo *info); char *(*prepareForDragOperation)(WMView *self, WMDraggingInfo *info);
Bool (*performDragOperation)(WMView *self, WMDraggingInfo *info); Bool (*performDragOperation)(WMView *self, WMDraggingInfo *info,
WMData *data);
void (*concludeDragOperation)(WMView *self, WMDraggingInfo *info); void (*concludeDragOperation)(WMView *self, WMDraggingInfo *info);
} WMDragDestinationProcs; } WMDragDestinationProcs;
@@ -581,12 +599,16 @@ WMHandlerID WMAddInputHandler(int fd, int condition, WMInputProc *proc,
void WMDeleteInputHandler(WMHandlerID handlerID); 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" #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. #error There_is_an_old_WINGs.h_file_somewhere_in_your_system._Please_remove_it.
#endif #endif
@@ -104,10 +104,11 @@ struct W_DraggingInfo {
Time timestamp; Time timestamp;
int protocolVersion; int protocolVersion;
/* should be treated as internal data */
WMView *sourceView;
WMView *destView; 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; Pixmap stipple;
struct W_View *dragSourceView;
struct W_DraggingInfo dragInfo; struct W_DraggingInfo dragInfo;
/* colors */ /* colors */
@@ -262,7 +264,13 @@ typedef struct W_Screen {
Atom xdndFinishedAtom; Atom xdndFinishedAtom;
Atom xdndTypeListAtom; Atom xdndTypeListAtom;
Atom xdndStatusAtom; Atom xdndStatusAtom;
Atom xdndActionCopy;
Atom xdndActionMove;
Atom xdndActionLink;
Atom xdndActionAsk;
Atom xdndActionPrivate;
Atom wmStateAtom; /* WM_STATE */ Atom wmStateAtom; /* WM_STATE */
/* stuff for detecting double-clicks */ /* stuff for detecting double-clicks */
@@ -485,8 +493,6 @@ void W_RedisplayView(WMView *view);
Bool W_ApplicationInitialized(void); Bool W_ApplicationInitialized(void);
char *W_GetTextSelection(WMScreen *scr, Atom selection);
void W_HandleSelectionEvent(XEvent *event); void W_HandleSelectionEvent(XEvent *event);
void W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event); void W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event);

View File

@@ -117,6 +117,10 @@ typedef struct W_Host WMHost;
typedef struct W_Connection WMConnection; typedef struct W_Connection WMConnection;
typedef void WMFreeDataProc(void *data);
typedef struct { typedef struct {
int position; int position;
@@ -438,6 +442,10 @@ WMData* WMCreateDataWithBytes(void *bytes, unsigned length);
WMData* WMCreateDataWithBytesNoCopy(void *bytes, unsigned length); WMData* WMCreateDataWithBytesNoCopy(void *bytes, unsigned length);
WMData* WMCreateDataWithBytesAndDestructor(void *bytes, unsigned length,
WMFreeDataProc *destructor);
WMData* WMCreateDataWithData(WMData *aData); WMData* WMCreateDataWithData(WMData *aData);
WMData* WMRetainData(WMData *aData); WMData* WMRetainData(WMData *aData);
@@ -470,8 +478,6 @@ Bool WMIsDataEqualToData(WMData *aData, WMData *anotherData);
unsigned WMGetDataLength(WMData *aData); unsigned WMGetDataLength(WMData *aData);
unsigned WMGetDataHash(WMData *aData);
/* Adding data */ /* Adding data */
void WMAppendDataBytes(WMData *aData, void *bytes, unsigned length); void WMAppendDataBytes(WMData *aData, void *bytes, unsigned length);

View File

@@ -30,6 +30,8 @@ typedef struct W_Data {
unsigned growth; /* How much to grow */ unsigned growth; /* How much to grow */
void *bytes; /* Actual data */ void *bytes; /* Actual data */
unsigned retainCount; unsigned retainCount;
WMFreeDataProc *destructor;
int format; /* 0, 8, 16 or 32 */
unsigned freeData:1; /* whether the data should be released */ unsigned freeData:1; /* whether the data should be released */
} W_Data; } W_Data;
@@ -54,6 +56,8 @@ WMCreateDataWithCapacity(unsigned capacity) /*FOLD00*/
aData->length = 0; aData->length = 0;
aData->retainCount = 1; aData->retainCount = 1;
aData->freeData = 1; aData->freeData = 1;
aData->format = 0;
aData->destructor = NULL;
return aData; return aData;
} }
@@ -99,6 +103,28 @@ WMCreateDataWithBytesNoCopy(void *bytes, unsigned length) /*FOLD00*/
aData->bytes = bytes; aData->bytes = bytes;
aData->retainCount = 1; aData->retainCount = 1;
aData->freeData = 0; 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; return aData;
} }
@@ -107,10 +133,16 @@ WMCreateDataWithBytesNoCopy(void *bytes, unsigned length) /*FOLD00*/
WMData* WMData*
WMCreateDataWithData(WMData *aData) /*FOLD00*/ WMCreateDataWithData(WMData *aData) /*FOLD00*/
{ {
if (aData->length > 0) WMData *newData;
return WMCreateDataWithBytes(aData->bytes, aData->length); if (aData->length > 0) {
else newData = WMCreateDataWithBytes(aData->bytes, aData->length);
return WMCreateDataWithCapacity(0); } else {
newData = WMCreateDataWithCapacity(0);
}
newData->destructor = aData->destructor;
newData->format = aData->format;
return newData;
} }
@@ -128,8 +160,12 @@ WMReleaseData(WMData *aData) /*FOLD00*/
aData->retainCount--; aData->retainCount--;
if (aData->retainCount > 0) if (aData->retainCount > 0)
return; return;
if (aData->bytes && aData->freeData) if (aData->bytes && aData->freeData) {
wfree(aData->bytes); if (aData->destructor != NULL)
aData->destructor(aData->bytes);
else
wfree(aData->bytes);
}
wfree(aData); wfree(aData);
} }
@@ -158,7 +194,7 @@ WMSetDataLength(WMData *aData, unsigned length) /*FOLD00*/
WMSetDataCapacity(aData, length); WMSetDataCapacity(aData, length);
} }
if (length > 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); 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 void
WMIncreaseDataLengthBy(WMData *aData, unsigned extraLength) /*FOLD00*/ WMIncreaseDataLengthBy(WMData *aData, unsigned extraLength) /*FOLD00*/
{ {
@@ -191,6 +234,13 @@ WMGetDataBytes(WMData *aData, void *buffer) /*FOLD00*/
} }
unsigned
WMGetDataFormat(WMData *aData)
{
return aData->format;
}
void void
WMGetDataBytesWithLength(WMData *aData, void *buffer, unsigned length) /*FOLD00*/ WMGetDataBytesWithLength(WMData *aData, void *buffer, unsigned length) /*FOLD00*/
{ {
@@ -217,13 +267,18 @@ WMData*
WMGetSubdataWithRange(WMData *aData, WMRange aRange) /*FOLD00*/ WMGetSubdataWithRange(WMData *aData, WMRange aRange) /*FOLD00*/
{ {
void *buffer; void *buffer;
WMData *newData;
/* return an empty subdata instead if aRange.count is 0 ? */ /* return an empty subdata instead if aRange.count is 0 ? */
wassertrv(aRange.count > 0, NULL); wassertrv(aRange.count > 0, NULL);
buffer = wmalloc(aRange.count); buffer = wmalloc(aRange.count);
WMGetDataBytesWithRange(aData, buffer, aRange); 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 */ /* Adding data */
void void
WMAppendDataBytes(WMData *aData, void *bytes, unsigned length) /*FOLD00*/ 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 void
WMRegisterViewForDraggedTypes(WMView *view, char *acceptedTypes[]) 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 void
WMSetViewDragDestinationProcs(WMView *view, WMDragDestinationProcs *procs) WMSetViewDragDestinationProcs(WMView *view, WMDragDestinationProcs *procs)
{ {
@@ -110,6 +134,27 @@ WMSetViewDragDestinationProcs(WMView *view, WMDragDestinationProcs *procs)
*view->dragDestinationProcs = *procs; *view->dragDestinationProcs = *procs;
/*XXX fill in non-implemented stuffs */ /*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 && \ #define IS_DROPPABLE(view) (view!=NULL && view->droppableTypes!=NULL && \
view->dragDestinationProcs!=NULL) view->dragDestinationProcs!=NULL)
static Atom operationToAction(WMScreen *scr, WMDragOperationType operation);
static WMDragOperationType actionToOperation(WMScreen *scr, Atom action);
static Bool _XErrorOccured = False; static Bool _XErrorOccured = False;
@@ -317,13 +320,7 @@ sendClientMessage(Display *dpy, Window win, Atom message,
static unsigned static unsigned
notifyPosition(WMScreen *scr, WMDraggingInfo *info) notifyPosition(WMScreen *scr, WMDraggingInfo *info)
{ {
unsigned operation; Atom action = operationToAction(scr, info->sourceOperation);
switch (info->sourceOperation) {
default:
operation = None;
break;
}
sendClientMessage(scr->display, info->destinationWindow, sendClientMessage(scr->display, info->destinationWindow,
scr->xdndPositionAtom, scr->xdndPositionAtom,
@@ -331,7 +328,7 @@ notifyPosition(WMScreen *scr, WMDraggingInfo *info)
0, /* reserved */ 0, /* reserved */
info->location.x<<16|info->location.y, info->location.x<<16|info->location.y,
info->timestamp, info->timestamp,
operation/* operation */); action/* operation */);
return 0; return 0;
} }
@@ -418,34 +415,6 @@ updateDraggingInfo(WMScreen *scr, WMDraggingInfo *info,
info->location.y, info->location.y,
iconWindow); iconWindow);
info->destinationWindow = toplevel; 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; 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 static void
timeoutCallback(void *data) timeoutCallback(void *data)
{ {
wwarning("drag & drop timed out while waiting for response from 0x%x\n", wwarning("drag & drop timed out while waiting for response from 0x%x\n",
(unsigned)data); (unsigned)data);
_XErrorOccured = 1; _XErrorOccured = 2;
} }
/* /*
@@ -594,9 +584,15 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
WMDraggingInfo dragInfo; WMDraggingInfo dragInfo;
WMDraggingInfo oldDragInfo; WMDraggingInfo oldDragInfo;
WMHandlerID timer = NULL; WMHandlerID timer = NULL;
WMData *draggedData = NULL; static WMSelectionProcs handler = {
convertSelection,
selectionLost,
selectionDone
};
wassertr(scr->dragSourceView == NULL);
wassertr(view->dragSourceProcs != NULL); wassertr(view->dragSourceProcs != NULL);
@@ -614,9 +610,13 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
/* init dragging info */ /* init dragging info */
scr->dragSourceView = view;
memset(&dragInfo, 0, sizeof(WMDraggingInfo)); memset(&dragInfo, 0, sizeof(WMDraggingInfo));
memset(&oldDragInfo, 0, sizeof(WMDraggingInfo)); memset(&oldDragInfo, 0, sizeof(WMDraggingInfo));
dragInfo.image = image; dragInfo.image = image;
dragInfo.sourceView = view;
dragInfo.sourceWindow = W_VIEW_DRAWABLE(W_TopLevelOfView(view)); dragInfo.sourceWindow = W_VIEW_DRAWABLE(W_TopLevelOfView(view));
dragInfo.destinationWindow = dragInfo.sourceWindow; dragInfo.destinationWindow = dragInfo.sourceWindow;
@@ -636,9 +636,14 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
_XErrorOccured = False; _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) { if (view->dragSourceProcs->beganDragImage != NULL) {
view->dragSourceProcs->beganDragImage(view, image, atLocation); view->dragSourceProcs->beganDragImage(view, image, atLocation);
} }
@@ -665,9 +670,8 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
XMoveWindow(dpy, icon, dragInfo.imageLocation.x, XMoveWindow(dpy, icon, dragInfo.imageLocation.x,
dragInfo.imageLocation.y); dragInfo.imageLocation.y);
if (state != 2) { processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);
processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);
}
protectBlock(False); protectBlock(False);
/* XXXif entered a different destination, check the operation */ /* XXXif entered a different destination, check the operation */
@@ -675,6 +679,7 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
switch (state) { switch (state) {
case 1: case 1:
if (oldDragInfo.destinationWindow != None if (oldDragInfo.destinationWindow != None
&& oldDragInfo.destinationWindow != scr->rootWin
&& (dragInfo.destinationWindow == None && (dragInfo.destinationWindow == None
|| dragInfo.destinationWindow == scr->rootWin)) { || dragInfo.destinationWindow == scr->rootWin)) {
/* left the droppable window */ /* left the droppable window */
@@ -684,7 +689,9 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
break; break;
case 2: case 2:
if (dragInfo.destinationWindow != None) { if (dragInfo.destinationWindow != None
&& dragInfo.destinationWindow != scr->rootWin) {
state = 1; state = 1;
action = -1; action = -1;
} }
@@ -693,6 +700,7 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
case 3: case 3:
case 4: case 4:
if (oldDragInfo.destinationWindow != None if (oldDragInfo.destinationWindow != None
&& oldDragInfo.destinationWindow != scr->rootWin
&& (dragInfo.destinationWindow == None && (dragInfo.destinationWindow == None
|| dragInfo.destinationWindow == scr->rootWin)) { || dragInfo.destinationWindow == scr->rootWin)) {
/* left the droppable window */ /* left the droppable window */
@@ -713,12 +721,13 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
oldDragInfo = dragInfo; oldDragInfo = dragInfo;
updateDraggingInfo(scr, &dragInfo, &ev, icon); updateDraggingInfo(scr, &dragInfo, &ev, icon);
XMoveWindow(dpy, icon, dragInfo.imageLocation.x, XMoveWindow(dpy, icon, dragInfo.imageLocation.x,
dragInfo.imageLocation.y); dragInfo.imageLocation.y);
processMotion(scr, &dragInfo, &oldDragInfo, &rect, processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);
action);
dragInfo.timestamp = ev.xbutton.time;
protectBlock(False); protectBlock(False);
@@ -741,20 +750,13 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
} }
break; break;
case SelectionRequest:
draggedData = NULL;
break;
case ClientMessage: case ClientMessage:
if ((state == 1 || state == 3 || state == 4 || state == 5) if ((state == 1 || state == 3 || state == 4 || state == 5)
&& ev.xclient.message_type == scr->xdndStatusAtom && 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) { if (ev.xclient.data.l[1] & 1) {
puts("got accept msg"); SPIT("got accept msg");
/* will accept drop */ /* will accept drop */
switch (state) { switch (state) {
case 1: case 1:
@@ -770,13 +772,9 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
state = 6; state = 6;
break; break;
} }
if (ev.xclient.data.l[4] == None) { action = actionToOperation(scr, ev.xclient.data.l[4]);
action = 0;
} else {
action = ev.xclient.data.l[4];/*XXX*/
}
} else { } else {
puts("got reject msg"); SPIT("got reject msg");
switch (state) { switch (state) {
case 1: case 1:
case 3: case 3:
@@ -825,7 +823,6 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
} }
if (ostate != state) { if (ostate != state) {
printf("state changed to %i\n", state);
if (state == 3) { if (state == 3) {
XRecolorCursor(dpy, scr->defaultCursor, &green, &back); XRecolorCursor(dpy, scr->defaultCursor, &green, &back);
} else if (ostate == 3) { } else if (ostate == 3) {
@@ -834,10 +831,13 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
ostate = state; ostate = state;
} }
} }
if (timer) { if (timer) {
WMDeleteTimerHandler(timer); WMDeleteTimerHandler(timer);
timer = NULL; timer = NULL;
} else if (_XErrorOccured) {
/* got a timeout, send leave */
notifyDragLeave(scr, &dragInfo);
} }
XUngrabPointer(dpy, CurrentTime); XUngrabPointer(dpy, CurrentTime);
@@ -859,23 +859,18 @@ WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
SPIT("dropped"); SPIT("dropped");
/* wait for Finished message and SelectionRequest if not a local drop */
XDestroyWindow(dpy, icon); XDestroyWindow(dpy, icon);
if (view->dragSourceProcs->endedDragImage != NULL) {
view->dragSourceProcs->endedDragImage(view, image,
dragInfo.imageLocation,
True);
}
return; return;
cancelled: cancelled:
if (draggedData) { scr->dragSourceView = NULL;
WMReleaseData(draggedData);
}
WMDeleteSelectionHandler(view, scr->xdndSelectionAtom,
event->xmotion.time);
if (slideBack) { if (slideBack) {
slideWindow(dpy, icon, slideWindow(dpy, icon,
dragInfo.imageLocation.x, dragInfo.imageLocation.y, dragInfo.imageLocation.x, dragInfo.imageLocation.y,
@@ -900,8 +895,67 @@ 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 void
W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event)
{ {
#if 0
WMScreen *scr = W_VIEW_SCREEN(toplevel); WMScreen *scr = W_VIEW_SCREEN(toplevel);
WMView *oldView = NULL, *newView = NULL; WMView *oldView = NULL;
WMView *newView = NULL;
unsigned operation = 0; unsigned operation = 0;
int x, y; 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) { if (event->message_type == scr->xdndEnterAtom) {
Window foo, bar; Window foo, bar;
int bla; int bla;
unsigned ble; unsigned ble;
puts("entered");
if (scr->dragInfo.sourceWindow != None) { if (scr->dragInfo.sourceWindow != None) {
puts("received Enter event in bad order"); puts("received Enter event in bad order");
} }
@@ -956,14 +1076,14 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event)
memset(&scr->dragInfo, 0, sizeof(WMDraggingInfo)); 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", wwarning("received drag & drop request with unsupported version %i",
(event->data.l[0] >> 24)); (event->data.l[1] >> 24));
return; return;
} }
scr->dragInfo.protocolVersion = event->data.l[1] >> 24; 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; scr->dragInfo.destinationWindow = event->window;
/* XXX */ /* XXX */
@@ -981,103 +1101,147 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event)
newView = findViewInToplevel(scr->display, newView = findViewInToplevel(scr->display,
scr->dragInfo.destinationWindow, scr->dragInfo.destinationWindow,
x, y); 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 } else if (event->message_type == scr->xdndPositionAtom
&& scr->dragInfo.sourceWindow == event->data.l[0]) { && scr->dragInfo.sourceWindow == event->data.l[0]) {
scr->dragInfo.location.x = event->data.l[2] >> 16; scr->dragInfo.location.x = event->data.l[2] >> 16;
scr->dragInfo.location.y = event->data.l[2] & 0xffff; scr->dragInfo.location.y = event->data.l[2] & 0xffff;
if (scr->dragInfo.protocolVersion >= 1) { if (scr->dragInfo.protocolVersion >= 1) {
scr->dragInfo.timestamp = event->data.l[3]; scr->dragInfo.timestamp = event->data.l[3];
scr->dragInfo.sourceOperation = event->data.l[4]; scr->dragInfo.sourceOperation = actionToOperation(scr,
event->data.l[4]);
} else { } else {
scr->dragInfo.timestamp = CurrentTime; scr->dragInfo.timestamp = CurrentTime;
scr->dragInfo.sourceOperation = 0; /*XXX*/ scr->dragInfo.sourceOperation = WDOperationCopy;
} }
translateCoordinates(scr, scr->dragInfo.destinationWindow, translateCoordinates(scr, scr->dragInfo.destinationWindow,
scr->dragInfo.location.x, scr->dragInfo.location.x,
scr->dragInfo.location.y, &x, &y); scr->dragInfo.location.y, &x, &y);
view = findViewInToplevel(scr->display, newView = findViewInToplevel(scr->display,
scr->dragInfo.destinationWindow, scr->dragInfo.destinationWindow,
x, y); 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);
}
} else if (event->message_type == scr->xdndLeaveAtom } else if (event->message_type == scr->xdndLeaveAtom
&& scr->dragInfo.sourceWindow == event->data.l[0]) { && 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 } else if (event->message_type == scr->xdndDropAtom
&& scr->dragInfo.sourceWindow == event->data.l[0]) { && scr->dragInfo.sourceWindow == event->data.l[0]) {
/* drop */
what = WDrop;
} else {
return;
puts("drop"); }
/*
* 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 { typedef struct SelectionHandler {
WMWidget *widget; WMView *view;
Atom selection; Atom selection;
Time timestamp; Time timestamp;
WMConvertSelectionProc *convProc; WMSelectionProcs procs;
WMLoseSelectionProc *loseProc; void *data;
WMSelectionDoneProc *doneProc;
struct { struct {
unsigned delete_pending:1; unsigned delete_pending:1;
unsigned done_pending:1; unsigned done_pending:1;
} flags; } flags;
struct SelectionHandler *next;
} SelectionHandler; } 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 void
WMDeleteSelectionHandler(WMWidget *widget, Atom selection) WMDeleteSelectionHandler(WMView *view, Atom selection, Time timestamp)
{ {
SelectionHandler *handler, *tmp; SelectionHandler *handler;
Display *dpy = WMWidgetScreen(widget)->display; Display *dpy = W_VIEW_SCREEN(view)->display;
Window win = WMWidgetXID(widget); Window win = W_VIEW_DRAWABLE(view);
Time timestamp; WMBagIterator iter;
if (!selHandlers) if (!selHandlers)
return; return;
WM_ITERATE_BAG(selHandlers, handler, iter) {
if (handler->view == view
&& (handler->selection == selection || selection == None)
&& (handler->timestamp == timestamp || timestamp == CurrentTime)) {
tmp = selHandlers; if (handler->flags.done_pending) {
handler->flags.delete_pending = 1;
if (tmp->widget == widget) { return;
}
if (tmp->flags.done_pending) { WMRemoveFromBag(selHandlers, handler);
tmp->flags.delete_pending = 1; wfree(handler);
return; break;
}
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;
} }
} }
@@ -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 Bool gotError = 0;
/* /*
static int static int
@@ -88,8 +117,14 @@ errorHandler(XErrorEvent *error)
static Bool static Bool
writeSelection(Display *dpy, Window requestor, Atom property, Atom type, 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)); 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 #ifndef __sgi
if (!XChangeProperty(dpy, requestor, property, type, format, if (!XChangeProperty(dpy, requestor, property, type, format,
PropModeReplace, value, length)) PropModeReplace, WMDataBytes(data),
WMGetDataLength(data)))
return False; return False;
#else #else
/* in sgi seems this seems to return void */ /* in sgi seems this seems to return void */
XChangeProperty(dpy, requestor, property, type, format, XChangeProperty(dpy, requestor, property, type, format,
PropModeReplace, value, length); PropModeReplace, WMDataBytes(data), WMGetDataLength(data));
#endif #endif
XFlush(dpy); XFlush(dpy);
@@ -134,92 +170,222 @@ notifySelection(XEvent *event, Atom prop)
} }
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 void
W_HandleSelectionEvent(XEvent *event) W_HandleSelectionEvent(XEvent *event)
{ {
SelectionHandler *handler; if (event->type == SelectionNotify) {
handleNotifyEvent(event);
handler = selHandlers; } else {
handleRequestEvent(event);
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;
} }
} }
@@ -227,196 +393,69 @@ W_HandleSelectionEvent(XEvent *event)
Bool Bool
WMCreateSelectionHandler(WMWidget *w, Atom selection, Time timestamp, WMCreateSelectionHandler(WMView *view, Atom selection, Time timestamp,
WMConvertSelectionProc *convProc, WMSelectionProcs *procs, void *cdata)
WMLoseSelectionProc *loseProc,
WMSelectionDoneProc *doneProc)
{ {
SelectionHandler *handler, *tmp; SelectionHandler *handler;
Display *dpy = WMWidgetScreen(w)->display; Display *dpy = W_VIEW_SCREEN(view)->display;
XSetSelectionOwner(dpy, selection, WMWidgetXID(w), timestamp); XSetSelectionOwner(dpy, selection, W_VIEW_DRAWABLE(view), timestamp);
if (XGetSelectionOwner(dpy, selection) != WMWidgetXID(w)) if (XGetSelectionOwner(dpy, selection) != W_VIEW_DRAWABLE(view))
return False; return False;
handler = malloc(sizeof(SelectionHandler)); handler = malloc(sizeof(SelectionHandler));
if (!handler) if (handler == NULL)
return False; return False;
handler->widget = w; handler->view = view;
handler->selection = selection; handler->selection = selection;
handler->timestamp = timestamp; handler->timestamp = timestamp;
handler->convProc = convProc; handler->procs = *procs;
handler->loseProc = loseProc; handler->data = cdata;
handler->doneProc = doneProc;
memset(&handler->flags, 0, sizeof(handler->flags)); memset(&handler->flags, 0, sizeof(handler->flags));
if (!selHandlers) { if (selHandlers == NULL) {
/* first in the queue */ selHandlers = WMCreateTreeBag();
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) { WMPutInBag(selHandlers, handler);
case XA_CUT_BUFFER0:
buffer = 0; return True;
break; }
case XA_CUT_BUFFER1:
buffer = 1;
break;
case XA_CUT_BUFFER2: Bool
buffer = 2; WMRequestSelection(WMView *view, Atom selection, Atom target, Time timestamp,
break; WMSelectionCallback *callback, void *cdata)
case XA_CUT_BUFFER3: {
buffer = 3; SelectionCallback *handler;
break;
case XA_CUT_BUFFER4: if (XGetSelectionOwner(W_VIEW_SCREEN(view)->display, selection) == None)
buffer = 4; return False;
break;
case XA_CUT_BUFFER5: handler = wmalloc(sizeof(SelectionCallback));
buffer = 5;
break; handler->view = view;
case XA_CUT_BUFFER6: handler->selection = selection;
buffer = 6; handler->target = target;
break; handler->timestamp = timestamp;
case XA_CUT_BUFFER7: handler->callback = callback;
buffer = 7; handler->data = cdata;
break; memset(&handler->flags, 0, sizeof(handler->flags));
}
if (buffer >= 0) { if (selCallbacks == NULL) {
char *data; selCallbacks = WMCreateTreeBag();
int size; }
data = XFetchBuffer(scr->display, &size, buffer); WMPutInBag(selCallbacks, handler);
return data; if (!XConvertSelection(W_VIEW_SCREEN(view)->display, selection, target,
} else { W_VIEW_SCREEN(view)->clipboardAtom,
char *data; W_VIEW_DRAWABLE(view), timestamp)) {
int bits; return False;
Atom rtype; }
unsigned long len, bytes;
WMHandlerID timer; return True;
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 = { W_ViewDelegate _ColorWellViewDelegate = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
willResizeColorWell willResizeColorWell
}; };
#if 0 static unsigned draggingSourceOperation(WMView *self, Bool local);
static WMDragSourceProcs dragProcs = {
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_WIDTH 60
#define DEFAULT_HEIGHT 30 #define DEFAULT_HEIGHT 30
@@ -168,7 +192,16 @@ WMCreateColorWell(WMWidget *parent)
WMAddNotificationObserver(colorChangedObserver, cPtr, WMAddNotificationObserver(colorChangedObserver, cPtr,
WMColorPanelColorChangedNotification, NULL); WMColorPanelColorChangedNotification, NULL);
WMSetViewDragSourceProcs(cPtr->view, &_DragSourceProcs);
WMSetViewDragDestinationProcs(cPtr->view, &_DragDestinationProcs);
{
char *types[2] = {"application/X-color", NULL};
WMRegisterViewForDraggedTypes(cPtr->view, types);
}
return cPtr; 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* static WMPixmap*
makeDragPixmap(WMColorWell *cPtr) 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 static void
handleDragEvents(XEvent *event, void *data) handleDragEvents(XEvent *event, void *data)
{ {
@@ -526,17 +365,17 @@ handleDragEvents(XEvent *event, void *data)
|| abs(cPtr->ipoint.y - event->xmotion.y) > 4) { || abs(cPtr->ipoint.y - event->xmotion.y) > 4) {
WMSize offs; WMSize offs;
WMPixmap *pixmap; WMPixmap *pixmap;
char *types[2] = {"application/X-color", NULL};
offs.width = 2; offs.width = 2;
offs.height = 2; offs.height = 2;
pixmap = makeDragPixmap(cPtr); pixmap = makeDragPixmap(cPtr);
/* WMDragImageFromView(cPtr->view, pixmap, types,
WMDragImageFromView(cPtr->view, pixmap, cPtr->view->pos, wmkpoint(event->xmotion.x_root,
offs, event, True); event->xmotion.y_root),
* */ offs, event, True);
dragColor(cPtr, event, pixmap);
WMReleasePixmap(pixmap); WMReleasePixmap(pixmap);
} }
@@ -585,3 +424,53 @@ destroyColorWell(ColorWell *cPtr)
wfree(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", "XdndDrop",
"XdndFinished", "XdndFinished",
"XdndTypeList", "XdndTypeList",
"XdndActionCopy",
"XdndActionMove",
"XdndActionLink",
"XdndActionAsk",
"XdndActionPrivate",
"XdndStatus", "XdndStatus",
"WM_STATE" "WM_STATE"
}; };
Atom atoms[sizeof(atomNames)/sizeof(char*)]; Atom atoms[sizeof(atomNames)/sizeof(char*)];
int i = 0;
if (!initialized) { if (!initialized) {
@@ -766,26 +772,33 @@ WMCreateScreenWithRContext(Display *display, int screen, RContext *context)
} }
} }
#endif #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->clipboardAtom = atoms[i++];
scrPtr->xdndAwareAtom = atoms[4]; scrPtr->xdndAwareAtom = atoms[i++];
scrPtr->xdndSelectionAtom = atoms[5]; scrPtr->xdndSelectionAtom = atoms[i++];
scrPtr->xdndEnterAtom = atoms[6]; scrPtr->xdndEnterAtom = atoms[i++];
scrPtr->xdndLeaveAtom = atoms[7]; scrPtr->xdndLeaveAtom = atoms[i++];
scrPtr->xdndPositionAtom = atoms[8]; scrPtr->xdndPositionAtom = atoms[i++];
scrPtr->xdndDropAtom = atoms[9]; scrPtr->xdndDropAtom = atoms[i++];
scrPtr->xdndFinishedAtom = atoms[10]; scrPtr->xdndFinishedAtom = atoms[i++];
scrPtr->xdndTypeListAtom = atoms[11]; scrPtr->xdndTypeListAtom = atoms[i++];
scrPtr->xdndStatusAtom = atoms[12]; 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); scrPtr->rootView = W_CreateRootView(scrPtr);

View File

@@ -28,7 +28,7 @@ typedef struct W_TabView {
struct { struct {
WMReliefType relief:4; WMReliefType relief:4;
WMTitlePosition titlePosition:4; WMTitlePosition titlePosition:4;
WMTabViewTypes type:2; WMTabViewType type:2;
unsigned tabbed:1; unsigned tabbed:1;
unsigned dontFitAll:1; unsigned dontFitAll:1;

View File

@@ -64,6 +64,11 @@ typedef struct W_TextField {
unsigned int secure:1; /* password entry style */ unsigned int secure:1; /* password entry style */
unsigned int pointerGrabbed:1; unsigned int pointerGrabbed:1;
unsigned int ownsSelection:1;
unsigned int waitingSelection:1; /* requested selection, but
* didnt get yet */
/**/ /**/
unsigned int notIllegalMovement:1; 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, \ #define TEXT_WIDTH(tPtr, start) (WMWidthOfString((tPtr)->font, \
&((tPtr)->text[(start)]), (tPtr)->textLen - (start) + 1)) &((tPtr)->text[(start)]), (tPtr)->textLen - (start) + 1))
@@ -210,73 +229,73 @@ decrToFit(TextField *tPtr)
#undef TEXT_WIDTH #undef TEXT_WIDTH
#undef TEXT_WIDTH2 #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; int count;
Display *dpy = tPtr->view->screen->display; Display *dpy = tPtr->view->screen->display;
Atom _TARGETS; Atom _TARGETS;
char *text; Atom TEXT = XInternAtom(dpy, "TEXT", False);
text = XGetAtomName(tPtr->view->screen->display,target); Atom COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", False);
XFree(text); WMData *data;
text = XGetAtomName(tPtr->view->screen->display,selection);
XFree(text);
*format = 32;
*length = 0;
*value = NULL;
count = tPtr->selection.count < 0 count = tPtr->selection.count < 0
? tPtr->selection.position + tPtr->selection.count ? tPtr->selection.position + tPtr->selection.count
: tPtr->selection.position; : tPtr->selection.position;
if (target == XA_STRING || if (target == XA_STRING || target == TEXT || target == COMPOUND_TEXT) {
target == XInternAtom(dpy, "TEXT", False) ||
target == XInternAtom(dpy, "COMPOUND_TEXT", False)) { data = WMCreateDataWithBytes(&(tPtr->text[count]),
*value = wstrdup(&(tPtr->text[count])); abs(tPtr->selection.count));
*length = abs(tPtr->selection.count); WMSetDataFormat(data, 8);
*format = 8;
*type = target; *type = target;
return True;
return data;
} }
_TARGETS = XInternAtom(dpy, "TARGETS", False); _TARGETS = XInternAtom(dpy, "TARGETS", False);
if (target == _TARGETS) { if (target == _TARGETS) {
int *ptr; Atom *ptr;
*length = 4; ptr = wmalloc(4 * sizeof(Atom));
ptr = *value = (char *) wmalloc(4 * sizeof(Atom));
ptr[0] = _TARGETS; ptr[0] = _TARGETS;
ptr[1] = XA_STRING; ptr[1] = XA_STRING;
ptr[2] = XInternAtom(dpy, "TEXT", False); ptr[2] = TEXT;
ptr[3] = XInternAtom(dpy, "COMPOUND_TEXT", False); ptr[3] = COMPOUND_TEXT;
data = WMCreateDataWithBytes(ptr, 4*4);
WMSetDataFormat(data, 32);
*type = target; *type = target;
return True; return data;
} }
/*
*target = XA_PRIMARY; return NULL;
*/
return False;
} }
static void 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; tPtr->selection.count = 0;
paintTextField(tPtr); paintTextField(tPtr);
} }
static void static void
_notification(void *observerData, WMNotification *notification) _notification(void *observerData, WMNotification *notification)
{ {
WMTextField *to = (WMTextField*)observerData; WMTextField *to = (WMTextField*)observerData;
WMTextField *tw = (WMTextField*)WMGetNotificationClientData(notification); WMTextField *tw = (WMTextField*)WMGetNotificationClientData(notification);
if (to != tw) lostHandler(to, 0); if (to != tw) lostHandler(to->view, XA_PRIMARY, NULL);
} }
WMTextField* WMTextField*
@@ -327,8 +346,6 @@ WMCreateTextField(WMWidget *parent)
|ButtonReleaseMask|ButtonPressMask|KeyPressMask|Button1MotionMask, |ButtonReleaseMask|ButtonPressMask|KeyPressMask|Button1MotionMask,
handleTextFieldActionEvents, tPtr); handleTextFieldActionEvents, tPtr);
WMCreateSelectionHandler(tPtr, XA_PRIMARY, CurrentTime, requestHandler,
lostHandler, NULL);
WMAddNotificationObserver(_notification, tPtr, "_lostOwnership", tPtr); WMAddNotificationObserver(_notification, tPtr, "_lostOwnership", tPtr);
@@ -1185,20 +1202,17 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
if (!cancelSelection) { if (!cancelSelection) {
if (tPtr->selection.count != tPtr->cursorPosition - tPtr->selection.position) { if (tPtr->selection.count != tPtr->cursorPosition - tPtr->selection.position) {
WMNotification *notif;
tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position; tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position;
XSetSelectionOwner(tPtr->view->screen->display, WMPostNotificationName("_lostOwnership", NULL, tPtr);
XA_PRIMARY, tPtr->view->window,
event->xbutton.time);
notif = WMCreateNotification("_lostOwnership", NULL, tPtr);
WMPostNotification(notif);
WMReleaseNotification(notif);
refresh = 1; refresh = 1;
} }
} else { } else {
lostHandler(tPtr->view, XA_PRIMARY, NULL);
if (tPtr->selection.count) { if (tPtr->selection.count) {
tPtr->selection.count = 0; tPtr->selection.count = 0;
refresh = 1; 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 static void
handleTextFieldActionEvents(XEvent *event, void *data) handleTextFieldActionEvents(XEvent *event, void *data)
{ {
TextField *tPtr = (TextField*)data; TextField *tPtr = (TextField*)data;
static int move = 0; static int move = 0;
static Time lastButtonReleasedEvent = 0; static Time lastButtonReleasedEvent = 0;
Display *dpy = event->xany.display;
CHECK_CLASS(data, WC_TextField); CHECK_CLASS(data, WC_TextField);
switch (event->type) { switch (event->type) {
case KeyPress: case KeyPress:
if (tPtr->flags.waitingSelection) {
return;
}
if (tPtr->flags.enabled && tPtr->flags.focused) { if (tPtr->flags.enabled && tPtr->flags.focused) {
handleTextFieldKeyPress(tPtr, event); handleTextFieldKeyPress(tPtr, event);
XGrabPointer(WMScreenDisplay(W_VIEW(tPtr)->screen), XGrabPointer(dpy, W_VIEW(tPtr)->window, False,
W_VIEW(tPtr)->window, False,
PointerMotionMask|ButtonPressMask|ButtonReleaseMask, PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, GrabModeAsync, GrabModeAsync, None,
W_VIEW(tPtr)->screen->invisibleCursor, W_VIEW(tPtr)->screen->invisibleCursor,
@@ -1291,7 +1340,10 @@ handleTextFieldActionEvents(XEvent *event, void *data)
if (tPtr->flags.pointerGrabbed) { if (tPtr->flags.pointerGrabbed) {
tPtr->flags.pointerGrabbed = 0; 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)) { if (tPtr->flags.enabled && (event->xmotion.state & Button1Mask)) {
@@ -1309,40 +1361,35 @@ handleTextFieldActionEvents(XEvent *event, void *data)
tPtr->viewPosition--; tPtr->viewPosition--;
} }
/*if (!tPtr->selection.count) {
tPtr->selection.position = tPtr->cursorPosition;
}*/
tPtr->cursorPosition = tPtr->cursorPosition =
pointToCursorPosition(tPtr, event->xmotion.x); pointToCursorPosition(tPtr, event->xmotion.x);
tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position; tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position;
/*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count);*/
/* if (tPtr->selection.count != 0) {
printf("notify %d %d\n",event->xmotion.x,tPtr->usableWidth); if (!tPtr->flags.ownsSelection) {
*/ WMCreateSelectionHandler(tPtr->view,
XA_PRIMARY,
event->xbutton.time,
&selectionHandler, NULL);
tPtr->flags.ownsSelection = 1;
}
}
paintCursor(tPtr); paintCursor(tPtr);
paintTextField(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; break;
case ButtonPress: case ButtonPress:
if (tPtr->flags.pointerGrabbed) { if (tPtr->flags.pointerGrabbed) {
tPtr->flags.pointerGrabbed = 0; tPtr->flags.pointerGrabbed = 0;
XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr)->screen), CurrentTime); XUngrabPointer(dpy, CurrentTime);
break;
}
if (tPtr->flags.waitingSelection) {
break; break;
} }
@@ -1353,26 +1400,18 @@ handleTextFieldActionEvents(XEvent *event, void *data)
textWidth = WMWidthOfString(tPtr->font, tPtr->text, tPtr->textLen); textWidth = WMWidthOfString(tPtr->font, tPtr->text, tPtr->textLen);
if (tPtr->flags.enabled && !tPtr->flags.focused) { if (tPtr->flags.enabled && !tPtr->flags.focused) {
WMSetFocusToWidget(tPtr); WMSetFocusToWidget(tPtr);
} else if (tPtr->flags.focused) { } else if (tPtr->flags.focused) {
tPtr->selection.position = tPtr->cursorPosition; tPtr->selection.position = tPtr->cursorPosition;
tPtr->selection.count = 0; tPtr->selection.count = 0;
} }
if(textWidth < tPtr->usableWidth){ if(textWidth < tPtr->usableWidth) {
tPtr->cursorPosition = pointToCursorPosition(tPtr, tPtr->cursorPosition = pointToCursorPosition(tPtr,
event->xbutton.x - tPtr->usableWidth event->xbutton.x - tPtr->usableWidth
+ textWidth); + textWidth);
} } else tPtr->cursorPosition = pointToCursorPosition(tPtr,
else tPtr->cursorPosition = pointToCursorPosition(tPtr,
event->xbutton.x); event->xbutton.x);
/*
tPtr->cursorPosition = pointToCursorPosition(tPtr,
event->xbutton.x);
tPtr->cursorPosition += tPtr->usableWidth - textWidth;
}
tPtr->cursorPosition = pointToCursorPosition(tPtr,
event->xbutton.x);
*/
paintTextField(tPtr); paintTextField(tPtr);
break; break;
@@ -1382,7 +1421,8 @@ handleTextFieldActionEvents(XEvent *event, void *data)
tPtr->cursorPosition = pointToCursorPosition(tPtr, tPtr->cursorPosition = pointToCursorPosition(tPtr,
event->xbutton.x); event->xbutton.x);
paintTextField(tPtr); paintTextField(tPtr);
} else if (tPtr->flags.focused) { } else if (tPtr->flags.focused
&& event->xbutton.button == Button1) {
tPtr->cursorPosition = pointToCursorPosition(tPtr, tPtr->cursorPosition = pointToCursorPosition(tPtr,
event->xbutton.x); event->xbutton.x);
tPtr->selection.position = tPtr->cursorPosition; tPtr->selection.position = tPtr->cursorPosition;
@@ -1391,51 +1431,71 @@ handleTextFieldActionEvents(XEvent *event, void *data)
} }
if (event->xbutton.button == Button2 && tPtr->flags.enabled) { if (event->xbutton.button == Button2 && tPtr->flags.enabled) {
char *text; char *text;
int n;
text = W_GetTextSelection(tPtr->view->screen, XA_PRIMARY); if (!WMRequestSelection(tPtr->view, XA_PRIMARY, XA_STRING,
event->xbutton.time,
if (!text) { pasteText, NULL)) {
text = W_GetTextSelection(tPtr->view->screen, text = XFetchBuffer(tPtr->view->screen->display, &n, 0);
tPtr->view->screen->clipboardAtom);
} if (text) {
if (!text) { text[n] = 0;
text = W_GetTextSelection(tPtr->view->screen, WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition);
XA_CUT_BUFFER0); XFree(text);
} NOTIFY(tPtr, didChange, WMTextDidChangeNotification,
if (text) { (void*)WMInsertTextEvent);
WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition); }
XFree(text); } else {
NOTIFY(tPtr, didChange, WMTextDidChangeNotification, tPtr->flags.waitingSelection = 1;
(void*)WMInsertTextEvent); }
}
} }
break; break;
default:
break;
} }
break; break;
case ButtonRelease: case ButtonRelease:
if (tPtr->flags.pointerGrabbed) { if (tPtr->flags.pointerGrabbed) {
tPtr->flags.pointerGrabbed = 0; tPtr->flags.pointerGrabbed = 0;
XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr)->screen), CurrentTime); 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 if (event->xbutton.time - lastButtonReleasedEvent
<= WINGsConfiguration.doubleClickDelay) { <= WINGsConfiguration.doubleClickDelay) {
tPtr->selection.position = 0; tPtr->selection.position = 0;
tPtr->selection.count = tPtr->textLen; tPtr->selection.count = tPtr->textLen;
paintTextField(tPtr); paintTextField(tPtr);
XSetSelectionOwner(tPtr->view->screen->display,
XA_PRIMARY, tPtr->view->window, event->xbutton.time); if (!tPtr->flags.ownsSelection) {
{ WMCreateSelectionHandler(tPtr->view,
WMNotification *notif = WMCreateNotification("_lostOwnership", XA_PRIMARY,
NULL,tPtr); event->xbutton.time,
WMPostNotification(notif); &selectionHandler, NULL);
WMReleaseNotification(notif); tPtr->flags.ownsSelection = 1;
}
} }
lastButtonReleasedEvent = event->xbutton.time;
WMPostNotificationName("_lostOwnership", NULL, tPtr);
}
lastButtonReleasedEvent = event->xbutton.time;
break; break;
} }
@@ -1451,7 +1511,7 @@ destroyTextField(TextField *tPtr)
#endif #endif
WMReleaseFont(tPtr->font); WMReleaseFont(tPtr->font);
WMDeleteSelectionHandler(tPtr, XA_PRIMARY); WMDeleteSelectionHandler(tPtr->view, XA_PRIMARY, CurrentTime);
WMRemoveNotificationObserver(tPtr); WMRemoveNotificationObserver(tPtr);
if (tPtr->text) if (tPtr->text)

View File

@@ -411,6 +411,10 @@ destroyView(W_View *view)
if (view->dragDestinationProcs) if (view->dragDestinationProcs)
wfree(view->dragDestinationProcs); wfree(view->dragDestinationProcs);
if (scr->dragInfo.destView == view) {
scr->dragInfo.destView = NULL;
}
#endif #endif
wfree(view); wfree(view);
} }