Beispiel #1
0
            public void CopyToImage(X11Image image)
            {
                if (image.Height != height || image.Width != width)
                {
                    throw new InvalidOperationException($"Source size ({width} x {height}) does not match image size ({image.Width} x {image.Height}).");
                }

                using (X11Bitmap xBitmap = X11Bitmap.Create(image.Display, image.Visual, width, height))
                {
                    if (pixelFormat == PixelFormat.RGBA_32)
                    {
                        PixelConverter.Convert_RGBA_32BE_To_PARGB_32(dataPtr, stride, xBitmap.ImageData, 4 * width, width, height);
                    }
                    else if (pixelFormat == PixelFormat.RGB_24)
                    {
                        PixelConverter.Convert_RGB_24BE_To_ARGB_32(dataPtr, stride, xBitmap.ImageData, 4 * width, width, height);
                    }
                    else
                    {
                        throw new InvalidOperationException($"Unexpected pixel format: {pixelFormat}.");
                    }

                    var gcValues = new XGCValues();
                    var gc       = LibX11.XCreateGC(image.Display, image.PixmapId, 0, ref gcValues);
                    try
                    {
                        LibX11.XPutImage(image.Display, image.PixmapId, gc, xBitmap.XImage, 0, 0, 0, 0, (uint)width, (uint)height);
                    }
                    finally
                    {
                        LibX11.XFreeGC(image.Display, gc);
                    }
                }
            }
Beispiel #2
0
        private void FillEllipseXLib(Color color, int x, int y, int width, int height)
        {
            var gcValues = new XGCValues();

            gcValues.foreground = ToPArgb(color);

            var gcValueMask = XGCValueMask.GCForeground;

            var gc = LibX11.XCreateGC(display, drawableId, gcValueMask, ref gcValues);

            try
            {
                if (clipRectangles != null)
                {
                    LibX11.XSetClipRectangles(display, gc, 0, 0, clipRectangles, clipRectangles.Length, 0);
                }

                LibX11.XDrawArc(display, drawableId, gc, x, y, (uint)width - 1, (uint)height - 1, 0, 360 * 64);
                LibX11.XFillArc(display, drawableId, gc, x, y, (uint)width - 1, (uint)height - 1, 0, 360 * 64);
            }
            finally
            {
                LibX11.XFreeGC(display, gc);
            }
        }
Beispiel #3
0
        public static X11Graphics Create(IntPtr display)
        {
            int   defaultScreen     = LibX11.XDefaultScreen(display);
            ulong defaultRootWindow = LibX11.XDefaultRootWindow(display);

            //todo: is is safe to keep pictFormatPtr after reading it into XRenderPictFormat
            IntPtr pictFormatPtr = LibXRender.XRenderFindStandardFormat(display, StandardPictFormat.PictStandardARGB32);

            if (pictFormatPtr == IntPtr.Zero)
            {
                throw new InvalidOperationException("Display does not support 32-bit ARGB.");
            }

            XRenderPictFormat pictFormat = Marshal.PtrToStructure <XRenderPictFormat>(pictFormatPtr);

            int status = LibX11.XMatchVisualInfo
                         (
                display,
                defaultScreen,
                pictFormat.depth,
                VisualClass.TrueColor,
                out XVisualInfo visualInfo
                         );

            if (status == 0)
            {
                throw new InvalidOperationException($"TrueColor visual with depth {pictFormat.depth} does not exist.");
            }

            ulong colorMap = LibX11.XCreateColormap(display, defaultRootWindow, visualInfo.visual, CreateColormapOption.AllocNone);

            return(new X11Graphics(display, defaultScreen, defaultRootWindow, visualInfo.visual, colorMap, pictFormat, pictFormatPtr));
        }
Beispiel #4
0
        private void Run()
        {
            bool stopped = false;

            while (!stopped)
            {
                LibX11.XNextEvent(display, out XEvent evt);
                // todo: log and handle exceptions
                if (evt.type == XEventType.SelectionClear)
                {
                    HandleSelectionClear(evt.SelectionClearEvent);
                }
                else if (evt.type == XEventType.SelectionRequest)
                {
                    HandleSelectionRequest(evt.SelectionRequestEvent);
                }
                else if (evt.type == XEventType.SelectionNotify)
                {
                    HandleSelectionNotify(evt.SelectionEvent);
                }
                else if (evt.type == XEventType.ClientMessage)
                {
                    if (evt.ClientMessageEvent.message_type == XA_NWINDOWS_CLIPBOARD_STOP)
                    {
                        stopped = true;
                    }
                }
            }

            LibX11.XCloseDisplay(display);
        }
Beispiel #5
0
        private void WithExtraCanvas(Rectangle rect, Action <X11Canvas> action)
        {
            using (X11Image tempImage = X11Image.Create(display, visual, drawableId, rect.Width, rect.Height))
            {
                var gcValues = new XGCValues();
                gcValues.foreground = ToPArgb(Color.Transparent);
                var gcValueMask = XGCValueMask.GCForeground;
                var gc          = LibX11.XCreateGC(display, drawableId, gcValueMask, ref gcValues);
                try
                {
                    // todo: check int -> uint conversion
                    LibX11.XFillRectangle(display, tempImage.PixmapId, gc, 0, 0, (uint)rect.Width, (uint)rect.Height);
                }
                finally
                {
                    LibX11.XFreeGC(display, gc);
                }

                using (var innerCanvas = X11Canvas.CreateForDrawable(display, screenNum, objectCache, visual, colormap, pictFormatPtr, tempImage.PixmapId))
                {
                    action(innerCanvas);
                    DrawImage(tempImage, rect.X + origin.X, rect.Y + origin.Y);
                }
            }
        }
Beispiel #6
0
        public void SetTitle(string title)
        {
            byte[] windowTitleASCII = Encoding.ASCII.GetBytes(title);
            LibX11.XChangeProperty(
                display,
                windowId,
                LibX11.XInternAtom(display, "WM_NAME", 0),
                LibX11.XInternAtom(display, "STRING", 0),
                XChangePropertyFormat.Byte,
                XChangePropertyMode.PropModeReplace,
                windowTitleASCII,
                windowTitleASCII.Length
                );

            byte[] windowTitleUTF8 = Encoding.UTF8.GetBytes(title);
            LibX11.XChangeProperty(
                display,
                windowId,
                LibX11.XInternAtom(display, "_NET_WM_NAME", 0),
                LibX11.XInternAtom(display, "UTF8_STRING", 0),
                XChangePropertyFormat.Byte,
                XChangePropertyMode.PropModeReplace,
                windowTitleUTF8,
                windowTitleUTF8.Length
                );
        }
Beispiel #7
0
        private void DrawPathWithXLibDirectly(Color color, int width, Point[] points)
        {
            var gcValues = new XGCValues();

            gcValues.cap_style  = X11CapStyle.CapRound;
            gcValues.join_style = X11JoinStyle.JoinRound;
            gcValues.foreground = ToPArgb(color);
            gcValues.line_width = width;

            var gcValueMask = XGCValueMask.GCCapStyle | XGCValueMask.GCForeground | XGCValueMask.GCJoinStyle | XGCValueMask.GCLineWidth;

            var gc = LibX11.XCreateGC(display, drawableId, gcValueMask, ref gcValues);

            try
            {
                if (clipRectangles != null)
                {
                    LibX11.XSetClipRectangles(display, gc, 0, 0, clipRectangles, clipRectangles.Length, 0);
                }

                XPoint[] xPoints = new XPoint[points.Length];
                for (int i = 0; i < points.Length; i++)
                {
                    var point = points[i];
                    xPoints[i] = new XPoint(point.X, point.Y);
                }

                LibX11.XDrawLines(display, drawableId, gc, xPoints, xPoints.Length, X11CoordinateMode.CoordModeOrigin);
            }
            finally
            {
                LibX11.XFreeGC(display, gc);
            }
        }
Beispiel #8
0
        private bool ConvertOwnSelection(ulong requestor, ulong selection, ulong targetType, ulong targetProperty)
        {
            if (selection != XA_CLIPBOARD)
            {
                return(false);
            }

            string textToConvert;

            lock (selectionConversionLock)
            {
                textToConvert = bufferText;
                if (textToConvert == null)
                {
                    return(false);
                }
            }

            if (targetType == XA_TARGETS)
            {
                ulong[] targets = { XA_TARGETS, XA_UTF8_STRING };

                LibX11.XChangeProperty
                (
                    display,
                    requestor,
                    targetProperty,
                    XA_ATOM,
                    XChangePropertyFormat.Atom,
                    XChangePropertyMode.PropModeReplace,
                    targets,
                    targets.Length
                );

                return(true);
            }

            if (targetType == XA_UTF8_STRING)
            {
                byte[] text = Encoding.UTF8.GetBytes(textToConvert);
                LibX11.XChangeProperty
                (
                    display,
                    requestor,
                    targetProperty,
                    XA_UTF8_STRING,
                    XChangePropertyFormat.Byte,
                    XChangePropertyMode.PropModeReplace,
                    text,
                    text.Length
                );

                return(true);
            }

            return(false);
        }
Beispiel #9
0
 public void PutText(string text)
 {
     lock (selectionConversionLock)
     {
         bufferText = text;
         LibX11.XSetSelectionOwner(display, XA_CLIPBOARD, windowId, 0);
         LibX11.XFlush(display);
     }
 }
Beispiel #10
0
        public static X11Clipboard Create()
        {
            IntPtr display  = IntPtr.Zero;
            ulong  windowId = 0;

            try
            {
                display = LibX11.XOpenDisplay(null);
                if (display == IntPtr.Zero)
                {
                    throw new InvalidOperationException("Cannot open display.");
                }

                ulong  rootWindow    = LibX11.XDefaultRootWindow(display);
                int    defaultScreen = LibX11.XDefaultScreen(display);
                IntPtr defaultVisual = LibX11.XDefaultVisual(display, defaultScreen);

                XSetWindowAttributes attr = new XSetWindowAttributes();
                windowId = LibX11.XCreateWindow
                           (
                    display,
                    rootWindow,
                    0, 0,
                    10, 10,
                    0,
                    0,
                    WindowClass.InputOnly,
                    defaultVisual,
                    0,
                    ref attr
                           );

                LibX11.XFlush(display);

                X11Clipboard clipboard = new X11Clipboard(display, windowId);
                clipboard.Start();
                windowId = 0;
                display  = IntPtr.Zero;
                return(clipboard);
            }
            finally
            {
                if (windowId != 0)
                {
                    LibX11.XDestroyWindow(display, windowId);
                    LibX11.XFlush(display);
                }

                if (display != IntPtr.Zero)
                {
                    LibX11.XCloseDisplay(display);
                }
            }
        }
Beispiel #11
0
        public void Stop()
        {
            lock (selectionConversionLock)
            {
                var message = XEvent.CreateClientMessage(windowId, XA_NWINDOWS_CLIPBOARD_STOP);
                LibX11.XSendEvent(display, windowId, 0, XEventMask.NoEventMask, ref message);
                LibX11.XFlush(display);
            }

            thread.Join(TimeSpan.FromSeconds(30));
        }
Beispiel #12
0
        private X11Clipboard(IntPtr display, ulong windowId)
        {
            this.display  = display;
            this.windowId = windowId;

            thread              = new Thread(Run);
            thread.Name         = nameof(X11Clipboard);
            thread.IsBackground = true;

            XA_ATOM        = LibX11.XInternAtom(display, "ATOM", 0);
            XA_CLIPBOARD   = LibX11.XInternAtom(display, "CLIPBOARD", 0);
            XA_TARGETS     = LibX11.XInternAtom(display, "TARGETS", 0);
            XA_UTF8_STRING = LibX11.XInternAtom(display, "UTF8_STRING", 0);
            XA_NWINDOWS_CONVERTED_CLIPBOARD = LibX11.XInternAtom(display, "NWINDOWS_CONVERTED_CLIPBOARD", 0);
            XA_NWINDOWS_CLIPBOARD_STOP      = LibX11.XInternAtom(display, "NWINDOWS_CLIPBOARD_STOP", 0);
        }
Beispiel #13
0
        public void Init()
        {
            LibX11.XInitThreads();
            display = LibX11.XOpenDisplay(null);
            if (display == IntPtr.Zero)
            {
                throw new InvalidOperationException("Cannot open display.");
            }

            WM_PROTOCOLS               = LibX11.XInternAtom(display, "WM_PROTOCOLS", 0);
            WM_DELETE_WINDOW           = LibX11.XInternAtom(display, "WM_DELETE_WINDOW", 0);
            XA_NWINDOWS_PAINT_COMPLETE = LibX11.XInternAtom(display, "NWINDOWS_PAINT_COMPLETE", 0);

            graphics   = X11Graphics.Create(display);
            imageCodec = new GdkPixBufImageCodec(display, graphics.Visual, graphics.RootWindow);
            clipboard  = X11Clipboard.Create();
        }
Beispiel #14
0
        public static X11Bitmap Create(IntPtr display, IntPtr visual, int width, int height)
        {
            if (width < 0 || height < 0)
            {
                throw new ArgumentException($"Image dimensions cannot be negative ({width} x {height}).");
            }

            IntPtr imageData = Marshal.AllocHGlobal(4 * width * height);
            IntPtr xImage    = IntPtr.Zero;

            try
            {
                xImage = LibX11.XCreateImage
                         (
                    display,
                    visual,
                    X11Application.RequiredColorDepth,
                    XImageFormat.ZPixmap,
                    0,
                    imageData,
                    (uint)width,
                    (uint)height,
                    X11Application.RequiredColorDepth,
                    width * 4
                         );

                X11Bitmap bitmap = new X11Bitmap(xImage, imageData);

                xImage    = IntPtr.Zero;
                imageData = IntPtr.Zero;

                return(bitmap);
            }
            finally
            {
                if (xImage != IntPtr.Zero)
                {
                    LibX11.XDestroyImage(xImage);
                }
                else if (imageData != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(imageData);
                }
            }
        }
Beispiel #15
0
        public static X11Image Create(IntPtr display, IntPtr visual, ulong drawable, int width, int height)
        {
            if (width < 0 || height < 0)
            {
                throw new ArgumentException($"Image dimensions cannot be negative ({width} x {height}).");
            }

            // todo: handle zero width / height

            ulong pixmapId = LibX11.XCreatePixmap(
                display,
                drawable,
                (uint)width,
                (uint)height,
                X11Application.RequiredColorDepth
                );

            return(new X11Image(display, visual, pixmapId, width, height));
        }
Beispiel #16
0
        private void HandleSelectionRequest(XSelectionRequestEvent evt)
        {
            if (evt.owner != windowId)
            {
                return;
            }

            var targetProperty = evt.property;

            if (targetProperty == 0)
            {
                // Owners receiving ConvertSelection requests with a property argument of None are talking to an obsolete client.
                // They should choose the target atom as the property name to be used for the reply.
                targetProperty = evt.target;
            }

            bool dataSent = ConvertOwnSelection(evt.requestor, evt.selection, evt.target, targetProperty);
            var  response = XEvent.CreateSelectionNotify(evt.requestor, evt.selection, evt.target, dataSent ? targetProperty : 0, evt.time);

            LibX11.XSendEvent(display, evt.requestor, 0, XEventMask.NoEventMask, ref response);
        }
Beispiel #17
0
        public void CopyFromBitmap(Rectangle imageArea, IntPtr bitmap, int bitmapStride)
        {
            // todo: create separate validation ?
            NativeBitmapSourceParameterValidation.CopyToBitmap(this, imageArea, bitmap, bitmapStride, out _);

            using (X11Bitmap xBitmap = X11Bitmap.Create(Display, Visual, imageArea.Width, imageArea.Height))
            {
                PixelConverter.Convert_ARGB_32_To_PARGB_32(bitmap, bitmapStride, xBitmap.ImageData, imageArea.Width * 4, imageArea.Width, imageArea.Height);

                var gcValues = new XGCValues();
                var gc       = LibX11.XCreateGC(Display, PixmapId, 0, ref gcValues);
                try
                {
                    LibX11.XPutImage(Display, PixmapId, gc, xBitmap.XImage, 0, 0, imageArea.X, imageArea.Y, (uint)imageArea.Width, (uint)imageArea.Height);
                }
                finally
                {
                    LibX11.XFreeGC(Display, gc);
                }
            }
        }
Beispiel #18
0
        public bool TryGetText(out string text)
        {
            lock (selectionConversionLock)
            {
                selectionConvertedEvent.Reset();

                // todo: review usage of XLib under lock

                LibX11.XConvertSelection
                (
                    display,
                    XA_CLIPBOARD,
                    XA_UTF8_STRING,
                    XA_NWINDOWS_CONVERTED_CLIPBOARD,
                    windowId,
                    0 /* CurrentTime */
                );

                LibX11.XFlush(display);
            }

            if (!selectionConvertedEvent.WaitOne(OperationTimeout))
            {
                text = null;
                return(false);
            }

            lock (selectionConversionLock)
            {
                if (convertedText == null)
                {
                    text = null;
                    return(false);
                }

                text          = convertedText;
                convertedText = null;
                return(true);
            }
        }
Beispiel #19
0
        public static bool IsAvailable()
        {
            try
            {
                LibX11.XInitThreads();
                IntPtr display = LibX11.XOpenDisplay(null);
                if (display == IntPtr.Zero)
                {
                    return(false);
                }

                LibX11.XCloseDisplay(display);
                return(true);
            }
            catch (DllNotFoundException)
            {
                return(false);
            }
            catch (EntryPointNotFoundException)
            {
                return(false);
            }
        }
Beispiel #20
0
        public void CopyToBitmap(Rectangle imageArea, IntPtr bitmap, int bitmapStride)
        {
            NativeBitmapSourceParameterValidation.CopyToBitmap(this, imageArea, bitmap, bitmapStride, out _);

            using (X11Bitmap xBitmap = X11Bitmap.Create(Display, Visual, imageArea.Width, imageArea.Height))
            {
                LibX11.XGetSubImage(
                    Display,
                    PixmapId,
                    imageArea.X,
                    imageArea.Y,
                    (uint)imageArea.Width,
                    (uint)imageArea.Height,
                    ulong.MaxValue,
                    XImageFormat.ZPixmap,
                    xBitmap.XImage,
                    0,
                    0
                    );

                PixelConverter.Convert_PARGB_32_To_ARGB_32(xBitmap.ImageData, imageArea.Width * 4, bitmap, bitmapStride, imageArea.Width, imageArea.Height);
            }
        }
Beispiel #21
0
        private static byte[] ReadWindowProperty(IntPtr display, ulong windowId, ulong property)
        {
            const long smallPropertyLength = 1024;

            LibX11.XGetWindowProperty
            (
                display,
                windowId,
                property,
                0,
                smallPropertyLength,
                1,
                0 /* AnyPropertyType */,
                out ulong type,
                out int format,
                out ulong nItems,
                out ulong bytes_after_return,
                out IntPtr bufferPtr
            );

            if (bytes_after_return != 0)
            {
                if (bufferPtr != IntPtr.Zero)
                {
                    LibX11.XFree(bufferPtr);
                }

                ulong actualLength = bytes_after_return + 4 * smallPropertyLength;

                if (bytes_after_return > int.MaxValue || actualLength > int.MaxValue)
                {
                    throw new InvalidOperationException
                          (
                              $"Property {property} is too long: {nameof(bytes_after_return)} = {bytes_after_return}."
                          );
                }

                LibX11.XGetWindowProperty
                (
                    display,
                    windowId,
                    property,
                    0,
                    (long)(actualLength + 3) / 4,
                    1,
                    0 /* AnyPropertyType */,
                    out type,
                    out format,
                    out nItems,
                    out bytes_after_return,
                    out bufferPtr
                );
            }

            try
            {
                if ((nItems != 0) && (format <= 0 || format % 8 != 0))
                {
                    throw new InvalidOperationException($"{nameof(LibX11.XGetWindowProperty)} returned an invalid format: {format}.");
                }

                int    chunkSize = (int)nItems * format / 8;
                byte[] res       = new byte [chunkSize];
                if (chunkSize != 0)
                {
                    if (bufferPtr == IntPtr.Zero)
                    {
                        throw new InvalidOperationException($"{nameof(LibX11.XGetWindowProperty)} returned an empty buffer for a non-empty value.");
                    }

                    Marshal.Copy(bufferPtr, res, 0, chunkSize);
                }

                return(res);
            }
            finally
            {
                if (bufferPtr != IntPtr.Zero)
                {
                    LibX11.XFree(bufferPtr);
                }
            }
        }
Beispiel #22
0
 public void Dispose()
 {
     // todo: use finalizer?
     LibX11.XFreePixmap(Display, PixmapId);
 }
Beispiel #23
0
        public void Run(INativeWindowStartupInfo window)
        {
            XSetWindowAttributes attr = new XSetWindowAttributes();

            attr.border_pixel = 0;
            attr.bit_gravity  = 1 /*NorthWestGravity	*/;
            attr.event_mask   = XEventMask.ExposureMask |
                                XEventMask.ButtonPressMask |
                                XEventMask.ButtonReleaseMask |
                                XEventMask.FocusChangeMask |
                                XEventMask.KeyPressMask |
                                XEventMask.KeyReleaseMask |
                                XEventMask.PointerMotionMask |
                                XEventMask.StructureNotifyMask;
            attr.colormap = graphics.ColorMap;

            ulong windowId = LibX11.XCreateWindow
                             (
                display,
                graphics.RootWindow,
                0, 0,
                (uint)window.Width, (uint)window.Height,
                1,
                graphics.PictFormat.depth,
                WindowClass.InputOutput,
                graphics.Visual,
                XSetWindowAttributeMask.CWBorderPixel |
                XSetWindowAttributeMask.CWBitGravity |
                XSetWindowAttributeMask.CWEventMask |
                XSetWindowAttributeMask.CWColormap,
                ref attr
                             );

            X11Window nativeWindow = new X11Window(display, windowId, Invalidate);

            window.OnCreate(nativeWindow);
            nativeWindow.SetTitle(window.Title);

            var protocols = new[] { WM_DELETE_WINDOW };

            LibX11.XSetWMProtocols(display, windowId, protocols, protocols.Length);

            LibX11.XMapWindow(display, windowId);
            LibX11.XFlush(display);

            byte[] textBuffer = new byte[32];
            bool   autoRepeat = false;

            bool windowClosed = false;

            while (!windowClosed)
            {
                LibX11.XNextEvent(display, out XEvent evt);
                if (evt.type == XEventType.Expose)
                {
                    var rect = new Rectangle(evt.ExposeEvent.x, evt.ExposeEvent.y, evt.ExposeEvent.width, evt.ExposeEvent.height);
                    Invalidate(rect);
                }
                else if (evt.type == XEventType.MotionNotify)
                {
                    window.OnMouseMove(new Point(evt.MotionEvent.x, evt.MotionEvent.y));
                }
                else if (evt.type == XEventType.ConfigureNotify)
                {
                    Size clientArea = new Size(evt.ConfigureEvent.width, evt.ConfigureEvent.height);
                    window.OnResize(clientArea);
                }
                else if (evt.type == XEventType.ButtonPress)
                {
                    window.OnMouseButtonDown(
                        GetMouseButton(evt.ButtonEvent.button),
                        new Point(evt.ButtonEvent.x, evt.ButtonEvent.y),
                        GetModifierKey(evt.ButtonEvent.state)
                        );
                }
                else if (evt.type == XEventType.ButtonRelease)
                {
                    window.OnMouseButtonUp(
                        GetMouseButton(evt.ButtonEvent.button),
                        new Point(evt.ButtonEvent.x, evt.ButtonEvent.y)
                        );
                }
                else if (evt.type == XEventType.KeyPress)
                {
                    // XLookupString returns no more than the requested number of characters, but it also writes a zero-byte after them
                    int charCount = LibX11.XLookupString(ref evt.KeyEvent, textBuffer, textBuffer.Length - 1, out var keySym, IntPtr.Zero);
                    var keyCode   = X11KeyMap.GetKeyCode(keySym);
                    if (keyCode == NKeyCode.Unknown)
                    {
                        keySym  = LibX11.XLookupKeysym(ref evt.KeyEvent, 0);
                        keyCode = X11KeyMap.GetKeyCode(keySym);
                    }

                    window.OnKeyDown(keyCode, GetModifierKey(evt.KeyEvent.state), autoRepeat);
                    autoRepeat = false;

                    if (charCount > 0)
                    {
                        string        text = Encoding.UTF8.GetString(textBuffer, 0, charCount);
                        StringBuilder sb   = new StringBuilder(text.Length);
                        foreach (char c in text)
                        {
                            if (!char.IsControl(c))
                            {
                                sb.Append(c);
                            }
                        }

                        if (sb.Length > 0)
                        {
                            window.OnTextInput(sb.ToString());
                        }
                    }
                }
                else if (evt.type == XEventType.KeyRelease)
                {
                    if (LibX11.XPending(display) > 0)
                    {
                        LibX11.XPeekEvent(display, out XEvent nextEvent);
                        autoRepeat =
                            nextEvent.type == XEventType.KeyPress &&
                            nextEvent.KeyEvent.time == evt.KeyEvent.time &&
                            nextEvent.KeyEvent.keycode == evt.KeyEvent.keycode;
                    }

                    if (!autoRepeat)
                    {
                        // XLookupString returns no more than the requested number of characters, but it also writes a zero-byte after them
                        LibX11.XLookupString(ref evt.KeyEvent, textBuffer, textBuffer.Length - 1, out var keySym, IntPtr.Zero);
                        var keyCode = X11KeyMap.GetKeyCode(keySym);
                        if (keyCode == NKeyCode.Unknown)
                        {
                            keySym  = LibX11.XLookupKeysym(ref evt.KeyEvent, 0);
                            keyCode = X11KeyMap.GetKeyCode(keySym);
                        }

                        window.OnKeyUp(keyCode);
                    }
                }
                else if (evt.type == XEventType.FocusIn)
                {
                    if (IsWindowActivationEvent(evt.FocusChangeEvent.mode, evt.FocusChangeEvent.detail))
                    {
                        window.OnActivated();
                    }
                }
                else if (evt.type == XEventType.FocusOut)
                {
                    if (IsWindowActivationEvent(evt.FocusChangeEvent.mode, evt.FocusChangeEvent.detail))
                    {
                        window.OnDeactivated();
                    }
                }
                else if (evt.type == XEventType.ClientMessage)
                {
                    var cevt = evt.ClientMessageEvent;
                    if (cevt.message_type == WM_PROTOCOLS && cevt.data0 == WM_DELETE_WINDOW)
                    {
                        windowClosed = true;
                    }
                    else if (cevt.message_type == XA_NWINDOWS_PAINT_COMPLETE)
                    {
                        paintQueued = false;
                    }
                }

                if (invalidatedArea != null && !paintQueued)
                {
                    Rectangle area = invalidatedArea.Value;
                    invalidatedArea = null;

                    using (X11Image image = graphics.CreateImage(area.Width, area.Height))
                    {
                        using (X11Canvas canvas = graphics.CreateCanvas(image.PixmapId))
                        {
                            canvas.SetOrigin(area.X, area.Y);
                            window.OnPaint(canvas, area);
                        }

                        using (X11Canvas canvas = graphics.CreateCanvas(windowId))
                        {
                            canvas.DrawImage(image, area.X, area.Y);
                        }
                    }

                    paintQueued = true;
                    var message = XEvent.CreateClientMessage(windowId, XA_NWINDOWS_PAINT_COMPLETE);
                    LibX11.XSendEvent(display, windowId, 0, XEventMask.NoEventMask, ref message);
                }
            }
        }
Beispiel #24
0
 public void Dispose()
 {
     // todo: use finalizer?
     LibX11.XDestroyImage(XImage);
 }
Beispiel #25
0
 public void Dispose()
 {
     clipboard.Stop();
     graphics.Dispose();
     LibX11.XCloseDisplay(display);
 }