diff options
Diffstat (limited to 'ksnapshot/ksnapshot.cpp')
| -rw-r--r-- | ksnapshot/ksnapshot.cpp | 245 |
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" |
