WindowWalkerSettings.cs
  1  // Copyright (c) Microsoft Corporation
  2  // The Microsoft Corporation licenses this file to you under the MIT license.
  3  // See the LICENSE file in the project root for more information.
  4  
  5  using System.Collections.Generic;
  6  using System.Linq;
  7  using System.Runtime.CompilerServices;
  8  
  9  using Microsoft.Plugin.WindowWalker.Properties;
 10  using Microsoft.PowerToys.Settings.UI.Library;
 11  
 12  [assembly: InternalsVisibleTo("Microsoft.Plugin.WindowWalker.UnitTests")]
 13  
 14  namespace Microsoft.Plugin.WindowWalker.Components
 15  {
 16      /// <summary>
 17      /// Additional settings for the WindowWalker plugin.
 18      /// </summary>
 19      /// <remarks>Some code parts reused from TimeZone plugin.</remarks>
 20      internal sealed class WindowWalkerSettings
 21      {
 22          /// <summary>
 23          /// Are the class properties initialized with default values
 24          /// </summary>
 25          private readonly bool _initialized;
 26  
 27          /// <summary>
 28          /// An instance of the class <see cref="WindowWalkerSettings"></see>
 29          /// </summary>
 30          private static WindowWalkerSettings instance;
 31  
 32          /// <summary>
 33          /// Gets a value indicating whether we only search for windows on the currently visible desktop or on all desktops.
 34          /// </summary>
 35          internal bool ResultsFromVisibleDesktopOnly { get; private set; }
 36  
 37          /// <summary>
 38          /// Gets a value indicating whether the process id is shown in the subtitle.
 39          /// </summary>
 40          internal bool SubtitleShowPid { get; private set; }
 41  
 42          /// <summary>
 43          /// Gets a value indicating whether the desktop name is shown in the subtitle.
 44          /// We don't show the desktop name if there is only one desktop.
 45          /// </summary>
 46          internal bool SubtitleShowDesktopName { get; private set; }
 47  
 48          /// <summary>
 49          /// Gets a value indicating whether we request a confirmation when the user kills a process.
 50          /// </summary>
 51          internal bool ConfirmKillProcess { get; private set; }
 52  
 53          /// <summary>
 54          /// Gets a value indicating whether to kill the entire process tree or the selected process only.
 55          /// </summary>
 56          internal bool KillProcessTree { get; private set; }
 57  
 58          /// <summary>
 59          /// Gets a value indicating whether PowerToys run should stay open after executing killing process and closing window.
 60          /// </summary>
 61          internal bool OpenAfterKillAndClose { get; private set; }
 62  
 63          /// <summary>
 64          /// Gets a value indicating whether the "kill process" command is hidden on processes that require additional permissions (UAC).
 65          /// </summary>
 66          internal bool HideKillProcessOnElevatedProcesses { get; private set; }
 67  
 68          /// <summary>
 69          /// Gets a value indicating whether we show the explorer settings info or not.
 70          /// </summary>
 71          internal bool HideExplorerSettingInfo { get; private set; }
 72  
 73          /// <summary>
 74          /// Initializes a new instance of the <see cref="WindowWalkerSettings"/> class.
 75          /// Private constructor to make sure there is never more than one instance of this class
 76          /// </summary>
 77          private WindowWalkerSettings()
 78          {
 79              // Init class properties with default values
 80              UpdateSettings(null);
 81              _initialized = true;
 82          }
 83  
 84          /// <summary>
 85          /// Gets an instance property of this class that makes sure that the first instance gets created
 86          /// and that all the requests end up at that one instance.
 87          /// The benefit of this is that we don't need additional variables/parameters
 88          /// to communicate the settings between plugin's classes/methods.
 89          /// We can simply access this one instance, whenever we need the actual settings.
 90          /// </summary>
 91          internal static WindowWalkerSettings Instance
 92          {
 93              get
 94              {
 95                  if (instance == null)
 96                  {
 97                      instance = new WindowWalkerSettings();
 98                  }
 99  
100                  return instance;
101              }
102          }
103  
104          /// <summary>
105          /// Return a list with all additional plugin options.
106          /// </summary>
107          /// <returns>A list with all additional plugin options.</returns>
108          internal static List<PluginAdditionalOption> GetAdditionalOptions()
109          {
110              var optionList = new List<PluginAdditionalOption>
111              {
112                  new PluginAdditionalOption
113                  {
114                      Key = nameof(ResultsFromVisibleDesktopOnly),
115                      DisplayLabel = Resources.wox_plugin_windowwalker_SettingResultsVisibleDesktop,
116                      Value = false,
117                  },
118                  new PluginAdditionalOption
119                  {
120                      Key = nameof(SubtitleShowPid),
121                      DisplayLabel = Resources.wox_plugin_windowwalker_SettingSubtitlePid,
122                      Value = false,
123                  },
124                  new PluginAdditionalOption
125                  {
126                      Key = nameof(SubtitleShowDesktopName),
127                      DisplayLabel = Resources.wox_plugin_windowwalker_SettingSubtitleDesktopName,
128                      DisplayDescription = Resources.wox_plugin_windowwalker_SettingSubtitleDesktopName_Description,
129                      Value = true,
130                  },
131                  new PluginAdditionalOption
132                  {
133                      Key = nameof(ConfirmKillProcess),
134                      DisplayLabel = Resources.wox_plugin_windowwalker_SettingConfirmKillProcess,
135                      Value = true,
136                  },
137                  new PluginAdditionalOption
138                  {
139                      Key = nameof(KillProcessTree),
140                      DisplayLabel = Resources.wox_plugin_windowwalker_SettingKillProcessTree,
141                      DisplayDescription = Resources.wox_plugin_windowwalker_SettingKillProcessTree_Description,
142                      Value = false,
143                  },
144                  new PluginAdditionalOption
145                  {
146                      Key = nameof(OpenAfterKillAndClose),
147                      DisplayLabel = Resources.wox_plugin_windowwalker_SettingOpenAfterKillAndClose,
148                      DisplayDescription = Resources.wox_plugin_windowwalker_SettingOpenAfterKillAndClose_Description,
149                      Value = false,
150                  },
151                  new PluginAdditionalOption
152                  {
153                      Key = nameof(HideKillProcessOnElevatedProcesses),
154                      DisplayLabel = Resources.wox_plugin_windowwalker_SettingHideKillProcess,
155                      Value = false,
156                  },
157                  new PluginAdditionalOption
158                  {
159                      Key = nameof(HideExplorerSettingInfo),
160                      DisplayLabel = Resources.wox_plugin_windowwalker_SettingExplorerSettingInfo,
161                      DisplayDescription = Resources.wox_plugin_windowwalker_SettingExplorerSettingInfo_Description,
162                      Value = false,
163                  },
164              };
165  
166              return optionList;
167          }
168  
169          /// <summary>
170          /// Update this settings.
171          /// </summary>
172          /// <param name="settings">The settings for all power launcher plugins.</param>
173          internal void UpdateSettings(PowerLauncherPluginSettings settings)
174          {
175              if ((settings is null || settings.AdditionalOptions is null) & _initialized)
176              {
177                  return;
178              }
179  
180              ResultsFromVisibleDesktopOnly = GetSettingOrDefault(settings, nameof(ResultsFromVisibleDesktopOnly));
181              SubtitleShowPid = GetSettingOrDefault(settings, nameof(SubtitleShowPid));
182              SubtitleShowDesktopName = GetSettingOrDefault(settings, nameof(SubtitleShowDesktopName));
183              ConfirmKillProcess = GetSettingOrDefault(settings, nameof(ConfirmKillProcess));
184              KillProcessTree = GetSettingOrDefault(settings, nameof(KillProcessTree));
185              OpenAfterKillAndClose = GetSettingOrDefault(settings, nameof(OpenAfterKillAndClose));
186              HideKillProcessOnElevatedProcesses = GetSettingOrDefault(settings, nameof(HideKillProcessOnElevatedProcesses));
187              HideExplorerSettingInfo = GetSettingOrDefault(settings, nameof(HideExplorerSettingInfo));
188          }
189  
190          /// <summary>
191          /// Return one <see cref="bool"/> setting of the given settings list with the given name.
192          /// </summary>
193          /// <param name="settings">The object that contain all settings.</param>
194          /// <param name="name">The name of the setting.</param>
195          /// <returns>A settings value.</returns>
196          private static bool GetSettingOrDefault(PowerLauncherPluginSettings settings, string name)
197          {
198              var option = settings?.AdditionalOptions?.FirstOrDefault(x => x.Key == name);
199  
200              // If a setting isn't available, we use the value defined in the method GetAdditionalOptions() as fallback.
201              // We can use First() instead of FirstOrDefault() because the values must exist. Otherwise, we made a mistake when defining the settings.
202              return option?.Value ?? GetAdditionalOptions().First(x => x.Key == name).Value;
203          }
204      }
205  }