Screenshot effect provides hooks for KSnapshot.

This adds a DBus slot to capture a window and the pixmap handle
is passed back via a DBus signal.
Previous code using a shortcut and saving to filesystem is dropped
completely in favor for ksnapshot.
See http://reviewboard.kde.org/r/4814/

svn path=/trunk/KDE/kdebase/workspace/; revision=1175353
This commit is contained in:
Martin Gräßlin 2010-09-14 19:52:44 +00:00
parent 245f00c189
commit 379e1a268b
3 changed files with 98 additions and 28 deletions

View file

@ -8,6 +8,9 @@ kde4_no_enable_final(kwineffects)
macro( KWIN4_ADD_EFFECT name )
kde4_add_plugin( kwin4_effect_${name} ${ARGN} )
target_link_libraries( kwin4_effect_${name} kwineffects ${KDE4_KDEUI_LIBS} kephal ${KDE4_PLASMA_LIBS} ${X11_Xfixes_LIB} ${X11_Xcursor_LIB})
if (X11_Xfixes_FOUND)
target_link_libraries(kwin4_effect_${name} ${X11_Xfixes_LIB})
endif (X11_Xfixes_FOUND)
install( TARGETS kwin4_effect_${name} DESTINATION ${PLUGIN_INSTALL_DIR} )
endmacro( KWIN4_ADD_EFFECT )

View file

@ -20,9 +20,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "screenshot.h"
#include <kwinglutils.h>
#include <QDir>
#include <KDE/KAction>
#include <KDE/KActionCollection>
#include <KDE/KDebug>
#include <QtDBus/QDBusConnection>
#include <QtCore/QVarLengthArray>
#include <QtGui/QPainter>
#include <X11/extensions/Xfixes.h>
#include <QX11Info>
namespace KWin
{
@ -38,15 +42,14 @@ bool ScreenShotEffect::supported()
ScreenShotEffect::ScreenShotEffect()
: m_scheduledScreenshot( 0 )
{
KActionCollection* actionCollection = new KActionCollection( this );
KAction* cubeAction = static_cast< KAction* >( actionCollection->addAction( "Screenshot Effect" ));
cubeAction->setText( i18n("Save screenshot of active window" ));
cubeAction->setGlobalShortcut( KShortcut(), KAction::ActiveShortcut);
connect( cubeAction, SIGNAL(triggered(bool)), SLOT(screenshot()) );
QDBusConnection::sessionBus().registerObject( "/Screenshot", this, QDBusConnection::ExportScriptableContents );
QDBusConnection::sessionBus().registerService( "org.kde.kwin.Screenshot" );
}
ScreenShotEffect::~ScreenShotEffect()
{
QDBusConnection::sessionBus().unregisterObject( "/Screenshot" );
QDBusConnection::sessionBus().unregisterService( "org.kde.kwin.Screenshot" );
}
void ScreenShotEffect::postPaintScreen()
{
@ -71,13 +74,36 @@ void ScreenShotEffect::postPaintScreen()
double top = 0;
double right = m_scheduledScreenshot->width();
double bottom = m_scheduledScreenshot->height();
foreach( const WindowQuad& quad, d.quads )
if( m_scheduledScreenshot->hasDecoration() && m_type & INCLUDE_DECORATION )
{
// we need this loop to include the decoration padding
left = qMin(left, quad.left());
top = qMin(top, quad.top());
right = qMax(right, quad.right());
bottom = qMax(bottom, quad.bottom());
foreach( const WindowQuad& quad, d.quads )
{
// we need this loop to include the decoration padding
left = qMin(left, quad.left());
top = qMin(top, quad.top());
right = qMax(right, quad.right());
bottom = qMax(bottom, quad.bottom());
}
}
else if( m_scheduledScreenshot->hasDecoration() )
{
WindowQuadList newQuads;
left = m_scheduledScreenshot->width();
top = m_scheduledScreenshot->height();
right = 0;
bottom = 0;
foreach( const WindowQuad& quad, d.quads )
{
if( quad.type() == WindowQuadContents )
{
newQuads << quad;
left = qMin(left, quad.left());
top = qMin(top, quad.top());
right = qMax(right, quad.right());
bottom = qMax(bottom, quad.bottom());
}
}
d.quads = newQuads;
}
int width = right - left;
int height = bottom - top;
@ -103,17 +129,12 @@ void ScreenShotEffect::postPaintScreen()
tex->unbind();
delete tex;
ScreenShotEffect::convertFromGLImage( img, width, height );
// save screenshot in home directory
QString filePart( QDir::homePath() + '/' + m_scheduledScreenshot->caption() );
QString file( filePart + ".png" );
int counter = 1;
while( QFile::exists( file ) )
if( m_type & INCLUDE_CURSOR )
{
file = QString( filePart + '_' + QString::number( counter ) + ".png" );
counter++;
grabPointerImage( img, m_scheduledScreenshot->x() + left, m_scheduledScreenshot->y() + top );
}
img.save( file );
m_lastScreenshot = QPixmap::fromImage( img );
emit screenshotCreated( m_lastScreenshot.handle() );
}
delete offscreenTexture;
delete target;
@ -121,13 +142,46 @@ void ScreenShotEffect::postPaintScreen()
}
}
void ScreenShotEffect::screenshot()
void ScreenShotEffect::screenshotWindowUnderCursor(int mask)
{
EffectWindow* w = effects->activeWindow();
m_scheduledScreenshot = w;
w->addRepaintFull();
m_type = (ScreenShotType)mask;
const QPoint cursor = effects->cursorPos();
foreach( EffectWindow* w, effects->stackingOrder() )
{
if( w->geometry().contains( cursor ) && w->isOnCurrentDesktop() && !w->isMinimized() )
{
m_scheduledScreenshot = w;
}
}
if( m_scheduledScreenshot )
{
m_scheduledScreenshot->addRepaintFull();
}
}
void ScreenShotEffect::grabPointerImage( QImage& snapshot, int offsetx, int offsety )
// Uses the X11_EXTENSIONS_XFIXES_H extension to grab the pointer image, and overlays it onto the snapshot.
{
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);
}
void ScreenShotEffect::convertFromGLImage(QImage &img, int w, int h)
{
// from QtOpenGL/qgl.cpp

View file

@ -23,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kwineffects.h>
#include <QObject>
#include <QImage>
namespace KWin
{
@ -30,7 +31,13 @@ namespace KWin
class ScreenShotEffect : public QObject, public Effect
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Screenshot")
public:
enum ScreenShotType
{
INCLUDE_DECORATION = 1 << 0,
INCLUDE_CURSOR = 1 << 1
};
ScreenShotEffect();
virtual ~ScreenShotEffect();
virtual void postPaintScreen();
@ -38,10 +45,16 @@ class ScreenShotEffect : public QObject, public Effect
static bool supported();
static void convertFromGLImage(QImage &img, int w, int h);
public Q_SLOTS:
void screenshot();
Q_SCRIPTABLE void screenshotWindowUnderCursor( int mask = 0 );
Q_SIGNALS:
Q_SCRIPTABLE void screenshotCreated( qulonglong handle );
private:
void grabPointerImage( QImage& snapshot, int offsetx, int offsety );
EffectWindow *m_scheduledScreenshot;
ScreenShotType m_type;
QPixmap m_lastScreenshot;
};
} // namespace