From e129eac3401f6af629ef96e91f4db62b3528cbc9 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Wed, 29 Apr 2026 01:20:11 +0300 Subject: #5719 Partial detection of shutdown from task manager We can't be absolutely certain about the source in this case, but at least try to distinguish termination caused by task manager from 'unknowns'. --- indra/llwindow/llwindowcallbacks.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra/llwindow/llwindowcallbacks.cpp') diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 7331f50ba0..6267433751 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -68,6 +68,10 @@ void LLWindowCallbacks::handleMouseLeave(LLWindow *window) return; } +void LLWindowCallbacks::handlePreCloseRequest() +{ +} + bool LLWindowCallbacks::handleCloseRequest(LLWindow *window, bool from_user) { //allow the window to close -- cgit v1.3 From edf982b7a4efbee1ba75349c460e7040e8d04428 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 29 May 2026 03:03:31 +0300 Subject: #5719 Detect hybernation #2 --- indra/llwindow/llwindowcallbacks.cpp | 8 ++++++++ indra/llwindow/llwindowcallbacks.h | 2 ++ indra/llwindow/llwindowwin32.cpp | 15 ++++++++------- indra/newview/llappviewer.cpp | 29 ++++++++++++++++++----------- indra/newview/llappviewer.h | 2 ++ indra/newview/llviewerwindow.cpp | 18 ++++++++++++++++++ indra/newview/llviewerwindow.h | 2 ++ 7 files changed, 58 insertions(+), 18 deletions(-) (limited to 'indra/llwindow/llwindowcallbacks.cpp') diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 6267433751..8d1eebe33d 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -72,6 +72,14 @@ void LLWindowCallbacks::handlePreCloseRequest() { } +void LLWindowCallbacks::handleCloseRequestCanceled() +{ +} + +void LLWindowCallbacks::handleSuspendRequest() +{ +} + bool LLWindowCallbacks::handleCloseRequest(LLWindow *window, bool from_user) { //allow the window to close diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 457087448f..390e3ff93a 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -43,6 +43,8 @@ public: virtual void handleMouseLeave(LLWindow *window); // Called before close request is processed (ex: to create marker file in case OS is about to kill app). virtual void handlePreCloseRequest(); + virtual void handleCloseRequestCanceled(); + virtual void handleSuspendRequest(); // return true to allow window to close, which will then cause handleQuit to be called virtual bool handleCloseRequest(LLWindow *window, bool from_user); virtual bool handleSessionExit(LLWindow* window); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 52e0cdd5d5..79cdf8b67a 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2657,21 +2657,22 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // Viewer can't function in hibernation, try to shut down. // The system allows approximately two seconds for an // application to handle this notification. + + // Mark app as potentially closing, to minimize issues if OS does not recover. + window_imp->mCallbacks->handlePreCloseRequest(); window_imp->post([=]() { - LL_INFOS("Window") << "Shutting down due to system suspending (sleep/hibernate)" << LL_ENDL; - if (window_imp->mCallbacks->handleSessionExit(window_imp)) - { - // Get the app to initiate cleanup. - window_imp->mCallbacks->handleQuit(window_imp); - } + window_imp->mCallbacks->handleSuspendRequest(); }); + // Window thread normally doesn't block main thread, but OS can suspend + // immediately if we don't wait. + // Keep OS from suspending to give a chance to send stats. ms_sleep(1000); return TRUE; case PBT_APMRESUMESUSPEND: LL_INFOS("Window") << "System is resuming from suspend" << LL_ENDL; - // Shouldn't be up, but log just in case. + window_imp->mCallbacks->handleCloseRequestCanceled(); return TRUE; case PBT_APMPOWERSTATUSCHANGE: diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 7f06f991b0..6b5c0ea6b0 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4055,8 +4055,10 @@ void LLAppViewer::processMarkerFiles() // - Other Crash (SecondLife.error_marker present) // - Watchdog freeze (SecondLife.watchdog_marker present) // - Failed to initialize (SecondLife.inited_marker not present) - // - Potentially killed by task manager (SecondLife.close_marker present) - // These checks should also remove these files for the last 2 cases if they currently exist + // - Potentially killed by task manager or computer + // didn't recover from hibernation (SecondLife.close_marker present) + // These checks should also remove these files for the last 2 cases + // if they currently exist std::ostringstream marker_log_stream; bool marker_is_same_version = true; @@ -4227,21 +4229,21 @@ void LLAppViewer::processMarkerFiles() } } // If 'close' marker is found, viewer either started shutdown but - // failed, or viewer got killed by task manager. + // failed, OS did not recover from hibernation or viewer got + // killed by task manager. // Marker does not indicate that viewer was closed or is closing, // just that 'close' was requested before viewer died. else if (LLAPRFile::isExist(close_marker_file, NULL, LL_APR_RB)) { - // For now treat as 'other' cause. - // Unfortunately we can't for certain distinguish task - // manager's case from other shutdown problems, so we - // have to report both. - // Todo: if this bears noticeable fruits, make a new state later. - // New categories need server/web side support. + // Unfortunately we can't reliably distinguish + // task manager's case from genuine shutdown, so we + // have to report all of them as the same thing. + // Todo: but we can distinguish hibernation, might want + // to simply not report it as an issue. if (markerIsSameVersion(close_marker_file)) { - gLastExecEvent = LAST_EXEC_UNKNOWN == gLastExecEvent ? LAST_EXEC_OTHER_CRASH : LAST_EXEC_LOGOUT_CRASH; - LL_INFOS("MarkerFile") << "'Close' marker '" << close_marker_file << "' found, setting LastExecEvent to CRASH" + gLastExecEvent = LAST_EXEC_OS_EVENT; + LL_INFOS("MarkerFile") << "'Close' marker '" << close_marker_file << "' found, setting LastExecEvent to OS_EVENT" << LL_ENDL; } } @@ -4472,6 +4474,11 @@ void LLAppViewer::abortQuit() mClosingFloaters = false; } +void LLAppViewer::sendViewerStatistics() +{ + send_viewer_stats(false); +} + void LLAppViewer::migrateCacheDirectory() { #if LL_WINDOWS || LL_DARWIN diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index b404ec2c03..cde58b0850 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -79,6 +79,7 @@ typedef enum LAST_EXEC_INIT, LAST_EXEC_UNKNOWN, LAST_EXEC_LOGOUT_UNKNOWN, + LAST_EXEC_OS_EVENT, LAST_EXEC_COUNT } eLastExecEvent; @@ -113,6 +114,7 @@ public: const LLSD& substitutions = LLSD()); // Display an error dialog and forcibly quit. void earlyExitNoNotify(); // Do not display error dialog then forcibly quit. void abortQuit(); // Called to abort a quit request. + void sendViewerStatistics(); bool quitRequested() { return mQuitRequested; } bool logoutRequestSent() { return mLogoutRequestSent; } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index dbf9fe6bf2..abd7096f50 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1474,7 +1474,25 @@ void LLViewerWindow::handlePreCloseRequest() { LLAppViewer::instance()->createCloseRequestMarker(); } +} +void LLViewerWindow::handleCloseRequestCanceled() +{ + // WINDOW THREAD! since we need this to act fast. + if (!LLApp::isExiting() && !LLApp::isStopped()) + { + LLAppViewer::instance()->removeCloseRequestMarker(); + } +} + +void LLViewerWindow::handleSuspendRequest() +{ + LLAppViewer::instance()->sendViewerStatistics(); + // Todo: this should send a disconnect request as viewer + // can't keep heartbeat up while suspended and will get + // disconnected within a minute. + // Add a disconnect here once 'prevent OS from sleeping' + // feature is ready. } bool LLViewerWindow::handleCloseRequest(LLWindow *window, bool from_user) diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index ff5da371ec..b68956d853 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -203,6 +203,8 @@ public: /*virtual*/ bool handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ bool handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handlePreCloseRequest(); + /*virtual*/ void handleCloseRequestCanceled(); + /*virtual*/ void handleSuspendRequest(); /*virtual*/ bool handleCloseRequest(LLWindow *window, bool from_user); /*virtual*/ bool handleSessionExit(LLWindow* window); /*virtual*/ void handleQuit(LLWindow *window); -- cgit v1.3 From e47869b667ae34b524f303f7ab2b1c1c5d661278 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 28 Aug 2026 20:59:44 +0300 Subject: p#700 Add a postponed size update on viewDidMoveToWindow --- indra/llwindow/llopenglview-objc.mm | 46 ++++++++++++++++++++++++++++++++---- indra/llwindow/llwindowcallbacks.cpp | 4 ++++ indra/llwindow/llwindowcallbacks.h | 1 + indra/llwindow/llwindowmacosx-objc.h | 2 ++ indra/llwindow/llwindowmacosx.cpp | 17 +++++++++++-- indra/llwindow/llwindowmacosx.h | 5 ++++ indra/newview/llviewerwindow.cpp | 21 ++++++++++++++-- indra/newview/llviewerwindow.h | 1 + 8 files changed, 89 insertions(+), 8 deletions(-) (limited to 'indra/llwindow/llwindowcallbacks.cpp') diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 403103991e..0786449286 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -137,6 +137,18 @@ attributedStringInfo getSegments(NSAttributedString *str) - (void)viewDidMoveToWindow { + // viewDidMoveToWindow is called both when the view is attached to a window + // and when it is detached (window == nil). + [NSObject cancelPreviousPerformRequestsWithTarget:self + selector:@selector(performDeferredResolutionUpdate) + object:nil]; + + if (![self window]) + { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + return; + } + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowResized:) name:NSWindowDidResizeNotification object:[self window]]; @@ -157,11 +169,37 @@ attributedStringInfo getSegments(NSAttributedString *str) object:[self window]]; - NSRect wnd_rect = [[self window] frame]; - NSRect dev_rect = [self convertRectToBacking:wnd_rect]; - if (!NSEqualSizes(wnd_rect.size,dev_rect.size)) + if (windowCallbacksReady()) + { + NSRect wnd_rect = [[self window] frame]; + NSRect dev_rect = [self convertRectToBacking:wnd_rect]; + if (!NSEqualSizes(wnd_rect.size,dev_rect.size)) + { + // If window size actually changes, update size immediately + callResize(dev_rect.size.width, dev_rect.size.height); + } + else + { + // Defer size update to let the window settle on its final display + // before checkSettings() reads the live backing size. + callRequestResolutionUpdate(); + } + } + else + { + // Defer so that mCallbacks is the real callbacks object, + // not the null_callbacks used during LLWindowMacOSX construction. + // afterDelay will fire on the next loop iteration. + NSLog(@"viewDidMoveToWindow triggered, but callbacks not ready, postponing resolution update", nil); + [self performSelector:@selector(performDeferredResolutionUpdate) withObject:nil afterDelay:0]; + } +} + +- (void)performDeferredResolutionUpdate +{ + if ([self window]) { - callResize(dev_rect.size.width, dev_rect.size.height); + callRequestResolutionUpdate(); } } diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index f997aebb9d..b16d0ffce8 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -156,6 +156,10 @@ void LLWindowCallbacks::handleResize(LLWindow *window, const S32 width, const S3 { } +void LLWindowCallbacks::handleRequestResolutionUpdate(LLWindow* window) +{ +} + void LLWindowCallbacks::handleFocus(LLWindow *window) { LL_WARNS("COCOA") << "Called handleFocus proto" << LL_ENDL; diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index cd54ccd7c9..1fcf2974b5 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -63,6 +63,7 @@ public: virtual void handleScrollWheel(LLWindow *window, S32 clicks); virtual void handleScrollHWheel(LLWindow *window, S32 clicks); virtual void handleResize(LLWindow *window, S32 width, S32 height); + virtual void handleRequestResolutionUpdate(LLWindow* window); virtual void handleFocus(LLWindow *window); virtual void handleFocusLost(LLWindow *window); virtual void handleMenuSelect(LLWindow *window, S32 menu_item); diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index ec9afb1844..a9698bc0e1 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -140,6 +140,7 @@ void callLeftMouseDown(float *pos, unsigned int mask); void callLeftMouseUp(float *pos, unsigned int mask); void callDoubleClick(float *pos, unsigned int mask); void callResize(unsigned int width, unsigned int height); +void callRequestResolutionUpdate(); void callMouseMoved(float *pos, unsigned int mask); void callMouseDragged(float *pos, unsigned int mask); void callScrollMoved(float deltaX, float deltaY); @@ -157,6 +158,7 @@ void callFocusLost(); void callModifier(unsigned int mask); void callQuitHandler(); void commitCurrentPreedit(GLViewRef glView); +bool windowCallbacksReady(); #include void callHandleDragEntered(std::string url); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 7cb681aefe..7310e5b2fa 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -165,6 +165,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, // Route them to a dummy callback structure until the end of constructor. LLWindowCallbacks null_callbacks; mCallbacks = &null_callbacks; + mIsConstructing = true; // Voodoo for calling cocoa from carbon (see llwindowmacosx-objc.mm). setupCocoa(); @@ -236,9 +237,8 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, } mCallbacks = callbacks; + mIsConstructing = false; stop_glerror(); - - } // These functions are used as wrappers for our internal event handling callbacks. @@ -412,6 +412,14 @@ void callResize(unsigned int width, unsigned int height) } } +void callRequestResolutionUpdate() +{ + if (gWindowImplementation && gWindowImplementation->getCallbacks()) + { + gWindowImplementation->getCallbacks()->handleRequestResolutionUpdate(gWindowImplementation); + } +} + void callMouseMoved(float *pos, MASK mask) { if (!gWindowImplementation) @@ -705,6 +713,11 @@ void getPreeditLocation(float *location, unsigned int length) } } +bool windowCallbacksReady() +{ + return gWindowImplementation && !gWindowImplementation->isConstructing(); +} + void LLWindowMacOSX::updateMouseDeltas(float* deltas) { if (mCursorDecoupled) diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 9534eadf8e..cc6490bb62 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -147,6 +147,10 @@ public: // enable or disable multithreaded GL static void setUseMultGL(bool use_mult_gl); + // During construction null_callbacks are used, + // this is a way to determine when callbacks are ready. + bool isConstructing() const { return mIsConstructing; } + protected: LLWindowMacOSX(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, @@ -223,6 +227,7 @@ protected: bool mMinimized; U32 mFSAASamples; bool mForceRebuild; + bool mIsConstructing = true; S32 mDragOverrideCursor; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index e3e8cd1fce..e44dbd8f0b 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1581,6 +1581,12 @@ void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height) LL_DEBUGS("Window") << "handleResize, new width: " << width << " height: " << height << LL_ENDL; } +void LLViewerWindow::handleRequestResolutionUpdate(LLWindow* window) +{ + requestResolutionUpdate(); + LL_DEBUGS("Window") << "handleRequestResolutionUpdate: mResDirty set" << LL_ENDL; +} + // The top-level window has gained focus (e.g. via ALT-TAB) void LLViewerWindow::handleFocus(LLWindow *window) { @@ -2043,7 +2049,7 @@ LLViewerWindow::LLViewerWindow(const Params& p) } else { - LL_DEBUGS("Window") << "Display init diagnostics:" + LL_DEBUGS("Window") << "Display init:" << " screen_size=" << scr.mX << "x" << scr.mY << " system_ui_size=" << mWindow->getSystemUISize() << " pixel_aspect_ratio=" << mWindow->getPixelAspectRatio() @@ -6091,7 +6097,18 @@ void LLViewerWindow::checkSettings() // We want to update the resolution AFTER the states getting refreshed not before. if (mResDirty) { - reshape(getWindowWidthRaw(), getWindowHeightRaw()); + LLCoordScreen window_size; + if (mWindow->getSize(&window_size)) + { + reshape(window_size.mX, window_size.mY); + } + else + { + S32 width = getWindowWidthRaw(); + S32 height = getWindowHeightRaw(); + LL_WARNS() << "Failed to get window size, using raw window size " << width << "x" << height << " instead" << LL_ENDL; + reshape(width, height); + } mResDirty = false; } } diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 06d49df56d..e09e8fee14 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -221,6 +221,7 @@ public: void handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handleMouseLeave(LLWindow *window); /*virtual*/ void handleResize(LLWindow *window, S32 x, S32 y); + /*virtual*/ void handleRequestResolutionUpdate(LLWindow* window); /*virtual*/ void handleFocus(LLWindow *window); /*virtual*/ void handleFocusLost(LLWindow *window); /*virtual*/ bool handleActivate(LLWindow *window, bool activated); -- cgit v1.3