From a78ec21feaca928ffc8ba8964ef161dc0436b448 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 14 Jan 2009 01:49:47 +0100 Subject: [PATCH 001/216] ERROR_SET_* macros for different logging levels --- src/lib/error.h | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/lib/error.h b/src/lib/error.h index b6fb8a416..100ad7c7b 100644 --- a/src/lib/error.h +++ b/src/lib/error.h @@ -64,8 +64,10 @@ lumiera_err LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg /** * Helper macro to raise an error for the current thread. * This macro eases setting an error. It adds NoBug logging support to the low level error handling. + * Used for unexpected errors which can be handled without any problems. * @param flag NoBug flag describing the subsystem where the error was raised * @param err name of the error without the 'LUMIERA_ERROR_' prefix (example: NO_MEMORY) + * @param extra optional string (or NULL) which adds some more context to the error, can be a temporary */ #define LUMIERA_ERROR_SET(flag, err, extra) \ do { \ @@ -74,11 +76,56 @@ lumiera_err LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg lumiera_error_set(LUMIERA_ERROR_##err, theextra); \ } while (0) +/** + * Helper macro to raise an error for the current thread. + * Same as LUMIERA_ERROR_SET(), but logs at 'LOG_ALERT' level. + * Use this when the application is about to do a emergency shutdown. + * @param flag NoBug flag describing the subsystem where the error was raised + * @param err name of the error without the 'LUMIERA_ERROR_' prefix (example: NO_MEMORY) + * @param extra optional string (or NULL) which adds some more context to the error, can be a temporary + */ +#define LUMIERA_ERROR_SET_ALERT(flag, err, extra) \ + do { \ + const char* theextra = extra; \ + ALERT (flag, "%s%s%s", strchr(LUMIERA_ERROR_##err, ':')+1, theextra?": ":"", theextra?theextra:""); \ + lumiera_error_set(LUMIERA_ERROR_##err, theextra); \ + } while (0) + +/** + * Helper macro to raise an error for the current thread. + * Same as LUMIERA_ERROR_SET(), but logs at 'LOG_CRIT' level. + * Use this when a requested task can not be completed (maybe user intervention is necessary). + * @param flag NoBug flag describing the subsystem where the error was raised + * @param err name of the error without the 'LUMIERA_ERROR_' prefix (example: NO_MEMORY) + * @param extra optional string (or NULL) which adds some more context to the error, can be a temporary + */ +#define LUMIERA_ERROR_SET_CRITICAL(flag, err, extra) \ + do { \ + const char* theextra = extra; \ + CRITICAL (flag, "%s%s%s", strchr(LUMIERA_ERROR_##err, ':')+1, theextra?": ":"", theextra?theextra:"");\ + lumiera_error_set(LUMIERA_ERROR_##err, theextra); \ + } while (0) + +/** + * Helper macro to raise an error for the current thread. + * Same as LUMIERA_ERROR_SET(), but logs at 'LOG_WARNING' level. + * Use this when a not unexected error happens which can be handled. + * @param flag NoBug flag describing the subsystem where the error was raised + * @param err name of the error without the 'LUMIERA_ERROR_' prefix (example: NO_MEMORY) + * @param extra optional string (or NULL) which adds some more context to the error, can be a temporary + */ +#define LUMIERA_ERROR_SET_WARNING(flag, err, extra) \ + do { \ + const char* theextra = extra; \ + WARN (flag, "%s%s%s", strchr(LUMIERA_ERROR_##err, ':')+1, theextra?": ":"", theextra?theextra:""); \ + lumiera_error_set(LUMIERA_ERROR_##err, theextra); \ + } while (0) + /** * Set error state for the current thread. * If the error state of the current thread was cleared, then set it, else preserve the old state. * @param nerr name of the error with 'LUMIERA_ERROR_' prefix (example: LUMIERA_ERROR_NO_MEMORY) - * @param extra a string (possibly a constructed tmpbuf) which adds some more context to the error occured this will be copied + * @param extra a string (possibly a constructed tmpbuf) which adds some more context to the error, can be a temporary * @return old state, that is NULL for success, when the state was cleared and a pointer to a pending * error when the error state was already set */ From 9665aa1df93b3eeebc2b05a5528439267c6b93fa Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 14 Jan 2009 14:50:25 +0100 Subject: [PATCH 002/216] Apply log levels to existing errors --- src/backend/filedescriptor.c | 6 +++--- src/backend/filehandle.c | 9 ++++++--- src/backend/filehandlecache.c | 3 ++- src/backend/mmap.c | 3 ++- src/common/config.c | 2 +- src/common/config_typed.c | 8 ++++---- src/common/plugin.c | 2 +- 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index 8f68e3e42..e27bf66f0 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -141,7 +141,7 @@ lumiera_filedescriptor_acquire (const char* name, int flags, LList filenode) INFO (filedescriptor, "try creating dir: %s", dir); if (mkdir (dir, 0777) == -1 && errno != EEXIST) { - LUMIERA_ERROR_SET (filedescriptor, ERRNO, name); + LUMIERA_ERROR_SET_CRITICAL (filedescriptor, ERRNO, name); goto error; } *slash = '/'; @@ -152,14 +152,14 @@ lumiera_filedescriptor_acquire (const char* name, int flags, LList filenode) fd = creat (name, 0666); if (fd == -1) { - LUMIERA_ERROR_SET (filedescriptor, ERRNO, name); + LUMIERA_ERROR_SET_CRITICAL (filedescriptor, ERRNO, name); goto error; } close (fd); if (stat (name, &fdesc.stat) != 0) { /* finally, no luck */ - LUMIERA_ERROR_SET (filedescriptor, ERRNO, name); + LUMIERA_ERROR_SET_CRITICAL (filedescriptor, ERRNO, name); goto error; } } diff --git a/src/backend/filehandle.c b/src/backend/filehandle.c index 2197a0805..86d9107f2 100644 --- a/src/backend/filehandle.c +++ b/src/backend/filehandle.c @@ -84,7 +84,8 @@ lumiera_filehandle_handle (LumieraFilehandle self) fd = open (lumiera_filedescriptor_name (self->descriptor), lumiera_filedescriptor_flags (self->descriptor) & LUMIERA_FILE_MASK); if (fd == -1) { - LUMIERA_ERROR_SET (filehandle, ERRNO, lumiera_filedescriptor_name (self->descriptor)); + FIXME ("Handle EMFILE etc with the resourcecollector"); + LUMIERA_ERROR_SET_CRITICAL (filehandle, ERRNO, lumiera_filedescriptor_name (self->descriptor)); } else { @@ -92,13 +93,15 @@ lumiera_filehandle_handle (LumieraFilehandle self) if (fstat (fd, &st) == -1) { close (fd); - LUMIERA_ERROR_SET (filehandle, ERRNO, lumiera_filedescriptor_name (self->descriptor)); + fd = -1; + LUMIERA_ERROR_SET_CRITICAL (filehandle, ERRNO, lumiera_filedescriptor_name (self->descriptor)); } else if (!lumiera_filedescriptor_samestat (self->descriptor, &st)) { close (fd); + fd = -1; /* Woops this is not the file we expected to use */ - LUMIERA_ERROR_SET (filehandle, FILE_CHANGED, lumiera_filedescriptor_name (self->descriptor)); + LUMIERA_ERROR_SET_CRITICAL (filehandle, FILE_CHANGED, lumiera_filedescriptor_name (self->descriptor)); } } self->fd = fd; diff --git a/src/backend/filehandlecache.c b/src/backend/filehandlecache.c index 23dd5fb74..fcec07202 100644 --- a/src/backend/filehandlecache.c +++ b/src/backend/filehandlecache.c @@ -84,8 +84,9 @@ lumiera_filehandlecache_handle_acquire (LumieraFilehandlecache self, LumieraFile /* allocate new filehandle if we are below the limit or no cached handles are available (overallocating) */ NOTICE (filehandlecache, "overallocating filehandle"); ret = lumiera_filehandle_new (desc); + TODO ("use resourcecollector here"); if (!ret) - LUMIERA_ERROR_SET (filehandlecache, FILEHANDLECACHE_NOHANDLE, lumiera_filedescriptor_name (desc)); + LUMIERA_ERROR_SET_ALERT (filehandlecache, FILEHANDLECACHE_NOHANDLE, lumiera_filedescriptor_name (desc)); else --self->available; } diff --git a/src/backend/mmap.c b/src/backend/mmap.c index f39bafc12..d06c8effb 100644 --- a/src/backend/mmap.c +++ b/src/backend/mmap.c @@ -124,6 +124,7 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, off_t start, size_t size) { TODO ("check if current mmapped size exceeds configured as_size (as_size be smaller than retrieved from getrlimit())"); + TODO ("use resourcecllector here"); switch (strategy++) { case FIRST_TRY: @@ -173,7 +174,7 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, off_t start, size_t size) break; case GIVE_UP: - LUMIERA_ERROR_SET (mmap, MMAP_SPACE, lumiera_filedescriptor_name (file->descriptor)); + LUMIERA_ERROR_SET_ALERT (mmap, MMAP_SPACE, lumiera_filedescriptor_name (file->descriptor)); goto espace; } diff --git a/src/common/config.c b/src/common/config.c index 34d78dcdb..af994ab64 100644 --- a/src/common/config.c +++ b/src/common/config.c @@ -208,7 +208,7 @@ lumiera_config_get (const char* key, const char** value) *value = item->delim+1; } else - LUMIERA_ERROR_SET (configsys, CONFIG_NO_ENTRY, key); + LUMIERA_ERROR_SET_WARNING (configsys, CONFIG_NO_ENTRY, key); } } else diff --git a/src/common/config_typed.c b/src/common/config_typed.c index 4fb55e6cc..aec3fce6c 100644 --- a/src/common/config_typed.c +++ b/src/common/config_typed.c @@ -82,7 +82,7 @@ lumiera_config_number_get (const char* key, long long* value) } } else - LUMIERA_ERROR_SET (configsys, CONFIG_NO_ENTRY, key); + LUMIERA_ERROR_SET_WARNING (configsys, CONFIG_NO_ENTRY, key); } } @@ -208,7 +208,7 @@ lumiera_config_string_get (const char* key, const char** value) *value = scan_string (raw_value); } else - LUMIERA_ERROR_SET (configsys, CONFIG_NO_ENTRY, key); + LUMIERA_ERROR_SET_WARNING (configsys, CONFIG_NO_ENTRY, key); } } @@ -253,7 +253,7 @@ lumiera_config_wordlist_get (const char* key, const char** value) *value = raw_value; } else - LUMIERA_ERROR_SET (configsys, CONFIG_NO_ENTRY, key); + LUMIERA_ERROR_SET_WARNING (configsys, CONFIG_NO_ENTRY, key); TODO ("remove the ERROR_SET because config_get sets it already? also in all other getters in this file"); } @@ -322,7 +322,7 @@ lumiera_config_word_get (const char* key, const char** value) *value = scan_word (raw_value); } else - LUMIERA_ERROR_SET (configsys, CONFIG_NO_ENTRY, key); + LUMIERA_ERROR_SET_WARNING (configsys, CONFIG_NO_ENTRY, key); } } diff --git a/src/common/plugin.c b/src/common/plugin.c index e5045b8e9..ae71ea8b3 100644 --- a/src/common/plugin.c +++ b/src/common/plugin.c @@ -289,7 +289,7 @@ lumiera_plugin_register (LumieraPlugin plugin) } else { - LUMIERA_ERROR_SET (plugin, PLUGIN_REGISTER, plugin->name); + LUMIERA_ERROR_SET_CRITICAL (plugin, PLUGIN_REGISTER, plugin->name); } } return !!lumiera_error_peek(); From 4172bdf17f66308df407f807f565d8d51e63f3f2 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 15 Jan 2009 01:34:01 +0100 Subject: [PATCH 003/216] move vgsuppression to tests/tool, it will only needed for running tests --- Makefile.am | 1 + src/tool/Makefile.am | 6 ------ src/tool/SConscript | 2 -- tests/tool/Makefile.am | 24 ++++++++++++++++++++++++ tests/tool/SConscript | 14 ++++++++++++++ {src => tests}/tool/vgsuppression.c | 0 6 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 tests/tool/Makefile.am create mode 100644 tests/tool/SConscript rename {src => tests}/tool/vgsuppression.c (100%) diff --git a/Makefile.am b/Makefile.am index c8703c6fa..ac8c0a1b4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,6 +64,7 @@ include $(top_srcdir)/icons/Makefile.am include $(top_srcdir)/tests/lib/Makefile.am include $(top_srcdir)/tests/components/Makefile.am include $(top_srcdir)/tests/Makefile.am +include $(top_srcdir)/tests/tool/Makefile.am #EXTRA_DIST += admin debian doc depcomp README.BUILD LICENSE \ # cinelerra-cvs-current.spec diff --git a/src/tool/Makefile.am b/src/tool/Makefile.am index f9445f934..4f6d14b6e 100644 --- a/src/tool/Makefile.am +++ b/src/tool/Makefile.am @@ -24,12 +24,6 @@ luidgen_LDADD = liblumiera.la $(NOBUGMT_LUMIERA_LIBS) liblumiera luidgen_SOURCES = $(lumitool_srcdir)/luidgen.c -noinst_PROGRAMS += vgsuppression -vgsuppression_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -vgsuppression_LDADD = liblumiera.la $(NOBUGMT_LUMIERA_LIBS) -ldl liblumieracommon.la liblumieraproc.la -lboost_regex-mt -lboost_program_options-mt -ldl -vgsuppression_SOURCES = $(lumitool_srcdir)/vgsuppression.c - - noinst_PROGRAMS += rsvg-convert 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/src/tool/SConscript b/src/tool/SConscript index 0ca19490d..bea1305ed 100644 --- a/src/tool/SConscript +++ b/src/tool/SConscript @@ -7,7 +7,6 @@ Import('env','envGtk','artifacts','core') support_lib = artifacts['support'] -vgsuppr = env.Program('#$BINDIR/vgsuppression','vgsuppression.c', LIBS=core) ## for suppressing false valgrind alarms luidgen = env.Program('#$BINDIR/luidgen', 'luidgen.c', LIBS=support_lib) ## for rendering SVG icons (uses librsvg) rsvg = envGtk.Program('#$BINDIR/rsvg-convert','rsvg-convert.c') @@ -17,7 +16,6 @@ rsvg = envGtk.Program('#$BINDIR/rsvg-convert','rsvg-convert.c') artifacts['tools'] = [ env.Program('#$BINDIR/hello-world','hello.c') #### hello world (checks C build) + env.Program('#$BINDIR/try', 'try.cpp') #### to try out some feature... + luidgen - + vgsuppr + rsvg ] diff --git a/tests/tool/Makefile.am b/tests/tool/Makefile.am new file mode 100644 index 000000000..be9f5b5ef --- /dev/null +++ b/tests/tool/Makefile.am @@ -0,0 +1,24 @@ +# 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. + +lumitesttool_srcdir = $(top_srcdir)/tests/tool + +noinst_PROGRAMS += vgsuppression +vgsuppression_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror +vgsuppression_LDADD = liblumiera.la $(NOBUGMT_LUMIERA_LIBS) -ldl liblumieracommon.la liblumieraproc.la -lboost_regex-mt -lboost_program_options-mt -ldl +vgsuppression_SOURCES = $(lumitesttool_srcdir)/vgsuppression.c + diff --git a/tests/tool/SConscript b/tests/tool/SConscript new file mode 100644 index 000000000..83e25b99d --- /dev/null +++ b/tests/tool/SConscript @@ -0,0 +1,14 @@ +# -*- python -*- +## +## SConscript - SCons buildscript for tool subdirectory (called by SConstruct) +## + +Import('env','envGtk','artifacts','core') + +support_lib = artifacts['support'] + +vgsuppr = env.Program('#$BINDIR/vgsuppression','vgsuppression.c', LIBS=core) ## for suppressing false valgrind alarms + +# build additional test +artifacts['tools'] = [vgsuppr] + diff --git a/src/tool/vgsuppression.c b/tests/tool/vgsuppression.c similarity index 100% rename from src/tool/vgsuppression.c rename to tests/tool/vgsuppression.c From 0b5fb555b6a3878926bac0844fd8b3db1b1e99c7 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Thu, 15 Jan 2009 18:54:13 +0000 Subject: [PATCH 004/216] Added dragging of whole branches --- .../timeline/timeline-layout-helper.cpp | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 4efb2cf2a..2d5f1d22b 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -243,24 +243,28 @@ TimelineLayoutHelper::layout_headers_recursive( REQUIRE(depth >= 0); int child_offset = 0; - + TrackTree::sibling_iterator iterator; for(iterator = layoutTree.begin(parent_iterator); iterator != layoutTree.end(parent_iterator); iterator++) { Gdk::Rectangle rect; + int track_height = 0; + const shared_ptr &model_track = *iterator; REQUIRE(model_track); - shared_ptr timeline_track = lookup_timeline_track(model_track); + + const bool being_dragged = (timeline_track == draggingTrack); // Is the track going to be shown? if(parent_expanded) { // Calculate and store the box of the header - const int track_height = timeline_track->get_height(); + track_height = timeline_track->get_height() + + TimelineWidget::TrackPadding; const int indent = depth * indent_width; rect = Gdk::Rectangle( @@ -270,19 +274,15 @@ TimelineLayoutHelper::layout_headers_recursive( track_height); // height // Offset for the next header - child_offset += track_height + TimelineWidget::TrackPadding; + child_offset += track_height; // Is this header being dragged? - if(timeline_track == draggingTrack) - { - rect.set_y(dragPoint.get_y() - dragStartOffset.get_y()); - } + if(being_dragged) + rect.set_y(dragPoint.get_y() - dragStartOffset.get_y()); headerBoxes[timeline_track] = rect; } - - // Is the track animating? const bool is_track_animating = timeline_track->is_expand_animating(); @@ -292,10 +292,11 @@ TimelineLayoutHelper::layout_headers_recursive( const bool expand_child = (animating || timeline_track->get_expanded()) && parent_expanded; - + int child_branch_height = layout_headers_recursive( - iterator, branch_offset + child_offset, - header_width, indent_width, depth + 1, expand_child); + iterator, rect.get_y() + track_height, + header_width, indent_width, depth + 1, + expand_child); // Do collapse animation as necessary if(is_track_animating) From c9d269872e6e1fbaa946cae7efb99c6a23f0cc30 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Thu, 15 Jan 2009 18:57:58 +0000 Subject: [PATCH 005/216] Fixed a bug with dragging when the timeline is scrolled down --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 2d5f1d22b..a47097854 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -139,7 +139,8 @@ TimelineLayoutHelper::begin_dragging_track( const Gdk::Rectangle &rect = headerBoxes[draggingTrack]; dragStartOffset = Gdk::Point( mouse_point.get_x() - rect.get_x(), - mouse_point.get_y() - rect.get_y()); + mouse_point.get_y() - rect.get_y() + + timelineWidget.get_y_scroll_offset()); // Find the track in the tree const shared_ptr model_track = @@ -187,7 +188,7 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) const weak_ptr track = lookup_timeline_track(*iterator); - if(util::pt_in_rect(point, headerBoxes[track])) + if(util::pt_in_rect(dragPoint, headerBoxes[track])) { // Relocate the header draggingTrackIter = layoutTree.move_after( From e4208803e069bf5788a00e14fba73f92c5af2ea8 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 16 Jan 2009 00:10:20 +0100 Subject: [PATCH 006/216] FIX: use .lum extension for the pluginexample.c --- tests/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index e1f01fc90..750acb887 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -78,13 +78,12 @@ test_config_LDADD = \ check_LTLIBRARIES += examplepluginc.la examplepluginc_la_SOURCES = $(tests_srcdir)/plugin/examplepluginc/example_plugin.c 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 +examplepluginc_la_LDFLAGS = -module -avoid-version -no-undefined -rpath /dev/null -shrext .lum check_PROGRAMS += test-interfaces test_interfaces_SOURCES = $(tests_srcdir)/common/test-interfaces.c test_interfaces_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_interfaces_LDADD = liblumiera.la $(LUMIERA_PLUGIN_LIBS) $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt -test_interfaces_DEPENDENCIES = examplepluginc.la liblumiera.la check_PROGRAMS += test-filemmap test_filemmap_SOURCES = $(tests_srcdir)/backend/test-filemmap.c From bb8ad9fbd51713cdb9515e3dcaa69153dba44f04 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 16 Jan 2009 02:18:58 +0100 Subject: [PATCH 007/216] move threads back into the backend --- src/backend/Makefile.am | 11 +++-------- src/{lib => backend}/thread-wrapper.hpp | 2 +- src/{lib => backend}/threads.c | 2 +- src/{lib => backend}/threads.h | 0 src/gui/guistart.cpp | 2 +- src/lib/Makefile.am | 2 -- tests/lib/subsystem-runner-test.cpp | 2 +- tests/lib/thread-wrapper-test.cpp | 2 +- 8 files changed, 8 insertions(+), 15 deletions(-) rename src/{lib => backend}/thread-wrapper.hpp (99%) rename src/{lib => backend}/threads.c (99%) rename src/{lib => backend}/threads.h (100%) diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 75bcc0d7e..c2161cc82 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -25,6 +25,7 @@ liblumierabackend_la_LIBADD = liblumiera.la liblumierabackend_la_SOURCES = \ $(liblumierabackend_la_srcdir)/mediaaccessfacade.cpp \ $(liblumierabackend_la_srcdir)/backend.c \ + $(liblumierabackend_la_srcdir)/threads.c \ $(liblumierabackend_la_srcdir)/file.c \ $(liblumierabackend_la_srcdir)/filehandle.c \ $(liblumierabackend_la_srcdir)/filedescriptor.c \ @@ -39,6 +40,7 @@ liblumierabackend_la_SOURCES = \ noinst_HEADERS += \ $(liblumierabackend_la_srcdir)/backend.h \ + $(liblumierabackend_la_srcdir)/threads.h \ $(liblumierabackend_la_srcdir)/file.h \ $(liblumierabackend_la_srcdir)/filehandle.h \ $(liblumierabackend_la_srcdir)/filedescriptor.h \ @@ -46,11 +48,4 @@ noinst_HEADERS += \ $(liblumierabackend_la_srcdir)/mmap.h \ $(liblumierabackend_la_srcdir)/mmapings.h \ $(liblumierabackend_la_srcdir)/mmapcache.h - $(liblumierabackend_la_srcdir)/backend.h \ - $(liblumierabackend_la_srcdir)/file.h \ - $(liblumierabackend_la_srcdir)/filehandle.h \ - $(liblumierabackend_la_srcdir)/filedescriptor.h \ - $(liblumierabackend_la_srcdir)/filehandlecache.h \ - $(liblumierabackend_la_srcdir)/mmap.h \ - $(liblumierabackend_la_srcdir)/mmapings.h \ - $(liblumierabackend_la_srcdir)/mmapcache.h + diff --git a/src/lib/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp similarity index 99% rename from src/lib/thread-wrapper.hpp rename to src/backend/thread-wrapper.hpp index 1edc110ee..3c60cda09 100644 --- a/src/lib/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -29,7 +29,7 @@ #include "lib/sync.hpp" extern "C" { -#include "lib/threads.h" +#include "backend/threads.h" } #include diff --git a/src/lib/threads.c b/src/backend/threads.c similarity index 99% rename from src/lib/threads.c rename to src/backend/threads.c index 128187095..d0feec9b8 100644 --- a/src/lib/threads.c +++ b/src/backend/threads.c @@ -23,7 +23,7 @@ //TODO: Lumiera header includes// -#include "lib/threads.h" +#include "threads.h" //TODO: internal/static forward declarations// diff --git a/src/lib/threads.h b/src/backend/threads.h similarity index 100% rename from src/lib/threads.h rename to src/backend/threads.h diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index 86a8a0ab4..e0e3b2930 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -53,7 +53,7 @@ #include "gui/guifacade.hpp" #include "gui/notification-service.hpp" #include "common/subsys.hpp" -#include "lib/thread-wrapper.hpp" +#include "backend/thread-wrapper.hpp" #include "lib/singleton.hpp" extern "C" { diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index ab9567089..10ad2f8ed 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -28,7 +28,6 @@ liblumiera_la_SOURCES = \ $(liblumiera_la_srcdir)/rwlock.c \ $(liblumiera_la_srcdir)/condition.c \ $(liblumiera_la_srcdir)/reccondition.c \ - $(liblumiera_la_srcdir)/threads.c \ $(liblumiera_la_srcdir)/luid.c \ $(liblumiera_la_srcdir)/safeclib.c \ $(liblumiera_la_srcdir)/psplay.c \ @@ -54,7 +53,6 @@ noinst_HEADERS += \ $(liblumiera_la_srcdir)/rwlock.h \ $(liblumiera_la_srcdir)/condition.h \ $(liblumiera_la_srcdir)/reccondition.h \ - $(liblumiera_la_srcdir)/threads.h \ $(liblumiera_la_srcdir)/luid.h \ $(liblumiera_la_srcdir)/safeclib.h \ $(liblumiera_la_srcdir)/psplay.h \ diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp index 06cf5ccfd..99d1fd11f 100644 --- a/tests/lib/subsystem-runner-test.cpp +++ b/tests/lib/subsystem-runner-test.cpp @@ -27,7 +27,7 @@ #include "common/option.hpp" #include "include/symbol.hpp" -#include "lib/thread-wrapper.hpp" +#include "backend/thread-wrapper.hpp" #include "lib/error.hpp" #include "lib/query.hpp" #include "lib/util.hpp" diff --git a/tests/lib/thread-wrapper-test.cpp b/tests/lib/thread-wrapper-test.cpp index e7eb0c5ab..0183cf391 100644 --- a/tests/lib/thread-wrapper-test.cpp +++ b/tests/lib/thread-wrapper-test.cpp @@ -24,7 +24,7 @@ #include "lib/test/run.hpp" #include "include/symbol.hpp" -#include "lib/thread-wrapper.hpp" +#include "backend/thread-wrapper.hpp" #include "lib/sync.hpp" #include From 7a939e5d872244000da5dde5899de01c9b71a437 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 17 Jan 2009 11:09:44 +0000 Subject: [PATCH 008/216] Added header dragging scroll slide animation --- src/gui/widgets/timeline-widget.cpp | 6 +++ src/gui/widgets/timeline-widget.hpp | 2 + .../timeline/timeline-header-container.cpp | 53 +++++++++++++++++++ .../timeline/timeline-header-container.hpp | 48 +++++++++++++++++ 4 files changed, 109 insertions(+) diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 9859a3def..0e589bba0 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -484,6 +484,12 @@ TimelineWidget::get_y_scroll_offset() const return (int)verticalAdjustment.get_value(); } +void +TimelineWidget::set_y_scroll_offset(const int offset) +{ + verticalAdjustment.set_value(offset); +} + bool TimelineWidget::on_motion_in_body_notify_event(GdkEventMotion *event) { diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index b95073230..7113d100f 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -226,6 +226,8 @@ private: int get_y_scroll_offset() const; + void set_y_scroll_offset(const int offset); + // ----- Event Handlers -----// /** diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 172c130d6..1c552182b 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -36,6 +36,13 @@ using namespace util; namespace gui { namespace widgets { namespace timeline { + +// ===== Constants ===== // + +const int TimelineHeaderContainer::ScrollSlideRateDivisor = 4; +const int TimelineHeaderContainer::ScrollSlideEventInterval = 40; + +// ===== Implementation ===== // TimelineHeaderContainer::TimelineHeaderContainer( gui::widgets::TimelineWidget &timeline_widget) : @@ -208,7 +215,19 @@ bool TimelineHeaderContainer::on_motion_notify_event ( // Are we currently dragging? if(layout.get_dragging_track()) { + // Forward the message to the layout manager layout.drag_to_point(mousePoint); + + // Is the mouse out of bounds? if so we must begin scrolling + const int height = get_allocation().get_height(); + const int y = mousePoint.get_y(); + + if(y < 0) + begin_scroll_slide(y / ScrollSlideRateDivisor); + else if(y > height) + begin_scroll_slide((y - height) / ScrollSlideRateDivisor); + else end_scroll_slide(); + return result; } @@ -304,6 +323,22 @@ TimelineHeaderContainer::on_hovering_track_changed( } + +bool +TimelineHeaderContainer::on_scroll_slide_timer() +{ + // Shift the view + const int view_height = get_allocation().get_height(); + timelineWidget.set_y_scroll_offset( + timelineWidget.get_y_scroll_offset() + + scrollSlideRate * view_height / 256); + + // Keep the layout manager updated + timelineWidget.layoutHelper.drag_to_point(mousePoint); + + // Return true to keep the timer going + return true; +} void TimelineHeaderContainer::layout_headers() @@ -365,6 +400,24 @@ TimelineHeaderContainer::lookup_timeline_track( return timeline_track; } +void +TimelineHeaderContainer::begin_scroll_slide(int scroll_slide_rate) +{ + scrollSlideRate = scroll_slide_rate; + if(!scrollSlideEvent.connected()) + scrollSlideEvent = Glib::signal_timeout().connect(sigc::mem_fun( + this, &TimelineHeaderContainer::on_scroll_slide_timer), + ScrollSlideEventInterval); +} + +void +TimelineHeaderContainer::end_scroll_slide() +{ + scrollSlideRate = 0; + if(scrollSlideEvent.connected()) + scrollSlideEvent.disconnect(); +} + } // namespace timeline } // namespace widgets } // namespace gui diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 6526244c3..9caefecee 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -139,6 +139,15 @@ private: void on_hovering_track_changed( boost::shared_ptr hovering_track); +private: + /* ===== Internal Event Handlers ===== */ + + /** + * An internal event handler, which is called when the scroll slide + * timer calls it. + */ + bool on_scroll_slide_timer(); + /* ===== Internals ===== */ private: @@ -172,6 +181,18 @@ private: **/ boost::shared_ptr lookup_timeline_track( boost::shared_ptr model_track); + + /** + * Begins, or continues a scroll slide at a given rate + * @param scroll_slide_rate The distance to slide every timer event + * in units of 1/256th of the view height. + */ + void begin_scroll_slide(int scroll_slide_rate); + + /** + * Ends a scroll slide, and disconnects the slide timer + */ + void end_scroll_slide(); private: @@ -195,11 +216,38 @@ private: * click is not processed by track headers. **/ Gtk::Menu contextMenu; + + /** + * This connection is used to represent the timer which causes scroll + * sliding to occur. + * @remarks Scroll sliding is an animated scroll which occurs when + * the user drags a header outside the area of the timeline body. + */ + sigc::connection scrollSlideEvent; + + /** + * Specifies the rate at which scroll sliding is currently taking + * place. + */ + int scrollSlideRate; //----- User Interaction State -----// boost::shared_ptr hoveringTrack; Gdk::Point mousePoint; + + /* ===== Constants ===== */ + /** + * The amount to divide the mouse overshoot by to produce the slide + * scroll rate. + * @remarks Smaller values cause faster scrolling. + */ + static const int ScrollSlideRateDivisor; + + /** + * The interval between scroll slide events in ms. + */ + static const int ScrollSlideEventInterval; friend class gui::widgets::TimelineWidget; friend class timeline::Track; From 7d19d195490501892615beff0220184dc0888c2e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 17 Jan 2009 14:27:35 +0100 Subject: [PATCH 009/216] SCons: integrated building vgsuppression into the test SConscript --- tests/SConscript | 4 ++++ tests/tool/SConscript | 14 -------------- 2 files changed, 4 insertions(+), 14 deletions(-) delete mode 100644 tests/tool/SConscript diff --git a/tests/SConscript b/tests/SConscript index e914ca001..0a3b5e314 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -63,6 +63,10 @@ artifacts['testsuite'] = ts = ( [ testExecutable(env, dir) for dir in ['lib','co +# for creating a Valgrind-Suppression file +vgsuppr = env.Program('#$BINDIR/vgsuppression','tool/vgsuppression.c', LIBS=core) ## for suppressing false valgrind alarms +artifacts['tools'] += [vgsuppr] +Depends(ts,vgsuppr) # diff --git a/tests/tool/SConscript b/tests/tool/SConscript deleted file mode 100644 index 83e25b99d..000000000 --- a/tests/tool/SConscript +++ /dev/null @@ -1,14 +0,0 @@ -# -*- python -*- -## -## SConscript - SCons buildscript for tool subdirectory (called by SConstruct) -## - -Import('env','envGtk','artifacts','core') - -support_lib = artifacts['support'] - -vgsuppr = env.Program('#$BINDIR/vgsuppression','vgsuppression.c', LIBS=core) ## for suppressing false valgrind alarms - -# build additional test -artifacts['tools'] = [vgsuppr] - From 054c652571cffb32429df2767f337dc5cd31dc30 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 15 Jan 2009 15:16:45 +0100 Subject: [PATCH 010/216] improve error handling when starting the GUI thread --- src/common/guifacade.cpp | 8 ++++---- src/gui/guifacade.hpp | 7 +++++-- src/gui/guistart.cpp | 23 ++++++++++++++++++----- src/lib/exception.cpp | 2 +- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index 408c7b1d0..4adb83d47 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -60,18 +60,18 @@ namespace gui { : theGUI_("lumieraorg_Gui", 1, 1, "lumieraorg_GuiStarterPlugin") // load GuiStarterPlugin { ASSERT (theGUI_); - this->kickOff (terminationHandle); + bool res = this->kickOff (terminationHandle); - if (lumiera_error_peek()) + if (!res || lumiera_error_peek()) throw lumiera::error::Fatal("failed to bring up GUI",lumiera_error()); } ~GuiRunner () { } - void kickOff (Subsys::SigTerm& terminationHandle) + bool kickOff (Subsys::SigTerm& terminationHandle) { - theGUI_->kickOff (reinterpret_cast (&terminationHandle)); + return theGUI_->kickOff (reinterpret_cast (&terminationHandle)); } }; diff --git a/src/gui/guifacade.hpp b/src/gui/guifacade.hpp index 5afa230f0..212a62b47 100644 --- a/src/gui/guifacade.hpp +++ b/src/gui/guifacade.hpp @@ -44,6 +44,8 @@ extern "C" { #include "common/interface.h" } +#include + namespace gui { @@ -69,6 +71,7 @@ namespace gui { * */ class GuiFacade + : boost::noncopyable { public: @@ -91,7 +94,7 @@ namespace gui { * @internal this function is invoked automatically during the GUI * loading and startup process. Don't call it manually. */ - virtual void kickOff (lumiera::Subsys::SigTerm&) =0; + virtual bool kickOff (lumiera::Subsys::SigTerm&) =0; protected: @@ -100,7 +103,7 @@ namespace gui { /** interface of the GuiStarterPlugin */ LUMIERA_INTERFACE_DECLARE (lumieraorg_Gui, 1, - LUMIERA_INTERFACE_SLOT (void, kickOff, (void*)) + LUMIERA_INTERFACE_SLOT (bool, kickOff, (void*)) ); diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index e0e3b2930..08311797c 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -70,6 +70,7 @@ using std::string; using lib::Thread; using std::tr1::bind; using lumiera::Subsys; +using lumiera::error::LUMIERA_ERROR_STATE; using gui::LUMIERA_INTERFACE_INAME(lumieraorg_Gui, 1); @@ -77,7 +78,7 @@ namespace gui { namespace { // implementation details - /** + /****************************************************************************** * Implement the necessary steps for actually making the Lumiera Gui available. * Open the business interface(s) and start up the GTK GUI main event loop. */ @@ -133,10 +134,22 @@ namespace gui { } // (End) impl details - void + + + bool kickOff (Subsys::SigTerm& terminationHandle) { - Thread ("GUI-Main", bind (&runGUI, terminationHandle)); + try + { + Thread ("GUI-Main", bind (&runGUI, terminationHandle)); + return true; // if we reach this line... + } + catch(...) + { + if (!lumiera_error_peek()) + LUMIERA_ERROR_SET (gui, STATE, "unexpected error when starting the GUI thread"); + return false; + } } } // namespace gui @@ -226,9 +239,9 @@ extern "C" { /* ================== define an lumieraorg_Gui instance =========== , NULL /* on open */ , NULL /* on close */ , LUMIERA_INTERFACE_INLINE (kickOff, "\255\142\006\244\057\170\152\312\301\372\220\323\230\026\200\065", - void, (void* termSig), + bool, (void* termSig), { - gui::kickOff (*reinterpret_cast (termSig)); + return gui::kickOff (*reinterpret_cast (termSig)); } ) ) diff --git a/src/lib/exception.cpp b/src/lib/exception.cpp index d59928025..091319110 100644 --- a/src/lib/exception.cpp +++ b/src/lib/exception.cpp @@ -79,7 +79,7 @@ namespace lumiera { desc_ (description), cause_ ("") { - lumiera_error_set (this->id_, description.c_str ()); + lumiera_error_set (this->id_, description.c_str ()); } From d1d8d164e17fdcc2a51851178db47a3e1bfe1d9e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 16 Jan 2009 23:32:45 +0100 Subject: [PATCH 011/216] fix the logging flag "sync" using the wrong parent --- src/include/nobugcfg.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/include/nobugcfg.h b/src/include/nobugcfg.h index 37b336503..a8d3d7d5a 100644 --- a/src/include/nobugcfg.h +++ b/src/include/nobugcfg.h @@ -83,15 +83,19 @@ namespace lumiera { /* declare flags used throughout the code base */ NOBUG_DECLARE_FLAG (all); NOBUG_DECLARE_FLAG (lumiera_all); + NOBUG_DECLARE_FLAG (lib_all); NOBUG_DECLARE_FLAG (lumiera); ///< master log, informative console output NOBUG_DECLARE_FLAG (operate); ///< logging channel reporting what the application does NOBUG_DECLARE_FLAG (render); ///< logging channel focusing on the render engine's workings NOBUG_DECLARE_FLAG (config); ///< logging channel covering application and session configuration NOBUG_DECLARE_FLAG (memory); ///< logging channel covering memory management issues - NOBUG_DECLARE_FLAG (sync); ///< especially for tracing synchronisation NOBUG_DECLARE_FLAG (test); + /* further flags which don't fit into any specific translation unit */ + NOBUG_DECLARE_FLAG (sync); ///< especially for tracing synchronisation + + #endif /*NOBUGCFG_H ======= (End) Part 1: DECLARATIONS ======== */ @@ -105,15 +109,18 @@ namespace lumiera { /* flags used throughout the code base... */ NOBUG_CPP_DEFINE_FLAG (all); NOBUG_CPP_DEFINE_FLAG_PARENT (lumiera_all, all); + NOBUG_CPP_DEFINE_FLAG_PARENT (lib_all, all); + NOBUG_CPP_DEFINE_FLAG_PARENT (lumiera, lumiera_all); NOBUG_CPP_DEFINE_FLAG_PARENT (config, lumiera); NOBUG_CPP_DEFINE_FLAG_PARENT (operate, lumiera); NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (render, lumiera, LOG_WARNING); NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (memory, lumiera, LOG_WARNING); - NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (sync, memory, LOG_WARNING); NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (test, all, LOG_ERR); + NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (sync, lib_all, LOG_WARNING); + #endif /*NOBUG_INIT_DEFS_ ==== (End) Part 2: DEFINITIONS ========= */ From ff78f9e535469b3d712d5bf180d14827c9261d7b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 17 Jan 2009 14:58:48 +0100 Subject: [PATCH 012/216] concept sketch --- doc/devel/draw/PlayerArch-1.svg | 412 ++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 doc/devel/draw/PlayerArch-1.svg diff --git a/doc/devel/draw/PlayerArch-1.svg b/doc/devel/draw/PlayerArch-1.svg new file mode 100644 index 000000000..8e7b3f9b8 --- /dev/null +++ b/doc/devel/draw/PlayerArch-1.svg @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + AllocationCluster + + + Ichthyostega + + + design sketch: Structure of the AllocationCluster mem manager + 2008 + + + + + + + + + + + + + + + + + Displayer + OutSink + put(Frame&) + Display(facade) + + + + createProcess(...) + OutputProcess + Player(facade) + openDisplayer(...) + + + uses + GUI (Plugin) + Backend (or Proc?) + + Displayer (Proxy) + DisplayFacade (Proxy) + + C Language Interface of the GUI-Plugin + + + actuallytalks to... + + libCommon + From 47296381a834561e526738be3bee78aeabb92d51 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 17 Jan 2009 15:05:19 +0000 Subject: [PATCH 013/216] WIP: Added keep-above code --- .../timeline/timeline-header-container.cpp | 64 ++++++++++++++++++- .../timeline/timeline-header-container.hpp | 10 +++ .../timeline/timeline-layout-helper.cpp | 32 ++++++---- .../timeline/timeline-layout-helper.hpp | 13 +++- 4 files changed, 104 insertions(+), 15 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 1c552182b..4041ab554 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -183,7 +183,7 @@ bool TimelineHeaderContainer::on_button_release_event ( // Has the user been dragging? if(layout.get_dragging_track()) - layout.end_dragging_track(); + end_drag(); return Container::on_button_release_event(event); } @@ -208,7 +208,7 @@ bool TimelineHeaderContainer::on_motion_notify_event ( if((event->state & GDK_BUTTON1_MASK) && hoveringTrack && !layout.get_dragging_track()) { - layout.begin_dragging_track(mousePoint); + begin_drag(); return result; } @@ -400,6 +400,66 @@ TimelineHeaderContainer::lookup_timeline_track( return timeline_track; } +void +TimelineHeaderContainer::begin_drag() +{ + TimelineLayoutHelper &layout = timelineWidget.layoutHelper; + + shared_ptr dragging_track = + layout.begin_dragging_track(mousePoint); + ENSURE(dragging_track); // Something strange has happened if we + // were somehow not hovering on a track + + const TimelineLayoutHelper::TrackTree::pre_order_iterator node = + layout.iterator_from_track(dragging_track->get_model_track()); + set_keep_above_recursive(node, true); +} + +void +TimelineHeaderContainer::end_drag() +{ + TimelineLayoutHelper &layout = timelineWidget.layoutHelper; + + shared_ptr dragging_track = + layout.get_dragging_track(); + ENSURE(dragging_track); // Something strange has happened if we + // were somehow not dragging on a track + + const TimelineLayoutHelper::TrackTree::pre_order_iterator node = + layout.iterator_from_track(dragging_track->get_model_track()); + set_keep_above_recursive(node, false); + + layout.end_dragging_track(); +} + +void +TimelineHeaderContainer::set_keep_above_recursive( + TimelineLayoutHelper::TrackTree::iterator_base node, + const bool keep_above) +{ + TimelineLayoutHelper::TrackTree::pre_order_iterator iter; + + const TimelineLayoutHelper::TrackTree &layout_tree = + timelineWidget.layoutHelper.get_layout_tree(); + + shared_ptr timeline_track = + lookup_timeline_track(*node); + REQUIRE(timeline_track); + + Glib::RefPtr window = + timeline_track->get_header_widget().get_window(); + ENSURE(window); // Something strange has happened if there was no + // window + window->set_keep_above(keep_above); + + for(iter = layout_tree.begin(node); + iter != layout_tree.end(node); + iter++) + { + set_keep_above_recursive(iter, keep_above); + } +} + void TimelineHeaderContainer::begin_scroll_slide(int scroll_slide_rate) { diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 9caefecee..4b2883d47 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -29,6 +29,7 @@ #define HEADER_CONTAINER_HPP #include "../../gtk-lumiera.hpp" +#include "timeline-layout-helper.hpp" namespace gui { @@ -182,6 +183,15 @@ private: boost::shared_ptr lookup_timeline_track( boost::shared_ptr model_track); + void begin_drag(); + + + void end_drag(); + + void set_keep_above_recursive( + TimelineLayoutHelper::TrackTree::iterator_base node, + const bool keep_above); + /** * Begins, or continues a scroll slide at a given rate * @param scroll_slide_rate The distance to slide every timer event diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index a47097854..dccd9d143 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -128,13 +128,13 @@ TimelineLayoutHelper::track_from_y(int y) return shared_ptr(); } -bool +shared_ptr TimelineLayoutHelper::begin_dragging_track( const Gdk::Point &mouse_point) { draggingTrack = header_from_point(mouse_point); if(!draggingTrack) - return false; + return shared_ptr(); const Gdk::Rectangle &rect = headerBoxes[draggingTrack]; dragStartOffset = Gdk::Point( @@ -142,19 +142,11 @@ TimelineLayoutHelper::begin_dragging_track( mouse_point.get_y() - rect.get_y() + timelineWidget.get_y_scroll_offset()); - // Find the track in the tree const shared_ptr model_track = draggingTrack->get_model_track(); - REQUIRE(model_track); - for(draggingTrackIter = layoutTree.begin(); - draggingTrackIter != layoutTree.end(); - draggingTrackIter++) - { - if(*draggingTrackIter == model_track) - break; - } + draggingTrackIter = iterator_from_track(model_track); - return true; + return draggingTrack; } void @@ -212,6 +204,22 @@ TimelineLayoutHelper::is_animating() const return animating; } +TimelineLayoutHelper::TrackTree::pre_order_iterator +TimelineLayoutHelper::iterator_from_track( + boost::shared_ptr model_track) +{ + REQUIRE(model_track); + + TrackTree::pre_order_iterator iter; + for(iter = layoutTree.begin(); iter != layoutTree.end(); iter++) + { + if(*iter == model_track) + break; + } + + return iter; +} + void TimelineLayoutHelper::update_layout() { diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index a93f88fa4..68f44939a 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -127,7 +127,8 @@ public: **/ boost::shared_ptr track_from_y(int y); - bool begin_dragging_track(const Gdk::Point &mouse_point); + boost::shared_ptr + begin_dragging_track(const Gdk::Point &mouse_point); void end_dragging_track(); @@ -144,6 +145,16 @@ public: int get_total_height() const; bool is_animating() const; + + /** + * A utility function which finds the iterator of a track in the + * layout tree. + * @param model_track The model track to look for. + * @return Returns the model iterator of layoutTree.end() if no + * iterator was found. + **/ + TrackTree::pre_order_iterator iterator_from_track( + boost::shared_ptr model_track); protected: From ebb552e32329395f7bc02b559e3397c4e85692bb Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 17 Jan 2009 15:38:39 +0000 Subject: [PATCH 014/216] Transitioned to references of project instead of pointers --- src/gui/gtk-lumiera.cpp | 2 +- src/gui/panels/assets-panel.cpp | 2 +- src/gui/panels/assets-panel.hpp | 2 +- src/gui/panels/panel.cpp | 6 ++---- src/gui/panels/panel.hpp | 6 +++--- src/gui/panels/timeline-panel.cpp | 6 +++--- src/gui/panels/timeline-panel.hpp | 2 +- src/gui/panels/viewer-panel.cpp | 2 +- src/gui/panels/viewer-panel.hpp | 2 +- src/gui/workspace/actions.cpp | 2 +- src/gui/workspace/workspace-window.cpp | 10 ++++------ src/gui/workspace/workspace-window.hpp | 6 +++--- 12 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index 9fd41b94e..feb73ea5b 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -65,7 +65,7 @@ GtkLumiera::main(int argc, char *argv[]) window_manager.set_theme("lumiera_ui.rc"); - WorkspaceWindow main_window(&project); + WorkspaceWindow main_window(project); kit.run(main_window); diff --git a/src/gui/panels/assets-panel.cpp b/src/gui/panels/assets-panel.cpp index 316ebf256..5ed878be8 100644 --- a/src/gui/panels/assets-panel.cpp +++ b/src/gui/panels/assets-panel.cpp @@ -26,7 +26,7 @@ namespace gui { namespace panels { -AssetsPanel::AssetsPanel(model::Project *const owner_project) : +AssetsPanel::AssetsPanel(model::Project &owner_project) : Panel(owner_project, "assets", _("Assets"), "panel_assets"), placeholder("Assets/Media") { diff --git a/src/gui/panels/assets-panel.hpp b/src/gui/panels/assets-panel.hpp index 05c473dca..4f815a78d 100644 --- a/src/gui/panels/assets-panel.hpp +++ b/src/gui/panels/assets-panel.hpp @@ -38,7 +38,7 @@ public: * Constructor * @param owner_project The project associated with this panel. **/ - AssetsPanel(model::Project *const owner_project); + AssetsPanel(model::Project &owner_project); protected: Gtk::Label placeholder; diff --git a/src/gui/panels/panel.cpp b/src/gui/panels/panel.cpp index 05fb096b1..49eb6cd47 100644 --- a/src/gui/panels/panel.cpp +++ b/src/gui/panels/panel.cpp @@ -26,12 +26,11 @@ namespace gui { namespace panels { -Panel::Panel(model::Project *const owner_project, +Panel::Panel(model::Project &owner_project, const gchar *name, const gchar *long_name, GdlDockItemBehavior behavior) : project(owner_project) { - REQUIRE(owner_project != NULL); REQUIRE(name != NULL); REQUIRE(long_name != NULL); @@ -42,12 +41,11 @@ Panel::Panel(model::Project *const owner_project, ENSURE(dock_item != NULL); } -Panel::Panel(model::Project *const owner_project, +Panel::Panel(model::Project &owner_project, const gchar *name, const gchar *long_name, const gchar *stock_id, GdlDockItemBehavior behavior) : project(owner_project) { - REQUIRE(owner_project != NULL); REQUIRE(name != NULL); REQUIRE(long_name != NULL); REQUIRE(stock_id != NULL); diff --git a/src/gui/panels/panel.hpp b/src/gui/panels/panel.hpp index 669a7a4f1..adc4f34ab 100644 --- a/src/gui/panels/panel.hpp +++ b/src/gui/panels/panel.hpp @@ -51,7 +51,7 @@ protected: * @param long_name The name to display on the caption * @param behavior The GDL behaviour of this item */ - Panel(model::Project *const owner_project, + Panel(model::Project &owner_project, const gchar *name, const gchar *long_name, GdlDockItemBehavior behavior = GDL_DOCK_ITEM_BEH_NORMAL); @@ -63,7 +63,7 @@ protected: * @param stock_id The id of the stock item to display on the caption * @param behavior The GDL behaviour of this item */ - Panel(model::Project *const owner_project, + Panel(model::Project &owner_project, const gchar *name, const gchar *long_name, const gchar *stock_id, GdlDockItemBehavior behavior = GDL_DOCK_ITEM_BEH_NORMAL); @@ -99,7 +99,7 @@ private: protected: - model::Project *const project; + model::Project &project; GdlDockItem* dock_item; }; diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp index f1ca132d2..7b9e5fe06 100644 --- a/src/gui/panels/timeline-panel.cpp +++ b/src/gui/panels/timeline-panel.cpp @@ -43,7 +43,7 @@ namespace panels { const int TimelinePanel::ZoomToolSteps = 2; // 2 seems comfortable -TimelinePanel::TimelinePanel(model::Project *const owner_project) : +TimelinePanel::TimelinePanel(model::Project &owner_project) : Panel(owner_project, "timeline", _("Timeline"), "panel_timeline"), timeIndicator(), previousButton(Stock::MEDIA_PREVIOUS), @@ -65,7 +65,7 @@ TimelinePanel::TimelinePanel(model::Project *const owner_project) : // mem_fun(this, &TimelinePanel::on_playback_period_drag_released)); // Hook up notifications - project->get_sequences().signal_changed().connect( + project.get_sequences().signal_changed().connect( mem_fun(this, &TimelinePanel::on_sequence_list_changed)); // Setup the notebook @@ -223,7 +223,7 @@ TimelinePanel::update_notebook() old_pages.swap(notebook_pages); BOOST_FOREACH( shared_ptr< model::Sequence > sequence, - project->get_sequences() ) + project.get_sequences() ) { std::map >:: iterator iterator = old_pages.find(sequence.get()); diff --git a/src/gui/panels/timeline-panel.hpp b/src/gui/panels/timeline-panel.hpp index 846d675fe..48b00d551 100644 --- a/src/gui/panels/timeline-panel.hpp +++ b/src/gui/panels/timeline-panel.hpp @@ -50,7 +50,7 @@ public: * Constructor * @param owner_project The project associated with this panel. */ - TimelinePanel(model::Project *const owner_project); + TimelinePanel(model::Project &owner_project); /** diff --git a/src/gui/panels/viewer-panel.cpp b/src/gui/panels/viewer-panel.cpp index 070dd2d29..2e8de0e9b 100644 --- a/src/gui/panels/viewer-panel.cpp +++ b/src/gui/panels/viewer-panel.cpp @@ -29,7 +29,7 @@ using namespace Gtk; namespace gui { namespace panels { -ViewerPanel::ViewerPanel(model::Project *const owner_project) : +ViewerPanel::ViewerPanel(model::Project &owner_project) : Panel(owner_project, "viewer", _("Viewer"), "panel_viewer") { //----- Pack in the Widgets -----// diff --git a/src/gui/panels/viewer-panel.hpp b/src/gui/panels/viewer-panel.hpp index 027ab1fc2..30f37f284 100644 --- a/src/gui/panels/viewer-panel.hpp +++ b/src/gui/panels/viewer-panel.hpp @@ -44,7 +44,7 @@ public: * Contructor. @param owner_project The project associated with this panel. **/ - ViewerPanel(model::Project *const owner_project); + ViewerPanel(model::Project &owner_project); protected: diff --git a/src/gui/workspace/actions.cpp b/src/gui/workspace/actions.cpp index ed5a43002..2ac749528 100644 --- a/src/gui/workspace/actions.cpp +++ b/src/gui/workspace/actions.cpp @@ -188,7 +188,7 @@ Actions::on_menu_sequence_add() dialogs::NameChooser dialog(workspaceWindow, _("Add Sequence"), _("New Sequence")); if(dialog.run() == RESPONSE_OK) - workspaceWindow.get_project()->add_new_sequence(dialog.get_name()); + workspaceWindow.get_project().add_new_sequence(dialog.get_name()); } /* ===== Track Menu Event Handlers ===== */ diff --git a/src/gui/workspace/workspace-window.cpp b/src/gui/workspace/workspace-window.cpp index ee315e026..8b673a27a 100644 --- a/src/gui/workspace/workspace-window.cpp +++ b/src/gui/workspace/workspace-window.cpp @@ -41,12 +41,10 @@ using namespace gui::model; namespace gui { namespace workspace { -WorkspaceWindow::WorkspaceWindow(Project *source_project) : +WorkspaceWindow::WorkspaceWindow(Project &source_project) : project(source_project), actions(*this) -{ - REQUIRE(source_project != NULL); - +{ layout = NULL; assetsPanel = NULL; viewerPanel = NULL; @@ -68,8 +66,8 @@ WorkspaceWindow::~WorkspaceWindow() timelinePanel->unreference(); } -Project* -WorkspaceWindow::get_project() const +Project& +WorkspaceWindow::get_project() { return project; } diff --git a/src/gui/workspace/workspace-window.hpp b/src/gui/workspace/workspace-window.hpp index 91c16d642..69951a4b9 100644 --- a/src/gui/workspace/workspace-window.hpp +++ b/src/gui/workspace/workspace-window.hpp @@ -54,18 +54,18 @@ namespace workspace { class WorkspaceWindow : public Gtk::Window { public: - WorkspaceWindow(gui::model::Project *source_project); + WorkspaceWindow(gui::model::Project &source_project); ~WorkspaceWindow(); - gui::model::Project* get_project() const; + gui::model::Project& get_project(); private: void create_ui(); /* ===== Model ===== */ private: - gui::model::Project *project; + gui::model::Project &project; /* ===== UI ===== */ private: From d16623892202c0e6596ee8cff01e8b1fd7b98566 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 17 Jan 2009 16:12:11 +0000 Subject: [PATCH 015/216] Added the new controller classes --- src/gui/Makefile.am | 4 ++ src/gui/controller/controller.cpp | 41 ++++++++++++++++ src/gui/controller/controller.hpp | 56 ++++++++++++++++++++++ src/gui/controller/playback-controller.cpp | 39 +++++++++++++++ src/gui/controller/playback-controller.hpp | 46 ++++++++++++++++++ src/gui/gtk-lumiera.cpp | 5 +- src/gui/panels/assets-panel.cpp | 4 +- src/gui/panels/assets-panel.hpp | 7 +-- src/gui/panels/panel.cpp | 8 ++-- src/gui/panels/panel.hpp | 14 +++--- src/gui/panels/timeline-panel.cpp | 15 ++++-- src/gui/panels/timeline-panel.hpp | 5 +- src/gui/panels/viewer-panel.cpp | 4 +- src/gui/panels/viewer-panel.hpp | 4 +- src/gui/workspace/workspace-window.cpp | 17 +++++-- src/gui/workspace/workspace-window.hpp | 15 +++++- 16 files changed, 249 insertions(+), 35 deletions(-) create mode 100644 src/gui/controller/controller.cpp create mode 100644 src/gui/controller/controller.hpp create mode 100644 src/gui/controller/playback-controller.cpp create mode 100644 src/gui/controller/playback-controller.hpp diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index e46c1e78d..44a77c0c3 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -163,6 +163,10 @@ libgui_la_SOURCES = \ $(lumigui_srcdir)/model/sequence.hpp \ $(lumigui_srcdir)/model/clip.cpp \ $(lumigui_srcdir)/model/clip.hpp \ + $(lumigui_srcdir)/controller/controller.cpp \ + $(lumigui_srcdir)/controller/controller.hpp \ + $(lumigui_srcdir)/controller/playback-controller.cpp \ + $(lumigui_srcdir)/controller/playback-controller.hpp \ $(lumigui_srcdir)/output/displayer.cpp \ $(lumigui_srcdir)/output/displayer.hpp \ $(lumigui_srcdir)/output/gdkdisplayer.cpp \ diff --git a/src/gui/controller/controller.cpp b/src/gui/controller/controller.cpp new file mode 100644 index 000000000..2d7deefc9 --- /dev/null +++ b/src/gui/controller/controller.cpp @@ -0,0 +1,41 @@ +/* + controllerk.cpp - Implementation of the timeline track object + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 "controller.hpp" + +namespace gui { +namespace controller { + +Controller::Controller(model::Project &model_project) : + project(model_project) +{ + +} + +PlaybackController& Controller::get_playback_controller() +{ + return playback; +} + +} // namespace controller +} // namespace gui + diff --git a/src/gui/controller/controller.hpp b/src/gui/controller/controller.hpp new file mode 100644 index 000000000..27f185e97 --- /dev/null +++ b/src/gui/controller/controller.hpp @@ -0,0 +1,56 @@ +/* + controller.hpp - Declaration of the controller object + + Copyright (C) Lumiera.org + 2009, Joel Holdsworth + + 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 controller/controller.hpp + ** This file contains the definition of the controller object + */ + +#include "playback-controller.hpp" + +#ifndef CONTROLLER_HPP +#define CONTROLLER_HPP + +namespace gui { + +namespace model { +class Project; +} // namespace model + +namespace controller { + +class Controller +{ +public: + Controller(model::Project &model_project); + + PlaybackController& get_playback_controller(); + +private: + model::Project &project; + + PlaybackController playback; +}; + +} // namespace controller +} // namespace gui + +#endif // CONTROLLER_HPP + diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp new file mode 100644 index 000000000..19f490f47 --- /dev/null +++ b/src/gui/controller/playback-controller.cpp @@ -0,0 +1,39 @@ +/* + timeline-track.cpp - Implementation of the timeline track object + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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. + +* *****************************************************/ + +// !!! This header must soon be removed when we drop Etch compatibility +#include + +#include "playback-controller.hpp" + +namespace gui { +namespace controller { + +void +PlaybackController::play() +{ + g_message("Play"); +} + +} // namespace controller +} // namespace gui + diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp new file mode 100644 index 000000000..61833206c --- /dev/null +++ b/src/gui/controller/playback-controller.hpp @@ -0,0 +1,46 @@ +/* + playback-controller.hpp - Declaration of the playback controller object + + Copyright (C) Lumiera.org + 2009, Joel Holdsworth + + 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 controller/playback-controller.hpp + ** This file contains the definition of the playback controller object + */ + +#ifndef PLAYBACK_CONTROLLER_HPP +#define PLAYBACK_CONTROLLER_HPP + +namespace gui { +namespace controller { + +class PlaybackController +{ +public: + + void play(); + +private: + void pull_frame(); +}; + +} // namespace controller +} // namespace gui + +#endif // PLAYBACK_CONTROLLER_HPP + diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index feb73ea5b..a2147b72d 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -31,6 +31,7 @@ #include "window-manager.hpp" #include "workspace/workspace-window.hpp" #include "model/project.hpp" +#include "controller/controller.hpp" extern "C" { #include "common/interface.h" @@ -43,6 +44,7 @@ using namespace Glib; using namespace gui; using namespace gui::workspace; using namespace gui::model; +using namespace gui::controller; GtkLumiera the_application; @@ -61,11 +63,12 @@ GtkLumiera::main(int argc, char *argv[]) Glib::set_application_name(AppTitle); Project project; + Controller controller(project); WindowManager window_manager; window_manager.set_theme("lumiera_ui.rc"); - WorkspaceWindow main_window(project); + WorkspaceWindow main_window(project, controller); kit.run(main_window); diff --git a/src/gui/panels/assets-panel.cpp b/src/gui/panels/assets-panel.cpp index 5ed878be8..1e189c0fc 100644 --- a/src/gui/panels/assets-panel.cpp +++ b/src/gui/panels/assets-panel.cpp @@ -26,8 +26,8 @@ namespace gui { namespace panels { -AssetsPanel::AssetsPanel(model::Project &owner_project) : - Panel(owner_project, "assets", _("Assets"), "panel_assets"), +AssetsPanel::AssetsPanel(workspace::WorkspaceWindow &workspace_window) : + Panel(workspace_window, "assets", _("Assets"), "panel_assets"), placeholder("Assets/Media") { pack_start(placeholder); diff --git a/src/gui/panels/assets-panel.hpp b/src/gui/panels/assets-panel.hpp index 4f815a78d..33513243a 100644 --- a/src/gui/panels/assets-panel.hpp +++ b/src/gui/panels/assets-panel.hpp @@ -34,11 +34,12 @@ namespace panels { class AssetsPanel : public Panel { public: + /** - * Constructor - * @param owner_project The project associated with this panel. + * Contructor. + * @param workspace_window The window that owns this panel. **/ - AssetsPanel(model::Project &owner_project); + AssetsPanel(workspace::WorkspaceWindow &workspace_window); protected: Gtk::Label placeholder; diff --git a/src/gui/panels/panel.cpp b/src/gui/panels/panel.cpp index 49eb6cd47..aa600cafd 100644 --- a/src/gui/panels/panel.cpp +++ b/src/gui/panels/panel.cpp @@ -26,10 +26,10 @@ namespace gui { namespace panels { -Panel::Panel(model::Project &owner_project, +Panel::Panel(workspace::WorkspaceWindow &workspace_window, const gchar *name, const gchar *long_name, GdlDockItemBehavior behavior) : - project(owner_project) + workspace(workspace_window) { REQUIRE(name != NULL); REQUIRE(long_name != NULL); @@ -41,10 +41,10 @@ Panel::Panel(model::Project &owner_project, ENSURE(dock_item != NULL); } -Panel::Panel(model::Project &owner_project, +Panel::Panel(workspace::WorkspaceWindow &workspace_window, const gchar *name, const gchar *long_name, const gchar *stock_id, GdlDockItemBehavior behavior) : - project(owner_project) + workspace(workspace_window) { REQUIRE(name != NULL); REQUIRE(long_name != NULL); diff --git a/src/gui/panels/panel.hpp b/src/gui/panels/panel.hpp index adc4f34ab..941afa0b8 100644 --- a/src/gui/panels/panel.hpp +++ b/src/gui/panels/panel.hpp @@ -32,8 +32,8 @@ namespace gui { -namespace model { -class Project; +namespace workspace { +class WorkspaceWindow; } namespace panels { @@ -46,24 +46,24 @@ class Panel : public Gtk::VBox protected: /** * Constructs a panel object - * @param owner_project The project associated with this panel. + * @param workspace_window The window that owns this panel. * @param name The internal name of this panel * @param long_name The name to display on the caption * @param behavior The GDL behaviour of this item */ - Panel(model::Project &owner_project, + Panel(workspace::WorkspaceWindow &workspace_window, const gchar *name, const gchar *long_name, GdlDockItemBehavior behavior = GDL_DOCK_ITEM_BEH_NORMAL); /** * Constructs a panel object with a stock item for a caption - * @param owner_project The project associated with this panel. + * @param owner_window The window that owns this panel. * @param name The internal name of this panel * @param long_name The name to display on the caption * @param stock_id The id of the stock item to display on the caption * @param behavior The GDL behaviour of this item */ - Panel(model::Project &owner_project, + Panel(workspace::WorkspaceWindow &owner_window, const gchar *name, const gchar *long_name, const gchar *stock_id, GdlDockItemBehavior behavior = GDL_DOCK_ITEM_BEH_NORMAL); @@ -99,7 +99,7 @@ private: protected: - model::Project &project; + workspace::WorkspaceWindow &workspace; GdlDockItem* dock_item; }; diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp index 7b9e5fe06..ea8215aaf 100644 --- a/src/gui/panels/timeline-panel.cpp +++ b/src/gui/panels/timeline-panel.cpp @@ -25,7 +25,9 @@ #include "../gtk-lumiera.hpp" #include "timeline-panel.hpp" +#include "../workspace/workspace-window.hpp" #include "../model/project.hpp" +#include "../controller/controller.hpp" extern "C" { #include "../../lib/time.h" @@ -43,8 +45,9 @@ namespace panels { const int TimelinePanel::ZoomToolSteps = 2; // 2 seems comfortable -TimelinePanel::TimelinePanel(model::Project &owner_project) : - Panel(owner_project, "timeline", _("Timeline"), "panel_timeline"), +TimelinePanel::TimelinePanel(workspace::WorkspaceWindow + &workspace_window) : + Panel(workspace_window, "timeline", _("Timeline"), "panel_timeline"), timeIndicator(), previousButton(Stock::MEDIA_PREVIOUS), rewindButton(Stock::MEDIA_REWIND), @@ -65,7 +68,7 @@ TimelinePanel::TimelinePanel(model::Project &owner_project) : // mem_fun(this, &TimelinePanel::on_playback_period_drag_released)); // Hook up notifications - project.get_sequences().signal_changed().connect( + workspace.get_project().get_sequences().signal_changed().connect( mem_fun(this, &TimelinePanel::on_sequence_list_changed)); // Setup the notebook @@ -119,7 +122,9 @@ TimelinePanel::~TimelinePanel() void TimelinePanel::on_play_pause() -{ +{ + workspace.get_controller().get_playback_controller().play(); + // TEST CODE! if(!is_playing()) { @@ -223,7 +228,7 @@ TimelinePanel::update_notebook() old_pages.swap(notebook_pages); BOOST_FOREACH( shared_ptr< model::Sequence > sequence, - project.get_sequences() ) + workspace.get_project().get_sequences() ) { std::map >:: iterator iterator = old_pages.find(sequence.get()); diff --git a/src/gui/panels/timeline-panel.hpp b/src/gui/panels/timeline-panel.hpp index 48b00d551..463130f5c 100644 --- a/src/gui/panels/timeline-panel.hpp +++ b/src/gui/panels/timeline-panel.hpp @@ -48,10 +48,9 @@ class TimelinePanel : public Panel public: /** * Constructor - * @param owner_project The project associated with this panel. + * @param workspace_window The window that owns this panel. */ - TimelinePanel(model::Project &owner_project); - + TimelinePanel(workspace::WorkspaceWindow &workspace_window); /** * Destructor diff --git a/src/gui/panels/viewer-panel.cpp b/src/gui/panels/viewer-panel.cpp index 2e8de0e9b..7f68b39f3 100644 --- a/src/gui/panels/viewer-panel.cpp +++ b/src/gui/panels/viewer-panel.cpp @@ -29,8 +29,8 @@ using namespace Gtk; namespace gui { namespace panels { -ViewerPanel::ViewerPanel(model::Project &owner_project) : - Panel(owner_project, "viewer", _("Viewer"), "panel_viewer") +ViewerPanel::ViewerPanel(workspace::WorkspaceWindow &workspace_window) : + Panel(workspace_window, "viewer", _("Viewer"), "panel_viewer") { //----- Pack in the Widgets -----// pack_start(display, PACK_EXPAND_WIDGET); diff --git a/src/gui/panels/viewer-panel.hpp b/src/gui/panels/viewer-panel.hpp index 30f37f284..a991014e9 100644 --- a/src/gui/panels/viewer-panel.hpp +++ b/src/gui/panels/viewer-panel.hpp @@ -42,9 +42,9 @@ class ViewerPanel : public Panel public: /** * Contructor. - @param owner_project The project associated with this panel. + * @param workspace_window The window that owns this panel. **/ - ViewerPanel(model::Project &owner_project); + ViewerPanel(workspace::WorkspaceWindow &owner_window); protected: diff --git a/src/gui/workspace/workspace-window.cpp b/src/gui/workspace/workspace-window.cpp index 8b673a27a..24557053d 100644 --- a/src/gui/workspace/workspace-window.cpp +++ b/src/gui/workspace/workspace-window.cpp @@ -37,12 +37,15 @@ using namespace Gtk; using namespace gui::model; +using namespace gui::controller; namespace gui { namespace workspace { -WorkspaceWindow::WorkspaceWindow(Project &source_project) : +WorkspaceWindow::WorkspaceWindow(Project &source_project, + gui::controller::Controller &source_controller) : project(source_project), + controller(source_controller), actions(*this) { layout = NULL; @@ -72,6 +75,12 @@ WorkspaceWindow::get_project() return project; } +Controller& +WorkspaceWindow::get_controller() +{ + return controller; +} + void WorkspaceWindow::create_ui() { @@ -150,11 +159,11 @@ WorkspaceWindow::create_ui() baseContainer.pack_start(*toolbar, Gtk::PACK_SHRINK); //----- Create the Panels -----// - assetsPanel = new AssetsPanel(project); + assetsPanel = new AssetsPanel(*this); ENSURE(assetsPanel != NULL); - viewerPanel = new ViewerPanel(project); + viewerPanel = new ViewerPanel(*this); ENSURE(viewerPanel != NULL); - timelinePanel = new TimelinePanel(project); + timelinePanel = new TimelinePanel(*this); ENSURE(timelinePanel != NULL); //----- Create the Dock -----// diff --git a/src/gui/workspace/workspace-window.hpp b/src/gui/workspace/workspace-window.hpp index 69951a4b9..fb0254d2d 100644 --- a/src/gui/workspace/workspace-window.hpp +++ b/src/gui/workspace/workspace-window.hpp @@ -46,6 +46,10 @@ namespace model { class Project; } // model +namespace controller { + class Controller; +} // model + namespace workspace { /** @@ -54,19 +58,26 @@ namespace workspace { class WorkspaceWindow : public Gtk::Window { public: - WorkspaceWindow(gui::model::Project &source_project); + WorkspaceWindow(gui::model::Project &source_project, + gui::controller::Controller &source_controller); ~WorkspaceWindow(); gui::model::Project& get_project(); + + gui::controller::Controller& get_controller(); private: void create_ui(); - + /* ===== Model ===== */ private: gui::model::Project &project; + /* ===== Controller ===== */ +private: + gui::controller::Controller &controller; + /* ===== UI ===== */ private: Glib::RefPtr uiManager; From d3f94730b5b07eab7ee0accd55ae024a06cd36a9 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 17 Jan 2009 16:17:42 +0000 Subject: [PATCH 016/216] Removed a spurious include --- src/gui/controller/playback-controller.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index 19f490f47..8312be602 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -20,9 +20,6 @@ * *****************************************************/ -// !!! This header must soon be removed when we drop Etch compatibility -#include - #include "playback-controller.hpp" namespace gui { From ebe91793c5ff0974a9393bf4a9d1ddf674977de4 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 17 Jan 2009 16:53:01 +0000 Subject: [PATCH 017/216] WIP: Corrected some compile problems --- src/gui/controller/playback-controller.cpp | 11 +++++++++++ src/gui/controller/playback-controller.hpp | 3 +++ src/gui/gtk-lumiera.hpp | 1 + 3 files changed, 15 insertions(+) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index 8312be602..a89036075 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -21,6 +21,7 @@ * *****************************************************/ #include "playback-controller.hpp" +#include "../gtk-lumiera.hpp" namespace gui { namespace controller { @@ -31,6 +32,16 @@ PlaybackController::play() g_message("Play"); } +void PlaybackController::playback_thread() +{ + pull_frame(); +} + +void PlaybackController::pull_frame() +{ + +} + } // namespace controller } // namespace gui diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 61833206c..ea0f8dc96 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -36,6 +36,9 @@ public: void play(); private: + + void playback_thread(); + void pull_frame(); }; diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index a01bc5dc4..7f5a8cacd 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -37,6 +37,7 @@ #include #include #include "lib/util.hpp" +#include "backend/thread-wrapper.hpp" extern "C" { #include From 9197aa2ddf1d3f1e2463ef66a391d151522c384a Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 17 Jan 2009 17:37:06 +0000 Subject: [PATCH 018/216] WIP: PlaybackController can now push frames to the Viewer --- src/gui/controller/playback-controller.cpp | 13 ++++++++++++- src/gui/controller/playback-controller.hpp | 7 +++++++ src/gui/gtk-lumiera.hpp | 1 - src/gui/panels/viewer-panel.cpp | 21 ++++++++++++++++++++- src/gui/panels/viewer-panel.hpp | 4 ++++ src/gui/widgets/video-display-widget.cpp | 6 ++++++ src/gui/widgets/video-display-widget.hpp | 2 ++ 7 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index a89036075..d69d3f7ce 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -29,7 +29,13 @@ namespace controller { void PlaybackController::play() { - g_message("Play"); + pull_frame(); +} + +void +PlaybackController::attach_viewer(const sigc::slot& on_frame) +{ + frame_signal.connect(on_frame); } void PlaybackController::playback_thread() @@ -39,7 +45,12 @@ void PlaybackController::playback_thread() void PlaybackController::pull_frame() { + unsigned char buffer[320 * 240 * 4]; + + for(int i = 0; i < 320*240*4; i++) + buffer[i] = rand(); + frame_signal.emit(buffer); } } // namespace controller diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index ea0f8dc96..601fb9d2b 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -23,6 +23,8 @@ ** This file contains the definition of the playback controller object */ +#include + #ifndef PLAYBACK_CONTROLLER_HPP #define PLAYBACK_CONTROLLER_HPP @@ -34,12 +36,17 @@ class PlaybackController public: void play(); + + void attach_viewer(const sigc::slot& on_frame); private: void playback_thread(); void pull_frame(); + +private: + sigc::signal frame_signal; }; } // namespace controller diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index 7f5a8cacd..a01bc5dc4 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -37,7 +37,6 @@ #include #include #include "lib/util.hpp" -#include "backend/thread-wrapper.hpp" extern "C" { #include diff --git a/src/gui/panels/viewer-panel.cpp b/src/gui/panels/viewer-panel.cpp index 7f68b39f3..f012a406e 100644 --- a/src/gui/panels/viewer-panel.cpp +++ b/src/gui/panels/viewer-panel.cpp @@ -23,8 +23,13 @@ #include "../gtk-lumiera.hpp" #include "viewer-panel.hpp" -using namespace gui::widgets; +#include "../workspace/workspace-window.hpp" +#include "../controller/controller.hpp" +#include "../controller/playback-controller.hpp" + using namespace Gtk; +using namespace gui::widgets; +using namespace gui::controller; namespace gui { namespace panels { @@ -34,6 +39,20 @@ ViewerPanel::ViewerPanel(workspace::WorkspaceWindow &workspace_window) : { //----- Pack in the Widgets -----// pack_start(display, PACK_EXPAND_WIDGET); + + PlaybackController &playback = + workspace_window.get_controller().get_playback_controller(); + + playback.attach_viewer(sigc::mem_fun(this, &ViewerPanel::on_frame)); +} + +void +ViewerPanel::on_frame(void *buffer) +{ + Displayer *displayer = display.get_displayer(); + REQUIRE(displayer); + + displayer->put(buffer); } } // namespace panels diff --git a/src/gui/panels/viewer-panel.hpp b/src/gui/panels/viewer-panel.hpp index a991014e9..b56fb3701 100644 --- a/src/gui/panels/viewer-panel.hpp +++ b/src/gui/panels/viewer-panel.hpp @@ -45,6 +45,10 @@ public: * @param workspace_window The window that owns this panel. **/ ViewerPanel(workspace::WorkspaceWindow &owner_window); + +protected: + + void on_frame(void *buffer); protected: diff --git a/src/gui/widgets/video-display-widget.cpp b/src/gui/widgets/video-display-widget.cpp index 0c396ed4d..1f9dca844 100644 --- a/src/gui/widgets/video-display-widget.cpp +++ b/src/gui/widgets/video-display-widget.cpp @@ -45,6 +45,12 @@ VideoDisplayWidget::~VideoDisplayWidget() delete displayer; } +Displayer* +VideoDisplayWidget::get_displayer() const +{ + return displayer; +} + void VideoDisplayWidget::on_realize() { diff --git a/src/gui/widgets/video-display-widget.hpp b/src/gui/widgets/video-display-widget.hpp index 6bf829f7a..5ea827d81 100644 --- a/src/gui/widgets/video-display-widget.hpp +++ b/src/gui/widgets/video-display-widget.hpp @@ -41,6 +41,8 @@ public: VideoDisplayWidget(); ~VideoDisplayWidget(); + + Displayer* get_displayer() const; /* ===== Overrides ===== */ private: From b0db84ec148b3c6671f3efd03f34cb4148db6878 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sun, 18 Jan 2009 16:17:39 +0000 Subject: [PATCH 019/216] Implemented intial playback controller thread --- configure.ac | 6 +- src/gui/controller/playback-controller.cpp | 86 +++++++++++++++++++--- src/gui/controller/playback-controller.hpp | 28 +++++++ src/gui/gtk-lumiera.cpp | 1 + src/gui/panels/timeline-panel.cpp | 30 +++----- src/gui/panels/timeline-panel.hpp | 4 +- src/gui/widgets/video-display-widget.cpp | 15 ---- src/gui/widgets/video-display-widget.hpp | 3 - 8 files changed, 122 insertions(+), 51 deletions(-) diff --git a/configure.ac b/configure.ac index 717fe6f4b..1b2ec96dc 100644 --- a/configure.ac +++ b/configure.ac @@ -141,9 +141,9 @@ PKG_CHECK_MODULES(LUMIERA_COMMON_LIBS, [sigc++-2.0 >= 2.0.17]) # gtk+-2.0 >= 2.12 gtkmm-2.4 >= 2.12 for Debian Lenny compatibility PKG_CHECK_MODULES(LUMIERA_GUI, [ - gtk+-2.0 >= 2.8 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]) + gtk+-2.0 >= 2.8 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 + gthread-2.0 >= 2.12.4]) # END Gtk Dependancies diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index d69d3f7ce..44251278a 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -26,30 +26,94 @@ namespace gui { namespace controller { -void -PlaybackController::play() +PlaybackController::PlaybackController() : + finish_playback_thread(false), + playing(false) { - pull_frame(); + start_playback_thread(); +} + +PlaybackController::~PlaybackController() +{ + mutex.lock(); + finish_playback_thread = true; + mutex.unlock(); + thread->join(); } void -PlaybackController::attach_viewer(const sigc::slot& on_frame) +PlaybackController::play() +{ + Glib::Mutex::Lock lock(mutex); + playing = true; +} + +void +PlaybackController::pause() +{ + Glib::Mutex::Lock lock(mutex); + playing = false; +} + +void +PlaybackController::stop() +{ + Glib::Mutex::Lock lock(mutex); + playing = false; +} + +bool +PlaybackController::is_playing() +{ + Glib::Mutex::Lock lock(mutex); + return playing; +} + +void +PlaybackController::start_playback_thread() +{ + dispatcher.connect(sigc::mem_fun(this, &PlaybackController::on_frame)); + thread = Glib::Thread::create (sigc::mem_fun( + this, &PlaybackController::playback_thread), true); +} + +void +PlaybackController::attach_viewer( + const sigc::slot& on_frame) { frame_signal.connect(on_frame); } -void PlaybackController::playback_thread() -{ - pull_frame(); +void +PlaybackController::playback_thread() +{ + for(;;) + { + { + Glib::Mutex::Lock lock(mutex); + if(finish_playback_thread) + return; + } + + if(is_playing()) + pull_frame(); + + Glib::Thread::yield(); + } } -void PlaybackController::pull_frame() +void +PlaybackController::pull_frame() { - unsigned char buffer[320 * 240 * 4]; - for(int i = 0; i < 320*240*4; i++) buffer[i] = rand(); - + + dispatcher.emit(); +} + +void +PlaybackController::on_frame() +{ frame_signal.emit(buffer); } diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 601fb9d2b..9333fcbc2 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -24,6 +24,7 @@ */ #include +#include #ifndef PLAYBACK_CONTROLLER_HPP #define PLAYBACK_CONTROLLER_HPP @@ -35,17 +36,44 @@ class PlaybackController { public: + PlaybackController(); + + ~PlaybackController(); + void play(); + + void pause(); + + void stop(); + + bool is_playing(); void attach_viewer(const sigc::slot& on_frame); private: + void start_playback_thread(); + void playback_thread(); void pull_frame(); + void on_frame(); + private: + + Glib::Thread *thread; + + Glib::StaticMutex mutex; + + Glib::Dispatcher dispatcher; + + volatile bool finish_playback_thread; + + volatile bool playing; + + unsigned char buffer[320 * 240 * 4]; + sigc::signal frame_signal; }; diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index a2147b72d..eb8fbe023 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -57,6 +57,7 @@ namespace gui { void GtkLumiera::main(int argc, char *argv[]) { + Glib::thread_init(); Main kit(argc, argv); diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp index ea8215aaf..0c7a566cb 100644 --- a/src/gui/panels/timeline-panel.cpp +++ b/src/gui/panels/timeline-panel.cpp @@ -123,16 +123,13 @@ TimelinePanel::~TimelinePanel() void TimelinePanel::on_play_pause() { - workspace.get_controller().get_playback_controller().play(); - - // TEST CODE! if(!is_playing()) { play(); } else { - frameEvent.disconnect(); + pause(); } update_playback_buttons(); @@ -141,12 +138,8 @@ TimelinePanel::on_play_pause() void TimelinePanel::on_stop() { - // TEST CODE! - /*timelineWidget.set_playback_point(GAVL_TIME_UNDEFINED); - frameEvent.disconnect(); - show_time(timelineWidget.get_playback_period_start()); - - update_playback_buttons();*/ + workspace.get_controller().get_playback_controller().stop(); + update_playback_buttons(); } void @@ -288,20 +281,21 @@ TimelinePanel::update_zoom_buttons() void TimelinePanel::play() +{ + workspace.get_controller().get_playback_controller().play(); +} + +void +TimelinePanel::pause() { - /*if(timelineWidget.get_playback_point() == GAVL_TIME_UNDEFINED) - timelineWidget.set_playback_point( - timelineWidget.get_playback_period_start()); - frameEvent = Glib::signal_timeout().connect( - sigc::mem_fun(this, &TimelinePanel::on_frame), - 1000 / 25);*/ + workspace.get_controller().get_playback_controller().pause(); } bool TimelinePanel::is_playing() const { - // TEST CODE! - this should be hooked up to the real playback control - return frameEvent.connected(); + return workspace.get_controller().get_playback_controller(). + is_playing(); } void diff --git a/src/gui/panels/timeline-panel.hpp b/src/gui/panels/timeline-panel.hpp index 463130f5c..9c860b05a 100644 --- a/src/gui/panels/timeline-panel.hpp +++ b/src/gui/panels/timeline-panel.hpp @@ -87,6 +87,9 @@ private: void update_zoom_buttons(); void play(); + + void pause(); + bool is_playing() const; void set_tool(gui::widgets::timeline::ToolType tool); @@ -137,7 +140,6 @@ private: private: // TEST CODE bool on_frame(); - sigc::connection frameEvent; //----- Constants -----// private: diff --git a/src/gui/widgets/video-display-widget.cpp b/src/gui/widgets/video-display-widget.cpp index 1f9dca844..4a31af101 100644 --- a/src/gui/widgets/video-display-widget.cpp +++ b/src/gui/widgets/video-display-widget.cpp @@ -67,21 +67,6 @@ VideoDisplayWidget::on_realize() add_events(Gdk::ALL_EVENTS_MASK); } -bool -VideoDisplayWidget::on_button_press_event (GdkEventButton* event) -{ - (void)event; - - unsigned char buffer[320 * 240 * 4]; - - for(int i = 0; i < 320*240*4; i++) - buffer[i] = rand(); - - displayer->put((void*)buffer); - - return true; -} - Displayer* VideoDisplayWidget::createDisplayer( Gtk::Widget *drawingArea, int width, int height ) { diff --git a/src/gui/widgets/video-display-widget.hpp b/src/gui/widgets/video-display-widget.hpp index 5ea827d81..6587362cf 100644 --- a/src/gui/widgets/video-display-widget.hpp +++ b/src/gui/widgets/video-display-widget.hpp @@ -47,9 +47,6 @@ public: /* ===== Overrides ===== */ private: virtual void on_realize(); - - // TEST CODE!!!! - virtual bool on_button_press_event (GdkEventButton* event); /* ===== Internals ===== */ private: From 20b2cb1ee536f3bd7f6c725828350d01f4b3cded Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sun, 18 Jan 2009 17:41:55 +0000 Subject: [PATCH 020/216] Implemented a funky test card generator --- src/gui/controller/playback-controller.cpp | 89 +++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index 44251278a..07a1fbd6d 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -102,11 +102,96 @@ PlaybackController::playback_thread() } } +typedef unsigned char byte; + +inline int +clamp(const int &val, const int &maxval, const int &minval) +{ + if(val > maxval) return maxval; + if(val < minval) return minval; + return val; +} + +inline void +rgb_to_yuv(int r, int g, int b, byte &y, byte &u, byte &v) +{ + // This code isn't great, but it does the job + y = (byte)clamp((299 * r + 587 * g + 114 * b) / 1000, 235, 16); + v = (byte)clamp((500 * r - 419 * g - 81 * b) / 1000 + 127, 255, 0); + u = (byte)clamp((-169 * r - 331 * g + 500 * b) / 1000 + 127, 255, 0); +} + +void rgb_buffer_to_yuy2(unsigned char *in, unsigned char *out) +{ + for(int i = 0; i < 320*240*2; i+=4) + { + byte y0, u0, v0; + const byte r0 = *(in++); + const byte g0 = *(in++); + const byte b0 = *(in++); + rgb_to_yuv(r0, g0, b0, y0, u0, v0); + + byte y1, u1, v1; + const byte r1 = *(in++); + const byte g1 = *(in++); + const byte b1 = *(in++); + rgb_to_yuv(r1, g1, b1, y1, u1, v1); + + out[i] = y0; + out[i + 1] = (byte)(((int)u0 + (int)u1) / 2); + out[i + 2] = y1; + out[i + 3] = (byte)(((int)v0 + (int)v1) / 2); + } +} + void PlaybackController::pull_frame() { - for(int i = 0; i < 320*240*4; i++) - buffer[i] = rand(); + static int frame = 0; + unsigned char in[320 * 240 * 3]; + + frame--; + + if(frame <= 0) + frame = 200; + + if(frame > 150) + { + for(int i = 0; i < 320*240*3; i+=3) + { + byte value = (byte)rand(); + in[i] = value; + in[i+1] = value; + in[i+2] = value; + } + } + else + { + unsigned char row[320 * 3]; + + + for(int x = 0; x < 320; x++) + { + byte &r = row[x*3]; + byte &g = row[x*3+1]; + byte &b = row[x*3+2]; + + if(x < 1*320/7) r = 0xC0, g = 0xC0, b = 0xC0; + else if(x < 2*320/7) r = 0xC0, g = 0xC0, b = 0x00; + else if(x < 3*320/7) r = 0x00, g = 0xC0, b = 0xC0; + else if(x < 4*320/7) r = 0x00, g = 0xC0, b = 0x00; + else if(x < 5*320/7) r = 0xC0, g = 0x00, b = 0xC0; + else if(x < 6*320/7) r = 0xC0, g = 0x00, b = 0x00; + else r = 0x00, g = 0x00, b = 0xC0; + } + + for(int y = 0; y < 240; y++) + { + memcpy(in + y*320*3, row, sizeof(row)); + } + } + + rgb_buffer_to_yuy2(in, buffer); dispatcher.emit(); } From 2679156a9c04a2ced27206cfa3245038f3b7e198 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 18 Jan 2009 15:18:58 +0100 Subject: [PATCH 021/216] Thread-wrapper: improve comments, push action down into private function --- src/backend/thread-wrapper.hpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 3c60cda09..2280d097c 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -42,8 +42,10 @@ namespace lib { using std::tr1::function; using lumiera::Literal; + typedef struct nobug_flag* NoBugFlag; - /** + + /**************************************************************************** * A thin convenience wrapper for dealing with threads, * as implemented by the backend (on top of pthread). * Using this wrapper... @@ -87,10 +89,8 @@ namespace lib { } - public: - Thread (Literal& purpose, Operation const& operation, struct nobug_flag *logging_flag = &NOBUG_FLAG(operate)) - : started_(false), - operation_(operation) + void + start_thread (Literal& purpose, NoBugFlag logging_flag) { Lock sync(this); LumieraThread res = @@ -109,6 +109,26 @@ namespace lib { // prior to leaving and thereby possibly destroying this local context sync.wait (started_); } + + public: + /** Create a new thread to execute the given operation. + * The new thread starts up synchronously, i.e. when the ctor returns, the new thread + * has started running and taken over (copied) the operation functor passed in. The + * thread will be created by lumiera_thread_run (declared in threads.h), it can't + * be cancelled and it can't be joined. + * @param purpose fixed char string used to denote the thread for diagnostics + * @param logging_flag NoBug flag to receive diagnostics regarding the new thread + * @param operation defining what to execute within the new thread. Any functor + * which can be bound to function. Note this functor will be + * copied onto the stack of the new thread, thus it can be transient. + * + */ + Thread (Literal& purpose, Operation const& operation, NoBugFlag logging_flag = &NOBUG_FLAG(operate)) ///TODO: define a dedicated flag for threads + : started_(false), + operation_(operation) + { + start_thread (purpose, logging_flag); + } }; From c6bc14375cf4e1ce3133d26a8e3a5ebd8cf024a9 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 18 Jan 2009 16:14:00 +0100 Subject: [PATCH 022/216] write a draft how I'd like to deal with joining threads. --- src/backend/thread-wrapper.hpp | 105 +++++++++++++++++++++++++++++++-- src/lib/sync.hpp | 7 +++ 2 files changed, 106 insertions(+), 6 deletions(-) diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 2280d097c..d4dfc1e70 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -44,6 +44,85 @@ namespace lib { typedef struct nobug_flag* NoBugFlag; + class Thread; + + /** + * Brainstorming-in-code: how I would like to shape the API for joining threads. + * Intended use: This non-copyable handle has to be created within the thread which + * wants to wait-blocking on the termination of another thread. You then pass it + * into the ctor of the Thread starting wrapper class (see below), which causes + * the embedded lock/condition var to be used to sync on the end of the newly + * created thread. Note, after ending the execution, the newly created thread + * will be on hold until either the #join() function is called or this handle + * goes out of scope altogether. Explanation: this is implemented by locking + * the embedded monitor immediately in the ctor. Thus, unless entering the + * wait state, the contained mutex remains locked and prevents the thread + * manager from invoking the broadcast() on the condition var. + * + * @note this is a draft. It doesn't even work, because Cehteh is still planning + * details of the thread handling and didn't implement the waiting feature. + */ + class JoinHandle + : public Sync + , Sync::Lock + { + typedef Sync SyncBase; + + bool isWaiting_; + volatile bool armed_; + + friend class Thread; + + LumieraCondition + accessLockedCondition() + { + ASSERT (!armed_, "Lifecycle error, JoinHandle used for several threads."); + armed_ = true; + return accessMonitor().accessCond(); + } + + bool + wakeupCheck() + { + if (!armed_) + throw lumiera::error::Logic ("no thread created blocking on this JoinHandle"); + + if (!isWaiting_) + { + isWaiting_ = true; + return false; // causes entering the blocking wait + } + TODO ("any possibility to detect spurious wakeups? can they happen?"); + return true; // causes end of the blocking wait + } + + + public: + /** Create a promise, that the current thread will or may + * wait-blocking on another not-yet existing thread to terminate. + * When passed in on creation of the other thread, as long as this + * handle lives, the other thread will be on hold after termination. + */ + JoinHandle() + : SyncBase::Lock(this) + , isWaiting_(false) + , armed_(false) + { } + + /** put the current thread into a blocking wait until another thread + * has terminated. This other thread needs to be created by the Thread + * wrapper, passing this JoinHandle as ctor parameter. + * @throws error::Logic if no thread has been registered to block on this + */ + void + join() + { + accessMonitor().wait (*this, &JoinHandle::wakeupCheck); + } + }; + + + /**************************************************************************** * A thin convenience wrapper for dealing with threads, @@ -65,8 +144,8 @@ namespace lib { * is superfluous in the final application. Re-evaluate this! */ class Thread - : public Sync, - boost::noncopyable + : public Sync + , boost::noncopyable { volatile bool started_; @@ -90,14 +169,14 @@ namespace lib { void - start_thread (Literal& purpose, NoBugFlag logging_flag) + start_thread (lumiera_thread_class kind, Literal& purpose, NoBugFlag logging_flag, LumieraCondition joinCond=0) { Lock sync(this); LumieraThread res = - lumiera_thread_run ( LUMIERA_THREAD_INTERACTIVE + lumiera_thread_run ( kind , &run // invoking the run helper and.. , this // passing this start context as parameter - , 0 // no condition variable provided (for now...) + , joinCond // maybe wait-blocking for the thread to terminate , purpose.c_str() , logging_flag ); @@ -127,7 +206,21 @@ namespace lib { : started_(false), operation_(operation) { - start_thread (purpose, logging_flag); + start_thread (LUMIERA_THREAD_INTERACTIVE, purpose, logging_flag); + } + + /** Variant of the standard case, used to register a JoinHandle in addition to starting a thread. + * @param join ref to a JoinHandle, which needs to be created in the thread which plans + * to wait-blocking on the termination of this newly created thread + * + */ + Thread (Literal& purpose, Operation const& operation, + JoinHandle& join, NoBugFlag logging_flag = &NOBUG_FLAG(operate)) ///TODO: define a dedicated flag for threads + : started_(false), + operation_(operation) + { + start_thread (LUMIERA_THREAD_INTERACTIVE, purpose, logging_flag, + join.accessLockedCondition()); } }; diff --git a/src/lib/sync.hpp b/src/lib/sync.hpp index ef08e7f83..4abc55993 100644 --- a/src/lib/sync.hpp +++ b/src/lib/sync.hpp @@ -331,6 +331,8 @@ namespace lib { void setTimeout(ulong relative) {timeout_.setOffset(relative);} bool isTimedWait() {return (timeout_);} + + LumieraCondition accessCond() {return static_cast (this);} }; typedef Mutex NonrecursiveLock_NoWait; @@ -419,6 +421,11 @@ namespace lib { /** for creating a ClassLock */ Lock(Monitor& m) : mon_(m) { mon_.acquireLock(); } + + /** for controlled access to the + * underlying sync primitives */ + Monitor& + accessMonitor() { return mon_; } }; From 810e531508b7534e01577b5c2da2a3a07deb547f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 18 Jan 2009 16:59:24 +0100 Subject: [PATCH 023/216] perpare a test (which of course currently fails).... --- tests/40components.tests | 4 + tests/lib/Makefile.am | 1 + tests/lib/singletonsubclasstest.cpp | 1 + tests/lib/thread-wrapper-join-test.cpp | 141 +++++++++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 tests/lib/thread-wrapper-join-test.cpp diff --git a/tests/40components.tests b/tests/40components.tests index 6ed448349..ba14f909f 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -337,6 +337,10 @@ return: 0 END +PLANNED "Waiting on Thread termination" ThreadWrapperJoin_test < + + 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/test/run.hpp" + +#include "include/symbol.hpp" +#include "backend/thread-wrapper.hpp" +#include "lib/error.hpp" +#include "lib/sync.hpp" + +#include + +using std::tr1::bind; +using test::Test; + + + +namespace lib { + namespace test { + + /************************************************************************** + * @test use the Lumiera backend to create some new threads, additionally + * passing an condition variable for waiting on thread termination. + * Actually this is implemented as creating and passing a JoinHandle. + * + * @see lib::Thread + * @see threads.h + */ + class ThreadWrapperJoin_test : public Test + { + + virtual void + run (Arg) + { + simpleUse (); + wrongUse (); + } + + + volatile int aValue_; ///< state to be modified by the other thread + + void + theAction (int secretValue) ///< to be run in a new thread... + { + sleep(1); + aValue_ = secretValue+42; + } + + + void + simpleUse () + { + aValue_=0; + int mySecret = (rand() % 1000) - 500; + + JoinHandle waitingHandle; + + Thread("test Thread joining", + bind (&ThreadWrapperJoin_test::theAction, this, mySecret), + waitingHandle); + // note binding and thread wrapper already destroyed + + waitingHandle.join(); // blocks until theAction() is done + + ASSERT (aValue_ == mySecret+42); + } + + + void + wrongUse () + { + JoinHandle waitingHandle; + + Thread("test Thread joining-1", + bind (&ThreadWrapperJoin_test::theAction, this, 111)); + // note we "forget" to pass the JoinHandle + try + { + waitingHandle.join(); // protocol error: handle wasn't passed for starting a Thread; + NOTREACHED; + } + catch (lumiera::error::Logic& logo) + { lumiera_error(); } + + + Thread("test Thread joining-2", + bind (&ThreadWrapperJoin_test::theAction, this, 222), + waitingHandle); // this time we pass it.... + +#ifdef DEBUG + /////////////////////////////////////////////////////////////////////////////////////////////TODO: better way of detecting debug builds + try + { + Thread("test Thread joining-3", + bind (&ThreadWrapperJoin_test::theAction, this, 333), + waitingHandle); // but then pass it again for another thread.... + NOTREACHED; + } + catch (...) + { + ASSERT (lumiera_error() == lumiera::error::LUMIERA_ERROR_ASSERTION); + } +#endif + + // note: the waitingHandle goes out of scope here, + // which unblocks the second thread. The first thread wasn't blocked, + // while the third thread wasn't created at all. + } + + }; + + + + /** Register this test class... */ + LAUNCHER (ThreadWrapperJoin_test, "function common"); + + + + } // namespace test + +} // namespace lib From 1be33426e47b444a2db6091db5e4aea44aaa545e Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sun, 18 Jan 2009 23:26:41 +0000 Subject: [PATCH 024/216] Reduced the hack level in the test card --- src/gui/controller/playback-controller.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index 07a1fbd6d..10e370cd3 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -138,9 +138,9 @@ void rgb_buffer_to_yuy2(unsigned char *in, unsigned char *out) rgb_to_yuv(r1, g1, b1, y1, u1, v1); out[i] = y0; - out[i + 1] = (byte)(((int)u0 + (int)u1) / 2); + out[i + 1] = u0; out[i + 2] = y1; - out[i + 3] = (byte)(((int)v0 + (int)v1) / 2); + out[i + 3] = v0; } } @@ -168,7 +168,6 @@ PlaybackController::pull_frame() else { unsigned char row[320 * 3]; - for(int x = 0; x < 320; x++) { From 198d6bde7304fc0d474ef4059513a4d15407b193 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 19 Jan 2009 02:21:41 +0100 Subject: [PATCH 025/216] better make GuiNotification an experimental interface (Version=0) --- src/gui/notification-service.cpp | 2 +- src/gui/notification-service.hpp | 2 +- src/include/guinotificationfacade.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/notification-service.cpp b/src/gui/notification-service.cpp index f713d7390..fcbec39e8 100644 --- a/src/gui/notification-service.cpp +++ b/src/gui/notification-service.cpp @@ -139,7 +139,7 @@ namespace gui { - LUMIERA_INTERFACE_INSTANCE (lumieraorg_GuiNotification, 1 + LUMIERA_INTERFACE_INSTANCE (lumieraorg_GuiNotification, 0 ,lumieraorg_GuiNotificationFacade , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_GuiNotificationFacade_descriptor) , NULL /* on open */ diff --git a/src/gui/notification-service.hpp b/src/gui/notification-service.hpp index 41e404e46..63ef677a4 100644 --- a/src/gui/notification-service.hpp +++ b/src/gui/notification-service.hpp @@ -73,7 +73,7 @@ namespace gui { /* === Interface Lifecycle === */ - typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 1) + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 0) , GuiNotification > ServiceInstanceHandle; diff --git a/src/include/guinotificationfacade.h b/src/include/guinotificationfacade.h index 9f4f91474..f3e334bff 100644 --- a/src/include/guinotificationfacade.h +++ b/src/include/guinotificationfacade.h @@ -85,7 +85,7 @@ extern "C" { #include "common/interface.h" -LUMIERA_INTERFACE_DECLARE (lumieraorg_GuiNotification, 1, +LUMIERA_INTERFACE_DECLARE (lumieraorg_GuiNotification, 0, LUMIERA_INTERFACE_SLOT (void, displayInfo, (const char*)), LUMIERA_INTERFACE_SLOT (void, triggerGuiShutdown, (const char*)), ); From 29b9887faa9a8bc4ccdf5c4dfdb4d70d742f68ca Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 19 Jan 2009 11:38:20 +0100 Subject: [PATCH 026/216] first draft of a Dummy-Player service --- SConstruct | 2 +- doc/devel/draw/PlayerArch-1.svg | 276 ++++++++++++++++++------------ src/include/dummy-player-facade.h | 119 +++++++++++++ src/proc/dummy-player-service.cpp | 85 +++++++++ src/proc/dummy-player-service.hpp | 92 ++++++++++ 5 files changed, 463 insertions(+), 111 deletions(-) create mode 100644 src/include/dummy-player-facade.h create mode 100644 src/proc/dummy-player-service.cpp create mode 100644 src/proc/dummy-player-service.hpp diff --git a/SConstruct b/SConstruct index dc0f76864..7a1aa2592 100644 --- a/SConstruct +++ b/SConstruct @@ -257,7 +257,7 @@ def configurePlatform(env): if not conf.CheckPkgConfig('glibmm-2.4', '2.16'): problems.append('Unable to configure Lib glib--, exiting.') - if not conf.CheckPkgConfig('gthread-2.0', '2.12'): + if not conf.CheckPkgConfig('gthread-2.0', '2.12.4'): problems.append('Need gthread support lib for glib-- based thread handling.') if not conf.CheckPkgConfig('cairomm-1.0', 0.6): diff --git a/doc/devel/draw/PlayerArch-1.svg b/doc/devel/draw/PlayerArch-1.svg index 8e7b3f9b8..519d5317d 100644 --- a/doc/devel/draw/PlayerArch-1.svg +++ b/doc/devel/draw/PlayerArch-1.svg @@ -25,8 +25,8 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="2" - inkscape:cx="466.20838" - inkscape:cy="425.69964" + inkscape:cx="346.20838" + inkscape:cy="304.01881" inkscape:document-units="px" inkscape:current-layer="svg2" inkscape:window-width="1668" @@ -145,18 +145,18 @@ id="rect4200" width="130.423" height="70.324265" - x="439.99997" - y="229.87326" /> + x="340" + y="260" /> + width="110.59406" + height="30.243902" + x="249.40594" + y="169.7561" /> Displayer - OutSink + x="260" + y="180" + style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">play thread put(Frame&) Display(facade) + y="143.5">PlaybackController - createProcess(...) + style="font-size:8px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">start(...) OutputProcess + x="240" + y="410" + style="font-size:8px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans" + id="tspan2218">PlayProcess Player(facade) + y="263.5">Player (interface) openDisplayer(...) + sodipodi:role="line">start_playback_thread() uses + x="220" + y="290" + style="font-size:7px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-opacity:1;font-family:Bitstream Vera Sans">yields Backend (or Proc?) + y="370">Proc (or Backend?) Displayer (Proxy) DisplayFacade (Proxy) - - C Language Interface of the GUI-Plugin + x="345.00003" + y="273.12677" + style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">PlayerFacade (Proxy) + d="M 110,290 L 210,290 L 270,390" + id="path3481" + sodipodi:nodetypes="ccc" /> actuallytalks to... - libCommon + x="480.00003" + y="280.12677">libCommon + + + PlayContext + PlayerService + + + + PlayContext + PlayContext + PlayContext + diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h new file mode 100644 index 000000000..807f48393 --- /dev/null +++ b/src/include/dummy-player-facade.h @@ -0,0 +1,119 @@ +/* + DUMMY-PLAYER-FACADE.hpp - access point to a dummy test player + + Copyright (C) Lumiera.org + 2009, 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 PROC_INTERFACE_DUMMYPLAYER_H +#define PROC_INTERFACE_DUMMYPLAYER_H + + + +struct lumiera_playprocess_struct { }; +typedef struct lumiera_playprocess_struct lumiera_playprocess; +typedef lumiera_playprocess* LumieraPlayProcess; + + + + +#ifdef __cplusplus /* ============== C++ Interface ================= */ + +#include "common/subsys.hpp" +#include "include/interfaceproxy.hpp" + + + + +namespace proc { + + class PlayProcess; + + + /****************************************************************** + * Interface Proc-Layer (or maybe the backend?): + * Global access point for starting a dummy playback, generating + * some test image data for the GUI to display in a viewer window. + * + * This is a mockup service we created 1/2009 to collect some + * experiences regarding integration of the application layers. + * Lumiera is not yet able actually to deliver rendered video data. + * + */ + class DummyPlayer + { + public: + /** provide a descriptor for lumiera::AppState, + * wired accordingly to allow main to deal with + * the dummy player as independent subsystem. */ + static lumiera::Subsys& getDescriptor(); + + /** get an implementation instance of this service */ + static lumiera::facade::Accessor facade; + + + //////////////////TODO: define some dummy negotiation about size and framerate.... + + virtual PlayProcess& start() =0; + + virtual ~DummyPlayer(); + }; + + + /** + * Continuous playback process, which has been started with a specific + * output size, format and framerate. It is a handle to a calculation process, + * which is about to produce a stream of frames to be retrieved by calling + * the #getFrame function on this handle. + * + * @todo solve the lifecycle and ownership! + */ + class PlayProcess + : public LumieraPlayProcess + { + public: + virtual void pause(bool) =0; + virtual void* const getFrame() =0; + + virtual ~PlayProcess(); + }; + + +} // namespace proc + + + +extern "C" { +#endif /* =========================== CL Interface ===================== */ + + +#include "common/interface.h" + +LUMIERA_INTERFACE_DECLARE (lumieraorg_DummyPlayer, 0 + , LUMIERA_INTERFACE_SLOT (LumieraPlayProcess, startPlay,(void) ) + , LUMIERA_INTERFACE_SLOT (void, pausePlay,(LumieraPlayProcess, bool)) + , LUMIERA_INTERFACE_SLOT (void, terminate,(LumieraPlayProcess) ) + , LUMIERA_INTERFACE_SLOT (void *, getFrame, (LumieraPlayProcess) ) +); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp new file mode 100644 index 000000000..a728613af --- /dev/null +++ b/src/proc/dummy-player-service.cpp @@ -0,0 +1,85 @@ +/* + DummyPlayerService - access point and service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, 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 "proc/dummy-player-service.hpp" +#include "lib/singleton.hpp" + +#include + + +namespace proc { + + using std::string; + using lumiera::Subsys; + + class DummyPlayerSubsysDescriptor + : public Subsys + { + operator string () const { return "Engine"; } + + bool + shouldStart (lumiera::Option&) + { + TODO ("determine, if renderengine should be started"); + return false; + } + + bool + start (lumiera::Option&, Subsys::SigTerm termination) + { + UNIMPLEMENTED ("pull up renderengine and register shutdown hook"); + return false; + } + + void + triggerShutdown () throw() + { + UNIMPLEMENTED ("initiate halting the engine"); + } + + bool + checkRunningState () throw() + { + //Lock guard (*this); + TODO ("implement detecting running state"); + return false; + } + }; + + namespace { + lumiera::Singleton theDescriptor; + } + + + + + /** @internal intended for use by main(). */ + Subsys& + DummyPlayer::getDescriptor() + { + return theDescriptor(); + } + + + +} // namespace proc diff --git a/src/proc/dummy-player-service.hpp b/src/proc/dummy-player-service.hpp new file mode 100644 index 000000000..76d06881a --- /dev/null +++ b/src/proc/dummy-player-service.hpp @@ -0,0 +1,92 @@ +/* + DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player + + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file notification-service.hpp + ** A public service provided by the GUI, implementing the gui::GuiNotification facade interface. + ** The purpose of this service is to push state update and notification of events from the lower + ** layers into the Lumiera GUI. Typically, this happens asynchronously and triggered by events + ** within the lower layers. + ** + ** This service is the implementation of a layer separation facade interface. Clients should use + ** gui::GuiNotification#facade to access this service. This header defines the interface used + ** to \em provide this service, not to access it. + ** + ** @see gui::GuiFacade + ** @see guifacade.cpp starting this service + */ + + +#ifndef PROC_DUMMYPLAYER_SERVICE_H +#define PROC_DUMMYPLAYER_SERVICE_H + + +#include "include/dummy-player-facade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" + + + +namespace proc { + + + + /****************************************************** + * Actual implementation of the GuiNotification service + * within the Lumiera GTK GUI. Creating an instance of + * this class automatically registers the interface + * with the Lumiera Interface/Plugin system and creates + * a forwarding proxy within the application core to + * route calls through this interface. + * + * @todo the ctor of this class should take references + * to any internal service providers within the + * GUI which are needed to implement the service. + */ + class DummyPlayerService + : public DummyPlayer + { + + /* === Implementation of the Facade Interface === */ + + void displayInfo (string const& text); + void triggerGuiShutdown (string const& cause); + + + /* === Interface Lifecycle === */ + + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) + , DummyPlayer + > ServiceInstanceHandle; + + lib::SingletonRef implInstance_; + ServiceInstanceHandle serviceInstance_; + + public: + DummyPlayerService(); + + }; + + + +} // namespace proc +#endif From 60d41ea0173006e21d7b6e88cb4d9ffdb1ebc689 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 19 Jan 2009 12:43:28 +0100 Subject: [PATCH 027/216] WIP (unfinished, doesn't compile) flesh out some impl details --- src/gui/notification-service.cpp | 2 +- src/include/dummy-player-facade.h | 47 +++--- src/proc/dummy-player-service.cpp | 246 +++++++++++++++++++++++++----- src/proc/dummy-player-service.hpp | 17 ++- 4 files changed, 252 insertions(+), 60 deletions(-) diff --git a/src/gui/notification-service.cpp b/src/gui/notification-service.cpp index fcbec39e8..eca7c268f 100644 --- a/src/gui/notification-service.cpp +++ b/src/gui/notification-service.cpp @@ -171,7 +171,7 @@ namespace gui { NotificationService::NotificationService () : implInstance_(this,_instance), - serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_GuiNotification, 1,lumieraorg_GuiNotificationFacade)) + serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_GuiNotification, 0,lumieraorg_GuiNotificationFacade)) { INFO (operate, "GuiNotification Facade opened."); } diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h index 807f48393..1b12a0bfa 100644 --- a/src/include/dummy-player-facade.h +++ b/src/include/dummy-player-facade.h @@ -38,12 +38,12 @@ typedef lumiera_playprocess* LumieraPlayProcess; #include "common/subsys.hpp" #include "include/interfaceproxy.hpp" +#include namespace proc { - - class PlayProcess; + /****************************************************************** @@ -68,31 +68,34 @@ namespace proc { static lumiera::facade::Accessor facade; + /** + * Continuous playback process, which has been started with a specific + * output size, format and framerate. It is a handle to a calculation process, + * which is about to produce a stream of frames to be retrieved by calling + * the #getFrame function on this handle. + * + * @todo solve the lifecycle and ownership! + */ + class Process + : public LumieraPlayProcess, + boost::noncopyable + { + public: + virtual void pause(bool) =0; + virtual void* const getFrame() =0; + + virtual ~Process(); + }; + + //////////////////TODO: define some dummy negotiation about size and framerate.... - virtual PlayProcess& start() =0; + virtual Process& start() =0; virtual ~DummyPlayer(); }; - /** - * Continuous playback process, which has been started with a specific - * output size, format and framerate. It is a handle to a calculation process, - * which is about to produce a stream of frames to be retrieved by calling - * the #getFrame function on this handle. - * - * @todo solve the lifecycle and ownership! - */ - class PlayProcess - : public LumieraPlayProcess - { - public: - virtual void pause(bool) =0; - virtual void* const getFrame() =0; - - virtual ~PlayProcess(); - }; } // namespace proc @@ -100,9 +103,9 @@ namespace proc { extern "C" { -#endif /* =========================== CL Interface ===================== */ +#endif /* =========================== CL Interface ===================== */ + - #include "common/interface.h" LUMIERA_INTERFACE_DECLARE (lumieraorg_DummyPlayer, 0 diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp index a728613af..863462c9e 100644 --- a/src/proc/dummy-player-service.cpp +++ b/src/proc/dummy-player-service.cpp @@ -25,49 +25,227 @@ #include "lib/singleton.hpp" #include +#include namespace proc { using std::string; using lumiera::Subsys; + using boost::scoped_ptr; - class DummyPlayerSubsysDescriptor - : public Subsys - { - operator string () const { return "Engine"; } - - bool - shouldStart (lumiera::Option&) - { - TODO ("determine, if renderengine should be started"); - return false; - } - - bool - start (lumiera::Option&, Subsys::SigTerm termination) - { - UNIMPLEMENTED ("pull up renderengine and register shutdown hook"); - return false; - } - - void - triggerShutdown () throw() - { - UNIMPLEMENTED ("initiate halting the engine"); - } - - bool - checkRunningState () throw() - { - //Lock guard (*this); - TODO ("implement detecting running state"); - return false; - } - }; - namespace { + namespace { // hidden local details of the service implementation.... + + class DummyPlayerSubsysDescriptor + : public Subsys + { + operator string () const { return "Dummy-Player"; } + + bool + shouldStart (lumiera::Option&) + { + return false; // for now the DummyPlayerService only comes "up" as dependency, + } // but doesn't start as a subsystem on it's own. + + bool + start (lumiera::Option&, Subsys::SigTerm terminationHandle) + { + ASSERT (!thePlayer_); + + thePlayer_.reset (new DummyPlayerService (terminationHandle)); + return true; + } + + /** manages the actual (single) instance of the player service impl */ + scoped_ptr thePlayer_; + + + void + triggerShutdown () throw() + { + TODO ("implement waiting for any playback processes to terminate gracefully"); + //..... but this would require us to use a separate thread, so I skip it for now. + // Probably it's better design to mange the processes in a separate thread anyway... + + thePlayer_.reset(0); + } + + bool + checkRunningState () throw() + { + //note: not locking here... + return (thePlayer_); + } + }; + lumiera::Singleton theDescriptor; + + + + + + /* ================== define an lumieraorg_GuiNotification instance ======================= */ + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 + ,lumieraorg_DummyPlayerFacade_descriptor + , NULL, NULL, NULL + , LUMIERA_INTERFACE_INLINE (name, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "DummyPlayer"; } + ) + , LUMIERA_INTERFACE_INLINE (brief, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; } + ) + , LUMIERA_INTERFACE_INLINE (homepage, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "http://www.lumiera.org/develompent.html" ;} + ) + , LUMIERA_INTERFACE_INLINE (version, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "0.1~pre"; } + ) + , LUMIERA_INTERFACE_INLINE (author, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "Hermann Vosseler"; } + ) + , LUMIERA_INTERFACE_INLINE (email, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "Ichthyostega@web.de"; } + ) + , LUMIERA_INTERFACE_INLINE (copyright, LUIDGEN, + const char*, (LumieraInterface ifa), + { + (void)ifa; + return + "Copyright (C) Lumiera.org\n" + " 2009 Hermann Vosseler "; + } + ) + , LUMIERA_INTERFACE_INLINE (license, LUIDGEN, + const char*, (LumieraInterface ifa), + { + (void)ifa; + return + "This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version.\n" + "\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program; if not, write to the Free Software\n" + "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"; + } + ) + , LUMIERA_INTERFACE_INLINE (state, LUIDGEN, + int, (LumieraInterface ifa), + {(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; } + ) + , LUMIERA_INTERFACE_INLINE (versioncmp, LUIDGEN, + int, (const char* a, const char* b), + {return 0;} ////////////////////////////////////////////TODO define version ordering + ) + ); + + + + + + using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; + typedef lib::SingletonRef::Accessor InstanceRef; + + InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual GuiNotification implementation... + + typedef DummyPlayer::Process* ProcP; + + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0 + ,lumieraorg_DummyPlayerFacade + , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor) + , NULL /* on open */ + , NULL /* on close */ + , LUMIERA_INTERFACE_INLINE (startPlay, LUIDGEN, + LumieraPlayProcess, (void), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return 0; + } + + return static_cast (& (_instance->start())); + } + ) + , LUMIERA_INTERFACE_INLINE (pausePlay, LUIDGEN, + void, (LumieraPlayProcess handle, bool doPlay), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return; + } + + REQUIRE (handle); + ProcP proc = dynamic_cast (handle); + ASSERT (proc); + + proc->pause(doPlay); + } + ) + , LUMIERA_INTERFACE_INLINE (terminate, LUIDGEN, + void, (LumieraPlayProcess handle), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return; + } + + REQUIRE (handle); + ProcP proc = dynamic_cast (handle); + ASSERT (proc); + + UNIMPLEMENTED ("terminate a running playback process"); + } + ) + , LUMIERA_INTERFACE_INLINE (getFrame, LUIDGEN, + void *, (LumieraPlayProcess handle), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return 0; + } + + REQUIRE (handle); + ProcP proc = dynamic_cast (handle); + ASSERT (proc); + + return const_cast (proc->getFrame()); + } + ) + ); + + + + + } // (End) hidden service impl details + + + + + DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle) + : notifyTermination_(terminationHandle) + , implInstance_(this,_instance) + , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade)) + { + INFO (operate, "GuiNotification Facade opened."); } diff --git a/src/proc/dummy-player-service.hpp b/src/proc/dummy-player-service.hpp index 76d06881a..2a4aaf734 100644 --- a/src/proc/dummy-player-service.hpp +++ b/src/proc/dummy-player-service.hpp @@ -68,8 +68,17 @@ namespace proc { /* === Implementation of the Facade Interface === */ - void displayInfo (string const& text); - void triggerGuiShutdown (string const& cause); + Process& start(); + + + /** for now we use an single inline Process... + * @todo actually implement multiple independent Playback processes! + * @todo I am aware holding this object inline may cause a segfault at shutdown! + */ + Process theProcess_; + + Subsys::SigTerm notifyTermination_; + /* === Interface Lifecycle === */ @@ -82,7 +91,9 @@ namespace proc { ServiceInstanceHandle serviceInstance_; public: - DummyPlayerService(); + DummyPlayerService(Subsys::SigTerm terminationHandle); + + ~DummyPlayerService() { notifyTermination_(); } }; From 977cbf9e64b2b22d18a8ceadef7d2badfa299b80 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Mon, 19 Jan 2009 18:14:52 +0000 Subject: [PATCH 028/216] Fixed track drag raise behaviour --- .../timeline/timeline-header-container.cpp | 40 +++++-------------- .../timeline/timeline-header-container.hpp | 16 ++++---- .../timeline/timeline-layout-helper.cpp | 6 +++ .../timeline/timeline-layout-helper.hpp | 2 + 4 files changed, 26 insertions(+), 38 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 4041ab554..97df83cb6 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -183,7 +183,7 @@ bool TimelineHeaderContainer::on_button_release_event ( // Has the user been dragging? if(layout.get_dragging_track()) - end_drag(); + layout.end_dragging_track(); return Container::on_button_release_event(event); } @@ -404,38 +404,16 @@ void TimelineHeaderContainer::begin_drag() { TimelineLayoutHelper &layout = timelineWidget.layoutHelper; - - shared_ptr dragging_track = - layout.begin_dragging_track(mousePoint); - ENSURE(dragging_track); // Something strange has happened if we - // were somehow not hovering on a track + layout.begin_dragging_track(mousePoint); - const TimelineLayoutHelper::TrackTree::pre_order_iterator node = - layout.iterator_from_track(dragging_track->get_model_track()); - set_keep_above_recursive(node, true); + // Raise all the header widgets so they float above the widgets not + // being dragged + raise_recursive(layout.get_dragging_track_iter()); } void -TimelineHeaderContainer::end_drag() -{ - TimelineLayoutHelper &layout = timelineWidget.layoutHelper; - - shared_ptr dragging_track = - layout.get_dragging_track(); - ENSURE(dragging_track); // Something strange has happened if we - // were somehow not dragging on a track - - const TimelineLayoutHelper::TrackTree::pre_order_iterator node = - layout.iterator_from_track(dragging_track->get_model_track()); - set_keep_above_recursive(node, false); - - layout.end_dragging_track(); -} - -void -TimelineHeaderContainer::set_keep_above_recursive( - TimelineLayoutHelper::TrackTree::iterator_base node, - const bool keep_above) +TimelineHeaderContainer::raise_recursive( + TimelineLayoutHelper::TrackTree::iterator_base node) { TimelineLayoutHelper::TrackTree::pre_order_iterator iter; @@ -450,13 +428,13 @@ TimelineHeaderContainer::set_keep_above_recursive( timeline_track->get_header_widget().get_window(); ENSURE(window); // Something strange has happened if there was no // window - window->set_keep_above(keep_above); + window->raise(); for(iter = layout_tree.begin(node); iter != layout_tree.end(node); iter++) { - set_keep_above_recursive(iter, keep_above); + raise_recursive(iter); } } diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 4b2883d47..be2250bab 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -184,13 +184,15 @@ private: boost::shared_ptr model_track); void begin_drag(); - - - void end_drag(); - - void set_keep_above_recursive( - TimelineLayoutHelper::TrackTree::iterator_base node, - const bool keep_above); + + /** + * Recusively raises all the header widget windows in a branch to the + * top of the Z-order. + * @param node The window of node's track header will be raised, as + * well as all it's descendant nodes. + **/ + void raise_recursive( + TimelineLayoutHelper::TrackTree::iterator_base node); /** * Begins, or continues a scroll slide at a given rate diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index dccd9d143..f90633e97 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -163,6 +163,12 @@ TimelineLayoutHelper::get_dragging_track() const return draggingTrack; } +TimelineLayoutHelper::TrackTree::pre_order_iterator +TimelineLayoutHelper::get_dragging_track_iter() const +{ + return draggingTrackIter; +} + void TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) { diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 68f44939a..560ffc2c8 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -134,6 +134,8 @@ public: boost::shared_ptr get_dragging_track() const; + TrackTree::pre_order_iterator get_dragging_track_iter() const; + void drag_to_point(const Gdk::Point &point); /** From f6e28febdbee541f021608f91fc2877b37be8649 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Mon, 19 Jan 2009 19:25:06 +0000 Subject: [PATCH 029/216] Removed static App* constants in GtkLumiera - replaced with static functions --- src/gui/gtk-lumiera.cpp | 58 ++++++++++++++++++-------- src/gui/gtk-lumiera.hpp | 52 ++++++++++------------- src/gui/workspace/actions.cpp | 9 ++-- src/gui/workspace/workspace-window.cpp | 2 +- 4 files changed, 67 insertions(+), 54 deletions(-) diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index eb8fbe023..fd53d31f7 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -45,7 +45,7 @@ using namespace gui; using namespace gui::workspace; using namespace gui::model; using namespace gui::controller; - +using namespace std; GtkLumiera the_application; @@ -61,7 +61,7 @@ GtkLumiera::main(int argc, char *argv[]) Main kit(argc, argv); - Glib::set_application_name(AppTitle); + Glib::set_application_name(get_app_title()); Project project; Controller controller(project); @@ -84,30 +84,52 @@ GtkLumiera::get_home_data_path() return ustring::compose("%1/.%2", path, app_name); } +const Glib::ustring +GtkLumiera::get_app_title() +{ + return "Lumiera"; +} + +const Glib::ustring +GtkLumiera::get_app_version() +{ + return "0.1-dev"; +} + +const Glib::ustring GtkLumiera::get_app_copyright() +{ + return _("© 2008 The Lumiera Team"); +} + +const Glib::ustring GtkLumiera::get_app_website() +{ + return "www.lumiera.org"; +} + +const std::vector +GtkLumiera::get_app_authors() +{ + const gchar* app_authors[] = { + "Joel Holdsworth", + "Christian Thaeter", + "Hermann Vosseler", + ""}; + + const int count = sizeof(app_authors) / sizeof(gchar*); + std::vector list(count); + for(int i = 0; i < count; i++) + list[i] = app_authors[i]; + return list; +} + GtkLumiera& application() { return the_application; } -/* ===== Constants ===== */ - -const gchar* GtkLumiera::AppTitle = "Lumiera"; -const gchar* GtkLumiera::AppVersion = _("0.1-dev"); -const gchar* GtkLumiera::AppCopyright = - _("© 2008 The Lumiera Team"); -const gchar* GtkLumiera::AppWebsite = "www.lumiera.org"; -const gchar* GtkLumiera::AppAuthors[] = { - "Joel Holdsworth", - "Christian Thaeter", - "Hermann Vosseler", - ""}; -const int GtkLumiera::AppAuthorCount = 4; - } // namespace gui - - /** * Run the Lumiera GTK GUI as standalone application without backend. */ diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index a01bc5dc4..53d146b95 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -73,38 +73,30 @@ public: static Glib::ustring get_home_data_path(); - -public: - /* ----- Constants ----- */ /** - * The name of the application - */ - static const gchar* AppTitle; - - /** - * The version number of the application - */ - static const gchar* AppVersion; - - /** - * The copyright of the application - */ - static const gchar* AppCopyright; - - /** - * The website of the application - */ - static const gchar* AppWebsite; - - /** - * An alphabetical list of the application's authors - */ - static const gchar* AppAuthors[]; - - /** - * The number of authors in AppAuthors + * Returns the name of the application **/ - static const int AppAuthorCount; + static const Glib::ustring get_app_title(); + + /** + * Returns the version number of the application + **/ + static const Glib::ustring get_app_version(); + + /** + * Returns the copyright of the application + **/ + static const Glib::ustring get_app_copyright(); + + /** + * Returns the website of the application + **/ + static const Glib::ustring get_app_website(); + + /** + * Returns tn alphabetical list of the application's authors + **/ + static const std::vector get_app_authors(); }; /** diff --git a/src/gui/workspace/actions.cpp b/src/gui/workspace/actions.cpp index 2ac749528..9cbc94aea 100644 --- a/src/gui/workspace/actions.cpp +++ b/src/gui/workspace/actions.cpp @@ -208,12 +208,11 @@ Actions::on_menu_help_about() AboutDialog dialog; //dialog.set_program_name(AppTitle); - dialog.set_version(GtkLumiera::AppVersion); + dialog.set_version(GtkLumiera::get_app_version()); //dialog.set_version(AppState::get("version")); - dialog.set_copyright(GtkLumiera::AppCopyright); - dialog.set_website(GtkLumiera::AppWebsite); - dialog.set_authors(StringArrayHandle(GtkLumiera::AppAuthors, - GtkLumiera::AppAuthorCount, OWNERSHIP_NONE)); + dialog.set_copyright(GtkLumiera::get_app_copyright()); + dialog.set_website(GtkLumiera::get_app_website()); + dialog.set_authors(GtkLumiera::get_app_authors()); dialog.set_transient_for(workspaceWindow); diff --git a/src/gui/workspace/workspace-window.cpp b/src/gui/workspace/workspace-window.cpp index 24557053d..abcce5601 100644 --- a/src/gui/workspace/workspace-window.cpp +++ b/src/gui/workspace/workspace-window.cpp @@ -85,7 +85,7 @@ void WorkspaceWindow::create_ui() { //----- Configure the Window -----// - set_title(GtkLumiera::AppTitle); + set_title(GtkLumiera::get_app_title()); set_default_size(1024, 768); //----- Set up the UI Manager -----// From 6d8f598312bd1e231243d2692488f43050cea117 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Mon, 19 Jan 2009 19:33:13 +0000 Subject: [PATCH 030/216] Fixed a bug when SCons.__version__ == "0.97.0d20071203" --- admin/scons/LumieraEnvironment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/scons/LumieraEnvironment.py b/admin/scons/LumieraEnvironment.py index 2d8f1bb01..d8aeed54e 100644 --- a/admin/scons/LumieraEnvironment.py +++ b/admin/scons/LumieraEnvironment.py @@ -88,7 +88,7 @@ class LumieraEnvironment(Environment): #### temporary pre 1.0 SCons compatibility hack #### -_ver = map(int, SCons.__version__.split('.')) +_ver = map(int, SCons.__version__.split('.')[:2]) _old = (_ver[0]<1 and _ver[1]<98) if _old: ConfigBase = SCons.SConf.SConf From 5ee6d375c0756c8ba589f88740a7aa4da600b46b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 20 Jan 2009 02:38:13 +0100 Subject: [PATCH 031/216] SCons: fix the compatibility switch; the new code path should also be used for scons 0.97 --- admin/scons/LumieraEnvironment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/scons/LumieraEnvironment.py b/admin/scons/LumieraEnvironment.py index d8aeed54e..56fd81a81 100644 --- a/admin/scons/LumieraEnvironment.py +++ b/admin/scons/LumieraEnvironment.py @@ -89,7 +89,7 @@ class LumieraEnvironment(Environment): #### temporary pre 1.0 SCons compatibility hack #### _ver = map(int, SCons.__version__.split('.')[:2]) -_old = (_ver[0]<1 and _ver[1]<98) +_old = (_ver[0]<1 and _ver[1]<97) if _old: ConfigBase = SCons.SConf.SConf else: From 962921d375d6a688cee3008a8495ac68c3c7eb7e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 20 Jan 2009 12:41:21 +0100 Subject: [PATCH 032/216] WIP (still doesnt compile...) add impl of the forwarding proxy... --- src/common/interfaceproxy.cpp | 57 +++++++++++++++++++++++++++-- src/include/dummy-player-facade.h | 4 +-- src/proc/dummy-player-service.cpp | 60 ++++++++++++++++--------------- src/proc/dummy-player-service.hpp | 19 ++++++++-- 4 files changed, 104 insertions(+), 36 deletions(-) diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 6cbc8b4cb..984555f28 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -40,6 +40,17 @@ namespace gui { +#include "include/dummy-player-facade.h" + +namespace proc { + + /** storage for the DummyPlayer facade proxy factory... */ + lumiera::facade::Accessor DummyPlayer::facade; + +} // namespace gui + + + namespace lumiera { namespace facade { @@ -107,7 +118,9 @@ namespace lumiera { - typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 1) + /* ==================== GuiNotification =================================== */ + + typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 0) , gui::GuiNotification > Handle_GuiNotification; @@ -127,12 +140,50 @@ namespace lumiera { }; - - template void openProxy (Handle_GuiNotification const&); template void closeProxy (void); + + + + + + /* ==================== DummyPlayer ======================================= */ + + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) + , proc::DummyPlayer + > Handle_DummyPlayer; + + + template<> + class Proxy + : public Holder + { + //----Proxy-Implementation-of-DummyPlayer-------- + typedef proc::DummyPlayer::Process Process; + + Process& start() + { + Process* pP = static_cast (_i_.startPlay()); + + if (!pP || lumiera_error_peek()) + throw lumiera::error::State("failed to start DummyPlayer", lumiera_error()); + + return *pP; + } + + + + public: + Proxy (IHandle const& iha) : THolder(iha) {} + }; + + + template void openProxy (Handle_DummyPlayer const&); + template void closeProxy (void); + + } // namespace facade } // namespace lumiera diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h index 1b12a0bfa..2899096c0 100644 --- a/src/include/dummy-player-facade.h +++ b/src/include/dummy-player-facade.h @@ -77,8 +77,8 @@ namespace proc { * @todo solve the lifecycle and ownership! */ class Process - : public LumieraPlayProcess, - boost::noncopyable + : public lumiera_playprocess + , boost::noncopyable { public: virtual void pause(bool) =0; diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp index 863462c9e..400bfafa4 100644 --- a/src/proc/dummy-player-service.cpp +++ b/src/proc/dummy-player-service.cpp @@ -24,6 +24,10 @@ #include "proc/dummy-player-service.hpp" #include "lib/singleton.hpp" +extern "C" { +#include "common/interfacedescriptor.h" +} + #include #include @@ -37,11 +41,14 @@ namespace proc { namespace { // hidden local details of the service implementation.... + /** details of how the DummyPlayer service can be started + * and used as independent "subsystem" within main() */ class DummyPlayerSubsysDescriptor : public Subsys { operator string () const { return "Dummy-Player"; } + bool shouldStart (lumiera::Option&) { @@ -66,7 +73,7 @@ namespace proc { { TODO ("implement waiting for any playback processes to terminate gracefully"); //..... but this would require us to use a separate thread, so I skip it for now. - // Probably it's better design to mange the processes in a separate thread anyway... + // Probably it's better design to manage the processes in a separate thread anyway... thePlayer_.reset(0); } @@ -90,31 +97,31 @@ namespace proc { LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 ,lumieraorg_DummyPlayerFacade_descriptor , NULL, NULL, NULL - , LUMIERA_INTERFACE_INLINE (name, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (name, "\305\162\202\240\075\316\146\100\314\152\075\343\372\065\226\307", const char*, (LumieraInterface ifa), { (void)ifa; return "DummyPlayer"; } ) - , LUMIERA_INTERFACE_INLINE (brief, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (brief, "\317\045\366\076\064\072\156\274\220\346\262\207\062\367\057\232", const char*, (LumieraInterface ifa), { (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; } ) - , LUMIERA_INTERFACE_INLINE (homepage, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (homepage, "\136\225\033\362\161\251\300\256\117\072\171\102\235\004\235\200", const char*, (LumieraInterface ifa), { (void)ifa; return "http://www.lumiera.org/develompent.html" ;} ) - , LUMIERA_INTERFACE_INLINE (version, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (version, "\212\146\344\127\124\116\101\205\211\174\322\241\162\122\023\165", const char*, (LumieraInterface ifa), { (void)ifa; return "0.1~pre"; } ) - , LUMIERA_INTERFACE_INLINE (author, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (author, "\064\226\072\300\054\345\042\357\337\226\155\025\306\051\117\105", const char*, (LumieraInterface ifa), { (void)ifa; return "Hermann Vosseler"; } ) - , LUMIERA_INTERFACE_INLINE (email, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (email, "\041\075\220\112\246\304\261\135\003\135\060\202\230\327\303\206", const char*, (LumieraInterface ifa), { (void)ifa; return "Ichthyostega@web.de"; } ) - , LUMIERA_INTERFACE_INLINE (copyright, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (copyright, "\232\305\163\271\174\025\270\075\012\201\331\256\327\375\066\210", const char*, (LumieraInterface ifa), { (void)ifa; @@ -123,7 +130,7 @@ namespace proc { " 2009 Hermann Vosseler "; } ) - , LUMIERA_INTERFACE_INLINE (license, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (license, "\136\136\073\173\145\357\151\062\040\013\323\272\051\352\305\060", const char*, (LumieraInterface ifa), { (void)ifa; @@ -143,11 +150,11 @@ namespace proc { "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"; } ) - , LUMIERA_INTERFACE_INLINE (state, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (state, "\224\251\004\001\165\140\116\246\126\311\115\234\023\026\331\350", int, (LumieraInterface ifa), {(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; } ) - , LUMIERA_INTERFACE_INLINE (versioncmp, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (versioncmp, "\267\155\303\046\353\222\323\014\145\027\043\100\370\311\257\126", int, (const char* a, const char* b), {return 0;} ////////////////////////////////////////////TODO define version ordering ) @@ -158,9 +165,9 @@ namespace proc { using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; - typedef lib::SingletonRef::Accessor InstanceRef; + typedef lib::SingletonRef::Accessor InstanceRef; - InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual GuiNotification implementation... + InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation... typedef DummyPlayer::Process* ProcP; @@ -170,7 +177,7 @@ namespace proc { , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor) , NULL /* on open */ , NULL /* on close */ - , LUMIERA_INTERFACE_INLINE (startPlay, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (startPlay, "\143\323\102\155\051\006\235\004\037\310\354\121\176\142\342\210", LumieraPlayProcess, (void), { if (!_instance) @@ -182,7 +189,7 @@ namespace proc { return static_cast (& (_instance->start())); } ) - , LUMIERA_INTERFACE_INLINE (pausePlay, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (pausePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307", void, (LumieraPlayProcess handle, bool doPlay), { if (!_instance) @@ -192,13 +199,12 @@ namespace proc { } REQUIRE (handle); - ProcP proc = dynamic_cast (handle); - ASSERT (proc); + ProcP proc = static_cast (handle); proc->pause(doPlay); } ) - , LUMIERA_INTERFACE_INLINE (terminate, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (terminate, "\005\265\115\021\076\143\010\215\373\252\370\174\235\136\340\004", void, (LumieraPlayProcess handle), { if (!_instance) @@ -208,24 +214,19 @@ namespace proc { } REQUIRE (handle); - ProcP proc = dynamic_cast (handle); - ASSERT (proc); + ProcP proc = static_cast (handle); UNIMPLEMENTED ("terminate a running playback process"); } ) - , LUMIERA_INTERFACE_INLINE (getFrame, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (getFrame, "\230\130\101\300\047\065\170\052\226\164\026\112\150\166\074\134", void *, (LumieraPlayProcess handle), { - if (!_instance) - { - lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); - return 0; - } + //skipping full checks for performance reasons + REQUIRE (_instance && !lumiera_error_peek()); REQUIRE (handle); - ProcP proc = dynamic_cast (handle); - ASSERT (proc); + ProcP proc = static_cast (handle); return const_cast (proc->getFrame()); } @@ -241,7 +242,8 @@ namespace proc { DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle) - : notifyTermination_(terminationHandle) + : error_("") + , notifyTermination_(terminationHandle) , implInstance_(this,_instance) , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade)) { diff --git a/src/proc/dummy-player-service.hpp b/src/proc/dummy-player-service.hpp index 2a4aaf734..7610b91c3 100644 --- a/src/proc/dummy-player-service.hpp +++ b/src/proc/dummy-player-service.hpp @@ -44,12 +44,26 @@ #include "common/instancehandle.hpp" #include "lib/singleton-ref.hpp" +#include namespace proc { + using std::string; + using lumiera::Subsys; + class ProcessImpl + : public DummyPlayer::Process + { + void pause(bool doPlay); + void* const getFrame(); + + public: + ProcessImpl() {} + }; + + /****************************************************** * Actual implementation of the GuiNotification service * within the Lumiera GTK GUI. Creating an instance of @@ -75,8 +89,9 @@ namespace proc { * @todo actually implement multiple independent Playback processes! * @todo I am aware holding this object inline may cause a segfault at shutdown! */ - Process theProcess_; + ProcessImpl theProcess_; + string error_; Subsys::SigTerm notifyTermination_; @@ -93,7 +108,7 @@ namespace proc { public: DummyPlayerService(Subsys::SigTerm terminationHandle); - ~DummyPlayerService() { notifyTermination_(); } + ~DummyPlayerService() { notifyTermination_(&error_); } }; From b0f56c070d7edea2e1fcf48fecf3d47170b579a2 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 20 Jan 2009 21:39:33 +0000 Subject: [PATCH 033/216] WIP: Initial commit of prototype real drop hit test code --- src/gui/model/parent-track.cpp | 6 ++ src/gui/model/parent-track.hpp | 2 + src/gui/model/track.cpp | 8 +- src/gui/model/track.hpp | 2 + .../timeline/timeline-layout-helper.cpp | 78 ++++++++++++++++--- 5 files changed, 84 insertions(+), 12 deletions(-) diff --git a/src/gui/model/parent-track.cpp b/src/gui/model/parent-track.cpp index 612e112d7..6aec58e8a 100644 --- a/src/gui/model/parent-track.cpp +++ b/src/gui/model/parent-track.cpp @@ -42,6 +42,12 @@ ParentTrack::get_child_track_list() return tracks; } +bool +ParentTrack::can_host_children() const +{ + return true; +} + bool ParentTrack::remove_child_track(const boost::shared_ptr track) { diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index a895b3427..ecc084e4b 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -46,6 +46,8 @@ public: lumiera::observable_list< boost::shared_ptr >& get_child_track_list(); + bool can_host_children() const; + bool remove_child_track(const boost::shared_ptr track); protected: diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index 50d50e4b8..d13e698e1 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -52,7 +52,13 @@ Track::set_name(const std::string &name) } bool -Track::remove_child_track(const boost::shared_ptr track) +Track::can_host_children() const +{ + return false; +} + +bool +Track::remove_child_track(const boost::shared_ptr /*track*/) { return false; } diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index 42c6e890b..300e0f9b8 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -45,6 +45,8 @@ public: void set_name(const std::string &name); + virtual bool can_host_children() const; + virtual bool remove_child_track(const boost::shared_ptr track); std::string print_branch(); diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index f90633e97..6b772b0a8 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -33,6 +33,7 @@ using namespace std; using namespace boost; using namespace lumiera; using namespace util; +using namespace gui::util; namespace gui { namespace widgets { @@ -178,23 +179,78 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) // Search the headers TrackTree::pre_order_iterator iterator; - for(iterator = ++layoutTree.begin(); // ++ so we miss out the root sequence + + for(iterator = ++layoutTree.begin(); iterator != layoutTree.end(); iterator++) - { - // Hit test the rectangle - const weak_ptr track = - lookup_timeline_track(*iterator); - - if(util::pt_in_rect(dragPoint, headerBoxes[track])) + { + // Skip the dragging branch + if(iterator == draggingTrackIter) { - // Relocate the header - draggingTrackIter = layoutTree.move_after( + iterator.skip_children(); + continue; + } + + // Get the rectangle and the next rectangle + const shared_ptr model_track(*iterator); + REQUIRE(model_track); + const weak_ptr timeline_track = + lookup_timeline_track(model_track); + const Gdk::Rectangle &rect = headerBoxes[timeline_track]; + const int half_height = rect.get_height() / 2; + const int y = rect.get_y(); + const int y_mid = y + half_height; + const int full_width = TimelineWidget::HeaderWidth; + const int x_mid = rect.get_x() + rect.get_width() / 2; + + // Is our track being dragged before this header? + if(pt_in_rect(dragPoint, + Gdk::Rectangle(0, y, full_width, half_height))) + { + draggingTrackIter = layoutTree.move_before( iterator, draggingTrackIter); - update_layout(); - return; + break; + } + + if(model_track->can_host_children() && + model_track->get_child_tracks().empty()) + { + // Is our track being dragged after this header? + if(pt_in_rect(dragPoint, + Gdk::Rectangle(0, y_mid, x_mid, half_height))) + { + draggingTrackIter = layoutTree.move_after( + iterator, draggingTrackIter); + break; + } + else if(pt_in_rect(dragPoint, + Gdk::Rectangle(x_mid, y_mid, + full_width - x_mid, half_height))) + { + // Insert a place-holder in the tree + const TrackTree::pre_order_iterator placeholder = + layoutTree.append_child( + iterator, shared_ptr()); + + // Replace it with the relocated branch + draggingTrackIter = layoutTree.move_ontop( + placeholder, draggingTrackIter); + break; + } + } + else + { + if(pt_in_rect(dragPoint, + Gdk::Rectangle(0, y_mid, full_width, half_height))) + { + draggingTrackIter = layoutTree.move_after( + iterator, draggingTrackIter); + break; + } } } + + update_layout(); } int From d42bc4ea90cf0bf912e135565118f422528839ca Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 20 Jan 2009 23:17:40 +0000 Subject: [PATCH 034/216] Fixed a bug in tree --- src/lib/tree.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tree.hpp b/src/lib/tree.hpp index a3cef9f57..d856e9430 100644 --- a/src/lib/tree.hpp +++ b/src/lib/tree.hpp @@ -892,7 +892,7 @@ iter tree::prepend_child(iter position) position.node->last_child=tmp; } tmp->next_sibling=position.node->first_child; - position.node->prev_child=tmp; + position.node->first_child=tmp; tmp->prev_sibling=0; return tmp; } From d209e0e2f2b40e11a34ae0378df3121fb3a40862 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 20 Jan 2009 23:31:40 +0000 Subject: [PATCH 035/216] Made drop targets more sensible --- .../timeline/timeline-layout-helper.cpp | 134 ++++++++++++------ .../timeline/timeline-layout-helper.hpp | 7 + 2 files changed, 95 insertions(+), 46 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 6b772b0a8..660f08f4d 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -191,68 +191,110 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) continue; } - // Get the rectangle and the next rectangle + // Lookup the tracks const shared_ptr model_track(*iterator); REQUIRE(model_track); const weak_ptr timeline_track = lookup_timeline_track(model_track); + + // Calculate coordinates const Gdk::Rectangle &rect = headerBoxes[timeline_track]; const int half_height = rect.get_height() / 2; const int y = rect.get_y(); const int y_mid = y + half_height; - const int full_width = TimelineWidget::HeaderWidth; + const int full_width = rect.get_x() + rect.get_width(); const int x_mid = rect.get_x() + rect.get_width() / 2; - // Is our track being dragged before this header? - if(pt_in_rect(dragPoint, - Gdk::Rectangle(0, y, full_width, half_height))) - { - draggingTrackIter = layoutTree.move_before( - iterator, draggingTrackIter); - break; - } + // Do hit test + if(attempt_drop_upper(iterator, dragPoint, + y, full_width, half_height)) + break; - if(model_track->can_host_children() && - model_track->get_child_tracks().empty()) - { - // Is our track being dragged after this header? - if(pt_in_rect(dragPoint, - Gdk::Rectangle(0, y_mid, x_mid, half_height))) - { - draggingTrackIter = layoutTree.move_after( - iterator, draggingTrackIter); - break; - } - else if(pt_in_rect(dragPoint, - Gdk::Rectangle(x_mid, y_mid, - full_width - x_mid, half_height))) - { - // Insert a place-holder in the tree - const TrackTree::pre_order_iterator placeholder = - layoutTree.append_child( - iterator, shared_ptr()); - - // Replace it with the relocated branch - draggingTrackIter = layoutTree.move_ontop( - placeholder, draggingTrackIter); - break; - } - } - else - { - if(pt_in_rect(dragPoint, - Gdk::Rectangle(0, y_mid, full_width, half_height))) - { - draggingTrackIter = layoutTree.move_after( - iterator, draggingTrackIter); - break; - } - } + if(attempt_drop_lower(iterator, dragPoint, + x_mid, full_width, y_mid, half_height)) + break; } update_layout(); } +bool +TimelineLayoutHelper::attempt_drop_upper( + TrackTree::pre_order_iterator target, const Gdk::Point &point, + const int y, const int full_width, const int half_height) +{ + if(pt_in_rect(point, Gdk::Rectangle(0, y, full_width, half_height))) + { + draggingTrackIter = layoutTree.move_before( + target, draggingTrackIter); + return true; + } + return false; +} + + +bool +TimelineLayoutHelper::attempt_drop_lower( + TrackTree::pre_order_iterator target, const Gdk::Point &point, + const int x_mid, const int full_width, const int y_mid, + const int half_height) +{ + const shared_ptr model_track(*target); + REQUIRE(model_track); + + if(!pt_in_rect(point, Gdk::Rectangle(0, y_mid, + full_width, half_height))) + return false; + + if(model_track->can_host_children()) + { + if(model_track->get_child_tracks().empty()) + { + // Is our track being dragged after this header? + if(dragPoint.get_x() < x_mid) + { + draggingTrackIter = layoutTree.move_after( + target, draggingTrackIter); + } + else + { + if(draggingTrackIter.node->parent != target.node) + { + // Insert a place-holder in the tree + const TrackTree::pre_order_iterator placeholder = + layoutTree.prepend_child(target); + + // Replace it with the relocated branch + draggingTrackIter = layoutTree.move_ontop( + placeholder, draggingTrackIter); + } + } + } + else + { + if(draggingTrackIter.node->parent != target.node) + { + // Insert a place-holder in the tree + const TrackTree::pre_order_iterator placeholder = + layoutTree.append_child(target); + + // Replace it with the relocated branch + draggingTrackIter = layoutTree.move_ontop( + placeholder, draggingTrackIter); + } + } + } + else + { + // When this track cannot be a parent, the dragging track is + // simply dropped after + draggingTrackIter = layoutTree.move_after( + target, draggingTrackIter); + } + + return true; +} + int TimelineLayoutHelper::get_total_height() const { diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 560ffc2c8..524be4566 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -219,6 +219,13 @@ protected: * The animation timer tick callback. **/ bool on_animation_tick(); + +bool +attempt_drop_upper(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int y, const int full_width, const int half_height); + + +bool +attempt_drop_lower(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int x_mid, const int full_width, const int y_mid, const int half_height); protected: From 78e0f9bbe6535cd2acb8003b5ea04a1335861383 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 21 Jan 2009 00:20:33 +0000 Subject: [PATCH 036/216] WIP: Gave dragging a more immediate feeling --- .../timeline/timeline-layout-helper.cpp | 48 +++++++++++++++---- .../timeline/timeline-layout-helper.hpp | 8 +++- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 660f08f4d..e37e3ee91 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -42,6 +42,7 @@ namespace timeline { TimelineLayoutHelper::TimelineLayoutHelper(TimelineWidget &owner) : timelineWidget(owner), totalHeight(0), + dragBranchHeight(0), animating(false) { } @@ -146,6 +147,7 @@ TimelineLayoutHelper::begin_dragging_track( const shared_ptr model_track = draggingTrack->get_model_track(); draggingTrackIter = iterator_from_track(model_track); + dragBranchHeight = measure_branch_height(draggingTrackIter); return draggingTrack; } @@ -206,11 +208,10 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) const int x_mid = rect.get_x() + rect.get_width() / 2; // Do hit test - if(attempt_drop_upper(iterator, dragPoint, - y, full_width, half_height)) + if(attempt_drop_upper(iterator, y, full_width, half_height)) break; - if(attempt_drop_lower(iterator, dragPoint, + if(attempt_drop_lower(iterator, x_mid, full_width, y_mid, half_height)) break; } @@ -220,9 +221,13 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) bool TimelineLayoutHelper::attempt_drop_upper( - TrackTree::pre_order_iterator target, const Gdk::Point &point, - const int y, const int full_width, const int half_height) -{ + TrackTree::pre_order_iterator target, const int y, + const int full_width, const int half_height) +{ + const Gdk::Point point(dragPoint.get_x(), + dragPoint.get_y() - dragStartOffset.get_y() + + dragBranchHeight); + if(pt_in_rect(point, Gdk::Rectangle(0, y, full_width, half_height))) { draggingTrackIter = layoutTree.move_before( @@ -232,16 +237,18 @@ TimelineLayoutHelper::attempt_drop_upper( return false; } - bool TimelineLayoutHelper::attempt_drop_lower( - TrackTree::pre_order_iterator target, const Gdk::Point &point, + TrackTree::pre_order_iterator target, const int x_mid, const int full_width, const int y_mid, const int half_height) { const shared_ptr model_track(*target); REQUIRE(model_track); + const Gdk::Point point(dragPoint.get_x(), + dragPoint.get_y() - dragStartOffset.get_y()); + if(!pt_in_rect(point, Gdk::Rectangle(0, y_mid, full_width, half_height))) return false; @@ -324,6 +331,31 @@ TimelineLayoutHelper::iterator_from_track( return iter; } +int +TimelineLayoutHelper::measure_branch_height( + TrackTree::iterator_base parent_iterator) +{ + shared_ptr parent_track = + lookup_timeline_track(*parent_iterator); + + int branch_height = parent_track->get_height() + + TimelineWidget::TrackPadding; + + TrackTree::sibling_iterator iterator; + for(iterator = layoutTree.begin(parent_iterator); + iterator != layoutTree.end(parent_iterator); + iterator++) + { + shared_ptr child_track = + lookup_timeline_track(*iterator); + + if(child_track->get_expanded()) + branch_height += measure_branch_height(iterator); + } + + return branch_height; +} + void TimelineLayoutHelper::update_layout() { diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 524be4566..27616f9c7 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -157,6 +157,8 @@ public: **/ TrackTree::pre_order_iterator iterator_from_track( boost::shared_ptr model_track); + + int measure_branch_height(TrackTree::iterator_base parent_iterator); protected: @@ -221,11 +223,11 @@ protected: bool on_animation_tick(); bool -attempt_drop_upper(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int y, const int full_width, const int half_height); +attempt_drop_upper(TrackTree::pre_order_iterator target, const int y, const int full_width, const int half_height); bool -attempt_drop_lower(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int x_mid, const int full_width, const int y_mid, const int half_height); +attempt_drop_lower(TrackTree::pre_order_iterator target, const int x_mid, const int full_width, const int y_mid, const int half_height); protected: @@ -264,6 +266,8 @@ protected: Gdk::Point dragPoint; + int dragBranchHeight; + /** * The connection to the animation timer. * @see begin_animation() From 801f070a7de3bad358cb0a44ea2194823e9d850a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 21 Jan 2009 12:19:02 +0100 Subject: [PATCH 037/216] Fix for broken logic of the ClassLock (showed up on Ubuntu Hardy) this was nice copy-n-paster error, of course the implementation namespace was never intended to be anonymous. --- src/lib/sync-classlock.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib/sync-classlock.hpp b/src/lib/sync-classlock.hpp index 2cb37d17a..ea2c1a75d 100644 --- a/src/lib/sync-classlock.hpp +++ b/src/lib/sync-classlock.hpp @@ -41,22 +41,22 @@ namespace lib { - namespace { // implementation details + namespace nifty { // implementation details template - struct NiftyHolder + struct Holder { static uint accessed_; static char content_[sizeof(X)]; - NiftyHolder() + Holder() { if (!accessed_) new(content_) X(); ++accessed_; } - ~NiftyHolder() + ~Holder() { --accessed_; if (0==accessed_) @@ -73,12 +73,12 @@ namespace lib { }; template - uint NiftyHolder::accessed_; + uint Holder::accessed_; template - char NiftyHolder::content_[sizeof(X)]; + char Holder::content_[sizeof(X)]; - } // (End) implementation details + } // (End) nifty implementation details @@ -100,14 +100,14 @@ namespace lib { Monitor& getPerClassMonitor() { - static NiftyHolder __used_here; + static nifty::Holder __used_here; return __used_here.get(); } public: ClassLock() : Lock (getPerClassMonitor()) {} - uint use_count() { return NiftyHolder::accessed_; } + uint use_count() { return nifty::Holder::accessed_; } }; From 974e83676ace8dcb448504ea1e49176593f7b1c2 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 21 Jan 2009 13:04:28 +0100 Subject: [PATCH 038/216] Further ClassLock refactoring; added linkonce assertion check --- src/lib/sync-classlock.hpp | 18 +++++++++++++---- tests/lib/sync-classlock-test.cpp | 33 +++++++++++++++++++------------ 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/lib/sync-classlock.hpp b/src/lib/sync-classlock.hpp index ea2c1a75d..f4fe93dda 100644 --- a/src/lib/sync-classlock.hpp +++ b/src/lib/sync-classlock.hpp @@ -87,27 +87,37 @@ namespace lib { * to the parameter type as a whole, not an individual instance. * After creating an instance, every other access specifying the same * type is blocked. - * @warn beware of recursion when using a nonrecursive Mutex + * @note the Lock is recursive, because several instances within the same + * thread may want to acquire it at the same time without deadlock. + * @note there is a design sloppiness, as two instantiations of the + * ClassLock template with differing CONF count as different type. + * Actually using two different configurations within for a single + * class X should be detected and flagged as error, but actually + * just two non-shared lock instances get created silently. Beware! * @see Sync::Lock the usual simple instance-bound variant */ - template + template class ClassLock : public Sync::Lock { typedef typename Sync::Lock Lock; typedef typename sync::Monitor Monitor; + struct PerClassMonitor : Monitor {}; + Monitor& getPerClassMonitor() { - static nifty::Holder __used_here; + static nifty::Holder __used_here; + ASSERT (1==use_count(), "static init broken"); + return __used_here.get(); } public: ClassLock() : Lock (getPerClassMonitor()) {} - uint use_count() { return nifty::Holder::accessed_; } + uint use_count() { return nifty::Holder::accessed_; } }; diff --git a/tests/lib/sync-classlock-test.cpp b/tests/lib/sync-classlock-test.cpp index 81ad457d1..2cfa271e5 100644 --- a/tests/lib/sync-classlock-test.cpp +++ b/tests/lib/sync-classlock-test.cpp @@ -34,22 +34,25 @@ using test::Test; namespace lib { namespace test { - - namespace { // private test classes and data... + namespace { // private test classes and data... + const uint NUM_INSTANCES = 20; ///< number of probe instances to create - /** - * instances of this probe class will be created statically. - * They utilise the class-based locking within ctor and dtor + /** + * Several instances of this probe class will be created. + * Each of them acquires the shared lock; but anyway, just + * by defining this class, the embedded Monitor got created. */ struct Probe { - Probe() { ClassLock ctor_lock; } - ~Probe() { ClassLock dtor_lock; } + ClassLock shared_lock_; + + Probe() {} + ~Probe() {} }; - + } // (End) test classes and data.... @@ -76,17 +79,21 @@ namespace lib { { virtual void - run (Arg) + run (Arg) { - static Probe objs[NUM_INSTANCES]; + { + Probe objs[NUM_INSTANCES]; + + ASSERT (1 == objs[0].shared_lock_.use_count()); + } ClassLock get_class_lock; - ASSERT ( 1 == get_class_lock.use_count()); // ClassLock got created exactly once - } + ASSERT ( 1 == get_class_lock.use_count()); // embedded PerClassMonitor got created exactly once + } // and stays alive until static dtors are called.... }; - + /** Register this test class... */ LAUNCHER (SyncClasslock_test, "unit common"); From 1472a2ebe47e8108365da6bacf7b40983227ff90 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 21 Jan 2009 18:20:11 +0000 Subject: [PATCH 039/216] Improved track drop code --- .../timeline/timeline-layout-helper.cpp | 40 +++++++++++-------- .../timeline/timeline-layout-helper.hpp | 4 +- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index e37e3ee91..d4cefec4a 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -138,11 +138,13 @@ TimelineLayoutHelper::begin_dragging_track( if(!draggingTrack) return shared_ptr(); + dragPoint = Gdk::Point(mouse_point.get_x(), + mouse_point.get_y() + timelineWidget.get_y_scroll_offset()); + const Gdk::Rectangle &rect = headerBoxes[draggingTrack]; dragStartOffset = Gdk::Point( - mouse_point.get_x() - rect.get_x(), - mouse_point.get_y() - rect.get_y() + - timelineWidget.get_y_scroll_offset()); + dragPoint.get_x() - rect.get_x(), + dragPoint.get_y() - rect.get_y()); const shared_ptr model_track = draggingTrack->get_model_track(); @@ -176,9 +178,21 @@ void TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) { // Apply the scroll offset + const Gdk::Point last_point(dragPoint); dragPoint = Gdk::Point(point.get_x(), point.get_y() + timelineWidget.get_y_scroll_offset()); + // Get a test-point + // We probe on the bottom edge of the dragging branch if the track is + // being dragged downward, and on the top edge if it's being dragged + // upward. + Gdk::Point test_point(dragPoint.get_x(), + dragPoint.get_y() - dragStartOffset.get_y()); + if(last_point.get_y() > dragPoint.get_y()) + test_point.set_y(test_point.get_y()); + else + test_point.set_y(test_point.get_y() + dragBranchHeight); + // Search the headers TrackTree::pre_order_iterator iterator; @@ -208,10 +222,11 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) const int x_mid = rect.get_x() + rect.get_width() / 2; // Do hit test - if(attempt_drop_upper(iterator, y, full_width, half_height)) + if(attempt_drop_upper(iterator, test_point, y, + full_width, half_height)) break; - if(attempt_drop_lower(iterator, + if(attempt_drop_lower(iterator, test_point, x_mid, full_width, y_mid, half_height)) break; } @@ -221,13 +236,9 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) bool TimelineLayoutHelper::attempt_drop_upper( - TrackTree::pre_order_iterator target, const int y, - const int full_width, const int half_height) -{ - const Gdk::Point point(dragPoint.get_x(), - dragPoint.get_y() - dragStartOffset.get_y() + - dragBranchHeight); - + TrackTree::pre_order_iterator target, const Gdk::Point &point, + const int y, const int full_width, const int half_height) +{ if(pt_in_rect(point, Gdk::Rectangle(0, y, full_width, half_height))) { draggingTrackIter = layoutTree.move_before( @@ -239,15 +250,12 @@ TimelineLayoutHelper::attempt_drop_upper( bool TimelineLayoutHelper::attempt_drop_lower( - TrackTree::pre_order_iterator target, + TrackTree::pre_order_iterator target, const Gdk::Point &point, const int x_mid, const int full_width, const int y_mid, const int half_height) { const shared_ptr model_track(*target); REQUIRE(model_track); - - const Gdk::Point point(dragPoint.get_x(), - dragPoint.get_y() - dragStartOffset.get_y()); if(!pt_in_rect(point, Gdk::Rectangle(0, y_mid, full_width, half_height))) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 27616f9c7..4f7acf0b5 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -223,11 +223,11 @@ protected: bool on_animation_tick(); bool -attempt_drop_upper(TrackTree::pre_order_iterator target, const int y, const int full_width, const int half_height); +attempt_drop_upper(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int y, const int full_width, const int half_height); bool -attempt_drop_lower(TrackTree::pre_order_iterator target, const int x_mid, const int full_width, const int y_mid, const int half_height); +attempt_drop_lower(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int x_mid, const int full_width, const int y_mid, const int half_height); protected: From 355da8863050a9a0a6d0373f506e5e74be98e475 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 21 Jan 2009 18:40:13 +0000 Subject: [PATCH 040/216] Added a dragging cursor --- .../timeline/timeline-header-container.cpp | 25 ++++++++++++++----- .../timeline/timeline-header-container.hpp | 2 ++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 97df83cb6..4497be6bc 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -179,12 +179,7 @@ bool TimelineHeaderContainer::on_button_press_event ( bool TimelineHeaderContainer::on_button_release_event ( GdkEventButton* event) { - TimelineLayoutHelper &layout = timelineWidget.layoutHelper; - - // Has the user been dragging? - if(layout.get_dragging_track()) - layout.end_dragging_track(); - + end_drag(); return Container::on_button_release_event(event); } @@ -409,6 +404,24 @@ TimelineHeaderContainer::begin_drag() // Raise all the header widgets so they float above the widgets not // being dragged raise_recursive(layout.get_dragging_track_iter()); + + // Set the cursor to a hand + REQUIRE(gdkWindow); + gdkWindow->set_cursor(Gdk::Cursor(Gdk::HAND1)); +} + +void +TimelineHeaderContainer::end_drag() +{ + TimelineLayoutHelper &layout = timelineWidget.layoutHelper; + + // Has the user been dragging? + if(layout.get_dragging_track()) + layout.end_dragging_track(); + + // Reset the arrow as a cursor + REQUIRE(gdkWindow); + gdkWindow->set_cursor(Gdk::Cursor(Gdk::ARROW)); } void diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index be2250bab..fe1006b1d 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -184,6 +184,8 @@ private: boost::shared_ptr model_track); void begin_drag(); + + void end_drag(); /** * Recusively raises all the header widget windows in a branch to the From 5eadcfb56a3eab643a50d31595bef654d8967ec2 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 21 Jan 2009 22:15:50 +0000 Subject: [PATCH 041/216] Added boost and std namespaces to model/track.cpp --- src/gui/model/track.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index d13e698e1..b5cd7e2da 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -23,30 +23,33 @@ #include "track.hpp" #include +using namespace boost; +using namespace std; + namespace gui { namespace model { -const std::list< boost::shared_ptr > Track::NoChildren; +const list< shared_ptr > Track::NoChildren; Track::Track() { } -std::list< boost::shared_ptr > +list< shared_ptr > Track::get_child_tracks() const { return Track::NoChildren; } -const std::string +const string Track::get_name() const { return name; } void -Track::set_name(const std::string &name) +Track::set_name(const string &name) { this->name = name; } @@ -58,18 +61,18 @@ Track::can_host_children() const } bool -Track::remove_child_track(const boost::shared_ptr /*track*/) +Track::remove_child_track(const shared_ptr /*track*/) { return false; } -std::string +string Track::print_branch() { return print_branch_recursive(0); } -std::string +string Track::print_branch_recursive(const unsigned int indentation) { Glib::ustring str; @@ -79,7 +82,7 @@ Track::print_branch_recursive(const unsigned int indentation) str += print_track(); str += "\n"; - BOOST_FOREACH(boost::shared_ptr track, get_child_tracks()) + BOOST_FOREACH(shared_ptr track, get_child_tracks()) { REQUIRE(track); str += track->print_branch_recursive(indentation + 1); From f18c039074953d3ce8bf4427e18a77595f0e1150 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 21 Jan 2009 22:18:55 +0000 Subject: [PATCH 042/216] Replaced an errant Glib::ustring with std::string --- src/gui/model/track.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index b5cd7e2da..a0287efd9 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -75,8 +75,8 @@ Track::print_branch() string Track::print_branch_recursive(const unsigned int indentation) { - Glib::ustring str; - + string str; + for(unsigned int i = 0; i < indentation; i++) str += " "; str += print_track(); From 69253909e3943aed689cab784fc0c938405f07e7 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 21 Jan 2009 23:48:56 +0000 Subject: [PATCH 043/216] Initial drop code added --- src/gui/model/track.cpp | 19 ++ src/gui/model/track.hpp | 4 +- src/gui/widgets/timeline-widget.cpp | 18 +- src/gui/widgets/timeline-widget.hpp | 6 + .../timeline/timeline-header-container.cpp | 4 +- .../timeline/timeline-header-container.hpp | 2 +- .../timeline/timeline-layout-helper.cpp | 201 +++++++++++++----- .../timeline/timeline-layout-helper.hpp | 33 ++- 8 files changed, 228 insertions(+), 59 deletions(-) diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index a0287efd9..c8d1c3356 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -72,6 +72,25 @@ Track::print_branch() return print_branch_recursive(0); } +shared_ptr +Track::find_parent(shared_ptr root, shared_ptr child) +{ + REQUIRE(root != NULL); + REQUIRE(child != NULL); + const list< shared_ptr > children = root->get_child_tracks(); + BOOST_FOREACH(shared_ptr track, children) + { + if(track == child) + return root; + + shared_ptr result = find_parent(track, child); + if(result) + return result; + } + + return shared_ptr(); +} + string Track::print_branch_recursive(const unsigned int indentation) { diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index 300e0f9b8..37bbe955e 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -53,7 +53,9 @@ public: virtual std::string print_track() = 0; - + static boost::shared_ptr + find_parent(boost::shared_ptr root, + boost::shared_ptr child); protected: std::string print_branch_recursive(const unsigned int indentation); diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 0e589bba0..3aec39992 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -54,7 +54,8 @@ TimelineWidget::TimelineWidget( horizontalAdjustment(0, 0, 0), verticalAdjustment(0, 0, 0), horizontalScroll(horizontalAdjustment), - verticalScroll(verticalAdjustment) + verticalScroll(verticalAdjustment), + update_tracks_frozen(false) { REQUIRE(sequence); @@ -288,6 +289,9 @@ TimelineWidget::on_add_track_command() void TimelineWidget::update_tracks() { + if(update_tracks_frozen) + return; + REQUIRE(sequence); // Remove any tracks which are no longer present in the model @@ -301,6 +305,18 @@ TimelineWidget::update_tracks() layoutHelper.update_layout(); } +void +TimelineWidget::freeze_update_tracks() +{ + update_tracks_frozen = true; +} + +void +TimelineWidget::thaw_update_tracks() +{ + update_tracks_frozen = false; +} + void TimelineWidget::create_timeline_tracks() { diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index 7113d100f..d79547935 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -171,6 +171,10 @@ private: **/ void update_tracks(); + void freeze_update_tracks(); + + void thaw_update_tracks(); + /** * Ensures timeline UI tracks have been created for every model track * present in sequence. @@ -297,6 +301,8 @@ protected: sigc::signal playbackPeriodDragReleasedSignal; sigc::signal > hoveringTrackChangedSignal; + + bool update_tracks_frozen; /* ===== Constants ===== */ public: diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 4497be6bc..dfc81bef4 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -411,13 +411,13 @@ TimelineHeaderContainer::begin_drag() } void -TimelineHeaderContainer::end_drag() +TimelineHeaderContainer::end_drag(bool apply) { TimelineLayoutHelper &layout = timelineWidget.layoutHelper; // Has the user been dragging? if(layout.get_dragging_track()) - layout.end_dragging_track(); + layout.end_dragging_track(apply); // Reset the arrow as a cursor REQUIRE(gdkWindow); diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index fe1006b1d..6787d7984 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -185,7 +185,7 @@ private: void begin_drag(); - void end_drag(); + void end_drag(bool apply = true); /** * Recusively raises all the header widget windows in a branch to the diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index d4cefec4a..cb22de581 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -150,13 +150,18 @@ TimelineLayoutHelper::begin_dragging_track( draggingTrack->get_model_track(); draggingTrackIter = iterator_from_track(model_track); dragBranchHeight = measure_branch_height(draggingTrackIter); + + draggingDrop.relation = None; return draggingTrack; } void -TimelineLayoutHelper::end_dragging_track() +TimelineLayoutHelper::end_dragging_track(bool apply) { + if(apply) + apply_drop_to_model_tree(draggingDrop); + draggingTrack.reset(); clone_tree_from_sequence(); update_layout(); @@ -177,6 +182,8 @@ TimelineLayoutHelper::get_dragging_track_iter() const void TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) { + optional drop; + // Apply the scroll offset const Gdk::Point last_point(dragPoint); dragPoint = Gdk::Point(point.get_x(), @@ -221,34 +228,42 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) const int full_width = rect.get_x() + rect.get_width(); const int x_mid = rect.get_x() + rect.get_width() / 2; - // Do hit test - if(attempt_drop_upper(iterator, test_point, y, - full_width, half_height)) - break; + // Do hit test + drop = attempt_drop_upper(iterator, test_point, y, + full_width, half_height); + if(drop) break; - if(attempt_drop_lower(iterator, test_point, - x_mid, full_width, y_mid, half_height)) - break; + drop = attempt_drop_lower(iterator, test_point, + x_mid, full_width, y_mid, half_height); + if(drop) break; } - + + // Did we get a drop point? + if(drop) + { + apply_drop_to_layout_tree(*drop); + draggingDrop = *drop; + } + update_layout(); } -bool +optional TimelineLayoutHelper::attempt_drop_upper( TrackTree::pre_order_iterator target, const Gdk::Point &point, const int y, const int full_width, const int half_height) { if(pt_in_rect(point, Gdk::Rectangle(0, y, full_width, half_height))) { - draggingTrackIter = layoutTree.move_before( - target, draggingTrackIter); - return true; + Drop drop; + drop.target = target; + drop.relation = Before; + return drop; } - return false; + return optional(); } -bool +optional TimelineLayoutHelper::attempt_drop_lower( TrackTree::pre_order_iterator target, const Gdk::Point &point, const int x_mid, const int full_width, const int y_mid, @@ -259,7 +274,9 @@ TimelineLayoutHelper::attempt_drop_lower( if(!pt_in_rect(point, Gdk::Rectangle(0, y_mid, full_width, half_height))) - return false; + return optional(); + + Drop drop = {target, None}; if(model_track->can_host_children()) { @@ -267,47 +284,135 @@ TimelineLayoutHelper::attempt_drop_lower( { // Is our track being dragged after this header? if(dragPoint.get_x() < x_mid) - { - draggingTrackIter = layoutTree.move_after( - target, draggingTrackIter); - } + drop.relation = After; else - { - if(draggingTrackIter.node->parent != target.node) - { - // Insert a place-holder in the tree - const TrackTree::pre_order_iterator placeholder = - layoutTree.prepend_child(target); - - // Replace it with the relocated branch - draggingTrackIter = layoutTree.move_ontop( - placeholder, draggingTrackIter); - } - } + drop.relation = FirstChild; } else - { - if(draggingTrackIter.node->parent != target.node) - { - // Insert a place-holder in the tree - const TrackTree::pre_order_iterator placeholder = - layoutTree.append_child(target); - - // Replace it with the relocated branch - draggingTrackIter = layoutTree.move_ontop( - placeholder, draggingTrackIter); - } - } + drop.relation = LastChild; } else { // When this track cannot be a parent, the dragging track is - // simply dropped after - draggingTrackIter = layoutTree.move_after( - target, draggingTrackIter); + // simply dropped after + drop.relation = After; } - return true; + return drop; +} + +void +TimelineLayoutHelper::apply_drop_to_layout_tree( + const TimelineLayoutHelper::Drop &drop) +{ + switch(drop.relation) + { + case None: + break; + + case Before: + draggingTrackIter = layoutTree.move_before( + drop.target, draggingTrackIter); + break; + + case After: + draggingTrackIter = layoutTree.move_after( + drop.target, draggingTrackIter); + break; + + case FirstChild: + if(draggingTrackIter.node->parent != drop.target.node) + { + draggingTrackIter = layoutTree.move_ontop( + layoutTree.prepend_child(drop.target), draggingTrackIter); + } + break; + + case LastChild: + if(draggingTrackIter.node->parent != drop.target.node) + { + draggingTrackIter = layoutTree.move_ontop( + layoutTree.append_child(drop.target), draggingTrackIter); + } + break; + + default: + ASSERT(0); // Unexpected value of relation + break; + } +} + +void +TimelineLayoutHelper::apply_drop_to_model_tree( + const TimelineLayoutHelper::Drop &drop) +{ + if(drop.relation == None) + return; + + // Freeze the timeline widget - it must be done manually later + timelineWidget.freeze_update_tracks(); + + // Get the tracks + shared_ptr &dragging_track = *draggingTrackIter; + REQUIRE(dragging_track); + REQUIRE(dragging_track != timelineWidget.sequence); + + shared_ptr &target_track = *drop.target; + REQUIRE(target_track); + REQUIRE(target_track != timelineWidget.sequence); + + // Detach the track from the old parent + shared_ptr old_parent = + dynamic_pointer_cast( + model::Track::find_parent( + timelineWidget.sequence, dragging_track)); + REQUIRE(old_parent); // The track must have a parent + old_parent->get_child_track_list().remove(dragging_track); + + if(drop.relation == Before || drop.relation == After) + { + // Find the new parent track + shared_ptr new_parent = + dynamic_pointer_cast( + model::Track::find_parent( + timelineWidget.sequence, target_track)); + REQUIRE(new_parent); // The track must have a parent + + // Find the destination point + observable_list< shared_ptr > &dest = + new_parent->get_child_track_list(); + list< shared_ptr >::iterator iter; + for(iter = dest.begin(); iter != dest.end(); iter++) + { + if(*iter == target_track) + break; + } + REQUIRE(iter != dest.end()); // The target must be + // in the destination + + // We have to jump on 1 if we want to insert after + if(drop.relation == After) + iter++; + + // Insert at this point + dest.insert(iter, dragging_track); + } + else if(drop.relation == FirstChild || drop.relation == LastChild) + { + shared_ptr new_parent = + dynamic_pointer_cast( + target_track); + REQUIRE(new_parent); // The track must have a parent + + if(drop.relation == FirstChild) + new_parent->get_child_track_list().push_front(dragging_track); + else if(drop.relation == LastChild) + new_parent->get_child_track_list().push_back(dragging_track); + } + else ASSERT(0); // Unexpected value of relation + + // Freeze the timeline widget - we will do it manually + timelineWidget.freeze_update_tracks(); } int diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 4f7acf0b5..afecb6aab 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -130,7 +130,7 @@ public: boost::shared_ptr begin_dragging_track(const Gdk::Point &mouse_point); - void end_dragging_track(); + void end_dragging_track(bool apply); boost::shared_ptr get_dragging_track() const; @@ -159,7 +159,23 @@ public: boost::shared_ptr model_track); int measure_branch_height(TrackTree::iterator_base parent_iterator); + +protected: + enum TreeRelation + { + None, + Before, + After, + FirstChild, + LastChild + }; + struct Drop + { + TrackTree::pre_order_iterator target; + TreeRelation relation; + }; + protected: /** @@ -221,16 +237,19 @@ protected: * The animation timer tick callback. **/ bool on_animation_tick(); - -bool + +boost::optional attempt_drop_upper(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int y, const int full_width, const int half_height); -bool +boost::optional attempt_drop_lower(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int x_mid, const int full_width, const int y_mid, const int half_height); - -protected: + void apply_drop_to_layout_tree(const Drop &drop); + + void apply_drop_to_model_tree(const Drop &drop); + +protected: /** * The owner timeline widget as provided to the constructor. **/ @@ -268,6 +287,8 @@ protected: int dragBranchHeight; + Drop draggingDrop; + /** * The connection to the animation timer. * @see begin_animation() From 3dae60f559e22f954aac0be6ddd8642dd9f158e7 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 22 Jan 2009 17:29:17 +0100 Subject: [PATCH 044/216] add missing stubs to make it pass the compiler --- src/lib/singleton-ref.hpp | 2 +- src/proc/dummy-player-service.cpp | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/lib/singleton-ref.hpp b/src/lib/singleton-ref.hpp index f3fad3921..1adf14698 100644 --- a/src/lib/singleton-ref.hpp +++ b/src/lib/singleton-ref.hpp @@ -78,7 +78,7 @@ namespace lib { } - typedef void* _ThisType::*unspecified_bool_type; + typedef TY* _ThisType::*unspecified_bool_type; /** implicit conversion to "bool" */ operator unspecified_bool_type() const // never throws diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp index 400bfafa4..f1f80409a 100644 --- a/src/proc/dummy-player-service.cpp +++ b/src/proc/dummy-player-service.cpp @@ -259,7 +259,33 @@ namespace proc { { return theDescriptor(); } - + + DummyPlayer::~DummyPlayer() { } ///< emit the vtable here into this translation unit within liblumieraproc.so ... + DummyPlayer::Process::~Process() { } + + + + DummyPlayer::Process& + DummyPlayerService::start() + { + UNIMPLEMENTED ("initiate a new playback process"); + } + + + + void + ProcessImpl::pause(bool doPlay) + { + UNIMPLEMENTED ("pause playback"); + } + + + + void* const + ProcessImpl::getFrame() + { + UNIMPLEMENTED ("actually deliver a frame"); + } } // namespace proc From 7150ab9ee93941a99ec14079809a078427e3acbb Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 22 Jan 2009 23:16:46 +0100 Subject: [PATCH 045/216] add implementation of PlayProcess logic --- src/common/interfaceproxy.cpp | 5 +++++ src/proc/dummy-player-service.cpp | 27 +++++++++++++++++++++++---- src/proc/dummy-player-service.hpp | 14 +++++++++++++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 984555f28..bf7607f17 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -163,6 +163,11 @@ namespace lumiera { //----Proxy-Implementation-of-DummyPlayer-------- typedef proc::DummyPlayer::Process Process; + /** @note as an optimisation we hand out a direct reference + * to the implementing process object. While this ref could + * still be passed as handle to the C Language interface, using + * it directly within the client (=GUI) retains only on level + * of indirection, irrespective which interface is used. */ Process& start() { Process* pP = static_cast (_i_.startPlay()); diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp index f1f80409a..4984f9b45 100644 --- a/src/proc/dummy-player-service.cpp +++ b/src/proc/dummy-player-service.cpp @@ -247,7 +247,7 @@ namespace proc { , implInstance_(this,_instance) , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade)) { - INFO (operate, "GuiNotification Facade opened."); + INFO (operate, "DummyPlayer Facade opened."); } @@ -260,7 +260,8 @@ namespace proc { return theDescriptor(); } - DummyPlayer::~DummyPlayer() { } ///< emit the vtable here into this translation unit within liblumieraproc.so ... + // emit the vtable here into this translation unit within liblumieraproc.so ... + DummyPlayer::~DummyPlayer() { } DummyPlayer::Process::~Process() { } @@ -268,7 +269,22 @@ namespace proc { DummyPlayer::Process& DummyPlayerService::start() { - UNIMPLEMENTED ("initiate a new playback process"); + REQUIRE (!theProcess_.isActive()); + theProcess_.setRate(25); + + return theProcess_; + } + + + + void + ProcessImpl::setRate (uint fps) + { + REQUIRE (fps==0 || fps_==0 ); + REQUIRE (fps==0 || !play_ ); + + fps_ = fps; + play_ = (fps != 0); } @@ -276,7 +292,8 @@ namespace proc { void ProcessImpl::pause(bool doPlay) { - UNIMPLEMENTED ("pause playback"); + REQUIRE (isActive()); + play_ = doPlay; } @@ -284,6 +301,8 @@ namespace proc { void* const ProcessImpl::getFrame() { + REQUIRE (isActive()); + UNIMPLEMENTED ("actually deliver a frame"); } diff --git a/src/proc/dummy-player-service.hpp b/src/proc/dummy-player-service.hpp index 7610b91c3..f007e5cf4 100644 --- a/src/proc/dummy-player-service.hpp +++ b/src/proc/dummy-player-service.hpp @@ -59,8 +59,20 @@ namespace proc { void pause(bool doPlay); void* const getFrame(); + uint fps_; + bool play_; + public: - ProcessImpl() {} + ProcessImpl() : fps_(0), play_(false) {} + + /* Implementation-level API to be used By DummyPlayerService */ + + /** activate a playback process + * with given specification */ + void setRate (uint fps); + + bool isActive () { return fps_ != 0; } + bool isPlaying() { return play_; } }; From 791b09142a6aeb66ebf5cf4309fe888038fda3b0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 23 Jan 2009 03:05:21 +0100 Subject: [PATCH 046/216] Refactoring: extract test image generation code into a separate class --- src/proc/dummy-player-service.cpp | 310 ----------------------- src/proc/dummy-player-service.hpp | 130 ---------- src/proc/play/dummy-image-generator.cpp | 163 ++++++++++++ src/proc/play/dummy-image-generator.hpp | 85 +++++++ src/proc/play/dummy-player-service.cpp | 317 ++++++++++++++++++++++++ src/proc/play/dummy-player-service.hpp | 133 ++++++++++ 6 files changed, 698 insertions(+), 440 deletions(-) delete mode 100644 src/proc/dummy-player-service.cpp delete mode 100644 src/proc/dummy-player-service.hpp create mode 100644 src/proc/play/dummy-image-generator.cpp create mode 100644 src/proc/play/dummy-image-generator.hpp create mode 100644 src/proc/play/dummy-player-service.cpp create mode 100644 src/proc/play/dummy-player-service.hpp diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp deleted file mode 100644 index 4984f9b45..000000000 --- a/src/proc/dummy-player-service.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/* - DummyPlayerService - access point and service implementing a dummy test player - - Copyright (C) Lumiera.org - 2009, 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 "proc/dummy-player-service.hpp" -#include "lib/singleton.hpp" - -extern "C" { -#include "common/interfacedescriptor.h" -} - -#include -#include - - -namespace proc { - - using std::string; - using lumiera::Subsys; - using boost::scoped_ptr; - - - namespace { // hidden local details of the service implementation.... - - /** details of how the DummyPlayer service can be started - * and used as independent "subsystem" within main() */ - class DummyPlayerSubsysDescriptor - : public Subsys - { - operator string () const { return "Dummy-Player"; } - - - bool - shouldStart (lumiera::Option&) - { - return false; // for now the DummyPlayerService only comes "up" as dependency, - } // but doesn't start as a subsystem on it's own. - - bool - start (lumiera::Option&, Subsys::SigTerm terminationHandle) - { - ASSERT (!thePlayer_); - - thePlayer_.reset (new DummyPlayerService (terminationHandle)); - return true; - } - - /** manages the actual (single) instance of the player service impl */ - scoped_ptr thePlayer_; - - - void - triggerShutdown () throw() - { - TODO ("implement waiting for any playback processes to terminate gracefully"); - //..... but this would require us to use a separate thread, so I skip it for now. - // Probably it's better design to manage the processes in a separate thread anyway... - - thePlayer_.reset(0); - } - - bool - checkRunningState () throw() - { - //note: not locking here... - return (thePlayer_); - } - }; - - lumiera::Singleton theDescriptor; - - - - - - /* ================== define an lumieraorg_GuiNotification instance ======================= */ - - LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 - ,lumieraorg_DummyPlayerFacade_descriptor - , NULL, NULL, NULL - , LUMIERA_INTERFACE_INLINE (name, "\305\162\202\240\075\316\146\100\314\152\075\343\372\065\226\307", - const char*, (LumieraInterface ifa), - { (void)ifa; return "DummyPlayer"; } - ) - , LUMIERA_INTERFACE_INLINE (brief, "\317\045\366\076\064\072\156\274\220\346\262\207\062\367\057\232", - const char*, (LumieraInterface ifa), - { (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; } - ) - , LUMIERA_INTERFACE_INLINE (homepage, "\136\225\033\362\161\251\300\256\117\072\171\102\235\004\235\200", - const char*, (LumieraInterface ifa), - { (void)ifa; return "http://www.lumiera.org/develompent.html" ;} - ) - , LUMIERA_INTERFACE_INLINE (version, "\212\146\344\127\124\116\101\205\211\174\322\241\162\122\023\165", - const char*, (LumieraInterface ifa), - { (void)ifa; return "0.1~pre"; } - ) - , LUMIERA_INTERFACE_INLINE (author, "\064\226\072\300\054\345\042\357\337\226\155\025\306\051\117\105", - const char*, (LumieraInterface ifa), - { (void)ifa; return "Hermann Vosseler"; } - ) - , LUMIERA_INTERFACE_INLINE (email, "\041\075\220\112\246\304\261\135\003\135\060\202\230\327\303\206", - const char*, (LumieraInterface ifa), - { (void)ifa; return "Ichthyostega@web.de"; } - ) - , LUMIERA_INTERFACE_INLINE (copyright, "\232\305\163\271\174\025\270\075\012\201\331\256\327\375\066\210", - const char*, (LumieraInterface ifa), - { - (void)ifa; - return - "Copyright (C) Lumiera.org\n" - " 2009 Hermann Vosseler "; - } - ) - , LUMIERA_INTERFACE_INLINE (license, "\136\136\073\173\145\357\151\062\040\013\323\272\051\352\305\060", - const char*, (LumieraInterface ifa), - { - (void)ifa; - return - "This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n" - "\n" - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n" - "\n" - "You should have received a copy of the GNU General Public License\n" - "along with this program; if not, write to the Free Software\n" - "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"; - } - ) - , LUMIERA_INTERFACE_INLINE (state, "\224\251\004\001\165\140\116\246\126\311\115\234\023\026\331\350", - int, (LumieraInterface ifa), - {(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; } - ) - , LUMIERA_INTERFACE_INLINE (versioncmp, "\267\155\303\046\353\222\323\014\145\027\043\100\370\311\257\126", - int, (const char* a, const char* b), - {return 0;} ////////////////////////////////////////////TODO define version ordering - ) - ); - - - - - - using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; - typedef lib::SingletonRef::Accessor InstanceRef; - - InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation... - - typedef DummyPlayer::Process* ProcP; - - - LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0 - ,lumieraorg_DummyPlayerFacade - , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor) - , NULL /* on open */ - , NULL /* on close */ - , LUMIERA_INTERFACE_INLINE (startPlay, "\143\323\102\155\051\006\235\004\037\310\354\121\176\142\342\210", - LumieraPlayProcess, (void), - { - if (!_instance) - { - lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); - return 0; - } - - return static_cast (& (_instance->start())); - } - ) - , LUMIERA_INTERFACE_INLINE (pausePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307", - void, (LumieraPlayProcess handle, bool doPlay), - { - if (!_instance) - { - lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); - return; - } - - REQUIRE (handle); - ProcP proc = static_cast (handle); - - proc->pause(doPlay); - } - ) - , LUMIERA_INTERFACE_INLINE (terminate, "\005\265\115\021\076\143\010\215\373\252\370\174\235\136\340\004", - void, (LumieraPlayProcess handle), - { - if (!_instance) - { - lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); - return; - } - - REQUIRE (handle); - ProcP proc = static_cast (handle); - - UNIMPLEMENTED ("terminate a running playback process"); - } - ) - , LUMIERA_INTERFACE_INLINE (getFrame, "\230\130\101\300\047\065\170\052\226\164\026\112\150\166\074\134", - void *, (LumieraPlayProcess handle), - { - //skipping full checks for performance reasons - REQUIRE (_instance && !lumiera_error_peek()); - - REQUIRE (handle); - ProcP proc = static_cast (handle); - - return const_cast (proc->getFrame()); - } - ) - ); - - - - - } // (End) hidden service impl details - - - - - DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle) - : error_("") - , notifyTermination_(terminationHandle) - , implInstance_(this,_instance) - , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade)) - { - INFO (operate, "DummyPlayer Facade opened."); - } - - - - - /** @internal intended for use by main(). */ - Subsys& - DummyPlayer::getDescriptor() - { - return theDescriptor(); - } - - // emit the vtable here into this translation unit within liblumieraproc.so ... - DummyPlayer::~DummyPlayer() { } - DummyPlayer::Process::~Process() { } - - - - DummyPlayer::Process& - DummyPlayerService::start() - { - REQUIRE (!theProcess_.isActive()); - theProcess_.setRate(25); - - return theProcess_; - } - - - - void - ProcessImpl::setRate (uint fps) - { - REQUIRE (fps==0 || fps_==0 ); - REQUIRE (fps==0 || !play_ ); - - fps_ = fps; - play_ = (fps != 0); - } - - - - void - ProcessImpl::pause(bool doPlay) - { - REQUIRE (isActive()); - play_ = doPlay; - } - - - - void* const - ProcessImpl::getFrame() - { - REQUIRE (isActive()); - - UNIMPLEMENTED ("actually deliver a frame"); - } - - -} // namespace proc diff --git a/src/proc/dummy-player-service.hpp b/src/proc/dummy-player-service.hpp deleted file mode 100644 index f007e5cf4..000000000 --- a/src/proc/dummy-player-service.hpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player - - - Copyright (C) Lumiera.org - 2009, Hermann Vosseler - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file notification-service.hpp - ** A public service provided by the GUI, implementing the gui::GuiNotification facade interface. - ** The purpose of this service is to push state update and notification of events from the lower - ** layers into the Lumiera GUI. Typically, this happens asynchronously and triggered by events - ** within the lower layers. - ** - ** This service is the implementation of a layer separation facade interface. Clients should use - ** gui::GuiNotification#facade to access this service. This header defines the interface used - ** to \em provide this service, not to access it. - ** - ** @see gui::GuiFacade - ** @see guifacade.cpp starting this service - */ - - -#ifndef PROC_DUMMYPLAYER_SERVICE_H -#define PROC_DUMMYPLAYER_SERVICE_H - - -#include "include/dummy-player-facade.h" -#include "common/instancehandle.hpp" -#include "lib/singleton-ref.hpp" - -#include - - -namespace proc { - - using std::string; - using lumiera::Subsys; - - - class ProcessImpl - : public DummyPlayer::Process - { - void pause(bool doPlay); - void* const getFrame(); - - uint fps_; - bool play_; - - public: - ProcessImpl() : fps_(0), play_(false) {} - - /* Implementation-level API to be used By DummyPlayerService */ - - /** activate a playback process - * with given specification */ - void setRate (uint fps); - - bool isActive () { return fps_ != 0; } - bool isPlaying() { return play_; } - }; - - - /****************************************************** - * Actual implementation of the GuiNotification service - * within the Lumiera GTK GUI. Creating an instance of - * this class automatically registers the interface - * with the Lumiera Interface/Plugin system and creates - * a forwarding proxy within the application core to - * route calls through this interface. - * - * @todo the ctor of this class should take references - * to any internal service providers within the - * GUI which are needed to implement the service. - */ - class DummyPlayerService - : public DummyPlayer - { - - /* === Implementation of the Facade Interface === */ - - Process& start(); - - - /** for now we use an single inline Process... - * @todo actually implement multiple independent Playback processes! - * @todo I am aware holding this object inline may cause a segfault at shutdown! - */ - ProcessImpl theProcess_; - - string error_; - Subsys::SigTerm notifyTermination_; - - - - /* === Interface Lifecycle === */ - - typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) - , DummyPlayer - > ServiceInstanceHandle; - - lib::SingletonRef implInstance_; - ServiceInstanceHandle serviceInstance_; - - public: - DummyPlayerService(Subsys::SigTerm terminationHandle); - - ~DummyPlayerService() { notifyTermination_(&error_); } - - }; - - - -} // namespace proc -#endif diff --git a/src/proc/play/dummy-image-generator.cpp b/src/proc/play/dummy-image-generator.cpp new file mode 100644 index 000000000..ba1cef9c5 --- /dev/null +++ b/src/proc/play/dummy-image-generator.cpp @@ -0,0 +1,163 @@ +/* + DummyImageGenerator - creating test output frames for simulated playback + + Copyright (C) Lumiera.org + 2009, Joel Holdsworth , + 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 "proc/play/dummy-image-generator.hpp" + + +namespace proc { + namespace play { + + + + namespace { // implementation details + + + typedef unsigned char byte; + + inline int + clamp (const int &val, const int &maxval, const int &minval) + { + if(val > maxval) return maxval; + if(val < minval) return minval; + return val; + } + + inline void + rgb_to_yuv (int r, int g, int b, byte &y, byte &u, byte &v) + { + // This code isn't great, but it does the job + y = (byte)clamp((299 * r + 587 * g + 114 * b) / 1000, 235, 16); + v = (byte)clamp((500 * r - 419 * g - 81 * b) / 1000 + 127, 255, 0); + u = (byte)clamp((-169 * r - 331 * g + 500 * b) / 1000 + 127, 255, 0); + } + + + void + rgb_buffer_to_yuy2 (unsigned char *in, unsigned char *out) + { + for (uint i = 0; i < 320*240*2; i+=4) + { + byte y0, u0, v0; + const byte r0 = *(in++); + const byte g0 = *(in++); + const byte b0 = *(in++); + rgb_to_yuv(r0, g0, b0, y0, u0, v0); + + byte y1, u1, v1; + const byte r1 = *(in++); + const byte g1 = *(in++); + const byte b1 = *(in++); + rgb_to_yuv(r1, g1, b1, y1, u1, v1); + + out[i] = y0; + out[i + 1] = u0; + out[i + 2] = y1; + out[i + 3] = v0; + } } + + + } // (End) implementation details + + + + + DummyImageGenerator::DummyImageGenerator(uint fps) + : current_(0) + , frame_(0) + , fps_(fps) + { } + + + void * const + DummyImageGenerator::next() + { + + ++frame_; + if(frame_ > 2 * fps_) + frame_ = 0; + + if(frame_ < 1 * fps_) + { + // create random snow... + for(int i = 0; i < 320*240*3; i+=3) + { + byte value ( rand() ); + buf_[i] = value; + buf_[i+1] = value; + buf_[i+2] = value; + } + } + else + { // create a colour strip pattern + typedef unsigned char Row[320 * 3]; + + unsigned char * row = buf_; + + // create a colour strip pattern in the first row... + for(int x = 0; x < 320; ++x) + { + byte &r = row[x*3]; + byte &g = row[x*3+1]; + byte &b = row[x*3+2]; + + if (x < 1*320/7) r = 0xC0, g = 0xC0, b = 0xC0; + else if(x < 2*320/7) r = 0xC0, g = 0xC0, b = 0x00; + else if(x < 3*320/7) r = 0x00, g = 0xC0, b = 0xC0; + else if(x < 4*320/7) r = 0x00, g = 0xC0, b = 0x00; + else if(x < 5*320/7) r = 0xC0, g = 0x00, b = 0xC0; + else if(x < 6*320/7) r = 0xC0, g = 0x00, b = 0x00; + else r = 0x00, g = 0x00, b = 0xC0; + } + + // fill remaining rows of the frame with the same pattern + for(int y = 1; y < 240; ++y) + memcpy(buf_ + y*sizeof(Row), row, sizeof(Row)); + + } + + // select output buffer to return + unsigned char * outBuff; + + if (!current_) + { + outBuff = outFrame_A_; + current_= 1; + } + else + { + outBuff = outFrame_B_; + current_= 0; + } + + rgb_buffer_to_yuy2(buf_, outBuff); + return outBuff; + + } + + + + + } // namespace play + +} // namespace proc diff --git a/src/proc/play/dummy-image-generator.hpp b/src/proc/play/dummy-image-generator.hpp new file mode 100644 index 000000000..0cab60404 --- /dev/null +++ b/src/proc/play/dummy-image-generator.hpp @@ -0,0 +1,85 @@ +/* + DUMMY-IMAGE-GENERATOR.hpp - creating test output frames for simulated playback + + Copyright (C) Lumiera.org + 2009, Joel Holdsworth , + 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 dummy-image-generator.hpp + ** Generator for test dummy video frames to simulate playback of rendered output. + ** As of 1/2009 the render engine and source reading functions are not ready yet. + ** So, in order to learn how to build up the GUI/Playback interfaces, we use + ** this dummy image generator to create visible output. First implemented + ** by Joel within PlaybackController, then factored out into a separate + ** dummy playback service. + ** + ** @see gui::controller::PlaybackController + ** @see proc::play::DummyPlayerService + ** + */ + + +#ifndef PROC_PLAY_DUMMY_IMAGE_GENERATOR_H +#define PROC_PLAY_DUMMY_IMAGE_GENERATOR_H + + +#include "lib/error.hpp" + + +namespace proc { + namespace play { + + + class DummyImageGenerator + { + + unsigned char buf_[320 * 240 * 3]; ///< working buffer for next frame + + unsigned char outFrame_A_[320 * 240 * 4]; ///< output frame 1 + unsigned char outFrame_B_[320 * 240 * 4]; ///< output frame 2 + + uint current_; + uint frame_; + uint fps_; + + + public: + DummyImageGenerator(uint fps); + + ~DummyImageGenerator() { } + + /** generate the next frame and + * occupy the alternate buffer. + * @return the buffer containing the new frame + */ + void * const next(); + + + private: + + }; + + + + + } // namespace play + +} // namespace proc +#endif // PROC_PLAY_DUMMY_IMAGE_GENERATOR_H + diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp new file mode 100644 index 000000000..2d86a07c5 --- /dev/null +++ b/src/proc/play/dummy-player-service.cpp @@ -0,0 +1,317 @@ +/* + DummyPlayerService - access point and service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, 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 "proc/play/dummy-player-service.hpp" +#include "lib/singleton.hpp" + +extern "C" { +#include "common/interfacedescriptor.h" +} + +#include +#include + + +namespace proc { + namespace play{ + + using std::string; + using lumiera::Subsys; + using boost::scoped_ptr; + + + namespace { // hidden local details of the service implementation.... + + /** details of how the DummyPlayer service can be started + * and used as independent "subsystem" within main() */ + class DummyPlayerSubsysDescriptor + : public Subsys + { + operator string () const { return "Dummy-Player"; } + + + bool + shouldStart (lumiera::Option&) + { + return false; // for now the DummyPlayerService only comes "up" as dependency, + } // but doesn't start as a subsystem on it's own. + + bool + start (lumiera::Option&, Subsys::SigTerm terminationHandle) + { + ASSERT (!thePlayer_); + + thePlayer_.reset (new DummyPlayerService (terminationHandle)); + return true; + } + + /** manages the actual (single) instance of the player service impl */ + scoped_ptr thePlayer_; + + + void + triggerShutdown () throw() + { + TODO ("implement waiting for any playback processes to terminate gracefully"); + //..... but this would require us to use a separate thread, so I skip it for now. + // Probably it's better design to manage the processes in a separate thread anyway... + + thePlayer_.reset(0); + } + + bool + checkRunningState () throw() + { + //note: not locking here... + return (thePlayer_); + } + }; + + lumiera::Singleton theDescriptor; + + + + + + /* ================== define an lumieraorg_GuiNotification instance ======================= */ + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 + ,lumieraorg_DummyPlayerFacade_descriptor + , NULL, NULL, NULL + , LUMIERA_INTERFACE_INLINE (name, "\305\162\202\240\075\316\146\100\314\152\075\343\372\065\226\307", + const char*, (LumieraInterface ifa), + { (void)ifa; return "DummyPlayer"; } + ) + , LUMIERA_INTERFACE_INLINE (brief, "\317\045\366\076\064\072\156\274\220\346\262\207\062\367\057\232", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; } + ) + , LUMIERA_INTERFACE_INLINE (homepage, "\136\225\033\362\161\251\300\256\117\072\171\102\235\004\235\200", + const char*, (LumieraInterface ifa), + { (void)ifa; return "http://www.lumiera.org/develompent.html" ;} + ) + , LUMIERA_INTERFACE_INLINE (version, "\212\146\344\127\124\116\101\205\211\174\322\241\162\122\023\165", + const char*, (LumieraInterface ifa), + { (void)ifa; return "0.1~pre"; } + ) + , LUMIERA_INTERFACE_INLINE (author, "\064\226\072\300\054\345\042\357\337\226\155\025\306\051\117\105", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Hermann Vosseler"; } + ) + , LUMIERA_INTERFACE_INLINE (email, "\041\075\220\112\246\304\261\135\003\135\060\202\230\327\303\206", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Ichthyostega@web.de"; } + ) + , LUMIERA_INTERFACE_INLINE (copyright, "\232\305\163\271\174\025\270\075\012\201\331\256\327\375\066\210", + const char*, (LumieraInterface ifa), + { + (void)ifa; + return + "Copyright (C) Lumiera.org\n" + " 2009 Hermann Vosseler "; + } + ) + , LUMIERA_INTERFACE_INLINE (license, "\136\136\073\173\145\357\151\062\040\013\323\272\051\352\305\060", + const char*, (LumieraInterface ifa), + { + (void)ifa; + return + "This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version.\n" + "\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program; if not, write to the Free Software\n" + "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"; + } + ) + , LUMIERA_INTERFACE_INLINE (state, "\224\251\004\001\165\140\116\246\126\311\115\234\023\026\331\350", + int, (LumieraInterface ifa), + {(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; } + ) + , LUMIERA_INTERFACE_INLINE (versioncmp, "\267\155\303\046\353\222\323\014\145\027\043\100\370\311\257\126", + int, (const char* a, const char* b), + {return 0;} ////////////////////////////////////////////TODO define version ordering + ) + ); + + + + + + using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; + typedef lib::SingletonRef::Accessor InstanceRef; + + InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation... + + typedef DummyPlayer::Process* ProcP; + + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0 + ,lumieraorg_DummyPlayerFacade + , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor) + , NULL /* on open */ + , NULL /* on close */ + , LUMIERA_INTERFACE_INLINE (startPlay, "\143\323\102\155\051\006\235\004\037\310\354\121\176\142\342\210", + LumieraPlayProcess, (void), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return 0; + } + + return static_cast (& (_instance->start())); + } + ) + , LUMIERA_INTERFACE_INLINE (pausePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307", + void, (LumieraPlayProcess handle, bool doPlay), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return; + } + + REQUIRE (handle); + ProcP proc = static_cast (handle); + + proc->pause(doPlay); + } + ) + , LUMIERA_INTERFACE_INLINE (terminate, "\005\265\115\021\076\143\010\215\373\252\370\174\235\136\340\004", + void, (LumieraPlayProcess handle), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return; + } + + REQUIRE (handle); + ProcP proc = static_cast (handle); + + UNIMPLEMENTED ("terminate a running playback process"); + } + ) + , LUMIERA_INTERFACE_INLINE (getFrame, "\230\130\101\300\047\065\170\052\226\164\026\112\150\166\074\134", + void *, (LumieraPlayProcess handle), + { + //skipping full checks for performance reasons + REQUIRE (_instance && !lumiera_error_peek()); + + REQUIRE (handle); + ProcP proc = static_cast (handle); + + return const_cast (proc->getFrame()); + } + ) + ); + + + + + } // (End) hidden service impl details + + + + + DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle) + : error_("") + , notifyTermination_(terminationHandle) + , implInstance_(this,_instance) + , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade)) + { + INFO (operate, "DummyPlayer Facade opened."); + } + + + + + DummyPlayer::Process& + DummyPlayerService::start() + { + REQUIRE (!theProcess_.isActive()); + theProcess_.setRate(25); + + return theProcess_; + } + + + + void + ProcessImpl::setRate (uint fps) + { + REQUIRE (fps==0 || fps_==0 ); + REQUIRE (fps==0 || !play_ ); + + fps_ = fps; + play_ = (fps != 0); + } + + + + void + ProcessImpl::pause(bool doPlay) + { + REQUIRE (isActive()); + play_ = doPlay; + } + + + + void* const + ProcessImpl::getFrame() + { + REQUIRE (isActive()); + + UNIMPLEMENTED ("actually deliver a frame"); + } + + + + } // namespace play + + + + /** @internal intended for use by main(). */ + lumiera::Subsys& + DummyPlayer::getDescriptor() + { + return play::theDescriptor(); + } + + // emit the vtable here into this translation unit within liblumieraproc.so ... + DummyPlayer::~DummyPlayer() { } + DummyPlayer::Process::~Process() { } + + + + +} // namespace proc diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp new file mode 100644 index 000000000..1d7c9f9aa --- /dev/null +++ b/src/proc/play/dummy-player-service.hpp @@ -0,0 +1,133 @@ +/* + DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file notification-service.hpp + ** A public service provided by the GUI, implementing the gui::GuiNotification facade interface. + ** The purpose of this service is to push state update and notification of events from the lower + ** layers into the Lumiera GUI. Typically, this happens asynchronously and triggered by events + ** within the lower layers. + ** + ** This service is the implementation of a layer separation facade interface. Clients should use + ** gui::GuiNotification#facade to access this service. This header defines the interface used + ** to \em provide this service, not to access it. + ** + ** @see gui::GuiFacade + ** @see guifacade.cpp starting this service + */ + + +#ifndef PROC_DUMMYPLAYER_SERVICE_H +#define PROC_DUMMYPLAYER_SERVICE_H + + +#include "include/dummy-player-facade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" + +#include + + +namespace proc { + namespace play { + + using std::string; + using lumiera::Subsys; + + + class ProcessImpl + : public DummyPlayer::Process + { + void pause(bool doPlay); + void* const getFrame(); + + uint fps_; + bool play_; + + public: + ProcessImpl() : fps_(0), play_(false) {} + + /* Implementation-level API to be used By DummyPlayerService */ + + /** activate a playback process + * with given specification */ + void setRate (uint fps); + + bool isActive () { return fps_ != 0; } + bool isPlaying() { return play_; } + }; + + + /****************************************************** + * Actual implementation of the GuiNotification service + * within the Lumiera GTK GUI. Creating an instance of + * this class automatically registers the interface + * with the Lumiera Interface/Plugin system and creates + * a forwarding proxy within the application core to + * route calls through this interface. + * + * @todo the ctor of this class should take references + * to any internal service providers within the + * GUI which are needed to implement the service. + */ + class DummyPlayerService + : public DummyPlayer + { + + /* === Implementation of the Facade Interface === */ + + Process& start(); + + + /** for now we use an single inline Process... + * @todo actually implement multiple independent Playback processes! + * @todo I am aware holding this object inline may cause a segfault at shutdown! + */ + ProcessImpl theProcess_; + + string error_; + Subsys::SigTerm notifyTermination_; + + + + /* === Interface Lifecycle === */ + + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) + , DummyPlayer + > ServiceInstanceHandle; + + lib::SingletonRef implInstance_; + ServiceInstanceHandle serviceInstance_; + + public: + DummyPlayerService(Subsys::SigTerm terminationHandle); + + ~DummyPlayerService() { notifyTermination_(&error_); } + + }; + + + + + } // namespace play + +} // namespace proc +#endif From 6c3492396c6d32b28b5f63d94d89c392503e052f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 23 Jan 2009 04:15:58 +0100 Subject: [PATCH 047/216] Refactoring: switch gui::PlaybackController to use the player service --- src/gui/controller/controller.hpp | 5 +- src/gui/controller/playback-controller.cpp | 132 ++++++--------------- src/gui/controller/playback-controller.hpp | 14 ++- src/proc/play/dummy-image-generator.cpp | 9 +- src/proc/play/dummy-image-generator.hpp | 4 + src/proc/play/dummy-player-service.cpp | 10 +- src/proc/play/dummy-player-service.hpp | 11 +- 7 files changed, 82 insertions(+), 103 deletions(-) diff --git a/src/gui/controller/controller.hpp b/src/gui/controller/controller.hpp index 27f185e97..594f5e19e 100644 --- a/src/gui/controller/controller.hpp +++ b/src/gui/controller/controller.hpp @@ -23,11 +23,12 @@ ** This file contains the definition of the controller object */ -#include "playback-controller.hpp" - #ifndef CONTROLLER_HPP #define CONTROLLER_HPP +#include "playback-controller.hpp" + + namespace gui { namespace model { diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index d68373025..90b3ec29d 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -20,32 +20,46 @@ * *****************************************************/ -#include "playback-controller.hpp" -#include "../gtk-lumiera.hpp" +#include "gui/controller/playback-controller.hpp" +#include "lib/error.hpp" +#include namespace gui { namespace controller { PlaybackController::PlaybackController() : finish_playback_thread(false), - playing(false) -{ - start_playback_thread(); -} + playing(false), + playHandle(0) +{ } + PlaybackController::~PlaybackController() { mutex.lock(); finish_playback_thread = true; mutex.unlock(); - thread->join(); + if (thread) + thread->join(); } void PlaybackController::play() { Glib::Mutex::Lock lock(mutex); - playing = true; + try + { + playHandle = & (proc::DummyPlayer::facade().start()); + start_playback_thread(); + playing = true; + + } + catch (lumiera::error::State& err) + { + WARN (operate, "failed to start playback: %s" ,err.what()); + lumiera_error(); + playing = false; + } } void @@ -53,6 +67,8 @@ PlaybackController::pause() { Glib::Mutex::Lock lock(mutex); playing = false; + if (playHandle) + playHandle->pause(true); } void @@ -60,6 +76,7 @@ PlaybackController::stop() { Glib::Mutex::Lock lock(mutex); playing = false; + // TODO: stop player somehow? } bool @@ -97,108 +114,37 @@ PlaybackController::playback_thread() if(is_playing()) pull_frame(); - + + ////////////////////////////////TODO: usleep Glib::Thread::yield(); } } -typedef unsigned char byte; - -inline int -clamp(const int &val, const int &maxval, const int &minval) -{ - if(val > maxval) return maxval; - if(val < minval) return minval; - return val; -} - -inline void -rgb_to_yuv(int r, int g, int b, byte &y, byte &u, byte &v) -{ - // This code isn't great, but it does the job - y = (byte)clamp((299 * r + 587 * g + 114 * b) / 1000, 235, 16); - v = (byte)clamp((500 * r - 419 * g - 81 * b) / 1000 + 127, 255, 0); - u = (byte)clamp((-169 * r - 331 * g + 500 * b) / 1000 + 127, 255, 0); -} - -void rgb_buffer_to_yuy2(unsigned char *in, unsigned char *out) -{ - for(int i = 0; i < 320*240*2; i+=4) - { - byte y0, u0, v0; - const byte r0 = *(in++); - const byte g0 = *(in++); - const byte b0 = *(in++); - rgb_to_yuv(r0, g0, b0, y0, u0, v0); - - byte y1, u1, v1; - const byte r1 = *(in++); - const byte g1 = *(in++); - const byte b1 = *(in++); - rgb_to_yuv(r1, g1, b1, y1, u1, v1); - - out[i] = y0; - out[i + 1] = u0; - out[i + 2] = y1; - out[i + 3] = v0; - } -} void PlaybackController::pull_frame() { - static int frame = 0; - unsigned char in[320 * 240 * 3]; + REQUIRE (is_playing()); + REQUIRE (playHandle); - frame--; + unsigned char * newBuffer = reinterpret_cast (playHandle->getFrame()); - if(frame <= 0) - frame = 200; - - if(frame > 150) - { - for(int i = 0; i < 320*240*3; i+=3) - { - byte value = (byte)rand(); - in[i] = value; - in[i+1] = value; - in[i+2] = value; - } - } - else - { - unsigned char row[320 * 3]; - - for(int x = 0; x < 320; x++) - { - byte &r = row[x*3]; - byte &g = row[x*3+1]; - byte &b = row[x*3+2]; - - if(x < 1*320/7) r = 0xC0, g = 0xC0, b = 0xC0; - else if(x < 2*320/7) r = 0xC0, g = 0xC0, b = 0x00; - else if(x < 3*320/7) r = 0x00, g = 0xC0, b = 0xC0; - else if(x < 4*320/7) r = 0x00, g = 0xC0, b = 0x00; - else if(x < 5*320/7) r = 0xC0, g = 0x00, b = 0xC0; - else if(x < 6*320/7) r = 0xC0, g = 0x00, b = 0x00; - else r = 0x00, g = 0x00, b = 0xC0; - } - - for(int y = 0; y < 240; y++) + if (newBuffer != currentBuffer) { - memcpy(in + y*320*3, row, sizeof(row)); + currentBuffer = newBuffer; + dispatcher.emit(); + } + else + { + TRACE (render, "frame dropped?"); } - } - - rgb_buffer_to_yuy2(in, buffer); - - dispatcher.emit(); } + void PlaybackController::on_frame() { - frame_signal.emit(buffer); + frame_signal.emit(currentBuffer); } } // namespace controller diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 9333fcbc2..52a7d0b42 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -23,16 +23,20 @@ ** This file contains the definition of the playback controller object */ -#include -#include - #ifndef PLAYBACK_CONTROLLER_HPP #define PLAYBACK_CONTROLLER_HPP +#include "include/dummy-player-facade.h" + +#include +#include +#include + namespace gui { namespace controller { class PlaybackController + : boost::noncopyable { public: @@ -72,7 +76,9 @@ private: volatile bool playing; - unsigned char buffer[320 * 240 * 4]; + proc::DummyPlayer::Process *playHandle; + + unsigned char * currentBuffer; sigc::signal frame_signal; }; diff --git a/src/proc/play/dummy-image-generator.cpp b/src/proc/play/dummy-image-generator.cpp index ba1cef9c5..29d58a1ac 100644 --- a/src/proc/play/dummy-image-generator.cpp +++ b/src/proc/play/dummy-image-generator.cpp @@ -154,7 +154,14 @@ namespace proc { return outBuff; } - + + + void * const + DummyImageGenerator::current() + { + if (!current_) return outFrame_A_; + else return outFrame_B_; + } diff --git a/src/proc/play/dummy-image-generator.hpp b/src/proc/play/dummy-image-generator.hpp index 0cab60404..e24a4592e 100644 --- a/src/proc/play/dummy-image-generator.hpp +++ b/src/proc/play/dummy-image-generator.hpp @@ -69,6 +69,10 @@ namespace proc { * @return the buffer containing the new frame */ void * const next(); + + /** just re-return a pointer to the current frame + * without generating any new image data */ + void * const current(); private: diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 2d86a07c5..378d7d7ff 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -22,6 +22,7 @@ #include "proc/play/dummy-player-service.hpp" +#include "proc/play/dummy-image-generator.hpp" #include "lib/singleton.hpp" extern "C" { @@ -273,6 +274,9 @@ namespace proc { fps_ = fps; play_ = (fps != 0); + + if (play_) + imageGen_.reset(new DummyImageGenerator(fps)); } @@ -290,8 +294,12 @@ namespace proc { ProcessImpl::getFrame() { REQUIRE (isActive()); + ASSERT (imageGen_); - UNIMPLEMENTED ("actually deliver a frame"); + if (play_) + return imageGen_->next(); + else + return imageGen_->current(); } diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index 1d7c9f9aa..8f7a045e6 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -43,6 +43,7 @@ #include "common/instancehandle.hpp" #include "lib/singleton-ref.hpp" +#include #include @@ -53,6 +54,9 @@ namespace proc { using lumiera::Subsys; + class DummyImageGenerator; + + class ProcessImpl : public DummyPlayer::Process { @@ -60,10 +64,13 @@ namespace proc { void* const getFrame(); uint fps_; - bool play_; + bool play_; + + boost::scoped_ptr imageGen_; + public: - ProcessImpl() : fps_(0), play_(false) {} + ProcessImpl() : fps_(0), play_(false), imageGen_(0) {} /* Implementation-level API to be used By DummyPlayerService */ From 48a632434a76c239569b68711a16ee3f0d3c04cd Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 23 Jan 2009 19:57:12 +0100 Subject: [PATCH 048/216] switch from Glib::Mutex to an object monitor (using LumieraMutex) --- src/gui/controller/playback-controller.cpp | 21 +++++++++++++-------- src/gui/controller/playback-controller.hpp | 14 ++++++++++---- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index 90b3ec29d..27028dbfb 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -36,9 +36,7 @@ PlaybackController::PlaybackController() : PlaybackController::~PlaybackController() { - mutex.lock(); - finish_playback_thread = true; - mutex.unlock(); + quit_playback_thread(); if (thread) thread->join(); } @@ -46,7 +44,7 @@ PlaybackController::~PlaybackController() void PlaybackController::play() { - Glib::Mutex::Lock lock(mutex); + Lock sync(this); try { playHandle = & (proc::DummyPlayer::facade().start()); @@ -65,7 +63,7 @@ PlaybackController::play() void PlaybackController::pause() { - Glib::Mutex::Lock lock(mutex); + Lock sync(this); playing = false; if (playHandle) playHandle->pause(true); @@ -74,7 +72,7 @@ PlaybackController::pause() void PlaybackController::stop() { - Glib::Mutex::Lock lock(mutex); + Lock sync(this); playing = false; // TODO: stop player somehow? } @@ -82,7 +80,7 @@ PlaybackController::stop() bool PlaybackController::is_playing() { - Glib::Mutex::Lock lock(mutex); + Lock sync(this); return playing; } @@ -94,6 +92,13 @@ PlaybackController::start_playback_thread() this, &PlaybackController::playback_thread), true); } +void +PlaybackController::quit_playback_thread() +{ + Lock sync(this); + finish_playback_thread = true; +} + void PlaybackController::attach_viewer( const sigc::slot& on_frame) @@ -107,7 +112,7 @@ PlaybackController::playback_thread() for(;;) { { - Glib::Mutex::Lock lock(mutex); + Lock sync(this); if(finish_playback_thread) return; } diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 52a7d0b42..142737dfd 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -27,16 +27,22 @@ #define PLAYBACK_CONTROLLER_HPP #include "include/dummy-player-facade.h" +#include "lib/sync.hpp" #include #include #include namespace gui { -namespace controller { +namespace controller { + +using lib::Sync; +using lib::NonrecursiveLock_NoWait; + class PlaybackController - : boost::noncopyable + : boost::noncopyable, + public Sync { public: @@ -58,6 +64,8 @@ private: void start_playback_thread(); + void quit_playback_thread(); + void playback_thread(); void pull_frame(); @@ -68,8 +76,6 @@ private: Glib::Thread *thread; - Glib::StaticMutex mutex; - Glib::Dispatcher dispatcher; volatile bool finish_playback_thread; From 58512e8a340359703a5015ef9250da726a51fb1a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 23 Jan 2009 20:23:24 +0100 Subject: [PATCH 049/216] First version working again. Thread handling is not stable and stop hangs though --- src/gui/controller/playback-controller.cpp | 29 ++++++++++++++-------- src/gui/controller/playback-controller.hpp | 2 +- src/lumiera/main.cpp | 3 +++ src/proc/play/dummy-player-service.cpp | 8 +++--- src/proc/play/dummy-player-service.hpp | 2 +- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index 27028dbfb..bad1ebcc1 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -28,6 +28,7 @@ namespace gui { namespace controller { PlaybackController::PlaybackController() : + thread(0), finish_playback_thread(false), playing(false), playHandle(0) @@ -36,9 +37,7 @@ PlaybackController::PlaybackController() : PlaybackController::~PlaybackController() { - quit_playback_thread(); - if (thread) - thread->join(); + end_playback_thread(); } void @@ -47,10 +46,15 @@ PlaybackController::play() Lock sync(this); try { - playHandle = & (proc::DummyPlayer::facade().start()); - start_playback_thread(); - playing = true; - + if (playing && thread && playHandle) playHandle->pause(false); + else + { + playHandle = & (proc::DummyPlayer::facade().start()); + if (thread) + end_playback_thread(); + start_playback_thread(); + playing = true; + } } catch (lumiera::error::State& err) { @@ -74,6 +78,8 @@ PlaybackController::stop() { Lock sync(this); playing = false; + end_playback_thread(); + playHandle = 0; // TODO: stop player somehow? } @@ -88,15 +94,19 @@ void PlaybackController::start_playback_thread() { dispatcher.connect(sigc::mem_fun(this, &PlaybackController::on_frame)); + finish_playback_thread = false; thread = Glib::Thread::create (sigc::mem_fun( this, &PlaybackController::playback_thread), true); } void -PlaybackController::quit_playback_thread() +PlaybackController::end_playback_thread() { Lock sync(this); finish_playback_thread = true; + if (thread) + thread->join(); + thread = 0; } void @@ -120,8 +130,7 @@ PlaybackController::playback_thread() if(is_playing()) pull_frame(); - ////////////////////////////////TODO: usleep - Glib::Thread::yield(); + usleep(40000); // ca 25 frames pre second } } diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 142737dfd..9cab6d968 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -64,7 +64,7 @@ private: void start_playback_thread(); - void quit_playback_thread(); + void end_playback_thread(); void playback_thread(); diff --git a/src/lumiera/main.cpp b/src/lumiera/main.cpp index 9d0317102..05e732a9f 100644 --- a/src/lumiera/main.cpp +++ b/src/lumiera/main.cpp @@ -30,6 +30,7 @@ #include "backend/enginefacade.hpp" #include "backend/netnodefacade.hpp" #include "backend/scriptrunnerfacade.hpp" +#include "include/dummy-player-facade.h" #include "proc/facade.hpp" #include "gui/guifacade.hpp" @@ -42,6 +43,7 @@ namespace { Subsys& engine = backend::EngineFacade::getDescriptor(); Subsys& netNode = backend::NetNodeFacade::getDescriptor(); Subsys& script = backend::ScriptRunnerFacade::getDescriptor(); + Subsys& player = proc::DummyPlayer::getDescriptor(); Subsys& builder = proc::Facade::getBuilderDescriptor(); Subsys& session = proc::Facade::getSessionDescriptor(); Subsys& lumigui = gui::GuiFacade::getDescriptor(); @@ -66,6 +68,7 @@ main (int argc, const char* argv[]) netNode.depends (engine); // lumigui.depends (session); //////TODO commented out in order to be able to start up a dummy GuiStarterPlugin // lumigui.depends (engine); + lumigui.depends (player); script.depends (session); script.depends (engine); diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 378d7d7ff..4ec1a87ad 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -258,7 +258,7 @@ namespace proc { DummyPlayer::Process& DummyPlayerService::start() { - REQUIRE (!theProcess_.isActive()); + // REQUIRE (!theProcess_.isActive()); //////////////TODO: reactivate this check when we have really independent processes which can be stopped! theProcess_.setRate(25); return theProcess_; @@ -269,7 +269,7 @@ namespace proc { void ProcessImpl::setRate (uint fps) { - REQUIRE (fps==0 || fps_==0 ); + // REQUIRE (fps==0 || fps_==0 ); //////////////TODO: reactivate this check when we have really independent processes which can be stopped! REQUIRE (fps==0 || !play_ ); fps_ = fps; @@ -282,10 +282,10 @@ namespace proc { void - ProcessImpl::pause(bool doPlay) + ProcessImpl::pause(bool doPause) { REQUIRE (isActive()); - play_ = doPlay; + play_ = !doPause; } diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index 8f7a045e6..ae8b3161e 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -60,7 +60,7 @@ namespace proc { class ProcessImpl : public DummyPlayer::Process { - void pause(bool doPlay); + void pause(bool doPause); void* const getFrame(); uint fps_; From e15adf1afb6b9ebc7ad409d4d4d2416fbb27e83c Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 10:15:58 +0000 Subject: [PATCH 050/216] Reorganized attempt_drop_* functions --- .../timeline/timeline-layout-helper.cpp | 120 ++++++++---------- .../timeline/timeline-layout-helper.hpp | 9 +- 2 files changed, 55 insertions(+), 74 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index cb22de581..5a7d05e83 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -182,7 +182,7 @@ TimelineLayoutHelper::get_dragging_track_iter() const void TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) { - optional drop; + Drop drop; // Apply the scroll offset const Gdk::Point last_point(dragPoint); @@ -209,95 +209,79 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) { // Skip the dragging branch if(iterator == draggingTrackIter) + iterator.skip_children(); + else { - iterator.skip_children(); - continue; + // Do hit test + drop = attempt_drop(iterator, test_point); + if(drop.relation != None) + break; } - - // Lookup the tracks - const shared_ptr model_track(*iterator); - REQUIRE(model_track); - const weak_ptr timeline_track = - lookup_timeline_track(model_track); - - // Calculate coordinates - const Gdk::Rectangle &rect = headerBoxes[timeline_track]; - const int half_height = rect.get_height() / 2; - const int y = rect.get_y(); - const int y_mid = y + half_height; - const int full_width = rect.get_x() + rect.get_width(); - const int x_mid = rect.get_x() + rect.get_width() / 2; - - // Do hit test - drop = attempt_drop_upper(iterator, test_point, y, - full_width, half_height); - if(drop) break; - - drop = attempt_drop_lower(iterator, test_point, - x_mid, full_width, y_mid, half_height); - if(drop) break; } // Did we get a drop point? - if(drop) + if(drop.relation != None) { - apply_drop_to_layout_tree(*drop); - draggingDrop = *drop; + apply_drop_to_layout_tree(drop); + draggingDrop = drop; } update_layout(); } -optional -TimelineLayoutHelper::attempt_drop_upper( - TrackTree::pre_order_iterator target, const Gdk::Point &point, - const int y, const int full_width, const int half_height) -{ - if(pt_in_rect(point, Gdk::Rectangle(0, y, full_width, half_height))) - { - Drop drop; - drop.target = target; - drop.relation = Before; - return drop; - } - return optional(); -} - -optional -TimelineLayoutHelper::attempt_drop_lower( - TrackTree::pre_order_iterator target, const Gdk::Point &point, - const int x_mid, const int full_width, const int y_mid, - const int half_height) +TimelineLayoutHelper::Drop +TimelineLayoutHelper::attempt_drop(TrackTree::pre_order_iterator target, + const Gdk::Point &point) { + // Lookup the tracks const shared_ptr model_track(*target); REQUIRE(model_track); - - if(!pt_in_rect(point, Gdk::Rectangle(0, y_mid, - full_width, half_height))) - return optional(); + const weak_ptr timeline_track = + lookup_timeline_track(model_track); + + // Calculate coordinates + const Gdk::Rectangle &rect = headerBoxes[timeline_track]; + const int half_height = rect.get_height() / 2; + const int y = rect.get_y(); + const int y_mid = y + half_height; + const int full_width = rect.get_x() + rect.get_width(); + const int x_mid = rect.get_x() + rect.get_width() / 2; + // Initialize the drop + // By specifying relation = None, the default return value will signal + // no drop-point was foind at point Drop drop = {target, None}; - - if(model_track->can_host_children()) + + if(pt_in_rect(point, Gdk::Rectangle(0, y, full_width, half_height))) { - if(model_track->get_child_tracks().empty()) + // We're hovering over the upper half of the header + drop.relation = Before; + } + else if(pt_in_rect(point, Gdk::Rectangle(0, y_mid, + full_width, half_height))) + { + // We're hovering over the lower half of the header + if(model_track->can_host_children()) { - // Is our track being dragged after this header? - if(dragPoint.get_x() < x_mid) - drop.relation = After; + if(model_track->get_child_tracks().empty()) + { + // Is our track being dragged after this header? + if(dragPoint.get_x() < x_mid) + drop.relation = After; + else + drop.relation = FirstChild; + } else - drop.relation = FirstChild; + drop.relation = LastChild; } else - drop.relation = LastChild; + { + // When this track cannot be a parent, the dragging track is + // simply dropped after + drop.relation = After; + } } - else - { - // When this track cannot be a parent, the dragging track is - // simply dropped after - drop.relation = After; - } - + return drop; } diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index afecb6aab..5233a801e 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -238,12 +238,9 @@ protected: **/ bool on_animation_tick(); -boost::optional -attempt_drop_upper(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int y, const int full_width, const int half_height); - - -boost::optional -attempt_drop_lower(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int x_mid, const int full_width, const int y_mid, const int half_height); + TimelineLayoutHelper::Drop + attempt_drop(TrackTree::pre_order_iterator target, + const Gdk::Point &point); void apply_drop_to_layout_tree(const Drop &drop); From 1908ff08a03f3280447f1848ad0f0522436765f6 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 10:37:04 +0000 Subject: [PATCH 051/216] Removed extraneous TimelineLayoutHelper::draggingTrack member --- .../timeline/timeline-header-container.cpp | 9 ++---- .../timeline/timeline-layout-helper.cpp | 31 ++++++++++++------- .../timeline/timeline-layout-helper.hpp | 6 ++-- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index dfc81bef4..c4e189081 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -201,14 +201,14 @@ bool TimelineHeaderContainer::on_motion_notify_event ( // Are we beginning to drag a header? if((event->state & GDK_BUTTON1_MASK) && hoveringTrack && - !layout.get_dragging_track()) + !layout.is_dragging_track()) { begin_drag(); return result; } // Are we currently dragging? - if(layout.get_dragging_track()) + if(layout.is_dragging_track()) { // Forward the message to the layout manager layout.drag_to_point(mousePoint); @@ -346,9 +346,6 @@ TimelineHeaderContainer::layout_headers() timelineWidget.layoutHelper; const TimelineLayoutHelper::TrackTree &layout_tree = layout_helper.get_layout_tree(); - - shared_ptr dragging_track = - layout_helper.get_dragging_track(); TimelineLayoutHelper::TrackTree::pre_order_iterator iterator; for(iterator = ++layout_tree.begin(); // ++ so that we skip the sequence root @@ -416,7 +413,7 @@ TimelineHeaderContainer::end_drag(bool apply) TimelineLayoutHelper &layout = timelineWidget.layoutHelper; // Has the user been dragging? - if(layout.get_dragging_track()) + if(layout.is_dragging_track()) layout.end_dragging_track(apply); // Reset the arrow as a cursor diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 5a7d05e83..4df9b0c98 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -45,6 +45,8 @@ TimelineLayoutHelper::TimelineLayoutHelper(TimelineWidget &owner) : dragBranchHeight(0), animating(false) { + // Init draggingTrackIter into a non-dragging state + draggingTrackIter.node = NULL; } void @@ -134,26 +136,27 @@ shared_ptr TimelineLayoutHelper::begin_dragging_track( const Gdk::Point &mouse_point) { - draggingTrack = header_from_point(mouse_point); - if(!draggingTrack) + shared_ptr dragging_track = + header_from_point(mouse_point); + if(!dragging_track) return shared_ptr(); dragPoint = Gdk::Point(mouse_point.get_x(), mouse_point.get_y() + timelineWidget.get_y_scroll_offset()); - const Gdk::Rectangle &rect = headerBoxes[draggingTrack]; + const Gdk::Rectangle &rect = headerBoxes[dragging_track]; dragStartOffset = Gdk::Point( dragPoint.get_x() - rect.get_x(), dragPoint.get_y() - rect.get_y()); const shared_ptr model_track = - draggingTrack->get_model_track(); + dragging_track->get_model_track(); draggingTrackIter = iterator_from_track(model_track); dragBranchHeight = measure_branch_height(draggingTrackIter); draggingDrop.relation = None; - return draggingTrack; + return dragging_track; } void @@ -162,15 +165,15 @@ TimelineLayoutHelper::end_dragging_track(bool apply) if(apply) apply_drop_to_model_tree(draggingDrop); - draggingTrack.reset(); + draggingTrackIter.node = NULL; clone_tree_from_sequence(); update_layout(); } -boost::shared_ptr -TimelineLayoutHelper::get_dragging_track() const +bool +TimelineLayoutHelper::is_dragging_track() const { - return draggingTrack; + return draggingTrackIter.node != NULL; } TimelineLayoutHelper::TrackTree::pre_order_iterator @@ -484,8 +487,9 @@ TimelineLayoutHelper::layout_headers_recursive( { REQUIRE(depth >= 0); + const bool dragging = is_dragging_track(); int child_offset = 0; - + TrackTree::sibling_iterator iterator; for(iterator = layoutTree.begin(parent_iterator); iterator != layoutTree.end(parent_iterator); @@ -498,8 +502,11 @@ TimelineLayoutHelper::layout_headers_recursive( REQUIRE(model_track); shared_ptr timeline_track = lookup_timeline_track(model_track); - - const bool being_dragged = (timeline_track == draggingTrack); + + // Is this the root track of a dragging branch? + bool being_dragged = false; + if(dragging) + being_dragged = (model_track == *draggingTrackIter); // Is the track going to be shown? if(parent_expanded) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 5233a801e..18463af49 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -132,7 +132,7 @@ public: void end_dragging_track(bool apply); - boost::shared_ptr get_dragging_track() const; + bool is_dragging_track() const; TrackTree::pre_order_iterator get_dragging_track_iter() const; @@ -275,9 +275,7 @@ protected: int totalHeight; TrackTree::pre_order_iterator draggingTrackIter; - - boost::shared_ptr draggingTrack; - + Gdk::Point dragStartOffset; Gdk::Point dragPoint; From 9879aef3ddb3dc903a3de272eda182a4e5c1a9cc Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 10:58:54 +0000 Subject: [PATCH 052/216] Tidied and documented TimelineLayoutHelper --- .../timeline/timeline-layout-helper.cpp | 357 +++++++++--------- .../timeline/timeline-layout-helper.hpp | 134 ++++++- 2 files changed, 304 insertions(+), 187 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 4df9b0c98..105e6fcd1 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -154,7 +154,7 @@ TimelineLayoutHelper::begin_dragging_track( draggingTrackIter = iterator_from_track(model_track); dragBranchHeight = measure_branch_height(draggingTrackIter); - draggingDrop.relation = None; + dropPoint.relation = None; return dragging_track; } @@ -163,7 +163,7 @@ void TimelineLayoutHelper::end_dragging_track(bool apply) { if(apply) - apply_drop_to_model_tree(draggingDrop); + apply_drop_to_model_tree(dropPoint); draggingTrackIter.node = NULL; clone_tree_from_sequence(); @@ -183,14 +183,17 @@ TimelineLayoutHelper::get_dragging_track_iter() const } void -TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) +TimelineLayoutHelper::drag_to_point(const Gdk::Point &mouse_point) { - Drop drop; + DropPoint drop; + + // begin_dragging_track must have been called before + REQUIRE(is_dragging_track()); // Apply the scroll offset const Gdk::Point last_point(dragPoint); - dragPoint = Gdk::Point(point.get_x(), - point.get_y() + timelineWidget.get_y_scroll_offset()); + dragPoint = Gdk::Point(mouse_point.get_x(), + mouse_point.get_y() + timelineWidget.get_y_scroll_offset()); // Get a test-point // We probe on the bottom edge of the dragging branch if the track is @@ -226,182 +229,12 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) if(drop.relation != None) { apply_drop_to_layout_tree(drop); - draggingDrop = drop; + dropPoint = drop; } update_layout(); } -TimelineLayoutHelper::Drop -TimelineLayoutHelper::attempt_drop(TrackTree::pre_order_iterator target, - const Gdk::Point &point) -{ - // Lookup the tracks - const shared_ptr model_track(*target); - REQUIRE(model_track); - const weak_ptr timeline_track = - lookup_timeline_track(model_track); - - // Calculate coordinates - const Gdk::Rectangle &rect = headerBoxes[timeline_track]; - const int half_height = rect.get_height() / 2; - const int y = rect.get_y(); - const int y_mid = y + half_height; - const int full_width = rect.get_x() + rect.get_width(); - const int x_mid = rect.get_x() + rect.get_width() / 2; - - // Initialize the drop - // By specifying relation = None, the default return value will signal - // no drop-point was foind at point - Drop drop = {target, None}; - - if(pt_in_rect(point, Gdk::Rectangle(0, y, full_width, half_height))) - { - // We're hovering over the upper half of the header - drop.relation = Before; - } - else if(pt_in_rect(point, Gdk::Rectangle(0, y_mid, - full_width, half_height))) - { - // We're hovering over the lower half of the header - if(model_track->can_host_children()) - { - if(model_track->get_child_tracks().empty()) - { - // Is our track being dragged after this header? - if(dragPoint.get_x() < x_mid) - drop.relation = After; - else - drop.relation = FirstChild; - } - else - drop.relation = LastChild; - } - else - { - // When this track cannot be a parent, the dragging track is - // simply dropped after - drop.relation = After; - } - } - - return drop; -} - -void -TimelineLayoutHelper::apply_drop_to_layout_tree( - const TimelineLayoutHelper::Drop &drop) -{ - switch(drop.relation) - { - case None: - break; - - case Before: - draggingTrackIter = layoutTree.move_before( - drop.target, draggingTrackIter); - break; - - case After: - draggingTrackIter = layoutTree.move_after( - drop.target, draggingTrackIter); - break; - - case FirstChild: - if(draggingTrackIter.node->parent != drop.target.node) - { - draggingTrackIter = layoutTree.move_ontop( - layoutTree.prepend_child(drop.target), draggingTrackIter); - } - break; - - case LastChild: - if(draggingTrackIter.node->parent != drop.target.node) - { - draggingTrackIter = layoutTree.move_ontop( - layoutTree.append_child(drop.target), draggingTrackIter); - } - break; - - default: - ASSERT(0); // Unexpected value of relation - break; - } -} - -void -TimelineLayoutHelper::apply_drop_to_model_tree( - const TimelineLayoutHelper::Drop &drop) -{ - if(drop.relation == None) - return; - - // Freeze the timeline widget - it must be done manually later - timelineWidget.freeze_update_tracks(); - - // Get the tracks - shared_ptr &dragging_track = *draggingTrackIter; - REQUIRE(dragging_track); - REQUIRE(dragging_track != timelineWidget.sequence); - - shared_ptr &target_track = *drop.target; - REQUIRE(target_track); - REQUIRE(target_track != timelineWidget.sequence); - - // Detach the track from the old parent - shared_ptr old_parent = - dynamic_pointer_cast( - model::Track::find_parent( - timelineWidget.sequence, dragging_track)); - REQUIRE(old_parent); // The track must have a parent - old_parent->get_child_track_list().remove(dragging_track); - - if(drop.relation == Before || drop.relation == After) - { - // Find the new parent track - shared_ptr new_parent = - dynamic_pointer_cast( - model::Track::find_parent( - timelineWidget.sequence, target_track)); - REQUIRE(new_parent); // The track must have a parent - - // Find the destination point - observable_list< shared_ptr > &dest = - new_parent->get_child_track_list(); - list< shared_ptr >::iterator iter; - for(iter = dest.begin(); iter != dest.end(); iter++) - { - if(*iter == target_track) - break; - } - REQUIRE(iter != dest.end()); // The target must be - // in the destination - - // We have to jump on 1 if we want to insert after - if(drop.relation == After) - iter++; - - // Insert at this point - dest.insert(iter, dragging_track); - } - else if(drop.relation == FirstChild || drop.relation == LastChild) - { - shared_ptr new_parent = - dynamic_pointer_cast( - target_track); - REQUIRE(new_parent); // The track must have a parent - - if(drop.relation == FirstChild) - new_parent->get_child_track_list().push_front(dragging_track); - else if(drop.relation == LastChild) - new_parent->get_child_track_list().push_back(dragging_track); - } - else ASSERT(0); // Unexpected value of relation - - // Freeze the timeline widget - we will do it manually - timelineWidget.freeze_update_tracks(); -} - int TimelineLayoutHelper::get_total_height() const { @@ -612,6 +445,176 @@ TimelineLayoutHelper::on_animation_tick() return animating; } +TimelineLayoutHelper::DropPoint +TimelineLayoutHelper::attempt_drop(TrackTree::pre_order_iterator target, + const Gdk::Point &point) +{ + // Lookup the tracks + const shared_ptr model_track(*target); + REQUIRE(model_track); + const weak_ptr timeline_track = + lookup_timeline_track(model_track); + + // Calculate coordinates + const Gdk::Rectangle &rect = headerBoxes[timeline_track]; + const int half_height = rect.get_height() / 2; + const int y = rect.get_y(); + const int y_mid = y + half_height; + const int full_width = rect.get_x() + rect.get_width(); + const int x_mid = rect.get_x() + rect.get_width() / 2; + + // Initialize the drop + // By specifying relation = None, the default return value will signal + // no drop-point was foind at point + DropPoint drop = {target, None}; + + if(pt_in_rect(point, Gdk::Rectangle(0, y, full_width, half_height))) + { + // We're hovering over the upper half of the header + drop.relation = Before; + } + else if(pt_in_rect(point, Gdk::Rectangle(0, y_mid, + full_width, half_height))) + { + // We're hovering over the lower half of the header + if(model_track->can_host_children()) + { + if(model_track->get_child_tracks().empty()) + { + // Is our track being dragged after this header? + if(dragPoint.get_x() < x_mid) + drop.relation = After; + else + drop.relation = FirstChild; + } + else + drop.relation = LastChild; + } + else + { + // When this track cannot be a parent, the dragging track is + // simply dropped after + drop.relation = After; + } + } + + return drop; +} + +void +TimelineLayoutHelper::apply_drop_to_layout_tree( + const TimelineLayoutHelper::DropPoint &drop) +{ + switch(drop.relation) + { + case None: + break; + + case Before: + draggingTrackIter = layoutTree.move_before( + drop.target, draggingTrackIter); + break; + + case After: + draggingTrackIter = layoutTree.move_after( + drop.target, draggingTrackIter); + break; + + case FirstChild: + if(draggingTrackIter.node->parent != drop.target.node) + { + draggingTrackIter = layoutTree.move_ontop( + layoutTree.prepend_child(drop.target), draggingTrackIter); + } + break; + + case LastChild: + if(draggingTrackIter.node->parent != drop.target.node) + { + draggingTrackIter = layoutTree.move_ontop( + layoutTree.append_child(drop.target), draggingTrackIter); + } + break; + + default: + ASSERT(0); // Unexpected value of relation + break; + } +} + +void +TimelineLayoutHelper::apply_drop_to_model_tree( + const TimelineLayoutHelper::DropPoint &drop) +{ + if(drop.relation == None) + return; + + // Freeze the timeline widget - it must be done manually later + timelineWidget.freeze_update_tracks(); + + // Get the tracks + shared_ptr &dragging_track = *draggingTrackIter; + REQUIRE(dragging_track); + REQUIRE(dragging_track != timelineWidget.sequence); + + shared_ptr &target_track = *drop.target; + REQUIRE(target_track); + REQUIRE(target_track != timelineWidget.sequence); + + // Detach the track from the old parent + shared_ptr old_parent = + dynamic_pointer_cast( + model::Track::find_parent( + timelineWidget.sequence, dragging_track)); + REQUIRE(old_parent); // The track must have a parent + old_parent->get_child_track_list().remove(dragging_track); + + if(drop.relation == Before || drop.relation == After) + { + // Find the new parent track + shared_ptr new_parent = + dynamic_pointer_cast( + model::Track::find_parent( + timelineWidget.sequence, target_track)); + REQUIRE(new_parent); // The track must have a parent + + // Find the destination point + observable_list< shared_ptr > &dest = + new_parent->get_child_track_list(); + list< shared_ptr >::iterator iter; + for(iter = dest.begin(); iter != dest.end(); iter++) + { + if(*iter == target_track) + break; + } + REQUIRE(iter != dest.end()); // The target must be + // in the destination + + // We have to jump on 1 if we want to insert after + if(drop.relation == After) + iter++; + + // Insert at this point + dest.insert(iter, dragging_track); + } + else if(drop.relation == FirstChild || drop.relation == LastChild) + { + shared_ptr new_parent = + dynamic_pointer_cast( + target_track); + REQUIRE(new_parent); // The track must have a parent + + if(drop.relation == FirstChild) + new_parent->get_child_track_list().push_front(dragging_track); + else if(drop.relation == LastChild) + new_parent->get_child_track_list().push_back(dragging_track); + } + else ASSERT(0); // Unexpected value of relation + + // Freeze the timeline widget - we will do it manually + timelineWidget.freeze_update_tracks(); +} + } // namespace timeline } // namespace widgets } // namespace gui diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 18463af49..22da655d9 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -127,16 +127,40 @@ public: **/ boost::shared_ptr track_from_y(int y); + /** + * Begins to drag the track under mouse_point, if there is one. + * @param mouse_point The mouse point to begin dragging from, measured + * in pixels from the top left of the header container widget. + **/ boost::shared_ptr begin_dragging_track(const Gdk::Point &mouse_point); + /** + * Drops the dragging track. + * @param apply true if the model tree should be modified. + **/ void end_dragging_track(bool apply); - + + /** + * Returns true if a track is being dragged. + **/ bool is_dragging_track() const; + /** + * Gets the iterator of the layout tree node that is being dragged. + **/ TrackTree::pre_order_iterator get_dragging_track_iter() const; - void drag_to_point(const Gdk::Point &point); + /** + * Drags the dragging branch to a new mouse point. + * @param mouse_point The mouse point to drag the dragging track to. + * This point is in pixels relative to the top left of the header + * container. + * @remarks drag_to_point may only be called after + * begin_dragging_track and before end_dragging_point have been + * called. + **/ + void drag_to_point(const Gdk::Point &mouse_point); /** * Returns the total height in pixels of the layout tree. @@ -146,6 +170,9 @@ public: **/ int get_total_height() const; + /** + * Returns true if the layout is currently animating. + **/ bool is_animating() const; /** @@ -157,22 +184,65 @@ public: **/ TrackTree::pre_order_iterator iterator_from_track( boost::shared_ptr model_track); - + + /** + * A function that recursively calculates the visible height of a + * branch taking into account branches that are expanded or collapsed. + * @param parent_iterator The parent of the branch to measure. This + * node and all the child nodes will be included in the measurement. + * @return Returns the height of the branch in pixels. + **/ int measure_branch_height(TrackTree::iterator_base parent_iterator); protected: + + /** + * An enum to specify the relationship between a tree node, and + * another node which is going to be inserted adjacent. + **/ enum TreeRelation { + /** + * No relation + **/ None, + + /** + * The node will be inserted immediately before this one. + **/ Before, + + /** + * The node will be inserted immediately after this one. + **/ After, + + /** + * The node will be inserted as the first child of this one. + **/ FirstChild, + + /** + * The node will be inserted as the last child of this one. + **/ LastChild }; - struct Drop + /** + * A structure used to specify where a track will be dropped when + * dragging ends. + **/ + struct DropPoint { + /** + * Specifies the target node onto which the dragging track will be + * dropped. + **/ TrackTree::pre_order_iterator target; + + /** + * The where to drop the dragging track in relation to target. + **/ TreeRelation relation; }; @@ -237,14 +307,34 @@ protected: * The animation timer tick callback. **/ bool on_animation_tick(); - - TimelineLayoutHelper::Drop + + /** + * Attempts to find a drop point on the target node at point. + * @param[in] target The iterator of the target node on which to make + * the attempt. + * @param[in] point The point on which do to the test. + * @remarks This function hit-tests a header looking to see if the + * point is hovering over it, and if it is, it works out what part of + * the header, and therefore what drop location the user us gesturally + * pointing to. + **/ + TimelineLayoutHelper::DropPoint attempt_drop(TrackTree::pre_order_iterator target, const Gdk::Point &point); - void apply_drop_to_layout_tree(const Drop &drop); + /** + * Drops the dragging track to a new location in the layout tree as + * specified by drop. + * @param[in] drop The point in the tree to drop onto. + **/ + void apply_drop_to_layout_tree(const DropPoint &drop); - void apply_drop_to_model_tree(const Drop &drop); + /** + * Drops the dragging track to a new location in the model tree as + * specified by drop. + * @param[in] drop The point in the tree to drop onto. + **/ + void apply_drop_to_model_tree(const DropPoint &drop); protected: /** @@ -274,15 +364,39 @@ protected: **/ int totalHeight; + /** + * The iterator of the layoutTree node that is presently being + * dragged. + * @remarks draggingTrackIter.node is set to NULL when no drag is + * taking place. + **/ TrackTree::pre_order_iterator draggingTrackIter; - + + /** + * The offset of the mouse relative to the top-left corner of the + * dragging track. + **/ Gdk::Point dragStartOffset; + /** + * The coordinates of the dragging mouse in pixels, measured from the + * top left of the whole layout. + * @remarks This value is changed by begin_dragging_track and + * drag_to_point + **/ Gdk::Point dragPoint; + /** + * The total height of the dragging branch in pixels. + * @remarks This value is updated by begin_dragging_track + **/ int dragBranchHeight; - Drop draggingDrop; + /** + * The tree point the the user is currently hovering on. + * @remarks This value is updated by drag_to_point. + **/ + DropPoint dropPoint; /** * The connection to the animation timer. From c88aec9c03f395a036aa44621df5b23b621782f8 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 11:45:47 +0000 Subject: [PATCH 053/216] Added some documentation to model::Track --- src/gui/model/track.hpp | 55 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index 37bbe955e..039d61969 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -31,40 +31,91 @@ namespace gui { namespace model { - + +/** + * The model representation of a track. This is the base class for all + * types of track that are implemented. + **/ class Track { protected: + /** + * Constructor + **/ Track(); public: + + /** + * Gets the list of child tracks. + **/ virtual std::list< boost::shared_ptr > get_child_tracks() const; - + + /** + * Gets the name of this track. + **/ const std::string get_name() const; + /** + * Sets the name of this track. + * @param[in] name The new name to set this track to. + **/ void set_name(const std::string &name); + /** + * Returns true if this track can own any child tracks. + **/ virtual bool can_host_children() const; + /** + * Tries to remove a given child track from the list. + * @param The model track to try and remove. + * @return Returns true if the track was successfully removed. + **/ virtual bool remove_child_track(const boost::shared_ptr track); + /** + * A debugging helper function that prints this track, and all it's + * child tracks in a human-readable form. + * @return Returns the human readable string. + **/ std::string print_branch(); + /** + * A pure-virtual function which is the base of functions that print + * this track in human readable form. + * @return Returns the human readable string. + **/ virtual std::string print_track() = 0; +protected: + static boost::shared_ptr find_parent(boost::shared_ptr root, boost::shared_ptr child); protected: + /** + * The internal implementation of print_branch. + * @param indentation The level of recursion into the tree. This value + * is used to specify the width of indentation to print with. + * @return Returns the human readable string. + **/ std::string print_branch_recursive(const unsigned int indentation); private: //----- Data -----// + /** + * The name of this track. + **/ std::string name; protected: + /** + * An object used internally as a return value for when there's no + * children. + **/ static const std::list< boost::shared_ptr > NoChildren; }; From 53297cccd6dea76e25f010e31c24d7b635bd86d0 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 12:02:09 +0000 Subject: [PATCH 054/216] Tidied and documented Track::find_parent --- src/gui/model/track.cpp | 20 +++++++++++++------ src/gui/model/track.hpp | 16 ++++++++++++--- .../timeline/timeline-layout-helper.cpp | 8 +++----- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index c8d1c3356..aa099848f 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -21,6 +21,7 @@ * *****************************************************/ #include "track.hpp" +#include "parent-track.hpp" #include using namespace boost; @@ -72,8 +73,8 @@ Track::print_branch() return print_branch_recursive(0); } -shared_ptr -Track::find_parent(shared_ptr root, shared_ptr child) +shared_ptr +Track::find_parent(shared_ptr root, shared_ptr child) { REQUIRE(root != NULL); REQUIRE(child != NULL); @@ -83,12 +84,19 @@ Track::find_parent(shared_ptr root, shared_ptr child) if(track == child) return root; - shared_ptr result = find_parent(track, child); - if(result) - return result; + shared_ptr parent_track = + dynamic_pointer_cast( + track); + if(parent_track) + { + shared_ptr result = find_parent( + parent_track, child); + if(result) + return result; + } } - return shared_ptr(); + return shared_ptr(); } string diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index 039d61969..9e116e743 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -31,6 +31,8 @@ namespace gui { namespace model { + +class ParentTrack; /** * The model representation of a track. This is the base class for all @@ -89,10 +91,18 @@ public: **/ virtual std::string print_track() = 0; -protected: +public: - static boost::shared_ptr - find_parent(boost::shared_ptr root, + /** + * A utility function that attempts to find the parent of a track by + * searching through the tree from a root downward. + * @param root The root track to begin searching down from. + * @param child The child track to find the parent of. + * @return Returns the parent track if one was found, or an empty + * shared_ptr if none was found. + **/ + static boost::shared_ptr + find_parent(boost::shared_ptr root, boost::shared_ptr child); protected: diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 105e6fcd1..f05b63155 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -563,9 +563,8 @@ TimelineLayoutHelper::apply_drop_to_model_tree( // Detach the track from the old parent shared_ptr old_parent = - dynamic_pointer_cast( model::Track::find_parent( - timelineWidget.sequence, dragging_track)); + timelineWidget.sequence, dragging_track); REQUIRE(old_parent); // The track must have a parent old_parent->get_child_track_list().remove(dragging_track); @@ -573,9 +572,8 @@ TimelineLayoutHelper::apply_drop_to_model_tree( { // Find the new parent track shared_ptr new_parent = - dynamic_pointer_cast( - model::Track::find_parent( - timelineWidget.sequence, target_track)); + model::Track::find_parent( + timelineWidget.sequence, target_track); REQUIRE(new_parent); // The track must have a parent // Find the destination point From 41f394a57b1544441c4831b3361990a7e1f82aec Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 12:18:12 +0000 Subject: [PATCH 055/216] Excised ObservableList::to_list --- src/gui/model/parent-track.cpp | 4 ++-- src/gui/model/parent-track.hpp | 2 +- src/gui/model/track.cpp | 2 +- src/gui/model/track.hpp | 2 +- src/lib/observable-list.hpp | 6 ++---- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/gui/model/parent-track.cpp b/src/gui/model/parent-track.cpp index 6aec58e8a..4e8a3ca11 100644 --- a/src/gui/model/parent-track.cpp +++ b/src/gui/model/parent-track.cpp @@ -30,10 +30,10 @@ ParentTrack::ParentTrack() { } -std::list< boost::shared_ptr > +const std::list< boost::shared_ptr >& ParentTrack::get_child_tracks() const { - return tracks.to_list(); + return tracks.get_list(); } lumiera::observable_list< boost::shared_ptr >& diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index ecc084e4b..b59bd2ce8 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -40,7 +40,7 @@ protected: ParentTrack(); public: - std::list< boost::shared_ptr > + const std::list< boost::shared_ptr >& get_child_tracks() const; lumiera::observable_list< boost::shared_ptr >& diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index aa099848f..f445e0f0c 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -37,7 +37,7 @@ Track::Track() } -list< shared_ptr > +const std::list< boost::shared_ptr >& Track::get_child_tracks() const { return Track::NoChildren; diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index 9e116e743..a886192d9 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -51,7 +51,7 @@ public: /** * Gets the list of child tracks. **/ - virtual std::list< boost::shared_ptr > + virtual const std::list< boost::shared_ptr >& get_child_tracks() const; /** diff --git a/src/lib/observable-list.hpp b/src/lib/observable-list.hpp index c672d2a1b..dd06d0979 100644 --- a/src/lib/observable-list.hpp +++ b/src/lib/observable-list.hpp @@ -267,11 +267,9 @@ public: /* ===== Conversions ===== */ /** - * Returns a copy of this observable_list converted to an STL list - * object. - * @return Returns a copy of the STL list. + * Returns a read only reference to the list. **/ - std::list to_list() const + const std::list& get_list() const { return list; } From e7481afc3daefbd3c4901d22e59991859fcd3813 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 12:23:18 +0000 Subject: [PATCH 056/216] Renamed remove_child_track -> remove_descendant_track --- src/gui/model/parent-track.cpp | 4 ++-- src/gui/model/parent-track.hpp | 10 ++++++++-- src/gui/model/track.cpp | 2 +- src/gui/model/track.hpp | 6 ++++-- src/gui/widgets/timeline/timeline-track.cpp | 2 +- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/gui/model/parent-track.cpp b/src/gui/model/parent-track.cpp index 4e8a3ca11..4b1a678cf 100644 --- a/src/gui/model/parent-track.cpp +++ b/src/gui/model/parent-track.cpp @@ -49,7 +49,7 @@ ParentTrack::can_host_children() const } bool -ParentTrack::remove_child_track(const boost::shared_ptr track) +ParentTrack::remove_descendant_track(const boost::shared_ptr track) { REQUIRE(track); @@ -63,7 +63,7 @@ ParentTrack::remove_child_track(const boost::shared_ptr track) return true; } - if(child_track->remove_child_track(track)) + if(child_track->remove_descendant_track(track)) return true; } diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index b59bd2ce8..9f3478f9d 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -47,8 +47,14 @@ public: get_child_track_list(); bool can_host_children() const; - - bool remove_child_track(const boost::shared_ptr track); + + /** + * Tries to remove a given track from amongst the descendants of this + * track. + * @param The model track to try and remove. + * @return Returns true if the track was successfully removed. + **/ + bool remove_descendant_track(const boost::shared_ptr track); protected: lumiera::observable_list< boost::shared_ptr > tracks; diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index f445e0f0c..2cb517447 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -62,7 +62,7 @@ Track::can_host_children() const } bool -Track::remove_child_track(const shared_ptr /*track*/) +Track::remove_descendant_track(const shared_ptr /*track*/) { return false; } diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index a886192d9..9b5ee03f3 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -71,11 +71,13 @@ public: virtual bool can_host_children() const; /** - * Tries to remove a given child track from the list. + * Tries to remove a given track from amongst the descendants of this + * track. * @param The model track to try and remove. * @return Returns true if the track was successfully removed. **/ - virtual bool remove_child_track(const boost::shared_ptr track); + virtual bool remove_descendant_track( + const boost::shared_ptr track); /** * A debugging helper function that prints this track, and all it's diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp index 1e5e25c71..717a106dd 100644 --- a/src/gui/widgets/timeline/timeline-track.cpp +++ b/src/gui/widgets/timeline/timeline-track.cpp @@ -251,7 +251,7 @@ Track::on_remove_track() REQUIRE(model_track); REQUIRE(timelineWidget.sequence); - timelineWidget.sequence->remove_child_track(model_track); + timelineWidget.sequence->remove_descendant_track(model_track); } } // namespace timeline From c0d008167704134f96672b8537a4031564e2f46c Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 12:25:02 +0000 Subject: [PATCH 057/216] Documented model::ParentTrack --- src/gui/model/parent-track.hpp | 26 ++++++++++++++++++++++++-- src/gui/model/track.hpp | 4 ++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index 9f3478f9d..d3ff1878d 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -34,18 +34,37 @@ namespace gui { namespace model { +/** + * ParentTrack is the abstract base class of all tracks that can parent + * children. + **/ class ParentTrack : public Track { protected: + /** + * Constructor + **/ ParentTrack(); -public: +public: + + /** + * Gets a read-only reference to the the list of child tracks. + **/ const std::list< boost::shared_ptr >& get_child_tracks() const; + /** + * Gets read-write access to the list of child tracks. + **/ lumiera::observable_list< boost::shared_ptr >& get_child_track_list(); - + + /** + * Returns true if this track can own any child tracks. + * @return Returns true because all classed derrived from ParentTrack + * can. + **/ bool can_host_children() const; /** @@ -57,6 +76,9 @@ public: bool remove_descendant_track(const boost::shared_ptr track); protected: + /** + * The internal list of child tracks of this paremt. + **/ lumiera::observable_list< boost::shared_ptr > tracks; }; diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index 9b5ee03f3..3f5c2cdf1 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -35,8 +35,8 @@ namespace model { class ParentTrack; /** - * The model representation of a track. This is the base class for all - * types of track that are implemented. + * The model representation of a track. This is the abstract base class + * for all types of track that are implemented. **/ class Track { From 2f12e5b239d9a659665cb0b1dc268063278e12c2 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 12:26:50 +0000 Subject: [PATCH 058/216] Reorganized test code --- src/gui/model/sequence.cpp | 4 ++++ src/gui/model/sequence.hpp | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/model/sequence.cpp b/src/gui/model/sequence.cpp index 2503b88cc..e6f90207a 100644 --- a/src/gui/model/sequence.cpp +++ b/src/gui/model/sequence.cpp @@ -22,6 +22,10 @@ #include "sequence.hpp" +// TEST CODE +#include "group-track.hpp" +#include "clip-track.hpp" + using namespace boost; namespace gui { diff --git a/src/gui/model/sequence.hpp b/src/gui/model/sequence.hpp index 277fbf426..fb9f406ba 100644 --- a/src/gui/model/sequence.hpp +++ b/src/gui/model/sequence.hpp @@ -29,10 +29,6 @@ #include "parent-track.hpp" -// TEST CODE -#include "group-track.hpp" -#include "clip-track.hpp" - namespace gui { namespace model { From f0c7d85a1f74789d8e0c7946237c4e85f83cb1c1 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 12:30:07 +0000 Subject: [PATCH 059/216] Documented model::Sequence --- src/gui/model/sequence.hpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/gui/model/sequence.hpp b/src/gui/model/sequence.hpp index fb9f406ba..717368a9c 100644 --- a/src/gui/model/sequence.hpp +++ b/src/gui/model/sequence.hpp @@ -34,15 +34,24 @@ namespace model { class Track; +/** + * A class representation of a sequence. + * @remarks Sequence objects are also the roots of track trees. + **/ class Sequence : public ParentTrack { public: + /** + * Constructor + **/ Sequence(); + /** + * Produces a human readable debug string representation of this + * track. + * @return Returns the human readable string. + **/ std::string print_track(); - -private: - }; } // namespace model From e2992c62ef15b02b10b7d6bcc8ed12e3d7399704 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 12:31:03 +0000 Subject: [PATCH 060/216] Documented model::GroupTrack --- src/gui/model/group-track.hpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/gui/model/group-track.hpp b/src/gui/model/group-track.hpp index 06da74060..ae3f48b63 100644 --- a/src/gui/model/group-track.hpp +++ b/src/gui/model/group-track.hpp @@ -30,12 +30,23 @@ namespace gui { namespace model { - + +/** + * A class representation of a grouping of tracks. + **/ class GroupTrack : public ParentTrack { public: + /** + * Constructor + **/ GroupTrack(); + /** + * Produces a human readable debug string representation of this + * track. + * @return Returns the human readable string. + **/ std::string print_track(); }; From ed1f4abfeac9d18e9994686df4d780cd61bcabfe Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 12:50:49 +0000 Subject: [PATCH 061/216] Refactored find_branch_parent --- src/gui/gtk-lumiera.hpp | 1 + src/gui/model/parent-track.cpp | 21 +++++++++++++++ src/gui/model/parent-track.hpp | 7 ++++- src/gui/model/track.cpp | 25 +++--------------- src/gui/model/track.hpp | 26 ++++++++----------- .../timeline/timeline-layout-helper.cpp | 8 +++--- 6 files changed, 46 insertions(+), 42 deletions(-) diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index 53d146b95..956223de9 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include "lib/util.hpp" extern "C" { diff --git a/src/gui/model/parent-track.cpp b/src/gui/model/parent-track.cpp index 4b1a678cf..d46f007f4 100644 --- a/src/gui/model/parent-track.cpp +++ b/src/gui/model/parent-track.cpp @@ -23,6 +23,8 @@ #include "parent-track.hpp" #include +using namespace boost; + namespace gui { namespace model { @@ -70,5 +72,24 @@ ParentTrack::remove_descendant_track(const boost::shared_ptr track) return false; } +boost::shared_ptr +ParentTrack::find_descendant_track_parent( + boost::shared_ptr child) +{ + REQUIRE(child != NULL); + BOOST_FOREACH(shared_ptr track, tracks) + { + if(track == child) + return shared_from_this(); + + shared_ptr result = + track->find_descendant_track_parent(child); + if(result) + return result; + } + + return shared_ptr(); +} + } // namespace model } // namespace gui diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index d3ff1878d..5ef2c0265 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -38,7 +38,9 @@ namespace model { * ParentTrack is the abstract base class of all tracks that can parent * children. **/ -class ParentTrack : public Track +class ParentTrack : + public Track, + public boost::enable_shared_from_this { protected: /** @@ -74,6 +76,9 @@ public: * @return Returns true if the track was successfully removed. **/ bool remove_descendant_track(const boost::shared_ptr track); + + boost::shared_ptr + find_descendant_track_parent(boost::shared_ptr child); protected: /** diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index 2cb517447..f2c52b19d 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -73,29 +73,10 @@ Track::print_branch() return print_branch_recursive(0); } -shared_ptr -Track::find_parent(shared_ptr root, shared_ptr child) +boost::shared_ptr +Track::find_descendant_track_parent( + boost::shared_ptr /*child*/) { - REQUIRE(root != NULL); - REQUIRE(child != NULL); - const list< shared_ptr > children = root->get_child_tracks(); - BOOST_FOREACH(shared_ptr track, children) - { - if(track == child) - return root; - - shared_ptr parent_track = - dynamic_pointer_cast( - track); - if(parent_track) - { - shared_ptr result = find_parent( - parent_track, child); - if(result) - return result; - } - } - return shared_ptr(); } diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index 3f5c2cdf1..7bc0e7c45 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -78,6 +78,16 @@ public: **/ virtual bool remove_descendant_track( const boost::shared_ptr track); + + /** + * A utility function that attempts to find the parent of a track by + * searching through the tree from this track downward. + * @param child The child track to find the parent of. + * @return Returns the parent track if one was found, or an empty + * shared_ptr if none was found. + **/ + virtual boost::shared_ptr + find_descendant_track_parent(boost::shared_ptr child); /** * A debugging helper function that prints this track, and all it's @@ -92,21 +102,7 @@ public: * @return Returns the human readable string. **/ virtual std::string print_track() = 0; - -public: - - /** - * A utility function that attempts to find the parent of a track by - * searching through the tree from a root downward. - * @param root The root track to begin searching down from. - * @param child The child track to find the parent of. - * @return Returns the parent track if one was found, or an empty - * shared_ptr if none was found. - **/ - static boost::shared_ptr - find_parent(boost::shared_ptr root, - boost::shared_ptr child); - + protected: /** * The internal implementation of print_branch. diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index f05b63155..a67fd94bd 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -563,8 +563,8 @@ TimelineLayoutHelper::apply_drop_to_model_tree( // Detach the track from the old parent shared_ptr old_parent = - model::Track::find_parent( - timelineWidget.sequence, dragging_track); + timelineWidget.sequence->find_descendant_track_parent( + dragging_track); REQUIRE(old_parent); // The track must have a parent old_parent->get_child_track_list().remove(dragging_track); @@ -572,8 +572,8 @@ TimelineLayoutHelper::apply_drop_to_model_tree( { // Find the new parent track shared_ptr new_parent = - model::Track::find_parent( - timelineWidget.sequence, target_track); + timelineWidget.sequence->find_descendant_track_parent( + target_track); REQUIRE(new_parent); // The track must have a parent // Find the destination point From 0689e0256c92b3491d4f0ca1dbf409d55ac7be11 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 12:59:56 +0000 Subject: [PATCH 062/216] Refactored ParentTrack::remove_descendant_track --- src/gui/model/parent-track.cpp | 19 +++++++------------ src/gui/model/track.cpp | 6 ------ src/gui/model/track.hpp | 11 +---------- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/src/gui/model/parent-track.cpp b/src/gui/model/parent-track.cpp index d46f007f4..f7122fe46 100644 --- a/src/gui/model/parent-track.cpp +++ b/src/gui/model/parent-track.cpp @@ -51,22 +51,17 @@ ParentTrack::can_host_children() const } bool -ParentTrack::remove_descendant_track(const boost::shared_ptr track) +ParentTrack::remove_descendant_track( + const boost::shared_ptr track) { REQUIRE(track); - BOOST_FOREACH(const boost::shared_ptr child_track, tracks) + boost::shared_ptr parent = + find_descendant_track_parent(track); + if(parent) { - REQUIRE(child_track); - - if(track.get() == child_track.get()) - { - tracks.remove(track); - return true; - } - - if(child_track->remove_descendant_track(track)) - return true; + parent->tracks.remove(track); + return true; } return false; diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index f2c52b19d..7e9a3992b 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -61,12 +61,6 @@ Track::can_host_children() const return false; } -bool -Track::remove_descendant_track(const shared_ptr /*track*/) -{ - return false; -} - string Track::print_branch() { diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index 7bc0e7c45..ac137d451 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -69,16 +69,7 @@ public: * Returns true if this track can own any child tracks. **/ virtual bool can_host_children() const; - - /** - * Tries to remove a given track from amongst the descendants of this - * track. - * @param The model track to try and remove. - * @return Returns true if the track was successfully removed. - **/ - virtual bool remove_descendant_track( - const boost::shared_ptr track); - + /** * A utility function that attempts to find the parent of a track by * searching through the tree from this track downward. From b48c5e0cc0e50d62d9b3842bac8fa533f1348c16 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 13:00:56 +0000 Subject: [PATCH 063/216] Added some ParentTrack documentation --- src/gui/model/parent-track.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index 5ef2c0265..bc26be80f 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -77,6 +77,13 @@ public: **/ bool remove_descendant_track(const boost::shared_ptr track); + /** + * A utility function that attempts to find the parent of a track by + * searching through the tree from this track downward. + * @param child The child track to find the parent of. + * @return Returns the parent track if one was found, or an empty + * shared_ptr if none was found. + **/ boost::shared_ptr find_descendant_track_parent(boost::shared_ptr child); From 523eecfc24e8471fe4d14f39cae03e9584df5a2e Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 14:12:13 +0000 Subject: [PATCH 064/216] Fixed drag by expander bug --- src/gui/widgets/timeline/timeline-header-widget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-header-widget.cpp b/src/gui/widgets/timeline/timeline-header-widget.cpp index d11f96ce1..b71c6c8ad 100644 --- a/src/gui/widgets/timeline/timeline-header-widget.cpp +++ b/src/gui/widgets/timeline/timeline-header-widget.cpp @@ -208,7 +208,7 @@ TimelineHeaderWidget::on_button_release_event (GdkEventButton* event) TimelineLayoutHelper &layout = track.timelineWidget.layoutHelper; // Did the user release the button on an expander? - if(clickedExpander) + if(clickedExpander && !layout.is_dragging_track()) { // Yes? The toggle the expanding track.expand_collapse(track.get_expanded() ? From 7a066cdd724e31b86398e37c3dcd2562c020e1d2 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 14:16:33 +0000 Subject: [PATCH 065/216] Fixed bug in measure branch height --- .../timeline/timeline-layout-helper.cpp | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index a67fd94bd..696824b42 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -274,18 +274,21 @@ TimelineLayoutHelper::measure_branch_height( int branch_height = parent_track->get_height() + TimelineWidget::TrackPadding; - TrackTree::sibling_iterator iterator; - for(iterator = layoutTree.begin(parent_iterator); - iterator != layoutTree.end(parent_iterator); - iterator++) - { - shared_ptr child_track = - lookup_timeline_track(*iterator); - - if(child_track->get_expanded()) - branch_height += measure_branch_height(iterator); + // Add the heights of child tracks if this parent is expanded + if(parent_track->get_expanded()) + { + TrackTree::sibling_iterator iterator; + for(iterator = layoutTree.begin(parent_iterator); + iterator != layoutTree.end(parent_iterator); + iterator++) + { + shared_ptr child_track = + lookup_timeline_track(*iterator); + + branch_height += measure_branch_height(iterator); + } } - + return branch_height; } From 19513247261dfdfe2b525a4554f4af36d6438a4e Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 14:17:20 +0000 Subject: [PATCH 066/216] Corrected a typo --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 696824b42..a06734d37 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -386,7 +386,7 @@ TimelineLayoutHelper::layout_headers_recursive( // Do collapse animation as necessary if(is_track_animating) { - // Calculate the height of te area which will be + // Calculate the height of the area which will be // shown as expanded const float a = timeline_track->get_expand_animation_state(); child_branch_height *= a * a; From aa5cf0ea3ab5755251d4cf57ca811d93cea09ebc Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 14:33:49 +0000 Subject: [PATCH 067/216] Made a track expand when the dragging track is going to be dragged inside --- .../widgets/timeline/timeline-header-container.cpp | 12 +++++++++++- src/gui/widgets/timeline/timeline-layout-helper.cpp | 11 +++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index c4e189081..0ac0df624 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -342,6 +342,8 @@ TimelineHeaderContainer::layout_headers() if(!gdkWindow) return; + bool headers_shown = false; + TimelineLayoutHelper &layout_helper = timelineWidget.layoutHelper; const TimelineLayoutHelper::TrackTree &layout_tree = @@ -368,12 +370,20 @@ TimelineHeaderContainer::layout_headers() // Apply the allocation to the header widget.size_allocate (*header_rect); if(!widget.is_visible()) - widget.show(); + { + widget.show(); + headers_shown = true; + } } else // No header rect, so the track must be hidden if(widget.is_visible()) widget.hide(); } + + // If headers have been shown while we're dragging, the dragging + // branch headers have to be brought back to the top again + if(headers_shown && layout_helper.is_dragging_track()) + raise_recursive(layout_helper.get_dragging_track_iter()); // Repaint the background of our parenting queue_draw(); diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index a06734d37..d5ab696a5 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -228,8 +228,19 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &mouse_point) // Did we get a drop point? if(drop.relation != None) { + REQUIRE(*drop.target); + shared_ptr target_timeline_track = + lookup_timeline_track(*drop.target); + apply_drop_to_layout_tree(drop); dropPoint = drop; + + if((drop.relation == FirstChild || drop.relation == LastChild)&& + !target_timeline_track->get_expanded()) + { + target_timeline_track->expand_collapse(Track::Expand); + + } } update_layout(); From f327dcab7a0e2a47d71121dc74222bbd5e7f602f Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 14:34:26 +0000 Subject: [PATCH 068/216] Tidyups --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index d5ab696a5..c8c6b4675 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -235,7 +235,7 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &mouse_point) apply_drop_to_layout_tree(drop); dropPoint = drop; - if((drop.relation == FirstChild || drop.relation == LastChild)&& + if((drop.relation == FirstChild || drop.relation == LastChild) && !target_timeline_track->get_expanded()) { target_timeline_track->expand_collapse(Track::Expand); From ec78f73ca93d9acc275035e5589abd4a6dd63b27 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 14:41:32 +0000 Subject: [PATCH 069/216] Timeline scroll is updated as the layout changes --- src/gui/widgets/timeline-widget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 3aec39992..58a9f8e74 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -449,6 +449,7 @@ TimelineWidget::on_layout_changed() headerContainer->on_layout_changed(); body->queue_draw(); + update_scroll(); } void From 73f738050675736fed61417314c486f68340c3d0 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 15:15:38 +0000 Subject: [PATCH 070/216] Removed some debug messages --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index c8c6b4675..822747cce 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -186,6 +186,7 @@ void TimelineLayoutHelper::drag_to_point(const Gdk::Point &mouse_point) { DropPoint drop; + drop.relation = None; // begin_dragging_track must have been called before REQUIRE(is_dragging_track()); @@ -479,7 +480,7 @@ TimelineLayoutHelper::attempt_drop(TrackTree::pre_order_iterator target, // Initialize the drop // By specifying relation = None, the default return value will signal - // no drop-point was foind at point + // no drop-point was found at point DropPoint drop = {target, None}; if(pt_in_rect(point, Gdk::Rectangle(0, y, full_width, half_height))) From 64a794100253d87c60f994d0eb666d9239f968a4 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 15:28:54 +0000 Subject: [PATCH 071/216] Fixed a bug related to the scroll slide timer not being correctly terminated --- src/gui/widgets/timeline/timeline-header-container.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 0ac0df624..a5880d6e0 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -421,10 +421,13 @@ void TimelineHeaderContainer::end_drag(bool apply) { TimelineLayoutHelper &layout = timelineWidget.layoutHelper; - + // Has the user been dragging? if(layout.is_dragging_track()) layout.end_dragging_track(apply); + + // End the scroll slide + end_scroll_slide(); // Reset the arrow as a cursor REQUIRE(gdkWindow); From 5740a3687e39a05017c65fad61f1bc783849ebbf Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 15:39:30 +0000 Subject: [PATCH 072/216] Removed spurious curlies --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 822747cce..b0dc1e80f 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -238,10 +238,7 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &mouse_point) if((drop.relation == FirstChild || drop.relation == LastChild) && !target_timeline_track->get_expanded()) - { target_timeline_track->expand_collapse(Track::Expand); - - } } update_layout(); From 4bdee1623001d3e6577b2bd486f8528550b4f91e Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 15:42:45 +0000 Subject: [PATCH 073/216] Fixed a more flaw in drop logic --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index b0dc1e80f..5e8d6dd45 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -500,7 +500,7 @@ TimelineLayoutHelper::attempt_drop(TrackTree::pre_order_iterator target, drop.relation = FirstChild; } else - drop.relation = LastChild; + drop.relation = FirstChild; } else { From 28c758b032d97be0848447db8c6509d5ff16dbd1 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 15:54:19 +0000 Subject: [PATCH 074/216] Tidied and documented TimelineHeaderWidget --- .../timeline/timeline-header-widget.hpp | 57 ++++++++++++++++++- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-header-widget.hpp b/src/gui/widgets/timeline/timeline-header-widget.hpp index 93ae93b8d..62a33cb9d 100644 --- a/src/gui/widgets/timeline/timeline-header-widget.hpp +++ b/src/gui/widgets/timeline/timeline-header-widget.hpp @@ -35,16 +35,24 @@ namespace timeline { class Track; +/** + * TimelineHeaderWidget is the base implementation of all header widgets + * and acts as a containers for the header controls. + **/ class TimelineHeaderWidget : public Gtk::Container { public: + /** + * Constructor + * @param timeline_track The timeline track that owns this header + * widget + **/ TimelineHeaderWidget(timeline::Track &timeline_track); void set_child_widget(Widget& child); private: /* ===== Overrides ===== */ -private: /** * An event handler for the window realized signal. @@ -56,8 +64,18 @@ private: */ void on_unrealize(); - //Overrides: + /** + * An event handler that is called to offer an allocation to this + * widget. + * @param requisition The area offered for this widget. + */ void on_size_request(Gtk::Requisition* requisition); + + /** + * An event handler that is called to notify this widget to allocate + * a given area for itself. + * @param allocation The area to allocate for this widget. + */ void on_size_allocate(Gtk::Allocation& allocation); /** @@ -83,10 +101,26 @@ private: */ bool on_motion_notify_event (GdkEventMotion* event); - void forall_vfunc(gboolean include_internals, GtkCallback callback, gpointer callback_data); + /** + * Applies a given function to all the widgets in the container. + **/ + void forall_vfunc(gboolean include_internals, GtkCallback callback, + gpointer callback_data); + /** + * A notification of when a widget is added to this container. + **/ void on_add(Gtk::Widget* child); + + /** + * A notification of when a widget is removed to this container. + **/ void on_remove(Gtk::Widget* child); + + /** + * An implementation of the a container function that specifies the + * types of child widget that this widget will accept. + **/ GtkType child_type_vfunc() const; /** @@ -101,12 +135,29 @@ private: private: + /** + * A reference to the timeline track that owns this widget. + **/ timeline::Track &track; + /** + * The widget placed inside this container. + * @remarks This value is set to NULL if the container is empty + **/ Gtk::Widget* widget; + /** + * This value is true if the mouse hovering over the expander. + * @remarks This value is updated by on_motion_notify_event + **/ bool hoveringExpander; + /** + * This value is true if the mouse button is depressed over the + * expander. + * @remarks This value is updated by on_button_press_event and + * on_button_release_event + **/ bool clickedExpander; /** From ce37fa649de8add7343d4596bacea1d458e7ed25 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 17:04:31 +0000 Subject: [PATCH 075/216] Added a comment --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 5e8d6dd45..06bbbbc0f 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -236,6 +236,8 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &mouse_point) apply_drop_to_layout_tree(drop); dropPoint = drop; + // Expand the branch if the user is hovering to add the track + // as a child if((drop.relation == FirstChild || drop.relation == LastChild) && !target_timeline_track->get_expanded()) target_timeline_track->expand_collapse(Track::Expand); From 262ee3655bf59b2a05aed1ac03180be3cee76f51 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 17:19:10 +0000 Subject: [PATCH 076/216] Added is_descendant_of method to tree --- src/lib/tree.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/lib/tree.hpp b/src/lib/tree.hpp index d856e9430..f70cf30e7 100644 --- a/src/lib/tree.hpp +++ b/src/lib/tree.hpp @@ -139,6 +139,9 @@ class tree { void skip_children(); /// Number of children of the node pointed to by the iterator. unsigned int number_of_children() const; + /// Determines if the node pointed to by the iterator is a descendant of + /// another node pointed to by another iterator + bool is_descendant_of(iterator_base parent) const; sibling_iterator begin() const; sibling_iterator end() const; @@ -2000,6 +2003,17 @@ unsigned int tree::iterator_base::number_of_children() c } return ret; } + +template +bool tree::iterator_base::is_descendant_of(iterator_base parent) const + { + tree_node node = this->node; + while(node != NULL) { + if(node == parent->node) return true; + node = node->parent; + } + return false; + } From 0355c83f0edf8c42d15c7fe5a27d55f0c86a0c79 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 17:50:18 +0000 Subject: [PATCH 077/216] Added handling for when the user drags beyond the end of the tree --- .../timeline/timeline-layout-helper.cpp | 65 +++++++++++++++---- src/lib/tree.hpp | 4 +- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 06bbbbc0f..1f7cf8377 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -185,6 +185,7 @@ TimelineLayoutHelper::get_dragging_track_iter() const void TimelineLayoutHelper::drag_to_point(const Gdk::Point &mouse_point) { + DropPoint drop; drop.relation = None; @@ -207,22 +208,60 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &mouse_point) else test_point.set_y(test_point.get_y() + dragBranchHeight); - // Search the headers TrackTree::pre_order_iterator iterator; + TrackTree::pre_order_iterator begin = ++layoutTree.begin(); - for(iterator = ++layoutTree.begin(); - iterator != layoutTree.end(); - iterator++) - { - // Skip the dragging branch - if(iterator == draggingTrackIter) - iterator.skip_children(); - else + if(test_point.get_y() < 0) + { + // Find the first header that's not being dragged + for(iterator = begin; + iterator != layoutTree.end(); + iterator++) { - // Do hit test - drop = attempt_drop(iterator, test_point); - if(drop.relation != None) - break; + if(iterator == draggingTrackIter) + iterator.skip_children(); + else + { + drop.relation = Before; + drop.target = iterator; + break; + } + } + } + else if(test_point.get_y() > totalHeight) + { + // Find the last header that's not being dragged + for(iterator = --layoutTree.end(); + iterator != begin; + iterator--) + { + if(iterator.is_descendant_of(draggingTrackIter)) + iterator.skip_children(); + else + { + drop.relation = After; + drop.target = iterator; + break; + } + } + } + else + { + // Search the headers + for(iterator = ++layoutTree.begin(); + iterator != layoutTree.end(); + iterator++) + { + // Skip the dragging branch + if(iterator == draggingTrackIter) + iterator.skip_children(); + else + { + // Do hit test + drop = attempt_drop(iterator, test_point); + if(drop.relation != None) + break; + } } } diff --git a/src/lib/tree.hpp b/src/lib/tree.hpp index f70cf30e7..66774b8e1 100644 --- a/src/lib/tree.hpp +++ b/src/lib/tree.hpp @@ -2007,9 +2007,9 @@ unsigned int tree::iterator_base::number_of_children() c template bool tree::iterator_base::is_descendant_of(iterator_base parent) const { - tree_node node = this->node; + const tree_node *node = this->node; while(node != NULL) { - if(node == parent->node) return true; + if(node == parent.node) return true; node = node->parent; } return false; From 9d9f7c40e9ad25e84a2550d4280ee640b0413f78 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 18:18:41 +0000 Subject: [PATCH 078/216] Renamed Assets to Resources --- src/gui/Makefile.am | 4 ++-- .../{assets-panel.cpp => resources-panel.cpp} | 8 ++++---- .../{assets-panel.hpp => resources-panel.hpp} | 4 ++-- src/gui/workspace/actions.cpp | 7 ++++--- src/gui/workspace/workspace-window.cpp | 16 ++++++++-------- src/gui/workspace/workspace-window.hpp | 4 ++-- 6 files changed, 22 insertions(+), 21 deletions(-) rename src/gui/panels/{assets-panel.cpp => resources-panel.cpp} (83%) rename src/gui/panels/{assets-panel.hpp => resources-panel.hpp} (92%) diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 44a77c0c3..1cef51ae3 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -115,8 +115,8 @@ libgui_la_SOURCES = \ $(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)/panels/resources-panel.cpp \ + $(lumigui_srcdir)/panels/resources-panel.hpp \ $(lumigui_srcdir)/widgets/menu-button.cpp \ $(lumigui_srcdir)/widgets/menu-button.hpp \ $(lumigui_srcdir)/widgets/video-display-widget.cpp \ diff --git a/src/gui/panels/assets-panel.cpp b/src/gui/panels/resources-panel.cpp similarity index 83% rename from src/gui/panels/assets-panel.cpp rename to src/gui/panels/resources-panel.cpp index 1e189c0fc..360b7c4c8 100644 --- a/src/gui/panels/assets-panel.cpp +++ b/src/gui/panels/resources-panel.cpp @@ -21,14 +21,14 @@ * *****************************************************/ #include "../gtk-lumiera.hpp" -#include "assets-panel.hpp" +#include "resources-panel.hpp" namespace gui { namespace panels { -AssetsPanel::AssetsPanel(workspace::WorkspaceWindow &workspace_window) : - Panel(workspace_window, "assets", _("Assets"), "panel_assets"), - placeholder("Assets/Media") +ResourcesPanel::ResourcesPanel(workspace::WorkspaceWindow &workspace_window) : + Panel(workspace_window, "resources", _("Resources"), "panel_resources"), + placeholder("Resources") { pack_start(placeholder); } diff --git a/src/gui/panels/assets-panel.hpp b/src/gui/panels/resources-panel.hpp similarity index 92% rename from src/gui/panels/assets-panel.hpp rename to src/gui/panels/resources-panel.hpp index 33513243a..465fa78c3 100644 --- a/src/gui/panels/assets-panel.hpp +++ b/src/gui/panels/resources-panel.hpp @@ -31,7 +31,7 @@ namespace gui { namespace panels { -class AssetsPanel : public Panel +class ResourcesPanel : public Panel { public: @@ -39,7 +39,7 @@ public: * Contructor. * @param workspace_window The window that owns this panel. **/ - AssetsPanel(workspace::WorkspaceWindow &workspace_window); + ResourcesPanel(workspace::WorkspaceWindow &workspace_window); protected: Gtk::Label placeholder; diff --git a/src/gui/workspace/actions.cpp b/src/gui/workspace/actions.cpp index 9cbc94aea..88a440103 100644 --- a/src/gui/workspace/actions.cpp +++ b/src/gui/workspace/actions.cpp @@ -107,13 +107,13 @@ Actions::Actions(WorkspaceWindow &workspace_window) : void Actions::update_action_state() { - REQUIRE(workspaceWindow.assetsPanel != NULL); + REQUIRE(workspaceWindow.resourcesPanel != NULL); REQUIRE(workspaceWindow.timelinePanel != NULL); REQUIRE(workspaceWindow.viewerPanel != NULL); is_updating_action_state = true; assetsPanelAction->set_active( - workspaceWindow.assetsPanel->is_shown()); + workspaceWindow.resourcesPanel->is_shown()); timelinePanelAction->set_active( workspaceWindow.timelinePanel->is_shown()); viewerPanelAction->set_active( @@ -163,7 +163,8 @@ void Actions::on_menu_view_assets() { if(!is_updating_action_state) - workspaceWindow.assetsPanel->show(assetsPanelAction->get_active()); + workspaceWindow.resourcesPanel->show( + assetsPanelAction->get_active()); } void diff --git a/src/gui/workspace/workspace-window.cpp b/src/gui/workspace/workspace-window.cpp index abcce5601..9ac7c0edc 100644 --- a/src/gui/workspace/workspace-window.cpp +++ b/src/gui/workspace/workspace-window.cpp @@ -49,7 +49,7 @@ WorkspaceWindow::WorkspaceWindow(Project &source_project, actions(*this) { layout = NULL; - assetsPanel = NULL; + resourcesPanel = NULL; viewerPanel = NULL; timelinePanel = NULL; @@ -61,8 +61,8 @@ WorkspaceWindow::~WorkspaceWindow() REQUIRE(layout != NULL); g_object_unref(layout); - REQUIRE(assetsPanel != NULL); - assetsPanel->unreference(); + REQUIRE(resourcesPanel != NULL); + resourcesPanel->unreference(); REQUIRE(viewerPanel != NULL); viewerPanel->unreference(); REQUIRE(timelinePanel != NULL); @@ -159,8 +159,8 @@ WorkspaceWindow::create_ui() baseContainer.pack_start(*toolbar, Gtk::PACK_SHRINK); //----- Create the Panels -----// - assetsPanel = new AssetsPanel(*this); - ENSURE(assetsPanel != NULL); + resourcesPanel = new ResourcesPanel(*this); + ENSURE(resourcesPanel != NULL); viewerPanel = new ViewerPanel(*this); ENSURE(viewerPanel != NULL); timelinePanel = new TimelinePanel(*this); @@ -178,7 +178,7 @@ WorkspaceWindow::create_ui() baseContainer.pack_start(dockContainer, PACK_EXPAND_WIDGET); gdl_dock_add_item ((GdlDock*)dock->gobj(), - assetsPanel->get_dock_item(), GDL_DOCK_LEFT); + resourcesPanel->get_dock_item(), GDL_DOCK_LEFT); gdl_dock_add_item ((GdlDock*)dock->gobj(), viewerPanel->get_dock_item(), GDL_DOCK_RIGHT); gdl_dock_add_item ((GdlDock*)dock->gobj(), @@ -186,9 +186,9 @@ WorkspaceWindow::create_ui() // Manually dock and move around some of the items gdl_dock_item_dock_to (timelinePanel->get_dock_item(), - assetsPanel->get_dock_item(), GDL_DOCK_BOTTOM, -1); + resourcesPanel->get_dock_item(), GDL_DOCK_BOTTOM, -1); gdl_dock_item_dock_to (viewerPanel->get_dock_item(), - assetsPanel->get_dock_item(), GDL_DOCK_RIGHT, -1); + resourcesPanel->get_dock_item(), GDL_DOCK_RIGHT, -1); gchar ph1[] = "ph1"; gdl_dock_placeholder_new (ph1, (GdlDockObject*)dock->gobj(), diff --git a/src/gui/workspace/workspace-window.hpp b/src/gui/workspace/workspace-window.hpp index fb0254d2d..48c3c6916 100644 --- a/src/gui/workspace/workspace-window.hpp +++ b/src/gui/workspace/workspace-window.hpp @@ -34,7 +34,7 @@ #include "actions.hpp" -#include "../panels/assets-panel.hpp" +#include "../panels/resources-panel.hpp" #include "../panels/viewer-panel.hpp" #include "../panels/timeline-panel.hpp" @@ -94,7 +94,7 @@ private: /* ===== Panels ===== */ private: - AssetsPanel *assetsPanel; + ResourcesPanel *resourcesPanel; ViewerPanel *viewerPanel; TimelinePanel *timelinePanel; From 2f335a87d181202975859d85278b7c194295c7ff Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 18:31:26 +0000 Subject: [PATCH 079/216] Added an initial resources notebook --- src/gui/panels/resources-panel.cpp | 15 ++++++++++----- src/gui/panels/resources-panel.hpp | 7 ++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/gui/panels/resources-panel.cpp b/src/gui/panels/resources-panel.cpp index 360b7c4c8..83f4e916a 100644 --- a/src/gui/panels/resources-panel.cpp +++ b/src/gui/panels/resources-panel.cpp @@ -27,11 +27,16 @@ namespace gui { namespace panels { ResourcesPanel::ResourcesPanel(workspace::WorkspaceWindow &workspace_window) : - Panel(workspace_window, "resources", _("Resources"), "panel_resources"), - placeholder("Resources") - { - pack_start(placeholder); - } + Panel(workspace_window, "resources", _("Resources"), "panel_resources") +{ + + notebook.append_page(media, _("Media")); + notebook.append_page(clips, _("Clips")); + notebook.append_page(effects, _("Effects")); + notebook.append_page(transitions, _("Transitions")); + + pack_start(notebook); +} } // namespace panels } // namespace gui diff --git a/src/gui/panels/resources-panel.hpp b/src/gui/panels/resources-panel.hpp index 465fa78c3..2f038fdf1 100644 --- a/src/gui/panels/resources-panel.hpp +++ b/src/gui/panels/resources-panel.hpp @@ -42,7 +42,12 @@ public: ResourcesPanel(workspace::WorkspaceWindow &workspace_window); protected: - Gtk::Label placeholder; + Gtk::Notebook notebook; + + Gtk::IconView media; + Gtk::IconView clips; + Gtk::IconView effects; + Gtk::IconView transitions; }; } // namespace panels From c938526a94fe15d1e27d505d484387c24b2e604c Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 18:40:20 +0000 Subject: [PATCH 080/216] Renamed panel-assets icon to panel-resources --- icons/Makefile.am | 14 +++++++------- .../{panel-assets.png => panel-resources.png} | Bin .../{panel-assets.png => panel-resources.png} | Bin .../{panel-assets.png => panel-resources.png} | Bin src/gui/window-manager.cpp | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) rename icons/prerendered/16x16/{panel-assets.png => panel-resources.png} (100%) rename icons/prerendered/22x22/{panel-assets.png => panel-resources.png} (100%) rename icons/prerendered/32x32/{panel-assets.png => panel-resources.png} (100%) diff --git a/icons/Makefile.am b/icons/Makefile.am index 6490393ab..97d817ab4 100644 --- a/icons/Makefile.am +++ b/icons/Makefile.am @@ -40,7 +40,7 @@ dist_pkgdata_DATA += \ $(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-resources.png $(22x22)/panel-resources.png $(32x32)/panel-resources.png \ $(16x16)/panel-timeline.png \ $(16x16)/panel-viewer.png $(22x22)/panel-viewer.png $(32x32)/panel-viewer.png @@ -75,12 +75,12 @@ $(16x16)/track-unlocked.png : $(svgdir)/track-unlocked.svg $(top_builddir)/rsvg- # Panels -$(16x16)/panel-assets.png: - cp $(16x16pre)/panel-assets.png $(16x16) -$(22x22)/panel-assets.png: - cp $(22x22pre)/panel-assets.png $(22x22) -$(32x32)/panel-assets.png: - cp $(32x32pre)/panel-assets.png $(32x32) +$(16x16)/panel-resources.png: + cp $(16x16pre)/panel-resources.png $(16x16) +$(22x22)/panel-resources.png: + cp $(22x22pre)/panel-resources.png $(22x22) +$(32x32)/panel-resources.png: + cp $(32x32pre)/panel-resources.png $(32x32) $(16x16)/panel-timeline.png: cp $(16x16pre)/panel-timeline.png $(16x16) diff --git a/icons/prerendered/16x16/panel-assets.png b/icons/prerendered/16x16/panel-resources.png similarity index 100% rename from icons/prerendered/16x16/panel-assets.png rename to icons/prerendered/16x16/panel-resources.png diff --git a/icons/prerendered/22x22/panel-assets.png b/icons/prerendered/22x22/panel-resources.png similarity index 100% rename from icons/prerendered/22x22/panel-assets.png rename to icons/prerendered/22x22/panel-resources.png diff --git a/icons/prerendered/32x32/panel-assets.png b/icons/prerendered/32x32/panel-resources.png similarity index 100% rename from icons/prerendered/32x32/panel-assets.png rename to icons/prerendered/32x32/panel-resources.png diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index 88de4db56..5128e4ec7 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -87,7 +87,7 @@ WindowManager::register_stock_items() { RefPtr factory = IconFactory::create(); - add_stock_icon_set(factory, "panel-assets", "panel_assets", _("_Assets")); + add_stock_icon_set(factory, "panel-resources", "panel_resources", _("_Resources")); add_stock_icon_set(factory, "panel-timeline", "panel_timeline", _("_Timeline")); add_stock_icon_set(factory, "panel-viewer", "panel_viewer", _("_Viewer")); From e524e8c52866e365add78e765a5ae7dc905caca3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 24 Jan 2009 21:33:41 +0100 Subject: [PATCH 081/216] Fix the most obvious lockups ... but the design still doesn't feel right for me! --- src/gui/controller/playback-controller.cpp | 56 +++++++++++++--------- src/gui/controller/playback-controller.hpp | 4 +- src/proc/play/dummy-player-service.cpp | 2 +- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index bad1ebcc1..f360ca6a5 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -43,25 +43,29 @@ PlaybackController::~PlaybackController() void PlaybackController::play() { - Lock sync(this); - try + if (playing && thread && playHandle) { - if (playing && thread && playHandle) playHandle->pause(false); - else - { - playHandle = & (proc::DummyPlayer::facade().start()); - if (thread) - end_playback_thread(); - start_playback_thread(); - playing = true; - } - } - catch (lumiera::error::State& err) - { - WARN (operate, "failed to start playback: %s" ,err.what()); - lumiera_error(); - playing = false; + playHandle->pause(false); + return; } + if (thread) + end_playback_thread(); + + { + Lock sync(this); + try + { + playHandle = & (proc::DummyPlayer::facade().start()); + start_playback_thread(); + playing = true; + } + catch (lumiera::error::State& err) + { + WARN (operate, "failed to start playback: %s" ,err.what()); + lumiera_error(); + playing = false; + } + } } void @@ -76,11 +80,13 @@ PlaybackController::pause() void PlaybackController::stop() { - Lock sync(this); - playing = false; + { + Lock sync(this); + playing = false; + playHandle = 0; + // TODO: stop player somehow? + } end_playback_thread(); - playHandle = 0; - // TODO: stop player somehow? } bool @@ -102,11 +108,15 @@ PlaybackController::start_playback_thread() void PlaybackController::end_playback_thread() { - Lock sync(this); - finish_playback_thread = true; + { + Lock sync(this); + finish_playback_thread = true; + playing = false; + } if (thread) thread->join(); thread = 0; + finish_playback_thread = false; } void diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 9cab6d968..8b9a0916d 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -37,12 +37,12 @@ namespace gui { namespace controller { using lib::Sync; -using lib::NonrecursiveLock_NoWait; +using lib::RecursiveLock_NoWait; class PlaybackController : boost::noncopyable, - public Sync + public Sync { public: diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 4ec1a87ad..ca2f0dd31 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -270,7 +270,7 @@ namespace proc { ProcessImpl::setRate (uint fps) { // REQUIRE (fps==0 || fps_==0 ); //////////////TODO: reactivate this check when we have really independent processes which can be stopped! - REQUIRE (fps==0 || !play_ ); + // REQUIRE (fps==0 || !play_ ); //////////////TODO: reactivate this check when we have really independent processes which can be stopped! fps_ = fps; play_ = (fps != 0); From 19c7226c9f65a6d30ffc79f8412d4c392ee4d3b8 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 24 Jan 2009 22:25:50 +0100 Subject: [PATCH 082/216] Autotools fix: add dummy-player-service to lublumieraproc.so --- src/proc/Makefile.am | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/proc/Makefile.am b/src/proc/Makefile.am index c0058adfa..ad41212ee 100644 --- a/src/proc/Makefile.am +++ b/src/proc/Makefile.am @@ -122,6 +122,18 @@ liblumiproccontrol_la_SOURCES = \ $(liblumiproccontrol_la_srcdir)/stypemanager.cpp +liblumiprocplay_la_srcdir = $(top_srcdir)/src/proc/play +noinst_LTLIBRARIES += liblumiprocplay.la + +liblumiprocplay_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +liblumiprocplay_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra + +liblumiprocplay_la_SOURCES = \ + $(liblumiprocplay_la_srcdir)/dummy-player-service.cpp \ + $(liblumiprocplay_la_srcdir)/dummy-image-generator.cpp + + + liblumiprocmobjectsession_la_srcdir = $(top_srcdir)/src/proc/mobject/session noinst_LTLIBRARIES += liblumiprocmobjectsession.la @@ -193,6 +205,8 @@ noinst_HEADERS += \ $(liblumiproc_la_srcdir)/mobject/builderfacade.hpp \ $(liblumiproc_la_srcdir)/control/pathmanager.hpp \ $(liblumiproc_la_srcdir)/control/renderstate.hpp \ + $(liblumiproc_la_srcdir)/play/dummy-player-service.cpp \ + $(liblumiproc_la_srcdir)/play/dummy-image-generator.hpp \ $(liblumiproc_la_srcdir)/mobject/interpolator.hpp \ $(liblumiproc_la_srcdir)/mobject/parameter.hpp \ $(liblumiproc_la_srcdir)/mobject/paramprovider.hpp \ @@ -243,5 +257,6 @@ liblumieraproc_la_LIBADD = \ liblumiprocmobject.la \ liblumiprocmobjectbuilder.la \ liblumiproccontrol.la \ + liblumiprocplay.la \ liblumiprocmobjectsession.la From ef6344057c62424fd051b9749160d5304df4e31f Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 22 Jan 2009 09:44:29 +0100 Subject: [PATCH 083/216] first attempt to organize the nobug flags for review I grepped out all flags which are actually defined/used in lumiera and refactored them into one big tree here. There are some annotations and issues which shall be finally resolved. Please check if the intended hierarchy looks OK this way and add more flags when you think some are missing. I chosen to make a quite verbose hierarchy, this doesnt cost much in nobug and adds some flexibility. The Documentation at the head needs to be reviewed. Many flags which are collected here need to be brought back into the subsystems which use them, this is only to get a big picture for now. --- src/{lib/nobugcfg.cpp => common/logging.cpp} | 50 +++--- src/common/logging.h | 162 +++++++++++++++++++ src/include/nobugcfg.h | 119 -------------- 3 files changed, 182 insertions(+), 149 deletions(-) rename src/{lib/nobugcfg.cpp => common/logging.cpp} (60%) create mode 100644 src/common/logging.h delete mode 100644 src/include/nobugcfg.h diff --git a/src/lib/nobugcfg.cpp b/src/common/logging.cpp similarity index 60% rename from src/lib/nobugcfg.cpp rename to src/common/logging.cpp index ecbde0e79..6a3e265a7 100644 --- a/src/lib/nobugcfg.cpp +++ b/src/common/logging.cpp @@ -1,47 +1,37 @@ /* - NoBugCfg - NoBug definitions and initialisation for the Proc-Layer - + logging.cpp - Configure basic nobug logging + Copyright (C) Lumiera.org - 2008, Christian Thaeter - + 2008, 2009 Christian Thaeter + 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 "include/nobugcfg.h" +#define LOGGING_C -#define NOBUG_INIT_DEFS_ -#include "include/nobugcfg.h" -#undef NOBUG_INIT_DEFS_ - - - - -namespace lumiera { - - void - initialise_NoBug () - { - NOBUG_INIT; - -#ifdef DEBUG - static uint callCount = 0; - ASSERT ( 0 == callCount++ ); -#endif - } - -} +/* + logging.h defines the flags here, thats all + */ +#include "logging.h" +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/common/logging.h b/src/common/logging.h new file mode 100644 index 000000000..40d4aaa5b --- /dev/null +++ b/src/common/logging.h @@ -0,0 +1,162 @@ +/* + logging.h - Configure basic nobug logging + + Copyright (C) Lumiera.org + 2008, 2009 Christian Thaeter + 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 LUMIERA_LOGGING_H +#define LUMIERA_LOGGING_H + +/** @file logging.h + ** This header is for including and configuring NoBug. + ** The idea is that configuration and some commonly used flag + ** declarations are to be kept in one central location. Subsystems + ** are free to define and use additional flags for local use. Typically, + ** this header will be included via some of the basic headers like error.hpp, + ** which in turn gets included e.g. by proc/common.hpp + ** + ** This header can thus be assumed to be effectively global. It should contain + ** only declarations of global relevance, as any change causes the whole project + ** to be rebuilt. All flags defined here are automatic initialised. + ** + ** We use the 'NOBUG_DECLARATIONS_ONLY' magic to generate declarations and + ** definitions only out of this header. + ** + ** @par Logging configuration + ** By default, logging is configured such as to emit a small number of informative + ** messages on the starting terminal and to report fatal errors. But besides the + ** usual fine-grained tracing messages, we define a small number of distinct + ** thematic Logging Channels providing a consistent high-level view of + ** what is going on with regards to a specific aspect of the application + ** - \c progress documents a high-level overall view of what the application \em does + ** - \c render focuses on the working of the render engine (without logging each frame) + ** - \c config shows anything of relevance regarding the configured state of App and session + ** - \c memory allows to diagnose a high-level view of memory management + ** + ** Any log level can be overridden by an environment variable, for example + ** \code NOBUG_LOG='progress:INFO' ./lumiera \endcode + ** + ** @todo logging to files? NOBUG_LOG='progress:INFO@file(name=filename)' api to set this statically up by the program will follow --cehteh + ** @todo review this documentation ################################################################################################################################ + */ + + +#include + +#ifndef LUMIERA_LOGGING_C +#define NOBUG_DECLARE_ONLY 1 +#endif + +/** the root switch for all logging */ +NOBUG_CPP_DEFINE_FLAG (all); +/** debug logging */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( debugging, all); +/** debug logging for the main application starter */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( main_dbg, debugging); +/** base of debug logging for the backend */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( backend_dbg, debugging); +NOBUG_CPP_DEFINE_FLAG_PARENT ( file_dbg, backend_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( filehandle_dbg, backend_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( filehandlecache_dbg, backend_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( filedescriptor_dbg, backend_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( mmap_dbg, backend_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( mmapcache_dbg, backend_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( mmapings_dbg, backend_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( threads_dbg, backend_dbg); +/** base of debug logging for the proc layer */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( proc_dbg, debugging); +/** base of debug logging for the gui */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( gui_dbg, debugging); +/** base if debug logging for the support library */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( library_dbg, debugging); +NOBUG_CPP_DEFINE_FLAG_PARENT ( psplay_dbg, library_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( resourcecollector_dbg, library_dbg); +/** base of debug logging for the common library */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( common_dbg, debugging); +NOBUG_CPP_DEFINE_FLAG_PARENT ( config_dbg, common_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( configfile_dbg, config_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( configitem_dbg, config_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( configtyped_dbg, config_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( configlookup_dbg, config_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( interface_dbg, common_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( interfaceregistry_dbg, interface_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( plugin_dbg, common_dbg); +/** base of runtime logging always available */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( logging, all); +/** general application progress base */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( progress, logging); +/** progress log for the main starter */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( main, progress); +/** progress log for the backend */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( backend, progress); +NOBUG_CPP_DEFINE_FLAG_PARENT ( file, backend); //opening/closing files etc +/** progress log for the proc layer */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( proc, progress); +/** progress log for the render subsystem of proc */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( render, proc); //ichthyo: did you want this as global channel or as progress child? +/** progress log for the gui */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( gui, progress); +/** progress log for the support lib */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( library, progress); +NOBUG_CPP_DEFINE_FLAG_PARENT ( resourcecollector, library); +/** progress log for the common lib */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( common, progress); +/** progress log, config subsystem */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( config, common); +NOBUG_CPP_DEFINE_FLAG_PARENT ( configfiles, config); //reading, writing, lookup configfiles +NOBUG_CPP_DEFINE_FLAG_PARENT ( configtyped, config); //values queried, errors +/** progress log, interfaces */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( interface, common); +NOBUG_CPP_DEFINE_FLAG_PARENT ( interfaceregistry, common); //interfaces which get registered/removed +/** progress log, plugin loader*/ +NOBUG_CPP_DEFINE_FLAG_PARENT ( plugin, common); //plugins loaded/unloaded/errors +/** base flag for software testing */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( test, logging); +/** base flag for syncronization logging */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( sync, logging); +NOBUG_CPP_DEFINE_FLAG_PARENT ( mutex_sync, sync); //locking/unlocking mutexes +NOBUG_CPP_DEFINE_FLAG_PARENT ( condwait_sync, sync); //waiting and signalling condition vars +/** base flag for memory related logging */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( memory, logging); +/** memory busines of the proc layer */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( proc_mem, memory); +NOBUG_CPP_DEFINE_FLAG_PARENT ( mobject_mem, proc_mem); +NOBUG_CPP_DEFINE_FLAG_PARENT ( builder_mem, proc_mem); +NOBUG_CPP_DEFINE_FLAG_PARENT ( asset_mem, proc_mem); +/** event which drive the application are separately logged to reconstruct what happend/yielded to a problem */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( events, all); +/** caveat joel, you need to implement this */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( gui_event, all); + + + +#ifndef LUMIERA_LOGGING_C +#undef NOBUG_DECLARE_ONLY +#define NOBUG_DECLARE_ONLY 0 +#endif + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/include/nobugcfg.h b/src/include/nobugcfg.h deleted file mode 100644 index 37b336503..000000000 --- a/src/include/nobugcfg.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - NOBUGCFG.h - NoBug definitions and initialisation for the Proc-Layer - - - Copyright (C) Lumiera.org - 2008, Christian Thaeter - 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 nobugcfg.h - ** This header is for including and configuring NoBug. - ** The idea is that configuration and some commonly used flag - ** declarations are to be kept in one central location. Subsystems - ** are free to define and use additional flags for local use. Typically, - ** this header will be included via some of the basic headers like error.hpp, - ** which in turn gets included e.g. by proc/common.hpp - ** - ** This header can thus be assumed to be effectively global. It should contain - ** only declarations of global relevance, as any change causes the whole project - ** to be rebuilt. Moreover, for C++ this header assures automatic initialisation - ** of NoBug by placing a static ctor call. - ** - ** Besides the usual guarded declarations, this header contains one section - ** with the corresponding definitions. This section is to be included once - ** by some translation unit (currently this is lumiera/nobugcfg.cpp) in order to - ** generate the necessary definitions. - ** - ** @par Logging configuration - ** By default, logging is configured such as to emit a small number of informative - ** messages on the starting terminal and to report fatal errors. But besides the - ** usual fine-grained tracing messages, we define a small number of distinct - ** thematic Logging Channels providing a consistent high-level view of - ** what is going on with regards to a specific aspect of the application - ** - \c operate documents a high-level overall view of what the application \em does - ** - \c render focuses on the working of the render engine (without logging each frame) - ** - \c config shows anything of relevance regarding the configured state of App and session - ** - \c memory allows to diagnose a high-level view of memory management - ** - ** Any log level can be overridden by an environment variable, for example - ** \code NOBUG_LOG='operate:INFO' ./lumiera \endcode - ** - ** @todo logging to files? - */ - - -#ifndef NOBUGCFG_H /* ============= Part 1: DECLARATIONS ======== */ -#define NOBUGCFG_H - -#include -#include - - -#ifdef __cplusplus /* ============= C++ ================ */ - -#include "include/lifecycle.h" -#include "lib/error.hpp" ///< make assertions throw instead of abort() - -namespace lumiera { - void initialise_NoBug (); - namespace { - LifecycleHook trigger_it_ (ON_BASIC_INIT, &initialise_NoBug); -} } -#endif /* =====================(End) C++ ================ */ - - - - - /* declare flags used throughout the code base */ - NOBUG_DECLARE_FLAG (all); - NOBUG_DECLARE_FLAG (lumiera_all); - NOBUG_DECLARE_FLAG (lumiera); ///< master log, informative console output - NOBUG_DECLARE_FLAG (operate); ///< logging channel reporting what the application does - NOBUG_DECLARE_FLAG (render); ///< logging channel focusing on the render engine's workings - NOBUG_DECLARE_FLAG (config); ///< logging channel covering application and session configuration - NOBUG_DECLARE_FLAG (memory); ///< logging channel covering memory management issues - NOBUG_DECLARE_FLAG (sync); ///< especially for tracing synchronisation - NOBUG_DECLARE_FLAG (test); - - -#endif /*NOBUGCFG_H ======= (End) Part 1: DECLARATIONS ======== */ - - - - - - -#ifdef NOBUG_INIT_DEFS_ /*========== Part 2: DEFINITIONS ========= */ - - - /* flags used throughout the code base... */ - NOBUG_CPP_DEFINE_FLAG (all); - NOBUG_CPP_DEFINE_FLAG_PARENT (lumiera_all, all); - NOBUG_CPP_DEFINE_FLAG_PARENT (lumiera, lumiera_all); - NOBUG_CPP_DEFINE_FLAG_PARENT (config, lumiera); - NOBUG_CPP_DEFINE_FLAG_PARENT (operate, lumiera); - NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (render, lumiera, LOG_WARNING); - NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (memory, lumiera, LOG_WARNING); - NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (sync, memory, LOG_WARNING); - NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (test, all, LOG_ERR); - - - - -#endif /*NOBUG_INIT_DEFS_ ==== (End) Part 2: DEFINITIONS ========= */ From 16ebdd65b1ba0ad984ee734241f0beaa64868d33 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 24 Jan 2009 03:10:38 +0100 Subject: [PATCH 084/216] some more logging flags, little cleanup, fix to Makefile.am --- src/common/Makefile.am | 3 ++- src/common/logging.cpp | 10 +++------- src/common/logging.h | 28 ++++++++++++++++++++++------ src/lib/Makefile.am | 1 - 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/common/Makefile.am b/src/common/Makefile.am index bf63ed6eb..61738c00f 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -43,7 +43,8 @@ liblumieracommon_la_SOURCES = \ $(liblumieracommon_la_srcdir)/appstate.cpp \ $(liblumieracommon_la_srcdir)/option.cpp \ $(liblumieracommon_la_srcdir)/subsys.cpp \ - $(liblumieracommon_la_srcdir)/interfaceproxy.cpp + $(liblumieracommon_la_srcdir)/interfaceproxy.cpp \ + $(liblumieracommon_la_srcdir)/logging.cpp noinst_HEADERS += \ diff --git a/src/common/logging.cpp b/src/common/logging.cpp index 6a3e265a7..b2a62dfce 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -21,16 +21,12 @@ */ -#define LOGGING_C - -/* - logging.h defines the flags here, thats all - */ -#include "logging.h" +#define LUMIERA_LOGGING_CXX +#include "include/logging.h" /* // Local Variables: -// mode: C +// mode: C++ // c-file-style: "gnu" // indent-tabs-mode: nil // End: diff --git a/src/common/logging.h b/src/common/logging.h index 40d4aaa5b..0a2e49c4a 100644 --- a/src/common/logging.h +++ b/src/common/logging.h @@ -60,12 +60,15 @@ #include -#ifndef LUMIERA_LOGGING_C +#ifndef LUMIERA_LOGGING_CXX +#undef NOBUG_DECLARE_ONLY #define NOBUG_DECLARE_ONLY 1 #endif /** the root switch for all logging */ NOBUG_CPP_DEFINE_FLAG (all); + + /** debug logging */ NOBUG_CPP_DEFINE_FLAG_PARENT ( debugging, all); /** debug logging for the main application starter */ @@ -88,6 +91,8 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( gui_dbg, debugging); NOBUG_CPP_DEFINE_FLAG_PARENT ( library_dbg, debugging); NOBUG_CPP_DEFINE_FLAG_PARENT ( psplay_dbg, library_dbg); NOBUG_CPP_DEFINE_FLAG_PARENT ( resourcecollector_dbg, library_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( mutex_dbg, library_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( cond_dbg, library_dbg); /** base of debug logging for the common library */ NOBUG_CPP_DEFINE_FLAG_PARENT ( common_dbg, debugging); NOBUG_CPP_DEFINE_FLAG_PARENT ( config_dbg, common_dbg); @@ -97,7 +102,10 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( configtyped_dbg, config_dbg); NOBUG_CPP_DEFINE_FLAG_PARENT ( configlookup_dbg, config_dbg); NOBUG_CPP_DEFINE_FLAG_PARENT ( interface_dbg, common_dbg); NOBUG_CPP_DEFINE_FLAG_PARENT ( interfaceregistry_dbg, interface_dbg); -NOBUG_CPP_DEFINE_FLAG_PARENT ( plugin_dbg, common_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( pluginloader_dbg, common_dbg); +NOBUG_CPP_DEFINE_FLAG_PARENT ( plugins_dbg, debugging); + + /** base of runtime logging always available */ NOBUG_CPP_DEFINE_FLAG_PARENT ( logging, all); /** general application progress base */ @@ -107,6 +115,8 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( main, progress); /** progress log for the backend */ NOBUG_CPP_DEFINE_FLAG_PARENT ( backend, progress); NOBUG_CPP_DEFINE_FLAG_PARENT ( file, backend); //opening/closing files etc +NOBUG_CPP_DEFINE_FLAG_PARENT ( mmap, backend); //mmap errors +NOBUG_CPP_DEFINE_FLAG_PARENT ( thread, backend); //starting/stopping threads /** progress log for the proc layer */ NOBUG_CPP_DEFINE_FLAG_PARENT ( proc, progress); /** progress log for the render subsystem of proc */ @@ -125,14 +135,18 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( configtyped, config); /** progress log, interfaces */ NOBUG_CPP_DEFINE_FLAG_PARENT ( interface, common); NOBUG_CPP_DEFINE_FLAG_PARENT ( interfaceregistry, common); //interfaces which get registered/removed +NOBUG_CPP_DEFINE_FLAG_PARENT ( guifacade, common); +NOBUG_CPP_DEFINE_FLAG_PARENT ( subsystem, common); /** progress log, plugin loader*/ -NOBUG_CPP_DEFINE_FLAG_PARENT ( plugin, common); //plugins loaded/unloaded/errors +NOBUG_CPP_DEFINE_FLAG_PARENT ( pluginloader, common); //plugins loaded/unloaded/errors +/** progress log, external plugins*/ +NOBUG_CPP_DEFINE_FLAG_PARENT ( plugins, progress); /** base flag for software testing */ NOBUG_CPP_DEFINE_FLAG_PARENT ( test, logging); /** base flag for syncronization logging */ -NOBUG_CPP_DEFINE_FLAG_PARENT ( sync, logging); +NOBUG_CPP_DEFINE_FLAG_PARENT ( sync, logging); // do we need subsections here? backend_mutex_sync proc_mutex_sync etc? NOBUG_CPP_DEFINE_FLAG_PARENT ( mutex_sync, sync); //locking/unlocking mutexes -NOBUG_CPP_DEFINE_FLAG_PARENT ( condwait_sync, sync); //waiting and signalling condition vars +NOBUG_CPP_DEFINE_FLAG_PARENT ( cond_sync, sync); //waiting and signalling condition vars /** base flag for memory related logging */ NOBUG_CPP_DEFINE_FLAG_PARENT ( memory, logging); /** memory busines of the proc layer */ @@ -140,6 +154,8 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( proc_mem, memory); NOBUG_CPP_DEFINE_FLAG_PARENT ( mobject_mem, proc_mem); NOBUG_CPP_DEFINE_FLAG_PARENT ( builder_mem, proc_mem); NOBUG_CPP_DEFINE_FLAG_PARENT ( asset_mem, proc_mem); + + /** event which drive the application are separately logged to reconstruct what happend/yielded to a problem */ NOBUG_CPP_DEFINE_FLAG_PARENT ( events, all); /** caveat joel, you need to implement this */ @@ -147,7 +163,7 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( gui_event, all); -#ifndef LUMIERA_LOGGING_C +#ifndef LUMIERA_LOGGING_CXX #undef NOBUG_DECLARE_ONLY #define NOBUG_DECLARE_ONLY 0 #endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 10ad2f8ed..489be37ce 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -37,7 +37,6 @@ liblumiera_la_SOURCES = \ $(liblumiera_la_srcdir)/allocationcluster.cpp \ $(liblumiera_la_srcdir)/lumitime.cpp \ $(liblumiera_la_srcdir)/lifecycle.cpp \ - $(liblumiera_la_srcdir)/nobugcfg.cpp \ $(liblumiera_la_srcdir)/util.cpp \ $(liblumiera_la_srcdir)/visitor.cpp \ $(liblumiera_la_srcdir)/query.cpp \ From 65142d9cae1d08fafac4b2e9fec07500947b275c Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 24 Jan 2009 03:12:32 +0100 Subject: [PATCH 085/216] WIP: deploy new logging flags in backend --- src/backend/backend.c | 39 +++++++++++++------------- src/backend/backend.h | 2 +- src/backend/file.c | 18 +++++++----- src/backend/file.h | 2 +- src/backend/filedescriptor.c | 51 +++++++++++++++++----------------- src/backend/filehandle.c | 13 +++++---- src/backend/filehandle.h | 2 +- src/backend/filehandlecache.c | 21 +++++++------- src/backend/mmap.c | 27 +++++++++--------- src/backend/mmap.h | 2 +- src/backend/mmapcache.c | 37 ++++++++++++------------ src/backend/mmapings.c | 25 +++++++++-------- src/backend/mmapings.h | 2 +- src/backend/thread-wrapper.hpp | 6 ++-- src/backend/threads.c | 2 +- 15 files changed, 131 insertions(+), 118 deletions(-) diff --git a/src/backend/backend.c b/src/backend/backend.c index a06bdf853..569673405 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/safeclib.h" #include "backend/backend.h" @@ -31,20 +32,20 @@ #include //NOBUG_DEFINE_FLAG_PARENT (backend, lumiera); TODO -NOBUG_DEFINE_FLAG (backend); -NOBUG_DEFINE_FLAG_PARENT (file_all, backend); -NOBUG_DEFINE_FLAG_PARENT (filehandle, file_all); +//NOBUG_DEFINE_FLAG (backend); +//NOBUG_DEFINE_FLAG_PARENT (file_all, backend); +//NOBUG_DEFINE_FLAG_PARENT (filehandle, file_all); -NOBUG_DEFINE_FLAG_PARENT (mmapings, mmap_all); +//NOBUG_DEFINE_FLAG_PARENT (mmapings, mmap_all); -NOBUG_DECLARE_FLAG (file); +//NOBUG_DECLARE_FLAG (file); -NOBUG_DECLARE_FLAG (mmap_all); -NOBUG_DECLARE_FLAG (mmap); -NOBUG_DECLARE_FLAG (mmapings); -NOBUG_DECLARE_FLAG (mmapcache); +//NOBUG_DECLARE_FLAG (mmap_all); +//NOBUG_DECLARE_FLAG (mmap); +//NOBUG_DECLARE_FLAG (mmapings); +//NOBUG_DECLARE_FLAG (mmapcache); size_t lumiera_backend_pagesize; @@ -52,16 +53,16 @@ size_t lumiera_backend_pagesize; int lumiera_backend_init (void) { - NOBUG_INIT_FLAG (backend); - NOBUG_INIT_FLAG (file_all); - NOBUG_INIT_FLAG (file); - NOBUG_INIT_FLAG (filehandle); - NOBUG_INIT_FLAG (mmap_all); - NOBUG_INIT_FLAG (mmap); - NOBUG_INIT_FLAG (mmapings); - NOBUG_INIT_FLAG (mmapcache); + //NOBUG_INIT_FLAG (backend); + //NOBUG_INIT_FLAG (file_all); + //NOBUG_INIT_FLAG (file); + //NOBUG_INIT_FLAG (filehandle); + //NOBUG_INIT_FLAG (mmap_all); + //NOBUG_INIT_FLAG (mmap); + //NOBUG_INIT_FLAG (mmapings); + //NOBUG_INIT_FLAG (mmapcache); - TRACE (backend); + TRACE (backend_dbg); lumiera_filedescriptor_registry_init (); lumiera_backend_pagesize = sysconf(_SC_PAGESIZE); @@ -107,7 +108,7 @@ lumiera_backend_init (void) void lumiera_backend_destroy (void) { - TRACE (backend); + TRACE (backend_dbg); lumiera_mmapcache_delete (); lumiera_filehandlecache_delete (); lumiera_filedescriptor_registry_destroy (); diff --git a/src/backend/backend.h b/src/backend/backend.h index ded220b6e..8bfa18db5 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -23,7 +23,7 @@ #include -NOBUG_DECLARE_FLAG (backend); +//NOBUG_DECLARE_FLAG (backend); extern size_t lumiera_backend_pagesize; diff --git a/src/backend/file.c b/src/backend/file.c index b8b8ae937..ba18f93be 100644 --- a/src/backend/file.c +++ b/src/backend/file.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/mutex.h" #include "lib/safeclib.h" @@ -28,7 +29,7 @@ #include #include -NOBUG_DEFINE_FLAG_PARENT (file, file_all); +//NOBUG_DEFINE_FLAG_PARENT (file, file_all); LUMIERA_ERROR_DEFINE (FILE_CHANGED, "File changed unexpected"); LUMIERA_ERROR_DEFINE (FILE_NOCHUNKSIZE, "Chunksize not set"); @@ -37,7 +38,7 @@ LUMIERA_ERROR_DEFINE (FILE_NOCHUNKSIZE, "Chunksize not set"); LumieraFile lumiera_file_init (LumieraFile self, const char* name, int flags) { - TRACE (file); + TRACE (file_dbg); if (self) { @@ -55,7 +56,7 @@ lumiera_file_init (LumieraFile self, const char* name, int flags) LumieraFile lumiera_file_destroy (LumieraFile self) { - TRACE (file); + TRACE (file_dbg); lumiera_filedescriptor_release (self->descriptor, self->name, &self->node); lumiera_free (self->name); @@ -66,7 +67,9 @@ lumiera_file_destroy (LumieraFile self) LumieraFile lumiera_file_new (const char* name, int flags) { - TRACE (file); + TRACE (file_dbg); + TRACE (file, "opening file '%s' with flags '%x'", name, flags); + LumieraFile self = lumiera_malloc (sizeof (lumiera_file)); if (!lumiera_file_init (self, name, flags)) { @@ -80,7 +83,8 @@ lumiera_file_new (const char* name, int flags) void lumiera_file_delete (LumieraFile self) { - TRACE (file); + TRACE (file_dbg); + TRACE (file, "close file '%s'", self->name); lumiera_free (lumiera_file_destroy (self)); } @@ -88,7 +92,7 @@ lumiera_file_delete (LumieraFile self) int lumiera_file_handle_acquire (LumieraFile self) { - TRACE (file); + TRACE (file_dbg); REQUIRE (self); REQUIRE (self->descriptor); REQUIRE (lumiera_fhcache); @@ -100,7 +104,7 @@ lumiera_file_handle_acquire (LumieraFile self) void lumiera_file_handle_release (LumieraFile self) { - TRACE (file); + TRACE (file_dbg); REQUIRE (self); REQUIRE (self->descriptor); REQUIRE (lumiera_fhcache); diff --git a/src/backend/file.h b/src/backend/file.h index dd1188e02..cafd66939 100644 --- a/src/backend/file.h +++ b/src/backend/file.h @@ -27,7 +27,7 @@ #include "lib/llist.h" #include "lib/error.h" -NOBUG_DECLARE_FLAG (file); +//NOBUG_DECLARE_FLAG (file); LUMIERA_ERROR_DECLARE(FILE_CHANGED); LUMIERA_ERROR_DECLARE(FILE_NOCHUNKSIZE); diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index e27bf66f0..edb6afbfd 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/mutex.h" #include "lib/safeclib.h" @@ -34,7 +35,7 @@ #include -NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all); +//NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all); /* Filedescriptor registry @@ -89,24 +90,24 @@ key_fn (const PSplaynode node) void lumiera_filedescriptor_registry_init (void) { - NOBUG_INIT_FLAG (filedescriptor); - TRACE (filedescriptor); + //NOBUG_INIT_FLAG (filedescriptor); + TRACE (filedescriptor_dbg); REQUIRE (!registry); registry = psplay_new (cmp_fn, key_fn, delete_fn); if (!registry) LUMIERA_DIE (NO_MEMORY); - lumiera_mutex_init (®istry_mutex, "filedescriptor_registry", &NOBUG_FLAG (filedescriptor)); + lumiera_mutex_init (®istry_mutex, "filedescriptor_registry", &NOBUG_FLAG (mutex_dbg)); } void lumiera_filedescriptor_registry_destroy (void) { - TRACE (filedescriptor); + TRACE (filedescriptor_dbg); REQUIRE (!psplay_nelements (registry)); - lumiera_mutex_destroy (®istry_mutex, &NOBUG_FLAG (filedescriptor)); + lumiera_mutex_destroy (®istry_mutex, &NOBUG_FLAG (mutex_dbg)); if (registry) psplay_destroy (registry); @@ -117,13 +118,13 @@ lumiera_filedescriptor_registry_destroy (void) LumieraFiledescriptor lumiera_filedescriptor_acquire (const char* name, int flags, LList filenode) { - TRACE (filedescriptor, "%s", name); + TRACE (filedescriptor_dbg, "%s", name); REQUIRE (registry, "not initialized"); REQUIRE (llist_is_empty (filenode)); LumieraFiledescriptor dest = NULL; - LUMIERA_MUTEX_SECTION (filedescriptor, ®istry_mutex) + LUMIERA_MUTEX_SECTION (mutex_sync, ®istry_mutex) { lumiera_filedescriptor fdesc; fdesc.flags = flags; @@ -138,28 +139,28 @@ lumiera_filedescriptor_acquire (const char* name, int flags, LList filenode) while ((slash = strchr (slash+1, '/'))) { *slash = '\0'; - INFO (filedescriptor, "try creating dir: %s", dir); + INFO (filedescriptor_dbg, "try creating dir: %s", dir); if (mkdir (dir, 0777) == -1 && errno != EEXIST) { - LUMIERA_ERROR_SET_CRITICAL (filedescriptor, ERRNO, name); + LUMIERA_ERROR_SET_CRITICAL (file, ERRNO, name); goto error; } *slash = '/'; } int fd; - INFO (filedescriptor, "try creating file: %s", name); + INFO (filedescriptor_dbg, "try creating file: %s", name); TODO ("creat mode from config"); fd = creat (name, 0666); if (fd == -1) { - LUMIERA_ERROR_SET_CRITICAL (filedescriptor, ERRNO, name); + LUMIERA_ERROR_SET_CRITICAL (file, ERRNO, name); goto error; } close (fd); if (stat (name, &fdesc.stat) != 0) { /* finally, no luck */ - LUMIERA_ERROR_SET_CRITICAL (filedescriptor, ERRNO, name); + LUMIERA_ERROR_SET_CRITICAL (file, ERRNO, name); goto error; } } @@ -188,10 +189,10 @@ lumiera_filedescriptor_acquire (const char* name, int flags, LList filenode) void lumiera_filedescriptor_release (LumieraFiledescriptor self, const char* name, LList filenode) { - TRACE (filedescriptor); + TRACE (filedescriptor_dbg); if (filenode) - LUMIERA_MUTEX_SECTION (filedescriptor, &self->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { REQUIRE (llist_is_member (&self->files, filenode)); llist_unlink (filenode); @@ -205,11 +206,11 @@ lumiera_filedescriptor_release (LumieraFiledescriptor self, const char* name, LL int lumiera_filedescriptor_handle_acquire (LumieraFiledescriptor self) { - TRACE (filedescriptor); + TRACE (filedescriptor_dbg); int fd = -1; - LUMIERA_MUTEX_SECTION (filedescriptor, &self->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { if (!self->handle) /* no handle yet, get a new one */ @@ -227,10 +228,10 @@ lumiera_filedescriptor_handle_acquire (LumieraFiledescriptor self) void lumiera_filedescriptor_handle_release (LumieraFiledescriptor self) { - TRACE (filedescriptor); + TRACE (filedescriptor_dbg); REQUIRE (self->handle); - LUMIERA_MUTEX_SECTION (filedescriptor, &self->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) lumiera_filehandlecache_checkin (lumiera_fhcache, self->handle); } @@ -265,7 +266,7 @@ LumieraFiledescriptor lumiera_filedescriptor_new (LumieraFiledescriptor template) { LumieraFiledescriptor self = lumiera_malloc (sizeof (lumiera_filedescriptor)); - TRACE (filedescriptor, "at %p", self); + TRACE (filedescriptor_dbg, "at %p", self); psplaynode_init (&self->node); self->stat = template->stat; @@ -276,7 +277,7 @@ lumiera_filedescriptor_new (LumieraFiledescriptor template) self->mmapings = NULL; llist_init (&self->files); - lumiera_mutex_init (&self->lock, "filedescriptor", &NOBUG_FLAG (filedescriptor)); + lumiera_mutex_init (&self->lock, "filedescriptor", &NOBUG_FLAG (mutex_dbg)); return self; } @@ -285,9 +286,9 @@ lumiera_filedescriptor_new (LumieraFiledescriptor template) void lumiera_filedescriptor_delete (LumieraFiledescriptor self, const char* name) { - TRACE (filedescriptor, "%p %s", self, name); + TRACE (filedescriptor_dbg, "%p %s", self, name); - LUMIERA_MUTEX_SECTION (filedescriptor, ®istry_mutex) + LUMIERA_MUTEX_SECTION (mutex_sync, ®istry_mutex) { REQUIRE (llist_is_empty (&self->files)); @@ -297,7 +298,7 @@ lumiera_filedescriptor_delete (LumieraFiledescriptor self, const char* name) if (self->handle && name && ((self->flags & O_RDWR) == O_RDWR)) { - TRACE (filedescriptor, "truncate %s to %lld", name, self->realsize); + TRACE (filedescriptor_dbg, "truncate %s to %lld", name, self->realsize); lumiera_filehandlecache_checkout (lumiera_fhcache, self->handle); int dummy = ftruncate (lumiera_filehandle_handle (self->handle), self->realsize); (void) dummy; /* this is present to silence a warning */ @@ -309,7 +310,7 @@ lumiera_filedescriptor_delete (LumieraFiledescriptor self, const char* name) TODO ("release filehandle"); - lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG (filedescriptor)); + lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG (mutex_dbg)); lumiera_free (self); } } diff --git a/src/backend/filehandle.c b/src/backend/filehandle.c index 86d9107f2..5aa8de6e8 100644 --- a/src/backend/filehandle.c +++ b/src/backend/filehandle.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/llist.h" #include "lib/safeclib.h" @@ -31,7 +32,7 @@ LumieraFilehandle lumiera_filehandle_init (LumieraFilehandle self, LumieraFiledescriptor desc) { - TRACE (filehandle, "%p", self); + TRACE (filehandle_dbg, "%p", self); if (self) { llist_init (&self->cachenode); @@ -54,7 +55,7 @@ lumiera_filehandle_new (LumieraFiledescriptor desc) void* lumiera_filehandle_destroy_node (LList node) { - TRACE (filehandle); + TRACE (filehandle_dbg); REQUIRE (llist_is_empty (node)); LumieraFilehandle self = (LumieraFilehandle)node; REQUIRE (self->use_cnt == 0); @@ -76,7 +77,7 @@ lumiera_filehandle_get (LumieraFilehandle self) int lumiera_filehandle_handle (LumieraFilehandle self) { - TRACE (filehandle); + TRACE (filehandle_dbg); int fd = -1; if (self->fd == -1) @@ -85,7 +86,7 @@ lumiera_filehandle_handle (LumieraFilehandle self) if (fd == -1) { FIXME ("Handle EMFILE etc with the resourcecollector"); - LUMIERA_ERROR_SET_CRITICAL (filehandle, ERRNO, lumiera_filedescriptor_name (self->descriptor)); + LUMIERA_ERROR_SET_CRITICAL (file, ERRNO, lumiera_filedescriptor_name (self->descriptor)); } else { @@ -94,14 +95,14 @@ lumiera_filehandle_handle (LumieraFilehandle self) { close (fd); fd = -1; - LUMIERA_ERROR_SET_CRITICAL (filehandle, ERRNO, lumiera_filedescriptor_name (self->descriptor)); + LUMIERA_ERROR_SET_CRITICAL (file, ERRNO, lumiera_filedescriptor_name (self->descriptor)); } else if (!lumiera_filedescriptor_samestat (self->descriptor, &st)) { close (fd); fd = -1; /* Woops this is not the file we expected to use */ - LUMIERA_ERROR_SET_CRITICAL (filehandle, FILE_CHANGED, lumiera_filedescriptor_name (self->descriptor)); + LUMIERA_ERROR_SET_CRITICAL (file, FILE_CHANGED, lumiera_filedescriptor_name (self->descriptor)); } } self->fd = fd; diff --git a/src/backend/filehandle.h b/src/backend/filehandle.h index d92410a78..21d1f11ad 100644 --- a/src/backend/filehandle.h +++ b/src/backend/filehandle.h @@ -29,7 +29,7 @@ typedef lumiera_filehandle* LumieraFilehandle; #include "backend/filedescriptor.h" -NOBUG_DECLARE_FLAG (filehandle); +//NOBUG_DECLARE_FLAG (filehandle); /** * @file diff --git a/src/backend/filehandlecache.c b/src/backend/filehandlecache.c index fcec07202..123f8924c 100644 --- a/src/backend/filehandlecache.c +++ b/src/backend/filehandlecache.c @@ -19,12 +19,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/safeclib.h" #include "backend/file.h" #include "backend/filehandlecache.h" -NOBUG_DEFINE_FLAG_PARENT (filehandlecache, file_all); +//NOBUG_DEFINE_FLAG_PARENT (filehandlecache, file_all); /* errors */ @@ -39,12 +40,12 @@ lumiera_filehandlecache_new (int max_entries) { REQUIRE (!lumiera_fhcache, "Filehandlecache already initialized"); - NOBUG_INIT_FLAG (filehandlecache); + //NOBUG_INIT_FLAG (filehandlecache); lumiera_fhcache = lumiera_malloc (sizeof (lumiera_filehandlecache)); lumiera_mrucache_init (&lumiera_fhcache->cache, lumiera_filehandle_destroy_node); lumiera_fhcache->available = max_entries; lumiera_fhcache->checked_out = 0; - lumiera_mutex_init (&lumiera_fhcache->lock, "filehandlecache", &NOBUG_FLAG (filehandlecache)); + lumiera_mutex_init (&lumiera_fhcache->lock, "filehandlecache", &NOBUG_FLAG (mutex_dbg)); } @@ -55,7 +56,7 @@ lumiera_filehandlecache_delete (void) { REQUIRE (!lumiera_fhcache->checked_out, "Filehandles in use at shutdown"); lumiera_mrucache_destroy (&lumiera_fhcache->cache); - lumiera_mutex_destroy (&lumiera_fhcache->lock, &NOBUG_FLAG (filehandlecache)); + lumiera_mutex_destroy (&lumiera_fhcache->lock, &NOBUG_FLAG (mutex_dbg)); lumiera_free (lumiera_fhcache); lumiera_fhcache = NULL; } @@ -65,10 +66,10 @@ lumiera_filehandlecache_delete (void) LumieraFilehandle lumiera_filehandlecache_handle_acquire (LumieraFilehandlecache self, LumieraFiledescriptor desc) { - TRACE (filehandlecache); + TRACE (filehandlecache_dbg); LumieraFilehandle ret = NULL; - LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { if (self->available <= 0 && self->cache.cached) { @@ -82,11 +83,11 @@ lumiera_filehandlecache_handle_acquire (LumieraFilehandlecache self, LumieraFile else { /* allocate new filehandle if we are below the limit or no cached handles are available (overallocating) */ - NOTICE (filehandlecache, "overallocating filehandle"); + NOTICE (file, "overallocating filehandle"); ret = lumiera_filehandle_new (desc); TODO ("use resourcecollector here"); if (!ret) - LUMIERA_ERROR_SET_ALERT (filehandlecache, FILEHANDLECACHE_NOHANDLE, lumiera_filedescriptor_name (desc)); + LUMIERA_ERROR_SET_ALERT (file, FILEHANDLECACHE_NOHANDLE, lumiera_filedescriptor_name (desc)); else --self->available; } @@ -106,7 +107,7 @@ lumiera_filehandlecache_checkout (LumieraFilehandlecache self, LumieraFilehandle if (!handle->use_cnt) { /* lock cache and checkout */ - LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { lumiera_mrucache_checkout (&self->cache, &handle->cachenode); } @@ -129,7 +130,7 @@ lumiera_filehandlecache_checkin (LumieraFilehandlecache self, LumieraFilehandle if (!--handle->use_cnt) { /* lock cache and checin */ - LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { --self->checked_out; lumiera_mrucache_checkin (&self->cache, &handle->cachenode); diff --git a/src/backend/mmap.c b/src/backend/mmap.c index d06c8effb..e10d3d664 100644 --- a/src/backend/mmap.c +++ b/src/backend/mmap.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/safeclib.h" #include "backend/mmap.h" @@ -34,8 +35,8 @@ * */ -NOBUG_DEFINE_FLAG_PARENT (mmap_all, backend); -NOBUG_DEFINE_FLAG_PARENT (mmap, mmap_all); +//NOBUG_DEFINE_FLAG_PARENT (mmap_all, backend); +//NOBUG_DEFINE_FLAG_PARENT (mmap, mmap_all); LUMIERA_ERROR_DEFINE (MMAP_NWRITE, "Backing file not writable"); @@ -51,7 +52,7 @@ LUMIERA_ERROR_DEFINE (MMAP_SPACE, "Address space exhausted"); LumieraMMap lumiera_mmap_init (LumieraMMap self, LumieraFile file, off_t start, size_t size) { - TRACE (mmap); + TRACE (mmap_dbg); REQUIRE (self); REQUIRE (file); @@ -80,7 +81,7 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, off_t start, size_t size) LumieraFiledescriptor descriptor = file->descriptor; int fd = lumiera_file_handle_acquire (file); - TRACE (mmap, "got fd %d", fd); + TRACE (mmap_dbg, "got fd %d", fd); if (fd == -1) goto efile; @@ -128,7 +129,7 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, off_t start, size_t size) switch (strategy++) { case FIRST_TRY: - TRACE (mmap, "FIRST_TRY"); + TRACE (mmap_dbg, "FIRST_TRY"); /* align begin and end to chunk boundaries */ begin = start & ~(chunksize-1); length = ((start+size+chunksize-1) & ~(chunksize-1)) - begin; @@ -159,17 +160,17 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, off_t start, size_t size) break; case DROP_FROM_CACHE: - TRACE (mmap, "drop a mapping from cache"); + TRACE (mmap_dbg, "drop a mapping from cache"); UNIMPLEMENTED ("mmap cache drop"); break; case REDUCE_WINDOW: - NOTICE (mmap, "mmaping window reduced to NN MB"); + NOTICE (mmap_dbg, "mmaping window reduced to NN MB"); UNIMPLEMENTED ("mmap window reduce"); break; case REDUCE_IN_USE: - NOTICE (mmap, "reduce mmapings in use"); + NOTICE (mmap_dbg, "reduce mmapings in use"); UNIMPLEMENTED ("mmapings in use reduce"); break; @@ -185,7 +186,7 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, off_t start, size_t size) fd, begin); - INFO_IF (addr==(void*)-1, mmap, "mmap failed %s", strerror (errno)); + INFO_IF (addr==(void*)-1, mmap_dbg, "mmap failed %s", strerror (errno)); ENSURE (errno == 0 || errno == ENOMEM, "unexpected mmap error %s", strerror (errno)); } @@ -213,7 +214,7 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, off_t start, size_t size) LumieraMMap lumiera_mmap_new (LumieraFile file, off_t start, size_t size) { - TRACE (mmap); + TRACE (mmap_dbg); LumieraMMap self = lumiera_mmapcache_mmap_acquire (lumiera_mcache); @@ -230,7 +231,7 @@ lumiera_mmap_new (LumieraFile file, off_t start, size_t size) void lumiera_mmap_delete (LumieraMMap self) { - TRACE (mmap); + TRACE (mmap_dbg); if (self) { lumiera_mmapcache_forget (lumiera_mcache, self); @@ -238,7 +239,7 @@ lumiera_mmap_delete (LumieraMMap self) /* The matching mappings->lock must be hold or being irrelevant (mappings destructor) here, we can't asset this from here, good luck */ llist_unlink (&self->searchnode); - TRACE (mmap, "unmap at %p with size %zd", self->address, self->size); + TRACE (mmap_dbg, "unmap at %p with size %zd", self->address, self->size); munmap (self->address, self->size); lumiera_free (self->refmap); lumiera_free (self); @@ -249,7 +250,7 @@ lumiera_mmap_delete (LumieraMMap self) void* lumiera_mmap_destroy_node (LList node) { - TRACE (mmap); + TRACE (mmap_dbg); REQUIRE (llist_is_empty (node)); LumieraMMap self = (LumieraMMap)node; diff --git a/src/backend/mmap.h b/src/backend/mmap.h index 311b323f4..2bd9db7c2 100644 --- a/src/backend/mmap.h +++ b/src/backend/mmap.h @@ -36,7 +36,7 @@ typedef lumiera_mmap* LumieraMMap; #include #include -NOBUG_DECLARE_FLAG (mmap); +//NOBUG_DECLARE_FLAG (mmap); /** diff --git a/src/backend/mmapcache.c b/src/backend/mmapcache.c index ea1d7dac3..2510ead0b 100644 --- a/src/backend/mmapcache.c +++ b/src/backend/mmapcache.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/safeclib.h" #include "backend/mmapcache.h" @@ -28,7 +29,7 @@ * */ -NOBUG_DEFINE_FLAG_PARENT (mmapcache, mmap_all); +//NOBUG_DEFINE_FLAG_PARENT (mmapcache, mmap_all); LumieraMMapcache lumiera_mcache = NULL; @@ -36,7 +37,7 @@ LumieraMMapcache lumiera_mcache = NULL; void lumiera_mmapcache_new (size_t limit) { - TRACE (mmapcache); + TRACE (mmapcache_dbg); lumiera_mcache = lumiera_malloc (sizeof (*lumiera_mcache)); lumiera_mrucache_init (&lumiera_mcache->cache, lumiera_mmap_destroy_node); @@ -45,19 +46,19 @@ lumiera_mmapcache_new (size_t limit) lumiera_mcache->total = 0; lumiera_mcache->cached = 0; - lumiera_mutex_init (&lumiera_mcache->lock, "mmapcache", &NOBUG_FLAG (mmapcache)); + lumiera_mutex_init (&lumiera_mcache->lock, "mmapcache", &NOBUG_FLAG (mutex_dbg)); } void lumiera_mmapcache_delete (void) { - TRACE (mmapcache); + TRACE (mmapcache_dbg); if (lumiera_mcache) { REQUIRE (lumiera_mcache->total == lumiera_mcache->cached, "MMaps still checked out at shutdown"); lumiera_mrucache_destroy (&lumiera_mcache->cache); - lumiera_mutex_destroy (&lumiera_mcache->lock, &NOBUG_FLAG (mmapcache)); + lumiera_mutex_destroy (&lumiera_mcache->lock, &NOBUG_FLAG (mutex_dbg)); free (lumiera_mcache); lumiera_mcache = NULL; } @@ -67,10 +68,10 @@ lumiera_mmapcache_delete (void) void* lumiera_mmapcache_mmap_acquire (LumieraMMapcache self) { - TRACE (mmapcache); + TRACE (mmapcache_dbg); void* map = NULL; - LUMIERA_MUTEX_SECTION (mmapcache, &self->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { map = lumiera_mrucache_pop (&self->cache); } @@ -78,11 +79,11 @@ lumiera_mmapcache_mmap_acquire (LumieraMMapcache self) if (!map) { map = lumiera_malloc (sizeof (*self)); - TRACE (mmapcache, "allocated new mmap"); + TRACE (mmapcache_dbg, "allocated new mmap"); } else { - TRACE (mmapcache, "poped mmap from cache"); + TRACE (mmapcache_dbg, "poped mmap from cache"); } return map; @@ -92,8 +93,8 @@ lumiera_mmapcache_mmap_acquire (LumieraMMapcache self) void lumiera_mmapcache_announce (LumieraMMapcache self, LumieraMMap map) { - TRACE (mmapcache); - LUMIERA_MUTEX_SECTION (mmapcache, &self->lock) + TRACE (mmapcache_dbg); + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { self->total += map->size; } @@ -103,8 +104,8 @@ lumiera_mmapcache_announce (LumieraMMapcache self, LumieraMMap map) void lumiera_mmapcache_forget (LumieraMMapcache self, LumieraMMap map) { - TRACE (mmapcache); - LUMIERA_MUTEX_SECTION (mmapcache, &self->lock) + TRACE (mmapcache_dbg); + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { if (!llist_is_empty (&map->cachenode)) { @@ -120,7 +121,7 @@ lumiera_mmapcache_forget (LumieraMMapcache self, LumieraMMap map) int lumiera_mmapcache_age (LumieraMMapcache self) { - TRACE (mmapcache); + TRACE (mmapcache_dbg); int ret = 0; LUMIERA_MUTEX_SECTION (mmapcache, &self->lock) @@ -135,9 +136,9 @@ lumiera_mmapcache_age (LumieraMMapcache self) LumieraMMap lumiera_mmapcache_checkout (LumieraMMapcache self, LumieraMMap handle) { - TRACE (mmapcache); + TRACE (mmapcache_dbg); - LUMIERA_MUTEX_SECTION (mmapcache, &self->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { TODO ("cached stats"); lumiera_mrucache_checkout (&self->cache, &handle->cachenode); @@ -151,9 +152,9 @@ lumiera_mmapcache_checkout (LumieraMMapcache self, LumieraMMap handle) void lumiera_mmapcache_checkin (LumieraMMapcache self, LumieraMMap handle) { - TRACE (mmapcache); + TRACE (mmapcache_dbg); - LUMIERA_MUTEX_SECTION (mmapcache, &self->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { TODO ("cached stats"); --handle->refcnt; diff --git a/src/backend/mmapings.c b/src/backend/mmapings.c index b36d77d62..88e6cab3e 100644 --- a/src/backend/mmapings.c +++ b/src/backend/mmapings.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/mutex.h" #include "lib/safeclib.h" @@ -36,14 +37,14 @@ LumieraMMapings lumiera_mmapings_init (LumieraMMapings self, LumieraFile file, size_t chunksize) { - TRACE (mmapings); + TRACE (mmapings_dbg); REQUIRE (!file->descriptor->mmapings); llist_init (&self->mmaps); self->descriptor = file->descriptor; self->chunksize = chunksize; - lumiera_mutex_init (&self->lock, "mmapings", &NOBUG_FLAG(mmapings)); + lumiera_mutex_init (&self->lock, "mmapings", &NOBUG_FLAG(mutex_dbg)); return self; } @@ -52,7 +53,7 @@ lumiera_mmapings_init (LumieraMMapings self, LumieraFile file, size_t chunksize) LumieraMMapings lumiera_mmapings_destroy (LumieraMMapings self) { - TRACE (mmapings); + TRACE (mmapings_dbg); if (!self) return NULL; @@ -62,7 +63,7 @@ lumiera_mmapings_destroy (LumieraMMapings self) lumiera_mmap_delete (mmap); } - lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG(mmapings)); + lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG(mutex_dbg)); return self; } @@ -71,6 +72,7 @@ lumiera_mmapings_destroy (LumieraMMapings self) LumieraMMapings lumiera_mmapings_new (LumieraFile file, size_t chunksize) { + TRACE (mmapings_dbg); LumieraMMapings self = lumiera_malloc (sizeof (*self)); return lumiera_mmapings_init (self, file, chunksize); } @@ -79,7 +81,7 @@ lumiera_mmapings_new (LumieraFile file, size_t chunksize) void lumiera_mmapings_delete (LumieraMMapings self) { - TRACE (mmapings); + TRACE (mmapings_dbg); free (lumiera_mmapings_destroy (self)); } @@ -87,11 +89,11 @@ lumiera_mmapings_delete (LumieraMMapings self) LumieraMMap lumiera_mmapings_mmap_acquire (LumieraMMapings self, LumieraFile file, LList acquirer, off_t start, size_t size) { - TRACE (mmapings); + TRACE (mmapings_dbg); LumieraMMap ret = NULL; - LUMIERA_MUTEX_SECTION (mmapings, &self->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { REQUIRE (llist_is_empty (acquirer)); @@ -119,7 +121,7 @@ lumiera_mmapings_mmap_acquire (LumieraMMapings self, LumieraFile file, LList acq else { /* create new mmap */ - TRACE (mmapings, "mmap not found, creating", mmap); + TRACE (mmapings_dbg, "mmap not found, creating", mmap); ret = lumiera_mmap_new (file, start, size); llist_insert_head (&self->mmaps, &ret->searchnode); @@ -137,13 +139,14 @@ lumiera_mmapings_mmap_acquire (LumieraMMapings self, LumieraFile file, LList acq void lumiera_mmapings_release_mmap (LumieraMMapings self, LList acquirer, LumieraMMap map) { - TRACE (mmapings); - LUMIERA_MUTEX_SECTION (mmapings, &self->lock) + TRACE (mmapings_dbg); + + LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock) { llist_unlink (acquirer); if (llist_is_empty (&map->cachenode)) { - TRACE (mmapings, "checkin"); + TRACE (mmapcache_dbg, "checkin"); lumiera_mmapcache_checkin (lumiera_mcache, map); } } diff --git a/src/backend/mmapings.h b/src/backend/mmapings.h index 17548f1a9..1e21d03d3 100644 --- a/src/backend/mmapings.h +++ b/src/backend/mmapings.h @@ -34,7 +34,7 @@ typedef lumiera_mmapings* LumieraMMapings; #include -NOBUG_DECLARE_FLAG (mmapings); +//NOBUG_DECLARE_FLAG (mmapings); /** * @file diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 3c60cda09..9847b6c2e 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -25,7 +25,7 @@ #define LIB_THREADWRAPPER_H -#include "include/nobugcfg.h" +#include "common/logging.h" #include "lib/sync.hpp" extern "C" { @@ -74,7 +74,7 @@ namespace lib { static void run (void* arg) { - ASSERT (arg); + REQUIRE (arg); Thread* startingWrapper = reinterpret_cast(arg); Operation _doIt_(startingWrapper->operation_); { @@ -88,7 +88,7 @@ namespace lib { public: - Thread (Literal& purpose, Operation const& operation, struct nobug_flag *logging_flag = &NOBUG_FLAG(operate)) + Thread (Literal& purpose, Operation const& operation, struct nobug_flag *logging_flag = &NOBUG_FLAG(thread)) : started_(false), operation_(operation) { diff --git a/src/backend/threads.c b/src/backend/threads.c index d0feec9b8..794d13b79 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -36,7 +36,7 @@ * */ -NOBUG_DEFINE_FLAG_PARENT (threads, lumiera); /*TODO insert a suitable/better parent flag here */ +//NOBUG_DEFINE_FLAG_PARENT (threads, lumiera); /*TODO insert a suitable/better parent flag here */ //code goes here// From 6a5951bad6d48c611f894701fac4c7b3b144c1aa Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 24 Jan 2009 03:13:08 +0100 Subject: [PATCH 086/216] WIP: deploy new logging flags in common --- src/common/appstate.cpp | 20 ++++----- src/common/appstate.hpp | 2 +- src/common/config.c | 63 ++++++++++++++------------- src/common/config.h | 12 ++--- src/common/config_lookup.c | 22 +++++----- src/common/config_typed.c | 57 ++++++++++++------------ src/common/config_wordlist.c | 5 ++- src/common/configfacade.cpp | 6 +-- src/common/configitem.c | 23 +++++----- src/common/configrules.cpp | 2 +- src/common/guifacade.cpp | 19 +++++--- src/common/instancehandle.hpp | 2 +- src/common/interface.c | 28 ++++++------ src/common/interfaceregistry.c | 44 ++++++++++--------- src/common/interfaceregistry.h | 6 +-- src/common/logging.cpp | 2 +- src/common/plugin.c | 30 ++++++------- src/common/plugin.h | 2 +- src/common/plugin_dynlib.c | 10 +++-- src/common/query/fake-configrules.cpp | 2 +- src/common/subsystem-runner.hpp | 14 +++--- 21 files changed, 196 insertions(+), 175 deletions(-) diff --git a/src/common/appstate.cpp b/src/common/appstate.cpp index 4bea6168b..f20025ab2 100644 --- a/src/common/appstate.cpp +++ b/src/common/appstate.cpp @@ -49,7 +49,7 @@ namespace lumiera { log_and_clear_unexpected_errorstate () { if (const char * errorstate = lumiera_error ()) - ERROR (NOBUG_ON, "*** Unexpected error: %s\n Triggering emergency exit.", errorstate); + ALERT (common, "*** Unexpected error: %s\n Triggering emergency exit.", errorstate); } void @@ -108,7 +108,7 @@ namespace lumiera { void AppState::init (Option& options) { - TRACE (lumiera, "initialising application core..."); + TRACE (common, "initialising application core..."); lumiera_interfaceregistry_init (); _THROW_IF @@ -126,7 +126,7 @@ namespace lumiera { subsystems_.reset (new SubsystemRunner (options)); - TRACE (lumiera, "Lumiera core started successfully."); + TRACE (common, "Lumiera core started successfully."); } @@ -134,8 +134,8 @@ namespace lumiera { void AppState::maybeStart (lumiera::Subsys& subsys) { - TRACE (lumiera, "maybe startup %s...?", cStr(subsys)); - ASSERT (subsystems_); + TRACE (common, "maybe startup %s...?", cStr(subsys)); + REQUIRE (subsystems_); subsystems_->maybeRun (subsys); } @@ -165,11 +165,11 @@ namespace lumiera { subsystems_.reset(0); } - NOTICE (lumiera, "Shutting down Lumiera..."); + NOTICE (common, "Shutting down Lumiera..."); if (emergency_) { - ERROR (operate, "Triggering emergency exit..."); + ALERT (common, "Triggering emergency exit..."); LifecycleHook::trigger (ON_EMERGENCY); return CLEAN_EMERGENCY_EXIT; } @@ -186,9 +186,9 @@ namespace lumiera { AppState::abort (lumiera::Error& problem) { - INFO (operate, "Address of Config Facade = %x", &lumiera::Config::instance()); //////////TODO: a temp hack to force configfacade.cpp to be linked into lumiera exe. + INFO (common, "Address of Config Facade = %x", &lumiera::Config::instance()); //////////TODO: a temp hack to force configfacade.cpp to be linked into lumiera exe. - ERROR (operate, "Aborting Lumiera after unhandled error: %s", cStr(problem.what())); + ERROR (common, "Aborting Lumiera after unhandled error: %s", cStr(problem.what())); log_and_clear_unexpected_errorstate(); @@ -239,7 +239,7 @@ namespace lumiera { if (core_up_) try { - TRACE (lumiera, "shutting down basic application layer..."); + TRACE (common, "shutting down basic application layer..."); lumiera_config_interface_destroy (); lumiera_interfaceregistry_destroy (); } diff --git a/src/common/appstate.hpp b/src/common/appstate.hpp index e31d75328..ca77f7128 100644 --- a/src/common/appstate.hpp +++ b/src/common/appstate.hpp @@ -28,7 +28,7 @@ ** ** @see LifecycleHook ** @see main.cpp - ** @see nobugcfg.h + ** @see logging.h */ diff --git a/src/common/config.c b/src/common/config.c index af994ab64..70341d68c 100644 --- a/src/common/config.c +++ b/src/common/config.c @@ -20,6 +20,7 @@ */ //TODO: Support library includes// +#include "common/logging.h" #include "lib/safeclib.h" #include "common/config.h" @@ -39,12 +40,12 @@ * */ -NOBUG_DEFINE_FLAG_PARENT (config_all, lumiera_all); -NOBUG_DEFINE_FLAG_PARENT (configsys, config_all); -NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all); -NOBUG_DEFINE_FLAG_PARENT (config_file, config_all); -NOBUG_DEFINE_FLAG_PARENT (config_item, config_all); -NOBUG_DEFINE_FLAG_PARENT (config_lookup, config_all); +//NOBUG_DEFINE_FLAG_PARENT (config_all, lumiera_all); +//NOBUG_DEFINE_FLAG_PARENT (configsys, config_all); +//NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all); +//NOBUG_DEFINE_FLAG_PARENT (config_file, config_all); +//NOBUG_DEFINE_FLAG_PARENT (config_item, config_all); +//NOBUG_DEFINE_FLAG_PARENT (config_lookup, config_all); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "syntax error in configfile"); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "syntax error in key"); @@ -93,16 +94,16 @@ LumieraConfig lumiera_global_config = NULL; int lumiera_config_init (const char* path) { - TRACE (configsys); + TRACE (config_dbg); REQUIRE (!lumiera_global_config, "Configuration subsystem already initialized"); REQUIRE (path); - NOBUG_INIT_FLAG (config_all); - NOBUG_INIT_FLAG (configsys); - NOBUG_INIT_FLAG (config_typed); - NOBUG_INIT_FLAG (config_file); - NOBUG_INIT_FLAG (config_item); - NOBUG_INIT_FLAG (config_lookup); + //NOBUG_INIT_FLAG (config_all); + //NOBUG_INIT_FLAG (configsys); + //NOBUG_INIT_FLAG (config_typed); + //NOBUG_INIT_FLAG (config_file); + //NOBUG_INIT_FLAG (config_item); + //NOBUG_INIT_FLAG (config_lookup); lumiera_global_config = lumiera_malloc (sizeof (*lumiera_global_config)); lumiera_config_lookup_init (&lumiera_global_config->keys); @@ -111,7 +112,7 @@ lumiera_config_init (const char* path) lumiera_configitem_init (&lumiera_global_config->files); lumiera_configitem_init (&lumiera_global_config->TODO_unknown); - lumiera_mutex_init (&lumiera_global_config->lock, "config mutex", &NOBUG_FLAG (configsys)); + lumiera_mutex_init (&lumiera_global_config->lock, "config mutex", &NOBUG_FLAG (mutex_dbg)); lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "config.path = %s", path)); @@ -127,10 +128,10 @@ lumiera_config_init (const char* path) void lumiera_config_destroy () { - TRACE (configsys); + TRACE (config_dbg); if (lumiera_global_config) { - lumiera_mutex_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (configsys)); + lumiera_mutex_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (mutex_dbg)); lumiera_configitem_destroy (&lumiera_global_config->defaults, &lumiera_global_config->keys); lumiera_configitem_destroy (&lumiera_global_config->files, &lumiera_global_config->keys); lumiera_configitem_destroy (&lumiera_global_config->TODO_unknown, &lumiera_global_config->keys); @@ -139,7 +140,7 @@ lumiera_config_destroy () lumiera_global_config = NULL; } else - WARN (configsys, "Tried to destroy non initialized config subsystem"); + WARN (config_dbg, "Tried to destroy non initialized config subsystem"); } @@ -147,7 +148,7 @@ int lumiera_config_load (const char* file) { (void) file; - TRACE (configsys); + TRACE (config_dbg); UNIMPLEMENTED(); return -1; } @@ -156,7 +157,7 @@ lumiera_config_load (const char* file) int lumiera_config_save () { - TRACE (configsys); + TRACE (config_dbg); UNIMPLEMENTED(); return -1; } @@ -166,7 +167,7 @@ int lumiera_config_purge (const char* filename) { (void) filename; - TRACE (configsys); + TRACE (config_dbg); UNIMPLEMENTED(); return -1; @@ -176,7 +177,7 @@ lumiera_config_purge (const char* filename) const char* lumiera_config_get (const char* key, const char** value) { - TRACE (configsys); + TRACE (config_dbg); REQUIRE (key); REQUIRE (value); @@ -196,7 +197,7 @@ lumiera_config_get (const char* key, const char** value) *value = getenv (env); if (*value) { - NOTICE (configsys, "envvar override for config %s = %s", env, *value); + NOTICE (config, "envvar override for config %s = %s", env, *value); } else { @@ -208,12 +209,12 @@ lumiera_config_get (const char* key, const char** value) *value = item->delim+1; } else - LUMIERA_ERROR_SET_WARNING (configsys, CONFIG_NO_ENTRY, key); + LUMIERA_ERROR_SET_WARNING (config, CONFIG_NO_ENTRY, key); } } else { - LUMIERA_ERROR_SET (configsys, CONFIG_SYNTAX_KEY, key); + LUMIERA_ERROR_SET (config, CONFIG_SYNTAX_KEY, key); } return *value; @@ -223,7 +224,7 @@ lumiera_config_get (const char* key, const char** value) const char* lumiera_config_get_default (const char* key, const char** value) { - TRACE (configsys); + TRACE (config_dbg); REQUIRE (key); REQUIRE (value); @@ -245,7 +246,7 @@ lumiera_config_get_default (const char* key, const char** value) LumieraConfigitem lumiera_config_set (const char* key, const char* delim_value) { - TRACE (configsys); + TRACE (config_dbg); LumieraConfigitem item = lumiera_config_lookup_item_find (&lumiera_global_config->keys, key); if (item && item->parent != &lumiera_global_config->defaults) @@ -287,12 +288,12 @@ lumiera_config_set (const char* key, const char* delim_value) LumieraConfigitem lumiera_config_setdefault (const char* line) { - TRACE (configsys); + TRACE (config_dbg); REQUIRE (line); LumieraConfigitem item = NULL; - LUMIERA_MUTEX_SECTION (configsys, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_global_config->lock) { const char* key = line; while (*key && isspace (*key)) @@ -308,7 +309,7 @@ lumiera_config_setdefault (const char* line) { ENSURE (item->delim, "default must be a configentry with key=value or keydelim == '=' || *item->delim == '<', "default must be a configentry with key=value or keyline); + TRACE (config_dbg, "registering default: '%s'", item->line); llist_insert_head (&lumiera_global_config->defaults.childs, &item->link); item->parent = &lumiera_global_config->defaults; @@ -345,7 +346,7 @@ int lumiera_config_reset (const char* key) { (void) key; - TRACE (configsys); + TRACE (config_dbg); UNIMPLEMENTED(); return -1; } @@ -357,7 +358,7 @@ lumiera_config_info (const char* key, const char** filename, unsigned* line) (void) key; (void) filename; (void) line; - TRACE (configsys); + TRACE (config_dbg); UNIMPLEMENTED(); return -1; } diff --git a/src/common/config.h b/src/common/config.h index 0eeca4913..7cf0ff2df 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -31,17 +31,17 @@ struct lumiera_config_struct; /* master config subsystem debug flag */ -NOBUG_DECLARE_FLAG (config_all); +//NOBUG_DECLARE_FLAG (config_all); /* config subsystem internals */ -NOBUG_DECLARE_FLAG (configsys); +//NOBUG_DECLARE_FLAG (configsys); /* high level typed interface operations */ -NOBUG_DECLARE_FLAG (config_typed); +//NOBUG_DECLARE_FLAG (config_typed); /* file operations */ -NOBUG_DECLARE_FLAG (config_file); +//NOBUG_DECLARE_FLAG (config_file); /* single config items */ -NOBUG_DECLARE_FLAG (config_item); +//NOBUG_DECLARE_FLAG (config_item); /* lookup config keys */ -NOBUG_DECLARE_FLAG (config_lookup); +//NOBUG_DECLARE_FLAG (config_lookup); LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); diff --git a/src/common/config_lookup.c b/src/common/config_lookup.c index 1c5792edf..c9be918c5 100644 --- a/src/common/config_lookup.c +++ b/src/common/config_lookup.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 "common/logging.h" #include "lib/safeclib.h" #include "common/config_lookup.h" @@ -48,7 +50,7 @@ key_fn (const PSplaynode node); LumieraConfigLookup lumiera_config_lookup_init (LumieraConfigLookup self) { - TRACE (config_lookup); + TRACE (configlookup_dbg); psplay_init (&self->tree, cmp_fn, key_fn, delete_fn); return self; } @@ -57,7 +59,7 @@ lumiera_config_lookup_init (LumieraConfigLookup self) LumieraConfigLookup lumiera_config_lookup_destroy (LumieraConfigLookup self) { - TRACE (config_lookup); + TRACE (configlookup_dbg); if (self) psplay_destroy (&self->tree); return self; @@ -67,7 +69,7 @@ lumiera_config_lookup_destroy (LumieraConfigLookup self) LumieraConfigLookupentry lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item) { - TRACE (config_lookup, "%s", item->line); + TRACE (configlookup_dbg, "%s", item->line); REQUIRE (self); REQUIRE (item); REQUIRE (item->key); @@ -88,7 +90,7 @@ lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item) LumieraConfigLookupentry lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigitem item) { - TRACE (config_lookup, "%s", item->line); + TRACE (configlookup_dbg, "%s", item->line); REQUIRE (self); REQUIRE (item); REQUIRE (item->key); @@ -108,7 +110,7 @@ lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigite LumieraConfigitem lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item) { - TRACE (config_lookup, "%s", item->line); + TRACE (configlookup_dbg, "%s", item->line); REQUIRE (!llist_is_empty (&item->lookup), "item is not in a lookup"); if (llist_is_single (&item->lookup)) @@ -131,7 +133,7 @@ lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item) LumieraConfigLookupentry lumiera_config_lookup_find (LumieraConfigLookup self, const char* key) { - TRACE (config_lookup, "%s", key); + TRACE (configlookup_dbg, "%s", key); return (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100); } @@ -139,7 +141,7 @@ lumiera_config_lookup_find (LumieraConfigLookup self, const char* key) LumieraConfigitem lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key) { - TRACE (config_lookup, "%s", key); + TRACE (configlookup_dbg, "%s", key); LumieraConfigLookupentry entry = lumiera_config_lookup_find (self, key); @@ -154,7 +156,7 @@ lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key) LumieraConfigitem lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key) { - TRACE (config_lookup, "%s", key); + TRACE (configlookup_dbg, "%s", key); LumieraConfigLookupentry entry = lumiera_config_lookup_find (self, key); @@ -174,7 +176,7 @@ lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key) LumieraConfigLookupentry lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key) { - TRACE (config_lookup, "%s", key); + TRACE (configlookup_dbg, "%s", key); if (self) { psplaynode_init (&self->node); @@ -195,7 +197,7 @@ lumiera_config_lookupentry_new (const char* key) LumieraConfigLookupentry lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self) { - TRACE (config_lookup); + TRACE (configlookup_dbg); if (self) { REQUIRE (llist_is_empty (&self->configitems), "lookup node still in use"); diff --git a/src/common/config_typed.c b/src/common/config_typed.c index aec3fce6c..59b04a674 100644 --- a/src/common/config_typed.c +++ b/src/common/config_typed.c @@ -20,6 +20,7 @@ */ //TODO: Support library includes// +#include "common/logging.h" #include "lib/safeclib.h" @@ -42,7 +43,7 @@ const char* lumiera_config_link_get (const char* key, const char** value) { (void) key; (void) value; - TRACE (config_typed); + TRACE (configtyped_dbg); UNIMPLEMENTED(); return 0; } @@ -51,7 +52,7 @@ LumieraConfigitem lumiera_config_link_set (const char* key, const char** value) { (void) key; (void) value; - TRACE (config_typed); + TRACE (configtyped_dbg); UNIMPLEMENTED(); return 0; } @@ -64,11 +65,11 @@ lumiera_config_link_set (const char* key, const char** value) const char* lumiera_config_number_get (const char* key, long long* value) { - TRACE (config_typed); + TRACE (configtyped_dbg); const char* raw_value = NULL; - LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_global_config->lock) { if (lumiera_config_get (key, &raw_value)) { @@ -77,12 +78,12 @@ lumiera_config_number_get (const char* key, long long* value) /* got it, scan it */ if (sscanf (raw_value, "%Li", value) != 1) { - LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE, lumiera_tmpbuf_snprintf (5000, "key '%s', value '%s'", key, raw_value)); + LUMIERA_ERROR_SET (config, CONFIG_SYNTAX_VALUE, lumiera_tmpbuf_snprintf (5000, "key '%s', value '%s'", key, raw_value)); raw_value = NULL; } } else - LUMIERA_ERROR_SET_WARNING (configsys, CONFIG_NO_ENTRY, key); + LUMIERA_ERROR_SET_WARNING (config, CONFIG_NO_ENTRY, key); } } @@ -92,11 +93,11 @@ lumiera_config_number_get (const char* key, long long* value) LumieraConfigitem lumiera_config_number_set (const char* key, long long* value) { - TRACE (config_typed); + TRACE (configtyped_dbg); LumieraConfigitem item = NULL; - LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_global_config->lock) { const char* fmt = "= %lld"; TODO ("use the config system (config.format*...) to deduce the desired format for this key"); item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, *value)); @@ -114,7 +115,7 @@ const char* lumiera_config_real_get (const char* key, long double* value) { (void) key; (void) value; - TRACE (config_typed); + TRACE (configtyped_dbg); UNIMPLEMENTED(); return 0; } @@ -123,7 +124,7 @@ LumieraConfigitem lumiera_config_real_set (const char* key, long double* value) { (void) key; (void) value; - TRACE (config_typed); + TRACE (configtyped_dbg); UNIMPLEMENTED(); return 0; } @@ -176,7 +177,7 @@ scan_string (const char* in) } else /* quotes doesnt match */ - LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE, "unmatched quotes"); + LUMIERA_ERROR_SET (config, CONFIG_SYNTAX_VALUE, "unmatched quotes"); } else { @@ -195,11 +196,11 @@ scan_string (const char* in) const char* lumiera_config_string_get (const char* key, const char** value) { - TRACE (config_typed); + TRACE (configtyped_dbg); const char* raw_value = *value = NULL; - LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_global_config->lock) { if (lumiera_config_get (key, &raw_value)) { @@ -208,7 +209,7 @@ lumiera_config_string_get (const char* key, const char** value) *value = scan_string (raw_value); } else - LUMIERA_ERROR_SET_WARNING (configsys, CONFIG_NO_ENTRY, key); + LUMIERA_ERROR_SET_WARNING (config, CONFIG_NO_ENTRY, key); } } @@ -218,11 +219,11 @@ lumiera_config_string_get (const char* key, const char** value) LumieraConfigitem lumiera_config_string_set (const char* key, const char** value) { - TRACE (config_typed); + TRACE (configtyped_dbg); LumieraConfigitem item = NULL; - LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_global_config->lock) { const char* fmt = "= %s"; TODO ("use the config system (config.format*...) to deduce the desired format for this key"); item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, *value)); @@ -240,11 +241,11 @@ lumiera_config_string_set (const char* key, const char** value) const char* lumiera_config_wordlist_get (const char* key, const char** value) { - TRACE (config_typed, "KEY %s", key); + TRACE (configtyped_dbg, "KEY %s", key); const char* raw_value = *value = NULL; - LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_global_config->lock) { if (lumiera_config_get (key, &raw_value)) { @@ -253,7 +254,7 @@ lumiera_config_wordlist_get (const char* key, const char** value) *value = raw_value; } else - LUMIERA_ERROR_SET_WARNING (configsys, CONFIG_NO_ENTRY, key); + LUMIERA_ERROR_SET_WARNING (config, CONFIG_NO_ENTRY, key); TODO ("remove the ERROR_SET because config_get sets it already? also in all other getters in this file"); } @@ -266,11 +267,11 @@ lumiera_config_wordlist_get (const char* key, const char** value) LumieraConfigitem lumiera_config_wordlist_set (const char* key, const char** value) { - TRACE (config_typed); + TRACE (configtyped_dbg); LumieraConfigitem item = NULL; - LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_global_config->lock) { const char* fmt = "= %s"; TODO ("use the config system (config.format*...) to deduce the desired format for this key"); item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, *value)); @@ -309,11 +310,11 @@ scan_word (const char* in) const char* lumiera_config_word_get (const char* key, const char** value) { - TRACE (config_typed, "KEY %s", key); + TRACE (configtyped_dbg, "KEY %s", key); const char* raw_value = *value = NULL; - LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_global_config->lock) { if (lumiera_config_get (key, &raw_value)) { @@ -322,7 +323,7 @@ lumiera_config_word_get (const char* key, const char** value) *value = scan_word (raw_value); } else - LUMIERA_ERROR_SET_WARNING (configsys, CONFIG_NO_ENTRY, key); + LUMIERA_ERROR_SET_WARNING (config, CONFIG_NO_ENTRY, key); } } @@ -332,11 +333,11 @@ lumiera_config_word_get (const char* key, const char** value) LumieraConfigitem lumiera_config_word_set (const char* key, const char** value) { - TRACE (config_typed); + TRACE (configtyped_dbg); LumieraConfigitem item = NULL; - LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_global_config->lock) { const char* fmt = "= %s"; TODO ("use the config system (config.format*...) to deduce the desired format for this key"); item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, scan_word (*value))); @@ -354,7 +355,7 @@ const char* lumiera_config_bool_get (const char* key, int* value) { (void) key; (void) value; - TRACE (config_typed); + TRACE (configtyped_dbg); UNIMPLEMENTED(); return 0; } @@ -364,7 +365,7 @@ LumieraConfigitem lumiera_config_bool_set (const char* key, int* value) { (void) key; (void) value; - TRACE (config_typed); + TRACE (configtyped_dbg); UNIMPLEMENTED(); return 0; } diff --git a/src/common/config_wordlist.c b/src/common/config_wordlist.c index 9b479f796..8a3c74212 100644 --- a/src/common/config_wordlist.c +++ b/src/common/config_wordlist.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/error.h" #include "lib/safeclib.h" @@ -92,7 +93,7 @@ lumiera_config_wordlist_replace (const char* key, const char* value, const char* if (!value) return NULL; - LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_global_config->lock) { if (lumiera_config_get (key, &wordlist)) { @@ -143,7 +144,7 @@ lumiera_config_wordlist_add (const char* key, const char* value, const char* del if (value && *value) { - LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_global_config->lock) { if (lumiera_config_get (key, &wordlist)) { diff --git a/src/common/configfacade.cpp b/src/common/configfacade.cpp index 27e953acf..18c95ccb0 100644 --- a/src/common/configfacade.cpp +++ b/src/common/configfacade.cpp @@ -21,7 +21,7 @@ * *****************************************************/ -#include "include/nobugcfg.h" +#include "common/logging.h" #include "include/lifecycle.h" #include "include/configfacade.hpp" @@ -54,7 +54,7 @@ namespace lumiera { void pull_up_ConfigSystem () { - TRACE (lumiera, "booting up config system"); + TRACE (common, "booting up config system"); Config::instance(); } @@ -80,7 +80,7 @@ namespace lumiera { Config::~Config() { lumiera_config_destroy(); - TRACE (lumiera, "config system closed."); + TRACE (common, "config system closed."); } diff --git a/src/common/configitem.c b/src/common/configitem.c index 82de5ae25..e6b8a7839 100644 --- a/src/common/configitem.c +++ b/src/common/configitem.c @@ -20,6 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/llist.h" #include "lib/safeclib.h" @@ -51,7 +52,7 @@ static LumieraConfigitem parse_configentry (LumieraConfigitem self, char* itr); LumieraConfigitem lumiera_configitem_init (LumieraConfigitem self) { - TRACE (config_item); + TRACE (configitem_dbg); REQUIRE (self); llist_init (&self->link); @@ -74,7 +75,7 @@ lumiera_configitem_init (LumieraConfigitem self) LumieraConfigitem lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup) { - TRACE (config_item); + TRACE (configitem_dbg); if (self) { @@ -100,7 +101,7 @@ lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup) LumieraConfigitem lumiera_configitem_new (const char* line) { - TRACE (config_item, "%s", line); + TRACE (configitem_dbg, "%s", line); lumiera_configitem tmp; lumiera_configitem_init (&tmp); @@ -118,7 +119,7 @@ lumiera_configitem_new (const char* line) void lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup) { - TRACE (config_item); + TRACE (configitem_dbg); lumiera_free (lumiera_configitem_destroy (self, lookup)); } @@ -139,7 +140,7 @@ lumiera_configitem_set_value (LumieraConfigitem self, const char* delim_value) LumieraConfigitem lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source) { - TRACE (config_item); + TRACE (configitem_dbg); REQUIRE (self); REQUIRE (source); @@ -169,7 +170,7 @@ lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source) LumieraConfigitem lumiera_configitem_parse (LumieraConfigitem self, const char* line) { - TRACE (config_item); + TRACE (configitem_dbg); lumiera_free (self->line); self->line = lumiera_strndup (line, SIZE_MAX); @@ -250,7 +251,7 @@ parse_directive (LumieraConfigitem self, char* itr) self->key = NULL; self->key_size = 0; - LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX, self->line); + LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line); } } else @@ -260,7 +261,7 @@ parse_directive (LumieraConfigitem self, char* itr) self->key = NULL; self->key_size = 0; - LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX, self->line); + LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line); } return self; } @@ -317,7 +318,7 @@ parse_section (LumieraConfigitem self, char* itr) self->key = NULL; self->key_size = 0; - LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX, self->line); + LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line); } } else @@ -329,7 +330,7 @@ parse_section (LumieraConfigitem self, char* itr) self->key = NULL; self->key_size = 0; - LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX, self->line); + LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line); } return self; @@ -368,7 +369,7 @@ parse_configentry (LumieraConfigitem self, char* itr) self->key = NULL; self->key_size = 0; - LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX, self->line); + LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line); } return self; diff --git a/src/common/configrules.cpp b/src/common/configrules.cpp index f50814fb7..85ffcf5d5 100644 --- a/src/common/configrules.cpp +++ b/src/common/configrules.cpp @@ -24,7 +24,7 @@ #include "common/configrules.hpp" #include "common/query/fake-configrules.hpp" //#include "lib/util.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index 408c7b1d0..9aa5492b8 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -94,7 +94,7 @@ namespace gui { { if (opts.isHeadless() || 0 < opts.getPort()) { - INFO (lumiera, "*not* starting the GUI..."); + INFO (guifacade, "*not* starting the GUI..."); return false; } else @@ -135,8 +135,8 @@ namespace gui { Lock guard (this); if (!facade) { - WARN (operate, "Termination signal invoked, but GUI is currently closed. " - "Probably this is due to some broken startup logic and should be fixed."); + WARN (guifacade, "Termination signal invoked, but GUI is currently closed. " + "Probably this is due to some broken startup logic and should be fixed."); } else facade.reset (0); @@ -152,12 +152,13 @@ namespace gui { ~GuiSubsysDescriptor() { + FIXME ("ichthyo: when you want to ignore errors, then you have to error_get() them to clear the error state"); if (facade) { - WARN (operate, "GUI subsystem terminates, but GuiFacade isn't properly closed. " + WARN (guifacade, "GUI subsystem terminates, but GuiFacade isn't properly closed. " "Closing it forcedly; this indicates broken startup logic and should be fixed."); try { facade.reset (0); } - catch(...) { WARN_IF (lumiera_error_peek(), operate, "Ignoring error: %s", lumiera_error()); } + catch(...) { WARN_IF (lumiera_error_peek(), guifacade, "Ignoring error: %s", lumiera_error()); } } } }; @@ -188,3 +189,11 @@ namespace gui { } // namespace gui + +/* +// Local Variables: +// mode: C++ +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp index e12b8ec2d..82bed78fe 100644 --- a/src/common/instancehandle.hpp +++ b/src/common/instancehandle.hpp @@ -41,7 +41,7 @@ #define LUMIERA_INSTANCEHANDLE_H -#include "include/nobugcfg.h" +#include "common/logging.h" #include "lib/error.hpp" #include "include/interfaceproxy.hpp" diff --git a/src/common/interface.c b/src/common/interface.c index 9b86ae4f3..b4a3cac85 100644 --- a/src/common/interface.c +++ b/src/common/interface.c @@ -19,6 +19,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" + #include "lib/mutex.h" #include "lib/safeclib.h" @@ -54,7 +56,7 @@ lumiera_interface_open (const char* interface, unsigned version, size_t minminor TRACE (interface, "%s", name); WARN_IF (version == 0, interface, "opening experimental interface: %s_%d_%s", interface, version, name); - LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex) { self = lumiera_interfaceregistry_interfacenode_find (interface, version, name); @@ -84,7 +86,7 @@ static void push_dependency (LumieraInterfacenode parent, LumieraInterfacenode child) { /* push a dependency on the dependency array, allcoate or resize it on demand */ - TRACE (interface, "%s %s", parent->interface->name, child->interface->name); + TRACE (interface_dbg, "%s %s", parent->interface->name, child->interface->name); /* no dependencies recorded yet, alloc a first block for 4 pointers */ if (!parent->deps_size) @@ -119,16 +121,16 @@ depwalk (LumieraInterfacenode self, LumieraInterfacenode* stack) /* increment refcount for all non-cyclic dependencies recursively */ if (self->deps) { - TRACE (interface, "%s %d", self->interface->name, self->refcnt); + TRACE (interface_dbg, "%s %d", self->interface->name, self->refcnt); for (LumieraInterfacenode* dep = self->deps; *dep; ++dep) { - TRACE (interface, "loop %s", (*dep)->interface->name); + TRACE (interface_dbg, "loop %s", (*dep)->interface->name); int cycle = 0; for (LumieraInterfacenode itr = *stack; itr; itr = itr->lnk) { if (itr == *dep) { - TRACE (interface, "CYCLE"); + TRACE (interface_dbg, "CYCLE"); cycle = 1; break; } @@ -165,9 +167,9 @@ lumiera_interface_open_interfacenode (LumieraInterfacenode self) if (self) { - TRACE (interface, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:""); + TRACE (interface_dbg, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:""); - LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex) { /* discover cycles, cycles don't refcount! */ int cycle = 0; @@ -176,7 +178,7 @@ lumiera_interface_open_interfacenode (LumieraInterfacenode self) { if (itr == self) { - TRACE (interface, "CYCLE"); + TRACE (interface_dbg, "CYCLE"); cycle = 1; break; } @@ -201,7 +203,7 @@ lumiera_interface_open_interfacenode (LumieraInterfacenode self) /* first opening, run acquire, recursive opening shall record its dependencies here */ if (self->interface->acquire) { - TRACE (interface, "Acquire %s", self->interface->name); + TRACE (interface_dbg, "Acquire %s", self->interface->name); collect_dependencies = self->deps?0:1; self->interface = self->interface->acquire (self->interface, lumiera_interface_interface); } @@ -227,7 +229,7 @@ lumiera_interface_open_interfacenode (LumieraInterfacenode self) void lumiera_interface_close (LumieraInterface self) { - TRACE (interface); + TRACE (interface_dbg); LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) { @@ -265,7 +267,7 @@ lumiera_interfacenode_close (LumieraInterfacenode self) { if (itr == self) { - TRACE (interface, "CYCLE"); + TRACE (interface_dbg, "CYCLE"); cycle = 1; break; } @@ -280,7 +282,7 @@ lumiera_interfacenode_close (LumieraInterfacenode self) { if (self->interface->release) { - TRACE (interface, "Release %s", self->interface->name); + TRACE (interface_dbg, "Release %s", self->interface->name); self->interface->release (self->interface); } } @@ -288,7 +290,7 @@ lumiera_interfacenode_close (LumieraInterfacenode self) { if (self->deps) { - TRACE (interface, "Recurse %s %d", self->interface->name, self->refcnt); + TRACE (interface_dbg, "Recurse %s %d", self->interface->name, self->refcnt); for (LumieraInterfacenode* dep = self->deps; *dep; ++dep) lumiera_interfacenode_close (*dep); diff --git a/src/common/interfaceregistry.c b/src/common/interfaceregistry.c index 81ad12b06..e7973b361 100644 --- a/src/common/interfaceregistry.c +++ b/src/common/interfaceregistry.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/mutex.h" #include "lib/error.h" #include "lib/psplay.h" @@ -39,10 +40,10 @@ * by their name and major version. */ -NOBUG_DEFINE_FLAG_PARENT (interface_all, lumiera_all); -NOBUG_DEFINE_FLAG_PARENT (plugin, interface_all); -NOBUG_DEFINE_FLAG_PARENT (interfaceregistry, interface_all); -NOBUG_DEFINE_FLAG_PARENT (interface, interface_all); +//NOBUG_DEFINE_FLAG_PARENT (interface_all, lumiera_all); +//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; @@ -91,12 +92,12 @@ lumiera_interfacenode_delete (LumieraInterfacenode self) void lumiera_interfaceregistry_init (void) { - NOBUG_INIT_FLAG (interface_all); - NOBUG_INIT_FLAG (interfaceregistry); - NOBUG_INIT_FLAG (interface); - NOBUG_INIT_FLAG (plugin); + //NOBUG_INIT_FLAG (interface_all); + //NOBUG_INIT_FLAG (interfaceregistry); + //NOBUG_INIT_FLAG (interface); + //NOBUG_INIT_FLAG (plugin); - TRACE (interfaceregistry); + TRACE (interfaceregistry_dbg); REQUIRE (!lumiera_interfaceregistry); REQUIRE (!lumiera_pluginregistry); @@ -117,7 +118,7 @@ lumiera_interfaceregistry_init (void) void lumiera_interfaceregistry_destroy (void) { - TRACE (interfaceregistry); + TRACE (interfaceregistry_dbg); lumiera_interface_destroy (); @@ -125,7 +126,7 @@ lumiera_interfaceregistry_destroy (void) psplay_delete (lumiera_pluginregistry); lumiera_pluginregistry = NULL; - lumiera_mutex_destroy (&lumiera_interface_mutex, &NOBUG_FLAG(interfaceregistry)); + lumiera_mutex_destroy (&lumiera_interface_mutex, &NOBUG_FLAG(mutex_dbg)); REQUIRE (!psplay_nelements (lumiera_interfaceregistry), "some interfaces still registered at shutdown"); @@ -138,10 +139,10 @@ lumiera_interfaceregistry_destroy (void) void lumiera_interfaceregistry_register_interface (LumieraInterface self, LumieraPlugin plugin) { - TRACE (interfaceregistry); + TRACE (interfaceregistry_dbg); REQUIRE (self); - LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + LUMIERA_RECMUTEX_SECTION (mutex_sync, &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, plugin)->node, 100); @@ -152,10 +153,10 @@ lumiera_interfaceregistry_register_interface (LumieraInterface self, LumieraPlug void lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self, LumieraPlugin plugin) { - TRACE (interfaceregistry); + TRACE (interfaceregistry_dbg); REQUIRE (self); - LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex) { while (*self) { @@ -170,11 +171,12 @@ lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self, Lumie void lumiera_interfaceregistry_remove_interface (LumieraInterface self) { - TRACE (interfaceregistry); + TRACE (interfaceregistry_dbg); REQUIRE (self); - LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex) { + TRACE (interfaceregistry, "interface %s, version %d, instance %s", self->interface, self->version, self->name); LumieraInterfacenode node = (LumieraInterfacenode) psplay_find (lumiera_interfaceregistry, self, 0); REQUIRE (node->refcnt == 0, "but is %d", node->refcnt); @@ -186,10 +188,10 @@ lumiera_interfaceregistry_remove_interface (LumieraInterface self) void lumiera_interfaceregistry_bulkremove_interfaces (LumieraInterface* self) { - TRACE (interfaceregistry); + TRACE (interfaceregistry_dbg); REQUIRE (self); - LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex) { while (*self) { @@ -209,7 +211,7 @@ lumiera_interfaceregistry_bulkremove_interfaces (LumieraInterface* self) LumieraInterfacenode lumiera_interfaceregistry_interfacenode_find (const char* interface, unsigned version, const char* name) { - TRACE (interfaceregistry); + TRACE (interfaceregistry_dbg); struct lumiera_interface_struct cmp; cmp.interface = interface; cmp.version = version; @@ -217,7 +219,7 @@ lumiera_interfaceregistry_interfacenode_find (const char* interface, unsigned ve LumieraInterfacenode ret = NULL; - LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex) { ret = (LumieraInterfacenode)psplay_find (lumiera_interfaceregistry, &cmp, 100); } diff --git a/src/common/interfaceregistry.h b/src/common/interfaceregistry.h index 41ba6cecd..8adc46313 100644 --- a/src/common/interfaceregistry.h +++ b/src/common/interfaceregistry.h @@ -37,9 +37,9 @@ * by their name and major version. */ -NOBUG_DECLARE_FLAG (interface_all); -NOBUG_DECLARE_FLAG (interfaceregistry); -NOBUG_DECLARE_FLAG (interface); +//NOBUG_DECLARE_FLAG (interface_all); +//NOBUG_DECLARE_FLAG (interfaceregistry); +//NOBUG_DECLARE_FLAG (interface); extern PSplay lumiera_interfaceregistry; extern lumiera_mutex lumiera_interface_mutex; diff --git a/src/common/logging.cpp b/src/common/logging.cpp index b2a62dfce..07a53eab3 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -22,7 +22,7 @@ */ #define LUMIERA_LOGGING_CXX -#include "include/logging.h" +#include "common/logging.h" /* // Local Variables: diff --git a/src/common/plugin.c b/src/common/plugin.c index ae71ea8b3..12641437c 100644 --- a/src/common/plugin.c +++ b/src/common/plugin.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - +#include "common/logging.h" #include "lib/safeclib.h" #include "lib/psplay.h" #include "lib/mutex.h" @@ -193,7 +193,7 @@ int lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), int (*callback_register) (LumieraPlugin)) { - TRACE (plugin); + TRACE (pluginloader_dbg); REQUIRE (callback_load); REQUIRE (callback_register); @@ -212,7 +212,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); - TRACE (plugin, "globbing path '%s'", path); + TRACE (pluginloader_dbg, "globbing path '%s'", path); int ret = glob (path, flags, NULL, &globs); if (ret == GLOB_NOSPACE) LUMIERA_DIE (NO_MEMORY); @@ -222,13 +222,13 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), } if (globs.gl_pathc) - LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) + LUMIERA_RECMUTEX_SECTION (mutex_sync, &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); + TRACE (pluginloader, "found new plugin '%s'", *itr); callback_register (callback_load (*itr)); } } @@ -243,7 +243,7 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin), LumieraPlugin lumiera_plugin_load (const char* plugin) { - TRACE (plugin); + TRACE (pluginloader_dbg); /* dispatch on ext, call the registered function */ const char* ext = strrchr (plugin, '.'); @@ -262,11 +262,11 @@ lumiera_plugin_load (const char* plugin) int lumiera_plugin_register (LumieraPlugin plugin) { - TRACE (plugin); + TRACE (pluginloader_dbg); if (!plugin) return 1; - LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) + LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex) { if (psplay_insert (lumiera_pluginregistry, &plugin->node, 100)) { @@ -276,20 +276,20 @@ lumiera_plugin_register (LumieraPlugin plugin) { case 0: { - TRACE (plugin, "registering %s", plugin->name); + TRACE (pluginloader, "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, plugin->name); + LUMIERA_ERROR_SET (pluginloader, PLUGIN_VERSION, plugin->name); } } } else { - LUMIERA_ERROR_SET_CRITICAL (plugin, PLUGIN_REGISTER, plugin->name); + LUMIERA_ERROR_SET_CRITICAL (pluginloader, PLUGIN_REGISTER, plugin->name); } } return !!lumiera_error_peek(); @@ -299,7 +299,7 @@ lumiera_plugin_register (LumieraPlugin plugin) unsigned lumiera_plugin_unload (LumieraPlugin self) { - TRACE (plugin); + TRACE (pluginloader_dbg); if (!self) return 0; @@ -315,7 +315,7 @@ lumiera_plugin_unload (LumieraPlugin self) { if (!strcmp (itr->ext, ext)) { - LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) + LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex) { if (psplay_remove (lumiera_pluginregistry, &self->node)) { @@ -343,7 +343,7 @@ lumiera_plugin_lookup (const char* name) LumieraPlugin ret = NULL; if (name) - LUMIERA_RECMUTEX_SECTION (plugin, &lumiera_interface_mutex) + LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex) ret = (LumieraPlugin) psplay_find (lumiera_pluginregistry, name, 100); return ret; @@ -374,7 +374,7 @@ static char* init_exts_globs () ++itr; } exts_globs[exts_sz-2] = '}'; - TRACE (plugin, "initialized extension glob to '%s'", exts_globs); + TRACE (pluginloader_dbg, "initialized extension glob to '%s'", exts_globs); return exts_globs; } diff --git a/src/common/plugin.h b/src/common/plugin.h index c05cfe1bd..df75cd012 100644 --- a/src/common/plugin.h +++ b/src/common/plugin.h @@ -64,7 +64,7 @@ LUMIERA_ERROR_DECLARE(PLUGIN_REGISTER); LUMIERA_ERROR_DECLARE(PLUGIN_VERSION); -NOBUG_DECLARE_FLAG (plugin); +//NOBUG_DECLARE_FLAG (plugin); /* tool macros*/ diff --git a/src/common/plugin_dynlib.c b/src/common/plugin_dynlib.c index 920d1f385..be2c93c6d 100644 --- a/src/common/plugin_dynlib.c +++ b/src/common/plugin_dynlib.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 "common/logging.h" #include "lib/safeclib.h" #include "common/plugin.h" @@ -32,7 +34,7 @@ LumieraPlugin lumiera_plugin_load_DYNLIB (const char* name) { - TRACE (plugin); + TRACE (pluginloader_dbg); REQUIRE (name); LumieraPlugin self = lumiera_plugin_new (name); LumieraInterface plugin = NULL; @@ -43,10 +45,10 @@ lumiera_plugin_load_DYNLIB (const char* name) plugin = (LumieraInterface) dlsym (handle, LUMIERA_INTERFACE_DSTRING (lumieraorg__plugin, 0, lumieraorg_plugin)); if (!plugin) - LUMIERA_ERROR_SET (plugin, PLUGIN_WTF, name); + LUMIERA_ERROR_SET (pluginloader, PLUGIN_WTF, name); } else - LUMIERA_ERROR_SET (plugin, PLUGIN_OPEN, lumiera_tmpbuf_snprintf (4096, "%s: %s", name, dlerror())); + LUMIERA_ERROR_SET (pluginloader_dbg, PLUGIN_OPEN, lumiera_tmpbuf_snprintf (4096, "%s: %s", name, dlerror())); return lumiera_plugin_init (self, handle, plugin); } @@ -55,7 +57,7 @@ lumiera_plugin_load_DYNLIB (const char* name) void lumiera_plugin_unload_DYNLIB (LumieraPlugin self) { - TRACE (plugin); + TRACE (pluginloader_dbg); void* handle = lumiera_plugin_handle (self); if (handle) dlclose (handle); diff --git a/src/common/query/fake-configrules.cpp b/src/common/query/fake-configrules.cpp index 3e53855ac..3a3eb1d66 100644 --- a/src/common/query/fake-configrules.cpp +++ b/src/common/query/fake-configrules.cpp @@ -28,7 +28,7 @@ #include "proc/asset/pipe.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" #include "lib/util.hpp" using util::isnil; diff --git a/src/common/subsystem-runner.hpp b/src/common/subsystem-runner.hpp index d2476a77e..d8fa5bb6d 100644 --- a/src/common/subsystem-runner.hpp +++ b/src/common/subsystem-runner.hpp @@ -153,10 +153,10 @@ namespace lumiera { void triggerStartup (Subsys* susy) { - ASSERT (susy); + REQUIRE (susy); if (susy->isRunning()) return; - INFO (operate, "Triggering startup of subsystem \"%s\"", cStr(*susy)); + INFO (subsystem, "Triggering startup of subsystem \"%s\"", cStr(*susy)); for_each (susy->getPrerequisites(), start_); bool started = susy->start (opts_, bind (&SubsystemRunner::sigTerm, this, susy, _1)); @@ -178,13 +178,13 @@ namespace lumiera { void sigTerm (Subsys* susy, string* problem) ///< called from subsystem on termination { - ASSERT (susy); + REQUIRE (susy); Lock sync (this); triggerEmergency(!isnil (problem)); - INFO (operate, "Subsystem '%s' terminated.", cStr(*susy)); - WARN_IF (!isnil(problem), operate, "Irregular shutdown caused by: %s", cStr(*problem)); - ERROR_IF (susy->isRunning(), lumiera, "Subsystem '%s' signals termination, " - "without resetting running state", cStr(*susy)); + INFO (subsystem, "Subsystem '%s' terminated.", cStr(*susy)); + WARN_IF (!isnil(problem), subsystem, "Irregular shutdown caused by: %s", cStr(*problem)); + ERROR_IF (susy->isRunning(), subsystem, "Subsystem '%s' signals termination, " + "without resetting running state", cStr(*susy)); removeall (running_, susy); shutdownAll(); sync.notify(); From 9aefc2e9712598f9b399efbe4353676283dcebb8 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 24 Jan 2009 03:13:54 +0100 Subject: [PATCH 087/216] WIP: deploy new logging flags in gui --- src/gui/dialogs/render.cpp | 1 + src/gui/gtk-lumiera.hpp | 2 +- src/gui/guistart.cpp | 2 +- src/gui/model/sequence.cpp | 1 + src/gui/notification-service.cpp | 8 ++++---- src/gui/output/xvdisplayer.cpp | 7 ++++--- src/gui/widgets/timeline/timeline-body.cpp | 1 + src/gui/widgets/timeline/timeline-track.cpp | 4 +++- src/gui/window-manager.cpp | 4 +++- src/gui/workspace/workspace-window.cpp | 3 ++- 10 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/gui/dialogs/render.cpp b/src/gui/dialogs/render.cpp index 91bdbaf67..7e4b40378 100644 --- a/src/gui/dialogs/render.cpp +++ b/src/gui/dialogs/render.cpp @@ -24,6 +24,7 @@ #include "render.hpp" #include "dialog.hpp" +#include "common/logging.h" using namespace Gtk; diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index 956223de9..9536f348b 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -43,7 +43,7 @@ extern "C" { #include } -NOBUG_DECLARE_FLAG(gui); +//NOBUG_DECLARE_FLAG(gui); #ifdef ENABLE_NLS # include diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index e0e3b2930..fe26d92d5 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -48,7 +48,7 @@ #include // need to include this to prevent errors when libintl.h defines textdomain (because gtk-lumiera removes the def when ENABLE_NLS isn't defined) #include "gui/gtk-lumiera.hpp" // need to include this before nobugcfg.h, because types.h from GTK tries to shaddow the ERROR macro from windows, which kills nobug's ERROR macro -#include "include/nobugcfg.h" +// TODO not needed? #include "common/logging.h" #include "lib/error.hpp" #include "gui/guifacade.hpp" #include "gui/notification-service.hpp" diff --git a/src/gui/model/sequence.cpp b/src/gui/model/sequence.cpp index e6f90207a..a6bab6178 100644 --- a/src/gui/model/sequence.cpp +++ b/src/gui/model/sequence.cpp @@ -21,6 +21,7 @@ * *****************************************************/ #include "sequence.hpp" +#include "common/logging.h" // TEST CODE #include "group-track.hpp" diff --git a/src/gui/notification-service.cpp b/src/gui/notification-service.cpp index f713d7390..ebca1bc7c 100644 --- a/src/gui/notification-service.cpp +++ b/src/gui/notification-service.cpp @@ -23,7 +23,7 @@ #include "gui/notification-service.hpp" #include "lib/singleton.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" #include "lib/util.hpp" extern "C" { @@ -44,7 +44,7 @@ namespace gui { void NotificationService::displayInfo (string const& text) { - INFO (operate, "@GUI: display '%s' as notification message.", cStr(text)); + INFO (gui, "@GUI: display '%s' as notification message.", cStr(text)); ////////////////////////TODO actually push the information to the GUI } @@ -52,7 +52,7 @@ namespace gui { void NotificationService::triggerGuiShutdown (string const& cause) { - NOTICE (operate, "@GUI: shutdown triggered with explanation '%s'....", cStr(cause)); + NOTICE (gui, "@GUI: shutdown triggered with explanation '%s'....", cStr(cause)); TODO ("actually request a shutdown from the GUI"); } @@ -173,7 +173,7 @@ namespace gui { : implInstance_(this,_instance), serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_GuiNotification, 1,lumieraorg_GuiNotificationFacade)) { - INFO (operate, "GuiNotification Facade opened."); + INFO (gui, "GuiNotification Facade opened."); } diff --git a/src/gui/output/xvdisplayer.cpp b/src/gui/output/xvdisplayer.cpp index ade6973e5..82f6c9115 100644 --- a/src/gui/output/xvdisplayer.cpp +++ b/src/gui/output/xvdisplayer.cpp @@ -27,6 +27,7 @@ #include #include "xvdisplayer.hpp" +#include "common/logging.h" namespace gui { namespace output { @@ -126,13 +127,13 @@ XvDisplayer::XvDisplayer( Gtk::Widget *drawing_area, int width, int height ) : { Atom val_atom = XInternAtom( display, xvattr[k].name, False ); if ( XvSetPortAttribute( display, grabbedPort, val_atom, 1 ) != Success ) - ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); + NOBUG_ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); } else if ( strcmp( xvattr[k].name, "XV_COLORKEY") == 0 ) { Atom val_atom = XInternAtom( display, xvattr[k].name, False ); if ( XvSetPortAttribute( display, grabbedPort, val_atom, 0x010102 ) != Success ) - ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); + NOBUG_ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); } } } @@ -173,7 +174,7 @@ XvDisplayer::XvDisplayer( Gtk::Widget *drawing_area, int width, int height ) : XvDisplayer::~XvDisplayer() { - ERROR(gui, "Destroying XV Displayer"); + NOBUG_ERROR(gui, "Destroying XV Displayer"); if ( gotPort ) { diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index e755ddaad..bd3a3451f 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -29,6 +29,7 @@ #include "timeline-arrow-tool.hpp" #include "timeline-ibeam-tool.hpp" +#include "common/logging.h" using namespace Gtk; using namespace std; diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp index 717a106dd..5222e64c6 100644 --- a/src/gui/widgets/timeline/timeline-track.cpp +++ b/src/gui/widgets/timeline/timeline-track.cpp @@ -27,6 +27,7 @@ #include "../timeline-widget.hpp" #include "../../window-manager.hpp" #include "../../dialogs/name-chooser.hpp" +#include "common/logging.h" using namespace boost; using namespace Gtk; @@ -209,7 +210,8 @@ Track::get_expander_style() const return EXPANDER_SEMI_COLLAPSED; } - ERROR(gui, "Track::get_expander_style() final return reached"); + NOBUG_ERROR(gui, "Track::get_expander_style() final return reached"); + return EXPANDER_COLLAPSED; // This should never happen } diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index 88de4db56..c25992695 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -21,6 +21,7 @@ * *****************************************************/ #include "window-manager.hpp" +#include "common/logging.h" using namespace Gtk; using namespace Glib; @@ -41,7 +42,8 @@ WindowManager::set_theme(Glib::ustring path) { if(access(path.c_str(), R_OK)) { - ERROR(gui, "WindowManger: Unable to load rc file \"%s\"", + // gdk defines 'ERROR' need to prefix it with 'NOBUG_' here + NOBUG_ERROR(gui, "WindowManger: Unable to load rc file \"%s\"", path.c_str()); return false; } diff --git a/src/gui/workspace/workspace-window.cpp b/src/gui/workspace/workspace-window.cpp index abcce5601..f41033421 100644 --- a/src/gui/workspace/workspace-window.cpp +++ b/src/gui/workspace/workspace-window.cpp @@ -34,6 +34,7 @@ #include "../gtk-lumiera.hpp" #include "workspace-window.hpp" +#include "common/logging.h" using namespace Gtk; using namespace gui::model; @@ -142,7 +143,7 @@ WorkspaceWindow::create_ui() } catch(const Glib::Error& ex) { - ERROR(gui, "Building menus failed: %s", ex.what().data()); + NOBUG_ERROR(gui, "Building menus failed: %s", ex.what().data()); return; } From b9fc2d6522f90c15e339abd4704fd5b1aa0666c2 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 24 Jan 2009 03:15:02 +0100 Subject: [PATCH 088/216] WIP: deploy new logging flags in lib --- src/lib/allocationcluster.cpp | 12 ++++++++-- src/lib/cmdline.cpp | 2 +- src/lib/error.hpp | 5 +++-- src/lib/psplay.c | 41 ++++++++++++++++++----------------- src/lib/query.cpp | 2 +- src/lib/resourcecollector.c | 31 +++++++++++++------------- src/lib/resourcecollector.h | 2 +- src/lib/singletonfactory.hpp | 17 ++++++++++++--- src/lib/sync-classlock.hpp | 2 +- src/lib/sync.hpp | 2 +- src/lib/test/run.hpp | 2 +- src/lib/test/suite.cpp | 2 +- 12 files changed, 71 insertions(+), 49 deletions(-) diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp index 1e210d80d..8dcd5da6e 100644 --- a/src/lib/allocationcluster.cpp +++ b/src/lib/allocationcluster.cpp @@ -189,11 +189,11 @@ namespace lib { } catch (lumiera::Error & ex) { - WARN (operate, "Exception while closing AllocationCluster: %s",ex.what()); + WARN (progress, "Exception while closing AllocationCluster: %s", ex.what()); } catch (...) { - ERROR (NOBUG_ON, "Unexpected fatal Exception while closing AllocationCluster."); + ALERT (progress, "Unexpected fatal Exception while closing AllocationCluster."); lumiera::error::lumiera_unexpectedException(); // terminate } } @@ -243,3 +243,11 @@ namespace lib { } // namespace lib + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/cmdline.cpp b/src/lib/cmdline.cpp index e7474a021..aed6aae40 100644 --- a/src/lib/cmdline.cpp +++ b/src/lib/cmdline.cpp @@ -24,7 +24,7 @@ #include "lib/cmdline.hpp" #include "lib/util.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" #include #include diff --git a/src/lib/error.hpp b/src/lib/error.hpp index 50d43187d..d2e2537ef 100644 --- a/src/lib/error.hpp +++ b/src/lib/error.hpp @@ -25,7 +25,7 @@ #define LUMIERA_ERROR_HPP_ #include -#include "include/nobugcfg.h" +#include "common/logging.h" #include "include/lifecycle.h" #include "lib/error.h" @@ -165,6 +165,7 @@ namespace lumiera { * if NoBug is used, redefine some macros * to rather throw Lumiera Errors instead of aborting */ +#if 0 /*This will not work, nobug aborts are hard and may hold some locks, we discussed that before -- cehteh */ #ifdef NOBUG_ABORT #undef NOBUG_ABORT #define LUMIERA_NOBUG_LOCATION \ @@ -172,6 +173,6 @@ namespace lumiera { #define NOBUG_ABORT \ lumiera::error::assertion_terminate (LUMIERA_NOBUG_LOCATION); #endif - +#endif #endif // LUMIERA_ERROR_HPP_ diff --git a/src/lib/psplay.c b/src/lib/psplay.c index 2fc38e75c..dcb10a24f 100644 --- a/src/lib/psplay.c +++ b/src/lib/psplay.c @@ -21,6 +21,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/psplay.h" #include @@ -28,7 +29,7 @@ #include #include -NOBUG_DEFINE_FLAG (psplay); +//NOBUG_DEFINE_FLAG (psplay); #ifndef PSPLAY_TRAIL_DEPTH #define PSPLAY_TRAIL_DEPTH 128 @@ -68,8 +69,8 @@ static inline uint32_t psplay_fast_prng () PSplay psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn del) { - NOBUG_INIT_FLAG (psplay); - TRACE (psplay); + //NOBUG_INIT_FLAG (psplay); + TRACE (psplay_dbg); REQUIRE (cmp); REQUIRE (key); @@ -103,7 +104,7 @@ psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn del) PSplay psplay_destroy (PSplay self) { - TRACE (psplay); + TRACE (psplay_dbg); if (self) while (self->tree) { PSplaynode n = psplay_remove (self, self->tree); @@ -159,7 +160,7 @@ trailidx (unsigned n) static inline void psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor) { - TRACE (psplay, "%p %u", self, splayfactor); + TRACE (psplay_dbg, "%p %u", self, splayfactor); if (trail->dir < 0) trail->dir = - trail->dir; @@ -170,17 +171,17 @@ psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor) PSplaynode grandparent = *trail->trail [trailidx (depth-2)]; unsigned r = PSPLAY_FORMULA; - TRACE (psplay, "r is %u", r); + TRACE (psplay_dbg, "r is %u", r); if (parent == grandparent->left) { - TRACE (psplay, "ZIG.."); + TRACE (psplay_dbg, "ZIG.."); if (node == parent->left) { - TRACE (psplay, "..ZIG"); + TRACE (psplay_dbg, "..ZIG"); if (r < PSPLAY_PROB_ZIGZIG) { - TRACE (psplay, "BREAK"); + TRACE (psplay_dbg, "BREAK"); return; } @@ -192,10 +193,10 @@ psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor) } else { - TRACE (psplay, "..ZAG"); + TRACE (psplay_dbg, "..ZAG"); if (r < PSPLAY_PROB_ZIGZAG) { - TRACE (psplay, "BREAK"); + TRACE (psplay_dbg, "BREAK"); return; } @@ -208,13 +209,13 @@ psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor) } else { - TRACE (psplay, "ZAG.."); + TRACE (psplay_dbg, "ZAG.."); if (node == parent->left) { - TRACE (psplay, "..ZIG"); + TRACE (psplay_dbg, "..ZIG"); if (r < PSPLAY_PROB_ZIGZAG) { - TRACE (psplay, "BREAK"); + TRACE (psplay_dbg, "BREAK"); return; } @@ -226,10 +227,10 @@ psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor) } else { - TRACE (psplay, "..ZAG"); + TRACE (psplay_dbg, "..ZAG"); if (r < PSPLAY_PROB_ZIGZIG) { - TRACE (psplay, "BREAK"); + TRACE (psplay_dbg, "BREAK"); return; } @@ -248,7 +249,7 @@ psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor) PSplaynode psplay_insert (PSplay self, PSplaynode node, int splayfactor) { - TRACE (psplay); + TRACE (psplay_dbg); PSplaynode n = self->tree; struct psplaytrail trail; @@ -301,7 +302,7 @@ psplay_insert (PSplay self, PSplaynode node, int splayfactor) PSplaynode psplay_find (PSplay self, const void* key, int splayfactor) { - TRACE (psplay); + TRACE (psplay_dbg); PSplaynode node = self->tree; struct psplaytrail trail; trail.dir = 0; @@ -341,7 +342,7 @@ psplay_find (PSplay self, const void* key, int splayfactor) PSplaynode psplay_remove (PSplay self, PSplaynode node) { - TRACE (psplay); + TRACE (psplay_dbg); if (!node) return NULL; PSplaynode* r = self->found_parent; @@ -350,7 +351,7 @@ psplay_remove (PSplay self, PSplaynode node) { if (!psplay_find (self, self->key (node), 0)) { - WARN (psplay, "node %p is not in splay tree %p", node, self); + WARN (psplay_dbg, "node %p is not in splay tree %p", node, self); return NULL; } r = self->found_parent; diff --git a/src/lib/query.cpp b/src/lib/query.cpp index 5dcc8e4ab..41df0fc53 100644 --- a/src/lib/query.cpp +++ b/src/lib/query.cpp @@ -23,7 +23,7 @@ #include "lib/query.hpp" #include "lib/util.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" #include #include diff --git a/src/lib/resourcecollector.c b/src/lib/resourcecollector.c index e8ba7cb6c..e1c21b83c 100644 --- a/src/lib/resourcecollector.c +++ b/src/lib/resourcecollector.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "common/logging.h" #include "lib/llist.h" #include "lib/mutex.h" #include "lib/safeclib.h" @@ -27,7 +28,7 @@ #include -NOBUG_DEFINE_FLAG (resourcecollector); /* TODO: make this a hierachy, derrive from PARENT (library) ? */ +//NOBUG_DEFINE_FLAG (resourcecollector); /* TODO: make this a hierachy, derrive from PARENT (library) ? */ llist lumiera_resourcecollector_registry[LUMIERA_RESOURCE_END]; lumiera_mutex lumiera_resourcecollector_lock; @@ -44,13 +45,13 @@ struct lumiera_resourcehandler_struct static void lumiera_resourcecollector_init_ (void) { - NOBUG_INIT_FLAG (resourcecollector); - TRACE (resourcecollector); + //NOBUG_INIT_FLAG (resourcecollector); + TRACE (resourcecollector_dbg); for (int i = 0; i < LUMIERA_RESOURCE_END; ++i) llist_init (&lumiera_resourcecollector_registry[i]); - lumiera_mutex_init (&lumiera_resourcecollector_lock, "resourcecollector", &NOBUG_FLAG(resourcecollector)); + lumiera_mutex_init (&lumiera_resourcecollector_lock, "resourcecollector", &NOBUG_FLAG(mutex_dbg)); } @@ -58,25 +59,25 @@ lumiera_resourcecollector_init_ (void) void lumiera_resourcecollector_destroy (void) { - TRACE (resourcecollector); + TRACE (resourcecollector_dbg); for (int i = 0; i < LUMIERA_RESOURCE_END; ++i) LLIST_WHILE_HEAD (&lumiera_resourcecollector_registry[i], head) lumiera_resourcehandler_unregister ((LumieraResourcehandler)head); - lumiera_mutex_destroy (&lumiera_resourcecollector_lock, &NOBUG_FLAG(resourcecollector)); + lumiera_mutex_destroy (&lumiera_resourcecollector_lock, &NOBUG_FLAG(mutex_dbg)); } int lumiera_resourcecollector_run (enum lumiera_resource which, enum lumiera_resource_try* iteration, void* context) { - TRACE (resourcecollector); + TRACE (resourcecollector_dbg); if (lumiera_resourcecollector_once == PTHREAD_ONCE_INIT) pthread_once (&lumiera_resourcecollector_once, lumiera_resourcecollector_init_); - LUMIERA_MUTEX_SECTION (resourcecollector, &lumiera_resourcecollector_lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_resourcecollector_lock) { for (enum lumiera_resource_try progress = LUMIERA_RESOURCE_NONE; progress < *iteration; ++*iteration) { @@ -99,7 +100,7 @@ lumiera_resourcecollector_run (enum lumiera_resource which, enum lumiera_resourc } else { - ERROR (resourcecollector, "PANIC, Not enough resources %d", which); + ALERT (resourcecollector, "PANIC, Not enough resources %d", which); for (int i = 0; i < LUMIERA_RESOURCE_END; ++i) LLIST_FOREACH (&lumiera_resourcecollector_registry[i], node) { @@ -122,7 +123,7 @@ lumiera_resourcecollector_register_handler (enum lumiera_resource resource, lumi if (lumiera_resourcecollector_once == PTHREAD_ONCE_INIT) pthread_once (&lumiera_resourcecollector_once, lumiera_resourcecollector_init_); - TRACE (resourcecollector); + TRACE (resourcecollector_dbg); LumieraResourcehandler self = lumiera_malloc (sizeof (*self)); @@ -130,7 +131,7 @@ lumiera_resourcecollector_register_handler (enum lumiera_resource resource, lumi self->handler = handler; self->data = data; - LUMIERA_MUTEX_SECTION (resourcecollector, &lumiera_resourcecollector_lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_resourcecollector_lock) { llist_insert_tail (&lumiera_resourcecollector_registry[resource], &self->node); } @@ -142,11 +143,11 @@ lumiera_resourcecollector_register_handler (enum lumiera_resource resource, lumi void lumiera_resourcehandler_unregister (LumieraResourcehandler self) { - TRACE (resourcecollector); + TRACE (resourcecollector_dbg); if (self) { - LUMIERA_MUTEX_SECTION (resourcecollector, &lumiera_resourcecollector_lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_resourcecollector_lock) { llist_unlink (&self->node); self->handler (LUMIERA_RESOURCE_UNREGISTER, self->data, NULL); @@ -160,10 +161,10 @@ lumiera_resourcehandler_unregister (LumieraResourcehandler self) LumieraResourcehandler lumiera_resourcecollector_handler_find (enum lumiera_resource resource, lumiera_resource_handler_fn handler, void* data) { - TRACE (resourcecollector); + TRACE (resourcecollector_dbg); LumieraResourcehandler self = NULL; - LUMIERA_MUTEX_SECTION (resourcecollector, &lumiera_resourcecollector_lock) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_resourcecollector_lock) { LLIST_FOREACH (&lumiera_resourcecollector_registry[resource], node) { diff --git a/src/lib/resourcecollector.h b/src/lib/resourcecollector.h index 863eec600..e7addae49 100644 --- a/src/lib/resourcecollector.h +++ b/src/lib/resourcecollector.h @@ -23,7 +23,7 @@ #include -NOBUG_DECLARE_FLAG (resourcecollector); +//NOBUG_DECLARE_FLAG (resourcecollector); /** * Resources known to the resource collector diff --git a/src/lib/singletonfactory.hpp b/src/lib/singletonfactory.hpp index 151af7855..31725dedf 100644 --- a/src/lib/singletonfactory.hpp +++ b/src/lib/singletonfactory.hpp @@ -37,12 +37,10 @@ This code is heavily inspired by #include "lib/singletonpolicies.hpp" // several Policies usable together with SingletonFactory -#include "include/nobugcfg.h" +#include "common/logging.h" #include "lib/util.hpp" #include "lib/sync-classlock.hpp" - - namespace lumiera { /** @@ -72,6 +70,7 @@ namespace lumiera { static PType pInstance_; static bool isDead_; + public: /** Interface to be used by SingletonFactory's clients. @@ -83,7 +82,12 @@ namespace lumiera { { if (!pInstance_) { + NOBUG_INIT; + FIXME ("NoBug wasnt even basically initialized here, the old ON_BASIC_INIT did not initialize it in proper order" + " so I explicitly init it here (calling init multiple times does not harm) --cehteh" + " nb maybe as exception we can use an explicit mutex here since pthread mutexes can be statically initialized"); ThreadLock guard SIDEEFFECT; + if (!pInstance_) { if (isDead_) @@ -144,3 +148,10 @@ namespace lumiera { } // namespace lumiera #endif +/* +// Local Variables: +// mode: C++ +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/sync-classlock.hpp b/src/lib/sync-classlock.hpp index f4fe93dda..6a060eb1f 100644 --- a/src/lib/sync-classlock.hpp +++ b/src/lib/sync-classlock.hpp @@ -115,7 +115,7 @@ namespace lib { } public: - ClassLock() : Lock (getPerClassMonitor()) {} + ClassLock(...) : Lock (getPerClassMonitor()) {} uint use_count() { return nifty::Holder::accessed_; } }; diff --git a/src/lib/sync.hpp b/src/lib/sync.hpp index ef08e7f83..63212bfa5 100644 --- a/src/lib/sync.hpp +++ b/src/lib/sync.hpp @@ -67,7 +67,7 @@ #ifndef LIB_SYNC_H #define LIB_SYNC_H -#include "include/nobugcfg.h" +#include "common/logging.h" #include "lib/error.hpp" #include "lib/util.hpp" diff --git a/src/lib/test/run.hpp b/src/lib/test/run.hpp index c79753dad..9f6f2f415 100644 --- a/src/lib/test/run.hpp +++ b/src/lib/test/run.hpp @@ -28,7 +28,7 @@ #include "pre.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" #include "lib/test/suite.hpp" #include "lib/util.hpp" diff --git a/src/lib/test/suite.cpp b/src/lib/test/suite.cpp index 3c318cfc4..a4df524b6 100644 --- a/src/lib/test/suite.cpp +++ b/src/lib/test/suite.cpp @@ -30,7 +30,7 @@ #include #include -#include "include/nobugcfg.h" +#include "common/logging.h" #include "lib/cmdline.hpp" #include "lib/test/suite.hpp" #include "lib/test/run.hpp" From 288df8eb35033633f223c374fb2b7e88cabb9601 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 24 Jan 2009 03:15:26 +0100 Subject: [PATCH 089/216] WIP: deploy new logging flags in lumiera --- src/lumiera/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lumiera/main.cpp b/src/lumiera/main.cpp index 9d0317102..9d143d419 100644 --- a/src/lumiera/main.cpp +++ b/src/lumiera/main.cpp @@ -22,7 +22,7 @@ */ -#include "include/nobugcfg.h" +#include "common/logging.h" #include "lib/error.hpp" #include "common/appstate.hpp" #include "common/option.hpp" @@ -52,7 +52,7 @@ namespace { int main (int argc, const char* argv[]) { - NOTICE (lumiera, "*** Lumiera NLE for Linux ***"); + NOTICE (main, "*** Lumiera NLE for Linux ***"); AppState& application = AppState::instance(); try From 62d24569b37bf7dafbae4563aacac6bd6b840211 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 24 Jan 2009 03:16:14 +0100 Subject: [PATCH 090/216] WIP: deploy new logging flags in proc --- src/proc/asset.hpp | 11 +++++++++-- src/proc/asset/category.cpp | 2 +- src/proc/asset/db.hpp | 4 ++-- src/proc/asset/media.cpp | 2 +- src/proc/asset/meta.cpp | 2 +- src/proc/asset/proc.cpp | 2 +- src/proc/asset/struct.cpp | 2 +- src/proc/common.hpp | 2 +- src/proc/mobject/builder/common.hpp | 12 ++++++++++-- src/proc/mobject/mobject.hpp | 9 ++++++++- src/proc/mobject/session/fixture.cpp | 10 +++++++++- src/proc/mobject/session/sessmanagerimpl.cpp | 2 +- 12 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index 0786f84db..785c4948e 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -56,7 +56,7 @@ #include "proc/asset/category.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" #include "lib/error.hpp" #include "lib/p.hpp" @@ -84,7 +84,7 @@ namespace asset { using lumiera::P; - NOBUG_DECLARE_FLAG (assetmem); + //NOBUG_DECLARE_FLAG (assetmem); /** @@ -360,3 +360,10 @@ namespace proc_interface } #endif +/* +// Local Variables: +// mode: C++ +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/proc/asset/category.cpp b/src/proc/asset/category.cpp index 151e64268..622ae8205 100644 --- a/src/proc/asset/category.cpp +++ b/src/proc/asset/category.cpp @@ -23,7 +23,7 @@ #include "proc/asset/category.hpp" #include "lib/util.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" #include diff --git a/src/proc/asset/db.hpp b/src/proc/asset/db.hpp index a90b7d152..c4fa89f00 100644 --- a/src/proc/asset/db.hpp +++ b/src/proc/asset/db.hpp @@ -136,11 +136,11 @@ namespace asset { } catch (lumiera::Error& EX) { - WARN (operate, "Problems while clearing Asset registry: %s", EX.what()); + WARN (progress, "Problems while clearing Asset registry: %s", EX.what()); } catch (...) { - ERROR (operate, "Serious trouble while clearing Asset registry."); + ERROR (progress, "Serious trouble while clearing Asset registry."); } } diff --git a/src/proc/asset/media.cpp b/src/proc/asset/media.cpp index a8c4a9255..cb7d9249d 100644 --- a/src/proc/asset/media.cpp +++ b/src/proc/asset/media.cpp @@ -29,7 +29,7 @@ #include "proc/mobject/session/clip.hpp" #include "proc/mobject/session/mobjectfactory.hpp" #include "lib/util.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" #include #include diff --git a/src/proc/asset/meta.cpp b/src/proc/asset/meta.cpp index 3b0eaaa5e..d72767265 100644 --- a/src/proc/asset/meta.cpp +++ b/src/proc/asset/meta.cpp @@ -24,7 +24,7 @@ #include "proc/assetmanager.hpp" #include "proc/asset/meta.hpp" #include "lib/util.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" namespace asset diff --git a/src/proc/asset/proc.cpp b/src/proc/asset/proc.cpp index 66b670bbd..870fdc739 100644 --- a/src/proc/asset/proc.cpp +++ b/src/proc/asset/proc.cpp @@ -24,7 +24,7 @@ #include "proc/assetmanager.hpp" #include "proc/asset/proc.hpp" #include "lib/util.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" namespace asset diff --git a/src/proc/asset/struct.cpp b/src/proc/asset/struct.cpp index e92fa0bb9..9503bed13 100644 --- a/src/proc/asset/struct.cpp +++ b/src/proc/asset/struct.cpp @@ -31,7 +31,7 @@ #include "proc/asset/structfactoryimpl.hpp" #include "lib/util.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" #include diff --git a/src/proc/common.hpp b/src/proc/common.hpp index e3fd94c2d..7c0680b91 100644 --- a/src/proc/common.hpp +++ b/src/proc/common.hpp @@ -46,7 +46,7 @@ #include "lib/util.hpp" #include "lib/lumitime.hpp" #include "include/symbol.hpp" -#include "lib/error.hpp" ///< pulls in NoBug via nobugcfg.h +#include "lib/error.hpp" ///< pulls in NoBug via loggging.h /** diff --git a/src/proc/mobject/builder/common.hpp b/src/proc/mobject/builder/common.hpp index 36993fa03..b22786f75 100644 --- a/src/proc/mobject/builder/common.hpp +++ b/src/proc/mobject/builder/common.hpp @@ -24,17 +24,25 @@ #ifndef MOBJECT_BUILDER_COMMON_H #define MOBJECT_BUILDER_COMMON_H -#include "include/nobugcfg.h" +#include "common/logging.h" namespace mobject { namespace builder { - NOBUG_DECLARE_FLAG (buildermem); + // TODO NOBUG_DECLARE_FLAG (builder_mem); } // namespace builder } // namespace mobject #endif + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/proc/mobject/mobject.hpp b/src/proc/mobject/mobject.hpp index 9770590e3..c97ac6d63 100644 --- a/src/proc/mobject/mobject.hpp +++ b/src/proc/mobject/mobject.hpp @@ -48,7 +48,7 @@ namespace mobject { using lumiera::P; - NOBUG_DECLARE_FLAG (mobjectmem); + //NOBUG_DECLARE_FLAG (mobjectmem); namespace session @@ -100,3 +100,10 @@ namespace mobject } // namespace mobject #endif +/* +// Local Variables: +// mode: C++ +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/proc/mobject/session/fixture.cpp b/src/proc/mobject/session/fixture.cpp index 88329075d..1c47cd889 100644 --- a/src/proc/mobject/session/fixture.cpp +++ b/src/proc/mobject/session/fixture.cpp @@ -22,7 +22,7 @@ #include "proc/mobject/session/fixture.hpp" -#include "include/nobugcfg.h" +#include "common/logging.h" namespace mobject { @@ -53,3 +53,11 @@ namespace mobject } // namespace mobject::session } // namespace mobject + +/* +// Local Variables: +// mode: C++ +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/proc/mobject/session/sessmanagerimpl.cpp b/src/proc/mobject/session/sessmanagerimpl.cpp index 9515a926e..d2c827aff 100644 --- a/src/proc/mobject/session/sessmanagerimpl.cpp +++ b/src/proc/mobject/session/sessmanagerimpl.cpp @@ -69,7 +69,7 @@ namespace mobject { } catch (...) { - ERROR (operate, "Unrecoverable Failure while creating the empty default session."); + ERROR (progress, "Unrecoverable Failure while creating the empty default session."); throw lumiera::error::Fatal ( "Failure while creating the basic session object. System halted." , LUMIERA_ERROR_CREATE_SESSION ); } From 25108f6afc422a56fa107017945c01e7a3a641b1 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 24 Jan 2009 03:16:39 +0100 Subject: [PATCH 091/216] WIP: deploy new logging flags in tests --- tests/components/proc/asset/basicpipetest.cpp | 3 ++- tests/components/proc/asset/compoundmediatest.cpp | 3 ++- tests/components/proc/asset/createassettest.cpp | 5 +++-- tests/components/proc/asset/identityofassetstest.cpp | 5 +++-- tests/components/proc/asset/makecliptest.cpp | 7 ++++--- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/tests/components/proc/asset/basicpipetest.cpp b/tests/components/proc/asset/basicpipetest.cpp index c18dca4ec..7ab6972af 100644 --- a/tests/components/proc/asset/basicpipetest.cpp +++ b/tests/components/proc/asset/basicpipetest.cpp @@ -21,6 +21,7 @@ * *****************************************************/ +#include "common/logging.h" #include "lib/test/run.hpp" #include "lib/util.hpp" @@ -200,7 +201,7 @@ namespace asset ASSERT (pipe3x != pipe2x); // ..we got a new default pipe for "pattern(another)" too! - TRACE (assetmem, "leaving BasicPipe_test::dependProcPatt()"); + TRACE (asset_mem, "leaving BasicPipe_test::dependProcPatt()"); // expect now pipe2x and pattern2 to be destroyed... } }; diff --git a/tests/components/proc/asset/compoundmediatest.cpp b/tests/components/proc/asset/compoundmediatest.cpp index d0f70db35..aec887051 100644 --- a/tests/components/proc/asset/compoundmediatest.cpp +++ b/tests/components/proc/asset/compoundmediatest.cpp @@ -21,6 +21,7 @@ * *****************************************************/ +#include "common/logging.h" #include "lib/test/run.hpp" #include "lib/util.hpp" @@ -56,7 +57,7 @@ namespace asset if (!isnil (arg)) dumpAssetManager(); - TRACE (assetmem, "leaving CreateAsset_test::run()"); + TRACE (asset_mem, "leaving CreateAsset_test::run()"); } diff --git a/tests/components/proc/asset/createassettest.cpp b/tests/components/proc/asset/createassettest.cpp index c5fde8f76..5eea290d4 100644 --- a/tests/components/proc/asset/createassettest.cpp +++ b/tests/components/proc/asset/createassettest.cpp @@ -21,6 +21,7 @@ * *****************************************************/ +#include "common/logging.h" #include "lib/test/run.hpp" #include "lib/util.hpp" @@ -55,7 +56,7 @@ namespace asset if (!isnil (arg)) dumpAssetManager(); - TRACE (assetmem, "leaving CreateAsset_test::run()"); + TRACE (asset_mem, "leaving CreateAsset_test::run()"); } @@ -147,7 +148,7 @@ namespace asset ASSERT (mm3->getFilename() == "testfile2.mov"); - TRACE (assetmem, "leaving test method scope"); + TRACE (asset_mem, "leaving test method scope"); } diff --git a/tests/components/proc/asset/identityofassetstest.cpp b/tests/components/proc/asset/identityofassetstest.cpp index 9b629e9db..21c45a474 100644 --- a/tests/components/proc/asset/identityofassetstest.cpp +++ b/tests/components/proc/asset/identityofassetstest.cpp @@ -21,6 +21,7 @@ * *****************************************************/ +#include "common/logging.h" #include "lib/test/run.hpp" #include "lib/util.hpp" @@ -55,7 +56,7 @@ namespace asset if (!isnil (arg)) dumpAssetManager(); - TRACE (assetmem, "leaving IdentityOfAssets_test::run()"); + TRACE (asset_mem, "leaving IdentityOfAssets_test::run()"); } @@ -91,7 +92,7 @@ namespace asset ASSERT (mm2->getFilename() == "testfile2.mov"); - TRACE (assetmem, "leaving test method scope"); + TRACE (asset_mem, "leaving test method scope"); } }; diff --git a/tests/components/proc/asset/makecliptest.cpp b/tests/components/proc/asset/makecliptest.cpp index db1b85dda..7e21a996d 100644 --- a/tests/components/proc/asset/makecliptest.cpp +++ b/tests/components/proc/asset/makecliptest.cpp @@ -21,6 +21,7 @@ * *****************************************************/ +#include "common/logging.h" #include "lib/test/run.hpp" #include "lib/util.hpp" @@ -38,7 +39,7 @@ using std::tr1::static_pointer_cast; //TODO only temporarily; namespace asset { namespace test { - using mobject::NOBUG_FLAG(mobjectmem); + //using mobject::NOBUG_FLAG(mobject_mem); @@ -68,8 +69,8 @@ TODO ("implement Processing Pattern!!!"); ASSERT (cm->ident.org == mm->ident.org); ASSERT (dependencyCheck (cm,mm)); - TRACE (assetmem, "leaving MakeClip_test::run()"); - TRACE (mobjectmem, "leaving MakeClip_test::run()"); + TRACE (asset_mem, "leaving MakeClip_test::run()"); + TRACE (mobject_mem, "leaving MakeClip_test::run()"); } From e5665f382089de4d5bf39972ecf554b0108286e6 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 24 Jan 2009 21:36:50 +0000 Subject: [PATCH 092/216] Fixed a headers issue introduced by a proc merge --- src/gui/gtk-lumiera.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index 956223de9..e7693c63f 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -28,6 +28,7 @@ #ifndef GTK_LUMIERA_HPP #define GTK_LUMIERA_HPP +#include #include #include // need to include this after gtkmm.h, because types.h from GTK tries to shaddow the ERROR macro from windows, which kills NoBug's ERROR macro #include From 10597beebab65d0d6229520be344699acd6573a2 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 25 Jan 2009 00:24:42 +0100 Subject: [PATCH 093/216] mass rename: relocate basic Logging conf. from liblumieracommon to liblumiera --- src/backend/backend.c | 2 +- src/backend/file.c | 2 +- src/backend/filedescriptor.c | 2 +- src/backend/filehandle.c | 2 +- src/backend/filehandlecache.c | 2 +- src/backend/mmap.c | 2 +- src/backend/mmapcache.c | 2 +- src/backend/mmapings.c | 2 +- src/backend/thread-wrapper.hpp | 2 +- src/common/Makefile.am | 3 +-- src/common/config.c | 2 +- src/common/config_lookup.c | 2 +- src/common/config_typed.c | 2 +- src/common/config_wordlist.c | 2 +- src/common/configfacade.cpp | 2 +- src/common/configitem.c | 2 +- src/common/configrules.cpp | 2 +- src/common/instancehandle.hpp | 2 +- src/common/interface.c | 2 +- src/common/interfaceregistry.c | 2 +- src/common/plugin.c | 2 +- src/common/plugin_dynlib.c | 2 +- src/common/query/fake-configrules.cpp | 2 +- src/gui/dialogs/render.cpp | 2 +- src/gui/guistart.cpp | 2 +- src/gui/model/sequence.cpp | 2 +- src/gui/notification-service.cpp | 2 +- src/gui/output/xvdisplayer.cpp | 2 +- src/gui/widgets/timeline/timeline-body.cpp | 2 +- src/gui/widgets/timeline/timeline-track.cpp | 2 +- src/gui/window-manager.cpp | 2 +- src/gui/workspace/workspace-window.cpp | 2 +- src/{common => include}/logging.h | 2 +- src/lib/Makefile.am | 3 ++- src/lib/cmdline.cpp | 2 +- src/lib/error.hpp | 2 +- src/{common => lib}/logging.cpp | 2 +- src/lib/psplay.c | 2 +- src/lib/query.cpp | 2 +- src/lib/resourcecollector.c | 2 +- src/lib/singletonfactory.hpp | 2 +- src/lib/sync.hpp | 2 +- src/lib/test/run.hpp | 2 +- src/lib/test/suite.cpp | 2 +- src/lumiera/main.cpp | 2 +- src/proc/asset.hpp | 2 +- src/proc/asset/category.cpp | 2 +- src/proc/asset/media.cpp | 2 +- src/proc/asset/meta.cpp | 2 +- src/proc/asset/proc.cpp | 2 +- src/proc/asset/struct.cpp | 2 +- src/proc/mobject/builder/common.hpp | 2 +- src/proc/mobject/session/fixture.cpp | 2 +- tests/components/proc/asset/basicpipetest.cpp | 2 +- tests/components/proc/asset/compoundmediatest.cpp | 2 +- tests/components/proc/asset/createassettest.cpp | 2 +- tests/components/proc/asset/identityofassetstest.cpp | 2 +- tests/components/proc/asset/makecliptest.cpp | 2 +- 58 files changed, 59 insertions(+), 59 deletions(-) rename src/{common => include}/logging.h (99%) rename src/{common => lib}/logging.cpp (97%) diff --git a/src/backend/backend.c b/src/backend/backend.c index 569673405..f0099f6f6 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/safeclib.h" #include "backend/backend.h" diff --git a/src/backend/file.c b/src/backend/file.c index ba18f93be..cd22d00ba 100644 --- a/src/backend/file.c +++ b/src/backend/file.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/mutex.h" #include "lib/safeclib.h" diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index edb6afbfd..5ab30eba8 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/mutex.h" #include "lib/safeclib.h" diff --git a/src/backend/filehandle.c b/src/backend/filehandle.c index 5aa8de6e8..c988ca0b9 100644 --- a/src/backend/filehandle.c +++ b/src/backend/filehandle.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/llist.h" #include "lib/safeclib.h" diff --git a/src/backend/filehandlecache.c b/src/backend/filehandlecache.c index 123f8924c..73f9ecae6 100644 --- a/src/backend/filehandlecache.c +++ b/src/backend/filehandlecache.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/safeclib.h" #include "backend/file.h" diff --git a/src/backend/mmap.c b/src/backend/mmap.c index e10d3d664..4a69144f4 100644 --- a/src/backend/mmap.c +++ b/src/backend/mmap.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/safeclib.h" #include "backend/mmap.h" diff --git a/src/backend/mmapcache.c b/src/backend/mmapcache.c index 2510ead0b..1e416e68e 100644 --- a/src/backend/mmapcache.c +++ b/src/backend/mmapcache.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/safeclib.h" #include "backend/mmapcache.h" diff --git a/src/backend/mmapings.c b/src/backend/mmapings.c index 88e6cab3e..ebf0c12db 100644 --- a/src/backend/mmapings.c +++ b/src/backend/mmapings.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/mutex.h" #include "lib/safeclib.h" diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 9847b6c2e..8981498cb 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -25,7 +25,7 @@ #define LIB_THREADWRAPPER_H -#include "common/logging.h" +#include "include/logging.h" #include "lib/sync.hpp" extern "C" { diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 61738c00f..661c92f64 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -43,8 +43,7 @@ liblumieracommon_la_SOURCES = \ $(liblumieracommon_la_srcdir)/appstate.cpp \ $(liblumieracommon_la_srcdir)/option.cpp \ $(liblumieracommon_la_srcdir)/subsys.cpp \ - $(liblumieracommon_la_srcdir)/interfaceproxy.cpp \ - $(liblumieracommon_la_srcdir)/logging.cpp + $(liblumieracommon_la_srcdir)/interfaceproxy.cpp noinst_HEADERS += \ diff --git a/src/common/config.c b/src/common/config.c index 70341d68c..b3a2fb745 100644 --- a/src/common/config.c +++ b/src/common/config.c @@ -20,7 +20,7 @@ */ //TODO: Support library includes// -#include "common/logging.h" +#include "include/logging.h" #include "lib/safeclib.h" #include "common/config.h" diff --git a/src/common/config_lookup.c b/src/common/config_lookup.c index c9be918c5..03837dcb4 100644 --- a/src/common/config_lookup.c +++ b/src/common/config_lookup.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/safeclib.h" #include "common/config_lookup.h" diff --git a/src/common/config_typed.c b/src/common/config_typed.c index 59b04a674..8018c12c0 100644 --- a/src/common/config_typed.c +++ b/src/common/config_typed.c @@ -20,7 +20,7 @@ */ //TODO: Support library includes// -#include "common/logging.h" +#include "include/logging.h" #include "lib/safeclib.h" diff --git a/src/common/config_wordlist.c b/src/common/config_wordlist.c index 8a3c74212..4f90a46ff 100644 --- a/src/common/config_wordlist.c +++ b/src/common/config_wordlist.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/error.h" #include "lib/safeclib.h" diff --git a/src/common/configfacade.cpp b/src/common/configfacade.cpp index 18c95ccb0..ca4310480 100644 --- a/src/common/configfacade.cpp +++ b/src/common/configfacade.cpp @@ -21,7 +21,7 @@ * *****************************************************/ -#include "common/logging.h" +#include "include/logging.h" #include "include/lifecycle.h" #include "include/configfacade.hpp" diff --git a/src/common/configitem.c b/src/common/configitem.c index e6b8a7839..78e861ecb 100644 --- a/src/common/configitem.c +++ b/src/common/configitem.c @@ -20,7 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/llist.h" #include "lib/safeclib.h" diff --git a/src/common/configrules.cpp b/src/common/configrules.cpp index 85ffcf5d5..2a5530324 100644 --- a/src/common/configrules.cpp +++ b/src/common/configrules.cpp @@ -24,7 +24,7 @@ #include "common/configrules.hpp" #include "common/query/fake-configrules.hpp" //#include "lib/util.hpp" -#include "common/logging.h" +#include "include/logging.h" diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp index 82bed78fe..6de4fbde9 100644 --- a/src/common/instancehandle.hpp +++ b/src/common/instancehandle.hpp @@ -41,7 +41,7 @@ #define LUMIERA_INSTANCEHANDLE_H -#include "common/logging.h" +#include "include/logging.h" #include "lib/error.hpp" #include "include/interfaceproxy.hpp" diff --git a/src/common/interface.c b/src/common/interface.c index b4a3cac85..1853c7af3 100644 --- a/src/common/interface.c +++ b/src/common/interface.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/mutex.h" #include "lib/safeclib.h" diff --git a/src/common/interfaceregistry.c b/src/common/interfaceregistry.c index e7973b361..ad8bd8224 100644 --- a/src/common/interfaceregistry.c +++ b/src/common/interfaceregistry.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/mutex.h" #include "lib/error.h" #include "lib/psplay.h" diff --git a/src/common/plugin.c b/src/common/plugin.c index 12641437c..7329d51b0 100644 --- a/src/common/plugin.c +++ b/src/common/plugin.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/safeclib.h" #include "lib/psplay.h" #include "lib/mutex.h" diff --git a/src/common/plugin_dynlib.c b/src/common/plugin_dynlib.c index be2c93c6d..c8fe5a19d 100644 --- a/src/common/plugin_dynlib.c +++ b/src/common/plugin_dynlib.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/safeclib.h" #include "common/plugin.h" diff --git a/src/common/query/fake-configrules.cpp b/src/common/query/fake-configrules.cpp index 3a3eb1d66..db7d453d1 100644 --- a/src/common/query/fake-configrules.cpp +++ b/src/common/query/fake-configrules.cpp @@ -28,7 +28,7 @@ #include "proc/asset/pipe.hpp" -#include "common/logging.h" +#include "include/logging.h" #include "lib/util.hpp" using util::isnil; diff --git a/src/gui/dialogs/render.cpp b/src/gui/dialogs/render.cpp index 7e4b40378..64dcd23d5 100644 --- a/src/gui/dialogs/render.cpp +++ b/src/gui/dialogs/render.cpp @@ -24,7 +24,7 @@ #include "render.hpp" #include "dialog.hpp" -#include "common/logging.h" +#include "include/logging.h" using namespace Gtk; diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index fe26d92d5..591f0ce2e 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -48,7 +48,7 @@ #include // need to include this to prevent errors when libintl.h defines textdomain (because gtk-lumiera removes the def when ENABLE_NLS isn't defined) #include "gui/gtk-lumiera.hpp" // need to include this before nobugcfg.h, because types.h from GTK tries to shaddow the ERROR macro from windows, which kills nobug's ERROR macro -// TODO not needed? #include "common/logging.h" +// TODO not needed? #include "include/logging.h" #include "lib/error.hpp" #include "gui/guifacade.hpp" #include "gui/notification-service.hpp" diff --git a/src/gui/model/sequence.cpp b/src/gui/model/sequence.cpp index a6bab6178..361724125 100644 --- a/src/gui/model/sequence.cpp +++ b/src/gui/model/sequence.cpp @@ -21,7 +21,7 @@ * *****************************************************/ #include "sequence.hpp" -#include "common/logging.h" +#include "include/logging.h" // TEST CODE #include "group-track.hpp" diff --git a/src/gui/notification-service.cpp b/src/gui/notification-service.cpp index ebca1bc7c..fd43c6e6c 100644 --- a/src/gui/notification-service.cpp +++ b/src/gui/notification-service.cpp @@ -23,7 +23,7 @@ #include "gui/notification-service.hpp" #include "lib/singleton.hpp" -#include "common/logging.h" +#include "include/logging.h" #include "lib/util.hpp" extern "C" { diff --git a/src/gui/output/xvdisplayer.cpp b/src/gui/output/xvdisplayer.cpp index 82f6c9115..17017ff30 100644 --- a/src/gui/output/xvdisplayer.cpp +++ b/src/gui/output/xvdisplayer.cpp @@ -27,7 +27,7 @@ #include #include "xvdisplayer.hpp" -#include "common/logging.h" +#include "include/logging.h" namespace gui { namespace output { diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index bd3a3451f..a3b9c7a5e 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -29,7 +29,7 @@ #include "timeline-arrow-tool.hpp" #include "timeline-ibeam-tool.hpp" -#include "common/logging.h" +#include "include/logging.h" using namespace Gtk; using namespace std; diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp index 5222e64c6..6a8f4f023 100644 --- a/src/gui/widgets/timeline/timeline-track.cpp +++ b/src/gui/widgets/timeline/timeline-track.cpp @@ -27,7 +27,7 @@ #include "../timeline-widget.hpp" #include "../../window-manager.hpp" #include "../../dialogs/name-chooser.hpp" -#include "common/logging.h" +#include "include/logging.h" using namespace boost; using namespace Gtk; diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index c25992695..66cc728dd 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -21,7 +21,7 @@ * *****************************************************/ #include "window-manager.hpp" -#include "common/logging.h" +#include "include/logging.h" using namespace Gtk; using namespace Glib; diff --git a/src/gui/workspace/workspace-window.cpp b/src/gui/workspace/workspace-window.cpp index f41033421..0d5d4fb6f 100644 --- a/src/gui/workspace/workspace-window.cpp +++ b/src/gui/workspace/workspace-window.cpp @@ -34,7 +34,7 @@ #include "../gtk-lumiera.hpp" #include "workspace-window.hpp" -#include "common/logging.h" +#include "include/logging.h" using namespace Gtk; using namespace gui::model; diff --git a/src/common/logging.h b/src/include/logging.h similarity index 99% rename from src/common/logging.h rename to src/include/logging.h index 0a2e49c4a..202836c08 100644 --- a/src/common/logging.h +++ b/src/include/logging.h @@ -34,7 +34,7 @@ ** ** This header can thus be assumed to be effectively global. It should contain ** only declarations of global relevance, as any change causes the whole project - ** to be rebuilt. All flags defined here are automatic initialised. + ** to be rebuilt. All flags defined here are initialised automatically. ** ** We use the 'NOBUG_DECLARATIONS_ONLY' magic to generate declarations and ** definitions only out of this header. diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 489be37ce..ede6de1cf 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -43,7 +43,8 @@ liblumiera_la_SOURCES = \ $(liblumiera_la_srcdir)/streamtype.cpp \ $(liblumiera_la_srcdir)/test/testoption.cpp \ $(liblumiera_la_srcdir)/test/suite.cpp \ - $(liblumiera_la_srcdir)/cmdline.cpp + $(liblumiera_la_srcdir)/cmdline.cpp \ + $(liblumiera_la_srcdir)/logging.cpp noinst_HEADERS += \ $(liblumiera_la_srcdir)/error.h \ diff --git a/src/lib/cmdline.cpp b/src/lib/cmdline.cpp index aed6aae40..89ebc2137 100644 --- a/src/lib/cmdline.cpp +++ b/src/lib/cmdline.cpp @@ -24,7 +24,7 @@ #include "lib/cmdline.hpp" #include "lib/util.hpp" -#include "common/logging.h" +#include "include/logging.h" #include #include diff --git a/src/lib/error.hpp b/src/lib/error.hpp index d2e2537ef..2dd654037 100644 --- a/src/lib/error.hpp +++ b/src/lib/error.hpp @@ -25,7 +25,7 @@ #define LUMIERA_ERROR_HPP_ #include -#include "common/logging.h" +#include "include/logging.h" #include "include/lifecycle.h" #include "lib/error.h" diff --git a/src/common/logging.cpp b/src/lib/logging.cpp similarity index 97% rename from src/common/logging.cpp rename to src/lib/logging.cpp index 07a53eab3..b2a62dfce 100644 --- a/src/common/logging.cpp +++ b/src/lib/logging.cpp @@ -22,7 +22,7 @@ */ #define LUMIERA_LOGGING_CXX -#include "common/logging.h" +#include "include/logging.h" /* // Local Variables: diff --git a/src/lib/psplay.c b/src/lib/psplay.c index dcb10a24f..1f788a644 100644 --- a/src/lib/psplay.c +++ b/src/lib/psplay.c @@ -21,7 +21,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/psplay.h" #include diff --git a/src/lib/query.cpp b/src/lib/query.cpp index 41df0fc53..259207387 100644 --- a/src/lib/query.cpp +++ b/src/lib/query.cpp @@ -23,7 +23,7 @@ #include "lib/query.hpp" #include "lib/util.hpp" -#include "common/logging.h" +#include "include/logging.h" #include #include diff --git a/src/lib/resourcecollector.c b/src/lib/resourcecollector.c index e1c21b83c..1919c853f 100644 --- a/src/lib/resourcecollector.c +++ b/src/lib/resourcecollector.c @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/llist.h" #include "lib/mutex.h" #include "lib/safeclib.h" diff --git a/src/lib/singletonfactory.hpp b/src/lib/singletonfactory.hpp index 31725dedf..0f2f4b225 100644 --- a/src/lib/singletonfactory.hpp +++ b/src/lib/singletonfactory.hpp @@ -37,7 +37,7 @@ This code is heavily inspired by #include "lib/singletonpolicies.hpp" // several Policies usable together with SingletonFactory -#include "common/logging.h" +#include "include/logging.h" #include "lib/util.hpp" #include "lib/sync-classlock.hpp" diff --git a/src/lib/sync.hpp b/src/lib/sync.hpp index 63212bfa5..077ab8b42 100644 --- a/src/lib/sync.hpp +++ b/src/lib/sync.hpp @@ -67,7 +67,7 @@ #ifndef LIB_SYNC_H #define LIB_SYNC_H -#include "common/logging.h" +#include "include/logging.h" #include "lib/error.hpp" #include "lib/util.hpp" diff --git a/src/lib/test/run.hpp b/src/lib/test/run.hpp index 9f6f2f415..0b3e896b3 100644 --- a/src/lib/test/run.hpp +++ b/src/lib/test/run.hpp @@ -28,7 +28,7 @@ #include "pre.hpp" -#include "common/logging.h" +#include "include/logging.h" #include "lib/test/suite.hpp" #include "lib/util.hpp" diff --git a/src/lib/test/suite.cpp b/src/lib/test/suite.cpp index a4df524b6..f6107fafc 100644 --- a/src/lib/test/suite.cpp +++ b/src/lib/test/suite.cpp @@ -30,7 +30,7 @@ #include #include -#include "common/logging.h" +#include "include/logging.h" #include "lib/cmdline.hpp" #include "lib/test/suite.hpp" #include "lib/test/run.hpp" diff --git a/src/lumiera/main.cpp b/src/lumiera/main.cpp index 9d143d419..3cc2b2eeb 100644 --- a/src/lumiera/main.cpp +++ b/src/lumiera/main.cpp @@ -22,7 +22,7 @@ */ -#include "common/logging.h" +#include "include/logging.h" #include "lib/error.hpp" #include "common/appstate.hpp" #include "common/option.hpp" diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index 785c4948e..0186289fd 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -56,7 +56,7 @@ #include "proc/asset/category.hpp" -#include "common/logging.h" +#include "include/logging.h" #include "lib/error.hpp" #include "lib/p.hpp" diff --git a/src/proc/asset/category.cpp b/src/proc/asset/category.cpp index 622ae8205..e285bf011 100644 --- a/src/proc/asset/category.cpp +++ b/src/proc/asset/category.cpp @@ -23,7 +23,7 @@ #include "proc/asset/category.hpp" #include "lib/util.hpp" -#include "common/logging.h" +#include "include/logging.h" #include diff --git a/src/proc/asset/media.cpp b/src/proc/asset/media.cpp index cb7d9249d..e8c6ac12b 100644 --- a/src/proc/asset/media.cpp +++ b/src/proc/asset/media.cpp @@ -29,7 +29,7 @@ #include "proc/mobject/session/clip.hpp" #include "proc/mobject/session/mobjectfactory.hpp" #include "lib/util.hpp" -#include "common/logging.h" +#include "include/logging.h" #include #include diff --git a/src/proc/asset/meta.cpp b/src/proc/asset/meta.cpp index d72767265..ecb918ed1 100644 --- a/src/proc/asset/meta.cpp +++ b/src/proc/asset/meta.cpp @@ -24,7 +24,7 @@ #include "proc/assetmanager.hpp" #include "proc/asset/meta.hpp" #include "lib/util.hpp" -#include "common/logging.h" +#include "include/logging.h" namespace asset diff --git a/src/proc/asset/proc.cpp b/src/proc/asset/proc.cpp index 870fdc739..764c3a928 100644 --- a/src/proc/asset/proc.cpp +++ b/src/proc/asset/proc.cpp @@ -24,7 +24,7 @@ #include "proc/assetmanager.hpp" #include "proc/asset/proc.hpp" #include "lib/util.hpp" -#include "common/logging.h" +#include "include/logging.h" namespace asset diff --git a/src/proc/asset/struct.cpp b/src/proc/asset/struct.cpp index 9503bed13..4288e066a 100644 --- a/src/proc/asset/struct.cpp +++ b/src/proc/asset/struct.cpp @@ -31,7 +31,7 @@ #include "proc/asset/structfactoryimpl.hpp" #include "lib/util.hpp" -#include "common/logging.h" +#include "include/logging.h" #include diff --git a/src/proc/mobject/builder/common.hpp b/src/proc/mobject/builder/common.hpp index b22786f75..e0503499b 100644 --- a/src/proc/mobject/builder/common.hpp +++ b/src/proc/mobject/builder/common.hpp @@ -24,7 +24,7 @@ #ifndef MOBJECT_BUILDER_COMMON_H #define MOBJECT_BUILDER_COMMON_H -#include "common/logging.h" +#include "include/logging.h" namespace mobject { diff --git a/src/proc/mobject/session/fixture.cpp b/src/proc/mobject/session/fixture.cpp index 1c47cd889..2ff3b1612 100644 --- a/src/proc/mobject/session/fixture.cpp +++ b/src/proc/mobject/session/fixture.cpp @@ -22,7 +22,7 @@ #include "proc/mobject/session/fixture.hpp" -#include "common/logging.h" +#include "include/logging.h" namespace mobject { diff --git a/tests/components/proc/asset/basicpipetest.cpp b/tests/components/proc/asset/basicpipetest.cpp index 7ab6972af..c10c77ea8 100644 --- a/tests/components/proc/asset/basicpipetest.cpp +++ b/tests/components/proc/asset/basicpipetest.cpp @@ -21,7 +21,7 @@ * *****************************************************/ -#include "common/logging.h" +#include "include/logging.h" #include "lib/test/run.hpp" #include "lib/util.hpp" diff --git a/tests/components/proc/asset/compoundmediatest.cpp b/tests/components/proc/asset/compoundmediatest.cpp index aec887051..e6e045895 100644 --- a/tests/components/proc/asset/compoundmediatest.cpp +++ b/tests/components/proc/asset/compoundmediatest.cpp @@ -21,7 +21,7 @@ * *****************************************************/ -#include "common/logging.h" +#include "include/logging.h" #include "lib/test/run.hpp" #include "lib/util.hpp" diff --git a/tests/components/proc/asset/createassettest.cpp b/tests/components/proc/asset/createassettest.cpp index 5eea290d4..c2eb633f8 100644 --- a/tests/components/proc/asset/createassettest.cpp +++ b/tests/components/proc/asset/createassettest.cpp @@ -21,7 +21,7 @@ * *****************************************************/ -#include "common/logging.h" +#include "include/logging.h" #include "lib/test/run.hpp" #include "lib/util.hpp" diff --git a/tests/components/proc/asset/identityofassetstest.cpp b/tests/components/proc/asset/identityofassetstest.cpp index 21c45a474..98ba41e84 100644 --- a/tests/components/proc/asset/identityofassetstest.cpp +++ b/tests/components/proc/asset/identityofassetstest.cpp @@ -21,7 +21,7 @@ * *****************************************************/ -#include "common/logging.h" +#include "include/logging.h" #include "lib/test/run.hpp" #include "lib/util.hpp" diff --git a/tests/components/proc/asset/makecliptest.cpp b/tests/components/proc/asset/makecliptest.cpp index 7e21a996d..0dc4365cc 100644 --- a/tests/components/proc/asset/makecliptest.cpp +++ b/tests/components/proc/asset/makecliptest.cpp @@ -21,7 +21,7 @@ * *****************************************************/ -#include "common/logging.h" +#include "include/logging.h" #include "lib/test/run.hpp" #include "lib/util.hpp" From 4690565956756afa43f75e7fc77292eb25928f3f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 25 Jan 2009 01:03:15 +0100 Subject: [PATCH 094/216] disabled a test which verified an additional ASSERTION sanity check in order to get this back, we need a way to configure assertions for parts of the project... --- tests/lib/singletonsubclasstest.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/lib/singletonsubclasstest.cpp b/tests/lib/singletonsubclasstest.cpp index 1b9097c44..318ed76e1 100644 --- a/tests/lib/singletonsubclasstest.cpp +++ b/tests/lib/singletonsubclasstest.cpp @@ -119,10 +119,13 @@ namespace lumiera cout << "calling a non-static method on the Singleton-" << t1.identify() << "\n" << string (t1) << "\n"; - -#ifdef DEBUG - verify_error_detection (); -#endif + +///////////////////////////////////////////////////////////////////////////////TODO: find a way to configure NoBug to throw in case of assertion +///////////////////////////////////////////////////////////////////////////////TODO: just for the proc tests. Also find a better way to configure +///////////////////////////////////////////////////////////////////////////////TODO: the non-release check. Then re-enable these checks... +//#ifdef DEBUG +// verify_error_detection (); +//#endif } From a8285878acea685b0d877d1fa8e30c25b45c5ec6 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 25 Jan 2009 03:27:16 +0100 Subject: [PATCH 095/216] fix some logging flags after merge --- src/gui/controller/playback-controller.cpp | 2 +- src/proc/play/dummy-player-service.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index f360ca6a5..7465d29f0 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -61,7 +61,7 @@ PlaybackController::play() } catch (lumiera::error::State& err) { - WARN (operate, "failed to start playback: %s" ,err.what()); + WARN (gui, "failed to start playback: %s" ,err.what()); lumiera_error(); playing = false; } diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index ca2f0dd31..bd4508207 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -249,7 +249,7 @@ namespace proc { , implInstance_(this,_instance) , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade)) { - INFO (operate, "DummyPlayer Facade opened."); + INFO (progress, "DummyPlayer Facade opened."); } From 7660324d234b9d2dfde88228fc5e1740ab031ef6 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 25 Jan 2009 03:33:29 +0100 Subject: [PATCH 096/216] for the tests change some sleep into much shorter micro sleeps --- tests/lib/sync-waiting-test.cpp | 2 +- tests/lib/thread-wrapper-join-test.cpp | 2 +- tests/lib/thread-wrapper-test.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/lib/sync-waiting-test.cpp b/tests/lib/sync-waiting-test.cpp index 5e54262e4..05fe56e7c 100644 --- a/tests/lib/sync-waiting-test.cpp +++ b/tests/lib/sync-waiting-test.cpp @@ -162,7 +162,7 @@ namespace lib { ASSERT (pong); ASSERT (0 == tok.result()); - sleep (1); // if the threads don't block correctly, they've missed their chance by now... + usleep (100000); // if the threads don't block correctly, they've missed their chance by now... // kick off the notification cascade... uint val = (rand() % 1000); diff --git a/tests/lib/thread-wrapper-join-test.cpp b/tests/lib/thread-wrapper-join-test.cpp index 97f6e0c0e..5c87e3a65 100644 --- a/tests/lib/thread-wrapper-join-test.cpp +++ b/tests/lib/thread-wrapper-join-test.cpp @@ -62,7 +62,7 @@ namespace lib { void theAction (int secretValue) ///< to be run in a new thread... { - sleep(1); + usleep (100000); // pause 100ms prior to modifying aValue_ = secretValue+42; } diff --git a/tests/lib/thread-wrapper-test.cpp b/tests/lib/thread-wrapper-test.cpp index 0183cf391..4d08150ed 100644 --- a/tests/lib/thread-wrapper-test.cpp +++ b/tests/lib/thread-wrapper-test.cpp @@ -98,7 +98,7 @@ namespace lib { sum = checksum = 0; TestThread instances[NUM_THREADS] SIDEEFFECT; - sleep (1); /////////////////TODO better method of waiting for the threads to terminate..... + usleep (200000); // pause 200ms for the threads to terminate..... ASSERT (0 < sum); ASSERT (sum==checksum); From aa7fe2591c673c607156a1218645338b018d9808 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 26 Jan 2009 01:09:49 +0100 Subject: [PATCH 097/216] use a dedicated header to pull up early NoBug init --- src/lib/Makefile.am | 2 ++ src/lib/nobug-init.cpp | 43 ++++++++++++++++++++++++++++ src/lib/nobug-init.hpp | 53 +++++++++++++++++++++++++++++++++++ src/lib/singletonfactory.hpp | 5 +--- src/lib/singletonpolicies.hpp | 1 + src/lib/sync-classlock.hpp | 1 + 6 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 src/lib/nobug-init.cpp create mode 100644 src/lib/nobug-init.hpp diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index ede6de1cf..cb1451c4f 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -37,6 +37,7 @@ liblumiera_la_SOURCES = \ $(liblumiera_la_srcdir)/allocationcluster.cpp \ $(liblumiera_la_srcdir)/lumitime.cpp \ $(liblumiera_la_srcdir)/lifecycle.cpp \ + $(liblumiera_la_srcdir)/nobug-init.cpp \ $(liblumiera_la_srcdir)/util.cpp \ $(liblumiera_la_srcdir)/visitor.cpp \ $(liblumiera_la_srcdir)/query.cpp \ @@ -64,6 +65,7 @@ noinst_HEADERS += \ $(liblumiera_la_srcdir)/scopedholdertransfer.hpp \ $(liblumiera_la_srcdir)/scopedholder.hpp \ $(liblumiera_la_srcdir)/lifecycleregistry.hpp \ + $(liblumiera_la_srcdir)/nobug-init.hpp \ $(liblumiera_la_srcdir)/factory.hpp \ $(liblumiera_la_srcdir)/frameid.hpp \ $(liblumiera_la_srcdir)/singleton.hpp \ diff --git a/src/lib/nobug-init.cpp b/src/lib/nobug-init.cpp new file mode 100644 index 000000000..69b75b98e --- /dev/null +++ b/src/lib/nobug-init.cpp @@ -0,0 +1,43 @@ +/* + NoBugInit - pull up NoBug automagically in static initialisation + + Copyright (C) Lumiera.org + 2009, 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/nobug-init.hpp" + + + +namespace lumiera { + + void + initialise_NoBug () + { + NOBUG_INIT; + +////////////////////////////////////////////////////////////////////////TODO: a better way to detect Alpha/beta builds +#ifdef DEBUG + static uint callCount = 0; + ASSERT ( 0 == callCount++ ); +#endif + } + +} + diff --git a/src/lib/nobug-init.hpp b/src/lib/nobug-init.hpp new file mode 100644 index 000000000..a34fa8577 --- /dev/null +++ b/src/lib/nobug-init.hpp @@ -0,0 +1,53 @@ +/* + NOBUG-INIT.hpp - pull up NoBug automagically in static initialisation + + + Copyright (C) Lumiera.org + 2009, 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 nobug-init.hpp + ** Trigger the basic NoBug initialisation by placing a static variable. + ** Any facility which uses NoBug (especially logging) already within the + ** static initialisation phase of the application, should do the include + ** via this header, which additionally installs a Lifecycle callback to + ** be run as early as possible. + ** + ** @see logging.h + ** + */ + + +#ifndef NOBUG_INIT_H +#define NOBUG_INIT_H + +#include "include/lifecycle.h" + +#include + + + +namespace lumiera { + void initialise_NoBug (); + + namespace { + LifecycleHook trigger_init_ (ON_BASIC_INIT, &initialise_NoBug); +} } + + +#endif /* NOBUG_INIT_H */ diff --git a/src/lib/singletonfactory.hpp b/src/lib/singletonfactory.hpp index 0f2f4b225..13751c956 100644 --- a/src/lib/singletonfactory.hpp +++ b/src/lib/singletonfactory.hpp @@ -37,6 +37,7 @@ This code is heavily inspired by #include "lib/singletonpolicies.hpp" // several Policies usable together with SingletonFactory +#include "lib/nobug-init.hpp" #include "include/logging.h" #include "lib/util.hpp" #include "lib/sync-classlock.hpp" @@ -82,10 +83,6 @@ namespace lumiera { { if (!pInstance_) { - NOBUG_INIT; - FIXME ("NoBug wasnt even basically initialized here, the old ON_BASIC_INIT did not initialize it in proper order" - " so I explicitly init it here (calling init multiple times does not harm) --cehteh" - " nb maybe as exception we can use an explicit mutex here since pthread mutexes can be statically initialized"); ThreadLock guard SIDEEFFECT; if (!pInstance_) diff --git a/src/lib/singletonpolicies.hpp b/src/lib/singletonpolicies.hpp index cfc21c67a..8a4f3271b 100644 --- a/src/lib/singletonpolicies.hpp +++ b/src/lib/singletonpolicies.hpp @@ -34,6 +34,7 @@ This code is heavily inspired by #ifndef LUMIERA_SINGLETONPOLICIES_H #define LUMIERA_SINGLETONPOLICIES_H +#include "lib/nobug-init.hpp" #include "lib/error.hpp" #include diff --git a/src/lib/sync-classlock.hpp b/src/lib/sync-classlock.hpp index 6a060eb1f..c18593838 100644 --- a/src/lib/sync-classlock.hpp +++ b/src/lib/sync-classlock.hpp @@ -36,6 +36,7 @@ #ifndef LIB_SYNC_CLASSLOCK_H #define LIB_SYNC_CLASSLOCK_H +#include "lib/nobug-init.hpp" #include "lib/sync.hpp" From 8419534f498908913a8df1367a78dd6300dede2b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 28 Jan 2009 02:44:59 +0100 Subject: [PATCH 098/216] A generic opaque Handle type built on top of shared_ptr, for managing lifecycle --- src/lib/handle.hpp | 136 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/lib/handle.hpp diff --git a/src/lib/handle.hpp b/src/lib/handle.hpp new file mode 100644 index 000000000..e0dbaa661 --- /dev/null +++ b/src/lib/handle.hpp @@ -0,0 +1,136 @@ +/* + HANDLE.hpp - opaque handle to an implementation entity, automatically managing lifecycle + + Copyright (C) Lumiera.org + 2009, 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 handle.hpp + ** A generic opaque handle to an implementation entity, including lifecycle management. + ** The intended use is for some public interface to return such a handle to track the + ** lifecycle or registration of a dedicated service created for this call. The handle + ** is implemented as refcounting smart-ptr on top of shared_ptr, which especially + ** means for the client code that the handle has value semantics, can be copied and + ** stored, while the referred service will stay alive as long as there is still an + ** handle in use. A handle may be empty ("null handle") or closed; the latter + ** also decreases the ref count and can be used to close a service explicitly. + ** + ** Possibly a service may use an extension of the handle template carrying dedicated + ** API functions. In this case, the handle acts like a PImpl; the actual definition + ** of the implementation class the handle points at is necessary only in the + ** translation unit implementing such an extended handle. + ** + ** @see proc::DummyPlayer::Process usage example + ** + */ + + +#ifndef LIB_HANDLE_H +#define LIB_HANDLE_H + +#include "lib/nobug-init.hpp" +#include "lib/sync.hpp" + +#include + + +namespace lib { + + using std::tr1::shared_ptr; + using std::tr1::weak_ptr; + + + + /** + * Generic opaque reference counting handle, for accessing a service + * and managing its lifecycle. Usually such a handle is created by + * an service interface and \link #activate activated \endlink by + * setting up the link to some internal implementation object. + * This setup can only be done by a friend or derived class, + * while client code is free to copy and store handle objects. + * Finally, any handle can be closed, thereby decrementing + * the use count. + */ + template + class Handle + : protected std::tr1::shared_ptr + { + public: + typedef std::tr1::shared_ptr SmP; + + /** by default create an Null handle. + * Typically this is followed by activating + * the handle by the managing service. + */ + Handle ( ) + : SmP() + { } + + Handle (Handle const& r) : SmP(r) {} + template Handle (shared_ptr const& r) : SmP(r) {} + template explicit Handle (weak_ptr const& wr) : SmP(wr) {} + template explicit Handle (std::auto_ptr & ar) : SmP(ar) {} + + Handle& operator= (Handle const& r) { SmP::operator= (r); return *this; } + template Handle& operator=(shared_ptr const& sr) { SmP::operator= (sr); return *this; } + template Handle& operator=(std::auto_ptr & ar) { SmP::operator= (ar); return *this; } + + + /** deactivate this handle, so it isn't tied any longer + * to the associated implementation or service object. + * When all handles have either been deactivated or + * went out of scope, the associated implementation + * reaches end-of-life. + */ + void close () { SmP::reset(); } + + + typedef IMP* SmP::*__unspecified_bool_type; + + /** implicit conversion to "bool" */ + operator __unspecified_bool_type() const { return *this; } // never throws + bool operator! () const { return !SmP::get(); } // dito + + + + + protected: + + /** Activation of the handle by the managing service. + * @param impl the implementation object this handle is tied to + * @param whenDead functor to be invoked when reaching end-of-life + */ + template + Handle& + activate (IMP* impl, DEL whenDead) + { + SmP::reset (impl, whenDead); + return *this; + } + + IMP& + impl() + { + REQUIRE (SmP::get(), "Lifecycle-Error"); + return *(SmP::get()); + } + }; + + +} // namespace lib +#endif From cbd27b04184d7115dc1fb2701a9176dbf2418b31 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 28 Jan 2009 02:49:20 +0100 Subject: [PATCH 099/216] Completely reworked the design of the DummyPlayer API, now using the handle this allows the C++ version to provide automatic lifecycle management for the play process, while both versions of the API (C and C++) impose only one level of indirection. --- src/common/interfaceproxy.cpp | 26 +++-- src/gui/controller/playback-controller.cpp | 13 +-- src/gui/controller/playback-controller.hpp | 2 +- src/include/dummy-player-facade.h | 124 +++++++++++---------- src/lumiera/main.cpp | 2 +- src/proc/play/dummy-player-service.cpp | 106 +++++++++++++----- src/proc/play/dummy-player-service.hpp | 64 ++++++----- tests/lib/allocationclustertest.cpp | 2 +- 8 files changed, 201 insertions(+), 138 deletions(-) diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index bf7607f17..6d72dc967 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -40,14 +40,15 @@ namespace gui { -#include "include/dummy-player-facade.h" +#include "proc/play/dummy-player-service.hpp" namespace proc { + namespace play { /** storage for the DummyPlayer facade proxy factory... */ lumiera::facade::Accessor DummyPlayer::facade; - -} // namespace gui + +} } @@ -152,7 +153,7 @@ namespace lumiera { /* ==================== DummyPlayer ======================================= */ typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) - , proc::DummyPlayer + , proc::play::DummyPlayer > Handle_DummyPlayer; @@ -161,21 +162,24 @@ namespace lumiera { : public Holder { //----Proxy-Implementation-of-DummyPlayer-------- - typedef proc::DummyPlayer::Process Process; + typedef proc::play::DummyPlayer::Process Process; + typedef proc::play::ProcessImpl ProcessImpl; /** @note as an optimisation we hand out a direct reference * to the implementing process object. While this ref could * still be passed as handle to the C Language interface, using - * it directly within the client (=GUI) retains only on level - * of indirection, irrespective which interface is used. */ - Process& start() + * it directly within the client (=GUI) bypasses the C interface + * and thus leaves us only with one level of indirection, + * irrespective if using the C or C++ interface. + */ + Process start() { - Process* pP = static_cast (_i_.startPlay()); + ProcessImpl* pP = static_cast (_i_.startPlay()); - if (!pP || lumiera_error_peek()) + if (!pP) throw lumiera::error::State("failed to start DummyPlayer", lumiera_error()); - return *pP; + return pP->createHandle(); } diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index 7465d29f0..0ec7c6fe6 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -30,8 +30,7 @@ namespace controller { PlaybackController::PlaybackController() : thread(0), finish_playback_thread(false), - playing(false), - playHandle(0) + playing(false) { } @@ -45,7 +44,7 @@ PlaybackController::play() { if (playing && thread && playHandle) { - playHandle->pause(false); + playHandle.play(true); return; } if (thread) @@ -55,7 +54,7 @@ PlaybackController::play() Lock sync(this); try { - playHandle = & (proc::DummyPlayer::facade().start()); + playHandle = proc::play::DummyPlayer::facade().start(); start_playback_thread(); playing = true; } @@ -74,7 +73,7 @@ PlaybackController::pause() Lock sync(this); playing = false; if (playHandle) - playHandle->pause(true); + playHandle.play(false); } void @@ -83,7 +82,7 @@ PlaybackController::stop() { Lock sync(this); playing = false; - playHandle = 0; + playHandle.close(); // TODO: stop player somehow? } end_playback_thread(); @@ -151,7 +150,7 @@ PlaybackController::pull_frame() REQUIRE (is_playing()); REQUIRE (playHandle); - unsigned char * newBuffer = reinterpret_cast (playHandle->getFrame()); + unsigned char * newBuffer = reinterpret_cast (playHandle.getFrame()); if (newBuffer != currentBuffer) { diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 8b9a0916d..b05ae0c6f 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -82,7 +82,7 @@ private: volatile bool playing; - proc::DummyPlayer::Process *playHandle; + proc::play::DummyPlayer::Process playHandle; unsigned char * currentBuffer; diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h index 2899096c0..b10da3684 100644 --- a/src/include/dummy-player-facade.h +++ b/src/include/dummy-player-facade.h @@ -37,66 +37,74 @@ typedef lumiera_playprocess* LumieraPlayProcess; #include "common/subsys.hpp" #include "include/interfaceproxy.hpp" +#include "lib/handle.hpp" #include namespace proc { - - - - /****************************************************************** - * Interface Proc-Layer (or maybe the backend?): - * Global access point for starting a dummy playback, generating - * some test image data for the GUI to display in a viewer window. - * - * This is a mockup service we created 1/2009 to collect some - * experiences regarding integration of the application layers. - * Lumiera is not yet able actually to deliver rendered video data. - * - */ - class DummyPlayer - { - public: - /** provide a descriptor for lumiera::AppState, - * wired accordingly to allow main to deal with - * the dummy player as independent subsystem. */ - static lumiera::Subsys& getDescriptor(); - - /** get an implementation instance of this service */ - static lumiera::facade::Accessor facade; - - - /** - * Continuous playback process, which has been started with a specific - * output size, format and framerate. It is a handle to a calculation process, - * which is about to produce a stream of frames to be retrieved by calling - * the #getFrame function on this handle. - * - * @todo solve the lifecycle and ownership! - */ - class Process - : public lumiera_playprocess - , boost::noncopyable - { - public: - virtual void pause(bool) =0; - virtual void* const getFrame() =0; - - virtual ~Process(); - }; - - - //////////////////TODO: define some dummy negotiation about size and framerate.... - - virtual Process& start() =0; - - virtual ~DummyPlayer(); - }; - - - + namespace play { + + + class ProcessImpl; + + + /****************************************************************** + * Interface Proc-Layer (or maybe the backend?): + * Global access point for starting a dummy playback, generating + * some test image data for the GUI to display in a viewer window. + * + * This is a mockup service we created 1/2009 to collect some + * experiences regarding integration of the application layers. + * Lumiera is not yet able actually to deliver rendered video data. + * + */ + class DummyPlayer + { + public: + /** provide a descriptor for lumiera::AppState, + * wired accordingly to allow main to deal with + * the dummy player as independent subsystem. */ + static lumiera::Subsys& getDescriptor(); + + /** get an implementation instance of this service */ + static lumiera::facade::Accessor facade; + + + /** + * Continuous playback process, which has been started with a specific + * output size, format and framerate. It is a handle to a calculation process, + * which is about to produce a stream of frames to be retrieved by calling + * the #getFrame function on this handle. + * + * The Lifecycle of the referred playback process is managed automatically + * through this handle (by ref count). + * @see handle.hpp + * @see dummy-player-service.cpp implementation + */ + class Process + : public lib::Handle + { + friend class ProcessImpl; + + public: + void play(bool); + void* const getFrame(); + + }; + + + //////////////////TODO: define some dummy negotiation about size and framerate.... + + virtual Process start() =0; + + virtual ~DummyPlayer(); + }; + + + + } // namespace play } // namespace proc @@ -109,10 +117,10 @@ extern "C" { #include "common/interface.h" LUMIERA_INTERFACE_DECLARE (lumieraorg_DummyPlayer, 0 - , LUMIERA_INTERFACE_SLOT (LumieraPlayProcess, startPlay,(void) ) - , LUMIERA_INTERFACE_SLOT (void, pausePlay,(LumieraPlayProcess, bool)) - , LUMIERA_INTERFACE_SLOT (void, terminate,(LumieraPlayProcess) ) - , LUMIERA_INTERFACE_SLOT (void *, getFrame, (LumieraPlayProcess) ) + , LUMIERA_INTERFACE_SLOT (LumieraPlayProcess, startPlay, (void) ) + , LUMIERA_INTERFACE_SLOT (void, togglePlay,(LumieraPlayProcess, bool)) + , LUMIERA_INTERFACE_SLOT (void, terminate, (LumieraPlayProcess) ) + , LUMIERA_INTERFACE_SLOT (void *, getFrame, (LumieraPlayProcess) ) ); diff --git a/src/lumiera/main.cpp b/src/lumiera/main.cpp index 67f3dfc9f..94a133e11 100644 --- a/src/lumiera/main.cpp +++ b/src/lumiera/main.cpp @@ -43,7 +43,7 @@ namespace { Subsys& engine = backend::EngineFacade::getDescriptor(); Subsys& netNode = backend::NetNodeFacade::getDescriptor(); Subsys& script = backend::ScriptRunnerFacade::getDescriptor(); - Subsys& player = proc::DummyPlayer::getDescriptor(); + Subsys& player = proc::play::DummyPlayer::getDescriptor(); Subsys& builder = proc::Facade::getBuilderDescriptor(); Subsys& session = proc::Facade::getSessionDescriptor(); Subsys& lumigui = gui::GuiFacade::getDescriptor(); diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index bd4508207..892237d41 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -30,6 +30,7 @@ extern "C" { } #include +#include #include @@ -38,6 +39,7 @@ namespace proc { using std::string; using lumiera::Subsys; + using std::auto_ptr; using boost::scoped_ptr; @@ -167,11 +169,11 @@ namespace proc { using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; - typedef lib::SingletonRef::Accessor InstanceRef; + typedef lib::SingletonRef::Accessor InstanceRef; InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation... - typedef DummyPlayer::Process* ProcP; + typedef ProcessImpl* ProcP; LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0 @@ -188,10 +190,10 @@ namespace proc { return 0; } - return static_cast (& (_instance->start())); + return static_cast (_instance->start()); } ) - , LUMIERA_INTERFACE_INLINE (pausePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307", + , LUMIERA_INTERFACE_INLINE (togglePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307", void, (LumieraPlayProcess handle, bool doPlay), { if (!_instance) @@ -203,7 +205,7 @@ namespace proc { REQUIRE (handle); ProcP proc = static_cast (handle); - proc->pause(doPlay); + proc->doPlay(doPlay); } ) , LUMIERA_INTERFACE_INLINE (terminate, "\005\265\115\021\076\143\010\215\373\252\370\174\235\136\340\004", @@ -218,7 +220,7 @@ namespace proc { REQUIRE (handle); ProcP proc = static_cast (handle); - UNIMPLEMENTED ("terminate a running playback process"); + ProcessImpl::terminate (proc); } ) , LUMIERA_INTERFACE_INLINE (getFrame, "\230\130\101\300\047\065\170\052\226\164\026\112\150\166\074\134", @@ -255,22 +257,67 @@ namespace proc { - DummyPlayer::Process& + /** @par implementation note + * A new process (implementation) is created, configured + * and started here. This may include spawning a thread or + * allocating a timer. The newly created process is self-contained + * and will be just handed out, without caring for its lifecycle. + * If client code accesses this function via the plain C interface, + * the client is responsible for terminating this process, whereas + * when using the C++ interface, you'll get a Handle object which + * manages the lifecycle automatically. + */ + ProcessImpl* DummyPlayerService::start() { - // REQUIRE (!theProcess_.isActive()); //////////////TODO: reactivate this check when we have really independent processes which can be stopped! - theProcess_.setRate(25); + auto_ptr newProcess (new ProcessImpl); + + REQUIRE (!newProcess->isActive()); + newProcess->setRate(25); - return theProcess_; + return newProcess.release(); } + /* === Forwarding functions on the Process handle === */ + + void DummyPlayer::Process::play(bool yes) { impl().doPlay(yes); } + void* const DummyPlayer::Process::getFrame() { return impl().getFrame(); } + + + + + + /* === Process Implementation === */ + + + ProcessImpl::ProcessImpl() : fps_(0), play_(false), imageGen_(0) {} + ProcessImpl::~ProcessImpl() {} + + + DummyPlayer::Process + ProcessImpl::createHandle() + { + DummyPlayer::Process handle; + handle.activate(this, &terminate); + return handle; + } + + + void + ProcessImpl::terminate (ProcessImpl* process) + { + if (process) + delete process; + } + + void ProcessImpl::setRate (uint fps) { - // REQUIRE (fps==0 || fps_==0 ); //////////////TODO: reactivate this check when we have really independent processes which can be stopped! - // REQUIRE (fps==0 || !play_ ); //////////////TODO: reactivate this check when we have really independent processes which can be stopped! + REQUIRE (fps==0 || fps_==0 ); + REQUIRE (fps==0 || !play_ ); fps_ = fps; play_ = (fps != 0); @@ -282,10 +329,10 @@ namespace proc { void - ProcessImpl::pause(bool doPause) + ProcessImpl::doPlay(bool yes) { REQUIRE (isActive()); - play_ = !doPause; + play_ = yes; } @@ -304,22 +351,21 @@ namespace proc { + + + + /** @internal intended for use by main(). */ + lumiera::Subsys& + DummyPlayer::getDescriptor() + { + return play::theDescriptor(); + } + + // emit the vtable here into this translation unit within liblumieraproc.so ... + DummyPlayer::~DummyPlayer() { } + + + } // namespace play - - - /** @internal intended for use by main(). */ - lumiera::Subsys& - DummyPlayer::getDescriptor() - { - return play::theDescriptor(); - } - - // emit the vtable here into this translation unit within liblumieraproc.so ... - DummyPlayer::~DummyPlayer() { } - DummyPlayer::Process::~Process() { } - - - - } // namespace proc diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index ae8b3161e..0648f982a 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -27,7 +27,7 @@ ** within the lower layers. ** ** This service is the implementation of a layer separation facade interface. Clients should use - ** gui::GuiNotification#facade to access this service. This header defines the interface used + ** proc::play::DummyPlayer#facade to access this service. This header defines the interface used ** to \em provide this service, not to access it. ** ** @see gui::GuiFacade @@ -43,6 +43,7 @@ #include "common/instancehandle.hpp" #include "lib/singleton-ref.hpp" +#include #include #include @@ -57,12 +58,17 @@ namespace proc { class DummyImageGenerator; + /******************************************************************** + * Actual implementation of a single (dummy) playback process. + * The DummyPlayerService (see below) maintains a collection of such + * actively running playback processes, while the client code gets + * DummyPlayer::Process handles to track any ongoing use. Users of + * the plain C interface get a direct bare pointer to the respective + * ProcessImpl instance and have to manage the lifecycle manually. + */ class ProcessImpl - : public DummyPlayer::Process + : public lumiera_playprocess { - void pause(bool doPause); - void* const getFrame(); - uint fps_; bool play_; @@ -70,7 +76,8 @@ namespace proc { public: - ProcessImpl() : fps_(0), play_(false), imageGen_(0) {} + ProcessImpl() ; + ~ProcessImpl(); /* Implementation-level API to be used By DummyPlayerService */ @@ -80,48 +87,39 @@ namespace proc { bool isActive () { return fps_ != 0; } bool isPlaying() { return play_; } + + void doPlay(bool yes); + void* const getFrame(); + + DummyPlayer::Process createHandle(); + static void terminate(ProcessImpl* process); }; - + + /****************************************************** - * Actual implementation of the GuiNotification service - * within the Lumiera GTK GUI. Creating an instance of - * this class automatically registers the interface - * with the Lumiera Interface/Plugin system and creates + * Actual implementation of the DummyPlayer service. + * Creating an instance of this class automatically + * registers the interface lumieraorg_DummyPlayer with + * the Lumiera Interface/Plugin system and creates * a forwarding proxy within the application core to * route calls through this interface. - * - * @todo the ctor of this class should take references - * to any internal service providers within the - * GUI which are needed to implement the service. */ class DummyPlayerService - : public DummyPlayer + : boost::noncopyable { - /* === Implementation of the Facade Interface === */ - - Process& start(); - - - /** for now we use an single inline Process... - * @todo actually implement multiple independent Playback processes! - * @todo I am aware holding this object inline may cause a segfault at shutdown! - */ - ProcessImpl theProcess_; - string error_; Subsys::SigTerm notifyTermination_; - /* === Interface Lifecycle === */ typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) , DummyPlayer > ServiceInstanceHandle; - lib::SingletonRef implInstance_; + lib::SingletonRef implInstance_; ServiceInstanceHandle serviceInstance_; public: @@ -129,6 +127,14 @@ namespace proc { ~DummyPlayerService() { notifyTermination_(&error_); } + + + /** conceptually, this serves as implementation + * of the DummyPlayer#start() function. But because + * this function sits \em behind the interface, it + * just returns an impl pointer. */ + ProcessImpl* start(); + }; diff --git a/tests/lib/allocationclustertest.cpp b/tests/lib/allocationclustertest.cpp index 447f18e5d..c818ad63e 100644 --- a/tests/lib/allocationclustertest.cpp +++ b/tests/lib/allocationclustertest.cpp @@ -183,7 +183,7 @@ namespace lib { // 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. + // all created object's dtors will be invoked. } From 4a2e5c276236b3f6e6cb0d22ed7fbbfcb40536cc Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Mon, 26 Jan 2009 22:34:09 +0000 Subject: [PATCH 100/216] Fixed the resources menu item --- src/gui/workspace/actions.cpp | 8 ++++---- src/gui/workspace/actions.hpp | 2 +- src/gui/workspace/workspace-window.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/workspace/actions.cpp b/src/gui/workspace/actions.cpp index 88a440103..4ed0a18a3 100644 --- a/src/gui/workspace/actions.cpp +++ b/src/gui/workspace/actions.cpp @@ -70,10 +70,10 @@ Actions::Actions(WorkspaceWindow &workspace_window) : // View Menu actionGroup->add(Action::create("ViewMenu", _("_View"))); - assetsPanelAction = ToggleAction::create("ViewAssets", - Gtk::StockID("panel_assets")); + assetsPanelAction = ToggleAction::create("ViewResources", + Gtk::StockID("panel_resources")); assetsPanelAction->signal_toggled().connect( - sigc::mem_fun(*this, &Actions::on_menu_view_assets)); + sigc::mem_fun(*this, &Actions::on_menu_view_resources)); actionGroup->add(assetsPanelAction); timelinePanelAction = ToggleAction::create("ViewTimeline", @@ -160,7 +160,7 @@ Actions::on_menu_edit_preferences() /* ===== View Menu Event Handlers ===== */ void -Actions::on_menu_view_assets() +Actions::on_menu_view_resources() { if(!is_updating_action_state) workspaceWindow.resourcesPanel->show( diff --git a/src/gui/workspace/actions.hpp b/src/gui/workspace/actions.hpp index 76034ac6e..a11b58cfd 100644 --- a/src/gui/workspace/actions.hpp +++ b/src/gui/workspace/actions.hpp @@ -66,7 +66,7 @@ private: void on_menu_edit_preferences(); - void on_menu_view_assets(); + void on_menu_view_resources(); void on_menu_view_timeline(); void on_menu_view_viewer(); diff --git a/src/gui/workspace/workspace-window.cpp b/src/gui/workspace/workspace-window.cpp index 76a67a4d8..0fe2d8377 100644 --- a/src/gui/workspace/workspace-window.cpp +++ b/src/gui/workspace/workspace-window.cpp @@ -117,7 +117,7 @@ WorkspaceWindow::create_ui() " " " " " " - " " + " " " " " " " " From 1084a12e8a204f87b02aca0d21aad2054656f917 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 31 Jan 2009 16:31:15 +0000 Subject: [PATCH 101/216] Added theme icons support, and a New Window menu command --- src/gui/window-manager.cpp | 73 +++++++++++++++++++------- src/gui/window-manager.hpp | 28 +++++++++- src/gui/workspace/actions.cpp | 10 ++++ src/gui/workspace/actions.hpp | 1 + src/gui/workspace/workspace-window.cpp | 2 + 5 files changed, 94 insertions(+), 20 deletions(-) diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index c227d4b5d..663ac3002 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -93,6 +93,8 @@ WindowManager::register_stock_items() add_stock_icon_set(factory, "panel-timeline", "panel_timeline", _("_Timeline")); add_stock_icon_set(factory, "panel-viewer", "panel_viewer", _("_Viewer")); + add_stock_icon_set(factory, "window-new", "new_window", _("New _Window")); + add_stock_icon_set(factory, "tool-arrow", "tool_arrow", _("_Arrow")); add_stock_icon_set(factory, "tool-i-beam", "tool_i_beam", _("_I-Beam")); @@ -144,14 +146,19 @@ WindowManager::add_stock_icon_set( bool WindowManager::add_stock_icon(Gtk::IconSet &icon_set, const Glib::ustring& icon_name, Gtk::IconSize size, bool wildcard) -{ +{ + // Try the icon theme + if(add_theme_icon_source(icon_set, icon_name, size, wildcard)) + return true; + // Try the ~/.lumiera/icons folder - if(add_stock_icon_source(icon_set, ustring::compose("%1/%2", + if(add_non_theme_icon_source(icon_set, ustring::compose("%1/%2", GtkLumiera::get_home_data_path(), ustring("icons")), icon_name, size, wildcard)) return true; - if(add_stock_icon_source( + // Try the local directory + if(add_non_theme_icon_source( icon_set, get_current_dir(), icon_name, size, wildcard)) return true; @@ -159,38 +166,68 @@ WindowManager::add_stock_icon(Gtk::IconSet &icon_set, } bool -WindowManager::add_stock_icon_source(Gtk::IconSet &icon_set, - const Glib::ustring& base_dir, const Glib::ustring& icon_name, - Gtk::IconSize size, bool wildcard) +WindowManager::add_theme_icon_source(Gtk::IconSet &icon_set, + const Glib::ustring& icon_name, Gtk::IconSize size, bool wildcard) { - ustring path; - Gtk::IconSource source; - + // Get the size int width = 0, height = 0; if(!IconSize::lookup(size, width, height)) return false; + REQUIRE(width > 0); + + // Try to load the icon + RefPtr theme = Gtk::IconTheme::get_default(); + REQUIRE(theme); + const IconInfo info = theme->lookup_icon(icon_name, width, + (IconLookupFlags)0); + if(info) + { + const ustring path(info.get_filename()); + if(add_stock_icon_from_path(path, icon_set, size, wildcard)) + return true; + } + + return false; +} + +bool +WindowManager::add_non_theme_icon_source(Gtk::IconSet &icon_set, + const Glib::ustring& base_dir, const Glib::ustring& icon_name, + Gtk::IconSize size, bool wildcard) +{ + // Get the size + int width = 0, height = 0; + if(!IconSize::lookup(size, width, height)) + return false; + REQUIRE(width > 0); + + // Try to load the icon + const ustring path(ustring::compose("%1/%2x%3/%4.png", + base_dir, width, height, icon_name)); + return add_stock_icon_from_path(path, icon_set, size, wildcard); +} + +bool +WindowManager::add_stock_icon_from_path(Glib::ustring path, + Gtk::IconSet &icon_set, Gtk::IconSize size, bool wildcard) +{ + Gtk::IconSource source; try - { - ustring path = ustring::compose("%1/%2x%3/%4.png", - base_dir, width, height, icon_name); - - INFO(gui, "Attempting to load icon: %s", path.c_str()); - + { // This throws an exception if the file is not found: source.set_pixbuf(Gdk::Pixbuf::create_from_file(path)); } catch(const Glib::Exception& ex) { - INFO(gui, "Failed to load icon: %s", path.c_str()); return false; } - + source.set_size(size); source.set_size_wildcarded(wildcard); icon_set.add_source(source); - + return true; } diff --git a/src/gui/window-manager.hpp b/src/gui/window-manager.hpp index 64783d250..66fd4b71f 100644 --- a/src/gui/window-manager.hpp +++ b/src/gui/window-manager.hpp @@ -103,9 +103,21 @@ private: **/ static bool add_stock_icon(Gtk::IconSet &icon_set, const Glib::ustring& icon_name, Gtk::IconSize size, bool wildcard); + + /** + * Loads an icon from a the icon theme + * @param icon_set The icon set to add the icon to. + * @param icon_name The name of the icon to load. + * @param size The size of the icon to load. + * @param wildcard This value is set to true if this icon is + * wildcarded. + * @return Returns true if the icon was loaded successfully. + **/ + static bool add_theme_icon_source(Gtk::IconSet &icon_set, + const Glib::ustring& icon_name, Gtk::IconSize size, bool wildcard); /** - * Loads an icon from a specific path and adds it to an icon set. + * Loads an icon from a non theme set. * @param icon_set The icon set to add the icon to. * @param base_dir The root icons directory to load from. * @param icon_name The file name of the icon to load. @@ -114,9 +126,21 @@ private: * wildcarded. * @return Returns true if the icon was loaded successfully. **/ - static bool add_stock_icon_source(Gtk::IconSet &icon_set, + static bool add_non_theme_icon_source(Gtk::IconSet &icon_set, const Glib::ustring& base_dir, const Glib::ustring& icon_name, Gtk::IconSize size, bool wildcard); + + /** + * Loads an icon from a specific path and adds it to an icon set. + * @param path The path to load from. + * @param icon_set The icon set to add the icon to. + * @param size The size of the icon to load. + * @param wildcard This value is set to true if this icon is + * wildcarded. + * @return Returns true if the icon was loaded successfully. + **/ + static bool add_stock_icon_from_path(Glib::ustring path, + Gtk::IconSet &icon_set, Gtk::IconSize size, bool wildcard); public: diff --git a/src/gui/workspace/actions.cpp b/src/gui/workspace/actions.cpp index 4ed0a18a3..fa89310d5 100644 --- a/src/gui/workspace/actions.cpp +++ b/src/gui/workspace/actions.cpp @@ -88,6 +88,10 @@ Actions::Actions(WorkspaceWindow &workspace_window) : sigc::mem_fun(*this, &Actions::on_menu_view_viewer)); actionGroup->add(viewerPanelAction); + actionGroup->add(Action::create("ViewNewWindow", + Gtk::StockID("new_window")), + sigc::mem_fun(*this, &Actions::on_menu_view_new_window)); + // Sequence Menu actionGroup->add(Action::create("SequenceMenu", _("_Sequence"))); actionGroup->add(Action::create("SequenceAdd", _("_Add...")), @@ -181,6 +185,12 @@ Actions::on_menu_view_viewer() workspaceWindow.viewerPanel->show(viewerPanelAction->get_active()); } +void +Actions::on_menu_view_new_window() +{ + g_message("New Window"); +} + /* ===== Sequence Menu Event Handlers ===== */ void diff --git a/src/gui/workspace/actions.hpp b/src/gui/workspace/actions.hpp index a11b58cfd..eb995fc02 100644 --- a/src/gui/workspace/actions.hpp +++ b/src/gui/workspace/actions.hpp @@ -69,6 +69,7 @@ private: void on_menu_view_resources(); void on_menu_view_timeline(); void on_menu_view_viewer(); + void on_menu_view_new_window(); void on_menu_sequence_add(); diff --git a/src/gui/workspace/workspace-window.cpp b/src/gui/workspace/workspace-window.cpp index 0fe2d8377..d79008367 100644 --- a/src/gui/workspace/workspace-window.cpp +++ b/src/gui/workspace/workspace-window.cpp @@ -120,6 +120,8 @@ WorkspaceWindow::create_ui() " " " " " " + " " + " " " " " " " " From cef0e0e0744d05f58507a8292734845fdc624d76 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 31 Jan 2009 18:12:04 +0000 Subject: [PATCH 102/216] Added WindowManager::new_window, and used it as the standard way of creaing the workspaces --- src/gui/gtk-lumiera.cpp | 6 ++--- src/gui/window-manager.cpp | 50 ++++++++++++++++++++++++++++++++++++++ src/gui/window-manager.hpp | 36 ++++++++++++++++++++++++--- 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index fd53d31f7..f112c613c 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -68,11 +68,9 @@ GtkLumiera::main(int argc, char *argv[]) WindowManager window_manager; window_manager.set_theme("lumiera_ui.rc"); + window_manager.new_window(project, controller); - WorkspaceWindow main_window(project, controller); - - kit.run(main_window); - + kit.run(); } diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index 663ac3002..b077b45dd 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -25,6 +25,9 @@ using namespace Gtk; using namespace Glib; +using namespace boost; +using namespace std; +using namespace gui::workspace; namespace gui { @@ -37,6 +40,22 @@ WindowManager::WindowManager() register_stock_items(); } +void +WindowManager::new_window(gui::model::Project &source_project, + gui::controller::Controller &source_controller) +{ + shared_ptr window( + new WorkspaceWindow(source_project, source_controller)); + REQUIRE(window); + + window->signal_delete_event().connect(sigc::mem_fun( + this, &WindowManager::on_window_closed)); + + windowList.push_back(window); + + window->show(); +} + bool WindowManager::set_theme(Glib::ustring path) { @@ -53,7 +72,38 @@ WindowManager::set_theme(Glib::ustring path) return true; } + +bool +WindowManager::on_window_closed(GdkEventAny*) +{ + list< shared_ptr >::iterator iterator = + windowList.begin(); + while(iterator != windowList.end()) + { + shared_ptr window(*iterator); + REQUIRE(window); + + if(!window->get_frame()) + { + // This window has been closed + iterator = windowList.erase(iterator); + } + else + iterator++; + } + if(windowList.empty()) + { + // All windows have been closed - we should exit + Main *main = Main::instance(); + REQUIRE(main); + main->quit(); + } + + // Unless this is false, the window won't close + return false; +} + GdkColor WindowManager::read_style_colour_property( Gtk::Widget &widget, const gchar *property_name, diff --git a/src/gui/window-manager.hpp b/src/gui/window-manager.hpp index 66fd4b71f..8599f7bd9 100644 --- a/src/gui/window-manager.hpp +++ b/src/gui/window-manager.hpp @@ -25,13 +25,22 @@ ** @see gtk-lumiera.hpp */ +#include "gtk-lumiera.hpp" +#include "workspace/workspace-window.hpp" + #ifndef WINDOW_MANAGER_HPP #define WINDOW_MANAGER_HPP -#include "gtk-lumiera.hpp" - namespace gui { +namespace model { + class Project; +} // model + +namespace controller { + class Controller; +} // model + /** * The centralised manager of all lumiera-gui's windows. **/ @@ -42,6 +51,15 @@ public: * Default constructor **/ WindowManager(); + + /** + * Creates a new window connected to a specified project and + * controller + * @param source_project The project to connect the window to. + * @param source_controller The controller to connect the window to. + **/ + void new_window(gui::model::Project &source_project, + gui::controller::Controller &source_controller); /** * Sets the theme of the lumiera-gui's. @@ -49,7 +67,8 @@ public: * will be found. **/ bool set_theme(Glib::ustring path); - + +public: /** * A utility function which reads a colour style from the GTK Style. * @param widget The widget to load the style out of. @@ -62,6 +81,13 @@ public: static GdkColor read_style_colour_property( Gtk::Widget &widget, const gchar *property_name, guint16 red, guint16 green, guint16 blue); + +private: + + /** + * An event handler for when a window has been closed. + **/ + bool on_window_closed(GdkEventAny*); private: @@ -142,6 +168,10 @@ private: static bool add_stock_icon_from_path(Glib::ustring path, Gtk::IconSet &icon_set, Gtk::IconSize size, bool wildcard); +private: + + std::list< boost::shared_ptr > windowList; + public: /** From 852377c1f1b3d0375363295bebb7e55fc3feff57 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 31 Jan 2009 18:49:44 +0000 Subject: [PATCH 103/216] Implemented New Window command --- src/gui/gtk-lumiera.cpp | 7 ++++--- src/gui/window-manager.cpp | 24 +++++++++++++++++++----- src/gui/window-manager.hpp | 5 ++++- src/gui/workspace/actions.cpp | 5 ++++- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index f112c613c..31d319b47 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -65,10 +65,11 @@ GtkLumiera::main(int argc, char *argv[]) Project project; Controller controller(project); - WindowManager window_manager; - window_manager.set_theme("lumiera_ui.rc"); - window_manager.new_window(project, controller); + WindowManager *manager = WindowManager::instance(); + REQUIRE(manager); + manager->set_theme("lumiera_ui.rc"); + manager->new_window(project, controller); kit.run(); } diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index b077b45dd..ec8596563 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -73,17 +73,31 @@ WindowManager::set_theme(Glib::ustring path) return true; } +WindowManager* +WindowManager::instance() +{ + // Initialized during first access + static WindowManager manager; + return &manager; +} + bool -WindowManager::on_window_closed(GdkEventAny*) -{ +WindowManager::on_window_closed(GdkEventAny* event) +{ + REQUIRE(event); + REQUIRE(event->window); + list< shared_ptr >::iterator iterator = windowList.begin(); + while(iterator != windowList.end()) { - shared_ptr window(*iterator); - REQUIRE(window); + shared_ptr workspace_window(*iterator); + REQUIRE(workspace_window); - if(!window->get_frame()) + RefPtr window = workspace_window->get_window(); + REQUIRE(window); + if(window->gobj() == event->window) { // This window has been closed iterator = windowList.erase(iterator); diff --git a/src/gui/window-manager.hpp b/src/gui/window-manager.hpp index 8599f7bd9..0f2f9c0e2 100644 --- a/src/gui/window-manager.hpp +++ b/src/gui/window-manager.hpp @@ -69,6 +69,9 @@ public: bool set_theme(Glib::ustring path); public: + + static WindowManager* instance(); + /** * A utility function which reads a colour style from the GTK Style. * @param widget The widget to load the style out of. @@ -87,7 +90,7 @@ private: /** * An event handler for when a window has been closed. **/ - bool on_window_closed(GdkEventAny*); + bool on_window_closed(GdkEventAny* event); private: diff --git a/src/gui/workspace/actions.cpp b/src/gui/workspace/actions.cpp index fa89310d5..f226775be 100644 --- a/src/gui/workspace/actions.cpp +++ b/src/gui/workspace/actions.cpp @@ -23,6 +23,8 @@ #include "actions.hpp" #include "workspace-window.hpp" +#include "../window-manager.hpp" + #include "../dialogs/render.hpp" #include "../dialogs/preferences-dialog.hpp" #include "../dialogs/name-chooser.hpp" @@ -188,7 +190,8 @@ Actions::on_menu_view_viewer() void Actions::on_menu_view_new_window() { - g_message("New Window"); + WindowManager::instance()->new_window(workspaceWindow.project, + workspaceWindow.controller); } /* ===== Sequence Menu Event Handlers ===== */ From 9e585ab5915f16c17b47bff094b2f8191ba7ef9b Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sat, 31 Jan 2009 19:30:58 +0000 Subject: [PATCH 104/216] Removed stupid WindowManager singleton --- src/gui/gtk-lumiera.cpp | 12 ++++++++---- src/gui/gtk-lumiera.hpp | 10 ++++++++++ src/gui/window-manager.cpp | 12 +++--------- src/gui/window-manager.hpp | 14 +++++++------- src/gui/workspace/actions.cpp | 2 +- 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index 31d319b47..87e2c34a7 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -66,14 +66,18 @@ GtkLumiera::main(int argc, char *argv[]) Project project; Controller controller(project); - WindowManager *manager = WindowManager::instance(); - REQUIRE(manager); - manager->set_theme("lumiera_ui.rc"); - manager->new_window(project, controller); + windowManager.init(); + windowManager.set_theme("lumiera_ui.rc"); + windowManager.new_window(project, controller); kit.run(); } +WindowManager& +GtkLumiera::get_window_manager() +{ + return windowManager; +} Glib::ustring GtkLumiera::get_home_data_path() diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index 9536f348b..07b36b290 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -39,6 +39,8 @@ #include #include "lib/util.hpp" +#include "window-manager.hpp" + extern "C" { #include } @@ -72,6 +74,8 @@ class GtkLumiera : private boost::noncopyable public: void main(int argc, char *argv[]); + WindowManager& get_window_manager(); + static Glib::ustring get_home_data_path(); /** @@ -98,6 +102,12 @@ public: * Returns tn alphabetical list of the application's authors **/ static const std::vector get_app_authors(); + +protected: + /** + * The application window manager object + **/ + WindowManager windowManager; }; /** diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index ec8596563..04f9ffdc9 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -22,6 +22,7 @@ #include "window-manager.hpp" #include "include/logging.h" +#include "workspace/workspace-window.hpp" using namespace Gtk; using namespace Glib; @@ -34,7 +35,8 @@ namespace gui { IconSize WindowManager::GiantIconSize = ICON_SIZE_INVALID; IconSize WindowManager::MenuIconSize = ICON_SIZE_INVALID; -WindowManager::WindowManager() +void +WindowManager::init() { register_app_icon_sizes(); register_stock_items(); @@ -73,14 +75,6 @@ WindowManager::set_theme(Glib::ustring path) return true; } -WindowManager* -WindowManager::instance() -{ - // Initialized during first access - static WindowManager manager; - return &manager; -} - bool WindowManager::on_window_closed(GdkEventAny* event) { diff --git a/src/gui/window-manager.hpp b/src/gui/window-manager.hpp index 0f2f9c0e2..341c25fcb 100644 --- a/src/gui/window-manager.hpp +++ b/src/gui/window-manager.hpp @@ -26,7 +26,7 @@ */ #include "gtk-lumiera.hpp" -#include "workspace/workspace-window.hpp" +//#include "workspace/workspace-window.hpp" #ifndef WINDOW_MANAGER_HPP #define WINDOW_MANAGER_HPP @@ -41,6 +41,10 @@ namespace controller { class Controller; } // model +namespace workspace { + class WorkspaceWindow; +} + /** * The centralised manager of all lumiera-gui's windows. **/ @@ -48,9 +52,9 @@ class WindowManager : private boost::noncopyable { public: /** - * Default constructor + * Initializes the window manager object **/ - WindowManager(); + void init(); /** * Creates a new window connected to a specified project and @@ -68,10 +72,6 @@ public: **/ bool set_theme(Glib::ustring path); -public: - - static WindowManager* instance(); - /** * A utility function which reads a colour style from the GTK Style. * @param widget The widget to load the style out of. diff --git a/src/gui/workspace/actions.cpp b/src/gui/workspace/actions.cpp index f226775be..e2679b7f1 100644 --- a/src/gui/workspace/actions.cpp +++ b/src/gui/workspace/actions.cpp @@ -190,7 +190,7 @@ Actions::on_menu_view_viewer() void Actions::on_menu_view_new_window() { - WindowManager::instance()->new_window(workspaceWindow.project, + application().get_window_manager().new_window(workspaceWindow.project, workspaceWindow.controller); } From 19e85a95d400c306425751aa874c55092c01cee7 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 31 Jan 2009 23:28:09 +0100 Subject: [PATCH 105/216] fix: better make the shared_ptr a member of the Handle class this change circumvents compiler uncertainities with the operator bool() and actually seems to be better design too... --- src/lib/handle.hpp | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/lib/handle.hpp b/src/lib/handle.hpp index e0dbaa661..cf2059923 100644 --- a/src/lib/handle.hpp +++ b/src/lib/handle.hpp @@ -68,27 +68,28 @@ namespace lib { */ template class Handle - : protected std::tr1::shared_ptr { + protected: + std::tr1::shared_ptr smPtr_; + public: - typedef std::tr1::shared_ptr SmP; /** by default create an Null handle. * Typically this is followed by activating * the handle by the managing service. */ Handle ( ) - : SmP() + : smPtr_() { } - Handle (Handle const& r) : SmP(r) {} - template Handle (shared_ptr const& r) : SmP(r) {} - template explicit Handle (weak_ptr const& wr) : SmP(wr) {} - template explicit Handle (std::auto_ptr & ar) : SmP(ar) {} + Handle (Handle const& r) : smPtr_(r.smPtr_) { } + template Handle (shared_ptr const& r) : smPtr_(r) { } + template explicit Handle (weak_ptr const& wr) : smPtr_(wr) { } + template explicit Handle (std::auto_ptr & ar) : smPtr_(ar) { } - Handle& operator= (Handle const& r) { SmP::operator= (r); return *this; } - template Handle& operator=(shared_ptr const& sr) { SmP::operator= (sr); return *this; } - template Handle& operator=(std::auto_ptr & ar) { SmP::operator= (ar); return *this; } + Handle& operator= (Handle const& r) { smPtr_ = r.smPtr_; return *this; } + template Handle& operator=(shared_ptr const& sr) { smPtr_ = sr; return *this; } + template Handle& operator=(std::auto_ptr & ar) { smPtr_ = ar; return *this; } /** deactivate this handle, so it isn't tied any longer @@ -97,14 +98,14 @@ namespace lib { * went out of scope, the associated implementation * reaches end-of-life. */ - void close () { SmP::reset(); } + void close () { smPtr_.reset(); } - typedef IMP* SmP::*__unspecified_bool_type; + typedef std::tr1::shared_ptr Handle::*__unspecified_bool_type; /** implicit conversion to "bool" */ - operator __unspecified_bool_type() const { return *this; } // never throws - bool operator! () const { return !SmP::get(); } // dito + operator __unspecified_bool_type() const { return &Handle::smPtr_; } // never throws + bool operator! () const { return !bool(smPtr_); } // dito @@ -119,15 +120,15 @@ namespace lib { Handle& activate (IMP* impl, DEL whenDead) { - SmP::reset (impl, whenDead); + smPtr_.reset (impl, whenDead); return *this; } IMP& impl() { - REQUIRE (SmP::get(), "Lifecycle-Error"); - return *(SmP::get()); + REQUIRE (smPtr_.get(), "Lifecycle-Error"); + return *(smPtr_.get()); } }; From ee950d62551ae3266fe8ab6fbf942a900e0d5dd5 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 30 Jan 2009 00:17:01 +0100 Subject: [PATCH 106/216] some cleanup and re-ordering --- src/common/interfaceproxy.cpp | 66 +++++++++++++++----------- src/include/dummy-player-facade.h | 2 - src/lib/handle.hpp | 29 ++++++----- src/proc/play/dummy-player-service.cpp | 5 +- src/proc/play/dummy-player-service.hpp | 4 +- 5 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 6d72dc967..8386aa343 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -28,31 +28,6 @@ using util::cStr; - -#include "include/guinotificationfacade.h" - -namespace gui { - - /** storage for the facade proxy factory used by client code to invoke through the interface */ - lumiera::facade::Accessor GuiNotification::facade; - -} // namespace gui - - - -#include "proc/play/dummy-player-service.hpp" - -namespace proc { - namespace play { - - /** storage for the DummyPlayer facade proxy factory... */ - lumiera::facade::Accessor DummyPlayer::facade; - -} } - - - - namespace lumiera { namespace facade { @@ -117,10 +92,30 @@ namespace lumiera { Proxy::close(); } - + } // namespace facade + +} // namespace lumiera + + + + /* ==================== GuiNotification =================================== */ +#include "include/guinotificationfacade.h" + +namespace gui { + + /** storage for the facade proxy factory used by client code to invoke through the interface */ + lumiera::facade::Accessor GuiNotification::facade; + +} // namespace gui + + + +namespace lumiera { + namespace facade { + typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 0) , gui::GuiNotification > Handle_GuiNotification; @@ -144,7 +139,10 @@ namespace lumiera { template void openProxy (Handle_GuiNotification const&); template void closeProxy (void); - + } // namespace facade + +} // namespace lumiera + @@ -152,6 +150,20 @@ namespace lumiera { /* ==================== DummyPlayer ======================================= */ +#include "proc/play/dummy-player-service.hpp" + +namespace proc { + namespace play { + + /** storage for the DummyPlayer facade proxy factory... */ + lumiera::facade::Accessor DummyPlayer::facade; + +} } + + +namespace lumiera { + namespace facade { + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) , proc::play::DummyPlayer > Handle_DummyPlayer; diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h index b10da3684..c2750e1c8 100644 --- a/src/include/dummy-player-facade.h +++ b/src/include/dummy-player-facade.h @@ -86,8 +86,6 @@ namespace proc { class Process : public lib::Handle { - friend class ProcessImpl; - public: void play(bool); void* const getFrame(); diff --git a/src/lib/handle.hpp b/src/lib/handle.hpp index cf2059923..30bbca52f 100644 --- a/src/lib/handle.hpp +++ b/src/lib/handle.hpp @@ -87,11 +87,23 @@ namespace lib { template explicit Handle (weak_ptr const& wr) : smPtr_(wr) { } template explicit Handle (std::auto_ptr & ar) : smPtr_(ar) { } - Handle& operator= (Handle const& r) { smPtr_ = r.smPtr_; return *this; } + Handle& operator=(Handle const& r) { smPtr_ = r.smPtr_; return *this; } template Handle& operator=(shared_ptr const& sr) { smPtr_ = sr; return *this; } template Handle& operator=(std::auto_ptr & ar) { smPtr_ = ar; return *this; } + /** Activation of the handle by the managing service. + * @param impl the implementation object this handle is tied to + * @param whenDead functor to be invoked when reaching end-of-life + */ + template + Handle& + activate (IMP* impl, DEL whenDead) + { + smPtr_.reset (impl, whenDead); + return *this; + } + /** deactivate this handle, so it isn't tied any longer * to the associated implementation or service object. * When all handles have either been deactivated or @@ -106,24 +118,11 @@ namespace lib { /** implicit conversion to "bool" */ operator __unspecified_bool_type() const { return &Handle::smPtr_; } // never throws bool operator! () const { return !bool(smPtr_); } // dito - + protected: - - /** Activation of the handle by the managing service. - * @param impl the implementation object this handle is tied to - * @param whenDead functor to be invoked when reaching end-of-life - */ - template - Handle& - activate (IMP* impl, DEL whenDead) - { - smPtr_.reset (impl, whenDead); - return *this; - } - IMP& impl() { diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 892237d41..27f78559f 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -291,8 +291,9 @@ namespace proc { /* === Process Implementation === */ - ProcessImpl::ProcessImpl() : fps_(0), play_(false), imageGen_(0) {} - ProcessImpl::~ProcessImpl() {} + ProcessImpl::ProcessImpl() + : fps_(0), play_(false), imageGen_(0) + { } DummyPlayer::Process diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index 0648f982a..92c4d27ca 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -67,7 +67,8 @@ namespace proc { * ProcessImpl instance and have to manage the lifecycle manually. */ class ProcessImpl - : public lumiera_playprocess + : public lumiera_playprocess, + boost::noncopyable { uint fps_; bool play_; @@ -77,7 +78,6 @@ namespace proc { public: ProcessImpl() ; - ~ProcessImpl(); /* Implementation-level API to be used By DummyPlayerService */ From c01657b93fd2ff73f476197423290be99e5e0ba7 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 30 Jan 2009 17:55:01 +0100 Subject: [PATCH 107/216] continued achitecture planning for the Dummy Player --- doc/devel/draw/PlayerArch-1.svg | 649 +++++++++++++++++++++++++++----- wiki/draw/PlayerArch1.png | Bin 0 -> 56668 bytes wiki/renderengine.html | 41 +- 3 files changed, 581 insertions(+), 109 deletions(-) create mode 100644 wiki/draw/PlayerArch1.png diff --git a/doc/devel/draw/PlayerArch-1.svg b/doc/devel/draw/PlayerArch-1.svg index 519d5317d..0b28c1478 100644 --- a/doc/devel/draw/PlayerArch-1.svg +++ b/doc/devel/draw/PlayerArch-1.svg @@ -13,7 +13,7 @@ id="svg2" sodipodi:version="0.32" inkscape:version="0.45.1" - sodipodi:docbase="/mnt/Lager/heim/devel/lumi/doc/devel/draw" + sodipodi:docbase="/home/hiv/devel/lumi/doc/devel/draw" sodipodi:docname="PlayerArch-1.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" version="1.0"> @@ -25,8 +25,8 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="2" - inkscape:cx="346.20838" - inkscape:cy="304.01881" + inkscape:cx="426.20838" + inkscape:cy="310.01992" inkscape:document-units="px" inkscape:current-layer="svg2" inkscape:window-width="1668" @@ -138,72 +138,68 @@ id="rect4196" width="180.16087" height="80" - x="190.12445" - y="130" /> + x="160" + y="100" /> + width="99.876717" + height="49.91003" + x="220.07802" + y="250" /> + x="460" + y="450" /> play thread + x="470.59406" + y="460.2439" + style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">TickService put(Frame&) + x="362.5" + y="402.5" + style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans;fill:#ff5555">display(Frame&) PlaybackController - + x="163.5" + y="113.5">PlaybackController @@ -219,18 +215,6 @@ x="70" y="290" style="font-size:8px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">start(...) - PlayProcess start_playback_thread() - - + sodipodi:role="line">play() yields Proc (or Backend?) + x="210" + y="380">Proc (or Backend?) Displayer (Proxy) PlayerFacade (Proxy) - actuallytalks to... libCommon + x="260" + y="320">libCommon + y="389.93243" /> PlayerService @@ -462,7 +432,486 @@ id="tspan2255">PlayContext + start(...) + start(...) + + Process + + + Handle<ProcessImpl> + + yields + + + + has_a + + + Display (iface) + DisplayFacade (Proxy) + + + + Displayer + DisplayService + + + + Displayer + Displayer + Displayer + open(...) + + + + CL Interface + + close() + getHandle(slot) + getHandle(slot) + getHandle(slot) + + yields + PlayerImpl + + has_a + + invokes (periodically triggered) + + periodically + + + + CL Interface + + pause() + stop() + attach_viewer() diff --git a/wiki/draw/PlayerArch1.png b/wiki/draw/PlayerArch1.png new file mode 100644 index 0000000000000000000000000000000000000000..76bb3712a21d2302c114ab47c62ffdd2d3c8ab44 GIT binary patch literal 56668 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 Q%76gESvq3NPWW8^2OKeuP5=M^ literal 0 HcmV?d00001 diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 806303db6..bf608f166 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -1375,16 +1375,29 @@ Thus, the Proc-Layer exposes (one or several) facade interfaces for the GUI to u -
-
Considering how to interface to and integrate with the GUI Layer. Running the GUI is //optional,// but it requires to be [[started up|GuiStart]], installing the necessary LayerSeparationInterfaces.
+
+
Considering how to interface to and integrate with the GUI Layer. Running the GUI is //optional,// but it requires to be [[started up|GuiStart]], installing the necessary LayerSeparationInterfaces. As an example how to integrate the GUI with the lower layers, in 1/2009 we created an PlayerDummy, which "pulls" dummy frames from the (not yet existing) engine and displays them within an XV viewer widget.
+
-
+
Starting up the GUI is optional and is considered part of the Application start/stop and lifecycle.
 * main and AppState activate the lifecyle methods on the ~GuiSubsysDescriptor
-* loading a GuiStarterPlugin creates an instance of the notification interface within the InterfaceSystem
-* its implementation (within GuiStarterPlugin) is linked against the GuiNotificationFacade, i.e. the actual implementation. This link is hard wired.
-* the process of loading this GuiStarterPlugin creates an interface ref on the calling side, which is made available through the usual singleton factory embedded within the GuiNotificationFacade interface. {{red{TODO current solution doesn't handle shutdown correctly}}}
-* activating this singleton factory yields the (single) instance of the forwarding proxy, which calls through this interface ref.
+* loading a GuiStarterPlugin actually
+** loads the GUI (shared lib)
+** creates instances of all the GUI services available through LayerSeparationInterfaces
+*** GuiNotificationFacade
+*** DisplayFacade
+** Finally, the ~GTK-main() is invoked.
+
+!public services
+The GUI provides a small number of public services, callable through LayerSeparationInterfaces. Besides that, the main purpose of the GUI of course is user interaction. Effectively the behaviour of the whole system is driven by GUI events to a large extent. These events are executed within the event handling thread (~GTK-main-Thread) and may in turn invoke services of the lower layers, again through the respective LayerSeparationInterfaces.
+But the question of special interest here is how the //public services// of the GUI are implemented and made accessible for the lower Layers. Layer isolation is an issue here. If implemented in a rigorous manner, no facility within one layer may invoke implementation code of another layer directly. In practice, this tends to put quite some additional burden on the implementer, without and obvious benefit. Thus we decided to lower the barrier somewhat: while we still require that all service invoking calls are written against an public LayerSeparationInterface, actually the GUI (shared lib) is //linked// against the respective shared libs of the lower layers, thus especially enabling the exchange of iterators, closures and functor objects.
+
+Note that we retain strict isolation in the other direction: no part of the lower layers is allowed to call directly into the GUI. Thus it's especially interesting how access to some GUI public service from the lower layers works in detail.
+* when the GUI plugin starts, instances of the Services implementing those public service interfaces are created.
+* these service objects in turn hold an ~InstanceHandle, which cares to register and open the corresponding C Language Interface
+* additionally this InstanceHandle is configured such as to create an "facade proxy" object, which is implemented within liblumieracommon.so
+Now, when invoking an operation on some public interface, the code in the lower layers actually executes an implementation of this operation //on the facade proxy,// which in turn forwards the call through the CL interface into the GUI, where it is actually implemented by the corresponding service object instance.
 
@@ -1801,11 +1814,11 @@ From experiences with other middle scale projects, I prefer having the test code [img[Example: Interfaces/Namespaces of the ~Session-Subsystems|uml/fig130053.png]]
-
+
Lumiera uses a 3-layered architecture. Separation between layers is crucial. Any communication between the layers regarding the normal operation of the application should //at least be initiated// through ''Layer abstraction interfaces''. This is a low-impact version of layering, because, aside from this triggering, direct cooperation of parts within the single Lumiera process is allowed, under the condition that is is implemented using additional abstractions (interfaces with implementation level granularity). We stick to the policy of //disallowing direct coupling of implementations located in different layers.//
 
 To implement such a structure, each layer separation interface actually is comprised of several parts:
-* an CLI interface to be installed into the InterfaceSystem
+* an C Language Interface ("CL Interface") to be installed into the InterfaceSystem
 * a facade interface defining the respective abstractions in terms of the implementation language (C or C++)
 * a implementation object on the service proiding side which is directly addressed by the implementation instantiated within the InterfaceSystem
 * a proxy object on the client side, which usually is given inline alongside with the CLI interface definition.
@@ -2784,6 +2797,16 @@ We need a way of addressing existing [[pipes|Pipe]]. Besides, as the Pipes and T
 <<tasksum end>>
 
+
+
Joelholdsworth and Ichthyo created this player mockup in 1/2009 to find out about the implementation details regarding integration and colaboration between the layers. There is no working render engine yet, thus we use a ~DummyImageGenerator for creating faked yuv frames to display. Within the GUI, there is a ~PlaybackController hooked up with the transport controls on the timeline pane.
+# first everything was contained within ~PlaybackController, which spawns a thread for periodically creating those dummy frames
+# then, a ~PlayerService was factored out, now implemented within Proc-Layer (probably to be relocated into the backend for the final version). A new LayerSeparationInterface called ''~DummyPlayer'' was created and set up as a [[Subsystem]] within main().
+# the next step was to support multiple playback processes going on in parallel. Now, the ~PlaybackController holds an smart-handle to the ~PlayProcess currently generating output for this viewer, and invokes the transport control functions and the pull frame call on this handle.
+# then, also the tick generation (and thus the handling of the thread which pulls the frames) was factored out and pushed down into the mentioned ~PlayProcess. For this to work, the ~PlaybackController now makes a display slot available on the public GUI DisplayFacade interface.
+
+[img[Overview to the dummy player operation|draw/PlayerArch1.png]]
+
+
Playlist is a sequence of individual Render Engine Processors able to render a segment of the timeline. So, together these Processors are able to render the whole timeline (or part of the timeline if only a part has to be rendered).
 

From 45668836bafa1d5001e4ff0b05019bc6ec558409 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 31 Jan 2009 23:05:41 +0100
Subject: [PATCH 108/216] start fleshing out a display facade interface

---
 src/include/display-facade.h      | 125 ++++++++++++++++++++++++++++++
 src/include/dummy-player-facade.h |   1 +
 2 files changed, 126 insertions(+)
 create mode 100644 src/include/display-facade.h

diff --git a/src/include/display-facade.h b/src/include/display-facade.h
new file mode 100644
index 000000000..d46afe2ca
--- /dev/null
+++ b/src/include/display-facade.h
@@ -0,0 +1,125 @@
+/*
+  DISPLAY-FACADE.hpp  -  accessing a display for outputting frames
+ 
+  Copyright (C)         Lumiera.org
+    2009,               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 GUI_INTERFACE_DISPLAY_H
+#define GUI_INTERFACE_DISPLAY_H
+
+
+
+struct lumiera_displaySlot_struct 
+  {
+    unsigned int index_;
+  };
+
+typedef struct lumiera_displaySlot_struct LumieraDisplaySlot;  ///< value semantics
+
+
+struct lumiera_displayFrame_struct 
+  { 
+    void* const buff_;
+  };
+typedef struct lumiera_displayFrame_struct LumieraDisplayFrame;
+
+
+
+
+#ifdef __cplusplus  /* ============== C++ Interface ================= */
+
+#include "include/interfaceproxy.hpp"
+
+#include 
+#include 
+
+
+
+namespace lumiera {
+  
+  using std::tr1::function;
+
+  
+//  class ProcessImpl;
+  
+  
+  /******************************************************************
+   * Interface for outputting frames to an (already allocated) viewer
+   * or display. The viewer is addressed by an "slot" handle, which the 
+   * client receives from some other public interface. This reflects
+   * the fact that is's not up to the client to create an display or
+   * viewer; rather they are provided by some internal facility and
+   * the client code is handed out an display handle in the course
+   * of a larger interaction, like starting a player. This way,
+   * when the client code actually is about to produce output, 
+   * he can allocate the slot and obtain a Displayer (functor)
+   * for pushing the frames out. (Users of the C Language Interface
+   * have to carry out these steps manually and also have to care
+   * for cleaning up and deallocating the slot).
+   * 
+   * @note This is a first draft version of a rather important 
+   *       interface. The current version as of 1/2009 just serves
+   *       a mockup player implementation. You can expect this interface
+   *       to change considerably if we get at devising the real player.
+   * @see dummy-player-facade.hpp
+   * @see gui::PlaybackController 
+   * 
+   */
+  class Display
+    {
+    public:
+      
+      
+      /**
+       * Functor for pushing frames to the display
+       */
+      typedef function Displayer;
+      
+      
+      /** allocate an already existing display/viewer for output
+       *  @return a functor representing the frame sink */
+      virtual Displayer getHandle(LumieraDisplaySlot)   =0;
+      
+      
+      virtual ~DummyPlayer();
+    };
+  
+    
+
+  
+} // namespace lumiera
+
+
+
+extern "C" {
+#endif /* =========================== CL Interface ===================== */
+
+
+#include "common/interface.h"
+
+LUMIERA_INTERFACE_DECLARE (lumieraorg_Display, 0
+                          , LUMIERA_INTERFACE_SLOT (void,               put,(LumieraDisplaySlot, LumieraDisplayFrame, bool))
+);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h
index c2750e1c8..8bea6568a 100644
--- a/src/include/dummy-player-facade.h
+++ b/src/include/dummy-player-facade.h
@@ -24,6 +24,7 @@
 #ifndef PROC_INTERFACE_DUMMYPLAYER_H
 #define PROC_INTERFACE_DUMMYPLAYER_H
 
+#include "include/display-facade.h"
 
 
 struct lumiera_playprocess_struct { };

From 6473971d605cb766166a292e8dbf2e47c6b39287 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sat, 31 Jan 2009 23:05:49 +0100
Subject: [PATCH 109/216] fix a typo

---
 doc/devel/draw/PlayerArch-1.svg |  13 ++++++++++---
 wiki/draw/PlayerArch1.png       | Bin 56668 -> 56700 bytes
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/doc/devel/draw/PlayerArch-1.svg b/doc/devel/draw/PlayerArch-1.svg
index 0b28c1478..0342c6914 100644
--- a/doc/devel/draw/PlayerArch-1.svg
+++ b/doc/devel/draw/PlayerArch-1.svg
@@ -25,8 +25,8 @@
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
      inkscape:zoom="2"
-     inkscape:cx="426.20838"
-     inkscape:cy="310.01992"
+     inkscape:cx="419.63217"
+     inkscape:cy="331.20952"
      inkscape:document-units="px"
      inkscape:current-layer="svg2"
      inkscape:window-width="1668"
@@ -798,7 +798,7 @@
        y="420"
        x="310"
        id="tspan2441"
-       sodipodi:role="line">PlayerImpl
+       sodipodi:role="line">ProcessImpl
   attach_viewer()
+  
 
diff --git a/wiki/draw/PlayerArch1.png b/wiki/draw/PlayerArch1.png
index 76bb3712a21d2302c114ab47c62ffdd2d3c8ab44..2a8e24e3540819a51cb60c763ba20ec3fc6c1dae 100644
GIT binary patch
literal 56700
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

literal 56668
zcmcG#cQl)C{5~GBYFF(UDxu!C*t5$B#hX^GSk(r#qV|res$HQa6fLP5rPNBRh+P^~
zs)$h`HEXs;>|gr+e7@&=|NNcbIX@@P^CWqmJNI*s>vi4N>$;QwwKU;i6=nqh030yW
z>ox!Y@FxI3M>xks`=qeGwUl;X2)YWpb&mEIeeUiP+ItqHsY4L$`tiU2bXPAGgwsA0
z3O2G2z8QcB4s(BS4-gg>rs(bO6XfBJyr&rOz_VaOPZ$7@0Kl$axfT9mtuQRl_WSpw
z*;(b_x;p_Ae7{y-}8cQ
zdAlcdW9~IPc%i(x&e|VKn5F5cA%m#Rpp6%;;|@`L7$F!M{NF1lDdjVd
z+8F=;SoA+%X5wizd2amuI~(xXZQEU2sV_=KNt_;Q6CUjWO$O|u6Gd540?Y<=m6emm
zJFj@2J!2y!%fwE@V@zq!h_L!wx4X|@LWkif7M=_`4d&-`#*(d%NjAK+`6Yjj=BcEn2hDeV^X;H+l
z9`E53+=bolx4;TCBY${dmQ?vC2vVxesMMC{9}I&gI0!oke-}W;kc2q_B*BZ)FI6{r-JxVfg%$
zOR9i+qm}7{=j9&vCY#Ul_tt#`^&`dH8fi&kD=&(Ikd+rSuAP%9e+W}
zs`U@{C1L2>DMPyNq)JWV&dCF#S$yx>+JcVDZ-ngnTP9ZL1mQ^6DOTPePt!&&17iEt^wZG^s3|V;ck@k$x(3%DG<+f+g9C>)|Kx%
z*REq(35y--luPvvF~Rn&hTM#z_f_?lq6a!Z1JG)$;8?j#)rq7H567
zRonf=xGdW6z8ea*xQzyTYxky+=mjqIT|B9IrOfGOYa8ZZ``s@3;9eNv{!?kX1QFg}
zVpCVmr)8Rytg0R2kvz{r^JaWb4qG?UNr=lLWDY=K$XK+y#y5V!8+O*;A`16OK>(e>_vu^r#_CN1h1Hk{SuFJMMZ_Cf+F#V_u+&@=5Y=>RF^76s3c>wmOP?XovU
zzpn#=nR*49#&u41dQ^Neeeg>?jYHW_rRfC%fA@P*hKdSN?o5vx+(qL`uxADCWBh{M
z6>n-%8nphsX4C^(dzm0jDvGjX`jP%CPGxA7Z+t6_)-v(_BWL%2jc*Q?hrL>!I#Pzb
zzhUR5hv*UsZ2k+!+Btt=*;^Yf$G+v)-xd_FpS5vS6}!1krL^}Xx}(NLMt|!PCOyXD
zGsKv!?Z(+MZxge;S$-<|+DWvk+_UoYQ-XgnU|G?cW{L@$Y;vZ}%M5kRn=1)EpNq#9
za+?`Hx@+)WBn#=7PWXcw788rJQF5J&4(ti8>#n15Rru0%r%~K_;uaA#EIc7v7!d0>d0R
z>rDV4SoRf2O)w8%2
zsIJZ|>GuTVlP4$lP6<{+zh#15P;PmUpWfsb#mpn)0+6q|Y2`d*spB1fmu}ti-oofG
zGzzH2At;=I0q9;lxlr$yRn)a6OK7^5PYlorJ%&>Hika59m3TY>5+`zIFXDav1f-nA
z^_0GatGv!gNeQZ`5-~RFSs(pgh#F<92ccXo_7|mTW1#xs4fY%`tcnI+VN&a9Bo$h?
z+ULJd5hSZ&b5-Q#6QkgP_7JsYi;4gh@;7AYOvzo_zf8)z2itE(yZzZLUDUUl8Fht;
z-U}%ACUN2__r*ZLTBDnZfm^mftgG9YZsInr13x5<{v}TYiI2Nu8th^pIcpzyHO`i~
zws&w}RiTv!6E^z4Xw-kSfOZ!c_Wy=m-C!S0S($3y48;d7Y?z?cq%_$@wYGjg2)if?
ziaFYwVb&_2J~2hG4T)+Y$@B{w*U@Us6_NonqReldH!Q(0Xr1cU_US^?fua7(`+x7!
z^~q*^gXPN-{yjGQG@hQ>--UKrKY`dBFl!z^Gcc2Rw~0JL`~0->?_DOdZ80FFFc2E6
z4U3OfyiWXdY~Qt$g^3w^NtlhV!Mh{&u0b0<0FVY-7>t-<{jNo6x*1vTCH;?0mT$6C
zO!j>CV$=)aU4%C8;=59CLjL1&p5V9d+FCwT>r7$#rL0qLi#_@eM81{nq
z^OB`MP=k(lRt}O5s3fdO!)8#1bbcskd~?C8LBDucIvx~1_vgU5!{*CTFF{*IT|o3d
zsCrZz6+6S9ckY(yM@DKZ=DUW8C%BMfEtQQBHgwl{J^ubnew?ulbN<=i+G2jizb*%j
zOH+nJ)3JsHq(%UmVU2HLF`%qzpYbDrO~d3KT8Hk8ajc7vy+_>wU(H%l<-YI7o8cGGlfc$H#dMo$Hw#)zTVD;{njKwEJhRGFsjpz6
zIHUSdUGX}{lZGil3~TgnzowlWaMUW--i3}fGAWC1{*r4T1mu8&z>;`HrcpouzzW#4
zwRF#gd?~`cmhSNEL-ah&Skv+NF8~Fpf)I0~4PmFND
zbaJK>$nv%8Iwa(UOX7n?pSwrHbV`7@Vl#bbaASe72wxqr01V^#I|8oR*ue$Q=qCCI
zI)J0Tur77dFJNK(KH;q;@hUnacP9tC51Enney4nNnP^lOkcAHY2jVQfVhQ_07LK65
z?=f42KDF0LHg&WhMxdEsk#@u$w1(f;GY#}9c*Pyo1!KF$U3E-5Lk
zu)+dNBb|w|J>5e4^8@AW@34Io@pq)rvsYjYhXb2nQag6T6H!n=TE+jyn?@6koO0GV
zd^tW7+MYGM#KxHkb44>AORVs~oM4XjL=%+_ebzKaZoBn|!Ljxfn5iQ|$dn;=VT|E!!Wj|;*Q
zAl3YRldwo9;u3m;vG@9{Nw2yB+-7(HZIHcF2M^r#glk);y%vKMLROq;u>1ns46YXL
zi!zNAj*}IVU15W@5WXs5z(KO!?^X9lcmys?0k7SeEuRps(f^0wP?UUPi%U+Lq3ltrl!ydJJKl%qCK^c}ronyN^5n{K>qNueXz4W75|hj^Fh
zb{0Kq%N-)m@m6jH0hiDuv%tR4?F02orc?3p+XqZg-3pu}LPJOka{6>92!8Fm!76k*
zG|HB|j5BPZbjAhFzH~`Fk@YXSDH8IQr!NT@_vBBge6pF|1t
zTaWiFtpS}Fqnk31#%r)YDDmkizml`4o`AZrQ57M3V0bzhQ!ndcFDL7e2(2H6obXWP
zPH)hyvCE@;M(M=U{>aQx27YRd(Jw#onb4ijK?^*IkYcLn7)WZ-OH8>4e(tNCTkG*|@iFm{<|Ii6B
zdtOjLXi2P5wfXd$kS!GvGAMAcYyO2l)&Al^<%&6#`i5F?e!SlJ(@y*O{kRMM(xZGh
z81WFX*L!yC2tyxpRY(>e*$W5^=m5>l4|$LlYd)!LH9q8oqd$Q|1^7XH5%un#guzRY
z2ZHI7=xiL5gtv;GUg2D4^c(85IF*SCL8>U$*6=OR6?GP>hIJQJQSZ+2{MA4H}SUl&d`TFnq(*ju+beUefy~WO64>RKHL>J$TdG~HXAN$ue9-<
zfou!^91A@>bcz-_b{!eJ1P`B8IGklFUY4e_n?oqL_BL^j&u^x(?G~21s&0t&6{l?8
zjFmb-A8?E;jc+BNrg(XHz~ttDN%KWy{h|ZC)V#g9ThW)Ldz)&zeyAB3
z@;v-?pPIU}O@)5qZMz@Nu`6ety`|#EJWd;SX
zhhMCTa)?%MklF}Jzz)t&Tqo~S?MI|1_&WSN)y;s8Mldr1ZnW+l
zfvgvAl11I@qHXd3zW#^+vyaSH8`h~xAlD?e@|bNFH%a&t{@UogfHmQTeUD)pxJ7!Qc+N9tye+1MYdxgVpV
zUeRO2S%G{~I^aR}2Q#-P7~7t6PHwEXa7?$iE(Fyw|A~{T)dFs-9Agx~hpE($jGSq1
z*G0y_I{6s=;*SVxLJ>P66
z3Jg=_vymu1TIQQ#jV7O7Xy(xyB)Fu#{syDEot0sW=gL50<*vpGw{NF>7Pp!Mo?Mg+
z<_|d@B1k9RE{AT_VEFQj`$v@;V-+h{wYWi_Q#}%8KTAXdy}6e)OP
ztb3>2UcsoSAUnk`aA;x^u%E!y8_8RLu
zZ*On%!SuI1+oX1tW_h+e>*&Q@LSA44akVX)$m^npug=;9WYWFKvl9gZ1e6rv$+A8=tYl3fa
zCijWu^6I#2_tD^V3C7f!!?tucav<6-JBQR&cMkS
z;LcCdflvXRGF3@t^GE#V-J7`$^+Jlbnz|CFDO>#%m+9CRF{HLZhhC-j7Cj8_G`9iQSBP&?lVCXwpT97fO
zVt?t<3z+V_fwmoGcu|vzQ{e@*k1-j@*3rdrf=V+|W8+W-+maO}f*^wL#jUtHpdGcV
zp{uVBhT}N&JR-
z694Pt<$Y81-9s$L!L*T8^vgtVuAGATGXbT?ejavklp(WbAPH2=+k1iYG2(WD5_4ED
z~hc$y>yX2Rde}QY*6LKxhH)Jso=8#28PIo^2ST!NG1yTj<3X
zcOVMptucG&qe}{&v|moMjw!EeEII8|;aMHDHKx}!F6f)%apn*gD$(4X+@i(p?HJ#k
z2s-i|s4h>lJ1BLk>s?yAe8WPY(m5DW_>ymtF8#01rRSVeeUgvJ!}BazH{R5;#DRv}
zk(t=iz?+}ml!u)Y6WX=J+ck1#HMC)a%3WXSTpS1nws9!zlmwp2gs1(9o0o%=m3kSu
z{@nyEr^zF~a
z)Oy=g6aV`OXPZ`?jNRAF-h1*Z)elqh$zoe+h1rx(8r1p_wKm5I$dD6AbM6vhZAi6V
z6I@8hbPZPONjz2GQmOkl^837j0^=~5VjHFR2jPCd{`P1ybfdw=tGlD`>w1^TYeWB|
zR(2$t0fM(GT7Z12zfOZK_uIo^B}1JmC&LI0jSRjIqLXBgK3!^FtEm4_kSR>pb1ta!
zO5mAN@{!AQ-^EC~zv!d>Ge|&eE1ueaAv;<2bG2^O)^u-vx!y~M=l`*Ch(c-)_cRxb@Pp8Wt
z2dGHmlx1hMzd*W@cICvKpr!?Ca!DGJZBo7Nnk~#W!y2=_qg4kOsu|L+=N}pXmcbxcIHG^+m
z@3B(4-Mo?*wD6)H3~|k+v#~8;et7HzH@N#Q-k-yUWSGo0Y-ddRf(*)H36EZvK~)ph
z#8(TOi19^R-U7rn_kxhjB?{aWl4Ygr*|&(J^s~
z;tmL7d|42jBgl#5?4RKh3r&Jfm4S4QjAl-rOl_mOY62F_}`U%hw7Xy9&_D{NWk
zeNo$WoSZ{Icu>RFF8SM+u_+ST4I6WFpG$1KCairE(rc&RxTVfbecL_PVEgrd1dG4F
zHDSeX>8LHQ!6PllbiP6Yj64-l9Q+yb>hicCmY5kN*(QF#x#CgN(210yTDKIoIO^GJ3UnHtf
zLP;{un{{b&&tPY`-sHEt`NP~F`NMv%J=6_xnZ2Id|6|oHc4q1a5z@Azrl5YOcnvnmW(sXb3zFZo)zeCTERD
zTXV4AAR*6!%djy}V)b2=Ddx_WU%APdr55z>?u{2u!Q&H1e1OYnfd
z#L7g)nyY^A+r4jE0sRwuS;65qkMh9%Ygbr*_FDz=75x?`-z7`I(g$;JS6>9V@l37J
zAM;JLB`>KzhN3*;UFrrWR$!{RQr-~qO|laDBPFoY>Pc4|oj;=nCcZKX@E!jHf0_K$
zyP;hfDX`Ty|N7-4DHLUUt&?MTii>*P2IM9~2Eu#>FB@iqWudgp<;|xJ*;sdU8#=fe
z8xr^mmw@HQUkNWsyMngNQnM#sf`yqon%g8zoYi2hP=%$d^d&>7BKIS}eo8BTu&P8v
zwDMP7&UPhlHrT$ouwq3qHU`ov?Y-c2_5jvmELQbM+WY#Bw;${cOc=c40XyrE>5Up(
zlO)5)5-?{($GQdjE)cPo
znt)?uR%~IqkECPru(@~A4ob11=u=7BlD$YP?AEBEJy8k5@oXmizl`jRZNNoF`2mi;#%ufZ`_CG*x$PN?pFEz+9%c)C
z%Z!YSKE1G<>4O;q45j#Sxe2*J$Xxgl{4Z*1cPCy8E^;cprSO$0{L*SPaDulOS$zNZ
zj2SJjwFJU%;7joc+*Twj^3oP(tu#{HV5pJKg<;a@0~BmaUl_QqO|^&W4C#u53)>3`
z(h=xiJZ2k<0~RrkF|L*u`^4d)!5PVsmgpT}#p|<=GvC8<&`$_u6i+=#BJ)h&!N0EykaM$w
z12#PnA{3rXS~6_b=tB|5WHdWfa6)Eal$UPD(~q<*W^sG80707B3R@6`Tyeu2#nQ@)+<0|suzb^8W6qA_N~oHOK4V3vqj5
za3=->p~3{8CZ!%3UDU97WhD0JQ8oS^UL6mnG2^x}7l7-l+uwVNaK=%mTKmFeN3tt56@WLV+8-QIKk>D#GS@UnOm3!TmUaccI?;!T1zr)0
zW`xpmVrgm)FtZ3Y*E{-Yk#k25Zp_gvyYDCV!HR$cD^4R)Rs6~JYg<%-FlnO^_w54p
zx~*5FL8naFF7hUC$%YAX{dgCzv<2I6k9KJOI+|eh@m+4ipNszJdOoB|+arC>V&&}H
z53&CEcVDJbv2+l+d?@*wR{~=}(Vyr*uAIFVKR1|~%3RFPM0Z0M*~pW}2lGciy?DsR
z(TsJ-t7n4EpfjV<#@jo)2x!zB>oA%QOiH08{%kn=)UUA3XAd6XVEs<`RUBo+8MnA(
zNM-mcHf}$jN8&->?kTNoNdB!fA4=JzjIfIPoo5Psh-rnagi#-?OW~M)T_=ZY$KCo2aFvtF^fisrF
zH-pU;cHqD*fNDOfcsNMt#3}1>)hK|H*_y)057!)VUr(*z|Nanj?RPp4s(cIgeoKSh|{&#@3Yu8v%#`}@YdOg
zd{StcS`Ik^Qaqe|=^w-QQn?L980VYse=)BXYIn#qIGML)_KNAHp6WRgPp57e=FBAr
z4oO6_9BzJ-Eg*c*^GCeNY2jfpo#Ye{^i)rszv>UExmB)O58B#Zc+YgN&pMz|lMxyv
z5cY$?)$hnB;i6}5v_a|5Ki(Vz&ziyvcY%fgZo}hy&?tU8)tuk=eGLJJ>dUiL_$oBs
zPSRNY(_N3p^9
zQm^R@lZkMa@T!X8i5o~zQMr$?Rtl1s@$0XjB|n)qW{YXd1-Cz94||-#m*2JYe+{C=
z`~|h9KW2x9uvu87YQyp`(?}Dd1Po-Z!*rP_i8dyWM8rPAHiBosG+lfNwrcahmm6kc
z8p*9cY7`9eXdbAv)M|$1@h@2@{s|#$m;-emTvd3E5)O-tm_V
z{~7R=T6q9-H9Le8L6nbjrN>p)8_uw^CvArE-rBHSSfn*k0KM_N!K{CGjV@YdC1d$o
z3*zV*t@evH#0n_pYIlP(z@C#!M3dJFUys9DhD+lT`Ph@vOMLXj(!_PjS})%{14KH73`s
zS6`XYoIl&&oRd5?$Wr6Adf&)lFqY9#Pvpl42{13F4}Y28-kI%?;yU5WbZ)&V+9IOG
zlxgCe>WOJB$7a%(Znn(1|BeM{bW_|j@g7tGOi%|8s+xPf8YNRB#CpuG#XBK5tf#GZ
z`1RG#{3NpXLRgPSSSC7{4cUabH#S8ZIYKlk2AeY#D0$^_A@-Vih8PUy>kMmWRHS1v
zpA^(&UVg|1rXcC=vAh(v3e5sW*!cg0wb
zTY@Pn#4Bghk(k-z(Za8&%+-;&d@qph#5OjqWaAel_H9xhbygz7s+V#9tcyoMpYHtC
z{V}x0lOQ{Mwu(h}b}A%Yf>)yT%S9l<6BMHbr&{mm
zMhGu3%_-$3eswrB)E6IruxZiyn0gbc%Nu@+2(&(n#kslMy>r}4=(T)ZEwa5-{`qng
z&&HQJzTH#NH^5?m9DQ7J%p0;SiA`tjYGg+h&cVW?qU&2zg3r2L+OYnX0IC2LN0Ihz
zv?$jMWOxyP7|v~xs^>u~F2pT8{U5MV!&YH+w_y7QZv7MOI*M;UnaZaZkh0xnTI7rN
z4yvg?prWnMfr}lDp)eauCW^+ye(%0{V9R#Zb}peB>G?AvP+|Y>@mV{^hNiXFB@lab
z!kMe9t<6TOR)8lNIz7sOGWCoVLSnFHFZGcZ6$$(=IP?T7WElQ-Lbzdqw7DbO
z1gKf1U2r^nljUtD+Z5N_)i^sciF$gm4Y-It@GTjxO!vQULa>gYvJ6jgJyJWa+H?RUJW{cXc!}rr-Nxrw9VBEJ~CJGxl
z5s?WeO7p-6+c92UO@uY|X;OWT&n52DZO^8hc6F+Y@NcB4FG$gwG7E6$Pr!)T*_^IW
zJ^TfFA!2mwD)lmDHxX6v38Lv4)(3SBx$fppe`H0bhx;_sZ3P?K(`Z*l
zA~h4>`8D12}DZ-
z&q+4-4ThdREchY%*rWyn5arOzT(X?t4Cir8UQRFA;)NAtba$C>b{BfTSp+)`#37S@
zD8#o2lV(|`9rl8zKY59`p|CRBwa)^86tL}F=&=+^E^uj1*ey0%)D>JQD!n4%=A*Z^
z_$>U=R1sp#%0?6Z)lhb0WRE&9Vua%w87`d(L_BwJ%*Ha(ysnssm_kzbZ##h9jeBw2
zp4xvs9RvLwIOj7DTrqwHSN}^m{Q0OlG8?j9c?cfZXdb*8;OU
zw(-$;PFymv4PDb2!_d^3cyO&WqX|bJaO73b8UBi8{3*Df{i(EEzq}EVh#q_1fWz(%
z%oNi|gAAI#Cvp2MkMume{BzN^rsz1T{jqNA2KSp?yxrayp7J5?Nx|&*xvM@PI4%au
z?R=@Xxx-?4Pp3}dPOrd-F?(j%8Ees2e+gFsz})04a!yIYe69*W7T&pH-3E-)4yO%=
zR3GxYZXVNk*Uh_dQ&;Bpu?@uS(OfW$jTSakzdQxQr-JCe3WO`(5&k=8H2?I4VzI4(
zH`AMu9eZ-{qnYf;r5|&6Z5-1i$Ku(d2}N6Ek>
z?)~J1wwMzG@g|7S1nm82H1(X;xpBPS<0%LK1Q~DyWOWi)%y2Z9Vctg}v8NtpW3|ia
zIG;B}e9%P$6ajI{RU+#3?&!yJi{eL={=(DLf?!`%ra8|xgS94w@?#|MP!2M6)kmK}
z;DNxC&GC7bY|B0icrQ6{Ik&sZv2C9~icMrFz!#k6QDIJ0J>1IIX)
ztINXT^zjsaHleSuSaf%+NBxsg46%v_Id^)5tBFAVc@b4|dbNP&6=S2ZW}AUJ9Q5fH
zwO5Wpe>fHx9S3uoSIKdG77P{7UyqG0v1bJ>YvN_%Q@2<)0dVs_expJ4m{z%!7STr}#6phcXbyD*woHE;{4zDJFdZ7JXcZVw>8>kWSFC$tLeViU{Pj^s0Yi
zU%L>a>;~{pdCyv-e=P@4G~@%Ol6xJres`|={}vqvxYas3v9zY!bPJ*Cai4)pd#Pi
z+GP&gFU{O5-YhRYM4CY-U%_V2+}iD_TQ@-rSs{G?1tI>z|)Ck=1JG
z)5n=vQo?x;UIP+>9`Yt9<6FVA
z97Fa@BSR)FJYluuw4&$hY?*8f&3V2^lkmJhgW=iw;`@6bl+R7^UgqVR@SU8DaHeZW
z$tc(84`IyHlI8X#r~J(pqC871t|=${#?5CG46DCC9;D_S{$
z(GE#{-%pej?K685*8`AFU31~()wx>}KljNGPhxTS)6Mc<*Y!FFh&Xy{ZY7$k897vH
z@N*_2e35{S!0|M970n5V!I>&CqHy@FRSBn!k%M
zq<9eNXWsM-93@tn2`>(Vp7Z*?INfi`SCn$U=(MpRJJCuYkrAhbgerwS~GMd
z>V&^9?71^rfGz@@^3Ez;^)7no*>_C8@rgy;Q19>F3PfImq*a+4!YYqs{@1=o=s9M|
z^cpR@>sm0e|E8iS>&7$F>w8Li)3amY`3G+(NCm|-*UUF*o2Y_Cg~v&X$514H?6AyS
zT}xsC*)PRs*tPpw>qC<}v}Gd3oz`4ssaObt{DKi&DCx}&d((psM1#LwAzlr?Ra&9F
zETk+k08aOSz}?#V3E~>{%&2?w_Dd5*neQ&6lH6l1Sgi#q)&{Kwq{__F#cAKC=appA
zOk0O41k%yqQ=jI6RJ8!FGfvBU--Je0vb+&bNIHqUz(s0OEut+)A*T7mgf^uxLr0;L
zz#vwOg}izDICyEnvDz$oa(f+In5mnkl*&dPo_pnJ)x(3a0FL#FO-|9Z#)C?VOyV^I
z|KuEPUB6ZgTg}j&YUAA=Dln5F-++}OmRB8>e5@Z6YG5}0e;-l8`x+cNN*^weX{XDH
zvmox`qo@})@-FRb7je`)aflW6&yBdW^&WF#N36!b11oqUx?qdp;N1?XxVLs2Z4Lb3
z>I_e_7x~HtuLY5{SaZT!y2H16Z5nLIRtVd%iqh%vClz&D*oO85$wgbnh$p&|ljAlR
zP9G*cm=T}2I26T_snw|H-)6&nj9_Zf;vAnC)=XGxzO4gHecr+YQ>~&=2-$^TICSTH
zjm4qx`242~EAcacK_?|;7Uk1n$6!2{Jz*QJ)vY*cf`|ZSekK+ivKRJ?reX9ISYWys
zQq01JmE7Dz>E|a7<{?;hcZ8?uq3+ing0Y6yr*v$Dx$3JQAd4?B)47amuP_grP5$~Q^fak?&L>d5>Zf9qScjKwvgKmNIzzg`WXDJ=+X?1soL
zyO<`>XRLYbLOUMy@^^;U%J}OV6k|Ai_c&>2ZTH_4x;$O>Tc3PcFIyUa5!WONKex$U
z%qB8#JD;f~@Dj*=LBkeu)9$*{-YVYC
z)5%lS1z5ZIsll~dWUwBKbr>|tCz8+9ks%CzB2WXTZPn0_`MZ)nL7KdABpX1Zq(${L
z>0OvOpR}vs({X;`jQ&;z>^S-NGtLYzB)plYX`?uJ**7MS6oalLK9BBYx%s4`?d`_L
zUp1wrH`)k8kn4M24REC^XLFWs=)wBQy1H#FX{l*_t;lS=T;OX{4rRj)k6P1P+Bb+-
z!bSH~tV2~^zQOFKK5dZcncdso*CwVocb{>0Gf
zh(3y(v7JkP_{Xkpo#B|1YsNnLND6*om!s#I3}xF(Q5V2Pe`NNN6~{ioDzM0vt}{75
zbhutRs1vKlOtXXou^bVqU3sK*JS)eeK*E|XRQCs=O}(CHaINcou(EgHRj9wWc@Zu3
zrBfH9-ee?rqwAV-+e6(P;f>&SmRdDMwf#;zxm=(|${%AuLP<2ExaHP@R;Xf4eES9J
zwY8)3ncv!MckbzZogt(gI&z>t!W^4vZfEpEniPfUBoG~-vJF3JSS3nZ245!Mf;9SWnW@unu(t*)$HDrj4EsmX
z<@3dM%tH)6k~cT$tLE}|+;J8Cvs-sf_sMez8I#r!{CTp1+uhL!pyG5Kmpp2z*j{}o
zG1Bi)G#Ps@@XZ)~;L+g$N`v~PuN@_YU0ImV_lW2qoI26G*cMWMBS(Hh1H=lAS%SfF
zMgJGG>iCaY0R`rPe-v>q{qTTk-g|uTs8ju~pl0r30G!#EIk=an&G{Z8#QLlQKY(`*
zzuJ7(CDjHF;_vJ#5obA$kiK9Csn7en^918<*6>refYeF@AT%L4k8~^B4?`Nn39*b8
zypUL-Qp3wJ`c4l9Y9Pg$a@%-E%zQzEtYkeOy1$37wHM+C*?RFT3{FNw3BR
z;kFA^40A=_^~VzoH0wnO1Yw6$A85-zh1(qj1GV}qhRzR$Xb_rD;>MRzQ~G`har^8+
z{%hFmQ8aDE(f~l~m^s?o2*Bht_Vl1pQ-n}J2E)+votIc~h4F89jsM#Qg^+5b{Tw*m
zgcxx@x;%GxOKYcq-bbTR0U9MS)FRNVbe4oo%y+aRs{Xh0C@9;J)^!&y6J^n~l9H&W
z=CGwl5ZaM&0J>-4HHa
z{{mV)6Ll>({AsR_d=;)v7J+@4V<{@4`$)#vO<_o2y)i9(74`m44}=E7SVwSgK^K@r
z?+J^%L@V)HuVlc<+nK-lewu7>cVoV`i<5Hr>z%82fnQTZ%ro2D-Zj)_InA5;Fjd`J
z0P+Qv{>w}jDb05K=k@CNAv_a)css4!3Mi2H^+an+eai$EKo6QvE_~kM(K*Z}pCRL0
z$v8<*0f(gj!FM?qxg%tTeN6_}uE2bZqB6}sa%8%m4id%+)iQWLJ860X`<}J%^iTKG
z@K*QE*Oymj@~tJ}m~pQ#t7hm2^~y!PtucRvwh_Kzd7VBF1U)!Jxt{ooWNwptA$>2l
zF2>O&3R>_lZ%zY9xeokxq4>^`9jp*lXtt+r66dom@c38Y;L*P@Pk=xo!od5AjYL4t
z-(47VpOayZV6^S;1Moz>O|o65qrje_9oW9#7jY(fiLJq_E_D<6;Es;dJ?Z6|BeGx(eWUUej9oo|6cqL6diN^
z&RxnA-1it{{IQOk3QY#Gh|j5L{!7e9D`p4BV|^gIoryXqcQhwDxC&bZ
z@dJBv!RSj`{n0h->Bj-!nTr+eSR=5XaEOcI%CSS7rXyo3>dN*(v>RAiJX~a%<+;P~6b}hGf@$q?b<;1DDmNRh)pMk%w
z7kcmn{m~eZWU3<~C_V*2CVk0{kE2ZfvJ8LwM{4kGPsv*hN!jgg&YPicWQW{2y6>CHpv)wHZkq1+Vw)il4%q2STyzP~n~Dj1#RY#N
z^2js%Er7p=XJn1-1)DEDoRimk+_1a;x<6xD7vn*ZWHiJA?E4Os_U=gSTzojvH%?@V
z0swOWbqYva9IGFb4}D*p2tP7i15I(6Sz;iPnS*Pup17WxOt&3dzI5$X3ecfxHQ@fY
zCDtTehyvIf^L*11O$g;JlfDL4NS{hiC{RNcXdUxg(OhOV?(4}(ETSn>kjx&&Ei2?J
zUyoG_v9^~km#4+3OgM2bfj$Fz7ob1WbH)uT_fH3Tj_0~7a_Sy;Qq=}5l)&@ykQ;uA
zz1ce7pYAO{um9aCje)3LF>iymsnODotCKXx3X-w=J8OgjL2U|=#yro(;_FH1&2J-
zFVYScFP^f6{2wm>y!@Y{;fvK#=wmQqPYgMFYd&|W(o5>Uc;f(5Z~LUvO7~Hq_9~XQ
zT~OenWe4LENyJ_NEUqUpX_&C~o|xSg(V*GZ9aoOADC##j6P^&Y3eo=({xi$uR9kMU
zfbKTq7*nWRn295|)qLkJ1AL-wn6Qz%V@}r4Tbr&7*Z9H~7#|^UETp2hd-wtW4{q-`
z>Nuh*S?3*nQ`gOp?VRxc!yV3se_)bew(zr~6GCl*M1gMklalgFDJ{K_6qS6hk_#vI
zOH`7DpLM&cB}=a=)c3nqz)Ui?>qEEK%Juv4o2HXoIB;M4aW&Acx}4>T
zIK!3tEDwm`1Yx6EhV&S(LS<+c+jc)Z+Ij+HHvI@{E&=%=LL5e9$UFs{9f|$jdbeUe
zVbTY#8B{aDlKw?yC5)wEz6*(u68yVnOeKCjc!-65>&qTo`|#o#=g`3?Ps_ubD3$PY
ztssnp#em`Xxc0SDk0RzP&Uqv$?bC%!@Y(Mmf^TSi)$N=|ToLCP1}$0x`)^J(lf0LM
zhb)&UnE-1^bAIWazPR=!ftJz-Ae|nmMnZ6~%&0vJzr7{fm)=Y$p#BTcfAT~8@
zUq6(%rf~Kf5}w!n4IFX_`8_4${Ld@r)#PLqBO0*@zb0B`x7-guiTR6dvPRRpwjEf&
z4C#%@Y<@S&L!veH(B0dYlkVhGc^M9R31tPOL7G-`!*GgF1Fg>#wiIJH=prm)Nbk0^
zj-r48eUrSd5cutf5|3=~EcuvAFn-_1qHbqtfKqkxJWlzgvIhR6wD@w@X@9u)IUX~yFi9{$vGa_FDf@5Nb9E2f4Km<9@EMz+m
zt$z&Pi+W8;Y$lO*X;#3(!F=?9uPX2$JiE3G)4sS?Wb
z1m)Q{^|%S;hO4O7o*Q{@HgE!PHwE-hb~6OWjqjB?f68e;HsF
zxL?(5!cIGR7jp0&=@ynvyudR}`e}M{AvN++jsu@QoM==(;<#TvOQIn!?N<2fteu|J
z{WrfzZ`<2_1}q172$!rP7`BS?oTc#hHKV}1J;{c0FZpxhps3l`1M&bqie~Sw&*SJ1
zQn09}({14MB@Jl7R!&2${Wz;H=4pC5M*C+8m0NEKi&#kOyT
zeqQE&57}>n{ct$=*NqfMv%XexN98|07)5;1N0VkoG|~
z(^EdcT6*muoJ5pb$9$gek%`TUGoL*BO3?Y1ep%VmhVLA?1?ofd23^`i|Tr?b;Bu`AS(2qlWEt<$G%nziPG
z=Hx$&t*>1AK?btcmT5wLxF}Bp-)d3CnUE#S^^ZOUI7gA*a=>TgYWOc($Oy!bS$QXf
z7*~ZH+GSEIw0+a93D^q*6ER#9HtnT)ensq-tjVC^14k^o?N8+W;P7pJvI}KH(CyP*y%SSX;Ps?>qG!9!WGO0Ab5nZu)Xv*k>i+K@qdR{OkE*)(n~dz&0X-*
zZoU2;(f;3}9*O5mw>u&(U5M;BQ~do`@d$SA)d$#6Y$U-RD}YW$d1fWg)DfvPb01W+
z@Dte}@EK9+hi2jG-bd27yPiqNby#6oh?h9@Ro7P~F$No*gOh;zGf)N|8DR^g?DS!3
zuTHz6VJE3gPq78XOmk(||4F3zU{#5mCuxTEFL^!12E0+_o%-TxWX$p=EF+8-W;NuM
zO~hz$eBIVfv6dd)iXuPf45)X+X{e5%G-f$K_=sMik2VZU!hox-9wxXkan+-R-&r})
zIDbP!UFsd|(*6JY
zRXEA@aK+1efPd5)|Gfsdq0(?zdGVS9FL0UuLz>u+-88$FRHj-Ew>LUZ;%)^#|19`Z
z-e+^tx0ple^{1u@NJg))k5%-0_vu=`$NmhRUS7S2a)2<&CNV;mGwPOlc@Xh(bY`O(@xDv4Tu{Ii;=Wpj?`A~rO|pY
z3E=+`2Q-ZM>P@knfsvQ1JwiU@Bzee3R(i_555|-ZHm1Mt(cF0Eb+|c{hW~TtcyF_#
zn%+F)aMq$Db+_Q=4s;zVd^S$$I9lhiI>?$8_=+xQdn$F%KkJHlo)v8s`C1b>HY)I?7!5dS!I{x#`
z*Z9r;r|o+S^<`j1rBJ%${ZrZ<1$s6u1mbgvwHpWoFcPkC2n=2!GkkJB!4+4
zV$5!AI>>ugX=t_TiNff{MAlFGzC}P%T+L6|{O251X0K3&Q_FH=V
z&m>=xW!9lwI##kpEpiunv1!={j(Ju=KV8jet!h!_?e4RGdy5cT6uU-Z}YE%uc{cQ)9rvsLj0)rJD#ED{V814T4T23sxMTnI>9uIX@LMoIy
zn&_K3X(Q^dz}|27*zA9_A^sO4N{{y_3!=na0jDl#KOU#VayTILqu!NT!tt5demQS2
zAuMKk&DmnB_WsKlch|;NR^R16pF^m4JCT^5U!j+;ygH5)Bx0lg`%Aa(VEznD!%}g?
zs))xGEzy&(WCbmI1M?Yju-5Ij+9@2^|I)G%
zTjH(`_K-2hLePpk)a6sXMo03z-H7cVcau1xioueOTvnLU+K
zP?aOjcp9OQ7v6uKYGvUTaX#_>MC3PGbaZQL%p>-
zvyuMGfHnR+kY`_=&LhnZEql|+DP&)+I&JEI*5@kYs#C=}$PVi+nRpk+uC+Q;P3n)S
zX7p&1%chmt`t{|pk*oZ7wlR!YlK-q3`jcGuIOHXLt-nV*F=cV@o7Ck$>lC!`xVVDo>#M6;EuaG
zaH<9V?v3cNe#f%9Hp!GRYp3AJ%hy+sjh3{-LxenO#MmAfC}4T8j)Gm^*dOrFXP*Aa+3_sWrv)ROf48Olshh;4{L?eW=`gFX^0i4I#YczBSDB0)TT?w7O?=F<)rWt6kDv3=
z)yrh(|GwN7Vnd>HJ)g&{UA+8c=#UbhV;i5-XF15``?GFUjE)(
zsj_(C==p!q^q*_J3yGeIRJ_c^+`^tNnzrw1JTj#MvL54q+F#)e_r>7d*!BL)jQ)4g
z@5vv@QLq0Jti`Z@YHFT7E>9=YQHXmSb(uBI^9En0^3=cYruSW5&x>P`uCJx)zRahL
z>6vRuXs=!7SH|y=+XEG&UQsszRVP#B`1eScB|)$DjHt`Uk~KRs{<}}z+q7L>`=$wX
zk=}owDfQ3&xgh0=7S@S3|NWi*2GiNE2b*}rL`Ncb6Zxmae#M9z-BPJmeiOaDW;sY-
z7~@Ogk1~^2C@dWz*;0<5dlwbxuHj3$9;q-cGMs7aCxm_z=%{{sdewGHafPKqk%DxE
zDF?$1Bc;}N*OxgVRtM!^mP_N*uHYYDJJTlm(@&=R`500E(S#;&e!p9!&b5TEL+0h}
z54Ys-#?)hWjkb`l)X)49B9OY|cgt&v78t_o6CSAywY?AJgZvApFQ$gS2G{BiI<20(1W0{rMre8PpcsH^ueBPa(y_EQ0beBU#e5Uu
zzha!YToxBWgAaW1jy8K%dx=~y$5^HOD>4+Wxeg9WLn`oW!t=_SlJQfboJUgn#{I+e
zXM7=?$;Y2(JXUw|!6&c5AdOl}1H+p~;ar>*!klhiVo}LE@xCyA7&+Pij6s+5Y%G1M
z0FkhfmXP+ZeBStjrXxfb$1mP)k_Vp+M4Hc3NRdstn1=_jt2m69e&$?Rbw4=C#szf(w)|41C>7#DGqz@9-0hPv?nwl{I)
zo>xPanbC^a*eA<7w6y&RFFDl#XQx-HBKhE)k}n4mu=}u(Kv2IQu1bUt)?f9?Zc~d0&h`&
zqVf49%uLTS7OxA}^FM&1UYRT;Rn#tEI~=24XSif6!NsD{!CN(uL(p7S^n(Mx_z
ztVirfvab1>Xj>1I+u}#TH@c?h(Z8wZjlVEnQ&CCUOToles85bPHb5X(2G7}ei?h86
zErgEk1Gv28aXd}9tz7S1*?lI{=$N)1##7MhH13_yLLc6B(wgFf_DSK+=hg^VC9f6T
zEgGNSY++F3i%{ZQkulTm@VH-A;K`5d1t*L^JicEl>Um}6rQ>O|Gi(dJ2Mjet^Dr8r
zlu(sPcPlNf=JrUSOIdkIp=V*Izagckyz;%AXNRN)HBGHnb`%Tq^4^WJNs>K1GvrT*
z)n4I$G`IR6?lrJNOIctR9WpwBCUeHSoLZBeJu~nMiY;r2yLt7YXgat%c@;YHkwjBW
z?&$%EpU#p_^TiOY(`S2mS_uo|zqP~aYdEc*qA%B+6iBsti@?E)Jib!pk7@ISZhplD
zm73iYx3l!mp#&!Dt+vV#aR4*ArvT;!KaXNllh(PjH-+}!xz-27xLbQplvB(Coc
z4WX@8d-4l^q|j5pp(H^h{NKu43?{b0lebXZxy9hsNRoC^(y$Pi$K2N27ew&ee{BNl
zPE3_n0zxJ)Y7u8LZYRt$^i+QleZ}%2v&5j47{iI0vsHhb@*@7(c~cnoj&fL%yBH1*
zfVCUzJi4m+mb`M1#E=7WocIs^8+p60tFydcek{^HK}_NuAjZ?S^L!5tWF#!cJ1VSt
zT)h}azLNd5g=p<2vOnHZo4F+-*aCA8h#1uy1P8PX(So`~=N|eAn5k^|dqUAIJMUfy
zg_d9NQN@`I9(w$GHM{YL5O4L4W<<-tdSQoRf2IQX`0&}=$u?pB1$kK7EfY%!4{Zzi
z`osF2Zl#iYSOM@I!79P9LfBA;a@0mN%~DszrYQOlW(BiZpta$}QDXT~Y}$_44@rky
zWwdkC1kz5s{22;NHvZ&>yKv1-C`|5t?rNIhp^ITCGob~2j!LVc}Gx$e}e<{-YA{H%Twnfdt;Vr7pt(CXn@^x_DU!-#MC8)f8Frq`t3An*IoASx
z$j&2Gu1J6DkutQ%UiG)u{rb4jn)*?~B8A1{;%qevT-u_8ej?744S(7P+K^xzAcsh|u{ql1
zw*;PytyLKgE+-kw?*++O&;vT?1!WaPXH{g3pw&92~y+LW9zVRF+#yKeAC%om#E*m0qHHoK=f?JBB~G|533lzU>O*?<@K8!st!>
zTRGiDc@+k|>GXwH)lQGuVg9I-g~MMFgch7UlxbknaMA+N+|H=^{n&IwomnI
z);FxBTYC@I*nf~b+X*dTf_{G)vv?rUva=4zKmHkM%%Vt9(ER3(73!&%zW~|qg8ODSU7sk+ysM{;5
z5*A5Ceh(t7q
zu4#j853IY`?ODi
z0z7z@Y>Ru{MYt^GRC_Nu&+Bt}3NoTY8loazu36JBLpTx!mD)!NE|XZ~9)B8xX`yuk
zxOesA2pGQPS!U4p7DM)_x$vl@i|6&%GNUY73Wow4GCum#PGmUenfqqax@P00F-sIg
zV79#Y5#()i@DfVaCA-QoP69JnYf;d@cS}60yV1Vn{m1oj6`2NlJqPW4ZXNMm_Fx`c
z3v5fpra!@h0*3q=1|^N>Yd+)BzwLBu0$h};C4bXn{J#AY;~y=Y@VMp+1=w3S#r#*<
z_LW=S;&P)up7~KJhd+zH@bKo{q*8?0cxcoP_k<#pX|{`O#LLHqV68!fi1u!jk?T<~
zS@0s{>)sLf>7<;Hm4YKytv><=)siO%(R+N8-wcyklNmX;qj?w5atnAs*1u>3@iJ0Dx+Qp%^>rw4?F2@a4d;@Zp#uW#$r
zWN$~DbIQEiLtdQj>$L0$i_AmxH1*U%NYBFlr`f)MDMjf#PS%H2oUf(arYN?@vb0t%
zbm}wLI>t_h{0*lC4cXUUf1g%jw+Np-p4I=-4eE~cHq{@QQ2HaX6m)wA6cQf4#u>>*deCUjIE?1h#
z(bj!_%xC$jDc&ZB6MJK)&t8~;(bKMui8Fc~W^t1A))1!pjCNy5@&sD2&nBp*RmM`^wC6gH(?vrYkFe(mO=y
zh>2UuzSuE-VKmc^z_3lc8e~)dCzxS7AoTsk1+-0_J!PK$wnf4|{~41%tvracm+)dT
zlznD^t}PpPLGOW_K}SXeEyVtr$^THf^CwL=U?GU7vxy0`V`X?ILmrpBm*G>q-#?LR
zcSWSFxp>)PZkMSI`|J4iY1k%z0BJ2~hQ;KYymcJCT~jK)k!9QRejq58D^G0H3pd+9
zUA;v{jx<&=R5;xb#np(!gzb7gExp=wDABmAqA^-;GdH>=71pFxOIv*^+`9etYUJGJ
zfn~kTS`t2(*+YUN;e%3u&AuVVv4Pv{Mb8kbvRr7yK|rKu{Y8i+&&XD!Jn60>=MbBR
zOG*OsUzyxjv+cCyI>h(^xvd|b#-lkSz19mM>yL0IoIUkLcV^%YoLpm0kI%HUv
z2;?W%QjIi681|thTA0LLn~_U`hGYawuO|HVdN4i?YB
zq*o-fgx`YCRBP{x1wXt!JdN&Y=ltCmFN4O$LdW)wuGJe-czm~MA^)wux|_UeslITy
z4JA0cu6%hg=r8cW_m*XX9y?HZYUZ;h@9x}_cz2RPm!d9LLz$gAMC?BoK;&^UMVvOl
z1a8-u?Cs%beZ1QcU@>qFG>UlIOUhfRCt`{C)AC24$pLxIy54FFrh>YlYFcUhh(D2a
z{4z7{WBJ7N>?iThM7btR=-r`q`*2>@nAvtKn9QQL$}x8HuyuGkJM{gbs*&a&t3?_t
zd&(2WWn{ffn>v-qZ}l*hmXji%uQvU<7!n;iBt~Ja_%}1&)rlr!-?dtK%Cv@boNrHif^=X2Fy9HIe#Ufax3OCx
z`f(XtW_;La-xBGbRpoHZPIzsjAI=uucUz&_PQZPY6UHXCjpn>}vT);w^)$UM%faSI}0@!;BllFnnpx+425tO=8iqQvimB7|`A9^VZ5oHqU}lVz(ATWCC`z7vC_
zAjBX-ND>}0D96y8z1RVNx-*4~|G&w>|QB#a7q
zyP@|&pf^3z{M+A-I--~XODBfjA1ODKUjYrtLGYpZ#truqo$fm*XY^eQj>-#}%tn~X
zvsC+VBsVs3=kq03lX1STCEs@S`^~>Ig1yLw<-^++L>};>A45`{iY%z}5EJ%94l7?E
zmZ{d<3U3a@wrc-?F5Fg%3uRi4!)3JhLh8FHAlbUw-Kyvpkv>fbAFjli!L$R-F6WWrRcf~sNfxnK=GgKq5Vel?@|u}*vzA6rw->t
zEU|9>AlrxdurvPBM-$9^$<`NbC*OKB*0NB|4+ENx_|CD%3iVcm@tzcLEn_y59Fd2K
zgnIpeJZQLK&uEg<{!UL-h+CDc5`M^YOXi&1ub0YJkj@vSHUX2
ziSMFoyJ#ZqV6ARj7}FDQ&q1VHBN+NG&>+$xjcf_}fb!mrw~JrMLPIuVR9uz9*&NRW
zR*f(k6%^+e{w?aM%G!aM>1!?lC(?o=ODcp)8R->8{%?nv#uaCYI=Ym@pGKXLAwoDU
z@ZlUiynpU6Ef?RX#Z7H8M;~w1S$pV88*B$Do?$M?7hcTlFz0XN3m#$&Xe$xsw$!`r
zQh8%0srM;zAA0f6VtLa
zQ7wnzs^@HGG)p>!$4ZnJI?B@J;QSxn9c_#yZ60V9ej0VY?a9JU2iD^gA~gW0%DR#LrLEqR|(AES<(U1eB#w+;eUl?ab{k2LoF+@K6I5&xt
z&^U!Bd3&LtQ2M6Fqx^~z9t*E9A@-DTmpe00lCW+&XXu&Lne|U`-94Q(j37Wk|5{?c
zzd#Avz2nHoJVy7krnQqzgubl)MToseTwA~d?b(;@I@~|gI7u3tTJ=8?nOU*t
zu)o@L!Ot5O!a4(eSk)iE2@2p}pcm2d1fi;W+E+t3F&cRKV9A3Qr_dj5v7D6HvEM2?
zF83sw@w%9FMcQo_5p=BF6mmgDy4;D-V#bd#KPR6lap-E~;LJaw3!Uz3rmrX3VI^hb#;DSlKQ@aySti0n
zhmyLJt1$Y%5LZMuzd#a^Lk`T-$?BwpT_i(C#LMd&bmf+kcJe;G>LLU$zKucj`MTQB
zgQSxKB91qi7ymH(i~pssuxNc<6lTFx5GIU23R+6Kjd@s0J`g0ed#_m-l`E)W7)`J0
zPT^DV0@_~T@c^PSGj4t?Od;jTj(OcBkf-e&JzEgwt-|d8)O=!La>d#ORbnsYPA-_A
zTqQctn0Vw@ybeVdv-7TcE97XgJJpVSv^kWo@`&;$QgN|wm@NJqiY}I?P)u+1Z(}Ue?gm|vN&A62%HgDZxJ?n$aay~yr)E+7OKx-`dsMSrcP(PH=!Fe<
zO`XzVlFL%x=-ceyC=yFb;Q|0dRz>+bw?89qb_-rRdGg7n+^X*<YaIo&Z=HQTAx)=_RL0WmOTzq(YTmm`3QsYg3JB#Ssa%iqS$CTt7s;!#*yxI~e
z?4tL;D!JYnm$%NGn-3wsX3$eCRcZC13Y{GuFHwHj82YTcHTb&0kM+(Wl*76~p;Xxm
zNV&2!(v%R2eTji*SpF@!z?1td4|}
z_V~*_@|#2h2LZ_s_HZe99v@UJsNS{@sg<%O?0{ls}wn!opC${*Ss+B65x
zA3@o)Zw`Z<%k^Bv?4(0zx0IhfGtDwyl`PlW`7Tm3<@^%)IbUkv3t0_9Nz42$fElV%
zzh>Hgn=G)9KlYB>AKPEa{r*$ID=cKH>pA)Sz7zoJ=Hq=uzt^|_ZEX#dz1;P>+(W}Z
zOf+o=&ZemsZ+SPi#C;3cHY5|&`L~%z-D=Aoc_r{BaA^_oZxd1Ju|0d_znwGHEZ{Lr
zw3i6MuLJv6qT$bf#znOI&;d9=;e@}Alah049Avb&R~dr;L*Qd)kCK*y^t|j1;XV<(vBu`!ijF5w;3Dwh
zuUQMDTH9(oXFm>hR8yXBInE!uyo#>0?!Fua6L6@(>#H_1{trH{Gcxghz00v4@W|BZ
zt;X8hi#$+nKfvV4omOcx*;Wc*#&5=mmhN+7U#*#Ss~Ui?BEigSTa|vCktO$KE8-Ro
z$iHdI-?Aw?3$`V6jh0s$Zk%abLWzOxN$N*s6qaEnS87bc3K^LM;B*uPG0pN>S5#-h
z6NZfjY2nJLd!La0ylz~pB;aiDYl-*op$pybE^ea4*|W@+K+9W5|Fa9jqptvmp3
zbn<4vnOH_${XKOb_vh0QdK*S1U`1Ohw0Uv0`VniR_L)ZTNMAN_KejMDG^*su*`osB
z6c}~1O4u2!J&e>KYtyr3(ic6-Lm8DN9Z7g}H&
zN@WU)1#ZqvSYB@rk6ZR&J;ha0X>x#=(9MIPof84GE!h1Fg$bkX-)Rg2U4D9Zc=w5$CH7I86{@qvbk*yb}D(jJTB$hE2LKid}SAvNw<7rUa
z3pXCkjXpG}ZA1$L9X&tvG@tZMc?m8BU>Oy|TSHJ$fgGIYHc4@Hpfo#3yw)V8>=h8i
zpTy9sX-*Bshy!~iqj-JjwlWkr#@XWo?9jrHgGA)Cp|y(MiZ4L2C^|0z6^VGAjdV|<
zwom9{2`p1gz}WZzN&;z9iVv-_qCc0iS+4bZ>u$da6pm;py|)CGPcDL54LlSu{^z|k
zcWzIXCRAU2jlGj6;VxA_(DN-XWGv4_WNf$(-2=fg?h-A}ZIRblrtcn!?gvvGZuc%8
zk!@Wsy#=r&An6l^gx|G5$wr5?uh6LJFf4{wn4Aw`mQg1igUWW=9m__<0_YNxguMb}
zM0!oE=xfePxbMdommu!kPU%#Vj5(PnghWc;r$wVX`#9O?&VIk{@iu8;Gx#Zs6}8S&owcNjcdRwYV&rx3`eN|5(5fPsP0ACq
z3iq>YNT(6m+4QGC!(NDG3aW(QI
z>}%K=uNBX#7+5B6OjY14dx+ZQ#m-U`KKPMSlS6q?5GxdHyv;~JM)vT0sD_!~SQ>V{5<@w}80jB1G1-hb>nV1eYoY0f
z4s0a9V8~ZP+{$)jB1r5Y9;CBLK38nAqXv_1#m6W0w170niC)IfR?HHI!Xm@guHJel
znw9Xrvz95Fw&`kqt<-!K>woRDi8(k`(F^zmbn4o?1+ORlPalX|?L
zOpq_Q)B7&6TeHn1_@=v5k5Jufc^s#r_P_&6WGczjw=unkxO&i0(r
zQoo@teV-m5g_w?Lw+qQbL}Pdxpi!c1!R+TS`Rn6UP%+E!n7spn=1Xh}PMLsP8G?+`
zR43`ll&iBo-AY*vdBxH9d1QbDsECVqMC3d+goW~%63=O!8&Tis7=o8o&l}^fW9~@{
zZDvt?pcrj_D@Q0WjPShX!zqGpE{?UB4_{r9{IkmhuG5^f1b_46oPLNMrjk_?+lmU((Jf+T3{*4VnFrLC2@XSB3*?$c0VeI&b7jXJ$KFvkd-^k
zf3hew#-@+q@*0zBeV3aJa#w?}^C6nvpX_PAqycif1Rvedl>jEP<&9|I7kv>y$_2qE
z4gt|cZ-ejPu58KU)GXgL#fj1=boSf;AIs({(Sy{mTjUl*sk!x_c`bBfxP?k~^R)FO
z>56o-9Jw$Vc#61x&KS;1hys5LYot9SryQqlqEjJxhm8@ck38WH2YSe%Y)dq+h0pxr
z_g8+eVj9YZVzCLH<0N$G@%`9{UXyhm=`Vc=9NKd)-;i{5^c$gg0qdqCL=7P668HhD
z13UCGq$&n?tk2!XaQbtJ5u<2qTGxazsfRZ(%#Tr=N8SRPSBWHobOy6fl{>^3%}}mJ
z^I?yj_ZjRk8Cd%cPCYk(Ck5aoSps6vuLzE|k;z!lBDr7>;It_VFvL(>N0j&+D2n_T
zqvX&mOaKTSKDH_t`e2eq$udtH)X7fnTh8B{e4HAqeXYW{R(C3QcL)hTsP?+xKlInm
zTjhV$ssx)S*BTe!UR#7z-2}B))`+ioy9pj>RpLzn8;ve2i$n;Mi*$jdZ#USa&wo55
z5iwngrYt6r$RNFC-u~m`D`k~|2OLnKRtcA6mSz4fS-!o*Q>W0tDeR<$p+A$AD0F?q
zt}d1IZ5*7k6A1CM`@9aPyz}dlQNm~oxk#2QAS(2~!Cd@2S63p4C7>oul9SX?M(b_3
z^ke4-#^X_G6AJeHa0=o0e>tsA``t-Ya{V}vLxq1)HHd#WcKa^tKX{wuHOPTY4w8!d
z2U7$6B`fHAcI40(71aUGY_vl005gDSdzo9Y8YKvXlN>srF^vytmWZcO_ozD%yaXGnypq?(q};xcJ|
z`44$E@LTd{a{YH&SDkAPx%P`4iL}CG*DKu3k0WLf=2t{XlN5xg)y=KrABv
zI){0U!?n2*M%nS4y}P;Ic|#qk!TXtHXSNN2rQB
z3SYSeKJ$#}ejssDHn2|>9dV7ZjhzZ})l~^Hj;p4z$_5aARWPIptSq=_Mqt%7rvZ^!
zek|p}`ioNVO4%p6Q|{jZ`u_-M43a8eJ8XU@o8G*8#he8GnpB+_3Q!`#zkF2@^8n<&
zOJkLI`LJ-rH0Af=-@Np|@}$oT-2jm;2V@o<_iu4iO06+zJUDi`3FPki9>s2I>m6Tu
z|J_>=$dgROPXZOad?e2$h_SigXQ&d*20M*Ue{kY3oov3}mn!>zk1bUJ=zMp|H1$Dj
z|F|8tZ#CqFgo`4P-T?5+ujeTAJ#zNjBCuu8bEZF-4by@FO9cU^3S^VUq-<_)WHMmO
z5jo_Z*F7CR3tnU50<~3F6f1uX1
z*hn!&k~E4>b`ZmyP18<*Vd2IKu%c*aFq1_~DXAs-yZtsQD?yxAp3RfpO*X*K;}*{2
z(GZ`350Bm?1M+G6{~%s556?_;7{x&2SsU}Z8QAdpTcF+e;jX%o6ZlGyT@Kevr%yzu
zQ#~otCSkQ_2L@Qif`Z!b^}+m;)!Ed++D1nCA}CumXXjC5?Xho;`IzNUOPoq$*-U+(
zlE0p_b0g(Om<8K6u4&Ewtc%h_Zo%}G59U(;aRtH
zmcdO|Pqhr7mI-6nAA&A21bZ=+x=3U`b>aIb
zY*M7gJqyy3jEMl)r^f;3|39$X;&u&b>S}mN1(!@YK3VBo4X_5SaG+~vi>J@1!ED0(
zG>rWE#i)Ojz7c1-h8_
zizzV3QdCO{sV^;^C04b$mL(_am^YpsOlcuxy$rDu@_w%UWezQ3LG4{#--!SIq6sp1
z`jZq_keuAx*;xV_04~pr1+KVh>gYgwvMS5Ua*3R#DAJVN92|@)p+uSfGhEKj6b9zU
zRcGgi*^7%)`(?0F74;)7-hkBf0
zSUX3!QL`Y;jgD&*i0Y3g@Cu#!K-xFjf3>IWWG5e8;!(~P){01Z;a
zg$N2-wEcb$BFZDqHhlU=CfVrgpRXn8BKpDjgcLgntJ3j9g_TbqlI`voh$g4@lOB`A
zBx-+E=Zu(mOt^a7ioOrL%G&Q>!h`7L-d|Fnv;J0^(NjPp@p!1Y*+fUu_B2`sA-*7i
zJWn$+FnizCec|BXz`uM1efj^Edk-dn?-vfQ__c4;t3P}fpt!;(M{ev3C#MawRDgNh
zNcUbaziY&!-8J6r?culeV<+-Dn}QiJ4+n_T;sB7x@UUeO9pUda^m=L)Q9;H4X(EejE@ssVGw9JB+N@4p
z3#S<+uboTz(1;rO%2fU%ZJPM%gX8P@On-HCdOL~kiE@TbD5VvLP5gRxaUClg%MlV#
z(66gul;##?CMB|07{nkgU|{88HVcY4VG?F*n@fEHdHdum*z3>+!^`>{XoATioc
zpx431>&20|T`e_e%Y!texX4ur>x5xn9!PTD-BV`ys}AneN3vQXo5+C!;(t6Kzg~Yh
z19@iT7Fi)QvML%NTS$Y8jB3^RDz+Zc{|z*#d{1;6W}&AEqr9nz;s@p@JHbqzNr!i2odm&M}sM0|6H)=w^=bo5F_(|LtpbIkX
zu8g+gyu9szsyv+ioac3W8oZKOO{E`OK_uG=7@pno51zs2SSCTijJGEg#xF(_*VgjW
zHeqIm&$i14)l~H`qM^j=Mc%4-w(YkTQz}~Y*Eff1I9(z+tpP)nvVUle@XalIb@D9R
zAt{B!!!b(^1Ug|RkUlJ@UI2n%GReA(e+{60&0~qfW`j06cZD~@T5yS5#sIoLNBGrM
zvA&*k=oeexeSM6xrKZ`0eQ>y=iS4`0(Bm)mv0EP|)DJRdg^2V617&P=EYm`x)eV30
zq_4ja6RB4ipKxqSDOWN)KN%i&jigzQyUKBTlSoQxW&mMiW;S8Cn&uYPr(t7iHW94&
z`?&zl6LOuuk>QP4oo}H1&2lSGt&5>FxA(&=PPNI&A=c_jvt;jxt;92&95eS-yT;aO
z%F4=?Z?vt??YjQUn3!&Qs}0u#_*8@jT>R8k6--tKF1saWlR`!HClv1ZHg70-3m$Qx
z{$?Z`I6h?d>yTS!Lc>M(p;(7z=
z0Q0Jn!YS^RpKL@#}ie(GP*n6nk2#kYb#s%x|Mtx_|4)A%`>>%D@4LGhVo3K#$sL;z?
z{G&%^RFh2b0}AJ!jeH75869%Jc5QUIQ@0pW6DyFMno1Ob>r5s!vObr=&@S?Wd$OK8
zIFw7i-jlU7&HjPM>+G~Lzau(X2%Ts`A{VK8G{p*$U*`Q{InKyDKMmaO1$>m@?}qH6S2iIYczc4*o9{wcbE
z`qE1C5MVN{PCq|=BE>7!exsJ7xA}Pe6#t!$eH2mAn-U-IJWOni$FVUUzWzM-CKlp(
z9V=Q;U$14}krxh!n~1YT4bzot_Dpg+JR~0Fnzmc{ZUBoDkZqW
zn7I3{K;UGb@(Fu#>MYdr1w
zZKRLaMX^8rDVVcY=G%32<~0*W4Dt(`&YWHf&T`Dotl6D8%nI^fnb{7S@$O@r@0#TU
z;h$T--u>cuKcX~@^b@pk#HSxZdE4NFb1dKWS*l>Y`$ytp42dn_4QARew*^wICs`7I
zJdnD>2%6#^6uos4`{a~Ok_ogJw;)UV;89ict;fBcAJKE@$~*W65}ZK}gt~%IBO7ke
zBHe_>K}VRHJRb$Un^L)Q{-n^(7o+zmR`RNWKIQ$&)8j(TnNaT;U39<6+ymdQuNCiv
z=!fVtzSm??IN*7tX&SU?vWk)GZs*L7=pcF4^kknw$okZdU1E8z)#{UXpEj6}l8BO6
z;Y+PDj`YUbPC^`q66piR_uM>)VCr!Yjrfs`?ADiD*Dzk0`-zOOO8pRu2lR?!+%MX*
zuJ}CMC!eg0F?=dcmsTqqT8|<;E+}mOd^|UQ{lgBS9BBZu>*oHN^L&XTp45;08#i94
zfPUo$9sK7DJ@Pwyn{|&83bUd#L^U-zoGY4CTUKfR4^2-Q7S;Fk!qUBfbh*+UN|(5V
zO2g6(f^?TO5(_A}poBC^Ee(Pqwe+HtAh0w_cS%UT*WdqnzX6wf&zzY#Gjk>fvqjx{
zqH$Sfy;({hcuN|QZ>L=_NkXl0Qfwr?3%$$j-Y4C1@pkv_^)Ot_UR
z(Rn#Dl4&)hH5JjR&Mx?|Qt;bwOTY*7GrPPXKLTT`&oaB;GuYOz*P}M&+jBPa6Fxn;Y~E
z;f~Uq8)um^4RMVjv}wbKvaF+Rq?J19#kUfpAFR|yf_tb+RHJs3U;P2C)?84
zS1gYG;-Uv&Ahbn^0jVyn|pQ$9z{&$YkYKkq-`#6=SQVb@(K2z%h#5r{1pxV$dm
zIbJVjXo5STD#U>%6$;Jg--iBy^EO@8w8oh4&K<^upou3&o?rCjJT5P7B$-E}X5I@1
z&bM$~-k=DXJ!kSXV3}fV?|Im+qs|txMw(^=e>HVbt|e|uu6Kr%BDDpWJ;&G}K`Wh`
zT0WLJO}&@|oj|maEQO>k4XYQXgz;ghk#|*-s(e;
z@22}78RfjQi_iV)Gk#)y0I&o1`#aq2G8wz^f%r>t+wBFFg22^@izV=g!2c9^t7Nv&
zd4q2q>OprH6f;)O`|O!sxR{+#`&ChNIQU!e(IGoRHRGn^W^dNT#kJwjY-LWfuRiR9
zb9j@UT#??dJh_hL%l(S7^5OdB;ra7@1Eu;ik&rh-{JS&e{)+wOg#Sr8fds@KJhtA+
zip->{u28OndjU#qjMAkzmj9ZJLfhbtdIFXS8ZrlbULhui&*|NAU)|yuKN#a*U8JQavR>YT{HM=XllK7KG|}!p`F~pI^r3{h@wQ=t%8K_p`yYR
zU!mnC!}f_V7ah%uKfI2+Y`s0pUEJB}4f{1Oj=Cuy$p6KX4a+*&%lf@K-j4|DUrDJ<
zeCllamTeo`m8S3_ebhIX`ht?z>3n!T^XO0oRUv^uUogM*o-t*Hye6j9%}Xau!sn{X0AHW@Flyse8*V5hW5
z8lPP-4_F~mN=&R>Z1j#aDFY9bFcGr{JtBng(IYKkD;y9$2=cY6Lxh+lX~3;MY?88{
zg#+4R$<&=e*cIbuO&YFd|Ef%3!xa-Z*?>w;bjSW{K
zaw>8=QVDlC%09|9YCN(7#~hp;YuSNQ0_s51<=)#F$C1XB7XOpItZ$=KAXh8wCDJt6
zXZovwp^2@J7@Z$EXLvpD;u^vMWw!;#<)Ixkb392jNtL!&S@*--xZEO5(RfR+C6rAz
zXca5VAqUO}_jaC^*4=?wAJxZeztja(4`GRM$I)2Mmdfl{P}xWQJF9j7Vz_?q@Ft34
zH-jWA?!0!-8t30258bz$^Ja0H(48=YG?UV-$ksIbT5e#TvnG>B>w`*A6!Io?i6hMU}3q+E{{iK54WamEGrSQ|{Z5fuvc6HtRj
z!0|X~wY{M?V0rvj{2a>AsMwYq$jm+^3mHo!x%6az&jsPH<3{EeZGfm1tVCE;=wDy#
zG`p*(=wt`X?~7+8`oB1lJsX?YEd3&RYHL5e@`=Bd0FW`mTMd@yxfQQ1z!tbyI5b1u
zQTw7g$1$VrO5AguJ%5_8EwY-VTc!7XVM
z3xRx8La?aV?R{>{6rmMb#g{*FJu*0xql4vmc(IS#GvcN9!@Yym3^`-_4_%S~yY`mU
zHswg|PuGyRC6CK)zMkR;Wa&4B1I+jfZNot>9~p~$Yjam15Y&M$+0#01x+H8PAh=_%
zw^8bOel5;D+)#M^2yIn3e~s1%HPQidl65Jt$1l=Q=&X|lOZm}#^E>H=O!?rp{n
z=w#MjkIKEf|G<(7$K#LE67@V1$b1tH&Lj>cb&H9uBcgke+V^K;q)vKwJhDdR(mYb6
zZuHG`Ce^Ub!cG9%8vX$P6+s@}4W%^apELNmX?g^%t8H@2v)PrM+b3{(oDW@x7r0V!
z$M56FS#HR8;)0j+$xr8~FaBC$_dgI=K9DaTceY1hMrwl^gbe-F!gg7mOo3DKm7cp#
zCljz~giad&0XIIt<&WBWbRyYwIv?4LdJjR~+7TmHm0!DfFm@Kt1Y+JP(IS=XRN4u!
zFnH;D<2LO@nOSGuEI1!0!eHW<$;K5AQSP$qqu2pv#tS7NBeFUl5v{qI0_FYOtkjEv
zUPa)f3istspr5kI0xI(^N>*Thch{t>-$(V2cq2v$v`4UqpE@-0C?Ev(Ku=MI7L7Y1Gr`s
z##iL~1QB|(UI$m+?p0XPu26-A>gG~n-S0Q7f(Sq?3@
zU=sJF@ihQ*|I8IRfE~^5K=mo+2v|x{NhIzm<7*qQg-YeCfVY7!x&j5~xkfLsOrLH+
zd4?0E|Nen{lRQ-EKbcDY4>OZ2@(#VuS~;(UKz_Oar_Tsly#)5(?;J4qXzvpV%mGi7
z1Zxd=*>5B(|xL>v!~=^C1Frfo4T_qAtR0tGs9U{~Z(j$=?4cnZ^O_
z=tg~%`3_*z`3FLS?|{Rr9M!J-JS0bQNY;cQ|3BrWrUpwUxFHBNer|3C1;9-ou0r#m
zUTFP;Mc(RY6tL2XsgMSMtS9q&7B%FI{6}g#2r@0|A-XBHsn_)0f5;feAT)5#!J`zJ
zl_&#JH~pj@{N`~e1j!mHh7LfP=>dyA!2J)MuMvnjqANNo?Z$i1Y>*D9AEzOz8EudM0EPdL7=Zoly`;D_g1UGPsHREY
z)|JA4hEgFaKM^y9jz>R6zeYcbZA7j92L8F&n^iJVn{I~6>Ggl?s=e$(cYs7G;&2-J
z8x@kflz)i_`l%x@&uye@U!q+8eNg%WBtkz!1nBmrNW>o;ZE#$yRv_JI4qXbs$Es9M
zpsYAMWvF9-o(+y-|F|qN8TbeQZXJ-bVFd5M^-`Zr1gJ&J0{N@pMZn!xN7zhY}DwyEFL{(n>^LTHG2DR?EKCTVB#CZmCM
zZ4j6RbdZe{JXil8Hktm1%}3$T(sAW~pLqxiAn+hOg-@K3x+O3FAs9n{QeplLFpOFG
zJ>>|Kt(ty(qJcjoGkJ$kU(ZB&^
z#?b+V#YeN4YycLN&KGoc8^}p}S+;zOVyCe_44v8A_&Ut1^*h2sH
zzeD|49@*gSMcF+55rI(z=CS@jy$C7Xbtd7=5=?Wb54;vK=l1!#x*A(=E!_OEg)_}{
zVpbSDbkv!3TB_kOV#u!N$6Qo+qtYkI|gUBtE`9_=8wUC_xH(Cz~SsT+Zb%!
z<_PUz`>J$c5J;YUc}IMD1td_^}gOO?er;P4?dkSlA4pfVN%g)!-@NNp_D
zKX`*%|MTY{Pg*eHgh7;66k8eF>n$2w+*Xi7l<#{q^?wu)NZ|326b2+0(;Y|x&S%?u
zYrF8qLs%Y0w*c?*cRp!l66SGP`kSFV+*T;P^<0`EzxM6T;_(2F`J18BBBv3aKUjMM
z+^$&qQ=aVIM}nt$d4UUON-{kFh{a6-z6IbP8|ngoT6OZnaYTubv1Q4IqrKM_etPWU
zSvY0k0D?=CKJ%oB+1#6Hyi7Ml#TdE>7
zC?-V;)tYPsK0ux))Y4L=4!n+PM;I1d#Boz6Mc!2=M-`WaQ(Xw$W!im-DVlqbdbpgF
zCE?@?n^ZjkYjL)l%$>b6Zu(GEL@)X-s8yi+C)%c8=jK%0W3I%Zfmz@1k1Wa@ycluM)>eJcY=krc}5j1m+`
z2k}IVb)-0ls%$RO;fO?wle*T#(29a3UITA}Y}!pNbs)kSdU%nV=iVE+&>6QT-^&r{GEdt7bA~;no9q
z{d8`WAPNo=57_yIw(jyD069PAcA|QnJbFBGE4U+->2@kScr2(aRFJB<7ejm$fS!7<
z@$-qe3{g;wrlW!le{J0>)(}yY6u7vIks@`%y*qCc6V-us&}SdV+ahV9`~xfQ
z?=^C8IsWmA--WFqA&!`fi#WQ=W<=n<#$c*LeFZmluz=wXO;z(
z+dS@bw}*QR-T*cUekbI-P614T*U^Yda(PNk!tm)0ph8caf#$MCg(?^-hf{E2dQf0&
z+x5vl==$C${W;H?Wj>`L6xXYSGpz$uP=DkBOD4UJAPh}#VL{ffn)r(8;tm$8rC#9L0?
z!TXf7IE&CDnbX`oEp7=WfSL{QLXSH$xtks=9dXUIDH
zz+V34Poz`+icnk@Kvu-#nSbs{&m9p`vc4mK+5hcXhX31;{nx2a6ymo;VfEMozC`k5
z{-`OO`^d68RFAo99-XXs2|xaape}F67}xeqpBwIq#Q)tfy8(&DNWU`d@=qbw;G|S+
z?ZY3;Z}flpGd5fn(1SO315lagqrP>48B3ETE?IZ$A3nj4#mvRUVS3jz+@JP2ksB(v
zH}kqxeR#jx|8YdwUflGxIjcm;XKw0j&^0fg%o{E|kPbcyJJMoHjD{gpDV`)S-KxT-CK2|CP$nodRR1xjIN$?)
z9m!mKP;y_?`OuUnO$wJMF3|Wn)Y}^<33=6vl=^0)Q^0BQ;eYm`GZnO+kS_g&YN5OH
z(|?{EQphxW5b+liEhPjYBLR?FNt6<)O8t9{6*4VOHg$h#l(!8aYcgD*dRqP`
zI0zWkV?C?z=;*B|LdQsp!GI9Mk)BioHb6~8&D{lrl;Q1pf2>m7v%R@p(I44&=~|e9
zqv*u}-L|v(yXXwnbI#p(is0q`c^P-jPbFiio&qG{8@zievimCdoE}sIIs@->s89{^
zJR)j{Viu)5zNKm=l*UC$i{^VTOA_~2s+`nXm;ml)Q!UN~a=7c)0yF0143(4TTAUP<
zu%gthEo)FO;%C8E9-tB86Y+AvtRg{m2VSTt%q2lB1rQ??S(=}{^2CaMc5U+==7uLga*04>Ta*IaUtgi6QutA%xM73IoY@1E
zH7L#R&xUH@Pyq*fshxG>&s2M`C7!*;nn*Eh~-Jch>G`fko^VUosiW
zNsXo_E3-_P2Ae}0h
zi>>$R5ELYuaFy361>n550Zy4xcgAPi8&Ep@SR0rroz&KRII9H|`HVT{P|GDYawf*fuTjroo(>tk+q
z)fHmHDSV2DE5UuQWT>$$%wB?jTM%xPyr`NDnf1YRhoh&0kYoPG+z|vhk>r40oqIVK
zZm(CR`q8KSd)Tkomr<78&H3gdjjp0UW(-F(Bn1X<@-!sPa}qyiFPMb=^V>fJ*ogR$
z!Kd^gLPHZ)-P8W&QnHjG!=YYblm^KJv$EE1xLcMEUR-;!jx+k9U#Sko2U(I{8l;N9
z=FF8dAFRbBWR~p^3ziLF+A^wzn`h?58;t-Vq9RI+sx-s-fmi%A-uYS#}+4u>#A@&i+
zzLAP$!embu*5#Lg&{@rl6ep&gv1ty^uxN(#3z-Q!(xldvIwmM+!oQot?(yqm2XPh2
zODDmdjSp80w-a3NwW`2W1C9e~MT47TCrKBl!2Q{j<`6bq(vRP4AOamDCEdjmF^nMu
zJS7pekwcG_sVBZJw|@8$0j8%;5QIy}8!9ut!Zf2JBDZy~$!k5S8aFb2v>
ziLaQY6NN23s>bt~wC_5f9Z5^--7pysbBXm$M=-
z8iQZ9Kv9s;lZLK|szZZ+UARRJ@m>k+M38dNjX;r^37Ad96>(5t9URI7vVT6chaBBM
zfkDk}PsTh|97GIt9-X*doJ9~SkH|OR0vB{nE-uQ|+~sE5$a;jD)q9!L0m15PD+3GJ
zK-=J{RT11(>EwpE-vU08lto{Qbd8*})M2N%HzXF-s43vinI6rV2Ea#p(3;HH@D#X!
zCB?+%wX4G*f18upEUn8%p46T6l=5W21vdz5%fi-E7MQ+nNA~S30@q+64(K|LIclqh
z#QmvxAK;eBMQDUTn%PLD&Kr{s^ADtKBB01L5_b)ARhk4w1WV+WkmPfnht?M`kZpqp=O5My@H=(xD&DzXla$
z#3aNq$TQ+K
z2fQ|BOn|<-`Vt>X&eIb=A1(B>JzluHbXVFv-Q;Tk-$N@)eZV;bc(I6`aMQw6hu69l
zR$O_Z)DWaWt=W%T{3dU)y-Ger*@~4@QJtUvnFl-F7#m;)r$_Vn&=H)ysfj{hlF@K<
zsEs-N1Ya-bL82dLJMY=oddt5bop(dREi^*@0YNpj1Q1W|wb`?0Kg;w8LF-ax@!B86
zLr!;oXIO_fujk14KKVT7^PLe)K$dBKYgI8gwA`Ok<7>-W`V0!)2CLIeCax8(XYo+Z
z_~qxGg3ph-MXatbR+JPBo@bj$pOtO##7cH~=ag`9`Xmz)1nmSJk73!4(xOfxGnkvL
zogSEcdaif)U8JLRQ))4^!J{Mmx@50$$|}Eq`Oxh;q*}bYc2k&sr7G!ORBqHdsf((_
zo9fEyp|-rsg?{Thqi-kClFB^qoiEH_Y86|t6}8s1(mL?|>aKR&oGMgCw#^9jXmH0tq)qYAYs*m8@q=y>-KmWs|r)1h8O7_fbJRs1&(cB#aMS
zekz~~N)(gr5gNp`QK%cv9TiyIN)kTAl(I~3BJ2C+UNF3^z**2;=FfHL7+dIBZ`8Zu
z)kUE%yQla5G|i63HkB7cp`|$6QsZ?{bVRi12B90CCP4{qHfoCyIz|D+BXD1V=*qTS
z(Iv|M8}@|oFg+MSOn9FD1imfZb9F(}-QCtl`2_MJP|GO)sCG0d>f$BB5BIdkMN9{R
z)Qb8&x)-w4cECCZ&P=^zi#uVV!_6*pX++4=HPwK3n1(k`YOQ4s{JyN;Y65QeF&=D-
z2HYtD(}$+~C0~RNMiWAPl+xcWlAjY`SWDSOsm_VcsWosqNTwuEsQpBZ2pi=+EL5Cf
z16LDF2kMT>Fg$5Fke?R$Gi3=^qCpZ}NI45j|$gQ_QDwu6;!sgP}5TJ#XU
zZVyiDBnF#tCEZMcL))I5;0_7FBi#Yam
z9Y69_vL(9rzvJKpK#=oMcQfC#5@ZTNuD~mG#bdlp&kU!^<>FddhVVxZ82VDR=mw
zv*7+XcjK6-LCa2$$nRbLn6Lowfs7abLHKin#BuHe*l^dl#pB$FE_sS((S)ifaO7F!
zZf&*^69TLxnWp6rg}UPG+bzT~1dQ*HxDoBBj4wvUf%Rg=Z4{6D7#?N`qbqYUf>9x@uuHy7x+N%`L=8GDLyNj6meXQ=m8j#y`LXS6c4z=;r9NbG*ApIJ%Y(>BUO_WhsFq)WxIc(eX
zJEC5go@+NzUTfnf6Ar^C_PcJn>-N1EPu(_Cf@=wFM+&8)9z_nL$(d5yqY19gg89Q=|2{NPNpSx`%s0#Pges~)2WCQc}`jZ}rcO}Mb;
zy&#e%bP2wa?u5wk#SZaXVRKd(Y?9y`+}~xP=|n||G%5l0exGskCGpfW7F+<94BDV@
z5KTef)^7GJ+Oxg6TK4bqFnoqK|I4=F)vy&4OnYG`)xxLz4i(;}skCkLOV-+EJYqhQ
zIm3CJ5G#m1ITi2c?~K8EV+(k2G%@q7xsv@aI_>=>y-2*cP9u&P)*iS~vLs%2w7tC6
z0p=;+Dw4bf5#q+zl-~(J$<@eJlmtCl%@N*KuzGHuQ_O&Cfwx0>1qXai&56=?GBNU`
zzDsZMMvjr#+jHr`mOx3mVZGRS^>w?&gkhi-Qw)189Y|?ONmB)S8MSv;a5ZeF`J@Q7
zz>+8DOANg)-_qWbCo~WHC{;_dCZzOW5R`(uN4|a{%Kc@E8fluDaf!E7=4G|t0Q*9T
zlV>oIcwkYXJMr0vo=@J`zSCEc79(R7XJfTjRZEpOSNV{s#gmL|YH2;wV25sy*eH2O
zbLFBOhpj6w!qtAH#{;U*cG@9iaYmSN4VJBd#5C=
zPo8PkHZLg<1Y1#F$~VceBETRpDcJkJ9F`0UOke@V6YE`y*IhTgcPBmW9t7_6(e%r6
z!lCtn46Br2t4=&O0vf*Bo}`F)R9YSf
z1|LXReuV%W`JQp@1Yl1asi~8w+nCc^ihNJ1VSBL$2#e`TL3lwTG5%aS1!-AC{B@fOOdw^#LIZe5_?Qoj$
zak2~qs|CyJlkdB<8%c4k4cYqz^z%
zY7r$X^l6bK2o85j#NeZUWj@**F_8}yHawcNS+7Qip)Q&bp~>WI!o7G`BZeny`8UM5
zlQBV1r=&s|yuZ3TeehRY9k5!yFD&^szoFn(hNf$hmW1$^^RIyDGQ(rI0!I-2g^g4a
zKDm
z0Lit55L74D7yr0Du$O?7RFqOn(jrajQMP$^yQeMqZT)EYivzXR=wM#)U#+q+XCZb{
zXKa}V)qV1hcmKtrUv(^hQndn8qhz_~G%MhZ`mpvc)JIxdaGy3x)*4oV_pna*;4OkB
zDvWT=?q%l#ir8=DGycJK)g#fLH@qQ#-3?cU%iwKaTH6)n=p`-7}8FoyuzGAeH5PA32=h<-iT|YtLcHM?)`=U2yZ?$g~i!U^tIelI*
z^(A7|Vzp7m6Y*X9@!k83=vN09tIuW>`%^C?ZrX2$T+^)|tVSI)?1(8*6ecp;Hq?E;
zsk&_+yfn4#7&*Q$anY?n-FEi`C98MsPh**=WUPplWPBuyQj%81E%C1^s;}7LVIPy-
zDdRKZL2aTV7aySYjJ3?CEX{nMuGwg&WZH+eogk7XnEep%iOQwXuQt=ma#hs8E&lHP
zc#cH^W-TYN&NiI2A%VVD47=^`f@rP}S7~+5=i)Z3J8C`*Yt0~m?*W_#q)VZYze04r
z#xG;jbE34!CqXSS*mg@%PumR9#xGzxZi73g&2mAk)%eL2lKCVoJkUkE5B;|UDW{vi
zLWR-48=ppH#o*mLqK*^o3=5!AW4B@4eS`yZuyz~OP2!p&>+JC-USs{sBdKgcRlOW&
zV)89tR4*^dDS`qkf~cQTnZ5RYxUfdVHrrN9#TBi-e17o4F!Ohf{sdWJ$rlv2>POB+
zFh7*l(Ep+D>|$!>c=5L7-~DdQ?oRBPdhN+`?k0J!?w*?bplFOjDM^`
zGJ6-6*+!bLP-?{JU|cD`up+wM$Vg?K`Q#)?6&e_j*dJ*AM!Uv-
z$=h2iy=mM{W^Fup7t*a2`n`YwcfexDs-@
z|HZ52qeCwbO#;yq%HFz2Ph0g{~Xm-qQy
zYzBE4Wsm$cY2^6v@5x1?DVyh+sCGVVSShNV$EdfM^?*_GxeSQe(Bfq*I}4tCltR#D
zjH@}#g7Hc&4>q#PIbM)qOt8o)|u-k2Exq6!jSOl$HAueWgErQOi6d*
zK8*5xFw^H8Q=)sFT=C7}E6&^gWdkUc<(nt&ZcaVXgB*8W#UsZ{JV6Jp
zxL#`=hsR@1)j#z;5=CBe)%u~k9^BBD987h}?=_DiS-dOX{`4#0q4V&Wt`CSW|Iya_
z#40yFn2$C|eUY2R_}sbqlOXrk6tex>_xUg;MLF7RCIy^hA7k5JA~q-9_e}b3jS6q|
z2L*1NYzpF3IbaS-g7T`{wctvY^zlC33E4ENZqUA=+tR55-4^_1*ykDB!}8m*dspAY
z)bPZ@;imV$20!DLz`acV0L`tC$np?F#yU^P(U<54`U&%27-RPl0Y5e-OedC2sgEzM
zZS3T!H{X48oDxokB|ml&4-|S*ssp+a6?r$)Y9M%8hN2LDtwwKDGT!ht<1H2BE;C)@
z<7W-cUI>~B@vPFQ2s(9Wn``~_iT?DCE#wPdPmjfqyKG7}w)~BXUUuG`KK_q6eKhps
z6+Nx^?<6IJX6o&-N2SU2FNdv{=nHBT$EEk%=@i@QYjOM5BmQieSzP^!e*Ye@a6+s?
zy_4M|wZFUhvXuId69d9a@4i3l(QC0f6XGjVxF>uf-UkTC3axpEDgwdUV|0us{+g&b@PE2}hwAfHGWo5qA`8T?Uqcq8BPg9fZ
zDA%)0h=|ed{(mf^d*jY}V@~UTuPX@3a}B3r+q_Zl1x}-47$l-;L
zZuPrxfg+2kRU6W!zDm{ld*6Sb#CYTT^CoUq6(*~uI(8>ZQ$2kUw7{GKD?!cY@9`$X
z=zcni&sQ`|hl89aa7d7TlFU^Yhf`Pfq@fL}B!zm>TsEtB+WBTI35KiZPTvd59~s5j*fqah74d6uf1YOTQI3aw4D;wrrSW~7@z>kcvljMBr!Q4jZ(Lt(l&pEn4W
z_})&Z=-1!#j^i^w*ApBsjPy`Hl(T0$9>#(XEeFT{Lhq(o!)~I3PbkrjRNQti6M;lZ
zJfq=ip7g`24PQQDgT9|rhyOK|cZT}K;kHCOlcrUC2@fsR#~AKEFQIpMiK6k3fZ{DK7~9rUZQvVBNc!
z1@nxg6THtJ7umO?!}vZ`;N0l=m)AS+*ud4l+Iy!P+d!KXxQ9RAGYlJ;EoFX+%DG|_
z$ZFJ*J`F@ycean$d1W#f;kwAD8&2`D_=-M7RSUwGP2mD{Z*s*44Z^_(#+B*r!eB*k
z4kXp_CYfCNBFrmrOKoFqw{WQt&AM*;xWT^^A~34ZBf+)#%t+$H
zsoEo_+}hhTVH37KU3gnhZ_vx24`KIT7{F!Q9`k1l(a=m8*g@f@6P~UO(^@VK)Av3=
z%ZoHtEN~3psc!z!=K8U5cC25XR*y1x`r!xr`sAe5oG?>v3vcd%6u)?lh65A2b!H}>
zUxKmxn_~@5rh$3LJ!L^^8Sb>9a3k7;!TvoVhoy$G=YI$zRkH^DckSyK-);U`@J9Ys
zh5FVbG4x_cCL2e|>|8VIguy<$u8vn~P-_v*Vrqaec~)-+u3kLk_kW`jYQ^vG(;sxz
z_P4R|5~ez)hYaK&+pLO20t}P4@-Dz1aOJ(vC^>y|%SeN+nLH_+*>df#b0D@6?Yty2
zVm}e6wD@_7-m!Qr4B12oec>>9{WIbFpO6ehYdrCqmRQO!IrO8#nSsVklW-2t{Le54
zA|q`tDx>NHUqP$u1>HtmcrH`xCXda8K3;{$vTkC
z>#qrursJP;w5g~(UTBK#GqR~}l+auaialmqlp*^e7XP?9;$?4*qS4ezfEnRQP=|H*
z7JWy%8{eneMQ$vAltlK#hLQGpbsi_wsTf{y)ZX$81QjRPFiIO5t{!%%w@ge@f2a0=
z6c9~$qz2^{m+QXQu_QdZF5+3SAj`zWYW0MG8N
z&zqz+qVWj+jN4c2UvA&S=lTz;QEBC+M&+mlz%nMI3qO3mu$FppTsGVc`1LlEx-?8ppb=
znQ9Y+>E3mt>W}B^iGDAFcYR%HL2n?zALQxGUBmhP!>YTqc(uOZljoFMy!$5YzuU0W
zv{cvOJ^e)f-&T%)usow=PP4XQ`$Z<%*b-t{C@K_1Wu0f9cRrOFcqxJwv-0s6dIoP>
z)c$Vg;lBHXJald9=Ugm2#w;PTB%+E3i=#jcn?b&JVdAW$G_y5Ex-BNnu-e$w}QE
zWguy8T+6A>fN1V=_rB!ak5#NqxCiWYF1p${dJ}+jV*wgW)u_w@IBkG3ed18{y$dZ(
z!03^?wNxQ2*r^2}$X{5W-+gbRwfpH7HWRDJF2tMkHymuFAk%IW!+p-g
z2n|CRK?3FwdPE8NODmur{NlOK1Hf_ZQG`-2+Y&-uR3{zYxd&xV#5{x^F+)rR+~mw)
z;p2$@4H4+<&&B%Tu+MbJ*3aiuC;;Nv;P<2hf>TBg6ST~gozE*Q5Z9c;mAl$vaxQdGP0B^-Oku*AExj}Cn8
zFp`L+X-QG7!>+cO43o4BCqj^SZ6B=mE$J(@;1TD=Hkda45wA-OK5yIp(cha>_*Z8f}KnXgg1v`Zx
zlVB^RJD$=wG{0+X4aRc~{psNfI&gM>v4s^fP@?F*SF)8d7q?~#&S`hg(ceO&GmXKt
zE2>%vNm5BB>HB}AXh~VW3kfJO9KWTvEqvAwhNF$J*LK^Zj*wc`gOn2KA1}U`!$t79
zZOCAvL$g*<#2drEuD#qO-3*p$Y-gEG2K_^9(pm#>=PFPk;ECWc
z67HV--aYdUPIWxx3VqEU#pxpWvKAUoPN(oWCS;*sP$S-?psSY
zM~P$^Yl`kYd?(b_+4mi5QhA)vSHZoVInv##A6paL|7DCn16m6`Dq7*g(%Rt%e6SP<
z4dqYIEXO{QBMpt7N35f^-nKS%i%~M0>;%(8vbdm9K+qMc59C}WV5ESmO`VCyRF#8*CLStIOLlGr$3-%9o-3HZ$?E&x@}{GS=>qC?
z&aY*RAgj!RJs?5FR%W_nNy;F~FDya)oZGp{^WDk4tta%c;d^)&wuKbm$hw0H*E|OjpU}ri7Ng9jL({9WUNJq`VzU`NKU}_~o1rWHwc>dHy`8EWBnt@b
z7q^~BRhFzdy$ta_;ElRB)XDBLy+mzprV}xF-N9MN9
z076U%@?W;_>lD%>I<>NmBnNV
z5WL!}pmgcCYJ63bZ=3XsN;r$FN*b$p-O1lezOVm8@ckJJKLvvqJi|bpCf-I}!^!?&C(_|H0iNSxFVf52pY+
z?WaGTxd(NetlRNMD?OE!f!@>&OIj0Ha5%&2X}y2h*jR!vxw~n!6puE&Bjwa!
zOaipYpMEYNmwM?S(eO?BjnqgK+HI-S0i;Ba1qZ2&;iG$jA)C@m6gIS8;-aKMWI@G(
z5;R}%uq4uVp1-+Ia4vg5djMX-U1BI86s;MIV6J6i;Br=9;#f)>P4y2CqT{nFAvTpDaZlUA=QLf99AiM|dRr
z4m6idHr1a#Fg}1(=SFr0a@BHq5sVV;s4Xx!gxGlfC9^SswOUMu5Q;LM^9MV1*rMYd
z%Jv?`or5DAqLLl_ax~)h@1nQSw!o~`4-UqeQyA1W`D(*oH0jC!EPL6;J^L%-95&X5
zCOR?}sF+MxxoM)Q#UHJjS<9SW8;)uXCrq8#%#F$edY*C+X8wynT1ni>J-d+@u(`pj
zWfyJXdqq!(bD1`8D~zMa)g8hv9z;p#2ui}-P8o{lMChk4mdfvw=D;W(WAA*alMg3)
zm4uMk`g;#Qw?*jv=h^fm#ocM!zhfS`MuLk?29-PCzP+=&eEoF~OF^D1M|rWEMu^z>
zT4di%*ATLIe#U;X6#@>Ws|@kq|LX7Ow)j`a>SD@M#w7c?#TpnJe+`Aw8P8`9nZiPO
zH_eu~>n{ty%~|koz&2iDSkL~VEg^M=`r|{2rvwDJ_L#(A8$?S+Hi(ZO
z21qWP9UidMn}0(bv1*O?rSjmu`PC6V^nr+|
zY0iJ`(_KrtA;mAtiL2IfL90hEWkt+q9@Qlawx}Ujt{T!UJ^zqFx8pTstB!}O
z!4@z36t0tQ(M7hB3d$S*Im6~YZQNH_$tRN2wfW@
z0u{VUKU%Bz)T5Z~ulNpx^Kbpf2P-FJ-c0SwE+G*?pB-oJtVpsvB{*z%n0P^9iqEWO
z)Lw&&KwNTa;c62$akYGu*NEHojf_RlJNSnPi{@2+9Kp%s61k9P%Oq&ku%h}($T;Wp
zhCXKDNr1gfVXG30bp3d*Qs#_jAG5K0$MXe9ZievQqsqPMTD#z>(+cAUuJ>YkP!!|>
z#?=<>JHQZe+17T;MPtX4>E%+Kr|;Joz5A6|3H(Bq(6{=&IOQ)JO<|gE?lYc0UE+a%
zcJif%9CPIovKafD{}278h)iWGJVUu%)C0s!adT)Pq^{{%Plz`jFb(hn
zJ>tI|XRp?sx?*lp8sGEp*Q67oC022!+qh=p^JbD;s_C>w}^3IB%uff
zX-bJ2q<0YM?-%FozTJJF-97)_`^)d%Q@`irchAizjfwE6c^ui)=O1&~A^co#l7PQq
zc=oG=Z!2yQlP`Q+Z@*oMiy!Y(dY-+)qGs$ZPhMnPSI#@tNy9gb*=L4FV(q;bhHH;o
zw!WkmyN!ryf213v1cTu3lrOn2^SuTBx_Zb5_MZg4V;*VjIKe=R?MoCr$9CuRY9AlM<}|#
z3Pj&N^-)I^sz&8DNw^itzDO>@GhnWI#c!@K_AcF8Fc8ugjH(oG?l{w5!?0j1lm=0T
z-n5frM@;#UiTje{PFk=x7+}}B7TxSu;QX>icy0rd5y;pp{Q9;rkfHK?)x^oFHRJiJ
zSO1Cjir1aZ`~VLiD6|`>+jS(VE3asP^ptcMzBE(v(U(X(m=B58wwV?}2-5iS6DjMM
zynV9>c%6=~$xcTMpOhS2PSpbE2pu*_iWJhAT%C5PI)e>=D6BK)1qh^6k4
zaiXnfxry|k5*q2uOO9E@wq;50S^JtN+`IGf?TJj-fk0NZ$BY^vPdON!5^-ZT6fpFTXH
zTjNTd2O32egTe;tO!_U^WQH%pvTIkUv-9$g7|QMAN>cl>!^kEi991plz4DYVE)uty
zP;`mSgdjNd^xd)R`NKDnS=Cv)Sh9?$fDRiai;MtmlF?JtA87FDm
z=)w-b9Z--(Po2RXz^qYq+}OPg%#%4MoMF9dU1rX;^YA6ZMOBV2&aZZHx(?h(^UF6A
zXiO959*dx@&?-mG{95)lV}vvWv&Cpf%iF+qBr%0K{I^G9wuUv;Pkjwu*Jm7k{D6Q!Xfp+v9WNKKCA*uv!@N84)Na#uNPVxcr~r3aed<@-
ztJLs2ML|HjsO%xDPA|7@CijPDhM&g{
zJM%3WIc(7-KB(zsyxOwy*`nxsv%8t{hhX46$w_PyqS_8mlUzL7BU#^IKLgQ8vCI@B
zt+UcnG8hG^mRVt}o%yHS{cQ-`IyejB+rB<4u;Xv
ziekSUAg8s*-en&6;~5vc`iIsvxn-Y5^=R{R&~SmEqsdno^%Q*!TISWNn?{wJI6RoT
zbu*6fg&I@lTT5p6U%Uxi7!U(-2kn{9YdeB=_tl%B)xb$0BGv1I8gy4L#BfoPpz$hu
zIFkQGVbM$S$f3{FpWj$YfJPN=D4I8EiAJQn{?-#(Sm^7ib#LHPE&*g(fGA!AmSOD!
zTOMG^rMiC0=ZYRszgbXRFRcR3&&8|H0Cn!jLoMH1#*MCm9a?U`
zRj}C5eBP7M)~V|(%3V8%g^sO|=i!>aNS!qOm}`tmk}q`vb*E)ag9%I|cw2PRHSW!D
z&8pH^X{T9vXKy|&1#%DL#E)u;4_@XNl8kLS6;w2mA(Eg%@>}lfKghyUDLe0tYM4A`
zNWu%KN)vlfx<|=)4K#H`9d(!QCG*5_P&svrY6@TS$a(t6_^V~><;oaS$fP7(o5|Uf
zz!S2eh|Y;Nn4Bo$goH?@?WW-3o#n5l+O`_rkZtkkJO}^jv-uNNt_-lxtlI{WykB>vgh!)0SNbY|uNgjEogd*y=#OZHl?=#GGv@t6eM#a3=voVx%LdokLjr}y7<
z$KB_@ml1vmJABG?^x&YK!E~<$!M#?E;2P^N6^aJo^2kr%6(`w(xPcY?*upM#_r7q+
z0p@i^2SNFj72Bs$YxLGEG4iJdbs3xaa%ig8ca+n<+Ot;)X>N;B8+F5nrj%l@q&<-)
zppXu`?a?yQC08@L7ZlVFv1F4j*5~l=g=)g&riNW-OF~(4U(_HB9oh@nPsi
zlyq%3Sb{2^4b_TGR@!>pEx%4CTGY>4ZZtp
zHLuypfZc1!jhhU3=z=|}QWaMhE{*rdG-@(dKh*RN4wuATrclN&=9FS0%JA0D7i>P1
z2rsO&<+796&x_4AO2-mb#Rz%_nBHPgs^qUo>u*A1w}ktGQ}kk+?haeORah`JOc~Bf
z!dQ35p
z_zl(|wgEkTVE`7!iURGe=(_
zI(Ua^SBap}rgtbStdiA&)D~&vh{W}VoSeQk@^ELsfuG=MOn<8&^ljs7rNb#iuNH;-
zIrxL0&4Y-wcPQab*jd=NUZqjTXVv%arCWP@?WZhMTNFTWwgS%nY^~n0N>B%
z%|RdeR7!%d2jAbJ3smO>UO->aj1H@48`!mXhV-Nzbz3co4!_i;dp{?z1i>7bbKw+I
zq+B8_K2T$hxD#uq4o9xUmK*C*ig)gojuC4OmU*ZXAo0*!bZLb(%$7&l|AoLl-yn9X
z`!s!xy`2M44bq*N>!%Q+9%8mwR`iK+jFGWcX3l=X@MMfIOw4`vZ>}A^idbwe3f3#^
z%F3wy=Kn^E_p*Ll1T%NSJd{8d0)r>`u7c7Oyim_hvD>Kg)Kw8&ufm+lB~M(pos7sf
zb@q0&Oo*rk5-1#4u@N{in-4hlG3q(0js=^5YXjAROUb9GYU$xmi-xF*HilSs4OP*0
z8gq$O^ptF8`>}u;9#R^lstu5*I^ZSKiey=EC=vXlMDVCl5xm8xLRKYfldOF70A2t0
z5`o@JphUnp`A}?8Fa#8$+mmVx&))YySQvZ`CJHHoA~8*W(yfw6Ar>0}ri*;hTIYEi
z45X-V*NjqVjtjyFh_O91lysQD8I>J;Y=8A>XT0K~31`1nPj`^um%olPb{Wc?o0XkD
zTKAmz9gnO4A7ef&rheMy1?Yz+(I+&1_W1Vz4eX{$Vw{)g5*AJ5CXsLpGI+e|C7H~S
zs+18~G{!$enkUS{84JwZ0EFtL0d_%bxz-+C%js(62~mwqV>n58?f&Uyu!{{aC
z;DxSI5f#(zww~v`TfcBC-gY*lfZCB|EC2H2jt`fT-_vD>Rv!y%>dSikuURW8xBpD>
zv*q2((I8_NBp`7&tTD@P;7xW;pc{gzN22_iUab-ho?x%3`S3I%R~5D_qJRc&yod61
z(SOUh{db-T;cp?BT|8DF;Q~GhAUAm+QR2y0&>$t3H^Y@#NTYe`aVDtE-hdrvdyzC<
z_5K8&2ypo<*ua~CzjapLyDplM2>*0BLu;v!tdd?)PaJ#gBu9vKri*jd&aAY{`
zG47}-XO1c-h=Y7s!M_ueX(Afs&92LR_qD^;bL*I|^pBlkM7dpID2;>lKm8P<_5!AX
zV+&AaFxQSwso};_bR5{t)Y^`8@S{nu1Lz@NdK?z_vJ`1ubLxllm
z{Ld^xCMtbaa7Cs^sQyu`u3Qw^I7fpg72Q_xLLZY_OA`NRYD&l7l}hV&aHKBbHeiBzSNF07Ea(>cvzJ^9A+Qu~iW
z8u|1xt&M!nVjuhrPxOva$>xdkZYY3aP+H&f#ln**j~Jxop;3nUa}j6&4&EE{SF79rT&
zo_#v{%o1qZ4^WNre}jx<0fL?cGe{A9RPn}&5Fx5r6*uyVOc=A2cXgvpl%A#
zzpS}h-U>ey-AaLH1(DWj@6V4kEsU0VHI;4x7yO>@16nH74iR&`uC7ilIm+&hy*%^e
zIPdpzNtvQtCy<#y+|Zvhfvy$_!sq*Gcvm2LPQ5FHU7c_6GviDe66G3p@w|1|!{0qt
zL171UpYxw_pn7^m~`?h-aVE!p@0_8g1
Q%76gESvq3NPWW8^2OKeuP5=M^


From cc585dd0d6a33f5a5feec32a5419d6e65564e8ae Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sun, 1 Feb 2009 00:02:50 +0100
Subject: [PATCH 110/216] comment, rename guinotification-facade

---
 src/common/guifacade.cpp                        |  2 +-
 src/common/interfaceproxy.cpp                   |  2 +-
 src/gui/notification-service.hpp                |  2 +-
 src/include/display-facade.h                    | 17 ++++++++++++++++-
 ...icationfacade.h => guinotification-facade.h} |  4 ++--
 src/include/interfaceproxy.hpp                  |  2 +-
 6 files changed, 22 insertions(+), 7 deletions(-)
 rename src/include/{guinotificationfacade.h => guinotification-facade.h} (96%)

diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp
index 2797da693..a3081e953 100644
--- a/src/common/guifacade.cpp
+++ b/src/common/guifacade.cpp
@@ -22,7 +22,7 @@
 
 
 #include "gui/guifacade.hpp"
-#include "include/guinotificationfacade.h"
+#include "include/guinotification-facade.h"
 #include "lib/sync.hpp"
 #include "lib/error.hpp"
 #include "lib/singleton.hpp"
diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp
index 8386aa343..ea838e701 100644
--- a/src/common/interfaceproxy.cpp
+++ b/src/common/interfaceproxy.cpp
@@ -102,7 +102,7 @@ namespace lumiera {
   
     /* ==================== GuiNotification =================================== */
     
-#include "include/guinotificationfacade.h"
+#include "include/guinotification-facade.h"
 
 namespace gui {
   
diff --git a/src/gui/notification-service.hpp b/src/gui/notification-service.hpp
index 63ef677a4..c6e862be8 100644
--- a/src/gui/notification-service.hpp
+++ b/src/gui/notification-service.hpp
@@ -39,7 +39,7 @@
 #define GUI_NOTIFICATION_SERVICE_H
 
 
-#include "include/guinotificationfacade.h"
+#include "include/guinotification-facade.h"
 #include "common/instancehandle.hpp"
 #include "lib/singleton-ref.hpp"
 
diff --git a/src/include/display-facade.h b/src/include/display-facade.h
index d46afe2ca..7375ffce2 100644
--- a/src/include/display-facade.h
+++ b/src/include/display-facade.h
@@ -20,6 +20,19 @@
  
 */
 
+/** @file display-facade.hpp
+ ** Major public Interface of the Lumiera GUI. While generally speaking, the GUI
+ ** controls the application and thus acts on its own, it exposes some services
+ ** to the lower layers. Especially the lumiera::Display interface serves to
+ ** hand over calculated frames to the GUI for displaying them in a viewer.
+ ** It's a first draft as of 1/2009, probably it can be factored out into
+ ** a more general display service in future.
+ **
+ ** @see gui::GuiFacade
+ ** @see dummy-player-facade.h
+ ** 
+ */
+
 
 #ifndef GUI_INTERFACE_DISPLAY_H
 #define GUI_INTERFACE_DISPLAY_H
@@ -115,7 +128,9 @@ extern "C" {
 #include "common/interface.h"
 
 LUMIERA_INTERFACE_DECLARE (lumieraorg_Display, 0
-                          , LUMIERA_INTERFACE_SLOT (void,               put,(LumieraDisplaySlot, LumieraDisplayFrame, bool))
+                          , LUMIERA_INTERFACE_SLOT (void, allocate,(LumieraDisplaySlot)                     )
+                          , LUMIERA_INTERFACE_SLOT (void,  release,(LumieraDisplaySlot)                     )
+                          , LUMIERA_INTERFACE_SLOT (void,      put,(LumieraDisplaySlot, LumieraDisplayFrame))
 );
 
 
diff --git a/src/include/guinotificationfacade.h b/src/include/guinotification-facade.h
similarity index 96%
rename from src/include/guinotificationfacade.h
rename to src/include/guinotification-facade.h
index f3e334bff..dd07ad68c 100644
--- a/src/include/guinotificationfacade.h
+++ b/src/include/guinotification-facade.h
@@ -20,8 +20,8 @@
  
 */
 
-/** @file guinotificationfacade.hpp
- ** Main public Interface of the Lumiera GUI. While generally speaking, the GUI
+/** @file guinotification-facade.hpp
+ ** Major public Interface of the Lumiera GUI. While generally speaking, the GUI
  ** controls the application and thus acts on its own, it exposes some services
  ** usable by scripts or the two lower layers. The main purpose of these services
  ** is to push informations and status updates into the GUI.
diff --git a/src/include/interfaceproxy.hpp b/src/include/interfaceproxy.hpp
index 32248d762..26d1761f1 100644
--- a/src/include/interfaceproxy.hpp
+++ b/src/include/interfaceproxy.hpp
@@ -69,7 +69,7 @@
  ** @see plugin.h
  ** @see lumiera::Subsys
  ** @see guinotification.h usage example (facade interface)
- ** @see guinotificationfacade.cpp corresponding implementation within the GUI
+ ** @see guinotification-facade.cpp corresponding implementation within the GUI
  */
 
 

From e78383b0442bd8694472caf6fe4c6a5cce7321ce Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sun, 1 Feb 2009 00:43:21 +0100
Subject: [PATCH 111/216] WIP continue with the skeleton of a DisplayService
 within the GUI

---
 src/common/interfaceproxy.cpp          |  77 ++++--
 src/gui/display-service.cpp            | 310 +++++++++++++++++++++++++
 src/gui/display-service.hpp            | 125 ++++++++++
 src/gui/notification-service.cpp       |   4 +-
 src/include/display-facade.h           |   2 +
 src/proc/play/dummy-player-service.cpp |   4 +-
 6 files changed, 503 insertions(+), 19 deletions(-)
 create mode 100644 src/gui/display-service.cpp
 create mode 100644 src/gui/display-service.hpp

diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp
index ea838e701..8390a6609 100644
--- a/src/common/interfaceproxy.cpp
+++ b/src/common/interfaceproxy.cpp
@@ -30,10 +30,10 @@ using util::cStr;
 
 namespace lumiera {
   namespace facade {
-  
-  
+    
+    
     LUMIERA_ERROR_DEFINE (FACADE_LIFECYCLE, "facade interface currently not accessible");  
-
+    
     
     template
     class Holder;
@@ -95,11 +95,11 @@ namespace lumiera {
    } // namespace facade
   
 } // namespace lumiera
-   
 
 
 
-  
+
+
     /* ==================== GuiNotification =================================== */
     
 #include "include/guinotification-facade.h"
@@ -115,7 +115,7 @@ namespace gui {
 
 namespace lumiera {
   namespace facade {
-
+    
     typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 0)
                           , gui::GuiNotification
                           > Handle_GuiNotification;
@@ -132,7 +132,7 @@ namespace lumiera {
         
         
       public:
-        Proxy (IHandle const& iha) : THolder(iha) {} 
+        Proxy (IHandle const& iha) : THolder(iha) {}
       };
     
     
@@ -142,12 +142,59 @@ namespace lumiera {
    } // namespace facade
   
 } // namespace lumiera
-   
-    
-    
-    
+
+
+
+
+
+    /* ==================== gui::Display ====================================== */
     
+#include "include/display-facade.h"
+
+namespace lumiera {
   
+  /** storage for the facade proxy factory used by client code to invoke through the interface */
+  lumiera::facade::Accessor Display::facade;
+  
+} // namespace lumiera
+
+
+
+namespace lumiera {
+  namespace facade {
+    
+    typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_Display, 0)
+                          , lumiera::Display
+                          > Handle_Display;
+    
+    
+    template<>
+    class Proxy
+      : public Holder
+      {
+        //----Proxy-Implementation-of-lumiera::Display--------
+        
+        void displayInfo (string const& text)           { _i_.displayInfo (cStr(text)); }
+        void triggerGuiShutdown (string const& cause)   { _i_.triggerGuiShutdown (cStr(cause)); }
+        
+        
+      public:
+        Proxy (IHandle const& iha) : THolder(iha) {} 
+      };
+    
+    
+    template  void openProxy  (Handle_Display const&);
+    template  void closeProxy (void);
+    
+   } // namespace facade
+  
+} // namespace lumiera
+
+
+
+
+
+
     /* ==================== DummyPlayer ======================================= */
     
 #include "proc/play/dummy-player-service.hpp"
@@ -163,7 +210,7 @@ namespace proc {
 
 namespace lumiera {
   namespace facade {
-
+    
     typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0)
                                      , proc::play::DummyPlayer
                                      > Handle_DummyPlayer;
@@ -184,8 +231,8 @@ namespace lumiera {
          *  and thus leaves us only with one level of indirection,
          *  irrespective if using the C or C++ interface.
          */
-        Process start()                           
-          { 
+        Process start()
+          {
             ProcessImpl* pP = static_cast (_i_.startPlay());
             
             if (!pP)
@@ -197,7 +244,7 @@ namespace lumiera {
         
         
       public:
-        Proxy (IHandle const& iha) : THolder(iha) {} 
+        Proxy (IHandle const& iha) : THolder(iha) {}
       };
     
     
diff --git a/src/gui/display-service.cpp b/src/gui/display-service.cpp
new file mode 100644
index 000000000..68fe45b25
--- /dev/null
+++ b/src/gui/display-service.cpp
@@ -0,0 +1,310 @@
+/*
+  DisplayService  -  service providing access to a display for outputting frames
+ 
+  Copyright (C)         Lumiera.org
+    2009,               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 "gui/display-service.hpp"
+//#include "lib/singleton.hpp"
+
+extern "C" {
+#include "common/interfacedescriptor.h"
+}
+
+#include 
+//#include 
+//#include 
+
+
+namespace gui {
+  
+  using std::string;
+//    using boost::scoped_ptr;
+  
+  
+  namespace { // hidden local details of the service implementation....
+    
+    
+    
+    /* ================== define an lumieraorg_GuiNotification instance ======================= */
+    
+    LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0
+                               ,lumieraorg_DisplayFacade_descriptor
+                               , NULL, NULL, NULL
+                               , LUMIERA_INTERFACE_INLINE (name, LUIDGEN,
+                                                           const char*, (LumieraInterface ifa),
+                                                             { (void)ifa;  return "Display"; }
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (brief, LUIDGEN,
+                                                           const char*, (LumieraInterface ifa),
+                                                             { (void)ifa;  return "UI Interface: service for outputting frames to a viewer or display"; }
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (homepage, LUIDGEN,
+                                                           const char*, (LumieraInterface ifa),
+                                                             { (void)ifa;  return "http://www.lumiera.org/develompent.html" ;}
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (version, LUIDGEN,
+                                                           const char*, (LumieraInterface ifa),
+                                                             { (void)ifa;  return "0.1~pre"; }
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (author, LUIDGEN,
+                                                           const char*, (LumieraInterface ifa),
+                                                             { (void)ifa;  return "Hermann Vosseler"; }
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (email, LUIDGEN,
+                                                           const char*, (LumieraInterface ifa),
+                                                             { (void)ifa;  return "Ichthyostega@web.de"; }
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (copyright, LUIDGEN,
+                                                           const char*, (LumieraInterface ifa),
+                                                             {
+                                                               (void)ifa;
+                                                               return
+                                                                 "Copyright (C)        Lumiera.org\n"
+                                                                 "  2009               Hermann Vosseler ";
+                                                             }
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (license, LUIDGEN,
+                                                           const char*, (LumieraInterface ifa),
+                                                             {
+                                                               (void)ifa;
+                                                               return
+                                                                 "This program is free software; you can redistribute it and/or modify\n"
+                                                                 "it under the terms of the GNU General Public License as published by\n"
+                                                                 "the Free Software Foundation; either version 2 of the License, or\n"
+                                                                 "(at your option) any later version.\n"
+                                                                 "\n"
+                                                                 "This program is distributed in the hope that it will be useful,\n"
+                                                                 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+                                                                 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
+                                                                 "GNU General Public License for more details.\n"
+                                                                 "\n"
+                                                                 "You should have received a copy of the GNU General Public License\n"
+                                                                 "along with this program; if not, write to the Free Software\n"
+                                                                 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA";
+                                                             }
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (state, LUIDGEN,
+                                                           int, (LumieraInterface ifa),
+                                                             {(void)ifa;  return LUMIERA_INTERFACE_EXPERIMENTAL; }
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (versioncmp, LUIDGEN,
+                                                           int, (const char* a, const char* b),
+                                                             {return 0;}  ////////////////////////////////////////////TODO define version ordering
+                                                          )
+                               );
+    
+    
+    
+    
+    
+    using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE;
+    typedef lib::SingletonRef::Accessor InstanceRef;
+    
+    InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation...
+    
+    typedef ProcessImpl* ProcP;   ///////////////TODO
+    
+    
+    LUMIERA_INTERFACE_INSTANCE (lumieraorg_Display, 0
+                               ,lumieraorg_DisplayService
+                               , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DisplayFacade_descriptor)
+                               , NULL /* on  open  */
+                               , NULL /* on  close */
+                               , LUMIERA_INTERFACE_INLINE (startPlay, LUIDGEN,
+                                                           LumieraPlayProcess, (void),
+                                                             { 
+                                                               if (!_instance)
+                                                                 { 
+                                                                   lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
+                                                                   return 0;
+                                                                 }
+                                                               
+                                                               return static_cast (_instance->start()); 
+                                                             }
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (togglePlay, LUIDGEN,
+                                                           void, (LumieraPlayProcess handle, bool doPlay),
+                                                             { 
+                                                               if (!_instance)
+                                                                 { 
+                                                                   lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
+                                                                   return;
+                                                                 }
+                                                               
+                                                               REQUIRE (handle);
+                                                               ProcP proc = static_cast (handle);
+                                                               
+                                                               proc->doPlay(doPlay);
+                                                             }
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (terminate, LUIDGEN,
+                                                           void, (LumieraPlayProcess handle),
+                                                             { 
+                                                               if (!_instance)
+                                                                 { 
+                                                                   lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
+                                                                   return;
+                                                                 }
+                                                               
+                                                               REQUIRE (handle);
+                                                               ProcP proc = static_cast (handle);
+                                                               
+                                                               ProcessImpl::terminate (proc);
+                                                             }
+                                                          )
+                               , LUMIERA_INTERFACE_INLINE (getFrame, LUIDGEN,
+                                                           void *, (LumieraPlayProcess handle),
+                                                             { 
+                                                               //skipping full checks for performance reasons
+                                                               REQUIRE (_instance && !lumiera_error_peek());
+                                                               
+                                                               REQUIRE (handle);
+                                                               ProcP proc = static_cast (handle);
+                                                               
+                                                               return const_cast (proc->getFrame());
+                                                             }
+                                                          )
+                               );
+    
+    
+    
+    
+  } // (End) hidden service impl details
+  
+  
+  
+  
+  DisplayService::DisplayService()
+    : error_("")
+    , implInstance_(this,_instance)
+    , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_Display, 0, lumieraorg_DisplayService))
+  {
+    INFO (progress, "Display Facade opened.");
+  }
+  
+  
+  
+  
+  /** @par implementation note
+   *  A new process (implementation) is created, configured
+   *  and started here. This may include spawning a thread or
+   *  allocating a timer. The newly created process is self-contained
+   *  and will be just handed out, without caring for its lifecycle.
+   *  If client code accesses this function via the plain C interface,
+   *  the client is responsible for terminating this process, whereas
+   *  when using the C++ interface, you'll get a Handle object which
+   *  manages the lifecycle automatically.
+   */
+  ProcessImpl*
+  DisplayService::start()
+    {
+      auto_ptr newProcess (new ProcessImpl);
+
+      REQUIRE (!newProcess->isActive());
+      newProcess->setRate(25);
+      
+      return newProcess.release();
+    }
+  
+  
+  /* === Forwarding functions on the Process handle === */
+  
+  void DummyPlayer::Process::play(bool yes)    { impl().doPlay(yes);       }
+  void* const DummyPlayer::Process::getFrame() { return impl().getFrame(); }
+  
+  
+  
+  
+  
+  /* === Process Implementation === */
+  
+  
+  ProcessImpl::ProcessImpl()
+    : fps_(0), play_(false), imageGen_(0)
+    { }
+  
+  
+  DummyPlayer::Process
+  ProcessImpl::createHandle()
+  {
+    DummyPlayer::Process handle;
+    handle.activate(this, &terminate);
+    return handle;
+  }
+  
+  
+  void
+  ProcessImpl::terminate (ProcessImpl* process)
+  {
+    if (process)
+      delete process;
+  }
+  
+  
+  
+  void
+  ProcessImpl::setRate (uint fps)
+    {
+      REQUIRE (fps==0 || fps_==0 );
+      REQUIRE (fps==0 || !play_  );
+      
+      fps_ = fps;
+      play_ = (fps != 0);
+      
+      if (play_)
+        imageGen_.reset(new DummyImageGenerator(fps));
+    }
+  
+  
+  
+  void
+  ProcessImpl::doPlay(bool yes)
+    {
+      REQUIRE (isActive());
+      play_ = yes;
+    }
+  
+  
+  
+  void* const 
+  ProcessImpl::getFrame()
+    {
+      REQUIRE (isActive());
+      ASSERT (imageGen_);
+      
+      if (play_)
+        return imageGen_->next();
+      else
+        return imageGen_->current();
+    }
+  
+  
+  
+
+
+
+  
+  // emit the vtable here into this translation unit within liblumieraproc.so ...
+  DummyPlayer::~DummyPlayer()      { }
+
+
+
+} // namespace proc
diff --git a/src/gui/display-service.hpp b/src/gui/display-service.hpp
new file mode 100644
index 000000000..4d11768cf
--- /dev/null
+++ b/src/gui/display-service.hpp
@@ -0,0 +1,125 @@
+/*
+  DISPLAY-SERVICE.hpp  -  service providing access to a display for outputting frames
+ 
+  Copyright (C)         Lumiera.org
+    2009,               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 display-service.hpp
+ ** A public service provided by the GUI, implementing the gui::GuiNotification facade interface.
+ ** The purpose of this service is to push state update and notification of events from the lower
+ ** layers into the Lumiera GUI. Typically, this happens asynchronously and triggered by events
+ ** within the lower layers.
+ ** 
+ ** This service is the implementation of a layer separation facade interface. Clients should use
+ ** proc::play::DummyPlayer#facade to access this service. This header defines the interface used
+ ** to \em provide this service, not to access it.
+ **
+ ** @see gui::GuiFacade
+ ** @see guifacade.cpp starting this service 
+ */
+
+
+#ifndef GUI_DISPLAY_SERVICE_H
+#define GUI_DISPLAY_SERVICE_H
+
+
+#include "include/display-facade.h"
+#include "common/instancehandle.hpp"
+#include "lib/singleton-ref.hpp"
+
+#include 
+#include 
+#include 
+
+
+namespace gui {
+
+  using std::string;
+  using lumiera::Display;
+  
+  
+//  class DummyImageGenerator;
+  
+  
+  /********************************************************************
+   * Actual implementation of a single displayer slot. Internally,
+   * it is connected* via the Glib::Dispatcher to output frames 
+   * to a viewer widget executing within the GTK event thread.
+   */
+  class DisplayerSlot
+    : public Display::Displayer,
+      boost::noncopyable
+    {
+      
+    public:
+      DisplayerSlot() ;
+      
+      /* Implementation-level API to be used by DisplayService */
+      
+    };
+  
+  
+  
+  /******************************************************
+   * Actual implementation of the DisplayService.
+   * Creating an instance of this class automatically
+   * registers the interface lumieraorg_Display with
+   * the Lumiera Interface/Plugin system and creates
+   * a forwarding proxy within the application core to
+   * route calls through this interface.
+   * \par
+   * In addition to the Display interface, this class 
+   * implements an additional service for the GUI, 
+   * allowing actually to set up display slots, which
+   * then can be handed out to client code in the
+   * course of the play process for outputting frames.
+   */
+  class DisplayService
+    : boost::noncopyable
+    {
+      
+      string error_;
+      
+      
+      /* === Interface Lifecycle === */
+      
+      typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_Display, 0)
+                                     , lumiera::Display
+                                     > ServiceInstanceHandle;
+      
+      lib::SingletonRef implInstance_;
+      ServiceInstanceHandle serviceInstance_;
+      
+    public:
+      DisplayService();
+      
+     ~DummyPlayerService() { }  ///TODO
+      
+      
+      
+      /** allocate and lock the given display slot  */
+      Display::Displayer getHandle(LumieraDisplaySlot)   =0;
+      
+    };
+  
+  
+  
+  
+} // namespace gui
+#endif
diff --git a/src/gui/notification-service.cpp b/src/gui/notification-service.cpp
index 4138129ba..080d1461d 100644
--- a/src/gui/notification-service.cpp
+++ b/src/gui/notification-service.cpp
@@ -140,7 +140,7 @@ namespace gui {
     
     
     LUMIERA_INTERFACE_INSTANCE (lumieraorg_GuiNotification, 0
-                               ,lumieraorg_GuiNotificationFacade
+                               ,lumieraorg_GuiNotificationService
                                , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_GuiNotificationFacade_descriptor)
                                , NULL /* on  open  */
                                , NULL /* on  close */
@@ -171,7 +171,7 @@ namespace gui {
   
   NotificationService::NotificationService () 
     : implInstance_(this,_instance),
-      serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_GuiNotification, 0,lumieraorg_GuiNotificationFacade))
+      serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_GuiNotification, 0,lumieraorg_GuiNotificationService))
   {
     INFO (gui, "GuiNotification Facade opened.");
   }
diff --git a/src/include/display-facade.h b/src/include/display-facade.h
index 7375ffce2..2e2261a55 100644
--- a/src/include/display-facade.h
+++ b/src/include/display-facade.h
@@ -98,6 +98,8 @@ namespace lumiera {
   class Display
     {
     public:
+      /** get an implementation instance of this service */
+      static lumiera::facade::Accessor facade;
       
       
       /**
diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp
index 27f78559f..865aa18f4 100644
--- a/src/proc/play/dummy-player-service.cpp
+++ b/src/proc/play/dummy-player-service.cpp
@@ -177,7 +177,7 @@ namespace proc  {
       
       
       LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0
-                                 ,lumieraorg_DummyPlayerFacade
+                                 ,lumieraorg_DummyPlayerService
                                  , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor)
                                  , NULL /* on  open  */
                                  , NULL /* on  close */
@@ -249,7 +249,7 @@ namespace proc  {
       : error_("")
       , notifyTermination_(terminationHandle)
       , implInstance_(this,_instance)
-      , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade))
+      , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerService))
     {
       INFO (progress, "DummyPlayer Facade opened.");
     }

From 3ad22308643e531c46e74211d11510590b1dd468 Mon Sep 17 00:00:00 2001
From: Joel Holdsworth 
Date: Sat, 31 Jan 2009 23:45:32 +0000
Subject: [PATCH 112/216] Added synchronisation between multiple views of the
 track title

---
 src/gui/model/track.cpp                     |  7 +++++++
 src/gui/model/track.hpp                     | 17 ++++++++++++++++-
 src/gui/widgets/timeline/timeline-track.cpp | 12 ++++++++++++
 src/gui/widgets/timeline/timeline-track.hpp |  5 +++++
 4 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp
index 7e9a3992b..d94926229 100644
--- a/src/gui/model/track.cpp
+++ b/src/gui/model/track.cpp
@@ -53,6 +53,7 @@ void
 Track::set_name(const string &name)
 {
   this->name = name;
+  nameChangedSignal.emit(name);
 }
 
 bool
@@ -74,6 +75,12 @@ Track::find_descendant_track_parent(
   return shared_ptr();
 }
 
+sigc::signal
+Track::signal_name_changed() const
+{
+  return nameChangedSignal;
+}
+
 string
 Track::print_branch_recursive(const unsigned int indentation)
 {
diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp
index ac137d451..c59d06875 100644
--- a/src/gui/model/track.hpp
+++ b/src/gui/model/track.hpp
@@ -79,7 +79,17 @@ public:
    **/
   virtual boost::shared_ptr
     find_descendant_track_parent(boost::shared_ptr child);
-  
+
+public:
+
+  /**
+   * A signal which fires when the name changes.
+   * @return Returns the signal. The signal sends the new name for the
+   * track.
+   **/
+  sigc::signal signal_name_changed() const;
+
+public:
   /**
    * A debugging helper function that prints this track, and all it's
    * child tracks in a human-readable form.
@@ -109,6 +119,11 @@ private:
    * The name of this track.
    **/
   std::string name;
+  
+  /**
+   * A signal which fires when the name changes.
+   **/
+  sigc::signal nameChangedSignal;
 
 protected:
   /**
diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp
index 6a8f4f023..1dc00cc8f 100644
--- a/src/gui/widgets/timeline/timeline-track.cpp
+++ b/src/gui/widgets/timeline/timeline-track.cpp
@@ -89,6 +89,11 @@ Track::Track(TimelineWidget &timeline_widget,
     mem_fun(timelineWidget, &TimelineWidget::on_add_track_command) ) );
   context_list.push_back( Menu_Helpers::MenuElem(_("_Remove Track"),
     mem_fun(this, &Track::on_remove_track) ) );
+    
+  // Connect to the model
+  model_track->signal_name_changed().connect(sigc::mem_fun(this,
+    &Track::on_name_changed));
+    
 }
 
 Gtk::Widget&
@@ -247,6 +252,13 @@ Track::on_set_name()
     }
 }
 
+void
+Track::on_name_changed(std::string new_name)
+{
+  if(new_name != titleMenuButton.get_label())
+    update_name();
+}
+
 void
 Track::on_remove_track()
 {
diff --git a/src/gui/widgets/timeline/timeline-track.hpp b/src/gui/widgets/timeline/timeline-track.hpp
index 3c7e4ee6b..97a3dcf1c 100644
--- a/src/gui/widgets/timeline/timeline-track.hpp
+++ b/src/gui/widgets/timeline/timeline-track.hpp
@@ -135,6 +135,11 @@ private:
 
   //----- Event Handlers -----//
   void on_set_name();
+  
+  /**
+   * Event handler for when the track name changes
+   **/
+  void on_name_changed(std::string new_name);
 
   void on_remove_track();
   

From 5ebd0dcf5a968354ccf7776f60e804398f986938 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sun, 1 Feb 2009 01:01:44 +0100
Subject: [PATCH 113/216] WIP fix namespace

---
 src/backend/thread-wrapper.hpp         |  4 ++--
 src/gui/guistart.cpp                   |  2 +-
 tests/lib/subsystem-runner-test.cpp    |  2 +-
 tests/lib/thread-wrapper-join-test.cpp | 10 +++++-----
 tests/lib/thread-wrapper-test.cpp      |  8 ++++----
 5 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp
index 75aec7f61..635602a97 100644
--- a/src/backend/thread-wrapper.hpp
+++ b/src/backend/thread-wrapper.hpp
@@ -36,7 +36,7 @@ extern "C" {
 #include 
 
 
-namespace lib {
+namespace backend {
   
   using std::tr1::bind;
   using std::tr1::function;
@@ -226,5 +226,5 @@ namespace lib {
   
   
   
- } // namespace lib
+ } // namespace backend
 #endif
diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp
index d220d8264..bb6793ecc 100644
--- a/src/gui/guistart.cpp
+++ b/src/gui/guistart.cpp
@@ -67,7 +67,7 @@ extern "C" {
 
 
 using std::string;
-using lib::Thread;
+using backend::Thread;
 using std::tr1::bind;
 using lumiera::Subsys;
 using lumiera::error::LUMIERA_ERROR_STATE;
diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp
index 99d1fd11f..648b32d0c 100644
--- a/tests/lib/subsystem-runner-test.cpp
+++ b/tests/lib/subsystem-runner-test.cpp
@@ -43,7 +43,7 @@ using util::cStr;
 using test::Test;
 using lib::Sync;
 using lib::RecursiveLock_Waitable;
-using lib::Thread;
+using backend::Thread;
 
 
 namespace lumiera {
diff --git a/tests/lib/thread-wrapper-join-test.cpp b/tests/lib/thread-wrapper-join-test.cpp
index 5c87e3a65..9ced9c4b3 100644
--- a/tests/lib/thread-wrapper-join-test.cpp
+++ b/tests/lib/thread-wrapper-join-test.cpp
@@ -35,15 +35,15 @@ using test::Test;
 
 
 
-namespace lib {
-  namespace test {
+namespace backend {
+  namespace test  {
   
     /**************************************************************************
      * @test use the Lumiera backend to create some new threads, additionally
      *       passing an condition variable for waiting on thread termination. 
      *       Actually this is implemented as creating and passing a JoinHandle.
      * 
-     * @see lib::Thread
+     * @see backend::Thread
      * @see threads.h
      */
     class ThreadWrapperJoin_test : public Test
@@ -62,7 +62,7 @@ namespace lib {
         void
         theAction (int secretValue)   ///< to be run in a new thread...
           {
-            usleep (100000);           // pause 100ms prior to modifying
+            usleep (100000);          // pause 100ms prior to modifying
             aValue_ =  secretValue+42;
           }
         
@@ -138,4 +138,4 @@ namespace lib {
     
   } // namespace test
 
-} // namespace lib
+} // namespace backend
diff --git a/tests/lib/thread-wrapper-test.cpp b/tests/lib/thread-wrapper-test.cpp
index 4d08150ed..9c66b4145 100644
--- a/tests/lib/thread-wrapper-test.cpp
+++ b/tests/lib/thread-wrapper-test.cpp
@@ -34,8 +34,8 @@ using test::Test;
 
 
 
-namespace lib {
-  namespace test {
+namespace backend {
+  namespace test  {
   
     namespace { // private test classes and data...
       
@@ -86,7 +86,7 @@ namespace lib {
      *       lumiera::Thread wrapper for binding to an arbitrary operation
      *       and passing the appropriate context.
      * 
-     * @see lib::Thread
+     * @see backend::Thread
      * @see threads.h
      */
     class ThreadWrapper_test : public Test
@@ -116,4 +116,4 @@ namespace lib {
     
   } // namespace test
 
-} // namespace lib
+} // namespace backend

From 17c1942c68074507f5d82fa0d78a89d9f73f3534 Mon Sep 17 00:00:00 2001
From: Joel Holdsworth 
Date: Sun, 1 Feb 2009 00:05:15 +0000
Subject: [PATCH 114/216] Removed some redundant name setting code

---
 src/gui/widgets/timeline/timeline-track.cpp | 10 +++-------
 src/gui/widgets/timeline/timeline-track.hpp |  2 +-
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp
index 1dc00cc8f..4dd938184 100644
--- a/src/gui/widgets/timeline/timeline-track.cpp
+++ b/src/gui/widgets/timeline/timeline-track.cpp
@@ -246,17 +246,13 @@ Track::on_set_name()
     _("Set Track Name"), model_track->get_name());
     
   if(dialog.run() == RESPONSE_OK)
-    {
-      model_track->set_name(dialog.get_name());
-      update_name();
-    }
+    model_track->set_name(dialog.get_name());
 }
 
 void
-Track::on_name_changed(std::string new_name)
+Track::on_name_changed(std::string)
 {
-  if(new_name != titleMenuButton.get_label())
-    update_name();
+  update_name();
 }
 
 void
diff --git a/src/gui/widgets/timeline/timeline-track.hpp b/src/gui/widgets/timeline/timeline-track.hpp
index 97a3dcf1c..43f9db39f 100644
--- a/src/gui/widgets/timeline/timeline-track.hpp
+++ b/src/gui/widgets/timeline/timeline-track.hpp
@@ -139,7 +139,7 @@ private:
   /**
    * Event handler for when the track name changes
    **/
-  void on_name_changed(std::string new_name);
+  void on_name_changed(std::string);
 
   void on_remove_track();
   

From e23417cfc082728df4edc53ce59bbbee0b2a5a71 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sun, 1 Feb 2009 01:24:33 +0100
Subject: [PATCH 115/216] WIP quick'n dirty Tick service implementation

---
 src/proc/play/dummy-player-service.cpp |  11 ++-
 src/proc/play/dummy-player-service.hpp |   2 +
 src/proc/play/tick-service.hpp         | 115 +++++++++++++++++++++++++
 3 files changed, 127 insertions(+), 1 deletion(-)
 create mode 100644 src/proc/play/tick-service.hpp

diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp
index 865aa18f4..3fea947e3 100644
--- a/src/proc/play/dummy-player-service.cpp
+++ b/src/proc/play/dummy-player-service.cpp
@@ -23,6 +23,7 @@
 
 #include "proc/play/dummy-player-service.hpp"
 #include "proc/play/dummy-image-generator.hpp"
+#include "proc/play/tick-service.hpp"
 #include "lib/singleton.hpp"
 
 extern "C" {
@@ -31,9 +32,11 @@ extern "C" {
 
 #include 
 #include 
+#include 
 #include 
 
 
+
 namespace proc  {
   namespace play{
   
@@ -41,6 +44,7 @@ namespace proc  {
     using lumiera::Subsys;
     using std::auto_ptr;
     using boost::scoped_ptr;
+    using std::tr1::bind;
     
     
     namespace { // hidden local details of the service implementation....
@@ -292,7 +296,7 @@ namespace proc  {
     
     
     ProcessImpl::ProcessImpl()
-      : fps_(0), play_(false), imageGen_(0)
+      : fps_(0), play_(false), imageGen_(0), tick_(new TickService (bind (ProcessImpl::doFrame, this)))
       { }
     
     
@@ -319,12 +323,16 @@ namespace proc  {
       {
         REQUIRE (fps==0 || fps_==0 );
         REQUIRE (fps==0 || !play_  );
+        REQUIRE (tick_)
         
         fps_ = fps;
         play_ = (fps != 0);
         
         if (play_)
           imageGen_.reset(new DummyImageGenerator(fps));
+        
+        // callbacks with given frequency, starting now
+        tick_->activate(fps); 
       }
     
     
@@ -333,6 +341,7 @@ namespace proc  {
     ProcessImpl::doPlay(bool yes)
       {
         REQUIRE (isActive());
+        tick_->activate (yes? fps_:0);
         play_ = yes;
       }
     
diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp
index 92c4d27ca..a1856c745 100644
--- a/src/proc/play/dummy-player-service.hpp
+++ b/src/proc/play/dummy-player-service.hpp
@@ -56,6 +56,7 @@ namespace proc {
     
     
     class DummyImageGenerator;
+    class TickService;
     
     
     /********************************************************************
@@ -74,6 +75,7 @@ namespace proc {
         bool play_;
         
         boost::scoped_ptr imageGen_;
+        boost::scoped_ptr         tick_;
         
         
       public:
diff --git a/src/proc/play/tick-service.hpp b/src/proc/play/tick-service.hpp
new file mode 100644
index 000000000..84c85af7c
--- /dev/null
+++ b/src/proc/play/tick-service.hpp
@@ -0,0 +1,115 @@
+/*
+  TICK-SERVICE.hpp  -  issuing timed callbacks
+ 
+  Copyright (C)         Lumiera.org
+    2009,               Joel Holdsworth ,
+                        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 tick-service.hpp
+ ** A timer service invoking a given callback periodically.
+ ** This is a rough preliminary implementation as of 1/2009. We use it to
+ ** drive the frame "creation" of a player dummy (the render engine is not 
+ ** ready yet). The intention is to make this a real service later on, which
+ ** might consolidate and sync various ongoing output processes to a common
+ ** beat, which it implements by precision posix timers. Probably then this
+ ** service will become part of the backend, or rely on a timing service.
+ ** 
+ ** @see proc::play::DummyPlayerService
+ **  
+ */
+
+
+#ifndef PROC_PLAY_TICKSERVICE_H
+#define PROC_PLAY_TICKSERVICE_H
+
+
+#include "backend/thread-wrapper.hpp"
+
+#include 
+
+
+namespace proc {
+  namespace play {
+    
+    
+    /************************************************************
+     * Tick generating service for a periodic callback,
+     * with adjustable frequency. Quick'n dirty implementation!
+     */
+    class TickService
+      : backend::Thread
+      {
+        typedef function Tick;
+        volatile uint timespan_;
+        
+        /** poll interval for new settings in wait state */
+        static const uint POLL_TIMEOUT = 1000;
+        
+      public:
+        TickService (Tick& callback)
+          : Thread("Tick generator (dummy)",
+                   bind (&TickService::timerLoop, this, callback))
+          { }
+        
+       ~TickService ()
+          {
+            uint curr_tick = timespan_;
+            timespan_ = 0;
+            usleep (curr_tick); ////TODO actually should wait for timer thread termination
+          }
+        
+        
+        /** set the periodic timer to run with a given frequency,
+         *  starting \em now. Well, not actually now, but at the next
+         *  opportunity. It should be \em now, but this implementation
+         *  is sloppy! setting fps==0 halts (pauses) the timer.
+         */
+        void activate (uint fps)
+          {
+            REQUIRE (  0==fps 
+                    ||    1000000/fps < std::numeric_limits::max() 
+                       && 1000000/fps > POLL_TIMEOUT);
+            if (fps)
+              timespan_ = 1000000/fps; // microseconds per tick
+            else
+              timespan_ = POLL_TIMEOUT;
+          }
+        
+        
+      private:
+        void timerLoop(Tick periodicFun)
+          {
+            timespan_ = POLL_TIMEOUT;
+            while (0 < timespan_)
+              {
+                if (timespan_ > POLL_TIMEOUT)
+                  periodicFun();
+                
+                usleep (timespan_);
+          }   }
+      };
+    
+    
+    
+    
+  } // namespace play
+
+} // namespace proc
+#endif // PROC_PLAY_TICKSERVICE_H
+

From c2bcb9f1991657926a99cd788e0215f663b87af3 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sun, 1 Feb 2009 01:39:52 +0100
Subject: [PATCH 116/216] WIP remove all locking and thread handling from
 PlaybackController.

Yay! as expected, just by refactoring orthogonally, the controller
gets much simpler, without adding much complexities to ProcessImpl
---
 src/gui/controller/playback-controller.cpp | 74 +++-------------------
 src/gui/controller/playback-controller.hpp | 21 +-----
 2 files changed, 11 insertions(+), 84 deletions(-)

diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp
index 0ec7c6fe6..27832ec32 100644
--- a/src/gui/controller/playback-controller.cpp
+++ b/src/gui/controller/playback-controller.cpp
@@ -28,34 +28,22 @@ namespace gui {
 namespace controller { 
 
 PlaybackController::PlaybackController() :
-  thread(0),
-  finish_playback_thread(false),
   playing(false)
 { }
 
 
-PlaybackController::~PlaybackController()
-{
-  end_playback_thread();
-}
-
 void
 PlaybackController::play()
 {
-  if (playing && thread && playHandle)
+  if (playHandle)
     {
       playHandle.play(true);
-      return;
+      playing = true;
     }
-  if (thread)
-    end_playback_thread();
-  
-  {
-    Lock sync(this);
+  else
     try
       {
         playHandle =  proc::play::DummyPlayer::facade().start();
-        start_playback_thread();
         playing = true;
       }
     catch (lumiera::error::State& err)
@@ -64,59 +52,31 @@ PlaybackController::play()
         lumiera_error();
         playing = false;
       }
-  }
 }
 
 void
 PlaybackController::pause()
 {
-  Lock sync(this);
-  playing = false;
   if (playHandle)
     playHandle.play(false);
+  playing = false;
 }
 
 void
 PlaybackController::stop()
 {
-  {
-    Lock sync(this);
-    playing = false;
-    playHandle.close();
-    // TODO: stop player somehow?
-  }
-  end_playback_thread();
+  playHandle.close();
+  playing = false;
 }
 
 bool
 PlaybackController::is_playing()
 {
-  Lock sync(this);
   return playing;
 }
 
-void
-PlaybackController::start_playback_thread()
-{
-  dispatcher.connect(sigc::mem_fun(this, &PlaybackController::on_frame));
-  finish_playback_thread = false;
-  thread = Glib::Thread::create (sigc::mem_fun(
-    this, &PlaybackController::playback_thread), true);
-}
+//dispatcher.connect(sigc::mem_fun(this, &PlaybackController::on_frame));
 
-void
-PlaybackController::end_playback_thread()
-{
-  {
-    Lock sync(this);
-    finish_playback_thread = true;
-    playing = false;
-  }
-  if (thread)
-    thread->join();
-  thread = 0;
-  finish_playback_thread = false;
-}
 
 void
 PlaybackController::attach_viewer(
@@ -125,25 +85,8 @@ PlaybackController::attach_viewer(
   frame_signal.connect(on_frame);
 }
 
-void
-PlaybackController::playback_thread()
-{  
-  for(;;)
-    {
-      {
-        Lock sync(this);
-        if(finish_playback_thread)
-          return;
-      }
-      
-      if(is_playing())
-        pull_frame();
-      
-      usleep(40000); // ca 25 frames pre second
-    }
-}
-
 
+/*
 void
 PlaybackController::pull_frame()
 {
@@ -162,6 +105,7 @@ PlaybackController::pull_frame()
       TRACE (render, "frame dropped?");
     }
 }
+*/
 
 
 void
diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp
index b05ae0c6f..abe1340c5 100644
--- a/src/gui/controller/playback-controller.hpp
+++ b/src/gui/controller/playback-controller.hpp
@@ -27,7 +27,6 @@
 #define PLAYBACK_CONTROLLER_HPP
 
 #include "include/dummy-player-facade.h"
-#include "lib/sync.hpp"
 
 #include 
 #include 
@@ -36,19 +35,14 @@
 namespace gui {
 namespace controller {
 
-using lib::Sync;
-using lib::RecursiveLock_NoWait;
 
 
 class PlaybackController
   : boost::noncopyable,
-    public Sync
 {
 public:
 
   PlaybackController();
-  
-  ~PlaybackController();
 
   void play();
   
@@ -61,27 +55,16 @@ public:
   void attach_viewer(const sigc::slot& on_frame);
   
 private:
-
-  void start_playback_thread();
-
-  void end_playback_thread();
-  
-  void playback_thread();
-
-  void pull_frame();
   
   void on_frame();
   
+  
 private:
 
-  Glib::Thread *thread;
+  volatile bool playing;
   
   Glib::Dispatcher dispatcher;
   
-  volatile bool finish_playback_thread;
-  
-  volatile bool playing;
-  
   proc::play::DummyPlayer::Process playHandle;
   
   unsigned char * currentBuffer;

From c9f9c3d0d38b489f3fe74be2a93092c9565a5c21 Mon Sep 17 00:00:00 2001
From: Ichthyostega 
Date: Sun, 1 Feb 2009 17:26:25 +0100
Subject: [PATCH 117/216] Document what happens when running the DummyPlayer

---
 doc/devel/draw/PlayerArch-1.svg | 11 +++++++----
 wiki/renderengine.html          | 15 +++++++++++++--
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/doc/devel/draw/PlayerArch-1.svg b/doc/devel/draw/PlayerArch-1.svg
index 0342c6914..a3799f876 100644
--- a/doc/devel/draw/PlayerArch-1.svg
+++ b/doc/devel/draw/PlayerArch-1.svg
@@ -16,7 +16,10 @@
    sodipodi:docbase="/home/hiv/devel/lumi/doc/devel/draw"
    sodipodi:docname="PlayerArch-1.svg"
    inkscape:output_extension="org.inkscape.output.svg.inkscape"
-   version="1.0">
+   version="1.0"
+   inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
   display(Frame&)
+       style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ff5555;font-family:Bitstream Vera Sans">doFrame()
   
 
-
+
Joelholdsworth and Ichthyo created this player mockup in 1/2009 to find out about the implementation details regarding integration and colaboration between the layers. There is no working render engine yet, thus we use a ~DummyImageGenerator for creating faked yuv frames to display. Within the GUI, there is a ~PlaybackController hooked up with the transport controls on the timeline pane.
 # first everything was contained within ~PlaybackController, which spawns a thread for periodically creating those dummy frames
 # then, a ~PlayerService was factored out, now implemented within Proc-Layer (probably to be relocated into the backend for the final version). A new LayerSeparationInterface called ''~DummyPlayer'' was created and set up as a [[Subsystem]] within main().
 # the next step was to support multiple playback processes going on in parallel. Now, the ~PlaybackController holds an smart-handle to the ~PlayProcess currently generating output for this viewer, and invokes the transport control functions and the pull frame call on this handle.
 # then, also the tick generation (and thus the handling of the thread which pulls the frames) was factored out and pushed down into the mentioned ~PlayProcess. For this to work, the ~PlaybackController now makes a display slot available on the public GUI DisplayFacade interface.
-
 [img[Overview to the dummy player operation|draw/PlayerArch1.png]]
+
+!when playing...
+As a prerequisite, a viewer has to be prepared within the GUI. A XV video display widget is wired up to a sigc++ signal slot, using the Glib::Dispatcher to forward calls from the play process thread to the GTK main event loop thread. When doing so, additionally a Displayer slot is created with the DisplayService.
+
+When starting playback, the slot handle created by these preparations is used to create a ~PlayProcess on the ~DummyPlayer interface. Actually
+* a ~PlayProcessImpl object is created down within the player implementation
+* this uses the slot handle to actually allocate the display slot via the Display facade
+* moreover, it aquires an TickService instance, which is still trotteling (not calling the periodic callback)
+* on the "upper" side of the ~DummyPlayer facade, an lib::Handle object is created to track and manage this ~PlayProcesImpl instance
+The handle is returned to the ~PlaybackController within the GUI, which uses this handle for all further interactions with the Player. The handle is ref counting and has value semantics, so it can be stored away, passed as parameter and so on. All such handles corresponding to one ~PlayProcess form a family; when the last goes out of scope, the ~PlayProcess terminates and deallocates any resources. Conceptually, this corresponds to pushing the "stop" button. Handles can be deliberately disconnected by calling {{{handle.close()}}} &mdash; this has the same effect as deleting a handle (when all are closed or deleted the process ends).
+
+All the other play control operations are simply forwarded via the handle and the ~PlayProcessImpl. For example, "pause" corresponds to setting the tick frequency to 0 (thus temporarily discontinuing the tick callbacks). When allocating the display slot in the course of creating the ~PlayProcessImpl, the latter only accesses the Display facade. It can't access the display or viewer directly, because the GUI lives within an plugin; lower layers can't call directly into GUI functions. Thus, within the Display facade a functor (proxy) is created to represent the output sink. This (proxy) Displayer can be used within the implementation of the perodic callback function. As usual, the implementation of the (proxy) Displayer can be inlined and doesn't create an indirection at runtime. Thus, each frame output call has to pass though two indirections: the function pointer in the Display facade interface, and the Glib::Dispatcher.
 
From dc99cc58416544d2b537502e89881ff4a9b2dc71 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sun, 1 Feb 2009 17:06:27 +0000 Subject: [PATCH 118/216] Fixed a typo in a comment --- src/gui/workspace/actions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/workspace/actions.cpp b/src/gui/workspace/actions.cpp index e2679b7f1..f1337fc94 100644 --- a/src/gui/workspace/actions.cpp +++ b/src/gui/workspace/actions.cpp @@ -213,7 +213,7 @@ Actions::on_menu_track_add() g_message("Hello"); } -/* ===== View Menu Event Handlers ===== */ +/* ===== Help Menu Event Handlers ===== */ void Actions::on_menu_help_about() From 0edd7ceda3f51c59627b24a9d71e13cd0059c664 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Sun, 1 Feb 2009 17:12:44 +0000 Subject: [PATCH 119/216] Moved the New Window command into the new Window menu --- src/gui/workspace/actions.cpp | 26 +++++++++++++++----------- src/gui/workspace/actions.hpp | 3 ++- src/gui/workspace/workspace-window.cpp | 5 +++-- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/gui/workspace/actions.cpp b/src/gui/workspace/actions.cpp index f1337fc94..2b0df60ed 100644 --- a/src/gui/workspace/actions.cpp +++ b/src/gui/workspace/actions.cpp @@ -90,10 +90,6 @@ Actions::Actions(WorkspaceWindow &workspace_window) : sigc::mem_fun(*this, &Actions::on_menu_view_viewer)); actionGroup->add(viewerPanelAction); - actionGroup->add(Action::create("ViewNewWindow", - Gtk::StockID("new_window")), - sigc::mem_fun(*this, &Actions::on_menu_view_new_window)); - // Sequence Menu actionGroup->add(Action::create("SequenceMenu", _("_Sequence"))); actionGroup->add(Action::create("SequenceAdd", _("_Add...")), @@ -104,6 +100,12 @@ Actions::Actions(WorkspaceWindow &workspace_window) : actionGroup->add(Action::create("TrackAdd", _("_Add...")), sigc::mem_fun(*this, &Actions::on_menu_track_add)); + // Window Menu + actionGroup->add(Action::create("WindowMenu", _("_Window"))); + actionGroup->add(Action::create("WindowNewWindow", + Gtk::StockID("new_window")), + sigc::mem_fun(*this, &Actions::on_menu_window_new_window)); + // Help Menu actionGroup->add(Action::create("HelpMenu", _("_Help")) ); actionGroup->add(Action::create("HelpAbout", Stock::ABOUT), @@ -187,13 +189,6 @@ Actions::on_menu_view_viewer() workspaceWindow.viewerPanel->show(viewerPanelAction->get_active()); } -void -Actions::on_menu_view_new_window() -{ - application().get_window_manager().new_window(workspaceWindow.project, - workspaceWindow.controller); -} - /* ===== Sequence Menu Event Handlers ===== */ void @@ -213,6 +208,15 @@ Actions::on_menu_track_add() g_message("Hello"); } +/* ===== Window Menu Event Handlers ===== */ + +void +Actions::on_menu_window_new_window() +{ + application().get_window_manager().new_window(workspaceWindow.project, + workspaceWindow.controller); +} + /* ===== Help Menu Event Handlers ===== */ void diff --git a/src/gui/workspace/actions.hpp b/src/gui/workspace/actions.hpp index eb995fc02..668c71975 100644 --- a/src/gui/workspace/actions.hpp +++ b/src/gui/workspace/actions.hpp @@ -69,12 +69,13 @@ private: void on_menu_view_resources(); void on_menu_view_timeline(); void on_menu_view_viewer(); - void on_menu_view_new_window(); void on_menu_sequence_add(); void on_menu_track_add(); + void on_menu_window_new_window(); + void on_menu_help_about(); // Temporary Junk diff --git a/src/gui/workspace/workspace-window.cpp b/src/gui/workspace/workspace-window.cpp index d79008367..1d872c5c9 100644 --- a/src/gui/workspace/workspace-window.cpp +++ b/src/gui/workspace/workspace-window.cpp @@ -120,8 +120,6 @@ WorkspaceWindow::create_ui() " " " " " " - " " - " " "
" " " " " @@ -129,6 +127,9 @@ WorkspaceWindow::create_ui() " " " " " " + " " + " " + " " " " " " " " From 2cae8d8ccc67a4df2e050ebe6cc911b238c478d2 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 1 Feb 2009 19:56:49 +0100 Subject: [PATCH 120/216] fix to circumvent a problem with Iconinfo::operator bool() not being const seemingly this has been fixed in recent gtkmm, but is still present on lenny (and etch) --- src/gui/window-manager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index 04f9ffdc9..0e6319816 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -236,7 +236,9 @@ WindowManager::add_theme_icon_source(Gtk::IconSet &icon_set, // Try to load the icon RefPtr theme = Gtk::IconTheme::get_default(); REQUIRE(theme); - const IconInfo info = theme->lookup_icon(icon_name, width, + + TODO ("find out how IconInfo could be made const. For example, GTKmm 2.10.10 is missing the const on operator bool() in iconinfo.h"); + IconInfo info = theme->lookup_icon(icon_name, width, (IconLookupFlags)0); if(info) { From ec2f362c3acd6456b330442a19204805d5a80a4d Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 1 Feb 2009 20:43:23 +0100 Subject: [PATCH 121/216] During alpha: build .libs into the LUMIERA_PLUGIN_PATH to ease developent --- SConstruct | 8 ++++---- src/common/Makefile.am | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SConstruct b/SConstruct index 7a1aa2592..3c49573da 100644 --- a/SConstruct +++ b/SConstruct @@ -93,10 +93,10 @@ def setupBasicEnvironment(): 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\\"') - appendCppDefine(env,'PKGDATADIR','LUMIERA_CONFIG_PATH=\\"$PKGLIBDIR\\"' - ,'LUMIERA_CONFIG_PATH=\\"$DESTDIR/share/lumiera\\"') + appendCppDefine(env,'PKGLIBDIR','LUMIERA_PLUGIN_PATH=\\"$PKGLIBDIR/:./.libs\\"' + ,'LUMIERA_PLUGIN_PATH=\\"$DESTDIR/lib/lumiera/:./.libs\\"') + appendCppDefine(env,'PKGDATADIR','LUMIERA_CONFIG_PATH=\\"$PKGLIBDIR/:.\\"' + ,'LUMIERA_CONFIG_PATH=\\"$DESTDIR/share/lumiera/:.\\"') prepareOptionsHelp(opts,env) opts.Save(OPTIONSCACHEFILE, env) diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 661c92f64..451b0a982 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -18,7 +18,7 @@ liblumieracommon_la_srcdir = $(top_srcdir)/src/common lib_LTLIBRARIES += liblumieracommon.la -liblumieracommon_la_CPPFLAGS = $(AM_CPPFLAGS) -DLUMIERA_CONFIG_PATH="\"$(pkgdatadir)/config\"" -DLUMIERA_PLUGIN_PATH="\"$(pkglibdir)/\"" +liblumieracommon_la_CPPFLAGS = $(AM_CPPFLAGS) -DLUMIERA_CONFIG_PATH="\"$(pkgdatadir)/config:.\"" -DLUMIERA_PLUGIN_PATH="\"$(pkglibdir)/:./.libs\"" liblumieracommon_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wextra -Wall -Werror liblumieracommon_la_CXXFLAGS = $(AM_CXXFLAGS) -Wextra -Wall liblumieracommon_la_LIBADD = liblumiera.la From 7de661f4c95f57df5f274562b6c7047ee1898670 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 2 Feb 2009 05:25:49 +0100 Subject: [PATCH 122/216] WIP factor out all signal dispatching from playback-controller into DisplayService and DisplayerSlot DisplayService is intended to implement the Display facade and additionally manage N display output sinks (DisplayerSlot). Now the playback-controller contains just the bare controller logic, all services like tick generation or signal dispatching have been factored out... makes me feel better :-) --- src/gui/controller/playback-controller.cpp | 40 ++++----------- src/gui/controller/playback-controller.hpp | 7 +-- src/gui/display-service.cpp | 18 +++++-- src/gui/display-service.hpp | 59 ++++++++++++++++++---- src/gui/guistart.cpp | 6 +-- src/include/display-facade.h | 12 ++--- src/proc/play/dummy-player-service.cpp | 5 +- 7 files changed, 85 insertions(+), 62 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index 27832ec32..cc7881393 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -20,13 +20,18 @@ * *****************************************************/ + #include "gui/controller/playback-controller.hpp" +#include "gui/display-service.hpp" #include "lib/error.hpp" + #include namespace gui { namespace controller { + + PlaybackController::PlaybackController() : playing(false) { } @@ -75,45 +80,18 @@ PlaybackController::is_playing() return playing; } -//dispatcher.connect(sigc::mem_fun(this, &PlaybackController::on_frame)); void -PlaybackController::attach_viewer( - const sigc::slot& on_frame) +PlaybackController::attach_viewer (FrameDestination const& outputDestination) { - frame_signal.connect(on_frame); -} - - -/* -void -PlaybackController::pull_frame() -{ - REQUIRE (is_playing()); - REQUIRE (playHandle); + /////////////////////TODO: unsolved problem: how to access the display-service from /within/ the GUI?? + DisplayService& displayService = do_something_magic(); - unsigned char * newBuffer = reinterpret_cast (playHandle.getFrame()); - - if (newBuffer != currentBuffer) - { - currentBuffer = newBuffer; - dispatcher.emit(); - } - else - { - TRACE (render, "frame dropped?"); - } + viewerHandle_ = displayService.setUp (outputDestination); } -*/ -void -PlaybackController::on_frame() -{ - frame_signal.emit(currentBuffer); -} - } // namespace controller } // namespace gui diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index abe1340c5..5b3b598ae 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -27,8 +27,8 @@ #define PLAYBACK_CONTROLLER_HPP #include "include/dummy-player-facade.h" +#include "include/display-facade.h" -#include #include #include @@ -63,13 +63,10 @@ private: volatile bool playing; - Glib::Dispatcher dispatcher; - proc::play::DummyPlayer::Process playHandle; - unsigned char * currentBuffer; + LumieraDisplaySlot viewerHandle_; - sigc::signal frame_signal; }; } // namespace controller diff --git a/src/gui/display-service.cpp b/src/gui/display-service.cpp index 68fe45b25..07205fcb7 100644 --- a/src/gui/display-service.cpp +++ b/src/gui/display-service.cpp @@ -234,12 +234,22 @@ namespace gui { - /* === Process Implementation === */ + /* === DisplayerSlot Implementation === */ - ProcessImpl::ProcessImpl() - : fps_(0), play_(false), imageGen_(0) - { } + DisplayerSlot::DisplayerSlot (FrameDestination const& outputDestination) + : currBuffer_(0) + { + hasFrame_.connect (outputDestination); + dispatcher_.connect (sigc::mem_fun (this, &DisplayerSlot::displayCurrentFrame)); + } + + + void + DisplayerSlot::displayCurrentFrame() + { + hasFrame_.emit (currentBuffer_); + } DummyPlayer::Process diff --git a/src/gui/display-service.hpp b/src/gui/display-service.hpp index 4d11768cf..ce2027091 100644 --- a/src/gui/display-service.hpp +++ b/src/gui/display-service.hpp @@ -43,37 +43,60 @@ #include "common/instancehandle.hpp" #include "lib/singleton-ref.hpp" +#include #include #include #include +#include namespace gui { - + using std::string; + using std::vector; + using boost::scoped_ptr; using lumiera::Display; + using Glib::Dispatcher; -// class DummyImageGenerator; + typedef sigc::slot FrameDestination; + typedef sigc::signal FrameSignal; + /******************************************************************** * Actual implementation of a single displayer slot. Internally, - * it is connected* via the Glib::Dispatcher to output frames - * to a viewer widget executing within the GTK event thread. + * it is connected via the Glib::Dispatcher for outputting frames + * to a viewer widget, which executes within the GTK event thread. + * @note must be created from the GTK event thread. */ class DisplayerSlot - : public Display::Displayer, - boost::noncopyable + : boost::noncopyable { + Dispatcher dispatcher_; + FrameSignal hasFrame_; + + LumieraDisplayFrame currBuffer_; + public: - DisplayerSlot() ; + DisplayerSlot (FrameDestination const&) ; /* Implementation-level API to be used by DisplayService */ + /** receive a frame to be displayed */ + inline void put (LumieraDisplayFrame); + + + private: + /** internal: activated via Dispatcher + * and running in GTK main thread */ + void displayCurrentFrame(); + }; + typedef vector > DisplayerTab; + /****************************************************** @@ -95,6 +118,7 @@ namespace gui { { string error_; + DisplayerTab slots_; /* === Interface Lifecycle === */ @@ -106,20 +130,35 @@ namespace gui { lib::SingletonRef implInstance_; ServiceInstanceHandle serviceInstance_; + public: DisplayService(); ~DummyPlayerService() { } ///TODO - - /** allocate and lock the given display slot */ - Display::Displayer getHandle(LumieraDisplaySlot) =0; + LumieraDisplaySlot setUp (FrameDestination const&); }; + void + DisplayerSlot::put(LumieraDisplayFrame newFrame) + { + if (newFrame != currBuffer_) + { + currBuffer_ = newFrame; + dispatcher_.emit(); + } + else + { + TRACE (render, "frame dropped?"); + } + } + + + } // namespace gui #endif diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index bb6793ecc..1aa7d9782 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -48,7 +48,7 @@ #include // need to include this to prevent errors when libintl.h defines textdomain (because gtk-lumiera removes the def when ENABLE_NLS isn't defined) #include "gui/gtk-lumiera.hpp" // need to include this before nobugcfg.h, because types.h from GTK tries to shaddow the ERROR macro from windows, which kills nobug's ERROR macro -// TODO not needed? #include "include/logging.h" + #include "lib/error.hpp" #include "gui/guifacade.hpp" #include "gui/notification-service.hpp" @@ -110,7 +110,7 @@ namespace gui { gui::application().main(argc, argv); // execute the GTK Event Loop if (!lumiera_error_peek()) - return; + return; // all went well, normal shutdown } catch (lumiera::Error& problem) { @@ -149,7 +149,7 @@ namespace gui { if (!lumiera_error_peek()) LUMIERA_ERROR_SET (gui, STATE, "unexpected error when starting the GUI thread"); return false; - } + } // note: lumiera_error state remains set } } // namespace gui diff --git a/src/include/display-facade.h b/src/include/display-facade.h index 2e2261a55..eb7f37f09 100644 --- a/src/include/display-facade.h +++ b/src/include/display-facade.h @@ -47,11 +47,7 @@ struct lumiera_displaySlot_struct typedef struct lumiera_displaySlot_struct LumieraDisplaySlot; ///< value semantics -struct lumiera_displayFrame_struct - { - void* const buff_; - }; -typedef struct lumiera_displayFrame_struct LumieraDisplayFrame; +typedef unsigned char * LumieraDisplayFrame; @@ -105,15 +101,15 @@ namespace lumiera { /** * Functor for pushing frames to the display */ - typedef function Displayer; + typedef function Sink; /** allocate an already existing display/viewer for output * @return a functor representing the frame sink */ - virtual Displayer getHandle(LumieraDisplaySlot) =0; + virtual Sink getHandle(LumieraDisplaySlot) =0; - virtual ~DummyPlayer(); + virtual ~Display(); }; diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 3fea947e3..c4bd9e92b 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -296,7 +296,10 @@ namespace proc { ProcessImpl::ProcessImpl() - : fps_(0), play_(false), imageGen_(0), tick_(new TickService (bind (ProcessImpl::doFrame, this))) + : fps_(0) + , play_(false) + , imageGen_(0) + , tick_(new TickService (bind (ProcessImpl::doFrame, this))) { } From 981ff2153094a8911b23bdbf03a4678bc9b54310 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 3 Feb 2009 22:35:11 +0000 Subject: [PATCH 123/216] Removed lumigui, and fixed broken lumiera build in autotools --- src/gui/Makefile.am | 71 +++++++++------------------------------------ 1 file changed, 13 insertions(+), 58 deletions(-) diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 1cef51ae3..166744b2a 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -17,36 +17,6 @@ lumigui_srcdir = $(top_srcdir)/src/gui -# -# lumigui is the standalone gui mockup, will be removed later -# -bin_PROGRAMS += lumigui - -lumigui_CPPFLAGS = $(AM_CPPFLAGS) \ - -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ - -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ - -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ - $(LUMIERA_GUI_CFLAGS) - -lumigui_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -lumigui_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra - -lumigui_LDADD = \ - liblumieracommon.la \ - liblumierabackend.la \ - liblumieraproc.la \ - liblumiera.la \ - libgui.la \ - $(LUMIERA_GUI_LIBS) \ - $(NOBUGMT_LUMIERA_LIBS) \ - -lboost_program_options-mt \ - -lboost_regex-mt - -lumigui_SOURCES = \ - $(lumigui_srcdir)/gtk-lumiera.cpp \ - $(lumigui_srcdir)/gtk-lumiera.hpp - - # # themes, locales and other supplemental data # @@ -64,7 +34,13 @@ pkglib_LTLIBRARIES += gtk_gui.la gtk_gui_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror gtk_gui_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra -gtk_gui_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUMIERA_GUI_CFLAGS) -DLUMIERA_PLUGIN -I$(top_srcdir)/src/ +gtk_gui_la_CPPFLAGS = $(AM_CPPFLAGS) \ + $(LUMIERA_GUI_CFLAGS) \ + -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ + -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ + -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ + -DLUMIERA_PLUGIN -I$(top_srcdir)/src/ \ + $(LUMIERA_GUI_CFLAGS) gtk_gui_la_LDFLAGS = -module -avoid-version -no-undefined -rpath /dev/null -shrext .lum gtk_gui_la_LIBADD = \ @@ -72,29 +48,13 @@ gtk_gui_la_LIBADD = \ liblumierabackend.la \ liblumieraproc.la \ liblumiera.la \ - libgui.la \ $(LUMIERA_GUI_LIBS) \ $(NOBUGMT_LUMIERA_LIBS) -gtk_gui_la_SOURCES = \ - $(lumigui_srcdir)/guistart.cpp - - -# -# libgui is a convenience library used by lumigui and the gtk_gui module -# -noinst_LTLIBRARIES += libgui.la - -libgui_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror -libgui_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra - -libgui_la_CPPFLAGS = $(AM_CPPFLAGS) \ - -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ - -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ - -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ - $(LUMIERA_GUI_CFLAGS) - -libgui_la_SOURCES = \ +gtk_gui_la_SOURCES = \ + $(lumigui_srcdir)/guistart.cpp \ + $(lumigui_srcdir)/gtk-lumiera.cpp \ + $(lumigui_srcdir)/gtk-lumiera.hpp \ $(lumigui_srcdir)/notification-service.cpp \ $(lumigui_srcdir)/window-manager.cpp \ $(lumigui_srcdir)/window-manager.hpp \ @@ -176,13 +136,8 @@ libgui_la_SOURCES = \ $(lumigui_srcdir)/util/rectangle.cpp \ $(lumigui_srcdir)/util/rectangle.hpp -libgui_la_LIBADD = \ - liblumieracommon.la \ - liblumierabackend.la \ - liblumieraproc.la \ - liblumiera.la \ - $(LUMIERA_GUI_LIBS) \ - $(NOBUGMT_LUMIERA_LIBS) + + From 4683b120c5cb257065213ed7035227d0d3f8dbf8 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 3 Feb 2009 23:33:26 +0000 Subject: [PATCH 124/216] Ion Fixes: Corrected the timeline header dragging cursors --- src/gui/widgets/timeline/timeline-header-container.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index a5880d6e0..9e4a60512 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -414,7 +414,7 @@ TimelineHeaderContainer::begin_drag() // Set the cursor to a hand REQUIRE(gdkWindow); - gdkWindow->set_cursor(Gdk::Cursor(Gdk::HAND1)); + gdkWindow->set_cursor(Gdk::Cursor(Gdk::FLEUR)); } void @@ -431,7 +431,7 @@ TimelineHeaderContainer::end_drag(bool apply) // Reset the arrow as a cursor REQUIRE(gdkWindow); - gdkWindow->set_cursor(Gdk::Cursor(Gdk::ARROW)); + gdkWindow->set_cursor(Gdk::Cursor(Gdk::LEFT_PTR)); } void From 6fb86a2caf941a1bedbc93586d8c0236d5199aab Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 4 Feb 2009 05:23:43 +0100 Subject: [PATCH 125/216] WIP setUp of an output slot, connecting playback_controller --- src/common/interfaceproxy.cpp | 7 +++---- src/gui/controller/playback-controller.cpp | 14 ++++++-------- src/gui/controller/playback-controller.hpp | 2 +- src/gui/display-service.cpp | 10 +++++----- src/gui/display-service.hpp | 15 ++++++++++----- src/gui/panels/viewer-panel.cpp | 7 +++++-- src/include/display-facade.h | 4 ++-- src/include/dummy-player-facade.h | 4 ++-- src/proc/play/dummy-player-service.cpp | 6 +++--- src/proc/play/dummy-player-service.hpp | 2 +- 10 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 8390a6609..f62330d65 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -174,8 +174,7 @@ namespace lumiera { { //----Proxy-Implementation-of-lumiera::Display-------- - void displayInfo (string const& text) { _i_.displayInfo (cStr(text)); } - void triggerGuiShutdown (string const& cause) { _i_.triggerGuiShutdown (cStr(cause)); } + Sink getHandle (LumieraDisplaySlot display) { return Sink (display); } public: @@ -231,9 +230,9 @@ namespace lumiera { * and thus leaves us only with one level of indirection, * irrespective if using the C or C++ interface. */ - Process start() + Process start(LumieraDisplaySlot viewerHandle) { - ProcessImpl* pP = static_cast (_i_.startPlay()); + ProcessImpl* pP = static_cast (_i_.startPlay (viewerHandle)); if (!pP) throw lumiera::error::State("failed to start DummyPlayer", lumiera_error()); diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index cc7881393..88925415c 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -33,7 +33,8 @@ namespace controller { PlaybackController::PlaybackController() : - playing(false) + playing(false), + viewerHandle_(0) { } @@ -45,10 +46,10 @@ PlaybackController::play() playHandle.play(true); playing = true; } - else + else if (viewerHandle_) try { - playHandle = proc::play::DummyPlayer::facade().start(); + playHandle = proc::play::DummyPlayer::facade().start (viewerHandle_); playing = true; } catch (lumiera::error::State& err) @@ -83,12 +84,9 @@ PlaybackController::is_playing() void -PlaybackController::attach_viewer (FrameDestination const& outputDestination) +PlaybackController::use_display (LumieraDisplaySlot display) { - /////////////////////TODO: unsolved problem: how to access the display-service from /within/ the GUI?? - DisplayService& displayService = do_something_magic(); - - viewerHandle_ = displayService.setUp (outputDestination); + viewerHandle_ = display; } diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 5b3b598ae..97a6fca44 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -52,7 +52,7 @@ public: bool is_playing(); - void attach_viewer(const sigc::slot& on_frame); + void use_display (LumieraDisplaySlot display); private: diff --git a/src/gui/display-service.cpp b/src/gui/display-service.cpp index 07205fcb7..9829ea896 100644 --- a/src/gui/display-service.cpp +++ b/src/gui/display-service.cpp @@ -252,12 +252,12 @@ namespace gui { } - DummyPlayer::Process - ProcessImpl::createHandle() + LumieraDisplaySlot + DisplayService::setUp (FrameDestination const& outputDestination) { - DummyPlayer::Process handle; - handle.activate(this, &terminate); - return handle; + ptr_vector& slots (_instance->slots_); + slots.push_back (new DisplayerSlot (outputDestination)); + return &slots.back(); } diff --git a/src/gui/display-service.hpp b/src/gui/display-service.hpp index ce2027091..a13a50bf3 100644 --- a/src/gui/display-service.hpp +++ b/src/gui/display-service.hpp @@ -45,7 +45,8 @@ #include #include -#include +//#include +#include #include #include @@ -54,7 +55,7 @@ namespace gui { using std::string; using std::vector; - using boost::scoped_ptr; + using boost::ptr_vector; using lumiera::Display; using Glib::Dispatcher; @@ -71,7 +72,8 @@ namespace gui { * @note must be created from the GTK event thread. */ class DisplayerSlot - : boost::noncopyable + : public lumiera_displaySlot, + boost::noncopyable { Dispatcher dispatcher_; FrameSignal hasFrame_; @@ -95,7 +97,7 @@ namespace gui { }; - typedef vector > DisplayerTab; + typedef ptr_vector DisplayerTab; @@ -137,7 +139,10 @@ namespace gui { ~DummyPlayerService() { } ///TODO - LumieraDisplaySlot setUp (FrameDestination const&); + /** open a new display, sending frames to the given output destination + * @return handle for this slot, can be used to start a play process. + * NULL handle in case of any error. */ + static LumieraDisplaySlot setUp (FrameDestination const&); }; diff --git a/src/gui/panels/viewer-panel.cpp b/src/gui/panels/viewer-panel.cpp index f012a406e..f14ff2023 100644 --- a/src/gui/panels/viewer-panel.cpp +++ b/src/gui/panels/viewer-panel.cpp @@ -27,6 +27,8 @@ #include "../controller/controller.hpp" #include "../controller/playback-controller.hpp" +#include "gui/display-service.hpp" + using namespace Gtk; using namespace gui::widgets; using namespace gui::controller; @@ -42,8 +44,9 @@ ViewerPanel::ViewerPanel(workspace::WorkspaceWindow &workspace_window) : PlaybackController &playback = workspace_window.get_controller().get_playback_controller(); - - playback.attach_viewer(sigc::mem_fun(this, &ViewerPanel::on_frame)); + + FrameDestination outputDestination (sigc::mem_fun(this, &ViewerPanel::on_frame)); + playback.use_display (DisplayService::setUp (outputDestination)); } void diff --git a/src/include/display-facade.h b/src/include/display-facade.h index eb7f37f09..868e629ea 100644 --- a/src/include/display-facade.h +++ b/src/include/display-facade.h @@ -43,8 +43,8 @@ struct lumiera_displaySlot_struct { unsigned int index_; }; - -typedef struct lumiera_displaySlot_struct LumieraDisplaySlot; ///< value semantics +typedef struct lumiera_displaySlot_struct lumiera_displaySlot; +typedef lumiera_displaySlot* LumieraDisplaySlot; typedef unsigned char * LumieraDisplayFrame; diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h index 8bea6568a..547124468 100644 --- a/src/include/dummy-player-facade.h +++ b/src/include/dummy-player-facade.h @@ -96,7 +96,7 @@ namespace proc { //////////////////TODO: define some dummy negotiation about size and framerate.... - virtual Process start() =0; + virtual Process start(LumieraDisplaySlot viewerHandle) =0; virtual ~DummyPlayer(); }; @@ -116,7 +116,7 @@ extern "C" { #include "common/interface.h" LUMIERA_INTERFACE_DECLARE (lumieraorg_DummyPlayer, 0 - , LUMIERA_INTERFACE_SLOT (LumieraPlayProcess, startPlay, (void) ) + , LUMIERA_INTERFACE_SLOT (LumieraPlayProcess, startPlay, (LumieraDisplaySlot) ) , LUMIERA_INTERFACE_SLOT (void, togglePlay,(LumieraPlayProcess, bool)) , LUMIERA_INTERFACE_SLOT (void, terminate, (LumieraPlayProcess) ) , LUMIERA_INTERFACE_SLOT (void *, getFrame, (LumieraPlayProcess) ) diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index c4bd9e92b..74ead13d2 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -186,7 +186,7 @@ namespace proc { , NULL /* on open */ , NULL /* on close */ , LUMIERA_INTERFACE_INLINE (startPlay, "\143\323\102\155\051\006\235\004\037\310\354\121\176\142\342\210", - LumieraPlayProcess, (void), + LumieraPlayProcess, (LumieraDisplaySlot viewerHandle), { if (!_instance) { @@ -194,7 +194,7 @@ namespace proc { return 0; } - return static_cast (_instance->start()); + return static_cast (_instance->start(viewerHandle)); } ) , LUMIERA_INTERFACE_INLINE (togglePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307", @@ -272,7 +272,7 @@ namespace proc { * manages the lifecycle automatically. */ ProcessImpl* - DummyPlayerService::start() + DummyPlayerService::start (LumieraDisplaySlot viewerHandle) { auto_ptr newProcess (new ProcessImpl); diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index a1856c745..0cf035cb9 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -135,7 +135,7 @@ namespace proc { * of the DummyPlayer#start() function. But because * this function sits \em behind the interface, it * just returns an impl pointer. */ - ProcessImpl* start(); + ProcessImpl* start (LumieraDisplaySlot viewerHandle); }; From 2d8a1d7d5936025220c99e6653c9ea0d50409f40 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 4 Feb 2009 17:06:07 +0000 Subject: [PATCH 126/216] Retired lumigui from scons and removed GUI main --- SConstruct | 25 +++++++++++-------------- src/gui/gtk-lumiera.cpp | 11 ----------- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/SConstruct b/SConstruct index 3c49573da..c8f1d03d0 100644 --- a/SConstruct +++ b/SConstruct @@ -342,13 +342,6 @@ def defineBuildTargets(env, artifacts): envPlu.Append(CPPDEFINES='LUMIERA_PLUGIN') artifacts['plugins'] = [] # currently none - - # the Lumiera GTK GUI - envGtk = env.Clone() - envGtk.mergeConf(['gtkmm-2.4','cairomm-1.0','gdl-1.0','librsvg-2.0','xv','xext','sm']) - envGtk.Append(CPPDEFINES='LUMIERA_PLUGIN', LIBS=core) - objgui = srcSubtree(envGtk,'$SRCDIR/gui') - # render and install Icons vector_icon_dir = env.subst('$ICONDIR/svg') prerendered_icon_dir = env.subst('$ICONDIR/prerendered') @@ -356,13 +349,17 @@ def defineBuildTargets(env, artifacts): + [env.IconCopy(f) for f in scanSubtree(prerendered_icon_dir, ['*.png'])] ) + # the Lumiera GTK GUI + envGtk = env.Clone() + envGtk.mergeConf(['gtkmm-2.4','cairomm-1.0','gdl-1.0','librsvg-2.0','xv','xext','sm']) + envGtk.Append(CPPDEFINES='LUMIERA_PLUGIN', LIBS=core) + objgui = srcSubtree(envGtk,'$SRCDIR/gui') guimodule = envGtk.LoadableModule('$LIBDIR/gtk_gui', objgui, SHLIBPREFIX='', SHLIBSUFFIX='.lum') - artifacts['lumigui'] = ( guimodule - + envGtk.Program('$BINDIR/lumigui', objgui ) - + env.Install('$BINDIR', env.Glob('$SRCDIR/gui/*.rc')) - + artifacts['icons'] - ) - + artifacts['gui'] = ( guimodule + + env.Install('$BINDIR', env.Glob('$SRCDIR/gui/*.rc')) + + artifacts['icons'] + ) + # call subdir SConscript(s) for independent components SConscript(dirs=[SRCDIR+'/tool'], exports='env envGtk artifacts core') SConscript(dirs=[TESTDIR], exports='env envPlu artifacts core') @@ -377,7 +374,7 @@ def definePostBuildTargets(env, artifacts): il = env.Alias('install-lib', '$DESTDIR/lib') env.Alias('install', [ib, il]) - build = env.Alias('build', artifacts['lumiera']+artifacts['lumigui']+artifacts['plugins']+artifacts['tools']) + build = env.Alias('build', artifacts['lumiera']+artifacts['gui']+artifacts['plugins']+artifacts['tools']) allbu = env.Alias('allbuild', build+artifacts['testsuite']) env.Default('build') # additional files to be cleaned when cleaning 'build' diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index 87e2c34a7..fb804c2d6 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -132,14 +132,3 @@ application() } } // namespace gui - -/** - * Run the Lumiera GTK GUI as standalone application without backend. - */ -int -main (int argc, char *argv[]) -{ - NOBUG_INIT; - gui::application().main(argc, argv); - return 0; -} From a0cb94788079d6a1223f053c7878afd1dc66cae8 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 4 Feb 2009 17:14:57 +0000 Subject: [PATCH 127/216] Bugfix: Fixed File>Exit --- src/gui/workspace/actions.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/workspace/actions.cpp b/src/gui/workspace/actions.cpp index 2b0df60ed..b2cf555db 100644 --- a/src/gui/workspace/actions.cpp +++ b/src/gui/workspace/actions.cpp @@ -153,7 +153,9 @@ Actions::on_menu_file_render() void Actions::on_menu_file_quit() { - workspaceWindow.hide(); // Closes the main window to stop the Gtk::Main::run(). + Main *main = Main::instance(); + REQUIRE(main); + main->quit(); } /* ===== Edit Menu Event Handlers ===== */ From 8e5097cbe01ce7ab3219637a2d1f77a09df4e578 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 6 Feb 2009 22:51:39 +0100 Subject: [PATCH 128/216] cleanup, fixes, comments... --- src/backend/thread-wrapper.hpp | 2 ++ src/common/instancehandle.hpp | 2 +- src/common/interfaceproxy.cpp | 23 +++++++++++----------- src/gui/controller/playback-controller.hpp | 2 +- src/include/dummy-player-facade.h | 5 ++--- src/include/guinotification-facade.h | 1 + src/lib/handle.hpp | 8 ++++---- 7 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 635602a97..e7e83ca57 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -41,6 +41,8 @@ namespace backend { using std::tr1::bind; using std::tr1::function; using lumiera::Literal; + using lib::Sync; + using lib::NonrecursiveLock_Waitable; typedef struct nobug_flag* NoBugFlag; diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp index 6de4fbde9..9b9a12bd9 100644 --- a/src/common/instancehandle.hpp +++ b/src/common/instancehandle.hpp @@ -177,7 +177,7 @@ namespace lumiera { : private boost::noncopyable { LumieraInterface desc_; - I* instance_; + I* instance_; facade::Link facadeLink_; typedef InstanceHandle _ThisType; diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index f62330d65..ee6b854d3 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -106,7 +106,8 @@ namespace lumiera { namespace gui { - /** storage for the facade proxy factory used by client code to invoke through the interface */ + /** storage for the facade proxy factory + * used by client code to invoke through the interface */ lumiera::facade::Accessor GuiNotification::facade; } // namespace gui @@ -118,12 +119,12 @@ namespace lumiera { typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 0) , gui::GuiNotification - > Handle_GuiNotification; + > IHandle_GuiNotification; template<> - class Proxy - : public Holder + class Proxy + : public Holder { //----Proxy-Implementation-of-GuiNotification-------- @@ -136,8 +137,8 @@ namespace lumiera { }; - template void openProxy (Handle_GuiNotification const&); - template void closeProxy (void); + template void openProxy (IHandle_GuiNotification const&); + template void closeProxy (void); } // namespace facade @@ -212,12 +213,12 @@ namespace lumiera { typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) , proc::play::DummyPlayer - > Handle_DummyPlayer; + > IHandle_DummyPlayer; template<> - class Proxy - : public Holder + class Proxy + : public Holder { //----Proxy-Implementation-of-DummyPlayer-------- typedef proc::play::DummyPlayer::Process Process; @@ -247,8 +248,8 @@ namespace lumiera { }; - template void openProxy (Handle_DummyPlayer const&); - template void closeProxy (void); + template void openProxy (IHandle_DummyPlayer const&); + template void closeProxy (void); } // namespace facade diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 97a6fca44..bf0eeff94 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -38,7 +38,7 @@ namespace controller { class PlaybackController - : boost::noncopyable, + : boost::noncopyable { public: diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h index 547124468..fcecb234f 100644 --- a/src/include/dummy-player-facade.h +++ b/src/include/dummy-player-facade.h @@ -89,8 +89,6 @@ namespace proc { { public: void play(bool); - void* const getFrame(); - }; @@ -98,6 +96,8 @@ namespace proc { virtual Process start(LumieraDisplaySlot viewerHandle) =0; + + protected: virtual ~DummyPlayer(); }; @@ -119,7 +119,6 @@ LUMIERA_INTERFACE_DECLARE (lumieraorg_DummyPlayer, 0 , LUMIERA_INTERFACE_SLOT (LumieraPlayProcess, startPlay, (LumieraDisplaySlot) ) , LUMIERA_INTERFACE_SLOT (void, togglePlay,(LumieraPlayProcess, bool)) , LUMIERA_INTERFACE_SLOT (void, terminate, (LumieraPlayProcess) ) - , LUMIERA_INTERFACE_SLOT (void *, getFrame, (LumieraPlayProcess) ) ); diff --git a/src/include/guinotification-facade.h b/src/include/guinotification-facade.h index dd07ad68c..c28f47d85 100644 --- a/src/include/guinotification-facade.h +++ b/src/include/guinotification-facade.h @@ -70,6 +70,7 @@ namespace gui { * reason causing this shutdown */ virtual void triggerGuiShutdown (string const& cause) =0; + protected: virtual ~GuiNotification() {} }; diff --git a/src/lib/handle.hpp b/src/lib/handle.hpp index 30bbca52f..3c15296a2 100644 --- a/src/lib/handle.hpp +++ b/src/lib/handle.hpp @@ -82,10 +82,10 @@ namespace lib { : smPtr_() { } - Handle (Handle const& r) : smPtr_(r.smPtr_) { } - template Handle (shared_ptr const& r) : smPtr_(r) { } - template explicit Handle (weak_ptr const& wr) : smPtr_(wr) { } - template explicit Handle (std::auto_ptr & ar) : smPtr_(ar) { } + Handle (Handle const& r) : smPtr_(r.smPtr_) { } + template explicit Handle (shared_ptr const& r) : smPtr_(r) { } + template explicit Handle (weak_ptr const& wr) : smPtr_(wr) { } + template explicit Handle (std::auto_ptr & ar) : smPtr_(ar) { } Handle& operator=(Handle const& r) { smPtr_ = r.smPtr_; return *this; } template Handle& operator=(shared_ptr const& sr) { smPtr_ = sr; return *this; } From e1dd3cac74eecccf639863646012160222539c7a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 6 Feb 2009 22:52:06 +0100 Subject: [PATCH 129/216] WIP allocating and using a display slot (impl of Display facade interface) --- src/common/interfaceproxy.cpp | 28 +++- src/gui/display-service.cpp | 196 ++++++++----------------- src/gui/display-service.hpp | 16 +- src/include/display-facade.h | 40 +++-- src/proc/play/dummy-player-service.cpp | 28 ++-- src/proc/play/dummy-player-service.hpp | 4 +- src/proc/play/tick-service.hpp | 6 +- 7 files changed, 144 insertions(+), 174 deletions(-) diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index ee6b854d3..20ec00218 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -154,9 +154,13 @@ namespace lumiera { namespace lumiera { - /** storage for the facade proxy factory used by client code to invoke through the interface */ + /** storage for the facade proxy factory + * used by client code to invoke through the interface */ lumiera::facade::Accessor Display::facade; + /// emit the vtable here into this translation unit within liblumieracommon.so... + Display::~Display() { } + } // namespace lumiera @@ -166,16 +170,26 @@ namespace lumiera { typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_Display, 0) , lumiera::Display - > Handle_Display; + > IHandle_Display; template<> - class Proxy - : public Holder + class Proxy + : public Holder { //----Proxy-Implementation-of-lumiera::Display-------- - Sink getHandle (LumieraDisplaySlot display) { return Sink (display); } + Display::Sink + getHandle (LumieraDisplaySlot display) + { + _i_.allocate (display); + Sink sinkHandle; + sinkHandle.activate (display, _i_.release); + if (lumiera_error_peek() || !sinkHandle) + throw lumiera::error::State("failed to allocate output DisplayerSlot", + lumiera_error()); + return sinkHandle; + } public: @@ -183,8 +197,8 @@ namespace lumiera { }; - template void openProxy (Handle_Display const&); - template void closeProxy (void); + template void openProxy (IHandle_Display const&); + template void closeProxy (void); } // namespace facade diff --git a/src/gui/display-service.cpp b/src/gui/display-service.cpp index 9829ea896..cf0d76fab 100644 --- a/src/gui/display-service.cpp +++ b/src/gui/display-service.cpp @@ -48,31 +48,31 @@ namespace gui { LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 ,lumieraorg_DisplayFacade_descriptor , NULL, NULL, NULL - , LUMIERA_INTERFACE_INLINE (name, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (name, "\323\343\324\023\064\216\120\201\073\056\366\020\110\263\060\023", const char*, (LumieraInterface ifa), { (void)ifa; return "Display"; } ) - , LUMIERA_INTERFACE_INLINE (brief, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (brief, "\305\026\070\133\033\357\014\202\203\270\174\072\341\256\226\235", const char*, (LumieraInterface ifa), { (void)ifa; return "UI Interface: service for outputting frames to a viewer or display"; } ) - , LUMIERA_INTERFACE_INLINE (homepage, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (homepage, "\170\104\246\175\123\144\332\312\315\263\071\170\164\213\024\275", const char*, (LumieraInterface ifa), { (void)ifa; return "http://www.lumiera.org/develompent.html" ;} ) - , LUMIERA_INTERFACE_INLINE (version, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (version, "\265\343\045\346\110\241\276\111\217\120\155\246\230\341\344\124", const char*, (LumieraInterface ifa), { (void)ifa; return "0.1~pre"; } ) - , LUMIERA_INTERFACE_INLINE (author, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (author, "\302\027\122\045\301\166\046\236\257\253\144\035\105\166\070\103", const char*, (LumieraInterface ifa), { (void)ifa; return "Hermann Vosseler"; } ) - , LUMIERA_INTERFACE_INLINE (email, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (email, "\074\013\020\161\075\135\302\265\260\000\301\147\116\355\035\261", const char*, (LumieraInterface ifa), { (void)ifa; return "Ichthyostega@web.de"; } ) - , LUMIERA_INTERFACE_INLINE (copyright, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (copyright, "\037\232\153\100\114\103\074\342\164\132\370\210\372\164\115\275", const char*, (LumieraInterface ifa), { (void)ifa; @@ -81,7 +81,7 @@ namespace gui { " 2009 Hermann Vosseler "; } ) - , LUMIERA_INTERFACE_INLINE (license, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (license, "\026\243\334\056\125\245\315\311\155\375\262\344\007\076\341\254", const char*, (LumieraInterface ifa), { (void)ifa; @@ -101,11 +101,11 @@ namespace gui { "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"; } ) - , LUMIERA_INTERFACE_INLINE (state, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (state, "\243\302\332\160\060\272\155\334\212\256\303\141\160\063\164\154", int, (LumieraInterface ifa), {(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; } ) - , LUMIERA_INTERFACE_INLINE (versioncmp, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (versioncmp, "\363\125\123\060\231\147\053\017\131\341\105\157\231\273\334\136", int, (const char* a, const char* b), {return 0;} ////////////////////////////////////////////TODO define version ordering ) @@ -120,7 +120,6 @@ namespace gui { InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation... - typedef ProcessImpl* ProcP; ///////////////TODO LUMIERA_INTERFACE_INSTANCE (lumieraorg_Display, 0 @@ -128,20 +127,8 @@ namespace gui { , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DisplayFacade_descriptor) , NULL /* on open */ , NULL /* on close */ - , LUMIERA_INTERFACE_INLINE (startPlay, LUIDGEN, - LumieraPlayProcess, (void), - { - if (!_instance) - { - lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); - return 0; - } - - return static_cast (_instance->start()); - } - ) - , LUMIERA_INTERFACE_INLINE (togglePlay, LUIDGEN, - void, (LumieraPlayProcess handle, bool doPlay), + , LUMIERA_INTERFACE_INLINE (allocate, "\177\221\146\253\255\161\160\137\015\005\263\362\307\022\243\365", + void, (LumieraDisplaySlot slotHandle), { if (!_instance) { @@ -149,14 +136,16 @@ namespace gui { return; } - REQUIRE (handle); - ProcP proc = static_cast (handle); - - proc->doPlay(doPlay); + REQUIRE (slotHandle); + try + { + _instance->allocate (slotHandle,true); + } + catch (lumiera::Error&){ /* error state remains set */ } } ) - , LUMIERA_INTERFACE_INLINE (terminate, LUIDGEN, - void, (LumieraPlayProcess handle), + , LUMIERA_INTERFACE_INLINE (release, "\166\374\106\313\011\142\115\161\111\110\376\016\346\115\240\364", + void, (LumieraDisplaySlot slotHandle), { if (!_instance) { @@ -164,22 +153,19 @@ namespace gui { return; } - REQUIRE (handle); - ProcP proc = static_cast (handle); - - ProcessImpl::terminate (proc); + REQUIRE (slotHandle); + _instance->allocate (slotHandle,false); } ) - , LUMIERA_INTERFACE_INLINE (getFrame, LUIDGEN, - void *, (LumieraPlayProcess handle), + , LUMIERA_INTERFACE_INLINE (put, "\340\062\234\227\152\131\370\272\146\207\224\015\361\070\252\135", + void, (LumieraDisplaySlot slotHandle, LumieraDisplayFrame frame), { //skipping full checks for performance reasons REQUIRE (_instance && !lumiera_error_peek()); - REQUIRE (handle); - ProcP proc = static_cast (handle); - - return const_cast (proc->getFrame()); + REQUIRE (slotHandle); + DisplayerSlot& slot = _instance->resolve (slotHandle); + slot.put (frame); } ) ); @@ -202,33 +188,45 @@ namespace gui { - - /** @par implementation note - * A new process (implementation) is created, configured - * and started here. This may include spawning a thread or - * allocating a timer. The newly created process is self-contained - * and will be just handed out, without caring for its lifecycle. - * If client code accesses this function via the plain C interface, - * the client is responsible for terminating this process, whereas - * when using the C++ interface, you'll get a Handle object which - * manages the lifecycle automatically. - */ - ProcessImpl* - DisplayService::start() - { - auto_ptr newProcess (new ProcessImpl); - - REQUIRE (!newProcess->isActive()); - newProcess->setRate(25); - - return newProcess.release(); - } + LumieraDisplaySlot + DisplayService::setUp (FrameDestination const& outputDestination) + { + DisplayerTab& slots (_instance->slots_); + slots.push_back (new DisplayerSlot (outputDestination)); + return &slots.back(); + } - /* === Forwarding functions on the Process handle === */ - void DummyPlayer::Process::play(bool yes) { impl().doPlay(yes); } - void* const DummyPlayer::Process::getFrame() { return impl().getFrame(); } + void + DisplayService::allocate (LumieraDisplaySlot handle, bool doAllocate) + { + REQUIRE (handle); + if (doAllocate) + { + if (handle->put_) + throw lumiera::error::Logic("slot already allocated for output"); + else + // Mark the handle as "allocated" and ready for output: + // Place the function pointer from the C interface into the handle struct. + // calling it will invoke the implementing instance's "put" function + // (see the LUMIERA_INTERFACE_INLINE above in this file!) + handle->put_ = serviceInstance_.get().put; + } + else + handle->put_ = 0; + } + + + + DisplayerSlot& + DisplayService::resolve (LumieraDisplaySlot handle) + { + REQUIRE (handle); + REQUIRE (handle->put_, "accessing a DisplayerSlot, which hasn't been locked for output"); + + return *static_cast (handle); + } @@ -240,6 +238,7 @@ namespace gui { DisplayerSlot::DisplayerSlot (FrameDestination const& outputDestination) : currBuffer_(0) { + put_ = 0; // mark as not allocated hasFrame_.connect (outputDestination); dispatcher_.connect (sigc::mem_fun (this, &DisplayerSlot::displayCurrentFrame)); } @@ -248,73 +247,8 @@ namespace gui { void DisplayerSlot::displayCurrentFrame() { - hasFrame_.emit (currentBuffer_); + hasFrame_.emit (currBuffer_); } - LumieraDisplaySlot - DisplayService::setUp (FrameDestination const& outputDestination) - { - ptr_vector& slots (_instance->slots_); - slots.push_back (new DisplayerSlot (outputDestination)); - return &slots.back(); - } - - - void - ProcessImpl::terminate (ProcessImpl* process) - { - if (process) - delete process; - } - - - - void - ProcessImpl::setRate (uint fps) - { - REQUIRE (fps==0 || fps_==0 ); - REQUIRE (fps==0 || !play_ ); - - fps_ = fps; - play_ = (fps != 0); - - if (play_) - imageGen_.reset(new DummyImageGenerator(fps)); - } - - - - void - ProcessImpl::doPlay(bool yes) - { - REQUIRE (isActive()); - play_ = yes; - } - - - - void* const - ProcessImpl::getFrame() - { - REQUIRE (isActive()); - ASSERT (imageGen_); - - if (play_) - return imageGen_->next(); - else - return imageGen_->current(); - } - - - - - - - - // emit the vtable here into this translation unit within liblumieraproc.so ... - DummyPlayer::~DummyPlayer() { } - - - } // namespace proc diff --git a/src/gui/display-service.hpp b/src/gui/display-service.hpp index a13a50bf3..0cf37990c 100644 --- a/src/gui/display-service.hpp +++ b/src/gui/display-service.hpp @@ -43,6 +43,7 @@ #include "common/instancehandle.hpp" #include "lib/singleton-ref.hpp" +#include #include #include //#include @@ -135,8 +136,7 @@ namespace gui { public: DisplayService(); - - ~DummyPlayerService() { } ///TODO + ~DisplayService() { } /** open a new display, sending frames to the given output destination @@ -144,6 +144,18 @@ namespace gui { * NULL handle in case of any error. */ static LumieraDisplaySlot setUp (FrameDestination const&); + + /** prepare and the given slot for output + * @param doAllocate allocate when true, else release it + * @throw lumiera::error::Logic when already in use */ + void allocate (LumieraDisplaySlot, bool doAllocate); + + + /** resolve the given display slot handle to yield a ref + * to an actual implementation object. In order to be resolvable, + * the DisplayerSlot needs to be locked (=allocated) for output use. */ + DisplayerSlot& resolve (LumieraDisplaySlot); + }; diff --git a/src/include/display-facade.h b/src/include/display-facade.h index 868e629ea..6cabedce0 100644 --- a/src/include/display-facade.h +++ b/src/include/display-facade.h @@ -39,32 +39,30 @@ +typedef unsigned char * LumieraDisplayFrame; + + struct lumiera_displaySlot_struct { - unsigned int index_; + void (*put_)(lumiera_displaySlot_struct*, LumieraDisplayFrame); }; typedef struct lumiera_displaySlot_struct lumiera_displaySlot; typedef lumiera_displaySlot* LumieraDisplaySlot; -typedef unsigned char * LumieraDisplayFrame; - - #ifdef __cplusplus /* ============== C++ Interface ================= */ #include "include/interfaceproxy.hpp" +#include "lib/handle.hpp" #include -#include namespace lumiera { - using std::tr1::function; - // class ProcessImpl; @@ -83,10 +81,11 @@ namespace lumiera { * have to carry out these steps manually and also have to care * for cleaning up and deallocating the slot). * - * @note This is a first draft version of a rather important - * interface. The current version as of 1/2009 just serves - * a mockup player implementation. You can expect this interface - * to change considerably if we get at devising the real player. + * @note This is a first draft version of a rather important interface. + * The current version as of 1/2009 just serves a mockup player + * implementation. You can expect this interface to change + * considerably if we get at devising the real player. + * * @see dummy-player-facade.hpp * @see gui::PlaybackController * @@ -99,9 +98,23 @@ namespace lumiera { /** - * Functor for pushing frames to the display + * Functor for pushing frames to the display. + * While one client is holding such a Sink handle, + * the corresponding DisplayerSlot is locked for + * exclusive use by this client. */ - typedef function Sink; + class Sink + : public lib::Handle + { + + public: + inline void + operator() (LumieraDisplayFrame frame) + { + impl().put_ (&impl(),frame); + } + }; + /** allocate an already existing display/viewer for output @@ -109,6 +122,7 @@ namespace lumiera { virtual Sink getHandle(LumieraDisplaySlot) =0; + protected: virtual ~Display(); }; diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 74ead13d2..9b2d80cf7 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -227,18 +227,6 @@ namespace proc { ProcessImpl::terminate (proc); } ) - , LUMIERA_INTERFACE_INLINE (getFrame, "\230\130\101\300\047\065\170\052\226\164\026\112\150\166\074\134", - void *, (LumieraPlayProcess handle), - { - //skipping full checks for performance reasons - REQUIRE (_instance && !lumiera_error_peek()); - - REQUIRE (handle); - ProcP proc = static_cast (handle); - - return const_cast (proc->getFrame()); - } - ) ); @@ -283,10 +271,9 @@ namespace proc { } - /* === Forwarding functions on the Process handle === */ + /* === Forwarding function(s) on the Process handle === */ void DummyPlayer::Process::play(bool yes) { impl().doPlay(yes); } - void* const DummyPlayer::Process::getFrame() { return impl().getFrame(); } @@ -299,7 +286,7 @@ namespace proc { : fps_(0) , play_(false) , imageGen_(0) - , tick_(new TickService (bind (ProcessImpl::doFrame, this))) + , tick_(new TickService (bind (&ProcessImpl::doFrame, this))) { } @@ -326,7 +313,7 @@ namespace proc { { REQUIRE (fps==0 || fps_==0 ); REQUIRE (fps==0 || !play_ ); - REQUIRE (tick_) + REQUIRE (tick_); fps_ = fps; play_ = (fps != 0); @@ -350,16 +337,19 @@ namespace proc { - void* const - ProcessImpl::getFrame() + void + ProcessImpl::doFrame() { REQUIRE (isActive()); ASSERT (imageGen_); - + + /////////////////////////////////////////TODO rewrite impl; now actively pushing up the frame! +/* if (play_) return imageGen_->next(); else return imageGen_->current(); +*/ } diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index 0cf035cb9..0a7bce34e 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -91,10 +91,12 @@ namespace proc { bool isPlaying() { return play_; } void doPlay(bool yes); - void* const getFrame(); DummyPlayer::Process createHandle(); static void terminate(ProcessImpl* process); + + private: + void doFrame (); ///< periodically invoked while playing }; diff --git a/src/proc/play/tick-service.hpp b/src/proc/play/tick-service.hpp index 84c85af7c..8c7dcaec7 100644 --- a/src/proc/play/tick-service.hpp +++ b/src/proc/play/tick-service.hpp @@ -41,11 +41,15 @@ #include "backend/thread-wrapper.hpp" +#include #include namespace proc { namespace play { + + using std::tr1::function; + /************************************************************ @@ -62,7 +66,7 @@ namespace proc { static const uint POLL_TIMEOUT = 1000; public: - TickService (Tick& callback) + TickService (Tick callback) : Thread("Tick generator (dummy)", bind (&TickService::timerLoop, this, callback)) { } From e435822de63b23324da0c2f2fe4609984a3dcb57 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 8 Feb 2009 01:31:01 +0100 Subject: [PATCH 130/216] Ouch.. boost::ptr_vector depends on boost-serialisation. Write a simple replacement... --- src/lib/scoped-ptrvect.hpp | 162 ++++++++++++++++++++++++++++++ src/lib/scopedholder.hpp | 7 +- tests/40components.tests | 5 + tests/lib/scoped-ptrvect-test.cpp | 109 ++++++++++++++++++++ 4 files changed, 280 insertions(+), 3 deletions(-) create mode 100644 src/lib/scoped-ptrvect.hpp create mode 100644 tests/lib/scoped-ptrvect-test.cpp diff --git a/src/lib/scoped-ptrvect.hpp b/src/lib/scoped-ptrvect.hpp new file mode 100644 index 000000000..af48dac45 --- /dev/null +++ b/src/lib/scoped-ptrvect.hpp @@ -0,0 +1,162 @@ +/* + SCOPED-PTRVECT.hpp - simple noncopyable lifecycle managing collection of pointers + + Copyright (C) Lumiera.org + 2009, 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 scoped-ptrvect.hpp + ** Managing lifecycle for a collection of objects. Sometimes we need to + ** build and own a number of objects, including lifecycle management. + ** For example, a service provider may need to maintain a number of individual + ** process handles. The solution here is deliberately kept simple, it is + ** similar to using a stl container with shared_ptr(s), but behaves rather + ** like boost::scoped_ptr. It provides the same basic functionality as + ** boost::ptr_vector, but doesn't require us to depend on boost-serialisation. + ** + ** Some details to note: + ** - contained objects accessed by reference, never NULL. + ** - TODO: iterators, detaching of objects... + ** - TODO: retro-fit with refarray interface (--> builder branch) + ** + ** @see scoped-ptrvect-test.cpp + ** @see scopedholder.hpp + ** @see gui::DisplayService usage example + */ + + +#ifndef LIB_SCOPED_PTRVECT_H +#define LIB_SCOPED_PTRVECT_H + + +#include "include/logging.h" +#include "lib/error.hpp" +#include "lib/util.hpp" + +#include +#include + + +namespace lib { + + using util::for_each; + + + + /** + * Simple vector based collection of pointers, noncopyable and managing + * lifecycle of the pointed-to objects. Implemented by a vector of + * bare pointers (private inheritance) + */ + template + class ScopedPtrVect + : std::vector, + boost::noncopyable + { + typedef std::vector _Vec; + + public: + typedef size_t size_type; + typedef T & reference; + typedef T const& const_reference; + + + ScopedPtrVect () + : _Vec() + { } + + explicit + ScopedPtrVect (size_type capacity) + : _Vec() + { + _Vec::reserve (capacity); + } + + ~ScopedPtrVect () + { + clear(); + } + + + /** take ownership of the given object, + * adding it at the end of the collection + * @note object is deleted in case of any + * problem while adding it + */ + T& + manage (T* obj) + { + if (obj) + try + { + push_back (obj); + return *obj; + } + catch(...) + { + delete obj; + throw; + } } + + + void + clear() + { + typedef typename _Vec::iterator VIter; + VIter e = this->end(); + for (VIter i = this->begin(); i!=e; ++i) + { + if (*i) + try + { + delete *i; + *i = 0; + } + catch(std::exception& ex) + { + WARN (library, "Problem while deallocating ScopedPtrVect: %s", ex.what()); + } } + _Vec::clear(); + } + + + /* ====== proxied vector functions ==================== */ + + size_type size () const { return _Vec::size(); } + size_type max_size () const { return _Vec::max_size(); } + size_type capacity () const { return _Vec::capacity(); } + bool empty () const { return _Vec::empty(); } + + + private: + /** currently not used as of 2/2009 */ + T* get(size_type i) + { + T* p (_Vec::at (i)); + if (!p) + throw lumiera::error::Invalid("no valid object at this index"); + else + return p; + } + }; + + + + +} // namespace lib +#endif diff --git a/src/lib/scopedholder.hpp b/src/lib/scopedholder.hpp index 6dbb8c37a..042c78844 100644 --- a/src/lib/scopedholder.hpp +++ b/src/lib/scopedholder.hpp @@ -25,9 +25,9 @@ ** 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. + ** including the boost::ptr_container library or lib::ScopedPtrVect, the + ** use of shared_ptr or even a garbage collector. Sometimes circumstances + ** rather call for a very simple or lightweight solution though. ** ** ScopedPtrHolder is a simple extension to boost::scoped_ptr, enabling ** to use it within STL containers if we stick to a specific protocol. @@ -49,6 +49,7 @@ ** @see scopedholdertest.cpp ** @see scopedholdertransfer.hpp use in std::vector ** @see AllocationCluster usage example + ** @see scoped-ptrvect.hpp simple pointer-holding collection */ diff --git a/tests/40components.tests b/tests/40components.tests index ba14f909f..d05bea6f9 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -295,6 +295,11 @@ out: .throw some exceptions... END +TEST "ScopedPtrVect_test" ScopedPtrVect_test < + + 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/test/run.hpp" +#include "lib/util.hpp" + +#include "lib/scoped-ptrvect.hpp" +#include "testdummy.hpp" + +#include +//#include + + +namespace lib { + namespace test { + + using ::Test; + using util::isnil; + +// using std::map; + using std::cout; + + typedef ScopedPtrVect VectD; + + + /******************************************************************** + * @test ScopedPtrVect manages the lifecycle of a number of objects. + */ + class ScopedPtrVect_test : public Test + { + + virtual void + run (Arg) + { + simpleUsage(); +// iterating(); +// detaching(); + } + + + + void + simpleUsage() + { + ASSERT (0==checksum); + { + VectD holder; + ASSERT (isnil (holder)); + ASSERT (0==checksum); + + Dummy* ptr = new Dummy(); + Dummy& ref = holder.manage (ptr); + ASSERT (!isnil (holder)); + ASSERT (0!=checksum); + ASSERT (&ref==ptr); + + holder.manage (new Dummy); + holder.manage (new Dummy); + ASSERT (3 == holder.size()); + + holder.clear(); + ASSERT (0==checksum); + ASSERT (isnil (holder)); + + holder.manage (new Dummy); + holder.manage (new Dummy); + holder.manage (new Dummy); + holder.manage (new Dummy); + holder.manage (new Dummy); + holder.manage (new Dummy); + holder.manage (new Dummy); + holder.manage (new Dummy); + holder.manage (new Dummy); + ASSERT (9 == holder.size()); + ASSERT (0!=checksum); + } + ASSERT (0==checksum); + } + + }; + + LAUNCHER (ScopedPtrVect_test, "unit common"); + + + }// namespace test + +} // namespace lib + From 4524c23832a21ce4b4fe79dcaa6d47fb27ddf016 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 8 Feb 2009 01:35:45 +0100 Subject: [PATCH 131/216] replace ptr_vector by lib:ScopedPtrVect. passes compiler. --- src/gui/display-service.cpp | 3 +-- src/gui/display-service.hpp | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/gui/display-service.cpp b/src/gui/display-service.cpp index cf0d76fab..0db6da3dc 100644 --- a/src/gui/display-service.cpp +++ b/src/gui/display-service.cpp @@ -192,8 +192,7 @@ namespace gui { DisplayService::setUp (FrameDestination const& outputDestination) { DisplayerTab& slots (_instance->slots_); - slots.push_back (new DisplayerSlot (outputDestination)); - return &slots.back(); + return &slots.manage (new DisplayerSlot (outputDestination)); } diff --git a/src/gui/display-service.hpp b/src/gui/display-service.hpp index 0cf37990c..094d2f895 100644 --- a/src/gui/display-service.hpp +++ b/src/gui/display-service.hpp @@ -42,12 +42,11 @@ #include "include/display-facade.h" #include "common/instancehandle.hpp" #include "lib/singleton-ref.hpp" +#include "lib/scoped-ptrvect.hpp" #include #include #include -//#include -#include #include #include @@ -56,7 +55,6 @@ namespace gui { using std::string; using std::vector; - using boost::ptr_vector; using lumiera::Display; using Glib::Dispatcher; @@ -98,7 +96,7 @@ namespace gui { }; - typedef ptr_vector DisplayerTab; + typedef lib::ScopedPtrVect DisplayerTab; From 32c2c85abc8ec8e6d4de21cd9610aa17eb81a0ec Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 8 Feb 2009 02:00:55 +0100 Subject: [PATCH 132/216] add the impl. of the periodic playback function, now pushing output up to GUI --- src/proc/play/dummy-image-generator.cpp | 6 +++--- src/proc/play/dummy-image-generator.hpp | 5 +++-- src/proc/play/dummy-player-service.cpp | 12 +++++------- src/proc/play/dummy-player-service.hpp | 5 ++++- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/proc/play/dummy-image-generator.cpp b/src/proc/play/dummy-image-generator.cpp index 29d58a1ac..603b0d033 100644 --- a/src/proc/play/dummy-image-generator.cpp +++ b/src/proc/play/dummy-image-generator.cpp @@ -89,7 +89,7 @@ namespace proc { { } - void * const + const LumieraDisplayFrame DummyImageGenerator::next() { @@ -137,7 +137,7 @@ namespace proc { } // select output buffer to return - unsigned char * outBuff; + LumieraDisplayFrame outBuff; if (!current_) { @@ -156,7 +156,7 @@ namespace proc { } - void * const + const LumieraDisplayFrame DummyImageGenerator::current() { if (!current_) return outFrame_A_; diff --git a/src/proc/play/dummy-image-generator.hpp b/src/proc/play/dummy-image-generator.hpp index e24a4592e..693a6058e 100644 --- a/src/proc/play/dummy-image-generator.hpp +++ b/src/proc/play/dummy-image-generator.hpp @@ -40,6 +40,7 @@ #include "lib/error.hpp" +#include "include/display-facade.h" namespace proc { @@ -68,11 +69,11 @@ namespace proc { * occupy the alternate buffer. * @return the buffer containing the new frame */ - void * const next(); + const LumieraDisplayFrame next(); /** just re-return a pointer to the current frame * without generating any new image data */ - void * const current(); + const LumieraDisplayFrame current(); private: diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 9b2d80cf7..52b66cf42 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -262,7 +262,7 @@ namespace proc { ProcessImpl* DummyPlayerService::start (LumieraDisplaySlot viewerHandle) { - auto_ptr newProcess (new ProcessImpl); + auto_ptr newProcess (new ProcessImpl (viewerHandle)); REQUIRE (!newProcess->isActive()); newProcess->setRate(25); @@ -282,9 +282,10 @@ namespace proc { /* === Process Implementation === */ - ProcessImpl::ProcessImpl() + ProcessImpl::ProcessImpl(LumieraDisplaySlot viewerHandle) : fps_(0) , play_(false) + , display_(Display::facade().getHandle (viewerHandle)) , imageGen_(0) , tick_(new TickService (bind (&ProcessImpl::doFrame, this))) { } @@ -343,13 +344,10 @@ namespace proc { REQUIRE (isActive()); ASSERT (imageGen_); - /////////////////////////////////////////TODO rewrite impl; now actively pushing up the frame! -/* if (play_) - return imageGen_->next(); + display_(imageGen_->next()); else - return imageGen_->current(); -*/ + display_(imageGen_->current()); } diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index 0a7bce34e..b7d3f5656 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -40,6 +40,7 @@ #include "include/dummy-player-facade.h" +#include "include/display-facade.h" #include "common/instancehandle.hpp" #include "lib/singleton-ref.hpp" @@ -53,6 +54,7 @@ namespace proc { using std::string; using lumiera::Subsys; + using lumiera::Display; class DummyImageGenerator; @@ -74,12 +76,13 @@ namespace proc { uint fps_; bool play_; + Display::Sink display_; boost::scoped_ptr imageGen_; boost::scoped_ptr tick_; public: - ProcessImpl() ; + ProcessImpl(LumieraDisplaySlot) ; /* Implementation-level API to be used By DummyPlayerService */ From 73f29f3a6af56c818674f5ddc0e675cb1c846aa3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 8 Feb 2009 02:02:03 +0100 Subject: [PATCH 133/216] Set up gui::DisplayService as one of the facade interfaces provided by the GUI --- src/gui/guistart.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index 1aa7d9782..e345f9047 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -52,6 +52,7 @@ #include "lib/error.hpp" #include "gui/guifacade.hpp" #include "gui/notification-service.hpp" +#include "gui/display-service.hpp" #include "common/subsys.hpp" #include "backend/thread-wrapper.hpp" #include "lib/singleton.hpp" @@ -87,10 +88,12 @@ namespace gui { string error_; Subsys::SigTerm& reportOnTermination_; NotificationService activateNotificationService_; + DisplayService activateDisplayService_; GuiLifecycle (Subsys::SigTerm& terminationHandler) : reportOnTermination_(terminationHandler) - , activateNotificationService_() // opens the GuiNotification facade interface + , activateNotificationService_() // opens the GuiNotification facade interface + , activateDisplayService_() // opens the gui::Display facade interface { } ~GuiLifecycle () From b0e64682936dfc67e3f2b810f2980ac02fee6f0e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 8 Feb 2009 04:10:37 +0100 Subject: [PATCH 134/216] some testing and debugging --- src/common/guifacade.cpp | 2 +- src/gui/display-service.cpp | 6 ++++++ src/gui/display-service.hpp | 6 +++++- src/lib/handle.hpp | 10 ++++++---- src/proc/play/dummy-image-generator.hpp | 2 +- src/proc/play/dummy-player-service.cpp | 17 ++++++++++++----- src/proc/play/dummy-player-service.hpp | 1 + src/proc/play/tick-service.hpp | 13 ++++++++++--- 8 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index a3081e953..8d6f3fb98 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -152,13 +152,13 @@ namespace gui { ~GuiSubsysDescriptor() { - FIXME ("ichthyo: when you want to ignore errors, then you have to error_get() them to clear the error state"); if (facade) { WARN (guifacade, "GUI subsystem terminates, but GuiFacade isn't properly closed. " "Closing it forcedly; this indicates broken startup logic and should be fixed."); try { facade.reset (0); } catch(...) { WARN_IF (lumiera_error_peek(), guifacade, "Ignoring error: %s", lumiera_error()); } + lumiera_error(); // clear any remaining error state... } } }; diff --git a/src/gui/display-service.cpp b/src/gui/display-service.cpp index 0db6da3dc..45d38c4dd 100644 --- a/src/gui/display-service.cpp +++ b/src/gui/display-service.cpp @@ -243,6 +243,12 @@ namespace gui { } + DisplayerSlot::~DisplayerSlot() + { + TRACE (gui_dbg, "Displayer Slot closing..."); + } + + void DisplayerSlot::displayCurrentFrame() { diff --git a/src/gui/display-service.hpp b/src/gui/display-service.hpp index 094d2f895..3783b8dfc 100644 --- a/src/gui/display-service.hpp +++ b/src/gui/display-service.hpp @@ -82,6 +82,7 @@ namespace gui { public: DisplayerSlot (FrameDestination const&) ; + ~DisplayerSlot () ; /* Implementation-level API to be used by DisplayService */ @@ -134,7 +135,10 @@ namespace gui { public: DisplayService(); - ~DisplayService() { } + ~DisplayService() { + INFO (proc_dbg, "Display service dying..."); + + } /** open a new display, sending frames to the given output destination diff --git a/src/lib/handle.hpp b/src/lib/handle.hpp index 3c15296a2..54bff4c89 100644 --- a/src/lib/handle.hpp +++ b/src/lib/handle.hpp @@ -70,7 +70,9 @@ namespace lib { class Handle { protected: - std::tr1::shared_ptr smPtr_; + typedef std::tr1::shared_ptr SmPtr; + + SmPtr smPtr_; public: @@ -113,11 +115,11 @@ namespace lib { void close () { smPtr_.reset(); } - typedef std::tr1::shared_ptr Handle::*__unspecified_bool_type; + typedef SmPtr Handle::*__unspecified_bool_type; /** implicit conversion to "bool" */ - operator __unspecified_bool_type() const { return &Handle::smPtr_; } // never throws - bool operator! () const { return !bool(smPtr_); } // dito + operator __unspecified_bool_type() const { return smPtr_? &Handle::smPtr_ : 0; } // never throws + bool operator! () const { return !bool(smPtr_); } // ditto diff --git a/src/proc/play/dummy-image-generator.hpp b/src/proc/play/dummy-image-generator.hpp index 693a6058e..17056997d 100644 --- a/src/proc/play/dummy-image-generator.hpp +++ b/src/proc/play/dummy-image-generator.hpp @@ -63,7 +63,7 @@ namespace proc { public: DummyImageGenerator(uint fps); - ~DummyImageGenerator() { } + ~DummyImageGenerator() { } /** generate the next frame and * occupy the alternate buffer. diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 52b66cf42..52125c7bb 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -291,12 +291,9 @@ namespace proc { { } - DummyPlayer::Process - ProcessImpl::createHandle() + ProcessImpl::~ProcessImpl() { - DummyPlayer::Process handle; - handle.activate(this, &terminate); - return handle; + INFO (proc_dbg, "Playback process halted..."); } @@ -309,6 +306,16 @@ namespace proc { + DummyPlayer::Process + ProcessImpl::createHandle() + { + DummyPlayer::Process handle; + handle.activate(this, &terminate); + return handle; + } + + + void ProcessImpl::setRate (uint fps) { diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index b7d3f5656..55c07e430 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -83,6 +83,7 @@ namespace proc { public: ProcessImpl(LumieraDisplaySlot) ; + ~ProcessImpl() ; /* Implementation-level API to be used By DummyPlayerService */ diff --git a/src/proc/play/tick-service.hpp b/src/proc/play/tick-service.hpp index 8c7dcaec7..b27f936a3 100644 --- a/src/proc/play/tick-service.hpp +++ b/src/proc/play/tick-service.hpp @@ -69,13 +69,17 @@ namespace proc { TickService (Tick callback) : Thread("Tick generator (dummy)", bind (&TickService::timerLoop, this, callback)) - { } + { + INFO (proc, "TickService started."); + } ~TickService () { uint curr_tick = timespan_; timespan_ = 0; - usleep (curr_tick); ////TODO actually should wait for timer thread termination + usleep (2*curr_tick); ////TODO actually should wait for timer thread termination + + INFO (proc, "TickService shutdown."); } @@ -106,7 +110,10 @@ namespace proc { periodicFun(); usleep (timespan_); - } } + } + TRACE (proc_dbg, "Tick Thread timer loop exiting..."); + } + }; From da2519ac34e95a27ab4601070868bdeb8403afb3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 8 Feb 2009 20:13:19 +0100 Subject: [PATCH 135/216] fixed linking dependencies --- SConstruct | 4 ++-- src/gui/Makefile.am | 8 +++---- src/tool/Makefile.am | 2 +- src/tool/SConscript | 9 +++++--- tests/Makefile.am | 48 +++++++++++++++++++++++++----------------- tests/tool/Makefile.am | 2 +- 6 files changed, 43 insertions(+), 30 deletions(-) diff --git a/SConstruct b/SConstruct index 03df2a5c9..194c2df7e 100644 --- a/SConstruct +++ b/SConstruct @@ -351,7 +351,7 @@ def defineBuildTargets(env, artifacts): # the Lumiera GTK GUI envGtk = env.Clone() - envGtk.mergeConf(['gtkmm-2.4','cairomm-1.0','gdl-1.0','librsvg-2.0','xv','xext','sm']) + envGtk.mergeConf(['gtkmm-2.4','cairomm-1.0','gdl-1.0','xv','xext','sm']) envGtk.Append(CPPDEFINES='LUMIERA_PLUGIN', LIBS=core) objgui = srcSubtree(envGtk,'$SRCDIR/gui') @@ -362,7 +362,7 @@ def defineBuildTargets(env, artifacts): ) # call subdir SConscript(s) for independent components - SConscript(dirs=[SRCDIR+'/tool'], exports='env envGtk artifacts core') + SConscript(dirs=[SRCDIR+'/tool'], exports='env artifacts core') SConscript(dirs=[TESTDIR], exports='env envPlu artifacts core') diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 166744b2a..427375ad8 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -1,5 +1,5 @@ -# Copyright (C) Lumiera.org -# 2007, Joel Holdsworth +# Copyright (C) Lumiera.org +# 2007, Joel Holdsworth # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as @@ -44,9 +44,9 @@ gtk_gui_la_CPPFLAGS = $(AM_CPPFLAGS) \ gtk_gui_la_LDFLAGS = -module -avoid-version -no-undefined -rpath /dev/null -shrext .lum gtk_gui_la_LIBADD = \ - liblumieracommon.la \ - liblumierabackend.la \ liblumieraproc.la \ + liblumierabackend.la \ + liblumieracommon.la \ liblumiera.la \ $(LUMIERA_GUI_LIBS) \ $(NOBUGMT_LUMIERA_LIBS) diff --git a/src/tool/Makefile.am b/src/tool/Makefile.am index 4f6d14b6e..2bf1acf99 100644 --- a/src/tool/Makefile.am +++ b/src/tool/Makefile.am @@ -20,7 +20,7 @@ lumitool_srcdir = $(top_srcdir)/src/tool noinst_PROGRAMS += luidgen luidgen_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror luidgen_CPPFLAGS = -I$(top_srcdir)/src/ -luidgen_LDADD = liblumiera.la $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -lboost_regex-mt -lboost_program_options-mt -ldl +luidgen_LDADD = liblumiera.la $(NOBUGMT_LUMIERA_LIBS) -lboost_regex-mt -lboost_program_options-mt luidgen_SOURCES = $(lumitool_srcdir)/luidgen.c diff --git a/src/tool/SConscript b/src/tool/SConscript index bea1305ed..ca3f99211 100644 --- a/src/tool/SConscript +++ b/src/tool/SConscript @@ -3,14 +3,17 @@ ## SConscript - SCons buildscript for tool subdirectory (called by SConstruct) ## -Import('env','envGtk','artifacts','core') +Import('env','artifacts','core') support_lib = artifacts['support'] -luidgen = env.Program('#$BINDIR/luidgen', 'luidgen.c', LIBS=support_lib) ## for rendering SVG icons (uses librsvg) +envSvg = env.Clone() +envSvg.mergeConf(['librsvg-2.0']) +envSvg.Append(LIBS=support_lib) -rsvg = envGtk.Program('#$BINDIR/rsvg-convert','rsvg-convert.c') +luidgen = env.Program('#$BINDIR/luidgen', 'luidgen.c', LIBS=support_lib) ## for generating Lumiera-UIDs +rsvg = envSvg.Program('#$BINDIR/rsvg-convert','rsvg-convert.c') ## for rendering SVG icons (uses librsvg) # build additional test and administrative tools.... artifacts['tools'] = [ env.Program('#$BINDIR/hello-world','hello.c') #### hello world (checks C build) diff --git a/tests/Makefile.am b/tests/Makefile.am index 750acb887..acaf205b6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -22,42 +22,52 @@ tests_srcdir = $(top_srcdir)/tests check_PROGRAMS += test-error test_error_SOURCES = $(tests_srcdir)/library/test-error.c test_error_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_error_LDADD = liblumiera.la $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt +test_error_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt 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.la $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt +test_locking_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt 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.la $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt +test_llist_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt 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.la $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt +test_psplay_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt 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.la $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt +test_safeclib_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt 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.la $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt +test_luid_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt 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 = liblumierabackend.la liblumiera.la $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt +test_filedescriptors_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la -ldl liblumiera.la -lboost_program_options-mt -lboost_regex-mt 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 = liblumierabackend.la liblumiera.la $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt +test_filehandles_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la -ldl liblumiera.la -lboost_program_options-mt -lboost_regex-mt + +check_PROGRAMS += test-filemmap +test_filemmap_SOURCES = $(tests_srcdir)/backend/test-filemmap.c +test_filemmap_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_filemmap_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la -ldl liblumiera.la -lboost_program_options-mt -lboost_regex-mt + +check_PROGRAMS += test-resourcecollector +test_resourcecollector_SOURCES = $(tests_srcdir)/library/test-resourcecollector.c +test_resourcecollector_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_resourcecollector_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la -ldl liblumiera.la -lboost_program_options-mt -lboost_regex-mt check_PROGRAMS += test-config @@ -65,6 +75,7 @@ test_config_SOURCES = $(tests_srcdir)/common/test-config.c test_config_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ test_config_LDADD = \ liblumieraproc.la \ + liblumierabackend.la \ liblumieracommon.la \ liblumiera.la \ $(LUMIERA_PLUGIN_LIBS) \ @@ -83,16 +94,15 @@ examplepluginc_la_LDFLAGS = -module -avoid-version -no-undefined -rpath /dev/nul check_PROGRAMS += test-interfaces test_interfaces_SOURCES = $(tests_srcdir)/common/test-interfaces.c test_interfaces_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_interfaces_LDADD = liblumiera.la $(LUMIERA_PLUGIN_LIBS) $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt - -check_PROGRAMS += test-filemmap -test_filemmap_SOURCES = $(tests_srcdir)/backend/test-filemmap.c -test_filemmap_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ -test_filemmap_LDADD = liblumierabackend.la liblumiera.la -lnobugmt -lpthread -ldl -lm liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt - -check_PROGRAMS += test-resourcecollector -test_resourcecollector_SOURCES = $(tests_srcdir)/library/test-resourcecollector.c -test_resourcecollector_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ -test_resourcecollector_LDADD = liblumierabackend.la liblumiera.la -lnobugmt -lpthread -ldl -lm liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt +test_interfaces_LDADD = \ + liblumieraproc.la \ + liblumierabackend.la \ + liblumieracommon.la \ + liblumiera.la \ + $(LUMIERA_PLUGIN_LIBS) \ + $(NOBUGMT_LUMIERA_LIBS) \ + -ldl \ + -lboost_program_options-mt \ + -lboost_regex-mt TESTS = $(tests_srcdir)/test.sh diff --git a/tests/tool/Makefile.am b/tests/tool/Makefile.am index be9f5b5ef..7cd7e7e6b 100644 --- a/tests/tool/Makefile.am +++ b/tests/tool/Makefile.am @@ -19,6 +19,6 @@ lumitesttool_srcdir = $(top_srcdir)/tests/tool noinst_PROGRAMS += vgsuppression vgsuppression_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -vgsuppression_LDADD = liblumiera.la $(NOBUGMT_LUMIERA_LIBS) -ldl liblumieracommon.la liblumieraproc.la -lboost_regex-mt -lboost_program_options-mt -ldl +vgsuppression_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumieraproc.la liblumierabackend.la liblumieracommon.la liblumiera.la -lboost_regex-mt -lboost_program_options-mt -ldl vgsuppression_SOURCES = $(lumitesttool_srcdir)/vgsuppression.c From 268f8cbc4c80ea390782fa5a9a5cd1d3ff52820b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 9 Feb 2009 01:21:01 +0100 Subject: [PATCH 136/216] refactor interfaceproxy.cpp to rather include the definitions this allows to put the proxy definitions alongside with the actually implementing service, which makes much more sense than having all in one huge interfaceproxy.cpp file --- src/common/interfaceproxy.cpp | 173 ++---------------- src/gui/display-interface-proxy.hpp | 94 ++++++++++ src/gui/notification-interface-proxy.hpp | 81 ++++++++ .../play/dummy-player-interface-proxy.hpp | 99 ++++++++++ 4 files changed, 287 insertions(+), 160 deletions(-) create mode 100644 src/gui/display-interface-proxy.hpp create mode 100644 src/gui/notification-interface-proxy.hpp create mode 100644 src/proc/play/dummy-player-interface-proxy.hpp diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 20ec00218..1970cce21 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -100,172 +100,25 @@ namespace lumiera { - /* ==================== GuiNotification =================================== */ + + /* ===================================================================== */ + /* including explicit Proxy-Definitions for all facade interfaces */ + /* ===================================================================== */ + + + + /* ==================== GuiNotification ================================ */ -#include "include/guinotification-facade.h" - -namespace gui { - - /** storage for the facade proxy factory - * used by client code to invoke through the interface */ - lumiera::facade::Accessor GuiNotification::facade; - -} // namespace gui +#include "gui/notification-interface-proxy.hpp" - -namespace lumiera { - namespace facade { + /* ==================== gui::Display =================================== */ - typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 0) - , gui::GuiNotification - > IHandle_GuiNotification; - - - template<> - class Proxy - : public Holder - { - //----Proxy-Implementation-of-GuiNotification-------- - - void displayInfo (string const& text) { _i_.displayInfo (cStr(text)); } - void triggerGuiShutdown (string const& cause) { _i_.triggerGuiShutdown (cStr(cause)); } - - - public: - Proxy (IHandle const& iha) : THolder(iha) {} - }; - - - template void openProxy (IHandle_GuiNotification const&); - template void closeProxy (void); - - } // namespace facade - -} // namespace lumiera +#include "gui/display-interface-proxy.hpp" - - - - /* ==================== gui::Display ====================================== */ + /* ==================== DummyPlayer ==================================== */ -#include "include/display-facade.h" - -namespace lumiera { - - /** storage for the facade proxy factory - * used by client code to invoke through the interface */ - lumiera::facade::Accessor Display::facade; - - /// emit the vtable here into this translation unit within liblumieracommon.so... - Display::~Display() { } - -} // namespace lumiera +#include "proc/play/dummy-player-interface-proxy.hpp" - -namespace lumiera { - namespace facade { - - typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_Display, 0) - , lumiera::Display - > IHandle_Display; - - - template<> - class Proxy - : public Holder - { - //----Proxy-Implementation-of-lumiera::Display-------- - - Display::Sink - getHandle (LumieraDisplaySlot display) - { - _i_.allocate (display); - Sink sinkHandle; - sinkHandle.activate (display, _i_.release); - if (lumiera_error_peek() || !sinkHandle) - throw lumiera::error::State("failed to allocate output DisplayerSlot", - lumiera_error()); - return sinkHandle; - } - - - public: - Proxy (IHandle const& iha) : THolder(iha) {} - }; - - - template void openProxy (IHandle_Display const&); - template void closeProxy (void); - - } // namespace facade - -} // namespace lumiera - - - - - - - /* ==================== DummyPlayer ======================================= */ - -#include "proc/play/dummy-player-service.hpp" - -namespace proc { - namespace play { - - /** storage for the DummyPlayer facade proxy factory... */ - lumiera::facade::Accessor DummyPlayer::facade; - -} } - - -namespace lumiera { - namespace facade { - - typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) - , proc::play::DummyPlayer - > IHandle_DummyPlayer; - - - template<> - class Proxy - : public Holder - { - //----Proxy-Implementation-of-DummyPlayer-------- - typedef proc::play::DummyPlayer::Process Process; - typedef proc::play::ProcessImpl ProcessImpl; - - /** @note as an optimisation we hand out a direct reference - * to the implementing process object. While this ref could - * still be passed as handle to the C Language interface, using - * it directly within the client (=GUI) bypasses the C interface - * and thus leaves us only with one level of indirection, - * irrespective if using the C or C++ interface. - */ - Process start(LumieraDisplaySlot viewerHandle) - { - ProcessImpl* pP = static_cast (_i_.startPlay (viewerHandle)); - - if (!pP) - throw lumiera::error::State("failed to start DummyPlayer", lumiera_error()); - - return pP->createHandle(); - } - - - - public: - Proxy (IHandle const& iha) : THolder(iha) {} - }; - - - template void openProxy (IHandle_DummyPlayer const&); - template void closeProxy (void); - - - } // namespace facade - -} // namespace lumiera diff --git a/src/gui/display-interface-proxy.hpp b/src/gui/display-interface-proxy.hpp new file mode 100644 index 000000000..8ae035124 --- /dev/null +++ b/src/gui/display-interface-proxy.hpp @@ -0,0 +1,94 @@ +/* + Display(Proxy) - service providing access to a display for outputting frames + + Copyright (C) Lumiera.org + 2009, 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 display-interface-proxy.hpp + ** This is an implementation fragment, intended to be included into common/interfaceproxy.cpp + ** + ** The purpose is to define a proxy implementation of lumiera::Display, in order to + ** redirect any calls through the associated C Language Interface "lumieraorg_Display" + ** + ** @see display-facade.hpp + ** @see display-service.hpp actual implementation within the GUI + */ + + + + + + + /* ==================== gui::Display ====================================== */ + +#include "include/display-facade.h" + +namespace lumiera { + + /** storage for the facade proxy factory + * used by client code to invoke through the interface */ + lumiera::facade::Accessor Display::facade; + + /// emit the vtable here into this translation unit within liblumieracommon.so... + Display::~Display() { } + +} // namespace lumiera + + + +namespace lumiera { + namespace facade { + + typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_Display, 0) + , lumiera::Display + > IHandle_Display; + + + template<> + class Proxy + : public Holder + { + //----Proxy-Implementation-of-lumiera::Display-------- + + Display::Sink + getHandle (LumieraDisplaySlot display) + { + _i_.allocate (display); + Sink sinkHandle; + sinkHandle.activate (display, _i_.release); + if (lumiera_error_peek() || !sinkHandle) + throw lumiera::error::State("failed to allocate output DisplayerSlot", + lumiera_error()); + return sinkHandle; + } + + + public: + Proxy (IHandle const& iha) : THolder(iha) {} + }; + + + template void openProxy (IHandle_Display const&); + template void closeProxy (void); + + } // namespace facade + +} // namespace lumiera diff --git a/src/gui/notification-interface-proxy.hpp b/src/gui/notification-interface-proxy.hpp new file mode 100644 index 000000000..361e01865 --- /dev/null +++ b/src/gui/notification-interface-proxy.hpp @@ -0,0 +1,81 @@ +/* + Notification(Proxy) - public service allowing to push informations into the GUI + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + + +/** @file notification-interface-proxy.hpp + ** This is an implementation fragment, intended to be included into common/interfaceproxy.cpp + ** + ** The purpose is to define a proxy implementation of gui::GuiNotification, in order to + ** redirect any calls through the associated C Language Interface "lumieraorg_GuiNotification" + ** + ** @see guinotification-facade.hpp + ** @see notification-service.hpp actual implementation within the GUI + */ + + + + + + /* ==================== GuiNotification =================================== */ + +#include "include/guinotification-facade.h" + +namespace gui { + + /** storage for the facade proxy factory + * used by client code to invoke through the interface */ + lumiera::facade::Accessor GuiNotification::facade; + +} // namespace gui + + + +namespace lumiera { + namespace facade { + + typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 0) + , gui::GuiNotification + > IHandle_GuiNotification; + + + template<> + class Proxy + : public Holder + { + //----Proxy-Implementation-of-GuiNotification-------- + + void displayInfo (string const& text) { _i_.displayInfo (cStr(text)); } + void triggerGuiShutdown (string const& cause) { _i_.triggerGuiShutdown (cStr(cause)); } + + + public: + Proxy (IHandle const& iha) : THolder(iha) {} + }; + + + template void openProxy (IHandle_GuiNotification const&); + template void closeProxy (void); + + } // namespace facade + +} // namespace lumiera diff --git a/src/proc/play/dummy-player-interface-proxy.hpp b/src/proc/play/dummy-player-interface-proxy.hpp new file mode 100644 index 000000000..9726357b4 --- /dev/null +++ b/src/proc/play/dummy-player-interface-proxy.hpp @@ -0,0 +1,99 @@ +/* + DummyPlayer(Proxy) - access point and service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, 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 dummy-player-interface-proxy.hpp + ** This is an implementation fragment, intended to be included into common/interfaceproxy.cpp + ** + ** The purpose is to define a proxy implementation of lumiera::DummyPlayer, in order to + ** redirect any calls through the associated C Language Interface "lumieraorg_DummyPlayer" + ** + ** @see dummy-player-facade.hpp + ** @see dummy-player-service.hpp actual implementation within the Proc-Layer + */ + + + + + + + /* ==================== DummyPlayer ======================================= */ + +#include "proc/play/dummy-player-service.hpp" + +namespace proc { + namespace play { + + /** storage for the DummyPlayer facade proxy factory... */ + lumiera::facade::Accessor DummyPlayer::facade; + +} } + + +namespace lumiera { + namespace facade { + + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) + , proc::play::DummyPlayer + > IHandle_DummyPlayer; + + + template<> + class Proxy + : public Holder + { + //----Proxy-Implementation-of-DummyPlayer-------- + typedef proc::play::DummyPlayer::Process Process; + typedef proc::play::ProcessImpl ProcessImpl; + + /** @note as an optimisation we hand out a direct reference + * to the implementing process object. While this ref could + * still be passed as handle to the C Language interface, using + * it directly within the client (=GUI) bypasses the C interface + * and thus leaves us only with one level of indirection, + * irrespective if using the C or C++ interface. + */ + Process start(LumieraDisplaySlot viewerHandle) + { + ProcessImpl* pP = static_cast (_i_.startPlay (viewerHandle)); + + if (!pP) + throw lumiera::error::State("failed to start DummyPlayer", lumiera_error()); + + return pP->createHandle(); + } + + + + public: + Proxy (IHandle const& iha) : THolder(iha) {} + }; + + + template void openProxy (IHandle_DummyPlayer const&); + template void closeProxy (void); + + + } // namespace facade + +} // namespace lumiera From 379ec7a126723ef13d0cfcc3394d2905f9ffc2ca Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 9 Feb 2009 01:42:28 +0100 Subject: [PATCH 137/216] refactor the dummy player facade to be in namespace lumiera --- src/gui/controller/playback-controller.cpp | 2 +- src/gui/controller/playback-controller.hpp | 2 +- src/include/dummy-player-facade.h | 15 +++--- src/lumiera/main.cpp | 2 +- .../play/dummy-player-interface-proxy.hpp | 11 ++--- src/proc/play/dummy-player-service.cpp | 46 +++++++++++-------- src/proc/play/dummy-player-service.hpp | 1 + 7 files changed, 43 insertions(+), 36 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index 88925415c..bfb623860 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -49,7 +49,7 @@ PlaybackController::play() else if (viewerHandle_) try { - playHandle = proc::play::DummyPlayer::facade().start (viewerHandle_); + playHandle = lumiera::DummyPlayer::facade().start (viewerHandle_); playing = true; } catch (lumiera::error::State& err) diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index bf0eeff94..7ef5ce4fb 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -63,7 +63,7 @@ private: volatile bool playing; - proc::play::DummyPlayer::Process playHandle; + lumiera::DummyPlayer::Process playHandle; LumieraDisplaySlot viewerHandle_; diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h index fcecb234f..3cbca54eb 100644 --- a/src/include/dummy-player-facade.h +++ b/src/include/dummy-player-facade.h @@ -44,15 +44,18 @@ typedef lumiera_playprocess* LumieraPlayProcess; -namespace proc { +namespace proc { namespace play { - class ProcessImpl; +} } + + +namespace lumiera { /****************************************************************** - * Interface Proc-Layer (or maybe the backend?): + * Experimental Interface Proc-Layer (or maybe the backend?): * Global access point for starting a dummy playback, generating * some test image data for the GUI to display in a viewer window. * @@ -85,7 +88,7 @@ namespace proc { * @see dummy-player-service.cpp implementation */ class Process - : public lib::Handle + : public lib::Handle { public: void play(bool); @@ -102,10 +105,8 @@ namespace proc { }; +} // namespace lumiera - } // namespace play - -} // namespace proc diff --git a/src/lumiera/main.cpp b/src/lumiera/main.cpp index 94a133e11..002961de4 100644 --- a/src/lumiera/main.cpp +++ b/src/lumiera/main.cpp @@ -43,7 +43,7 @@ namespace { Subsys& engine = backend::EngineFacade::getDescriptor(); Subsys& netNode = backend::NetNodeFacade::getDescriptor(); Subsys& script = backend::ScriptRunnerFacade::getDescriptor(); - Subsys& player = proc::play::DummyPlayer::getDescriptor(); + Subsys& player = lumiera::DummyPlayer::getDescriptor(); Subsys& builder = proc::Facade::getBuilderDescriptor(); Subsys& session = proc::Facade::getSessionDescriptor(); Subsys& lumigui = gui::GuiFacade::getDescriptor(); diff --git a/src/proc/play/dummy-player-interface-proxy.hpp b/src/proc/play/dummy-player-interface-proxy.hpp index 9726357b4..05319dc27 100644 --- a/src/proc/play/dummy-player-interface-proxy.hpp +++ b/src/proc/play/dummy-player-interface-proxy.hpp @@ -41,16 +41,15 @@ #include "proc/play/dummy-player-service.hpp" -namespace proc { - namespace play { +namespace lumiera { /** storage for the DummyPlayer facade proxy factory... */ lumiera::facade::Accessor DummyPlayer::facade; -} } - - -namespace lumiera { + + + + namespace facade { typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 52125c7bb..d34288de0 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -94,7 +94,7 @@ namespace proc { } }; - lumiera::Singleton theDescriptor; + lumiera::Singleton theDummyPlayerDescriptor; @@ -271,10 +271,6 @@ namespace proc { } - /* === Forwarding function(s) on the Process handle === */ - - void DummyPlayer::Process::play(bool yes) { impl().doPlay(yes); } - @@ -356,24 +352,34 @@ namespace proc { else display_(imageGen_->current()); } - - - - - - - /** @internal intended for use by main(). */ - lumiera::Subsys& - DummyPlayer::getDescriptor() - { - return play::theDescriptor(); - } - - // emit the vtable here into this translation unit within liblumieraproc.so ... - DummyPlayer::~DummyPlayer() { } } // namespace play } // namespace proc + + + + + +namespace lumiera { /* === Forwarding function(s) on the Process handle === */ + + void DummyPlayer::Process::play(bool yes) { impl().doPlay(yes); } + + + + + + /** @internal intended for use by main(). */ + lumiera::Subsys& + DummyPlayer::getDescriptor() + { + return proc::play::theDummyPlayerDescriptor(); + } + + // emit the vtable here into this translation unit within liblumieraproc.so ... + DummyPlayer::~DummyPlayer() { } + + +} // namespace lumiera diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index 55c07e430..2512f38bc 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -55,6 +55,7 @@ namespace proc { using std::string; using lumiera::Subsys; using lumiera::Display; + using lumiera::DummyPlayer; class DummyImageGenerator; From 6757eda3bda35265c2c663a13a5b9f67eb6e8092 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 9 Feb 2009 01:48:13 +0100 Subject: [PATCH 138/216] autotools fix --- tests/lib/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am index 21f6f92e6..2c38a2439 100644 --- a/tests/lib/Makefile.am +++ b/tests/lib/Makefile.am @@ -54,6 +54,7 @@ test_lib_SOURCES = \ $(testlib_srcdir)/sanitizedidentifiertest.cpp \ $(testlib_srcdir)/scopedholdertest.cpp \ $(testlib_srcdir)/scopedholdertransfertest.cpp \ + $(testlib_srcdir)/scoped-ptrvect-test.cpp \ $(testlib_srcdir)/singletonsubclasstest.cpp \ $(testlib_srcdir)/singletontest.cpp \ $(testlib_srcdir)/singletontestmocktest.cpp \ From ebf625acaea4469aa1bc325e9a096ccaa689801c Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 9 Feb 2009 02:40:57 +0100 Subject: [PATCH 139/216] cleanup and comment --- src/gui/display-service.cpp | 11 ++--------- src/gui/display-service.hpp | 25 ++++++++++++++++--------- src/include/display-facade.h | 12 ++++++------ src/include/dummy-player-facade.h | 11 +++++++---- src/proc/play/dummy-player-service.cpp | 13 +++++-------- src/proc/play/dummy-player-service.hpp | 24 +++++++++++++++--------- 6 files changed, 51 insertions(+), 45 deletions(-) diff --git a/src/gui/display-service.cpp b/src/gui/display-service.cpp index 45d38c4dd..c61dce8ee 100644 --- a/src/gui/display-service.cpp +++ b/src/gui/display-service.cpp @@ -22,28 +22,21 @@ #include "gui/display-service.hpp" -//#include "lib/singleton.hpp" extern "C" { #include "common/interfacedescriptor.h" } -#include -//#include -//#include - namespace gui { - using std::string; -// using boost::scoped_ptr; namespace { // hidden local details of the service implementation.... - /* ================== define an lumieraorg_GuiNotification instance ======================= */ + /* ================== define an lumieraorg_Display instance ======================= */ LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 ,lumieraorg_DisplayFacade_descriptor @@ -118,7 +111,7 @@ namespace gui { using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; typedef lib::SingletonRef::Accessor InstanceRef; - InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation... + InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DisplayService implementation... diff --git a/src/gui/display-service.hpp b/src/gui/display-service.hpp index 3783b8dfc..2a84f9c12 100644 --- a/src/gui/display-service.hpp +++ b/src/gui/display-service.hpp @@ -21,17 +21,24 @@ */ /** @file display-service.hpp - ** A public service provided by the GUI, implementing the gui::GuiNotification facade interface. - ** The purpose of this service is to push state update and notification of events from the lower - ** layers into the Lumiera GUI. Typically, this happens asynchronously and triggered by events - ** within the lower layers. + ** A public service provided by the GUI, implementing the lumiera::Display facade interface. + ** It serves two purposes: + ** - It maintains a collection of DisplayerSlot objects, which are the actual connection points + ** and allow to receive frames and dispatch them to the GTK main event loop thread. + ** Conceptually, creating such a slot means providing a possible display for output. + ** - It provides the actual implementation of the Display facade interface, i.e. the function + ** which is to invoked periodically by the playback processes to dispose a new frame into + ** the display. ** - ** This service is the implementation of a layer separation facade interface. Clients should use - ** proc::play::DummyPlayer#facade to access this service. This header defines the interface used - ** to \em provide this service, not to access it. + ** This service is the implementation of a layer separation facade interface. This header defines + ** the interface used to \em provide this service, not to access it. Clients get a specific + ** LumieraDisplaySlot passed as parameter when initiating a playback process from the GUI. Using + ** this LumieraDisplaySlot handle, clients should then use lumiera::DummyPlayer#facade to access + ** an implementation instance of this service in order to push actual frames up. ** - ** @see gui::GuiFacade - ** @see guifacade.cpp starting this service + ** @see lumiera::Display + ** @see lumiera::DummyPlayer + ** @see gui::PlaybackController usage example */ diff --git a/src/include/display-facade.h b/src/include/display-facade.h index 6cabedce0..d3681a08d 100644 --- a/src/include/display-facade.h +++ b/src/include/display-facade.h @@ -21,7 +21,7 @@ */ /** @file display-facade.hpp - ** Major public Interface of the Lumiera GUI. While generally speaking, the GUI + ** Major public Interface of the Lumiera GUI. While, generally speaking, the GUI ** controls the application and thus acts on its own, it exposes some services ** to the lower layers. Especially the lumiera::Display interface serves to ** hand over calculated frames to the GUI for displaying them in a viewer. @@ -64,9 +64,6 @@ typedef lumiera_displaySlot* LumieraDisplaySlot; namespace lumiera { -// class ProcessImpl; - - /****************************************************************** * Interface for outputting frames to an (already allocated) viewer * or display. The viewer is addressed by an "slot" handle, which the @@ -108,6 +105,9 @@ namespace lumiera { { public: + /** push a frame up to the display, calling + * through the CL Interface. + * @see DisplayService::allocate */ inline void operator() (LumieraDisplayFrame frame) { @@ -126,8 +126,8 @@ namespace lumiera { virtual ~Display(); }; - - + + } // namespace lumiera diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h index 3cbca54eb..7b4daff02 100644 --- a/src/include/dummy-player-facade.h +++ b/src/include/dummy-player-facade.h @@ -79,11 +79,13 @@ namespace lumiera { /** * Continuous playback process, which has been started with a specific * output size, format and framerate. It is a handle to a calculation process, - * which is about to produce a stream of frames to be retrieved by calling - * the #getFrame function on this handle. + * which is about to produce a stream of frames and push them to the viewer widget, + * specified by a LumieraDisplaySlot when starting this process. * * The Lifecycle of the referred playback process is managed automatically - * through this handle (by ref count). + * through this handle (by ref count). Client code is supposed to use the + * API on this handle to control the playback mode. + * * @see handle.hpp * @see dummy-player-service.cpp implementation */ @@ -91,12 +93,13 @@ namespace lumiera { : public lib::Handle { public: - void play(bool); + void play(bool); ///< play/pause toggle }; //////////////////TODO: define some dummy negotiation about size and framerate.... + /** create a new playback process outputting to the given viewer/display */ virtual Process start(LumieraDisplaySlot viewerHandle) =0; diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index d34288de0..18f80277b 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -79,17 +79,14 @@ namespace proc { void triggerShutdown () throw() { - TODO ("implement waiting for any playback processes to terminate gracefully"); - //..... but this would require us to use a separate thread, so I skip it for now. - // Probably it's better design to manage the processes in a separate thread anyway... - thePlayer_.reset(0); + // note: shutdown of the DummyPlayerService instance may block + // for a short period, until termination of all tick services } bool checkRunningState () throw() { - //note: not locking here... return (thePlayer_); } }; @@ -100,7 +97,7 @@ namespace proc { - /* ================== define an lumieraorg_GuiNotification instance ======================= */ + /* ================== define an lumieraorg_DummyPlayer instance ======================= */ LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 ,lumieraorg_DummyPlayerFacade_descriptor @@ -294,7 +291,7 @@ namespace proc { void - ProcessImpl::terminate (ProcessImpl* process) + ProcessImpl::terminate (ProcessImpl* process) ///< deleter function for lib::Handle { if (process) delete process; @@ -306,7 +303,7 @@ namespace proc { ProcessImpl::createHandle() { DummyPlayer::Process handle; - handle.activate(this, &terminate); + handle.activate(this, &terminate); // note the deleter function... return handle; } diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index 2512f38bc..8dc1f87e8 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -20,18 +20,20 @@ */ -/** @file notification-service.hpp - ** A public service provided by the GUI, implementing the gui::GuiNotification facade interface. - ** The purpose of this service is to push state update and notification of events from the lower - ** layers into the Lumiera GUI. Typically, this happens asynchronously and triggered by events - ** within the lower layers. +/** @file dummy-player-service.hpp + ** A public service provided by the Proc-Layer, implementing a dummy/mockup playback process. + ** This is a design sketch; Lumiera isn't able to generate rendered output as of 2/2009. The + ** idea is, that for each ongoing calculation process, there is a ProcessImpl instance holding + ** the necessary handles and allocations and providing an uniform API to the client side. + ** Especially, this ProcessImpl holds a TickService, which generates periodic callbacks, and + ** it uses an output handle (functor) to push the generated frames up. ** ** This service is the implementation of a layer separation facade interface. Clients should use ** proc::play::DummyPlayer#facade to access this service. This header defines the interface used ** to \em provide this service, not to access it. ** - ** @see gui::GuiFacade - ** @see guifacade.cpp starting this service + ** @see lumiera::DummyPlayer + ** @see gui::PlaybackController usage example */ @@ -86,9 +88,10 @@ namespace proc { ProcessImpl(LumieraDisplaySlot) ; ~ProcessImpl() ; - /* Implementation-level API to be used By DummyPlayerService */ - /** activate a playback process + /* Implementation-level API */ + + /** activate a playback process * with given specification */ void setRate (uint fps); @@ -97,6 +100,9 @@ namespace proc { void doPlay(bool yes); + + /* Lifecycle */ + DummyPlayer::Process createHandle(); static void terminate(ProcessImpl* process); From 0e5314e0cfe947e51121061a02dee15c6a4c7496 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 9 Feb 2009 05:43:55 +0100 Subject: [PATCH 140/216] keep the display handles within a separate header --- src/gui/Makefile.am | 1 + src/gui/display-service.cpp | 2 +- src/include/display-facade.h | 15 ++------ src/include/display-handles.h | 55 ++++++++++++++++++++++++++++ src/include/dummy-player-facade.h | 9 +---- src/include/guinotification-facade.h | 5 ++- src/proc/Makefile.am | 4 +- 7 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 src/include/display-handles.h diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 427375ad8..2fb9ce96d 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -56,6 +56,7 @@ gtk_gui_la_SOURCES = \ $(lumigui_srcdir)/gtk-lumiera.cpp \ $(lumigui_srcdir)/gtk-lumiera.hpp \ $(lumigui_srcdir)/notification-service.cpp \ + $(lumigui_srcdir)/display-service.cpp \ $(lumigui_srcdir)/window-manager.cpp \ $(lumigui_srcdir)/window-manager.hpp \ $(lumigui_srcdir)/workspace/actions.cpp \ diff --git a/src/gui/display-service.cpp b/src/gui/display-service.cpp index c61dce8ee..1c20dd4de 100644 --- a/src/gui/display-service.cpp +++ b/src/gui/display-service.cpp @@ -228,7 +228,7 @@ namespace gui { DisplayerSlot::DisplayerSlot (FrameDestination const& outputDestination) - : currBuffer_(0) + : currBuffer_(0) { put_ = 0; // mark as not allocated hasFrame_.connect (outputDestination); diff --git a/src/include/display-facade.h b/src/include/display-facade.h index d3681a08d..ef12fdb1d 100644 --- a/src/include/display-facade.h +++ b/src/include/display-facade.h @@ -1,5 +1,5 @@ /* - DISPLAY-FACADE.hpp - accessing a display for outputting frames + DISPLAY-FACADE.h - accessing a display for outputting frames Copyright (C) Lumiera.org 2009, Hermann Vosseler @@ -20,7 +20,7 @@ */ -/** @file display-facade.hpp +/** @file display-facade.h ** Major public Interface of the Lumiera GUI. While, generally speaking, the GUI ** controls the application and thus acts on its own, it exposes some services ** to the lower layers. Especially the lumiera::Display interface serves to @@ -37,18 +37,9 @@ #ifndef GUI_INTERFACE_DISPLAY_H #define GUI_INTERFACE_DISPLAY_H +#include "include/display-handles.h" -typedef unsigned char * LumieraDisplayFrame; - - -struct lumiera_displaySlot_struct - { - void (*put_)(lumiera_displaySlot_struct*, LumieraDisplayFrame); - }; -typedef struct lumiera_displaySlot_struct lumiera_displaySlot; -typedef lumiera_displaySlot* LumieraDisplaySlot; - diff --git a/src/include/display-handles.h b/src/include/display-handles.h new file mode 100644 index 000000000..467607427 --- /dev/null +++ b/src/include/display-handles.h @@ -0,0 +1,55 @@ +/* + DISPLAY-HANDLES.h - opaque handle types for playback and display + + Copyright (C) Lumiera.org + 2009, 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 display-handles.hpp + ** Opaque handles and similar typedefs used to communicate via the + ** lumiera::Display and lumiera::DummyPlayer facade interfaces. + ** + ** @see gui::DisplayService + ** + */ + + +#ifndef LUMIERA_DISPLAY_HANDLES_H +#define LUMIERA_DISPLAY_HANDLES_H + + + + +typedef unsigned char * LumieraDisplayFrame; + + +struct lumiera_displaySlot_struct + { + void (*put_)(lumiera_displaySlot_struct*, LumieraDisplayFrame); + }; +typedef struct lumiera_displaySlot_struct lumiera_displaySlot; +typedef lumiera_displaySlot* LumieraDisplaySlot; + + + +struct lumiera_playprocess_struct { }; +typedef struct lumiera_playprocess_struct lumiera_playprocess; +typedef lumiera_playprocess* LumieraPlayProcess; + + +#endif diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h index 7b4daff02..0447172d1 100644 --- a/src/include/dummy-player-facade.h +++ b/src/include/dummy-player-facade.h @@ -1,5 +1,5 @@ /* - DUMMY-PLAYER-FACADE.hpp - access point to a dummy test player + DUMMY-PLAYER-FACADE.h - access point to a dummy test player Copyright (C) Lumiera.org 2009, Hermann Vosseler @@ -25,12 +25,7 @@ #define PROC_INTERFACE_DUMMYPLAYER_H #include "include/display-facade.h" - - -struct lumiera_playprocess_struct { }; -typedef struct lumiera_playprocess_struct lumiera_playprocess; -typedef lumiera_playprocess* LumieraPlayProcess; - +#include "include/display-handles.h" diff --git a/src/include/guinotification-facade.h b/src/include/guinotification-facade.h index c28f47d85..aba81ea0b 100644 --- a/src/include/guinotification-facade.h +++ b/src/include/guinotification-facade.h @@ -1,5 +1,5 @@ /* - GUINOTIFICATIONFACADE.hpp - access point for pushing informations into the GUI + GUINOTIFICATION-FACADE.h - access point for pushing informations into the GUI Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -20,7 +20,7 @@ */ -/** @file guinotification-facade.hpp +/** @file guinotification-facade.h ** Major public Interface of the Lumiera GUI. While generally speaking, the GUI ** controls the application and thus acts on its own, it exposes some services ** usable by scripts or the two lower layers. The main purpose of these services @@ -35,6 +35,7 @@ #define GUI_GUINOTIFICATION_H + #ifdef __cplusplus /* ============== C++ Interface ================= */ #include "include/interfaceproxy.hpp" diff --git a/src/proc/Makefile.am b/src/proc/Makefile.am index ad41212ee..a79f07183 100644 --- a/src/proc/Makefile.am +++ b/src/proc/Makefile.am @@ -24,7 +24,7 @@ noinst_LTLIBRARIES += liblumiproc.la liblumiproc_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror liblumiproc_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra -liblumiproc_la_SOURCES = \ +liblumiproc_la_SOURCES = \ $(liblumiproc_la_srcdir)/controllerfacade.cpp \ $(liblumiproc_la_srcdir)/facade.cpp \ $(liblumiproc_la_srcdir)/state.cpp \ @@ -205,7 +205,7 @@ noinst_HEADERS += \ $(liblumiproc_la_srcdir)/mobject/builderfacade.hpp \ $(liblumiproc_la_srcdir)/control/pathmanager.hpp \ $(liblumiproc_la_srcdir)/control/renderstate.hpp \ - $(liblumiproc_la_srcdir)/play/dummy-player-service.cpp \ + $(liblumiproc_la_srcdir)/play/tick-service.hpp \ $(liblumiproc_la_srcdir)/play/dummy-image-generator.hpp \ $(liblumiproc_la_srcdir)/mobject/interpolator.hpp \ $(liblumiproc_la_srcdir)/mobject/parameter.hpp \ From ea56841389ee6027029680aa3664c72e6ed2c2e2 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 9 Feb 2009 05:20:58 +0100 Subject: [PATCH 141/216] DummyPlayer finished. General Documentation regarding Layer Interfaces and DummyPlayer --- doc/devel/draw/PlayerArch-1.svg | 580 ++++++++++++++++++++++++------- doc/devel/uml/class146565.html | 21 ++ doc/devel/uml/class146693.html | 23 ++ doc/devel/uml/class146821.html | 23 ++ doc/devel/uml/class146949.html | 21 ++ doc/devel/uml/class147077.html | 23 ++ doc/devel/uml/class147205.html | 22 ++ doc/devel/uml/classdiagrams.html | 1 + doc/devel/uml/classes.html | 6 + doc/devel/uml/classes_list.html | 6 + doc/devel/uml/fig132869.png | Bin 0 -> 13284 bytes doc/devel/uml/index.html | 45 ++- doc/devel/uml/index_67.html | 42 +-- doc/devel/uml/index_70.html | 1 + doc/devel/uml/index_73.html | 4 +- doc/devel/uml/index_76.html | 1 + doc/devel/uml/index_80.html | 1 + doc/devel/uml/index_83.html | 5 +- uml/lumiera/128517 | 182 +++++++++- uml/lumiera/129285 | 2 +- uml/lumiera/132869.diagram | 75 ++++ uml/lumiera/5.session | 5 +- uml/lumiera/lumiera.prj | 2 +- wiki/draw/PlayerArch1.png | Bin 56700 -> 61724 bytes wiki/renderengine.html | 115 +++++- 25 files changed, 1021 insertions(+), 185 deletions(-) create mode 100644 doc/devel/uml/class146565.html create mode 100644 doc/devel/uml/class146693.html create mode 100644 doc/devel/uml/class146821.html create mode 100644 doc/devel/uml/class146949.html create mode 100644 doc/devel/uml/class147077.html create mode 100644 doc/devel/uml/class147205.html create mode 100644 doc/devel/uml/fig132869.png create mode 100644 uml/lumiera/132869.diagram diff --git a/doc/devel/draw/PlayerArch-1.svg b/doc/devel/draw/PlayerArch-1.svg index a3799f876..14862c94a 100644 --- a/doc/devel/draw/PlayerArch-1.svg +++ b/doc/devel/draw/PlayerArch-1.svg @@ -29,7 +29,7 @@ inkscape:pageshadow="2" inkscape:zoom="2" inkscape:cx="419.63217" - inkscape:cy="331.20952" + inkscape:cy="291.20952" inkscape:document-units="px" inkscape:current-layer="svg2" inkscape:window-width="1668" @@ -38,7 +38,7 @@ inkscape:window-y="0" width="800px" height="600px" - showgrid="true" + showgrid="false" gridspacingx="2px" gridspacingy="2px" gridanglex="30px" @@ -56,6 +56,19 @@ guidetolerance="5" /> + + + + y="100" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + y="250" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + y="450" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#6c6c6c;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> start(...) + style="font-size:8px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">start( slot ) yields Proc (or Backend?) + style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> Displayer (Proxy) + sodipodi:role="line">Display::Sink (functor) PlayerFacade (Proxy) + style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans" + id="tspan2303">Proxy<Player> + sodipodi:nodetypes="ccc" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + y="389.93243" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + y="450" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + y="490" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> PlayContext + sodipodi:nodetypes="cc" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + y="190" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + id="path2241" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#4f4f4f;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInL);stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + sodipodi:nodetypes="cc" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + sodipodi:nodetypes="ccc" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + y="250" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> DisplayFacade (Proxy) + sodipodi:role="line">Proxy<Display> + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#4f4f4f;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInL);stroke-opacity:1;opacity:1;color:#000000;marker:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#6c6c6c;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> Displayer + id="tspan2294">DisplayerSlot + y="140.06757" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + y="180.06757" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> Displayer + sodipodi:role="line">DisplayerSlot Displayer + id="tspan2312">DisplayerSlot Displayer + sodipodi:role="line">DisplayerSlot + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + transform="translate(529.80198,-99.756098)" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + sodipodi:nodetypes="ccc" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> yields - ProcessImpl + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + sodipodi:nodetypes="ccc" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + sodipodi:nodetypes="ccc" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> periodically + id="path3436" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#2d2abd;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> attach_viewer() + style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">use_display (slot) + y="70" + inkscape:export-filename="/home/hiv/devel/lumi/wiki/draw/PlayerArch1.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" /> + ProcessImpl + + dispatch toGTK main thread... + play(..) + play(..) + not yet implemented... + diff --git a/doc/devel/uml/class146565.html b/doc/devel/uml/class146565.html new file mode 100644 index 000000000..caadd3954 --- /dev/null +++ b/doc/devel/uml/class146565.html @@ -0,0 +1,21 @@ + + + + + + +Class Facade + + + + + +
Class Facade
+

+ + + +
+

Declaration :

  • C++ : class Facade
  • Java : package interface Facade

Directly inherited by : Proxy ServiceImpl

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

+ + + + +

Declaration :

  • C++ : class Proxy : public Facade
+ +
Relation <unidirectional association>

Declaration :

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

+ + + + +

Declaration :

  • C++ : class ServiceImpl : public Facade
+ +
Relation <unidirectional association>

Declaration :

+ + diff --git a/doc/devel/uml/class146949.html b/doc/devel/uml/class146949.html new file mode 100644 index 000000000..875ffa2e8 --- /dev/null +++ b/doc/devel/uml/class146949.html @@ -0,0 +1,21 @@ + + + + + + +Class C_Interface + + + + + +
Class C_Interface
+

+ + + + +

Declaration :

  • C++ : class C_Interface

Directly inherited by : C_Instance

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

+ + + + +

Declaration :

+ +
Relation <unidirectional association>

Declaration :

+ + diff --git a/doc/devel/uml/class147205.html b/doc/devel/uml/class147205.html new file mode 100644 index 000000000..09e455a99 --- /dev/null +++ b/doc/devel/uml/class147205.html @@ -0,0 +1,22 @@ + + + + + + +Class InstanceHandle + + + + + +
Class InstanceHandle
+

+ + + + +

Declaration :

  • C++ : template<class C_Interface, class Facade> class InstanceHandle
+
+ + diff --git a/doc/devel/uml/classdiagrams.html b/doc/devel/uml/classdiagrams.html index f66c12462..8159cb541 100644 --- a/doc/devel/uml/classdiagrams.html +++ b/doc/devel/uml/classdiagrams.html @@ -24,6 +24,7 @@ HierarchyLumiera Exception hierarchy In Memory Database interface components +Layer Separation Interface Media-Asset Relations Proc-Asset Relations Render Entities diff --git a/doc/devel/uml/classes.html b/doc/devel/uml/classes.html index 63214df7b..637ca483e 100644 --- a/doc/devel/uml/classes.html +++ b/doc/devel/uml/classes.html @@ -32,6 +32,8 @@ BuilderFacadeboundaryProvides unified access to the builder functionality. While individual components of the builder subsystem may be called if necessary or suitable, it is usually better to do all extern invocations via the high level methods of this Facade BuilderToolinterfaceUsed according to the visitor pattern: each Tool contains the concrete implementation for one task to be done to the various MObject classes BuildInstruct(Interface) building instructions to be executed by the Builder on the render node network under construction. +C_Instance +C_Interface Caller Categorytree like classification of Assets Clipbookkeeping (asset) view of a media clip. @@ -58,6 +60,7 @@ ExitNodeThe output of the render pipeline. Pulling from such exit nodes actually ivokes the render process ExplicitPlacementinterface External +Facadeinterface Factorya template for generating functor-like Factory objects, used to encapsulate object creation and providing access via smart-pointers only. FeedCache File @@ -75,6 +78,7 @@ FrameReference GLBuf ImplFacade +InstanceHandle InterpolatorProvides the implementation for getting the acutal value of a time varying or automated effect/plugin parameter Invalid Invocation @@ -117,6 +121,7 @@ Project ProjectorSpecial video processing node used to scale and translate image data. Prototype +Proxy PullInput QueryCache QueryHandlerinterface @@ -134,6 +139,7 @@ Seq Sequence Serializeractor +ServiceImpl 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 SessManager diff --git a/doc/devel/uml/classes_list.html b/doc/devel/uml/classes_list.html index 96378253b..33f50cb20 100644 --- a/doc/devel/uml/classes_list.html +++ b/doc/devel/uml/classes_list.html @@ -33,6 +33,8 @@ BuilderFacade
BuilderTool
BuildInstruct
+C_Instance
+C_Interface
Caller
Category
Clip
@@ -59,6 +61,7 @@ ExitNode
ExplicitPlacement
External
+Facade
Factory
FeedCache
File
@@ -76,6 +79,7 @@ FrameReference
GLBuf
ImplFacade
+InstanceHandle
Interpolator
Invalid
Invocation
@@ -118,6 +122,7 @@ Project
Projector
Prototype
+Proxy
PullInput
QueryCache
QueryHandler
@@ -135,6 +140,7 @@ Seq
Sequence
Serializer
+ServiceImpl
Session
SessionImpl
SessManager
diff --git a/doc/devel/uml/fig132869.png b/doc/devel/uml/fig132869.png new file mode 100644 index 0000000000000000000000000000000000000000..5935bc63c86672bee9da2ce067594897ddd97f40 GIT binary patch literal 13284 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 literal 0 HcmV?d00001 diff --git a/doc/devel/uml/index.html b/doc/devel/uml/index.html index c05d6f597..55bbadb38 100644 --- a/doc/devel/uml/index.html +++ b/doc/devel/uml/index.html @@ -129,7 +129,7 @@ Documentation
Artifact Lumiera

Depends on common

Depends on gui

Depends on proc

Depends on backend

the main executable to be built

-

executable associated with : glbuf, procnode, stateproxy, hub, buildable, abstractmo, nodecreatertool, projector, interpolator, edl, fixture, glpipe, vrender, exitnode, pathmanager, track, paramprovider, mask, main, conmanager, clip, meta, fixedlocation, relativelocation, mobject, source, frame, placement, sessionimpl, builderfacade, controllerfacade, processor, pluginadapter, effect, buildertool, segmentationtool, aframe, assembler, trafo, explicitplacement, auto, glrender, link, parameter, renderengine, allocation, vframe, toolfactory, arender, renderstate, label

+

executable associated with : controllerfacade, processor, pluginadapter, effect, buildertool, segmentationtool, aframe, assembler, trafo, explicitplacement, auto, glrender, link, parameter, renderengine, allocation, vframe, toolfactory, arender, renderstate, label, glbuf, procnode, stateproxy, hub, buildable, abstractmo, nodecreatertool, projector, interpolator, edl, fixture, glpipe, vrender, exitnode, pathmanager, track, paramprovider, mask, main, conmanager, clip, meta, fixedlocation, relativelocation, mobject, source, frame, placement, sessionimpl, builderfacade

Artifact main

Artifact source

@@ -1180,8 +1180,21 @@ 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 InterfaceSystem

    +
    + +

    +

    Layer Separation Interface



    +
    Class Facade
    +
    Class Proxy
    +
    +
    +
    +
    +
    -

    5.1 Class View StreamType

    +

    5.2 Class View StreamType

    @@ -1193,10 +1206,10 @@ reuse exiting Engine

    Selection :

      Transformation
      Class MediaKind

      -

      5.2 Package ConfigQuery

      +

      5.3 Package ConfigQuery

      -

      5.2.1 Component View Query System overview

      +

      5.3.1 Component View Query System overview

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

      Selection :

        Transformation
        Component DefaultsManager

        -

        5.2.2 Class View query

        +

        5.3.2 Class View query

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

        Selection :

          Transformation

          -

          5.2.3 Use Case View query use

          +

          5.3.3 Use Case View query use

          when to query



          -

          5.2.3.1 Use Case create specific object

          +

          5.3.3.1 Use Case create specific object

          -

          5.2.3.2 Use Case use "default" object

          +

          5.3.3.2 Use Case use "default" object

          -

          5.2.3.3 Use Case load object from session

          +

          5.3.3.3 Use Case load object from session

          -

          5.2.3.4 Use Case add new object to session

          +

          5.3.3.4 Use Case add new object to session

          Class User
          -

          5.2.3.5 Use Case ConfigQuery

          +

          5.3.3.5 Use Case ConfigQuery

          -

          5.2.3.6 Use Case need sub object

          +

          5.3.3.6 Use Case need sub object

          "default" object



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

          Selection :

            Transformation
            Class instance predicate impl

            type :TypeHandler

            -

            5.3 Class View error

            +

            5.4 Class View error

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

            Selection :

              Transformation

              -

              5.4 Class View Service Components

              +

              5.5 Class View Service Components

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

              Selection :

                Transformation
                Class Appconfig

                -

                5.5 Class View Posix Threads Abstraction

                +

                5.6 Class View Posix Threads Abstraction

                C++ wrapers for pthreads

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

                Selection :

                  Transformation
                  Class Mutex

                  -

                  5.6 Class View SmartPointers

                  +

                  5.7 Class View SmartPointers

                  diff --git a/doc/devel/uml/index_67.html b/doc/devel/uml/index_67.html index 81d96139c..b906f4d25 100644 --- a/doc/devel/uml/index_67.html +++ b/doc/devel/uml/index_67.html @@ -17,6 +17,8 @@ + + @@ -30,39 +32,39 @@ - + + + + + - - - + - - - - - - - - - - - + + + + + - + + - - - + + + + + + - + diff --git a/doc/devel/uml/index_70.html b/doc/devel/uml/index_70.html index 77ab812da..5f2c83e88 100644 --- a/doc/devel/uml/index_70.html +++ b/doc/devel/uml/index_70.html @@ -17,6 +17,7 @@
                  NameKindDescription
                  C_Instanceclass
                  C_Interfaceclass
                  Cachecomponent
                  Cachecomponent view
                  callDownoperation
                  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
                  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.
                  clipartifacta Media Clip
                  clipartifactbookkeeping (asset) view of a media clip.
                  clipartifacta Media Clip
                  Clipclass
                  clipsrelation
                  Codecclassdescription of some media data decoder or encoder facility
                  + diff --git a/doc/devel/uml/index_73.html b/doc/devel/uml/index_73.html index 963294360..7f152ccfe 100644 --- a/doc/devel/uml/index_73.html +++ b/doc/devel/uml/index_73.html @@ -22,13 +22,15 @@ - + + + diff --git a/doc/devel/uml/index_76.html b/doc/devel/uml/index_76.html index 75cbabe50..0689ba659 100644 --- a/doc/devel/uml/index_76.html +++ b/doc/devel/uml/index_76.html @@ -19,6 +19,7 @@ + diff --git a/doc/devel/uml/index_80.html b/doc/devel/uml/index_80.html index 85ccb15d9..d024e3dca 100644 --- a/doc/devel/uml/index_80.html +++ b/doc/devel/uml/index_80.html @@ -71,6 +71,7 @@ +
                  NameKindDescription
                  Facadeclass
                  Factoryclassa template for generating functor-like Factory objects, used to encapsulate object creation and providing access via smart-pointers only.
                  FeedCacheclass
                  fetchoperation
                  In Memory Databaseclass diagram
                  inFixtureactivity action pin
                  inputclass instance
                  inputclass instance
                  inputclass instance
                  inputclass instance
                  instanceoperation
                  InstanceHandleclass
                  instructionsrelation
                  Interfaceclass view
                  interface componentsclass diagram
                  interfacescomponent view
                  InterfaceSystemclass view
                  interpolatorartifactdenotes a facility to get (continuously interpolated) parameter values
                  InterpolatorclassProvides the implementation for getting the acutal value of a time varying or automated effect/plugin parameter
                  Invalidclass
                  NameKindDescription
                  labelartifact
                  Labelclass
                  Layer Separation Interfaceclass diagram
                  lengthattributeTODO: how to represent time intervals?
                  lengthattributeduration (span) of this timeline segment.
                  Linkclass
                  projectorartifactvideo ProcNode for scaling and translating image data
                  Prototypeclass
                  providerrelation
                  Proxyclass
                  pulloperation
                  PullInputclass
                  diff --git a/doc/devel/uml/index_83.html b/doc/devel/uml/index_83.html index e92c87510..9c9ebb223 100644 --- a/doc/devel/uml/index_83.html +++ b/doc/devel/uml/index_83.html @@ -32,10 +32,11 @@ Sequenceclass Serializerclass Service Componentsclass view +ServiceImplclass Sessioncomponent sessionartifactInterface: the session edited by the user -sessionpackagesourcecode package

                  Everything concerning the EDL and Session, within the MObject Subsystem Sessionclass view +sessionpackagesourcecode package

                  Everything concerning the EDL and Session, within the MObject Subsystem 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 @@ -49,8 +50,8 @@ SimpleClipclassElementary clip consisting of only one media stream SmartPointerclass SmartPointersclass view -sourcerelationthe media source this clip referes to sourcerelationmedia source of this clip +sourcerelationthe media source this clip referes to SourceclassSource Node: represents a media source to pull data from. sourceartifactRepresentation of a Media source Source Overviewdeployment diagram diff --git a/uml/lumiera/128517 b/uml/lumiera/128517 index 6feb7ce56..6f5c8ce9d 100644 --- a/uml/lumiera/128517 +++ b/uml/lumiera/128517 @@ -1,6 +1,6 @@ format 40 "CommonLib" // CommonLib - revision 13 + revision 14 modified_by 5 "hiv" // class settings //class diagram settings @@ -26,6 +26,184 @@ format 40 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 + classview 129541 "InterfaceSystem" + //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 132869 "Layer Separation Interface" + 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 146565 "Facade" + visibility package stereotype "interface" + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "${comment}${@}${visibility}interface ${name}${extends} { +${members}} +" + idl_decl "${comment}${abstract}${local}interface ${name}${inherit} { +${members}}; +" + explicit_switch_type "" + + end + + class 146693 "Proxy" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 161797 // + relation 157189 -_-|> + a public + cpp default "${type}" + classrelation_ref 161797 // + b multiplicity "" parent class_ref 146565 // Facade + end + + classrelation 162181 // + relation 157573 ---> + stereotype "uses" + a role_name "" multiplicity "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 162181 // + b multiplicity "" parent class_ref 146949 // C_Interface + end + end + + class 146821 "ServiceImpl" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 161925 // + relation 157317 -_-|> + a public + cpp default "${type}" + classrelation_ref 161925 // + b multiplicity "" parent class_ref 146565 // Facade + end + + classrelation 162437 // + relation 157829 ---> + stereotype "has_a" + a role_name "" multiplicity "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 162437 // + b multiplicity "" parent class_ref 147205 // InstanceHandle + end + end + + class 146949 "C_Interface" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + end + + class 147077 "C_Instance" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 162053 // + relation 157445 -_-|> + a public + cpp default "${type}" + classrelation_ref 162053 // + b multiplicity "" parent class_ref 146949 // C_Interface + end + + classrelation 162309 // + relation 157701 ---> + stereotype "calls" + a role_name "" multiplicity "" protected + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 162309 // + b multiplicity "" parent class_ref 146821 // ServiceImpl + end + end + + class 147205 "InstanceHandle" + visibility package + nformals 2 + formal name "C_Interface" type "class" explicit_default_value "" + explicit_extends "" + formal name "Facade" type "class" explicit_default_value "" + explicit_extends "" + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + classrelation 162565 // + relation 157957 -_-> + stereotype "opens" + a package + cpp default "#include in source" + classrelation_ref 162565 // + b multiplicity "" parent class_ref 147077 // C_Instance + end + + classrelation 162693 // + relation 158085 -_-> + stereotype "creates" + a package + cpp default "#include in source" + classrelation_ref 162693 // + b multiplicity "" parent class_ref 146693 // Proxy + end + end + end + classview 129285 "StreamType" //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 @@ -127,7 +305,7 @@ ${inlines} classrelation 158341 // relation 154245 -_-> a default - cpp default "Generated" + cpp default "#include in header" classrelation_ref 158341 // b multiplicity "" parent class_ref 144773 // StreamType end diff --git a/uml/lumiera/129285 b/uml/lumiera/129285 index 4089706c0..96ad397a7 100644 --- a/uml/lumiera/129285 +++ b/uml/lumiera/129285 @@ -1,6 +1,6 @@ format 40 "ProcessingLayer" // ProcessingLayer - revision 24 + revision 25 modified_by 5 "hiv" // class settings //class diagram settings diff --git a/uml/lumiera/132869.diagram b/uml/lumiera/132869.diagram new file mode 100644 index 000000000..654d09664 --- /dev/null +++ b/uml/lumiera/132869.diagram @@ -0,0 +1,75 @@ +format 40 + +classcanvas 128005 class_ref 146565 // Facade + 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 66 14 2000 + end +classcanvas 128133 class_ref 146693 // Proxy + 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 23 116 2000 + end +classcanvas 128261 class_ref 146821 // ServiceImpl + 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 271 198 2000 + end +classcanvas 128389 class_ref 146949 // C_Interface + 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 136 117 2000 + end +classcanvas 128517 class_ref 147077 // C_Instance + 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 137 197 2000 + end +classcanvas 128645 class_ref 147205 // InstanceHandle + 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 171 277 2000 + end +textcanvas 130309 "conceptually equivalent" + xyzwh 165 11 2000 115 18 +relationcanvas 128773 relation_ref 157189 // + geometry VHV + from ref 128133 z 1999 to point 43 95 + line 129157 z 1999 to point 103 95 + line 129285 z 1999 to ref 128005 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 128901 relation_ref 157317 // + geometry VHV unfixed + from ref 128261 z 1999 to point 305 95 + line 129413 z 1999 to point 103 95 + line 129541 z 1999 to ref 128005 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 129029 relation_ref 157445 // + from ref 128517 z 1999 to ref 128389 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 129669 relation_ref 157573 // + from ref 128133 z 1999 stereotype "<>" xyz 75 135 3000 to ref 128389 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 129797 relation_ref 157701 // + from ref 128517 z 1999 stereotype "<>" xyz 213 216 3000 to ref 128261 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 130437 relation_ref 157829 // + geometry HVr + from ref 128261 z 1999 stereotype "<>" xyz 279 305 3000 to point 305 305 + line 130565 z 1999 to ref 128645 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 130693 relation_ref 157957 // + from ref 128645 z 1999 stereotype "<>" xyz 112 281 3000 to point 104 296 + line 130821 z 1999 to point 104 213 + line 130949 z 1999 to ref 128517 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +relationcanvas 131077 relation_ref 158085 // + from ref 128645 z 1999 stereotype "<>" xyz 88 306 3000 to point 89 305 + line 131205 z 1999 to ref 128133 + no_role_a no_role_b + no_multiplicity_a no_multiplicity_b +line 130053 -_-_ + from ref 128005 z 1999 to point 224 27 + line 130181 z 1999 to ref 128389 +end diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session index d04da5e91..83fe86cc6 100644 --- a/uml/lumiera/5.session +++ b/uml/lumiera/5.session @@ -2,8 +2,10 @@ window_sizes 1302 1004 270 1022 854 71 diagrams classdiagram_ref 128133 // Session structure 853 742 100 4 120 0 - active classdiagram_ref 132741 // TimelineSequences + classdiagram_ref 132741 // TimelineSequences 585 732 100 4 0 0 + active classdiagram_ref 132869 // Layer Separation Interface + 373 417 100 4 0 0 end show_stereotypes selected @@ -38,6 +40,7 @@ open class_ref 144517 // Strategy class_ref 144005 // BuffTable class_ref 144261 // Invocation + classview_ref 129541 // InterfaceSystem 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 1017e01e2..212f6ce25 100644 --- a/uml/lumiera/lumiera.prj +++ b/uml/lumiera/lumiera.prj @@ -1,6 +1,6 @@ format 40 "lumiera" - revision 49 + revision 50 modified_by 5 "hiv" cpp_root_dir "../../src/" diff --git a/wiki/draw/PlayerArch1.png b/wiki/draw/PlayerArch1.png index 2a8e24e3540819a51cb60c763ba20ec3fc6c1dae..5d3b947d4e2b7c768d979f1e1deb7f1fc7c434bb 100644 GIT binary patch literal 61724 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 Q8z7)z3@y;*mt7zH54nQsv;Y7A literal 56700 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 diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 68eee94a7..cdc7d9ac7 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -1121,6 +1121,21 @@ 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.
                  +
                  +
                  LayerSeparationInterface provided by the GUI.
                  +Access point especially for the playback. A render- or playback process uses the DisplayFacade to push media date up to the GUI for display within a viewer widget of full-screen display. This can be thought off as a callback mechanism. In order to use the DisplayFacade, client code needs a DisplayerSlot (handle), which needs to be set up by the UI first and will be provided when starting the render or playback process.
                  +
                  +
                  +
                  +
                  A service within the GUI to manage output of frames generated by the lower layers of the application.
                  +*providing the actual implementation of the DisplayFacade
                  +*creating and maintaining of [[displayer slots|DisplayerSlot]], connected to viewer widgets or similar
                  +
                  +
                  +
                  +
                  An output port wired up to some display facility or viewer widget within the UI. For the client code, each slot is represented by a handle, which can be used to lock into this slot for an continuous output process. Managed by the DisplayService
                  +
                  +
                  <<<
                   {{red{WARNING: Naming is currently being discussed (11/08)}}}
                  @@ -1373,15 +1388,24 @@ Thus, the Proc-Layer exposes (one or several) facade interfaces for the GUI to u
                   * GuiFacade is implemented by a class //in core// and exposes a notification proxy implementing GuiNotificationFacade, which actually is wired through the InterfaceSystem to forward to the corresponding implementation facade object within the GUI
                   * similarly, starting the fundamental subsystems within proc installs Interfaces into the InterfaceSystem and exposes them through proxy objects
                   
                  +
                  +
                  +
                  +
                  special LayerSeparationInterface which serves the main purpose to load the GuiStarterPlugin, thus bringing up the Lumiera GTK UI at application start.
                   
                  Considering how to interface to and integrate with the GUI Layer. Running the GUI is //optional,// but it requires to be [[started up|GuiStart]], installing the necessary LayerSeparationInterfaces. As an example how to integrate the GUI with the lower layers, in 1/2009 we created an PlayerDummy, which "pulls" dummy frames from the (not yet existing) engine and displays them within an XV viewer widget.
                   
                  -
                  +
                  +
                  LayerSeparationInterface provided by the GUI.
                  +Access point for the lower layers to push information and state changes (aynchronously) to the GUI. Actually, most operations within Lumiera are initiated by the user through the GUI. In the course of such actions, the GUI uses the services of the lower layer and typically recieves an synchronous response. In some exceptional cases, these operations may cause additional changes to happen asynchronously from the GUI's perspective. For example, an edit operation might trigger a re-build of the low-level model, which then detects an error.
                  +
                  +
                  +
                  Starting up the GUI is optional and is considered part of the Application start/stop and lifecycle.
                  -* main and AppState activate the lifecyle methods on the ~GuiSubsysDescriptor
                  +* main and AppState activate the lifecyle methods on the ~GuiSubsysDescriptor, accessible via the GuiFacade
                   * loading a GuiStarterPlugin actually
                   ** loads the GUI (shared lib)
                   ** creates instances of all the GUI services available through LayerSeparationInterfaces
                  @@ -1400,6 +1424,10 @@ Note that we retain strict isolation in the other direction: no part of the lowe
                   Now, when invoking an operation on some public interface, the code in the lower layers actually executes an implementation of this operation //on the facade proxy,// which in turn forwards the call through the CL interface into the GUI, where it is actually implemented by the corresponding service object instance.
                   
                  +
                  +
                  A specially configured LumieraPlugin, which actually contains or loads the complete code of the (GTK)GUI, and additionally is linked dynamically against the application core lib. During the [[UI startup process|GuiStart]], loading of this Plugin is triggered from {{{main()}}}. Actually this causes spawning of the GTK event thread and execution of the GTK main loop.
                  +
                  +
                  While the low-level model holds the data used for carrying out the actual media data processing (=rendering), the high-level model is what the user works upon when performing edit operations through the GUI (or script driven in &raquo;headless mode&laquo;). Its building blocks and combination rules determine largely what structures can be created within the [[Session]].
                   On the whole, it is a collection of [[media objects|MObjects]] stuck together and arranged by [[placements|Placement]].
                  @@ -1437,7 +1465,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]]
                  @@ -1458,6 +1486,7 @@ Finally, this example shows an ''automation'' data set controlling some paramete
                   * how to classify and [[describe media stream types|StreamType]] and how to [[use them|StreamTypeUse]]
                   * the relation of [[Project, Timelines and Sequences|TimelineSequences]]
                   * how to [[start the GUI|GuiStart]] and how to [[communicate|GuiCommunication]]
                  +* build the first LayerSeparationInterfaces
                   
                  @@ -1782,6 +1811,16 @@ config.formatters.push( { } ) //}}}
                  +
                  +
                  An RAII class, used to manage a [[facade interface between layers|LayerSeparationInterface]].
                  +The InstanceHandle is created by the service implementation and will automatically
                  +* either register and open a ''C Language Interface'', using Lumiera's InterfaceSystem
                  +* or load and open a LumieraPlugin, also by using the InterfaceSystem
                  +* and optionally also create and manage a facade proxy to allow transparent access for client code
                  +
                  +&rarr; see [[detailed description here|LayerSeparationInterfaces]]
                  +
                  +
                  Because we rely on strong decoupling and separation into self contained components, there is not much need for a common quasi-global namespace. Operations needing the cooperation of another subsystem will be delegated or even dispatched, consequently implementation code needs only the service acces points from "direct cooperation partner" subsystems. Hierarchical scopes besides classes are needed only when multiple subsystems share a set of common abstractions. Interface and Implementation use separate namespaces.
                   
                  @@ -1814,18 +1853,41 @@ From experiences with other middle scale projects, I prefer having the test code
                   [img[Example: Interfaces/Namespaces of the ~Session-Subsystems|uml/fig130053.png]]
                   
                  -
                  -
                  Lumiera uses a 3-layered architecture. Separation between layers is crucial. Any communication between the layers regarding the normal operation of the application should //at least be initiated// through ''Layer abstraction interfaces''. This is a low-impact version of layering, because, aside from this triggering, direct cooperation of parts within the single Lumiera process is allowed, under the condition that is is implemented using additional abstractions (interfaces with implementation level granularity). We stick to the policy of //disallowing direct coupling of implementations located in different layers.//
                  +
                  +
                  A major //business interfaces// &mdash; used by the layers for interfacing to each other; also to be invoked externally by scripts.
                  +&rarr; [[overfiew and technical details|LayerSeparationInterfaces]]
                  +
                  +
                  +
                  +
                  Lumiera uses a 3-layered architecture. Separation between layers is crucial. Any communication between the layers regarding the normal operation of the application should //at least be initiated// through ''Layer abstraction interfaces'' (Facade Interfaces). This is a low-impact version of layering, because, aside from this triggering, direct cooperation of parts within the single Lumiera process is allowed, under the condition that is is implemented using additional abstractions (interfaces with implementation level granularity). We stick to the policy of //disallowing direct coupling of implementations located in different layers.//
                   
                  +[>img[Anatomy of a Layer Separation Interface|uml/fig132869.png]]
                  +The goal is for the interface to remain fairly transparent for the client and to get an automatic lifecycle management. 
                   To implement such a structure, each layer separation interface actually is comprised of several parts:
                  -* an C Language Interface ("CL Interface") to be installed into the InterfaceSystem
                  -* a facade interface defining the respective abstractions in terms of the implementation language (C or C++)
                  -* a implementation object on the service proiding side which is directly addressed by the implementation instantiated within the InterfaceSystem
                  -* a proxy object on the client side, which usually is given inline alongside with the CLI interface definition.
                  +* an C Language Interface ("''CL Interface''") to be installed into the InterfaceSystem
                  +* a ''facade interface'' defining the respective abstractions in terms of the client side impl. language (C or C++)
                  +* a ''service implementation'' directly addressed by the implementation instantiated within the InterfaceSystem
                  +* a ''facade proxy'' object on the client side, which usually is given inline alongside with the CL interface definition.
                   
                   !opening and closing
                   Handling the lifecycle can be tricky, because client- and service-side need to carry out the opening and closing operations in sync and observing a specific call order to ensure calls get blocked already on the client side unless the whole interface compound is really up and running. To add to this complexity, plugins and built-in interfaces are handled differently regarding the question who is in charge of the lifecycle: interfaces are installed on the service side, whereas the loading of plugins is triggered from client side by requesting the plugin from the loader.
                  -Anyway, interfaces are resources which best should be managed automatically. At least within the C++ part of the application we can ensure this by using a handle class. This way the handling of plugins and interfaces can be unified; the only remaining difference is on what side (client or service provider side) the handle is instantiated, with the appropriate ctor parameters.
                  +Anyway, interfaces are resources which best should be managed automatically. At least within the C++ part of the application we can ensure this by using the InstanceHandle template. This way the handling of plugins and interfaces can be unified and the opening and closing of the facade proxy happens automatically.
                  +
                  +The general idea is, that each facade interface actually provides access to a specific service; there will always be a single implementation object somewhere, which can be thought of as acting as "the" service. This service-providing object will then contain the mentioned InstanceHandle; thus, its lifecycle becomes identical with the service lifecycle.
                  +* when the service relies on a [[plugin|LumieraPlugin]], this service providing object (containing the InstanceHandle) needs to sit at the service accessing side (as the plugin may not yet be loaded and someone has to pull it up).
                  +* otherwise, when the service is just an interface to an already loaded facility, the service providing object (containing the InstanceHandle) will live on the service providing side, not the client side. Then the ctor of the service providing object needs to be able to access an interface instance definition (&rarr; InterfaceSystem); the only difference to the plugin case is to create the InstanceHandle with a different ctor, passing the interface and the implementing instance.
                  +
                  +!outline of the major interfaces
                  +|!Layer|>|!Interface |
                  +|GUI|GuiFacade|UI lifecycle &rarr; GuiStart|
                  +|~|GuiNotificationFacade|status/error messages, asynchronous object status change notifications, trigger shutdown|
                  +|~|DisplayFacade|pushing frames to a display/viewer|
                  +|Proc|SessionFacade|session lifecycle|
                  +|~|EditFacade|edit operations, object mutations|
                  +|~|PlayerDummy|player mockup, maybe move to backend?|
                  +|//Lumiera's major interfaces//|c
                  +
                  +
                   
                  @@ -2797,25 +2859,29 @@ We need a way of addressing existing [[pipes|Pipe]]. Besides, as the Pipes and T <<tasksum end>>
                  -
                  -
                  Joelholdsworth and Ichthyo created this player mockup in 1/2009 to find out about the implementation details regarding integration and colaboration between the layers. There is no working render engine yet, thus we use a ~DummyImageGenerator for creating faked yuv frames to display. Within the GUI, there is a ~PlaybackController hooked up with the transport controls on the timeline pane.
                  +
                  +
                  __Joelholdsworth__ and __Ichthyo__ created this player mockup in 1/2009 to find out about the implementation details regarding integration and colaboration between the layers. There is no working render engine yet, thus we use a ~DummyImageGenerator for creating faked yuv frames to display. Within the GUI, there is a ~PlaybackController hooked up with the transport controls on the timeline pane.
                   # first everything was contained within ~PlaybackController, which spawns a thread for periodically creating those dummy frames
                   # then, a ~PlayerService was factored out, now implemented within Proc-Layer (probably to be relocated into the backend for the final version). A new LayerSeparationInterface called ''~DummyPlayer'' was created and set up as a [[Subsystem]] within main().
                   # the next step was to support multiple playback processes going on in parallel. Now, the ~PlaybackController holds an smart-handle to the ~PlayProcess currently generating output for this viewer, and invokes the transport control functions and the pull frame call on this handle.
                  -# then, also the tick generation (and thus the handling of the thread which pulls the frames) was factored out and pushed down into the mentioned ~PlayProcess. For this to work, the ~PlaybackController now makes a display slot available on the public GUI DisplayFacade interface.
                  +# then, also the tick generation (and thus the handling of the thread which pulls the frames) was factored out and pushed down into the mentioned ~PlayProcess. For this to work, the ~PlaybackController now makes a display slot available on the public GUI DisplayFacade interface, so the ~PlayProcessImpl can push up the frames for display within the GUI
                   [img[Overview to the dummy player operation|draw/PlayerArch1.png]]
                   
                   !when playing...
                  -As a prerequisite, a viewer has to be prepared within the GUI. A XV video display widget is wired up to a sigc++ signal slot, using the Glib::Dispatcher to forward calls from the play process thread to the GTK main event loop thread. When doing so, additionally a Displayer slot is created with the DisplayService.
                  +As a prerequisite, a viewer has to be prepared within the GUI. A XV video display widget is wired up to a sigc++ signal slot, using the Glib::Dispatcher to forward calls from the play process thread to the GTK main event loop thread. All of this wiring actually is encapsulated as a DisplayerSlot, created and registered with the DisplayService.
                   
                  -When starting playback, the slot handle created by these preparations is used to create a ~PlayProcess on the ~DummyPlayer interface. Actually
                  +When starting playback, the display slot handle created by these preparations is used to create a ~PlayProcess on the ~DummyPlayer interface. Actually
                   * a ~PlayProcessImpl object is created down within the player implementation
                  -* this uses the slot handle to actually allocate the display slot via the Display facade
                  -* moreover, it aquires an TickService instance, which is still trotteling (not calling the periodic callback)
                  +* this uses the provided slot handle to actually //allocate// the display slot via the Display facade. Here, //allocating// means registering and preparing it for output by //one single// ~PlayProcess. For the latter, this allocation yields an actually opened display handle.
                  +* moreover, the ~PlayProcessImpl aquires an TickService instance, which is still trotteling (not calling the periodic callback)
                  +* probably, a real player at this point would initiate a rendering process, so he can fetch the actual output frames periodically.
                   * on the "upper" side of the ~DummyPlayer facade, an lib::Handle object is created to track and manage this ~PlayProcesImpl instance
                  -The handle is returned to the ~PlaybackController within the GUI, which uses this handle for all further interactions with the Player. The handle is ref counting and has value semantics, so it can be stored away, passed as parameter and so on. All such handles corresponding to one ~PlayProcess form a family; when the last goes out of scope, the ~PlayProcess terminates and deallocates any resources. Conceptually, this corresponds to pushing the "stop" button. Handles can be deliberately disconnected by calling {{{handle.close()}}} &mdash; this has the same effect as deleting a handle (when all are closed or deleted the process ends).
                  +The mentioned handle is returned to the ~PlaybackController within the GUI, which uses this handle for all further interactions with the Player. The handle is ref counting and has value semantics, so it can be stored away, passed as parameter and so on. All such handles corresponding to one ~PlayProcess form a family; when the last goes out of scope, the ~PlayProcess terminates and deallocates any resources. Conceptually, this corresponds to pushing the "stop" button. Handles can be deliberately disconnected by calling {{{handle.close()}}} &mdash; this has the same effect as deleting a handle (when all are closed or deleted the process ends).
                   
                  -All the other play control operations are simply forwarded via the handle and the ~PlayProcessImpl. For example, "pause" corresponds to setting the tick frequency to 0 (thus temporarily discontinuing the tick callbacks). When allocating the display slot in the course of creating the ~PlayProcessImpl, the latter only accesses the Display facade. It can't access the display or viewer directly, because the GUI lives within an plugin; lower layers can't call directly into GUI functions. Thus, within the Display facade a functor (proxy) is created to represent the output sink. This (proxy) Displayer can be used within the implementation of the perodic callback function. As usual, the implementation of the (proxy) Displayer can be inlined and doesn't create an indirection at runtime. Thus, each frame output call has to pass though two indirections: the function pointer in the Display facade interface, and the Glib::Dispatcher.
                  +All the other play control operations are simply forwarded via the handle and the ~PlayProcessImpl. For example, "pause" corresponds to setting the tick frequency to 0 (thus temporarily discontinuing the tick callbacks). When allocating the display slot in the course of creating the ~PlayProcessImpl, the latter only accesses the Display facade. It can't access the display or viewer directly, because the GUI lives within an plugin; lower layers aren't allowed to call GUI implementation functions directly. Thus, within the Display facade a functor (proxy) is created to represent the output sink. This (proxy) Displayer can be used within the implementation of the perodic callback function. As usual, the implementation of the (proxy) Displayer can be inlined and doesn't create runtime overhead. Thus, each frame output call has to pass though two indirections: the function pointer in the Display facade interface, and the Glib::Dispatcher.
                  +
                  +!rationale
                  +There can be multiple viewer widgets, to be connected dynamically to multiple play-controllers. (the latter are associated with the timeline(s)). Any playback can require multiple playback processes to work in parallel. The playback controller(s) should not be concerned with managing the play processes, which in turn should neither care for the actual rendering, nor manage the display frequency and synchronisation issues. Moreover, the mentioned parts live in different layers and especially the GUI needs to remain separated from the core. And finally, in case of a problem within one play process, it should be able to unwind automatically, without interfering with other ongoing play processes.
                   
                  @@ -4823,6 +4889,14 @@ function addKeyDownHandlers(e) } //}}}
                  +
                  +
                  A service generating //periodic ticks// &mdash; repetedly invoking a callback with a given frequency.
                  +* defined 1/2009 as part of the PlayerDummy (design sketch)
                  +* probably to be implemented later on based on Posix timers
                  +* will probably be later on integrated into a synchronisation framework (display sync, audio sync, MTC master/slave...)
                  +
                  +
                  +
                  http://tiddlywiki.com/
                  @@ -5075,6 +5149,9 @@ Wiring requests are small stateful value objects. They will be collected, sorted [[Automation]] is treated as a function over time. Everything beyond this definition is considered an implementation detail of the [[parameter provider|ParamProvider]] used to yield the value. Thus automation is closely tied to the concept of a [[Parameter]], which also plays an important role in the communication with the GUI and while [[setting up and wiring the render nodes|BuildRenderNode]] in the course of the build process (&rarr; see [[tag:Builder|Builder]])
                  +
                  +
                  Definition of commonly used terms and facilities...
                  +
                  From b8d3e841d0596c87800b92e304d3cd7d147f3271 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 15 Feb 2009 19:29:10 +0100 Subject: [PATCH 142/216] forgot new llist.h --- src/lib/llist.h | 73 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/src/lib/llist.h b/src/lib/llist.h index 353fe4320..25a9dca39 100644 --- a/src/lib/llist.h +++ b/src/lib/llist.h @@ -79,17 +79,19 @@ int that is increased with each revision of this International Standard. /* * Type of a llist node. */ +#ifndef LLIST_DEFINED +#define LLIST_DEFINED struct llist_struct { struct llist_struct *next; struct llist_struct *prev; }; +#endif typedef struct llist_struct llist; typedef llist * LList; typedef const llist * const_LList; typedef llist ** LList_ref; - /** * Macro to instantiate a local llist. * @param name of the llist node @@ -533,11 +535,11 @@ LLIST_FUNC (LList llist_get_nth_stop (LList self, int n, const_LList stop), /** * Sort a list. + * recursive mergesort, needs much extra stackspace (crappy implementation yet) but it reasonable fast * @param self list to be sorted * @param cmp function takeing 2 LLists - * simple recursive mergesort */ -typedef int (*llist_cmpfn)(LList a, LList b); +typedef int (*llist_cmpfn)(const_LList a, const_LList b); LLIST_FUNC (LList llist_sort (LList self, llist_cmpfn cmp), llist left; @@ -564,6 +566,71 @@ LLIST_FUNC (LList llist_sort (LList self, llist_cmpfn cmp), return self; ) + +/** + * Find a element in list. + * searches the list for a element. + * Does not change the list order. + * @param self list to be searched + * @param templ template for the element being searched + * @param cmp function taking 2 LLists + * @return pointer to the found LList element or NULL if nothing foound + */ +LLIST_FUNC (LList llist_find (const_LList self, const_LList templ, llist_cmpfn cmp), + LLIST_FOREACH(self, node) + { + if (!cmp (node, templ)) + return node; + } + return NULL; +) + + +/** + * Find a element in a unsorted list. + * searches the list until it finds the searched element and moves it then to the head. + * Useful if the order of the list is not required and few elements are frequently searched. + * @param self list to be searched + * @param templ template for the element being searched + * @param cmp function taking 2 LLists + * @return pointer to the found LList element (head) or NULL if nothing foound + */ +LLIST_FUNC (LList llist_ufind (LList self, const_LList templ, llist_cmpfn cmp), + LLIST_FOREACH(self, node) + { + if (!cmp (node, templ)) + { + llist_insert_next (self, node); + return node; + } + } + return NULL; +) + + +/** + * Find a element in a sorted list. + * searches the list until it find the searched element, exits searching when found an element + * biggier than the searched one. + * @param self list to be searched + * @param templ template for the element being searched + * @param cmp function takeing 2 LLists + * @return pointer to the found LList element or NULL if nothing foound + */ +LLIST_FUNC (LList llist_sfind (const_LList self, const_LList templ, llist_cmpfn cmp), + LLIST_FOREACH(self, node) + { + int c = cmp (node, templ); + if (!c) + return node; + else if (c>0) + break; + } + return NULL; +) + + + #endif /* LLIST_H */ /* // Local Variables: From f2cb3e47fca27d7ca75edafb6b1791d979792255 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 16 Feb 2009 07:43:36 +0100 Subject: [PATCH 143/216] note some additional lib dependencies (found on Lenny) --- wiki/compatibility.html | 7 ++++++- wiki/index.html | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/wiki/compatibility.html b/wiki/compatibility.html index a014734fe..477edbca6 100644 --- a/wiki/compatibility.html +++ b/wiki/compatibility.html @@ -747,7 +747,7 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS } //}}} -
                  +
                  ! Programming Languages
                   * C
                   ** a C99 compatible compiler, some GCC extensions are used, most are optional.
                  @@ -786,9 +786,14 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS
                   ** libgtkmm-2.4-dev (>=2.8)
                   ** libcairomm-1.0-dev (>=0.6.0)
                   ** libgdl-1-dev (>=0.6.1)
                  +*** libglade2-dev (>=2.6)
                   *** libbonoboui2-dev (>=2.14.0)
                  +*** libxml2-dev (>=2.6)
                   ** libglibmm-2.4-dev (>=2.16), requiring glib2.0 (>=2.16) and gthread-2.0 (>=2.12.4)
                   ** libxv-dev ~~(1.0.2 is known to work)~~
                  +* for rendering the icons: librsvg-2.0 
                  +** librsvg2-dev (>= 2.18)
                  +//usually, newer versions are OK//
                   
                   
                   //usually, newer versions are OK//
                  diff --git a/wiki/index.html b/wiki/index.html
                  index fc7632387..3a9c8b107 100644
                  --- a/wiki/index.html
                  +++ b/wiki/index.html
                  @@ -780,7 +780,7 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS
                   }
                   //}}}
                  -
                  +
                  for __Building__
                   * gcc (4.1), glibc6 (2.3), libstdc++6 (4.1)
                   * [[build system|BuildSystem]] dependencies: SCons (0.96.90), Python (2.4), pkg-config
                  @@ -798,9 +798,13 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS
                   ** libgtkmm-2.4-dev (>=2.8)
                   ** libcairomm-1.0-dev (>=0.6.0)
                   ** libgdl-1-dev (>=0.6.1)
                  +*** libglade2-dev (>=2.6)
                   *** libbonoboui2-dev (>=2.14.0)
                  +*** libxml2-dev (>=2.6)
                   ** libglibmm-2.4-dev (>=2.16), requiring glib2.0 (>=2.16) and gthread-2.0 (>=2.12.4)
                   ** libxv-dev (>=1.0.2)
                  +* for rendering the icons: librsvg-2.0 
                  +** librsvg2-dev (>= 2.18)
                   //usually, newer versions are OK//
                   
                   boost 1.35 works too.
                  
                  From 9d1054f83824a5a0afdd5936aeebfd0dcb9a5445 Mon Sep 17 00:00:00 2001
                  From: Christian Thaeter 
                  Date: Fri, 20 Feb 2009 00:38:21 +0100
                  Subject: [PATCH 144/216] FIX: prototype and call of init_exts_globs was wrong
                  
                  ---
                   src/common/plugin.c | 6 +++---
                   1 file changed, 3 insertions(+), 3 deletions(-)
                  
                  diff --git a/src/common/plugin.c b/src/common/plugin.c
                  index 7329d51b0..1d24f9c5e 100644
                  --- a/src/common/plugin.c
                  +++ b/src/common/plugin.c
                  @@ -44,7 +44,7 @@
                   
                   /* just some declarations */
                   extern PSplay lumiera_pluginregistry;
                  -static char* init_exts_globs ();
                  +static char* init_exts_globs (void);
                   
                   /* TODO default plugin path should be set by the build system */
                   
                  @@ -202,7 +202,7 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin),
                     /* construct glob trail {.so,.c,.foo} ... */
                     static char* exts_globs = NULL;
                     if (!exts_globs)
                  -    exts_globs = init_exts_globs (&exts_globs);
                  +    exts_globs = init_exts_globs ();
                   
                     const char* path;
                     unsigned i = 0;
                  @@ -350,7 +350,7 @@ lumiera_plugin_lookup (const char* name)
                   }
                   
                   
                  -static char* init_exts_globs ()
                  +static char* init_exts_globs (void)
                   {
                     char* exts_globs;
                     size_t exts_sz = 3; /* * { } \0 less one comma */
                  
                  From 7e46bc504f0e4d2429c10719f5b1cb44a38111e0 Mon Sep 17 00:00:00 2001
                  From: Joel Holdsworth 
                  Date: Wed, 4 Feb 2009 18:32:31 +0000
                  Subject: [PATCH 145/216] Removed spurious add_events call
                  
                  ---
                   src/gui/widgets/timeline/timeline-header-widget.cpp | 12 +++++-------
                   1 file changed, 5 insertions(+), 7 deletions(-)
                  
                  diff --git a/src/gui/widgets/timeline/timeline-header-widget.cpp b/src/gui/widgets/timeline/timeline-header-widget.cpp
                  index b71c6c8ad..f51e026cf 100644
                  --- a/src/gui/widgets/timeline/timeline-header-widget.cpp
                  +++ b/src/gui/widgets/timeline/timeline-header-widget.cpp
                  @@ -74,7 +74,11 @@ TimelineHeaderWidget::on_realize()
                     attributes.width = allocation.get_width();
                     attributes.height = allocation.get_height();
                   
                  -  attributes.event_mask = get_events () | Gdk::EXPOSURE_MASK; 
                  +  attributes.event_mask = get_events () |
                  +    Gdk::EXPOSURE_MASK |
                  +    Gdk::POINTER_MOTION_MASK |
                  +    Gdk::BUTTON_PRESS_MASK |
                  +    Gdk::BUTTON_RELEASE_MASK; 
                     attributes.window_type = GDK_WINDOW_CHILD;
                     attributes.wclass = GDK_INPUT_OUTPUT;
                   
                  @@ -89,12 +93,6 @@ TimelineHeaderWidget::on_realize()
                   
                     // 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
                  
                  From 1eec9df89735d39b4496b3dfd7b82988e7a255fb Mon Sep 17 00:00:00 2001
                  From: Joel Holdsworth 
                  Date: Wed, 4 Feb 2009 19:02:08 +0000
                  Subject: [PATCH 146/216] Correction to menu-button.hpp documentation
                  
                  ---
                   src/gui/widgets/menu-button.hpp | 4 ++--
                   1 file changed, 2 insertions(+), 2 deletions(-)
                  
                  diff --git a/src/gui/widgets/menu-button.hpp b/src/gui/widgets/menu-button.hpp
                  index 37a9b0447..4670cb718 100644
                  --- a/src/gui/widgets/menu-button.hpp
                  +++ b/src/gui/widgets/menu-button.hpp
                  @@ -19,8 +19,8 @@
                     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                    
                   */
                  -/** @file timeline-widget.hpp
                  - ** This file contains the definition of timeline widget
                  +/** @file menu-button.hpp
                  + ** This file contains the definition of menu button widget
                    */
                   
                   #ifndef MENU_BUTTON_HPP
                  
                  From b4e4f6c4b7857f399f6052e2daef1a421647bc07 Mon Sep 17 00:00:00 2001
                  From: Joel Holdsworth 
                  Date: Wed, 4 Feb 2009 19:08:51 +0000
                  Subject: [PATCH 147/216] Correction to a comment
                  
                  ---
                   src/gui/widgets/menu-button.cpp | 2 +-
                   1 file changed, 1 insertion(+), 1 deletion(-)
                  
                  diff --git a/src/gui/widgets/menu-button.cpp b/src/gui/widgets/menu-button.cpp
                  index fb58845f7..ea2b50662 100644
                  --- a/src/gui/widgets/menu-button.cpp
                  +++ b/src/gui/widgets/menu-button.cpp
                  @@ -1,5 +1,5 @@
                   /*
                  -  timeline-widget.cpp  -  Implementation of the menu button widget
                  +  menu-button.cpp  -  Implementation of the menu button widget
                    
                     Copyright (C)         Lumiera.org
                       2008,               Joel Holdsworth 
                  
                  From 4a359e0dfeffa85fed42f2f20a2252e3d4dcc906 Mon Sep 17 00:00:00 2001
                  From: Joel Holdsworth 
                  Date: Mon, 9 Mar 2009 22:18:18 +0000
                  Subject: [PATCH 148/216] Correct alignment of 16x16 arrow and i-beam icons
                  
                  ---
                   icons/svg/tool-arrow.svg  | 30 +++++++++++++++++++-----------
                   icons/svg/tool-i-beam.svg | 15 +++++++++++----
                   2 files changed, 30 insertions(+), 15 deletions(-)
                  
                  diff --git a/icons/svg/tool-arrow.svg b/icons/svg/tool-arrow.svg
                  index 84807f4fb..03930ad40 100644
                  --- a/icons/svg/tool-arrow.svg
                  +++ b/icons/svg/tool-arrow.svg
                  @@ -19,6 +19,13 @@
                      inkscape:output_extension="org.inkscape.output.svg.inkscape">
                     
                  +    
                       
                  @@ -185,7 +192,7 @@
                          xlink:href="#linearGradient10554"
                          id="linearGradient7986"
                          gradientUnits="userSpaceOnUse"
                  -       gradientTransform="matrix(0.7041896,0,0,0.7041896,-40.406443,-220.43015)"
                  +       gradientTransform="matrix(0.7041896,0,0,0.7041896,-41.406433,-220.43017)"
                          x1="240.9062"
                          y1="425.18195"
                          x2="248.28683"
                  @@ -195,7 +202,7 @@
                          xlink:href="#linearGradient124"
                          id="radialGradient7989"
                          gradientUnits="userSpaceOnUse"
                  -       gradientTransform="matrix(0.5869533,0,0,0.8448423,-51.871574,-221.82034)"
                  +       gradientTransform="matrix(0.5869533,0,0,0.8448423,-52.871564,-221.82036)"
                          cx="307.7507"
                          cy="361.47824"
                          fx="307.7507"
                  @@ -206,7 +213,7 @@
                          xlink:href="#linearGradient124"
                          id="linearGradient7992"
                          gradientUnits="userSpaceOnUse"
                  -       gradientTransform="matrix(0.559542,1.292457,-0.3231142,0.1398855,-51.871571,-221.82034)"
                  +       gradientTransform="matrix(0.559542,1.292457,-0.3231142,0.1398855,-52.871561,-221.82036)"
                          x1="253.75711"
                          y1="-129.52815"
                          x2="252.00447"
                  @@ -222,9 +229,9 @@
                        objecttolerance="10"
                        inkscape:pageopacity="0.0"
                        inkscape:pageshadow="2"
                  -     inkscape:zoom="5.6568545"
                  -     inkscape:cx="67.786397"
                  -     inkscape:cy="10.056284"
                  +     inkscape:zoom="22.627418"
                  +     inkscape:cx="121.33645"
                  +     inkscape:cy="16.380045"
                        inkscape:document-units="px"
                        inkscape:current-layer="layer3"
                        showgrid="true"
                  @@ -294,22 +301,22 @@
                          sodipodi:nodetypes="ccccc" />