mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-15 19:27:56 +01:00
Option to toggle the system tray icon (#23220)
* Added option to toggle the system tray icon At the moment, this hides the icon making the settings window inaccessible without first modifying the general `settings.json` file. * Use IPC messages to manage the tray icon settings * Fix launching second window binds to active settings process * Added context menu option to hide tray icon * Added Exit PT button to settings ui NavigationView.PaneFooter * Moved DllImports to NativeMethods.cs * Sentence case titles * Fix whitespace * Re-add exit icon to NavView * Re-added toggle switch to new UI * Fix build * Fix build after merge main * Fix the string to display * add shut down buttons * finish polish * fix string * Styling tweaks to titlebar and settingscards * fix comment * fix unit test * fix ut --------- Co-authored-by: Jaime Bernardo <jaime@janeasystems.com> Co-authored-by: vanzue <vanzue@outlook.com> Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com> Co-authored-by: Niels Laute <niels.laute@live.nl>
This commit is contained in:
@@ -1,5 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@@ -89,7 +148,7 @@
|
||||
<value>This setting has been disabled by your administrator.</value>
|
||||
</data>
|
||||
<data name="STARTUP_DISABLED_BY_USER" xml:space="preserve">
|
||||
<value>This setting has been disabled manually via <a href="https://ms_settings_startupapps" target="_blank">Startup Settings</a>.</value>
|
||||
<value>This setting has been disabled manually via <a href="https://ms_settings_startupapps" target="_blank">Startup Settings</a>.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_AVAILABLE" xml:space="preserve">
|
||||
<value>An update to PowerToys is available.</value>
|
||||
@@ -121,6 +180,9 @@
|
||||
<value>Exit</value>
|
||||
<comment>Exit as a verb, as in Exit the application</comment>
|
||||
</data>
|
||||
<data name="SHOW_TRAY_ICON_MENU_TEXT" xml:space="preserve">
|
||||
<value>Show icon</value>
|
||||
</data>
|
||||
<data name="SUBMIT_BUG_TEXT" xml:space="preserve">
|
||||
<value>Report bug</value>
|
||||
</data>
|
||||
@@ -134,4 +196,4 @@
|
||||
<data name="TRAY_ICON_ADMIN_TOOLTIP" xml:space="preserve">
|
||||
<value>Administrator</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "general_settings.h"
|
||||
#include "auto_start_helper.h"
|
||||
#include "tray_icon.h"
|
||||
#include "Generated files/resource.h"
|
||||
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
@@ -14,6 +15,7 @@
|
||||
|
||||
// TODO: would be nice to get rid of these globals, since they're basically cached json settings
|
||||
static std::wstring settings_theme = L"system";
|
||||
static bool show_tray_icon = true;
|
||||
static bool run_as_elevated = false;
|
||||
static bool show_new_updates_toast_notification = true;
|
||||
static bool download_updates_automatically = true;
|
||||
@@ -38,6 +40,7 @@ json::JsonObject GeneralSettings::to_json()
|
||||
}
|
||||
result.SetNamedValue(L"enabled", std::move(enabled));
|
||||
|
||||
result.SetNamedValue(L"show_tray_icon", json::value(showSystemTrayIcon));
|
||||
result.SetNamedValue(L"is_elevated", json::value(isElevated));
|
||||
result.SetNamedValue(L"run_elevated", json::value(isRunElevated));
|
||||
result.SetNamedValue(L"show_new_updates_toast_notification", json::value(showNewUpdatesToastNotification));
|
||||
@@ -74,7 +77,9 @@ json::JsonObject load_general_settings()
|
||||
GeneralSettings get_general_settings()
|
||||
{
|
||||
const bool is_user_admin = check_user_is_admin();
|
||||
GeneralSettings settings{
|
||||
GeneralSettings settings
|
||||
{
|
||||
.showSystemTrayIcon = show_tray_icon,
|
||||
.isElevated = is_process_elevated(),
|
||||
.isRunElevated = run_as_elevated,
|
||||
.isAdmin = is_user_admin,
|
||||
@@ -214,6 +219,13 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save)
|
||||
settings_theme = general_configs.GetNamedString(L"theme");
|
||||
}
|
||||
|
||||
if (json::has(general_configs, L"show_tray_icon", json::JsonValueType::Boolean))
|
||||
{
|
||||
show_tray_icon = general_configs.GetNamedBoolean(L"show_tray_icon");
|
||||
// Update tray icon visibility when setting is toggled
|
||||
set_tray_icon_visible(show_tray_icon);
|
||||
}
|
||||
|
||||
if (save)
|
||||
{
|
||||
GeneralSettings save_settings = get_general_settings();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
struct GeneralSettings
|
||||
{
|
||||
bool isStartupEnabled;
|
||||
bool showSystemTrayIcon;
|
||||
std::wstring startupDisabledReason;
|
||||
std::map<std::wstring, bool> isModulesEnabledMap;
|
||||
bool isElevated;
|
||||
|
||||
@@ -90,6 +90,7 @@ void open_menu_from_another_instance(std::optional<std::string> settings_window)
|
||||
msg = static_cast<LPARAM>(ESettingsWindowNames_from_string(settings_window.value()));
|
||||
}
|
||||
PostMessageW(hwnd_main, WM_COMMAND, ID_SETTINGS_MENU_COMMAND, msg);
|
||||
SetForegroundWindow(hwnd_main); // Bring the settings window to the front
|
||||
}
|
||||
|
||||
int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow, bool openOobe, bool openScoobe, bool showRestartNotificationAfterUpdate)
|
||||
@@ -104,6 +105,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
||||
#endif
|
||||
Trace::RegisterProvider();
|
||||
start_tray_icon(isProcessElevated);
|
||||
set_tray_icon_visible(get_general_settings().showSystemTrayIcon);
|
||||
CentralizedKeyboardHook::Start();
|
||||
|
||||
int result = -1;
|
||||
|
||||
@@ -20,4 +20,5 @@
|
||||
#define ID_ABOUT_MENU_COMMAND 40003
|
||||
#define ID_REPORT_BUG_COMMAND 40004
|
||||
#define ID_DOCUMENTATION_MENU_COMMAND 40005
|
||||
#define ID_QUICK_ACCESS_MENU_COMMAND 40006
|
||||
#define ID_QUICK_ACCESS_MENU_COMMAND 40006
|
||||
#define ID_SHOW_TRAY_ICON_MENU_COMMAND 40007
|
||||
|
||||
Binary file not shown.
@@ -2,6 +2,7 @@
|
||||
#include "Generated files/resource.h"
|
||||
#include "settings_window.h"
|
||||
#include "tray_icon.h"
|
||||
#include "general_settings.h"
|
||||
#include "centralized_hotkeys.h"
|
||||
#include "centralized_kb_hook.h"
|
||||
#include <Windows.h>
|
||||
@@ -90,6 +91,13 @@ void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam)
|
||||
}
|
||||
DestroyWindow(window);
|
||||
break;
|
||||
case ID_SHOW_TRAY_ICON_MENU_COMMAND:
|
||||
{
|
||||
GeneralSettings settings = get_general_settings();
|
||||
settings.showSystemTrayIcon = true;
|
||||
apply_general_settings(settings.to_json(), true);
|
||||
break;
|
||||
}
|
||||
case ID_ABOUT_MENU_COMMAND:
|
||||
if (!about_box_shown)
|
||||
{
|
||||
@@ -191,11 +199,13 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
|
||||
{
|
||||
static std::wstring settings_menuitem_label = GET_RESOURCE_STRING(IDS_SETTINGS_MENU_TEXT);
|
||||
static std::wstring exit_menuitem_label = GET_RESOURCE_STRING(IDS_EXIT_MENU_TEXT);
|
||||
static std::wstring show_tray_icon_menuitem_label = GET_RESOURCE_STRING(IDS_SHOW_TRAY_ICON_MENU_TEXT);
|
||||
static std::wstring submit_bug_menuitem_label = GET_RESOURCE_STRING(IDS_SUBMIT_BUG_TEXT);
|
||||
static std::wstring documentation_menuitem_label = GET_RESOURCE_STRING(IDS_DOCUMENTATION_MENU_TEXT);
|
||||
static std::wstring quick_access_menuitem_label = GET_RESOURCE_STRING(IDS_QUICK_ACCESS_MENU_TEXT);
|
||||
change_menu_item_text(ID_SETTINGS_MENU_COMMAND, settings_menuitem_label.data());
|
||||
change_menu_item_text(ID_EXIT_MENU_COMMAND, exit_menuitem_label.data());
|
||||
change_menu_item_text(ID_SHOW_TRAY_ICON_MENU_COMMAND, show_tray_icon_menuitem_label.data());
|
||||
change_menu_item_text(ID_REPORT_BUG_COMMAND, submit_bug_menuitem_label.data());
|
||||
change_menu_item_text(ID_DOCUMENTATION_MENU_COMMAND, documentation_menuitem_label.data());
|
||||
change_menu_item_text(ID_QUICK_ACCESS_MENU_COMMAND, quick_access_menuitem_label.data());
|
||||
@@ -312,6 +322,14 @@ void start_tray_icon(bool isProcessElevated)
|
||||
}
|
||||
}
|
||||
|
||||
void set_tray_icon_visible(bool shouldIconBeVisible)
|
||||
{
|
||||
tray_icon_data.uFlags |= NIF_STATE;
|
||||
tray_icon_data.dwStateMask = NIS_HIDDEN;
|
||||
tray_icon_data.dwState = shouldIconBeVisible ? 0 : NIS_HIDDEN;
|
||||
Shell_NotifyIcon(NIM_MODIFY, &tray_icon_data);
|
||||
}
|
||||
|
||||
void stop_tray_icon()
|
||||
{
|
||||
if (tray_icon_created)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
// Start the Tray Icon
|
||||
void start_tray_icon(bool isProcessElevated);
|
||||
// Change the Tray Icon visibility
|
||||
void set_tray_icon_visible(bool shouldIconBeVisible);
|
||||
// Stop the Tray Icon
|
||||
void stop_tray_icon();
|
||||
// Open the Settings Window
|
||||
@@ -13,4 +15,5 @@ typedef void (*main_loop_callback_function)(PVOID);
|
||||
// Calls a callback in _callback
|
||||
bool dispatch_run_on_main_ui_thread(main_loop_callback_function _callback, PVOID data);
|
||||
|
||||
// Must be the same as: settings-ui/Settings.UI/Views/ShellPage.xaml.cs -> ExitPTItem_Tapped() -> const string ptTrayIconWindowClass
|
||||
const inline wchar_t* pt_tray_icon_window_class = L"PToyTrayIconWindow";
|
||||
@@ -19,6 +19,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonPropertyName("startup")]
|
||||
public bool Startup { get; set; }
|
||||
|
||||
// Gets or sets a value indicating whether the powertoys system tray icon should be hidden.
|
||||
[JsonPropertyName("show_tray_icon")]
|
||||
public bool ShowSysTrayIcon { get; set; }
|
||||
|
||||
// Gets or sets a value indicating whether the powertoy elevated.
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
[JsonPropertyName("is_elevated")]
|
||||
@@ -75,6 +79,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public GeneralSettings()
|
||||
{
|
||||
Startup = false;
|
||||
ShowSysTrayIcon = true;
|
||||
IsAdmin = false;
|
||||
EnableWarningsElevatedApps = true;
|
||||
IsElevated = false;
|
||||
|
||||
@@ -224,6 +224,36 @@ namespace ViewModelTests
|
||||
viewModel.ThemeIndex = 0;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IsShowSysTrayIconEnabledByDefaultShouldDisableWhenSuccessful()
|
||||
{
|
||||
// Arrange
|
||||
// Assert
|
||||
Func<string, int> sendMockIPCConfigMSG = msg =>
|
||||
{
|
||||
OutGoingGeneralSettings snd = JsonSerializer.Deserialize<OutGoingGeneralSettings>(msg);
|
||||
Assert.IsFalse(snd.GeneralSettings.ShowSysTrayIcon);
|
||||
return 0;
|
||||
};
|
||||
|
||||
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
|
||||
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
||||
GeneralViewModel viewModel = new(
|
||||
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
||||
"GeneralSettings_RunningAsAdminText",
|
||||
"GeneralSettings_RunningAsUserText",
|
||||
false,
|
||||
false,
|
||||
sendMockIPCConfigMSG,
|
||||
sendRestartAdminIPCMessage,
|
||||
sendCheckForUpdatesIPCMessage,
|
||||
GeneralSettingsFileName);
|
||||
Assert.IsTrue(viewModel.ShowSysTrayIcon);
|
||||
|
||||
// Act
|
||||
viewModel.ShowSysTrayIcon = false;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AllModulesAreEnabledByDefault()
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
internal const int SW_SHOWNORMAL = 1;
|
||||
internal const int SW_SHOWMAXIMIZED = 3;
|
||||
internal const int SW_HIDE = 0;
|
||||
internal const int WM_COMMAND = 0x0111; // https://learn.microsoft.com/en-us/windows/win32/menurc/wm-command
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr GetActiveWindow();
|
||||
@@ -48,6 +49,12 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
[DllImport("Comdlg32.dll", CharSet = CharSet.Unicode)]
|
||||
internal static extern bool GetOpenFileName([In, Out] OpenFileName openFileName);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr SendMessage(IntPtr hWnd, IntPtr msg, UIntPtr wParam, UIntPtr lParam);
|
||||
|
||||
[DllImport("comdlg32.dll", CharSet = CharSet.Auto, EntryPoint = "ChooseFont", SetLastError = true)]
|
||||
internal static extern bool ChooseFont(IntPtr lpChooseFont);
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
<tkconverters:StringFormatConverter x:Key="StringFormatConverter" />
|
||||
<tkconverters:BoolNegationConverter x:Key="BoolNegationConverter" />
|
||||
<x:Double x:Key="SettingsCardSpacing">2</x:Double>
|
||||
|
||||
<!-- Overrides -->
|
||||
<Thickness x:Key="InfoBarIconMargin">6,16,16,16</Thickness>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<StackPanel
|
||||
ChildrenTransitions="{StaticResource SettingsCardsAnimations}"
|
||||
Orientation="Vertical"
|
||||
Spacing="2" />
|
||||
Spacing="{StaticResource SettingsCardSpacing}" />
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
@@ -176,7 +176,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
|
||||
});
|
||||
}
|
||||
|
||||
private void ReportBugBtn_Click(object sender, RoutedEventArgs e)
|
||||
internal void ReportBugBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.StartBugReport();
|
||||
|
||||
|
||||
@@ -266,6 +266,10 @@
|
||||
<tkcontrols:SettingsCard x:Uid="GeneralPage_RunAtStartUp" IsEnabled="{x:Bind ViewModel.IsRunAtStartupGPOManaged, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.Startup, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="ShowSystemTrayIcon">
|
||||
<ToggleSwitch x:Uid="ShowSystemTrayIcon_ToggleSwitch" IsOn="{x:Bind ViewModel.ShowSysTrayIcon, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<InfoBar
|
||||
x:Uid="GPO_SettingIsManaged"
|
||||
BorderThickness="0"
|
||||
@@ -402,10 +406,11 @@
|
||||
</InfoBar>
|
||||
</controls:SettingsGroup>
|
||||
<controls:SettingsGroup x:Uid="General_DiagnosticsAndFeedback" Visibility="Visible">
|
||||
<StackPanel>
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
<HyperlinkButton
|
||||
x:Uid="GeneralPage_DiagnosticsAndFeedback_Link"
|
||||
Margin="-8,0,0,0"
|
||||
Margin="0,0,0,8"
|
||||
Padding="0"
|
||||
NavigateUri="https://aka.ms/powertoys-data-and-privacy-documentation" />
|
||||
<tkcontrols:SettingsCard
|
||||
x:Uid="GeneralPage_EnableDataDiagnostics"
|
||||
@@ -449,7 +454,12 @@
|
||||
<Button x:Uid="GeneralPage_ViewDiagnosticDataViewerInfoButton" Click="Click_ViewDiagnosticDataViewerRestart" />
|
||||
</InfoBar.ActionButton>
|
||||
</InfoBar>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="GeneralPage_ReportBugPackage" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<Button
|
||||
x:Uid="GeneralPageReportBugPackage"
|
||||
HorizontalAlignment="Right"
|
||||
Click="BugReportToolClicked" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</StackPanel>
|
||||
</controls:SettingsGroup>
|
||||
</StackPanel>
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Flyout;
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||
@@ -165,5 +166,24 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
await Task.Run(ViewModel.ViewDiagnosticData);
|
||||
}
|
||||
|
||||
private void ExitPTItem_Tapped(object sender, RoutedEventArgs e)
|
||||
{
|
||||
const string ptTrayIconWindowClass = "PToyTrayIconWindow"; // Defined in runner/tray_icon.h
|
||||
const nuint ID_EXIT_MENU_COMMAND = 40001; // Generated resource from runner/runner.base.rc
|
||||
|
||||
// Exit the XAML application
|
||||
Application.Current.Exit();
|
||||
|
||||
// Invoke the exit command from the tray icon
|
||||
IntPtr hWnd = NativeMethods.FindWindow(ptTrayIconWindowClass, ptTrayIconWindowClass);
|
||||
NativeMethods.SendMessage(hWnd, NativeMethods.WM_COMMAND, ID_EXIT_MENU_COMMAND, 0);
|
||||
}
|
||||
|
||||
private void BugReportToolClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var launchPage = new LaunchPage();
|
||||
launchPage.ReportBugBtn_Click(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,17 @@
|
||||
Margin="48,0,0,0"
|
||||
VerticalAlignment="Top"
|
||||
IsHitTestVisible="True">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition x:Name="LeftTitleBarColumn" Width="*" />
|
||||
<ColumnDefinition x:Name="RightTitleBarColumn" Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<animations:Implicit.Animations>
|
||||
<animations:OffsetAnimation Duration="0:0:0.3" />
|
||||
</animations:Implicit.Animations>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<StackPanel
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Left"
|
||||
Orientation="Horizontal">
|
||||
<Image
|
||||
Width="16"
|
||||
Height="16"
|
||||
@@ -64,6 +71,24 @@
|
||||
TextWrapping="NoWrap"
|
||||
Visibility="Collapsed" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
Margin="0,0,148,0"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="ShutDownBtn"
|
||||
Height="48"
|
||||
Click="ExitPTItem_Tapped"
|
||||
Style="{StaticResource SubtleButtonStyle}">
|
||||
<FontIcon FontSize="16" Glyph="" />
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip>
|
||||
<TextBlock x:Uid="AppTitleBarShutDown_Tooltip" />
|
||||
</ToolTip>
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<NavigationView
|
||||
x:Name="navigationView"
|
||||
|
||||
@@ -9,6 +9,7 @@ using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Services;
|
||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Automation.Peers;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
@@ -422,6 +423,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
// A custom title bar is required for full window theme and Mica support.
|
||||
// https://docs.microsoft.com/windows/apps/develop/title-bar?tabs=winui3#full-customization
|
||||
u.ExtendsContentIntoTitleBar = true;
|
||||
u.AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall;
|
||||
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(u));
|
||||
u.SetTitleBar(AppTitleBar);
|
||||
var loader = ResourceLoaderInstance.ResourceLoader;
|
||||
@@ -457,5 +459,18 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
navigationView.IsPaneOpen = !navigationView.IsPaneOpen;
|
||||
}
|
||||
|
||||
private void ExitPTItem_Tapped(object sender, RoutedEventArgs e)
|
||||
{
|
||||
const string ptTrayIconWindowClass = "PToyTrayIconWindow"; // Defined in runner/tray_icon.h
|
||||
const nuint ID_EXIT_MENU_COMMAND = 40001; // Generated resource from runner/runner.base.rc
|
||||
|
||||
// Exit the XAML application
|
||||
Application.Current.Exit();
|
||||
|
||||
// Invoke the exit command from the tray icon
|
||||
IntPtr hWnd = NativeMethods.FindWindow(ptTrayIconWindowClass, ptTrayIconWindowClass);
|
||||
NativeMethods.SendMessage(hWnd, NativeMethods.WM_COMMAND, ID_EXIT_MENU_COMMAND, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4299,6 +4299,12 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<data name="GeneralPage_ShowWhatsNewAfterUpdates.Content" xml:space="preserve">
|
||||
<value>Show the release notes after an update</value>
|
||||
</data>
|
||||
<data name="ShowSystemTrayIcon.Description" xml:space="preserve">
|
||||
<value>This settings page is accessible by running the PowerToys executable again</value>
|
||||
</data>
|
||||
<data name="ShowSystemTrayIcon.Header" xml:space="preserve">
|
||||
<value>Show system tray icon</value>
|
||||
</data>
|
||||
<data name="QuickAccent_Prevent_Activation_On_Game_Mode.Content" xml:space="preserve">
|
||||
<value>Do not activate when Game Mode is on</value>
|
||||
<comment>"Game mode" is the Windows feature to prevent notification when playing a game.</comment>
|
||||
@@ -5020,4 +5026,25 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<data name="Help_hueOklch" xml:space="preserve">
|
||||
<value>hue (Oklch)</value>
|
||||
</data>
|
||||
<data name="ExitPT_NavViewItem.Content" xml:space="preserve">
|
||||
<value>Exit PowerToys</value>
|
||||
</data>
|
||||
<data name="General_System.Header" xml:space="preserve">
|
||||
<value>System</value>
|
||||
</data>
|
||||
<data name="GeneralPage_ReportBugPackage.Header" xml:space="preserve">
|
||||
<value>Generate bug report package</value>
|
||||
</data>
|
||||
<data name="GeneralPage_ReportBugPackage.Description" xml:space="preserve">
|
||||
<value>Create zip folder with logs on the Desktop</value>
|
||||
</data>
|
||||
<data name="GeneralPageReportBugPackage.Content" xml:space="preserve">
|
||||
<value>Generate package</value>
|
||||
</data>
|
||||
<data name="AppTitleBarShutDown_Tooltip.Text" xml:space="preserve">
|
||||
<value>Shut down</value>
|
||||
</data>
|
||||
<data name="BugReportUnderConstruction" xml:space="preserve">
|
||||
<value>Bug report package is being created</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -146,6 +146,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
_startup = GeneralSettingsConfig.Startup;
|
||||
}
|
||||
|
||||
_showSysTrayIcon = GeneralSettingsConfig.ShowSysTrayIcon;
|
||||
_showNewUpdatesToastNotification = GeneralSettingsConfig.ShowNewUpdatesToastNotification;
|
||||
_autoDownloadUpdates = GeneralSettingsConfig.AutoDownloadUpdates;
|
||||
_showWhatsNewAfterUpdates = GeneralSettingsConfig.ShowWhatsNewAfterUpdates;
|
||||
@@ -228,6 +229,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
|
||||
private static bool _isDevBuild;
|
||||
private bool _startup;
|
||||
private bool _showSysTrayIcon;
|
||||
private GpoRuleConfigured _runAtStartupGpoRuleConfiguration;
|
||||
private bool _runAtStartupIsGPOConfigured;
|
||||
private bool _isElevated;
|
||||
@@ -359,6 +361,25 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
// Gets or sets a value indicating whether the PowerToys icon should be shown in the system tray.
|
||||
public bool ShowSysTrayIcon
|
||||
{
|
||||
get
|
||||
{
|
||||
return _showSysTrayIcon;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_showSysTrayIcon != value)
|
||||
{
|
||||
_showSysTrayIcon = value;
|
||||
GeneralSettingsConfig.ShowSysTrayIcon = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string RunningAsText
|
||||
{
|
||||
get
|
||||
|
||||
Reference in New Issue
Block a user