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 x11
->clipboard_data_size
= 0;
215 x11
->clipboard_request_target
= None
;
216 x11
->expect_property_notify
= 0;
218 if (new_owner
== owner_none
) {
219 /* When going from owner_guest to owner_none we need to send a
220 clipboard release message to the client */
221 if (x11
->clipboard_owner
== owner_guest
)
222 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_RELEASE
, 0, NULL
, 0);
224 x11
->clipboard_type_count
= 0;
226 x11
->clipboard_owner
= new_owner
;
229 static void vdagent_x11_handle_event(struct vdagent_x11
*x11
, XEvent event
)
234 if (event
.type
== x11
->xfixes_event_base
) {
237 XFixesSelectionNotifyEvent xfev
;
241 switch (ev
.xfev
.subtype
) {
242 case XFixesSetSelectionOwnerNotify
:
244 /* Treat ... as a SelectionOwnerNotify None */
245 case XFixesSelectionWindowDestroyNotify
:
246 case XFixesSelectionClientCloseNotify
:
247 ev
.xfev
.owner
= None
;
251 fprintf(x11
->errfile
,
252 "unexpected xfix event subtype %d window %d\n",
253 (int)ev
.xfev
.subtype
, (int)event
.xany
.window
);
258 fprintf(x11
->errfile
, "New selection owner: %u\n",
259 (unsigned int)ev
.xfev
.owner
);
261 /* Ignore becoming the owner ourselves */
262 if (ev
.xfev
.owner
== x11
->selection_window
)
265 /* If the clipboard owner is changed we no longer own it */
266 vdagent_x11_set_clipboard_owner(x11
, owner_none
);
268 if (ev
.xfev
.owner
== None
)
271 /* Request the supported targets from the new owner */
272 XConvertSelection(x11
->display
, x11
->clipboard_atom
, x11
->targets_atom
,
273 x11
->targets_atom
, x11
->selection_window
,
275 XFlush(x11
->display
);
276 x11
->expected_targets_notifies
++;
280 switch (event
.type
) {
281 case ConfigureNotify
:
282 if (event
.xconfigure
.window
!= x11
->root_window
)
287 if (event
.xconfigure
.width
== x11
->width
&&
288 event
.xconfigure
.height
== x11
->height
)
291 x11
->width
= event
.xconfigure
.width
;
292 x11
->height
= event
.xconfigure
.height
;
294 vdagent_x11_send_daemon_guest_xorg_res(x11
);
296 case SelectionNotify
:
297 if (event
.xselection
.target
== x11
->targets_atom
)
298 vdagent_x11_handle_targets_notify(x11
, &event
, 0);
300 vdagent_x11_handle_selection_notify(x11
, &event
, 0);
306 if (!x11
->expect_property_notify
||
307 event
.xproperty
.state
!= PropertyNewValue
)
310 if (event
.xproperty
.atom
== x11
->targets_atom
)
311 vdagent_x11_handle_targets_notify(x11
, &event
, 1);
313 vdagent_x11_handle_selection_notify(x11
, &event
, 1);
316 /* Do nothing the clipboard ownership will get updated through
317 the XFixesSetSelectionOwnerNotify event */
320 case SelectionRequest
: {
321 struct vdagent_x11_selection_request
*req
, *new_req
;
323 new_req
= malloc(sizeof(*new_req
));
325 fprintf(x11
->errfile
,
326 "out of memory on SelectionRequest, ignoring.\n");
332 new_req
->event
= event
;
333 new_req
->next
= NULL
;
335 if (!x11
->selection_request
) {
336 x11
->selection_request
= new_req
;
337 vdagent_x11_handle_selection_request(x11
);
341 /* maybe we should limit the selection_request stack depth ? */
342 req
= x11
->selection_request
;
350 if (!handled
&& x11
->verbose
)
351 fprintf(x11
->errfile
, "unhandled x11 event, type %d, window %d\n",
352 (int)event
.type
, (int)event
.xany
.window
);
355 void vdagent_x11_do_read(struct vdagent_x11
*x11
)
359 while (XPending(x11
->display
)) {
360 XNextEvent(x11
->display
, &event
);
361 vdagent_x11_handle_event(x11
, event
);
365 static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11
*x11
)
367 struct vdagentd_guest_xorg_resolution res
;
369 res
.width
= x11
->width
;
370 res
.height
= x11
->height
;
372 udscs_write(x11
->vdagentd
, VDAGENTD_GUEST_XORG_RESOLUTION
, 0,
373 (uint8_t *)&res
, sizeof(res
));
376 static const char *vdagent_x11_get_atom_name(struct vdagent_x11
*x11
, Atom a
)
381 return XGetAtomName(x11
->display
, a
);
384 static int vdagent_x11_get_selection(struct vdagent_x11
*x11
, XEvent
*event
,
385 Atom type
, Atom prop
, int format
,
386 unsigned char **data_ret
, int incr
)
388 Bool del
= incr
? True
: False
;
390 int format_ret
, ret_val
= -1;
391 unsigned long len
, remain
;
392 unsigned char *data
= NULL
;
397 if (event
->xproperty
.atom
!= prop
) {
398 fprintf(x11
->errfile
, "PropertyNotify parameters mismatch\n");
402 if (event
->xselection
.property
== None
) {
404 fprintf(x11
->errfile
,
405 "XConvertSelection refused by clipboard owner\n");
409 if (event
->xselection
.requestor
!= x11
->selection_window
||
410 event
->xselection
.selection
!= x11
->clipboard_atom
||
411 event
->xselection
.property
!= prop
) {
412 fprintf(x11
->errfile
, "SelectionNotify parameters mismatch\n");
417 if (XGetWindowProperty(x11
->display
, x11
->selection_window
, prop
, 0,
418 LONG_MAX
, del
, type
, &type_ret
, &format_ret
, &len
,
419 &remain
, &data
) != Success
) {
420 fprintf(x11
->errfile
, "XGetWindowProperty failed\n");
425 if (type_ret
== x11
->incr_atom
) {
426 int prop_min_size
= *(uint32_t*)data
;
428 if (x11
->expect_property_notify
) {
429 fprintf(x11
->errfile
,
430 "received an incr property notify while "
431 "still reading another incr property\n");
435 if (x11
->clipboard_data_space
< prop_min_size
) {
436 free(x11
->clipboard_data
);
437 x11
->clipboard_data
= malloc(prop_min_size
);
438 if (!x11
->clipboard_data
) {
439 fprintf(x11
->errfile
,
440 "out of memory allocating clipboard buffer\n");
441 x11
->clipboard_data_space
= 0;
444 x11
->clipboard_data_space
= prop_min_size
;
446 x11
->expect_property_notify
= 1;
447 XSelectInput(x11
->display
, x11
->selection_window
,
449 XDeleteProperty(x11
->display
, x11
->selection_window
, prop
);
450 XFlush(x11
->display
);
452 return 0; /* Wait for more data */
454 XDeleteProperty(x11
->display
, x11
->selection_window
, prop
);
455 XFlush(x11
->display
);
458 if (type_ret
!= type
) {
459 fprintf(x11
->errfile
, "expected property type: %s, got: %s\n",
460 vdagent_x11_get_atom_name(x11
, type
),
461 vdagent_x11_get_atom_name(x11
, type_ret
));
465 if (format_ret
!= format
) {
466 fprintf(x11
->errfile
, "expected %d bit format, got %d bits\n", format
,
471 /* Convert len to bytes */
476 len
*= sizeof(short);
485 if (x11
->clipboard_data_size
+ len
> x11
->clipboard_data_space
) {
486 void *old_clipboard_data
= x11
->clipboard_data
;
488 x11
->clipboard_data_space
= x11
->clipboard_data_size
+ len
;
489 x11
->clipboard_data
= realloc(x11
->clipboard_data
,
490 x11
->clipboard_data_space
);
491 if (!x11
->clipboard_data
) {
492 fprintf(x11
->errfile
,
493 "out of memory allocating clipboard buffer\n");
494 x11
->clipboard_data_space
= 0;
495 free(old_clipboard_data
);
499 memcpy(x11
->clipboard_data
+ x11
->clipboard_data_size
, data
, len
);
500 x11
->clipboard_data_size
+= len
;
502 fprintf(x11
->errfile
, "Appended %ld bytes to buffer\n", len
);
504 return 0; /* Wait for more data */
506 len
= x11
->clipboard_data_size
;
507 *data_ret
= x11
->clipboard_data
;
514 fprintf(x11
->errfile
, "property contains no data (zero length)\n");
519 if ((incr
|| ret_val
== -1) && data
)
523 x11
->clipboard_data_size
= 0;
524 x11
->expect_property_notify
= 0;
530 static void vdagent_x11_get_selection_free(struct vdagent_x11
*x11
,
531 unsigned char *data
, int incr
)
534 /* If the clipboard has grown large return the memory to the system */
535 if (x11
->clipboard_data_space
> 512 * 1024) {
536 free(x11
->clipboard_data
);
537 x11
->clipboard_data
= NULL
;
538 x11
->clipboard_data_space
= 0;
544 static uint32_t vdagent_x11_target_to_type(struct vdagent_x11
*x11
,
550 return VD_AGENT_CLIPBOARD_NONE
;
552 for (i
= 0; i
< clipboard_format_count
; i
++) {
553 for (j
= 0; j
< x11
->clipboard_formats
[i
].atom_count
; i
++) {
554 if (x11
->clipboard_formats
[i
].atoms
[j
] == target
) {
555 return x11
->clipboard_formats
[i
].type
;
560 fprintf(x11
->errfile
, "unexpected selection type %s\n",
561 vdagent_x11_get_atom_name(x11
, target
));
562 return VD_AGENT_CLIPBOARD_NONE
;
565 static Atom
vdagent_x11_type_to_target(struct vdagent_x11
*x11
, uint32_t type
)
569 for (i
= 0; i
< x11
->clipboard_type_count
; i
++)
570 if (x11
->clipboard_agent_types
[i
] == type
)
571 return x11
->clipboard_x11_targets
[i
];
573 fprintf(x11
->errfile
, "client requested unavailable type %u\n", type
);
577 static void vdagent_x11_handle_selection_notify(struct vdagent_x11
*x11
,
578 XEvent
*event
, int incr
)
581 unsigned char *data
= NULL
;
584 type
= vdagent_x11_target_to_type(x11
, x11
->clipboard_request_target
);
586 if (x11
->clipboard_request_target
== None
)
587 fprintf(x11
->errfile
, "SelectionNotify received without a target\n");
589 event
->xselection
.target
!= x11
->clipboard_request_target
)
590 fprintf(x11
->errfile
, "Requested %s target got %s\n",
591 vdagent_x11_get_atom_name(x11
, x11
->clipboard_request_target
),
592 vdagent_x11_get_atom_name(x11
, event
->xselection
.target
));
594 len
= vdagent_x11_get_selection(x11
, event
, x11
->clipboard_request_target
,
595 x11
->clipboard_atom
, 8, &data
, incr
);
596 if (len
== 0) /* waiting for more data? */
599 type
= VD_AGENT_CLIPBOARD_NONE
;
603 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
, type
, data
, len
);
604 x11
->clipboard_request_target
= None
;
605 vdagent_x11_get_selection_free(x11
, data
, incr
);
608 static Atom
atom_lists_overlap(Atom
*atoms1
, Atom
*atoms2
, int l1
, int l2
)
612 for (i
= 0; i
< l1
; i
++)
613 for (j
= 0; j
< l2
; j
++)
614 if (atoms1
[i
] == atoms2
[j
])
620 static void vdagent_x11_print_targets(struct vdagent_x11
*x11
,
621 const char *action
, Atom
*atoms
, int c
)
628 fprintf(x11
->errfile
, "%s %d targets:\n", action
, c
);
629 for (i
= 0; i
< c
; i
++)
630 fprintf(x11
->errfile
, "%s\n",
631 vdagent_x11_get_atom_name(x11
, atoms
[i
]));
634 static void vdagent_x11_handle_targets_notify(struct vdagent_x11
*x11
,
635 XEvent
*event
, int incr
)
638 Atom atom
, *atoms
= NULL
;
640 if (!x11
->expected_targets_notifies
) {
641 fprintf(x11
->errfile
, "unexpected selection notify TARGETS\n");
645 x11
->expected_targets_notifies
--;
647 /* If we have more targets_notifies pending, ignore this one, we
648 are only interested in the targets list of the current owner
649 (which is the last one we've requested a targets list from) */
650 if (x11
->expected_targets_notifies
)
653 len
= vdagent_x11_get_selection(x11
, event
, XA_ATOM
, x11
->targets_atom
, 32,
654 (unsigned char **)&atoms
, incr
);
655 if (len
== 0 || len
== -1) /* waiting for more data or error? */
660 vdagent_x11_print_targets(x11
, "received", atoms
, len
);
662 x11
->clipboard_type_count
= 0;
663 for (i
= 0; i
< clipboard_format_count
; i
++) {
664 atom
= atom_lists_overlap(x11
->clipboard_formats
[i
].atoms
, atoms
,
665 x11
->clipboard_formats
[i
].atom_count
, len
);
667 x11
->clipboard_agent_types
[x11
->clipboard_type_count
] =
668 x11
->clipboard_formats
[i
].type
;
669 x11
->clipboard_x11_targets
[x11
->clipboard_type_count
] = atom
;
670 x11
->clipboard_type_count
++;
671 if (x11
->clipboard_type_count
==
672 sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t)) {
673 fprintf(x11
->errfile
,
674 "handle_targets_notify: too many types\n");
680 if (x11
->clipboard_type_count
) {
681 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_GRAB
, 0,
682 (uint8_t *)x11
->clipboard_agent_types
,
683 x11
->clipboard_type_count
* sizeof(uint32_t));
684 vdagent_x11_set_clipboard_owner(x11
, owner_guest
);
687 vdagent_x11_get_selection_free(x11
, (unsigned char *)atoms
, incr
);
690 static void vdagent_x11_send_selection_notify(struct vdagent_x11
*x11
,
691 Atom prop
, int process_next_req
)
693 XEvent res
, *event
= &x11
->selection_request
->event
;
694 struct vdagent_x11_selection_request
*selection_request
;
696 res
.xselection
.property
= prop
;
697 res
.xselection
.type
= SelectionNotify
;
698 res
.xselection
.display
= event
->xselectionrequest
.display
;
699 res
.xselection
.requestor
= event
->xselectionrequest
.requestor
;
700 res
.xselection
.selection
= event
->xselectionrequest
.selection
;
701 res
.xselection
.target
= event
->xselectionrequest
.target
;
702 res
.xselection
.time
= event
->xselectionrequest
.time
;
703 XSendEvent(x11
->display
, event
->xselectionrequest
.requestor
, 0, 0, &res
);
704 XFlush(x11
->display
);
706 selection_request
= x11
->selection_request
;
707 x11
->selection_request
= selection_request
->next
;
708 free(selection_request
);
709 if (process_next_req
)
710 vdagent_x11_handle_selection_request(x11
);
713 static void vdagent_x11_send_targets(struct vdagent_x11
*x11
, XEvent
*event
)
715 Atom prop
, targets
[256] = { x11
->targets_atom
, };
716 int i
, j
, k
, target_count
= 1;
718 for (i
= 0; i
< x11
->clipboard_type_count
; i
++) {
719 for (j
= 0; j
< clipboard_format_count
; j
++) {
720 if (x11
->clipboard_formats
[j
].type
!=
721 x11
->clipboard_agent_types
[i
])
724 for (k
= 0; k
< x11
->clipboard_formats
[j
].atom_count
; k
++) {
725 targets
[target_count
] = x11
->clipboard_formats
[j
].atoms
[k
];
727 if (target_count
== sizeof(targets
)/sizeof(Atom
)) {
728 fprintf(x11
->errfile
, "send_targets: too many targets\n");
736 prop
= event
->xselectionrequest
.property
;
738 prop
= event
->xselectionrequest
.target
;
740 XChangeProperty(x11
->display
, event
->xselectionrequest
.requestor
, prop
,
741 XA_ATOM
, 32, PropModeReplace
, (unsigned char *)&targets
,
743 vdagent_x11_print_targets(x11
, "sent", targets
, target_count
);
744 vdagent_x11_send_selection_notify(x11
, prop
, 1);
747 static void vdagent_x11_handle_selection_request(struct vdagent_x11
*x11
)
750 uint32_t type
= VD_AGENT_CLIPBOARD_NONE
;
752 if (!x11
->selection_request
)
755 event
= &x11
->selection_request
->event
;
757 if (x11
->clipboard_owner
!= owner_client
) {
758 fprintf(x11
->errfile
,
759 "received selection request event for target %s, "
760 "while not owning client clipboard\n",
761 vdagent_x11_get_atom_name(x11
, event
->xselectionrequest
.target
));
762 vdagent_x11_send_selection_notify(x11
, None
, 1);
766 if (event
->xselectionrequest
.target
== x11
->multiple_atom
) {
767 fprintf(x11
->errfile
, "multiple target not supported\n");
768 vdagent_x11_send_selection_notify(x11
, None
, 1);
772 if (event
->xselectionrequest
.target
== x11
->targets_atom
) {
773 vdagent_x11_send_targets(x11
, event
);
777 type
= vdagent_x11_target_to_type(x11
, event
->xselectionrequest
.target
);
778 if (type
== VD_AGENT_CLIPBOARD_NONE
) {
779 vdagent_x11_send_selection_notify(x11
, None
, 1);
783 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_REQUEST
, type
, NULL
, 0);
786 void vdagent_x11_set_monitor_config(struct vdagent_x11
*x11
,
787 VDAgentMonitorsConfig
*mon_config
)
789 int i
, num_sizes
= 0;
791 unsigned int closest_diff
= -1;
792 XRRScreenSize
* sizes
;
793 XRRScreenConfiguration
* config
;
796 if (!x11
->has_xrandr
)
799 if (mon_config
->num_of_monitors
!= 1) {
800 fprintf(x11
->errfile
,
801 "Only 1 monitor supported, ignoring monitor config\n");
805 sizes
= XRRSizes(x11
->display
, x11
->screen
, &num_sizes
);
806 if (!sizes
|| !num_sizes
) {
807 fprintf(x11
->errfile
, "XRRSizes failed\n");
811 /* Find the closest size which will fit within the monitor */
812 for (i
= 0; i
< num_sizes
; i
++) {
813 if (sizes
[i
].width
> mon_config
->monitors
[0].width
||
814 sizes
[i
].height
> mon_config
->monitors
[0].height
)
815 continue; /* Too large for the monitor */
817 unsigned int wdiff
= mon_config
->monitors
[0].width
- sizes
[i
].width
;
818 unsigned int hdiff
= mon_config
->monitors
[0].height
- sizes
[i
].height
;
819 unsigned int diff
= wdiff
* wdiff
+ hdiff
* hdiff
;
820 if (diff
< closest_diff
) {
827 fprintf(x11
->errfile
, "no suitable resolution found for monitor\n");
831 config
= XRRGetScreenInfo(x11
->display
, x11
->root_window
);
833 fprintf(x11
->errfile
, "get screen info failed\n");
836 XRRConfigCurrentConfiguration(config
, &rotation
);
837 XRRSetScreenConfig(x11
->display
, config
, x11
->root_window
, best
,
838 rotation
, CurrentTime
);
839 XRRFreeScreenConfigInfo(config
);
840 XFlush(x11
->display
);
841 x11
->width
= sizes
[best
].width
;
842 x11
->height
= sizes
[best
].height
;
843 vdagent_x11_send_daemon_guest_xorg_res(x11
);
846 void vdagent_x11_clipboard_request(struct vdagent_x11
*x11
, uint32_t type
)
850 if (x11
->clipboard_owner
!= owner_guest
) {
851 fprintf(x11
->errfile
,
852 "received clipboard req while not owning guest clipboard\n");
853 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
854 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
858 target
= vdagent_x11_type_to_target(x11
, type
);
859 if (target
== None
) {
860 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
861 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
865 if (x11
->clipboard_request_target
) {
866 fprintf(x11
->errfile
,
867 "XConvertSelection request is already pending\n");
868 udscs_write(x11
->vdagentd
, VDAGENTD_CLIPBOARD_DATA
,
869 VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
872 x11
->clipboard_request_target
= target
;
873 XConvertSelection(x11
->display
, x11
->clipboard_atom
, target
,
874 x11
->clipboard_atom
, x11
->selection_window
, CurrentTime
);
875 XFlush(x11
->display
);
878 void vdagent_x11_clipboard_grab(struct vdagent_x11
*x11
, uint32_t *types
,
881 if (type_count
> sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t)) {
882 fprintf(x11
->errfile
, "x11_clipboard_grab: too many types\n");
883 type_count
= sizeof(x11
->clipboard_agent_types
)/sizeof(uint32_t);
886 memcpy(x11
->clipboard_agent_types
, types
, type_count
* sizeof(uint32_t));
887 x11
->clipboard_type_count
= type_count
;
889 XSetSelectionOwner(x11
->display
, x11
->clipboard_atom
,
890 x11
->selection_window
, CurrentTime
);
891 XFlush(x11
->display
);
892 vdagent_x11_set_clipboard_owner(x11
, owner_client
);
895 void vdagent_x11_clipboard_data(struct vdagent_x11
*x11
, uint32_t type
,
896 const uint8_t *data
, uint32_t size
)
900 uint32_t type_from_event
;
902 if (!x11
->selection_request
) {
903 fprintf(x11
->errfile
, "received clipboard data without an outstanding"
904 "selection request, ignoring\n");
908 event
= &x11
->selection_request
->event
;
909 type_from_event
= vdagent_x11_target_to_type(x11
,
910 event
->xselectionrequest
.target
);
911 if (type_from_event
!= type
) {
912 fprintf(x11
->errfile
, "expecting type %u clipboard data got %u\n",
913 type_from_event
, type
);
914 vdagent_x11_send_selection_notify(x11
, None
, 1);
918 prop
= event
->xselectionrequest
.property
;
920 prop
= event
->xselectionrequest
.target
;
922 /* FIXME: use INCR for large data transfers */
923 XChangeProperty(x11
->display
, event
->xselectionrequest
.requestor
, prop
,
924 event
->xselectionrequest
.target
, 8, PropModeReplace
,
926 vdagent_x11_send_selection_notify(x11
, prop
, 1);
929 void vdagent_x11_clipboard_release(struct vdagent_x11
*x11
)
933 if (x11
->clipboard_owner
!= owner_client
) {
934 fprintf(x11
->errfile
,
935 "received clipboard release while not owning client clipboard\n");
939 XSetSelectionOwner(x11
->display
, x11
->clipboard_atom
, None
, CurrentTime
);
940 /* Make sure we process the XFixesSetSelectionOwnerNotify event caused
941 by this, so we don't end up changing the clipboard owner to none, after
942 it has already been re-owned because this event is still pending. */
943 XSync(x11
->display
, False
);
944 while (XCheckTypedEvent(x11
->display
, x11
->xfixes_event_base
,
946 vdagent_x11_handle_event(x11
, event
);
948 /* Note no need to do a set_clipboard_owner(owner_none) here, as that is
949 already done by processing the XFixesSetSelectionOwnerNotify event. */