mirror of
				https://gitee.com/csharpui/CPF.git
				synced 2025-11-01 00:46:56 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			1801 lines
		
	
	
		
			76 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1801 lines
		
	
	
		
			76 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | ||
| using System.Collections;
 | ||
| using System.Collections.Generic;
 | ||
| using System.Text;
 | ||
| using CPF.Controls;
 | ||
| using CPF.Drawing;
 | ||
| using CPF.Platform;
 | ||
| using System.Linq;
 | ||
| using System.Runtime.InteropServices;
 | ||
| using System.Threading;
 | ||
| using CPF.Input;
 | ||
| using static CPF.Linux.XLib;
 | ||
| using CPF.OpenGL;
 | ||
| 
 | ||
| namespace CPF.Linux
 | ||
| {
 | ||
|     public class XWindow : IDisposable
 | ||
|     {
 | ||
|         internal static object XlibLock = new object();
 | ||
|         public XWindow()
 | ||
|         {
 | ||
|             OnCreateWindw();
 | ||
|             LinuxPlatform.Platform.windows.Add(Handle, this);
 | ||
|         }
 | ||
| 
 | ||
|         protected virtual void OnCreateWindw()
 | ||
|         {
 | ||
|             Handle = XCreateSimpleWindow(LinuxPlatform.Platform.Display, LinuxPlatform.Platform.Info.DefaultRootWindow,
 | ||
|                 0, 0, 1, 1, 0, IntPtr.Zero, IntPtr.Zero);
 | ||
|         }
 | ||
| 
 | ||
|         public IntPtr Handle { get; protected set; }
 | ||
| 
 | ||
|         public OnEventHandler EventAction { get; set; }
 | ||
|         public virtual void OnEvent(ref XEvent e)
 | ||
|         {
 | ||
|             if (EventAction != null)
 | ||
|             {
 | ||
|                 EventAction(ref e);
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         #region IDisposable Support
 | ||
|         private bool disposedValue = false; // 要检测冗余调用
 | ||
| 
 | ||
|         protected virtual void Dispose(bool disposing)
 | ||
|         {
 | ||
|             if (!disposedValue)
 | ||
|             {
 | ||
|                 if (disposing)
 | ||
|                 {
 | ||
|                     // TODO: 释放托管状态(托管对象)。
 | ||
|                 }
 | ||
|                 if (Handle != IntPtr.Zero)
 | ||
|                 {
 | ||
|                     XDestroyWindow(LinuxPlatform.Platform.Display, Handle);
 | ||
|                     LinuxPlatform.Platform.windows.Remove(Handle);
 | ||
|                     Handle = IntPtr.Zero;
 | ||
|                 }
 | ||
| 
 | ||
|                 disposedValue = true;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
 | ||
|         ~XWindow()
 | ||
|         {
 | ||
|             // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
 | ||
|             Dispose(false);
 | ||
|         }
 | ||
| 
 | ||
|         // 添加此代码以正确实现可处置模式。
 | ||
|         public void Dispose()
 | ||
|         {
 | ||
|             // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
 | ||
|             Dispose(true);
 | ||
|             // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
 | ||
|             // GC.SuppressFinalize(this);
 | ||
|         }
 | ||
|         #endregion
 | ||
|     }
 | ||
| 
 | ||
|     public delegate void OnEventHandler(ref XEvent xEvent);
 | ||
|     public unsafe class X11Window : XWindow, IWindowImpl
 | ||
|     {
 | ||
|         internal static IntPtr mouseDownWindow;
 | ||
|         public static X11Window main;
 | ||
|         protected override void OnCreateWindw()
 | ||
|         {
 | ||
|             if (main == null)
 | ||
|             {
 | ||
|                 //Thread.Sleep(10000);
 | ||
|                 main = this;
 | ||
|             }
 | ||
|             x11info = LinuxPlatform.Platform.Info;
 | ||
|             XSetWindowAttributes attr = new XSetWindowAttributes();
 | ||
|             var valueMask = default(SetWindowValuemask);
 | ||
| 
 | ||
|             attr.background_pixel = IntPtr.Zero;
 | ||
|             attr.border_pixel = IntPtr.Zero;
 | ||
|             attr.backing_store = 1;
 | ||
|             attr.bit_gravity = Gravity.NorthWestGravity;
 | ||
|             attr.win_gravity = Gravity.NorthWestGravity;
 | ||
|             attr.override_redirect = this is PopWindow;
 | ||
|             valueMask |= SetWindowValuemask.BackPixel | SetWindowValuemask.BorderPixel | SetWindowValuemask.BackingStore | SetWindowValuemask.OverrideRedirect
 | ||
|                          //| SetWindowValuemask.BackPixmap 
 | ||
|                          | SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
 | ||
|             var depth = 32;// (int)x11info.TransparentVisualInfo.depth;
 | ||
|             attr.colormap = XCreateColormap(x11info.Display, x11info.RootWindow, x11info.TransparentVisualInfo.visual, 0);
 | ||
|             valueMask |= SetWindowValuemask.ColorMap;
 | ||
|             size = new PixelSize(300, 200);
 | ||
|             position = new PixelPoint(10, 10);
 | ||
| 
 | ||
|             Handle = XCreateWindow(x11info.Display, x11info.RootWindow, 10, 10, size.Width, size.Height, 0, depth, (int)CreateWindowArgs.InputOutput, x11info.TransparentVisualInfo.visual, new UIntPtr((uint)valueMask), ref attr);
 | ||
| 
 | ||
|             //      var attributes = new XSetWindowAttributes();
 | ||
|             //      attributes.background_pixel = XWhitePixel(x11info.Display, x11info.DefaultScreen);
 | ||
|             //      Handle = XCreateWindow(x11info.Display, x11info.RootWindow,
 | ||
|             //0, 0, 100, 100, 0, depth,
 | ||
|             //(int)CreateWindowArgs.InputOutput, XDefaultVisual(x11info.Display, 0)
 | ||
|             //, ((ulong)SetWindowValuemask.BackPixel), ref attributes);
 | ||
| 
 | ||
|             //Handle = XCreateSimpleWindow(x11info.Display, x11info.RootWindow, 10, 10, 100, 100, 0, XWhitePixel(x11info.Display, x11info.DefaultScreen), XWhitePixel(x11info.Display, x11info.DefaultScreen));
 | ||
| 
 | ||
|             //      var attributes = new XSetWindowAttributes();
 | ||
|             //      attributes.background_pixel = XWhitePixel(x11info.Display, x11info.DefaultScreen);
 | ||
|             //      Handle = XCreateWindow(x11info.Display, x11info.RootWindow,
 | ||
|             //0, 0, 100, 100, 0, depth,
 | ||
|             //(int)CreateWindowArgs.InputOutput, XDefaultVisual(x11info.Display, 0)
 | ||
|             //, ((ulong)SetWindowValuemask.BackPixel), ref attributes);
 | ||
| 
 | ||
| 
 | ||
|             var protocols = new[]
 | ||
|             {
 | ||
|                 x11info.Atoms.WM_DELETE_WINDOW
 | ||
|             };
 | ||
|             XSetWMProtocols(x11info.Display, Handle, protocols, protocols.Length);
 | ||
|             XChangeProperty(x11info.Display, Handle, x11info.Atoms._NET_WM_WINDOW_TYPE, x11info.Atoms.XA_ATOM,
 | ||
|                 32, PropertyMode.Replace, new[] { x11info.Atoms._NET_WM_WINDOW_TYPE_NORMAL }, 1);
 | ||
| 
 | ||
|             SetWmClass("CPFApplication");
 | ||
| 
 | ||
|             UpdateMotifHints();
 | ||
| 
 | ||
|             var def = IntPtr.Zero;
 | ||
|             var fontset = XCreateFontSet(x11info.Display, "-*-*-*-*-*-*-14-*-*-*-*-*-*-*", out var missing_charset_list_return, out var missing_charset_count_return, ref def);
 | ||
| 
 | ||
|             //Console.WriteLine("Display:" + x11info.Display + " fontset:" + fontset + " missing_charset_count_return:" + missing_charset_count_return);
 | ||
| 
 | ||
|             //var list = XVaCreateNestedList(0, XNames.XNFontSet, fontset, IntPtr.Zero);
 | ||
|             XPoint spot = new XPoint();
 | ||
|             var pSL = Marshal.StringToHGlobalAnsi(XNames.XNSpotLocation);
 | ||
|             var pFS = Marshal.StringToHGlobalAnsi(XNames.XNFontSet);
 | ||
|             var list = XVaCreateNestedList(0, pSL, spot, pFS, fontset, IntPtr.Zero);
 | ||
| 
 | ||
|             //Console.WriteLine("list:" + list);
 | ||
| 
 | ||
|             //Console.WriteLine(string.Join(" - ", GetSupportedInputStyles(x11info.Xim)));
 | ||
|             //UpdateSizeHints(null);
 | ||
|             xic = XCreateIC(x11info.Xim, XNames.XNInputStyle, styleOverTheSpot,
 | ||
|                 XNames.XNClientWindow, Handle, XNames.XNPreeditAttributes, list, IntPtr.Zero);
 | ||
|             //xic = LinuxPlatform.CreateIC(x11info.Xim, Handle);
 | ||
|             //Console.WriteLine("xic:" + xic);
 | ||
| 
 | ||
|             if (xic == IntPtr.Zero)
 | ||
|             {
 | ||
|                 //ximStyle = styleRoot;
 | ||
|                 xic = XCreateIC(x11info.Xim,
 | ||
|                     XNames.XNInputStyle, styleRoot,
 | ||
|                     XNames.XNClientWindow, Handle,
 | ||
|                     XNames.XNFocusWindow, Handle,
 | ||
|                     IntPtr.Zero);
 | ||
|                 Console.WriteLine("xic:" + xic);
 | ||
|             }
 | ||
|             if (pSL != IntPtr.Zero)
 | ||
|                 Marshal.FreeHGlobal(pSL);
 | ||
|             if (pFS != IntPtr.Zero)
 | ||
|                 Marshal.FreeHGlobal(pFS);
 | ||
|             XFree(list);
 | ||
|             //long im_event_mask = 0;
 | ||
|             ////XIMStyles xIMStyles = new XIMStyles();
 | ||
|             //var icv = XGetICValues(_xic, XNames.XNFilterEvents, ref im_event_mask, IntPtr.Zero);
 | ||
|             //Console.WriteLine(icv);
 | ||
| 
 | ||
|             XEventMask ignoredMask = XEventMask.SubstructureRedirectMask
 | ||
|                          | XEventMask.ResizeRedirectMask
 | ||
|                          | XEventMask.PointerMotionHintMask;
 | ||
|             if (LinuxPlatform.Platform.XI2 != null)
 | ||
|                 LinuxPlatform.Platform.XI2.AddWindow(Handle);
 | ||
| 
 | ||
|             var mask = new IntPtr(0xffffff ^ (int)ignoredMask);
 | ||
|             //lock (XlibLock)
 | ||
|             //{
 | ||
|             XSelectInput(x11info.Display, Handle, mask);
 | ||
|             //}
 | ||
| 
 | ||
|             //启用拖拽
 | ||
|             IntPtr[] XdndVersion = new IntPtr[] { new IntPtr(4) };
 | ||
|             int[] atoms;
 | ||
|             atoms = new int[XdndVersion.Length];
 | ||
|             for (int i = 0; i < XdndVersion.Length; i++)
 | ||
|             {
 | ||
|                 atoms[i] = XdndVersion[i].ToInt32();
 | ||
|             }
 | ||
|             XChangeProperty(x11info.Display, Handle, x11info.Atoms.XdndAware,
 | ||
|                     (IntPtr)Atom.XA_ATOM, 32,
 | ||
|                     PropertyMode.Replace, atoms, 1);
 | ||
| 
 | ||
|             ScreenImpl.GetDpi();
 | ||
| 
 | ||
|             XFlush(x11info.Display);
 | ||
|             //Thread.Sleep(10000);
 | ||
|             //var att = GetXWindowAttributes();
 | ||
|             //Console.WriteLine(att);
 | ||
|             if (Application.GetDrawingFactory().UseGPU)
 | ||
|             {
 | ||
|                 //Thread.Sleep(5000);
 | ||
|                 context = new OpenGL.GlxContext(this);
 | ||
|                 if (context.Context == IntPtr.Zero)
 | ||
|                 {
 | ||
|                     Application.GetDrawingFactory().UseGPU = false;
 | ||
|                     context = null;
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
|         CPF.Linux.OpenGL.GlxContext context;
 | ||
| 
 | ||
|         //private IEnumerable GetMatchingStylesInPreferredOrder(IntPtr xim)
 | ||
|         //{
 | ||
|         //    XIMProperties[] supportedStyles = GetSupportedInputStyles(xim);
 | ||
|         //    foreach (XIMProperties p in GetPreferredStyles())
 | ||
|         //        if (Array.IndexOf(supportedStyles, p) >= 0)
 | ||
|         //            yield return p;
 | ||
|         //}
 | ||
|         public static XIMProperties[] GetSupportedInputStyles(IntPtr xim)
 | ||
|         {
 | ||
|             //Thread.Sleep(10000);
 | ||
|             IntPtr stylesPtr;
 | ||
|             string ret = XGetIMValues(xim, XNames.XNQueryInputStyle, out stylesPtr, IntPtr.Zero);
 | ||
|             if (ret != null || stylesPtr == IntPtr.Zero)
 | ||
|                 return new XIMProperties[0];
 | ||
|             XIMStyles styles = (XIMStyles)Marshal.PtrToStructure(stylesPtr, typeof(XIMStyles));
 | ||
|             XIMProperties[] supportedStyles = new XIMProperties[styles.count_styles];
 | ||
|             var p = (long*)styles.supported_styles;
 | ||
|             for (int i = 0; i < styles.count_styles; i++)
 | ||
|             {
 | ||
|                 //supportedStyles[i] = (XIMProperties)Marshal.PtrToStructure(new IntPtr((long)styles.supported_styles + i * Marshal.SizeOf (typeof (IntPtr)))), typeof(XIMProperties));
 | ||
|                 supportedStyles[i] = (XIMProperties)p[i];
 | ||
|             }
 | ||
|             XFree(stylesPtr);
 | ||
|             return supportedStyles;
 | ||
|         }
 | ||
| 
 | ||
|         const XIMProperties styleRoot = XIMProperties.XIMPreeditNothing | XIMProperties.XIMStatusNothing;
 | ||
|         const XIMProperties styleOverTheSpot = XIMProperties.XIMPreeditPosition | XIMProperties.XIMStatusNothing;
 | ||
|         const XIMProperties styleOnTheSpot = XIMProperties.XIMPreeditCallbacks | XIMProperties.XIMStatusNothing;
 | ||
|         //private XIMProperties[] GetPreferredStyles()
 | ||
|         //{
 | ||
|         //    var env = "over-the-spot";
 | ||
|         //    string[] list = env.Split(' ');
 | ||
|         //    XIMProperties[] ret = new XIMProperties[list.Length];
 | ||
|         //    for (int i = 0; i < list.Length; i++)
 | ||
|         //    {
 | ||
|         //        string s = list[i];
 | ||
|         //        switch (s)
 | ||
|         //        {
 | ||
|         //            case "over-the-spot":
 | ||
|         //                ret[i] = styleOverTheSpot;
 | ||
|         //                break;
 | ||
|         //            case "on-the-spot":
 | ||
|         //                ret[i] = styleOnTheSpot;
 | ||
|         //                break;
 | ||
|         //            case "root":
 | ||
|         //                ret[i] = styleRoot;
 | ||
|         //                break;
 | ||
|         //        }
 | ||
|         //    }
 | ||
|         //    return ret;
 | ||
|         //}
 | ||
| 
 | ||
| 
 | ||
|         private void SetWmClass(string wmClass)
 | ||
|         {
 | ||
|             var data = Encoding.ASCII.GetBytes(wmClass);
 | ||
|             fixed (void* pdata = data)
 | ||
|             {
 | ||
|                 XChangeProperty(x11info.Display, Handle, x11info.Atoms.XA_WM_CLASS, x11info.Atoms.XA_STRING, 8,
 | ||
|                     PropertyMode.Replace, pdata, data.Length);
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         X11Info x11info;
 | ||
|         IntPtr xic;
 | ||
|         //X11Window parent;
 | ||
|         internal View root;
 | ||
|         PixelSize size;
 | ||
|         PixelPoint position;
 | ||
|         //private bool have_Xutf8ResetIC = true;
 | ||
|         public PixelSize Size
 | ||
|         {
 | ||
|             get { return size; }
 | ||
|         }
 | ||
|         void UpdateMotifHints()
 | ||
|         {
 | ||
|             var functions = MotifFunctions.Move | MotifFunctions.Close | MotifFunctions.Resize |
 | ||
|                             MotifFunctions.Minimize | MotifFunctions.Maximize; ;// 
 | ||
|             //var decorations = MotifDecorations.Menu | MotifDecorations.Title | MotifDecorations.Border |
 | ||
|             //                  MotifDecorations.Maximize | MotifDecorations.Minimize | MotifDecorations.ResizeH;
 | ||
| 
 | ||
|             //if (_popup || _systemDecorations == SystemDecorations.None)
 | ||
|             //{
 | ||
|             //    decorations = 0;
 | ||
|             //}
 | ||
|             //else if (_systemDecorations == SystemDecorations.BorderOnly)
 | ||
|             //{
 | ||
|             //    decorations = MotifDecorations.Border;
 | ||
|             //}
 | ||
| 
 | ||
|             //if (!_canResize || _systemDecorations == SystemDecorations.BorderOnly)
 | ||
|             //{
 | ||
|             //    functions &= ~(MotifFunctions.Resize | MotifFunctions.Maximize);
 | ||
|             //    decorations &= ~(MotifDecorations.Maximize | MotifDecorations.ResizeH);
 | ||
|             //}
 | ||
| 
 | ||
|             var hints = new MotifWmHints
 | ||
|             {
 | ||
|                 flags = new IntPtr((int)(MotifFlags.Decorations | MotifFlags.Functions)),//
 | ||
|                 //decorations = new IntPtr((int)decorations),
 | ||
|                 functions = new IntPtr((int)functions)
 | ||
|             };
 | ||
| 
 | ||
|             XChangeProperty(x11info.Display, Handle,
 | ||
|                 x11info.Atoms._MOTIF_WM_HINTS, x11info.Atoms._MOTIF_WM_HINTS, 32,
 | ||
|                 PropertyMode.Replace, ref hints, 5);
 | ||
|         }
 | ||
| 
 | ||
|         void UpdateSizeHints(PixelSize? preResize)
 | ||
|         {
 | ||
|             var size = Screen.WorkingArea.Size;
 | ||
|             var min = new PixelSize(1, 1); //_minMaxSize.minSize;
 | ||
|             var max = new PixelSize((int)size.Width, (int)size.Height);//_minMaxSize.maxSize;
 | ||
| 
 | ||
|             //if (!_canResize || _systemDecorations == SystemDecorations.BorderOnly)
 | ||
|             //    max = min = _realSize;
 | ||
| 
 | ||
|             if (preResize.HasValue)
 | ||
|             {
 | ||
|                 var desired = preResize.Value;
 | ||
|                 max = new PixelSize(Math.Max(desired.Width, max.Width), Math.Max(desired.Height, max.Height));
 | ||
|                 min = new PixelSize(Math.Min(desired.Width, min.Width), Math.Min(desired.Height, min.Height));
 | ||
|             }
 | ||
| 
 | ||
|             var hints = new XSizeHints
 | ||
|             {
 | ||
|                 min_width = min.Width,
 | ||
|                 min_height = min.Height
 | ||
|             };
 | ||
|             hints.height_inc = hints.width_inc = 1;
 | ||
|             var flags = XSizeHintsFlags.PMinSize | XSizeHintsFlags.PResizeInc;
 | ||
|             // People might be passing double.MaxValue
 | ||
|             if (max.Width < 100000 && max.Height < 100000)
 | ||
|             {
 | ||
|                 hints.max_width = max.Width;
 | ||
|                 hints.max_height = max.Height;
 | ||
|                 flags |= XSizeHintsFlags.PMaxSize;
 | ||
|             }
 | ||
| 
 | ||
|             hints.flags = (IntPtr)flags;
 | ||
| 
 | ||
|             XSetWMNormalHints(x11info.Display, Handle, ref hints);
 | ||
|         }
 | ||
| 
 | ||
|         XWindowAttributes GetXWindowAttributes()
 | ||
|         {
 | ||
|             XWindowAttributes attributes = new XWindowAttributes();
 | ||
|             XGetWindowAttributes(x11info.Display, Handle, ref attributes);
 | ||
|             return attributes;
 | ||
|         }
 | ||
| 
 | ||
|         //bool _mapped;
 | ||
|         Bitmap bitmap;
 | ||
|         public override void OnEvent(ref XEvent e)
 | ||
|         {
 | ||
|             //Console.WriteLine(e.type);
 | ||
|             var ev = e;
 | ||
|             //if (ev.AnyEvent.type == XEventName.KeyPress ||
 | ||
|             //    ev.AnyEvent.type == XEventName.KeyRelease)
 | ||
|             //{
 | ||
|             //    // PreFilter() handles "shift key state updates.
 | ||
|             //    //Keyboard.PreFilter(xevent);
 | ||
|             //    if (XFilterEvent(ref ev, Handle))
 | ||
|             //    {
 | ||
|             //        // probably here we could raise WM_IME_KEYDOWN and
 | ||
|             //        // WM_IME_KEYUP, but I'm not sure it is worthy.
 | ||
|             //        return;
 | ||
|             //    }
 | ||
|             //}
 | ||
|             //else if (XFilterEvent(ref ev, IntPtr.Zero))
 | ||
|             //{ return; }
 | ||
|             if (ev.type == XEventName.MapNotify)
 | ||
|             {
 | ||
|                 //_mapped = true;
 | ||
|                 //if (_useRenderWindow)
 | ||
|                 //    XMapWindow(_x11.Display, _renderHandle);
 | ||
|             }
 | ||
|             else if (ev.type == XEventName.UnmapNotify)
 | ||
|             {   //_mapped = false;
 | ||
|             }
 | ||
|             else
 | ||
|             if (ev.type == XEventName.Expose)
 | ||
|             {
 | ||
|                 var rect = new Rect(ev.ExposeEvent.x, ev.ExposeEvent.y, ev.ExposeEvent.width <= 0 ? size.Width : ev.ExposeEvent.width, ev.ExposeEvent.height <= 0 ? size.Height : ev.ExposeEvent.height);
 | ||
|                 if (!firstLayout)
 | ||
|                 {
 | ||
|                     Paint(rect, size);
 | ||
|                 }
 | ||
|                 //if (!_triggeredExpose)
 | ||
|                 //{
 | ||
|                 //    _triggeredExpose = true;
 | ||
|                 //    Dispatcher.UIThread.Post(() =>
 | ||
|                 //    {
 | ||
|                 //        _triggeredExpose = false;
 | ||
|                 //        DoPaint();
 | ||
|                 //    }, DispatcherPriority.Render);
 | ||
|                 //}
 | ||
|             }
 | ||
|             else if (ev.type == XEventName.FocusIn)
 | ||
|             {
 | ||
|                 activate = true;
 | ||
|                 //if (ActivateTransientChildIfNeeded())
 | ||
|                 //    return;
 | ||
|                 Activated?.Invoke();
 | ||
|                 //Console.WriteLine("Activated");
 | ||
|                 //XSetICFocus(xic);
 | ||
|             }
 | ||
|             else if (ev.type == XEventName.FocusOut)
 | ||
|             {
 | ||
|                 activate = false;
 | ||
|                 //Console.WriteLine("Deactivated");
 | ||
|                 Deactivated?.Invoke();
 | ||
|                 XUnsetICFocus(xic);
 | ||
|                 if (xic != IntPtr.Zero)
 | ||
|                 {
 | ||
|                     //if (have_Xutf8ResetIC)
 | ||
|                     //{
 | ||
|                     //    try
 | ||
|                     //    {
 | ||
|                     //        Xutf8ResetIC(xic);
 | ||
|                     //    }
 | ||
|                     //    catch (EntryPointNotFoundException)
 | ||
|                     //    {
 | ||
|                     //        have_Xutf8ResetIC = false;
 | ||
|                     //    }
 | ||
|                     //}
 | ||
|                     //XUnsetICFocus(xic);
 | ||
|                 }
 | ||
|             }
 | ||
|             else if (ev.type == XEventName.MotionNotify)
 | ||
|             {
 | ||
|                 modifiers = TranslateModifiers(ev.MotionEvent.state);
 | ||
|                 MouseEvent(EventType.MouseMove, new Point(ev.MotionEvent.x, ev.MotionEvent.y), modifiers, new Vector(), MouseButton.None);
 | ||
|             }
 | ||
|             else if (ev.type == XEventName.LeaveNotify)
 | ||
|             {
 | ||
|                 modifiers = TranslateModifiers(ev.CrossingEvent.state);
 | ||
|                 MouseEvent(EventType.MouseLeave, new Point(ev.MotionEvent.x, ev.MotionEvent.y), modifiers, new Vector(), MouseButton.None);
 | ||
|             }
 | ||
|             else if (ev.type == XEventName.PropertyNotify)
 | ||
|             {
 | ||
|                 OnPropertyChange(ev.PropertyEvent.atom, ev.PropertyEvent.state == 0);
 | ||
|             }
 | ||
|             else
 | ||
|             if (ev.type == XEventName.ButtonPress)
 | ||
|             {
 | ||
|                 //Console.WriteLine("ButtonPress");
 | ||
|                 if (ActivateTransientChildIfNeeded())
 | ||
|                     return;
 | ||
|                 if (ev.ButtonEvent.button < 4 || ev.ButtonEvent.button == 8 || ev.ButtonEvent.button == 9)
 | ||
|                 {
 | ||
|                     MouseButton mouseButton = MouseButton.None;
 | ||
|                     switch (ev.ButtonEvent.button)
 | ||
|                     {
 | ||
|                         case 1:
 | ||
|                             mouseButton = MouseButton.Left;
 | ||
|                             break;
 | ||
|                         case 2:
 | ||
|                             mouseButton = MouseButton.Middle;
 | ||
|                             break;
 | ||
|                         case 3:
 | ||
|                             mouseButton = MouseButton.Right;
 | ||
|                             break;
 | ||
|                         case 8:
 | ||
|                             mouseButton = MouseButton.XButton1;
 | ||
|                             break;
 | ||
|                         case 9:
 | ||
|                             mouseButton = MouseButton.XButton2;
 | ||
|                             break;
 | ||
|                     }
 | ||
|                     modifiers = TranslateModifiers(ev.ButtonEvent.state);
 | ||
|                     MouseEvent(EventType.MouseDown, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), modifiers, new Vector(), mouseButton);
 | ||
| 
 | ||
|                 }
 | ||
|                 else
 | ||
|                 {
 | ||
|                     modifiers = TranslateModifiers(ev.ButtonEvent.state);
 | ||
|                     //var delta = ev.ButtonEvent.button == 4
 | ||
|                     //    ? new Vector(0, 1)
 | ||
|                     //    : ev.ButtonEvent.button == 5
 | ||
|                     //        ? new Vector(0, -1)
 | ||
|                     //        : ev.ButtonEvent.button == 6
 | ||
|                     //            ? new Vector(1, 0)
 | ||
|                     //            : new Vector(-1, 0);
 | ||
|                     var delta = ev.ButtonEvent.button == 4
 | ||
|                         ? new Vector(0, 120)
 | ||
|                         : ev.ButtonEvent.button == 5
 | ||
|                             ? new Vector(0, -120)
 | ||
|                             : ev.ButtonEvent.button == 6
 | ||
|                                 ? new Vector(120, 0)
 | ||
|                                 : new Vector(-120, 0);
 | ||
|                     MouseEvent(EventType.MouseWheel, new Point(ev.MotionEvent.x, ev.MotionEvent.y), modifiers, delta, MouseButton.None);
 | ||
|                 }
 | ||
| 
 | ||
|             }
 | ||
|             else if (ev.type == XEventName.ButtonRelease)
 | ||
|             {
 | ||
|                 if (ActivateTransientChildIfNeeded())
 | ||
|                     return;
 | ||
|                 //Console.WriteLine("ButtonRelease");
 | ||
|                 if (ev.ButtonEvent.button < 4 || ev.ButtonEvent.button == 8 || ev.ButtonEvent.button == 9)
 | ||
|                 {
 | ||
|                     MouseButton mouseButton = MouseButton.None;
 | ||
|                     switch (ev.ButtonEvent.button)
 | ||
|                     {
 | ||
|                         case 1:
 | ||
|                             mouseButton = MouseButton.Left;
 | ||
|                             break;
 | ||
|                         case 2:
 | ||
|                             mouseButton = MouseButton.Middle;
 | ||
|                             break;
 | ||
|                         case 3:
 | ||
|                             mouseButton = MouseButton.Right;
 | ||
|                             break;
 | ||
|                         case 8:
 | ||
|                             mouseButton = MouseButton.XButton1;
 | ||
|                             break;
 | ||
|                         case 9:
 | ||
|                             mouseButton = MouseButton.XButton2;
 | ||
|                             break;
 | ||
|                     }
 | ||
|                     modifiers = TranslateModifiers(ev.ButtonEvent.state);
 | ||
|                     MouseEvent(EventType.MouseUp, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), modifiers, new Vector(), mouseButton);
 | ||
|                 }
 | ||
|             }
 | ||
|             else
 | ||
|             if (ev.type == XEventName.ConfigureNotify)
 | ||
|             {
 | ||
|                 if (ev.ConfigureEvent.window != Handle)
 | ||
|                     return;
 | ||
|                 ev.ConfigureEvent.override_redirect = true;
 | ||
|                 //var needEnqueue = (_configure == null);
 | ||
|                 //_configure = ev.ConfigureEvent;
 | ||
|                 PixelPoint _configurePoint;
 | ||
|                 if (ev.ConfigureEvent.override_redirect || ev.ConfigureEvent.send_event)
 | ||
|                     _configurePoint = new PixelPoint(ev.ConfigureEvent.x, ev.ConfigureEvent.y);
 | ||
|                 else
 | ||
|                 {
 | ||
|                     XTranslateCoordinates(x11info.Display, Handle, x11info.RootWindow,
 | ||
|                         0, 0,
 | ||
|                         out var tx, out var ty, out _);
 | ||
|                     _configurePoint = new PixelPoint(tx, ty);
 | ||
|                 }
 | ||
|                 //if (needEnqueue)
 | ||
|                 //    Dispatcher.UIThread.Post(() =>
 | ||
|                 //    {
 | ||
|                 //if (_configure == null)
 | ||
|                 //    return;
 | ||
|                 var cev = ev.ConfigureEvent;
 | ||
|                 var npos = _configurePoint;
 | ||
| 
 | ||
|                 var nsize = new PixelSize(cev.width, cev.height);
 | ||
|                 var changedSize = size != nsize;
 | ||
|                 var changedPos = npos != position;
 | ||
|                 size = nsize;
 | ||
|                 position = npos;
 | ||
|                 bool updatedSizeViaScaling = false;
 | ||
|                 //if (changedPos)
 | ||
|                 {
 | ||
|                     PositionChanged?.Invoke(npos);
 | ||
|                     //updatedSizeViaScaling = UpdateScaling();
 | ||
|                 }
 | ||
| 
 | ||
|                 if (changedSize && !updatedSizeViaScaling)
 | ||
|                 {
 | ||
|                     Resized?.Invoke(ClientSize);
 | ||
|                     //Console.WriteLine(position + " , " + size);
 | ||
|                 }
 | ||
| 
 | ||
|                 if (changedSize && !firstLayout)
 | ||
|                 {
 | ||
|                     Paint(new Rect(0, 0, size.Width, size.Height), nsize);
 | ||
|                 }
 | ||
|                 //Console.WriteLine("firstLayout");
 | ||
|                 if (firstLayout)
 | ||
|                 {
 | ||
|                     root.Invalidate();
 | ||
|                 }
 | ||
|                 firstLayout = false;
 | ||
|                 //    Dispatcher.UIThread.RunJobs(DispatcherPriority.Layout);
 | ||
|                 //}, DispatcherPriority.Layout);
 | ||
|                 //if (_useRenderWindow)
 | ||
|                 //    XConfigureResizeWindow(x11info.Info.Display, _renderHandle, ev.ConfigureEvent.width,
 | ||
|                 //        ev.ConfigureEvent.height);
 | ||
|             }
 | ||
|             else if (ev.type == XEventName.ConfigureRequest)
 | ||
|             {
 | ||
|                 var v = ev.ConfigureRequestEvent;
 | ||
|             }
 | ||
|             else if (ev.type == XEventName.DestroyNotify && ev.AnyEvent.window == Handle)
 | ||
|             {
 | ||
|                 //Cleanup();
 | ||
|                 Close();
 | ||
|             }
 | ||
|             else if (ev.type == XEventName.ClientMessage)
 | ||
|             {
 | ||
|                 //Console.WriteLine(ev.ClientMessageEvent.message_type + " " + GetAtomName(x11info.Display, ev.ClientMessageEvent.ptr1) + ev.ClientMessageEvent.ptr1 + " " + ev.ClientMessageEvent.ptr2);
 | ||
|                 if (ev.ClientMessageEvent.message_type == x11info.Atoms.WM_PROTOCOLS)
 | ||
|                 {
 | ||
|                     if (ev.ClientMessageEvent.ptr1 == x11info.Atoms.WM_DELETE_WINDOW)
 | ||
|                     {
 | ||
|                         Close();
 | ||
|                     }
 | ||
| 
 | ||
|                 }
 | ||
|                 //else if (ev.ClientMessageEvent.message_type == x11info.Atoms.XdndSelection)
 | ||
|                 //{
 | ||
|                 //    Console.WriteLine("XdndSelection");
 | ||
|                 //}
 | ||
|                 //else if (ev.ClientMessageEvent.message_type == x11info.Atoms.XdndPosition)
 | ||
|                 //{
 | ||
|                 //    var pos_x = (int)ev.ClientMessageEvent.ptr3 >> 16;
 | ||
|                 //    var pos_y = (int)ev.ClientMessageEvent.ptr3 & 0xFFFF;
 | ||
|                 //    Console.WriteLine(pos_x + "," + pos_y);
 | ||
|                 //}
 | ||
|                 else if (ev.ClientMessageEvent.message_type == x11info.Atoms.XdndEnter)
 | ||
|                 {
 | ||
|                     //Console.WriteLine("dragenter");
 | ||
|                     var mp = MouseDevice.Location;
 | ||
|                     dataObject.AllowedEffects = dataObject.EffectFromAction(ev.ClientMessageEvent.ptr5);
 | ||
|                     dataObject.SetDragDropEffects(root.InputManager.DragDropDevice.DragEnter(new DragEventArgs(dataObject, new Point(mp.X - position.X, mp.Y - position.Y), root) { DragEffects = dataObject.AllowedEffects }, root.LayoutManager.VisibleUIElements));
 | ||
|                     //查询格式,判断是否可以接受数据
 | ||
|                     dataObject.DragEnter(ref ev, (s, ee) =>
 | ||
|                     {
 | ||
|                         var mmp = MouseDevice.Location;
 | ||
|                         dataObject.SetDragDropEffects(root.InputManager.DragDropDevice.DragOver(new DragEventArgs(dataObject, new Point(mmp.X - position.X, mmp.Y - position.Y), root) { DragEffects = dataObject.AllowedEffects }, root.LayoutManager.VisibleUIElements));
 | ||
|                     });
 | ||
| 
 | ||
|                 }
 | ||
|                 else if (ev.ClientMessageEvent.message_type == x11info.Atoms.XdndDrop)
 | ||
|                 {
 | ||
|                     var mp = MouseDevice.Location;
 | ||
|                     root.InputManager.DragDropDevice.Drop(new DragEventArgs(dataObject, new Point(mp.X - position.X, mp.Y - position.Y), root) { DragEffects = dataObject.DropEffects }, root.LayoutManager.VisibleUIElements);
 | ||
|                     dataObject.StopTimer();
 | ||
|                     dataObject.SendFinished();
 | ||
|                 }
 | ||
|                 else if (ev.ClientMessageEvent.message_type == x11info.Atoms.XdndLeave)
 | ||
|                 {
 | ||
|                     root.InputManager.DragDropDevice.DragLeave(root.LayoutManager.VisibleUIElements);
 | ||
|                     dataObject.StopTimer();
 | ||
|                 }
 | ||
|                 //else if (ev.ClientMessageEvent.message_type == x11info.Atoms.XdndStatus)
 | ||
|                 //{
 | ||
|                 //    Console.WriteLine("XdndStatus");
 | ||
|                 //}
 | ||
|                 //else if (ev.ClientMessageEvent.message_type == x11info.Atoms.XdndFinished)
 | ||
|                 //{
 | ||
|                 //    Console.WriteLine("XdndFinished");
 | ||
|                 //}
 | ||
|                 //else if (ev.ClientMessageEvent.message_type == x11info.Atoms.XdndAware)
 | ||
|                 //{
 | ||
|                 //    Console.WriteLine("XdndAware");
 | ||
|                 //}
 | ||
|             }
 | ||
|             //else if (ev.type == XEventName.SelectionNotify)
 | ||
|             //{
 | ||
|             //    Console.WriteLine("SelectionNotify:" + dataObject.GetText(ref ev));
 | ||
|             //}
 | ||
|             else if (ev.type == XEventName.KeyPress || ev.type == XEventName.KeyRelease)
 | ||
|             {
 | ||
|                 if (ActivateTransientChildIfNeeded())
 | ||
|                     return;
 | ||
| 
 | ||
|                 var index = ev.KeyEvent.state.HasFlag(XModifierMask.ShiftMask);
 | ||
| 
 | ||
|                 // We need the latin key, since it's mainly used for hotkeys, we use a different API for text anyway
 | ||
|                 var key = (X11Key)XKeycodeToKeysym(x11info.Display, ev.KeyEvent.keycode, index ? 1 : 0).ToInt32();
 | ||
| 
 | ||
|                 // Manually switch the Shift index for the keypad,
 | ||
|                 // there should be a proper way to do this
 | ||
|                 if (ev.KeyEvent.state.HasFlag(XModifierMask.Mod2Mask)
 | ||
|                     && key > X11Key.Num_Lock && key <= X11Key.KP_9)
 | ||
|                 { key = (X11Key)XKeycodeToKeysym(x11info.Display, ev.KeyEvent.keycode, index ? 0 : 1).ToInt32(); }
 | ||
| 
 | ||
| 
 | ||
|                 modifiers = TranslateModifiers(ev.KeyEvent.state);
 | ||
|                 root.InputManager.KeyboardDevice.Modifiers = modifiers;
 | ||
| 
 | ||
|                 if (ev.type == XEventName.KeyPress)
 | ||
|                 {
 | ||
|                     root.InputManager.KeyboardDevice.ProcessEvent(new KeyEventArgs(root, X11KeyConvert.ConvertKey(key), ev.KeyEvent.keycode, modifiers, root.InputManager.KeyboardDevice), KeyEventType.KeyDown);
 | ||
|                     var len = LookupString(ref ev, 24, out var xKeySym, out var status);
 | ||
|                     //Console.WriteLine(lookup_buffer.ToString());
 | ||
| 
 | ||
|                     //var buffer = stackalloc byte[1024];
 | ||
|                     //var len = Xutf8LookupString(_xic, ref ev, buffer, 1024, out var x11Key, out var status);
 | ||
|                     //Console.WriteLine(len);
 | ||
|                     //var len = XwcLookupString(_xic, ref ev, buffer, 1024, out _, out var status);
 | ||
|                     //var str = new StringBuilder(40);
 | ||
|                     //X11Key x11Key= X11Key.a;
 | ||
|                     //LookupStatus status = LookupStatus.XBufferOverflow;
 | ||
|                     //var len = XmbLookupString(_xic, ref ev.KeyEvent, buffer, 1024, out var x11Key, out var status);
 | ||
|                     //Console.WriteLine(status);
 | ||
|                     if (status == XLookupStatus.XLookupChars || status == XLookupStatus.XLookupBoth)
 | ||
|                     {
 | ||
|                         var text = lookup_buffer.ToString();
 | ||
|                         //var text = Encoding.UTF8.GetString(buffer, len);
 | ||
|                         if ((text.Length == 1 && !(text[0] < ' ' || text[0] == 0x7f)) || text.Length > 1)
 | ||
|                         {
 | ||
|                             root.InputManager.KeyboardDevice.ProcessEvent(new TextInputEventArgs(root, root.InputManager.KeyboardDevice, text), KeyEventType.TextInput);
 | ||
|                         }
 | ||
|                     }
 | ||
|                 }
 | ||
|                 else
 | ||
|                 {
 | ||
|                     root.InputManager.KeyboardDevice.ProcessEvent(new KeyEventArgs(root, X11KeyConvert.ConvertKey(key), ev.KeyEvent.keycode, modifiers, root.InputManager.KeyboardDevice), KeyEventType.KeyUp);
 | ||
|                 }
 | ||
| 
 | ||
|                 //x11info.LastActivityTimestamp = ev.ButtonEvent.time;
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             base.OnEvent(ref e);
 | ||
|         }
 | ||
| 
 | ||
|         DataObject dataObject = new DataObject();
 | ||
| 
 | ||
|         private bool have_Xutf8LookupString = true;
 | ||
| 
 | ||
|         private byte[] lookup_byte_buffer = new byte[100];
 | ||
|         private StringBuilder lookup_buffer = new StringBuilder(24);
 | ||
|         private int LookupString(ref XEvent xevent, int len, out XKeySym keysym, out XLookupStatus status)
 | ||
|         {
 | ||
|             IntPtr keysym_res;
 | ||
|             int res;
 | ||
| 
 | ||
|             status = XLookupStatus.XLookupNone;
 | ||
|             if (xic != IntPtr.Zero && have_Xutf8LookupString && xevent.type == XEventName.KeyPress)
 | ||
|             {
 | ||
|                 do
 | ||
|                 {
 | ||
|                     try
 | ||
|                     {
 | ||
|                         res = Xutf8LookupString(xic, ref xevent, lookup_byte_buffer, lookup_byte_buffer.Length, out keysym_res, out status);
 | ||
|                     }
 | ||
|                     catch (EntryPointNotFoundException)
 | ||
|                     {
 | ||
|                         have_Xutf8LookupString = false;
 | ||
| 
 | ||
|                         // call again, this time we'll go through the non-xic clause
 | ||
|                         return LookupString(ref xevent, len, out keysym, out status);
 | ||
|                     }
 | ||
|                     if (status != XLookupStatus.XBufferOverflow)
 | ||
|                         break;
 | ||
|                     lookup_byte_buffer = new byte[lookup_byte_buffer.Length << 1];
 | ||
|                 } while (true);
 | ||
|                 lookup_buffer.Length = 0;
 | ||
|                 string s = Encoding.UTF8.GetString(lookup_byte_buffer, 0, res);
 | ||
|                 lookup_buffer.Append(s);
 | ||
|                 keysym = (XKeySym)keysym_res.ToInt32();
 | ||
|                 return s.Length;
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 IntPtr statusPtr = IntPtr.Zero;
 | ||
|                 res = XLookupString(ref xevent, lookup_byte_buffer, len, out keysym_res, out statusPtr);
 | ||
|                 lookup_buffer.Length = 0;
 | ||
|                 string s = Encoding.ASCII.GetString(lookup_byte_buffer, 0, res);
 | ||
|                 lookup_buffer.Append(s);
 | ||
|                 keysym = (XKeySym)keysym_res.ToInt32();
 | ||
|                 return res;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         private void Paint(Rect rect, PixelSize size)
 | ||
|         {
 | ||
|             root.LayoutManager.ExecuteLayoutPass();
 | ||
|             if (context != null)
 | ||
|             {
 | ||
|                 context.MakeCurrent();
 | ||
|                 if (root.LayoutManager.VisibleUIElements != null)
 | ||
|                 {
 | ||
|                     context.GetFramebufferInfo(out var fb, out var sam, out var sten);
 | ||
|                     var rt = new OpenGlRenderTarget(context, size.Width, (int)size.Height, fb, sam, sten);
 | ||
|                     using (DrawingContext dc = DrawingContext.FromRenderTarget(rt))
 | ||
|                     {
 | ||
|                         root.RenderView(dc, rect);
 | ||
|                     }
 | ||
|                 }
 | ||
|                 context.SwapBuffers();
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 if (bitmap == null || bitmap.Width != size.Width || bitmap.Height != size.Height)
 | ||
|                 {
 | ||
|                     if (bitmap != null)
 | ||
|                     {
 | ||
|                         bitmap.Dispose();
 | ||
|                     }
 | ||
|                     bitmap = new Bitmap(size.Width, size.Height);
 | ||
|                 }
 | ||
|                 if (root != null && root.LayoutManager.VisibleUIElements != null)
 | ||
|                 {
 | ||
|                     using (DrawingContext dc = DrawingContext.FromBitmap(bitmap))
 | ||
|                     {
 | ||
|                         root.RenderView(dc, rect);
 | ||
|                     }
 | ||
|                 }
 | ||
| 
 | ||
|                 using (var l = bitmap.Lock())
 | ||
|                 {
 | ||
|                     var gc = XCreateGC(x11info.Display, Handle, 0, IntPtr.Zero);
 | ||
|                     //XLockDisplay(x11info.Display);
 | ||
|                     var img = new XImage();
 | ||
|                     int bitsPerPixel = 32;
 | ||
|                     img.width = bitmap.Width;
 | ||
|                     img.height = bitmap.Height;
 | ||
|                     img.format = 2; //ZPixmap;
 | ||
|                     img.data = l.DataPointer;
 | ||
|                     img.byte_order = 0;// LSBFirst;
 | ||
|                     img.bitmap_unit = bitsPerPixel;
 | ||
|                     img.bitmap_bit_order = 0;// LSBFirst;
 | ||
|                     img.bitmap_pad = bitsPerPixel;
 | ||
|                     img.depth = 32;
 | ||
|                     img.bytes_per_line = bitmap.Width * 4;
 | ||
|                     img.bits_per_pixel = bitsPerPixel;
 | ||
|                     XInitImage(ref img);
 | ||
| 
 | ||
|                     XPutImage(x11info.Display, Handle, gc, ref img, 0, 0, 0, 0, (uint)size.Width, (uint)size.Height);
 | ||
|                     //XSync(x11info.Display, false);
 | ||
|                     //XUnlockDisplay(x11info.Display);
 | ||
|                     XFreeGC(x11info.Display, gc);
 | ||
|                     //XFlush(x11info.Display);
 | ||
|                     //Console.WriteLine("Expose");
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         WindowState _lastWindowState = WindowState.Normal;
 | ||
|         /// <summary>
 | ||
|         /// 
 | ||
|         /// </summary>
 | ||
|         /// <param name="atom"></param>
 | ||
|         /// <param name="hasValue"></param>
 | ||
|         /// <param name="windowState">部分Linux里会丢失状态消息</param>
 | ||
|         private void OnPropertyChange(IntPtr atom, bool hasValue, WindowState? windowState = null)
 | ||
|         {
 | ||
|             //Console.WriteLine(GetAtomName(x11info.Display, atom));
 | ||
|             if (atom == x11info.Atoms._NET_WM_STATE)
 | ||
|             {
 | ||
|                 WindowState state = WindowState.Normal;
 | ||
|                 if (hasValue)
 | ||
|                 {
 | ||
|                     if (windowState.HasValue)
 | ||
|                     {
 | ||
|                         state = windowState.Value;
 | ||
|                     }
 | ||
|                     else
 | ||
|                     {
 | ||
|                         XGetWindowProperty(x11info.Display, Handle, x11info.Atoms._NET_WM_STATE, IntPtr.Zero, new IntPtr(256),
 | ||
|                             false, (IntPtr)Atom.XA_ATOM, out _, out _, out var nitems, out _,
 | ||
|                             out var prop);
 | ||
|                         int maximized = 0;
 | ||
|                         var pitems = (IntPtr*)prop.ToPointer();
 | ||
|                         if (nitems.ToInt32() == 0)
 | ||
|                         {
 | ||
|                             return;
 | ||
|                         }
 | ||
|                         for (var c = 0; c < nitems.ToInt32(); c++)
 | ||
|                         {
 | ||
|                             if (pitems[c] == x11info.Atoms._NET_WM_STATE_HIDDEN)
 | ||
|                             {
 | ||
|                                 state = WindowState.Minimized;
 | ||
|                                 break;
 | ||
|                             }
 | ||
|                             if (pitems[c] == x11info.Atoms._NET_WM_STATE_FULLSCREEN)
 | ||
|                             {
 | ||
|                                 state = WindowState.FullScreen;
 | ||
|                                 break;
 | ||
|                             }
 | ||
|                             if (pitems[c] == x11info.Atoms._NET_WM_STATE_MAXIMIZED_HORZ ||
 | ||
|                                 pitems[c] == x11info.Atoms._NET_WM_STATE_MAXIMIZED_VERT)
 | ||
|                             {
 | ||
|                                 maximized++;
 | ||
|                                 if (maximized == 2)
 | ||
|                                 {
 | ||
|                                     state = WindowState.Maximized;
 | ||
|                                     break;
 | ||
|                                 }
 | ||
|                             }
 | ||
|                         }
 | ||
|                         XFree(prop);
 | ||
|                     }
 | ||
|                 }
 | ||
|                 if (_lastWindowState != state)
 | ||
|                 {
 | ||
|                     var old = _lastWindowState;
 | ||
|                     _lastWindowState = state;
 | ||
|                     WindowStateChanged?.Invoke();
 | ||
|                     if (state == WindowState.Maximized)
 | ||
|                     {
 | ||
|                         var sc = Screen;
 | ||
|                         lastRect = new Rect(position.X, position.Y, size.Width, size.Height);
 | ||
|                         //Console.WriteLine(sc.WorkingArea);
 | ||
|                         if (sc.Primary)
 | ||
|                         {
 | ||
|                             Position = new PixelPoint((int)sc.WorkingArea.Left, (int)sc.WorkingArea.Top);
 | ||
|                             //root.MarginLeft = sc.WorkingArea.Left / LayoutScaling;
 | ||
|                             //root.MarginTop = sc.WorkingArea.Top / LayoutScaling;
 | ||
|                             PositionChanged(position);
 | ||
|                             Resize(sc.WorkingArea.Size / RenderScaling, true);
 | ||
|                         }
 | ||
|                         else
 | ||
|                         {
 | ||
|                             //Console.WriteLine(sc.Bounds);
 | ||
|                             //Position = new PixelPoint((int)sc.Bounds.Left, (int)sc.Bounds.Top);
 | ||
|                             //PositionChanged(position);
 | ||
|                             //Resize(sc.Bounds.Size, true);
 | ||
|                             root.BeginInvoke(() =>
 | ||
|                             {
 | ||
|                                 (root as Window).WindowState = WindowState.FullScreen;
 | ||
|                             });
 | ||
|                         }
 | ||
| 
 | ||
|                         root.Delay(TimeSpan.FromMilliseconds(100), () =>
 | ||
|                         {
 | ||
|                             root.Invalidate();//Centos里开启GPU后最大化有时候会丢失图像,这里强制刷新
 | ||
|                         });
 | ||
|                     }
 | ||
|                     else if (state == WindowState.Normal && old == WindowState.Maximized)
 | ||
|                     {
 | ||
|                         Resize(lastRect.Size / RenderScaling, true);
 | ||
|                         root.BeginInvoke(() =>
 | ||
|                         {
 | ||
|                             if (!(root is Window window) || !window.IsDragMove)
 | ||
|                             {
 | ||
|                                 Position = new PixelPoint((int)lastRect.X, (int)lastRect.Y);
 | ||
|                             }
 | ||
| 
 | ||
|                             root.Delay(TimeSpan.FromMilliseconds(100), () =>
 | ||
|                             {
 | ||
|                                 root.Invalidate();//Centos里开启GPU后最大化还原有时候会丢失图像,这里强制刷新
 | ||
|                             });
 | ||
|                         });
 | ||
|                     }
 | ||
| 
 | ||
|                     //Console.WriteLine(lastRect + " " + state + " " + old);
 | ||
|                 }
 | ||
|                 //else if (fullscreen && _lastWindowState != state && state != WindowState.Normal)
 | ||
|                 //{
 | ||
|                 //    _lastWindowState = state;
 | ||
|                 //    WindowStateChanged?.Invoke();
 | ||
|                 //}
 | ||
|             }
 | ||
| 
 | ||
|         }
 | ||
|         Rect lastRect;
 | ||
| 
 | ||
|         InputModifiers modifiers;
 | ||
|         public void MouseEvent(EventType type, Point pos, InputModifiers modifiers, Vector delta, MouseButton mouseButton, bool isTouch = false)
 | ||
|         {
 | ||
|             this.modifiers = modifiers;
 | ||
|             if (type == EventType.MouseMove && root is Window window && window.IsDragMove)
 | ||
|             {
 | ||
|                 if (WindowState == WindowState.Maximized || WindowState == WindowState.FullScreen)
 | ||
|                 {
 | ||
|                     var me = pos / RenderScaling;
 | ||
|                     var left = me.X;
 | ||
|                     var t = me.Y;
 | ||
|                     var w = window.ActualSize.Width;
 | ||
|                     var percent = left / w;
 | ||
|                     var ml = MouseDevice.Location;
 | ||
|                     WindowState = WindowState.Normal;
 | ||
|                     root.BeginInvoke(() =>
 | ||
|                     {
 | ||
|                         var atr = GetXWindowAttributes();
 | ||
|                         var scr = window.Screen;
 | ||
|                         var tt = (ml.Y - scr.WorkingArea.Y) / window.RenderScaling - t;
 | ||
|                         window.MarginTop = tt;
 | ||
|                         window.MarginLeft = left - atr.width / window.RenderScaling * percent;
 | ||
|                         //Console.WriteLine(left + "-" + window.ActualSize.Width + "-" + percent + "--" + tt + "," + window.MarginLeft);
 | ||
|                         DragMove();
 | ||
|                     });
 | ||
|                 }
 | ||
|                 else
 | ||
|                 {
 | ||
|                     DragMove();
 | ||
|                 }
 | ||
| 
 | ||
|                 return;
 | ||
|             }
 | ||
|             if (type == EventType.MouseDown)
 | ||
|             {
 | ||
|                 mouseDownWindow = Handle;
 | ||
|             }
 | ||
|             //modifiers = TranslateModifiers(mods);
 | ||
|             root.InputManager.KeyboardDevice.Modifiers = modifiers;
 | ||
|             if (type == EventType.MouseLeave || type == EventType.MouseMove)
 | ||
|             {
 | ||
|                 root.InputManager.MouseDevice.ProcessEvent(new MouseEventArgs(root, modifiers.HasFlag(InputModifiers.LeftMouseButton), modifiers.HasFlag(InputModifiers.RightMouseButton), modifiers.HasFlag(InputModifiers.MiddleMouseButton), pos / RenderScaling, root.InputManager.MouseDevice, isTouch), root.LayoutManager.VisibleUIElements, type);
 | ||
|                 //Console.WriteLine("mousemove:" + ev.MotionEvent.x + "," + ev.MotionEvent.y + "===" + new Point(ev.MotionEvent.x, ev.MotionEvent.y) / LayoutScaling);
 | ||
|             }
 | ||
|             else if (type == EventType.MouseWheel)
 | ||
|             {
 | ||
|                 root.InputManager.MouseDevice.ProcessEvent(new MouseWheelEventArgs(root, modifiers.HasFlag(InputModifiers.LeftMouseButton), modifiers.HasFlag(InputModifiers.RightMouseButton), modifiers.HasFlag(InputModifiers.MiddleMouseButton), pos / RenderScaling, root.InputManager.MouseDevice, delta), root.LayoutManager.VisibleUIElements, type);
 | ||
|             }
 | ||
|             else if (type == EventType.MouseDown || type == EventType.MouseUp)
 | ||
|             {
 | ||
|                 if (type == EventType.MouseDown)
 | ||
|                 {
 | ||
|                     switch (mouseButton)
 | ||
|                     {
 | ||
|                         case MouseButton.Left:
 | ||
|                             modifiers |= InputModifiers.LeftMouseButton;
 | ||
|                             break;
 | ||
|                         case MouseButton.Middle:
 | ||
|                             modifiers |= InputModifiers.MiddleMouseButton;
 | ||
|                             break;
 | ||
|                         case MouseButton.Right:
 | ||
|                             modifiers |= InputModifiers.RightMouseButton;
 | ||
|                             break;
 | ||
|                     }
 | ||
|                 }
 | ||
|                 else
 | ||
|                 {
 | ||
|                     switch (mouseButton)
 | ||
|                     {
 | ||
|                         case MouseButton.Left:
 | ||
|                             modifiers ^= InputModifiers.LeftMouseButton;
 | ||
|                             break;
 | ||
|                         case MouseButton.Middle:
 | ||
|                             modifiers ^= InputModifiers.MiddleMouseButton;
 | ||
|                             break;
 | ||
|                         case MouseButton.Right:
 | ||
|                             modifiers ^= InputModifiers.RightMouseButton;
 | ||
|                             break;
 | ||
|                     }
 | ||
|                 }
 | ||
|                 root.InputManager.KeyboardDevice.Modifiers = modifiers;
 | ||
|                 root.InputManager.MouseDevice.ProcessEvent(new MouseButtonEventArgs(root, modifiers.HasFlag(InputModifiers.LeftMouseButton), modifiers.HasFlag(InputModifiers.RightMouseButton), modifiers.HasFlag(InputModifiers.MiddleMouseButton), pos / RenderScaling, root.InputManager.MouseDevice, mouseButton, isTouch), root.LayoutManager.VisibleUIElements, type);
 | ||
|             }
 | ||
|             if (type == EventType.MouseUp)
 | ||
|             {
 | ||
|                 if (xic != IntPtr.Zero && !(root.InputManager.KeyboardDevice.FocusedElement is IEditor))
 | ||
|                 {
 | ||
|                     XUnsetICFocus(xic);
 | ||
|                 }
 | ||
|                 else if (xic != IntPtr.Zero && root.InputManager.KeyboardDevice.FocusedElement is IEditor editor && editor.IsInputMethodEnabled && CanActivate)
 | ||
|                 {
 | ||
|                     XSetICFocus(xic);
 | ||
|                 }
 | ||
|                 mouseDownWindow = IntPtr.Zero;
 | ||
|             }
 | ||
|             //x11info.LastActivityTimestamp = ev.ButtonEvent.time;
 | ||
|         }
 | ||
| 
 | ||
|         private void DragMove()
 | ||
|         {
 | ||
|             root.BeginInvoke(() =>
 | ||
|             {
 | ||
|                 lock (XlibLock)
 | ||
|                 {
 | ||
|                     XEvent xEvent = new XEvent();
 | ||
|                     var p = MouseDevice.Location;
 | ||
|                     var display = x11info.Display;
 | ||
|                     xEvent.ClientMessageEvent.type = XEventName.ClientMessage;
 | ||
|                     xEvent.ClientMessageEvent.message_type = x11info.Atoms._NET_WM_MOVERESIZE;
 | ||
|                     xEvent.ClientMessageEvent.display = display;
 | ||
|                     xEvent.ClientMessageEvent.window = Handle;
 | ||
|                     xEvent.ClientMessageEvent.format = 32;
 | ||
|                     xEvent.ClientMessageEvent.ptr1 = (IntPtr)p.X;
 | ||
|                     xEvent.ClientMessageEvent.ptr2 = (IntPtr)p.Y;
 | ||
|                     xEvent.ClientMessageEvent.ptr3 = (IntPtr)8;
 | ||
|                     xEvent.ClientMessageEvent.ptr4 = (IntPtr)1;
 | ||
|                     XUngrabPointer(display, IntPtr.Zero);
 | ||
|                     XSendEvent(display, x11info.RootWindow, false, (IntPtr)(EventMask.SubstructureNotifyMask | EventMask.SubstructureRedirectMask), ref xEvent);
 | ||
|                     XFlush(display);
 | ||
| 
 | ||
| 
 | ||
|                     //p = MouseDevice.Location;
 | ||
|                     XEvent xevent = new XEvent();
 | ||
|                     xevent.type = XEventName.ButtonRelease;
 | ||
|                     xevent.ButtonEvent.button = 1;
 | ||
|                     xevent.ButtonEvent.window = Handle;
 | ||
|                     xevent.ButtonEvent.x = p.X - position.X;
 | ||
|                     xevent.ButtonEvent.y = p.Y - position.Y;
 | ||
|                     xevent.ButtonEvent.x_root = p.X;
 | ||
|                     xevent.ButtonEvent.y_root = p.X;
 | ||
|                     xevent.ButtonEvent.display = display;
 | ||
|                     xevent.ButtonEvent.state = XModifierMask.Button1Mask;
 | ||
| 
 | ||
|                     XSendEvent(display, Handle, false, (IntPtr)EventMask.ButtonReleaseMask, ref xevent);
 | ||
|                     XFlush(display);
 | ||
|                 }
 | ||
|             });
 | ||
|         }
 | ||
| 
 | ||
|         InputModifiers TranslateModifiers(XModifierMask state)
 | ||
|         {
 | ||
|             var rv = default(InputModifiers);
 | ||
|             if (state.HasFlag(XModifierMask.Button1Mask))
 | ||
|                 rv |= InputModifiers.LeftMouseButton;
 | ||
|             if (state.HasFlag(XModifierMask.Button2Mask))
 | ||
|                 rv |= InputModifiers.MiddleMouseButton;
 | ||
|             if (state.HasFlag(XModifierMask.Button3Mask))
 | ||
|                 rv |= InputModifiers.RightMouseButton;
 | ||
|             //if (state.HasFlag(XModifierMask.Button4Mask))
 | ||
|             //    rv |= InputModifiers.XButton1MouseButton;
 | ||
|             //if (state.HasFlag(XModifierMask.Button5Mask))
 | ||
|             //    rv |= InputModifiers.XButton2MouseButton;
 | ||
|             if (state.HasFlag(XModifierMask.ShiftMask))
 | ||
|                 rv |= InputModifiers.Shift;
 | ||
|             if (state.HasFlag(XModifierMask.ControlMask))
 | ||
|                 rv |= InputModifiers.Control;
 | ||
|             if (state.HasFlag(XModifierMask.Mod1Mask))
 | ||
|                 rv |= InputModifiers.Alt;
 | ||
|             //if (state.HasFlag(XModifierMask.Mod4Mask))
 | ||
|             //    rv |= InputModifiers.Meta;
 | ||
|             return rv;
 | ||
|         }
 | ||
| 
 | ||
|         void Resize(Size clientSize, bool force)
 | ||
|         {
 | ||
|             if (!force && clientSize == ClientSize)
 | ||
|                 return;
 | ||
| 
 | ||
|             var needImmediatePopupResize = clientSize != ClientSize;
 | ||
| 
 | ||
|             var pixelSize = ToPixelSize(clientSize);
 | ||
|             //Paint(new Rect(new Point(), new Size(pixelSize.Width, pixelSize.Height)), pixelSize);
 | ||
|             //UpdateSizeHints(pixelSize);
 | ||
|             XConfigureResizeWindow(x11info.Display, Handle, pixelSize);
 | ||
|             XFlush(x11info.Display);
 | ||
| 
 | ||
|             if (force)//|| (_popup && needImmediatePopupResize))
 | ||
|             {
 | ||
|                 size = pixelSize;
 | ||
|                 Resized?.Invoke(ClientSize);
 | ||
|             }
 | ||
|         }
 | ||
|         PixelSize ToPixelSize(Size size) => new PixelSize((int)Math.Ceiling(size.Width * RenderScaling), (int)Math.Ceiling(size.Height * RenderScaling));
 | ||
|         public void UpdateScaling()
 | ||
|         {
 | ||
|             //lock (XlibLock)
 | ||
|             {
 | ||
|                 //float newScaling;
 | ||
|                 //var pos = new Point(position.X, position.Y);
 | ||
|                 //var monitor = ScreenImpl.Screens.OrderBy(x => x.PixelDensity)
 | ||
|                 //    .FirstOrDefault(m => m.Bounds.Contains(pos));
 | ||
| 
 | ||
|                 //if (RenderScaling != newScaling * Application.BaseScale)
 | ||
|                 {
 | ||
|                     //var oldScaledSize = ClientSize;
 | ||
|                     //RenderScaling = newScaling * Application.BaseScale;
 | ||
|                     ScalingChanged?.Invoke();
 | ||
|                     //SetMinMaxSize(_scaledMinMaxSize.minSize, _scaledMinMaxSize.maxSize);
 | ||
|                     Resized(ClientSize);
 | ||
|                     //return true;
 | ||
|                 }
 | ||
| 
 | ||
|                 //return false;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         public Func<bool> Closing { get; set; }
 | ||
|         public Action Closed { get; set; }
 | ||
|         public WindowState WindowState
 | ||
|         {
 | ||
|             get { return _lastWindowState; }
 | ||
|             set
 | ||
|             {
 | ||
|                 if (_lastWindowState == value)
 | ||
|                     return;
 | ||
|                 if (value == WindowState.Minimized)
 | ||
|                 {
 | ||
|                     XIconifyWindow(x11info.Display, Handle, x11info.DefaultScreen);
 | ||
|                 }
 | ||
|                 else if (value == WindowState.Maximized)
 | ||
|                 {
 | ||
|                     ChangeWMAtoms(false, x11info.Atoms._NET_WM_STATE_HIDDEN);
 | ||
|                     ChangeWMAtoms(false, x11info.Atoms._NET_WM_STATE_FULLSCREEN);
 | ||
|                     ChangeWMAtoms(true, x11info.Atoms._NET_WM_STATE_MAXIMIZED_VERT,
 | ||
|                         x11info.Atoms._NET_WM_STATE_MAXIMIZED_HORZ);
 | ||
|                     lastRect = new Rect(position.X, position.Y, size.Width, size.Height);
 | ||
|                 }
 | ||
|                 else if (value == WindowState.FullScreen)
 | ||
|                 {
 | ||
|                     //lastRect = new Rect(position.X, position.Y, size.Width, size.Height);
 | ||
|                     ChangeWMAtoms(false, x11info.Atoms._NET_WM_STATE_HIDDEN);
 | ||
|                     ChangeWMAtoms(false, x11info.Atoms._NET_WM_STATE_MAXIMIZED_VERT,
 | ||
|                         x11info.Atoms._NET_WM_STATE_MAXIMIZED_HORZ);
 | ||
|                     ChangeWMAtoms(true, x11info.Atoms._NET_WM_STATE_FULLSCREEN);
 | ||
|                 }
 | ||
|                 else
 | ||
|                 {
 | ||
|                     ChangeWMAtoms(false, x11info.Atoms._NET_WM_STATE_HIDDEN);
 | ||
|                     ChangeWMAtoms(false, x11info.Atoms._NET_WM_STATE_FULLSCREEN);
 | ||
|                     ChangeWMAtoms(false, x11info.Atoms._NET_WM_STATE_MAXIMIZED_VERT,
 | ||
|                         x11info.Atoms._NET_WM_STATE_MAXIMIZED_HORZ);
 | ||
|                     SendNetWMMessage(x11info.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1);
 | ||
|                 }
 | ||
|                 //if (fullscreen && value == WindowState.Normal)
 | ||
|                 //{
 | ||
|                 //    SetFullscreen(false);
 | ||
|                 //}
 | ||
|                 //else if (fullscreen && value == WindowState.Maximized)
 | ||
|                 //{
 | ||
| 
 | ||
|                 //}
 | ||
|                 XFlush(x11info.Display);
 | ||
|                 OnPropertyChange(x11info.Atoms._NET_WM_STATE, true, value);
 | ||
|                 //_lastWindowState = value;
 | ||
|             }
 | ||
|         }
 | ||
|         public Action WindowStateChanged { get; set; }
 | ||
| 
 | ||
|         public Screen Screen
 | ||
|         {
 | ||
|             get
 | ||
|             {
 | ||
|                 //XWindowAttributes attributes = new XWindowAttributes();
 | ||
|                 //XGetWindowAttributes(x11info.Display, Handle, ref attributes);
 | ||
|                 //var sc = Marshal.PtrToStructure<XScreen>(attributes.screen);
 | ||
|                 var pos = position;
 | ||
|                 var rect = new Rect(pos.X, pos.Y, size.Width, size.Height);
 | ||
|                 var screen = Screen.AllScreens.Select(a =>
 | ||
|                 {
 | ||
|                     if (rect.IntersectsWith(a.WorkingArea) || rect == a.WorkingArea || a.WorkingArea.Contains(rect) || rect.Contains(a.WorkingArea))
 | ||
|                     {
 | ||
|                         var r = rect;
 | ||
|                         r.Intersect(a.WorkingArea);
 | ||
|                         return new { sc = a, v = r.Width * r.Height };
 | ||
|                     }
 | ||
|                     else
 | ||
|                     {
 | ||
|                         return new { sc = a, v = 0f };
 | ||
|                     }
 | ||
|                 }).OrderByDescending(a => a.v).Select(a => a.sc).FirstOrDefault();
 | ||
|                 if (screen == null)
 | ||
|                 {
 | ||
|                     screen = Screen.AllScreens[0];
 | ||
|                 }
 | ||
|                 return screen;
 | ||
|             }
 | ||
|         }
 | ||
|         bool ismain;
 | ||
|         public bool IsMain
 | ||
|         {
 | ||
|             get
 | ||
|             {
 | ||
|                 return ismain;
 | ||
|             }
 | ||
| 
 | ||
|             set
 | ||
|             {
 | ||
|                 ismain = value;
 | ||
|                 if (value)
 | ||
|                 {
 | ||
|                     main = this;
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
|         public Size ClientSize => new Size(size.Width / RenderScaling, size.Height / RenderScaling);
 | ||
| 
 | ||
|         public float RenderScaling { get { return Application.BaseScale * ScreenImpl.DpiScale; } }
 | ||
| 
 | ||
|         public float LayoutScaling { get { return RenderScaling; } }
 | ||
| 
 | ||
|         public Action ScalingChanged { get; set; }
 | ||
|         public Action<Size> Resized { get; set; }
 | ||
|         public Action<PixelPoint> PositionChanged { get; set; }
 | ||
|         public Action Activated { get; set; }
 | ||
|         public Action Deactivated { get; set; }
 | ||
|         public bool CanActivate { get; set; } = true;
 | ||
|         public PixelPoint Position
 | ||
|         {
 | ||
|             get { return position; }
 | ||
|             set
 | ||
|             {
 | ||
|                 //if (!(this is PopWindow))
 | ||
|                 //{
 | ||
|                 //    Console.WriteLine(value);
 | ||
|                 //}
 | ||
|                 //if (this is PopWindow)
 | ||
|                 //{
 | ||
|                 position = value;
 | ||
|                 XMoveWindow(x11info.Display, Handle, value.X, value.Y);
 | ||
|                 return;
 | ||
|                 //}
 | ||
|                 //
 | ||
|                 //XMoveResizeWindow(x11info.Display, Handle, value.X, value.Y,size.Width,size.Height);
 | ||
| 
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         bool activate;
 | ||
|         public void Activate()
 | ||
|         {
 | ||
|             if (activate)
 | ||
|             {
 | ||
|                 return;
 | ||
|             }
 | ||
|             //if (x11info.Atoms._NET_ACTIVE_WINDOW != IntPtr.Zero)
 | ||
|             //{//这个鬼东西会有个系统消息提示
 | ||
|             //    SendNetWMMessage(x11info.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, x11info.LastActivityTimestamp,
 | ||
|             //        IntPtr.Zero);
 | ||
|             //}
 | ||
|             //else
 | ||
|             {
 | ||
|                 XRaiseWindow(x11info.Display, Handle);
 | ||
|                 XSetInputFocus(x11info.Display, Handle, 0, IntPtr.Zero);
 | ||
|             }
 | ||
|         }
 | ||
|         void SendNetWMMessage(IntPtr message_type, IntPtr l1,
 | ||
|          IntPtr? l2 = null, IntPtr? l3 = null, IntPtr? l4 = null, IntPtr? l5 = null)
 | ||
|         {
 | ||
|             var xev = new XEvent
 | ||
|             {
 | ||
|                 ClientMessageEvent =
 | ||
|                 {
 | ||
|                     type = XEventName.ClientMessage,
 | ||
|                     send_event = true,
 | ||
|                     window = Handle,
 | ||
|                     message_type = message_type,
 | ||
|                     format = 32,
 | ||
|                     //ptr1 = l1,
 | ||
|                     //ptr2 = l2 ?? IntPtr.Zero,
 | ||
|                     //ptr3 = l3 ?? IntPtr.Zero,
 | ||
|                     //ptr4 = l4 ?? IntPtr.Zero,
 | ||
|                     //ptr5 = l5 ?? IntPtr.Zero
 | ||
|                 }
 | ||
|             };
 | ||
|             xev.ClientMessageEvent.ptr1 = l1;
 | ||
|             xev.ClientMessageEvent.ptr2 = l2 ?? IntPtr.Zero;
 | ||
|             xev.ClientMessageEvent.ptr3 = l3 ?? IntPtr.Zero;
 | ||
|             xev.ClientMessageEvent.ptr4 = l4 ?? IntPtr.Zero;
 | ||
|             xev.ClientMessageEvent.ptr5 = l5 ?? IntPtr.Zero;
 | ||
|             lock (XlibLock)
 | ||
|             {
 | ||
|                 XSendEvent(x11info.Display, x11info.RootWindow, false,
 | ||
|                 new IntPtr((int)(EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev);
 | ||
|             }
 | ||
|             XFlush(x11info.Display);
 | ||
|         }
 | ||
| 
 | ||
|         public void Capture()
 | ||
|         {
 | ||
|             //throw new NotImplementedException();
 | ||
|         }
 | ||
| 
 | ||
|         public void Close()
 | ||
|         {
 | ||
|             if (Closing.Invoke() != true)
 | ||
|             {
 | ||
|                 Closed.Invoke();
 | ||
|                 Dispose();
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         bool paint = false;
 | ||
|         Rect invalidateRect;
 | ||
|         public void Invalidate(in Rect rect)
 | ||
|         {
 | ||
|             Rect all = new Rect(new Point(), root.ActualSize);//控件区域
 | ||
|             if ((all.Contains(rect) || rect.IntersectsWith(all) || all == rect || rect.Contains(all)) && !rect.IsEmpty && !all.IsEmpty)
 | ||
|             {
 | ||
|                 //Debug.WriteLine(invalidateRect);
 | ||
|                 if (invalidateRect.IsEmpty || rect.Contains(invalidateRect) || rect == invalidateRect)//如果更新区域大于原有失效区域,则当前失效区域设为更新区域
 | ||
|                 {
 | ||
|                     invalidateRect = rect;
 | ||
|                 }
 | ||
|                 else if (invalidateRect.Contains(rect))//如果更新区域小于原来的失效区域,则失效区域不变
 | ||
|                 {
 | ||
| 
 | ||
|                 }
 | ||
|                 else if (invalidateRect.IsEmpty)//如果原来的失效区域为空
 | ||
|                 {
 | ||
|                     invalidateRect = rect;
 | ||
|                 }
 | ||
|                 else
 | ||
|                 {//如果两个区域没有关联或者相交
 | ||
|                     var minX = invalidateRect.X < rect.X ? invalidateRect.X : rect.X;//确定包含这两个矩形的最小矩形
 | ||
|                     var minY = invalidateRect.Y < rect.Y ? invalidateRect.Y : rect.Y;
 | ||
|                     var maxW = (invalidateRect.Width + invalidateRect.X - minX) > (rect.Width + rect.X - minX) ? (invalidateRect.Width + invalidateRect.X - minX) : (rect.Width + rect.X - minX);
 | ||
|                     var maxH = (invalidateRect.Height + invalidateRect.Y - minY) > (rect.Height + rect.Y - minY) ? (invalidateRect.Height + invalidateRect.Y - minY) : (rect.Height + rect.Y - minY);
 | ||
|                     Rect min = new Rect(minX, minY, maxW, maxH);
 | ||
| 
 | ||
|                     invalidateRect = min;
 | ||
|                 }
 | ||
|                 invalidateRect.Intersect(all);//最后失效区域为在控件区域里面的相交区域
 | ||
|             }
 | ||
|             if (!paint)
 | ||
|             {
 | ||
|                 paint = true;
 | ||
|                 Threading.Dispatcher.MainThread.BeginInvoke(() =>
 | ||
|                {
 | ||
|                    root.LayoutManager.ExecuteLayoutPass();
 | ||
|                    //OnPaint(IntPtr.Zero, new Rect(((invalidateRect.X - 1) * scaling), ((invalidateRect.Y - 1) * scaling), ((invalidateRect.Width + 2) * scaling), ((invalidateRect.Height + 2) * scaling)));
 | ||
|                    var r = new Rect(((invalidateRect.X - 1) * RenderScaling), ((invalidateRect.Y - 1) * RenderScaling), ((invalidateRect.Width + 2) * RenderScaling), ((invalidateRect.Height + 2) * RenderScaling));
 | ||
|                    r.X = Math.Max(0, r.X);
 | ||
|                    r.Y = Math.Max(0, r.Y);
 | ||
|                    var xev = new XEvent
 | ||
|                    {
 | ||
|                        ExposeEvent =
 | ||
|                        {
 | ||
|                         type = XEventName.Expose,
 | ||
|                         send_event = true,
 | ||
|                         window = Handle,
 | ||
|                         count=1,
 | ||
|                         display=x11info.Display,
 | ||
|                         height=(int)r.Height+1,
 | ||
|                         width= (int)r.Width+1,
 | ||
|                         x=(int)r.X,
 | ||
|                         y= (int)r.Y
 | ||
|                        }
 | ||
|                    };
 | ||
|                    //Console.WriteLine("Invalidate:" + r);
 | ||
|                    lock (XlibLock)
 | ||
|                    {
 | ||
|                        XSendEvent(x11info.Display, Handle, false,
 | ||
|                            new IntPtr((int)(EventMask.ExposureMask)), ref xev);
 | ||
|                    }
 | ||
|                    invalidateRect = new Rect();
 | ||
|                    paint = false;
 | ||
|                    XFlush(x11info.Display);
 | ||
|                    //Console.WriteLine("Invalidate");
 | ||
|                });
 | ||
|             }
 | ||
| 
 | ||
|             //RECT r = new RECT((int)((rect.X - 1) * scaling), (int)((rect.Y - 1) * scaling), (int)((rect.Right + 2) * scaling), (int)((rect.Bottom + 2) * scaling));
 | ||
|             //InvalidateRect(handle, ref r, false);
 | ||
|         }
 | ||
|         public Point PointToClient(Point point)
 | ||
|         {
 | ||
|             return new Point((point.X - Position.X) / RenderScaling, (point.Y - Position.Y) / RenderScaling);
 | ||
|         }
 | ||
| 
 | ||
|         public Point PointToScreen(Point point)
 | ||
|         {
 | ||
|             return new Point(
 | ||
|             (int)(point.X * RenderScaling + Position.X),
 | ||
|             (int)(point.Y * RenderScaling + Position.Y));
 | ||
|         }
 | ||
| 
 | ||
|         public void ReleaseCapture()
 | ||
|         {
 | ||
|             //throw new NotImplementedException();
 | ||
|         }
 | ||
| 
 | ||
|         public void SetCursor(Cursor cursor)
 | ||
|         {
 | ||
|             XDefineCursor(x11info.Display, Handle, (IntPtr)cursor.PlatformCursor);
 | ||
|         }
 | ||
| 
 | ||
|         //bool fullscreen;
 | ||
|         //public void SetFullscreen(bool fullscreen)
 | ||
|         //{
 | ||
|         //    this.fullscreen = fullscreen;
 | ||
|         //    //XSetWindowAttributes attr = new XSetWindowAttributes();
 | ||
|         //    //var valueMask = SetWindowValuemask.OverrideRedirect;
 | ||
|         //    //attr.override_redirect = fullscreen;
 | ||
|         //    //XChangeWindowAttributes(x11info.Display, Handle, (ulong)valueMask, ref attr);
 | ||
|         //    //XMapWindow(x11info.Display, Handle);
 | ||
|         //    //XFlush(x11info.Display);
 | ||
|         //    ChangeWMAtoms(fullscreen, x11info.Atoms._NET_WM_STATE_FULLSCREEN);
 | ||
|         //    if (fullscreen)
 | ||
|         //    {
 | ||
|         //        lastRect = new Rect(position.X, position.Y, size.Width, size.Height);
 | ||
|         //        //var sc = Screen;
 | ||
|         //        //Resize(sc.Bounds.Size, true);
 | ||
|         //        //Position = new PixelPoint();
 | ||
|         //        _lastWindowState = WindowState.Maximized;
 | ||
|         //        WindowStateChanged?.Invoke();
 | ||
|         //    }
 | ||
|         //    else
 | ||
|         //    {
 | ||
|         //        if (_lastWindowState == WindowState.Maximized)
 | ||
|         //        {
 | ||
|         //            _lastWindowState = WindowState.Normal;
 | ||
|         //            WindowStateChanged?.Invoke();
 | ||
|         //        }
 | ||
|         //    }
 | ||
|         //}
 | ||
|         public void SetIcon(Image image)
 | ||
|         {
 | ||
|             if (image == null)
 | ||
|             {
 | ||
|                 XDeleteProperty(x11info.Display, Handle, x11info.Atoms._NET_WM_ICON);
 | ||
|                 return;
 | ||
|             }
 | ||
|             var _width = Math.Min(image.Width, 128);
 | ||
|             var _height = Math.Min(image.Height, 128);
 | ||
|             var _bdata = new uint[_width * _height];
 | ||
|             fixed (void* ptr = _bdata)
 | ||
|             {
 | ||
|                 var iptr = (int*)ptr;
 | ||
|                 iptr[0] = _width;
 | ||
|                 iptr[1] = _height;
 | ||
|             }
 | ||
| 
 | ||
|             var h = GCHandle.Alloc(_bdata, GCHandleType.Pinned);
 | ||
|             using (Bitmap bmp = new Bitmap(_width, _height, _width * 4, PixelFormat.Bgra, h.AddrOfPinnedObject()))
 | ||
|             {
 | ||
|                 using (var dc = DrawingContext.FromBitmap(bmp))
 | ||
|                 {
 | ||
|                     dc.DrawImage(image, new Rect(0, 0, _width, _height), new Rect(0, 0, image.Width, image.Height));
 | ||
|                 }
 | ||
|             }
 | ||
|             h.Free();
 | ||
| 
 | ||
| 
 | ||
|             var data = new UIntPtr[_width * _height + 2];
 | ||
|             data[0] = new UIntPtr((uint)_width);
 | ||
|             data[1] = new UIntPtr((uint)_height);
 | ||
|             for (var y = 0; y < _height; y++)
 | ||
|             {
 | ||
|                 var r = y * _width;
 | ||
|                 for (var x = 0; x < _width; x++)
 | ||
|                     data[r + x] = new UIntPtr(_bdata[r + x]);
 | ||
|             }
 | ||
| 
 | ||
|             fixed (void* pdata = data)
 | ||
|                 XChangeProperty(x11info.Display, Handle, x11info.Atoms._NET_WM_ICON,
 | ||
|                     new IntPtr((int)Atom.XA_CARDINAL), 32, PropertyMode.Replace,
 | ||
|                     pdata, data.Length);
 | ||
|         }
 | ||
| 
 | ||
|         public void SetIMEEnable(bool enable)
 | ||
|         {
 | ||
|             //throw new NotImplementedException();
 | ||
|             if (xic != IntPtr.Zero)
 | ||
|             {
 | ||
|                 //if (!enable)
 | ||
|                 //{
 | ||
|                 //    XUnsetICFocus(xic);
 | ||
|                 //}
 | ||
|                 //else
 | ||
|                 //{
 | ||
|                 XSetICFocus(xic);
 | ||
|                 //}
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         public void SetIMEPosition(Point point)
 | ||
|         {
 | ||
|             XPoint spot = new XPoint();
 | ||
|             spot.X = (short)point.X;
 | ||
|             spot.Y = (short)(point.Y + 20);
 | ||
| 
 | ||
|             IntPtr pSL = IntPtr.Zero;
 | ||
|             try
 | ||
|             {
 | ||
|                 pSL = Marshal.StringToHGlobalAnsi(XNames.XNSpotLocation);
 | ||
|                 IntPtr preedit = XVaCreateNestedList(0, pSL, spot, IntPtr.Zero);
 | ||
|                 XSetICValues(xic, XNames.XNPreeditAttributes, preedit, IntPtr.Zero);
 | ||
|             }
 | ||
|             finally
 | ||
|             {
 | ||
|                 if (pSL != IntPtr.Zero)
 | ||
|                     Marshal.FreeHGlobal(pSL);
 | ||
|             }
 | ||
|             //throw new NotImplementedException();
 | ||
|         }
 | ||
| 
 | ||
|         public void SetRoot(View view)
 | ||
|         {
 | ||
|             root = view;
 | ||
|             root.LayoutUpdated += Root_LayoutUpdated;
 | ||
|             //root.PropertyChanged += Root_PropertyChanged;
 | ||
|         }
 | ||
| 
 | ||
|         //private void Root_PropertyChanged(object sender, CPFPropertyChangedEventArgs e)
 | ||
|         //{
 | ||
|         //    if (e.PropertyName == nameof(Window.IsDragMove))
 | ||
|         //    {
 | ||
|         //        lock (XlibLock)
 | ||
|         //        {
 | ||
|         //            XEvent xEvent = new XEvent();
 | ||
|         //            var p = MouseDevice.Location;
 | ||
|         //            var display = x11info.Display;
 | ||
|         //            xEvent.ClientMessageEvent.type = XEventName.ClientMessage;
 | ||
|         //            xEvent.ClientMessageEvent.message_type = x11info.Atoms._NET_WM_MOVERESIZE;
 | ||
|         //            xEvent.ClientMessageEvent.display = display;
 | ||
|         //            xEvent.ClientMessageEvent.window = Handle;
 | ||
|         //            xEvent.ClientMessageEvent.format = 32;
 | ||
|         //            xEvent.ClientMessageEvent.ptr1 = (IntPtr)p.X;
 | ||
|         //            xEvent.ClientMessageEvent.ptr2 = (IntPtr)p.Y;
 | ||
|         //            xEvent.ClientMessageEvent.ptr3 = (IntPtr)8;
 | ||
|         //            xEvent.ClientMessageEvent.ptr4 = (IntPtr)1;
 | ||
|         //            XUngrabPointer(display, IntPtr.Zero);
 | ||
|         //            XSendEvent(display, x11info.RootWindow, false, (IntPtr)(EventMask.SubstructureNotifyMask | EventMask.SubstructureRedirectMask), ref xEvent);
 | ||
| 
 | ||
| 
 | ||
|         //            //p = MouseDevice.Location;
 | ||
|         //            XEvent xevent = new XEvent();
 | ||
|         //            xevent.type = XEventName.ButtonRelease;
 | ||
|         //            xevent.ButtonEvent.button = 1;
 | ||
|         //            xevent.ButtonEvent.window = Handle;
 | ||
|         //            xevent.ButtonEvent.x = p.X - position.X;
 | ||
|         //            xevent.ButtonEvent.y = p.Y - position.Y;
 | ||
|         //            xevent.ButtonEvent.x_root = p.X;
 | ||
|         //            xevent.ButtonEvent.y_root = p.X;
 | ||
|         //            xevent.ButtonEvent.display = display;
 | ||
|         //            xevent.ButtonEvent.state = XModifierMask.Button1Mask;
 | ||
| 
 | ||
|         //            XSendEvent(display, Handle, false, (IntPtr)EventMask.ButtonReleaseMask, ref xevent);
 | ||
|         //            XFlush(display);
 | ||
|         //        }
 | ||
|         //    }
 | ||
|         //}
 | ||
| 
 | ||
|         bool firstLayout = true;
 | ||
|         private void Root_LayoutUpdated(object sender, RoutedEventArgs e)
 | ||
|         {
 | ||
|             var b = position;
 | ||
|             var s = root.ActualSize;
 | ||
|             var l = root.ActualOffset;
 | ||
|             var src = root.Screen;
 | ||
|             if (size.Width != (int)Math.Ceiling(s.Width * RenderScaling) || size.Height != (int)Math.Ceiling(s.Height * RenderScaling) || b.X != (int)(l.X * RenderScaling + src.WorkingArea.X) || b.Y != (int)(l.Y * RenderScaling + src.WorkingArea.Y))
 | ||
|             {
 | ||
|                 //Bounds = new Rect(l.X * RenderScaling, l.Y * RenderScaling, s.Width * RenderScaling, s.Height * RenderScaling);
 | ||
|                 Position = new PixelPoint((int)(l.X * RenderScaling + src.WorkingArea.X), (int)(l.Y * RenderScaling + src.WorkingArea.Y));
 | ||
|                 Resize(s, false);
 | ||
|             }
 | ||
|             //Console.WriteLine("Root_LayoutUpdated" + l.ToString() + "," + s.ToString() + "----" + position);
 | ||
|         }
 | ||
| 
 | ||
|         public void SetTitle(string text)
 | ||
|         {
 | ||
|             var data = Encoding.UTF8.GetBytes(text);
 | ||
|             fixed (void* pdata = data)
 | ||
|             {
 | ||
|                 XChangeProperty(x11info.Display, Handle, x11info.Atoms._NET_WM_NAME, x11info.Atoms.UTF8_STRING, 8,
 | ||
|                     PropertyMode.Replace, pdata, data.Length);
 | ||
|                 XStoreName(x11info.Display, Handle, text);
 | ||
| 
 | ||
|                 //XSetIconName(x11info.Display, Handle, text);
 | ||
|                 //XTextProperty xTextProperty = new XTextProperty { encoding = x11info.Atoms.UTF8_STRING, format = 8, value = (IntPtr)pdata, nitems = (IntPtr)data.Length };
 | ||
|                 //XSetWMIconName(x11info.Display, Handle, ref xTextProperty);
 | ||
|                 //XSetWMName(x11info.Display, Handle, ref xTextProperty);
 | ||
|                 //Console.WriteLine(r);
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         public void SetVisible(bool visible)
 | ||
|         {
 | ||
|             if (visible)
 | ||
|             {
 | ||
|                 XMapWindow(x11info.Display, Handle);
 | ||
|                 root.LayoutManager.ExecuteLayoutPass();
 | ||
|                 root.Visibility = Visibility.Visible;
 | ||
|                 if (CanActivate)
 | ||
|                 {
 | ||
|                     Activate();
 | ||
|                 }
 | ||
|                 else
 | ||
|                 {
 | ||
|                     XRaiseWindow(x11info.Display, Handle);
 | ||
|                 }
 | ||
|                 Position = position;
 | ||
|                 //XFlush(x11info.Display);
 | ||
|                 //Console.WriteLine("显示后:" + position);
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 activate = false;
 | ||
|                 //position = new PixelPoint();
 | ||
|                 XUnmapWindow(x11info.Display, Handle);
 | ||
|             }
 | ||
|         }
 | ||
|         //private HashSet<X11Window> _transientChildren = new HashSet<X11Window>();
 | ||
|         public bool ActivateTransientChildIfNeeded()
 | ||
|         {
 | ||
|             return _disabled;
 | ||
|             //if (_disabled)
 | ||
|             //{
 | ||
|             //    return true;
 | ||
|             //}
 | ||
|             //if (_transientChildren.Count == 0)
 | ||
|             //    return false;
 | ||
|             //var child = _transientChildren.First();
 | ||
|             //if (!child.ActivateTransientChildIfNeeded())
 | ||
|             //    child.Activate();
 | ||
|             //return true;
 | ||
|         }
 | ||
|         void SetTransientParent(X11Window window, bool informServer = true)
 | ||
|         {
 | ||
|             //parent?._transientChildren.Remove(this);
 | ||
|             //parent = window;
 | ||
|             //parent?._transientChildren.Add(this);
 | ||
|             if (informServer)
 | ||
|                 XSetTransientForHint(x11info.Display, Handle, window?.Handle ?? IntPtr.Zero);
 | ||
|         }
 | ||
|         public void ShowDialog(Window window)
 | ||
|         {
 | ||
|             SetTransientParent((X11Window)window.ViewImpl);
 | ||
|             XMapWindow(x11info.Display, Handle);
 | ||
|             XFlush(x11info.Display);
 | ||
|             root.LayoutManager.ExecuteLayoutPass();
 | ||
|             root.Visibility = Visibility.Visible;
 | ||
|         }
 | ||
| 
 | ||
|         public void ShowInTaskbar(bool value)
 | ||
|         {
 | ||
|             ChangeWMAtoms(!value, x11info.Atoms._NET_WM_STATE_SKIP_TASKBAR);
 | ||
|         }
 | ||
| 
 | ||
|         public void TopMost(bool value)
 | ||
|         {
 | ||
|             ChangeWMAtoms(value, x11info.Atoms._NET_WM_STATE_ABOVE);
 | ||
|         }
 | ||
| 
 | ||
|         void ChangeWMAtoms(bool enable, params IntPtr[] atoms)
 | ||
|         {
 | ||
|             if (atoms.Length < 1 || atoms.Length > 4)
 | ||
|                 throw new ArgumentException();
 | ||
| 
 | ||
|             //if (!_mapped)
 | ||
|             {
 | ||
|                 XGetWindowProperty(x11info.Display, Handle, x11info.Atoms._NET_WM_STATE, IntPtr.Zero, new IntPtr(256),
 | ||
|                     false, (IntPtr)Atom.XA_ATOM, out _, out _, out var nitems, out _,
 | ||
|                     out var prop);
 | ||
|                 var ptr = (IntPtr*)prop.ToPointer();
 | ||
|                 var newAtoms = new HashSet<IntPtr>();
 | ||
|                 for (var c = 0; c < nitems.ToInt64(); c++)
 | ||
|                     newAtoms.Add(*ptr);
 | ||
|                 XFree(prop);
 | ||
|                 foreach (var atom in atoms)
 | ||
|                     if (enable)
 | ||
|                         newAtoms.Add(atom);
 | ||
|                     else
 | ||
|                         newAtoms.Remove(atom);
 | ||
| 
 | ||
|                 XChangeProperty(x11info.Display, Handle, x11info.Atoms._NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32,
 | ||
|                     PropertyMode.Replace, newAtoms.ToArray(), newAtoms.Count);
 | ||
|             }
 | ||
| 
 | ||
|             SendNetWMMessage(x11info.Atoms._NET_WM_STATE,
 | ||
|                 (IntPtr)(enable ? 1 : 0),
 | ||
|                 atoms[0],
 | ||
|                 atoms.Length > 1 ? atoms[1] : IntPtr.Zero,
 | ||
|                 atoms.Length > 2 ? atoms[2] : IntPtr.Zero,
 | ||
|                 atoms.Length > 3 ? atoms[3] : IntPtr.Zero
 | ||
|             );
 | ||
|         }
 | ||
| 
 | ||
|         protected override void Dispose(bool disposing)
 | ||
|         {
 | ||
|             context?.Dispose();
 | ||
|             context = null;
 | ||
|             SetTransientParent(null, false);
 | ||
|             if (xic != IntPtr.Zero)
 | ||
|             {
 | ||
|                 XDestroyIC(xic);
 | ||
|                 xic = IntPtr.Zero;
 | ||
|             }
 | ||
|             if (bitmap != null)
 | ||
|             {
 | ||
|                 bitmap.Dispose();
 | ||
|                 bitmap = null;
 | ||
|             }
 | ||
|             base.Dispose(disposing);
 | ||
|             if (ismain)
 | ||
|             {
 | ||
|                 LinuxPlatform.Platform.run = false;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         bool _disabled;
 | ||
|         public void SetEnable(bool enable)
 | ||
|         {
 | ||
|             _disabled = !enable;
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     public class PopWindow : X11Window, IPopupImpl
 | ||
|     {
 | ||
| 
 | ||
|     }
 | ||
| }
 | 
