Initial update from my source tree. For 0.52.0
[wmaker-crm.git] / WINGs / selection.c
blob139dc1068f49b00da0505c656b1aa7e31e5b2fcb
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 if (!XChangeProperty(dpy, requestor, property, type, format,
99 PropModeReplace, value, length))
100 return False;
101 XFlush(dpy);
103 return !gotError;
107 static void
108 notifySelection(XEvent *event, Atom prop)
110 XEvent ev;
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,
124 False, 0, &ev);
125 XFlush(event->xany.display);
129 void
130 W_HandleSelectionEvent(XEvent *event)
132 SelectionHandler *handler;
134 handler = selHandlers;
136 while (handler) {
137 if (WMWidgetXID(handler->widget)==event->xany.window
138 /* && handler->selection == event->selection*/) {
140 switch (event->type) {
141 case SelectionClear:
142 if (handler->loseProc)
143 (*handler->loseProc)(handler->widget, handler->selection);
144 break;
146 case SelectionRequest:
147 if (handler->convProc) {
148 Atom atom;
149 void *data;
150 unsigned length;
151 int format;
152 Atom prop;
154 /* they're requesting for something old */
155 if (event->xselectionrequest.time < handler->timestamp
156 && event->xselectionrequest.time != CurrentTime) {
158 notifySelection(event, None);
159 break;
162 handler->flags.done_pending = 1;
164 if (!(*handler->convProc)(handler->widget,
165 handler->selection,
166 event->xselectionrequest.target,
167 &atom, &data, &length, &format)) {
169 notifySelection(event, None);
170 break;
174 prop = event->xselectionrequest.property;
175 /* obsolete clients that don't set the property field */
176 if (prop == None)
177 prop = event->xselectionrequest.target;
179 if (!writeSelection(event->xselectionrequest.display,
180 event->xselectionrequest.requestor,
181 prop, atom, data, length, format)) {
183 free(data);
184 notifySelection(event, None);
185 break;
187 free(data);
189 notifySelection(event, prop);
191 if (handler->doneProc) {
192 (*handler->doneProc)(handler->widget,
193 handler->selection,
194 event->xselectionrequest.target);
197 handler->flags.done_pending = 0;
199 /* in case the handler was deleted from some
200 * callback */
201 if (handler->flags.delete_pending) {
202 WMDeleteSelectionHandler(handler->widget,
203 handler->selection);
206 break;
208 case SelectionNotify:
210 break;
214 handler = handler->next;
221 Bool
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))
232 return False;
234 handler = malloc(sizeof(SelectionHandler));
235 if (!handler)
236 return False;
238 handler->widget = w;
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));
246 if (!selHandlers) {
247 /* first in the queue */
248 handler->next = selHandlers;
249 selHandlers = handler;
250 } else {
251 tmp = selHandlers;
252 while (tmp->next) {
253 tmp = tmp->next;
255 handler->next = tmp->next;
256 tmp->next = handler;
259 return True;
266 static void
267 timeoutHandler(void *data)
269 *(int*)data = 1;
273 char*
274 W_GetTextSelection(WMScreen *scr, Atom selection)
276 int buffer = -1;
278 switch (selection) {
279 case XA_CUT_BUFFER0:
280 buffer = 0;
281 break;
282 case XA_CUT_BUFFER1:
283 buffer = 1;
284 break;
285 case XA_CUT_BUFFER2:
286 buffer = 2;
287 break;
288 case XA_CUT_BUFFER3:
289 buffer = 3;
290 break;
291 case XA_CUT_BUFFER4:
292 buffer = 4;
293 break;
294 case XA_CUT_BUFFER5:
295 buffer = 5;
296 break;
297 case XA_CUT_BUFFER6:
298 buffer = 6;
299 break;
300 case XA_CUT_BUFFER7:
301 buffer = 7;
302 break;
304 if (buffer >= 0) {
305 char *data;
306 int size;
308 data = XFetchBuffer(scr->display, &size, buffer);
310 return data;
311 } else {
312 char *data;
313 int bits;
314 Atom rtype;
315 unsigned long len, bytes;
316 WMHandlerID timer;
317 int timeout = 0;
318 XEvent ev;
320 XDeleteProperty(scr->display, scr->groupLeader, scr->clipboardAtom);
321 XConvertSelection(scr->display, selection, XA_STRING,
322 scr->clipboardAtom, scr->groupLeader,
323 scr->lastEventTime);
325 timer = WMAddTimerHandler(1000, timeoutHandler, &timeout);
327 while (!XCheckTypedWindowEvent(scr->display, scr->groupLeader,
328 SelectionNotify, &ev) && !timeout);
330 if (!timeout) {
331 WMDeleteTimerHandler(timer);
332 } else {
333 wwarning("selection retrieval timed out");
334 return NULL;
337 /* nobody owns the selection or the current owner has
338 * nothing to do with what we need */
339 if (ev.xselection.property == None) {
340 return NULL;
343 if (XGetWindowProperty(scr->display, scr->groupLeader,
344 scr->clipboardAtom, 0, MAX_PROPERTY_SIZE,
345 False, XA_STRING, &rtype, &bits, &len,
346 &bytes, (unsigned char**)&data)!=Success) {
347 return NULL;
349 if (rtype!=XA_STRING || bits!=8) {
350 wwarning("invalid data in text selection");
351 if (data)
352 XFree(data);
353 return NULL;
355 return data;