fix a typo bug?
[wmaker-crm.git] / WINGs / selection.c
blobc242f3b2b66e235bf1db06c8f27594e17f238dbd
3 #include <stdlib.h>
5 #include <X11/Xatom.h>
7 #include "WINGsP.h"
9 #define MAX_PROPERTY_SIZE 8*1024
12 typedef struct SelectionHandler {
13 WMWidget *widget;
14 Atom selection;
15 Time timestamp;
16 WMConvertSelectionProc *convProc;
17 WMLoseSelectionProc *loseProc;
18 WMSelectionDoneProc *doneProc;
20 struct {
21 unsigned delete_pending:1;
22 unsigned done_pending:1;
23 } flags;
25 struct SelectionHandler *next;
26 } SelectionHandler;
29 static SelectionHandler *selHandlers = NULL;
32 void
33 WMDeleteSelectionHandler(WMWidget *widget, Atom selection)
35 SelectionHandler *handler, *tmp;
36 Display *dpy = WMWidgetScreen(widget)->display;
37 Window win = WMWidgetXID(widget);
38 Time timestamp;
40 if (!selHandlers)
41 return;
43 tmp = selHandlers;
45 if (tmp->widget == widget) {
47 if (tmp->flags.done_pending) {
48 tmp->flags.delete_pending = 1;
49 return;
51 selHandlers = tmp->next;
52 timestamp = tmp->timestamp;
53 free(tmp);
54 } else {
55 while (tmp->next) {
56 if (tmp->next->widget == widget) {
58 if (tmp->next->flags.done_pending) {
59 tmp->next->flags.delete_pending = 1;
60 return;
62 handler = tmp->next;
63 tmp->next = handler->next;
64 timestamp = handler->timestamp;
65 free(handler);
66 break;
68 tmp = tmp->next;
72 XGrabServer(dpy);
73 if (XGetSelectionOwner(dpy, selection) == win) {
74 XSetSelectionOwner(dpy, selection, None, timestamp);
76 XUngrabServer(dpy);
80 static Bool gotError = 0;
82 static int
83 errorHandler(XErrorEvent *error)
85 return 0;
89 static Bool
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));
96 gotError = False;
98 #ifndef __sgi
99 if (!XChangeProperty(dpy, requestor, property, type, format,
100 PropModeReplace, value, length))
101 return False;
102 #else
103 /* in sgi seems this seems to return void */
104 XChangeProperty(dpy, requestor, property, type, format,
105 PropModeReplace, value, length);
106 #endif
108 XFlush(dpy);
110 return !gotError;
114 static void
115 notifySelection(XEvent *event, Atom prop)
117 XEvent ev;
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,
132 False, 0, &ev);
133 XFlush(event->xany.display);
137 void
138 W_HandleSelectionEvent(XEvent *event)
140 SelectionHandler *handler;
142 handler = selHandlers;
144 while (handler) {
145 if (WMWidgetXID(handler->widget)==event->xany.window
146 /* && handler->selection == event->selection*/) {
148 switch (event->type) {
149 case SelectionClear:
150 if (handler->loseProc)
151 (*handler->loseProc)(handler->widget, handler->selection);
152 break;
154 case SelectionRequest:
155 if (handler->convProc) {
156 Atom atom;
157 void *data;
158 unsigned length;
159 int format;
160 Atom prop;
162 /* they're requesting for something old */
163 if (event->xselectionrequest.time < handler->timestamp
164 && event->xselectionrequest.time != CurrentTime) {
166 notifySelection(event, None);
167 break;
170 handler->flags.done_pending = 1;
172 if (!(*handler->convProc)(handler->widget,
173 handler->selection,
174 event->xselectionrequest.target,
175 &atom, &data, &length, &format)) {
177 notifySelection(event, None);
178 break;
182 prop = event->xselectionrequest.property;
183 /* obsolete clients that don't set the property field */
184 if (prop == None)
185 prop = event->xselectionrequest.target;
187 if (!writeSelection(event->xselectionrequest.display,
188 event->xselectionrequest.requestor,
189 prop, atom, data, length, format)) {
191 free(data);
192 notifySelection(event, None);
193 break;
195 free(data);
197 notifySelection(event, prop);
199 if (handler->doneProc) {
200 (*handler->doneProc)(handler->widget,
201 handler->selection,
202 event->xselectionrequest.target);
205 handler->flags.done_pending = 0;
207 /* in case the handler was deleted from some
208 * callback */
209 if (handler->flags.delete_pending) {
210 WMDeleteSelectionHandler(handler->widget,
211 handler->selection);
214 break;
216 case SelectionNotify:
218 break;
222 handler = handler->next;
229 Bool
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))
240 return False;
242 handler = malloc(sizeof(SelectionHandler));
243 if (!handler)
244 return False;
246 handler->widget = w;
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));
254 if (!selHandlers) {
255 /* first in the queue */
256 handler->next = selHandlers;
257 selHandlers = handler;
258 } else {
259 tmp = selHandlers;
260 while (tmp->next) {
261 tmp = tmp->next;
263 handler->next = tmp->next;
264 tmp->next = handler;
267 return True;
273 static void
274 timeoutHandler(void *data)
276 *(int*)data = 1;
280 static Bool
281 getInternalSelection(WMScreen *scr, Atom selection, Atom target,
282 void **data, unsigned *length)
284 Window owner;
285 SelectionHandler *handler;
288 * Check if the selection is owned by this application and if so,
289 * do the conversion directly.
292 *data = NULL;
294 owner = XGetSelectionOwner(scr->display, selection);
295 if (!owner)
296 return False;
298 handler = selHandlers;
300 while (handler) {
301 if (WMWidgetXID(handler->widget) == owner
302 /* && handler->selection == event->selection*/) {
303 break;
305 handler = handler->next;
308 if (!handler)
309 return False;
311 if (handler->convProc) {
312 Atom atom;
313 int format;
315 if (!(*handler->convProc)(handler->widget, handler->selection,
316 target, &atom, data, length, &format)) {
317 return True;
320 if (handler->doneProc) {
321 (*handler->doneProc)(handler->widget, handler->selection, target);
325 return True;
329 char*
330 W_GetTextSelection(WMScreen *scr, Atom selection)
332 int buffer = -1;
334 switch (selection) {
335 case XA_CUT_BUFFER0:
336 buffer = 0;
337 break;
338 case XA_CUT_BUFFER1:
339 buffer = 1;
340 break;
341 case XA_CUT_BUFFER2:
342 buffer = 2;
343 break;
344 case XA_CUT_BUFFER3:
345 buffer = 3;
346 break;
347 case XA_CUT_BUFFER4:
348 buffer = 4;
349 break;
350 case XA_CUT_BUFFER5:
351 buffer = 5;
352 break;
353 case XA_CUT_BUFFER6:
354 buffer = 6;
355 break;
356 case XA_CUT_BUFFER7:
357 buffer = 7;
358 break;
360 if (buffer >= 0) {
361 char *data;
362 int size;
364 data = XFetchBuffer(scr->display, &size, buffer);
366 return data;
367 } else {
368 char *data;
369 int bits;
370 Atom rtype;
371 unsigned long len, bytes;
372 WMHandlerID timer;
373 int timeout = 0;
374 XEvent ev;
375 unsigned length;
377 XDeleteProperty(scr->display, scr->groupLeader, scr->clipboardAtom);
379 if (getInternalSelection(scr, selection, XA_STRING, (void**)&data,
380 &length)) {
382 return data;
385 XConvertSelection(scr->display, selection, XA_STRING,
386 scr->clipboardAtom, scr->groupLeader,
387 scr->lastEventTime);
389 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
391 while (!XCheckTypedWindowEvent(scr->display, scr->groupLeader,
392 SelectionNotify, &ev) && !timeout);
394 if (!timeout) {
395 WMDeleteTimerHandler(timer);
396 } else {
397 wwarning("selection retrieval timed out");
398 return NULL;
401 /* nobody owns the selection or the current owner has
402 * nothing to do with what we need */
403 if (ev.xselection.property == None) {
404 return NULL;
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) {
411 return NULL;
413 if (rtype!=XA_STRING || bits!=8) {
414 wwarning("invalid data in text selection");
415 if (data)
416 XFree(data);
417 return NULL;
419 return data;