Skip to content
Permalink
Browse files

Implement mouse grabbing for GTK on X11 (#1637)

The same thing should somehow also be possible using gdk_device_grab(),
but I couldn't get it to work properly.
  • Loading branch information
lluchs committed Feb 24, 2016
1 parent bfd9989 commit 3a4e667f4d7bd34af185e7ea6d15641fb81eac7a
Showing with 48 additions and 1 deletion.
  1. +2 −0 src/platform/C4Window.h
  2. +46 −1 src/platform/C4WindowGTK.cpp
@@ -430,6 +430,8 @@ class C4Window
// Set by Init to the widget which is used as a
// render target, which can be the whole window.
/*GtkWidget*/void * render_widget;
// Mouse grabbing has to be restored when the window gains focus.
bool mouse_was_grabbed = false;
#elif defined(USE_SDL_MAINLOOP)
SDL_Window * window;
#endif
@@ -378,6 +378,36 @@ static gboolean fullscreen_restore(gpointer data)
return FALSE;
}

static bool grab_mouse(GtkWidget *widget)
{
// This should be possible with pure GTK code as well, using
// gdk_device_grab(). However, while gdk_device_grab() will prevent clicks
// outside of the game window, the mouse gets stuck near the edge of the
// window when trying to move outside.
#ifdef GDK_WINDOWING_X11
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
Window xwindow = gdk_x11_window_get_xid(gtk_widget_get_window(widget));
int result = XGrabPointer(dpy, xwindow, true, 0, GrabModeAsync, GrabModeAsync, xwindow, None, CurrentTime);
return result == GrabSuccess;
#endif
return true;
}

static void ungrab_mouse()
{
#ifdef GDK_WINDOWING_X11
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
XUngrabPointer(dpy, CurrentTime);
#endif
}

static gboolean grab_mouse_fn(gpointer user_data)
{
// Grabbing may not be possible immediately after focusing the window, so
// try again if we don't succeed.
return !grab_mouse((GtkWidget*) user_data);
}

static gboolean OnFocusInFS(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
Application.Active = true;
@@ -386,6 +416,9 @@ static gboolean OnFocusInFS(GtkWidget *widget, GdkEvent *event, gpointer user_d
fullscreen_needs_restore = true;
gdk_threads_add_idle(fullscreen_restore, NULL);
}
C4Window *window = (C4Window*) user_data;
if (window->mouse_was_grabbed)
gdk_threads_add_timeout(50, grab_mouse_fn, widget);
return false;
}
static gboolean OnFocusOutFS(GtkWidget *widget, GdkEvent *event, gpointer user_data)
@@ -397,6 +430,7 @@ static gboolean OnFocusOutFS(GtkWidget *widget, GdkEvent *event, gpointer user_
gtk_window_iconify(GTK_WINDOW(widget));
fullscreen_needs_restore = false;
}
ungrab_mouse();
return false;
}

@@ -607,7 +641,18 @@ void C4Window::FlashWindow()

void C4Window::GrabMouse(bool grab)
{
// TODO
if (grab)
{
// Don't grab the mouse while the game window isn't focused.
if (Application.Active)
grab_mouse(GTK_WIDGET(window));
mouse_was_grabbed = true;
}
else
{
ungrab_mouse();
mouse_was_grabbed = false;
}
}

C4Window* C4Window::Init(WindowKind windowKind, C4AbstractApp * pApp, const char * Title, const C4Rect * size)

0 comments on commit 3a4e667

Please sign in to comment.
You can’t perform that action at this time.