Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package impressive for openSUSE:Factory checked in at 2022-03-20 20:55:34 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/impressive (Old) and /work/SRC/openSUSE:Factory/.impressive.new.25692 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "impressive" Sun Mar 20 20:55:34 2022 rev:5 rq:963216 version:0.13.1 Changes: -------- --- /work/SRC/openSUSE:Factory/impressive/impressive.changes 2020-07-07 12:59:21.677939726 +0200 +++ /work/SRC/openSUSE:Factory/.impressive.new.25692/impressive.changes 2022-03-20 20:55:48.214548474 +0100 @@ -1,0 +2,23 @@ +Sun Mar 20 09:19:42 UTC 2022 - Christophe Giboudeaux <christo...@krop.fr> + +- Update to 0.13.1 + * support for SDL 2 via PyGame 2.0 + * many fixes in native library path detection + * new option --background to set display background color + * fixed crash with page title extraction in PDF files with broken + text encoding + * fixed mouse hiding (--mousedelay 1) not working properly; + added -N/--nocursor as an alias for that + * --mousedelay now also works in windowed mode + * software mouse cursor is hidden too when the mouse leaves + the window + * fixed interactive toggling of the "no-overview" (O key) and + "skip" (I key) + properties from overview page (they acted on the wrong page) + * 'transition' PageProps can now be strings instead of direct + class references + * basic support for Raspberry Pi 1-3 with KMS graphics drivers + * improved library version number and crash reporting + * removed bytecode version again due to compatibility issues + +------------------------------------------------------------------- Old: ---- Impressive-0.13.0-beta2.tar.gz New: ---- Impressive-0.13.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ impressive.spec ++++++ --- /var/tmp/diff_new_pack.L1KJeG/_old 2022-03-20 20:55:49.750550684 +0100 +++ /var/tmp/diff_new_pack.L1KJeG/_new 2022-03-20 20:55:49.754550690 +0100 @@ -1,7 +1,7 @@ # # spec file for package impressive # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,15 +17,14 @@ %define dist_name Impressive -%define fileversion 0.13.0-beta2 Name: impressive -Version: 0.13.0~beta2 +Version: 0.13.1 Release: 0 Summary: PDF and image viewer optimized for presentations License: GPL-2.0-only Group: Productivity/Office/Other URL: http://impressive.sourceforge.net/ -Source0: http://downloads.sourceforge.net/project/%{name}/%{dist_name}/%{fileversion}/%{dist_name}-%{fileversion}.tar.gz +Source0: http://downloads.sourceforge.net/project/%{name}/%{dist_name}/%{version}/%{dist_name}-%{version}.tar.gz Requires: ghostscript Requires: python3-imaging Requires: python3-opengl @@ -34,27 +33,27 @@ BuildArch: noarch %description -A DRI accelerated PDF document viewer with 3D effects. Currently, it only -supports keyboard commands (not mouse) and a single 3D cube effect. +Impressive is a program that displays presentation slides. +Features: +- Page transitions +- Overview screen +- Highlight boxes +- Spotlight effect %prep -%setup -q -n %{dist_name}-%{fileversion} +%autosetup -p1 -n %{dist_name}-%{version} -sed -i 's/env python/python3/' impressive.py +sed -i 's/env python$/python3/' impressive.py %build %install -cd %{_builddir}/%{dist_name}-%{fileversion} -install -d -m 755 %{buildroot}%{_bindir} -install -d -m 755 %{buildroot}%{_mandir}/man1 -install -m 755 %{name}.py %{buildroot}%{_bindir}/%{name} - -gzip -9c <%{name}.1 >%{buildroot}%{_mandir}/man1/%{name}.1.gz +install -Dm 0755 %{name}.py %{buildroot}%{_bindir}/%{name} +install -Dm 0644 %{name}.1 %{buildroot}%{_mandir}/man1/%{name}.1 %files %license license.txt -%doc changelog.txt +%doc changelog.txt demo.pdf %{_bindir}/%{name} %{_mandir}/man1/%{name}.1%{?ext_man} ++++++ Impressive-0.13.0-beta2.tar.gz -> Impressive-0.13.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Impressive-0.13.0-beta2/changelog.txt new/Impressive-0.13.1/changelog.txt --- old/Impressive-0.13.0-beta2/changelog.txt 2020-05-31 21:44:02.000000000 +0200 +++ new/Impressive-0.13.1/changelog.txt 2022-03-19 13:47:40.000000000 +0100 @@ -1,3 +1,20 @@ +0.13.1 [2022-03-19] +- support for SDL 2 via PyGame 2.0 +- many fixes in native library path detection +- new option --background to set display background color +- fixed crash with page title extraction in PDF files with broken text encoding +- fixed mouse hiding (--mousedelay 1) not working properly; + added -N/--nocursor as an alias for that +- --mousedelay now also works in windowed mode +- software mouse cursor is hidden too when the mouse leaves the window +- fixed interactive toggling of the "no-overview" (O key) and "skip" (I key) + properties from overview page (they acted on the wrong page) +- 'transition' PageProps can now be strings instead of direct class references +- basic support for Raspberry Pi 1-3 with KMS graphics drivers +- improved library version number and crash reporting +- removed bytecode version again due to compatibility issues + + 0.13.0-beta2 [2020-05-31] - added 'prev' and 'next' PageProps to change order of pages - fixed many remaining Python 3 compatibility issues Binary files old/Impressive-0.13.0-beta2/impressive and new/Impressive-0.13.1/impressive differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Impressive-0.13.0-beta2/impressive.1 new/Impressive-0.13.1/impressive.1 --- old/Impressive-0.13.0-beta2/impressive.1 2020-05-31 21:44:02.000000000 +0200 +++ new/Impressive-0.13.1/impressive.1 2022-03-19 13:47:40.000000000 +0100 @@ -1,5 +1,5 @@ .\" generated by KeyJ's html2man.py version 0.1.2 -.TH IMPRESSIVE 1 2020-05-31 "Martin J. Fiedler" "Impressive Documentation"> +.TH IMPRESSIVE 1 2022-03-19 "Martin J. Fiedler" "Impressive Documentation"> .SH "NAME" Impressive \- presentation tool with eye candy .SH "SYNOPSIS" @@ -35,6 +35,14 @@ .RE .PP .br +\fB\-\-background \fI<color>\fR\fR +.RS +Sets the background color of the overview page and the page border that's visible if the page's and the screen's aspect ratios don't match. +.br +The color is specified using HTML/\:CSS 3\-digit or 6\-digit hexadecimal RGB syntax: \fB#f00\fR or \fB#ff0000\fR is bright red, for example. The leading hash sign (\fB#\fR) is optional. In addition, the words \fBblack\fR (which is also the default) and \fBwhite\fR are recognized. +.RE +.PP +.br \fB\-bare\fR .RS Disables all functionality that relies on temporary files, specifically video frame extraction using MPlayer (extracting video frames with FFmpeg still works), PDF page title extraction, PDF hyperlinks, and even PDF rendering for all backends except MuPDF 1.4 or newer on Unix\-like operating systems. @@ -115,7 +123,7 @@ .br \fB\-D \fI<ms>\fR\fR or \fB\-\-mousedelay \fI<ms>\fR\fR .RS -Sets the time (in milliseconds) the mouse cursor is shown in fullscreen mode if it is not moved. There are two special values: 0 (zero) shows the mouse cursor permanently, 1 (one) hides it completely. The default value is 3000 ms. +Sets the time (in milliseconds) the mouse cursor is shown if it is not moved. There are two special values: 0 (zero) shows the mouse cursor permanently, 1 (one) hides it completely. The default value is 3000 ms if Impressive is started in fullscreen mode, and 0 (i.e. don't hide) if started in windowed mode. .RE .PP .br @@ -273,7 +281,7 @@ .br \fB\-N\fR or \fB\-\-nocursor\fR .RS -This option disables any display of a mouse cursor, i.e. neither the system ("hardware") not bitmap ("software") cursor is shown at any time. This is mainly useful for automated presentations, where no mouse interaction is needed. +This option disables any display of a mouse cursor, i.e. neither the system ("hardware") not bitmap ("software") cursor is shown at any time. It it equivalent to setting \fB\-\-mousedelay\fR to 1. This is mainly useful for automated presentations, where no mouse interaction is needed. .RE .PP .br diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Impressive-0.13.0-beta2/impressive.html new/Impressive-0.13.1/impressive.html --- old/Impressive-0.13.0-beta2/impressive.html 2020-05-31 21:44:02.000000000 +0200 +++ new/Impressive-0.13.1/impressive.html 2022-03-19 13:47:40.000000000 +0100 @@ -13,12 +13,12 @@ <!--VERSION--> <p style="text-indent:0;"> <a href="http://impressive.sourceforge.net/">http://impressive.sourceforge.net/</a><br /> -<b>Version:</b> 0.13.0<br /> +<b>Version:</b> 0.13.1<br /> <b>Author:</b> <a href="mailto:martin.fied...@gmx.net">Martin J. Fiedler</a><br /> -<b>Last updated:</b> 2020-05-31</p> +<b>Last updated:</b> 2022-03-19</p> <!--END--> <!--man -.TH IMPRESSIVE 1 2020-05-31 "Martin J. Fiedler" "Impressive Documentation"> +.TH IMPRESSIVE 1 2022-03-19 "Martin J. Fiedler" "Impressive Documentation"> .SH "NAME" Impressive \- presentation tool with eye candy .SH "SYNOPSIS" @@ -104,14 +104,15 @@ <p>Impressive runs on Rasbperry Pi Single-Board Computers with bearable performance, if the following notes are taken into consideration:</p> <ul> -<li>On Raspberry Pi generations 1, 2 and 3:<ul> +<li>On Raspberry Pi generations 1, 2 and 3 with the classic (non-KMS) graphics driver stack:<ul> <li>Overscan must be off (set <code>disable_overscan=1</code> in <code>/boot/config.txt</code>, or run <code>raspi-config</code> → Advanced Menu → Overscan).</li> -<li>The classic Broadcom OpenGL ES driver stack must be used, <strong>not</strong> the Fake-KMS or Full-KMS Mesa drivers (disable <code>dtoverlay=vc4-</code>(<code>f</code>)<code>kms-v3d</code> in <code>/boot/config.txt</code>, or run <code>raspi-config</code> → Advanced Menu → GL Driver → Legacy: Original non-GL desktop driver).</li> <li>Doesn't require X11 – can also be run from a normal text console in Raspbian Lite.</li> <li>Can be run from X11, but only in fullscreen mode.</li> </ul></li> -<li>On the Raspberry Pi 4, Impressive behaves like the desktop version.<ul> -<li>Must be run from X11, can use windowed mode.</li></ul></li> +<li>On the Raspberry Pi 4 and Pi 1-3 with KMS drivers, Impressive behaves like the desktop version.<ul> +<li>Must be run from X11, can use windowed mode.</li> +<li>On Raspberry Pi 1 to 3, 3D acceleration might not work, falling back to (very slow!) software rendering.</li> +</ul></li> <li>Video playback uses omxplayer instead of MPlayer. This has the following advantages and drawbacks:<ul> <li>Only H.264 and (if licensed on the specific device) MPEG-2 video codecs are supported.</li> <li>These are, however, hardware-decoded with full performance.</li> @@ -142,6 +143,10 @@ <dt><code>-b</code> or <code>--noback</code></dt> <dd>Disables background rendering. By default, Impressive will pre-render all pages in a separate background thread while the presentation runs. If this option is specified, it will instead render all pages immediately on startup. This option has no effect if caching is disabled (<code>--cache none</code>, see below).</dd> +<dt><code>--background <em><color></em></code></dt> +<dd>Sets the background color of the overview page and the page border that's visible if the page's and the screen's aspect ratios don't match.<br /> +The color is specified using HTML/CSS 3-digit or 6-digit hexadecimal RGB syntax: <code>#f00</code> or <code>#ff0000</code> is bright red, for example. The leading hash sign (<code>#</code>) is optional. In addition, the words <code>black</code> (which is also the default) and <code>white</code> are recognized.</dd> + <dt><code>-bare</code></dt> <dd>Disables all functionality that relies on temporary files, specifically video frame extraction using MPlayer (extracting video frames with FFmpeg still works), PDF page title extraction, PDF hyperlinks, and even PDF rendering for all backends except MuPDF 1.4 or newer on Unix-like operating systems.</dd> @@ -175,7 +180,7 @@ If an expected duration is specified, Impressive will show a semi-transparent green progress bar at the bottom edge of the screen, indicating how much time has already passed. If the time is up, the bar will occupy the whole edge and fade to yellow (at 125% of the expected time) to red (at 150% or more).</dd> <dt><code>-D <em><ms></em></code> or <code>--mousedelay <em><ms></em></code></dt> -<dd>Sets the time (in milliseconds) the mouse cursor is shown in fullscreen mode if it is not moved. There are two special values: 0 (zero) shows the mouse cursor permanently, 1 (one) hides it completely. The default value is 3000 ms.</dd> +<dd>Sets the time (in milliseconds) the mouse cursor is shown if it is not moved. There are two special values: 0 (zero) shows the mouse cursor permanently, 1 (one) hides it completely. The default value is 3000 ms if Impressive is started in fullscreen mode, and 0 (i.e. don't hide) if started in windowed mode.</dd> <dt><code>--darkness <em><percentage></em></code></dt> <dd>Specifies how much the screen shall become darker when using highlight boxes or spotlight mode. The value is specified in percent, with 25 being the default. A value of zero would mean no darkening at all (the screen would just be blurred slightly, and desaturated if the graphics hardware supports it), and a value of 100 would make everything but the highlighted parts of the screen black.</dd> @@ -258,7 +263,7 @@ There might be situations where this mechanism fails and Impressive tries to use the non-functional shader anyway. In these cases, the <code>--noblur</code> option can be used to enforce the fallback implementation.</dd> <dt><code>-N</code> or <code>--nocursor</code></dt> -<dd>This option disables any display of a mouse cursor, i.e. neither the system (»hardware«) not bitmap (»software«) cursor is shown at any time. This is mainly useful for automated presentations, where no mouse interaction is needed.</dd> +<dd>This option disables any display of a mouse cursor, i.e. neither the system (»hardware«) not bitmap (»software«) cursor is shown at any time. It it equivalent to setting <code>--mousedelay</code> to 1. This is mainly useful for automated presentations, where no mouse interaction is needed.</dd> <dt><code>--noclicks</code></dt> <dd>If this option is enabled, switching to the previous or next page with the left and right mouse buttons is deactivated. The keyboard shortcuts are unaffected from this.<br /> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Impressive-0.13.0-beta2/impressive.py new/Impressive-0.13.1/impressive.py --- old/Impressive-0.13.0-beta2/impressive.py 2020-05-31 21:44:02.000000000 +0200 +++ new/Impressive-0.13.1/impressive.py 2022-03-19 13:47:40.000000000 +0100 @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # Impressive, a fancy presentation tool -# Copyright (C) 2005-2019 Martin J. Fiedler <martin.fied...@gmx.net> +# Copyright (C) 2005-2022 Martin J. Fiedler <martin.fied...@gmx.net> # and contributors # # This program is free software; you can redistribute it and/or modify @@ -21,8 +21,8 @@ from __future__ import print_function, division, unicode_literals __title__ = "Impressive" -__version__ = "0.13.0-beta2" -__rev__ = 298 +__version__ = "0.13.1" +__rev__ = 316 __author__ = "Martin J. Fiedler" __email__ = "martin.fied...@gmx.net" __website__ = "http://impressive.sourceforge.net/" @@ -57,7 +57,8 @@ ScreenHeight = 768 WindowPos = None TransitionDuration = 1000 -MouseHideDelay = 3000 +DefaultMouseHideDelay = 3000 +MouseHideDelay = None BoxFadeDuration = 100 ZoomDuration = 250 OverviewDuration = 250 @@ -110,9 +111,9 @@ ProgressBarColorPage = (0.0, 0.5, 1.0) ProgressBarWarningFactor = 1.25 ProgressBarCriticalFactor = 1.5 -EnableCursor = True CursorImage = None CursorHotspot = (0, 0) +BackgroundColor = (0, 0, 0) MinutesOnly = False OSDMargin = 16 OSDAlpha = 1.0 @@ -204,8 +205,13 @@ # import special modules try: - import pygame - from pygame.locals import * + os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "1" + if 0: # set this to 1 to get experimental pre-PyGame 2.0 SDL2 support + import pygame_sdl2 as pygame + from pygame_sdl2.locals import * + else: + import pygame + from pygame.locals import * from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageChops, ImageOps from PIL import TiffImagePlugin, BmpImagePlugin, JpegImagePlugin, PngImagePlugin, PpmImagePlugin except (ValueError, ImportError) as err: @@ -314,6 +320,7 @@ FirstPage = True ProgressBarPos = 0 CursorVisible = True +CursorOnScreen = True OverviewMode = False LastPage = 0 WantStatus = False @@ -351,7 +358,15 @@ def Init(self): os.environ["SDL_MOUSE_RELATIVE"] = "0" - pygame.display.init() + print("Platform library: [{}]".format(self.name), "Python", sys.version.split()[0], "/ PyGame", pygame.version.ver, "/ SDL", '.'.join(map(str, pygame.get_sdl_version()))) + if (2,0,0) < tuple(pygame.version.vernum) < (2,1,0): + # on PyGame 2.0.1, pygame.display.init doesn't automatically + # initialize the timer module, but there's no way to initialize + # the timer module "by hand" -- we need to do a full initialization, + # including all the stuff we don't need (like sound) + pygame.init() + else: + pygame.display.init() def GetTicks(self): return pygame.time.get_ticks() @@ -374,7 +389,11 @@ if WindowPos: os.environ["SDL_VIDEO_WINDOW_POS"] = ','.join(map(str, WindowPos)) pygame.display.set_mode((ScreenWidth, ScreenHeight), flags) - pygame.key.set_repeat(500, 30) + + # Do *not* set key repeat. We used to do that, but there are some + # broken(?) PyGame 2.x versions that produce spurious key-down + # messages after transition animations when enabled. + # pygame.key.set_repeat(500, 30) def LoadOpenGL(self): sdl = None @@ -385,8 +404,8 @@ try: pattern = re.compile(r'(lib)?SDL(?!_[a-zA-Z]+).*?\.(dll|so(\..*)?|dylib)$', re.I) libs = [] - for suffix in (".libs", ".dylibs"): - libdir = os.path.join(pygame.__path__[0], suffix) + for suffix in ("/.libs", "/.dylibs", ".libs", ".dylibs"): + libdir = pygame.__path__[0].rstrip('/\\') + suffix if os.path.isdir(libdir): libs += [os.path.join(libdir, lib) for lib in sorted(os.listdir(libdir)) if pattern.match(lib)] sdl = libs.pop(0) @@ -394,7 +413,10 @@ pass # generic case: load the system-wide SDL - sdl = sdl or ctypes.util.find_library("SDL") or ctypes.util.find_library("SDL-1.2") or "SDL" + if pygame.get_sdl_version() >= (2, 0, 0): + sdl = sdl or ctypes.util.find_library("SDL2") or ctypes.util.find_library("SDL2-2.0") or ctypes.util.find_library("SDL-2.0") or "SDL2" + else: + sdl = sdl or ctypes.util.find_library("SDL") or ctypes.util.find_library("SDL-1.2") or "SDL" # load the library try: @@ -485,6 +507,8 @@ if not(self.schedule_map_ev2flag.get(ev.type)): pygame.time.set_timer(ev.type, 0) return [self.schedule_map_ev2name.get(ev.type)] + elif (ev.type == ACTIVEEVENT) and (ev.state == 1): # APPMOUSEFOCUS=1 + return ["$enter" if ev.gain else "$leave"] else: return [] @@ -590,7 +614,8 @@ return Platform_PyGame.GetScreenSize(self) -class Platform_RasPi4(Platform_Unix): +class Platform_RasPiKMS(Platform_Unix): + name = 'pygame-unix-pi4' use_omxplayer = True @@ -599,20 +624,30 @@ egllib = "EGL" gles2lib = "GLESv2" + def _findlib(self, lib, desc): + path = ctypes.util.find_library(lib) + if not path: + raise ImportError(desc + " library (lib" + lib + ") not found") + return path + def StartDisplay(self, display=None, window=None, width=None, height=None): global ScreenWidth, ScreenHeight width = width or ScreenWidth height = height or ScreenHeight + # resolve library names + egllib = self._findlib(self.egllib, "EGL") + gles2lib = self._findlib(self.gles2lib, "GLESv2") + # load the GLESv2 library before the EGL library (required on the BCM2835) try: - self.gles = ctypes.CDLL(ctypes.util.find_library(self.gles2lib)) + self.gles = CDLL(gles2lib) except OSError: raise ImportError("failed to load the OpenGL ES 2.0 library") # import all functions first try: - egl = CDLL(ctypes.util.find_library(self.egllib)) + egl = CDLL(egllib) def loadfunc(func, ret, *args): return CFUNCTYPE(ret, *args)((func, egl)) eglGetDisplay = loadfunc("eglGetDisplay", c_void_p, c_void_p) @@ -690,6 +725,7 @@ self.libbcm_host_path = libbcm_host def Init(self): + print("Platform library: [{}]".format(self.name), "Python", sys.version.split()[0], "/ libbcm_host / EGL / PyGame", pygame.version.ver) try: self.bcm_host = CDLL(self.libbcm_host_path) def loadfunc(func, ret, *args): @@ -762,14 +798,25 @@ libbcm_host = ctypes.util.find_library("bcm_host") if libbcm_host: + kms_enabled = False try: + # Raspberry Pi 4 always uses the KMS driver with open("/sys/firmware/devicetree/base/model") as f: model = f.read() + m = re.search(r'pi\s*(\d+)', model, flags=re.I) + if m and (int(m.group(1)) >= 4): + kms_enabled = True + # on older Pis, it's optional + if not kms_enabled: + for d in os.listdir("/proc/device-tree/soc"): + if not d.startswith("v3d"): continue + with open("/proc/device-tree/soc/" + d + "/status", "r") as f: + if "ok" in f.read().lower(): + kms_enabled = True except EnvironmentError: - model = "" - m = re.search(r'pi\s*(\d+)', model, flags=re.I) - if m and (int(m.group(1)) >= 4): - Platform = Platform_RasPi4() + pass + if kms_enabled: + Platform = Platform_RasPiKMS() else: Platform = Platform_BCM2835(libbcm_host) elif os.name == "nt": @@ -934,7 +981,7 @@ elif key == "infokey": InfoKey = value.lower() elif (key == "infovalue") and (InfoKey == "title"): - Title = unescape_pdf(value) + Title = unescape_pdf(value).split(u'\x00', 1)[0] InfoKey = None elif key == "bookmarktitle": BookmarkTitle = unescape_pdf(value) @@ -3361,7 +3408,7 @@ # generate a dummy image def DummyPage(): - img = Image.new('RGB', (ScreenWidth, ScreenHeight)) + img = Image.new('RGB', (ScreenWidth, ScreenHeight), BackgroundColor) img.paste(LogoImage, ((ScreenWidth - LogoImage.size[0]) // 2, (ScreenHeight - LogoImage.size[1]) // 2)) return img @@ -3623,11 +3670,11 @@ # create black background image to paste real image onto if ZoomMode: - TextureImage = Image.new('RGB', (int(ResZoomFactor * TexWidth), int(ResZoomFactor * TexHeight))) + TextureImage = Image.new('RGB', (int(ResZoomFactor * TexWidth), int(ResZoomFactor * TexHeight)), BackgroundColor) TextureImage.paste(img, (int((ResZoomFactor * ScreenWidth - img.size[0]) / 2), int((ResZoomFactor * ScreenHeight - img.size[1]) / 2))) else: - TextureImage = Image.new('RGB', (TexWidth, TexHeight)) + TextureImage = Image.new('RGB', (TexWidth, TexHeight), BackgroundColor) x0 = (ScreenWidth - img.size[0]) // 2 y0 = (ScreenHeight - img.size[1]) // 2 TextureImage.paste(img, (x0, y0)) @@ -3645,7 +3692,7 @@ try: # first, fill the underlying area with black (i.e. remove the dummy logo) blackness = Image.new('RGB', (OverviewCellX - OverviewBorder, - OverviewCellY - OverviewBorder)) + OverviewCellY - OverviewBorder), BackgroundColor) OverviewImage.paste(blackness, (pos[0] + OverviewBorder // 2, pos[1] + OverviewBorder)) del blackness @@ -3804,15 +3851,12 @@ del props['boxes'] return props -# Generate a string representation of a property value. Mainly this converts -# classes or instances to the name of the class. -class dummyClass: - pass - -typesClassType = type(dummyClass) -typesInstanceType = type(dummyClass()) +# helper definitions for PropValueRepr +class dummyClass(object): pass typesFunctionType = type(GetPublicProps) +# Generate a string representation of a property value. +# Mainly this converts classes or instances to the name of the class. def PropValueRepr(value): global ScriptTainted if type(value) == typesFunctionType: @@ -3824,14 +3868,17 @@ print(" minimize data loss.", file=sys.stderr) ScriptTainted = True return "here_was_a_lambda_expression_that_could_not_be_saved" - elif isinstance(value, typesClassType): + elif isinstance(value, type): # transition class return value.__name__ - elif isinstance(value, typesInstanceType): + elif isinstance(value, Transition): # transition instance return value.__class__.__name__ - elif type(value) == dict: + elif isinstance(value, dict): return "{ " + ", ".join([PropValueRepr(k) + ": " + PropValueRepr(value[k]) for k in value]) + " }" else: - return repr(value) + value = repr(value) + if value.startswith(('u"', "u'")): # strip unicode prefixes on Python 2 + value = value[1:] + return value # generate a nicely formatted string representation of a page's properties def SinglePagePropRepr(page): @@ -3882,7 +3929,7 @@ except IOError: script = "" if not script: - script = "# -*- coding: iso-8859-1 -*-\n" + script = "# -*- coding: utf-8 -*-\n" # replace the PageProps of the old info script with the current ones try: @@ -3982,7 +4029,7 @@ CurrentOSDComment, Center, Up) OSDFont.EndDraw() - if EnableCursor and CursorVisible and CursorImage: + if (MouseHideDelay != 1) and CursorVisible and CursorImage and CursorOnScreen: x, y = Platform.GetMousePos() x -= CursorHotspot[0] y -= CursorHotspot[1] @@ -4474,6 +4521,16 @@ # create an instance of a transition class def InstantiateTransition(trans_class): + if isinstance(trans_class, basestring): + index = dict((c.__name__.lower(), c) for c in AllTransitions) + try: + trans_class = index[trans_class.lower()] + except KeyError: + print("Error: invalid transition '{}', ignoring".format(trans_class), file=sys.stderr) + return None + elif not(isinstance(trans_class, type) and issubclass(trans_class, Transition)): + print("Error: invalid transition '{!r}', ignoring".format(trans_class), file=sys.stderr) + return None try: return trans_class() except GLInvalidShaderError: @@ -4746,7 +4803,7 @@ def SetCursor(visible): global CursorVisible CursorVisible = visible - if EnableCursor and not(CursorImage) and (MouseHideDelay != 1): + if not(CursorImage) and (MouseHideDelay != 1): Platform.SetMouseVisible(visible) # handle a shortcut key event: store it (if shifted) or return the @@ -5120,11 +5177,18 @@ Platform.PostQuitEvent() def _X_move(self): - # mouse move in fullscreen mode -> show mouse cursor and reset mouse timer - if Fullscreen: + # mouse move -> show mouse cursor and reset mouse timer + if Fullscreen or (MouseHideDelay > 1): Platform.ScheduleEvent("$hide-mouse", MouseHideDelay) SetCursor(True) + def _X_enter(self): + global CursorOnScreen + CursorOnScreen = True + def _X_leave(self): + global CursorOnScreen + CursorOnScreen = False + def _X_call(self): while CallQueue: func, args, kwargs = CallQueue.pop(0) @@ -5241,6 +5305,8 @@ OverviewSelection = dest x, y = OverviewPos(OverviewSelection) Platform.SetMousePos((x + (OverviewCellX // 2), y + (OverviewCellY // 2))) + UpdateCaption(OverviewPageMap[OverviewSelection]) + DrawOverview() # overview mode PageProp toggle def OverviewTogglePageProp(prop, default): @@ -5282,6 +5348,12 @@ SetCursor(False) DrawOverview() + def _X_leave(self): + global CursorOnScreen + CursorOnScreen = False + if CursorImage and (MouseHideDelay != 1): + DrawOverview() + def _X_timer_update(self): force_update = OverviewNeedUpdate if OverviewNeedUpdate: @@ -5319,9 +5391,9 @@ DrawOverview() def _toggle_skip(self): - TogglePageProp('skip', False) + OverviewTogglePageProp('skip', False) def _toggle_overview(self): - TogglePageProp('overview', GetPageProp(Pcurrent, '_overview', True)) + OverviewTogglePageProp('overview', True) def _overview_up(self): "move the overview selection upwards" @@ -5408,17 +5480,14 @@ if not Platform.ToggleFullscreen(): return Fullscreen = fs DrawCurrentPage() - if fs: + if MouseHideDelay > 1: Platform.ScheduleEvent("$hide-mouse", MouseHideDelay) - else: - Platform.ScheduleEvent("$hide-mouse", 0) - SetCursor(True) # PageProp toggle def TogglePageProp(prop, default): global WantStatus SetPageProp(Pcurrent, prop, not(GetPageProp(Pcurrent, prop, default))) - UpdateCaption(Pcurrent, force=True) + UpdateCaption(page, force=True) WantStatus = True DrawCurrentPage() @@ -5433,6 +5502,12 @@ def _X_expose(self): DrawCurrentPage() + def _X_leave(self): + global CursorOnScreen + CursorOnScreen = False + if CursorImage and (MouseHideDelay != 1): + DrawCurrentPage() + def _X_hide_mouse(self): # mouse timer event -> hide fullscreen cursor SetCursor(False) @@ -5821,7 +5896,7 @@ TogglePageProp('skip', False) def _toggle_overview(self): "toggle 'visible on overview' flag of current page" - TogglePageProp('overview', GetPageProp(Pcurrent, '_overview', True)) + TogglePageProp('overview', True) def _fade_less(self): "decrease the spotlight/box background darkness" @@ -5995,7 +6070,7 @@ global CursorImage, CursorVisible, InfoScriptPath global HalfScreen, AutoAdvanceTime, AutoAdvanceEnabled, WindowPos global BoxFadeDarknessBase, BoxZoomDarknessBase, SpotRadiusBase - global BoxIndexBuffer, UseBlurShader + global BoxIndexBuffer, UseBlurShader, MouseHideDelay # allocate temporary file TempFileName = None @@ -6016,7 +6091,12 @@ DocumentTitle = os.path.splitext(os.path.split(FileName)[1])[0] # early graphics initialization - Platform.Init() + try: + Platform.Init() + except Exception as e: + print("FATAL: failed to initialize the platform library", file=sys.stderr) + print(" detailed error message:", e, file=sys.stderr) + sys.exit(1) # detect screen size and compute aspect ratio if Fullscreen and (UseAutoScreenSize or not(Platform.allow_custom_fullscreen_res)): @@ -6078,7 +6158,6 @@ except KeyboardInterrupt: raise except: - print("pdftkParse() FAILED") pass # phase 3: use mutool (if pdftk wasn't successful) @@ -6138,6 +6217,8 @@ BoxFadeDarknessBase = BoxFadeDarkness BoxZoomDarknessBase = BoxZoomDarkness SpotRadiusBase = SpotRadius + if MouseHideDelay is None: + MouseHideDelay = DefaultMouseHideDelay if Fullscreen else 0 # get the initial page number if not InitialPage: @@ -6237,6 +6318,12 @@ LogoTexture = gl.make_texture(gl.TEXTURE_2D, filter=gl.NEAREST, img=LogoImage) DrawLogo() Platform.SwapBuffers() + if BackgroundColor != (0, 0, 0): + mask = LogoImage + luma = sum(c*w for c,w in zip(BackgroundColor, (299, 587, 114))) + LogoImage = Image.new('RGB', LogoImage.size, BackgroundColor) + LogoImage.paste(Image.new('RGB', LogoImage.size, (0, 0, 0) if (luma > 128000) else (255, 255, 255)), mask=mask) + del mask # initialize OSD font try: @@ -6259,7 +6346,7 @@ DoEventTestMode() # initialize mouse cursor - if EnableCursor and (CursorImage or not(Platform.has_hardware_cursor)): + if (MouseHideDelay != 1) and (CursorImage or not(Platform.has_hardware_cursor)): img = None if CursorImage and not(CursorImage.lower() in ("-", "default")): try: @@ -6310,7 +6397,7 @@ int((OverviewPageCount + OverviewGridSize - 1) / OverviewGridSize)) / 2) while OverviewBorder and (min(OverviewCellX - 2 * OverviewBorder, OverviewCellY - 2 * OverviewBorder) < 16): OverviewBorder -= 1 - OverviewImage = Image.new('RGB', (TexWidth, TexHeight)) + OverviewImage = Image.new('RGB', (TexWidth, TexHeight), BackgroundColor) if HalfScreen: OverviewOfsX += ScreenWidth ScreenWidth = saved_screen_width @@ -6424,7 +6511,7 @@ if TimeTracking or TimeDisplay: EnableTimeTracking(True) Platform.ScheduleEvent("$timer-update", 100, periodic=True) - if not(Fullscreen) and (not(EnableCursor) or CursorImage): + if (MouseHideDelay == 1) or CursorImage: Platform.SetMouseVisible(False) if FadeInOut: LeaveFadeMode() @@ -6493,8 +6580,10 @@ print("please also send the input files you used.", file=sys.stderr) print(file=sys.stderr) print("Impressive version:", __version__, file=sys.stderr) - print("Python version:", sys.version, file=sys.stderr) - print("PyGame version:", pygame.__version__, file=sys.stderr) + print("Python version:", sys.version.replace('\r', '').replace('\n', ' ').replace(' ', ' '), file=sys.stderr) + print("Impressive platform:", Platform.name) + print("PyGame version:", pygame.version.ver, file=sys.stderr) + print("SDL version:", '.'.join(map(str, pygame.get_sdl_version())), file=sys.stderr) if hasattr(Image, "__version__"): # Pillow >= 5.2 print("PIL version: Pillow", Image.__version__, file=sys.stderr) elif hasattr(Image, "PILLOW_VERSION"): # Pillow < 7.0 @@ -6611,7 +6700,7 @@ -F, --font <file> use a specific TrueType font file for the OSD -S, --fontsize <px> specify the OSD font size in pixels -C, --cursor <F[:X,Y]> use a .png image as the mouse cursor - -N, --nocursor don't show a mouse cursor at all + -N, --nocursor don't show a mouse cursor at all (equivalent to -D 1) -L, --layout <spec> set the OSD layout (please read the documentation) -z, --zoom <factor> set zoom factor (default: 2.0) --maxzoom <factor> maximum factor to render high-resolution zoom @@ -6624,6 +6713,7 @@ --zbox-edge <px> size of zoom box borders, in pixels --darkness <p> set highlight box mode darkness to <p> percent --zoomdarkness <p> set box-zoom mode darkness to <p> percent + --background <c> set background color (HTML/CSS hex style: rgb/rrggbb) Timing options: -a, --auto <seconds> automatically advance to next page after some seconds @@ -6806,13 +6896,13 @@ global BackgroundRendering, UseAutoScreenSize, PollInterval, CacheFileName global PageRangeStart, PageRangeEnd, FontList, FontSize, Gamma, BlackLevel global EstimatedDuration, CursorImage, CursorHotspot, MinutesOnly, Overscan - global PDFRendererPath, InfoScriptPath, EventTestMode, EnableCursor + global PDFRendererPath, InfoScriptPath, EventTestMode global AutoOverview, DefaultZoomFactor, FadeInOut, ShowLogo, Shuffle global QuitAtEnd, ShowClock, HalfScreen, SpotRadius, InvertPages global MinBoxSize, AutoAdvanceProgress, BoxFadeDarkness global WindowPos, FakeFullscreen, UseBlurShader, Bare, EnableOverview global PageProgress, ProgressLast, BoxZoomDarkness, MaxZoomFactor, BoxEdgeSize - global TimeDisplay, MouseWheelZoom, ZoomBoxEdgeSize + global TimeDisplay, MouseWheelZoom, ZoomBoxEdgeSize, BackgroundColor DefaultControls = True # on Python 2, ensure that all command-line strings are encoded properly @@ -6839,7 +6929,7 @@ "noquit", "bare", "no-overview", "nooverview", "no-cursor", "nocursor", "zoomdarkness=", "zoom-darkness=", "box-edge=", "maxzoom=", "max-zoom=", "time-display", "zbox-edge=", - "vht0=", "vht1="]) + "vht0=", "vht1=", "background="]) except getopt.GetoptError as message: opterr(message) @@ -7132,7 +7222,18 @@ if opt in ("--no-overview", "--nooverview"): EnableOverview = not(EnableOverview) if opt in ("-N", "--no-cursor", "--nocursor"): - EnableCursor = not(EnableCursor) + MouseHideDelay = 1 + if opt == "--background": + if arg.startswith("#"): arg = arg[1:] + if arg == "white": arg = "fff" + elif arg == "black": arg = "000" + if len(arg) == 3: arg = [d+d for d in arg] + elif len(arg) == 6: arg = [arg[n:n+2] for n in (0,2,4)] + else: opterr("invalid parameter for --background") + try: + BackgroundColor = tuple(int(c, 16) for c in arg) + except: + opterr("invalid parameter for --background") if opt.startswith("--vht"): # DEBUG OPTION ONLY Win32FullscreenVideoHackTiming[int(opt[5:])] = float(arg)