diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index 8a8c6f287c..581f08934b 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -92,6 +92,7 @@ if( KWIN_HAVE_OPENGL_COMPOSITING ) include( lookingglass/CMakeLists.txt ) include( magnifier/CMakeLists.txt ) include( mousemark/CMakeLists.txt ) + include( screenshot/CMakeLists.txt ) include( sharpen/CMakeLists.txt ) include( sheet/CMakeLists.txt ) include( snaphelper/CMakeLists.txt ) diff --git a/effects/screenshot/CMakeLists.txt b/effects/screenshot/CMakeLists.txt new file mode 100644 index 0000000000..b20244f6be --- /dev/null +++ b/effects/screenshot/CMakeLists.txt @@ -0,0 +1,12 @@ +####################################### +# Effect + +# Source files +set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources} + screenshot/screenshot.cpp + ) + +# .desktop files +install( FILES + screenshot/screenshot.desktop + DESTINATION ${SERVICES_INSTALL_DIR}/kwin ) diff --git a/effects/screenshot/screenshot.cpp b/effects/screenshot/screenshot.cpp new file mode 100644 index 0000000000..aaafc1f6ff --- /dev/null +++ b/effects/screenshot/screenshot.cpp @@ -0,0 +1,162 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2010 Martin Gräßlin + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . +*********************************************************************/ +#include "screenshot.h" +#include +#include +#include +#include + +namespace KWin +{ + +KWIN_EFFECT( screenshot, ScreenShotEffect ) +KWIN_EFFECT_SUPPORTED( screenshot, ScreenShotEffect::supported() ) + +bool ScreenShotEffect::supported() + { + return effects->compositingType() == KWin::OpenGLCompositing && GLRenderTarget::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()) ); + } + +ScreenShotEffect::~ScreenShotEffect() + { + } +void ScreenShotEffect::postPaintScreen() + { + effects->postPaintScreen(); + if( m_scheduledScreenshot ) + { + int w = displayWidth(); + int h = displayHeight(); + if( !GLTexture::NPOTTextureSupported() ) + { + w = nearestPowerOfTwo( w ); + h = nearestPowerOfTwo( h ); + } + GLTexture* offscreenTexture = new GLTexture( w, h ); + offscreenTexture->setFilter( GL_LINEAR ); + offscreenTexture->setWrapMode( GL_CLAMP_TO_EDGE ); + GLRenderTarget* target = new GLRenderTarget( offscreenTexture ); + if( target->valid() ) + { + WindowPaintData d( m_scheduledScreenshot ); + double left = 0; + double top = 0; + double right = m_scheduledScreenshot->width(); + double bottom = m_scheduledScreenshot->height(); + 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()); + } + int width = right - left; + int height = bottom - top; + d.xTranslate = -m_scheduledScreenshot->x() - left; + d.yTranslate = -m_scheduledScreenshot->y() - top; + // render window into offscreen texture + int mask = PAINT_WINDOW_TRANSFORMED | PAINT_WINDOW_TRANSLUCENT; + effects->pushRenderTarget( target ); + glClear( GL_COLOR_BUFFER_BIT ); + effects->drawWindow( m_scheduledScreenshot, mask, QRegion( 0, 0, width, height ), d ); + // Create a scratch texture and copy the rendered window into it + GLTexture* tex = new GLTexture( width, height ); + tex->setFilter( GL_LINEAR ); + tex->setWrapMode( GL_CLAMP_TO_EDGE ); + tex->bind(); + + glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, offscreenTexture->height() - height, width, height ); + effects->popRenderTarget(); + // copy content from GL texture into image + QImage img( QSize( width, height ), QImage::Format_ARGB32 ); + tex->bind(); + glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits() ); + 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 ) ) + { + file = QString( filePart + '_' + QString::number( counter ) + ".png" ); + counter++; + } + img.save( file ); + } + delete offscreenTexture; + delete target; + m_scheduledScreenshot = NULL; + } + } + +void ScreenShotEffect::screenshot() + { + EffectWindow* w = effects->activeWindow(); + m_scheduledScreenshot = w; + w->addRepaintFull(); + } + +void ScreenShotEffect::convertFromGLImage(QImage &img, int w, int h) +{ + // from QtOpenGL/qgl.cpp + // Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + // see http://qt.gitorious.org/qt/qt/blobs/master/src/opengl/qgl.cpp + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + // OpenGL gives RGBA; Qt wants ARGB + uint *p = (uint*)img.bits(); + uint *end = p + w*h; + while (p < end) { + uint a = *p << 24; + *p = (*p >> 8) | a; + p++; + } + } else { + // OpenGL gives ABGR (i.e. RGBA backwards); Qt wants ARGB + for (int y = 0; y < h; y++) { + uint *q = (uint*)img.scanLine(y); + for (int x=0; x < w; ++x) { + const uint pixel = *q; + *q = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) + | (pixel & 0xff00ff00); + + q++; + } + } + + } + img = img.mirrored(); +} + +} // namespace diff --git a/effects/screenshot/screenshot.desktop b/effects/screenshot/screenshot.desktop new file mode 100644 index 0000000000..7355a8d55b --- /dev/null +++ b/effects/screenshot/screenshot.desktop @@ -0,0 +1,17 @@ +[Desktop Entry] +Name=Screenshot +Icon=preferences-system-windows-effect-screenshot +Comment=Saves screenshot of active window into the home directory + +Type=Service +X-KDE-ServiceTypes=KWin/Effect +X-KDE-PluginInfo-Author=Martin Gräßlin +X-KDE-PluginInfo-Email=kde@martin-graesslin.com +X-KDE-PluginInfo-Name=kwin4_effect_screenshot +X-KDE-PluginInfo-Version=0.1.0 +X-KDE-PluginInfo-Category=Appearance +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-Library=kwin4_effect_builtins +X-KDE-Ordering=50 diff --git a/effects/screenshot/screenshot.h b/effects/screenshot/screenshot.h new file mode 100644 index 0000000000..41cc8b006f --- /dev/null +++ b/effects/screenshot/screenshot.h @@ -0,0 +1,49 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2010 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . +*********************************************************************/ + +#ifndef KWIN_SCREENSHOT_H +#define KWIN_SCREENSHOT_H + +#include +#include + +namespace KWin +{ + +class ScreenShotEffect : public QObject, public Effect + { + Q_OBJECT + public: + ScreenShotEffect(); + virtual ~ScreenShotEffect(); + virtual void postPaintScreen(); + + static bool supported(); + static void convertFromGLImage(QImage &img, int w, int h); + public Q_SLOTS: + void screenshot(); + + private: + EffectWindow *m_scheduledScreenshot; + }; + +} // namespace + +#endif // KWIN_SCREENSHOT_H