Skip to content

Add MiniTaskbar mod#4422

Open
Mirochill wants to merge 2 commits into
ramensoftware:mainfrom
Mirochill:add-mini-taskbar
Open

Add MiniTaskbar mod#4422
Mirochill wants to merge 2 commits into
ramensoftware:mainfrom
Mirochill:add-mini-taskbar

Conversation

@Mirochill

@Mirochill Mirochill commented Jun 14, 2026

Copy link
Copy Markdown

Adds the MiniTaskbar Windhawk mod as a dedicated tool-process mod.

Validation performed locally:

  • python .github\pr_validation.py mods\mini-taskbar.wh.cpp Mirochill
  • python scripts\compile_mod.py -w "C:\Program Files\Windhawk" -f mods\mini-taskbar.wh.cpp -o32 %TEMP%\pr-mini-taskbar_32.dll -o64 %TEMP%\pr-mini-taskbar_64.dll -oarm64 %TEMP%\pr-mini-taskbar_arm64.dll

Notes:

  • Designed for the classic Windows 10 Explorer taskbar.
  • Applies transparent taskbar accent, optional DWM wallpaper backing, and centered MSTaskListWClass application buttons.
  • The helper process is launched automatically by Windhawk using the tool-mod pattern.

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):

Please select the options that best apply. Your selection does not affect the acceptance criteria, but it helps reviewers understand the context of the code and provide relevant feedback.

@Mirochill

Mirochill commented Jun 14, 2026

Copy link
Copy Markdown
Author

Local validation is complete on my side.

Latest update:

  • The worker thread now creates its message queue explicitly before exposing its thread id, making PostThreadMessage reliable for settings reload/unload.
  • Disabling transparentTaskbar now restores the default taskbar accent immediately when restoreOnUnload is enabled.

Validation:

  • python .github\pr_validation.py mods\mini-taskbar.wh.cpp Mirochill
  • Compiles with installed Windhawk 1.7.3:
    python scripts\compile_mod.py -w "C:\Program Files\Windhawk" -f mods\mini-taskbar.wh.cpp -o32 %TEMP%\pr-mini-taskbar_32.dll -o64 %TEMP%\pr-mini-taskbar_64.dll -oarm64 %TEMP%\pr-mini-taskbar_arm64.dll
  • Also compiles with portable Windhawk 1.6.1:
    python scripts\compile_mod.py -w %TEMP%\windhawk-ci-compat\1.6.1 -f mods\mini-taskbar.wh.cpp -o32 %TEMP%\compat-161-mini-taskbar_32.dll -o64 %TEMP%\compat-161-mini-taskbar_64.dll -oarm64 %TEMP%\compat-161-mini-taskbar_arm64.dll

The GitHub Actions runs currently show action_required; I don't have repository admin rights to approve/rerun them from the fork PR.

@m417z

m417z commented Jun 15, 2026

Copy link
Copy Markdown
Member

In addition to the review below, please fill the "Mod authorship" form.

Submission review

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

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


The mod runs its worker loop inside explorer.exe, not in a dedicated process — and the tool-mod launcher you wrote is dead code. The README says "Windhawk starts this mod automatically in a dedicated helper process. The main Explorer process is not used for a resident loop." That's not what happens. With @include explorer.exe, Wh_ModInit calls ShouldRunInThisProcess() and, in the shell explorer.exe, runs WhTool_ModInit() → the resident worker thread inside explorer.exe itself. Meanwhile the actual dedicated-process plumbing is never invoked:

  • LaunchToolModProcess() (the CreateProcessInternalW launcher, lines 1292–1340) — never called.
  • EntryPoint_Hook() (line 1206) — never hooked.
  • g_isToolModProcessLauncher (line 182) and g_toolModProcessMutex (created nowhere, only CloseHandle'd) — dead.
  • GetToolProcessKind()'s CurrentToolMod/OtherToolMod branches are unreachable, since no -tool-mod process is ever spawned.

This mod is a textbook fit for the real "Mods as tools" pattern: it installs zero function hooks — everything it does (SetWinEventHook, EnumWindows, FindWindow, SetWindowPos, AccessibleObjectFromWindow, SetWindowCompositionAttribute, DWM thumbnails) works cross-process from a dedicated process. Running it inside the shell means a bug in the centering math, the UIA calls, or the DWM handling can destabilize/crash explorer.exe, which is exactly what the tool-mod pattern exists to avoid. It also injects the DLL into every explorer.exe (file-browser windows included), staying loaded-but-inert in all but the shell process.

Please complete the conversion to a genuine tool mod rather than running in the shell:

  • Set @include windhawk.exe.
  • Use the verbatim launcher snippet from the wiki — the bottom of mods/explorer-folder-hover-menu.wh.cpp is a direct copy and demonstrates all three WhTool_* callbacks. You already have the WhTool_ModInit/SettingsChanged/Uninit bodies and a CreateProcessInternalW launcher; just wire Wh_ModInit to the canonical flow (launcher process spawns the dedicated process; the -tool-mod process runs WhTool_ModInit and hooks its entry point to ExitThread).
  • Delete the home-grown ShouldRunInThisProcess/IsShellExplorerProcess/CommandLineHasNoArguments/LaunchToolModProcess glue and the unused scaffolding above.

(If you have a deliberate reason the worker must live in explorer.exe, then at minimum the README is wrong and must be corrected, and all the unused launcher code should be removed — but given there are no function hooks, the dedicated-process pattern is the right call.)

Add a screenshot or GIF to the README. The mod has a strong, clearly visible effect (transparent taskbar, centered buttons, wallpaper backing) but the README has no image. A before/after screenshot or a short GIF would help users a lot. Only i.imgur.com and raw.githubusercontent.com are allowed image hosts.

Optional improvements

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

  • Use the real DWM_THUMBNAIL_PROPERTIES. You include <dwmapi.h>, which already declares DWM_THUMBNAIL_PROPERTIES, yet you hand-roll DwmThumbnailPropertiesCompat (lines 158–165) and reinterpret_cast it (line 870). The layouts are identical, so drop the compat struct and use the SDK type directly — it's clearer and removes a fragile cast.
  • std::atomic event flags look unnecessary. With WINEVENT_OUTOFCONTEXT, WinEventProc is dispatched on the thread that registered the hooks — i.e. your worker thread, which also reads/clears g_centeringEvent/g_foregroundEvent/g_foregroundLocationEvent and g_foregroundWindow. So there's no cross-thread access and the atomics aren't buying anything; plain bools would do. (Harmless as-is — flagging it as a likely artifact of the dual-design scaffolding.)
  • g_workerThreadId is read across threads as a plain DWORD (set on the worker at line 1055, read on the unload thread at lines 1185/1192). The read is benign on x86/ARM64, but making it std::atomic<DWORD> documents the intent. There's also a small startup window where a settings change arriving before the worker sets the id is silently dropped — minor.
  • Remove -lgdi32 from @compilerOptions — no GDI function is used (MulDiv is in kernel32, GetDpiForWindow in user32). CI doesn't catch unused -l libs.

Functionality notes

Non-critical observations about the feature behavior itself — no action required.

  • Centering fights Explorer's own layout. Repositioning MSTaskListWClass with SetWindowPos is inherently best-effort: Explorer re-lays-out the rebar on its own passes, which is why you need event re-assertion + the centerFallbackMilliseconds poll. Under rapid button churn this can briefly flicker or snap back. That's expected for this approach; just noting it's not perfectly authoritative.
  • EstimateApplicationGroupWidth fallback is coarse. When the UIA anchor fails, the width estimate counts every application window across all monitors (CountApplicationWindowsForTaskbar enumerates all top-level windows) and applies it per taskbar, so on multi-monitor setups the per-monitor estimate can be off. It's only the fallback path, so impact is limited.
  • Accent restore goes to Disabled, not the original state. On unload (with restoreOnUnload) you force AccentState::Disabled, which makes the taskbar opaque/default rather than whatever accent the user actually had (e.g. blur-behind). It's transient (resets on Explorer restart) so not a reversibility problem, but the restored look may not match the pre-mod look.
  • Wallpaper backing via a non-topmost DWM-thumbnail window. The backing STATIC popup is z-ordered just behind the taskbar but isn't WS_EX_TOPMOST, while the taskbar typically is. Against other topmost windows the backing may not always sit exactly where intended. Creative approach overall — just calling out the z-order edge case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants