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 WMArray
*selCallbacks
= NULL
;
43 WMArray
*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_ARRAY(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 WMRemoveFromArray(selHandlers
, handler
);
73 if (XGetSelectionOwner(dpy
, selection
) == win
) {
74 XSetSelectionOwner(dpy
, selection
, None
, timestamp
);
82 WMDeleteSelectionCallback(WMView
*view
, Atom selection
, Time timestamp
)
84 SelectionCallback
*handler
;
90 WM_ITERATE_ARRAY(selCallbacks
, handler
, iter
) {
91 if (handler
->view
== view
92 && (handler
->selection
== selection
|| selection
== None
)
93 && (handler
->timestamp
== timestamp
|| timestamp
== CurrentTime
)) {
95 if (handler
->flags
.done_pending
) {
96 handler
->flags
.delete_pending
= 1;
99 WMRemoveFromArray(selCallbacks
, handler
);
107 static Bool gotError
= 0;
110 errorHandler(XErrorEvent *error)
117 writeSelection(Display
*dpy
, Window requestor
, Atom property
, Atom type
,
122 format
= WMGetDataFormat(data
);
128 /* printf("write to %x: %s\n", requestor, XGetAtomName(dpy, property)); */
133 if (!XChangeProperty(dpy
, requestor
, property
, type
, format
,
134 PropModeReplace
, WMDataBytes(data
),
135 WMGetDataLength(data
)/bpi
))
138 /* in sgi seems this seems to return void */
139 XChangeProperty(dpy
, requestor
, property
, type
, format
,
140 PropModeReplace
, WMDataBytes(data
),
141 WMGetDataLength(data
)/bpi
);
151 notifySelection(XEvent
*event
, Atom prop
)
155 /* printf("event 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
);
174 handleRequestEvent(XEvent
*event
)
176 SelectionHandler
*handler
;
177 WMArrayIterator iter
;
181 WM_ITERATE_ARRAY(selHandlers
, handler
, iter
) {
183 switch (event
->type
) {
185 if (W_VIEW_DRAWABLE(handler
->view
)
186 != event
->xselectionclear
.window
) {
190 handler
->flags
.done_pending
= 1;
191 if (handler
->procs
.selectionLost
)
192 handler
->procs
.selectionLost(handler
->view
,
195 handler
->flags
.done_pending
= 0;
196 handler
->flags
.delete_pending
= 1;
199 case SelectionRequest
:
200 if (W_VIEW_DRAWABLE(handler
->view
)!=event
->xselectionrequest
.owner
) {
204 if (handler
->procs
.convertSelection
!= NULL
205 && handler
->selection
== event
->xselectionrequest
.selection
) {
210 /* they're requesting for something old.. maybe another handler
212 if (event
->xselectionrequest
.time
< handler
->timestamp
213 && event
->xselectionrequest
.time
!= CurrentTime
) {
217 handledRequest
= False
;
219 handler
->flags
.done_pending
= 1;
221 data
= handler
->procs
.convertSelection(handler
->view
,
223 event
->xselectionrequest
.target
,
227 prop
= event
->xselectionrequest
.property
;
228 /* obsolete clients that don't set the property field */
230 prop
= event
->xselectionrequest
.target
;
233 if (writeSelection(event
->xselectionrequest
.display
,
234 event
->xselectionrequest
.requestor
,
236 handledRequest
= True
;
241 notifySelection(event
, (handledRequest
==True
? prop
: None
));
243 if (handler
->procs
.selectionDone
!= NULL
) {
244 handler
->procs
.selectionDone(handler
->view
,
246 event
->xselectionrequest
.target
,
250 handler
->flags
.done_pending
= 0;
256 /* delete handlers */
257 copy
= WMDuplicateArray(selHandlers
);
258 WM_ITERATE_ARRAY(copy
, handler
, iter
) {
259 if (handler
&& handler
->flags
.delete_pending
) {
260 WMDeleteSelectionHandler(handler
->view
, handler
->selection
,
269 getSelectionData(Display
*dpy
, Window win
, Atom where
)
275 unsigned long len
, bytes
;
278 if (XGetWindowProperty(dpy
, win
, where
, 0, MAX_PROPERTY_SIZE
,
279 False
, AnyPropertyType
, &rtype
, &bits
, &len
,
280 &bytes
, &data
)!=Success
) {
286 wdata
= WMCreateDataWithBytesNoCopy(data
, len
*bpi
, (WMFreeDataProc
*)XFree
);
287 WMSetDataFormat(wdata
, bits
);
294 handleNotifyEvent(XEvent
*event
)
296 SelectionCallback
*handler
;
297 WMArrayIterator iter
;
301 WM_ITERATE_ARRAY(selCallbacks
, handler
, iter
) {
303 if (W_VIEW_DRAWABLE(handler
->view
) != event
->xselection
.requestor
304 || handler
->selection
!= event
->xselection
.selection
) {
307 handler
->flags
.done_pending
= 1;
309 if (event
->xselection
.property
== None
) {
312 data
= getSelectionData(event
->xselection
.display
,
313 event
->xselection
.requestor
,
314 event
->xselection
.property
);
317 (*handler
->callback
)(handler
->view
, handler
->selection
,
318 handler
->target
, handler
->timestamp
,
319 handler
->data
, data
);
324 handler
->flags
.done_pending
= 0;
325 handler
->flags
.delete_pending
= 1;
328 /* delete callbacks */
329 copy
= WMDuplicateArray(selCallbacks
);
330 WM_ITERATE_ARRAY(copy
, handler
, iter
) {
331 if (handler
&& handler
->flags
.delete_pending
) {
332 WMDeleteSelectionCallback(handler
->view
, handler
->selection
,
342 W_HandleSelectionEvent(XEvent
*event
)
344 if (event
->type
== SelectionNotify
) {
345 handleNotifyEvent(event
);
347 handleRequestEvent(event
);
355 WMCreateSelectionHandler(WMView
*view
, Atom selection
, Time timestamp
,
356 WMSelectionProcs
*procs
, void *cdata
)
358 SelectionHandler
*handler
;
359 Display
*dpy
= W_VIEW_SCREEN(view
)->display
;
361 XSetSelectionOwner(dpy
, selection
, W_VIEW_DRAWABLE(view
), timestamp
);
362 if (XGetSelectionOwner(dpy
, selection
) != W_VIEW_DRAWABLE(view
))
365 handler
= malloc(sizeof(SelectionHandler
));
369 handler
->view
= view
;
370 handler
->selection
= selection
;
371 handler
->timestamp
= timestamp
;
372 handler
->procs
= *procs
;
373 handler
->data
= cdata
;
374 memset(&handler
->flags
, 0, sizeof(handler
->flags
));
376 if (selHandlers
== NULL
) {
377 selHandlers
= WMCreateArrayWithDestructor(4, wfree
);
380 WMAddToArray(selHandlers
, handler
);
388 WMRequestSelection(WMView
*view
, Atom selection
, Atom target
, Time timestamp
,
389 WMSelectionCallback
*callback
, void *cdata
)
391 SelectionCallback
*handler
;
393 if (XGetSelectionOwner(W_VIEW_SCREEN(view
)->display
, selection
) == None
)
396 handler
= wmalloc(sizeof(SelectionCallback
));
398 handler
->view
= view
;
399 handler
->selection
= selection
;
400 handler
->target
= target
;
401 handler
->timestamp
= timestamp
;
402 handler
->callback
= callback
;
403 handler
->data
= cdata
;
404 memset(&handler
->flags
, 0, sizeof(handler
->flags
));
406 if (selCallbacks
== NULL
) {
407 selCallbacks
= WMCreateArrayWithDestructor(4, wfree
);
410 WMAddToArray(selCallbacks
, handler
);
412 if (!XConvertSelection(W_VIEW_SCREEN(view
)->display
, selection
, target
,
413 W_VIEW_SCREEN(view
)->clipboardAtom
,
414 W_VIEW_DRAWABLE(view
), timestamp
)) {