Add Mallss Music Overlay - #5449
Conversation
|
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 See the pull request review process for the full details. |
Added readme documentation for the Mallss Music Overlay mod, detailing features, usage, controls, and supported media.
Submission reviewNote: 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 overlay itself is nicely put together, but there are several structural problems to resolve before it can be merged — the process it runs in, two globals that will take down Explorer at shutdown, a window class that is never cleaned up, and an init check that prevents the mod from ever starting after a reboot. 1. This should be a tool mod, not an The mod does not hook a single function. Everything it does — Please convert it per Mods as tools: Running mods in a dedicated process: set quick-launch-media-panel.wh.cpp is a very close reference — a desktop panel with Windows media controls and GDI+ artwork, running as a tool mod. explorer-folder-hover-menu.wh.cpp has a verbatim copy of the launcher snippet at the bottom of the file. 2. The mod never starts after a reboot or an Explorer restart
Converting to a tool mod removes this check entirely. If you keep it for some other reason, it has to be deferred to a point where the shell windows actually exist (e.g. from the worker thread, retrying). 3. Lines 126–127. [[clang::no_destroy]] static std::optional<std::thread> g_uiThread;
[[clang::no_destroy]] static std::optional<std::thread> g_mediaThread;Then 4. Lines 186–190. These are out-of-process WinRT proxies. At process exit their automatic destructors marshal a [[clang::no_destroy]] static GlobalSystemMediaTransportControlsSessionManager g_sessionManager{nullptr};
[[clang::no_destroy]] static GlobalSystemMediaTransportControlsSession g_session{nullptr};Same wiki page, section 3; island-media-controls.wh.cpp#L580 does the same for its COM globals. 5. The window class is never unregistered, and Lines 3320–3370. Two related problems:
Fix: register with the mod's own module handle, treat HINSTANCE GetCurrentModuleHandle() {
HINSTANCE instance = nullptr;
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCWSTR>(&GetCurrentModuleHandle),
&instance);
return instance;
}
// registration
wc.hInstance = g_hInst;
if (!RegisterClassExW(&wc)) {
Wh_Log(L"RegisterClassExW failed: %lu", GetLastError());
return; // including ERROR_CLASS_ALREADY_EXISTS
}
// Wh_ModUninit, after the UI thread has been joined:
UnregisterClassW(L"MallssMusicOverlay", g_hInst);
6. Media commands run on the UI thread, race with the poll thread, and can hang the unload
Fix: guard 7. The UI thread never idles The loop at lines 3509–3766 is a Suggested changes, roughly in order of payoff:
8. No DPI scaling, and the overlay is pinned to the primary monitor All geometry is hard-coded in pixels (lines 49–93) and 9. Nothing is configurable There is no 10. Please describe how this differs from the existing media mods The catalog already has quick-launch-media-panel (a desktop panel with album art and media controls, already a tool mod), plus island-media-controls, taskbar-music-lounge and taskbar-fluent-media-player on the taskbar side. A free-floating desktop overlay with a clock is arguably a different thing, but the overlap with the first one in particular is close enough that it's worth stating in the README what this offers that it doesn't — and, if the gap is small, considering an option on the existing mod instead. The maintainer's consistent preference is to extend an existing mod rather than merge a near-duplicate. 11. README CI is currently red; please fix what it reports. When you add the README block, include a screenshot or a short GIF of the overlay — this is a purely visual mod, and users pick it from the catalog on the strength of that image. Only Optional improvements
Minor polish — none of this affects users, so it's your call.
Functionality notes
Non-critical observations and ideas about the feature behavior itself.
Next steps:
See the review process for details. |
Submission reviewNote: 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. A nicely self-contained overlay, but as an 1. Global static std::thread g_mediaThread; // line 176
static std::thread g_uiThread; // line 177
[[clang::no_destroy]] static std::optional<std::thread> g_mediaThread;
[[clang::no_destroy]] static std::optional<std::thread> g_uiThread;
// Wh_ModInit: g_uiThread.emplace(UIThreadProc);
// Wh_ModUninit: if (g_uiThread->joinable()) g_uiThread->join(); g_uiThread.reset();Example: taskbar-fluent-media-player.wh.cpp#L4399, taskbar-system-info.wh.cpp#L478. 2. The WinRT media-session globals have the same problem, and are released on the wrong thread. static GlobalSystemMediaTransportControlsSessionManager g_sessionManager{nullptr}; // 236
static GlobalSystemMediaTransportControlsSession g_session{nullptr}; // 239These are out-of-process proxies. At process exit their automatic [[clang::no_destroy]] static GlobalSystemMediaTransportControlsSessionManager g_sessionManager{nullptr};
[[clang::no_destroy]] static GlobalSystemMediaTransportControlsSession g_session{nullptr};Precedent: taskbar-fluent-media-player.wh.cpp#L2067. Separately, the explicit release ordering in 3. The window class is never unregistered, and wc.hInstance = GetModuleHandleW(nullptr); // 3378
wc.lpszClassName = L"MallssMusicOverlay141"; // 3383
ATOM atom = RegisterClassExW(&wc);
if (atom == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) { ... return; } // 3400There is no Two changes: register with the mod's own module handle (the static HMODULE GetCurrentModuleHandle() {
HMODULE mod = nullptr;
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
L"", &mod);
return mod;
}
// ... wc.hInstance = GetCurrentModuleHandle();
// on teardown, after DestroyWindow:
UnregisterClassW(kClassName, GetCurrentModuleHandle());References: autoscroll-win32.wh.cpp#L984, mic-mute-hotkey-overlay.wh.cpp#L1093, desktop-draggable-widgets.wh.cpp#L1975. 4. This should be a tool mod, not an The mod installs zero function hooks and zero symbol hooks. It creates its own window, its own UI thread and its own polling thread, and never touches Explorer's state — it just needs a process to live in. It also hand-rolls the two things the tool-mod framework gives you for free: a single-instance mutex ( The rewrite: 5. The shell-PID gate makes the mod fail to start after a reboot or an Explorer restart. const DWORD desktopShellPid = GetDesktopShellPid();
if (desktopShellPid == 0 || currentPid != desktopShellPid) { return FALSE; } // 4062
6.
7. The UI thread spins at ~62 Hz forever and re-renders the whole overlay every frame. while (g_running.load()) {
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) { ... }
...
if (shouldShow) { RenderFrame(); PresentFrame(); }
Sleep(FRAME_MS); // 3813, FRAME_MS = 16
}Two costs. First, the loop never blocks — even with no media playing and the window hidden it wakes 62 times a second to call Use a blocking wait and only redraw when there's something to redraw: 8. The overlay ignores DPI and is hard-wired to the primary monitor. Every dimension is a fixed physical pixel count ( Scale all geometry and font sizes by 9. GSMTC is polled twice a second instead of using its events.
10. The mod has no settings block at all. Everything is a compile-time constant: overlay size and position, every color, the marquee speed, the poll interval, and whether the clock is shown. For a desktop overlay, position (corner / monitor / offset) and the option to hide the clock are the minimum users will ask for. Adding a 11. The clock and date formats are hard-coded and ignore the user's regional settings. swprintf_s(buffer, L"%02d:%02d", st.wHour, st.wMinute); // 442
swprintf_s(buffer, L"%02d/%02d/%04d", st.wDay, st.wMonth, st.wYear); // 462That's a fixed 24-hour clock and a fixed 12. The README has no screenshot. This is a purely visual mod — a desktop card with album art, a clock and controls — and the README describes it entirely in prose. Please add a screenshot or a short GIF; only 13. Please state how this differs from the existing media mods. There are already several mods in this space — quick-launch-media-panel (desktop panel with a GSMTC media card), dynamic-island-for-windows, island-media-controls, taskbar-fluent-media-player and taskbar-music-lounge. A standalone floating desktop card that isn't attached to the taskbar does look like a distinct niche, so this isn't a blocker — but the README should say so explicitly so users can tell them apart. Optional improvements
Minor polish — none of this affects users, so it's your call.
Functionality notes
Non-critical observations and ideas about the feature behavior itself.
Next steps:
See the review process for details. |
|
@ItsMeMal |
Submission reviewNote: 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 tool-mod structure is the right call here (no hooks, only 1. None of the controls work —
static HitArea HitTest(int screenX, int screenY) {
RECT rect{};
GetWindowRect(g_hwnd, &rect);
const int x = static_cast<int>((screenX - rect.left) / scale);
const int y = static_cast<int>((screenY - rect.top) / scale);
Note that the seek math a few lines below already treats static HitArea HitTest(int clientX, int clientY) {
const float scale = g_scale <= 0.0f ? 1.0f : g_scale;
const int x = static_cast<int>(clientX / scale);
const int y = static_cast<int>(clientY / scale);
...
}
case WM_NCHITTEST: {
POINT pt{GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
ScreenToClient(hwnd, &pt);
return HitTest(pt.x, pt.y) != HitArea::None ? HTCLIENT : HTTRANSPARENT;
}2. The overlay re-renders at 30–60 fps permanently, including while it is completely hidden. The UI loop renders whenever if (visible) {
RenderFrame();
PresentFrame();
}
...
sleepMs = (visible && playing && titleOverflow) ? 16 : (visible && playing) ? 33 : ...When another app is in the foreground the overlay is moved to Gate rendering on the overlay actually being on top, and only use the 16 ms cadence when the marquee is actually animating: const bool onScreen = visible && g_lastDesktopActive;
if (onScreen) { RenderFrame(); PresentFrame(); }and fall back to a long sleep (or no redraw at all) otherwise, redrawing once when 3. The tool-mod launcher boilerplate deviates from the wiki snippet. The launcher must be a verbatim copy of the snippet from Mods as tools: Running mods in a dedicated process so it stays maintainable. Two functional pieces are missing:
See mods/explorer-folder-hover-menu.wh.cpp for a verbatim copy of the current snippet. (The extra 4. The clock and date ignore the user's locale. swprintf_s(buffer, L"%02d:%02d", st.wHour, st.wMinute); // CurrentClock
swprintf_s(buffer, L"%02d/%02d/%04d", st.wDay, st.wMonth, st.wYear); // CurrentDateThis hard-codes a 24-hour clock and 5. Nothing is configurable, and the position is hard-pinned to the primary monitor. There's no 6. Please add a screenshot or GIF to the README. The README currently says a screenshot "should be added once hosted at an allowed location". For a mod whose entire purpose is a visual overlay, the catalog entry really needs one — users pick these mods by the picture. Allowed hosts are 7. Spell out how this differs from the existing desktop media overlays. The README's "Difference from taskbar media mods" section only compares against taskbar mods, but the two closest neighbours are also desktop overlays running as The fixed bottom-right card with an integrated clock is a defensible difference, but please say so explicitly in the README, and consider whether an option on one of those mods would serve users better than a fourth entry in this cluster. Optional improvements
Minor polish — none of this affects users, so it's your call.
Functionality notes
Non-critical observations and ideas about the feature behavior itself.
Next steps:
See the review process for details. |
|
This pull request has already had 3 AI reviews in the last 24 hours, which is the limit, so no review was posted this time. Comment |
|
/ai-review |
|
This pull request has already had 3 AI reviews in the last 24 hours, which is the limit, so no review was posted this time. Comment |
|
/ai-review |
|
This pull request has already had 3 AI reviews in the last 24 hours, which is the limit, so no review was posted this time. Comment |
|
/ai-review |
Submission reviewNote: 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. Good progress since the last round — the tool-mod structure is in place, the window class is registered against the mod's own module and unregistered on the way out, the thread and WinRT globals use the right 1. Once the overlay hides, it never comes back
case WM_MALSS_UPDATE: {
if (g_visible.load()) {
PositionOverlay(); // SetWindowPos without SWP_SHOWWINDOW
RenderFrame();
InvalidateRect(hwnd, nullptr, FALSE);
UpdateWindow(hwnd);
} else {
ShowWindow(hwnd, SW_HIDE);
}
return 0;
}
Add the show back to the visible branch, or fold it into the positioning call: SetWindowPos(g_hwnd, nullptr, x, y, width, height,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER |
SWP_SHOWWINDOW);quick-launch-media-panel.wh.cpp#L927-L931 does exactly this ( 2. Every media state change yanks the overlay in front of whatever you're using
SetWindowPos(g_hwnd, HWND_TOP, x, y, width, height,
SWP_NOACTIVATE | SWP_NOOWNERZORDER);and it's called from Use 3. The UI thread re-renders at 30–60 fps for as long as anything is playing, even when the overlay is completely covered if (playing || minuteChanged || g_forceRedraw.exchange(false)) {
RenderFrame();
InvalidateRect(g_hwnd, nullptr, FALSE);
UpdateWindow(g_hwnd);
}
int sleepMs = playing && titleOverflow ? 16 : playing ? 33 : 250;
Sleep(sleepMs);
Suggested changes, in order of payoff:
While you're in that loop: 4. The README still has no screenshot or GIF This is a purely visual mod — a corner card is exactly the kind of thing users judge from the catalog picture, and right now there's nothing to look at. Please add a screenshot (or a short GIF showing the marquee and the controls). Allowed image hosts are 5. Say explicitly how this differs from the existing desktop media overlays The README's "Difference from other desktop media overlays" section doesn't name anything it's differing from:
The two closest neighbours are also The fixed corner card with an integrated clock/date is a defensible difference, but please name those two in the README and state what this does that they don't. The maintainer's consistent preference is to add an option to an existing mod over merging a fourth entry in the same cluster, so it's worth making the case up front. Optional improvements
Minor polish — none of this affects users, so it's your call.
Functionality notes
Non-critical observations and ideas about the feature behavior itself.
Next steps:
See the review process for details. |
|
/ready-for-reviewer |
|
Please explain why the review items are left unaddressed. Start from these items: Say explicitly how this differs from the existing desktop media overlays The README still has no screenshot or GIF The tool-mod launcher boilerplate deviates from the wiki snippet. The launcher must be a verbatim copy of the snippet from Mods as tools: Running mods in a dedicated process so it stays maintainable. ... See mods/explorer-folder-hover-menu.wh.cpp for a verbatim copy of the current snippet. |
Changelog
Mod authorship
If this pull request introduces a new mod, please complete the section below.
This mod was created by: