Skip to content

Commit

Permalink
Windows message loop manager (#9614)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattleibow authored Aug 26, 2022
1 parent 99d99c1 commit abd82aa
Show file tree
Hide file tree
Showing 19 changed files with 738 additions and 233 deletions.
1 change: 1 addition & 0 deletions src/Core/src/Handlers/Window/WindowHandler.Windows.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Maui.ApplicationModel;

namespace Microsoft.Maui.Handlers
{
Expand Down
4 changes: 0 additions & 4 deletions src/Core/src/Hosting/EssentialsMauiAppBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,6 @@ internal static MauiAppBuilder UseEssentials(this MauiAppBuilder builder)
}));
#elif WINDOWS
life.AddWindows(windows => windows
.OnPlatformMessage((window, args) =>
{
ApplicationModel.Platform.OnWindowMessage(args.Hwnd, args.MessageId, args.WParam, args.LParam);
})
.OnActivated((window, args) =>
{
ApplicationModel.Platform.OnActivated(window, args);
Expand Down
48 changes: 16 additions & 32 deletions src/Core/src/Platform/Windows/MauiWinUIWindow.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Devices;
using Microsoft.Maui.LifecycleEvents;
using Microsoft.UI;
Expand All @@ -10,11 +11,15 @@ namespace Microsoft.Maui
{
public class MauiWinUIWindow : UI.Xaml.Window
{
readonly WindowMessageManager _windowManager;

IntPtr _windowIcon;
bool _enableResumeEvent;

public MauiWinUIWindow()
{
_windowManager = WindowMessageManager.Get(this);

Activated += OnActivated;
Closed += OnClosedPrivate;
VisibilityChanged += OnVisibilityChanged;
Expand Down Expand Up @@ -62,58 +67,37 @@ protected virtual void OnVisibilityChanged(object sender, UI.Xaml.WindowVisibili
MauiWinUIApplication.Current.Services?.InvokeLifecycleEvents<WindowsLifecycle.OnVisibilityChanged>(del => del(this, args));
}

#region Platform Window

IntPtr _hwnd = IntPtr.Zero;

/// <summary>
/// Returns a pointer to the underlying platform window handle (hWnd).
/// </summary>
public IntPtr WindowHandle
{
get
{
if (_hwnd == IntPtr.Zero)
_hwnd = this.GetWindowHandle();
return _hwnd;
}
}

PlatformMethods.WindowProc? newWndProc = null;
IntPtr oldWndProc = IntPtr.Zero;
public IntPtr WindowHandle => _windowManager.WindowHandle;

void SubClassingWin32()
{
MauiWinUIApplication.Current.Services?.InvokeLifecycleEvents<WindowsLifecycle.OnPlatformWindowSubclassed>(
del => del(this, new WindowsPlatformWindowSubclassedEventArgs(WindowHandle)));

newWndProc = new PlatformMethods.WindowProc(NewWindowProc);
oldWndProc = PlatformMethods.SetWindowLongPtr(WindowHandle, PlatformMethods.WindowLongFlags.GWL_WNDPROC, newWndProc);
_windowManager.WindowMessage += OnWindowMessage;

IntPtr NewWindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
void OnWindowMessage(object? sender, WindowMessageEventArgs e)
{
if (msg == WindowsPlatformMessageIds.WM_SETTINGCHANGE || msg == WindowsPlatformMessageIds.WM_THEMECHANGE)
if (e.MessageId == PlatformMethods.MessageIds.WM_SETTINGCHANGE ||
e.MessageId == PlatformMethods.MessageIds.WM_THEMECHANGE)
{
MauiWinUIApplication.Current.Application?.ThemeChanged();

if (msg == WindowsPlatformMessageIds.WM_DPICHANGED)
}
else if (e.MessageId == PlatformMethods.MessageIds.WM_DPICHANGED)
{
var dpiX = (short)(long)wParam;
var dpiY = (short)((long)wParam >> 16);
var dpiX = (short)(long)e.WParam;
var dpiY = (short)((long)e.WParam >> 16);

var window = this.GetWindow();
if (window is not null)
window.DisplayDensityChanged(dpiX / DeviceDisplay.BaseLogicalDpi);
}

MauiWinUIApplication.Current.Services?.InvokeLifecycleEvents<WindowsLifecycle.OnPlatformMessage>(
m => m.Invoke(this, new WindowsPlatformMessageEventArgs(hWnd, msg, wParam, lParam)));

return PlatformMethods.CallWindowProc(oldWndProc, hWnd, msg, wParam, lParam);
m => m.Invoke(this, new WindowsPlatformMessageEventArgs(e.Hwnd, e.MessageId, e.WParam, e.LParam)));
}
}

#endregion

/// <summary>
/// Default the Window Icon to the icon stored in the .exe, if any.
///
Expand Down
1 change: 1 addition & 0 deletions src/Core/src/Platform/Windows/NavigationRootManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Microsoft.Maui.ApplicationModel;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
Expand Down
1 change: 1 addition & 0 deletions src/Core/src/Platform/Windows/WindowExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Devices;
using System.Threading.Tasks;
using Microsoft.Maui.Media;
Expand Down
10 changes: 0 additions & 10 deletions src/Core/src/Platform/Windows/WindowsPlatformMessageIds.cs

This file was deleted.

25 changes: 15 additions & 10 deletions src/Essentials/src/AppInfo/AppInfo.uwp.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
using System;
using System.Globalization;
using Windows.ApplicationModel;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
#if WINDOWS
using Microsoft.UI.Xaml;
#else
using Windows.UI.Xaml;
#endif
using Windows.ApplicationModel;

namespace Microsoft.Maui.ApplicationModel
{
Expand All @@ -19,11 +15,13 @@ class AppInfoImplementation : IAppInfo

ApplicationTheme? _applicationTheme;

readonly ActiveWindowTracker _activeWindowTracker;

public AppInfoImplementation()
{
// TODO: NET7 use new public events
if (WindowStateManager.Default is WindowStateManagerImplementation impl)
impl.ActiveWindowThemeChanged += OnActiveWindowThemeChanged;
_activeWindowTracker = new(WindowStateManager.Default);
_activeWindowTracker.Start();
_activeWindowTracker.WindowMessage += OnWindowMessage;

if (MainThread.IsMainThread)
OnActiveWindowThemeChanged();
Expand Down Expand Up @@ -78,7 +76,14 @@ public AppTheme RequestedTheme
public LayoutDirection RequestedLayoutDirection =>
CultureInfo.CurrentCulture.TextInfo.IsRightToLeft ? LayoutDirection.RightToLeft : LayoutDirection.LeftToRight;

void OnActiveWindowThemeChanged(object sender = null, EventArgs e = null)
void OnWindowMessage(object sender, WindowMessageEventArgs e)
{
if (e.MessageId == PlatformMethods.MessageIds.WM_SETTINGCHANGE ||
e.MessageId == PlatformMethods.MessageIds.WM_THEMECHANGE)
OnActiveWindowThemeChanged();
}

void OnActiveWindowThemeChanged()
{
if (Application.Current is Application app)
_applicationTheme = app.RequestedTheme;
Expand Down
57 changes: 19 additions & 38 deletions src/Essentials/src/DeviceDisplay/DeviceDisplay.uwp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,16 @@ namespace Microsoft.Maui.Devices
partial class DeviceDisplayImplementation
{
readonly object locker = new object();
readonly ActiveWindowTracker _activeWindowTracker;

DisplayRequest? displayRequest;

public DeviceDisplayImplementation()
{
_activeWindowTracker = new(WindowStateManager.Default);
_activeWindowTracker.WindowMessage += OnWindowMessage;
}

protected override bool GetKeepScreenOn()
{
lock (locker)
Expand Down Expand Up @@ -44,8 +52,6 @@ protected override void SetKeepScreenOn(bool keepScreenOn)
}
}

AppWindow? _currentAppWindowListeningTo;

protected override DisplayInfo GetMainDisplayInfo()
{
if (WindowStateManager.Default.GetActiveAppWindow(false) is not AppWindow appWindow)
Expand Down Expand Up @@ -102,47 +108,22 @@ protected override DisplayInfo GetMainDisplayInfo()
return null;
}

protected override void StartScreenMetricsListeners()
{
MainThread.BeginInvokeOnMainThread(() =>
{
WindowStateManager.Default.ActiveWindowDisplayChanged += OnWindowDisplayChanged;
WindowStateManager.Default.ActiveWindowChanged += OnCurrentWindowChanged;
protected override void StartScreenMetricsListeners() =>
MainThread.BeginInvokeOnMainThread(_activeWindowTracker.Start);

_currentAppWindowListeningTo = WindowStateManager.Default.GetActiveAppWindow(true)!;
_currentAppWindowListeningTo.Changed += OnAppWindowChanged;
});
}
protected override void StopScreenMetricsListeners() =>
MainThread.BeginInvokeOnMainThread(_activeWindowTracker.Stop);

protected override void StopScreenMetricsListeners()
// Currently there isn't a way to detect Orientation Changes unless you subclass the WinUI.Window and watch the messages.
// This is the "subtlest" way to currently wire this together.
// Hopefully there will be a more public API for this down the road so we can just use that directly from Essentials
void OnWindowMessage(object? sender, WindowMessageEventArgs e)
{
MainThread.BeginInvokeOnMainThread(() =>
{
WindowStateManager.Default.ActiveWindowChanged -= OnCurrentWindowChanged;
WindowStateManager.Default.ActiveWindowDisplayChanged -= OnWindowDisplayChanged;
if (_currentAppWindowListeningTo != null)
_currentAppWindowListeningTo.Changed -= OnAppWindowChanged;
_currentAppWindowListeningTo = null;
});
}

void OnCurrentWindowChanged(object? sender, EventArgs e)
{
if (_currentAppWindowListeningTo != null)
_currentAppWindowListeningTo.Changed -= OnAppWindowChanged;

_currentAppWindowListeningTo = WindowStateManager.Default.GetActiveAppWindow(true)!;
_currentAppWindowListeningTo.Changed += OnAppWindowChanged;
if (e.MessageId == PlatformMethods.MessageIds.WM_DISPLAYCHANGE ||
e.MessageId == PlatformMethods.MessageIds.WM_DPICHANGED)
OnMainDisplayInfoChanged();
}

void OnWindowDisplayChanged(object? sender, EventArgs e) =>
OnMainDisplayInfoChanged();

void OnAppWindowChanged(AppWindow sender, AppWindowChangedEventArgs args) =>
OnMainDisplayInfoChanged();

static DisplayRotation CalculateRotation(DisplayOrientations orientation) =>
orientation switch
{
Expand Down
58 changes: 58 additions & 0 deletions src/Essentials/src/Platform/ActiveWindowTracker.uwp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#nullable enable
using System;

namespace Microsoft.Maui.ApplicationModel
{
class ActiveWindowTracker
{
readonly IWindowStateManager _windowStateManager;

WindowMessageManager? _currentWindowManager;

public ActiveWindowTracker(IWindowStateManager windowStateManager)
{
_windowStateManager = windowStateManager;
}

public event EventHandler<WindowMessageEventArgs>? WindowMessage;

public void Start()
{
var window = _windowStateManager.GetActiveWindow();
OnActiveWindowChanged(window);

_windowStateManager.ActiveWindowChanged += OnActiveWindowChanged;
}

public void Stop()
{
OnActiveWindowChanged(null);

_windowStateManager.ActiveWindowChanged -= OnActiveWindowChanged;
}

void OnActiveWindowChanged(object? sender, EventArgs e)
{
var window = _windowStateManager?.GetActiveWindow();
OnActiveWindowChanged(window);
}

void OnActiveWindowChanged(UI.Xaml.Window? window)
{
if (_currentWindowManager is not null)
{
_currentWindowManager.WindowMessage -= OnWindowMessage;
_currentWindowManager = null;
}

if (window is not null)
{
_currentWindowManager = WindowMessageManager.Get(window);
_currentWindowManager.WindowMessage += OnWindowMessage;
}
}

void OnWindowMessage(object? sender, WindowMessageEventArgs e) =>
WindowMessage?.Invoke(sender, e);
}
}
3 changes: 0 additions & 3 deletions src/Essentials/src/Platform/Platform.shared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,6 @@ public static void OnLaunched(UI.Xaml.LaunchActivatedEventArgs e) =>
public static void OnActivated(UI.Xaml.Window window, UI.Xaml.WindowActivatedEventArgs args) =>
WindowStateManager.Default.OnActivated(window, args);

public static void OnWindowMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) =>
WindowStateManager.Default.OnWindowMessage(hWnd, msg, wParam, lParam);

#elif TIZEN
public static Tizen.Applications.Package CurrentPackage
{
Expand Down
Loading

0 comments on commit abd82aa

Please sign in to comment.