2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
5 Desc: X11 hidd. Host clipboard support.
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>
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>
33 #define timeval sys_timeval
34 #include <sys/types.h>
44 #include <X11/Xutil.h>
45 #include <X11/Xatom.h>
48 #include "x11gfx_intern.h"
51 #include <aros/debug.h>
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
;
71 XCALL(XGetWindowAttributes
, xsd
->display
,
72 xsd
->dummy_window_for_creating_pixmaps
,
76 event
= xwa
.your_event_mask
| event
;
80 event
= xwa
.your_event_mask
&~ event
;
83 XCALL(XSelectInput
, xsd
->display
, xsd
->dummy_window_for_creating_pixmaps
, event
);
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
)
126 if (xsd
->hostclipboardmsg
) return;
128 D(bug("X11CLIPBOARD: handle_commands\n"));
129 while((msg
= GetMsg(xsd
->hostclipboardmp
)))
131 char cmd
= REQ_CMD(msg
);
134 REQ_SUCCESS(msg
) = FALSE
;
138 D(bug("X11CLIPBOARD: handle_commands - READ\n"));
140 if ((xsd
->hostclipboard_readstate
== HOSTCLIPBOARDSTATE_IDLE
))
143 XCALL(XConvertSelection
, xsd
->display
,
146 xsd
->clipboard_property_atom
,
147 xsd
->dummy_window_for_creating_pixmaps
,
152 xsd
->hostclipboard_readstate
= HOSTCLIPBOARDSTATE_READ
;
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
);
167 memcpy(newbuffer
, srcbuffer
, size
);
169 FreeVec(xsd
->hostclipboard_writebuffer
);
171 xsd
->hostclipboard_writebuffer
= newbuffer
;
172 xsd
->hostclipboard_writebuffer_size
= size
;
175 XCALL(XSetSelectionOwner
, xsd
->display
, xsd
->clipboard_atom
,
176 xsd
->dummy_window_for_creating_pixmaps
, xsd
->x_time
);
179 REQ_SUCCESS(msg
) = TRUE
;
180 REQ_RETVAL(msg
) = NULL
;
184 REQ_SUCCESS(msg
) = FALSE
;
185 REQ_RETVAL(msg
) = NULL
;
191 xsd
->hostclipboardmsg
= msg
;
199 /****************************************************************************************/
201 BOOL
x11clipboard_want_event(XEvent
*event
)
203 if ((event
->type
== SelectionNotify
) ||
204 (event
->type
== PropertyNotify
) ||
205 (event
->type
== SelectionRequest
))
213 /****************************************************************************************/
215 VOID
x11clipboard_handle_event(struct x11_staticdata
*xsd
, XEvent
*event
)
219 case SelectionNotify
:
220 D(bug("X11CLIPBOARD: SelectionNotify Event\n"));
222 if (xsd
->hostclipboardmsg
&& (xsd
->hostclipboard_readstate
== HOSTCLIPBOARDSTATE_READ
))
226 unsigned long nitems
;
227 unsigned long bytes_after
;
228 unsigned char *buffer
, *arosbuffer
;
231 XCALL(XGetWindowProperty
, xsd
->display
,
232 xsd
->dummy_window_for_creating_pixmaps
,
233 xsd
->clipboard_property_atom
,
243 XCALL(XFree
, buffer
);
246 if (actual_type
== xsd
->clipboard_incr_atom
)
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
);
256 xsd
->hostclipboard_readstate
= HOSTCLIPBOARDSTATE_READ_INCR
;
258 D(bug("X11CLIPBOARD: SelectionNotify - INCR protocol\n"));
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
);
271 XCALL(XGetWindowProperty
, xsd
->display
,
272 xsd
->dummy_window_for_creating_pixmaps
,
273 xsd
->clipboard_property_atom
,
284 XCALL(XDeleteProperty
, xsd
->display
,
285 xsd
->dummy_window_for_creating_pixmaps
,
286 xsd
->clipboard_property_atom
);
288 arosbuffer
= AllocVec(nitems
+ 1, MEMF_ANY
);
291 memcpy(arosbuffer
, buffer
, nitems
);
292 arosbuffer
[nitems
] = '\0';
294 XCALL(XFree
, buffer
);
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))*/
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
))
314 unsigned long nitems
;
315 unsigned long bytes_after
;
316 unsigned char *buffer
, *arosbuffer
;
318 D(bug("X11CLIPBOARD: PropertyNotify - property event okay\n"));
321 XCALL(XGetWindowProperty
, xsd
->display
,
322 xsd
->dummy_window_for_creating_pixmaps
,
323 xsd
->clipboard_property_atom
,
333 XCALL(XFree
, buffer
);
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
);
355 XCALL(XGetWindowProperty
, xsd
->display
,
356 xsd
->dummy_window_for_creating_pixmaps
,
357 xsd
->clipboard_property_atom
,
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
;
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
);
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
);
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
,
407 xsd
->hostclipboard_incrbuffer_size
+= nitems
;
408 xsd
->hostclipboard_incrbuffer
[xsd
->hostclipboard_incrbuffer_size
] = '\0';
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
);
429 } /* if (bytes_after == 0) else ... */
431 } /* if (actual_format == 8) */
434 XCALL(XDeleteProperty
, xsd
->display
,
435 xsd
->dummy_window_for_creating_pixmaps
,
436 xsd
->clipboard_property_atom
);
437 XCALL(XFlush
, xsd
->display
);
440 } /* if it's right property and the property has new value */
442 } /* if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ_INCR)) */
446 case SelectionRequest
:
447 D(bug("X11CLIPBOARD: SelectionRequest Event\n"));
449 if (xsd
->hostclipboard_writebuffer
)
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
};
471 XCALL(XChangeProperty
, xsd
->display
,
472 xsd
->hostclipboard_writerequest_window
,
473 xsd
->hostclipboard_writerequest_property
,
474 xsd
->clipboard_targets_atom
,
477 (unsigned char *)supported_targets
,
478 sizeof(supported_targets
) / sizeof(supported_targets
[0]));
482 else if (event
->xselectionrequest
.target
== XA_STRING
)
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
,
501 (unsigned char *)xsd
->hostclipboard_writebuffer
,
502 (int)xsd
->hostclipboard_writebuffer_size
);
506 /* FIXME TODO: Use INCR protocol for large requests */
508 e
.xselection
.property
= None
;
514 e
.xselection
.property
= None
;
517 D(bug("X11CLIPBOARD: SelectionRequest Event - sending SelectionNotify event to clipboard requestor\n"));
520 XCALL(XSendEvent
, xsd
->display
,
521 xsd
->hostclipboard_writerequest_window
,
525 XCALL(XFlush
, xsd
->display
);
530 } /* switch(event->type) */
534 /****************************************************************************************/