10.12., 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit 03041535 authored by Jakob Weiss's avatar Jakob Weiss

Fullscreen and Thread Names on Windows

* Debug Feature: Thread names for pipelines and some important active threads show in debugger
* fullscreen can be toggled per pipeline via the pipeline property and via ALT+Return key combination
parent 69d7ea4d
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include "core/pipeline/abstractworkflow.h" #include "core/pipeline/abstractworkflow.h"
#include "core/pipeline/pipelinefactory.h" #include "core/pipeline/pipelinefactory.h"
#include "core/pipeline/pipelinepainter.h" #include "core/pipeline/pipelinepainter.h"
#include "core/pipeline/visualizationprocessor.h"
#include "core/datastructures/imagerepresentationconverter.h" #include "core/datastructures/imagerepresentationconverter.h"
#include "core/pipeline/visualizationprocessor.h" #include "core/pipeline/visualizationprocessor.h"
...@@ -275,6 +276,7 @@ namespace campvis { ...@@ -275,6 +276,7 @@ namespace campvis {
#endif #endif
GLCtxtMgr.releaseContext(canvas, false); GLCtxtMgr.releaseContext(canvas, false);
s_PipelinesChanged.emitSignal(); s_PipelinesChanged.emitSignal();
startOpenGlThreadAndMoveQtThreadAffinity(pipeline, canvas); startOpenGlThreadAndMoveQtThreadAffinity(pipeline, canvas);
......
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
#include "mdidockarea.h" #include "mdidockarea.h"
#include <QAction> #include <QAction>
#include <QLayout>
#include <QMainWindow>
#include <cgt/qt/qtcanvas.h>
namespace campvis { namespace campvis {
...@@ -36,6 +39,8 @@ namespace campvis { ...@@ -36,6 +39,8 @@ namespace campvis {
, _dockedWindow(0) , _dockedWindow(0)
, _floatingWindow(0) , _floatingWindow(0)
, _toggleViewAction(0) , _toggleViewAction(0)
, _widget(widget)
, _fullScreenWidget(0)
{ {
this->setWindowFlags(windowFlags); this->setWindowFlags(windowFlags);
_dockedWindow = this->newDockedWindow(widget); _dockedWindow = this->newDockedWindow(widget);
...@@ -44,6 +49,11 @@ namespace campvis { ...@@ -44,6 +49,11 @@ namespace campvis {
_toggleViewAction->setCheckable(true); _toggleViewAction->setCheckable(true);
_toggleViewAction->setChecked(false); _toggleViewAction->setChecked(false);
this->connect(_toggleViewAction, SIGNAL(toggled(bool)), SLOT(toggleWindowVisibility(bool))); this->connect(_toggleViewAction, SIGNAL(toggled(bool)), SLOT(toggleWindowVisibility(bool)));
if (dynamic_cast<cgt::QtCanvas*>(widget)) {
connect(widget, SIGNAL(fullScreenChanged(bool)), this, SLOT(handleFullScreenChanged(bool)));
}
} }
void MdiDockableWindow::setWindowTitle(const QString& title) { void MdiDockableWindow::setWindowTitle(const QString& title) {
...@@ -163,5 +173,32 @@ namespace campvis { ...@@ -163,5 +173,32 @@ namespace campvis {
SLOT(trackFloatingWindowPosition(const QPoint&))); SLOT(trackFloatingWindowPosition(const QPoint&)));
} }
} }
void MdiDockableWindow::handleFullScreenChanged(bool fullscreen) {
if (_docked && _dockedWindow) {
if (fullscreen) {
_fullScreenWidget = new QMainWindow();
_fullScreenWidget->setCentralWidget(_widget);
_fullScreenWidget->showFullScreen();
}
else {
if (_dockedWindow->layout()) {
_dockedWindow->layout()->addWidget(_widget);
}
else {
setParent(_dockedWindow);
}
delete _fullScreenWidget;
_fullScreenWidget = nullptr;
}
}
if (!_docked && _floatingWindow) {
if (fullscreen)
_floatingWindow->showFullScreen();
else
_floatingWindow->showNormal();
}
}
} }
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include "application/gui/qtcolortools.h" #include "application/gui/qtcolortools.h"
#include <QWidget> #include <QWidget>
class QMainWindow;
namespace campvis { namespace campvis {
class MdiDockArea; class MdiDockArea;
...@@ -111,6 +113,11 @@ namespace campvis { ...@@ -111,6 +113,11 @@ namespace campvis {
*/ */
void handleWindowClosing(); void handleWindowClosing();
/**
* Handle changing fullscreen state requested by the QtCanvas widget
*/
void handleFullScreenChanged(bool fullscreen);
private: private:
/** /**
* Create and return an MdiDockedWindow wrapping the \p widget. * Create and return an MdiDockedWindow wrapping the \p widget.
...@@ -124,7 +131,8 @@ namespace campvis { ...@@ -124,7 +131,8 @@ namespace campvis {
MdiDockedWindow* _dockedWindow; ///< The window's docked representation. MdiDockedWindow* _dockedWindow; ///< The window's docked representation.
MdiFloatingWindow* _floatingWindow; ///< The window's floating representation. MdiFloatingWindow* _floatingWindow; ///< The window's floating representation.
QAction* _toggleViewAction; ///< A checkable action that can be used to show or hide this window. QAction* _toggleViewAction; ///< A checkable action that can be used to show or hide this window.
QWidget* _widget; ///< Widget that was wrapped
QMainWindow* _fullScreenWidget; ///< Container widget used to display docked canvas in fullscreen
}; };
} }
......
...@@ -49,6 +49,7 @@ namespace campvis { ...@@ -49,6 +49,7 @@ namespace campvis {
, _canvasSize("CanvasSize", "Canvas Size", cgt::ivec2(128, 128), cgt::ivec2(1, 1), cgt::ivec2(4096, 4096)) , _canvasSize("CanvasSize", "Canvas Size", cgt::ivec2(128, 128), cgt::ivec2(1, 1), cgt::ivec2(4096, 4096))
, _ignoreCanvasSizeUpdate(false) , _ignoreCanvasSizeUpdate(false)
, _renderTargetID("renderTargetID", "Render Target ID", "AbstractPipeline.renderTarget", DataNameProperty::READ) , _renderTargetID("renderTargetID", "Render Target ID", "AbstractPipeline.renderTarget", DataNameProperty::READ)
, p_showFullscreen("ShowFullscreen", "Show Fullscreen", false)
{ {
cgtAssert(_dataContainer != nullptr, "Pointer to the DataContainer for this pipeline must not be 0!"); cgtAssert(_dataContainer != nullptr, "Pointer to the DataContainer for this pipeline must not be 0!");
...@@ -59,12 +60,15 @@ namespace campvis { ...@@ -59,12 +60,15 @@ namespace campvis {
addProperty(_renderTargetID); addProperty(_renderTargetID);
addProperty(_canvasSize); addProperty(_canvasSize);
addProperty(p_showFullscreen);
} }
AbstractPipeline::~AbstractPipeline() { AbstractPipeline::~AbstractPipeline() {
} }
void AbstractPipeline::init() { void AbstractPipeline::init() {
setThreadName(std::string("Pipeline ") + getName());
_dataContainer->s_dataAdded.connect(this, &AbstractPipeline::onDataContainerDataAdded); _dataContainer->s_dataAdded.connect(this, &AbstractPipeline::onDataContainerDataAdded);
_painter->init(); _painter->init();
...@@ -80,6 +84,8 @@ namespace campvis { ...@@ -80,6 +84,8 @@ namespace campvis {
} }
} }
p_showFullscreen.s_changed.connect(this, &AbstractPipeline::onFullscreenChanged);
// use trigger signal to enforce blocking call // use trigger signal to enforce blocking call
s_init.triggerSignal(); s_init.triggerSignal();
} }
...@@ -148,6 +154,13 @@ namespace campvis { ...@@ -148,6 +154,13 @@ namespace campvis {
} }
} }
void AbstractPipeline::onFullscreenChanged(const AbstractProperty * prop)
{
if (_canvas) {
_canvas->toggleFullScreen();
}
}
void AbstractPipeline::paint() { void AbstractPipeline::paint() {
// render nothing. May be overridden in sub classes. // render nothing. May be overridden in sub classes.
} }
......
...@@ -215,6 +215,9 @@ namespace campvis { ...@@ -215,6 +215,9 @@ namespace campvis {
*/ */
IVec2Property& getCanvasSize() { return _canvasSize; } IVec2Property& getCanvasSize() { return _canvasSize; }
/** Property indicating whether this pipeline should display fullscreen */
BoolProperty p_showFullscreen;
/** /**
* Returns this pipelines PipelinePainter. * Returns this pipelines PipelinePainter.
* \return _painter * \return _painter
...@@ -256,11 +259,16 @@ namespace campvis { ...@@ -256,11 +259,16 @@ namespace campvis {
/** /**
* Slot getting called when one of the observed properties changed and notifies its observers. * Slot getting called when one of the observed properties changed and notifies its observers.
* The default behaviour is just to set the invalidation level to invalid. * The default behavior is just to set the invalidation level to invalid.
* \param prop Property that emitted the signal * \param prop Property that emitted the signal
*/ */
virtual void onPropertyChanged(const AbstractProperty* prop); virtual void onPropertyChanged(const AbstractProperty* prop);
/**
* Slot getting called when p_showFullscreen changes. Triggers a switch between fullscreen and non-fullscreen mode
* \param fullscreen Flag indicating whether the pipeline should display fullscreen
*/
virtual void onFullscreenChanged(const AbstractProperty * prop);
/// Pointer to the DataContainer containing local working set of data for this Pipeline, must not be 0. /// Pointer to the DataContainer containing local working set of data for this Pipeline, must not be 0.
DataContainer* _dataContainer; DataContainer* _dataContainer;
......
...@@ -60,6 +60,8 @@ SET(CGT_SOURCES ...@@ -60,6 +60,8 @@ SET(CGT_SOURCES
# Qt related stuff: # Qt related stuff:
IF(CGT_WITH_QT) IF(CGT_WITH_QT)
QT5_WRAP_CPP(qt/qtcanvas.h)
LIST(APPEND CGT_HEADERS LIST(APPEND CGT_HEADERS
qt/qtcanvas.h qt/qtcanvas.h
qt/qtthreadedcanvas.h qt/qtthreadedcanvas.h
...@@ -68,7 +70,8 @@ IF(CGT_WITH_QT) ...@@ -68,7 +70,8 @@ IF(CGT_WITH_QT)
LIST(APPEND CGT_SOURCES LIST(APPEND CGT_SOURCES
qt/qtcanvas.cpp qt/qtcanvas.cpp
qt/qtthreadedcanvas.cpp qt/qtthreadedcanvas.cpp
qt/qttimer.cpp) qt/qttimer.cpp
${CGT_MOC_CPPS})
ENDIF(CGT_WITH_QT) ENDIF(CGT_WITH_QT)
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
namespace cgt { namespace cgt {
OpenGLJobProcessor::OpenGLJobProcessor() OpenGLJobProcessor::OpenGLJobProcessor()
: RunnableWithConditionalWait("OpenGLJobProcessor")
{ {
_pause = 0; _pause = 0;
_context= nullptr; _context= nullptr;
......
...@@ -64,6 +64,7 @@ QtCanvas::QtCanvas(const std::string& title, ...@@ -64,6 +64,7 @@ QtCanvas::QtCanvas(const std::string& title,
stereoViewing_ = format().stereo(); stereoViewing_ = format().stereo();
connect(this, SIGNAL(s_sizeChangedExternally(int, int)), this, SLOT(sizeChangedExternally(int, int))); connect(this, SIGNAL(s_sizeChangedExternally(int, int)), this, SLOT(sizeChangedExternally(int, int)));
connect(this, SIGNAL(fullScreenChanged(bool)), this, SLOT(changeFullScreen(bool)));
} }
QtCanvas::QtCanvas(QWidget* parent, bool shared, Qt::WindowFlags f, char* /*name*/) QtCanvas::QtCanvas(QWidget* parent, bool shared, Qt::WindowFlags f, char* /*name*/)
...@@ -123,12 +124,13 @@ void QtCanvas::swap() { ...@@ -123,12 +124,13 @@ void QtCanvas::swap() {
void QtCanvas::toggleFullScreen() { void QtCanvas::toggleFullScreen() {
if (fullscreen_) { if (fullscreen_) {
fullscreen_ = false; fullscreen_ = false;
showNormal(); //showNormal();
} }
else { else {
showFullScreen(); //showFullScreen();
fullscreen_ = !fullscreen_; fullscreen_ = !fullscreen_;
} }
emit fullScreenChanged(fullscreen_); // emit a Qt signal to process the GUI changes
}; };
/* /*
...@@ -190,8 +192,14 @@ void QtCanvas::wheelEvent(QWheelEvent* e) { ...@@ -190,8 +192,14 @@ void QtCanvas::wheelEvent(QWheelEvent* e) {
// See mousePressEvent // See mousePressEvent
void QtCanvas::keyPressEvent(QKeyEvent* event) { void QtCanvas::keyPressEvent(QKeyEvent* event) {
cgt::KeyEvent* ke = new cgt::KeyEvent(getKey(event->key()), getModifier(event), true); if (event->key() == Qt::Key_Return && event->modifiers() == Qt::Modifier::ALT) {
eventHandler_->broadcastEvent(ke); toggleFullScreen();
event->accept();
}
else {
cgt::KeyEvent* ke = new cgt::KeyEvent(getKey(event->key()), getModifier(event), true);
eventHandler_->broadcastEvent(ke);
}
} }
// See mousePressEvent // See mousePressEvent
...@@ -601,5 +609,4 @@ void QtCanvas::sizeChangedExternally(int w, int h) { ...@@ -601,5 +609,4 @@ void QtCanvas::sizeChangedExternally(int w, int h) {
QWidget::resize(w, h); QWidget::resize(w, h);
} }
} // namespace } // namespace
...@@ -162,6 +162,9 @@ protected: ...@@ -162,6 +162,9 @@ protected:
static QGLWidget* shareWidget_; ///< widget that this canvas shares the OpenGL context with static QGLWidget* shareWidget_; ///< widget that this canvas shares the OpenGL context with
signals:
void fullScreenChanged(bool fullscreen);
}; };
......
...@@ -28,6 +28,17 @@ ...@@ -28,6 +28,17 @@
#include "runnable.h" #include "runnable.h"
#ifdef WIN32
#include <Windows.h>
namespace {
void SetThreadName(HANDLE hThread, const char* threadName);
}
#else // WIN32 -> must be POSIX
#include <pthread.h>
#endif // WIN32
namespace cgt { namespace cgt {
void invokeThread(Runnable* r) { void invokeThread(Runnable* r) {
r->_initFunction(); r->_initFunction();
...@@ -37,9 +48,10 @@ namespace cgt { ...@@ -37,9 +48,10 @@ namespace cgt {
r->_running = false; r->_running = false;
} }
Runnable::Runnable() Runnable::Runnable(const std::string& threadName /*= ""*/)
: _stopExecution() : _stopExecution()
, _thread(0) , _thread(0)
, _threadName(threadName)
{ {
_initFunction = [] () {}; _initFunction = [] () {};
_deinitFunction = [] () {}; _deinitFunction = [] () {};
...@@ -74,12 +86,28 @@ namespace cgt { ...@@ -74,12 +86,28 @@ namespace cgt {
_initFunction = initFunction; _initFunction = initFunction;
_thread = new std::thread(&invokeThread, this); _thread = new std::thread(&invokeThread, this);
_running = true; _running = true;
// set the platform native thread name
if (!_threadName.empty()) {
setThreadName(_threadName);
}
}
void Runnable::setThreadName(const std::string& threadName) {
_threadName = threadName;
if (_running) {
#ifdef WIN32
SetThreadName(HANDLE(_thread->native_handle()), _threadName.c_str());
#else // WIN32 -> must be POSIX
pthread_setname_np(_thread->native_handle(), _threadName.c_str()); // UNTESTED!!
#endif
}
} }
// ================================================================================================ // ================================================================================================
RunnableWithConditionalWait::RunnableWithConditionalWait() RunnableWithConditionalWait::RunnableWithConditionalWait(const std::string& threadName /*= ""*/)
: Runnable() : Runnable(threadName)
{} {}
RunnableWithConditionalWait::~RunnableWithConditionalWait() { RunnableWithConditionalWait::~RunnableWithConditionalWait() {
...@@ -99,3 +127,41 @@ namespace cgt { ...@@ -99,3 +127,41 @@ namespace cgt {
} }
} }
// Platform dependent code for setting the native thread name
#ifdef WIN32
// Code for setting a thread name in Windows / VC from https://msdn.microsoft.com/de-de/library/xcb2z8hs.aspx
namespace {
const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
void SetThreadName(HANDLE hThread, const char* threadName) {
DWORD dwThreadID = GetThreadId(hThread);
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = threadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
#pragma warning(push)
#pragma warning(disable: 6320 6322)
__try {
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
}
#pragma warning(pop)
}
}
#endif //WIN32
...@@ -55,7 +55,7 @@ namespace cgt { ...@@ -55,7 +55,7 @@ namespace cgt {
/** /**
* Creates a new Runnable object * Creates a new Runnable object
*/ */
Runnable(); Runnable(const std::string& threadName = "");
/** /**
* Destructor, stops and waits for the thread to finish if the thread is still running. * Destructor, stops and waits for the thread to finish if the thread is still running.
...@@ -80,10 +80,16 @@ namespace cgt { ...@@ -80,10 +80,16 @@ namespace cgt {
*/ */
virtual void run() = 0; virtual void run() = 0;
/**
* Sets the thread name of the native thread. Useful for debugging
*/
void setThreadName(const std::string& threadName);
protected: protected:
tbb::atomic<bool> _stopExecution; ///< Flag whether the thread should stop tbb::atomic<bool> _stopExecution; ///< Flag whether the thread should stop
std::function<void(void)> _initFunction; ///< Function to execute in the thread as very first code. std::function<void(void)> _initFunction; ///< Function to execute in the thread as very first code.
std::function<void(void)> _deinitFunction; ///< Function to execute in the thread as very last code. std::function<void(void)> _deinitFunction; ///< Function to execute in the thread as very last code.
std::string _threadName; ///< Thread name of the runnable, useful for debugging
private: private:
/// Runnables are not copyable /// Runnables are not copyable
...@@ -109,7 +115,7 @@ namespace cgt { ...@@ -109,7 +115,7 @@ namespace cgt {
/** /**
* Creates a new RunnableWithConditionalWait object * Creates a new RunnableWithConditionalWait object
*/ */
RunnableWithConditionalWait(); RunnableWithConditionalWait(const std::string& threadName = "");
/** /**
* Destructor, stops and waits for thread to finish if the thread is still running. * Destructor, stops and waits for thread to finish if the thread is still running.
......
...@@ -34,7 +34,8 @@ ...@@ -34,7 +34,8 @@
namespace sigslot { namespace sigslot {
signal_manager::signal_manager() signal_manager::signal_manager()
: _handlingMode(DEFAULT) : RunnableWithConditionalWait("sigslot::signal_manager")
, _handlingMode(DEFAULT)
{ {
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment