- german po file for WINGs (Guido Scholz <guido.scholz@bayernline.de>)
[wmaker-crm.git] / WINGs / selection.c
blob4ac0fcde86540ab16f2667eef7c3b0e6239f5d9e
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 == None)
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("event 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;
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)!=event->xselectionrequest.owner) {
201 break;
204 if (handler->procs.convertSelection != NULL
205 && handler->selection == event->xselectionrequest.selection) {
206 Atom atom;
207 WMData *data;
208 Atom prop;
210 /* they're requesting for something old.. maybe another handler
211 * can handle it */
212 if (event->xselectionrequest.time < handler->timestamp
213 && event->xselectionrequest.time != CurrentTime) {
214 break;
217 handledRequest = False;
219 handler->flags.done_pending = 1;
221 data = handler->procs.convertSelection(handler->view,
222 handler->selection,
223 event->xselectionrequest.target,
224 handler->data,
225 &atom);
227 prop = event->xselectionrequest.property;
228 /* obsolete clients that don't set the property field */
229 if (prop == None)
230 prop = event->xselectionrequest.target;
232 if (data) {
233 if (writeSelection(event->xselectionrequest.display,
234 event->xselectionrequest.requestor,
235 prop, atom, data)) {
236 handledRequest = True;
238 WMReleaseData(data);
241 notifySelection(event, (handledRequest==True ? prop : None));
243 if (handler->procs.selectionDone != NULL) {
244 handler->procs.selectionDone(handler->view,
245 handler->selection,
246 event->xselectionrequest.target,
247 handler->data);
250 handler->flags.done_pending = 0;
252 break;
256 /* delete handlers */
257 copy = WMDuplicateArray(selHandlers);
258 WM_ITERATE_ARRAY(copy, handler, iter) {
259 if (handler && handler->flags.delete_pending) {
260 WMDeleteSelectionHandler(handler->view, handler->selection,
261 handler->timestamp);
264 WMFreeArray(copy);
268 static WMData*
269 getSelectionData(Display *dpy, Window win, Atom where)
271 WMData *wdata;
272 unsigned char *data;
273 Atom rtype;
274 unsigned bits, bpi;
275 unsigned long len, bytes;
278 if (XGetWindowProperty(dpy, win, where, 0, MAX_PROPERTY_SIZE,
279 False, AnyPropertyType, &rtype, &bits, &len,
280 &bytes, &data)!=Success) {
281 return NULL;
284 bpi = bits/8;
286 wdata = WMCreateDataWithBytesNoCopy(data, len*bpi, (WMFreeDataProc*)XFree);
287 WMSetDataFormat(wdata, bits);
289 return wdata;
293 static void
294 handleNotifyEvent(XEvent *event)
296 SelectionCallback *handler;
297 WMArrayIterator iter;
298 WMArray *copy;
299 WMData *data;
301 WM_ITERATE_ARRAY(selCallbacks, handler, iter) {
303 if (W_VIEW_DRAWABLE(handler->view) != event->xselection.requestor
304 || handler->selection != event->xselection.selection) {
305 continue;
307 handler->flags.done_pending = 1;
309 if (event->xselection.property == None) {
310 data = NULL;
311 } else {
312 data = getSelectionData(event->xselection.display,
313 event->xselection.requestor,
314 event->xselection.property);
317 (*handler->callback)(handler->view, handler->selection,
318 handler->target, handler->timestamp,
319 handler->data, data);
321 if (data != NULL) {
322 WMReleaseData(data);
324 handler->flags.done_pending = 0;
325 handler->flags.delete_pending = 1;
328 /* delete callbacks */
329 copy = WMDuplicateArray(selCallbacks);
330 WM_ITERATE_ARRAY(copy, handler, iter) {
331 if (handler && handler->flags.delete_pending) {
332 WMDeleteSelectionCallback(handler->view, handler->selection,
333 handler->timestamp);
336 WMFreeArray(copy);
341 void
342 W_HandleSelectionEvent(XEvent *event)
344 if (event->type == SelectionNotify) {
345 handleNotifyEvent(event);
346 } else {
347 handleRequestEvent(event);
354 Bool
355 WMCreateSelectionHandler(WMView *view, Atom selection, Time timestamp,
356 WMSelectionProcs *procs, void *cdata)
358 SelectionHandler *handler;
359 Display *dpy = W_VIEW_SCREEN(view)->display;
361 XSetSelectionOwner(dpy, selection, W_VIEW_DRAWABLE(view), timestamp);
362 if (XGetSelectionOwner(dpy, selection) != W_VIEW_DRAWABLE(view))
363 return False;
365 handler = malloc(sizeof(SelectionHandler));
366 if (handler == NULL)
367 return False;
369 handler->view = view;
370 handler->selection = selection;
371 handler->timestamp = timestamp;
372 handler->procs = *procs;
373 handler->data = cdata;
374 memset(&handler->flags, 0, sizeof(handler->flags));
376 if (selHandlers == NULL) {
377 selHandlers = WMCreateArrayWithDestructor(4, wfree);
380 WMAddToArray(selHandlers, handler);
382 return True;
387 Bool
388 WMRequestSelection(WMView *view, Atom selection, Atom target, Time timestamp,
389 WMSelectionCallback *callback, void *cdata)
391 SelectionCallback *handler;
393 if (XGetSelectionOwner(W_VIEW_SCREEN(view)->display, selection) == None)
394 return False;
396 handler = wmalloc(sizeof(SelectionCallback));
398 handler->view = view;
399 handler->selection = selection;
400 handler->target = target;
401 handler->timestamp = timestamp;
402 handler->callback = callback;
403 handler->data = cdata;
404 memset(&handler->flags, 0, sizeof(handler->flags));
406 if (selCallbacks == NULL) {
407 selCallbacks = WMCreateArrayWithDestructor(4, wfree);
410 WMAddToArray(selCallbacks, handler);
412 if (!XConvertSelection(W_VIEW_SCREEN(view)->display, selection, target,
413 W_VIEW_SCREEN(view)->clipboardAtom,
414 W_VIEW_DRAWABLE(view), timestamp)) {
415 return False;
418 return True;