static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, void *opaque) { GtkDisplayState *s = opaque; int x, y; int mx, my; int fbh, fbw; int ww, wh; fbw = surface_width(s->ds) * s->scale_x; fbh = surface_height(s->ds) * s->scale_y; gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh); mx = my = 0; if (ww > fbw) { mx = (ww - fbw) / 2; } if (wh > fbh) { my = (wh - fbh) / 2; } 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()) { 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)) { 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; if (!qemu_input_is_absolute() && gd_is_grab_active(s)) { GdkScreen *screen = gtk_widget_get_screen(s->drawing_area); int x = (int)motion->x_root; int y = (int)motion->y_root; /* In relative mode check to see if client pointer hit * one of the screen edges, and if so move it back by * 200 pixels. This is important because the pointer * in the server doesn't correspond 1-for-1, and so * may still be only half way across the screen. Without * this warp, the server pointer would thus appear to hit * an invisible wall */ if (x == 0) { x += 200; } if (y == 0) { y += 200; } if (x == (gdk_screen_get_width(screen) - 1)) { x -= 200; } if (y == (gdk_screen_get_height(screen) - 1)) { y -= 200; } if (x != (int)motion->x_root || y != (int)motion->y_root) { #if GTK_CHECK_VERSION(3, 0, 0) GdkDevice *dev = gdk_event_get_device((GdkEvent *)motion); gdk_device_warp(dev, screen, x, y); #else GdkDisplay *display = gtk_widget_get_display(widget); gdk_display_warp_pointer(display, screen, x, y); #endif s->last_x = -1; s->last_y = -1; return FALSE; } } return TRUE; }