|
|
@@ -1,404 +1,118 @@
|
|
|
-// Copyright (c) The Avalonia Project. All rights reserved.
|
|
|
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
|
-
|
|
|
using System;
|
|
|
using System.Reactive.Disposables;
|
|
|
-using System.Runtime.InteropServices;
|
|
|
-using Gdk;
|
|
|
-using Avalonia.Controls;
|
|
|
-using Avalonia.Input.Raw;
|
|
|
using Avalonia.Platform;
|
|
|
-using Avalonia.Input;
|
|
|
-using Avalonia.Threading;
|
|
|
-using Action = System.Action;
|
|
|
-using WindowEdge = Avalonia.Controls.WindowEdge;
|
|
|
+using Gdk;
|
|
|
|
|
|
namespace Avalonia.Gtk
|
|
|
{
|
|
|
using Gtk = global::Gtk;
|
|
|
-
|
|
|
- public class WindowImpl : Gtk.Window, IWindowImpl, IPlatformHandle
|
|
|
+ public class WindowImpl : WindowImplBase
|
|
|
{
|
|
|
- private IInputRoot _inputRoot;
|
|
|
+ private Gtk.Window _window;
|
|
|
+ private Gtk.Window Window => _window ?? (_window = (Gtk.Window) Widget);
|
|
|
|
|
|
- private Size _lastClientSize;
|
|
|
|
|
|
- private Gtk.IMContext _imContext;
|
|
|
|
|
|
- private uint _lastKeyEventTimestamp;
|
|
|
-
|
|
|
- private static readonly Gdk.Cursor DefaultCursor = new Gdk.Cursor(CursorType.LeftPtr);
|
|
|
-
|
|
|
- public WindowImpl()
|
|
|
- : base(Gtk.WindowType.Toplevel)
|
|
|
+ public WindowImpl(Gtk.WindowType type) : base(new PlatformHandleAwareWindow(type))
|
|
|
{
|
|
|
- DefaultSize = new Gdk.Size(900, 480);
|
|
|
Init();
|
|
|
}
|
|
|
|
|
|
- public WindowImpl(Gtk.WindowType type)
|
|
|
- : base(type)
|
|
|
+ public WindowImpl()
|
|
|
+ : base(new PlatformHandleAwareWindow(Gtk.WindowType.Toplevel) {DefaultSize = new Gdk.Size(900, 480)})
|
|
|
{
|
|
|
Init();
|
|
|
}
|
|
|
|
|
|
- private void Init()
|
|
|
+ void Init()
|
|
|
{
|
|
|
- Events = EventMask.PointerMotionMask |
|
|
|
- EventMask.ButtonPressMask |
|
|
|
- EventMask.ButtonReleaseMask;
|
|
|
- _imContext = new Gtk.IMMulticontext();
|
|
|
- _imContext.Commit += ImContext_Commit;
|
|
|
- DoubleBuffered = false;
|
|
|
- Realize();
|
|
|
+ Window.FocusActivated += OnFocusActivated;
|
|
|
+ Window.ConfigureEvent += OnConfigureEvent;
|
|
|
_lastClientSize = ClientSize;
|
|
|
}
|
|
|
-
|
|
|
- protected override void OnRealized ()
|
|
|
- {
|
|
|
- base.OnRealized ();
|
|
|
- _imContext.ClientWindow = this.GdkWindow;
|
|
|
- }
|
|
|
-
|
|
|
- public Size ClientSize
|
|
|
+ private Size _lastClientSize;
|
|
|
+ void OnConfigureEvent(object o, Gtk.ConfigureEventArgs args)
|
|
|
{
|
|
|
- get
|
|
|
- {
|
|
|
- int width;
|
|
|
- int height;
|
|
|
- GetSize(out width, out height);
|
|
|
- return new Size(width, height);
|
|
|
- }
|
|
|
-
|
|
|
- set
|
|
|
- {
|
|
|
- Resize((int)value.Width, (int)value.Height);
|
|
|
- }
|
|
|
- }
|
|
|
+ var evnt = args.Event;
|
|
|
+ args.RetVal = true;
|
|
|
+ var newSize = new Size(evnt.Width, evnt.Height);
|
|
|
|
|
|
- public Size MaxClientSize
|
|
|
- {
|
|
|
- get
|
|
|
+ if (newSize != _lastClientSize)
|
|
|
{
|
|
|
- // TODO: This should take into account things such as taskbar and window border
|
|
|
- // thickness etc.
|
|
|
- return new Size(Screen.Width, Screen.Height);
|
|
|
+ Resized(newSize);
|
|
|
+ _lastClientSize = newSize;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public Avalonia.Controls.WindowState WindowState
|
|
|
+ public override Size ClientSize
|
|
|
{
|
|
|
get
|
|
|
{
|
|
|
- switch (GdkWindow.State)
|
|
|
- {
|
|
|
- case Gdk.WindowState.Iconified:
|
|
|
- return Controls.WindowState.Minimized;
|
|
|
- case Gdk.WindowState.Maximized:
|
|
|
- return Controls.WindowState.Maximized;
|
|
|
- default:
|
|
|
- return Controls.WindowState.Normal;
|
|
|
- }
|
|
|
+ int width;
|
|
|
+ int height;
|
|
|
+ Window.GetSize(out width, out height);
|
|
|
+ return new Size(width, height);
|
|
|
}
|
|
|
|
|
|
set
|
|
|
{
|
|
|
- switch (value)
|
|
|
- {
|
|
|
- case Controls.WindowState.Minimized:
|
|
|
- GdkWindow.Iconify();
|
|
|
- break;
|
|
|
- case Controls.WindowState.Maximized:
|
|
|
- GdkWindow.Maximize();
|
|
|
- break;
|
|
|
- case Controls.WindowState.Normal:
|
|
|
- GdkWindow.Deiconify();
|
|
|
- GdkWindow.Unmaximize();
|
|
|
- break;
|
|
|
- }
|
|
|
+ Window.Resize((int)value.Width, (int)value.Height);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public double Scaling => 1;
|
|
|
-
|
|
|
- IPlatformHandle ITopLevelImpl.Handle => this;
|
|
|
-
|
|
|
- [DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
|
|
|
- extern static IntPtr gdk_win32_drawable_get_handle(IntPtr gdkWindow);
|
|
|
-
|
|
|
- [DllImport("libgtk-x11-2.0.so.0", CallingConvention = CallingConvention.Cdecl)]
|
|
|
- extern static IntPtr gdk_x11_drawable_get_xid(IntPtr gdkWindow);
|
|
|
-
|
|
|
- [DllImport("libgdk-quartz-2.0-0.dylib", CallingConvention = CallingConvention.Cdecl)]
|
|
|
- extern static IntPtr gdk_quartz_window_get_nswindow(IntPtr gdkWindow);
|
|
|
-
|
|
|
- IntPtr _nativeWindow;
|
|
|
-
|
|
|
- IntPtr GetNativeWindow()
|
|
|
+ public override void SetTitle(string title)
|
|
|
{
|
|
|
- IntPtr h = GdkWindow.Handle;
|
|
|
- if (_nativeWindow != IntPtr.Zero)
|
|
|
- return _nativeWindow;
|
|
|
- //Try whatever backend that works
|
|
|
- try
|
|
|
- {
|
|
|
- return _nativeWindow = gdk_quartz_window_get_nswindow(h);
|
|
|
- }
|
|
|
- catch
|
|
|
- {
|
|
|
- }
|
|
|
- try
|
|
|
- {
|
|
|
- return _nativeWindow = gdk_x11_drawable_get_xid(h);
|
|
|
- }
|
|
|
- catch
|
|
|
- {
|
|
|
- }
|
|
|
- return _nativeWindow = gdk_win32_drawable_get_handle(h);
|
|
|
+ Window.Title = title;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- IntPtr IPlatformHandle.Handle => GetNativeWindow();
|
|
|
- public string HandleDescriptor => "HWND";
|
|
|
-
|
|
|
- public Action Activated { get; set; }
|
|
|
-
|
|
|
- public Action Closed { get; set; }
|
|
|
-
|
|
|
- public Action Deactivated { get; set; }
|
|
|
-
|
|
|
- public Action<RawInputEventArgs> Input { get; set; }
|
|
|
-
|
|
|
- public Action<Rect> Paint { get; set; }
|
|
|
-
|
|
|
- public Action<Size> Resized { get; set; }
|
|
|
-
|
|
|
- public Action<double> ScalingChanged { get; set; }
|
|
|
-
|
|
|
- public IPopupImpl CreatePopup()
|
|
|
- {
|
|
|
- return new PopupImpl();
|
|
|
- }
|
|
|
-
|
|
|
- public void Invalidate(Rect rect)
|
|
|
- {
|
|
|
- if (base.GdkWindow != null)
|
|
|
- base.GdkWindow.InvalidateRect(
|
|
|
- new Rectangle((int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height), true);
|
|
|
- }
|
|
|
-
|
|
|
- public Point PointToClient(Point point)
|
|
|
+ void OnFocusActivated(object sender, EventArgs eventArgs)
|
|
|
{
|
|
|
- int x, y;
|
|
|
- GdkWindow.GetDeskrelativeOrigin(out x, out y);
|
|
|
-
|
|
|
- return new Point(point.X - x, point.Y - y);
|
|
|
- }
|
|
|
-
|
|
|
- public Point PointToScreen(Point point)
|
|
|
- {
|
|
|
- int x, y;
|
|
|
- GdkWindow.GetDeskrelativeOrigin(out x, out y);
|
|
|
-
|
|
|
- return new Point(point.X + x, point.Y + y);
|
|
|
- }
|
|
|
-
|
|
|
- public void SetInputRoot(IInputRoot inputRoot)
|
|
|
- {
|
|
|
- _inputRoot = inputRoot;
|
|
|
- }
|
|
|
-
|
|
|
- public void SetTitle(string title)
|
|
|
- {
|
|
|
- Title = title;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- public void SetCursor(IPlatformHandle cursor)
|
|
|
- {
|
|
|
- GdkWindow.Cursor = cursor != null ? new Gdk.Cursor(cursor.Handle) : DefaultCursor;
|
|
|
+ Activated();
|
|
|
}
|
|
|
|
|
|
- public void BeginMoveDrag()
|
|
|
+ public override void BeginMoveDrag()
|
|
|
{
|
|
|
int x, y;
|
|
|
ModifierType mod;
|
|
|
- Screen.RootWindow.GetPointer(out x, out y, out mod);
|
|
|
- BeginMoveDrag(1, x, y, 0);
|
|
|
+ Window.Screen.RootWindow.GetPointer(out x, out y, out mod);
|
|
|
+ Window.BeginMoveDrag(1, x, y, 0);
|
|
|
}
|
|
|
|
|
|
- public void BeginResizeDrag(WindowEdge edge)
|
|
|
+ public override void BeginResizeDrag(Controls.WindowEdge edge)
|
|
|
{
|
|
|
int x, y;
|
|
|
ModifierType mod;
|
|
|
- Screen.RootWindow.GetPointer(out x, out y, out mod);
|
|
|
- BeginResizeDrag((Gdk.WindowEdge) (int) edge, 1, x, y, 0);
|
|
|
+ Window.Screen.RootWindow.GetPointer(out x, out y, out mod);
|
|
|
+ Window.BeginResizeDrag((Gdk.WindowEdge)(int)edge, 1, x, y, 0);
|
|
|
}
|
|
|
|
|
|
- public Point Position
|
|
|
+ public override Point Position
|
|
|
{
|
|
|
get
|
|
|
{
|
|
|
int x, y;
|
|
|
- GetPosition(out x, out y);
|
|
|
+ Window.GetPosition(out x, out y);
|
|
|
return new Point(x, y);
|
|
|
}
|
|
|
set
|
|
|
{
|
|
|
- Move((int)value.X, (int)value.Y);
|
|
|
+ Window.Move((int)value.X, (int)value.Y);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public IDisposable ShowDialog()
|
|
|
+ public override IDisposable ShowDialog()
|
|
|
{
|
|
|
- Modal = true;
|
|
|
- Show();
|
|
|
+ Window.Modal = true;
|
|
|
+ Window.Show();
|
|
|
|
|
|
return Disposable.Empty;
|
|
|
}
|
|
|
|
|
|
- public void SetSystemDecorations(bool enabled) => Decorated = enabled;
|
|
|
-
|
|
|
- void ITopLevelImpl.Activate()
|
|
|
- {
|
|
|
- Activate();
|
|
|
- }
|
|
|
-
|
|
|
- private static InputModifiers GetModifierKeys(ModifierType state)
|
|
|
- {
|
|
|
- var rv = InputModifiers.None;
|
|
|
- if (state.HasFlag(ModifierType.ControlMask))
|
|
|
- rv |= InputModifiers.Control;
|
|
|
- if (state.HasFlag(ModifierType.ShiftMask))
|
|
|
- rv |= InputModifiers.Shift;
|
|
|
- if (state.HasFlag(ModifierType.Mod1Mask))
|
|
|
- rv |= InputModifiers.Control;
|
|
|
- if(state.HasFlag(ModifierType.Button1Mask))
|
|
|
- rv |= InputModifiers.LeftMouseButton;
|
|
|
- if (state.HasFlag(ModifierType.Button2Mask))
|
|
|
- rv |= InputModifiers.RightMouseButton;
|
|
|
- if (state.HasFlag(ModifierType.Button3Mask))
|
|
|
- rv |= InputModifiers.MiddleMouseButton;
|
|
|
- return rv;
|
|
|
- }
|
|
|
-
|
|
|
- protected override bool OnButtonPressEvent(EventButton evnt)
|
|
|
- {
|
|
|
-
|
|
|
- var e = new RawMouseEventArgs(
|
|
|
- GtkMouseDevice.Instance,
|
|
|
- evnt.Time,
|
|
|
- _inputRoot,
|
|
|
- evnt.Button == 1
|
|
|
- ? RawMouseEventType.LeftButtonDown
|
|
|
- : evnt.Button == 3 ? RawMouseEventType.RightButtonDown : RawMouseEventType.MiddleButtonDown,
|
|
|
- new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
|
|
|
- Input(e);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- protected override bool OnScrollEvent(EventScroll evnt)
|
|
|
- {
|
|
|
- double step = 1;
|
|
|
- var delta = new Vector();
|
|
|
- if (evnt.Direction == ScrollDirection.Down)
|
|
|
- delta = new Vector(0, -step);
|
|
|
- else if (evnt.Direction == ScrollDirection.Up)
|
|
|
- delta = new Vector(0, step);
|
|
|
- else if (evnt.Direction == ScrollDirection.Right)
|
|
|
- delta = new Vector(-step, 0);
|
|
|
- if (evnt.Direction == ScrollDirection.Left)
|
|
|
- delta = new Vector(step, 0);
|
|
|
- var e = new RawMouseWheelEventArgs(GtkMouseDevice.Instance, evnt.Time, _inputRoot, new Point(evnt.X, evnt.Y), delta, GetModifierKeys(evnt.State));
|
|
|
- Input(e);
|
|
|
- return base.OnScrollEvent(evnt);
|
|
|
- }
|
|
|
-
|
|
|
- protected override bool OnButtonReleaseEvent(EventButton evnt)
|
|
|
- {
|
|
|
- var e = new RawMouseEventArgs(
|
|
|
- GtkMouseDevice.Instance,
|
|
|
- evnt.Time,
|
|
|
- _inputRoot,
|
|
|
- evnt.Button == 1
|
|
|
- ? RawMouseEventType.LeftButtonUp
|
|
|
- : evnt.Button == 3 ? RawMouseEventType.RightButtonUp : RawMouseEventType.MiddleButtonUp,
|
|
|
- new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
|
|
|
- Input(e);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- protected override bool OnConfigureEvent(EventConfigure evnt)
|
|
|
- {
|
|
|
- var newSize = new Size(evnt.Width, evnt.Height);
|
|
|
-
|
|
|
- if (newSize != _lastClientSize)
|
|
|
- {
|
|
|
- Resized(newSize);
|
|
|
- _lastClientSize = newSize;
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- protected override void OnDestroyed()
|
|
|
- {
|
|
|
- Closed();
|
|
|
- }
|
|
|
-
|
|
|
- private bool ProcessKeyEvent(EventKey evnt)
|
|
|
- {
|
|
|
- _lastKeyEventTimestamp = evnt.Time;
|
|
|
- if (_imContext.FilterKeypress(evnt))
|
|
|
- return true;
|
|
|
- var e = new RawKeyEventArgs(
|
|
|
- GtkKeyboardDevice.Instance,
|
|
|
- evnt.Time,
|
|
|
- evnt.Type == EventType.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
|
|
|
- GtkKeyboardDevice.ConvertKey(evnt.Key), GetModifierKeys(evnt.State));
|
|
|
- Input(e);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- protected override bool OnKeyPressEvent(EventKey evnt) => ProcessKeyEvent(evnt);
|
|
|
-
|
|
|
- protected override bool OnKeyReleaseEvent(EventKey evnt) => ProcessKeyEvent(evnt);
|
|
|
-
|
|
|
- private void ImContext_Commit(object o, Gtk.CommitArgs args)
|
|
|
- {
|
|
|
- Input(new RawTextInputEventArgs(GtkKeyboardDevice.Instance, _lastKeyEventTimestamp, args.Str));
|
|
|
- }
|
|
|
-
|
|
|
- protected override bool OnExposeEvent(EventExpose evnt)
|
|
|
- {
|
|
|
- Paint(evnt.Area.ToAvalonia());
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- protected override void OnFocusActivated()
|
|
|
- {
|
|
|
- Activated();
|
|
|
- }
|
|
|
-
|
|
|
- protected override bool OnMotionNotifyEvent(EventMotion evnt)
|
|
|
- {
|
|
|
- var position = new Point(evnt.X, evnt.Y);
|
|
|
-
|
|
|
- GtkMouseDevice.Instance.SetClientPosition(position);
|
|
|
-
|
|
|
- var e = new RawMouseEventArgs(
|
|
|
- GtkMouseDevice.Instance,
|
|
|
- evnt.Time,
|
|
|
- _inputRoot,
|
|
|
- RawMouseEventType.Move,
|
|
|
- position, GetModifierKeys(evnt.State));
|
|
|
- Input(e);
|
|
|
- return true;
|
|
|
- }
|
|
|
+ public override void SetSystemDecorations(bool enabled) => Window.Decorated = enabled;
|
|
|
|
|
|
- public void SetIcon(IWindowIconImpl icon)
|
|
|
+ public override void SetIcon(IWindowIconImpl icon)
|
|
|
{
|
|
|
- Icon = ((IconImpl)icon).Pixbuf;
|
|
|
+ Window.Icon = ((IconImpl)icon).Pixbuf;
|
|
|
}
|
|
|
}
|
|
|
-}
|
|
|
+}
|