internal void ProcessWindowEvent(XEvent *xevent, bool isWmProtocolsEvent) { ThrowIfNotThread(ParentThread); switch (xevent->type) { case VisibilityNotify: { HandleXVisibility(&xevent->xvisibility); break; } case DestroyNotify: { HandleXDestroyWindow(&xevent->xdestroywindow); break; } case ConfigureNotify: { HandleXConfigure(&xevent->xconfigure); break; } case CirculateNotify: { HandleXCirculate(&xevent->xcirculate); break; } case ClientMessage: { HandleXClientMessage(&xevent->xclient, isWmProtocolsEvent); break; } } }
public static extern IntPtr XNextEvent(IntPtr display, XEvent *xevent);
public static extern unsafe int Xutf8LookupString(IntPtr xic, XEvent *xevent, void *buffer, int num_bytes, out IntPtr keysym, out IntPtr status);
public static extern bool XFilterEvent(XEvent *xevent, IntPtr window);
internal void ProcessWindowEvent(XEvent *xevent) { ThrowIfNotThread(ParentThread); switch (xevent->type) { case Expose: { HandleXExpose(&xevent->xexpose); break; } case VisibilityNotify: { HandleXVisibility(&xevent->xvisibility); break; } case DestroyNotify: { HandleXDestroyWindow(&xevent->xdestroywindow); break; } case UnmapNotify: { HandleXUnmap(&xevent->xunmap); break; } case MapNotify: { HandleXMap(&xevent->xmap); break; } case ConfigureNotify: { HandleXConfigure(&xevent->xconfigure); break; } case CirculateNotify: { HandleXCirculate(&xevent->xcirculate); break; } case PropertyNotify: { HandleXProperty(&xevent->xproperty); break; } case ClientMessage: { HandleXClientMessage(&xevent->xclient); break; } } }
internal static void ForwardWindowEvent(XEvent *xevent, bool isWmProtocolsEvent) { IntPtr userData; var dispatchProvider = Xlib.XlibDispatchProvider.Instance; if (isWmProtocolsEvent && (xevent->xclient.data.l[0] == (IntPtr)(void *)dispatchProvider.WindowProviderCreateWindowAtom)) { // We allow the WindowProviderCreateWindowAtom message to be forwarded to the Window instance // for xevent->xany.window. This allows some delayed initialization to occur since most of the // fields in Window are lazy. if (Environment.Is64BitProcess) { var lowerBits = unchecked ((uint)xevent->xclient.data.l[2].ToInt64()); var upperBits = unchecked ((ulong)(uint)xevent->xclient.data.l[3].ToInt64()); userData = (IntPtr)((upperBits << 32) | lowerBits); } else { var bits = xevent->xclient.data.l[1].ToInt32(); userData = (IntPtr)bits; } _ = XChangeProperty( xevent->xany.display, xevent->xany.window, dispatchProvider.WindowWindowProviderAtom, dispatchProvider.SystemIntPtrAtom, format: 8, PropModeReplace, (byte *)&userData, nelements: IntPtr.Size ); } else { UIntPtr actualTypeReturn; int actualFormatReturn; UIntPtr nitemsReturn; UIntPtr bytesAfterReturn; IntPtr *propReturn; ThrowExternalExceptionIfFailed(nameof(XGetWindowProperty), XGetWindowProperty( xevent->xany.display, xevent->xany.window, dispatchProvider.WindowWindowProviderAtom, long_offset: IntPtr.Zero, long_length: (IntPtr)IntPtr.Size, delete: False, dispatchProvider.SystemIntPtrAtom, &actualTypeReturn, &actualFormatReturn, &nitemsReturn, &bytesAfterReturn, (byte **)&propReturn )); userData = *propReturn; } XlibWindowProvider windowProvider = null !; Dictionary <UIntPtr, XlibWindow>?windows = null; var forwardMessage = false; XlibWindow?window = null; if (userData != IntPtr.Zero) { windowProvider = (XlibWindowProvider)GCHandle.FromIntPtr(userData).Target !; windows = windowProvider._windows.Value; forwardMessage = (windows?.TryGetValue(xevent->xany.window, out window)).GetValueOrDefault(); } if (forwardMessage) { Assert(windows != null, Resources.ArgumentNullExceptionMessage, nameof(windows)); Assert(window != null, Resources.ArgumentNullExceptionMessage, nameof(window)); window.ProcessWindowEvent(xevent, isWmProtocolsEvent); if (isWmProtocolsEvent && (xevent->xclient.data.l[0] == (IntPtr)(void *)dispatchProvider.WmDeleteWindowAtom)) { // We forward the WM_DELETE_WINDOW message to the corresponding Window instance // so that it can still be properly disposed of in the scenario that the // xevent->xany.window was destroyed externally. _ = RemoveWindow(windows, xevent->xany.display, xevent->xany.window, dispatchProvider); } } }
internal static void ForwardWindowEvent(XEvent *xevent) { nint userData; GCHandle gcHandle; XlibWindowService windowService; Dictionary <nuint, XlibWindow>?windows; XlibWindow?window; bool forwardMessage; var dispatchService = XlibDispatchService.Instance; if ((xevent->type == ClientMessage) && (xevent->xclient.format == 32) && ((xevent->xclient.message_type == dispatchService.GetAtom(_TERRAFX_CREATE_WINDOW)) || (xevent->xclient.message_type == dispatchService.GetAtom(_TERRAFX_DISPOSE_WINDOW)))) { // We allow the create and dispose message to be forwarded to the Window instance for xevent->xany.window. // This allows some delayed initialization to occur since most of the fields in Window are lazy. userData = Environment.Is64BitProcess ? (xevent->xclient.data.l[1] << 32) | unchecked ((nint)(uint)xevent->xclient.data.l[0]) : xevent->xclient.data.l[0]; // Unlike the WindowService GCHandle, the Window GCHandle is short lived and // we want to free it after we add the relevant entries to the window map. gcHandle = GCHandle.FromIntPtr(userData); { window = (XlibWindow)gcHandle.Target !; windowService = window.WindowService; windows = windowService._windows.Value !; } gcHandle.Free(); if (xevent->xclient.message_type == dispatchService.GetAtom(_TERRAFX_CREATE_WINDOW)) { if (windows is null) { windows = new Dictionary <nuint, XlibWindow>(capacity: 4); windowService._windows.Value = windows; } windows.Add(xevent->xany.window, window); // We then want to ensure the window service is registered as a property for fast // subsequent lookups. This proocess also allows everything to be lazily initialized. gcHandle = windowService.NativeHandle; userData = GCHandle.ToIntPtr(gcHandle); _ = XChangeProperty( xevent->xany.display, xevent->xany.window, dispatchService.GetAtom(_TERRAFX_WINDOWSERVICE), dispatchService.GetAtom(_TERRAFX_NATIVE_INT), 8, PropModeReplace, (byte *)&userData, sizeof(nint) ); } else { Assert(AssertionsEnabled && (xevent->xclient.message_type == dispatchService.GetAtom(_TERRAFX_DISPOSE_WINDOW))); _ = RemoveWindow(windows, xevent->xany.display, xevent->xany.window, dispatchService); } forwardMessage = true; } else { nuint actualType; int actualFormat; nuint itemCount; nuint bytesRemaining; nint *pUserData; // We don't check the result as there are various cases where this might fail // For example, if the property doesn't exist or has already been deleted _ = XGetWindowProperty( xevent->xany.display, xevent->xany.window, dispatchService.GetAtom(_TERRAFX_WINDOWSERVICE), 0, sizeof(nint) / sizeof(int), False, dispatchService.GetAtom(_TERRAFX_NATIVE_INT), &actualType, &actualFormat, &itemCount, &bytesRemaining, (byte **)&pUserData ); if ((actualType == dispatchService.GetAtom(_TERRAFX_NATIVE_INT)) && (actualFormat == 8) && (itemCount == SizeOf <nuint>()) && (bytesRemaining == 0)) { userData = pUserData[0]; gcHandle = GCHandle.FromIntPtr(userData); windowService = (XlibWindowService)gcHandle.Target !; windows = windowService._windows.Value !; forwardMessage = windows.TryGetValue(xevent->xany.window, out window); } else { windows = null; window = null; forwardMessage = false; } } if (forwardMessage) { AssertNotNull(windows); AssertNotNull(window); window.ProcessWindowEvent(xevent); if (xevent->type == DestroyNotify) { _ = RemoveWindow(windows, xevent->xany.display, xevent->xany.window, dispatchService); } } }
public static extern int XPeekIfEvent( [In] Display *display, [Out] XEvent *event_return, [In] predicate predicate, [In] XPointer arg );
public static extern void XPeekEvent( [In] Display *display, [Out] XEvent *event_Return );