- Really fixed problem with keyboard shortcuts executed an every screen for
[wmaker-crm.git] / WINGs / selection.c
blob1f52a770714f7566b59b8e2866e1d0f879e2486d
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 WMView *view;
14 Atom selection;
15 Time timestamp;
16 WMSelectionProcs procs;
17 void *data;
19 struct {
20 unsigned delete_pending:1;
21 unsigned done_pending:1;
22 } flags;
23 } SelectionHandler;
26 typedef struct SelectionCallback {
27 WMView *view;
28 Atom selection;
29 Atom target;
30 Time timestamp;
31 WMSelectionCallback *callback;
32 void *data;
34 struct {
35 unsigned delete_pending:1;
36 unsigned done_pending:1;
37 } flags;
38 } SelectionCallback;
41 WMArray *selCallbacks = NULL;
43 WMArray *selHandlers = NULL;
46 void
47 WMDeleteSelectionHandler(WMView *view, Atom selection, Time timestamp)
49 SelectionHandler *handler;
50 Display *dpy = W_VIEW_SCREEN(view)->display;
51 Window win = W_VIEW_DRAWABLE(view);
52 WMArrayIterator iter;
54 if (!selHandlers)
55 return;
58 WM_ITERATE_ARRAY(selHandlers, handler, iter) {
59 if (handler->view == view
60 && (handler->selection == selection || selection == None)
61 && (handler->timestamp == timestamp || timestamp == CurrentTime)) {
63 if (handler->flags.done_pending) {
64 handler->flags.delete_pending = 1;
65 return;
67 WMRemoveFromArray(selHandlers, handler);
68 break;
72 XGrabServer(dpy);
73 if (XGetSelectionOwner(dpy, selection) == win) {
74 XSetSelectionOwner(dpy, selection, None, timestamp);
76 XUngrabServer(dpy);
81 void
82 WMDeleteSelectionCallback(WMView *view, Atom selection, Time timestamp)
84 SelectionCallback *handler;
85 WMArrayIterator iter;
87 if (!selCallbacks)
88 return;
90 WM_ITERATE_ARRAY(selCallbacks, handler, iter) {
91 if (handler->view == view
92 && (handler->selection == selection || selection == 0)
93 && (handler->timestamp == timestamp || timestamp == CurrentTime)) {
95 if (handler->flags.done_pending) {
96 handler->flags.delete_pending = 1;
97 return;
99 WMRemoveFromArray(selCallbacks, handler);
100 break;
107 static Bool gotError = 0;
109 static int
110 errorHandler(XErrorEvent *error)
112 return 0;
116 static Bool
117 writeSelection(Display *dpy, Window requestor, Atom property, Atom type,
118 WMData *data)
120 int format, bpi;
122 format = WMGetDataFormat(data);
123 if (format == 0)
124 format = 8;
126 bpi = format/8;
128 /* printf("write to %x: %s\n", requestor, XGetAtomName(dpy, property)); */
130 gotError = False;
132 #ifndef __sgi
133 if (!XChangeProperty(dpy, requestor, property, type, format,
134 PropModeReplace, WMDataBytes(data),
135 WMGetDataLength(data)/bpi))
136 return False;
137 #else
138 /* in sgi seems this seems to return void */
139 XChangeProperty(dpy, requestor, property, type, format,
140 PropModeReplace, WMDataBytes(data),
141 WMGetDataLength(data)/bpi);
142 #endif
144 XFlush(dpy);
146 return !gotError;
150 static void
151 notifySelection(XEvent *event, Atom prop)
153 XEvent ev;
155 /* printf("envent to %x\n", event->xselectionrequest.requestor); */
157 ev.xselection.type = SelectionNotify;
158 ev.xselection.serial = 0;
159 ev.xselection.send_event = True;
160 ev.xselection.display = event->xselectionrequest.display;
161 ev.xselection.requestor = event->xselectionrequest.requestor;
162 ev.xselection.target = event->xselectionrequest.target;
163 ev.xselection.selection = event->xselectionrequest.selection;
164 ev.xselection.property = prop;
165 ev.xselection.time = event->xselectionrequest.time;
167 XSendEvent(event->xany.display, event->xselectionrequest.requestor,
168 False, 0, &ev);
169 XFlush(event->xany.display);
173 static void
174 handleRequestEvent(XEvent *event)
176 SelectionHandler *handler;
177 WMArrayIterator iter;
178 WMArray *copy;
179 Bool handledRequest = False;
181 WM_ITERATE_ARRAY(selHandlers, handler, iter) {
183 switch (event->type) {
184 case SelectionClear:
185 if (W_VIEW_DRAWABLE(handler->view)
186 != event->xselectionclear.window) {
187 break;
190 handler->flags.done_pending = 1;
191 if (handler->procs.selectionLost)
192 handler->procs.selectionLost(handler->view,
193 handler->selection,
194 handler->data);
195 handler->flags.done_pending = 0;
196 handler->flags.delete_pending = 1;
197 break;
199 case SelectionRequest:
200 if (W_VIEW_DRAWABLE(handler->view)
201 != event->xselectionrequest.owner) {
202 break;
205 if (handler->procs.convertSelection != NULL
206 && handler->selection == event->xselectionrequest.selection) {
207 Atom atom;
208 WMData *data;
209 Atom prop;
211 /* they're requesting for something old.. maybe another handler
212 * can handle it */
213 if (event->xselectionrequest.time < handler->timestamp
214 && event->xselectionrequest.time != CurrentTime) {
215 break;
218 handler->flags.done_pending = 1;
220 data = handler->procs.convertSelection(handler->view,
221 handler->selection,
222 event->xselectionrequest.target,
223 handler->data,
224 &atom);
225 if (data == NULL) {
226 break;
229 handledRequest = True;
232 prop = event->xselectionrequest.property;
233 /* obsolete clients that don't set the property field */
234 if (prop == None)
235 prop = event->xselectionrequest.target;
237 if (!writeSelection(event->xselectionrequest.display,
238 event->xselectionrequest.requestor,
239 prop, atom, data)) {
240 WMReleaseData(data);
241 notifySelection(event, None);
242 break;
244 WMReleaseData(data);
246 notifySelection(event, prop);
248 if (handler->procs.selectionDone != NULL) {
249 handler->procs.selectionDone(handler->view,
250 handler->selection,
251 event->xselectionrequest.target,
252 handler->data);
255 handler->flags.done_pending = 0;
257 if (!handledRequest) {
258 notifySelection(event, None);
261 break;
265 /* delete handlers */
266 copy = WMDuplicateArray(selHandlers);
267 WM_ITERATE_ARRAY(copy, handler, iter) {
268 if (handler && handler->flags.delete_pending) {
269 WMDeleteSelectionHandler(handler->view, handler->selection,
270 handler->timestamp);
273 WMFreeArray(copy);
277 static WMData*
278 getSelectionData(Display *dpy, Window win, Atom where)
280 WMData *wdata;
281 unsigned char *data;
282 Atom rtype;
283 unsigned bits, bpi;
284 unsigned long len, bytes;
287 if (XGetWindowProperty(dpy, win, where, 0, MAX_PROPERTY_SIZE,
288 False, AnyPropertyType, &rtype, &bits, &len,
289 &bytes, &data)!=Success) {
290 return NULL;
293 bpi = bits/8;
295 wdata = WMCreateDataWithBytesNoCopy(data, len*bpi, (WMFreeDataProc*)XFree);
296 if (wdata == NULL) {
297 return NULL;
299 WMSetDataFormat(wdata, bits);
301 return wdata;
305 static void
306 handleNotifyEvent(XEvent *event)
308 SelectionCallback *handler;
309 WMArrayIterator iter;
310 WMArray *copy;
311 WMData *data;
313 WM_ITERATE_ARRAY(selCallbacks, handler, iter) {
315 if (W_VIEW_DRAWABLE(handler->view) != event->xselection.requestor
316 || handler->selection != event->xselection.selection) {
317 continue;
319 handler->flags.done_pending = 1;
321 if (event->xselection.property == None) {
322 data = NULL;
323 } else {
324 data = getSelectionData(event->xselection.display,
325 event->xselection.requestor,
326 event->xselection.property);
329 (*handler->callback)(handler->view, handler->selection,
330 handler->target, handler->timestamp,
331 handler->data, data);
333 if (data != NULL) {
334 WMReleaseData(data);
336 handler->flags.done_pending = 0;
337 handler->flags.delete_pending = 1;
340 /* delete callbacks */
341 copy = WMDuplicateArray(selCallbacks);
342 WM_ITERATE_ARRAY(copy, handler, iter) {
343 if (handler && handler->flags.delete_pending) {
344 WMDeleteSelectionCallback(handler->view, handler->selection,
345 handler->timestamp);
348 WMFreeArray(copy);
353 void
354 W_HandleSelectionEvent(XEvent *event)
356 if (event->type == SelectionNotify) {
357 handleNotifyEvent(event);
358 } else {
359 handleRequestEvent(event);
366 Bool
367 WMCreateSelectionHandler(WMView *view, Atom selection, Time timestamp,
368 WMSelectionProcs *procs, void *cdata)
370 SelectionHandler *handler;
371 Display *dpy = W_VIEW_SCREEN(view)->display;
373 XSetSelectionOwner(dpy, selection, W_VIEW_DRAWABLE(view), timestamp);
374 if (XGetSelectionOwner(dpy, selection) != W_VIEW_DRAWABLE(view))
375 return False;
377 handler = malloc(sizeof(SelectionHandler));
378 if (handler == NULL)
379 return False;
381 handler->view = view;
382 handler->selection = selection;
383 handler->timestamp = timestamp;
384 handler->procs = *procs;
385 handler->data = cdata;
386 memset(&handler->flags, 0, sizeof(handler->flags));
388 if (selHandlers == NULL) {
389 selHandlers = WMCreateArrayWithDestructor(4, wfree);
392 WMAddToArray(selHandlers, handler);
394 return True;
399 Bool
400 WMRequestSelection(WMView *view, Atom selection, Atom target, Time timestamp,
401 WMSelectionCallback *callback, void *cdata)
403 SelectionCallback *handler;
405 if (XGetSelectionOwner(W_VIEW_SCREEN(view)->display, selection) == None)
406 return False;
408 handler = wmalloc(sizeof(SelectionCallback));
410 handler->view = view;
411 handler->selection = selection;
412 handler->target = target;
413 handler->timestamp = timestamp;
414 handler->callback = callback;
415 handler->data = cdata;
416 memset(&handler->flags, 0, sizeof(handler->flags));
418 if (selCallbacks == NULL) {
419 selCallbacks = WMCreateArrayWithDestructor(4, wfree);
422 WMAddToArray(selCallbacks, handler);
424 if (!XConvertSelection(W_VIEW_SCREEN(view)->display, selection, target,
425 W_VIEW_SCREEN(view)->clipboardAtom,
426 W_VIEW_DRAWABLE(view), timestamp)) {
427 return False;
430 return True;