Ejemplo n.º 1
0
        public void Run(INativeWindowStartupInfo startupInfo)
        {
            GdiplusStartupInput gdiPlusStartupInput = GdiplusStartupInput.CreateV1();

            GdiPlusAPI.CheckStatus(GdiPlusAPI.GdiplusStartup(out var gdiPlusToken, ref gdiPlusStartupInput, out _));
            IntPtr hInstance = Win32API.GetModuleHandleW(null);

            var windowClass = new WNDCLASSEXW();

            windowClass.cbSize        = (uint)Marshal.SizeOf <WNDCLASSEXW>();
            windowClass.lpfnWndProc   = WindowProc;
            windowClass.hInstance     = hInstance;
            windowClass.lpszClassName = WindowClassName;
            var atom = Win32API.RegisterClassExW(ref windowClass);

            if (atom == 0)
            {
                throw new InvalidOperationException("Failed to register window class.");
            }

            try
            {
                const int CW_USEDEFAULT = unchecked ((int)0x80000000);
                IntPtr    hwnd          = Win32API.CreateWindowExW(
                    0,
                    WindowClassName,
                    startupInfo.Title,
                    Win32WindowStyle.WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT, CW_USEDEFAULT,
                    startupInfo.Width, startupInfo.Height,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    hInstance,
                    IntPtr.Zero
                    );

                if (hwnd == IntPtr.Zero)
                {
                    throw new InvalidOperationException("Failed to create a window.");
                }

                var window = new Win32Window(hwnd, startupInfo);
                windows.Add(hwnd, window);
                startupInfo.OnCreate(window);

                try
                {
                    Win32API.ShowWindow(hwnd, Win32ShowWindowCommand.SW_SHOWNORMAL);

                    MSG msg = new MSG();
                    int mRet;
                    while ((mRet = Win32API.GetMessageW(ref msg, IntPtr.Zero, 0, 0)) != 0)
                    {
                        if (mRet == -1)
                        {
                            throw new InvalidOperationException("Failed to retrieve a message.");
                        }

                        Win32API.TranslateMessage(ref msg);
                        Win32API.DispatchMessageW(ref msg);
                    }
                }
                finally
                {
                    // usually window will be destroyed before this point, unless error occurs
                    if (Win32API.DestroyWindow(hwnd) == 0)
                    {
                        // todo: log warning ?
                    }
                }
            }
            finally
            {
                if (Win32API.UnregisterClassW(WindowClassName, hInstance) == 0)
                {
                    // todo: log warning
                }

                // todo: use separate finally for GDI+
                GdiPlusAPI.GdiplusShutdown(gdiPlusToken);
            }
        }
Ejemplo n.º 2
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);
                }
            }
        }
Ejemplo n.º 3
0
 internal Win32Window(IntPtr windowHandle, INativeWindowStartupInfo startupInfo)
 {
     this.windowHandle = windowHandle;
     this.startupInfo  = startupInfo;
 }