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 int 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));
98 if (!XChangeProperty(dpy
, requestor
, property
, type
, format
,
99 PropModeReplace
, value
, length
))
108 notifySelection(XEvent
*event
, Atom prop
)
112 printf("envent to %x\n", event->xselectionrequest.requestor);
114 ev
.xselection
.type
= SelectionNotify
;
115 ev
.xselection
.serial
= 0;
116 ev
.xselection
.send_event
= True
;
117 ev
.xselection
.display
= event
->xselectionrequest
.display
;
118 ev
.xselection
.requestor
= event
->xselectionrequest
.requestor
;
119 ev
.xselection
.target
= event
->xselectionrequest
.target
;
120 ev
.xselection
.property
= prop
;
121 ev
.xselection
.time
= event
->xselectionrequest
.time
;
123 XSendEvent(event
->xany
.display
, event
->xselectionrequest
.requestor
,
125 XFlush(event
->xany
.display
);
130 W_HandleSelectionEvent(XEvent
*event
)
132 SelectionHandler
*handler
;
134 handler
= selHandlers
;
137 if (WMWidgetXID(handler
->widget
)==event
->xany
.window
138 /* && handler->selection == event->selection*/) {
140 switch (event
->type
) {
142 if (handler
->loseProc
)
143 (*handler
->loseProc
)(handler
->widget
, handler
->selection
);
146 case SelectionRequest
:
147 if (handler
->convProc
) {
154 /* they're requesting for something old */
155 if (event
->xselectionrequest
.time
< handler
->timestamp
156 && event
->xselectionrequest
.time
!= CurrentTime
) {
158 notifySelection(event
, None
);
162 handler
->flags
.done_pending
= 1;
164 if (!(*handler
->convProc
)(handler
->widget
,
166 event
->xselectionrequest
.target
,
167 &atom
, &data
, &length
, &format
)) {
169 notifySelection(event
, None
);
174 prop
= event
->xselectionrequest
.property
;
175 /* obsolete clients that don't set the property field */
177 prop
= event
->xselectionrequest
.target
;
179 if (!writeSelection(event
->xselectionrequest
.display
,
180 event
->xselectionrequest
.requestor
,
181 prop
, atom
, data
, length
, format
)) {
184 notifySelection(event
, None
);
189 notifySelection(event
, prop
);
191 if (handler
->doneProc
) {
192 (*handler
->doneProc
)(handler
->widget
,
194 event
->xselectionrequest
.target
);
197 handler
->flags
.done_pending
= 0;
199 /* in case the handler was deleted from some
201 if (handler
->flags
.delete_pending
) {
202 WMDeleteSelectionHandler(handler
->widget
,
208 case SelectionNotify
:
214 handler
= handler
->next
;
222 WMCreateSelectionHandler(WMWidget
*w
, Atom selection
, Time timestamp
,
223 WMConvertSelectionProc
*convProc
,
224 WMLoseSelectionProc
*loseProc
,
225 WMSelectionDoneProc
*doneProc
)
227 SelectionHandler
*handler
, *tmp
;
228 Display
*dpy
= WMWidgetScreen(w
)->display
;
230 XSetSelectionOwner(dpy
, selection
, WMWidgetXID(w
), timestamp
);
231 if (XGetSelectionOwner(dpy
, selection
) != WMWidgetXID(w
))
234 handler
= malloc(sizeof(SelectionHandler
));
239 handler
->selection
= selection
;
240 handler
->timestamp
= timestamp
;
241 handler
->convProc
= convProc
;
242 handler
->loseProc
= loseProc
;
243 handler
->doneProc
= doneProc
;
244 memset(&handler
->flags
, 0, sizeof(handler
->flags
));
247 /* first in the queue */
248 handler
->next
= selHandlers
;
249 selHandlers
= handler
;
255 handler
->next
= tmp
->next
;
267 timeoutHandler(void *data
)
274 W_GetTextSelection(WMScreen
*scr
, Atom selection
)
308 data
= XFetchBuffer(scr
->display
, &size
, buffer
);
315 unsigned long len
, bytes
;
320 XDeleteProperty(scr
->display
, scr
->groupLeader
, scr
->clipboardAtom
);
321 XConvertSelection(scr
->display
, selection
, XA_STRING
,
322 scr
->clipboardAtom
, scr
->groupLeader
,
325 timer
= WMAddTimerHandler(1000, timeoutHandler
, &timeout
);
327 while (!XCheckTypedWindowEvent(scr
->display
, scr
->groupLeader
,
328 SelectionNotify
, &ev
) && !timeout
);
331 WMDeleteTimerHandler(timer
);
333 wwarning("selection retrieval timed out");
337 /* nobody owns the selection or the current owner has
338 * nothing to do with what we need */
339 if (ev
.xselection
.property
== None
) {
343 if (XGetWindowProperty(scr
->display
, scr
->groupLeader
,
344 scr
->clipboardAtom
, 0, MAX_PROPERTY_SIZE
,
345 False
, XA_STRING
, &rtype
, &bits
, &len
,
346 &bytes
, &data
)!=Success
) {
349 if (rtype
!=XA_STRING
|| bits
!=8) {
350 wwarning("invalid data in text selection");