Guistart(#1045): relocate opening of GuiNotification into the CoreServices

up to now this happened from the GuiRunner, which was a rather bad idea
- it can throw and thus interfer with the startup process
- the GuiNotification can not sensibly be *implemented* just backed
  by the GuiRunner. While CoreService offers access to the necessary
  implementation facilities to do so
This commit is contained in:
Fischlurch 2016-12-12 01:49:11 +01:00
parent 5e9b3be985
commit b6e7caf737
5 changed files with 78 additions and 15 deletions

View file

@ -62,7 +62,7 @@ namespace backend {
* The new thread starts immediately within the ctor; after returning, the new
* thread has already copied the arguments and indeed actively started to run.
*
* \par Joining, cancellation and memory management
* # Joining, cancellation and memory management
* In the basic version (class Thread), the created thread is completely detached
* and not further controllable. There is no way to find out its execution state,
* wait on termination or even cancel it. Client code needs to implement such
@ -77,7 +77,7 @@ namespace backend {
* must join to prevent pulling away member variables the thread function will
* continue to use.
*
* \par failures in the thread function
* # failures in the thread function
* The operation started in the new thread is protected by a top-level catch block.
* Error states or caught exceptions can be propagated through the lumiera_error
* state flag, when using the \c join() facility. By invoking \join().maybeThrow()
@ -86,7 +86,7 @@ namespace backend {
* async Thread is considered a violation of policy and will result in emergency
* shutdown of the whole application.
*
* \par synchronisation barriers
* # synchronisation barriers
* Lumiera threads provide a low-level synchronisation mechanism, which is used
* to secure the hand-over of additional arguments to the thread function. It
* can be used by client code, but care has to be taken to avoid getting out

View file

@ -115,6 +115,14 @@ namespace gui {
return true;
}
/**
* @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,
* since opening the GuiNotification interface is done early, while starting the UI-Bus.
*/
void
triggerShutdown () noexcept override
{

View file

@ -53,6 +53,7 @@
#include "lib/error.hpp"
#include "include/logging.h"
//#include "lib/idi/entry-id.hpp"
#include "gui/notification-service.hpp"
#include "gui/ctrl/bus-term.hpp"
#include "gui/ctrl/nexus.hpp"
//#include "lib/util.hpp"
@ -89,6 +90,7 @@ namespace ctrl{
{
Nexus uiBusBackbone_;
NotificationService activateNotificationService_;
virtual void
act (GenNode const& command)
@ -109,6 +111,7 @@ namespace ctrl{
CoreService (ID identity =lib::idi::EntryID<CoreService>())
: BusTerm(identity, uiBusBackbone_)
, uiBusBackbone_{*this}
, activateNotificationService_() // opens the GuiNotification facade interface
{
INFO (gui, "UI-Backbone operative.");
}

View file

@ -30,15 +30,16 @@
** up the GUI. The loading and shutdown process is carried out by gui::GuiFacade and
** controlled by lumiera::AppState, which in turn is activated by Lumiera main().
**
** After successfully loading this module, a call to #kickOff is expected to be
** issued, passing a termination signal (callback) to be executed when the GUI
** terminates. The \c kickOff() call remains blocked within the main GTK event loop;
** thus typically this call should be issued within a separate dedicated GUI thread.
** Especially, the gui::GuiRunner will ensure this to happen.
** After successfully loading this module, a call to GuiFacade::launchUI is expected to
** happen, passing a termination signal (callback) to be executed when the GUI terminates.
** The implementation of GuiFacade in the GuiRunner in fact issues this call from the ctor
** body, while the interface is opened via an InstanceHandle member. The `launchUI()` call
** starts a new thread, which then becomes the UI event thread and remains blocked within
** the main GTK event loop. Before entering this loop, the CoreService of the GUI and
** especially the [UI-Bus](\ref ui-bus.hpp) is started see \ref GtkLumiera::run.
** This entails also to open the primary "business" interface(s) of the GUI
** (currently as of 1/16 this is the interface gui::GuiNotification.)
**
** Prior to entering the GTK event loop, all primary "business" interface of the GUI
** will be opened (currently as of 1/09 this is the interface gui::GuiNotification.)
**
** @see lumiera::AppState
** @see gui::GuiFacade
** @see guifacade.cpp
@ -54,7 +55,6 @@
#include "lib/error.hpp"
#include "gui/guifacade.hpp"
#include "gui/notification-service.hpp"
#include "gui/display-service.hpp"
#include "common/subsys.hpp"
#include "backend/thread-wrapper.hpp"
@ -85,17 +85,18 @@ namespace gui {
/**************************************************************************//**
* Implement the necessary steps for actually making the Lumiera Gui available.
* Open the business interface(s) and start up the GTK GUI main event loop.
* @todo to ensure invocation of the termination signal, any members
* should be failsafe on initialisation (that means, we must no
* open other interfaces here...) ///////////////////////////TICKET #82
*/
struct GuiLifecycle
{
string error_;
Subsys::SigTerm& reportOnTermination_;
NotificationService activateNotificationService_;
DisplayService activateDisplayService_;
DisplayService activateDisplayService_; ///////////////////////////TICKET #82 will go away once we have a real OutputSlot offered by the UI
GuiLifecycle (Subsys::SigTerm& terminationHandler)
: reportOnTermination_(terminationHandler)
, activateNotificationService_() // opens the GuiNotification facade interface
, activateDisplayService_() // opens the gui::Display facade interface
{ }

View file

@ -153,6 +153,57 @@
</body>
</html>
</richcontent>
<node CREATED="1481502320065" ID="ID_1298358905" MODIFIED="1481502325705" TEXT="macht bisher der GuiRunner">
<node CREATED="1481502327528" ID="ID_75293128" MODIFIED="1481502442640" TEXT="das ist ohnehin schlecht">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...weil es dadurch passieren k&#246;nnte,
</p>
<p>
da&#223; die Konstruktion des GuiRunners schon scheitert, bevor der Rumpf des ctors aufgerufen wird.
</p>
<p>
In einem solchen Fall wird leider auch der Rumpf des dtors nicht aufgerufen, wodurch das
</p>
<p>
Term-Signal nicht ausgesendet w&#252;rde.
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1481502335583" ID="ID_1245191241" MODIFIED="1481502372882" TEXT="Felder im GuiRunner sollten noexcept sein">
<icon BUILTIN="yes"/>
</node>
</node>
<node CREATED="1481502305995" ID="ID_1943234904" MODIFIED="1481502317084" TEXT="in CoreService verschieben"/>
<node CREATED="1481502251450" ID="ID_1125529151" MODIFIED="1481502303814" TEXT="m&#xf6;glicher Race">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1481502257825" ID="ID_232782099" MODIFIED="1481502300621" TEXT="Gefahr gering">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...weil unser Thread-Framework
</p>
<p>
tats&#228;chlich <i>erzwingt,</i>&#160;da&#223; der neue Thrad zu laufen beginnt, bevor die
</p>
<p>
startende Funktion zur&#252;ckkehrt.
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1481320772830" ID="ID_1607125695" MODIFIED="1481320786893">
<richcontent TYPE="NODE"><html>