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 struct vdagent_x11_selection_request
{
42 struct vdagent_x11_selection_request
*next
;
45 struct clipboard_format_tmpl
{
47 const char *atom_names
[16];
50 struct clipboard_format_info
{
56 static const struct clipboard_format_tmpl clipboard_format_templates
[] = {
57 { VD_AGENT_CLIPBOARD_UTF8_TEXT
, { "UTF8_STRING",
58 "text/plain;charset=UTF-8", "text/plain;charset=utf-8", NULL
}, },
59 { VD_AGENT_CLIPBOARD_IMAGE_PNG
, { "image/png", NULL
}, },
60 { VD_AGENT_CLIPBOARD_IMAGE_BMP
, { "image/bmp", "image/x-bmp",
61 "image/x-MS-bmp", "image/x-win-bitmap", NULL
}, },
62 { VD_AGENT_CLIPBOARD_IMAGE_TIFF
, { "image/tiff", NULL
}, },
63 { VD_AGENT_CLIPBOARD_IMAGE_JPG
, { "image/jpeg", NULL
}, },
66 #define clipboard_format_count (sizeof(clipboard_format_templates)/sizeof(clipboard_format_templates[0]))
69 struct clipboard_format_info clipboard_formats
[clipboard_format_count
];
76 Window selection_window
;
77 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
,
112 struct vdagent_x11
*x11
;
113 XWindowAttributes attrib
;
114 int i
, j
, major
, minor
;
116 x11
= calloc(1, sizeof(*x11
));
118 fprintf(stderr
, "out of memory allocating vdagent_x11 struct\n");
122 x11
->vdagentd
= vdagentd
;
123 x11
->verbose
= verbose
;
125 x11
->display
= XOpenDisplay(NULL
);
127 fprintf(stderr
, "could not connect to X-server\n");
132 x11
->screen
= DefaultScreen(x11
->display
);
133 x11
->root_window
= RootWindow(x11
->display
, x11
->screen
);
134 x11
->fd
= ConnectionNumber(x11
->display
);
135 x11
->clipboard_atom
= XInternAtom(x11
->display
, "CLIPBOARD", False
);
136 x11
->targets_atom
= XInternAtom(x11
->display
, "TARGETS", False
);
137 x11
->incr_atom
= XInternAtom(x11
->display
, "INCR", False
);
138 x11
->multiple_atom
= XInternAtom(x11
->display
, "MULTIPLE", False
);
139 for(i
= 0; i
< clipboard_format_count
; i
++) {
140 x11
->clipboard_formats
[i
].type
= clipboard_format_templates
[i
].type
;
141 for(j
= 0; clipboard_format_templates
[i
].atom_names
[j
]; j
++) {
142 x11
->clipboard_formats
[i
].atoms
[j
] =
143 XInternAtom(x11
->display
,
144 clipboard_format_templates
[i
].atom_names
[j
],
147 x11
->clipboard_formats
[i
].atom_count
= j
;
150 /* We should not store properties (for selections) on the root window */
151 x11
->selection_window
= XCreateSimpleWindow(x11
->display
, x11
->root_window
,
152 0, 0, 1, 1, 0, 0, 0);
154 fprintf(stderr
, "Selection window: %u\n",
155 (unsigned int)x11
->selection_window
);
157 if (XRRQueryExtension(x11
->display
, &i
, &i
))
160 fprintf(stderr
, "no xrandr\n");
162 if (XFixesQueryExtension(x11
->display
, &x11
->xfixes_event_base
, &i
) &&
163 XFixesQueryVersion(x11
->display
, &major
, &minor
) && major
>= 1) {
165 XFixesSelectSelectionInput(x11
->display
, x11
->root_window
,
167 XFixesSetSelectionOwnerNotifyMask
);
169 fprintf(stderr
, "no xfixes, no guest -> client copy paste support\n");
171 /* Catch resolution changes */
172 XSelectInput(x11
->display
, x11
->root_window
, StructureNotifyMask
);
174 /* Get the current resolution */
175 XGetWindowAttributes(x11
->display
, x11
->root_window
, &attrib
);
176 x11
->width
= attrib
.width
;
177 x11
->height
= attrib
.height
;
178 vdagent_x11_send_daemon_guest_xorg_res(x11
);
180 /* No need for XFlush as XGetWindowAttributes does an implicit Xflush */
185 void vdagent_x11_destroy(struct vdagent_x11
*x11
)
190 XCloseDisplay(x11
->display
);
194 int vdagent_x11_get_fd(struct vdagent_x11
*x11
)
199 static void vdagent_x11_set_clipboard_owner(struct vdagent_x11
*x11
,
202 /* Clear pending requests and clipboard data */
203 if (x11
->selection_request
) {
205 "selection requests pending on clipboard ownership change, "
207 while (x11
->selection_request
)
208 vdagent_x11_send_selection_notify(x11
, None
, 0);
210 x11
->clipboard_data_size
= 0;
211 x11
->clipboard_request_target
= None
;
212 x11
->expect_property_notify
= 0;
214 if (new_owner
== owner_none
) {
215 /* When going from owner_guest to owner_none we need to send a
216 clipboard release message to the client */
217 if (x11
->clipboard_owner
== owner_guest
)
218 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_RELEASE
, 0, NULL
, 0);
220 x11
->clipboard_type_count
= 0;
222 x11
->clipboard_owner
= new_owner
;
225 static void vdagent_x11_handle_event(struct vdagent_x11
*x11
, XEvent event
)
230 if (event
.type
== x11
->xfixes_event_base
) {
233 XFixesSelectionNotifyEvent xfev
;
237 if (ev
.xfev
.subtype
!= XFixesSetSelectionOwnerNotify
) {
239 fprintf(stderr
, "unexpected xfix event subtype %d window %d\n",
240 (int)ev
.xfev
.subtype
, (int)event
.xany
.window
);
245 fprintf(stderr
, "New selection owner: %u\n",
246 (unsigned int)ev
.xfev
.owner
);
248 /* Ignore becoming the owner ourselves */
249 if (ev
.xfev
.owner
== x11
->selection_window
)
252 /* If the clipboard owner is changed we no longer own it */
253 vdagent_x11_set_clipboard_owner(x11
, owner_none
);
255 if (ev
.xfev
.owner
== None
)
258 /* Request the supported targets from the new owner */
259 XConvertSelection(x11
->display
, x11
->clipboard_atom
, x11
->targets_atom
,
260 x11
->targets_atom
, x11
->selection_window
,
262 XFlush(x11
->display
);
263 x11
->expected_targets_notifies
++;
267 switch (event
.type
) {
268 case ConfigureNotify
:
269 if (event
.xconfigure
.window
!= x11
->root_window
)
274 if (event
.xconfigure
.width
== x11
->width
&&
275 event
.xconfigure
.height
== x11
->height
)
278 x11
->width
= event
.xconfigure
.width
;
279 x11
->height
= event
.xconfigure
.height
;
281 vdagent_x11_send_daemon_guest_xorg_res(x11
);
283 case SelectionNotify
:
284 if (event
.xselection
.target
== x11
->targets_atom
)
285 vdagent_x11_handle_targets_notify(x11
, &event
, 0);
287 vdagent_x11_handle_selection_notify(x11
, &event
, 0);
293 if (!x11
->expect_property_notify
||
294 event
.xproperty
.state
!= PropertyNewValue
)
297 if (event
.xproperty
.atom
== x11
->targets_atom
)
298 vdagent_x11_handle_targets_notify(x11
, &event
, 1);
300 vdagent_x11_handle_selection_notify(x11
, &event
, 1);
303 /* Do nothing the clipboard ownership will get updated through
304 the XFixesSetSelectionOwnerNotify event */
307 case SelectionRequest
: {
308 struct vdagent_x11_selection_request
*req
, *new_req
;
310 new_req
= malloc(sizeof(*new_req
));
312 fprintf(stderr
, "out of memory on SelectionRequest, ignoring.\n");
318 new_req
->event
= event
;
319 new_req
->next
= NULL
;
321 if (!x11
->selection_request
) {
322 x11
->selection_request
= new_req
;
323 vdagent_x11_handle_selection_request(x11
);
327 /* maybe we should limit the selection_request stack depth ? */
328 req
= x11
->selection_request
;
336 if (!handled
&& x11
->verbose
)
337 fprintf(stderr
, "unhandled x11 event, type %d, window %d\n",
338 (int)event
.type
, (int)event
.xany
.window
);
341 void vdagent_x11_do_read(struct vdagent_x11
*x11
)
345 while (XPending(x11
->display
)) {
346 XNextEvent(x11
->display
, &event
);
347 vdagent_x11_handle_event(x11
, event
);
351 static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11
*x11
)
353 struct vdagentd_guest_xorg_resolution res
;
355 res
.width
= x11
->width
;
356 res
.height
= x11
->height
;
358 udscs_write(x11
->vdagentd
, VDAGENTD_GUEST_XORG_RESOLUTION
, 0,
359 (uint8_t *)&res
, sizeof(res
));
362 static const char *vdagent_x11_get_atom_name(struct vdagent_x11
*x11
, Atom a
)
367 return XGetAtomName(x11
->display
, a
);
370 static int vdagent_x11_get_selection(struct vdagent_x11
*x11
, XEvent
*event
,
371 Atom type
, Atom prop
, int format
,
372 unsigned char **data_ret
, int incr
)
374 Bool del
= incr
? True
: False
;
376 int format_ret
, ret_val
= -1;
377 unsigned long len
, remain
;
378 unsigned char *data
= NULL
;
381 if (event
->xproperty
.atom
!= prop
) {
382 fprintf(stderr
, "PropertyNotify parameters mismatch\n");
386 if (event
->xselection
.property
== None
) {
388 fprintf(stderr
, "XConvertSelection refused by clipboard owner\n");
392 if (event
->xselection
.requestor
!= x11
->selection_window
||
393 event
->xselection
.selection
!= x11
->clipboard_atom
||
394 event
->xselection
.property
!= prop
) {
395 fprintf(stderr
, "SelectionNotify parameters mismatch\n");
400 if (XGetWindowProperty(x11
->display
, x11
->selection_window
, prop
, 0,
401 LONG_MAX
, del
, type
, &type_ret
, &format_ret
, &len
,
402 &remain
, &data
) != Success
) {
403 fprintf(stderr
, "XGetWindowProperty failed\n");
408 if (type_ret
== x11
->incr_atom
) {
409 int prop_min_size
= *(uint32_t*)data
;
411 if (x11
->expect_property_notify
) {
413 "received an incr property notify while "
414 "still reading another incr property\n");
418 if (x11
->clipboard_data_space
< prop_min_size
) {
419 free(x11
->clipboard_data
);
420 x11
->clipboard_data
= malloc(prop_min_size
);
421 if (!x11
->clipboard_data
) {
423 "out of memory allocating clipboard buffer\n");
424 x11
->clipboard_data_space
= 0;
427 x11
->clipboard_data_space
= prop_min_size
;
429 x11
->expect_property_notify
= 1;
430 XSelectInput(x11
->display
, x11
->selection_window
,
432 XDeleteProperty(x11
->display
, x11
->selection_window
, prop
);
433 XFlush(x11
->display
);
435 return 0; /* Wait for more data */
437 XDeleteProperty(x11
->display
, x11
->selection_window
, prop
);
438 XFlush(x11
->display
);
441 if (type_ret
!= type
) {
442 fprintf(stderr
, "expected property type: %s, got: %s\n",
443 vdagent_x11_get_atom_name(x11
, type
),
444 vdagent_x11_get_atom_name(x11
, type_ret
));
448 if (format_ret
!= format
) {
449 fprintf(stderr
, "expected %d bit format, got %d bits\n", format
,
454 /* Convert len to bytes */
459 len
*= sizeof(short);
468 if (x11
->clipboard_data_size
+ len
> x11
->clipboard_data_space
) {
469 void *old_clipboard_data
= x11
->clipboard_data
;
471 x11
->clipboard_data_space
= x11
->clipboard_data_size
+ len
;
472 x11
->clipboard_data
= realloc(x11
->clipboard_data
,
473 x11
->clipboard_data_space
);
474 if (!x11
->clipboard_data
) {
476 "out of memory allocating clipboard buffer\n");
477 x11
->clipboard_data_space
= 0;
478 free(old_clipboard_data
);
482 memcpy(x11
->clipboard_data
+ x11
->clipboard_data_size
, data
, len
);
483 x11
->clipboard_data_size
+= len
;
485 fprintf(stderr
, "Appended %ld bytes to buffer\n", len
);
487 return 0; /* Wait for more data */
489 len
= x11
->clipboard_data_size
;
490 *data_ret
= x11
->clipboard_data
;
497 fprintf(stderr
, "property contains no data (zero length)\n");
500 if ((incr
|| ret_val
== -1) && data
)
504 x11
->clipboard_data_size
= 0;
505 x11
->expect_property_notify
= 0;
511 static void vdagent_x11_get_selection_free(struct vdagent_x11
*x11
,
512 unsigned char *data
, int incr
)
515 /* If the clipboard has grown large return the memory to the system */
516 if (x11
->clipboard_data_space
> 512 * 1024) {
517 free(x11
->clipboard_data
);
518 x11
->clipboard_data
= NULL
;
519 x11
->clipboard_data_space
= 0;
525 static uint32_t vdagent_x11_target_to_type(struct vdagent_x11
*x11
,
531 return VD_AGENT_CLIPBOARD_NONE
;
533 for (i
= 0; i
< clipboard_format_count
; i
++) {
534 for (j
= 0; j
< x11
->clipboard_formats
[i
].atom_count
; i
++) {
535 if (x11
->clipboard_formats
[i
].atoms
[j
] == target
) {
536 return x11
->clipboard_formats
[i
].type
;
541 fprintf(stderr
, "unexpected selection type %s\n",
542 vdagent_x11_get_atom_name(x11
, target
));
543 return VD_AGENT_CLIPBOARD_NONE
;
546 static Atom
vdagent_x11_type_to_target(struct vdagent_x11
*x11
, uint32_t type
)
550 for (i
= 0; i
< x11
->clipboard_type_count
; i
++)
551 if (x11
->clipboard_agent_types
[i
] == type
)
552 return x11
->clipboard_x11_targets
[i
];
554 fprintf(stderr
, "client requested unavailable type %u\n", type
);
558 static void vdagent_x11_handle_selection_notify(struct vdagent_x11
*x11
,
559 XEvent
*event
, int incr
)
562 unsigned char *data
= NULL
;
565 type
= vdagent_x11_target_to_type(x11
, x11
->clipboard_request_target
);
567 if (x11
->clipboard_request_target
== None
)
568 fprintf(stderr
, "SelectionNotify received without a target\n");
570 event
->xselection
.target
!= x11
->clipboard_request_target
)
571 fprintf(stderr
, "Requested %s target got %s\n",
572 vdagent_x11_get_atom_name(x11
, x11
->clipboard_request_target
),
573 vdagent_x11_get_atom_name(x11
, event
->xselection
.target
));
575 len
= vdagent_x11_get_selection(x11
, event
, x11
->clipboard_request_target
,
576 x11
->clipboard_atom
, 8, &data
, incr
);
577 if (len
== 0) /* waiting for more data? */
580 type
= VD_AGENT_CLIPBOARD_NONE
;
584 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
, type
, data
, len
);
585 x11
->clipboard_request_target
= None
;
586 vdagent_x11_get_selection_free(x11
, data
, incr
);
589 static Atom
atom_lists_overlap(Atom
*atoms1
, Atom
*atoms2
, int l1
, int l2
)
593 for (i
= 0; i
< l1
; i
++)
594 for (j
= 0; j
< l2
; j
++)
595 if (atoms1
[i
] == atoms2
[j
])
601 static void vdagent_x11_print_targets(struct vdagent_x11
*x11
,
602 const char *action
, Atom
*atoms
, int c
)
609 fprintf(stderr
, "%s %d targets:\n", action
, c
);
610 for (i
= 0; i
< c
; i
++)
611 fprintf(stderr
, "%s\n", vdagent_x11_get_atom_name(x11
, atoms
[i
]));
614 static void vdagent_x11_handle_targets_notify(struct vdagent_x11
*x11
,
615 XEvent
*event
, int incr
)
618 Atom atom
, *atoms
= NULL
;
620 if (!x11
->expected_targets_notifies
) {
621 fprintf(stderr
, "unexpected selection notify TARGETS\n");
625 x11
->expected_targets_notifies
--;
627 /* If we have more targets_notifies pending, ignore this one, we
628 are only interested in the targets list of the current owner
629 (which is the last one we've requested a targets list from) */
630 if (x11
->expected_targets_notifies
)
633 len
= vdagent_x11_get_selection(x11
, event
, XA_ATOM
, x11
->targets_atom
, 32,
634 (unsigned char **)&atoms
, incr
);
635 if (len
== 0 || len
== -1) /* waiting for more data or error? */
640 vdagent_x11_print_targets(x11
, "received", atoms
, len
);
642 x11
->clipboard_type_count
= 0;
643 for (i
= 0; i
< clipboard_format_count
; i
++) {
644 atom
= atom_lists_overlap(x11
->clipboard_formats
[i
].atoms
, atoms
,
645 x11
->clipboard_formats
[i
].atom_count
, len
);
647 x11
->clipboard_agent_types
[x11
->clipboard_type_count
] =
648 x11
->clipboard_formats
[i
].type
;
649 x11
->clipboard_x11_targets
[x11
->clipboard_type_count
] = atom
;
650 x11
->clipboard_type_count
++;
651 if (x11
->clipboard_type_count
==
652 sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t)) {
653 fprintf(stderr
, "handle_targets_notify: too many types\n");
659 if (x11
->clipboard_type_count
) {
660 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_GRAB
, 0,
661 (uint8_t *)x11
->clipboard_agent_types
,
662 x11
->clipboard_type_count
* sizeof(uint32_t));
663 vdagent_x11_set_clipboard_owner(x11
, owner_guest
);
666 vdagent_x11_get_selection_free(x11
, (unsigned char *)atoms
, incr
);
669 static void vdagent_x11_send_selection_notify(struct vdagent_x11
*x11
,
670 Atom prop
, int process_next_req
)
672 XEvent res
, *event
= &x11
->selection_request
->event
;
673 struct vdagent_x11_selection_request
*selection_request
;
675 res
.xselection
.property
= prop
;
676 res
.xselection
.type
= SelectionNotify
;
677 res
.xselection
.display
= event
->xselectionrequest
.display
;
678 res
.xselection
.requestor
= event
->xselectionrequest
.requestor
;
679 res
.xselection
.selection
= event
->xselectionrequest
.selection
;
680 res
.xselection
.target
= event
->xselectionrequest
.target
;
681 res
.xselection
.time
= event
->xselectionrequest
.time
;
682 XSendEvent(x11
->display
, event
->xselectionrequest
.requestor
, 0, 0, &res
);
683 XFlush(x11
->display
);
685 selection_request
= x11
->selection_request
;
686 x11
->selection_request
= selection_request
->next
;
687 free(selection_request
);
688 if (process_next_req
)
689 vdagent_x11_handle_selection_request(x11
);
692 static void vdagent_x11_send_targets(struct vdagent_x11
*x11
, XEvent
*event
)
694 Atom prop
, targets
[256] = { x11
->targets_atom
, };
695 int i
, j
, k
, target_count
= 1;
697 for (i
= 0; i
< x11
->clipboard_type_count
; i
++) {
698 for (j
= 0; j
< clipboard_format_count
; j
++) {
699 if (x11
->clipboard_formats
[j
].type
!=
700 x11
->clipboard_agent_types
[i
])
703 for (k
= 0; k
< x11
->clipboard_formats
[j
].atom_count
; k
++) {
704 targets
[target_count
] = x11
->clipboard_formats
[j
].atoms
[k
];
706 if (target_count
== sizeof(targets
)/sizeof(Atom
)) {
707 fprintf(stderr
, "send_targets: too many targets\n");
715 prop
= event
->xselectionrequest
.property
;
717 prop
= event
->xselectionrequest
.target
;
719 XChangeProperty(x11
->display
, event
->xselectionrequest
.requestor
, prop
,
720 XA_ATOM
, 32, PropModeReplace
, (unsigned char *)&targets
,
722 vdagent_x11_print_targets(x11
, "sent", targets
, target_count
);
723 vdagent_x11_send_selection_notify(x11
, prop
, 1);
726 static void vdagent_x11_handle_selection_request(struct vdagent_x11
*x11
)
729 uint32_t type
= VD_AGENT_CLIPBOARD_NONE
;
731 if (!x11
->selection_request
)
734 event
= &x11
->selection_request
->event
;
736 if (x11
->clipboard_owner
!= owner_client
) {
738 "received selection request event for target %s, "
739 "while not owning client clipboard\n",
740 vdagent_x11_get_atom_name(x11
, event
->xselectionrequest
.target
));
741 vdagent_x11_send_selection_notify(x11
, None
, 1);
745 if (event
->xselectionrequest
.target
== x11
->multiple_atom
) {
746 fprintf(stderr
, "multiple target not supported\n");
747 vdagent_x11_send_selection_notify(x11
, None
, 1);
751 if (event
->xselectionrequest
.target
== x11
->targets_atom
) {
752 vdagent_x11_send_targets(x11
, event
);
756 type
= vdagent_x11_target_to_type(x11
, event
->xselectionrequest
.target
);
757 if (type
== VD_AGENT_CLIPBOARD_NONE
) {
758 vdagent_x11_send_selection_notify(x11
, None
, 1);
762 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_REQUEST
, type
, NULL
, 0);
765 void vdagent_x11_set_monitor_config(struct vdagent_x11
*x11
,
766 VDAgentMonitorsConfig
*mon_config
)
768 int i
, num_sizes
= 0;
770 unsigned int closest_diff
= -1;
771 XRRScreenSize
* sizes
;
772 XRRScreenConfiguration
* config
;
775 if (!x11
->has_xrandr
)
778 if (mon_config
->num_of_monitors
!= 1) {
779 fprintf(stderr
, "Only 1 monitor supported, ignoring monitor config\n");
783 sizes
= XRRSizes(x11
->display
, x11
->screen
, &num_sizes
);
784 if (!sizes
|| !num_sizes
) {
785 fprintf(stderr
, "XRRSizes failed\n");
789 /* Find the closest size which will fit within the monitor */
790 for (i
= 0; i
< num_sizes
; i
++) {
791 if (sizes
[i
].width
> mon_config
->monitors
[0].width
||
792 sizes
[i
].height
> mon_config
->monitors
[0].height
)
793 continue; /* Too large for the monitor */
795 unsigned int wdiff
= mon_config
->monitors
[0].width
- sizes
[i
].width
;
796 unsigned int hdiff
= mon_config
->monitors
[0].height
- sizes
[i
].height
;
797 unsigned int diff
= wdiff
* wdiff
+ hdiff
* hdiff
;
798 if (diff
< closest_diff
) {
805 fprintf(stderr
, "no suitable resolution found for monitor\n");
809 config
= XRRGetScreenInfo(x11
->display
, x11
->root_window
);
811 fprintf(stderr
, "get screen info failed\n");
814 XRRConfigCurrentConfiguration(config
, &rotation
);
815 XRRSetScreenConfig(x11
->display
, config
, x11
->root_window
, best
,
816 rotation
, CurrentTime
);
817 XRRFreeScreenConfigInfo(config
);
818 XFlush(x11
->display
);
819 x11
->width
= sizes
[best
].width
;
820 x11
->height
= sizes
[best
].height
;
821 vdagent_x11_send_daemon_guest_xorg_res(x11
);
824 void vdagent_x11_clipboard_request(struct vdagent_x11
*x11
, uint32_t type
)
828 if (x11
->clipboard_owner
!= owner_guest
) {
830 "received clipboard req while not owning guest clipboard\n");
831 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
832 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
836 target
= vdagent_x11_type_to_target(x11
, type
);
837 if (target
== None
) {
838 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
839 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
843 if (x11
->clipboard_request_target
) {
844 fprintf(stderr
, "XConvertSelection request is already pending\n");
845 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
846 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
849 x11
->clipboard_request_target
= target
;
850 XConvertSelection(x11
->display
, x11
->clipboard_atom
, target
,
851 x11
->clipboard_atom
, x11
->selection_window
, CurrentTime
);
852 XFlush(x11
->display
);
855 void vdagent_x11_clipboard_grab(struct vdagent_x11
*x11
, uint32_t *types
,
858 if (type_count
> sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t)) {
859 fprintf(stderr
, "x11_clipboard_grab: too many types\n");
860 type_count
= sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t);
863 memcpy(x11
->clipboard_agent_types
, types
, type_count
* sizeof(uint32_t));
864 x11
->clipboard_type_count
= type_count
;
866 XSetSelectionOwner(x11
->display
, x11
->clipboard_atom
,
867 x11
->selection_window
, CurrentTime
);
868 XFlush(x11
->display
);
869 vdagent_x11_set_clipboard_owner(x11
, owner_client
);
872 void vdagent_x11_clipboard_data(struct vdagent_x11
*x11
, uint32_t type
,
873 const uint8_t *data
, uint32_t size
)
877 uint32_t type_from_event
;
879 if (!x11
->selection_request
) {
880 fprintf(stderr
, "received clipboard data without an outstanding"
881 "selection request, ignoring\n");
885 event
= &x11
->selection_request
->event
;
886 type_from_event
= vdagent_x11_target_to_type(x11
,
887 event
->xselectionrequest
.target
);
888 if (type_from_event
!= type
) {
889 fprintf(stderr
, "expecting type %u clipboard data got %u\n",
890 type_from_event
, type
);
891 vdagent_x11_send_selection_notify(x11
, None
, 1);
895 prop
= event
->xselectionrequest
.property
;
897 prop
= event
->xselectionrequest
.target
;
899 /* FIXME: use INCR for large data transfers */
900 XChangeProperty(x11
->display
, event
->xselectionrequest
.requestor
, prop
,
901 event
->xselectionrequest
.target
, 8, PropModeReplace
,
903 vdagent_x11_send_selection_notify(x11
, prop
, 1);
906 void vdagent_x11_clipboard_release(struct vdagent_x11
*x11
)
910 if (x11
->clipboard_owner
!= owner_client
) {
912 "received clipboard release while not owning client clipboard\n");
916 XSetSelectionOwner(x11
->display
, x11
->clipboard_atom
, None
, CurrentTime
);
917 /* Make sure we process the XFixesSetSelectionOwnerNotify event caused
918 by this, so we don't end up changing the clipboard owner to none, after
919 it has already been re-owned because this event is still pending. */
920 XSync(x11
->display
, False
);
921 while (XCheckTypedEvent(x11
->display
, x11
->xfixes_event_base
,
923 vdagent_x11_handle_event(x11
, event
);
925 /* Note no need to do a set_clipboard_owner(owner_none) here, as that is
926 already done by processing the XFixesSetSelectionOwnerNotify event. */