2023-11-21 23:05:03 +08:00
|
|
|
|
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);
|
2025-01-10 17:44:19 +08:00
|
|
|
|
var offset = 2;
|
2023-11-21 23:05:03 +08:00
|
|
|
|
for (var y = 0; y < _height; y++)
|
|
|
|
|
{
|
|
|
|
|
var r = y * _width;
|
|
|
|
|
for (var x = 0; x < _width; x++)
|
2025-01-10 17:44:19 +08:00
|
|
|
|
data[r + x + offset] = new UIntPtr(_bdata[r + x]);
|
2023-11-21 23:05:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|