Grab mouse on linux when panning is enabled

This commit is contained in:
Deve 2018-05-18 22:35:54 +02:00
parent ad9a314bcf
commit f2325e9140
2 changed files with 88 additions and 26 deletions

View File

@ -105,7 +105,8 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters& param)
Width(param.WindowSize.Width), Height(param.WindowSize.Height), Width(param.WindowSize.Width), Height(param.WindowSize.Height),
WindowHasFocus(false), WindowMinimized(false), WindowHasFocus(false), WindowMinimized(false),
UseXVidMode(false), UseXRandR(false), UseGLXWindow(false), UseXVidMode(false), UseXRandR(false), UseGLXWindow(false),
ExternalWindow(false), AutorepeatSupport(0) ExternalWindow(false), AutorepeatSupport(0), SupportsNetWM(false),
NeedsGrabPointer(false)
{ {
#ifdef _DEBUG #ifdef _DEBUG
setDebugName("CIrrDeviceLinux"); setDebugName("CIrrDeviceLinux");
@ -478,6 +479,19 @@ bool CIrrDeviceLinux::changeResolution()
if (s == Success) if (s == Success)
UseXRandR = true; UseXRandR = true;
if (UseXRandR && SupportsNetWM)
{
XRRPanning* panning = XRRGetPanning(display, res, output->crtc);
if ((panning->width != Width && panning->width != 0) ||
(panning->height != Height && panning->height != 0))
{
NeedsGrabPointer = true;
}
XRRFreePanning(panning);
}
XRRFreeCrtcInfo(crtc); XRRFreeCrtcInfo(crtc);
XRRFreeOutputInfo(output); XRRFreeOutputInfo(output);
XRRFreeScreenResources(res); XRRFreeScreenResources(res);
@ -614,6 +628,40 @@ static GLXContext getMeAGLContext(Display *display, GLXFBConfig glxFBConfig, boo
#endif #endif
#endif #endif
void CIrrDeviceLinux::grabPointer(bool grab)
{
#ifdef _IRR_COMPILE_WITH_X11_
if (grab)
{
int result = 0;
for (int i = 0; i < 500; i++)
{
const unsigned int mask = ButtonPressMask | ButtonReleaseMask |
PointerMotionMask | FocusChangeMask;
int result = XGrabPointer(display, window, True, mask,
GrabModeAsync, GrabModeAsync,
window, None, CurrentTime);
if (result == GrabSuccess)
break;
usleep(1000);
}
if (result != GrabSuccess)
{
os::Printer::log("Couldn't grab pointer.", ELL_WARNING);
}
}
else
{
XUngrabPointer(display, CurrentTime);
}
#endif
}
bool CIrrDeviceLinux::createWindow() bool CIrrDeviceLinux::createWindow()
{ {
#ifdef _IRR_COMPILE_WITH_X11_ #ifdef _IRR_COMPILE_WITH_X11_
@ -633,6 +681,24 @@ bool CIrrDeviceLinux::createWindow()
screennr = DefaultScreen(display); screennr = DefaultScreen(display);
Atom *list;
Atom type;
int form;
unsigned long remain, len;
Atom WMCheck = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", false);
Status s = XGetWindowProperty(display, DefaultRootWindow(display),
WMCheck, 0L, 1L, False, XA_WINDOW,
&type, &form, &len, &remain,
(unsigned char **)&list);
if (s == Success)
{
XFree(list);
SupportsNetWM = (len > 0);
}
changeResolution(); changeResolution();
#ifdef _IRR_COMPILE_WITH_OPENGL_ #ifdef _IRR_COMPILE_WITH_OPENGL_
@ -955,29 +1021,9 @@ bool CIrrDeviceLinux::createWindow()
ButtonPressMask | KeyPressMask | ButtonPressMask | KeyPressMask |
ButtonReleaseMask | KeyReleaseMask; ButtonReleaseMask | KeyReleaseMask;
bool netWM = false;
Atom *list;
Atom type;
int form;
unsigned long remain, len;
Atom WMCheck = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", false);
Status s = XGetWindowProperty(display, DefaultRootWindow(display),
WMCheck, 0L, 1L, False, XA_WINDOW,
&type, &form, &len, &remain,
(unsigned char **)&list);
if (s == Success)
{
XFree(list);
netWM = (len > 0);
}
if (!CreationParams.WindowId) if (!CreationParams.WindowId)
{ {
attributes.override_redirect = !netWM && CreationParams.Fullscreen; attributes.override_redirect = !SupportsNetWM && CreationParams.Fullscreen;
// create new Window // create new Window
window = XCreateWindow(display, window = XCreateWindow(display,
@ -1010,7 +1056,7 @@ bool CIrrDeviceLinux::createWindow()
bool has_display_size = (Width == display_width && Height == display_height); bool has_display_size = (Width == display_width && Height == display_height);
if (netWM && (CreationParams.Fullscreen || has_display_size)) if (SupportsNetWM && (CreationParams.Fullscreen || has_display_size))
{ {
Atom WMStateAtom = XInternAtom(display, "_NET_WM_STATE", true); Atom WMStateAtom = XInternAtom(display, "_NET_WM_STATE", true);
Atom WMStateAtom1 = None; Atom WMStateAtom1 = None;
@ -1078,9 +1124,14 @@ bool CIrrDeviceLinux::createWindow()
{ {
os::Printer::log("Warning! Got timeout when changing window state", ELL_WARNING); os::Printer::log("Warning! Got timeout when changing window state", ELL_WARNING);
} }
if (NeedsGrabPointer)
{
grabPointer(true);
}
} }
if (!netWM && CreationParams.Fullscreen) if (!SupportsNetWM && CreationParams.Fullscreen)
{ {
XSetInputFocus(display, window, RevertToParent, CurrentTime); XSetInputFocus(display, window, RevertToParent, CurrentTime);
int grabKb = XGrabKeyboard(display, window, True, GrabModeAsync, int grabKb = XGrabKeyboard(display, window, True, GrabModeAsync,
@ -1178,7 +1229,7 @@ bool CIrrDeviceLinux::createWindow()
CreationParams.WindowSize.Width = Width; CreationParams.WindowSize.Width = Width;
CreationParams.WindowSize.Height = Height; CreationParams.WindowSize.Height = Height;
if (netWM == true) if (SupportsNetWM == true)
{ {
Atom opaque_region = XInternAtom(display, "_NET_WM_OPAQUE_REGION", true); Atom opaque_region = XInternAtom(display, "_NET_WM_OPAQUE_REGION", true);
@ -1614,10 +1665,18 @@ bool CIrrDeviceLinux::run()
break; break;
case FocusIn: case FocusIn:
if (NeedsGrabPointer)
{
grabPointer(true);
}
WindowHasFocus=true; WindowHasFocus=true;
break; break;
case FocusOut: case FocusOut:
if (NeedsGrabPointer)
{
grabPointer(false);
}
WindowHasFocus=false; WindowHasFocus=false;
break; break;

View File

@ -158,6 +158,7 @@ namespace irr
bool restoreResolution(); bool restoreResolution();
bool changeResolution(); bool changeResolution();
void grabPointer(bool grab);
#ifdef _IRR_COMPILE_WITH_X11_ #ifdef _IRR_COMPILE_WITH_X11_
bool createInputContext(); bool createInputContext();
@ -434,6 +435,8 @@ namespace irr
bool UseGLXWindow; bool UseGLXWindow;
bool ExternalWindow; bool ExternalWindow;
int AutorepeatSupport; int AutorepeatSupport;
bool SupportsNetWM;
bool NeedsGrabPointer;
struct SKeyMap struct SKeyMap
{ {