1 /* vdagent-x11.c vdagent x11 code
3 Copyright 2010 Red Hat, Inc.
6 Hans de Goede <hdegoede@redhat.com>
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /* Note *all* X11 calls in this file which do not wait for a result must be
23 followed by an XFlush, given that the X11 code pumping the event loop
24 (and thus flushing queued writes) is only called when there is data to be
25 read from the X11 socket. */
31 #include <X11/Xatom.h>
33 #include <X11/extensions/Xrandr.h>
34 #include <X11/extensions/Xfixes.h>
35 #include "vdagentd-proto.h"
36 #include "vdagent-x11.h"
38 enum { owner_none
, owner_guest
, owner_client
};
40 const char *utf8_atom_names
[] = {
42 "text/plain;charset=UTF-8",
43 "text/plain;charset=utf-8",
46 #define utf8_atom_count (sizeof(utf8_atom_names)/sizeof(utf8_atom_names[0]))
48 struct vdagent_x11_selection_request
{
50 struct vdagent_x11_selection_request
*next
;
59 Atom utf8_atoms
[utf8_atom_count
];
61 Window selection_window
;
62 struct udscs_connection
*vdagentd
;
70 int xfixes_event_base
;
71 int expected_targets_notifies
;
72 int expect_property_notify
;
74 Atom clipboard_request_target
;
75 int clipboard_type_count
;
76 /* TODO Add support for more types here */
77 /* Warning the size of these needs to be increased each time we add
78 support for a new type!! */
79 uint32_t clipboard_agent_types
[1];
80 Atom clipboard_x11_targets
[1];
81 uint8_t *clipboard_data
;
82 uint32_t clipboard_data_size
;
83 uint32_t clipboard_data_space
;
84 struct vdagent_x11_selection_request
*selection_request
;
87 static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11
*x11
);
88 static void vdagent_x11_handle_selection_notify(struct vdagent_x11
*x11
,
89 XEvent
*event
, int incr
);
90 static void vdagent_x11_handle_selection_request(struct vdagent_x11
*x11
);
91 static void vdagent_x11_handle_targets_notify(struct vdagent_x11
*x11
,
92 XEvent
*event
, int incr
);
93 static void vdagent_x11_send_selection_notify(struct vdagent_x11
*x11
,
95 int process_next_req
);
97 struct vdagent_x11
*vdagent_x11_create(struct udscs_connection
*vdagentd
,
100 struct vdagent_x11
*x11
;
101 XWindowAttributes attrib
;
104 x11
= calloc(1, sizeof(*x11
));
106 fprintf(stderr
, "out of memory allocating vdagent_x11 struct\n");
110 x11
->vdagentd
= vdagentd
;
111 x11
->verbose
= verbose
;
113 x11
->display
= XOpenDisplay(NULL
);
115 fprintf(stderr
, "could not connect to X-server\n");
120 x11
->screen
= DefaultScreen(x11
->display
);
121 x11
->root_window
= RootWindow(x11
->display
, x11
->screen
);
122 x11
->fd
= ConnectionNumber(x11
->display
);
123 x11
->clipboard_atom
= XInternAtom(x11
->display
, "CLIPBOARD", False
);
124 x11
->targets_atom
= XInternAtom(x11
->display
, "TARGETS", False
);
125 x11
->incr_atom
= XInternAtom(x11
->display
, "INCR", False
);
126 x11
->multiple_atom
= XInternAtom(x11
->display
, "MULTIPLE", False
);
127 for(i
= 0; i
< utf8_atom_count
; i
++)
128 x11
->utf8_atoms
[i
] = XInternAtom(x11
->display
, utf8_atom_names
[i
],
131 /* We should not store properties (for selections) on the root window */
132 x11
->selection_window
= XCreateSimpleWindow(x11
->display
, x11
->root_window
,
133 0, 0, 1, 1, 0, 0, 0);
135 fprintf(stderr
, "Selection window: %u\n",
136 (unsigned int)x11
->selection_window
);
138 if (XRRQueryExtension(x11
->display
, &i
, &i
))
141 fprintf(stderr
, "no xrandr\n");
143 if (XFixesQueryExtension(x11
->display
, &x11
->xfixes_event_base
, &i
) &&
144 XFixesQueryVersion(x11
->display
, &major
, &minor
) && major
>= 1) {
146 XFixesSelectSelectionInput(x11
->display
, x11
->root_window
,
148 XFixesSetSelectionOwnerNotifyMask
);
150 fprintf(stderr
, "no xfixes, no guest -> client copy paste support\n");
152 /* Catch resolution changes */
153 XSelectInput(x11
->display
, x11
->root_window
, StructureNotifyMask
);
155 /* Get the current resolution */
156 XGetWindowAttributes(x11
->display
, x11
->root_window
, &attrib
);
157 x11
->width
= attrib
.width
;
158 x11
->height
= attrib
.height
;
159 vdagent_x11_send_daemon_guest_xorg_res(x11
);
161 /* No need for XFlush as XGetWindowAttributes does an implicit Xflush */
166 void vdagent_x11_destroy(struct vdagent_x11
*x11
)
171 XCloseDisplay(x11
->display
);
175 int vdagent_x11_get_fd(struct vdagent_x11
*x11
)
180 static void vdagent_x11_set_clipboard_owner(struct vdagent_x11
*x11
,
183 /* Clear pending requests and clipboard data */
184 if (x11
->selection_request
) {
186 "selection requests pending on clipboard ownership change, "
188 while (x11
->selection_request
)
189 vdagent_x11_send_selection_notify(x11
, None
, 0);
191 x11
->clipboard_data_size
= 0;
192 x11
->clipboard_request_target
= None
;
193 x11
->expect_property_notify
= 0;
195 if (new_owner
== owner_none
) {
196 /* When going from owner_guest to owner_none we need to send a
197 clipboard release message to the client */
198 if (x11
->clipboard_owner
== owner_guest
)
199 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_RELEASE
, 0, NULL
, 0);
201 x11
->clipboard_type_count
= 0;
203 x11
->clipboard_owner
= new_owner
;
206 static void vdagent_x11_handle_event(struct vdagent_x11
*x11
, XEvent event
)
211 if (event
.type
== x11
->xfixes_event_base
) {
214 XFixesSelectionNotifyEvent xfev
;
218 if (ev
.xfev
.subtype
!= XFixesSetSelectionOwnerNotify
) {
220 fprintf(stderr
, "unexpected xfix event subtype %d window %d\n",
221 (int)ev
.xfev
.subtype
, (int)event
.xany
.window
);
226 fprintf(stderr
, "New selection owner: %u\n",
227 (unsigned int)ev
.xfev
.owner
);
229 /* Ignore becoming the owner ourselves */
230 if (ev
.xfev
.owner
== x11
->selection_window
)
233 /* If the clipboard owner is changed we no longer own it */
234 vdagent_x11_set_clipboard_owner(x11
, owner_none
);
236 if (ev
.xfev
.owner
== None
)
239 /* Request the supported targets from the new owner */
240 XConvertSelection(x11
->display
, x11
->clipboard_atom
, x11
->targets_atom
,
241 x11
->targets_atom
, x11
->selection_window
,
243 XFlush(x11
->display
);
244 x11
->expected_targets_notifies
++;
248 switch (event
.type
) {
249 case ConfigureNotify
:
250 if (event
.xconfigure
.window
!= x11
->root_window
)
255 if (event
.xconfigure
.width
== x11
->width
&&
256 event
.xconfigure
.height
== x11
->height
)
259 x11
->width
= event
.xconfigure
.width
;
260 x11
->height
= event
.xconfigure
.height
;
262 vdagent_x11_send_daemon_guest_xorg_res(x11
);
264 case SelectionNotify
:
265 if (event
.xselection
.target
== x11
->targets_atom
)
266 vdagent_x11_handle_targets_notify(x11
, &event
, 0);
268 vdagent_x11_handle_selection_notify(x11
, &event
, 0);
274 if (!x11
->expect_property_notify
||
275 event
.xproperty
.state
!= PropertyNewValue
)
278 if (event
.xproperty
.atom
== x11
->targets_atom
)
279 vdagent_x11_handle_targets_notify(x11
, &event
, 1);
281 vdagent_x11_handle_selection_notify(x11
, &event
, 1);
284 /* Do nothing the clipboard ownership will get updated through
285 the XFixesSetSelectionOwnerNotify event */
288 case SelectionRequest
: {
289 struct vdagent_x11_selection_request
*req
, *new_req
;
291 new_req
= malloc(sizeof(*new_req
));
293 fprintf(stderr
, "out of memory on SelectionRequest, ignoring.\n");
299 new_req
->event
= event
;
300 new_req
->next
= NULL
;
302 if (!x11
->selection_request
) {
303 x11
->selection_request
= new_req
;
304 vdagent_x11_handle_selection_request(x11
);
308 /* maybe we should limit the selection_request stack depth ? */
309 req
= x11
->selection_request
;
317 if (!handled
&& x11
->verbose
)
318 fprintf(stderr
, "unhandled x11 event, type %d, window %d\n",
319 (int)event
.type
, (int)event
.xany
.window
);
322 void vdagent_x11_do_read(struct vdagent_x11
*x11
)
326 while (XPending(x11
->display
)) {
327 XNextEvent(x11
->display
, &event
);
328 vdagent_x11_handle_event(x11
, event
);
332 static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11
*x11
)
334 struct vdagentd_guest_xorg_resolution res
;
336 res
.width
= x11
->width
;
337 res
.height
= x11
->height
;
339 udscs_write(x11
->vdagentd
, VDAGENTD_GUEST_XORG_RESOLUTION
, 0,
340 (uint8_t *)&res
, sizeof(res
));
343 static const char *vdagent_x11_get_atom_name(struct vdagent_x11
*x11
, Atom a
)
348 return XGetAtomName(x11
->display
, a
);
351 static int vdagent_x11_get_selection(struct vdagent_x11
*x11
, XEvent
*event
,
352 Atom type
, Atom prop
, int format
,
353 unsigned char **data_ret
, int incr
)
355 Bool del
= incr
? True
: False
;
357 int format_ret
, ret_val
= -1;
358 unsigned long len
, remain
;
359 unsigned char *data
= NULL
;
362 if (event
->xproperty
.atom
!= prop
) {
363 fprintf(stderr
, "PropertyNotify parameters mismatch\n");
367 if (event
->xselection
.property
== None
) {
369 fprintf(stderr
, "XConvertSelection refused by clipboard owner\n");
373 if (event
->xselection
.requestor
!= x11
->selection_window
||
374 event
->xselection
.selection
!= x11
->clipboard_atom
||
375 event
->xselection
.property
!= prop
) {
376 fprintf(stderr
, "SelectionNotify parameters mismatch\n");
381 /* FIXME when we've incr support we should not immediately
382 delete the property (as we need to first register for
383 property change events) */
384 if (XGetWindowProperty(x11
->display
, x11
->selection_window
, prop
, 0,
385 LONG_MAX
, del
, type
, &type_ret
, &format_ret
, &len
,
386 &remain
, &data
) != Success
) {
387 fprintf(stderr
, "XGetWindowProperty failed\n");
392 if (type_ret
== x11
->incr_atom
) {
393 int prop_min_size
= *(uint32_t*)data
;
395 if (x11
->expect_property_notify
) {
397 "received an incr property notify while "
398 "still reading another incr property\n");
402 if (x11
->clipboard_data_space
< prop_min_size
) {
403 free(x11
->clipboard_data
);
404 x11
->clipboard_data
= malloc(prop_min_size
);
405 if (!x11
->clipboard_data
) {
407 "out of memory allocating clipboard buffer\n");
408 x11
->clipboard_data_space
= 0;
411 x11
->clipboard_data_space
= prop_min_size
;
413 x11
->expect_property_notify
= 1;
414 XSelectInput(x11
->display
, x11
->selection_window
,
416 XDeleteProperty(x11
->display
, x11
->selection_window
, prop
);
417 XFlush(x11
->display
);
419 return 0; /* Wait for more data */
421 XDeleteProperty(x11
->display
, x11
->selection_window
, prop
);
422 XFlush(x11
->display
);
425 if (type_ret
!= type
) {
426 fprintf(stderr
, "expected property type: %s, got: %s\n",
427 vdagent_x11_get_atom_name(x11
, type
),
428 vdagent_x11_get_atom_name(x11
, type_ret
));
432 if (format_ret
!= format
) {
433 fprintf(stderr
, "expected %d bit format, got %d bits\n", format
,
438 /* Convert len to bytes */
443 len
*= sizeof(short);
452 if (x11
->clipboard_data_size
+ len
> x11
->clipboard_data_space
) {
453 void *old_clipboard_data
= x11
->clipboard_data
;
455 x11
->clipboard_data_space
= x11
->clipboard_data_size
+ len
;
456 x11
->clipboard_data
= realloc(x11
->clipboard_data
,
457 x11
->clipboard_data_space
);
458 if (!x11
->clipboard_data
) {
460 "out of memory allocating clipboard buffer\n");
461 x11
->clipboard_data_space
= 0;
462 free(old_clipboard_data
);
466 memcpy(x11
->clipboard_data
+ x11
->clipboard_data_size
, data
, len
);
467 x11
->clipboard_data_size
+= len
;
469 fprintf(stderr
, "Appended %ld bytes to buffer\n", len
);
471 return 0; /* Wait for more data */
473 len
= x11
->clipboard_data_size
;
474 *data_ret
= x11
->clipboard_data
;
481 fprintf(stderr
, "property contains no data (zero length)\n");
484 if ((incr
|| ret_val
== -1) && data
)
488 x11
->clipboard_data_size
= 0;
489 x11
->expect_property_notify
= 0;
495 static void vdagent_x11_get_selection_free(struct vdagent_x11
*x11
,
496 unsigned char *data
, int incr
)
499 /* If the clipboard has grown large return the memory to the system */
500 if (x11
->clipboard_data_space
> 512 * 1024) {
501 free(x11
->clipboard_data
);
502 x11
->clipboard_data
= NULL
;
503 x11
->clipboard_data_space
= 0;
509 static uint32_t vdagent_x11_target_to_type(struct vdagent_x11
*x11
,
515 return VD_AGENT_CLIPBOARD_NONE
;
517 for (i
= 0; i
< utf8_atom_count
; i
++)
518 if (x11
->utf8_atoms
[i
] == target
)
519 return VD_AGENT_CLIPBOARD_UTF8_TEXT
;
521 /* TODO Add support for more types here */
523 fprintf(stderr
, "unexpected selection type %s\n",
524 vdagent_x11_get_atom_name(x11
, target
));
525 return VD_AGENT_CLIPBOARD_NONE
;
528 static Atom
vdagent_x11_type_to_target(struct vdagent_x11
*x11
, uint32_t type
)
532 for (i
= 0; i
< x11
->clipboard_type_count
; i
++)
533 if (x11
->clipboard_agent_types
[i
] == type
)
534 return x11
->clipboard_x11_targets
[i
];
536 fprintf(stderr
, "client requested unavailable type %u\n", type
);
540 static void vdagent_x11_handle_selection_notify(struct vdagent_x11
*x11
,
541 XEvent
*event
, int incr
)
544 unsigned char *data
= NULL
;
547 type
= vdagent_x11_target_to_type(x11
, x11
->clipboard_request_target
);
549 if (x11
->clipboard_request_target
== None
)
550 fprintf(stderr
, "SelectionNotify received without a target\n");
552 event
->xselection
.target
!= x11
->clipboard_request_target
)
553 fprintf(stderr
, "Requested %s target got %s\n",
554 vdagent_x11_get_atom_name(x11
, x11
->clipboard_request_target
),
555 vdagent_x11_get_atom_name(x11
, event
->xselection
.target
));
557 len
= vdagent_x11_get_selection(x11
, event
, event
->xselection
.target
,
558 x11
->clipboard_atom
, 8, &data
, incr
);
559 if (len
== 0) /* waiting for more data? */
562 type
= VD_AGENT_CLIPBOARD_NONE
;
566 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
, type
, data
, len
);
567 x11
->clipboard_request_target
= None
;
568 vdagent_x11_get_selection_free(x11
, data
, incr
);
571 static Atom
atom_lists_overlap(Atom
*atoms1
, Atom
*atoms2
, int l1
, int l2
)
575 for (i
= 0; i
< l1
; i
++)
576 for (j
= 0; j
< l2
; j
++)
577 if (atoms1
[i
] == atoms2
[j
])
583 static void vdagent_x11_print_targets(struct vdagent_x11
*x11
,
584 const char *action
, Atom
*atoms
, int c
)
591 fprintf(stderr
, "%s %d targets:\n", action
, c
);
592 for (i
= 0; i
< c
; i
++)
593 fprintf(stderr
, "%s\n", vdagent_x11_get_atom_name(x11
, atoms
[i
]));
596 static void vdagent_x11_handle_targets_notify(struct vdagent_x11
*x11
,
597 XEvent
*event
, int incr
)
600 Atom atom
, *atoms
= NULL
;
602 if (!x11
->expected_targets_notifies
) {
603 fprintf(stderr
, "unexpected selection notify TARGETS\n");
607 x11
->expected_targets_notifies
--;
609 /* If we have more targets_notifies pending, ignore this one, we
610 are only interested in the targets list of the current owner
611 (which is the last one we've requested a targets list from) */
612 if (x11
->expected_targets_notifies
)
615 len
= vdagent_x11_get_selection(x11
, event
, XA_ATOM
, x11
->targets_atom
, 32,
616 (unsigned char **)&atoms
, incr
);
617 if (len
== 0 || len
== -1) /* waiting for more data or error? */
622 vdagent_x11_print_targets(x11
, "received", atoms
, len
);
624 x11
->clipboard_type_count
= 0;
625 atom
= atom_lists_overlap(x11
->utf8_atoms
, atoms
, utf8_atom_count
, len
);
627 x11
->clipboard_agent_types
[x11
->clipboard_type_count
] =
628 VD_AGENT_CLIPBOARD_UTF8_TEXT
;
629 x11
->clipboard_x11_targets
[x11
->clipboard_type_count
] = atom
;
630 x11
->clipboard_type_count
++;
633 /* TODO Add support for more types here */
635 if (x11
->clipboard_type_count
) {
636 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_GRAB
, 0,
637 (uint8_t *)x11
->clipboard_agent_types
,
638 x11
->clipboard_type_count
* sizeof(uint32_t));
639 vdagent_x11_set_clipboard_owner(x11
, owner_guest
);
642 vdagent_x11_get_selection_free(x11
, (unsigned char *)atoms
, incr
);
645 static void vdagent_x11_send_selection_notify(struct vdagent_x11
*x11
,
646 Atom prop
, int process_next_req
)
648 XEvent res
, *event
= &x11
->selection_request
->event
;
649 struct vdagent_x11_selection_request
*selection_request
;
651 res
.xselection
.property
= prop
;
652 res
.xselection
.type
= SelectionNotify
;
653 res
.xselection
.display
= event
->xselectionrequest
.display
;
654 res
.xselection
.requestor
= event
->xselectionrequest
.requestor
;
655 res
.xselection
.selection
= event
->xselectionrequest
.selection
;
656 res
.xselection
.target
= event
->xselectionrequest
.target
;
657 res
.xselection
.time
= event
->xselectionrequest
.time
;
658 XSendEvent(x11
->display
, event
->xselectionrequest
.requestor
, 0, 0, &res
);
659 XFlush(x11
->display
);
661 selection_request
= x11
->selection_request
;
662 x11
->selection_request
= selection_request
->next
;
663 free(selection_request
);
664 if (process_next_req
)
665 vdagent_x11_handle_selection_request(x11
);
668 static void vdagent_x11_send_targets(struct vdagent_x11
*x11
, XEvent
*event
)
670 /* TODO Add support for more types here */
671 /* Warning the size of this needs to be increased each time we add support
672 for a new type, or the atom count of an existing type changes */
673 Atom prop
, targets
[4] = { x11
->targets_atom
, };
674 int i
, j
, target_count
= 1;
676 for (i
= 0; i
< x11
->clipboard_type_count
; i
++) {
677 switch (x11
->clipboard_agent_types
[i
]) {
678 case VD_AGENT_CLIPBOARD_UTF8_TEXT
:
679 for (j
= 0; j
< utf8_atom_count
; j
++) {
680 targets
[target_count
] = x11
->utf8_atoms
[j
];
684 /* TODO Add support for more types here */
688 prop
= event
->xselectionrequest
.property
;
690 prop
= event
->xselectionrequest
.target
;
692 XChangeProperty(x11
->display
, event
->xselectionrequest
.requestor
, prop
,
693 XA_ATOM
, 32, PropModeReplace
, (unsigned char *)&targets
,
695 vdagent_x11_print_targets(x11
, "sent", targets
, target_count
);
696 vdagent_x11_send_selection_notify(x11
, prop
, 1);
699 static void vdagent_x11_handle_selection_request(struct vdagent_x11
*x11
)
702 uint32_t type
= VD_AGENT_CLIPBOARD_NONE
;
704 if (!x11
->selection_request
)
707 event
= &x11
->selection_request
->event
;
709 if (x11
->clipboard_owner
!= owner_client
) {
711 "received selection request event for target %s, "
712 "while not owning client clipboard\n",
713 vdagent_x11_get_atom_name(x11
, event
->xselectionrequest
.target
));
714 vdagent_x11_send_selection_notify(x11
, None
, 1);
718 if (event
->xselectionrequest
.target
== x11
->multiple_atom
) {
719 fprintf(stderr
, "multiple target not supported\n");
720 vdagent_x11_send_selection_notify(x11
, None
, 1);
724 if (event
->xselectionrequest
.target
== x11
->targets_atom
) {
725 vdagent_x11_send_targets(x11
, event
);
729 type
= vdagent_x11_target_to_type(x11
, event
->xselectionrequest
.target
);
730 if (type
== VD_AGENT_CLIPBOARD_NONE
) {
731 vdagent_x11_send_selection_notify(x11
, None
, 1);
735 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_REQUEST
, type
, NULL
, 0);
738 void vdagent_x11_set_monitor_config(struct vdagent_x11
*x11
,
739 VDAgentMonitorsConfig
*mon_config
)
741 int i
, num_sizes
= 0;
743 unsigned int closest_diff
= -1;
744 XRRScreenSize
* sizes
;
745 XRRScreenConfiguration
* config
;
748 if (!x11
->has_xrandr
)
751 if (mon_config
->num_of_monitors
!= 1) {
752 fprintf(stderr
, "Only 1 monitor supported, ignoring monitor config\n");
756 sizes
= XRRSizes(x11
->display
, x11
->screen
, &num_sizes
);
757 if (!sizes
|| !num_sizes
) {
758 fprintf(stderr
, "XRRSizes failed\n");
762 /* Find the closest size which will fit within the monitor */
763 for (i
= 0; i
< num_sizes
; i
++) {
764 if (sizes
[i
].width
> mon_config
->monitors
[0].width
||
765 sizes
[i
].height
> mon_config
->monitors
[0].height
)
766 continue; /* Too large for the monitor */
768 unsigned int wdiff
= mon_config
->monitors
[0].width
- sizes
[i
].width
;
769 unsigned int hdiff
= mon_config
->monitors
[0].height
- sizes
[i
].height
;
770 unsigned int diff
= wdiff
* wdiff
+ hdiff
* hdiff
;
771 if (diff
< closest_diff
) {
778 fprintf(stderr
, "no suitable resolution found for monitor\n");
782 config
= XRRGetScreenInfo(x11
->display
, x11
->root_window
);
784 fprintf(stderr
, "get screen info failed\n");
787 XRRConfigCurrentConfiguration(config
, &rotation
);
788 XRRSetScreenConfig(x11
->display
, config
, x11
->root_window
, best
,
789 rotation
, CurrentTime
);
790 XRRFreeScreenConfigInfo(config
);
791 XFlush(x11
->display
);
794 void vdagent_x11_clipboard_request(struct vdagent_x11
*x11
, uint32_t type
)
798 if (x11
->clipboard_owner
!= owner_guest
) {
800 "received clipboard req while not owning guest clipboard\n");
801 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
802 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
806 target
= vdagent_x11_type_to_target(x11
, type
);
807 if (target
== None
) {
808 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
809 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
813 if (x11
->clipboard_request_target
) {
814 fprintf(stderr
, "XConvertSelection request is already pending\n");
815 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
816 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
819 x11
->clipboard_request_target
= target
;
820 XConvertSelection(x11
->display
, x11
->clipboard_atom
, target
,
821 x11
->clipboard_atom
, x11
->selection_window
, CurrentTime
);
822 XFlush(x11
->display
);
825 void vdagent_x11_clipboard_grab(struct vdagent_x11
*x11
, uint32_t *types
,
830 x11
->clipboard_type_count
= 0;
831 for (i
= 0; i
< type_count
; i
++) {
832 /* TODO Add support for more types here */
833 /* Check if we support the type */
834 if (types
[i
] != VD_AGENT_CLIPBOARD_UTF8_TEXT
)
837 x11
->clipboard_agent_types
[x11
->clipboard_type_count
] = types
[i
];
838 x11
->clipboard_type_count
++;
841 if (!x11
->clipboard_type_count
)
844 XSetSelectionOwner(x11
->display
, x11
->clipboard_atom
,
845 x11
->selection_window
, CurrentTime
);
846 XFlush(x11
->display
);
847 vdagent_x11_set_clipboard_owner(x11
, owner_client
);
850 void vdagent_x11_clipboard_data(struct vdagent_x11
*x11
, uint32_t type
,
851 const uint8_t *data
, uint32_t size
)
855 uint32_t type_from_event
;
857 if (!x11
->selection_request
) {
858 fprintf(stderr
, "received clipboard data without an outstanding"
859 "selection request, ignoring\n");
863 event
= &x11
->selection_request
->event
;
864 type_from_event
= vdagent_x11_target_to_type(x11
,
865 event
->xselectionrequest
.target
);
866 if (type_from_event
!= type
) {
867 fprintf(stderr
, "expecting type %u clipboard data got %u\n",
868 type_from_event
, type
);
869 vdagent_x11_send_selection_notify(x11
, None
, 1);
873 prop
= event
->xselectionrequest
.property
;
875 prop
= event
->xselectionrequest
.target
;
877 /* FIXME: use INCR for large data transfers */
878 XChangeProperty(x11
->display
, event
->xselectionrequest
.requestor
, prop
,
879 event
->xselectionrequest
.target
, 8, PropModeReplace
,
881 vdagent_x11_send_selection_notify(x11
, prop
, 1);
884 void vdagent_x11_clipboard_release(struct vdagent_x11
*x11
)
888 if (x11
->clipboard_owner
!= owner_client
) {
890 "received clipboard release while not owning client clipboard\n");
894 XSetSelectionOwner(x11
->display
, x11
->clipboard_atom
, None
, CurrentTime
);
895 /* Make sure we process the XFixesSetSelectionOwnerNotify event caused
896 by this, so we don't end up changing the clipboard owner to none, after
897 it has already been re-owned because this event is still pending. */
898 XSync(x11
->display
, False
);
899 while (XCheckTypedEvent(x11
->display
, x11
->xfixes_event_base
,
901 vdagent_x11_handle_event(x11
, event
);
903 /* Note no need to do a set_clipboard_owner(owner_none) here, as that is
904 already done by processing the XFixesSetSelectionOwnerNotify event. */