1 /*
2 * Virt Viewer: A virtual machine console viewer
3 *
4 * Copyright (C) 2007-2012 Red Hat, Inc.
5 * Copyright (C) 2009-2012 Daniel P. Berrange
6 * Copyright (C) 2010 Marc-André Lureau
7 *
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 2 of the License, or
11 * (at your option) any later version.
12 *
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.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * Author: Daniel P. Berrange <berrange@redhat.com>
23 */
24
25 #include <config.h>
26
27 #include <locale.h>
28 #include <math.h>
29
30 #include "virt-viewer-session.h"
31 #include "virt-viewer-display.h"
32 #include "virt-viewer-util.h"
33
34 typedef struct _VirtViewerDisplayPrivate VirtViewerDisplayPrivate;
35 struct _VirtViewerDisplayPrivate
36 {
37 guint desktopWidth;
38 guint desktopHeight;
39 guint zoom_level;
40 gint nth_display; /* Monitor number inside the guest */
41 gint monitor; /* Monitor number on the client */
42 guint show_hint;
43 VirtViewerSession *session;
44 gboolean fullscreen;
45 gboolean auto_resize;
46 gboolean force_aspect;
47 };
48
49 static void virt_viewer_display_get_preferred_width(GtkWidget *widget,
50 int *minwidth,
51 int *defwidth);
52 static void virt_viewer_display_get_preferred_height(GtkWidget *widget,
53 int *minheight,
54 int *defheight);
55 static void virt_viewer_display_size_allocate(GtkWidget *widget,
56 GtkAllocation *allocation);
57 static void virt_viewer_display_set_property(GObject *object,
58 guint prop_id,
59 const GValue *value,
60 GParamSpec *pspec);
61 static void virt_viewer_display_get_property(GObject *object,
62 guint prop_id,
63 GValue *value,
64 GParamSpec *pspec);
65 static void virt_viewer_display_grab_focus(GtkWidget *widget);
66
67 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(VirtViewerDisplay, virt_viewer_display, GTK_TYPE_BIN)
68
69 enum {
70 PROP_0,
71
72 PROP_DESKTOP_WIDTH,
73 PROP_DESKTOP_HEIGHT,
74 PROP_FULLSCREEN,
75 PROP_NTH_DISPLAY,
76 PROP_ZOOM_LEVEL,
77 PROP_SHOW_HINT,
78 PROP_SESSION,
79 PROP_SELECTABLE,
80 PROP_MONITOR,
81 PROP_AUTO_RESIZE,
82 PROP_FORCE_ASPECT,
83 };
84
85 static void
virt_viewer_display_class_init(VirtViewerDisplayClass * class)86 virt_viewer_display_class_init(VirtViewerDisplayClass *class)
87 {
88 GObjectClass *object_class = G_OBJECT_CLASS(class);
89 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class);
90
91 object_class->set_property = virt_viewer_display_set_property;
92 object_class->get_property = virt_viewer_display_get_property;
93
94 widget_class->get_preferred_width = virt_viewer_display_get_preferred_width;
95 widget_class->get_preferred_height = virt_viewer_display_get_preferred_height;
96 widget_class->size_allocate = virt_viewer_display_size_allocate;
97 widget_class->grab_focus = virt_viewer_display_grab_focus;
98
99 g_object_class_install_property(object_class,
100 PROP_DESKTOP_WIDTH,
101 g_param_spec_int("desktop-width",
102 "Width",
103 "Desktop width",
104 1,
105 G_MAXINT32,
106 MIN_DISPLAY_WIDTH,
107 G_PARAM_READWRITE));
108
109 g_object_class_install_property(object_class,
110 PROP_DESKTOP_HEIGHT,
111 g_param_spec_int("desktop-height",
112 "Height",
113 "Desktop height",
114 1,
115 G_MAXINT32,
116 MIN_DISPLAY_HEIGHT,
117 G_PARAM_READWRITE));
118
119 g_object_class_install_property(object_class,
120 PROP_ZOOM_LEVEL,
121 g_param_spec_int("zoom-level",
122 "Zoom",
123 "Zoom level",
124 MIN_ZOOM_LEVEL,
125 MAX_ZOOM_LEVEL,
126 NORMAL_ZOOM_LEVEL,
127 G_PARAM_READWRITE));
128
129 g_object_class_install_property(object_class,
130 PROP_NTH_DISPLAY,
131 g_param_spec_int("nth-display",
132 "Nth display",
133 "Nth display",
134 -1,
135 G_MAXINT32,
136 0,
137 G_PARAM_READWRITE |
138 G_PARAM_CONSTRUCT_ONLY));
139
140 g_object_class_install_property(object_class,
141 PROP_SHOW_HINT,
142 g_param_spec_flags("show-hint",
143 "Show hint",
144 "Show state hint",
145 VIRT_VIEWER_TYPE_DISPLAY_SHOW_HINT_FLAGS,
146 0,
147 G_PARAM_READABLE));
148
149 g_object_class_install_property(object_class,
150 PROP_SESSION,
151 g_param_spec_object("session",
152 "Session",
153 "VirtSession",
154 VIRT_VIEWER_TYPE_SESSION,
155 G_PARAM_READWRITE |
156 G_PARAM_CONSTRUCT_ONLY));
157
158 g_object_class_install_property(object_class,
159 PROP_SELECTABLE,
160 g_param_spec_boolean("selectable",
161 "Selectable",
162 "Selectable",
163 FALSE,
164 G_PARAM_READABLE));
165
166 g_object_class_install_property(object_class,
167 PROP_MONITOR,
168 g_param_spec_int("monitor",
169 "Monitor",
170 "Display Monitor",
171 -1,
172 G_MAXINT32,
173 -1,
174 G_PARAM_READWRITE |
175 G_PARAM_CONSTRUCT));
176
177 g_object_class_install_property(object_class,
178 PROP_FULLSCREEN,
179 g_param_spec_boolean("fullscreen",
180 "Fullscreen",
181 "Fullscreen",
182 FALSE,
183 G_PARAM_READABLE));
184
185 g_object_class_install_property(object_class,
186 PROP_AUTO_RESIZE,
187 g_param_spec_boolean("auto-resize",
188 "Auto-resize",
189 "Auto-resize",
190 TRUE,
191 G_PARAM_READABLE |
192 G_PARAM_WRITABLE));
193
194 g_object_class_install_property(object_class,
195 PROP_FORCE_ASPECT,
196 g_param_spec_boolean("force-aspect",
197 "Force aspect",
198 "Force aspect ratio for widget",
199 TRUE,
200 G_PARAM_READABLE |
201 G_PARAM_WRITABLE));
202
203 g_signal_new("display-pointer-grab",
204 G_OBJECT_CLASS_TYPE(object_class),
205 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
206 0,
207 NULL,
208 NULL,
209 g_cclosure_marshal_VOID__VOID,
210 G_TYPE_NONE,
211 0);
212
213 g_signal_new("display-pointer-ungrab",
214 G_OBJECT_CLASS_TYPE(object_class),
215 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
216 0,
217 NULL,
218 NULL,
219 g_cclosure_marshal_VOID__VOID,
220 G_TYPE_NONE,
221 0);
222
223 g_signal_new("display-keyboard-grab",
224 G_OBJECT_CLASS_TYPE(object_class),
225 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
226 0,
227 NULL,
228 NULL,
229 g_cclosure_marshal_VOID__VOID,
230 G_TYPE_NONE,
231 0);
232
233 g_signal_new("display-keyboard-ungrab",
234 G_OBJECT_CLASS_TYPE(object_class),
235 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
236 0,
237 NULL,
238 NULL,
239 g_cclosure_marshal_VOID__VOID,
240 G_TYPE_NONE,
241 0);
242
243 g_signal_new("display-desktop-resize",
244 G_OBJECT_CLASS_TYPE(object_class),
245 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
246 0,
247 NULL,
248 NULL,
249 g_cclosure_marshal_VOID__VOID,
250 G_TYPE_NONE,
251 0);
252
253 g_signal_new("monitor-geometry-changed",
254 G_OBJECT_CLASS_TYPE(object_class),
255 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
256 0,
257 NULL,
258 NULL,
259 g_cclosure_marshal_VOID__VOID,
260 G_TYPE_NONE,
261 0);
262 }
263
264 static void
virt_viewer_display_init(VirtViewerDisplay * display)265 virt_viewer_display_init(VirtViewerDisplay *display)
266 {
267 VirtViewerDisplayPrivate *priv = virt_viewer_display_get_instance_private(display);
268 gtk_widget_set_has_window(GTK_WIDGET(display), FALSE);
269 gtk_widget_set_redraw_on_allocate(GTK_WIDGET(display), FALSE);
270
271 priv->desktopWidth = MIN_DISPLAY_WIDTH;
272 priv->desktopHeight = MIN_DISPLAY_HEIGHT;
273 priv->zoom_level = NORMAL_ZOOM_LEVEL;
274 priv->force_aspect = TRUE;
275 }
276
277 GtkWidget*
virt_viewer_display_new(void)278 virt_viewer_display_new(void)
279 {
280 return g_object_new(VIRT_VIEWER_TYPE_DISPLAY, NULL);
281 }
282
283 static void
virt_viewer_display_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)284 virt_viewer_display_set_property(GObject *object,
285 guint prop_id,
286 const GValue *value,
287 GParamSpec *pspec)
288 {
289 VirtViewerDisplay *display = VIRT_VIEWER_DISPLAY(object);
290 VirtViewerDisplayPrivate *priv = virt_viewer_display_get_instance_private(display);
291
292 switch (prop_id) {
293 case PROP_DESKTOP_WIDTH:
294 priv->desktopWidth = g_value_get_int(value);
295 break;
296 case PROP_DESKTOP_HEIGHT:
297 priv->desktopHeight = g_value_get_int(value);
298 break;
299 case PROP_NTH_DISPLAY:
300 priv->nth_display = g_value_get_int(value);
301 break;
302 case PROP_SESSION:
303 g_warn_if_fail(priv->session == NULL);
304 priv->session = g_value_get_object(value);
305 break;
306 case PROP_MONITOR:
307 priv->monitor = g_value_get_int(value);
308 break;
309 case PROP_AUTO_RESIZE:
310 priv->auto_resize = g_value_get_boolean(value);
311 break;
312 case PROP_FORCE_ASPECT:
313 priv->force_aspect = g_value_get_boolean(value);
314 break;
315
316 default:
317 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
318 break;
319 }
320 }
321
322 static void
virt_viewer_display_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)323 virt_viewer_display_get_property(GObject *object,
324 guint prop_id,
325 GValue *value,
326 GParamSpec *pspec)
327 {
328 VirtViewerDisplay *display = VIRT_VIEWER_DISPLAY(object);
329 VirtViewerDisplayPrivate *priv = virt_viewer_display_get_instance_private(display);
330
331 switch (prop_id) {
332 case PROP_DESKTOP_WIDTH:
333 g_value_set_int(value, priv->desktopWidth);
334 break;
335 case PROP_DESKTOP_HEIGHT:
336 g_value_set_int(value, priv->desktopHeight);
337 break;
338 case PROP_NTH_DISPLAY:
339 g_value_set_int(value, priv->nth_display);
340 break;
341 case PROP_SHOW_HINT:
342 g_value_set_flags(value, priv->show_hint);
343 break;
344 case PROP_SESSION:
345 g_value_set_object(value, virt_viewer_display_get_session(display));
346 break;
347 case PROP_SELECTABLE:
348 g_value_set_boolean(value, virt_viewer_display_get_selectable(display));
349 break;
350 case PROP_MONITOR:
351 g_value_set_int(value, priv->monitor);
352 break;
353 case PROP_FULLSCREEN:
354 g_value_set_boolean(value, virt_viewer_display_get_fullscreen(display));
355 break;
356 case PROP_AUTO_RESIZE:
357 g_value_set_boolean(value, virt_viewer_display_get_auto_resize(display));
358 break;
359 case PROP_FORCE_ASPECT:
360 g_value_set_boolean(value, priv->force_aspect);
361 break;
362
363 default:
364 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
365 break;
366 }
367 }
368
369
370 static void
virt_viewer_display_grab_focus(GtkWidget * widget)371 virt_viewer_display_grab_focus(GtkWidget *widget)
372 {
373 GtkBin *bin = GTK_BIN(widget);
374
375 gtk_widget_grab_focus(gtk_bin_get_child(bin));
376 }
377
virt_viewer_display_get_preferred_dimension_from_desktop(VirtViewerDisplay * display,const int minimal_size,const int desktop_dim,int * minimal_dim,int * preferred_dim)378 static void virt_viewer_display_get_preferred_dimension_from_desktop(VirtViewerDisplay *display,
379 const int minimal_size,
380 const int desktop_dim,
381 int *minimal_dim,
382 int *preferred_dim)
383 {
384 int border_width = gtk_container_get_border_width(GTK_CONTAINER(display));
385
386 if (virt_viewer_display_get_zoom(display)) {
387 guint zoom_level = virt_viewer_display_get_zoom_level(display);
388 *preferred_dim = round(desktop_dim * zoom_level / (double) NORMAL_ZOOM_LEVEL);
389 *minimal_dim = round(minimal_size * zoom_level / (double) NORMAL_ZOOM_LEVEL);
390 } else {
391 *preferred_dim = desktop_dim;
392 *minimal_dim = minimal_size;
393 }
394 *preferred_dim += 2 * border_width;
395 *minimal_dim += 2 * border_width;
396 }
397
398
virt_viewer_display_get_preferred_width(GtkWidget * widget,int * minwidth,int * defwidth)399 static void virt_viewer_display_get_preferred_width(GtkWidget *widget,
400 int *minwidth,
401 int *defwidth)
402 {
403 VirtViewerDisplay *display = VIRT_VIEWER_DISPLAY(widget);
404 VirtViewerDisplayPrivate *priv = virt_viewer_display_get_instance_private(display);
405
406 virt_viewer_display_get_preferred_dimension_from_desktop(display,
407 MIN_DISPLAY_WIDTH,
408 priv->desktopWidth,
409 minwidth,
410 defwidth);
411 }
412
413
virt_viewer_display_get_preferred_height(GtkWidget * widget,int * minheight,int * defheight)414 static void virt_viewer_display_get_preferred_height(GtkWidget *widget,
415 int *minheight,
416 int *defheight)
417 {
418 VirtViewerDisplay *display = VIRT_VIEWER_DISPLAY(widget);
419 VirtViewerDisplayPrivate *priv = virt_viewer_display_get_instance_private(display);
420
421 virt_viewer_display_get_preferred_dimension_from_desktop(display,
422 MIN_DISPLAY_HEIGHT,
423 priv->desktopHeight,
424 minheight,
425 defheight);
426 }
427
428
429 static void
virt_viewer_display_size_allocate(GtkWidget * widget,GtkAllocation * allocation)430 virt_viewer_display_size_allocate(GtkWidget *widget,
431 GtkAllocation *allocation)
432 {
433 GtkBin *bin = GTK_BIN(widget);
434 VirtViewerDisplay *display = VIRT_VIEWER_DISPLAY(widget);
435 VirtViewerDisplayPrivate *priv = virt_viewer_display_get_instance_private(display);
436 GtkAllocation child_allocation;
437 gint width, height;
438 gint border_width;
439 GtkWidget *child = gtk_bin_get_child(bin);
440
441 g_debug("Allocated %dx%d", allocation->width, allocation->height);
442 gtk_widget_set_allocation(widget, allocation);
443
444 if (priv->desktopWidth == 0 || priv->desktopHeight == 0 ||
445 child == NULL || !gtk_widget_get_visible(child))
446 return;
447
448 border_width = gtk_container_get_border_width(GTK_CONTAINER(display));
449
450 width = MAX(MIN_DISPLAY_WIDTH, allocation->width - 2 * border_width);
451 height = MAX(MIN_DISPLAY_HEIGHT, allocation->height - 2 * border_width);
452
453 if (priv->force_aspect) {
454 double desktopAspect = (double) priv->desktopWidth / (double) priv->desktopHeight;
455 double actualAspect = (double) width / (double) height;
456
457 if (actualAspect > desktopAspect) {
458 child_allocation.width = round(height * desktopAspect);
459 child_allocation.height = height;
460 } else {
461 child_allocation.width = width;
462 child_allocation.height = round(width / desktopAspect);
463 }
464 } else {
465 child_allocation.width = width;
466 child_allocation.height = height;
467 }
468
469 child_allocation.x = 0.5 * (width - child_allocation.width) + allocation->x + border_width;
470 child_allocation.y = 0.5 * (height - child_allocation.height) + allocation->y + border_width;
471
472 g_debug("Child allocate %dx%d", child_allocation.width, child_allocation.height);
473 gtk_widget_size_allocate(child, &child_allocation);
474 }
475
476
virt_viewer_display_set_desktop_size(VirtViewerDisplay * display,guint width,guint height)477 void virt_viewer_display_set_desktop_size(VirtViewerDisplay *display,
478 guint width,
479 guint height)
480 {
481 VirtViewerDisplayPrivate *priv = virt_viewer_display_get_instance_private(display);
482
483 if (width == priv->desktopWidth && height == priv->desktopHeight)
484 return;
485
486 priv->desktopWidth = width;
487 priv->desktopHeight = height;
488
489 virt_viewer_display_queue_resize(display);
490
491 g_signal_emit_by_name(display, "display-desktop-resize");
492 }
493
494
virt_viewer_display_get_desktop_size(VirtViewerDisplay * display,guint * width,guint * height)495 void virt_viewer_display_get_desktop_size(VirtViewerDisplay *display,
496 guint *width,
497 guint *height)
498 {
499 VirtViewerDisplayPrivate *priv = virt_viewer_display_get_instance_private(display);
500
501 *width = priv->desktopWidth;
502 *height = priv->desktopHeight;
503 }
504
505
virt_viewer_display_queue_resize(VirtViewerDisplay * display)506 void virt_viewer_display_queue_resize(VirtViewerDisplay *display)
507 {
508 GtkWidget *child = gtk_bin_get_child(GTK_BIN(display));
509
510 if (child && gtk_widget_get_visible(child)) {
511 gtk_widget_queue_resize(GTK_WIDGET(display));
512 }
513 }
514
virt_viewer_display_set_zoom_level(VirtViewerDisplay * display,guint zoom)515 void virt_viewer_display_set_zoom_level(VirtViewerDisplay *display,
516 guint zoom)
517 {
518 VirtViewerDisplayPrivate *priv = virt_viewer_display_get_instance_private(display);
519
520 if (zoom < MIN_ZOOM_LEVEL)
521 zoom = MIN_ZOOM_LEVEL;
522 if (zoom > MAX_ZOOM_LEVEL)
523 zoom = MAX_ZOOM_LEVEL;
524
525 if (priv->zoom_level == zoom)
526 return;
527
528 priv->zoom_level = zoom;
529
530 virt_viewer_display_queue_resize(display);
531 g_object_notify(G_OBJECT(display), "zoom-level");
532 }
533
534
virt_viewer_display_get_zoom_level(VirtViewerDisplay * display)535 guint virt_viewer_display_get_zoom_level(VirtViewerDisplay *display)
536 {
537 VirtViewerDisplayPrivate *priv = virt_viewer_display_get_instance_private(display);
538 return priv->zoom_level;
539 }
540
virt_viewer_display_get_zoom(VirtViewerDisplay * display)541 gboolean virt_viewer_display_get_zoom(VirtViewerDisplay *display)
542 {
543 return virt_viewer_display_get_zoom_level(display) != NORMAL_ZOOM_LEVEL;
544 }
545
546
virt_viewer_display_send_keys(VirtViewerDisplay * display,const guint * keyvals,int nkeyvals)547 void virt_viewer_display_send_keys(VirtViewerDisplay *display,
548 const guint *keyvals, int nkeyvals)
549 {
550 g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(display));
551
552 VIRT_VIEWER_DISPLAY_GET_CLASS(display)->send_keys(display, keyvals, nkeyvals);
553 }
554
virt_viewer_display_get_pixbuf(VirtViewerDisplay * display)555 GdkPixbuf* virt_viewer_display_get_pixbuf(VirtViewerDisplay *display)
556 {
557 g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(display), NULL);
558
559 return VIRT_VIEWER_DISPLAY_GET_CLASS(display)->get_pixbuf(display);
560 }
561
virt_viewer_display_get_show_hint(VirtViewerDisplay * self)562 guint virt_viewer_display_get_show_hint(VirtViewerDisplay *self)
563 {
564 VirtViewerDisplayPrivate *priv;
565 g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), 0);
566
567 priv = virt_viewer_display_get_instance_private(self);
568 return priv->show_hint;
569 }
570
virt_viewer_display_set_show_hint(VirtViewerDisplay * self,guint mask,gboolean enable)571 void virt_viewer_display_set_show_hint(VirtViewerDisplay *self, guint mask, gboolean enable)
572 {
573 VirtViewerDisplayPrivate *priv;
574 guint hint;
575 g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(self));
576
577 priv = virt_viewer_display_get_instance_private(self);
578 hint = priv->show_hint;
579
580 if (enable)
581 hint |= mask;
582 else
583 hint &= ~mask;
584
585 if (priv->show_hint == hint)
586 return;
587
588 priv->show_hint = hint;
589 g_object_notify(G_OBJECT(self), "show-hint");
590 }
591
592 /* This function attempts to enable the display if supported by the backend */
virt_viewer_display_enable(VirtViewerDisplay * self)593 void virt_viewer_display_enable(VirtViewerDisplay *self)
594 {
595 VirtViewerDisplayClass *klass;
596
597 g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(self));
598
599 klass = VIRT_VIEWER_DISPLAY_GET_CLASS(self);
600 if (!klass->enable)
601 return;
602
603 klass->enable(self);
604 }
605
606 /* This function attempts to disable the display if supported by the backend */
virt_viewer_display_disable(VirtViewerDisplay * self)607 void virt_viewer_display_disable(VirtViewerDisplay *self)
608 {
609 VirtViewerDisplayClass *klass;
610
611 g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(self));
612
613 klass = VIRT_VIEWER_DISPLAY_GET_CLASS(self);
614 if (!klass->disable)
615 return;
616
617 klass->disable(self);
618 }
619
620 /* this function simply informs the display that it is enabled. see
621 * virt_viewer_display_enable()/disable() if you want to attempt to change the
622 * state of the display */
virt_viewer_display_set_enabled(VirtViewerDisplay * self,gboolean enabled)623 void virt_viewer_display_set_enabled(VirtViewerDisplay *self, gboolean enabled)
624 {
625 g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(self));
626
627 g_object_freeze_notify(G_OBJECT(self));
628
629 virt_viewer_display_set_show_hint(self, VIRT_VIEWER_DISPLAY_SHOW_HINT_SET, TRUE);
630 virt_viewer_display_set_show_hint(self, VIRT_VIEWER_DISPLAY_SHOW_HINT_DISABLED, !enabled);
631
632 g_object_thaw_notify(G_OBJECT(self));
633 }
634
virt_viewer_display_get_enabled(VirtViewerDisplay * self)635 gboolean virt_viewer_display_get_enabled(VirtViewerDisplay *self)
636 {
637 VirtViewerDisplayPrivate *priv;
638 priv = virt_viewer_display_get_instance_private(self);
639 return ((priv->show_hint & VIRT_VIEWER_DISPLAY_SHOW_HINT_SET) &&
640 !(priv->show_hint & VIRT_VIEWER_DISPLAY_SHOW_HINT_DISABLED));
641 }
642
virt_viewer_display_get_session(VirtViewerDisplay * self)643 VirtViewerSession* virt_viewer_display_get_session(VirtViewerDisplay *self)
644 {
645 VirtViewerDisplayPrivate *priv;
646 g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), NULL);
647
648 priv = virt_viewer_display_get_instance_private(self);
649 return priv->session;
650 }
651
virt_viewer_display_set_monitor(VirtViewerDisplay * self,gint monitor)652 void virt_viewer_display_set_monitor(VirtViewerDisplay *self, gint monitor)
653 {
654 VirtViewerDisplayPrivate *priv;
655 g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(self));
656
657 priv = virt_viewer_display_get_instance_private(self);
658 priv->monitor = monitor;
659 g_object_notify(G_OBJECT(self), "monitor");
660 }
661
virt_viewer_display_get_monitor(VirtViewerDisplay * self)662 gint virt_viewer_display_get_monitor(VirtViewerDisplay *self)
663 {
664 VirtViewerDisplayPrivate *priv;
665 g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), -1);
666
667 priv = virt_viewer_display_get_instance_private(self);
668 return priv->monitor;
669 }
670
virt_viewer_display_release_cursor(VirtViewerDisplay * self)671 void virt_viewer_display_release_cursor(VirtViewerDisplay *self)
672 {
673 VirtViewerDisplayClass *klass;
674
675 g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(self));
676
677 klass = VIRT_VIEWER_DISPLAY_GET_CLASS(self);
678 g_return_if_fail(klass->release_cursor != NULL);
679
680 klass->release_cursor(self);
681 }
682
virt_viewer_display_get_selectable(VirtViewerDisplay * self)683 gboolean virt_viewer_display_get_selectable(VirtViewerDisplay *self)
684 {
685 VirtViewerDisplayClass *klass;
686
687 g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), FALSE);
688
689 klass = VIRT_VIEWER_DISPLAY_GET_CLASS(self);
690 if (klass->selectable)
691 return klass->selectable(self);
692
693 return TRUE;
694 }
695
virt_viewer_display_close(VirtViewerDisplay * self)696 void virt_viewer_display_close(VirtViewerDisplay *self)
697 {
698 VirtViewerDisplayClass *klass;
699
700 g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(self));
701
702 klass = VIRT_VIEWER_DISPLAY_GET_CLASS(self);
703 if (klass->close)
704 klass->close(self);
705 }
706
virt_viewer_display_set_fullscreen(VirtViewerDisplay * self,gboolean fullscreen)707 void virt_viewer_display_set_fullscreen(VirtViewerDisplay *self, gboolean fullscreen)
708 {
709 VirtViewerDisplayPrivate *priv;
710 g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(self));
711
712 priv = virt_viewer_display_get_instance_private(self);
713 if (priv->fullscreen == fullscreen)
714 return;
715
716 priv->fullscreen = fullscreen;
717 g_object_notify(G_OBJECT(self), "fullscreen");
718 }
719
virt_viewer_display_get_fullscreen(VirtViewerDisplay * self)720 gboolean virt_viewer_display_get_fullscreen(VirtViewerDisplay *self)
721 {
722 VirtViewerDisplayPrivate *priv;
723 g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), FALSE);
724
725 priv = virt_viewer_display_get_instance_private(self);
726 return priv->fullscreen;
727 }
728
virt_viewer_display_get_preferred_monitor_geometry(VirtViewerDisplay * self,GdkRectangle * preferred)729 void virt_viewer_display_get_preferred_monitor_geometry(VirtViewerDisplay* self,
730 GdkRectangle* preferred)
731 {
732 GtkWidget *top = NULL;
733 gint topx = 0, topy = 0;
734
735 g_return_if_fail(preferred != NULL);
736
737 top = gtk_widget_get_toplevel(GTK_WIDGET(self));
738 if (!virt_viewer_display_get_enabled(self) ||
739 !GTK_IS_WINDOW(top)) {
740 preferred->width = 0;
741 preferred->height = 0;
742 preferred->x = 0;
743 preferred->y = 0;
744 return;
745 }
746
747 gtk_window_get_position(GTK_WINDOW(top), &topx, &topy);
748 topx = MAX(topx, 0);
749 topy = MAX(topy, 0);
750
751 if (virt_viewer_display_get_fullscreen(self)) {
752 GdkRectangle physical_monitor;
753 GdkScreen *screen = gtk_widget_get_screen(GTK_WIDGET(self));
754 int n = virt_viewer_display_get_monitor(self);
755 if (n == -1)
756 n = gdk_screen_get_monitor_at_window(screen,
757 gtk_widget_get_window(GTK_WIDGET(self)));
758 gdk_screen_get_monitor_geometry(screen, n, &physical_monitor);
759 preferred->x = physical_monitor.x;
760 preferred->y = physical_monitor.y;
761 preferred->width = physical_monitor.width;
762 preferred->height = physical_monitor.height;
763 } else {
764 gtk_widget_get_allocation(GTK_WIDGET(self), preferred);
765 preferred->x = topx;
766 preferred->y = topy;
767 }
768
769 if (virt_viewer_display_get_zoom(self)) {
770 guint zoom = virt_viewer_display_get_zoom_level(self);
771
772 preferred->width = round(preferred->width * NORMAL_ZOOM_LEVEL / (double) zoom);
773 preferred->height = round(preferred->height * NORMAL_ZOOM_LEVEL / (double) zoom);
774 }
775
776 /* calculate device pixel size on HiDPI screens */
777 gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self));
778
779 preferred->x *= scale_factor;
780 preferred->y *= scale_factor;
781 preferred->width *= scale_factor;
782 preferred->height *= scale_factor;
783 }
784
785 gint
virt_viewer_display_get_nth(VirtViewerDisplay * self)786 virt_viewer_display_get_nth(VirtViewerDisplay *self)
787 {
788 VirtViewerDisplayPrivate *priv;
789 priv = virt_viewer_display_get_instance_private(self);
790 return priv->nth_display;
791 }
792
virt_viewer_display_set_auto_resize(VirtViewerDisplay * self,gboolean enabled)793 void virt_viewer_display_set_auto_resize(VirtViewerDisplay *self, gboolean enabled)
794 {
795 VirtViewerDisplayPrivate *priv;
796 g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(self));
797
798 priv = virt_viewer_display_get_instance_private(self);
799 priv->auto_resize = enabled;
800 g_object_notify(G_OBJECT(self), "auto-resize");
801 }
802
virt_viewer_display_get_auto_resize(VirtViewerDisplay * self)803 gboolean virt_viewer_display_get_auto_resize(VirtViewerDisplay *self)
804 {
805 VirtViewerDisplayPrivate *priv;
806 g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), FALSE);
807
808 priv = virt_viewer_display_get_instance_private(self);
809 return priv->auto_resize;
810 }
811