@ -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 TQImage Drag( snapshot . convertToImage ( ) , this ) ;
TQDragObject * drobj = new Snapshot Drag( 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_t mpFiles)
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"