X-Git-Url: https://repo.or.cz/w/wmaker-crm.git/blobdiff_plain/59fc927dc9f183802621138534fa6eaafe5593ba..688a56e8ab67b56550e2874d9d7423f0d435bfd9:/WINGs/selection.c diff --git a/WINGs/selection.c b/WINGs/selection.c dissimilarity index 95% index 2f955482..ce93d225 100644 --- a/WINGs/selection.c +++ b/WINGs/selection.c @@ -1,443 +1,392 @@ - - -#include - -#include - -#include "WINGsP.h" - -#define MAX_PROPERTY_SIZE 8*1024 - - -char *WMSelectionOwnerDidChangeNotification = "WMSelectionOwnerDidChange"; - - -typedef struct SelectionHandler { - WMView *view; - Atom selection; - Time timestamp; - WMSelectionProcs procs; - void *data; - - struct { - unsigned delete_pending:1; - unsigned done_pending:1; - } flags; -} SelectionHandler; - - -typedef struct SelectionCallback { - WMView *view; - Atom selection; - Atom target; - Time timestamp; - WMSelectionCallback *callback; - void *data; - - struct { - unsigned delete_pending:1; - unsigned done_pending:1; - } flags; -} SelectionCallback; - - - -static WMArray *selCallbacks = NULL; - -static WMArray *selHandlers = NULL; - -static Bool gotXError = False; - - - - -void -WMDeleteSelectionHandler(WMView *view, Atom selection, Time timestamp) -{ - SelectionHandler *handler; - Display *dpy = W_VIEW_SCREEN(view)->display; - Window win = W_VIEW_DRAWABLE(view); - WMArrayIterator iter; - - if (!selHandlers) - return; - - /*//printf("deleting selection handler for %d", win);*/ - - WM_ITERATE_ARRAY(selHandlers, handler, iter) { - if (handler->view == view - && (handler->selection == selection || selection == None) - && (handler->timestamp == timestamp || timestamp == CurrentTime)) { - - if (handler->flags.done_pending) { - handler->flags.delete_pending = 1; - /*//puts(": postponed because still pending");*/ - return; - } - /*//printf(": found & removed");*/ - WMRemoveFromArray(selHandlers, handler); - break; - } - } - - /*//printf("\n");*/ - - XGrabServer(dpy); - if (XGetSelectionOwner(dpy, selection) == win) { - XSetSelectionOwner(dpy, selection, None, timestamp); - } - XUngrabServer(dpy); -} - - - -void -WMDeleteSelectionCallback(WMView *view, Atom selection, Time timestamp) -{ - SelectionCallback *handler; - WMArrayIterator iter; - - if (!selCallbacks) - return; - - WM_ITERATE_ARRAY(selCallbacks, handler, iter) { - if (handler->view == view - && (handler->selection == selection || selection == None) - && (handler->timestamp == timestamp || timestamp == CurrentTime)) { - - if (handler->flags.done_pending) { - handler->flags.delete_pending = 1; - return; - } - WMRemoveFromArray(selCallbacks, handler); - break; - } - } -} - - -static int -handleXError(Display *dpy, XErrorEvent *ev) -{ - gotXError = True; - - return 1; -} - - -static Bool -writeSelection(Display *dpy, Window requestor, Atom property, Atom type, - WMData *data) -{ - static void *oldHandler; - int format, bpi; - - format = WMGetDataFormat(data); - if (format == 0) - format = 8; - - bpi = format/8; - - /* printf("write to %x: %s\n", requestor, XGetAtomName(dpy, property)); */ - - oldHandler = XSetErrorHandler(handleXError); - - gotXError = False; - - XChangeProperty(dpy, requestor, property, type, format, PropModeReplace, - WMDataBytes(data), WMGetDataLength(data)/bpi); - - XFlush(dpy); - - XSetErrorHandler(oldHandler); - - return !gotXError; -} - - -static void -notifySelection(XEvent *event, Atom prop) -{ - XEvent ev; - - /* printf("event to %x\n", event->xselectionrequest.requestor); */ - - ev.xselection.type = SelectionNotify; - ev.xselection.serial = 0; - ev.xselection.send_event = True; - ev.xselection.display = event->xselectionrequest.display; - ev.xselection.requestor = event->xselectionrequest.requestor; - ev.xselection.target = event->xselectionrequest.target; - ev.xselection.selection = event->xselectionrequest.selection; - ev.xselection.property = prop; - ev.xselection.time = event->xselectionrequest.time; - - XSendEvent(event->xany.display, event->xselectionrequest.requestor, - False, 0, &ev); - XFlush(event->xany.display); -} - - -static void -handleRequestEvent(XEvent *event) -{ - SelectionHandler *handler; - WMArrayIterator iter; - WMArray *copy; - Bool handledRequest; - - WM_ITERATE_ARRAY(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; - } - - handledRequest = False; - - handler->flags.done_pending = 1; - - data = handler->procs.convertSelection(handler->view, - handler->selection, - event->xselectionrequest.target, - handler->data, - &atom); - - prop = event->xselectionrequest.property; - /* obsolete clients that don't set the property field */ - if (prop == None) - prop = event->xselectionrequest.target; - - if (data) { - if (writeSelection(event->xselectionrequest.display, - event->xselectionrequest.requestor, - prop, atom, data)) { - handledRequest = True; - } - WMReleaseData(data); - } - - notifySelection(event, (handledRequest==True ? prop : None)); - - if (handler->procs.selectionDone != NULL) { - handler->procs.selectionDone(handler->view, - handler->selection, - event->xselectionrequest.target, - handler->data); - } - - handler->flags.done_pending = 0; - } - break; - } - } - - /* delete handlers */ - copy = WMDuplicateArray(selHandlers); - WM_ITERATE_ARRAY(copy, handler, iter) { - if (handler && handler->flags.delete_pending) { - WMDeleteSelectionHandler(handler->view, handler->selection, - handler->timestamp); - } - } - WMFreeArray(copy); -} - - -static WMData* -getSelectionData(Display *dpy, Window win, Atom where) -{ - WMData *wdata; - unsigned char *data; - Atom rtype; - int bits, bpi; - unsigned long len, bytes; - - - if (XGetWindowProperty(dpy, win, where, 0, MAX_PROPERTY_SIZE, - False, AnyPropertyType, &rtype, &bits, &len, - &bytes, &data)!=Success) { - return NULL; - } - - bpi = bits/8; - - wdata = WMCreateDataWithBytesNoCopy(data, len*bpi, (WMFreeDataProc*)XFree); - WMSetDataFormat(wdata, bits); - - return wdata; -} - - -static void -handleNotifyEvent(XEvent *event) -{ - SelectionCallback *handler; - WMArrayIterator iter; - WMArray *copy; - WMData *data; - - WM_ITERATE_ARRAY(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; - } - - /* delete callbacks */ - copy = WMDuplicateArray(selCallbacks); - WM_ITERATE_ARRAY(copy, handler, iter) { - if (handler && handler->flags.delete_pending) { - WMDeleteSelectionCallback(handler->view, handler->selection, - handler->timestamp); - } - } - WMFreeArray(copy); -} - - - -void -W_HandleSelectionEvent(XEvent *event) -{ - /*//printf("%d received selection ", event->xany.window);*/ - /*//switch(event->type) { - case SelectionNotify: - puts("notify"); break; - case SelectionRequest: - puts("request"); break; - case SelectionClear: - puts("clear"); break; - default: - puts("unknown"); break; - }*/ - - if (event->type == SelectionNotify) { - handleNotifyEvent(event); - } else { - handleRequestEvent(event); - } -} - - - -Bool -WMCreateSelectionHandler(WMView *view, Atom selection, Time timestamp, - WMSelectionProcs *procs, void *cdata) -{ - SelectionHandler *handler; - Display *dpy = W_VIEW_SCREEN(view)->display; - - XSetSelectionOwner(dpy, selection, W_VIEW_DRAWABLE(view), timestamp); - if (XGetSelectionOwner(dpy, selection) != W_VIEW_DRAWABLE(view)) { - return False; - } - - WMPostNotificationName(WMSelectionOwnerDidChangeNotification, - (void*)selection, (void*)view); - - /*//printf("created selection handler for %d\n", W_VIEW_DRAWABLE(view));*/ - - handler = wmalloc(sizeof(SelectionHandler)); - - handler->view = view; - handler->selection = selection; - handler->timestamp = timestamp; - handler->procs = *procs; - handler->data = cdata; - memset(&handler->flags, 0, sizeof(handler->flags)); - - if (selHandlers == NULL) { - selHandlers = WMCreateArrayWithDestructor(4, wfree); - } - - WMAddToArray(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; - - if (!XConvertSelection(W_VIEW_SCREEN(view)->display, selection, target, - W_VIEW_SCREEN(view)->clipboardAtom, - W_VIEW_DRAWABLE(view), timestamp)) { - 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 = WMCreateArrayWithDestructor(4, wfree); - } - - WMAddToArray(selCallbacks, handler); - - return True; -} - + +#include + +#include + +#include "WINGsP.h" + +#define MAX_PROPERTY_SIZE 8*1024 + +char *WMSelectionOwnerDidChangeNotification = "WMSelectionOwnerDidChange"; + +typedef struct SelectionHandler { + WMView *view; + Atom selection; + Time timestamp; + WMSelectionProcs procs; + void *data; + + struct { + unsigned delete_pending:1; + unsigned done_pending:1; + } flags; +} SelectionHandler; + +typedef struct SelectionCallback { + WMView *view; + Atom selection; + Atom target; + Time timestamp; + WMSelectionCallback *callback; + void *data; + + struct { + unsigned delete_pending:1; + unsigned done_pending:1; + } flags; +} SelectionCallback; + +static WMArray *selCallbacks = NULL; + +static WMArray *selHandlers = NULL; + +static Bool gotXError = False; + +void WMDeleteSelectionHandler(WMView * view, Atom selection, Time timestamp) +{ + SelectionHandler *handler; + Display *dpy = W_VIEW_SCREEN(view)->display; + Window win = W_VIEW_DRAWABLE(view); + WMArrayIterator iter; + + if (!selHandlers) + return; + + /*//printf("deleting selection handler for %d", win); */ + + WM_ITERATE_ARRAY(selHandlers, handler, iter) { + if (handler->view == view && (handler->selection == selection || selection == None) + && (handler->timestamp == timestamp || timestamp == CurrentTime)) { + + if (handler->flags.done_pending) { + handler->flags.delete_pending = 1; + /*//puts(": postponed because still pending"); */ + return; + } + /*//printf(": found & removed"); */ + WMRemoveFromArray(selHandlers, handler); + break; + } + } + + /*//printf("\n"); */ + + XGrabServer(dpy); + if (XGetSelectionOwner(dpy, selection) == win) { + XSetSelectionOwner(dpy, selection, None, timestamp); + } + XUngrabServer(dpy); +} + +void WMDeleteSelectionCallback(WMView * view, Atom selection, Time timestamp) +{ + SelectionCallback *handler; + WMArrayIterator iter; + + if (!selCallbacks) + return; + + WM_ITERATE_ARRAY(selCallbacks, handler, iter) { + if (handler->view == view && (handler->selection == selection || selection == None) + && (handler->timestamp == timestamp || timestamp == CurrentTime)) { + + if (handler->flags.done_pending) { + handler->flags.delete_pending = 1; + return; + } + WMRemoveFromArray(selCallbacks, handler); + break; + } + } +} + +static int handleXError(Display * dpy, XErrorEvent * ev) +{ + gotXError = True; + + return 1; +} + +static Bool writeSelection(Display * dpy, Window requestor, Atom property, Atom type, WMData * data) +{ + static void *oldHandler; + int format, bpi; + + format = WMGetDataFormat(data); + if (format == 0) + format = 8; + + bpi = format / 8; + + /* printf("write to %x: %s\n", requestor, XGetAtomName(dpy, property)); */ + + oldHandler = XSetErrorHandler(handleXError); + + gotXError = False; + + XChangeProperty(dpy, requestor, property, type, format, PropModeReplace, + WMDataBytes(data), WMGetDataLength(data) / bpi); + + XFlush(dpy); + + XSetErrorHandler(oldHandler); + + return !gotXError; +} + +static void notifySelection(XEvent * event, Atom prop) +{ + XEvent ev; + + /* printf("event to %x\n", event->xselectionrequest.requestor); */ + + ev.xselection.type = SelectionNotify; + ev.xselection.serial = 0; + ev.xselection.send_event = True; + ev.xselection.display = event->xselectionrequest.display; + ev.xselection.requestor = event->xselectionrequest.requestor; + ev.xselection.target = event->xselectionrequest.target; + ev.xselection.selection = event->xselectionrequest.selection; + ev.xselection.property = prop; + ev.xselection.time = event->xselectionrequest.time; + + XSendEvent(event->xany.display, event->xselectionrequest.requestor, False, 0, &ev); + XFlush(event->xany.display); +} + +static void handleRequestEvent(XEvent * event) +{ + SelectionHandler *handler; + WMArrayIterator iter; + WMArray *copy; + Bool handledRequest; + + WM_ITERATE_ARRAY(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; + } + + handledRequest = False; + + handler->flags.done_pending = 1; + + data = handler->procs.convertSelection(handler->view, + handler->selection, + event->xselectionrequest.target, + handler->data, &atom); + + prop = event->xselectionrequest.property; + /* obsolete clients that don't set the property field */ + if (prop == None) + prop = event->xselectionrequest.target; + + if (data) { + if (writeSelection(event->xselectionrequest.display, + event->xselectionrequest.requestor, prop, atom, data)) { + handledRequest = True; + } + WMReleaseData(data); + } + + notifySelection(event, (handledRequest == True ? prop : None)); + + if (handler->procs.selectionDone != NULL) { + handler->procs.selectionDone(handler->view, + handler->selection, + event->xselectionrequest.target, + handler->data); + } + + handler->flags.done_pending = 0; + } + break; + } + } + + /* delete handlers */ + copy = WMDuplicateArray(selHandlers); + WM_ITERATE_ARRAY(copy, handler, iter) { + if (handler && handler->flags.delete_pending) { + WMDeleteSelectionHandler(handler->view, handler->selection, handler->timestamp); + } + } + WMFreeArray(copy); +} + +static WMData *getSelectionData(Display * dpy, Window win, Atom where) +{ + WMData *wdata; + unsigned char *data; + Atom rtype; + int bits, bpi; + unsigned long len, bytes; + + if (XGetWindowProperty(dpy, win, where, 0, MAX_PROPERTY_SIZE, + False, AnyPropertyType, &rtype, &bits, &len, &bytes, &data) != Success) { + return NULL; + } + + bpi = bits / 8; + + wdata = WMCreateDataWithBytesNoCopy(data, len * bpi, (WMFreeDataProc *) XFree); + WMSetDataFormat(wdata, bits); + + return wdata; +} + +static void handleNotifyEvent(XEvent * event) +{ + SelectionCallback *handler; + WMArrayIterator iter; + WMArray *copy; + WMData *data; + + WM_ITERATE_ARRAY(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; + } + + /* delete callbacks */ + copy = WMDuplicateArray(selCallbacks); + WM_ITERATE_ARRAY(copy, handler, iter) { + if (handler && handler->flags.delete_pending) { + WMDeleteSelectionCallback(handler->view, handler->selection, handler->timestamp); + } + } + WMFreeArray(copy); +} + +void W_HandleSelectionEvent(XEvent * event) +{ + /*//printf("%d received selection ", event->xany.window); */ + /*//switch(event->type) { + case SelectionNotify: + puts("notify"); break; + case SelectionRequest: + puts("request"); break; + case SelectionClear: + puts("clear"); break; + default: + puts("unknown"); break; + } */ + + if (event->type == SelectionNotify) { + handleNotifyEvent(event); + } else { + handleRequestEvent(event); + } +} + +Bool WMCreateSelectionHandler(WMView * view, Atom selection, Time timestamp, WMSelectionProcs * procs, void *cdata) +{ + SelectionHandler *handler; + Display *dpy = W_VIEW_SCREEN(view)->display; + + XSetSelectionOwner(dpy, selection, W_VIEW_DRAWABLE(view), timestamp); + if (XGetSelectionOwner(dpy, selection) != W_VIEW_DRAWABLE(view)) { + return False; + } + + WMPostNotificationName(WMSelectionOwnerDidChangeNotification, (void *)selection, (void *)view); + + /*//printf("created selection handler for %d\n", W_VIEW_DRAWABLE(view)); */ + + handler = wmalloc(sizeof(SelectionHandler)); + + handler->view = view; + handler->selection = selection; + handler->timestamp = timestamp; + handler->procs = *procs; + handler->data = cdata; + memset(&handler->flags, 0, sizeof(handler->flags)); + + if (selHandlers == NULL) { + selHandlers = WMCreateArrayWithDestructor(4, wfree); + } + + WMAddToArray(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; + + if (!XConvertSelection(W_VIEW_SCREEN(view)->display, selection, target, + W_VIEW_SCREEN(view)->clipboardAtom, W_VIEW_DRAWABLE(view), timestamp)) { + 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 = WMCreateArrayWithDestructor(4, wfree); + } + + WMAddToArray(selCallbacks, handler); + + return True; +}