From 747d793121971cd1c1de3b72b049f47f564c8947 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 18 Oct 2008 02:32:34 +0200 Subject: [PATCH 001/249] draft framework for handling the memory allocation of render nodes --- src/lib/allocationcluster.cpp | 72 +++++++++++++++++++ src/lib/allocationcluster.hpp | 131 ++++++++++++++++++++++++++++++++++ wiki/renderengine.html | 17 ++++- 3 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 src/lib/allocationcluster.cpp create mode 100644 src/lib/allocationcluster.hpp diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp new file mode 100644 index 000000000..0ff0000bd --- /dev/null +++ b/src/lib/allocationcluster.cpp @@ -0,0 +1,72 @@ +/* + AllocationCluster - allocating and owning a pile of objects + + 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. + +* *****************************************************/ + + +#include "lib/allocationcluster.hpp" +#include "common/error.hpp" +//#include "common/util.hpp" + + +//using util::isnil; +//using util::cStr; + +namespace lib { + + + /** creating a new AllocationCluster prepares a table capable + * of holding the individual object families to come. Each of those + * is managed by a separate instance of the low-level memory manager. + */ + AllocationCluster::AllocationCluster() +// : configParam_ (new Configmap), + { + } + + + /** On shutdown of the AllocationCluster we need to assure a certain + * destruction order is maintained by explicitly invoking a cleanup + * operation on each of the low-level memory manager objects. + */ + AllocationCluster::~AllocationCluster() throw() + { + try + { + + } + catch (lumiera::Error & ex) + { + WARN ("Exception while closing AllocationCluster: %s",ex.what()); + } + catch (...) + { + ERROR ("Unexpected fatal Exception while closing AllocationCluster. Application will terminate."); + throw; + } + } + + + // ==== implementation LifecycleHook class ======= + + //x + + +} // namespace lib diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp new file mode 100644 index 000000000..18ada0209 --- /dev/null +++ b/src/lib/allocationcluster.hpp @@ -0,0 +1,131 @@ +/* + ALLOCATIONCLUSTER.hpp - allocating and owning a pile of objects + + 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 allocationcluster.hpp + ** Memory management for the low-level model (render nodes network). + ** The model is organised into temporal segments, which are considered + ** to be structurally constant and uniform. The objects within each + ** segment are strongly interconnected, and thus each segment is + ** being built in a single build process and is replaced or released + ** as a whole. AllocationCluster implements memory management to + ** support this usage pattern. + ** + ** @see allocationclustertest.cpp + ** @see builder::ToolFactory + ** @see frameid.hpp + */ + + +#ifndef LUMIERA_APPCONFIG_H +#define LUMIERA_APPCONFIG_H + +//#include +#include +//#include +#include + + + +namespace lib { + using std::string; +// using boost::scoped_ptr; + + + /** + * A pile of objects sharing common allocation and lifecycle. + * AllocationCluster owns a number of object families of various types. + * Each of those contains a initially undetermined (but rather large) + * number of individual objects, which can be expected to be allocated + * within a short timespan and which are to be released cleanly on + * destruction of the AllocationCluster. There is a service creating + * individual objects with arbitrary ctor parameters and it is possible + * to control the oder in which the object families are to be discarded. + * @warning make sure the objects dtors aren't called and object references + * aren't used after shutting down a given AllocationCluster. + */ + class AllocationCluster + : boost::noncopyable + { + + public: + AllocationCluster (); + ~AllocationCluster () throw(); + + template + TY& + create () + { + TY* obj = new(allocation()) TY(); + return success(obj); + } + + template + TY& + create (P0& p0) + { + TY* obj = new(allocation()) TY (p0); + return success(obj); + } + + template + TY& + create (P0& p0, P1& p1) + { + TY* obj = new(allocation()) TY (p0,p1); + return success(obj); + } + + template + TY& + create (P0& p0, P1& p1, P2& p2) + { + TY* obj = new(allocation()) TY (p0,p1,p2); + return success(obj); + } + + template + TY& + create (P0& p0, P1& p1, P2& p2, P3& p3) + { + TY* obj = new(allocation()) TY (p0,p1,p2,p3); + return success(obj); + } + + + protected: + /** initiate an allocation for the given type */ + template + void* + allocation(); + + /** finish the allocation after the ctor is successful */ + template + TY& + success (TY* obj); + }; + + + + + +} // namespace lib +#endif diff --git a/wiki/renderengine.html b/wiki/renderengine.html index bb22c2320..c65e96504 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -514,6 +514,17 @@ ColorPalette SiteUrl +
+
Memory management facility for the low-level model (render nodes network). The model is organised into temporal segments, which are considered to be structurally constant and uniform. The objects within each segment are strongly interconnected, and thus each segment is being built in a single build process and is replaced or released as a whole. __~AllocationCluster__ implements memory management to support this usage pattern. He owns a number of object families of various types.
+* [[processing nodes|ProcNode]] — probably with several subclasses (?)
+* [[wiring descriptors|WiringDescriptor]]
+* the input/output descriptor arrays used by the latter
+
+To Each of those families we can expect an initially undetermined (but rather large) number of individual objects, which can be expected to be allocated within a short timespan and which are to be released cleanly on destruction of the AllocationCluster.
+
+→ see MemoryManagement
+
+
Asset management is a subsystem on its own. Assets are "things" that can be loaded into a session, like Media, Clips, Effects, Transitions. It is the "bookkeeping view", while the EDL is the "manipulation and process view". Some Assets can be //loaded// and a collection of Assets is saved with each Session. Besides, there is a collection of basic Assets always available by default.
 
@@ -1826,10 +1837,10 @@ This Design strives to achieve a StrongSeparation between the low-level Structur
 {{red{let's see if this approach works...}}}
 
-
-
Contrary to the →[[Assets and MObjects|ManagementAssetRelation]], the usage pattern for [[render nodes|ProcNode]] is quite simple: All nodes are created together every time a new segment of the network is being build and are all needed together until this segment is re-built, at which point they can be thrown away altogether. While it would be easy to handle the nodes automatically by smart-ptr (the creation is accessible only by use of the {{{NodeFactory}}} anyways), it //seems advisable to care for a bulk allocation/deallocation here.// The reason being not so much the amount of memory (which is expected to be moderate), but the fact, that the build process can be triggered repeatedly several times a second when tweaking the EDL, which could lead to fragmentation and memory pressure.
+
+
Contrary to the →[[Assets and MObjects|ManagementAssetRelation]], the usage pattern for [[render nodes|ProcNode]] is quite simple: All nodes are created together every time a new segment of the network is being build and are all needed together until this segment is re-built, at which point they can be thrown away altogether. While it would be easy to handle the nodes automatically by smart-ptr (the creation is accessible only by use of the {{{NodeFactory}}} anyways), it //seems advisable to care for a bulk allocation/deallocation here.// The reason being not so much the amount of memory (which is expected to be moderate), but the fact the build process can be triggered repeatedly several times a second when tweaking the EDL, which could lead to fragmentation and memory pressure.
 
-__5/2008__: the allocation mechanism can surely be improved later, but for now I am going for a simple implementation based on keeping all nodes of one kind together in a vector. The list of possible node kinds is hard wired, allowing to generate the object holding a chunk of nodes for one segment, mostly relying on the runtime system for the management.
+__10/2008__: the allocation mechanism can surely be improved later, but for now I am going for a simple implementation based on heap allocated objects owned by a vector or smart-ptrs. For each segment of the render nodes network, we have several families of objects, each of with will be maintained by a separate low-level memory manager (as said, for now implemented as vector of smart-ptrs). Together, they form an AllocationCluster; all objects contained in such a cluster will be destroyed together.
 
From 1b6df94aab13aa3d7d40fa67530d4ef2336031eb Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 18 Oct 2008 03:42:00 +0200 Subject: [PATCH 002/249] documentation (drawing) --- doc/devel/draw/AllocationCluster.svg | 544 +++++++++++++++++++++++++++ src/common/error.hpp | 1 + src/lib/allocationcluster.cpp | 4 +- src/lib/allocationcluster.hpp | 4 +- wiki/draw/AllocationCluster.png | Bin 0 -> 15026 bytes wiki/renderengine.html | 9 +- 6 files changed, 555 insertions(+), 7 deletions(-) create mode 100644 doc/devel/draw/AllocationCluster.svg create mode 100644 wiki/draw/AllocationCluster.png diff --git a/doc/devel/draw/AllocationCluster.svg b/doc/devel/draw/AllocationCluster.svg new file mode 100644 index 000000000..b2e91a268 --- /dev/null +++ b/doc/devel/draw/AllocationCluster.svg @@ -0,0 +1,544 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + AllocationCluster + + + Ichthyostega + + + design sketch: Structure of the AllocationCluster mem manager + 2008 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Type<T1> + Type<T2> + Type<T3> + Segments + AllocationCluster + memManager<T2> + raw storage + Obj1 + Obj2 + Obj3 + + + diff --git a/src/common/error.hpp b/src/common/error.hpp index 84140af80..ffd344323 100644 --- a/src/common/error.hpp +++ b/src/common/error.hpp @@ -26,6 +26,7 @@ #include #include "proc/nobugcfg.hpp" +#include "lib/appconfig.hpp" #include "lib/error.h" diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp index 0ff0000bd..c0172446e 100644 --- a/src/lib/allocationcluster.cpp +++ b/src/lib/allocationcluster.cpp @@ -54,11 +54,11 @@ namespace lib { } catch (lumiera::Error & ex) { - WARN ("Exception while closing AllocationCluster: %s",ex.what()); + WARN (oper, "Exception while closing AllocationCluster: %s",ex.what()); } catch (...) { - ERROR ("Unexpected fatal Exception while closing AllocationCluster. Application will terminate."); + ERROR (NOBUG_ON, "Unexpected fatal Exception while closing AllocationCluster. Application will terminate."); throw; } } diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp index 18ada0209..4e35f8485 100644 --- a/src/lib/allocationcluster.hpp +++ b/src/lib/allocationcluster.hpp @@ -35,8 +35,8 @@ */ -#ifndef LUMIERA_APPCONFIG_H -#define LUMIERA_APPCONFIG_H +#ifndef LIB_ALLOCATIONCLUSTER_H +#define LIB_ALLOCATIONCLUSTER_H //#include #include diff --git a/wiki/draw/AllocationCluster.png b/wiki/draw/AllocationCluster.png new file mode 100644 index 0000000000000000000000000000000000000000..9a4a13e8b67e0aea1934a0b659629d5856e71ec3 GIT binary patch literal 15026 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 KPKB1!%l`p?5*!8q literal 0 HcmV?d00001 diff --git a/wiki/renderengine.html b/wiki/renderengine.html index c65e96504..b8cd1c799 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -514,14 +514,17 @@ ColorPalette SiteUrl
-
-
Memory management facility for the low-level model (render nodes network). The model is organised into temporal segments, which are considered to be structurally constant and uniform. The objects within each segment are strongly interconnected, and thus each segment is being built in a single build process and is replaced or released as a whole. __~AllocationCluster__ implements memory management to support this usage pattern. He owns a number of object families of various types.
+
+
Memory management facility for the low-level model (render nodes network). The model is organised into temporal segments, which are considered to be structurally constant and uniform. The objects within each segment are strongly interconnected, and thus each segment is being built in a single build process and is replaced or released as a whole. __~AllocationCluster__ implements memory management to support this usage pattern. He owns a number of object families of various types.[>img[draw/AllocationCluster.png]]
 * [[processing nodes|ProcNode]] &mdash; probably with several subclasses (?)
 * [[wiring descriptors|WiringDescriptor]]
 * the input/output descriptor arrays used by the latter
 
 To Each of those families we can expect an initially undetermined (but rather large) number of individual objects, which can be expected to be allocated within a short timespan and which are to be released cleanly on destruction of the AllocationCluster.
 
+''Problem of calling the dtors''
+Even if the low-level memory manager(s) may use raw storage, we require that the allocated objects desctuctores be called. This means keeping track at least of the number of objects acllocated (without wasting too much memory for bookeeping). Besides, as the objects are expected to be interconnected, it may be dangerous to destroy a given family of objects while another family of objects may rely on the former in its destructor. //If we happen do get into this situation,// we need to define a priority order on the types and assure the destruction sequence is respected.
+
 &rarr; see MemoryManagement
 
@@ -1793,7 +1796,7 @@ From experiences with other middle scale projects, I prefer having the test code * {{red{and what else?}}}
-
+
The ~MObjects Subsystem contains everything related to the [[EDL]] and the various Media Objects placed within. It is complemented by the Asset Management (see &rarr; [[Asset]]). Examples for [[MObjects|MObject]] being:
 * audio/video clips
 * effects and plugins

From d89e979aa09b7cd9e90848e8eda752ef761bfb8f Mon Sep 17 00:00:00 2001
From: Joel Holdsworth 
Date: Sat, 18 Oct 2008 11:20:02 +0100
Subject: [PATCH 003/249] Renamed HeaderContainer to TimelineHeaderContainer

---
 src/gui/Makefile.am                           | 104 +++++++++---------
 src/gui/lumiera_ui.rc                         |   4 +-
 src/gui/widgets/timeline-widget.cpp           |   2 +-
 src/gui/widgets/timeline-widget.hpp           |   6 +-
 ...iner.cpp => timeline-header-container.cpp} |  33 +++---
 ...iner.hpp => timeline-header-container.hpp} |  13 ++-
 6 files changed, 82 insertions(+), 80 deletions(-)
 rename src/gui/widgets/timeline/{header-container.cpp => timeline-header-container.cpp} (88%)
 rename src/gui/widgets/timeline/{header-container.hpp => timeline-header-container.hpp} (90%)

diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am
index 79e402310..7e8d356ea 100644
--- a/src/gui/Makefile.am
+++ b/src/gui/Makefile.am
@@ -21,67 +21,67 @@ lumigui_srcdir = $(top_srcdir)/src/gui
 #lumigui_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror
 
 lumigui_CPPFLAGS = $(AM_CPPFLAGS) \
-	-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\"	\
-	-DPACKAGE_SRC_DIR=\""$(srcdir)"\"							\
-	-DPACKAGE_DATA_DIR=\""$(datadir)"\"							\
+	-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\"				\
+	-DPACKAGE_SRC_DIR=\""$(srcdir)"\"										\
+	-DPACKAGE_DATA_DIR=\""$(datadir)"\"										\
 	$(GTK_LUMIERA_CFLAGS)
 
 bin_PROGRAMS += lumigui
 
-lumigui_SOURCES =												\
-	  $(lumigui_srcdir)/gtk-lumiera.cpp							\
-	$(lumigui_srcdir)/gtk-lumiera.hpp							\
-	  $(lumigui_srcdir)/window-manager.cpp						\
-	$(lumigui_srcdir)/window-manager.hpp						\
-	$(lumigui_srcdir)/workspace/actions.cpp						\
-	$(lumigui_srcdir)/workspace/actions.hpp						\
-	$(lumigui_srcdir)/workspace/workspace-window.cpp			\
-	$(lumigui_srcdir)/workspace/workspace-window.hpp			\
-	$(lumigui_srcdir)/dialogs/render.cpp						\
-	$(lumigui_srcdir)/dialogs/render.hpp						\
-	$(lumigui_srcdir)/dialogs/preferences-dialog.cpp			\
-	$(lumigui_srcdir)/dialogs/preferences-dialog.hpp			\
-	$(lumigui_srcdir)/panels/panel.cpp							\
-	$(lumigui_srcdir)/panels/panel.hpp							\
-	$(lumigui_srcdir)/panels/timeline-panel.cpp					\
-	$(lumigui_srcdir)/panels/timeline-panel.hpp					\
-	$(lumigui_srcdir)/panels/viewer-panel.cpp					\
-	$(lumigui_srcdir)/panels/viewer-panel.hpp					\
-	$(lumigui_srcdir)/panels/assets-panel.cpp					\
-	$(lumigui_srcdir)/panels/assets-panel.hpp					\
-	$(lumigui_srcdir)/widgets/video-display-widget.cpp			\
-	$(lumigui_srcdir)/widgets/video-display-widget.hpp			\
-	$(lumigui_srcdir)/widgets/timeline-widget.cpp				\
-	$(lumigui_srcdir)/widgets/timeline-widget.hpp				\
-	$(lumigui_srcdir)/widgets/timeline/header-container.cpp		\
-	$(lumigui_srcdir)/widgets/timeline/header-container.hpp		\
-	$(lumigui_srcdir)/widgets/timeline/track.cpp				\
-	$(lumigui_srcdir)/widgets/timeline/track.hpp				\
-	$(lumigui_srcdir)/widgets/timeline/timeline-body.cpp		\
-	$(lumigui_srcdir)/widgets/timeline/timeline-body.hpp		\
-	$(lumigui_srcdir)/widgets/timeline/timeline-ruler.cpp		\
-	$(lumigui_srcdir)/widgets/timeline/timeline-ruler.hpp		\
-	$(lumigui_srcdir)/widgets/timeline/timeline-tool.cpp		\
-	$(lumigui_srcdir)/widgets/timeline/timeline-tool.hpp		\
-	$(lumigui_srcdir)/widgets/timeline/timeline-arrow-tool.cpp	\
-	$(lumigui_srcdir)/widgets/timeline/timeline-arrow-tool.hpp	\
-	$(lumigui_srcdir)/widgets/timeline/timeline-ibeam-tool.cpp	\
-	$(lumigui_srcdir)/widgets/timeline/timeline-ibeam-tool.hpp	\
-	$(lumigui_srcdir)/model/project.cpp							\
-	$(lumigui_srcdir)/model/project.hpp							\
-	$(lumigui_srcdir)/output/displayer.cpp						\
-	$(lumigui_srcdir)/output/displayer.hpp						\
-	$(lumigui_srcdir)/output/gdkdisplayer.cpp					\
-	$(lumigui_srcdir)/output/gdkdisplayer.hpp					\
-	$(lumigui_srcdir)/output/xvdisplayer.cpp					\
+lumigui_SOURCES =															\
+	  $(lumigui_srcdir)/gtk-lumiera.cpp										\
+	$(lumigui_srcdir)/gtk-lumiera.hpp										\
+	  $(lumigui_srcdir)/window-manager.cpp									\
+	$(lumigui_srcdir)/window-manager.hpp									\
+	$(lumigui_srcdir)/workspace/actions.cpp									\
+	$(lumigui_srcdir)/workspace/actions.hpp									\
+	$(lumigui_srcdir)/workspace/workspace-window.cpp						\
+	$(lumigui_srcdir)/workspace/workspace-window.hpp						\
+	$(lumigui_srcdir)/dialogs/render.cpp									\
+	$(lumigui_srcdir)/dialogs/render.hpp									\
+	$(lumigui_srcdir)/dialogs/preferences-dialog.cpp						\
+	$(lumigui_srcdir)/dialogs/preferences-dialog.hpp						\
+	$(lumigui_srcdir)/panels/panel.cpp										\
+	$(lumigui_srcdir)/panels/panel.hpp										\
+	$(lumigui_srcdir)/panels/timeline-panel.cpp								\
+	$(lumigui_srcdir)/panels/timeline-panel.hpp								\
+	$(lumigui_srcdir)/panels/viewer-panel.cpp								\
+	$(lumigui_srcdir)/panels/viewer-panel.hpp								\
+	$(lumigui_srcdir)/panels/assets-panel.cpp								\
+	$(lumigui_srcdir)/panels/assets-panel.hpp								\
+	$(lumigui_srcdir)/widgets/video-display-widget.cpp						\
+	$(lumigui_srcdir)/widgets/video-display-widget.hpp						\
+	$(lumigui_srcdir)/widgets/timeline-widget.cpp							\
+	$(lumigui_srcdir)/widgets/timeline-widget.hpp							\
+	$(lumigui_srcdir)/widgets/timeline/timeline-header-container.cpp		\
+	$(lumigui_srcdir)/widgets/timeline/timeline-header-container.hpp		\
+	$(lumigui_srcdir)/widgets/timeline/track.cpp							\
+	$(lumigui_srcdir)/widgets/timeline/track.hpp							\
+	$(lumigui_srcdir)/widgets/timeline/timeline-body.cpp					\
+	$(lumigui_srcdir)/widgets/timeline/timeline-body.hpp					\
+	$(lumigui_srcdir)/widgets/timeline/timeline-ruler.cpp					\
+	$(lumigui_srcdir)/widgets/timeline/timeline-ruler.hpp					\
+	$(lumigui_srcdir)/widgets/timeline/timeline-tool.cpp					\
+	$(lumigui_srcdir)/widgets/timeline/timeline-tool.hpp					\
+	$(lumigui_srcdir)/widgets/timeline/timeline-arrow-tool.cpp				\
+	$(lumigui_srcdir)/widgets/timeline/timeline-arrow-tool.hpp				\
+	$(lumigui_srcdir)/widgets/timeline/timeline-ibeam-tool.cpp				\
+	$(lumigui_srcdir)/widgets/timeline/timeline-ibeam-tool.hpp				\
+	$(lumigui_srcdir)/model/project.cpp										\
+	$(lumigui_srcdir)/model/project.hpp										\
+	$(lumigui_srcdir)/output/displayer.cpp									\
+	$(lumigui_srcdir)/output/displayer.hpp									\
+	$(lumigui_srcdir)/output/gdkdisplayer.cpp								\
+	$(lumigui_srcdir)/output/gdkdisplayer.hpp								\
+	$(lumigui_srcdir)/output/xvdisplayer.cpp								\
 	$(lumigui_srcdir)/output/xvdisplayer.hpp
 
 lumigui_LDFLAGS = 
 lumigui_LDADD = $(GTK_LUMIERA_LIBS) liblumicommon.a liblumi.a $(NOBUGMT_LUMIERA_LIBS)
 
-lumigui_DEPENDENCIES =											\
-	$(top_builddir)/lumiera_ui.rc								\
-	$(top_builddir)/liblumicommon.a								\
+lumigui_DEPENDENCIES =														\
+	$(top_builddir)/lumiera_ui.rc											\
+	$(top_builddir)/liblumicommon.a											\
 	$(top_builddir)/liblumi.a
 	 
 $(top_builddir)/lumiera_ui.rc:
diff --git a/src/gui/lumiera_ui.rc b/src/gui/lumiera_ui.rc
index 9d4f4d771..dcce8df48 100644
--- a/src/gui/lumiera_ui.rc
+++ b/src/gui/lumiera_ui.rc
@@ -152,13 +152,13 @@ style "timeline_ruler" = "default_base"
   gtkmm__CustomObject_TimelineRuler::playback_period_arrow_stem_size = 3
 }
 
-style "header_container" = "default_base"
+style "timeline_header_container" = "default_base"
 {
   gtkmm__CustomObject_HeaderContainer::heading_margin = 4
 }
 
 class "gtkmm__CustomObject_TimelineBody" style:highest "timeline_body"
 class "gtkmm__CustomObject_TimelineRuler" style:highest "timeline_ruler"
-class "gtkmm__CustomObject_HeaderContainer" style:highest "header_container"
+class "gtkmm__CustomObject_TimelineHeaderContainer" style:highest "timeline_header_container"
 
 
diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp
index 20014e675..6c397f9f1 100644
--- a/src/gui/widgets/timeline-widget.cpp
+++ b/src/gui/widgets/timeline-widget.cpp
@@ -53,7 +53,7 @@ TimelineWidget::TimelineWidget() :
 {
   body = new TimelineBody(this);
   ENSURE(body != NULL);
-  headerContainer = new HeaderContainer(this);
+  headerContainer = new TimelineHeaderContainer(this);
   ENSURE(headerContainer != NULL);
   ruler = new TimelineRuler(this);
   ENSURE(ruler != NULL);
diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp
index 9a43769ed..7785e7bc8 100644
--- a/src/gui/widgets/timeline-widget.hpp
+++ b/src/gui/widgets/timeline-widget.hpp
@@ -27,7 +27,7 @@
 #define TIMELINE_WIDGET_HPP
 
 #include "../gtk-lumiera.hpp"
-#include "timeline/header-container.hpp"
+#include "timeline/timeline-header-container.hpp"
 #include "timeline/timeline-body.hpp"
 #include "timeline/timeline-ruler.hpp"
 #include "timeline/timeline-tool.hpp"
@@ -228,7 +228,7 @@ protected:
   std::vector tracks;
 
   // Child Widgets
-  timeline::HeaderContainer *headerContainer;
+  timeline::TimelineHeaderContainer *headerContainer;
   timeline::TimelineBody *body;
   timeline::TimelineRuler *ruler;
 
@@ -257,7 +257,7 @@ protected:
   static const double ZoomIncrement;
 
   friend class timeline::TimelineBody;
-  friend class timeline::HeaderContainer;
+  friend class timeline::TimelineHeaderContainer;
   friend class timeline::TimelineRuler;
   friend class timeline::Tool;
   friend class timeline::ArrowTool;
diff --git a/src/gui/widgets/timeline/header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp
similarity index 88%
rename from src/gui/widgets/timeline/header-container.cpp
rename to src/gui/widgets/timeline/timeline-header-container.cpp
index 27812ccd1..ba8323aab 100644
--- a/src/gui/widgets/timeline/header-container.cpp
+++ b/src/gui/widgets/timeline/timeline-header-container.cpp
@@ -1,5 +1,6 @@
 /*
-  header-container.cpp  -  Implementation of the header container widget
+  timeline-header-container.cpp  -  Implementation of the timeline
+  header container widget
  
   Copyright (C)         Lumiera.org
     2008,               Joel Holdsworth 
@@ -22,7 +23,7 @@
 
 #include 
 
-#include "header-container.hpp"
+#include "timeline-header-container.hpp"
 #include "track.hpp"
 #include "../timeline-widget.hpp"
 
@@ -33,9 +34,9 @@ namespace gui {
 namespace widgets {
 namespace timeline {
 
-HeaderContainer::HeaderContainer(gui::widgets::TimelineWidget
+TimelineHeaderContainer::TimelineHeaderContainer(gui::widgets::TimelineWidget
     *timeline_widget) :
-    Glib::ObjectBase("HeaderContainer"),
+    Glib::ObjectBase("TimelineHeaderContainer"),
     timelineWidget(timeline_widget),
     margin(-1)
 {
@@ -49,14 +50,14 @@ HeaderContainer::HeaderContainer(gui::widgets::TimelineWidget
   // Connect to the timeline widget's vertical scroll event,
   // so that we get notified when the view shifts
   timelineWidget->verticalAdjustment.signal_value_changed().connect(
-    sigc::mem_fun(this, &HeaderContainer::on_scroll) );
+    sigc::mem_fun(this, &TimelineHeaderContainer::on_scroll) );
     
   // Install style properties
   register_styles();
 }
   
 void
-HeaderContainer::update_headers()
+TimelineHeaderContainer::update_headers()
 {
   REQUIRE(timelineWidget != NULL);
   
@@ -83,7 +84,7 @@ HeaderContainer::update_headers()
 }
   
 void
-HeaderContainer::on_realize()
+TimelineHeaderContainer::on_realize()
 {
   set_flags(Gtk::NO_WINDOW);
   
@@ -119,7 +120,7 @@ HeaderContainer::on_realize()
 }
   
 void
-HeaderContainer::on_unrealize()
+TimelineHeaderContainer::on_unrealize()
 {
   // Unreference any window we may have created
   gdkWindow.clear();
@@ -129,7 +130,7 @@ HeaderContainer::on_unrealize()
 }
 
 void
-HeaderContainer::on_size_request (Requisition* requisition)
+TimelineHeaderContainer::on_size_request (Requisition* requisition)
 { 
   // Initialize the output parameter:
   *requisition = Gtk::Requisition();
@@ -148,7 +149,7 @@ HeaderContainer::on_size_request (Requisition* requisition)
 }
   
 void
-HeaderContainer::on_size_allocate (Allocation& allocation)
+TimelineHeaderContainer::on_size_allocate (Allocation& allocation)
 { 
   // Use the offered allocation for this container:
   set_allocation(allocation);
@@ -162,7 +163,7 @@ HeaderContainer::on_size_allocate (Allocation& allocation)
 }
   
 void
-HeaderContainer::forall_vfunc(gboolean /* include_internals */,
+TimelineHeaderContainer::forall_vfunc(gboolean /* include_internals */,
         GtkCallback callback, gpointer callback_data)
 { 
   BOOST_FOREACH( RootHeader &header, rootHeaders )
@@ -173,7 +174,7 @@ HeaderContainer::forall_vfunc(gboolean /* include_internals */,
 }
 
 bool
-HeaderContainer::on_expose_event(GdkEventExpose *event)
+TimelineHeaderContainer::on_expose_event(GdkEventExpose *event)
 {
   if(gdkWindow)
     {
@@ -211,7 +212,7 @@ HeaderContainer::on_expose_event(GdkEventExpose *event)
 }
   
 void
-HeaderContainer::on_scroll()
+TimelineHeaderContainer::on_scroll()
 {
   // If the scroll has changed, we will have to shift all the
   // header widgets
@@ -219,7 +220,7 @@ HeaderContainer::on_scroll()
 }
   
 void
-HeaderContainer::layout_headers()
+TimelineHeaderContainer::layout_headers()
 {
   ASSERT(timelineWidget != NULL);
   
@@ -261,7 +262,7 @@ HeaderContainer::layout_headers()
 }
 
 void
-HeaderContainer::register_styles() const
+TimelineHeaderContainer::register_styles() const
 {
   GtkWidgetClass *klass = GTK_WIDGET_CLASS(G_OBJECT_GET_CLASS(gobj()));
 
@@ -273,7 +274,7 @@ HeaderContainer::register_styles() const
 }
 
 void
-HeaderContainer::read_styles()
+TimelineHeaderContainer::read_styles()
 {
   if(margin <= 0)
     get_style_property("heading_margin", margin);
diff --git a/src/gui/widgets/timeline/header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp
similarity index 90%
rename from src/gui/widgets/timeline/header-container.hpp
rename to src/gui/widgets/timeline/timeline-header-container.hpp
index 84f15116d..480ab6cde 100644
--- a/src/gui/widgets/timeline/header-container.hpp
+++ b/src/gui/widgets/timeline/timeline-header-container.hpp
@@ -1,5 +1,6 @@
 /*
-  header-container.hpp  -  Declaration of the header container widget
+  timeline-header-container.cpp  -  Declaration of the timeline
+  header container widget
  
   Copyright (C)         Lumiera.org
     2008,               Joel Holdsworth 
@@ -19,7 +20,7 @@
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  
 */
-/** @file header-container.hpp
+/** @file timeline-header-container.hpp
  ** This file contains the definition of the header container
  ** widget
  */
@@ -40,11 +41,11 @@ namespace timeline {
 class Track;
 
 /**
- * A helper class for the TimelineWidget. HeaderContainer is
- * container widget for all the left-hand-side header widgets
+ * A helper class for the TimelineWidget. TimelineHeaderContainer
+ * is container widget for all the left-hand-side header widgets
  * associated with timeline tracks.
  */
-class HeaderContainer : public Gtk::Container
+class TimelineHeaderContainer : public Gtk::Container
 {
 public:
   /**
@@ -52,7 +53,7 @@ public:
    *
    * @param[in] timeline_widget A pointer to the owner timeline widget
    */
-  HeaderContainer(gui::widgets::TimelineWidget* timeline_widget);
+  TimelineHeaderContainer(gui::widgets::TimelineWidget* timeline_widget);
   
   /**
    * Attaches the header all the header widgets of root

From 3a4175868275f615456442e1c9a9383825c0f0fb Mon Sep 17 00:00:00 2001
From: Joel Holdsworth 
Date: Sat, 18 Oct 2008 12:25:18 +0100
Subject: [PATCH 004/249] Changed the "delete" variable name to "del" to
 satisfy the C++ compiler

---
 src/lib/psplay.c | 18 +++++++++---------
 src/lib/psplay.h |  6 +++---
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/lib/psplay.c b/src/lib/psplay.c
index 7647fd905..1d2d4dd27 100644
--- a/src/lib/psplay.c
+++ b/src/lib/psplay.c
@@ -66,7 +66,7 @@ static inline uint32_t psplay_fast_prng ()
 
 
 PSplay
-psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete)
+psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn del)
 {
   NOBUG_INIT_FLAG (psplay);
   TRACE (psplay);
@@ -79,7 +79,7 @@ psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn
       self->found_parent = &self->tree;
       self->cmp = cmp;
       self->key = key;
-      self->delete = delete;
+      self->del = del;
       self->elem_cnt = 0;
       self->log2 = 0;
     }
@@ -88,12 +88,12 @@ psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn
 
 
 PSplay
-psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete)
+psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn del)
 {
   PSplay self = malloc (sizeof *self);
   if (self)
     {
-      psplay_init (self , cmp, key, delete);
+      psplay_init (self , cmp, key, del);
     }
   return self;
 }
@@ -107,8 +107,8 @@ psplay_destroy (PSplay self)
   if (self) while (self->tree)
     {
       PSplaynode n = psplay_remove (self, self->tree);
-      if (self->delete)
-        self->delete (n);
+      if (self->del)
+        self->del (n);
     }
   return self;
 }
@@ -400,7 +400,7 @@ void
 psplay_delete_node (PSplay self, PSplaynode node)
 {
   if (node)
-    self->delete (psplay_remove (self, node));
+    self->del (psplay_remove (self, node));
 }
 
 
@@ -428,8 +428,8 @@ psplay_handle (PSplay self, PSplaynode node, psplay_delete_fn res)
   else if (res == PSPLAY_REMOVE)
     {
       psplay_remove (self, node);
-      if (self->delete)
-        self->delete (node);
+      if (self->del)
+        self->del (node);
     }
   else
     {
diff --git a/src/lib/psplay.h b/src/lib/psplay.h
index b3c016c52..70c450fe3 100644
--- a/src/lib/psplay.h
+++ b/src/lib/psplay.h
@@ -94,7 +94,7 @@ struct psplay_struct
   PSplaynode* found_parent;             /* maybe direct parent of last found node, used for fast remove */
   psplay_cmp_fn cmp;
   psplay_key_fn key;
-  psplay_delete_fn delete;
+  psplay_delete_fn del;
 
   size_t elem_cnt;
   unsigned log2;                        /* roughly log2 of the elem_cnt*/
@@ -122,7 +122,7 @@ psplay_nelements (PSplay self)
  * @return self
  */
 PSplay
-psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete);
+psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn del);
 
 
 /**
@@ -142,7 +142,7 @@ psplay_destroy (PSplay self);
  * @return allcoated splay tree or NULL on error
  */
 PSplay
-psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete);
+psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn del);
 
 
 /**

From 74164e890ebb25449a266500914832927f3d5e84 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Mon, 20 Oct 2008 03:13:02 +0200
Subject: [PATCH 005/249] finished the outline

---
 src/common/visitordispatcher.hpp |   4 +-
 src/lib/allocationcluster.cpp    |   8 +-
 src/lib/allocationcluster.hpp    | 160 ++++++++++++++++++++++++++++---
 3 files changed, 157 insertions(+), 15 deletions(-)

diff --git a/src/common/visitordispatcher.hpp b/src/common/visitordispatcher.hpp
index dcc28391b..4ed6a52e2 100644
--- a/src/common/visitordispatcher.hpp
+++ b/src/common/visitordispatcher.hpp
@@ -100,9 +100,9 @@ namespace lumiera
     
     
     /**
-     * For each posible call entry point via some subclass of the visitable hierarchy,
+     * For each possible call entry point via some subclass of the visitable hierarchy,
      * we maintain a dispatcher table to keep track of all concrete tool implementations
-     * able to recieve and process calls on objects of this subclass.
+     * able to receive and process calls on objects of this subclass.
      */
     template
     class Dispatcher
diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp
index c0172446e..32be6fa54 100644
--- a/src/lib/allocationcluster.cpp
+++ b/src/lib/allocationcluster.cpp
@@ -31,7 +31,13 @@
 
 namespace lib {
   
-  
+  class AllocationCluster::MemoryManager
+    {
+      
+    };
+
+
+
   /** creating a new AllocationCluster prepares a table capable
    *  of holding the individual object families to come. Each of those
    *  is managed by a separate instance of the low-level memory manager.
diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp
index 4e35f8485..f9c63eccf 100644
--- a/src/lib/allocationcluster.hpp
+++ b/src/lib/allocationcluster.hpp
@@ -27,7 +27,16 @@
  ** segment are strongly interconnected, and thus each segment is 
  ** being built in a single build process and is replaced or released
  ** as a whole. AllocationCluster implements memory management to
- ** support this usage pattern. 
+ ** support this usage pattern.
+ ** 
+ ** @note this file is organised in a way which doesn't bind the
+ ** client code to the memory manager implementation. Parts of the
+ ** interface depending on the usage situation are implemented using
+ ** templates, and thus need to be in the header. This way they can
+ ** exploit the type information available in call context. This
+ ** information is passed to generic implementation functions
+ ** defined in allocationcluster.cpp . In a similar vein, the 
+ ** AllocationCluster::MemoryManger is just forward declared.
  **
  ** @see allocationclustertest.cpp
  ** @see builder::ToolFactory
@@ -38,16 +47,20 @@
 #ifndef LIB_ALLOCATIONCLUSTER_H
 #define LIB_ALLOCATIONCLUSTER_H
 
-//#include 
+#include 
 #include 
-//#include 
+#include 
 #include 
 
+#include "common/multithread.hpp"
+#include "common/error.hpp"
+#include "common/util.hpp"
+
 
 
 namespace lib {
   using std::string;
-//  using boost::scoped_ptr;
+  using boost::scoped_ptr;
 
 
   /**
@@ -75,7 +88,7 @@ namespace lib {
       create ()
         {
           TY* obj = new(allocation()) TY();
-          return success(obj);
+          return commit(obj);
         }
       
       template
@@ -83,7 +96,7 @@ namespace lib {
       create (P0& p0)
         {
           TY* obj = new(allocation()) TY (p0);
-          return success(obj);
+          return commit(obj);
         }
       
       template
@@ -91,7 +104,7 @@ namespace lib {
       create (P0& p0, P1& p1)
         {
           TY* obj = new(allocation()) TY (p0,p1);
-          return success(obj);
+          return commit(obj);
         }
       
       template
@@ -99,7 +112,7 @@ namespace lib {
       create (P0& p0, P1& p1, P2& p2)
         {
           TY* obj = new(allocation()) TY (p0,p1,p2);
-          return success(obj);
+          return commit(obj);
         }
       
       template
@@ -107,7 +120,7 @@ namespace lib {
       create (P0& p0, P1& p1, P2& p2, P3& p3)
         {
           TY* obj = new(allocation()) TY (p0,p1,p2,p3);
-          return success(obj);
+          return commit(obj);
         }
 
       
@@ -120,12 +133,135 @@ namespace lib {
       /** finish the allocation after the ctor is successful */
       template
       TY&
-      success (TY* obj);
+      commit (TY* obj);
+      
+      
+      /**
+       * The type-specific configuration information
+       * any low-level memory manager needs to know
+       */
+      struct TypeInfo;
+      
+      /**
+       * low-level memory manager responsible for
+       * the allocations of one specific type.  
+       */
+      class MemoryManager;
+      
+      /**
+       * organising the association Type -> table entry
+       */
+      template
+      struct TypeSlot;
+      
+      static size_t maxTypeIDs;
+      
+      
+      typedef scoped_ptr PMemManager;
+      typedef std::vector ManagerTable;
+      ManagerTable typeHandlers_;
+      
+      
+      /** implementation of the actual memory allocation
+       *  is pushed down to the MemoryManager impl. */
+      void* initiateAlloc (PMemManager&);
+      
+      /** enrol the allocation after successful ctor call */ 
+      void finishAlloc (PMemManager&, void*);
+      
+      /** create a new MemoryManager implementation */
+      MemoryManager* setupMemoryManager (TypeInfo);
     };
-    
+  
+  
+  
+  
+  
+  //-----implementation-details------------------------
+  
+  struct AllocationCluster::TypeInfo
+        {
+          size_t allocSize;
+          void (*killIt)(void*);
+          
+          template
+          TypeInfo(TY*)
+            : allocSize(sizeof(TY)),
+              killIt(&TypeSlot::kill)
+            { }
+        };
+  
   
 
+  template
+  struct AllocationCluster::TypeSlot
+    {
+      static size_t id_; ///< table pos of the memory manager in charge for type TY
+      
+      static PMemManager&
+      get(ManagerTable& handlers)
+        {
+          ENSURE (id_ < handlers.size() || 1 <= handlers.size()); // 0th Element used as "undefined" marker
+          
+          return handlers[id_ guard   SIDEEFFECT;
+          if (!id_)
+            id_= ++maxTypeIDs;
+          if (id_ >= handlers.size())
+            handlers.resize(id_);
+          if (!handlers[id_])
+            handlers[id_].reset (setupMemoryManager (TypeInfo((TY*)0)));
+        }
+      
+      static void
+      kill (void* obj)
+        {
+          ASSERT (INSTANCEOF (TY,obj));
+          TY* p = static_cast(obj);
+          ASSERT (p);
+          p->~TY();
+        }
+      
+    };
+  
+  
+  /** storage for static bookkeeping of type allocation slots */
+  template
+  size_t AllocationCluster::TypeSlot::id_;
+    
+  size_t AllocationCluster::maxTypeIDs;
+  
+  
 
-
+  
+  template
+  void*
+  AllocationCluster::allocation()
+  {
+    scoped_ptr typeHandler (TypeSlot::get (typeHandlers_));
+    if (!typeHandler)
+      TypeSlot::setup (typeHandlers_);
+    return initiateAlloc (typeHandler);
+  }
+    
+  template
+  TY&
+  AllocationCluster::commit (TY* obj)
+  {
+    scoped_ptr typeHandler (TypeSlot::get (typeHandlers_));
+    REQUIRE (typeHandler);
+    REQUIRE (obj);
+    finishAlloc (typeHandler, obj);
+    return *obj;
+  }
+  
+  
+  
+  
 } // namespace lib
 #endif

From 490b7d163cf3047af45d9257ea46daf238e76feb Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Mon, 20 Oct 2008 03:33:55 +0200
Subject: [PATCH 006/249] doc cleanup

---
 doc/devel/draw/AllocationCluster.svg | 199 ++-------------------------
 wiki/draw/AllocationCluster.png      | Bin 15026 -> 15306 bytes
 wiki/renderengine.html               |   4 +-
 3 files changed, 11 insertions(+), 192 deletions(-)

diff --git a/doc/devel/draw/AllocationCluster.svg b/doc/devel/draw/AllocationCluster.svg
index b2e91a268..968a15311 100644
--- a/doc/devel/draw/AllocationCluster.svg
+++ b/doc/devel/draw/AllocationCluster.svg
@@ -6,7 +6,6 @@
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
    width="800"
@@ -25,9 +24,9 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="1"
-     inkscape:cx="280.90499"
-     inkscape:cy="352.82916"
+     inkscape:zoom="2.8284271"
+     inkscape:cx="311.29718"
+     inkscape:cy="408.68554"
      inkscape:document-units="px"
      inkscape:current-layer="svg2"
      inkscape:window-width="1485"
@@ -54,186 +53,6 @@
      guidetolerance="5" />
   
-    
-      
-      
-      
-    
-    
-      
-      
-      
-      
-    
-    
-      
-      
-      
-      
-    
-    
-      
-      
-      
-    
-    
-      
-      
-      
-      
-    
-    
-      
-      
-      
-      
-      
-    
-    
-      
-      
-    
-    
-      
-      
-      
-      
-    
-    
-      
-      
-      
-    
-    
-    
-      
-      
-      
-    
     
   
   
   <T2>
   raw storage
   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
JbJgeme*p$2%)kHu

literal 15026
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
KPKB1!%l`p?5*!8q

diff --git a/wiki/renderengine.html b/wiki/renderengine.html
index b8cd1c799..f29e753cc 100644
--- a/wiki/renderengine.html
+++ b/wiki/renderengine.html
@@ -514,7 +514,7 @@ ColorPalette
 
 SiteUrl
-
+
Memory management facility for the low-level model (render nodes network). The model is organised into temporal segments, which are considered to be structurally constant and uniform. The objects within each segment are strongly interconnected, and thus each segment is being built in a single build process and is replaced or released as a whole. __~AllocationCluster__ implements memory management to support this usage pattern. He owns a number of object families of various types.[>img[draw/AllocationCluster.png]]
 * [[processing nodes|ProcNode]] &mdash; probably with several subclasses (?)
 * [[wiring descriptors|WiringDescriptor]]
@@ -523,7 +523,7 @@ SiteUrl
To Each of those families we can expect an initially undetermined (but rather large) number of individual objects, which can be expected to be allocated within a short timespan and which are to be released cleanly on destruction of the AllocationCluster. ''Problem of calling the dtors'' -Even if the low-level memory manager(s) may use raw storage, we require that the allocated objects desctuctores be called. This means keeping track at least of the number of objects acllocated (without wasting too much memory for bookeeping). Besides, as the objects are expected to be interconnected, it may be dangerous to destroy a given family of objects while another family of objects may rely on the former in its destructor. //If we happen do get into this situation,// we need to define a priority order on the types and assure the destruction sequence is respected. +Even if the low-level memory manager(s) may use raw storage, we require that the allocated object's destructors be called. This means keeping track at least of the number of objects allocated (without wasting too much memory for bookkeeping). Besides, as the objects are expected to be interconnected, it may be dangerous to destroy a given family of objects while another family of objects may rely on the former in its destructor. //If we happen do get into this situation,// we need to define a priority order on the types and assure the destruction sequence is respected. &rarr; see MemoryManagement From eaa89067bb2f9359b2d279290d17dd1375743b8f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 20 Oct 2008 06:27:14 +0200 Subject: [PATCH 007/249] WIP test covering the AllocationCluster draft --- src/lib/allocationcluster.hpp | 20 ++- tests/common/allocationclustertest.cpp | 193 +++++++++++++++++++++++++ 2 files changed, 205 insertions(+), 8 deletions(-) create mode 100644 tests/common/allocationclustertest.cpp diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp index f9c63eccf..d9ce5d660 100644 --- a/src/lib/allocationcluster.hpp +++ b/src/lib/allocationcluster.hpp @@ -76,11 +76,11 @@ namespace lib { * aren't used after shutting down a given AllocationCluster. */ class AllocationCluster - : boost::noncopyable { public: AllocationCluster (); + AllocationCluster (const AllocationCluster&); ~AllocationCluster () throw(); template @@ -170,7 +170,7 @@ namespace lib { void finishAlloc (PMemManager&, void*); /** create a new MemoryManager implementation */ - MemoryManager* setupMemoryManager (TypeInfo); + static MemoryManager* setupMemoryManager (TypeInfo const&); }; @@ -202,6 +202,7 @@ namespace lib { get(ManagerTable& handlers) { ENSURE (id_ < handlers.size() || 1 <= handlers.size()); // 0th Element used as "undefined" marker + TODO ("this is very fishy and probably not threadsafe...!"); return handlers[id_= handlers.size()) handlers.resize(id_); if (!handlers[id_]) - handlers[id_].reset (setupMemoryManager (TypeInfo((TY*)0))); + { + TY* type_hint(0); + TypeInfo info (type_hint); + handlers[id_].reset (setupMemoryManager (info)); + } } static void kill (void* obj) { - ASSERT (INSTANCEOF (TY,obj)); TY* p = static_cast(obj); ASSERT (p); + ASSERT (INSTANCEOF (TY,p)); p->~TY(); } @@ -243,17 +248,16 @@ namespace lib { void* AllocationCluster::allocation() { - scoped_ptr typeHandler (TypeSlot::get (typeHandlers_)); - if (!typeHandler) + if (!TypeSlot::get (typeHandlers_)) TypeSlot::setup (typeHandlers_); - return initiateAlloc (typeHandler); + return initiateAlloc (TypeSlot::get (typeHandlers_)); } template TY& AllocationCluster::commit (TY* obj) { - scoped_ptr typeHandler (TypeSlot::get (typeHandlers_)); + PMemManager & typeHandler (TypeSlot::get (typeHandlers_)); REQUIRE (typeHandler); REQUIRE (obj); finishAlloc (typeHandler, obj); diff --git a/tests/common/allocationclustertest.cpp b/tests/common/allocationclustertest.cpp new file mode 100644 index 000000000..d9fc1ddad --- /dev/null +++ b/tests/common/allocationclustertest.cpp @@ -0,0 +1,193 @@ +/* + AllocationCluster(Test) - verify bulk (de)allocating a family of objects + + 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. + +* *****************************************************/ + + + +#include "common/test/run.hpp" +#include "common/util.hpp" + +#include "lib/allocationcluster.hpp" + +#include +#include +#include + +using boost::lexical_cast; +using util::for_each; +using util::isnil; +using ::Test; + +using std::numeric_limits; +using std::vector; + +namespace lib { + namespace test { + + namespace { // a family of test dummy classes + + uint NUM_CLUSTERS = 5; + uint NUM_OBJECTS = 500; + uint NUM_FAMILIES = 5; + + long checksum = 0; + + template + class Dummy + { + char content[i]; + + public: + Dummy (char id) + { + content[0] = id; + checksum += id; + } + Dummy (char i1, char i2, char i3=0) + { + char id = i1 + i2 + i3; + content[0] = id; + if (0 == (rand() % 20)) + throw id; + checksum += id; + } + + ~Dummy() + { + checksum -= content[0]; + } + }; + + + typedef vector ClusterList; + + inline char + truncChar (uint x) + { + return x % numeric_limits::max(); + } + + template + void + place_object (AllocationCluster& clu, uint id) + { + clu.create > (id); + } + + typedef void (Invoker)(AllocationCluster&, uint); + + Invoker* invoke[20] = { &place_object<1> + , &place_object<2> + , &place_object<3> + , &place_object<5> + , &place_object<10> + , &place_object<13> + , &place_object<14> + , &place_object<15> + , &place_object<16> + , &place_object<17> + , &place_object<18> + , &place_object<19> + , &place_object<20> + , &place_object<25> + , &place_object<30> + , &place_object<35> + , &place_object<40> + , &place_object<50> + , &place_object<100> + , &place_object<200> + }; + + void + fillIt (AllocationCluster& clu) + { + if (20 (arg[0]); + if (1 < arg.size()) NUM_OBJECTS = lexical_cast (arg[1]); + if (2 < arg.size()) NUM_FAMILIES = lexical_cast (arg[2]); + + checkAllocation(); + checkErrorHandling(); + } + + void + checkAllocation() + { + ASSERT (0==checksum); + { + ClusterList clusters (NUM_CLUSTERS); + for_each (clusters, fillIt); + ASSERT (0!=checksum); + } + ASSERT (0==checksum); + } + + void + checkErrorHandling() + { + ASSERT (0==checksum); + { + AllocationCluster clu; + for (uint i=0; i > (i1,i2); + } + catch (char id) + { + checksum -= id; + } + } + ASSERT (0==checksum); + } + }; + + LAUNCHER (AllocationCluster_test, "unit common"); + + + }// namespace test + +} // namespace lib + From d880b341b45e96e724d69b1a04abff7cfb5e298c Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Mon, 20 Oct 2008 18:50:37 +0100 Subject: [PATCH 008/249] Showed some love to viewer panel --- src/gui/panels/viewer-panel.cpp | 16 ++++------------ src/gui/panels/viewer-panel.hpp | 24 ++++++++++++++++-------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/gui/panels/viewer-panel.cpp b/src/gui/panels/viewer-panel.cpp index 4ebd3d0cb..e280694f3 100644 --- a/src/gui/panels/viewer-panel.cpp +++ b/src/gui/panels/viewer-panel.cpp @@ -31,18 +31,10 @@ namespace panels { ViewerPanel::ViewerPanel() : Panel("viewer", _("Viewer"), "panel_viewer") - { - //----- Set up the Tool Bar -----// - // Add the commands - - - // Configure the toolbar - toolBar.set_toolbar_style(TOOLBAR_ICONS); - - //----- Pack in the Widgets -----// - pack_start(display, PACK_EXPAND_WIDGET); - pack_start(toolBar, PACK_SHRINK); - } +{ + //----- Pack in the Widgets -----// + pack_start(display, PACK_EXPAND_WIDGET); +} } // namespace panels } // namespace gui diff --git a/src/gui/panels/viewer-panel.hpp b/src/gui/panels/viewer-panel.hpp index 0185e6d4a..a53e30561 100644 --- a/src/gui/panels/viewer-panel.hpp +++ b/src/gui/panels/viewer-panel.hpp @@ -34,16 +34,24 @@ namespace gui { namespace panels { - class ViewerPanel : public Panel - { - public: - ViewerPanel(); +/** + * A panel to display the video output. + **/ +class ViewerPanel : public Panel +{ +public: + /** + * Contructor. + **/ + ViewerPanel(); - protected: +protected: - gui::widgets::VideoDisplayWidget display; - Gtk::Toolbar toolBar; - }; + /** + * The video display widget, which will display the video. + **/ + gui::widgets::VideoDisplayWidget display; +}; } // namespace panels } // namespace gui From 6396323e9e89d45467424234234fdbec838ab219 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Mon, 20 Oct 2008 18:51:46 +0100 Subject: [PATCH 009/249] Added the backend as a lib, and included the interface header --- src/gui/Makefile.am | 3 ++- src/gui/gtk-lumiera.cpp | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 7e8d356ea..4b7504ef1 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -77,7 +77,8 @@ lumigui_SOURCES = \ $(lumigui_srcdir)/output/xvdisplayer.hpp lumigui_LDFLAGS = -lumigui_LDADD = $(GTK_LUMIERA_LIBS) liblumicommon.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) +lumigui_LDADD = $(GTK_LUMIERA_LIBS) liblumibackend.a liblumicommon.a \ + liblumi.a $(NOBUGMT_LUMIERA_LIBS) lumigui_DEPENDENCIES = \ $(top_builddir)/lumiera_ui.rc \ diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index 1a895084f..c73e45977 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -32,6 +32,10 @@ #include "workspace/workspace-window.hpp" #include "model/project.hpp" +extern "C" { +#include "backend/interface.h" +} + NOBUG_CPP_DEFINE_FLAG(gui); using namespace Gtk; From ee6fac5914ece1a63fb96e9b833daeeafa127e7b Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Mon, 20 Oct 2008 19:19:06 +0100 Subject: [PATCH 010/249] Made GtkLumiera and WindowManager boost::noncopyable --- src/gui/gtk-lumiera.hpp | 3 ++- src/gui/window-manager.hpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index 180148f7f..a25927712 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -31,6 +31,7 @@ #include #include #include +#include extern "C" { #include @@ -91,7 +92,7 @@ static const gchar* AppAuthors[] = { /** * The main application class. */ -class GtkLumiera +class GtkLumiera : private boost::noncopyable { public: int main(int argc, char *argv[]); diff --git a/src/gui/window-manager.hpp b/src/gui/window-manager.hpp index c25a763ef..49c69ea50 100644 --- a/src/gui/window-manager.hpp +++ b/src/gui/window-manager.hpp @@ -35,7 +35,7 @@ namespace gui { /** * The centralised manager of all lumiera-gui's windows. **/ -class WindowManager +class WindowManager : private boost::noncopyable { public: /** From 1e3df8028841508528ea71f0832b32f2a853a76b Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Mon, 20 Oct 2008 19:28:29 +0100 Subject: [PATCH 011/249] Added linkage to the proc layer --- src/gui/Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 4b7504ef1..835e5f1a5 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -29,9 +29,9 @@ lumigui_CPPFLAGS = $(AM_CPPFLAGS) \ bin_PROGRAMS += lumigui lumigui_SOURCES = \ - $(lumigui_srcdir)/gtk-lumiera.cpp \ + $(lumigui_srcdir)/gtk-lumiera.cpp \ $(lumigui_srcdir)/gtk-lumiera.hpp \ - $(lumigui_srcdir)/window-manager.cpp \ + $(lumigui_srcdir)/window-manager.cpp \ $(lumigui_srcdir)/window-manager.hpp \ $(lumigui_srcdir)/workspace/actions.cpp \ $(lumigui_srcdir)/workspace/actions.hpp \ @@ -77,8 +77,8 @@ lumigui_SOURCES = \ $(lumigui_srcdir)/output/xvdisplayer.hpp lumigui_LDFLAGS = -lumigui_LDADD = $(GTK_LUMIERA_LIBS) liblumibackend.a liblumicommon.a \ - liblumi.a $(NOBUGMT_LUMIERA_LIBS) +lumigui_LDADD = $(GTK_LUMIERA_LIBS) liblumiproc.a liblumibackend.a \ + liblumicommon.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) lumigui_DEPENDENCIES = \ $(top_builddir)/lumiera_ui.rc \ From 1e3a03b4c5203d052bfafb486248042f273143ba Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 21 Oct 2008 09:04:59 +0200 Subject: [PATCH 012/249] WIP dealing with object collections taking ownership --- src/lib/allocationcluster.hpp | 10 +- src/lib/scopedholder.hpp | 198 +++++++++++++++++++++++++ tests/common/allocationclustertest.cpp | 11 +- 3 files changed, 210 insertions(+), 9 deletions(-) create mode 100644 src/lib/scopedholder.hpp diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp index d9ce5d660..67645b04b 100644 --- a/src/lib/allocationcluster.hpp +++ b/src/lib/allocationcluster.hpp @@ -48,18 +48,17 @@ #define LIB_ALLOCATIONCLUSTER_H #include -#include #include #include #include "common/multithread.hpp" #include "common/error.hpp" #include "common/util.hpp" +#include "lib/scopedholder.hpp" namespace lib { - using std::string; using boost::scoped_ptr; @@ -158,7 +157,7 @@ namespace lib { typedef scoped_ptr PMemManager; - typedef std::vector ManagerTable; + typedef std::vector > ManagerTable; ManagerTable typeHandlers_; @@ -214,12 +213,13 @@ namespace lib { if (!id_) id_= ++maxTypeIDs; if (id_ >= handlers.size()) - handlers.resize(id_); + for (size_t idx=handlers.size(); idx()); ////////////////////////////////////////TODO calls ~MemoryManager() but shouldn't if (!handlers[id_]) { TY* type_hint(0); TypeInfo info (type_hint); - handlers[id_].reset (setupMemoryManager (info)); + handlers[id_].reset (setupMemoryManager (info)); ////////////////////////////////////////TODO calls ~MemoryManager() but shouldn't } } diff --git a/src/lib/scopedholder.hpp b/src/lib/scopedholder.hpp new file mode 100644 index 000000000..f82ee1bba --- /dev/null +++ b/src/lib/scopedholder.hpp @@ -0,0 +1,198 @@ +/* + SCOPEDHOLDER.hpp - general purpose wrapper for dealing with ownership problems + + 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 scopedholder.hpp + ** Some wrappers for coping with ownership problems. + ** Working with collections of objects, especially in conjunction with + ** polymorphism, can be challenging when we are bound to care for lifecycle + ** and ownership for the contained classes. There are several solutions, + ** including the boost::ptr_container library, the use of shared_ptr + ** or even a garbage collector. Sometimes the circumstances rather call + ** for a very simple or lightweight solution though. + ** + ** ScopedPtrHolder is a small extension to boost::scoped_ptr, enabling + ** to use it within STL containers if we stick to a specific protocol. + ** The idea is to permit copying as long as the scoped_ptr is empty. + ** This can be used to allow for extension of the STL container on + ** demand, i.e. to handle the typical situation of a registry which + ** is initialised lazily, but only released in a controlled fashion. + ** + ** ScopedHolder implements a similar concept for in-place storage of + ** noncopyable objects within STL containers. + ** + ** @see scopedholdertest.cpp + ** @see AllocationCluster usage example + */ + + +#ifndef LIB_SCOPEDHOLDER_H +#define LIB_SCOPEDHOLDER_H + +#include + +#include "common/error.hpp" + + + +namespace lib { + + + + + /** + * Extension to boost::scoped_ptr, allowing copy operations + * as long as the pointer is still null. + * @throw error::Logic on attempt to copy otherwise + */ + template + class ScopedPtrHolder + : public boost::scoped_ptr + { + typedef boost::scoped_ptr _Parent; + + + public: + ScopedPtrHolder () + : _Parent(0) + { } + + template + explicit ScopedPtrHolder (SU * p) // never throws + : _Parent(p) + { } + + template + explicit ScopedPtrHolder (std::auto_ptr p) // never throws + : _Parent(p.release()) + { } + + ScopedPtrHolder (ScopedPtrHolder const& ref) + : _Parent(must_be_null (ref)) + { } + + ScopedPtrHolder& + operator= (ScopedPtrHolder const& ref) + { + must_be_null (*this); + must_be_null (ref); + return *this; + } + + + private: + static B* must_be_null (_Parent const& ptr) + { + if (ptr) + throw lumiera::error::Logic("ScopedPtrHolder protocol violation: " + "attempt to copy from non-null."); + return 0; + } + }; + + + + + template + class ScopedHolder + { + char content_[sizeof(TY)]; + char created_; + + typedef ScopedHolder _ThisType; + + + public: + ScopedHolder() + : created_(0) + { } + + TY& + create () + { + ASSERT (!created_); + TY * obj = new(content_) TY(); + ++created_; + return *obj; + } + + ~ScopedHolder() + { + if (created_) + content_->~TY(); + } + + + ScopedHolder (ScopedHolder const& ref) + : created_(must_be_empty (ref)) + { } + + ScopedHolder& + operator= (ScopedHolder const& ref) + { + must_be_empty (*this); + must_be_empty (ref); + return *this; + } + + + TY& + operator* () const // never throws + { + ASSERT (created_); + return (TY&) content_; + } + + TY* + operator-> () const // never throws + { + ASSERT (created_); + return (TY*) &content_; + } + + TY* get() const { return &content_; } + bool operator! () const { return !created_; } + + + typedef char _ThisType::*unspecified_bool_type; + + /** implicit conversion to "bool" */ + operator unspecified_bool_type() const // never throws + { + return created_? &_ThisType::created_ : 0; + } + + + private: + static char must_be_empty (_ThisType const& ref) + { + if (ref) + throw lumiera::error::Logic("ScopedHolder protocol violation: " + "attempt after having invoked create()."); + return 0; + } + }; + + + + +} // namespace lib +#endif diff --git a/tests/common/allocationclustertest.cpp b/tests/common/allocationclustertest.cpp index d9fc1ddad..27f37cff0 100644 --- a/tests/common/allocationclustertest.cpp +++ b/tests/common/allocationclustertest.cpp @@ -26,6 +26,7 @@ #include "common/util.hpp" #include "lib/allocationcluster.hpp" +#include "lib/scopedholder.hpp" #include #include @@ -76,8 +77,8 @@ namespace lib { } }; - - typedef vector ClusterList; + typedef ScopedHolder PCluster; + typedef vector ClusterList; inline char truncChar (uint x) @@ -117,15 +118,17 @@ namespace lib { }; void - fillIt (AllocationCluster& clu) + fillIt (PCluster& clu) { + clu.create(); + if (20 Date: Wed, 22 Oct 2008 04:55:28 +0200 Subject: [PATCH 013/249] draft solution finished, compiles but test fails of course... solved the problem to push the actual memory manager completely into the cpp file --- src/lib/allocationcluster.cpp | 75 +++++++++++++++++++++++++++++++++-- src/lib/allocationcluster.hpp | 54 +++++++++++++------------ src/tool/try.cpp | 13 ++++++ 3 files changed, 112 insertions(+), 30 deletions(-) diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp index 32be6fa54..5e9a18131 100644 --- a/src/lib/allocationcluster.cpp +++ b/src/lib/allocationcluster.cpp @@ -33,9 +33,39 @@ namespace lib { class AllocationCluster::MemoryManager { + public: + MemoryManager(TypeInfo info); + void* allocate(); + + void commit (void* pendingAlloc); }; + + AllocationCluster::MemoryManager::MemoryManager (TypeInfo info) + { + UNIMPLEMENTED ("create a new MemoryManager instance for the specific type given"); + //////////////////////////////////////////////////////TODO + } + + void* + AllocationCluster::MemoryManager::allocate() + { + UNIMPLEMENTED ("do the actual raw memory allocation"); + return 0; ////////////////////////////////////////////TODO + } + + void + AllocationCluster::MemoryManager::commit (void* pendingAlloc) + { + UNIMPLEMENTED ("commit a pending allocation to be valid"); + //////////////////////////////////////////////////////TODO + } + + + + /** storage for static bookkeeping of type allocation slots */ + size_t AllocationCluster::maxTypeIDs; /** creating a new AllocationCluster prepares a table capable @@ -64,15 +94,52 @@ namespace lib { } catch (...) { - ERROR (NOBUG_ON, "Unexpected fatal Exception while closing AllocationCluster. Application will terminate."); - throw; + ERROR (NOBUG_ON, "Unexpected fatal Exception while closing AllocationCluster."); + lumiera::error::lumiera_unexpectedException(); // terminate } } - // ==== implementation LifecycleHook class ======= - //x + void* + AllocationCluster::initiateAlloc (size_t& slot) + { + TODO ("this is still a bit fishy, probably off by one and not threadsafe...!"); + + if (!slot || slot >= typeHandlers_.size() || !typeHandlers_[slot]) + return 0; // Memory manager not yet initialised + else + return typeHandlers_[slot]->allocate(); + } + + + void* + AllocationCluster::initiateAlloc (TypeInfo type, size_t& slot) + { + ASSERT (0 < slot && (slot >=typeHandlers_.size() || !typeHandlers_[slot])); + + if (slot >= typeHandlers_.size()) + typeHandlers_.resize(slot); + if (!typeHandlers_[slot]) + typeHandlers_[slot].reset (new MemoryManager (type)); + + ASSERT (typeHandlers_[slot]); + + return initiateAlloc(slot); + + } + + + void + AllocationCluster::finishAlloc (size_t& slot, void* allocatedObj) + { + ASSERT (typeHandlers_[slot]); + ASSERT (allocatedObj); + + typeHandlers_[slot]->commit(allocatedObj); + } + + } // namespace lib diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp index 67645b04b..5e612406b 100644 --- a/src/lib/allocationcluster.hpp +++ b/src/lib/allocationcluster.hpp @@ -163,13 +163,12 @@ namespace lib { /** implementation of the actual memory allocation * is pushed down to the MemoryManager impl. */ - void* initiateAlloc (PMemManager&); + void* initiateAlloc (size_t& slot); + void* initiateAlloc (TypeInfo type, size_t& slot); /** enrol the allocation after successful ctor call */ - void finishAlloc (PMemManager&, void*); + void finishAlloc (size_t& slot, void*); - /** create a new MemoryManager implementation */ - static MemoryManager* setupMemoryManager (TypeInfo const&); }; @@ -197,30 +196,30 @@ namespace lib { { static size_t id_; ///< table pos of the memory manager in charge for type TY - static PMemManager& - get(ManagerTable& handlers) + static size_t & + get() //ManagerTable& handlers) { - ENSURE (id_ < handlers.size() || 1 <= handlers.size()); // 0th Element used as "undefined" marker - TODO ("this is very fishy and probably not threadsafe...!"); + //ENSURE (id_ < handlers.size() || 1 <= handlers.size()); // 0th Element used as "undefined" marker - return handlers[id_ guard SIDEEFFECT; if (!id_) id_= ++maxTypeIDs; - if (id_ >= handlers.size()) - for (size_t idx=handlers.size(); idx()); ////////////////////////////////////////TODO calls ~MemoryManager() but shouldn't - if (!handlers[id_]) - { +// if (id_ >= handlers.size()) +// for (size_t idx=handlers.size(); idx()); ////////////////////////////////////////TODO calls ~MemoryManager() but shouldn't +// if (!handlers[id_]) +// { TY* type_hint(0); TypeInfo info (type_hint); - handlers[id_].reset (setupMemoryManager (info)); ////////////////////////////////////////TODO calls ~MemoryManager() but shouldn't - } + return info; +// handlers[id_].reset (setupMemoryManager (info)); ////////////////////////////////////////TODO calls ~MemoryManager() but shouldn't +// } } static void @@ -238,8 +237,6 @@ namespace lib { /** storage for static bookkeeping of type allocation slots */ template size_t AllocationCluster::TypeSlot::id_; - - size_t AllocationCluster::maxTypeIDs; @@ -248,19 +245,24 @@ namespace lib { void* AllocationCluster::allocation() { - if (!TypeSlot::get (typeHandlers_)) - TypeSlot::setup (typeHandlers_); - return initiateAlloc (TypeSlot::get (typeHandlers_)); +// if (!TypeSlot::get (typeHandlers_)) +// TypeSlot::setup (typeHandlers_); +// return initiateAlloc (TypeSlot::get (typeHandlers_)); + void *mem = initiateAlloc (TypeSlot::get()); + if (!mem) + mem = initiateAlloc (TypeSlot::setup(),TypeSlot::get()); + ENSURE (mem); + return mem; } template TY& AllocationCluster::commit (TY* obj) { - PMemManager & typeHandler (TypeSlot::get (typeHandlers_)); - REQUIRE (typeHandler); +// PMemManager & typeHandler (TypeSlot::get (typeHandlers_)); +// REQUIRE (typeHandler); REQUIRE (obj); - finishAlloc (typeHandler, obj); + finishAlloc (TypeSlot::get(), obj); return *obj; } diff --git a/src/tool/try.cpp b/src/tool/try.cpp index 167946552..1e4d663ee 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -17,6 +17,7 @@ #include #include #include +#include using std::string; using std::cout; @@ -29,6 +30,18 @@ using boost::format; } + struct No {}; + + template + struct Invoker + { + static TY* + call (P0& p0, P1& p1, P2& p2) + { + return new TY (p0,p1,p2); + } + }; + int main (int argc, char* argv[]) { From a3030515bef5b7e725f1b61ec2ed23a8878d55f8 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 22 Oct 2008 22:23:04 +0100 Subject: [PATCH 014/249] Corrected a selection rendering bug in TimelineBody --- src/gui/widgets/timeline/timeline-body.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index 11c3b2b73..7fa0881c5 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -147,11 +147,8 @@ TimelineBody::on_expose_event(GdkEventExpose* event) Cairo::RefPtr cr = window->create_cairo_context(); REQUIRE(cr); - - // Translate the view by the scroll distance - cr->translate(0, -get_vertical_offset()); - - // Draw the view + + //----- Draw the view -----// draw_tracks(cr); draw_selection(cr); draw_playback_point(cr); @@ -272,6 +269,9 @@ TimelineBody::draw_tracks(Cairo::RefPtr cr) Cairo::Matrix view_matrix; cr->get_matrix(view_matrix); + // Translate the view by the scroll distance + cr->translate(0, -get_vertical_offset()); + // Interate drawing each track BOOST_FOREACH( Track* track, timelineWidget->tracks ) { From efd9ab771b02e731b0327ea509c2466f76ca2cbc Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 22 Oct 2008 23:11:23 +0100 Subject: [PATCH 015/249] Added track tree support and added widgets to headers --- icons/Makefile.am | 34 +- icons/svg/track-disabled.svg | 663 ++++++++++++ icons/svg/track-enabled.svg | 967 ++++++++++++++++++ icons/svg/track-locked.svg | 866 ++++++++++++++++ icons/svg/track-unlocked.svg | 655 ++++++++++++ src/gui/widgets/timeline-widget.cpp | 19 +- src/gui/widgets/timeline-widget.hpp | 8 +- src/gui/widgets/timeline/timeline-body.cpp | 49 +- src/gui/widgets/timeline/timeline-body.hpp | 6 + .../timeline/timeline-header-container.cpp | 139 ++- .../timeline/timeline-header-container.hpp | 33 +- src/gui/widgets/timeline/track.cpp | 42 +- src/gui/widgets/timeline/track.hpp | 35 +- src/gui/window-manager.cpp | 7 +- 14 files changed, 3405 insertions(+), 118 deletions(-) create mode 100644 icons/svg/track-disabled.svg create mode 100644 icons/svg/track-enabled.svg create mode 100644 icons/svg/track-locked.svg create mode 100644 icons/svg/track-unlocked.svg diff --git a/icons/Makefile.am b/icons/Makefile.am index 6693b6d1d..281901e78 100644 --- a/icons/Makefile.am +++ b/icons/Makefile.am @@ -33,18 +33,40 @@ iconcommand = python $(top_srcdir)/admin/render-icon.py 48x48pre = $(prerendereddir)/48x48 lumigui_DEPENDENCIES += \ - rsvg-convert \ - $(16x16)/tool-arrow.png $(22x22)/tool-arrow.png $(24x24)/tool-arrow.png $(32x32)/tool-arrow.png $(48x48)/tool-arrow.png \ - $(16x16)/tool-i-beam.png $(22x22)/tool-i-beam.png $(24x24)/tool-i-beam.png $(32x32)/tool-i-beam.png $(48x48)/tool-i-beam.png \ - $(16x16)/panel-assets.png $(22x22)/panel-assets.png $(32x32)/panel-assets.png \ - $(16x16)/panel-timeline.png \ - $(16x16)/panel-viewer.png $(22x22)/panel-viewer.png $(32x32)/panel-viewer.png + rsvg-convert \ + $(16x16)/tool-arrow.png $(22x22)/tool-arrow.png $(24x24)/tool-arrow.png $(32x32)/tool-arrow.png $(48x48)/tool-arrow.png \ + $(16x16)/tool-i-beam.png $(22x22)/tool-i-beam.png $(24x24)/tool-i-beam.png $(32x32)/tool-i-beam.png $(48x48)/tool-i-beam.png \ + $(16x16)/track-disabled.png \ + $(16x16)/track-enabled.png \ + $(16x16)/track-locked.png \ + $(16x16)/track-unlocked.png \ + $(16x16)/panel-assets.png $(22x22)/panel-assets.png $(32x32)/panel-assets.png \ + $(16x16)/panel-timeline.png \ + $(16x16)/panel-viewer.png $(22x22)/panel-viewer.png $(32x32)/panel-viewer.png + +# ========== SVG Icons ========== + +# Timeline Tools $(16x16)/tool-arrow.png $(22x22)/tool-arrow.png $(24x24)/tool-arrow.png $(32x32)/tool-arrow.png $(48x48)/tool-arrow.png : $(svgdir)/tool-arrow.svg $(iconcommand) $< $(icondir) $(16x16)/tool-i-beam.png $(22x22)/tool-i-beam.png $(24x24)/tool-i-beam.png $(32x32)/tool-i-beam.png $(48x48)/tool-i-beam.png : $(svgdir)/tool-i-beam.svg $(iconcommand) $< $(icondir) +# Timeline Tracks +$(16x16)/track-disabled.png : $(svgdir)/track-disabled.svg + $(iconcommand) $< $(icondir) +$(16x16)/track-enabled.png : $(svgdir)/track-enabled.svg + $(iconcommand) $< $(icondir) +$(16x16)/track-locked.png : $(svgdir)/track-locked.svg + $(iconcommand) $< $(icondir) +$(16x16)/track-unlocked.png : $(svgdir)/track-unlocked.svg + $(iconcommand) $< $(icondir) + +# ========== Prerendered Icons ========== + +# Panels + $(16x16)/panel-assets.png: cp $(16x16pre)/panel-assets.png $(16x16) $(22x22)/panel-assets.png: diff --git a/icons/svg/track-disabled.svg b/icons/svg/track-disabled.svg new file mode 100644 index 000000000..04e87768e --- /dev/null +++ b/icons/svg/track-disabled.svg @@ -0,0 +1,663 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/icons/svg/track-enabled.svg b/icons/svg/track-enabled.svg new file mode 100644 index 000000000..ab6af9f53 --- /dev/null +++ b/icons/svg/track-enabled.svg @@ -0,0 +1,967 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/icons/svg/track-locked.svg b/icons/svg/track-locked.svg new file mode 100644 index 000000000..3ff1d34a4 --- /dev/null +++ b/icons/svg/track-locked.svg @@ -0,0 +1,866 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/icons/svg/track-unlocked.svg b/icons/svg/track-unlocked.svg new file mode 100644 index 000000000..beea19846 --- /dev/null +++ b/icons/svg/track-unlocked.svg @@ -0,0 +1,655 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 6c397f9f1..40d0ad09f 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -69,6 +69,9 @@ TimelineWidget::TimelineWidget() : set_selection(2000000, 4000000); tracks.push_back(&video1); + video1.add_child_track(&video1a); + video1.add_child_track(&video1b); + video1b.add_child_track(&video1ba); tracks.push_back(&video2); update_tracks(); @@ -332,7 +335,7 @@ TimelineWidget::update_tracks() BOOST_FOREACH( Track* track, tracks ) { ASSERT(track != NULL); - totalHeight += track->get_height() + TrackPadding; + totalHeight += measure_branch_height(track); } } @@ -378,6 +381,20 @@ TimelineWidget::update_scroll() } +int +TimelineWidget::measure_branch_height(Track* track) +{ + REQUIRE(track != NULL); + + int height = track->get_height(); + + // Recurse through all the children + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + height += measure_branch_height(child); + + return height; +} + int TimelineWidget::get_y_scroll_offset() const { diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index 7785e7bc8..b1b3b0600 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -202,6 +202,8 @@ private: void update_scroll(); + static int measure_branch_height(timeline::Track* track); + int get_y_scroll_offset() const; bool on_motion_in_body_notify_event(GdkEventMotion *event); @@ -224,6 +226,9 @@ protected: int totalHeight; timeline::Track video1; + timeline::Track video1a; + timeline::Track video1b; + timeline::Track video1ba; timeline::Track video2; std::vector tracks; @@ -239,8 +244,7 @@ protected: // Signals sigc::signal viewChangedSignal; sigc::signal mouseHoverSignal; - sigc::signal - playbackPeriodDragReleasedSignal; + sigc::signal playbackPeriodDragReleasedSignal; /* ===== Constants ===== */ public: diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index 7fa0881c5..72d56fd24 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -276,28 +276,45 @@ TimelineBody::draw_tracks(Cairo::RefPtr cr) BOOST_FOREACH( Track* track, timelineWidget->tracks ) { ASSERT(track != NULL); - - const int height = track->get_height(); - ASSERT(height >= 0); - - // Draw the track background - cr->rectangle(0, 0, allocation.get_width(), height); - gdk_cairo_set_source_color(cr->cobj(), &backgroundColour); - cr->fill(); - - // Render the track - cr->save(); - track->draw_track(cr); - cr->restore(); - - // Shift for the next track - cr->translate(0, height + TimelineWidget::TrackPadding); + draw_track_recursive(cr, track, allocation.get_width()); } // Restore the view matrix cr->set_matrix(view_matrix); } +void +TimelineBody::draw_track_recursive(Cairo::RefPtr cr, + const Track *track, const int view_width) const +{ + REQUIRE(cr); + REQUIRE(track != NULL); + + const int height = track->get_height(); + ASSERT(height >= 0); + + // Draw the track background + cr->rectangle(0, 0, view_width, + height - TimelineWidget::TrackPadding); + GdkColor colour = backgroundColour; // Needed to preserve const qualifier + gdk_cairo_set_source_color(cr->cobj(), &colour); + cr->fill(); + + // Render the track + cr->save(); + track->draw_track(cr); + cr->restore(); + + // Shift for the next track + cr->translate(0, height); + + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + { + ASSERT(track != NULL); + draw_track_recursive(cr, child, view_width); + } +} + void TimelineBody::draw_selection(Cairo::RefPtr cr) { diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp index 894cb9f09..9ce48f5e1 100644 --- a/src/gui/widgets/timeline/timeline-body.hpp +++ b/src/gui/widgets/timeline/timeline-body.hpp @@ -36,6 +36,8 @@ class TimelineWidget; namespace timeline { +class Track; + /** * Implementation of the timeline body subwidget. This widget is * displayed in the centre of the timeline widget, and displays the @@ -111,6 +113,10 @@ private: */ void draw_tracks(Cairo::RefPtr cr); + void draw_track_recursive(Cairo::RefPtr cr, + const gui::widgets::timeline::Track *track, + const int view_width) const; + /** * Draws the selected timeline period. * @param cr The cairo context to draw into. diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index ba8323aab..3c16d912e 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -55,32 +55,15 @@ TimelineHeaderContainer::TimelineHeaderContainer(gui::widgets::TimelineWidget // Install style properties register_styles(); } - + void TimelineHeaderContainer::update_headers() { REQUIRE(timelineWidget != NULL); - - // Remove any pre-exisitng headers - BOOST_FOREACH( RootHeader header, rootHeaders ) - { - header.widget->unparent(); - } - rootHeaders.clear(); - // Add fresh headers BOOST_FOREACH( Track* track, timelineWidget->tracks ) - { - ASSERT(track != NULL); - - const RootHeader header = { &track->get_header_widget(), track }; - header.widget->set_parent(*this); - - rootHeaders.push_back(header); - } - - layout_headers(); + set_parent_recursive(track); } void @@ -132,18 +115,14 @@ TimelineHeaderContainer::on_unrealize() void TimelineHeaderContainer::on_size_request (Requisition* requisition) { - // Initialize the output parameter: - *requisition = Gtk::Requisition(); - // We don't care about the size of all the child widgets, but if we // don't send the size request down the tree, some widgets fail to - // calculate their text layout correctly. - BOOST_FOREACH( RootHeader header, rootHeaders ) - { - if(header.widget != NULL && header.widget->is_visible()) - header.widget->size_request(); - } - + // calculate their text layout correctly. + BOOST_FOREACH( Track* track, timelineWidget->tracks ) + size_request_recursive(track); + + // Initialize the output parameter: + *requisition = Gtk::Requisition(); requisition->width = TimelineWidget::HeaderWidth; requisition->height = 0; } @@ -166,10 +145,12 @@ void TimelineHeaderContainer::forall_vfunc(gboolean /* include_internals */, GtkCallback callback, gpointer callback_data) { - BOOST_FOREACH( RootHeader &header, rootHeaders ) + REQUIRE(callback != NULL); + + BOOST_FOREACH( Track* track, timelineWidget->tracks ) { - ASSERT(header.widget); - callback(header.widget->gobj(), callback_data); + ASSERT(track != NULL); + forall_vfunc_recursive(track, callback, callback_data); } } @@ -187,12 +168,12 @@ TimelineHeaderContainer::on_expose_event(GdkEventExpose *event) read_styles(); // Paint a border underneath all the root headers - BOOST_FOREACH( RootHeader &header, rootHeaders ) + BOOST_FOREACH( Track* track, timelineWidget->tracks ) { - ASSERT(header.widget); - ASSERT(header.track != NULL); + ASSERT(track != NULL); - const int height = header.track->get_height(); + const int height = TimelineWidget::measure_branch_height( + track); ASSERT(height >= 0); style->paint_box( @@ -237,30 +218,82 @@ TimelineHeaderContainer::layout_headers() const int header_width = container_allocation.get_width () - margin * 2; - BOOST_FOREACH( RootHeader &header, rootHeaders ) + BOOST_FOREACH( Track* track, timelineWidget->tracks ) { - ASSERT(header.widget); - ASSERT(header.track != NULL); - - const int height = header.track->get_height(); - ASSERT(height >= 0); - - Gtk::Allocation header_allocation; - header_allocation.set_x (margin); - header_allocation.set_y (offset - y_scroll_offset + margin); - header_allocation.set_width (header_width); - header_allocation.set_height (height - margin * 2); - - if(header.widget->is_visible()) - header.widget->size_allocate (header_allocation); - - offset += height + TimelineWidget::TrackPadding; + ASSERT(track != NULL); + layout_headers_recursive(track, y_scroll_offset, offset, + header_width, 0); } // Repaint the background of our parenting queue_draw (); } +void +TimelineHeaderContainer::layout_headers_recursive(Track *track, + const int y_scroll_offset, int &offset, + const int header_width, int depth) const +{ + const int height = track->get_height(); + ASSERT(height >= 0); + + const int indent = depth * 10; + + Allocation header_allocation; + header_allocation.set_x (margin + indent); + header_allocation.set_y (offset - y_scroll_offset + margin); + header_allocation.set_width (header_width - indent); + header_allocation.set_height (height - margin * 2); + + Widget &widget = track->get_header_widget(); + if(widget.is_visible()) + widget.size_allocate (header_allocation); + + offset += height + TimelineWidget::TrackPadding; + + // Recurse through all the children + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + layout_headers_recursive(child, y_scroll_offset, offset, + header_width, depth + 1); +} + +void +TimelineHeaderContainer::set_parent_recursive(Track *track) +{ + REQUIRE(track != NULL); + track->get_header_widget().set_parent(*this); + + // Recurse through all the children + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + set_parent_recursive(child); +} + +void +TimelineHeaderContainer::size_request_recursive(Track *track) +{ + REQUIRE(track != NULL); + if(track->get_header_widget().is_visible()) + track->get_header_widget().size_request(); + + // Recurse through all the children + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + size_request_recursive(child); +} + +void +TimelineHeaderContainer::forall_vfunc_recursive(Track* track, + GtkCallback callback, gpointer callback_data) +{ + REQUIRE(track != NULL); + REQUIRE(callback != NULL); + + callback(track->get_header_widget().gobj(), callback_data); + + // Recurse through all the children + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + forall_vfunc_recursive(child, callback, callback_data); +} + void TimelineHeaderContainer::register_styles() const { diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 480ab6cde..d287f2056 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -119,6 +119,21 @@ private: */ void layout_headers(); + void layout_headers_recursive(Track *track, + const int y_scroll_offset, int &offset, + const int header_width, int depth) const; + + /** + * Recursively sets all the track header widgets to be child widgets + * of this widget. + **/ + void set_parent_recursive(Track *track); + + static void size_request_recursive(Track *track); + + static void forall_vfunc_recursive(Track* track, + GtkCallback callback, gpointer callback_data); + /** * Registers all the styles that this class will respond to. */ @@ -143,24 +158,6 @@ private: * widgets are scrolled. */ Glib::RefPtr gdkWindow; - - //----- Header List -----// - - /** - * A structure to represent a header widget and it's - * associated track - */ - struct RootHeader - { - Gtk::Widget *widget; - Track *track; - }; - - /** - * Contains a list of the root currently present on - * the timeline view - */ - std::vector< RootHeader > rootHeaders; //----- Style Values -----// diff --git a/src/gui/widgets/timeline/track.cpp b/src/gui/widgets/timeline/track.cpp index f8acb35de..bac443ced 100644 --- a/src/gui/widgets/timeline/track.cpp +++ b/src/gui/widgets/timeline/track.cpp @@ -29,12 +29,30 @@ namespace widgets { namespace timeline { Track::Track() : - label1("test1"), label2("test2"), label3("test3"), label4("test4") + enableButton(Gtk::StockID("track_enabled")), + lockButton(Gtk::StockID("track_unlocked")) { - headerWidget.pack_start(label1, PACK_EXPAND_WIDGET); - headerWidget.pack_start(label2, PACK_EXPAND_WIDGET); - headerWidget.pack_start(label3, PACK_EXPAND_WIDGET); - headerWidget.pack_start(label4, PACK_EXPAND_WIDGET); + buttonBar.append(enableButton); + buttonBar.append(lockButton); + + buttonBar.set_toolbar_style(TOOLBAR_ICONS); + buttonBar.set_icon_size(ICON_SIZE_MENU); + + headerWidget.pack_start(titleBox, PACK_SHRINK); + headerWidget.pack_start(buttonBar, PACK_SHRINK); +} + +void +Track::add_child_track(timeline::Track* child) +{ + REQUIRE(child != NULL); + children.push_back(child); +} + +const std::vector& +Track::get_child_tracks() const +{ + return children; } Gtk::Widget& @@ -43,20 +61,20 @@ Track::get_header_widget() return headerWidget; } +int +Track::get_height() const +{ + return 100; +} + Glib::ustring Track::get_title() { return "Hello"; } -int -Track::get_height() -{ - return 100; -} - void -Track::draw_track(Cairo::RefPtr cairo) +Track::draw_track(Cairo::RefPtr cairo) const { } diff --git a/src/gui/widgets/timeline/track.hpp b/src/gui/widgets/timeline/track.hpp index a1b6d48e8..9f7277dd1 100644 --- a/src/gui/widgets/timeline/track.hpp +++ b/src/gui/widgets/timeline/track.hpp @@ -32,25 +32,42 @@ namespace gui { namespace widgets { namespace timeline { +class Clip; + class Track { public: Track(); + void add_child_track(timeline::Track* child); + + const std::vector& get_child_tracks() const; + + Gtk::Widget& get_header_widget(); + + int get_height() const; + Glib::ustring get_title(); - Gtk::Widget& get_header_widget(); + void draw_track(Cairo::RefPtr cairo) const; + +private: + +private: - int get_height(); + //----- Data -----// + std::vector children; + std::vector clips; - void draw_track(Cairo::RefPtr cairo); - -protected: + //----- Header Widgets ------// + Gtk::VBox headerWidget; - Gtk::Label label1; - Gtk::Label label2; - Gtk::CheckButton label3; - Gtk::Button label4; + + Gtk::ToolButton enableButton; + Gtk::ToolButton lockButton; + + Gtk::Entry titleBox; + Gtk::Toolbar buttonBar; }; diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index 4a89158d7..c7cbb3c32 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -92,7 +92,12 @@ WindowManager::register_stock_items() add_stock_icon_set(factory, "panel-viewer", "panel_viewer", _("_Viewer")); add_stock_icon_set(factory, "tool-arrow", "tool_arrow", _("_Arrow")); - add_stock_icon_set(factory, "tool-i-beam", "tool_i_beam", _("_I-Beam")); + add_stock_icon_set(factory, "tool-i-beam", "tool_i_beam", _("_I-Beam")); + + add_stock_icon_set(factory, "track-disabled", "track_disabled", _("Track Disabled")); + add_stock_icon_set(factory, "track-enabled", "track_enabled", _("Track Enabled")); + add_stock_icon_set(factory, "track-locked", "track_locked", _("Track Locked")); + add_stock_icon_set(factory, "track-unlocked", "track_unlocked", _("Track Unlocked")); factory->add_default(); //Add factory to list of factories. } From 7dcfa84d6a5b89c292f36ae82946c94a1396590f Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Thu, 23 Oct 2008 00:38:47 +0100 Subject: [PATCH 016/249] Correct a liblumi to liblumiera --- src/gui/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 835e5f1a5..e6c3ed16d 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -78,7 +78,7 @@ lumigui_SOURCES = \ lumigui_LDFLAGS = lumigui_LDADD = $(GTK_LUMIERA_LIBS) liblumiproc.a liblumibackend.a \ - liblumicommon.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) + liblumicommon.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) lumigui_DEPENDENCIES = \ $(top_builddir)/lumiera_ui.rc \ From 2b2654cb38b1567b43fb1f06773f50712f55803e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 23 Oct 2008 07:15:48 +0200 Subject: [PATCH 017/249] WIP test covering the ScopedHolder helpers --- src/lib/scopedholder.hpp | 15 +- tests/common/scopedholdertest.cpp | 295 ++++++++++++++++++++++++++++++ 2 files changed, 309 insertions(+), 1 deletion(-) create mode 100644 tests/common/scopedholdertest.cpp diff --git a/src/lib/scopedholder.hpp b/src/lib/scopedholder.hpp index f82ee1bba..99be159a1 100644 --- a/src/lib/scopedholder.hpp +++ b/src/lib/scopedholder.hpp @@ -111,6 +111,19 @@ namespace lib { + /** + * Inline buffer holding and owning an object similar to scoped_ptr. + * Access to the contained object is similar to a smart-pointer, + * but the object isn't heap allocated, rather placed into an + * buffer within ScopedHolder. Initially, ScopedHolder is empty + * and behaves like a null pointer. The contained object must be + * created explicitly by calling #create() (using the default ctor). + * This state change is remembered (requiring 1 char of additional + * storage). After the creation of the object, ScopedHolder is + * effectively noncopyable, which is enforced by run-time checks. + * ScopedHolder may be used to hold noncopyable objects within STL + * containers inline without extra heap allocation. + */ template class ScopedHolder { @@ -186,7 +199,7 @@ namespace lib { { if (ref) throw lumiera::error::Logic("ScopedHolder protocol violation: " - "attempt after having invoked create()."); + "copy operation after having invoked create()."); return 0; } }; diff --git a/tests/common/scopedholdertest.cpp b/tests/common/scopedholdertest.cpp new file mode 100644 index 000000000..757acce9a --- /dev/null +++ b/tests/common/scopedholdertest.cpp @@ -0,0 +1,295 @@ +/* + ScopedHolder(Test) - holding and owning noncopyable objects + + 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. + +* *****************************************************/ + + + +#include "common/test/run.hpp" +#include "common/util.hpp" + +#include "lib/scopedholder.hpp" + +#include +#include +//#include +//#include +#include + +//using boost::lexical_cast; +//using util::for_each; +using util::isnil; +using ::Test; + +//using std::numeric_limits; +//using std::vector; +using std::map; +using std::cout; + +namespace lib { + namespace test { + + namespace { // yet another test dummy + + long checksum = 0; + bool magic = false; + + class Dummy : boost::noncopyable + { + long val_; + + public: + Dummy () + : val_(1 + (rand() % 100000000)) + { + checksum += val_; + if (magic) + throw val_; + } + + ~Dummy() + { + checksum -= val_; + } + + long add (int i) { return val_+i; } + }; + + + typedef ScopedHolder HolderD; + typedef ScopedPtrHolder PtrHolderD; + + } + + + /********************************************************************************** + * @test ScopedHolder and ScopedPtrHolder are initially empty and copyable. + * After taking ownership, they prohibit copy operations, manage the + * lifecycle of the contained object and provide smart-ptr like access. + * A series of identical tests is conducted both with the ScopedPtrHolder + * (the contained objects are heap allocated but managed by the holder) + * and with the ScopedHolder (objects placed inline) + */ + class ScopedHolder_test : public Test + { + + virtual void + run (Arg arg) + { + + cout << "checking ScopedHolder...\n"; + checkAllocation(); + checkErrorHandling(); + checkCopyProtocol(); + checkSTLContainer(); + + cout << "checking ScopedPtrHolder...\n"; + checkAllocation(); + checkErrorHandling(); + checkCopyProtocol(); + checkSTLContainer(); + } + + void create_contained_object (HolderD& holder) { holder.create(); } + void create_contained_object (PtrHolderD& holder) { holder.reset(new Dummy()); } + + + template + void + checkAllocation() + { + ASSERT (0==checksum); + { + HO holder; + ASSERT (!holder); + ASSERT (0==checksum); + + create_contained_object (holder); + ASSERT (holder); + ASSERT (true==holder); + ASSERT (false!=holder); + ASSERT (holder!=false); + + ASSERT (0!=checksum); + ASSERT (! *holder); + ASSERT (holder->add(2) == checksum+2); + + Dummy *rawP = holder.get(); + ASSERT (rawP); + ASSERT (holder); + ASSERT (rawP == &(*holder)); + ASSERT (rawP->add(-5) == holder->add(-5)); + } + ASSERT (0==checksum); + } + + + template + void + checkErrorHandling() + { + ASSERT (0==checksum); + { + HO holder; + + magic = true; + try + { + create_contained_object (holder); + NOTREACHED ; + } + catch (long val) + { + ASSERT (0!=checksum); + checksum -= val; + ASSERT (0==checksum); + } + ASSERT (!holder); /* because the exception happens in ctor + object doesn't count as "created" */ + magic = false; + } + ASSERT (0==checksum); + } + + + template + void + checkCopyProtocol() + { + ASSERT (0==checksum); + { + HO holder; + HO holder2 (holder); + holder2 = holder; + + ASSERT (!holder); + create_contained_object (holder); + ASSERT (holder); + long currSum = checksum; + try + { + holder2 = holder; + NOTREACHED ; + } + catch (lumiera::error::Logic&) + { + ASSERT (holder); + ASSERT (!holder2); + ASSERT (checksum==currSum); + } + + try + { + holder = holder2; + NOTREACHED ; + } + catch (lumiera::error::Logic&) + { + ASSERT (holder); + ASSERT (!holder2); + ASSERT (checksum==currSum); + } + + create_contained_object (holder2); + ASSERT (holder2); + ASSERT (checksum != currSum); + currSum = checksum; + try + { + holder = holder2; + NOTREACHED ; + } + catch (lumiera::error::Logic&) + { + ASSERT (holder); + ASSERT (holder2); + ASSERT (checksum==currSum); + } + + try + { + HO holder3 (holder2); + NOTREACHED ; + } + catch (lumiera::error::Logic&) + { + ASSERT (holder); + ASSERT (holder2); + ASSERT (checksum==currSum); + } + } + ASSERT (0==checksum); + } + + + /** @test a collection of noncopyable objects + * maintained within a STL map + */ + template + void + checkSTLContainer() + { + typedef std::map MapHO; + + ASSERT (0==checksum); + { + MapHO maph; + ASSERT (isnil (maph)); + + for (uint i=0; i<100; ++i) + ASSERT (!maph[i]); + + ASSERT (!isnil (maph)); // 100 holder objects created by sideeffect + ASSERT (0==checksum); // ....without creating any contained object + ASSERT (100==maph.size()); + + for (uint i=0; i<100; ++i) + { + create_contained_object (maph[i]) + ASSERT (maph[i]); + ASSERT (0 < maph[i]->add(12)); + } + ASSERT (100==maph.size()); + ASSERT (0!=checksum); + + + long theVal = maph[55]->add(0); + long currSum = checksum; + + ASSERT (1 == maph.erase(55)); + ASSERT (maph.size() == 99); + ASSERT (checksum == currSum - theVal); // proves no55's dtor has been invoked + + ASSERT (!maph[55]); + ASSERT (maph.size() == 100); // created a new empty holder by sideeffect + } + ASSERT (0==checksum); + } + + + }; + + LAUNCHER (ScopedHolder_test, "unit common"); + + + }// namespace test + +} // namespace lib + From 75cf4a97b3ed95b26050290f7a25b5fa7f53f7b0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 23 Oct 2008 18:33:56 +0200 Subject: [PATCH 018/249] ScopedHolder test passed --- src/lib/scopedholder.hpp | 40 ++++++++-------- tests/common/scopedholdertest.cpp | 77 ++++++++++++++++++------------- 2 files changed, 66 insertions(+), 51 deletions(-) diff --git a/src/lib/scopedholder.hpp b/src/lib/scopedholder.hpp index 99be159a1..8d1564731 100644 --- a/src/lib/scopedholder.hpp +++ b/src/lib/scopedholder.hpp @@ -29,7 +29,7 @@ ** or even a garbage collector. Sometimes the circumstances rather call ** for a very simple or lightweight solution though. ** - ** ScopedPtrHolder is a small extension to boost::scoped_ptr, enabling + ** ScopedPtrHolder is a simple extension to boost::scoped_ptr, enabling ** to use it within STL containers if we stick to a specific protocol. ** The idea is to permit copying as long as the scoped_ptr is empty. ** This can be used to allow for extension of the STL container on @@ -57,10 +57,10 @@ namespace lib { - + /** * Extension to boost::scoped_ptr, allowing copy operations - * as long as the pointer is still null. + * on empty pointers (i.e. contained pointer is null). * @throw error::Logic on attempt to copy otherwise */ template @@ -79,12 +79,12 @@ namespace lib { explicit ScopedPtrHolder (SU * p) // never throws : _Parent(p) { } - + template explicit ScopedPtrHolder (std::auto_ptr p) // never throws : _Parent(p.release()) { } - + ScopedPtrHolder (ScopedPtrHolder const& ref) : _Parent(must_be_null (ref)) { } @@ -107,9 +107,9 @@ namespace lib { return 0; } }; - - - + + + /** * Inline buffer holding and owning an object similar to scoped_ptr. @@ -131,7 +131,7 @@ namespace lib { char created_; typedef ScopedHolder _ThisType; - + public: ScopedHolder() @@ -150,10 +150,10 @@ namespace lib { ~ScopedHolder() { if (created_) - content_->~TY(); + get()->~TY(); } - - + + ScopedHolder (ScopedHolder const& ref) : created_(must_be_empty (ref)) { } @@ -173,26 +173,30 @@ namespace lib { ASSERT (created_); return (TY&) content_; } - + TY* operator-> () const // never throws { ASSERT (created_); return (TY*) &content_; } - - TY* get() const { return &content_; } - bool operator! () const { return !created_; } + + TY* get() const // never throws + { + return (TY*) &content_; + } typedef char _ThisType::*unspecified_bool_type; - + /** implicit conversion to "bool" */ operator unspecified_bool_type() const // never throws { return created_? &_ThisType::created_ : 0; } - + + bool operator! () const { return !created_; } + private: static char must_be_empty (_ThisType const& ref) diff --git a/tests/common/scopedholdertest.cpp b/tests/common/scopedholdertest.cpp index 757acce9a..f250c6f88 100644 --- a/tests/common/scopedholdertest.cpp +++ b/tests/common/scopedholdertest.cpp @@ -27,33 +27,29 @@ #include "lib/scopedholder.hpp" +#include #include #include -//#include -//#include -#include -//using boost::lexical_cast; -//using util::for_each; -using util::isnil; -using ::Test; - -//using std::numeric_limits; -//using std::vector; -using std::map; -using std::cout; namespace lib { namespace test { + using ::Test; + using util::isnil; + + using std::map; + using std::cout; + namespace { // yet another test dummy long checksum = 0; bool magic = false; - class Dummy : boost::noncopyable + class Dummy + : boost::noncopyable { - long val_; + int val_; public: Dummy () @@ -73,7 +69,7 @@ namespace lib { }; - typedef ScopedHolder HolderD; + typedef ScopedHolder HolderD; typedef ScopedPtrHolder PtrHolderD; } @@ -107,7 +103,7 @@ namespace lib { checkSTLContainer(); } - void create_contained_object (HolderD& holder) { holder.create(); } + void create_contained_object (HolderD& holder) { holder.create(); } void create_contained_object (PtrHolderD& holder) { holder.reset(new Dummy()); } @@ -123,12 +119,11 @@ namespace lib { create_contained_object (holder); ASSERT (holder); - ASSERT (true==holder); ASSERT (false!=holder); ASSERT (holder!=false); ASSERT (0!=checksum); - ASSERT (! *holder); + ASSERT ( &(*holder)); ASSERT (holder->add(2) == checksum+2); Dummy *rawP = holder.get(); @@ -136,6 +131,11 @@ namespace lib { ASSERT (holder); ASSERT (rawP == &(*holder)); ASSERT (rawP->add(-5) == holder->add(-5)); + + TRACE (test, "holder at %x", &holder); + TRACE (test, "object at %x", holder.get() ); + TRACE (test, "size(object) = %d", sizeof(*holder)); + TRACE (test, "size(holder) = %d", sizeof(holder)); } ASSERT (0==checksum); } @@ -155,7 +155,7 @@ namespace lib { create_contained_object (holder); NOTREACHED ; } - catch (long val) + catch (int val) { ASSERT (0!=checksum); checksum -= val; @@ -178,11 +178,14 @@ namespace lib { HO holder; HO holder2 (holder); holder2 = holder; + // copy and assignment of empty holders is tolerated + // but after enclosing an object it will be copy protected... ASSERT (!holder); create_contained_object (holder); ASSERT (holder); long currSum = checksum; + void* adr = holder.get(); try { holder2 = holder; @@ -192,6 +195,7 @@ namespace lib { { ASSERT (holder); ASSERT (!holder2); + ASSERT (holder.get()==adr); ASSERT (checksum==currSum); } @@ -204,6 +208,7 @@ namespace lib { { ASSERT (holder); ASSERT (!holder2); + ASSERT (holder.get()==adr); ASSERT (checksum==currSum); } @@ -220,6 +225,7 @@ namespace lib { { ASSERT (holder); ASSERT (holder2); + ASSERT (holder.get()==adr); ASSERT (checksum==currSum); } @@ -239,7 +245,7 @@ namespace lib { } - /** @test a collection of noncopyable objects + /** @test collection of noncopyable objects * maintained within a STL map */ template @@ -254,15 +260,18 @@ namespace lib { ASSERT (isnil (maph)); for (uint i=0; i<100; ++i) - ASSERT (!maph[i]); - - ASSERT (!isnil (maph)); // 100 holder objects created by sideeffect - ASSERT (0==checksum); // ....without creating any contained object + { + HO & contained = maph[i]; + ASSERT (!contained); + } // 100 holder objects created by sideeffect + + ASSERT (0==checksum); // ..... without creating any contained object! + ASSERT (!isnil (maph)); ASSERT (100==maph.size()); for (uint i=0; i<100; ++i) { - create_contained_object (maph[i]) + create_contained_object (maph[i]); ASSERT (maph[i]); ASSERT (0 < maph[i]->add(12)); } @@ -270,15 +279,17 @@ namespace lib { ASSERT (0!=checksum); - long theVal = maph[55]->add(0); + long value55 = maph[55]->add(0); long currSum = checksum; ASSERT (1 == maph.erase(55)); + ASSERT (checksum == currSum - value55); // proves object#55's dtor has been invoked ASSERT (maph.size() == 99); - ASSERT (checksum == currSum - theVal); // proves no55's dtor has been invoked - + + maph[55]; // create new empty holder by sideeffect... + ASSERT (&maph[55]); ASSERT (!maph[55]); - ASSERT (maph.size() == 100); // created a new empty holder by sideeffect + ASSERT (maph.size() == 100); } ASSERT (0==checksum); } @@ -286,10 +297,10 @@ namespace lib { }; - LAUNCHER (ScopedHolder_test, "unit common"); - - - }// namespace test + LAUNCHER (ScopedHolder_test, "unit common"); + + }// namespace test + } // namespace lib From b4794042886095402b323259e9d238495e5cd10f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 23 Oct 2008 19:47:08 +0200 Subject: [PATCH 019/249] fix logic for allocating a new memory manager --- src/lib/allocationcluster.cpp | 29 +++++++++++++++-------------- src/lib/allocationcluster.hpp | 4 ++-- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp index 5e9a18131..795ee903c 100644 --- a/src/lib/allocationcluster.cpp +++ b/src/lib/allocationcluster.cpp @@ -104,39 +104,40 @@ namespace lib { void* AllocationCluster::initiateAlloc (size_t& slot) { - TODO ("this is still a bit fishy, probably off by one and not threadsafe...!"); - - if (!slot || slot >= typeHandlers_.size() || !typeHandlers_[slot]) + if (!slot || slot > typeHandlers_.size() || !typeHandlers_[slot-1]) return 0; // Memory manager not yet initialised else - return typeHandlers_[slot]->allocate(); + return typeHandlers_[slot-1]->allocate(); } void* AllocationCluster::initiateAlloc (TypeInfo type, size_t& slot) { - ASSERT (0 < slot && (slot >=typeHandlers_.size() || !typeHandlers_[slot])); - - if (slot >= typeHandlers_.size()) - typeHandlers_.resize(slot); - if (!typeHandlers_[slot]) - typeHandlers_[slot].reset (new MemoryManager (type)); + ASSERT (0 < slot); - ASSERT (typeHandlers_[slot]); + { + Thread::Lock guard SIDEEFFECT; ////TODO: it's sufficient to just lock the instance, not the whole class + if (slot > typeHandlers_.size()) + typeHandlers_.resize(slot); + if (!typeHandlers_[slot-1]) + typeHandlers_[slot-1].reset (new MemoryManager (type)); + + } + + ASSERT (typeHandlers_[slot-1]); return initiateAlloc(slot); - } void AllocationCluster::finishAlloc (size_t& slot, void* allocatedObj) { - ASSERT (typeHandlers_[slot]); + ASSERT (typeHandlers_[slot-1]); ASSERT (allocatedObj); - typeHandlers_[slot]->commit(allocatedObj); + typeHandlers_[slot-1]->commit(allocatedObj); } diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp index 5e612406b..b874256f3 100644 --- a/src/lib/allocationcluster.hpp +++ b/src/lib/allocationcluster.hpp @@ -60,7 +60,7 @@ namespace lib { using boost::scoped_ptr; - + using lumiera::Thread; /** * A pile of objects sharing common allocation and lifecycle. @@ -207,7 +207,7 @@ namespace lib { static TypeInfo setup() // ManagerTable& handlers) { - lumiera::Thread::Lock guard SIDEEFFECT; + Thread::Lock guard SIDEEFFECT; if (!id_) id_= ++maxTypeIDs; // if (id_ >= handlers.size()) From 6bd0c84355d452747ff8787e23bfb335e4613493 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 23 Oct 2008 23:08:27 +0200 Subject: [PATCH 020/249] WIP added preliminary pseudo-implementation for the raw memory manager. Actually this beast does just per object heap allocations, .... any takers? --- src/lib/allocationcluster.cpp | 137 +++++++++++++++++++++++++++------- src/lib/allocationcluster.hpp | 24 ++++-- src/proc/nobugcfg.hpp | 2 + 3 files changed, 129 insertions(+), 34 deletions(-) diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp index 795ee903c..a9db60c20 100644 --- a/src/lib/allocationcluster.cpp +++ b/src/lib/allocationcluster.cpp @@ -23,18 +23,51 @@ #include "lib/allocationcluster.hpp" #include "common/error.hpp" -//#include "common/util.hpp" +#include "common/util.hpp" -//using util::isnil; +using util::isnil; //using util::cStr; namespace lib { + /** + * "Low-level" Memory manager for allocating small objects of a fixed size. + * The usage pattern is definite: Objects will be allocated in the course of + * a build process and then live until all Objects will be purged in one sway. + * Allocations will be requested one by one and immediately committed after + * successful ctor call of the object being allocated. Allocations and commits + * can be assumed to come in pairs, thus if an allocation immediately follows + * another one (without commit), the previous allocation can be considered + * a failure and can be dropped silently. After an allocation has succeeds + * (i.e. was committed), the MemoryManager is in charge for the lifecycle + * of the object within the allocated spaces and has to guarantee calling + * it's dtor, either on shutdown or on explicit #purge() -- the type info + * structure handed in on initialisation provides a means for invoking + * the dtor without actually knowing the object's type. + * + * @todo this is a preliminary or pseudo-implementation based on + * a vector of smart pointers, i.e. actually the objects are heap + * allocated. What actually should happen is for the MemoryManager to + * allocate raw memory chunk wise, sub partition it and place the objects + * into this private memory buffer. Further, possibly we could maintain + * a pool of raw memory chunks used by all MemoryManager instances. I am + * skipping those details for now (10/2008) because they should be based + * on real-world measurements, not guessing. + */ class AllocationCluster::MemoryManager { + typedef std::vector MemTable; + TypeInfo type_; + MemTable mem_; + size_t top_; + public: - MemoryManager(TypeInfo info); + MemoryManager(TypeInfo info) { reset(info); } + ~MemoryManager() { purge(); } + + void purge(); + void reset(TypeInfo info); void* allocate(); @@ -42,24 +75,66 @@ namespace lib { }; - AllocationCluster::MemoryManager::MemoryManager (TypeInfo info) - { - UNIMPLEMENTED ("create a new MemoryManager instance for the specific type given"); - //////////////////////////////////////////////////////TODO - } - - void* - AllocationCluster::MemoryManager::allocate() - { - UNIMPLEMENTED ("do the actual raw memory allocation"); - return 0; ////////////////////////////////////////////TODO - } void + AllocationCluster::MemoryManager::reset (TypeInfo info) + { + Thread::Lock guard SIDEEFFECT; + + if (0 < mem_.size()) purge(); + type_ = info; + + ENSURE (0==top_); + ENSURE (isnil (mem_)); + ENSURE (0 < type_.allocSize); + ENSURE (type_.killIt); + } + + + void + AllocationCluster::MemoryManager::purge() + { + Thread::Lock guard SIDEEFFECT; + + REQUIRE (type_.killIt, "we need a deleter function"); + REQUIRE (0 < type_.allocSize, "allocation size unknown"); + REQUIRE (top_ == mem_.size() || (top_+1) == mem_.size()); + + while (top_) + type_.killIt (&mem_[--top_]); + mem_.resize(0); + }// note: unnecessary to kill pending allocations + + + inline void* + AllocationCluster::MemoryManager::allocate() + { + Thread::Lock guard SIDEEFFECT; + + REQUIRE (0 < type_.allocSize); + REQUIRE (top_ <= mem_.size()); + + if (top_==mem_.size()) + mem_.resize(top_+1); + mem_[top_] = new char[type_.allocSize]; + + ENSURE (top_ < mem_.size()); + return mem_[top_]; + } + + + inline void AllocationCluster::MemoryManager::commit (void* pendingAlloc) { - UNIMPLEMENTED ("commit a pending allocation to be valid"); - //////////////////////////////////////////////////////TODO + Thread::Lock guard SIDEEFFECT; + + REQUIRE (pendingAlloc); + ASSERT (top_ < mem_.size()); + ASSERT (pendingAlloc == mem_[top_], "allocation protocol violated"); + + ++top_; + + ENSURE (top_ == mem_.size()); } @@ -75,6 +150,7 @@ namespace lib { AllocationCluster::AllocationCluster() // : configParam_ (new Configmap), { + TRACE (buildermem, "new AllocationCluster"); } @@ -86,6 +162,13 @@ namespace lib { { try { + Thread::Lock guard SIDEEFFECT + + TRACE (buildermem, "shutting down AllocationCluster"); + for (size_t i = typeHandlers_.size(); 0 < i; --i) + handler(i)->purge(); + + typeHandlers_.resize(0); } catch (lumiera::Error & ex) @@ -104,10 +187,10 @@ namespace lib { void* AllocationCluster::initiateAlloc (size_t& slot) { - if (!slot || slot > typeHandlers_.size() || !typeHandlers_[slot-1]) - return 0; // Memory manager not yet initialised + if (!slot || slot > typeHandlers_.size() || !handler(slot) ) + return 0; // Memory manager not yet initialised else - return typeHandlers_[slot-1]->allocate(); + return handler(slot)->allocate(); } @@ -117,16 +200,16 @@ namespace lib { ASSERT (0 < slot); { - Thread::Lock guard SIDEEFFECT; ////TODO: it's sufficient to just lock the instance, not the whole class - + Thread::Lock guard SIDEEFFECT; /////TODO: decide tradeoff: lock just the instance, or lock the AllocationCluster class? + if (slot > typeHandlers_.size()) typeHandlers_.resize(slot); - if (!typeHandlers_[slot-1]) - typeHandlers_[slot-1].reset (new MemoryManager (type)); + if (!handler(slot)) + handler(slot).reset (new MemoryManager (type)); } - ASSERT (typeHandlers_[slot-1]); + ASSERT (handler(slot)); return initiateAlloc(slot); } @@ -134,10 +217,10 @@ namespace lib { void AllocationCluster::finishAlloc (size_t& slot, void* allocatedObj) { - ASSERT (typeHandlers_[slot-1]); + ASSERT (handler(slot)); ASSERT (allocatedObj); - typeHandlers_[slot-1]->commit(allocatedObj); + handler(slot)->commit(allocatedObj); } diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp index b874256f3..473ff8cd1 100644 --- a/src/lib/allocationcluster.hpp +++ b/src/lib/allocationcluster.hpp @@ -53,7 +53,7 @@ #include "common/multithread.hpp" #include "common/error.hpp" -#include "common/util.hpp" +//#include "common/util.hpp" #include "lib/scopedholder.hpp" @@ -123,7 +123,7 @@ namespace lib { } - protected: + private: /** initiate an allocation for the given type */ template void* @@ -156,10 +156,16 @@ namespace lib { static size_t maxTypeIDs; - typedef scoped_ptr PMemManager; - typedef std::vector > ManagerTable; + typedef ScopedPtrHolder HMemManager; + typedef std::vector ManagerTable; ManagerTable typeHandlers_; + HMemManager& + handler (size_t slot) + { + ASSERT (0::kill) { } + + TypeInfo() ///< denotes "unknown" type + : allocSize(0), + killIt(0) + { } }; @@ -238,11 +249,10 @@ namespace lib { template size_t AllocationCluster::TypeSlot::id_; - template - void* + inline void* AllocationCluster::allocation() { // if (!TypeSlot::get (typeHandlers_)) @@ -256,7 +266,7 @@ namespace lib { } template - TY& + inline TY& AllocationCluster::commit (TY* obj) { // PMemManager & typeHandler (TypeSlot::get (typeHandlers_)); diff --git a/src/proc/nobugcfg.hpp b/src/proc/nobugcfg.hpp index 567838320..edb079d05 100644 --- a/src/proc/nobugcfg.hpp +++ b/src/proc/nobugcfg.hpp @@ -56,6 +56,7 @@ NOBUG_DECLARE_FLAG(singleton); NOBUG_DECLARE_FLAG(assetmem); NOBUG_DECLARE_FLAG(mobjectmem); + NOBUG_DECLARE_FLAG(buildermem); namespace lumiera { @@ -80,6 +81,7 @@ namespace lumiera { NOBUG_CPP_DEFINE_FLAG_LIMIT(singleton, LOG_WARNING); NOBUG_CPP_DEFINE_FLAG_LIMIT(assetmem, LOG_WARNING); NOBUG_CPP_DEFINE_FLAG_LIMIT(mobjectmem, LOG_WARNING); + NOBUG_CPP_DEFINE_FLAG_LIMIT(buildermem, LOG_INFO); From 89fca1921dddd7e27ff0b2862392310deb5d7090 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 24 Oct 2008 06:06:24 +0200 Subject: [PATCH 021/249] WIP added simple usage test ... and made it compile, but still a fundamental problem to resolve with the use of std::vector in this scenario --- src/lib/allocationcluster.cpp | 10 ++++----- tests/common/allocationclustertest.cpp | 31 +++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp index a9db60c20..118abbe23 100644 --- a/src/lib/allocationcluster.cpp +++ b/src/lib/allocationcluster.cpp @@ -63,8 +63,8 @@ namespace lib { size_t top_; public: - MemoryManager(TypeInfo info) { reset(info); } - ~MemoryManager() { purge(); } + MemoryManager(TypeInfo info) : top_(0) { reset(info); } + ~MemoryManager() { purge(); } void purge(); void reset(TypeInfo info); @@ -102,7 +102,7 @@ namespace lib { while (top_) type_.killIt (&mem_[--top_]); - mem_.resize(0); + mem_.clear(); }// note: unnecessary to kill pending allocations @@ -168,7 +168,7 @@ namespace lib { for (size_t i = typeHandlers_.size(); 0 < i; --i) handler(i)->purge(); - typeHandlers_.resize(0); + typeHandlers_.clear(); } catch (lumiera::Error & ex) @@ -203,7 +203,7 @@ namespace lib { Thread::Lock guard SIDEEFFECT; /////TODO: decide tradeoff: lock just the instance, or lock the AllocationCluster class? if (slot > typeHandlers_.size()) - typeHandlers_.resize(slot); + typeHandlers_.resize(slot); /////////////////////////////TODO: still a fundamental problem buried here with the way stl::vector grows... if (!handler(slot)) handler(slot).reset (new MemoryManager (type)); diff --git a/tests/common/allocationclustertest.cpp b/tests/common/allocationclustertest.cpp index 27f37cff0..001326ce1 100644 --- a/tests/common/allocationclustertest.cpp +++ b/tests/common/allocationclustertest.cpp @@ -57,7 +57,7 @@ namespace lib { char content[i]; public: - Dummy (char id) + Dummy (char id=1) { content[0] = id; checksum += id; @@ -75,6 +75,8 @@ namespace lib { { checksum -= content[0]; } + + char getID() { return content[0]; } }; typedef ScopedHolder PCluster; @@ -149,10 +151,37 @@ namespace lib { if (1 < arg.size()) NUM_OBJECTS = lexical_cast (arg[1]); if (2 < arg.size()) NUM_FAMILIES = lexical_cast (arg[2]); + simpleUsage(); checkAllocation(); checkErrorHandling(); } + + void + simpleUsage() + { + AllocationCluster clu; + + char c1(123), c2(56), c3(3), c4(4), c5(5); + Dummy<44>& ref1 = clu.create > (); + Dummy<37>& ref2 = clu.create > (c1); + Dummy<37>& ref3 = clu.create > (c2); + Dummy<1234>& rX = clu.create > (c3,c4,c5); + + ASSERT (&ref1); + ASSERT (&ref2); + ASSERT (&ref3); + ASSERT (&rX); + TRACE (test, "sizeof( Dummy<1234> ) = %d", sizeof(rX)); + + ASSERT (123==ref2.getID()); + ASSERT (3+4+5==rX.getID()); + // shows that the returned references actually + // point at the objects we created. Just use them + // and let them go. When clu goes out of scope, + // all created objects dtors will be invoked. + } + void checkAllocation() { From 32637dd95830d10e7a05f00b5558a8f85d0c7e50 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 26 Oct 2008 03:21:33 +0100 Subject: [PATCH 022/249] experiment: possibility to circumvent the problem using an custom allocator for std::vector with an explicit transfer_control(). Indeed seems to solve the problem... --- src/tool/SConscript | 2 +- src/tool/try.cpp | 175 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 166 insertions(+), 11 deletions(-) diff --git a/src/tool/SConscript b/src/tool/SConscript index c2bc612f6..9cbf5c8b5 100644 --- a/src/tool/SConscript +++ b/src/tool/SConscript @@ -9,6 +9,6 @@ Import('env','artifacts','core') # build the ubiquitous Hello World application (note: C source) artifacts['tools'] = [ env.Program('#$BINDIR/hello-world','hello.c') + env.Program('#$BINDIR/luidgen', ['luidgen.c']+core) - + env.Program('#$BINDIR/try', 'try.cpp') #### to try out some feature... + + env.Program('#$BINDIR/try', ['try.cpp']+core) #### to try out some feature... ] diff --git a/src/tool/try.cpp b/src/tool/try.cpp index 1e4d663ee..5741ccf6f 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -11,43 +11,198 @@ // 4/08 - conversions on the value_type used for boost::any // 5/08 - how to guard a downcasting access, so it is compiled in only if the involved types are convertible // 7/08 - combining partial specialisation and subclasses +// 10/8 - abusing the STL containers to hold noncopyable values -#include +//#include +#include "proc/nobugcfg.hpp" + #include #include #include -#include +#include +#include + +#include "lib/scopedholder.hpp" using std::string; using std::cout; +using std::vector; using boost::format; namespace { - boost::format fmt ("<%2i>"); - + long checksum = 0; } - struct No {}; - template - struct Invoker + namespace funny { + + + class Mrpf + : boost::noncopyable + { + long secret_; + + typedef Mrpf _ThisType; + + public: + Mrpf() + : secret_(0) + { + cout << "Mrpf() this=" << this <<"\n"; + } + ~Mrpf() + { + checksum -= secret_; + cout << "~Mrpf() this=" << this <<" skeret="<"< > + class Allocator_TransferNoncopyable + { + typedef Allocator_TransferNoncopyable _ThisType; + + PAR par_; + + + public: + typedef typename PAR::size_type size_type; + typedef typename PAR::difference_type difference_type; + typedef typename PAR::pointer pointer; + typedef typename PAR::const_pointer const_pointer; + typedef typename PAR::reference reference; + typedef typename PAR::const_reference const_reference; + typedef typename PAR::value_type value_type; + + template + struct rebind + { typedef Allocator_TransferNoncopyable<_Tp1, PAR> other; }; + + Allocator_TransferNoncopyable() { } + + Allocator_TransferNoncopyable(const _ThisType& __a) + : par_(__a.par_) { } + Allocator_TransferNoncopyable(const PAR& __a) + : par_(__a) { } + + template + Allocator_TransferNoncopyable(const std::allocator&) { } + + ~Allocator_TransferNoncopyable() { } + + + + size_type max_size() const { return par_.max_size(); } + pointer address(reference r) const { return par_.address(r); } + const_pointer address(const_reference cr) const { return par_.address(cr); } + pointer allocate(size_type n, const void *p=0){ return par_.allocate(n,p); } + void deallocate(pointer p, size_type n) { return par_.deallocate(p,n); } + void destroy(pointer p) { return par_.destroy(p); } + + + void + construct (pointer p, const TY& ref) { - return new TY (p0,p1,p2); + cout << "Allo::construct( p="<(ref), *p); } }; + template + inline bool + operator== (Allocator_TransferNoncopyable<_T1> const&, Allocator_TransferNoncopyable<_T2> const&) + { return true; } + + template + inline bool + operator!= (Allocator_TransferNoncopyable<_T1> const&, Allocator_TransferNoncopyable<_T2> const&) + { return false; } + + + + typedef Allocator_TransferNoncopyable Allo; + int main (int argc, char* argv[]) { NOBUG_INIT; + vector mrmpf; + + mrmpf.reserve(2); + mrmpf.push_back(funny::Mrpf()); + mrmpf[0].setup(33); + + cout << ".....resize:\n"; + + mrmpf.resize(5); + + + cout << "Summmmmmmmmmmmmmmmmmmm="< Date: Sun, 26 Oct 2008 22:35:01 +0100 Subject: [PATCH 023/249] create a lib header based on this solution --- src/lib/scopedholder.hpp | 68 +++++++-- src/lib/scopedholdertransfer.hpp | 137 +++++++++++++++++ src/tool/SConscript | 2 +- src/tool/try.cpp | 173 +--------------------- tests/common/scopedholdertest.cpp | 35 +---- tests/common/scopedholdertransfertest.cpp | 164 ++++++++++++++++++++ tests/common/testdummy.hpp | 73 +++++++++ tests/common/vectortransfertest.cpp | 163 ++++++++++++++++++++ 8 files changed, 599 insertions(+), 216 deletions(-) create mode 100644 src/lib/scopedholdertransfer.hpp create mode 100644 tests/common/scopedholdertransfertest.cpp create mode 100644 tests/common/testdummy.hpp create mode 100644 tests/common/vectortransfertest.cpp diff --git a/src/lib/scopedholder.hpp b/src/lib/scopedholder.hpp index 8d1564731..0019b6966 100644 --- a/src/lib/scopedholder.hpp +++ b/src/lib/scopedholder.hpp @@ -39,7 +39,15 @@ ** ScopedHolder implements a similar concept for in-place storage of ** noncopyable objects within STL containers. ** + ** While the added copy operations (secured with the "empty" requirement) + ** are enough to use those holders within fixed sized STL containers, + ** supporting dynamic growth (like in std::vector#resize() ) additionally + ** requires a facility to transfer the lifecycle management control between + ** holder instances. This is the purpose of the \c transfer_control + ** friend function. + ** ** @see scopedholdertest.cpp + ** @see scopedholdertransfer.hpp use in std::vector ** @see AllocationCluster usage example */ @@ -69,6 +77,13 @@ namespace lib { { typedef boost::scoped_ptr _Parent; + static B* must_be_null (_Parent const& ptr) + { + if (ptr) + throw lumiera::error::Logic("ScopedPtrHolder protocol violation: " + "attempt to copy from non-null."); + return 0; + } public: ScopedPtrHolder () @@ -97,14 +112,13 @@ namespace lib { return *this; } - - private: - static B* must_be_null (_Parent const& ptr) + friend void + transfer_control (ScopedPtrHolder& from, ScopedPtrHolder& to) { - if (ptr) - throw lumiera::error::Logic("ScopedPtrHolder protocol violation: " - "attempt to copy from non-null."); - return 0; + if (!from) return; + TRACE (test, "transfer_control... from=%x to=%x",&from, &to); + must_be_null (to); + to.swap(from); } }; @@ -133,11 +147,22 @@ namespace lib { typedef ScopedHolder _ThisType; + static char must_be_empty (_ThisType const& ref) + { + if (ref) + throw lumiera::error::Logic("ScopedHolder protocol violation: " + "copy operation after having invoked create()."); + return 0; + } + public: ScopedHolder() : created_(0) { } + ~ScopedHolder() { clear(); } + + TY& create () { @@ -147,7 +172,8 @@ namespace lib { return *obj; } - ~ScopedHolder() + void + clear () { if (created_) get()->~TY(); @@ -198,16 +224,28 @@ namespace lib { bool operator! () const { return !created_; } - private: - static char must_be_empty (_ThisType const& ref) + friend void + transfer_control (ScopedHolder& from, ScopedHolder& to) { - if (ref) - throw lumiera::error::Logic("ScopedHolder protocol violation: " - "copy operation after having invoked create()."); - return 0; + if (!from) return; + TRACE (test, "transfer_control... from=%x to=%x",&from, &to); + must_be_empty (to); + to.create(); + try + { + transfer_control(*from,*to); // note: assumed to have no side-effect in case it throws + from.clear(); + return; + } + catch(...) + { + to.clear(); + WARN (test, "transfer_control operation aborted."); + throw; + } } }; - + diff --git a/src/lib/scopedholdertransfer.hpp b/src/lib/scopedholdertransfer.hpp new file mode 100644 index 000000000..d894de114 --- /dev/null +++ b/src/lib/scopedholdertransfer.hpp @@ -0,0 +1,137 @@ +/* + SCOPEDHOLDERVECTOR.hpp - using ScopedHolder within a STL vector + + 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. + +*/ + + + +#ifndef LIB_SCOPEDHOLDERVECTOR_H +#define LIB_SCOPEDHOLDERVECTOR_H + +#include "common/error.hpp" +#include + + +namespace lib { + + + + + /** + * Addendum to scopedholder.hpp for transferring the lifecycle + * management to another instance. Using these wrappers within + * STL vector and similar containers may result in the need to + * do a re-allocation in response to a request to grow. + * Obviously such a feature needs support by the objects being + * wrapped, which should provide an operation for transferring + * lifecycle management in a controlled fashion. This behaviour + * is similar to std::auto_ptr, but because we use a separate + * dedicated operation, we avoid some of the dangers pertaining + * the use of the latter: just taking the "value" can't kill + * the managed object. + * \par + * To implement this feature we need + * - a custom allocator to be used by the vector. By default + * it is built as a thin proxy round std::allocator. + * - the \em noncopyable type to be managed within the vector + * needs to provide a custom extension point: when the + * allocator detects the need to transfer control between + * two instances, it will invoke a free function named + * transfer_control(TY& from, TY& to) intended + * to be found by ADL. Note: in case this function throws, + * it must not have any side effects. + * - besides, the \em noncopyable type needs to provide an + * operator bool() yielding true iff currently + * containing an managed object. This is similar to + * boost::scoped_ptr or even the behaviour of a plain + * old raw pointer, which is equivalent to \c true + * when the pointer isn'T \c NULL + * + */ + template > + class Allocator_TransferNoncopyable + { + typedef Allocator_TransferNoncopyable _ThisType; + + PAR par_; + + + public: + typedef typename PAR::size_type size_type; + typedef typename PAR::difference_type difference_type; + typedef typename PAR::pointer pointer; + typedef typename PAR::const_pointer const_pointer; + typedef typename PAR::reference reference; + typedef typename PAR::const_reference const_reference; + typedef typename PAR::value_type value_type; + + template + struct rebind + { typedef Allocator_TransferNoncopyable other; }; + + Allocator_TransferNoncopyable() { } + + Allocator_TransferNoncopyable(const _ThisType& allo) + : par_(allo.par_) { } + Allocator_TransferNoncopyable(const PAR& allo) + : par_(allo) { } + + template + Allocator_TransferNoncopyable(const std::allocator&) { } + + ~Allocator_TransferNoncopyable() { } + + + //------------proxying-the-parent-allocator------------------------------------ + + size_type max_size() const { return par_.max_size(); } + pointer address(reference r) const { return par_.address(r); } + const_pointer address(const_reference cr) const { return par_.address(cr); } + pointer allocate(size_type n, const void *p=0){ return par_.allocate(n,p); } + void deallocate(pointer p, size_type n) { return par_.deallocate(p,n); } + void destroy(pointer p) { return par_.destroy(p); } + + + void + construct (pointer p, const TY& ref) + { + new(p) TY(); + ASSERT (p); + ASSERT (!(*p), "protocol violation: target already manages another object."); + if (ref) + transfer_control (const_cast(ref), *p); + } + }; + + template + inline bool + operator== (Allocator_TransferNoncopyable const&, Allocator_TransferNoncopyable const&) + { return true; } + + template + inline bool + operator!= (Allocator_TransferNoncopyable const&, Allocator_TransferNoncopyable const&) + { return false; } + + + + +} // namespace lib +#endif diff --git a/src/tool/SConscript b/src/tool/SConscript index 9cbf5c8b5..2336c3553 100644 --- a/src/tool/SConscript +++ b/src/tool/SConscript @@ -9,6 +9,6 @@ Import('env','artifacts','core') # build the ubiquitous Hello World application (note: C source) artifacts['tools'] = [ env.Program('#$BINDIR/hello-world','hello.c') + env.Program('#$BINDIR/luidgen', ['luidgen.c']+core) - + env.Program('#$BINDIR/try', ['try.cpp']+core) #### to try out some feature... + + env.Program('#$BINDIR/try', 'try.cpp') #### to try out some feature... ] diff --git a/src/tool/try.cpp b/src/tool/try.cpp index 5741ccf6f..5d1034645 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -14,20 +14,16 @@ // 10/8 - abusing the STL containers to hold noncopyable values -//#include -#include "proc/nobugcfg.hpp" +#include +//#include "proc/nobugcfg.hpp" #include -#include +//#include #include -#include -#include - -#include "lib/scopedholder.hpp" +//#include using std::string; using std::cout; -using std::vector; using boost::format; @@ -37,150 +33,6 @@ using boost::format; } - namespace funny { - - - class Mrpf - : boost::noncopyable - { - long secret_; - - typedef Mrpf _ThisType; - - public: - Mrpf() - : secret_(0) - { - cout << "Mrpf() this=" << this <<"\n"; - } - ~Mrpf() - { - checksum -= secret_; - cout << "~Mrpf() this=" << this <<" skeret="<"< > - class Allocator_TransferNoncopyable - { - typedef Allocator_TransferNoncopyable _ThisType; - - PAR par_; - - - public: - typedef typename PAR::size_type size_type; - typedef typename PAR::difference_type difference_type; - typedef typename PAR::pointer pointer; - typedef typename PAR::const_pointer const_pointer; - typedef typename PAR::reference reference; - typedef typename PAR::const_reference const_reference; - typedef typename PAR::value_type value_type; - - template - struct rebind - { typedef Allocator_TransferNoncopyable<_Tp1, PAR> other; }; - - Allocator_TransferNoncopyable() { } - - Allocator_TransferNoncopyable(const _ThisType& __a) - : par_(__a.par_) { } - Allocator_TransferNoncopyable(const PAR& __a) - : par_(__a) { } - - template - Allocator_TransferNoncopyable(const std::allocator&) { } - - ~Allocator_TransferNoncopyable() { } - - - - size_type max_size() const { return par_.max_size(); } - pointer address(reference r) const { return par_.address(r); } - const_pointer address(const_reference cr) const { return par_.address(cr); } - pointer allocate(size_type n, const void *p=0){ return par_.allocate(n,p); } - void deallocate(pointer p, size_type n) { return par_.deallocate(p,n); } - void destroy(pointer p) { return par_.destroy(p); } - - - void - construct (pointer p, const TY& ref) - { - cout << "Allo::construct( p="<(ref), *p); - } - }; - - template - inline bool - operator== (Allocator_TransferNoncopyable<_T1> const&, Allocator_TransferNoncopyable<_T2> const&) - { return true; } - - template - inline bool - operator!= (Allocator_TransferNoncopyable<_T1> const&, Allocator_TransferNoncopyable<_T2> const&) - { return false; } - - - - typedef Allocator_TransferNoncopyable Allo; int main (int argc, char* argv[]) @@ -188,22 +40,7 @@ main (int argc, char* argv[]) NOBUG_INIT; - vector mrmpf; - - mrmpf.reserve(2); - mrmpf.push_back(funny::Mrpf()); - mrmpf[0].setup(33); - - cout << ".....resize:\n"; - - mrmpf.resize(5); - - - cout << "Summmmmmmmmmmmmmmmmmmm="< #include @@ -40,39 +41,9 @@ namespace lib { using std::map; using std::cout; - - namespace { // yet another test dummy - long checksum = 0; - bool magic = false; - - class Dummy - : boost::noncopyable - { - int val_; - - public: - Dummy () - : val_(1 + (rand() % 100000000)) - { - checksum += val_; - if (magic) - throw val_; - } - - ~Dummy() - { - checksum -= val_; - } - - long add (int i) { return val_+i; } - }; - - - typedef ScopedHolder HolderD; - typedef ScopedPtrHolder PtrHolderD; - - } + typedef ScopedHolder HolderD; + typedef ScopedPtrHolder PtrHolderD; /********************************************************************************** diff --git a/tests/common/scopedholdertransfertest.cpp b/tests/common/scopedholdertransfertest.cpp new file mode 100644 index 000000000..b933ad253 --- /dev/null +++ b/tests/common/scopedholdertransfertest.cpp @@ -0,0 +1,164 @@ +/* + ScopedHolderTransfer(Test) - managing noncopyable objects within a growing vector + + 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. + +* *****************************************************/ + + + +#include "common/test/run.hpp" +#include "common/util.hpp" + +#include "lib/scopedholder.hpp" +#include "lib/scopedholdertransfer.hpp" +#include "testdummy.hpp" + +#include +#include + + +namespace lib { + namespace test { + + using ::Test; + using util::isnil; + + using std::map; + using std::cout; + + + typedef ScopedHolder HolderD; + typedef ScopedPtrHolder PtrHolderD; + + + + /********************************************************************************** + * @test ScopedHolder and ScopedPtrHolder are initially empty and copyable. + * After taking ownership, they prohibit copy operations, manage the + * lifecycle of the contained object and provide smart-ptr like access. + * A series of identical tests is conducted both with the ScopedPtrHolder + * (the contained objects are heap allocated but managed by the holder) + * and with the ScopedHolder (objects placed inline) + */ + class ScopedHolderTransfer_test : public Test + { + + virtual void + run (Arg arg) + { + + cout << "checking ScopedHolder...\n"; + buildVector(); + growVector(); + checkErrorHandling(); + + cout << "checking ScopedPtrHolder...\n"; + buildVector(); + growVector(); + checkErrorHandling(); + } + + void create_contained_object (HolderD& holder) { holder.create(); } + void create_contained_object (PtrHolderD& holder) { holder.reset(new Dummy()); } + + + template + void + buildVector() + { + ASSERT (0==checksum); + { + UNIMPLEMENTED ("create constant sized vector holding noncopyables"); + HO holder; + ASSERT (!holder); + ASSERT (0==checksum); + + create_contained_object (holder); + ASSERT (holder); + ASSERT (false!=holder); + ASSERT (holder!=false); + + ASSERT (0!=checksum); + ASSERT ( &(*holder)); + ASSERT (holder->add(2) == checksum+2); + + Dummy *rawP = holder.get(); + ASSERT (rawP); + ASSERT (holder); + ASSERT (rawP == &(*holder)); + ASSERT (rawP->add(-5) == holder->add(-5)); + + TRACE (test, "holder at %x", &holder); + TRACE (test, "object at %x", holder.get() ); + TRACE (test, "size(object) = %d", sizeof(*holder)); + TRACE (test, "size(holder) = %d", sizeof(holder)); + } + ASSERT (0==checksum); + } + + + template + void + growVector() + { + ASSERT (0==checksum); + { + UNIMPLEMENTED ("check growing a vector holding noncopyables"); + } + ASSERT (0==checksum); + } + + + template + void + checkErrorHandling() + { + UNIMPLEMENTED ("throw an error while growing"); + ASSERT (0==checksum); + { + HO holder; + + magic = true; + try + { + create_contained_object (holder); + NOTREACHED ; + } + catch (int val) + { + ASSERT (0!=checksum); + checksum -= val; + ASSERT (0==checksum); + } + ASSERT (!holder); /* because the exception happens in ctor + object doesn't count as "created" */ + magic = false; + } + ASSERT (0==checksum); + } + + }; + + LAUNCHER (ScopedHolderTransfer_test, "unit common"); + + + }// namespace test + +} // namespace lib + diff --git a/tests/common/testdummy.hpp b/tests/common/testdummy.hpp new file mode 100644 index 000000000..31db265b3 --- /dev/null +++ b/tests/common/testdummy.hpp @@ -0,0 +1,73 @@ +/* + TESTDUMMY.hpp - yet another test dummy for tracking ctor/dtor calls + + 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. + +* *****************************************************/ + + + +#include + + +namespace lib { + namespace test { + + namespace { // yet another test dummy + + long checksum = 0; + bool magic = false; + + class Dummy + : boost::noncopyable + { + int val_; + + public: + Dummy () + : val_(1 + (rand() % 100000000)) + { + checksum += val_; + if (magic) + throw val_; + } + + ~Dummy() + { + checksum -= val_; + } + + long add (int i) { return val_+i; } + + protected: + int getVal() const { return val_; } + + void + setVal (int newVal) + { + checksum += newVal - val_; + val_ = newVal; + } + }; + + }// anonymous test dummy + + }// namespace test + +} // namespace lib + diff --git a/tests/common/vectortransfertest.cpp b/tests/common/vectortransfertest.cpp new file mode 100644 index 000000000..b4c415c3e --- /dev/null +++ b/tests/common/vectortransfertest.cpp @@ -0,0 +1,163 @@ +/* + VectorTransfer(Test) - intercept object copying when a STL vector grows + + 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. + +* *****************************************************/ + + + +#include "common/test/run.hpp" + +#include "lib/scopedholdertransfer.hpp" +#include "testdummy.hpp" + +#include +#include + + +namespace lib { + namespace test { + + using ::Test; + using std::vector; + using std::cout; + + namespace { // extending the Dummy for our special purpose.... + + class TransDummy + : public Dummy + { + public: + TransDummy() + { + TRACE (test, "CTOR TransDummy() --> this=%x", this); + setVal(0); // we use val_==0 to mark the "empty" state + } + + ~TransDummy() + { + TRACE (test, "DTOR ~TransDummy() this=%x", this); + } + + /* to make Dummy usable within vector, we need to provide + * \em special copy operations, an operator bool() and + * a transfer_control friend function to be used by + * our special allocator. + */ + + TransDummy (const TransDummy& o) + { + TRACE (test, "COPY-ctor TransDummy( ref=%x ) --> this=%x", &o,this); + ASSERT (!o, "protocol violation: real copy operations inhibited"); + } + + TransDummy& + operator= (TransDummy const& ref) + { + TRACE (test, "COPY target=%x <-- source=%x", this,&ref); + ASSERT (!(*this)); + ASSERT (!ref, "protocol violation: real copy operations inhibited"); + return *this; + } + + void + setup (int x=0) + { + setVal (x? x : (rand() % 10000)); + TRACE (test, "CREATE val=%d ---> this=%x", getVal(),this); + } + + + // define implicit conversion to "bool" the naive way... + operator bool() const + { + return 0!=getVal(); + } + + + friend void transfer_control (TransDummy& from, TransDummy& to); + + }; + + + void + transfer_control (TransDummy& from, TransDummy& to) + { + TRACE (test, "TRANSFER target=%x <-- source=%x", &to,&from); + ASSERT (!to, "protocol violation: target already manages another object"); + to.setVal (from.getVal()); + from.setVal(0); + } + + typedef Allocator_TransferNoncopyable Allo; + typedef vector TransDummyVector; + } + + + + + /********************************************************************************** + * @test ScopedHolder and ScopedPtrHolder are initially empty and copyable. + * After taking ownership, they prohibit copy operations, manage the + * lifecycle of the contained object and provide smart-ptr like access. + * A series of identical tests is conducted both with the ScopedPtrHolder + * (the contained objects are heap allocated but managed by the holder) + * and with the ScopedHolder (objects placed inline) + */ + class VectorTransfer_test : public Test + { + + virtual void + run (Arg arg) + { + cout << "\n..setup table space for 2 elements\n"; + TransDummyVector table; + table.reserve(2); + ASSERT (0==checksum); + + cout << "\n..install one element at index[0]\n"; + table.push_back(TransDummy()); + ASSERT (0==checksum); + + table[0].setup(); // switches into "managed" state + ASSERT (0 < checksum); + int theSum = checksum; + + cout << "\n..*** resize table to 5 elements\n"; + table.resize(5); + ASSERT (theSum==checksum); + + cout << "\n..install another element\n"; + table[3].setup(375); + ASSERT (theSum+375==checksum); + + cout << "\n..kill all elements....\n"; + table.clear(); + ASSERT (0==checksum); + } + + }; + + LAUNCHER (VectorTransfer_test, "unit common"); + + + }// namespace test + +} // namespace lib + From 340b90bee10c8b7553daa711b852ad3ea4ed7e2d Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 26 Oct 2008 22:43:54 +0100 Subject: [PATCH 024/249] add the new tests to proc lib test suite --- tests/50components.tests | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/50components.tests b/tests/50components.tests index 37b867be1..71f4a5d51 100644 --- a/tests/50components.tests +++ b/tests/50components.tests @@ -266,6 +266,18 @@ out: TestSingletonO::doIt() call=3 END +TEST "ScopedHolder_test" ScopedHolder_test <... +out: checking ScopedPtrHolder... +END + + +TEST "ScopedHolderTransfer_test" ScopedHolderTransfer_test <... +out: checking ScopedPtrHolder... +END + + TEST "Singleton_test" Singleton_test 23 < Date: Sat, 25 Oct 2008 06:38:56 +0200 Subject: [PATCH 025/249] define an 'LUIDGEN' macro as uuid containing only zeros This *must* be replaced by a real luid with a upcoming luidgen tool ASAP, luids starting with zeros are invalid. For the time until this luidgen tool is not ready we just leave it this way. Later it will be changed to give a compile error. --- src/lib/luid.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib/luid.h b/src/lib/luid.h index 553d22765..9d699cfcb 100644 --- a/src/lib/luid.h +++ b/src/lib/luid.h @@ -48,6 +48,11 @@ typedef lumiera_uid* LumieraUid; #define LUMIERA_UID_INITIALIZER(l) l #endif +/** + * LUIDGEN will be replaced by the 'luidgen' tool with a random uuid + */ +#define LUIDGEN "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + /** * Retrieve a generic pointer stored in a luid */ From 99e3e79fe6d940fd4b7029a1a6b7bc96c9a8d9b7 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 25 Oct 2008 06:41:38 +0200 Subject: [PATCH 026/249] Complete the interface descriptor declaration After a discussion with ichthyo and some further thinking this should be mostly finished now. Nevertheless it is still experimental until we gain experience with it. --- src/backend/interfacedescriptor.h | 40 ++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/backend/interfacedescriptor.h b/src/backend/interfacedescriptor.h index 468bd2e80..513a783a7 100644 --- a/src/backend/interfacedescriptor.h +++ b/src/backend/interfacedescriptor.h @@ -23,17 +23,51 @@ #include "backend/interface.h" + /** - * WIP: interface descriptor, needs some generic metadata interface + * Release state of an interface implementation. + * The interfase subsystem must be able to categorize implementation to present possible + * upgrade paths to the user. This is done by the tagging it to a certain state in concert + * with the version and the user supplied version compare function. The respective numbers + * are choosen in a way that a higher value indicates precedence when selecting an implementation. + * Note that 'BETA' is higher than 'DEPRECATED' (we make the assumption that BETA is at least + * maintained code and something gets deprecated for some reason), for common practice it is still + * suggested to make a stable release before declaring its predcessor version as deprecated. + */ +enum lumiera_interface_state { + /** some known bugs exist which won't be fixed, don't use this */ + LUMIERA_INTERFACE_BROKEN = -1, + /** Not finished development code */ + LUMIERA_INTERFACE_EXPERIMENTAL = 0, + /** Old implementation which is now unmaintained and will be removed soon */ + LUMIERA_INTERFACE_DEPRECATED = 1, + /** Finished but not finally released implementation for open testing */ + LUMIERA_INTERFACE_BETA = 2, + /** Finished, released and maintained implementation */ + LUMIERA_INTERFACE_STABLE = 3 +}; + + +/** + * Interface descriptor. + * This defines an interface for querying metadata common to all interface implementations */ LUMIERA_INTERFACE_DECLARE (lumieraorg_interfacedescriptor, 0, /* The following slots are some human-readable descriptions of certain properties */ LUMIERA_INTERFACE_SLOT (const char*, name, (LumieraInterface)), + LUMIERA_INTERFACE_SLOT (const char*, brief, (LumieraInterface)), + LUMIERA_INTERFACE_SLOT (const char*, homepage, (LumieraInterface)), LUMIERA_INTERFACE_SLOT (const char*, version, (LumieraInterface)), LUMIERA_INTERFACE_SLOT (const char*, author, (LumieraInterface)), + LUMIERA_INTERFACE_SLOT (const char*, email, (LumieraInterface)), LUMIERA_INTERFACE_SLOT (const char*, copyright, (LumieraInterface)), - LUMIERA_INTERFACE_SLOT (const char*, license, (LumieraInterface)) - /* TODO add more things here, dependencies, provisions etc */ + LUMIERA_INTERFACE_SLOT (const char*, license, (LumieraInterface)), + + /* some flags for properties */ + LUMIERA_INTERFACE_SLOT (int, state, (LumieraInterface)), + + /* compare 2 version strings in a custom way */ + LUMIERA_INTERFACE_SLOT (int, versioncmp, (const char*, const char*)) ); From 41ec9edd6f3ebb1781d30d711a8a4f687b35f657 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 25 Oct 2008 06:42:30 +0200 Subject: [PATCH 027/249] fix tests to adhere with the new interface descriptor --- tests/backend/test-interfaces.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/backend/test-interfaces.c b/tests/backend/test-interfaces.c index 09fa25afa..b27bf7227 100644 --- a/tests/backend/test-interfaces.c +++ b/tests/backend/test-interfaces.c @@ -79,16 +79,28 @@ LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0, testacquire, testrelease, LUMIERA_INTERFACE_INLINE (name, "\073\003\054\127\344\046\324\321\221\262\232\026\376\123\125\243", + const char*, (LumieraInterface iface), + {return "LumieraTest";} + ), + LUMIERA_INTERFACE_INLINE (brief, LUIDGEN, const char*, (LumieraInterface iface), {return "Lumiera Test suite examples";} ), + LUMIERA_INTERFACE_INLINE (homepage, LUIDGEN, + const char*, (LumieraInterface iface), + {return "http://www.lumiera.org/develompent.html";} + ), LUMIERA_INTERFACE_INLINE (version, "\271\330\345\066\304\217\211\065\157\120\031\365\304\363\364\074", const char*, (LumieraInterface iface), {return "No Version";} ), LUMIERA_INTERFACE_INLINE (author, "\367\160\342\065\147\007\237\371\141\335\371\131\025\030\257\232", const char*, (LumieraInterface iface), - {return "Christian Thaeter ";} + {return "Christian Thaeter";} + ), + LUMIERA_INTERFACE_INLINE (email, LUIDGEN, + const char*, (LumieraInterface iface), + {return "ct@pipapo.org";} ), LUMIERA_INTERFACE_INLINE (copyright, "\163\106\344\014\251\125\111\252\236\322\174\120\335\225\333\245", const char*, (LumieraInterface iface), @@ -116,6 +128,16 @@ LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0, "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, LUIDGEN, + int, (LumieraInterface iface), + {return LUMIERA_INTERFACE_EXPERIMENTAL;} + ), + + LUMIERA_INTERFACE_INLINE (versioncmp, LUIDGEN, + int, (const char* a, const char* b), + {return 0;} ) ); From 1886f41bf57f14a164ce5e5da05152b77e4c75cb Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 25 Oct 2008 07:00:21 +0200 Subject: [PATCH 028/249] WIP: testsuite for interfaces --- tests/30interfaces.tests | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/30interfaces.tests diff --git a/tests/30interfaces.tests b/tests/30interfaces.tests new file mode 100644 index 000000000..efc9f1148 --- /dev/null +++ b/tests/30interfaces.tests @@ -0,0 +1,38 @@ +TESTING "test interfaces" ./test-interfaces + +TEST "Basic operations" basic < Date: Sun, 26 Oct 2008 03:11:02 +0100 Subject: [PATCH 029/249] Complete the luidgen tool calling 'luidgen' with a list of filenames replaces the word LUIDGEN in each of this files with a octal escaped string consisting a unique identifier add luid formatter help macros to luid.h let compilation of files which contain the word 'LUIDGEN' fail with a hopefully self-explaining error message --- src/lib/luid.h | 18 +++++++++- src/tool/Makefile.am | 2 +- src/tool/luidgen.c | 83 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/lib/luid.h b/src/lib/luid.h index 9d699cfcb..0986e5580 100644 --- a/src/lib/luid.h +++ b/src/lib/luid.h @@ -48,10 +48,26 @@ typedef lumiera_uid* LumieraUid; #define LUMIERA_UID_INITIALIZER(l) l #endif +#define LUMIERA_UID_FMT \ + "\\%.3hho\\%.3hho\\%.3hho\\%.3hho" \ + "\\%.3hho\\%.3hho\\%.3hho\\%.3hho" \ + "\\%.3hho\\%.3hho\\%.3hho\\%.3hho" \ + "\\%.3hho\\%.3hho\\%.3hho\\%.3hho" + +#define LUMIERA_UID_CHAR(l,n) ((unsigned char*)l)[n] + + +#define LUMIERA_UID_ELEMENTS(l) \ + LUMIERA_UID_CHAR(l,0), LUMIERA_UID_CHAR(l,1), LUMIERA_UID_CHAR(l,2), LUMIERA_UID_CHAR(l,3), \ + LUMIERA_UID_CHAR(l,4), LUMIERA_UID_CHAR(l,5), LUMIERA_UID_CHAR(l,6), LUMIERA_UID_CHAR(l,7), \ + LUMIERA_UID_CHAR(l,8), LUMIERA_UID_CHAR(l,9), LUMIERA_UID_CHAR(l,10), LUMIERA_UID_CHAR(l,11), \ + LUMIERA_UID_CHAR(l,12), LUMIERA_UID_CHAR(l,13), LUMIERA_UID_CHAR(l,14), LUMIERA_UID_CHAR(l,15) + /** * LUIDGEN will be replaced by the 'luidgen' tool with a random uuid */ -#define LUIDGEN "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" +#define LUIDGEN PLEASE_RUN_THE_LUIDGEN_TOOL_ON_THIS_FILE + /** * Retrieve a generic pointer stored in a luid diff --git a/src/tool/Makefile.am b/src/tool/Makefile.am index 8a4234c05..a48bf0cea 100644 --- a/src/tool/Makefile.am +++ b/src/tool/Makefile.am @@ -24,4 +24,4 @@ luidgen_CPPFLAGS = -I$(top_srcdir)/src/ luidgen_SOURCES = \ $(lumitool_srcdir)/luidgen.c -luidgen_LDADD = liblumiera.a +luidgen_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) diff --git a/src/tool/luidgen.c b/src/tool/luidgen.c index 41081ca97..730395b6c 100644 --- a/src/tool/luidgen.c +++ b/src/tool/luidgen.c @@ -19,25 +19,98 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "lib/safeclib.h" #include "lib/luid.h" +#include +#include +#include #include +#include +#include /** * @file * Generate amd print a Lumiera uid as octal escaped string + * or process a file replaceing 'LUIDGEN' with a octal escaped string */ + int main (int argc, char** argv) { + NOBUG_INIT; lumiera_uid luid; - lumiera_uid_gen (&luid); - printf ("\""); - for (int i = 0; i < 16; ++i) - printf ("\\%.3hho", *(((char*)&luid)+i)); - printf ("\"\n"); + if (argc == 1) + { + lumiera_uid_gen (&luid); + printf ("\""); + for (int i = 0; i < 16; ++i) + printf ("\\%.3hho", *(((char*)&luid)+i)); + printf ("\"\n"); + } + else + { + for (int i = 1; i < argc; ++i) + { + FILE* in = fopen (argv[i], "r"); + if (!in) + { + fprintf (stderr, "Failed to open file %s for reading: %s\n", argv[i], strerror (errno)); + continue; + } + + char* outname = lumiera_tmpbuf_snprintf (SIZE_MAX, "%s.luidgen", argv[i]); + FILE* out = fopen (outname, "wx"); + if (!out) + { + fprintf (stderr, "Failed to open file %s for writing: %s\n", outname, strerror (errno)); + fclose (in); + continue; + } + + char buf[4096]; + char luidbuf[67]; + + printf ("Luidgen %s ", argv[i]); fflush (stdout); + + while (fgets (buf, 4096, in)) + { + char* pos; + while ((pos = strstr(buf, "LUIDGEN"))) + { + memmove (pos+66, pos+7, strlen (pos+7)+1); + lumiera_uid_gen (&luid); + sprintf (luidbuf, "\""LUMIERA_UID_FMT"\"", LUMIERA_UID_ELEMENTS(luid)); + memcpy (pos, luidbuf, 66); + putchar ('.'); fflush (stdout); + } + fputs (buf, out); + } + + fclose (out); + fclose (in); + + char* backup = lumiera_tmpbuf_snprintf (SIZE_MAX, "%s~", argv[i]); + unlink (backup); + + if (!!rename (argv[i], backup)) + { + fprintf (stderr, "Failed to create backupfile %s: %s\n", backup, strerror (errno)); + continue; + } + + if (!!rename (outname, argv[i])) + { + fprintf (stderr, "Renaming %s to %s failed: %s\n", outname, argv[i], strerror (errno)); + rename (backup, argv[i]); + continue; + } + + printf (" done\n"); + } + } return 0; } From 33c8e79ccb259d09ddb1bcf6364b471e7e6ad968 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 26 Oct 2008 03:08:23 +0100 Subject: [PATCH 030/249] ran luidgen on test-interfaces.c --- tests/backend/test-interfaces.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/backend/test-interfaces.c b/tests/backend/test-interfaces.c index b27bf7227..8d7c377e8 100644 --- a/tests/backend/test-interfaces.c +++ b/tests/backend/test-interfaces.c @@ -82,11 +82,11 @@ LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0, const char*, (LumieraInterface iface), {return "LumieraTest";} ), - LUMIERA_INTERFACE_INLINE (brief, LUIDGEN, + LUMIERA_INTERFACE_INLINE (brief, "\241\337\035\172\323\377\355\036\171\326\323\163\177\242\364\172", const char*, (LumieraInterface iface), {return "Lumiera Test suite examples";} ), - LUMIERA_INTERFACE_INLINE (homepage, LUIDGEN, + LUMIERA_INTERFACE_INLINE (homepage, "\030\374\031\152\024\167\154\346\303\372\177\353\304\306\275\247", const char*, (LumieraInterface iface), {return "http://www.lumiera.org/develompent.html";} ), @@ -98,7 +98,7 @@ LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0, const char*, (LumieraInterface iface), {return "Christian Thaeter";} ), - LUMIERA_INTERFACE_INLINE (email, LUIDGEN, + LUMIERA_INTERFACE_INLINE (email, "\334\272\125\312\140\347\121\020\155\047\226\352\244\141\107\363", const char*, (LumieraInterface iface), {return "ct@pipapo.org";} ), @@ -130,12 +130,12 @@ LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0, } ), - LUMIERA_INTERFACE_INLINE (state, LUIDGEN, + LUMIERA_INTERFACE_INLINE (state, "\364\002\115\170\361\321\301\244\350\322\270\362\010\231\207\334", int, (LumieraInterface iface), {return LUMIERA_INTERFACE_EXPERIMENTAL;} ), - LUMIERA_INTERFACE_INLINE (versioncmp, LUIDGEN, + LUMIERA_INTERFACE_INLINE (versioncmp, "\136\037\234\304\100\247\244\342\324\353\072\060\161\053\077\263", int, (const char* a, const char* b), {return 0;} ) From 84df01893153999b7bfa865429eda0300283e39f Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 26 Oct 2008 05:04:44 +0100 Subject: [PATCH 031/249] some cosmetics and a copy'n'paste interfacedescriptor example --- src/backend/interfacedescriptor.h | 65 +++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/src/backend/interfacedescriptor.h b/src/backend/interfacedescriptor.h index 513a783a7..29894c686 100644 --- a/src/backend/interfacedescriptor.h +++ b/src/backend/interfacedescriptor.h @@ -26,12 +26,12 @@ /** * Release state of an interface implementation. - * The interfase subsystem must be able to categorize implementation to present possible + * The interface subsystem must be able to categorize implementations to present possible * upgrade paths to the user. This is done by the tagging it to a certain state in concert * with the version and the user supplied version compare function. The respective numbers * are choosen in a way that a higher value indicates precedence when selecting an implementation. - * Note that 'BETA' is higher than 'DEPRECATED' (we make the assumption that BETA is at least - * maintained code and something gets deprecated for some reason), for common practice it is still + * Note that 'BETA' is higher than 'DEPRECATED', we make the assumption that BETA is at least + * maintained code and something gets deprecated for some reason. For common practice it is * suggested to make a stable release before declaring its predcessor version as deprecated. */ enum lumiera_interface_state { @@ -71,6 +71,65 @@ LUMIERA_INTERFACE_DECLARE (lumieraorg_interfacedescriptor, 0, ); +#if 0 +/** + * For convinience, a copy'n'paste descriptor + */ +LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0, + /*IDENTIFIER*/, + NULL, NULL, NULL, + LUMIERA_INTERFACE_INLINE (name, LUIDGEN, + const char*, (LumieraInterface iface), + {return /*NAME*/;} + ), + LUMIERA_INTERFACE_INLINE (brief, LUIDGEN, + const char*, (LumieraInterface iface), + {return /*BRIEF*/;} + ), + LUMIERA_INTERFACE_INLINE (homepage, LUIDGEN, + const char*, (LumieraInterface iface), + {return /*HOMEPAGE*/;} + ), + LUMIERA_INTERFACE_INLINE (version, LUIDGEN, + const char*, (LumieraInterface iface), + {return /*VERSION*/;} + ), + LUMIERA_INTERFACE_INLINE (author, LUIDGEN, + const char*, (LumieraInterface iface), + {return /*AUTHOR*/;} + ), + LUMIERA_INTERFACE_INLINE (email, LUIDGEN, + const char*, (LumieraInterface iface), + {return /*EMAIL*/;} + ), + LUMIERA_INTERFACE_INLINE (copyright, LUIDGEN, + const char*, (LumieraInterface iface), + { + return + "Copyright (C) "/*ORGANIZATION*/"\n" + " "/*YEARS*/" "/*AUTHOR*/" <"/*EMAIL*/">"; + } + ), + LUMIERA_INTERFACE_INLINE (license, LUIDGEN, + const char*, (LumieraInterface iface), + { + return + /*LICENSE*/; + } + ), + + LUMIERA_INTERFACE_INLINE (state, LUIDGEN, + int, (LumieraInterface iface), + {return /*LUMIERA_INTERFACE_EXPERIMENTAL*/;} + ), + + LUMIERA_INTERFACE_INLINE (versioncmp, LUIDGEN, + int, (const char* a, const char* b), + {return /*COMPARERESULT*/;} + ) + ); +#endif + #endif /* LUMIERA_INTERFACEDESCRIPTORS_H */ /* From ab3d3823f6941da7ea522cc9014e25e4ab248550 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 26 Oct 2008 05:38:06 +0100 Subject: [PATCH 032/249] autotools fixes for the plugin system don't link the tests with -ldl Renamed GTK_LUMIERA_* to LUMIERA_GUI_* and include all gui relevant config results here. Set it explicit, don't add the results to CFLAGS or LIBS, the default behaviour linked all LIBS in, even in plugins, that was not intended. --- admin/Makefile.am | 2 +- configure.ac | 29 +++++++++++++---------------- src/gui/Makefile.am | 9 +++++---- tests/Makefile.am | 20 ++++++++++---------- 4 files changed, 29 insertions(+), 31 deletions(-) diff --git a/admin/Makefile.am b/admin/Makefile.am index da1c244a7..9160c34ee 100644 --- a/admin/Makefile.am +++ b/admin/Makefile.am @@ -24,5 +24,5 @@ vgsuppression_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -ldl noinst_PROGRAMS += rsvg-convert rsvg_convert_SOURCES = $(admin_srcdir)/rsvg-convert.c -rsvg_convert_CPPFLAGS = $(AM_CPPFLAGS) $(GTK_LUMIERA_CFLAGS) -std=gnu99 -Wall -Werror +rsvg_convert_CPPFLAGS = $(AM_CPPFLAGS) $(LUMIERA_GUI_CFLAGS) -std=gnu99 -Wall -Werror rsvg_convert_LDADD = -lcairo -lglib-2.0 -lgthread-2.0 -lrsvg-2 diff --git a/configure.ac b/configure.ac index 4df50f245..6aafc1a2c 100644 --- a/configure.ac +++ b/configure.ac @@ -124,15 +124,19 @@ AC_LANG_POP([C++]) # END Internatinalization +############## Gtk Dependancies +PKG_CHECK_MODULES(LUMIERA_GUI, [ + gtkmm-2.4 >= 2.8 gdl-1.0 >= 0.6.1 cairomm-1.0 >= 0.6.0 + gavl >= 0.2.5 librsvg-2.0 >= 2.18.1]) + +# END Gtk Dependancies ############## X11 Dependancies AC_PATH_X AC_PATH_XTRA -# CFLAGS="$CFLAGS $X_CFLAGS" -LIBS="$LIBS $X_PRE_LIBS $X_LIBS $X_EXTRA_LIBS" AC_CHECK_HEADERS([X11/Xlib.h X11/Xutil.h],[], - [AC_MSG_ERROR([Xlib.h or Xutil.h not found install xdevel])]) + [AC_MSG_ERROR([Xlib.h or Xutil.h not found install xdevel])]) AC_CHECK_HEADERS([sys/ipc.h sys/shm.h],, [AC_MSG_ERROR([Required header not found. Please check that it is installed])] @@ -142,25 +146,18 @@ AC_CHECK_HEADERS([X11/extensions/Xvlib.h X11/extensions/XShm.h],, [#include ] ) -AC_CHECK_LIB(Xext, XInitExtension, , - [AC_MSG_ERROR([Could not link with libXext. Check that you have libXext installed])], -lX11 +AC_CHECK_LIB(Xext, XInitExtension, [LUMIERA_GUI_LIBS="$LUMIERA_GUI_LIBS -lXext"], + [AC_MSG_ERROR([Could not link with libXext. Check that you have libXext installed])], -lX11 ) -AC_CHECK_LIB(Xv, XvQueryAdaptors, , - [AC_MSG_ERROR([Could not link with libXv. Check that you have libXv installed])] +AC_CHECK_LIB(Xv, XvQueryAdaptors, [LUMIERA_GUI_LIBS="$LUMIERA_GUI_LIBS -lXv"], + [AC_MSG_ERROR([Could not link with libXv. Check that you have libXv installed])] ) # END X11 Dependancies -############## Gtk Dependancies -PKG_CHECK_MODULES(GTK_LUMIERA, [ - gtkmm-2.4 >= 2.8 gdl-1.0 >= 0.6.1 cairomm-1.0 >= 0.6.0 - gavl >= 0.2.5 librsvg-2.0 >= 2.18.1]) - -AC_SUBST(GTK_LUMIERA_CFLAGS) -AC_SUBST(GTK_LUMIERA_LIBS) - -# END Gtk Dependancies +AC_SUBST(LUMIERA_GUI_CFLAGS) +AC_SUBST(LUMIERA_GUI_LIBS) ############## Nobug Dependancies diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 316887403..928f42a9b 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -24,7 +24,7 @@ lumigui_CPPFLAGS = $(AM_CPPFLAGS) \ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ - $(GTK_LUMIERA_CFLAGS) + $(LUMIERA_GUI_CFLAGS) bin_PROGRAMS += lumigui @@ -76,14 +76,15 @@ lumigui_SOURCES = \ $(lumigui_srcdir)/output/xvdisplayer.cpp \ $(lumigui_srcdir)/output/xvdisplayer.hpp -lumigui_LDFLAGS = -lumigui_LDADD = $(GTK_LUMIERA_LIBS) liblumicommon.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) +lumigui_LDFLAGS = +# $(LIBS) $(X_PRE_LIBS) $(X_LIBS) $(X_EXTRA_LIBS) +lumigui_LDADD = $(LUMIERA_GUI_LIBS) liblumicommon.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) lumigui_DEPENDENCIES = \ $(top_builddir)/lumiera_ui.rc \ $(top_builddir)/liblumicommon.a \ $(top_builddir)/liblumiera.a - + $(top_builddir)/lumiera_ui.rc: cp $(lumigui_srcdir)/lumiera_ui.rc $(top_builddir) diff --git a/tests/Makefile.am b/tests/Makefile.am index 10cdeed10..5554c0dc3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -21,51 +21,51 @@ tests_srcdir = $(top_srcdir)/tests check_PROGRAMS += test-error test_error_SOURCES = $(tests_srcdir)/error/errortest.c test_error_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_error_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -ldl +test_error_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) check_PROGRAMS += test-locking test_locking_SOURCES = $(tests_srcdir)/library/test-locking.c test_locking_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_locking_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +test_locking_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm check_PROGRAMS += test-llist test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_llist_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +test_llist_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm check_PROGRAMS += test-psplay test_psplay_SOURCES = $(tests_srcdir)/library/test-psplay.c test_psplay_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ -test_psplay_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +test_psplay_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm check_PROGRAMS += test-safeclib test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_safeclib_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +test_safeclib_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm check_PROGRAMS += test-luid test_luid_SOURCES = $(tests_srcdir)/library/test-luid.c test_luid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_luid_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +test_luid_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm check_PROGRAMS += test-interfaces test_interfaces_SOURCES = $(tests_srcdir)/backend/test-interfaces.c test_interfaces_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_interfaces_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +test_interfaces_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm check_PROGRAMS += test-filedescriptors test_filedescriptors_SOURCES = $(tests_srcdir)/backend/test-filedescriptors.c test_filedescriptors_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_filedescriptors_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +test_filedescriptors_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm check_PROGRAMS += test-filehandles test_filehandles_SOURCES = $(tests_srcdir)/backend/test-filehandles.c test_filehandles_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_filehandles_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +test_filehandles_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm check_PROGRAMS += test-config test_config_SOURCES = $(tests_srcdir)/backend/test-config.c test_config_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ -test_config_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +test_config_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm TESTS = $(tests_srcdir)/test.sh From a4c028bd34eb84d57c01d2c2372167f4b75baf38 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 26 Oct 2008 22:00:02 +0100 Subject: [PATCH 033/249] Prepare autotools for plugins --- Makefile.am | 4 +++- configure.ac | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index d236fbfd8..068388274 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,11 +19,13 @@ ACLOCAL_AMFLAGS = -I m4 bin_PROGRAMS = -lib_LTLIBRARIES = noinst_PROGRAMS = check_PROGRAMS = noinst_LIBRARIES = +lib_LTLIBRARIES = check_LTLIBRARIES = +pkglib_LTLIBRARIES = +noinst_LTLIBRARIES = noinst_HEADERS = BUILT_SOURCES = EXTRA_DIST = diff --git a/configure.ac b/configure.ac index 6aafc1a2c..ae9f0d79b 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,11 @@ AC_COPYRIGHT([ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ]) +# +# Global configuration +# AC_GNU_SOURCE +AC_DISABLE_STATIC # # Required programs From b242f3359be50fa3aa94c38dcb5a194b0d63e873 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 26 Oct 2008 22:03:10 +0100 Subject: [PATCH 034/249] Fix/Wip: LUMIERA_PLUGIN definition There where some bugs slipped in (not yet tested code) removed the descriptor from the plugin itself, lets see if we can remove the acquire and release functions later too. Declare the plugin interface itself in its first experimental state --- src/backend/interface.h | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/backend/interface.h b/src/backend/interface.h index ef13e40e1..7b97fd82e 100644 --- a/src/backend/interface.h +++ b/src/backend/interface.h @@ -291,17 +291,15 @@ queryfunc (void) \ * lumiera uuid generator tool (to be written) over the source file to generate luid's automatically * @param ... list of LUMIERA_INTERFACE_DEFINE() for all interfaces this plugin provides. */ -#define LUMIERA_PLUGIN(descriptor, acquire, release, luid, ...) \ +#define LUMIERA_PLUGIN(acquire, release, luid, ...) \ LUMIERA_EXPORT(plugin_interfaces, __VA_ARGS__) \ -LUMIERA_INTERFACE_DEFINE (lumieraorg_plugin, 0, \ - lumieraorg_plugin_0, \ - NULL, \ - NULL, \ - NULL, \ - LUMIERA_INTERFACE_MAP (plugin_interfaces, plugin_interfaces, luid) \ - ) - - +LUMIERA_INTERFACE_INSTANCE (lumieraorg_plugin, 0, \ + lumieraorg_plugin, \ + NULL, \ + acquire, \ + release, \ + LUMIERA_INTERFACE_MAP (plugin_interfaces, luid, plugin_interfaces) \ + ); /** * create a handle for a interface (WIP) @@ -372,6 +370,15 @@ struct lumiera_interface_struct #endif }; + +/** + * Plugin interface + */ +LUMIERA_INTERFACE_DECLARE (lumieraorg_plugin, 0, + LUMIERA_INTERFACE_SLOT (LumieraInterface*, plugin_interfaces, (void)), +); + + /* API to handle interfaces */ From 0dc8a68afba80c740acd075508c00640bdb9029c Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 26 Oct 2008 22:04:58 +0100 Subject: [PATCH 035/249] Reinstantiated the first test plugin --- tests/Makefile.am | 16 ++++-- tests/backend/example_plugin.c | 97 ++++++++++++++++++++++++++++++--- tests/backend/hello_interface.h | 10 ++-- 3 files changed, 106 insertions(+), 17 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 5554c0dc3..66367ffb4 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -48,11 +48,6 @@ test_luid_SOURCES = $(tests_srcdir)/library/test-luid.c test_luid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_luid_LDADD = liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm -check_PROGRAMS += test-interfaces -test_interfaces_SOURCES = $(tests_srcdir)/backend/test-interfaces.c -test_interfaces_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_interfaces_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm - check_PROGRAMS += test-filedescriptors test_filedescriptors_SOURCES = $(tests_srcdir)/backend/test-filedescriptors.c test_filedescriptors_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror @@ -68,4 +63,15 @@ test_config_SOURCES = $(tests_srcdir)/backend/test-config.c test_config_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ test_config_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm +check_LTLIBRARIES += examplepluginc.la +examplepluginc_la_SOURCES = $(tests_srcdir)/backend/example_plugin.c +examplepluginc_la_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +examplepluginc_la_LDFLAGS = -module -avoid-version -no-undefined -rpath /dev/null + +check_PROGRAMS += test-interfaces +test_interfaces_SOURCES = $(tests_srcdir)/backend/test-interfaces.c +test_interfaces_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror +test_interfaces_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm +test_interfaces_DEPENDENCIES = examplepluginc.la + TESTS = $(tests_srcdir)/test.sh diff --git a/tests/backend/example_plugin.c b/tests/backend/example_plugin.c index 7540aa35d..346585190 100644 --- a/tests/backend/example_plugin.c +++ b/tests/backend/example_plugin.c @@ -1,6 +1,7 @@ #include #include "hello_interface.h" +#include "backend/interfacedescriptor.h" int myopen(void) { @@ -34,12 +35,94 @@ void bye(const char* m) printf("Bye %s\n", m); } -LUMIERA_INTERFACE_IMPLEMENT(hello, 1, german, myopen, myclose, - hallo, - tschuess + +LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0, + lumieraorg_exampleplugin_descriptor, + NULL, NULL, NULL, + LUMIERA_INTERFACE_INLINE (name, "\003\307\005\305\201\304\175\377\120\105\332\016\136\354\251\022", + const char*, (LumieraInterface iface), + {return "LumieraTest";} + ), + LUMIERA_INTERFACE_INLINE (brief, "\303\047\265\010\242\210\365\340\024\030\350\310\067\171\170\260", + const char*, (LumieraInterface iface), + {return "Lumiera Test suite examples";} + ), + LUMIERA_INTERFACE_INLINE (homepage, "\363\125\352\312\056\255\274\322\351\245\051\350\120\024\115\263", + const char*, (LumieraInterface iface), + {return "http://www.lumiera.org/develompent.html";} + ), + LUMIERA_INTERFACE_INLINE (version, "\114\043\133\175\354\011\232\002\117\240\107\141\234\157\217\176", + const char*, (LumieraInterface iface), + {return "No Version";} + ), + LUMIERA_INTERFACE_INLINE (author, "\313\300\055\156\126\320\144\247\140\023\261\002\270\367\017\267", + const char*, (LumieraInterface iface), + {return "Christian Thaeter";} + ), + LUMIERA_INTERFACE_INLINE (email, "\163\051\312\276\137\317\267\305\237\274\133\012\276\006\255\160", + const char*, (LumieraInterface iface), + {return "ct@pipapo.org";} + ), + LUMIERA_INTERFACE_INLINE (copyright, "\160\246\161\204\123\262\375\351\157\276\333\073\355\036\062\341", + const char*, (LumieraInterface iface), + { + return + "Copyright (C) Lumiera.org\n" + " 2008 Christian Thaeter "; + } + ), + LUMIERA_INTERFACE_INLINE (license, "\007\311\044\214\064\223\201\326\331\111\233\356\055\264\211\201", + const char*, (LumieraInterface iface), + { + 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, "\331\353\126\162\067\376\340\242\232\175\167\105\122\177\306\354", + int, (LumieraInterface iface), + {return LUMIERA_INTERFACE_EXPERIMENTAL;} + ), + + LUMIERA_INTERFACE_INLINE (versioncmp, "\363\145\363\224\325\104\177\057\344\023\367\111\376\221\152\135", + int, (const char* a, const char* b), + {return 0;} + ) ); -LUMIERA_INTERFACE_IMPLEMENT(hello, 1, english, myopen, myclose, - hello, - bye - ); + +LUMIERA_PLUGIN (NULL, NULL, + "\046\150\040\062\077\110\134\143\236\244\346\365\072\377\371\263", + LUMIERA_INTERFACE_DEFINE (lumieraorg_testhello, 0, + lumieraorg_hello_german, + LUMIERA_INTERFACE_REF (lumieraorg_interfacedescriptor, 0, lumieraorg_exampleplugin_descriptor), + NULL, + NULL, + LUMIERA_INTERFACE_MAP (hello, "\167\012\306\023\031\151\006\362\026\003\125\017\170\022\100\333", + hallo), + LUMIERA_INTERFACE_MAP (goodbye, "\324\267\214\166\340\213\155\053\157\125\064\264\167\235\020\223", + tschuess) + ), + LUMIERA_INTERFACE_DEFINE (lumieraorg_testhello, 0, + lumieraorg_hello_english, + LUMIERA_INTERFACE_REF (lumieraorg_interfacedescriptor, 0, lumieraorg_exampleplugin_descriptor), + NULL, + NULL, + LUMIERA_INTERFACE_MAP (hello, "\326\247\370\247\032\103\223\357\262\007\356\042\051\330\073\116", + hello), + LUMIERA_INTERFACE_MAP (goodbye, "\365\141\371\047\101\230\050\106\071\231\022\235\325\112\354\241", + bye) + ) + ) diff --git a/tests/backend/hello_interface.h b/tests/backend/hello_interface.h index d5cf99ea5..097861c01 100644 --- a/tests/backend/hello_interface.h +++ b/tests/backend/hello_interface.h @@ -1,6 +1,6 @@ -#include "lib/plugin.h" +#include "backend/interface.h" -LUMIERA_INTERFACE(hello, 1, - LUMIERA_INTERFACE_PROTO(void, hello, (void)) - LUMIERA_INTERFACE_PROTO(void, goodbye, (const char*)) - ); +LUMIERA_INTERFACE_DECLARE (lumieraorg_testhello, 0, + LUMIERA_INTERFACE_SLOT (void, hello, (void)), + LUMIERA_INTERFACE_SLOT (void, goodbye, (const char*)), +); From 9f8f0c7c20bbf245738bd7fe4e02d7bfe2b184e6 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 28 Oct 2008 01:10:16 +0100 Subject: [PATCH 036/249] temp. fix to make it compile on Etch based system --- src/gui/widgets/timeline/track.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/track.cpp b/src/gui/widgets/timeline/track.cpp index bac443ced..6d619b231 100644 --- a/src/gui/widgets/timeline/track.cpp +++ b/src/gui/widgets/timeline/track.cpp @@ -36,7 +36,8 @@ Track::Track() : buttonBar.append(lockButton); buttonBar.set_toolbar_style(TOOLBAR_ICONS); - buttonBar.set_icon_size(ICON_SIZE_MENU); +// buttonBar.set_icon_size(ICON_SIZE_MENU); /////TODO: commented out because it makes compile fail on Etch based system + headerWidget.pack_start(titleBox, PACK_SHRINK); headerWidget.pack_start(buttonBar, PACK_SHRINK); From 91d10cb44b38811f174f308862a952e0842decd3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 28 Oct 2008 01:54:45 +0100 Subject: [PATCH 037/249] aligned the Xlib checks to match autotools build --- SConstruct | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/SConstruct b/SConstruct index 19063b865..c6b0e0e66 100644 --- a/SConstruct +++ b/SConstruct @@ -215,7 +215,6 @@ def configurePlatform(env): if not conf.CheckLibWithHeader('boost_regex-mt','boost/regex.hpp','C++'): problems.append('We need the boost regular expression lib (incl. binary lib for linking).') -# if not conf.CheckLibWithHeader('gavl', ['gavlconfig.h', 'gavl/gavl.h'], 'C'): if not conf.CheckPkgConfig('gavl', 1.0): problems.append('Did not find Gmerlin Audio Video Lib [http://gmerlin.sourceforge.net/gavl.html].') @@ -232,13 +231,16 @@ def configurePlatform(env): problems.append('Unable to configure Cairo--, exiting.') if not conf.CheckPkgConfig('gdl-1.0', '0.6.1'): - problems.append('Unable to configure the GNOME DevTool Library, exiting.') + problems.append('Unable to configure the GNOME DevTool Library.') if not conf.CheckPkgConfig('librsvg-2.0', '2.18.1'): problems.append('Need rsvg Library for rendering icons.') - if not conf.CheckPkgConfig('xv'): problems.append('Need lib xv') -# if not conf.CheckPkgConfig('xext'): Exit(1) + if not conf.CheckCHeader(['X11/Xutil.h', 'X11/Xlib.h'],'<>'): + problems.append('Xlib.h and Xutil.h required. Please install libx11-dev.') + + if not conf.CheckPkgConfig('xv') : problems.append('Need libXv...') + if not conf.CheckPkgConfig('xext'): problems.append('Need libXext.') # if not conf.CheckPkgConfig('sm'): Exit(1) # # obviously not needed? From a912159d700e8934b088feee9eef1ca88bfd065f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 28 Oct 2008 01:55:45 +0100 Subject: [PATCH 038/249] re-enabled building of the testpluginc.so --- admin/SConscript | 2 +- tests/SConscript | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/admin/SConscript b/admin/SConscript index d0ad7b84e..2737bab7e 100644 --- a/admin/SConscript +++ b/admin/SConscript @@ -8,7 +8,7 @@ Import('env','envgtk','artifacts','core') vgsuppr = env.Program('#$BINDIR/vgsuppression',['vgsuppression.c']+core) rsvg = envgtk.Program('#$BINDIR/rsvg-convert','rsvg-convert.c') -artifacts['tools'] += [ vgsuppr ## for supressing false valgrind alarms +artifacts['tools'] += [ vgsuppr ## for suppressing false valgrind alarms + rsvg ## for rendering SVG icons (uses librsvg) ] diff --git a/tests/SConscript b/tests/SConscript index f115d152b..d28b70218 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -52,15 +52,12 @@ def treatPluginTestcase(env): prfx = path.join(tree,'example_plugin') oC = env.SharedObject(prfx, prfx+'.c') oCPP = env.SharedObject(prfx+'_cpp', prfx+'.cpp') - testplugin = ( env.SharedLibrary('#$BINDIR/.libs/example_plugin', oC, SHLIBPREFIX='') - + env.SharedLibrary('#$BINDIR/.libs/example_plugin_cpp', oCPP, SHLIBPREFIX='') + testplugin = ( env.SharedLibrary('#$BINDIR/.libs/examplepluginc', oC, SHLIBPREFIX='') + +# doesn't compile yet... +# + env.SharedLibrary('#$BINDIR/.libs/exampleplugincpp', oCPP, SHLIBPREFIX='') ) -# testExe = env.Program('#$BINDIR/test-plugin', ['plugin/plugin_main.c'] + core) -# env.Depends(testExe, testplugin) -# return testExe - - # 10/2008 example_plugin moved to backend directory. - # ...we should try to find some convention here + return testplugin #-- it depends (at the moment) on a specific isolated test-plugin, # which is not integrated in the "normal procedure" for building Plugins @@ -78,7 +75,7 @@ specials = ['plugin','library','backend'] artifacts['testsuite'] = ts = ( [ testExecutable(env, dir) for dir in moduledirs if not dir in specials] -# + treatPluginTestcase(env) + + treatPluginTestcase(env) + testCollection(env, 'library') + testCollection(env, 'backend') ) From a8ff2ec137fa327cb58b4daf4c2139cad25a86f3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 28 Oct 2008 05:01:20 +0100 Subject: [PATCH 039/249] cover the case of noncopyable objects wrapped into ScopedHolders and placed into a dynamically growing vector --- tests/common/scopedholdertest.cpp | 4 +- tests/common/scopedholdertransfertest.cpp | 154 ++++++++++++++++------ tests/common/testdummy.hpp | 4 +- 3 files changed, 118 insertions(+), 44 deletions(-) diff --git a/tests/common/scopedholdertest.cpp b/tests/common/scopedholdertest.cpp index 50ed8f360..2337d60df 100644 --- a/tests/common/scopedholdertest.cpp +++ b/tests/common/scopedholdertest.cpp @@ -120,7 +120,7 @@ namespace lib { { HO holder; - magic = true; + throw_in_ctor = true; try { create_contained_object (holder); @@ -134,7 +134,7 @@ namespace lib { } ASSERT (!holder); /* because the exception happens in ctor object doesn't count as "created" */ - magic = false; + throw_in_ctor = false; } ASSERT (0==checksum); } diff --git a/tests/common/scopedholdertransfertest.cpp b/tests/common/scopedholdertransfertest.cpp index b933ad253..7507cfbdd 100644 --- a/tests/common/scopedholdertransfertest.cpp +++ b/tests/common/scopedholdertransfertest.cpp @@ -39,22 +39,63 @@ namespace lib { using ::Test; using util::isnil; - using std::map; + using std::vector; using std::cout; + namespace { // extending the Dummy for our special purpose.... + + bool throw_in_transfer = false; + + class FixedDummy + : public Dummy + { + public: + FixedDummy() + { + TRACE (test, "CTOR FixedDummy() --> this=%x val=%d", this, getVal()); + } + + ~FixedDummy() + { + TRACE (test, "DTOR ~FixedDummy() this=%x val=%d", this, getVal()); + } + + friend void + transfer_control (FixedDummy& from, FixedDummy& to) + { + TRACE (test, "TRANSFER target=%x <-- source=%x (%d,%d)", &to,&from, to.getVal(),from.getVal()); + + if (throw_in_transfer) + throw to.getVal(); + + to.setVal (from.getVal()); + from.setVal(0); + } + + }; + + + typedef ScopedHolder HolderD; + typedef ScopedPtrHolder PtrHolderD; + + template + struct Table + { + typedef Allocator_TransferNoncopyable Allo; + typedef typename std::vector Type; + + }; + } - typedef ScopedHolder HolderD; - typedef ScopedPtrHolder PtrHolderD; /********************************************************************************** - * @test ScopedHolder and ScopedPtrHolder are initially empty and copyable. - * After taking ownership, they prohibit copy operations, manage the - * lifecycle of the contained object and provide smart-ptr like access. - * A series of identical tests is conducted both with the ScopedPtrHolder - * (the contained objects are heap allocated but managed by the holder) - * and with the ScopedHolder (objects placed inline) + * @test growing a vector containing noncopyable objects wrapped into ScopedHolder + * instances. This requires the use of a custom allocator, invoking a + * \c transfer_control() function to be provided for the concrete + * noncopyable class type, being invoked when the vector + * needs to reallocate. */ class ScopedHolderTransfer_test : public Test { @@ -74,8 +115,8 @@ namespace lib { checkErrorHandling(); } - void create_contained_object (HolderD& holder) { holder.create(); } - void create_contained_object (PtrHolderD& holder) { holder.reset(new Dummy()); } + void create_contained_object (HolderD& holder) { holder.create(); } + void create_contained_object (PtrHolderD& holder) { holder.reset(new FixedDummy()); } template @@ -84,30 +125,23 @@ namespace lib { { ASSERT (0==checksum); { - UNIMPLEMENTED ("create constant sized vector holding noncopyables"); - HO holder; - ASSERT (!holder); + typedef typename Table::Type Vect; + + Vect table(50); ASSERT (0==checksum); - create_contained_object (holder); - ASSERT (holder); - ASSERT (false!=holder); - ASSERT (holder!=false); + for (uint i=0; i<10; ++i) + create_contained_object (table[i]); - ASSERT (0!=checksum); - ASSERT ( &(*holder)); - ASSERT (holder->add(2) == checksum+2); + ASSERT (0 < checksum); + ASSERT ( table[9]); + ASSERT (!table[10]); - Dummy *rawP = holder.get(); + Dummy *rawP = table[5].get(); ASSERT (rawP); - ASSERT (holder); - ASSERT (rawP == &(*holder)); - ASSERT (rawP->add(-5) == holder->add(-5)); - - TRACE (test, "holder at %x", &holder); - TRACE (test, "object at %x", holder.get() ); - TRACE (test, "size(object) = %d", sizeof(*holder)); - TRACE (test, "size(holder) = %d", sizeof(holder)); + ASSERT (table[5]); + ASSERT (rawP == &(*table[5])); + ASSERT (rawP->add(-555) == table[5]->add(-555)); } ASSERT (0==checksum); } @@ -119,7 +153,25 @@ namespace lib { { ASSERT (0==checksum); { - UNIMPLEMENTED ("check growing a vector holding noncopyables"); + typedef typename Table::Type Vect; + + Vect table; + table.reserve(2); + ASSERT (0==checksum); + + cout << "\n..install one element at index[0]\n"; + table.push_back(HO()); + ASSERT (0==checksum); + + create_contained_object (table[0]); // switches into "managed" state + ASSERT (0 < checksum); + int theSum = checksum; + + cout << "\n..*** resize table to 16 elements\n"; + for (uint i=0; i<15; ++i) + table.push_back(HO()); + + ASSERT (theSum==checksum); } ASSERT (0==checksum); } @@ -129,26 +181,48 @@ namespace lib { void checkErrorHandling() { - UNIMPLEMENTED ("throw an error while growing"); ASSERT (0==checksum); { - HO holder; + typedef typename Table::Type Vect; - magic = true; + Vect table(5); + table.reserve(5); + ASSERT (0==checksum); + + create_contained_object (table[2]); + create_contained_object (table[4]); + ASSERT (0 < checksum); + int theSum = checksum; + + cout << "\n.throw some exceptions...\n"; + throw_in_ctor = true; try { - create_contained_object (holder); + create_contained_object (table[3]); NOTREACHED ; } catch (int val) { - ASSERT (0!=checksum); + ASSERT (theSum < checksum); checksum -= val; - ASSERT (0==checksum); + ASSERT (theSum==checksum); } - ASSERT (!holder); /* because the exception happens in ctor - object doesn't count as "created" */ - magic = false; + ASSERT ( table[2]); + ASSERT (!table[3]); // not created because of exception + ASSERT ( table[4]); + + throw_in_ctor = false; + throw_in_transfer=true; // can do this only when using ScopedHolder + try + { + table.resize(10); + } + catch (int val) + { + ASSERT ( table.size() < 10); + } + ASSERT (theSum == checksum); + throw_in_transfer=false; } ASSERT (0==checksum); } diff --git a/tests/common/testdummy.hpp b/tests/common/testdummy.hpp index 31db265b3..7bfffb4bc 100644 --- a/tests/common/testdummy.hpp +++ b/tests/common/testdummy.hpp @@ -31,7 +31,7 @@ namespace lib { namespace { // yet another test dummy long checksum = 0; - bool magic = false; + bool throw_in_ctor = false; class Dummy : boost::noncopyable @@ -43,7 +43,7 @@ namespace lib { : val_(1 + (rand() % 100000000)) { checksum += val_; - if (magic) + if (throw_in_ctor) throw val_; } From a00edd2a84c71e23b3098de7486ffb9a0d385f81 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 28 Oct 2008 06:07:23 +0100 Subject: [PATCH 040/249] cluster datastructure works, finally. WIP still a bug somewhere in the pseudo-memory manager (de-allocation fails) --- src/lib/allocationcluster.cpp | 3 +-- src/lib/allocationcluster.hpp | 31 +++++++++---------------------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp index 118abbe23..868496a22 100644 --- a/src/lib/allocationcluster.cpp +++ b/src/lib/allocationcluster.cpp @@ -148,7 +148,6 @@ namespace lib { * is managed by a separate instance of the low-level memory manager. */ AllocationCluster::AllocationCluster() -// : configParam_ (new Configmap), { TRACE (buildermem, "new AllocationCluster"); } @@ -203,7 +202,7 @@ namespace lib { Thread::Lock guard SIDEEFFECT; /////TODO: decide tradeoff: lock just the instance, or lock the AllocationCluster class? if (slot > typeHandlers_.size()) - typeHandlers_.resize(slot); /////////////////////////////TODO: still a fundamental problem buried here with the way stl::vector grows... + typeHandlers_.resize(slot); if (!handler(slot)) handler(slot).reset (new MemoryManager (type)); diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp index 473ff8cd1..05226ef0a 100644 --- a/src/lib/allocationcluster.hpp +++ b/src/lib/allocationcluster.hpp @@ -55,6 +55,7 @@ #include "common/error.hpp" //#include "common/util.hpp" #include "lib/scopedholder.hpp" +#include "lib/scopedholdertransfer.hpp" @@ -75,11 +76,11 @@ namespace lib { * aren't used after shutting down a given AllocationCluster. */ class AllocationCluster + : boost::noncopyable { public: AllocationCluster (); - AllocationCluster (const AllocationCluster&); ~AllocationCluster () throw(); template @@ -157,7 +158,8 @@ namespace lib { typedef ScopedPtrHolder HMemManager; - typedef std::vector ManagerTable; + typedef Allocator_TransferNoncopyable Allo; + typedef std::vector ManagerTable; ManagerTable typeHandlers_; HMemManager& @@ -208,29 +210,19 @@ namespace lib { static size_t id_; ///< table pos of the memory manager in charge for type TY static size_t & - get() //ManagerTable& handlers) + get() { - //ENSURE (id_ < handlers.size() || 1 <= handlers.size()); // 0th Element used as "undefined" marker - - return id_; //handlers[id_ guard SIDEEFFECT; if (!id_) id_= ++maxTypeIDs; -// if (id_ >= handlers.size()) -// for (size_t idx=handlers.size(); idx()); ////////////////////////////////////////TODO calls ~MemoryManager() but shouldn't -// if (!handlers[id_]) -// { - TY* type_hint(0); - TypeInfo info (type_hint); - return info; -// handlers[id_].reset (setupMemoryManager (info)); ////////////////////////////////////////TODO calls ~MemoryManager() but shouldn't -// } + + return TypeInfo ((TY*) 0 ); } static void @@ -255,9 +247,6 @@ namespace lib { inline void* AllocationCluster::allocation() { -// if (!TypeSlot::get (typeHandlers_)) -// TypeSlot::setup (typeHandlers_); -// return initiateAlloc (TypeSlot::get (typeHandlers_)); void *mem = initiateAlloc (TypeSlot::get()); if (!mem) mem = initiateAlloc (TypeSlot::setup(),TypeSlot::get()); @@ -269,8 +258,6 @@ namespace lib { inline TY& AllocationCluster::commit (TY* obj) { -// PMemManager & typeHandler (TypeSlot::get (typeHandlers_)); -// REQUIRE (typeHandler); REQUIRE (obj); finishAlloc (TypeSlot::get(), obj); return *obj; From b475fd09795ae562cff4d2f547c94b3685644a26 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 30 Oct 2008 04:03:14 +0100 Subject: [PATCH 041/249] AllocationCluster passes test --- src/lib/allocationcluster.cpp | 25 ++++++++++++++++++++----- tests/common/allocationclustertest.cpp | 6 +++--- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp index 868496a22..1f76fed72 100644 --- a/src/lib/allocationcluster.cpp +++ b/src/lib/allocationcluster.cpp @@ -60,7 +60,7 @@ namespace lib { typedef std::vector MemTable; TypeInfo type_; MemTable mem_; - size_t top_; + size_t top_; ///< index of the next slot available for allocation public: MemoryManager(TypeInfo info) : top_(0) { reset(info); } @@ -72,6 +72,9 @@ namespace lib { void* allocate(); void commit (void* pendingAlloc); + + private: + void clearStorage(); }; @@ -101,11 +104,20 @@ namespace lib { REQUIRE (top_ == mem_.size() || (top_+1) == mem_.size()); while (top_) - type_.killIt (&mem_[--top_]); - mem_.clear(); + type_.killIt (mem_[--top_]); + clearStorage(); }// note: unnecessary to kill pending allocations + inline void + AllocationCluster::MemoryManager::clearStorage() + { + for (size_t i=mem_.size(); 0 < i; ) + delete[] mem_[--i]; + mem_.clear(); + } + + inline void* AllocationCluster::MemoryManager::allocate() { @@ -116,9 +128,11 @@ namespace lib { if (top_==mem_.size()) mem_.resize(top_+1); - mem_[top_] = new char[type_.allocSize]; + if (!mem_[top_]) + mem_[top_] = new char[type_.allocSize]; ENSURE (top_ < mem_.size()); + ENSURE (mem_[top_]); return mem_[top_]; } @@ -165,7 +179,8 @@ namespace lib { TRACE (buildermem, "shutting down AllocationCluster"); for (size_t i = typeHandlers_.size(); 0 < i; --i) - handler(i)->purge(); + if (handler(i)) + handler(i)->purge(); typeHandlers_.clear(); diff --git a/tests/common/allocationclustertest.cpp b/tests/common/allocationclustertest.cpp index 001326ce1..4b5d1f458 100644 --- a/tests/common/allocationclustertest.cpp +++ b/tests/common/allocationclustertest.cpp @@ -66,9 +66,9 @@ namespace lib { { char id = i1 + i2 + i3; content[0] = id; + checksum += id; if (0 == (rand() % 20)) throw id; - checksum += id; } ~Dummy() @@ -209,8 +209,8 @@ namespace lib { } catch (char id) { - checksum -= id; - } + checksum -= id; // exception thrown from within constructor, + } // thus dtor won't be called. Repair the checksum! } ASSERT (0==checksum); } From 57ccc289b0c12b95c909400f310a384ae8408cf0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 30 Oct 2008 04:34:05 +0100 Subject: [PATCH 042/249] comment, add to testsuite --- src/lib/allocationcluster.cpp | 26 +++++++++---------- src/lib/allocationcluster.hpp | 31 +++++++++++++---------- tests/50components.tests | 17 +++++++++++++ tests/common/allocationclustertest.cpp | 20 ++++++++++----- tests/common/scopedholdertransfertest.cpp | 6 ++--- 5 files changed, 65 insertions(+), 35 deletions(-) diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp index 1f76fed72..306e4a659 100644 --- a/src/lib/allocationcluster.cpp +++ b/src/lib/allocationcluster.cpp @@ -1,5 +1,5 @@ /* - AllocationCluster - allocating and owning a pile of objects + AllocationCluster - allocating and owning a pile of objects Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -25,9 +25,8 @@ #include "common/error.hpp" #include "common/util.hpp" - using util::isnil; -//using util::cStr; + namespace lib { @@ -47,7 +46,7 @@ namespace lib { * the dtor without actually knowing the object's type. * * @todo this is a preliminary or pseudo-implementation based on - * a vector of smart pointers, i.e. actually the objects are heap + * a vector of raw pointers, i.e. actually the objects are heap * allocated. What actually should happen is for the MemoryManager to * allocate raw memory chunk wise, sub partition it and place the objects * into this private memory buffer. Further, possibly we could maintain @@ -76,7 +75,7 @@ namespace lib { private: void clearStorage(); }; - + void @@ -98,7 +97,7 @@ namespace lib { AllocationCluster::MemoryManager::purge() { Thread::Lock guard SIDEEFFECT; - + REQUIRE (type_.killIt, "we need a deleter function"); REQUIRE (0 < type_.allocSize, "allocation size unknown"); REQUIRE (top_ == mem_.size() || (top_+1) == mem_.size()); @@ -116,7 +115,7 @@ namespace lib { delete[] mem_[--i]; mem_.clear(); } - + inline void* AllocationCluster::MemoryManager::allocate() @@ -125,10 +124,11 @@ namespace lib { REQUIRE (0 < type_.allocSize); REQUIRE (top_ <= mem_.size()); - + if (top_==mem_.size()) mem_.resize(top_+1); - if (!mem_[top_]) + + if (!mem_[top_]) // re-use existing allocation, if any mem_[top_] = new char[type_.allocSize]; ENSURE (top_ < mem_.size()); @@ -141,7 +141,7 @@ namespace lib { AllocationCluster::MemoryManager::commit (void* pendingAlloc) { Thread::Lock guard SIDEEFFECT; - + REQUIRE (pendingAlloc); ASSERT (top_ < mem_.size()); ASSERT (pendingAlloc == mem_[top_], "allocation protocol violated"); @@ -155,8 +155,8 @@ namespace lib { /** storage for static bookkeeping of type allocation slots */ size_t AllocationCluster::maxTypeIDs; - - + + /** creating a new AllocationCluster prepares a table capable * of holding the individual object families to come. Each of those * is managed by a separate instance of the low-level memory manager. @@ -224,7 +224,7 @@ namespace lib { } ASSERT (handler(slot)); - return initiateAlloc(slot); + return initiateAlloc(slot); } diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp index 05226ef0a..a44151957 100644 --- a/src/lib/allocationcluster.hpp +++ b/src/lib/allocationcluster.hpp @@ -1,5 +1,5 @@ /* - ALLOCATIONCLUSTER.hpp - allocating and owning a pile of objects + ALLOCATIONCLUSTER.hpp - allocating and owning a pile of objects Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -53,7 +53,6 @@ #include "common/multithread.hpp" #include "common/error.hpp" -//#include "common/util.hpp" #include "lib/scopedholder.hpp" #include "lib/scopedholdertransfer.hpp" @@ -69,11 +68,14 @@ namespace lib { * Each of those contains a initially undetermined (but rather large) * number of individual objects, which can be expected to be allocated * within a short timespan and which are to be released cleanly on - * destruction of the AllocationCluster. There is a service creating - * individual objects with arbitrary ctor parameters and it is possible - * to control the oder in which the object families are to be discarded. + * destruction of the AllocationCluster. We provide a service creating + * individual objects with arbitrary ctor parameters. * @warning make sure the objects dtors aren't called and object references * aren't used after shutting down a given AllocationCluster. + * @todo implement a facility to control the oder in which + * the object families are to be discarded. Currently + * they are just purged in reverse order defined by + * the first request for allocating a certain type. */ class AllocationCluster : boost::noncopyable @@ -83,6 +85,7 @@ namespace lib { AllocationCluster (); ~AllocationCluster () throw(); + template TY& create () @@ -122,7 +125,7 @@ namespace lib { TY* obj = new(allocation()) TY (p0,p1,p2,p3); return commit(obj); } - + private: /** initiate an allocation for the given type */ @@ -160,7 +163,9 @@ namespace lib { typedef ScopedPtrHolder HMemManager; typedef Allocator_TransferNoncopyable Allo; typedef std::vector ManagerTable; - ManagerTable typeHandlers_; + + ManagerTable typeHandlers_; ///< table of active MemoryManager instances + HMemManager& handler (size_t slot) @@ -174,7 +179,7 @@ namespace lib { void* initiateAlloc (size_t& slot); void* initiateAlloc (TypeInfo type, size_t& slot); - /** enrol the allocation after successful ctor call */ + /** enrol the allocation after successful ctor call */ void finishAlloc (size_t& slot, void*); }; @@ -188,7 +193,7 @@ namespace lib { struct AllocationCluster::TypeInfo { size_t allocSize; - void (*killIt)(void*); + void (*killIt)(void*); ///< deleter function template TypeInfo(TY*) @@ -203,11 +208,11 @@ namespace lib { }; - + template struct AllocationCluster::TypeSlot { - static size_t id_; ///< table pos of the memory manager in charge for type TY + static size_t id_; ///< table pos+1 of the memory manager in charge for type TY static size_t & get() @@ -241,7 +246,7 @@ namespace lib { template size_t AllocationCluster::TypeSlot::id_; - + template inline void* @@ -253,7 +258,7 @@ namespace lib { ENSURE (mem); return mem; } - + template inline TY& AllocationCluster::commit (TY* obj) diff --git a/tests/50components.tests b/tests/50components.tests index 71f4a5d51..4f505c5f6 100644 --- a/tests/50components.tests +++ b/tests/50components.tests @@ -10,6 +10,11 @@ return: 0 END +TEST "AllocationCluster_test" AllocationCluster_test <... +out: . +out: ..install one element at index[0] +out: . +out: ..*** resize table to 16 elements +out: . +out: .throw some exceptions... out: checking ScopedPtrHolder... +out: . +out: ..install one element at index[0] +out: . +out: ..*** resize table to 16 elements +out: . +out: .throw some exceptions... END diff --git a/tests/common/allocationclustertest.cpp b/tests/common/allocationclustertest.cpp index 4b5d1f458..2d634ac37 100644 --- a/tests/common/allocationclustertest.cpp +++ b/tests/common/allocationclustertest.cpp @@ -40,6 +40,8 @@ using ::Test; using std::numeric_limits; using std::vector; + + namespace lib { namespace test { @@ -49,7 +51,8 @@ namespace lib { uint NUM_OBJECTS = 500; uint NUM_FAMILIES = 5; - long checksum = 0; + long checksum = 0; // validate proper pairing of ctor/dtor calls + bool randomFailures = false; template class Dummy @@ -67,7 +70,7 @@ namespace lib { char id = i1 + i2 + i3; content[0] = id; checksum += id; - if (0 == (rand() % 20)) + if (randomFailures && 0 == (rand() % 20)) throw id; } @@ -137,6 +140,7 @@ namespace lib { } + /************************************************************************* * @test verify the proper workings of our custom allocation scheme * managing families of interconnected objects for the segments @@ -182,6 +186,7 @@ namespace lib { // all created objects dtors will be invoked. } + void checkAllocation() { @@ -194,11 +199,14 @@ namespace lib { ASSERT (0==checksum); } + void checkErrorHandling() { ASSERT (0==checksum); { + randomFailures = true; + AllocationCluster clu; for (uint i=0; i Date: Fri, 31 Oct 2008 06:29:55 +0100 Subject: [PATCH 043/249] Adding explicit delimiters to the config wordlist feature This greatly simplifies the task where we want to handle colon separated paths within the config. --- src/backend/config.h | 12 ++++++--- src/backend/config_wordlist.c | 49 ++++++++++++++--------------------- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/src/backend/config.h b/src/backend/config.h index 4e3acd9a9..445ed6e23 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -228,20 +228,22 @@ LUMIERA_CONFIG_TYPES * Get nth word of a wordlist. * @param key key under which this wordlist is stored * @param nth index of the word to get, starting with 0 + * @param delims a string literal listing all characters which are treated as delimiters * @return pointer to a tempbuf holding the nth word or NULL in case of error */ const char* -lumiera_config_wordlist_get_nth (const char* key, unsigned nth); +lumiera_config_wordlist_get_nth (const char* key, unsigned nth, const char* delims); /** * Find the index of a word in a wordlist. * @param key key under which this wordlist is stored * @param value word to find + * @param delims a string literal listing all characters which are treated as delimiters * @return index of the first occurence of the word or -1 in case of failure */ int -lumiera_config_wordlist_find (const char* key, const char* value); +lumiera_config_wordlist_find (const char* key, const char* value, const char* delims); /** @@ -254,20 +256,22 @@ lumiera_config_wordlist_find (const char* key, const char* value); * @param value word to be replaced * @param subst1 first replacement word * @param subst2 second replacement word + * @param delims a string literal listing all characters which are treated as delimiters * @return internal representation of the wordlist in a tmpbuf or NULL in case of an error */ const char* -lumiera_config_wordlist_replace (const char* key, const char* value, const char* subst1, const char* subst2); +lumiera_config_wordlist_replace (const char* key, const char* value, const char* subst1, const char* subst2, const char* delims); /** * Add a word to the end of a wordlist if it doesnt exist already * @param key key under which this wordlist is stored * @param value new word to add + * @param delims a string literal listing all characters which are treated as delimiters * @return internal representation of the wordlist in a tmpbuf or NULL in case of an error */ const char* -lumiera_config_wordlist_add (const char* key, const char* value); +lumiera_config_wordlist_add (const char* key, const char* value, const char* delims); // * {{{ lumiera_config_TYPE_set (const char* key, TYPE*value, const char* fmt) }}} // Highlevel interface for different types, fmt is a printf format specifier for the desired format, when NULL, defaults apply. diff --git a/src/backend/config_wordlist.c b/src/backend/config_wordlist.c index 6cd0389a7..47232f483 100644 --- a/src/backend/config_wordlist.c +++ b/src/backend/config_wordlist.c @@ -19,25 +19,20 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -//TODO: Support library includes// #include "lib/error.h" #include "lib/safeclib.h" -//TODO: Lumiera header includes// #include "backend/config.h" -//TODO: internal/static forward declarations// extern LumieraConfig lumiera_global_config; -//TODO: System includes// - /** * return nth word of a wordlist */ const char* -lumiera_config_wordlist_get_nth (const char* key, unsigned nth) +lumiera_config_wordlist_get_nth (const char* key, unsigned nth, const char* delims) { const char* value; size_t len; @@ -47,8 +42,8 @@ lumiera_config_wordlist_get_nth (const char* key, unsigned nth) for (;;) { - value += strspn (value, " \t,;"); - len = strcspn (value, " \t,;"); + value += strspn (value, delims); + len = strcspn (value, delims); if (!nth && *value) break; @@ -64,7 +59,7 @@ lumiera_config_wordlist_get_nth (const char* key, unsigned nth) int -lumiera_config_wordlist_find (const char* key, const char* value) +lumiera_config_wordlist_find (const char* key, const char* value, const char* delims) { const char* itr; size_t vlen = strlen (value); @@ -75,8 +70,8 @@ lumiera_config_wordlist_find (const char* key, const char* value) for (int idx = 0; *itr; itr += len, ++idx) { - itr += strspn (itr, " \t,;"); - len = strcspn (itr, " \t,;"); + itr += strspn (itr, delims); + len = strcspn (itr, delims); if (len == vlen && !strncmp (itr, value, vlen)) return idx; @@ -87,7 +82,7 @@ lumiera_config_wordlist_find (const char* key, const char* value) const char* -lumiera_config_wordlist_replace (const char* key, const char* value, const char* subst1, const char* subst2) +lumiera_config_wordlist_replace (const char* key, const char* value, const char* subst1, const char* subst2, const char* delims) { const char* wordlist; const char* str = NULL; @@ -106,28 +101,25 @@ lumiera_config_wordlist_replace (const char* key, const char* value, const char* for (const char* itr = start; *itr; itr += len) { const char* left_end = itr; - itr += strspn (itr, " \t,;"); - len = strcspn (itr, " \t,;"); + itr += strspn (itr, delims); + len = strcspn (itr, delims); if (len == vlen && !strncmp (itr, value, vlen)) { - TODO ("figure delimiter from original string out"); - const char* delim = " "; - /* step over the word */ itr += len; - itr += strspn (itr, " \t,;"); + itr += strspn (itr, delims); /* getting the delimiters right for the corner cases looks ugly, want to refactor it? just do it */ str = lumiera_tmpbuf_snprintf (SIZE_MAX, - "%.*s%.*s%s%s%s%s%s%s", + "%.*s%.*s%.1s%s%.1s%s%.1s%s", start - wordlist, wordlist, left_end - start, start, - (left_end - start && subst1 && *subst1) ? delim : "", + (left_end - start && subst1 && *subst1) ? delims : "", (subst1 && *subst1) ? subst1 : "", - ((left_end - start || (subst1 && *subst1)) && subst2 && *subst2) ? delim : "", + ((left_end - start || (subst1 && *subst1)) && subst2 && *subst2) ? delims : "", (subst2 && *subst2) ? subst2 : "", - ((left_end - start || (subst1 && *subst1) || (subst2 && *subst2)) && *itr) ? delim : "", + ((left_end - start || (subst1 && *subst1) || (subst2 && *subst2)) && *itr) ? delims : "", itr ); @@ -145,7 +137,7 @@ lumiera_config_wordlist_replace (const char* key, const char* value, const char* const char* -lumiera_config_wordlist_add (const char* key, const char* value) +lumiera_config_wordlist_add (const char* key, const char* value, const char* delims) { const char* wordlist = NULL; @@ -160,19 +152,16 @@ lumiera_config_wordlist_add (const char* key, const char* value) for (const char* itr = wordlist; *itr; itr += len) { - itr += strspn (itr, " \t,;"); - len = strcspn (itr, " \t,;"); + itr += strspn (itr, delims); + len = strcspn (itr, delims); if (len == vlen && !strncmp (itr, value, vlen)) goto end; } - TODO ("figure delimiter from original string out"); - const char* delim = " "; - - wordlist = lumiera_tmpbuf_snprintf (SIZE_MAX, "%s%s%s", + wordlist = lumiera_tmpbuf_snprintf (SIZE_MAX, "%s%.1s%s", wordlist, - wordlist[strspn (wordlist, " \t,;")]?delim:"", + wordlist[strspn (wordlist, delims)] ? delims : "", value); if (!lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, "=%s", wordlist))) From 48778cf3d7d35bd97fcf0ba89d1cca228948ea04 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 31 Oct 2008 06:42:53 +0100 Subject: [PATCH 044/249] WIP: new plugin.h header This ditches the old 'proof of concept' implementation, interfaces and plugins are internally separate now and publically only accessed over the 'interfaces' api. The interface registry now gets an additional 'plugin' member to backreference plugins from interfaces. --- src/backend/interfaceregistry.c | 13 ++-- src/backend/interfaceregistry.h | 9 ++- src/backend/plugin.h | 134 +++++++++----------------------- 3 files changed, 52 insertions(+), 104 deletions(-) diff --git a/src/backend/interfaceregistry.c b/src/backend/interfaceregistry.c index ffa979340..cc175dd0a 100644 --- a/src/backend/interfaceregistry.c +++ b/src/backend/interfaceregistry.c @@ -53,13 +53,15 @@ key_fn (const PSplaynode node); static LumieraInterfacenode -lumiera_interfacenode_new (LumieraInterface iface) +lumiera_interfacenode_new (LumieraInterface iface, LumieraPlugin plugin) { LumieraInterfacenode self = lumiera_malloc (sizeof (*self)); psplaynode_init (&self->node); self->interface = iface; self->refcnt = 0; + self->plugin = plugin; + FIXME ("plugin handling (refcnt, atime)"); self->lnk = NULL; self->deps_size = 0; self->deps = NULL; @@ -74,6 +76,7 @@ lumiera_interfacenode_delete (LumieraInterfacenode self) if (self) { REQUIRE (self->refcnt == 0); + FIXME ("plugin handling"); lumiera_free (self->deps); lumiera_free (self); } @@ -115,7 +118,7 @@ lumiera_interfaceregistry_destroy (void) void -lumiera_interfaceregistry_register_interface (LumieraInterface self) +lumiera_interfaceregistry_register_interface (LumieraInterface self, LumieraPlugin plugin) { TRACE (interfaceregistry); REQUIRE (self); @@ -123,13 +126,13 @@ lumiera_interfaceregistry_register_interface (LumieraInterface self) LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) { TRACE (interfaceregistry, "interface %s, version %d, instance %s", self->interface, self->version, self->name); - psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (self)->node, 100); + psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (self, plugin)->node, 100); } } void -lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self) +lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self, LumieraPlugin plugin) { TRACE (interfaceregistry); REQUIRE (self); @@ -139,7 +142,7 @@ lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self) while (*self) { TRACE (interfaceregistry, "interface %s, version %d, instance %s", (*self)->interface, (*self)->version, (*self)->name); - psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (*self)->node, 100); + psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (*self, plugin)->node, 100); ++self; } } diff --git a/src/backend/interfaceregistry.h b/src/backend/interfaceregistry.h index 02481072d..54ede293a 100644 --- a/src/backend/interfaceregistry.h +++ b/src/backend/interfaceregistry.h @@ -25,6 +25,7 @@ #include "lib/psplay.h" #include "backend/interface.h" +#include "backend/plugin.h" #include @@ -62,6 +63,10 @@ struct lumiera_interfacenode_struct /** reference counters and link used for internal reference management */ unsigned refcnt; + + /** backreference to its plugin if it comes from a plugin, else NULL */ + LumieraPlugin plugin; + /** temporary used to stack interfaces when recursively opening/closing them */ LumieraInterfacenode lnk; /** allocated size of the following deps table */ @@ -84,10 +89,10 @@ lumiera_interfaceregistry_destroy (void); void -lumiera_interfaceregistry_register_interface (LumieraInterface self); +lumiera_interfaceregistry_register_interface (LumieraInterface self, LumieraPlugin plugin); void -lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self); +lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self, LumieraPlugin plugin); void lumiera_interfaceregistry_remove_interface (LumieraInterface self); diff --git a/src/backend/plugin.h b/src/backend/plugin.h index 7e17afc18..6696e395f 100644 --- a/src/backend/plugin.h +++ b/src/backend/plugin.h @@ -21,111 +21,68 @@ #ifndef LUMIERA_PLUGIN_H #define LUMIERA_PLUGIN_H -#ifdef __cplusplus -extern "C" { -#elif 0 -} /*eek, fixes emacs indenting for now*/ -#endif #include #include -#include "error.h" +#include "lib/error.h" /** * @file - * Plugin loader, header. + * Lumiera plugins defines 'interfaces' as shown in interface.h, the plugin system handles the loading + * of all kinds of plugins under the hood, invoked from the interface system. Anything defined here is + * called internally and should not be used by other parts of the application. */ -NOBUG_DECLARE_FLAG (lumiera_plugin); +LUMIERA_ERROR_DECLARE(PLUGIN_DLOPEN); + + +NOBUG_DECLARE_FLAG (plugin); /* tool macros*/ -#define LUMIERA_INTERFACE_TYPE(name, version) struct lumiera_interface_##name##_##version -#define LUMIERA_INTERFACE_CAST(name, version) (LUMIERA_INTERFACE_TYPE(name, version)*) - -/* Interface definition */ -#define LUMIERA_INTERFACE(name, version, ...) \ -LUMIERA_INTERFACE_TYPE(name, version) \ -{ \ - struct lumiera_interface interface_header_; \ - __VA_ARGS__ \ -} - -#define LUMIERA_INTERFACE_PROTO(ret, name, params) ret (*name) params; - -/* Interface instantiation */ -#define LUMIERA_INTERFACE_IMPLEMENT(iname, version, name, open, close, ...) \ -LUMIERA_INTERFACE_TYPE(iname, version) name##_##version = \ -{ \ - { \ - version, \ - sizeof(LUMIERA_INTERFACE_TYPE(iname, version)), \ - NULL, \ - 0, \ - open, \ - close \ - }, \ - __VA_ARGS__ \ -} +struct lumiera_plugin_struct; +typedef struct lumiera_plugin_struct lumiera_plugin; +typedef lumiera_plugin* LumieraPlugin; -/* internally used */ -struct lumiera_plugin; - -/** - * This is the header for any interface exported by plugins. - * Real interfaces append their functions at the end. There are few standard functions on each Interface - * Every function is required to be implemnted. - */ -struct lumiera_interface -{ - /// interface version number - unsigned version; - /// size of the full structure is used to determine the revision (adding a new function increments the size) - size_t size; - /// back reference to plugin - struct lumiera_plugin* plugin; - /// incremented for each user of this interface and decremented when closed - unsigned use_count; - - /// called for each open of this interface - int (*open)(void); - /// called for each close of this interface - int (*close)(void); -}; /** * Initialize the plugin system. * always succeeds or aborts */ void -lumiera_init_plugin (void); - +lumiera_pluginregistry_init (void); /** - * Make an interface available. - * To use an interface provided by a plugin it must be opened first. It is allowed to open an interface - * more than once. Each open must be paired with a close. - * @param name name of the plugin to use. - * @param interface name of the interface to open. - * @param min_revision the size of the interface structure is used as measure of a minimal required - * revision (new functions are appended at the end) - * @return handle to the interface or NULL in case of a error. The application shall cast this handle to - * the actual interface type. - */ -struct lumiera_interface* -lumiera_interface_open (const char* plugin, const char* name, size_t min_revision); - - -/** - * Close an interface. Does not free associated resources - * Calling this function with self==NULL is legal. Every interface handle must be closed only once. - * @param ptr interface to be closed + * destroy the plugin system, free all resources */ void -lumiera_interface_close (void* self); +lumiera_pluginregistry_destroy (void); + + +LumieraPlugin +lumiera_plugin_load (const char* plugin); + + +int +lumiera_plugin_register (LumieraPlugin); + + +/** + * discover new plugins + * traverses the configured plugin dirs and calls the callback_load function for any plugin + * not actually loaded. If callback_load returns a plugin (and not NULL) then this is feed to + * the callback_register function. + */ +int +lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), + int (*callback_register) (LumieraPlugin)); + + + + /** * Tries to unload a plugin. @@ -136,22 +93,5 @@ lumiera_interface_close (void* self); int lumiera_plugin_unload (const char* plugin); -/** - * Tries to unload plugins which are not in use. - * Calls lumiera_plugin_unload() for each Plugin which is not used for more than age seconds. - * This function might be infrequently called by the scheduler to remove things which are not needed. - * @param age timeout in seconds when to unload plugins - */ -void -lumiera_plugin_expire (time_t age); -LUMIERA_ERROR_DECLARE(PLUGIN_DLOPEN); -LUMIERA_ERROR_DECLARE(PLUGIN_HOOK); -LUMIERA_ERROR_DECLARE(PLUGIN_NFILE); -LUMIERA_ERROR_DECLARE(PLUGIN_NIFACE); -LUMIERA_ERROR_DECLARE(PLUGIN_REVISION); - -#ifdef __cplusplus -} /* extern "C" */ -#endif #endif /* LUMIERA_PLUGIN_H */ From d510ade5c3cb48426da8370fe1407150f493f74e Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 31 Oct 2008 06:43:54 +0100 Subject: [PATCH 045/249] fix wordlist tests to use explicit delimiters --- tests/backend/test-config.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/backend/test-config.c b/tests/backend/test-config.c index 506801454..120fc57d7 100644 --- a/tests/backend/test-config.c +++ b/tests/backend/test-config.c @@ -330,7 +330,7 @@ TEST ("wordlist_get_nth") if (!lumiera_config_wordlist_set (argv[2], &argv[3])) printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ()); - const char* word = lumiera_config_wordlist_get_nth (argv[2], atoi (argv[4])); + const char* word = lumiera_config_wordlist_get_nth (argv[2], atoi (argv[4]), " \t,;"); printf ("'%s'\n", word?word:"NULL"); @@ -349,7 +349,7 @@ TEST ("wordlist_find") if (!lumiera_config_wordlist_set (argv[2], &argv[3])) printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ()); - int n = lumiera_config_wordlist_find (argv[2], argv[4]); + int n = lumiera_config_wordlist_find (argv[2], argv[4], " \t,;"); printf ("'%d'\n", n); @@ -370,7 +370,7 @@ TEST ("wordlist_replace") if (!lumiera_config_wordlist_set (argv[2], &argv[3])) printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ()); - const char* wordlist = lumiera_config_wordlist_replace (argv[2], argv[4], *argv[5]?argv[5]:NULL, *argv[6]?argv[6]:NULL); + const char* wordlist = lumiera_config_wordlist_replace (argv[2], argv[4], *argv[5]?argv[5]:NULL, *argv[6]?argv[6]:NULL, " \t,;"); if (wordlist) printf ("'%s'\n", wordlist); @@ -393,13 +393,13 @@ TEST ("wordlist_add") if (!lumiera_config_wordlist_set (argv[2], &argv[3])) printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ()); - const char* wordlist = lumiera_config_wordlist_add (argv[2], argv[4]); + const char* wordlist = lumiera_config_wordlist_add (argv[2], argv[4], " \t,;"); if (wordlist) printf ("'%s'\n", wordlist); else printf ("%s\n", lumiera_error ()); - wordlist = lumiera_config_wordlist_add (argv[2], argv[5]); + wordlist = lumiera_config_wordlist_add (argv[2], argv[5], " \t,;"); if (wordlist) printf ("'%s'\n", wordlist); else From 10e22c74f7c8cc84e8d13cf762dcab77bce0d898 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 31 Oct 2008 06:44:27 +0100 Subject: [PATCH 046/249] fix test-interfaces for new plugin parameter --- tests/backend/test-interfaces.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/backend/test-interfaces.c b/tests/backend/test-interfaces.c index 8d7c377e8..110c6a855 100644 --- a/tests/backend/test-interfaces.c +++ b/tests/backend/test-interfaces.c @@ -298,7 +298,7 @@ TEST ("basic") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (interfaces_defined_here()); + lumiera_interfaceregistry_bulkregister_interfaces (interfaces_defined_here(), NULL); /* some ugly lowlevel handling tests */ @@ -321,7 +321,7 @@ TEST ("basic") TEST ("open_close") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (interfaces_defined_here()); + lumiera_interfaceregistry_bulkregister_interfaces (interfaces_defined_here(), NULL); LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_one, 0) handle = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_one, 0, 0, lumieraorg_first_test); @@ -338,7 +338,7 @@ TEST ("open_close") TEST ("dependencies_one") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (dependencytests()); + lumiera_interfaceregistry_bulkregister_interfaces (dependencytests(), NULL); LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_one); @@ -356,7 +356,7 @@ TEST ("dependencies_one") TEST ("dependencies_two") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (dependencytests()); + lumiera_interfaceregistry_bulkregister_interfaces (dependencytests(), NULL); LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two); @@ -373,7 +373,7 @@ TEST ("dependencies_two") TEST ("dependencies_three") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (dependencytests()); + lumiera_interfaceregistry_bulkregister_interfaces (dependencytests(), NULL); LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_three); @@ -391,7 +391,7 @@ TEST ("dependencies_three") TEST ("dependencies_four") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (dependencytests()); + lumiera_interfaceregistry_bulkregister_interfaces (dependencytests(), NULL); LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_four); @@ -410,7 +410,7 @@ TEST ("dependencies_four") TEST ("dependencies_all") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (dependencytests()); + lumiera_interfaceregistry_bulkregister_interfaces (dependencytests(), NULL); TRACE (tests, "OPEN one"); LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle_one = From 1da6e70d549086ad1aa08680a9989a99e6ee8510 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 1 Nov 2008 19:54:59 +0100 Subject: [PATCH 047/249] draft for a solution how to relate project, timeline(s) and EDLs --- wiki/renderengine.html | 91 +++++++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 19 deletions(-) diff --git a/wiki/renderengine.html b/wiki/renderengine.html index bb22c2320..26659922d 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -514,6 +514,20 @@ ColorPalette SiteUrl
+
+
Memory management facility for the low-level model (render nodes network). The model is organised into temporal segments, which are considered to be structurally constant and uniform. The objects within each segment are strongly interconnected, and thus each segment is being built in a single build process and is replaced or released as a whole. __~AllocationCluster__ implements memory management to support this usage pattern. He owns a number of object families of various types.[>img[draw/AllocationCluster.png]]
+* [[processing nodes|ProcNode]] &mdash; probably with several subclasses (?)
+* [[wiring descriptors|WiringDescriptor]]
+* the input/output descriptor arrays used by the latter
+
+To Each of those families we can expect an initially undetermined (but rather large) number of individual objects, which can be expected to be allocated within a short timespan and which are to be released cleanly on destruction of the AllocationCluster.
+
+''Problem of calling the dtors''
+Even if the low-level memory manager(s) may use raw storage, we require that the allocated object's destructors be called. This means keeping track at least of the number of objects allocated (without wasting too much memory for bookkeeping). Besides, as the objects are expected to be interconnected, it may be dangerous to destroy a given family of objects while another family of objects may rely on the former in its destructor. //If we happen do get into this situation,// we need to define a priority order on the types and assure the destruction sequence is respected.
+
+&rarr; see MemoryManagement
+
+
Asset management is a subsystem on its own. Assets are "things" that can be loaded into a session, like Media, Clips, Effects, Transitions. It is the "bookkeeping view", while the EDL is the "manipulation and process view". Some Assets can be //loaded// and a collection of Assets is saved with each Session. Besides, there is a collection of basic Assets always available by default.
 
@@ -1107,8 +1121,16 @@ The main tool used to implement this separation is the [[Builder Pattern|http://
 Another pertinent theme is to make the basic building blocks simpler, while on the other hand gaining much more flexibility for combining these building blocks. For example we try to unfold any "internal-multi" effects into separate instances (e.g. the possibility of having an arbitrary number of single masks at any point of the pipeline instead of having one special masking facility encompassing multiple sub-masks. Similarly, we treat the Objects in the EDL in a more uniform manner and gain the possibility to [[place|Placement]] them in various ways.
 
-
-
''EDL'' is a short-hand for __E__dit __D__ecision __L__ist. The use of this term can be confusing; for the usual meaning see the definition in [[Wikipedia|http://en.wikipedia.org/wiki/Edit_decision_list]]
+
+
<<<
+{{red{WARNING: Naming is currently being discussed (11/08)}}}
+* [[EDL]] probably will be called ''Sequence'' (or maybe ''Arrangement'')
+* [[Session]] maybe renamed to ''Project''
+* there seems to be a new entity called [[Timeline]] which holds the global Pipes
+<<<
+
+
+''EDL'' is a short-hand for __E__dit __D__ecision __L__ist. The use of this term can be confusing; for the usual meaning see the definition in [[Wikipedia|http://en.wikipedia.org/wiki/Edit_decision_list]]
 
 Cinelerra uses this term in a related manner but with a somewhat shifted focus (and we just stick to this usage here): In Lumiera the EDL is comprised of the whole set of clips and other media objects parametrized and placed onto the tracks by the user. It is the result of the user's //editing efforts.//
 
@@ -1379,7 +1401,7 @@ Besides routing to a global pipe, wiring plugs can also connect to the source po
 Finally, this example shows an ''automation'' data set controlling some parameter of an effect contained in one of the global pipes. From the effect's POV, the automation is simply a ParamProvider, i.e a function yielding a scalar value over time. The automation data set may be implemented as a bézier curve, or by a mathematical function (e.g. sine or fractal pseudo random) or by some captured and interpolated data values. Interestingly, in this example the automation data set has been placed relatively to the meta clip (albeit on another track), thus it will follow and adjust when the latter is moved.
 
-
+
This wiki page is the entry point to detail notes covering some technical decisions, details and problems encountered in the course of the implementation of the Lumiera Renderengine, the Builder and the related parts.
 
 * [[Packages, Interfaces and Namespaces|InterfaceNamespaces]]
@@ -1398,6 +1420,7 @@ Finally, this example shows an ''automation'' data set controlling some paramete
 * [[how to handle »attached placement«|AttachedPlacementProblem]]
 * working out the [[basic building situations|BuilderPrimitives]] and [[mechanics of rendering|RenderMechanics]]
 * how to classify and [[describe media stream types|StreamType]] and how to [[use them|StreamTypeUse]]
+* the relation of [[Project, Timelines and Sequences|TimelineSequences]]
 
@@ -1782,7 +1805,7 @@ From experiences with other middle scale projects, I prefer having the test code * {{red{and what else?}}}
-
+
The ~MObjects Subsystem contains everything related to the [[EDL]] and the various Media Objects placed within. It is complemented by the Asset Management (see &rarr; [[Asset]]). Examples for [[MObjects|MObject]] being:
 * audio/video clips
 * effects and plugins
@@ -1826,10 +1849,10 @@ This Design strives to achieve a StrongSeparation between the low-level Structur
 {{red{let's see if this approach works...}}}
 
-
-
Contrary to the &rarr;[[Assets and MObjects|ManagementAssetRelation]], the usage pattern for [[render nodes|ProcNode]] is quite simple: All nodes are created together every time a new segment of the network is being build and are all needed together until this segment is re-built, at which point they can be thrown away altogether. While it would be easy to handle the nodes automatically by smart-ptr (the creation is accessible only by use of the {{{NodeFactory}}} anyways), it //seems advisable to care for a bulk allocation/deallocation here.// The reason being not so much the amount of memory (which is expected to be moderate), but the fact, that the build process can be triggered repeatedly several times a second when tweaking the EDL, which could lead to fragmentation and memory pressure.
+
+
Contrary to the &rarr;[[Assets and MObjects|ManagementAssetRelation]], the usage pattern for [[render nodes|ProcNode]] is quite simple: All nodes are created together every time a new segment of the network is being build and are all needed together until this segment is re-built, at which point they can be thrown away altogether. While it would be easy to handle the nodes automatically by smart-ptr (the creation is accessible only by use of the {{{NodeFactory}}} anyways), it //seems advisable to care for a bulk allocation/deallocation here.// The reason being not so much the amount of memory (which is expected to be moderate), but the fact the build process can be triggered repeatedly several times a second when tweaking the EDL, which could lead to fragmentation and memory pressure.
 
-__5/2008__: the allocation mechanism can surely be improved later, but for now I am going for a simple implementation based on keeping all nodes of one kind together in a vector. The list of possible node kinds is hard wired, allowing to generate the object holding a chunk of nodes for one segment, mostly relying on the runtime system for the management.
+__10/2008__: the allocation mechanism can surely be improved later, but for now I am going for a simple implementation based on heap allocated objects owned by a vector or smart-ptrs. For each segment of the render nodes network, we have several families of objects, each of with will be maintained by a separate low-level memory manager (as said, for now implemented as vector of smart-ptrs). Together, they form an AllocationCluster; all objects contained in such a cluster will be destroyed together.
 
@@ -2787,13 +2810,14 @@ Besides, they provide an important __inward interface__ for the [[ProcNode]]s, w
-
+
The Render Engine is the part of the application doing the actual video calculations. Its operations are guided by the Objects and Parameters edited by the user in [[the EDL|EDL]] and it retrieves the raw audio and video data from the [[Data backend|backend.html]]. Because the inner workings of the Render Engine are closely related to the structures used in the EDL, this design covers [[the aspect of objects placed into the EDL|MObjects]] as well.
 <<<
 ''Status'': started out as design draft in summer '07, Ichthyo is now in the middle of a implementing the foundations and main structures in C++
 * basic [[AssetManager]] working
 * [[Builder]] implementation is on the way (&rarr;[[more|BuilderPrimitives]])
 * made a first draft of how to wire and operate procesing nodes (&rarr;[[more|RenderMechanics]])
+* working out the relation of [[Project, Timelines and Sequences|TimelineSequences]]
 <<<
 
 !Summary
@@ -3239,12 +3263,22 @@ The Session object is a singleton &mdash; actually it is a »~PImpl«-Facade
 * a collection of ''global Pipes''
 * the ''Fixture'' with a possibility to [[(re)build it|PlanningBuildFixture]]
-
-
The [[Session]] (sometimes also called //Project// ) contains all informations and objects to be edited by the User. It can be saved and loaded. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one (or several) collections within the Session, which we call [[EDL (Edit Decision List)|EDL]]. Moreover, the sesion contains references to all the Media files used, and it contains various default or user defined configuration, all being represented as [[Asset]]. At any given time, there is //only one current session// opened within the application.
-The Session is close to what is visible in the GUI. From a user's perspective, you'll find a timeline-like structure, where various Media Objects are arranged and placed. The available building blocks and the rules how they can be combined together form Lumiera's [[high-level data model|HighLevelModel]]. Basically, besides the [[media objects|MObjects]] there are data connections and all processing is organized around processing chains or [[pipes|Pipe]], which can be either global (in the Session) or local (in real or virtual clips)
+
+
<<<
+{{red{WARNING: Naming is currently being discussed (11/08)}}}
+* [[EDL]] probably will be called ''Sequence'' (or maybe ''Arrangement'')
+* [[Session]] maybe renamed to ''Project''
+* there seems to be a new entity called [[Timeline]] which holds the global Pipes
+<<<
+The [[Session]] (sometimes also called //Project// ) contains all informations and objects to be edited by the User. It can be saved and loaded. The individual Objects within the Session, i.e. Clips, Media, Effects, are contained in one (or several) collections within the Session, which we call [[EDL (Edit Decision List)|EDL]]. Moreover, the sesion contains references to all the Media files used, and it contains various default or user defined configuration, all being represented as [[Asset]]. At any given time, there is //only one current session// opened within the application.
+The Session is close to what is visible in the GUI. From a user's perspective, you'll find a [[Timeline]]-like structure, containing an [[EDL (or Sequence)|EDL]], where various Media Objects are arranged and placed. The available building blocks and the rules how they can be combined together form Lumiera's [[high-level data model|HighLevelModel]]. Basically, besides the [[media objects|MObjects]] there are data connections and all processing is organized around processing chains or [[pipes|Pipe]], which can be either global (in the Session) or local (in real or virtual clips)
 
 !!!larger projects
-For larger editing projects the simple structure of a session containing "the" timeline is not sufficient. Rather, we have several timelines, e.g. one for each scene. Or we could have several layered or nested timelines (compositional work, multimedia productions). To support these cases without making the default case more complicated, Lumiera introduces a //focus// for selecting the //current EDL,// which will receive all editing operations.
+For larger editing projects the simple structure of a session containing "the" timeline is not sufficient. Rather
+* we may have several [[EDLs (=Sequences)|EDL]], e.g. one for each scene. These sequences can be even layered or nested (compositional work).
+* within one project, there may be multiple, //independant Timelines// &mdash; each of which may have an associated Viewer or Monitor
+To support these cases without making the default case more complicated, Lumiera introduces a //focus// for selecting the //current EDL,// which will receive all editing operations. [[Timelines|Timeline]] on the other hand are always top-level objects and can't be combined further. You can render a given timeline to output.
+&rarr; see [[Relation of Project, Timelines and Sequences|TimelineSequences]]
 
 !!!the definitive state
 With all the structural complexities possible within such a session, we need an isolation layer to provide __one__ definitive state where all configuration has been made explicit. Thus the session manages one special object list, the [[Fixture]], which can be seen as all currently active objects placed onto a single timeline.
@@ -3260,6 +3294,8 @@ While all these possibilities may seem daunting, there is a simple default confi
 It will contain a global video and audio out pipe, just one EDL with a single track; this track will have a internal video and audio pipe (bus) configured with one fading device sending to the global output ports. So, by adding some clip with a simple absolute placement to this track and some time position, the clip gets connected and rendered, after [[(re)building|PlanningBuildFixture]] the [[Fixture]] and passing the result to the [[Builder]] &mdash; and using the resulting render nodes network (Render Engine).
 
 &rarr; [[anatomy of the high-level model|HighLevelModel]]
+&rarr; considerations regarding [[Tracks and Pipes within the EDL|TrackPipeEDL]]
+&rarr; see [[Relation of Project, Timelines and Sequences|TimelineSequences]]
 
@@ -4717,20 +4753,37 @@ function addKeyDownHandlers(e)
http://tiddlywiki.com/
-
-
Timeline is the name of a specific facility located in the [[Fixture]] (EDL): It is a ordered list of ExplicitPlacement.s of MObjects. By traversing the Playlist you get at all elements actually to be rendered; the [[Builder]] uses this Timeline-list to construct actual Render Engine configurations to carry out the calculations.
+
+
Timeline is the top level element within the [[Session (Project)|Session]]. It is visible within a //timeline view// in the GUI and represents the definitive arrangement of media objects, to be rendered for output or viewed in a Monitor (viewer window). A timeline is comprised of:
+* a time axis in abolute time (WIP: not clear if this is an entity or just a conceptual definition) 
+* a PlayControler
+* a list of global Pipes representing the possible outputs
+* //exactly one// top-level [[EDL (Sequence)|EDL]], which in turn may contain further nested ~EDLs (Sequences).
+Please note especially that following this design //a timeline doesn't define tracks.// [[Tracks form a Tree|Track]] and are part of the individual ~EDLs (Sequences), together with the media objects placed to these tracks.
 
+Within the Project, there may be ''multiple timelines'', to be viewed and rendered independently. But, being the top-level entities, multiple timelines may not be combined further. You can always just render (or view) one specific timeline. A given sequence may be referred directly or indirectly from multiple timelines though.
+
+''Note'': in early drafts of the design (2007) there was an entity called "Timeline" within the [[Fixture]]. This entity seems superfluous and has been dropped. It never got any relevance in existing code and at most was used in some code comments.
 
-
-
Tracks are just a structure used to organize the Media Objects within the EDL. They form a grid, and besides that, they have no special meaning. They are grouping devices, not first-class entities. A track doesn't "have" a port or pipe or "is" a video track and the like; it can be configured to behave in such manner by using placements.
+
+
Each Project can contain ''multiple timelines'', to be viewed and rendered independently. But, being the top-level entities, multiple timelines may not be combined further. You can always just render (or view) one specific timeline. Of course it is possible to use ~Sub-EDLs (~Sub-Sequences) within the top-level Sequence within a timeline to organize a movie into several scenes or chapters. 
 
-Tracks are assets on their own, but they can be found within a given EDL. So, several ~EDLs can share a single track or each EDL can have its own, separate tracks. 
-* Like most ~MObjects, tracks have a asset view: you can find a track asset in the asset manager.
-* and they have an object view: there is an track MObject which can be [[placed|Placement]], thus defining properties of this track within one EDL
+As stated in the [[definition|Timeline]], a timeline refers to exactly one EDL (Sequence), and the latter defines a tree of [[tracks|Track]] and a bunch of media objects placed to these tracks. A Sequence may optionally also contain nested sequences as [[meta-clips|MetaClip]]. Moreover, obviously several timelines (top-level entities) may refer to the same Sequence without problems.
+This is because the top-level entities (Timelines) are not permitted to be combined further. You may play or render a given timeline, you may even play several timelines simultanously in different monitor windows, and these different timelines may incorporate the same sequence in a different way
+
+
+
+
Tracks are just a structure used to organize the Media Objects within the EDL. Tracks are associated allways to a specific EDL and the Tracks of an EDL form a //tree.// They can be considered to be an organizing grid, and besides that, they have no special meaning. They are grouping devices, not first-class entities. A track doesn't "have" a port or pipe or "is" a video track and the like; it can be configured to behave in such manner by using placements.
+
+The ~Track-IDs are assets on their own, but they can be found within a given EDL. So, several ~EDLs can share a single track or each EDL can have tracks with their own, separate identity. (the latter is the default)
+* Like most ~MObjects, tracks have a asset view: you can find a track asset (a track ID) in the asset manager.
+* and they have an object view: there is an track MObject which can be [[placed|Placement]], thus defining properties of this track within one EDL, e.g. the starting point in time
 Of course, we can place other ~MObjects relative to some track (that's the main reason why we want to have tracks). In this sense, the [[handling of Tracks|TrackHandling]] is somewhat special: the placement of some track can be found directly within the EDL (and not within the general collection of placed objects which form the contents of any EDL). This placement defines properties of the track, which will be inherited if necessary by all ~MObjects placed to this track. For example, if placing (=plugging) a track to some global [[Pipe]], and if placing a clip to this track, without placing the clip directly to another pipe, the associated-to-pipe information of the track will be fetched by the builder when needed to make the output connection of the clip.
 &rarr; [[Handling of Tracks|TrackHandling]]
 &rarr; [[Handling of Pipes|PipeHandling]]
+
+&rarr; [[Anatomy of the high-level model|HighLevelModel]]
 
From 0d1dbac28fdfa00677487dcb8dce1df415ba6a4c Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 2 Nov 2008 23:19:37 +0100 Subject: [PATCH 048/249] UML drawing and further description of Timeline, Sequence, Output --- doc/devel/uml/class128005.html | 2 +- doc/devel/uml/class128133.html | 6 +- doc/devel/uml/class128261.html | 4 +- doc/devel/uml/class128389.html | 2 +- doc/devel/uml/class128517.html | 2 +- doc/devel/uml/class128901.html | 6 +- doc/devel/uml/class129029.html | 6 +- doc/devel/uml/class129669.html | 2 +- doc/devel/uml/class139653.html | 2 +- doc/devel/uml/classdiagrams.html | 2 + doc/devel/uml/classes.html | 16 +- doc/devel/uml/classes_list.html | 16 +- doc/devel/uml/fig128133.png | Bin 67880 -> 64556 bytes doc/devel/uml/fig132485.png | Bin 0 -> 6985 bytes doc/devel/uml/fig132741.png | Bin 0 -> 25229 bytes doc/devel/uml/index.html | 306 +++++++++++++++------------ doc/devel/uml/index_60.html | 4 +- doc/devel/uml/index_65.html | 6 +- doc/devel/uml/index_67.html | 50 ++--- doc/devel/uml/index_69.html | 2 +- doc/devel/uml/index_70.html | 2 +- doc/devel/uml/index_71.html | 1 + doc/devel/uml/index_73.html | 5 +- doc/devel/uml/index_77.html | 2 + doc/devel/uml/index_80.html | 7 +- doc/devel/uml/index_82.html | 1 + doc/devel/uml/index_83.html | 13 +- doc/devel/uml/index_84.html | 17 +- doc/devel/uml/index_86.html | 12 +- doc/devel/uml/packages.html | 6 +- doc/devel/uml/public_operations.html | 4 +- uml/lumiera/128005 | 208 +++++++++++++++++- uml/lumiera/128133.diagram | 33 ++- uml/lumiera/128261 | 146 +++++++++++-- uml/lumiera/129029 | 2 +- uml/lumiera/129285 | 16 +- uml/lumiera/5.session | 25 ++- uml/lumiera/lumiera.prj | 2 +- wiki/renderengine.html | 23 +- 39 files changed, 676 insertions(+), 283 deletions(-) create mode 100644 doc/devel/uml/fig132485.png create mode 100644 doc/devel/uml/fig132741.png diff --git a/doc/devel/uml/class128005.html b/doc/devel/uml/class128005.html index 06db277ae..d033a8de1 100644 --- a/doc/devel/uml/class128005.html +++ b/doc/devel/uml/class128005.html @@ -18,7 +18,7 @@

Declaration :

Implementation class for the Session interface

Artifact : sessionimpl, Component(s) : Session

-
Relation edls (<directional aggregation by value>)

Declaration :

  • Uml : # edls : EDL, multiplicity : 1..*
  • C++ : protected: <EDL> edls
+
Relation edls (<directional aggregation by value>)

Declaration :

  • Uml : # edls : Seq, multiplicity : 1..*
  • C++ : protected: <Seq> edls
Relation theFixture (<unidirectional association>)

Declaration :

  • Uml : # theFixture : Fixture, multiplicity : 1
  • C++ : protected: Fixture * theFixture
Relation pipes (<directional aggregation>)

Declaration :

  • Uml : # pipes : Pipe, multiplicity : *
  • C++ : protected: Pipe* pipes

the global ports (busses) of the session

All public operations : currEDL , getFixture

diff --git a/doc/devel/uml/class128133.html b/doc/devel/uml/class128133.html index caa5c3e37..175eb30d6 100644 --- a/doc/devel/uml/class128133.html +++ b/doc/devel/uml/class128133.html @@ -4,19 +4,19 @@ -Class EDL +Class Seq -
Class EDL
+
Class Seq

-

Declaration :

  • C++ : class EDL

Directly inherited by : Fixture

+

Declaration :

  • C++ : class Seq

Directly inherited by : Fixture

Artifact : edl, Component(s) : Session

Relation clips (<directional aggregation>)

Declaration :

  • Uml : # clips : MObject, multiplicity : *
  • C++ : protected: list<MObject *> clips
diff --git a/doc/devel/uml/class128261.html b/doc/devel/uml/class128261.html index 0d8043e71..f02717863 100644 --- a/doc/devel/uml/class128261.html +++ b/doc/devel/uml/class128261.html @@ -16,9 +16,9 @@ -

Declaration :

  • C++ : class Fixture : public EDL

Artifact : fixture, Component(s) : Session

+

Declaration :

  • C++ : class Fixture : public Seq

Artifact : fixture, Component(s) : Session

-
Relation theTimeline (<directional aggregation by value>)

Declaration :

+
Relation effectiveTimeline (<directional aggregation by value>)

Declaration :

Operation getPlaylistForRender

Declaration :

  • Uml : + getPlaylistForRender() : list<ExplicitPlacement [ProcessingLayer::MObject]>
  • C++ : public: list<ExplicitPlacement [ProcessingLayer::MObject]> getPlaylistForRender ()
Operation getAutomation

Declaration :

  • Uml : + getAutomation() : Auto [ProcessingLayer::MObject]*
  • C++ : public: Auto [ProcessingLayer::MObject]* getAutomation ()
Relation track (<unidirectional association>)

Declaration :

  • Uml : # track : Track
  • C++ : protected: Track* track
diff --git a/doc/devel/uml/class128389.html b/doc/devel/uml/class128389.html index 222aa9902..1adc7425d 100644 --- a/doc/devel/uml/class128389.html +++ b/doc/devel/uml/class128389.html @@ -16,7 +16,7 @@ -

Declaration :

  • C++ : class Track : public Meta

Artifact : track, Diagram : Session structure

+

Declaration :

Artifact : track, Diagram : Session structure

Relation subTracks (<directional aggregation by value>)

Declaration :

  • Uml : + subTracks : Track, multiplicity : *
  • C++ : public: Track subTracks

Child tracks in a tree structure

All public operations : apply , apply , dispatchOp

diff --git a/doc/devel/uml/class128517.html b/doc/devel/uml/class128517.html index 9b18007fc..892d720be 100644 --- a/doc/devel/uml/class128517.html +++ b/doc/devel/uml/class128517.html @@ -16,7 +16,7 @@ -

Declaration :

  • C++ : class MObject : public Buildable
  • Java : public interface MObject

Directly inherited by : AbstractMO

+

Declaration :

  • C++ : class MObject : public Buildable
  • Java : public interface MObject

Directly inherited by : AbstractMO Clip Effect Label Track

Artifact : mobject, Component(s) : Session

Attribut length
diff --git a/doc/devel/uml/class128901.html b/doc/devel/uml/class128901.html index 3258b0d8f..9cc9def6f 100644 --- a/doc/devel/uml/class128901.html +++ b/doc/devel/uml/class128901.html @@ -16,11 +16,9 @@ -

Declaration :

Directly inherited by : CompoundClip SimpleClip

+

Declaration :

Directly inherited by : CompoundClip SimpleClip

Artifact : clip

- -
Attribut start
-

Declaration :

  • Uml : # start : Time
  • C++ : protected: Time start

startpos in source

+
Relation source (<unidirectional association>)

Declaration :

  • Uml : # source : Media, multiplicity : 1
  • C++ : protected: Media* source

the media source this clip referes to

All public operations : apply , apply , dispatchOp

diff --git a/doc/devel/uml/class129029.html b/doc/devel/uml/class129029.html index f9a14681d..b04d54df7 100644 --- a/doc/devel/uml/class129029.html +++ b/doc/devel/uml/class129029.html @@ -16,10 +16,10 @@ -

Declaration :

Artifact : effect

+

Declaration :

Artifact : effect

-
Attribut plugID
-

Declaration :

  • Uml : # plugID : string
  • C++ : protected: string plugID

Identifier of the Plugin to be used

+
Attribut plugin
+

Declaration :

  • Uml : # plugin : string
  • C++ : protected: string plugin

Identifier of the Plugin to be used

All public operations : apply , apply , dispatchOp

diff --git a/doc/devel/uml/class129669.html b/doc/devel/uml/class129669.html index 8653baa45..199b5d53f 100644 --- a/doc/devel/uml/class129669.html +++ b/doc/devel/uml/class129669.html @@ -16,7 +16,7 @@ -

Declaration :

  • C++ : class Label : public Meta

Artifact : label

+

Declaration :

Artifact : label

All public operations : apply , apply , dispatchOp

diff --git a/doc/devel/uml/class139653.html b/doc/devel/uml/class139653.html index 641046544..076a6ee5b 100644 --- a/doc/devel/uml/class139653.html +++ b/doc/devel/uml/class139653.html @@ -19,7 +19,7 @@

Declaration :

  • C++ : class Session

Directly inherited by : SessionImpl

Primary Interface for all editing tasks.
The session contains defaults, all the assets being edited, and a set of EDL with the individual MObjects to be manipulated and rendered.

Artifact : session

-
Operation currEDL

Declaration :

  • Uml : + currEDL() : EDL
  • C++ : public: EDL currEDL ()

The EDL currently in focus. In most cases, Session and EDL are almost the same, just EDL emphasizes the collection aspect. But generally (for larger editing projects) one Session can contain several EDLs, which may even be nested. At any given time, only one of these EDLs has focus and recieves the editing commands.

+
Operation currEDL

Declaration :

  • Uml : + currEDL() : Seq
  • C++ : public: Seq currEDL ()

The EDL currently in focus. In most cases, Session and EDL are almost the same, just EDL emphasizes the collection aspect. But generally (for larger editing projects) one Session can contain several EDLs, which may even be nested. At any given time, only one of these EDLs has focus and recieves the editing commands.

Operation getFixture

Declaration :

  • Uml : + getFixture() : Fixture&
  • C++ : public: Fixture& getFixture ()

While the session can be comprised of several EDLs,
there is only one Fixture, which represents the actual
configuration of all Objects to be rendered

Relation current (<unidirectional association>)

Declaration :

Standard access path to get at the current session via the Session Manager, which acts as a "PImpl" smart pointer

Relation defaults (<unidirectional association>)

Declaration :

diff --git a/doc/devel/uml/classdiagrams.html b/doc/devel/uml/classdiagrams.html index e1289d57d..f66c12462 100644 --- a/doc/devel/uml/classdiagrams.html +++ b/doc/devel/uml/classdiagrams.html @@ -31,7 +31,9 @@ Rules access Session structure StateAdapter composition +Stream Type Framework Struct-Asset Relations +TimelineSequences diff --git a/doc/devel/uml/classes.html b/doc/devel/uml/classes.html index 319577971..63214df7b 100644 --- a/doc/devel/uml/classes.html +++ b/doc/devel/uml/classes.html @@ -52,7 +52,6 @@ DefaultsRegistry DoAttach DoRecurse -EDL EffectEffect or media processing component Effect Error @@ -75,6 +74,7 @@ FrameDescriptorinterfaceA FrameDescriptor implements the higher level interfaces for frames. Further refinements are made by subclassing and policy classes FrameReference GLBuf +ImplFacade InterpolatorProvides the implementation for getting the acutal value of a time varying or automated effect/plugin parameter Invalid Invocation @@ -88,9 +88,11 @@ Mediakey abstraction: media-like assets MediaAccessFacadeboundaryprovides functions for querying (opening) a media file, detecting the channels or streams found within this file, etc. Delegating to the actual backend functions MediaFactoryspecialized Asset Factory for configuring (new) media asset instances based on existing media files on disk; can create placeholder assets as well +MediaKindenum Metakey abstraction: metadata and organisational asset Meta MObjectinterface +Monitor MutexI provided a reworked Mutex class in my Cinelerra2 repository NodeCreatorToolThis Tool implementation plays the central role in the buld process: given a MObject from Session, it is able to attach ProcNodes to the render engine under construction such as to reflect the properties of the MObject in the actual render. NodeWiring @@ -100,6 +102,8 @@ PathManagerWhile building a render engine, this Strategy class decides on the actual render strategy in accordance to the current controller settings (system state) Pipestructural asset representing a basic building block within the high level model: a port for building a processing chain and generating media output Placementinterfaceused to specify the position of a MObject in the EDL. This can be done in various ways (absolute, relative).
Placement at the same time acts as (refcounting) smart pointer for accessing the MObject. +PlayControl +PlayheadCursor Plug PluginAdapterAdapter used to integrage an effects processor in the render pipeline Prefetch @@ -110,7 +114,9 @@ Processor ProcNodeinterfaceKey abstraction of the Render Engine: A Data processing Node ProcPattspecial type of structural Asset representing information how to build some part of the render engine's processing nodes network. +Project ProjectorSpecial video processing node used to scale and translate image data. +Prototype PullInput QueryCache QueryHandlerinterface @@ -120,10 +126,13 @@ RelTypeenumthe possible kinds of RelativePlacements RenderEngine RenderStateEncapsulates the logic used to get a "current render process" in accordance to the currentyl applicable controller settings. The provided StateProxy serves to hold any mutalbe state used in the render process, so the rest of the render engine can be stateless. +RenderTask ResolverBase Scheduler Segment SegmentationToolTool implementation for deriving a partitioning of the current timeline such, that each segement has a constant configuration. "Constant" means here, that any remaining changes over time can be represented by automation solely, without the need to change the node connections. +Seq +Sequence Serializeractor SessionPrimary Interface for all editing tasks.
The session contains defaults, all the assets being edited, and a set of EDL with the individual MObjects to be manipulated and rendered. SessionImplImplementation class for the Session interface @@ -137,9 +146,14 @@ StateProxyimplementation std::exceptionauxiliary Strategy +StreamType +StreamTypeID Structkey abstraction: structural asset +STypeManager ThreadWe can basically reuse the Thread class design from Cinelerra2, Thread becomes a baseclass for all Threads Timedenotes a temporal position (time point), based on timeline start.

investigate posix.4 realtime timers, wrap these here +Timeline +TimelineView Tool ToolFactory Trackstructural asset holding the configuration of a track in the EDL diff --git a/doc/devel/uml/classes_list.html b/doc/devel/uml/classes_list.html index 8e8c2d9a6..96378253b 100644 --- a/doc/devel/uml/classes_list.html +++ b/doc/devel/uml/classes_list.html @@ -53,7 +53,6 @@ DefaultsRegistry
DoAttach
DoRecurse
-EDL
Effect
Effect
Error
@@ -76,6 +75,7 @@ FrameDescriptor
FrameReference
GLBuf
+ImplFacade
Interpolator
Invalid
Invocation
@@ -89,9 +89,11 @@ Media
MediaAccessFacade
MediaFactory
+MediaKind
Meta
Meta
MObject
+Monitor
Mutex
NodeCreatorTool
NodeWiring
@@ -101,6 +103,8 @@ PathManager
Pipe
Placement
+PlayControl
+PlayheadCursor
Plug
PluginAdapter
Prefetch
@@ -111,7 +115,9 @@ Processor
ProcNode
ProcPatt
+Project
Projector
+Prototype
PullInput
QueryCache
QueryHandler
@@ -121,10 +127,13 @@ RelType
RenderEngine
RenderState
+RenderTask
ResolverBase
Scheduler
Segment
SegmentationTool
+Seq
+Sequence
Serializer
Session
SessionImpl
@@ -138,9 +147,14 @@ StateProxy
std::exception
Strategy
+StreamType
+StreamTypeID
Struct
+STypeManager
Thread
Time
+Timeline
+TimelineView
Tool
ToolFactory
Track
diff --git a/doc/devel/uml/fig128133.png b/doc/devel/uml/fig128133.png index 089545c768e411dfdcb5932e8689a0fab1b558c7..ca5e20d4ee1ef62dbd8c8a511a5ad013669ea218 100644 GIT binary patch literal 64556 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 G9`J9u_w2U- literal 67880 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 WGx+L3582lt2VfL2~ft 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�jHolL-@ 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

`|uF*P18GfZY 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

H53HiBtXp64XIXjR@M#h z9|#9NJ!#)0{^d(X((%-;3duzIZtqlEYR0De zR0lL&&8{srA$jLQ_>3qGC|I0DV8FNNzSh#(y8Zk2`3o2D8$~50K3-l+U~qBYe9?YC_BH$)*TfdXdb`V%tEk zN9>p$Cs+`d-_*uGeaglA+sveQdvh!pl1I>(wuO=oR-vnNb4r1ubwv*!9@5i$^Cvkj zMe%z%N%!#K&&MRi2M4Y=I|~ApKq6V0|7mTll{DuDr}Q&+S?|Tm#UCz92>lo^>{R{d z&t4VLn~9NM)#t}Fyq1Hb5 zON)PqiJ)bEO2NH${b0~9hT;+$UnMH)qso-WRl-S%SLW<9cFK4g7g7Dq3DT%6FGXOU zZ^zZ2boQV;WXtPZKJvRvK-$-JY3z>pkt1d6`Rfx?=B>$6JGZ|Sb-sQbTaJw!7#y^D z8x*jyxCzthw?4}&_wMC-Y?VUG=l@2@0gHW>#?K+}?2YHlL`upE-L0DXy84}@r%td) zNJ+U}dU-L4Om@e;Bmpqq-#6Bri}l<39v>eqA`)ad!zk#vI$fWV!m_AgYb#9{ad2og zH|=X_#lby#UK2u@3~so(_8l4k>&TChfPcDk+;%pryr_--#Ea?wj-1B&?^NDnKb)YH zm}H|Iu<?UrGc^ zOIJZAH6b{dupaHE++xNS!Y7+5-TF&oU77aB9CVuEw4a&M7$_6jah9NSF!ZMPoqa(({M4?P5Z~{5i*L3BV$g5LW~je4+d4>=t1vFi!?yj!%g`qnKDvUKal4)SoI`j`(TZjxtiwI zg5S|fvdXYcROk%^(LluwHTJ%J=`g=uHL>!ogvB;0{Qdq0^myC|(^5T+(Cz4)-DGK! zr&osjwaZf^wSIgh{zPxD{O{lI{C)MUYvhvy=M&9aWd+SjMwjN#xQ^Bx54y1*VMWE+ zWM}1?&|5$Cn;RXO*k0dz{@ihzG?s%W)%jUWOoS4NnzE@0)8!hG8~FUT_AaupV-f?R z1tZaWW}!}##!h+ZIr*<&kN3O`?(KV7R3v+NQU%i%!{>M^i-q2|r;iw*r-$c&AFSG$;{6morpDpA4UZeCReBvqg}kE)%@g!Yc@%Yc_u6sy!oqm~(#bnx?^XAz ze5Ixk_|gE%cLd0Xy2Zo_E`Q?+nC>hO^Zm1Jj@`@Py71I=K;R>$oNRfI zK=-n!x|M->e)(7;Bv(iWQ&kB6C}u&f=lLZH?p=Lvqk8MB;)M$rq@_#PRDXvIH^Ft! z(-~I*W~rev$4IF0!@|NoK^30DbTyO?lpfSaN~X9Sc!dA6Rz%@X|62~CuumZp|F^XC ee;)pat?EYZ6{_z`j_@rHh>qsP^Timud;bOBF=lfB literal 0 HcmV?d00001 diff --git a/doc/devel/uml/index.html b/doc/devel/uml/index.html index 1081df7d3..c05d6f597 100644 --- a/doc/devel/uml/index.html +++ b/doc/devel/uml/index.html @@ -36,7 +36,7 @@ Documentation

required classes : Fixture, SessionImpl

Component Session
-

provided classes : EDL, Fixture, MObject, ParamProvider, SessionImpl

+

provided classes : Seq, Fixture, MObject, ParamProvider, SessionImpl

Component EDL
@@ -83,8 +83,21 @@ Documentation
Component client code

required classes : ProcDispatcher

+ +

1.2 Class View Project Entities

+
+ +

+

TimelineSequences



+
Class Project
+
+
Class Monitor
+
+
Class Sequence
+
+
-

1.2 Component View interfaces

+

1.3 Component View interfaces

@@ -104,10 +117,10 @@ Documentation

provided classes : MediaAccessFacade

-

1.3 Package codegen

+

1.4 Package codegen

This package is used to organize code generation by BOUML. It is considered useless after having generated the initial code skeleton.

-

1.3.1 Deployment View EXE Deployment

+

1.4.1 Deployment View EXE Deployment

defines and lists how the Lumiera executable has to be created

@@ -122,14 +135,14 @@ Documentation

Artifact source

-

1.3.2 Package common

+

1.4.2 Package common

  • C++ namespace : lumiera

sourcecode package

Common library and helper classes

Diagram : Source Overview

-

1.3.2.1 Deployment View gen

+

1.4.2.1 Deployment View gen

defines source files to be generated by BOUML

@@ -148,26 +161,29 @@ Documentation
Artifact time

unified representation of a time point, including conversion functions

Artifact source associated with : Time

+ +
Artifact streamtype
+

Artifact source associated with : StreamType, Prototype, ImplFacade

-

1.3.2.2 Package error

+

1.4.2.2 Package error

  • C++ namespace : lumiera::error

Namespace for Exception Kinds

-

1.3.2.3 Package visitor

+

1.4.2.3 Package visitor

  • C++ namespace : lumiera::visitor

sub-namespace for visitor library implementation

-

1.3.3 Package backend

+

1.4.3 Package backend

  • C++ namespace : backend_interface

sourcecode package

Data backend classes here...

-

1.3.3.1 Deployment View gen

+

1.4.3.1 Deployment View gen

Artifact mediaaccessfacade
@@ -176,13 +192,13 @@ Documentation
-

1.3.4 Package proc

+

1.4.4 Package proc

  • C++ namespace : proc_interface

sourcecode package

All classes belonging to the (middle) processing layer

-

1.3.4.1 Deployment View gen

+

1.4.4.1 Deployment View gen

defines source files to be generated by BOUML

@@ -207,13 +223,13 @@ Documentation

Artifact source associated with : Frame

-

1.3.4.2 Package asset

+

1.4.4.2 Package asset

  • C++ namespace : asset

sourcecode package

Asset Management

-

1.3.4.2.1 Deployment View gen

+

1.4.4.2.1 Deployment View gen

defines source files to be generated by BOUML

@@ -286,14 +302,37 @@ Documentation

Artifact source associated with : DB

+ +

1.4.4.3 Package control

+

    +
  • C++ namespace : control
  • +
+

sourcecode package

The Processing and Render Controller,
and the Proc-Layer dispatcher

+ +

1.4.4.3.1 Deployment View gen

+

defines source files to be generated by BOUML

+
+ +
Artifact pathmanager
+

Manager for deciding the actual render strategy

+

Artifact source associated with : PathManager

+ +
Artifact renderstate
+

renderengine state manager

+

Artifact source associated with : RenderState

+ +
Artifact stypemanager
+

Artifact source associated with : STypeManager

+
+
-

1.3.4.3 Package mobject

+

1.4.4.4 Package mobject

  • C++ namespace : mobject

sourcecode package

MObject Subsystem
including the Session (EDL), Builder and Processing Controller

-

1.3.4.3.1 Deployment View gen

+

1.4.4.4.1 Deployment View gen

defines source files to be generated by BOUML

@@ -334,13 +373,13 @@ Documentation

Artifact source associated with : Interpolator

-

1.3.4.3.2 Package session

+

1.4.4.4.2 Package session

  • C++ namespace : mobject::session

sourcecode package

Everything concerning the EDL and Session, within the MObject Subsystem

-

1.3.4.3.2.1 Deployment View gen

+

1.4.4.4.2.1 Deployment View gen

defines source files to be generated by BOUML

@@ -354,7 +393,7 @@ Documentation
Artifact edl

the (high level) Edit Decision List within the current Session

-

Artifact source associated with : EDL

+

Artifact source associated with : Seq

Artifact fixture

the (low level) representation of the EDL with concrete placement data

@@ -428,13 +467,13 @@ Documentation
-

1.3.4.3.3 Package builder

+

1.4.4.4.3 Package builder

  • C++ namespace : mobject::builder

sourcecode package

The Builder creating the Render Engine,
located within the MObject Subsystem

-

1.3.4.3.3.1 Deployment View gen

+

1.4.4.4.3.1 Deployment View gen

defines source files to be generated by BOUML

@@ -463,35 +502,15 @@ Documentation

Artifact source associated with : NodeCreatorTool

- -

1.3.4.3.4 Package controller

-

    -
  • C++ namespace : mobject::controller
  • -
-

sourcecode package

The Processing and Render Controller,
located within the MObject Subsystem

- -

1.3.4.3.4.1 Deployment View gen

-

defines source files to be generated by BOUML

-
- -
Artifact pathmanager
-

Manager for deciding the actual render strategy

-

Artifact source associated with : PathManager

- -
Artifact renderstate
-

renderengine state manager

-

Artifact source associated with : RenderState

-
-
-

1.3.4.4 Package engine

+

1.4.4.5 Package engine

  • C++ namespace : engine

sourcecode package

The Core Render Engine

-

1.3.4.4.1 Deployment View gen

+

1.4.4.5.1 Deployment View gen

defines source files to be generated by BOUML

@@ -574,20 +593,20 @@ Documentation
-

1.3.5 Package gui

+

1.4.5 Package gui

  • C++ namespace : gui

sourcecode package

User Interface classes go here

-

1.3.5.1 Deployment View gen

+

1.4.5.1 Deployment View gen

defines source files to be generated by BOUML

-

1.3.6 Package tool

+

1.4.6 Package tool

sourcecode package

Tools and Utilities
(separate from the main cinelrra binary)

-

1.3.6.1 Deployment View gen

+

1.4.6.1 Deployment View gen

defines source files to be generated by BOUML

@@ -637,11 +656,69 @@ Documentation
Class DoRecurse
+ +

2.2 Package Control

+
+ +

2.2.1 Class View Controller Workings

+
+ +

+

Controller Entities



+ +

2.2.1.1 Activity configure Render

+

Pre Condition :

    Post Condition :

      + +

      +

      the render configuration flow



      + +
      Activity action pin Render Request
      +

      Direction : input

      Type :

      Selection :

        +
        Flow <flow>

        From Render Request To determine Render Params

        Weight :

          Guard :

            Selection :

              Transformation :

                + +
                Opaque activity action setup StateProxy
                +

                Defined in configure Render

                Pre Condition :

                  Post Condition :

                    Behavior :

                      +
                      Flow <flow>

                      From setup StateProxy To build necessary?

                      Weight :

                        Guard :

                          Selection :

                            Transformation :

                              + + +
                              Decision activity node build necessary?
                              +

                              Defined in configure Render

                              +
                              Flow <flow>

                              From build necessary? To build Render Engine

                              Weight :

                                Guard :

                                • OCL :
                                  +build necessary

                                Selection :

                                  Transformation :

                                    Flow <flow>

                                    From build necessary? To merge activity node

                                    Weight :

                                      Guard :

                                      • OCL :
                                        +reuse exiting Engine

                                      Selection :

                                        Transformation :

                                          + +
                                          Opaque activity action setup Build Params
                                          +

                                          Defined in configure Render

                                          Pre Condition :

                                            Post Condition :

                                              Behavior :

                                                + +
                                                Merge activity node
                                                +

                                                Defined in configure Render

                                                +
                                                Flow <flow>

                                                From merge activity node To activity final

                                                Weight :

                                                  Guard :

                                                    Selection :

                                                      Transformation :

                                                        + +

                                                        2.2.1.1.1 Expansion region determine Render Params

                                                        + +
                                                        Opaque activity action determine Render Params
                                                        +

                                                        Diagram : the render configuration flow

                                                        +

                                                        Defined in configure Render

                                                        Pre Condition :

                                                          Post Condition :

                                                            Behavior :

                                                              +
                                                              Flow <flow>

                                                              From determine Render Params To setup StateProxy

                                                              Weight :

                                                                Guard :

                                                                  Selection :

                                                                    Transformation :

                                                                      + +
                                                                      Opaque activity action build Render Engine
                                                                      +

                                                                      Defined in configure Render

                                                                      Pre Condition :

                                                                        Post Condition :

                                                                          Behavior :

                                                                            +
                                                                            Flow <flow>

                                                                            From build Render Engine To merge activity node

                                                                            Weight :

                                                                              Guard :

                                                                                Selection :

                                                                                  Transformation :

                                                                                    + + +
                                                                                    Activity final
                                                                                    +

                                                                                    Defined in configure Render

                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    -

                                                                                    2.2 Package MObject

                                                                                    +

                                                                                    2.3 Package MObject

                                                                                    -

                                                                                    2.2.1 Class View Session

                                                                                    +

                                                                                    2.3.1 Class View Session

                                                                                    @@ -649,7 +726,9 @@ Documentation
                                                                                    Class Session
                                                                                    -
                                                                                    Class EDL
                                                                                    +
                                                                                    Class Timeline
                                                                                    +
                                                                                    +
                                                                                    Class Seq
                                                                                    Class Fixture
                                                                                    Class Segment
                                                                                    Class Track
                                                                                    @@ -677,16 +756,16 @@ Documentation
                                                                                    -

                                                                                    2.2.2 Package Builder

                                                                                    +

                                                                                    2.3.2 Package Builder

                                                                                    -

                                                                                    2.2.2.1 Class View Builder Workings

                                                                                    +

                                                                                    2.3.2.1 Class View Builder Workings

                                                                                    build process



                                                                                    This figure shows the process of building and starting a RenderEngine

                                                                                    -

                                                                                    2.2.2.1.1 Activity building the Engine

                                                                                    +

                                                                                    2.3.2.1.1 Activity building the Engine

                                                                                    Pre Condition :

                                                                                      Post Condition :

                                                                                        @@ -700,7 +779,7 @@ Documentation

                                                                                        Defined in building the Engine

                                                                                        Pre Condition :

                                                                                          Post Condition :

                                                                                            Behavior :

                                                                                              Flow <flow>

                                                                                              From configure Tools To fork activity node

                                                                                              Weight :

                                                                                                Guard :

                                                                                                  Selection :

                                                                                                    Transformation :

                                                                                                      -

                                                                                                      2.2.2.1.1.1 Expansion region establish partitioning

                                                                                                      +

                                                                                                      2.3.2.1.1.1 Expansion region establish partitioning

                                                                                                      Opaque activity action define segment
                                                                                                      @@ -727,7 +806,7 @@ Documentation

                                                                                                      Defined in building the Engine

                                                                                                      Flow <flow>

                                                                                                      From fork activity node To segment Tool

                                                                                                      Weight :

                                                                                                        Guard :

                                                                                                          Selection :

                                                                                                            Transformation :

                                                                                                              Flow <flow>

                                                                                                              From fork activity node To build Tool

                                                                                                              Weight :

                                                                                                                Guard :

                                                                                                                  Selection :

                                                                                                                    Transformation :

                                                                                                                      -

                                                                                                                      2.2.2.1.1.2 Expansion region build Processors

                                                                                                                      +

                                                                                                                      2.3.2.1.1.2 Expansion region build Processors

                                                                                                                      Activity object build Tool
                                                                                                                      @@ -771,65 +850,8 @@ Documentation
                                                                                                                      - -

                                                                                                                      2.2.3 Package Controller

                                                                                                                      -
                                                                                                                      - -

                                                                                                                      2.2.3.1 Class View Controller Workings

                                                                                                                      -
                                                                                                                      - -

                                                                                                                      -

                                                                                                                      Controller Entities



                                                                                                                      - -

                                                                                                                      2.2.3.1.1 Activity configure Render

                                                                                                                      -

                                                                                                                      Pre Condition :

                                                                                                                        Post Condition :

                                                                                                                          - -

                                                                                                                          -

                                                                                                                          the render configuration flow



                                                                                                                          - -
                                                                                                                          Activity action pin Render Request
                                                                                                                          -

                                                                                                                          Direction : input

                                                                                                                          Type :

                                                                                                                          Selection :

                                                                                                                            -
                                                                                                                            Flow <flow>

                                                                                                                            From Render Request To determine Render Params

                                                                                                                            Weight :

                                                                                                                              Guard :

                                                                                                                                Selection :

                                                                                                                                  Transformation :

                                                                                                                                    - -
                                                                                                                                    Opaque activity action setup StateProxy
                                                                                                                                    -

                                                                                                                                    Defined in configure Render

                                                                                                                                    Pre Condition :

                                                                                                                                      Post Condition :

                                                                                                                                        Behavior :

                                                                                                                                          -
                                                                                                                                          Flow <flow>

                                                                                                                                          From setup StateProxy To build necessary?

                                                                                                                                          Weight :

                                                                                                                                            Guard :

                                                                                                                                              Selection :

                                                                                                                                                Transformation :

                                                                                                                                                  - - -
                                                                                                                                                  Decision activity node build necessary?
                                                                                                                                                  -

                                                                                                                                                  Defined in configure Render

                                                                                                                                                  -
                                                                                                                                                  Flow <flow>

                                                                                                                                                  From build necessary? To build Render Engine

                                                                                                                                                  Weight :

                                                                                                                                                    Guard :

                                                                                                                                                    • OCL :
                                                                                                                                                      -build necessary

                                                                                                                                                    Selection :

                                                                                                                                                      Transformation :

                                                                                                                                                        Flow <flow>

                                                                                                                                                        From build necessary? To merge activity node

                                                                                                                                                        Weight :

                                                                                                                                                          Guard :

                                                                                                                                                          • OCL :
                                                                                                                                                            -reuse exiting Engine

                                                                                                                                                          Selection :

                                                                                                                                                            Transformation :

                                                                                                                                                              - -
                                                                                                                                                              Opaque activity action setup Build Params
                                                                                                                                                              -

                                                                                                                                                              Defined in configure Render

                                                                                                                                                              Pre Condition :

                                                                                                                                                                Post Condition :

                                                                                                                                                                  Behavior :

                                                                                                                                                                    - -
                                                                                                                                                                    Merge activity node
                                                                                                                                                                    -

                                                                                                                                                                    Defined in configure Render

                                                                                                                                                                    -
                                                                                                                                                                    Flow <flow>

                                                                                                                                                                    From merge activity node To activity final

                                                                                                                                                                    Weight :

                                                                                                                                                                      Guard :

                                                                                                                                                                        Selection :

                                                                                                                                                                          Transformation :

                                                                                                                                                                            - -

                                                                                                                                                                            2.2.3.1.1.1 Expansion region determine Render Params

                                                                                                                                                                            - -
                                                                                                                                                                            Opaque activity action determine Render Params
                                                                                                                                                                            -

                                                                                                                                                                            Diagram : the render configuration flow

                                                                                                                                                                            -

                                                                                                                                                                            Defined in configure Render

                                                                                                                                                                            Pre Condition :

                                                                                                                                                                              Post Condition :

                                                                                                                                                                                Behavior :

                                                                                                                                                                                  -
                                                                                                                                                                                  Flow <flow>

                                                                                                                                                                                  From determine Render Params To setup StateProxy

                                                                                                                                                                                  Weight :

                                                                                                                                                                                    Guard :

                                                                                                                                                                                      Selection :

                                                                                                                                                                                        Transformation :

                                                                                                                                                                                          - -
                                                                                                                                                                                          Opaque activity action build Render Engine
                                                                                                                                                                                          -

                                                                                                                                                                                          Defined in configure Render

                                                                                                                                                                                          Pre Condition :

                                                                                                                                                                                            Post Condition :

                                                                                                                                                                                              Behavior :

                                                                                                                                                                                                -
                                                                                                                                                                                                Flow <flow>

                                                                                                                                                                                                From build Render Engine To merge activity node

                                                                                                                                                                                                Weight :

                                                                                                                                                                                                  Guard :

                                                                                                                                                                                                    Selection :

                                                                                                                                                                                                      Transformation :

                                                                                                                                                                                                        - - -
                                                                                                                                                                                                        Activity final
                                                                                                                                                                                                        -

                                                                                                                                                                                                        Defined in configure Render

                                                                                                                                                                                                        -
                                                                                                                                                                                                        -
                                                                                                                                                                                                        -
                                                                                                                                                                                                        -
                                                                                                                                                                                                        -
                                                                                                                                                                                                        -

                                                                                                                                                                                                        2.2.4 Use Case View config examples

                                                                                                                                                                                                        +

                                                                                                                                                                                                        2.3.3 Use Case View config examples

                                                                                                                                                                                                        @@ -847,10 +869,10 @@ reuse exiting Engine

                                                                                                                                                                                                        Selection :

                                                                                                                                                                                                          Transformation
                                                                                                                                                                                                          Class instance

                                                                                                                                                                                                          type :Placement

                                                                                                                                                                                                          -

                                                                                                                                                                                                          2.3 Package RenderEngine

                                                                                                                                                                                                          +

                                                                                                                                                                                                          2.4 Package RenderEngine

                                                                                                                                                                                                          -

                                                                                                                                                                                                          2.3.1 Deployment View Engine Parts

                                                                                                                                                                                                          +

                                                                                                                                                                                                          2.4.1 Deployment View Engine Parts

                                                                                                                                                                                                          @@ -869,7 +891,7 @@ reuse exiting Engine

                                                                                                                                                                                                          Selection :

                                                                                                                                                                                                            Transformation
                                                                                                                                                                                                            Node State

                                                                                                                                                                                                            -

                                                                                                                                                                                                            2.3.2 Class View Engine Workings

                                                                                                                                                                                                            +

                                                                                                                                                                                                            2.4.2 Class View Engine Workings

                                                                                                                                                                                                            @@ -915,7 +937,7 @@ reuse exiting Engine

                                                                                                                                                                                                            Selection :

                                                                                                                                                                                                              Transformation

                                                                                                                                                                                                              -

                                                                                                                                                                                                              2.4 Use Case View Renderengine Use

                                                                                                                                                                                                              +

                                                                                                                                                                                                              2.5 Use Case View Renderengine Use

                                                                                                                                                                                                              @@ -943,11 +965,9 @@ reuse exiting Engine

                                                                                                                                                                                                              Selection :

                                                                                                                                                                                                                Transformation
                                                                                                                                                                                                                Class instance video1

                                                                                                                                                                                                                type :Track

                                                                                                                                                                                                                Class instance vid_A

                                                                                                                                                                                                                type :Clip

                                                                                                                                                                                                                attributes :

                                                                                                                                                                                                                Class instance aud_A

                                                                                                                                                                                                                type :Clip

                                                                                                                                                                                                                attributes :

                                                                                                                                                                                                                Class instance audio1

                                                                                                                                                                                                                type :Track

                                                                                                                                                                                                                Class instance

                                                                                                                                                                                                                type :ExplicitPlacement

                                                                                                                                                                                                                attributes :

                                                                                                                                                                                                                  @@ -958,9 +978,8 @@ reuse exiting Engine

                                                                                                                                                                                                                Selection :

                                                                                                                                                                                                                  Transformation
                                                                                                                                                                                                                  Class instance

                                                                                                                                                                                                                  type :Fixture

                                                                                                                                                                                                                  Class instance vid_A

                                                                                                                                                                                                                  type :Clip

                                                                                                                                                                                                                  attributes :

                                                                                                                                                                                                                  -
                                                                                                                                                                                                                  Class instance

                                                                                                                                                                                                                  type :EDL

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                  Class instance

                                                                                                                                                                                                                  type :Seq

                                                                                                                                                                                                                  Class instance refPoint

                                                                                                                                                                                                                  type :Label

                                                                                                                                                                                                                  attributes :

                                                                                                                                                                                                                  @@ -969,7 +988,6 @@ reuse exiting Engine

                                                                                                                                                                                                                  Selection :

                                                                                                                                                                                                                    Transformation

                                                                                                                                                                                                                    Class instance vid_A

                                                                                                                                                                                                                    type :Clip

                                                                                                                                                                                                                    attributes :

                                                                                                                                                                                                                    Class instance

                                                                                                                                                                                                                    type :RelativeLocation

                                                                                                                                                                                                                    attributes :

                                                                                                                                                                                                                    • relType = SAMETIME
                                                                                                                                                                                                                    • @@ -978,7 +996,7 @@ reuse exiting Engine

                                                                                                                                                                                                                    Selection :

                                                                                                                                                                                                                      Transformation

                                                                                                                                                                                                                      Class instance

                                                                                                                                                                                                                      type :Effect

                                                                                                                                                                                                                      attributes :

                                                                                                                                                                                                                      Class instance

                                                                                                                                                                                                                      type :RelativeLocation

                                                                                                                                                                                                                      attributes :

                                                                                                                                                                                                                      • offset = +3
                                                                                                                                                                                                                      • @@ -988,7 +1006,7 @@ reuse exiting Engine

                                                                                                                                                                                                                      Selection :

                                                                                                                                                                                                                        Transformation

                                                                                                                                                                                                                        Class instance

                                                                                                                                                                                                                        type :Effect

                                                                                                                                                                                                                        attributes :

                                                                                                                                                                                                                        Class instance

                                                                                                                                                                                                                        type :ExplicitPlacement

                                                                                                                                                                                                                        attributes :

                                                                                                                                                                                                                        • time = 5
                                                                                                                                                                                                                        • @@ -1162,11 +1180,23 @@ reuse exiting Engine

                                                                                                                                                                                                                        Selection :

                                                                                                                                                                                                                          Transformation

                                                                                                                                                                                                                          GUI is here just a container to hold any entities considered to be User Interface related, which is not in focus for this Design draft

                                                                                                                                                                                                                          5 Package CommonLib

                                                                                                                                                                                                                          + +

                                                                                                                                                                                                                          5.1 Class View StreamType

                                                                                                                                                                                                                          +
                                                                                                                                                                                                                          + +

                                                                                                                                                                                                                          +

                                                                                                                                                                                                                          Stream Type Framework



                                                                                                                                                                                                                          +
                                                                                                                                                                                                                          +
                                                                                                                                                                                                                          Class Prototype
                                                                                                                                                                                                                          +
                                                                                                                                                                                                                          +
                                                                                                                                                                                                                          +
                                                                                                                                                                                                                          Class MediaKind
                                                                                                                                                                                                                          +
                                                                                                                                                                                                                          -

                                                                                                                                                                                                                          5.1 Package ConfigQuery

                                                                                                                                                                                                                          +

                                                                                                                                                                                                                          5.2 Package ConfigQuery

                                                                                                                                                                                                                          -

                                                                                                                                                                                                                          5.1.1 Component View Query System overview

                                                                                                                                                                                                                          +

                                                                                                                                                                                                                          5.2.1 Component View Query System overview

                                                                                                                                                                                                                          @@ -1182,7 +1212,7 @@ reuse exiting Engine

                                                                                                                                                                                                                          Selection :

                                                                                                                                                                                                                            Transformation
                                                                                                                                                                                                                            Component DefaultsManager

                                                                                                                                                                                                                            -

                                                                                                                                                                                                                            5.1.2 Class View query

                                                                                                                                                                                                                            +

                                                                                                                                                                                                                            5.2.2 Class View query

                                                                                                                                                                                                                            @@ -1198,27 +1228,27 @@ reuse exiting Engine

                                                                                                                                                                                                                            Selection :

                                                                                                                                                                                                                              Transformation

                                                                                                                                                                                                                              -

                                                                                                                                                                                                                              5.1.3 Use Case View query use

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                              5.2.3 Use Case View query use

                                                                                                                                                                                                                              when to query



                                                                                                                                                                                                                              -

                                                                                                                                                                                                                              5.1.3.1 Use Case create specific object

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                              5.2.3.1 Use Case create specific object

                                                                                                                                                                                                                              -

                                                                                                                                                                                                                              5.1.3.2 Use Case use "default" object

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                              5.2.3.2 Use Case use "default" object

                                                                                                                                                                                                                              -

                                                                                                                                                                                                                              5.1.3.3 Use Case load object from session

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                              5.2.3.3 Use Case load object from session

                                                                                                                                                                                                                              -

                                                                                                                                                                                                                              5.1.3.4 Use Case add new object to session

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                              5.2.3.4 Use Case add new object to session

                                                                                                                                                                                                                              Class User
                                                                                                                                                                                                                              -

                                                                                                                                                                                                                              5.1.3.5 Use Case ConfigQuery

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                              5.2.3.5 Use Case ConfigQuery

                                                                                                                                                                                                                              -

                                                                                                                                                                                                                              5.1.3.6 Use Case need sub object

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                              5.2.3.6 Use Case need sub object

                                                                                                                                                                                                                              "default" object



                                                                                                                                                                                                                              @@ -1226,7 +1256,7 @@ reuse exiting Engine

                                                                                                                                                                                                                              Selection :

                                                                                                                                                                                                                                Transformation
                                                                                                                                                                                                                                Class instance predicate impl

                                                                                                                                                                                                                                type :TypeHandler

                                                                                                                                                                                                                                -

                                                                                                                                                                                                                                5.2 Class View error

                                                                                                                                                                                                                                +

                                                                                                                                                                                                                                5.3 Class View error

                                                                                                                                                                                                                                @@ -1240,7 +1270,7 @@ reuse exiting Engine

                                                                                                                                                                                                                                Selection :

                                                                                                                                                                                                                                  Transformation

                                                                                                                                                                                                                                  -

                                                                                                                                                                                                                                  5.3 Class View Service Components

                                                                                                                                                                                                                                  +

                                                                                                                                                                                                                                  5.4 Class View Service Components

                                                                                                                                                                                                                                  Class Tool
                                                                                                                                                                                                                                  @@ -1250,7 +1280,7 @@ reuse exiting Engine

                                                                                                                                                                                                                                  Selection :

                                                                                                                                                                                                                                    Transformation
                                                                                                                                                                                                                                    Class Appconfig

                                                                                                                                                                                                                                    -

                                                                                                                                                                                                                                    5.4 Class View Posix Threads Abstraction

                                                                                                                                                                                                                                    +

                                                                                                                                                                                                                                    5.5 Class View Posix Threads Abstraction

                                                                                                                                                                                                                                    C++ wrapers for pthreads

                                                                                                                                                                                                                                    Class Thread
                                                                                                                                                                                                                                    @@ -1258,7 +1288,7 @@ reuse exiting Engine

                                                                                                                                                                                                                                    Selection :

                                                                                                                                                                                                                                      Transformation
                                                                                                                                                                                                                                      Class Mutex

                                                                                                                                                                                                                                      -

                                                                                                                                                                                                                                      5.5 Class View SmartPointers

                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      5.6 Class View SmartPointers

                                                                                                                                                                                                                                      diff --git a/doc/devel/uml/index_60.html b/doc/devel/uml/index_60.html index a873c25b0..75ccc147d 100644 --- a/doc/devel/uml/index_60.html +++ b/doc/devel/uml/index_60.html @@ -17,8 +17,8 @@ - + @@ -28,8 +28,8 @@ - + diff --git a/doc/devel/uml/index_65.html b/doc/devel/uml/index_65.html index 33d5ebd2f..ab57596c5 100644 --- a/doc/devel/uml/index_65.html +++ b/doc/devel/uml/index_65.html @@ -55,12 +55,12 @@ - + - - + + diff --git a/doc/devel/uml/index_67.html b/doc/devel/uml/index_67.html index 8432e5cc6..81d96139c 100644 --- a/doc/devel/uml/index_67.html +++ b/doc/devel/uml/index_67.html @@ -26,38 +26,38 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -96,9 +96,9 @@ + + - - diff --git a/doc/devel/uml/index_69.html b/doc/devel/uml/index_69.html index a7245b34b..4fe57adfd 100644 --- a/doc/devel/uml/index_69.html +++ b/doc/devel/uml/index_69.html @@ -19,7 +19,6 @@ - @@ -27,6 +26,7 @@ + diff --git a/doc/devel/uml/index_70.html b/doc/devel/uml/index_70.html index 56bc1daaf..77ab812da 100644 --- a/doc/devel/uml/index_70.html +++ b/doc/devel/uml/index_70.html @@ -36,8 +36,8 @@ - + diff --git a/doc/devel/uml/index_71.html b/doc/devel/uml/index_71.html index f4ad7d96d..75f10c74f 100644 --- a/doc/devel/uml/index_71.html +++ b/doc/devel/uml/index_71.html @@ -46,6 +46,7 @@ + diff --git a/doc/devel/uml/index_73.html b/doc/devel/uml/index_73.html index e127cf07e..963294360 100644 --- a/doc/devel/uml/index_73.html +++ b/doc/devel/uml/index_73.html @@ -18,11 +18,12 @@
                                                                                                                                                                                                                                      NameKindDescription
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      <flow>transition
                                                                                                                                                                                                                                      Assetsclass view
                                                                                                                                                                                                                                      ATTACHattributeattach subject to anchor (e.g. an effect to a clip)
                                                                                                                                                                                                                                      au1class instance
                                                                                                                                                                                                                                      aud_Aclass instance
                                                                                                                                                                                                                                      aud_aclass instance
                                                                                                                                                                                                                                      aud_Aclass instance
                                                                                                                                                                                                                                      audioclass instance
                                                                                                                                                                                                                                      audio1class instance
                                                                                                                                                                                                                                      audio1class instance
                                                                                                                                                                                                                                      audio1class instance
                                                                                                                                                                                                                                      audio1class instance
                                                                                                                                                                                                                                      audio1class instance
                                                                                                                                                                                                                                      autoartifactMedia Object holding automation data
                                                                                                                                                                                                                                      AutoclassAutomation data for some parameter (i.e. a time varying function)
                                                                                                                                                                                                                                      Automation Entitiesclass diagram
                                                                                                                                                                                                                                      Categoryclasstree like classification of Assets
                                                                                                                                                                                                                                      categoryartifacttree like classification of Assets
                                                                                                                                                                                                                                      causeattributea copy of the first exception encountered in this exception chain
                                                                                                                                                                                                                                      chainoperationcreate and add another Placement for this media object, thus increasingly constraining the (possible) position of this object.
                                                                                                                                                                                                                                      chainrelationChain of additional Placements further constraining the position of this MObject
                                                                                                                                                                                                                                      chainoperationcreate and add another Placement for this media object, thus increasingly constraining the (possible) position of this object.
                                                                                                                                                                                                                                      checked_inrelationchecked_in objects are subject of cache aging and must be not in use
                                                                                                                                                                                                                                      checked_outrelationthis list keeps all mappings which are in use, and thus prevents them from Cache aging
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      class instanceclass instance
                                                                                                                                                                                                                                      clearoperationclear current session contents
                                                                                                                                                                                                                                      without resetting overall session config.
                                                                                                                                                                                                                                      Afterwards, the session will contain only one
                                                                                                                                                                                                                                      empty EDL, while all Assets are retained.
                                                                                                                                                                                                                                      client codecomponent
                                                                                                                                                                                                                                      Clipclassbookkeeping (asset) view of a media clip.
                                                                                                                                                                                                                                      connectopaque activity action
                                                                                                                                                                                                                                      constraintartifactLocatingPin representing an directive by the user that
                                                                                                                                                                                                                                      must not be violated
                                                                                                                                                                                                                                      Constraintclass
                                                                                                                                                                                                                                      controlpackagesourcecode package

                                                                                                                                                                                                                                      The Processing and Render Controller,
                                                                                                                                                                                                                                      and the Proc-Layer dispatcher
                                                                                                                                                                                                                                      Controlpackage
                                                                                                                                                                                                                                      Controllercomponent
                                                                                                                                                                                                                                      Controllerpackage
                                                                                                                                                                                                                                      controllerpackagesourcecode package

                                                                                                                                                                                                                                      The Processing and Render Controller,
                                                                                                                                                                                                                                      located within the MObject Subsystem
                                                                                                                                                                                                                                      Controller Entitiesclass diagram
                                                                                                                                                                                                                                      Controller Workingsclass view
                                                                                                                                                                                                                                      ControllerFacadeclassProvides unified access to the Proc-Subsystem Controller. Especially, this Facade class provides the functions to get a render engine to carry out actual renderings.
                                                                                                                                                                                                                                      NameKindDescription
                                                                                                                                                                                                                                      edlartifactthe (high level) Edit Decision List within the current Session
                                                                                                                                                                                                                                      EDLcomponent
                                                                                                                                                                                                                                      EDLclass
                                                                                                                                                                                                                                      EDL Example1object diagramA simple example showing how the actual objects are placed in the Fixture (=definitive playlist). It shows a Video and Audio clip placed on two tracks
                                                                                                                                                                                                                                      EDL Example2object diagramMore complex example showing the Object graph in the EDL and how it is linked into the Fixture to yield the actual locations. In this example, an HUE Effect is applied on a part of the Clip
                                                                                                                                                                                                                                      edlsrelation
                                                                                                                                                                                                                                      effectartifactEDL representation of a pluggable and automatable effect.
                                                                                                                                                                                                                                      effectartifactEffect or media processing component
                                                                                                                                                                                                                                      Effectclass
                                                                                                                                                                                                                                      effectiveTimelinerelation
                                                                                                                                                                                                                                      elementsrelationrelevant MObjects comprising this segment. TODO: actually necessary??
                                                                                                                                                                                                                                      enableoperationchange the enabled status of this asset. Note the corresponding #isActive predicate may depend on the enablement status of parent assets as well
                                                                                                                                                                                                                                      endattributeend of the timerange (excl)
                                                                                                                                                                                                                                      FixedLocationclass
                                                                                                                                                                                                                                      Fixtureactivity object
                                                                                                                                                                                                                                      fixtureartifactthe (low level) representation of the EDL with concrete placement data
                                                                                                                                                                                                                                      Fixturecomponent
                                                                                                                                                                                                                                      Fixtureclass
                                                                                                                                                                                                                                      Fixturecomponent
                                                                                                                                                                                                                                      fork activity nodefork activity node
                                                                                                                                                                                                                                      FrameclassFrames are just a low level lump of continous memory, most parts are opaque. Frames are memory sensitive, they will be small constant sized structures which can be efficently managed in a pool.
                                                                                                                                                                                                                                      Framenode
                                                                                                                                                                                                                                      getValueoperation
                                                                                                                                                                                                                                      GLBufclass
                                                                                                                                                                                                                                      glbufartifacta buffer and render process holding a Video frame for OpenGL rendering
                                                                                                                                                                                                                                      globalBussesrelation
                                                                                                                                                                                                                                      glpipeartifactspecialized connection element for handling OpenGL implementation details
                                                                                                                                                                                                                                      glrenderartifactRepresentation of a OpenGL accellerated Video render process
                                                                                                                                                                                                                                      groupsattributeadditional classification, selections or departments this asset belongs to. Groups are optional, non-exclusive and may be overlapping.
                                                                                                                                                                                                                                      + - - + + diff --git a/doc/devel/uml/index_77.html b/doc/devel/uml/index_77.html index e6d8e8031..c88824279 100644 --- a/doc/devel/uml/index_77.html +++ b/doc/devel/uml/index_77.html @@ -31,6 +31,7 @@ + @@ -40,6 +41,7 @@ +
                                                                                                                                                                                                                                      NameKindDescription
                                                                                                                                                                                                                                      idattributeAsset primary key.
                                                                                                                                                                                                                                      ImplFacadeclass
                                                                                                                                                                                                                                      In Memory Databaseclass diagram
                                                                                                                                                                                                                                      inFixtureactivity action pin
                                                                                                                                                                                                                                      inputclass instance
                                                                                                                                                                                                                                      inputclass instance
                                                                                                                                                                                                                                      inputclass instance
                                                                                                                                                                                                                                      inputclass instance
                                                                                                                                                                                                                                      inputclass instance
                                                                                                                                                                                                                                      instanceoperation
                                                                                                                                                                                                                                      instructionsrelation
                                                                                                                                                                                                                                      Interfaceclass view
                                                                                                                                                                                                                                      MediaAccessFacadeclassprovides functions for querying (opening) a media file, detecting the channels or streams found within this file, etc. Delegating to the actual backend functions
                                                                                                                                                                                                                                      MediaFactorycomponent
                                                                                                                                                                                                                                      MediaFactoryclassspecialized Asset Factory for configuring (new) media asset instances based on existing media files on disk; can create placeholder assets as well
                                                                                                                                                                                                                                      MediaKindclass
                                                                                                                                                                                                                                      merge activity nodemerge activity node
                                                                                                                                                                                                                                      Metaclasskey abstraction: metadata and organisational asset
                                                                                                                                                                                                                                      metaartifactkey abstraction: metadata and organisational asset
                                                                                                                                                                                                                                      mobjectpackagesourcecode package

                                                                                                                                                                                                                                      MObject Subsystem
                                                                                                                                                                                                                                      including the Session (EDL), Builder and Processing Controller
                                                                                                                                                                                                                                      MObjectpackage
                                                                                                                                                                                                                                      MObjectclass
                                                                                                                                                                                                                                      Monitorclass
                                                                                                                                                                                                                                      multichannel clipobject diagram
                                                                                                                                                                                                                                      MutexclassI provided a reworked Mutex class in my Cinelerra2 repository
                                                                                                                                                                                                                                      diff --git a/doc/devel/uml/index_80.html b/doc/devel/uml/index_80.html index 368babe6a..85ccb15d9 100644 --- a/doc/devel/uml/index_80.html +++ b/doc/devel/uml/index_80.html @@ -31,10 +31,12 @@ placementartifactKey Abstraction: a way to place and locate a Media Object Placementclassused to specify the position of a MObject in the EDL. This can be done in various ways (absolute, relative).
                                                                                                                                                                                                                                      Placement at the same time acts as (refcounting) smart pointer for accessing the MObject. playoperationTODO: will probably be handled differently (see Cehteh) +PlayControlclass +PlayheadCursorclass playlistnode plugartifactLocatingPin for requesting connection to some Port Plugclass -plugIDattributeIdentifier of the Plugin to be used +pluginattributeIdentifier of the Plugin to be used PluginAdapterclassAdapter used to integrage an effects processor in the render pipeline pluginadapterartifactAdapter for integrating various Effect processors in the render pipeline pnodenode @@ -63,8 +65,11 @@ procnodeartifactKey abstraction of the Render Engine: a Processing Node ProcPattclassspecial type of structural Asset representing information how to build some part of the render engine's processing nodes network. procpattartifacttemplate for building some render processing network +Projectclass +Project Entitiesclass view ProjectorclassSpecial video processing node used to scale and translate image data. projectorartifactvideo ProcNode for scaling and translating image data +Prototypeclass providerrelation pulloperation PullInputclass diff --git a/doc/devel/uml/index_82.html b/doc/devel/uml/index_82.html index 9b107d854..fd3368437 100644 --- a/doc/devel/uml/index_82.html +++ b/doc/devel/uml/index_82.html @@ -39,6 +39,7 @@ renderSegmentsrelation RenderStateclassEncapsulates the logic used to get a "current render process" in accordance to the currentyl applicable controller settings. The provided StateProxy serves to hold any mutalbe state used in the render process, so the rest of the render engine can be stateless. renderstateartifactrenderengine state manager +RenderTaskclass reprattributehuman readable representation of the condition characterizing this allocaton, e.g. "t >= 10" resetoperationreset all session config and
                                                                                                                                                                                                                                      start with a pristine default session. resolveoperationcreate an actual (explicit) placement while trying to satisfy the network of adjacent objects and placements. diff --git a/doc/devel/uml/index_83.html b/doc/devel/uml/index_83.html index 4ea8bf79b..e92c87510 100644 --- a/doc/devel/uml/index_83.html +++ b/doc/devel/uml/index_83.html @@ -28,12 +28,14 @@ segmentsactivity object segmentsactivity object segmentsrelationthe partitioning of the Timeline to be created by this tool. +Seqclass +Sequenceclass Serializerclass Service Componentsclass view Sessioncomponent sessionartifactInterface: the session edited by the user -Sessionclass view sessionpackagesourcecode package

                                                                                                                                                                                                                                      Everything concerning the EDL and Session, within the MObject Subsystem +Sessionclass view SessionclassPrimary Interface for all editing tasks.
                                                                                                                                                                                                                                      The session contains defaults, all the assets being edited, and a set of EDL with the individual MObjects to be manipulated and rendered. Session structureclass diagram sessionimplartifactholds the complete session data to be edited by the user @@ -52,7 +54,6 @@ SourceclassSource Node: represents a media source to pull data from. sourceartifactRepresentation of a Media source Source Overviewdeployment diagram -startattributestartpos in source startattributebegin of the timerange covered by this processor startattribute Stateclass @@ -65,11 +66,19 @@ stateproxyartifactKey Interface representing a render process and encapsulating state std::exceptionclass Strategyclass +Stream Type Frameworkclass diagram +StreamTypeclass view +streamtypeartifact +StreamTypeclass +StreamTypeIDclass Structclasskey abstraction: structural asset structartifactkey abstraction: structural asset Struct-Asset Relationsclass diagram +STypeManagerclass +stypemanagerartifact subjectrelationPlacement acts as smart pointer subPatternrelation +subSequencesrelation subTracksrelationChild tracks in a tree structure diff --git a/doc/devel/uml/index_84.html b/doc/devel/uml/index_84.html index 96532f18f..8f80d7c8d 100644 --- a/doc/devel/uml/index_84.html +++ b/doc/devel/uml/index_84.html @@ -20,35 +20,38 @@ the render configuration flowactivity diagram theApp_attributeholds the single instance and triggers initialization theFixturerelation -theTimelinerelation ThreadclassWe can basically reuse the Thread class design from Cinelerra2, Thread becomes a baseclass for all Threads timeattribute timeartifactunified representation of a time point, including conversion functions Timeclassdenotes a temporal position (time point), based on timeline start.

                                                                                                                                                                                                                                      investigate posix.4 realtime timers, wrap these here timelinenode +Timelineclass +TimelineSequencesclass diagram +TimelineViewclass toolpackagesourcecode package

                                                                                                                                                                                                                                      Tools and Utilities
                                                                                                                                                                                                                                      (separate from the main cinelrra binary) Toolclass ToolFactoryclass toolfactoryartifactsupply of Tool implementations for the Builder Trackclassstructural asset holding the configuration of a track in the EDL -trackrelation trackattribute trackrelation -trackartifactA grouping device within the EDL. The corresponding Placement
                                                                                                                                                                                                                                      by which this Track object is refered defines fallback placing
                                                                                                                                                                                                                                      properties to be used by all objects placed on this track in
                                                                                                                                                                                                                                      case they don't specify more concrete placements.
                                                                                                                                                                                                                                      Typically, tracks are used do make default Port connections,
                                                                                                                                                                                                                                      define a layer or pan for sound and for for disabling groups
                                                                                                                                                                                                                                      of clips. Note tracks are grouped in a tree like fashion.
                                                                                                                                                                                                                                      trackartifactstructural asset holding the configuration of a track in the EDL +trackartifactA grouping device within the EDL. The corresponding Placement
                                                                                                                                                                                                                                      by which this Track object is refered defines fallback placing
                                                                                                                                                                                                                                      properties to be used by all objects placed on this track in
                                                                                                                                                                                                                                      case they don't specify more concrete placements.
                                                                                                                                                                                                                                      Typically, tracks are used do make default Port connections,
                                                                                                                                                                                                                                      define a layer or pan for sound and for for disabling groups
                                                                                                                                                                                                                                      of clips. Note tracks are grouped in a tree like fashion.
                                                                                                                                                                                                                                      +trackrelation Trackclass tracksrelationelementary media assets comprising this compound +trackTreerelation Trafoclass trafoartifacttransforming processing Node treatoperation treatoperationThis operation is to be overloaded for the specific MObject subclasses to be treated. -treatoperation -treatoperation -treatoperation treatoperation +treatoperation +treatoperation +treatoperation treatoperation -treatoperation treatoperation +treatoperation TypeHandlerclass TypeHandler<Pipe>class diff --git a/doc/devel/uml/index_86.html b/doc/devel/uml/index_86.html index 3538c8202..203265efb 100644 --- a/doc/devel/uml/index_86.html +++ b/doc/devel/uml/index_86.html @@ -21,21 +21,21 @@ VFrameclass vframeartifacta buffer and render process holding a Video frame vid1class instance -vid_Aclass instance vid_aclass instance +vid_aclass instance +vid_Aclass instance vid_Aclass instance vid_Aclass instance -vid_aclass instance -videoclass instance videoclass instance videoclass instance videoclass instance -video1class instance -video1class instance -video1class instance +videoclass instance video1class instance +video1class instance +video1class instance video1class instance video1class instance +video1class instance Visitableclass visitorpackagesub-namespace for visitor library implementation visitorartifactAcyclic Visitor library diff --git a/doc/devel/uml/packages.html b/doc/devel/uml/packages.html index 49c0f4f80..25b52f427 100644 --- a/doc/devel/uml/packages.html +++ b/doc/devel/uml/packages.html @@ -20,14 +20,14 @@ Asset backendsrcsourcecode package

                                                                                                                                                                                                                                      Data backend classes here... BackendLayer -buildersrcsourcecode package

                                                                                                                                                                                                                                      The Builder creating the Render Engine,
                                                                                                                                                                                                                                      located within the MObject Subsystem Builder +buildersrcsourcecode package

                                                                                                                                                                                                                                      The Builder creating the Render Engine,
                                                                                                                                                                                                                                      located within the MObject Subsystem codegenThis package is used to organize code generation by BOUML. It is considered useless after having generated the initial code skeleton. commonsrcsourcecode package

                                                                                                                                                                                                                                      Common library and helper classes CommonLib ConfigQuery -Controller -controllersrcsourcecode package

                                                                                                                                                                                                                                      The Processing and Render Controller,
                                                                                                                                                                                                                                      located within the MObject Subsystem +controlsrcsourcecode package

                                                                                                                                                                                                                                      The Processing and Render Controller,
                                                                                                                                                                                                                                      and the Proc-Layer dispatcher +Control design designAll things concering the big picture.
                                                                                                                                                                                                                                      Not a real code package, rather a container for design drafts, specifications, decisions. enginesrcsourcecode package

                                                                                                                                                                                                                                      The Core Render Engine diff --git a/doc/devel/uml/public_operations.html b/doc/devel/uml/public_operations.html index 07fb079d7..fe9b01e39 100644 --- a/doc/devel/uml/public_operations.html +++ b/doc/devel/uml/public_operations.html @@ -69,12 +69,12 @@ saveSessManagercreate a complete, serialized representation
                                                                                                                                                                                                                                      of the current session config and contents.
                                                                                                                                                                                                                                      @todo how to serialize, prameters, return value? treatApplicable treatBuilderToolThis operation is to be overloaded for the specific MObject subclasses to be treated. +treatNodeCreatorTool treatNodeCreatorTool treatNodeCreatorTool -treatNodeCreatorTool treatNodeCreatorTool -treatSegmentationTool treatSegmentationTool +treatSegmentationTool treatSegmentationTool useFileFileProviderAnnounces that the application intends to use this file with mode (READ|WRITE|READWRITE) useTemporaryStorageFileProviderProvides a pool for interminate frames diff --git a/uml/lumiera/128005 b/uml/lumiera/128005 index dc0adfe5f..d3970e39a 100644 --- a/uml/lumiera/128005 +++ b/uml/lumiera/128005 @@ -1,6 +1,6 @@ format 40 "design" // design - revision 11 + revision 13 modified_by 5 "hiv" // class settings //class diagram settings @@ -50,7 +50,7 @@ Not a real code package, rather a container for design drafts, specifications, d component 128005 "Builder" stereotype "subsystem" provided_classes - class_ref 132741 // StateProxy + class_ref 132741 // State end required_classes class_ref 128261 // Fixture @@ -61,7 +61,7 @@ Not a real code package, rather a container for design drafts, specifications, d component 128133 "Session" stereotype "subsystem" provided_classes - class_ref 128133 // EDL + class_ref 128133 // Seq class_ref 128261 // Fixture class_ref 128517 // MObject class_ref 134661 // ParamProvider @@ -99,7 +99,7 @@ Not a real code package, rather a container for design drafts, specifications, d component 128901 "Engine" required_classes - class_ref 132741 // StateProxy + class_ref 132741 // State end simplerelation 128133 -_-> @@ -151,6 +151,206 @@ Not a real code package, rather a container for design drafts, specifications, d end end + classview 129413 "Project Entities" + //class diagram settings + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + //collaboration diagram settings + show_full_operations_definition default show_hierarchical_rank default write_horizontally default drawing_language default package_name_in_tab default show_context default draw_all_relations default shadow default + //object diagram settings + write_horizontally default package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default + //sequence diagram settings + show_full_operations_definition default write_horizontally default class_drawing_mode default drawing_language default draw_all_relations default shadow default + //state diagram settings + package_name_in_tab default show_context default auto_label_position default write_trans_label_horizontally default show_trans_definition default draw_all_relations default shadow default + show_activities default region_horizontally default drawing_language default + //class settings + //activity diagram settings + package_name_in_tab default show_context default show_opaque_action_definition default auto_label_position default write_flow_label_horizontally default draw_all_relations default shadow default + show_infonote default drawing_language default + + classdiagram 132741 "TimelineSequences" + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + size A4 + end + + class 145669 "Project" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 158981 // + relation 154885 *--- + a role_name "" multiplicity "1..*" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + classrelation_ref 158981 // + b role_name "" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + classrelation_ref 159109 // + end + + classrelation 159365 // + relation 155141 *--- + a role_name "" multiplicity "1..*" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + classrelation_ref 159365 // + b role_name "" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + classrelation_ref 159493 // + end + end + + class 145925 "PlayControl" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 160389 // + relation 156037 ---> + stereotype "direct" + a role_name "" multiplicity "*" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 160389 // + b multiplicity "" parent class_ref 146437 // PlayheadCursor + end + end + + class 146053 "Monitor" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 160133 // + relation 155781 ---> + stereotype "attach" + a role_name "" multiplicity "0..1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 160133 // + b multiplicity "" parent class_ref 145541 // Timeline + end + + classrelation 160517 // + relation 156165 ---- + a role_name "" multiplicity "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 160517 // + b role_name "" multiplicity "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 160645 // + end + end + + class 146181 "RenderTask" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 160261 // + relation 155909 ---> + a role_name "" multiplicity "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 160261 // + b multiplicity "" parent class_ref 145541 // Timeline + end + end + + class 146309 "Sequence" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 159493 // + relation_ref 155141 // + end + + classrelation 159877 // subSequences () + relation 155525 ---> + stereotype "contains" + a role_name "subSequences" multiplicity "*" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 159877 // subSequences () + b multiplicity "1..*" parent class_ref 146309 // Sequence + end + + classrelation 161541 // + relation 156933 ---> + a role_name "" multiplicity "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 161541 // + b multiplicity "" parent class_ref 128517 // MObject + end + + classrelation 161669 // trackTree () + relation 157061 ---> + a role_name "trackTree" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 161669 // trackTree () + b multiplicity "" parent class_ref 128389 // Track + end + end + + class 146437 "PlayheadCursor" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 160645 // + relation_ref 156165 // + end + + classrelation 160901 // + relation_ref 156293 // + end + end + end + componentview 128133 "interfaces" //component diagram settings package_name_in_tab default show_context default auto_label_position default draw_all_relations default shadow default diff --git a/uml/lumiera/128133.diagram b/uml/lumiera/128133.diagram index 466c2ad1d..1fbd686ec 100644 --- a/uml/lumiera/128133.diagram +++ b/uml/lumiera/128133.diagram @@ -4,7 +4,7 @@ classcanvas 128005 class_ref 128005 // SessionImpl draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default xyz 18 679 2000 end -classcanvas 128133 class_ref 128133 // EDL +classcanvas 128133 class_ref 128133 // Seq draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default xyz 231 679 2000 end @@ -34,11 +34,11 @@ classcanvas 130949 class_ref 128773 // AbstractMO end classcanvas 131461 class_ref 128901 // Clip draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default - xyz 279 361 2000 + xyz 279 368 2000 end classcanvas 131717 class_ref 129029 // Effect draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default - xyz 332 361 2000 + xyz 332 368 2000 end classcanvas 131973 class_ref 129157 // Meta draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default @@ -74,10 +74,8 @@ classcanvas 136581 class_ref 129925 // Auto end note 136837 "Placement \"locates\" a Media Object" xyzwh 370 73 3005 207 36 -textcanvas 136965 "the Timeline is a list of placements reduced to absolute coordinates (time, track)" - xyzwh 468 919 2000 121 90 textcanvas 137093 "Fixture is the actual assembly of various Media Objects ready to be performed" - xyzwh -27 863 2000 147 108 + xyzwh 28 862 2000 151 86 classcanvas 137221 class_ref 130053 // Wish draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default xyz 560 532 2000 @@ -114,8 +112,10 @@ classcanvas 146437 class_ref 140421 // Plug draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default xyz 560 597 2000 end -textcanvas 146821 "global processing Pipe Asset" - xyzwh 271 568 2000 149 24 +classcanvas 146949 class_ref 145541 // Timeline + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 114 546 2000 + end relationcanvas 128389 relation_ref 128005 // from ref 128005 z 1999 to ref 128133 role_a_pos 200 676 3000 no_role_b @@ -173,7 +173,7 @@ relationcanvas 135685 relation_ref 130949 // no_multiplicity_a no_multiplicity_b relationcanvas 135941 relation_ref 131077 // from ref 128261 z 1999 stereotype "<>" xyz 371 893 3000 to ref 135813 - role_a_pos 389 857 3000 no_role_b + role_a_pos 365 849 3000 no_role_b multiplicity_a_pos 451 877 3000 no_multiplicity_b relationcanvas 136069 relation_ref 131205 // from ref 135813 z 1999 to point 433 897 @@ -258,21 +258,16 @@ relationcanvas 145285 relation_ref 145029 // from ref 129029 z 1999 stereotype "<>" xyz 389 732 3000 to point 445 749 line 145413 z 1999 to point 369 749 line 145541 z 1999 to ref 129029 - role_a_pos 382 748 3000 no_role_b - multiplicity_a_pos 403 704 3000 no_multiplicity_b + role_a_pos 390 750 3000 no_role_b + multiplicity_a_pos 410 715 3000 no_multiplicity_b relationcanvas 145669 relation_ref 145157 // from ref 128133 z 1999 to ref 129029 - role_a_pos 376 681 3000 no_role_b + role_a_pos 392 672 3000 no_role_b no_multiplicity_a no_multiplicity_b relationcanvas 145925 relation_ref 145413 // from ref 128261 z 1999 to ref 129925 role_a_pos 321 978 3000 no_role_b no_multiplicity_a no_multiplicity_b -relationcanvas 146181 relation_ref 145541 // - from ref 128005 z 1999 to point 311 616 - line 146309 z 1999 stereotype "<>" xyz 103 649 3000 to ref 146053 - role_a_pos 307 594 3000 no_role_b - multiplicity_a_pos 329 627 3000 no_multiplicity_b relationcanvas 146565 relation_ref 145669 // from ref 146437 z 1999 to ref 137221 no_role_a no_role_b @@ -281,4 +276,8 @@ relationcanvas 146693 relation_ref 145797 // from ref 146437 z 1999 to ref 146053 role_a_pos 398 594 3000 no_role_b no_multiplicity_a no_multiplicity_b +relationcanvas 147077 relation_ref 155653 // + from ref 146949 z 1999 stereotype "<>" xyz 191 582 3000 to ref 146053 + role_a_pos 285 575 3000 no_role_b + multiplicity_a_pos 327 613 3000 multiplicity_b_pos 180 584 3000 end diff --git a/uml/lumiera/128261 b/uml/lumiera/128261 index c4b03ca90..0d01de253 100644 --- a/uml/lumiera/128261 +++ b/uml/lumiera/128261 @@ -1,6 +1,6 @@ format 40 "MObject" // ProcessingLayer::MObject - revision 32 + revision 33 modified_by 5 "hiv" // class settings //class diagram settings @@ -62,7 +62,7 @@ ${inlines} comment "Primary Interface for all editing tasks. The session contains defaults, all the assets being edited, and a set of EDL with the individual MObjects to be manipulated and rendered." operation 133509 "currEDL" - public return_type class_ref 128133 // EDL + public return_type class_ref 128133 // Seq nparams 0 cpp_decl " ${comment}${friend}${static}${inline}${virtual}${type} ${name} ${(}${)}${const}${volatile} ${throw}${abstract};" cpp_def "${comment}${inline}${type} @@ -133,7 +133,7 @@ ${inlines} cpp default " ${comment}${static}${mutable}${volatile}${const}${stereotype}<${type}> ${name}${value}; " classrelation_ref 128005 // edls () - b multiplicity "" parent class_ref 128133 // EDL + b multiplicity "" parent class_ref 128133 // Seq end classrelation 128261 // theFixture () @@ -250,7 +250,93 @@ of the current session config and contents. end end - class 128133 "EDL" + class 145541 "Timeline" + abstract visibility public + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 159109 // + relation_ref 154885 // + end + + classrelation 159237 // + relation 155013 ---> + stereotype "own" + a role_name "" multiplicity "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 159237 // + b multiplicity "" parent class_ref 145925 // PlayControl + end + + classrelation 159621 // + relation 155269 ---> + a role_name "" multiplicity "1" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 159621 // + b multiplicity "" parent class_ref 146309 // Sequence + end + + classrelation 160005 // globalBusses () + relation 155653 *--> + stereotype "list" + a role_name "globalBusses" multiplicity "*" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; +" + classrelation_ref 160005 // globalBusses () + b multiplicity "1" parent class_ref 138117 // Pipe + end + end + + class 145797 "TimelineView" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 158853 // + relation 154757 -_-|> + a public + cpp default "${type}" + classrelation_ref 158853 // + b multiplicity "" parent class_ref 145541 // Timeline + end + + classrelation 159749 // + relation 155397 ---> + a role_name "" multiplicity "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 159749 // + b multiplicity "" parent class_ref 146309 // Sequence + end + + classrelation 160773 // + relation 156293 ---- + a role_name "" multiplicity "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 160773 // + b role_name "" multiplicity "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 160901 // + end + end + + class 128133 "Seq" visibility package cpp_decl "${comment}${template}class ${name}${inherit} { @@ -298,16 +384,16 @@ ${inlines} a public cpp default "${type}" classrelation_ref 128517 // - b multiplicity "" parent class_ref 128133 // EDL + b multiplicity "" parent class_ref 128133 // Seq end - classrelation 131717 // theTimeline () + classrelation 131717 // effectiveTimeline () relation 131077 *--> stereotype "list" - a role_name "theTimeline" multiplicity "*" protected + a role_name "effectiveTimeline" multiplicity "*" protected cpp default " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; " - classrelation_ref 131717 // theTimeline () + classrelation_ref 131717 // effectiveTimeline () b multiplicity "" parent class_ref 129797 // ExplicitPlacement end @@ -423,6 +509,14 @@ ${inlines} b multiplicity "" parent class_ref 128389 // Track association_type class_ref 128645 // Placement end + + classrelation 161413 // + relation 156805 -_-|> + a public + cpp default "${type}" + classrelation_ref 161413 // + b multiplicity "" parent class_ref 128517 // MObject + end end class 128517 "MObject" @@ -618,16 +712,6 @@ ${inlines} b multiplicity "" parent class_ref 128773 // AbstractMO end - attribute 128645 "start" - protected type class_ref 134917 // Time - init_value "Time(0)" - cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; -" - java_decl "" - idl_decl "" - comment "startpos in source" - end - classrelation 142469 // source () relation 140677 ---> a role_name "source" multiplicity "1" protected @@ -637,6 +721,14 @@ ${inlines} classrelation_ref 142469 // source () b multiplicity "*" parent class_ref 136709 // Media end + + classrelation 161029 // + relation 156421 -_-|> + a public + cpp default "${type}" + classrelation_ref 161029 // + b multiplicity "" parent class_ref 128517 // MObject + end end class 138885 "SimpleClip" @@ -711,7 +803,7 @@ ${inlines} b multiplicity "" parent class_ref 128773 // AbstractMO end - attribute 128901 "plugID" + attribute 128901 "plugin" protected explicit_type "string" cpp_decl " ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value}; " @@ -719,6 +811,14 @@ ${inlines} idl_decl "" comment "Identifier of the Plugin to be used" end + + classrelation 161157 // + relation 156549 -_-|> + a public + cpp default "${type}" + classrelation_ref 161157 // + b multiplicity "" parent class_ref 128517 // MObject + end end class 129157 "Meta" @@ -911,6 +1011,14 @@ ${inlines} classrelation_ref 130949 // b multiplicity "" parent class_ref 129157 // Meta end + + classrelation 161285 // + relation 156677 -_-|> + a public + cpp default "${type}" + classrelation_ref 161285 // + b multiplicity "" parent class_ref 128517 // MObject + end end class 129925 "Auto" diff --git a/uml/lumiera/129029 b/uml/lumiera/129029 index 5c7a2a6f4..e091ca09b 100644 --- a/uml/lumiera/129029 +++ b/uml/lumiera/129029 @@ -1,6 +1,6 @@ format 40 "Control" // ProcessingLayer::Control - revision 6 + revision 7 modified_by 5 "hiv" // class settings //class diagram settings diff --git a/uml/lumiera/129285 b/uml/lumiera/129285 index 4ff722e2d..4089706c0 100644 --- a/uml/lumiera/129285 +++ b/uml/lumiera/129285 @@ -1,6 +1,6 @@ format 40 "ProcessingLayer" // ProcessingLayer - revision 23 + revision 24 modified_by 5 "hiv" // class settings //class diagram settings @@ -120,8 +120,6 @@ format 40 attributes attribute_ref 128517 // length "5" - attribute_ref 128645 // start - "100" end relations end @@ -132,8 +130,6 @@ format 40 attributes attribute_ref 128517 // length "8820" - attribute_ref 128645 // start - "176400" end relations end @@ -180,15 +176,13 @@ format 40 attributes attribute_ref 128517 // length "5" - attribute_ref 128645 // start - "100" end relations end end classinstance 129541 "" - type class_ref 128133 // EDL + type class_ref 128133 // Seq attributes end relations @@ -220,8 +214,6 @@ format 40 attributes attribute_ref 128517 // length "5" - attribute_ref 128645 // start - "100" end relations end @@ -244,7 +236,7 @@ format 40 attributes attribute_ref 128517 // length "3" - attribute_ref 128901 // plugID + attribute_ref 128901 // plugin "\"Hue\"" end relations @@ -270,7 +262,7 @@ format 40 attributes attribute_ref 128517 // length "3" - attribute_ref 128901 // plugID + attribute_ref 128901 // plugin "\"Hue\"" end relations diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session index af68f0264..d04da5e91 100644 --- a/uml/lumiera/5.session +++ b/uml/lumiera/5.session @@ -1,24 +1,30 @@ window_sizes 1302 1004 270 1022 854 71 diagrams - classdiagram_ref 131973 // Render Mechanics - 407 690 100 4 2 0 - collaborationdiagram_ref 132229 // Render Process - 825 684 100 4 0 0 - classdiagram_ref 132357 // StateAdapter composition - 414 658 100 4 0 0 - active classdiagram_ref 132485 // Stream Type Framework - 463 594 100 4 0 0 + classdiagram_ref 128133 // Session structure + 853 742 100 4 120 0 + active classdiagram_ref 132741 // TimelineSequences + 585 732 100 4 0 0 end show_stereotypes selected package_ref 129 // lumiera open + class_ref 145925 // PlayControl deploymentview_ref 128261 // gen deploymentview_ref 129157 // gen package_ref 130181 // mobject classview_ref 128389 // Controller Workings - class_ref 132741 // State + class_ref 139653 // Session + class_ref 128005 // SessionImpl + class_ref 145541 // Timeline + class_ref 145797 // TimelineView + class_ref 128133 // Seq + class_ref 128389 // Track + class_ref 128901 // Clip + class_ref 129029 // Effect + + package_ref 128901 // Builder class_ref 131717 // ProcNode class_ref 142469 // StateProxy class_ref 142597 // StateAdapter @@ -32,7 +38,6 @@ open class_ref 144517 // Strategy class_ref 144005 // BuffTable class_ref 144261 // Invocation - usecaseview_ref 128005 // Renderengine Use classview_ref 129285 // StreamType classview_ref 128773 // error class_ref 140165 // Visitable diff --git a/uml/lumiera/lumiera.prj b/uml/lumiera/lumiera.prj index a533da6cc..1017e01e2 100644 --- a/uml/lumiera/lumiera.prj +++ b/uml/lumiera/lumiera.prj @@ -1,6 +1,6 @@ format 40 "lumiera" - revision 48 + revision 49 modified_by 5 "hiv" cpp_root_dir "../../src/" diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 26659922d..01c9a849d 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -4753,11 +4753,11 @@ function addKeyDownHandlers(e)
                                                                                                                                                                                                                                      http://tiddlywiki.com/
                                                                                                                                                                                                                                      -
                                                                                                                                                                                                                                      -
                                                                                                                                                                                                                                      Timeline is the top level element within the [[Session (Project)|Session]]. It is visible within a //timeline view// in the GUI and represents the definitive arrangement of media objects, to be rendered for output or viewed in a Monitor (viewer window). A timeline is comprised of:
                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Timeline is the top level element within the [[Session (Project)|Session]]. It is visible within a //timeline view// in the GUI and represents the effective (resulting) arrangement of media objects, to be rendered for output or viewed in a Monitor (viewer window). A timeline is comprised of:
                                                                                                                                                                                                                                       * a time axis in abolute time (WIP: not clear if this is an entity or just a conceptual definition) 
                                                                                                                                                                                                                                       * a PlayControler
                                                                                                                                                                                                                                      -* a list of global Pipes representing the possible outputs
                                                                                                                                                                                                                                      +* a list of global Pipes representing the possible outputs (master busses)
                                                                                                                                                                                                                                       * //exactly one// top-level [[EDL (Sequence)|EDL]], which in turn may contain further nested ~EDLs (Sequences).
                                                                                                                                                                                                                                       Please note especially that following this design //a timeline doesn't define tracks.// [[Tracks form a Tree|Track]] and are part of the individual ~EDLs (Sequences), together with the media objects placed to these tracks.
                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                      @@ -4766,11 +4766,20 @@ Within the Project, there may be ''multiple timelines'', to be viewed and render
                                                                                                                                                                                                                                       ''Note'': in early drafts of the design (2007) there was an entity called "Timeline" within the [[Fixture]]. This entity seems superfluous and has been dropped. It never got any relevance in existing code and at most was used in some code comments.
                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                      -
                                                                                                                                                                                                                                      -
                                                                                                                                                                                                                                      Each Project can contain ''multiple timelines'', to be viewed and rendered independently. But, being the top-level entities, multiple timelines may not be combined further. You can always just render (or view) one specific timeline. Of course it is possible to use ~Sub-EDLs (~Sub-Sequences) within the top-level Sequence within a timeline to organize a movie into several scenes or chapters. 
                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      There is a three-level hierarchy: [[Project|Session]], [[Timeline]], [[Sequence|EDL]]. Each project can contain ''multiple timelines'', to be viewed and rendered independently. But, being the top-level entities, these timelines may not be combined further. You can always just render (or view) one specific timeline. Each of those timelines refers to a Sequence, which is a bunch of [[media objects|MObject]] placed to a tree of [[tracks|Track]]. Of course it is possible to use ~Sub-EDLs (Sub-sequences) within the top-level sequence within a timeline to organize a movie into several scenes or chapters. 
                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                      -As stated in the [[definition|Timeline]], a timeline refers to exactly one EDL (Sequence), and the latter defines a tree of [[tracks|Track]] and a bunch of media objects placed to these tracks. A Sequence may optionally also contain nested sequences as [[meta-clips|MetaClip]]. Moreover, obviously several timelines (top-level entities) may refer to the same Sequence without problems.
                                                                                                                                                                                                                                      -This is because the top-level entities (Timelines) are not permitted to be combined further. You may play or render a given timeline, you may even play several timelines simultanously in different monitor windows, and these different timelines may incorporate the same sequence in a different way
                                                                                                                                                                                                                                      +[>img[Relation of Timelines, Sequences and MObjects within the Project|uml/fig132741.png]]
                                                                                                                                                                                                                                      +As stated in the [[definition|Timeline]], a timeline refers to exactly one EDL (Sequence), and the latter defines a tree of [[tracks|Track]] and a bunch of media objects placed to these tracks. A Sequence may optionally also contain nested sequences as [[meta-clips|VirtualClip]]. Moreover, obviously several timelines (top-level entities) may refer to the same Sequence without problems.
                                                                                                                                                                                                                                      +This is because the top-level entities (Timelines) are not permitted to be combined further. You may play or render a given timeline, you may even play several timelines simultaneously in different monitor windows, and these different timelines may incorporate the same sequence in a different way. The Sequence just defines the relations between some objects and may be placed relatively to another object (clip, label,...) or similar reference point, or even anchored at an absolute time if desired. In a similar open fashion, within the track-tree of a sequence, we may define a specific signal routing, or we may just fall back to automatic output wiring.
                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      +!Attaching output
                                                                                                                                                                                                                                      +The Timeline owns a list of global [[pipes (busses)|Pipe]] which are used to collect output. If the track tree of a sequence doesn't contain specific routing advice, then connections will be done directly to these global pipes in order and by matching StreamType (i.e. typically video to video master, audio to stereo audio master). When a monitor (viewer window) is attached to this timeline, similar output connections are made from those global pipes, i.e. the video display will take the contents of the first video (master) bus, and the first stereo audio pipe will be pulled and sent to system audio out. The timeline owns a ''play control'' shared by all attached viewers and coordinating the rendering-for-viewing. Similarly, a render task may be attached to the timeline to pull the pipes needed for a given kind of generated output. The actual implementation of the play controller and the coordination of render tasks is located in the Backend, which uses the service of the Proc-Layer to pull the respective exit nodes of the render engine network.
                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      +!Timeline versus Timeline View
                                                                                                                                                                                                                                      +Actually, what the GUI creates and uses is the //view// of a given timeline. This makes no difference to start with, as the view is modelled to be a sub-concept of "timeline" and thus can stand-in. All different views of the //same// timeline also share one single play control instance, i.e. they all have one single playhead position. Doing it this way should be the default, because it's the least confusing. Anyway, it's also possible to create multiple //independent timelines// &mdash; in an extreme case even so when referring to the same top-level sequence. This configuration gives the ability to play the same arrangement in parallel with multiple independent play controllers (and thus independent playhead positions)
                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      +To complement this possibilities, I'd propose to give the //timeline view// the possibility to be re-linked to a sub-sequence. This way, it would stay connected to the main play control, but at the same time show a sub-sequence //in the way it will be treated as  embedded// within the top-level sequence. This would be the default operation mode when a meta-clip is opened (and showed in a separate tab with such a linked timeline view). The reason for this proposed handling is again to give the user the least surprising behaviour. Because, when &mdash; on the contrary &mdash; the sub-sequence would be opened as //separate timeline,// a different absolute time position and a different signal routing may result; doing such should be reserved for advanced use, e.g. when multiple editors cooperate on a single project and a sequence has to be prepared in isolation prior to being integrated in the global sequence (featuring the whole movie).
                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                      From a21a6b5d3dd803d09e7a5ff567b781e73a06154f Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 3 Nov 2008 08:00:32 +0100 Subject: [PATCH 049/249] Add dependencies to test-interfaces looks like one needs to add all dependencies manually when using _DEPENDENCIES at least works by that, maybe investigate this later --- tests/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 66367ffb4..a88377b92 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -72,6 +72,6 @@ check_PROGRAMS += test-interfaces test_interfaces_SOURCES = $(tests_srcdir)/backend/test-interfaces.c test_interfaces_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_interfaces_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) -lm -test_interfaces_DEPENDENCIES = examplepluginc.la +test_interfaces_DEPENDENCIES = examplepluginc.la liblumibackend.a liblumiera.a TESTS = $(tests_srcdir)/test.sh From 257b310699e3baf4bf9b491d7588d26a888bcbb7 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 3 Nov 2008 08:03:48 +0100 Subject: [PATCH 050/249] add an error_peek function, fix prototypes lumiera_error_peek() lets one investigate the error state without resetting it. --- src/lib/error.c | 11 ++++++++++- src/lib/error.h | 14 +++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/lib/error.c b/src/lib/error.c index 1d3fb50c3..6007dcbdb 100644 --- a/src/lib/error.c +++ b/src/lib/error.c @@ -60,7 +60,7 @@ lumiera_error_set (lumiera_err nerr) lumiera_err -lumiera_error () +lumiera_error (void) { pthread_once (&lumiera_error_initialized, lumiera_error_tls_init); @@ -69,3 +69,12 @@ lumiera_error () pthread_setspecific (lumiera_error_tls, NULL); return err; } + + +lumiera_err +lumiera_error_peek (void) +{ + pthread_once (&lumiera_error_initialized, lumiera_error_tls_init); + + return pthread_getspecific (lumiera_error_tls); +} diff --git a/src/lib/error.h b/src/lib/error.h index 5c4a8c145..5ad8a3142 100644 --- a/src/lib/error.h +++ b/src/lib/error.h @@ -88,7 +88,19 @@ lumiera_error_set (lumiera_err err); * @return pointer to any pending error of this thread, NULL if no error is pending */ lumiera_err -lumiera_error (); +lumiera_error (void); + + +/** + * Check current error state without clearing it + * Please avoid this function and use lumiera_error() if possible. Errors must be cleared else certain + * parts of the application refuse to cooperate with you. This shall only be used to decide if one + * wants to barf out of a loop or subroutine to deliver the error to a higher level. + * @return pointer to any pending error of this thread, NULL if no error is pending + */ +lumiera_err +lumiera_error_peek (void); + /* predefined errors From 2342c3a87ad519b0879ed0c191260dd3fce9080b Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 3 Nov 2008 08:07:22 +0100 Subject: [PATCH 051/249] New Plugin implementation * plugin{.h,.c} are back but work in progress * the interfaceregistry also manages a pluginregistry, makes no much sense to isolate it yet, both share a mutex and are commonly used together --- src/backend/Makefile.am | 2 + src/backend/interfaceregistry.c | 29 ++- src/backend/plugin.c | 374 +++++++++++--------------------- src/backend/plugin.h | 18 +- 4 files changed, 160 insertions(+), 263 deletions(-) diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index da39e71c6..be9b9cd90 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -29,6 +29,7 @@ liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/filehandlecache.c \ $(liblumibackend_a_srcdir)/interface.c \ $(liblumibackend_a_srcdir)/interfaceregistry.c \ + $(liblumibackend_a_srcdir)/plugin.c \ $(liblumibackend_a_srcdir)/config.c \ $(liblumibackend_a_srcdir)/config_typed.c \ $(liblumibackend_a_srcdir)/config_wordlist.c \ @@ -47,6 +48,7 @@ noinst_HEADERS += \ $(liblumibackend_a_srcdir)/interface.h \ $(liblumibackend_a_srcdir)/interfaceregistry.h \ $(liblumibackend_a_srcdir)/interfacedescriptor.h \ + $(liblumibackend_a_srcdir)/plugin.h \ $(liblumibackend_a_srcdir)/config.h \ $(liblumibackend_a_srcdir)/configentry.h \ $(liblumibackend_a_srcdir)/configitem.h \ diff --git a/src/backend/interfaceregistry.c b/src/backend/interfaceregistry.c index cc175dd0a..05e2224a1 100644 --- a/src/backend/interfaceregistry.c +++ b/src/backend/interfaceregistry.c @@ -29,6 +29,7 @@ +#include "backend/plugin.h" #include "backend/interfaceregistry.h" /** @@ -39,17 +40,20 @@ */ NOBUG_DEFINE_FLAG_PARENT (interface_all, backend); +NOBUG_DEFINE_FLAG_PARENT (plugin, interface_all); NOBUG_DEFINE_FLAG_PARENT (interfaceregistry, interface_all); NOBUG_DEFINE_FLAG_PARENT (interface, interface_all); PSplay lumiera_interfaceregistry; +PSplay lumiera_pluginregistry; lumiera_mutex lumiera_interface_mutex; static int -cmp_fn (const void* keya, const void* keyb); +lumiera_interface_cmp_fn (const void* keya, const void* keyb); static const void* -key_fn (const PSplaynode node); +lumiera_interface_key_fn (const PSplaynode node); + static LumieraInterfacenode @@ -92,13 +96,20 @@ lumiera_interfaceregistry_init (void) NOBUG_INIT_FLAG (interface_all); NOBUG_INIT_FLAG (interfaceregistry); NOBUG_INIT_FLAG (interface); + NOBUG_INIT_FLAG (plugin); + TRACE (interfaceregistry); REQUIRE (!lumiera_interfaceregistry); + REQUIRE (!lumiera_pluginregistry); - lumiera_interfaceregistry = psplay_new (cmp_fn, key_fn, NULL); + lumiera_interfaceregistry = psplay_new (lumiera_interface_cmp_fn, lumiera_interface_key_fn, NULL); if (!lumiera_interfaceregistry) LUMIERA_DIE (ERRNO); + lumiera_pluginregistry = psplay_new (lumiera_plugin_cmp_fn, lumiera_plugin_key_fn, NULL); + if (!lumiera_pluginregistry) + LUMIERA_DIE (ERRNO); + lumiera_recmutex_init (&lumiera_interface_mutex, "interfaceregistry", &NOBUG_FLAG(interfaceregistry)); } @@ -114,6 +125,13 @@ lumiera_interfaceregistry_destroy (void) if (lumiera_interfaceregistry) psplay_destroy (lumiera_interfaceregistry); lumiera_interfaceregistry = NULL; + + TODO ("provide a delete function for the psplay tree to tear it down"); + REQUIRE (psplay_nelements (lumiera_pluginregistry) == 0, "plugins still loaded at destroy"); + + if (lumiera_pluginregistry) + psplay_delete (lumiera_pluginregistry); + lumiera_pluginregistry = NULL; } @@ -216,7 +234,7 @@ lumiera_interfaceregistry_interface_find (const char* interface, unsigned versio static int -cmp_fn (const void* keya, const void* keyb) +lumiera_interface_cmp_fn (const void* keya, const void* keyb) { const LumieraInterface a = (const LumieraInterface)keya; const LumieraInterface b = (const LumieraInterface)keyb; @@ -243,12 +261,11 @@ cmp_fn (const void* keya, const void* keyb) static const void* -key_fn (const PSplaynode node) +lumiera_interface_key_fn (const PSplaynode node) { return ((LumieraInterfacenode)node)->interface; } - /* // Local Variables: // mode: C diff --git a/src/backend/plugin.c b/src/backend/plugin.c index f6ecd7649..1b708c6be 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -18,72 +18,72 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include -#include -#include -#include -#include -#include -#include - #include "lib/safeclib.h" +#include "lib/psplay.h" +#include "lib/mutex.h" +#include "lib/error.h" +#include "backend/interfaceregistry.h" +#include "backend/config.h" #include "backend/plugin.h" +#include + +#include + /** * @file * Plugin loader. */ +extern PSplay lumiera_pluginregistry; /* TODO should be set by the build system to the actual plugin path */ -#define LUMIERA_PLUGIN_PATH "~/.lumiera/plugins:/usr/local/lib/lumiera/plugins:.libs" - -NOBUG_DEFINE_FLAG (lumiera_plugin); /* errors */ LUMIERA_ERROR_DEFINE(PLUGIN_DLOPEN, "Could not open plugin"); -LUMIERA_ERROR_DEFINE(PLUGIN_HOOK, "Hook function failed"); -LUMIERA_ERROR_DEFINE(PLUGIN_NFILE, "No such plugin"); -LUMIERA_ERROR_DEFINE(PLUGIN_NIFACE, "No such interface"); -LUMIERA_ERROR_DEFINE(PLUGIN_REVISION, "Interface revision too old"); /* supported (planned) plugin types and their file extensions */ +#define LUMIERA_PLUGIN_TYPES \ + LUMIERA_PLUGIN_TYPE(DYNLIB, ".so") + +/* + only .so dynlibs for now, later we may support some more + LUMIERA_PLUGIN_TYPE(LUA, ".lua") + LUMIERA_PLUGIN_TYPE(CSOURCE, ".c") +*/ + +#define LUMIERA_PLUGIN_TYPE(type, ext) LUMIERA_PLUGIN_##type, enum lumiera_plugin_type { - LUMIERA_PLUGIN_NULL, - LUMIERA_PLUGIN_DYNLIB, - LUMIERA_PLUGIN_CSOURCE + LUMIERA_PLUGIN_TYPES + LUMIERA_PLUGIN_NONE }; +#undef LUMIERA_PLUGIN_TYPE -static const struct -{ - const char* const ext; - enum lumiera_plugin_type type; -} lumiera_plugin_extensions [] = +#define LUMIERA_PLUGIN_TYPE(type, ext) ext, +static const char* const lumiera_plugin_ext[] = { - {"so", LUMIERA_PLUGIN_DYNLIB}, - {"o", LUMIERA_PLUGIN_DYNLIB}, - {"c", LUMIERA_PLUGIN_CSOURCE}, - /* extend here */ - {NULL, LUMIERA_PLUGIN_NULL} + LUMIERA_PLUGIN_TYPES + NULL }; +#undef LUMIERA_PLUGIN_TYPE -struct lumiera_plugin + + +struct lumiera_plugin_struct { - /* short name as queried ("effects/audio/normalize") used for sorting/finding */ - const char* name; + psplaynode node; /* long names as looked up ("/usr/local/lib/lumiera/plugins/effects/audio/normalize.so") */ - const char* pathname; + const char* name; /* use count for all interfaces of this plugin */ - unsigned use_count; + unsigned refcnt; /* time when the last open or close action happened */ time_t last; @@ -96,242 +96,124 @@ struct lumiera_plugin }; -/* global plugin registry */ -void* lumiera_plugin_registry = NULL; -/* plugin operations are protected by one big mutex */ -pthread_mutex_t lumiera_plugin_mutex = PTHREAD_MUTEX_INITIALIZER; - -/** - * the compare function for the registry tree. - * Compares the names of two struct lumiera_plugin. - * @return 0 if a and b are equal, just like strcmp. */ -static int -lumiera_plugin_name_cmp (const void* a, const void* b) -{ - return strcmp (((struct lumiera_plugin*) a)->name, ((struct lumiera_plugin*) b)->name); -} - -void -lumiera_init_plugin (void) -{ - NOBUG_INIT_FLAG (lumiera_plugin); -} - -/** - * Find and set pathname for the plugin. - * Searches through given path for given plugin, trying to find the file's location in the filesystem. - * If found, self->pathname will be set to the found plugin file. - * @param self The lumiera_plugin to open look for. - * @param path The path to search trough (paths seperated by ":") - * @return 0 on success. -1 on error, or if plugin not found in path. - */ int -lumiera_plugin_lookup (struct lumiera_plugin* self, const char* path) +lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), + int (*callback_register) (LumieraPlugin)) { - if (!path) - return -1; + TRACE (plugin); + REQUIRE (callback_load); + REQUIRE (callback_register); - if (strlen(path) > 1023) - return -1; /*TODO error handling*/ - - char tpath[1024]; - TODO("dunno if PATH_MAX may be undefined (in case arbitary lengths are supported), I check that later"); - char pathname[1024] = {0}; - char* tmp; - - strcpy(tpath, path); - - /*for each in path*/ - for (char* tok = strtok_r (tpath, ":", &tmp); tok; tok = strtok_r (NULL, ":", &tmp)) + /* construct glob trail {.so,.c,.foo} ... */ + static char* exts_globs = NULL; + if (!exts_globs) { - /*for each extension*/ - for (int i = 0; lumiera_plugin_extensions[i].ext; ++i) + size_t exts_sz = 4; /* / * { } \0 less one comma */ + const char*const* itr = lumiera_plugin_ext; + while (*itr) { - /* path/name.extension */ - int r = snprintf(pathname, 1024, "%s/%s.%s", tok, self->name, lumiera_plugin_extensions[i].ext); - if (r >= 1024) - return -1; /*TODO error handling, name too long*/ + exts_sz += strlen (*itr) + 1; + ++itr; + } - TRACE (lumiera_plugin, "trying %s", pathname); + exts_globs = lumiera_malloc (exts_sz); + *exts_globs = '\0'; - if (!access(pathname, R_OK)) + itr = lumiera_plugin_ext; + strcat (exts_globs, "/*{"); + + while (*itr) + { + strcat (exts_globs, *itr); + strcat (exts_globs, ","); + ++itr; + } + exts_globs[exts_sz-2] = '}'; + TRACE (plugin, "initialized extension glob to '%s'", exts_globs); + } + + const char* path; + unsigned i = 0; + int flags = GLOB_PERIOD|GLOB_BRACE|GLOB_TILDE_CHECK; + glob_t globs; + + while ((path = lumiera_config_wordlist_get_nth ("plugin.path", i, ":"))) + { + path = lumiera_tmpbuf_snprintf (SIZE_MAX,"%s%s", path, exts_globs); + TRACE (plugin, "globbing path '%s'", path); + int ret = glob (path, flags, NULL, &globs); + if (ret == GLOB_NOSPACE) + LUMIERA_DIE (NO_MEMORY); + + flags |= GLOB_APPEND; + ++i; + } + + LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) + { + for (char** itr = globs.gl_pathv; *itr; ++itr) + { + + if (!psplay_find (lumiera_pluginregistry, *itr, 100)) { - /* got it */ - TRACE (lumiera_plugin, "found %s", pathname); - self->pathname = lumiera_strndup (pathname, PATH_MAX); + TRACE (plugin, "found new plugin '%s'", *itr); - self->type = lumiera_plugin_extensions[i].type; - return 0; + LumieraPlugin plugin = callback_load (*itr); + if (plugin) + callback_register (plugin); } } } - return -1; /* plugin not found */ + + globfree (&globs); + + return !lumiera_error_peek (); } -struct lumiera_interface* -lumiera_interface_open (const char* name, const char* interface, size_t min_revision) + + + +LumieraPlugin +lumiera_plugin_load (const char* plugin) { - //REQUIRE (min_revision > sizeof(struct lumiera_interface), "try to use an empty interface eh?"); - REQUIRE (interface, "interface name must be given"); + TRACE (plugin); + UNIMPLEMENTED(); + (void) plugin; - pthread_mutex_lock (&lumiera_plugin_mutex); - - struct lumiera_plugin plugin; - struct lumiera_plugin** found; - - plugin.name = name; /* for searching */ - - found = tsearch (&plugin, &lumiera_plugin_registry, lumiera_plugin_name_cmp); - if (!found) - LUMIERA_DIE (NO_MEMORY); - - if (*found == &plugin) - { - NOTICE (lumiera_plugin, "new plugin"); - - /* now really create new item */ - *found = lumiera_malloc (sizeof (struct lumiera_plugin)); - - if (name) /* NULL is main app, no lookup needed */ - { - /*lookup for $LUMIERA_PLUGIN_PATH*/ - (*found)->name = lumiera_strndup (name, PATH_MAX); - - if (!!lumiera_plugin_lookup (*found, getenv("LUMIERA_PLUGIN_PATH")) -#ifdef LUMIERA_PLUGIN_PATH - /* else lookup for -DLUMIERA_PLUGIN_PATH */ - && !!lumiera_plugin_lookup (*found, LUMIERA_PLUGIN_PATH) -#endif - ) - { - LUMIERA_ERROR_SET (lumiera_plugin, PLUGIN_NFILE); - goto elookup; - } - } - else - { - (*found)->name = NULL; - (*found)->pathname = NULL; - } - - (*found)->use_count = 0; - - PLANNED("if .so like then dlopen; else if .c like tcc compile"); - TODO("factor dlopen and dlsym out"); - - TRACE(lumiera_plugin, "trying to open %s", (*found)->pathname); - - (*found)->handle = dlopen ((*found)->pathname, RTLD_LAZY|RTLD_LOCAL); - if (!(*found)->handle) - { - ERROR (lumiera_plugin, "dlopen failed: %s", dlerror()); - LUMIERA_ERROR_SET (lumiera_plugin, PLUGIN_DLOPEN); - goto edlopen; - } - - /* if the plugin defines a 'lumiera_plugin_init' function, we call it, must return 0 on success */ - int (*init)(void) = dlsym((*found)->handle, "lumiera_plugin_init"); - if (init && init()) - { - //ERROR (lumiera_plugin, "lumiera_plugin_init failed: %s: %s", name, interface); - LUMIERA_ERROR_SET (lumiera_plugin, PLUGIN_HOOK); - goto einit; - } - } - /* we have the plugin, now get the interface descriptor */ - struct lumiera_interface* ret; - - dlerror(); - ret = dlsym ((*found)->handle, interface); - - const char *dlerr = dlerror(); - TRACE(lumiera_plugin, "%s", dlerr); - TODO ("need some way to tell 'interface not provided by plugin', maybe lumiera_plugin_error()?"); - if (dlerr) - { - //ERROR (lumiera_plugin, "plugin %s doesnt provide interface %s", name, interface); - LUMIERA_ERROR_SET (lumiera_plugin, PLUGIN_NIFACE); - goto edlsym; - } - - /* is the interface older than required? */ - if (ret->size < min_revision) - { - ERROR (lumiera_plugin, "plugin %s provides older interface %s revision than required", name, interface); - LUMIERA_ERROR_SET (lumiera_plugin, PLUGIN_REVISION); - goto erevision; - } - - ret->plugin = *found; - - /* if the interface provides a 'open' function, call it now, must return 0 on success */ - if (ret->open && ret->open()) - { - ERROR (lumiera_plugin, "open hook indicated an error"); - LUMIERA_ERROR_SET (lumiera_plugin, PLUGIN_HOOK); - goto eopen; - } - - (*found)->use_count++; - (*found)->last = time (NULL); - ret->use_count++; - - pthread_mutex_unlock (&lumiera_plugin_mutex); - return ret; - - /* Error cleanup */ - einit: - dlclose((*found)->handle); - eopen: - erevision: - edlsym: - edlopen: - elookup: - free ((char*)(*found)->name); - free (*found); - *found = &plugin; - tdelete (&plugin, &lumiera_plugin_registry, lumiera_plugin_name_cmp); - pthread_mutex_unlock (&lumiera_plugin_mutex); return NULL; } -void -lumiera_interface_close (void* ptr) + +int +lumiera_plugin_register (LumieraPlugin plugin) { - TRACE (lumiera_plugin, "%p", ptr); - if(!ptr) - return; + TRACE (plugin); + UNIMPLEMENTED(); - struct lumiera_interface* self = (struct lumiera_interface*) ptr; - - pthread_mutex_lock (&lumiera_plugin_mutex); - - struct lumiera_plugin* plugin = self->plugin; - - plugin->use_count--; - self->use_count--; - - /* if the interface provides a 'close' function, call it now */ - if (self->close) - self->close(); - - /* plugin not longer in use, unload it */ - if (!plugin->use_count) + LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) { - TODO ("we dont want to close here, instead store time of recent use and make a expire run, already planned in my head"); + (void) plugin; - /* if the plugin defines a 'lumiera_plugin_destroy' function, we call it */ - int (*destroy)(void) = dlsym(plugin->handle, "lumiera_plugin_destroy"); - if (destroy) - destroy(); - - /* and now cleanup */ - tdelete (plugin, &lumiera_plugin_registry, lumiera_plugin_name_cmp); - free ((char*)plugin->name); - dlclose(plugin->handle); - free (plugin); } - pthread_mutex_unlock (&lumiera_plugin_mutex); + return 0; } + + + + + +int +lumiera_plugin_cmp_fn (const void* keya, const void* keyb) +{ + return strcmp ((const char*)keya, (const char*)keyb); +} + + +const void* +lumiera_plugin_key_fn (const PSplaynode node) +{ + return ((LumieraPlugin)node)->name; +} + diff --git a/src/backend/plugin.h b/src/backend/plugin.h index 6696e395f..8c0e5e7ae 100644 --- a/src/backend/plugin.h +++ b/src/backend/plugin.h @@ -36,6 +36,7 @@ LUMIERA_ERROR_DECLARE(PLUGIN_DLOPEN); +LUMIERA_ERROR_DECLARE(PLUGIN_PLUGINPATH); NOBUG_DECLARE_FLAG (plugin); @@ -48,18 +49,11 @@ typedef struct lumiera_plugin_struct lumiera_plugin; typedef lumiera_plugin* LumieraPlugin; -/** - * Initialize the plugin system. - * always succeeds or aborts - */ -void -lumiera_pluginregistry_init (void); +int +lumiera_plugin_cmp_fn (const void* keya, const void* keyb); -/** - * destroy the plugin system, free all resources - */ -void -lumiera_pluginregistry_destroy (void); +const void* +lumiera_plugin_key_fn (const PSplaynode node); LumieraPlugin @@ -70,6 +64,8 @@ int lumiera_plugin_register (LumieraPlugin); + + /** * discover new plugins * traverses the configured plugin dirs and calls the callback_load function for any plugin From 9f8b0070a6510795c557f306e18a12323d81bcdc Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 3 Nov 2008 21:24:15 +0100 Subject: [PATCH 052/249] build option for SCons (verbose) --- SConstruct | 16 +++++++++++++--- tests/SConscript | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/SConstruct b/SConstruct index c6b0e0e66..20fa76840 100644 --- a/SConstruct +++ b/SConstruct @@ -63,6 +63,7 @@ def setupBasicEnvironment(): ,toolpath = [TOOLDIR] ,tools = ["default", "BuilderGCH", "BuilderDoxygen"] ) + handleVerboseMessages(env) env.Append ( CCCOM=' -std=gnu99') # workaround for a bug: CCCOM currently doesn't honor CFLAGS, only CCFLAGS env.Replace( VERSION=VERSION @@ -73,7 +74,6 @@ def setupBasicEnvironment(): , CPPDEFINES=['-DLUMIERA_VERSION='+VERSION ] # note: it's a list to append further defines , CCFLAGS='-Wall ' # -fdiagnostics-show-option ) - RegisterIcon_Builder(env,SVGRENDERER) handleNoBugSwitches(env) @@ -113,6 +113,15 @@ def handleNoBugSwitches(env): elif level == 'RELEASE': env.Replace( DEBUG = 0 ) +def handleVerboseMessages(env): + """ toggle verbose build output """ + if not env['VERBOSE']: + # SetOption('silent', True) + env['CCCOMSTR'] = " Compiling $SOURCE" + env['CXXCOMSTR'] = " Compiling++ $SOURCE" + env['LINKCOMSTR'] = " Linking --> $TARGET" + env['LDMODULECOMSTR'] = " creating module [ $TARGET ]" + @@ -129,6 +138,7 @@ def defineCmdlineOptions(): ,BoolOption('DEBUG', 'Build with debugging information and no optimizations', False) ,BoolOption('OPTIMIZE', 'Build with strong optimization (-O3)', False) ,BoolOption('VALGRIND', 'Run Testsuite under valgrind control', True) + ,BoolOption('VERBOSE', 'Print full build commands', False) ,('TESTSUITES', 'Run only Testsuites matching the given pattern', '') # ,BoolOption('OPENGL', 'Include support for OpenGL preview rendering', False) # ,EnumOption('DIST_TARGET', 'Build target architecture', 'auto', @@ -153,7 +163,7 @@ Special Targets: build : just compile and link testcode: additionally compile the Testsuite check : build and run the Testsuite - doc : generate documetation (Doxygen) + doc : generate documentation (Doxygen) install : install created artifacts at PREFIX src.tar : create source tarball doc.tar : create developer doc tarball @@ -302,7 +312,7 @@ def defineBuildTargets(env, artifacts): artifacts['lumiera'] = env.Program('$BINDIR/lumiera', ['$SRCDIR/main.cpp']+ core ) - artifacts['plugins'] = env.SharedLibrary('$BINDIR/lumiera-plugin', objplug) + artifacts['plugins'] = env.LoadableModule('$BINDIR/lumiera-plugin', objplug) # the Lumiera GTK GUI envgtk = env.Clone().mergeConf(['gtkmm-2.4','cairomm-1.0','gdl-1.0','librsvg-2.0','xv','xext','sm']) diff --git a/tests/SConscript b/tests/SConscript index d28b70218..901c2280c 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -52,7 +52,7 @@ def treatPluginTestcase(env): prfx = path.join(tree,'example_plugin') oC = env.SharedObject(prfx, prfx+'.c') oCPP = env.SharedObject(prfx+'_cpp', prfx+'.cpp') - testplugin = ( env.SharedLibrary('#$BINDIR/.libs/examplepluginc', oC, SHLIBPREFIX='') + testplugin = ( env.LoadableModule('#$BINDIR/.libs/examplepluginc', oC, SHLIBPREFIX='') # doesn't compile yet... # + env.SharedLibrary('#$BINDIR/.libs/exampleplugincpp', oCPP, SHLIBPREFIX='') From b0b29e86a45e04991a9602a628cb37f5f2699cba Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 3 Nov 2008 21:27:03 +0100 Subject: [PATCH 053/249] forgot to add some UML --- doc/devel/uml/class144773.html | 25 ++++++ doc/devel/uml/class144901.html | 20 +++++ doc/devel/uml/class145029.html | 20 +++++ doc/devel/uml/class145157.html | 22 +++++ doc/devel/uml/class145285.html | 20 +++++ doc/devel/uml/class145413.html | 20 +++++ doc/devel/uml/class145541.html | 27 ++++++ doc/devel/uml/class145669.html | 24 ++++++ doc/devel/uml/class145797.html | 24 ++++++ doc/devel/uml/class145925.html | 23 +++++ doc/devel/uml/class146053.html | 24 ++++++ doc/devel/uml/class146181.html | 23 +++++ doc/devel/uml/class146309.html | 26 ++++++ doc/devel/uml/class146437.html | 24 ++++++ uml/lumiera/132741.diagram | 153 +++++++++++++++++++++++++++++++++ 15 files changed, 475 insertions(+) create mode 100644 doc/devel/uml/class144773.html create mode 100644 doc/devel/uml/class144901.html create mode 100644 doc/devel/uml/class145029.html create mode 100644 doc/devel/uml/class145157.html create mode 100644 doc/devel/uml/class145285.html create mode 100644 doc/devel/uml/class145413.html create mode 100644 doc/devel/uml/class145541.html create mode 100644 doc/devel/uml/class145669.html create mode 100644 doc/devel/uml/class145797.html create mode 100644 doc/devel/uml/class145925.html create mode 100644 doc/devel/uml/class146053.html create mode 100644 doc/devel/uml/class146181.html create mode 100644 doc/devel/uml/class146309.html create mode 100644 doc/devel/uml/class146437.html create mode 100644 uml/lumiera/132741.diagram diff --git a/doc/devel/uml/class144773.html b/doc/devel/uml/class144773.html new file mode 100644 index 000000000..86e164da0 --- /dev/null +++ b/doc/devel/uml/class144773.html @@ -0,0 +1,25 @@ + + + + + + +Class StreamType + + + + + +
                                                                                                                                                                                                                                      Class StreamType
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class StreamType

                                                                                                                                                                                                                                      Artifact : streamtype

                                                                                                                                                                                                                                      + +
                                                                                                                                                                                                                                      Relation <unidirectional association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation <unidirectional association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation <unidirectional association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      + + diff --git a/doc/devel/uml/class144901.html b/doc/devel/uml/class144901.html new file mode 100644 index 000000000..59beaefed --- /dev/null +++ b/doc/devel/uml/class144901.html @@ -0,0 +1,20 @@ + + + + + + +Class Prototype + + + + + +
                                                                                                                                                                                                                                      Class Prototype
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class Prototype

                                                                                                                                                                                                                                      Artifact : streamtype

                                                                                                                                                                                                                                      + diff --git a/doc/devel/uml/class145029.html b/doc/devel/uml/class145029.html new file mode 100644 index 000000000..13e240717 --- /dev/null +++ b/doc/devel/uml/class145029.html @@ -0,0 +1,20 @@ + + + + + + +Class ImplFacade + + + + + +
                                                                                                                                                                                                                                      Class ImplFacade
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class ImplFacade

                                                                                                                                                                                                                                      Artifact : streamtype

                                                                                                                                                                                                                                      + diff --git a/doc/devel/uml/class145157.html b/doc/devel/uml/class145157.html new file mode 100644 index 000000000..ca22769ab --- /dev/null +++ b/doc/devel/uml/class145157.html @@ -0,0 +1,22 @@ + + + + + + +Class StreamTypeID + + + + + +
                                                                                                                                                                                                                                      Class StreamTypeID
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class StreamTypeID
                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      + + diff --git a/doc/devel/uml/class145285.html b/doc/devel/uml/class145285.html new file mode 100644 index 000000000..914d312aa --- /dev/null +++ b/doc/devel/uml/class145285.html @@ -0,0 +1,20 @@ + + + + + + +Class MediaKind + + + + + +
                                                                                                                                                                                                                                      Class MediaKind
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : enum MediaKind
                                                                                                                                                                                                                                      • Java : package enum MediaKind
                                                                                                                                                                                                                                      + diff --git a/doc/devel/uml/class145413.html b/doc/devel/uml/class145413.html new file mode 100644 index 000000000..fa26d80d8 --- /dev/null +++ b/doc/devel/uml/class145413.html @@ -0,0 +1,20 @@ + + + + + + +Class STypeManager + + + + + +
                                                                                                                                                                                                                                      Class STypeManager
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class STypeManager

                                                                                                                                                                                                                                      Artifact : stypemanager

                                                                                                                                                                                                                                      + diff --git a/doc/devel/uml/class145541.html b/doc/devel/uml/class145541.html new file mode 100644 index 000000000..06bd62289 --- /dev/null +++ b/doc/devel/uml/class145541.html @@ -0,0 +1,27 @@ + + + + + + +Class Timeline + + + + + +
                                                                                                                                                                                                                                      Class Timeline
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class Timeline

                                                                                                                                                                                                                                      Directly inherited by : TimelineView

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      + +
                                                                                                                                                                                                                                      Relation <aggregation by value>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation <unidirectional association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation <unidirectional association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation globalBusses (<directional aggregation by value>)

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • Uml : # globalBusses : Pipe, multiplicity : *
                                                                                                                                                                                                                                      • C++ : protected: Pipe globalBusses
                                                                                                                                                                                                                                      + + diff --git a/doc/devel/uml/class145669.html b/doc/devel/uml/class145669.html new file mode 100644 index 000000000..d2fb577a5 --- /dev/null +++ b/doc/devel/uml/class145669.html @@ -0,0 +1,24 @@ + + + + + + +Class Project + + + + + +
                                                                                                                                                                                                                                      Class Project
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class Project
                                                                                                                                                                                                                                      + +
                                                                                                                                                                                                                                      Relation <aggregation by value>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation <aggregation by value>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      + + diff --git a/doc/devel/uml/class145797.html b/doc/devel/uml/class145797.html new file mode 100644 index 000000000..d5a2b67c9 --- /dev/null +++ b/doc/devel/uml/class145797.html @@ -0,0 +1,24 @@ + + + + + + +Class TimelineView + + + + + +
                                                                                                                                                                                                                                      Class TimelineView
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class TimelineView : public Timeline
                                                                                                                                                                                                                                      + +
                                                                                                                                                                                                                                      Relation <unidirectional association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation <association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      + + diff --git a/doc/devel/uml/class145925.html b/doc/devel/uml/class145925.html new file mode 100644 index 000000000..ae3ae19c7 --- /dev/null +++ b/doc/devel/uml/class145925.html @@ -0,0 +1,23 @@ + + + + + + +Class PlayControl + + + + + +
                                                                                                                                                                                                                                      Class PlayControl
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class PlayControl
                                                                                                                                                                                                                                      + +
                                                                                                                                                                                                                                      Relation <unidirectional association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      + + diff --git a/doc/devel/uml/class146053.html b/doc/devel/uml/class146053.html new file mode 100644 index 000000000..d2e874de1 --- /dev/null +++ b/doc/devel/uml/class146053.html @@ -0,0 +1,24 @@ + + + + + + +Class Monitor + + + + + +
                                                                                                                                                                                                                                      Class Monitor
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class Monitor
                                                                                                                                                                                                                                      + +
                                                                                                                                                                                                                                      Relation <unidirectional association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation <association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      + + diff --git a/doc/devel/uml/class146181.html b/doc/devel/uml/class146181.html new file mode 100644 index 000000000..31c08ed9c --- /dev/null +++ b/doc/devel/uml/class146181.html @@ -0,0 +1,23 @@ + + + + + + +Class RenderTask + + + + + +
                                                                                                                                                                                                                                      Class RenderTask
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class RenderTask
                                                                                                                                                                                                                                      + +
                                                                                                                                                                                                                                      Relation <unidirectional association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      + + diff --git a/doc/devel/uml/class146309.html b/doc/devel/uml/class146309.html new file mode 100644 index 000000000..485390623 --- /dev/null +++ b/doc/devel/uml/class146309.html @@ -0,0 +1,26 @@ + + + + + + +Class Sequence + + + + + +
                                                                                                                                                                                                                                      Class Sequence
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class Sequence
                                                                                                                                                                                                                                      + +
                                                                                                                                                                                                                                      Relation <aggregation by value>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation subSequences (<unidirectional association>)

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • Uml : # subSequences : Sequence, multiplicity : *
                                                                                                                                                                                                                                      • C++ : protected: Sequence* subSequences
                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation <unidirectional association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation trackTree (<unidirectional association>)

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • Uml : # trackTree : Track, multiplicity : 1
                                                                                                                                                                                                                                      • C++ : protected: Track* trackTree
                                                                                                                                                                                                                                      + + diff --git a/doc/devel/uml/class146437.html b/doc/devel/uml/class146437.html new file mode 100644 index 000000000..57ebd91f2 --- /dev/null +++ b/doc/devel/uml/class146437.html @@ -0,0 +1,24 @@ + + + + + + +Class PlayheadCursor + + + + + +
                                                                                                                                                                                                                                      Class PlayheadCursor
                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                      + + + + +

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      • C++ : class PlayheadCursor
                                                                                                                                                                                                                                      + +
                                                                                                                                                                                                                                      Relation <association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      Relation <association>

                                                                                                                                                                                                                                      Declaration :

                                                                                                                                                                                                                                      + + diff --git a/uml/lumiera/132741.diagram b/uml/lumiera/132741.diagram new file mode 100644 index 000000000..c3a8d44f4 --- /dev/null +++ b/uml/lumiera/132741.diagram @@ -0,0 +1,153 @@ +format 40 + +classcanvas 128005 class_ref 145669 // Project + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 161 115 2000 + end +classcanvas 128133 class_ref 145541 // Timeline + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 177 222 2000 + end +classcanvas 128261 class_ref 145797 // TimelineView + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 163 323 2000 + end +classcanvas 128645 class_ref 145925 // PlayControl + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 315 223 2000 + end +classcanvas 128773 class_ref 146053 // Monitor + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 456 90 2000 + end +classcanvas 128901 class_ref 146181 // RenderTask + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 456 32 2000 + end +classcanvas 129029 class_ref 146309 // Sequence + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 41 323 2000 + end +classcanvas 130437 class_ref 138117 // Pipe + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 317 294 2000 + end +classcanvas 132101 class_ref 146437 // PlayheadCursor + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 452 222 2000 + end +classcanvas 132997 class_ref 128389 // Track + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 99 611 2000 + end +classcanvas 133125 class_ref 128517 // MObject + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 163 485 2000 + end +classcanvas 133253 class_ref 129029 // Effect + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 211 611 2000 + end +classcanvas 133381 class_ref 129669 // Label + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 259 611 2000 + end +classcanvas 133509 class_ref 128901 // Clip + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 163 611 2000 + end +relationcanvas 128389 relation_ref 154757 // + from ref 128261 z 1999 to ref 128133 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 129157 relation_ref 154885 // + from ref 128005 z 1999 to ref 128133 + no_role_a no_role_b + multiplicity_a_pos 173 197 3000 multiplicity_b_pos 173 166 3000 +relationcanvas 129285 relation_ref 155013 // + from ref 128133 z 1999 stereotype "<>" xyz 251 226 3000 to ref 128645 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 129413 relation_ref 155141 // + geometry VHr + from ref 128005 z 1999 to point 71 134 + line 129541 z 1999 to ref 129029 + no_role_a no_role_b + multiplicity_a_pos 47 298 3000 multiplicity_b_pos 144 145 3000 +relationcanvas 129669 relation_ref 155269 // + from ref 128133 z 1999 to ref 129029 + no_role_a no_role_b + multiplicity_a_pos 113 322 3000 no_multiplicity_b +relationcanvas 129797 relation_ref 155397 // + from ref 128261 z 1999 to ref 129029 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 129925 relation_ref 155525 // + from ref 129029 z 1999 stereotype "<>" xyz 33 389 3000 to point 71 387 + line 130309 z 1999 to point 46 387 + line 130181 z 1999 to ref 129029 + role_a_pos 23 401 3000 no_role_b + multiplicity_a_pos 42 369 3000 multiplicity_b_pos 75 369 3000 +relationcanvas 130565 relation_ref 155653 // + from ref 128133 z 1999 stereotype "<>" xyz 265 265 3000 to point 263 281 + line 131077 z 1999 to point 303 281 + line 131205 z 1999 to ref 130437 + role_a_pos 242 280 3000 no_role_b + multiplicity_a_pos 322 279 3000 multiplicity_b_pos 237 268 3000 +relationcanvas 131589 relation_ref 155781 // + from ref 128773 z 1999 stereotype "<>" xyz 274 147 3000 to point 282 172 + line 131845 z 1999 to ref 128133 + no_role_a no_role_b + multiplicity_a_pos 221 180 3000 no_multiplicity_b +relationcanvas 131717 relation_ref 155909 // + from ref 128901 z 1999 to point 272 156 + line 131973 z 1999 to ref 128133 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 132229 relation_ref 156037 // + from ref 128645 z 1999 stereotype "<>" xyz 391 226 3000 to ref 132101 + no_role_a no_role_b + multiplicity_a_pos 436 247 3000 no_multiplicity_b +relationcanvas 132357 relation_ref 156165 // + from ref 128773 z 1999 to ref 132101 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 132485 relation_ref 156293 // + from ref 128261 z 1999 to point 478 341 + line 132613 z 1999 to ref 132101 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 133765 relation_ref 156421 // + from ref 133509 z 1999 to ref 133125 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 133893 relation_ref 156549 // + from ref 133253 z 1999 to ref 133125 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 134021 relation_ref 156677 // + from ref 133381 z 1999 to ref 133125 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 134149 relation_ref 156805 // + from ref 132997 z 1999 to ref 133125 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 134405 relation_ref 156933 // + from ref 129029 z 1999 to point 99 363 + line 134533 z 1999 to ref 133125 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 134661 relation_ref 157061 // + from ref 129029 z 1999 to point 99 364 + line 134789 z 1999 to point 118 463 + line 134917 z 1999 to ref 132997 + role_a_pos 68 538 3000 no_role_b + multiplicity_a_pos 104 586 3000 no_multiplicity_b +relationcanvas 135045 relation_ref 145029 // + from ref 132997 z 1999 stereotype "<>" xyz 35 599 3000 to point 70 630 + line 135173 z 1999 to point 70 661 + line 135301 z 1999 to ref 132997 + role_a_pos 37 612 3000 no_role_b + multiplicity_a_pos 91 657 3000 no_multiplicity_b +end From 4d2fe242d0f42ed320a006f27e4fe66ea658cf35 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 4 Nov 2008 07:50:42 +0100 Subject: [PATCH 054/249] Some more interfaces improvements * add a lumiera_interface_version() function for runtime type and version checking of interfaces * the 'lumieraorg__plugin' interface is now private * add a macro to construct a interface instance name string --- src/backend/interface.c | 10 ++++++++++ src/backend/interface.h | 26 ++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/backend/interface.c b/src/backend/interface.c index 917c663d9..26fa3a42e 100644 --- a/src/backend/interface.c +++ b/src/backend/interface.c @@ -229,6 +229,16 @@ lumiera_interface_close (LumieraInterface self) } +unsigned +lumiera_interface_version (LumieraInterface self, const char* iname) +{ + if (self && iname && !strcmp (self->interface, iname)) + return self->version; + + return ~0; +} + + /* internal function, does no locking! */ static void lumiera_interfacenode_close (LumieraInterfacenode self) diff --git a/src/backend/interface.h b/src/backend/interface.h index 7b97fd82e..222fbbc62 100644 --- a/src/backend/interface.h +++ b/src/backend/interface.h @@ -102,9 +102,18 @@ * @param iname name of the interface * @param version major version of the interface * @param dname name for the instance + * @return constructed identifier */ -#define LUMIERA_INTERFACE_DNAME(iname, version, dname) PPMPL_CAT (LUMIERA_INTERFACE_INAME(iname, version), _##dname) +#define LUMIERA_INTERFACE_DNAME(iname, version, dname) PPMPL_CAT (LUMIERA_INTERFACE_INAME (iname, version), _##dname) +/** + * Construct a definition string r for an interface + * @param iname name of the interface + * @param version major version of the interface + * @param dname name for the instance + * @return constructed string + */ +#define LUMIERA_INTERFACE_DSTRING(iname, version, dname) PPMPL_STRINGIFY (LUMIERA_INTERFACE_DNAME (iname, version, dname)) /** * Return a reference (pointer) to an interface implementation @@ -293,7 +302,7 @@ queryfunc (void) \ */ #define LUMIERA_PLUGIN(acquire, release, luid, ...) \ LUMIERA_EXPORT(plugin_interfaces, __VA_ARGS__) \ -LUMIERA_INTERFACE_INSTANCE (lumieraorg_plugin, 0, \ +LUMIERA_INTERFACE_INSTANCE (lumieraorg__plugin, 0, \ lumieraorg_plugin, \ NULL, \ acquire, \ @@ -374,7 +383,7 @@ struct lumiera_interface_struct /** * Plugin interface */ -LUMIERA_INTERFACE_DECLARE (lumieraorg_plugin, 0, +LUMIERA_INTERFACE_DECLARE (lumieraorg__plugin, 0, LUMIERA_INTERFACE_SLOT (LumieraInterface*, plugin_interfaces, (void)), ); @@ -402,7 +411,16 @@ lumiera_interface_open (const char* interface, unsigned version, size_t minminor * consider 'self' to be invalidated after this call */ void -lumiera_interface_close (LumieraInterface iface); +lumiera_interface_close (LumieraInterface self); + +/** + * Runtime check for interface type and version + * @param self interface to check + * @param iname name of the interface + * @return version of the interface or ~0 (-1) if iname doesn't match the requested name + */ +unsigned +lumiera_interface_version (LumieraInterface self, const char* iname); #endif /* LUMIERA_INTERFACE_H */ From c30c98bebd4d4951e26f75f4ed2e9b0fc5f34aca Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 5 Nov 2008 11:07:49 +0100 Subject: [PATCH 055/249] add a LUMIERA_INTERFACE_CLOSE macro This is a small typesafe wrapper around the interface_close() function and since we need INTERFACE_OPEN wraped too this makes it more orthogonal --- src/backend/interface.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backend/interface.h b/src/backend/interface.h index 222fbbc62..c84238d1c 100644 --- a/src/backend/interface.h +++ b/src/backend/interface.h @@ -320,6 +320,9 @@ LUMIERA_INTERFACE_INSTANCE (lumieraorg__plugin, 0, #define LUMIERA_INTERFACE_OPEN(interface, version, minminor, name) \ LUMIERA_INTERFACE_CAST(interface, version) lumiera_interface_open (#interface, version, minminor, #name) +#define LUMIERA_INTERFACE_CLOSE(handle) \ + lumiera_interface_close (&(handle)->interface_header_) + typedef struct lumiera_interfaceslot_struct lumiera_interfaceslot; typedef lumiera_interfaceslot* LumieraInterfaceslot; From 7c2415838b95f92d2f16c94bebf913d4f7d4d846 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 4 Nov 2008 08:03:18 +0100 Subject: [PATCH 056/249] WIP: big plugin update * fix configure.ac to check for dlopen, introduce $(LUMIERA_PLUGIN_LIBS) * Generic pluginloader finished, all plugins get loaded and registered at start for now, it is prepared for on-demand loading and unloading but not implemented because that needs the plugindb. - plugin unloading not yet finished, this asserts at the end --- configure.ac | 5 + src/backend/Makefile.am | 1 + src/backend/plugin.c | 223 +++++++++++++++++++++++++++------------- src/backend/plugin.h | 19 +++- 4 files changed, 171 insertions(+), 77 deletions(-) diff --git a/configure.ac b/configure.ac index ae9f0d79b..4f705e01b 100644 --- a/configure.ac +++ b/configure.ac @@ -87,6 +87,10 @@ AC_LANG_PUSH([C]) AC_CHECK_HEADER([execinfo.h], AC_DEFINE(HAVE_EXECINFO_H)) # there is a warning in nobug, disabled til fixed AC_CHECK_HEADER([valgrind/valgrind.h], AC_DEFINE(HAVE_VALGRIND_VALGRIND_H)) +AC_CHECK_LIB(dl, dlopen, [LUMIERA_PLUGIN_LIBS="$LUMIERA_PLUGIN_LIBS -ldl"], + [AC_MSG_ERROR([Dynamic linking not supported, report a bug])] +) + AC_LANG_POP([C]) @@ -160,6 +164,7 @@ AC_CHECK_LIB(Xv, XvQueryAdaptors, [LUMIERA_GUI_LIBS="$LUMIERA_GUI_LIBS -lXv"], # END X11 Dependancies +AC_SUBST(LUMIERA_PLUGIN_LIBS) AC_SUBST(LUMIERA_GUI_CFLAGS) AC_SUBST(LUMIERA_GUI_LIBS) diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index be9b9cd90..d8c0c159e 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -30,6 +30,7 @@ liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/interface.c \ $(liblumibackend_a_srcdir)/interfaceregistry.c \ $(liblumibackend_a_srcdir)/plugin.c \ + $(liblumibackend_a_srcdir)/plugin_dynlib.c \ $(liblumibackend_a_srcdir)/config.c \ $(liblumibackend_a_srcdir)/config_typed.c \ $(liblumibackend_a_srcdir)/config_wordlist.c \ diff --git a/src/backend/plugin.c b/src/backend/plugin.c index 1b708c6be..66ebd345c 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -18,6 +18,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + #include "lib/safeclib.h" #include "lib/psplay.h" #include "lib/mutex.h" @@ -41,40 +43,56 @@ extern PSplay lumiera_pluginregistry; /* TODO should be set by the build system to the actual plugin path */ /* errors */ +LUMIERA_ERROR_DEFINE(PLUGIN_INIT, "Initialization error"); LUMIERA_ERROR_DEFINE(PLUGIN_DLOPEN, "Could not open plugin"); +LUMIERA_ERROR_DEFINE(PLUGIN_WTF, "Not a Lumiera plugin"); +LUMIERA_ERROR_DEFINE(PLUGIN_REGISTER, "Could not register plugin"); +LUMIERA_ERROR_DEFINE(PLUGIN_VERSION, "Plugin Version unsupported"); -/* - supported (planned) plugin types and their file extensions -*/ +#define LUMIERA_PLUGIN_TYPE_PLANNED(name, ext) -#define LUMIERA_PLUGIN_TYPES \ - LUMIERA_PLUGIN_TYPE(DYNLIB, ".so") +/** + * Supported (and planned) plugin types and their file extensions + * This maps filename extensions to implementations (of the respective _load_NAME and _unload_NAME functions) + * So far we only support platform dynamic libraries, later we may add plugins implemented in lua + * and c source modules which get compiled on the fly. + */ +#define LUMIERA_PLUGIN_TYPES \ + LUMIERA_PLUGIN_TYPE_PLANNED(DYNLIB, ".so") \ + LUMIERA_PLUGIN_TYPE_PLANNED(DYNLIB, ".lum") \ + LUMIERA_PLUGIN_TYPE_PLANNED(LUA, ".lua") \ + LUMIERA_PLUGIN_TYPE_PLANNED(CSOURCE, ".c") -/* - only .so dynlibs for now, later we may support some more - LUMIERA_PLUGIN_TYPE(LUA, ".lua") - LUMIERA_PLUGIN_TYPE(CSOURCE, ".c") -*/ -#define LUMIERA_PLUGIN_TYPE(type, ext) LUMIERA_PLUGIN_##type, -enum lumiera_plugin_type - { - LUMIERA_PLUGIN_TYPES - LUMIERA_PLUGIN_NONE - }; +/** + * record the extension and a callback function for loading the associated plugin for each plugin type + */ +struct lumiera_plugintype_struct +{ + LumieraPlugin (*lumiera_plugin_load_fn)(const char*); + void (*lumiera_plugin_unload_fn)(LumieraPlugin); + const char* ext; +}; +typedef struct lumiera_plugintype_struct lumiera_plugintype; +typedef lumiera_plugintype* LumieraPlugintype; + +/* forward declare loader functions for all types */ +#define LUMIERA_PLUGIN_TYPE(type, ext) \ + LumieraPlugin lumiera_plugin_load_##type (const char*); \ + void lumiera_plugin_unload_##type (LumieraPlugin); +LUMIERA_PLUGIN_TYPES #undef LUMIERA_PLUGIN_TYPE -#define LUMIERA_PLUGIN_TYPE(type, ext) ext, -static const char* const lumiera_plugin_ext[] = +/* and now setup a table which will be used for dispatching loaders depending on the type of the plugin */ +#define LUMIERA_PLUGIN_TYPE(type, ext) {lumiera_plugin_load_##type, lumiera_plugin_unload_##type, ext}, +static lumiera_plugintype lumiera_plugin_types[] = { LUMIERA_PLUGIN_TYPES - NULL + {NULL, NULL, NULL} }; #undef LUMIERA_PLUGIN_TYPE - - struct lumiera_plugin_struct { psplaynode node; @@ -88,14 +106,46 @@ struct lumiera_plugin_struct /* time when the last open or close action happened */ time_t last; - /* kind of plugin */ - enum lumiera_plugin_type type; + /* when loading plugins en masse we do not want to fail completely if one doesnt cooperate, instead we record local errors here */ + lumiera_err error; - /* dlopen handle */ + /* the 'plugin' interface itself */ + LumieraInterface plugin; + + /* generic handle for the plugin, dlopen handle, etc */ void* handle; }; +LumieraPlugin +lumiera_plugin_new (const char* name) +{ + LumieraPlugin self = lumiera_malloc (sizeof (*self)); + + psplaynode_init (&self->node); + self->name = lumiera_strndup (name, SIZE_MAX); + self->refcnt = 0; + time (&self->last); + self->error = LUMIERA_ERROR_PLUGIN_INIT; + self->plugin = NULL; + self->handle = NULL; + return self; +} + + +LumieraPlugin +lumiera_plugin_init (LumieraPlugin self, void* handle, LumieraInterface plugin) +{ + self->error = lumiera_error (); + self->plugin = plugin; + self->handle = handle; + return self; +} + + + + +static char* init_exts_globs (); int lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), @@ -108,30 +158,7 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), /* construct glob trail {.so,.c,.foo} ... */ static char* exts_globs = NULL; if (!exts_globs) - { - size_t exts_sz = 4; /* / * { } \0 less one comma */ - const char*const* itr = lumiera_plugin_ext; - while (*itr) - { - exts_sz += strlen (*itr) + 1; - ++itr; - } - - exts_globs = lumiera_malloc (exts_sz); - *exts_globs = '\0'; - - itr = lumiera_plugin_ext; - strcat (exts_globs, "/*{"); - - while (*itr) - { - strcat (exts_globs, *itr); - strcat (exts_globs, ","); - ++itr; - } - exts_globs[exts_sz-2] = '}'; - TRACE (plugin, "initialized extension glob to '%s'", exts_globs); - } + exts_globs = init_exts_globs (&exts_globs); const char* path; unsigned i = 0; @@ -150,21 +177,18 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), ++i; } - LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) - { - for (char** itr = globs.gl_pathv; *itr; ++itr) - { - - if (!psplay_find (lumiera_pluginregistry, *itr, 100)) - { - TRACE (plugin, "found new plugin '%s'", *itr); - - LumieraPlugin plugin = callback_load (*itr); - if (plugin) - callback_register (plugin); - } - } - } + if (globs.gl_pathc) + LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) + { + for (char** itr = globs.gl_pathv; *itr; ++itr) + { + if (!psplay_find (lumiera_pluginregistry, *itr, 100)) + { + TRACE (plugin, "found new plugin '%s'", *itr); + callback_register (callback_load (*itr)); + } + } + } globfree (&globs); @@ -172,37 +196,90 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), } - - - LumieraPlugin lumiera_plugin_load (const char* plugin) { TRACE (plugin); - UNIMPLEMENTED(); - (void) plugin; + /* dispatch on ext, call the registered function */ + const char* ext = strrchr (plugin, '.'); + + LumieraPlugintype itr = lumiera_plugin_types; + while (itr->ext) + { + if (!strcmp (itr->ext, ext)) + return itr->lumiera_plugin_load_fn (plugin); + ++itr; + } return NULL; } - int lumiera_plugin_register (LumieraPlugin plugin) { TRACE (plugin); - UNIMPLEMENTED(); + if (!plugin) + return 1; LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) { - (void) plugin; - + if (psplay_insert (lumiera_pluginregistry, &plugin->node, 100)) + { + if (!plugin->error) + { + switch (lumiera_interface_version (plugin->plugin, "lumieraorg__plugin")) + { + case 0: + { + TRACE (plugin, "registering %s", plugin->name); + LUMIERA_INTERFACE_HANDLE(lumieraorg__plugin, 0) handle = + LUMIERA_INTERFACE_CAST(lumieraorg__plugin, 0) plugin->plugin; + lumiera_interfaceregistry_bulkregister_interfaces (handle->plugin_interfaces (), plugin); + } + break; + default: + LUMIERA_ERROR_SET (plugin, PLUGIN_VERSION); + } + } + } + else + { + LUMIERA_ERROR_SET (plugin, PLUGIN_REGISTER); + } } - return 0; + return !!lumiera_error_peek(); } +static char* init_exts_globs () +{ + char* exts_globs; + size_t exts_sz = 4; /* / * { } \0 less one comma */ + LumieraPlugintype itr = lumiera_plugin_types; + while (itr->ext) + { + exts_sz += strlen (itr->ext) + 1; + ++itr; + } + + exts_globs = lumiera_malloc (exts_sz); + *exts_globs = '\0'; + + itr = lumiera_plugin_types; + strcat (exts_globs, "/*{"); + + while (itr->ext) + { + strcat (exts_globs, itr->ext); + strcat (exts_globs, ","); + ++itr; + } + exts_globs[exts_sz-2] = '}'; + TRACE (plugin, "initialized extension glob to '%s'", exts_globs); + return exts_globs; +} int lumiera_plugin_cmp_fn (const void* keya, const void* keyb) diff --git a/src/backend/plugin.h b/src/backend/plugin.h index 8c0e5e7ae..03b963990 100644 --- a/src/backend/plugin.h +++ b/src/backend/plugin.h @@ -21,12 +21,14 @@ #ifndef LUMIERA_PLUGIN_H #define LUMIERA_PLUGIN_H +#include "lib/psplay.h" +#include "lib/error.h" + +#include "backend/interface.h" #include #include -#include "lib/error.h" - /** * @file * Lumiera plugins defines 'interfaces' as shown in interface.h, the plugin system handles the loading @@ -35,8 +37,11 @@ */ +LUMIERA_ERROR_DECLARE(PLUGIN_INIT); LUMIERA_ERROR_DECLARE(PLUGIN_DLOPEN); -LUMIERA_ERROR_DECLARE(PLUGIN_PLUGINPATH); +LUMIERA_ERROR_DECLARE(PLUGIN_WTF); +LUMIERA_ERROR_DECLARE(PLUGIN_REGISTER); +LUMIERA_ERROR_DECLARE(PLUGIN_VERSION); NOBUG_DECLARE_FLAG (plugin); @@ -47,6 +52,7 @@ NOBUG_DECLARE_FLAG (plugin); struct lumiera_plugin_struct; typedef struct lumiera_plugin_struct lumiera_plugin; typedef lumiera_plugin* LumieraPlugin; +enum lumiera_plugin_type; int @@ -55,6 +61,11 @@ lumiera_plugin_cmp_fn (const void* keya, const void* keyb); const void* lumiera_plugin_key_fn (const PSplaynode node); +LumieraPlugin +lumiera_plugin_new (const char* name); + +LumieraPlugin +lumiera_plugin_init (LumieraPlugin self, void* handle, LumieraInterface plugin); LumieraPlugin lumiera_plugin_load (const char* plugin); @@ -68,7 +79,7 @@ lumiera_plugin_register (LumieraPlugin); /** * discover new plugins - * traverses the configured plugin dirs and calls the callback_load function for any plugin + * traverses the configured plugin paths and calls the callback_load function for any plugin * not actually loaded. If callback_load returns a plugin (and not NULL) then this is feed to * the callback_register function. */ From 3155ae068f65c156705528eb60b77585aeead9ac Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 4 Nov 2008 08:05:53 +0100 Subject: [PATCH 057/249] Loading of dynamic modules * loads dynamic libs as module. * file extensions .so and .lum (LUmieraModule) - no unloading yet --- src/backend/plugin.c | 4 +-- src/backend/plugin_dynlib.c | 58 +++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 src/backend/plugin_dynlib.c diff --git a/src/backend/plugin.c b/src/backend/plugin.c index 66ebd345c..264cc8df5 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -58,8 +58,8 @@ LUMIERA_ERROR_DEFINE(PLUGIN_VERSION, "Plugin Version unsupported"); * and c source modules which get compiled on the fly. */ #define LUMIERA_PLUGIN_TYPES \ - LUMIERA_PLUGIN_TYPE_PLANNED(DYNLIB, ".so") \ - LUMIERA_PLUGIN_TYPE_PLANNED(DYNLIB, ".lum") \ + LUMIERA_PLUGIN_TYPE(DYNLIB, ".so") \ + LUMIERA_PLUGIN_TYPE(DYNLIB, ".lum") \ LUMIERA_PLUGIN_TYPE_PLANNED(LUA, ".lua") \ LUMIERA_PLUGIN_TYPE_PLANNED(CSOURCE, ".c") diff --git a/src/backend/plugin_dynlib.c b/src/backend/plugin_dynlib.c new file mode 100644 index 000000000..62b105078 --- /dev/null +++ b/src/backend/plugin_dynlib.c @@ -0,0 +1,58 @@ +/* + plugin_dynlib.c - Lumiera Plugin loader for dynamic libraries + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + 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. +*/ +#include "backend/plugin.h" + +#include +#include + +/** + * @file + * Plugin loader for dynamic libraries. + */ + +LumieraPlugin +lumiera_plugin_load_DYNLIB (const char* name) +{ + TRACE (plugin); + LumieraPlugin self = lumiera_plugin_new (name); + LumieraInterface plugin = NULL; + + void* handle = dlopen (name, RTLD_LAZY|RTLD_LOCAL); + if (handle) + { + plugin = (LumieraInterface) dlsym (handle, LUMIERA_INTERFACE_DSTRING (lumieraorg__plugin, 0, lumieraorg_plugin)); + + if (!plugin) + LUMIERA_ERROR_SET (plugin, PLUGIN_WTF); + } + else + LUMIERA_ERROR_SET (plugin, PLUGIN_DLOPEN); + + return lumiera_plugin_init (self, handle, plugin); +} + + +void +lumiera_plugin_unload_DYNLIB (LumieraPlugin self) +{ + (void) self; + UNIMPLEMENTED(); +} From 2646b9035b50e6c1394333051f8e17a65d0110a4 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 5 Nov 2008 05:33:37 +0100 Subject: [PATCH 058/249] some plugin docwork --- src/backend/plugin.h | 93 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 20 deletions(-) diff --git a/src/backend/plugin.h b/src/backend/plugin.h index 03b963990..fe2204596 100644 --- a/src/backend/plugin.h +++ b/src/backend/plugin.h @@ -32,8 +32,28 @@ /** * @file * Lumiera plugins defines 'interfaces' as shown in interface.h, the plugin system handles the loading - * of all kinds of plugins under the hood, invoked from the interface system. Anything defined here is - * called internally and should not be used by other parts of the application. + * of all kinds of plugins under the hood, invoked from the interface system. Most things defined here + * are called internally and should not be used by other parts of the application. + * + * Plugin discovery + * The plugin_discover() function offers a automatic way to load and register new plugins. It traverses + * all configured plugin directories. It takes to function for loading and registering plugins as + * parameter, by now this only uses the here defined plugin_load() and plugin_register() functions + * which lets it load any newly found plugin unconditionally. Later these callbacks will be replaced by + * a smarter system (plugindb) which makes it possible to load plugins on-demand and select proper + * plugins based on their version and capabilities. + * + * Plugin loading + * Plugins are loaded and initialized in a sequence of steps: + * plugin_load() dispatches to a specific loader function depending on the type (extension) of a plugin. + * This loader allocates a new plugin structure with plugin_new() and then does it work and eventually + * finalizing the plugin structure initialization with plugin_init() by providing a handle to a + * lumieraorg__plugin interface. plugin_init() also stores the current error state (which might be clean) + * into the plugin. After that the plugin can be registered which records it in the pluginregistry and if + * its error state is clean, registering all interfaces it offers in the interface registry. With that + * the plugin is ready to be used. Plugins with the error state set should still be registered to prevent + * further discovery runs to try loading them again. + * */ @@ -54,27 +74,65 @@ typedef struct lumiera_plugin_struct lumiera_plugin; typedef lumiera_plugin* LumieraPlugin; enum lumiera_plugin_type; - -int -lumiera_plugin_cmp_fn (const void* keya, const void* keyb); - -const void* -lumiera_plugin_key_fn (const PSplaynode node); - +/** + * Allocates an preinitializes a plugin structure + * @internal + * @param name path/filename of the plugin + * @return new allocated/preinitialized plugin structure with its error state set to LUMIERA_ERROR_PLUGIN_INIT + */ LumieraPlugin lumiera_plugin_new (const char* name); +/** + * Complete plugin initialization + * @internal + * Stores any pending error (from loading) in self which clears out the LUMIERA_ERROR_PLUGIN_INIT error state + * which was initialized by lumiera_plugin_new(), stores the handle and plugin pointers in the plugin struct. + * @param self pointer to the plugin struct + * @param handle opaque handle refering to some plugin type specific data + * @param plugin a lumieraorg__plugin interface which will be used to initialize this plugin + */ LumieraPlugin lumiera_plugin_init (LumieraPlugin self, void* handle, LumieraInterface plugin); + +/** + * Tries to load a plugin + * Creates a new plugin structure and tries to load and initialize the plugin. + * The plugins error state may be set on any problem which should be queried later. + * @param plugin path/filename of the plugin to load + * @return pointer to the new plugin structure (always, never NULL, check error state) + */ LumieraPlugin lumiera_plugin_load (const char* plugin); + +/** + * Register a plugin and its interfaces. + * Registers the plugin (unconditionally) at the pluginregistry. + * When the error state of the plugin is NULL then use its lumieraorg__plugin interface + * to register all interfaces offered by the plugin at the interface registry. + * Registered plugins will be automatic unloaded at application end. + * @param self the plugin to be registered (calling with NULL is a no-op) + * @return 1 on success (including calling with NULL) and 0 when a error occured + */ int -lumiera_plugin_register (LumieraPlugin); +lumiera_plugin_register (LumieraPlugin self); +lumiera_err +lumiera_plugin_error (LumieraPlugin self); + + +/** + * Tries to unload a plugin. + * When the Plugin is unused, then all resources associated with it are freed and it will be removed from memory + * @param plugin name of the plugin to be unloaded. + * @return 0 on success, else the number if users which keeping the plugin loaded + */ +unsigned +lumiera_plugin_unload (LumieraPlugin self); /** @@ -88,17 +146,12 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), int (*callback_register) (LumieraPlugin)); - - - -/** - * Tries to unload a plugin. - * When the Plugin is unused, then all resources associated with it are freed and it will be removed from memory - * @param plugin name of the plugin to be unloaded. - * @return 0 on success, else the number if users which keeping the plugin loaded - */ +/* psplay support functions */ int -lumiera_plugin_unload (const char* plugin); +lumiera_plugin_cmp_fn (const void* keya, const void* keyb); + +const void* +lumiera_plugin_key_fn (const PSplaynode node); #endif /* LUMIERA_PLUGIN_H */ From c35e5fb0f9cdf85072545575eb062e619b5ca049 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 5 Nov 2008 08:04:34 +0100 Subject: [PATCH 059/249] Plugin unloading, at least manually works --- src/backend/plugin.c | 73 +++++++++++++++++++++++++++++++++++-- src/backend/plugin.h | 29 +++++++++++++-- src/backend/plugin_dynlib.c | 6 +-- 3 files changed, 98 insertions(+), 10 deletions(-) diff --git a/src/backend/plugin.c b/src/backend/plugin.c index 264cc8df5..5b0d87728 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -38,13 +38,15 @@ * Plugin loader. */ +/* just some declarations */ extern PSplay lumiera_pluginregistry; +static char* init_exts_globs (); -/* TODO should be set by the build system to the actual plugin path */ +/* TODO default plugin path should be set by the build system */ /* errors */ LUMIERA_ERROR_DEFINE(PLUGIN_INIT, "Initialization error"); -LUMIERA_ERROR_DEFINE(PLUGIN_DLOPEN, "Could not open plugin"); +LUMIERA_ERROR_DEFINE(PLUGIN_OPEN, "Could not open plugin"); LUMIERA_ERROR_DEFINE(PLUGIN_WTF, "Not a Lumiera plugin"); LUMIERA_ERROR_DEFINE(PLUGIN_REGISTER, "Could not register plugin"); LUMIERA_ERROR_DEFINE(PLUGIN_VERSION, "Plugin Version unsupported"); @@ -93,6 +95,8 @@ static lumiera_plugintype lumiera_plugin_types[] = #undef LUMIERA_PLUGIN_TYPE + + struct lumiera_plugin_struct { psplaynode node; @@ -143,9 +147,20 @@ lumiera_plugin_init (LumieraPlugin self, void* handle, LumieraInterface plugin) } +lumiera_err +lumiera_plugin_error (LumieraPlugin self) +{ + REQUIRE (self); + return self->error; +} +void * +lumiera_plugin_handle (LumieraPlugin self) +{ + REQUIRE (self); + return self->handle; +} -static char* init_exts_globs (); int lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), @@ -214,6 +229,7 @@ lumiera_plugin_load (const char* plugin) return NULL; } + int lumiera_plugin_register (LumieraPlugin plugin) { @@ -251,6 +267,57 @@ lumiera_plugin_register (LumieraPlugin plugin) } +unsigned +lumiera_plugin_unload (LumieraPlugin self) +{ + TRACE (plugin); + + if (!self) + return 0; + + if (self->refcnt) + return self->refcnt; + + /* dispatch on ext, call the registered function */ + const char* ext = strrchr (self->name, '.'); + + LumieraPlugintype itr = lumiera_plugin_types; + while (itr->ext) + { + if (!strcmp (itr->ext, ext)) + { + //unregister plugin + if (psplay_remove (lumiera_pluginregistry, &self->node)) + { + if (!self->error) + { + LUMIERA_INTERFACE_HANDLE(lumieraorg__plugin, 0) handle = + LUMIERA_INTERFACE_CAST(lumieraorg__plugin, 0) self->plugin; + + lumiera_interfaceregistry_bulkremove_interfaces (handle->plugin_interfaces ()); + } + itr->lumiera_plugin_unload_fn (self); + break; + } + } + ++itr; + } + + return 0; +} + + +LumieraPlugin +lumiera_plugin_lookup (const char* name) +{ + LumieraPlugin ret = NULL; + + if (name) + LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) + ret = (LumieraPlugin) psplay_find (lumiera_pluginregistry, name, 100); + + return ret; +} static char* init_exts_globs () diff --git a/src/backend/plugin.h b/src/backend/plugin.h index fe2204596..dcf9180f1 100644 --- a/src/backend/plugin.h +++ b/src/backend/plugin.h @@ -58,7 +58,7 @@ LUMIERA_ERROR_DECLARE(PLUGIN_INIT); -LUMIERA_ERROR_DECLARE(PLUGIN_DLOPEN); +LUMIERA_ERROR_DECLARE(PLUGIN_OPEN); LUMIERA_ERROR_DECLARE(PLUGIN_WTF); LUMIERA_ERROR_DECLARE(PLUGIN_REGISTER); LUMIERA_ERROR_DECLARE(PLUGIN_VERSION); @@ -107,7 +107,6 @@ LumieraPlugin lumiera_plugin_load (const char* plugin); - /** * Register a plugin and its interfaces. * Registers the plugin (unconditionally) at the pluginregistry. @@ -121,20 +120,42 @@ int lumiera_plugin_register (LumieraPlugin self); +/** + * Query the error state of a plugin + * @param self plugin to query + * @return error identifier, NULL if no error was set + */ lumiera_err lumiera_plugin_error (LumieraPlugin self); +/** + * Query the plugin handle + * @param self plugin to query + * @return opaque handle set by the loader functions + */ +void* +lumiera_plugin_handle (LumieraPlugin self); + /** * Tries to unload a plugin. * When the Plugin is unused, then all resources associated with it are freed and it will be removed from memory - * @param plugin name of the plugin to be unloaded. - * @return 0 on success, else the number if users which keeping the plugin loaded + * @param plugin the plugin to be unloaded. + * @return 0 on success, else the refcount of users which keeping the plugin loaded */ unsigned lumiera_plugin_unload (LumieraPlugin self); +/** + * Lookup a plugin handle in the pluginregistry + * @param name name of the plugin to be looked up + * @return plugin handle on success, NULL if the plugin is not found in the registry + */ +LumieraPlugin +lumiera_plugin_lookup (const char* name); + + /** * discover new plugins * traverses the configured plugin paths and calls the callback_load function for any plugin diff --git a/src/backend/plugin_dynlib.c b/src/backend/plugin_dynlib.c index 62b105078..75ce4aa89 100644 --- a/src/backend/plugin_dynlib.c +++ b/src/backend/plugin_dynlib.c @@ -44,7 +44,7 @@ lumiera_plugin_load_DYNLIB (const char* name) LUMIERA_ERROR_SET (plugin, PLUGIN_WTF); } else - LUMIERA_ERROR_SET (plugin, PLUGIN_DLOPEN); + LUMIERA_ERROR_SET (plugin, PLUGIN_OPEN); return lumiera_plugin_init (self, handle, plugin); } @@ -53,6 +53,6 @@ lumiera_plugin_load_DYNLIB (const char* name) void lumiera_plugin_unload_DYNLIB (LumieraPlugin self) { - (void) self; - UNIMPLEMENTED(); + TRACE (plugin); + dlclose (lumiera_plugin_handle (self)); } From 240e7cb295623040b0d788b611ecddafba7feb27 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 5 Nov 2008 09:43:59 +0100 Subject: [PATCH 060/249] plugin_unload must lock the registry tree --- src/backend/plugin.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/backend/plugin.c b/src/backend/plugin.c index 5b0d87728..69bac0525 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -286,19 +286,20 @@ lumiera_plugin_unload (LumieraPlugin self) { if (!strcmp (itr->ext, ext)) { - //unregister plugin - if (psplay_remove (lumiera_pluginregistry, &self->node)) + LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) { - if (!self->error) + if (psplay_remove (lumiera_pluginregistry, &self->node)) { - LUMIERA_INTERFACE_HANDLE(lumieraorg__plugin, 0) handle = - LUMIERA_INTERFACE_CAST(lumieraorg__plugin, 0) self->plugin; - - lumiera_interfaceregistry_bulkremove_interfaces (handle->plugin_interfaces ()); + if (!self->error) + { + LUMIERA_INTERFACE_HANDLE(lumieraorg__plugin, 0) handle = + LUMIERA_INTERFACE_CAST(lumieraorg__plugin, 0) self->plugin; + lumiera_interfaceregistry_bulkremove_interfaces (handle->plugin_interfaces ()); + } } - itr->lumiera_plugin_unload_fn (self); - break; } + itr->lumiera_plugin_unload_fn (self); + break; } ++itr; } From c26cd391b0160ca494eb033db4b445f771292f93 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 5 Nov 2008 09:47:52 +0100 Subject: [PATCH 061/249] automatic plugin unloading at interfaceregistry_destroy() All open plugins will be unloaded when the registry gets destroyed. If there are still interfaces open, this will assert at ALPHA builds. --- src/backend/interfaceregistry.c | 20 +++++++++----------- src/backend/plugin.c | 28 ++++++++++++++++++++++++++++ src/backend/plugin.h | 2 ++ src/backend/plugin_dynlib.c | 4 +++- 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/backend/interfaceregistry.c b/src/backend/interfaceregistry.c index 05e2224a1..180c2043f 100644 --- a/src/backend/interfaceregistry.c +++ b/src/backend/interfaceregistry.c @@ -106,7 +106,7 @@ lumiera_interfaceregistry_init (void) if (!lumiera_interfaceregistry) LUMIERA_DIE (ERRNO); - lumiera_pluginregistry = psplay_new (lumiera_plugin_cmp_fn, lumiera_plugin_key_fn, NULL); + lumiera_pluginregistry = psplay_new (lumiera_plugin_cmp_fn, lumiera_plugin_key_fn, lumiera_plugin_delete_fn); if (!lumiera_pluginregistry) LUMIERA_DIE (ERRNO); @@ -118,20 +118,18 @@ void lumiera_interfaceregistry_destroy (void) { TRACE (interfaceregistry); - REQUIRE (!psplay_nelements (lumiera_interfaceregistry)); - - lumiera_mutex_destroy (&lumiera_interface_mutex, &NOBUG_FLAG(interfaceregistry)); - - if (lumiera_interfaceregistry) - psplay_destroy (lumiera_interfaceregistry); - lumiera_interfaceregistry = NULL; - - TODO ("provide a delete function for the psplay tree to tear it down"); - REQUIRE (psplay_nelements (lumiera_pluginregistry) == 0, "plugins still loaded at destroy"); if (lumiera_pluginregistry) psplay_delete (lumiera_pluginregistry); lumiera_pluginregistry = NULL; + + lumiera_mutex_destroy (&lumiera_interface_mutex, &NOBUG_FLAG(interfaceregistry)); + + REQUIRE (!psplay_nelements (lumiera_interfaceregistry), "some interfaces still registered at shutdown"); + + if (lumiera_interfaceregistry) + psplay_destroy (lumiera_interfaceregistry); + lumiera_interfaceregistry = NULL; } diff --git a/src/backend/plugin.c b/src/backend/plugin.c index 69bac0525..23d9aeed1 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -362,3 +362,31 @@ lumiera_plugin_key_fn (const PSplaynode node) return ((LumieraPlugin)node)->name; } + +void +lumiera_plugin_delete_fn (PSplaynode node) +{ + LumieraPlugin self = (LumieraPlugin) node; + + ENSURE (!self->refcnt, "plugin %s still in use at shutdown", self->name); + + + const char* ext = strrchr (self->name, '.'); + + LumieraPlugintype itr = lumiera_plugin_types; + while (itr->ext) + { + if (!strcmp (itr->ext, ext)) + { + if (!self->error) + { + LUMIERA_INTERFACE_HANDLE(lumieraorg__plugin, 0) handle = + LUMIERA_INTERFACE_CAST(lumieraorg__plugin, 0) self->plugin; + lumiera_interfaceregistry_bulkremove_interfaces (handle->plugin_interfaces ()); + } + itr->lumiera_plugin_unload_fn (self); + break; + } + ++itr; + } +} diff --git a/src/backend/plugin.h b/src/backend/plugin.h index dcf9180f1..b7ccd5326 100644 --- a/src/backend/plugin.h +++ b/src/backend/plugin.h @@ -174,5 +174,7 @@ lumiera_plugin_cmp_fn (const void* keya, const void* keyb); const void* lumiera_plugin_key_fn (const PSplaynode node); +void +lumiera_plugin_delete_fn (PSplaynode node); #endif /* LUMIERA_PLUGIN_H */ diff --git a/src/backend/plugin_dynlib.c b/src/backend/plugin_dynlib.c index 75ce4aa89..50030843c 100644 --- a/src/backend/plugin_dynlib.c +++ b/src/backend/plugin_dynlib.c @@ -54,5 +54,7 @@ void lumiera_plugin_unload_DYNLIB (LumieraPlugin self) { TRACE (plugin); - dlclose (lumiera_plugin_handle (self)); + void* handle = lumiera_plugin_handle (self); + if (handle) + dlclose (handle); } From 7afce647fbeaf376019507ce472664c2f927382a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 5 Nov 2008 11:11:25 +0100 Subject: [PATCH 062/249] few tool functions for the plugin implementation * plugin_name() to figure out the name of the plugin * plugin_refinc() and plugin_refdec() to manage the refcount --- src/backend/plugin.c | 25 +++++++++++++++++++++++-- src/backend/plugin.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/backend/plugin.c b/src/backend/plugin.c index 23d9aeed1..f66c73456 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -154,7 +154,8 @@ lumiera_plugin_error (LumieraPlugin self) return self->error; } -void * + +void* lumiera_plugin_handle (LumieraPlugin self) { REQUIRE (self); @@ -162,6 +163,27 @@ lumiera_plugin_handle (LumieraPlugin self) } +const char* +lumiera_plugin_name (LumieraPlugin self) +{ + return self?self->name:NULL; +} + + +void +lumiera_plugin_refinc (LumieraPlugin self) +{ + ++self->refcnt; +} + + +void +lumiera_plugin_refdec (LumieraPlugin self) +{ + --self->refcnt; +} + + int lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), int (*callback_register) (LumieraPlugin)) @@ -370,7 +392,6 @@ lumiera_plugin_delete_fn (PSplaynode node) ENSURE (!self->refcnt, "plugin %s still in use at shutdown", self->name); - const char* ext = strrchr (self->name, '.'); LumieraPlugintype itr = lumiera_plugin_types; diff --git a/src/backend/plugin.h b/src/backend/plugin.h index b7ccd5326..26451edac 100644 --- a/src/backend/plugin.h +++ b/src/backend/plugin.h @@ -137,6 +137,34 @@ void* lumiera_plugin_handle (LumieraPlugin self); +/** + * Query the plugin name + * The name is the path and filname under which it was loaded + * @param self plugin to query + * @return pointer to the name string + */ +const char* +lumiera_plugin_name (LumieraPlugin self); + + +/** + * Increment refcount + * @internal + * @param self plugin which refcount to increment + */ +void +lumiera_plugin_refinc (LumieraPlugin self); + + +/** + * Decrement refcount + * @internal + * @param self plugin which refcount to decrement + */ +void +lumiera_plugin_refdec (LumieraPlugin self); + + /** * Tries to unload a plugin. * When the Plugin is unused, then all resources associated with it are freed and it will be removed from memory From fa6b6d54e9b2c9d6dd349bb003b0a8f735eea9a4 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 5 Nov 2008 11:12:48 +0100 Subject: [PATCH 063/249] hook the plugin refcounting in The plugin refcounter is driven from interface opening/closing, this is quite internal. The 'last' time in plugin now records the last time the refcounter dropped to 0, this is just sufficient enough to find out how long a plugin is unused. --- src/backend/interface.c | 9 ++++++++- src/backend/interfaceregistry.c | 2 -- src/backend/plugin.c | 5 +++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/backend/interface.c b/src/backend/interface.c index 26fa3a42e..22e94cbcc 100644 --- a/src/backend/interface.c +++ b/src/backend/interface.c @@ -22,6 +22,7 @@ #include "lib/mutex.h" #include "lib/safeclib.h" +#include "backend/plugin.h" #include "backend/interface.h" #include "backend/interfaceregistry.h" @@ -133,8 +134,9 @@ depwalk (LumieraInterfacenode self, LumieraInterfacenode* stack) if (!cycle) { + if ((*dep)->plugin) + lumiera_plugin_refinc ((*dep)->plugin); ++(*dep)->refcnt; - (*dep)->lnk = *stack; *stack = *dep; @@ -184,7 +186,10 @@ lumiera_interface_open_interfacenode (LumieraInterfacenode self) if (!cycle) { + if (self->plugin) + lumiera_plugin_refinc (self->plugin); ++self->refcnt; + self->lnk = stack; stack = self; int collect_dependencies_bak = collect_dependencies; @@ -290,6 +295,8 @@ lumiera_interfacenode_close (LumieraInterfacenode self) stack = self->lnk; self->lnk = NULL; + if (self->plugin) + lumiera_plugin_refdec (self->plugin); --self->refcnt; } } diff --git a/src/backend/interfaceregistry.c b/src/backend/interfaceregistry.c index 180c2043f..969ab23e0 100644 --- a/src/backend/interfaceregistry.c +++ b/src/backend/interfaceregistry.c @@ -65,7 +65,6 @@ lumiera_interfacenode_new (LumieraInterface iface, LumieraPlugin plugin) self->interface = iface; self->refcnt = 0; self->plugin = plugin; - FIXME ("plugin handling (refcnt, atime)"); self->lnk = NULL; self->deps_size = 0; self->deps = NULL; @@ -80,7 +79,6 @@ lumiera_interfacenode_delete (LumieraInterfacenode self) if (self) { REQUIRE (self->refcnt == 0); - FIXME ("plugin handling"); lumiera_free (self->deps); lumiera_free (self); } diff --git a/src/backend/plugin.c b/src/backend/plugin.c index f66c73456..768157946 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -107,7 +107,7 @@ struct lumiera_plugin_struct /* use count for all interfaces of this plugin */ unsigned refcnt; - /* time when the last open or close action happened */ + /* time when the refcounter dropped to 0 last time */ time_t last; /* when loading plugins en masse we do not want to fail completely if one doesnt cooperate, instead we record local errors here */ @@ -180,7 +180,8 @@ lumiera_plugin_refinc (LumieraPlugin self) void lumiera_plugin_refdec (LumieraPlugin self) { - --self->refcnt; + if (!--self->refcnt) + time (&self->last); } From d5c61c0e9ddc8496b3963fc139c7390dfd51754c Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 5 Nov 2008 11:13:42 +0100 Subject: [PATCH 064/249] let plugin_discover() barf out when the plugin.path config cant be found --- src/backend/plugin.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backend/plugin.c b/src/backend/plugin.c index 768157946..0bba34409 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -215,6 +215,9 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), ++i; } + if (lumiera_error_peek ()) + return 0; + if (globs.gl_pathc) LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) { From 038f1279466c25dfa41c64e2149620d80d5cd4d6 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 4 Nov 2008 08:07:48 +0100 Subject: [PATCH 065/249] testsuite updates * Makefile.am removed -lm, added $(LUMIERA_PLUGIN_LIBS) * simple test for the plugin loader * remove the old 20plugin.tests, new 31plugin.tests --- tests/20plugin.tests | 24 ------------- tests/31plugin.tests | 29 ++++++++++++++++ tests/Makefile.am | 18 +++++----- tests/backend/test-interfaces.c | 61 +++++++++++++++++++++++++++++++-- 4 files changed, 97 insertions(+), 35 deletions(-) delete mode 100644 tests/20plugin.tests create mode 100644 tests/31plugin.tests diff --git a/tests/20plugin.tests b/tests/20plugin.tests deleted file mode 100644 index d1d9fba2f..000000000 --- a/tests/20plugin.tests +++ /dev/null @@ -1,24 +0,0 @@ -TESTING "test plugin example code" ./test-plugin - -PLANNED "C plugin example" C <hello (); + german->goodbye ("Welt!"); + + english->hello (); + english->goodbye ("World!"); + + LUMIERA_INTERFACE_CLOSE (german); + LUMIERA_INTERFACE_CLOSE (english); + + lumiera_interfaceregistry_destroy (); + lumiera_config_destroy (); } TESTS_END From c04f1e77d6736dcb86aea876ce8efa5636dc2fac Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 6 Nov 2008 04:13:13 +0100 Subject: [PATCH 066/249] set LUMIERA_PLUGIN_PATH to $pkglibdir as default --- src/backend/Makefile.am | 3 ++- src/backend/plugin.c | 15 +++++++++------ tests/31plugin.tests | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index d8c0c159e..f37f51a57 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -18,7 +18,8 @@ liblumibackend_a_srcdir = $(top_srcdir)/src/backend noinst_LIBRARIES += liblumibackend.a -liblumibackend_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wextra -Wall -Werror +liblumibackend_a_CPPFLAGS = $(AM_CPPFLAGS) -DLUMIERA_PLUGIN_PATH="\"$(pkglibdir)\"" +liblumibackend_a_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wextra -Wall -Werror liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/mediaaccessfacade.cpp \ diff --git a/src/backend/plugin.c b/src/backend/plugin.c index 0bba34409..ea189b57e 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -33,6 +33,10 @@ #include +#ifndef LUMIERA_PLUGIN_PATH +#error TODO: hey ichthyo, please figure the $pkglib path out by scons and use it as -DLUMIERA_PLUGIN_PATH for this source +#endif + /** * @file * Plugin loader. @@ -193,6 +197,8 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), REQUIRE (callback_load); REQUIRE (callback_register); + lumiera_config_setdefault ("plugin.path ="LUMIERA_PLUGIN_PATH); + /* construct glob trail {.so,.c,.foo} ... */ static char* exts_globs = NULL; if (!exts_globs) @@ -205,7 +211,7 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), while ((path = lumiera_config_wordlist_get_nth ("plugin.path", i, ":"))) { - path = lumiera_tmpbuf_snprintf (SIZE_MAX,"%s%s", path, exts_globs); + path = lumiera_tmpbuf_snprintf (SIZE_MAX,"%s/%s", path, exts_globs); TRACE (plugin, "globbing path '%s'", path); int ret = glob (path, flags, NULL, &globs); if (ret == GLOB_NOSPACE) @@ -215,9 +221,6 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), ++i; } - if (lumiera_error_peek ()) - return 0; - if (globs.gl_pathc) LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) { @@ -350,7 +353,7 @@ lumiera_plugin_lookup (const char* name) static char* init_exts_globs () { char* exts_globs; - size_t exts_sz = 4; /* / * { } \0 less one comma */ + size_t exts_sz = 3; /* * { } \0 less one comma */ LumieraPlugintype itr = lumiera_plugin_types; while (itr->ext) { @@ -362,7 +365,7 @@ static char* init_exts_globs () *exts_globs = '\0'; itr = lumiera_plugin_types; - strcat (exts_globs, "/*{"); + strcat (exts_globs, "*{"); while (itr->ext) { diff --git a/tests/31plugin.tests b/tests/31plugin.tests index d2107dd3c..776f79da6 100644 --- a/tests/31plugin.tests +++ b/tests/31plugin.tests @@ -2,7 +2,7 @@ TESTING "testing plugins" ./test-interfaces TEST "discovering plugins, missing path" plugin_discover < Date: Thu, 6 Nov 2008 04:25:33 +0100 Subject: [PATCH 067/249] automake fixes --- src/common/Makefile.am | 3 ++- src/lib/Makefile.am | 56 ++++++++++++++++++++++------------------ src/proc/Makefile.am | 7 ++--- tests/common/Makefile.am | 45 ++++++++++++++++++-------------- 4 files changed, 63 insertions(+), 48 deletions(-) diff --git a/src/common/Makefile.am b/src/common/Makefile.am index d7c95467c..a2a9e45a2 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -24,7 +24,7 @@ noinst_LIBRARIES += liblumicommon.a liblumicommon_a_CXXFLAGS = $(CXXFLAGS) -Wall liblumicommon_a_SOURCES = \ - $(liblumicommon_a_srcdir)/lumitime.cpp \ + $(liblumicommon_a_srcdir)/lumitime.cpp \ $(liblumicommon_a_srcdir)/util.cpp \ $(liblumicommon_a_srcdir)/visitor.cpp \ $(liblumicommon_a_srcdir)/cmdline.cpp \ @@ -32,6 +32,7 @@ liblumicommon_a_SOURCES = \ $(liblumicommon_a_srcdir)/error.cpp \ $(liblumicommon_a_srcdir)/query.cpp \ $(liblumicommon_a_srcdir)/query/mockconfigrules.cpp \ + $(liblumicommon_a_srcdir)/streamtype.cpp \ $(liblumicommon_a_srcdir)/test/suite.cpp \ $(liblumicommon_a_srcdir)/test/testoption.cpp diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 55d88e71a..2681ddf24 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -20,31 +20,37 @@ noinst_LIBRARIES += liblumi.a liblumi_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror -liblumi_a_SOURCES = \ - $(liblumi_a_srcdir)/error.c \ - $(liblumi_a_srcdir)/mutex.c \ - $(liblumi_a_srcdir)/rwlock.c \ - $(liblumi_a_srcdir)/condition.c \ - $(liblumi_a_srcdir)/luid.c \ - $(liblumi_a_srcdir)/safeclib.c \ - $(liblumi_a_srcdir)/cuckoo.c \ - $(liblumi_a_srcdir)/psplay.c \ - $(liblumi_a_srcdir)/mrucache.c \ - $(liblumi_a_srcdir)/time.c \ - $(liblumi_a_srcdir)/appconfig.cpp +liblumiera_a_SOURCES = \ + $(liblumiera_a_srcdir)/error.c \ + $(liblumiera_a_srcdir)/mutex.c \ + $(liblumiera_a_srcdir)/rwlock.c \ + $(liblumiera_a_srcdir)/condition.c \ + $(liblumiera_a_srcdir)/luid.c \ + $(liblumiera_a_srcdir)/safeclib.c \ + $(liblumiera_a_srcdir)/cuckoo.c \ + $(liblumiera_a_srcdir)/psplay.c \ + $(liblumiera_a_srcdir)/mrucache.c \ + $(liblumiera_a_srcdir)/time.c \ + $(liblumiera_a_srcdir)/allocationcluster.cpp \ + $(liblumiera_a_srcdir)/external/libgavl.cpp \ + $(liblumiera_a_srcdir)/appconfig.cpp noinst_HEADERS += \ - $(liblumi_a_srcdir)/error.h \ - $(liblumi_a_srcdir)/mutex.h \ - $(liblumi_a_srcdir)/rwlock.h \ - $(liblumi_a_srcdir)/condition.h \ - $(liblumi_a_srcdir)/luid.h \ - $(liblumi_a_srcdir)/safeclib.h \ - $(liblumi_a_srcdir)/cuckoo.h \ - $(liblumi_a_srcdir)/psplay.h \ - $(liblumi_a_srcdir)/mrucache.h \ - $(liblumi_a_srcdir)/time.h \ - $(liblumi_a_srcdir)/ppmpl.h \ - $(liblumi_a_srcdir)/appconfig.hpp \ - $(liblumi_a_srcdir)/lifecycleregistry.hpp + $(liblumiera_a_srcdir)/error.h \ + $(liblumiera_a_srcdir)/mutex.h \ + $(liblumiera_a_srcdir)/rwlock.h \ + $(liblumiera_a_srcdir)/condition.h \ + $(liblumiera_a_srcdir)/luid.h \ + $(liblumiera_a_srcdir)/safeclib.h \ + $(liblumiera_a_srcdir)/cuckoo.h \ + $(liblumiera_a_srcdir)/psplay.h \ + $(liblumiera_a_srcdir)/mrucache.h \ + $(liblumiera_a_srcdir)/time.h \ + $(liblumiera_a_srcdir)/ppmpl.h \ + $(liblumiera_a_srcdir)/appconfig.hpp \ + $(liblumiera_a_srcdir)/allocationcluster.hpp \ + $(liblumiera_a_srcdir)/scopedholdertransfer.hpp \ + $(liblumiera_a_srcdir)/scopedholder.hpp \ + $(liblumiera_a_srcdir)/external/libgavl.hpp \ + $(liblumiera_a_srcdir)/lifecycleregistry.hpp diff --git a/src/proc/Makefile.am b/src/proc/Makefile.am index c972070ba..580bb637e 100644 --- a/src/proc/Makefile.am +++ b/src/proc/Makefile.am @@ -112,7 +112,8 @@ noinst_LIBRARIES += liblumiproccontrol.a liblumiproccontrol_a_CXXFLAGS = $(CXXFLAGS) -Wall liblumiproccontrol_a_SOURCES = \ - $(liblumiproccontrol_a_srcdir)/pathmanager.cpp + $(liblumiproccontrol_a_srcdir)/pathmanager.cpp \ + $(liblumiproccontrol_a_srcdir)/stypemanager.cpp liblumiprocmobjectsession_a_srcdir = $(top_srcdir)/src/proc/mobject/session @@ -125,11 +126,11 @@ liblumiprocmobjectsession_a_SOURCES = \ $(liblumiprocmobjectsession_a_srcdir)/allocation.cpp \ $(liblumiprocmobjectsession_a_srcdir)/auto.cpp \ $(liblumiprocmobjectsession_a_srcdir)/clip.cpp \ - $(liblumiprocmobjectsession_a_srcdir)/compoundclip.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/compoundclip.cpp \ $(liblumiprocmobjectsession_a_srcdir)/constraint.cpp \ $(liblumiprocmobjectsession_a_srcdir)/defsmanager.cpp \ $(liblumiprocmobjectsession_a_srcdir)/effect.cpp \ - $(liblumiprocmobjectsession_a_srcdir)/fixedlocation.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/fixedlocation.cpp \ $(liblumiprocmobjectsession_a_srcdir)/label.cpp \ $(liblumiprocmobjectsession_a_srcdir)/meta.cpp \ $(liblumiprocmobjectsession_a_srcdir)/relativelocation.cpp \ diff --git a/tests/common/Makefile.am b/tests/common/Makefile.am index 55393df9c..5469b486e 100644 --- a/tests/common/Makefile.am +++ b/tests/common/Makefile.am @@ -20,20 +20,21 @@ testcommon_srcdir = $(top_srcdir)/tests/common check_PROGRAMS += test-common test_common_CPPFLAGS = $(AM_CPPFLAGS) -Wall -I$(testcommon_srcdir) -test_common_LDADD = \ - liblumiproc.a \ - liblumiprocengine.a \ - liblumiprocmobjectbuilder.a \ - liblumiprocmobjectsession.a \ - liblumiprocasset.a \ - liblumiprocmobject.a \ - liblumiprocmobjectcontroller.a \ - liblumi.a \ - liblumicommon.a \ +test_common_LDADD = \ + liblumiprocmobjectbuilder.a \ + liblumiprocmobjectsession.a \ + liblumiprocmobject.a \ + liblumiprocengine.a \ + liblumiproccontrol.a \ + liblumiproc.a \ + liblumiprocasset.a \ liblumibackend.a \ + liblumicommon.a \ + liblumiera.a \ $(NOBUGMT_LUMIERA_LIBS) -ldl -lboost_program_options-mt -lboost_regex-mt -test_common_SOURCES = \ +test_common_SOURCES = \ + $(testcommon_srcdir)/allocationclustertest.cpp \ $(testcommon_srcdir)/appconfigtest.cpp \ $(testcommon_srcdir)/customsharedptrtest.cpp \ $(testcommon_srcdir)/exceptionerrortest.cpp \ @@ -42,22 +43,28 @@ test_common_SOURCES = \ $(testcommon_srcdir)/helloworldtest.cpp \ $(testcommon_srcdir)/lifecycletest.cpp \ $(testcommon_srcdir)/mainsuite.cpp \ - $(testcommon_srcdir)/query/queryutilstest.cpp \ - $(testcommon_srcdir)/removefromsettest.cpp \ - $(testcommon_srcdir)/sanitizedidentifiertest.cpp \ - $(testcommon_srcdir)/singletonsubclasstest.cpp \ - $(testcommon_srcdir)/singletontest.cpp \ - $(testcommon_srcdir)/singletontestmocktest.cpp \ - $(testcommon_srcdir)/test/cmdlinewrappertest.cpp \ - $(testcommon_srcdir)/test/testoptiontest.cpp \ $(testcommon_srcdir)/meta/typelisttest.cpp \ $(testcommon_srcdir)/meta/typelistmaniptest.cpp \ $(testcommon_srcdir)/meta/generatortest.cpp \ $(testcommon_srcdir)/meta/configflagstest.cpp \ + $(testcommon_srcdir)/query/queryutilstest.cpp \ + $(testcommon_srcdir)/removefromsettest.cpp \ + $(testcommon_srcdir)/sanitizedidentifiertest.cpp \ + $(testcommon_srcdir)/scopedholdertest.cpp \ + $(testcommon_srcdir)/scopedholdertransfertest.cpp \ + $(testcommon_srcdir)/singletonsubclasstest.cpp \ + $(testcommon_srcdir)/singletontest.cpp \ + $(testcommon_srcdir)/singletontestmocktest.cpp \ + $(testcommon_srcdir)/streamtypebasicstest.cpp \ + $(testcommon_srcdir)/streamtypelifecycletest.cpp \ + $(testcommon_srcdir)/test/cmdlinewrappertest.cpp \ + $(testcommon_srcdir)/test/testoptiontest.cpp \ + $(testcommon_srcdir)/vectortransfertest.cpp \ $(testcommon_srcdir)/visitingtoolconcept.cpp \ $(testcommon_srcdir)/visitingtoolextendedtest.cpp \ $(testcommon_srcdir)/visitingtooltest.cpp noinst_HEADERS += \ $(testcommon_srcdir)/query/querydiagnostics.hpp \ + $(testcommon_srcdir)/testdummy.hpp \ $(testcommon_srcdir)/testtargetobj.hpp From aae3c8ed81567cbd82baae88e02f14cbdd4610b1 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 6 Nov 2008 05:23:47 +0100 Subject: [PATCH 068/249] LUMIERA_PLUGIN is dead, long life LUMIERA_PLUGIN removes the difference in compiled in and plugin interfaces. * All interfaces are now defined with LUMIERA_EXPORT(...) * The definition of LUMIERA_PLUGIN at compile time takes action to compile as plugin which gets automatically managed. * compiled in (core) interfaces need still be registered, this is simplified with the LUMIERA_INTERFACE_REGISTEREXPORTED and LUMIERA_INTERFACE_UNREGISTEREXPORTED macros which become no-ops for plugins. --- src/backend/interface.h | 64 +++++++++++++++++------------ tests/Makefile.am | 2 +- tests/backend/example_plugin.c | 45 ++++++++++----------- tests/backend/test-interfaces.c | 72 ++++++++++++++++----------------- 4 files changed, 96 insertions(+), 87 deletions(-) diff --git a/src/backend/interface.h b/src/backend/interface.h index c84238d1c..e962a2d10 100644 --- a/src/backend/interface.h +++ b/src/backend/interface.h @@ -268,16 +268,16 @@ LUMIERA_INTERFACE_INSTANCE (iname, version, /** * Generate interface container suitable for enumerating interfaces. * This takes a list of interface definitions, instantiates them and places pointers to them - * into a zero terminated array which address is returned by the a created function. - * For interfaces generated by he core, the user is responsible to register these at the - * plugindb dynamically - * @param queryfunc name of the function to be created. - * @param ... list of LUMIERA_INTERFACE_DEFINE() for all interfaces this plugin provides. + * into a zero terminated array which address is returned by a static function named 'lumiera_plugin_interfaces'. + * For interfaces generated by he core, the user is responsible to register these dynamically. + * When LUMIERA_PLUGIN is defined, things change and an additional 'lumieraorg__plugin' interface is generated. + * The plugin loader then uses this to register the provided interfaces automatically. + * @param ... list of LUMIERA_INTERFACE_DEFINE()/LUMIERA_INTERFACE_INLINE() for all interfaces this plugin provides. */ -#define LUMIERA_EXPORT(queryfunc, ...) \ +#define LUMIERA_EXPORT(...) \ PPMPL_FOREACH_L1(_P1_, __VA_ARGS__) \ static LumieraInterface* \ -queryfunc (void) \ +lumiera_plugin_interfaces (void) \ { \ static LumieraInterface interfaces[] = \ { \ @@ -285,30 +285,42 @@ queryfunc (void) \ NULL \ }; \ return interfaces; \ -} +} \ +LUMIERA_PLUGININTERFACE /** - * Generate interface container suitable for a lumiera plugin. - * This takes a list of interface definitions and places pointers to them into a zero terminated array. Further - * it instances a local 'plugin interface' which will be picked up by the plugin loader to query the array of - * provided interfaces. - * @param descriptor pointer to an interface instance which provides a description of this plugin, might be NULL - * @param acquire a function which is called whenever the plugin interface is opened for using, might be NULL - * @param release a function which is called whenever this plugin interface is closed after use, might be NULL - * @param luid unique identifier for the this plugin interfaces query, use the magic word LUIDGEN here and run the - * lumiera uuid generator tool (to be written) over the source file to generate luid's automatically - * @param ... list of LUMIERA_INTERFACE_DEFINE() for all interfaces this plugin provides. + * Create a plugin interface when being copiled as plugin */ -#define LUMIERA_PLUGIN(acquire, release, luid, ...) \ -LUMIERA_EXPORT(plugin_interfaces, __VA_ARGS__) \ -LUMIERA_INTERFACE_INSTANCE (lumieraorg__plugin, 0, \ - lumieraorg_plugin, \ - NULL, \ - acquire, \ - release, \ - LUMIERA_INTERFACE_MAP (plugin_interfaces, luid, plugin_interfaces) \ +#ifdef LUMIERA_PLUGIN +#define LUMIERA_PLUGININTERFACE \ +LUMIERA_INTERFACE_INSTANCE (lumieraorg__plugin, 0, \ + lumieraorg_plugin, \ + NULL, \ + NULL, \ + NULL, \ + LUMIERA_INTERFACE_MAP (plugin_interfaces, \ + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", \ + lumiera_plugin_interfaces) \ ); +#define LUMIERA_INTERFACE_REGISTEREXPORTED +#define LUMIERA_INTERFACE_UNREGISTEREXPORTED +#else +#define LUMIERA_PLUGININTERFACE +/** + * Register all exported interfaces when not a plugin + * This is a no-op when LUMIERA_PLUGIN is defined, since plugins are automatically registered + */ +#define LUMIERA_INTERFACE_REGISTEREXPORTED \ + lumiera_interfaceregistry_bulkregister_interfaces (lumiera_plugin_interfaces(), NULL) +/** + * Unregister all exported interfaces when not a plugin + * This is a no-op when LUMIERA_PLUGIN is defined, since plugins are automatically registered + */ +#define LUMIERA_INTERFACE_UNREGISTEREXPORTED \ + lumiera_interfaceregistry_bulkremove_interfaces (lumiera_plugin_interfaces()) +#endif + /** * create a handle for a interface (WIP) diff --git a/tests/Makefile.am b/tests/Makefile.am index 12be3704d..ce422a4e8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -65,7 +65,7 @@ test_config_LDADD = liblumibackend.a liblumiera.a $(NOBUGMT_LUMIERA_LIBS) check_LTLIBRARIES += examplepluginc.la examplepluginc_la_SOURCES = $(tests_srcdir)/backend/example_plugin.c -examplepluginc_la_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +examplepluginc_la_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -DLUMIERA_PLUGIN -I$(top_srcdir)/src/ examplepluginc_la_LDFLAGS = -module -avoid-version -no-undefined -rpath /dev/null check_PROGRAMS += test-interfaces diff --git a/tests/backend/example_plugin.c b/tests/backend/example_plugin.c index 346585190..66a93c838 100644 --- a/tests/backend/example_plugin.c +++ b/tests/backend/example_plugin.c @@ -103,26 +103,25 @@ LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0, ); -LUMIERA_PLUGIN (NULL, NULL, - "\046\150\040\062\077\110\134\143\236\244\346\365\072\377\371\263", - LUMIERA_INTERFACE_DEFINE (lumieraorg_testhello, 0, - lumieraorg_hello_german, - LUMIERA_INTERFACE_REF (lumieraorg_interfacedescriptor, 0, lumieraorg_exampleplugin_descriptor), - NULL, - NULL, - LUMIERA_INTERFACE_MAP (hello, "\167\012\306\023\031\151\006\362\026\003\125\017\170\022\100\333", - hallo), - LUMIERA_INTERFACE_MAP (goodbye, "\324\267\214\166\340\213\155\053\157\125\064\264\167\235\020\223", - tschuess) - ), - LUMIERA_INTERFACE_DEFINE (lumieraorg_testhello, 0, - lumieraorg_hello_english, - LUMIERA_INTERFACE_REF (lumieraorg_interfacedescriptor, 0, lumieraorg_exampleplugin_descriptor), - NULL, - NULL, - LUMIERA_INTERFACE_MAP (hello, "\326\247\370\247\032\103\223\357\262\007\356\042\051\330\073\116", - hello), - LUMIERA_INTERFACE_MAP (goodbye, "\365\141\371\047\101\230\050\106\071\231\022\235\325\112\354\241", - bye) - ) - ) +LUMIERA_EXPORT( + LUMIERA_INTERFACE_DEFINE (lumieraorg_testhello, 0, + lumieraorg_hello_german, + LUMIERA_INTERFACE_REF (lumieraorg_interfacedescriptor, 0, lumieraorg_exampleplugin_descriptor), + NULL, + NULL, + LUMIERA_INTERFACE_MAP (hello, "\167\012\306\023\031\151\006\362\026\003\125\017\170\022\100\333", + hallo), + LUMIERA_INTERFACE_MAP (goodbye, "\324\267\214\166\340\213\155\053\157\125\064\264\167\235\020\223", + tschuess) + ), + LUMIERA_INTERFACE_DEFINE (lumieraorg_testhello, 0, + lumieraorg_hello_english, + LUMIERA_INTERFACE_REF (lumieraorg_interfacedescriptor, 0, lumieraorg_exampleplugin_descriptor), + NULL, + NULL, + LUMIERA_INTERFACE_MAP (hello, "\326\247\370\247\032\103\223\357\262\007\356\042\051\330\073\116", + hello), + LUMIERA_INTERFACE_MAP (goodbye, "\365\141\371\047\101\230\050\106\071\231\022\235\325\112\354\241", + bye) + ) + ) diff --git a/tests/backend/test-interfaces.c b/tests/backend/test-interfaces.c index f4355cc3b..a087da735 100644 --- a/tests/backend/test-interfaces.c +++ b/tests/backend/test-interfaces.c @@ -146,28 +146,6 @@ LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0, -LUMIERA_EXPORT (interfaces_defined_here, - LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_one, 0, - lumieraorg_first_test, - LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor), - testacquire, - testrelease, - LUMIERA_INTERFACE_MAP (foo1, "\214\310\136\372\003\344\163\377\075\100\070\200\375\221\227\324", - testfunc), - LUMIERA_INTERFACE_MAP (bar1, "\262\253\067\211\157\052\212\140\114\334\231\250\340\075\214\030", - testfunc) - ), - LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_two, 0, - lumieraorg_second_test, - LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor), - testacquire, - testrelease, - LUMIERA_INTERFACE_MAP (foo2, "\110\152\002\271\363\052\324\272\373\045\132\270\277\000\271\217", - testfunc), - LUMIERA_INTERFACE_MAP (bar2, "\376\042\027\336\355\113\132\233\350\312\170\077\377\370\356\167", - testfunc) - ) - ); /* @@ -267,7 +245,27 @@ testrelease_four (LumieraInterface self) } -LUMIERA_EXPORT (dependencytests, +LUMIERA_EXPORT ( + LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_one, 0, + lumieraorg_first_test, + LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor), + testacquire, + testrelease, + LUMIERA_INTERFACE_MAP (foo1, "\214\310\136\372\003\344\163\377\075\100\070\200\375\221\227\324", + testfunc), + LUMIERA_INTERFACE_MAP (bar1, "\262\253\067\211\157\052\212\140\114\334\231\250\340\075\214\030", + testfunc) + ), + LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_two, 0, + lumieraorg_second_test, + LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor), + testacquire, + testrelease, + LUMIERA_INTERFACE_MAP (foo2, "\110\152\002\271\363\052\324\272\373\045\132\270\277\000\271\217", + testfunc), + LUMIERA_INTERFACE_MAP (bar2, "\376\042\027\336\355\113\132\233\350\312\170\077\377\370\356\167", + testfunc) + ), LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_void, 0, lumieraorg_dependencytest_one, LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor), @@ -301,7 +299,7 @@ TEST ("basic") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (interfaces_defined_here(), NULL); + lumiera_interfaceregistry_bulkregister_interfaces (lumiera_plugin_interfaces(), NULL); /* some ugly lowlevel handling tests */ @@ -317,14 +315,14 @@ TEST ("basic") handle2->foo2 ("this is foo2"); - lumiera_interfaceregistry_bulkremove_interfaces (interfaces_defined_here()); + LUMIERA_INTERFACE_UNREGISTEREXPORTED; lumiera_interfaceregistry_destroy (); } TEST ("open_close") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (interfaces_defined_here(), NULL); + lumiera_interfaceregistry_bulkregister_interfaces (lumiera_plugin_interfaces(), NULL); LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_one, 0) handle = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_one, 0, 0, lumieraorg_first_test); @@ -334,14 +332,14 @@ TEST ("open_close") lumiera_interface_close ((LumieraInterface)handle); - lumiera_interfaceregistry_bulkremove_interfaces (interfaces_defined_here()); + LUMIERA_INTERFACE_UNREGISTEREXPORTED; lumiera_interfaceregistry_destroy (); } TEST ("dependencies_one") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (dependencytests(), NULL); + LUMIERA_INTERFACE_REGISTEREXPORTED; LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_one); @@ -351,7 +349,7 @@ TEST ("dependencies_one") lumiera_interface_close ((LumieraInterface)handle); - lumiera_interfaceregistry_bulkremove_interfaces (dependencytests()); + LUMIERA_INTERFACE_UNREGISTEREXPORTED; lumiera_interfaceregistry_destroy (); } @@ -359,7 +357,7 @@ TEST ("dependencies_one") TEST ("dependencies_two") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (dependencytests(), NULL); + LUMIERA_INTERFACE_REGISTEREXPORTED; LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two); @@ -369,14 +367,14 @@ TEST ("dependencies_two") lumiera_interface_close ((LumieraInterface)handle); - lumiera_interfaceregistry_bulkremove_interfaces (dependencytests()); + LUMIERA_INTERFACE_UNREGISTEREXPORTED; lumiera_interfaceregistry_destroy (); } TEST ("dependencies_three") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (dependencytests(), NULL); + LUMIERA_INTERFACE_REGISTEREXPORTED; LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_three); @@ -386,7 +384,7 @@ TEST ("dependencies_three") lumiera_interface_close ((LumieraInterface)handle); - lumiera_interfaceregistry_bulkremove_interfaces (dependencytests()); + LUMIERA_INTERFACE_UNREGISTEREXPORTED; lumiera_interfaceregistry_destroy (); } @@ -394,7 +392,7 @@ TEST ("dependencies_three") TEST ("dependencies_four") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (dependencytests(), NULL); + LUMIERA_INTERFACE_REGISTEREXPORTED; LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_four); @@ -404,7 +402,7 @@ TEST ("dependencies_four") lumiera_interface_close ((LumieraInterface)handle); - lumiera_interfaceregistry_bulkremove_interfaces (dependencytests()); + LUMIERA_INTERFACE_UNREGISTEREXPORTED; lumiera_interfaceregistry_destroy (); } @@ -413,7 +411,7 @@ TEST ("dependencies_four") TEST ("dependencies_all") { lumiera_interfaceregistry_init (); - lumiera_interfaceregistry_bulkregister_interfaces (dependencytests(), NULL); + LUMIERA_INTERFACE_REGISTEREXPORTED; TRACE (tests, "OPEN one"); LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle_one = @@ -450,7 +448,7 @@ TEST ("dependencies_all") lumiera_interface_close ((LumieraInterface)handle_one); - lumiera_interfaceregistry_bulkremove_interfaces (dependencytests()); + LUMIERA_INTERFACE_UNREGISTEREXPORTED; lumiera_interfaceregistry_destroy (); } From 58bcc59a908cc8ae98bf2b6cd4c28262565559b3 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 6 Nov 2008 05:38:33 +0100 Subject: [PATCH 069/249] The incomplete Guide to Lumiera Configuration This shall become a reference of all (most) lumiera configuation keys. So far this is only prelimary located in the doc/devel dir and will be moved to the documentation wiki as soon as it becomes available. --- doc/devel/config_guide.txt | 80 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 doc/devel/config_guide.txt diff --git a/doc/devel/config_guide.txt b/doc/devel/config_guide.txt new file mode 100644 index 000000000..a4a5d711d --- /dev/null +++ b/doc/devel/config_guide.txt @@ -0,0 +1,80 @@ +The incomplete Guide to Lumiera Configuration +============================================== + +DONT EDIT THE CONFIG IF YOU DONT KNOW WHAT YOU ARE DOING! +Misconfiguration will break Lumiera and may destroy all your data! + +Order is roughly alphabetically, depending on the mood of the writer. +Defaults are noted if present. Not all are implemented yet. + +General Introduction +-------------------- + +Lumiera uses plaintext files with a INI file like syntax for +configuration. This Syntax is strictly line based. There are only a +few syntactic elements. + +TODO:describe config syntax here + +Config Subsystem +---------------- + +The path where Lumiera searches its configuration. Single components are +separated by colons as in PATH and other such environment variables. +Here it might be handy that any Lumiera configuration can be +overridden by a environment variable: +'LUMIERA_CONFIG_PATH=somewhere:else lumiera ...' +A default are initialized at installation time, this is important to +bootstrap the whole configuration system. + + config.path + + +The config system check for a preferred format when writing config +entries. For each key 'foo.bar', these can be overridden with a key +'config.format.foo.bar' linking to the desired format. + + config.formatkey ='config.format.%s' + + +The following are links to the default formatting when no explicit +format is set for a key. Changing these to a wrong type will break the +system! + + config.formatdef.link < config.formatstr.link + config.formatdef.number < config.formatstr.number.dec + config.formatdef.real < config.formatstr.real + config.formatdef.string < config.formatstr.string + config.formatdef.word < config.formatstr.word + config.formatdef.bool < config.formatstr.bool + + +This are the low level formating specifications for the buildin +types, DONT TOUCH THESE! + + config.formatstr.link = '< %s' + config.formatstr.number.dec = '= %lld' + config.formatstr.number.hex = '= 0x%llX' + config.formatstr.number.oct = '= 0%llo' + config.formatstr.real = '= %Lg' + config.formatstr.real.dec = '= %Lf' + config.formatstr.real.sci = '= %Le' + config.formatstr.string = '= %s' + config.formatstr.string.dquoted = '= \"%s\"' + config.formatstr.string.quoted = '= ''%s''' + config.formatstr.word = '= %s' + config.formatstr.bool = '= %d' + + +Plugin System +------------- + +The path where Lumiera searches its plugins. Single components are +separated by colons as in PATH and other such environment variables. +Here it might be handy that any Lumiera configuration can be +overridden by a environment variable: +'LUMIERA_PLUGIN_PATH=somewhere:else lumiera ...' +Sensible defaults are initialized at installation time. + + plugin.path + From 8ffbc29b29645d8e9d4ba33907584b467df546fe Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 7 Nov 2008 01:42:32 +0100 Subject: [PATCH 070/249] SCons: generally expand vars when setting Flags to environment --- SConstruct | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/SConstruct b/SConstruct index 20fa76840..40fba1845 100644 --- a/SConstruct +++ b/SConstruct @@ -80,9 +80,9 @@ def setupBasicEnvironment(): env.Append(CPPDEFINES = '_GNU_SOURCE') appendCppDefine(env,'DEBUG','DEBUG', 'NDEBUG') # appendCppDefine(env,'OPENGL','USE_OPENGL') - appendVal(env,'ARCHFLAGS', 'CCFLAGS') # for both C and C++ - appendVal(env,'OPTIMIZE', 'CCFLAGS', val=' -O3') - appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb') + appendVal(env,'ARCHFLAGS','CCFLAGS') # for both C and C++ + appendVal(env,'OPTIMIZE', 'CCFLAGS', val=' -O3') + appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb') prepareOptionsHelp(opts,env) opts.Save(OPTIONSCACHEFILE, env) @@ -90,13 +90,13 @@ def setupBasicEnvironment(): def appendCppDefine(env,var,cppVar, elseVal=''): if env[var]: - env.Append(CPPDEFINES = cppVar ) + env.Append(CPPDEFINES = env.subst(cppVar) ) elif elseVal: - env.Append(CPPDEFINES = elseVal) + env.Append(CPPDEFINES = env.subst(elseVal)) def appendVal(env,var,targetVar,val=None): if env[var]: - env.Append( **{targetVar: val or env[var]}) + env.Append( **{targetVar: env.subst(val) or env[var]}) def handleNoBugSwitches(env): From 18b750d86b516482c7010d2dcd0e51c2eedb4f9f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 7 Nov 2008 01:54:39 +0100 Subject: [PATCH 071/249] SCons: set LUMIERA_PLUGIN_PATH, add option PKGLIBDIR --- SConstruct | 5 +++++ tests/SConscript | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/SConstruct b/SConstruct index 40fba1845..26efb00e8 100644 --- a/SConstruct +++ b/SConstruct @@ -84,6 +84,10 @@ def setupBasicEnvironment(): appendVal(env,'OPTIMIZE', 'CCFLAGS', val=' -O3') appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb') + # setup search path for Lumiera plugins + appendCppDefine(env,'PKGLIBDIR','LUMIERA_PLUGIN_PATH=\\"$PKGLIBDIR\\"' + ,'LUMIERA_PLUGIN_PATH=\\"$DESTDIR/lib/lumiera\\"') + prepareOptionsHelp(opts,env) opts.Save(OPTIONSCACHEFILE, env) return env @@ -144,6 +148,7 @@ def defineCmdlineOptions(): # ,EnumOption('DIST_TARGET', 'Build target architecture', 'auto', # allowed_values=('auto', 'i386', 'i686', 'x86_64' ), ignorecase=2) ,PathOption('DESTDIR', 'Installation dir prefix', '/usr/local') + ,PathOption('PKGLIBDIR', 'Installation dir for plugins, defaults to DESTDIR/lib/lumiera', '',PathOption.PathAccept) ,PathOption('SRCTAR', 'Create source tarball prior to compiling', '..', PathOption.PathAccept) ,PathOption('DOCTAR', 'Create tarball with dev documentaionl', '..', PathOption.PathAccept) ) diff --git a/tests/SConscript b/tests/SConscript index 901c2280c..fe378b891 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -48,14 +48,13 @@ def treatPluginTestcase(env): """ tree = 'backend' env = env.Clone() - env.Append(CPPPATH=tree) + env.Append(CPPPATH=tree, CPPDEFINES='LUMIERA_PLUGIN') prfx = path.join(tree,'example_plugin') oC = env.SharedObject(prfx, prfx+'.c') oCPP = env.SharedObject(prfx+'_cpp', prfx+'.cpp') - testplugin = ( env.LoadableModule('#$BINDIR/.libs/examplepluginc', oC, SHLIBPREFIX='') - + testplugin = ( env.LoadableModule('#$BINDIR/.libs/examplepluginc', oC, SHLIBPREFIX='') +# + env.SharedLibrary('#$BINDIR/.libs/exampleplugincpp', oCPP, SHLIBPREFIX='') # doesn't compile yet... -# + env.SharedLibrary('#$BINDIR/.libs/exampleplugincpp', oCPP, SHLIBPREFIX='') ) return testplugin From bd538edfe9f8d17ce01adae98391cab9dbd46229 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 7 Nov 2008 19:13:58 +0100 Subject: [PATCH 072/249] try to make icon-render-script more robust regarding the output destination --- admin/render-icon.py | 45 +++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/admin/render-icon.py b/admin/render-icon.py index 26bdb3653..534ddaa1c 100755 --- a/admin/render-icon.py +++ b/admin/render-icon.py @@ -1,5 +1,5 @@ #!/usr/bin/python - +# # render-icons.py - Icon rendering utility script # # Copyright (C) Lumiera.org @@ -20,9 +20,10 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. import sys +import os +import os.path as Path import getopt from xml.dom import minidom -import os import shutil #svgDir = "svg" @@ -32,14 +33,20 @@ rsvgPath = "./rsvg-convert" artworkLayerPrefix = "artwork:" def createDirectory( name ): - if os.path.exists(name) == False: + if Path.isfile(name): + print "WARNING: moving %s to %s.bak because it's in the way." % name + bak_name = name + ".bak" + if Path.isfile(bak_name): + os.remove(bak_name) + os.rename(name,bak_name) + if not Path.isdir(name): os.mkdir(name) - + def copyMergeDirectory( src, dst ): listing = os.listdir(src) for file_name in listing: - src_file_path = os.path.join(src, file_name) - dst_file_path = os.path.join(dst, file_name) + src_file_path = Path.join(src, file_name) + dst_file_path = Path.join(dst, file_name) shutil.copyfile(src_file_path, dst_file_path) def getDocumentSize( svg_element ): @@ -99,7 +106,7 @@ def renderSvgInkscape(file_path, out_dir, artwork_name, rectangle, doc_size): "-a %g:%g:%g:%g" % (x1, y1, x2, y2), "-w %g" % (rectangle[2]), "-h %g" % (rectangle[3]), "--export-png=" + os.path.join(out_dir, "%gx%g/%s.png" % (rectangle[2], rectangle[3], artwork_name))) - + def renderSvgRsvg(file_path, out_dir, artwork_name, rectangle, doc_size): # Prepare a Cairo context width = int(rectangle[2]) @@ -154,19 +161,23 @@ def parseArguments(argv): def main(argv): in_path, out_dir = parseArguments(argv) - if in_path == None or out_dir == None: - return + if not (in_path and out_dir): + print "Missing arguments in_path and out_dir." + sys.exit(1) - if os.path.exists(out_dir) == False: - print "Directory not found: " + out_dir - return + if Path.isfile(out_dir): + print "Unable to use '%s' as output directory, because it\'s a file." % out_dir + sys.exit(1) + if not Path.isdir(out_dir): + print "Output directory '%s' not found." % out_dir + sys.exit(1) # Create the icons folders - createDirectory(os.path.join(out_dir, "48x48")) - createDirectory(os.path.join(out_dir, "32x32")) - createDirectory(os.path.join(out_dir, "24x24")) - createDirectory(os.path.join(out_dir, "22x22")) - createDirectory(os.path.join(out_dir, "16x16")) + createDirectory(Path.join(out_dir, "48x48")) + createDirectory(Path.join(out_dir, "32x32")) + createDirectory(Path.join(out_dir, "24x24")) + createDirectory(Path.join(out_dir, "22x22")) + createDirectory(Path.join(out_dir, "16x16")) renderSvgIcon(in_path, out_dir) From 27052a8f586f66c2f1fa263151dc78bdbabca299 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 7 Nov 2008 21:59:36 +0100 Subject: [PATCH 073/249] bugfix --- admin/render-icon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/render-icon.py b/admin/render-icon.py index 534ddaa1c..4b0d464ca 100755 --- a/admin/render-icon.py +++ b/admin/render-icon.py @@ -34,7 +34,7 @@ artworkLayerPrefix = "artwork:" def createDirectory( name ): if Path.isfile(name): - print "WARNING: moving %s to %s.bak because it's in the way." % name + print "WARNING: moving %s to %s.bak because it's in the way." % (name,name) bak_name = name + ".bak" if Path.isfile(bak_name): os.remove(bak_name) From f13f851d77007bad4a2703740208db2a5a303767 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 7 Nov 2008 23:10:08 +0100 Subject: [PATCH 074/249] error message when plugin.c is built without defining the plugin search path (and btw... thanks for the hint ;-) --- src/backend/plugin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/plugin.c b/src/backend/plugin.c index ea189b57e..d5db02c48 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -34,7 +34,7 @@ #include #ifndef LUMIERA_PLUGIN_PATH -#error TODO: hey ichthyo, please figure the $pkglib path out by scons and use it as -DLUMIERA_PLUGIN_PATH for this source +#error please define the plugin search path as -DLUMIERA_PLUGIN_PATH, e.g. as $INSTALL_PREFIX/lib/lumiera #endif /** From 6c50182db17456673dc4a670c0dbd43aab6870d0 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 15 Nov 2008 15:17:26 +0000 Subject: [PATCH 075/249] Added support for highlighting the hovering track --- src/gui/widgets/timeline-widget.cpp | 32 ++++- src/gui/widgets/timeline-widget.hpp | 10 ++ src/gui/widgets/timeline/timeline-body.cpp | 76 +++++++++-- src/gui/widgets/timeline/timeline-body.hpp | 5 + .../timeline/timeline-header-container.cpp | 126 +++++++++++++----- .../timeline/timeline-header-container.hpp | 35 ++++- 6 files changed, 233 insertions(+), 51 deletions(-) diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 40d0ad09f..8172dce80 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -32,7 +32,7 @@ namespace gui { namespace widgets { const int TimelineWidget::TrackPadding = 1; -const int TimelineWidget::HeaderWidth = 100; +const int TimelineWidget::HeaderWidth = 150; const double TimelineWidget::ZoomIncrement = 1.25; const int64_t TimelineWidget::MaxScale = 30000000; @@ -48,6 +48,7 @@ TimelineWidget::TimelineWidget() : playbackPeriodStart(0), playbackPeriodEnd(0), playbackPoint(GAVL_TIME_UNDEFINED), + hoveringTrack(NULL), horizontalScroll(horizontalAdjustment), verticalScroll(verticalAdjustment) { @@ -100,6 +101,8 @@ TimelineWidget::~TimelineWidget() ruler->unreference(); } +/* ===== Data Access ===== */ + gavl_time_t TimelineWidget::get_time_offset() const { @@ -279,6 +282,14 @@ TimelineWidget::set_tool(ToolType tool_type) body->set_tool(tool_type); } +timeline::Track* +TimelineWidget::get_hovering_track() const +{ + return hoveringTrack; +} + +/* ===== Signals ===== */ + sigc::signal TimelineWidget::view_changed_signal() const { @@ -297,6 +308,14 @@ TimelineWidget::playback_period_drag_released_signal() const return playbackPeriodDragReleasedSignal; } +sigc::signal +TimelineWidget::hovering_track_changed_signal() const +{ + return hoveringTrackChangedSignal; +} + +/* ===== Events ===== */ + void TimelineWidget::on_scroll() { @@ -312,6 +331,8 @@ TimelineWidget::on_size_allocate(Allocation& allocation) update_scroll(); } +/* ===== Utilities ===== */ + int TimelineWidget::time_to_x(gavl_time_t time) const { @@ -324,6 +345,8 @@ TimelineWidget::x_to_time(int x) const return (gavl_time_t)((int64_t)x * timeScale + timeOffset); } +/* ===== Internals ===== */ + void TimelineWidget::update_tracks() { @@ -417,5 +440,12 @@ TimelineWidget::on_playback_period_drag_released() playbackPeriodDragReleasedSignal.emit(); } +void +TimelineWidget::set_hovering_track(timeline::Track *hovering_track) +{ + hoveringTrack = hovering_track; + hoveringTrackChangedSignal.emit(hovering_track); +} + } // namespace widgets } // namespace gui diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index b1b3b0600..873986ff8 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -174,6 +174,8 @@ public: */ void set_tool(timeline::ToolType tool_type); + timeline::Track* get_hovering_track() const; + public: /* ===== Signals ===== */ sigc::signal view_changed_signal() const; @@ -181,6 +183,9 @@ public: sigc::signal mouse_hover_signal() const; sigc::signal playback_period_drag_released_signal() const; + + sigc::signal hovering_track_changed_signal() + const; /* ===== Events ===== */ protected: @@ -209,6 +214,8 @@ private: bool on_motion_in_body_notify_event(GdkEventMotion *event); void on_playback_period_drag_released(); + + void set_hovering_track(timeline::Track *hovering_track); protected: @@ -222,6 +229,8 @@ protected: gavl_time_t playbackPeriodStart; gavl_time_t playbackPeriodEnd; gavl_time_t playbackPoint; + + timeline::Track *hoveringTrack; int totalHeight; @@ -245,6 +254,7 @@ protected: sigc::signal viewChangedSignal; sigc::signal mouseHoverSignal; sigc::signal playbackPeriodDragReleasedSignal; + sigc::signal hoveringTrackChangedSignal; /* ===== Constants ===== */ public: diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index 72d56fd24..05d92bb55 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -233,25 +233,31 @@ bool TimelineBody::on_motion_notify_event(GdkEventMotion *event) { REQUIRE(event != NULL); - + + // Handle a middle-mouse drag if one is occuring switch(dragType) - { - case Shift: { - const int64_t scale = timelineWidget->get_time_scale(); - gavl_time_t offset = beginShiftTimeOffset + - (int64_t)(mouseDownX - event->x) * scale; - timelineWidget->set_time_offset(offset); - - set_vertical_offset((int)(mouseDownY - event->y) + - beginShiftVerticalOffset); - break; + case Shift: + { + const int64_t scale = timelineWidget->get_time_scale(); + gavl_time_t offset = beginShiftTimeOffset + + (int64_t)(mouseDownX - event->x) * scale; + timelineWidget->set_time_offset(offset); + + set_vertical_offset((int)(mouseDownY - event->y) + + beginShiftVerticalOffset); + break; + } } - } // Forward the event to the tool tool->on_motion_notify_event(event); + // See if the track that we're hovering over has changed + Track *new_hovering_track = track_from_point(event->y); + if(timelineWidget->get_hovering_track() != new_hovering_track) + timelineWidget->set_hovering_track(new_hovering_track); + // false so that the message is passed up to the owner TimelineWidget return false; } @@ -308,6 +314,7 @@ TimelineBody::draw_track_recursive(Cairo::RefPtr cr, // Shift for the next track cr->translate(0, height); + // Recurse drawing into children BOOST_FOREACH( Track* child, track->get_child_tracks() ) { ASSERT(track != NULL); @@ -410,6 +417,51 @@ TimelineBody::set_vertical_offset(int offset) timelineWidget->verticalAdjustment.set_value(offset); } +Track* +TimelineBody::track_from_point(const int y) const +{ + int offset = -get_vertical_offset(); + + BOOST_FOREACH( Track* track, timelineWidget->tracks ) + { + ASSERT(track != NULL); + Track* result = track_from_branch(track, y, offset); + if(result != NULL) + return result; + } + + // No track has been found with this point in it + return NULL; +} + +Track* TimelineBody::track_from_branch(Track *track, + const int y, int &offset) +{ + REQUIRE(track != NULL); + + const int height = track->get_height(); + ASSERT(height >= 0); + + // Does the point fall in this track? + if(offset <= y && y < offset + height) + return track; + + // Add the height of this track to the accumulation + offset += height; + + // Recurse drawing into children + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + { + ASSERT(track != NULL); + Track* result = track_from_branch(child, y, offset); + if(result != NULL) + return result; + } + + // No track has been found in this branch + return NULL; +} + void TimelineBody::register_styles() const { diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp index 9ce48f5e1..172df8b30 100644 --- a/src/gui/widgets/timeline/timeline-body.hpp +++ b/src/gui/widgets/timeline/timeline-body.hpp @@ -135,6 +135,11 @@ private: void set_vertical_offset(int offset); + Track* track_from_point(const int y) const; + + static Track* track_from_branch(Track *track, const int y, + int &offset); + /** * Registers all the styles that this class will respond to. */ diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 3c16d912e..4b1cb8f7d 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -38,7 +38,8 @@ TimelineHeaderContainer::TimelineHeaderContainer(gui::widgets::TimelineWidget *timeline_widget) : Glib::ObjectBase("TimelineHeaderContainer"), timelineWidget(timeline_widget), - margin(-1) + margin(-1), + expand_button_size(12) { REQUIRE(timeline_widget != NULL); @@ -52,6 +53,12 @@ TimelineHeaderContainer::TimelineHeaderContainer(gui::widgets::TimelineWidget timelineWidget->verticalAdjustment.signal_value_changed().connect( sigc::mem_fun(this, &TimelineHeaderContainer::on_scroll) ); + // Connect to the timeline widget's hover event, + // so that we get notified when tracks are hovered on + timelineWidget->hovering_track_changed_signal().connect( + sigc::mem_fun(this, + &TimelineHeaderContainer::on_hovering_track_changed) ); + // Install style properties register_styles(); } @@ -95,11 +102,18 @@ TimelineHeaderContainer::on_realize() unset_flags(Gtk::NO_WINDOW); set_window(gdkWindow); - // Unset the background so as to make the colour match the parent window + // Unset the background so as to make the colour match the parent + // window unset_bg(STATE_NORMAL); // Make the widget receive expose events gdkWindow->set_user_data(gobj()); + + // Make the widget sensitive to mouse events + add_events( + Gdk::POINTER_MOTION_MASK | + Gdk::BUTTON_PRESS_MASK | + Gdk::BUTTON_RELEASE_MASK); } void @@ -112,6 +126,13 @@ TimelineHeaderContainer::on_unrealize() Gtk::Widget::on_unrealize(); } +bool TimelineHeaderContainer::on_motion_notify_event ( + GdkEventMotion* event) +{ + REQUIRE(event != NULL); + return Container::on_motion_notify_event(event); +} + void TimelineHeaderContainer::on_size_request (Requisition* requisition) { @@ -159,33 +180,23 @@ TimelineHeaderContainer::on_expose_event(GdkEventExpose *event) { if(gdkWindow) { - int offset = 0; - const int y_scroll_offset = timelineWidget->get_y_scroll_offset(); - - Glib::RefPtr