--- a/src/eric7/Snapshot/SnapshotWaylandGrabber.py Wed Jul 13 11:16:20 2022 +0200 +++ b/src/eric7/Snapshot/SnapshotWaylandGrabber.py Wed Jul 13 14:55:47 2022 +0200 @@ -17,6 +17,7 @@ try: from PyQt6.QtDBus import QDBusInterface, QDBusMessage + DBusAvailable = True except ImportError: DBusAvailable = False @@ -31,28 +32,30 @@ class SnapshotWaylandGrabber(QObject): """ Class implementing a grabber object for non-Wayland desktops. - + @signal grabbed(QPixmap) emitted after the grab operation is finished """ + grabbed = pyqtSignal(QPixmap) - + def __init__(self, parent=None): """ Constructor - + @param parent reference to the parent object @type QObject """ super().__init__(parent) - + from .SnapshotTimer import SnapshotTimer + self.__grabTimer = SnapshotTimer() self.__grabTimer.timeout.connect(self.__performGrab) - + def supportedModes(self): """ Public method to get the supported screenshot modes. - + @return tuple of supported screenshot modes @rtype tuple of SnapshotModes """ @@ -72,12 +75,11 @@ ) else: return () - - def grab(self, mode, delay=0, captureCursor=False, - captureDecorations=False): + + def grab(self, mode, delay=0, captureCursor=False, captureDecorations=False): """ Public method to perform a grab operation potentially after a delay. - + @param mode screenshot mode @type ScreenshotModes @param delay delay in seconds @@ -92,7 +94,7 @@ # just to play it safe self.grabbed.emit(QPixmap()) return - + self.__mode = mode self.__captureCursor = captureCursor self.__captureDecorations = captureDecorations @@ -100,19 +102,21 @@ self.__grabTimer.start(delay) else: QTimer.singleShot(200, self.__performGrab) - + def __performGrab(self): """ Private method to perform the grab operations. - + @exception RuntimeError raised to indicate an unsupported grab mode """ if self.__mode not in ( - SnapshotModes.FULLSCREEN, SnapshotModes.SELECTEDSCREEN, - SnapshotModes.SELECTEDWINDOW, SnapshotModes.RECTANGLE, + SnapshotModes.FULLSCREEN, + SnapshotModes.SELECTEDSCREEN, + SnapshotModes.SELECTEDWINDOW, + SnapshotModes.RECTANGLE, ): raise RuntimeError("unsupported grab mode given") - + if self.__mode == SnapshotModes.FULLSCREEN: self.__grabFullscreen() elif self.__mode == SnapshotModes.SELECTEDSCREEN: @@ -121,23 +125,18 @@ self.__grabSelectedWindow() else: self.__grabRectangle() - + def __grabFullscreen(self): """ Private method to grab the complete desktop. """ snapshot = QPixmap() - + if Globals.isKdeDesktop(): interface = QDBusInterface( - "org.kde.KWin", - "/Screenshot", - "org.kde.kwin.Screenshot" + "org.kde.KWin", "/Screenshot", "org.kde.kwin.Screenshot" ) - reply = interface.call( - "screenshotFullscreen", - self.__captureCursor - ) + reply = interface.call("screenshotFullscreen", self.__captureCursor) if self.__checkReply(reply, 1): filename = reply.arguments()[0] if filename: @@ -149,29 +148,24 @@ interface = QDBusInterface( "org.gnome.Shell", "/org/gnome/Shell/Screenshot", - "org.gnome.Shell.Screenshot" + "org.gnome.Shell.Screenshot", ) - reply = interface.call( - "Screenshot", - self.__captureCursor, - False, - path - ) + reply = interface.call("Screenshot", self.__captureCursor, False, path) if self.__checkReply(reply, 2): filename = reply.arguments()[1] if filename: snapshot = QPixmap(filename) with contextlib.suppress(OSError): os.remove(filename) - + self.grabbed.emit(snapshot) - + def __grabSelectedScreen(self): """ Private method to grab a selected screen. """ snapshot = QPixmap() - + if Globals.isKdeDesktop(): screen = QApplication.screenAt(QCursor.pos()) try: @@ -179,18 +173,12 @@ except ValueError: # default to screen 0 screenId = 0 - + # Step 2: grab the screen interface = QDBusInterface( - "org.kde.KWin", - "/Screenshot", - "org.kde.kwin.Screenshot" + "org.kde.KWin", "/Screenshot", "org.kde.kwin.Screenshot" ) - reply = interface.call( - "screenshotScreen", - screenId, - self.__captureCursor - ) + reply = interface.call("screenshotScreen", screenId, self.__captureCursor) if self.__checkReply(reply, 1): filename = reply.arguments()[0] if filename: @@ -203,14 +191,14 @@ interface = QDBusInterface( "org.gnome.Shell", "/org/gnome/Shell/Screenshot", - "org.gnome.Shell.Screenshot" + "org.gnome.Shell.Screenshot", ) reply = interface.call( "ScreenshotWindow", self.__captureDecorations, self.__captureCursor, False, - path + path, ) if self.__checkReply(reply, 2): filename = reply.arguments()[1] @@ -218,22 +206,22 @@ snapshot = QPixmap(filename) with contextlib.suppress(OSError): os.remove(filename) - + # Step 2: extract the area of the screen containing # the cursor if not snapshot.isNull(): screen = QApplication.screenAt(QCursor.pos()) geom = screen.geometry() snapshot = snapshot.copy(geom) - + self.grabbed.emit(snapshot) - + def __grabSelectedWindow(self): """ Private method to grab a selected window. """ snapshot = QPixmap() - + if Globals.isKdeDesktop(): mask = 0 if self.__captureDecorations: @@ -241,14 +229,9 @@ if self.__captureCursor: mask |= 2 interface = QDBusInterface( - "org.kde.KWin", - "/Screenshot", - "org.kde.kwin.Screenshot" + "org.kde.KWin", "/Screenshot", "org.kde.kwin.Screenshot" ) - reply = interface.call( - "interactive", - mask - ) + reply = interface.call("interactive", mask) if self.__checkReply(reply, 1): filename = reply.arguments()[0] if filename: @@ -260,14 +243,14 @@ interface = QDBusInterface( "org.gnome.Shell", "/org/gnome/Shell/Screenshot", - "org.gnome.Shell.Screenshot" + "org.gnome.Shell.Screenshot", ) reply = interface.call( "ScreenshotWindow", self.__captureDecorations, self.__captureCursor, False, - path + path, ) if self.__checkReply(reply, 2): filename = reply.arguments()[1] @@ -275,33 +258,30 @@ snapshot = QPixmap(filename) with contextlib.suppress(OSError): os.remove(filename) - + self.grabbed.emit(snapshot) - + def __grabRectangle(self): """ Private method to grab a rectangular desktop area. """ snapshot = QPixmap() - + if Globals.isGnomeDesktop(): # Step 1: let the user select the area interface = QDBusInterface( "org.gnome.Shell", "/org/gnome/Shell/Screenshot", - "org.gnome.Shell.Screenshot" + "org.gnome.Shell.Screenshot", ) reply = interface.call("SelectArea") if self.__checkReply(reply, 4): x, y, width, height = reply.arguments()[:4] - + # Step 2: grab the selected area path = self.__temporaryFilename() reply = interface.call( - "ScreenshotArea", - x, y, width, height, - False, - path + "ScreenshotArea", x, y, width, height, False, path ) if self.__checkReply(reply, 2): filename = reply.arguments()[1] @@ -309,13 +289,13 @@ snapshot = QPixmap(filename) with contextlib.suppress(OSError): os.remove(filename) - + self.grabbed.emit(snapshot) - + def __checkReply(self, reply, argumentsCount): """ Private method to check, if a reply is valid. - + @param reply reference to the reply message @type QDBusMessage @param argumentsCount number of expected arguments @@ -326,45 +306,51 @@ if reply.type() == QDBusMessage.MessageType.ReplyMessage: if len(reply.arguments()) == argumentsCount: return True - + EricMessageBox.warning( None, self.tr("Screenshot Error"), - self.tr("<p>Received an unexpected number of reply arguments." - " Expected {0} but got {1}</p>").format( + self.tr( + "<p>Received an unexpected number of reply arguments." + " Expected {0} but got {1}</p>" + ).format( argumentsCount, len(reply.arguments()), - )) - + ), + ) + elif reply.type() == QDBusMessage.MessageType.ErrorMessage: EricMessageBox.warning( None, self.tr("Screenshot Error"), - self.tr("<p>Received error <b>{0}</b> from DBus while" - " performing screenshot.</p><p>{1}</p>").format( + self.tr( + "<p>Received error <b>{0}</b> from DBus while" + " performing screenshot.</p><p>{1}</p>" + ).format( reply.errorName(), reply.errorMessage(), - )) - + ), + ) + elif reply.type() == QDBusMessage.MessageType.InvalidMessage: EricMessageBox.warning( - None, - self.tr("Screenshot Error"), - self.tr("Received an invalid reply.")) - + None, self.tr("Screenshot Error"), self.tr("Received an invalid reply.") + ) + else: EricMessageBox.warning( None, self.tr("Screenshot Error"), - self.tr("Received an unexpected reply.")) - + self.tr("Received an unexpected reply."), + ) + return False - + def __temporaryFilename(self): """ Private method to generate a temporary filename. - + @return path name for a unique, temporary file @rtype str """ - return "/tmp/eric-snap-{0}.png".format(uuid.uuid4().hex) # secok + return "/tmp/eric-snap-{0}.png".format(uuid.uuid4().hex) # secok