summaryrefslogtreecommitdiffstats
path: root/ksnapshot/ksnapshot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ksnapshot/ksnapshot.cpp')
-rw-r--r--ksnapshot/ksnapshot.cpp447
1 files changed, 280 insertions, 167 deletions
diff --git a/ksnapshot/ksnapshot.cpp b/ksnapshot/ksnapshot.cpp
index c0ebc1be..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,9 +68,29 @@
#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,
+ : DCOPObject("interface"),
+ KDialogBase(parent, name, true, TQString(), Help|User1, User1,
true, KStdGuiItem::quit() )
{
grabber = new TQWidget( 0, 0, WStyle_Customize | WX11BypassWM );
@@ -85,12 +113,14 @@ KSnapshot::KSnapshot(TQWidget *parent, const char *name, bool grabCurrent)
grabber->show();
grabber->grabMouse( waitCursor );
- if ( !grabCurrent )
- snapshot = TQPixmap::grabWindow( tqt_xrootwin() );
- else {
- mainWidget->setMode( WindowUnderCursor );
- mainWidget->setIncludeDecorations( true );
- performGrab();
+ if ( !grabCurrent ) {
+ snapshot = TQPixmap::grabWindow( tqt_xrootwin() );
+ timestamp = TQDateTime::currentDateTime();
+ setLocalFilePath(TQString::null);
+ } else {
+ mainWidget->setMode( WindowUnderCursor );
+ mainWidget->setIncludeDecorations( true );
+ performGrab();
}
updatePreview();
@@ -106,7 +136,7 @@ KSnapshot::KSnapshot(TQWidget *parent, const char *name, bool grabCurrent)
// Make sure the name is not already being used
while(TDEIO::NetAccess::exists( filename, false, this )) {
- autoincFilename();
+ autoincFilename();
}
connect( &grabTimer, TQ_SIGNAL( timeout() ), this, TQ_SLOT( grabTimerDone() ) );
@@ -139,13 +169,13 @@ KSnapshot::KSnapshot(TQWidget *parent, const char *name, bool grabCurrent)
TDEAccel* accel = new TDEAccel(this);
accel->insert(TDEStdAccel::Quit, tdeApp, TQ_SLOT(quit()));
accel->insert( "QuickSave", i18n("Quick Save Snapshot &As..."),
- i18n("Save the snapshot to the file specified by the user without showing the file dialog."),
- CTRL+SHIFT+Key_S, this, TQ_SLOT(slotSave()));
+ i18n("Save the snapshot to the file specified by the user without showing the file dialog."),
+ CTRL+SHIFT+Key_S, this, TQ_SLOT(slotSave()));
accel->insert(TDEStdAccel::Save, this, TQ_SLOT(slotSaveAs()));
// accel->insert(TDEShortcut(CTRL+Key_A), this, TQ_SLOT(slotSaveAs()));
accel->insert( "SaveAs", i18n("Save Snapshot &As..."),
- i18n("Save the snapshot to the file specified by the user."),
- CTRL+Key_A, this, TQ_SLOT(slotSaveAs()));
+ i18n("Save the snapshot to the file specified by the user."),
+ CTRL+Key_A, this, TQ_SLOT(slotSaveAs()));
accel->insert(TDEStdAccel::Print, this, TQ_SLOT(slotPrint()));
accel->insert(TDEStdAccel::New, this, TQ_SLOT(slotGrab()));
accel->insert(TDEStdAccel::Copy, this, TQ_SLOT(slotCopy()));
@@ -168,12 +198,12 @@ KSnapshot::~KSnapshot()
{
}
-void KSnapshot::resizeEvent( TQResizeEvent *event)
+void KSnapshot::resizeEvent( TQResizeEvent * /*event*/)
{
- if( !updateTimer.isActive() )
- updateTimer.start(200, true);
- else
- updateTimer.changeInterval(200);
+ if( !updateTimer.isActive() )
+ updateTimer.start(200, true);
+ else
+ updateTimer.changeInterval(200);
}
bool KSnapshot::save( const TQString &filename )
@@ -186,7 +216,7 @@ bool KSnapshot::save( const KURL& url )
if ( TDEIO::NetAccess::exists( url, false, this ) ) {
const TQString title = i18n( "File Exists" );
const TQString text = i18n( "<qt>Do you really want to overwrite <b>%1</b>?</qt>" ).arg(url.prettyURL());
- if (KMessageBox::Continue != KMessageBox::warningContinueCancel( this, text, title, i18n("Overwrite") ) )
+ if (KMessageBox::Continue != KMessageBox::warningContinueCancel( this, text, title, i18n("Overwrite") ) )
{
return false;
}
@@ -194,36 +224,40 @@ bool KSnapshot::save( const KURL& url )
TQString type( KImageIO::type(url.path()) );
if ( type.isNull() )
- type = "PNG";
+ type = "PNG";
bool ok = false;
if ( url.isLocalFile() ) {
- KSaveFile saveFile( url.path() );
- if ( saveFile.status() == 0 ) {
- if ( snapshot.save( saveFile.file(), type.latin1() ) )
- ok = saveFile.close();
- }
+ KSaveFile saveFile( url.path() );
+ if ( saveFile.status() == 0 ) {
+ if ( snapshot.save( saveFile.file(), type.latin1() ) ) {
+ ok = saveFile.close();
+ if (ok) {
+ setLocalFilePath(saveFile.name());
+ }
+ }
+ }
}
else {
- KTempFile tmpFile;
+ KTempFile tmpFile;
tmpFile.setAutoDelete( true );
- if ( tmpFile.status() == 0 ) {
- if ( snapshot.save( tmpFile.file(), type.latin1() ) ) {
- if ( tmpFile.close() )
- ok = TDEIO::NetAccess::upload( tmpFile.name(), url, this );
- }
- }
+ if ( tmpFile.status() == 0 ) {
+ if ( snapshot.save( tmpFile.file(), type.latin1() ) ) {
+ if ( tmpFile.close() )
+ ok = TDEIO::NetAccess::upload( tmpFile.name(), url, this );
+ }
+ }
}
TQApplication::restoreOverrideCursor();
if ( !ok ) {
- kdWarning() << "KSnapshot was unable to save the snapshot" << endl;
+ kdWarning() << "KSnapshot was unable to save the snapshot" << endl;
- TQString caption = i18n("Unable to save image");
- TQString text = i18n("KSnapshot was unable to save the image to\n%1.")
- .arg(url.prettyURL());
- KMessageBox::error(this, text, caption);
+ TQString caption = i18n("Unable to save image");
+ TQString text = i18n("KSnapshot was unable to save the image to\n%1.")
+ .arg(url.prettyURL());
+ KMessageBox::error(this, text, caption);
}
return ok;
@@ -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();
}
@@ -281,17 +315,17 @@ void KSnapshot::slotGrab()
hide();
if ( mainWidget->delay() )
- grabTimer.start( mainWidget->delay() * 1000, true );
+ grabTimer.start( mainWidget->delay() * 1000, true );
else {
- if ( mainWidget->mode() == Region ) {
- rgnGrab = new RegionGrabber();
- connect( rgnGrab, TQ_SIGNAL( regionGrabbed( const TQPixmap & ) ),
- TQ_SLOT( slotRegionGrabbed( const TQPixmap & ) ) );
- }
- else {
- grabber->show();
- grabber->grabMouse( crossCursor );
- }
+ if ( mainWidget->mode() == Region ) {
+ rgnGrab = new RegionGrabber();
+ connect( rgnGrab, TQ_SIGNAL( regionGrabbed( const TQPixmap & ) ),
+ TQ_SLOT( slotRegionGrabbed( const TQPixmap & ) ) );
+ }
+ else {
+ grabber->show();
+ grabber->grabMouse( crossCursor );
+ }
}
}
@@ -307,48 +341,48 @@ void KSnapshot::slotPrint()
if (printer.setup(this, i18n("Print Screenshot")))
{
- tqApp->processEvents();
+ tqApp->processEvents();
TQPainter painter(&printer);
TQPaintDeviceMetrics metrics(painter.device());
- float w = snapshot.width();
- float dw = w - metrics.width();
- float h = snapshot.height();
- float dh = h - metrics.height();
- bool scale = false;
+ float w = snapshot.width();
+ float dw = w - metrics.width();
+ float h = snapshot.height();
+ float dh = h - metrics.height();
+ bool scale = false;
- if ( (dw > 0.0) || (dh > 0.0) )
- scale = true;
+ if ( (dw > 0.0) || (dh > 0.0) )
+ scale = true;
- if ( scale ) {
+ if ( scale ) {
- TQImage img = snapshot.convertToImage();
- tqApp->processEvents();
+ TQImage img = snapshot.convertToImage();
+ tqApp->processEvents();
- float newh, neww;
- if ( dw > dh ) {
- neww = w-dw;
- newh = neww/w*h;
- }
- else {
- newh = h-dh;
- neww = newh/h*w;
- }
+ float newh, neww;
+ if ( dw > dh ) {
+ neww = w-dw;
+ newh = neww/w*h;
+ }
+ else {
+ newh = h-dh;
+ neww = newh/h*w;
+ }
- img = img.smoothScale( int(neww), int(newh), TQImage::ScaleMin );
- tqApp->processEvents();
+ img = img.smoothScale( int(neww), int(newh), TQImage::ScaleMin );
+ tqApp->processEvents();
- int x = (metrics.width()-img.width())/2;
- int y = (metrics.height()-img.height())/2;
+ int x = (metrics.width()-img.width())/2;
+ int y = (metrics.height()-img.height())/2;
- painter.drawImage( x, y, img);
- }
- else {
- int x = (metrics.width()-snapshot.width())/2;
- int y = (metrics.height()-snapshot.height())/2;
- painter.drawPixmap( x, y, snapshot );
- }
+ painter.drawImage( x, y, img);
+ }
+ else {
+ int x = (metrics.width()-snapshot.width())/2;
+ int y = (metrics.height()-snapshot.height())/2;
+ painter.drawPixmap( x, y, snapshot );
+ }
}
tqApp->processEvents();
@@ -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,92 +423,141 @@ 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)
- {
- tmpFile->unlink();
- delete tmpFile;
- }
- m_tmpFiles.clear();
+ for(const TQString &file: tempFiles)
+ {
+ TQFile::remove(file);
+ }
+ tempFiles.clear();
- TDEConfig *conf=TDEGlobal::config();
- conf->setGroup("GENERAL");
- conf->writeEntry("delay",mainWidget->delay());
- conf->writeEntry("mode",mainWidget->mode());
- conf->writeEntry("includeDecorations",mainWidget->includeDecorations());
- KURL url = filename;
- url.setPass( TQString() );
- conf->writePathEntry("filename",url.url());
+ TDEConfig *conf=TDEGlobal::config();
+ conf->setGroup("GENERAL");
+ conf->writeEntry("delay",mainWidget->delay());
+ conf->writeEntry("mode",mainWidget->mode());
+ conf->writeEntry("includeDecorations",mainWidget->includeDecorations());
+ KURL url = filename;
+ url.setPass( TQString() );
+ conf->writePathEntry("filename",url.url());
}
void KSnapshot::closeEvent( TQCloseEvent * e )
{
- e->accept();
+ e->accept();
}
bool KSnapshot::eventFilter( TQObject* o, TQEvent* e)
{
if ( o == grabber && e->type() == TQEvent::MouseButtonPress ) {
- TQMouseEvent* me = (TQMouseEvent*) e;
- if ( TQWidget::mouseGrabber() != grabber )
- return false;
- if ( me->button() == TQt::LeftButton )
- performGrab();
+ TQMouseEvent* me = (TQMouseEvent*) e;
+ if ( TQWidget::mouseGrabber() != grabber )
+ return false;
+ if ( me->button() == TQt::LeftButton )
+ performGrab();
}
return false;
}
@@ -500,10 +575,10 @@ void KSnapshot::autoincFilename()
if (start != -1) {
// It has a number, increment it
int len = numSearch.matchedLength();
- TQString numAsStr= name.mid(start, len);
- TQString number = TQString::number(numAsStr.toInt() + 1);
- number = number.rightJustify( len, '0');
- name.replace(start, len, number );
+ TQString numAsStr= name.mid(start, len);
+ TQString number = TQString::number(numAsStr.toInt() + 1);
+ number = number.rightJustify( len, '0');
+ name.replace(start, len, number );
}
else {
// no number
@@ -518,7 +593,7 @@ void KSnapshot::autoincFilename()
}
}
- //Rebuild the path
+ // Rebuild the path
KURL newURL = filename;
newURL.setFileName( name );
setURL( newURL.url() );
@@ -537,7 +612,7 @@ void KSnapshot::grabTimerDone()
TQ_SLOT( slotRegionGrabbed( const TQPixmap & ) ) );
}
else {
- performGrab();
+ performGrab();
}
KNotifyClient::beep(i18n("The screen has been successfully grabbed."));
}
@@ -548,23 +623,22 @@ void KSnapshot::performGrab()
grabber->hide();
grabTimer.stop();
if ( mainWidget->mode() == ChildWindow ) {
- WindowGrabber wndGrab;
- connect( &wndGrab, TQ_SIGNAL( windowGrabbed( const TQPixmap & ) ),
- TQ_SLOT( slotWindowGrabbed( const TQPixmap & ) ) );
- wndGrab.exec();
- }
- else if ( mainWidget->mode() == WindowUnderCursor ) {
- snapshot = WindowGrabber::grabCurrent( mainWidget->includeDecorations() );
+ WindowGrabber wndGrab;
+ connect( &wndGrab, TQ_SIGNAL( windowGrabbed( const TQPixmap & ) ),
+ TQ_SLOT( newSnapshot( const TQPixmap & ) ) );
+ wndGrab.exec();
}
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)
@@ -581,7 +655,7 @@ void KSnapshot::setURL( const TQString &url )
{
KURL newURL = KURL::fromPathOrURL( url );
if ( newURL == filename )
- return;
+ return;
filename = newURL;
updateCaption();
@@ -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"