diff --git a/gtk/src/gtk_control.cpp b/gtk/src/gtk_control.cpp index 2d4e3f47..f79be2ad 100644 --- a/gtk/src/gtk_control.cpp +++ b/gtk/src/gtk_control.cpp @@ -99,6 +99,7 @@ const BindingLink b_links[] = { "b_seek_to_frame", "GTK_seek_to_frame" }, { "b_swap_controllers", "GTK_swap_controllers" }, { "b_rewind", "GTK_rewind" }, + { "b_grab_mouse", "GTK_grab_mouse" }, { NULL, NULL } }; @@ -112,7 +113,7 @@ const int b_breaks[] = 43, /* End of Graphic options */ 69, /* End of save/load states */ 78, /* End of sound buttons */ - 85, /* End of miscellaneous buttons */ + 86, /* End of miscellaneous buttons */ -1 }; @@ -289,6 +290,11 @@ void S9xHandlePortCommand (s9xcommand_t cmd, int16 data1, int16 data2) { change_slot (-1); } + + else if (cmd.port[0] == PORT_GRABMOUSE) + { + top_level->toggle_grab_mouse (); + } } } @@ -437,6 +443,11 @@ s9xcommand_t S9xGetPortCommandT (const char *name) cmd.port[0] = PORT_DECREMENTSLOT; } + else if (strstr (name, "GTK_grab_mouse")) + { + cmd.port[0] = PORT_GRABMOUSE; + } + else { diff --git a/gtk/src/gtk_control.h b/gtk/src/gtk_control.h index 1130645c..31a0e34c 100644 --- a/gtk/src/gtk_control.h +++ b/gtk/src/gtk_control.h @@ -49,6 +49,7 @@ enum PORT_DECREMENTLOADSLOT = 22, PORT_INCREMENTSLOT = 23, PORT_DECREMENTSLOT = 24, + PORT_GRABMOUSE = 25 }; typedef struct BindingLink @@ -61,7 +62,7 @@ typedef struct BindingLink extern const BindingLink b_links[]; extern const int b_breaks[]; const int NUM_JOYPAD_LINKS = 24; -const int NUM_EMU_LINKS = 61; +const int NUM_EMU_LINKS = 62; typedef struct JoypadBinding { diff --git a/gtk/src/gtk_s9xwindow.cpp b/gtk/src/gtk_s9xwindow.cpp index 9b9d01e5..def31d5f 100644 --- a/gtk/src/gtk_s9xwindow.cpp +++ b/gtk/src/gtk_s9xwindow.cpp @@ -232,6 +232,19 @@ event_motion_notify (GtkWidget *widget, return FALSE; } + if (window->mouse_grabbed) + { + if (event->x_root == window->mouse_reported_x && + event->y_root == window->mouse_reported_y) + return FALSE; + + window->mouse_loc_x += (event->x_root - window->mouse_reported_x); + window->mouse_loc_y += (event->y_root - window->mouse_reported_y); + window->center_mouse (); + + return FALSE; + } + #if GTK_CHECK_VERSION(3,10,0) int scale_factor = gdk_window_get_scale_factor (gtk_widget_get_window (GTK_WIDGET (window->get_window ()))); #else @@ -594,6 +607,7 @@ Snes9xWindow::Snes9xWindow (Snes9xConfig *config) : paused_from_focus_loss = 0; cr = NULL; cairo_owned = 0; + mouse_grabbed = 0; if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default (), "snes9x")) { @@ -1804,6 +1818,84 @@ Snes9xWindow::show_mouse_cursor () config->pointer_is_visible = TRUE; } +void +Snes9xWindow::center_mouse () +{ + GdkWindow *gdk_window = gtk_widget_get_window (window); + GdkDisplay *gdk_display = gdk_window_get_display (gdk_window); + GdkScreen *gdk_screen = gdk_window_get_screen (gdk_window); + int x, y, w, h; + + gdk_window_get_origin (gdk_window, &x, &y); + w = gdk_window_get_width (gdk_window); + h = gdk_window_get_height (gdk_window); + + mouse_reported_x = x + w / 2; + mouse_reported_y = y + h / 2; + +#if GTK_MAJOR_VERSION < 3 + gdk_display_warp_pointer (gdk_display, gdk_screen, mouse_reported_x, + mouse_reported_y); +#elif GTK_MINOR_VERSION < 20 + GdkDeviceManager *manager = gdk_display_get_device_manager (gdk_display); + GdkDevice *pointer = gdk_device_manager_get_client_pointer (manager); + + gdk_device_warp (pointer, gdk_screen, mouse_reported_x, mouse_reported_y); +#else + GdkSeat *seat = gdk_display_get_default_seat (gdk_display); + GdkDevice *pointer = gdk_seat_get_pointer (seat); + + gdk_device_warp (pointer, gdk_screen, mouse_reported_x, mouse_reported_y); +#endif +} + +void +Snes9xWindow::toggle_grab_mouse () +{ + GdkWindow *gdk_window = gtk_widget_get_window (window); + GdkDisplay *gdk_display = gdk_window_get_display (gdk_window); + + if ((!mouse_grabbed && !S9xIsMousePluggedIn ()) || !config->rom_loaded) + return; + +#if GTK_MAJOR_VERSION < 3 + if (!mouse_grabbed) + { + gdk_pointer_grab (gdk_window, TRUE, (GdkEventMask) 1020, gdk_window, empty_cursor, GDK_CURRENT_TIME); + center_mouse (); + } + else + { + gdk_pointer_ungrab (GDK_CURRENT_TIME); + if (config->pointer_is_visible) + show_mouse_cursor (); + } +#elif GTK_MINOR_VERSION < 20 + GdkDeviceManager *manager = gdk_display_get_device_manager (gdk_display); + GdkDevice *pointer = gdk_device_manager_get_client_pointer (manager); + + if (!mouse_grabbed) + gdk_device_grab (pointer, gdk_window, GDK_OWNERSHIP_NONE, TRUE, + (GdkEventMask) 1020, empty_cursor, GDK_CURRENT_TIME); + else + gdk_device_ungrab (pointer, GDK_CURRENT_TIME); +#else + GdkSeat *seat = gdk_display_get_default_seat (gdk_display); + + if (!mouse_grabbed) + gdk_seat_grab (seat, gdk_window, GDK_SEAT_CAPABILITY_ALL_POINTING, TRUE, + empty_cursor, NULL, NULL, NULL); + else + gdk_seat_ungrab (seat); +#endif + + S9xReportPointer (BINDING_MOUSE_POINTER, 0, 0); + mouse_loc_x = 0; mouse_loc_y = 0; + mouse_grabbed ^= 1; + if (mouse_grabbed) + center_mouse (); +} + void Snes9xWindow::show () { diff --git a/gtk/src/gtk_s9xwindow.h b/gtk/src/gtk_s9xwindow.h index ea9c2888..742882a7 100644 --- a/gtk/src/gtk_s9xwindow.h +++ b/gtk/src/gtk_s9xwindow.h @@ -30,6 +30,8 @@ class Snes9xWindow : public GtkBuilderWindow /* Cursor modifying functions */ void show_mouse_cursor (); void hide_mouse_cursor (); + void toggle_grab_mouse (); + void center_mouse (); /* Rom-related functions */ void open_rom_dialog (); @@ -75,6 +77,8 @@ class Snes9xWindow : public GtkBuilderWindow int focused; int paused_from_focus_loss; uint16 mouse_loc_x, mouse_loc_y; + uint16 mouse_reported_x, mouse_reported_y; + int mouse_grabbed; GdkPixbuf *icon, *splash; GdkCursor *default_cursor, *empty_cursor; GtkDrawingArea *drawing_area; diff --git a/gtk/src/snes9x.ui b/gtk/src/snes9x.ui index 6cff9698..c6ae0daa 100644 --- a/gtk/src/snes9x.ui +++ b/gtk/src/snes9x.ui @@ -8709,7 +8709,7 @@ False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 10 - 7 + 8 2 10 5 @@ -8936,6 +8936,37 @@ GTK_FILL + + + True + False + 0 + Capture/release mouse + + + 7 + 8 + GTK_FILL + + + + + + True + True + False + False + True + True + + + 1 + 2 + 7 + 8 + GTK_FILL + + 4