From 4cf6c05ced16a357248900a99051e7f8e7bfc73e Mon Sep 17 00:00:00 2001 From: lx-s Date: Tue, 18 Aug 2026 11:53:06 +0200 Subject: [PATCH] Open log window only once. Fixed selection when opening log window. --- WinMute/LogDialog.cpp | 203 +++++++++++++++++--------------- WinMute/Settings_GeneralDlg.cpp | 6 +- WinMute/WinMute.cpp | 5 + 3 files changed, 118 insertions(+), 96 deletions(-) diff --git a/WinMute/LogDialog.cpp b/WinMute/LogDialog.cpp index 852de78..fb077bd 100644 --- a/WinMute/LogDialog.cpp +++ b/WinMute/LogDialog.cpp @@ -1,6 +1,6 @@ /* WinMute - Copyright (c) 2024, Alexander Steinhoefer + Copyright (c) 2011-2026 Alexander Steinhoefer ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -33,99 +33,118 @@ POSSIBILITY OF SUCH DAMAGE. #include "common.h" +extern HINSTANCE hglobInstance; + struct LogDlgData { - HWND hLogContent; + HWND hLogContent; }; -INT_PTR CALLBACK LogDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +static HWND hLogDlg_ = nullptr; + +static INT_PTR CALLBACK LogDlgProc(HWND hDlg, UINT msg, WPARAM wParam, + LPARAM lParam) { - auto *dlgData = - reinterpret_cast(GetWindowLongPtr(hDlg, DWLP_USER)); - UNREFERENCED_PARAMETER(wParam); - UNREFERENCED_PARAMETER(lParam); - switch (msg) { - case WM_INITDIALOG: - { - dlgData = new LogDlgData(); - SetWindowLongPtr(hDlg, DWLP_USER, reinterpret_cast(dlgData)); - - WMi18n &i18n = WMi18n::GetInstance(); - SetWindowText(hDlg, i18n.GetTranslationW("log.title").c_str()); - - HICON hIcon = LoadIcon( - GetModuleHandle(nullptr), - MAKEINTRESOURCE(IDI_TRAY_DARK)); - SendMessageW(hDlg, WM_SETICON, ICON_BIG, reinterpret_cast(hIcon)); - - auto& wmLog = WMLog::GetInstance(); - const auto logMessages = wmLog.GetLogMessages(); - std::wstring logText; - logText.reserve(logMessages.size() * 30); - for (auto &lm : logMessages) { - logText.append(wmLog.FormatLogMessage(lm, true)); - } - - dlgData->hLogContent = GetDlgItem(hDlg, IDC_LOG_CONTENT); - Edit_SetText(dlgData->hLogContent, logText.c_str()); - wmLog.RegisterForLogUpdates(hDlg); - - // Initial sizing - RECT rcClient; - GetClientRect(hDlg, &rcClient); - SetWindowPos( - dlgData->hLogContent, - nullptr, - 0, - 0, - rcClient.right - rcClient.left, - rcClient.bottom - rcClient.top, - SWP_NOZORDER); - - return TRUE; - } - case WM_COMMAND: - return 0; - case WM_SIZE: - { - // WM_SIZE arrives before WM_INITDIALOG, when dlgData is not set yet - if (dlgData == nullptr) { - return 0; - } - RECT rcClient; - GetClientRect(hDlg, &rcClient); - SetWindowPos( - dlgData->hLogContent, - nullptr, - 0, - 0, - rcClient.right - rcClient.left, - rcClient.bottom - rcClient.top, - SWP_NOZORDER); - return 0; - } - case WM_LOG_UPDATED: { - const WMLog &wmLog = WMLog::GetInstance(); - auto logMsg = reinterpret_cast(lParam); - if (dlgData == nullptr || logMsg == nullptr) { - return FALSE; - } - const auto formattedMsg = wmLog.FormatLogMessage(*logMsg, true); - const auto textLen = Edit_GetTextLength(dlgData->hLogContent); - Edit_SetSel(dlgData->hLogContent, textLen, textLen); - Edit_ReplaceSel(dlgData->hLogContent, formattedMsg.c_str()); - return TRUE; - } - case WM_DESTROY: - delete dlgData; - SetWindowLongPtrW(hDlg, DWLP_USER, 0); - WMLog::GetInstance().UnregisterForLogUpdates(hDlg); - return 0; - case WM_CLOSE: - //EndDialog(hDlg, 0); - DestroyWindow(hDlg); - return TRUE; - default: - break; - } - return FALSE; + auto* dlgData = + reinterpret_cast(GetWindowLongPtr(hDlg, DWLP_USER)); + UNREFERENCED_PARAMETER(wParam); + UNREFERENCED_PARAMETER(lParam); + switch (msg) { + case WM_INITDIALOG: { + dlgData = new LogDlgData(); + SetWindowLongPtr(hDlg, DWLP_USER, + reinterpret_cast(dlgData)); + hLogDlg_ = hDlg; + + WMi18n& i18n = WMi18n::GetInstance(); + SetWindowText(hDlg, i18n.GetTranslationW("log.title").c_str()); + + HICON hIcon = LoadIcon(GetModuleHandle(nullptr), + MAKEINTRESOURCE(IDI_TRAY_DARK)); + SendMessageW(hDlg, WM_SETICON, ICON_BIG, + reinterpret_cast(hIcon)); + + auto& wmLog = WMLog::GetInstance(); + const auto logMessages = wmLog.GetLogMessages(); + std::wstring logText; + logText.reserve(logMessages.size() * 30); + for (auto& lm : logMessages) { + logText.append(wmLog.FormatLogMessage(lm, true)); + } + + dlgData->hLogContent = GetDlgItem(hDlg, IDC_LOG_CONTENT); + Edit_SetText(dlgData->hLogContent, logText.c_str()); + Edit_SetSel(dlgData->hLogContent, static_cast(-1), 0); + wmLog.RegisterForLogUpdates(hDlg); + SetFocus(dlgData->hLogContent); + + // Initial sizing + RECT rcClient; + GetClientRect(hDlg, &rcClient); + SetWindowPos(dlgData->hLogContent, nullptr, 0, 0, + rcClient.right - rcClient.left, + rcClient.bottom - rcClient.top, SWP_NOZORDER); + return FALSE; + } + case WM_COMMAND: + return 0; + case WM_SIZE: { + // WM_SIZE arrives before WM_INITDIALOG, when dlgData is not set yet + if (dlgData == nullptr) { + return 0; + } + RECT rcClient; + GetClientRect(hDlg, &rcClient); + SetWindowPos(dlgData->hLogContent, nullptr, 0, 0, + rcClient.right - rcClient.left, + rcClient.bottom - rcClient.top, SWP_NOZORDER); + return 0; + } + case WM_LOG_UPDATED: { + const WMLog& wmLog = WMLog::GetInstance(); + auto logMsg = reinterpret_cast(lParam); + if (dlgData == nullptr || logMsg == nullptr) { + return FALSE; + } + const auto formattedMsg = wmLog.FormatLogMessage(*logMsg, true); + const auto textLen = Edit_GetTextLength(dlgData->hLogContent); + Edit_SetSel(dlgData->hLogContent, textLen, textLen); + Edit_ReplaceSel(dlgData->hLogContent, formattedMsg.c_str()); + return TRUE; + } + case WM_DESTROY: + delete dlgData; + SetWindowLongPtrW(hDlg, DWLP_USER, 0); + WMLog::GetInstance().UnregisterForLogUpdates(hDlg); + if (hLogDlg_ == hDlg) { + hLogDlg_ = nullptr; + } + return 0; + case WM_CLOSE: + // EndDialog(hDlg, 0); + DestroyWindow(hDlg); + return TRUE; + default: + break; + } + return FALSE; +} + +void ShowLogDialog(HWND hParent) +{ + if (hLogDlg_ != nullptr) { + // Already open: surface the existing window instead of a second copy. + if (IsIconic(hLogDlg_)) { + ShowWindow(hLogDlg_, SW_RESTORE); + } + SetForegroundWindow(hLogDlg_); + return; + } + + HWND hLogDlg = CreateDialogW(hglobInstance, MAKEINTRESOURCEW(IDD_LOG), + hParent, LogDlgProc); + if (hLogDlg == nullptr) { + ShowWindowsError(L"CreateDialog"); + return; + } + ShowWindow(hLogDlg, SW_SHOW); } diff --git a/WinMute/Settings_GeneralDlg.cpp b/WinMute/Settings_GeneralDlg.cpp index 23fe3e0..0d386c0 100644 --- a/WinMute/Settings_GeneralDlg.cpp +++ b/WinMute/Settings_GeneralDlg.cpp @@ -35,7 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. namespace fs = std::filesystem; -extern INT_PTR CALLBACK LogDlgProc(HWND, UINT, WPARAM, LPARAM); +extern void ShowLogDialog(HWND hParent); extern HINSTANCE hglobInstance; struct SettingsGeneralData { @@ -230,9 +230,7 @@ INT_PTR CALLBACK Settings_GeneralDlgProc(HWND hDlg, UINT msg, WPARAM wParam, GetDlgItem(hDlg, IDC_ENABLE_GLOBAL_MUTE_HOTKEY)); EnableWindow(GetDlgItem(hDlg, IDC_GLOBAL_MUTE_HOTKEY), checked); } else if (LOWORD(wParam) == IDC_OPENLOGDLG) { - auto hLogDlg = CreateDialogW( - hglobInstance, MAKEINTRESOURCEW(IDD_LOG), hDlg, LogDlgProc); - ShowWindow(hLogDlg, SW_SHOW); + ShowLogDialog(hDlg); } else if (LOWORD(wParam) == IDC_CHECK_FOR_UPDATES_ON_STARTUP) { const int enabled = Button_GetCheck( GetDlgItem(hDlg, IDC_CHECK_FOR_UPDATES_ON_STARTUP)); diff --git a/WinMute/WinMute.cpp b/WinMute/WinMute.cpp index e4e78d8..fa38afc 100644 --- a/WinMute/WinMute.cpp +++ b/WinMute/WinMute.cpp @@ -56,6 +56,8 @@ static constexpr int WTS_RETRY_MAX_ATTEMPTS = 30; static constexpr int GLOBAL_HOTKEY_ID_MUTE = 1000; +extern void ShowLogDialog(HWND hParent); + static LRESULT CALLBACK WinMuteWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -736,6 +738,9 @@ LRESULT WinMute::OnCommand(HWND hWnd, WPARAM wParam, LPARAM) case ID_TRAYMENU_EXIT: SendMessage(hWnd, WM_CLOSE, 0, 0); break; + case ID_TRAYMENU_SHOWLOG: + ShowLogDialog(hWnd); + break; case ID_TRAYMENU_SETTINGS: { static bool dialogOpen = false; if (!dialogOpen) { -- 2.43.0