HaikuDepot: Shutdown Handling
Improvements to the shutdown handling mechanics so that if there is an install etc... happening when the application is quit that it will wait until the process is complete before actually terminating. Change-Id: I8d3c4fbd9de0abc9382d55f0a6955b7f63a36637 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4322 Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org> Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
This commit is contained in:
parent
6a41334ced
commit
95c7b01864
@ -149,6 +149,7 @@ local applicationSources =
|
||||
ScrollableGroupView.cpp
|
||||
SettingsWindow.cpp
|
||||
SharedBitmap.cpp
|
||||
ShuttingDownWindow.cpp
|
||||
ToLatestUserUsageConditionsWindow.cpp
|
||||
UserCredentials.cpp
|
||||
UserDetail.cpp
|
||||
@ -174,7 +175,6 @@ local applicationSources =
|
||||
AbstractSingleFileServerProcess.cpp
|
||||
LocalPkgDataLoadProcess.cpp
|
||||
LocalRepositoryUpdateProcess.cpp
|
||||
NonBlockingProcessNode.cpp
|
||||
ProcessCoordinator.cpp
|
||||
ProcessCoordinatorFactory.cpp
|
||||
ServerHelper.cpp
|
||||
|
@ -12,8 +12,8 @@
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
#define SPIN_UNTIL_STARTED_DELAY_MI 250 * 1000
|
||||
// quarter of a second
|
||||
#define SPIN_DELAY_MI 500 * 1000
|
||||
// half of a second
|
||||
|
||||
#define TIMEOUT_UNTIL_STARTED_SECS 10
|
||||
#define TIMEOUT_UNTIL_STOPPED_SECS 10
|
||||
@ -45,20 +45,21 @@ AbstractProcessNode::Process() const
|
||||
|
||||
status_t
|
||||
AbstractProcessNode::_SpinUntilProcessState(
|
||||
uint32 desiredStatesMask, uint32 timeoutSeconds)
|
||||
uint32 desiredStatesMask, int32 timeoutSeconds)
|
||||
{
|
||||
bigtime_t start = system_time();
|
||||
bigtime_t timeoutMicroSeconds = timeoutSeconds * 1000 * 1000;
|
||||
|
||||
while (true) {
|
||||
if ((Process()->ProcessState() & desiredStatesMask) != 0)
|
||||
return B_OK;
|
||||
|
||||
usleep(SPIN_UNTIL_STARTED_DELAY_MI);
|
||||
usleep(SPIN_DELAY_MI);
|
||||
|
||||
if (system_time() - start > timeoutMicroSeconds) {
|
||||
HDERROR("[Node<%s>] timeout waiting for process state",
|
||||
Process()->Name());
|
||||
int32 secondElapsed = static_cast<int32>(
|
||||
(system_time() - start) / (1000 * 1000));
|
||||
|
||||
if (timeoutSeconds > 0 && secondElapsed > timeoutSeconds) {
|
||||
HDERROR("[Node<%s>] timeout waiting for process state after %"
|
||||
B_PRIi32 " seconds", Process()->Name(), secondElapsed);
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ public:
|
||||
virtual ~AbstractProcessNode();
|
||||
|
||||
AbstractProcess* Process() const;
|
||||
virtual status_t StartProcess() = 0;
|
||||
virtual status_t StopProcess() = 0;
|
||||
virtual status_t Start() = 0;
|
||||
virtual status_t RequestStop() = 0;
|
||||
|
||||
void AddPredecessor(AbstractProcessNode* node);
|
||||
int32 CountPredecessors() const;
|
||||
@ -40,7 +40,7 @@ public:
|
||||
protected:
|
||||
status_t _SpinUntilProcessState(
|
||||
uint32 desiredStatesMask,
|
||||
uint32 timeoutSeconds);
|
||||
int32 timeoutSeconds);
|
||||
|
||||
private:
|
||||
void _AddSuccessor(AbstractProcessNode* node);
|
||||
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "NonBlockingProcessNode.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "AbstractProcess.h"
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
#define TIMEOUT_UNTIL_STARTED_SECS 10
|
||||
#define TIMEOUT_UNTIL_STOPPED_SECS 10
|
||||
|
||||
|
||||
NonBlockingProcessNode::NonBlockingProcessNode(AbstractProcess* process)
|
||||
:
|
||||
AbstractProcessNode(process)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NonBlockingProcessNode::~NonBlockingProcessNode()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*! Considered to be protected from concurrent access by the ProcessCoordinator
|
||||
*/
|
||||
|
||||
status_t
|
||||
NonBlockingProcessNode::StartProcess()
|
||||
{
|
||||
HDINFO("[Node<%s>] initiating non-blocking", Process()->Name());
|
||||
Process()->Run();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*! Considered to be protected from concurrent access by the ProcessCoordinator
|
||||
*/
|
||||
|
||||
status_t
|
||||
NonBlockingProcessNode::StopProcess()
|
||||
{
|
||||
Process()->SetListener(NULL);
|
||||
status_t stopResult = Process()->Stop();
|
||||
return stopResult;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef NON_BLOCKING_PROCESS_NODE_H
|
||||
#define NON_BLOCKING_PROCESS_NODE_H
|
||||
|
||||
|
||||
#include "AbstractProcessNode.h"
|
||||
|
||||
|
||||
class AbstractProcess;
|
||||
|
||||
|
||||
class NonBlockingProcessNode : public AbstractProcessNode {
|
||||
public:
|
||||
NonBlockingProcessNode(
|
||||
AbstractProcess* process);
|
||||
virtual ~NonBlockingProcessNode();
|
||||
|
||||
virtual status_t StartProcess();
|
||||
virtual status_t StopProcess();
|
||||
};
|
||||
|
||||
|
||||
#endif // NON_BLOCKING_PROCESS_NODE_H
|
@ -142,7 +142,7 @@ ProcessCoordinator::Start()
|
||||
|
||||
|
||||
void
|
||||
ProcessCoordinator::Stop()
|
||||
ProcessCoordinator::RequestStop()
|
||||
{
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
if (!fWasStopped) {
|
||||
@ -150,20 +150,11 @@ ProcessCoordinator::Stop()
|
||||
HDINFO("[Coordinator] will stop process coordinator");
|
||||
for (int32 i = 0; i < fNodes.CountItems(); i++) {
|
||||
AbstractProcessNode* node = fNodes.ItemAt(i);
|
||||
if (node->Process()->ErrorStatus() != B_OK) {
|
||||
HDINFO("[Coordinator] stopping process [%s] (owing to error)",
|
||||
node->Process()->Name());
|
||||
} else {
|
||||
HDINFO("[Coordinator] stopping process [%s]",
|
||||
node->Process()->Name());
|
||||
}
|
||||
node->StopProcess();
|
||||
HDINFO("[Coordinator] stopping process [%s]",
|
||||
node->Process()->Name());
|
||||
node->RequestStop();
|
||||
}
|
||||
}
|
||||
if (fListener != NULL) {
|
||||
ProcessCoordinatorState state = _CreateStatus();
|
||||
fListener->CoordinatorChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -307,7 +298,7 @@ ProcessCoordinator::_Coordinate()
|
||||
|
||||
if (node->Process()->ProcessState() == PROCESS_INITIAL) {
|
||||
if (node->AllPredecessorsComplete())
|
||||
node->StartProcess();
|
||||
node->Start();
|
||||
else {
|
||||
HDTRACE("[Coordinator] all predecessors not complete -> "
|
||||
"[%s] not started", node->Process()->Name());
|
||||
@ -349,7 +340,7 @@ ProcessCoordinator::_StopSuccessorNodes(AbstractProcessNode* predecessorNode)
|
||||
if (process->ProcessState() == PROCESS_INITIAL) {
|
||||
HDDEBUG("[Coordinator] [%s] (failed) --> [%s] (stopping)",
|
||||
predecessorNode->Process()->Name(), process->Name());
|
||||
node->StopProcess();
|
||||
node->RequestStop();
|
||||
_StopSuccessorNodes(node);
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ public:
|
||||
bool IsRunning();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
void RequestStop();
|
||||
|
||||
status_t ErrorStatus();
|
||||
|
||||
|
@ -173,7 +173,8 @@ ProcessCoordinatorFactory::_CreateInstallPackageActionCoordinator(
|
||||
PackageInfoRef package = _ExtractPackageFromMessage(model, message);
|
||||
if (package.IsSet()) {
|
||||
AbstractProcessNode *processNode =
|
||||
new ThreadedProcessNode(new InstallPackageProcess(package, model));
|
||||
new ThreadedProcessNode(
|
||||
new InstallPackageProcess(package, model), 10);
|
||||
processCoordinator->AddNode(processNode);
|
||||
} else {
|
||||
HDERROR("unable to find the package");
|
||||
@ -191,8 +192,8 @@ ProcessCoordinatorFactory::_CreateUninstallPackageActionCoordinator(
|
||||
PackageInfoRef package = _ExtractPackageFromMessage(model, message);
|
||||
if (package.IsSet()) {
|
||||
AbstractProcessNode *processNode =
|
||||
new ThreadedProcessNode(new UninstallPackageProcess(
|
||||
package, model));
|
||||
new ThreadedProcessNode(
|
||||
new UninstallPackageProcess(package, model), 10);
|
||||
processCoordinator->AddNode(processNode);
|
||||
} else {
|
||||
HDERROR("unable to find the package");
|
||||
|
@ -12,15 +12,25 @@
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
#define TIMEOUT_UNTIL_STARTED_SECS 10
|
||||
#define TIMEOUT_UNTIL_STOPPED_SECS 10
|
||||
#define TIMEOUT_UNTIL_STARTED_SECS_DEFAULT 10
|
||||
#define TIMEOUT_UNTIL_STOPPED_SECS_DEFAULT 10
|
||||
|
||||
|
||||
ThreadedProcessNode::ThreadedProcessNode(AbstractProcess* process,
|
||||
int32 startTimeoutSeconds)
|
||||
:
|
||||
AbstractProcessNode(process),
|
||||
fWorker(B_BAD_THREAD_ID),
|
||||
fStartTimeoutSeconds(startTimeoutSeconds)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ThreadedProcessNode::ThreadedProcessNode(AbstractProcess* process)
|
||||
:
|
||||
AbstractProcessNode(process),
|
||||
fWorker(B_BAD_THREAD_ID)
|
||||
|
||||
fWorker(B_BAD_THREAD_ID),
|
||||
fStartTimeoutSeconds(TIMEOUT_UNTIL_STARTED_SECS_DEFAULT)
|
||||
{
|
||||
}
|
||||
|
||||
@ -34,7 +44,7 @@ ThreadedProcessNode::~ThreadedProcessNode()
|
||||
*/
|
||||
|
||||
status_t
|
||||
ThreadedProcessNode::StartProcess()
|
||||
ThreadedProcessNode::Start()
|
||||
{
|
||||
if (fWorker != B_BAD_THREAD_ID)
|
||||
return B_BUSY;
|
||||
@ -47,40 +57,17 @@ ThreadedProcessNode::StartProcess()
|
||||
if (fWorker >= 0) {
|
||||
resume_thread(fWorker);
|
||||
return _SpinUntilProcessState(PROCESS_RUNNING | PROCESS_COMPLETE,
|
||||
TIMEOUT_UNTIL_STARTED_SECS);
|
||||
fStartTimeoutSeconds);
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*! Considered to be protected from concurrent access by the ProcessCoordinator
|
||||
*/
|
||||
|
||||
status_t
|
||||
ThreadedProcessNode::StopProcess()
|
||||
ThreadedProcessNode::RequestStop()
|
||||
{
|
||||
Process()->SetListener(NULL);
|
||||
status_t stopResult = Process()->Stop();
|
||||
status_t waitResult = _SpinUntilProcessState(PROCESS_COMPLETE,
|
||||
TIMEOUT_UNTIL_STOPPED_SECS);
|
||||
|
||||
// if the thread is still running then it will be necessary to tear it
|
||||
// down.
|
||||
|
||||
if (waitResult != B_OK) {
|
||||
HDINFO("[%s] process did not stop within timeout - will be stopped "
|
||||
"uncleanly", Process()->Name());
|
||||
kill_thread(fWorker);
|
||||
}
|
||||
|
||||
if (stopResult != B_OK)
|
||||
return stopResult;
|
||||
|
||||
if (waitResult != B_OK)
|
||||
return waitResult;
|
||||
|
||||
return B_OK;
|
||||
return Process()->Stop();
|
||||
}
|
||||
|
||||
|
||||
|
@ -14,16 +14,19 @@ class AbstractProcess;
|
||||
|
||||
class ThreadedProcessNode : public AbstractProcessNode {
|
||||
public:
|
||||
ThreadedProcessNode(AbstractProcess* process,
|
||||
int32 startTimeoutSeconds);
|
||||
ThreadedProcessNode(AbstractProcess* process);
|
||||
virtual ~ThreadedProcessNode();
|
||||
|
||||
virtual status_t StartProcess();
|
||||
virtual status_t StopProcess();
|
||||
virtual status_t Start();
|
||||
virtual status_t RequestStop();
|
||||
|
||||
private:
|
||||
static status_t _StartProcess(void* cookie);
|
||||
|
||||
thread_id fWorker;
|
||||
int32 fStartTimeoutSeconds;
|
||||
};
|
||||
|
||||
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "support.h"
|
||||
#include "ScreenshotWindow.h"
|
||||
#include "SettingsWindow.h"
|
||||
#include "ShuttingDownWindow.h"
|
||||
#include "ToLatestUserUsageConditionsWindow.h"
|
||||
#include "UserLoginWindow.h"
|
||||
#include "UserUsageConditionsWindow.h"
|
||||
@ -133,12 +134,14 @@ MainWindow::MainWindow(const BMessage& settings)
|
||||
B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
|
||||
B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
|
||||
fScreenshotWindow(NULL),
|
||||
fShuttingDownWindow(NULL),
|
||||
fUserMenu(NULL),
|
||||
fLogInItem(NULL),
|
||||
fLogOutItem(NULL),
|
||||
fUsersUserUsageConditionsMenuItem(NULL),
|
||||
fModelListener(new MainWindowModelListener(BMessenger(this)), true),
|
||||
fCoordinator(NULL),
|
||||
fShouldCloseWhenNoProcessesToCoordinate(false),
|
||||
fSinglePackageMode(false)
|
||||
{
|
||||
if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK)
|
||||
@ -226,12 +229,14 @@ MainWindow::MainWindow(const BMessage& settings, const PackageInfoRef& package)
|
||||
fPackageListView(NULL),
|
||||
fWorkStatusView(NULL),
|
||||
fScreenshotWindow(NULL),
|
||||
fShuttingDownWindow(NULL),
|
||||
fUserMenu(NULL),
|
||||
fLogInItem(NULL),
|
||||
fLogOutItem(NULL),
|
||||
fUsersUserUsageConditionsMenuItem(NULL),
|
||||
fModelListener(new MainWindowModelListener(BMessenger(this)), true),
|
||||
fCoordinator(NULL),
|
||||
fShouldCloseWhenNoProcessesToCoordinate(false),
|
||||
fSinglePackageMode(true)
|
||||
{
|
||||
if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK)
|
||||
@ -268,24 +273,57 @@ MainWindow::~MainWindow()
|
||||
|
||||
BPackageRoster().StopWatching(this);
|
||||
|
||||
if (fScreenshotWindow != NULL && fScreenshotWindow->Lock())
|
||||
fScreenshotWindow->Quit();
|
||||
if (fScreenshotWindow != NULL) {
|
||||
if (fScreenshotWindow->Lock())
|
||||
fScreenshotWindow->Quit();
|
||||
}
|
||||
|
||||
if (fShuttingDownWindow != NULL) {
|
||||
if (fShuttingDownWindow->Lock())
|
||||
fShuttingDownWindow->Quit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MainWindow::QuitRequested()
|
||||
{
|
||||
BMessage settings;
|
||||
StoreSettings(settings);
|
||||
|
||||
BMessage message(MSG_MAIN_WINDOW_CLOSED);
|
||||
message.AddMessage(KEY_WINDOW_SETTINGS, &settings);
|
||||
|
||||
be_app->PostMessage(&message);
|
||||
|
||||
_StopProcessCoordinators();
|
||||
|
||||
// If there are any processes in flight we need to be careful to make
|
||||
// sure that they are cleanly completed before actually quitting. By
|
||||
// turning on the `fShouldCloseWhenNoProcessesToCoordinate` flag, when
|
||||
// the process coordination has completed then it will detect this and
|
||||
// quit again.
|
||||
|
||||
{
|
||||
AutoLocker<BLocker> lock(&fCoordinatorLock);
|
||||
fShouldCloseWhenNoProcessesToCoordinate = true;
|
||||
|
||||
if (fCoordinator.IsSet()) {
|
||||
HDINFO("a coordinator is running --> will wait before quitting...");
|
||||
|
||||
if (fShuttingDownWindow == NULL)
|
||||
fShuttingDownWindow = new ShuttingDownWindow(this);
|
||||
fShuttingDownWindow->Show();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
BMessage settings;
|
||||
StoreSettings(settings);
|
||||
BMessage message(MSG_MAIN_WINDOW_CLOSED);
|
||||
message.AddMessage(KEY_WINDOW_SETTINGS, &settings);
|
||||
be_app->PostMessage(&message);
|
||||
|
||||
if (fShuttingDownWindow != NULL) {
|
||||
if (fShuttingDownWindow->Lock())
|
||||
fShuttingDownWindow->Quit();
|
||||
fShuttingDownWindow = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1367,6 +1405,13 @@ MainWindow::_AddProcessCoordinator(ProcessCoordinator* item)
|
||||
{
|
||||
AutoLocker<BLocker> lock(&fCoordinatorLock);
|
||||
|
||||
if (fShouldCloseWhenNoProcessesToCoordinate) {
|
||||
HDINFO("system shutting down --> new process coordinator [%s] rejected",
|
||||
item->Name().String());
|
||||
delete item;
|
||||
return;
|
||||
}
|
||||
|
||||
item->SetListener(this);
|
||||
|
||||
if (!fCoordinator.IsSet()) {
|
||||
@ -1405,29 +1450,19 @@ MainWindow::_SpinUntilProcessCoordinatorComplete()
|
||||
void
|
||||
MainWindow::_StopProcessCoordinators()
|
||||
{
|
||||
HDINFO("will stop all process coordinators");
|
||||
HDINFO("will stop all queued process coordinators");
|
||||
AutoLocker<BLocker> lock(&fCoordinatorLock);
|
||||
|
||||
{
|
||||
AutoLocker<BLocker> lock(&fCoordinatorLock);
|
||||
|
||||
while (!fCoordinatorQueue.empty()) {
|
||||
BReference<ProcessCoordinator> processCoordinator
|
||||
= fCoordinatorQueue.front();
|
||||
HDINFO("will drop queued process coordinator [%s]",
|
||||
processCoordinator->Name().String());
|
||||
fCoordinatorQueue.pop();
|
||||
}
|
||||
|
||||
if (fCoordinator.IsSet()) {
|
||||
fCoordinator->Stop();
|
||||
}
|
||||
while (!fCoordinatorQueue.empty()) {
|
||||
BReference<ProcessCoordinator> processCoordinator
|
||||
= fCoordinatorQueue.front();
|
||||
HDINFO("will drop queued process coordinator [%s]",
|
||||
processCoordinator->Name().String());
|
||||
fCoordinatorQueue.pop();
|
||||
}
|
||||
|
||||
HDINFO("will wait until the process coordinator has stopped");
|
||||
|
||||
_SpinUntilProcessCoordinatorComplete();
|
||||
|
||||
HDINFO("did stop all process coordinators");
|
||||
if (fCoordinator.IsSet())
|
||||
fCoordinator->RequestStop();
|
||||
}
|
||||
|
||||
|
||||
@ -1474,6 +1509,11 @@ MainWindow::CoordinatorChanged(ProcessCoordinatorState& coordinatorState)
|
||||
}
|
||||
else {
|
||||
_NotifyWorkStatusClear();
|
||||
if (fShouldCloseWhenNoProcessesToCoordinate) {
|
||||
HDINFO("no more processes to coord --> will quit");
|
||||
BMessage message(B_QUIT_REQUESTED);
|
||||
PostMessage(&message);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1481,8 +1521,10 @@ MainWindow::CoordinatorChanged(ProcessCoordinatorState& coordinatorState)
|
||||
coordinatorState.Progress());
|
||||
// show the progress to the user.
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
_NotifyWorkStatusClear();
|
||||
HDINFO("! unknown process coordinator changed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -31,6 +31,7 @@ class PackageActionsView;
|
||||
class PackageInfoView;
|
||||
class PackageListView;
|
||||
class ScreenshotWindow;
|
||||
class ShuttingDownWindow;
|
||||
class WorkStatusView;
|
||||
|
||||
|
||||
@ -146,6 +147,7 @@ private:
|
||||
WorkStatusView* fWorkStatusView;
|
||||
|
||||
ScreenshotWindow* fScreenshotWindow;
|
||||
ShuttingDownWindow* fShuttingDownWindow;
|
||||
|
||||
BMenu* fUserMenu;
|
||||
BMenu* fRepositoryMenu;
|
||||
@ -169,6 +171,7 @@ private:
|
||||
fCoordinator;
|
||||
BLocker fCoordinatorLock;
|
||||
sem_id fCoordinatorRunningSem;
|
||||
bool fShouldCloseWhenNoProcessesToCoordinate;
|
||||
|
||||
bool fSinglePackageMode;
|
||||
|
||||
|
47
src/apps/haikudepot/ui/ShuttingDownWindow.cpp
Normal file
47
src/apps/haikudepot/ui/ShuttingDownWindow.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "ShuttingDownWindow.h"
|
||||
|
||||
#include <Catalog.h>
|
||||
#include <LayoutBuilder.h>
|
||||
#include <Locker.h>
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "ShuttingDownWindow"
|
||||
|
||||
#define WINDOW_FRAME BRect(0, 0, 240, 120)
|
||||
|
||||
|
||||
ShuttingDownWindow::ShuttingDownWindow(BWindow* parent)
|
||||
:
|
||||
BWindow(WINDOW_FRAME, B_TRANSLATE("Shutting Down"),
|
||||
B_FLOATING_WINDOW_LOOK, B_MODAL_SUBSET_WINDOW_FEEL,
|
||||
B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS
|
||||
| B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_NOT_CLOSABLE )
|
||||
{
|
||||
AddToSubset(parent);
|
||||
|
||||
BTextView* textView = new BTextView("shutting down message");
|
||||
textView->AdoptSystemColors();
|
||||
textView->MakeEditable(false);
|
||||
textView->MakeSelectable(false);
|
||||
textView->SetText(B_TRANSLATE("Haiku Depot is stopping or completing "
|
||||
"running operations before shutting down."));
|
||||
|
||||
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
|
||||
.SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
|
||||
B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING)
|
||||
.Add(textView)
|
||||
.End();
|
||||
|
||||
CenterOnScreen();
|
||||
}
|
||||
|
||||
|
||||
ShuttingDownWindow::~ShuttingDownWindow()
|
||||
{
|
||||
}
|
||||
|
30
src/apps/haikudepot/ui/ShuttingDownWindow.h
Normal file
30
src/apps/haikudepot/ui/ShuttingDownWindow.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef SHUTTING_DOWN_WINDOW_H
|
||||
#define SHUTTING_DOWN_WINDOW_H
|
||||
|
||||
#include <Locker.h>
|
||||
#include <Messenger.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "BarberPole.h"
|
||||
#include "HaikuDepotConstants.h"
|
||||
#include "UserDetail.h"
|
||||
#include "UserUsageConditions.h"
|
||||
|
||||
|
||||
class BButton;
|
||||
class BCheckBox;
|
||||
class Model;
|
||||
|
||||
|
||||
class ShuttingDownWindow : public BWindow {
|
||||
public:
|
||||
ShuttingDownWindow(BWindow* parent);
|
||||
virtual ~ShuttingDownWindow();
|
||||
};
|
||||
|
||||
|
||||
#endif // SHUTTING_DOWN_WINDOW_H
|
@ -15,6 +15,8 @@
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
// #pragma mark - MachineRoom
|
||||
|
||||
@ -78,6 +80,7 @@ private:
|
||||
|
||||
BMessenger* messenger = new BMessenger(pole);
|
||||
fMessengers.AddItem(messenger);
|
||||
HDTRACE("did add barber-pole to machine room");
|
||||
|
||||
if (wasEmpty)
|
||||
release_sem(fSpinLoopLock);
|
||||
@ -91,6 +94,7 @@ private:
|
||||
BMessenger* messenger = fMessengers.ItemAt(i);
|
||||
if (messenger->Target(NULL) == pole) {
|
||||
fMessengers.RemoveItem(messenger, true);
|
||||
HDTRACE("did remove barber-pole from machine room");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -417,6 +417,7 @@ BHttpRequest::Result() const
|
||||
status_t
|
||||
BHttpRequest::Stop()
|
||||
{
|
||||
|
||||
if (fSocket != NULL) {
|
||||
fSocket->Disconnect();
|
||||
// Unlock any pending connect, read or write operation.
|
||||
|
Loading…
x
Reference in New Issue
Block a user