/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ksnapshot.h" #include "regiongrabber.h" #include "ksnapshotwidget.h" #include #include #include #ifdef HAVE_X11_EXTENSIONS_SHAPE_H #include #endif #include KSnapshot::KSnapshot(TQWidget *parent, const char *name) : super(parent, 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, parent; Window* tqchildren; unsigned int ntqchildren; Window ret = None; if( XQueryTree( qt_xdisplay(), w, &root, &parent, &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 mask; int rootX, rootY, winX, winY; XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child, &rootX, &rootY, &winX, &winY, &mask); 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 parent; Window* tqchildren; unsigned int ntqchildren; if( XQueryTree( qt_xdisplay(), child, &root, &parent, &tqchildren, &ntqchildren ) != 0 ) { if( tqchildren != NULL ) XFree( tqchildren ); int newx, newy; Window dummy; if( XTranslateCoordinates( qt_xdisplay(), parent, 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 mask(w, h); //As the first step, get the mask 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 mask. 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 masked away area. TQRegion maskedAway = bbox - contents; TQMemArray maskedAwayRects = maskedAway.rects(); //Construct a bitmap mask from the rectangles TQPainter p(&mask); p.fillRect(0, 0, w, h, TQt::color1); for (uint pos = 0; pos < maskedAwayRects.count(); pos++) p.fillRect(maskedAwayRects[pos], TQt::color0); p.end(); snapshot.setMask(mask); } } #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"