├── CHANGELOG.md ├── CMakeLists.txt ├── COPYING ├── INSTALL ├── README.md ├── _travis └── osx-install-dependencies ├── adjustedlink.cpp ├── adjustedlink.h ├── cmake ├── compiler_appleclang.cmake ├── compiler_clang.cmake ├── compiler_gnu_gcc.cmake ├── compiler_msvc.cmake ├── compiler_unknown.cmake ├── compilers.cmake ├── external_libraries.cmake ├── filelists.cmake ├── platforms.cmake ├── qrc_embedding.cmake └── version_number.cmake ├── debug.h ├── docs ├── .bundle │ └── config ├── CNAME ├── Gemfile ├── Gemfile.lock ├── Makefile ├── README.md ├── Windows │ ├── Help.hhp │ ├── TOC.hhc │ ├── bugs.html │ ├── controls.html │ ├── description.html │ ├── files.html │ ├── license.html │ ├── name.html │ ├── options.html │ ├── presenter.html │ ├── seealso.html │ ├── style.css │ └── synopsis.html ├── _config.yml ├── _includes │ ├── html_footer.html │ └── html_header.html ├── _layouts │ └── default.html ├── _sass │ ├── _page-generator.scss │ └── _rouge.scss ├── css │ ├── pygments.css │ └── styles.scss ├── index.md ├── installation │ ├── arch.md │ ├── daily-deb.md │ ├── debian.md │ ├── gentoo.md │ ├── index.md │ ├── macos.md │ ├── source │ │ ├── dependencies.md │ │ ├── git.md │ │ ├── options.md │ │ └── stable.md │ ├── ubuntu.md │ ├── ubuntu │ │ └── ppa.md │ └── windows.md ├── manpage-release.html ├── manpage.html └── robots.txt ├── dspdfviewer.1 ├── dspdfviewer.cpp ├── dspdfviewer.desktop ├── dspdfviewer.h ├── dspdfviewer.qrc ├── hyperlinkarea.cpp ├── hyperlinkarea.h ├── keybindings.ui ├── main.cpp ├── pagepart.cpp ├── pagepart.h ├── pdfcacheoption.h ├── pdfdocumentreference.cpp ├── pdfdocumentreference.h ├── pdfpagereference.cpp ├── pdfpagereference.h ├── pdfrenderfactory.cpp ├── pdfrenderfactory.h ├── pdfviewerwindow.cpp ├── pdfviewerwindow.h ├── pdfviewerwindow.ui ├── poppler-qt.h ├── renderedpage.cpp ├── renderedpage.h ├── renderingidentifier.cpp ├── renderingidentifier.h ├── renderthread.cpp ├── renderthread.h ├── renderutils.cpp ├── renderutils.h ├── runtimeconfiguration.cpp ├── runtimeconfiguration.h ├── sconnect.h ├── testing ├── CMakeLists.txt ├── pdfs │ ├── colored-rectangles.pdf │ ├── colored-rectangles.tex │ ├── images.pdf │ ├── images.tex │ ├── jpeg-image.jpg │ ├── many-many-pages.pdf │ ├── many-many-pages.tex │ └── png-image.png ├── test-images.cc ├── test-thumbnail-cmdline.cc ├── testhelpers.cc ├── testhelpers.hh ├── testrenderonepage.cc ├── testrunner.cc ├── testswapscreen-main.cc ├── testswapscreen.cc ├── testswapscreen.h └── xorg.conf ├── translations └── dspdfviewer_de.ts ├── windowrole.cpp └── windowrole.h /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | dspdfviewer changelog 2 | ===================== 3 | 4 | This file aims to record all user relevant changes to dspdfviewer. 5 | 6 | If you're intrested in the specific source-level changes between versions, 7 | or non user-relevant changes (like build system or packaging related), please 8 | inspect the output of commands like `git diff -w v1.11..v1.12` directly. 9 | 10 | v1.15.2 - UNRELEASED 11 | -------------------- 12 | 13 | This is a maintenance release, not introducing any new functionality, 14 | but restoring compatibility with Qt 5.15 LTS. 15 | 16 | Building with Qt4 is no longer supported. If you really need Qt4 17 | support, please get in touch. 18 | 19 | 20 | v1.15.1 - 2016-09-13 21 | -------------------- 22 | 23 | Bugfix: 24 | 25 | * No longer advances two slides on mouse wheel when 26 | used with recent Qt5. Thanks to @nbecker for reporting 27 | this on GitHub. 28 | 29 | 30 | v1.15 - 2016-04-05 31 | ------------------ 32 | 33 | Changes in behaviour: 34 | 35 | * When compiling dspdfviewer yourself: 36 | * You must now execute the testsuite within a running X Server 37 | (Linux) or within a graphical environment (Windows/OSX). 38 | It will no longer try to set up one on its own. 39 | * The testsuite expects two screens to be connected by default. 40 | If your environment only has one screen, you can pass 41 | -DRunDualScreenTests=OFF at CMake time to avoid a test failure. 42 | * Instead of offering pre-rendered PDFs for download, they are now 43 | included in the source tree. The option `DownloadTestPDF` has 44 | been replaced with `UsePrerenderedPDF` accordingly. 45 | * Qt5 is now the default. If you want to build against Qt4, 46 | you will have to pass -DUseQtFive=OFF to CMake. 47 | Note that Qt4 support is now considered deprecated and will be 48 | removed in one of the next versions. Please file a bug if your 49 | system does not work correctly with Qt5. 50 | 51 | New features: 52 | 53 | * Predictable memory usage and configurable cache size limit 54 | * Previously, dspdfviewer allowed to cache 100 images. It did not 55 | matter whether these where thumbnails or full pages, resulting in 56 | unpredictable memory usage. 57 | * Now you can specify memory limit for the cache in MiB, using 58 | the command-line parameter --cache-size. The default value 1024 59 | is normally fine, setting is below 250 will result in severe 60 | performance crippling. 61 | * This only affects the *cache* memory. The total memory usage of 62 | dspdfviewer can be up to 300M higher, mainly depending on whether 63 | the shared libraries (poppler/qt) are also used by other programs, 64 | or are specifically loaded for dspdfviewer. 65 | 66 | Other: 67 | 68 | * A lot of work has gone into the Windows port, and compiling on 69 | Windows with MSVC is now part of the automated testing. 70 | * The testsuite is currently disabled on big-endian machines. 71 | It keeps failing with what appears to be an endian issue. 72 | If you want to help out, you can force the testsuite to run 73 | by passing -DRunTestsOnBigEndian=ON at cmake time. 74 | 75 | 76 | v1.14 - 2015-12-01 77 | ------------------ 78 | 79 | New features: 80 | 81 | * Translation support 82 | * For now, a german translation is included, thanks to projekter. 83 | * Experimental i3 support 84 | * If you specify the --i3-workaround=true option, dspdfviewer will try to 85 | use i3-cmd to move the audience window one screen to the right. 86 | * This code is not well tested, please leave feedback and suggestions. 87 | * Add support for Qt5 88 | * Add support for Windows, thanks to projekter. 89 | 90 | 91 | v1.13.1 - 2015-08-06 92 | -------------------- 93 | 94 | This is a bugfix and maintenance release for v1.13. 95 | 96 | Bugfixes: 97 | 98 | * Regression: Changing slide while blanked crashed the program 99 | 100 | Other: 101 | 102 | * A `dspdfviewer.desktop` file has been added, helping desktop enviroments 103 | to include the program in their menus 104 | * `dspdfviewer --help` informs about the manpage and the F1 help box 105 | * This changelog has been started, listing changes since v1.8. 106 | 107 | 108 | 109 | v1.13 - 2015-07-30 110 | ------------------ 111 | 112 | New features: 113 | 114 | * dspdfviewer will open a file chooser dialog when started without a 115 | command-line file parameter (instead of aborting with error message) 116 | * Hyperlinks between pages are now clickable 117 | * The height of the bottom pane (thumbnails and clocks) on the second 118 | screen can now be configured 119 | 120 | 121 | 122 | v1.12 - 2015-07-23 123 | ------------------ 124 | 125 | New features: 126 | 127 | * Added support for the Logitech R400 presenter remote control. 128 | * Secondary screen can be toggled between notes and main presentation. 129 | * `F1` or `?` key show a quick help box. 130 | * A configuration file at `~/.config/dspdfviewer.ini` can now be 131 | used in addition to command-line parameters. 132 | 133 | 134 | 135 | v1.11 - 2014-07-12 136 | ------------------ 137 | 138 | New features: 139 | 140 | * The window for the presenter now spawns on the primary screen 141 | (see `man xrandr` on how to define this) which is assumed to be 142 | the notebook you carry to the presenation site. 143 | * The windows now have different window titles and window roles. 144 | This enables scripting, especially useful on tiling window managers. 145 | * dspdfviewer will now watch the file on disk and re-read when it changes. 146 | This is useful if you're using dspdfviewer as a previewer while 147 | writing a presentation. 148 | 149 | 150 | 151 | v1.10.1 - 2013-10-22 152 | -------------------- 153 | 154 | This is a bugfix and maintenance release for 1.10. 155 | 156 | Bugfixes: 157 | 158 | * Regression: Primary and secondary window could not be swapped on Kubuntu 13.10. 159 | 160 | 161 | 162 | 1.10 - 2013-03-25 163 | ----------------- 164 | 165 | Improvement: 166 | 167 | * Speed up initial rendering 168 | 169 | 170 | 171 | 1.9 - 2013-01-23 172 | ---------------- 173 | 174 | New feature: 175 | 176 | * The "go to" command (`G`) now displays the range of valid page numbers 177 | 178 | 179 | 180 | 1.8 - 2012-12-11 181 | ---------------- 182 | 183 | Initial *free and open source software* release: 184 | 185 | * dspdfviewer is now distributed under the GNU GPL, version 2, or 186 | (at your option) any later version. 187 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # /* 2 | # dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | # Copyright (C) 2012 Danny Edel 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License along 16 | # with this program; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | # */ 19 | cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) 20 | if( NOT CMAKE_VERSION VERSION_LESS 3.1) 21 | cmake_policy(SET CMP0054 NEW) # dont expand quoted strings in if()s 22 | endif() 23 | if( NOT CMAKE_VERSION VERSION_LESS 3.10) 24 | cmake_policy(SET CMP0071 NEW) # Also process generated source files with MOC 25 | endif() 26 | if( NOT CMAKE_VERSION VERSION_LESS 3.17) 27 | cmake_policy(SET CMP0100 NEW) # Allow .hh extension 28 | endif() 29 | 30 | project(dspdfviewer) 31 | 32 | include(FindPkgConfig) 33 | set(CMAKE_AUTOMOC ON)# 34 | set(CMAKE_AUTORCC OFF) 35 | set(CMAKE_INCLUDE_CURRENT_DIR OFF) 36 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 37 | 38 | option(UpdateTranslations "Do you want to update the .ts files (WARNING: running make clean will delete them!)" OFF) 39 | option(BuildTests "Build unit tests (this requires pdflatex or internet access and DownloadTestPDFs=ON)" ON) 40 | option(RunDualScreenTests "Also run tests that require two screens to be connected" ON) 41 | option(RunTestsOnBigEndian "Run tests on a big-endian system" OFF) 42 | option(BoostStaticLink "Link statically against the boost libraries" OFF) 43 | option(WindowsStaticLink "Windows/MSVC only: Link statically against the dependencies and set /MT instead of /MD" ON) 44 | option(UsePrerenderedPDF "Use prerendered PDFs included in the source for testing, instead of building with pdflatex" OFF) 45 | option(CodeCoverage "Add coverage analysis code to the program. Will slow it down. A lot. Only supported on GCC right now." OFF) 46 | option(WarningAsError "Turn on -Werror and similar compiler settings. This can be useful during development, but is disabled by default for release build scripts." OFF) 47 | 48 | include(cmake/platforms.cmake) 49 | include(cmake/filelists.cmake) 50 | include(cmake/external_libraries.cmake) 51 | include(cmake/qrc_embedding.cmake) 52 | include(cmake/compilers.cmake) 53 | include(cmake/version_number.cmake) 54 | 55 | 56 | if( I3WORKAROUND_SHELLCODE ) 57 | add_definitions(-DI3WORKAROUND_SHELLCODE="${I3WORKAROUND_SHELLCODE}") 58 | endif() 59 | 60 | include_directories(SYSTEM ${LIST_INCLUDE_DIRS}) 61 | 62 | ### Compile all the source code into one .a file 63 | 64 | add_library(libdspdfviewer ${libdspdfviewer_SRCS} ${dspdfviewer_UIS_H} ${TRANSLATIONS}) 65 | # Set target name to "libdspdfviewer" 66 | # without a prefix (normally unix would auto-add lib...) 67 | set_target_properties(libdspdfviewer PROPERTIES 68 | PREFIX "" 69 | ) 70 | target_link_libraries(libdspdfviewer ${LIST_LIBRARIES}) 71 | 72 | ### And link it together with main.cpp to produce an executable 73 | add_executable(dspdfviewer ${dspdfviewer_SRCS} ${EMBEDDED_QRC}) 74 | target_link_libraries(dspdfviewer libdspdfviewer) 75 | 76 | ### ... and link it with the tests to produce a testing executable. 77 | if(BuildTests) 78 | # Run unit tests regardless of debug/release 79 | # Set a default timeout to 60 seconds 80 | set(DART_TESTING_TIMEOUT 60) 81 | set(CTEST_TEST_TIMEOUT 60) 82 | # Check for big endian 83 | include(TestBigEndian) 84 | TEST_BIG_ENDIAN(BigEndian) 85 | if( NOT BigEndian OR RunTestsOnBigEndian) 86 | include(CTest) 87 | add_subdirectory(testing) 88 | else() 89 | message(WARNING "The unit tests have been temporarily disabled on big-endian " 90 | "systems. If you want to help in debugging this, please pass " 91 | "-DRunTestsOnBigEndian=ON to cmake to force their execution.") 92 | endif() 93 | endif() 94 | 95 | #### Installation 96 | 97 | install(TARGETS dspdfviewer 98 | RUNTIME DESTINATION bin) 99 | 100 | install(FILES dspdfviewer.1 101 | DESTINATION share/man/man1) 102 | 103 | install(FILES dspdfviewer.desktop 104 | DESTINATION share/applications) 105 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | How to install the dspdfviewer 2 | ============================== 3 | 4 | 5 | 6 | System-specific installation instructions 7 | ----------------------------------------- 8 | 9 | Please refer to the project's website for installation instructions, 10 | broken down by operating system. 11 | 12 | At least for Debian, Ubuntu, Gentoo, Arch, MacOS and Windows the website 13 | contains specific installation instructions. For some systems, 14 | ready-made binaries are provided. 15 | 16 | http://dspdfviewer.danny-edel.de 17 | 18 | 19 | 20 | Installation from source (generic cmake) 21 | ---------------------------------------- 22 | dspdfviewer requires the following build-time dependencies: 23 | * cmake 24 | * boost 25 | * qt5 26 | * poppler-qt5 27 | 28 | From inside the source directory, execute the following steps: 29 | 30 | mkdir build 31 | cd build 32 | cmake .. 33 | make 34 | (as root) make install 35 | 36 | Note that there is no make uninstall, so please redirect the make install 37 | step through your system's package management utility. The 38 | "cmake" step will respect --prefix= parameters, and "make install" 39 | will respect DESTDIR. 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dual-Screen PDF Viewer for latex-beamer 2 | 3 | [![Build Status](https://travis-ci.org/dannyedel/dspdfviewer.svg?branch=master)](https://travis-ci.org/dannyedel/dspdfviewer) 4 | 5 | This is a simple viewer for latex-beamer presentations that are built 6 | with the **show notes on second screen** option of latex-beamer. 7 | 8 | It will take your PDF file, split it in a left and right half and 9 | render the two halves individually to the screens. 10 | 11 | ## Usage 12 | There is a manpage included that explains all the options and keybindings. Most important ones are probably: 13 | 14 | Command line: 15 | 16 | dspdfviewer [options] *pdf-file* 17 | 18 | where the most useful option is probably -f, because it enables you to use the software with a standard pdf (i.e. not specifically built for latex-beamer). 19 | 20 | In-Program-Controls: 21 | 22 | Left/Right, Mouse Buttons or Mouse Wheel: Back/Forward 23 | 24 | S or F12: Swap screens (if you see the wall clock on the projector) 25 | 26 | B or . (period): blank/unblank audience screen 27 | 28 | Q/Esc: Quit 29 | 30 | ## Installation 31 | 32 | Please read the [installation section] on the project's website for 33 | detailed instructions, broken down by operating system. 34 | 35 | For generic from-source installation instructions, you can also consult 36 | the INSTALL file. 37 | 38 | [installation section]: http://dspdfviewer.danny-edel.de/#how-do-i-install-it 39 | -------------------------------------------------------------------------------- /_travis/osx-install-dependencies: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Exit in case of an error, and show the steps 4 | set -ex 5 | 6 | # Travis recommends to run homebrew update 7 | brew update > /dev/null 8 | if [ "$QT_VERSION" -eq 5 ] ; then 9 | brew install poppler --with-qt5 10 | else 11 | brew install poppler --with-qt 12 | fi 13 | -------------------------------------------------------------------------------- /adjustedlink.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2012 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #include "adjustedlink.h" 22 | 23 | #include 24 | #include 25 | using boost::numeric_cast; 26 | 27 | QSharedPointer< Poppler::Link > AdjustedLink::link() const 28 | { 29 | return m_link; 30 | } 31 | 32 | QRectF AdjustedLink::linkArea() const 33 | { 34 | QRectF const& orig( link()->linkArea() ); 35 | QRectF retval( link()->linkArea() ); 36 | switch(ri.pagePart()) { 37 | case PagePart::FullPage: 38 | break; 39 | case PagePart::LeftHalf: 40 | if ( retval.left() > 0.5 ) { 41 | return QRectF(); 42 | } 43 | retval.setLeft( orig.left() * 2.0 ); 44 | retval.setWidth( orig.width() * 2.0 ); 45 | break; 46 | case PagePart::RightHalf: 47 | if ( retval.right() < 0.5 ) { 48 | // no part of the rectangle is in our page 49 | return QRectF(); 50 | } 51 | retval.setLeft( (orig.left() - 0.5) * 2.0 ); 52 | retval.setWidth( orig.width() * 2.0 ); 53 | break; 54 | } 55 | 56 | if ( retval.height() < 0 ) { 57 | retval.setHeight( -retval.height() ); 58 | retval.moveTop( retval.top() - retval.height()); 59 | } 60 | 61 | return retval; 62 | 63 | } 64 | 65 | Poppler::Link::LinkType AdjustedLink::linkType() const 66 | { 67 | return link()->linkType(); 68 | } 69 | 70 | 71 | AdjustedLink::AdjustedLink(const RenderingIdentifier& renderIdent, QSharedPointer< Poppler::Link > link) 72 | : m_link(link), ri(renderIdent) 73 | { 74 | if ( linkArea().isNull() ) 75 | throw OutsidePage(); 76 | } 77 | 78 | 79 | AdjustedLink::OutsidePage::OutsidePage(): runtime_error("This link is not inside the current page part") 80 | { 81 | } 82 | 83 | 84 | uint AdjustedLink::targetPageNumber() const 85 | { 86 | /* Although page numbers in a PDF are non-negative, poppler's pageNumber 87 | * is a signed integer. 88 | * 89 | * numeric_cast checks that the number actually *is* non-negative. 90 | */ 91 | return numeric_cast(lgt().destination().pageNumber()) -1u; 92 | } 93 | 94 | 95 | Poppler::LinkGoto const& AdjustedLink::lgt() const 96 | { 97 | return dynamic_cast( *m_link ); 98 | } 99 | -------------------------------------------------------------------------------- /adjustedlink.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2012 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #ifndef ADJUSTEDLINK_H 22 | #define ADJUSTEDLINK_H 23 | #include "renderingidentifier.h" 24 | #include 25 | #include "poppler-qt.h" 26 | 27 | #include 28 | 29 | /** Link that is adjusted to a rendered page. 30 | * This includes failing to construct if it is completely outside the scope. 31 | */ 32 | class AdjustedLink 33 | { 34 | public: 35 | /** Exception class */ 36 | struct OutsidePage: public std::runtime_error { 37 | OutsidePage(); 38 | }; 39 | 40 | /** Exception class */ 41 | struct UnsupportedLinkType{}; 42 | 43 | AdjustedLink(const RenderingIdentifier& renderIdent, QSharedPointer link); 44 | 45 | /** Returns the link area as floating point in the range 0..1 **/ 46 | QRectF linkArea() const; 47 | 48 | /** Returns the link area, but scaled to the given QRectangle **/ 49 | QRect linkArea(const QRect& rect) const; 50 | 51 | /** Target page number */ 52 | uint targetPageNumber() const; 53 | 54 | /** Returns a shared pointer to the Poppler link 55 | */ 56 | QSharedPointer link() const; 57 | 58 | /** Forwarding function for Poppler::Link::LinkType **/ 59 | Poppler::Link::LinkType linkType() const; 60 | 61 | private: 62 | QSharedPointer m_link; 63 | RenderingIdentifier ri; 64 | 65 | Poppler::LinkGoto const& lgt() const; 66 | }; 67 | 68 | 69 | #endif // ADJUSTEDLINK_H 70 | -------------------------------------------------------------------------------- /cmake/compiler_appleclang.cmake: -------------------------------------------------------------------------------- 1 | message(WARNING "Optimal settings for AppleClang unknown, send pull-requests!") 2 | message(STATUS "Including definitions for clang.") 3 | include(cmake/compiler_clang.cmake) 4 | 5 | # error: include location '/usr/local/include' is unsafe for cross-compilation 6 | add_definitions(-Wno-error=poison-system-directories) 7 | -------------------------------------------------------------------------------- /cmake/compiler_clang.cmake: -------------------------------------------------------------------------------- 1 | # CMake fragment 2 | 3 | # Clang 4 | add_definitions("-std=c++11") 5 | 6 | # Turn on a lot of warnings, hopefully helping with code quality. 7 | add_definitions(-Weverything) 8 | 9 | # Disable warnings irrelevant to the project: 10 | # c++98 compatibility warnings 11 | add_definitions(-Wno-c++98-compat -Wno-c++98-compat-pedantic) 12 | 13 | # Currently this warning triggers in exception classes 14 | add_definitions(-Wno-error=weak-vtables) 15 | 16 | # We don't care about padding right now. 17 | add_definitions(-Wno-padded) 18 | 19 | # in release mode: Unrechable code / Macro expansion (these stem from QDEBUG) 20 | # trigger a lot (QDEBUG compiles into the equivalent of while(false) { ... } ) 21 | # So these are safe to ignore IFF we're not in Debug mode. 22 | if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug" ) 23 | add_definitions(-Wno-unreachable-code -Wno-disabled-macro-expansion) 24 | endif() 25 | 26 | if(WarningAsError) 27 | # Turn warnings into errors. 28 | add_definitions(-Werror) 29 | 30 | # Qt's moc (Meta Object Compiler) generates code that triggers warnings 31 | # about undefined behaviours. 32 | 33 | # So don't set Werror for it. 34 | # FIXME: Set this only for the automoc files 35 | add_definitions(-Wno-error=undefined-reinterpret-cast) 36 | add_definitions(-Wno-error=redundant-parens) 37 | add_definitions(-Wno-error=extra-semi-stmt) 38 | 39 | # FIXME: These are apple-clang specific 40 | add_definitions(-Wno-error=poison-system-directories) 41 | add_definitions("-Wno-error=#warnings") 42 | 43 | # Clang on recent XCode fails to compile the boost tests 44 | add_definitions(-Wno-error=disabled-macro-expansion) 45 | 46 | # unit_test_log from boost::test will trigger this warning 47 | add_definitions(-Wno-error=used-but-marked-unused) 48 | endif() 49 | # clang will complain about -isystem passed but not used. 50 | # This adds unnecessary noise 51 | add_definitions(-Wno-unused-command-line-argument) 52 | 53 | 54 | # qrc system generates code that triggers a lot of the 55 | # clang warnings. 56 | set_source_files_properties( ${EMBEDDED_QRC} 57 | PROPERTIES COMPILE_FLAGS "-Wno-error") 58 | 59 | if(CodeCoverage) 60 | add_definitions(--coverage -O0) 61 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") 62 | endif() 63 | -------------------------------------------------------------------------------- /cmake/compiler_gnu_gcc.cmake: -------------------------------------------------------------------------------- 1 | # GNU GCC 2 | 3 | include(CheckCXXCompilerFlag) 4 | 5 | CHECK_CXX_COMPILER_FLAG("-std=c++20" C20FLAG) 6 | CHECK_CXX_COMPILER_FLAG("-std=c++17" C17FLAG) 7 | CHECK_CXX_COMPILER_FLAG("-std=c++14" C14FLAG) 8 | CHECK_CXX_COMPILER_FLAG("-std=c++11" C11FLAG) 9 | if(C20FLAG) 10 | message(STATUS "Compiler supports -std=c++20, using it.") 11 | add_definitions(-std=c++20) 12 | elseif(C17FLAG) 13 | message(STATUS "Compiler supports -std=c++17, using it.") 14 | add_definitions(-std=c++17) 15 | elseif(C14FLAG) 16 | message(STATUS "Compiler supports -std=c++14, using it.") 17 | add_definitions(-std=c++14) 18 | elseif(C11FLAG) 19 | message(STATUS "Compiler supports -std=c++11, using it.") 20 | add_definitions(-std=c++11) 21 | else() 22 | message(WARNING "Compiler does not support -std=c++11, trying c++0x") 23 | CHECK_CXX_COMPILER_FLAG("-std=c++0x" C0XFLAG) 24 | if(C0XFLAG) 25 | message(STATUS "Using -std=c++0x") 26 | add_definitions(-std=c++0x) 27 | else() 28 | message(FATAL_ERROR "Compiler does not support -std=c++0x either. " 29 | "Please upgrade your compiler." 30 | ) 31 | endif() 32 | endif() 33 | 34 | # Set as much warnings as possible. 35 | add_definitions( 36 | -Wall 37 | -Wextra 38 | -pedantic 39 | -Wold-style-cast 40 | -Woverloaded-virtual 41 | -Weffc++ 42 | ) 43 | 44 | if(WarningAsError) 45 | # Turn all warnings into errors 46 | add_definitions(-Werror -pedantic-errors) 47 | endif() 48 | 49 | if(CodeCoverage) 50 | message(STATUS "Adding gcov as test coverage helper") 51 | add_definitions(-fprofile-arcs -ftest-coverage -O0) 52 | LIST(APPEND LIST_LIBRARIES 53 | gcov 54 | ) 55 | endif() 56 | -------------------------------------------------------------------------------- /cmake/compiler_msvc.cmake: -------------------------------------------------------------------------------- 1 | # MSVC 2 | 3 | foreach(var 4 | CMAKE_C_FLAGS 5 | CMAKE_C_FLAGS_DEBUG 6 | CMAKE_C_FLAGS_RELEASE 7 | CMAKE_C_FLAGS_MINSIZEREL 8 | CMAKE_C_FLAGS_RELWITHDEBINFO 9 | CMAKE_CXX_FLAGS 10 | CMAKE_CXX_FLAGS_DEBUG 11 | CMAKE_CXX_FLAGS_RELEASE 12 | CMAKE_CXX_FLAGS_MINSIZEREL 13 | CMAKE_CXX_FLAGS_RELWITHDEBINFO 14 | ) 15 | if(WindowsStaticLink) 16 | if(${var} MATCHES "/MD") 17 | string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}") 18 | endif() 19 | add_definitions(-DWINDOWS_STATIC_LINK) 20 | endif() 21 | endforeach() 22 | -------------------------------------------------------------------------------- /cmake/compiler_unknown.cmake: -------------------------------------------------------------------------------- 1 | # CMake framgent: unknown compiler 2 | 3 | # Let's hops this works. 4 | 5 | add_definitions(-std=c++11) 6 | include_directories(${LIST_INCLUDE_DIRS}) 7 | -------------------------------------------------------------------------------- /cmake/compilers.cmake: -------------------------------------------------------------------------------- 1 | # cmake fragment 2 | 3 | # Compiler support 4 | 5 | if(CMAKE_COMPILER_IS_GNUCXX) 6 | message(STATUS "GNU G++ detected.") 7 | include(cmake/compiler_gnu_gcc.cmake) 8 | 9 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") 10 | message(STATUS "AppleClang detected.") 11 | include(cmake/compiler_appleclang.cmake) 12 | 13 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 14 | message(STATUS "Clang++ detected.") 15 | include(cmake/compiler_clang.cmake) 16 | 17 | elseif(MSVC) 18 | message(STATUS "MSVC detected.") 19 | include(cmake/compiler_msvc.cmake) 20 | 21 | else() 22 | # Unknown Compiler 23 | message(WARNING "You are using an unidentified and therefore unsupported compiler. " 24 | " If this works for you, please report that to upstream and - if possible -" 25 | " please send patches activating sensible compile flags on it.") 26 | include(cmake/compiler_unknown.cmake) 27 | endif() 28 | 29 | # 30 | ### Common for all compilers 31 | # 32 | 33 | # Add -DQT_NO_DEBUG_OUTPUT to Release 34 | # and Release with Debug Info builds 35 | 36 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DQT_NO_DEBUG_OUTPUT") 37 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DQT_NO_DEBUG_OUTPUT") 38 | 39 | # This helps with translation, since it disables QString(const char*) 40 | add_definitions(-DQT_NO_CAST_FROM_ASCII) 41 | -------------------------------------------------------------------------------- /cmake/external_libraries.cmake: -------------------------------------------------------------------------------- 1 | # cmake frament 2 | 3 | # External libraries 4 | 5 | 6 | ### Boost Libraries ### 7 | 8 | if( BoostStaticLink ) 9 | set(Boost_USE_STATIC_LIBS ON) 10 | if(WindowsStaticLink) 11 | set(Boost_USE_STATIC_RUNTIME ON) 12 | endif() 13 | elseif(BuildTests) 14 | add_definitions(-DBOOST_TEST_DYN_LINK) 15 | endif() 16 | 17 | if(BuildTests) 18 | # If we're building tests, we need program_options 19 | # AND unit_test_framework 20 | find_package(Boost 21 | COMPONENTS program_options unit_test_framework 22 | REQUIRED) 23 | else() 24 | # No unit tests: Only program_options needed 25 | find_package(Boost 26 | COMPONENTS program_options 27 | REQUIRED) 28 | endif() 29 | 30 | 31 | # Qt5 32 | message(STATUS "Using Qt5 and libpoppler-qt5") 33 | if(MSVC AND WindowsStaticLink) 34 | # If linking statically, 35 | # Try to find Qt in /qt/static/qtbase 36 | # or plain /qt/static 37 | set(CMAKE_PREFIX_PATH 38 | "/Qt/static/qtbase;/Qt/static;/Qt/static/qttools;${CMAKE_PREFIX_PATH}") 39 | endif() 40 | find_package(Qt5Core 5.1.1 REQUIRED) 41 | # On lower versions, QTBUG-32100 prevents compilation at least on clang 42 | # https://bugreports.qt.io/browse/QTBUG-32100 43 | find_package(Qt5Gui REQUIRED) 44 | find_package(Qt5Widgets REQUIRED) 45 | find_package(Qt5LinguistTools REQUIRED) 46 | find_package(Qt5Xml REQUIRED) 47 | message(STATUS "Found Qt5 at ${Qt5Core_DIR}") 48 | 49 | if(MSVC) 50 | if (WindowsStaticLink) 51 | set(POPPLER_LIBRARIES 52 | ${WINDOWS_PRECOMPILED_STATIC_LIBRARIES} 53 | ) 54 | set(POPPLER_INCLUDE_DIRS 55 | "C:/dspdf/poppler/poppler/include/poppler/qt5" 56 | ) 57 | else() # MSVC, but not statically linking 58 | set(POPPLER_LIBRARIES 59 | ${WINDOWS_PRECOMPILED_DYNAMIC_LIBRARIES} 60 | ) 61 | set(POPPLER_INCLUDE_DIRS 62 | "C:/dspdf/popplerDyn/poppler/include/poppler/qt5" 63 | ) 64 | endif() 65 | else() 66 | # Non-MSVC Platforms: 67 | # Find poppler using pkg-config 68 | pkg_search_module(POPPLER REQUIRED poppler-qt5) 69 | endif() 70 | 71 | # add their link flags 72 | list(APPEND LIST_LIBRARIES 73 | ${Qt5Core_LIBRARIES} 74 | ${Qt5Gui_LIBRARIES} 75 | ${Qt5Widgets_LIBRARIES} 76 | ${Qt5LinguistTools_LIBRARIES} 77 | ${Qt5Xml_LIBRARIES} 78 | ) 79 | 80 | # add their include directories 81 | list(APPEND LIST_INCLUDE_DIRS 82 | ${Qt5Core_INCLUDE_DIRS} 83 | ${Qt5Gui_INCLUDE_DIRS} 84 | ${Qt5Widgets_INCLUDE_DIRS} 85 | ${Qt5LinguistTools_INCLUDE_DIRS} 86 | ${Qt5Xml_INCLUDE_DIRS} 87 | ) 88 | 89 | # Set conditional compilation to Qt5 mode 90 | add_definitions(-DPOPPLER_QT5) 91 | qt5_wrap_ui(dspdfviewer_UIS_H ${UIFILES}) 92 | if( UpdateTranslations ) 93 | qt5_create_translation(TRANSLATIONS 94 | ${libdspdfviewer_SRCS} ${dspdfviewer_SRCS} ${UIFILES} ${TRANSLATIONFILES} 95 | OPTIONS -no-obsolete 96 | ) 97 | else() 98 | qt5_add_translation(TRANSLATIONS ${TRANSLATIONFILES}) 99 | endif() 100 | 101 | # include/link poppler 102 | link_directories(${POPPLER_LIBRARY_DIRS}) 103 | list(APPEND LIST_LIBRARIES ${POPPLER_LIBRARIES}) 104 | list(APPEND LIST_INCLUDE_DIRS ${POPPLER_INCLUDE_DIRS}) 105 | 106 | list(APPEND LIST_INCLUDE_DIRS ${Boost_INCLUDE_DIRS}) 107 | list(APPEND LIST_LIBRARIES ${Boost_PROGRAM_OPTIONS_LIBRARY}) 108 | if(BuildTests) 109 | list(APPEND LIST_TEST_LIBRARIES ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) 110 | endif() 111 | 112 | # This is needed for moc/uic results 113 | list(APPEND LIST_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}) 114 | -------------------------------------------------------------------------------- /cmake/filelists.cmake: -------------------------------------------------------------------------------- 1 | # CMake file fragment 2 | 3 | # File lists 4 | 5 | list(APPEND TRANSLATIONFILES 6 | translations/dspdfviewer_de.ts 7 | ) 8 | 9 | list(APPEND UIFILES 10 | pdfviewerwindow.ui 11 | keybindings.ui 12 | ) 13 | 14 | list(APPEND libdspdfviewer_SRCS 15 | adjustedlink.cpp 16 | hyperlinkarea.cpp 17 | pdfpagereference.cpp 18 | pdfdocumentreference.cpp 19 | runtimeconfiguration.cpp 20 | renderutils.cpp 21 | renderthread.cpp 22 | renderingidentifier.cpp 23 | pagepart.cpp 24 | renderedpage.cpp 25 | pdfrenderfactory.cpp 26 | pdfviewerwindow.cpp 27 | dspdfviewer.cpp 28 | windowrole.cpp 29 | ) 30 | 31 | list(APPEND dspdfviewer_SRCS 32 | main.cpp 33 | ) 34 | 35 | list(APPEND QRCFILES 36 | dspdfviewer.qrc 37 | ) 38 | 39 | list(APPEND UIFILES 40 | pdfviewerwindow.ui 41 | keybindings.ui 42 | ) 43 | 44 | # Windows file lists: 45 | # Dynamic and static precompiled dependencies 46 | 47 | list(APPEND WINDOWS_PRECOMPILED_STATIC_LIBRARIES 48 | optimized "C:/dspdf/poppler/poppler/lib/poppler.lib" 49 | debug "C:/dspdf/poppler/poppler/lib/popplerd.lib" 50 | optimized "C:/dspdf/poppler/poppler/lib/poppler-qt5.lib" 51 | debug "C:/dspdf/poppler/poppler/lib/poppler-qt5d.lib" 52 | optimized "C:/dspdf/poppler/deps/cairo/lib/cairo-static.lib" 53 | debug "C:/dspdf/poppler/deps/cairo/lib/cairo-staticd.lib" 54 | optimized "C:/dspdf/poppler/deps/freetype/lib/freetype.lib" 55 | debug "C:/dspdf/poppler/deps/freetype/lib/freetyped.lib" 56 | optimized "C:/dspdf/poppler/deps/lcms/Lib/MS/lcms2_static.lib" 57 | debug "C:/dspdf/poppler/deps/lcms/Lib/MS/lcms2_staticd.lib" 58 | optimized "C:/dspdf/poppler/deps/fontconfig/lib/libfontconfig.lib" 59 | debug "C:/dspdf/poppler/deps/fontconfig/lib/libfontconfigd.lib" 60 | optimized "C:/dspdf/poppler/deps/libpng/lib/libpng16_static.lib" 61 | debug "C:/dspdf/poppler/deps/libpng/lib/libpng16_staticd.lib" 62 | optimized "C:/dspdf/poppler/deps/libtiff/lib/tiff_static.lib" 63 | debug "C:/dspdf/poppler/deps/libtiff/lib/tiff_staticd.lib" 64 | optimized "C:/dspdf/poppler/deps/zlib/lib/zlibstatic.lib" 65 | debug "C:/dspdf/poppler/deps/zlib/lib/zlibstaticd.lib" 66 | optimized "C:/dspdf/poppler/deps/expat/lib/expat.lib" 67 | debug "C:/dspdf/poppler/deps/expat/lib/expatd.lib" 68 | optimized "C:/dspdf/poppler/deps/openjpeg/lib/openjp2.lib" 69 | debug "C:/dspdf/poppler/deps/openjpeg/lib/openjp2d.lib" 70 | optimized "C:/dspdf/poppler/deps/libtiff/lib/port.lib" 71 | debug "C:/dspdf/poppler/deps/libtiff/lib/portd.lib" 72 | optimized "C:/dspdf/poppler/deps/libiconv/lib/libiconvStatic.lib" 73 | debug "C:/dspdf/poppler/deps/libiconv/lib/libiconvStaticD.lib" 74 | optimized "C:/dspdf/poppler/deps/pixman/lib/pixman-1_static.lib" 75 | debug "C:/dspdf/poppler/deps/pixman/lib/pixman-1_staticd.lib" 76 | # Microsoft SDK 77 | "C:/Program Files (x86)/Microsoft SDKs/Windows/v7.1A/Lib/WS2_32.Lib" 78 | "C:/Program Files (x86)/Microsoft SDKs/Windows/v7.1A/Lib/OpenGL32.Lib" 79 | "C:/Program Files (x86)/Microsoft SDKs/Windows/v7.1A/Lib/MSImg32.Lib" 80 | "C:/Program Files (x86)/Microsoft SDKs/Windows/v7.1A/Lib/Imm32.Lib" 81 | "C:/Program Files (x86)/Microsoft SDKs/Windows/v7.1A/Lib/Winmm.Lib" 82 | # Qt Platform Support 83 | optimized "C:/Qt/Static/qtbase/lib/Qt5PlatformSupport.lib" 84 | debug "C:/Qt/Static/qtbase/lib/Qt5PlatformSupportd.lib" 85 | optimized "C:/Qt/Static/qtbase/lib/qtharfbuzzng.lib" 86 | debug "C:/Qt/Static/qtbase/lib/qtharfbuzzngd.lib" 87 | optimized "C:/Qt/Static/qtbase/lib/qtpcre.lib" 88 | debug "C:/Qt/Static/qtbase/lib/qtpcred.lib" 89 | optimized "C:/Qt/Static/qtbase/plugins/platforms/qwindows.lib" 90 | debug "C:/Qt/Static/qtbase/plugins/platforms/qwindowsd.lib" 91 | ) 92 | 93 | list(APPEND WINDOWS_PRECOMPILED_DYNAMIC_LIBRARIES 94 | optimized "C:/dspdf/popplerDyn/poppler/lib/poppler.lib" 95 | debug "C:/dspdf/popplerDyn/poppler/lib/popplerd.lib" 96 | optimized "C:/dspdf/popplerDyn/poppler/lib/poppler-qt5.lib" 97 | debug "C:/dspdf/popplerDyn/poppler/lib/poppler-qt5d.lib" 98 | optimized "C:/dspdf/popplerDyn/deps/cairo/lib/cairo.lib" 99 | debug "C:/dspdf/popplerDyn/deps/cairo/lib/cairod.lib" 100 | optimized "C:/dspdf/popplerDyn/deps/freetype/lib/freetype.lib" 101 | debug "C:/dspdf/popplerDyn/deps/freetype/lib/freetyped.lib" 102 | optimized "C:/dspdf/popplerDyn/deps/lcms/Lib/MS/lcms2.lib" 103 | debug "C:/dspdf/popplerDyn/deps/lcms/Lib/MS/lcms2d.lib" 104 | optimized "C:/dspdf/popplerDyn/deps/fontconfig/lib/fontconfig.lib" 105 | debug "C:/dspdf/popplerDyn/deps/fontconfig/lib/fontconfigd.lib" 106 | optimized "C:/dspdf/popplerDyn/deps/libpng/lib/libpng16.lib" 107 | debug "C:/dspdf/popplerDyn/deps/libpng/lib/libpng16d.lib" 108 | optimized "C:/dspdf/popplerDyn/deps/libtiff/lib/tiff.lib" 109 | debug "C:/dspdf/popplerDyn/deps/libtiff/lib/tiffd.lib" 110 | optimized "C:/dspdf/popplerDyn/deps/zlib/lib/zlib.lib" 111 | debug "C:/dspdf/popplerDyn/deps/zlib/lib/zlibd.lib" 112 | "C:/dspdf/popplerDyn/deps/expat/lib/expat.lib" 113 | optimized "C:/dspdf/popplerDyn/deps/openjpeg/lib/openjpeg.lib" 114 | debug "C:/dspdf/popplerDyn/deps/openjpeg/lib/openjpegd.lib" 115 | optimized "C:/dspdf/popplerDyn/deps/libiconv/lib/libiconv.lib" 116 | debug "C:/dspdf/popplerDyn/deps/libiconv/lib/libiconvD.lib" 117 | optimized "C:/dspdf/popplerDyn/deps/pixman/lib/pixman-1_static.lib" 118 | debug "C:/dspdf/popplerDyn/deps/pixman/lib/pixman-1_staticd.lib" 119 | ) 120 | -------------------------------------------------------------------------------- /cmake/platforms.cmake: -------------------------------------------------------------------------------- 1 | # If building on MSVC, WIN32 is defined, but on Cygwin/MSYS/MinGW it is not. 2 | 3 | # use the WINDOWS variable for everything on windows (regardless of which 4 | # compiler type), MSVC or MINGW for compiler-specific things. 5 | 6 | message(STATUS "Compiling for system ${CMAKE_SYSTEM_NAME}") 7 | if( CMAKE_SYSTEM_NAME STREQUAL "Windows" ) 8 | set(WINDOWS ON) 9 | elseif( CMAKE_SYSTEM_NAME STREQUAL "MSYS" ) 10 | set(WINDOWS ON) 11 | else() 12 | set(WINDOWS OFF) 13 | endif() 14 | -------------------------------------------------------------------------------- /cmake/qrc_embedding.cmake: -------------------------------------------------------------------------------- 1 | # Copy all the filex in QRCFILES into the binary dir, 2 | # and execute qrc (Qt Resource Compiler) on them. 3 | 4 | foreach(qrc IN LISTS QRCFILES) 5 | 6 | add_custom_command( 7 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${qrc} 8 | DEPENDS 9 | ${CMAKE_CURRENT_SOURCE_DIR}/${qrc} 10 | ${TRANSLATIONFILES} 11 | COMMAND cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${qrc} ${CMAKE_CURRENT_BINARY_DIR}/${qrc} 12 | ) 13 | 14 | set(TMP_OUTFILENAME "${CMAKE_CURRENT_BINARY_DIR}/${qrc}.cxx") 15 | 16 | set(RCCCOMPILER ${Qt5Core_RCC_EXECUTABLE}) 17 | 18 | add_custom_command( 19 | OUTPUT ${TMP_OUTFILENAME} 20 | DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${qrc} 21 | COMMAND ${RCCCOMPILER} -o ${TMP_OUTFILENAME} ${CMAKE_CURRENT_BINARY_DIR}/${qrc} 22 | ) 23 | 24 | unset(RCCCOMPILER) 25 | 26 | list(APPEND EMBEDDED_QRC 27 | ${TMP_OUTFILENAME} 28 | ) 29 | 30 | unset(TMP_OUTFILENAME) 31 | endforeach() 32 | -------------------------------------------------------------------------------- /cmake/version_number.cmake: -------------------------------------------------------------------------------- 1 | ### CMake Fragment: Include version number 2 | 3 | ### Version-number inclusion logic. 4 | 5 | # Rationale: dspdfviewer --version should print something meaningful 6 | # Especially on builds from git, it should include the git revision. 7 | 8 | if( DSPDFVIEWER_VERSION ) 9 | # Not-Empty version given on the command line. This has absolute priority. 10 | message(STATUS "Embedding the version number ${DSPDFVIEWER_VERSION} specified on the command line.") 11 | endif() 12 | 13 | if( NOT DSPDFVIEWER_VERSION AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git" ) 14 | # We don't have a version number yet, but 15 | # this looks like a checkout from git. 16 | # Ask "git describe" for a version number. 17 | message(STATUS "Building from a git clone, using git describe for a version number.") 18 | execute_process(COMMAND git describe 19 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 20 | OUTPUT_VARIABLE GIT_DESCRIBE_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) 21 | # Check if it gave something back 22 | if( NOT "${GIT_DESCRIBE_VERSION}" MATCHES "^$" ) 23 | message(STATUS "Embedding version number ${GIT_DESCRIBE_VERSION} as defined by git-describe.") 24 | set(DSPDFVIEWER_VERSION ${GIT_DESCRIBE_VERSION}) 25 | endif() 26 | endif() 27 | 28 | if( NOT DSPDFVIEWER_VERSION ) 29 | # We still don't know version number to embed. 30 | # Use default 31 | 32 | # TODO: Keep me updated! 33 | set(DSPDFVIEWER_VERSION "1.15") 34 | message(STATUS "Embedding version number ${DSPDFVIEWER_VERSION}. If you want to override this, " 35 | "for example to embed the git revision you built from, please pass " 36 | "-DDSPDFVIEWER_VERSION=1.2.3.4.5 to the cmake command.") 37 | endif() 38 | 39 | if( NOT "${DSPDFVIEWER_VERSION}" MATCHES "^$" ) 40 | add_definitions(-DDSPDFVIEWER_VERSION="${DSPDFVIEWER_VERSION}") 41 | endif() 42 | -------------------------------------------------------------------------------- /debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef QT_NO_DEBUG_OUTPUT 6 | 7 | /* Qt is defined to squelch debug output. Simply forward to 8 | * qDebug()'s definition. 9 | */ 10 | #define DEBUGOUT qDebug() 11 | #define WARNINGOUT qWarning() << "WARNING" 12 | 13 | #else 14 | 15 | #include 16 | #include 17 | 18 | /* We're debugging. 19 | * Add crazy mumbo jumbo here. 20 | */ 21 | 22 | 23 | /** Print filename / line / function info 24 | */ 25 | 26 | #if defined(_MSC_VER) 27 | #define __func__ __FUNCTION__ 28 | #endif 29 | 30 | #define DEBUGOUT qDebug() << \ 31 | QString::fromUtf8("%1:%2 [%3()]"). \ 32 | arg(QFileInfo( QString::fromUtf8(__FILE__) ).fileName()). \ 33 | arg(QString::number( __LINE__ )). \ 34 | arg(QString::fromUtf8(__func__) ) 35 | 36 | #define WARNINGOUT qWarning() << "WARNING" << \ 37 | QString::fromUtf8("%1:%2 [%3()]"). \ 38 | arg(QFileInfo( QString::fromUtf8(__FILE__) ).fileName()). \ 39 | arg(QString::number( __LINE__ )). \ 40 | arg(QString::fromUtf8(__func__) ) 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /docs/.bundle/config: -------------------------------------------------------------------------------- 1 | --- 2 | BUNDLE_PATH: vendor/bundle 3 | BUNDLE_DISABLE_SHARED_GEMS: '1' 4 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | dspdfviewer.danny-edel.de 2 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'github-pages' 4 | gem 'webrick' 5 | -------------------------------------------------------------------------------- /docs/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (7.0.4.3) 5 | concurrent-ruby (~> 1.0, >= 1.0.2) 6 | i18n (>= 1.6, < 2) 7 | minitest (>= 5.1) 8 | tzinfo (~> 2.0) 9 | addressable (2.8.4) 10 | public_suffix (>= 2.0.2, < 6.0) 11 | coffee-script (2.4.1) 12 | coffee-script-source 13 | execjs 14 | coffee-script-source (1.11.1) 15 | colorator (1.1.0) 16 | commonmarker (0.23.9) 17 | concurrent-ruby (1.2.2) 18 | dnsruby (1.70.0) 19 | simpleidn (~> 0.2.1) 20 | em-websocket (0.5.3) 21 | eventmachine (>= 0.12.9) 22 | http_parser.rb (~> 0) 23 | ethon (0.16.0) 24 | ffi (>= 1.15.0) 25 | eventmachine (1.2.7) 26 | execjs (2.8.1) 27 | faraday (2.7.4) 28 | faraday-net_http (>= 2.0, < 3.1) 29 | ruby2_keywords (>= 0.0.4) 30 | faraday-net_http (3.0.2) 31 | ffi (1.15.5) 32 | forwardable-extended (2.6.0) 33 | gemoji (3.0.1) 34 | github-pages (228) 35 | github-pages-health-check (= 1.17.9) 36 | jekyll (= 3.9.3) 37 | jekyll-avatar (= 0.7.0) 38 | jekyll-coffeescript (= 1.1.1) 39 | jekyll-commonmark-ghpages (= 0.4.0) 40 | jekyll-default-layout (= 0.1.4) 41 | jekyll-feed (= 0.15.1) 42 | jekyll-gist (= 1.5.0) 43 | jekyll-github-metadata (= 2.13.0) 44 | jekyll-include-cache (= 0.2.1) 45 | jekyll-mentions (= 1.6.0) 46 | jekyll-optional-front-matter (= 0.3.2) 47 | jekyll-paginate (= 1.1.0) 48 | jekyll-readme-index (= 0.3.0) 49 | jekyll-redirect-from (= 0.16.0) 50 | jekyll-relative-links (= 0.6.1) 51 | jekyll-remote-theme (= 0.4.3) 52 | jekyll-sass-converter (= 1.5.2) 53 | jekyll-seo-tag (= 2.8.0) 54 | jekyll-sitemap (= 1.4.0) 55 | jekyll-swiss (= 1.0.0) 56 | jekyll-theme-architect (= 0.2.0) 57 | jekyll-theme-cayman (= 0.2.0) 58 | jekyll-theme-dinky (= 0.2.0) 59 | jekyll-theme-hacker (= 0.2.0) 60 | jekyll-theme-leap-day (= 0.2.0) 61 | jekyll-theme-merlot (= 0.2.0) 62 | jekyll-theme-midnight (= 0.2.0) 63 | jekyll-theme-minimal (= 0.2.0) 64 | jekyll-theme-modernist (= 0.2.0) 65 | jekyll-theme-primer (= 0.6.0) 66 | jekyll-theme-slate (= 0.2.0) 67 | jekyll-theme-tactile (= 0.2.0) 68 | jekyll-theme-time-machine (= 0.2.0) 69 | jekyll-titles-from-headings (= 0.5.3) 70 | jemoji (= 0.12.0) 71 | kramdown (= 2.3.2) 72 | kramdown-parser-gfm (= 1.1.0) 73 | liquid (= 4.0.4) 74 | mercenary (~> 0.3) 75 | minima (= 2.5.1) 76 | nokogiri (>= 1.13.6, < 2.0) 77 | rouge (= 3.26.0) 78 | terminal-table (~> 1.4) 79 | github-pages-health-check (1.17.9) 80 | addressable (~> 2.3) 81 | dnsruby (~> 1.60) 82 | octokit (~> 4.0) 83 | public_suffix (>= 3.0, < 5.0) 84 | typhoeus (~> 1.3) 85 | html-pipeline (2.14.3) 86 | activesupport (>= 2) 87 | nokogiri (>= 1.4) 88 | http_parser.rb (0.8.0) 89 | i18n (1.13.0) 90 | concurrent-ruby (~> 1.0) 91 | jekyll (3.9.3) 92 | addressable (~> 2.4) 93 | colorator (~> 1.0) 94 | em-websocket (~> 0.5) 95 | i18n (>= 0.7, < 2) 96 | jekyll-sass-converter (~> 1.0) 97 | jekyll-watch (~> 2.0) 98 | kramdown (>= 1.17, < 3) 99 | liquid (~> 4.0) 100 | mercenary (~> 0.3.3) 101 | pathutil (~> 0.9) 102 | rouge (>= 1.7, < 4) 103 | safe_yaml (~> 1.0) 104 | jekyll-avatar (0.7.0) 105 | jekyll (>= 3.0, < 5.0) 106 | jekyll-coffeescript (1.1.1) 107 | coffee-script (~> 2.2) 108 | coffee-script-source (~> 1.11.1) 109 | jekyll-commonmark (1.4.0) 110 | commonmarker (~> 0.22) 111 | jekyll-commonmark-ghpages (0.4.0) 112 | commonmarker (~> 0.23.7) 113 | jekyll (~> 3.9.0) 114 | jekyll-commonmark (~> 1.4.0) 115 | rouge (>= 2.0, < 5.0) 116 | jekyll-default-layout (0.1.4) 117 | jekyll (~> 3.0) 118 | jekyll-feed (0.15.1) 119 | jekyll (>= 3.7, < 5.0) 120 | jekyll-gist (1.5.0) 121 | octokit (~> 4.2) 122 | jekyll-github-metadata (2.13.0) 123 | jekyll (>= 3.4, < 5.0) 124 | octokit (~> 4.0, != 4.4.0) 125 | jekyll-include-cache (0.2.1) 126 | jekyll (>= 3.7, < 5.0) 127 | jekyll-mentions (1.6.0) 128 | html-pipeline (~> 2.3) 129 | jekyll (>= 3.7, < 5.0) 130 | jekyll-optional-front-matter (0.3.2) 131 | jekyll (>= 3.0, < 5.0) 132 | jekyll-paginate (1.1.0) 133 | jekyll-readme-index (0.3.0) 134 | jekyll (>= 3.0, < 5.0) 135 | jekyll-redirect-from (0.16.0) 136 | jekyll (>= 3.3, < 5.0) 137 | jekyll-relative-links (0.6.1) 138 | jekyll (>= 3.3, < 5.0) 139 | jekyll-remote-theme (0.4.3) 140 | addressable (~> 2.0) 141 | jekyll (>= 3.5, < 5.0) 142 | jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) 143 | rubyzip (>= 1.3.0, < 3.0) 144 | jekyll-sass-converter (1.5.2) 145 | sass (~> 3.4) 146 | jekyll-seo-tag (2.8.0) 147 | jekyll (>= 3.8, < 5.0) 148 | jekyll-sitemap (1.4.0) 149 | jekyll (>= 3.7, < 5.0) 150 | jekyll-swiss (1.0.0) 151 | jekyll-theme-architect (0.2.0) 152 | jekyll (> 3.5, < 5.0) 153 | jekyll-seo-tag (~> 2.0) 154 | jekyll-theme-cayman (0.2.0) 155 | jekyll (> 3.5, < 5.0) 156 | jekyll-seo-tag (~> 2.0) 157 | jekyll-theme-dinky (0.2.0) 158 | jekyll (> 3.5, < 5.0) 159 | jekyll-seo-tag (~> 2.0) 160 | jekyll-theme-hacker (0.2.0) 161 | jekyll (> 3.5, < 5.0) 162 | jekyll-seo-tag (~> 2.0) 163 | jekyll-theme-leap-day (0.2.0) 164 | jekyll (> 3.5, < 5.0) 165 | jekyll-seo-tag (~> 2.0) 166 | jekyll-theme-merlot (0.2.0) 167 | jekyll (> 3.5, < 5.0) 168 | jekyll-seo-tag (~> 2.0) 169 | jekyll-theme-midnight (0.2.0) 170 | jekyll (> 3.5, < 5.0) 171 | jekyll-seo-tag (~> 2.0) 172 | jekyll-theme-minimal (0.2.0) 173 | jekyll (> 3.5, < 5.0) 174 | jekyll-seo-tag (~> 2.0) 175 | jekyll-theme-modernist (0.2.0) 176 | jekyll (> 3.5, < 5.0) 177 | jekyll-seo-tag (~> 2.0) 178 | jekyll-theme-primer (0.6.0) 179 | jekyll (> 3.5, < 5.0) 180 | jekyll-github-metadata (~> 2.9) 181 | jekyll-seo-tag (~> 2.0) 182 | jekyll-theme-slate (0.2.0) 183 | jekyll (> 3.5, < 5.0) 184 | jekyll-seo-tag (~> 2.0) 185 | jekyll-theme-tactile (0.2.0) 186 | jekyll (> 3.5, < 5.0) 187 | jekyll-seo-tag (~> 2.0) 188 | jekyll-theme-time-machine (0.2.0) 189 | jekyll (> 3.5, < 5.0) 190 | jekyll-seo-tag (~> 2.0) 191 | jekyll-titles-from-headings (0.5.3) 192 | jekyll (>= 3.3, < 5.0) 193 | jekyll-watch (2.2.1) 194 | listen (~> 3.0) 195 | jemoji (0.12.0) 196 | gemoji (~> 3.0) 197 | html-pipeline (~> 2.2) 198 | jekyll (>= 3.0, < 5.0) 199 | kramdown (2.3.2) 200 | rexml 201 | kramdown-parser-gfm (1.1.0) 202 | kramdown (~> 2.0) 203 | liquid (4.0.4) 204 | listen (3.8.0) 205 | rb-fsevent (~> 0.10, >= 0.10.3) 206 | rb-inotify (~> 0.9, >= 0.9.10) 207 | mercenary (0.3.6) 208 | mini_portile2 (2.8.1) 209 | minima (2.5.1) 210 | jekyll (>= 3.5, < 5.0) 211 | jekyll-feed (~> 0.9) 212 | jekyll-seo-tag (~> 2.1) 213 | minitest (5.18.0) 214 | nokogiri (1.14.3) 215 | mini_portile2 (~> 2.8.0) 216 | racc (~> 1.4) 217 | octokit (4.25.1) 218 | faraday (>= 1, < 3) 219 | sawyer (~> 0.9) 220 | pathutil (0.16.2) 221 | forwardable-extended (~> 2.6) 222 | public_suffix (4.0.7) 223 | racc (1.6.2) 224 | rb-fsevent (0.11.2) 225 | rb-inotify (0.10.1) 226 | ffi (~> 1.0) 227 | rexml (3.2.5) 228 | rouge (3.26.0) 229 | ruby2_keywords (0.0.5) 230 | rubyzip (2.3.2) 231 | safe_yaml (1.0.5) 232 | sass (3.7.4) 233 | sass-listen (~> 4.0.0) 234 | sass-listen (4.0.0) 235 | rb-fsevent (~> 0.9, >= 0.9.4) 236 | rb-inotify (~> 0.9, >= 0.9.7) 237 | sawyer (0.9.2) 238 | addressable (>= 2.3.5) 239 | faraday (>= 0.17.3, < 3) 240 | simpleidn (0.2.1) 241 | unf (~> 0.1.4) 242 | terminal-table (1.8.0) 243 | unicode-display_width (~> 1.1, >= 1.1.1) 244 | typhoeus (1.4.0) 245 | ethon (>= 0.9.0) 246 | tzinfo (2.0.6) 247 | concurrent-ruby (~> 1.0) 248 | unf (0.1.4) 249 | unf_ext 250 | unf_ext (0.0.8.2) 251 | unicode-display_width (1.8.0) 252 | webrick (1.8.1) 253 | 254 | PLATFORMS 255 | ruby 256 | 257 | DEPENDENCIES 258 | github-pages 259 | webrick 260 | 261 | BUNDLED WITH 262 | 1.17.3 263 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | 2 | RELEASE=v1.14 3 | 4 | .PHONY: manpage.html 5 | 6 | manpage.html: 7 | ( cd ../dspdfviewer && \ 8 | git show master:docs/dspdfviewer.1 ) \ 9 | | groff -mandoc -T html > $@ 10 | 11 | manpage-release.html: 12 | ( cd ../dspdfviewer && \ 13 | git show $(RELEASE):docs/dspdfviewer.1 ) \ 14 | | groff -mandoc -T html > $@ 15 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | dspdfviewer website 2 | =================== 3 | 4 | This is source of the documentation website for [dspdfviewer]. 5 | 6 | [Github Pages] renders it to http://dspdfviewer.danny-edel.de 7 | 8 | How to contribute? 9 | ------------------ 10 | 11 | 1. Fork this 12 | 2. Clone your fork, running the web server locally 13 | * `bundle install && bundle exec jekyll serve` 14 | * Check out http://localhost:4000/ 15 | 3. Commit your changes 16 | 4. Pull-Request 17 | 18 | [Github Pages]: https://pages.github.com/ 19 | [dspdfviewer]: https://github.com/dannyedel/dspdfviewer 20 | -------------------------------------------------------------------------------- /docs/Windows/Help.hhp: -------------------------------------------------------------------------------- 1 | [OPTIONS] 2 | Compatibility=1.1 or later 3 | Compiled file=Help.chm 4 | Contents file=TOC.hhc 5 | Default Font=Segoe UI,10,0 6 | Default topic=name.html 7 | Display compile progress=No 8 | Language=0x409 English (United States) 9 | Title=DSPDFVIEWER help 10 | 11 | 12 | [FILES] 13 | bugs.html 14 | controls.html 15 | description.html 16 | files.html 17 | name.html 18 | options.html 19 | presenter.html 20 | seealso.html 21 | synopsis.html 22 | license.html 23 | 24 | [INFOTYPES] 25 | 26 | -------------------------------------------------------------------------------- /docs/Windows/TOC.hhc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
    11 |
  • 12 | 13 | 14 | 15 |
  • 16 | 17 | 18 | 19 |
  • 20 | 21 | 22 | 23 |
  • 24 | 25 | 26 | 27 |
  • 28 | 29 | 30 | 31 |
  • 32 | 33 | 34 | 35 |
  • 36 | 37 | 38 | 39 |
  • 40 | 41 | 42 | 43 |
  • 44 | 45 | 46 | 47 |
  • 48 | 49 | 50 | 51 |
52 | 53 | -------------------------------------------------------------------------------- /docs/Windows/bugs.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Bugs 7 | 8 | 9 | 10 |

Bugs

11 | 12 |

None currently known.

13 | 14 |

If you find any bugs, the preferred way to report them is at the github issue tracker at GitHub.

15 | 16 |

As a fallback, you can send e-mail to mail@danny-edel.de with the word "dspdfviewer" in the subject line.

17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/Windows/controls.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Controls 7 | 8 | 9 | 10 |

Controls

11 | 12 |

You can use the following controls while dspdfviewer is running.

13 | 14 |

Note that mouse-clicks are subject to pointer position if the hyperlink support is enabled. If your mouse cursor changes to a hand, it will follow the link you are hovering on a click. 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 44 | 45 | 46 | 47 |

Use this if you want the clocks to stop at zero, use the G (goto) function to page 1 if you want to them to keep running.

48 |

Note that the Home key may be called "Pos 1" on some keyboards.

49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 59 | 60 | 61 | 62 | 64 | 65 | 66 | 67 | 69 | 70 |
Keyboard: ?, F1

Display quick-help (most important key bindings)

Keyboard: Spacebar, Page Down /
Mouse: Left-Click, Wheel Down

Go one page forward

28 |

Additional keyboard aliases: Down, Right, Return, Enter, N, F

Keyboard: Backspace, Page Up /
Mouse: Right-Click, Wheel Up

Go one page backward

33 |

Additional keyboard aliases: Up, Left, P

Keyboard: B, . (period)

Toggle blanking of the audience screen

Keyboard: G

Go to specific page (a number entry window will pop up)

42 |

Note that the this counts PDF pages, so a single slide having 6 unmasking steps will be 7 PDF pages long, including the initial near-blank page.

Keyboard: Home, H

Go to the first page and reset the clocks to zero.

Keyboard: Escape, Q

Quit dspdfviewer.

Keyboard: S, F12

Switch primary and secondary screens

57 |

Use this if the audience sees your ’note’ side with the clocks and you see the actual presentation on your screen.

58 |

If you just want to see the main presentation (for example, because the projector is behind you), use T.

Keyboard: T

Switch secondary screen’s function

63 |

Use this if you want to see the audience side on your screen, without showing the notes to the audience. Pressing the button again will switch back to normal operation.

Keyboard: D

Switch duplication of the audience’s screen

68 |

Use this if you want to see the audience side and the notes on your screen (so the full presentation), leaving the audience’s screen untouched. Pressing the button again will switch back to split mode.

71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /docs/Windows/description.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Description 7 | 8 | 9 | 10 |

Description

11 | 12 |

dspdfviewer is intended for presentations created with the latex-beamer class, specifically documents created with the show notes on second screen=right option.

13 | 14 |

Its purpose is to display the left half of a page on the audience’s screen (which will most commonly be a projector) and the right half on your "private" screen (think: the notebook you carried to the presentation site). The basic idea is that you will display personal notes and information to help you with your presentation on your personal screen, while the audience sees only the PDF they are supposed to see.

15 | 16 |

On the secondary screen you will see three clocks: A "wall clock", a "presentation" clock and a "slide" clock.

17 | 18 |

The wall clock in the bottom left corner that display current time of day, the presentation clock (labeled "Total") counts the time you spent since you started the presentation, and the "slide" counter (bottom right) displays the time you spent on the current slide.

19 | 20 |

The clocks don’t start the second you launch the program, the idea behind that behaviour is that many people have a "title" slide active long before the audience even arrives.

21 | 22 |

Once you use the next/previous slide commands, the clock starts. If you want to start the clock, but still display the title slide, just press "previous" (for example, Up Arrow or Right Mouse Button) on the title slide.

23 | 24 |

If you want to reset the clocks to zero, press the "Home" button on the keybord.

25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /docs/Windows/files.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Files 7 | 8 | 9 | 10 |

Files

11 | 12 |

%userprofile%\.config\dspdfviewer.ini

13 | 14 |

You can specify all long command-line options (without leading --) here, in a "option=value" format, one per line.

15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/Windows/license.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Licenses 7 | 8 | 9 | 10 |

Licenses

11 | 12 |

dspdfviewer contains several third party components with different licenses. All licenses are provided in the License subfolder in the application's location.

13 | 14 |
    15 |
  • boost 1.59.0 — Homepage • License: boost.txt
  • 16 |
  • cairo 1.14.2 — Homepage • License: cairo-LGPL.txt and cairo-MPL.txt
  • 17 |
  • dspdfviewer — Homepage • License: GPLv2.txt
  • 18 |
  • Expat 2.1.0 — Homepage • License: expat.txt
  • 19 |
  • Fontconfig 2.11.94 — Homepage • License: fontconfig.txt
  • 20 |
  • FreeType 2.6 — Homepage • License: GPLv2.txt
  • 21 |
  • lcms 2.7 — Homepage • License: lcms.txt
  • 22 |
  • libiconv 1.14 — Homepage • License: libiconv.txt
  • 23 |
  • libpng 1.6.18 — Homepage • License: libpng.txt
  • 24 |
  • LibTIFF 4.0.5 — Homepage • License: libtiff.txt
  • 25 |
  • OpenJPEG 2.1.0 — Homepage • License: openjpeg.txt
  • 26 |
  • pixman 0.32.6 — Homepage • License: pixman.txt
  • 27 |
  • poppler 0.36.0 — Homepage • License: GPLv2.txt
  • 28 |
  • Qt 5.5.0 — Homepage • License: GPLv2.txt
  • 29 |
  • zlib 1.2.8 — Homepage • License: zlib.txt
  • 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/Windows/name.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Name 7 | 8 | 9 |

Name

10 |

dspdfviewer − Dual-Screen PDF Viewer

11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/Windows/options.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Options 7 | 8 | 9 | 10 |

Options

11 | 12 |

The exact behaviour of dspdfviewer is configurable using command-line parameters.

13 | 14 |

Unless otherwise noted, all command-line options can be written in a configuration file. See the Files section for the location.

15 | 16 |

For the command-line parameters, this program follows the usual GNU command line syntax, with long options starting with two dashes (’-’). A summary of options is included below.

17 | 18 |

If you specify those in a configuration file, write one option per line, use the long version without the two leading dashes, followed by an equals sign and the desired value.

19 | 20 |

For example, bottom-pane-height=20 is a valid configuration line.

21 | 22 |

If an option is specified in both the configuration file and the command-line, the command-line value takes precedence.

23 | 24 |

Note for options of type <bool>: They take true, false, 0 or 1 as arguments. For example, --use-second-screen false can be expressed as --use-second-screen 0 or shortened to -u0. 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 39 | 40 | 41 | 45 | 46 | 47 | 48 | 51 | 52 | 53 | 54 | 56 | 57 | 58 | 59 | 61 | 62 | 63 | 64 | 66 | 67 | 68 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 91 | 92 |
-h, --helpShow summary of options.
-f, --full-page

Use the presentation program with a normal single-screen PDF, that is display the full page on both the primary and secondary monitor.

37 |

The secondary screen still contains timers and thumbnails to help you with your presentation, unless you disable them using the options below.

-u, --use-second-screen <bool>

Controls whether the program actually works as a dual-screen viewer.

42 |

The default is true.

43 |

If you only have one screen, but still want to use the cache features, you can set this option to false. If the window ends up on the wrong display, you can still use the switch command (see below).

44 |

What comes out on the primary screen depends on whether you use the -f Option: -u0 -f results in a simple full-screen PDF viewer, while -u0 without -f still splits the page in half and outputs only the left frame.

-l, --hyperlink-support <bool>

Controls whether the program makes PDF Hyperlinks clickable.

49 |

The default is true.

50 |

While it is normally desired to have clickable hyperlinks, if you cannot control the position of your pointer (if your remote control has only left-click and right-click) it might be safer to disable hyperlinks.

--prerender-previous-pages n

When jumping to slide m, also pre-render the slides (m-n)..(m-1) (default 3)

55 |

Note: If you set this to zero, you will not get a thumbnail for the previous page rendered before you have visited it.

--prerender-next-pages n

When jumping to slide m, also pre-render the slides (m+1)..(m+n) (default 10)

60 |

Note: If you set this to zero, you will not get a thumbnail for the next page rendered before you have visited it.

-a, --presenter-area <bool>

Show (true, 1) or hide (false, 0) the presenter’s area on the second screen. If this is set to zero, the following options will have no effect.

65 |
-d, --duplicate <bool>

Duplicate (true, 1) or hide (false, 0) the audience’s screen next to the notes on the second screen.

69 |

The default is false.

-t, --thumbnails <bool>

Show (true, 1) or hide (false, 0) the thumbnails on the second screen.

-w, --wall-clock <bool>

Show (true, 1) or hide (false, 0) the wall clock on the second screen.

-p, --presentation-clock <bool>

Show (true, 1) or hide (false, 0) the presentation clock on the second screen.

-s, --slide-clock <bool>

Show (true, 1) or hide (false, 0) the slide clock on the second screen.

-b, --bottom-pane-height n

Configure how large the presenter area on the second screen will be, unit is percent of second screen’s total height.

90 |

Default value 20.

93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /docs/Windows/presenter.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Presenter remote controls 7 | 8 | 9 | 10 |

Presenter remote controls

11 | 12 |

Most (maybe not all) presenter remote controls technically act as a keyboard sending one of the keystrokes listed either in the main or additional keybindings. If your remote control does not work as intended, please file a bug report describing what keystrokes it generates when you press its buttons. If there is no conflict, a keybinding will be included in the next release.

13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/Windows/seealso.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | See also 7 | 8 | 9 | 10 |

See also

11 | 12 |

<path to LaTeX>\doc\latex\beamer\beameruserguide.pdf from the latex-beamer package on how to create beamer presentations.

13 |

Note: Use "show notes on second screen=right" because dspdfviewer assumes that the right half of the page is the notes.

14 |

http://dspdfviewer.danny-edel.de for installation instructions and new release announcements.

15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/Windows/style.css: -------------------------------------------------------------------------------- 1 | td { 2 | vertical-align: top; 3 | } 4 | 5 | td p { 6 | margin: 0; 7 | } 8 | 9 | html, body { 10 | font-family: 'Segoe UI', 'Trebuchet MS', Tahoma, Verdana, Arial, sans-serif; 11 | font-size: 12pt; 12 | } 13 | -------------------------------------------------------------------------------- /docs/Windows/synopsis.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Synopsis 7 | 8 | 9 | 10 | 11 |

Synopsis

12 | 13 |

dspdfviewer [options] [filename]

14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | exclude: 2 | - vendor 3 | - Gemfile 4 | - Makefile 5 | - README.md 6 | - build* 7 | 8 | markdown: kramdown 9 | kramdown: 10 | input: GFM 11 | hard_wrap: false 12 | # syntax_highlighter_opts: 13 | # line_numbers: false 14 | 15 | # mimick github 16 | # fixed 17 | lsi: false 18 | source: . 19 | 20 | defaults: 21 | - 22 | scope: 23 | path: "" 24 | values: 25 | layout: "default" 26 | -------------------------------------------------------------------------------- /docs/_includes/html_footer.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannyedel/dspdfviewer/d432d8d60de3d41a7b9ca1bc031b2344e8009d26/docs/_includes/html_footer.html -------------------------------------------------------------------------------- /docs/_includes/html_header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ page.title }} 7 | {% if page.title %} 8 | [dspdfviewer] 9 | {% else %} 10 | dspdfviewer 11 | {% endif %} 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | {% include html_header.html %} 2 | 3 | {% if page.url != "/index.html" %} 4 | 10 | {% endif %} 11 | 12 | {% if page.title %} 13 |

{{page.title}}

14 | {% endif %} 15 | 16 | {{content}} 17 | 18 | {% include html_footer.html %} 19 | -------------------------------------------------------------------------------- /docs/_sass/_page-generator.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * @import url(https://fonts.googleapis.com/css?family=Lato:300italic,700italic,300,700); 3 | */ 4 | 5 | body { 6 | padding:50px; 7 | font:14px/1.5 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; 8 | color:#000; 9 | font-weight:300; 10 | } 11 | 12 | h1, h2, h3, h4, h5, h6 { 13 | color:#222; 14 | margin:0 0 20px; 15 | } 16 | 17 | p, ul, ol, table, pre, dl { 18 | margin:0 0 20px; 19 | } 20 | 21 | h1, h2, h3 { 22 | line-height:1.1; 23 | } 24 | 25 | h1 { 26 | font-size:28px; 27 | } 28 | 29 | h2 { 30 | color:#393939; 31 | } 32 | 33 | h3, h4, h5, h6 { 34 | color:#494949; 35 | } 36 | 37 | a { 38 | color:#39c; 39 | font-weight:400; 40 | text-decoration:none; 41 | } 42 | 43 | a small { 44 | font-size:11px; 45 | color:#777; 46 | margin-top:-0.6em; 47 | display:block; 48 | } 49 | 50 | .wrapper { 51 | width:860px; 52 | margin:0 auto; 53 | } 54 | 55 | blockquote { 56 | border-left:1px solid #e5e5e5; 57 | margin:0; 58 | padding:0 0 0 20px; 59 | font-style:italic; 60 | } 61 | 62 | code, pre { 63 | font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; 64 | color:#333; 65 | font-size:12px; 66 | } 67 | 68 | pre { 69 | padding:8px 15px; 70 | background: #f8f8f8; 71 | border-radius:5px; 72 | border:1px solid #e5e5e5; 73 | overflow-x: auto; 74 | } 75 | 76 | table { 77 | width:100%; 78 | border-collapse:collapse; 79 | } 80 | 81 | th, td { 82 | text-align:left; 83 | padding:5px 10px; 84 | border-bottom:1px solid #e5e5e5; 85 | } 86 | 87 | dt { 88 | color:#444; 89 | font-weight:700; 90 | } 91 | 92 | th { 93 | color:#444; 94 | } 95 | 96 | img { 97 | max-width:100%; 98 | } 99 | 100 | header { 101 | width:270px; 102 | float:left; 103 | position:fixed; 104 | } 105 | 106 | header ul { 107 | list-style:none; 108 | height:40px; 109 | 110 | padding:0; 111 | 112 | background: #eee; 113 | background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); 114 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); 115 | background: -webkit-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); 116 | background: -o-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); 117 | background: -ms-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); 118 | background: linear-gradient(top, #f8f8f8 0%,#dddddd 100%); 119 | 120 | border-radius:5px; 121 | border:1px solid #d2d2d2; 122 | box-shadow:inset #fff 0 1px 0, inset rgba(0,0,0,0.03) 0 -1px 0; 123 | width:270px; 124 | } 125 | 126 | header li { 127 | width:89px; 128 | float:left; 129 | border-right:1px solid #d2d2d2; 130 | height:40px; 131 | } 132 | 133 | header ul a { 134 | line-height:1; 135 | font-size:11px; 136 | color:#999; 137 | display:block; 138 | text-align:center; 139 | padding-top:6px; 140 | height:40px; 141 | } 142 | 143 | strong { 144 | color:#222; 145 | font-weight:700; 146 | } 147 | 148 | header ul li + li { 149 | width:88px; 150 | border-left:1px solid #fff; 151 | } 152 | 153 | header ul li + li + li { 154 | border-right:none; 155 | width:89px; 156 | } 157 | 158 | header ul a strong { 159 | font-size:14px; 160 | display:block; 161 | color:#222; 162 | } 163 | 164 | section { 165 | width:500px; 166 | float:right; 167 | padding-bottom:50px; 168 | } 169 | 170 | small { 171 | font-size:11px; 172 | } 173 | 174 | hr { 175 | border:0; 176 | background:#e5e5e5; 177 | height:1px; 178 | margin:0 0 20px; 179 | } 180 | 181 | footer { 182 | width:270px; 183 | float:left; 184 | position:fixed; 185 | bottom:50px; 186 | } 187 | 188 | @media print, screen and (max-width: 960px) { 189 | 190 | div.wrapper { 191 | width:auto; 192 | margin:0; 193 | } 194 | 195 | header, section, footer { 196 | float:none; 197 | position:static; 198 | width:auto; 199 | } 200 | 201 | header { 202 | padding-right:320px; 203 | } 204 | 205 | section { 206 | border:1px solid #e5e5e5; 207 | border-width:1px 0; 208 | padding:20px 0; 209 | margin:0 0 20px; 210 | } 211 | 212 | header a small { 213 | display:inline; 214 | } 215 | 216 | header ul { 217 | position:absolute; 218 | right:50px; 219 | top:52px; 220 | } 221 | } 222 | 223 | @media print, screen and (max-width: 720px) { 224 | body { 225 | word-wrap:break-word; 226 | } 227 | 228 | header { 229 | padding:0; 230 | } 231 | 232 | header ul, header p.view { 233 | position:static; 234 | } 235 | 236 | pre, code { 237 | word-wrap:normal; 238 | } 239 | } 240 | 241 | @media print, screen and (max-width: 480px) { 242 | body { 243 | padding:15px; 244 | } 245 | 246 | header ul { 247 | display:none; 248 | } 249 | } 250 | 251 | @media print { 252 | body { 253 | padding:0.4in; 254 | font-size:12pt; 255 | color:#444; 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /docs/_sass/_rouge.scss: -------------------------------------------------------------------------------- 1 | .highlight table td { padding: 5px; } 2 | .highlight table pre { margin: 0; } 3 | .highlight .cm { 4 | color: #999988; 5 | font-style: italic; 6 | } 7 | .highlight .cp { 8 | color: #999999; 9 | font-weight: bold; 10 | } 11 | .highlight .c1 { 12 | color: #999988; 13 | font-style: italic; 14 | } 15 | .highlight .cs { 16 | color: #999999; 17 | font-weight: bold; 18 | font-style: italic; 19 | } 20 | .highlight .c, .highlight .cd { 21 | color: #999988; 22 | font-style: italic; 23 | } 24 | .highlight .err { 25 | color: #a61717; 26 | background-color: #e3d2d2; 27 | } 28 | .highlight .gd { 29 | color: #000000; 30 | background-color: #ffdddd; 31 | } 32 | .highlight .ge { 33 | color: #000000; 34 | font-style: italic; 35 | } 36 | .highlight .gr { 37 | color: #aa0000; 38 | } 39 | .highlight .gh { 40 | color: #999999; 41 | } 42 | .highlight .gi { 43 | color: #000000; 44 | background-color: #ddffdd; 45 | } 46 | .highlight .go { 47 | color: #888888; 48 | } 49 | .highlight .gp { 50 | color: #555555; 51 | } 52 | .highlight .gs { 53 | font-weight: bold; 54 | } 55 | .highlight .gu { 56 | color: #aaaaaa; 57 | } 58 | .highlight .gt { 59 | color: #aa0000; 60 | } 61 | .highlight .kc { 62 | color: #000000; 63 | font-weight: bold; 64 | } 65 | .highlight .kd { 66 | color: #000000; 67 | font-weight: bold; 68 | } 69 | .highlight .kn { 70 | color: #000000; 71 | font-weight: bold; 72 | } 73 | .highlight .kp { 74 | color: #000000; 75 | font-weight: bold; 76 | } 77 | .highlight .kr { 78 | color: #000000; 79 | font-weight: bold; 80 | } 81 | .highlight .kt { 82 | color: #445588; 83 | font-weight: bold; 84 | } 85 | .highlight .k, .highlight .kv { 86 | color: #000000; 87 | font-weight: bold; 88 | } 89 | .highlight .mf { 90 | color: #009999; 91 | } 92 | .highlight .mh { 93 | color: #009999; 94 | } 95 | .highlight .il { 96 | color: #009999; 97 | } 98 | .highlight .mi { 99 | color: #009999; 100 | } 101 | .highlight .mo { 102 | color: #009999; 103 | } 104 | .highlight .m, .highlight .mb, .highlight .mx { 105 | color: #009999; 106 | } 107 | .highlight .sb { 108 | color: #d14; 109 | } 110 | .highlight .sc { 111 | color: #d14; 112 | } 113 | .highlight .sd { 114 | color: #d14; 115 | } 116 | .highlight .s2 { 117 | color: #d14; 118 | } 119 | .highlight .se { 120 | color: #d14; 121 | } 122 | .highlight .sh { 123 | color: #d14; 124 | } 125 | .highlight .si { 126 | color: #d14; 127 | } 128 | .highlight .sx { 129 | color: #d14; 130 | } 131 | .highlight .sr { 132 | color: #009926; 133 | } 134 | .highlight .s1 { 135 | color: #d14; 136 | } 137 | .highlight .ss { 138 | color: #990073; 139 | } 140 | .highlight .s { 141 | color: #d14; 142 | } 143 | .highlight .na { 144 | color: #008080; 145 | } 146 | .highlight .bp { 147 | color: #999999; 148 | } 149 | .highlight .nb { 150 | color: #0086B3; 151 | } 152 | .highlight .nc { 153 | color: #445588; 154 | font-weight: bold; 155 | } 156 | .highlight .no { 157 | color: #008080; 158 | } 159 | .highlight .nd { 160 | color: #3c5d5d; 161 | font-weight: bold; 162 | } 163 | .highlight .ni { 164 | color: #800080; 165 | } 166 | .highlight .ne { 167 | color: #990000; 168 | font-weight: bold; 169 | } 170 | .highlight .nf { 171 | color: #990000; 172 | font-weight: bold; 173 | } 174 | .highlight .nl { 175 | color: #990000; 176 | font-weight: bold; 177 | } 178 | .highlight .nn { 179 | color: #555555; 180 | } 181 | .highlight .nt { 182 | color: #000080; 183 | } 184 | .highlight .vc { 185 | color: #008080; 186 | } 187 | .highlight .vg { 188 | color: #008080; 189 | } 190 | .highlight .vi { 191 | color: #008080; 192 | } 193 | .highlight .nv { 194 | color: #008080; 195 | } 196 | .highlight .ow { 197 | color: #000000; 198 | font-weight: bold; 199 | } 200 | .highlight .o { 201 | color: #000000; 202 | font-weight: bold; 203 | } 204 | .highlight .w { 205 | color: #bbbbbb; 206 | } 207 | .highlight { 208 | background-color: #f8f8f8; 209 | } 210 | -------------------------------------------------------------------------------- /docs/css/pygments.css: -------------------------------------------------------------------------------- 1 | .hll { background-color: #ffffcc } 2 | .c { color: #408080; font-style: italic } /* Comment */ 3 | .err { border: 1px solid #FF0000 } /* Error */ 4 | .k { color: #008000; font-weight: bold } /* Keyword */ 5 | .o { color: #666666 } /* Operator */ 6 | .ch { color: #408080; font-style: italic } /* Comment.Hashbang */ 7 | .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 8 | .cp { color: #BC7A00 } /* Comment.Preproc */ 9 | .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */ 10 | .c1 { color: #408080; font-style: italic } /* Comment.Single */ 11 | .cs { color: #408080; font-style: italic } /* Comment.Special */ 12 | .gd { color: #A00000 } /* Generic.Deleted */ 13 | .ge { font-style: italic } /* Generic.Emph */ 14 | .gr { color: #FF0000 } /* Generic.Error */ 15 | .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 16 | .gi { color: #00A000 } /* Generic.Inserted */ 17 | .go { color: #888888 } /* Generic.Output */ 18 | .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 19 | .gs { font-weight: bold } /* Generic.Strong */ 20 | .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 21 | .gt { color: #0044DD } /* Generic.Traceback */ 22 | .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 23 | .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 24 | .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 25 | .kp { color: #008000 } /* Keyword.Pseudo */ 26 | .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 27 | .kt { color: #B00040 } /* Keyword.Type */ 28 | .m { color: #666666 } /* Literal.Number */ 29 | .s { color: #BA2121 } /* Literal.String */ 30 | .na { color: #7D9029 } /* Name.Attribute */ 31 | .nb { color: #008000 } /* Name.Builtin */ 32 | .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 33 | .no { color: #880000 } /* Name.Constant */ 34 | .nd { color: #AA22FF } /* Name.Decorator */ 35 | .ni { color: #999999; font-weight: bold } /* Name.Entity */ 36 | .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 37 | .nf { color: #0000FF } /* Name.Function */ 38 | .nl { color: #A0A000 } /* Name.Label */ 39 | .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 40 | .nt { color: #008000; font-weight: bold } /* Name.Tag */ 41 | .nv { color: #19177C } /* Name.Variable */ 42 | .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 43 | .w { color: #bbbbbb } /* Text.Whitespace */ 44 | .mb { color: #666666 } /* Literal.Number.Bin */ 45 | .mf { color: #666666 } /* Literal.Number.Float */ 46 | .mh { color: #666666 } /* Literal.Number.Hex */ 47 | .mi { color: #666666 } /* Literal.Number.Integer */ 48 | .mo { color: #666666 } /* Literal.Number.Oct */ 49 | .sb { color: #BA2121 } /* Literal.String.Backtick */ 50 | .sc { color: #BA2121 } /* Literal.String.Char */ 51 | .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 52 | .s2 { color: #BA2121 } /* Literal.String.Double */ 53 | .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 54 | .sh { color: #BA2121 } /* Literal.String.Heredoc */ 55 | .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 56 | .sx { color: #008000 } /* Literal.String.Other */ 57 | .sr { color: #BB6688 } /* Literal.String.Regex */ 58 | .s1 { color: #BA2121 } /* Literal.String.Single */ 59 | .ss { color: #19177C } /* Literal.String.Symbol */ 60 | .bp { color: #008000 } /* Name.Builtin.Pseudo */ 61 | .vc { color: #19177C } /* Name.Variable.Class */ 62 | .vg { color: #19177C } /* Name.Variable.Global */ 63 | .vi { color: #19177C } /* Name.Variable.Instance */ 64 | .il { color: #666666 } /* Literal.Number.Integer.Long */ 65 | -------------------------------------------------------------------------------- /docs/css/styles.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | code { 5 | white-space: pre; 6 | } 7 | 8 | body { 9 | max-width: 60em; 10 | margin: auto; 11 | } 12 | 13 | div.backlink { 14 | float: right; 15 | } 16 | 17 | h1::after { 18 | clear: right; 19 | } 20 | 21 | div.root code::before { 22 | content: 'root permission required\A'; 23 | font-style: italic; 24 | font-size: 90%; 25 | padding: 2px; 26 | border: thin #888; 27 | border-radius: 4px; 28 | margin-left: 4em; 29 | color: black; 30 | } 31 | 32 | span.root code::before { 33 | content: 'as root'; 34 | font-style: italic; 35 | font-size: 85%; 36 | background-color: #faa; 37 | margin-right: 0.5em; 38 | color: black; 39 | } 40 | 41 | p code, li > code, li > span.root > code { 42 | /* Mark Inline code with a little border 43 | */ 44 | background-color: #eee; 45 | border: thin #888; 46 | border-radius: 5px; 47 | padding: 2px; 48 | } 49 | 50 | 51 | .root pre { 52 | background-color: #f8eeee; 53 | } 54 | 55 | /* Underline headers */ 56 | 57 | h1, h2, h3 { 58 | border-bottom: 1px solid #eee; 59 | } 60 | 61 | code.language-bash .c 62 | { 63 | /* Comments */ 64 | color: #888; 65 | } 66 | 67 | /* Include the page-generator css */ 68 | @import 'page-generator'; 69 | 70 | /* Include syntax highlighting, 71 | * create with 72 | * bundle exec rougify style github > /path/to/scss 73 | */ 74 | @import 'rouge'; 75 | 76 | /* Overwrite any font definitions, 77 | * use the systems default monospace font 78 | */ 79 | code,pre { 80 | font-family: monospace; 81 | } 82 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Dual-Screen PDF Viewer 4 | --- 5 | 6 | This website aims to provide some documentation for the dspdfviewer 7 | project. Its main purpose is to decouple installation instructions 8 | from the primary sourcecode tree. 9 | You can [inspect the sourcecode on github.][sourcecode] 10 | 11 | It is a work-in-progress, and accepting suggestions and help. 12 | Read further down on how to get involved. 13 | 14 | ## What is dspdfviewer? 15 | dspdfviewer is a pre-rendering and caching (read: *fast*) full-screen pdf 16 | viewer specifically designed for latex-beamer presentations, 17 | that were created with the `show notes on second screen=right` option. 18 | 19 | It will take your double-width PDF file, split it in half, render the 20 | left half to the audience (via a beamer) and the right half - which will 21 | contain the notes you entered in your LaTeX source - on your laptop screen. 22 | 23 | In addition, your laptop screen will contain some counters and a wall-clock, 24 | which may help you time your presentation right. 25 | 26 | Both screens will be rendered and scaled completely independent of each other, 27 | so you can use two screens with different resolutions and/or aspect ratios, 28 | such as your 16:10 laptop screen and a 4:3 beamer, or the other way around. 29 | Please use both devices' native resolutions for maximum image quality. 30 | 31 | ## How do I use it? 32 | 33 | First of all: You should have a pdf generated by `latex-beamer` with 34 | the `show notes on second screen=right` option. 35 | While you can leave the `=right` part out (is the default if not specified) 36 | dspdfviewer will not work correctly if you specify any other direction; 37 | It always assumes the left half is for the audience and the right half 38 | is for the presenter. 39 | 40 | Simply call `dspdfviewer /path/to/your/presentation.pdf` to start. 41 | If you start `dspdfviewer` without a command-line parameter, 42 | it will use a file-open-dialog-window to ask you for a PDF file. 43 | 44 | Once its loaded, try the following commands: 45 | 46 | * Swap Screens (If the audience sees the clock and the note page) 47 | * Keyboard: `S`, `F12` 48 | * Advance one frame 49 | * Mouse: `Left-Click`, `Wheel-Down` 50 | * Keyboard: `Right`, `Down` 51 | * Back one frame 52 | * Mouse: `Right-Click`, `Wheel-Up` 53 | * Keyboard: `Left`, `Up` 54 | * Keybindings popup 55 | * Keyboard: `F1` or `?` 56 | * Quit program 57 | * Keyboard: `Q` 58 | 59 | For a more complete list, please read the program's manual page. 60 | With dspdfviewer installed, a manual page corresponding to your installed version 61 | should be available as `man dspdfviewer`. 62 | 63 | In addition, you can [access the manpage online]. Note that the online version 64 | is generated from git and may contain commands not yet in your installation. 65 | You can also read the [release manpage] from version v1.14. 66 | 67 | [access the manpage online]: manpage.html 68 | [release manpage]: manpage-release.html 69 | 70 | If the manual doesn't answer your question, feel free to open a ticket in 71 | the [issues system] requesting help or clarification. 72 | 73 | ## How do I install it? 74 | 75 | This varies depending on your operating system. 76 | Please follow the specific instructions: 77 | 78 | * Linux and other Unixes 79 | * [Debian](installation/debian.html) 80 | * [Ubuntu](installation/ubuntu.html) 81 | * [Gentoo](installation/gentoo.html) 82 | * [Arch](installation/arch.html) 83 | * [Generic (from source)](installation/) 84 | * [Mac OS](installation/macos.html) 85 | * [Windows](installation/windows.html) 86 | 87 | If your system isn't listed here, please try the Generic instructions. 88 | Feel free to open a ticket in the [issues system] asking for help if something goes wrong. 89 | 90 | [issues system]: https://github.com/dannyedel/dspdfviewer/issues 91 | 92 | ## How do I contribute? 93 | 94 | First, you help a lot if you use the software and report any problems or 95 | missing features in the [issues system]. 96 | 97 | If you want to help on development, please use github's 98 | amazing [pull request] feature. 99 | 100 | The full [sourcecode], which includes [this website], is available 101 | to view and improve, 102 | and any help is greatly appreciated! 103 | 104 | [sourcecode]: https://github.com/dannyedel/dspdfviewer 105 | [this website]: https://github.com/dannyedel/dspdfviewer/tree/master/docs/ 106 | [pull request]: https://help.github.com/articles/using-pull-requests/ 107 | 108 | ## Who built this program? 109 | 110 | Github maintains a [contributors] list for the sourcecode. 111 | 112 | [contributors]: https://github.com/dannyedel/dspdfviewer/graphs/contributors 113 | 114 | ## Contact information 115 | 116 | If you have any questions that don't fit the [issues system], 117 | you can contact me ([@dannyedel]) by e-mail at `mail@danny-edel.de`. 118 | 119 | Since e-mails on the internet are everything but secure, 120 | please use my [gpg key] to send encrypted. 121 | 122 | [@dannyedel]: https://github.com/dannyedel 123 | [gpg key]: https://sks-keyservers.net/pks/lookup?op=get&search=0xF132F84C7183343C 124 | -------------------------------------------------------------------------------- /docs/installation/arch.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation on Arch Linux 3 | layout: default 4 | --- 5 | 6 | `dspdfviewer` is available via the [Arch User Repository AUR][aur]. 7 | 8 | There is a PKGBUILD file for the [latest release version][release]. 9 | 10 | [aur]: https://wiki.archlinux.org/index.php/Arch_User_Repository 11 | [release]: https://aur.archlinux.org/packages/dspdfviewer/ 12 | [git]: https://aur.archlinux.org/packages/dspdfviewer-git/ 13 | -------------------------------------------------------------------------------- /docs/installation/daily-deb.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation of daily debs, directly from git 3 | --- 4 | 5 | The daily deb repository has been discontinued. 6 | 7 | Please use the official [Debian instructions][deb] and/or [compile from source yourself][src]. 8 | 9 | [deb]: /installation/debian 10 | [src]: /installation/source 11 | -------------------------------------------------------------------------------- /docs/installation/debian.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation on Debian 3 | layout: default 4 | --- 5 | 6 | If you're running Debian, it is recommended to use the version included in your 7 | distribution. Depending on which Debian release you have, installing `dspdfviewer` is 8 | a little bit different. 9 | 10 | ## Debian stretch and newer (incl. sid) 11 | 12 | `dspdfviewer` is included in the distribution since `stretch`. 13 | 14 | You don't need to activate anything special, simply call 15 | `apt-get install dspdfviewer` 16 | (or use your favorite GUI to install the `dspdfviewer` package) 17 | and you're ready to go. 18 | 19 | ## Older Debian releases 20 | 21 | * Debian jessie: dspdfviewer is available via jessie-backports. 22 | If you have not activated backports yet, 23 | [Click here for detailed instructions.][1] 24 | 25 | [1]: /installation/debian/jessie.html 26 | 27 | ## Versions overview 28 | 29 | To see which versions are available in Debian, please take a look at the 30 | [package tracker]. 31 | 32 | [package tracker]: https://tracker.debian.org/pkg/dspdfviewer 33 | [@dannyedel]: https://github.com/dannyedel 34 | -------------------------------------------------------------------------------- /docs/installation/gentoo.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation on Gentoo 3 | layout: default 4 | --- 5 | 6 | Gentoo 7 | ====== 8 | 9 | Install from ebuild 10 | ------------------- 11 | 12 | Two kinds of ebuilds are available for dspdfviewer: the git ebuild 13 | (with version number 9999), which downloads and installs the latest 14 | git version of dspdfviewer, and regular ebuilds with normal version 15 | numbers. 16 | 17 | To install, move the ebuilds in the ["gentoo" subdirectory][0] into an 18 | overlay (for more information on overlays, see [the gentoo manual][1]) 19 | in the "app-text/dspdfviewer" directory. Then, unmask the version you 20 | want and run "emerge dspdfviewer". 21 | 22 | [0]: https://github.com/dannyedel/dspdfviewer/tree/master/gentoo 23 | [1]: https://www.gentoo.org/proj/en/overlays/userguide.xml 24 | 25 | ----- 26 | 27 | The inclusion request for the main Gentoo repository is filed under 28 | [bug 520120 in the Gentoo bugzilla][gentoobug]. 29 | 30 | [gentoobug]: https://bugs.gentoo.org/show_bug.cgi?id=520120 31 | -------------------------------------------------------------------------------- /docs/installation/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation and compilation from source 3 | layout: default 4 | --- 5 | 6 | You can choose if you want to install the bleeding-edge development version 7 | (may eat your firstborn, plain out crash, or do other unexpected things) or the 8 | last stable release. 9 | 10 | * [stable version] 11 | * [current development (git)] 12 | 13 | When you compile from source, you have a few choices that may affect the build. 14 | Please read [compile options and dependencies][compile options] carefully, 15 | especially if you're building a package for a wider audience. 16 | 17 | [stable version]: /installation/source/stable.html 18 | [current development (git)]: /installation/source/git.html 19 | [compile options]: /installation/source/options.html 20 | -------------------------------------------------------------------------------- /docs/installation/macos.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation on MacOS 3 | layout: default 4 | --- 5 | 6 | ## Homebrew (recommended) 7 | If you use a mac with Homebrew, there already is [a formula][formula] 8 | to install dspdfviewer 9 | 10 | {% highlight bash %} 11 | brew install dspdfviewer 12 | {% endhighlight %} 13 | 14 | The previous command installs the latest release. If you want to test out the 15 | newest features, provide the head option: 16 | 17 | {% highlight bash %} 18 | brew install dspdfviewer --HEAD 19 | {% endhighlight %} 20 | 21 | ## Manually (advanced users) 22 | 23 | If you want to compile from source, please read the 24 | [generic install instructions](/installation/) about 25 | the available cmake-time switches. 26 | 27 | If you installed Qt5 via Homebrew, you will have 28 | to pass its installation prefix to `cmake`: 29 | 30 | ```bash 31 | cmake /path/to/source -DSomeOption=ON -DCMAKE_PREFIX_PATH=$(brew --prefix qt5) 32 | ``` 33 | 34 | [formula]: https://github.com/Homebrew/homebrew-core/blob/master/Formula/dspdfviewer.rb 35 | -------------------------------------------------------------------------------- /docs/installation/source/dependencies.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Compile-time Dependencies 3 | --- 4 | 5 | You will need a c++11 compiler, cmake, and the 6 | "development" editions of the libraries used (boost, poppler, qt5). 7 | 8 | The exact names of those packages will vary based on your operating system 9 | and/or distribution, but development versions often end in `-dev`, 10 | `-headers` or similar. 11 | 12 | If your distribution does not yet have a package for `dspdfviewer`, 13 | you might want to consider packaging it, 14 | so that in the future, you (and other users of your distribution) 15 | can simply install the package. 16 | 17 | ## Debian and Ubuntu based systems 18 | 19 | The following package list works on current debian-based systems: 20 | 21 | {% highlight bash %} 22 | sudo apt install libboost-program-options-dev libboost-test-dev \ 23 | libpoppler-qt5-dev qtbase5-dev qttools5-dev qttools5-dev-tools 24 | {% endhighlight %} 25 | 26 | ## Fedora 27 | 28 | Fedora dependencies, thanks to [LorhanSohaky](https://github.com/LorhanSohaky): 29 | 30 | {% highlight bash %} 31 | sudo dnf install cmake boost-devel poppler-qt5-devel qt5-qtbase-devel qt5-linguist 32 | {% endhighlight %} 33 | -------------------------------------------------------------------------------- /docs/installation/source/git.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Compiling from git 3 | --- 4 | 5 | You will need a c++11 compiler (for example `g++` or `clang`), `cmake`, 6 | and `boost` installed. 7 | 8 | Please take a look at [compile options] for the available options. 9 | 10 | [compile options]: /installation/source/options.html 11 | 12 | ## Initial installation 13 | 14 | 1. (download sourcecode) 15 | `git clone git://github.com/dannyedel/dspdfviewer.git` 16 | 2. (enter directory) 17 | `cd dspdfviewer` 18 | 3. (make a build sub-directory) 19 | `mkdir build ; cd build` 20 | 4. (create Makefile) 21 | `cmake ..` 22 | (*note: this step should tell you about missing build-deps*) 23 | 5. (build) 24 | `make` 25 | 6. (install) 26 | `make install` 27 | (optional) 28 | 29 | Be advised that there is *no* automatic uninstallation, 30 | so please consider packaging 31 | the software using your distribution's preferred packaging method. 32 | 33 | The `cmake` step accepts `--prefix=` and the generated 34 | `make install` accepts the `DESTDIR` setting, so your packager can 35 | redirect the files where it needs them. 36 | 37 | ## Updating 38 | 39 | 1. (enter directory) 40 | `cd .../dspdfviewer/build/` 41 | 2. (update from git) 42 | `git pull` 43 | 3. (build) 44 | `make` 45 | 4. (install system-wide) 46 | `make install` 47 | (optional) 48 | 49 | Again, please use your distribution's preferred packaging wrapper around `make install`. 50 | -------------------------------------------------------------------------------- /docs/installation/source/options.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Compile-time options and dependencies 3 | --- 4 | 5 | At the `cmake` step, you can customize a few things by using cmake defines. 6 | The generic syntax is: 7 | 8 | ```bash 9 | cd $(mktemp -d) # some empty(!) build directory 10 | cmake /path/to/dspdfviewer/source -DSomeOption=ON -DSomethingElse=OFF 11 | make # builds the app 12 | cmake . -DSomeOption=OFF # change from inside the build dir 13 | make # rebuild with changed option 14 | ``` 15 | 16 | Boolean options in `cmake` are specified with `-DSomeOpt=ON` and `OFF`, respectively. 17 | For string-type options you can specify an arbitrary string, just make sure to correctly 18 | escape it for your shell. 19 | 20 | ## Options for v1.15 21 | 22 | By default, you will need the following external software: 23 | 24 | * `boost` 25 | * `cmake` 26 | * `qt5` 27 | * `poppler` with the Qt5 bindings 28 | * If you want to compile the test PDFs during build (activated by default): 29 | * `pdflatex` with `latex-beamer` package installed 30 | 31 | The following `cmake` options manipulate the compilation and dependency list: 32 | 33 | * `DSPDFVIEWER_VERSION` string 34 | * Completely overrides the version reported by `dspdfviewer --version`. 35 | Use this if you're packaging `dspdfviewer` for a distribution and want 36 | to include a dist-specific version. 37 | * By default, this is auto-detected using `git describe`, with a hardcoded 38 | fallback version number (such as, when not building from a git clone). 39 | * `UpdateTranslations` boolean, default OFF 40 | * If you want to work on the translation, you can activate this flag 41 | to make `cmake` regenerate the `.ts` files. 42 | **Be warned** that when this switch is ON, cmake sees the `.ts` files 43 | as *output* files and will **delete** them if you call `make clean`. 44 | * `BuildTests` boolean, default ON 45 | * Builds unit tests. These tests will require PDFs to function, which 46 | are included in the tarball, but can be (re)generated during the build. 47 | * `RunDualScreenTests` boolean, default ON 48 | * Include unit tests that require two screens to be connected. 49 | * `RunTestsOnBigEndian` boolean, default OFF 50 | * Run the unit tests on a big-endian system. By default, tests are 51 | only run on little-endian systems. 52 | * `UsePrerenderedPDF` boolean, default OFF 53 | * Use pre-rendered PDFs for the test suite, instead of compiling them 54 | on-the-fly during the build. 55 | * Enable this to speed up build time and reduce dependencies. 56 | * The default value will probably switch to ON in a future version. 57 | * `BoostStaticLink` boolean, default OFF 58 | * Link against the `boost` libraries statically (ON) or dynamically (OFF) 59 | * If your platform supports dynamic linking, ideally through a package manager 60 | that takes care of installing and updating the libraries, it is highly 61 | recommended to stick to dynamic linking. 62 | * If you link statically, please ensure that you recompile when the boost 63 | libraries get updated. 64 | * `WindowsStaticLink` boolean, default ON 65 | * Only relevant for Windows builds using the MS Visual C++ Compiler. 66 | * Sets the `/MT` instead of the `/MD` compiler flags. 67 | * `CodeCoverage` boolean, default OFF 68 | * This flag adds the necessary flags to record code coverage (currently 69 | only supported with gcc). Only of interest for developers, this massively 70 | slows down the code. Don't use it for production builds. 71 | 72 | 73 | --- 74 | 75 | ## Historical options (no longer present in current version) 76 | 77 | * `DownloadTestPDF` 78 | * This option is ignored since v1.15, 79 | because the pre-rendered PDF files are now distributed in 80 | the release tarball. 81 | 82 | back to [compile from source](/installation/) 83 | -------------------------------------------------------------------------------- /docs/installation/source/stable.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Compile the stable release from source 3 | --- 4 | 5 | 6 | Note: Please take a look at the [github releases][rel] page to get an 7 | overview of the released versions and how they changed. 8 | 9 | You can also jump directly to the [latest version][latest]. 10 | 11 | [rel]: https://github.com/dannyedel/dspdfviewer/releases 12 | [latest]: https://github.com/dannyedel/dspdfviewer/releases/latest 13 | 14 | Dependencies: You will need to install the [build dependencies][bdep] 15 | before you can compile this software. 16 | 17 | 18 | Info: When compiling software yourself, you have the opportunity to 19 | change certain aspects. 20 | Please read the [compile-time options list][opts] if you want to 21 | fine-tune certain things. 22 | 23 | [opts]: /installation/source/options.html 24 | [bdep]: /installation/source/dependencies.html 25 | 26 | {% highlight bash %} 27 | VERSION=1.33.7 # Change this! 28 | wget https://github.com/dannyedel/dspdfviewer/archive/v$VERSION.tar.gz 29 | wget https://github.com/dannyedel/dspdfviewer/releases/download/v$VERSION/dspdfviewer-$VERSION.tar.gz.asc 30 | gpgv dspdfviewer-$VERSION.tar.gz.asc v$VERSION.tar.gz # verify archive integrity 31 | cd dspdfviewer-$VERSION 32 | mkdir build 33 | cd build 34 | cmake .. # You could pass options here (see above) 35 | make 36 | 37 | # 38 | # You can now use the software as ./dspdfviewer 39 | # 40 | 41 | make install # optional, requires root privileges 42 | {% endhighlight %} 43 | 44 | Note that there is no uninstall script, so please consider replacing the final 45 | `make install` with something more appropriate for your distribution. 46 | It will respect the usual DESTDIR parameter. 47 | 48 | If you are willing to write and maintain a dspdfviewer installation 49 | script/package for a specific distribution, please get in touch. 50 | -------------------------------------------------------------------------------- /docs/installation/ubuntu.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation on Ubuntu 3 | layout: default 4 | --- 5 | 6 | `dspdfviewer` is **included in the main repositories** since wily (2015/10). 7 | 8 | Simply call `apt-get install dspdfviewer` or 9 | use your favorite GUI to install the `dspdfviewer` package. 10 | 11 | ## Older versions 12 | 13 | * There is a [PPA hosting 1.15 for trusty and precise][ppa]. 14 | 15 | [ppa]: /installation/ubuntu/ppa 16 | -------------------------------------------------------------------------------- /docs/installation/ubuntu/ppa.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation on Trusty and Precise via PPA 3 | --- 4 | 5 | [Back to Ubuntu installation](/installation/ubuntu.html) 6 | 7 | Add the repository `ppa:dannyedel/dspdfviewer` to your system source list 8 | and install from it. 9 | 10 | You can do this by running 11 | 12 | {% highlight bash %} 13 | sudo add-apt-repository ppa:dannyedel/dspdfviewer 14 | # the system will ask for your password and confirmation 15 | sudo apt-get update 16 | sudo apt-get install dspdfviewer 17 | {% endhighlight %} 18 | 19 | ## Versions overview 20 | 21 | To see which version of `dspdfviewer` is included in which Ubuntu release, 22 | check out the following pages: 23 | 24 | * [Ubuntu official distributions][launchpad] 25 | * PPAs for... 26 | * [precise][precise] 27 | * [trusty][trusty] 28 | 29 | [launchpad]: https://launchpad.net/ubuntu/+source/dspdfviewer 30 | [precise]: https://launchpad.net/~dannyedel/+archive/ubuntu/dspdfviewer?field.series_filter=precise 31 | [trusty]: https://launchpad.net/~dannyedel/+archive/ubuntu/dspdfviewer?field.series_filter=trusty 32 | -------------------------------------------------------------------------------- /docs/installation/windows.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation on Windows 3 | layout: default 4 | --- 5 | 6 | ## Use a ready-to-run binary (recommended for most users) 7 | 8 | [@projekter][] provides ready-to-use windows binaries for you. 9 | 10 | It is recommended that you use the [latest release version][latest]. 11 | 12 | The recommended way is to download the `setup.exe`, 13 | start it and follow the on-screen-instructions to install 14 | dspdfviewer into your programs folder, and create shortcuts where desired. 15 | 16 | Since v1.15.1, there is also a `dspdfviewer-$VERSION.zip` archive available, 17 | containing a portable version that works without installation. 18 | 19 | If you want to install an older version or a pre-release, 20 | please see the full list at [@projekters release page][]. 21 | 22 | ## Advanced users: Compile dspdfviewer from source 23 | 24 | In the course of adding a Windows build to the CI tests, 25 | [@projekter][] created [archives of poppler and its dependencies][deps], 26 | compiled with MSVC 2013. 27 | This can of course also be used to quickly get a development environment set up 28 | on a windows machine, without needing to spend much time on compiling 29 | dependencies. 30 | 31 | *Warning: The dependency archive is provided as-is; 32 | do not expect to receive any kind of update support. 33 | Please only use it as a quickstart mechanism, 34 | and don't expect the included DLLs to be continually 35 | updated with patches from upstream. 36 | If you plan to distribute a dspdfviewer binary, 37 | do yourself a favor and re-compile the 38 | most recent stable versions of all dependencies.* 39 | 40 | In addition to the dependency archive, 41 | you will also need the following programs and libraries on your system: 42 | 43 | * MSVC 2013 (also known as version 12.0) 44 | * Qt 5.x (make sure you pick the version for MSVC 2013 32bit) 45 | * Boost (also make sure you pick the version for MSVC 12.0 32 bit) 46 | * CMake 47 | * git 48 | * Something to extract the archive with (7z for example) 49 | 50 | To use the prebuilt DLLs, extract the archives directly to `c:\` and 51 | make sure to set `-DWindowsStaticLink=OFF` at cmake time, 52 | and it is probably easier to use `-DBoostStaticLink=ON` on a Windows build. 53 | You will also need to set the `PATH` environment to contain the directories of the 54 | DLLs unless you want to copy them to the build dir. 55 | 56 | On a debug build, you must make sure that the debug version of `poppler-qt5.dll` is loaded, 57 | for example by copying it into the executable's directory. 58 | See [buildme.bat][] or the [AppVeyor CI configuration][appveyor] 59 | for examples of how to set up and compile a Debug configuration. 60 | 61 | [@projekter]: https://github.com/projekter 62 | [@projekters release page]: https://github.com/projekter/dspdfviewer/releases 63 | [deps]: https://github.com/projekter/dspdfviewer/releases/tag/v1.14-42-g4acfb31 64 | [buildme.bat]: https://gist.github.com/dannyedel/549e57aa73936d7d7a7f 65 | [appveyor]: https://github.com/dannyedel/dspdfviewer/blob/master/.appveyor.yml 66 | [latest]: https://github.com/projekter/dspdfviewer/releases/latest 67 | -------------------------------------------------------------------------------- /docs/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /dspdfviewer.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Version=1.0 4 | Name=DS PDF Viewer 5 | Comment=Dual-Screen PDF Viewer for LaTeX-Beamer presentations utilizing the "show notes on second screen" option 6 | Keywords=pdf;presentation;latex;beamer;notes; 7 | Exec=dspdfviewer %f 8 | -------------------------------------------------------------------------------- /dspdfviewer.h: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #ifndef dspdfviewer_H 22 | #define dspdfviewer_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include "poppler-qt.h" 28 | 29 | #include "pdfviewerwindow.h" 30 | #include "pdfrenderfactory.h" 31 | #include "runtimeconfiguration.h" 32 | 33 | class DSPDFViewer: public QObject 34 | { 35 | Q_OBJECT 36 | 37 | private: 38 | const RuntimeConfiguration& runtimeConfiguration; 39 | enum { 40 | TIMER_UPDATE_INTERVAL=250 41 | }; 42 | 43 | private: 44 | QTimer clockDisplayTimer; 45 | QTime slideStart; 46 | QTime presentationStart; 47 | bool presentationClockRunning; 48 | 49 | private: 50 | QFileSystemWatcher documentFileWatcher; 51 | PdfRenderFactory renderFactory; 52 | unsigned int m_pagenumber; 53 | PDFViewerWindow audienceWindow; 54 | PDFViewerWindow secondaryWindow; 55 | 56 | 57 | 58 | private: 59 | QString timeToString(QTime time) const; 60 | QString timeToString(int milliseconds) const; 61 | void resetSlideClock(); 62 | 63 | RenderingIdentifier toRenderIdent(unsigned int pageNumber, const PDFViewerWindow& window); 64 | RenderingIdentifier toThumbnailRenderIdent(unsigned int pageNumber, PDFViewerWindow& window); 65 | 66 | private slots: 67 | void sendAllClockSignals() const; 68 | 69 | public: 70 | DSPDFViewer(const RuntimeConfiguration& r); 71 | virtual ~DSPDFViewer() override; 72 | 73 | 74 | /** get current page number 75 | */ 76 | unsigned int pageNumber() const; 77 | 78 | /** get page count 79 | */ 80 | unsigned int numberOfPages() const; 81 | 82 | void setHighQuality(bool hq); 83 | 84 | bool isReadyToRender() const; 85 | 86 | PdfRenderFactory* theFactory(); 87 | 88 | QTime wallClock() const; 89 | QTime slideClock() const; 90 | QTime presentationClock() const; 91 | 92 | QTime timeSince( const QTime& startPoint) const; 93 | 94 | bool isAudienceScreenBlank() const; 95 | 96 | /** Allow const access to the windows' positions. 97 | * Needed for tests to inspect things. */ 98 | const QRect audienceGeometry() const; 99 | const QRect secondGeometry() const; 100 | 101 | signals: 102 | void wallClockUpdate(const QTime& wallClock) const; 103 | void slideClockUpdate(const QTime& slideClock) const; 104 | void presentationClockUpdate(const QTime& presentationClock) const; 105 | 106 | public slots: 107 | /** (re-)Renders the current page on both monitors 108 | */ 109 | void renderPage(); 110 | 111 | /** goes to the specified page. Pages start at zero. 112 | */ 113 | void gotoPage(unsigned int pageNumber); 114 | /** go Forward one page 115 | */ 116 | void goForward(); 117 | 118 | /** go backward one page 119 | */ 120 | void goBackward(); 121 | 122 | void goToStartAndResetClocks(); 123 | 124 | void swapScreens(); 125 | 126 | void toggleAudienceScreenBlank(); 127 | void setAudienceScreenBlank(); 128 | void setAudienceScreenVisible(); 129 | 130 | void toggleSecondaryScreenFunction(); 131 | void toggleSecondaryScreenDuplication(); 132 | 133 | void exit(); 134 | }; 135 | 136 | #endif // dspdfviewer_H 137 | -------------------------------------------------------------------------------- /dspdfviewer.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | dspdfviewer_de.qm 4 | 5 | 6 | -------------------------------------------------------------------------------- /hyperlinkarea.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #include "hyperlinkarea.h" 22 | #include 23 | #include 24 | #include 25 | #include "debug.h" 26 | #include 27 | 28 | using boost::math::iround; 29 | 30 | HyperlinkArea::HyperlinkArea(QLabel* imageLabel, const AdjustedLink& link): QLabel(), targetPage(link.targetPageNumber()) 31 | { 32 | if ( link.linkType() != Poppler::Link::Goto ) 33 | throw WrongLinkType(); 34 | QRect mySize; 35 | #if QT_VERSION < QT_VERSION_CHECK(5,15,0) 36 | // QT Version is below 5.15, which added the Return-By-Value overload. 37 | // Handle the copy ourselves. 38 | // FIXME: Delete this code at some point 39 | const QPixmap *ppixmap = imageLabel->pixmap(); 40 | if ( ppixmap == nullptr) 41 | throw std::runtime_error("imageLabel with nullptr pixmap()"); 42 | const QPixmap pixmap = QPixmap{ *ppixmap }; //copy 43 | #else 44 | // Qt version is at least 5.15, use Qt's own copy function. 45 | const QPixmap pixmap = imageLabel->pixmap(Qt::ReturnByValue); 46 | #endif 47 | if ( pixmap.isNull() ) 48 | throw /** FIXME Exception **/ std::runtime_error("Tried to construct a HyperlinkArea from an image label without a pixmap"); 49 | 50 | QRectF sizeWithinImageLabel = link.linkArea(); 51 | 52 | mySize.setTop( iround(sizeWithinImageLabel.top() * pixmap.height()) ); 53 | mySize.setLeft( iround(sizeWithinImageLabel.left() * pixmap.width()) ); 54 | 55 | mySize.setHeight(std::abs( iround(sizeWithinImageLabel.height() * pixmap.height())) ); 56 | mySize.setWidth( iround(sizeWithinImageLabel.width() * pixmap.width()) ); 57 | 58 | setParent(imageLabel); 59 | setGeometry(mySize); 60 | 61 | /* 62 | setAutoFillBackground(true); 63 | QPalette pal = palette(); 64 | pal.setColor(QPalette::Window, QColor(Qt::black) ); 65 | setPalette(pal); 66 | 67 | */ 68 | 69 | // setText( QString("%1 @ +%2,%3").arg(targetPage).arg( link.linkArea().right() ). arg(link.linkArea().top()) ); 70 | 71 | show(); 72 | 73 | 74 | setCursor( Qt::PointingHandCursor ); 75 | 76 | 77 | DEBUGOUT << "Added an hyperlink to" << link.targetPageNumber() << "at" << geometry(); 78 | } 79 | 80 | 81 | void HyperlinkArea::mousePressEvent(QMouseEvent* ev) 82 | { 83 | DEBUGOUT << "Hyperlink clicked" << ev << "Target page" << targetPage; 84 | 85 | emit gotoPageRequested(targetPage); 86 | } 87 | -------------------------------------------------------------------------------- /hyperlinkarea.h: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #ifndef HYPERLINKAREA_H 22 | #define HYPERLINKAREA_H 23 | 24 | #include 25 | #include "poppler-qt.h" 26 | 27 | #include "adjustedlink.h" 28 | 29 | class HyperlinkArea : public QLabel 30 | { 31 | Q_OBJECT 32 | 33 | /** FIXME Exception class */ 34 | struct WrongLinkType{}; 35 | 36 | uint targetPage; 37 | public: 38 | HyperlinkArea(QLabel* imageLabel, const AdjustedLink& gotoLink); 39 | 40 | virtual void mousePressEvent(QMouseEvent* ev) override; 41 | 42 | signals: 43 | void gotoPageRequested(uint targetPage); 44 | 45 | 46 | }; 47 | 48 | #endif // HYPERLINKAREA_H 49 | -------------------------------------------------------------------------------- /keybindings.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | KeybindingsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 554 10 | 224 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Keybindings 21 | 22 | 23 | true 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 10 33 | 75 34 | true 35 | 36 | 37 | 38 | Key 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 10 47 | 75 48 | true 49 | 50 | 51 | 52 | Action 53 | 54 | 55 | 56 | 57 | 58 | 59 | Next slide 60 | 61 | 62 | 63 | 64 | 65 | 66 | N or Left/Down arrow 67 | 68 | 69 | 70 | 71 | 72 | 73 | P or Right/Down arrow 74 | 75 | 76 | 77 | 78 | 79 | 80 | Blank/Unblank audience screen 81 | 82 | 83 | 84 | 85 | 86 | 87 | Quit 88 | 89 | 90 | 91 | 92 | 93 | 94 | Previous slide 95 | 96 | 97 | 98 | 99 | 100 | 101 | Go to specific slide 102 | 103 | 104 | 105 | 106 | 107 | 108 | Toggle between notes and slides on the secondary screen 109 | 110 | 111 | 112 | 113 | 114 | 115 | Toggle between displaying both notes and slides on the secondary screen or only notes 116 | 117 | 118 | 119 | 120 | 121 | 122 | Switch primary and secondary screens 123 | 124 | 125 | 126 | 127 | 128 | 129 | Go to first page and reset counters 130 | 131 | 132 | 133 | 134 | 135 | 136 | Show this help box 137 | 138 | 139 | 140 | 141 | 142 | 143 | B or . 144 | 145 | 146 | 147 | 148 | 149 | 150 | G 151 | 152 | 153 | 154 | 155 | 156 | 157 | H or Home 158 | 159 | 160 | 161 | 162 | 163 | 164 | Q or Esc 165 | 166 | 167 | 168 | 169 | 170 | 171 | S or F12 172 | 173 | 174 | 175 | 176 | 177 | 178 | T 179 | 180 | 181 | 182 | 183 | 184 | 185 | D 186 | 187 | 188 | 189 | 190 | 191 | 192 | ? or F1 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | Qt::Horizontal 204 | 205 | 206 | 207 | 40 208 | 20 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | OK 217 | 218 | 219 | true 220 | 221 | 222 | 223 | 224 | 225 | 226 | Qt::Horizontal 227 | 228 | 229 | 230 | 40 231 | 20 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | dspdfviewer version %1 242 | 243 | 244 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | pushButton 254 | clicked() 255 | KeybindingsDialog 256 | accept() 257 | 258 | 259 | 272 260 | 200 261 | 262 | 263 | 398 264 | 201 265 | 266 | 267 | 268 | 269 | 270 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #include 22 | #include "debug.h" 23 | #include "dspdfviewer.h" 24 | #include "runtimeconfiguration.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #if defined ( _WIN32 ) 33 | #pragma comment(linker, "/ENTRY:mainCRTStartup") 34 | 35 | #if defined( NDEBUG ) 36 | #pragma comment(linker, "/SUBSYSTEM:windows") 37 | #endif 38 | 39 | #endif 40 | 41 | int main(int argc, char** argv) 42 | { 43 | QApplication app(argc, argv); 44 | 45 | app.setApplicationName( QString::fromUtf8("dspdfviewer") ); 46 | app.setApplicationVersion( QString::fromUtf8( DSPDFVIEWER_VERSION ) ); 47 | 48 | const auto locale = QLocale::system(); 49 | const auto localeName = locale.name(); 50 | const auto systemTranslationsPath = 51 | QLibraryInfo::location(QLibraryInfo::TranslationsPath); 52 | 53 | QTranslator qtTranslator; 54 | DEBUGOUT << "Loading qt system translation for" << localeName 55 | << "from" << systemTranslationsPath; 56 | if ( !qtTranslator.load( 57 | QString::fromUtf8( "qt_" ) + localeName, systemTranslationsPath ) 58 | ) { 59 | WARNINGOUT << "Failed to load qt translations for locale" << localeName; 60 | } else { 61 | app.installTranslator(&qtTranslator); 62 | DEBUGOUT << "Qt system translation loaded for" << localeName; 63 | } 64 | 65 | QTranslator appTranslator; 66 | DEBUGOUT << "Loading dspdfviewer translation for current locale:" << localeName; 67 | if ( ! appTranslator.load(QString::fromUtf8(":/translations/dspdfviewer") ) ) { 68 | WARNINGOUT << "Failed to load dspdfviewer translation for current locale" << localeName; 69 | } else { 70 | app.installTranslator(&appTranslator); 71 | DEBUGOUT << "dspdfviewer translation loaded for" << localeName; 72 | } 73 | 74 | /* If anything goes wrong, try to display the exception to the user. 75 | * Its the least i can do. 76 | */ 77 | try { 78 | /* Register the meta-type so that rendered pages can be passed around 79 | * using Qt's event/callback system 80 | */ 81 | qRegisterMetaType< QSharedPointer >("QSharedPointer"); 82 | RuntimeConfiguration rc(argc, argv); 83 | 84 | if ( ! rc.filePathDefined() ) { 85 | rc.filePath( qPrintable( QFileDialog::getOpenFileName( 86 | nullptr, QFileDialog::tr("Load PDF from disk"), QString(), QFileDialog::tr("PDF (*.pdf)") ) ) ); 87 | } 88 | 89 | DSPDFViewer foo( rc ); 90 | return app.exec(); 91 | } catch ( std::exception& e ) { 92 | std::cerr << "----- FATAL ERROR -----" << std::endl 93 | << qPrintable( QCoreApplication::translate("DSPDFViewer", "Dual-Screen PDF Viewer has encountered an error and cannot continue") ) << std::endl 94 | << e.what() << std::endl; 95 | 96 | QMessageBox errorMsg; 97 | errorMsg.setText( QCoreApplication::translate("DSPDFViewer", "Dual-Screen PDF Viewer has encountered an error and cannot continue") ); 98 | errorMsg.setInformativeText( QString::fromLocal8Bit( e.what() ) ); 99 | errorMsg.setDefaultButton(QMessageBox::Discard); 100 | errorMsg.setIcon( QMessageBox::Critical ); 101 | errorMsg.exec(); 102 | return 1; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /pagepart.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #include "pagepart.h" 22 | #include 23 | 24 | namespace { 25 | const char * const left = "left"; 26 | const char * const right = "right"; 27 | const char * const both = "both"; 28 | } 29 | 30 | std::ostream& operator << ( std::ostream& out, const PagePart& pagepart ) { 31 | if ( pagepart == PagePart::LeftHalf ) 32 | return out << left; 33 | else if ( pagepart == PagePart::RightHalf ) 34 | return out << right; 35 | else 36 | return out << both; 37 | } 38 | 39 | std::istream& operator >> ( std::istream& in, PagePart& pagepart ) { 40 | std::string s; 41 | in >> s; 42 | if ( s == left ) 43 | pagepart = PagePart::LeftHalf; 44 | else if ( s == right ) 45 | pagepart = PagePart::RightHalf; 46 | else if ( s == both ) 47 | pagepart = PagePart::FullPage; 48 | else 49 | in.setstate( std::ios::failbit ); 50 | return in; 51 | } 52 | -------------------------------------------------------------------------------- /pagepart.h: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #ifndef PAGEPART_H 22 | #define PAGEPART_H 23 | #include 24 | 25 | enum class PagePart 26 | { 27 | 28 | FullPage, 29 | LeftHalf, 30 | RightHalf 31 | 32 | }; 33 | 34 | std::istream& operator >> ( std::istream& in, PagePart& pagepart ); 35 | std::ostream& operator << ( std::ostream& out, const PagePart& pagepart ); 36 | 37 | 38 | 39 | #endif // PAGEPART_H 40 | -------------------------------------------------------------------------------- /pdfcacheoption.h: -------------------------------------------------------------------------------- 1 | #ifndef PDFCACHEOPTION_H 2 | #define PDFCACHEOPTION_H 3 | 4 | enum class PDFCacheOption { 5 | keepPDFinMemory, 6 | rereadFromDisk 7 | }; 8 | 9 | #endif // PDFCACHEOPTION_H 10 | -------------------------------------------------------------------------------- /pdfdocumentreference.cpp: -------------------------------------------------------------------------------- 1 | #include "pdfdocumentreference.h" 2 | #include "pdfpagereference.h" 3 | 4 | #include 5 | #include 6 | #include "debug.h" 7 | 8 | QSharedPointer< const Poppler::Document > PDFDocumentReference::popplerDocument() const 9 | { 10 | // Make sure this function is "single threaded" 11 | Lock lk{mutex_}; 12 | 13 | if ( ! popplerDocument_ ) { 14 | /** No document defined yet. Create it from the disk/memory cache. */ 15 | 16 | QSharedPointer m_document; 17 | if ( cacheOption() == PDFCacheOption::rereadFromDisk ) { 18 | DEBUGOUT << "Trying to build a Poppler::Document from file" << filename(); 19 | QSharedPointer diskDocument( Poppler::Document::load(filename()) ); 20 | m_document.swap(diskDocument); 21 | } 22 | else if ( cacheOption() == PDFCacheOption::keepPDFinMemory ) { 23 | DEBUGOUT << "Trying to build a document from" << fileContents_.size() << "byte memory cache"; 24 | QSharedPointer memoryDocument( Poppler::Document::loadFromData(fileContents_) ); 25 | m_document.swap(memoryDocument); 26 | } 27 | if ( !m_document || m_document->isLocked() ) 28 | throw std::runtime_error("Document not readable"); 29 | m_document->setRenderHint(Poppler::Document::Antialiasing, true); 30 | m_document->setRenderHint(Poppler::Document::TextAntialiasing, true); 31 | m_document->setRenderHint(Poppler::Document::TextHinting, true); 32 | popplerDocument_ = m_document; 33 | } 34 | return popplerDocument_; 35 | } 36 | 37 | PDFPageReference PDFDocumentReference::page(unsigned int pageNumber) const 38 | { 39 | PDFPageReference ppr(*this, pageNumber); 40 | return ppr; 41 | } 42 | 43 | PDFDocumentReference::PDFDocumentReference(const QString& theFilename, const PDFCacheOption& theCacheOption): 44 | filename_(theFilename), 45 | fileContents_(), 46 | cacheOption_(theCacheOption), 47 | mutex_(), 48 | popplerDocument_() 49 | { 50 | if ( cacheOption() == PDFCacheOption::keepPDFinMemory ) { 51 | DEBUGOUT << "Reading file into memory"; 52 | QFile file(filename()); 53 | file.open(QIODevice::ReadOnly); 54 | fileContents_ = file.readAll(); 55 | DEBUGOUT << fileContents_.size() << "bytes read"; 56 | } 57 | } 58 | const PDFCacheOption& PDFDocumentReference::cacheOption() const 59 | { 60 | return cacheOption_; 61 | } 62 | 63 | const QString& PDFDocumentReference::filename() const 64 | { 65 | return filename_; 66 | } 67 | 68 | PDFDocumentReference& PDFDocumentReference::operator=(const PDFDocumentReference& rhs) 69 | { 70 | if ( rhs.filename() != filename() ) { 71 | throw std::runtime_error("This PDFDocumentReference has a different filename"); 72 | } 73 | if ( rhs.cacheOption() != cacheOption() ) { 74 | throw std::runtime_error("This PDFDocumentReference has a different cache setting"); 75 | } 76 | fileContents_=rhs.fileContents_; 77 | popplerDocument_=rhs.popplerDocument_; 78 | return *this; 79 | } 80 | 81 | bool operator==(const PDFDocumentReference& lhs, const PDFDocumentReference& rhs) 82 | { 83 | if ( lhs.cacheOption() != rhs.cacheOption() ) { 84 | return false; 85 | } 86 | else if ( lhs.cacheOption() == PDFCacheOption::keepPDFinMemory ) { 87 | DEBUGOUT << "Using memory cache, comparing byte-by-byte."; 88 | return lhs.fileContents_ == rhs.fileContents_; 89 | } 90 | else { 91 | DEBUGOUT << "Not using memory cache, just comparing the filename."; 92 | return lhs.filename() == rhs.filename(); 93 | } 94 | } 95 | 96 | -------------------------------------------------------------------------------- /pdfdocumentreference.h: -------------------------------------------------------------------------------- 1 | #ifndef PDFDOCUMENTREFERENCE_H 2 | #define PDFDOCUMENTREFERENCE_H 3 | #include 4 | #include 5 | #include "pdfcacheoption.h" 6 | #include "poppler-qt.h" 7 | 8 | #include 9 | 10 | // forward-declare 11 | struct PDFPageReference; 12 | 13 | /** Holds a reference to a PDF document. 14 | * 15 | * What exactly this means depends on the cache option: 16 | * If the cache option is hold in memory, this class wild have a 17 | * complete in-memory copy of the PDF file. 18 | * 19 | * If the cache option is reread from disk, the reference is 20 | * just the file name. 21 | * 22 | */ 23 | class PDFDocumentReference 24 | { 25 | private: 26 | const QString filename_; 27 | QByteArray fileContents_; 28 | const PDFCacheOption cacheOption_; 29 | // protects access to the poppler document 30 | mutable std::mutex mutex_; 31 | typedef std::lock_guard Lock; 32 | mutable QSharedPointer popplerDocument_; 33 | 34 | public: 35 | /** Create the document reference. 36 | * 37 | * If the cache option is keep in memory, this will read the entire file into memory. 38 | */ 39 | PDFDocumentReference( const QString& filename, const PDFCacheOption& cacheOption); 40 | 41 | /** Returns a Poppler::Page reference to the requested page number 42 | * NOTE: Until poppler supports multi-threading, this will 43 | * create a new Poppler::Document for each request. 44 | */ 45 | PDFPageReference page(unsigned pageNumber) const; 46 | 47 | /** Create a Poppler::Document from this reference. 48 | * If you did not cache the file to memory, this step will try to 49 | * read the file. 50 | */ 51 | QSharedPointer popplerDocument() const; 52 | 53 | /** get filename */ 54 | const QString& filename() const; 55 | 56 | /** get cache setting */ 57 | const PDFCacheOption& cacheOption() const; 58 | 59 | /** Update the document reference. 60 | * This only works if rhs has the same filename and cache options, 61 | * effectively only updating the file contents buffer. 62 | */ 63 | PDFDocumentReference& operator = (const PDFDocumentReference& rhs); 64 | 65 | /** Compares the references. Exact behaviour depends on the cache option: 66 | * If we are memory-caching, this compares the ByteArrays (i.e. checks for 67 | * identical files). 68 | * 69 | * If we are not caching, it just checks for the same filename. 70 | */ 71 | friend bool operator == (const PDFDocumentReference& lhs, const PDFDocumentReference& rhs); 72 | }; 73 | 74 | #endif // PDFDOCUMENTREFERENCE_H 75 | -------------------------------------------------------------------------------- /pdfpagereference.cpp: -------------------------------------------------------------------------------- 1 | #include "pdfpagereference.h" 2 | 3 | #include 4 | 5 | using boost::numeric_cast; 6 | 7 | PDFPageReference::PDFPageReference(const PDFDocumentReference& documentReference, const unsigned int& pageNumber): 8 | document( documentReference.popplerDocument() ), 9 | page( document->page( numeric_cast(pageNumber) ) ) 10 | { 11 | } 12 | -------------------------------------------------------------------------------- /pdfpagereference.h: -------------------------------------------------------------------------------- 1 | #ifndef PDFPAGEREFERENCE_H 2 | #define PDFPAGEREFERENCE_H 3 | 4 | #include 5 | #include "poppler-qt.h" 6 | #include "pdfdocumentreference.h" 7 | 8 | /** This holds a reference to a page in a certain document 9 | * WARNING: This also contains a shared pointer to the Poppler::Document, 10 | * so if you delete this object, using the returned page() is undefined 11 | * behaviour. 12 | */ 13 | struct PDFPageReference 14 | { 15 | const QSharedPointer document; 16 | const QSharedPointer page; 17 | 18 | 19 | PDFPageReference( const PDFDocumentReference& documentReference, const unsigned int& pageNumber ); 20 | }; 21 | 22 | #endif // PDFPAGEREFERENCE_H 23 | -------------------------------------------------------------------------------- /pdfrenderfactory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #include "pdfrenderfactory.h" 22 | #include "renderthread.h" 23 | #include "sconnect.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include "debug.h" 29 | #include "renderutils.h" 30 | 31 | #include 32 | 33 | namespace { 34 | /** Estimates size in bytes of a rendered Page 35 | * 36 | * This currently assumes 32 bit (4 byte) per pixel, and no 37 | * overhead. 38 | */ 39 | int cacheCost(const RenderedPage& renderedPage) { 40 | const QSize& imageSize = renderedPage.getImage().size(); 41 | return boost::numeric_cast(sizeof(RenderedPage)) + 42 | 4 * imageSize.width() * imageSize.height(); 43 | } 44 | } 45 | 46 | void PdfRenderFactory::pageThreadFinishedRendering(QSharedPointer renderedPage) 47 | { 48 | { 49 | QMutexLocker lock(&mutex); 50 | const RenderingIdentifier ident( renderedPage->getIdentifier() ); 51 | // Ignore this incoming rendering if it was from an old version 52 | if ( ident.theVersion != currentVersion ) 53 | return; 54 | 55 | renderedPages.insert(ident, new RenderedPage(*renderedPage), cacheCost(*renderedPage) ); 56 | currentlyRenderingPages.remove(ident); 57 | if ( renderedPages.contains(ident) ) { 58 | DEBUGOUT << "Stored" << ident << "into cache"; 59 | } else { 60 | WARNINGOUT << "Unable to store" << ident << "into the cache! It would cost" << 61 | cacheCost(*renderedPage) << "but Current load is" << 62 | renderedPages.totalCost() << "/" << renderedPages.maxCost(); 63 | } 64 | 65 | DEBUGOUT << "Current cache fill is " << 66 | renderedPages.totalCost() << "/" << renderedPages.maxCost() << '(' << 67 | 100.0 * renderedPages.totalCost() / renderedPages.maxCost() << "% )"; 68 | } 69 | 70 | emit pageRendered(renderedPage); 71 | } 72 | 73 | void PdfRenderFactory::rewatchFile() 74 | { 75 | if ( ! fileWatcher.files().contains( documentReference.filename() ) ) { 76 | fileWatcher.addPath( documentReference.filename() ); 77 | // Check if it has been added (i.e. if it exists) 78 | if ( fileWatcher.files().contains( documentReference.filename() ) ) { 79 | // The file was created in the meantime. FileWatcher does not report this as a "change", 80 | // So we have to check it manually. 81 | fileOnDiskChanged(documentReference.filename()); 82 | } 83 | } 84 | } 85 | 86 | 87 | 88 | PdfRenderFactory::PdfRenderFactory( const RuntimeConfiguration& rc): 89 | QObject(), 90 | documentReference(rc.filePathQString(), rc.cacheSetting()), 91 | fileWatcher(), 92 | fileWatcherRewatchTimer(), 93 | currentlyRenderingPages(), 94 | renderedPages( boost::numeric_cast(rc.cacheSizeBytes()) ), 95 | mutex(), 96 | currentVersion(0), 97 | // Attempt to read the document to get the number of pages within. 98 | // This will throw an error if the document is unreadable. 99 | numberOfPages_(documentReference.popplerDocument()->numPages()) 100 | { 101 | 102 | rewatchFile(); 103 | 104 | // register the on-change function 105 | sconnect(&fileWatcher, SIGNAL(fileChanged(QString)), this, SLOT(fileOnDiskChanged(QString))); 106 | 107 | // Make sure it re-watches the file 108 | fileWatcherRewatchTimer.setInterval(1000); 109 | sconnect(&fileWatcherRewatchTimer, SIGNAL(timeout()), this, SLOT(rewatchFile())); 110 | fileWatcherRewatchTimer.start(); 111 | } 112 | 113 | void PdfRenderFactory::requestPageRendering(const RenderingIdentifier& originalIdentifier, QThread::Priority priority) 114 | { 115 | QMutexLocker lock(&mutex); 116 | 117 | RenderingIdentifier renderingIdentifier(originalIdentifier); 118 | 119 | renderingIdentifier.theVersion = currentVersion; 120 | 121 | if ( renderedPages.contains(renderingIdentifier) ) 122 | { 123 | /* Page is ready. Take a copy and lets go. */ 124 | QSharedPointer page( new RenderedPage( * renderedPages.object(renderingIdentifier) )); 125 | emit pageRendered(page); 126 | return; 127 | } 128 | /* Page was not in cache. Check if its currently in the render stage. */ 129 | if ( currentlyRenderingPages.contains(renderingIdentifier) ) 130 | { 131 | /* Page is already rendering, so there is nothing to do. */ 132 | return; 133 | } 134 | /* Nobody is working on the page right now. Lets create it. */ 135 | 136 | RenderThread* t = new RenderThread( documentReference, renderingIdentifier ); 137 | sconnect(t, SIGNAL(renderingFinished(QSharedPointer)), this, SLOT(pageThreadFinishedRendering(QSharedPointer))); 138 | currentlyRenderingPages.insert(renderingIdentifier); 139 | QThreadPool::globalInstance()->start(t, priority); 140 | 141 | } 142 | 143 | void PdfRenderFactory::fileOnDiskChanged(const QString& filename) 144 | { 145 | DEBUGOUT << "File" << filename << "has changed on disk"; 146 | 147 | if ( filename != documentReference.filename() ) { 148 | DEBUGOUT << "Ignoring that file."; 149 | return; 150 | } 151 | 152 | // Add path back in case it was modified via "move temporary onto filename", 153 | // which filewatcher treats as a remove and stops watching 154 | 155 | try { 156 | emit pdfFileChanged(); 157 | 158 | { 159 | 160 | // Lock mutex 161 | QMutexLocker locker(&mutex); 162 | 163 | // Create a new File Reference 164 | PDFDocumentReference newDoc(filename, documentReference.cacheOption()); 165 | 166 | if ( documentReference.cacheOption() == PDFCacheOption::keepPDFinMemory ) { 167 | // If we keep them in memory, a byte-by-byte compare should be resonably fast. 168 | // If they are *identical*, we can skip the reloading. 169 | 170 | if( documentReference == newDoc ) { 171 | DEBUGOUT << "The new document compares identical to the old one, not doing anything."; 172 | return; 173 | } 174 | 175 | } 176 | DEBUGOUT << "The file on disk has different contents. Trying to parse it as PDF."; 177 | 178 | // Verify poppler can read this 179 | newDoc.popplerDocument(); 180 | 181 | // replace the current reference with the new one 182 | documentReference = newDoc; 183 | 184 | numberOfPages_ = documentReference.popplerDocument()->numPages(); 185 | DEBUGOUT << "New document has" << numberOfPages_ << "pages."; 186 | 187 | // clear the page cache 188 | clearAllCaches(); 189 | } 190 | 191 | emit pdfFileRereadSuccesfully(); 192 | } catch( std::runtime_error& ) { 193 | DEBUGOUT << "Unable to read the new reference. keeping the old one."; 194 | emit pdfFileRereadFailed(); 195 | } 196 | } 197 | 198 | void PdfRenderFactory::clearAllCaches() 199 | { 200 | 201 | // Increment version, so that incoming "old" renders will get ignored 202 | /// TODO: Send a termination signal to these lingering threads 203 | 204 | ++currentVersion; 205 | 206 | // No renders of the current version are taking place, incoming old renders 207 | // will be ignored. 208 | currentlyRenderingPages.clear(); 209 | 210 | // Remove the caches. Since we use explicit copy semantics, its safe to empty 211 | // these. 212 | renderedPages.clear(); 213 | 214 | } 215 | 216 | int PdfRenderFactory::numberOfPages() const 217 | { 218 | QMutexLocker lock(&mutex); 219 | return numberOfPages_; 220 | } 221 | 222 | PdfRenderFactory::~PdfRenderFactory() { 223 | RenderUtils::notifyShutdown(); 224 | } 225 | -------------------------------------------------------------------------------- /pdfrenderfactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #ifndef PDFRENDERFACTORY_H 22 | #define PDFRENDERFACTORY_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "poppler-qt.h" 32 | #include "renderedpage.h" 33 | #include "runtimeconfiguration.h" 34 | #include "pdfcacheoption.h" 35 | #include "pdfdocumentreference.h" 36 | 37 | 38 | /** Factory for rendered pages 39 | * 40 | * This class is responsible for rendering the PDF to images. 41 | * 42 | * You create a factory using a filename (if the file cannot be opened this will throw), 43 | * then you can simply request renderings by supplying the desired size and page part 44 | * to requestPageRendering. 45 | * 46 | * The class uses the global instance of QThreadPool and renders in paralell, meaning it 47 | * can take advantage of SMP or Multi-Core Systems. 48 | * 49 | * NOTE for updating the external file: 50 | * If you plan on rewriting the displayed file while this application is running, 51 | * you can cache the entire file to memory. This can be done via constructor parameter. 52 | * 53 | * That way, if you create an invalid PDF file (for example you make an error in your latex 54 | * document), it still has a copy of the old file present. 55 | * The tradeoff is that this will cost you additional memory for *the entire PDF file*, which 56 | * can be a lot if you have an image-heavy PDF file. 57 | * 58 | * The class will notify you via signals when it detects a file change. Then it will try to re-read 59 | * the file, and it will notify you if that has succeeded or failed. 60 | * 61 | * If the re-reading failed, you can still get pages from cache, and you can keep rendering new ones 62 | * if you have used the memory cache. However, if you try to render new pages, you will probably 63 | * experience strange behaviour or the program will crash. 64 | * 65 | * If the re-reading went well, the cache will be cleared and new page renders will use the new pdf 66 | * file. 67 | * 68 | */ 69 | class PdfRenderFactory : public QObject 70 | { 71 | Q_OBJECT 72 | 73 | private: 74 | PDFDocumentReference documentReference; 75 | QFileSystemWatcher fileWatcher; 76 | QTimer fileWatcherRewatchTimer; 77 | 78 | QSet< RenderingIdentifier > currentlyRenderingPages; 79 | QCache< RenderingIdentifier, RenderedPage> renderedPages; 80 | 81 | mutable QMutex mutex; 82 | 83 | /** This is a little helper for the cache-clear-function to detect 84 | * renderings that have been started before, but finished after 85 | * a cache clearing. 86 | */ 87 | quint64 currentVersion; 88 | 89 | int numberOfPages_; 90 | 91 | private: 92 | void clearAllCaches(); 93 | 94 | public: 95 | PdfRenderFactory( const RuntimeConfiguration& ); 96 | ~PdfRenderFactory() override; 97 | 98 | /** Request a page rendering. Defaults to low priority (i.e. background rendering), please set High priority manually 99 | * on the current page. 100 | */ 101 | void requestPageRendering( const RenderingIdentifier& originalIdentifier, QThread::Priority priority = QThread::LowPriority); 102 | 103 | int numberOfPages() const; 104 | 105 | private slots: 106 | void fileOnDiskChanged(const QString& filename); 107 | void pageThreadFinishedRendering( QSharedPointer renderedPage ); 108 | 109 | signals: 110 | void pageRendered( QSharedPointer renderedPage); 111 | 112 | void pdfFileChanged(); 113 | void pdfFileRereadSuccesfully(); 114 | void pdfFileRereadFailed(); 115 | 116 | public slots: 117 | void rewatchFile(); 118 | }; 119 | 120 | #endif // PDFRENDERFACTORY_H 121 | -------------------------------------------------------------------------------- /pdfviewerwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #ifndef PDFVIEWERWINDOW_H 22 | #define PDFVIEWERWINDOW_H 23 | 24 | #include "renderedpage.h" 25 | #include "pdfrenderfactory.h" 26 | #include "runtimeconfiguration.h" 27 | #include "hyperlinkarea.h" 28 | #include "windowrole.h" 29 | 30 | #include "ui_pdfviewerwindow.h" 31 | 32 | /** Shared base class for both windows (primary and secondary) 33 | * 34 | */ 35 | class PDFViewerWindow : public QWidget 36 | { 37 | Q_OBJECT 38 | private: 39 | Ui::Form ui; 40 | bool m_enabled; 41 | unsigned int m_monitor; 42 | QImage currentImage; 43 | bool blank; 44 | bool informationLineVisible; 45 | 46 | uint currentPageNumber; 47 | uint minimumPageNumber; 48 | uint maximumPageNumber; 49 | bool correctImageRendered; 50 | PagePart myPart; 51 | 52 | const WindowRole windowRole; 53 | // Reference to the runtime configuration object. 54 | const RuntimeConfiguration& runtimeConfiguration; 55 | 56 | /** Display this image 57 | */ 58 | void displayImage(QImage image); 59 | 60 | virtual void wheelEvent(QWheelEvent* e) override; 61 | 62 | virtual void keyPressEvent(QKeyEvent* e) override; 63 | 64 | virtual void mousePressEvent(QMouseEvent* e) override; 65 | 66 | void addThumbnail(uint pageNumber, QImage thumbnail); 67 | 68 | 69 | QString timeToString(const QTime& time) const; 70 | QString timeToString(int milliseconds) const; 71 | 72 | void keybindingsPopup(); 73 | void changePageNumberDialog(); 74 | 75 | void parseLinks( QList< AdjustedLink > links); 76 | QList< HyperlinkArea* > linkAreas; 77 | 78 | public: 79 | /** Standard constructor 80 | * @param monitor monitor to start on (usually 0 for primary) 81 | */ 82 | explicit PDFViewerWindow(unsigned int monitor, PagePart myPart, bool showInformationLine, const RuntimeConfiguration& r, const WindowRole& windowRole, bool enabled=true); 83 | 84 | /** Sets the monitor to display this window on 85 | * Automatically calls reposition 86 | */ 87 | void setMonitor(const unsigned int monitor); 88 | 89 | /** Gets the current monitor setting 90 | */ 91 | unsigned int getMonitor() const; 92 | 93 | /** Reposition the window (for example after a monitor change) 94 | */ 95 | void reposition(); 96 | 97 | QSize getTargetImageSize() const; 98 | 99 | QSize getPreviewImageSize(); 100 | 101 | PagePart getMyPagePart() const; 102 | 103 | void showInformationLine(); 104 | 105 | void hideInformationLine(); 106 | 107 | bool isInformationLineVisible() const; 108 | 109 | bool isBlank() const; 110 | 111 | void showLoadingScreen(uint pageNumberToWaitFor); 112 | 113 | public slots: 114 | void renderedPageIncoming( QSharedPointer renderedPage); 115 | 116 | void resizeEvent(QResizeEvent* resizeEvent) override; 117 | 118 | void updateWallClock(const QTime& wallClock); 119 | void updateSlideClock(const QTime& slideClock); 120 | void updatePresentationClock(const QTime& presentationClock); 121 | 122 | void setPageNumberLimits(uint minimumPageNumber, uint maximumPageNumber); 123 | 124 | void setBlank(const bool blank); 125 | 126 | void setMyPagePart(const PagePart& newPagePart); 127 | 128 | signals: 129 | void nextPageRequested(); 130 | void previousPageRequested(); 131 | void pageRequested(unsigned requestedPageNumber); 132 | void restartRequested(); 133 | 134 | void screenSwapRequested(); 135 | 136 | void rerenderRequested(); 137 | 138 | void quitRequested(); 139 | void secondScreenFunctionToggleRequested(); 140 | void secondScreenDuplicateRequested(); 141 | 142 | void blankToggleRequested(); 143 | private slots: 144 | void linkClicked(uint targetNumber); 145 | }; 146 | 147 | #endif // PDFVIEWERWINDOW_H 148 | -------------------------------------------------------------------------------- /pdfviewerwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1216 10 | 808 11 | 12 | 13 | 14 | DS PDF Viewer 15 | 16 | 17 | #Form, 18 | #thumbnailAreaWidget, 19 | #bottomArea QLabel, 20 | #imageArea, 21 | #imageLabel 22 | { 23 | background-color: black; 24 | color: white; 25 | } 26 | 27 | 28 | 29 | 0 30 | 31 | 32 | 0 33 | 34 | 35 | 36 | 37 | Qt::NoFocus 38 | 39 | 40 | QFrame::NoFrame 41 | 42 | 43 | 0 44 | 45 | 46 | Qt::ScrollBarAlwaysOff 47 | 48 | 49 | Qt::ScrollBarAlwaysOff 50 | 51 | 52 | false 53 | 54 | 55 | Qt::AlignCenter 56 | 57 | 58 | 59 | 60 | 508 61 | 311 62 | 200 63 | 25 64 | 65 | 66 | 67 | 68 | 0 69 | 0 70 | 71 | 72 | 73 | The actual image goes here. 74 | 75 | 76 | false 77 | 78 | 79 | Qt::AlignCenter 80 | 81 | 82 | Qt::NoTextInteraction 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 0 92 | 0 93 | 94 | 95 | 96 | 97 | 16777215 98 | 16777215 99 | 100 | 101 | 102 | 103 | 0 104 | 105 | 106 | 107 | 108 | 109 | 0 110 | 0 111 | 112 | 113 | 114 | 115 | 25 116 | 117 | 118 | 119 | 09:12:34 120 | 121 | 122 | Qt::AlignCenter 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 16777215 131 | 16777215 132 | 133 | 134 | 135 | Qt::NoFocus 136 | 137 | 138 | QFrame::NoFrame 139 | 140 | 141 | 0 142 | 143 | 144 | Qt::ScrollBarAlwaysOff 145 | 146 | 147 | Qt::ScrollBarAlwaysOff 148 | 149 | 150 | true 151 | 152 | 153 | 154 | 155 | 0 156 | 0 157 | 829 158 | 162 159 | 160 | 161 | 162 | 163 | 0 164 | 165 | 166 | 0 167 | 168 | 169 | 170 | 171 | Next Page 172 | 173 | 174 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 0 183 | 0 184 | 185 | 186 | 187 | Current Page 188 | 189 | 190 | Qt::AlignCenter 191 | 192 | 193 | 194 | 195 | 196 | 197 | Previous Page 198 | 199 | 200 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 0 213 | 0 214 | 215 | 216 | 217 | 218 | 25 219 | 220 | 221 | 222 | Total 223 | 00:00:00 224 | 225 | 226 | Qt::AlignCenter 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 0 235 | 0 236 | 237 | 238 | 239 | 240 | 50 241 | 242 | 243 | 244 | 00:00 245 | 246 | 247 | Qt::AlignCenter 248 | 249 | 250 | 251 | 252 | thumbnailArea 253 | presentationClock 254 | wallClock 255 | slideClock 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | -------------------------------------------------------------------------------- /poppler-qt.h: -------------------------------------------------------------------------------- 1 | #ifndef POPPLER_QT5 2 | #include 3 | #else 4 | #include 5 | 6 | #if defined( WINDOWS_STATIC_LINK ) && ! defined( qtplugin ) 7 | #define qtplugin 8 | #if defined(WIN32) || defined(WIN64) 9 | #include 10 | Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) 11 | #endif 12 | #endif 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /renderedpage.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #include "renderedpage.h" 22 | 23 | #include "renderingidentifier.h" 24 | 25 | RenderingIdentifier RenderedPage::getIdentifier() const 26 | { 27 | return theIdentifier; 28 | } 29 | 30 | QImage RenderedPage::getImage() const 31 | { 32 | return theRenderedImage; 33 | } 34 | 35 | QList< AdjustedLink > RenderedPage::getLinks() const 36 | { 37 | return theLinks; 38 | } 39 | 40 | unsigned RenderedPage::getPageNumber() const 41 | { 42 | return getIdentifier().pageNumber(); 43 | } 44 | 45 | 46 | PagePart RenderedPage::getPart() const 47 | { 48 | return getIdentifier().pagePart(); 49 | } 50 | 51 | RenderedPage::RenderedPage(QImage img, QList< AdjustedLink > links, PagePart whichPart, unsigned pageNum) 52 | : theRenderedImage(img), theLinks(links), theIdentifier(pageNum, whichPart, img.size()) 53 | { 54 | 55 | } 56 | 57 | RenderedPage::RenderedPage(QImage img, QList< AdjustedLink > links, RenderingIdentifier identifier) 58 | : theRenderedImage(img), theLinks(links), theIdentifier(identifier) 59 | { 60 | 61 | } 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /renderedpage.h: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #ifndef RENDEREDPAGE_H 22 | #define RENDEREDPAGE_H 23 | #include 24 | #include "poppler-qt.h" 25 | #include "pagepart.h" 26 | #include "renderingidentifier.h" 27 | #include "adjustedlink.h" 28 | 29 | class RenderedPage 30 | { 31 | private: 32 | QImage theRenderedImage; 33 | QList< AdjustedLink > theLinks; 34 | RenderingIdentifier theIdentifier; 35 | public: 36 | 37 | RenderedPage(QImage img, QList links, PagePart whichPart, unsigned pageNum); 38 | RenderedPage(QImage img, QList links, RenderingIdentifier identifier); 39 | QImage getImage() const; 40 | QList< AdjustedLink > getLinks() const; 41 | PagePart getPart() const; 42 | uint getPageNumber() const; 43 | RenderingIdentifier getIdentifier() const; 44 | }; 45 | 46 | Q_DECLARE_METATYPE(QSharedPointer) 47 | 48 | #endif // RENDEREDPAGE_H 49 | -------------------------------------------------------------------------------- /renderingidentifier.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #include "renderingidentifier.h" 22 | #include 23 | #include 24 | #include 25 | 26 | #if defined ( POPPLER_QT5 ) 27 | #include 28 | #else 29 | #include 30 | #endif 31 | 32 | bool RenderingIdentifier::operator==(const RenderingIdentifier& other) const 33 | { 34 | return 35 | thePageNumber == other.thePageNumber 36 | && thePagePart == other.thePagePart 37 | && theRequestedPageSize == other.theRequestedPageSize; 38 | } 39 | 40 | #if 0 41 | RenderingIdentifier::operator QString() const 42 | { 43 | QString s( "page%1_%2_size%3x%4" ) ; 44 | QString partId; 45 | switch( pagePart() ) { 46 | case PagePart::LeftHalf: 47 | partId= "LeftHalf"; 48 | break; 49 | case PagePart::RightHalf: 50 | partId="RightHalf"; 51 | break; 52 | case PagePart::FullPage: 53 | partId="FullPage"; 54 | break; 55 | } 56 | return s.arg(pageNumber()).arg(partId).arg(requestedPageSize().width()).arg(requestedPageSize().height()); 57 | } 58 | #endif 59 | 60 | unsigned RenderingIdentifier::pageNumber() const 61 | { 62 | return thePageNumber; 63 | } 64 | 65 | PagePart RenderingIdentifier::pagePart() const 66 | { 67 | return thePagePart; 68 | } 69 | 70 | QSize RenderingIdentifier::requestedPageSize() const 71 | { 72 | return theRequestedPageSize; 73 | } 74 | 75 | RenderingIdentifier::RenderingIdentifier(unsigned pagenum, PagePart pagepart, QSize pagesize): 76 | thePageNumber(pagenum), 77 | thePagePart(pagepart), 78 | theRequestedPageSize(pagesize), 79 | theVersion(1) 80 | { 81 | 82 | } 83 | 84 | 85 | uint qHash(const RenderingIdentifier& ri) 86 | { 87 | return qHash(ri.pageNumber()) ^ qHash(ri.requestedPageSize().height()) ^ qHash(ri.requestedPageSize().width()); 88 | } 89 | 90 | QDebug operator << (QDebug d, const RenderingIdentifier& ri) { 91 | #if defined ( POPPLER_QT5 ) 92 | // QDebugStateSaver only exists in Qt5.1 93 | QDebugStateSaver s(d); 94 | #endif 95 | std::ostringstream oss; 96 | oss << ri.pagePart(); 97 | d.nospace() << "[page " << ri.pageNumber() << '/' << oss.str().c_str() << '/' << 98 | ri.requestedPageSize().width() << 'x' << ri.requestedPageSize().height() << ']'; 99 | return d; 100 | } 101 | -------------------------------------------------------------------------------- /renderingidentifier.h: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #ifndef RENDERINGIDENTIFIER_H 22 | #define RENDERINGIDENTIFIER_H 23 | #include "pagepart.h" 24 | #include 25 | #include 26 | #include 27 | 28 | class RenderingIdentifier 29 | { 30 | private: 31 | unsigned thePageNumber; 32 | PagePart thePagePart; 33 | QSize theRequestedPageSize; 34 | 35 | public: 36 | /* 37 | * 38 | * This will be set and checked by PDFRenderFactory 39 | */ 40 | quint64 theVersion; 41 | 42 | RenderingIdentifier(unsigned pagenum, PagePart pagepart, QSize requestedPageSize); 43 | unsigned pageNumber() const; 44 | PagePart pagePart() const; 45 | QSize requestedPageSize() const; 46 | 47 | bool operator == (const RenderingIdentifier& other) const; 48 | 49 | #if 0 50 | /** Cast to a string that is usable as a hash identifier **/ 51 | operator QString() const; 52 | #endif 53 | }; 54 | 55 | /** Hashes this object to something useable in the cache */ 56 | uint qHash(const RenderingIdentifier& ri); 57 | 58 | /** allow outputting a rendering identifier */ 59 | QDebug operator << ( QDebug, const RenderingIdentifier&); 60 | 61 | #endif // RENDERINGIDENTIFIER_H 62 | -------------------------------------------------------------------------------- /renderthread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #include "renderthread.h" 22 | #include "renderutils.h" 23 | #include "adjustedlink.h" 24 | #include "debug.h" 25 | 26 | RenderThread::RenderThread(const PDFDocumentReference& theDocument, const RenderingIdentifier& renderIdent): 27 | QObject(), 28 | QRunnable(), 29 | m_page( theDocument.page( renderIdent.pageNumber() ) ), 30 | renderMe(renderIdent) 31 | { 32 | } 33 | 34 | void RenderThread::run() 35 | { 36 | DEBUGOUT << "RenderThread for" << renderMe << "started"; 37 | QImage renderImage = RenderUtils::renderPagePart(m_page.page, renderMe.requestedPageSize(), renderMe.pagePart()); 38 | if ( renderImage.isNull() ) 39 | { 40 | WARNINGOUT << "RenderThread for" << renderMe << "failed"; 41 | QSharedPointer ri( new RenderingIdentifier(renderMe) ); 42 | emit renderingFailed(ri); 43 | return; 44 | } 45 | 46 | QList< AdjustedLink > links; 47 | 48 | for( Poppler::Link* link: m_page.page->links() ) 49 | { 50 | QSharedPointer ptrLink(link); 51 | try{ 52 | AdjustedLink al(renderMe, ptrLink); 53 | links.append(al); 54 | } catch( AdjustedLink::OutsidePage &) { 55 | // no-op 56 | } 57 | } 58 | QSharedPointer renderResult(new RenderedPage( renderImage, links, renderMe )); 59 | DEBUGOUT << "RenderThread for" << renderMe << "successful, image has size" << renderResult->getImage().size(); 60 | emit renderingFinished(renderResult); 61 | } 62 | -------------------------------------------------------------------------------- /renderthread.h: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #ifndef RENDERTHREAD_H 22 | #define RENDERTHREAD_H 23 | 24 | #include 25 | #include 26 | #include "renderedpage.h" 27 | #include "pdfpagereference.h" 28 | 29 | class RenderThread: public QObject, public QRunnable 30 | { 31 | Q_OBJECT 32 | 33 | private: 34 | const PDFPageReference m_page; 35 | RenderingIdentifier renderMe; 36 | 37 | public: 38 | RenderThread( const PDFDocumentReference& theDocument, const RenderingIdentifier& renderIdent); 39 | 40 | void run() override; 41 | 42 | signals: 43 | void renderingFinished(QSharedPointer result); 44 | void renderingFailed(QSharedPointer requestedRender); 45 | }; 46 | 47 | #endif // RENDERTHREAD_H 48 | -------------------------------------------------------------------------------- /renderutils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #include "renderutils.h" 22 | 23 | #include "debug.h" 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | using boost::math::iround; 30 | 31 | namespace { 32 | bool shuttingDown = false; 33 | } 34 | 35 | QImage RenderUtils::renderPagePart(QSharedPointer< const Poppler::Page > page, QSize targetSize, PagePart whichPart) 36 | { 37 | if ( ! page ) 38 | { 39 | throw std::runtime_error( std::string( qPrintable( QApplication::translate("RenderUtils", "RenderUtils::renderPagePart called with null page. Target size was %1x%2"). 40 | arg(targetSize.width()).arg(targetSize.height()) ) ) ); 41 | } 42 | 43 | if ( shuttingDown ) 44 | return QImage(); 45 | 46 | /* pagesize in points, (72 points is an inch) */ 47 | QSizeF pagesize = page->pageSizeF(); 48 | QSizeF fullsize = pagesize; 49 | 50 | if ( whichPart != PagePart::FullPage ) 51 | { 52 | /* Only render half the page */ 53 | pagesize.setWidth(pagesize.width()/2); 54 | } 55 | 56 | /* Calculate DPI for displaying on size */ 57 | /* the 72 comes from converting from points to inches */ 58 | double dpiWidth = 72.0 * targetSize.width() / pagesize.width(); 59 | double dpiHeight = 72.0 * targetSize.height() / pagesize.height(); 60 | 61 | /* Take the smaller one, so that the image surely fits on target area */ 62 | double dpi = std::min(dpiWidth, dpiHeight); 63 | 64 | /* Calculate Page Size in pixels */ 65 | 66 | QSize fullSizePixels( iround(dpi * fullsize.width() / 72.0), 67 | iround(dpi * fullsize.height() / 72.0) ); 68 | 69 | /* Calculate rendered image size */ 70 | QSize imageSizePixels( iround(dpi * pagesize.width() / 72.0), 71 | iround( dpi * pagesize.height() / 72.0 ) ); 72 | 73 | /* Calculate x-offset */ 74 | int x = 0; 75 | if ( whichPart == PagePart::RightHalf ) { 76 | /* start at an offset of width() pixels to the right, rounding up */ 77 | x = (fullSizePixels.width()+1)/2; 78 | } 79 | 80 | /* render it */ 81 | QImage renderedImage = page->renderToImage( 82 | dpi, dpi, 83 | x, /* x-offset */ 84 | 0, /* y-offset */ 85 | imageSizePixels.width(), 86 | imageSizePixels.height() 87 | ); 88 | 89 | return renderedImage; 90 | } 91 | 92 | void RenderUtils::notifyShutdown(void) { 93 | shuttingDown = true; 94 | } 95 | -------------------------------------------------------------------------------- /renderutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #ifndef RENDERUTILS_H 22 | #define RENDERUTILS_H 23 | 24 | #include 25 | #include "pagepart.h" 26 | #include 27 | #include "poppler-qt.h" 28 | 29 | class RenderUtils 30 | { 31 | public: 32 | static QImage renderPagePart(QSharedPointer page, QSize targetSize, PagePart whichPart); 33 | 34 | /** Since only the static functions of this class are used, we do not need to construct instances */ 35 | RenderUtils() =delete; 36 | 37 | /** Notifies about impending shutdown. 38 | * 39 | * All further render attempts will return null images. 40 | */ 41 | static void notifyShutdown(void); 42 | }; 43 | 44 | #endif // RENDERUTILS_H 45 | -------------------------------------------------------------------------------- /runtimeconfiguration.h: -------------------------------------------------------------------------------- 1 | /* 2 | dspdfviewer - Dual Screen PDF Viewer for LaTeX-Beamer 3 | Copyright (C) 2012 Danny Edel 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | 21 | #ifndef RUNTIMECONFIGURATION_H 22 | #define RUNTIMECONFIGURATION_H 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "pagepart.h" 28 | #include "pdfcacheoption.h" 29 | 30 | struct noFileNameException: public std::logic_error { 31 | noFileNameException(); 32 | }; 33 | 34 | class RuntimeConfiguration: public QObject 35 | { 36 | Q_OBJECT 37 | 38 | /** Use the program to render a standard PDF (i.e. display 39 | * the full page on both sides) 40 | */ 41 | bool m_useFullPage; 42 | 43 | /** Show presenter area 44 | */ 45 | bool m_showPresenterArea; 46 | 47 | /** Show a full second screen 48 | */ 49 | bool m_duplicate; 50 | 51 | /** Show the wall clock 52 | */ 53 | bool m_showWallClock; 54 | 55 | /** Show the thumbnails of previous, this and next slide */ 56 | bool m_showThumbnails; 57 | 58 | /** Select page part of the thumbnails */ 59 | PagePart m_thumbnailPagePart; 60 | 61 | /** Show the total presentation time **/ 62 | bool m_showPresentationClock; 63 | 64 | /** Show the current slide time **/ 65 | bool m_showSlideClock; 66 | 67 | /** complete path to the PDF file */ 68 | std::string m_filePath; 69 | 70 | /** Support PDF Hyperlinks**/ 71 | bool m_hyperlinkSupport; 72 | 73 | /** Shall the complete PDF be read into memory */ 74 | bool m_cacheToMemory; 75 | 76 | /** Size of the pre-render-cache in megabytes */ 77 | unsigned m_cacheSizeMegaBytes; 78 | 79 | /** Single-Display mode 80 | * 81 | * If True, there is only the audience display, the presenter's screen will remain hidden 82 | * Probably most useful with -f 83 | */ 84 | bool m_useSecondScreen; 85 | 86 | /** Workaround for i3 window manager active 87 | */ 88 | bool m_i3workaround; 89 | 90 | /** Make sure that so many previous pages are pre-rendered 91 | * (Probably wont make sense until you can jump to slide 92 | * n without visiting 0..(n-1) first, but once PDF hyperlinks 93 | * are enabled, this will be quite useful. 94 | */ 95 | unsigned m_prerenderPreviousPages; 96 | 97 | /** Make sure so many next pages are pre-rendered 98 | */ 99 | unsigned m_prerenderNextPages; 100 | 101 | /** 102 | * Percentage of the second screen devoted to the bottom pane 103 | */ 104 | unsigned m_bottomPaneHeightPercent; 105 | public: 106 | 107 | /** fill the variables based on the config file and the C-style arguments to main() 108 | * 109 | * Note: Reads the config file before command-line arguments. 110 | * Command-line overrides config. 111 | * 112 | * Note: Might call exit() if a terminating option like --help 113 | * or --version was called. 114 | * 115 | * Note: Might throw exceptions if not parsable. 116 | */ 117 | RuntimeConfiguration(int argc, const char * const * argv); 118 | 119 | bool useFullPage() const; 120 | 121 | bool filePathDefined() const; 122 | 123 | QString filePathQString() const; 124 | 125 | std::string filePath() const; 126 | void filePath(const std::string& newPath); 127 | 128 | bool showPresenterArea() const; 129 | bool duplicate() const; 130 | bool showWallClock() const; 131 | bool showThumbnails() const; 132 | PagePart thumbnailPagePart() const; 133 | bool showPresentationClock() const; 134 | bool showSlideClock() const; 135 | 136 | unsigned prerenderPreviousPages() const; 137 | unsigned prerenderNextPages() const; 138 | 139 | unsigned cacheSizeMegaBytes() const; 140 | unsigned cacheSizeBytes() const; 141 | 142 | bool useSecondScreen() const; 143 | 144 | PDFCacheOption cacheSetting() const; 145 | 146 | unsigned bottomPaneHeight() const; 147 | bool hyperlinkSupport() const; 148 | 149 | /* Use i3-workaround. 150 | * 151 | * In the future, this might auto-detect if we're running on i3. 152 | */ 153 | bool i3workaround() const; 154 | 155 | /* What shellcode to execute. 156 | * 157 | * This may be programatically generated in the future. 158 | */ 159 | std::string i3workaround_shellcode() const; 160 | }; 161 | 162 | #endif // RUNTIMECONFIGURATION_H 163 | -------------------------------------------------------------------------------- /sconnect.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** secure connect: 4 | * 5 | * Quick and dirty hack to check QObject::connect()'s return value 6 | */ 7 | template 8 | void sconnect(Sender sender, Signal signal, Receiver receiver, Slot slot, Qt::ConnectionType type=Qt::AutoConnection) { 9 | bool okay = QObject::connect( 10 | sender, signal, receiver, slot, type); 11 | if ( ! okay ) { 12 | throw std::runtime_error( 13 | std::string("QObject::connect failed. sender: ")+signal+" receiver: "+slot); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /testing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Test driver library for convenience linking. 2 | add_library(testhelp 3 | testhelpers.cc 4 | ) 5 | # Link this helper library to dspdfviewer's functions 6 | target_link_libraries(testhelp 7 | libdspdfviewer 8 | ${LIST_TEST_LIBRARIES} 9 | ) 10 | 11 | list(APPEND PDFFILENAMES 12 | colored-rectangles.pdf 13 | images.pdf 14 | many-many-pages.pdf 15 | ) 16 | 17 | if(DownloadTestPDF) 18 | message(WARNING "DownloadTestPDF option has been deprectated, since " 19 | "prerendered PDFs are now included in the source. Use the option 20 | -DUsePrerenderedPDF=ON from now on.") 21 | set(UsePrerenderedPDF ON) 22 | endif() 23 | 24 | if(UsePrerenderedPDF) 25 | foreach(pdffile IN LISTS PDFFILENAMES) 26 | file( 27 | COPY "pdfs/${pdffile}" 28 | DESTINATION . 29 | ) 30 | message(STATUS "Using pre-rendered ${pdffile}") 31 | endforeach() 32 | else() 33 | # Compile from source 34 | find_program(PDFLATEX 35 | NAMES pdflatex 36 | ) 37 | if( PDFLATEX STREQUAL "PDFLATEX-NOTFOUND") 38 | message(FATAL_ERROR "Compiling PDFs from source requires pdflatex with latex-beamer installed") 39 | endif() 40 | foreach(pdffile IN LISTS PDFFILENAMES) 41 | # get source file name. 42 | # replace .pdf with .tex ending, 43 | # prefix source directory 44 | # and replace any ~ characters in filename with \\string~ 45 | STRING(REGEX REPLACE "\\.pdf$" ".tex" SOURCEFILENAME ${pdffile}) 46 | SET(SOURCEDIRNAME "${CMAKE_CURRENT_SOURCE_DIR}/pdfs") 47 | SET(SOURCEFULLPATH "${SOURCEDIRNAME}/${SOURCEFILENAME}") 48 | STRING(REPLACE "~" "\\\\string~" PDFLATEX_FIXED_DIRNAME ${SOURCEDIRNAME}) 49 | SET(PDFLATEX_FIXED_FILENAME "${PDFLATEX_FIXED_DIRNAME}/${SOURCEFILENAME}") 50 | 51 | add_custom_command(OUTPUT ${pdffile} 52 | DEPENDS ${SOURCEFULLPATH} 53 | COMMAND # env TEXINPUTS=${SOURCEDIRNAME} 54 | ${PDFLATEX} 55 | -interaction=nonstopmode 56 | -output-directory ${CMAKE_CURRENT_BINARY_DIR} 57 | ${PDFLATEX_FIXED_FILENAME} 58 | WORKING_DIRECTORY ${SOURCEDIRNAME} 59 | ) 60 | 61 | message(STATUS "Building ${pdffile} from source.") 62 | endforeach() 63 | endif() 64 | 65 | foreach(pdffile IN LISTS PDFFILENAMES) 66 | list(APPEND PDFTARGETFILES ${CMAKE_CURRENT_BINARY_DIR}/${pdffile}) 67 | endforeach() 68 | add_custom_target(testpdfs DEPENDS 69 | ${PDFTARGETFILES} 70 | ) 71 | 72 | 73 | add_dependencies(testhelp testpdfs) 74 | 75 | # Allow the programs headers to be found using #include <...> 76 | include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../ ) 77 | 78 | # Now add actual tests. 79 | add_executable(testrunner 80 | testrenderonepage.cc 81 | test-images.cc 82 | testrunner.cc 83 | test-thumbnail-cmdline.cc 84 | ) 85 | 86 | target_link_libraries(testrunner testhelp) 87 | 88 | # Clang/G++: Don't promote warnings to errors when building the test suite. 89 | if(CMAKE_COMPILER_IS_GNUCXX) 90 | set_target_properties(testrunner 91 | PROPERTIES 92 | COMPILE_FLAGS "-Wno-error=effc++" 93 | ) 94 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" ) 95 | set_target_properties(testrunner 96 | PROPERTIES 97 | COMPILE_FLAGS "-Wno-error=global-constructors" 98 | ) 99 | endif() 100 | 101 | add_test(NAME BoostTestRunner 102 | COMMAND testrunner --report_level=detailed 103 | ) 104 | 105 | # Check whether --version and --help contain 106 | # the version in their output 107 | add_test(NAME TestCommandLineVersion 108 | COMMAND dspdfviewer --version 109 | ) 110 | add_test(NAME TestCommandLineHelp 111 | COMMAND dspdfviewer --help 112 | ) 113 | set_tests_properties( 114 | TestCommandLineVersion 115 | TestCommandLineHelp 116 | PROPERTIES 117 | PASS_REGULAR_EXPRESSION ${DSPDFVIEWER_VERSION} 118 | ) 119 | 120 | # Only build and run the swap screen test on Qt5 121 | add_executable(testswapscreen 122 | testswapscreen.cc 123 | testswapscreen-main.cc 124 | ) 125 | target_link_libraries(testswapscreen 126 | testhelp 127 | ) 128 | 129 | if(RunDualScreenTests) 130 | add_test(NAME testswapscreen 131 | COMMAND testswapscreen 132 | --prerender-prev=0 133 | --prerender-next=0 134 | images.pdf 135 | ) 136 | set_tests_properties(testswapscreen 137 | PROPERTIES 138 | SKIP_RETURN_CODE 77 139 | ) 140 | endif() 141 | 142 | 143 | # On windows you cannot change the locale on a case-by-case basis. 144 | # 145 | # FIXME: Windows: Discover current locale 146 | # FIXME: Windows: Include the translation test for the current locale 147 | 148 | if(NOT WINDOWS) 149 | add_test(NAME EnglishByDefault 150 | COMMAND dspdfviewer --help 151 | ) 152 | 153 | set(ENVVARS 154 | "LC_ALL=C.UTF-8:C" 155 | "LANGUAGE=C" 156 | ) 157 | 158 | set_tests_properties(EnglishByDefault PROPERTIES 159 | PASS_REGULAR_EXPRESSION "Interactive Controls" 160 | ENVIRONMENT "${ENVVARS}" 161 | ) 162 | 163 | # the ENVIRONMENT property was added in 2.8.0 164 | add_test(NAME GermanWithDeDE 165 | COMMAND dspdfviewer --help 166 | ) 167 | 168 | set(ENVVARS 169 | "LC_ALL=de_DE.UTF-8:de_DE" 170 | "LANGUAGE=de" 171 | ) 172 | 173 | set_tests_properties(GermanWithDeDE PROPERTIES 174 | PASS_REGULAR_EXPRESSION "Interaktive Tasten" 175 | ENVIRONMENT "${ENVVARS}" 176 | ) 177 | endif() 178 | -------------------------------------------------------------------------------- /testing/pdfs/colored-rectangles.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannyedel/dspdfviewer/d432d8d60de3d41a7b9ca1bc031b2344e8009d26/testing/pdfs/colored-rectangles.pdf -------------------------------------------------------------------------------- /testing/pdfs/colored-rectangles.tex: -------------------------------------------------------------------------------- 1 | \documentclass[aspectratio=169]{beamer} 2 | \usepackage{color} 3 | \usepackage{pgfpages} 4 | 5 | \setbeameroption{show notes on second screen} 6 | 7 | \title{Colored Pages without content} 8 | 9 | \begin{document} 10 | 11 | 12 | 13 | \definecolor{8f8}{HTML}{88FF88} 14 | \definecolor{f8f}{HTML}{FF88FF} 15 | 16 | \begingroup 17 | \setbeamercolor{background canvas}{bg=8f8} 18 | \setbeamercolor{note page}{bg=f8f} 19 | \begin{frame} 20 | \end{frame} 21 | \endgroup 22 | 23 | \end{document} 24 | -------------------------------------------------------------------------------- /testing/pdfs/images.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannyedel/dspdfviewer/d432d8d60de3d41a7b9ca1bc031b2344e8009d26/testing/pdfs/images.pdf -------------------------------------------------------------------------------- /testing/pdfs/images.tex: -------------------------------------------------------------------------------- 1 | \documentclass[aspectratio=169]{beamer} 2 | \usepackage{color} 3 | \usepackage{pgfpages} 4 | 5 | \setbeameroption{show notes on second screen} 6 | 7 | \title{Image on primary screen} 8 | 9 | \begin{document} 10 | 11 | \begingroup 12 | \begin{frame} 13 | \begin{center} 14 | \includegraphics[width=0.5\textwidth]{jpeg-image} 15 | % Target color: 16 | % 112 29 193 // 701dc1 17 | \end{center} 18 | \end{frame} 19 | \begin{frame} 20 | \begin{center} 21 | \includegraphics[width=0.5\textwidth]{png-image} 22 | % Target color: 23 | % 20 99 180 // 1463b4 24 | \end{center} 25 | \end{frame} 26 | \endgroup 27 | 28 | \end{document} 29 | -------------------------------------------------------------------------------- /testing/pdfs/jpeg-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannyedel/dspdfviewer/d432d8d60de3d41a7b9ca1bc031b2344e8009d26/testing/pdfs/jpeg-image.jpg -------------------------------------------------------------------------------- /testing/pdfs/many-many-pages.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannyedel/dspdfviewer/d432d8d60de3d41a7b9ca1bc031b2344e8009d26/testing/pdfs/many-many-pages.pdf -------------------------------------------------------------------------------- /testing/pdfs/many-many-pages.tex: -------------------------------------------------------------------------------- 1 | \documentclass[aspectratio=169]{beamer} 2 | \usepackage{color} 3 | \usepackage{pgfpages} 4 | \usepackage{pgffor} 5 | 6 | \setbeameroption{show notes on second screen} 7 | 8 | \title{Many, Many, Many pages.} 9 | 10 | \begin{document} 11 | 12 | 13 | 14 | \definecolor{8f8}{HTML}{88FF88} 15 | \definecolor{f8f}{HTML}{FF88FF} 16 | 17 | \foreach \n in {1,...,100}{ 18 | 19 | \begingroup 20 | \setbeamercolor{background canvas}{bg=8f8} 21 | \setbeamercolor{note page}{bg=f8f} 22 | \begin{frame} 23 | Page \thepage 24 | \end{frame} 25 | \endgroup 26 | 27 | } 28 | 29 | \end{document} 30 | -------------------------------------------------------------------------------- /testing/pdfs/png-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannyedel/dspdfviewer/d432d8d60de3d41a7b9ca1bc031b2344e8009d26/testing/pdfs/png-image.png -------------------------------------------------------------------------------- /testing/test-images.cc: -------------------------------------------------------------------------------- 1 | #include "testhelpers.hh" 2 | 3 | using namespace std; 4 | using namespace TestHelpers; 5 | 6 | BOOST_AUTO_TEST_CASE(image_rendering) { 7 | PDFDocumentReference pdr( TestHelpers::pdfFilename("images.pdf"), PDFCacheOption::keepPDFinMemory ); 8 | 9 | auto first = RenderUtils::renderPagePart(pdr.page(0).page, QSize(1920,1080), PagePart::LeftHalf); 10 | auto second = RenderUtils::renderPagePart(pdr.page(1).page, QSize(1920,1080), PagePart::LeftHalf); 11 | 12 | auto firstColor = QColor( 0x70, 0x1e, 0xc1); 13 | auto secondColor = QColor( 0x14, 0x63, 0xb4); 14 | 15 | /** Check sizes of rendered images **/ 16 | BOOST_CHECK_EQUAL( QSize(1920,1080), first.size()); 17 | BOOST_CHECK_EQUAL( QSize(1920,1080), second.size()); 18 | 19 | /** Check pixels in the middle */ 20 | BOOST_CHECK_EQUAL( firstColor, QColor(first.pixel(960,540))); 21 | BOOST_CHECK_EQUAL( secondColor, QColor(second.pixel(960,540))); 22 | } 23 | -------------------------------------------------------------------------------- /testing/test-thumbnail-cmdline.cc: -------------------------------------------------------------------------------- 1 | #include "testhelpers.hh" 2 | 3 | // Test that the commandline accepts "left", "right" and "both", 4 | // but not another string. 5 | 6 | BOOST_AUTO_TEST_CASE(thumbnail_cmdline) { 7 | // correct arguments, left 8 | { 9 | const char * const argv[] = { 10 | "dspdfviewer", "--thumbnail-page-part", "left" 11 | }; 12 | RuntimeConfiguration rc{ 3, argv }; 13 | BOOST_CHECK_EQUAL( rc.thumbnailPagePart(), PagePart::LeftHalf ); 14 | } 15 | // shorthand, two words 16 | { 17 | const char * const argv[] = { 18 | "dspdfviewer", "-T", "left" 19 | }; 20 | RuntimeConfiguration rc{ 3, argv }; 21 | BOOST_CHECK_EQUAL( rc.thumbnailPagePart(), PagePart::LeftHalf ); 22 | } 23 | // shorthand, one word 24 | { 25 | const char * const argv[] = { 26 | "dspdfviewer", "-Tleft" 27 | }; 28 | RuntimeConfiguration rc{ 2, argv }; 29 | BOOST_CHECK_EQUAL( rc.thumbnailPagePart(), PagePart::LeftHalf ); 30 | } 31 | 32 | // right 33 | { 34 | const char* const argv[] = { 35 | "dspdfviewer", "--thumbnail-page-part", "right" 36 | }; 37 | RuntimeConfiguration rc{ 3, argv }; 38 | BOOST_CHECK_EQUAL( rc.thumbnailPagePart(), PagePart::RightHalf ); 39 | } 40 | { 41 | const char* const argv[] = { 42 | "dspdfviewer", "--thumbnail-page-part", "both" 43 | }; 44 | RuntimeConfiguration rc{ 3, argv }; 45 | BOOST_CHECK_EQUAL( rc.thumbnailPagePart(), PagePart::FullPage ); 46 | } 47 | 48 | // wrong argument 49 | { 50 | const char* const argv[] = { 51 | "dspdfviewer", "--thumbnail-page-part", "something" 52 | }; 53 | BOOST_CHECK_THROW( RuntimeConfiguration( 3, argv ) , std::logic_error ); 54 | } 55 | 56 | // no argument 57 | { 58 | const char* const argv[] = { 59 | "dspdfviewer", "--thumbnail-page-part" 60 | }; 61 | BOOST_CHECK_THROW( RuntimeConfiguration( 2, argv) , std::logic_error ); 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /testing/testhelpers.cc: -------------------------------------------------------------------------------- 1 | #include "testhelpers.hh" 2 | 3 | #include 4 | 5 | QString TestHelpers::pdfFilename(const std::string& basename) { 6 | const QString relativePart = QString::fromLocal8Bit( basename.c_str() ); 7 | const QDir myDir = QDir::current(); 8 | if ( ! myDir.exists(relativePart) ) { 9 | throw std::runtime_error("Could not find the test pdf. This is bad."); 10 | } 11 | return myDir.filePath(relativePart); 12 | } 13 | 14 | std::ostream& operator << (std::ostream& where, const QSize& what) { 15 | return where << "QSize(" << what.width() << 'x' << what.height() << ')'; 16 | } 17 | 18 | std::ostream& operator << (std::ostream& where, const QColor& what) { 19 | return where << "QColor(" << qPrintable( what.name() ) << ")"; 20 | } 21 | -------------------------------------------------------------------------------- /testing/testhelpers.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /** Include all headers to access the dspdfviewer objects */ 4 | #include "../adjustedlink.h" 5 | #include "../debug.h" 6 | #include "../dspdfviewer.h" 7 | #include "../hyperlinkarea.h" 8 | #include "../pagepart.h" 9 | #include "../pdfcacheoption.h" 10 | #include "../pdfdocumentreference.h" 11 | #include "../pdfpagereference.h" 12 | #include "../pdfrenderfactory.h" 13 | #include "../pdfviewerwindow.h" 14 | #include "../renderedpage.h" 15 | #include "../renderingidentifier.h" 16 | #include "../renderthread.h" 17 | #include "../renderutils.h" 18 | #include "../runtimeconfiguration.h" 19 | #include "../sconnect.h" 20 | #include "../windowrole.h" 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | namespace TestHelpers { 28 | 29 | /** Returns full path to the specified file */ 30 | QString pdfFilename( const std::string& basename ); 31 | 32 | /** Handle to a integration test environment. 33 | * Spawns an in-memory X-Server in the background and allows to send 34 | * keystrokes and inspect a certain pixel's color. 35 | */ 36 | class IntegrationTestEnv { 37 | public: 38 | /** 39 | * Starts a dummy X server and loads dspdfviewer with the 40 | * given command line arguments. 41 | */ 42 | IntegrationTestEnv( const std::vector & args); 43 | 44 | /** Send a keystroke and wait for a specified time 45 | * 46 | * See Qt::Key for the list of keys 47 | */ 48 | void sendKeyAndWait( const int& key, const std::chrono::milliseconds& t); 49 | 50 | /** Inspect pixel color */ 51 | QColor grabPixelColor( uint x, uint y); 52 | }; 53 | 54 | template 55 | inline 56 | void check(const T1& lhs, const T2& rhs, int failcode=2) { 57 | if ( ! (lhs == rhs) ) { 58 | WARNINGOUT << "Failure:" << lhs << "!=" << rhs; 59 | QApplication::exit(failcode); 60 | } else { 61 | DEBUGOUT << "All right." << lhs << "==" << rhs; 62 | } 63 | } 64 | } 65 | 66 | /** Print a QSize to a standard output stream */ 67 | std::ostream& operator << (std::ostream& where, const QSize& what); 68 | 69 | /** Print a QColor to a standard output stream */ 70 | std::ostream& operator << (std::ostream& where, const QColor& what); 71 | -------------------------------------------------------------------------------- /testing/testrenderonepage.cc: -------------------------------------------------------------------------------- 1 | #include "testhelpers.hh" 2 | 3 | using namespace std; 4 | using namespace TestHelpers; 5 | 6 | BOOST_AUTO_TEST_CASE(render_one_page) { 7 | PDFDocumentReference pdr( TestHelpers::pdfFilename("colored-rectangles.pdf"), PDFCacheOption::keepPDFinMemory ); 8 | 9 | const auto pageref = pdr.page(0); 10 | 11 | const auto left = RenderUtils::renderPagePart(pageref.page, QSize(1920,1080), PagePart::LeftHalf); 12 | const auto right = RenderUtils::renderPagePart(pageref.page, QSize(1920,1200), PagePart::RightHalf); 13 | const auto both = RenderUtils::renderPagePart(pageref.page, QSize(3840,1080), PagePart::FullPage); 14 | 15 | const auto leftScreenColor = QColor( 0x88, 0xff, 0x88); 16 | auto rightScreenColor = QColor( 0xff, 0x88, 0xff); 17 | 18 | /** Older texlive installation: Note page gets rendered white 19 | */ 20 | const auto fallbackRightScreenColor = QColor( 0xff, 0xff, 0xff); 21 | 22 | BOOST_CHECK_NE(rightScreenColor, fallbackRightScreenColor); 23 | 24 | /** Check sizes of rendered images **/ 25 | BOOST_CHECK_EQUAL( QSize(1920,1080), left.size()); 26 | BOOST_CHECK_EQUAL( QSize(1920,1080), right.size()); 27 | BOOST_CHECK_EQUAL( QSize(3840,1080), both.size()); 28 | 29 | /** Check middle pixel of left screen **/ 30 | BOOST_CHECK_EQUAL( leftScreenColor, QColor(left.pixel(960,540))); 31 | BOOST_CHECK_EQUAL( leftScreenColor, QColor(both.pixel(960,540))); 32 | 33 | const auto rightScreenMiddle = QColor(right.pixel(960,540)); 34 | 35 | BOOST_WARN_EQUAL( rightScreenColor, rightScreenMiddle ); 36 | /** Check middle pixel of right screen **/ 37 | if ( rightScreenMiddle == fallbackRightScreenColor) { 38 | BOOST_TEST_MESSAGE( "Middle of note screen was peak white, " 39 | ", using workaround for older latex-beamer versions."); 40 | rightScreenColor = fallbackRightScreenColor; 41 | } 42 | BOOST_CHECK_EQUAL( rightScreenColor, QColor(right.pixel(960,540))); 43 | BOOST_CHECK_EQUAL( rightScreenColor, QColor(both.pixel(2880,540))); 44 | 45 | /** Check all-the-way-left and all-the-way-right pixel colors */ 46 | BOOST_CHECK_EQUAL( leftScreenColor, QColor(left.pixel(0,540))); 47 | BOOST_CHECK_EQUAL( leftScreenColor, QColor(left.pixel(1919,540))); 48 | 49 | BOOST_CHECK_EQUAL( rightScreenColor, QColor(right.pixel(0,540))); 50 | BOOST_CHECK_EQUAL( rightScreenColor, QColor(right.pixel(1919,540))); 51 | 52 | BOOST_CHECK_EQUAL( leftScreenColor, QColor(both.pixel(0,540))); 53 | BOOST_CHECK_EQUAL( rightScreenColor, QColor(both.pixel(3839,540))); 54 | } 55 | -------------------------------------------------------------------------------- /testing/testrunner.cc: -------------------------------------------------------------------------------- 1 | 2 | #define BOOST_TEST_MAIN 3 | #include "testhelpers.hh" 4 | 5 | /** Boost will generate a main() function */ 6 | -------------------------------------------------------------------------------- /testing/testswapscreen-main.cc: -------------------------------------------------------------------------------- 1 | #include "testswapscreen.h" 2 | #include "testhelpers.hh" 3 | 4 | int main(int argc, char** argv) { 5 | 6 | QApplication qapp(argc,argv); 7 | 8 | qRegisterMetaType< QSharedPointer >("QSharedPointer"); 9 | 10 | RuntimeConfiguration rc{argc, argv}; 11 | 12 | DSPDFViewer dsp{rc}; 13 | SwapScreensAndCheckAlign testdriver{dsp}; 14 | 15 | sconnect(&testdriver, SIGNAL(screenSwapRequested()), &dsp, SLOT(swapScreens())); 16 | sconnect(&testdriver, SIGNAL(quitRequested()), &dsp, SLOT(exit())); 17 | 18 | return qapp.exec(); 19 | } 20 | -------------------------------------------------------------------------------- /testing/testswapscreen.cc: -------------------------------------------------------------------------------- 1 | #include "testswapscreen.h" 2 | #include "testhelpers.hh" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | using namespace TestHelpers; 10 | 11 | SwapScreensAndCheckAlign::SwapScreensAndCheckAlign(DSPDFViewer& d): 12 | dspdfviewer(d), 13 | screenPrimary( QApplication::screens().at(0)->geometry() ), 14 | screenSecondary( QApplication::screens().at(1)->geometry() ), 15 | verify(true) 16 | { 17 | DEBUGOUT << "Number of screens:" << QApplication::screens().size(); 18 | 19 | DEBUGOUT << "screen 0 [pri]:" << screenPrimary; 20 | DEBUGOUT << "screen 1 [sec]:" << screenSecondary; 21 | 22 | 23 | if ( QApplication::screens().size() != 2 ) { 24 | WARNINGOUT << "Not running in a dual-screen environment"; 25 | verify = false; 26 | } else if ( screenPrimary == screenSecondary ) { 27 | WARNINGOUT << "Cannot tell the screens apart"; 28 | verify = false; 29 | } else if ( screenPrimary.width() == 0 || screenPrimary.height() == 0 ) { 30 | WARNINGOUT << "Cannot query primary screen size"; 31 | verify = false; 32 | } else if ( screenSecondary.width() == 0 || screenSecondary.height() == 0 ) { 33 | WARNINGOUT << "Cannot query secondary screen size"; 34 | verify = false; 35 | } 36 | if ( ! verify ) { 37 | WARNINGOUT << "Disabling verification."; 38 | } 39 | // 1 Second time to boot 40 | QTimer::singleShot(1000, this, SLOT(checkStartPositions())); 41 | } 42 | 43 | void SwapScreensAndCheckAlign::checkStartPositions() { 44 | DEBUGOUT << "Start positions"; 45 | if ( verify ) { 46 | check(dspdfviewer.audienceGeometry(), screenSecondary); // Audience starts on external 47 | check(dspdfviewer.secondGeometry(), screenPrimary); // Presenter starts on internal 48 | } 49 | DEBUGOUT << "Firing screen swap event"; 50 | emit screenSwapRequested(); 51 | // 0.5 sec to swap 52 | QTimer::singleShot(500, this, SLOT(checkAfterFirstSwap())); 53 | } 54 | 55 | void SwapScreensAndCheckAlign::checkAfterFirstSwap() { 56 | DEBUGOUT << "Check after first swap"; 57 | if ( verify ) { 58 | check(dspdfviewer.audienceGeometry(), screenPrimary); // Audience window on laptop 59 | check(dspdfviewer.secondGeometry(), screenSecondary); // Presenter window on beamer 60 | } 61 | emit screenSwapRequested(); 62 | // 0.5 sec time to swap 63 | QTimer::singleShot(500, this, SLOT(checkAfterSwapBack())); 64 | } 65 | 66 | void SwapScreensAndCheckAlign::checkAfterSwapBack() { 67 | DEBUGOUT << "Check after swapping back"; 68 | if ( verify ) { 69 | check(dspdfviewer.audienceGeometry(), screenSecondary); 70 | check(dspdfviewer.secondGeometry(), screenPrimary); 71 | emit quitRequested(); 72 | } 73 | else { 74 | QCoreApplication::exit(77); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /testing/testswapscreen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dspdfviewer.h" 4 | 5 | /** Test driver 6 | * 7 | * If it detects two screens, it will verify that the windows switch to the 8 | * specified positions. 9 | * If running on single-screen, the commands will be executed without verification, 10 | * just to make sure the code doesn't segfault or similar. 11 | * 12 | * Rinse and repeat 3 times. 13 | * 14 | */ 15 | class SwapScreensAndCheckAlign: public QObject { 16 | Q_OBJECT 17 | 18 | DSPDFViewer& dspdfviewer; 19 | QRect screenPrimary; 20 | QRect screenSecondary; 21 | bool verify; 22 | public: 23 | SwapScreensAndCheckAlign(DSPDFViewer& app); 24 | signals: 25 | void screenSwapRequested(); 26 | void quitRequested(); 27 | public slots: 28 | void checkStartPositions(); 29 | void checkAfterFirstSwap(); 30 | void checkAfterSwapBack(); 31 | }; 32 | -------------------------------------------------------------------------------- /testing/xorg.conf: -------------------------------------------------------------------------------- 1 | # xorg.conf for Xdummy, to test dspdfviewer 2 | # 3 | # inspired by http://xpra.org/xorg.conf 4 | 5 | Section "ServerFlags" 6 | Option "DontVTSwitch" "true" 7 | Option "AllowMouseOpenFail" "true" 8 | Option "PciForceNone" "true" 9 | Option "AutoEnableDevices" "false" 10 | Option "AutoAddDevices" "false" 11 | EndSection 12 | 13 | Section "Module" 14 | Disable "glx" 15 | Disable "dri" 16 | Disable "dri2" 17 | Disable "dbe" 18 | Disable "record" 19 | SubSection "extmod" 20 | Option "omit XFree86-DGA" 21 | EndSubSection 22 | EndSection 23 | 24 | Section "InputDevice" 25 | Identifier "dummy_mouse" 26 | Option "CorePointer" "true" 27 | Driver "void" 28 | EndSection 29 | 30 | Section "InputDevice" 31 | Identifier "dummy_keyboard" 32 | Option "CoreKeyboard" "true" 33 | Driver "void" 34 | EndSection 35 | 36 | Section "Device" 37 | Identifier "dummy_videocard" 38 | Driver "dummy" 39 | Option "ConstantDPI" "true" 40 | VideoRam 192000 41 | EndSection 42 | 43 | Section "Monitor" 44 | Identifier "internal_monitor" 45 | HorizSync 5.0 - 1000.0 46 | VertRefresh 58.0 - 62.0 47 | Option "PreferredMode" "1920x1080" 48 | 49 | # 1920x1080 59.96 Hz (CVT 2.07M9) hsync: 67.16 kHz; pclk: 173.00 MHz 50 | Modeline "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync 51 | EndSection 52 | 53 | Section "Monitor" 54 | Identifier "external_monitor" 55 | Option "RightOf" "internal_monitor" 56 | HorizSync 5.0 - 1000.0 57 | VertRefresh 58.0 - 62.0 58 | 59 | Option "PreferredMode" "1920x1200" 60 | 61 | # 1920x1200 59.88 Hz (CVT 2.30MA) hsync: 74.56 kHz; pclk: 193.25 MHz 62 | Modeline "1920x1200_60.00" 193.25 1920 2056 2256 2592 1200 1203 1209 1245 -hsync +vsync 63 | EndSection 64 | 65 | Section "Screen" 66 | Identifier "internal_screen" 67 | Device "dummy_videocard" 68 | Monitor "internal_monitor" 69 | DefaultDepth 24 70 | SubSection "Display" 71 | Modes "1920x1080_60.00" 72 | Depth 24 73 | EndSubSection 74 | EndSection 75 | 76 | Section "Screen" 77 | Identifier "external_screen" 78 | Device "dummy_videocard" 79 | Monitor "external_monitor" 80 | DefaultDepth 24 81 | SubSection "Display" 82 | Modes "1920x1200_60.00" 83 | Depth 24 84 | EndSubSection 85 | EndSection 86 | 87 | Section "ServerLayout" 88 | Identifier "TheLayout" 89 | Screen 0 "internal_screen" 90 | Screen 1 "external_screen" RightOf "internal_screen" 91 | InputDevice "dummy_mouse" 92 | InputDevice "dummy_keyboard" 93 | EndSection 94 | -------------------------------------------------------------------------------- /windowrole.cpp: -------------------------------------------------------------------------------- 1 | #include "windowrole.h" 2 | #include 3 | 4 | QString to_QString( const WindowRole& wr) { 5 | if( wr == WindowRole::AudienceWindow ) { 6 | return QString::fromUtf8("Audience_Window"); 7 | } else { 8 | return QString::fromUtf8("Secondary_Window"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /windowrole.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | enum class WindowRole { 6 | AudienceWindow, 7 | PresenterWindow 8 | }; 9 | 10 | // Return "Audience_Window" or "Secondary_Window" 11 | QString to_QString ( const WindowRole& ); 12 | --------------------------------------------------------------------------------