diff --git a/cmake/compiler_gnu_gcc.cmake b/cmake/compiler_gnu_gcc.cmake index 20d614cb..a604d3af 100644 --- a/cmake/compiler_gnu_gcc.cmake +++ b/cmake/compiler_gnu_gcc.cmake @@ -12,6 +12,9 @@ else() if(C0XFLAG) message(STATUS "Using -std=c++0x") add_definitions(-std=c++0x) + # Abuse the preprocessor to remove the + # override keyword on this old compiler. + add_definitions(-Doverride= ) else() message(FATAL_ERROR "Compiler does not support -std=c++0x either. " "Please upgrade your compiler." diff --git a/cmake/filelists.cmake b/cmake/filelists.cmake index 49e46ced..7b41cfa8 100644 --- a/cmake/filelists.cmake +++ b/cmake/filelists.cmake @@ -26,8 +26,19 @@ list(APPEND libdspdfviewer_SRCS pdfviewerwindow.cpp dspdfviewer.cpp windowrole.cpp + desktopsupport.cpp + desktopsupportfactory.cpp + desktopsupportexceptions.cpp + desktopsupport/generic.cpp + desktopsupport/i3.cpp ) +if(UseQtFive) + list(APPEND libdspdfviewer_SRCS + desktopsupport/win32.cpp + ) +endif() + list(APPEND dspdfviewer_SRCS main.cpp ) diff --git a/.codecov.yml b/codecov.yml similarity index 100% rename from .codecov.yml rename to codecov.yml diff --git a/desktopsupport.cpp b/desktopsupport.cpp new file mode 100644 index 00000000..2c9ce731 --- /dev/null +++ b/desktopsupport.cpp @@ -0,0 +1,80 @@ +#include "desktopsupport.h" +#include "desktopsupportexceptions.h" + +namespace { + bool isPrimary(const OutputPtr& p) { + return p->isPrimary(); + } +} + +OutputPtr DesktopSupport::getPrimary(const DesktopSupportErrorHandling& err) const { + OutputList vec=getOutputs(); + + if ( vec.empty () ) { + throw NoOutputsFound(); + } + + /** Return (first) primary screen */ + for( OutputPtr& p: vec ) + { + if ( p->isPrimary() ) { + return move(p); + } + } + + /** No primary screen found! + * + * If there is not exactly one output left, + * we don't know 100% what to do. + */ + + if ( vec.size() != 1 ) { + if ( err == DesktopSupportErrorHandling::ThrowOnError ) + throw CannotDeterminePrimaryOutput(vec); + } + + /** Errors ignored or exactly one screen left. Output it */ + return move( vec.at(0) ); +} + +OutputPtr DesktopSupport::getSecondary(const DesktopSupportErrorHandling& err) const { + OutputList vec = getOutputs(); + if ( vec.empty() ) { + throw NoOutputsFound(); + } + + /** Remove primary outputs from the set */ + vec.erase( + remove_if( vec.begin(), vec.end(), isPrimary ), + vec.end() + ); + + /** If there is not exactly one output left, + * we have a problem. + */ + if ( vec.size() > 1 ) { + if ( err == DesktopSupportErrorHandling::ThrowOnError ) + { + throw TooManyScreens(vec); + } + } + + /** Return the first non-primary output */ + return move( vec.at(0) ); +} + +void DesktopSupport::makeFullscreen( QWidget& window ) const { + if ( isFullscreen(window) ) + return; + window.showFullScreen(); +} + +void DesktopSupport::removeFullscreen( QWidget& window ) const { + if ( ! isFullscreen(window) ) + return; + window.showNormal(); +} + +bool DesktopSupport::isFullscreen( QWidget& window ) const { + return window.isFullScreen(); +} diff --git a/desktopsupport.h b/desktopsupport.h new file mode 100644 index 00000000..1a2a6b26 --- /dev/null +++ b/desktopsupport.h @@ -0,0 +1,155 @@ +#pragma once + +#include +#include +#include +#include + +#include "windowrole.h" + +enum class DesktopEnvironmentHandlerQuality { + NotMyEnvironment = 0, + GenericHandler, + OperatingSystemSpecificHandler, + DesktopEnvironmentSpecificHandler +}; + +/** Represents one "output", + * meaning a physical screen connected to the machine + * + * Exact type will be dependent on the handler that created it. + */ +struct OutputHandle { + /** Get a human-readable name of the output */ + virtual std::string const name() const =0; + + /** Is this output marked as "primary" ? */ + virtual bool isPrimary() const =0; + + /** Polymorphic class */ + virtual ~OutputHandle() { } +}; +typedef std::unique_ptr OutputPtr; +typedef std::vector OutputList; + +enum class DesktopSupportErrorHandling { + ThrowOnError, + TryToIgnoreError +}; + +/** Abstract base class for desktop support */ +class DesktopSupport { +public: + /** Check handler quality + * + * This either outputs NotMyEnvironment, + * or the quality of the handler + * + * High quality means it is perfectly suited + * for the current execution environment. + * + */ + virtual DesktopEnvironmentHandlerQuality quality() const =0; + + /** Output the DesktopSupport's name + * + * Human-readable, but must be unique across implementations. + * */ + virtual std::string const name() const =0; + + /** Get all outputs on the machine + * + * This needs to be implemented by inheriting classes + * */ + virtual OutputList getOutputs() const =0; + + /** Get Primary output + * + * can throw CannotDeterminePrimaryOutput + * if there is more than one screen and + * none of them is marked primary + * + * If there is more than one "primary" screen, + * it will output the numerically first of them. + * + * If errors are ignored, will pick the numerically + * first screen returned from the environment. + */ + OutputPtr getPrimary( + const DesktopSupportErrorHandling& errorMode= + DesktopSupportErrorHandling::ThrowOnError + ) + const; + + /** Get secondary screen + * + * can throw OnlyOneOutput if there is only + * one output + * + * can throw CannotDeterminePrimaryOutput + * if no screeen is marked Primary + * + * can throw TooManyScreens if there is three + * or more screens + * + * If errors are ignored, will pick the numerically + * second one when there is no primary. + * + * If there is a primary, will pick the numerically + * first non-primary. + * + * The exact screen chosen depends on the environment + * and is probably random. + */ + OutputPtr getSecondary( + const DesktopSupportErrorHandling& errorMode= + DesktopSupportErrorHandling::ThrowOnError + ) + const; + + /** Move a window to a specified output + * + * Can throw FailedToMoveToOutput if the desktop environment + * signaled an error (this is likely fatal) + */ + virtual void moveWindow(QWidget& window, OutputHandle& to) + const =0; + + /** Get target output for a specific window role */ + OutputPtr getTargetOutput( + const WindowRole& windowRole, + const DesktopSupportErrorHandling& errorMode= + DesktopSupportErrorHandling::ThrowOnError + ) const; + + /** Make the window fullscreen. + * + * Must not make an already-fullscreened window + * "normal" again. + * + * If the desktop does not allow detection of fullscreen + * state, unconditional un-full-screening and re-full-screening + * is acceptable as a last resort. + * + * The default implementation simply calls QWidget::showFullscreen() + */ + virtual void makeFullscreen(QWidget& window) const; + + /** Make the window non-fullscreen. + * + * Must not make an already normal window fullscreen. + * + * The default implementation simply calls QWidget::showNormal(). + */ + virtual void removeFullscreen(QWidget& window) const; + + /** Can this desktop environment move fullscreen windows? + */ + virtual bool canMoveWindowWhileFullscreen() const =0; + + /* Is this window fullscreen? */ + virtual bool isFullscreen(QWidget& window) const; + + /** This is a base class, make destructor virtual */ + virtual ~DesktopSupport() { } +}; diff --git a/desktopsupport/generic.cpp b/desktopsupport/generic.cpp new file mode 100644 index 00000000..2f4665d7 --- /dev/null +++ b/desktopsupport/generic.cpp @@ -0,0 +1,39 @@ +#include "generic.h" + +#include +#include + +using namespace std; + +namespace { + ostream& operator << (ostream& o, const QRect& rect) { + return o << rect.width() << "x" << rect.height() << + "@" << rect.left() << "," << rect.top(); + } +} + +string const GenericOutputHandle::name() const { + ostringstream os; + os << "GenericOutputHandle - rect " << screenRect; + return os.str(); +} + + +OutputList GenericDesktopSupport::getOutputs() const { + OutputList vec; + QDesktopWidget* desk = QApplication::desktop(); + for( int i=0 ; i < desk->screenCount() ; ++i ) { + OutputPtr p{ new GenericOutputHandle{ + desk->screenGeometry( i ), + i == desk->primaryScreen() + }}; + vec.push_back( move(p) ); + } + return vec; +} + +void GenericDesktopSupport::moveWindow(QWidget& window, OutputHandle& outhand) const { + GenericOutputHandle& out = dynamic_cast(outhand); + window.move( out.screenRect.topLeft() ); + window.resize( out.screenRect.size() ); +} diff --git a/desktopsupport/generic.h b/desktopsupport/generic.h new file mode 100644 index 00000000..7e5c5baa --- /dev/null +++ b/desktopsupport/generic.h @@ -0,0 +1,43 @@ +#pragma once + +#include "../desktopsupport.h" + +#include +#include + +/** On the Generic Handler, an "output handle" + * is just a rectangular place on the output + */ +struct GenericOutputHandle: public OutputHandle { + QRect screenRect; + bool primary; + + inline bool isPrimary() const override{ + return primary; + } + + GenericOutputHandle(const QRect& rect, bool b): + screenRect(rect), primary(b) { + } + + const std::string name() const override; +}; + +class GenericDesktopSupport: public DesktopSupport { + + DesktopEnvironmentHandlerQuality quality() const override { + return DesktopEnvironmentHandlerQuality::GenericHandler; + } + + std::string const name() const override { + return "Generic Qt4/5 desktop support handler"; + } + + OutputList getOutputs() const override; + + void moveWindow(QWidget&, OutputHandle&) const override; + + bool canMoveWindowWhileFullscreen() const override { + return true; + } +}; diff --git a/desktopsupport/i3.cpp b/desktopsupport/i3.cpp new file mode 100644 index 00000000..eb7a2155 --- /dev/null +++ b/desktopsupport/i3.cpp @@ -0,0 +1,87 @@ +#include "i3.h" +#include "../debug.h" +#include +#include +#include + +using namespace std; + +DesktopEnvironmentHandlerQuality i3DesktopSupport::quality() const { + /** Check return code of i3 --get-socketpath + * to check verify whether we are on i3 + */ + DEBUGOUT << "Checking if we are on i3..."; + if ( ! getSocketpath().empty() ) { + return DesktopEnvironmentHandlerQuality:: + DesktopEnvironmentSpecificHandler; + } else { + return DesktopEnvironmentHandlerQuality:: + NotMyEnvironment; + } +} + +i3OutputHandle::i3OutputHandle(const string& name, bool prim): + xrandrName(name), primary(prim) +{ +} + +const std::string i3OutputHandle::name() const { + return xrandrName; +} + +OutputList i3DesktopSupport::getOutputs() const { + /** FIXME: Dummy code */ + /** FIXME: Parse output of i3-msg --get-outputs with a JSON parser */ + OutputList list; + list.emplace_back( new i3OutputHandle("DVI-I-1", true) ); + list.emplace_back( new i3OutputHandle("VGA-0", false) ); + return list; +} + +void i3DesktopSupport::moveWindow(QWidget& w, OutputHandle& hnd) const { + i3OutputHandle& h = dynamic_cast( hnd ); + ostringstream command; + command << "i3-msg " + << "[id=" << w.winId() << "] " +// << "fullscreen disable, " + << "move to output " << h.xrandrName; + cerr << "Trying to run " << command.str() << endl; + system( command.str().c_str() ); + QApplication::processEvents(); +} + +void i3DesktopSupport::makeFullscreen(QWidget& w) const { + if ( w.isFullScreen() ) + return; + ostringstream command; + command << "i3-msg " + << "[id=" << w.winId() << "] " + << "fullscreen enable"; + cerr << "Trying to run " << command.str() << endl; + system( command.str().c_str() ); + QApplication::processEvents(); +} + +void i3DesktopSupport::removeFullscreen(QWidget& w) const { + if ( ! w.isFullScreen() ) + return; + ostringstream command; + command << "i3-msg " + << "[id=" << w.winId() << "] " + << "fullscreen disable"; + cerr << "Trying to run " << command.str() << endl; + system( command.str().c_str() ); + QApplication::processEvents(); +} + + +const string i3DesktopSupport::getSocketpath() { + /** FIXME: Actually check the return STRING, not just the retval */ + int ret = system("i3 --get-socketpath"); + + if ( ret == 0 ) { + return "OK"; + } + + return string(); +} diff --git a/desktopsupport/i3.h b/desktopsupport/i3.h new file mode 100644 index 00000000..87261829 --- /dev/null +++ b/desktopsupport/i3.h @@ -0,0 +1,28 @@ +#pragma once + +#include "../desktopsupport.h" + +struct i3OutputHandle: public OutputHandle { + const std::string xrandrName; + const std::string name() const override; + const bool primary; + bool isPrimary() const override { return primary; } + + i3OutputHandle(const std::string&, bool); +}; + +class i3DesktopSupport: public DesktopSupport { + DesktopEnvironmentHandlerQuality quality() const override; + std::string const name() const override { + return "i3 desktop support via i3 IPC"; + } + OutputList getOutputs() const override; + void moveWindow(QWidget&, OutputHandle&) const override; + void makeFullscreen(QWidget&) const override; + void removeFullscreen(QWidget&) const override; + bool canMoveWindowWhileFullscreen() const override { + return false; + } +private: + static const std::string getSocketpath(); +}; diff --git a/desktopsupport/win32.cpp b/desktopsupport/win32.cpp new file mode 100644 index 00000000..868ea086 --- /dev/null +++ b/desktopsupport/win32.cpp @@ -0,0 +1,43 @@ +#include "win32.h" + +#include +#include +#include +#include + +DesktopEnvironmentHandlerQuality Win32DesktopSupport::quality() const { +#if defined( _WIN32 ) + return DesktopEnvironmentHandlerQuality::OperatingSystemSpecificHandler; +#else + return DesktopEnvironmentHandlerQuality::NotMyEnvironment; +#endif +} + +OutputList Win32DesktopSupport::getOutputs() const { + /** FIXME: Is this a memory leak? + * Who owns the memory pointed to by the pointers? + */ + QList screens = QApplication::screens(); + OutputList outs; + for( int i=0; i< screens.count() ; ++i ) { + outs.emplace_back( + new Win32OutputHandle(i) + ); + } + return outs; +} + +void Win32DesktopSupport::moveWindow(QWidget& window, OutputHandle& out) const { + Win32OutputHandle& h=dynamic_cast(out); + window.windowHandle()->setScreen( + QApplication::screens().at( h.screenNumber ) + ); +} + +std::string const Win32OutputHandle::name() const { + std::ostringstream os; + os << "Win32 Output [" << screenNumber << "]"; + if ( isPrimary() ) + os << "[PRIMARY]"; + return os.str(); +} diff --git a/desktopsupport/win32.h b/desktopsupport/win32.h new file mode 100644 index 00000000..f2d15640 --- /dev/null +++ b/desktopsupport/win32.h @@ -0,0 +1,32 @@ +#include "../desktopsupport.h" + +/** In the win32 handler, we "memorize" the screens + * by their index in + * QApplication::screens() + */ +struct Win32OutputHandle: OutputHandle{ + int screenNumber; + + inline bool isPrimary() const override { + return screenNumber == 0; + } + + Win32OutputHandle(int i): + screenNumber(i) + { + } + + const std::string name() const override; +}; + +class Win32DesktopSupport: public DesktopSupport { + DesktopEnvironmentHandlerQuality quality() const override; + inline std::string const name() const override { + return "Win32 Desktop Support"; + } + OutputList getOutputs() const override; + void moveWindow(QWidget&, OutputHandle&) const override; + bool canMoveWindowWhileFullscreen() const override { + return false; + } +}; diff --git a/desktopsupportexceptions.cpp b/desktopsupportexceptions.cpp new file mode 100644 index 00000000..ceb7f0ba --- /dev/null +++ b/desktopsupportexceptions.cpp @@ -0,0 +1,43 @@ +#include "desktopsupportexceptions.h" + +using namespace std; + +namespace { + string const stringify( const OutputHandle& oh) { + string s("Output "); + s+=oh.name(); + if ( oh.isPrimary() ) + s+="[primary]"; + return s; + } + string const stringify( const OutputList& ol) { + string s; + for( const OutputPtr& p: ol ){ + if (p) { + s+=stringify(*p); + s+=", "; + } else { + s+="NULL PTR, "; + } + } + return s; + } +} + +DesktopSupportException::DesktopSupportException(const std::string& s): + runtime_error(s) { +} + +NoOutputsFound::NoOutputsFound(): + DesktopSupportException("No outputs were detected") { +} + +CannotDeterminePrimaryOutput::CannotDeterminePrimaryOutput( const OutputList& ol ): + DesktopSupportException("Cannot determine primary output: "+stringify(ol) ) { +} + +TooManyScreens::TooManyScreens( const OutputList& ol): + DesktopSupportException("Too many screens: "+stringify(ol)) { +} + + diff --git a/desktopsupportexceptions.h b/desktopsupportexceptions.h new file mode 100644 index 00000000..6c2ae083 --- /dev/null +++ b/desktopsupportexceptions.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include "desktopsupport.h" + +/** Desktop support exceptions */ + + +struct DesktopSupportException: public std::runtime_error { + DesktopSupportException(const std::string&); +}; + +struct CannotDeterminePrimaryOutput: public DesktopSupportException { + CannotDeterminePrimaryOutput(const OutputList& outputs); +}; + +struct NoOutputsFound: public DesktopSupportException { + NoOutputsFound(); +}; + +struct OnlyOneOutput: public DesktopSupportException { + OnlyOneOutput(const OutputHandle& output); +}; + +struct TooManyScreens: public DesktopSupportException { + TooManyScreens(const OutputList& outputs); +}; + +struct FailedToMoveToOutput: public DesktopSupportException { + FailedToMoveToOutput(const QWidget& window, const OutputHandle& to); +}; diff --git a/desktopsupportfactory.cpp b/desktopsupportfactory.cpp new file mode 100644 index 00000000..fa2fc767 --- /dev/null +++ b/desktopsupportfactory.cpp @@ -0,0 +1,54 @@ +#include "desktopsupportfactory.h" +#include "debug.h" + +#include "desktopsupport/generic.h" +#include "desktopsupport/win32.h" +#include "desktopsupport/i3.h" + +#include +#include + +using namespace std; + +namespace { + /** Compare two DesktopSupportPtr's by their quality */ + inline bool lessQuality ( + const DesktopSupportPtr& lhs, + const DesktopSupportPtr& rhs + ) { + return lhs->quality() < rhs->quality(); + } +} + +struct NoDesktopSupportImpls: public std::runtime_error { + NoDesktopSupportImpls(): + runtime_error("No desktop support available. Cannot continue") + { + } +}; + +DesktopSupportPtr DesktopSupportFactory::getDesktopSupport() { + vector allImpls; + + /** Construct all the implementations here */ + allImpls.emplace_back( new GenericDesktopSupport() ); + + /** The Win32 support requires QT5 */ +#if defined( POPPLER_QT5 ) + allImpls.emplace_back( new Win32DesktopSupport() ); +#endif + + allImpls.emplace_back( new i3DesktopSupport() ); + + auto maxElemIt = max_element( + allImpls.begin(), + allImpls.end(), + lessQuality + ); + + DEBUGOUT << "DesktopSupportFactory chose" << + (**maxElemIt).name().c_str() << + "for the current desktop environment"; + + return move( *maxElemIt ); +} diff --git a/desktopsupportfactory.h b/desktopsupportfactory.h new file mode 100644 index 00000000..0ca776a7 --- /dev/null +++ b/desktopsupportfactory.h @@ -0,0 +1,18 @@ +#pragma once + +#include "desktopsupport.h" + +#include + +typedef std::unique_ptr< DesktopSupport > DesktopSupportPtr; + +class DesktopSupportFactory { +public: + /** Initializes all compiled-in modules, + * figures out which one is best suited for + * the current environment, + * and returns the instance. + */ + + static DesktopSupportPtr getDesktopSupport(); +}; diff --git a/dspdfviewer.cpp b/dspdfviewer.cpp index f41b065a..5ade7e28 100644 --- a/dspdfviewer.cpp +++ b/dspdfviewer.cpp @@ -39,6 +39,7 @@ using boost::numeric_cast; DSPDFViewer::DSPDFViewer(const RuntimeConfiguration& r): runtimeConfiguration(r), + desktopSupport( DesktopSupportFactory::getDesktopSupport() ), clockDisplayTimer(), slideStart(), presentationStart(), @@ -46,8 +47,9 @@ DSPDFViewer::DSPDFViewer(const RuntimeConfiguration& r): documentFileWatcher(), renderFactory(r), m_pagenumber(0), - audienceWindow(1, r.useFullPage() ? PagePart::FullPage : PagePart::LeftHalf , false, r, WindowRole::AudienceWindow), - secondaryWindow(0, (r.useFullPage() | r.duplicate())? PagePart::FullPage : PagePart::RightHalf, true , r, WindowRole::PresenterWindow, r.useSecondScreen()) + audienceWindow( r.useFullPage() ? PagePart::FullPage : PagePart::LeftHalf , false, r, WindowRole::AudienceWindow), + secondaryWindow((r.useFullPage() | r.duplicate())? PagePart::FullPage : PagePart::RightHalf, true , r, WindowRole::PresenterWindow, r.useSecondScreen()), + monitorsSwapped(false) { DEBUGOUT << tr("Starting constructor") ; @@ -117,6 +119,16 @@ DSPDFViewer::DSPDFViewer(const RuntimeConfiguration& r): } + // Activate windows + audienceWindow.show(); + if ( r.useSecondScreen() ) + { + secondaryWindow.show(); + } + + /** Position the windows */ + repositionWindows(); + renderPage(); clockDisplayTimer.setInterval(TIMER_UPDATE_INTERVAL); @@ -209,22 +221,15 @@ void DSPDFViewer::gotoPage(unsigned int pageNumber) void DSPDFViewer::swapScreens() { - if ( audienceWindow.getMonitor() == 0 ) - { - audienceWindow.setMonitor(1); - secondaryWindow.setMonitor(0); - renderPage(); - } - else - { - audienceWindow.setMonitor(0); - secondaryWindow.setMonitor(1); - renderPage(); - } + if( monitorsSwapped ) { + monitorsSwapped = false; + } else { + monitorsSwapped = true; + } + repositionWindows(); } - void DSPDFViewer::exit() { audienceWindow.close(); @@ -384,3 +389,65 @@ const QRect DSPDFViewer::audienceGeometry() const { const QRect DSPDFViewer::secondGeometry() const { return secondaryWindow.geometry(); } + +void DSPDFViewer::repositionWindows() { + renderFactory.suspendRendering(); + auto primaryOutput = desktopSupport->getPrimary(); + + /** Get secondary output only if we actually use + * two screens + */ + if ( runtimeConfiguration.useSecondScreen() ) { + auto secondaryOutput = desktopSupport->getSecondary(); + + /** If monitors should be swapped, invert the following + * logic. + */ + if ( monitorsSwapped ) { + primaryOutput.swap( secondaryOutput ); + } + + if ( ! desktopSupport->canMoveWindowWhileFullscreen() ) { + desktopSupport->removeFullscreen( audienceWindow ); + desktopSupport->removeFullscreen( secondaryWindow ); + } + + /** Primary Output: Built-in Laptop screen + * This has the window for the presenter */ + desktopSupport->moveWindow( secondaryWindow, *primaryOutput); + + /** Secondary Output: External screen / beamer + * This has the audience's window + */ + desktopSupport->moveWindow( audienceWindow, *secondaryOutput); + + /** FIXME: Add configuration setting for non-fullscreen-mode + */ + + /** Just in case the desktop environment will un-full-screen + * the first window, make the presenter's window fullscreen + * first (possibly disposable) and ensure the audience + * gets the real fullscreen. + */ + + if ( ! desktopSupport->canMoveWindowWhileFullscreen() ) { + desktopSupport->makeFullscreen( secondaryWindow ); + desktopSupport->makeFullscreen( audienceWindow ); + } + } else { + /** Only one window in use */ + if ( ! desktopSupport->canMoveWindowWhileFullscreen() ) { + desktopSupport->removeFullscreen( audienceWindow ); + } + + desktopSupport->moveWindow(audienceWindow, *primaryOutput); + + if ( ! desktopSupport->canMoveWindowWhileFullscreen() ) { + /** FIXME: Add configuration for non-fullscreen mode */ + desktopSupport->makeFullscreen( audienceWindow ); + } + } + + renderFactory.resumeRendering(); + renderPage(); +} diff --git a/dspdfviewer.h b/dspdfviewer.h index 160c8d7d..849d44a9 100644 --- a/dspdfviewer.h +++ b/dspdfviewer.h @@ -29,6 +29,7 @@ #include "pdfviewerwindow.h" #include "pdfrenderfactory.h" #include "runtimeconfiguration.h" +#include "desktopsupportfactory.h" class DSPDFViewer: public QObject { @@ -36,6 +37,7 @@ class DSPDFViewer: public QObject private: const RuntimeConfiguration& runtimeConfiguration; + const DesktopSupportPtr desktopSupport; enum { TIMER_UPDATE_INTERVAL=250 }; @@ -52,7 +54,7 @@ class DSPDFViewer: public QObject unsigned int m_pagenumber; PDFViewerWindow audienceWindow; PDFViewerWindow secondaryWindow; - + bool monitorsSwapped; private: @@ -122,6 +124,7 @@ public slots: void goToStartAndResetClocks(); void swapScreens(); + void repositionWindows(); void toggleAudienceScreenBlank(); void setAudienceScreenBlank(); diff --git a/pdfrenderfactory.cpp b/pdfrenderfactory.cpp index 71f628b6..3b310fca 100644 --- a/pdfrenderfactory.cpp +++ b/pdfrenderfactory.cpp @@ -96,7 +96,8 @@ PdfRenderFactory::PdfRenderFactory( const RuntimeConfiguration& rc): currentVersion(0), // Attempt to read the document to get the number of pages within. // This will throw an error if the document is unreadable. - numberOfPages_(documentReference.popplerDocument()->numPages()) + numberOfPages_(documentReference.popplerDocument()->numPages()), + renderingActive(true) { rewatchFile(); @@ -113,6 +114,10 @@ PdfRenderFactory::PdfRenderFactory( const RuntimeConfiguration& rc): void PdfRenderFactory::requestPageRendering(const RenderingIdentifier& originalIdentifier, QThread::Priority priority) { QMutexLocker lock(&mutex); + if ( ! renderingActive ) + { + return; + } RenderingIdentifier renderingIdentifier(originalIdentifier); @@ -222,3 +227,13 @@ int PdfRenderFactory::numberOfPages() const PdfRenderFactory::~PdfRenderFactory() { RenderUtils::notifyShutdown(); } + +void PdfRenderFactory::suspendRendering() +{ + renderingActive=false; +} + +void PdfRenderFactory::resumeRendering() +{ + renderingActive=true; +} diff --git a/pdfrenderfactory.h b/pdfrenderfactory.h index 4ec4a27c..c07c288c 100644 --- a/pdfrenderfactory.h +++ b/pdfrenderfactory.h @@ -87,6 +87,7 @@ class PdfRenderFactory : public QObject quint64 currentVersion; int numberOfPages_; + bool renderingActive; private: void clearAllCaches(); @@ -115,6 +116,8 @@ private slots: public slots: void rewatchFile(); + void suspendRendering(); + void resumeRendering(); }; #endif // PDFRENDERFACTORY_H diff --git a/pdfviewerwindow.cpp b/pdfviewerwindow.cpp index e2d3b2ed..ff813569 100644 --- a/pdfviewerwindow.cpp +++ b/pdfviewerwindow.cpp @@ -24,9 +24,6 @@ #include #include #include -#if defined(POPPLER_QT5) && defined(_WIN32) -#include -#endif #include "debug.h" #include #include @@ -37,25 +34,10 @@ using boost::numeric_cast; -void PDFViewerWindow::setMonitor(const unsigned int monitor) -{ - if ( m_monitor != monitor ) - { - m_monitor = monitor; - reposition(); - } -} - -unsigned int PDFViewerWindow::getMonitor() const -{ - return m_monitor; -} - -PDFViewerWindow::PDFViewerWindow(unsigned int monitor, PagePart pagePart, bool showInformationLine, const RuntimeConfiguration& r, const WindowRole& wr, bool enabled): +PDFViewerWindow::PDFViewerWindow(PagePart pagePart, bool showInformationLine, const RuntimeConfiguration& r, const WindowRole& wr, bool enabled): QWidget(), ui(), m_enabled(enabled), - m_monitor(monitor), currentImage(), blank(false), informationLineVisible(false), @@ -96,43 +78,6 @@ PDFViewerWindow::PDFViewerWindow(unsigned int monitor, PagePart pagePart, bool s ui.slideClock->setVisible(r.showSlideClock()); ui.presentationClock->setVisible(r.showPresentationClock()); } - - reposition(); // This will fullscreen on its own -} - - - -void PDFViewerWindow::reposition() -{ - if ( ! m_enabled ) - return; - this->setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint); - this->showNormal(); -#if defined(POPPLER_QT5) && defined(_WIN32) - static QList screens = QApplication::screens(); - if ( m_monitor < numeric_cast(screens.count()) ) - this->windowHandle()->setScreen(screens[m_monitor]); - else - this->windowHandle()->setScreen(0); - this->showFullScreen(); -#else - QRect rect = QApplication::desktop()->screenGeometry( numeric_cast(getMonitor()) ); - move(rect.topLeft()); - resize( rect.size() ); - this->showFullScreen(); -#endif - /* Note: The focus should be on the primary window, because at least - * Gnome draws the primary window's border onto the secondary. - * - * I dont mind the border on my helper screen, but the - * audience shouldnt see it. - */ - if ( !informationLineVisible ) - this->activateWindow(); -// this->resize( 100, 100 ); - // this->move(rect.topLeft()); - //this->showFullScreen(); - } void PDFViewerWindow::displayImage(QImage image) diff --git a/pdfviewerwindow.h b/pdfviewerwindow.h index 252bc736..3488732d 100644 --- a/pdfviewerwindow.h +++ b/pdfviewerwindow.h @@ -38,7 +38,6 @@ class PDFViewerWindow : public QWidget private: Ui::Form ui; bool m_enabled; - unsigned int m_monitor; QImage currentImage; bool blank; bool informationLineVisible; @@ -77,22 +76,8 @@ class PDFViewerWindow : public QWidget public: /** Standard constructor - * @param monitor monitor to start on (usually 0 for primary) */ - explicit PDFViewerWindow(unsigned int monitor, PagePart myPart, bool showInformationLine, const RuntimeConfiguration& r, const WindowRole& windowRole, bool enabled=true); - - /** Sets the monitor to display this window on - * Automatically calls reposition - */ - void setMonitor(const unsigned int monitor); - - /** Gets the current monitor setting - */ - unsigned int getMonitor() const; - - /** Reposition the window (for example after a monitor change) - */ - void reposition(); + explicit PDFViewerWindow(PagePart myPart, bool showInformationLine, const RuntimeConfiguration& r, const WindowRole& windowRole, bool enabled=true); QSize getTargetImageSize() const;