Skip to content

Autohide Taskbar on Desktop Only - #5004

Open
qwertyuiop00-art wants to merge 12 commits into
ramensoftware:mainfrom
qwertyuiop00-art:main
Open

Autohide Taskbar on Desktop Only#5004
qwertyuiop00-art wants to merge 12 commits into
ramensoftware:mainfrom
qwertyuiop00-art:main

Conversation

@qwertyuiop00-art

Copy link
Copy Markdown

Mod authorship

If this pull request introduces a new mod, please complete the section below.

This mod was created by:

    • The submitter, without AI assistance
    • The submitter, with AI assistance
    • Claude
    • ChatGPT
    • Gemini
    • Another AI (please specify):
    • Other (please specify):

@windhawk-reviewer windhawk-reviewer Bot added the waiting-for-author The author's turn: request an AI review, or respond to one that was posted. label Aug 4, 2026
@windhawk-reviewer

Copy link
Copy Markdown

Thanks for the pull request! This repository uses a two-stage review: an AI review that you run yourself, followed by a human review.

To get started, comment /ai-review. Once you're happy with the result, comment /ready-for-reviewer to hand it over to a human reviewer.

See the pull request review process for the full details.

@qwertyuiop00-art

Copy link
Copy Markdown
Author

/ai-review

@windhawk-reviewer windhawk-reviewer Bot added waiting-for-ai-review An AI review was requested and is being prepared. and removed waiting-for-author The author's turn: request an AI review, or respond to one that was posted. labels Aug 4, 2026
@qwertyuiop00-art

Copy link
Copy Markdown
Author

/ready-for-reviewer

@windhawk-reviewer

Copy link
Copy Markdown

@qwertyuiop00-art /ready-for-reviewer can't be applied here: an AI review is being prepared, please wait for it to be posted.

@windhawk-reviewer

Copy link
Copy Markdown

Submission review

Note: This review was done by Claude. Due to the amount of submissions, doing a fully manual review for each pull request is no longer feasible. Thank you for understanding.

Remember: The AI reviewer can be wrong - it may misread code, flag correct code as broken, or suggest changes that make things worse. Treat its findings as suggestions to verify, not instructions to follow blindly. You're responsible for the code you submit, so if a finding doesn't hold up, say so instead of changing working code to satisfy it.

Please address the following issues. The items in the collapsed sections are optional, so it's your call whether to address them.


Main issues: the WinEvent hook won't fire in the common case, the mod permanently overwrites the user's taskbar auto-hide setting, and the functionality overlaps an existing mod.

1. The WinEvent hook is installed on a thread with no message loop, so it usually never fires.

SetWinEventHook with WINEVENT_OUTOFCONTEXT delivers events to the installing thread's message queue — the callback only runs while that thread pumps messages, and the hook is owned by that thread. Per the mod lifetime, Wh_ModInit runs on the process main thread only when the mod is loaded before the process starts; when the mod is enabled, updated, or reloaded into an already-running explorer.exe — which is what happens every time you toggle it — it runs on the Windhawk engine thread, which has no message loop. So the mod does nothing until Explorer is restarted. (UnhookWinEvent in Wh_ModUninit has the same problem in reverse: it always runs on the engine thread, not the thread that installed the hook.)

This is exactly the "works after a reboot but not when enabled mid-session" class of bug the maintainer won't merge. Every mod in the repo that uses out-of-context WinEvent hooks creates its own message-loop thread — see keep-rainmeter-always-bottom.wh.cpp#L71 and taskbar-auto-hide-when-maximized.wh.cpp#L1076:

HANDLE g_thread;
DWORD g_threadId;

DWORD WINAPI WinEventHookThread(LPVOID) {
    HWINEVENTHOOK hook =
        SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND,
                        nullptr, WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
    if (!hook) {
        Wh_Log(L"SetWinEventHook failed: %u", GetLastError());
        return 1;
    }

    BOOL bRet;
    MSG msg;
    while ((bRet = GetMessage(&msg, nullptr, 0, 0)) != 0) {
        if (bRet == -1) {
            break;
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    UnhookWinEvent(hook);  // same thread that installed it
    return 0;
}

BOOL Wh_ModInit() {
    g_thread = CreateThread(nullptr, 0, WinEventHookThread, nullptr, 0, &g_threadId);
    return g_thread != nullptr;
}

void Wh_ModUninit() {
    if (g_thread) {
        PostThreadMessage(g_threadId, WM_QUIT, 0, 0);
        WaitForSingleObject(g_thread, INFINITE);
        CloseHandle(g_thread);
        g_thread = nullptr;
    }
    // ...restore the taskbar state here (see below)
}

2. The mod destroys the user's taskbar auto-hide setting and doesn't restore it.

SetTaskbarAutoHide(false) writes lParam = ABS_ALWAYSONTOP, which clears ABS_AUTOHIDE unconditionally. Two problems:

  • The auto-hide state is a persisted user setting, not a per-process one. A user who normally runs with auto-hide enabled loses that preference permanently the first time an app is focused — and Wh_ModUninit "restores" it to not auto-hide rather than to whatever it was, so disabling the mod doesn't undo it. That breaks Windhawk's core reversibility principle: the mod's effects must disappear when it's disabled.
  • Assigning the whole lParam also clobbers the other state bits instead of toggling only ABS_AUTOHIDE.

Read the state with ABM_GETSTATE, flip only the one bit, and save/restore the original:

UINT g_originalState;

void SetTaskbarAutoHide(bool enable) {
    APPBARDATA abd = {sizeof(APPBARDATA)};
    UINT state = (UINT)SHAppBarMessage(ABM_GETSTATE, &abd);
    UINT newState = enable ? (state | ABS_AUTOHIDE) : (state & ~ABS_AUTOHIDE);
    if (newState != state) {
        abd.lParam = newState;
        SHAppBarMessage(ABM_SETSTATE, &abd);
    }
}

...capture g_originalState in init, and write it back verbatim in uninit. taskbar-auto-hide-when-maximized.wh.cpp#L860 and #L1620 show the save-and-restore pattern; taskbar-auto-hide-per-monitor.wh.cpp#L148 shows the bit-preserving form.

Worth deciding explicitly what should happen when the user already has auto-hide enabled system-wide — with the current design the mod turns their setting off whenever an app is focused, which is probably not what they want.

3. Overlap with taskbar-auto-hide-when-maximized.

taskbar-auto-hide-when-maximized already covers "taskbar hidden when something is in the way, visible on the desktop", with intersected / maximized / never modes plus per-monitor and exclusion options — and it does it by keeping the real auto-hide setting enabled and controlling the taskbar's internal shown/hidden state, so the work area never changes and nothing persistent is written. The maintainer's strong preference is to extend an existing mod rather than merge a near-duplicate. Please either describe concretely how this differs from that mod, or propose the behavior as an extra mode there (e.g. a desktopFocused option) instead of a separate mod.

4. This doesn't need to be injected into explorer.exe — it's a tool mod.

The mod has no function hooks at all; it only calls SetWinEventHook, FindWindow and SHAppBarMessage, all of which work from any process. That's the textbook "mods as tools" case: injecting into the shell means a bug in the mod can destabilize Explorer, and the mod gets loaded once per explorer.exe instance (each installing its own system-wide hook). Switch @include to windhawk.exe, rename Wh_ModInit / Wh_ModUninit to WhTool_ModInit / WhTool_ModUninit, and paste the launcher boilerplate from the wiki page verbatim. keep-rainmeter-always-bottom.wh.cpp is a tool mod doing almost exactly this (foreground WinEvent hook + message loop thread) and is a good template.

5. The initial state is never applied.

Nothing runs at load time, so the taskbar keeps whatever state it had until the user next switches windows. If the desktop is already focused when the mod is enabled, the taskbar stays visible. Call the same update path once from init (evaluate GetForegroundWindow()), and note the symmetric case: with the tool-mod change, the mod should also apply the correct state after an Explorer restart.

6. No screenshot/GIF in the README.

This mod has a clearly visible effect. A short GIF showing the taskbar hiding on the desktop and reappearing on app focus would help a lot — images must be hosted on i.imgur.com or raw.githubusercontent.com.

Optional improvements

Minor polish — none of this affects users, so it's your call.

  • abd.hWnd = FindWindow(L"Shell_TrayWnd", NULL) is dead: ABM_SETSTATE only reads cbSize and lParam, so the window handle is ignored. You can drop the FindWindow call.
  • @name is autohide-taskbar-on-desktop — that's the id, and it's what users see in the Windhawk UI. Use a readable title, and keep it consistent with the README heading ("Hide Taskbar on Desktop Only") and the PR title ("Autohide Taskbar on Desktop Only"), which currently all differ.
  • There's no logging anywhere. Add a few Wh_Log calls (it's disabled by default in production, so it costs nothing), and don't return TRUE from Wh_ModInit when the hook install failed — log the error and return FALSE.
  • GetClassName(hwnd, className, 256) — use ARRAYSIZE(className) instead of repeating the literal, and consider checking the return value (0 on failure leaves className unset).

Functionality notes

Non-critical observations and ideas about the feature behavior itself.

  • Work-area churn. Toggling the real auto-hide setting changes the desktop work area, so every switch between the desktop and an app resizes all maximized windows and can shuffle desktop icons. This is inherent to the ABM_SETSTATE approach; the alternative used by taskbar-auto-hide-when-maximized is to leave auto-hide enabled and control the taskbar's shown/hidden state directly, which keeps the work area constant.
  • Focusing the taskbar counts as "an app". When auto-hide is active and the user slides the taskbar out and clicks it, Shell_TrayWnd (or the Start menu window) becomes the foreground window, which the current logic treats as "an app is active" and pins the taskbar open. Consider excluding the shell's own windows from the check.
  • WorkerW is a loose desktop test. Explorer creates WorkerW windows for purposes other than the desktop. A more precise check is comparing against GetShellWindow(), or verifying the window hosts a SHELLDLL_DefView child.
  • Foreground transitions where there is no foreground window (hwnd == NULL) are ignored by the if (... && hwnd) guard — probably fine, just noting it's a case that isn't handled.


Next steps:

  • /ai-review - after pushing fixes, to get a review of the updated code. You can repeat this as many times as you need, but each review is thorough and usually there's no need for more than 2-3 iterations.
  • /ready-for-reviewer - once you're satisfied with the state of the pull request, to hand it over to a human reviewer. If some findings above are left unaddressed, add a short note explaining why.

See the review process for details.

@windhawk-reviewer windhawk-reviewer Bot added waiting-for-author The author's turn: request an AI review, or respond to one that was posted. and removed waiting-for-ai-review An AI review was requested and is being prepared. labels Aug 4, 2026
@windhawk-reviewer windhawk-reviewer Bot added waiting-for-ai-review An AI review was requested and is being prepared. and removed waiting-for-author The author's turn: request an AI review, or respond to one that was posted. labels Aug 4, 2026
@windhawk-reviewer

Copy link
Copy Markdown

Submission review

Note: This review was done by Claude. Due to the amount of submissions, doing a fully manual review for each pull request is no longer feasible. Thank you for understanding.

Remember: The AI reviewer can be wrong - it may misread code, flag correct code as broken, or suggest changes that make things worse. Treat its findings as suggestions to verify, not instructions to follow blindly. You're responsible for the code you submit, so if a finding doesn't hold up, say so instead of changing working code to satisfy it.

Please address the following issues. The items in the collapsed sections are optional, so it's your call whether to address them.


The idea is fine and the tool-mod choice is the right one for it, but as submitted the mod never executes any of its own code, and the mechanism it uses rewrites a persisted system setting. Details below.

1. The tool-mod boilerplate is missing — the mod currently does nothing.

The file defines WhTool_ModInit / WhTool_ModUninit, but those names mean nothing to Windhawk by themselves. There is no built-in tool-mod support: the WhTool_* callbacks are invoked only by the launcher snippet from the wiki, which has to be pasted into the mod. This file has no Wh_ModInit, Wh_ModAfterInit or Wh_ModUninit at all, so it compiles and loads, but no dedicated windhawk.exe -tool-mod process is ever launched and neither WhTool_ModInit nor WhTool_ModUninit is ever called. The @include windhawk.exe line just means the mod loads into the Windhawk UI process and sits there inert.

Paste the snippet verbatim from Mods as tools: Running mods in a dedicated process at the end of the file. Note that the snippet calls WhTool_ModSettingsChanged(), so you also need to define it even though the mod has no settings:

void WhTool_ModSettingsChanged() {}

Examples of the boilerplate in place: theme-toggler-tray.wh.cpp#L150 and explorer-folder-hover-menu.wh.cpp#L3837.

2. ABM_SETSTATE rewrites the user's persisted taskbar setting on every window switch.

ABS_AUTOHIDE is not a per-process or transient flag — it is the user's global "Automatically hide the taskbar" setting, which explorer persists (StuckRects3). So the mod writes a user setting to the registry on every desktop↔app transition, and the only thing that restores it is WhTool_ModUninit, which runs on a clean unload. Every other way the process can end — sign-out, reboot, windhawk.exe being killed or crashing, power loss — leaves the setting exactly as the mod last wrote it. If that happened while the desktop was focused, the user's taskbar stays on auto-hide permanently, with no indication the mod caused it. A mod's effects are supposed to disappear when it stops running.

There is also a smaller variant of the same problem: g_originalState is captured once in WhTool_ModInit, so if the user toggles auto-hide themselves while the mod is loaded, unload silently reverts their change.

The clean approach is the one taskbar-auto-hide-when-maximized.wh.cpp uses: enable auto-hide once, suppress attempts to disable it, and then drive the actual show/hide through explorer's own tray code (TrayUI::_HandleTrayPrivateSettingMessage and TrayUI::Unhide) rather than rewriting the persisted state per switch. That requires injecting into explorer.exe, so it stops being a tool mod — which ties into the next point. If you keep the appbar approach, at minimum re-read the current state before restoring it (instead of blindly writing g_originalState), and handle session end so a sign-out/reboot doesn't leave the setting flipped (a hidden top-level window handling WM_ENDSESSION — a message-only window won't get it).

3. Overlap with taskbar-auto-hide-when-maximized.

taskbar-auto-hide-when-maximized already does dynamic auto-hide driven by the foreground window (it has a foregroundWindowOnly option and an EVENT_SYSTEM_FOREGROUND hook), and it already handles secondary taskbars, explorer restarts and ExplorerPatcher. What you want here is essentially one more mode in that mod — "auto-hide only when the desktop is focused" — rather than a second mod that toggles the same global setting from a different process. The maintainer's preference is consistently to extend an existing mod instead of merging a near-adjacent one, so please consider opening an issue/PR against that mod instead; it would also give you the non-persistent mechanism from point 2 for free.

4. Unload can hang forever.

PostThreadMessage(g_threadId, WM_QUIT, 0, 0);
WaitForSingleObject(g_thread, INFINITE);

A thread has no message queue until it calls a user32 function that creates one. Between CreateThread returning in WhTool_ModInit and the worker reaching SetWinEventHook, PostThreadMessage fails with ERROR_INVALID_THREAD_ID; the return value isn't checked, so the wait then blocks forever and the mod disable/update hangs. Enable-then-immediately-disable (or a settings-triggered reload right after enabling) is enough to hit it.

Have the worker create its queue and signal readiness before WhTool_ModInit returns, e.g.:

MSG msg;
PeekMessage(&msg, nullptr, WM_USER, WM_USER, PM_NOREMOVE);  // force queue creation
SetEvent(g_threadReadyEvent);

Related: SetWinEventHook's failure is handled by returning 1 from the thread, but WhTool_ModInit has already returned TRUE by then, so the mod shows as enabled while doing nothing. Better to report the failure (log it at least) so it's diagnosable.

5. @name is the mod id, not a display name.

// @name            autohide-taskbar-on-desktop

@name is the title shown in the Windhawk mod list and on windhawk.net. Use the readable form that the README and PR title already use, e.g. Autohide Taskbar on Desktop Only.

Optional improvements

Minor polish — none of this affects users, so it's your call.

  • The README has no screenshot or GIF. The effect is visual, so a short GIF of the taskbar hiding/showing would help a lot (only i.imgur.com and raw.githubusercontent.com are allowed image hosts).
  • WinEventProc doesn't filter the object: add if (idObject != OBJID_WINDOW || idChild != CHILDID_SELF) return; so only real foreground-window events are acted on.
  • -luser32 in @compilerOptions is redundant — user32 is linked by default (e.g. taskbar-auto-hide-when-maximized calls SetWinEventHook and doesn't list it). -lshell32 is genuinely needed, both for SHAppBarMessage and for CommandLineToArgvW in the tool-mod boilerplate.
  • Consider the WM_APP + PostQuitMessage teardown used at taskbar-auto-hide-when-maximized.wh.cpp#L1108 instead of posting WM_QUIT directly.
  • There are no Wh_Log calls anywhere. A couple of them (e.g. Wh_Log(L"> isDesktop=%d", isDesktop)) make user-reported issues much easier to diagnose; logging is off by default, so it costs nothing.
  • The README bullet "Preserves user's original taskbar auto-hide settings on unload" is only true for a clean unload — either make it true (point 2) or soften the wording.

Functionality notes

Non-critical observations and ideas about the feature behavior itself.

  • Anything that isn't Progman/WorkerW counts as "an app", including the taskbar itself, Start, Search and the tray flyouts. So while the taskbar is hidden, hovering to reveal it and clicking it makes Shell_TrayWnd foreground → auto-hide is turned off → the taskbar stays pinned open until you click back on the desktop. Opening/closing Start does the same round trip. Treating Shell_TrayWnd, Shell_SecondaryTrayWnd, Windows.UI.Core.CoreWindow and XamlExplorerHostIslandWindow as "leave the state alone" rather than "show" would make this much less jumpy.
  • When there is no foreground window (GetForegroundWindow() returns NULL — lock screen, secure desktop, transient states), className stays empty and the mod treats it as "not desktop" and shows the taskbar. Worth making that case explicit rather than incidental.
  • Each transition makes explorer re-layout the taskbar and recompute the desktop work area, which other windows react to. With frequent desktop↔app switching that's a fair amount of churn; the TrayUI::Unhide approach from point 2 avoids it entirely.


Next steps:

  • /ai-review - after pushing fixes, to get a review of the updated code. You can repeat this as many times as you need, but each review is thorough and usually there's no need for more than 2-3 iterations.
  • /ready-for-reviewer - once you're satisfied with the state of the pull request, to hand it over to a human reviewer. If some findings above are left unaddressed, add a short note explaining why.

See the review process for details.

@windhawk-reviewer windhawk-reviewer Bot added waiting-for-author The author's turn: request an AI review, or respond to one that was posted. and removed waiting-for-ai-review An AI review was requested and is being prepared. labels Aug 4, 2026
@qwertyuiop00-art

Copy link
Copy Markdown
Author

/ai-review

@windhawk-reviewer windhawk-reviewer Bot added waiting-for-ai-review An AI review was requested and is being prepared. and removed waiting-for-author The author's turn: request an AI review, or respond to one that was posted. labels Aug 4, 2026
@windhawk-reviewer

Copy link
Copy Markdown

Submission review

Note: This review was done by Claude. Due to the amount of submissions, doing a fully manual review for each pull request is no longer feasible. Thank you for understanding.

Remember: The AI reviewer can be wrong - it may misread code, flag correct code as broken, or suggest changes that make things worse. Treat its findings as suggestions to verify, not instructions to follow blindly. You're responsible for the code you submit, so if a finding doesn't hold up, say so instead of changing working code to satisfy it.

Please address the following issues. The items in the collapsed sections are optional, so it's your call whether to address them.


The idea is nice and the code is small and readable, but the mechanism it uses — flipping the persisted, system-wide taskbar auto-hide setting on every focus change — has several consequences that need fixing before this can be merged.

1. The mod makes a persistent system change that can survive its own removal

SHAppBarMessage(ABM_SETSTATE, ...) sets the very same "Automatically hide the taskbar" option the user sets in Settings; Explorer persists it (StuckRects3). The mod flips it on every foreground switch, and only restores the original in Wh_ModUninit.

Wh_ModUninit runs on a normal mod unload (disable/reload), but not when Explorer itself goes away — reboot, sign-out, or an Explorer crash. If the desktop happens to be focused at that moment, the taskbar is left permanently auto-hiding, and it stays that way after the mod is disabled or uninstalled. That's a violation of Windhawk's "a mod's effects disappear when it's disabled" principle.

For reference, taskbar-auto-hide-when-maximized solves the same class of problem without per-event setting flips: it enables auto-hide once, remembers that it did, and then controls visibility through the taskbar's own hide/unhide path (TrayUI::Unhide / the hide timer) instead of rewriting the user's setting. That's a bigger change, but it's the approach that doesn't leak state out of the mod. At minimum, please implement the mitigations in the next two items.

2. g_originalState is captured at the wrong time and poisons itself

Two separate problems:

  • At Explorer startup, Wh_ModInit runs before the process begins executing, so Shell_TrayWnd doesn't exist yet and SHAppBarMessage(ABM_GETSTATE, &abd) returns 0. Wh_ModUninit then "restores" state 0, i.e. auto-hide off and ABS_ALWAYSONTOP cleared — not what the user had. So the mod only behaves correctly when it's enabled mid-session, and misbehaves after every reboot / Explorer restart. (Testing after an Explorer restart is a standard expectation for submissions.)
  • After any ungraceful exit (item 1), the next Wh_ModInit reads back the mod's own value as "the original", so the user's actual preference is lost for good.

Fix: capture the original state once, lazily (from the worker thread, after the taskbar window exists), and persist it with Wh_SetIntValue / Wh_GetIntValue so it survives Explorer restarts and isn't re-captured from a value the mod itself wrote.

3. SetTaskbarAutoHide clobbers the other state bits

abd.lParam = enable ? ABS_AUTOHIDE : ABS_ALWAYSONTOP;

Disabling auto-hide also force-enables always-on-top, even for a user who had it off. Read the current state and flip only the one bit, as in taskbar-auto-hide-per-monitor:

abd.lParam = enable ? (state | ABS_AUTOHIDE) : (state & ~ABS_AUTOHIDE);

4. ABM_SETSTATE is issued on every foreground change, even when nothing changes

UpdateStateForWindow calls SetTaskbarAutoHide unconditionally, so every single alt-tab / window click makes Explorer re-apply and re-persist the taskbar state. Cache the last applied value and only call when it actually changes:

static int g_lastApplied = -1;  // or std::optional<bool>
if (g_lastApplied != (int)isDesktop) {
    g_lastApplied = isDesktop;
    SetTaskbarAutoHide(isDesktop);
}

5. This should be a tool mod, not an explorer.exe injection

The mod installs no function hooks at all — it only uses SetWinEventHook with WINEVENT_OUTOFCONTEXT, FindWindow and SHAppBarMessage, all of which work from any process. Meanwhile @include explorer.exe means one copy per explorer.exe process, and there can be more than one (e.g. with "launch folder windows in a separate process"). Each copy would install its own hook thread, snapshot its own g_originalState, and fight the others over a single global setting. A bug here also destabilizes the shell for no benefit.

Please convert it to a tool mod: @include windhawk.exe, rename Wh_ModInit/Wh_ModUninitWhTool_ModInit/WhTool_ModUninit, and paste the launcher snippet verbatim from Mods as tools: Running mods in a dedicated process. explorer-folder-hover-menu is a good working example.

(Note this doesn't fix item 1 by itself — the tool process is also terminated at sign-out/shutdown without Wh_ModUninit running.)

6. Unload can unload the DLL while the worker thread is still running

PostThreadMessage(g_threadId, WM_QUIT, 0, 0);
WaitForSingleObject(g_thread, 2000);

If the wait times out, Wh_ModUninit returns anyway, Windhawk unmaps the mod image, and the still-running thread executes freed code → crash in Explorer. This isn't hypothetical: PostThreadMessage fails with ERROR_INVALID_THREAD_ID if the target thread has no message queue yet, which is exactly the case if the 3 s g_readyEvent wait in Wh_ModInit timed out — and then the 2 s wait is guaranteed to time out.

Check the PostThreadMessage result and wait INFINITE, as in taskbar-auto-hide-when-maximized.

7. Relationship to existing mods

taskbar-auto-hide-when-maximized already covers "conditionally auto-hide the taskbar based on what's on screen" (with a mode option and foregroundWindowOnly), and taskbar-auto-hide-keyboard-only covers auto-hide fine-tuning. Your trigger (desktop focused) is genuinely different from theirs (window geometry), so this isn't a straight duplicate — but the maintainer's preference is to extend an existing mod with an option rather than add a near-neighbour. Please state in the README/PR description how this differs from those two, and consider whether "auto-hide when the desktop is focused" would fit better as an additional mode in taskbar-auto-hide-when-maximized (a PR to m417z/my-windhawk-mods).

Optional improvements

Minor polish — none of this affects users, so it's your call.

  • @name is set to the mod id (autohide-taskbar-on-desktop). That's what users see in the catalog — a human-readable title like Autohide taskbar on desktop reads better.
  • The README has no visual. This is a visible UI change, so a short GIF (Imgur or raw.githubusercontent.com) would help a lot.
  • -lshell32 -luser32 look unnecessary — taskbar-auto-hide-per-monitor calls SHAppBarMessage with only -lversion. Try dropping them.
  • SHAppBarMessage lives in <shellapi.h>; include it explicitly rather than relying on <windows.h> pulling it in.
  • abd.hWnd = FindWindow(L"Shell_TrayWnd", NULL); in SetTaskbarAutoHide / Wh_ModUninit — per the docs, ABM_SETSTATE only uses cbSize and lParam, so the lookup is dead code.
  • WinEventProc should filter to the window object itself:
    if (event != EVENT_SYSTEM_FOREGROUND || idObject != OBJID_WINDOW ||
        idChild != CHILDID_SELF || !hwnd) {
        return;
    }
  • g_readyEvent handle race: if the 3 s wait times out, Wh_ModInit closes the handle and nulls the global while the worker thread may be between the if (g_readyEvent) test and SetEvent(g_readyEvent) — signalling a closed (possibly recycled) handle. Simplest fix is to let the worker thread own the handle, or keep it alive until the thread is joined in Wh_ModUninit.
  • GetClassNameW(hwnd, className, 256) — use ARRAYSIZE(className) so the two can't drift apart.
  • There are no Wh_Log calls at all. A few (Wh_Log(L"> isDesktop=%d class=%s", ...)) make user-reported issues much easier to diagnose, and they cost nothing when logging is off.

Functionality notes

Non-critical observations and ideas about the feature behavior itself.

  • Toggling auto-hide changes the desktop work area, so every desktop⇄app switch resizes all maximized windows and can reflow desktop icons. It's the most visible side effect of the current approach and another argument for the TrayUI::Unhide-style mechanism in item 1 (which keeps the work area constant).
  • Opening the Start menu / search / a shell flyout changes the foreground window to something that isn't Progman/WorkerW, so the mod treats it as "an app is active" and unhides the taskbar; closing it hides it again. Expect a visible flicker when opening Start from the desktop. You may want to treat the shell's own windows (Shell_TrayWnd, Windows.UI.Core.CoreWindow, XamlExplorerHostIslandWindow, …) as "no change".
  • If the user changes the auto-hide setting manually while the mod is enabled, the mod silently overrides it on the next focus change and later "restores" the now-stale saved value. Worth documenting, or re-reading the state when the change didn't come from the mod.
  • The mod has no settings at all. Candidates that would make it more useful: an option to invert the behavior, a short delay before hiding (to avoid toggling on quick desktop clicks), or a list of window classes treated as "desktop".
  • Progman/WorkerW is the standard desktop check (same as dynamic-taskbar-transparency), so that part looks right — just be aware WorkerW is also used by non-desktop windows in some configurations.


Next steps:

  • /ai-review - after pushing fixes, to get a review of the updated code. You can repeat this as many times as you need, but each review is thorough and usually there's no need for more than 2-3 iterations.
  • /ready-for-reviewer - once you're satisfied with the state of the pull request, to hand it over to a human reviewer. If some findings above are left unaddressed, add a short note explaining why.

See the review process for details.

@windhawk-reviewer windhawk-reviewer Bot added waiting-for-author The author's turn: request an AI review, or respond to one that was posted. and removed waiting-for-ai-review An AI review was requested and is being prepared. labels Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-for-author The author's turn: request an AI review, or respond to one that was posted.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant