Mon, 01 Apr 2019 19:34:58 +0200
Snapshot: refactored the SnapWidget to prepare for implementing snapshot functionality for Wayland desktops.
--- a/Globals/__init__.py Sun Mar 31 16:22:00 2019 +0200 +++ b/Globals/__init__.py Mon Apr 01 19:34:58 2019 +0200 @@ -92,9 +92,100 @@ if currDesktop: return currDesktop + currDesktop = os.environ.get("GNOME_DESKTOP_SESSION_ID", "") + if currDesktop: + return currDesktop + + currDesktop = os.environ.get("KDE_FULL_SESSION", "") + if currDesktop: + return currDesktop + + currDesktop = os.environ.get("DESKTOP_SESSION", "") + if currDesktop: + return currDesktop + return "" +def isKdeDesktop(): + """ + Function to check, if the current session is a KDE desktop (Linux only). + + @return flag indicating a KDE desktop + @rtype bool + """ + if not isLinuxPlatform(): + return False + + isKDE = False + + desktop = os.environ.get("XDG_CURRENT_DESKTOP", "").lower() or \ + os.environ.get("XDG_SESSION_DESKTOP", "").lower() or \ + os.environ.get("DESKTOP_SESSION", "").lower() + if desktop: + isKDE = "kde" in desktop or "plasma" in desktop + else: + isKDE = bool(os.environ.get("KDE_FULL_SESSION", "")) + + return isKDE + + +def isGnomeDesktop(): + """ + Function to check, if the current session is a Gnome desktop (Linux only). + + @return flag indicating a Gnome desktop + @rtype bool + """ + if not isLinuxPlatform(): + return False + + isGnome = False + + desktop = os.environ.get("XDG_CURRENT_DESKTOP", "").lower() or \ + os.environ.get("XDG_SESSION_DESKTOP", "").lower() or \ + os.environ.get("GDMSESSION", "").lower() + if desktop: + isGnome = "gnome" in desktop + else: + isGnome = bool(os.environ.get("GNOME_DESKTOP_SESSION_ID", "")) + + return isGnome + + +def sessionType(): + """ + Function to determine the name of the running session (Linux only). + + @return name of the desktop environment + @rtype str + """ + if not isLinuxPlatform(): + return "" + + sessionType = os.environ.get("XDG_SESSION_TYPE").lower() + if "x11" in sessionType: + return "X11" + elif "wayland" in sessionType: + return "Wayland" + + sessionType = os.environ.get("WAYLAND_DISPLAY", "").lower() + if "wayland" in sessionType: + return "Wayland" + + return "" + + +def isWaylandSession(): + """ + Function to check, if the current session is a wayland session. + + @return flag indicating a wayland session + @rtype bool + """ + return sessionType() == "Wayland" + + def checkBlacklistedVersions(): """ Module functions to check for blacklisted versions of the prerequisites.
--- a/Snapshot/SnapWidget.py Sun Mar 31 16:22:00 2019 +0200 +++ b/Snapshot/SnapWidget.py Mon Apr 01 19:34:58 2019 +0200 @@ -29,6 +29,8 @@ import Globals from Globals import qVersionTuple +from .SnapshotModes import SnapshotModes + class SnapWidget(QWidget, Ui_SnapWidget): """ @@ -55,24 +57,37 @@ self.copyPreviewButton.setIcon(UI.PixmapCache.getIcon("editCopy.png")) self.setWindowIcon(UI.PixmapCache.getIcon("ericSnap.png")) - self.modeCombo.addItem(self.tr("Fullscreen"), - SnapWidget.ModeFullscreen) - if qVersionTuple() >= (5, 10, 0): - if len(QApplication.screens()) > 1: - self.modeCombo.addItem(self.tr("Current Screen"), - SnapWidget.ModeScreen) - else: - if QApplication.desktop().screenCount() > 1: - self.modeCombo.addItem(self.tr("Current Screen"), - SnapWidget.ModeScreen) - self.modeCombo.addItem(self.tr("Rectangular Selection"), - SnapWidget.ModeRectangle) - self.modeCombo.addItem(self.tr("Elliptical Selection"), - SnapWidget.ModeEllipse) - self.modeCombo.addItem(self.tr("Freehand Selection"), - SnapWidget.ModeFreehand) - self.__mode = int(Preferences.Prefs.settings.value("Snapshot/Mode", 0)) - index = self.modeCombo.findData(self.__mode) + from .SnapshotDefaultGrabber import SnapshotDefaultGrabber + self.__grabber = SnapshotDefaultGrabber(self) + self.__grabber.grabbed.connect(self.__captured) + supportedModes = self.__grabber.supportedModes() + + if SnapshotModes.Fullscreen in supportedModes: + self.modeCombo.addItem(self.tr("Fullscreen"), + SnapshotModes.Fullscreen) + if SnapshotModes.SelectedScreen in supportedModes: + if qVersionTuple() >= (5, 10, 0): + if len(QApplication.screens()) > 1: + self.modeCombo.addItem(self.tr("Selected Screen"), + SnapshotModes.SelectedScreen) + else: + if QApplication.desktop().screenCount() > 1: + self.modeCombo.addItem(self.tr("Selected Screen"), + SnapshotModes.SelectedScreen) + if SnapshotModes.SelectedWindow in supportedModes: + self.modeCombo.addItem(self.tr("Selected Window"), + SnapshotModes.SelectedWindow) + if SnapshotModes.Rectangle in supportedModes: + self.modeCombo.addItem(self.tr("Rectangular Selection"), + SnapshotModes.Rectangle) + if SnapshotModes.Ellipse in supportedModes: + self.modeCombo.addItem(self.tr("Elliptical Selection"), + SnapshotModes.Ellipse) + if SnapshotModes.Freehand in supportedModes: + self.modeCombo.addItem(self.tr("Freehand Selection"), + SnapshotModes.Freehand) + mode = int(Preferences.Prefs.settings.value("Snapshot/Mode", 0)) + index = self.modeCombo.findData(SnapshotModes(mode)) if index == -1: index = 0 self.modeCombo.setCurrentIndex(index) @@ -94,25 +109,16 @@ os.path.join(picturesLocation, self.tr("snapshot") + "1.png")) - self.__grabber = None self.__snapshot = QPixmap() self.__savedPosition = QPoint() self.__modified = False self.__locale = QLocale() - self.__grabberWidget = QWidget(None, Qt.X11BypassWindowManagerHint) - self.__grabberWidget.move(-10000, -10000) - self.__grabberWidget.installEventFilter(self) - self.__initFileFilters() - self.__initShortcuts() self.preview.startDrag.connect(self.__dragSnapshot) - from .SnapshotTimer import SnapshotTimer - self.__grabTimer = SnapshotTimer() - self.__grabTimer.timeout.connect(self.__grabTimerTimeout) self.__updateTimer = QTimer() self.__updateTimer.setSingleShot(True) self.__updateTimer.timeout.connect(self.__updatePreview) @@ -301,113 +307,14 @@ """ Private slot to take a snapshot. """ - self.__mode = self.modeCombo.itemData(self.modeCombo.currentIndex()) self.__delay = self.delaySpin.value() self.__savedPosition = self.pos() self.hide() - if self.__delay: - self.__grabTimer.start(self.__delay) - else: - QTimer.singleShot(200, self.__startUndelayedGrab) - - def __grabTimerTimeout(self): - """ - Private slot to perform a delayed grab operation. - """ - if self.__mode == SnapWidget.ModeRectangle: - self.__grabRectangle() - elif self.__mode == SnapWidget.ModeEllipse: - self.__grabEllipse() - elif self.__mode == SnapWidget.ModeFreehand: - self.__grabFreehand() - else: - self.__performGrab() - - def __startUndelayedGrab(self): - """ - Private slot to perform an undelayed grab operation. - """ - if self.__mode == SnapWidget.ModeRectangle: - self.__grabRectangle() - elif self.__mode == SnapWidget.ModeEllipse: - self.__grabEllipse() - elif self.__mode == SnapWidget.ModeFreehand: - self.__grabFreehand() - else: - if Globals.isMacPlatform(): - self.__performGrab() - else: - self.__grabberWidget.show() - self.__grabberWidget.grabMouse(Qt.CrossCursor) - - def __grabRectangle(self): - """ - Private method to grab a rectangular screen region. - """ - from .SnapshotRegionGrabber import SnapshotRegionGrabber - self.__grabber = SnapshotRegionGrabber( - mode=SnapshotRegionGrabber.Rectangle) - self.__grabber.grabbed.connect(self.__captured) - - def __grabEllipse(self): - """ - Private method to grab an elliptical screen region. - """ - from .SnapshotRegionGrabber import SnapshotRegionGrabber - self.__grabber = SnapshotRegionGrabber( - mode=SnapshotRegionGrabber.Ellipse) - self.__grabber.grabbed.connect(self.__captured) - - def __grabFreehand(self): - """ - Private method to grab a non-rectangular screen region. - """ - from .SnapshotFreehandGrabber import SnapshotFreehandGrabber - self.__grabber = SnapshotFreehandGrabber() - self.__grabber.grabbed.connect(self.__captured) - - def __performGrab(self): - """ - Private method to perform a screen grab other than a selected region. - """ - self.__grabberWidget.releaseMouse() - self.__grabberWidget.hide() - self.__grabTimer.stop() - - if self.__mode == SnapWidget.ModeFullscreen: - desktop = QApplication.desktop() - if qVersionTuple() >= (5, 0, 0): - self.__snapshot = QApplication.screens()[0].grabWindow( - desktop.winId(), desktop.x(), desktop.y(), - desktop.width(), desktop.height()) - else: - self.__snapshot = QPixmap.grabWindow( - desktop.winId(), desktop.x(), desktop.y(), - desktop.width(), desktop.height()) - elif self.__mode == SnapWidget.ModeScreen: - if qVersionTuple() >= (5, 10, 0): - screen = QApplication.screenAt(QCursor.pos()) - geom = screen.geometry() - else: - desktop = QApplication.desktop() - screenId = desktop.screenNumber(QCursor.pos()) - geom = desktop.screenGeometry(screenId) - x = geom.x() - y = geom.y() - if qVersionTuple() >= (5, 0, 0): - self.__snapshot = QApplication.screens()[0].grabWindow( - desktop.winId(), x, y, geom.width(), geom.height()) - else: - self.__snapshot = QPixmap.grabWindow( - desktop.winId(), x, y, geom.width(), geom.height()) - else: - self.__snapshot = QPixmap() - - self.__redisplay() - self.__modified = True - self.__updateCaption() + self.__grabber.grab( + self.modeCombo.itemData(self.modeCombo.currentIndex()), + self.delaySpin.value()) def __redisplay(self): """ @@ -445,12 +352,8 @@ @param pixmap pixmap of the snapshot (QPixmap) """ - self.__grabber.close() self.__snapshot = QPixmap(pixmap) - self.__grabber.grabbed.disconnect(self.__captured) - self.__grabber = None - self.__redisplay() self.__modified = True self.__updateCaption() @@ -486,23 +389,6 @@ drag.setPixmap(self.preview.pixmap()) drag.exec_(Qt.CopyAction) - def eventFilter(self, obj, evt): - """ - Public method to handle event for other objects. - - @param obj reference to the object (QObject) - @param evt reference to the event (QEvent) - @return flag indicating that the event should be filtered out (boolean) - """ - if obj == self.__grabberWidget and \ - evt.type() == QEvent.MouseButtonPress: - if QWidget.mouseGrabber() != self.__grabberWidget: - return False - if evt.button() == Qt.LeftButton: - self.__performGrab() - - return False - def closeEvent(self, evt): """ Protected method handling the close event. @@ -529,7 +415,7 @@ "Snapshot/Delay", self.delaySpin.value()) Preferences.Prefs.settings.setValue( "Snapshot/Mode", - self.modeCombo.itemData(self.modeCombo.currentIndex())) + self.modeCombo.itemData(self.modeCombo.currentIndex()).value) Preferences.Prefs.settings.setValue( "Snapshot/Filename", self.__filename) Preferences.Prefs.settings.sync()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Snapshot/SnapshotDefaultGrabber.py Mon Apr 01 19:34:58 2019 +0200 @@ -0,0 +1,204 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2019 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a grabber object for non-Wayland desktops. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSignal, Qt, QObject, QTimer, QEvent +from PyQt5.QtGui import QPixmap, QCursor +from PyQt5.QtWidgets import QWidget, QApplication + +from .SnapshotModes import SnapshotModes + +import Globals + + +class SnapshotDefaultGrabber(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(SnapshotDefaultGrabber, self).__init__(parent) + + self.__grabber = None + self.__grabberWidget = QWidget(None, Qt.X11BypassWindowManagerHint) + self.__grabberWidget.move(-10000, -10000) + self.__grabberWidget.installEventFilter(self) + + from .SnapshotTimer import SnapshotTimer + self.__grabTimer = SnapshotTimer() + self.__grabTimer.timeout.connect(self.__grabTimerTimeout) + + def supportedModes(self): + """ + Public method to get the supported screenshot modes. + + @return tuple of supported screenshot modes + @rtype tuple of SnapshotModes + """ + return ( + SnapshotModes.Fullscreen, + SnapshotModes.SelectedScreen, + SnapshotModes.Rectangle, + SnapshotModes.Freehand, + SnapshotModes.Ellipse, + ) + + def grab(self, mode, delay=0): + """ + Public method to perform a grab operation potentially after a delay. + + @param mode screenshot mode + @type ScreenshotModes + @param delay delay in seconds + @type int + """ + self.__mode = mode + if delay: + self.__grabTimer.start(delay) + else: + QTimer.singleShot(200, self.__startUndelayedGrab) + + def __grabTimerTimeout(self): + """ + Private slot to perform a delayed grab operation. + """ + if self.__mode == SnapshotModes.Rectangle: + self.__grabRectangle() + elif self.__mode == SnapshotModes.Ellipse: + self.__grabEllipse() + elif self.__mode == SnapshotModes.Freehand: + self.__grabFreehand() + else: + self.__performGrab(self.__mode) + + def __startUndelayedGrab(self): + """ + Private slot to perform an undelayed grab operation. + """ + if self.__mode == SnapshotModes.Rectangle: + self.__grabRectangle() + elif self.__mode == SnapshotModes.Ellipse: + self.__grabEllipse() + elif self.__mode == SnapshotModes.Freehand: + self.__grabFreehand() + else: + if Globals.isMacPlatform(): + self.__performGrab(self.__mode) + else: + self.__grabberWidget.show() + self.__grabberWidget.grabMouse(Qt.CrossCursor) + + def __grabRectangle(self): + """ + Private method to grab a rectangular screen region. + """ + from .SnapshotRegionGrabber import SnapshotRegionGrabber + self.__grabber = SnapshotRegionGrabber( + mode=SnapshotRegionGrabber.Rectangle) + self.__grabber.grabbed.connect(self.__captured) + + def __grabEllipse(self): + """ + Private method to grab an elliptical screen region. + """ + from .SnapshotRegionGrabber import SnapshotRegionGrabber + self.__grabber = SnapshotRegionGrabber( + mode=SnapshotRegionGrabber.Ellipse) + self.__grabber.grabbed.connect(self.__captured) + + def __grabFreehand(self): + """ + Private method to grab a non-rectangular screen region. + """ + from .SnapshotFreehandGrabber import SnapshotFreehandGrabber + self.__grabber = SnapshotFreehandGrabber() + self.__grabber.grabbed.connect(self.__captured) + + def __performGrab(self, mode): + """ + Private method to perform a screen grab other than a selected region. + + @param mode screenshot mode + @type SnapshotModes + """ + self.__grabberWidget.releaseMouse() + self.__grabberWidget.hide() + self.__grabTimer.stop() + + if mode == SnapshotModes.Fullscreen: + desktop = QApplication.desktop() + if Globals.qVersionTuple() >= (5, 0, 0): + snapshot = QApplication.screens()[0].grabWindow( + desktop.winId(), desktop.x(), desktop.y(), + desktop.width(), desktop.height()) + else: + snapshot = QPixmap.grabWindow( + desktop.winId(), desktop.x(), desktop.y(), + desktop.width(), desktop.height()) + elif mode == SnapshotModes.SelectedScreen: + desktop = QApplication.desktop() + if Globals.qVersionTuple() >= (5, 10, 0): + screen = QApplication.screenAt(QCursor.pos()) + geom = screen.geometry() + else: + screenId = desktop.screenNumber(QCursor.pos()) + geom = desktop.screenGeometry(screenId) + x = geom.x() + y = geom.y() + if Globals.qVersionTuple() >= (5, 0, 0): + snapshot = QApplication.screens()[0].grabWindow( + desktop.winId(), x, y, geom.width(), geom.height()) + else: + snapshot = QPixmap.grabWindow( + desktop.winId(), x, y, geom.width(), geom.height()) + else: + snapshot = QPixmap() + + self.grabbed.emit(snapshot) + + def __captured(self, pixmap): + """ + Private slot to show a preview of the snapshot. + + @param pixmap pixmap of the snapshot (QPixmap) + """ + self.__grabber.close() + snapshot = QPixmap(pixmap) + + self.__grabber.grabbed.disconnect(self.__captured) + self.__grabber = None + + self.grabbed.emit(snapshot) + + def eventFilter(self, obj, evt): + """ + Public method to handle event for other objects. + + @param obj reference to the object (QObject) + @param evt reference to the event (QEvent) + @return flag indicating that the event should be filtered out (boolean) + """ + if obj == self.__grabberWidget and \ + evt.type() == QEvent.MouseButtonPress: + if QWidget.mouseGrabber() != self.__grabberWidget: + return False + if evt.button() == Qt.LeftButton: + self.__performGrab(self.__mode) + + return False
--- a/Snapshot/SnapshotFreehandGrabber.py Sun Mar 31 16:22:00 2019 +0200 +++ b/Snapshot/SnapshotFreehandGrabber.py Mon Apr 01 19:34:58 2019 +0200 @@ -34,7 +34,7 @@ painter.setClipRegion(clip) painter.setPen(pen) painter.drawPolygon(QPolygon(polygon)) - if fill.isValid(): + if fill and fill.isValid(): painter.setClipping(False) painter.setBrush(fill or QColor()) painter.drawPolygon(QPolygon(polygon))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Snapshot/SnapshotModes.py Mon Apr 01 19:34:58 2019 +0200 @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2019 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the snapshot mode enumeration. +""" + +from __future__ import unicode_literals + +try: + from enum import Enum +except ImportError: + from ThirdParty.enum import Enum + + +class SnapshotModes(Enum): + """ + Class implementing the snapshot modes. + """ + Fullscreen = 0 + SelectedScreen = 1 + Rectangle = 2 + Freehand = 3 + Ellipse = 4 + SelectedWindow = 5
--- a/Snapshot/SnapshotTimer.py Sun Mar 31 16:22:00 2019 +0200 +++ b/Snapshot/SnapshotTimer.py Mon Apr 01 19:34:58 2019 +0200 @@ -15,6 +15,7 @@ from Globals import qVersionTuple + class SnapshotTimer(QWidget): """ Class implementing the snapshot timer widget.
--- a/eric6.e4p Sun Mar 31 16:22:00 2019 +0200 +++ b/eric6.e4p Mon Apr 01 19:34:58 2019 +0200 @@ -1037,7 +1037,9 @@ <Source>QScintilla/ZoomDialog.py</Source> <Source>QScintilla/__init__.py</Source> <Source>Snapshot/SnapWidget.py</Source> + <Source>Snapshot/SnapshotDefaultGrabber.py</Source> <Source>Snapshot/SnapshotFreehandGrabber.py</Source> + <Source>Snapshot/SnapshotModes.py</Source> <Source>Snapshot/SnapshotPreview.py</Source> <Source>Snapshot/SnapshotRegionGrabber.py</Source> <Source>Snapshot/SnapshotTimer.py</Source> @@ -2259,14 +2261,14 @@ </Resources> <Others> <Other>.hgignore</Other> - <Other>APIs/Python/zope-2.10.7.api</Other> - <Other>APIs/Python/zope-2.11.2.api</Other> - <Other>APIs/Python/zope-3.3.1.api</Other> <Other>APIs/Python3/PyQt4.bas</Other> <Other>APIs/Python3/PyQt5.bas</Other> <Other>APIs/Python3/QScintilla2.bas</Other> <Other>APIs/Python3/eric6.api</Other> <Other>APIs/Python3/eric6.bas</Other> + <Other>APIs/Python/zope-2.10.7.api</Other> + <Other>APIs/Python/zope-2.11.2.api</Other> + <Other>APIs/Python/zope-3.3.1.api</Other> <Other>APIs/QSS/qss.api</Other> <Other>APIs/Ruby/Ruby-1.8.7.api</Other> <Other>APIs/Ruby/Ruby-1.8.7.bas</Other>