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); } } }
public static X11Canvas CreateForDrawable( IntPtr display, int screenNum, X11ObjectCache objectCache, IntPtr visual, ulong colormap, IntPtr pictFormatPtr, ulong drawableId ) { const XRenderPictureAttributeMask attrMask = XRenderPictureAttributeMask.CPPolyEdge | XRenderPictureAttributeMask.CPPolyMode; XRenderPictureAttributes attr = new XRenderPictureAttributes { poly_edge = XRenderPolyEdge.Smooth, poly_mode = XRenderPolyMode.Imprecise }; ulong pictureId = LibXRender.XRenderCreatePicture ( display, drawableId, pictFormatPtr, attrMask, ref attr ); IntPtr xftDraw = IntPtr.Zero; X11Canvas canvas = null; try { xftDraw = LibXft.XftDrawCreate(display, drawableId, visual, colormap); canvas = new X11Canvas(display, screenNum, objectCache, visual, colormap, pictFormatPtr, drawableId, pictureId, xftDraw); xftDraw = IntPtr.Zero; } finally { if (canvas == null) { if (xftDraw != IntPtr.Zero) { LibXft.XftDrawDestroy(xftDraw); } LibXRender.XRenderFreePicture(display, pictureId); } } return(canvas); }
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); } } }
internal X11Canvas CreateCanvas(ulong drawableId) { return(X11Canvas.CreateForDrawable(display, screen, objectCache, visual, colorMap, pictFormatPtr, drawableId)); }