From ce78550bcdc382e068e38555ede3b84a13152bf4 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Sun, 28 Feb 2016 14:12:37 +0100 Subject: [PATCH 01/17] DesktopSupport: Create basic framework --- cmake/filelists.cmake | 4 ++ desktopsupport.cpp | 1 + desktopsupport.h | 102 +++++++++++++++++++++++++++++++++++ desktopsupport/generic.cpp | 3 ++ desktopsupport/generic.h | 6 +++ desktopsupportexceptions.cpp | 1 + desktopsupportexceptions.h | 30 +++++++++++ desktopsupportfactory.cpp | 1 + desktopsupportfactory.h | 18 +++++++ 9 files changed, 166 insertions(+) create mode 100644 desktopsupport.cpp create mode 100644 desktopsupport.h create mode 100644 desktopsupport/generic.cpp create mode 100644 desktopsupport/generic.h create mode 100644 desktopsupportexceptions.cpp create mode 100644 desktopsupportexceptions.h create mode 100644 desktopsupportfactory.cpp create mode 100644 desktopsupportfactory.h diff --git a/cmake/filelists.cmake b/cmake/filelists.cmake index 49e46ced..a68acd49 100644 --- a/cmake/filelists.cmake +++ b/cmake/filelists.cmake @@ -26,6 +26,10 @@ list(APPEND libdspdfviewer_SRCS pdfviewerwindow.cpp dspdfviewer.cpp windowrole.cpp + desktopsupport.cpp + desktopsupportfactory.cpp + desktopsupportexceptions.cpp + desktopsupport/generic.cpp ) list(APPEND dspdfviewer_SRCS diff --git a/desktopsupport.cpp b/desktopsupport.cpp new file mode 100644 index 00000000..fe11d206 --- /dev/null +++ b/desktopsupport.cpp @@ -0,0 +1 @@ +#include "desktopsupport.h" diff --git a/desktopsupport.h b/desktopsupport.h new file mode 100644 index 00000000..223edef8 --- /dev/null +++ b/desktopsupport.h @@ -0,0 +1,102 @@ +#pragma once + +#include +#include +#include + +enum class DesktopEnvironmentHandlerQuality { + NotMyEnvironment = 0, + GenericHandler, + OperatingSpecificHandler, + DesktopEnvironmentSpecificHandler +}; + +/** Represents one "output", + * meaning a physical screen connected to the machine + * + * Exact type will be dependent on the handler that created it. + */ +class OutputHandle { + /** Get a human-readable name of the output */ + virtual std::string const name() const =0; + + /** Polymorphic class */ + virtual ~OutputHandle() =default; +}; +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; + + /** Get all outputs on the machine */ + 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 errors are ignored, will pick the numerically + * first screen returned from the environment. + */ + virtual OutputPtr getPrimary( + const DesktopSupportErrorHandling& errorMode= + DesktopSupportErrorHandling::ThrowOnError + ) + const =0; + + /** 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. + */ + virtual OutputPtr getSecondary( + const DesktopSupportErrorHandling& errorMode= + DesktopSupportErrorHandling::ThrowOnError + ) + const =0; + + /** 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; + + /** This is a base class, make destructor virtual */ + virtual ~DesktopSupport() =default; +}; diff --git a/desktopsupport/generic.cpp b/desktopsupport/generic.cpp new file mode 100644 index 00000000..4dad58dc --- /dev/null +++ b/desktopsupport/generic.cpp @@ -0,0 +1,3 @@ +#include "generic.h" + + diff --git a/desktopsupport/generic.h b/desktopsupport/generic.h new file mode 100644 index 00000000..b23d31f3 --- /dev/null +++ b/desktopsupport/generic.h @@ -0,0 +1,6 @@ +#pragma once + +#include "../desktopsupport.h" + +class GenericDesktopSupport: public DesktopSupport { +}; diff --git a/desktopsupportexceptions.cpp b/desktopsupportexceptions.cpp new file mode 100644 index 00000000..a4c96bdb --- /dev/null +++ b/desktopsupportexceptions.cpp @@ -0,0 +1 @@ +#include "desktopsupportexceptions.h" diff --git a/desktopsupportexceptions.h b/desktopsupportexceptions.h new file mode 100644 index 00000000..e6ab12c5 --- /dev/null +++ b/desktopsupportexceptions.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include "desktopsupport.h" + +/** Desktop support exceptions */ + +struct DesktopSupportException: public std::runtime_error { + DesktopSupportException(const std::string&); +}; + +struct CannotDeterminePrimaryOutput: public DesktopSupportException { + const OutputList outputs; + CannotDeterminePrimaryOutput(OutputList&& outputs); +}; + +struct OnlyOneOutput: public DesktopSupportException { + const OutputPtr output; + OnlyOneOutput(OutputPtr&& output); +}; + +struct TooManyScreens: public DesktopSupportException { + const OutputList outputs; + TooManyScreens(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..6ac37f6f --- /dev/null +++ b/desktopsupportfactory.cpp @@ -0,0 +1 @@ +#include "desktopsupportfactory.h" 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(); +}; From 76407c17da6349da9e44ba2a60daa8aa2521f0d6 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Sun, 28 Feb 2016 16:38:22 +0100 Subject: [PATCH 02/17] initial version of generic supporter --- desktopsupport.cpp | 63 ++++++++++++++++++++++++++++++++++++ desktopsupport.h | 49 ++++++++++++++++++++++++---- desktopsupport/generic.cpp | 43 ++++++++++++++++++++++++ desktopsupport/generic.h | 35 ++++++++++++++++++++ desktopsupportexceptions.cpp | 42 ++++++++++++++++++++++++ desktopsupportexceptions.h | 14 ++++---- desktopsupportfactory.cpp | 31 ++++++++++++++++++ desktopsupportfactory.h | 8 +++++ dspdfviewer.cpp | 58 ++++++++++++++++++++++++--------- dspdfviewer.h | 5 ++- pdfviewerwindow.cpp | 22 ++----------- pdfviewerwindow.h | 16 +-------- 12 files changed, 323 insertions(+), 63 deletions(-) diff --git a/desktopsupport.cpp b/desktopsupport.cpp index fe11d206..6d48ddc5 100644 --- a/desktopsupport.cpp +++ b/desktopsupport.cpp @@ -1 +1,64 @@ #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) ); +} diff --git a/desktopsupport.h b/desktopsupport.h index 223edef8..2e2a46e1 100644 --- a/desktopsupport.h +++ b/desktopsupport.h @@ -4,10 +4,12 @@ #include #include +#include "windowrole.h" + enum class DesktopEnvironmentHandlerQuality { NotMyEnvironment = 0, GenericHandler, - OperatingSpecificHandler, + OperatingSystemSpecificHandler, DesktopEnvironmentSpecificHandler }; @@ -16,10 +18,13 @@ enum class DesktopEnvironmentHandlerQuality { * * Exact type will be dependent on the handler that created it. */ -class OutputHandle { +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() =default; }; @@ -45,7 +50,16 @@ class DesktopSupport { */ virtual DesktopEnvironmentHandlerQuality quality() const =0; - /** Get all outputs on the machine */ + /** 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 @@ -54,14 +68,17 @@ class DesktopSupport { * 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. */ - virtual OutputPtr getPrimary( + OutputPtr getPrimary( const DesktopSupportErrorHandling& errorMode= DesktopSupportErrorHandling::ThrowOnError ) - const =0; + const; /** Get secondary screen * @@ -83,11 +100,11 @@ class DesktopSupport { * The exact screen chosen depends on the environment * and is probably random. */ - virtual OutputPtr getSecondary( + OutputPtr getSecondary( const DesktopSupportErrorHandling& errorMode= DesktopSupportErrorHandling::ThrowOnError ) - const =0; + const; /** Move a window to a specified output * @@ -97,6 +114,24 @@ class DesktopSupport { 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. + */ + virtual void makeFullscreen(QWidget& window) const =0; + /** This is a base class, make destructor virtual */ virtual ~DesktopSupport() =default; }; diff --git a/desktopsupport/generic.cpp b/desktopsupport/generic.cpp index 4dad58dc..c2f523fe 100644 --- a/desktopsupport/generic.cpp +++ b/desktopsupport/generic.cpp @@ -1,3 +1,46 @@ #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::makeFullscreen(QWidget& window) const { + if ( window.isFullScreen() ) + return; + window.showNormal(); + window.showFullScreen(); +} + +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 index b23d31f3..bdc5a025 100644 --- a/desktopsupport/generic.h +++ b/desktopsupport/generic.h @@ -2,5 +2,40 @@ #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; + + void makeFullscreen(QWidget&) const override; }; diff --git a/desktopsupportexceptions.cpp b/desktopsupportexceptions.cpp index a4c96bdb..ceb7f0ba 100644 --- a/desktopsupportexceptions.cpp +++ b/desktopsupportexceptions.cpp @@ -1 +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 index e6ab12c5..6c2ae083 100644 --- a/desktopsupportexceptions.h +++ b/desktopsupportexceptions.h @@ -6,23 +6,25 @@ /** Desktop support exceptions */ + struct DesktopSupportException: public std::runtime_error { DesktopSupportException(const std::string&); }; struct CannotDeterminePrimaryOutput: public DesktopSupportException { - const OutputList outputs; - CannotDeterminePrimaryOutput(OutputList&& outputs); + CannotDeterminePrimaryOutput(const OutputList& outputs); +}; + +struct NoOutputsFound: public DesktopSupportException { + NoOutputsFound(); }; struct OnlyOneOutput: public DesktopSupportException { - const OutputPtr output; - OnlyOneOutput(OutputPtr&& output); + OnlyOneOutput(const OutputHandle& output); }; struct TooManyScreens: public DesktopSupportException { - const OutputList outputs; - TooManyScreens(OutputList&& outputs); + TooManyScreens(const OutputList& outputs); }; struct FailedToMoveToOutput: public DesktopSupportException { diff --git a/desktopsupportfactory.cpp b/desktopsupportfactory.cpp index 6ac37f6f..82e7b5dd 100644 --- a/desktopsupportfactory.cpp +++ b/desktopsupportfactory.cpp @@ -1 +1,32 @@ #include "desktopsupportfactory.h" + +#include "desktopsupport/generic.h" +#include "debug.h" + +using namespace std; + +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() ); + + 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 index 0ca776a7..0e333ce8 100644 --- a/desktopsupportfactory.h +++ b/desktopsupportfactory.h @@ -6,6 +6,14 @@ typedef std::unique_ptr< DesktopSupport > DesktopSupportPtr; +/** Compare two DesktopSupportPtr's by their quality */ +inline bool lessQuality ( + const DesktopSupportPtr& lhs, + const DesktopSupportPtr& rhs + ) { + return lhs->quality() < rhs->quality(); +} + class DesktopSupportFactory { public: /** Initializes all compiled-in modules, diff --git a/dspdfviewer.cpp b/dspdfviewer.cpp index f41b065a..c1bbadf3 100644 --- a/dspdfviewer.cpp +++ b/dspdfviewer.cpp @@ -46,8 +46,10 @@ 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), + desktopSupport( DesktopSupportFactory::getDesktopSupport() ) { DEBUGOUT << tr("Starting constructor") ; @@ -209,22 +211,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 +379,36 @@ const QRect DSPDFViewer::audienceGeometry() const { const QRect DSPDFViewer::secondGeometry() const { return secondaryWindow.geometry(); } + +void DSPDFViewer::repositionWindows() { + auto primaryOutput = desktopSupport->getPrimary(); + auto secondaryOutput = desktopSupport->getSecondary(); + + /** If monitors should be swapped, invert the following + * logic. + */ + if ( monitorsSwapped ) { + primaryOutput.swap( secondaryOutput ); + } + + /** 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. + */ + desktopSupport->makeFullscreen( secondaryWindow ); + desktopSupport->makeFullscreen( audienceWindow ); + +} diff --git a/dspdfviewer.h b/dspdfviewer.h index 160c8d7d..d93bdb27 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 { @@ -52,8 +53,9 @@ class DSPDFViewer: public QObject unsigned int m_pagenumber; PDFViewerWindow audienceWindow; PDFViewerWindow secondaryWindow; + bool monitorsSwapped; - + DesktopSupportPtr desktopSupport; private: QString timeToString(QTime time) const; @@ -122,6 +124,7 @@ public slots: void goToStartAndResetClocks(); void swapScreens(); + void repositionWindows(); void toggleAudienceScreenBlank(); void setAudienceScreenBlank(); diff --git a/pdfviewerwindow.cpp b/pdfviewerwindow.cpp index e2d3b2ed..b4f08200 100644 --- a/pdfviewerwindow.cpp +++ b/pdfviewerwindow.cpp @@ -37,25 +37,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,12 +81,10 @@ 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 } - +#if 0 void PDFViewerWindow::reposition() { if ( ! m_enabled ) @@ -134,6 +117,7 @@ void PDFViewerWindow::reposition() //this->showFullScreen(); } +#endif void PDFViewerWindow::displayImage(QImage image) { diff --git a/pdfviewerwindow.h b/pdfviewerwindow.h index 252bc736..4b8c8eb4 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; @@ -79,20 +78,7 @@ class PDFViewerWindow : public QWidget /** 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; From 789c50f6b3a714325f6fc20ac2695d0d93adf080 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Mon, 29 Feb 2016 11:53:19 +0100 Subject: [PATCH 03/17] Migrated win32 code to the new framework --- cmake/filelists.cmake | 1 + desktopsupport/win32.cpp | 51 ++++++++++++++++++++++++++ desktopsupport/win32.h | 30 +++++++++++++++ desktopsupportfactory.cpp | 15 +++++++- desktopsupportfactory.h | 8 ---- dspdfviewer.cpp | 77 +++++++++++++++++++++++++-------------- dspdfviewer.h | 2 +- pdfviewerwindow.cpp | 39 -------------------- 8 files changed, 146 insertions(+), 77 deletions(-) create mode 100644 desktopsupport/win32.cpp create mode 100644 desktopsupport/win32.h diff --git a/cmake/filelists.cmake b/cmake/filelists.cmake index a68acd49..795c7845 100644 --- a/cmake/filelists.cmake +++ b/cmake/filelists.cmake @@ -30,6 +30,7 @@ list(APPEND libdspdfviewer_SRCS desktopsupportfactory.cpp desktopsupportexceptions.cpp desktopsupport/generic.cpp + desktopsupport/win32.cpp ) list(APPEND dspdfviewer_SRCS diff --git a/desktopsupport/win32.cpp b/desktopsupport/win32.cpp new file mode 100644 index 00000000..47a9be73 --- /dev/null +++ b/desktopsupport/win32.cpp @@ -0,0 +1,51 @@ +#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); + /** Un-fullscreen the window, to be sure we're allowed to move it */ + if ( window.isFullScreen() ) { + window.showNormal(); + } + window.windowHandle()->setScreen( + QApplication::screens().at( h.screenNumber ) + ); +} + +void Win32DesktopSupport::makeFullscreen(QWidget& window) const { + window.showFullScreen(); +} + +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..abc8e1c7 --- /dev/null +++ b/desktopsupport/win32.h @@ -0,0 +1,30 @@ +#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; + void makeFullscreen(QWidget&) const override; +}; diff --git a/desktopsupportfactory.cpp b/desktopsupportfactory.cpp index 82e7b5dd..9ab11d99 100644 --- a/desktopsupportfactory.cpp +++ b/desktopsupportfactory.cpp @@ -1,10 +1,22 @@ #include "desktopsupportfactory.h" +#include "debug.h" #include "desktopsupport/generic.h" -#include "debug.h" +#include "desktopsupport/win32.h" +#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") @@ -17,6 +29,7 @@ DesktopSupportPtr DesktopSupportFactory::getDesktopSupport() { /** Construct all the implementations here */ allImpls.emplace_back( new GenericDesktopSupport() ); + allImpls.emplace_back( new Win32DesktopSupport() ); auto maxElemIt = max_element( allImpls.begin(), diff --git a/desktopsupportfactory.h b/desktopsupportfactory.h index 0e333ce8..0ca776a7 100644 --- a/desktopsupportfactory.h +++ b/desktopsupportfactory.h @@ -6,14 +6,6 @@ typedef std::unique_ptr< DesktopSupport > DesktopSupportPtr; -/** Compare two DesktopSupportPtr's by their quality */ -inline bool lessQuality ( - const DesktopSupportPtr& lhs, - const DesktopSupportPtr& rhs - ) { - return lhs->quality() < rhs->quality(); -} - class DesktopSupportFactory { public: /** Initializes all compiled-in modules, diff --git a/dspdfviewer.cpp b/dspdfviewer.cpp index c1bbadf3..6c0871d0 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(), @@ -48,8 +49,7 @@ DSPDFViewer::DSPDFViewer(const RuntimeConfiguration& r): m_pagenumber(0), 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), - desktopSupport( DesktopSupportFactory::getDesktopSupport() ) + monitorsSwapped(false) { DEBUGOUT << tr("Starting constructor") ; @@ -119,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); @@ -382,33 +392,44 @@ const QRect DSPDFViewer::secondGeometry() const { void DSPDFViewer::repositionWindows() { auto primaryOutput = desktopSupport->getPrimary(); - auto secondaryOutput = desktopSupport->getSecondary(); - /** If monitors should be swapped, invert the following - * logic. + /** Get secondary output only if we actually use + * two screens */ - if ( monitorsSwapped ) { - primaryOutput.swap( secondaryOutput ); - } - - /** 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. - */ - desktopSupport->makeFullscreen( secondaryWindow ); - desktopSupport->makeFullscreen( audienceWindow ); + if ( runtimeConfiguration.useSecondScreen() ) { + auto secondaryOutput = desktopSupport->getSecondary(); + + /** If monitors should be swapped, invert the following + * logic. + */ + if ( monitorsSwapped ) { + primaryOutput.swap( secondaryOutput ); + } + + /** 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. + */ + desktopSupport->makeFullscreen( secondaryWindow ); + desktopSupport->makeFullscreen( audienceWindow ); + } else { + /** Only one window in use */ + desktopSupport->moveWindow(audienceWindow, *primaryOutput); + /** FIXME: Add configuration for non-fullscreen mode */ + desktopSupport->makeFullscreen( audienceWindow ); + } } diff --git a/dspdfviewer.h b/dspdfviewer.h index d93bdb27..849d44a9 100644 --- a/dspdfviewer.h +++ b/dspdfviewer.h @@ -37,6 +37,7 @@ class DSPDFViewer: public QObject private: const RuntimeConfiguration& runtimeConfiguration; + const DesktopSupportPtr desktopSupport; enum { TIMER_UPDATE_INTERVAL=250 }; @@ -55,7 +56,6 @@ class DSPDFViewer: public QObject PDFViewerWindow secondaryWindow; bool monitorsSwapped; - DesktopSupportPtr desktopSupport; private: QString timeToString(QTime time) const; diff --git a/pdfviewerwindow.cpp b/pdfviewerwindow.cpp index b4f08200..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 @@ -83,42 +80,6 @@ PDFViewerWindow::PDFViewerWindow(PagePart pagePart, bool showInformationLine, co } } - -#if 0 -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(); - -} -#endif - void PDFViewerWindow::displayImage(QImage image) { ui.imageLabel->setText( QString() ); From 422b2dc31822ef4eed9612291feea2b50c5c61e7 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Mon, 29 Feb 2016 11:55:27 +0100 Subject: [PATCH 04/17] Give destructor default impl inline --- desktopsupport.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desktopsupport.h b/desktopsupport.h index 2e2a46e1..67d29ba2 100644 --- a/desktopsupport.h +++ b/desktopsupport.h @@ -26,7 +26,7 @@ struct OutputHandle { virtual bool isPrimary() const =0; /** Polymorphic class */ - virtual ~OutputHandle() =default; + virtual ~OutputHandle() { }; }; typedef std::unique_ptr OutputPtr; typedef std::vector OutputList; @@ -133,5 +133,5 @@ class DesktopSupport { virtual void makeFullscreen(QWidget& window) const =0; /** This is a base class, make destructor virtual */ - virtual ~DesktopSupport() =default; + virtual ~DesktopSupport() { }; }; From 183dbf266a9428f5b4114b33d0f905f598cdc42a Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Mon, 29 Feb 2016 12:00:31 +0100 Subject: [PATCH 05/17] remove invalid docstring --- pdfviewerwindow.h | 1 - 1 file changed, 1 deletion(-) diff --git a/pdfviewerwindow.h b/pdfviewerwindow.h index 4b8c8eb4..3488732d 100644 --- a/pdfviewerwindow.h +++ b/pdfviewerwindow.h @@ -76,7 +76,6 @@ class PDFViewerWindow : public QWidget public: /** Standard constructor - * @param monitor monitor to start on (usually 0 for primary) */ explicit PDFViewerWindow(PagePart myPart, bool showInformationLine, const RuntimeConfiguration& r, const WindowRole& windowRole, bool enabled=true); From 3c690e08bde8c2e40c1941635b08a664891aa8a6 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Mon, 29 Feb 2016 12:27:35 +0100 Subject: [PATCH 06/17] Fix FTBFS with gcc4.6 on precise --- cmake/compiler_gnu_gcc.cmake | 3 +++ cmake/filelists.cmake | 7 ++++++- desktopsupportfactory.cpp | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) 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 795c7845..9a111d5a 100644 --- a/cmake/filelists.cmake +++ b/cmake/filelists.cmake @@ -30,9 +30,14 @@ list(APPEND libdspdfviewer_SRCS desktopsupportfactory.cpp desktopsupportexceptions.cpp desktopsupport/generic.cpp - desktopsupport/win32.cpp ) +if(UseQtFive) + list(APPEND libdspdfviewer_SRCS + desktopsupport/win32.cpp + ) +endif() + list(APPEND dspdfviewer_SRCS main.cpp ) diff --git a/desktopsupportfactory.cpp b/desktopsupportfactory.cpp index 9ab11d99..8f173253 100644 --- a/desktopsupportfactory.cpp +++ b/desktopsupportfactory.cpp @@ -4,6 +4,7 @@ #include "desktopsupport/generic.h" #include "desktopsupport/win32.h" #include +#include using namespace std; @@ -29,7 +30,11 @@ DesktopSupportPtr DesktopSupportFactory::getDesktopSupport() { /** Construct all the implementations here */ allImpls.emplace_back( new GenericDesktopSupport() ); + + /** The Win32 support requires QT5 */ +#if POPPLER_QT5 allImpls.emplace_back( new Win32DesktopSupport() ); +#endif auto maxElemIt = max_element( allImpls.begin(), From bd86b2a2ca3aecec3039ca0e6344565a9d475f5e Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Mon, 29 Feb 2016 12:54:31 +0100 Subject: [PATCH 07/17] fix FTBFS with precise/qt4/clang --- desktopsupport.h | 4 ++-- desktopsupportfactory.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/desktopsupport.h b/desktopsupport.h index 67d29ba2..fff8a1df 100644 --- a/desktopsupport.h +++ b/desktopsupport.h @@ -26,7 +26,7 @@ struct OutputHandle { virtual bool isPrimary() const =0; /** Polymorphic class */ - virtual ~OutputHandle() { }; + virtual ~OutputHandle() { } }; typedef std::unique_ptr OutputPtr; typedef std::vector OutputList; @@ -133,5 +133,5 @@ class DesktopSupport { virtual void makeFullscreen(QWidget& window) const =0; /** This is a base class, make destructor virtual */ - virtual ~DesktopSupport() { }; + virtual ~DesktopSupport() { } }; diff --git a/desktopsupportfactory.cpp b/desktopsupportfactory.cpp index 8f173253..66150f06 100644 --- a/desktopsupportfactory.cpp +++ b/desktopsupportfactory.cpp @@ -32,7 +32,7 @@ DesktopSupportPtr DesktopSupportFactory::getDesktopSupport() { allImpls.emplace_back( new GenericDesktopSupport() ); /** The Win32 support requires QT5 */ -#if POPPLER_QT5 +#if defined( POPPLER_QT5 ) allImpls.emplace_back( new Win32DesktopSupport() ); #endif From 551cc79883412d5d564591c30c297d45c01d5534 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Sun, 3 Apr 2016 16:16:50 +0200 Subject: [PATCH 08/17] [WIP] preliminary i3 support --- cmake/filelists.cmake | 1 + desktopsupport/i3.cpp | 87 +++++++++++++++++++++++++++++++++++++++ desktopsupport/i3.h | 24 +++++++++++ desktopsupportfactory.cpp | 4 ++ 4 files changed, 116 insertions(+) create mode 100644 desktopsupport/i3.cpp create mode 100644 desktopsupport/i3.h diff --git a/cmake/filelists.cmake b/cmake/filelists.cmake index 9a111d5a..7b41cfa8 100644 --- a/cmake/filelists.cmake +++ b/cmake/filelists.cmake @@ -30,6 +30,7 @@ list(APPEND libdspdfviewer_SRCS desktopsupportfactory.cpp desktopsupportexceptions.cpp desktopsupport/generic.cpp + desktopsupport/i3.cpp ) if(UseQtFive) diff --git a/desktopsupport/i3.cpp b/desktopsupport/i3.cpp new file mode 100644 index 00000000..db4233b9 --- /dev/null +++ b/desktopsupport/i3.cpp @@ -0,0 +1,87 @@ +#include "i3.h" +#include "../debug.h" +#include +#include +#include +#include +#include +#include +#include + +namespace { + typedef std::unique_ptr< + FILE, + decltype(&pclose) + > FILEptr; +} + +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 */ + 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 { + ostringstream command; + command << "i3-msg " + << "[id=" << w.winId() << "] " + << "fullscreen enable"; + cerr << "Trying to run " << command.str() << endl; + system( command.str().c_str() ); + QApplication::processEvents(); +} + + +const string i3DesktopSupport::getSocketpath() { + /** Cache for the socket path */ + static string spath; + if ( ! spath.empty() ) { + return spath; + } + /** Socketpath not cached */ + + /** FIXME: Port this to boost or similar */ + FILEptr fd( popen("i3 --get-socketpath", "r"), pclose ); + + + return "/run/user/1000/i3/ipc-socket.1468"; +} diff --git a/desktopsupport/i3.h b/desktopsupport/i3.h new file mode 100644 index 00000000..6fd1abd4 --- /dev/null +++ b/desktopsupport/i3.h @@ -0,0 +1,24 @@ +#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 { 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; +private: + static const std::string getSocketpath(); +}; diff --git a/desktopsupportfactory.cpp b/desktopsupportfactory.cpp index 66150f06..fa2fc767 100644 --- a/desktopsupportfactory.cpp +++ b/desktopsupportfactory.cpp @@ -3,6 +3,8 @@ #include "desktopsupport/generic.h" #include "desktopsupport/win32.h" +#include "desktopsupport/i3.h" + #include #include @@ -36,6 +38,8 @@ DesktopSupportPtr DesktopSupportFactory::getDesktopSupport() { allImpls.emplace_back( new Win32DesktopSupport() ); #endif + allImpls.emplace_back( new i3DesktopSupport() ); + auto maxElemIt = max_element( allImpls.begin(), allImpls.end(), From e7b0a074f195ab54698f2e93cf00491d70052e55 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Thu, 7 Apr 2016 11:58:03 +0200 Subject: [PATCH 09/17] workaround: always un-fullscreen before moving --- desktopsupport.h | 2 ++ desktopsupport/generic.cpp | 6 ++++++ desktopsupport/generic.h | 1 + desktopsupport/i3.cpp | 16 +++++++++++++++- desktopsupport/i3.h | 3 ++- desktopsupport/win32.cpp | 4 ++++ desktopsupport/win32.h | 1 + dspdfviewer.cpp | 3 +++ 8 files changed, 34 insertions(+), 2 deletions(-) diff --git a/desktopsupport.h b/desktopsupport.h index fff8a1df..5eeb5753 100644 --- a/desktopsupport.h +++ b/desktopsupport.h @@ -132,6 +132,8 @@ class DesktopSupport { */ virtual void makeFullscreen(QWidget& window) const =0; + virtual void removeFullscreen(QWidget& window) const =0; + /** This is a base class, make destructor virtual */ virtual ~DesktopSupport() { } }; diff --git a/desktopsupport/generic.cpp b/desktopsupport/generic.cpp index c2f523fe..fcc4a764 100644 --- a/desktopsupport/generic.cpp +++ b/desktopsupport/generic.cpp @@ -39,6 +39,12 @@ void GenericDesktopSupport::makeFullscreen(QWidget& window) const { window.showFullScreen(); } +void GenericDesktopSupport::removeFullscreen(QWidget& window) const { + if ( ! window.isFullScreen() ) + return; + window.showNormal(); +} + void GenericDesktopSupport::moveWindow(QWidget& window, OutputHandle& outhand) const { GenericOutputHandle& out = dynamic_cast(outhand); window.move( out.screenRect.topLeft() ); diff --git a/desktopsupport/generic.h b/desktopsupport/generic.h index bdc5a025..861ab134 100644 --- a/desktopsupport/generic.h +++ b/desktopsupport/generic.h @@ -38,4 +38,5 @@ class GenericDesktopSupport: public DesktopSupport { void moveWindow(QWidget&, OutputHandle&) const override; void makeFullscreen(QWidget&) const override; + void removeFullscreen(QWidget&) const override; }; diff --git a/desktopsupport/i3.cpp b/desktopsupport/i3.cpp index db4233b9..5255ab52 100644 --- a/desktopsupport/i3.cpp +++ b/desktopsupport/i3.cpp @@ -53,7 +53,7 @@ void i3DesktopSupport::moveWindow(QWidget& w, OutputHandle& hnd) const { ostringstream command; command << "i3-msg " << "[id=" << w.winId() << "] " - << "fullscreen disable, " +// << "fullscreen disable, " << "move to output " << h.xrandrName; cerr << "Trying to run " << command.str() << endl; system( command.str().c_str() ); @@ -61,6 +61,8 @@ void i3DesktopSupport::moveWindow(QWidget& w, OutputHandle& hnd) const { } void i3DesktopSupport::makeFullscreen(QWidget& w) const { + if ( w.isFullScreen() ) + return; ostringstream command; command << "i3-msg " << "[id=" << w.winId() << "] " @@ -70,6 +72,18 @@ void i3DesktopSupport::makeFullscreen(QWidget& w) const { 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() { /** Cache for the socket path */ diff --git a/desktopsupport/i3.h b/desktopsupport/i3.h index 6fd1abd4..1cd11742 100644 --- a/desktopsupport/i3.h +++ b/desktopsupport/i3.h @@ -6,7 +6,7 @@ struct i3OutputHandle: public OutputHandle { const std::string xrandrName; const std::string name() const override; const bool primary; - bool isPrimary() const { return primary; } + bool isPrimary() const override { return primary; } i3OutputHandle(const std::string&, bool); }; @@ -19,6 +19,7 @@ class i3DesktopSupport: public DesktopSupport { OutputList getOutputs() const override; void moveWindow(QWidget&, OutputHandle&) const override; void makeFullscreen(QWidget&) const override; + void removeFullscreen(QWidget&) const override; private: static const std::string getSocketpath(); }; diff --git a/desktopsupport/win32.cpp b/desktopsupport/win32.cpp index 47a9be73..62714980 100644 --- a/desktopsupport/win32.cpp +++ b/desktopsupport/win32.cpp @@ -42,6 +42,10 @@ void Win32DesktopSupport::makeFullscreen(QWidget& window) const { window.showFullScreen(); } +void Win32DesktopSupport::removeFullscreen(QWidget& window) const { + window.showNormal(); +} + std::string const Win32OutputHandle::name() const { std::ostringstream os; os << "Win32 Output [" << screenNumber << "]"; diff --git a/desktopsupport/win32.h b/desktopsupport/win32.h index abc8e1c7..45fd58ad 100644 --- a/desktopsupport/win32.h +++ b/desktopsupport/win32.h @@ -27,4 +27,5 @@ class Win32DesktopSupport: public DesktopSupport { OutputList getOutputs() const override; void moveWindow(QWidget&, OutputHandle&) const override; void makeFullscreen(QWidget&) const override; + void removeFullscreen(QWidget&) const override; }; diff --git a/dspdfviewer.cpp b/dspdfviewer.cpp index 6c0871d0..25aec963 100644 --- a/dspdfviewer.cpp +++ b/dspdfviewer.cpp @@ -406,6 +406,9 @@ void DSPDFViewer::repositionWindows() { primaryOutput.swap( secondaryOutput ); } + desktopSupport->removeFullscreen( audienceWindow ); + desktopSupport->removeFullscreen( secondaryWindow ); + /** Primary Output: Built-in Laptop screen * This has the window for the presenter */ desktopSupport->moveWindow( secondaryWindow, *primaryOutput); From 6af2458633d26260d199511438e63d7044eaa3c1 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Fri, 8 Apr 2016 09:25:29 +0200 Subject: [PATCH 10/17] Move def. impl of makeFullscreen to DesktopSupport The simple forwarder to QWidget is generic enough to be moved inside DesktopSupport base class. Also, add a canMoveWindowWhileFullscreen() test to the implementations, and only if false dspdfviewer.cpp will un-fullscreen both windows before moving them. --- desktopsupport.cpp | 16 ++++++++++++++++ desktopsupport.h | 19 +++++++++++++++++-- desktopsupport/generic.cpp | 13 ------------- desktopsupport/generic.h | 5 +++-- desktopsupport/i3.h | 3 +++ desktopsupport/win32.cpp | 8 -------- desktopsupport/win32.h | 5 +++-- dspdfviewer.cpp | 23 +++++++++++++++++------ 8 files changed, 59 insertions(+), 33 deletions(-) diff --git a/desktopsupport.cpp b/desktopsupport.cpp index 6d48ddc5..2c9ce731 100644 --- a/desktopsupport.cpp +++ b/desktopsupport.cpp @@ -62,3 +62,19 @@ OutputPtr DesktopSupport::getSecondary(const DesktopSupportErrorHandling& err) c /** 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 index 5eeb5753..c6109da4 100644 --- a/desktopsupport.h +++ b/desktopsupport.h @@ -129,10 +129,25 @@ class DesktopSupport { * 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 void makeFullscreen(QWidget& window) const =0; + virtual bool canMoveWindowWhileFullscreen() const =0; - virtual void removeFullscreen(QWidget& window) 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 index fcc4a764..2f4665d7 100644 --- a/desktopsupport/generic.cpp +++ b/desktopsupport/generic.cpp @@ -32,19 +32,6 @@ OutputList GenericDesktopSupport::getOutputs() const { return vec; } -void GenericDesktopSupport::makeFullscreen(QWidget& window) const { - if ( window.isFullScreen() ) - return; - window.showNormal(); - window.showFullScreen(); -} - -void GenericDesktopSupport::removeFullscreen(QWidget& window) const { - if ( ! window.isFullScreen() ) - return; - window.showNormal(); -} - void GenericDesktopSupport::moveWindow(QWidget& window, OutputHandle& outhand) const { GenericOutputHandle& out = dynamic_cast(outhand); window.move( out.screenRect.topLeft() ); diff --git a/desktopsupport/generic.h b/desktopsupport/generic.h index 861ab134..7e5c5baa 100644 --- a/desktopsupport/generic.h +++ b/desktopsupport/generic.h @@ -37,6 +37,7 @@ class GenericDesktopSupport: public DesktopSupport { void moveWindow(QWidget&, OutputHandle&) const override; - void makeFullscreen(QWidget&) const override; - void removeFullscreen(QWidget&) const override; + bool canMoveWindowWhileFullscreen() const override { + return true; + } }; diff --git a/desktopsupport/i3.h b/desktopsupport/i3.h index 1cd11742..99a3f49b 100644 --- a/desktopsupport/i3.h +++ b/desktopsupport/i3.h @@ -20,6 +20,9 @@ class i3DesktopSupport: public DesktopSupport { void moveWindow(QWidget&, OutputHandle&) const override; void makeFullscreen(QWidget&) const override; void removeFullscreen(QWidget&) const override; + bool canMoveWindowWhileFullscreen() const { + return false; + } private: static const std::string getSocketpath(); }; diff --git a/desktopsupport/win32.cpp b/desktopsupport/win32.cpp index 62714980..d6a776e9 100644 --- a/desktopsupport/win32.cpp +++ b/desktopsupport/win32.cpp @@ -38,14 +38,6 @@ void Win32DesktopSupport::moveWindow(QWidget& window, OutputHandle& out) const { ); } -void Win32DesktopSupport::makeFullscreen(QWidget& window) const { - window.showFullScreen(); -} - -void Win32DesktopSupport::removeFullscreen(QWidget& window) const { - window.showNormal(); -} - std::string const Win32OutputHandle::name() const { std::ostringstream os; os << "Win32 Output [" << screenNumber << "]"; diff --git a/desktopsupport/win32.h b/desktopsupport/win32.h index 45fd58ad..325f2ce5 100644 --- a/desktopsupport/win32.h +++ b/desktopsupport/win32.h @@ -26,6 +26,7 @@ class Win32DesktopSupport: public DesktopSupport { } 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 true; + } }; diff --git a/dspdfviewer.cpp b/dspdfviewer.cpp index 25aec963..a0e60f21 100644 --- a/dspdfviewer.cpp +++ b/dspdfviewer.cpp @@ -406,8 +406,10 @@ void DSPDFViewer::repositionWindows() { primaryOutput.swap( secondaryOutput ); } - desktopSupport->removeFullscreen( audienceWindow ); - desktopSupport->removeFullscreen( secondaryWindow ); + if ( ! desktopSupport->canMoveWindowWhileFullscreen() ) { + desktopSupport->removeFullscreen( audienceWindow ); + desktopSupport->removeFullscreen( secondaryWindow ); + } /** Primary Output: Built-in Laptop screen * This has the window for the presenter */ @@ -426,13 +428,22 @@ void DSPDFViewer::repositionWindows() { * first (possibly disposable) and ensure the audience * gets the real fullscreen. */ - desktopSupport->makeFullscreen( secondaryWindow ); - desktopSupport->makeFullscreen( audienceWindow ); + + 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); - /** FIXME: Add configuration for non-fullscreen mode */ - desktopSupport->makeFullscreen( audienceWindow ); + if ( ! desktopSupport->canMoveWindowWhileFullscreen() ) { + /** FIXME: Add configuration for non-fullscreen mode */ + desktopSupport->makeFullscreen( audienceWindow ); + } } } From c64a0e53858024fb3b27a07403a3a36f09394d03 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Fri, 8 Apr 2016 10:03:34 +0200 Subject: [PATCH 11/17] i3: only check return value of i3 --get-socketpath --- desktopsupport/i3.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/desktopsupport/i3.cpp b/desktopsupport/i3.cpp index 5255ab52..fdac50da 100644 --- a/desktopsupport/i3.cpp +++ b/desktopsupport/i3.cpp @@ -1,20 +1,9 @@ #include "i3.h" #include "../debug.h" -#include -#include #include #include -#include -#include #include -namespace { - typedef std::unique_ptr< - FILE, - decltype(&pclose) - > FILEptr; -} - using namespace std; DesktopEnvironmentHandlerQuality i3DesktopSupport::quality() const { @@ -42,6 +31,7 @@ const std::string i3OutputHandle::name() const { 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) ); @@ -91,11 +81,13 @@ const string i3DesktopSupport::getSocketpath() { if ( ! spath.empty() ) { return spath; } - /** Socketpath not cached */ - /** FIXME: Port this to boost or similar */ - FILEptr fd( popen("i3 --get-socketpath", "r"), pclose ); + /** FIXME: Actually check the return STRING, not just the retval */ + int ret = system("i3 --get-socketpath"); + if ( ret == 0 ) { + spath = "OK"; + } - return "/run/user/1000/i3/ipc-socket.1468"; + return spath; } From 6c72240c24dd31245920cd53f7bfecd685a3d721 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Fri, 8 Apr 2016 11:23:57 +0200 Subject: [PATCH 12/17] i3: drop cache string --- desktopsupport/i3.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/desktopsupport/i3.cpp b/desktopsupport/i3.cpp index fdac50da..eb7a2155 100644 --- a/desktopsupport/i3.cpp +++ b/desktopsupport/i3.cpp @@ -76,18 +76,12 @@ void i3DesktopSupport::removeFullscreen(QWidget& w) const { const string i3DesktopSupport::getSocketpath() { - /** Cache for the socket path */ - static string spath; - if ( ! spath.empty() ) { - return spath; - } - /** FIXME: Actually check the return STRING, not just the retval */ int ret = system("i3 --get-socketpath"); if ( ret == 0 ) { - spath = "OK"; + return "OK"; } - return spath; + return string(); } From 7def6a29c446c6afecffabc3783249cfd51bedc2 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Fri, 20 May 2016 15:22:34 +0200 Subject: [PATCH 13/17] suspend rendering while swapping screens --- dspdfviewer.cpp | 4 ++++ pdfrenderfactory.cpp | 17 ++++++++++++++++- pdfrenderfactory.h | 3 +++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/dspdfviewer.cpp b/dspdfviewer.cpp index a0e60f21..5ade7e28 100644 --- a/dspdfviewer.cpp +++ b/dspdfviewer.cpp @@ -391,6 +391,7 @@ const QRect DSPDFViewer::secondGeometry() const { } void DSPDFViewer::repositionWindows() { + renderFactory.suspendRendering(); auto primaryOutput = desktopSupport->getPrimary(); /** Get secondary output only if we actually use @@ -446,4 +447,7 @@ void DSPDFViewer::repositionWindows() { desktopSupport->makeFullscreen( audienceWindow ); } } + + renderFactory.resumeRendering(); + renderPage(); } 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 From 217d70c95edb54f38e451c81268bf048fe13bd83 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Fri, 20 May 2016 15:23:41 +0200 Subject: [PATCH 14/17] rename .codecov.yml to codecov.yml It seems to get ignored when prefixed with a dot --- .codecov.yml => codecov.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .codecov.yml => codecov.yml (100%) diff --git a/.codecov.yml b/codecov.yml similarity index 100% rename from .codecov.yml rename to codecov.yml From 0f220d2ac98480e6607e0344ce47b209178c6390 Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Fri, 20 May 2016 15:25:20 +0200 Subject: [PATCH 15/17] include missing include desktopsupport.h uses std::string, but didn't include it --- desktopsupport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/desktopsupport.h b/desktopsupport.h index c6109da4..1a2a6b26 100644 --- a/desktopsupport.h +++ b/desktopsupport.h @@ -2,6 +2,7 @@ #include #include +#include #include #include "windowrole.h" From 85ec4bcfdbb3e79c654a8d98eacbee35c6cffe3b Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Fri, 20 May 2016 15:25:39 +0200 Subject: [PATCH 16/17] add missing override --- desktopsupport/i3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktopsupport/i3.h b/desktopsupport/i3.h index 99a3f49b..87261829 100644 --- a/desktopsupport/i3.h +++ b/desktopsupport/i3.h @@ -20,7 +20,7 @@ class i3DesktopSupport: public DesktopSupport { void moveWindow(QWidget&, OutputHandle&) const override; void makeFullscreen(QWidget&) const override; void removeFullscreen(QWidget&) const override; - bool canMoveWindowWhileFullscreen() const { + bool canMoveWindowWhileFullscreen() const override { return false; } private: From badc05e58ea60fc981be6c39c394ff31a895f1fa Mon Sep 17 00:00:00 2001 From: Danny Edel Date: Fri, 20 May 2016 16:23:21 +0200 Subject: [PATCH 17/17] Win32 support: Don't move fullscreen windows --- desktopsupport/win32.cpp | 4 ---- desktopsupport/win32.h | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/desktopsupport/win32.cpp b/desktopsupport/win32.cpp index d6a776e9..868ea086 100644 --- a/desktopsupport/win32.cpp +++ b/desktopsupport/win32.cpp @@ -29,10 +29,6 @@ OutputList Win32DesktopSupport::getOutputs() const { void Win32DesktopSupport::moveWindow(QWidget& window, OutputHandle& out) const { Win32OutputHandle& h=dynamic_cast(out); - /** Un-fullscreen the window, to be sure we're allowed to move it */ - if ( window.isFullScreen() ) { - window.showNormal(); - } window.windowHandle()->setScreen( QApplication::screens().at( h.screenNumber ) ); diff --git a/desktopsupport/win32.h b/desktopsupport/win32.h index 325f2ce5..f2d15640 100644 --- a/desktopsupport/win32.h +++ b/desktopsupport/win32.h @@ -27,6 +27,6 @@ class Win32DesktopSupport: public DesktopSupport { OutputList getOutputs() const override; void moveWindow(QWidget&, OutputHandle&) const override; bool canMoveWindowWhileFullscreen() const override { - return true; + return false; } };