Added a test for MUIA_Listview_SelectChange.
[AROS.git] / arch / all-hosted / hidd / x11 / x11clipboard.c
blob9936d66f442d7db17b8090a0c82ab9bd299245a7
1 /*
2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: X11 hidd. Host clipboard support.
6 Lang: English.
7 */
10 #include <proto/exec.h>
11 #include <proto/oop.h>
12 #include <proto/utility.h>
14 #define size_t aros_size_t
15 #include <hidd/unixio.h>
16 #include <hidd/hidd.h>
18 #include <oop/ifmeta.h>
20 #include <dos/dos.h>
22 #include <exec/types.h>
23 #include <exec/lists.h>
24 #include <exec/memory.h>
25 #include <exec/libraries.h>
26 #include <exec/resident.h>
27 #include <hardware/intbits.h>
28 #include <utility/utility.h>
30 #include <aros/asmcall.h>
31 #undef size_t
33 #define timeval sys_timeval
34 #include <sys/types.h>
35 #include <signal.h>
36 #include <stddef.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #undef timeval
43 #include <X11/Xlib.h>
44 #include <X11/Xutil.h>
45 #include <X11/Xatom.h>
47 #include "x11.h"
48 #include "x11gfx_intern.h"
50 #define DEBUG 0
51 #include <aros/debug.h>
53 #undef XSD
54 #define XSD(cl) xsd
56 /****************************************************************************************/
58 #define REQ_CMD(msg) ((msg)->mn_Node.ln_Pri)
59 #define REQ_PARAM(msg) ((msg)->mn_Node.ln_Name)
61 #define REQ_RETVAL(msg) ((msg)->mn_Node.ln_Name)
62 #define REQ_SUCCESS(msg) ((msg)->mn_Node.ln_Pri)
64 /****************************************************************************************/
66 STATIC VOID listen_for_xevent(struct x11_staticdata *xsd, long event, BOOL yesno)
68 XWindowAttributes xwa;
70 LOCK_X11
71 XCALL(XGetWindowAttributes, xsd->display,
72 xsd->dummy_window_for_creating_pixmaps,
73 &xwa);
74 if (yesno)
76 event = xwa.your_event_mask | event;
78 else
80 event = xwa.your_event_mask &~ event;
83 XCALL(XSelectInput, xsd->display, xsd->dummy_window_for_creating_pixmaps, event);
84 UNLOCK_X11
87 /****************************************************************************************/
89 STATIC VOID reply_async_request(struct x11_staticdata *xsd, void *primary_retval, int success)
91 xsd->hostclipboard_readstate = HOSTCLIPBOARDSTATE_IDLE;
92 REQ_SUCCESS(xsd->hostclipboardmsg) = success;
93 REQ_RETVAL(xsd->hostclipboardmsg) = (char *)primary_retval;
94 ReplyMsg(xsd->hostclipboardmsg);
96 xsd->hostclipboardmsg = NULL;
98 /* In case messages were sent, while an async request was in progress */
99 Signal(xsd->hostclipboardmp->mp_SigTask, 1L << xsd->hostclipboardmp->mp_SigBit);
102 /****************************************************************************************/
104 ULONG x11clipboard_init(struct x11_staticdata *xsd)
106 ULONG hostclipboardmask = 0;
108 xsd->hostclipboardmp = CreateMsgPort();
109 if (xsd->hostclipboardmp)
111 xsd->hostclipboardmp->mp_Node.ln_Name = "HOST_CLIPBOARD";
112 hostclipboardmask = 1L << xsd->hostclipboardmp->mp_SigBit;
114 AddPort(xsd->hostclipboardmp);
117 return hostclipboardmask;
120 /****************************************************************************************/
122 VOID x11clipboard_handle_commands(struct x11_staticdata *xsd)
124 struct Message *msg;
126 if (xsd->hostclipboardmsg) return;
128 D(bug("X11CLIPBOARD: handle_commands\n"));
129 while((msg = GetMsg(xsd->hostclipboardmp)))
131 char cmd = REQ_CMD(msg);
132 BOOL async = FALSE;
134 REQ_SUCCESS(msg) = FALSE;
136 if (cmd == 'R')
138 D(bug("X11CLIPBOARD: handle_commands - READ\n"));
140 if ((xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_IDLE))
142 LOCK_X11
143 XCALL(XConvertSelection, xsd->display,
144 xsd->clipboard_atom,
145 XA_STRING,
146 xsd->clipboard_property_atom,
147 xsd->dummy_window_for_creating_pixmaps,
148 CurrentTime);
150 UNLOCK_X11
152 xsd->hostclipboard_readstate = HOSTCLIPBOARDSTATE_READ;
153 async = TRUE;
156 else if (cmd == 'W')
158 unsigned char *srcbuffer = (unsigned char *)REQ_PARAM(msg);
159 ULONG size = strlen(srcbuffer);
160 unsigned char *newbuffer;
162 D(bug("X11CLIPBOARD: handle_commands: WRITE\n"));
164 newbuffer = AllocVec(size, MEMF_ANY);
165 if (newbuffer)
167 memcpy(newbuffer, srcbuffer, size);
169 FreeVec(xsd->hostclipboard_writebuffer);
171 xsd->hostclipboard_writebuffer = newbuffer;
172 xsd->hostclipboard_writebuffer_size = size;
174 LOCK_X11
175 XCALL(XSetSelectionOwner, xsd->display, xsd->clipboard_atom,
176 xsd->dummy_window_for_creating_pixmaps, xsd->x_time);
177 UNLOCK_X11
179 REQ_SUCCESS(msg) = TRUE;
180 REQ_RETVAL(msg) = NULL;
182 else
184 REQ_SUCCESS(msg) = FALSE;
185 REQ_RETVAL(msg) = NULL;
189 if (async)
191 xsd->hostclipboardmsg = msg;
192 break;
195 ReplyMsg(msg);
199 /****************************************************************************************/
201 BOOL x11clipboard_want_event(XEvent *event)
203 if ((event->type == SelectionNotify) ||
204 (event->type == PropertyNotify) ||
205 (event->type == SelectionRequest))
207 return TRUE;
210 return FALSE;
213 /****************************************************************************************/
215 VOID x11clipboard_handle_event(struct x11_staticdata *xsd, XEvent *event)
217 switch(event->type)
219 case SelectionNotify:
220 D(bug("X11CLIPBOARD: SelectionNotify Event\n"));
222 if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ))
224 Atom actual_type;
225 int actual_format;
226 unsigned long nitems;
227 unsigned long bytes_after;
228 unsigned char *buffer, *arosbuffer;
230 LOCK_X11
231 XCALL(XGetWindowProperty, xsd->display,
232 xsd->dummy_window_for_creating_pixmaps,
233 xsd->clipboard_property_atom,
236 False,
237 AnyPropertyType,
238 &actual_type,
239 &actual_format,
240 &nitems,
241 &bytes_after,
242 &buffer);
243 XCALL(XFree, buffer);
244 UNLOCK_X11
246 if (actual_type == xsd->clipboard_incr_atom)
248 LOCK_X11
249 listen_for_xevent(xsd, PropertyChangeMask, TRUE);
250 XCALL(XDeleteProperty, xsd->display,
251 xsd->dummy_window_for_creating_pixmaps,
252 xsd->clipboard_property_atom);
253 XCALL(XFlush, xsd->display);
254 UNLOCK_X11;
256 xsd->hostclipboard_readstate = HOSTCLIPBOARDSTATE_READ_INCR;
258 D(bug("X11CLIPBOARD: SelectionNotify - INCR protocol\n"));
259 break;
262 if (actual_format != 8)
264 D(bug("X11CLIPBOARD: SelectionNotify - format is <> 8, so terminating READ request with error.\n"));
266 reply_async_request(xsd, NULL, FALSE);
267 break;
270 LOCK_X11
271 XCALL(XGetWindowProperty, xsd->display,
272 xsd->dummy_window_for_creating_pixmaps,
273 xsd->clipboard_property_atom,
275 bytes_after,
276 False,
277 AnyPropertyType,
278 &actual_type,
279 &actual_format,
280 &nitems,
281 &bytes_after,
282 &buffer);
284 XCALL(XDeleteProperty, xsd->display,
285 xsd->dummy_window_for_creating_pixmaps,
286 xsd->clipboard_property_atom);
288 arosbuffer = AllocVec(nitems + 1, MEMF_ANY);
289 if (arosbuffer)
291 memcpy(arosbuffer, buffer, nitems);
292 arosbuffer[nitems] = '\0';
294 XCALL(XFree, buffer);
295 UNLOCK_X11;
297 D(bug("X11CLIPBOARD: SelectionNotify - terminating READ request with %s\n", arosbuffer ? "success" : "failure"));
299 reply_async_request(xsd, arosbuffer, arosbuffer ? TRUE : FALSE);
301 } /* if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ))*/
302 break;
304 case PropertyNotify:
305 D(bug("X11CLIPBOARD: PropertyNotify Event\n"));
307 if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ_INCR))
309 if ((event->xproperty.atom == xsd->clipboard_property_atom) &&
310 (event->xproperty.state == PropertyNewValue))
312 Atom actual_type;
313 int actual_format;
314 unsigned long nitems;
315 unsigned long bytes_after;
316 unsigned char *buffer, *arosbuffer;
318 D(bug("X11CLIPBOARD: PropertyNotify - property event okay\n"));
320 LOCK_X11
321 XCALL(XGetWindowProperty, xsd->display,
322 xsd->dummy_window_for_creating_pixmaps,
323 xsd->clipboard_property_atom,
326 False,
327 AnyPropertyType,
328 &actual_type,
329 &actual_format,
330 &nitems,
331 &bytes_after,
332 &buffer);
333 XCALL(XFree, buffer);
334 UNLOCK_X11
336 if (actual_format == 8)
338 D(bug("X11CLIPBOARD: PropertyNotify - format(8) okay\n"));
339 if (bytes_after == 0)
341 D(bug("X11CLIPBOARD: PropertyNotify - last one detected. Terminating READ request with %s\n",
342 xsd->hostclipboard_incrbuffer ? "success" : "failure"));
344 reply_async_request(xsd, xsd->hostclipboard_incrbuffer,
345 xsd->hostclipboard_incrbuffer ? TRUE : FALSE);
347 xsd->hostclipboard_incrbuffer = NULL;
348 xsd->hostclipboard_incrbuffer_size = 0;
350 listen_for_xevent(xsd, PropertyChangeMask, FALSE);
352 else
354 LOCK_X11
355 XCALL(XGetWindowProperty, xsd->display,
356 xsd->dummy_window_for_creating_pixmaps,
357 xsd->clipboard_property_atom,
359 bytes_after,
360 False,
361 AnyPropertyType,
362 &actual_type,
363 &actual_format,
364 &nitems,
365 &bytes_after,
366 &buffer);
368 if (!xsd->hostclipboard_incrbuffer)
370 /* No buffer allocated yet. */
372 D(bug("X11CLIPBOARD: PropertyNotify - First INCR packet of size %d\n", nitems));
373 xsd->hostclipboard_incrbuffer = AllocVec(nitems + 1, MEMF_ANY);
374 if (xsd->hostclipboard_incrbuffer)
376 memcpy(xsd->hostclipboard_incrbuffer, buffer, nitems);
377 xsd->hostclipboard_incrbuffer[nitems] = '\0';
378 xsd->hostclipboard_incrbuffer_size = nitems;
380 else
382 D(bug("X11CLIPBOARD: PropertyNotify - Allocation of incrbuffer failed! Terminating READ request with failure\n"));
384 reply_async_request(xsd, NULL, FALSE);
386 listen_for_xevent(xsd, PropertyChangeMask, FALSE);
389 else
391 /* Buffer already allocated. Do a re-allocation! */
393 D(bug("X11CLIPBOARD: PropertyNotify - One more INCR packet of size %d. Total size now %d\n",
394 nitems, xsd->hostclipboard_incrbuffer_size + nitems));
396 arosbuffer = AllocVec(xsd->hostclipboard_incrbuffer_size + nitems + 1, MEMF_ANY);
397 if (arosbuffer)
399 memcpy(arosbuffer, xsd->hostclipboard_incrbuffer, xsd->hostclipboard_incrbuffer_size);
400 FreeVec(xsd->hostclipboard_incrbuffer);
401 xsd->hostclipboard_incrbuffer = arosbuffer;
403 memcpy(xsd->hostclipboard_incrbuffer + xsd->hostclipboard_incrbuffer_size,
404 buffer,
405 nitems);
407 xsd->hostclipboard_incrbuffer_size += nitems;
408 xsd->hostclipboard_incrbuffer[xsd->hostclipboard_incrbuffer_size] = '\0';
410 else
412 D(bug("X11CLIPBOARD: PropertyNotify - Reallocation of incrbuffer failed! Terminating READ request with failure\n"));
414 FreeVec(xsd->hostclipboard_incrbuffer);
416 reply_async_request(xsd, NULL, FALSE);
418 xsd->hostclipboard_incrbuffer = NULL;
419 xsd->hostclipboard_incrbuffer_size = 0;
421 listen_for_xevent(xsd, PropertyChangeMask, FALSE);
424 } /* if (!xsd->hostclipboard_incrbuffer) else ... */
426 XCALL(XFree, buffer);
427 UNLOCK_X11
429 } /* if (bytes_after == 0) else ... */
431 } /* if (actual_format == 8) */
433 LOCK_X11
434 XCALL(XDeleteProperty, xsd->display,
435 xsd->dummy_window_for_creating_pixmaps,
436 xsd->clipboard_property_atom);
437 XCALL(XFlush, xsd->display);
438 UNLOCK_X11
440 } /* if it's right property and the property has new value */
442 } /* if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ_INCR)) */
444 break;
446 case SelectionRequest:
447 D(bug("X11CLIPBOARD: SelectionRequest Event\n"));
449 if (xsd->hostclipboard_writebuffer)
451 XEvent e;
453 D(bug("X11CLIPBOARD: SelectionRequest Event - state okay\n"));
455 e.xselection.type = SelectionNotify;
456 e.xselection.display = event->xselectionrequest.display;
457 e.xselection.requestor = event->xselectionrequest.requestor;
458 e.xselection.selection = event->xselectionrequest.selection;
459 e.xselection.target = event->xselectionrequest.target;
460 e.xselection.property = event->xselectionrequest.property;
461 e.xselection.time = event->xselectionrequest.time;
463 xsd->hostclipboard_writerequest_window = event->xselectionrequest.requestor;
464 xsd->hostclipboard_writerequest_property = event->xselectionrequest.property;
466 if (event->xselectionrequest.target == xsd->clipboard_targets_atom)
468 long supported_targets[] = {XA_STRING};
470 LOCK_X11
471 XCALL(XChangeProperty, xsd->display,
472 xsd->hostclipboard_writerequest_window,
473 xsd->hostclipboard_writerequest_property,
474 xsd->clipboard_targets_atom,
476 PropModeReplace,
477 (unsigned char *)supported_targets,
478 sizeof(supported_targets) / sizeof(supported_targets[0]));
479 UNLOCK_X11
482 else if (event->xselectionrequest.target == XA_STRING)
485 LOCK_X11
486 xsd->hostclipboard_write_chunks = XCALL(XMaxRequestSize, xsd->display) * 4 / 2;
488 /* FIXME TODO: Use INCR protocol for large requests */
489 if (1)// && xsd->hostclipboard_writebuffer_size <= xsd->hostclipboard_write_chunks)
491 D(bug("X11CLIPBOARD: SelectionRequest Event - one chunk is enough\n"));
493 //D(bug("[%s]\n", xsd->hostclipboard_writebuffer));
495 XCALL(XChangeProperty, xsd->display,
496 xsd->hostclipboard_writerequest_window,
497 xsd->hostclipboard_writerequest_property,
498 XA_STRING,
500 PropModeReplace,
501 (unsigned char *)xsd->hostclipboard_writebuffer,
502 (int)xsd->hostclipboard_writebuffer_size);
504 else
506 /* FIXME TODO: Use INCR protocol for large requests */
508 e.xselection.property = None;
510 UNLOCK_X11
512 else
514 e.xselection.property = None;
517 D(bug("X11CLIPBOARD: SelectionRequest Event - sending SelectionNotify event to clipboard requestor\n"));
519 LOCK_X11
520 XCALL(XSendEvent, xsd->display,
521 xsd->hostclipboard_writerequest_window,
522 False,
523 NoEventMask,
524 &e);
525 XCALL(XFlush, xsd->display);
526 UNLOCK_X11
528 break;
530 } /* switch(event->type) */
534 /****************************************************************************************/