Browse Source

WIP refactoring Window.

To make it x-platform. Currently breaks input.
pull/10/head
Steven Kirk 11 years ago
parent
commit
c999d45e94
  1. 1
      Perspex.Base/Perspex.Base.csproj
  2. 26
      Perspex.Base/Platform/IPlatformHandle.cs
  3. 2
      Perspex.Controls/Perspex.Controls.csproj
  4. 33
      Perspex.Controls/Platform/IWindowImpl.cs
  5. 156
      Perspex.Controls/Window.cs
  6. 1
      Perspex.Input/Perspex.Input.csproj
  7. 5
      Perspex.Input/Raw/RawInputEventArgs.cs
  8. 1
      Perspex.Input/Raw/RawMouseEventArgs.cs
  9. 25
      Perspex.Input/Raw/RawSizeEventArgs.cs
  10. 2
      Perspex.SceneGraph/Platform/IPlatformRenderInterface.cs
  11. 1
      Perspex.Themes.Default/DefaultTheme.cs
  12. 1
      Perspex.Themes.Default/Perspex.Themes.Default.csproj
  13. 43
      Perspex.Themes.Default/WindowStyle.cs
  14. 13
      Windows/Perspex.Direct2D1/Direct2D1Platform.cs
  15. 1
      Windows/Perspex.Win32/Input/WindowsKeyboardDevice.cs
  16. 4
      Windows/Perspex.Win32/Input/WindowsMouseDevice.cs
  17. 2
      Windows/Perspex.Win32/Perspex.Win32.csproj
  18. 1
      Windows/Perspex.Win32/Win32Platform.cs
  19. 179
      Windows/Perspex.Win32/WindowImpl.cs

1
Perspex.Base/Perspex.Base.csproj

@ -45,6 +45,7 @@
<Compile Include="PerspexObject.cs" />
<Compile Include="PerspexProperty.cs" />
<Compile Include="PerspexPropertyChangedEventArgs.cs" />
<Compile Include="Platform\IPlatformHandle.cs" />
<Compile Include="Platform\IPlatformThreadingInterface.cs" />
<Compile Include="PriorityValue.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

26
Perspex.Base/Platform/IPlatformHandle.cs

@ -0,0 +1,26 @@
// -----------------------------------------------------------------------
// <copyright file="Window.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Platform
{
using System;
/// <summary>
/// Represents a platform-specific handle.
/// </summary>
public interface IPlatformHandle
{
/// <summary>
/// Gets the handle.
/// </summary>
IntPtr Handle { get; }
/// <summary>
/// Gets an optional string that describes what <see cref="Handle"/> represents.
/// </summary>
string HandleDescriptor { get; }
}
}

2
Perspex.Controls/Perspex.Controls.csproj

@ -41,6 +41,7 @@
<Compile Include="ColumnDefinitions.cs" />
<Compile Include="ContentControl.cs" />
<Compile Include="GridSplitter.cs" />
<Compile Include="Platform\IWindowImpl.cs" />
<Compile Include="Presenters\ScrollContentPresenter.cs" />
<Compile Include="Presenters\ContentPresenter.cs" />
<Compile Include="Control.cs" />
@ -69,6 +70,7 @@
<Compile Include="Panel.cs" />
<Compile Include="Primitives\Track.cs" />
<Compile Include="Primitives\Thumb.cs" />
<Compile Include="Window.cs" />
<Compile Include="RowDefinition.cs" />
<Compile Include="RowDefinitions.cs" />
<Compile Include="Primitives\SelectingItemsControl.cs" />

33
Perspex.Controls/Platform/IWindowImpl.cs

@ -0,0 +1,33 @@
// -----------------------------------------------------------------------
// <copyright file="IWindowImpl.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Platform
{
using System;
using Perspex.Controls;
using Perspex.Input.Raw;
public interface IWindowImpl
{
event EventHandler Activated;
event EventHandler Closed;
event EventHandler<RawInputEventArgs> Input;
event EventHandler<RawSizeEventArgs> Resized;
Size ClientSize { get; }
IPlatformHandle Handle { get; }
void SetTitle(string title);
void SetOwner(Window window);
void Show();
}
}

156
Perspex.Controls/Window.cs

@ -0,0 +1,156 @@
// -----------------------------------------------------------------------
// <copyright file="Window.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls
{
using System;
using System.Reactive.Linq;
using Perspex.Input;
using Perspex.Layout;
using Perspex.Media;
using Perspex.Platform;
using Perspex.Rendering;
using Perspex.Styling;
using Perspex.Threading;
using Splat;
public class Window : ContentControl, ILayoutRoot, IRenderRoot, ICloseable
{
public static readonly PerspexProperty<Size> ClientSizeProperty =
PerspexProperty.Register<Window, Size>("ClientSize");
public static readonly PerspexProperty<string> TitleProperty =
PerspexProperty.Register<Window, string>("Title", "Window");
private IWindowImpl impl;
private Dispatcher dispatcher;
private IRenderer renderer;
private IInputManager inputManager;
public event EventHandler Activated;
public event EventHandler Closed;
static Window()
{
BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White);
}
public Window()
{
IPlatformRenderInterface renderInterface = Locator.Current.GetService<IPlatformRenderInterface>();
this.impl = Locator.Current.GetService<IWindowImpl>();
this.inputManager = Locator.Current.GetService<IInputManager>();
if (this.impl == null)
{
throw new InvalidOperationException(
"Could not create window implementation: maybe no windowing subsystem was initialized?");
}
if (this.inputManager == null)
{
throw new InvalidOperationException(
"Could not create input manager: maybe Application.RegisterServices() wasn't called?");
}
this.impl.SetOwner(this);
this.impl.Activated += this.HandleActivated;
this.impl.Closed += this.HandleClosed;
Size clientSize = this.ClientSize = this.impl.ClientSize;
this.dispatcher = Dispatcher.UIThread;
this.renderer = renderInterface.CreateRenderer(this.impl.Handle, clientSize.Width, clientSize.Height);
this.LayoutManager = new LayoutManager(this);
this.LayoutManager.LayoutNeeded.Subscribe(_ => this.HandleLayoutNeeded());
this.RenderManager = new RenderManager();
this.RenderManager.RenderNeeded.Subscribe(_ => this.HandleRenderNeeded());
this.GetObservable(TitleProperty).Subscribe(s => this.impl.SetTitle(s));
IStyler styler = Locator.Current.GetService<IStyler>();
styler.ApplyStyles(this);
}
public Size ClientSize
{
get { return this.GetValue(ClientSizeProperty); }
set { this.SetValue(ClientSizeProperty, value); }
}
public string Title
{
get { return this.GetValue(TitleProperty); }
set { this.SetValue(TitleProperty, value); }
}
public ILayoutManager LayoutManager
{
get;
private set;
}
public IRenderManager RenderManager
{
get;
private set;
}
public void Show()
{
this.impl.Show();
this.LayoutPass();
}
private void HandleActivated(object sender, EventArgs e)
{
if (this.Activated != null)
{
this.Activated(this, EventArgs.Empty);
}
}
private void HandleClosed(object sender, EventArgs e)
{
if (this.Closed != null)
{
this.Closed(this, EventArgs.Empty);
}
}
private void HandleLayoutNeeded()
{
this.dispatcher.InvokeAsync(this.LayoutPass, DispatcherPriority.Render);
}
private void HandleRenderNeeded()
{
this.dispatcher.InvokeAsync(this.RenderVisualTree, DispatcherPriority.Render);
}
private void LayoutPass()
{
this.LayoutManager.ExecuteLayoutPass();
this.renderer.Render(this);
this.RenderManager.RenderFinished();
}
private void RenderVisualTree()
{
if (!this.LayoutManager.LayoutQueued)
{
this.renderer.Render(this);
this.RenderManager.RenderFinished();
}
}
}
}

1
Perspex.Input/Perspex.Input.csproj

@ -66,6 +66,7 @@
<Compile Include="IPointerDevice.cs" />
<Compile Include="Key.cs" />
<Compile Include="KeyboardDevice.cs" />
<Compile Include="Raw\RawSizeEventArgs.cs" />
<Compile Include="VectorEventArgs.cs" />
<Compile Include="KeyEventArgs.cs" />
<Compile Include="MouseDevice.cs" />

5
Perspex.Input/Raw/RawInputEventArgs.cs

@ -7,11 +7,6 @@
namespace Perspex.Input.Raw
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Perspex.Layout;
public class RawInputEventArgs : EventArgs
{

1
Perspex.Input/Raw/RawMouseEventArgs.cs

@ -33,6 +33,7 @@ namespace Perspex.Input.Raw
this.Type = type;
}
//TODO: This should probably be IInputRoot or something.
public ILayoutRoot Root { get; private set; }
public Point Position { get; private set; }

25
Perspex.Input/Raw/RawSizeEventArgs.cs

@ -0,0 +1,25 @@
// -----------------------------------------------------------------------
// <copyright file="RawInputEventArgs.cs" company="Steven Kirk">
// Copyright 2013 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Input.Raw
{
using System;
public class RawSizeEventArgs : EventArgs
{
public RawSizeEventArgs(Size size)
{
this.Size = size;
}
public RawSizeEventArgs(double width, double height)
{
this.Size = new Size(width, height);
}
public Size Size { get; private set; }
}
}

2
Perspex.SceneGraph/Platform/IPlatformRenderInterface.cs

@ -17,7 +17,7 @@ namespace Perspex.Platform
IStreamGeometryImpl CreateStreamGeometry();
IRenderer CreateRenderer(IntPtr handle, double width, double height);
IRenderer CreateRenderer(IPlatformHandle handle, double width, double height);
IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height);

1
Perspex.Themes.Default/DefaultTheme.cs

@ -25,6 +25,7 @@ namespace Perspex.Themes.Default
this.Add(new TextBoxStyle());
this.Add(new TreeViewStyle());
this.Add(new TreeViewItemStyle());
this.Add(new WindowStyle());
}
}
}

1
Perspex.Themes.Default/Perspex.Themes.Default.csproj

@ -66,6 +66,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="WindowStyle.cs" />
<Compile Include="ScrollViewerStyle.cs" />
<Compile Include="ScrollBarStyle.cs" />
<Compile Include="GridSplitterStyle.cs" />

43
Perspex.Themes.Default/WindowStyle.cs

@ -0,0 +1,43 @@
// -----------------------------------------------------------------------
// <copyright file="WindowStyle.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Themes.Default
{
using System.Linq;
using Perspex.Controls;
using Perspex.Controls.Presenters;
using Perspex.Media;
using Perspex.Styling;
public class WindowStyle : Styles
{
public WindowStyle()
{
this.AddRange(new[]
{
new Style(x => x.OfType<Window>())
{
Setters = new[]
{
new Setter(Window.TemplateProperty, ControlTemplate.Create<Window>(this.Template)),
},
},
});
}
private Control Template(Window control)
{
return new Border
{
[~Border.BackgroundProperty] = control[~Window.BackgroundProperty],
Content = new ContentPresenter
{
[~ContentPresenter.ContentProperty] = control[~Window.ContentProperty],
}
};
}
}
}

13
Windows/Perspex.Direct2D1/Direct2D1Platform.cs

@ -44,9 +44,18 @@ namespace Perspex.Direct2D1
return new BitmapImpl(imagingFactory, width, height);
}
public IRenderer CreateRenderer(IntPtr handle, double width, double height)
public IRenderer CreateRenderer(IPlatformHandle handle, double width, double height)
{
return new Renderer(handle, width, height);
if (handle.HandleDescriptor == "HWND")
{
return new Renderer(handle.Handle, width, height);
}
else
{
throw new NotSupportedException(string.Format(
"Don't know how to create a Direct2D1 renderer from a '{0}' handle",
handle.HandleDescriptor));
}
}
public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height)

1
Windows/Perspex.Win32/Input/WindowsKeyboardDevice.cs

@ -7,6 +7,7 @@
namespace Perspex.Win32.Input
{
using System.Text;
using Perspex.Controls;
using Perspex.Input;
using Perspex.Win32.Interop;

4
Windows/Perspex.Win32/Input/WindowsMouseDevice.cs

@ -19,7 +19,7 @@ namespace Perspex.Win32.Input
get { return instance; }
}
public Window CurrentWindow
public WindowImpl CurrentWindow
{
get;
set;
@ -35,7 +35,7 @@ namespace Perspex.Win32.Input
{
UnmanagedMethods.POINT p;
UnmanagedMethods.GetCursorPos(out p);
UnmanagedMethods.ScreenToClient(this.CurrentWindow.Handle, ref p);
UnmanagedMethods.ScreenToClient(this.CurrentWindow.Handle.Handle, ref p);
return new Point(p.X, p.Y);
}
}

2
Windows/Perspex.Win32/Perspex.Win32.csproj

@ -60,7 +60,7 @@
<Compile Include="Input\WindowsKeyboardDevice.cs" />
<Compile Include="Input\WindowsMouseDevice.cs" />
<Compile Include="Interop\UnmanagedMethods.cs" />
<Compile Include="Window.cs" />
<Compile Include="WindowImpl.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Win32Platform.cs" />
</ItemGroup>

1
Windows/Perspex.Win32/Win32Platform.cs

@ -24,6 +24,7 @@ namespace Perspex.Win32
public static void Initialize()
{
var locator = Locator.CurrentMutable;
locator.Register(() => new WindowImpl(), typeof(IWindowImpl));
locator.Register(() => WindowsKeyboardDevice.Instance, typeof(IKeyboardDevice));
locator.Register(() => instance, typeof(IPlatformThreadingInterface));
}

179
Windows/Perspex.Win32/Window.cs → Windows/Perspex.Win32/WindowImpl.cs

@ -1,5 +1,5 @@
// -----------------------------------------------------------------------
// <copyright file="Window.cs" company="Steven Kirk">
// <copyright file="WindowImpl.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
@ -24,134 +24,58 @@ namespace Perspex.Win32
using Perspex.Win32.Interop;
using Splat;
public class Window : ContentControl, ILayoutRoot, IRenderRoot, ICloseable
public class WindowImpl : IWindowImpl
{
public static readonly PerspexProperty<string> TitleProperty = PerspexProperty.Register<Window, string>("Title");
private UnmanagedMethods.WndProc wndProcDelegate;
private string className;
private Dispatcher dispatcher;
private IRenderer renderer;
private IntPtr hwnd;
private IInputManager inputManager;
private Window owner;
public Window()
public WindowImpl()
{
IPlatformRenderInterface factory = Locator.Current.GetService<IPlatformRenderInterface>();
this.CreateWindow();
Size clientSize = this.ClientSize;
this.dispatcher = Dispatcher.UIThread;
this.LayoutManager = new LayoutManager(this);
this.RenderManager = new RenderManager();
this.renderer = factory.CreateRenderer(this.Handle, (int)clientSize.Width, (int)clientSize.Height);
this.inputManager = Locator.Current.GetService<IInputManager>();
this.Template = ControlTemplate.Create<Window>(this.DefaultTemplate);
this.LayoutManager.LayoutNeeded.Subscribe(x =>
{
this.dispatcher.InvokeAsync(
() =>
{
this.LayoutManager.ExecuteLayoutPass();
this.renderer.Render(this);
this.RenderManager.RenderFinished();
},
DispatcherPriority.Render);
});
this.GetObservable(TitleProperty).Subscribe(s => UnmanagedMethods.SetWindowText(Handle, s));
this.RenderManager.RenderNeeded
.Where(_ => !this.LayoutManager.LayoutQueued)
.Subscribe(x =>
{
this.dispatcher.InvokeAsync(
() =>
{
if (!this.LayoutManager.LayoutQueued)
{
this.renderer.Render(this);
this.RenderManager.RenderFinished();
}
},
DispatcherPriority.Render);
});
}
public event EventHandler Activated;
public event EventHandler Closed;
public string Title
{
get { return this.GetValue(TitleProperty); }
set { this.SetValue(TitleProperty, value); }
}
public event EventHandler<RawInputEventArgs> Input;
public event EventHandler<RawSizeEventArgs> Resized;
public Size ClientSize
{
get
{
UnmanagedMethods.RECT rect;
UnmanagedMethods.GetClientRect(this.Handle, out rect);
UnmanagedMethods.GetClientRect(this.hwnd, out rect);
return new Size(rect.right, rect.bottom);
}
}
public IntPtr Handle
public IPlatformHandle Handle
{
get;
private set;
}
public ILayoutManager LayoutManager
public void SetOwner(Window owner)
{
get;
private set;
this.owner = owner;
}
public IRenderManager RenderManager
public void SetTitle(string title)
{
get;
private set;
UnmanagedMethods.SetWindowText(this.hwnd, title);
}
public void Show()
{
UnmanagedMethods.ShowWindow(this.Handle, 1);
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
if (e.Key == Key.F12)
{
Window window = new Window
{
Content = new DevTools
{
Root = this,
},
};
window.Show();
}
}
private Control DefaultTemplate(Window c)
{
Border border = new Border();
border.Background = new Perspex.Media.SolidColorBrush(0xffffffff);
ContentPresenter contentPresenter = new ContentPresenter();
contentPresenter.Bind(
ContentPresenter.ContentProperty,
this.GetObservable(Window.ContentProperty),
BindingPriority.Style);
border.Content = contentPresenter;
return border;
UnmanagedMethods.ShowWindow(this.hwnd, 1);
}
private void CreateWindow()
@ -181,7 +105,7 @@ namespace Perspex.Win32
throw new Win32Exception();
}
this.Handle = UnmanagedMethods.CreateWindowEx(
this.hwnd = UnmanagedMethods.CreateWindowEx(
0,
atom,
null,
@ -195,36 +119,12 @@ namespace Perspex.Win32
IntPtr.Zero,
IntPtr.Zero);
if (this.Handle == IntPtr.Zero)
if (this.hwnd == IntPtr.Zero)
{
throw new Win32Exception();
}
}
private void OnActivated()
{
WindowsKeyboardDevice.Instance.WindowActivated(this);
if (this.Activated != null)
{
this.Activated(this, EventArgs.Empty);
}
}
private void OnResized(int width, int height)
{
this.renderer.Resize(width, height);
this.LayoutManager.ExecuteLayoutPass();
this.renderer.Render(this);
this.RenderManager.RenderFinished();
}
private void OnClosed()
{
if (this.Closed != null)
{
this.Closed(this, EventArgs.Empty);
}
this.Handle = new PlatformHandle(this.hwnd);
}
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")]
@ -237,11 +137,17 @@ namespace Perspex.Win32
switch ((UnmanagedMethods.WindowsMessage)msg)
{
case UnmanagedMethods.WindowsMessage.WM_ACTIVATE:
this.OnActivated();
if (this.Activated != null)
{
this.Activated(this, EventArgs.Empty);
}
break;
case UnmanagedMethods.WindowsMessage.WM_DESTROY:
this.OnClosed();
if (this.Closed != null)
{
this.Closed(this, EventArgs.Empty);
}
break;
case UnmanagedMethods.WindowsMessage.WM_KEYDOWN:
@ -255,39 +161,54 @@ namespace Perspex.Win32
case UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN:
e = new RawMouseEventArgs(
WindowsMouseDevice.Instance,
this,
WindowsMouseDevice.Instance,
this.owner,
RawMouseEventType.LeftButtonDown,
new Point((uint)lParam & 0xffff, (uint)lParam >> 16));
break;
case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP:
e = new RawMouseEventArgs(
WindowsMouseDevice.Instance,
this,
WindowsMouseDevice.Instance,
this.owner,
RawMouseEventType.LeftButtonUp,
new Point((uint)lParam & 0xffff, (uint)lParam >> 16));
break;
case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE:
e = new RawMouseEventArgs(
WindowsMouseDevice.Instance,
this,
WindowsMouseDevice.Instance,
this.owner,
RawMouseEventType.Move,
new Point((uint)lParam & 0xffff, (uint)lParam >> 16));
break;
case UnmanagedMethods.WindowsMessage.WM_SIZE:
this.OnResized((int)lParam & 0xffff, (int)lParam >> 16);
if (this.Resized != null)
{
this.Resized(this, new RawSizeEventArgs((int)lParam & 0xffff, (int)lParam >> 16));
}
return IntPtr.Zero;
}
if (e != null)
if (e != null && this.Input != null)
{
this.inputManager.Process(e);
this.Input(this, e);
}
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
}
private class PlatformHandle : IPlatformHandle
{
public PlatformHandle(IntPtr hwnd)
{
this.Handle = hwnd;
}
public IntPtr Handle { get; private set; }
public string HandleDescriptor { get { return "HWND"; } }
}
}
}
Loading…
Cancel
Save