diff --git a/data/man/man1/flameshot.1 b/data/man/man1/flameshot.1 index 95127275a7..90ac3a643e 100644 --- a/data/man/man1/flameshot.1 +++ b/data/man/man1/flameshot.1 @@ -131,6 +131,14 @@ Valid for subcommands: full, gui, screen .RE . .PP +\-e, \-\-edit +.RS 4 +Interactively select and edit the screenshot region +.br +Valid for subcommands: screen +.RE +. +.PP \-f, \-\-filename .RS 4 Set the filename pattern @@ -215,7 +223,7 @@ Valid for subcommands: full, gui, screen .RS 4 Screenshot region to select .br -Valid for subcommands: full, gui, screen +Valid for subcommands: gui, screen .RE . .PP @@ -234,14 +242,6 @@ Enable or disable the trayicon Valid for subcommands: config .RE . -.PP -\-u, \-\-upload -.RS 4 -Upload screenshot -.br -Valid for subcommands: full, gui, screen -.RE -. .\"---------------------------------------------------------------------------- .SH "EXAMPLE USAGE" .PP diff --git a/data/shell-completion/flameshot.bash b/data/shell-completion/flameshot.bash index 7b93433a19..5fd29c8cae 100644 --- a/data/shell-completion/flameshot.bash +++ b/data/shell-completion/flameshot.bash @@ -12,9 +12,9 @@ _flameshot() { prev="${COMP_WORDS[COMP_CWORD-1]}" cur="${COMP_WORDS[COMP_CWORD]}" cmd="gui full config launcher screen" - screen_opts="--number -n --path -p --clipboard -c --delay -d --region --raw -r --upload -u --pin --help" - gui_opts="--path -p --clipboard -c --delay -d --region --last-region --raw -r --print-geometry -g --upload -u --pin --accept-on-select -s --help" - full_opts="--path -p --clipboard -c --delay -d --region --raw -r --upload -u --help" + screen_opts="--number -n --edit -e --path -p --clipboard -c --delay -d --region --raw -r --pin --help" + gui_opts="--path -p --clipboard -c --delay -d --region --last-region --raw -r --print-geometry -g --pin --accept-on-select -s --help" + full_opts="--path -p --clipboard -c --delay -d --raw -r --help" config_opts="--autostart -a --filename -f --notifications -n --trayicon -t --showhelp -s --maincolor -m --contrastcolor -k --check" case "${prev}" in diff --git a/data/shell-completion/flameshot.fish b/data/shell-completion/flameshot.fish index 5a4605a7c3..cdaf933294 100644 --- a/data/shell-completion/flameshot.fish +++ b/data/shell-completion/flameshot.fish @@ -83,7 +83,6 @@ __flameshot_complete gui --long-option "region" --d __flameshot_complete gui --long-option "last-region" --description "Repeat screenshot with previously selected region" --no-files __flameshot_complete gui --long-option "raw" --short-option "r" --description "Print raw PNG capture" --no-files __flameshot_complete gui --long-option "print-geometry" --short-option "g" --description "Print geometry of the selection" --no-files -__flameshot_complete gui --long-option "upload" --short-option "u" --description "Upload the screenshot" --no-files __flameshot_complete gui --long-option "pin" --description "Pin the screenshot to the screen" --no-files __flameshot_complete gui --long-option "accept-on-select" --short-option "s" --description "Accept capture as soon as a selection is made" --no-files __flameshot_complete gui --long-option "help" --short-option "h" --description "Show the available arguments" --no-files @@ -91,12 +90,12 @@ __flameshot_complete gui --long-option "help" --short-option "h" --d # SCREEN subcommand __flameshot_complete screen --no-files __flameshot_complete screen --long-option "number" --short-option "n" --description "Screen number (starting from 0)" --require-parameter --no-files --arguments "(__flameshot_complete_screen_number)" +__flameshot_complete screen --long-option "edit" --short-option "e" --description "Interactively select and edit the screenshot region" --no-files __flameshot_complete screen --long-option "path" --short-option "p" --description "Output file or directory" --require-parameter __flameshot_complete screen --long-option "clipboard" --short-option "c" --description "Copy screenshot to the clipboard" --no-files __flameshot_complete screen --long-option "delay" --short-option "d" --description "Delay time in milliseconds" --require-parameter --no-files __flameshot_complete screen --long-option "region" --description "Screenshot region to select (WxH+X+Y)" --require-parameter --no-files --arguments "(__flameshot_complete_region screen)" __flameshot_complete screen --long-option "raw" --short-option "r" --description "Print raw PNG capture" --no-files -__flameshot_complete screen --long-option "upload" --short-option "u" --description "Upload the screenshot" --no-files __flameshot_complete screen --long-option "pin" --description "Pin the screenshot to the screen" --no-files __flameshot_complete screen --long-option "help" --short-option "h" --description "Show the available arguments" --no-files @@ -105,9 +104,7 @@ __flameshot_complete full --no-files __flameshot_complete full --long-option "path" --short-option "p" --description "Output file or directory" --require-parameter __flameshot_complete full --long-option "clipboard" --short-option "c" --description "Copy screenshot to the clipboard" --no-files __flameshot_complete full --long-option "delay" --short-option "d" --description "Delay time in milliseconds" --require-parameter --no-files -__flameshot_complete full --long-option "region" --description "Screenshot region to select (WxH+X+Y)" --require-parameter --no-files --arguments "(__flameshot_complete_region full)" --keep-order __flameshot_complete full --long-option "raw" --short-option "r" --description "Print raw PNG capture" --no-files -__flameshot_complete full --long-option "upload" --short-option "u" --description "Upload the screenshot" --no-files __flameshot_complete full --long-option "help" --short-option "h" --description "Show the available arguments" --no-files # LAUNCHER command diff --git a/data/shell-completion/flameshot.zsh b/data/shell-completion/flameshot.zsh index c65f4b5cdc..aaab421eb7 100644 --- a/data/shell-completion/flameshot.zsh +++ b/data/shell-completion/flameshot.zsh @@ -24,7 +24,6 @@ _flameshot_gui_opts=( "--last-region[Repeat screenshot with previously selected region]" {-r,--raw}'[Print raw PNG capture]' {-g,--print-geometry}'[Print geometry of the selection in the format WxH+X+Y. Does nothing if raw is specified]' - {-u,--upload}'[Upload screenshot]' "--pin[Pin the capture to the screen]" {-s,--accept-on-select}'[Accept capture as soon as a selection is made]' {-h,--help}'[Show the available arguments]' @@ -40,12 +39,12 @@ _flameshot_gui() { _flameshot_screen_opts=( {-n,--number}'[Define the screen to capture (starting from 0). Default: screen containing the cursor]' + {-e,--edit}'[Interactively select and edit the screenshot region]' {-p,--path}'[Existing directory or new file to save to]':dir:_files {-c,--clipboard}'[Save the capture to the clipboard]' {-d,--delay}'[Delay time in milliseconds]' "--region[Screenshot region to select ]" {-r,--raw}'[Print raw PNG capture]' - {-u,--upload}'[Upload screenshot]' "--pin[Pin the capture to the screen]" {-h,--help}'[Show the available arguments]' ) @@ -62,9 +61,7 @@ _flameshot_full_opts=( {-p,--path}'[Existing directory or new file to save to]':dir:_files {-c,--clipboard}'[Save the capture to the clipboard]' {-d,--delay}'[Delay time in milliseconds]' - "--region[Screenshot region to select ]" {-r,--raw}'[Print raw PNG capture]' - {-u,--upload}'[Upload screenshot]' {-h,--help}'[Show the available arguments]' ) diff --git a/src/core/flameshot.cpp b/src/core/flameshot.cpp index c6660518b7..8d1dfcae81 100644 --- a/src/core/flameshot.cpp +++ b/src/core/flameshot.cpp @@ -146,28 +146,40 @@ void Flameshot::screen(CaptureRequest req, const int screenNumber) return; } - bool ok = true; - QScreen* screen; + bool ok = false; + QPixmap p; + QRect geometry; if (screenNumber < 0) { - QPoint globalCursorPos = QCursor::pos(); - screen = qApp->screenAt(globalCursorPos); + ScreenGrabber grabber; + p = grabber.grabEntireDesktop(ok); + if (ok) { + QScreen* selectedScreen = grabber.getSelectedScreen(); + if (selectedScreen) { + geometry = ScreenGrabber().screenGeometry(selectedScreen); + } else { + ok = false; + } + } } else if (screenNumber >= qApp->screens().count()) { AbstractLogger() << QObject::tr( "Requested screen exceeds screen count"); - emit captureFailed(); - return; + ok = false; } else { - screen = qApp->screens()[screenNumber]; + // Specific screen number provided - use grabScreen to bypass selector + QScreen* screen = qApp->screens()[screenNumber]; + p = ScreenGrabber().grabScreen(screen, ok); + if (ok) { + geometry = ScreenGrabber().screenGeometry(screen); + } } - QPixmap p(ScreenGrabber().grabScreen(screen, ok)); + if (ok) { - QRect geometry = ScreenGrabber().screenGeometry(screen); QRect region = req.initialSelection(); if (region.isNull()) { - region = ScreenGrabber().screenGeometry(screen); + region = geometry; } else { - QRect screenGeom = ScreenGrabber().screenGeometry(screen); + QRect screenGeom = geometry; screenGeom.moveTopLeft({ 0, 0 }); region = region.intersected(screenGeom); p = p.copy(region); @@ -189,13 +201,9 @@ void Flameshot::full(const CaptureRequest& req) } bool ok = true; - QPixmap p(ScreenGrabber().grabEntireDesktop(ok)); - QRect region = req.initialSelection(); - if (!region.isNull()) { - p = p.copy(region); - } + QPixmap p(ScreenGrabber().grabFullDesktop(ok)); if (ok) { - QRect selection; // `flameshot full` does not support --selection + QRect selection; // `flameshot full` does not support region selection exportCapture(p, selection, req); } else { emit captureFailed(); diff --git a/src/main.cpp b/src/main.cpp index 3c8b01838f..9e9b52434e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -290,8 +290,6 @@ int main(int argc, char* argv[]) { "c", "clipboard" }, QObject::tr("Save the capture to the clipboard")); CommandOption pinOption("pin", QObject::tr("Pin the capture to the screen")); - CommandOption uploadOption({ "u", "upload" }, - QObject::tr("Upload screenshot")); CommandOption delayOption({ "d", "delay" }, QObject::tr("Delay time in milliseconds"), QStringLiteral("milliseconds")); @@ -345,6 +343,9 @@ int main(int argc, char* argv[]) QObject::tr("default: screen containing the cursor"), QObject::tr("Screen number"), QStringLiteral("-1")); + CommandOption editOption( + { "e", "edit" }, + QObject::tr("Interactively select and edit the screenshot region")); // Add checkers auto colorChecker = [](const QString& colorCode) -> bool { @@ -423,26 +424,21 @@ int main(int argc, char* argv[]) useLastRegionOption, rawImageOption, selectionOption, - uploadOption, pinOption, acceptOnSelectOption }, guiArgument); parser.AddOptions({ screenNumberOption, + editOption, clipboardOption, pathOption, delayOption, regionOption, rawImageOption, - uploadOption, pinOption }, screenArgument); - parser.AddOptions({ pathOption, - clipboardOption, - delayOption, - regionOption, - rawImageOption, - uploadOption }, - fullArgument); + parser.AddOptions( + { pathOption, clipboardOption, delayOption, rawImageOption }, + fullArgument); parser.AddOptions({ autostartOption, notificationOption, filenameOption, @@ -495,7 +491,6 @@ int main(int argc, char* argv[]) bool raw = parser.isSet(rawImageOption); bool printGeometry = parser.isSet(selectionOption); bool pin = parser.isSet(pinOption); - bool upload = parser.isSet(uploadOption); bool acceptOnSelect = parser.isSet(acceptOnSelectOption); CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, path); if (!region.isEmpty()) { @@ -519,13 +514,10 @@ int main(int argc, char* argv[]) if (pin) { req.addTask(CaptureRequest::PIN); } - if (upload) { - req.addTask(CaptureRequest::UPLOAD); - } if (acceptOnSelect) { req.addTask(CaptureRequest::ACCEPT_ON_SELECT); if (!clipboard && !raw && path.isEmpty() && !printGeometry && - !pin && !upload) { + !pin) { req.addSaveTask(); } } @@ -541,16 +533,10 @@ int main(int argc, char* argv[]) path = QDir(path).absolutePath(); } int delay = parser.value(delayOption).toInt(); - QString region = parser.value(regionOption); bool clipboard = parser.isSet(clipboardOption); bool raw = parser.isSet(rawImageOption); - bool upload = parser.isSet(uploadOption); - // Not a valid command CaptureRequest req(CaptureRequest::FULLSCREEN_MODE, delay); - if (!region.isEmpty()) { - req.setInitialSelection(Region().value(region).toRect()); - } if (clipboard) { req.addTask(CaptureRequest::COPY); } @@ -560,10 +546,7 @@ int main(int argc, char* argv[]) if (raw) { req.addTask(CaptureRequest::PRINT_RAW); } - if (upload) { - req.addTask(CaptureRequest::UPLOAD); - } - if (!clipboard && path.isEmpty() && !raw && !upload) { + if (!clipboard && path.isEmpty() && !raw) { req.addSaveTask(); } { @@ -587,9 +570,17 @@ int main(int argc, char* argv[]) bool clipboard = parser.isSet(clipboardOption); bool raw = parser.isSet(rawImageOption); bool pin = parser.isSet(pinOption); - bool upload = parser.isSet(uploadOption); + bool edit = parser.isSet(editOption); + + CaptureRequest req(edit ? CaptureRequest::GRAPHICAL_MODE + : CaptureRequest::SCREEN_MODE, + delay); + + // For edit mode, set the selected monitor + if (edit && screenNumber >= 0) { + req.setSelectedMonitor(screenNumber); + } - CaptureRequest req(CaptureRequest::SCREEN_MODE, delay, screenNumber); if (!region.isEmpty()) { if (region.startsWith("screen")) { AbstractLogger::error() @@ -612,11 +603,8 @@ int main(int argc, char* argv[]) if (pin) { req.addTask(CaptureRequest::PIN); } - if (upload) { - req.addTask(CaptureRequest::UPLOAD); - } - if (!clipboard && !raw && path.isEmpty() && !pin && !upload) { + if (!edit && !clipboard && !raw && path.isEmpty() && !pin) { req.addSaveTask(); } diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index d5557f6961..30b0465383 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -227,6 +228,46 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok, int preSelectedMonitor) return selectMonitorAndCrop(screenshot, ok); } +QPixmap ScreenGrabber::grabFullDesktop(bool& ok) +{ + ok = true; + QPixmap screenshot; + +#if defined(Q_OS_MACOS) + // On macOS, composite all screens into a single pixmap. + const QList screens = QGuiApplication::screens(); + QRect totalGeom; + for (QScreen* s : screens) { + totalGeom = totalGeom.united(s->geometry()); + } + qreal maxDpr = 1.0; + for (QScreen* s : screens) { + maxDpr = qMax(maxDpr, s->devicePixelRatio()); + } + screenshot = QPixmap(qRound(totalGeom.width() * maxDpr), + qRound(totalGeom.height() * maxDpr)); + screenshot.setDevicePixelRatio(maxDpr); + screenshot.fill(Qt::black); + QPainter painter(&screenshot); + for (QScreen* s : screens) { + QRect geom = s->geometry(); + QPixmap p = s->grabWindow(0); + QPoint offset = geom.topLeft() - totalGeom.topLeft(); + painter.drawPixmap(offset, p); + } + painter.end(); +#elif defined(Q_OS_LINUX) || defined(Q_OS_UNIX) + freeDesktopPortal(ok, screenshot); + if (!ok) { + AbstractLogger::error() << tr("Unable to capture screen"); + } +#elif defined(Q_OS_WIN) + screenshot = windowsScreenshot(0); +#endif + + return screenshot; +} + QRect ScreenGrabber::screenGeometry(QScreen* screen) { QRect geometry = screen->geometry(); @@ -242,15 +283,10 @@ QPixmap ScreenGrabber::grabScreen(QScreen* screen, bool& ok) QPixmap p; QRect geometry = screenGeometry(screen); #if defined(Q_OS_LINUX) - p = grabEntireDesktop(ok); - if (ok) { - // Both X11 and Wayland: Use cropToMonitor for consistent handling - // of misaligned monitors and mixed DPI - const QList screens = QGuiApplication::screens(); - int screenIndex = screens.indexOf(screen); + const QList screens = QGuiApplication::screens(); + int screenIndex = screens.indexOf(screen); - return cropToMonitor(p, screenIndex); - } + p = grabEntireDesktop(ok, screenIndex); #else ok = true; return screen->grabWindow( diff --git a/src/utils/screengrabber.h b/src/utils/screengrabber.h index d42c88c960..a546dcef47 100644 --- a/src/utils/screengrabber.h +++ b/src/utils/screengrabber.h @@ -19,6 +19,7 @@ class ScreenGrabber : public QObject public: explicit ScreenGrabber(QObject* parent = nullptr); QPixmap grabEntireDesktop(bool& ok, int preSelectedMonitor = -1); + QPixmap grabFullDesktop(bool& ok); QRect screenGeometry(QScreen* screen); QPixmap grabScreen(QScreen* screenNumber, bool& ok); void freeDesktopPortal(bool& ok, QPixmap& res);