From 21947778baaca205615a71a97ac8f563c998fdd3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 16 Apr 2024 23:25:01 +0300 Subject: SL-18721 Window shutdown adjustments On viewer shutdown 1. Instead of handling potential WM_* messages viewer is no longer equiped to handle drop window's pointer and expect only WM_DESTROY 2. Detach thread and let it do its own thing, thread will delete itself 3. Reverts commit 1161262029f9619fb02d81575382b64d82d9cd09 Reason for the change: window was closing too early (as son as "LLApp" status changes) without proper cleanup --- indra/llwindow/llwindowwin32.cpp | 102 ++++++++++++++------------------------- 1 file changed, 36 insertions(+), 66 deletions(-) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 54e5f43e87..3ffc7d3354 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -351,10 +351,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool LLWindowWin32Thread(); void run() override; - void close() override; // closes queue, wakes thread, waits until thread closes - void wakeAndDestroy(); + bool wakeAndDestroy(); void glReady() { @@ -425,6 +424,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // *HACK: Attempt to prevent startup crashes by deferring memory accounting // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 bool mGLReady = false; + bool mDeleteOnExit = false; // best guess at available video memory in MB std::atomic mAvailableVRAM; @@ -997,7 +997,11 @@ void LLWindowWin32::close() mhDC = NULL; mWindowHandle = NULL; - mWindowThread->wakeAndDestroy(); + if (mWindowThread->wakeAndDestroy()) + { + // thread will delete itselfs once done + mWindowThread = NULL; + } } BOOL LLWindowWin32::isValid() @@ -3104,10 +3108,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; } } - else + else // (NULL == window_imp) { - // (NULL == window_imp) - LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL; + if (u_msg == WM_DESTROY) + { + PostQuitMessage(0); // Posts WM_QUIT with an exit code of 0 + return 0; + } + else + { + LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL; + } } // pass unhandled messages down to Windows @@ -4563,25 +4574,11 @@ U32 LLWindowWin32::getAvailableVRAMMegabytes() #endif // LL_WINDOWS inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() - : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, true /*should be false, temporary workaround for SL-18721*/) + : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, false) { LL::ThreadPool::start(); } -void LLWindowWin32::LLWindowWin32Thread::close() -{ - if (!mQueue->isClosed()) - { - LL_WARNS() << "Closing window thread without using destroy_window_handler" << LL_ENDL; - LL::ThreadPool::close(); - - // Workaround for SL-18721 in case window closes too early and abruptly - LLSplashScreen::show(); - LLSplashScreen::update("..."); // will be updated later - } -} - - /** * LogChange is to log changes in status while trying to avoid spamming the * log with repeated messages, especially in a tight loop. It refuses to log @@ -4926,14 +4923,19 @@ void LLWindowWin32::LLWindowWin32Thread::run() } cleanupDX(); + + if (mDeleteOnExit) + { + delete this; + } } -void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() +bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() { if (mQueue->isClosed()) { - LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; - return; + LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." <close(); @@ -4986,49 +4997,8 @@ void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); } - // There are cases where window will refuse to close, - // can't wait forever on join, check state instead - LLTimer timeout; - timeout.setTimerExpirySec(2.0); - while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd) - { - ms_sleep(100); - } - - if (getQueue().done() || mWindowHandleThrd == NULL) - { - // Window is closed, started closing or is cleaning up - // now wait for our single thread to die. - if (mWindowHandleThrd) - { - LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; - } - else - { - LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; - } - for (auto& pair : mThreads) - { - pair.second.join(); - } - } - else - { - // Something suspended window thread, can't afford to wait forever - // so kill thread instead - // Ex: This can happen if user starts dragging window arround (if it - // was visible) or a modal notification pops up - LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL; - - for (auto& pair : mThreads) - { - // very unsafe - TerminateThread(pair.second.native_handle(), 0); - pair.second.detach(); - cleanupDX(); - } - } LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL; + return true; } void LLWindowWin32::post(const std::function& func) -- cgit v1.2.3 From a620e58daccf92b5b8d61347312739720ed2b51a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 4 Jul 2024 17:31:26 +0300 Subject: SL-18721 Don't 'post' window destruction, make thread do it automatically --- indra/llwindow/llwindowwin32.cpp | 70 ++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 31 deletions(-) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index aea7367337..abf86e363c 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -352,7 +352,12 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool void run() override; - // closes queue, wakes thread, waits until thread closes + // Detroys handles and window + // Either post to or call from window thread + void destroyWindow(); + + // Closes queue, wakes thread, waits until thread closes. + // Call from main thread bool wakeAndDestroy(); void glReady() @@ -424,7 +429,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // *HACK: Attempt to prevent startup crashes by deferring memory accounting // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 bool mGLReady = false; - bool mDeleteOnExit = false; + LLAtomicBool mDeleteOnExit = false; // best guess at available video memory in MB std::atomic mAvailableVRAM; @@ -873,6 +878,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, LLWindowWin32::~LLWindowWin32() { delete mDragDrop; + mDragDrop = NULL; delete [] mWindowTitle; mWindowTitle = NULL; @@ -884,6 +890,7 @@ LLWindowWin32::~LLWindowWin32() mWindowClassName = NULL; delete mWindowThread; + mWindowThread = NULL; } void LLWindowWin32::show() @@ -4931,6 +4938,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() #endif } + destroyWindow(); cleanupDX(); if (mDeleteOnExit) @@ -4939,6 +4947,35 @@ void LLWindowWin32::LLWindowWin32Thread::run() } } +void LLWindowWin32::LLWindowWin32Thread::destroyWindow() +{ + if (mWindowHandleThrd != NULL && IsWindow(mWindowHandleThrd)) + { + if (mhDCThrd) + { + if (!ReleaseDC(mWindowHandleThrd, mhDCThrd)) + { + LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL; + } + mhDCThrd = NULL; + } + + // This causes WM_DESTROY to be sent *immediately* + if (!destroy_window_handler(mWindowHandleThrd)) + { + LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL; + } + } + else + { + // Something killed the window while we were busy destroying gl or handle somehow got broken + LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; + } + mWindowHandleThrd = NULL; + mhDCThrd = NULL; + mGLReady = false; +} + bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() { if (mQueue->isClosed()) @@ -4954,35 +4991,6 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() // Schedule destruction HWND old_handle = mWindowHandleThrd; - post([this]() - { - if (IsWindow(mWindowHandleThrd)) - { - if (mhDCThrd) - { - if (!ReleaseDC(mWindowHandleThrd, mhDCThrd)) - { - LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL; - } - mhDCThrd = NULL; - } - - // This causes WM_DESTROY to be sent *immediately* - if (!destroy_window_handler(mWindowHandleThrd)) - { - LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL; - } - } - else - { - // Something killed the window while we were busy destroying gl or handle somehow got broken - LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; - } - mWindowHandleThrd = NULL; - mhDCThrd = NULL; - mGLReady = false; - }); - mDeleteOnExit = true; SetWindowLongPtr(old_handle, GWLP_USERDATA, NULL); -- cgit v1.2.3 From 28f45962fdf69ea5149133fbaff425f9e2ca6f42 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 15 Oct 2024 12:56:47 +0300 Subject: Post-merge cleanup: llwindowwin32.cpp --- indra/llwindow/llwindowwin32.cpp | 8 -------- 1 file changed, 8 deletions(-) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index beaf910a02..6ce0594c96 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -411,14 +411,6 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool bool mGLReady = false; bool mGotGLBuffer = false; LLAtomicBool mDeleteOnExit = false; - // best guess at available video memory in MB - std::atomic mAvailableVRAM; - - U32 mMaxVRAM = 0; // maximum amount of vram to allow in the "budget", or 0 for no maximum (see updateVRAMUsage) - - IDXGIAdapter3* mDXGIAdapter = nullptr; - LPDIRECT3D9 mD3D = nullptr; - LPDIRECT3DDEVICE9 mD3DDevice = nullptr; }; -- cgit v1.2.3 From 19347f7094c9448e02a021ae2d571b5fe8bfcc2e Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 15 Oct 2024 22:35:38 +0200 Subject: Fix merge issues: * Restore changes from 21947778baaca205615a71a97ac8f563c998fdd3 to llwindow/llwindowwin32.cpp * Restore changes from 3758618949684641fc94b5c9478d9002706213cc to newview/llinspecttexture.cpp * Fix apparent merge error in LLInventoryPanel::itemChanged * Restore changes from 1eeecfa1a8bf43a8980217ce34e3b5f4458483e0 in newview/llpaneloutfitsinventory.h * Restore changes from b9633c17e373bfe55b29228996e8473eb041466d in newview/llpaneloutfitsinventory.h & newview/llpanelwearing.cpp * Restore changes from f660f1f0fda4d2363d351fa550b4f8818b46c2c3 in newview/llviewertexture.cpp * Restore changes from b9633c17e373bfe55b29228996e8473eb041466d & 98f7d73d46fdc045759023eda6409e8c791f5cb2 in newview/lloutfitgallery.cpp and newview/lloutfitslist.cpp * Replace changes from 23729442aab7130f3368d433e8a5a9dd45ff6b98 with current implementation in develop branch * Fix more broken changes in LLViewerTexture::saveRawImage * Restore the changes in LLMath both from develop and maint-c * Fix all kind of other merge errors # Conflicts: # indra/llmath/v2math.h # indra/llmath/v3math.h # indra/llui/llfolderviewitem.cpp # indra/llwindow/llwindowwin32.cpp # indra/newview/llfloaterobjectweights.h # indra/newview/lloutfitgallery.cpp # indra/newview/lloutfitslist.cpp # indra/newview/llsidepaneliteminfo.cpp # indra/newview/llvoavatar.cpp --- indra/llwindow/llwindowwin32.cpp | 52 ++++++++-------------------------------- 1 file changed, 10 insertions(+), 42 deletions(-) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 6ce0594c96..6fad11d506 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -410,7 +410,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 bool mGLReady = false; bool mGotGLBuffer = false; - LLAtomicBool mDeleteOnExit = false; + bool mDeleteOnExit = false; }; @@ -4852,6 +4852,15 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() mGLReady = false; }); + mDeleteOnExit = true; + SetWindowLongPtr(old_handle, GWLP_USERDATA, NULL); + + // Let thread finish on its own and don't block main thread. + for (auto& pair : mThreads) + { + pair.second.detach(); + } + LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL; mQueue->close(); @@ -4866,47 +4875,6 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); } - // There are cases where window will refuse to close, - // can't wait forever on join, check state instead - LLTimer timeout; - timeout.setTimerExpirySec(2.0); - while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd) - { - ms_sleep(100); - } - - if (getQueue().done() || mWindowHandleThrd == NULL) - { - // Window is closed, started closing or is cleaning up - // now wait for our single thread to die. - if (mWindowHandleThrd) - { - LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; - } - else - { - LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; - } - for (auto& pair : mThreads) - { - pair.second.join(); - } - } - else - { - // Something suspended window thread, can't afford to wait forever - // so kill thread instead - // Ex: This can happen if user starts dragging window arround (if it - // was visible) or a modal notification pops up - LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL; - - for (auto& pair : mThreads) - { - // very unsafe - TerminateThread(pair.second.native_handle(), 0); - pair.second.detach(); - } - } LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL; return true; } -- cgit v1.2.3 From bab3bc4ebd8f33d80411d6d28e16eea6b865e8fd Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 15 Oct 2024 23:49:00 +0200 Subject: Fix more merge issues: * Re-apply changes from a620e58daccf92b5b8d61347312739720ed2b51a * Fix duplicate code resulting from 826236f1bc065fba257d7954d11ac98c59493445 # Conflicts: # indra/llwindow/llwindowwin32.cpp --- indra/llwindow/llwindowwin32.cpp | 44 +++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 6fad11d506..3ef162a870 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -351,6 +351,10 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool void run() override; + // Detroys handles and window + // Either post to or call from window thread + void destroyWindow(); + // Closes queue, wakes thread, waits until thread closes. // Call from main thread bool wakeAndDestroy(); @@ -410,7 +414,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 bool mGLReady = false; bool mGotGLBuffer = false; - bool mDeleteOnExit = false; + LLAtomicBool mDeleteOnExit = false; }; @@ -4802,30 +4806,17 @@ void LLWindowWin32::LLWindowWin32Thread::run() #endif } + destroyWindow(); + if (mDeleteOnExit) { delete this; } } -bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() +void LLWindowWin32::LLWindowWin32Thread::destroyWindow() { - if (mQueue->isClosed()) - { - LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; - return false; - } - - // Make sure we don't leave a blank toolbar button. - // Also hiding window now prevents user from suspending it - // via some action (like dragging it around) - ShowWindow(mWindowHandleThrd, SW_HIDE); - - // Schedule destruction - HWND old_handle = mWindowHandleThrd; - post([this]() - { - if (IsWindow(mWindowHandleThrd)) + if (mWindowHandleThrd != NULL && IsWindow(mWindowHandleThrd)) { if (mhDCThrd) { @@ -4849,9 +4840,24 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() } mWindowHandleThrd = NULL; mhDCThrd = NULL; +} + +bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() +{ + if (mQueue->isClosed()) + { + LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." < Date: Sat, 12 Apr 2025 06:18:44 +0300 Subject: Refactor LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() Key improvements: 1. Better error handling for thread detachment 2. More careful sequencing of operations 3. Ensuring the window is hidden before proceeding with other shutdown steps 4. Proper checking of thread joinability before detaching --- indra/llwindow/llwindowwin32.cpp | 49 ++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 14 deletions(-) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 3ef162a870..83ae302859 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -4846,41 +4846,62 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() { if (mQueue->isClosed()) { - LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." <close(); - // Post a nonsense user message to wake up the thread in - // case it is waiting for a getMessage() + // Wake up the thread if it's stuck in GetMessage() if (old_handle) { WPARAM wparam{ 0xB0B0 }; LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle << ", " << WM_DUMMY_ << ", " << wparam << ")" << std::dec << LL_ENDL; + + // Use PostMessage to signal thread to wake up PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); } + // Cleanly detach threads instead of joining them to avoid blocking the main thread + // This is acceptable since the thread will self-delete with mDeleteOnExit + for (auto& pair : mThreads) + { + try { + // Only detach if the thread is joinable + if (pair.second.joinable()) + { + pair.second.detach(); + } + } + catch (const std::system_error& e) { + LL_WARNS("Window") << "Exception detaching thread: " << e.what() << LL_ENDL; + } + } + LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL; return true; } -- cgit v1.2.3 From 0c89d06ec2441f035c8de4abc9c6545f9fe9ee66 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Wed, 23 Jul 2025 12:11:14 +0300 Subject: #4374 add support for the system theme (light and dark) --- indra/llwindow/llwindowwin32.cpp | 82 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index af53b6fb3f..d97d6e0bb2 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -76,6 +76,11 @@ #pragma comment(lib, "dxguid.lib") // needed for llurlentry test to build on some systems #pragma comment(lib, "dinput8") +#pragma comment(lib, "UxTheme.lib") +#pragma comment(lib, "Dwmapi.lib") +#include +#include // needed for DwmSetWindowAttribute to set window theme + const S32 MAX_MESSAGE_PER_UPDATE = 20; const S32 BITS_PER_PIXEL = 32; const S32 MAX_NUM_RESOLUTIONS = 32; @@ -85,6 +90,10 @@ const F32 ICON_FLASH_TIME = 0.5f; #define USER_DEFAULT_SCREEN_DPI 96 // Win7 #endif +#ifndef WM_DWMCOLORIZATIONCOLORCHANGED +#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320 +#endif + // Claim a couple unused GetMessage() message IDs const UINT WM_DUMMY_(WM_USER + 0x0017); const UINT WM_POST_FUNCTION_(WM_USER + 0x0018); @@ -137,6 +146,17 @@ typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)( _Out_ UINT *dpiX, _Out_ UINT *dpiY); +typedef enum PREFERRED_APP_MODE +{ + DEFAULT, + ALLOW_DARK, + FORCE_DARK, + FORCE_LIGHT, + MAX +} PREFERRED_APP_MODE; + +typedef PREFERRED_APP_MODE(WINAPI* fnSetPreferredAppMode)(PREFERRED_APP_MODE mode); + // // LLWindowWin32 // @@ -1809,6 +1829,8 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw mhDC = pair.second; sWindowHandleForMessageBox = mWindowHandle; + + updateWindowTheme(); } void* LLWindowWin32::createSharedContext() @@ -3007,6 +3029,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ WINDOW_IMP_POST(window_imp->mMouseVanish = true); } } + // Check if theme-related settings changed + else if (l_param && (wcscmp((LPCWSTR)l_param, L"ImmersiveColorSet") == 0)) + { + WINDOW_IMP_POST(window_imp->updateWindowTheme()); + } + } + break; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + { + WINDOW_IMP_POST(window_imp->updateWindowTheme()); } break; @@ -4962,3 +4995,52 @@ void LLWindowWin32::updateWindowRect() }); } } + +bool LLWindowWin32::isSystemAppDarkMode() +{ + HKEY hKey; + DWORD dwValue = 1; // Default to light theme + DWORD dwSize = sizeof(DWORD); + + // Check registry for system theme preference + LSTATUS ret_code = + RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey); + if (ERROR_SUCCESS == ret_code) + { + if (RegQueryValueExW(hKey, L"AppsUseLightTheme", NULL, NULL, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS) + { + // If AppsUseLightTheme is not found, check SystemUsesLightTheme + dwSize = sizeof(DWORD); + RegQueryValueExW(hKey, L"SystemUsesLightTheme", NULL, NULL, (LPBYTE)&dwValue, &dwSize); + } + RegCloseKey(hKey); + } + + // Return true if dark mode + return dwValue == 0; +} + +void LLWindowWin32::updateWindowTheme() +{ + bool use_dark_mode = isSystemAppDarkMode(); + if (use_dark_mode == mCurrentDarkMode) + { + return; + } + mCurrentDarkMode = use_dark_mode; + + HMODULE hUxTheme = LoadLibraryExW(L"uxtheme.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (hUxTheme) + { + auto SetPreferredAppMode = (fnSetPreferredAppMode)GetProcAddress(hUxTheme, "SetPreferredAppMode"); + if (SetPreferredAppMode) + { + SetPreferredAppMode(use_dark_mode ? ALLOW_DARK : FORCE_LIGHT); + } + FreeLibrary(hUxTheme); + } + BOOL dark_mode(use_dark_mode); + DwmSetWindowAttribute(mWindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark_mode, sizeof(dark_mode)); + + LL_INFOS("Window") << "Viewer window theme is set to " << (use_dark_mode ? "dark" : "light") << " mode" << LL_ENDL; +} -- cgit v1.2.3 From 9df3b30479e35f0a301d8871582b95e4e2caab7c Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Thu, 24 Jul 2025 00:44:16 +0300 Subject: #4424 don't try to update theme too early --- indra/llwindow/llwindowwin32.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index d97d6e0bb2..76d72fe725 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -859,6 +859,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // Initialize (boot strap) the Language text input management, // based on the system's (or user's) default settings. allowLanguageTextInput(NULL, false); + updateWindowTheme(); } @@ -1829,8 +1830,6 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw mhDC = pair.second; sWindowHandleForMessageBox = mWindowHandle; - - updateWindowTheme(); } void* LLWindowWin32::createSharedContext() -- cgit v1.2.3 From 5291fc252aba354e129ec85076348059cae01f3a Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Sat, 26 Jul 2025 01:20:22 +0300 Subject: #4374 update icon for title bar --- indra/llwindow/llwindowwin32.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 76d72fe725..68b6de197a 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -113,6 +113,7 @@ static std::thread::id sMainThreadId; LPWSTR gIconResource = IDI_APPLICATION; +LPWSTR gIconSmallResource = IDI_APPLICATION; LPDIRECTINPUT8 gDirectInput8; LLW32MsgCallback gAsyncMsgCallback = NULL; @@ -527,6 +528,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mFSAASamples = fsaa_samples; mIconResource = gIconResource; + mIconSmallResource = gIconSmallResource; mOverrideAspectRatio = 0.f; mNativeAspectRatio = 0.f; mInputProcessingPaused = false; @@ -860,6 +862,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // based on the system's (or user's) default settings. allowLanguageTextInput(NULL, false); updateWindowTheme(); + setCustomIcon(); } @@ -5043,3 +5046,20 @@ void LLWindowWin32::updateWindowTheme() LL_INFOS("Window") << "Viewer window theme is set to " << (use_dark_mode ? "dark" : "light") << " mode" << LL_ENDL; } + +void LLWindowWin32::setCustomIcon() +{ + if (mWindowHandle) + { + HICON hDefaultIcon = LoadIcon(mhInstance, mIconResource); + HICON hSmallIcon = LoadIcon(mhInstance, mIconSmallResource); + mWindowThread->post([=]() + { + SendMessage(mWindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hDefaultIcon); + SendMessage(mWindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon); + + SetClassLongPtr(mWindowHandle, GCLP_HICON, (LONG_PTR)hDefaultIcon); + SetClassLongPtr(mWindowHandle, GCLP_HICONSM, (LONG_PTR)hSmallIcon); + }); + } +} -- cgit v1.2.3 From 23083286601150854f1c4a10e92699e7783cb224 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 11 Aug 2025 21:17:13 +0300 Subject: #4284 Better window shutdown logging To help investigate shutdown freeze --- indra/llwindow/llwindowwin32.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index d46357629a..94fd104bcc 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1000,7 +1000,7 @@ void LLWindowWin32::close() // Restore gamma to the system values. restoreGamma(); - LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; + LL_INFOS("Window") << "Destroying Window Thread" << LL_ENDL; if (sWindowHandleForMessageBox == mWindowHandle) { @@ -4891,7 +4891,7 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() { if (mQueue->isClosed()) { - LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; + LL_WARNS("Window") << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; return false; } @@ -4900,6 +4900,11 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() { ShowWindow(mWindowHandleThrd, SW_HIDE); } + else + { + LL_WARNS("Window") << "Tried to hide window, but Win32 window handle is NULL." << LL_ENDL; + return false; + } mGLReady = false; -- cgit v1.2.3 From 143de1ddbf4489c490d16cc8cbf0eca688a81b43 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 19 Aug 2025 11:40:28 +0300 Subject: #4284 Reorder window shutdown --- indra/llwindow/llwindowwin32.cpp | 50 +++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 29 deletions(-) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 94fd104bcc..b127c9b48f 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1000,7 +1000,7 @@ void LLWindowWin32::close() // Restore gamma to the system values. restoreGamma(); - LL_INFOS("Window") << "Destroying Window Thread" << LL_ENDL; + LL_INFOS("Window") << "Cleanup and destruction of Window Thread" << LL_ENDL; if (sWindowHandleForMessageBox == mWindowHandle) { @@ -4895,17 +4895,7 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() return false; } - // Hide the window immediately to prevent user interaction during shutdown - if (mWindowHandleThrd) - { - ShowWindow(mWindowHandleThrd, SW_HIDE); - } - else - { - LL_WARNS("Window") << "Tried to hide window, but Win32 window handle is NULL." << LL_ENDL; - return false; - } - + // Stop checking budget mGLReady = false; // Capture current handle before we lose it @@ -4920,24 +4910,10 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() // Signal thread to clean up when done mDeleteOnExit = true; - // Close the queue first - LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL; - mQueue->close(); - - // Wake up the thread if it's stuck in GetMessage() - if (old_handle) - { - WPARAM wparam{ 0xB0B0 }; - LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle - << ", " << WM_DUMMY_ - << ", " << wparam << ")" << std::dec << LL_ENDL; - - // Use PostMessage to signal thread to wake up - PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); - } - + LL_INFOS("Window") << "Detaching window's thread" << LL_ENDL; // Cleanly detach threads instead of joining them to avoid blocking the main thread // This is acceptable since the thread will self-delete with mDeleteOnExit + // Doing it before close() to make sure thread doesn't die before or mid detach. for (auto& pair : mThreads) { try { @@ -4952,7 +4928,23 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() } } - LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL; + // Close the queue. + LL_INFOS("Window") << "Closing window's pool queue" << LL_ENDL; + mQueue->close(); + + // Wake up the thread if it's stuck in GetMessage() + if (old_handle) + { + WPARAM wparam{ 0xB0B0 }; + LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle + << ", " << WM_DUMMY_ + << ", " << wparam << ")" << std::dec << LL_ENDL; + + // Use PostMessage to signal thread to wake up + PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); + } + + LL_INFOS("Window") << "Thread pool shutdown complete" << LL_ENDL; return true; } -- cgit v1.2.3