I accidentally left the hardware cursor feature disabled. Now enabled.
[AROS.git] / arch / all-hosted / hidd / x11 / x11clipboard.c
blob5e059c147bf648040df88cea2e44600efc5cd829
1 /*
2 Copyright © 1995-2016, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: X11 hidd. Host clipboard support.
6 Lang: English.
7 */
9 #include "x11_debug.h"
11 #include <proto/exec.h>
13 #include <X11/Xatom.h>
15 #include "x11_types.h"
16 #include "x11.h"
17 #include "x11_hostlib.h"
19 #undef XSD
20 #define XSD(cl) xsd
22 /****************************************************************************************/
24 #define REQ_CMD(msg) ((msg)->mn_Node.ln_Pri)
25 #define REQ_PARAM(msg) ((msg)->mn_Node.ln_Name)
27 #define REQ_RETVAL(msg) ((msg)->mn_Node.ln_Name)
28 #define REQ_SUCCESS(msg) ((msg)->mn_Node.ln_Pri)
30 /****************************************************************************************/
32 STATIC VOID listen_for_xevent(struct x11_staticdata *xsd, long event, BOOL yesno)
34 XWindowAttributes xwa;
36 LOCK_X11
37 XCALL(XGetWindowAttributes, xsd->display,
38 xsd->dummy_window_for_creating_pixmaps,
39 &xwa);
40 if (yesno)
42 event = xwa.your_event_mask | event;
44 else
46 event = xwa.your_event_mask &~ event;
49 XCALL(XSelectInput, xsd->display, xsd->dummy_window_for_creating_pixmaps, event);
50 UNLOCK_X11
53 /****************************************************************************************/
55 STATIC VOID reply_async_request(struct x11_staticdata *xsd, void *primary_retval, int success)
57 xsd->hostclipboard_readstate = HOSTCLIPBOARDSTATE_IDLE;
58 REQ_SUCCESS(xsd->hostclipboardmsg) = success;
59 REQ_RETVAL(xsd->hostclipboardmsg) = (char *)primary_retval;
60 ReplyMsg(xsd->hostclipboardmsg);
62 xsd->hostclipboardmsg = NULL;
64 /* In case messages were sent, while an async request was in progress */
65 Signal(xsd->hostclipboardmp->mp_SigTask, 1L << xsd->hostclipboardmp->mp_SigBit);
68 /****************************************************************************************/
70 ULONG x11clipboard_init(struct x11_staticdata *xsd)
72 ULONG hostclipboardmask = 0;
74 xsd->hostclipboardmp = CreateMsgPort();
75 if (xsd->hostclipboardmp)
77 xsd->hostclipboardmp->mp_Node.ln_Name = "HOST_CLIPBOARD";
78 hostclipboardmask = 1L << xsd->hostclipboardmp->mp_SigBit;
80 AddPort(xsd->hostclipboardmp);
83 return hostclipboardmask;
86 /****************************************************************************************/
88 VOID x11clipboard_handle_commands(struct x11_staticdata *xsd)
90 struct Message *msg;
92 if (xsd->hostclipboardmsg) return;
94 D(bug("X11CLIPBOARD: handle_commands\n"));
95 while((msg = GetMsg(xsd->hostclipboardmp)))
97 char cmd = REQ_CMD(msg);
98 BOOL async = FALSE;
100 REQ_SUCCESS(msg) = FALSE;
102 if (cmd == 'R')
104 D(bug("X11CLIPBOARD: handle_commands - READ\n"));
106 if ((xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_IDLE))
108 LOCK_X11
109 XCALL(XConvertSelection, xsd->display,
110 xsd->clipboard_atom,
111 XA_STRING,
112 xsd->clipboard_property_atom,
113 xsd->dummy_window_for_creating_pixmaps,
114 CurrentTime);
116 UNLOCK_X11
118 xsd->hostclipboard_readstate = HOSTCLIPBOARDSTATE_READ;
119 async = TRUE;
122 else if (cmd == 'W')
124 unsigned char *srcbuffer = (unsigned char *)REQ_PARAM(msg);
125 ULONG size = strlen(srcbuffer);
126 unsigned char *newbuffer;
128 D(bug("X11CLIPBOARD: handle_commands: WRITE\n"));
130 newbuffer = AllocVec(size, MEMF_ANY);
131 if (newbuffer)
133 memcpy(newbuffer, srcbuffer, size);
135 FreeVec(xsd->hostclipboard_writebuffer);
137 xsd->hostclipboard_writebuffer = newbuffer;
138 xsd->hostclipboard_writebuffer_size = size;
140 LOCK_X11
141 XCALL(XSetSelectionOwner, xsd->display, xsd->clipboard_atom,
142 xsd->dummy_window_for_creating_pixmaps, xsd->x_time);
143 UNLOCK_X11
145 REQ_SUCCESS(msg) = TRUE;
146 REQ_RETVAL(msg) = NULL;
148 else
150 REQ_SUCCESS(msg) = FALSE;
151 REQ_RETVAL(msg) = NULL;
155 if (async)
157 xsd->hostclipboardmsg = msg;
158 break;
161 ReplyMsg(msg);
165 /****************************************************************************************/
167 BOOL x11clipboard_want_event(XEvent *event)
169 if ((event->type == SelectionNotify) ||
170 (event->type == PropertyNotify) ||
171 (event->type == SelectionRequest))
173 return TRUE;
176 return FALSE;
179 /****************************************************************************************/
181 VOID x11clipboard_handle_event(struct x11_staticdata *xsd, XEvent *event)
183 switch(event->type)
185 case SelectionNotify:
186 D(bug("X11CLIPBOARD: SelectionNotify Event\n"));
188 if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ))
190 Atom actual_type;
191 int actual_format;
192 unsigned long nitems;
193 unsigned long bytes_after;
194 unsigned char *buffer, *arosbuffer;
196 LOCK_X11
197 XCALL(XGetWindowProperty, xsd->display,
198 xsd->dummy_window_for_creating_pixmaps,
199 xsd->clipboard_property_atom,
202 False,
203 AnyPropertyType,
204 &actual_type,
205 &actual_format,
206 &nitems,
207 &bytes_after,
208 &buffer);
209 XCALL(XFree, buffer);
210 UNLOCK_X11
212 if (actual_type == xsd->clipboard_incr_atom)
214 LOCK_X11
215 listen_for_xevent(xsd, PropertyChangeMask, TRUE);
216 XCALL(XDeleteProperty, xsd->display,
217 xsd->dummy_window_for_creating_pixmaps,
218 xsd->clipboard_property_atom);
219 XCALL(XFlush, xsd->display);
220 UNLOCK_X11;
222 xsd->hostclipboard_readstate = HOSTCLIPBOARDSTATE_READ_INCR;
224 D(bug("X11CLIPBOARD: SelectionNotify - INCR protocol\n"));
225 break;
228 if (actual_format != 8)
230 D(bug("X11CLIPBOARD: SelectionNotify - format is <> 8, so terminating READ request with error.\n"));
232 reply_async_request(xsd, NULL, FALSE);
233 break;
236 LOCK_X11
237 XCALL(XGetWindowProperty, xsd->display,
238 xsd->dummy_window_for_creating_pixmaps,
239 xsd->clipboard_property_atom,
241 bytes_after,
242 False,
243 AnyPropertyType,
244 &actual_type,
245 &actual_format,
246 &nitems,
247 &bytes_after,
248 &buffer);
250 XCALL(XDeleteProperty, xsd->display,
251 xsd->dummy_window_for_creating_pixmaps,
252 xsd->clipboard_property_atom);
254 arosbuffer = AllocVec(nitems + 1, MEMF_ANY);
255 if (arosbuffer)
257 memcpy(arosbuffer, buffer, nitems);
258 arosbuffer[nitems] = '\0';
260 XCALL(XFree, buffer);
261 UNLOCK_X11;
263 D(bug("X11CLIPBOARD: SelectionNotify - terminating READ request with %s\n", arosbuffer ? "success" : "failure"));
265 reply_async_request(xsd, arosbuffer, arosbuffer ? TRUE : FALSE);
267 } /* if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ))*/
268 break;
270 case PropertyNotify:
271 D(bug("X11CLIPBOARD: PropertyNotify Event\n"));
273 if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ_INCR))
275 if ((event->xproperty.atom == xsd->clipboard_property_atom) &&
276 (event->xproperty.state == PropertyNewValue))
278 Atom actual_type;
279 int actual_format;
280 unsigned long nitems;
281 unsigned long bytes_after;
282 unsigned char *buffer, *arosbuffer;
284 D(bug("X11CLIPBOARD: PropertyNotify - property event okay\n"));
286 LOCK_X11
287 XCALL(XGetWindowProperty, xsd->display,
288 xsd->dummy_window_for_creating_pixmaps,
289 xsd->clipboard_property_atom,
292 False,
293 AnyPropertyType,
294 &actual_type,
295 &actual_format,
296 &nitems,
297 &bytes_after,
298 &buffer);
299 XCALL(XFree, buffer);
300 UNLOCK_X11
302 if (actual_format == 8)
304 D(bug("X11CLIPBOARD: PropertyNotify - format(8) okay\n"));
305 if (bytes_after == 0)
307 D(bug("X11CLIPBOARD: PropertyNotify - last one detected. Terminating READ request with %s\n",
308 xsd->hostclipboard_incrbuffer ? "success" : "failure"));
310 reply_async_request(xsd, xsd->hostclipboard_incrbuffer,
311 xsd->hostclipboard_incrbuffer ? TRUE : FALSE);
313 xsd->hostclipboard_incrbuffer = NULL;
314 xsd->hostclipboard_incrbuffer_size = 0;
316 listen_for_xevent(xsd, PropertyChangeMask, FALSE);
318 else
320 LOCK_X11
321 XCALL(XGetWindowProperty, xsd->display,
322 xsd->dummy_window_for_creating_pixmaps,
323 xsd->clipboard_property_atom,
325 bytes_after,
326 False,
327 AnyPropertyType,
328 &actual_type,
329 &actual_format,
330 &nitems,
331 &bytes_after,
332 &buffer);
334 if (!xsd->hostclipboard_incrbuffer)
336 /* No buffer allocated yet. */
338 D(bug("X11CLIPBOARD: PropertyNotify - First INCR packet of size %d\n", nitems));
339 xsd->hostclipboard_incrbuffer = AllocVec(nitems + 1, MEMF_ANY);
340 if (xsd->hostclipboard_incrbuffer)
342 memcpy(xsd->hostclipboard_incrbuffer, buffer, nitems);
343 xsd->hostclipboard_incrbuffer[nitems] = '\0';
344 xsd->hostclipboard_incrbuffer_size = nitems;
346 else
348 D(bug("X11CLIPBOARD: PropertyNotify - Allocation of incrbuffer failed! Terminating READ request with failure\n"));
350 reply_async_request(xsd, NULL, FALSE);
352 listen_for_xevent(xsd, PropertyChangeMask, FALSE);
355 else
357 /* Buffer already allocated. Do a re-allocation! */
359 D(bug("X11CLIPBOARD: PropertyNotify - One more INCR packet of size %d. Total size now %d\n",
360 nitems, xsd->hostclipboard_incrbuffer_size + nitems));
362 arosbuffer = AllocVec(xsd->hostclipboard_incrbuffer_size + nitems + 1, MEMF_ANY);
363 if (arosbuffer)
365 memcpy(arosbuffer, xsd->hostclipboard_incrbuffer, xsd->hostclipboard_incrbuffer_size);
366 FreeVec(xsd->hostclipboard_incrbuffer);
367 xsd->hostclipboard_incrbuffer = arosbuffer;
369 memcpy(xsd->hostclipboard_incrbuffer + xsd->hostclipboard_incrbuffer_size,
370 buffer,
371 nitems);
373 xsd->hostclipboard_incrbuffer_size += nitems;
374 xsd->hostclipboard_incrbuffer[xsd->hostclipboard_incrbuffer_size] = '\0';
376 else
378 D(bug("X11CLIPBOARD: PropertyNotify - Reallocation of incrbuffer failed! Terminating READ request with failure\n"));
380 FreeVec(xsd->hostclipboard_incrbuffer);
382 reply_async_request(xsd, NULL, FALSE);
384 xsd->hostclipboard_incrbuffer = NULL;
385 xsd->hostclipboard_incrbuffer_size = 0;
387 listen_for_xevent(xsd, PropertyChangeMask, FALSE);
390 } /* if (!xsd->hostclipboard_incrbuffer) else ... */
392 XCALL(XFree, buffer);
393 UNLOCK_X11
395 } /* if (bytes_after == 0) else ... */
397 } /* if (actual_format == 8) */
399 LOCK_X11
400 XCALL(XDeleteProperty, xsd->display,
401 xsd->dummy_window_for_creating_pixmaps,
402 xsd->clipboard_property_atom);
403 XCALL(XFlush, xsd->display);
404 UNLOCK_X11
406 } /* if it's right property and the property has new value */
408 } /* if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ_INCR)) */
410 break;
412 case SelectionRequest:
413 D(bug("X11CLIPBOARD: SelectionRequest Event\n"));
415 if (xsd->hostclipboard_writebuffer)
417 XEvent e;
419 D(bug("X11CLIPBOARD: SelectionRequest Event - state okay\n"));
421 e.xselection.type = SelectionNotify;
422 e.xselection.display = event->xselectionrequest.display;
423 e.xselection.requestor = event->xselectionrequest.requestor;
424 e.xselection.selection = event->xselectionrequest.selection;
425 e.xselection.target = event->xselectionrequest.target;
426 e.xselection.property = event->xselectionrequest.property;
427 e.xselection.time = event->xselectionrequest.time;
429 xsd->hostclipboard_writerequest_window = event->xselectionrequest.requestor;
430 xsd->hostclipboard_writerequest_property = event->xselectionrequest.property;
432 if (event->xselectionrequest.target == xsd->clipboard_targets_atom)
434 long supported_targets[] = {XA_STRING};
436 LOCK_X11
437 XCALL(XChangeProperty, xsd->display,
438 xsd->hostclipboard_writerequest_window,
439 xsd->hostclipboard_writerequest_property,
440 xsd->clipboard_targets_atom,
442 PropModeReplace,
443 (unsigned char *)supported_targets,
444 sizeof(supported_targets) / sizeof(supported_targets[0]));
445 UNLOCK_X11
448 else if (event->xselectionrequest.target == XA_STRING)
451 LOCK_X11
452 xsd->hostclipboard_write_chunks = XCALL(XMaxRequestSize, xsd->display) * 4 / 2;
454 /* FIXME TODO: Use INCR protocol for large requests */
455 if (1)// && xsd->hostclipboard_writebuffer_size <= xsd->hostclipboard_write_chunks)
457 D(bug("X11CLIPBOARD: SelectionRequest Event - one chunk is enough\n"));
459 //D(bug("[%s]\n", xsd->hostclipboard_writebuffer));
461 XCALL(XChangeProperty, xsd->display,
462 xsd->hostclipboard_writerequest_window,
463 xsd->hostclipboard_writerequest_property,
464 XA_STRING,
466 PropModeReplace,
467 (unsigned char *)xsd->hostclipboard_writebuffer,
468 (int)xsd->hostclipboard_writebuffer_size);
470 else
472 /* FIXME TODO: Use INCR protocol for large requests */
474 e.xselection.property = None;
476 UNLOCK_X11
478 else
480 e.xselection.property = None;
483 D(bug("X11CLIPBOARD: SelectionRequest Event - sending SelectionNotify event to clipboard requestor\n"));
485 LOCK_X11
486 XCALL(XSendEvent, xsd->display,
487 xsd->hostclipboard_writerequest_window,
488 False,
489 NoEventMask,
490 &e);
491 XCALL(XFlush, xsd->display);
492 UNLOCK_X11
494 break;
496 } /* switch(event->type) */
500 /****************************************************************************************/