From 8006d79d5d7ec8d7aa2069f69e87aad25ff6a185 Mon Sep 17 00:00:00 2001 From: El Thoro Date: Mon, 11 Aug 2025 22:36:39 +0200 Subject: [PATCH 1/2] Appimage build (fix for #4112) (#4146) --- .github/workflows/Linux-pack.yml | 245 ++++++++++++++----------------- 1 file changed, 113 insertions(+), 132 deletions(-) diff --git a/.github/workflows/Linux-pack.yml b/.github/workflows/Linux-pack.yml index 9c202274eb..c3ad399a62 100644 --- a/.github/workflows/Linux-pack.yml +++ b/.github/workflows/Linux-pack.yml @@ -253,138 +253,119 @@ jobs: ${{ github.workspace }}/build/${{ env.PRODUCT }}-*-lp${{ matrix.dist.symbol }}.${{ matrix.dist.arch }}.rpm.sha256sum overwrite: true -# appimage-pack: -# name: Build appimage on ${{ matrix.config.name }} -# runs-on: ubuntu-latest -# strategy: -# fail-fast: false -# matrix: -# config: -# - { -# name: ubuntu-22.04, -# os: ubuntu, -# symbol: jammy, -# arch: amd64, -# image_repo: quay.io/flameshot-org/ci-building -# } -# container: -# image: ${{ matrix.config.image_repo }}:${{ matrix.config.os }}-${{ matrix.config.symbol }} -# options: --cap-add SYS_ADMIN --device /dev/fuse --security-opt apparmor:unconfined -# steps: -# - name: -# shell: bash -# run: | -# git config --global --add safe.directory "$GITHUB_WORKSPACE" -# -# - name: Checkout Source code -# if: github.event_name == 'push' -# uses: actions/checkout@v4 -# with: -# fetch-depth: 0 -# ref: master -# - name: Checkout Source code -# if: github.event_name == 'pull_request' -# uses: actions/checkout@v4 -# with: -# fetch-depth: 0 -# ref: ${{ github.event.pull_request.head.sha }} -# - name: Set env & Print flameshot version -# shell: bash -# run: | -# last_committed_tag=$(git tag -l --sort=-v:refname | head -1) -# git_revno=$(git rev-list $(git describe --tags --abbrev=0)..HEAD --count) -# git_hash=$(git rev-parse --short HEAD) -# ver_info=${last_committed_tag}+git${git_revno}.${git_hash} -# echo "=======FLAMESHOT VERSION========" -# echo ${last_committed_tag:1} -# echo "Details: ${ver_info}" -# echo "================================" -# echo "VERSION=${last_committed_tag:1}" >> $GITHUB_ENV -# echo "VER_INFO=${ver_info}" >> $GITHUB_ENV -# - name: Install Dependencies -# run: | -# sudo apt-get -y -qq update -# sudo apt-get -y --no-install-recommends install \ -# python3 \ -# python3-pip \ -# fuse \ -# patchelf \ -# cmake \ -# extra-cmake-modules \ -# build-essential \ -# qt5-qmake \ -# qtbase5-dev \ -# qtbase5-dev-tools \ -# qttools5-dev-tools \ -# qttools5-dev \ -# libqt5dbus5 \ -# libqt5network5 \ -# libqt5core5a \ -# libqt5widgets5 \ -# libqt5gui5 \ -# libqt5svg5-dev \ -# appstream \ -# hicolor-icon-theme \ -# fcitx-frontend-qt5 \ -# openssl \ -# ca-certificates \ -# jq -# -# - name: Get go-appimage tool -# # Will not use linuxdeployqt anymore, because it suopprts currently still-supported mainstream distribution, -# # which is glibc 2.23. For more information, please see https://github.com/probonopd/linuxdeployqt/issues/340. -# # Will try new tool https://github.com/probonopd/go-appimage written in golang by probonopd. -# run: | -# wget $(curl https://api.github.com/repos/probonopd/go-appimage/releases | jq -r '.[] | select(.tag_name == "continuous") | .assets[] | select((.name | endswith("x86_64.AppImage")) and (.name | contains("appimagetool"))) | .browser_download_url') -O appimagetool -# -# chmod +x appimagetool -# env: -# APPIMAGETOOL_ARCH: x86_64 -# - name: Packaging appimage -# run: | -# set -x -# APPIMAGE_DST_PATH=$GITHUB_WORKSPACE/${PRODUCT}.AppDir -# mkdir -p ${APPIMAGE_DST_PATH} -# -# cd $GITHUB_WORKSPACE -# cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DUSE_LAUNCHER_ABSOLUTE_PATH:BOOL=OFF -# make -j$(nproc) DESTDIR=${APPIMAGE_DST_PATH} install -# -# $GITHUB_WORKSPACE/appimagetool -s deploy "${APPIMAGE_DST_PATH}/usr/share/applications/org.flameshot.Flameshot.desktop" -# -# mkdir -p ${APPIMAGE_DST_PATH}/usr/plugins/platforminputcontexts -# cp \ -# /usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin.so \ -# ${APPIMAGE_DST_PATH}/usr/plugins/platforminputcontexts/ -# -# cp \ -# $GITHUB_WORKSPACE/data/img/app/org.flameshot.Flameshot.png \ -# ${APPIMAGE_DST_PATH}/ -# -# if [ -f "${APPIMAGE_DST_PATH}/lib/x86_64-linux-gnu/libxcb-glx.so.0" ]; then -# rm ${APPIMAGE_DST_PATH}/lib/x86_64-linux-gnu/libxcb-glx.so.0 -# fi -# -# chmod +x ${APPIMAGE_DST_PATH}/usr/lib64/ld-*.so.* -# -# -# VERSION=${VERSION} $GITHUB_WORKSPACE/appimagetool "${APPIMAGE_DST_PATH}" -# mv $GITHUB_WORKSPACE/Flameshot-${VERSION}-x86_64.AppImage $GITHUB_WORKSPACE/Flameshot-${VERSION}.x86_64.AppImage -# -# -# - name: SHA256Sum of appimage package -# run: | -# cd "$GITHUB_WORKSPACE/" || { >&2 echo "Cannot cd to '$GITHUB_WORKSPACE/'!"; exit 11 ; } -# sha256sum Flameshot-${VERSION}.x86_64.AppImage | tee Flameshot-${VERSION}.x86_64.AppImage.sha256sum -# - name: Artifact Upload -# uses: actions/upload-artifact@v4 -# with: -# name: ${{ env.PRODUCT }}-${{ env.VER_INFO }}-artifact-appimage-x86_64 -# path: | -# ${{ github.workspace }}/Flameshot-*.x86_64.AppImage -# ${{ github.workspace }}/Flameshot-*.x86_64.AppImage.sha256sum -# overwrite: true -# + appimage-pack: + name: Build appimage on ${{ matrix.config.name }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + config: + - { + name: ubuntu-22.04, + os: ubuntu, + symbol: jammy, + arch: amd64, + image_repo: quay.io/flameshot-org/ci-building + } + container: + image: ${{ matrix.config.image_repo }}:${{ matrix.config.os }}-${{ matrix.config.symbol }} + options: --cap-add SYS_ADMIN --device /dev/fuse --security-opt apparmor:unconfined + steps: + - name: Configure git safe directory + shell: bash + run: | + git config --global --add safe.directory "$GITHUB_WORKSPACE" + + - name: Checkout Source code + if: github.event_name == 'push' + uses: actions/checkout@v4 + with: + fetch-depth: 0 +# ref: master + + - name: Checkout Source code + if: github.event_name == 'pull_request' + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + + - name: Checkout Source code + if: github.event_name == 'workflow_dispatch' + uses: actions/checkout@v4 + with: + ref: ${{ github.sha }} + + - name: Set env & Print flameshot version + shell: bash + run: | + last_committed_tag=$(git tag -l --sort=-v:refname | head -1) + git_revno=$(git rev-list $(git describe --tags --abbrev=0)..HEAD --count) + git_hash=$(git rev-parse --short HEAD) + ver_info=${last_committed_tag}+git${git_revno}.${git_hash} + echo "=======FLAMESHOT VERSION========" + echo ${last_committed_tag:1} + echo "Details: ${ver_info}" + echo "================================" + # This will allow to build pre-preleases without git tag + # echo "VERSION=${last_committed_tag:1}" >> $GITHUB_ENV + echo "VERSION=$(cat CMakeLists.txt |grep 'set.*(.*FLAMESHOT_VERSION' | sed 's/[^0-9.]*//' |sed 's/)//g')" >> $GITHUB_ENV + echo "VER_INFO=${ver_info}" >> $GITHUB_ENV + + - name: Install Dependencies + run: | + sudo apt-get -y -qq update + sudo apt-get -y --no-install-recommends install fuse cmake extra-cmake-modules build-essential qt6-base-dev qt6-tools-dev qt6-tools-dev-tools libqt6svg6-dev qt6-l10n-tools qt6-wayland libgl-dev appstream hicolor-icon-theme openssl ca-certificates jq + + - name: Download linuxdeploy + run: | + wget -c -nv "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage" + chmod a+x linuxdeploy-x86_64.AppImage + LINUXDEPLOY_BIN=${PWD}/linuxdeploy-x86_64.AppImage + + - name: Download linuxdeployqt-plugin-appimage + run: | + wget -c -nv "https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage" + chmod a+x linuxdeploy-plugin-appimage-x86_64.AppImage + + - name: Download linuxdeployqt-plugin-qt + run: | + wget -c -nv "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage" + chmod a+x linuxdeploy-plugin-qt-x86_64.AppImage + + - name: Packaging appimage + run: | + set -x + APPIMAGE_DST_PATH=$GITHUB_WORKSPACE/${PRODUCT}.AppDir + mkdir -p ${APPIMAGE_DST_PATH} + + cd $GITHUB_WORKSPACE + cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DUSE_LAUNCHER_ABSOLUTE_PATH:BOOL=OFF + make -j$(nproc) DESTDIR=${APPIMAGE_DST_PATH} install + rm -rf ${APPIMAGE_DST_PATH}/usr/include + rm -rf ${APPIMAGE_DST_PATH}/usr/lib + + export EXTRA_PLATFORM_PLUGINS="libqwayland-generic.so" + export EXTRA_QT_MODULES="waylandcompositor" + export QMAKE=/usr/lib/qt6/bin/qmake + ${PWD}/linuxdeploy-x86_64.AppImage --appdir ${APPIMAGE_DST_PATH} --plugin qt --output appimage + + mv $GITHUB_WORKSPACE/Flameshot-${VERSION}-x86_64.AppImage $GITHUB_WORKSPACE/Flameshot-${VERSION}.x86_64.AppImage + + - name: SHA256Sum of appimage package + run: | + cd "$GITHUB_WORKSPACE/" || { >&2 echo "Cannot cd to '$GITHUB_WORKSPACE/'!"; exit 11 ; } + sha256sum Flameshot-${VERSION}.x86_64.AppImage | tee Flameshot-${VERSION}.x86_64.AppImage.sha256sum + + - name: Artifact Upload + uses: actions/upload-artifact@v4 + with: + name: ${{ env.PRODUCT }}-${{ env.VER_INFO }}-artifact-appimage-x86_64 + path: | + ${{ github.workspace }}/Flameshot-*.x86_64.AppImage + ${{ github.workspace }}/Flameshot-*.x86_64.AppImage.sha256sum + overwrite: true + flatpak-pack: name: Build flatpak on ubuntu 24.04 runs-on: ubuntu-24.04 From 8d8a4c94cba2ca67e1b994a5cdb10b975628b7a1 Mon Sep 17 00:00:00 2001 From: ionsquare Date: Mon, 11 Aug 2025 17:48:19 -0700 Subject: [PATCH 2/2] Fix multi monitor offset bug in Qt6 multi-monitor setups for X11 (#4127) * Fix dual monitor offset bug in Qt6 multi-monitor setups The issue was caused by using QApplication::primaryScreen() to capture the entire desktop, but in Qt6 the primary screen is not necessarily the leftmost screen. This caused coordinate system misalignment in multi-monitor setups where the primary screen is positioned to the right. Additionally, the previous approach failed in edge cases where screens have different heights and the desktop bounding box includes virtual space that doesn't correspond to any physical screen. Changes: - Replace single-screen desktop capture with composite approach - Capture each screen individually and composite them together - Position capture widget to cover entire desktop geometry - Remove devicePixelRatio division that caused coordinate issues - Handle virtual desktop space by filling with black background This solution works with any multi-monitor configuration including: - Primary screen not being leftmost - Screens with different resolutions and alignments - Bottom-aligned or top-aligned screen arrangements - Complex layouts with virtual coordinate space Fixes #4111 * Fix clang-format issue --------- Co-authored-by: ionsquare --- src/utils/screengrabber.cpp | 34 +++++++++++++++++++++------ src/widgets/capture/capturewidget.cpp | 6 ++++- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index ba8b86c922..cdbc598497 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -205,11 +205,30 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok) #endif #if defined(Q_OS_LINUX) || defined(Q_OS_UNIX) || defined(Q_OS_WIN) QRect geometry = desktopGeometry(); - QPixmap p(QApplication::primaryScreen()->grabWindow( - wid, geometry.x(), geometry.y(), geometry.width(), geometry.height())); - QScreen* screen = qApp->screenAt(QCursor::pos()); - p.setDevicePixelRatio(screen->devicePixelRatio()); - return p; + + // Qt6 fix: Create a composite image from all screens to handle + // multi-monitor setups where screens have different positions/heights. + // This fixes the dual monitor offset bug and handles edge cases where + // the desktop bounding box includes virtual space. + QPixmap desktop(geometry.size()); + desktop.fill(Qt::black); // Fill with black background + + QPainter painter(&desktop); + for (QScreen* screen : QGuiApplication::screens()) { + QRect screenGeom = screen->geometry(); + QPixmap screenCapture = screen->grabWindow( + wid, 0, 0, screenGeom.width(), screenGeom.height()); + + // Calculate position relative to desktop top-left + QPoint relativePos = screenGeom.topLeft() - geometry.topLeft(); + painter.drawPixmap(relativePos, screenCapture); + } + painter.end(); + + // Set device pixel ratio based on the primary screen + desktop.setDevicePixelRatio( + QApplication::primaryScreen()->devicePixelRatio()); + return desktop; #endif } @@ -259,8 +278,9 @@ QRect ScreenGrabber::desktopGeometry() for (QScreen* const screen : QGuiApplication::screens()) { QRect scrRect = screen->geometry(); - scrRect.moveTo(scrRect.x() / screen->devicePixelRatio(), - scrRect.y() / screen->devicePixelRatio()); + // Qt6 fix: Don't divide by devicePixelRatio for multi-monitor setups + // This was causing coordinate offset issues in dual monitor + // configurations geometry = geometry.united(scrRect); } return geometry; diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index c765801865..3426bb9716 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -155,7 +155,11 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, #if !defined(FLAMESHOT_DEBUG_CAPTURE) setWindowFlags(Qt::BypassWindowManagerHint | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::Tool); - resize(pixmap().size()); + // Fix for Qt6 dual monitor offset: position widget to cover entire + // desktop + QRect desktopGeom = ScreenGrabber().desktopGeometry(); + move(desktopGeom.topLeft()); + resize(desktopGeom.size()); #endif #endif }