Revision c6158483
b/ui/gtk.c | ||
---|---|---|
80 | 80 |
|
81 | 81 |
GtkWidget *view_menu_item; |
82 | 82 |
GtkWidget *view_menu; |
83 |
GtkWidget *full_screen_item; |
|
84 |
GtkWidget *zoom_in_item; |
|
85 |
GtkWidget *zoom_out_item; |
|
86 |
GtkWidget *zoom_fixed_item; |
|
87 |
GtkWidget *zoom_fit_item; |
|
83 | 88 |
GtkWidget *grab_item; |
84 | 89 |
GtkWidget *grab_on_hover_item; |
85 | 90 |
GtkWidget *vga_item; |
... | ... | |
101 | 106 |
|
102 | 107 |
double scale_x; |
103 | 108 |
double scale_y; |
109 |
gboolean full_screen; |
|
104 | 110 |
|
105 | 111 |
GdkCursor *null_cursor; |
106 | 112 |
Notifier mouse_mode_notifier; |
113 |
gboolean free_scale; |
|
107 | 114 |
} GtkDisplayState; |
108 | 115 |
|
109 | 116 |
static GtkDisplayState *global_state; |
... | ... | |
135 | 142 |
on_vga = gd_on_vga(s); |
136 | 143 |
|
137 | 144 |
if ((override || on_vga) && |
138 |
(kbd_mouse_is_absolute() || gd_is_grab_active(s))) { |
|
145 |
(s->full_screen || kbd_mouse_is_absolute() || gd_is_grab_active(s))) {
|
|
139 | 146 |
gdk_window_set_cursor(window, s->null_cursor); |
140 | 147 |
} else { |
141 | 148 |
gdk_window_set_cursor(window, NULL); |
... | ... | |
173 | 180 |
{ |
174 | 181 |
GtkDisplayState *s = ds->opaque; |
175 | 182 |
int x1, x2, y1, y2; |
183 |
int mx, my; |
|
184 |
int fbw, fbh; |
|
185 |
int ww, wh; |
|
176 | 186 |
|
177 | 187 |
DPRINTF("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h); |
178 | 188 |
|
... | ... | |
182 | 192 |
x2 = ceil(x * s->scale_x + w * s->scale_x); |
183 | 193 |
y2 = ceil(y * s->scale_y + h * s->scale_y); |
184 | 194 |
|
185 |
gtk_widget_queue_draw_area(s->drawing_area, x1, y1, (x2 - x1), (y2 - y1)); |
|
195 |
fbw = ds_get_width(s->ds) * s->scale_x; |
|
196 |
fbh = ds_get_height(s->ds) * s->scale_y; |
|
197 |
|
|
198 |
gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh); |
|
199 |
|
|
200 |
mx = my = 0; |
|
201 |
if (ww > fbw) { |
|
202 |
mx = (ww - fbw) / 2; |
|
203 |
} |
|
204 |
if (wh > fbh) { |
|
205 |
my = (wh - fbh) / 2; |
|
206 |
} |
|
207 |
|
|
208 |
gtk_widget_queue_draw_area(s->drawing_area, mx + x1, my + y1, (x2 - x1), (y2 - y1)); |
|
186 | 209 |
} |
187 | 210 |
|
188 | 211 |
static void gd_refresh(DisplayState *ds) |
... | ... | |
227 | 250 |
ds_get_height(ds), |
228 | 251 |
ds_get_linesize(ds)); |
229 | 252 |
|
230 |
gtk_widget_set_size_request(s->drawing_area, |
|
231 |
ds_get_width(ds) * s->scale_x, |
|
232 |
ds_get_height(ds) * s->scale_y); |
|
253 |
if (!s->full_screen) { |
|
254 |
GtkRequisition req; |
|
255 |
double sx, sy; |
|
256 |
|
|
257 |
if (s->free_scale) { |
|
258 |
sx = s->scale_x; |
|
259 |
sy = s->scale_y; |
|
260 |
|
|
261 |
s->scale_y = 1.0; |
|
262 |
s->scale_x = 1.0; |
|
263 |
} else { |
|
264 |
sx = 1.0; |
|
265 |
sy = 1.0; |
|
266 |
} |
|
267 |
|
|
268 |
gtk_widget_set_size_request(s->drawing_area, |
|
269 |
ds_get_width(ds) * s->scale_x, |
|
270 |
ds_get_height(ds) * s->scale_y); |
|
271 |
gtk_widget_size_request(s->vbox, &req); |
|
272 |
|
|
273 |
gtk_window_resize(GTK_WINDOW(s->window), |
|
274 |
req.width * sx, req.height * sy); |
|
275 |
} |
|
233 | 276 |
} |
234 | 277 |
|
235 | 278 |
/** QEMU Events **/ |
... | ... | |
266 | 309 |
static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) |
267 | 310 |
{ |
268 | 311 |
GtkDisplayState *s = opaque; |
312 |
int mx, my; |
|
269 | 313 |
int ww, wh; |
270 | 314 |
int fbw, fbh; |
271 | 315 |
|
316 |
if (!gtk_widget_get_realized(widget)) { |
|
317 |
return FALSE; |
|
318 |
} |
|
319 |
|
|
272 | 320 |
fbw = ds_get_width(s->ds); |
273 | 321 |
fbh = ds_get_height(s->ds); |
274 | 322 |
|
275 | 323 |
gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh); |
276 | 324 |
|
277 |
cairo_rectangle(cr, 0, 0, ww, wh); |
|
278 |
|
|
279 |
if (ww != fbw || wh != fbh) { |
|
325 |
if (s->full_screen) { |
|
280 | 326 |
s->scale_x = (double)ww / fbw; |
281 | 327 |
s->scale_y = (double)wh / fbh; |
282 |
cairo_scale(cr, s->scale_x, s->scale_y); |
|
283 |
} else { |
|
284 |
s->scale_x = 1.0; |
|
285 |
s->scale_y = 1.0; |
|
328 |
} else if (s->free_scale) { |
|
329 |
double sx, sy; |
|
330 |
|
|
331 |
sx = (double)ww / fbw; |
|
332 |
sy = (double)wh / fbh; |
|
333 |
|
|
334 |
s->scale_x = s->scale_y = MIN(sx, sy); |
|
286 | 335 |
} |
287 | 336 |
|
288 | 337 |
fbw *= s->scale_x; |
289 | 338 |
fbh *= s->scale_y; |
290 | 339 |
|
291 |
cairo_set_source_surface(cr, s->surface, 0, 0); |
|
340 |
mx = my = 0; |
|
341 |
if (ww > fbw) { |
|
342 |
mx = (ww - fbw) / 2; |
|
343 |
} |
|
344 |
if (wh > fbh) { |
|
345 |
my = (wh - fbh) / 2; |
|
346 |
} |
|
347 |
|
|
348 |
cairo_rectangle(cr, 0, 0, ww, wh); |
|
349 |
|
|
350 |
/* Optionally cut out the inner area where the pixmap |
|
351 |
will be drawn. This avoids 'flashing' since we're |
|
352 |
not double-buffering. Note we're using the undocumented |
|
353 |
behaviour of drawing the rectangle from right to left |
|
354 |
to cut out the whole */ |
|
355 |
cairo_rectangle(cr, mx + fbw, my, |
|
356 |
-1 * fbw, fbh); |
|
357 |
cairo_fill(cr); |
|
358 |
|
|
359 |
cairo_scale(cr, s->scale_x, s->scale_y); |
|
360 |
cairo_set_source_surface(cr, s->surface, mx / s->scale_x, my / s->scale_y); |
|
292 | 361 |
cairo_paint(cr); |
293 | 362 |
|
294 | 363 |
return TRUE; |
... | ... | |
321 | 390 |
GtkDisplayState *s = opaque; |
322 | 391 |
int dx, dy; |
323 | 392 |
int x, y; |
393 |
int mx, my; |
|
394 |
int fbh, fbw; |
|
395 |
int ww, wh; |
|
396 |
|
|
397 |
fbw = ds_get_width(s->ds) * s->scale_x; |
|
398 |
fbh = ds_get_height(s->ds) * s->scale_y; |
|
324 | 399 |
|
325 |
x = motion->x / s->scale_x; |
|
326 |
y = motion->y / s->scale_y; |
|
400 |
gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh); |
|
401 |
|
|
402 |
mx = my = 0; |
|
403 |
if (ww > fbw) { |
|
404 |
mx = (ww - fbw) / 2; |
|
405 |
} |
|
406 |
if (wh > fbh) { |
|
407 |
my = (wh - fbh) / 2; |
|
408 |
} |
|
409 |
|
|
410 |
x = (motion->x - mx) / s->scale_x; |
|
411 |
y = (motion->y - my) / s->scale_y; |
|
412 |
|
|
413 |
if (x < 0 || y < 0 || |
|
414 |
x >= ds_get_width(s->ds) || |
|
415 |
y >= ds_get_height(s->ds)) { |
|
416 |
return TRUE; |
|
417 |
} |
|
327 | 418 |
|
328 | 419 |
if (kbd_mouse_is_absolute()) { |
329 | 420 |
dx = x * 0x7FFF / (ds_get_width(s->ds) - 1); |
... | ... | |
492 | 583 |
} |
493 | 584 |
} |
494 | 585 |
|
586 |
static void gd_menu_full_screen(GtkMenuItem *item, void *opaque) |
|
587 |
{ |
|
588 |
GtkDisplayState *s = opaque; |
|
589 |
|
|
590 |
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->full_screen_item))) { |
|
591 |
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE); |
|
592 |
gtk_widget_set_size_request(s->menu_bar, 0, 0); |
|
593 |
gtk_widget_set_size_request(s->drawing_area, -1, -1); |
|
594 |
gtk_window_fullscreen(GTK_WINDOW(s->window)); |
|
595 |
if (gd_on_vga(s)) { |
|
596 |
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), TRUE); |
|
597 |
} |
|
598 |
s->full_screen = TRUE; |
|
599 |
} else { |
|
600 |
gtk_window_unfullscreen(GTK_WINDOW(s->window)); |
|
601 |
gd_menu_show_tabs(GTK_MENU_ITEM(s->show_tabs_item), s); |
|
602 |
gtk_widget_set_size_request(s->menu_bar, -1, -1); |
|
603 |
gtk_widget_set_size_request(s->drawing_area, |
|
604 |
ds_get_width(s->ds), ds_get_height(s->ds)); |
|
605 |
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), FALSE); |
|
606 |
s->full_screen = FALSE; |
|
607 |
s->scale_x = 1.0; |
|
608 |
s->scale_y = 1.0; |
|
609 |
} |
|
610 |
|
|
611 |
gd_update_cursor(s, FALSE); |
|
612 |
} |
|
613 |
|
|
614 |
static void gd_menu_zoom_in(GtkMenuItem *item, void *opaque) |
|
615 |
{ |
|
616 |
GtkDisplayState *s = opaque; |
|
617 |
|
|
618 |
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item), |
|
619 |
FALSE); |
|
620 |
|
|
621 |
s->scale_x += .25; |
|
622 |
s->scale_y += .25; |
|
623 |
|
|
624 |
gd_resize(s->ds); |
|
625 |
} |
|
626 |
|
|
627 |
static void gd_menu_zoom_out(GtkMenuItem *item, void *opaque) |
|
628 |
{ |
|
629 |
GtkDisplayState *s = opaque; |
|
630 |
|
|
631 |
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item), |
|
632 |
FALSE); |
|
633 |
|
|
634 |
s->scale_x -= .25; |
|
635 |
s->scale_y -= .25; |
|
636 |
|
|
637 |
s->scale_x = MAX(s->scale_x, .25); |
|
638 |
s->scale_y = MAX(s->scale_y, .25); |
|
639 |
|
|
640 |
gd_resize(s->ds); |
|
641 |
} |
|
642 |
|
|
643 |
static void gd_menu_zoom_fixed(GtkMenuItem *item, void *opaque) |
|
644 |
{ |
|
645 |
GtkDisplayState *s = opaque; |
|
646 |
|
|
647 |
s->scale_x = 1.0; |
|
648 |
s->scale_y = 1.0; |
|
649 |
|
|
650 |
gd_resize(s->ds); |
|
651 |
} |
|
652 |
|
|
653 |
static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque) |
|
654 |
{ |
|
655 |
GtkDisplayState *s = opaque; |
|
656 |
int ww, wh; |
|
657 |
|
|
658 |
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item))) { |
|
659 |
s->free_scale = TRUE; |
|
660 |
} else { |
|
661 |
s->free_scale = FALSE; |
|
662 |
} |
|
663 |
|
|
664 |
gd_resize(s->ds); |
|
665 |
|
|
666 |
gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh); |
|
667 |
gtk_widget_queue_draw_area(s->drawing_area, 0, 0, ww, wh); |
|
668 |
} |
|
669 |
|
|
495 | 670 |
static void gd_grab_keyboard(GtkDisplayState *s) |
496 | 671 |
{ |
497 | 672 |
gdk_keyboard_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)), |
... | ... | |
551 | 726 |
if (!on_vga) { |
552 | 727 |
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), |
553 | 728 |
FALSE); |
729 |
} else if (s->full_screen) { |
|
730 |
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), |
|
731 |
TRUE); |
|
554 | 732 |
} |
555 | 733 |
|
556 | 734 |
if (arg2 == 0) { |
... | ... | |
739 | 917 |
|
740 | 918 |
g_signal_connect(s->quit_item, "activate", |
741 | 919 |
G_CALLBACK(gd_menu_quit), s); |
920 |
g_signal_connect(s->full_screen_item, "activate", |
|
921 |
G_CALLBACK(gd_menu_full_screen), s); |
|
922 |
g_signal_connect(s->zoom_in_item, "activate", |
|
923 |
G_CALLBACK(gd_menu_zoom_in), s); |
|
924 |
g_signal_connect(s->zoom_out_item, "activate", |
|
925 |
G_CALLBACK(gd_menu_zoom_out), s); |
|
926 |
g_signal_connect(s->zoom_fixed_item, "activate", |
|
927 |
G_CALLBACK(gd_menu_zoom_fixed), s); |
|
928 |
g_signal_connect(s->zoom_fit_item, "activate", |
|
929 |
G_CALLBACK(gd_menu_zoom_fit), s); |
|
742 | 930 |
g_signal_connect(s->vga_item, "activate", |
743 | 931 |
G_CALLBACK(gd_menu_switch_vc), s); |
744 | 932 |
g_signal_connect(s->grab_item, "activate", |
... | ... | |
774 | 962 |
gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group); |
775 | 963 |
s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View"); |
776 | 964 |
|
965 |
s->full_screen_item = gtk_check_menu_item_new_with_mnemonic("_Full Screen"); |
|
966 |
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item), |
|
967 |
"<QEMU>/View/Full Screen"); |
|
968 |
gtk_accel_map_add_entry("<QEMU>/View/Full Screen", GDK_KEY_f, GDK_CONTROL_MASK | GDK_MOD1_MASK); |
|
969 |
gtk_menu_append(GTK_MENU(s->view_menu), s->full_screen_item); |
|
970 |
|
|
971 |
separator = gtk_separator_menu_item_new(); |
|
972 |
gtk_menu_append(GTK_MENU(s->view_menu), separator); |
|
973 |
|
|
974 |
s->zoom_in_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_IN, NULL); |
|
975 |
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_in_item), |
|
976 |
"<QEMU>/View/Zoom In"); |
|
977 |
gtk_accel_map_add_entry("<QEMU>/View/Zoom In", GDK_KEY_plus, GDK_CONTROL_MASK | GDK_MOD1_MASK); |
|
978 |
gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_in_item); |
|
979 |
|
|
980 |
s->zoom_out_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_OUT, NULL); |
|
981 |
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_out_item), |
|
982 |
"<QEMU>/View/Zoom Out"); |
|
983 |
gtk_accel_map_add_entry("<QEMU>/View/Zoom Out", GDK_KEY_minus, GDK_CONTROL_MASK | GDK_MOD1_MASK); |
|
984 |
gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_out_item); |
|
985 |
|
|
986 |
s->zoom_fixed_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_100, NULL); |
|
987 |
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_fixed_item), |
|
988 |
"<QEMU>/View/Zoom Fixed"); |
|
989 |
gtk_accel_map_add_entry("<QEMU>/View/Zoom Fixed", GDK_KEY_0, GDK_CONTROL_MASK | GDK_MOD1_MASK); |
|
990 |
gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fixed_item); |
|
991 |
|
|
992 |
s->zoom_fit_item = gtk_check_menu_item_new_with_mnemonic("Zoom To _Fit"); |
|
993 |
gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fit_item); |
|
994 |
|
|
995 |
separator = gtk_separator_menu_item_new(); |
|
996 |
gtk_menu_append(GTK_MENU(s->view_menu), separator); |
|
997 |
|
|
777 | 998 |
s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic("Grab On _Hover"); |
778 | 999 |
gtk_menu_append(GTK_MENU(s->view_menu), s->grab_on_hover_item); |
779 | 1000 |
|
... | ... | |
837 | 1058 |
|
838 | 1059 |
s->scale_x = 1.0; |
839 | 1060 |
s->scale_y = 1.0; |
1061 |
s->free_scale = FALSE; |
|
840 | 1062 |
|
841 | 1063 |
s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR); |
842 | 1064 |
|
... | ... | |
865 | 1087 |
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE); |
866 | 1088 |
gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE); |
867 | 1089 |
|
868 |
gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE); |
|
869 |
|
|
870 | 1090 |
gd_update_caption(s); |
871 | 1091 |
|
872 | 1092 |
gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0); |
Also available in: Unified diff