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:
parent
245f00c189
commit
379e1a268b
3 changed files with 98 additions and 28 deletions
|
@ -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 )
|
||||
|
||||
|
|
|
@ -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,6 +74,8 @@ void ScreenShotEffect::postPaintScreen()
|
|||
double top = 0;
|
||||
double right = m_scheduledScreenshot->width();
|
||||
double bottom = m_scheduledScreenshot->height();
|
||||
if( m_scheduledScreenshot->hasDecoration() && m_type & INCLUDE_DECORATION )
|
||||
{
|
||||
foreach( const WindowQuad& quad, d.quads )
|
||||
{
|
||||
// we need this loop to include the decoration padding
|
||||
|
@ -79,6 +84,27 @@ void ScreenShotEffect::postPaintScreen()
|
|||
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;
|
||||
d.xTranslate = -m_scheduledScreenshot->x() - left;
|
||||
|
@ -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,12 +142,45 @@ void ScreenShotEffect::postPaintScreen()
|
|||
}
|
||||
}
|
||||
|
||||
void ScreenShotEffect::screenshot()
|
||||
void ScreenShotEffect::screenshotWindowUnderCursor(int mask)
|
||||
{
|
||||
m_type = (ScreenShotType)mask;
|
||||
const QPoint cursor = effects->cursorPos();
|
||||
foreach( EffectWindow* w, effects->stackingOrder() )
|
||||
{
|
||||
if( w->geometry().contains( cursor ) && w->isOnCurrentDesktop() && !w->isMinimized() )
|
||||
{
|
||||
EffectWindow* w = effects->activeWindow();
|
||||
m_scheduledScreenshot = w;
|
||||
w->addRepaintFull();
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue