Skip to content

Add Taskbar Folder Menus v0.7#4485

Open
sb4ssman wants to merge 1 commit into
ramensoftware:mainfrom
sb4ssman:sb4ssman-taskbar-folder-menus
Open

Add Taskbar Folder Menus v0.7#4485
sb4ssman wants to merge 1 commit into
ramensoftware:mainfrom
sb4ssman:sb4ssman-taskbar-folder-menus

Conversation

@sb4ssman

@sb4ssman sb4ssman commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds Taskbar Folder Menus v0.7 (taskbar-folder-menus) for Windows 11.
It adds compact system-tray buttons that open configured folders, drives, and
Shell namespace targets as native cascading menus, recreating the useful part
of classic taskbar toolbars without requiring users to minimize their windows.

Features

  • Configurable folders array with a short label and target for each button.
  • Normal paths, drive roots, environment variables, and Shell namespace roots
    such as shell:Desktop and shell:ControlPanelFolder.
  • Native Shell popup menus with icons, lazy subfolder loading, and an
    Open in Explorer command for the configured root and every subfolder.
  • Full classic Shell context menus on right-click, including owner-drawn and
    dynamic extensions through IContextMenu2/IContextMenu3.
  • Canonical Smart Grid layout with smart automatic, single row, single column,
    fixed rows, fixed columns, and fixed-grid modes; row/column fill order;
    first/last short groups; and short-group alignment.
  • Five tray placement anchors, configurable button geometry, native or custom
    button colors, Windows accent tokens, borders, opacity, shine, and group
    padding/offsets.
  • Optional limits for menu size, subfolder depth, and hidden/system items.

Review and reliability fixes

  • Uses documented WM_MENURBUTTONUP handling for right-clicked menu items.
  • Suppresses unsafe process-shutdown destruction of namespace-scope XAML
    holders and releases delegates, tooltips, and boxed content before removing
    the injected subtree.
  • Returns FALSE when required taskbar symbol hooks fail and clearly documents
    that the mod supports Windows 11 only.
  • Keeps the requested TrayUI::StartTaskbar trigger. After live testing found
    that the simpler startup path could still miss the tray after a restart,
    v0.7 adds the standard three-module IconView.Loaded trigger and a bounded
    slow-sign-in retry fallback for deterministic reapplication.
  • Replaces the old mixed-unit taskbar-window row calculation with the shared
    Smart Grid template and the live SystemTrayFrameGrid height in DIPs,
    including correct inter-row spacing.
  • Repairs native tray-column collisions after recreation and resets stale XAML
    pointer-over state after a modal native menu closes.

Validation

  • Default Desktop and Control Panel buttons load and open correctly.
  • Folder, drive-root, environment-variable, Desktop, and Control Panel
    targets work with Shell icons and lazy submenus.
  • Root and nested Open in Explorer commands work.
  • Classic right-click context menus, ordinary verbs, and modal Properties
    work; click-away dismissal releases the taskbar-button visual state.
  • Smart Grid layout and automatic row capacity look correct in live use.
  • Settings reload works and the mod survives a taskbar/Explorer restart.
  • Disable/unload cleanup completes without the prior Explorer crash.
  • Windhawk Clang syntax compilation passes.
  • Folder README and embedded README match, and all six screenshot links
    point to current assets.

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.

@m417z

m417z commented Jun 22, 2026

Copy link
Copy Markdown
Member
  • I think it makes more sense for the folders option to be an array.
  • If HookTaskbarDllSymbols fails, return FALSE at Wh_ModInit.
  • Instead of handling Taskbar.View.dll and hooking LoadLibraryExW, you can hook TrayUI::StartTaskbar and simplify the implementation. There are several mods you can use as reference, such as taskbar-ai-quota.
  • You might want to clarify that this is a Win11-only mod, and that it won't work on Win10.

@sb4ssman

Copy link
Copy Markdown
Contributor Author

Updated to v0.6 with all review points addressed:

  • folders is now an array setting (per-record label + target)
  • Wh_ModInit returns FALSE when HookTaskbarDllSymbols fails
  • Replaced the Taskbar.View.dll handling and LoadLibraryExW hook with a TrayUI::StartTaskbar hook, following taskbar-ai-quota
  • Readme and description now state this is a Windows 11-only mod

Also in v0.6:

  • Fixed an Explorer crash on mod disable: Click delegates, tooltips, and boxed Content are now released before the injected subtree is removed, since XAML tears removed subtrees down on a later UI tick that can land after the mod DLL has unloaded
  • Color settings now accept accent / accentLight / accentDark and transparent in addition to hex; the hover default changed from a hardcoded #4488FF to accent

@m417z

m417z commented Jul 18, 2026

Copy link
Copy Markdown
Member

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.

I haven't verified 1, let me know if it's incorrect.


1. The right-click context-menu feature never fires — wrong window message. The subclass handles a self-defined WM_MENURBUTTONDOWN = 0x012E:

#ifndef WM_MENURBUTTONDOWN
#define WM_MENURBUTTONDOWN 0x012E
#endif
...
    if (msg == WM_MENURBUTTONDOWN) {
        UINT index = (UINT)wParam;
        HMENU hMenu = (HMENU)lParam;

0x012E is not a real Win32 message, and there is no WM_MENURBUTTONDOWN. When the user right-clicks a menu item, Windows sends WM_MENURBUTTONUP (0x0122) to the menu owner — and its parameters are exactly what your handler already reads (wParam = item index, lParam = HMENU). So the constant is just wrong; the message you want is already defined in winuser.h. As written, IContextMenu on right-click (a headline feature, and the corresponding test-plan box is still unchecked) can never trigger. Fix:

    if (msg == WM_MENURBUTTONUP) {   // 0x0122, sent to the menu owner on menu-item right-click
        UINT index = (UINT)wParam;
        HMENU hMenu = (HMENU)lParam;

and drop the #define.

2. Global XAML strong references are destroyed at process shutdown, off the UI thread. g_buttonGrid (Grid), g_injectionParent (FrameworkElement), and g_buttonEventStates (a vector of Button) hold strong XAML references at namespace scope:

static Grid              g_buttonGrid = nullptr;
static FrameworkElement  g_injectionParent = nullptr;
...
static std::vector<ButtonEventState> g_buttonEventStates;

Wh_ModUninit is not called when the host process terminates (Explorer restart, sign-out, reboot — extremely common for a taskbar mod). In that case the OS runs these globals' destructors on the shutdown thread after the XAML core is already torn down, releasing strong FrameworkElements off their UI thread — the exact thread-affinity hazard described in the Windhawk cross-thread notes, and a potential crash on every Explorer restart. Your controlled-unload cleanup (RemoveButtonGrid / ClearButtonEventState) is already correct; you just need to suppress the automatic destructor:

[[clang::no_destroy]] static Grid g_buttonGrid = nullptr;
[[clang::no_destroy]] static std::vector<ButtonEventState> g_buttonEventStates;

g_injectionParent is only ever assigned, never read (see lines 1581/1660) — it holds a strong ref for no functional reason, so the cleanest fix there is to just delete the variable rather than annotate it.

Optional improvements

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

  • Unused dependency: #include <winver.h> and -lversion in @compilerOptions — no version API (GetFileVersionInfo, VerQueryValue, …) is used in the file. Both can be removed.
  • Log-category prefixes like [Init], [Apply], [Menu] in Wh_Log strings are redundant — Windhawk already prefixes each line with the mod name. Harmless, but they can go.
  • Fallback owner: in ShowFolderMenu, if the taskbar window isn't found you fall back to GetForegroundWindow() and then SetWindowSubclass it. Plain SetWindowSubclass can't subclass a window owned by another thread, so on that (rare) path the lazy-load / right-click handlers silently won't work. Not worth much, since in explorer.exe the Shell_TrayWnd lookup essentially always succeeds — just noting it.

Functionality notes

Non-critical observations about the feature behavior itself.

  • DPI units mismatch in GetAvailableFolderRows: the available-row count divides GetWindowRect(taskbar) (physical pixels) by buttonHeight + buttonSpacing, but XAML sizes (buttonHeight, etc.) are DIPs, not physical pixels. On a non-100% display scale the two are different units, so smart/auto grid row counts come out wrong (too many rows at >100% scale). Convert the rect height to DIPs (divide by the monitor scale factor) before dividing by the button pitch.
  • Synchronous Shell enumeration on the UI thread: WM_INITMENUPOPUP runs EnumerateShellFolder (Shell binding, EnumObjects, per-item SHGetFileInfo for icons) inline on the taskbar UI thread while the menu is up. For a very large folder this can briefly freeze the taskbar the first time a submenu opens. There's no clean alternative for a synchronous popup menu, so this is just an FYI — the lazy per-submenu loading already keeps it bounded in practice.

@sb4ssman
sb4ssman force-pushed the sb4ssman-taskbar-folder-menus branch from 2cf4fb8 to 32d4d7c Compare July 20, 2026 00:02
@sb4ssman sb4ssman changed the title Add Taskbar Folder Menus v0.5 Add Taskbar Folder Menus v0.7 Jul 20, 2026
@sb4ssman

Copy link
Copy Markdown
Contributor Author

Updated the PR to v0.7 on a clean rebase of current main.

The two required review items are addressed:

  • Right-click now uses the documented WM_MENURBUTTONUP path; the full classic
    Shell context-menu flow was live-tested, including modal Properties and
    click-away dismissal.
  • Namespace-scope XAML holders use [[clang::no_destroy]], the unused strong
    parent reference is gone, and delegates/tooltips/boxed content are released
    before subtree removal.

The DPI/layout note is also addressed by replacing the inline layout code with
the shared Smart Grid template and calculating row capacity from the live
SystemTrayFrameGrid height in DIPs.

One earlier simplification was adjusted based on live regression evidence:
TrayUI::StartTaskbar remains, but after the mod failed to reappear following a
restart, v0.7 also uses the standard three-module IconView.Loaded trigger plus
a bounded slow-sign-in retry fallback. The updated build now survives restart
in live testing.

The PR description and completed test plan now reflect the current array
settings, six grid modes, accent default, reliability fixes, and screenshot set.

@sb4ssman
sb4ssman force-pushed the sb4ssman-taskbar-folder-menus branch from 32d4d7c to 46f3301 Compare July 20, 2026 00:07
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.

2 participants