diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt
index 0ad432ffe9..e25f3a342f 100644
--- a/.github/actions/spell-check/expect.txt
+++ b/.github/actions/spell-check/expect.txt
@@ -663,6 +663,7 @@ ERRORTITLE
esize
estdir
etcore
+etcoreapp
etl
etw
EUQ
diff --git a/src/common/ManagedCommon/StartupPosition.cs b/src/common/ManagedCommon/StartupPosition.cs
new file mode 100644
index 0000000000..ae316eee36
--- /dev/null
+++ b/src/common/ManagedCommon/StartupPosition.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace ManagedCommon
+{
+ public enum StartupPosition
+ {
+ Cursor,
+ PrimaryMonitor,
+ Focus,
+ }
+}
diff --git a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs
index 2345cb2069..98b8a45921 100644
--- a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs
+++ b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs
@@ -207,7 +207,7 @@ namespace PowerLauncher
/// X co-ordinate of main window top left corner
private double WindowLeft()
{
- var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
+ var screen = GetScreen();
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0);
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.Width, 0);
var left = ((dip2.X - ActualWidth) / 2) + dip1.X;
@@ -216,13 +216,30 @@ namespace PowerLauncher
private double WindowTop()
{
- var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
+ var screen = GetScreen();
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y);
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Height);
var top = ((dip2.Y - SearchBox.ActualHeight) / 4) + dip1.Y;
return top;
}
+ private Screen GetScreen()
+ {
+ ManagedCommon.StartupPosition position = _settings.StartupPosition;
+ switch (position)
+ {
+ case ManagedCommon.StartupPosition.PrimaryMonitor:
+ return Screen.PrimaryScreen;
+ case ManagedCommon.StartupPosition.Focus:
+ IntPtr foregroundWindowHandle = NativeMethods.GetForegroundWindow();
+ Screen activeScreen = Screen.FromHandle(foregroundWindowHandle);
+ return activeScreen;
+ case ManagedCommon.StartupPosition.Cursor:
+ default:
+ return Screen.FromPoint(System.Windows.Forms.Cursor.Position);
+ }
+ }
+
private void Launcher_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Tab && Keyboard.IsKeyDown(Key.LeftShift))
diff --git a/src/modules/launcher/PowerLauncher/SettingsWatcher.cs b/src/modules/launcher/PowerLauncher/SettingsWatcher.cs
index 68641213cc..31bcaaf4d8 100644
--- a/src/modules/launcher/PowerLauncher/SettingsWatcher.cs
+++ b/src/modules/launcher/PowerLauncher/SettingsWatcher.cs
@@ -126,6 +126,11 @@ namespace PowerLauncher
_themeManager.ChangeTheme(_settings.Theme, true);
}
+ if (_settings.StartupPosition != overloadSettings.Properties.Position)
+ {
+ _settings.StartupPosition = overloadSettings.Properties.Position;
+ }
+
retry = false;
}
diff --git a/src/modules/launcher/Wox.Infrastructure/UserSettings/PowerToysRunSettings.cs b/src/modules/launcher/Wox.Infrastructure/UserSettings/PowerToysRunSettings.cs
index e01121be19..c30f98ff53 100644
--- a/src/modules/launcher/Wox.Infrastructure/UserSettings/PowerToysRunSettings.cs
+++ b/src/modules/launcher/Wox.Infrastructure/UserSettings/PowerToysRunSettings.cs
@@ -47,6 +47,8 @@ namespace Wox.Infrastructure.UserSettings
public Theme Theme { get; set; } = Theme.System;
+ public StartupPosition StartupPosition { get; set; } = StartupPosition.Cursor;
+
public string QueryBoxFont { get; set; } = FontFamily.GenericSansSerif.Name;
public string QueryBoxFontStyle { get; set; }
diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerLauncherProperties.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerLauncherProperties.cs
index 6723300b24..d4191871aa 100644
--- a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerLauncherProperties.cs
+++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerLauncherProperties.cs
@@ -45,6 +45,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonPropertyName("theme")]
public Theme Theme { get; set; }
+ [JsonPropertyName("startupPosition")]
+ public StartupPosition Position { get; set; }
+
public PowerLauncherProperties()
{
OpenPowerLauncher = new HotkeySettings(false, false, true, false, 32);
@@ -57,6 +60,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
ClearInputOnLaunch = false;
MaximumNumberOfResults = 4;
Theme = Theme.System;
+ Position = StartupPosition.Cursor;
}
}
}
diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerLauncherViewModel.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerLauncherViewModel.cs
index 668fe902ea..9abe73f2d4 100644
--- a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerLauncherViewModel.cs
+++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerLauncherViewModel.cs
@@ -22,6 +22,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
private bool _isLightThemeRadioButtonChecked;
private bool _isSystemThemeRadioButtonChecked;
+ private bool _isCursorPositionRadioButtonChecked;
+ private bool _isPrimaryMonitorPositionRadioButtonChecked;
+ private bool _isFocusPositionRadioButtonChecked;
+
private GeneralSettings GeneralSettingsConfig { get; set; }
private readonly ISettingsUtils _settingsUtils;
@@ -89,6 +93,19 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
break;
}
+ switch (settings.Properties.Position)
+ {
+ case StartupPosition.Cursor:
+ _isCursorPositionRadioButtonChecked = true;
+ break;
+ case StartupPosition.PrimaryMonitor:
+ _isPrimaryMonitorPositionRadioButtonChecked = true;
+ break;
+ case StartupPosition.Focus:
+ _isFocusPositionRadioButtonChecked = true;
+ break;
+ }
+
foreach (var plugin in Plugins)
{
plugin.PropertyChanged += OnPluginInfoChange;
@@ -243,6 +260,66 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
}
}
+ public bool IsCursorPositionRadioButtonChecked
+ {
+ get
+ {
+ return _isCursorPositionRadioButtonChecked;
+ }
+
+ set
+ {
+ if (value == true)
+ {
+ settings.Properties.Position = StartupPosition.Cursor;
+ }
+
+ _isCursorPositionRadioButtonChecked = value;
+
+ UpdateSettings();
+ }
+ }
+
+ public bool IsPrimaryMonitorPositionRadioButtonChecked
+ {
+ get
+ {
+ return _isPrimaryMonitorPositionRadioButtonChecked;
+ }
+
+ set
+ {
+ if (value == true)
+ {
+ settings.Properties.Position = StartupPosition.PrimaryMonitor;
+ }
+
+ _isPrimaryMonitorPositionRadioButtonChecked = value;
+
+ UpdateSettings();
+ }
+ }
+
+ public bool IsFocusPositionRadioButtonChecked
+ {
+ get
+ {
+ return _isFocusPositionRadioButtonChecked;
+ }
+
+ set
+ {
+ if (value == true)
+ {
+ settings.Properties.Position = StartupPosition.Focus;
+ }
+
+ _isFocusPositionRadioButtonChecked = value;
+
+ UpdateSettings();
+ }
+ }
+
public HotkeySettings OpenPowerLauncher
{
get
diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw
index 10af378234..250ed62400 100644
--- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw
+++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw
@@ -1151,4 +1151,20 @@ Win + Shift + O to toggle your video
PowerToys Settings
-
\ No newline at end of file
+
+ Position & appearance
+
+
+ Show PowerToys Run on
+ as in Show PowerToys Run on primary monitor
+
+
+ Monitor with mouse cursor
+
+
+ Monitor with focused window
+
+
+ Primary monitor
+
+
diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerLauncherPage.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerLauncherPage.xaml
index 72a99ee7d2..00fea94b85 100644
--- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerLauncherPage.xaml
+++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerLauncherPage.xaml
@@ -148,9 +148,30 @@
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher}"
/>
-
+
+
+
+
+
+
+
+
+