mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-23 18:32:53 +00:00
837 lines
23 KiB
C++
837 lines
23 KiB
C++
/*
|
|
* Copyright (C) 1997-2008 Richard J. Moore <rich@kde.org>
|
|
* Copyright (C) 2000 Matthias Ettrich <ettrich@troll.no>
|
|
* Copyright (C) 2002 Aaron J. Seigo <aseigo@kde.org>
|
|
* Copyright (C) 2003 Nadeem Hasan <nhasan@kde.org>
|
|
* Copyright (C) 2004 Bernd Brandstetter <bbrand@freenet.de>
|
|
* Copyright (C) 2006 Urs Wolfer <uwolfer @ kde.org>
|
|
* Copyright (C) 2010 Martin Gräßlin <kde@martin-graesslin.com>
|
|
* Copyright (C) 2010, 2011 Pau Garcia i Quiles <pgquiles@elpauer.org>
|
|
*
|
|
* 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 <QClipboard>
|
|
#include <QShortcut>
|
|
#include <QMenu>
|
|
#include <QDesktopWidget>
|
|
#include <QVarLengthArray>
|
|
#include <QDrag>
|
|
#include <QPainter>
|
|
#include <QtGui/qevent.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <KDebug>
|
|
#include <kglobal.h>
|
|
#include <kicon.h>
|
|
#include <kimageio.h>
|
|
#include <kcomponentdata.h>
|
|
#include <kfiledialog.h>
|
|
#include <kmessagebox.h>
|
|
#include <kio/netaccess.h>
|
|
#include <ksavefile.h>
|
|
#include <kstandardshortcut.h>
|
|
#include <knotification.h>
|
|
#include <khelpmenu.h>
|
|
#include <kmenu.h>
|
|
#include <kmimetypetrader.h>
|
|
#include <kopenwithdialog.h>
|
|
#include <krun.h>
|
|
#include <kstandarddirs.h>
|
|
#include <kstartupinfo.h>
|
|
#include <kvbox.h>
|
|
#include <qdebug.h>
|
|
|
|
#include "regiongrabber.h"
|
|
#include "freeregiongrabber.h"
|
|
#include "windowgrabber.h"
|
|
#include "ksnapshotpreview.h"
|
|
#include "ui_ksnapshotwidget.h"
|
|
|
|
#ifdef HAVE_X11_EXTENSIONS_XFIXES_H
|
|
#include <X11/extensions/Xfixes.h>
|
|
#include <X11/Xatom.h>
|
|
#include <QX11Info>
|
|
#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()->screenCount() < 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 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);
|
|
}
|
|
#else
|
|
mainWidget->cbIncludePointer->hide();
|
|
mainWidget->lblIncludePointer->hide();
|
|
#endif
|
|
setIncludePointer(conf.readEntry("includePointer", false));
|
|
setMode( conf.readEntry("mode", 0) );
|
|
|
|
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<KFileDialog> 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<QUrl> 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<KSnapshotServiceAction*>(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<KOpenWithDialog> 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<QAction*> currentActions = openMenu->actions();
|
|
foreach (QAction* currentAction, currentActions)
|
|
{
|
|
openMenu->removeAction(currentAction);
|
|
currentAction->deleteLater();
|
|
}
|
|
|
|
const KService::List services = KMimeTypeTrader::self()->query("image/png");
|
|
QMap<QString, KService::Ptr> 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));
|
|
}
|
|
|
|
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.setPassword(QString()); //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();
|
|
kDebug() << "last window position is" << offset;
|
|
} else if ( mode() == WindowUnderCursor ) {
|
|
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"
|