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. */
30 #include <X11/Xatom.h>
32 #include <X11/extensions/Xrandr.h>
33 #include <X11/extensions/Xfixes.h>
34 #include "vdagentd-proto.h"
35 #include "vdagent-x11.h"
37 enum { owner_none
, owner_guest
, owner_client
};
39 struct vdagent_x11_selection_request
{
41 struct vdagent_x11_selection_request
*next
;
44 struct clipboard_format_tmpl
{
46 const char *atom_names
[16];
49 struct clipboard_format_info
{
55 static const struct clipboard_format_tmpl clipboard_format_templates
[] = {
56 { VD_AGENT_CLIPBOARD_UTF8_TEXT
, { "UTF8_STRING",
57 "text/plain;charset=UTF-8", "text/plain;charset=utf-8", NULL
}, },
58 { VD_AGENT_CLIPBOARD_IMAGE_PNG
, { "image/png", NULL
}, },
59 { VD_AGENT_CLIPBOARD_IMAGE_BMP
, { "image/bmp", "image/x-bmp",
60 "image/x-MS-bmp", "image/x-win-bitmap", NULL
}, },
61 { VD_AGENT_CLIPBOARD_IMAGE_TIFF
, { "image/tiff", NULL
}, },
62 { VD_AGENT_CLIPBOARD_IMAGE_JPG
, { "image/jpeg", NULL
}, },
65 #define clipboard_format_count (sizeof(clipboard_format_templates)/sizeof(clipboard_format_templates[0]))
68 struct clipboard_format_info clipboard_formats
[clipboard_format_count
];
75 Window selection_window
;
76 struct udscs_connection
*vdagentd
;
85 int xfixes_event_base
;
86 int expected_targets_notifies
;
87 int expect_property_notify
;
89 Atom clipboard_request_target
;
90 int clipboard_type_count
;
91 uint32_t clipboard_agent_types
[256];
92 Atom clipboard_x11_targets
[256];
93 uint8_t *clipboard_data
;
94 uint32_t clipboard_data_size
;
95 uint32_t clipboard_data_space
;
96 struct vdagent_x11_selection_request
*selection_request
;
99 static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11
*x11
);
100 static void vdagent_x11_handle_selection_notify(struct vdagent_x11
*x11
,
101 XEvent
*event
, int incr
);
102 static void vdagent_x11_handle_selection_request(struct vdagent_x11
*x11
);
103 static void vdagent_x11_handle_targets_notify(struct vdagent_x11
*x11
,
104 XEvent
*event
, int incr
);
105 static void vdagent_x11_send_selection_notify(struct vdagent_x11
*x11
,
107 int process_next_req
);
109 struct vdagent_x11
*vdagent_x11_create(struct udscs_connection
*vdagentd
,
110 FILE *errfile
, int verbose
)
112 struct vdagent_x11
*x11
;
113 XWindowAttributes attrib
;
114 int i
, j
, major
, minor
;
116 x11
= calloc(1, sizeof(*x11
));
118 fprintf(errfile
, "out of memory allocating vdagent_x11 struct\n");
122 x11
->vdagentd
= vdagentd
;
123 x11
->errfile
= errfile
;
124 x11
->verbose
= verbose
;
126 x11
->display
= XOpenDisplay(NULL
);
128 fprintf(x11
->errfile
, "could not connect to X-server\n");
133 x11
->screen
= DefaultScreen(x11
->display
);
134 x11
->root_window
= RootWindow(x11
->display
, x11
->screen
);
135 x11
->fd
= ConnectionNumber(x11
->display
);
136 x11
->clipboard_atom
= XInternAtom(x11
->display
, "CLIPBOARD", False
);
137 x11
->targets_atom
= XInternAtom(x11
->display
, "TARGETS", False
);
138 x11
->incr_atom
= XInternAtom(x11
->display
, "INCR", False
);
139 x11
->multiple_atom
= XInternAtom(x11
->display
, "MULTIPLE", False
);
140 for(i
= 0; i
< clipboard_format_count
; i
++) {
141 x11
->clipboard_formats
[i
].type
= clipboard_format_templates
[i
].type
;
142 for(j
= 0; clipboard_format_templates
[i
].atom_names
[j
]; j
++) {
143 x11
->clipboard_formats
[i
].atoms
[j
] =
144 XInternAtom(x11
->display
,
145 clipboard_format_templates
[i
].atom_names
[j
],
148 x11
->clipboard_formats
[i
].atom_count
= j
;
151 /* We should not store properties (for selections) on the root window */
152 x11
->selection_window
= XCreateSimpleWindow(x11
->display
, x11
->root_window
,
153 0, 0, 1, 1, 0, 0, 0);
155 fprintf(x11
->errfile
, "Selection window: %u\n",
156 (unsigned int)x11
->selection_window
);
158 if (XRRQueryExtension(x11
->display
, &i
, &i
))
161 fprintf(x11
->errfile
, "no xrandr\n");
163 if (XFixesQueryExtension(x11
->display
, &x11
->xfixes_event_base
, &i
) &&
164 XFixesQueryVersion(x11
->display
, &major
, &minor
) && major
>= 1) {
166 XFixesSelectSelectionInput(x11
->display
, x11
->root_window
,
168 XFixesSetSelectionOwnerNotifyMask
|
169 XFixesSelectionWindowDestroyNotifyMask
|
170 XFixesSelectionClientCloseNotifyMask
);
172 fprintf(x11
->errfile
,
173 "no xfixes, no guest -> client copy paste support\n");
175 /* Catch resolution changes */
176 XSelectInput(x11
->display
, x11
->root_window
, StructureNotifyMask
);
178 /* Get the current resolution */
179 XGetWindowAttributes(x11
->display
, x11
->root_window
, &attrib
);
180 x11
->width
= attrib
.width
;
181 x11
->height
= attrib
.height
;
182 vdagent_x11_send_daemon_guest_xorg_res(x11
);
184 /* No need for XFlush as XGetWindowAttributes does an implicit Xflush */
189 void vdagent_x11_destroy(struct vdagent_x11
*x11
)
194 XCloseDisplay(x11
->display
);
198 int vdagent_x11_get_fd(struct vdagent_x11
*x11
)
203 static void vdagent_x11_set_clipboard_owner(struct vdagent_x11
*x11
,
206 /* Clear pending requests and clipboard data */
207 if (x11
->selection_request
) {
208 fprintf(x11
->errfile
,
209 "selection requests pending on clipboard ownership change, "
211 while (x11
->selection_request
)
212 vdagent_x11_send_selection_notify(x11
, None
, 0);
214 if (x11
->clipboard_request_target
!= None
) {
215 fprintf(x11
->errfile
,
216 "client clipboard request pending on clipboard ownership "
218 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
219 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
220 x11
->clipboard_request_target
= None
;
222 x11
->clipboard_data_size
= 0;
223 x11
->expect_property_notify
= 0;
225 if (new_owner
== owner_none
) {
226 /* When going from owner_guest to owner_none we need to send a
227 clipboard release message to the client */
228 if (x11
->clipboard_owner
== owner_guest
)
229 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_RELEASE
, 0, NULL
, 0);
231 x11
->clipboard_type_count
= 0;
233 x11
->clipboard_owner
= new_owner
;
236 static void vdagent_x11_handle_event(struct vdagent_x11
*x11
, XEvent event
)
241 if (event
.type
== x11
->xfixes_event_base
) {
244 XFixesSelectionNotifyEvent xfev
;
248 switch (ev
.xfev
.subtype
) {
249 case XFixesSetSelectionOwnerNotify
:
251 /* Treat ... as a SelectionOwnerNotify None */
252 case XFixesSelectionWindowDestroyNotify
:
253 case XFixesSelectionClientCloseNotify
:
254 ev
.xfev
.owner
= None
;
258 fprintf(x11
->errfile
,
259 "unexpected xfix event subtype %d window %d\n",
260 (int)ev
.xfev
.subtype
, (int)event
.xany
.window
);
265 fprintf(x11
->errfile
, "New selection owner: %u\n",
266 (unsigned int)ev
.xfev
.owner
);
268 /* Ignore becoming the owner ourselves */
269 if (ev
.xfev
.owner
== x11
->selection_window
)
272 /* If the clipboard owner is changed we no longer own it */
273 vdagent_x11_set_clipboard_owner(x11
, owner_none
);
275 if (ev
.xfev
.owner
== None
)
278 /* Request the supported targets from the new owner */
279 XConvertSelection(x11
->display
, x11
->clipboard_atom
, x11
->targets_atom
,
280 x11
->targets_atom
, x11
->selection_window
,
282 XFlush(x11
->display
);
283 x11
->expected_targets_notifies
++;
287 switch (event
.type
) {
288 case ConfigureNotify
:
289 if (event
.xconfigure
.window
!= x11
->root_window
)
294 if (event
.xconfigure
.width
== x11
->width
&&
295 event
.xconfigure
.height
== x11
->height
)
298 x11
->width
= event
.xconfigure
.width
;
299 x11
->height
= event
.xconfigure
.height
;
301 vdagent_x11_send_daemon_guest_xorg_res(x11
);
303 case SelectionNotify
:
304 if (event
.xselection
.target
== x11
->targets_atom
)
305 vdagent_x11_handle_targets_notify(x11
, &event
, 0);
307 vdagent_x11_handle_selection_notify(x11
, &event
, 0);
313 if (!x11
->expect_property_notify
||
314 event
.xproperty
.state
!= PropertyNewValue
)
317 if (event
.xproperty
.atom
== x11
->targets_atom
)
318 vdagent_x11_handle_targets_notify(x11
, &event
, 1);
320 vdagent_x11_handle_selection_notify(x11
, &event
, 1);
323 /* Do nothing the clipboard ownership will get updated through
324 the XFixesSetSelectionOwnerNotify event */
327 case SelectionRequest
: {
328 struct vdagent_x11_selection_request
*req
, *new_req
;
330 new_req
= malloc(sizeof(*new_req
));
332 fprintf(x11
->errfile
,
333 "out of memory on SelectionRequest, ignoring.\n");
339 new_req
->event
= event
;
340 new_req
->next
= NULL
;
342 if (!x11
->selection_request
) {
343 x11
->selection_request
= new_req
;
344 vdagent_x11_handle_selection_request(x11
);
348 /* maybe we should limit the selection_request stack depth ? */
349 req
= x11
->selection_request
;
357 if (!handled
&& x11
->verbose
)
358 fprintf(x11
->errfile
, "unhandled x11 event, type %d, window %d\n",
359 (int)event
.type
, (int)event
.xany
.window
);
362 void vdagent_x11_do_read(struct vdagent_x11
*x11
)
366 while (XPending(x11
->display
)) {
367 XNextEvent(x11
->display
, &event
);
368 vdagent_x11_handle_event(x11
, event
);
372 static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11
*x11
)
374 struct vdagentd_guest_xorg_resolution res
;
376 res
.width
= x11
->width
;
377 res
.height
= x11
->height
;
379 udscs_write(x11
->vdagentd
, VDAGENTD_GUEST_XORG_RESOLUTION
, 0,
380 (uint8_t *)&res
, sizeof(res
));
383 static const char *vdagent_x11_get_atom_name(struct vdagent_x11
*x11
, Atom a
)
388 return XGetAtomName(x11
->display
, a
);
391 static int vdagent_x11_get_selection(struct vdagent_x11
*x11
, XEvent
*event
,
392 Atom type
, Atom prop
, int format
,
393 unsigned char **data_ret
, int incr
)
395 Bool del
= incr
? True
: False
;
397 int format_ret
, ret_val
= -1;
398 unsigned long len
, remain
;
399 unsigned char *data
= NULL
;
404 if (event
->xproperty
.atom
!= prop
) {
405 fprintf(x11
->errfile
, "PropertyNotify parameters mismatch\n");
409 if (event
->xselection
.property
== None
) {
411 fprintf(x11
->errfile
,
412 "XConvertSelection refused by clipboard owner\n");
416 if (event
->xselection
.requestor
!= x11
->selection_window
||
417 event
->xselection
.selection
!= x11
->clipboard_atom
||
418 event
->xselection
.property
!= prop
) {
419 fprintf(x11
->errfile
, "SelectionNotify parameters mismatch\n");
424 if (XGetWindowProperty(x11
->display
, x11
->selection_window
, prop
, 0,
425 LONG_MAX
, del
, type
, &type_ret
, &format_ret
, &len
,
426 &remain
, &data
) != Success
) {
427 fprintf(x11
->errfile
, "XGetWindowProperty failed\n");
432 if (type_ret
== x11
->incr_atom
) {
433 int prop_min_size
= *(uint32_t*)data
;
435 if (x11
->expect_property_notify
) {
436 fprintf(x11
->errfile
,
437 "received an incr SelectionNotify while "
438 "still reading another incr property\n");
442 if (x11
->clipboard_data_space
< prop_min_size
) {
443 free(x11
->clipboard_data
);
444 x11
->clipboard_data
= malloc(prop_min_size
);
445 if (!x11
->clipboard_data
) {
446 fprintf(x11
->errfile
,
447 "out of memory allocating clipboard buffer\n");
448 x11
->clipboard_data_space
= 0;
451 x11
->clipboard_data_space
= prop_min_size
;
453 x11
->expect_property_notify
= 1;
454 XSelectInput(x11
->display
, x11
->selection_window
,
456 XDeleteProperty(x11
->display
, x11
->selection_window
, prop
);
457 XFlush(x11
->display
);
459 return 0; /* Wait for more data */
461 XDeleteProperty(x11
->display
, x11
->selection_window
, prop
);
462 XFlush(x11
->display
);
465 if (type_ret
!= type
) {
466 fprintf(x11
->errfile
, "expected property type: %s, got: %s\n",
467 vdagent_x11_get_atom_name(x11
, type
),
468 vdagent_x11_get_atom_name(x11
, type_ret
));
472 if (format_ret
!= format
) {
473 fprintf(x11
->errfile
, "expected %d bit format, got %d bits\n", format
,
478 /* Convert len to bytes */
483 len
*= sizeof(short);
492 if (x11
->clipboard_data_size
+ len
> x11
->clipboard_data_space
) {
493 void *old_clipboard_data
= x11
->clipboard_data
;
495 x11
->clipboard_data_space
= x11
->clipboard_data_size
+ len
;
496 x11
->clipboard_data
= realloc(x11
->clipboard_data
,
497 x11
->clipboard_data_space
);
498 if (!x11
->clipboard_data
) {
499 fprintf(x11
->errfile
,
500 "out of memory allocating clipboard buffer\n");
501 x11
->clipboard_data_space
= 0;
502 free(old_clipboard_data
);
506 memcpy(x11
->clipboard_data
+ x11
->clipboard_data_size
, data
, len
);
507 x11
->clipboard_data_size
+= len
;
509 fprintf(x11
->errfile
, "Appended %ld bytes to buffer\n", len
);
511 return 0; /* Wait for more data */
513 len
= x11
->clipboard_data_size
;
514 *data_ret
= x11
->clipboard_data
;
521 fprintf(x11
->errfile
, "property contains no data (zero length)\n");
526 if ((incr
|| ret_val
== -1) && data
)
530 x11
->clipboard_data_size
= 0;
531 x11
->expect_property_notify
= 0;
537 static void vdagent_x11_get_selection_free(struct vdagent_x11
*x11
,
538 unsigned char *data
, int incr
)
541 /* If the clipboard has grown large return the memory to the system */
542 if (x11
->clipboard_data_space
> 512 * 1024) {
543 free(x11
->clipboard_data
);
544 x11
->clipboard_data
= NULL
;
545 x11
->clipboard_data_space
= 0;
551 static uint32_t vdagent_x11_target_to_type(struct vdagent_x11
*x11
,
556 for (i
= 0; i
< clipboard_format_count
; i
++) {
557 for (j
= 0; j
< x11
->clipboard_formats
[i
].atom_count
; i
++) {
558 if (x11
->clipboard_formats
[i
].atoms
[j
] == target
) {
559 return x11
->clipboard_formats
[i
].type
;
564 fprintf(x11
->errfile
, "unexpected selection type %s\n",
565 vdagent_x11_get_atom_name(x11
, target
));
566 return VD_AGENT_CLIPBOARD_NONE
;
569 static Atom
vdagent_x11_type_to_target(struct vdagent_x11
*x11
, uint32_t type
)
573 for (i
= 0; i
< x11
->clipboard_type_count
; i
++)
574 if (x11
->clipboard_agent_types
[i
] == type
)
575 return x11
->clipboard_x11_targets
[i
];
577 fprintf(x11
->errfile
, "client requested unavailable type %u\n", type
);
581 static void vdagent_x11_handle_selection_notify(struct vdagent_x11
*x11
,
582 XEvent
*event
, int incr
)
585 unsigned char *data
= NULL
;
588 if (x11
->clipboard_request_target
== None
) {
589 fprintf(x11
->errfile
, "SelectionNotify received without a target\n");
593 type
= vdagent_x11_target_to_type(x11
, x11
->clipboard_request_target
);
595 event
->xselection
.target
!= x11
->clipboard_request_target
&&
596 event
->xselection
.target
!= x11
->incr_atom
)
597 fprintf(x11
->errfile
, "Requested %s target got %s\n",
598 vdagent_x11_get_atom_name(x11
, x11
->clipboard_request_target
),
599 vdagent_x11_get_atom_name(x11
, event
->xselection
.target
));
601 len
= vdagent_x11_get_selection(x11
, event
, x11
->clipboard_request_target
,
602 x11
->clipboard_atom
, 8, &data
, incr
);
603 if (len
== 0) /* waiting for more data? */
606 type
= VD_AGENT_CLIPBOARD_NONE
;
610 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
, type
, data
, len
);
611 x11
->clipboard_request_target
= None
;
612 vdagent_x11_get_selection_free(x11
, data
, incr
);
615 static Atom
atom_lists_overlap(Atom
*atoms1
, Atom
*atoms2
, int l1
, int l2
)
619 for (i
= 0; i
< l1
; i
++)
620 for (j
= 0; j
< l2
; j
++)
621 if (atoms1
[i
] == atoms2
[j
])
627 static void vdagent_x11_print_targets(struct vdagent_x11
*x11
,
628 const char *action
, Atom
*atoms
, int c
)
635 fprintf(x11
->errfile
, "%s %d targets:\n", action
, c
);
636 for (i
= 0; i
< c
; i
++)
637 fprintf(x11
->errfile
, "%s\n",
638 vdagent_x11_get_atom_name(x11
, atoms
[i
]));
641 static void vdagent_x11_handle_targets_notify(struct vdagent_x11
*x11
,
642 XEvent
*event
, int incr
)
645 Atom atom
, *atoms
= NULL
;
647 if (!x11
->expected_targets_notifies
) {
648 fprintf(x11
->errfile
, "unexpected selection notify TARGETS\n");
652 x11
->expected_targets_notifies
--;
654 /* If we have more targets_notifies pending, ignore this one, we
655 are only interested in the targets list of the current owner
656 (which is the last one we've requested a targets list from) */
657 if (x11
->expected_targets_notifies
)
660 len
= vdagent_x11_get_selection(x11
, event
, XA_ATOM
, x11
->targets_atom
, 32,
661 (unsigned char **)&atoms
, incr
);
662 if (len
== 0 || len
== -1) /* waiting for more data or error? */
667 vdagent_x11_print_targets(x11
, "received", atoms
, len
);
669 x11
->clipboard_type_count
= 0;
670 for (i
= 0; i
< clipboard_format_count
; i
++) {
671 atom
= atom_lists_overlap(x11
->clipboard_formats
[i
].atoms
, atoms
,
672 x11
->clipboard_formats
[i
].atom_count
, len
);
674 x11
->clipboard_agent_types
[x11
->clipboard_type_count
] =
675 x11
->clipboard_formats
[i
].type
;
676 x11
->clipboard_x11_targets
[x11
->clipboard_type_count
] = atom
;
677 x11
->clipboard_type_count
++;
678 if (x11
->clipboard_type_count
==
679 sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t)) {
680 fprintf(x11
->errfile
,
681 "handle_targets_notify: too many types\n");
687 if (x11
->clipboard_type_count
) {
688 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_GRAB
, 0,
689 (uint8_t *)x11
->clipboard_agent_types
,
690 x11
->clipboard_type_count
* sizeof(uint32_t));
691 vdagent_x11_set_clipboard_owner(x11
, owner_guest
);
694 vdagent_x11_get_selection_free(x11
, (unsigned char *)atoms
, incr
);
697 static void vdagent_x11_send_selection_notify(struct vdagent_x11
*x11
,
698 Atom prop
, int process_next_req
)
700 XEvent res
, *event
= &x11
->selection_request
->event
;
701 struct vdagent_x11_selection_request
*selection_request
;
703 res
.xselection
.property
= prop
;
704 res
.xselection
.type
= SelectionNotify
;
705 res
.xselection
.display
= event
->xselectionrequest
.display
;
706 res
.xselection
.requestor
= event
->xselectionrequest
.requestor
;
707 res
.xselection
.selection
= event
->xselectionrequest
.selection
;
708 res
.xselection
.target
= event
->xselectionrequest
.target
;
709 res
.xselection
.time
= event
->xselectionrequest
.time
;
710 XSendEvent(x11
->display
, event
->xselectionrequest
.requestor
, 0, 0, &res
);
711 XFlush(x11
->display
);
713 selection_request
= x11
->selection_request
;
714 x11
->selection_request
= selection_request
->next
;
715 free(selection_request
);
716 if (process_next_req
)
717 vdagent_x11_handle_selection_request(x11
);
720 static void vdagent_x11_send_targets(struct vdagent_x11
*x11
, XEvent
*event
)
722 Atom prop
, targets
[256] = { x11
->targets_atom
, };
723 int i
, j
, k
, target_count
= 1;
725 for (i
= 0; i
< x11
->clipboard_type_count
; i
++) {
726 for (j
= 0; j
< clipboard_format_count
; j
++) {
727 if (x11
->clipboard_formats
[j
].type
!=
728 x11
->clipboard_agent_types
[i
])
731 for (k
= 0; k
< x11
->clipboard_formats
[j
].atom_count
; k
++) {
732 targets
[target_count
] = x11
->clipboard_formats
[j
].atoms
[k
];
734 if (target_count
== sizeof(targets
)/sizeof(Atom
)) {
735 fprintf(x11
->errfile
, "send_targets: too many targets\n");
743 prop
= event
->xselectionrequest
.property
;
745 prop
= event
->xselectionrequest
.target
;
747 XChangeProperty(x11
->display
, event
->xselectionrequest
.requestor
, prop
,
748 XA_ATOM
, 32, PropModeReplace
, (unsigned char *)&targets
,
750 vdagent_x11_print_targets(x11
, "sent", targets
, target_count
);
751 vdagent_x11_send_selection_notify(x11
, prop
, 1);
754 static void vdagent_x11_handle_selection_request(struct vdagent_x11
*x11
)
757 uint32_t type
= VD_AGENT_CLIPBOARD_NONE
;
759 if (!x11
->selection_request
)
762 event
= &x11
->selection_request
->event
;
764 if (x11
->clipboard_owner
!= owner_client
) {
765 fprintf(x11
->errfile
,
766 "received selection request event for target %s, "
767 "while not owning client clipboard\n",
768 vdagent_x11_get_atom_name(x11
, event
->xselectionrequest
.target
));
769 vdagent_x11_send_selection_notify(x11
, None
, 1);
773 if (event
->xselectionrequest
.target
== x11
->multiple_atom
) {
774 fprintf(x11
->errfile
, "multiple target not supported\n");
775 vdagent_x11_send_selection_notify(x11
, None
, 1);
779 if (event
->xselectionrequest
.target
== x11
->targets_atom
) {
780 vdagent_x11_send_targets(x11
, event
);
784 type
= vdagent_x11_target_to_type(x11
, event
->xselectionrequest
.target
);
785 if (type
== VD_AGENT_CLIPBOARD_NONE
) {
786 vdagent_x11_send_selection_notify(x11
, None
, 1);
790 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_REQUEST
, type
, NULL
, 0);
793 void vdagent_x11_set_monitor_config(struct vdagent_x11
*x11
,
794 VDAgentMonitorsConfig
*mon_config
)
796 int i
, num_sizes
= 0;
798 unsigned int closest_diff
= -1;
799 XRRScreenSize
* sizes
;
800 XRRScreenConfiguration
* config
;
803 if (!x11
->has_xrandr
)
806 if (mon_config
->num_of_monitors
!= 1) {
807 fprintf(x11
->errfile
,
808 "Only 1 monitor supported, ignoring additional monitors\n");
811 sizes
= XRRSizes(x11
->display
, x11
->screen
, &num_sizes
);
812 if (!sizes
|| !num_sizes
) {
813 fprintf(x11
->errfile
, "XRRSizes failed\n");
817 /* Find the closest size which will fit within the monitor */
818 for (i
= 0; i
< num_sizes
; i
++) {
819 if (sizes
[i
].width
> mon_config
->monitors
[0].width
||
820 sizes
[i
].height
> mon_config
->monitors
[0].height
)
821 continue; /* Too large for the monitor */
823 unsigned int wdiff
= mon_config
->monitors
[0].width
- sizes
[i
].width
;
824 unsigned int hdiff
= mon_config
->monitors
[0].height
- sizes
[i
].height
;
825 unsigned int diff
= wdiff
* wdiff
+ hdiff
* hdiff
;
826 if (diff
< closest_diff
) {
833 fprintf(x11
->errfile
, "no suitable resolution found for monitor\n");
837 config
= XRRGetScreenInfo(x11
->display
, x11
->root_window
);
839 fprintf(x11
->errfile
, "get screen info failed\n");
842 XRRConfigCurrentConfiguration(config
, &rotation
);
843 XRRSetScreenConfig(x11
->display
, config
, x11
->root_window
, best
,
844 rotation
, CurrentTime
);
845 XRRFreeScreenConfigInfo(config
);
846 XFlush(x11
->display
);
847 x11
->width
= sizes
[best
].width
;
848 x11
->height
= sizes
[best
].height
;
849 vdagent_x11_send_daemon_guest_xorg_res(x11
);
852 void vdagent_x11_clipboard_request(struct vdagent_x11
*x11
, uint32_t type
)
856 if (x11
->clipboard_owner
!= owner_guest
) {
857 fprintf(x11
->errfile
,
858 "received clipboard req while not owning guest clipboard\n");
859 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
860 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
864 target
= vdagent_x11_type_to_target(x11
, type
);
865 if (target
== None
) {
866 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
867 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
871 if (x11
->clipboard_request_target
) {
872 fprintf(x11
->errfile
,
873 "XConvertSelection request is already pending\n");
874 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
875 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
878 x11
->clipboard_request_target
= target
;
879 XConvertSelection(x11
->display
, x11
->clipboard_atom
, target
,
880 x11
->clipboard_atom
, x11
->selection_window
, CurrentTime
);
881 XFlush(x11
->display
);
884 void vdagent_x11_clipboard_grab(struct vdagent_x11
*x11
, uint32_t *types
,
887 if (type_count
> sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t)) {
888 fprintf(x11
->errfile
, "x11_clipboard_grab: too many types\n");
889 type_count
= sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t);
892 memcpy(x11
->clipboard_agent_types
, types
, type_count
* sizeof(uint32_t));
893 x11
->clipboard_type_count
= type_count
;
895 XSetSelectionOwner(x11
->display
, x11
->clipboard_atom
,
896 x11
->selection_window
, CurrentTime
);
897 XFlush(x11
->display
);
898 vdagent_x11_set_clipboard_owner(x11
, owner_client
);
901 void vdagent_x11_clipboard_data(struct vdagent_x11
*x11
, uint32_t type
,
902 const uint8_t *data
, uint32_t size
)
906 uint32_t type_from_event
;
908 if (!x11
->selection_request
) {
909 fprintf(x11
->errfile
, "received clipboard data without an outstanding"
910 "selection request, ignoring\n");
914 event
= &x11
->selection_request
->event
;
915 type_from_event
= vdagent_x11_target_to_type(x11
,
916 event
->xselectionrequest
.target
);
917 if (type_from_event
!= type
) {
918 fprintf(x11
->errfile
, "expecting type %u clipboard data got %u\n",
919 type_from_event
, type
);
920 vdagent_x11_send_selection_notify(x11
, None
, 1);
924 prop
= event
->xselectionrequest
.property
;
926 prop
= event
->xselectionrequest
.target
;
928 /* FIXME: use INCR for large data transfers */
929 XChangeProperty(x11
->display
, event
->xselectionrequest
.requestor
, prop
,
930 event
->xselectionrequest
.target
, 8, PropModeReplace
,
932 vdagent_x11_send_selection_notify(x11
, prop
, 1);
935 void vdagent_x11_clipboard_release(struct vdagent_x11
*x11
)
939 if (x11
->clipboard_owner
!= owner_client
) {
940 fprintf(x11
->errfile
,
941 "received clipboard release while not owning client clipboard\n");
945 XSetSelectionOwner(x11
->display
, x11
->clipboard_atom
, None
, CurrentTime
);
946 /* Make sure we process the XFixesSetSelectionOwnerNotify event caused
947 by this, so we don't end up changing the clipboard owner to none, after
948 it has already been re-owned because this event is still pending. */
949 XSync(x11
->display
, False
);
950 while (XCheckTypedEvent(x11
->display
, x11
->xfixes_event_base
,
952 vdagent_x11_handle_event(x11
, event
);
954 /* Note no need to do a set_clipboard_owner(owner_none) here, as that is
955 already done by processing the XFixesSetSelectionOwnerNotify event. */