Don't call WDM_WINDOWSHAPE + ChangeWindowShape on
[tangerine.git] / arch / all-x11 / hidd / x11clipboard.c
blob31c007f11a6a53bbac33a2c96175a488b1f814ca
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 1
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 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 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 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 if (xsd->hostclipboard_writebuffer)
171 FreeVec(xsd->hostclipboard_writebuffer);
174 xsd->hostclipboard_writebuffer = newbuffer;
175 xsd->hostclipboard_writebuffer_size = size;
177 LOCK_X11
178 XSetSelectionOwner(xsd->display, xsd->clipboard_atom,
179 xsd->dummy_window_for_creating_pixmaps, xsd->x_time);
180 UNLOCK_X11
182 REQ_SUCCESS(msg) = TRUE;
183 REQ_RETVAL(msg) = NULL;
185 else
187 REQ_SUCCESS(msg) = FALSE;
188 REQ_RETVAL(msg) = NULL;
192 if (async)
194 xsd->hostclipboardmsg = msg;
195 break;
198 ReplyMsg(msg);
202 /****************************************************************************************/
204 BOOL x11clipboard_want_event(XEvent *event)
206 if ((event->type == SelectionNotify) ||
207 (event->type == PropertyNotify) ||
208 (event->type == SelectionRequest))
210 return TRUE;
213 return FALSE;
216 /****************************************************************************************/
218 VOID x11clipboard_handle_event(struct x11_staticdata *xsd, XEvent *event)
220 switch(event->type)
222 case SelectionNotify:
223 D(bug("X11CLIPBOARD: SelectionNotify Event\n"));
225 if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ))
227 Atom actual_type;
228 int actual_format;
229 unsigned long nitems;
230 unsigned long bytes_after;
231 unsigned char *buffer, *arosbuffer;
233 LOCK_X11
234 XGetWindowProperty(xsd->display,
235 xsd->dummy_window_for_creating_pixmaps,
236 xsd->clipboard_property_atom,
239 False,
240 AnyPropertyType,
241 &actual_type,
242 &actual_format,
243 &nitems,
244 &bytes_after,
245 &buffer);
246 XFree(buffer);
247 UNLOCK_X11
249 if (actual_type == xsd->clipboard_incr_atom)
251 LOCK_X11
252 listen_for_xevent(xsd, PropertyChangeMask, TRUE);
253 XDeleteProperty(xsd->display,
254 xsd->dummy_window_for_creating_pixmaps,
255 xsd->clipboard_property_atom);
256 XFlush(xsd->display);
257 UNLOCK_X11;
259 xsd->hostclipboard_readstate = HOSTCLIPBOARDSTATE_READ_INCR;
261 D(bug("X11CLIPBOARD: SelectionNotify - INCR protocol\n"));
262 break;
265 if (actual_format != 8)
267 D(bug("X11CLIPBOARD: SelectionNotify - format is <> 8, so terminating READ request with error.\n"));
269 reply_async_request(xsd, NULL, FALSE);
270 break;
273 LOCK_X11
274 XGetWindowProperty(xsd->display,
275 xsd->dummy_window_for_creating_pixmaps,
276 xsd->clipboard_property_atom,
278 bytes_after,
279 False,
280 AnyPropertyType,
281 &actual_type,
282 &actual_format,
283 &nitems,
284 &bytes_after,
285 &buffer);
287 XDeleteProperty(xsd->display,
288 xsd->dummy_window_for_creating_pixmaps,
289 xsd->clipboard_property_atom);
291 arosbuffer = AllocVec(nitems + 1, MEMF_ANY);
292 if (arosbuffer)
294 memcpy(arosbuffer, buffer, nitems);
295 arosbuffer[nitems] = '\0';
297 XFree(buffer);
298 UNLOCK_X11;
300 D(bug("X11CLIPBOARD: SelectionNotify - terminating READ request with %s\n", arosbuffer ? "success" : "failure"));
302 reply_async_request(xsd, arosbuffer, arosbuffer ? TRUE : FALSE);
304 } /* if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ))*/
305 break;
307 case PropertyNotify:
308 D(bug("X11CLIPBOARD: PropertyNotify Event\n"));
310 if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ_INCR))
312 if ((event->xproperty.atom == xsd->clipboard_property_atom) &&
313 (event->xproperty.state == PropertyNewValue))
315 Atom actual_type;
316 int actual_format;
317 unsigned long nitems;
318 unsigned long bytes_after;
319 unsigned char *buffer, *arosbuffer;
321 D(bug("X11CLIPBOARD: PropertyNotify - property event okay\n"));
323 LOCK_X11
324 XGetWindowProperty(xsd->display,
325 xsd->dummy_window_for_creating_pixmaps,
326 xsd->clipboard_property_atom,
329 False,
330 AnyPropertyType,
331 &actual_type,
332 &actual_format,
333 &nitems,
334 &bytes_after,
335 &buffer);
336 XFree(buffer);
337 UNLOCK_X11
339 if (actual_format == 8)
341 D(bug("X11CLIPBOARD: PropertyNotify - format(8) okay\n"));
342 if (bytes_after == 0)
344 D(bug("X11CLIPBOARD: PropertyNotify - last one detected. Terminating READ request with %s\n",
345 xsd->hostclipboard_incrbuffer ? "success" : "failure"));
347 reply_async_request(xsd, xsd->hostclipboard_incrbuffer,
348 xsd->hostclipboard_incrbuffer ? TRUE : FALSE);
350 xsd->hostclipboard_incrbuffer = NULL;
351 xsd->hostclipboard_incrbuffer_size = 0;
353 listen_for_xevent(xsd, PropertyChangeMask, FALSE);
355 else
357 LOCK_X11
358 XGetWindowProperty(xsd->display,
359 xsd->dummy_window_for_creating_pixmaps,
360 xsd->clipboard_property_atom,
362 bytes_after,
363 False,
364 AnyPropertyType,
365 &actual_type,
366 &actual_format,
367 &nitems,
368 &bytes_after,
369 &buffer);
371 if (!xsd->hostclipboard_incrbuffer)
373 /* No buffer allocated yet. */
375 D(bug("X11CLIPBOARD: PropertyNotify - First INCR packet of size %d\n", nitems));
376 xsd->hostclipboard_incrbuffer = AllocVec(nitems + 1, MEMF_ANY);
377 if (xsd->hostclipboard_incrbuffer)
379 memcpy(xsd->hostclipboard_incrbuffer, buffer, nitems);
380 xsd->hostclipboard_incrbuffer[nitems] = '\0';
381 xsd->hostclipboard_incrbuffer_size = nitems;
383 else
385 D(bug("X11CLIPBOARD: PropertyNotify - Allocation of incrbuffer failed! Terminating READ request with failure\n"));
387 reply_async_request(xsd, NULL, FALSE);
389 listen_for_xevent(xsd, PropertyChangeMask, FALSE);
392 else
394 /* Buffer already allocated. Do a re-allocation! */
396 D(bug("X11CLIPBOARD: PropertyNotify - One more INCR packet of size %d. Total size now %d\n",
397 nitems, xsd->hostclipboard_incrbuffer_size + nitems));
399 arosbuffer = AllocVec(xsd->hostclipboard_incrbuffer_size + nitems + 1, MEMF_ANY);
400 if (arosbuffer)
402 memcpy(arosbuffer, xsd->hostclipboard_incrbuffer, xsd->hostclipboard_incrbuffer_size);
403 FreeVec(xsd->hostclipboard_incrbuffer);
404 xsd->hostclipboard_incrbuffer = arosbuffer;
406 memcpy(xsd->hostclipboard_incrbuffer + xsd->hostclipboard_incrbuffer_size,
407 buffer,
408 nitems);
410 xsd->hostclipboard_incrbuffer_size += nitems;
411 xsd->hostclipboard_incrbuffer[xsd->hostclipboard_incrbuffer_size] = '\0';
413 else
415 D(bug("X11CLIPBOARD: PropertyNotify - Reallocation of incrbuffer failed! Terminating READ request with failure\n"));
417 FreeVec(xsd->hostclipboard_incrbuffer);
419 reply_async_request(xsd, NULL, FALSE);
421 xsd->hostclipboard_incrbuffer = NULL;
422 xsd->hostclipboard_incrbuffer_size = 0;
424 listen_for_xevent(xsd, PropertyChangeMask, FALSE);
427 } /* if (!xsd->hostclipboard_incrbuffer) else ... */
429 XFree(buffer);
430 UNLOCK_X11
432 } /* if (bytes_after == 0) else ... */
434 } /* if (actual_format == 8) */
436 LOCK_X11
437 XDeleteProperty(xsd->display,
438 xsd->dummy_window_for_creating_pixmaps,
439 xsd->clipboard_property_atom);
440 XFlush(xsd->display);
441 UNLOCK_X11
443 } /* if it's right property and the property has new value */
445 } /* if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ_INCR)) */
447 break;
449 case SelectionRequest:
450 D(bug("X11CLIPBOARD: SelectionRequest Event\n"));
452 if (xsd->hostclipboard_writebuffer)
454 XEvent e;
456 D(bug("X11CLIPBOARD: SelectionRequest Event - state okay\n"));
458 e.xselection.type = SelectionNotify;
459 e.xselection.display = event->xselectionrequest.display;
460 e.xselection.requestor = event->xselectionrequest.requestor;
461 e.xselection.selection = event->xselectionrequest.selection;
462 e.xselection.target = event->xselectionrequest.target;
463 e.xselection.property = event->xselectionrequest.property;
464 e.xselection.time = event->xselectionrequest.time;
466 xsd->hostclipboard_writerequest_window = event->xselectionrequest.requestor;
467 xsd->hostclipboard_writerequest_property = event->xselectionrequest.property;
469 if (event->xselectionrequest.target == xsd->clipboard_targets_atom)
471 long supported_targets[] = {XA_STRING};
473 LOCK_X11
474 XChangeProperty(xsd->display,
475 xsd->hostclipboard_writerequest_window,
476 xsd->hostclipboard_writerequest_property,
477 xsd->clipboard_targets_atom,
479 PropModeReplace,
480 (unsigned char *)supported_targets,
481 sizeof(supported_targets) / sizeof(supported_targets[0]));
482 UNLOCK_X11
485 else if (event->xselectionrequest.target == XA_STRING)
488 LOCK_X11
489 xsd->hostclipboard_write_chunks = XMaxRequestSize(xsd->display) * 4 / 2;
491 /* FIXME TODO: Use INCR protocol for large requests */
492 if (1)// && xsd->hostclipboard_writebuffer_size <= xsd->hostclipboard_write_chunks)
494 D(bug("X11CLIPBOARD: SelectionRequest Event - one chunk is enough\n"));
496 //D(bug("[%s]\n", xsd->hostclipboard_writebuffer));
498 XChangeProperty(xsd->display,
499 xsd->hostclipboard_writerequest_window,
500 xsd->hostclipboard_writerequest_property,
501 XA_STRING,
503 PropModeReplace,
504 (unsigned char *)xsd->hostclipboard_writebuffer,
505 (int)xsd->hostclipboard_writebuffer_size);
507 else
509 /* FIXME TODO: Use INCR protocol for large requests */
511 e.xselection.property = None;
513 UNLOCK_X11
515 else
517 e.xselection.property = None;
520 D(bug("X11CLIPBOARD: SelectionRequest Event - sending SelectionNotify event to clipboard requestor\n"));
522 LOCK_X11
523 XSendEvent(xsd->display,
524 xsd->hostclipboard_writerequest_window,
525 False,
526 NoEventMask,
527 &e);
528 XFlush(xsd->display);
529 UNLOCK_X11
531 break;
533 } /* switch(event->type) */
537 /****************************************************************************************/