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 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 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 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 if (xsd
->hostclipboard_writebuffer
)
171 FreeVec(xsd
->hostclipboard_writebuffer
);
174 xsd
->hostclipboard_writebuffer
= newbuffer
;
175 xsd
->hostclipboard_writebuffer_size
= size
;
178 XSetSelectionOwner(xsd
->display
, xsd
->clipboard_atom
,
179 xsd
->dummy_window_for_creating_pixmaps
, xsd
->x_time
);
182 REQ_SUCCESS(msg
) = TRUE
;
183 REQ_RETVAL(msg
) = NULL
;
187 REQ_SUCCESS(msg
) = FALSE
;
188 REQ_RETVAL(msg
) = NULL
;
194 xsd
->hostclipboardmsg
= msg
;
202 /****************************************************************************************/
204 BOOL
x11clipboard_want_event(XEvent
*event
)
206 if ((event
->type
== SelectionNotify
) ||
207 (event
->type
== PropertyNotify
) ||
208 (event
->type
== SelectionRequest
))
216 /****************************************************************************************/
218 VOID
x11clipboard_handle_event(struct x11_staticdata
*xsd
, XEvent
*event
)
222 case SelectionNotify
:
223 D(bug("X11CLIPBOARD: SelectionNotify Event\n"));
225 if (xsd
->hostclipboardmsg
&& (xsd
->hostclipboard_readstate
== HOSTCLIPBOARDSTATE_READ
))
229 unsigned long nitems
;
230 unsigned long bytes_after
;
231 unsigned char *buffer
, *arosbuffer
;
234 XGetWindowProperty(xsd
->display
,
235 xsd
->dummy_window_for_creating_pixmaps
,
236 xsd
->clipboard_property_atom
,
249 if (actual_type
== xsd
->clipboard_incr_atom
)
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
);
259 xsd
->hostclipboard_readstate
= HOSTCLIPBOARDSTATE_READ_INCR
;
261 D(bug("X11CLIPBOARD: SelectionNotify - INCR protocol\n"));
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
);
274 XGetWindowProperty(xsd
->display
,
275 xsd
->dummy_window_for_creating_pixmaps
,
276 xsd
->clipboard_property_atom
,
287 XDeleteProperty(xsd
->display
,
288 xsd
->dummy_window_for_creating_pixmaps
,
289 xsd
->clipboard_property_atom
);
291 arosbuffer
= AllocVec(nitems
+ 1, MEMF_ANY
);
294 memcpy(arosbuffer
, buffer
, nitems
);
295 arosbuffer
[nitems
] = '\0';
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))*/
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
))
317 unsigned long nitems
;
318 unsigned long bytes_after
;
319 unsigned char *buffer
, *arosbuffer
;
321 D(bug("X11CLIPBOARD: PropertyNotify - property event okay\n"));
324 XGetWindowProperty(xsd
->display
,
325 xsd
->dummy_window_for_creating_pixmaps
,
326 xsd
->clipboard_property_atom
,
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
);
358 XGetWindowProperty(xsd
->display
,
359 xsd
->dummy_window_for_creating_pixmaps
,
360 xsd
->clipboard_property_atom
,
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
;
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
);
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
);
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
,
410 xsd
->hostclipboard_incrbuffer_size
+= nitems
;
411 xsd
->hostclipboard_incrbuffer
[xsd
->hostclipboard_incrbuffer_size
] = '\0';
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 ... */
432 } /* if (bytes_after == 0) else ... */
434 } /* if (actual_format == 8) */
437 XDeleteProperty(xsd
->display
,
438 xsd
->dummy_window_for_creating_pixmaps
,
439 xsd
->clipboard_property_atom
);
440 XFlush(xsd
->display
);
443 } /* if it's right property and the property has new value */
445 } /* if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ_INCR)) */
449 case SelectionRequest
:
450 D(bug("X11CLIPBOARD: SelectionRequest Event\n"));
452 if (xsd
->hostclipboard_writebuffer
)
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
};
474 XChangeProperty(xsd
->display
,
475 xsd
->hostclipboard_writerequest_window
,
476 xsd
->hostclipboard_writerequest_property
,
477 xsd
->clipboard_targets_atom
,
480 (unsigned char *)supported_targets
,
481 sizeof(supported_targets
) / sizeof(supported_targets
[0]));
485 else if (event
->xselectionrequest
.target
== XA_STRING
)
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
,
504 (unsigned char *)xsd
->hostclipboard_writebuffer
,
505 (int)xsd
->hostclipboard_writebuffer_size
);
509 /* FIXME TODO: Use INCR protocol for large requests */
511 e
.xselection
.property
= None
;
517 e
.xselection
.property
= None
;
520 D(bug("X11CLIPBOARD: SelectionRequest Event - sending SelectionNotify event to clipboard requestor\n"));
523 XSendEvent(xsd
->display
,
524 xsd
->hostclipboard_writerequest_window
,
528 XFlush(xsd
->display
);
533 } /* switch(event->type) */
537 /****************************************************************************************/