diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index d803cecc3..2fb76dcc1 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -66,6 +66,10 @@ namespace gui { if (lumiera_error_peek()) throw lumiera::error::Fatal("failed to bring up GUI",lumiera_error()); + + ///////////////////////////////////////////////////////TODO: just a test to verify the GuiNotification facade is properly opened + GuiNotification::facade().displayInfo("Test-Notification message pushed to GUI!!!!"); + ///////////////////////////////////////////////////////TODO: just a test to verify the GuiNotification facade is properly opened } ~GuiRunner () { } diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp index 467870609..513a7607e 100644 --- a/src/common/instancehandle.hpp +++ b/src/common/instancehandle.hpp @@ -72,22 +72,22 @@ namespace lumiera { throw lumiera::error::Config("failed to open interface or plugin.",lumiera_error()); } - /** takes a bunch of instance definitions, as typically created - * when defining interfaces for external use, and registers them + /** takes a (single) instance definitions, as typically created + * when defining interfaces for external use, and registers it * with the InterfaceSystem. Then uses the data found in the - * \em first descriptor to open an instance handle. + * \em given instance descriptor to open an instance handle. + * @throws error::Config when the registration process fails */ LumieraInterface - register_and_open (LumieraInterface* descriptors) + register_and_open (LumieraInterface descriptor) { - if (!descriptors) return NULL; - lumiera_interfaceregistry_bulkregister_interfaces (descriptors, NULL); + if (!descriptor) return NULL; + lumiera_interfaceregistry_register_interface (descriptor, NULL); throwIfError(); - LumieraInterface masterI = descriptors[0]; - return lumiera_interface_open (masterI->interface, - masterI->version, - masterI->size, - masterI->name); + return lumiera_interface_open (descriptor->interface, + descriptor->version, + descriptor->size, + descriptor->name); } /** do a lookup within the interfaceregistry @@ -172,7 +172,7 @@ namespace lumiera { class InstanceHandle : private boost::noncopyable { - LumieraInterface* desc_; + LumieraInterface desc_; I* instance_; FacadeLink facadeLink_; @@ -198,11 +198,11 @@ namespace lumiera { /** Set up an InstanceHandle managing the * registration and deregistration of interface(s). * Should be placed at the service providing side. - * @param descriptors zero terminated array of interface descriptors, - * usually available through lumiera_plugin_interfaces() + * @param a (single) interface descriptor, which can be created with + * LUMIERA_INTERFACE_INSTANCE and referred to by LUMIERA_INTERFACE_REF */ - InstanceHandle (LumieraInterface* descriptors) - : desc_(descriptors) + InstanceHandle (LumieraInterface descriptor) + : desc_(descriptor) , instance_(reinterpret_cast (register_and_open (desc_))) , facadeLink_(*this) { @@ -213,7 +213,7 @@ namespace lumiera { { lumiera_interface_close (&instance_->interface_header_); if (desc_) - lumiera_interfaceregistry_bulkremove_interfaces (desc_); + lumiera_interfaceregistry_remove_interface (desc_); } diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 121c50929..52bd9d3f7 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -45,6 +45,9 @@ namespace lumiera { namespace facade { + LUMIERA_ERROR_DEFINE (FACADE_LIFECYCLE, "facade interface currently not accessible"); + + template class Holder; diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index dbff558a4..43efe6004 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -22,22 +22,22 @@ * *****************************************************/ + /** @file guistart.cpp ** Start up the Lumiera GTK GUI when loading it as dynamic module. ** This plugin is linked together with the Lumiera GUI code; when loaded as - ** Lumiera plugin, it allows to kick off the main GUI thread and thus to bring up - ** the GUI. The loading and shutdown process is carried out by gui::GuiFacade and + ** Lumiera plugin, it allows to kick off the GTK main event loop and thus to bring + ** 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. This call remains blocked within the main GTK event loop; thus - ** typically this should already run within a separate dedicated GUI thread. + ** 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. ** ** 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.) - ** @todo implement this! ** ** @see lumiera::AppState ** @see gui::GuiFacade @@ -50,6 +50,7 @@ #include "include/nobugcfg.h" #include "lib/error.hpp" #include "gui/guifacade.hpp" +#include "gui/notification-service.hpp" #include "common/subsys.hpp" #include "lib/singleton.hpp" @@ -58,9 +59,11 @@ extern "C" { #include "common/interfacedescriptor.h" } +#include +using std::string; using lumiera::Subsys; using gui::LUMIERA_INTERFACE_INAME(lumieraorg_Gui, 1); @@ -73,41 +76,58 @@ 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. */ - struct GuiFacadeImpl - : public GuiFacade + struct GuiLifecycle { + string error_; + Subsys::SigTerm& reportOnTermination_; + NotificationService activateNotificationService_; - void kickOff (Subsys::SigTerm& reportTermination) + GuiLifecycle (Subsys::SigTerm& terminationHandler) + : reportOnTermination_(terminationHandler) + , activateNotificationService_() // opens the GuiNotification facade interface + { } + + ~GuiLifecycle () + { + reportOnTermination_(0); /////////TODO: pass on error information + } + + + void + run () { try { - int argc =0; /////////////////////////////////////////////////////////////////////////////TODO pass arguments from core - char *argv[] = {}; + int argc =0; + char *argv[] = {}; // dummy command line for GTK gui::application().main(argc, argv); // execute the GTK Event Loop if (!lumiera_error_peek()) - { - reportTermination(0); // report GUI shutdown without error return; - } } catch (lumiera::Error& problem) { - reportTermination(&problem); // signal shutdown reporting the error + error_ = problem.what(); + lumiera_error(); // clear error flag return; } catch (...){ } - lumiera::error::Fatal problemIndicator("unexpected error terminated the GUI.", lumiera_error()); - reportTermination (&problemIndicator); + error_ = "unexpected error terminated the GUI."; return; } }; - lumiera::Singleton guiImplProvider_; } // (End) impl details + + + void + kickOff (Subsys::SigTerm& reportTermination) + { + GuiLifecycle(reportTermination).run(); + } } // namespace gui @@ -198,8 +218,7 @@ extern "C" { /* ================== define an lumieraorg_Gui instance =========== , LUMIERA_INTERFACE_INLINE (kickOff, "\255\142\006\244\057\170\152\312\301\372\220\323\230\026\200\065", void, (void* termSig), { - gui::guiImplProvider_().kickOff ( - *reinterpret_cast (termSig)); + gui::kickOff (*reinterpret_cast (termSig)); } ) ) diff --git a/src/gui/guinotificationfacade.cpp b/src/gui/notification-service.cpp similarity index 81% rename from src/gui/guinotificationfacade.cpp rename to src/gui/notification-service.cpp index 67ae31162..c09e1bbd5 100644 --- a/src/gui/guinotificationfacade.cpp +++ b/src/gui/notification-service.cpp @@ -1,5 +1,5 @@ /* - GuiNotificationFacade - access point for pushing informations into the GUI + NotificationService - public service allowing to push informations into the GUI Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -21,7 +21,7 @@ * *****************************************************/ -#include "include/guinotificationfacade.h" +#include "gui/notification-service.hpp" #include "lib/singleton.hpp" #include "include/nobugcfg.h" #include "lib/util.hpp" @@ -33,35 +33,33 @@ extern "C" { #include + + namespace gui { using std::string; using util::cStr; + + + void + NotificationService::displayInfo (string const& text) + { + INFO (operate, "@GUI: display '%s' as notification message.", cStr(text)); + ////////////////////////TODO actually push the information to the GUI + } + + + void + NotificationService::triggerGuiShutdown (string const& cause) + { + NOTICE (operate, "@GUI: shutdown triggered with explanation '%s'....", cStr(cause)); + TODO ("actually request a shutdown from the GUI"); + } + namespace { // facade implementation details - struct GuiNotificationFacade - : public GuiNotification - { - void - displayInfo (string const& text) - { - INFO (operate, "@GUI: display '%s' as notification message.", cStr(text)); - } - - void - triggerGuiShutdown (string const& cause) - { - NOTICE (operate, "@GUI: shutdown triggered with explanation '%s'....", cStr(cause)); - } - }; - - lumiera::Singleton _facade; - - - - /* ================== define an lumieraorg_GuiNotification instance ======================= */ LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 @@ -131,6 +129,16 @@ namespace gui { ); + + + + using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; + typedef lib::SingletonRef::Accessor InstanceRef; + + InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual GuiNotification implementation... + + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_GuiNotification, 1 ,lumieraorg_GuiNotificationFacade , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_GuiNotificationFacade_descriptor) @@ -138,15 +146,37 @@ namespace gui { , NULL /* on close */ , LUMIERA_INTERFACE_INLINE (displayInfo, "\366\075\213\163\207\040\221\233\010\366\174\374\317\126\331\205", void, (const char* text), - { return _facade().displayInfo(text); } + { + if (!_instance) lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE); + else + _instance->displayInfo(text); + } ) , LUMIERA_INTERFACE_INLINE (triggerGuiShutdown, "\267\043\244\065\107\314\370\175\063\330\264\257\302\146\326\303", void, (const char* cause), - { return _facade().triggerGuiShutdown(cause); } + { + if (!_instance) lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE); + else + _instance->triggerGuiShutdown(cause); + } ) ); - - + + + } // (END) facade implementation details + + + + + NotificationService::NotificationService () + : implInstance_(this,_instance), + serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_GuiNotification, 1,lumieraorg_GuiNotificationFacade)) + { + INFO (operate, "GuiNotification Facade opened."); + } + + + } // namespace gui diff --git a/src/gui/notification-service.hpp b/src/gui/notification-service.hpp new file mode 100644 index 000000000..41e404e46 --- /dev/null +++ b/src/gui/notification-service.hpp @@ -0,0 +1,91 @@ +/* + NOTIFICATION-SERVICE.hpp - public service allowing to push informations into the GUI + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + 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. + + 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. + +*/ + +/** @file notification-service.hpp + ** A public service provided by the GUI, implementing the gui::GuiNotification facade interface. + ** The purpose of this service is to push state update and notification of events from the lower + ** layers into the Lumiera GUI. Typically, this happens asynchronously and triggered by events + ** within the lower layers. + ** + ** This service is the implementation of a layer separation facade interface. Clients should use + ** gui::GuiNotification#facade to access this service. This header defines the interface used + ** to \em provide this service, not to access it. + ** + ** @see gui::GuiFacade + ** @see guifacade.cpp starting this service + */ + + +#ifndef GUI_NOTIFICATION_SERVICE_H +#define GUI_NOTIFICATION_SERVICE_H + + +#include "include/guinotificationfacade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" + + + +namespace gui { + + + + /****************************************************** + * Actual implementation of the GuiNotification service + * within the Lumiera GTK GUI. Creating an instance of + * this class automatically registers the interface + * with the Lumiera Interface/Plugin system and creates + * a forwarding proxy within the application core to + * route calls through this interface. + * + * @todo the ctor of this class should take references + * to any internal service providers within the + * GUI which are needed to implement the service. + */ + class NotificationService + : public GuiNotification + { + + /* === Implementation of the Facade Interface === */ + + void displayInfo (string const& text); + void triggerGuiShutdown (string const& cause); + + + /* === Interface Lifecycle === */ + + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 1) + , GuiNotification + > ServiceInstanceHandle; + + lib::SingletonRef implInstance_; + ServiceInstanceHandle serviceInstance_; + + public: + NotificationService(); + + }; + + + +} // namespace gui +#endif diff --git a/src/include/guinotificationfacade.h b/src/include/guinotificationfacade.h index 648839f50..9f4f91474 100644 --- a/src/include/guinotificationfacade.h +++ b/src/include/guinotificationfacade.h @@ -20,16 +20,13 @@ */ -/** @file guifacade.hpp - ** Interface for the GUI loader and for accessing the GUI interface from the - ** lower layers of Lumiera. While part of the public interface of the Lumiera GUI, - ** the implementation of this facility is part of the core application (and not - ** contained within the GUI dynamic module), because it's job is to load and - ** activate this module and to startup the GUI. +/** @file guinotificationfacade.hpp + ** Main public Interface of the Lumiera GUI. While generally speaking, the GUI + ** controls the application and thus acts on its own, it exposes some services + ** usable by scripts or the two lower layers. The main purpose of these services + ** is to push informations and status updates into the GUI. ** - ** @see lumiera::AppState - ** @see lumiera::Option - ** @see guifacade.cpp + ** @see gui::GuiFacade ** @see main.cpp */ diff --git a/src/include/interfaceproxy.hpp b/src/include/interfaceproxy.hpp index cb8da0d92..32248d762 100644 --- a/src/include/interfaceproxy.hpp +++ b/src/include/interfaceproxy.hpp @@ -84,6 +84,9 @@ namespace lumiera { namespace facade { + /** error-ID for accessing a (currently) closed facade */ + LUMIERA_ERROR_DECLARE(FACADE_LIFECYCLE); + /********************************************************************* * diff --git a/src/lib/singleton-ref.hpp b/src/lib/singleton-ref.hpp new file mode 100644 index 000000000..f3fad3921 --- /dev/null +++ b/src/lib/singleton-ref.hpp @@ -0,0 +1,131 @@ +/* + SINGLETON-REF.hpp - helper template providing singleton-like access for implementation code + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + 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. + + 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. + +*/ + +/** @file singleton-ref.hpp + ** Helper for singleton-kind access without managing object creation and lifecycle. + ** A typical usage scenario is when implementing C Language Interfaces without any + ** canonical access to some "this" pointer. + ** + ** @see gui::NotificationService usage example + */ + + +#ifndef LIB_SINGLETON_REF_H +#define LIB_SINGLETON_REF_H + + +#include "lib/error.hpp" + +#include + + +namespace lib { + + namespace singleton { + + /*************************************** + * Detail/Policy class specifying + * how the SingletonRef can be accessed + */ + template + class AccessAsReference + : boost::noncopyable + { + TY* obj_; + + typedef AccessAsReference _ThisType; + + public: + void + open (TY* instance) + { + ASSERT (!obj_, "Lifecycle error"); + obj_ = instance; + } + + void + close () + { + ASSERT (obj_, "Lifecycle error"); + obj_ = 0; + } + + TY* + operator-> () const + { + if (!obj_) + throw lumiera::error::State("Target currently not available."); + return obj_; + } + + + typedef void* _ThisType::*unspecified_bool_type; + + /** implicit conversion to "bool" */ + operator unspecified_bool_type() const // never throws + { + return obj_? &_ThisType::obj_ : 0; + } + + bool operator! () const { return !obj_; } + + }; + + } // namespace Singleton + + + + + /************************************************************* + * Helper template providing singleton access without managing + * object creation and lifecycle. + * @param TY the actual type to be made accessible + * @param B a base class to inherit from; defaults to noncopyable + * @param Accessor how to implement the static instance access + */ + template< class TY + , class B = boost::noncopyable + , template class Access = singleton::AccessAsReference + > + struct SingletonRef + : public B + { + + typedef Access Accessor; + Accessor& accessor_; + + SingletonRef(TY * instance, Accessor& acc) + : accessor_(acc) + { + accessor_.open (instance); + } + + ~SingletonRef() + { + accessor_.close (); + } + }; + + + +} // namespace lib +#endif diff --git a/src/proc/facade.hpp b/src/proc/facade.hpp index 1a30c7c27..5f4531617 100644 --- a/src/proc/facade.hpp +++ b/src/proc/facade.hpp @@ -33,18 +33,11 @@ namespace proc { /********************************************************************* - * Global access point for loading and starting up the Lumiera GTK GUI - * and for defining the public interface(s) for addressing the GUI - * from Backend or Proc-Layer. + * Global access point for the services implemented by the Proc-Layer. * - * If running Lumiera with a GUI is required (the default case), - * it is loaded as dynamic module, thus defining the interface(s) - * for any further access. After successfully loading and starting - * the GUI, this gui::Facade is wired internally with this interface - * such as to allow transparent access from within the core. This - * startup sequence includes providing the GUI with similar facade - * access via interface handles for communication with Backend and - * Proc-Layer. + * @todo this is a dummy placeholder as of 1/2009. Currently, there + * is only implementation-level code within the Proc-Layer and + * the interfaces need to be worked out. * */ struct Facade