diff --git a/.idea/dictionaries/romas.xml b/.idea/dictionaries/romas.xml
new file mode 100644
--- /dev/null
+++ b/.idea/dictionaries/romas.xml
@@ -0,0 +1,7 @@
+
+
+
+ filenames
+
+
+
\ No newline at end of file
diff --git a/doc/index.docbook b/doc/index.docbook
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -311,6 +311,7 @@
%H: Hour
%m: Minute
%S: Second
+ %T: Window's title
If a file with this name already exists, a serial number will be appended to the filename. For example, if the filename is Screenshot, and Screenshot.png already exists, the image will be saved as Screenshot-1.png.
Typing an extension into the filename will automatically set the image format correctly and remove the extension from the filename field.
diff --git a/src/ExportManager.h b/src/ExportManager.h
--- a/src/ExportManager.h
+++ b/src/ExportManager.h
@@ -26,6 +26,8 @@
#include
#include
+#include "PlatformBackends/ImageGrabber.h"
+
class QTemporaryDir;
class ExportManager : public QObject
@@ -52,14 +54,20 @@
Q_PROPERTY(QString saveLocation READ saveLocation WRITE setSaveLocation NOTIFY saveLocationChanged)
Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap NOTIFY pixmapChanged)
+ Q_PROPERTY(QString windowTitle READ windowTitle WRITE setWindowTitle)
+ Q_PROPERTY(ImageGrabber::GrabMode grabMode READ grabMode WRITE setGrabMode)
void setSaveLocation(const QString &location);
QString saveLocation() const;
QUrl lastSavePath() const;
bool isFileExists(const QUrl &url) const;
void setPixmap(const QPixmap &pixmap);
QPixmap pixmap() const;
QString pixmapDataUri() const;
+ void setWindowTitle(const QString &windowTitle);
+ QString windowTitle() const;
+ ImageGrabber::GrabMode grabMode() const;
+ void setGrabMode(const ImageGrabber::GrabMode &grabMode);
signals:
@@ -97,6 +105,8 @@
QUrl mTempFile;
QTemporaryDir *mTempDir;
QList mUsedTempFileNames;
+ QString mWindowTitle;
+ ImageGrabber::GrabMode mGrabMode;
};
#endif // EXPORTMANAGER_H
diff --git a/src/ExportManager.cpp b/src/ExportManager.cpp
--- a/src/ExportManager.cpp
+++ b/src/ExportManager.cpp
@@ -19,16 +19,17 @@
#include "ExportManager.h"
+#include
+#include
+#include
#include
-#include
+#include
#include
+#include
+#include
+#include
#include
#include
-#include
-#include
-#include
-#include
-#include
#include
#include
@@ -87,6 +88,26 @@
return uri;
}
+void ExportManager::setWindowTitle(const QString &windowTitle)
+{
+ mWindowTitle = windowTitle;
+}
+
+QString ExportManager::windowTitle() const
+{
+ return mWindowTitle;
+}
+
+ImageGrabber::GrabMode ExportManager::grabMode() const
+{
+ return mGrabMode;
+}
+
+void ExportManager::setGrabMode(const ImageGrabber::GrabMode &grabMode)
+{
+ mGrabMode = grabMode;
+}
+
void ExportManager::setPixmap(const QPixmap &pixmap)
{
mSavePixmap = pixmap;
@@ -161,13 +182,36 @@
const QDateTime timestamp = QDateTime::currentDateTime();
QString baseName = generalConfig.readEntry("save-filename-format", "Screenshot_%Y%M%D_%H%m%S");
- return baseName.replace(QLatin1String("%Y"), timestamp.toString(QStringLiteral("yyyy")))
- .replace(QLatin1String("%y"), timestamp.toString(QStringLiteral("yy")))
- .replace(QLatin1String("%M"), timestamp.toString(QStringLiteral("MM")))
- .replace(QLatin1String("%D"), timestamp.toString(QStringLiteral("dd")))
- .replace(QLatin1String("%H"), timestamp.toString(QStringLiteral("hh")))
- .replace(QLatin1String("%m"), timestamp.toString(QStringLiteral("mm")))
- .replace(QLatin1String("%S"), timestamp.toString(QStringLiteral("ss")));
+ QString title{};
+
+ if (mGrabMode == ImageGrabber::GrabMode::ActiveWindow ||
+ mGrabMode == ImageGrabber::GrabMode::TransientWithParent ||
+ mGrabMode == ImageGrabber::GrabMode::WindowUnderCursor) {
+ title = mWindowTitle;
+ } else {
+ // Remove '%T' with separators around it
+ const auto wordSymbol = QStringLiteral(R"(\p{L}\p{M}\p{N})");
+ const auto wordOrEmptyString = QStringLiteral("([%1]*)").arg(wordSymbol);
+ const auto separator = QStringLiteral("([^%1]+)").arg(wordSymbol);
+ const auto re = QRegularExpression(QStringLiteral("%1(%2%T|%T%2)%1").arg(wordOrEmptyString, separator));
+ baseName.replace(re, QStringLiteral(R"(\1\5)"));
+ }
+
+ QString result = baseName.replace(QLatin1String("%Y"), timestamp.toString(QStringLiteral("yyyy")))
+ .replace(QLatin1String("%y"), timestamp.toString(QStringLiteral("yy")))
+ .replace(QLatin1String("%M"), timestamp.toString(QStringLiteral("MM")))
+ .replace(QLatin1String("%D"), timestamp.toString(QStringLiteral("dd")))
+ .replace(QLatin1String("%H"), timestamp.toString(QStringLiteral("hh")))
+ .replace(QLatin1String("%m"), timestamp.toString(QStringLiteral("mm")))
+ .replace(QLatin1String("%S"), timestamp.toString(QStringLiteral("ss")))
+ .replace(QLatin1String("%T"), title)
+ .replace(QLatin1String("/"), QLatin1String("_")); // POSIX doesn't allow "/" in filenames
+ if (result.isEmpty()) {
+ result = QStringLiteral("Screenshot");
+ }
+ const auto maxFilenameLength = 255;
+ result.truncate(maxFilenameLength);
+ return result;
}
QString ExportManager::autoIncrementFilename(const QString &baseName, const QString &extension,
diff --git a/src/Gui/SettingsDialog/SaveOptionsPage.cpp b/src/Gui/SettingsDialog/SaveOptionsPage.cpp
--- a/src/Gui/SettingsDialog/SaveOptionsPage.cpp
+++ b/src/Gui/SettingsDialog/SaveOptionsPage.cpp
@@ -103,7 +103,8 @@
"%D: Day
"
"%H: Hour
"
"%m: Minute
"
- "%S: Second"
+ "%S: Second
"
+ "%T: Window title"
""
);
diff --git a/src/Gui/SettingsDialog/SettingsDialog.cpp b/src/Gui/SettingsDialog/SettingsDialog.cpp
--- a/src/Gui/SettingsDialog/SettingsDialog.cpp
+++ b/src/Gui/SettingsDialog/SettingsDialog.cpp
@@ -35,7 +35,7 @@
// set up window options and geometry
setWindowTitle(i18n("Configure"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
- resize(500, 470);
+ resize(500, 500);
// init all pages
QMetaObject::invokeMethod(this, "initPages", Qt::QueuedConnection);
diff --git a/src/PlatformBackends/ImageGrabber.h b/src/PlatformBackends/ImageGrabber.h
--- a/src/PlatformBackends/ImageGrabber.h
+++ b/src/PlatformBackends/ImageGrabber.h
@@ -67,6 +67,7 @@
signals:
void pixmapChanged(const QPixmap &pixmap);
+ void windowTitleChanged(const QString &windowTitle);
void imageGrabFailed();
void capturePointerChanged(bool capturePointer);
void captureDecorationsChanged(bool captureDecorations);
diff --git a/src/PlatformBackends/X11ImageGrabber.h b/src/PlatformBackends/X11ImageGrabber.h
--- a/src/PlatformBackends/X11ImageGrabber.h
+++ b/src/PlatformBackends/X11ImageGrabber.h
@@ -87,6 +87,7 @@
QPoint getNativeCursorPosition();
OnClickEventFilter *mNativeEventFilter;
+ void updateWindowTitle(xcb_window_t window);
};
template using CScopedPointer = QScopedPointer;
diff --git a/src/PlatformBackends/X11ImageGrabber.cpp b/src/PlatformBackends/X11ImageGrabber.cpp
--- a/src/PlatformBackends/X11ImageGrabber.cpp
+++ b/src/PlatformBackends/X11ImageGrabber.cpp
@@ -44,6 +44,9 @@
#include
#include
+#include
+#include
+
X11ImageGrabber::X11ImageGrabber(QObject *parent) :
ImageGrabber(parent)
{
@@ -413,6 +416,12 @@
// grabber methods
+void X11ImageGrabber::updateWindowTitle(xcb_window_t window)
+{
+ QString windowTitle = KWindowSystem::readNameProperty(window, XA_WM_NAME);
+ emit windowTitleChanged(windowTitle);
+}
+
void X11ImageGrabber::grabFullScreen()
{
mPixmap = getToplevelPixmap(QRect(), mCapturePointer);
@@ -422,6 +431,7 @@
void X11ImageGrabber::grabTransientWithParent()
{
xcb_window_t curWin = getRealWindowUnderCursor();
+ updateWindowTitle(curWin);
// grab the image early
@@ -514,6 +524,7 @@
void X11ImageGrabber::grabActiveWindow()
{
xcb_window_t activeWindow = KWindowSystem::activeWindow();
+ updateWindowTitle(activeWindow);
// if KWin is available, use the KWin DBus interfaces
@@ -542,6 +553,9 @@
void X11ImageGrabber::grabWindowUnderCursor()
{
+ xcb_window_t windowUnderCursor = getRealWindowUnderCursor();
+ updateWindowTitle(windowUnderCursor);
+
// if KWin is available, use the KWin DBus interfaces
if (mCaptureDecorations && isKWinAvailable()) {
@@ -564,7 +578,7 @@
// else, go native
- return grabApplicationWindowHelper(getRealWindowUnderCursor());
+ return grabApplicationWindowHelper(windowUnderCursor);
}
void X11ImageGrabber::grabApplicationWindowHelper(xcb_window_t window)
diff --git a/src/SpectacleCore.cpp b/src/SpectacleCore.cpp
--- a/src/SpectacleCore.cpp
+++ b/src/SpectacleCore.cpp
@@ -75,7 +75,7 @@
mImageGrabber = new DummyImageGrabber;
}
- mImageGrabber->setGrabMode(grabMode);
+ setGrabMode(grabMode);
mImageGrabber->setCapturePointer(guiConfig.readEntry("includePointer", true));
mImageGrabber->setCaptureDecorations(guiConfig.readEntry("includeDecorations", true));
@@ -86,6 +86,7 @@
connect(mExportManager, &ExportManager::errorMessage, this, &SpectacleCore::showErrorMessage);
connect(this, &SpectacleCore::errorMessage, this, &SpectacleCore::showErrorMessage);
connect(mImageGrabber, &ImageGrabber::pixmapChanged, this, &SpectacleCore::screenshotUpdated);
+ connect(mImageGrabber, &ImageGrabber::windowTitleChanged, mExportManager, &ExportManager::setWindowTitle);
connect(mImageGrabber, &ImageGrabber::imageGrabFailed, this, &SpectacleCore::screenshotFailed);
connect(mExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doCopyPath);
connect(mExportManager, &ExportManager::forceNotify, this, &SpectacleCore::doNotify);
@@ -132,6 +133,7 @@
void SpectacleCore::setGrabMode(const ImageGrabber::GrabMode &grabMode)
{
mImageGrabber->setGrabMode(grabMode);
+ mExportManager->setGrabMode(grabMode);
}
// Slots
@@ -148,7 +150,7 @@
void SpectacleCore::takeNewScreenshot(const ImageGrabber::GrabMode &mode,
const int &timeout, const bool &includePointer, const bool &includeDecorations)
{
- mImageGrabber->setGrabMode(mode);
+ setGrabMode(mode);
mImageGrabber->setCapturePointer(includePointer);
mImageGrabber->setCaptureDecorations(includeDecorations);