Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Flow.Launcher.Infrastructure/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,6 @@ PBT_APMRESUMEAUTOMATIC
PBT_APMRESUMESUSPEND
PowerRegisterSuspendResumeNotification
PowerUnregisterSuspendResumeNotification
DeviceNotifyCallbackRoutine
DeviceNotifyCallbackRoutine

MonitorFromWindow
1 change: 1 addition & 0 deletions Flow.Launcher.Infrastructure/UserSettings/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ public bool HideNotifyIcon
}
public bool LeaveCmdOpen { get; set; }
public bool HideWhenDeactivated { get; set; } = true;
public bool ShowTaskbarWhenInvoked { get; set; } = false;

private bool _showAtTopmost = false;
public bool ShowAtTopmost
Expand Down
28 changes: 28 additions & 0 deletions Flow.Launcher.Infrastructure/Win32Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
using Microsoft.Win32.SafeHandles;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Dwm;

Check warning on line 21 in Flow.Launcher.Infrastructure/Win32Helper.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Dwm` is not a recognized word. (unrecognized-spelling)
using Windows.Win32.System.Power;
using Windows.Win32.System.Threading;
using Windows.Win32.UI.Input.KeyboardAndMouse;
Expand All @@ -27,6 +27,7 @@
using Point = System.Windows.Point;
using SystemFonts = System.Windows.SystemFonts;


namespace Flow.Launcher.Infrastructure
{
public static class Win32Helper
Expand All @@ -44,7 +45,7 @@
{
var cloaked = cloak ? 1 : 0;

return PInvoke.DwmSetWindowAttribute(

Check warning on line 48 in Flow.Launcher.Infrastructure/Win32Helper.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Dwm` is not a recognized word. (unrecognized-spelling)
GetWindowHandle(window),
DWMWINDOWATTRIBUTE.DWMWA_CLOAK,
&cloaked,
Expand All @@ -55,9 +56,9 @@
{
var backdropType = backdrop switch
{
BackdropTypes.Acrylic => DWM_SYSTEMBACKDROP_TYPE.DWMSBT_TRANSIENTWINDOW,

Check warning on line 59 in Flow.Launcher.Infrastructure/Win32Helper.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`SYSTEMBACKDROP` is not a recognized word. (unrecognized-spelling)
BackdropTypes.Mica => DWM_SYSTEMBACKDROP_TYPE.DWMSBT_MAINWINDOW,

Check warning on line 60 in Flow.Launcher.Infrastructure/Win32Helper.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`SYSTEMBACKDROP` is not a recognized word. (unrecognized-spelling)

Check warning on line 60 in Flow.Launcher.Infrastructure/Win32Helper.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`DWMSBT` is not a recognized word. (unrecognized-spelling)
BackdropTypes.MicaAlt => DWM_SYSTEMBACKDROP_TYPE.DWMSBT_TABBEDWINDOW,

Check warning on line 61 in Flow.Launcher.Infrastructure/Win32Helper.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`SYSTEMBACKDROP` is not a recognized word. (unrecognized-spelling)

Check warning on line 61 in Flow.Launcher.Infrastructure/Win32Helper.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`DWMSBT` is not a recognized word. (unrecognized-spelling)
_ => DWM_SYSTEMBACKDROP_TYPE.DWMSBT_AUTO
};

Expand Down Expand Up @@ -1016,5 +1017,32 @@
}

#endregion

#region Taskbar

public static unsafe void ShowTaskbar()
{
// Find the taskbar window
var taskbarHwnd = PInvoke.FindWindowEx(HWND.Null, HWND.Null, "Shell_TrayWnd", null);
if (taskbarHwnd == HWND.Null) return;

// Magic from https://github.com/Oliviaophia/SmartTaskbar
const uint TrayBarFlag = 0x05D1;
var mon = PInvoke.MonitorFromWindow(taskbarHwnd, Windows.Win32.Graphics.Gdi.MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
PInvoke.PostMessage(taskbarHwnd, TrayBarFlag, new WPARAM(1), new LPARAM((nint)mon.Value));
}

public static void HideTaskbar()
{
// Find the taskbar window
var taskbarHwnd = PInvoke.FindWindowEx(HWND.Null, HWND.Null, "Shell_TrayWnd", null);
if (taskbarHwnd == HWND.Null) return;

// Magic from https://github.com/Oliviaophia/SmartTaskbar
const uint TrayBarFlag = 0x05D1;
PInvoke.PostMessage(taskbarHwnd, TrayBarFlag, new WPARAM(0), IntPtr.Zero);
}

#endregion
}
}
2 changes: 2 additions & 0 deletions Flow.Launcher/Languages/en.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@
<system:String x:Key="useLogonTaskForStartupTooltip">After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task Scheduler</system:String>
<system:String x:Key="setAutoStartFailed">Error setting launch on startup</system:String>
<system:String x:Key="hideFlowLauncherWhenLoseFocus">Hide Flow Launcher when focus is lost</system:String>
<system:String x:Key="showTaskbarWhenOpened">Show taskbar when Flow Launcher is opened</system:String>
<system:String x:Key="showTaskbarWhenOpenedToolTip">Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.</system:String>
<system:String x:Key="dontPromptUpdateMsg">Do not show new version notifications</system:String>
<system:String x:Key="SearchWindowPosition">Search Window Location</system:String>
<system:String x:Key="SearchWindowScreenRememberLastLaunchLocation">Remember Last Position</system:String>
Expand Down
10 changes: 10 additions & 0 deletions Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@
OnContent="{DynamicResource enable}" />
</ui:SettingsCard>

<ui:SettingsCard
Margin="0 4 0 0"
Description="{DynamicResource showTaskbarWhenOpenedToolTip}"
Header="{DynamicResource showTaskbarWhenOpened}">
<ui:ToggleSwitch
IsOn="{Binding Settings.ShowTaskbarWhenInvoked}"
OffContent="{DynamicResource disable}"
OnContent="{DynamicResource enable}" />
</ui:SettingsCard>

<ui:SettingsCard
Margin="0 4 0 0"
Description="{DynamicResource hideNotifyIconToolTip}"
Expand Down
11 changes: 11 additions & 0 deletions Flow.Launcher/ViewModel/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2097,6 +2097,12 @@ public void Show()
// When application is exiting, we should not show the main window
if (App.LoadingOrExiting) return;

// Show the taskbar if the setting is enabled
if (Settings.ShowTaskbarWhenInvoked)
{
Win32Helper.ShowTaskbar();
}

Comment on lines +2100 to +2105
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard HideTaskbar() with state so show/hide stay balanced

Wiring the feature through Show()/Hide() is good, but right now HideTaskbar() is gated only by the current value of Settings.ShowTaskbarWhenInvoked. That means:

  • If the setting is turned on while Flow is already open, Show() won’t have called ShowTaskbar(), but Hide() will call HideTaskbar().
  • If the setting is turned off while Flow is open, Show() will have called ShowTaskbar(), but Hide() will skip HideTaskbar().

Given this uses an undocumented taskbar message, unbalanced calls risk leaving the taskbar in a different mode than the user expects.

Consider tracking a simple flag, e.g. bool _taskbarShownByFlow;, set true only when ShowTaskbar() is actually invoked in Show(), and use that flag to decide whether to call HideTaskbar() in Hide() (and reset it to false afterward). That keeps your interaction with the shell clearly symmetric regardless of when the setting is toggled.

Also applies to: 2211-2215

🤖 Prompt for AI Agents
In Flow.Launcher/ViewModel/MainViewModel.cs around lines 2100-2105 (and
similarly 2211-2215), the current logic checks only
Settings.ShowTaskbarWhenInvoked when hiding the taskbar which can lead to
unbalanced ShowTaskbar/HideTaskbar calls if the setting is toggled while Flow is
open; add a private bool field (e.g. _taskbarShownByFlow) to the viewmodel, set
it to true only when Show() actually calls Win32Helper.ShowTaskbar() (and only
when the setting is enabled), and in Hide() call Win32Helper.HideTaskbar() only
if _taskbarShownByFlow is true, then reset _taskbarShownByFlow to false after
hiding — do the same mirrored change for the other method block at 2211-2215 to
keep show/hide symmetric.

// When application is exiting, the Application.Current will be null
Application.Current?.Dispatcher.Invoke(() =>
{
Expand Down Expand Up @@ -2202,6 +2208,11 @@ public async void Hide(bool reset = true)
Win32Helper.RestorePreviousKeyboardLayout();
}

if (Settings.ShowTaskbarWhenInvoked)
{
Win32Helper.HideTaskbar();
}

// Delay for a while to make sure clock will not flicker
await Task.Delay(50);

Expand Down
Loading