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;
41 WMBag
*selCallbacks
= NULL
;
43 WMBag
*selHandlers
= NULL
;
47 WMDeleteSelectionHandler(WMView
*view
, Atom selection
, Time timestamp
)
49 SelectionHandler
*handler
;
50 Display
*dpy
= W_VIEW_SCREEN(view
)->display
;
51 Window win
= W_VIEW_DRAWABLE(view
);
58 WM_ITERATE_BAG(selHandlers
, handler
, iter
) {
59 if (handler
->view
== view
60 && (handler
->selection
== selection
|| selection
== None
)
61 && (handler
->timestamp
== timestamp
|| timestamp
== CurrentTime
)) {
63 if (handler
->flags
.done_pending
) {
64 handler
->flags
.delete_pending
= 1;
67 WMRemoveFromBag(selHandlers
, handler
);
74 if (XGetSelectionOwner(dpy
, selection
) == win
) {
75 XSetSelectionOwner(dpy
, selection
, None
, timestamp
);
83 WMDeleteSelectionCallback(WMView
*view
, Atom selection
, Time timestamp
)
85 SelectionCallback
*handler
;
91 WM_ITERATE_BAG(selCallbacks
, handler
, iter
) {
92 if (handler
->view
== view
93 && (handler
->selection
== selection
|| selection
== 0)
94 && (handler
->timestamp
== timestamp
|| timestamp
== CurrentTime
)) {
96 if (handler
->flags
.done_pending
) {
97 handler
->flags
.delete_pending
= 1;
100 WMRemoveFromBag(selCallbacks
, handler
);
109 static Bool gotError
= 0;
112 errorHandler(XErrorEvent *error)
119 writeSelection(Display
*dpy
, Window requestor
, Atom property
, Atom type
,
124 format
= WMGetDataFormat(data
);
129 printf("write to %x: %s\n", requestor, XGetAtomName(dpy, property));
134 if (!XChangeProperty(dpy
, requestor
, property
, type
, format
,
135 PropModeReplace
, WMDataBytes(data
),
136 WMGetDataLength(data
)))
139 /* in sgi seems this seems to return void */
140 XChangeProperty(dpy
, requestor
, property
, type
, format
,
141 PropModeReplace
, WMDataBytes(data
), WMGetDataLength(data
));
151 notifySelection(XEvent
*event
, Atom prop
)
155 printf("envent to %x\n", event->xselectionrequest.requestor);
157 ev
.xselection
.type
= SelectionNotify
;
158 ev
.xselection
.serial
= 0;
159 ev
.xselection
.send_event
= True
;
160 ev
.xselection
.display
= event
->xselectionrequest
.display
;
161 ev
.xselection
.requestor
= event
->xselectionrequest
.requestor
;
162 ev
.xselection
.target
= event
->xselectionrequest
.target
;
163 ev
.xselection
.selection
= event
->xselectionrequest
.selection
;
164 ev
.xselection
.property
= prop
;
165 ev
.xselection
.time
= event
->xselectionrequest
.time
;
167 XSendEvent(event
->xany
.display
, event
->xselectionrequest
.requestor
,
169 XFlush(event
->xany
.display
);
175 deleteHandlers(WMBagIterator iter
)
177 SelectionHandler
*handler
;
180 handler
= WMBagFirst(selHandlers
, &iter
);
182 handler
= WMBagNext(selHandlers
, &iter
);
187 deleteHandlers(iter
);
189 if (handler
->flags
.delete_pending
) {
190 WMDeleteSelectionHandler(handler
->view
, handler
->selection
,
198 handleRequestEvent(XEvent
*event
)
200 SelectionHandler
*handler
;
202 Bool handledRequest
= False
;
204 WM_ITERATE_BAG(selHandlers
, handler
, iter
) {
206 switch (event
->type
) {
208 if (W_VIEW_DRAWABLE(handler
->view
)
209 != event
->xselectionclear
.window
) {
213 handler
->flags
.done_pending
= 1;
214 if (handler
->procs
.selectionLost
)
215 handler
->procs
.selectionLost(handler
->view
,
218 handler
->flags
.done_pending
= 0;
219 handler
->flags
.delete_pending
= 1;
222 case SelectionRequest
:
223 if (W_VIEW_DRAWABLE(handler
->view
)
224 != event
->xselectionrequest
.owner
) {
228 if (handler
->procs
.convertSelection
!= NULL
229 && handler
->selection
== event
->xselectionrequest
.selection
) {
234 /* they're requesting for something old.. maybe another handler
236 if (event
->xselectionrequest
.time
< handler
->timestamp
237 && event
->xselectionrequest
.time
!= CurrentTime
) {
241 handler
->flags
.done_pending
= 1;
243 data
= handler
->procs
.convertSelection(handler
->view
,
245 event
->xselectionrequest
.target
,
252 handledRequest
= True
;
255 prop
= event
->xselectionrequest
.property
;
256 /* obsolete clients that don't set the property field */
258 prop
= event
->xselectionrequest
.target
;
260 if (!writeSelection(event
->xselectionrequest
.display
,
261 event
->xselectionrequest
.requestor
,
264 notifySelection(event
, None
);
269 notifySelection(event
, prop
);
271 if (handler
->procs
.selectionDone
!= NULL
) {
272 handler
->procs
.selectionDone(handler
->view
,
274 event
->xselectionrequest
.target
,
278 handler
->flags
.done_pending
= 0;
280 if (!handledRequest
) {
281 notifySelection(event
, None
);
288 deleteHandlers(NULL
);
294 deleteCallbacks(WMBagIterator iter
)
296 SelectionCallback
*handler
;
299 handler
= WMBagFirst(selCallbacks
, &iter
);
301 handler
= WMBagNext(selCallbacks
, &iter
);
306 deleteCallbacks(iter
);
308 if (handler
->flags
.delete_pending
) {
309 WMDeleteSelectionCallback(handler
->view
, handler
->selection
,
318 getSelectionData(Display
*dpy
, Window win
, Atom where
)
324 unsigned long len
, bytes
;
327 if (XGetWindowProperty(dpy
, win
, where
, 0, MAX_PROPERTY_SIZE
,
328 False
, AnyPropertyType
, &rtype
, &bits
, &len
,
329 &bytes
, &data
)!=Success
) {
333 wdata
= WMCreateDataWithBytesNoCopy(data
, len
, (WMFreeDataProc
*)XFree
);
337 WMSetDataFormat(wdata
, bits
);
344 handleNotifyEvent(XEvent
*event
)
346 SelectionCallback
*handler
;
350 WM_ITERATE_BAG(selCallbacks
, handler
, iter
) {
352 if (W_VIEW_DRAWABLE(handler
->view
) != event
->xselection
.requestor
353 && handler
->selection
== event
->xselection
.selection
) {
356 handler
->flags
.done_pending
= 1;
358 if (event
->xselection
.property
== None
) {
361 data
= getSelectionData(event
->xselection
.display
,
362 event
->xselection
.requestor
,
363 event
->xselection
.property
);
366 (*handler
->callback
)(handler
->view
, handler
->selection
,
367 handler
->target
, handler
->timestamp
,
368 handler
->data
, data
);
373 handler
->flags
.done_pending
= 0;
374 handler
->flags
.delete_pending
= 1;
376 deleteCallbacks(NULL
);
382 W_HandleSelectionEvent(XEvent
*event
)
384 if (event
->type
== SelectionNotify
) {
385 handleNotifyEvent(event
);
387 handleRequestEvent(event
);
395 WMCreateSelectionHandler(WMView
*view
, Atom selection
, Time timestamp
,
396 WMSelectionProcs
*procs
, void *cdata
)
398 SelectionHandler
*handler
;
399 Display
*dpy
= W_VIEW_SCREEN(view
)->display
;
401 XSetSelectionOwner(dpy
, selection
, W_VIEW_DRAWABLE(view
), timestamp
);
402 if (XGetSelectionOwner(dpy
, selection
) != W_VIEW_DRAWABLE(view
))
405 handler
= malloc(sizeof(SelectionHandler
));
409 handler
->view
= view
;
410 handler
->selection
= selection
;
411 handler
->timestamp
= timestamp
;
412 handler
->procs
= *procs
;
413 handler
->data
= cdata
;
414 memset(&handler
->flags
, 0, sizeof(handler
->flags
));
416 if (selHandlers
== NULL
) {
417 selHandlers
= WMCreateTreeBag();
420 WMPutInBag(selHandlers
, handler
);
428 WMRequestSelection(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
429 WMSelectionCallback
*callback
, void *cdata
)
431 SelectionCallback
*handler
;
433 if (XGetSelectionOwner(W_VIEW_SCREEN(view
)->display
, selection
) == None
)
436 handler
= wmalloc(sizeof(SelectionCallback
));
438 handler
->view
= view
;
439 handler
->selection
= selection
;
440 handler
->target
= target
;
441 handler
->timestamp
= timestamp
;
442 handler
->callback
= callback
;
443 handler
->data
= cdata
;
444 memset(&handler
->flags
, 0, sizeof(handler
->flags
));
446 if (selCallbacks
== NULL
) {
447 selCallbacks
= WMCreateTreeBag();
450 WMPutInBag(selCallbacks
, handler
);
452 if (!XConvertSelection(W_VIEW_SCREEN(view
)->display
, selection
, target
,
453 W_VIEW_SCREEN(view
)->clipboardAtom
,
454 W_VIEW_DRAWABLE(view
), timestamp
)) {