summaryrefslogtreecommitdiffstats
path: root/kdesktop/bgmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kdesktop/bgmanager.cpp')
-rw-r--r--kdesktop/bgmanager.cpp1109
1 files changed, 1109 insertions, 0 deletions
diff --git a/kdesktop/bgmanager.cpp b/kdesktop/bgmanager.cpp
new file mode 100644
index 000000000..7e90e8fca
--- /dev/null
+++ b/kdesktop/bgmanager.cpp
@@ -0,0 +1,1109 @@
+/*
+ *
+ * This file is part of the KDE project, module kdesktop.
+ * Copyright (C) 1999,2000 Geert Jansen <[email protected]>
+ *
+ * You can Freely distribute this program under the GNU General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#include <config.h>
+#include "bgrender.h"
+#include "bgmanager.h"
+#include "bgdefaults.h"
+#include "kdesktopsettings.h"
+#include "bgsettings.h"
+#include "kdesktopapp.h"
+
+#include "KCrossBGRender.h"
+#include "crossfade.h"
+
+#include <assert.h>
+
+#include <tqtimer.h>
+#include <tqscrollview.h>
+#include <tqpainter.h>
+#include <tqdesktopwidget.h>
+
+#include <kiconloader.h>
+#include <tdeconfig.h>
+#include <twin.h>
+#include <tdeapplication.h>
+#include <kdebug.h>
+#include <kipc.h>
+#include <tdepopupmenu.h>
+#include <twinmodule.h>
+#include <krootpixmap.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrender.h>
+#include <unistd.h>
+
+#ifndef None
+#define None 0L
+#endif
+
+#ifdef COMPOSITE
+# include <X11/Xlib.h>
+# include <X11/extensions/Xrender.h>
+# include <fixx11h.h>
+#endif
+
+#include "pixmapserver.h"
+
+template class TQPtrVector<KCrossBGRender>;
+template class TQPtrVector<KBackgroundCacheEntry>;
+template class TQMemArray<int>;
+
+static Atom prop_root;
+static bool properties_inited = false;
+
+extern bool argb_visual;
+extern KDesktopApp *myApp;
+
+/**** KBackgroundManager ****/
+
+KBackgroundManager::KBackgroundManager(TQWidget *desktop, KWinModule* twinModule)
+ : KBackgroundIface()
+{
+ if( !properties_inited )
+ {
+ prop_root = XInternAtom(tqt_xdisplay(), "_XROOTPMAP_ID", False);
+ properties_inited = true;
+ }
+ m_bBgInitDone = false;
+ m_bEnabled = true;
+
+ m_pDesktop = desktop;
+ if (desktop == 0L)
+ desktop = TQT_TQWIDGET(TDEApplication::desktop()->screen());
+
+ m_Renderer.resize( 1 );
+ m_Cache.resize( 1 );
+
+ m_Serial = 0; m_Hash = 0;
+ m_pConfig = TDEGlobal::config();
+ m_bExport = m_bCommon = m_bInit = false;
+ m_pKwinmodule = twinModule;
+ m_pPixmapServer = new KPixmapServer();
+ m_xrootpmap = None;
+
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ {
+ m_Cache.insert(i, new KBackgroundCacheEntry);
+ m_Cache[i]->pixmap = 0L;
+ m_Cache[i]->hash = 0;
+ m_Cache[i]->exp_from = -1;
+ m_Renderer.insert (i, new KVirtualBGRenderer(i,m_pConfig));
+ connect(m_Renderer[i], TQT_SIGNAL(imageDone(int)), TQT_SLOT(slotImageDone(int)));
+ m_Renderer[i]->enableTiling( true ); // optimize
+ }
+
+#ifdef COMPOSITE
+ m_tPixmap = new KPixmap(kapp->desktop()->size());
+ m_tPixmap->fill(TQColor(0, 0x0));
+ connect(myApp, TQT_SIGNAL(cmBackgroundChanged( bool )),
+ TQT_SLOT(slotCmBackgroundChanged( bool )));
+#endif
+
+ configure();
+
+ m_pTimer = new TQTimer(this);
+ connect(m_pTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotTimeout()));
+ m_pTimer->start( 60000 );
+
+ /*CrossFade's config*/
+ m_crossTimer = new TQTimer(this);
+ connect(m_crossTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotCrossFadeTimeout()));
+ resizingDesktop = true;
+ /*Ends here*/
+
+
+ connect(m_pKwinmodule, TQT_SIGNAL(currentDesktopChanged(int)),
+ TQT_SLOT(slotChangeDesktop(int)));
+ connect(m_pKwinmodule, TQT_SIGNAL(numberOfDesktopsChanged(int)),
+ TQT_SLOT(slotChangeNumberOfDesktops(int)));
+ connect(m_pKwinmodule, TQT_SIGNAL(currentDesktopViewportChanged(int, const TQPoint&)),
+ TQT_SLOT(slotChangeViewport(int, const TQPoint&)));
+
+
+#if (TQT_VERSION-0 >= 0x030200)
+ connect( kapp->desktop(), TQT_SIGNAL( resized( int )), TQT_SLOT( desktopResized())); // RANDR support
+#endif
+
+ TQSize s(m_pKwinmodule->numberOfViewports(m_pKwinmodule->currentDesktop()));
+ m_numberOfViewports = s.width() * s.height();
+ if (m_numberOfViewports < 1) {
+ m_numberOfViewports = 1;
+ }
+ for (signed j=0;j<(m_pKwinmodule->numberOfDesktops() * m_numberOfViewports);j++) {
+ renderBackground(j);
+ }
+}
+
+
+KBackgroundManager::~KBackgroundManager()
+{
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ delete m_Renderer[i];
+
+ //delete m_pConfig; Very bad idea, this is TDEGlobal::config !
+ delete m_pPixmapServer;
+ delete m_pTimer;
+
+ // clear the Esetroot properties, as the pixmaps they refer to are going away...
+ Pixmap pm = None;
+ Atom type;
+ int format;
+ unsigned long length, after;
+ unsigned char* data_root;
+ if( XGetWindowProperty( tqt_xdisplay(), tqt_xrootwin(), prop_root, 0L, 1L, False, AnyPropertyType,
+ &type, &format, &length, &after, &data_root) == Success && data_root != NULL )
+ {
+ if (type == XA_PIXMAP)
+ pm = *((Pixmap*)data_root);
+ XFree( data_root );
+ }
+ // only if it's our pixmap
+ if( pm == m_xrootpmap )
+ XDeleteProperty(tqt_xdisplay(), tqt_xrootwin(), prop_root);
+ m_xrootpmap = None;
+
+ if (m_bExport)
+ return;
+
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ {
+ delete m_Cache[i]->pixmap;
+ delete m_Cache[i];
+ }
+}
+
+
+void KBackgroundManager::applyExport(bool exp)
+{
+ if (exp == m_bExport)
+ return;
+
+ // If export mode changed from true -> false, remove all shared pixmaps.
+ // If it changed false -> true force a redraw because the current screen
+ // image might not have an associated pixmap in the cache.
+ if (!exp)
+ {
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ removeCache(i);
+ } else
+ m_Hash = 0;
+
+ m_bExport = exp;
+}
+
+
+void KBackgroundManager::applyCommon(bool common)
+{
+ if (common == m_bCommon)
+ return;
+ m_bCommon = common;
+
+ // If common changed from false -> true, remove all cache entries, except
+ // at index 0 if exports are on.
+ if (m_bCommon)
+ {
+ if (!m_bExport)
+ removeCache(0);
+ for (unsigned i=1; i<m_Cache.size(); i++)
+ removeCache(i);
+ }
+}
+
+
+void KBackgroundManager::applyCache(bool limit, int size)
+{
+ m_bLimitCache = limit;
+ m_CacheLimit = size;
+ freeCache(0);
+}
+
+
+/*
+ * Call this when the configuration has changed.
+ * This method is exported with DCOP.
+ */
+void KBackgroundManager::configure()
+{
+ // Global settings
+ m_pConfig->reparseConfiguration();
+ KDesktopSettings::self()->readConfig();
+
+ // Read individual settings
+ KVirtualBGRenderer *r;
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ {
+ r = m_Renderer[i];
+ int ohash = r->hash();
+ r->load(i,false);
+ if ((r->hash() != ohash))
+ removeCache(i);
+ }
+
+ applyCommon(KDesktopSettings::commonDesktop());
+
+ bool limit = KDesktopSettings::limitCache();
+ int size = KDesktopSettings::cacheSize() * 1024;
+ applyCache(limit, size);
+
+ // Repaint desktop
+ slotChangeDesktop(0);
+
+ // Redraw all desktops so that applications relying on exported data, e.g. kpager, continue to work properly
+ TQSize s(m_pKwinmodule->numberOfViewports(m_pKwinmodule->currentDesktop()));
+ m_numberOfViewports = s.width() * s.height();
+ if (m_numberOfViewports < 1) {
+ m_numberOfViewports = 1;
+ }
+ for (signed j=0;j<(m_pKwinmodule->numberOfDesktops() * m_numberOfViewports);j++) {
+ renderBackground(j);
+ }
+}
+
+
+int KBackgroundManager::realDesktop()
+{
+ int desk = m_pKwinmodule->currentDesktop();
+ if (desk) desk--;
+ return desk;
+}
+
+
+int KBackgroundManager::effectiveDesktop()
+{
+ TQSize s(m_pKwinmodule->numberOfViewports(m_pKwinmodule->currentDesktop()));
+ m_numberOfViewports = s.width() * s.height();
+
+ if (m_numberOfViewports > 1) {
+ if (m_bCommon) {
+ return 0;
+ }
+ else {
+ TQPoint vx(m_pKwinmodule->currentViewport(m_pKwinmodule->currentDesktop()));
+ return (realDesktop() * m_numberOfViewports) + ((vx.x() * vx.y()) - 1);
+ }
+ }
+ else {
+ return m_bCommon ? 0 : realDesktop();
+ }
+}
+
+
+/*
+ * Number of desktops changed
+ */
+void KBackgroundManager::slotChangeNumberOfDesktops(int num)
+{
+ TQSize s(m_pKwinmodule->numberOfViewports(m_pKwinmodule->currentDesktop()));
+ m_numberOfViewports = s.width() * s.height();
+ if (m_numberOfViewports < 1) {
+ m_numberOfViewports = 1;
+ }
+ num = (num * m_numberOfViewports);
+
+ if (m_Renderer.size() == (unsigned) num)
+ return;
+
+ if (m_Renderer.size() > (unsigned) num)
+ {
+ for (unsigned i=num; i<m_Renderer.size(); i++)
+ {
+ if (m_Renderer[i]->isActive())
+ m_Renderer[i]->stop();
+ delete m_Renderer[i];
+ removeCache(i);
+ }
+ for (unsigned i=num; i<m_Renderer.size(); i++)
+ delete m_Cache[i];
+ m_Renderer.resize(num);
+ m_Cache.resize(num);
+ } else
+ {
+ // allocate new renderers and caches
+ int oldsz = m_Renderer.size();
+ m_Renderer.resize(num);
+ m_Cache.resize(num);
+ for (int i=oldsz; i<num; i++)
+ {
+ m_Cache.insert(i, new KBackgroundCacheEntry);
+ m_Cache[i]->pixmap = 0L;
+ m_Cache[i]->hash = 0;
+ m_Cache[i]->exp_from = -1;
+ m_Renderer.insert(i, new KVirtualBGRenderer(i,m_pConfig));
+ connect(m_Renderer[i], TQT_SIGNAL(imageDone(int)), TQT_SLOT(slotImageDone(int)));
+ m_Renderer[i]->enableTiling( true ); // optimize
+ }
+ }
+}
+
+/*
+ * Call this when the desktop has been changed.
+ * Desk is in KWin convention: [1..desks], instead of [0..desks-1].
+ * 0 repaints the current desktop.
+ */
+void KBackgroundManager::slotChangeDesktop(int desk)
+{
+ resizingDesktop = true;
+ TQSize s(m_pKwinmodule->numberOfViewports(m_pKwinmodule->currentDesktop()));
+ m_numberOfViewports = s.width() * s.height();
+ if (m_numberOfViewports < 1) {
+ m_numberOfViewports = 1;
+ }
+
+ if (desk == 0)
+ desk = realDesktop();
+ else
+ desk--;
+
+ // Lazy initialisation of # of desktops
+ if ((unsigned)(m_pKwinmodule->numberOfDesktops() * m_numberOfViewports) >= m_Renderer.size())
+ slotChangeNumberOfDesktops( m_pKwinmodule->numberOfDesktops() * m_numberOfViewports);
+
+ int edesk = effectiveDesktop();
+ m_Serial++;
+
+ // If the background is the same: do nothing
+ if ((m_Hash == m_Renderer[edesk]->hash()) && (desk != 0))
+ {
+ exportBackground(m_Current, desk);
+ return;
+ }
+ m_Renderer[edesk]->stop();
+ m_Renderer[edesk]->cleanup();
+
+ // If we have the background already rendered: set it
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ {
+ if (!m_Cache[i]->pixmap)
+ continue;
+ if (m_Cache[i]->hash != m_Renderer[edesk]->hash())
+ continue;
+ if (desk == 0)
+ continue;
+// kdDebug() << "slotChangeDesktop i=" << i << endl;
+ setPixmap(m_Cache[i]->pixmap, m_Cache[i]->hash, i);
+ m_Cache[i]->atime = m_Serial;
+ exportBackground(i, desk);
+ return;
+ }
+
+ // Do we have this or an identical config already running?
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ {
+ if (((m_Renderer[i]->hash() == m_Renderer[edesk]->hash()) && (m_Renderer[i]->isActive())) && (desk != 0)) {
+ return;
+ }
+ }
+
+ renderBackground(edesk);
+}
+
+/*
+ * Call this when the viewport has been changed.
+ * Desk is in KWin convention: [1..desks], instead of [0..desks-1].
+ * 0 repaints the current viewport.
+ */
+void KBackgroundManager::slotChangeViewport(int desk, const TQPoint& viewport)
+{
+ TQSize s(m_pKwinmodule->numberOfViewports(m_pKwinmodule->currentDesktop()));
+ m_numberOfViewports = s.width() * s.height();
+ if (m_numberOfViewports < 1) {
+ m_numberOfViewports = 1;
+ }
+
+ if (desk == 0)
+ desk = realDesktop();
+ else
+ desk--;
+
+ // Lazy initialisation of # of desktops
+ if ((unsigned)(m_pKwinmodule->numberOfDesktops() * m_numberOfViewports) >= m_Renderer.size())
+ slotChangeNumberOfDesktops( m_pKwinmodule->numberOfDesktops() * m_numberOfViewports );
+
+ int edesk = effectiveDesktop();
+ m_Serial++;
+
+ // If the background is the same: do nothing
+ if ((m_Hash == m_Renderer[edesk]->hash()) && (desk != 0))
+ {
+ exportBackground(m_Current, desk);
+ return;
+ }
+ m_Renderer[edesk]->stop();
+ m_Renderer[edesk]->cleanup();
+
+ // If we have the background already rendered: set it
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ {
+ if (!m_Cache[i]->pixmap)
+ continue;
+ if (m_Cache[i]->hash != m_Renderer[edesk]->hash())
+ continue;
+ if (desk == 0)
+ continue;
+// kdDebug() << "slotChangeDesktop i=" << i << endl;
+
+ //KPixmap * viewport_background = new KPixmap(TQPixmap(m_Cache[i]->pixmap->width()*s.width(), m_Cache[i]->pixmap->height()*s.height()));
+ //setPixmap(viewport_background, m_Cache[i]->hash, i);
+ //delete viewport_background;
+
+ setPixmap(m_Cache[i]->pixmap, m_Cache[i]->hash, i);
+ m_Cache[i]->atime = m_Serial;
+ exportBackground(i, desk);
+ return;
+ }
+
+ // Do we have this or an identical config already running?
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ {
+ if (((m_Renderer[i]->hash() == m_Renderer[edesk]->hash()) && (m_Renderer[i]->isActive())) && (desk != 0))
+ return;
+ }
+
+ renderBackground(edesk);
+}
+
+
+/*
+ * Share a desktop pixmap.
+ */
+void KBackgroundManager::exportBackground(int pixmap, int desk)
+{
+ if (!m_bExport || (m_Cache[desk]->exp_from == pixmap))
+ return;
+
+ m_Cache[desk]->exp_from = pixmap;
+ m_pPixmapServer->add(KRootPixmap::pixmapName(desk+1),
+ m_Cache[pixmap]->pixmap);
+ KIPC::sendMessageAll(KIPC::BackgroundChanged, desk+1);
+}
+
+
+/*
+ * Paint the pixmap to the root window.
+ */
+void KBackgroundManager::setPixmap(KPixmap *pm, int hash, int desk)
+{
+ KPixmap *ep = pm;
+
+#ifdef COMPOSITE
+ if (argb_visual && (KDesktopSettings::backgroundOpacity() < 100
+ || myApp->cmBackground()))
+ {
+ ep = m_tPixmap;
+ if (KDesktopSettings::backgroundOpacity() > 0 && pm
+ && !myApp->cmBackground())
+ {
+ XRenderPictFormat *format;
+ format = XRenderFindStandardFormat (tqt_xdisplay(), PictStandardARGB32);
+
+ XRenderColor fillColor;
+
+ int color = KDesktopSettings::backgroundOpacity() * 0xffff / 100;
+ fillColor.red = color;
+ fillColor.green = color;
+ fillColor.blue = color;
+ fillColor.alpha = color;
+
+ Picture fill = XRenderCreateSolidFill (tqt_xdisplay(), &fillColor);
+ Picture src = XRenderCreatePicture(tqt_xdisplay(), pm->handle(),
+ format, 0, NULL);
+ Picture dst = XRenderCreatePicture(tqt_xdisplay(), ep->handle(),
+ format, 0, NULL);
+
+ XRenderComposite (tqt_xdisplay(), PictOpSrc, src, fill, dst, 0, 0, 0,
+ 0, 0, 0, pm->width(), pm->height());
+
+ XRenderFreePicture (tqt_xdisplay(), fill);
+ XRenderFreePicture (tqt_xdisplay(), src);
+ XRenderFreePicture (tqt_xdisplay(), dst);
+ }
+ }
+#endif
+
+ if (m_pDesktop)
+ {
+ TQScrollView* sv = dynamic_cast<TQScrollView*>( m_pDesktop );
+ if ( sv ) {
+ // Qt eats repaint events in this case :-((
+ sv->viewport()->update();
+ }
+ m_pDesktop->setErasePixmap(*ep);
+ m_pDesktop->repaint();
+ static bool root_cleared = false;
+ if( !root_cleared )
+ { // clear the root window pixmap set by tdm
+ root_cleared = true;
+ TQTimer::singleShot( 0, this, TQT_SLOT( clearRoot()));
+ // but make the pixmap visible until m_pDesktop is visible
+ TQT_TQWIDGET(TDEApplication::desktop()->screen())->setErasePixmap(*ep);
+ TQT_TQWIDGET(TDEApplication::desktop()->screen())->erase();
+ }
+ }
+ else
+ {
+ TQT_TQWIDGET(TDEApplication::desktop()->screen())->setErasePixmap(*ep);
+ TQT_TQWIDGET(TDEApplication::desktop()->screen())->erase();
+ }
+
+ // and export it via Esetroot-style for gnome/GTK apps to share in the pretties
+ Pixmap bgPm = pm->handle(); // fetch the actual X handle to it
+ //kdDebug() << "Esetroot compat: setting pixmap to " << bgPm << endl;
+
+ // don't set the ESETROOT_PMAP_ID property - that would result in possible XKillClient()
+ // done on kdesktop
+
+ XChangeProperty(tqt_xdisplay(), tqt_xrootwin(), prop_root, XA_PIXMAP, 32, PropModeReplace,
+ (unsigned char *) &bgPm, 1);
+ m_xrootpmap = bgPm;
+
+ m_Hash = hash;
+ m_Current = desk;
+}
+
+void KBackgroundManager::clearRoot()
+{
+ TQT_TQWIDGET(TDEApplication::desktop()->screen())->setErasePixmap( TQPixmap());
+ TQT_TQWIDGET(TDEApplication::desktop()->screen())->erase();
+}
+
+/*
+ * Start the render of a desktop background.
+ */
+void KBackgroundManager::renderBackground(int desk)
+{
+ KVirtualBGRenderer *r = m_Renderer[desk];
+ if (r->isActive())
+ {
+ kdDebug() << "renderer " << desk << " already active" << endl;
+ return;
+ }
+
+ r->start();
+}
+
+
+/*
+ * This slot is called when the Timeout is executed
+ */
+void KBackgroundManager::slotCrossFadeTimeout()
+{
+ KVirtualBGRenderer *r = m_Renderer[fadeDesk];
+ if (crossInit) {
+ mBenchmark.start();
+ }
+
+ if (mAlpha <= 0.0 || mBenchmark.elapsed() > 300 ) {
+ mAlpha = 1;
+ m_crossTimer->stop();
+ KPixmap pixm(mNextScreen);
+ setPixmap(&pixm, r->hash(), fadeDesk);
+ return;
+ }
+ // Reset Timer
+ mBenchmark.start();
+
+ TQPixmap dst = crossFade(*mOldScreen, mNextScreen, mAlpha, crossInit);
+ KPixmap pixm(dst);
+ setPixmap(&pixm, r->hash(), fadeDesk);
+
+ mAlpha -=0.03;
+ crossInit = false;
+}
+
+
+/*
+ * This slot is called when a renderer is done.
+ */
+void KBackgroundManager::slotImageDone(int desk)
+{
+ TQSize s(m_pKwinmodule->numberOfViewports(m_pKwinmodule->currentDesktop()));
+ m_numberOfViewports = s.width() * s.height();
+ if (m_numberOfViewports < 1) {
+ m_numberOfViewports = 1;
+ }
+
+ KPixmap *pm = new KPixmap();
+ KVirtualBGRenderer *r = m_Renderer[desk];
+ bool do_cleanup = true;
+ fadeDesk = desk;
+ mAlpha = 1.0;
+ int width,height;
+
+
+ *pm = r->pixmap();
+ // If current: paint it
+ bool current = (r->hash() == m_Renderer[effectiveDesktop()]->hash());
+ if (current)
+ {
+ //START
+ if (m_Renderer[effectiveDesktop()]->renderer(0)->crossFadeBg() && !m_Renderer[effectiveDesktop()]->renderer(0)->usingCrossXml() && !resizingDesktop) {
+ int mode = m_Renderer[effectiveDesktop()]->renderer(0)->wallpaperMode();
+ width = TQApplication::desktop()->screenGeometry().width();
+ height = TQApplication::desktop()->screenGeometry().height();
+
+ if (mode == KBackgroundSettings::NoWallpaper || mode == KBackgroundSettings::Tiled || mode == KBackgroundSettings::CenterTiled ){
+ mNextScreen = TQPixmap(width,height);
+ TQPainter p (&mNextScreen);
+ p.drawTiledPixmap(0,0,width,height,*pm);
+ } else {
+ mNextScreen = TQPixmap(*pm);
+ }
+
+ if (m_pDesktop){
+ mOldScreen = const_cast<TQPixmap *>( m_pDesktop->backgroundPixmap() );
+ }else{
+ mOldScreen = const_cast<TQPixmap *>(
+ TQApplication::desktop()->screen()->backgroundPixmap() );
+ }
+
+ //TODO Find a way to discover if CrossFade effect needs to run
+ if (mOldScreen){
+ crossInit = true;
+ m_crossTimer->start(70);
+ } else{
+ setPixmap(pm, r->hash(), desk);
+ }
+ }else{
+ setPixmap(pm, r->hash(), desk);
+ }
+ //ENDS HERE */
+
+ if (!m_bBgInitDone)
+ {
+ m_bBgInitDone = true;
+ emit initDone();
+ TQTimer::singleShot( 30000, this, TQT_SLOT( saveImages()));
+ do_cleanup = false;
+ }
+ }
+ if (m_bExport || !m_bCommon) {
+ addCache(pm, r->hash(), desk);
+ }
+ else {
+ delete pm;
+ }
+
+ if (current) {
+ exportBackground(desk, realDesktop());
+ }
+
+ if( do_cleanup ) {
+ r->saveCacheFile();
+ r->cleanup();
+ }
+
+ resizingDesktop = false;
+}
+
+
+void KBackgroundManager::saveImages()
+{
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ {
+ m_Renderer[i]->saveCacheFile();
+ m_Renderer[i]->cleanup();
+ }
+}
+
+/*
+ * Size in bytes of a TQPixmap. For use in the pixmap cache.
+ */
+int KBackgroundManager::pixmapSize(TQPixmap *pm)
+{
+ return (pm->width() * pm->height()) * ((pm->depth() + 7) / 8);
+}
+
+
+/*
+ * Total size of the pixmap cache.
+ */
+int KBackgroundManager::cacheSize()
+{
+ int total = 0;
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ {
+ if (m_Cache[i]->pixmap)
+ total += pixmapSize(m_Cache[i]->pixmap);
+ }
+ return total;
+}
+
+
+/*
+ * Remove an entry from the pixmap cache.
+ */
+void KBackgroundManager::removeCache(int desk)
+{
+ if (m_bExport)
+ m_pPixmapServer->remove(KRootPixmap::pixmapName(desk+1));
+ else
+ delete m_Cache[desk]->pixmap;
+ m_Cache[desk]->pixmap = 0L;
+ m_Cache[desk]->hash = 0;
+ m_Cache[desk]->exp_from = -1;
+ m_Cache[desk]->atime = 0;
+
+ // Remove cache entries pointing to the removed entry
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ {
+ if (m_Cache[i]->exp_from == desk)
+ {
+ assert(m_bExport);
+ m_Cache[i]->exp_from = -1;
+ m_pPixmapServer->remove(KRootPixmap::pixmapName(i+1));
+ }
+ }
+}
+
+
+/*
+ * Try to free up to size bytes from the cache.
+ */
+bool KBackgroundManager::freeCache(int size)
+{
+ if (m_bExport || !m_bLimitCache)
+ return true;
+
+ // If it doesn't fit at all, return now.
+ if (size > m_CacheLimit)
+ return false;
+
+ // If cache is too full, purge it (LRU)
+ while (size+cacheSize() > m_CacheLimit)
+ {
+ int j, min;
+ min = m_Serial+1; j = 0;
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ {
+ if (m_Cache[i]->pixmap && (m_Cache[i]->atime < min))
+ {
+ min = m_Cache[i]->atime;
+ j = i;
+ }
+ }
+ removeCache(j);
+ }
+ return true;
+}
+
+
+/*
+ * Try to add a pixmap to the pixmap cache. We don't use TQPixmapCache here
+ * because if we're exporting pixmaps, this needs special care.
+ */
+void KBackgroundManager::addCache(KPixmap *pm, int hash, int desk)
+{
+ if (m_Cache[desk]->pixmap)
+ removeCache(desk);
+
+ if (m_bLimitCache && !m_bExport && !freeCache(pixmapSize(pm)))
+ {
+ // pixmap does not fit in cache
+ delete pm;
+ return;
+ }
+
+ m_Cache[desk]->pixmap = pm;
+ m_Cache[desk]->hash = hash;
+ m_Cache[desk]->atime = m_Serial;
+ m_Cache[desk]->exp_from = -1;
+ exportBackground(desk, desk);
+}
+
+/*
+ * Called every minute to check if we need to rerun a background program.
+ * or change a wallpaper.
+ */
+void KBackgroundManager::slotTimeout()
+{
+ TQMemArray<int> running(m_Renderer.size());
+ running.fill(0);
+
+ int NumDesks = m_Renderer.size();
+ if (m_bCommon)
+ NumDesks = 1;
+
+ int edesk = effectiveDesktop();
+
+ for (int i=0; i<NumDesks; i++)
+ {
+ KVirtualBGRenderer *r = m_Renderer[i];
+ bool change = false;
+
+ if (r->needProgramUpdate())
+ {
+ r->programUpdate();
+ change = true;
+ }
+
+ if (r->needWallpaperChange())
+ {
+ r->changeWallpaper();
+ change = true;
+ }
+
+ if (change && (i == edesk))
+ {
+ running[i] = r->hash();
+ r->start();
+ }
+ }
+}
+
+// Return a valid desk number.
+int KBackgroundManager::validateDesk(int desk)
+{
+ if (desk > (int)m_Renderer.size())
+ slotChangeNumberOfDesktops( m_pKwinmodule->numberOfDesktops() );
+
+ if ( (desk <= 0) || (desk > (int)m_Renderer.size()) )
+ return realDesktop();
+
+ return desk - 1;
+}
+
+// DCOP exported
+// Return current wallpaper for specified desk.
+// 0 is for the current visible desktop.
+TQString KBackgroundManager::currentWallpaper(int desk)
+{
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ KCrossBGRender *r = m_Renderer[validateDesk(desk)]->renderer(0);
+
+ return r->currentWallpaper();
+}
+
+// DCOP exported
+void KBackgroundManager::changeWallpaper()
+{
+ KVirtualBGRenderer *r = m_Renderer[effectiveDesktop()];
+
+ r->changeWallpaper();
+ slotChangeDesktop(0);
+}
+
+// DCOP exported
+void KBackgroundManager::setExport(int _export)
+{
+// kdDebug() << "KBackgroundManager enabling exports.\n";
+ bool changed = (_export != m_bExport);
+ applyExport(_export);
+ if (changed) {
+ slotChangeDesktop(0);
+ }
+}
+
+// DCOP exported
+void KBackgroundManager::setCommon(int common)
+{
+ applyCommon(common);
+ KDesktopSettings::setCommonDesktop( m_bCommon );
+ KDesktopSettings::writeConfig();
+ slotChangeDesktop(0);
+}
+
+// DCOP exported
+void KBackgroundManager::setWallpaper(TQString wallpaper, int mode)
+{
+ if (mode < 0 || mode >= KBackgroundSettings::lastWallpaperMode) {
+ kdDebug() << "Invalid background mode " << mode << " passed to " << k_funcinfo << "\n";
+ return;
+ }
+
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ for (unsigned i=0; i < m_Renderer[effectiveDesktop()]->numRenderers(); ++i)
+ {
+ KCrossBGRender *r = m_Renderer[effectiveDesktop()]->renderer(i);
+ r->stop();
+ r->setWallpaperMode(mode);
+ r->setMultiWallpaperMode(KBackgroundSettings::NoMulti);
+ r->setWallpaper(wallpaper);
+ r->writeSettings();
+ }
+ slotChangeDesktop(0);
+}
+
+void KBackgroundManager::setWallpaper(TQString wallpaper)
+{
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ KCrossBGRender *r = m_Renderer[effectiveDesktop()]->renderer(0);
+ int mode = r->wallpaperMode();
+ if (mode == KBackgroundSettings::NoWallpaper)
+ mode = KBackgroundSettings::Tiled;
+ setWallpaper(wallpaper, mode);
+}
+
+// DCOP exported
+// Returns the filenames of all wallpaper entries for specified desk
+// 0 is for current visible desktop.
+TQStringList KBackgroundManager::wallpaperFiles(int desk)
+{
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ KCrossBGRender *r = m_Renderer[validateDesk(desk)]->renderer(0);
+
+ return r->wallpaperFiles();
+}
+
+// DCOP exported
+// Returns the list of wallpaper entries (viewable in background slide
+// show window) for specified desk. 0 is for current visible desktop.
+TQStringList KBackgroundManager::wallpaperList(int desk)
+{
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ KCrossBGRender *r = m_Renderer[validateDesk(desk)]->renderer(0);;
+
+ return r->wallpaperList();
+}
+
+// DCOP exported
+void KBackgroundManager::setCache( int bLimit, int size )
+{
+ applyCache( bLimit, size*1024 );
+ KDesktopSettings::setLimitCache( (bool) bLimit );
+ KDesktopSettings::setCacheSize( size );
+ KDesktopSettings::writeConfig();
+}
+
+// DCOP exported
+void KBackgroundManager::setWallpaper(int desk, TQString wallpaper, int mode)
+{
+ if (mode < 0 || mode >= KBackgroundSettings::lastWallpaperMode) {
+ kdDebug() << "Invalid background mode " << mode << " passed to " << k_funcinfo << "\n";
+ return;
+ }
+
+ int sdesk = validateDesk(desk);
+
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ for (unsigned i=0; i < m_Renderer[sdesk]->numRenderers(); ++i)
+ {
+ KCrossBGRender *r = m_Renderer[sdesk]->renderer(i);
+
+ setCommon(false); // Force each desktop to have it's own wallpaper
+
+ r->stop();
+ r->setWallpaperMode(mode);
+ r->setMultiWallpaperMode(KBackgroundSettings::NoMulti);
+ r->setWallpaper(wallpaper);
+ r->writeSettings();
+ }
+ slotChangeDesktop(sdesk);
+}
+
+void KBackgroundManager::repaintBackground()
+{
+ if (m_pDesktop)
+ m_pDesktop->repaint();
+ else
+ TQT_TQWIDGET(TDEApplication::desktop()->screen())->erase();
+}
+
+void KBackgroundManager::desktopResized()
+{
+ resizingDesktop = true;
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ {
+ KVirtualBGRenderer * r = m_Renderer[i];
+ if( r->isActive())
+ r->stop();
+ removeCache(i);
+ // make the renderer update its desktop size
+ r->desktopResized();
+ for (unsigned j=0; j<(r->numRenderers()); ++j) {
+ r->renderer(j)->desktopResized();
+ }
+ }
+
+#ifdef COMPOSITE
+ if (m_tPixmap)
+ delete m_tPixmap;
+ m_tPixmap = new KPixmap(kapp->desktop()->size());
+ m_tPixmap->fill(TQColor(0, 0x0));
+#endif
+
+ m_Hash = 0;
+ if( m_pDesktop ) {
+ m_pDesktop->resize( kapp->desktop()->geometry().size());
+ if (m_Renderer[effectiveDesktop()]->renderer(0)->usingCrossXml()){
+ m_Renderer[effectiveDesktop()]->renderer(0)->changeWallpaper();
+ }
+ }
+ // Repaint desktop
+ slotChangeDesktop(0);
+ repaintBackground();
+
+ // Redraw all desktops so that applications relying on exported data, e.g. kpager, continue to work properly
+ TQSize s(m_pKwinmodule->numberOfViewports(m_pKwinmodule->currentDesktop()));
+ m_numberOfViewports = s.width() * s.height();
+ if (m_numberOfViewports < 1) {
+ m_numberOfViewports = 1;
+ }
+ for (signed j=0;j<(m_pKwinmodule->numberOfDesktops() * m_numberOfViewports);j++) {
+ renderBackground(j);
+ }
+}
+
+// DCOP exported
+void KBackgroundManager::setColor(const TQColor & c, bool isColorA)
+{
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ for (unsigned i=0; i < m_Renderer[effectiveDesktop()]->numRenderers(); ++i)
+ {
+ KCrossBGRender *r = m_Renderer[effectiveDesktop()]->renderer(i);
+ r->stop();
+
+ if (isColorA)
+ r->setColorA(c);
+ else
+ r->setColorB(c);
+
+ int mode = r->backgroundMode();
+ if (mode == KBackgroundSettings::Program)
+ mode = KBackgroundSettings::Flat;
+
+ if (!isColorA && (mode == KBackgroundSettings::Flat))
+ mode = KBackgroundSettings::VerticalGradient;
+ r->setBackgroundMode(mode);
+
+ r->writeSettings();
+ }
+ slotChangeDesktop(0);
+}
+
+void KBackgroundManager::setBackgroundEnabled( const bool enable )
+{
+ if (m_bEnabled == enable)
+ return;
+
+ m_bEnabled= enable;
+
+ int NumDesks = m_Renderer.size();
+ if (m_bCommon)
+ NumDesks = 1;
+
+ for (int i=0; i<NumDesks; i++)
+ {
+ m_Renderer[i]->setEnabled(enable);
+ }
+ slotChangeDesktop(0);
+}
+
+#ifdef COMPOSITE
+void KBackgroundManager::slotCmBackgroundChanged( bool )
+{
+ m_tPixmap->fill(TQColor(0, 0x0));
+ m_Hash = 0;
+ slotChangeDesktop(0);
+}
+#endif
+
+#include "bgmanager.moc"