many bug fixes, finished some delegate code, updated menu file bug from EXEC
[wmaker-crm.git] / WINGs / selection.c
blob821d1ad8368839533e027931457dc06d38e478c8
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.property = prop;
128 ev.xselection.time = event->xselectionrequest.time;
130 XSendEvent(event->xany.display, event->xselectionrequest.requestor,
131 False, 0, &ev);
132 XFlush(event->xany.display);
136 void
137 W_HandleSelectionEvent(XEvent *event)
139 SelectionHandler *handler;
141 handler = selHandlers;
143 while (handler) {
144 if (WMWidgetXID(handler->widget)==event->xany.window
145 /* && handler->selection == event->selection*/) {
147 switch (event->type) {
148 case SelectionClear:
149 if (handler->loseProc)
150 (*handler->loseProc)(handler->widget, handler->selection);
151 break;
153 case SelectionRequest:
154 if (handler->convProc) {
155 Atom atom;
156 void *data;
157 unsigned length;
158 int format;
159 Atom prop;
161 /* they're requesting for something old */
162 if (event->xselectionrequest.time < handler->timestamp
163 && event->xselectionrequest.time != CurrentTime) {
165 notifySelection(event, None);
166 break;
169 handler->flags.done_pending = 1;
171 if (!(*handler->convProc)(handler->widget,
172 handler->selection,
173 event->xselectionrequest.target,
174 &atom, &data, &length, &format)) {
176 notifySelection(event, None);
177 break;
181 prop = event->xselectionrequest.property;
182 /* obsolete clients that don't set the property field */
183 if (prop == None)
184 prop = event->xselectionrequest.target;
186 if (!writeSelection(event->xselectionrequest.display,
187 event->xselectionrequest.requestor,
188 prop, atom, data, length, format)) {
190 free(data);
191 notifySelection(event, None);
192 break;
194 free(data);
196 notifySelection(event, prop);
198 if (handler->doneProc) {
199 (*handler->doneProc)(handler->widget,
200 handler->selection,
201 event->xselectionrequest.target);
204 handler->flags.done_pending = 0;
206 /* in case the handler was deleted from some
207 * callback */
208 if (handler->flags.delete_pending) {
209 WMDeleteSelectionHandler(handler->widget,
210 handler->selection);
213 break;
215 case SelectionNotify:
217 break;
221 handler = handler->next;
228 Bool
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))
239 return False;
241 handler = malloc(sizeof(SelectionHandler));
242 if (!handler)
243 return False;
245 handler->widget = w;
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));
253 if (!selHandlers) {
254 /* first in the queue */
255 handler->next = selHandlers;
256 selHandlers = handler;
257 } else {
258 tmp = selHandlers;
259 while (tmp->next) {
260 tmp = tmp->next;
262 handler->next = tmp->next;
263 tmp->next = handler;
266 return True;
272 static void
273 timeoutHandler(void *data)
275 *(int*)data = 1;
279 static Bool
280 getInternalSelection(WMScreen *scr, Atom selection, Atom target,
281 void **data, unsigned *length)
283 Window owner;
284 SelectionHandler *handler;
287 * Check if the selection is owned by this application and if so,
288 * do the conversion directly.
291 *data = NULL;
293 owner = XGetSelectionOwner(scr->display, selection);
294 if (!owner)
295 return False;
297 handler = selHandlers;
299 while (handler) {
300 if (WMWidgetXID(handler->widget) == owner
301 /* && handler->selection == event->selection*/) {
302 break;
304 handler = handler->next;
307 if (!handler)
308 return False;
310 if (handler->convProc) {
311 Atom atom;
312 int format;
314 if (!(*handler->convProc)(handler->widget, handler->selection,
315 target, &atom, data, length, &format)) {
316 return True;
319 if (handler->doneProc) {
320 (*handler->doneProc)(handler->widget, handler->selection, target);
324 return True;
328 char*
329 W_GetTextSelection(WMScreen *scr, Atom selection)
331 int buffer = -1;
333 switch (selection) {
334 case XA_CUT_BUFFER0:
335 buffer = 0;
336 break;
337 case XA_CUT_BUFFER1:
338 buffer = 1;
339 break;
340 case XA_CUT_BUFFER2:
341 buffer = 2;
342 break;
343 case XA_CUT_BUFFER3:
344 buffer = 3;
345 break;
346 case XA_CUT_BUFFER4:
347 buffer = 4;
348 break;
349 case XA_CUT_BUFFER5:
350 buffer = 5;
351 break;
352 case XA_CUT_BUFFER6:
353 buffer = 6;
354 break;
355 case XA_CUT_BUFFER7:
356 buffer = 7;
357 break;
359 if (buffer >= 0) {
360 char *data;
361 int size;
363 data = XFetchBuffer(scr->display, &size, buffer);
365 return data;
366 } else {
367 char *data;
368 int bits;
369 Atom rtype;
370 unsigned long len, bytes;
371 WMHandlerID timer;
372 int timeout = 0;
373 XEvent ev;
374 unsigned length;
376 XDeleteProperty(scr->display, scr->groupLeader, scr->clipboardAtom);
378 if (getInternalSelection(scr, selection, XA_STRING, (void**)&data,
379 &length)) {
381 return data;
384 XConvertSelection(scr->display, selection, XA_STRING,
385 scr->clipboardAtom, scr->groupLeader,
386 scr->lastEventTime);
388 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
390 while (!XCheckTypedWindowEvent(scr->display, scr->groupLeader,
391 SelectionNotify, &ev) && !timeout);
393 if (!timeout) {
394 WMDeleteTimerHandler(timer);
395 } else {
396 wwarning("selection retrieval timed out");
397 return NULL;
400 /* nobody owns the selection or the current owner has
401 * nothing to do with what we need */
402 if (ev.xselection.property == None) {
403 return NULL;
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) {
410 return NULL;
412 if (rtype!=XA_STRING || bits!=8) {
413 wwarning("invalid data in text selection");
414 if (data)
415 XFree(data);
416 return NULL;
418 return data;