diff --git a/src/gui/ctrl/ui-dispatcher.hpp b/src/gui/ctrl/ui-dispatcher.hpp index 63f92d8f5..e48d1247b 100644 --- a/src/gui/ctrl/ui-dispatcher.hpp +++ b/src/gui/ctrl/ui-dispatcher.hpp @@ -77,6 +77,7 @@ #include "gui/gtk-base.hpp" #include "lib/call-queue.hpp" +#include "lib/format-string.hpp" #include #include @@ -86,7 +87,19 @@ namespace gui { namespace ctrl { using std::move; + using ::util::_Fmt; + namespace { + /** @note reads and clears the lumiera error flag */ + inline string + generateErrorResponse (const char* problem = "unexpected problem") + { + static _Fmt messageTemplate{"asynchronous UI response failed: %s (error flag was: %s)"}; + string response{messageTemplate % problem % lumiera_error()}; + WARN (gui, "%s", response.c_str()); + return response; + } + } /** @@ -104,13 +117,23 @@ namespace ctrl { using Operation = lib::CallQueue::Operation; public: - UiDispatcher() + template + UiDispatcher(FUN notification) : queue_{} , dispatcher_{} { dispatcher_.connect( - [this]() { - queue_.invoke(); /////////////////////TICKET #1098 : ensure no exception escapes from here!! + [=]() {try { + queue_.invoke(); + } + catch (std::exception& problem) + { + notification (generateErrorResponse(problem.what())); + } + catch (...) + { + notification (generateErrorResponse()); + } }); } diff --git a/src/gui/notification-service.cpp b/src/gui/notification-service.cpp index 400d16497..6eae6ce78 100644 --- a/src/gui/notification-service.cpp +++ b/src/gui/notification-service.cpp @@ -85,6 +85,12 @@ namespace gui { }); } + void + NotificationService::showErrorUI (string errorMsg) + { + UNIMPLEMENTED ("forward error message to the error log"); + } + void NotificationService::displayInfo (NotifyLevel severity, string const& text) @@ -277,7 +283,7 @@ namespace gui { */ NotificationService::NotificationService (ctrl::BusTerm& upLink, ctrl::UiManager& uiManager) : BusTerm{lib::idi::EntryID{}, upLink} - , dispatch_{new UiDispatcher{}} + , dispatch_{new UiDispatcher{[this](string msg){ showErrorUI(msg); }}} , uiManager_{uiManager} , implInstance_(this,_instance) , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_GuiNotification, 0,lumieraorg_GuiNotificationService)) diff --git a/src/gui/notification-service.hpp b/src/gui/notification-service.hpp index 12e4f6c76..78911c702 100644 --- a/src/gui/notification-service.hpp +++ b/src/gui/notification-service.hpp @@ -90,7 +90,8 @@ namespace gui { std::unique_ptr dispatch_; ctrl::UiManager& uiManager_; - void dispatchMsg(ID, lib::diff::GenNode&&); + void dispatchMsg (ID, lib::diff::GenNode&&); + void showErrorUI (string errorMsg); /* === Interface Lifecycle === */ diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 042db3fd5..a6f0aca07 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -2985,16 +2985,16 @@ This treatment ensures each nested diff is consumed within a properly typed cont → this is the purpose of the {{{DataCap}}} within our [[generic node element|GenNode]] -
+
LayerSeparationInterface provided by the GUI.
-Access point for the lower layers to push information and state changes (asynchronously) to the GUI. Most operations within Lumiera are in fact initiated by the user through the GUI. In the course of such actions, the GUI uses the services of the lower layer and typically receives an immediate synchronous response to indicate the change was noted. Yet often, these operations may cause additional changes to happen asynchronously from the GUI's perspective. For example, an edit operation might trigger a re-build of the low-level model, which then detects an error. Any such consequences and notifications can be "cast" up into the UI, using this service here.
+Access point for the lower layers to push information and state changes (asynchronously) to the GUI. Most operations within Lumiera are in fact initiated by the user through the GUI. In the course of such actions, the GUI uses the services of the lower layer and typically receives an immediate synchronous response to indicate the change was noted. Yet often, these operations may cause additional changes to happen asynchronously from the GUI's perspective. For example, an edit operation might trigger a re-build of the low-level model, which then detects an error. Any such consequences and notifications can be "cast" up into the UI, using the {{{NotificationService}}} described here.
 
-Beyond that, a call to trigger shutdown of the UI layer is also exposed here -- which becomes relevant when other [[sub-systems|Subsystem]] initiate general shutdown.
+Beyond that, a call to trigger shutdown of the UI layer is also exposed at this façade -- which becomes relevant when other [[sub-systems|Subsystem]] initiate general shutdown.
 
 !Lifecycle and Threading concerns
 The GuiNotificationFacade is installed as part of and managed by the ''UI Manager'', and connected to the UI-Bus, which happens while establishing the GuiTopLevel. Yet there is a specific twist, insofar GTK is ''not threadsafe by design''. Any event handling and presentation changes will happen from within a dedicated UI event loop, which needs to be started explicitly, after all of the primary windows and widgets are created and wired. Only after this point the UI becomes //life.//
 
-A dedicated ''activation state'' is necessary for this reason -- which within the implementation translate into a queuing and dispatching facility to reschedule any calls into the UI event thread ''asynchronously''.
+A dedicated ''activation state'' is necessary for this reason -- which within the implementation translates into a queuing and dispatching facility to reschedule any calls into the UI event thread ''asynchronously''.
 
 !Addressing of UI elements
 Most calls in this interface require to specify a receiver or target, in the form of an element ID. It is assumed the caller effectively just knows these ~IDs, typically because the same ~IDs are also used as element ~IDs for the corresponding session entities. And, to start with, the whole UI representation of the session was at some point generated by //population diff messages,// which used the same ~IDs to indicate the creation of the corresponding UI representation elements.
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index affd1f4e2..72bd8e753 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -262,8 +262,7 @@
       Sicht "von unten"
     

- - + @@ -447,8 +446,7 @@ GtkLumiera in Konstruktion

- - +
@@ -460,8 +458,7 @@ NotificationFacade noch nicht offen

- -
+
@@ -490,8 +487,7 @@ müssen eigens aktiviert werden

- - + @@ -567,8 +563,7 @@ dann kann der Shutdown-Prozeß den Start des GUI überholen.

- - +
@@ -824,8 +819,7 @@ muß eigens aktiviert werden

- - + @@ -841,18 +835,42 @@ - - + + + + + + - + + + + + + + + + + + + + + + + + + + + + @@ -906,8 +924,7 @@ - - + @@ -1023,8 +1040,7 @@ - - + @@ -1036,8 +1052,7 @@ das wird sowiso ein Desaster

- -
+
@@ -1217,8 +1232,8 @@ - - + + @@ -1349,8 +1364,7 @@ indem wir ein GTK-Signal erzeugen, das das Hauptfenster schließt

- - + @@ -1425,8 +1439,7 @@ eine einzige Funktion konkret durchdenkt: es läuft auf Spaghetti-Code hinaus

- - +
@@ -1458,8 +1471,7 @@ ...indem der NotificatonService nun vom UI-Manager gemanaged wird :)

- - +
@@ -3727,8 +3739,8 @@ - + @@ -11065,8 +11077,7 @@ nach beiden Setien

- - + @@ -12419,8 +12430,7 @@ - - + @@ -16779,8 +16789,7 @@ Paßt hier, da IterSource genau dieses Vorgehen nahelegt

- - +
@@ -16792,8 +16801,7 @@ MutationMessage::updateDiagnostics()

- -
+
@@ -16812,8 +16820,7 @@ ...diejenige, die zum Zeitpunkt des updateDiagnostics() noch anstand

- - +
@@ -17860,8 +17867,7 @@ Das ist eine subtile Falle.

- - +
@@ -17874,8 +17880,7 @@ alles was von sigc::trackable erbt

- - +
@@ -17891,8 +17896,7 @@ für alles aus GTKmm zu verwenden

- - + @@ -17905,8 +17909,7 @@ alles das nicht aus dem GUI-Thread heraus geschieht

- -
+