mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-13 07:46:23 +01:00
Compare commits
4 Commits
dev/vanzue
...
shawn/fixQ
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e0ebfd6db | ||
|
|
3d510dc382 | ||
|
|
8ffd88fdf3 | ||
|
|
097cf7414b |
@@ -2,7 +2,6 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
@@ -42,19 +41,15 @@ internal sealed partial class FancyZonesMonitorListItem : ListItem
|
||||
public static Details BuildMonitorDetails(FancyZonesMonitorDescriptor monitor)
|
||||
{
|
||||
var currentVirtualDesktop = FancyZonesVirtualDesktop.GetCurrentVirtualDesktopIdString();
|
||||
|
||||
// Calculate physical resolution from logical pixels and DPI
|
||||
var scaleFactor = monitor.Data.Dpi > 0 ? monitor.Data.Dpi / 96.0 : 1.0;
|
||||
var physicalWidth = (int)Math.Round(monitor.Data.MonitorWidth * scaleFactor);
|
||||
var physicalHeight = (int)Math.Round(monitor.Data.MonitorHeight * scaleFactor);
|
||||
var resolution = $"{physicalWidth}\u00D7{physicalHeight}";
|
||||
|
||||
var tags = new List<IDetailsElement>
|
||||
{
|
||||
DetailTag(Resources.FancyZones_Monitor, monitor.Data.Monitor),
|
||||
DetailTag(Resources.FancyZones_Instance, monitor.Data.MonitorInstanceId),
|
||||
DetailTag(Resources.FancyZones_Serial, monitor.Data.MonitorSerialNumber),
|
||||
DetailTag(Resources.FancyZones_Number, monitor.Data.MonitorNumber.ToString(CultureInfo.InvariantCulture)),
|
||||
DetailTag(Resources.FancyZones_VirtualDesktop, currentVirtualDesktop),
|
||||
DetailTag(Resources.FancyZones_Resolution, resolution),
|
||||
DetailTag(Resources.FancyZones_WorkArea, $"{monitor.Data.LeftCoordinate},{monitor.Data.TopCoordinate} {monitor.Data.WorkAreaWidth}\u00D7{monitor.Data.WorkAreaHeight}"),
|
||||
DetailTag(Resources.FancyZones_Resolution, $"{monitor.Data.MonitorWidth}\u00D7{monitor.Data.MonitorHeight}"),
|
||||
DetailTag(Resources.FancyZones_DPI, monitor.Data.Dpi.ToString(CultureInfo.InvariantCulture)),
|
||||
};
|
||||
|
||||
|
||||
@@ -19,12 +19,8 @@ internal readonly record struct FancyZonesMonitorDescriptor(
|
||||
{
|
||||
get
|
||||
{
|
||||
// MonitorWidth/Height are logical (DPI-scaled) pixels, calculate physical resolution
|
||||
var scaleFactor = Data.Dpi > 0 ? Data.Dpi / 96.0 : 1.0;
|
||||
var physicalWidth = (int)Math.Round(Data.MonitorWidth * scaleFactor);
|
||||
var physicalHeight = (int)Math.Round(Data.MonitorHeight * scaleFactor);
|
||||
var size = $"{physicalWidth}×{physicalHeight}";
|
||||
var scaling = Data.Dpi > 0 ? string.Format(CultureInfo.InvariantCulture, "{0}%", (int)Math.Round(scaleFactor * 100)) : "n/a";
|
||||
var size = $"{Data.MonitorWidth}×{Data.MonitorHeight}";
|
||||
var scaling = Data.Dpi > 0 ? string.Format(CultureInfo.InvariantCulture, "{0}%", (int)Math.Round(Data.Dpi * 100 / 96.0)) : "n/a";
|
||||
return $"{size} \u2022 {scaling}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,21 +485,12 @@ internal static class FancyZonesThumbnailRenderer
|
||||
|
||||
private static List<NormalizedRect> GetFocusRects(int zoneCount)
|
||||
{
|
||||
// Focus layout parameters from FancyZonesEditor CanvasLayoutModel:
|
||||
// - DefaultOffset = 100px from top-left (normalized: ~0.05 for typical screen)
|
||||
// - OffsetShift = 50px per zone (normalized: ~0.025)
|
||||
// - ZoneSizeMultiplier = 0.4 (zones are 40% of screen)
|
||||
zoneCount = Math.Clamp(zoneCount, 1, 8);
|
||||
var rects = new List<NormalizedRect>(zoneCount);
|
||||
|
||||
const float defaultOffset = 0.05f; // ~100px on 1920px screen
|
||||
const float offsetShift = 0.025f; // ~50px on 1920px screen
|
||||
const float zoneSize = 0.4f; // 40% of screen
|
||||
|
||||
for (var i = 0; i < zoneCount; i++)
|
||||
{
|
||||
var offset = i * offsetShift;
|
||||
rects.Add(new NormalizedRect(defaultOffset + offset, defaultOffset + offset, zoneSize, zoneSize));
|
||||
var offset = i * 0.06f;
|
||||
rects.Add(new NormalizedRect(0.1f + offset, 0.1f + offset, 0.8f, 0.8f));
|
||||
}
|
||||
|
||||
return rects;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using static FancyZonesEditorCommon.Data.CustomLayouts;
|
||||
|
||||
@@ -24,10 +23,8 @@ namespace FancyZonesEditorCommon.Data
|
||||
{
|
||||
public struct CanvasZoneWrapper
|
||||
{
|
||||
[JsonPropertyName("X")]
|
||||
public int X { get; set; }
|
||||
|
||||
[JsonPropertyName("Y")]
|
||||
public int Y { get; set; }
|
||||
|
||||
public int Width { get; set; }
|
||||
|
||||
@@ -19,6 +19,8 @@ public sealed partial class AppsListPage : Page
|
||||
public AppsListPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
NavigationCacheMode = NavigationCacheMode.Disabled;
|
||||
Unloaded += OnUnloaded;
|
||||
}
|
||||
|
||||
public AllAppsViewModel ViewModel { get; private set; } = default!;
|
||||
@@ -36,6 +38,30 @@ public sealed partial class AppsListPage : Page
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
||||
{
|
||||
base.OnNavigatingFrom(e);
|
||||
CleanupPage();
|
||||
}
|
||||
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CleanupPage();
|
||||
}
|
||||
|
||||
private void CleanupPage()
|
||||
{
|
||||
// Clear the collection before cleaning up to release all item references
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.FlyoutMenuItems.Clear();
|
||||
}
|
||||
|
||||
DataContext = null;
|
||||
ViewModel = null!;
|
||||
_context = null;
|
||||
}
|
||||
|
||||
private void BackButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_context == null || Frame == null)
|
||||
|
||||
@@ -27,6 +27,7 @@ public sealed partial class LaunchPage : Page
|
||||
public LaunchPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
NavigationCacheMode = NavigationCacheMode.Disabled;
|
||||
}
|
||||
|
||||
public LauncherViewModel ViewModel { get; private set; } = default!;
|
||||
@@ -44,6 +45,12 @@ public sealed partial class LaunchPage : Page
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
||||
{
|
||||
base.OnNavigatingFrom(e);
|
||||
DataContext = null;
|
||||
}
|
||||
|
||||
private void SettingsBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_coordinator?.OpenSettings();
|
||||
|
||||
@@ -65,4 +65,16 @@ public sealed partial class ShellPage : Page
|
||||
appsListPage.ViewModel?.RefreshSettings();
|
||||
}
|
||||
}
|
||||
|
||||
internal void NavigateToLaunchIfNeeded()
|
||||
{
|
||||
// Always clear FlyoutMenuItems to release memory
|
||||
_allAppsViewModel?.FlyoutMenuItems.Clear();
|
||||
|
||||
// Navigate back to LaunchPage if on AppsListPage
|
||||
if (ContentFrame.Content is AppsListPage)
|
||||
{
|
||||
NavigateToLaunch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,8 +143,11 @@ public sealed partial class MainWindow : WindowEx, IDisposable
|
||||
_trimCts = new CancellationTokenSource();
|
||||
var token = _trimCts.Token;
|
||||
|
||||
// Delay the trim to avoid aggressive GC during quick toggles
|
||||
Task.Delay(2000, token).ContinueWith(
|
||||
// Delay memory trim for 5 seconds to avoid aggressive GC during quick toggles.
|
||||
// A shorter delay (previously 2 seconds) caused heavy UI (e.g. AppsListPage) to be
|
||||
// torn down and rebuilt when users quickly reopened the window, which hurt perceived
|
||||
// responsiveness more than the extra few seconds of retained memory.
|
||||
Task.Delay(5000, token).ContinueWith(
|
||||
_ =>
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
@@ -152,7 +155,24 @@ public sealed partial class MainWindow : WindowEx, IDisposable
|
||||
return;
|
||||
}
|
||||
|
||||
TrimMemory();
|
||||
_dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
// Navigate back to LaunchPage before memory trim to release AppsListPage resources
|
||||
ShellHost.NavigateToLaunchIfNeeded();
|
||||
|
||||
// Give UI time to complete cleanup before forcing GC
|
||||
Task.Delay(500, token).ContinueWith(
|
||||
__ =>
|
||||
{
|
||||
if (!token.IsCancellationRequested)
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(TrimMemory);
|
||||
}
|
||||
},
|
||||
token,
|
||||
TaskContinuationOptions.None,
|
||||
TaskScheduler.Default);
|
||||
});
|
||||
},
|
||||
token,
|
||||
TaskContinuationOptions.None,
|
||||
|
||||
@@ -154,6 +154,9 @@ public sealed class AllAppsViewModel : Observable
|
||||
if (_coordinator.UpdateModuleEnabled(flyoutItem.Tag, flyoutItem.IsEnabled))
|
||||
{
|
||||
_coordinator.NotifyUserSettingsInteraction();
|
||||
|
||||
// Trigger re-sort immediately when status changes on UI
|
||||
RefreshFlyoutMenuItems();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user