~ubuntu-branches/ubuntu/gutsy/kdebase-workspace/gutsy

« back to all changes in this revision

Viewing changes to kcontrol/background/bgrender.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2007-09-05 20:45:14 UTC
  • Revision ID: james.westby@ubuntu.com-20070905204514-632hhspl0nvrc84i
Tags: upstream-3.93.0
ImportĀ upstreamĀ versionĀ 3.93.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vi: ts=8 sts=4 sw=4
 
2
 * kate: space-indent on; tab-width 8; indent-width 4; indent-mode cstyle;
 
3
 *
 
4
 * This file is part of the KDE project, module kdesktop.
 
5
 * Copyright (C) 1999 Geert Jansen <g.t.jansen@stud.tue.nl>
 
6
 *
 
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.
 
9
 */
 
10
#include "bgrender.h"
 
11
 
 
12
#include <fixx11h.h>
 
13
#include <config-workspace.h>
 
14
 
 
15
#include <time.h>
 
16
#include <stdlib.h>
 
17
#include <utime.h>
 
18
 
 
19
#include <QTimer>
 
20
#include <QPainter>
 
21
#include <QImage>
 
22
#include <QFileInfo>
 
23
#include <QDir>
 
24
#include <QDesktopWidget>
 
25
#include <QPaintEngine>
 
26
#include <QHash>
 
27
#include <QDateTime>
 
28
#include <QPixmap>
 
29
 
 
30
#include <kapplication.h>
 
31
#include <kdebug.h>
 
32
#include <kstandarddirs.h>
 
33
#include <kimageeffect.h>
 
34
#include <k3process.h>
 
35
#include <ktemporaryfile.h>
 
36
#include <kcursor.h>
 
37
#include <kfilemetainfo.h>
 
38
#include <kconfig.h>
 
39
#include <ksvgrenderer.h>
 
40
 
 
41
#include "bgdefaults.h"
 
42
 
 
43
#include <X11/Xlib.h>
 
44
 
 
45
#include <QX11Info>
 
46
 
 
47
/**** KBackgroundRenderer ****/
 
48
 
 
49
 
 
50
KBackgroundRenderer::KBackgroundRenderer(int desk, int screen, bool drawBackgroundPerScreen, const KSharedConfigPtr &config, bool kdmMode)
 
51
    : KBackgroundSettings(desk, screen, drawBackgroundPerScreen, config, kdmMode)
 
52
{
 
53
    m_State = 0;
 
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();
 
59
    m_pProc = 0L;
 
60
    m_Tempfile = 0L;
 
61
    m_bPreview = false;
 
62
    m_Cached = false;
 
63
    m_TilingEnabled = false;
 
64
 
 
65
    m_pTimer = new QTimer(this);
 
66
    m_pTimer->setSingleShot(true);
 
67
    connect(m_pTimer, SIGNAL(timeout()), SLOT(render()));
 
68
}
 
69
 
 
70
 
 
71
KBackgroundRenderer::~KBackgroundRenderer()
 
72
{
 
73
    cleanup();
 
74
    delete m_Tempfile;
 
75
    m_Tempfile = 0;
 
76
}
 
77
 
 
78
 
 
79
void KBackgroundRenderer::setSize(const QSize &size)
 
80
{
 
81
    m_rSize = m_Size = size;
 
82
}
 
83
 
 
84
/*
 
85
 * Re-configure because the desktop has been resized.
 
86
 */
 
87
void KBackgroundRenderer::desktopResized()
 
88
{
 
89
    m_State = 0;
 
90
    m_rSize = drawBackgroundPerScreen() ?
 
91
            QApplication::desktop()->screenGeometry(screen()).size() : QApplication::desktop()->size();
 
92
    if( !m_bPreview )
 
93
        m_Size = m_rSize;
 
94
}
 
95
 
 
96
 
 
97
void KBackgroundRenderer::tile(QImage& dest, const QRect &_rect, const QImage& src)
 
98
{
 
99
    QRect rect = _rect;
 
100
    rect &= dest.rect();
 
101
 
 
102
    int x, y;
 
103
    int h = rect.height(), w = rect.width();
 
104
    int offx = rect.x(), offy = rect.y();
 
105
    int sw = src.width(), sh = src.height();
 
106
 
 
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));
 
110
}
 
111
 
 
112
 
 
113
/*
 
114
 * Build a command line to run the program.
 
115
 */
 
116
 
 
117
QString KBackgroundRenderer::buildCommand()
 
118
{
 
119
    QString num;
 
120
    int pos = 0;
 
121
 
 
122
    QString cmd;
 
123
    if (m_bPreview)
 
124
        cmd = previewCommand();
 
125
    else
 
126
        cmd = command();
 
127
 
 
128
    if (cmd.isEmpty())
 
129
        return QString();
 
130
 
 
131
    while ((pos = cmd.indexOf('%', pos)) != -1) {
 
132
 
 
133
        if (pos == (int) (cmd.length() - 1))
 
134
            break;
 
135
 
 
136
        switch (cmd.at(pos+1).toLatin1()) {
 
137
        case 'f':
 
138
            createTempFile();
 
139
            cmd.replace(pos, 2, K3ShellProcess::quote(m_Tempfile->fileName()));
 
140
            pos += m_Tempfile->fileName().length() - 2;
 
141
            break;
 
142
 
 
143
        case 'x':
 
144
            num.setNum(m_Size.width());
 
145
            cmd.replace(pos, 2, num);
 
146
            pos += num.length() - 2;
 
147
            break;
 
148
 
 
149
        case 'y':
 
150
            num.setNum(m_Size.height());
 
151
            cmd.replace(pos, 2, num);
 
152
            pos += num.length() - 2;
 
153
            break;
 
154
 
 
155
        case '%':
 
156
            cmd.replace(pos, 2, "%");
 
157
            pos--;
 
158
            break;
 
159
        }
 
160
 
 
161
    }
 
162
    return cmd;
 
163
}
 
164
 
 
165
 
 
166
/*
 
167
 * Create a background tile. If the background mode is `Program',
 
168
 * this is asynchronous.
 
169
 */
 
170
int KBackgroundRenderer::doBackground(bool quit)
 
171
{
 
172
    if (m_State & BackgroundDone)
 
173
        return Done;
 
174
    int bgmode = backgroundMode();
 
175
 
 
176
    if (!enabled())
 
177
      bgmode= Flat;
 
178
 
 
179
    if (quit) {
 
180
        if (bgmode == Program && m_pProc)
 
181
            m_pProc->kill();
 
182
        return Done;
 
183
    }
 
184
 
 
185
    int retval = Done;
 
186
    QString file;
 
187
 
 
188
    static unsigned int tileWidth = 0;
 
189
    static unsigned int tileHeight = 0;
 
190
    if( tileWidth == 0 )
 
191
        {
 
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
 
194
    // for them
 
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
 
199
    }
 
200
    switch (bgmode) {
 
201
 
 
202
    case Flat:
 
203
        // this can be tiled correctly without problems
 
204
        m_Background = QImage( tileWidth, tileHeight, QImage::Format_RGB32 );
 
205
        m_Background.fill(colorA().rgb());
 
206
        break;
 
207
 
 
208
    case Pattern:
 
209
    {
 
210
        if (pattern().isEmpty())
 
211
            break;
 
212
        file = m_pDirs->findResource("dtop_pattern", pattern());
 
213
        if (file.isEmpty())
 
214
            break;
 
215
 
 
216
        m_Background.load(file);
 
217
        if (m_Background.isNull())
 
218
            break;
 
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);
 
225
        }
 
226
        KImageEffect::flatten(m_Background, colorA(), colorB(), 0);
 
227
        break;
 
228
    }
 
229
    case Program:
 
230
        if (m_State & BackgroundStarted)
 
231
            break;
 
232
        m_State |= BackgroundStarted;
 
233
        createTempFile();
 
234
 
 
235
        file = buildCommand();
 
236
        if (file.isEmpty())
 
237
            break;
 
238
 
 
239
        delete m_pProc;
 
240
        m_pProc = new K3ShellProcess;
 
241
        *m_pProc << file;
 
242
        connect(m_pProc, SIGNAL(processExited(K3Process *)),
 
243
                SLOT(slotBackgroundDone(K3Process *)));
 
244
        m_pProc->start(K3ShellProcess::NotifyOnExit);
 
245
        retval = Wait;
 
246
        break;
 
247
 
 
248
    case HorizontalGradient:
 
249
    {
 
250
        QSize size = m_Size;
 
251
        // on <16bpp displays the gradient sucks when tiled because of dithering
 
252
        if( canTile())
 
253
            size.setHeight( tileHeight );
 
254
        m_Background = KImageEffect::gradient(size, colorA(), colorB(),
 
255
        KImageEffect::HorizontalGradient, 0);
 
256
        break;
 
257
    }
 
258
    case VerticalGradient:
 
259
    {
 
260
        QSize size = m_Size;
 
261
        // on <16bpp displays the gradient sucks when tiled because of dithering
 
262
        if( canTile())
 
263
            size.setWidth( tileWidth );
 
264
        m_Background = KImageEffect::gradient(size, colorA(), colorB(),
 
265
        KImageEffect::VerticalGradient, 0);
 
266
        break;
 
267
    }
 
268
    case PyramidGradient:
 
269
        m_Background = KImageEffect::gradient(m_Size, colorA(), colorB(),
 
270
        KImageEffect::PyramidGradient, 0);
 
271
        break;
 
272
 
 
273
    case PipeCrossGradient:
 
274
        m_Background = KImageEffect::gradient(m_Size, colorA(), colorB(),
 
275
        KImageEffect::PipeCrossGradient, 0);
 
276
        break;
 
277
 
 
278
    case EllipticGradient:
 
279
        m_Background = KImageEffect::gradient(m_Size, colorA(), colorB(),
 
280
        KImageEffect::EllipticGradient, 0);
 
281
        break;
 
282
    }
 
283
 
 
284
    if (retval == Done)
 
285
        m_State |= BackgroundDone;
 
286
 
 
287
    return retval;
 
288
}
 
289
 
 
290
 
 
291
int KBackgroundRenderer::doWallpaper(bool quit)
 
292
{
 
293
    if (m_State & WallpaperDone)
 
294
        return Done;
 
295
 
 
296
    if (quit)
 
297
        // currently no asynch. wallpapers
 
298
        return Done;
 
299
 
 
300
    int wpmode= enabled()?wallpaperMode():NoWallpaper;
 
301
 
 
302
    m_Wallpaper = QImage();
 
303
    if (wpmode != NoWallpaper) {
 
304
wp_load:
 
305
        if (currentWallpaper().isEmpty()) {
 
306
            wpmode = NoWallpaper;
 
307
            goto wp_out;
 
308
        }
 
309
        QString file = m_pDirs->findResource("wallpaper", currentWallpaper());
 
310
        if (file.isEmpty()) {
 
311
            wpmode = NoWallpaper;
 
312
            goto wp_out;
 
313
        }
 
314
 
 
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")) {
 
319
 
 
320
            // Special stuff for SVG icons
 
321
 
 
322
            //FIXME
 
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
 
326
            int svgWidth;
 
327
            int svgHeight;
 
328
            switch (wpmode)
 
329
            {
 
330
                case Centred:
 
331
                case CentredAutoFit:
 
332
                    svgHeight = (int)(m_Size.height() * 0.8);
 
333
                    svgWidth = svgHeight;
 
334
                    break;
 
335
                case Tiled:
 
336
                case CenterTiled:
 
337
                    svgHeight = (int)(m_Size.height() * 0.5);
 
338
                    svgWidth = svgHeight;
 
339
                    break;
 
340
                case Scaled:
 
341
                    svgHeight = m_Size.height();
 
342
                    svgWidth = m_Size.width();
 
343
                    break;
 
344
                case CentredMaxpect:
 
345
                case ScaleAndCrop:
 
346
                case TiledMaxpect:
 
347
                    svgHeight = m_Size.height();
 
348
                    svgWidth = svgHeight;
 
349
                    break;
 
350
                case NoWallpaper:
 
351
                default:
 
352
                    kWarning() << "unknown diagram type" ;
 
353
                    svgHeight = m_Size.height();
 
354
                    svgWidth = svgHeight;
 
355
                    break;
 
356
            }
 
357
            //FIXME hack due to strangeness with
 
358
            //background control modules
 
359
            if ( svgHeight < 200 ) {
 
360
                svgHeight *= 6;
 
361
                svgWidth *= 6;
 
362
            }
 
363
 
 
364
            KSvgRenderer renderer(file);
 
365
            if (renderer.isValid()) {
 
366
                m_Wallpaper = QImage(svgWidth, svgHeight, QImage::Format_ARGB32_Premultiplied);
 
367
                m_Wallpaper.fill(0);
 
368
                QPainter p(&m_Wallpaper);
 
369
                renderer.render(&p);
 
370
            }
 
371
        } else {
 
372
            m_Wallpaper.load(file);
 
373
        }
 
374
        if (m_Wallpaper.isNull()) {
 
375
            kWarning() << "failed to load wallpaper " << file ;
 
376
            if (discardCurrentWallpaper())
 
377
               goto wp_load;
 
378
            wpmode = NoWallpaper;
 
379
            goto wp_out;
 
380
        }
 
381
        m_Wallpaper = m_Wallpaper.convertToFormat(QImage::Format_ARGB32_Premultiplied, Qt::DiffuseAlphaDither);
 
382
 
 
383
        // If we're previewing, scale the wallpaper down to make the preview
 
384
        // look more like the real desktop.
 
385
        if (m_bPreview) {
 
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))
 
389
            {
 
390
                xs = ys = 1;
 
391
            }
 
392
            if( m_WallpaperRect.size() != QSize( xs, ys ))
 
393
                m_Wallpaper = m_Wallpaper.scaled(xs, ys, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
 
394
        }
 
395
 
 
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).
 
399
        if (kapp) {
 
400
            KFileMetaInfo metaInfo(file);
 
401
            if (metaInfo.isValid() && metaInfo.item("Orientation").isValid()) {
 
402
                switch (metaInfo.item("Orientation").value().toInt()) {
 
403
                    case 2:
 
404
                        // Flipped horizontally
 
405
                        m_Wallpaper.mirrored(true, false);
 
406
                        break;
 
407
                    case 3:
 
408
                        // Rotated 180 degrees
 
409
                        m_Wallpaper = KImageEffect::rotate(m_Wallpaper, KImageEffect::Rotate180);
 
410
                        break;
 
411
                    case 4:
 
412
                        // Flipped vertically
 
413
                        m_Wallpaper = m_Wallpaper.mirrored(false, true);
 
414
                        break;
 
415
                    case 5:
 
416
                        // Rotated 90 degrees & flipped horizontally
 
417
                        m_Wallpaper = KImageEffect::rotate(m_Wallpaper, KImageEffect::Rotate90).mirrored(true, false);
 
418
                        break;
 
419
                    case 6:
 
420
                        // Rotated 90 degrees
 
421
                        m_Wallpaper = KImageEffect::rotate(m_Wallpaper, KImageEffect::Rotate90);
 
422
                        break;
 
423
                    case 7:
 
424
                        // Rotated 90 degrees & flipped vertically
 
425
                        m_Wallpaper = KImageEffect::rotate(m_Wallpaper, KImageEffect::Rotate90).mirrored(false, true);
 
426
                        break;
 
427
                    case 8:
 
428
                        // Rotated 270 degrees
 
429
                        m_Wallpaper = KImageEffect::rotate(m_Wallpaper, KImageEffect::Rotate270);
 
430
                        break;
 
431
                    case 1:
 
432
                    default:
 
433
                        // Normal or invalid orientation
 
434
                        break;
 
435
                }
 
436
            }
 
437
        }
 
438
    }
 
439
wp_out:
 
440
 
 
441
    if (m_Background.isNull()) {
 
442
        m_Background = QImage(8, 8, QImage::Format_RGB32);
 
443
        m_Background.fill(colorA().rgb());
 
444
    }
 
445
 
 
446
    int retval = Done;
 
447
 
 
448
    // desktop width/height
 
449
    int w = m_Size.width();
 
450
    int h = m_Size.height();
 
451
 
 
452
    // wallpaper width/height
 
453
    int ww = m_Wallpaper.width();
 
454
    int wh = m_Wallpaper.height();
 
455
 
 
456
    // to be filled destination rectangle; may exceed desktop!
 
457
    m_WallpaperRect = QRect();
 
458
 
 
459
    switch (wpmode)
 
460
    {
 
461
        case NoWallpaper:
 
462
            break;
 
463
        case Centred:
 
464
            m_WallpaperRect.setRect((w - ww) / 2, (h - wh) / 2, ww, wh);
 
465
            break;
 
466
        case Tiled:
 
467
            m_WallpaperRect.setRect(0, 0, w, h);
 
468
            break;
 
469
        case CenterTiled:
 
470
            m_WallpaperRect.setCoords(-ww + ((w - ww) / 2) % ww, -wh + ((h - wh) / 2) % wh, w-1, h-1);
 
471
            break;
 
472
        case Scaled:
 
473
            ww = w;
 
474
            wh = h;
 
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);
 
478
            break;
 
479
        case CentredAutoFit:
 
480
            if( ww <= w && wh <= h ) {
 
481
                m_WallpaperRect.setRect((w - ww) / 2, (h - wh) / 2, ww, wh); // like Centred
 
482
                break;
 
483
            }
 
484
            // fall through
 
485
        case CentredMaxpect:
 
486
            {
 
487
              double sx = (double) w / ww;
 
488
              double sy = (double) h / wh;
 
489
              if (sx > sy) {
 
490
                  ww = (int)(sy * ww);
 
491
                  wh = h;
 
492
              } else {
 
493
                  wh = (int)(sx * wh);
 
494
                  ww = w;
 
495
              }
 
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);
 
499
              break;
 
500
            }
 
501
        case TiledMaxpect:
 
502
            {
 
503
              double sx = (double) w / ww;
 
504
              double sy = (double) h / wh;
 
505
              if (sx > sy) {
 
506
                  ww = (int)(sy * ww);
 
507
                  wh = h;
 
508
              } else {
 
509
                  wh = (int)(sx * wh);
 
510
                  ww = w;
 
511
              }
 
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);
 
515
              break;
 
516
            }
 
517
        case ScaleAndCrop:
 
518
            {
 
519
              double sx = (double) w / ww;
 
520
              double sy = (double) h / wh;
 
521
              if (sx > sy) {
 
522
                  //Case 1: x needs bigger scaling. Lets increase x and leave part of y offscreen
 
523
                  ww = w;
 
524
                  wh=(int)(sx * wh);
 
525
              } else {
 
526
                  //Case 2: y needs bigger scaling. Lets increase y and leave part of x offscreen
 
527
                  wh = h;
 
528
                  ww = (int)(sy*ww);
 
529
              }
 
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);
 
533
              break;
 
534
            }
 
535
    }
 
536
 
 
537
    wallpaperBlend();
 
538
 
 
539
    if (retval == Done)
 
540
        m_State |= WallpaperDone;
 
541
 
 
542
    return retval;
 
543
}
 
544
 
 
545
bool KBackgroundRenderer::canTile() const
 
546
{
 
547
    return m_TilingEnabled && optimize();
 
548
}
 
549
 
 
550
void KBackgroundRenderer::wallpaperBlend()
 
551
{
 
552
    if( !enabled() || wallpaperMode() == NoWallpaper
 
553
        || (blendMode() == NoBlending &&
 
554
        ( QApplication::desktop()->paintEngine()->hasFeature(QPaintEngine::Antialiasing)
 
555
            || !m_Wallpaper.hasAlphaChannel()))) {
 
556
        fastWallpaperBlend();
 
557
    }
 
558
    else {
 
559
        fullWallpaperBlend();
 
560
    }
 
561
}
 
562
 
 
563
// works only for NoBlending and no alpha in wallpaper
 
564
// but is much faster than QImage fidling
 
565
void KBackgroundRenderer::fastWallpaperBlend()
 
566
{
 
567
    m_Image = QImage();
 
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 );
 
573
        return;
 
574
    }
 
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 );
 
578
        return;
 
579
    }
 
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 );
 
585
    else {
 
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 );
 
590
    }
 
591
 
 
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 );
 
601
            }
 
602
        }
 
603
    }
 
604
}
 
605
 
 
606
 
 
607
void KBackgroundRenderer::fullWallpaperBlend()
 
608
{
 
609
    m_Pixmap = QPixmap();
 
610
 
 
611
    // desktop width/height
 
612
    int w = m_Size.width();
 
613
    int h = m_Size.height();
 
614
 
 
615
    // copy background to m_pImage
 
616
    if (m_Background.size() == m_Size) {
 
617
        m_Image = m_Background.copy();
 
618
 
 
619
        if (m_Image.depth() < 32) {
 
620
            m_Image = m_Image.convertToFormat(QImage::Format_ARGB32_Premultiplied, Qt::DiffuseAlphaDither);
 
621
        }
 
622
    } else {
 
623
        m_Image = QImage(w, h, QImage::Format_RGB32);
 
624
        tile(m_Image, QRect(0, 0, w, h), m_Background);
 
625
    }
 
626
 
 
627
    // blend wallpaper to destination rectangle of m_pImage
 
628
    if (m_WallpaperRect.isValid())
 
629
    {
 
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);
 
639
            }
 
640
        }
 
641
    }
 
642
 
 
643
 
 
644
    // blend whole desktop
 
645
    if ( wallpaperMode() != NoWallpaper) {
 
646
      int bal = blendBalance();
 
647
 
 
648
      switch( blendMode() ) {
 
649
      case HorizontalBlending:
 
650
        KImageEffect::blend( m_Image, m_Background,
 
651
                             KImageEffect::HorizontalGradient,
 
652
                             bal, 100 );
 
653
        break;
 
654
 
 
655
      case VerticalBlending:
 
656
        KImageEffect::blend( m_Image, m_Background,
 
657
                             KImageEffect::VerticalGradient,
 
658
                             100, bal );
 
659
        break;
 
660
 
 
661
      case PyramidBlending:
 
662
        KImageEffect::blend( m_Image, m_Background,
 
663
                             KImageEffect::PyramidGradient,
 
664
                             bal, bal );
 
665
        break;
 
666
 
 
667
      case PipeCrossBlending:
 
668
        KImageEffect::blend( m_Image, m_Background,
 
669
                             KImageEffect::PipeCrossGradient,
 
670
                             bal, bal );
 
671
        break;
 
672
 
 
673
      case EllipticBlending:
 
674
        KImageEffect::blend( m_Image, m_Background,
 
675
                             KImageEffect::EllipticGradient,
 
676
                             bal, bal );
 
677
        break;
 
678
 
 
679
      case IntensityBlending:
 
680
        KImageEffect::modulate( m_Image, m_Background, reverseBlending(),
 
681
                    KImageEffect::Intensity, bal, KImageEffect::All );
 
682
        break;
 
683
 
 
684
      case SaturateBlending:
 
685
        KImageEffect::modulate( m_Image, m_Background, reverseBlending(),
 
686
                    KImageEffect::Saturation, bal, KImageEffect::Gray );
 
687
        break;
 
688
 
 
689
      case ContrastBlending:
 
690
        KImageEffect::modulate( m_Image, m_Background, reverseBlending(),
 
691
                    KImageEffect::Contrast, bal, KImageEffect::All );
 
692
        break;
 
693
 
 
694
      case HueShiftBlending:
 
695
        KImageEffect::modulate( m_Image, m_Background, reverseBlending(),
 
696
                    KImageEffect::HueShift, bal, KImageEffect::Gray );
 
697
        break;
 
698
 
 
699
      case FlatBlending:
 
700
        // Already handled
 
701
        break;
 
702
      }
 
703
    }
 
704
}
 
705
 
 
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%]
 
709
 */
 
710
void KBackgroundRenderer::blend(QImage& dst, const QRect &_dr, const QImage& src, const QPoint &soffs, int blendFactor)
 
711
{
 
712
    QRect dr = _dr;
 
713
    int x, y, a;
 
714
    dr &= dst.rect();
 
715
 
 
716
    for (y = 0; y < dr.height(); y++) {
 
717
        if (dst.scanLine(dr.y() + y) && src.scanLine(soffs.y() + y)) {
 
718
            QRgb *b;
 
719
            const QRgb *d;
 
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));
 
729
            }
 
730
        }
 
731
    }
 
732
}
 
733
 
 
734
 
 
735
 
 
736
void KBackgroundRenderer::slotBackgroundDone(K3Process *process)
 
737
{
 
738
    Q_ASSERT(process == m_pProc);
 
739
    m_State |= BackgroundDone;
 
740
 
 
741
    if (m_pProc->normalExit() && !m_pProc->exitStatus()) {
 
742
        m_Background.load(m_Tempfile->fileName());
 
743
        m_State |= BackgroundDone;
 
744
    }
 
745
 
 
746
    delete m_Tempfile; m_Tempfile = 0;
 
747
    m_pTimer->start(0);
 
748
    setBusyCursor(false);
 
749
}
 
750
 
 
751
 
 
752
 
 
753
/*
 
754
 * Starts the rendering process.
 
755
 */
 
756
void KBackgroundRenderer::start(bool enableBusyCursor)
 
757
{
 
758
    m_enableBusyCursor = enableBusyCursor;
 
759
    setBusyCursor(true);
 
760
 
 
761
    m_Cached = false;
 
762
 
 
763
    m_State = Rendering;
 
764
    m_pTimer->start(0);
 
765
}
 
766
 
 
767
 
 
768
/*
 
769
 * This slot is connected to a timer event. It is called repeatedly until
 
770
 * the rendering is done.
 
771
 */
 
772
void KBackgroundRenderer::render()
 
773
{
 
774
    setBusyCursor(true);
 
775
    if (!(m_State & Rendering))
 
776
        return;
 
777
 
 
778
    if( !(m_State & InitCheck)) {
 
779
        QString f = cacheFileName();
 
780
        if( useCacheFile()) {
 
781
            QString w = m_pDirs->findResource("wallpaper", currentWallpaper());
 
782
            QFileInfo wi( w );
 
783
            QFileInfo fi( f );
 
784
            if( wi.lastModified().isValid() && fi.lastModified().isValid()
 
785
                && wi.lastModified() < fi.lastModified()) {
 
786
                QImage im;
 
787
                if( im.load( f, "PNG" )) {
 
788
                    m_Image = im;
 
789
                    m_Pixmap = QPixmap::fromImage( m_Image );
 
790
                    m_Cached = true;
 
791
                    m_State |= InitCheck | BackgroundDone | WallpaperDone;
 
792
                }
 
793
            }
 
794
        }
 
795
        m_pTimer->start(0);
 
796
        m_State |= InitCheck;
 
797
        return;
 
798
    }
 
799
 
 
800
    int ret;
 
801
 
 
802
    if (!(m_State & BackgroundDone)) {
 
803
        ret = doBackground();
 
804
        if (ret != Wait)
 
805
            m_pTimer->start(0);
 
806
        return;
 
807
    }
 
808
 
 
809
    // No async wallpaper
 
810
    doWallpaper();
 
811
 
 
812
    done();
 
813
    setBusyCursor(false);
 
814
}
 
815
 
 
816
 
 
817
/*
 
818
 * Rendering is finished.
 
819
 */
 
820
void KBackgroundRenderer::done()
 
821
{
 
822
    setBusyCursor(false);
 
823
    m_State |= AllDone;
 
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());
 
833
     }
 
834
}
 
835
 
 
836
/*
 
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
 
840
 * once.
 
841
 */
 
842
void KBackgroundRenderer::setBusyCursor(bool isBusy) {
 
843
   if(m_isBusyCursor == isBusy)
 
844
      return;
 
845
   if (isBusy && !m_enableBusyCursor)
 
846
      return;
 
847
   m_isBusyCursor = isBusy;
 
848
   if(isBusy)
 
849
      QApplication::setOverrideCursor( QCursor(Qt::BusyCursor) );
 
850
   else
 
851
      QApplication::restoreOverrideCursor();
 
852
}
 
853
 
 
854
/*
 
855
 * Stop the rendering.
 
856
 */
 
857
void KBackgroundRenderer::stop()
 
858
{
 
859
    if (!(m_State & Rendering))
 
860
        return;
 
861
 
 
862
    doBackground(true);
 
863
    doWallpaper(true);
 
864
    m_State = 0;
 
865
}
 
866
 
 
867
 
 
868
/*
 
869
 * Cleanup after rendering.
 
870
 */
 
871
void KBackgroundRenderer::cleanup()
 
872
{
 
873
    setBusyCursor(false);
 
874
    m_Background = QImage();
 
875
    m_Image = QImage();
 
876
    m_Pixmap = QPixmap();
 
877
    m_Wallpaper = QImage();
 
878
    delete m_pProc; m_pProc = 0L;
 
879
    m_State = 0;
 
880
    m_WallpaperRect = QRect();
 
881
    m_Cached = false;
 
882
}
 
883
 
 
884
 
 
885
void KBackgroundRenderer::setPreview(const QSize &size)
 
886
{
 
887
    if (size.isNull())
 
888
        m_bPreview = false;
 
889
    else {
 
890
        m_bPreview = true;
 
891
        m_Size = size;
 
892
    }
 
893
}
 
894
 
 
895
 
 
896
QPixmap KBackgroundRenderer::pixmap()
 
897
{
 
898
    if (m_State & AllDone) {
 
899
        if( m_Pixmap.isNull())
 
900
            m_Pixmap = QPixmap::fromImage( m_Image );
 
901
        return m_Pixmap;
 
902
    }
 
903
    return QPixmap();
 
904
}
 
905
 
 
906
QImage KBackgroundRenderer::image()
 
907
{
 
908
    if (m_State & AllDone) {
 
909
        if( m_Image.isNull())
 
910
            fullWallpaperBlend(); // create from m_Pixmap
 
911
        return m_Image;
 
912
    }
 
913
    return QImage();
 
914
}
 
915
 
 
916
 
 
917
void KBackgroundRenderer::load(int desk, int screen, bool drawBackgroundPerScreen, bool reparseConfig)
 
918
{
 
919
    if (m_State & Rendering)
 
920
        stop();
 
921
 
 
922
    cleanup();
 
923
    m_bPreview = false;
 
924
    m_Size = m_rSize;
 
925
 
 
926
    KBackgroundSettings::load(desk, screen, drawBackgroundPerScreen, reparseConfig);
 
927
}
 
928
 
 
929
void KBackgroundRenderer::createTempFile()
 
930
{
 
931
    if( !m_Tempfile ){
 
932
     m_Tempfile = new KTemporaryFile();
 
933
     m_Tempfile->open();
 
934
    }
 
935
}
 
936
 
 
937
QString KBackgroundRenderer::cacheFileName()
 
938
{
 
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 ));
 
944
    return f;
 
945
}
 
946
 
 
947
bool KBackgroundRenderer::useCacheFile() const
 
948
{
 
949
    if( !enabled())
 
950
        return false;
 
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())
 
959
        {
 
960
        case NoWallpaper:
 
961
        case Centred:
 
962
        case Tiled:
 
963
        case CenterTiled:
 
964
            return false; // these don't need scaling
 
965
        case CentredMaxpect:
 
966
        case TiledMaxpect:
 
967
        case Scaled:
 
968
        case CentredAutoFit:
 
969
        case ScaleAndCrop:
 
970
        default:
 
971
            return true;
 
972
        }
 
973
}
 
974
 
 
975
void KBackgroundRenderer::saveCacheFile()
 
976
{
 
977
    if( !( m_State & AllDone ))
 
978
        return;
 
979
    if( !useCacheFile())
 
980
        return;
 
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 );
 
986
    else {
 
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()) {
 
992
            int size = 0;
 
993
            Q_FOREACH( QFileInfo info, list )
 
994
                size += info.size();
 
995
            Q_FOREACH( QFileInfo info, list ) {
 
996
                if( size < 8 * 1024 * 1024 )
 
997
                    break;
 
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 )
 
1001
                    break;
 
1002
                size -= info.size();
 
1003
                QFile::remove( info.absoluteFilePath());
 
1004
            }
 
1005
        }
 
1006
    }
 
1007
}
 
1008
 
 
1009
//BEGIN class KVirtualBGRenderer
 
1010
KVirtualBGRenderer::KVirtualBGRenderer(int desk, const KSharedConfigPtr &config, bool kdmMode)
 
1011
{
 
1012
    m_pPixmap = 0l;
 
1013
    m_desk = desk;
 
1014
    m_numRenderers = 0;
 
1015
    m_scaleX = 1;
 
1016
    m_scaleY = 1;
 
1017
    m_kdmMode = kdmMode;
 
1018
 
 
1019
    // The following code is borrowed from KBackgroundSettings::KBackgroundSettings
 
1020
    if (!config) {
 
1021
        int screen_number = 0;
 
1022
        if (QX11Info::display())
 
1023
            screen_number = DefaultScreen(QX11Info::display());
 
1024
        QString configname;
 
1025
        if (screen_number == 0)
 
1026
            configname = "kdesktoprc";
 
1027
        else
 
1028
            configname.sprintf("kdesktop-screen-%drc", screen_number);
 
1029
 
 
1030
        m_pConfig = KSharedConfig::openConfig(configname, KConfig::NoGlobals);
 
1031
    } else {
 
1032
        m_pConfig = config;
 
1033
    }
 
1034
 
 
1035
    initRenderers();
 
1036
    m_size = QApplication::desktop()->size();
 
1037
}
 
1038
 
 
1039
KVirtualBGRenderer::~KVirtualBGRenderer()
 
1040
{
 
1041
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1042
        delete m_renderer[i];
 
1043
 
 
1044
    delete m_pPixmap;
 
1045
}
 
1046
 
 
1047
 
 
1048
KBackgroundRenderer * KVirtualBGRenderer::renderer(unsigned screen)
 
1049
{
 
1050
    return m_renderer[screen];
 
1051
}
 
1052
 
 
1053
 
 
1054
QPixmap KVirtualBGRenderer::pixmap()
 
1055
{
 
1056
    if (m_numRenderers == 1)
 
1057
        return m_renderer[0]->pixmap();
 
1058
 
 
1059
    return *m_pPixmap;
 
1060
}
 
1061
 
 
1062
 
 
1063
bool KVirtualBGRenderer::needProgramUpdate()
 
1064
{
 
1065
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1066
    {
 
1067
        if ( m_renderer[i]->backgroundMode() == KBackgroundSettings::Program &&
 
1068
             m_renderer[i]->KBackgroundProgram::needUpdate() )
 
1069
            return true;
 
1070
    }
 
1071
    return false;
 
1072
}
 
1073
 
 
1074
 
 
1075
void KVirtualBGRenderer::programUpdate()
 
1076
{
 
1077
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1078
    {
 
1079
        if ( m_renderer[i]->backgroundMode() == KBackgroundSettings::Program &&
 
1080
             m_renderer[i]->KBackgroundProgram::needUpdate() )
 
1081
        {
 
1082
            m_renderer[i]->KBackgroundProgram::update();
 
1083
        }
 
1084
    }
 
1085
}
 
1086
 
 
1087
 
 
1088
bool KVirtualBGRenderer::needWallpaperChange()
 
1089
{
 
1090
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1091
    {
 
1092
        if ( m_renderer[i]->needWallpaperChange() )
 
1093
            return true;
 
1094
    }
 
1095
    return false;
 
1096
}
 
1097
 
 
1098
 
 
1099
void KVirtualBGRenderer::changeWallpaper()
 
1100
{
 
1101
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1102
    {
 
1103
        m_renderer[i]->changeWallpaper();
 
1104
    }
 
1105
}
 
1106
 
 
1107
 
 
1108
int KVirtualBGRenderer::hash()
 
1109
{
 
1110
    QString fp;
 
1111
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1112
    {
 
1113
        fp += m_renderer[i]->fingerprint();
 
1114
    }
 
1115
    int h = qHash(fp);
 
1116
    kDebug() << " fp=\""<<fp<<"\" h="<<h;
 
1117
    return qHash(fp);
 
1118
}
 
1119
 
 
1120
 
 
1121
bool KVirtualBGRenderer::isActive()
 
1122
{
 
1123
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1124
    {
 
1125
        if ( m_renderer[i]->isActive() )
 
1126
            return true;
 
1127
    }
 
1128
    return false;
 
1129
}
 
1130
 
 
1131
 
 
1132
void KVirtualBGRenderer::setEnabled(bool enable)
 
1133
{
 
1134
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1135
        m_renderer[i]->setEnabled(enable);
 
1136
}
 
1137
 
 
1138
 
 
1139
void KVirtualBGRenderer::desktopResized()
 
1140
{
 
1141
    m_size = QApplication::desktop()->size();
 
1142
 
 
1143
    if (m_pPixmap)
 
1144
    {
 
1145
        delete m_pPixmap;
 
1146
        m_pPixmap = new QPixmap(m_size);
 
1147
        m_pPixmap->fill(Qt::black);
 
1148
    }
 
1149
 
 
1150
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1151
        m_renderer[i]->desktopResized();
 
1152
}
 
1153
 
 
1154
 
 
1155
void KVirtualBGRenderer::setPreview(const QSize & size)
 
1156
{
 
1157
    if (m_size == size)
 
1158
        return;
 
1159
 
 
1160
    m_size = size;
 
1161
 
 
1162
    if (m_pPixmap)
 
1163
        *m_pPixmap = QPixmap(m_size);
 
1164
 
 
1165
    // Scaling factors
 
1166
    m_scaleX = float(m_size.width()) / float(QApplication::desktop()->size().width());
 
1167
    m_scaleY = float(m_size.height()) / float(QApplication::desktop()->size().height());
 
1168
 
 
1169
    // Scale renderers appropriately
 
1170
    for (unsigned i=0; i<m_renderer.size(); ++i)
 
1171
    {
 
1172
        QSize unscaledRendererSize = renderSize(i);
 
1173
 
 
1174
        m_renderer[i]->setPreview( QSize(
 
1175
                int(unscaledRendererSize.width() * m_scaleX),
 
1176
                int(unscaledRendererSize.height() * m_scaleY) ) );
 
1177
    }
 
1178
}
 
1179
 
 
1180
 
 
1181
QSize KVirtualBGRenderer::renderSize(int screen)
 
1182
{
 
1183
    return m_bDrawBackgroundPerScreen ?
 
1184
            QApplication::desktop()->screenGeometry(screen).size() : QApplication::desktop()->size();
 
1185
}
 
1186
 
 
1187
 
 
1188
void KVirtualBGRenderer::initRenderers()
 
1189
{
 
1190
    KConfigGroup cg(m_pConfig, "Background Common");
 
1191
    m_bDrawBackgroundPerScreen = cg.readEntry( QString("DrawBackgroundPerScreen_%1").arg(m_desk), _defDrawBackgroundPerScreen );
 
1192
 
 
1193
    m_bCommonScreen = cg.readEntry("CommonScreen", _defCommonScreen);
 
1194
 
 
1195
    m_numRenderers = m_bDrawBackgroundPerScreen ? QApplication::desktop()->numScreens() : 1;
 
1196
 
 
1197
    m_bFinished.resize(m_numRenderers);
 
1198
    m_bFinished.fill(false);
 
1199
 
 
1200
    if (m_numRenderers == m_renderer.size())
 
1201
        return;
 
1202
 
 
1203
    for (unsigned i=0; i<m_renderer.size(); ++i)
 
1204
        delete m_renderer[i];
 
1205
 
 
1206
    m_renderer.resize(m_numRenderers);
 
1207
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1208
    {
 
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)) );
 
1214
    }
 
1215
}
 
1216
 
 
1217
 
 
1218
void KVirtualBGRenderer::load(int desk, bool reparseConfig)
 
1219
{
 
1220
    m_desk = desk;
 
1221
 
 
1222
    m_bCommonScreen = m_pConfig->group("Background Common").readEntry("CommonScreen", _defCommonScreen);
 
1223
 
 
1224
    initRenderers();
 
1225
 
 
1226
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1227
    {
 
1228
        unsigned eScreen = m_bCommonScreen ? 0 : i;
 
1229
        m_renderer[i]->load(desk, eScreen, m_bDrawBackgroundPerScreen, reparseConfig);
 
1230
    }
 
1231
}
 
1232
 
 
1233
 
 
1234
void KVirtualBGRenderer::screenDone(int _desk, int _screen)
 
1235
{
 
1236
    Q_UNUSED(_desk);
 
1237
    Q_UNUSED(_screen);
 
1238
 
 
1239
    const KBackgroundRenderer * sender = dynamic_cast<const KBackgroundRenderer*>(this->sender());
 
1240
    int screen = m_renderer.find(sender);
 
1241
    if (screen == -1)
 
1242
        //??
 
1243
        return;
 
1244
 
 
1245
    m_bFinished[screen] = true;
 
1246
 
 
1247
 
 
1248
    if (m_pPixmap)
 
1249
    {
 
1250
        // There's more than one renderer, so we are drawing each output to our own pixmap
 
1251
 
 
1252
        QRect overallGeometry;
 
1253
        for (int i=0; i < QApplication::desktop()->numScreens(); ++i)
 
1254
            overallGeometry |= QApplication::desktop()->screenGeometry(i);
 
1255
 
 
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) );
 
1259
 
 
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) );
 
1264
 
 
1265
        QPainter p(m_pPixmap);
 
1266
 
 
1267
        if (renderSize == source.size())
 
1268
            p.drawPixmap( drawPos, source );
 
1269
 
 
1270
        else
 
1271
            p.drawTiledPixmap( drawPos.x(), drawPos.y(), renderSize.width(), renderSize.height(), source );
 
1272
 
 
1273
        p.end();
 
1274
    }
 
1275
 
 
1276
    for (int i=0; i<m_bFinished.size(); ++i)
 
1277
    {
 
1278
        if (!m_bFinished[i])
 
1279
            return;
 
1280
    }
 
1281
 
 
1282
    emit imageDone(m_desk);
 
1283
}
 
1284
 
 
1285
 
 
1286
void KVirtualBGRenderer::start()
 
1287
{
 
1288
    if (m_pPixmap)
 
1289
    {
 
1290
        delete m_pPixmap;
 
1291
        m_pPixmap = 0l;
 
1292
    }
 
1293
 
 
1294
    if (m_numRenderers > 1)
 
1295
    {
 
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
 
1299
        // previews, etc
 
1300
        m_pPixmap->fill(Qt::black);
 
1301
    }
 
1302
 
 
1303
    m_bFinished.fill(false);
 
1304
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1305
        m_renderer[i]->start();
 
1306
}
 
1307
 
 
1308
 
 
1309
void KVirtualBGRenderer::stop()
 
1310
{
 
1311
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1312
        m_renderer[i]->stop();
 
1313
}
 
1314
 
 
1315
 
 
1316
void KVirtualBGRenderer::cleanup()
 
1317
{
 
1318
    m_bFinished.fill(false);
 
1319
 
 
1320
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1321
        m_renderer[i]->cleanup();
 
1322
 
 
1323
    delete m_pPixmap;
 
1324
    m_pPixmap = 0l;
 
1325
}
 
1326
 
 
1327
void KVirtualBGRenderer::saveCacheFile()
 
1328
{
 
1329
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1330
        m_renderer[i]->saveCacheFile();
 
1331
}
 
1332
 
 
1333
void KVirtualBGRenderer::enableTiling( bool enable )
 
1334
{
 
1335
    for (unsigned i=0; i<m_numRenderers; ++i)
 
1336
        m_renderer[i]->enableTiling( enable );
 
1337
}
 
1338
 
 
1339
//END class KVirtualBGRenderer
 
1340
 
 
1341
 
 
1342
#include "bgrender.moc"