2 Copyright © 1995-2016, The AROS Development Team. All rights reserved.
5 Desc: X11 hidd. Host clipboard support.
11 #include <proto/exec.h>
13 #include <X11/Xatom.h>
15 #include "x11_types.h"
17 #include "x11_hostlib.h"
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
;
37 XCALL(XGetWindowAttributes
, xsd
->display
,
38 xsd
->dummy_window_for_creating_pixmaps
,
42 event
= xwa
.your_event_mask
| event
;
46 event
= xwa
.your_event_mask
&~ event
;
49 XCALL(XSelectInput
, xsd
->display
, xsd
->dummy_window_for_creating_pixmaps
, event
);
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
)
92 if (xsd
->hostclipboardmsg
) return;
94 D(bug("X11CLIPBOARD: handle_commands\n"));
95 while((msg
= GetMsg(xsd
->hostclipboardmp
)))
97 char cmd
= REQ_CMD(msg
);
100 REQ_SUCCESS(msg
) = FALSE
;
104 D(bug("X11CLIPBOARD: handle_commands - READ\n"));
106 if ((xsd
->hostclipboard_readstate
== HOSTCLIPBOARDSTATE_IDLE
))
109 XCALL(XConvertSelection
, xsd
->display
,
112 xsd
->clipboard_property_atom
,
113 xsd
->dummy_window_for_creating_pixmaps
,
118 xsd
->hostclipboard_readstate
= HOSTCLIPBOARDSTATE_READ
;
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
);
133 memcpy(newbuffer
, srcbuffer
, size
);
135 FreeVec(xsd
->hostclipboard_writebuffer
);
137 xsd
->hostclipboard_writebuffer
= newbuffer
;
138 xsd
->hostclipboard_writebuffer_size
= size
;
141 XCALL(XSetSelectionOwner
, xsd
->display
, xsd
->clipboard_atom
,
142 xsd
->dummy_window_for_creating_pixmaps
, xsd
->x_time
);
145 REQ_SUCCESS(msg
) = TRUE
;
146 REQ_RETVAL(msg
) = NULL
;
150 REQ_SUCCESS(msg
) = FALSE
;
151 REQ_RETVAL(msg
) = NULL
;
157 xsd
->hostclipboardmsg
= msg
;
165 /****************************************************************************************/
167 BOOL
x11clipboard_want_event(XEvent
*event
)
169 if ((event
->type
== SelectionNotify
) ||
170 (event
->type
== PropertyNotify
) ||
171 (event
->type
== SelectionRequest
))
179 /****************************************************************************************/
181 VOID
x11clipboard_handle_event(struct x11_staticdata
*xsd
, XEvent
*event
)
185 case SelectionNotify
:
186 D(bug("X11CLIPBOARD: SelectionNotify Event\n"));
188 if (xsd
->hostclipboardmsg
&& (xsd
->hostclipboard_readstate
== HOSTCLIPBOARDSTATE_READ
))
192 unsigned long nitems
;
193 unsigned long bytes_after
;
194 unsigned char *buffer
, *arosbuffer
;
197 XCALL(XGetWindowProperty
, xsd
->display
,
198 xsd
->dummy_window_for_creating_pixmaps
,
199 xsd
->clipboard_property_atom
,
209 XCALL(XFree
, buffer
);
212 if (actual_type
== xsd
->clipboard_incr_atom
)
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
);
222 xsd
->hostclipboard_readstate
= HOSTCLIPBOARDSTATE_READ_INCR
;
224 D(bug("X11CLIPBOARD: SelectionNotify - INCR protocol\n"));
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
);
237 XCALL(XGetWindowProperty
, xsd
->display
,
238 xsd
->dummy_window_for_creating_pixmaps
,
239 xsd
->clipboard_property_atom
,
250 XCALL(XDeleteProperty
, xsd
->display
,
251 xsd
->dummy_window_for_creating_pixmaps
,
252 xsd
->clipboard_property_atom
);
254 arosbuffer
= AllocVec(nitems
+ 1, MEMF_ANY
);
257 memcpy(arosbuffer
, buffer
, nitems
);
258 arosbuffer
[nitems
] = '\0';
260 XCALL(XFree
, buffer
);
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))*/
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
))
280 unsigned long nitems
;
281 unsigned long bytes_after
;
282 unsigned char *buffer
, *arosbuffer
;
284 D(bug("X11CLIPBOARD: PropertyNotify - property event okay\n"));
287 XCALL(XGetWindowProperty
, xsd
->display
,
288 xsd
->dummy_window_for_creating_pixmaps
,
289 xsd
->clipboard_property_atom
,
299 XCALL(XFree
, buffer
);
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
);
321 XCALL(XGetWindowProperty
, xsd
->display
,
322 xsd
->dummy_window_for_creating_pixmaps
,
323 xsd
->clipboard_property_atom
,
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
;
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
);
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
);
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
,
373 xsd
->hostclipboard_incrbuffer_size
+= nitems
;
374 xsd
->hostclipboard_incrbuffer
[xsd
->hostclipboard_incrbuffer_size
] = '\0';
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
);
395 } /* if (bytes_after == 0) else ... */
397 } /* if (actual_format == 8) */
400 XCALL(XDeleteProperty
, xsd
->display
,
401 xsd
->dummy_window_for_creating_pixmaps
,
402 xsd
->clipboard_property_atom
);
403 XCALL(XFlush
, xsd
->display
);
406 } /* if it's right property and the property has new value */
408 } /* if (xsd->hostclipboardmsg && (xsd->hostclipboard_readstate == HOSTCLIPBOARDSTATE_READ_INCR)) */
412 case SelectionRequest
:
413 D(bug("X11CLIPBOARD: SelectionRequest Event\n"));
415 if (xsd
->hostclipboard_writebuffer
)
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
};
437 XCALL(XChangeProperty
, xsd
->display
,
438 xsd
->hostclipboard_writerequest_window
,
439 xsd
->hostclipboard_writerequest_property
,
440 xsd
->clipboard_targets_atom
,
443 (unsigned char *)supported_targets
,
444 sizeof(supported_targets
) / sizeof(supported_targets
[0]));
448 else if (event
->xselectionrequest
.target
== XA_STRING
)
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
,
467 (unsigned char *)xsd
->hostclipboard_writebuffer
,
468 (int)xsd
->hostclipboard_writebuffer_size
);
472 /* FIXME TODO: Use INCR protocol for large requests */
474 e
.xselection
.property
= None
;
480 e
.xselection
.property
= None
;
483 D(bug("X11CLIPBOARD: SelectionRequest Event - sending SelectionNotify event to clipboard requestor\n"));
486 XCALL(XSendEvent
, xsd
->display
,
487 xsd
->hostclipboard_writerequest_window
,
491 XCALL(XFlush
, xsd
->display
);
496 } /* switch(event->type) */
500 /****************************************************************************************/