lumiera_/src/gui/display-service.cpp
Ichthyostega 1e81b8d61a Settle proper activation of the external UI interfaces (#1098)
This change was caused by investigation of UI event loop dispatch;
since the GTK UI is designed to run single threaded, any invocation
from other threads need to be diepatched explicitly.

A possible way to achieve this is to use Glib::Dispatcher, which
in turn requires that the current thread (which is in this case the UI thread)
already holds a Glib::MainContext

This prompted me to create a tight link between the external facade interfaces
of the UI and the event loop itself. What remains to be settled is how
to hand over arguments to the action in the main loop
2017-08-05 17:36:32 +02:00

263 lines
13 KiB
C++

/*
DisplayService - service providing access to a display for outputting frames
Copyright (C) Lumiera.org
2009, 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 display-service.cpp
** Implementation of _Displayer Service,_ exposed as a public interface.
** This service allows to set up _display slots,_ which can be handed over
** to client code in the course of the play process for outputting frames.
**
** @deprecated This is a first draft as of 1/2009, and likely to be superseded
** by a better design, where rather the \em provider of an output facility
** registers with the OutputManager in the core.
*/
#include "gui/display-service.hpp"
extern "C" {
#include "common/interface-descriptor.h"
}
namespace gui {
namespace { // hidden local details of the service implementation....
/* ================== define an lumieraorg_Display instance ======================= */
LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0
,lumieraorg_DisplayFacade_descriptor
, NULL, NULL, NULL
, LUMIERA_INTERFACE_INLINE (name,
const char*, (LumieraInterface ifa),
{ (void)ifa; return "Display"; }
)
, LUMIERA_INTERFACE_INLINE (brief,
const char*, (LumieraInterface ifa),
{ (void)ifa; return "UI Interface: service for outputting frames to a viewer or display"; }
)
, LUMIERA_INTERFACE_INLINE (homepage,
const char*, (LumieraInterface ifa),
{ (void)ifa; return "http://www.lumiera.org/develompent.html" ;}
)
, LUMIERA_INTERFACE_INLINE (version,
const char*, (LumieraInterface ifa),
{ (void)ifa; return "0.1~pre"; }
)
, LUMIERA_INTERFACE_INLINE (author,
const char*, (LumieraInterface ifa),
{ (void)ifa; return "Hermann Vosseler"; }
)
, LUMIERA_INTERFACE_INLINE (email,
const char*, (LumieraInterface ifa),
{ (void)ifa; return "Ichthyostega@web.de"; }
)
, LUMIERA_INTERFACE_INLINE (copyright,
const char*, (LumieraInterface ifa),
{
(void)ifa;
return
"Copyright (C) Lumiera.org\n"
" 2009 Hermann Vosseler <Ichthyostega@web.de>";
}
)
, LUMIERA_INTERFACE_INLINE (license,
const char*, (LumieraInterface ifa),
{
(void)ifa;
return
"This program is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation; either version 2 of the License, or\n"
"(at your option) any later version.\n"
"\n"
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA";
}
)
, LUMIERA_INTERFACE_INLINE (state,
int, (LumieraInterface ifa),
{(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; }
)
, LUMIERA_INTERFACE_INLINE (versioncmp,
int, (const char* a, const char* b),
{(void)a;(void)b; return 0;} ////////////////////////////////////////////TODO define version ordering
)
);
using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE;
typedef lib::SingletonRef<DisplayService>::Accessor InstanceRef;
InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DisplayService implementation...
LUMIERA_INTERFACE_INSTANCE (lumieraorg_Display, 0
,lumieraorg_DisplayService
, LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DisplayFacade_descriptor)
, NULL /* on open */
, NULL /* on close */
, LUMIERA_INTERFACE_INLINE (allocate,
void, (LumieraDisplaySlot slotHandle),
{
if (!_instance)
{
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
return;
}
REQUIRE (slotHandle);
try
{
_instance->allocate (slotHandle,true);
}
catch (lumiera::Error&){ /* error state remains set */ }
}
)
, LUMIERA_INTERFACE_INLINE (release,
void, (LumieraDisplaySlot slotHandle),
{
if (!_instance)
{
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
return;
}
REQUIRE (slotHandle);
_instance->allocate (slotHandle,false);
}
)
, LUMIERA_INTERFACE_INLINE (put,
void, (LumieraDisplaySlot slotHandle, LumieraDisplayFrame frame),
{
//skipping full checks for performance reasons
REQUIRE (_instance && !lumiera_error_peek());
REQUIRE (slotHandle);
DisplayerSlot& slot = _instance->resolve (slotHandle);
slot.put (frame);
}
)
);
} // (End) hidden service impl details
DisplayService::DisplayService()
: error_("")
, implInstance_(this,_instance)
, serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_Display, 0, lumieraorg_DisplayService))
{
INFO (progress, "Display Facade opened.");
}
LumieraDisplaySlot
DisplayService::setUp (FrameDestination const& outputDestination)
{
DisplayerTab& slots (_instance->slots_);
return &slots.manage (new DisplayerSlot (outputDestination));
}
void
DisplayService::allocate (LumieraDisplaySlot handle, bool doAllocate)
{
REQUIRE (handle);
if (doAllocate)
{
if (handle->put_)
throw lumiera::error::Logic("slot already allocated for output");
else
// Mark the handle as "allocated" and ready for output:
// Place the function pointer from the C interface into the handle struct.
// calling it will invoke the implementing instance's "put" function
// (see the LUMIERA_INTERFACE_INLINE above in this file!)
handle->put_ = serviceInstance_.get().put;
}
else
handle->put_ = 0;
}
DisplayerSlot&
DisplayService::resolve (LumieraDisplaySlot handle)
{
REQUIRE (handle);
REQUIRE (handle->put_, "accessing a DisplayerSlot, which hasn't been locked for output");
return *static_cast<DisplayerSlot*> (handle);
}
/* === DisplayerSlot Implementation === */
DisplayerSlot::DisplayerSlot (FrameDestination const& outputDestination)
: currBuffer_(0)
{
put_ = 0; // mark as not allocated
hasFrame_.connect (outputDestination);
dispatcher_.connect (sigc::mem_fun (this, &DisplayerSlot::displayCurrentFrame));
}
DisplayerSlot::~DisplayerSlot()
{
TRACE (gui_dbg, "Displayer Slot closing...");
}
void
DisplayerSlot::displayCurrentFrame()
{
hasFrame_.emit (currBuffer_);
}
} // namespace proc