diff options
Diffstat (limited to 'ui/gtk.c')
-rw-r--r-- | ui/gtk.c | 120 |
1 files changed, 102 insertions, 18 deletions
@@ -54,7 +54,9 @@ #include <gdk/gdkkeysyms.h> #include <glib/gi18n.h> #include <locale.h> +#if defined(CONFIG_VTE) #include <vte/vte.h> +#endif #include <math.h> #include "trace.h" @@ -68,6 +70,9 @@ #define MAX_VCS 10 +#if !defined(CONFIG_VTE) +# define VTE_CHECK_VERSION(a, b, c) 0 +#endif /* Compatibility define to let us build on both Gtk2 and Gtk3 */ #if GTK_CHECK_VERSION(3, 0, 0) @@ -105,8 +110,10 @@ typedef struct VirtualConsole { GtkWidget *menu_item; GtkWidget *terminal; +#if defined(CONFIG_VTE) GtkWidget *scrolled_window; CharDriverState *chr; +#endif int fd; } VirtualConsole; @@ -149,8 +156,11 @@ typedef struct GtkDisplayState DisplayChangeListener dcl; DisplaySurface *ds; int button_mask; + gboolean last_set; int last_x; int last_y; + int grab_x_root; + int grab_y_root; double scale_x; double scale_y; @@ -340,13 +350,17 @@ static void gd_mouse_set(DisplayChangeListener *dcl, GdkDeviceManager *mgr; gint x_root, y_root; + if (qemu_input_is_absolute()) { + return; + } + dpy = gtk_widget_get_display(s->drawing_area); mgr = gdk_display_get_device_manager(dpy); gdk_window_get_root_coords(gtk_widget_get_window(s->drawing_area), x, y, &x_root, &y_root); gdk_device_warp(gdk_device_manager_get_client_pointer(mgr), gtk_widget_get_screen(s->drawing_area), - x, y); + x_root, y_root); } #else static void gd_mouse_set(DisplayChangeListener *dcl, @@ -355,6 +369,10 @@ static void gd_mouse_set(DisplayChangeListener *dcl, GtkDisplayState *s = container_of(dcl, GtkDisplayState, dcl); gint x_root, y_root; + if (qemu_input_is_absolute()) { + return; + } + gdk_window_get_root_coords(gtk_widget_get_window(s->drawing_area), x, y, &x_root, &y_root); gdk_display_warp_pointer(gtk_widget_get_display(s->drawing_area), @@ -458,8 +476,15 @@ static void gd_change_runstate(void *opaque, int running, RunState state) static void gd_mouse_mode_change(Notifier *notify, void *data) { - gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier), - FALSE); + GtkDisplayState *s; + + s = container_of(notify, GtkDisplayState, mouse_mode_notifier); + /* release the grab at switching to absolute mode */ + if (qemu_input_is_absolute() && gd_is_grab_active(s)) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), + FALSE); + } + gd_update_cursor(s, FALSE); } /** GTK Events **/ @@ -601,25 +626,25 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, x = (motion->x - mx) / s->scale_x; y = (motion->y - my) / s->scale_y; - if (x < 0 || y < 0 || - x >= surface_width(s->ds) || - y >= surface_height(s->ds)) { - return TRUE; - } - if (qemu_input_is_absolute()) { + if (x < 0 || y < 0 || + x >= surface_width(s->ds) || + y >= surface_height(s->ds)) { + return TRUE; + } qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_X, x, surface_width(s->ds)); qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_Y, y, surface_height(s->ds)); qemu_input_event_sync(); - } else if (s->last_x != -1 && s->last_y != -1 && gd_is_grab_active(s)) { + } else if (s->last_set && gd_is_grab_active(s)) { qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_X, x - s->last_x); qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_Y, y - s->last_y); qemu_input_event_sync(); } s->last_x = x; s->last_y = y; + s->last_set = TRUE; if (!qemu_input_is_absolute() && gd_is_grab_active(s)) { GdkScreen *screen = gtk_widget_get_screen(s->drawing_area); @@ -654,8 +679,7 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, GdkDisplay *display = gtk_widget_get_display(widget); gdk_display_warp_pointer(display, screen, x, y); #endif - s->last_x = -1; - s->last_y = -1; + s->last_set = FALSE; return FALSE; } } @@ -668,6 +692,14 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, GtkDisplayState *s = opaque; InputButton btn; + /* implicitly grab the input at the first click in the relative mode */ + if (button->button == 1 && button->type == GDK_BUTTON_PRESS && + !qemu_input_is_absolute() && !gd_is_grab_active(s)) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), + TRUE); + return TRUE; + } + if (button->button == 1) { btn = INPUT_BUTTON_LEFT; } else if (button->button == 2) { @@ -683,6 +715,27 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, return TRUE; } +static gboolean gd_scroll_event(GtkWidget *widget, GdkEventScroll *scroll, + void *opaque) +{ + GtkDisplayState *s = opaque; + InputButton btn; + + if (scroll->direction == GDK_SCROLL_UP) { + btn = INPUT_BUTTON_WHEEL_UP; + } else if (scroll->direction == GDK_SCROLL_DOWN) { + btn = INPUT_BUTTON_WHEEL_DOWN; + } else { + return TRUE; + } + + qemu_input_queue_btn(s->dcl.con, btn, true); + qemu_input_event_sync(); + qemu_input_queue_btn(s->dcl.con, btn, false); + qemu_input_event_sync(); + return TRUE; +} + static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) { GtkDisplayState *s = opaque; @@ -729,6 +782,14 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) return TRUE; } +static gboolean gd_event(GtkWidget *widget, GdkEvent *event, void *opaque) +{ + if (event->type == GDK_MOTION_NOTIFY) { + return gd_motion_event(widget, &event->motion, opaque); + } + return FALSE; +} + /** Window Menu Actions **/ static void gd_menu_pause(GtkMenuItem *item, void *opaque) @@ -927,8 +988,8 @@ static void gd_ungrab_keyboard(GtkDisplayState *s) static void gd_grab_pointer(GtkDisplayState *s) { -#if GTK_CHECK_VERSION(3, 0, 0) GdkDisplay *display = gtk_widget_get_display(s->drawing_area); +#if GTK_CHECK_VERSION(3, 0, 0) GdkDeviceManager *mgr = gdk_display_get_device_manager(display); GList *devices = gdk_device_manager_list_devices(mgr, GDK_DEVICE_TYPE_MASTER); @@ -952,6 +1013,8 @@ static void gd_grab_pointer(GtkDisplayState *s) tmp = tmp->next; } g_list_free(devices); + gdk_device_get_position(gdk_device_manager_get_client_pointer(mgr), + NULL, &s->grab_x_root, &s->grab_y_root); #else gdk_pointer_grab(gtk_widget_get_window(s->drawing_area), FALSE, /* All events to come to our window directly */ @@ -963,13 +1026,15 @@ static void gd_grab_pointer(GtkDisplayState *s) NULL, /* Allow cursor to move over entire desktop */ s->null_cursor, GDK_CURRENT_TIME); + gdk_display_get_pointer(display, NULL, + &s->grab_x_root, &s->grab_y_root, NULL); #endif } static void gd_ungrab_pointer(GtkDisplayState *s) { -#if GTK_CHECK_VERSION(3, 0, 0) GdkDisplay *display = gtk_widget_get_display(s->drawing_area); +#if GTK_CHECK_VERSION(3, 0, 0) GdkDeviceManager *mgr = gdk_display_get_device_manager(display); GList *devices = gdk_device_manager_list_devices(mgr, GDK_DEVICE_TYPE_MASTER); @@ -983,8 +1048,14 @@ static void gd_ungrab_pointer(GtkDisplayState *s) tmp = tmp->next; } g_list_free(devices); + gdk_device_warp(gdk_device_manager_get_client_pointer(mgr), + gtk_widget_get_screen(s->drawing_area), + s->grab_x_root, s->grab_y_root); #else gdk_pointer_ungrab(GDK_CURRENT_TIME); + gdk_display_warp_pointer(display, + gtk_widget_get_screen(s->drawing_area), + s->grab_x_root, s->grab_y_root); #endif } @@ -1034,6 +1105,7 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2, if (arg2 == 0) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->vga_item), TRUE); } else { +#if defined(CONFIG_VTE) VirtualConsole *vc = &s->vc[arg2 - 1]; VteTerminal *term = VTE_TERMINAL(vc->terminal); int width, height; @@ -1043,6 +1115,9 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2, gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item), TRUE); gtk_widget_set_size_request(vc->terminal, width, height); +#else + g_assert_not_reached(); +#endif } gtk_widget_set_sensitive(s->grab_item, on_vga); @@ -1088,7 +1163,7 @@ static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { VirtualConsole *vc = chr->opaque; - return write(vc->fd, buf, len); + return vc ? write(vc->fd, buf, len) : len; } static int nb_vcs; @@ -1113,6 +1188,7 @@ void early_gtk_display_init(void) register_vc_handler(gd_vc_handler); } +#if defined(CONFIG_VTE) static gboolean gd_vc_in(GIOChannel *chan, GIOCondition cond, void *opaque) { VirtualConsole *vc = opaque; @@ -1128,10 +1204,12 @@ static gboolean gd_vc_in(GIOChannel *chan, GIOCondition cond, void *opaque) return TRUE; } +#endif static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSList *group, GtkWidget *view_menu) { +#if defined(CONFIG_VTE) const char *label; char buffer[32]; char path[32]; @@ -1201,6 +1279,7 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL chan = g_io_channel_unix_new(vc->fd); g_io_add_watch(chan, G_IO_IN, gd_vc_in, vc); +#endif /* CONFIG_VTE */ return group; } @@ -1223,12 +1302,14 @@ static void gd_connect_signals(GtkDisplayState *s) g_signal_connect(s->drawing_area, "expose-event", G_CALLBACK(gd_expose_event), s); #endif - g_signal_connect(s->drawing_area, "motion-notify-event", - G_CALLBACK(gd_motion_event), s); + g_signal_connect(s->drawing_area, "event", + G_CALLBACK(gd_event), s); g_signal_connect(s->drawing_area, "button-press-event", G_CALLBACK(gd_button_event), s); g_signal_connect(s->drawing_area, "button-release-event", G_CALLBACK(gd_button_event), s); + g_signal_connect(s->drawing_area, "scroll-event", + G_CALLBACK(gd_scroll_event), s); g_signal_connect(s->drawing_area, "key-press-event", G_CALLBACK(gd_key_event), s); g_signal_connect(s->drawing_area, "key-release-event", @@ -1415,7 +1496,7 @@ static const DisplayChangeListenerOps dcl_ops = { .dpy_cursor_define = gd_cursor_define, }; -void gtk_display_init(DisplayState *ds, bool full_screen) +void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover) { GtkDisplayState *s = g_malloc0(sizeof(*s)); char *filename; @@ -1494,6 +1575,9 @@ void gtk_display_init(DisplayState *ds, bool full_screen) if (full_screen) { gtk_menu_item_activate(GTK_MENU_ITEM(s->full_screen_item)); } + if (grab_on_hover) { + gtk_menu_item_activate(GTK_MENU_ITEM(s->grab_on_hover_item)); + } register_displaychangelistener(&s->dcl); |