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

@@ -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;
WM_ITERATE_BAG(selHandlers, handler, iter) {
if (handler->view == view
&& (handler->selection == selection || selection == None)
&& (handler->timestamp == timestamp || timestamp == CurrentTime)) {
tmp = selHandlers;
if (tmp->widget == widget) {
if (tmp->flags.done_pending) {
tmp->flags.delete_pending = 1;
return;
}
selHandlers = tmp->next;
timestamp = tmp->timestamp;
wfree(tmp);
} else {
while (tmp->next) {
if (tmp->next->widget == widget) {
if (tmp->next->flags.done_pending) {
tmp->next->flags.delete_pending = 1;
return;
}
handler = tmp->next;
tmp->next = handler->next;
timestamp = handler->timestamp;
wfree(handler);
break;
}
tmp = tmp->next;
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)
}
static void
deleteHandlers(WMBagIterator iter)
{
SelectionHandler *handler;
if (iter == NULL)
handler = WMBagFirst(selHandlers, &iter);
else
handler = WMBagNext(selHandlers, &iter);
if (handler == NULL)
return;
deleteHandlers(iter);
if (handler->flags.delete_pending) {
WMDeleteSelectionHandler(handler->view, handler->selection,
handler->timestamp);
}
}
static void
handleRequestEvent(XEvent *event)
{
SelectionHandler *handler;
WMBagIterator iter;
Bool handledRequest = False;
WM_ITERATE_BAG(selHandlers, handler, iter) {
switch (event->type) {
case SelectionClear:
if (W_VIEW_DRAWABLE(handler->view)
!= event->xselectionclear.window) {
break;
}
handler->flags.done_pending = 1;
if (handler->procs.selectionLost)
handler->procs.selectionLost(handler->view,
handler->selection,
handler->data);
handler->flags.done_pending = 0;
handler->flags.delete_pending = 1;
break;
case SelectionRequest:
if (W_VIEW_DRAWABLE(handler->view)
!= event->xselectionrequest.owner) {
break;
}
if (handler->procs.convertSelection != NULL
&& handler->selection == event->xselectionrequest.selection) {
Atom atom;
WMData *data;
Atom prop;
/* they're requesting for something old.. maybe another handler
* can handle it */
if (event->xselectionrequest.time < handler->timestamp
&& event->xselectionrequest.time != CurrentTime) {
break;
}
handler->flags.done_pending = 1;
data = handler->procs.convertSelection(handler->view,
handler->selection,
event->xselectionrequest.target,
handler->data,
&atom);
if (data == NULL) {
break;
}
handledRequest = True;
prop = event->xselectionrequest.property;
/* obsolete clients that don't set the property field */
if (prop == None)
prop = event->xselectionrequest.target;
if (!writeSelection(event->xselectionrequest.display,
event->xselectionrequest.requestor,
prop, atom, data)) {
WMReleaseData(data);
notifySelection(event, None);
break;
}
WMReleaseData(data);
notifySelection(event, prop);
if (handler->procs.selectionDone != NULL) {
handler->procs.selectionDone(handler->view,
handler->selection,
event->xselectionrequest.target,
handler->data);
}
handler->flags.done_pending = 0;
if (!handledRequest) {
notifySelection(event, None);
}
}
break;
}
}
deleteHandlers(NULL);
}
static void
deleteCallbacks(WMBagIterator iter)
{
SelectionCallback *handler;
if (iter == NULL)
handler = WMBagFirst(selCallbacks, &iter);
else
handler = WMBagNext(selCallbacks, &iter);
if (handler == NULL)
return;
deleteCallbacks(iter);
if (handler->flags.delete_pending) {
WMDeleteSelectionCallback(handler->view, handler->selection,
handler->timestamp);
}
}
static WMData*
getSelectionData(Display *dpy, Window win, Atom where)
{
WMData *wdata;
unsigned char *data;
Atom rtype;
unsigned bits;
unsigned long len, bytes;
if (XGetWindowProperty(dpy, win, where, 0, MAX_PROPERTY_SIZE,
False, AnyPropertyType, &rtype, &bits, &len,
&bytes, &data)!=Success) {
return NULL;
}
wdata = WMCreateDataWithBytesAndDestructor(data, len,
(WMFreeDataProc*)XFree);
if (wdata == NULL) {
return NULL;
}
WMSetDataFormat(wdata, bits);
return wdata;
}
static void
handleNotifyEvent(XEvent *event)
{
SelectionCallback *handler;
WMBagIterator iter;
WMData *data;
WM_ITERATE_BAG(selCallbacks, handler, iter) {
if (W_VIEW_DRAWABLE(handler->view) != event->xselection.requestor
&& handler->selection == event->xselection.selection) {
continue;
}
handler->flags.done_pending = 1;
if (event->xselection.property == None) {
data = NULL;
} else {
data = getSelectionData(event->xselection.display,
event->xselection.requestor,
event->xselection.property);
}
(*handler->callback)(handler->view, handler->selection,
handler->target, handler->timestamp,
handler->data, data);
if (data != NULL) {
WMReleaseData(data);
}
handler->flags.done_pending = 0;
handler->flags.delete_pending = 1;
}
deleteCallbacks(NULL);
}
void
W_HandleSelectionEvent(XEvent *event)
{
SelectionHandler *handler;
handler = selHandlers;
while (handler) {
if (WMWidgetXID(handler->widget)==event->xany.window
/* && handler->selection == event->selection*/) {
switch (event->type) {
case SelectionClear:
if (handler->loseProc)
(*handler->loseProc)(handler->widget, handler->selection);
break;
case SelectionRequest:
if (handler->convProc) {
Atom atom;
void *data;
unsigned length;
int format;
Atom prop;
/* they're requesting for something old */
if (event->xselectionrequest.time < handler->timestamp
&& event->xselectionrequest.time != CurrentTime) {
notifySelection(event, None);
break;
}
handler->flags.done_pending = 1;
if (!(*handler->convProc)(handler->widget,
handler->selection,
event->xselectionrequest.target,
&atom, &data, &length, &format)) {
notifySelection(event, None);
break;
}
prop = event->xselectionrequest.property;
/* obsolete clients that don't set the property field */
if (prop == None)
prop = event->xselectionrequest.target;
if (!writeSelection(event->xselectionrequest.display,
event->xselectionrequest.requestor,
prop, atom, data, length, format)) {
wfree(data);
notifySelection(event, None);
break;
}
wfree(data);
notifySelection(event, prop);
if (handler->doneProc) {
(*handler->doneProc)(handler->widget,
handler->selection,
event->xselectionrequest.target);
}
handler->flags.done_pending = 0;
/* in case the handler was deleted from some
* callback */
if (handler->flags.delete_pending) {
WMDeleteSelectionHandler(handler->widget,
handler->selection);
}
}
break;
case SelectionNotify:
break;
}
}
handler = handler->next;
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();
}
return True;
}
static void
timeoutHandler(void *data)
{
*(int*)data = 1;
}
static Bool
getInternalSelection(WMScreen *scr, Atom selection, Atom target,
void **data, unsigned *length)
{
Window owner;
SelectionHandler *handler;
/*
* Check if the selection is owned by this application and if so,
* do the conversion directly.
*/
*data = NULL;
owner = XGetSelectionOwner(scr->display, selection);
if (!owner)
return False;
handler = selHandlers;
while (handler) {
if (WMWidgetXID(handler->widget) == owner
/* && handler->selection == event->selection*/) {
break;
}
handler = handler->next;
}
if (!handler)
return False;
if (handler->convProc) {
Atom atom;
int format;
if (!(*handler->convProc)(handler->widget, handler->selection,
target, &atom, data, length, &format)) {
return True;
}
if (handler->doneProc) {
(*handler->doneProc)(handler->widget, handler->selection, target);
}
}
return True;
}
char*
W_GetTextSelection(WMScreen *scr, Atom selection)
{
int buffer = -1;
switch (selection) {
case XA_CUT_BUFFER0:
buffer = 0;
break;
case XA_CUT_BUFFER1:
buffer = 1;
break;
case XA_CUT_BUFFER2:
buffer = 2;
break;
case XA_CUT_BUFFER3:
buffer = 3;
break;
case XA_CUT_BUFFER4:
buffer = 4;
break;
case XA_CUT_BUFFER5:
buffer = 5;
break;
case XA_CUT_BUFFER6:
buffer = 6;
break;
case XA_CUT_BUFFER7:
buffer = 7;
break;
}
if (buffer >= 0) {
char *data;
int size;
data = XFetchBuffer(scr->display, &size, buffer);
return data;
} else {
char *data;
int bits;
Atom rtype;
unsigned long len, bytes;
WMHandlerID timer;
int timeout = 0;
XEvent ev;
unsigned length;
XDeleteProperty(scr->display, scr->groupLeader, scr->clipboardAtom);
if (getInternalSelection(scr, selection, XA_STRING, (void**)&data,
&length)) {
return data;
}
XConvertSelection(scr->display, selection, XA_STRING,
scr->clipboardAtom, scr->groupLeader,
scr->lastEventTime);
timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
while (!XCheckTypedWindowEvent(scr->display, scr->groupLeader,
SelectionNotify, &ev) && !timeout);
if (!timeout) {
WMDeleteTimerHandler(timer);
} else {
wwarning("selection retrieval timed out");
return NULL;
}
/* nobody owns the selection or the current owner has
* nothing to do with what we need */
if (ev.xselection.property == None) {
return NULL;
}
if (XGetWindowProperty(scr->display, scr->groupLeader,
scr->clipboardAtom, 0, MAX_PROPERTY_SIZE,
False, XA_STRING, &rtype, &bits, &len,
&bytes, (unsigned char**)&data)!=Success) {
return NULL;
}
if (rtype!=XA_STRING || bits!=8) {
wwarning("invalid data in text selection");
if (data)
XFree(data);
return NULL;
}
return data;
}
WMPutInBag(selHandlers, handler);
return True;
}
Bool
WMRequestSelection(WMView *view, Atom selection, Atom target, Time timestamp,
WMSelectionCallback *callback, void *cdata)
{
SelectionCallback *handler;
if (XGetSelectionOwner(W_VIEW_SCREEN(view)->display, selection) == None)
return False;
handler = wmalloc(sizeof(SelectionCallback));
handler->view = view;
handler->selection = selection;
handler->target = target;
handler->timestamp = timestamp;
handler->callback = callback;
handler->data = cdata;
memset(&handler->flags, 0, sizeof(handler->flags));
if (selCallbacks == NULL) {
selCallbacks = WMCreateTreeBag();
}
WMPutInBag(selCallbacks, handler);
if (!XConvertSelection(W_VIEW_SCREEN(view)->display, selection, target,
W_VIEW_SCREEN(view)->clipboardAtom,
W_VIEW_DRAWABLE(view), timestamp)) {
return False;
}
return True;
}