From ba67fe2668c5463d8611e006610a98bf06dbd393 Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Mon, 23 Feb 2026 19:24:04 +0100 Subject: [PATCH] fix: speed up ShowWindow --- src/MuiLanguage.c | 80 +++++++++++++++++++++++++++++------------------ src/Notepad3.c | 67 ++++++++++++++++++++++++++++++--------- src/PathLib.c | 2 +- 3 files changed, 103 insertions(+), 46 deletions(-) diff --git a/src/MuiLanguage.c b/src/MuiLanguage.c index 41bc914fd..53552f2f4 100644 --- a/src/MuiLanguage.c +++ b/src/MuiLanguage.c @@ -266,34 +266,41 @@ unsigned GetMUILanguageIndexByLocaleName(LPCWSTR pLocaleName) { // // CheckAvailableLanguages // +static bool s_bFullLngScanDone = false; + +static bool _CheckLanguageDLL(unsigned lng) +{ + if (lng == 0 || lng >= MuiLanguages_CountOf()) { + return (lng == 0); // internal (index 0) is always available + } + if (!IsValidLocaleName(MUI_LanguageDLLs[lng].LocaleName)) { + return false; + } +#if (defined(_DEBUG) || defined(DEBUG)) && !defined(NDEBUG) + WCHAR wchLngLocalName[LOCALE_NAME_MAX_LENGTH + 1]; + if (ResolveLocaleName(MUI_LanguageDLLs[lng].LocaleName, wchLngLocalName, COUNTOF(wchLngLocalName))) { + assert(IsSameLocale(MUI_LanguageDLLs[lng].LocaleName, wchLngLocalName) && "Problem with Locale Name of Language!"); + } +#endif + WCHAR wchRelPath[SMALL_BUFFER] = { L'\0' }; + StringCchPrintf(wchRelPath, COUNTOF(wchRelPath), L"lng/%s/np3lng.dll.mui", MUI_LanguageDLLs[lng].LocaleName); + HPATHL hpth = Path_Allocate(wchRelPath); + Path_AbsoluteFromApp(hpth, false); + bool const bAvail = Path_IsExistingFile(hpth); + Path_Release(hpth); + MUI_LanguageDLLs[lng].bHasDLL = bAvail; + return bAvail; +} + static unsigned _CheckAvailableLanguageDLLs() { unsigned count = 1; // internal instance always available - - HPATHL hpth = Path_Allocate(NULL); - for (unsigned lng = 1; lng < MuiLanguages_CountOf(); ++lng) { - - if (IsValidLocaleName(MUI_LanguageDLLs[lng].LocaleName)) { - -#if (defined(_DEBUG) || defined(DEBUG)) && !defined(NDEBUG) - WCHAR wchLngLocalName[LOCALE_NAME_MAX_LENGTH + 1]; - if (ResolveLocaleName(MUI_LanguageDLLs[lng].LocaleName, wchLngLocalName, COUNTOF(wchLngLocalName))) { - //~StringCchCopy(MUI_LanguageDLLs[lng].LocaleName, COUNTOF(MUI_LanguageDLLs[lng].LocaleName), wchLngLocalName); // put back resolved name - assert(IsSameLocale(MUI_LanguageDLLs[lng].LocaleName, wchLngLocalName) && "Problem with Locale Name of Language!"); - } -#endif - // check for DLL - WCHAR wchRelPath[SMALL_BUFFER] = { L'\0' }; - StringCchPrintf(wchRelPath, COUNTOF(wchRelPath), L"lng/%s/np3lng.dll.mui", MUI_LanguageDLLs[lng].LocaleName); - Path_Reset(hpth, wchRelPath); - Path_AbsoluteFromApp(hpth, false); - bool const bAvail = Path_IsExistingFile(hpth); - MUI_LanguageDLLs[lng].bHasDLL = bAvail; - count += bAvail ? 1 : 0; + if (_CheckLanguageDLL(lng)) { + ++count; } } - Path_Release(hpth); + s_bFullLngScanDone = true; return count; } @@ -344,22 +351,28 @@ unsigned LoadLanguageResources(LPCWSTR pLocaleName) { unsigned const iInternalLngIndex = max_u(0, GetMUILanguageIndexByLocaleName(MUI_BASE_LNG_ID)); - // 1st check language resources - Globals.uAvailLngCount = _CheckAvailableLanguageDLLs(); - - // set the appropriate fallback list + // Check only the preferred locale's DLL on startup (defer full scan to menu population) unsigned iLngIndex = MuiLanguages_CountOf(); - WCHAR tchAvailLngs[2 * (LOCALE_NAME_MAX_LENGTH + 1)] = { L'\0' }; for (unsigned lng = 0; lng < MuiLanguages_CountOf(); ++lng) { if (StrCmpIW(MUI_LanguageDLLs[lng].LocaleName, pLocaleName) == 0) { - if (MUI_LanguageDLLs[lng].bHasDLL && (lng > 0)) { - StringCchCatW(tchAvailLngs, COUNTOF(tchAvailLngs), MUI_LanguageDLLs[lng].LocaleName); - StringCchCatW(tchAvailLngs, COUNTOF(tchAvailLngs), L";"); - } iLngIndex = lng; + if (lng > 0 && !s_bFullLngScanDone) { + _CheckLanguageDLL(lng); // check only the preferred locale + } break; } } + if (!s_bFullLngScanDone) { + // Set count > 1 so language menu creation is not skipped prematurely + Globals.uAvailLngCount = MuiLanguages_CountOf(); + } + + // set the appropriate fallback list + WCHAR tchAvailLngs[2 * (LOCALE_NAME_MAX_LENGTH + 1)] = { L'\0' }; + if (iLngIndex < MuiLanguages_CountOf() && MUI_LanguageDLLs[iLngIndex].bHasDLL && (iLngIndex > 0)) { + StringCchCatW(tchAvailLngs, COUNTOF(tchAvailLngs), MUI_LanguageDLLs[iLngIndex].LocaleName); + StringCchCatW(tchAvailLngs, COUNTOF(tchAvailLngs), L";"); + } StringCchCatW(tchAvailLngs, COUNTOF(tchAvailLngs), MUI_LanguageDLLs[iInternalLngIndex].LocaleName); // en-US fallback // NOTES: @@ -473,6 +486,11 @@ static HMENU s_hmenuLanguage = NULL; bool InsertLanguageMenu(HMENU hMenuBar) { + // Perform full language DLL scan if deferred from startup + if (!s_bFullLngScanDone) { + Globals.uAvailLngCount = _CheckAvailableLanguageDLLs(); + } + // check, if we need a language switching menu if (Globals.uAvailLngCount < 2) { Settings.PreferredLocale4DateFmt = false; diff --git a/src/Notepad3.c b/src/Notepad3.c index f40753008..ac5d7f3b4 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -968,7 +968,7 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, #endif _InitGlobals(); - InitDarkMode(); + // Dark mode init deferred to after LoadSettings() — see below // Windows Class name StringCchCopy(s_wchWndClass, COUNTOF(s_wchWndClass), _W(SAPPNAME)); @@ -1046,7 +1046,13 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, Scintilla_RegisterClasses(hInstance); #ifdef D_NP3_WIN10_DARK_MODE - SetDarkMode(IsDarkModeSupported() && IsSettingDarkMode()); // settings + // Init dark mode after settings are loaded — skip UxTheme loading for explicit light mode + if (Settings.WinThemeDarkMode != WINDSPMOD_LIGHT) { + SetDarkMode(true); // probe: load UxTheme.dll, detect OS dark mode support + if (!IsSettingDarkMode()) { + SetDarkMode(false); // OS or user says light mode + } + } #endif HRSRC const hRes = FindResourceEx(hInstance, RT_RCDATA, MAKEINTRESOURCE(IDR_STD_DARKMODE_THEME), @@ -1451,7 +1457,14 @@ static BOOL CALLBACK _EnumWndProc(HWND hwnd, LPARAM lParam) if (StrCmpW(szClassName, s_wchWndClass) == 0) { - UINT const iReuseLock = GetDlgItemInt(hwnd, IDC_REUSELOCK, NULL, FALSE); + WCHAR wchReuseLock[32] = { L'\0' }; + DWORD_PTR dwResult = 0; + HWND const hCtl = GetDlgItem(hwnd, IDC_REUSELOCK); + if (!hCtl || SendMessageTimeout(hCtl, WM_GETTEXT, COUNTOF(wchReuseLock), + (LPARAM)wchReuseLock, SMTO_ABORTIFHUNG | SMTO_BLOCK, 500, &dwResult) == 0) { + return TRUE; // skip unresponsive instance + } + UINT const iReuseLock = (UINT)wcstoul(wchReuseLock, NULL, 10); if ((GetTicks_ms() - iReuseLock) >= REUSEWINDOWLOCKTIMEOUT) { *(HWND*)lParam = hwnd; @@ -1480,7 +1493,12 @@ static BOOL CALLBACK _EnumWndProc2(HWND hwnd, LPARAM lParam) if (StrCmpW(szClassName, s_wchWndClass) == 0) { WCHAR wchFileName[INTERNET_MAX_URL_LENGTH] = { L'\0' }; - GetDlgItemText(hwnd, IDC_FILENAME, wchFileName, COUNTOF(wchFileName)); + DWORD_PTR dwResult = 0; + HWND const hCtl = GetDlgItem(hwnd, IDC_FILENAME); + if (!hCtl || SendMessageTimeout(hCtl, WM_GETTEXT, COUNTOF(wchFileName), + (LPARAM)wchFileName, SMTO_ABORTIFHUNG | SMTO_BLOCK, 500, &dwResult) == 0) { + return TRUE; // skip unresponsive instance + } HPATHL hpthFileName = Path_Allocate(wchFileName); if (Path_StrgComparePath(hpthFileName, s_pthCheckFilePath, Paths.WorkingDirectory, true) == 0) { @@ -1771,17 +1789,39 @@ HWND InitInstance(const HINSTANCE hInstance, int nCmdShow) SetWindowTransparentMode(hwndMain, true, Settings2.OpacityLevel); } + // Determine if starting minimized/tray (don't show window early in that case) + bool const bStartMinimized = s_flagStartAsTrayIcon || (nCmdShow == SW_MINIMIZE) || (nCmdShow == SW_SHOWMINIMIZED); + + // Show window frame early for faster perceived startup — the user sees + // the window (with initial toolbar from WM_CREATE) while we re-create bars + if (!bStartMinimized) { + if (!Settings.ShowTitlebar) { + SetWindowLong(hwndMain, GWL_STYLE, GetWindowLong(hwndMain, GWL_STYLE) & ~WS_CAPTION); + } + SetWindowPos(hwndMain, Settings.AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + ShowWindow(hwndMain, nCmdShow); + UpdateWindow(hwndMain); + } + CreateBars(hwndMain, hInstance); SetMenu(hwndMain, (Settings.ShowMenubar ? Globals.hMainMenu : NULL)); DrawMenuBar(hwndMain); + // Force layout recalculation after toolbar/statusbar re-creation + // (early ShowWindow already triggered WM_SIZE with old child windows) + if (!bStartMinimized) { + RECT rc; + GetClientRect(hwndMain, &rc); + SendMessage(hwndMain, WM_SIZE, SIZE_RESTORED, MAKELPARAM(rc.right, rc.bottom)); + } + Globals.hwndMain = hwndMain; // make main window globaly available SetWindowAppUserModelID(hwndMain, Settings2.AppUserModelID); HPATHL hfile_pth = Path_Copy(s_pthArgFilePath); FileLoadFlags fLoadFlags = FLF_None; - + // Source Encoding Encoding_Forced(s_flagSetEncoding); @@ -1807,15 +1847,13 @@ HWND InitInstance(const HINSTANCE hInstance, int nCmdShow) ShowWindowAsync(s_hwndEditFrame, SW_SHOWDEFAULT); ShowWindowAsync(Globals.hwndEdit, SW_SHOWDEFAULT); - //~SnapToWinInfoPos(hwndMain, g_IniWinInfo, SCR_NORMAL, SW_HIDE); ~ instead set all needed properties here: - SetWindowPos(hwndMain, Settings.AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - UpdateWindow(hwndMain); - if (!Settings.ShowTitlebar) { - SetWindowLong(hwndMain, GWL_STYLE, GetWindowLong(hwndMain, GWL_STYLE) & ~WS_CAPTION); - } - - if (s_flagStartAsTrayIcon || (nCmdShow == SW_MINIMIZE) || (nCmdShow == SW_SHOWMINIMIZED)) { + if (bStartMinimized) { + //~SnapToWinInfoPos(hwndMain, g_IniWinInfo, SCR_NORMAL, SW_HIDE); + SetWindowPos(hwndMain, Settings.AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + if (!Settings.ShowTitlebar) { + SetWindowLong(hwndMain, GWL_STYLE, GetWindowLong(hwndMain, GWL_STYLE) & ~WS_CAPTION); + } if (Settings.MinimizeToTray) { MinimizeWndToTray(hwndMain); } @@ -1824,7 +1862,8 @@ HWND InitInstance(const HINSTANCE hInstance, int nCmdShow) } } else { - ShowWindow(hwndMain, nCmdShow); + // Window was already shown above; ensure children are painted + UpdateWindow(hwndMain); } bool bOpened = false; diff --git a/src/PathLib.c b/src/PathLib.c index 51f8c8052..0f4479d3f 100644 --- a/src/PathLib.c +++ b/src/PathLib.c @@ -1123,7 +1123,7 @@ void PTHAPI Path_ExpandEnvStrings(HPATHL hpth_in_out) StrgReplace(hstr_io, PATH_CSIDL_FAVORITES, PathGet(hfld_pth)); Path_Release(hfld_pth); } - + ExpandEnvironmentStrgs(hstr_io, true); } // ----------------------------------------------------------------------------