Skip to content

Commit 0ad3357

Browse files
Added x11 fallback (flameshot-org#4588)
1 parent 6e74dbe commit 0ad3357

File tree

7 files changed

+130
-10
lines changed

7 files changed

+130
-10
lines changed

flameshot.example.ini

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@
107107
;; (This option is not available on Windows)
108108
;useJpgForClipboard=false
109109
;
110+
;; [Deprecated] Use legacy Qt X11 screenshot method instead of freedesktop
111+
;; portal. Enable this if your WM has no xdg-desktop-portal (e.g. xmonad, i3).
112+
;; Only effective on X11; ignored on Wayland. (bool)
113+
;; (This option is only available on Linux)
114+
;useX11LegacyScreenshot=false
115+
;
110116
;; Upload to imgur without confirmation (bool)
111117
;uploadWithoutConfirmation=false
112118
;

src/config/generalconf.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ GeneralConf::GeneralConf(QWidget* parent)
5656
initAntialiasingPinZoom();
5757
initUndoLimit();
5858
initInsecurePixelate();
59+
#if defined(Q_OS_LINUX)
60+
initUseX11LegacyScreenshot();
61+
#endif
5962
#ifdef ENABLE_IMGUR
6063
initCopyAndCloseAfterUpload();
6164
initUploadWithoutConfirmation();
@@ -124,6 +127,9 @@ void GeneralConf::_updateComponents(bool allowEmptySavePath)
124127
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
125128
m_showTray->setChecked(!config.disabledTrayIcon());
126129
#endif
130+
#if defined(Q_OS_LINUX)
131+
m_useX11LegacyScreenshot->setChecked(config.useX11LegacyScreenshot());
132+
#endif
127133
}
128134

129135
void GeneralConf::updateComponents()
@@ -909,3 +915,27 @@ void GeneralConf::setInsecurePixelate(bool checked)
909915
{
910916
ConfigHandler().setInsecurePixelate(checked);
911917
}
918+
919+
#if defined(Q_OS_LINUX)
920+
void GeneralConf::initUseX11LegacyScreenshot()
921+
{
922+
m_useX11LegacyScreenshot =
923+
new QCheckBox(tr("Use legacy X11 screenshot method (deprecated)"), this);
924+
m_useX11LegacyScreenshot->setToolTip(
925+
tr("Bypass the freedesktop portal and use Qt's native X11 screen "
926+
"capture. Enable this if your window manager lacks "
927+
"xdg-desktop-portal (e.g. xmonad, i3). "
928+
"Only effective on X11; ignored on Wayland."));
929+
m_scrollAreaLayout->addWidget(m_useX11LegacyScreenshot);
930+
931+
connect(m_useX11LegacyScreenshot,
932+
&QCheckBox::clicked,
933+
this,
934+
&GeneralConf::useX11LegacyScreenshotChanged);
935+
}
936+
937+
void GeneralConf::useX11LegacyScreenshotChanged(bool checked)
938+
{
939+
ConfigHandler().setUseX11LegacyScreenshot(checked);
940+
}
941+
#endif

src/config/generalconf.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ private slots:
6161
void setJpegQuality(int v);
6262
void setReverseArrow(bool checked);
6363
void setInsecurePixelate(bool checked);
64+
#if defined(Q_OS_LINUX)
65+
void useX11LegacyScreenshotChanged(bool checked);
66+
#endif
6467

6568
private:
6669
const QString chooseFolder(const QString& currentPath = "");
@@ -99,6 +102,9 @@ private slots:
99102
void initJpegQuality();
100103
void initReverseArrow();
101104
void initInsecurePixelate();
105+
#if defined(Q_OS_LINUX)
106+
void initUseX11LegacyScreenshot();
107+
#endif
102108

103109
void _updateComponents(bool allowEmptySavePath);
104110

@@ -147,4 +153,7 @@ private slots:
147153
QSpinBox* m_jpegQuality;
148154
QCheckBox* m_reverseArrow;
149155
QCheckBox* m_insecurePixelate;
156+
#if defined(Q_OS_LINUX)
157+
QCheckBox* m_useX11LegacyScreenshot;
158+
#endif
150159
};

src/utils/confighandler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ static QMap<class QString, QSharedPointer<ValueHandler>>
140140
// Not visible on settings dialog
141141
OPTION("ignorePrntScrForcesSnipping" ,Bool ( false )),
142142
#endif
143+
#if defined(Q_OS_LINUX)
144+
// Bypass freedesktop portal and use Qt's native X11
145+
// screenshot method. Intended for WMs without xdg-desktop-portal.
146+
OPTION("useX11LegacyScreenshot" ,Bool ( false )),
147+
#endif
143148
};
144149

145150
static QMap<QString, QSharedPointer<KeySequence>> recognizedShortcuts = {

src/utils/confighandler.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ class ConfigHandler : public QObject
145145
setIgnorePrntScrForcesSnipping,
146146
bool)
147147
#endif
148+
#if defined(Q_OS_LINUX)
149+
CONFIG_GETTER_SETTER(useX11LegacyScreenshot,
150+
setUseX11LegacyScreenshot,
151+
bool)
152+
#endif
148153

149154
// SPECIAL CASES
150155
bool startupLaunch();

src/utils/screengrabber.cpp

Lines changed: 74 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,13 +205,25 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok, int preSelectedMonitor)
205205
screenshot.setDevicePixelRatio(currentScreen->devicePixelRatio());
206206
return screenshot;
207207

208-
#elif defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
209-
freeDesktopPortal(ok, screenshot);
210-
if (!ok) {
211-
AbstractLogger::error() << tr("Unable to capture screen");
212-
return QPixmap();
208+
#elif defined(Q_OS_LINUX)
209+
if (!m_info.waylandDetected() && ConfigHandler().useX11LegacyScreenshot()) {
210+
qWarning() << "Using deprecated legacy X11 screenshot method. "
211+
"Consider installing xdg-desktop-portal for your "
212+
"desktop. Future versions of Flameshot may remove the "
213+
"option to use the legacy method.";
214+
screenshot = x11LegacyScreenshot();
215+
ok = !screenshot.isNull();
216+
if (!ok) {
217+
AbstractLogger::error() << tr("Unable to capture screen");
218+
return QPixmap();
219+
}
220+
} else {
221+
freeDesktopPortal(ok, screenshot);
222+
if (!ok) {
223+
AbstractLogger::error() << tr("Unable to capture screen");
224+
return QPixmap();
225+
}
213226
}
214-
215227
#elif defined(Q_OS_WIN)
216228
screenshot = windowsScreenshot(wid);
217229
#endif
@@ -256,10 +268,21 @@ QPixmap ScreenGrabber::grabFullDesktop(bool& ok)
256268
painter.drawPixmap(offset, p);
257269
}
258270
painter.end();
259-
#elif defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
260-
freeDesktopPortal(ok, screenshot);
261-
if (!ok) {
262-
AbstractLogger::error() << tr("Unable to capture screen");
271+
#elif defined(Q_OS_LINUX)
272+
if (!m_info.waylandDetected() && ConfigHandler().useX11LegacyScreenshot()) {
273+
qWarning() << "Using deprecated legacy X11 screenshot method. "
274+
"Consider installing xdg-desktop-portal for your "
275+
"desktop.";
276+
screenshot = x11LegacyScreenshot();
277+
ok = !screenshot.isNull();
278+
if (!ok) {
279+
AbstractLogger::error() << tr("Unable to capture screen");
280+
}
281+
} else {
282+
freeDesktopPortal(ok, screenshot);
283+
if (!ok) {
284+
AbstractLogger::error() << tr("Unable to capture screen");
285+
}
263286
}
264287
#elif defined(Q_OS_WIN)
265288
screenshot = windowsScreenshot(0);
@@ -629,3 +652,44 @@ QPixmap ScreenGrabber::windowsScreenshot(int wid)
629652

630653
return desktop;
631654
}
655+
656+
QPixmap ScreenGrabber::x11LegacyScreenshot()
657+
{
658+
const QList<QScreen*> screens = QGuiApplication::screens();
659+
660+
if (screens.isEmpty()) {
661+
return QPixmap();
662+
}
663+
664+
if (screens.size() == 1) {
665+
QScreen* screen = screens.first();
666+
QPixmap p = screen->grabWindow(0);
667+
p.setDevicePixelRatio(screen->devicePixelRatio());
668+
return p;
669+
}
670+
671+
// Composite all screens using logical geometry.
672+
// On i3 (tested) DPR is uniform so we don't need the per-screen
673+
// physical pixel math that the Windows backend does. Not sure if this is
674+
// true for other DE's like xmonad.
675+
QRect totalGeom;
676+
for (QScreen* s : screens) {
677+
totalGeom = totalGeom.united(s->geometry());
678+
}
679+
680+
qreal dpr = screens.first()->devicePixelRatio();
681+
QPixmap desktop(qRound(totalGeom.width() * dpr),
682+
qRound(totalGeom.height() * dpr));
683+
desktop.setDevicePixelRatio(dpr);
684+
desktop.fill(Qt::black);
685+
686+
QPainter painter(&desktop);
687+
for (QScreen* s : screens) {
688+
QPixmap p = s->grabWindow(0);
689+
QPoint offset = s->geometry().topLeft() - totalGeom.topLeft();
690+
painter.drawPixmap(offset, p);
691+
}
692+
painter.end();
693+
694+
return desktop;
695+
}

src/utils/screengrabber.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class ScreenGrabber : public QObject
3838
QWidget* createMonitorPreviews(const QPixmap& fullScreenshot);
3939
QPixmap cropToMonitor(const QPixmap& fullScreenshot, int monitorIndex);
4040
QPixmap windowsScreenshot(int wid);
41+
QPixmap x11LegacyScreenshot();
4142

4243
DesktopInfo m_info;
4344
QPixmap Screenshot;

0 commit comments

Comments
 (0)