Skip to content

Commit

Permalink
Merge pull request #1642 from contour-terminal/features/make_screenshot
Browse files Browse the repository at this point in the history
Implement SaveScreenshot and CopyScreenshot action
  • Loading branch information
Yaraslaut authored Oct 24, 2024
2 parents 7d9ea8a + 1287daf commit 100902d
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 9 deletions.
1 change: 1 addition & 0 deletions metainfo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
<ul>
<li>Expose current profile's name through env var `CONTOUR_PROFILE` (#1637)</li>
<li>Add terminal tabs (#90)</li>
<li>Add `SaveScreenshot` and `CopyScreenshot` action (#210)</li>
<li>Add binding to exit normal mode with `Esc` (#1604)</li>
<li>Add config option to switch into insert mode after yank (#1604)</li>
<li>Improves window size/resize handling on HiDPI monitor settings (#1628)</li>
Expand Down
2 changes: 2 additions & 0 deletions src/contour/Actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ optional<Action> fromString(string const& name)
mapAction<actions::ResetConfig>("ResetConfig"),
mapAction<actions::ResetFontSize>("ResetFontSize"),
mapAction<actions::ScreenshotVT>("ScreenshotVT"),
mapAction<actions::SaveScreenshot>("SaveScreenshot"),
mapAction<actions::CopyScreenshot>("CopyScreenshot"),
mapAction<actions::ScrollDown>("ScrollDown"),
mapAction<actions::ScrollMarkDown>("ScrollMarkDown"),
mapAction<actions::ScrollMarkUp>("ScrollMarkUp"),
Expand Down
14 changes: 14 additions & 0 deletions src/contour/Actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ struct ReloadConfig{ std::optional<std::string> profileName; };
struct ResetConfig{};
struct ResetFontSize{};
struct ScreenshotVT{};
struct SaveScreenshot{};
struct CopyScreenshot{};
struct ScrollDown{};
struct ScrollMarkDown{};
struct ScrollMarkUp{};
Expand Down Expand Up @@ -110,6 +112,8 @@ using Action = std::variant<CancelSelection,
ResetConfig,
ResetFontSize,
ScreenshotVT,
SaveScreenshot,
CopyScreenshot,
ScrollDown,
ScrollMarkDown,
ScrollMarkUp,
Expand Down Expand Up @@ -201,6 +205,10 @@ namespace documentation
"Resets font size to what is configured in the config file."
};
constexpr inline std::string_view ScreenshotVT { "Takes a screenshot in form of VT escape sequences." };
constexpr inline std::string_view SaveScreenshot { "Takes a screenshot and saves it into a file." };
constexpr inline std::string_view CopyScreenshot {
"takes a screenshot and puts it into the system clipboard"
};
constexpr inline std::string_view ScrollDown { "Scrolls down by the multiplier factor." };
constexpr inline std::string_view ScrollMarkDown {
"Scrolls one mark down (if none present, bottom of the screen)"
Expand Down Expand Up @@ -285,6 +293,8 @@ inline auto getDocumentation()
std::tuple { Action { ResetConfig {} }, documentation::ResetConfig },
std::tuple { Action { ResetFontSize {} }, documentation::ResetFontSize },
std::tuple { Action { ScreenshotVT {} }, documentation::ScreenshotVT },
std::tuple { Action { SaveScreenshot {} }, documentation::SaveScreenshot },
std::tuple { Action { CopyScreenshot {} }, documentation::CopyScreenshot },
std::tuple { Action { ScrollDown {} }, documentation::ScrollDown },
std::tuple { Action { ScrollMarkDown {} }, documentation::ScrollMarkDown },
std::tuple { Action { ScrollMarkUp {} }, documentation::ScrollMarkUp },
Expand Down Expand Up @@ -356,6 +366,8 @@ DECLARE_ACTION_FMT(ReloadConfig)
DECLARE_ACTION_FMT(ResetConfig)
DECLARE_ACTION_FMT(ResetFontSize)
DECLARE_ACTION_FMT(ScreenshotVT)
DECLARE_ACTION_FMT(SaveScreenshot)
DECLARE_ACTION_FMT(CopyScreenshot)
DECLARE_ACTION_FMT(ScrollDown)
DECLARE_ACTION_FMT(ScrollMarkDown)
DECLARE_ACTION_FMT(ScrollMarkUp)
Expand Down Expand Up @@ -433,6 +445,8 @@ struct std::formatter<contour::actions::Action>: std::formatter<std::string>
HANDLE_ACTION(ResetConfig);
HANDLE_ACTION(ResetFontSize);
HANDLE_ACTION(ScreenshotVT);
HANDLE_ACTION(CopyScreenshot);
HANDLE_ACTION(SaveScreenshot);
HANDLE_ACTION(ScrollDown);
HANDLE_ACTION(ScrollMarkDown);
HANDLE_ACTION(ScrollMarkUp);
Expand Down
2 changes: 2 additions & 0 deletions src/contour/ConfigDocumentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,8 @@ constexpr StringLiteral InputMappingsConfig {
"it. Attention, all your current configuration will be lost due to overwrite!\n"
"{comment} - ResetFontSize Resets font size to what is configured in the config file.\n"
"{comment} - ScreenshotVT Takes a screenshot in form of VT escape sequences.\n"
"{comment} - SaveScreenshot Takes a screenshot and saves it into a file.\n"
"{comment} - CopyScreenshot Takes a screenshot and puts it into the system clipboard\n"
"{comment} - ScrollDown Scrolls down by the multiplier factor.\n"
"{comment} - ScrollMarkDown Scrolls one mark down (if none present, bottom of the screen)\n"
"{comment} - ScrollMarkUp Scrolls one mark up\n"
Expand Down
28 changes: 28 additions & 0 deletions src/contour/TerminalSession.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
#include <contour/Actions.h>
#include <contour/ContourGuiApp.h>
#include <contour/TerminalSession.h>
#include <contour/display/TerminalDisplay.h>
Expand Down Expand Up @@ -1184,6 +1185,33 @@ bool TerminalSession::operator()(actions::ScreenshotVT)
return true;
}

bool TerminalSession::operator()(actions::SaveScreenshot)
{
auto savePath =
app().dumpStateAtExit().value_or(crispy::app::instance()->localStateDir())
/ fs::path(std::format("contour-screenshot-{:%Y-%m-%d-%H-%M-%S}.png", chrono::system_clock::now()));

_display->setScreenshotOutput(savePath);
auto message = std::format("Saving screenshot to {}", savePath.string());
sessionLog()(message);

_display->post(
[this, message]() { emit showNotification("Screenshot", QString::fromStdString(message)); });
return true;
}

bool TerminalSession::operator()(actions::CopyScreenshot)
{
_display->setScreenshotOutput(std::monostate {});
auto message = std::format("Saving screenshot to clipboard");
sessionLog()(message);

_display->post(
[this, message]() { emit showNotification("Screenshot", QString::fromStdString(message)); });

return true;
}

bool TerminalSession::operator()(actions::ScrollDown)
{
terminal().viewport().scrollDown(_profile.history.value().historyScrollMultiplier);
Expand Down
2 changes: 2 additions & 0 deletions src/contour/TerminalSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ class TerminalSession: public QAbstractItemModel, public vtbackend::Terminal::Ev
bool operator()(actions::ResetConfig);
bool operator()(actions::ResetFontSize);
bool operator()(actions::ScreenshotVT);
bool operator()(actions::CopyScreenshot);
bool operator()(actions::SaveScreenshot);
bool operator()(actions::ScrollDown);
bool operator()(actions::ScrollMarkDown);
bool operator()(actions::ScrollMarkUp);
Expand Down
32 changes: 28 additions & 4 deletions src/contour/display/TerminalDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <fstream>
#include <string_view>
#include <tuple>
#include <variant>
#include <vector>

namespace fs = std::filesystem;
Expand Down Expand Up @@ -736,6 +737,20 @@ void TerminalDisplay::onAfterRendering()
// We use this to schedule the next rendering frame, if needed.
// This signal is emitted from the scene graph rendering thread
paint();
if (_saveScreenshot)
{
std::visit(crispy::overloaded { [&](const std::filesystem::path& path) {
screenshot().save(QString::fromStdString(path.string()));
},
[&](std::monostate) {
if (QClipboard* clipboard = QGuiApplication::clipboard();
clipboard != nullptr)
clipboard->setImage(screenshot(), QClipboard::Clipboard);
} },
_saveScreenshot.value());

_saveScreenshot = std::nullopt;
}

if (!_state.finish())
{
Expand Down Expand Up @@ -1092,6 +1107,18 @@ void TerminalDisplay::doDumpState()
_doDumpState = true;
}

QImage TerminalDisplay::screenshot()
{
_renderer->render(terminal(), _renderingPressure);
auto [size, image] = _renderTarget->takeScreenshot();

return QImage(image.data(),
size.width.as<int>(),
size.height.as<int>(),
QImage::Format_RGBA8888_Premultiplied)
.mirrored(false, true);
}

void TerminalDisplay::doDumpStateInternal()
{

Expand Down Expand Up @@ -1178,10 +1205,7 @@ void TerminalDisplay::doDumpStateInternal()

auto screenshotFilePath = targetDir / "screenshot.png";
displayLog()("Saving screenshot to: {}", screenshotFilePath.generic_string());
auto [size, image] = _renderTarget->takeScreenshot();
QImage(image.data(), size.width.as<int>(), size.height.as<int>(), QImage::Format_RGBA8888_Premultiplied)
.mirrored(false, true)
.save(QString::fromStdString(screenshotFilePath.string()));
screenshot().save(QString::fromStdString(screenshotFilePath.string()));
}

void TerminalDisplay::notify(std::string_view /*_title*/, std::string_view /*_body*/)
Expand Down
13 changes: 8 additions & 5 deletions src/contour/display/TerminalDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@
#include <QtGui/QOpenGLExtraFunctions>
#include <QtGui/QVector4D>
#include <QtMultimedia/QMediaPlayer>
#include <QtQml/QtQml>
#include <QtQuick/QQuickItem>

#include <QtQml>

#include <filesystem>
#include <memory>
#include <optional>
#include <variant>
#if defined(CONTOUR_PERF_STATS)
#include <atomic>
#endif

#include <memory>
#include <optional>

namespace contour::display
{

Expand Down Expand Up @@ -151,6 +151,7 @@ class TerminalDisplay: public QQuickItem
void onSelectionCompleted();
void bufferChanged(vtbackend::ScreenType);
void discardImage(vtbackend::Image const&);
void setScreenshotOutput(auto&& where) { _saveScreenshot = std::forward<decltype(where)>(where); }
// }}}

[[nodiscard]] std::optional<double> queryContentScaleOverride() const;
Expand Down Expand Up @@ -220,6 +221,7 @@ class TerminalDisplay: public QQuickItem
// helper methods
//
void doDumpStateInternal();
QImage screenshot();
void createRenderer();
[[nodiscard]] QMatrix4x4 createModelMatrix() const;
void configureScreenHooks();
Expand Down Expand Up @@ -274,6 +276,7 @@ class TerminalDisplay: public QQuickItem

RenderStateManager _state;
bool _doDumpState = false;
std::optional<std::variant<std::filesystem::path, std::monostate>> _saveScreenshot { std::nullopt };

QFileSystemWatcher _filesystemWatcher;
QMediaPlayer _mediaPlayer;
Expand Down

0 comments on commit 100902d

Please sign in to comment.