summaryrefslogtreecommitdiffstats
path: root/xbmc/dialogs/GUIDialogBusy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/dialogs/GUIDialogBusy.cpp')
-rw-r--r--xbmc/dialogs/GUIDialogBusy.cpp147
1 files changed, 147 insertions, 0 deletions
diff --git a/xbmc/dialogs/GUIDialogBusy.cpp b/xbmc/dialogs/GUIDialogBusy.cpp
new file mode 100644
index 0000000..e53f1fc
--- /dev/null
+++ b/xbmc/dialogs/GUIDialogBusy.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "GUIDialogBusy.h"
+
+#include "ServiceBroker.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "threads/IRunnable.h"
+#include "threads/Thread.h"
+#include "utils/log.h"
+
+using namespace std::chrono_literals;
+
+class CBusyWaiter : public CThread
+{
+ std::shared_ptr<CEvent> m_done;
+ IRunnable *m_runnable;
+public:
+ explicit CBusyWaiter(IRunnable *runnable) :
+ CThread(runnable, "waiting"), m_done(new CEvent()), m_runnable(runnable) { }
+
+ ~CBusyWaiter() override { StopThread(); }
+
+ bool Wait(unsigned int displaytime, bool allowCancel)
+ {
+ std::shared_ptr<CEvent> e_done(m_done);
+
+ Create();
+ auto start = std::chrono::steady_clock::now();
+ if (!CGUIDialogBusy::WaitOnEvent(*e_done, displaytime, allowCancel))
+ {
+ m_runnable->Cancel();
+
+ auto end = std::chrono::steady_clock::now();
+ auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
+
+ unsigned int remaining =
+ (duration.count() >= displaytime) ? 0 : displaytime - duration.count();
+ CGUIDialogBusy::WaitOnEvent(*e_done, remaining, false);
+ return false;
+ }
+ return true;
+ }
+
+ // 'this' is actually deleted from the thread where it's on the stack
+ void Process() override
+ {
+ std::shared_ptr<CEvent> e_done(m_done);
+
+ CThread::Process();
+ (*e_done).Set();
+ }
+
+};
+
+bool CGUIDialogBusy::Wait(IRunnable *runnable, unsigned int displaytime, bool allowCancel)
+{
+ if (!runnable)
+ return false;
+ CBusyWaiter waiter(runnable);
+ if (!waiter.Wait(displaytime, allowCancel))
+ {
+ return false;
+ }
+ return true;
+}
+
+bool CGUIDialogBusy::WaitOnEvent(CEvent &event, unsigned int displaytime /* = 100 */, bool allowCancel /* = true */)
+{
+ bool cancelled = false;
+ if (!event.Wait(std::chrono::milliseconds(displaytime)))
+ {
+ // throw up the progress
+ CGUIDialogBusy* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogBusy>(WINDOW_DIALOG_BUSY);
+ if (dialog)
+ {
+ if (dialog->IsDialogRunning())
+ {
+ CLog::Log(LOGFATAL, "Logic error due to two concurrent busydialogs, this is a known issue. "
+ "The application will exit.");
+ throw std::logic_error("busy dialog already running");
+ }
+
+ dialog->Open();
+
+ while (!event.Wait(1ms))
+ {
+ dialog->ProcessRenderLoop(false);
+ if (allowCancel && dialog->IsCanceled())
+ {
+ cancelled = true;
+ break;
+ }
+ }
+
+ dialog->Close(true);
+ }
+ }
+ return !cancelled;
+}
+
+CGUIDialogBusy::CGUIDialogBusy(void)
+ : CGUIDialog(WINDOW_DIALOG_BUSY, "DialogBusy.xml", DialogModalityType::MODAL)
+{
+ m_loadType = LOAD_ON_GUI_INIT;
+ m_bCanceled = false;
+}
+
+CGUIDialogBusy::~CGUIDialogBusy(void) = default;
+
+void CGUIDialogBusy::Open_Internal(bool bProcessRenderLoop, const std::string& param /* = "" */)
+{
+ m_bCanceled = false;
+ m_bLastVisible = true;
+
+ CGUIDialog::Open_Internal(false, param);
+}
+
+
+void CGUIDialogBusy::DoProcess(unsigned int currentTime, CDirtyRegionList &dirtyregions)
+{
+ bool visible = CServiceBroker::GetGUI()->GetWindowManager().IsModalDialogTopmost(WINDOW_DIALOG_BUSY);
+ if(!visible && m_bLastVisible)
+ dirtyregions.push_back(CDirtyRegion(m_renderRegion));
+ m_bLastVisible = visible;
+
+ CGUIDialog::DoProcess(currentTime, dirtyregions);
+}
+
+void CGUIDialogBusy::Render()
+{
+ if(!m_bLastVisible)
+ return;
+ CGUIDialog::Render();
+}
+
+bool CGUIDialogBusy::OnBack(int actionID)
+{
+ m_bCanceled = true;
+ return true;
+}