2
* kate: space-indent on; tab-width 8; indent-width 4; indent-mode cstyle;
4
* This file is part of the KDE project, module kdesktop.
5
* Copyright (C) 1999 Geert Jansen <g.t.jansen@stud.tue.nl>
7
* You can Freely distribute this program under the GNU Library General
8
* Public License. See the file "COPYING.LIB" for the exact licensing terms.
13
#include <config-workspace.h>
24
#include <QDesktopWidget>
25
#include <QPaintEngine>
30
#include <kapplication.h>
32
#include <kstandarddirs.h>
33
#include <kimageeffect.h>
34
#include <k3process.h>
35
#include <ktemporaryfile.h>
37
#include <kfilemetainfo.h>
39
#include <ksvgrenderer.h>
41
#include "bgdefaults.h"
47
/**** KBackgroundRenderer ****/
50
KBackgroundRenderer::KBackgroundRenderer(int desk, int screen, bool drawBackgroundPerScreen, const KSharedConfigPtr &config, bool kdmMode)
51
: KBackgroundSettings(desk, screen, drawBackgroundPerScreen, config, kdmMode)
54
m_isBusyCursor = false;
55
m_enableBusyCursor = false;
56
m_pDirs = KGlobal::dirs();
57
m_rSize = m_Size = drawBackgroundPerScreen ?
58
QApplication::desktop()->screenGeometry(screen).size() : QApplication::desktop()->size();
63
m_TilingEnabled = false;
65
m_pTimer = new QTimer(this);
66
m_pTimer->setSingleShot(true);
67
connect(m_pTimer, SIGNAL(timeout()), SLOT(render()));
71
KBackgroundRenderer::~KBackgroundRenderer()
79
void KBackgroundRenderer::setSize(const QSize &size)
81
m_rSize = m_Size = size;
85
* Re-configure because the desktop has been resized.
87
void KBackgroundRenderer::desktopResized()
90
m_rSize = drawBackgroundPerScreen() ?
91
QApplication::desktop()->screenGeometry(screen()).size() : QApplication::desktop()->size();
97
void KBackgroundRenderer::tile(QImage& dest, const QRect &_rect, const QImage& src)
103
int h = rect.height(), w = rect.width();
104
int offx = rect.x(), offy = rect.y();
105
int sw = src.width(), sh = src.height();
107
for (y=offy; y<offy+h; y++)
108
for (x=offx; x<offx+w; x++)
109
dest.setPixel(x, y, src.pixel(x%sw, y%sh));
114
* Build a command line to run the program.
117
QString KBackgroundRenderer::buildCommand()
124
cmd = previewCommand();
131
while ((pos = cmd.indexOf('%', pos)) != -1) {
133
if (pos == (int) (cmd.length() - 1))
136
switch (cmd.at(pos+1).toLatin1()) {
139
cmd.replace(pos, 2, K3ShellProcess::quote(m_Tempfile->fileName()));
140
pos += m_Tempfile->fileName().length() - 2;
144
num.setNum(m_Size.width());
145
cmd.replace(pos, 2, num);
146
pos += num.length() - 2;
150
num.setNum(m_Size.height());
151
cmd.replace(pos, 2, num);
152
pos += num.length() - 2;
156
cmd.replace(pos, 2, "%");
167
* Create a background tile. If the background mode is `Program',
168
* this is asynchronous.
170
int KBackgroundRenderer::doBackground(bool quit)
172
if (m_State & BackgroundDone)
174
int bgmode = backgroundMode();
180
if (bgmode == Program && m_pProc)
188
static unsigned int tileWidth = 0;
189
static unsigned int tileHeight = 0;
192
int tile_val = QPixmap::defaultDepth() >= 24 ? 1 : 2;
193
// some dithering may be needed even with bpb==15/16, so don't use tileWidth==1
195
// with tileWidth>2, repainting the desktop causes nasty effect (XFree86 4.1.0 )
196
if( XQueryBestTile( QX11Info::display(), QX11Info::appRootWindow(), tile_val, tile_val,
197
&tileWidth, &tileHeight ) != Success )
198
tileWidth = tileHeight = tile_val; // some defaults
203
// this can be tiled correctly without problems
204
m_Background = QImage( tileWidth, tileHeight, QImage::Format_RGB32 );
205
m_Background.fill(colorA().rgb());
210
if (pattern().isEmpty())
212
file = m_pDirs->findResource("dtop_pattern", pattern());
216
m_Background.load(file);
217
if (m_Background.isNull())
219
int w = m_Background.width();
220
int h = m_Background.height();
221
if ((w > m_Size.width()) || (h > m_Size.height())) {
222
w = qMin(w, m_Size.width());
223
h = qMin(h, m_Size.height());
224
m_Background = m_Background.copy(0, 0, w, h);
226
KImageEffect::flatten(m_Background, colorA(), colorB(), 0);
230
if (m_State & BackgroundStarted)
232
m_State |= BackgroundStarted;
235
file = buildCommand();
240
m_pProc = new K3ShellProcess;
242
connect(m_pProc, SIGNAL(processExited(K3Process *)),
243
SLOT(slotBackgroundDone(K3Process *)));
244
m_pProc->start(K3ShellProcess::NotifyOnExit);
248
case HorizontalGradient:
251
// on <16bpp displays the gradient sucks when tiled because of dithering
253
size.setHeight( tileHeight );
254
m_Background = KImageEffect::gradient(size, colorA(), colorB(),
255
KImageEffect::HorizontalGradient, 0);
258
case VerticalGradient:
261
// on <16bpp displays the gradient sucks when tiled because of dithering
263
size.setWidth( tileWidth );
264
m_Background = KImageEffect::gradient(size, colorA(), colorB(),
265
KImageEffect::VerticalGradient, 0);
268
case PyramidGradient:
269
m_Background = KImageEffect::gradient(m_Size, colorA(), colorB(),
270
KImageEffect::PyramidGradient, 0);
273
case PipeCrossGradient:
274
m_Background = KImageEffect::gradient(m_Size, colorA(), colorB(),
275
KImageEffect::PipeCrossGradient, 0);
278
case EllipticGradient:
279
m_Background = KImageEffect::gradient(m_Size, colorA(), colorB(),
280
KImageEffect::EllipticGradient, 0);
285
m_State |= BackgroundDone;
291
int KBackgroundRenderer::doWallpaper(bool quit)
293
if (m_State & WallpaperDone)
297
// currently no asynch. wallpapers
300
int wpmode= enabled()?wallpaperMode():NoWallpaper;
302
m_Wallpaper = QImage();
303
if (wpmode != NoWallpaper) {
305
if (currentWallpaper().isEmpty()) {
306
wpmode = NoWallpaper;
309
QString file = m_pDirs->findResource("wallpaper", currentWallpaper());
310
if (file.isEmpty()) {
311
wpmode = NoWallpaper;
315
// _Don't_ use KMimeType, as it relies on ksycoca which we really
316
// don't want in krootimage (kdm context).
317
//if ( KMimeType::findByPath( file )->is( "image/svg+xml" ) ) {
318
if (file.endsWith(".svg") || file.endsWith(".svgz")) {
320
// Special stuff for SVG icons
323
//ksvgiconloader doesn't seem to let us find out the
324
//ratio of width to height so for the most part we just
325
//assume it's a square
332
svgHeight = (int)(m_Size.height() * 0.8);
333
svgWidth = svgHeight;
337
svgHeight = (int)(m_Size.height() * 0.5);
338
svgWidth = svgHeight;
341
svgHeight = m_Size.height();
342
svgWidth = m_Size.width();
347
svgHeight = m_Size.height();
348
svgWidth = svgHeight;
352
kWarning() << "unknown diagram type" ;
353
svgHeight = m_Size.height();
354
svgWidth = svgHeight;
357
//FIXME hack due to strangeness with
358
//background control modules
359
if ( svgHeight < 200 ) {
364
KSvgRenderer renderer(file);
365
if (renderer.isValid()) {
366
m_Wallpaper = QImage(svgWidth, svgHeight, QImage::Format_ARGB32_Premultiplied);
368
QPainter p(&m_Wallpaper);
372
m_Wallpaper.load(file);
374
if (m_Wallpaper.isNull()) {
375
kWarning() << "failed to load wallpaper " << file ;
376
if (discardCurrentWallpaper())
378
wpmode = NoWallpaper;
381
m_Wallpaper = m_Wallpaper.convertToFormat(QImage::Format_ARGB32_Premultiplied, Qt::DiffuseAlphaDither);
383
// If we're previewing, scale the wallpaper down to make the preview
384
// look more like the real desktop.
386
int xs = m_Wallpaper.width() * m_Size.width() / m_rSize.width();
387
int ys = m_Wallpaper.height() * m_Size.height() / m_rSize.height();
388
if ((xs < 1) || (ys < 1))
392
if( m_WallpaperRect.size() != QSize( xs, ys ))
393
m_Wallpaper = m_Wallpaper.scaled(xs, ys, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
396
// HACK: Use KFileMetaInfo only when we have a KApplication
397
// KFileMetaInfo needs ksycoca and so on, but this code is
398
// used also in krootimage (which in turn is used by kdm).
400
KFileMetaInfo metaInfo(file);
401
if (metaInfo.isValid() && metaInfo.item("Orientation").isValid()) {
402
switch (metaInfo.item("Orientation").value().toInt()) {
404
// Flipped horizontally
405
m_Wallpaper.mirrored(true, false);
408
// Rotated 180 degrees
409
m_Wallpaper = KImageEffect::rotate(m_Wallpaper, KImageEffect::Rotate180);
412
// Flipped vertically
413
m_Wallpaper = m_Wallpaper.mirrored(false, true);
416
// Rotated 90 degrees & flipped horizontally
417
m_Wallpaper = KImageEffect::rotate(m_Wallpaper, KImageEffect::Rotate90).mirrored(true, false);
420
// Rotated 90 degrees
421
m_Wallpaper = KImageEffect::rotate(m_Wallpaper, KImageEffect::Rotate90);
424
// Rotated 90 degrees & flipped vertically
425
m_Wallpaper = KImageEffect::rotate(m_Wallpaper, KImageEffect::Rotate90).mirrored(false, true);
428
// Rotated 270 degrees
429
m_Wallpaper = KImageEffect::rotate(m_Wallpaper, KImageEffect::Rotate270);
433
// Normal or invalid orientation
441
if (m_Background.isNull()) {
442
m_Background = QImage(8, 8, QImage::Format_RGB32);
443
m_Background.fill(colorA().rgb());
448
// desktop width/height
449
int w = m_Size.width();
450
int h = m_Size.height();
452
// wallpaper width/height
453
int ww = m_Wallpaper.width();
454
int wh = m_Wallpaper.height();
456
// to be filled destination rectangle; may exceed desktop!
457
m_WallpaperRect = QRect();
464
m_WallpaperRect.setRect((w - ww) / 2, (h - wh) / 2, ww, wh);
467
m_WallpaperRect.setRect(0, 0, w, h);
470
m_WallpaperRect.setCoords(-ww + ((w - ww) / 2) % ww, -wh + ((h - wh) / 2) % wh, w-1, h-1);
475
if( m_WallpaperRect.size() != QSize( w, h ))
476
m_Wallpaper = m_Wallpaper.scaled( w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
477
m_WallpaperRect.setRect(0, 0, w, h);
480
if( ww <= w && wh <= h ) {
481
m_WallpaperRect.setRect((w - ww) / 2, (h - wh) / 2, ww, wh); // like Centred
487
double sx = (double) w / ww;
488
double sy = (double) h / wh;
496
if( m_WallpaperRect.size() != QSize( ww, wh ))
497
m_Wallpaper = m_Wallpaper.scaled(ww, wh, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
498
m_WallpaperRect.setRect((w - ww) / 2, (h - wh) / 2, ww, wh);
503
double sx = (double) w / ww;
504
double sy = (double) h / wh;
512
if( m_WallpaperRect.size() != QSize( ww, wh ))
513
m_Wallpaper = m_Wallpaper.scaled(ww, wh, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
514
m_WallpaperRect.setRect(0, 0, w, h);
519
double sx = (double) w / ww;
520
double sy = (double) h / wh;
522
//Case 1: x needs bigger scaling. Lets increase x and leave part of y offscreen
526
//Case 2: y needs bigger scaling. Lets increase y and leave part of x offscreen
530
if( m_WallpaperRect.size() != QSize( ww, wh ))
531
m_Wallpaper = m_Wallpaper.scaled(ww, wh, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
532
m_WallpaperRect.setRect((w - ww) / 2, (h - wh) / 2,w, h);
540
m_State |= WallpaperDone;
545
bool KBackgroundRenderer::canTile() const
547
return m_TilingEnabled && optimize();
550
void KBackgroundRenderer::wallpaperBlend()
552
if( !enabled() || wallpaperMode() == NoWallpaper
553
|| (blendMode() == NoBlending &&
554
( QApplication::desktop()->paintEngine()->hasFeature(QPaintEngine::Antialiasing)
555
|| !m_Wallpaper.hasAlphaChannel()))) {
556
fastWallpaperBlend();
559
fullWallpaperBlend();
563
// works only for NoBlending and no alpha in wallpaper
564
// but is much faster than QImage fidling
565
void KBackgroundRenderer::fastWallpaperBlend()
568
// copy background to m_pPixmap
569
if( !enabled() || (wallpaperMode() == NoWallpaper && canTile())) {
570
// if there's no wallpaper, no need to tile the pixmap to the size of desktop, as X does
571
// that automatically and using a smaller pixmap should save some memory
572
m_Pixmap = QPixmap::fromImage( m_Background );
575
else if( wallpaperMode() == Tiled && !m_Wallpaper.hasAlphaChannel() && canTile() && !m_bPreview ) {
576
// tiles will be tiled by X automatically
577
m_Pixmap = QPixmap::fromImage( m_Wallpaper );
580
else if( m_WallpaperRect.contains( QRect( QPoint( 0, 0 ), m_Size ))
581
&& !m_Wallpaper.hasAlphaChannel()) // wallpaper covers all and no blending
582
m_Pixmap = QPixmap( m_Size );
583
else if (m_Background.size() == m_Size)
584
m_Pixmap = QPixmap::fromImage( m_Background );
586
m_Pixmap = QPixmap( m_Size );
587
QPainter p( &m_Pixmap );
588
QPixmap pm = QPixmap::fromImage( m_Background );
589
p.drawTiledPixmap( 0, 0, m_Size.width(), m_Size.height(), pm );
592
// paint/alpha-blend wallpaper to destination rectangle of m_pPixmap
593
if (m_WallpaperRect.isValid()) {
594
QPixmap wp_pixmap = QPixmap::fromImage( m_Wallpaper );
595
QPainter pa( &m_Pixmap );
596
int ww = m_Wallpaper.width();
597
int wh = m_Wallpaper.height();
598
for (int y = m_WallpaperRect.top(); y < m_WallpaperRect.bottom(); y += wh) {
599
for (int x = m_WallpaperRect.left(); x < m_WallpaperRect.right(); x += ww) {
600
pa.drawPixmap( x, y, wp_pixmap );
607
void KBackgroundRenderer::fullWallpaperBlend()
609
m_Pixmap = QPixmap();
611
// desktop width/height
612
int w = m_Size.width();
613
int h = m_Size.height();
615
// copy background to m_pImage
616
if (m_Background.size() == m_Size) {
617
m_Image = m_Background.copy();
619
if (m_Image.depth() < 32) {
620
m_Image = m_Image.convertToFormat(QImage::Format_ARGB32_Premultiplied, Qt::DiffuseAlphaDither);
623
m_Image = QImage(w, h, QImage::Format_RGB32);
624
tile(m_Image, QRect(0, 0, w, h), m_Background);
627
// blend wallpaper to destination rectangle of m_pImage
628
if (m_WallpaperRect.isValid())
630
int blendFactor = 100;
631
if (blendMode() == FlatBlending)
632
blendFactor = (blendBalance()+200)/4;
633
int ww = m_Wallpaper.width();
634
int wh = m_Wallpaper.height();
635
for (int y = m_WallpaperRect.top(); y < m_WallpaperRect.bottom(); y += wh) {
636
for (int x = m_WallpaperRect.left(); x < m_WallpaperRect.right(); x += ww) {
637
blend(m_Image, QRect(x, y, ww, wh), m_Wallpaper,
638
QPoint(-qMin(x, 0), -qMin(y, 0)), blendFactor);
644
// blend whole desktop
645
if ( wallpaperMode() != NoWallpaper) {
646
int bal = blendBalance();
648
switch( blendMode() ) {
649
case HorizontalBlending:
650
KImageEffect::blend( m_Image, m_Background,
651
KImageEffect::HorizontalGradient,
655
case VerticalBlending:
656
KImageEffect::blend( m_Image, m_Background,
657
KImageEffect::VerticalGradient,
661
case PyramidBlending:
662
KImageEffect::blend( m_Image, m_Background,
663
KImageEffect::PyramidGradient,
667
case PipeCrossBlending:
668
KImageEffect::blend( m_Image, m_Background,
669
KImageEffect::PipeCrossGradient,
673
case EllipticBlending:
674
KImageEffect::blend( m_Image, m_Background,
675
KImageEffect::EllipticGradient,
679
case IntensityBlending:
680
KImageEffect::modulate( m_Image, m_Background, reverseBlending(),
681
KImageEffect::Intensity, bal, KImageEffect::All );
684
case SaturateBlending:
685
KImageEffect::modulate( m_Image, m_Background, reverseBlending(),
686
KImageEffect::Saturation, bal, KImageEffect::Gray );
689
case ContrastBlending:
690
KImageEffect::modulate( m_Image, m_Background, reverseBlending(),
691
KImageEffect::Contrast, bal, KImageEffect::All );
694
case HueShiftBlending:
695
KImageEffect::modulate( m_Image, m_Background, reverseBlending(),
696
KImageEffect::HueShift, bal, KImageEffect::Gray );
706
/* Alpha blend an area from <src> with offset <soffs> to rectangle <dr> of <dst>
707
* Default offset is QPoint(0, 0).
708
* blendfactor = [0, 100%]
710
void KBackgroundRenderer::blend(QImage& dst, const QRect &_dr, const QImage& src, const QPoint &soffs, int blendFactor)
716
for (y = 0; y < dr.height(); y++) {
717
if (dst.scanLine(dr.y() + y) && src.scanLine(soffs.y() + y)) {
720
for (x = 0; x < dr.width(); x++) {
721
b = reinterpret_cast<QRgb*>(dst.scanLine(dr.y() + y)
722
+ (dr.x() + x) * sizeof(QRgb));
723
d = reinterpret_cast<const QRgb*>(src.scanLine(soffs.y() + y)
724
+ (soffs.x() + x) * sizeof(QRgb));
725
a = (qAlpha(*d) * blendFactor) / 100;
726
*b = qRgb(qRed(*b) - (((qRed(*b) - qRed(*d)) * a) >> 8),
727
qGreen(*b) - (((qGreen(*b) - qGreen(*d)) * a) >> 8),
728
qBlue(*b) - (((qBlue(*b) - qBlue(*d)) * a) >> 8));
736
void KBackgroundRenderer::slotBackgroundDone(K3Process *process)
738
Q_ASSERT(process == m_pProc);
739
m_State |= BackgroundDone;
741
if (m_pProc->normalExit() && !m_pProc->exitStatus()) {
742
m_Background.load(m_Tempfile->fileName());
743
m_State |= BackgroundDone;
746
delete m_Tempfile; m_Tempfile = 0;
748
setBusyCursor(false);
754
* Starts the rendering process.
756
void KBackgroundRenderer::start(bool enableBusyCursor)
758
m_enableBusyCursor = enableBusyCursor;
769
* This slot is connected to a timer event. It is called repeatedly until
770
* the rendering is done.
772
void KBackgroundRenderer::render()
775
if (!(m_State & Rendering))
778
if( !(m_State & InitCheck)) {
779
QString f = cacheFileName();
780
if( useCacheFile()) {
781
QString w = m_pDirs->findResource("wallpaper", currentWallpaper());
784
if( wi.lastModified().isValid() && fi.lastModified().isValid()
785
&& wi.lastModified() < fi.lastModified()) {
787
if( im.load( f, "PNG" )) {
789
m_Pixmap = QPixmap::fromImage( m_Image );
791
m_State |= InitCheck | BackgroundDone | WallpaperDone;
796
m_State |= InitCheck;
802
if (!(m_State & BackgroundDone)) {
803
ret = doBackground();
809
// No async wallpaper
813
setBusyCursor(false);
818
* Rendering is finished.
820
void KBackgroundRenderer::done()
822
setBusyCursor(false);
824
emit imageDone(desk(), screen());
825
if(backgroundMode() == Program && m_pProc &&
826
m_pProc->normalExit() && m_pProc->exitStatus()) {
827
emit programFailure(desk(), m_pProc->exitStatus());
828
} else if(backgroundMode() == Program && m_pProc &&
829
!m_pProc->normalExit()) {
830
emit programFailure(desk(), -1);
831
} else if(backgroundMode() == Program) {
832
emit programSuccess(desk());
837
* This function toggles a busy cursor on and off, for use in rendering.
838
* It is useful because of the ASYNC nature of the rendering - it is hard
839
* to make sure we don't set the busy cursor twice, but only restore
842
void KBackgroundRenderer::setBusyCursor(bool isBusy) {
843
if(m_isBusyCursor == isBusy)
845
if (isBusy && !m_enableBusyCursor)
847
m_isBusyCursor = isBusy;
849
QApplication::setOverrideCursor( QCursor(Qt::BusyCursor) );
851
QApplication::restoreOverrideCursor();
855
* Stop the rendering.
857
void KBackgroundRenderer::stop()
859
if (!(m_State & Rendering))
869
* Cleanup after rendering.
871
void KBackgroundRenderer::cleanup()
873
setBusyCursor(false);
874
m_Background = QImage();
876
m_Pixmap = QPixmap();
877
m_Wallpaper = QImage();
878
delete m_pProc; m_pProc = 0L;
880
m_WallpaperRect = QRect();
885
void KBackgroundRenderer::setPreview(const QSize &size)
896
QPixmap KBackgroundRenderer::pixmap()
898
if (m_State & AllDone) {
899
if( m_Pixmap.isNull())
900
m_Pixmap = QPixmap::fromImage( m_Image );
906
QImage KBackgroundRenderer::image()
908
if (m_State & AllDone) {
909
if( m_Image.isNull())
910
fullWallpaperBlend(); // create from m_Pixmap
917
void KBackgroundRenderer::load(int desk, int screen, bool drawBackgroundPerScreen, bool reparseConfig)
919
if (m_State & Rendering)
926
KBackgroundSettings::load(desk, screen, drawBackgroundPerScreen, reparseConfig);
929
void KBackgroundRenderer::createTempFile()
932
m_Tempfile = new KTemporaryFile();
937
QString KBackgroundRenderer::cacheFileName()
939
QString f = fingerprint();
940
f.replace ( ':', '_' ); // avoid characters that shouldn't be in filenames
941
f.replace ( '/', '#' );
942
f = KStandardDirs::locateLocal( "cache", QString( "background/%1x%2_%3.png" )
943
.arg( m_Size.width()).arg( m_Size.height()).arg( f ));
947
bool KBackgroundRenderer::useCacheFile() const
951
if( backgroundMode() == Program )
952
return false; // don't cache these at all
953
if( wallpaperMode() == NoWallpaper )
954
return false; // generating only background patterns should be always faster
955
QString file = currentWallpaper();
956
if( file.endsWith(".svg") || file.endsWith(".svgz"))
957
return true; // cache these, they can be bloody slow
958
switch( backgroundMode())
964
return false; // these don't need scaling
975
void KBackgroundRenderer::saveCacheFile()
977
if( !( m_State & AllDone ))
981
if( m_Image.isNull())
982
fullWallpaperBlend(); // generate from m_Pixmap
983
QString f = cacheFileName();
984
if( KStandardDirs::exists( f ) || m_Cached )
985
utime( QFile::encodeName( f ), NULL );
987
m_Image.save( f, "PNG" );
988
// remove old entries from the cache
989
QDir dir( KStandardDirs::locateLocal( "cache", "background/" ));
990
const QFileInfoList list = dir.entryInfoList( QStringList() << "*.png", QDir::Files, QDir::Time | QDir::Reversed );
991
if( !list.isEmpty()) {
993
Q_FOREACH( QFileInfo info, list )
995
Q_FOREACH( QFileInfo info, list ) {
996
if( size < 8 * 1024 * 1024 )
998
// keep everything newer than 10 minutes if the total size is less than 50M (just in case)
999
if( size < 50 * 1024 * 1024
1000
&& ( time_t ) info.lastModified().toTime_t() >= time( NULL ) - 10 * 60 )
1002
size -= info.size();
1003
QFile::remove( info.absoluteFilePath());
1009
//BEGIN class KVirtualBGRenderer
1010
KVirtualBGRenderer::KVirtualBGRenderer(int desk, const KSharedConfigPtr &config, bool kdmMode)
1017
m_kdmMode = kdmMode;
1019
// The following code is borrowed from KBackgroundSettings::KBackgroundSettings
1021
int screen_number = 0;
1022
if (QX11Info::display())
1023
screen_number = DefaultScreen(QX11Info::display());
1025
if (screen_number == 0)
1026
configname = "kdesktoprc";
1028
configname.sprintf("kdesktop-screen-%drc", screen_number);
1030
m_pConfig = KSharedConfig::openConfig(configname, KConfig::NoGlobals);
1036
m_size = QApplication::desktop()->size();
1039
KVirtualBGRenderer::~KVirtualBGRenderer()
1041
for (unsigned i=0; i<m_numRenderers; ++i)
1042
delete m_renderer[i];
1048
KBackgroundRenderer * KVirtualBGRenderer::renderer(unsigned screen)
1050
return m_renderer[screen];
1054
QPixmap KVirtualBGRenderer::pixmap()
1056
if (m_numRenderers == 1)
1057
return m_renderer[0]->pixmap();
1063
bool KVirtualBGRenderer::needProgramUpdate()
1065
for (unsigned i=0; i<m_numRenderers; ++i)
1067
if ( m_renderer[i]->backgroundMode() == KBackgroundSettings::Program &&
1068
m_renderer[i]->KBackgroundProgram::needUpdate() )
1075
void KVirtualBGRenderer::programUpdate()
1077
for (unsigned i=0; i<m_numRenderers; ++i)
1079
if ( m_renderer[i]->backgroundMode() == KBackgroundSettings::Program &&
1080
m_renderer[i]->KBackgroundProgram::needUpdate() )
1082
m_renderer[i]->KBackgroundProgram::update();
1088
bool KVirtualBGRenderer::needWallpaperChange()
1090
for (unsigned i=0; i<m_numRenderers; ++i)
1092
if ( m_renderer[i]->needWallpaperChange() )
1099
void KVirtualBGRenderer::changeWallpaper()
1101
for (unsigned i=0; i<m_numRenderers; ++i)
1103
m_renderer[i]->changeWallpaper();
1108
int KVirtualBGRenderer::hash()
1111
for (unsigned i=0; i<m_numRenderers; ++i)
1113
fp += m_renderer[i]->fingerprint();
1116
kDebug() << " fp=\""<<fp<<"\" h="<<h;
1121
bool KVirtualBGRenderer::isActive()
1123
for (unsigned i=0; i<m_numRenderers; ++i)
1125
if ( m_renderer[i]->isActive() )
1132
void KVirtualBGRenderer::setEnabled(bool enable)
1134
for (unsigned i=0; i<m_numRenderers; ++i)
1135
m_renderer[i]->setEnabled(enable);
1139
void KVirtualBGRenderer::desktopResized()
1141
m_size = QApplication::desktop()->size();
1146
m_pPixmap = new QPixmap(m_size);
1147
m_pPixmap->fill(Qt::black);
1150
for (unsigned i=0; i<m_numRenderers; ++i)
1151
m_renderer[i]->desktopResized();
1155
void KVirtualBGRenderer::setPreview(const QSize & size)
1163
*m_pPixmap = QPixmap(m_size);
1166
m_scaleX = float(m_size.width()) / float(QApplication::desktop()->size().width());
1167
m_scaleY = float(m_size.height()) / float(QApplication::desktop()->size().height());
1169
// Scale renderers appropriately
1170
for (unsigned i=0; i<m_renderer.size(); ++i)
1172
QSize unscaledRendererSize = renderSize(i);
1174
m_renderer[i]->setPreview( QSize(
1175
int(unscaledRendererSize.width() * m_scaleX),
1176
int(unscaledRendererSize.height() * m_scaleY) ) );
1181
QSize KVirtualBGRenderer::renderSize(int screen)
1183
return m_bDrawBackgroundPerScreen ?
1184
QApplication::desktop()->screenGeometry(screen).size() : QApplication::desktop()->size();
1188
void KVirtualBGRenderer::initRenderers()
1190
KConfigGroup cg(m_pConfig, "Background Common");
1191
m_bDrawBackgroundPerScreen = cg.readEntry( QString("DrawBackgroundPerScreen_%1").arg(m_desk), _defDrawBackgroundPerScreen );
1193
m_bCommonScreen = cg.readEntry("CommonScreen", _defCommonScreen);
1195
m_numRenderers = m_bDrawBackgroundPerScreen ? QApplication::desktop()->numScreens() : 1;
1197
m_bFinished.resize(m_numRenderers);
1198
m_bFinished.fill(false);
1200
if (m_numRenderers == m_renderer.size())
1203
for (unsigned i=0; i<m_renderer.size(); ++i)
1204
delete m_renderer[i];
1206
m_renderer.resize(m_numRenderers);
1207
for (unsigned i=0; i<m_numRenderers; ++i)
1209
int eScreen = m_bCommonScreen ? 0 : i;
1210
KBackgroundRenderer * r = new KBackgroundRenderer( m_desk, eScreen, m_bDrawBackgroundPerScreen, m_pConfig, m_kdmMode );
1211
m_renderer.insert( i, r );
1212
r->setSize(renderSize(i));
1213
connect( r, SIGNAL(imageDone(int,int)), this, SLOT(screenDone(int,int)) );
1218
void KVirtualBGRenderer::load(int desk, bool reparseConfig)
1222
m_bCommonScreen = m_pConfig->group("Background Common").readEntry("CommonScreen", _defCommonScreen);
1226
for (unsigned i=0; i<m_numRenderers; ++i)
1228
unsigned eScreen = m_bCommonScreen ? 0 : i;
1229
m_renderer[i]->load(desk, eScreen, m_bDrawBackgroundPerScreen, reparseConfig);
1234
void KVirtualBGRenderer::screenDone(int _desk, int _screen)
1239
const KBackgroundRenderer * sender = dynamic_cast<const KBackgroundRenderer*>(this->sender());
1240
int screen = m_renderer.find(sender);
1245
m_bFinished[screen] = true;
1250
// There's more than one renderer, so we are drawing each output to our own pixmap
1252
QRect overallGeometry;
1253
for (int i=0; i < QApplication::desktop()->numScreens(); ++i)
1254
overallGeometry |= QApplication::desktop()->screenGeometry(i);
1256
QPoint drawPos = QApplication::desktop()->screenGeometry(screen).topLeft() - overallGeometry.topLeft();
1257
drawPos.setX( int(drawPos.x() * m_scaleX) );
1258
drawPos.setY( int(drawPos.y() * m_scaleY) );
1260
QPixmap source = m_renderer[screen]->pixmap();
1261
QSize renderSize = this->renderSize(screen);
1262
renderSize.setWidth( int(renderSize.width() * m_scaleX) );
1263
renderSize.setHeight( int(renderSize.height() * m_scaleY) );
1265
QPainter p(m_pPixmap);
1267
if (renderSize == source.size())
1268
p.drawPixmap( drawPos, source );
1271
p.drawTiledPixmap( drawPos.x(), drawPos.y(), renderSize.width(), renderSize.height(), source );
1276
for (int i=0; i<m_bFinished.size(); ++i)
1278
if (!m_bFinished[i])
1282
emit imageDone(m_desk);
1286
void KVirtualBGRenderer::start()
1294
if (m_numRenderers > 1)
1296
m_pPixmap = new QPixmap(m_size);
1297
// If are screen sizes do not properly tile the overall virtual screen
1298
// size, then we want the untiled parts to be black for use in desktop
1300
m_pPixmap->fill(Qt::black);
1303
m_bFinished.fill(false);
1304
for (unsigned i=0; i<m_numRenderers; ++i)
1305
m_renderer[i]->start();
1309
void KVirtualBGRenderer::stop()
1311
for (unsigned i=0; i<m_numRenderers; ++i)
1312
m_renderer[i]->stop();
1316
void KVirtualBGRenderer::cleanup()
1318
m_bFinished.fill(false);
1320
for (unsigned i=0; i<m_numRenderers; ++i)
1321
m_renderer[i]->cleanup();
1327
void KVirtualBGRenderer::saveCacheFile()
1329
for (unsigned i=0; i<m_numRenderers; ++i)
1330
m_renderer[i]->saveCacheFile();
1333
void KVirtualBGRenderer::enableTiling( bool enable )
1335
for (unsigned i=0; i<m_numRenderers; ++i)
1336
m_renderer[i]->enableTiling( enable );
1339
//END class KVirtualBGRenderer
1342
#include "bgrender.moc"