commit python-mss for openSUSE:Factory
![](https://seccdn.libravatar.org/avatar/128a7b98d536a9cf9b4d4d5a90d63475.jpg?s=120&d=mm&r=g)
Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-mss for openSUSE:Factory checked in at 2021-02-02 14:24:16 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-mss (Old) and /work/SRC/openSUSE:Factory/.python-mss.new.28504 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "python-mss" Tue Feb 2 14:24:16 2021 rev:2 rq:858348 version:6.1.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-mss/python-mss.changes 2020-08-18 15:09:45.436008535 +0200 +++ /work/SRC/openSUSE:Factory/.python-mss.new.28504/python-mss.changes 2021-02-02 14:24:17.983263790 +0100 @@ -1,0 +2,9 @@ +Wed Dec 23 09:33:38 UTC 2020 - Benjamin Greiner <code@bnavigator.de> + +- Update to v6.1.0 + * MSS: reworked how C functions are initialised + * tests: expand Python versions to 3.9 and 3.10 + * tests: fix test_entry_point() when there are several monitors +- clean test rig setup + +------------------------------------------------------------------- Old: ---- mss-6.0.0.tar.gz New: ---- mss-6.1.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-mss.spec ++++++ --- /var/tmp/diff_new_pack.SDbXoE/_old 2021-02-02 14:24:18.791265046 +0100 +++ /var/tmp/diff_new_pack.SDbXoE/_new 2021-02-02 14:24:18.795265052 +0100 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-mss -Version: 6.0.0 +Version: 6.1.0 Release: 0 Summary: Python multiple screenshots module License: MIT @@ -45,8 +45,6 @@ %prep %setup -q -n mss-%{version} -mv mss/tests . -rm tests/test_setup.py %build %python_build @@ -65,12 +63,17 @@ %check export LANG=en_US.UTF-8 # test_region_out_of_monitor_bounds fails on ppc64 only -%python_expand PYTHONPATH=%{buildroot}%{$python_sitelib} xvfb-run --server-args "-screen 0 1920x1080x24" $python -m pytest tests/test_*.py -k 'not test_region_out_of_monitor_bounds' +echo ' +%pytest --ignore mss/tests/test_setup.py -k "not test_region_out_of_monitor_bounds" +'> pytest_script.sh +# need explicitly set up screen. +xvfb-run --server-args "-screen 0 1920x1080x24" sh pytest_script.sh %files %{python_files} %doc README.rst %license LICENSE %python_alternative %{_bindir}/mss -%{python_sitelib}/* +%{python_sitelib}/mss +%{python_sitelib}/mss-%{version}*-info %changelog ++++++ mss-6.0.0.tar.gz -> mss-6.1.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/PKG-INFO new/mss-6.1.0/PKG-INFO --- old/mss-6.0.0/PKG-INFO 2020-06-30 18:00:14.000000000 +0200 +++ new/mss-6.1.0/PKG-INFO 2020-10-31 18:18:32.501716100 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: mss -Version: 6.0.0 +Version: 6.1.0 Summary: An ultra fast cross-platform multiple screenshots module in pure python using ctypes. Home-page: https://github.com/BoboTiG/python-mss Author: Micka��l 'Tiger-222' Schoentgen diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/mss/__init__.py new/mss-6.1.0/mss/__init__.py --- old/mss-6.0.0/mss/__init__.py 2020-06-28 19:22:53.000000000 +0200 +++ new/mss-6.1.0/mss/__init__.py 2020-10-31 18:09:38.000000000 +0100 @@ -12,7 +12,7 @@ from .exception import ScreenShotError from .factory import mss -__version__ = "6.0.0" +__version__ = "6.1.0" __author__ = "Micka��l 'Tiger-222' Schoentgen" __copyright__ = """ Copyright (c) 2013-2020, Micka��l 'Tiger-222' Schoentgen diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/mss/base.py new/mss-6.1.0/mss/base.py --- old/mss-6.0.0/mss/base.py 2020-06-30 17:37:13.000000000 +0200 +++ new/mss-6.1.0/mss/base.py 2020-10-31 18:07:02.000000000 +0100 @@ -164,6 +164,7 @@ try: monitor = monitors[mon] except IndexError: + # pylint: disable=raise-missing-from raise ScreenShotError("Monitor {!r} does not exist.".format(mon)) output = output.format(mon=mon, date=datetime.now(), **monitor) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/mss/darwin.py new/mss-6.1.0/mss/darwin.py --- old/mss-6.0.0/mss/darwin.py 2020-06-28 19:22:53.000000000 +0200 +++ new/mss-6.1.0/mss/darwin.py 2020-10-31 18:07:02.000000000 +0100 @@ -6,6 +6,18 @@ import ctypes import ctypes.util import sys +from ctypes import ( + POINTER, + Structure, + c_double, + c_float, + c_int32, + c_uint64, + c_ubyte, + c_uint32, + c_void_p, +) +from platform import mac_ver from typing import TYPE_CHECKING from .base import MSSBase @@ -22,13 +34,13 @@ def cgfloat(): - # type: () -> Union[Type[ctypes.c_double], Type[ctypes.c_float]] + # type: () -> Union[Type[c_double], Type[c_float]] """ Get the appropriate value for a float. """ - return ctypes.c_double if sys.maxsize > 2 ** 32 else ctypes.c_float + return c_double if sys.maxsize > 2 ** 32 else c_float -class CGPoint(ctypes.Structure): +class CGPoint(Structure): """ Structure that contains coordinates of a rectangle. """ _fields_ = [("x", cgfloat()), ("y", cgfloat())] @@ -37,7 +49,7 @@ return "{}(left={} top={})".format(type(self).__name__, self.x, self.y) -class CGSize(ctypes.Structure): +class CGSize(Structure): """ Structure that contains dimensions of an rectangle. """ _fields_ = [("width", cgfloat()), ("height", cgfloat())] @@ -48,7 +60,7 @@ ) -class CGRect(ctypes.Structure): +class CGRect(Structure): """ Structure that contains information about a rectangle. """ _fields_ = [("origin", CGPoint), ("size", CGSize)] @@ -57,6 +69,42 @@ return "{}<{} {}>".format(type(self).__name__, self.origin, self.size) +# C functions that will be initialised later. +# +# This is a dict: +# cfunction: (attr, argtypes, restype) +# +# Available attr: core. +# +# Note: keep it sorted by cfunction. +CFUNCTIONS = { + "CGDataProviderCopyData": ("core", [c_void_p], c_void_p), + "CGDisplayBounds": ("core", [c_uint32], CGRect), + "CGDisplayRotation": ("core", [c_uint32], c_float), + "CFDataGetBytePtr": ("core", [c_void_p], c_void_p), + "CFDataGetLength": ("core", [c_void_p], c_uint64), + "CFRelease": ("core", [c_void_p], c_void_p), + "CGDataProviderRelease": ("core", [c_void_p], c_void_p), + "CGGetActiveDisplayList": ( + "core", + [c_uint32, POINTER(c_uint32), POINTER(c_uint32)], + c_int32, + ), + "CGImageGetBitsPerPixel": ("core", [c_void_p], int), + "CGImageGetBytesPerRow": ("core", [c_void_p], int), + "CGImageGetDataProvider": ("core", [c_void_p], c_void_p), + "CGImageGetHeight": ("core", [c_void_p], int), + "CGImageGetWidth": ("core", [c_void_p], int), + "CGRectStandardize": ("core", [CGRect], CGRect), + "CGRectUnion": ("core", [CGRect, CGRect], CGRect), + "CGWindowListCreateImage": ( + "core", + [CGRect, c_uint32, c_uint32, c_uint32], + c_void_p, + ), +} + + class MSS(MSSBase): """ Multiple ScreenShots implementation for macOS. @@ -72,54 +120,37 @@ self.max_displays = 32 - coregraphics = ctypes.util.find_library("CoreGraphics") + self._init_library() + self._set_cfunctions() + + def _init_library(self): + """ Load the CoreGraphics library. """ + version = float(".".join(mac_ver()[0].split(".")[:2])) + if version < 10.16: + coregraphics = ctypes.util.find_library("CoreGraphics") + else: + # macOS Big Sur and newer + # pylint: disable=line-too-long + coregraphics = "/System/Library/Frameworks/CoreGraphics.framework/Versions/Current/CoreGraphics" + if not coregraphics: raise ScreenShotError("No CoreGraphics library found.") self.core = ctypes.cdll.LoadLibrary(coregraphics) - self._set_cfunctions() - def _set_cfunctions(self): # type: () -> None """ Set all ctypes functions and attach them to attributes. """ - def cfactory(func, argtypes, restype): - # type: (str, List[Any], Any) -> None - """ Factorize ctypes creations. """ - self._cfactory( - attr=self.core, func=func, argtypes=argtypes, restype=restype + cfactory = self._cfactory + attrs = {"core": self.core} + for func, (attr, argtypes, restype) in CFUNCTIONS.items(): + cfactory( + attr=attrs[attr], + func=func, + argtypes=argtypes, # type: ignore + restype=restype, ) - uint32 = ctypes.c_uint32 - void = ctypes.c_void_p - size_t = ctypes.c_size_t - pointer = ctypes.POINTER - - cfactory( - func="CGGetActiveDisplayList", - argtypes=[uint32, pointer(uint32), pointer(uint32)], - restype=ctypes.c_int32, - ) - cfactory(func="CGDisplayBounds", argtypes=[uint32], restype=CGRect) - cfactory(func="CGRectStandardize", argtypes=[CGRect], restype=CGRect) - cfactory(func="CGRectUnion", argtypes=[CGRect, CGRect], restype=CGRect) - cfactory(func="CGDisplayRotation", argtypes=[uint32], restype=ctypes.c_float) - cfactory( - func="CGWindowListCreateImage", - argtypes=[CGRect, uint32, uint32, uint32], - restype=void, - ) - cfactory(func="CGImageGetWidth", argtypes=[void], restype=size_t) - cfactory(func="CGImageGetHeight", argtypes=[void], restype=size_t) - cfactory(func="CGImageGetDataProvider", argtypes=[void], restype=void) - cfactory(func="CGDataProviderCopyData", argtypes=[void], restype=void) - cfactory(func="CFDataGetBytePtr", argtypes=[void], restype=void) - cfactory(func="CFDataGetLength", argtypes=[void], restype=ctypes.c_uint64) - cfactory(func="CGImageGetBytesPerRow", argtypes=[void], restype=size_t) - cfactory(func="CGImageGetBitsPerPixel", argtypes=[void], restype=size_t) - cfactory(func="CGDataProviderRelease", argtypes=[void], restype=void) - cfactory(func="CFRelease", argtypes=[void], restype=void) - def _monitors_impl(self): # type: () -> None """ Get positions of monitors. It will populate self._monitors. """ @@ -134,8 +165,8 @@ self._monitors.append({}) # Each monitors - display_count = ctypes.c_uint32(0) - active_displays = (ctypes.c_uint32 * self.max_displays)() + display_count = c_uint32(0) + active_displays = (c_uint32 * self.max_displays)() core.CGGetActiveDisplayList( self.max_displays, active_displays, ctypes.byref(display_count) ) @@ -183,20 +214,20 @@ if not image_ref: raise ScreenShotError("CoreGraphics.CGWindowListCreateImage() failed.") - width = int(core.CGImageGetWidth(image_ref)) - height = int(core.CGImageGetHeight(image_ref)) + width = core.CGImageGetWidth(image_ref) + height = core.CGImageGetHeight(image_ref) prov = copy_data = None try: prov = core.CGImageGetDataProvider(image_ref) copy_data = core.CGDataProviderCopyData(prov) data_ref = core.CFDataGetBytePtr(copy_data) buf_len = core.CFDataGetLength(copy_data) - raw = ctypes.cast(data_ref, ctypes.POINTER(ctypes.c_ubyte * buf_len)) + raw = ctypes.cast(data_ref, POINTER(c_ubyte * buf_len)) data = bytearray(raw.contents) # Remove padding per row - bytes_per_row = int(core.CGImageGetBytesPerRow(image_ref)) - bytes_per_pixel = int(core.CGImageGetBitsPerPixel(image_ref)) + bytes_per_row = core.CGImageGetBytesPerRow(image_ref) + bytes_per_pixel = core.CGImageGetBitsPerPixel(image_ref) bytes_per_pixel = (bytes_per_pixel + 7) // 8 if bytes_per_pixel * width != bytes_per_row: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/mss/linux.py new/mss-6.1.0/mss/linux.py --- old/mss-6.0.0/mss/linux.py 2020-06-30 17:58:00.000000000 +0200 +++ new/mss-6.1.0/mss/linux.py 2020-10-31 18:07:02.000000000 +0100 @@ -7,6 +7,21 @@ import ctypes.util import os import threading +from ctypes import ( + POINTER, + CFUNCTYPE, + Structure, + c_char_p, + c_int, + c_int32, + c_long, + c_ubyte, + c_uint, + c_uint32, + c_ulong, + c_ushort, + c_void_p, +) from types import SimpleNamespace from typing import TYPE_CHECKING @@ -28,127 +43,127 @@ ZPIXMAP = 2 -class Display(ctypes.Structure): +class Display(Structure): """ Structure that serves as the connection to the X server and that contains all the information about that X server. """ -class Event(ctypes.Structure): +class Event(Structure): """ XErrorEvent to debug eventual errors. https://tronche.com/gui/x/xlib/event-handling/protocol-errors/default-handle... """ _fields_ = [ - ("type", ctypes.c_int), - ("display", ctypes.POINTER(Display)), - ("serial", ctypes.c_ulong), - ("error_code", ctypes.c_ubyte), - ("request_code", ctypes.c_ubyte), - ("minor_code", ctypes.c_ubyte), - ("resourceid", ctypes.c_void_p), + ("type", c_int), + ("display", POINTER(Display)), + ("serial", c_ulong), + ("error_code", c_ubyte), + ("request_code", c_ubyte), + ("minor_code", c_ubyte), + ("resourceid", c_void_p), ] -class XWindowAttributes(ctypes.Structure): +class XWindowAttributes(Structure): """ Attributes for the specified window. """ _fields_ = [ - ("x", ctypes.c_int32), - ("y", ctypes.c_int32), - ("width", ctypes.c_int32), - ("height", ctypes.c_int32), - ("border_width", ctypes.c_int32), - ("depth", ctypes.c_int32), - ("visual", ctypes.c_ulong), - ("root", ctypes.c_ulong), - ("class", ctypes.c_int32), - ("bit_gravity", ctypes.c_int32), - ("win_gravity", ctypes.c_int32), - ("backing_store", ctypes.c_int32), - ("backing_planes", ctypes.c_ulong), - ("backing_pixel", ctypes.c_ulong), - ("save_under", ctypes.c_int32), - ("colourmap", ctypes.c_ulong), - ("mapinstalled", ctypes.c_uint32), - ("map_state", ctypes.c_uint32), - ("all_event_masks", ctypes.c_ulong), - ("your_event_mask", ctypes.c_ulong), - ("do_not_propagate_mask", ctypes.c_ulong), - ("override_redirect", ctypes.c_int32), - ("screen", ctypes.c_ulong), + ("x", c_int32), + ("y", c_int32), + ("width", c_int32), + ("height", c_int32), + ("border_width", c_int32), + ("depth", c_int32), + ("visual", c_ulong), + ("root", c_ulong), + ("class", c_int32), + ("bit_gravity", c_int32), + ("win_gravity", c_int32), + ("backing_store", c_int32), + ("backing_planes", c_ulong), + ("backing_pixel", c_ulong), + ("save_under", c_int32), + ("colourmap", c_ulong), + ("mapinstalled", c_uint32), + ("map_state", c_uint32), + ("all_event_masks", c_ulong), + ("your_event_mask", c_ulong), + ("do_not_propagate_mask", c_ulong), + ("override_redirect", c_int32), + ("screen", c_ulong), ] -class XImage(ctypes.Structure): +class XImage(Structure): """ Description of an image as it exists in the client's memory. https://tronche.com/gui/x/xlib/graphics/images.html """ _fields_ = [ - ("width", ctypes.c_int), - ("height", ctypes.c_int), - ("xoffset", ctypes.c_int), - ("format", ctypes.c_int), - ("data", ctypes.c_void_p), - ("byte_order", ctypes.c_int), - ("bitmap_unit", ctypes.c_int), - ("bitmap_bit_order", ctypes.c_int), - ("bitmap_pad", ctypes.c_int), - ("depth", ctypes.c_int), - ("bytes_per_line", ctypes.c_int), - ("bits_per_pixel", ctypes.c_int), - ("red_mask", ctypes.c_ulong), - ("green_mask", ctypes.c_ulong), - ("blue_mask", ctypes.c_ulong), + ("width", c_int), + ("height", c_int), + ("xoffset", c_int), + ("format", c_int), + ("data", c_void_p), + ("byte_order", c_int), + ("bitmap_unit", c_int), + ("bitmap_bit_order", c_int), + ("bitmap_pad", c_int), + ("depth", c_int), + ("bytes_per_line", c_int), + ("bits_per_pixel", c_int), + ("red_mask", c_ulong), + ("green_mask", c_ulong), + ("blue_mask", c_ulong), ] -class XRRModeInfo(ctypes.Structure): +class XRRModeInfo(Structure): """ Voil��, voil��. """ -class XRRScreenResources(ctypes.Structure): +class XRRScreenResources(Structure): """ Structure that contains arrays of XIDs that point to the available outputs and associated CRTCs. """ _fields_ = [ - ("timestamp", ctypes.c_ulong), - ("configTimestamp", ctypes.c_ulong), - ("ncrtc", ctypes.c_int), - ("crtcs", ctypes.POINTER(ctypes.c_long)), - ("noutput", ctypes.c_int), - ("outputs", ctypes.POINTER(ctypes.c_long)), - ("nmode", ctypes.c_int), - ("modes", ctypes.POINTER(XRRModeInfo)), + ("timestamp", c_ulong), + ("configTimestamp", c_ulong), + ("ncrtc", c_int), + ("crtcs", POINTER(c_long)), + ("noutput", c_int), + ("outputs", POINTER(c_long)), + ("nmode", c_int), + ("modes", POINTER(XRRModeInfo)), ] -class XRRCrtcInfo(ctypes.Structure): +class XRRCrtcInfo(Structure): """ Structure that contains CRTC information. """ _fields_ = [ - ("timestamp", ctypes.c_ulong), - ("x", ctypes.c_int), - ("y", ctypes.c_int), - ("width", ctypes.c_int), - ("height", ctypes.c_int), - ("mode", ctypes.c_long), - ("rotation", ctypes.c_int), - ("noutput", ctypes.c_int), - ("outputs", ctypes.POINTER(ctypes.c_long)), - ("rotations", ctypes.c_ushort), - ("npossible", ctypes.c_int), - ("possible", ctypes.POINTER(ctypes.c_long)), + ("timestamp", c_ulong), + ("x", c_int), + ("y", c_int), + ("width", c_int), + ("height", c_int), + ("mode", c_long), + ("rotation", c_int), + ("noutput", c_int), + ("outputs", POINTER(c_long)), + ("rotations", c_ushort), + ("npossible", c_int), + ("possible", POINTER(c_long)), ] -@ctypes.CFUNCTYPE(ctypes.c_int, ctypes.POINTER(Display), ctypes.POINTER(Event)) +@CFUNCTYPE(c_int, POINTER(Display), POINTER(Event)) def error_handler(_, event): # type: (Any, Any) -> int """ Specifies the program's supplied error handler. """ @@ -176,6 +191,71 @@ raise ScreenShotError(err, details=details) +# C functions that will be initialised later. +# See https://tronche.com/gui/x/xlib/function-index.html for details. +# +# This is a dict: +# cfunction: (attr, argtypes, restype) +# +# Available attr: xlib, xrandr. +# +# Note: keep it sorted by cfunction. +CFUNCTIONS = { + "XDefaultRootWindow": ("xlib", [POINTER(Display)], POINTER(XWindowAttributes)), + "XDestroyImage": ("xlib", [POINTER(XImage)], c_void_p), + "XGetErrorText": ("xlib", [POINTER(Display), c_int, c_char_p, c_int], c_void_p), + "XGetImage": ( + "xlib", + [ + POINTER(Display), + POINTER(Display), + c_int, + c_int, + c_uint, + c_uint, + c_ulong, + c_int, + ], + POINTER(XImage), + ), + "XGetWindowAttributes": ( + "xlib", + [POINTER(Display), POINTER(XWindowAttributes), POINTER(XWindowAttributes)], + c_int, + ), + "XOpenDisplay": ("xlib", [c_char_p], POINTER(Display)), + "XQueryExtension": ( + "xlib", + [ + POINTER(Display), + c_char_p, + POINTER(c_int), + POINTER(c_int), + POINTER(c_int), + ], + c_uint, + ), + "XRRFreeCrtcInfo": ("xrandr", [POINTER(XRRCrtcInfo)], c_void_p), + "XRRFreeScreenResources": ("xrandr", [POINTER(XRRScreenResources)], c_void_p), + "XRRGetCrtcInfo": ( + "xrandr", + [POINTER(Display), POINTER(XRRScreenResources), c_long], + POINTER(XRRCrtcInfo), + ), + "XRRGetScreenResources": ( + "xrandr", + [POINTER(Display), POINTER(Display)], + POINTER(XRRScreenResources), + ), + "XRRGetScreenResourcesCurrent": ( + "xrandr", + [POINTER(Display), POINTER(Display)], + POINTER(XRRScreenResources), + ), + "XSetErrorHandler": ("xlib", [c_void_p], c_int), +} + + class MSS(MSSBase): """ Multiple ScreenShots implementation for GNU/Linux. @@ -197,6 +277,7 @@ try: display = os.environ["DISPLAY"].encode("utf-8") except KeyError: + # pylint: disable=raise-missing-from raise ScreenShotError("$DISPLAY not set.") if not isinstance(display, bytes): @@ -228,14 +309,12 @@ # Fix for XRRGetScreenResources and XGetImage: # expected LP_Display instance instead of LP_XWindowAttributes - self.drawable = ctypes.cast(self.root, ctypes.POINTER(Display)) + self.drawable = ctypes.cast(self.root, POINTER(Display)) def has_extension(self, extension): # type: (str) -> bool """Return True if the given *extension* is part of the extensions list of the server.""" with lock: - byref = ctypes.byref - c_int = ctypes.c_int major_opcode_return = c_int() first_event_return = c_int() first_error_return = c_int() @@ -244,9 +323,9 @@ self.xlib.XQueryExtension( self._get_display(), extension.encode("latin1"), - byref(major_opcode_return), - byref(first_event_return), - byref(first_error_return), + ctypes.byref(major_opcode_return), + ctypes.byref(first_event_return), + ctypes.byref(first_error_return), ) except ScreenShotError: return False @@ -271,93 +350,24 @@ return display def _set_cfunctions(self): - """ - Set all ctypes functions and attach them to attributes. - See https://tronche.com/gui/x/xlib/function-index.html for details. - """ - - def cfactory(func, argtypes, restype, attr=self.xlib): - # type: (str, List[Any], Any, Any) -> None - """ Factorize ctypes creations. """ - self._cfactory( - attr=attr, - errcheck=validate, - func=func, - argtypes=argtypes, - restype=restype, - ) + """ Set all ctypes functions and attach them to attributes. """ - void = ctypes.c_void_p - c_int = ctypes.c_int - uint = ctypes.c_uint - ulong = ctypes.c_ulong - c_long = ctypes.c_long - char_p = ctypes.c_char_p - pointer = ctypes.POINTER - - cfactory("XSetErrorHandler", [void], c_int) - cfactory("XGetErrorText", [pointer(Display), c_int, char_p, c_int], void) - cfactory("XOpenDisplay", [char_p], pointer(Display)) - cfactory("XDefaultRootWindow", [pointer(Display)], pointer(XWindowAttributes)) - cfactory( - "XGetWindowAttributes", - [pointer(Display), pointer(XWindowAttributes), pointer(XWindowAttributes)], - c_int, - ) - cfactory( - "XGetImage", - [ - pointer(Display), - pointer(Display), - c_int, - c_int, - uint, - uint, - ulong, - c_int, - ], - pointer(XImage), - ) - cfactory("XDestroyImage", [pointer(XImage)], void) - cfactory( - "XQueryExtension", - [pointer(Display), char_p, pointer(c_int), pointer(c_int), pointer(c_int)], - uint, - ) - - # A simple benchmark calling 10 times those 2 functions: - # XRRGetScreenResources(): 0.1755971429956844 s - # XRRGetScreenResourcesCurrent(): 0.0039125580078689 s - # The second is faster by a factor of 44! So try to use it first. - try: - cfactory( - "XRRGetScreenResourcesCurrent", - [pointer(Display), pointer(Display)], - pointer(XRRScreenResources), - attr=self.xrandr, - ) - except AttributeError: - cfactory( - "XRRGetScreenResources", - [pointer(Display), pointer(Display)], - pointer(XRRScreenResources), - attr=self.xrandr, - ) - self.xrandr.XRRGetScreenResourcesCurrent = self.xrandr.XRRGetScreenResources - - cfactory( - "XRRGetCrtcInfo", - [pointer(Display), pointer(XRRScreenResources), c_long], - pointer(XRRCrtcInfo), - attr=self.xrandr, - ) - cfactory( - "XRRFreeScreenResources", - [pointer(XRRScreenResources)], - void, - attr=self.xrandr, - ) - cfactory("XRRFreeCrtcInfo", [pointer(XRRCrtcInfo)], void, attr=self.xrandr) + cfactory = self._cfactory + attrs = { + "xlib": self.xlib, + "xrandr": self.xrandr, + } + for func, (attr, argtypes, restype) in CFUNCTIONS.items(): + try: + cfactory( + attr=attrs[attr], + errcheck=validate, + func=func, + argtypes=argtypes, + restype=restype, + ) # type: ignore + except AttributeError: + pass def get_error_details(self): # type: () -> Optional[Dict[str, Any]] @@ -402,7 +412,15 @@ ) # Each monitors - mon = xrandr.XRRGetScreenResourcesCurrent(display, self.drawable).contents + # A simple benchmark calling 10 times those 2 functions: + # XRRGetScreenResources(): 0.1755971429956844 s + # XRRGetScreenResourcesCurrent(): 0.0039125580078689 s + # The second is faster by a factor of 44! So try to use it first. + try: + mon = xrandr.XRRGetScreenResourcesCurrent(display, self.drawable).contents + except AttributeError: + mon = xrandr.XRRGetScreenResources(display, self.drawable).contents + crtcs = mon.crtcs for idx in range(mon.ncrtc): crtc = xrandr.XRRGetCrtcInfo(display, mon, crtcs[idx]).contents @@ -447,9 +465,7 @@ raw_data = ctypes.cast( ximage.contents.data, - ctypes.POINTER( - ctypes.c_ubyte * monitor["height"] * monitor["width"] * 4 - ), + POINTER(c_ubyte * monitor["height"] * monitor["width"] * 4), ) data = bytearray(raw_data.contents) finally: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/mss/screenshot.py new/mss-6.1.0/mss/screenshot.py --- old/mss-6.0.0/mss/screenshot.py 2019-04-23 16:35:25.000000000 +0200 +++ new/mss-6.1.0/mss/screenshot.py 2020-10-31 18:07:02.000000000 +0100 @@ -152,6 +152,7 @@ try: return self.pixels[coord_y][coord_x] # type: ignore except IndexError: + # pylint: disable=raise-missing-from raise ScreenShotError( "Pixel location ({}, {}) is out of range.".format(coord_x, coord_y) ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/mss/tests/test_gnu_linux.py new/mss-6.1.0/mss/tests/test_gnu_linux.py --- old/mss-6.0.0/mss/tests/test_gnu_linux.py 2020-06-30 17:37:13.000000000 +0200 +++ new/mss-6.1.0/mss/tests/test_gnu_linux.py 2020-10-31 18:07:02.000000000 +0100 @@ -37,14 +37,15 @@ # macOS monkeypatch.setattr(platform, "system", lambda: "Darwin") - with pytest.raises(ScreenShotError): + with pytest.raises((ScreenShotError, ValueError)): + # ValueError on macOS Big Sur mss.mss() monkeypatch.undo() # Windows monkeypatch.setattr(platform, "system", lambda: "wInDoWs") - with pytest.raises(ValueError): - # wintypes.py:19: ValueError: _type_ 'v' not supported + with pytest.raises(ImportError): + # ImportError: cannot import name 'WINFUNCTYPE' mss.mss() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/mss/tests/test_implementation.py new/mss-6.1.0/mss/tests/test_implementation.py --- old/mss-6.0.0/mss/tests/test_implementation.py 2020-06-28 18:08:11.000000000 +0200 +++ new/mss-6.1.0/mss/tests/test_implementation.py 2020-10-31 18:07:02.000000000 +0100 @@ -96,11 +96,12 @@ fmt = "sct-{width}x{height}.png" for opt in ("-o", "--out"): main([opt, fmt]) - filename = fmt.format(**sct.monitors[1]) out, _ = capsys.readouterr() - assert out.endswith(filename + "\n") - assert os.path.isfile(filename) - os.remove(filename) + for monitor, line in zip(sct.monitors[1:], out.splitlines()): + filename = fmt.format(**monitor) + assert line.endswith(filename) + assert os.path.isfile(filename) + os.remove(filename) fmt = "sct_{mon}-{date:%Y-%m-%d}.png" for opt in ("-o", "--out"): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/mss/tests/test_macos.py new/mss-6.1.0/mss/tests/test_macos.py --- old/mss-6.0.0/mss/tests/test_macos.py 2019-12-31 18:37:33.000000000 +0100 +++ new/mss-6.1.0/mss/tests/test_macos.py 2020-10-31 18:07:02.000000000 +0100 @@ -44,10 +44,13 @@ def test_implementation(monkeypatch): # No `CoreGraphics` library - monkeypatch.setattr(ctypes.util, "find_library", lambda x: None) - with pytest.raises(ScreenShotError): - mss.mss() - monkeypatch.undo() + version = float(".".join(platform.mac_ver()[0].split(".")[:2])) + + if version < 10.16: + monkeypatch.setattr(ctypes.util, "find_library", lambda x: None) + with pytest.raises(ScreenShotError): + mss.mss() + monkeypatch.undo() with mss.mss() as sct: # Test monitor's rotation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/mss/tests/test_third_party.py new/mss-6.1.0/mss/tests/test_third_party.py --- old/mss-6.0.0/mss/tests/test_third_party.py 2020-01-04 21:27:05.000000000 +0100 +++ new/mss-6.1.0/mss/tests/test_third_party.py 2020-10-31 18:07:02.000000000 +0100 @@ -11,7 +11,8 @@ try: import numpy -except ImportError: +except (ImportError, RuntimeError): + # RuntimeError on Python 3.9 (macOS): Polyfit sanity test emitted a warning, ... numpy = None try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/mss/windows.py new/mss-6.1.0/mss/windows.py --- old/mss-6.0.0/mss/windows.py 2020-06-28 19:22:53.000000000 +0200 +++ new/mss-6.1.0/mss/windows.py 2020-10-31 18:07:02.000000000 +0100 @@ -6,6 +6,7 @@ import sys import ctypes import threading +from ctypes import POINTER, Structure, WINFUNCTYPE, c_void_p from ctypes.wintypes import ( BOOL, DOUBLE, @@ -40,7 +41,7 @@ SRCCOPY = 0x00CC0020 -class BITMAPINFOHEADER(ctypes.Structure): +class BITMAPINFOHEADER(Structure): """ Information about the dimensions and color format of a DIB. """ _fields_ = [ @@ -58,7 +59,7 @@ ] -class BITMAPINFO(ctypes.Structure): +class BITMAPINFO(Structure): """ Structure that defines the dimensions and color information for a DIB. """ @@ -66,10 +67,39 @@ _fields_ = [("bmiHeader", BITMAPINFOHEADER), ("bmiColors", DWORD * 3)] +MONITORNUMPROC = WINFUNCTYPE(INT, DWORD, DWORD, POINTER(RECT), DOUBLE) + + +# C functions that will be initialised later. +# +# This is a dict: +# cfunction: (attr, argtypes, restype) +# +# Available attr: gdi32, user32. +# +# Note: keep it sorted by cfunction. +CFUNCTIONS = { + "BitBlt": ("gdi32", [HDC, INT, INT, INT, INT, HDC, INT, INT, DWORD], BOOL), + "CreateCompatibleBitmap": ("gdi32", [HDC, INT, INT], HBITMAP), + "CreateCompatibleDC": ("gdi32", [HDC], HDC), + "DeleteObject": ("gdi32", [HGDIOBJ], INT), + "EnumDisplayMonitors": ("user32", [HDC, c_void_p, MONITORNUMPROC, LPARAM], BOOL), + "GetDeviceCaps": ("gdi32", [HWND, INT], INT), + "GetDIBits": ( + "gdi32", + [HDC, HBITMAP, UINT, UINT, c_void_p, POINTER(BITMAPINFO), UINT], + BOOL, + ), + "GetSystemMetrics": ("user32", [INT], INT), + "GetWindowDC": ("user32", [HWND], HDC), + "SelectObject": ("gdi32", [HDC, HGDIOBJ], HGDIOBJ), +} + + class MSS(MSSBase): """ Multiple ScreenShots implementation for Microsoft Windows. """ - __slots__ = {"_bbox", "_bmi", "_data", "gdi32", "monitorenumproc", "user32"} + __slots__ = {"_bbox", "_bmi", "_data", "gdi32", "user32"} # Class attributes instanced one time to prevent resource leaks. bmp = None @@ -84,10 +114,6 @@ super().__init__() - self.monitorenumproc = ctypes.WINFUNCTYPE( - INT, DWORD, DWORD, ctypes.POINTER(RECT), DOUBLE - ) - self.user32 = ctypes.WinDLL("user32") self.gdi32 = ctypes.WinDLL("gdi32") self._set_cfunctions() @@ -112,55 +138,18 @@ def _set_cfunctions(self): """ Set all ctypes functions and attach them to attributes. """ - void = ctypes.c_void_p - pointer = ctypes.POINTER - - self._cfactory( - attr=self.user32, func="GetSystemMetrics", argtypes=[INT], restype=INT - ) - self._cfactory( - attr=self.user32, - func="EnumDisplayMonitors", - argtypes=[HDC, void, self.monitorenumproc, LPARAM], - restype=BOOL, - ) - self._cfactory( - attr=self.user32, func="GetWindowDC", argtypes=[HWND], restype=HDC - ) - - self._cfactory( - attr=self.gdi32, func="GetDeviceCaps", argtypes=[HWND, INT], restype=INT - ) - self._cfactory( - attr=self.gdi32, func="CreateCompatibleDC", argtypes=[HDC], restype=HDC - ) - self._cfactory( - attr=self.gdi32, - func="CreateCompatibleBitmap", - argtypes=[HDC, INT, INT], - restype=HBITMAP, - ) - self._cfactory( - attr=self.gdi32, - func="SelectObject", - argtypes=[HDC, HGDIOBJ], - restype=HGDIOBJ, - ) - self._cfactory( - attr=self.gdi32, - func="BitBlt", - argtypes=[HDC, INT, INT, INT, INT, HDC, INT, INT, DWORD], - restype=BOOL, - ) - self._cfactory( - attr=self.gdi32, func="DeleteObject", argtypes=[HGDIOBJ], restype=INT - ) - self._cfactory( - attr=self.gdi32, - func="GetDIBits", - argtypes=[HDC, HBITMAP, UINT, UINT, void, pointer(BITMAPINFO), UINT], - restype=BOOL, - ) + cfactory = self._cfactory + attrs = { + "gdi32": self.gdi32, + "user32": self.user32, + } + for func, (attr, argtypes, restype) in CFUNCTIONS.items(): + cfactory( + attr=attrs[attr], + func=func, + argtypes=argtypes, + restype=restype, + ) # type: ignore def _set_dpi_awareness(self): """ Set DPI aware to capture full screen on Hi-DPI monitors. """ @@ -229,7 +218,7 @@ ) return 1 - callback = self.monitorenumproc(_callback) + callback = MONITORNUMPROC(_callback) user32.EnumDisplayMonitors(0, 0, callback, 0) def _grab_impl(self, monitor): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/mss.egg-info/PKG-INFO new/mss-6.1.0/mss.egg-info/PKG-INFO --- old/mss-6.0.0/mss.egg-info/PKG-INFO 2020-06-30 18:00:14.000000000 +0200 +++ new/mss-6.1.0/mss.egg-info/PKG-INFO 2020-10-31 18:18:32.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: mss -Version: 6.0.0 +Version: 6.1.0 Summary: An ultra fast cross-platform multiple screenshots module in pure python using ctypes. Home-page: https://github.com/BoboTiG/python-mss Author: Micka��l 'Tiger-222' Schoentgen diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mss-6.0.0/setup.cfg new/mss-6.1.0/setup.cfg --- old/mss-6.0.0/setup.cfg 2020-06-30 18:00:14.000000000 +0200 +++ new/mss-6.1.0/setup.cfg 2020-10-31 18:18:32.503833500 +0100 @@ -1,6 +1,6 @@ [metadata] name = mss -version = 6.0.0 +version = 6.1.0 author = Micka��l 'Tiger-222' Schoentgen author-email = contact@tiger-222.fr description = An ultra fast cross-platform multiple screenshots module in pure python using ctypes.
participants (1)
-
Source-Sync