summaryrefslogtreecommitdiffstats
path: root/ksnapshot/ksnapshot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ksnapshot/ksnapshot.cpp')
-rw-r--r--ksnapshot/ksnapshot.cpp245
1 files changed, 179 insertions, 66 deletions
diff --git a/ksnapshot/ksnapshot.cpp b/ksnapshot/ksnapshot.cpp
index 605a898a..36918c4a 100644
--- a/ksnapshot/ksnapshot.cpp
+++ b/ksnapshot/ksnapshot.cpp
@@ -22,10 +22,11 @@
#include <kprinter.h>
#include <tdeio/netaccess.h>
#include <ksavefile.h>
+#include <tdestandarddirs.h>
#include <tdetempfile.h>
+#include <kde_file.h>
#include <tqbitmap.h>
-#include <tqdragobject.h>
#include <tqimage.h>
#include <tqclipboard.h>
#include <tqvbox.h>
@@ -46,8 +47,15 @@
#include <tqpaintdevicemetrics.h>
#include <tqwhatsthis.h>
+#include <functional>
+#include <memory>
+#include <utility>
+
#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
#include "ksnapshot.h"
#include "regiongrabber.h"
#include "windowgrabber.h"
@@ -60,6 +68,26 @@
#include <tdeglobal.h>
+// A quick and dirty scope guard implementation
+class ExitGuard {
+public:
+ template<class Callable>
+ ExitGuard(Callable && undo_func) : f(std::forward<Callable>(undo_func)) {}
+ ExitGuard(ExitGuard && other) : f(std::move(other.f)) {
+ other.f = nullptr;
+ }
+
+ ~ExitGuard() {
+ if(f) { f(); f = nullptr; }
+ }
+
+ ExitGuard(const ExitGuard&) = delete;
+ void operator= (const ExitGuard&) = delete;
+
+private:
+ std::function<void()> f;
+};
+
KSnapshot::KSnapshot(TQWidget *parent, const char *name, bool grabCurrent)
: DCOPObject("interface"),
KDialogBase(parent, name, true, TQString(), Help|User1, User1,
@@ -85,9 +113,11 @@ KSnapshot::KSnapshot(TQWidget *parent, const char *name, bool grabCurrent)
grabber->show();
grabber->grabMouse( waitCursor );
- if ( !grabCurrent )
+ if ( !grabCurrent ) {
snapshot = TQPixmap::grabWindow( tqt_xrootwin() );
- else {
+ timestamp = TQDateTime::currentDateTime();
+ setLocalFilePath(TQString::null);
+ } else {
mainWidget->setMode( WindowUnderCursor );
mainWidget->setIncludeDecorations( true );
performGrab();
@@ -201,8 +231,12 @@ bool KSnapshot::save( const KURL& url )
if ( url.isLocalFile() ) {
KSaveFile saveFile( url.path() );
if ( saveFile.status() == 0 ) {
- if ( snapshot.save( saveFile.file(), type.latin1() ) )
+ if ( snapshot.save( saveFile.file(), type.latin1() ) ) {
ok = saveFile.close();
+ if (ok) {
+ setLocalFilePath(saveFile.name());
+ }
+ }
}
}
else {
@@ -270,7 +304,7 @@ void KSnapshot::slotCopy()
void KSnapshot::slotDragSnapshot()
{
- TQDragObject *drobj = new TQImageDrag(snapshot.convertToImage(), this);
+ TQDragObject *drobj = new SnapshotDrag(snapshot.convertToImage(), this);
drobj->setPixmap(mainWidget->preview());
drobj->dragCopy();
}
@@ -356,26 +390,18 @@ void KSnapshot::slotPrint()
void KSnapshot::slotRegionGrabbed( const TQPixmap &pix )
{
- if ( !pix.isNull() )
- {
- snapshot = pix;
- updatePreview();
- modified = true;
- updateCaption();
- }
-
- delete rgnGrab;
- TQApplication::restoreOverrideCursor();
- move(oldWinPos);
- show();
+ rgnGrab->deleteLater();
+ newSnapshot(pix);
}
-void KSnapshot::slotWindowGrabbed( const TQPixmap &pix )
+void KSnapshot::newSnapshot( const TQPixmap &pix )
{
if ( !pix.isNull() )
{
snapshot = pix;
updatePreview();
+ timestamp = TQDateTime::currentDateTime();
+ setLocalFilePath(TQString::null);
modified = true;
updateCaption();
}
@@ -397,68 +423,117 @@ void KSnapshot::slotOpenWithKP() {
}
}
-void KSnapshot::openWithExternalApp(const KService &service) {
- // Write snapshot to temporary file
- bool ok = false;
- KTempFile *tmpFile = new KTempFile;
- if (tmpFile->status() == 0) {
- if (snapshot.save(tmpFile->file(), "PNG")) {
- if (tmpFile->close()) {
- ok = true;
- }
+/// Writes the snapshot to a temporary file
+TQString KSnapshot::saveTempFile() {
+
+ // construct a pretty name for the temporary file
+ TQString base_fname =
+ i18n("A temporary filename; prefer dashes (-) as word separators if required", "snapshot")
+ .append(timestamp.toString("-yyyyMMdd-hhmmss"));
+ TQString base_fpath = locateLocal("tmp", base_fname);
+ TQString fname = base_fpath + ".png";
+
+ // We want the pretty names; unfortunately KTempFile forces us to use mkstemp-style name; which
+ // has a random string at the end, which is quite ugly. On the other hand TQFile doesn't
+ // provide any means to fail if file already exist (i.e. O_EXCL). So in order to have best of
+ // both worlds we will have to try to open the file manually and if it fails, we will fallback
+ // to KTempFile.
+ int fd = -1;
+ ExitGuard closeGuard { [&fd](){ if (fd>=0) { ::close(fd); } } };
+
+ std::unique_ptr<KTempFile> tmpFile; // used only if manual open() fails
+ std::unique_ptr<TQFile> tqfile; // used only if manual open() succeeds
+ TQFile* file; // either tqfile or tmpFile->file()
+
+ fd = KDE_open(TQFile::encodeName(fname), O_WRONLY | O_CREAT | O_EXCL, 0600);
+
+ if (fd>=0) {
+ tqfile = std::unique_ptr<TQFile>(new TQFile(fname));
+ tqfile->open( IO_WriteOnly, fd ); // according to docs TQFile won't close the fd so there is
+ // an exit guard above
+ file = tqfile.get();
+
+ } else {
+ tmpFile = std::unique_ptr<KTempFile>(new KTempFile(base_fpath + "-", ".png"));
+ if (!tmpFile || tmpFile->status() != 0) {
+ return TQString::null;
}
+ file = tmpFile->file();
+ fname = tmpFile->name();
}
+ // Actually save the image
+ bool ok = snapshot.save(file, "PNG");
+
if (!ok) {
+ file->remove();
+ return TQString::null;
+ }
+
+ tempFiles.append(fname);
+
+ return fname;
+}
+
+void KSnapshot::setLocalFilePath(TQString fp) {
+ localFilePath = fp;
+ if(!fp.isEmpty()) {
+ TQFileInfo fi(fp);
+ currentFilePathTimestamp = fi.lastModified ();
+ } else {
+ currentFilePathTimestamp = TQDateTime();
+ }
+}
+
+/// Returns a local file for the current snapshot. It may be either a file explicitly saved by the
+/// user or a temporary one saved internally
+TQString KSnapshot::localFile() {
+ bool needSaveTemp = true;
+ if(!localFilePath.isEmpty()) {
+ TQFileInfo fi(localFilePath);
+ // Checks that nobody have overwritten the file since we saved it
+ if( fi.exists() && currentFilePathTimestamp == fi.lastModified()) {
+ needSaveTemp = false;
+ }
+ }
+
+ if(needSaveTemp) {
+ setLocalFilePath( saveTempFile() );
+ }
+
+ return localFilePath;
+}
+
+void KSnapshot::openWithExternalApp(const KService &service) {
+ // Write snapshot to temporary file
+ TQString file = localFile();
+
+ if (file.isEmpty()) {
KMessageBox::error(this, i18n("KSnapshot was unable to create temporary file."),
i18n("Unable to save image"));
- delete tmpFile;
return;
}
// Launch application
KURL::List list;
- list.append(tmpFile->name());
+ list.append(file);
TQStringList args = KRun::processDesktopExec(service, list, false, false);
TDEProcess *externalApp = new TDEProcess;
*externalApp << args;
- connect(externalApp, TQ_SIGNAL(processExited(TDEProcess*)),
- this, TQ_SLOT(slotExternalAppClosed(TDEProcess*)));
if (!externalApp->start(TDEProcess::OwnGroup)) {
KMessageBox::error(this, i18n("Cannot start %1!").arg(service.name()));
- delete tmpFile;
- return;
- }
-
- m_tmpFiles[externalApp] = tmpFile;
-}
-
-void KSnapshot::slotExternalAppClosed(TDEProcess *process)
-{
- if (process && m_tmpFiles.contains(process))
- {
- KTempFile *tmpFile = m_tmpFiles[process];
- if (tmpFile)
- {
- snapshot.load(tmpFile->name());
- updatePreview();
- tmpFile->unlink();
- delete tmpFile;
- }
- m_tmpFiles.remove(process);
}
}
void KSnapshot::slotAboutToQuit()
{
- for (KTempFile *tmpFile : m_tmpFiles)
+ for(const TQString &file: tempFiles)
{
- tmpFile->unlink();
- delete tmpFile;
+ TQFile::remove(file);
}
- m_tmpFiles.clear();
+ tempFiles.clear();
TDEConfig *conf=TDEGlobal::config();
conf->setGroup("GENERAL");
@@ -550,21 +625,20 @@ void KSnapshot::performGrab()
if ( mainWidget->mode() == ChildWindow ) {
WindowGrabber wndGrab;
connect( &wndGrab, TQ_SIGNAL( windowGrabbed( const TQPixmap & ) ),
- TQ_SLOT( slotWindowGrabbed( const TQPixmap & ) ) );
+ TQ_SLOT( newSnapshot( const TQPixmap & ) ) );
wndGrab.exec();
}
- else if ( mainWidget->mode() == WindowUnderCursor ) {
- snapshot = WindowGrabber::grabCurrent( mainWidget->includeDecorations() );
- }
else {
- snapshot = TQPixmap::grabWindow( tqt_xrootwin() );
+ TQPixmap pix;
+ if ( mainWidget->mode() == WindowUnderCursor ) {
+ pix = WindowGrabber::grabCurrent( mainWidget->includeDecorations() );
+ }
+ else {
+ pix = TQPixmap::grabWindow( tqt_xrootwin() );
+ }
+
+ newSnapshot(pix);
}
- updatePreview();
- TQApplication::restoreOverrideCursor();
- modified = true;
- updateCaption();
- move(oldWinPos);
- show();
}
void KSnapshot::setTime(int newTime)
@@ -589,6 +663,8 @@ void KSnapshot::setURL( const TQString &url )
void KSnapshot::setPixmap(const TQPixmap &newImage) {
snapshot = newImage;
+ timestamp = TQDateTime::currentDateTime();
+ setLocalFilePath(TQString::null);
updatePreview();
}
@@ -616,4 +692,41 @@ void KSnapshot::exit()
{
reject();
}
+
+SnapshotDrag::SnapshotDrag( TQImage image, KSnapshot * dragSource, const char * name )
+ :TQImageDrag::TQImageDrag( image, dragSource, name ), ksnap(dragSource)
+{
+ // TQ*Drop API is a bit quirky, so to append our value to the list of formats we will have
+ // to iterate over the full list provided by TQImageDrag manually just to determine how many
+ // formats it supports
+
+ for (int i=0 ; ; i++) {
+ const char* format = TQImageDrag::format(i);
+ if (format) {
+ formats.append(format);
+ } else {
+ break;
+ }
+ }
+ formats.append("text/uri-list");
+}
+
+const char * SnapshotDrag::format(int i) const
+{
+ if( i < (int) formats.count() ) {
+ return formats[i];
+ } else {
+ return 0;
+ }
+}
+
+TQByteArray SnapshotDrag::encodedData(const char* format) const
+{
+ if( strcmp(format, "text/uri-list") == 0 ) {
+ return TQUriDrag::localFileToUri( ksnap->localFile() );
+ } else {
+ return TQImageDrag::encodedData(format);
+ }
+}
+
#include "ksnapshot.moc"