Rewrite the GuiNotification service to operate in sync with bringing up the GUI

This commit is contained in:
Fischlurch 2009-01-10 15:29:11 +01:00
parent 4ffa60161b
commit 3da9586824
10 changed files with 354 additions and 83 deletions

View file

@ -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 () { }

View file

@ -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<I,FA> 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<I*> (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_);
}

View file

@ -45,6 +45,9 @@ namespace lumiera {
namespace facade {
LUMIERA_ERROR_DEFINE (FACADE_LIFECYCLE, "facade interface currently not accessible");
template<class IHA>
class Holder;

View file

@ -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 <string>
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<GuiFacadeImpl> 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<Subsys::SigTerm *> (termSig));
gui::kickOff (*reinterpret_cast<Subsys::SigTerm *> (termSig));
}
)
)

View file

@ -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 <Ichthyostega@web.de>
@ -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 <string>
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<GuiNotificationFacade> _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<GuiNotification>::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

View file

@ -0,0 +1,91 @@
/*
NOTIFICATION-SERVICE.hpp - public service allowing to push informations into the GUI
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
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<GuiNotification> implInstance_;
ServiceInstanceHandle serviceInstance_;
public:
NotificationService();
};
} // namespace gui
#endif

View file

@ -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
*/

View file

@ -84,6 +84,9 @@
namespace lumiera {
namespace facade {
/** error-ID for accessing a (currently) closed facade */
LUMIERA_ERROR_DECLARE(FACADE_LIFECYCLE);
/*********************************************************************
*

131
src/lib/singleton-ref.hpp Normal file
View file

@ -0,0 +1,131 @@
/*
SINGLETON-REF.hpp - helper template providing singleton-like access for implementation code
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
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 <boost/noncopyable.hpp>
namespace lib {
namespace singleton {
/***************************************
* Detail/Policy class specifying
* how the SingletonRef can be accessed
*/
template<class TY>
class AccessAsReference
: boost::noncopyable
{
TY* obj_;
typedef AccessAsReference<TY> _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> class Access = singleton::AccessAsReference
>
struct SingletonRef
: public B
{
typedef Access<TY> Accessor;
Accessor& accessor_;
SingletonRef(TY * instance, Accessor& acc)
: accessor_(acc)
{
accessor_.open (instance);
}
~SingletonRef()
{
accessor_.close ();
}
};
} // namespace lib
#endif

View file

@ -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