mirror of
https://gitee.com/csharpui/CPF.git
synced 2025-04-04 23:39:26 +08:00
1802 lines
76 KiB
C#
1802 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);
|
||
var offset = 2;
|
||
for (var y = 0; y < _height; y++)
|
||
{
|
||
var r = y * _width;
|
||
for (var x = 0; x < _width; x++)
|
||
data[r + x + offset] = 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
|
||
{
|
||
|
||
}
|
||
}
|