9 #define MAX_PROPERTY_SIZE 8*1024
12 typedef struct SelectionHandler
{
16 WMSelectionProcs procs
;
20 unsigned delete_pending
:1;
21 unsigned done_pending
:1;
26 typedef struct SelectionCallback
{
31 WMSelectionCallback
*callback
;
35 unsigned delete_pending
:1;
36 unsigned done_pending
:1;
42 static WMArray
*selCallbacks
= NULL
;
44 static WMArray
*selHandlers
= NULL
;
46 static Bool gotXError
= False
;
52 WMDeleteSelectionHandler(WMView
*view
, Atom selection
, Time timestamp
)
54 SelectionHandler
*handler
;
55 Display
*dpy
= W_VIEW_SCREEN(view
)->display
;
56 Window win
= W_VIEW_DRAWABLE(view
);
62 //printf("deleting selection handler for %d\n", win);
64 WM_ITERATE_ARRAY(selHandlers
, handler
, iter
) {
65 if (handler
->view
== view
66 && (handler
->selection
== selection
|| selection
== None
)
67 && (handler
->timestamp
== timestamp
|| timestamp
== CurrentTime
)) {
69 if (handler
->flags
.done_pending
) {
70 handler
->flags
.delete_pending
= 1;
73 //puts("found & removed");
74 WMRemoveFromArray(selHandlers
, handler
);
80 if (XGetSelectionOwner(dpy
, selection
) == win
) {
81 XSetSelectionOwner(dpy
, selection
, None
, timestamp
);
89 WMDeleteSelectionCallback(WMView
*view
, Atom selection
, Time timestamp
)
91 SelectionCallback
*handler
;
97 WM_ITERATE_ARRAY(selCallbacks
, handler
, iter
) {
98 if (handler
->view
== view
99 && (handler
->selection
== selection
|| selection
== None
)
100 && (handler
->timestamp
== timestamp
|| timestamp
== CurrentTime
)) {
102 if (handler
->flags
.done_pending
) {
103 handler
->flags
.delete_pending
= 1;
106 WMRemoveFromArray(selCallbacks
, handler
);
114 handleXError(Display
*dpy
, XErrorEvent
*ev
)
123 writeSelection(Display
*dpy
, Window requestor
, Atom property
, Atom type
,
126 static void *oldHandler
;
129 format
= WMGetDataFormat(data
);
135 /* printf("write to %x: %s\n", requestor, XGetAtomName(dpy, property)); */
137 oldHandler
= XSetErrorHandler(handleXError
);
141 XChangeProperty(dpy
, requestor
, property
, type
, format
, PropModeReplace
,
142 WMDataBytes(data
), WMGetDataLength(data
)/bpi
);
146 XSetErrorHandler(oldHandler
);
153 notifySelection(XEvent
*event
, Atom prop
)
157 /* printf("event to %x\n", event->xselectionrequest.requestor); */
159 ev
.xselection
.type
= SelectionNotify
;
160 ev
.xselection
.serial
= 0;
161 ev
.xselection
.send_event
= True
;
162 ev
.xselection
.display
= event
->xselectionrequest
.display
;
163 ev
.xselection
.requestor
= event
->xselectionrequest
.requestor
;
164 ev
.xselection
.target
= event
->xselectionrequest
.target
;
165 ev
.xselection
.selection
= event
->xselectionrequest
.selection
;
166 ev
.xselection
.property
= prop
;
167 ev
.xselection
.time
= event
->xselectionrequest
.time
;
169 XSendEvent(event
->xany
.display
, event
->xselectionrequest
.requestor
,
171 XFlush(event
->xany
.display
);
176 handleRequestEvent(XEvent
*event
)
178 SelectionHandler
*handler
;
179 WMArrayIterator iter
;
183 WM_ITERATE_ARRAY(selHandlers
, handler
, iter
) {
185 switch (event
->type
) {
187 if (W_VIEW_DRAWABLE(handler
->view
)
188 != event
->xselectionclear
.window
) {
192 handler
->flags
.done_pending
= 1;
193 if (handler
->procs
.selectionLost
)
194 handler
->procs
.selectionLost(handler
->view
,
197 handler
->flags
.done_pending
= 0;
198 handler
->flags
.delete_pending
= 1;
201 case SelectionRequest
:
202 if (W_VIEW_DRAWABLE(handler
->view
)!=event
->xselectionrequest
.owner
) {
206 if (handler
->procs
.convertSelection
!= NULL
207 && handler
->selection
== event
->xselectionrequest
.selection
) {
212 /* they're requesting for something old.. maybe another handler
214 if (event
->xselectionrequest
.time
< handler
->timestamp
215 && event
->xselectionrequest
.time
!= CurrentTime
) {
219 handledRequest
= False
;
221 handler
->flags
.done_pending
= 1;
223 data
= handler
->procs
.convertSelection(handler
->view
,
225 event
->xselectionrequest
.target
,
229 prop
= event
->xselectionrequest
.property
;
230 /* obsolete clients that don't set the property field */
232 prop
= event
->xselectionrequest
.target
;
235 if (writeSelection(event
->xselectionrequest
.display
,
236 event
->xselectionrequest
.requestor
,
238 handledRequest
= True
;
243 notifySelection(event
, (handledRequest
==True
? prop
: None
));
245 if (handler
->procs
.selectionDone
!= NULL
) {
246 handler
->procs
.selectionDone(handler
->view
,
248 event
->xselectionrequest
.target
,
252 handler
->flags
.done_pending
= 0;
258 /* delete handlers */
259 copy
= WMDuplicateArray(selHandlers
);
260 WM_ITERATE_ARRAY(copy
, handler
, iter
) {
261 if (handler
&& handler
->flags
.delete_pending
) {
262 WMDeleteSelectionHandler(handler
->view
, handler
->selection
,
271 getSelectionData(Display
*dpy
, Window win
, Atom where
)
277 unsigned long len
, bytes
;
280 if (XGetWindowProperty(dpy
, win
, where
, 0, MAX_PROPERTY_SIZE
,
281 False
, AnyPropertyType
, &rtype
, &bits
, &len
,
282 &bytes
, &data
)!=Success
) {
288 wdata
= WMCreateDataWithBytesNoCopy(data
, len
*bpi
, (WMFreeDataProc
*)XFree
);
289 WMSetDataFormat(wdata
, bits
);
296 handleNotifyEvent(XEvent
*event
)
298 SelectionCallback
*handler
;
299 WMArrayIterator iter
;
303 WM_ITERATE_ARRAY(selCallbacks
, handler
, iter
) {
305 if (W_VIEW_DRAWABLE(handler
->view
) != event
->xselection
.requestor
306 || handler
->selection
!= event
->xselection
.selection
) {
309 handler
->flags
.done_pending
= 1;
311 if (event
->xselection
.property
== None
) {
314 data
= getSelectionData(event
->xselection
.display
,
315 event
->xselection
.requestor
,
316 event
->xselection
.property
);
319 (*handler
->callback
)(handler
->view
, handler
->selection
,
320 handler
->target
, handler
->timestamp
,
321 handler
->data
, data
);
326 handler
->flags
.done_pending
= 0;
327 handler
->flags
.delete_pending
= 1;
330 /* delete callbacks */
331 copy
= WMDuplicateArray(selCallbacks
);
332 WM_ITERATE_ARRAY(copy
, handler
, iter
) {
333 if (handler
&& handler
->flags
.delete_pending
) {
334 WMDeleteSelectionCallback(handler
->view
, handler
->selection
,
344 W_HandleSelectionEvent(XEvent
*event
)
346 //printf("%d received %d\n", event->xany.window, event->type);
347 if (event
->type
== SelectionNotify
) {
348 handleNotifyEvent(event
);
350 handleRequestEvent(event
);
358 WMCreateSelectionHandler(WMView
*view
, Atom selection
, Time timestamp
,
359 WMSelectionProcs
*procs
, void *cdata
)
361 SelectionHandler
*handler
;
362 Display
*dpy
= W_VIEW_SCREEN(view
)->display
;
364 XSetSelectionOwner(dpy
, selection
, W_VIEW_DRAWABLE(view
), timestamp
);
365 if (XGetSelectionOwner(dpy
, selection
) != W_VIEW_DRAWABLE(view
)) {
369 //printf("created selection handler for %d\n", W_VIEW_DRAWABLE(view));
370 handler
= malloc(sizeof(SelectionHandler
));
374 handler
->view
= view
;
375 handler
->selection
= selection
;
376 handler
->timestamp
= timestamp
;
377 handler
->procs
= *procs
;
378 handler
->data
= cdata
;
379 memset(&handler
->flags
, 0, sizeof(handler
->flags
));
381 if (selHandlers
== NULL
) {
382 selHandlers
= WMCreateArrayWithDestructor(4, wfree
);
385 WMAddToArray(selHandlers
, handler
);
393 WMRequestSelection(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
394 WMSelectionCallback
*callback
, void *cdata
)
396 SelectionCallback
*handler
;
398 if (XGetSelectionOwner(W_VIEW_SCREEN(view
)->display
, selection
) == None
)
401 handler
= wmalloc(sizeof(SelectionCallback
));
403 handler
->view
= view
;
404 handler
->selection
= selection
;
405 handler
->target
= target
;
406 handler
->timestamp
= timestamp
;
407 handler
->callback
= callback
;
408 handler
->data
= cdata
;
409 memset(&handler
->flags
, 0, sizeof(handler
->flags
));
411 if (selCallbacks
== NULL
) {
412 selCallbacks
= WMCreateArrayWithDestructor(4, wfree
);
415 WMAddToArray(selCallbacks
, handler
);
417 if (!XConvertSelection(W_VIEW_SCREEN(view
)->display
, selection
, target
,
418 W_VIEW_SCREEN(view
)->clipboardAtom
,
419 W_VIEW_DRAWABLE(view
), timestamp
)) {