diff options
Diffstat (limited to 'chalk/plugins/viewplugins/screenshot/ksnapshot.cpp')
-rw-r--r-- | chalk/plugins/viewplugins/screenshot/ksnapshot.cpp | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/chalk/plugins/viewplugins/screenshot/ksnapshot.cpp b/chalk/plugins/viewplugins/screenshot/ksnapshot.cpp new file mode 100644 index 00000000..f9887821 --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/ksnapshot.cpp @@ -0,0 +1,499 @@ +/* + * KSnapshot + * + * (c) Richard J. Moore 1997-2002 + * (c) Matthias Ettrich 2000 + * (c) Aaron J. Seigo 2002 + * (c) Nadeem Hasan 2003 + * This adaptation: (c) Boudewijn Rempt 2005 + * + * Released under the GPL see file LICENSE for details. + */ + +#include <kapplication.h> +#include <klocale.h> +#include <kimageio.h> +#include <kfiledialog.h> +#include <kimagefilepreview.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include <kprinter.h> +#include <kio/netaccess.h> +#include <ksavefile.h> +#include <ktempfile.h> + +#include <tqbitmap.h> +#include <tqdragobject.h> +#include <tqimage.h> +#include <tqclipboard.h> +#include <tqvbox.h> + +#include <kaccel.h> +#include <knotifyclient.h> +#include <khelpmenu.h> +#include <kpopupmenu.h> +#include <kpushbutton.h> +#include <kstartupinfo.h> + +#include <tqcursor.h> +#include <tqregexp.h> +#include <tqpainter.h> +#include <tqpaintdevicemetrics.h> +#include <tqwhatsthis.h> + +#include <stdlib.h> + +#include "ksnapshot.h" +#include "regiongrabber.h" +#include "ksnapshotwidget.h" + +#include <X11/Xlib.h> +#include <X11/Xatom.h> + +#include <config.h> + +#ifdef HAVE_X11_EXTENSIONS_SHAPE_H +#include <X11/extensions/shape.h> +#endif + +#include <kglobal.h> + +KSnapshot::KSnapshot(TQWidget *tqparent, const char *name) + : super(tqparent, name, false, TQString(), Ok|Cancel) +{ + grabber = new TQWidget( 0, 0, WStyle_Customize | WX11BypassWM ); + Q_CHECK_PTR(grabber); + grabber->move( -1000, -1000 ); + grabber->installEventFilter( this ); + +#ifdef HAVE_X11_EXTENSIONS_SHAPE_H + int tmp1, tmp2; + //Check whether the extension is available + haveXShape = XShapeQueryExtension( qt_xdisplay(), &tmp1, &tmp2 ); +#endif + + TQVBox *vbox = makeVBoxMainWidget(); + mainWidget = new KSnapshotWidget( vbox, "mainWidget" ); + Q_CHECK_PTR(mainWidget); + + mainWidget->btnSave->hide(); + mainWidget->btnPrint->hide(); + connect(mainWidget, TQT_SIGNAL(startImageDrag()), TQT_SLOT(slotDragSnapshot())); + + connect( mainWidget, TQT_SIGNAL( newClicked() ), TQT_SLOT( slotGrab() ) ); + connect( mainWidget, TQT_SIGNAL( printClicked() ), TQT_SLOT( slotPrint() ) ); + + grabber->show(); + grabber->grabMouse( waitCursor ); + + snapshot = TQPixmap::grabWindow( qt_xrootwin() ); + updatePreview(); + grabber->releaseMouse(); + grabber->hide(); + + KConfig *conf=KGlobal::config(); + conf->setGroup("GENERAL"); + mainWidget->setDelay(conf->readNumEntry("delay",0)); + mainWidget->setMode( conf->readNumEntry( "mode", 0 ) ); + mainWidget->setIncludeDecorations(conf->readBoolEntry("includeDecorations",true)); + + connect( &grabTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( grabTimerDone() ) ); + + KAccel* accel = new KAccel(this); + Q_CHECK_PTR(accel); + accel->insert(KStdAccel::Print, TQT_TQOBJECT(this), TQT_SLOT(slotPrint())); + accel->insert(KStdAccel::New, TQT_TQOBJECT(this), TQT_SLOT(slotGrab())); + + accel->insert( "Print2", TQt::Key_P, TQT_TQOBJECT(this), TQT_SLOT(slotPrint())); + accel->insert( "New2", TQt::Key_N, TQT_TQOBJECT(this), TQT_SLOT(slotGrab())); + accel->insert( "New3", TQt::Key_Space, TQT_TQOBJECT(this), TQT_SLOT(slotGrab())); + + mainWidget->btnNew->setFocus(); + +} + +KSnapshot::~KSnapshot() +{ +} + +bool KSnapshot::save( const TQString &filename ) +{ + return save( KURL::fromPathOrURL( filename )); +} + +bool KSnapshot::save( const KURL& url ) +{ + TQString type( KImageIO::type(url.path()) ); + if ( type.isNull() ) + 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(); + } + } + else { + KTempFile tmpFile; + tmpFile.setAutoDelete( true ); + if ( tmpFile.status() == 0 ) { + if ( snapshot.save( tmpFile.file(), type.latin1() ) ) { + if ( tmpFile.close() ) + ok = KIO::NetAccess::upload( tmpFile.name(), url, this ); + } + } + } + + TQApplication::restoreOverrideCursor(); + if ( !ok ) { + 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.") + .tqarg(url.prettyURL()); + KMessageBox::error(this, text, caption); + } + + return ok; +} + +void KSnapshot::slotCopy() +{ + TQClipboard *cb = TQApplication::tqclipboard(); + cb->setPixmap( snapshot ); +} + +void KSnapshot::slotDragSnapshot() +{ + TQDragObject *drobj = new TQImageDrag(snapshot.convertToImage(), this); + Q_CHECK_PTR(drobj); + drobj->setPixmap(mainWidget->preview()); + drobj->dragCopy(); +} + +void KSnapshot::slotGrab() +{ + hide(); + if ( mainWidget->mode() == Region ) + { + rgnGrab = new RegionGrabber(); + Q_CHECK_PTR(rgnGrab); + connect( rgnGrab, TQT_SIGNAL( regionGrabbed( const TQPixmap & ) ), + TQT_SLOT( slotRegionGrabbed( const TQPixmap & ) ) ); + } + else + { + if ( mainWidget->delay() ) + grabTimer.start( mainWidget->delay() * 1000, true ); + else { + grabber->show(); + grabber->grabMouse( crossCursor ); + } + } +} + +void KSnapshot::slotPrint() +{ + KPrinter printer; + if (snapshot.width() > snapshot.height()) + printer.setOrientation(KPrinter::Landscape); + else + printer.setOrientation(KPrinter::Portrait); + + tqApp->processEvents(); + + if (printer.setup(this, i18n("Print Screenshot"))) + { + 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; + + if ( (dw > 0.0) || (dh > 0.0) ) + scale = true; + + if ( scale ) { + + 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; + } + + img = img.smoothScale( int(neww), int(newh), TQ_ScaleMin ); + tqApp->processEvents(); + + 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 ); + } + } + + tqApp->processEvents(); +} + +void KSnapshot::slotRegionGrabbed( const TQPixmap &pix ) +{ + if ( !pix.isNull() ) + { + snapshot = pix; + updatePreview(); + modified = true; + } + + delete rgnGrab; + TQApplication::restoreOverrideCursor(); + show(); +} + +bool KSnapshot::eventFilter( TQObject* o, TQEvent* e) +{ + if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(grabber) && e->type() == TQEvent::MouseButtonPress ) { + TQMouseEvent* me = (TQMouseEvent*) e; + if ( TQWidget::mouseGrabber() != grabber ) + return false; + if ( me->button() == Qt::LeftButton ) + performGrab(); + } + return false; +} + +void KSnapshot::updatePreview() +{ + TQImage img = snapshot.convertToImage(); + double r1 = ((double) snapshot.height() ) / snapshot.width(); + if ( r1 * mainWidget->previewWidth() < mainWidget->previewHeight() ) + img = img.smoothScale( mainWidget->previewWidth(), + int( mainWidget->previewWidth() * r1 )); + else + img = img.smoothScale( (int) (((double)mainWidget->previewHeight()) / r1), + (mainWidget->previewHeight() ) ); + + TQPixmap pm; + pm.convertFromImage( img ); + mainWidget->setPreview( pm ); +} + +void KSnapshot::grabTimerDone() +{ + performGrab(); + KNotifyClient::beep(i18n("The screen has been successfully grabbed.")); +} + +static +Window findRealWindow( Window w, int depth = 0 ) +{ + if( depth > 5 ) + return None; + static Atom wm_state = XInternAtom( qt_xdisplay(), "WM_STATE", False ); + Atom type; + int format; + unsigned long nitems, after; + unsigned char* prop; + if( XGetWindowProperty( qt_xdisplay(), w, wm_state, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &prop ) == Success ) { + if( prop != NULL ) + XFree( prop ); + if( type != None ) + return w; + } + Window root, tqparent; + Window* tqchildren; + unsigned int ntqchildren; + Window ret = None; + if( XQueryTree( qt_xdisplay(), w, &root, &tqparent, &tqchildren, &ntqchildren ) != 0 ) { + for( unsigned int i = 0; + i < ntqchildren && ret == None; + ++i ) + ret = findRealWindow( tqchildren[ i ], depth + 1 ); + if( tqchildren != NULL ) + XFree( tqchildren ); + } + return ret; +} + +void KSnapshot::performGrab() +{ + grabber->releaseMouse(); + grabber->hide(); + grabTimer.stop(); + XGrabServer( qt_xdisplay()); + if ( mainWidget->mode() == WindowUnderCursor ) { + Window root; + Window child; + uint tqmask; + int rootX, rootY, winX, winY; + XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child, + &rootX, &rootY, &winX, &winY, + &tqmask); + if( child == None ) + child = qt_xrootwin(); + if( !mainWidget->includeDecorations()) { + Window real_child = findRealWindow( child ); + if( real_child != None ) // test just in case + child = real_child; + } + int x, y; + unsigned int w, h; + unsigned int border; + unsigned int depth; + XGetGeometry( qt_xdisplay(), child, &root, &x, &y, + &w, &h, &border, &depth ); + w += 2 * border; + h += 2 * border; + + Window tqparent; + Window* tqchildren; + unsigned int ntqchildren; + if( XQueryTree( qt_xdisplay(), child, &root, &tqparent, + &tqchildren, &ntqchildren ) != 0 ) { + if( tqchildren != NULL ) + XFree( tqchildren ); + int newx, newy; + Window dummy; + if( XTranslateCoordinates( qt_xdisplay(), tqparent, qt_xrootwin(), + x, y, &newx, &newy, &dummy )) { + x = newx; + y = newy; + } + } + + snapshot = TQPixmap::grabWindow( qt_xrootwin(), x, y, w, h ); + +#ifdef HAVE_X11_EXTENSIONS_SHAPE_H + //No XShape - no work. + if (haveXShape) { + TQBitmap tqmask(w, h); + //As the first step, get the tqmask from XShape. + int count, order; + XRectangle* rects = XShapeGetRectangles( qt_xdisplay(), child, + ShapeBounding, &count, &order); + //The ShapeBounding region is the outermost tqshape of the window; + //ShapeBounding - ShapeClipping is defined to be the border. + //Since the border area is part of the window, we use bounding + // to limit our work region + if (rects) { + //Create a TQRegion from the rectangles describing the bounding tqmask. + TQRegion contents; + for (int pos = 0; pos < count; pos++) + contents += TQRegion(rects[pos].x, rects[pos].y, + rects[pos].width, rects[pos].height); + XFree(rects); + + //Create the bounding box. + TQRegion bbox(0, 0, snapshot.width(), snapshot.height()); + + if( border > 0 ) { + contents.translate( border, border ); + contents += TQRegion( 0, 0, border, h ); + contents += TQRegion( 0, 0, w, border ); + contents += TQRegion( 0, h - border, w, border ); + contents += TQRegion( w - border, 0, border, h ); + } + + //Get the tqmasked away area. + TQRegion tqmaskedAway = bbox - contents; + TQMemArray<TQRect> tqmaskedAwayRects = tqmaskedAway.rects(); + + //Construct a bitmap tqmask from the rectangles + TQPainter p(&tqmask); + p.fillRect(0, 0, w, h, TQt::color1); + for (uint pos = 0; pos < tqmaskedAwayRects.count(); pos++) + p.fillRect(tqmaskedAwayRects[pos], TQt::color0); + p.end(); + + snapshot.setMask(tqmask); + } + } +#endif + } + else { + snapshot = TQPixmap::grabWindow( qt_xrootwin() ); + } + XUngrabServer( qt_xdisplay()); + updatePreview(); + TQApplication::restoreOverrideCursor(); + modified = true; +// show(); + slotOk(); +} + +void KSnapshot::setTime(int newTime) +{ + mainWidget->setDelay(newTime); +} + +void KSnapshot::setURL( const TQString &url ) +{ + KURL newURL = KURL::fromPathOrURL( url ); + if ( newURL == filename ) + return; + + filename = newURL; +} + +void KSnapshot::setGrabMode( int m ) +{ + mainWidget->setMode( m ); +} + +void KSnapshot::slotMovePointer(int x, int y) +{ + TQCursor::setPos( x, y ); +} + +void KSnapshot::exit() +{ + + KConfig *conf=KGlobal::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()); + + reject(); +} + +void KSnapshot::slotOk() +{ + + KConfig *conf=KGlobal::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()); + + emit screenGrabbed(); + + accept(); +} + +#include "ksnapshot.moc" |