# HG changeset patch # User Sebastien Jodogne # Date 1493305069 -7200 # Node ID c2dc924f1a6331355535f389125bc4cb463008e6 # Parent 37e504582af6a9d7dbf1e7b7a372c24c2e47f199 removing threading out of the framework diff -r 37e504582af6 -r c2dc924f1a63 Applications/BasicApplicationContext.cpp --- a/Applications/BasicApplicationContext.cpp Thu Apr 27 14:50:40 2017 +0200 +++ b/Applications/BasicApplicationContext.cpp Thu Apr 27 16:57:49 2017 +0200 @@ -27,8 +27,24 @@ namespace OrthancStone { + void BasicApplicationContext::UpdateThread(BasicApplicationContext* that) + { + while (!that->stopped_) + { + { + ViewportLocker locker(*that); + locker.GetViewport().UpdateContent(); + } + + boost::this_thread::sleep(boost::posix_time::milliseconds(that->updateDelay_)); + } + } + + BasicApplicationContext::BasicApplicationContext(OrthancPlugins::IOrthancConnection& orthanc) : - orthanc_(orthanc) + orthanc_(orthanc), + stopped_(true), + updateDelay_(100) // By default, 100ms between each refresh of the content { } @@ -119,11 +135,24 @@ } viewport_.Start(); + + if (viewport_.HasUpdateContent()) + { + stopped_ = false; + updateThread_ = boost::thread(UpdateThread, this); + } } void BasicApplicationContext::Stop() { + stopped_ = true; + + if (updateThread_.joinable()) + { + updateThread_.join(); + } + viewport_.Stop(); for (Volumes::iterator it = volumes_.begin(); it != volumes_.end(); ++it) diff -r 37e504582af6 -r c2dc924f1a63 Applications/BasicApplicationContext.h --- a/Applications/BasicApplicationContext.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Applications/BasicApplicationContext.h Thu Apr 27 16:57:49 2017 +0200 @@ -27,6 +27,7 @@ #include "../../Framework/Toolbox/DicomStructureSet.h" #include +#include namespace OrthancStone { @@ -37,25 +38,46 @@ typedef std::list Interactors; typedef std::list StructureSets; + static void UpdateThread(BasicApplicationContext* that); + OrthancPlugins::IOrthancConnection& orthanc_; + boost::mutex viewportMutex_; WidgetViewport viewport_; Volumes volumes_; Interactors interactors_; StructureSets structureSets_; + boost::thread updateThread_; + bool stopped_; + unsigned int updateDelay_; public: + class ViewportLocker : public boost::noncopyable + { + private: + boost::mutex::scoped_lock lock_; + IViewport& viewport_; + + public: + ViewportLocker(BasicApplicationContext& that) : + lock_(that.viewportMutex_), + viewport_(that.viewport_) + { + } + + IViewport& GetViewport() const + { + return viewport_; + } + }; + + BasicApplicationContext(OrthancPlugins::IOrthancConnection& orthanc); ~BasicApplicationContext(); IWidget& SetCentralWidget(IWidget* widget); // Takes ownership - IViewport& GetViewport() - { - return viewport_; - } - OrthancPlugins::IOrthancConnection& GetOrthancConnection() { return orthanc_; @@ -72,5 +94,10 @@ void Start(); void Stop(); + + void SetUpdateDelay(unsigned int delay) // In milliseconds + { + updateDelay_ = delay; + } }; } diff -r 37e504582af6 -r c2dc924f1a63 Applications/IBasicApplication.cpp --- a/Applications/IBasicApplication.cpp Thu Apr 27 14:50:40 2017 +0200 +++ b/Applications/IBasicApplication.cpp Thu Apr 27 16:57:49 2017 +0200 @@ -214,7 +214,11 @@ BasicApplicationContext context(orthanc); application.Initialize(context, statusBar, parameters); - context.GetViewport().SetStatusBar(statusBar); + + { + BasicApplicationContext::ViewportLocker locker(context); + locker.GetViewport().SetStatusBar(statusBar); + } std::string title = application.GetTitle(); if (title.empty()) @@ -232,7 +236,7 @@ LOG(WARNING) << "Starting the application"; SdlWindow window(title.c_str(), width, height, opengl); - SdlEngine sdl(window, context.GetViewport()); + SdlEngine sdl(window, context); sdl.Run(); @@ -248,7 +252,11 @@ LOG(WARNING) << "The application has stopped"; - context.GetViewport().ResetStatusBar(); + { + BasicApplicationContext::ViewportLocker locker(context); + locker.GetViewport().ResetStatusBar(); + } + application.Finalize(); } catch (Orthanc::OrthancException& e) diff -r 37e504582af6 -r c2dc924f1a63 Applications/Samples/TestPatternApplication.h --- a/Applications/Samples/TestPatternApplication.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Applications/Samples/TestPatternApplication.h Thu Apr 27 16:57:49 2017 +0200 @@ -54,9 +54,10 @@ layout->SetPadding(10); layout->SetBackgroundCleared(true); layout->AddWidget(new TestCairoWidget(parameters["animate"].as())); - layout->AddWidget(new TestWorldSceneWidget); + layout->AddWidget(new TestWorldSceneWidget(parameters["animate"].as())); context.SetCentralWidget(layout.release()); + context.SetUpdateDelay(25); // If animation, update the content each 25ms } }; } diff -r 37e504582af6 -r c2dc924f1a63 Applications/Sdl/SdlEngine.cpp --- a/Applications/Sdl/SdlEngine.cpp Thu Apr 27 14:50:40 2017 +0200 +++ b/Applications/Sdl/SdlEngine.cpp Thu Apr 27 16:57:49 2017 +0200 @@ -38,7 +38,14 @@ viewportChanged_ = false; - if (buffering_.RenderOffscreen(viewport_)) + bool updated; + + { + BasicApplicationContext::ViewportLocker locker(context_); + updated = buffering_.RenderOffscreen(locker.GetViewport()); + } + + if (updated) { // Do not notify twice when a new frame was rendered, to avoid // spoiling the SDL event queue @@ -119,10 +126,11 @@ } - void SdlEngine::SetSize(unsigned int width, + void SdlEngine::SetSize(BasicApplicationContext::ViewportLocker& locker, + unsigned int width, unsigned int height) { - buffering_.SetSize(width, height, viewport_); + buffering_.SetSize(width, height, locker.GetViewport()); viewportChanged_ = true; Refresh(); } @@ -146,16 +154,18 @@ SdlEngine::SdlEngine(SdlWindow& window, - IViewport& viewport) : + BasicApplicationContext& context) : window_(window), - viewport_(viewport), + context_(context), continue_(true) { refreshEvent_ = SDL_RegisterEvents(1); - SetSize(window_.GetWidth(), window_.GetHeight()); - - viewport_.Register(*this); + { + BasicApplicationContext::ViewportLocker locker(context_); + SetSize(locker, window_.GetWidth(), window_.GetHeight()); + locker.GetViewport().Register(*this); + } renderThread_ = boost::thread(RenderThread, this); } @@ -165,7 +175,10 @@ { Stop(); - viewport_.Unregister(*this); + { + BasicApplicationContext::ViewportLocker locker(context_); + locker.GetViewport().Unregister(*this); + } } @@ -183,6 +196,8 @@ while (SDL_PollEvent(&event)) { + BasicApplicationContext::ViewportLocker locker(context_); + if (event.type == SDL_QUIT) { stop = true; @@ -199,15 +214,15 @@ switch (event.button.button) { case SDL_BUTTON_LEFT: - viewport_.MouseDown(MouseButton_Left, event.button.x, event.button.y, modifiers); + locker.GetViewport().MouseDown(MouseButton_Left, event.button.x, event.button.y, modifiers); break; case SDL_BUTTON_RIGHT: - viewport_.MouseDown(MouseButton_Right, event.button.x, event.button.y, modifiers); + locker.GetViewport().MouseDown(MouseButton_Right, event.button.x, event.button.y, modifiers); break; case SDL_BUTTON_MIDDLE: - viewport_.MouseDown(MouseButton_Middle, event.button.x, event.button.y, modifiers); + locker.GetViewport().MouseDown(MouseButton_Middle, event.button.x, event.button.y, modifiers); break; default: @@ -216,26 +231,26 @@ } else if (event.type == SDL_MOUSEMOTION) { - viewport_.MouseMove(event.button.x, event.button.y); + locker.GetViewport().MouseMove(event.button.x, event.button.y); } else if (event.type == SDL_MOUSEBUTTONUP) { - viewport_.MouseUp(); + locker.GetViewport().MouseUp(); } else if (event.type == SDL_WINDOWEVENT) { switch (event.window.event) { case SDL_WINDOWEVENT_LEAVE: - viewport_.MouseLeave(); + locker.GetViewport().MouseLeave(); break; case SDL_WINDOWEVENT_ENTER: - viewport_.MouseEnter(); + locker.GetViewport().MouseEnter(); break; case SDL_WINDOWEVENT_SIZE_CHANGED: - SetSize(event.window.data1, event.window.data2); + SetSize(locker, event.window.data1, event.window.data2); break; default: @@ -251,11 +266,11 @@ if (event.wheel.y > 0) { - viewport_.MouseWheel(MouseWheelDirection_Up, x, y, modifiers); + locker.GetViewport().MouseWheel(MouseWheelDirection_Up, x, y, modifiers); } else if (event.wheel.y < 0) { - viewport_.MouseWheel(MouseWheelDirection_Down, x, y, modifiers); + locker.GetViewport().MouseWheel(MouseWheelDirection_Down, x, y, modifiers); } } else if (event.type == SDL_KEYDOWN) @@ -264,32 +279,32 @@ switch (event.key.keysym.sym) { - case SDLK_a: viewport_.KeyPressed('a', modifiers); break; - case SDLK_b: viewport_.KeyPressed('b', modifiers); break; - case SDLK_c: viewport_.KeyPressed('c', modifiers); break; - case SDLK_d: viewport_.KeyPressed('d', modifiers); break; - case SDLK_e: viewport_.KeyPressed('e', modifiers); break; - case SDLK_f: window_.ToggleMaximize(); break; - case SDLK_g: viewport_.KeyPressed('g', modifiers); break; - case SDLK_h: viewport_.KeyPressed('h', modifiers); break; - case SDLK_i: viewport_.KeyPressed('i', modifiers); break; - case SDLK_j: viewport_.KeyPressed('j', modifiers); break; - case SDLK_k: viewport_.KeyPressed('k', modifiers); break; - case SDLK_l: viewport_.KeyPressed('l', modifiers); break; - case SDLK_m: viewport_.KeyPressed('m', modifiers); break; - case SDLK_n: viewport_.KeyPressed('n', modifiers); break; - case SDLK_o: viewport_.KeyPressed('o', modifiers); break; - case SDLK_p: viewport_.KeyPressed('p', modifiers); break; - case SDLK_q: stop = true; break; - case SDLK_r: viewport_.KeyPressed('r', modifiers); break; - case SDLK_s: viewport_.KeyPressed('s', modifiers); break; - case SDLK_t: viewport_.KeyPressed('t', modifiers); break; - case SDLK_u: viewport_.KeyPressed('u', modifiers); break; - case SDLK_v: viewport_.KeyPressed('v', modifiers); break; - case SDLK_w: viewport_.KeyPressed('w', modifiers); break; - case SDLK_x: viewport_.KeyPressed('x', modifiers); break; - case SDLK_y: viewport_.KeyPressed('y', modifiers); break; - case SDLK_z: viewport_.KeyPressed('z', modifiers); break; + case SDLK_a: locker.GetViewport().KeyPressed('a', modifiers); break; + case SDLK_b: locker.GetViewport().KeyPressed('b', modifiers); break; + case SDLK_c: locker.GetViewport().KeyPressed('c', modifiers); break; + case SDLK_d: locker.GetViewport().KeyPressed('d', modifiers); break; + case SDLK_e: locker.GetViewport().KeyPressed('e', modifiers); break; + case SDLK_f: window_.ToggleMaximize(); break; + case SDLK_g: locker.GetViewport().KeyPressed('g', modifiers); break; + case SDLK_h: locker.GetViewport().KeyPressed('h', modifiers); break; + case SDLK_i: locker.GetViewport().KeyPressed('i', modifiers); break; + case SDLK_j: locker.GetViewport().KeyPressed('j', modifiers); break; + case SDLK_k: locker.GetViewport().KeyPressed('k', modifiers); break; + case SDLK_l: locker.GetViewport().KeyPressed('l', modifiers); break; + case SDLK_m: locker.GetViewport().KeyPressed('m', modifiers); break; + case SDLK_n: locker.GetViewport().KeyPressed('n', modifiers); break; + case SDLK_o: locker.GetViewport().KeyPressed('o', modifiers); break; + case SDLK_p: locker.GetViewport().KeyPressed('p', modifiers); break; + case SDLK_q: stop = true; break; + case SDLK_r: locker.GetViewport().KeyPressed('r', modifiers); break; + case SDLK_s: locker.GetViewport().KeyPressed('s', modifiers); break; + case SDLK_t: locker.GetViewport().KeyPressed('t', modifiers); break; + case SDLK_u: locker.GetViewport().KeyPressed('u', modifiers); break; + case SDLK_v: locker.GetViewport().KeyPressed('v', modifiers); break; + case SDLK_w: locker.GetViewport().KeyPressed('w', modifiers); break; + case SDLK_x: locker.GetViewport().KeyPressed('x', modifiers); break; + case SDLK_y: locker.GetViewport().KeyPressed('y', modifiers); break; + case SDLK_z: locker.GetViewport().KeyPressed('z', modifiers); break; default: break; diff -r 37e504582af6 -r c2dc924f1a63 Applications/Sdl/SdlEngine.h --- a/Applications/Sdl/SdlEngine.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Applications/Sdl/SdlEngine.h Thu Apr 27 16:57:49 2017 +0200 @@ -25,6 +25,7 @@ #include "SdlBuffering.h" #include "../BinarySemaphore.h" +#include "../BasicApplicationContext.h" #include @@ -33,14 +34,14 @@ class SdlEngine : public IViewport::IChangeObserver { private: - SdlWindow& window_; - IViewport& viewport_; - SdlBuffering buffering_; - boost::thread renderThread_; - bool continue_; - BinarySemaphore renderFrame_; - uint32_t refreshEvent_; - bool viewportChanged_; + SdlWindow& window_; + BasicApplicationContext& context_; + SdlBuffering buffering_; + boost::thread renderThread_; + bool continue_; + BinarySemaphore renderFrame_; + uint32_t refreshEvent_; + bool viewportChanged_; void RenderFrame(); @@ -49,7 +50,8 @@ static KeyboardModifiers GetKeyboardModifiers(const uint8_t* keyboardState, const int scancodeCount); - void SetSize(unsigned int width, + void SetSize(BasicApplicationContext::ViewportLocker& locker, + unsigned int width, unsigned int height); void Stop(); @@ -58,7 +60,7 @@ public: SdlEngine(SdlWindow& window, - IViewport& viewport); + BasicApplicationContext& context); virtual ~SdlEngine(); diff -r 37e504582af6 -r c2dc924f1a63 Framework/Layers/ILayerRenderer.h --- a/Framework/Layers/ILayerRenderer.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Layers/ILayerRenderer.h Thu Apr 27 16:57:49 2017 +0200 @@ -22,15 +22,18 @@ #pragma once #include "../Viewport/CairoContext.h" -#include "../Toolbox/IThreadSafety.h" #include "../Toolbox/ViewportGeometry.h" #include "RenderStyle.h" namespace OrthancStone { - class ILayerRenderer : public IThreadUnsafe + class ILayerRenderer : public boost::noncopyable { public: + virtual ~ILayerRenderer() + { + } + virtual bool RenderLayer(CairoContext& context, const ViewportGeometry& view) = 0; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Layers/ILayerRendererFactory.h --- a/Framework/Layers/ILayerRendererFactory.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Layers/ILayerRendererFactory.h Thu Apr 27 16:57:49 2017 +0200 @@ -27,7 +27,7 @@ namespace OrthancStone { - class ILayerRendererFactory : public IThreadUnsafe + class ILayerRendererFactory : public boost::noncopyable { public: virtual ~ILayerRendererFactory() diff -r 37e504582af6 -r c2dc924f1a63 Framework/Layers/SiblingSliceLocationFactory.cpp --- a/Framework/Layers/SiblingSliceLocationFactory.cpp Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Layers/SiblingSliceLocationFactory.cpp Thu Apr 27 16:57:49 2017 +0200 @@ -49,7 +49,6 @@ void SiblingSliceLocationFactory::SetLayerIndex(size_t layerIndex) { - boost::mutex::scoped_lock lock(mutex_); hasLayerIndex_ = true; layerIndex_ = layerIndex; } @@ -57,21 +56,18 @@ void SiblingSliceLocationFactory::SetStyle(const RenderStyle& style) { - boost::mutex::scoped_lock lock(mutex_); style_ = style; } RenderStyle SiblingSliceLocationFactory::GetRenderStyle() { - boost::mutex::scoped_lock lock(mutex_); return style_; } void SiblingSliceLocationFactory::SetSlice(const SliceGeometry& slice) { - boost::mutex::scoped_lock lock(mutex_); slice_ = slice; if (hasLayerIndex_) @@ -84,21 +80,14 @@ ILayerRenderer* SiblingSliceLocationFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice) { Vector p, d; - RenderStyle style; + // Compute the line of intersection between the two slices + if (!GeometryToolbox::IntersectTwoPlanes(p, d, + slice_.GetOrigin(), slice_.GetNormal(), + viewportSlice.GetOrigin(), viewportSlice.GetNormal())) { - boost::mutex::scoped_lock lock(mutex_); - - style = style_; - - // Compute the line of intersection between the two slices - if (!GeometryToolbox::IntersectTwoPlanes(p, d, - slice_.GetOrigin(), slice_.GetNormal(), - viewportSlice.GetOrigin(), viewportSlice.GetNormal())) - { - // The two slice are parallel, don't try and display the intersection - return NULL; - } + // The two slice are parallel, don't try and display the intersection + return NULL; } double x1, y1, x2, y2; @@ -113,7 +102,7 @@ sx1, sy1, sx2, sy2)) { std::auto_ptr layer(new LineLayerRenderer(x1, y1, x2, y2)); - layer->SetLayerStyle(style); + layer->SetLayerStyle(style_); return layer.release(); } else diff -r 37e504582af6 -r c2dc924f1a63 Framework/Layers/SiblingSliceLocationFactory.h --- a/Framework/Layers/SiblingSliceLocationFactory.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Layers/SiblingSliceLocationFactory.h Thu Apr 27 16:57:49 2017 +0200 @@ -30,7 +30,6 @@ public LayeredSceneWidget::ISliceObserver { private: - boost::mutex mutex_; LayeredSceneWidget& owner_; LayeredSceneWidget& sibling_; SliceGeometry slice_; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/DownloadStack.cpp --- a/Framework/Toolbox/DownloadStack.cpp Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Toolbox/DownloadStack.cpp Thu Apr 27 16:57:49 2017 +0200 @@ -99,8 +99,6 @@ bool DownloadStack::Pop(unsigned int& value) { - boost::mutex::scoped_lock lock(mutex_); - assert(CheckInvariants()); if (firstNode_ == NIL) diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/DownloadStack.h --- a/Framework/Toolbox/DownloadStack.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Toolbox/DownloadStack.h Thu Apr 27 16:57:49 2017 +0200 @@ -23,7 +23,8 @@ #include #include -#include + +#include // TODO remove namespace OrthancStone { @@ -40,7 +41,6 @@ bool dequeued_; }; - boost::mutex mutex_; std::vector nodes_; int firstNode_; @@ -63,8 +63,8 @@ public: Writer(DownloadStack& that) : - that_(that), - lock_(that.mutex_) + that_(that) + //lock_(that.mutex_) { } diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/ISeriesLoader.h --- a/Framework/Toolbox/ISeriesLoader.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Toolbox/ISeriesLoader.h Thu Apr 27 16:57:49 2017 +0200 @@ -23,16 +23,18 @@ #include "ParallelSlices.h" -#include "IThreadSafety.h" #include "../../Resources/Orthanc/Core/Images/ImageAccessor.h" #include "../../Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h" namespace OrthancStone { - // This class is NOT thread-safe - class ISeriesLoader : public IThreadUnsafe + class ISeriesLoader : public boost::noncopyable { public: + virtual ~ISeriesLoader() + { + } + virtual ParallelSlices& GetGeometry() = 0; virtual Orthanc::PixelFormat GetPixelFormat() = 0; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/IThreadSafety.h --- a/Framework/Toolbox/IThreadSafety.h Thu Apr 27 14:50:40 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 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 - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include - -namespace OrthancStone -{ - /** - * Dummy interface to explicitely tag the interfaces whose derived - * class must be thread-safe. The different methods of such classes - * might be simlultaneously invoked by several threads, and should - * be properly protected by mutexes. - **/ - class IThreadSafe : public boost::noncopyable - { - public: - virtual ~IThreadSafe() - { - } - }; - - - /** - * Dummy interface to explicitely tag the interfaces that are NOT - * expected to be thread-safe. The Orthanc Stone framework ensures - * that at most one method of such classes will be invoked at a - * given time. Such classes are automatically protected by the - * Orthanc Stone framework wherever required. - **/ - class IThreadUnsafe : public boost::noncopyable - { - public: - virtual ~IThreadUnsafe() - { - } - }; -} diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/ObserversRegistry.h --- a/Framework/Toolbox/ObserversRegistry.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Toolbox/ObserversRegistry.h Thu Apr 27 16:57:49 2017 +0200 @@ -24,7 +24,6 @@ #include "../../Resources/Orthanc/Core/OrthancException.h" #include -#include #include namespace OrthancStone @@ -47,32 +46,18 @@ typedef std::set Observers; - boost::mutex mutex_; - Observers observers_; - bool empty_; + Observers observers_; public: - ObserversRegistry() : empty_(true) - { - } - template void Notify(const Source* source, Functor& functor) { - if (empty_) - { - // Optimization to avoid the unnecessary locking of the mutex - return; - } - if (source == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - boost::mutex::scoped_lock lock(mutex_); - for (typename Observers::const_iterator observer = observers_.begin(); observer != observers_.end(); ++observer) { @@ -95,31 +80,17 @@ void Register(Observer& observer) { - empty_ = false; - - boost::mutex::scoped_lock lock(mutex_); observers_.insert(&observer); } void Unregister(Observer& observer) { - boost::mutex::scoped_lock lock(mutex_); observers_.erase(&observer); - - if (observers_.empty()) - { - empty_ = true; - } } bool IsEmpty() { -#if 0 - boost::mutex::scoped_lock lock(mutex_); return observers_.empty(); -#else - return empty_; -#endif } }; } diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/OrthancSeriesLoader.h --- a/Framework/Toolbox/OrthancSeriesLoader.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Toolbox/OrthancSeriesLoader.h Thu Apr 27 16:57:49 2017 +0200 @@ -28,10 +28,9 @@ namespace OrthancStone { - // This class is NOT thread-safe - // It sorts the slices from a given series, give access to their - // geometry and individual frames, making the assumption that there - // is a single frame in each instance of the series + // This class sorts the slices from a given series, give access to + // their geometry and individual frames, making the assumption that + // there is a single frame in each instance of the series class OrthancSeriesLoader : public ISeriesLoader { private: diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/ParallelSlices.h --- a/Framework/Toolbox/ParallelSlices.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Toolbox/ParallelSlices.h Thu Apr 27 16:57:49 2017 +0200 @@ -25,8 +25,7 @@ namespace OrthancStone { - // This class is NOT thread-safe - class ParallelSlices + class ParallelSlices : public boost::noncopyable { private: Vector normal_; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/ParallelSlicesCursor.cpp --- a/Framework/Toolbox/ParallelSlicesCursor.cpp Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Toolbox/ParallelSlicesCursor.cpp Thu Apr 27 16:57:49 2017 +0200 @@ -40,8 +40,6 @@ size_t ParallelSlicesCursor::GetSliceCount() { - boost::mutex::scoped_lock lock(mutex_); - if (slices_.get() == NULL) { return 0; @@ -55,8 +53,6 @@ SliceGeometry ParallelSlicesCursor::GetSlice(size_t slice) { - boost::mutex::scoped_lock lock(mutex_); - if (slices_.get() == NULL) { return SliceGeometry(); @@ -70,8 +66,6 @@ void ParallelSlicesCursor::SetGeometry(const ParallelSlices& slices) { - boost::mutex::scoped_lock lock(mutex_); - slices_.reset(new ParallelSlices(slices)); currentSlice_ = GetDefaultSlice(); @@ -80,8 +74,6 @@ SliceGeometry ParallelSlicesCursor::GetCurrentSlice() { - boost::mutex::scoped_lock lock(mutex_); - if (slices_.get() != NULL && currentSlice_ < slices_->GetSliceCount()) { @@ -96,8 +88,6 @@ bool ParallelSlicesCursor::SetDefaultSlice() { - boost::mutex::scoped_lock lock(mutex_); - size_t slice = GetDefaultSlice(); if (currentSlice_ != slice) @@ -115,8 +105,6 @@ bool ParallelSlicesCursor::ApplyOffset(SliceOffsetMode mode, int offset) { - boost::mutex::scoped_lock lock(mutex_); - if (slices_.get() == NULL) { return false; @@ -215,8 +203,6 @@ bool ParallelSlicesCursor::LookupSliceContainingPoint(const Vector& p) { - boost::mutex::scoped_lock lock(mutex_); - size_t slice; double distance; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/ParallelSlicesCursor.h --- a/Framework/Toolbox/ParallelSlicesCursor.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Toolbox/ParallelSlicesCursor.h Thu Apr 27 16:57:49 2017 +0200 @@ -24,15 +24,11 @@ #include "ParallelSlices.h" #include "../Enumerations.h" -#include - namespace OrthancStone { - // This class is thread-safe class ParallelSlicesCursor : public boost::noncopyable { private: - boost::mutex mutex_; std::auto_ptr slices_; size_t currentSlice_; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/SharedValue.h --- a/Framework/Toolbox/SharedValue.h Thu Apr 27 14:50:40 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 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 - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include - -namespace OrthancStone -{ - // A value that is protected by a mutex, in order to be shared by - // multiple threads - template - class SharedValue : public boost::noncopyable - { - private: - boost::mutex mutex_; - T value_; - - public: - class Locker : public boost::noncopyable - { - private: - boost::mutex::scoped_lock lock_; - T& value_; - - public: - Locker(SharedValue& shared) : - lock_(shared.mutex_), - value_(shared.value_) - { - } - - T& GetValue() const - { - return value_; - } - }; - }; -} diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/SliceGeometry.h --- a/Framework/Toolbox/SliceGeometry.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Toolbox/SliceGeometry.h Thu Apr 27 16:57:49 2017 +0200 @@ -26,7 +26,7 @@ namespace OrthancStone { - // Geometry of a 3D plane, NOT thread-safe + // Geometry of a 3D plane class SliceGeometry { private: diff -r 37e504582af6 -r c2dc924f1a63 Framework/Toolbox/ViewportGeometry.h --- a/Framework/Toolbox/ViewportGeometry.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Toolbox/ViewportGeometry.h Thu Apr 27 16:57:49 2017 +0200 @@ -25,7 +25,6 @@ namespace OrthancStone { - // Not thread-safe class ViewportGeometry { private: diff -r 37e504582af6 -r c2dc924f1a63 Framework/Viewport/IMouseTracker.h --- a/Framework/Viewport/IMouseTracker.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Viewport/IMouseTracker.h Thu Apr 27 16:57:49 2017 +0200 @@ -22,14 +22,16 @@ #pragma once #include "CairoSurface.h" -#include "../Toolbox/IThreadSafety.h" namespace OrthancStone { - // Not thread-safe - class IMouseTracker : public IThreadUnsafe + class IMouseTracker : public boost::noncopyable { public: + virtual ~IMouseTracker() + { + } + virtual void Render(Orthanc::ImageAccessor& surface) = 0; virtual void MouseUp() = 0; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Viewport/IStatusBar.h --- a/Framework/Viewport/IStatusBar.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Viewport/IStatusBar.h Thu Apr 27 16:57:49 2017 +0200 @@ -22,14 +22,17 @@ #pragma once #include -#include "../Toolbox/IThreadSafety.h" +#include namespace OrthancStone { - // This class must be thread-safe - class IStatusBar : public IThreadSafe + class IStatusBar : public boost::noncopyable { public: + virtual ~IStatusBar() + { + } + virtual void ClearMessage() = 0; virtual void SetMessage(const std::string& message) = 0; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Viewport/IViewport.h --- a/Framework/Viewport/IViewport.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Viewport/IViewport.h Thu Apr 27 16:57:49 2017 +0200 @@ -21,7 +21,6 @@ #pragma once -#include "../Toolbox/IThreadSafety.h" #include "IStatusBar.h" #include "../Enumerations.h" @@ -29,8 +28,7 @@ namespace OrthancStone { - // This class must be thread-safe - class IViewport : public IThreadSafe + class IViewport : public boost::noncopyable { public: class IChangeObserver : public boost::noncopyable @@ -43,6 +41,10 @@ virtual void NotifyChange(const IViewport& scene) = 0; }; + virtual ~IViewport() + { + } + virtual void Register(IChangeObserver& observer) = 0; virtual void Unregister(IChangeObserver& observer) = 0; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Viewport/WidgetViewport.cpp --- a/Framework/Viewport/WidgetViewport.cpp Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Viewport/WidgetViewport.cpp Thu Apr 27 16:57:49 2017 +0200 @@ -50,8 +50,6 @@ void WidgetViewport::SetStatusBar(IStatusBar& statusBar) { - boost::mutex::scoped_lock lock(mutex_); - statusBar_ = &statusBar; if (centralWidget_.get() != NULL) @@ -63,8 +61,6 @@ void WidgetViewport::ResetStatusBar() { - boost::mutex::scoped_lock lock(mutex_); - statusBar_ = NULL; if (centralWidget_.get() != NULL) @@ -81,8 +77,6 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } - boost::mutex::scoped_lock lock(mutex_); - if (widget == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); @@ -117,8 +111,6 @@ void WidgetViewport::Start() { - boost::mutex::scoped_lock lock(mutex_); - if (centralWidget_.get() != NULL) { centralWidget_->Start(); @@ -130,8 +122,6 @@ void WidgetViewport::Stop() { - boost::mutex::scoped_lock lock(mutex_); - started_ = false; if (centralWidget_.get() != NULL) @@ -144,8 +134,6 @@ void WidgetViewport::SetSize(unsigned int width, unsigned int height) { - boost::mutex::scoped_lock lock(mutex_); - background_.SetSize(width, height); if (centralWidget_.get() != NULL) @@ -159,8 +147,6 @@ bool WidgetViewport::Render(Orthanc::ImageAccessor& surface) { - boost::mutex::scoped_lock lock(mutex_); - if (!started_ || centralWidget_.get() == NULL) { @@ -201,8 +187,6 @@ int y, KeyboardModifiers modifiers) { - boost::mutex::scoped_lock lock(mutex_); - if (!started_) { return; @@ -226,8 +210,6 @@ void WidgetViewport::MouseUp() { - boost::mutex::scoped_lock lock(mutex_); - if (!started_) { return; @@ -245,8 +227,6 @@ void WidgetViewport::MouseMove(int x, int y) { - boost::mutex::scoped_lock lock(mutex_); - if (!started_) { return; @@ -267,7 +247,6 @@ void WidgetViewport::MouseEnter() { - boost::mutex::scoped_lock lock(mutex_); isMouseOver_ = true; observers_.NotifyChange(this); } @@ -275,7 +254,6 @@ void WidgetViewport::MouseLeave() { - boost::mutex::scoped_lock lock(mutex_); isMouseOver_ = false; if (started_ && @@ -294,8 +272,6 @@ int y, KeyboardModifiers modifiers) { - boost::mutex::scoped_lock lock(mutex_); - if (!started_) { return; @@ -312,8 +288,6 @@ void WidgetViewport::KeyPressed(char key, KeyboardModifiers modifiers) { - boost::mutex::scoped_lock lock(mutex_); - if (centralWidget_.get() != NULL && mouseTracker_.get() == NULL) { @@ -324,8 +298,6 @@ bool WidgetViewport::HasUpdateContent() { - boost::mutex::scoped_lock lock(mutex_); - if (centralWidget_.get() != NULL) { return centralWidget_->HasUpdateContent(); @@ -339,8 +311,6 @@ void WidgetViewport::UpdateContent() { - boost::mutex::scoped_lock lock(mutex_); - if (centralWidget_.get() != NULL) { centralWidget_->UpdateContent(); diff -r 37e504582af6 -r c2dc924f1a63 Framework/Viewport/WidgetViewport.h --- a/Framework/Viewport/WidgetViewport.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Viewport/WidgetViewport.h Thu Apr 27 16:57:49 2017 +0200 @@ -25,6 +25,8 @@ #include "../Toolbox/ObserversRegistry.h" #include "../Widgets/IWidget.h" +#include + namespace OrthancStone { class WidgetViewport : @@ -32,7 +34,6 @@ public IWidget::IChangeObserver { private: - boost::mutex mutex_; std::auto_ptr centralWidget_; IStatusBar* statusBar_; ObserversRegistry observers_; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Volumes/ISliceableVolume.h --- a/Framework/Volumes/ISliceableVolume.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Volumes/ISliceableVolume.h Thu Apr 27 16:57:49 2017 +0200 @@ -21,14 +21,13 @@ #pragma once -#include "../Toolbox/IThreadSafety.h" +#include namespace OrthancStone { - class ISliceableVolume : public IThreadSafe + class ISliceableVolume : public boost::noncopyable { public: - // Must be thread-safe class IChangeObserver : public boost::noncopyable { public: @@ -39,6 +38,10 @@ virtual void NotifyChange(const ISliceableVolume& volume) = 0; }; + virtual ~ISliceableVolume() + { + } + virtual void Register(IChangeObserver& observer) = 0; virtual void Unregister(IChangeObserver& observer) = 0; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Volumes/ImageBuffer3D.h --- a/Framework/Volumes/ImageBuffer3D.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Volumes/ImageBuffer3D.h Thu Apr 27 16:57:49 2017 +0200 @@ -22,7 +22,6 @@ #pragma once #include "../Enumerations.h" -#include "../Toolbox/IThreadSafety.h" #include "../Toolbox/SliceGeometry.h" #include "../Toolbox/ParallelSlices.h" @@ -36,7 +35,7 @@ namespace OrthancStone { - class ImageBuffer3D : public IThreadSafe + class ImageBuffer3D : public boost::noncopyable { private: typedef boost::shared_mutex Mutex; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Volumes/VolumeImage.h --- a/Framework/Volumes/VolumeImage.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Volumes/VolumeImage.h Thu Apr 27 16:57:49 2017 +0200 @@ -35,9 +35,13 @@ class VolumeImage : public ISliceableVolume { public: - class IDownloadPolicy : public IThreadSafe + class IDownloadPolicy : public boost::noncopyable { public: + virtual ~IDownloadPolicy() + { + } + virtual void Initialize(ImageBuffer3D& buffer, ISeriesLoader& loader) = 0; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Widgets/EmptyWidget.cpp --- a/Framework/Widgets/EmptyWidget.cpp Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Widgets/EmptyWidget.cpp Thu Apr 27 16:57:49 2017 +0200 @@ -22,6 +22,7 @@ #include "EmptyWidget.h" #include "../../Resources/Orthanc/Core/Images/ImageProcessing.h" +#include "../../Resources/Orthanc/Core/OrthancException.h" namespace OrthancStone { diff -r 37e504582af6 -r c2dc924f1a63 Framework/Widgets/IWidget.h --- a/Framework/Widgets/IWidget.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Widgets/IWidget.h Thu Apr 27 16:57:49 2017 +0200 @@ -27,7 +27,7 @@ namespace OrthancStone { - class IWidget : public IThreadUnsafe + class IWidget : public boost::noncopyable { public: class IChangeObserver : public boost::noncopyable @@ -40,6 +40,10 @@ virtual void NotifyChange(const IWidget& widget) = 0; }; + virtual ~IWidget() + { + } + virtual void SetStatusBar(IStatusBar& statusBar) = 0; virtual void ResetStatusBar() = 0; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Widgets/IWorldSceneInteractor.h --- a/Framework/Widgets/IWorldSceneInteractor.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Widgets/IWorldSceneInteractor.h Thu Apr 27 16:57:49 2017 +0200 @@ -32,9 +32,13 @@ { class WorldSceneWidget; - class IWorldSceneInteractor : public IThreadSafe + class IWorldSceneInteractor : public boost::noncopyable { public: + virtual ~IWorldSceneInteractor() + { + } + virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, const SliceGeometry& slice, const ViewportGeometry& view, diff -r 37e504582af6 -r c2dc924f1a63 Framework/Widgets/IWorldSceneMouseTracker.h --- a/Framework/Widgets/IWorldSceneMouseTracker.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Widgets/IWorldSceneMouseTracker.h Thu Apr 27 16:57:49 2017 +0200 @@ -21,14 +21,17 @@ #pragma once -#include "../Toolbox/IThreadSafety.h" #include "../Viewport/CairoContext.h" namespace OrthancStone { - class IWorldSceneMouseTracker : public IThreadUnsafe + class IWorldSceneMouseTracker : public boost::noncopyable { public: + virtual ~IWorldSceneMouseTracker() + { + } + virtual void Render(CairoContext& context, double zoom) = 0; diff -r 37e504582af6 -r c2dc924f1a63 Framework/Widgets/LayeredSceneWidget.cpp --- a/Framework/Widgets/LayeredSceneWidget.cpp Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Widgets/LayeredSceneWidget.cpp Thu Apr 27 16:57:49 2017 +0200 @@ -26,6 +26,8 @@ #include "../../Resources/Orthanc/Core/OrthancException.h" +#include // TODO Remove + namespace OrthancStone { class LayeredSceneWidget::Renderers : public boost::noncopyable diff -r 37e504582af6 -r c2dc924f1a63 Framework/Widgets/LayeredSceneWidget.h --- a/Framework/Widgets/LayeredSceneWidget.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Widgets/LayeredSceneWidget.h Thu Apr 27 16:57:49 2017 +0200 @@ -25,13 +25,13 @@ #include "../Layers/ILayerRendererFactory.h" +#include // TODO remove namespace OrthancStone { class LayeredSceneWidget : public WorldSceneWidget { public: - // Must be thread-safe class ISliceObserver : public boost::noncopyable { public: diff -r 37e504582af6 -r c2dc924f1a63 Framework/Widgets/LayoutWidget.cpp --- a/Framework/Widgets/LayoutWidget.cpp Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Widgets/LayoutWidget.cpp Thu Apr 27 16:57:49 2017 +0200 @@ -82,15 +82,25 @@ int top_; unsigned int width_; unsigned int height_; + bool hasUpdate_; public: ChildWidget(IWidget* widget) : - widget_(widget) + widget_(widget), + hasUpdate_(widget->HasUpdateContent()) { assert(widget != NULL); SetEmpty(); } + void UpdateContent() + { + if (hasUpdate_) + { + widget_->UpdateContent(); + } + } + IWidget& GetWidget() const { return *widget_; @@ -348,6 +358,11 @@ ComputeChildrenExtents(); + if (widget->HasUpdateContent()) + { + hasUpdateContent_ = true; + } + return *widget; } @@ -473,4 +488,20 @@ children_[i]->GetWidget().KeyPressed(key, modifiers); } } + + + void LayoutWidget::UpdateContent() + { + if (hasUpdateContent_) + { + for (size_t i = 0; i < children_.size(); i++) + { + children_[i]->UpdateContent(); + } + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } } diff -r 37e504582af6 -r c2dc924f1a63 Framework/Widgets/LayoutWidget.h --- a/Framework/Widgets/LayoutWidget.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Widgets/LayoutWidget.h Thu Apr 27 16:57:49 2017 +0200 @@ -23,6 +23,8 @@ #include "WidgetBase.h" +#include +#include namespace OrthancStone { @@ -45,6 +47,7 @@ unsigned int paddingRight_; unsigned int paddingBottom_; unsigned int paddingInternal_; + bool hasUpdateContent_; void ComputeChildrenExtents(); @@ -123,5 +126,12 @@ virtual void KeyPressed(char key, KeyboardModifiers modifiers); + + virtual bool HasUpdateContent() const + { + return hasUpdateContent_; + } + + virtual void UpdateContent(); }; } diff -r 37e504582af6 -r c2dc924f1a63 Framework/Widgets/WorldSceneWidget.cpp --- a/Framework/Widgets/WorldSceneWidget.cpp Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Widgets/WorldSceneWidget.cpp Thu Apr 27 16:57:49 2017 +0200 @@ -129,8 +129,7 @@ downX_(x), downY_(y) { - SharedValue::Locker locker(that_.view_); - locker.GetValue().GetPan(previousPanX_, previousPanY_); + that_.view_.GetPan(previousPanX_, previousPanY_); } virtual void Render(Orthanc::ImageAccessor& surface) @@ -144,11 +143,10 @@ virtual void MouseMove(int x, int y) { - SharedValue::Locker locker(that_.view_); - locker.GetValue().SetPan(previousPanX_ + x - downX_, - previousPanY_ + y - downY_); + that_.view_.SetPan(previousPanX_ + x - downX_, + previousPanY_ + y - downY_); - ViewChangeFunctor functor(locker.GetValue()); + ViewChangeFunctor functor(that_.view_); that_.observers_.Notify(&that_, functor); } }; @@ -172,9 +170,8 @@ downX_(x), downY_(y) { - SharedValue::Locker locker(that_.view_); - oldZoom_ = locker.GetValue().GetZoom(); - MapMouseToScene(centerX_, centerY_, locker.GetValue(), downX_, downY_); + oldZoom_ = that_.view_.GetZoom(); + MapMouseToScene(centerX_, centerY_, that_.view_, downX_, downY_); } virtual void Render(Orthanc::ImageAccessor& surface) @@ -191,15 +188,13 @@ static const double MIN_ZOOM = -4; static const double MAX_ZOOM = 4; - SharedValue::Locker locker(that_.view_); - - if (locker.GetValue().GetDisplayHeight() <= 3) + if (that_.view_.GetDisplayHeight() <= 3) { return; // Cannot zoom on such a small image } double dy = (static_cast(y - downY_) / - static_cast(locker.GetValue().GetDisplayHeight() - 1)); // In the range [-1,1] + static_cast(that_.view_.GetDisplayHeight() - 1)); // In the range [-1,1] double z; // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM] @@ -218,19 +213,19 @@ z = pow(2.0, z); - locker.GetValue().SetZoom(oldZoom_ * z); + that_.view_.SetZoom(oldZoom_ * z); // Correct the pan so that the original click point is kept at // the same location on the display double panX, panY; - locker.GetValue().GetPan(panX, panY); + that_.view_.GetPan(panX, panY); int tx, ty; - locker.GetValue().MapSceneToDisplay(tx, ty, centerX_, centerY_); - locker.GetValue().SetPan(panX + static_cast(downX_ - tx), + that_.view_.MapSceneToDisplay(tx, ty, centerX_, centerY_); + that_.view_.SetPan(panX + static_cast(downX_ - tx), panY + static_cast(downY_ - ty)); - ViewChangeFunctor functor(locker.GetValue()); + ViewChangeFunctor functor(that_.view_); that_.observers_.Notify(&that_, functor); } }; @@ -238,16 +233,8 @@ bool WorldSceneWidget::RenderCairo(CairoContext& context) { - ViewportGeometry view; - - { - SharedValue::Locker locker(view_); - view = locker.GetValue(); - } - - view.ApplyTransform(context); - - return RenderScene(context, view); + view_.ApplyTransform(context); + return RenderScene(context, view_); } @@ -264,11 +251,11 @@ } - void WorldSceneWidget::SetSceneExtent(SharedValue::Locker& locker) + void WorldSceneWidget::SetSceneExtent(ViewportGeometry& view) { double x1, y1, x2, y2; GetSceneExtent(x1, y1, x2, y2); - locker.GetValue().SetSceneExtent(x1, y1, x2, y2); + view.SetSceneExtent(x1, y1, x2, y2); } @@ -277,21 +264,18 @@ { CairoWidget::SetSize(width, height); - { - SharedValue::Locker locker(view_); - locker.GetValue().SetDisplaySize(width, height); + view_.SetDisplaySize(width, height); - if (observers_.IsEmpty()) - { - // Without a size observer, use the default view - locker.GetValue().SetDefaultView(); - } - else - { - // With a size observer, let it decide which view to use - SizeChangeFunctor functor(locker.GetValue()); - observers_.Notify(this, functor); - } + if (observers_.IsEmpty()) + { + // Without a size observer, use the default view + view_.SetDefaultView(); + } + else + { + // With a size observer, let it decide which view to use + SizeChangeFunctor functor(view_); + observers_.Notify(this, functor); } } @@ -309,57 +293,41 @@ void WorldSceneWidget::Start() { - ViewportGeometry geometry; - - { - SharedValue::Locker locker(view_); - SetSceneExtent(locker); - geometry = locker.GetValue(); - } - + SetSceneExtent(view_); + WidgetBase::Start(); - ViewChangeFunctor functor(geometry); + ViewChangeFunctor functor(view_); observers_.Notify(this, functor); } void WorldSceneWidget::SetDefaultView() { - ViewportGeometry geometry; - - { - SharedValue::Locker locker(view_); - SetSceneExtent(locker); - locker.GetValue().SetDefaultView(); - geometry = locker.GetValue(); - } + SetSceneExtent(view_); + view_.SetDefaultView(); NotifyChange(); - ViewChangeFunctor functor(geometry); + ViewChangeFunctor functor(view_); observers_.Notify(this, functor); } void WorldSceneWidget::SetView(const ViewportGeometry& view) { - { - SharedValue::Locker locker(view_); - locker.GetValue() = view; - } + view_ = view; NotifyChange(); - ViewChangeFunctor functor(view); + ViewChangeFunctor functor(view_); observers_.Notify(this, functor); } ViewportGeometry WorldSceneWidget::GetView() { - SharedValue::Locker locker(view_); - return locker.GetValue(); + return view_; } @@ -368,15 +336,15 @@ int y, KeyboardModifiers modifiers) { - ViewportGeometry view = GetView(); + double sceneX, sceneY; + MapMouseToScene(sceneX, sceneY, view_, x, y); - double sceneX, sceneY; - MapMouseToScene(sceneX, sceneY, view, x, y); + std::auto_ptr tracker + (CreateMouseSceneTracker(view_, button, sceneX, sceneY, modifiers)); - std::auto_ptr tracker(CreateMouseSceneTracker(view, button, sceneX, sceneY, modifiers)); if (tracker.get() != NULL) { - return new SceneMouseTracker(view, tracker.release()); + return new SceneMouseTracker(view_, tracker.release()); } switch (button) diff -r 37e504582af6 -r c2dc924f1a63 Framework/Widgets/WorldSceneWidget.h --- a/Framework/Widgets/WorldSceneWidget.h Thu Apr 27 14:50:40 2017 +0200 +++ b/Framework/Widgets/WorldSceneWidget.h Thu Apr 27 16:57:49 2017 +0200 @@ -24,7 +24,6 @@ #include "CairoWidget.h" #include "IWorldSceneInteractor.h" -#include "../Toolbox/SharedValue.h" #include "../Toolbox/ViewportGeometry.h" namespace OrthancStone @@ -32,7 +31,6 @@ class WorldSceneWidget : public CairoWidget { public: - // Must be thread-safe class IWorldObserver : public boost::noncopyable { public: @@ -57,9 +55,9 @@ typedef ObserversRegistry Observers; - SharedValue view_; - Observers observers_; - IWorldSceneInteractor* interactor_; + ViewportGeometry view_; + Observers observers_; + IWorldSceneInteractor* interactor_; protected: @@ -72,7 +70,7 @@ int x, int y); - void SetSceneExtent(SharedValue::Locker& locker); + void SetSceneExtent(ViewportGeometry& geometry); public: WorldSceneWidget() : diff -r 37e504582af6 -r c2dc924f1a63 Resources/Graveyard/Threading/IThreadSafety.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/Threading/IThreadSafety.h Thu Apr 27 16:57:49 2017 +0200 @@ -0,0 +1,57 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 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 + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include + +namespace OrthancStone +{ + /** + * Dummy interface to explicitely tag the interfaces whose derived + * class must be thread-safe. The different methods of such classes + * might be simlultaneously invoked by several threads, and should + * be properly protected by mutexes. + **/ + class IThreadSafe : public boost::noncopyable + { + public: + virtual ~IThreadSafe() + { + } + }; + + + /** + * Dummy interface to explicitely tag the interfaces that are NOT + * expected to be thread-safe. The Orthanc Stone framework ensures + * that at most one method of such classes will be invoked at a + * given time. Such classes are automatically protected by the + * Orthanc Stone framework wherever required. + **/ + class IThreadUnsafe : public boost::noncopyable + { + public: + virtual ~IThreadUnsafe() + { + } + }; +} diff -r 37e504582af6 -r c2dc924f1a63 Resources/Graveyard/Threading/SharedValue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/Threading/SharedValue.h Thu Apr 27 16:57:49 2017 +0200 @@ -0,0 +1,58 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 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 + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include +#include + +namespace OrthancStone +{ + // A value that is protected by a mutex, in order to be shared by + // multiple threads + template + class SharedValue : public boost::noncopyable + { + private: + boost::mutex mutex_; + T value_; + + public: + class Locker : public boost::noncopyable + { + private: + boost::mutex::scoped_lock lock_; + T& value_; + + public: + Locker(SharedValue& shared) : + lock_(shared.mutex_), + value_(shared.value_) + { + } + + T& GetValue() const + { + return value_; + } + }; + }; +}