2008-12-01 08:04:43 +01:00
|
|
|
/*
|
|
|
|
|
GuiFacade - access point for communicating with the Lumiera GTK GUI
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2008-12-01 08:04:43 +01:00
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2008-12-01 08:04:43 +01:00
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
2010-12-17 23:28:49 +01:00
|
|
|
published by the Free Software Foundation; either version 2 of
|
|
|
|
|
the License, or (at your option) any later version.
|
|
|
|
|
|
2008-12-01 08:04:43 +01:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2008-12-01 08:04:43 +01:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2008-12-01 08:04:43 +01:00
|
|
|
* *****************************************************/
|
|
|
|
|
|
|
|
|
|
|
2016-11-03 18:22:31 +01:00
|
|
|
/** @file guifacade.cpp
|
2016-11-06 14:19:14 +01:00
|
|
|
** Implementation of the GUI loader. Code generated from this
|
|
|
|
|
** translation unit is linked into the core application, where it implements
|
2018-09-21 13:46:42 +02:00
|
|
|
** the [Subsystem descriptor](\ref subsys.hpp) for the _UI Subsystem._ When main()
|
2016-11-06 14:19:14 +01:00
|
|
|
** activates and starts this subsystem, an instance of gui::GuiRunner will be
|
|
|
|
|
** created, which causes the Lumiera UI plug-in to be loaded and a new thread
|
|
|
|
|
** to be spawned, which launches the UI and performs the event loop.
|
2016-11-03 18:20:10 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
2018-11-15 23:42:43 +01:00
|
|
|
#include "stage/guifacade.hpp"
|
2016-12-12 02:10:52 +01:00
|
|
|
#include "include/gui-notification-facade.h"
|
2008-12-28 05:20:35 +01:00
|
|
|
#include "lib/sync.hpp"
|
2008-12-27 00:53:35 +01:00
|
|
|
#include "lib/error.hpp"
|
2013-10-20 03:19:36 +02:00
|
|
|
#include "lib/depend.hpp"
|
2009-07-20 04:21:24 +02:00
|
|
|
#include "lib/functor-util.hpp"
|
2008-12-18 08:12:40 +01:00
|
|
|
#include "common/instancehandle.hpp"
|
2017-01-27 23:46:55 +01:00
|
|
|
#include "common/option.hpp"
|
2008-12-01 08:04:43 +01:00
|
|
|
|
2017-01-05 00:56:46 +01:00
|
|
|
#include <memory>
|
2008-12-04 04:21:02 +01:00
|
|
|
#include <string>
|
2008-12-01 08:04:43 +01:00
|
|
|
|
|
|
|
|
|
2008-12-04 04:21:02 +01:00
|
|
|
namespace gui {
|
|
|
|
|
|
|
|
|
|
using std::string;
|
2017-01-05 00:56:46 +01:00
|
|
|
using std::unique_ptr;
|
2008-12-06 22:01:44 +01:00
|
|
|
using lumiera::Subsys;
|
2008-12-07 05:36:02 +01:00
|
|
|
using lumiera::InstanceHandle;
|
2008-12-28 05:20:35 +01:00
|
|
|
using lib::Sync;
|
2008-12-29 06:07:28 +01:00
|
|
|
using lib::RecursiveLock_NoWait;
|
2008-12-08 05:20:14 +01:00
|
|
|
|
2008-12-01 08:04:43 +01:00
|
|
|
|
2008-12-06 22:01:44 +01:00
|
|
|
|
2010-02-13 17:41:16 +01:00
|
|
|
/** load and start the GUI as a plugin */
|
2008-12-06 22:01:44 +01:00
|
|
|
struct GuiRunner
|
2018-03-24 05:35:13 +01:00
|
|
|
: util::NonCopyable
|
2008-12-01 08:04:43 +01:00
|
|
|
{
|
2008-12-07 05:36:02 +01:00
|
|
|
typedef InstanceHandle<LUMIERA_INTERFACE_INAME(lumieraorg_Gui, 1)> GuiHandle;
|
2008-12-06 22:01:44 +01:00
|
|
|
|
|
|
|
|
GuiHandle theGUI_;
|
2008-12-01 08:04:43 +01:00
|
|
|
|
|
|
|
|
|
2008-12-07 08:46:44 +01:00
|
|
|
GuiRunner (Subsys::SigTerm terminationHandle)
|
|
|
|
|
: theGUI_("lumieraorg_Gui", 1, 1, "lumieraorg_GuiStarterPlugin") // load GuiStarterPlugin
|
2008-12-01 08:04:43 +01:00
|
|
|
{
|
2008-12-07 05:36:02 +01:00
|
|
|
ASSERT (theGUI_);
|
2016-12-12 01:46:03 +01:00
|
|
|
bool res = this->launchUI (terminationHandle);
|
2009-01-03 16:05:04 +01:00
|
|
|
|
2009-01-15 15:16:45 +01:00
|
|
|
if (!res || lumiera_error_peek())
|
2017-05-19 18:12:58 +02:00
|
|
|
throw lumiera::error::Fatal{"failed to bring up the GUI", lumiera_error()};
|
2008-12-01 08:04:43 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-07 08:46:44 +01:00
|
|
|
|
2017-08-03 23:11:01 +02:00
|
|
|
/* ===== control interface for the GuiStarterPlugin ======= */
|
|
|
|
|
|
|
|
|
|
/** start the actual GUI thread(s), after successfully loading
|
|
|
|
|
* the GuiStarterPlugin, that is. The implementation of this function
|
|
|
|
|
* must ensure to invoke the given termination signal reliably after
|
|
|
|
|
* shutting down the GUI, otherwise the application will hang on exit.
|
|
|
|
|
* @internal this function is invoked automatically during the GUI
|
|
|
|
|
* loading and startup process. Don't call it manually.
|
|
|
|
|
*/
|
|
|
|
|
bool launchUI (Subsys::SigTerm& terminationHandle)
|
2008-12-07 08:46:44 +01:00
|
|
|
{
|
2016-12-12 01:46:03 +01:00
|
|
|
return theGUI_->launchUI (reinterpret_cast<void*> (&terminationHandle));
|
2008-12-01 08:04:43 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2008-12-06 22:01:44 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-02-13 17:41:16 +01:00
|
|
|
namespace { // implementation of GUI-"Subsystem" : start GUI through GuiStarterPlugin
|
2008-12-06 22:01:44 +01:00
|
|
|
|
2017-01-05 00:56:46 +01:00
|
|
|
unique_ptr<GuiRunner> facade;
|
2008-12-06 22:01:44 +01:00
|
|
|
|
2009-01-03 16:05:04 +01:00
|
|
|
|
2008-12-06 22:01:44 +01:00
|
|
|
class GuiSubsysDescriptor
|
2008-12-28 05:20:35 +01:00
|
|
|
: public lumiera::Subsys,
|
2008-12-29 06:07:28 +01:00
|
|
|
public Sync<RecursiveLock_NoWait>
|
2008-12-06 22:01:44 +01:00
|
|
|
{
|
2017-05-19 18:12:58 +02:00
|
|
|
operator string() const { return "Lumiera GTK GUI"; }
|
2008-12-06 22:01:44 +01:00
|
|
|
|
|
|
|
|
bool
|
2016-12-12 01:18:19 +01:00
|
|
|
shouldStart (lumiera::Option& opts) override
|
2008-12-06 22:01:44 +01:00
|
|
|
{
|
2016-12-13 02:44:37 +01:00
|
|
|
if (opts.isHeadless() or 0 < opts.getPort())
|
2008-12-08 03:01:02 +01:00
|
|
|
{
|
2009-01-24 03:13:08 +01:00
|
|
|
INFO (guifacade, "*not* starting the GUI...");
|
2008-12-08 03:01:02 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return true;
|
2008-12-06 22:01:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2017-01-19 03:49:25 +01:00
|
|
|
start (lumiera::Option&, Subsys::SigTerm termNotification) override
|
2008-12-06 22:01:44 +01:00
|
|
|
{
|
2008-12-28 05:20:35 +01:00
|
|
|
Lock guard (this);
|
2017-01-19 03:49:25 +01:00
|
|
|
if (facade)
|
|
|
|
|
return false; // already started
|
|
|
|
|
|
2017-05-19 18:12:58 +02:00
|
|
|
facade.reset ( // trigger loading of the GuiStarterPlugin...
|
2017-01-19 03:49:25 +01:00
|
|
|
new GuiRunner (
|
|
|
|
|
[=] (string* problemMessage)
|
2017-05-19 18:12:58 +02:00
|
|
|
{ // will be invoked when the UI thread exits
|
2017-01-19 03:49:25 +01:00
|
|
|
closeGuiModule();
|
|
|
|
|
termNotification(problemMessage);
|
|
|
|
|
}));
|
2008-12-08 03:01:02 +01:00
|
|
|
|
2008-12-07 08:46:44 +01:00
|
|
|
return true;
|
2008-12-06 22:01:44 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-12 01:49:11 +01:00
|
|
|
/**
|
|
|
|
|
* @warning there is a possible race here,
|
|
|
|
|
* when shutdown is triggered before the GUI was able to open the GuiNotification interface.
|
|
|
|
|
* However, the Lumiera thread handling wrapper/framework ensures that a new thread actually
|
|
|
|
|
* starts to execute (and picks up the arguments), prior to returning from the thread starting
|
|
|
|
|
* function. For this reason, it is rather unlikely this race actually happens in practice,
|
2016-12-15 20:48:35 +01:00
|
|
|
* since opening the GuiNotification interface is done early, while starting the UI-Bus.
|
2016-12-12 01:49:11 +01:00
|
|
|
*/
|
2008-12-06 22:01:44 +01:00
|
|
|
void
|
2016-12-12 01:18:19 +01:00
|
|
|
triggerShutdown () noexcept override
|
2008-12-06 22:01:44 +01:00
|
|
|
{
|
2008-12-07 08:46:44 +01:00
|
|
|
try { GuiNotification::facade().triggerGuiShutdown ("Application shutdown"); }
|
|
|
|
|
|
2016-12-12 01:18:19 +01:00
|
|
|
ERROR_LOG_AND_IGNORE (guifacade, "trigger shutdown of the GUI");
|
2008-12-06 22:01:44 +01:00
|
|
|
}
|
|
|
|
|
|
2018-10-08 05:00:06 +02:00
|
|
|
bool
|
2016-12-12 01:18:19 +01:00
|
|
|
checkRunningState () noexcept override
|
2008-12-08 03:01:02 +01:00
|
|
|
{
|
2014-04-29 09:51:00 +02:00
|
|
|
return bool(facade);
|
2008-12-08 03:01:02 +01:00
|
|
|
}
|
|
|
|
|
|
2009-01-03 16:05:04 +01:00
|
|
|
|
2008-12-08 03:01:02 +01:00
|
|
|
void
|
2017-01-19 03:49:25 +01:00
|
|
|
closeGuiModule ()
|
2008-12-08 03:01:02 +01:00
|
|
|
{
|
2008-12-28 05:20:35 +01:00
|
|
|
Lock guard (this);
|
2008-12-08 03:01:02 +01:00
|
|
|
if (!facade)
|
|
|
|
|
{
|
2009-01-24 03:13:08 +01:00
|
|
|
WARN (guifacade, "Termination signal invoked, but GUI is currently closed. "
|
|
|
|
|
"Probably this is due to some broken startup logic and should be fixed.");
|
2008-12-08 03:01:02 +01:00
|
|
|
}
|
|
|
|
|
else
|
2017-05-19 18:12:58 +02:00
|
|
|
facade.reset (nullptr);
|
2008-12-08 03:01:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
2017-01-19 03:49:25 +01:00
|
|
|
GuiSubsysDescriptor() { }
|
2008-12-08 03:01:02 +01:00
|
|
|
|
2017-01-19 03:49:25 +01:00
|
|
|
~GuiSubsysDescriptor()
|
2008-12-13 21:10:23 +01:00
|
|
|
{
|
|
|
|
|
if (facade)
|
|
|
|
|
{
|
2009-01-24 03:13:08 +01:00
|
|
|
WARN (guifacade, "GUI subsystem terminates, but GuiFacade isn't properly closed. "
|
2011-06-14 05:41:02 +02:00
|
|
|
"Closing it forcedly; this indicates broken startup logic and should be fixed.");
|
2008-12-13 21:10:23 +01:00
|
|
|
try { facade.reset (0); }
|
2016-12-12 01:18:19 +01:00
|
|
|
ERROR_LOG_AND_IGNORE (guifacade, "forcibly closing the GUI");
|
|
|
|
|
ENSURE (not lumiera_error_peek());
|
2008-12-13 21:10:23 +01:00
|
|
|
}
|
|
|
|
|
}
|
2008-12-06 22:01:44 +01:00
|
|
|
};
|
|
|
|
|
|
2013-10-20 03:19:36 +02:00
|
|
|
lib::Depend<GuiSubsysDescriptor> theDescriptor;
|
2008-12-06 22:01:44 +01:00
|
|
|
|
|
|
|
|
} // (End) impl details
|
2008-12-01 08:04:43 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-12-07 08:46:44 +01:00
|
|
|
|
|
|
|
|
|
2008-12-01 08:04:43 +01:00
|
|
|
/** @internal intended for use by main(). */
|
2008-12-05 11:07:01 +01:00
|
|
|
lumiera::Subsys&
|
2008-12-01 08:04:43 +01:00
|
|
|
GuiFacade::getDescriptor()
|
|
|
|
|
{
|
|
|
|
|
return theDescriptor();
|
|
|
|
|
}
|
2008-12-06 22:01:44 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
GuiFacade::isUp ()
|
|
|
|
|
{
|
2014-04-29 09:51:00 +02:00
|
|
|
return bool(facade);
|
2008-12-06 22:01:44 +01:00
|
|
|
}
|
2018-10-08 05:00:06 +02:00
|
|
|
|
|
|
|
|
|
2008-12-01 08:04:43 +01:00
|
|
|
} // namespace gui
|