/* * Copyright (C) 1997-2008 Richard J. Moore * Copyright (C) 2000 Matthias Ettrich * Copyright (C) 2002 Aaron J. Seigo * Copyright (C) 2003 Nadeem Hasan * Copyright (C) 2004 Bernd Brandstetter * Copyright (C) 2006 Urs Wolfer * Copyright (C) 2010 Martin Gräßlin * Copyright (C) 2010, 2011 Pau Garcia i Quiles * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "ksnapshot.h" #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 #include #include #include #include #include #include #include "regiongrabber.h" #include "freeregiongrabber.h" #include "windowgrabber.h" #include "ksnapshotpreview.h" #include "ui_ksnapshotwidget.h" #ifdef KIPI_FOUND #include #include #include "kipiinterface.h" #include #endif #ifdef HAVE_X11_EXTENSIONS_XFIXES_H #include #include #include #endif class KSnapshotWidget : public QWidget, public Ui::KSnapshotWidget { public: KSnapshotWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); btnNew->setIcon(KIcon("ksnapshot")); } }; KSnapshot::KSnapshot(QWidget *parent, KSnapshotObject::CaptureMode mode ) : KDialog(parent), KSnapshotObject(), modified(true), savedPosition(QPoint(-1, -1)), haveXFixes(false) { // TEMPORARY Make sure "untitled" enters the string freeze for 4.6, // as explained in http://lists.kde.org/?l=kde-graphics-devel&m=128942871430175&w=2 const QString untitled = QString(i18n("untitled")); setCaption( "" ); showButtonSeparator( true ); setButtons(Help | Apply | User1 | User2); setButtonGuiItem(Apply, KStandardGuiItem::saveAs()); setButtonGuiItem(User1, KGuiItem(i18n("Copy"), "edit-copy")); setButtonGuiItem(User2, KGuiItem(i18n("Send To..."), "document-open")); setDefaultButton(Apply); grabber = new QWidget( 0, Qt::X11BypassWindowManagerHint ); // TODO X11 (Xinerama and Twinview, actually) and Windows use different coordinates for the two monitors case // // On Windows, there are two displays. The origin (0, 0) ('o') is the top left of display 1. If display 2 is to the left, then coordinates in display 2 are negative: // .-------. // | |o-----. // | 2 | | // | | 1 | // ._______.._____. // // On Xinerama and Twinview, there is only one display and two screens. The origin (0, 0) ('o') is the top left of the display: // o-------. // | |.-----. // | 2 | | // | | 1 | // ._______.._____. // // Instead of moving to (-10000, -10000), we should compute how many displays are and make sure we move to somewhere out of the total coordinates. // - Windows: use GetSystemMetrics ( http://msdn.microsoft.com/en-us/library/ms724385(v=vs.85).aspx ) // If moving to a negative position, we need to count the size of the dialog; moving to a positive position avoids having to compute the size of the dialog grabber->move( -10000, -10000 ); // FIXME Read above grabber->installEventFilter( this ); KStartupInfo::appStarted(); KVBox *vbox = new KVBox( this ); vbox->setSpacing( spacingHint() ); setMainWidget( vbox ); mainWidget = new KSnapshotWidget( vbox ); connect(mainWidget->lblImage, SIGNAL(startDrag()), SLOT(slotDragSnapshot())); connect(mainWidget->btnNew, SIGNAL(clicked()), SLOT(slotGrab())); connect(this, SIGNAL(applyClicked()), SLOT(slotSaveAs())); connect(this, SIGNAL(user1Clicked()), SLOT(slotCopy())); connect(mainWidget->comboMode, SIGNAL(activated(int)), SLOT(slotModeChanged(int))); if (qApp->desktop()->numScreens() < 2) { mainWidget->comboMode->removeItem(CurrentScreen); } openMenu = new QMenu(this); button(User2)->setMenu(openMenu); connect(openMenu, SIGNAL(aboutToShow()), this, SLOT(slotPopulateOpenMenu())); connect(openMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotOpen(QAction*))); mainWidget->spinDelay->setSuffix(ki18np(" second", " seconds")); grabber->show(); grabber->grabMouse(); KConfigGroup conf(KGlobal::config(), "GENERAL"); #ifdef KIPI_FOUND #if(KIPI_VERSION >= 0x020000) mPluginLoader = new KIPI::PluginLoader(); mPluginLoader->setInterface(new KIPIInterface(this)); mPluginLoader->init(); #else mPluginLoader = new KIPI::PluginLoader(QStringList(), new KIPIInterface(this), ""); #endif #endif #ifdef HAVE_X11_EXTENSIONS_XFIXES_H { int tmp1, tmp2; //Check whether the XFixes extension is available Display *dpy = QX11Info::display(); if (!XFixesQueryExtension( dpy, &tmp1, &tmp2 )) { mainWidget->cbIncludePointer->hide(); mainWidget->lblIncludePointer->hide(); } else { haveXFixes = true; } // actually not depending on XFixes, but to simplify the ifdefs put here // we can safely assume that XFixes is present for this functionality // it's supposed to prevent that KWin animates the window in the compositor // and XFixes is a requirement for the compositor. So if XFixes is not present // KWin cannot be compiled at all. Atom atom = XInternAtom(dpy, "_KDE_NET_WM_SKIP_CLOSE_ANIMATION", False); long d = 1; XChangeProperty(dpy, winId(), atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &d, 1); } #elif !defined(Q_WS_WIN) mainWidget->cbIncludePointer->hide(); mainWidget->lblIncludePointer->hide(); #endif setIncludePointer(conf.readEntry("includePointer", false)); setMode( conf.readEntry("mode", 0) ); // check if kwin screenshot effect is available includeAlpha = false; if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.kwin" ) ) { QDBusInterface kwinInterface( "org.kde.kwin", "/", "org.freedesktop.DBus.Introspectable" ); QDBusReply reply = kwinInterface.call( "Introspect" ); if ( reply.isValid() ) { QXmlStreamReader xml( reply.value() ); while ( !xml.atEnd() ) { xml.readNext(); if ( xml.tokenType() == QXmlStreamReader::StartElement && xml.name().toString() == "node" ) { if ( xml.attributes().value( "name" ).toString() == "Screenshot" ) { includeAlpha = true; break; } } } } } kDebug() << "Mode = " << mode; if ( mode == KSnapshotObject::FullScreen ) { snapshot = QPixmap::grabWindow( QApplication::desktop()->winId() ); #ifdef HAVE_X11_EXTENSIONS_XFIXES_H if ( haveXFixes && includePointer() ) grabPointerImage(0, 0); #endif } else if ( mode == KSnapshotObject::CurrentScreen ) { kDebug() << "Desktop Geom = " << QApplication::desktop()->geometry(); QDesktopWidget *desktop = QApplication::desktop(); int screenId = desktop->screenNumber( QCursor::pos() ); kDebug() << "Screenid = " << screenId; QRect geom = desktop->screenGeometry( screenId ); kDebug() << "Geometry = " << screenId; snapshot = QPixmap::grabWindow( desktop->winId(), geom.x(), geom.y(), geom.width(), geom.height() ); } else { setMode( mode ); switch(mode) { case KSnapshotObject::WindowUnderCursor: { setIncludeDecorations( true ); performGrab(); break; } case KSnapshotObject::ChildWindow: { slotGrab(); break; } case KSnapshotObject::Region: { grabRegion(); break; } case KSnapshotObject::FreeRegion: { grabFreeRegion(); break; } default: break; } } //When we use argument to take snapshot we mustn't hide it. if (mode != KSnapshotObject::ChildWindow) { grabber->releaseMouse(); grabber->hide(); } setDelay( conf.readEntry("delay", 0) ); setIncludeDecorations(conf.readEntry("includeDecorations",true)); filename = KUrl( conf.readPathEntry( "filename", QDir::currentPath()+'/'+i18n("snapshot")+"1.png" )); connect( &grabTimer, SIGNAL(timeout()), this, SLOT(grabTimerDone()) ); connect( &updateTimer, SIGNAL(timeout()), this, SLOT(updatePreview()) ); QTimer::singleShot( 0, this, SLOT(updateCaption()) ); KHelpMenu *helpMenu = new KHelpMenu(this, KGlobal::mainComponent().aboutData(), true); setButtonMenu( Help, helpMenu->menu() ); #if 0 accel->insert( "QuickSave", i18n("Quick Save Snapshot &As..."), i18n("Save the snapshot to the file specified by the user without showing the file dialog."), Qt::CTRL+Qt::SHIFT+Qt::Key_S, this, SLOT(slotSave())); accel->insert( "SaveAs", i18n("Save Snapshot &As..."), i18n("Save the snapshot to the file specified by the user."), Qt::CTRL+Qt::Key_A, this, SLOT(slotSaveAs())); #endif new QShortcut( KStandardShortcut::shortcut( KStandardShortcut::Quit ).primary(), this, SLOT(reject())); new QShortcut( Qt::Key_Q, this, SLOT(slotSave())); new QShortcut( KStandardShortcut::shortcut( KStandardShortcut::Copy ).primary(), button(User1), SLOT(animateClick())); new QShortcut( KStandardShortcut::shortcut( KStandardShortcut::Save ).primary(), button(Apply), SLOT(animateClick())); new QShortcut( Qt::Key_S, button(Apply), SLOT(animateClick())); new QShortcut( KStandardShortcut::shortcut( KStandardShortcut::New ).primary(), mainWidget->btnNew, SLOT(animateClick()) ); new QShortcut( Qt::Key_N, mainWidget->btnNew, SLOT(animateClick()) ); new QShortcut( Qt::Key_Space, mainWidget->btnNew, SLOT(animateClick()) ); mainWidget->btnNew->setFocus(); setInitialSize(QSize(250, 500)); KConfigGroup cg(KGlobal::config(), "MainWindow"); restoreDialogSize(cg); } KSnapshot::~KSnapshot() { delete mainWidget; } void KSnapshot::resizeEvent( QResizeEvent * ) { updateTimer.setSingleShot( true ); updateTimer.start( 200 ); } void KSnapshot::slotSave() { // Make sure the name is not already being used while(KIO::NetAccess::exists( filename, KIO::NetAccess::DestinationSide, this )) { autoincFilename(); } if ( save(filename, this) ) { modified = false; autoincFilename(); updateCaption(); } } void KSnapshot::slotSaveAs() { QStringList mimetypes = KImageIO::mimeTypes( KImageIO::Writing ); // Make sure the name is not already being used while(KIO::NetAccess::exists( filename, KIO::NetAccess::DestinationSide, this )) { autoincFilename(); } QPointer dlg = new KFileDialog( filename.url(), mimetypes.join(" "), this); dlg->setOperationMode( KFileDialog::Saving ); dlg->setCaption( i18n("Save As") ); dlg->setSelection( filename.url() ); if ( !dlg->exec() ) { delete dlg; return; } KUrl url = dlg->selectedUrl(); if ( !url.isValid() ){ delete dlg; return; } if ( save(url,this) ) { filename = url; modified = false; autoincFilename(); updateCaption(); } delete dlg; } void KSnapshot::slotCopy() { QClipboard *cb = QApplication::clipboard(); cb->setPixmap( snapshot ); } void KSnapshot::slotDragSnapshot() { QDrag *drag = new QDrag(this); drag->setMimeData(new QMimeData); drag->mimeData()->setImageData(snapshot); drag->mimeData()->setData("application/x-kde-suggestedfilename", filename.fileName().toUtf8()); drag->setPixmap(preview()); QList urls; urls << urlToOpen(); drag->mimeData()->setUrls(urls); drag->start(); } void KSnapshot::slotGrab() { savedPosition = pos(); hide(); if (delay()) { //kDebug() << "starting timer with time of" << delay(); grabTimer.start(delay()); } else { QTimer::singleShot(0, this, SLOT(startUndelayedGrab())); } } void KSnapshot::startUndelayedGrab() { if (mode() == Region) { grabRegion(); } else if ( mode() == FreeRegion ) { grabFreeRegion(); } else { grabber->show(); grabber->grabMouse(Qt::CrossCursor); } } KUrl KSnapshot::urlToOpen(bool *isTempfile) { if (isTempfile) { *isTempfile = false; } if (!modified && filename.isValid()) { return filename; } const QString fileopen = KStandardDirs::locateLocal("tmp", filename.fileName()); if (saveEqual(fileopen, this)) { if (isTempfile) { *isTempfile = true; } return fileopen; } return KUrl(); } void KSnapshot::slotOpen(const QString& application) { KUrl url = urlToOpen(); if (!url.isValid()) { return; } KUrl::List list; list.append(url); KRun::run(application, list, this); } void KSnapshot::slotOpen(QAction* action) { KSnapshotServiceAction* serviceAction = qobject_cast(action); if (!serviceAction) { return; } bool isTempfile = false; KUrl url = urlToOpen(&isTempfile); if (!url.isValid()) { return; } KUrl::List list; list.append(url); KService::Ptr service = serviceAction->service; if (!service) { QPointer dlg = new KOpenWithDialog(list, this); if (!dlg->exec()) { delete dlg; return; } service = dlg->service(); if (!service && !dlg->text().isEmpty()) { KRun::run(dlg->text(), list, this); delete dlg; return; } delete dlg; } // we have an action with a service, run it! KRun::run(*service, list, this, isTempfile); } void KSnapshot::slotPopulateOpenMenu() { QList currentActions = openMenu->actions(); foreach (QAction* currentAction, currentActions) { openMenu->removeAction(currentAction); currentAction->deleteLater(); } const KService::List services = KMimeTypeTrader::self()->query("image/png"); QMap apps; foreach (const KService::Ptr &service, services) { apps.insert(service->name(), service); } foreach (const KService::Ptr &service, apps) { QString name = service->name().replace( '&', "&&" ); openMenu->addAction(new KSnapshotServiceAction(service, KIcon(service->icon()), name, this)); } #ifdef KIPI_FOUND KIPI::PluginLoader::PluginList pluginList = mPluginLoader->pluginList(); Q_FOREACH(KIPI::PluginLoader::Info* pluginInfo, pluginList) { if (!pluginInfo->shouldLoad()) { continue; } KIPI::Plugin* plugin = pluginInfo->plugin(); if (!plugin) { kWarning() << "Plugin from library" << pluginInfo->library() << "failed to load"; continue; } plugin->setup(this); QList actions = plugin->actions(); QSet exportActions; Q_FOREACH(KAction* action, actions) { KIPI::Category category = plugin->category(action); if(category == KIPI::ExportPlugin) { exportActions << action; } else if (category == KIPI::ImagesPlugin) { // Horrible hack. Why are the print images and the e-mail images plugins in the same category as rotate and edit metadata!? if( pluginInfo->library().contains("kipiplugin_printimages") || pluginInfo->library().contains("kipiplugin_sendimages")) { exportActions << action; } } } Q_FOREACH(KAction* action, exportActions) { openMenu->addAction(action); } // FIXME: Port // plugin->actionCollection()->readShortcutSettings(); } #endif openMenu->addSeparator(); KService::Ptr none; openMenu->addAction(new KSnapshotServiceAction(none, i18n("Other Application..."), this)); } void KSnapshot::slotRegionGrabbed( const QPixmap &pix ) { if ( !pix.isNull() ) { snapshot = pix; updatePreview(); modified = true; updateCaption(); } if( mode() == KSnapshotObject::Region ) { rgnGrab->deleteLater(); } else if( mode() == KSnapshotObject::FreeRegion ) { freeRgnGrab->deleteLater(); } QApplication::restoreOverrideCursor(); show(); } void KSnapshot::slotRegionUpdated( const QRect &selection ) { lastRegion = selection; } void KSnapshot::slotFreeRegionUpdated( const QPolygon &selection ) { lastFreeRegion = selection; } void KSnapshot::slotWindowGrabbed( const QPixmap &pix ) { if ( !pix.isNull() ) { snapshot = pix; updatePreview(); modified = true; updateCaption(); } QApplication::restoreOverrideCursor(); show(); } void KSnapshot::slotScreenshotReceived( qulonglong handle ) { #ifdef Q_WS_X11 slotWindowGrabbed( QPixmap::fromX11Pixmap( handle ) ); #endif } void KSnapshot::closeEvent( QCloseEvent * e ) { KConfigGroup conf(KGlobal::config(), "GENERAL"); conf.writeEntry("delay", delay()); conf.writeEntry("mode", mode()); conf.writeEntry("includeDecorations", includeDecorations()); conf.writeEntry("includePointer", includePointer()); KConfigGroup cg(KGlobal::config(), "MainWindow"); saveDialogSize(cg); KUrl url = filename; url.setPass(QString::null); //krazy:exclude=nullstrassign for old broken gcc conf.writePathEntry("filename", url.url()); conf.sync(); e->accept(); } bool KSnapshot::eventFilter( QObject* o, QEvent* e) { if ( o == grabber && e->type() == QEvent::MouseButtonPress ) { QMouseEvent* me = (QMouseEvent*) e; if ( QWidget::mouseGrabber() != grabber ) return false; if ( me->button() == Qt::LeftButton ) performGrab(); } return false; } void KSnapshot::updatePreview() { setPreview( snapshot ); } void KSnapshot::grabRegion() { rgnGrab = new RegionGrabber(lastRegion); connect( rgnGrab, SIGNAL(regionGrabbed(QPixmap)), SLOT(slotRegionGrabbed(QPixmap)) ); connect( rgnGrab, SIGNAL(regionUpdated(QRect)), SLOT(slotRegionUpdated(QRect)) ); } void KSnapshot::grabFreeRegion() { freeRgnGrab = new FreeRegionGrabber(lastFreeRegion); connect( freeRgnGrab, SIGNAL(freeRegionGrabbed(QPixmap)), SLOT(slotRegionGrabbed(QPixmap)) ); connect( freeRgnGrab, SIGNAL(freeRegionUpdated(QPolygon)), SLOT(slotFreeRegionUpdated(QPolygon)) ); } void KSnapshot::grabTimerDone() { if ( mode() == Region ) { grabRegion(); } else if ( mode() == FreeRegion ) { grabFreeRegion(); } else { performGrab(); } KNotification::beep(i18n("The screen has been successfully grabbed.")); } void KSnapshot::performGrab() { int x = 0; int y = 0; grabber->releaseMouse(); grabber->hide(); grabTimer.stop(); title.clear(); windowClass.clear(); if ( mode() == ChildWindow ) { WindowGrabber wndGrab; connect( &wndGrab, SIGNAL(windowGrabbed(QPixmap)), SLOT(slotWindowGrabbed(QPixmap)) ); wndGrab.exec(); QPoint offset = wndGrab.lastWindowPosition(); x = offset.x(); y = offset.y(); qDebug() << "last window position is" << offset; } else if ( mode() == WindowUnderCursor ) { if ( includeAlpha ) { // use kwin effect QDBusConnection::sessionBus().connect("org.kde.kwin", "/Screenshot", "org.kde.kwin.Screenshot", "screenshotCreated", this, SLOT(slotScreenshotReceived(qulonglong))); QDBusInterface interface( "org.kde.kwin", "/Screenshot", "org.kde.kwin.Screenshot" ); int mask = 0; if ( includeDecorations() ) { mask |= 1 << 0; } if ( includePointer() ) { mask |= 1 << 1; } interface.call( "screenshotWindowUnderCursor", mask ); } else { snapshot = WindowGrabber::grabCurrent( includeDecorations() ); QPoint offset = WindowGrabber::lastWindowPosition(); x = offset.x(); y = offset.y(); // If we're showing decorations anyway then we'll add the title and window // class to the output image meta data. if ( includeDecorations() ) { title = WindowGrabber::lastWindowTitle(); windowClass = WindowGrabber::lastWindowClass(); } } } else if ( mode() == CurrentScreen ) { kDebug() << "Desktop Geom2 = " << QApplication::desktop()->geometry(); QDesktopWidget *desktop = QApplication::desktop(); int screenId = desktop->screenNumber( QCursor::pos() ); kDebug() << "Screenid2 = " << screenId; QRect geom = desktop->screenGeometry( screenId ); kDebug() << "Geometry2 = " << geom; x = geom.x(); y = geom.y(); snapshot = QPixmap::grabWindow( desktop->winId(), x, y, geom.width(), geom.height() ); } else { snapshot = QPixmap::grabWindow( QApplication::desktop()->winId() ); } #ifdef HAVE_X11_EXTENSIONS_XFIXES_H if (haveXFixes && includePointer()) { grabPointerImage(x, y); } #endif // HAVE_X11_EXTENSIONS_XFIXES_H updatePreview(); QApplication::restoreOverrideCursor(); modified = true; updateCaption(); if (savedPosition != QPoint(-1, -1)) { move(savedPosition); } show(); } void KSnapshot::grabPointerImage(int offsetx, int offsety) // Uses the X11_EXTENSIONS_XFIXES_H extension to grab the pointer image, and overlays it onto the snapshot. { #ifdef HAVE_X11_EXTENSIONS_XFIXES_H XFixesCursorImage *xcursorimg = XFixesGetCursorImage( QX11Info::display() ); if ( !xcursorimg ) return; //Annoyingly, xfixes specifies the data to be 32bit, but places it in an unsigned long * //which can be 64 bit. So we need to iterate over a 64bit structure to put it in a 32bit //structure. QVarLengthArray< quint32 > pixels( xcursorimg->width * xcursorimg->height ); for (int i = 0; i < xcursorimg->width * xcursorimg->height; ++i) pixels[i] = xcursorimg->pixels[i] & 0xffffffff; QImage qcursorimg((uchar *) pixels.data(), xcursorimg->width, xcursorimg->height, QImage::Format_ARGB32_Premultiplied); QPainter painter(&snapshot); painter.drawImage(QPointF(xcursorimg->x - xcursorimg->xhot - offsetx, xcursorimg->y - xcursorimg ->yhot - offsety), qcursorimg); XFree(xcursorimg); #else // HAVE_X11_EXTENSIONS_XFIXES_H Q_UNUSED(offsetx); Q_UNUSED(offsety); return; #endif // HAVE_X11_EXTENSIONS_XFIXES_H } void KSnapshot::setTime(int newTime) { setDelay(newTime); } int KSnapshot::timeout() const { return delay(); } void KSnapshot::setURL( const QString &url ) { changeUrl( url ); } void KSnapshot::setGrabMode( int m ) { setMode( m ); } int KSnapshot::grabMode() const { return mode(); } void KSnapshot::refreshCaption() { updateCaption(); } void KSnapshot::updateCaption() { setCaption( filename.fileName(), modified ); } void KSnapshot::slotMovePointer(int x, int y) { QCursor::setPos( x, y ); } void KSnapshot::exit() { reject(); } void KSnapshot::slotModeChanged(int mode) { mainWidget->cbIncludePointer->setEnabled(!(mode == Region || mode == FreeRegion)); mainWidget->lblIncludePointer->setEnabled(!(mode == Region || mode == FreeRegion)); mainWidget->cbIncludeDecorations->setEnabled(mode == WindowUnderCursor); mainWidget->lblIncludeDecorations->setEnabled(mode == WindowUnderCursor); } void KSnapshot::setPreview( const QPixmap &pm ) { mainWidget->lblImage->setToolTip( i18n( "Preview of the snapshot image (%1 x %2)" , pm.width(), pm.height() ) ); mainWidget->lblImage->setPreview(pm); mainWidget->lblImage->adjustSize(); } void KSnapshot::setDelay( int i ) { mainWidget->spinDelay->setValue(i); } void KSnapshot::setIncludeDecorations( bool b ) { mainWidget->cbIncludeDecorations->setChecked(b); } void KSnapshot::setIncludePointer(bool enabled) { mainWidget->cbIncludePointer->setChecked(enabled); } bool KSnapshot::includePointer() const { return mainWidget->cbIncludePointer->isChecked(); } void KSnapshot::setMode( int mode ) { mainWidget->comboMode->setCurrentIndex(mode); slotModeChanged(mode); } int KSnapshot::delay() const { return mainWidget->spinDelay->value(); } bool KSnapshot::includeDecorations() const { return mainWidget->cbIncludeDecorations->isChecked(); } int KSnapshot::mode() const { return mainWidget->comboMode->currentIndex(); } QPixmap KSnapshot::preview() { return *mainWidget->lblImage->pixmap(); } int KSnapshot::previewWidth() const { return mainWidget->lblImage->width(); } int KSnapshot::previewHeight() const { return mainWidget->lblImage->height(); } #include "moc_ksnapshot.cpp"