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
);
108 static void vdagent_x11_set_clipboard_owner(struct vdagent_x11
*x11
,
111 struct vdagent_x11
*vdagent_x11_create(struct udscs_connection
*vdagentd
,
112 FILE *errfile
, int verbose
)
114 struct vdagent_x11
*x11
;
115 XWindowAttributes attrib
;
116 int i
, j
, major
, minor
;
118 x11
= calloc(1, sizeof(*x11
));
120 fprintf(errfile
, "out of memory allocating vdagent_x11 struct\n");
124 x11
->vdagentd
= vdagentd
;
125 x11
->errfile
= errfile
;
126 x11
->verbose
= verbose
;
128 x11
->display
= XOpenDisplay(NULL
);
130 fprintf(x11
->errfile
, "could not connect to X-server\n");
135 x11
->screen
= DefaultScreen(x11
->display
);
136 x11
->root_window
= RootWindow(x11
->display
, x11
->screen
);
137 x11
->fd
= ConnectionNumber(x11
->display
);
138 x11
->clipboard_atom
= XInternAtom(x11
->display
, "CLIPBOARD", False
);
139 x11
->targets_atom
= XInternAtom(x11
->display
, "TARGETS", False
);
140 x11
->incr_atom
= XInternAtom(x11
->display
, "INCR", False
);
141 x11
->multiple_atom
= XInternAtom(x11
->display
, "MULTIPLE", False
);
142 for(i
= 0; i
< clipboard_format_count
; i
++) {
143 x11
->clipboard_formats
[i
].type
= clipboard_format_templates
[i
].type
;
144 for(j
= 0; clipboard_format_templates
[i
].atom_names
[j
]; j
++) {
145 x11
->clipboard_formats
[i
].atoms
[j
] =
146 XInternAtom(x11
->display
,
147 clipboard_format_templates
[i
].atom_names
[j
],
150 x11
->clipboard_formats
[i
].atom_count
= j
;
153 /* We should not store properties (for selections) on the root window */
154 x11
->selection_window
= XCreateSimpleWindow(x11
->display
, x11
->root_window
,
155 0, 0, 1, 1, 0, 0, 0);
157 fprintf(x11
->errfile
, "Selection window: %u\n",
158 (unsigned int)x11
->selection_window
);
160 if (XRRQueryExtension(x11
->display
, &i
, &i
))
163 fprintf(x11
->errfile
, "no xrandr\n");
165 if (XFixesQueryExtension(x11
->display
, &x11
->xfixes_event_base
, &i
) &&
166 XFixesQueryVersion(x11
->display
, &major
, &minor
) && major
>= 1) {
168 XFixesSelectSelectionInput(x11
->display
, x11
->root_window
,
170 XFixesSetSelectionOwnerNotifyMask
|
171 XFixesSelectionWindowDestroyNotifyMask
|
172 XFixesSelectionClientCloseNotifyMask
);
174 fprintf(x11
->errfile
,
175 "no xfixes, no guest -> client copy paste support\n");
177 /* Catch resolution changes */
178 XSelectInput(x11
->display
, x11
->root_window
, StructureNotifyMask
);
180 /* Get the current resolution */
181 XGetWindowAttributes(x11
->display
, x11
->root_window
, &attrib
);
182 x11
->width
= attrib
.width
;
183 x11
->height
= attrib
.height
;
184 vdagent_x11_send_daemon_guest_xorg_res(x11
);
186 /* No need for XFlush as XGetWindowAttributes does an implicit XFlush */
191 void vdagent_x11_destroy(struct vdagent_x11
*x11
)
196 vdagent_x11_set_clipboard_owner(x11
, owner_none
);
197 XCloseDisplay(x11
->display
);
201 int vdagent_x11_get_fd(struct vdagent_x11
*x11
)
206 static void vdagent_x11_next_selection_request(struct vdagent_x11
*x11
)
208 struct vdagent_x11_selection_request
*selection_request
;
209 selection_request
= x11
->selection_request
;
210 x11
->selection_request
= selection_request
->next
;
211 free(selection_request
);
214 static void vdagent_x11_set_clipboard_owner(struct vdagent_x11
*x11
,
217 /* Clear pending requests and clipboard data */
218 if (x11
->selection_request
) {
219 fprintf(x11
->errfile
,
220 "selection requests pending on clipboard ownership change, "
222 while (x11
->selection_request
) {
223 vdagent_x11_send_selection_notify(x11
, None
, 0);
224 vdagent_x11_next_selection_request(x11
);
227 if (x11
->clipboard_request_target
!= None
) {
228 fprintf(x11
->errfile
,
229 "client clipboard request pending on clipboard ownership "
231 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
232 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
233 x11
->clipboard_request_target
= None
;
235 x11
->clipboard_data_size
= 0;
236 x11
->expect_property_notify
= 0;
238 if (new_owner
== owner_none
) {
239 /* When going from owner_guest to owner_none we need to send a
240 clipboard release message to the client */
241 if (x11
->clipboard_owner
== owner_guest
)
242 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_RELEASE
, 0, NULL
, 0);
244 x11
->clipboard_type_count
= 0;
246 x11
->clipboard_owner
= new_owner
;
249 static void vdagent_x11_handle_event(struct vdagent_x11
*x11
, XEvent event
)
254 if (event
.type
== x11
->xfixes_event_base
) {
257 XFixesSelectionNotifyEvent xfev
;
261 switch (ev
.xfev
.subtype
) {
262 case XFixesSetSelectionOwnerNotify
:
264 /* Treat ... as a SelectionOwnerNotify None */
265 case XFixesSelectionWindowDestroyNotify
:
266 case XFixesSelectionClientCloseNotify
:
267 ev
.xfev
.owner
= None
;
271 fprintf(x11
->errfile
,
272 "unexpected xfix event subtype %d window %d\n",
273 (int)ev
.xfev
.subtype
, (int)event
.xany
.window
);
278 fprintf(x11
->errfile
, "New selection owner: %u\n",
279 (unsigned int)ev
.xfev
.owner
);
281 /* Ignore becoming the owner ourselves */
282 if (ev
.xfev
.owner
== x11
->selection_window
)
285 /* If the clipboard owner is changed we no longer own it */
286 vdagent_x11_set_clipboard_owner(x11
, owner_none
);
288 if (ev
.xfev
.owner
== None
)
291 /* Request the supported targets from the new owner */
292 XConvertSelection(x11
->display
, x11
->clipboard_atom
, x11
->targets_atom
,
293 x11
->targets_atom
, x11
->selection_window
,
295 XFlush(x11
->display
);
296 x11
->expected_targets_notifies
++;
300 switch (event
.type
) {
301 case ConfigureNotify
:
302 if (event
.xconfigure
.window
!= x11
->root_window
)
307 if (event
.xconfigure
.width
== x11
->width
&&
308 event
.xconfigure
.height
== x11
->height
)
311 x11
->width
= event
.xconfigure
.width
;
312 x11
->height
= event
.xconfigure
.height
;
314 vdagent_x11_send_daemon_guest_xorg_res(x11
);
316 case SelectionNotify
:
317 if (event
.xselection
.target
== x11
->targets_atom
)
318 vdagent_x11_handle_targets_notify(x11
, &event
, 0);
320 vdagent_x11_handle_selection_notify(x11
, &event
, 0);
326 if (!x11
->expect_property_notify
||
327 event
.xproperty
.state
!= PropertyNewValue
)
330 if (event
.xproperty
.atom
== x11
->targets_atom
)
331 vdagent_x11_handle_targets_notify(x11
, &event
, 1);
333 vdagent_x11_handle_selection_notify(x11
, &event
, 1);
336 /* Do nothing the clipboard ownership will get updated through
337 the XFixesSetSelectionOwnerNotify event */
340 case SelectionRequest
: {
341 struct vdagent_x11_selection_request
*req
, *new_req
;
343 new_req
= malloc(sizeof(*new_req
));
345 fprintf(x11
->errfile
,
346 "out of memory on SelectionRequest, ignoring.\n");
352 new_req
->event
= event
;
353 new_req
->next
= NULL
;
355 if (!x11
->selection_request
) {
356 x11
->selection_request
= new_req
;
357 vdagent_x11_handle_selection_request(x11
);
361 /* maybe we should limit the selection_request stack depth ? */
362 req
= x11
->selection_request
;
370 if (!handled
&& x11
->verbose
)
371 fprintf(x11
->errfile
, "unhandled x11 event, type %d, window %d\n",
372 (int)event
.type
, (int)event
.xany
.window
);
375 void vdagent_x11_do_read(struct vdagent_x11
*x11
)
379 while (XPending(x11
->display
)) {
380 XNextEvent(x11
->display
, &event
);
381 vdagent_x11_handle_event(x11
, event
);
385 static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11
*x11
)
387 struct vdagentd_guest_xorg_resolution res
;
389 res
.width
= x11
->width
;
390 res
.height
= x11
->height
;
392 udscs_write(x11
->vdagentd
, VDAGENTD_GUEST_XORG_RESOLUTION
, 0,
393 (uint8_t *)&res
, sizeof(res
));
396 static const char *vdagent_x11_get_atom_name(struct vdagent_x11
*x11
, Atom a
)
401 return XGetAtomName(x11
->display
, a
);
404 static int vdagent_x11_get_selection(struct vdagent_x11
*x11
, XEvent
*event
,
405 Atom type
, Atom prop
, int format
,
406 unsigned char **data_ret
, int incr
)
408 Bool del
= incr
? True
: False
;
410 int format_ret
, ret_val
= -1;
411 unsigned long len
, remain
;
412 unsigned char *data
= NULL
;
417 if (event
->xproperty
.atom
!= prop
) {
418 fprintf(x11
->errfile
, "PropertyNotify parameters mismatch\n");
422 if (event
->xselection
.property
== None
) {
424 fprintf(x11
->errfile
,
425 "XConvertSelection refused by clipboard owner\n");
429 if (event
->xselection
.requestor
!= x11
->selection_window
||
430 event
->xselection
.selection
!= x11
->clipboard_atom
||
431 event
->xselection
.property
!= prop
) {
432 fprintf(x11
->errfile
, "SelectionNotify parameters mismatch\n");
437 if (XGetWindowProperty(x11
->display
, x11
->selection_window
, prop
, 0,
438 LONG_MAX
, del
, type
, &type_ret
, &format_ret
, &len
,
439 &remain
, &data
) != Success
) {
440 fprintf(x11
->errfile
, "XGetWindowProperty failed\n");
445 if (type_ret
== x11
->incr_atom
) {
446 int prop_min_size
= *(uint32_t*)data
;
448 if (x11
->expect_property_notify
) {
449 fprintf(x11
->errfile
,
450 "received an incr SelectionNotify while "
451 "still reading another incr property\n");
455 if (x11
->clipboard_data_space
< prop_min_size
) {
456 free(x11
->clipboard_data
);
457 x11
->clipboard_data
= malloc(prop_min_size
);
458 if (!x11
->clipboard_data
) {
459 fprintf(x11
->errfile
,
460 "out of memory allocating clipboard buffer\n");
461 x11
->clipboard_data_space
= 0;
464 x11
->clipboard_data_space
= prop_min_size
;
466 x11
->expect_property_notify
= 1;
467 XSelectInput(x11
->display
, x11
->selection_window
,
469 XDeleteProperty(x11
->display
, x11
->selection_window
, prop
);
470 XFlush(x11
->display
);
472 return 0; /* Wait for more data */
474 XDeleteProperty(x11
->display
, x11
->selection_window
, prop
);
475 XFlush(x11
->display
);
478 if (type_ret
!= type
) {
479 fprintf(x11
->errfile
, "expected property type: %s, got: %s\n",
480 vdagent_x11_get_atom_name(x11
, type
),
481 vdagent_x11_get_atom_name(x11
, type_ret
));
485 if (format_ret
!= format
) {
486 fprintf(x11
->errfile
, "expected %d bit format, got %d bits\n", format
,
491 /* Convert len to bytes */
496 len
*= sizeof(short);
505 if (x11
->clipboard_data_size
+ len
> x11
->clipboard_data_space
) {
506 void *old_clipboard_data
= x11
->clipboard_data
;
508 x11
->clipboard_data_space
= x11
->clipboard_data_size
+ len
;
509 x11
->clipboard_data
= realloc(x11
->clipboard_data
,
510 x11
->clipboard_data_space
);
511 if (!x11
->clipboard_data
) {
512 fprintf(x11
->errfile
,
513 "out of memory allocating clipboard buffer\n");
514 x11
->clipboard_data_space
= 0;
515 free(old_clipboard_data
);
519 memcpy(x11
->clipboard_data
+ x11
->clipboard_data_size
, data
, len
);
520 x11
->clipboard_data_size
+= len
;
522 fprintf(x11
->errfile
, "Appended %ld bytes to buffer\n", len
);
524 return 0; /* Wait for more data */
526 len
= x11
->clipboard_data_size
;
527 *data_ret
= x11
->clipboard_data
;
534 fprintf(x11
->errfile
, "property contains no data (zero length)\n");
539 if ((incr
|| ret_val
== -1) && data
)
543 x11
->clipboard_data_size
= 0;
544 x11
->expect_property_notify
= 0;
550 static void vdagent_x11_get_selection_free(struct vdagent_x11
*x11
,
551 unsigned char *data
, int incr
)
554 /* If the clipboard has grown large return the memory to the system */
555 if (x11
->clipboard_data_space
> 512 * 1024) {
556 free(x11
->clipboard_data
);
557 x11
->clipboard_data
= NULL
;
558 x11
->clipboard_data_space
= 0;
564 static uint32_t vdagent_x11_target_to_type(struct vdagent_x11
*x11
,
569 for (i
= 0; i
< clipboard_format_count
; i
++) {
570 for (j
= 0; j
< x11
->clipboard_formats
[i
].atom_count
; i
++) {
571 if (x11
->clipboard_formats
[i
].atoms
[j
] == target
) {
572 return x11
->clipboard_formats
[i
].type
;
577 fprintf(x11
->errfile
, "unexpected selection type %s\n",
578 vdagent_x11_get_atom_name(x11
, target
));
579 return VD_AGENT_CLIPBOARD_NONE
;
582 static Atom
vdagent_x11_type_to_target(struct vdagent_x11
*x11
, uint32_t type
)
586 for (i
= 0; i
< x11
->clipboard_type_count
; i
++)
587 if (x11
->clipboard_agent_types
[i
] == type
)
588 return x11
->clipboard_x11_targets
[i
];
590 fprintf(x11
->errfile
, "client requested unavailable type %u\n", type
);
594 static void vdagent_x11_handle_selection_notify(struct vdagent_x11
*x11
,
595 XEvent
*event
, int incr
)
598 unsigned char *data
= NULL
;
601 if (x11
->clipboard_request_target
== None
) {
602 fprintf(x11
->errfile
, "SelectionNotify received without a target\n");
606 type
= vdagent_x11_target_to_type(x11
, x11
->clipboard_request_target
);
608 event
->xselection
.target
!= x11
->clipboard_request_target
&&
609 event
->xselection
.target
!= x11
->incr_atom
)
610 fprintf(x11
->errfile
, "Requested %s target got %s\n",
611 vdagent_x11_get_atom_name(x11
, x11
->clipboard_request_target
),
612 vdagent_x11_get_atom_name(x11
, event
->xselection
.target
));
614 len
= vdagent_x11_get_selection(x11
, event
, x11
->clipboard_request_target
,
615 x11
->clipboard_atom
, 8, &data
, incr
);
616 if (len
== 0) /* waiting for more data? */
619 type
= VD_AGENT_CLIPBOARD_NONE
;
623 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
, type
, data
, len
);
624 x11
->clipboard_request_target
= None
;
625 vdagent_x11_get_selection_free(x11
, data
, incr
);
628 static Atom
atom_lists_overlap(Atom
*atoms1
, Atom
*atoms2
, int l1
, int l2
)
632 for (i
= 0; i
< l1
; i
++)
633 for (j
= 0; j
< l2
; j
++)
634 if (atoms1
[i
] == atoms2
[j
])
640 static void vdagent_x11_print_targets(struct vdagent_x11
*x11
,
641 const char *action
, Atom
*atoms
, int c
)
648 fprintf(x11
->errfile
, "%s %d targets:\n", action
, c
);
649 for (i
= 0; i
< c
; i
++)
650 fprintf(x11
->errfile
, "%s\n",
651 vdagent_x11_get_atom_name(x11
, atoms
[i
]));
654 static void vdagent_x11_handle_targets_notify(struct vdagent_x11
*x11
,
655 XEvent
*event
, int incr
)
658 Atom atom
, *atoms
= NULL
;
660 if (!x11
->expected_targets_notifies
) {
661 fprintf(x11
->errfile
, "unexpected selection notify TARGETS\n");
665 x11
->expected_targets_notifies
--;
667 /* If we have more targets_notifies pending, ignore this one, we
668 are only interested in the targets list of the current owner
669 (which is the last one we've requested a targets list from) */
670 if (x11
->expected_targets_notifies
)
673 len
= vdagent_x11_get_selection(x11
, event
, XA_ATOM
, x11
->targets_atom
, 32,
674 (unsigned char **)&atoms
, incr
);
675 if (len
== 0 || len
== -1) /* waiting for more data or error? */
680 vdagent_x11_print_targets(x11
, "received", atoms
, len
);
682 x11
->clipboard_type_count
= 0;
683 for (i
= 0; i
< clipboard_format_count
; i
++) {
684 atom
= atom_lists_overlap(x11
->clipboard_formats
[i
].atoms
, atoms
,
685 x11
->clipboard_formats
[i
].atom_count
, len
);
687 x11
->clipboard_agent_types
[x11
->clipboard_type_count
] =
688 x11
->clipboard_formats
[i
].type
;
689 x11
->clipboard_x11_targets
[x11
->clipboard_type_count
] = atom
;
690 x11
->clipboard_type_count
++;
691 if (x11
->clipboard_type_count
==
692 sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t)) {
693 fprintf(x11
->errfile
,
694 "handle_targets_notify: too many types\n");
700 if (x11
->clipboard_type_count
) {
701 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_GRAB
, 0,
702 (uint8_t *)x11
->clipboard_agent_types
,
703 x11
->clipboard_type_count
* sizeof(uint32_t));
704 vdagent_x11_set_clipboard_owner(x11
, owner_guest
);
707 vdagent_x11_get_selection_free(x11
, (unsigned char *)atoms
, incr
);
710 static void vdagent_x11_send_selection_notify(struct vdagent_x11
*x11
,
711 Atom prop
, int process_next_req
)
713 XEvent res
, *event
= &x11
->selection_request
->event
;
715 res
.xselection
.property
= prop
;
716 res
.xselection
.type
= SelectionNotify
;
717 res
.xselection
.display
= event
->xselectionrequest
.display
;
718 res
.xselection
.requestor
= event
->xselectionrequest
.requestor
;
719 res
.xselection
.selection
= event
->xselectionrequest
.selection
;
720 res
.xselection
.target
= event
->xselectionrequest
.target
;
721 res
.xselection
.time
= event
->xselectionrequest
.time
;
722 XSendEvent(x11
->display
, event
->xselectionrequest
.requestor
, 0, 0, &res
);
723 XFlush(x11
->display
);
725 if (process_next_req
) {
726 vdagent_x11_next_selection_request(x11
);
727 vdagent_x11_handle_selection_request(x11
);
731 static void vdagent_x11_send_targets(struct vdagent_x11
*x11
, XEvent
*event
)
733 Atom prop
, targets
[256] = { x11
->targets_atom
, };
734 int i
, j
, k
, target_count
= 1;
736 for (i
= 0; i
< x11
->clipboard_type_count
; i
++) {
737 for (j
= 0; j
< clipboard_format_count
; j
++) {
738 if (x11
->clipboard_formats
[j
].type
!=
739 x11
->clipboard_agent_types
[i
])
742 for (k
= 0; k
< x11
->clipboard_formats
[j
].atom_count
; k
++) {
743 targets
[target_count
] = x11
->clipboard_formats
[j
].atoms
[k
];
745 if (target_count
== sizeof(targets
)/sizeof(Atom
)) {
746 fprintf(x11
->errfile
, "send_targets: too many targets\n");
754 prop
= event
->xselectionrequest
.property
;
756 prop
= event
->xselectionrequest
.target
;
758 XChangeProperty(x11
->display
, event
->xselectionrequest
.requestor
, prop
,
759 XA_ATOM
, 32, PropModeReplace
, (unsigned char *)&targets
,
761 vdagent_x11_print_targets(x11
, "sent", targets
, target_count
);
762 vdagent_x11_send_selection_notify(x11
, prop
, 1);
765 static void vdagent_x11_handle_selection_request(struct vdagent_x11
*x11
)
768 uint32_t type
= VD_AGENT_CLIPBOARD_NONE
;
770 if (!x11
->selection_request
)
773 event
= &x11
->selection_request
->event
;
775 if (x11
->clipboard_owner
!= owner_client
) {
776 fprintf(x11
->errfile
,
777 "received selection request event for target %s, "
778 "while not owning client clipboard\n",
779 vdagent_x11_get_atom_name(x11
, event
->xselectionrequest
.target
));
780 vdagent_x11_send_selection_notify(x11
, None
, 1);
784 if (event
->xselectionrequest
.target
== x11
->multiple_atom
) {
785 fprintf(x11
->errfile
, "multiple target not supported\n");
786 vdagent_x11_send_selection_notify(x11
, None
, 1);
790 if (event
->xselectionrequest
.target
== x11
->targets_atom
) {
791 vdagent_x11_send_targets(x11
, event
);
795 type
= vdagent_x11_target_to_type(x11
, event
->xselectionrequest
.target
);
796 if (type
== VD_AGENT_CLIPBOARD_NONE
) {
797 vdagent_x11_send_selection_notify(x11
, None
, 1);
801 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_REQUEST
, type
, NULL
, 0);
804 void vdagent_x11_set_monitor_config(struct vdagent_x11
*x11
,
805 VDAgentMonitorsConfig
*mon_config
)
807 int i
, num_sizes
= 0;
809 unsigned int closest_diff
= -1;
810 XRRScreenSize
* sizes
;
811 XRRScreenConfiguration
* config
;
814 if (!x11
->has_xrandr
)
817 if (mon_config
->num_of_monitors
!= 1) {
818 fprintf(x11
->errfile
,
819 "Only 1 monitor supported, ignoring additional monitors\n");
822 sizes
= XRRSizes(x11
->display
, x11
->screen
, &num_sizes
);
823 if (!sizes
|| !num_sizes
) {
824 fprintf(x11
->errfile
, "XRRSizes failed\n");
828 /* Find the closest size which will fit within the monitor */
829 for (i
= 0; i
< num_sizes
; i
++) {
830 if (sizes
[i
].width
> mon_config
->monitors
[0].width
||
831 sizes
[i
].height
> mon_config
->monitors
[0].height
)
832 continue; /* Too large for the monitor */
834 unsigned int wdiff
= mon_config
->monitors
[0].width
- sizes
[i
].width
;
835 unsigned int hdiff
= mon_config
->monitors
[0].height
- sizes
[i
].height
;
836 unsigned int diff
= wdiff
* wdiff
+ hdiff
* hdiff
;
837 if (diff
< closest_diff
) {
844 fprintf(x11
->errfile
, "no suitable resolution found for monitor\n");
848 config
= XRRGetScreenInfo(x11
->display
, x11
->root_window
);
850 fprintf(x11
->errfile
, "get screen info failed\n");
853 XRRConfigCurrentConfiguration(config
, &rotation
);
854 XRRSetScreenConfig(x11
->display
, config
, x11
->root_window
, best
,
855 rotation
, CurrentTime
);
856 XRRFreeScreenConfigInfo(config
);
857 XFlush(x11
->display
);
858 x11
->width
= sizes
[best
].width
;
859 x11
->height
= sizes
[best
].height
;
860 vdagent_x11_send_daemon_guest_xorg_res(x11
);
863 void vdagent_x11_clipboard_request(struct vdagent_x11
*x11
, uint32_t type
)
867 if (x11
->clipboard_owner
!= owner_guest
) {
868 fprintf(x11
->errfile
,
869 "received clipboard req while not owning guest clipboard\n");
870 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
871 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
875 target
= vdagent_x11_type_to_target(x11
, type
);
876 if (target
== None
) {
877 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
878 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
882 if (x11
->clipboard_request_target
) {
883 fprintf(x11
->errfile
,
884 "XConvertSelection request is already pending\n");
885 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
886 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
889 x11
->clipboard_request_target
= target
;
890 XConvertSelection(x11
->display
, x11
->clipboard_atom
, target
,
891 x11
->clipboard_atom
, x11
->selection_window
, CurrentTime
);
892 XFlush(x11
->display
);
895 void vdagent_x11_clipboard_grab(struct vdagent_x11
*x11
, uint32_t *types
,
898 if (type_count
> sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t)) {
899 fprintf(x11
->errfile
, "x11_clipboard_grab: too many types\n");
900 type_count
= sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t);
903 memcpy(x11
->clipboard_agent_types
, types
, type_count
* sizeof(uint32_t));
904 x11
->clipboard_type_count
= type_count
;
906 XSetSelectionOwner(x11
->display
, x11
->clipboard_atom
,
907 x11
->selection_window
, CurrentTime
);
908 XFlush(x11
->display
);
909 vdagent_x11_set_clipboard_owner(x11
, owner_client
);
912 void vdagent_x11_clipboard_data(struct vdagent_x11
*x11
, uint32_t type
,
913 uint8_t *data
, uint32_t size
)
917 uint32_t type_from_event
;
919 if (!x11
->selection_request
) {
920 fprintf(x11
->errfile
, "received clipboard data without an outstanding"
921 "selection request, ignoring\n");
926 event
= &x11
->selection_request
->event
;
927 type_from_event
= vdagent_x11_target_to_type(x11
,
928 event
->xselectionrequest
.target
);
929 if (type_from_event
!= type
) {
930 fprintf(x11
->errfile
, "expecting type %u clipboard data got %u\n",
931 type_from_event
, type
);
932 vdagent_x11_send_selection_notify(x11
, None
, 1);
937 prop
= event
->xselectionrequest
.property
;
939 prop
= event
->xselectionrequest
.target
;
941 /* FIXME: use INCR for large data transfers */
942 XChangeProperty(x11
->display
, event
->xselectionrequest
.requestor
, prop
,
943 event
->xselectionrequest
.target
, 8, PropModeReplace
,
945 vdagent_x11_send_selection_notify(x11
, prop
, 1);
949 void vdagent_x11_clipboard_release(struct vdagent_x11
*x11
)
953 if (x11
->clipboard_owner
!= owner_client
) {
954 fprintf(x11
->errfile
,
955 "received clipboard release while not owning client clipboard\n");
959 XSetSelectionOwner(x11
->display
, x11
->clipboard_atom
, None
, CurrentTime
);
960 /* Make sure we process the XFixesSetSelectionOwnerNotify event caused
961 by this, so we don't end up changing the clipboard owner to none, after
962 it has already been re-owned because this event is still pending. */
963 XSync(x11
->display
, False
);
964 while (XCheckTypedEvent(x11
->display
, x11
->xfixes_event_base
,
966 vdagent_x11_handle_event(x11
, event
);
968 /* Note no need to do a set_clipboard_owner(owner_none) here, as that is
969 already done by processing the XFixesSetSelectionOwnerNotify event. */