I made a quick hack that will force the game to grab the pointer and lock it to the window. To try it out, save this C code to a file (e.g. grab_pointer.c):
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdbool.h>
#include <X11/Xlib.h>
typedef int (*real_XNextEvent_t)(Display *display, XEvent *event_return);
real_XNextEvent_t real_XNextEvent;
int XNextEvent(Display *display, XEvent *event_return)
{
static bool first_expose_done = false;
XExposeEvent *ev;
int ret;
ret = real_XNextEvent(display, event_return);
if (!first_expose_done && event_return->type == Expose) {
ev = (XExposeEvent *)event_return;
XGrabPointer(ev->display, ev->window, True, 0, GrabModeAsync, GrabModeAsync, ev->window, None, CurrentTime);
first_expose_done = true;
}
return ret;
}
__attribute__((constructor)) void init(void)
{
real_XNextEvent = dlsym(RTLD_NEXT, "XNextEvent");
}
Compile the file like this:
gcc -shared -fPIC -O3 -march=native -lX11 grab_pointer.c -o grab_pointer.so
This will create the shared object file grab_pointer.so.
Now you just need to "preload" this code when you run the game. At the command line, try this (changing the paths to the approriate locations):
LD_PRELOAD=/absolute/path/to/grab_pointer.so /path/to/Pillars\ of\ Eternity/start.sh
Or if you don't want to have to run that at the command line each time, you can edit the game's start.sh and add this line at the top (but after #!/bin/bash):
export LD_PRELOAD=/absolute/path/to/grab_pointer.so
Hope that works for you until Obsidian fixes the issue.