Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windowed capture mode #1565

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions src/config/generalconf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "src/core/controller.h"
#include "src/utils/confighandler.h"
#include <QCheckBox>
#include <QComboBox>
#include <QFile>
#include <QFileDialog>
#include <QGroupBox>
Expand Down Expand Up @@ -41,6 +42,7 @@ GeneralConf::GeneralConf(QWidget* parent)
initCopyAndCloseAfterUpload();
initCopyPathAfterSave();
initUseJpgForClipboard();
initWindowMode();
initSaveAfterCopy();
inituploadHistoryMax();
initUndoLimit();
Expand Down Expand Up @@ -68,6 +70,13 @@ void GeneralConf::_updateComponents(bool allowEmptySavePath)
m_checkForUpdates->setChecked(config.checkForUpdates());
m_showStartupLaunchMessage->setChecked(config.showStartupLaunchMessage());
m_screenshotPathFixedCheck->setChecked(config.savePathFixed());
auto configWindowMode = config.windowMode();
for (int i = 0; i < m_windowMode->count(); i++) {
if (m_windowMode->itemData(i) == configWindowMode) {
m_windowMode->setCurrentIndex(i);
break;
}
}
m_uploadHistoryMax->setValue(config.uploadHistoryMax());
m_undoLimit->setValue(config.undoLimit());

Expand Down Expand Up @@ -463,6 +472,44 @@ void GeneralConf::initUseJpgForClipboard()
&GeneralConf::useJpgForClipboardChanged);
}

void GeneralConf::initWindowMode()
{
m_windowMode = new QComboBox(this);
m_layout->addWidget(m_windowMode);
struct
{
QString label;
CaptureConfig::CaptureWindowMode mode;
} modes[] = {
#if !defined(Q_OS_MACOS)
{ tr("All screens"), CaptureConfig::CaptureWindowMode::FullScreenAll },
#endif
{ tr("Current screen"),
CaptureConfig::CaptureWindowMode::FullScreenCurrent },
{ tr("Maximized window"),
CaptureConfig::CaptureWindowMode::MaximizeWindow },
{ tr("Debug window"),
CaptureConfig::CaptureWindowMode::DebugNonFullScreen },
};
for (auto& item : modes) {
m_windowMode->addItem(item.label, item.mode);
}
connect(m_windowMode,
QOverload<int>::of(&QComboBox::currentIndexChanged),
this,
&GeneralConf::windowModeChanged);
}

void GeneralConf::windowModeChanged()
{
auto selectedData = m_windowMode->currentData();
if (selectedData.canConvert<CaptureConfig::CaptureWindowMode>()) {
auto selectedMode =
selectedData.value<CaptureConfig::CaptureWindowMode>();
ConfigHandler().setWindowMode(selectedMode);
}
}

void GeneralConf::saveAfterCopyChanged(bool checked)
{
ConfigHandler().setSaveAfterCopy(checked);
Expand Down
4 changes: 4 additions & 0 deletions src/config/generalconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class QPushButton;
class QLabel;
class QLineEdit;
class QSpinBox;
class QComboBox;

class GeneralConf : public QWidget
{
Expand Down Expand Up @@ -39,6 +40,7 @@ private slots:
void resetConfiguration();
void togglePathFixed();
void useJpgForClipboardChanged(bool checked);
void windowModeChanged();

private:
const QString chooseFolder(const QString currentPath = "");
Expand All @@ -59,6 +61,7 @@ private slots:
void initSaveAfterCopy();
void initCopyPathAfterSave();
void initUseJpgForClipboard();
void initWindowMode();

void _updateComponents(bool allowEmptySavePath);

Expand All @@ -84,6 +87,7 @@ private slots:
QCheckBox* m_screenshotPathFixedCheck;
QCheckBox* m_historyConfirmationToDelete;
QCheckBox* m_useJpgForClipboard;
QComboBox* m_windowMode;
QSpinBox* m_uploadHistoryMax;
QSpinBox* m_undoLimit;
};
15 changes: 3 additions & 12 deletions src/core/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ void Controller::startVisualCapture(const uint id,
return;
}

m_captureWindow = new CaptureWidget(id, forcedSavePath);
m_captureWindow = new CaptureWidget(id, forcedSavePath, ConfigHandler().windowMode());
// m_captureWindow = new CaptureWidget(id, forcedSavePath, false); //
// debug
connect(m_captureWindow,
Expand All @@ -297,17 +297,8 @@ void Controller::startVisualCapture(const uint id,
this,
&Controller::captureTaken);

#ifdef Q_OS_WIN
m_captureWindow->show();
#elif defined(Q_OS_MACOS)
// In "Emulate fullscreen mode"
m_captureWindow->showFullScreen();
m_captureWindow->activateWindow();
m_captureWindow->raise();
#else
m_captureWindow->showFullScreen();
// m_captureWindow->show(); // For CaptureWidget Debugging under Linux
#endif
m_captureWindow->OpenAndShow();

if (!m_appLatestUrl.isEmpty() &&
ConfigHandler().ignoreUpdateToVersion().compare(
m_appLatestVersion) < 0) {
Expand Down
34 changes: 33 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,35 @@ void wayland_hacks()
{
// Workaround to https://github.com/ksnip/ksnip/issues/416
DesktopInfo info;
if (info.windowManager() == DesktopInfo::GNOME) {
if (info.windowManager() == DesktopInfo::GNOME /*&&
QT_VERSION < QT_VERSION_CHECK(5, 15, 2)*/) {
qputenv("QT_QPA_PLATFORM", "xcb");
}
}
#endif

#ifdef Q_OS_WIN
void windowsHighDPIHack()
{
// On Windows when main screen is set to highDPI one or there is only highDPI screen
// the default font size gets set incorectly.
//
// Likely related to https://bugreports.qt.io/browse/QTBUG-58610 and
// https://codereview.qt-project.org/c/qt/qtbase/+/264388
// Seems to be fixed in Qt6. In a test app it reported default
// font size as ~8 regardless of which screen was chosen as main one.

#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QFont font;
font.resolve();
if (font.pointSizeF() < 8 || font.pointSizeF() > 9.5) {
font.setPointSizeF(8);
QApplication::setFont(font);
}
#endif
}
#endif

int main(int argc, char* argv[])
{
#ifdef Q_OS_LINUX
Expand All @@ -63,6 +86,12 @@ int main(int argc, char* argv[])
spdlog::set_level(spdlog::level::debug); // Set global log level to debug
spdlog::set_pattern("[source %s] [function %!] [line %#] %v");

// Configure high DPi scaling, must be done before creating application
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);

// required for the button serialization
// TODO: change to QVector in v1.0
qRegisterMetaTypeStreamOperators<QList<int>>("QList<int>");
Expand All @@ -76,6 +105,9 @@ int main(int argc, char* argv[])
QtSingleApplication app(argc, argv);
#endif
QApplication::setStyle(new StyleOverride);
#ifdef Q_OS_WIN
windowsHighDPIHack();
#endif

QTranslator translator, qtTranslator;
QStringList trPaths = PathInfo::translationsPaths();
Expand Down
24 changes: 24 additions & 0 deletions src/utils/confighandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
#include <QStandardPaths>
#include <QTextStream>
#include <QVector>
#include <QMetaEnum>
#include <algorithm>
#include <stdexcept>
#if defined(Q_OS_MACOS)
#include <QProcess>
#endif
Expand Down Expand Up @@ -111,6 +113,7 @@ static QMap<class QString, QSharedPointer<ValueHandler>>
OPTION("keepOpenAppLauncher" ,Bool ( false )),
OPTION("fontFamily" ,String ( "" )),
OPTION("setSaveAsFileExtension" ,String ( "" )),
OPTION("windowMode" ,String ( "" )),
};

static QMap<QString, QSharedPointer<KeySequence>> recognizedShortcuts = {
Expand Down Expand Up @@ -312,6 +315,27 @@ void ConfigHandler::setAllTheButtons()
setValue(QStringLiteral("buttons"), QVariant::fromValue(buttons));
}

CaptureConfig::CaptureWindowMode ConfigHandler::windowMode()
{
auto modeEnum = QMetaEnum::fromType<CaptureConfig::CaptureWindowMode>();
auto modeString = m_settings.value("windowMode", "").toString().toUtf8();
bool ok = false;
CaptureConfig::CaptureWindowMode result = static_cast<CaptureConfig::CaptureWindowMode>(modeEnum.keyToValue(modeString.constData(), &ok));
if (ok) {
return result;
}
#if defined(Q_OS_MACOS)
return CaptureConfig::CaptureWindowMode::FullScreenCurrent;
#endif
return CaptureConfig::CaptureWindowMode::FullScreenAll;
}

void ConfigHandler::setWindowMode(CaptureConfig::CaptureWindowMode mode)
{
auto modeEnum = QMetaEnum::fromType<CaptureConfig::CaptureWindowMode>();
m_settings.setValue("windowMode", modeEnum.valueToKey(static_cast<int>(mode)));
}

// DEFAULTS

QString ConfigHandler::filenamePatternDefault()
Expand Down
3 changes: 3 additions & 0 deletions src/utils/confighandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include "src/widgets/capture/capturetoolbutton.h"
#include "src/widgets/capture/captureconfig.h"
#include <QSettings>
#include <QStringList>
#include <QVariant>
Expand Down Expand Up @@ -101,6 +102,8 @@ class ConfigHandler : public QObject
QString saveAsFileExtension();
CONFIG_SETTER(setSaveAsFileExtension, setSaveAsFileExtension, QString)
void setAllTheButtons();
CaptureConfig::CaptureWindowMode windowMode();
void setWindowMode(CaptureConfig::CaptureWindowMode);

// DEFAULTS
QString filenamePatternDefault();
Expand Down
59 changes: 50 additions & 9 deletions src/utils/screengrabber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <QGuiApplication>
#include <QPixmap>
#include <QScreen>
#include <algorithm>

#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
#include "request.h"
Expand Down Expand Up @@ -148,12 +149,29 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok)
QRect geometry;
for (QScreen* const screen : QGuiApplication::screens()) {
QRect scrRect = screen->geometry();
#ifdef Q_OS_WIN
// On Win10 21H1 with Qt 5.15.2 positions are correct as the bitmap in
// memory without any scaling but each size is multiplied by device
// pixel ratio
scrRect.setSize(scrRect.size() * screen->devicePixelRatio());
geometry = geometry.united(scrRect);
#else
// this likely wrong for other os as well, but so far windows was tested
scrRect.moveTo(scrRect.x() / screen->devicePixelRatio(),
scrRect.y() / screen->devicePixelRatio());
geometry = geometry.united(scrRect);
#endif
}

QPixmap p(QApplication::primaryScreen()->grabWindow(
auto primaryScreen = QApplication::primaryScreen();
#ifdef Q_OS_WIN
// The roundtrip pixelDimensions->int(pixelDimensions / pixelRatio) -> pixelDimensions in capturedImage
// is potentially lossy, but that's how GrabWindow expects the dimensions.
geometry.setSize(geometry.size() / primaryScreen->devicePixelRatio());
geometry.moveTopLeft(geometry.topLeft() /
primaryScreen->devicePixelRatio());
#endif
QPixmap p(primaryScreen->grabWindow(
QApplication::desktop()->winId(),
geometry.x(),
geometry.y(),
Expand All @@ -166,36 +184,59 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok)
#endif
}

QPixmap ScreenGrabber::grabScreen(bool& ok)
{
return grabScreen(QGuiAppCurrentScreen().currentScreen(), ok);
}

QPixmap ScreenGrabber::grabScreen(int screenNumber, bool& ok)
{
auto screens = QGuiApplication::screens();
QScreen* screen = screens.value(screenNumber, QApplication::primaryScreen());
return grabScreen(screen, ok);
}

QPixmap ScreenGrabber::grabScreen(QScreen* captureScreen, bool& ok)
{
QPixmap p;
#ifdef Q_OS_WIN
{
QScreen* currentScreen = captureScreen;
auto platformScreen = currentScreen->handle();
// Pass 0 as window id so that qt adds the corresponding screen offset internally
// after conversion to actual pixel coordinates. That way reducing chance of
// rounding errors when making pixelRatio calculations and converting to integers.
p = captureScreen->grabWindow(0, 0, 0, captureScreen->size().width(), captureScreen->size().height());
ok = true;
return p;
}
#else
bool isVirtual = QApplication::desktop()->isVirtualDesktop();
if (isVirtual || m_info.waylandDetected()) {
p = grabEntireDesktop(ok);
if (ok) {
QPoint topLeft(0, 0);
QRect geometry = captureScreen->geometry();
#ifdef Q_OS_WIN
for (QScreen* const screen : QGuiApplication::screens()) {
QPoint topLeftScreen = screen->geometry().topLeft();
if (topLeft.x() > topLeftScreen.x() ||
topLeft.y() > topLeftScreen.y()) {
topLeft = topLeftScreen;
}
topLeft.setX(qMin(topLeft.x(), topLeftScreen.x()));
topLeft.setY(qMin(topLeft.y(), topLeftScreen.y()));
}
geometry.setSize(geometry.size() * captureScreen->devicePixelRatio());
geometry.translate(-topLeft);
#endif
QRect geometry =
QApplication::desktop()->screenGeometry(screenNumber);
geometry.moveTo(geometry.topLeft() - topLeft);
p = p.copy(geometry);
}
} else {
QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen();
p = currentScreen->grabWindow(screenNumber,
p = currentScreen->grabWindow(QApplication::desktop()->winId(),
currentScreen->geometry().x(),
currentScreen->geometry().y(),
currentScreen->geometry().width(),
currentScreen->geometry().height());
ok = true;
}
return p;
#endif
}
3 changes: 3 additions & 0 deletions src/utils/screengrabber.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@

#include "src/utils/desktopinfo.h"
#include <QObject>
#include <QScreen>

class ScreenGrabber : public QObject
{
Q_OBJECT
public:
explicit ScreenGrabber(QObject* parent = nullptr);
QPixmap grabEntireDesktop(bool& ok);
QPixmap grabScreen(QScreen* screen, bool& ok);
QPixmap grabScreen(int screenNumber, bool& ok);
QPixmap grabScreen(bool& ok);

private:
DesktopInfo m_info;
Expand Down
1 change: 1 addition & 0 deletions src/widgets/capture/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ target_sources(
PRIVATE buttonhandler.h
capturebutton.h
capturetoolbutton.h
captureconfig.h
capturewidget.h
colorpicker.h
hovereventfilter.h
Expand Down
Loading