9 #define MAX_PROPERTY_SIZE 8*1024
12 typedef struct SelectionHandler
{
16 WMConvertSelectionProc
*convProc
;
17 WMLoseSelectionProc
*loseProc
;
18 WMSelectionDoneProc
*doneProc
;
21 unsigned delete_pending
:1;
22 unsigned done_pending
:1;
25 struct SelectionHandler
*next
;
29 static SelectionHandler
*selHandlers
= NULL
;
33 WMDeleteSelectionHandler(WMWidget
*widget
, Atom selection
)
35 SelectionHandler
*handler
, *tmp
;
36 Display
*dpy
= WMWidgetScreen(widget
)->display
;
37 Window win
= WMWidgetXID(widget
);
45 if (tmp
->widget
== widget
) {
47 if (tmp
->flags
.done_pending
) {
48 tmp
->flags
.delete_pending
= 1;
51 selHandlers
= tmp
->next
;
52 timestamp
= tmp
->timestamp
;
56 if (tmp
->next
->widget
== widget
) {
58 if (tmp
->next
->flags
.done_pending
) {
59 tmp
->next
->flags
.delete_pending
= 1;
63 tmp
->next
= handler
->next
;
64 timestamp
= handler
->timestamp
;
73 if (XGetSelectionOwner(dpy
, selection
) == win
) {
74 XSetSelectionOwner(dpy
, selection
, None
, timestamp
);
80 static Bool gotError
= 0;
83 errorHandler(XErrorEvent *error)
90 writeSelection(Display
*dpy
, Window requestor
, Atom property
, Atom type
,
91 void *value
, long length
, int format
)
94 printf("write to %x: %s\n", requestor, XGetAtomName(dpy, property));
99 if (!XChangeProperty(dpy
, requestor
, property
, type
, format
,
100 PropModeReplace
, value
, length
))
103 /* in sgi seems this seems to return void */
104 XChangeProperty(dpy
, requestor
, property
, type
, format
,
105 PropModeReplace
, value
, length
);
115 notifySelection(XEvent
*event
, Atom prop
)
119 printf("envent to %x\n", event->xselectionrequest.requestor);
121 ev
.xselection
.type
= SelectionNotify
;
122 ev
.xselection
.serial
= 0;
123 ev
.xselection
.send_event
= True
;
124 ev
.xselection
.display
= event
->xselectionrequest
.display
;
125 ev
.xselection
.requestor
= event
->xselectionrequest
.requestor
;
126 ev
.xselection
.target
= event
->xselectionrequest
.target
;
127 ev
.xselection
.selection
= event
->xselectionrequest
.selection
;
128 ev
.xselection
.property
= prop
;
129 ev
.xselection
.time
= event
->xselectionrequest
.time
;
131 XSendEvent(event
->xany
.display
, event
->xselectionrequest
.requestor
,
133 XFlush(event
->xany
.display
);
138 W_HandleSelectionEvent(XEvent
*event
)
140 SelectionHandler
*handler
;
142 handler
= selHandlers
;
145 if (WMWidgetXID(handler
->widget
)==event
->xany
.window
146 /* && handler->selection == event->selection*/) {
148 switch (event
->type
) {
150 if (handler
->loseProc
)
151 (*handler
->loseProc
)(handler
->widget
, handler
->selection
);
154 case SelectionRequest
:
155 if (handler
->convProc
) {
162 /* they're requesting for something old */
163 if (event
->xselectionrequest
.time
< handler
->timestamp
164 && event
->xselectionrequest
.time
!= CurrentTime
) {
166 notifySelection(event
, None
);
170 handler
->flags
.done_pending
= 1;
172 if (!(*handler
->convProc
)(handler
->widget
,
174 event
->xselectionrequest
.target
,
175 &atom
, &data
, &length
, &format
)) {
177 notifySelection(event
, None
);
182 prop
= event
->xselectionrequest
.property
;
183 /* obsolete clients that don't set the property field */
185 prop
= event
->xselectionrequest
.target
;
187 if (!writeSelection(event
->xselectionrequest
.display
,
188 event
->xselectionrequest
.requestor
,
189 prop
, atom
, data
, length
, format
)) {
192 notifySelection(event
, None
);
197 notifySelection(event
, prop
);
199 if (handler
->doneProc
) {
200 (*handler
->doneProc
)(handler
->widget
,
202 event
->xselectionrequest
.target
);
205 handler
->flags
.done_pending
= 0;
207 /* in case the handler was deleted from some
209 if (handler
->flags
.delete_pending
) {
210 WMDeleteSelectionHandler(handler
->widget
,
216 case SelectionNotify
:
222 handler
= handler
->next
;
230 WMCreateSelectionHandler(WMWidget
*w
, Atom selection
, Time timestamp
,
231 WMConvertSelectionProc
*convProc
,
232 WMLoseSelectionProc
*loseProc
,
233 WMSelectionDoneProc
*doneProc
)
235 SelectionHandler
*handler
, *tmp
;
236 Display
*dpy
= WMWidgetScreen(w
)->display
;
238 XSetSelectionOwner(dpy
, selection
, WMWidgetXID(w
), timestamp
);
239 if (XGetSelectionOwner(dpy
, selection
) != WMWidgetXID(w
))
242 handler
= malloc(sizeof(SelectionHandler
));
247 handler
->selection
= selection
;
248 handler
->timestamp
= timestamp
;
249 handler
->convProc
= convProc
;
250 handler
->loseProc
= loseProc
;
251 handler
->doneProc
= doneProc
;
252 memset(&handler
->flags
, 0, sizeof(handler
->flags
));
255 /* first in the queue */
256 handler
->next
= selHandlers
;
257 selHandlers
= handler
;
263 handler
->next
= tmp
->next
;
274 timeoutHandler(void *data
)
281 getInternalSelection(WMScreen
*scr
, Atom selection
, Atom target
,
282 void **data
, unsigned *length
)
285 SelectionHandler
*handler
;
288 * Check if the selection is owned by this application and if so,
289 * do the conversion directly.
294 owner
= XGetSelectionOwner(scr
->display
, selection
);
298 handler
= selHandlers
;
301 if (WMWidgetXID(handler
->widget
) == owner
302 /* && handler->selection == event->selection*/) {
305 handler
= handler
->next
;
311 if (handler
->convProc
) {
315 if (!(*handler
->convProc
)(handler
->widget
, handler
->selection
,
316 target
, &atom
, data
, length
, &format
)) {
320 if (handler
->doneProc
) {
321 (*handler
->doneProc
)(handler
->widget
, handler
->selection
, target
);
330 W_GetTextSelection(WMScreen
*scr
, Atom selection
)
364 data
= XFetchBuffer(scr
->display
, &size
, buffer
);
371 unsigned long len
, bytes
;
377 XDeleteProperty(scr
->display
, scr
->groupLeader
, scr
->clipboardAtom
);
379 if (getInternalSelection(scr
, selection
, XA_STRING
, (void**)&data
,
385 XConvertSelection(scr
->display
, selection
, XA_STRING
,
386 scr
->clipboardAtom
, scr
->groupLeader
,
389 timer
= WMAddTimerHandler(1000, timeoutHandler
, &timeout
);
391 while (!XCheckTypedWindowEvent(scr
->display
, scr
->groupLeader
,
392 SelectionNotify
, &ev
) && !timeout
);
395 WMDeleteTimerHandler(timer
);
397 wwarning("selection retrieval timed out");
401 /* nobody owns the selection or the current owner has
402 * nothing to do with what we need */
403 if (ev
.xselection
.property
== None
) {
407 if (XGetWindowProperty(scr
->display
, scr
->groupLeader
,
408 scr
->clipboardAtom
, 0, MAX_PROPERTY_SIZE
,
409 False
, XA_STRING
, &rtype
, &bits
, &len
,
410 &bytes
, (unsigned char**)&data
)!=Success
) {
413 if (rtype
!=XA_STRING
|| bits
!=8) {
414 wwarning("invalid data in text selection");