4 * Copyright IBM, Corp. 2012
7 * Anthony Liguori <aliguori@us.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
12 * Portions from gtk-vnc:
16 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
17 * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com>
19 * This library is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU Lesser General Public
21 * License as published by the Free Software Foundation; either
22 * version 2.0 of the License, or (at your option) any later version.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
35 #include <gdk/gdkkeysyms.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
44 #include "qemu-common.h"
45 #include "ui/console.h"
46 #include "sysemu/sysemu.h"
47 #include "qmp-commands.h"
50 #include "char/char.h"
55 #define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
57 #define DPRINTF(fmt, ...) do { } while (0)
62 typedef struct VirtualConsole
66 GtkWidget
*scrolled_window
;
71 typedef struct GtkDisplayState
77 GtkWidget
*file_menu_item
;
81 GtkWidget
*view_menu_item
;
84 GtkWidget
*grab_on_hover_item
;
88 VirtualConsole vc
[MAX_VCS
];
90 GtkWidget
*show_tabs_item
;
94 GtkWidget
*drawing_area
;
95 cairo_surface_t
*surface
;
96 DisplayChangeListener dcl
;
105 GdkCursor
*null_cursor
;
106 Notifier mouse_mode_notifier
;
109 static GtkDisplayState
*global_state
;
111 /** Utility Functions **/
113 static bool gd_is_grab_active(GtkDisplayState
*s
)
115 return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s
->grab_item
));
118 static bool gd_grab_on_hover(GtkDisplayState
*s
)
120 return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s
->grab_on_hover_item
));
123 static bool gd_on_vga(GtkDisplayState
*s
)
125 return gtk_notebook_get_current_page(GTK_NOTEBOOK(s
->notebook
)) == 0;
128 static void gd_update_cursor(GtkDisplayState
*s
, gboolean override
)
133 window
= gtk_widget_get_window(GTK_WIDGET(s
->drawing_area
));
135 on_vga
= gd_on_vga(s
);
137 if ((override
|| on_vga
) &&
138 (kbd_mouse_is_absolute() || gd_is_grab_active(s
))) {
139 gdk_window_set_cursor(window
, s
->null_cursor
);
141 gdk_window_set_cursor(window
, NULL
);
145 static void gd_update_caption(GtkDisplayState
*s
)
147 const char *status
= "";
149 const char *grab
= "";
151 if (gd_is_grab_active(s
)) {
152 grab
= " - Press Ctrl+Alt+G to release grab";
155 if (!runstate_is_running()) {
156 status
= " [Stopped]";
160 title
= g_strdup_printf("QEMU (%s)%s%s", qemu_name
, status
, grab
);
162 title
= g_strdup_printf("QEMU%s%s", status
, grab
);
165 gtk_window_set_title(GTK_WINDOW(s
->window
), title
);
170 /** DisplayState Callbacks **/
172 static void gd_update(DisplayState
*ds
, int x
, int y
, int w
, int h
)
174 GtkDisplayState
*s
= ds
->opaque
;
177 DPRINTF("update(x=%d, y=%d, w=%d, h=%d)\n", x
, y
, w
, h
);
179 x1
= floor(x
* s
->scale_x
);
180 y1
= floor(y
* s
->scale_y
);
182 x2
= ceil(x
* s
->scale_x
+ w
* s
->scale_x
);
183 y2
= ceil(y
* s
->scale_y
+ h
* s
->scale_y
);
185 gtk_widget_queue_draw_area(s
->drawing_area
, x1
, y1
, (x2
- x1
), (y2
- y1
));
188 static void gd_refresh(DisplayState
*ds
)
193 static void gd_resize(DisplayState
*ds
)
195 GtkDisplayState
*s
= ds
->opaque
;
199 DPRINTF("resize(width=%d, height=%d)\n",
200 ds_get_width(ds
), ds_get_height(ds
));
203 cairo_surface_destroy(s
->surface
);
206 switch (ds
->surface
->pf
.bits_per_pixel
) {
208 kind
= CAIRO_FORMAT_A8
;
211 kind
= CAIRO_FORMAT_RGB16_565
;
214 kind
= CAIRO_FORMAT_RGB24
;
217 g_assert_not_reached();
221 stride
= cairo_format_stride_for_width(kind
, ds_get_width(ds
));
222 g_assert(ds_get_linesize(ds
) == stride
);
224 s
->surface
= cairo_image_surface_create_for_data(ds_get_data(ds
),
228 ds_get_linesize(ds
));
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
);
237 static void gd_change_runstate(void *opaque
, int running
, RunState state
)
239 GtkDisplayState
*s
= opaque
;
241 gd_update_caption(s
);
244 static void gd_mouse_mode_change(Notifier
*notify
, void *data
)
246 gd_update_cursor(container_of(notify
, GtkDisplayState
, mouse_mode_notifier
),
252 static gboolean
gd_window_close(GtkWidget
*widget
, GdkEvent
*event
,
255 GtkDisplayState
*s
= opaque
;
258 unregister_displaychangelistener(s
->ds
, &s
->dcl
);
266 static gboolean
gd_draw_event(GtkWidget
*widget
, cairo_t
*cr
, void *opaque
)
268 GtkDisplayState
*s
= opaque
;
272 fbw
= ds_get_width(s
->ds
);
273 fbh
= ds_get_height(s
->ds
);
275 gdk_drawable_get_size(gtk_widget_get_window(widget
), &ww
, &wh
);
277 cairo_rectangle(cr
, 0, 0, ww
, wh
);
279 if (ww
!= fbw
|| wh
!= fbh
) {
280 s
->scale_x
= (double)ww
/ fbw
;
281 s
->scale_y
= (double)wh
/ fbh
;
282 cairo_scale(cr
, s
->scale_x
, s
->scale_y
);
291 cairo_set_source_surface(cr
, s
->surface
, 0, 0);
297 static gboolean
gd_expose_event(GtkWidget
*widget
, GdkEventExpose
*expose
,
303 cr
= gdk_cairo_create(gtk_widget_get_window(widget
));
308 expose
->area
.height
);
311 ret
= gd_draw_event(widget
, cr
, opaque
);
318 static gboolean
gd_motion_event(GtkWidget
*widget
, GdkEventMotion
*motion
,
321 GtkDisplayState
*s
= opaque
;
325 x
= motion
->x
/ s
->scale_x
;
326 y
= motion
->y
/ s
->scale_y
;
328 if (kbd_mouse_is_absolute()) {
329 dx
= x
* 0x7FFF / (ds_get_width(s
->ds
) - 1);
330 dy
= y
* 0x7FFF / (ds_get_height(s
->ds
) - 1);
331 } else if (s
->last_x
== -1 || s
->last_y
== -1) {
342 if (kbd_mouse_is_absolute() || gd_is_grab_active(s
)) {
343 kbd_mouse_event(dx
, dy
, 0, s
->button_mask
);
346 if (!kbd_mouse_is_absolute() && gd_is_grab_active(s
)) {
347 GdkDrawable
*drawable
= GDK_DRAWABLE(gtk_widget_get_window(s
->drawing_area
));
348 GdkDisplay
*display
= gdk_drawable_get_display(drawable
);
349 GdkScreen
*screen
= gdk_drawable_get_screen(drawable
);
350 int x
= (int)motion
->x_root
;
351 int y
= (int)motion
->y_root
;
353 /* In relative mode check to see if client pointer hit
354 * one of the screen edges, and if so move it back by
355 * 200 pixels. This is important because the pointer
356 * in the server doesn't correspond 1-for-1, and so
357 * may still be only half way across the screen. Without
358 * this warp, the server pointer would thus appear to hit
359 * an invisible wall */
366 if (x
== (gdk_screen_get_width(screen
) - 1)) {
369 if (y
== (gdk_screen_get_height(screen
) - 1)) {
373 if (x
!= (int)motion
->x_root
|| y
!= (int)motion
->y_root
) {
374 gdk_display_warp_pointer(display
, screen
, x
, y
);
383 static gboolean
gd_button_event(GtkWidget
*widget
, GdkEventButton
*button
,
386 GtkDisplayState
*s
= opaque
;
390 if (button
->button
== 1) {
392 } else if (button
->button
== 2) {
394 } else if (button
->button
== 3) {
400 if (button
->type
== GDK_BUTTON_PRESS
) {
402 } else if (button
->type
== GDK_BUTTON_RELEASE
) {
403 s
->button_mask
&= ~n
;
406 if (kbd_mouse_is_absolute()) {
407 dx
= s
->last_x
* 0x7FFF / (ds_get_width(s
->ds
) - 1);
408 dy
= s
->last_y
* 0x7FFF / (ds_get_height(s
->ds
) - 1);
414 kbd_mouse_event(dx
, dy
, 0, s
->button_mask
);
419 static gboolean
gd_key_event(GtkWidget
*widget
, GdkEventKey
*key
, void *opaque
)
424 gdk_keycode
= key
->hardware_keycode
;
426 if (gdk_keycode
< 9) {
428 } else if (gdk_keycode
< 97) {
429 qemu_keycode
= gdk_keycode
- 8;
430 } else if (gdk_keycode
< 158) {
431 qemu_keycode
= translate_evdev_keycode(gdk_keycode
- 97);
432 } else if (gdk_keycode
== 208) { /* Hiragana_Katakana */
434 } else if (gdk_keycode
== 211) { /* backslash */
440 DPRINTF("translated GDK keycode %d to QEMU keycode %d (%s)\n",
441 gdk_keycode
, qemu_keycode
,
442 (key
->type
== GDK_KEY_PRESS
) ? "down" : "up");
444 if (qemu_keycode
& SCANCODE_GREY
) {
445 kbd_put_keycode(SCANCODE_EMUL0
);
448 if (key
->type
== GDK_KEY_PRESS
) {
449 kbd_put_keycode(qemu_keycode
& SCANCODE_KEYCODEMASK
);
450 } else if (key
->type
== GDK_KEY_RELEASE
) {
451 kbd_put_keycode(qemu_keycode
| SCANCODE_UP
);
453 g_assert_not_reached();
459 /** Window Menu Actions **/
461 static void gd_menu_quit(GtkMenuItem
*item
, void *opaque
)
466 static void gd_menu_switch_vc(GtkMenuItem
*item
, void *opaque
)
468 GtkDisplayState
*s
= opaque
;
470 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s
->vga_item
))) {
471 gtk_notebook_set_current_page(GTK_NOTEBOOK(s
->notebook
), 0);
475 for (i
= 0; i
< s
->nb_vcs
; i
++) {
476 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s
->vc
[i
].menu_item
))) {
477 gtk_notebook_set_current_page(GTK_NOTEBOOK(s
->notebook
), i
+ 1);
484 static void gd_menu_show_tabs(GtkMenuItem
*item
, void *opaque
)
486 GtkDisplayState
*s
= opaque
;
488 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s
->show_tabs_item
))) {
489 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s
->notebook
), TRUE
);
491 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s
->notebook
), FALSE
);
495 static void gd_grab_keyboard(GtkDisplayState
*s
)
497 gdk_keyboard_grab(gtk_widget_get_window(GTK_WIDGET(s
->drawing_area
)),
502 static void gd_ungrab_keyboard(GtkDisplayState
*s
)
504 gdk_keyboard_ungrab(GDK_CURRENT_TIME
);
507 static void gd_menu_grab_input(GtkMenuItem
*item
, void *opaque
)
509 GtkDisplayState
*s
= opaque
;
511 if (gd_is_grab_active(s
)) {
513 gdk_pointer_grab(gtk_widget_get_window(GTK_WIDGET(s
->drawing_area
)),
514 FALSE
, /* All events to come to our window directly */
515 GDK_POINTER_MOTION_MASK
|
516 GDK_BUTTON_PRESS_MASK
|
517 GDK_BUTTON_RELEASE_MASK
|
518 GDK_BUTTON_MOTION_MASK
|
520 NULL
, /* Allow cursor to move over entire desktop */
524 gd_ungrab_keyboard(s
);
525 gdk_pointer_ungrab(GDK_CURRENT_TIME
);
528 gd_update_caption(s
);
529 gd_update_cursor(s
, FALSE
);
532 static void gd_change_page(GtkNotebook
*nb
, gpointer arg1
, guint arg2
,
535 GtkDisplayState
*s
= data
;
539 if (!gtk_widget_get_realized(s
->notebook
)) {
543 last_page
= gtk_notebook_get_current_page(nb
);
546 gtk_widget_set_size_request(s
->vc
[last_page
- 1].terminal
, -1, -1);
552 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s
->grab_item
),
557 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s
->vga_item
), TRUE
);
559 VirtualConsole
*vc
= &s
->vc
[arg2
- 1];
560 VteTerminal
*term
= VTE_TERMINAL(vc
->terminal
);
563 width
= 80 * vte_terminal_get_char_width(term
);
564 height
= 25 * vte_terminal_get_char_height(term
);
566 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc
->menu_item
), TRUE
);
567 gtk_widget_set_size_request(vc
->terminal
, width
, height
);
570 gtk_widget_set_sensitive(s
->grab_item
, on_vga
);
572 gd_update_cursor(s
, TRUE
);
575 static gboolean
gd_enter_event(GtkWidget
*widget
, GdkEventCrossing
*crossing
, gpointer data
)
577 GtkDisplayState
*s
= data
;
579 if (!gd_is_grab_active(s
) && gd_grab_on_hover(s
)) {
586 static gboolean
gd_leave_event(GtkWidget
*widget
, GdkEventCrossing
*crossing
, gpointer data
)
588 GtkDisplayState
*s
= data
;
590 if (!gd_is_grab_active(s
) && gd_grab_on_hover(s
)) {
591 gd_ungrab_keyboard(s
);
597 /** Virtual Console Callbacks **/
599 static int gd_vc_chr_write(CharDriverState
*chr
, const uint8_t *buf
, int len
)
601 VirtualConsole
*vc
= chr
->opaque
;
603 return write(vc
->fd
, buf
, len
);
607 static CharDriverState
*vcs
[MAX_VCS
];
609 static CharDriverState
*gd_vc_handler(QemuOpts
*opts
)
611 CharDriverState
*chr
;
613 chr
= g_malloc0(sizeof(*chr
));
614 chr
->chr_write
= gd_vc_chr_write
;
621 void early_gtk_display_init(void)
623 register_vc_handler(gd_vc_handler
);
626 static gboolean
gd_vc_in(GIOChannel
*chan
, GIOCondition cond
, void *opaque
)
628 VirtualConsole
*vc
= opaque
;
629 uint8_t buffer
[1024];
632 len
= read(vc
->fd
, buffer
, sizeof(buffer
));
637 qemu_chr_be_write(vc
->chr
, buffer
, len
);
642 static GSList
*gd_vc_init(GtkDisplayState
*s
, VirtualConsole
*vc
, int index
, GSList
*group
)
649 GtkWidget
*scrolled_window
;
650 GtkAdjustment
*vadjustment
;
651 int master_fd
, slave_fd
, ret
;
654 snprintf(buffer
, sizeof(buffer
), "vc%d", index
);
655 snprintf(path
, sizeof(path
), "<QEMU>/View/VC%d", index
);
657 vc
->chr
= vcs
[index
];
659 if (vc
->chr
->label
) {
660 label
= vc
->chr
->label
;
665 vc
->menu_item
= gtk_radio_menu_item_new_with_mnemonic(group
, label
);
666 group
= gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc
->menu_item
));
667 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(vc
->menu_item
), path
);
668 gtk_accel_map_add_entry(path
, GDK_KEY_2
+ index
, GDK_CONTROL_MASK
| GDK_MOD1_MASK
);
670 vc
->terminal
= vte_terminal_new();
672 ret
= openpty(&master_fd
, &slave_fd
, NULL
, NULL
, NULL
);
675 /* Set raw attributes on the pty. */
676 tcgetattr(slave_fd
, &tty
);
678 tcsetattr(slave_fd
, TCSAFLUSH
, &tty
);
680 pty
= vte_pty_new_foreign(master_fd
, NULL
);
682 vte_terminal_set_pty_object(VTE_TERMINAL(vc
->terminal
), pty
);
684 vte_terminal_set_scrollback_lines(VTE_TERMINAL(vc
->terminal
), -1);
686 vadjustment
= vte_terminal_get_adjustment(VTE_TERMINAL(vc
->terminal
));
688 scrolled_window
= gtk_scrolled_window_new(NULL
, vadjustment
);
689 gtk_container_add(GTK_CONTAINER(scrolled_window
), vc
->terminal
);
691 vte_terminal_set_size(VTE_TERMINAL(vc
->terminal
), 80, 25);
694 vc
->chr
->opaque
= vc
;
695 vc
->scrolled_window
= scrolled_window
;
697 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vc
->scrolled_window
),
698 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
700 gtk_notebook_append_page(GTK_NOTEBOOK(s
->notebook
), scrolled_window
, gtk_label_new(label
));
701 g_signal_connect(vc
->menu_item
, "activate",
702 G_CALLBACK(gd_menu_switch_vc
), s
);
704 gtk_menu_append(GTK_MENU(s
->view_menu
), vc
->menu_item
);
706 qemu_chr_generic_open(vc
->chr
);
708 vc
->chr
->init(vc
->chr
);
711 chan
= g_io_channel_unix_new(vc
->fd
);
712 g_io_add_watch(chan
, G_IO_IN
, gd_vc_in
, vc
);
717 /** Window Creation **/
719 static void gd_connect_signals(GtkDisplayState
*s
)
721 g_signal_connect(s
->show_tabs_item
, "activate",
722 G_CALLBACK(gd_menu_show_tabs
), s
);
724 g_signal_connect(s
->window
, "delete-event",
725 G_CALLBACK(gd_window_close
), s
);
727 g_signal_connect(s
->drawing_area
, "expose-event",
728 G_CALLBACK(gd_expose_event
), s
);
729 g_signal_connect(s
->drawing_area
, "motion-notify-event",
730 G_CALLBACK(gd_motion_event
), s
);
731 g_signal_connect(s
->drawing_area
, "button-press-event",
732 G_CALLBACK(gd_button_event
), s
);
733 g_signal_connect(s
->drawing_area
, "button-release-event",
734 G_CALLBACK(gd_button_event
), s
);
735 g_signal_connect(s
->drawing_area
, "key-press-event",
736 G_CALLBACK(gd_key_event
), s
);
737 g_signal_connect(s
->drawing_area
, "key-release-event",
738 G_CALLBACK(gd_key_event
), s
);
740 g_signal_connect(s
->quit_item
, "activate",
741 G_CALLBACK(gd_menu_quit
), s
);
742 g_signal_connect(s
->vga_item
, "activate",
743 G_CALLBACK(gd_menu_switch_vc
), s
);
744 g_signal_connect(s
->grab_item
, "activate",
745 G_CALLBACK(gd_menu_grab_input
), s
);
746 g_signal_connect(s
->notebook
, "switch-page",
747 G_CALLBACK(gd_change_page
), s
);
748 g_signal_connect(s
->drawing_area
, "enter-notify-event",
749 G_CALLBACK(gd_enter_event
), s
);
750 g_signal_connect(s
->drawing_area
, "leave-notify-event",
751 G_CALLBACK(gd_leave_event
), s
);
754 static void gd_create_menus(GtkDisplayState
*s
)
757 GtkAccelGroup
*accel_group
;
758 GSList
*group
= NULL
;
759 GtkWidget
*separator
;
762 accel_group
= gtk_accel_group_new();
763 s
->file_menu
= gtk_menu_new();
764 gtk_menu_set_accel_group(GTK_MENU(s
->file_menu
), accel_group
);
765 s
->file_menu_item
= gtk_menu_item_new_with_mnemonic("_File");
767 s
->quit_item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT
, NULL
);
768 gtk_stock_lookup(GTK_STOCK_QUIT
, &item
);
769 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s
->quit_item
),
771 gtk_accel_map_add_entry("<QEMU>/File/Quit", item
.keyval
, item
.modifier
);
773 s
->view_menu
= gtk_menu_new();
774 gtk_menu_set_accel_group(GTK_MENU(s
->view_menu
), accel_group
);
775 s
->view_menu_item
= gtk_menu_item_new_with_mnemonic("_View");
777 s
->grab_on_hover_item
= gtk_check_menu_item_new_with_mnemonic("Grab On _Hover");
778 gtk_menu_append(GTK_MENU(s
->view_menu
), s
->grab_on_hover_item
);
780 s
->grab_item
= gtk_check_menu_item_new_with_mnemonic("_Grab Input");
781 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s
->grab_item
),
782 "<QEMU>/View/Grab Input");
783 gtk_accel_map_add_entry("<QEMU>/View/Grab Input", GDK_KEY_g
, GDK_CONTROL_MASK
| GDK_MOD1_MASK
);
784 gtk_menu_append(GTK_MENU(s
->view_menu
), s
->grab_item
);
786 separator
= gtk_separator_menu_item_new();
787 gtk_menu_append(GTK_MENU(s
->view_menu
), separator
);
789 s
->vga_item
= gtk_radio_menu_item_new_with_mnemonic(group
, "_VGA");
790 group
= gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s
->vga_item
));
791 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s
->vga_item
),
793 gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1
, GDK_CONTROL_MASK
| GDK_MOD1_MASK
);
794 gtk_menu_append(GTK_MENU(s
->view_menu
), s
->vga_item
);
796 for (i
= 0; i
< nb_vcs
; i
++) {
797 VirtualConsole
*vc
= &s
->vc
[i
];
799 group
= gd_vc_init(s
, vc
, i
, group
);
803 separator
= gtk_separator_menu_item_new();
804 gtk_menu_append(GTK_MENU(s
->view_menu
), separator
);
806 s
->show_tabs_item
= gtk_check_menu_item_new_with_mnemonic("Show _Tabs");
807 gtk_menu_append(GTK_MENU(s
->view_menu
), s
->show_tabs_item
);
809 g_object_set_data(G_OBJECT(s
->window
), "accel_group", accel_group
);
810 gtk_window_add_accel_group(GTK_WINDOW(s
->window
), accel_group
);
812 gtk_menu_append(GTK_MENU(s
->file_menu
), s
->quit_item
);
813 gtk_menu_item_set_submenu(GTK_MENU_ITEM(s
->file_menu_item
), s
->file_menu
);
814 gtk_menu_shell_append(GTK_MENU_SHELL(s
->menu_bar
), s
->file_menu_item
);
816 gtk_menu_item_set_submenu(GTK_MENU_ITEM(s
->view_menu_item
), s
->view_menu
);
817 gtk_menu_shell_append(GTK_MENU_SHELL(s
->menu_bar
), s
->view_menu_item
);
820 void gtk_display_init(DisplayState
*ds
)
822 GtkDisplayState
*s
= g_malloc0(sizeof(*s
));
824 gtk_init(NULL
, NULL
);
828 s
->dcl
.dpy_gfx_update
= gd_update
;
829 s
->dcl
.dpy_gfx_resize
= gd_resize
;
830 s
->dcl
.dpy_refresh
= gd_refresh
;
832 s
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
833 s
->vbox
= gtk_vbox_new(FALSE
, 0);
834 s
->notebook
= gtk_notebook_new();
835 s
->drawing_area
= gtk_drawing_area_new();
836 s
->menu_bar
= gtk_menu_bar_new();
841 s
->null_cursor
= gdk_cursor_new(GDK_BLANK_CURSOR
);
843 s
->mouse_mode_notifier
.notify
= gd_mouse_mode_change
;
844 qemu_add_mouse_mode_change_notifier(&s
->mouse_mode_notifier
);
845 qemu_add_vm_change_state_handler(gd_change_runstate
, s
);
847 gtk_notebook_append_page(GTK_NOTEBOOK(s
->notebook
), s
->drawing_area
, gtk_label_new("VGA"));
851 gd_connect_signals(s
);
853 gtk_widget_add_events(s
->drawing_area
,
854 GDK_POINTER_MOTION_MASK
|
855 GDK_BUTTON_PRESS_MASK
|
856 GDK_BUTTON_RELEASE_MASK
|
857 GDK_BUTTON_MOTION_MASK
|
858 GDK_ENTER_NOTIFY_MASK
|
859 GDK_LEAVE_NOTIFY_MASK
|
862 gtk_widget_set_double_buffered(s
->drawing_area
, FALSE
);
863 gtk_widget_set_can_focus(s
->drawing_area
, TRUE
);
865 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s
->notebook
), FALSE
);
866 gtk_notebook_set_show_border(GTK_NOTEBOOK(s
->notebook
), FALSE
);
868 gtk_window_set_resizable(GTK_WINDOW(s
->window
), FALSE
);
870 gd_update_caption(s
);
872 gtk_box_pack_start(GTK_BOX(s
->vbox
), s
->menu_bar
, FALSE
, TRUE
, 0);
873 gtk_box_pack_start(GTK_BOX(s
->vbox
), s
->notebook
, TRUE
, TRUE
, 0);
875 gtk_container_add(GTK_CONTAINER(s
->window
), s
->vbox
);
877 gtk_widget_show_all(s
->window
);
879 register_displaychangelistener(ds
, &s
->dcl
);