Skip to content

Create desktop transparent widgets#4766

Open
Stunning-dev wants to merge 1 commit into
ramensoftware:mainfrom
Stunning-dev:main
Open

Create desktop transparent widgets#4766
Stunning-dev wants to merge 1 commit into
ramensoftware:mainfrom
Stunning-dev:main

Conversation

@Stunning-dev

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

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 Jul 13, 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.


1. @include windhawk.exe without the "mods as tools" launcher — the mod is loaded into Windhawk's own processes, not a dedicated one. The mod has no function/symbol hooks at all — it only creates a window and calls system-wide APIs (CoCreateInstance, GetSystemPowerStatus, ShellExecute, SendInput). That's exactly the "Mods as tools" case. But setting @include windhawk.exe while keeping the plain Wh_ModInit/Wh_ModUninit callbacks is not how tool mods run — it makes Windhawk inject the mod directly into every existing windhawk.exe process, including the session-0 service process (where a desktop window can't be shown and audio COM won't behave), with no dedicated persistent process and no single-instance guard, so you can get zero, duplicate, or short-lived widgets depending on which windhawk.exe instances happen to be running.

The tool-mod pattern solves all of this: it spawns one dedicated windhawk.exe -tool-mod "desktop-transparent-widgets" process that stays alive independently. To adopt it:

  • Rename Wh_ModInitWhTool_ModInit and Wh_ModUninitWhTool_ModUninit.
  • Paste the launcher boilerplate verbatim from the wiki at the end of the file (keep @include windhawk.exe).

Every windhawk.exe-targeting mod in the catalog uses this pattern — see explorer-folder-hover-menu.wh.cpp (the launcher block at the bottom is a verbatim copy of the wiki snippet), or taskbar-music-lounge.wh.cpp for a similar always-on-desktop helper. As a bonus, the pattern's Wh_ModUninit ends in ExitProcess(0), which removes the fragility of the current teardown (the WaitForSingleObject(g_uiThread, 3000) timeout will CloseHandle and let the DLL unload even if the UI thread is still executing mod code — a crash window, however unlikely).

2. README image URL is not a valid/allowed image. https://imgur.com/gallery/widgets-pggFD5f#mGAWwJP.png is an Imgur gallery page, not a direct image, and imgur.com is not one of the allowed image hosts — only i.imgur.com and raw.githubusercontent.com are. As written, the image won't render in the README at all. Upload the preview and use the direct link, e.g. https://i.imgur.com/<id>.png (or a raw.githubusercontent.com URL). Since this is a purely visual mod, a good screenshot/GIF really is worth getting right.

3. Light mode is not supported. Either add support for light mode, or, less preferable, add a note that the mod is only for dark wallpapers. https://i.imgur.com/RNsH24s.png

Optional improvements

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

  • Don't recreate the audio endpoint every second. The 1 s WM_TIMER calls RefreshVolume()GetEndpointVolumeInterface(), which does a fresh CoCreateInstance(MMDeviceEnumerator) + GetDefaultAudioEndpoint + Activate on every tick just to read one float. Cache the IAudioEndpointVolume (recreating it only when the default device changes, e.g. via IMMNotificationClient), or subscribe to IAudioEndpointVolumeCallback and drop the polling entirely. GetSystemPowerStatus is cheap, so the battery poll is fine.
  • volatile bool g_unloading is used for cross-thread signalling — prefer std::atomic<bool>. (With the tool-mod rewrite the flag largely goes away anyway.)
  • #include <shlobj.h> appears unused (you only use ShellExecuteW from <shellapi.h>). Remove it if nothing else needs it.
  • OpenMusicFolder() can pass L"shell:My Music" directly to ShellExecuteW as the file, without launching explorer.exe explicitly.

Functionality notes

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

  • Single-monitor / DPI assumptions. The widget panel is a fixed 400×680 canvas pinned to the bottom-right of the primary monitor's work area, with UpdateScale() deriving a scale factor from GetSystemMetrics(SM_CXSCREEN/CYSCREEN) against a hard-coded 1920×1080. On multi-monitor or per-monitor-DPI setups this can land on the wrong monitor or scale oddly. There's no trivial fix, so this is just an FYI — but it's the main thing users on non-standard displays will notice.
  • Widget positions aren't persisted. Dragging updates g_widgets[i].rc in memory only, so every reload/toggle resets the layout to the defaults. Consider persisting positions with Wh_SetIntValue/Wh_GetIntValue.
  • OpenWindowsSearch() synthesizes Win+S via SendInput. It works, but injecting global keystrokes is fragile (races with modifier state, can be swallowed if focus shifts). There's no clean public API for the search flyout, so this may be the pragmatic choice — noting it as a known trade-off.
  • Consider exposing a settings block (opacity/colors, which widgets are shown, anchor corner) — the mod currently has no ==WindhawkModSettings== at all, so everything is hard-coded.

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