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
.property
= prop
;
128 ev
.xselection
.time
= event
->xselectionrequest
.time
;
130 XSendEvent(event
->xany
.display
, event
->xselectionrequest
.requestor
,
132 XFlush(event
->xany
.display
);
137 W_HandleSelectionEvent(XEvent
*event
)
139 SelectionHandler
*handler
;
141 handler
= selHandlers
;
144 if (WMWidgetXID(handler
->widget
)==event
->xany
.window
145 /* && handler->selection == event->selection*/) {
147 switch (event
->type
) {
149 if (handler
->loseProc
)
150 (*handler
->loseProc
)(handler
->widget
, handler
->selection
);
153 case SelectionRequest
:
154 if (handler
->convProc
) {
161 /* they're requesting for something old */
162 if (event
->xselectionrequest
.time
< handler
->timestamp
163 && event
->xselectionrequest
.time
!= CurrentTime
) {
165 notifySelection(event
, None
);
169 handler
->flags
.done_pending
= 1;
171 if (!(*handler
->convProc
)(handler
->widget
,
173 event
->xselectionrequest
.target
,
174 &atom
, &data
, &length
, &format
)) {
176 notifySelection(event
, None
);
181 prop
= event
->xselectionrequest
.property
;
182 /* obsolete clients that don't set the property field */
184 prop
= event
->xselectionrequest
.target
;
186 if (!writeSelection(event
->xselectionrequest
.display
,
187 event
->xselectionrequest
.requestor
,
188 prop
, atom
, data
, length
, format
)) {
191 notifySelection(event
, None
);
196 notifySelection(event
, prop
);
198 if (handler
->doneProc
) {
199 (*handler
->doneProc
)(handler
->widget
,
201 event
->xselectionrequest
.target
);
204 handler
->flags
.done_pending
= 0;
206 /* in case the handler was deleted from some
208 if (handler
->flags
.delete_pending
) {
209 WMDeleteSelectionHandler(handler
->widget
,
215 case SelectionNotify
:
221 handler
= handler
->next
;
229 WMCreateSelectionHandler(WMWidget
*w
, Atom selection
, Time timestamp
,
230 WMConvertSelectionProc
*convProc
,
231 WMLoseSelectionProc
*loseProc
,
232 WMSelectionDoneProc
*doneProc
)
234 SelectionHandler
*handler
, *tmp
;
235 Display
*dpy
= WMWidgetScreen(w
)->display
;
237 XSetSelectionOwner(dpy
, selection
, WMWidgetXID(w
), timestamp
);
238 if (XGetSelectionOwner(dpy
, selection
) != WMWidgetXID(w
))
241 handler
= malloc(sizeof(SelectionHandler
));
246 handler
->selection
= selection
;
247 handler
->timestamp
= timestamp
;
248 handler
->convProc
= convProc
;
249 handler
->loseProc
= loseProc
;
250 handler
->doneProc
= doneProc
;
251 memset(&handler
->flags
, 0, sizeof(handler
->flags
));
254 /* first in the queue */
255 handler
->next
= selHandlers
;
256 selHandlers
= handler
;
262 handler
->next
= tmp
->next
;
273 timeoutHandler(void *data
)
280 getInternalSelection(WMScreen
*scr
, Atom selection
, Atom target
,
281 void **data
, unsigned *length
)
284 SelectionHandler
*handler
;
287 * Check if the selection is owned by this application and if so,
288 * do the conversion directly.
293 owner
= XGetSelectionOwner(scr
->display
, selection
);
297 handler
= selHandlers
;
300 if (WMWidgetXID(handler
->widget
) == owner
301 /* && handler->selection == event->selection*/) {
304 handler
= handler
->next
;
310 if (handler
->convProc
) {
314 if (!(*handler
->convProc
)(handler
->widget
, handler
->selection
,
315 target
, &atom
, data
, length
, &format
)) {
319 if (handler
->doneProc
) {
320 (*handler
->doneProc
)(handler
->widget
, handler
->selection
, target
);
329 W_GetTextSelection(WMScreen
*scr
, Atom selection
)
363 data
= XFetchBuffer(scr
->display
, &size
, buffer
);
370 unsigned long len
, bytes
;
376 XDeleteProperty(scr
->display
, scr
->groupLeader
, scr
->clipboardAtom
);
378 if (getInternalSelection(scr
, selection
, XA_STRING
, (void**)&data
,
384 XConvertSelection(scr
->display
, selection
, XA_STRING
,
385 scr
->clipboardAtom
, scr
->groupLeader
,
388 timer
= WMAddTimerHandler(1000, timeoutHandler
, &timeout
);
390 while (!XCheckTypedWindowEvent(scr
->display
, scr
->groupLeader
,
391 SelectionNotify
, &ev
) && !timeout
);
394 WMDeleteTimerHandler(timer
);
396 wwarning("selection retrieval timed out");
400 /* nobody owns the selection or the current owner has
401 * nothing to do with what we need */
402 if (ev
.xselection
.property
== None
) {
406 if (XGetWindowProperty(scr
->display
, scr
->groupLeader
,
407 scr
->clipboardAtom
, 0, MAX_PROPERTY_SIZE
,
408 False
, XA_STRING
, &rtype
, &bits
, &len
,
409 &bytes
, (unsigned char**)&data
)!=Success
) {
412 if (rtype
!=XA_STRING
|| bits
!=8) {
413 wwarning("invalid data in text selection");