mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-23 15:55:31 +00:00
[X11] Send ClientMessage to exit input event loop
To do that, we need a custom InputOnly window. This window is only used for receiving the exit ClientMessage - XI2 input is still received through the root window. Fixes issue https://github.com/mono/MonoGame/issues/2711
This commit is contained in:
parent
7accefea3e
commit
ea5f1ad1e8
|
@ -36,7 +36,7 @@ namespace OpenTK.Platform.X11
|
|||
{
|
||||
sealed class XI2MouseKeyboard : IKeyboardDriver2, IMouseDriver2, IDisposable
|
||||
{
|
||||
const XEventName ExitEvent = XEventName.LASTEvent + 1;
|
||||
static readonly IntPtr ExitAtom;
|
||||
readonly object Sync = new object();
|
||||
readonly Thread ProcessingThread;
|
||||
readonly X11KeyMap KeyMap;
|
||||
|
@ -116,6 +116,9 @@ namespace OpenTK.Platform.X11
|
|||
//TouchPressure = Functions.XInternAtom(API.DefaultDisplay, "Abs MT Pressure", false);
|
||||
//TouchId = Functions.XInternAtom(API.DefaultDisplay, "Abs MT Tracking ID", false);
|
||||
//TouchMaxContacts = Functions.XInternAtom(API.DefaultDisplay, "Max Contacts", false);
|
||||
|
||||
// Custom
|
||||
ExitAtom = Functions.XInternAtom(API.DefaultDisplay, "Exit Input Thread Message", false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,9 +129,14 @@ namespace OpenTK.Platform.X11
|
|||
window.Display = Functions.XOpenDisplay(IntPtr.Zero);
|
||||
using (new XLock(window.Display))
|
||||
{
|
||||
XSetWindowAttributes attr = new XSetWindowAttributes();
|
||||
|
||||
window.Screen = Functions.XDefaultScreen(window.Display);
|
||||
window.RootWindow = Functions.XRootWindow(window.Display, window.Screen);
|
||||
window.Handle = window.RootWindow;
|
||||
window.Handle = Functions.XCreateWindow(window.Display, window.RootWindow,
|
||||
0, 0, 1, 1, 0, 0,
|
||||
CreateWindowArgs.InputOnly, IntPtr.Zero,
|
||||
SetWindowValuemask.Nothing, attr);
|
||||
|
||||
KeyMap = new X11KeyMap(window.Display);
|
||||
}
|
||||
|
@ -136,6 +144,10 @@ namespace OpenTK.Platform.X11
|
|||
if (!IsSupported(window.Display))
|
||||
throw new NotSupportedException("XInput2 not supported.");
|
||||
|
||||
// Enable XI2 mouse/keyboard events
|
||||
// Note: the input event loop blocks waiting for these events
|
||||
// *or* a custom ClientMessage event that instructs us to exit.
|
||||
// See SendExitEvent() below.
|
||||
using (new XLock(window.Display))
|
||||
using (XIEventMask mask = new XIEventMask(1,
|
||||
XIEventMasks.RawKeyPressMask |
|
||||
|
@ -144,10 +156,9 @@ namespace OpenTK.Platform.X11
|
|||
XIEventMasks.RawButtonReleaseMask |
|
||||
XIEventMasks.RawMotionMask |
|
||||
XIEventMasks.MotionMask |
|
||||
XIEventMasks.DeviceChangedMask |
|
||||
(XIEventMasks)(1 << (int)ExitEvent)))
|
||||
XIEventMasks.DeviceChangedMask))
|
||||
{
|
||||
XI.SelectEvents(window.Display, window.Handle, mask);
|
||||
XI.SelectEvents(window.Display, window.RootWindow, mask);
|
||||
UpdateDevices();
|
||||
}
|
||||
|
||||
|
@ -423,11 +434,16 @@ namespace OpenTK.Platform.X11
|
|||
using (new XLock(window.Display))
|
||||
{
|
||||
Functions.XIfEvent(window.Display, ref e, Predicate, new IntPtr(XIOpCode));
|
||||
if (e.type == ExitEvent)
|
||||
|
||||
if (e.type == XEventName.ClientMessage && e.ClientMessageEvent.ptr1 == ExitAtom)
|
||||
{
|
||||
return;
|
||||
Functions.XDestroyWindow(window.Display, window.Handle);
|
||||
window.Handle = IntPtr.Zero;
|
||||
break;
|
||||
}
|
||||
|
||||
if (e.type == XEventName.GenericEvent && e.GenericEvent.extension == XIOpCode)
|
||||
{
|
||||
IntPtr dummy;
|
||||
int x, y, dummy2;
|
||||
Functions.XQueryPointer(window.Display, window.RootWindow,
|
||||
|
@ -463,6 +479,8 @@ namespace OpenTK.Platform.X11
|
|||
}
|
||||
}
|
||||
}
|
||||
Debug.WriteLine("[X11] Exiting input event loop.");
|
||||
}
|
||||
|
||||
void ProcessRawEvent(ref XGenericEventCookie cookie)
|
||||
{
|
||||
|
@ -571,16 +589,29 @@ namespace OpenTK.Platform.X11
|
|||
static bool IsEventValid(IntPtr display, ref XEvent e, IntPtr arg)
|
||||
{
|
||||
bool valid = false;
|
||||
if ((long)e.GenericEventCookie.extension == arg.ToInt64())
|
||||
switch (e.type)
|
||||
{
|
||||
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawKeyPress;
|
||||
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawKeyRelease;
|
||||
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawMotion;
|
||||
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawButtonPress;
|
||||
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawButtonRelease;
|
||||
valid |= e.GenericEventCookie.evtype == (int)XIEventType.DeviceChanged;
|
||||
case XEventName.GenericEvent:
|
||||
{
|
||||
long extension = (long)e.GenericEventCookie.extension;
|
||||
valid =
|
||||
extension == arg.ToInt64() &&
|
||||
(e.GenericEventCookie.evtype == (int)XIEventType.RawKeyPress ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.RawKeyRelease ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.RawMotion ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.RawButtonPress ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.RawButtonRelease ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.DeviceChanged);
|
||||
valid |= extension == 0;
|
||||
break;
|
||||
}
|
||||
valid |= e.AnyEvent.type == ExitEvent;
|
||||
|
||||
case XEventName.ClientMessage:
|
||||
valid =
|
||||
e.ClientMessageEvent.ptr1 == ExitAtom;
|
||||
break;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
@ -592,6 +623,23 @@ namespace OpenTK.Platform.X11
|
|||
}
|
||||
}
|
||||
|
||||
void SendExitEvent()
|
||||
{
|
||||
// Send a ClientMessage event to unblock XIfEvent
|
||||
// and exit the input event loop.
|
||||
using (new XLock(API.DefaultDisplay))
|
||||
{
|
||||
XEvent ev = new XEvent();
|
||||
ev.type = XEventName.ClientMessage;
|
||||
ev.ClientMessageEvent.display = window.Display;
|
||||
ev.ClientMessageEvent.window = window.Handle;
|
||||
ev.ClientMessageEvent.format = 32;
|
||||
ev.ClientMessageEvent.ptr1 = ExitAtom;
|
||||
Functions.XSendEvent(API.DefaultDisplay, window.Handle, false, 0, ref ev);
|
||||
Functions.XFlush(API.DefaultDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
@ -606,17 +654,8 @@ namespace OpenTK.Platform.X11
|
|||
{
|
||||
if (!disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
using (new XLock(API.DefaultDisplay))
|
||||
{
|
||||
XEvent e = new XEvent();
|
||||
e.type = ExitEvent;
|
||||
Functions.XSendEvent(API.DefaultDisplay, window.Handle, false, IntPtr.Zero, ref e);
|
||||
Functions.XFlush(API.DefaultDisplay);
|
||||
}
|
||||
}
|
||||
disposed = true;
|
||||
SendExitEvent();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue