#4651 Handle window's sessions termination

master
Andrey Kleshchev 2025-09-11 20:38:09 +03:00
parent ac2cbdcc02
commit 8eb015666e
9 changed files with 99 additions and 17 deletions

View File

@ -68,7 +68,13 @@ void LLWindowCallbacks::handleMouseLeave(LLWindow *window)
return;
}
bool LLWindowCallbacks::handleCloseRequest(LLWindow *window)
bool LLWindowCallbacks::handleCloseRequest(LLWindow *window, bool from_user)
{
//allow the window to close
return true;
}
bool LLWindowCallbacks::handleSessionExit(LLWindow* window)
{
//allow the window to close
return true;

View File

@ -42,7 +42,8 @@ public:
virtual bool handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask);
virtual void handleMouseLeave(LLWindow *window);
// return true to allow window to close, which will then cause handleQuit to be called
virtual bool handleCloseRequest(LLWindow *window);
virtual bool handleCloseRequest(LLWindow *window, bool from_user);
virtual bool handleSessionExit(LLWindow* window);
// window is about to be destroyed, clean up your business
virtual void handleQuit(LLWindow *window);
virtual bool handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask);

View File

@ -610,7 +610,7 @@ void callQuitHandler()
{
if (gWindowImplementation && gWindowImplementation->getCallbacks())
{
if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation))
if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation, true))
{
gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation);
}

View File

@ -1881,7 +1881,7 @@ void LLWindowSDL::gatherInput()
{
// *FIX: More informative dialog?
LL_INFOS() << "Could not recreate context after resize! Quitting..." << LL_ENDL;
if(mCallbacks->handleCloseRequest(this))
if(mCallbacks->handleCloseRequest(this, false))
{
// Get the app to initiate cleanup.
mCallbacks->handleQuit(this);
@ -1931,7 +1931,7 @@ void LLWindowSDL::gatherInput()
break;
case SDL_QUIT:
if(mCallbacks->handleCloseRequest(this))
if(mCallbacks->handleCloseRequest(this, true))
{
// Get the app to initiate cleanup.
mCallbacks->handleQuit(this);

View File

@ -2461,10 +2461,13 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
case WM_CLOSE:
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CLOSE");
// todo: WM_CLOSE can be caused by user and by task manager,
// distinguish these cases.
// For now assume it is always user.
window_imp->post([=]()
{
// Will the app allow the window to close?
if (window_imp->mCallbacks->handleCloseRequest(window_imp))
if (window_imp->mCallbacks->handleCloseRequest(window_imp, true))
{
// Get the app to initiate cleanup.
window_imp->mCallbacks->handleQuit(window_imp);
@ -2482,6 +2485,50 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
}
return 0;
}
case WM_QUERYENDSESSION:
{
// Generally means that OS is going to shut down or user is going to log off.
// Can use ShutdownBlockReasonCreate here.
LL_INFOS("Window") << "Received WM_QUERYENDSESSION with wParam: " << (U32)w_param << " lParam: " << (U32)l_param << LL_ENDL;
return TRUE; // 1 = ok to end session. 0 no longer works by itself, use ShutdownBlockReasonCreate
}
case WM_ENDSESSION:
{
// OS session is shutting down, initiate cleanup.
// Comes after WM_QUERYENDSESSION
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ENDSESSION");
LL_INFOS("Window") << "Received WM_ENDSESSION with wParam: " << (U32)w_param << " lParam: " << (U32)l_param << LL_ENDL;
unsigned int end_session_flags = (U32)w_param;
if (end_session_flags == 0)
{
// session is not actually ending
return 0;
}
if ((end_session_flags & ENDSESSION_CLOSEAPP)
|| (end_session_flags & ENDSESSION_CRITICAL)
|| (end_session_flags & ENDSESSION_LOGOFF))
{
window_imp->post([=]()
{
// Check if app needs cleanup or can be closed immediately.
if (window_imp->mCallbacks->handleSessionExit(window_imp))
{
// Get the app to initiate cleanup.
window_imp->mCallbacks->handleQuit(window_imp);
// The app is responsible for calling destroyWindow when done with GL
}
});
// Give app a second to finish up. That's not enough for a clean exit,
// but better than nothing.
// Todo: sync this better, some kind of waitForResult? Can't wait forever,
// but can potentially use ShutdownBlockReasonCreate for a bigger delay.
ms_sleep(1000);
}
// Don't need to post quit or destroy window,
// if session is ending OS is going to take care of it.
return 0;
}
case WM_COMMAND:
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COMMAND");

View File

@ -4195,7 +4195,7 @@ void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions)
// case where we need the viewer to exit without any need for notifications
void LLAppViewer::earlyExitNoNotify()
{
LL_WARNS() << "app_early_exit with no notification: " << LL_ENDL;
LL_WARNS() << "app_early_exit with no notification." << LL_ENDL;
gDoDisconnect = true;
finish_early_exit( LLSD(), LLSD() );
}

View File

@ -149,6 +149,12 @@ public:
std::string getWindowTitle() const; // The window display name.
void forceDisconnect(const std::string& msg); // Force disconnection, with a message to the user.
// sendSimpleLogoutRequest does not create a marker file.
// Meant for lost network case, and for forced shutdowns,
// to at least attempt to remove the ghost from the world.
void sendSimpleLogoutRequest();
void badNetworkHandler(); // Cause a crash state due to bad network packet.
bool hasSavedFinalSnapshot() { return mSavedFinalSnapshot; }
@ -310,10 +316,6 @@ private:
void sendLogoutRequest();
void disconnectViewer();
// Does not create a marker file. For lost network case,
// to at least attempt to remove the ghost from the world.
void sendSimpleLogoutRequest();
// *FIX: the app viewer class should be some sort of singleton, no?
// Perhaps its child class is the singleton and this should be an abstract base.
static LLAppViewer* sInstance;

View File

@ -1461,18 +1461,43 @@ void LLViewerWindow::handleMouseLeave(LLWindow *window)
LLToolTipMgr::instance().blockToolTips();
}
bool LLViewerWindow::handleCloseRequest(LLWindow *window)
bool LLViewerWindow::handleCloseRequest(LLWindow *window, bool from_user)
{
if (!LLApp::isExiting() && !LLApp::isStopped())
{
// User has indicated they want to close, but we may need to ask
// about modified documents.
LLAppViewer::instance()->userQuit();
// Don't quit immediately
if (from_user)
{
// User has indicated they want to close, but we may need to ask
// about modified documents.
LLAppViewer::instance()->userQuit();
// Don't quit immediately
}
else
{
// OS is asking us to quit, assume we have time and start cleanup
LLAppViewer::instance()->requestQuit();
}
}
return false;
}
bool LLViewerWindow::handleSessionExit(LLWindow* window)
{
if (!LLApp::isExiting() && !LLApp::isStopped())
{
// Viewer received WM_ENDSESSION and app will be killed soon if it doesn't respond
LLAppViewer* app = LLAppViewer::instance();
app->sendSimpleLogoutRequest();
app->earlyExitNoNotify();
// Not viewer's fault, remove marker files so
// that statistics won't consider this to be a crash
app->removeMarkerFiles();
return false;
}
return true;
}
void LLViewerWindow::handleQuit(LLWindow *window)
{
if (gNonInteractive)

View File

@ -197,7 +197,8 @@ public:
/*virtual*/ bool handleUnicodeChar(llwchar uni_char, MASK mask); // NOT going to handle extended
/*virtual*/ bool handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask);
/*virtual*/ bool handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask);
/*virtual*/ bool handleCloseRequest(LLWindow *window);
/*virtual*/ bool handleCloseRequest(LLWindow *window, bool from_user);
/*virtual*/ bool handleSessionExit(LLWindow* window);
/*virtual*/ void handleQuit(LLWindow *window);
/*virtual*/ bool handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask);
/*virtual*/ bool handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask);