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