/* vi: ts=8 sts=4 sw=4
 * kate: space-indent on; indent-width 4; indent-mode cstyle;
 *
 * This file is part of the KDE project, module kdesktop.
 * Copyright (C) 1999 Geert Jansen <g.t.jansen@stud.tue.nl>
 *
 * You can Freely distribute this program under the GNU Library General
 * Public License. See the file "COPYING.LIB" for the exact licensing terms.
 */

#include <netwm.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>

// Clean up after X.h/Xlib.h
#undef Bool
#undef Unsorted

#include <qdir.h>
#include <qpixmap.h>

#include <dcopclient.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kglobalsettings.h>
#include <ksimpleconfig.h>
#include <kstandarddirs.h>
#include <krandomsequence.h>
#include <konq_defaults.h>

#include "bgdefaults.h"
#include "bghash.h"
#include "bgsettings.h"


/**** KBackgroundPattern ****/


KBackgroundPattern::KBackgroundPattern(QString name)
{
    dirty = false;
    hashdirty = true;

    m_pDirs = KGlobal::dirs();
    m_pDirs->addResourceType("dtop_pattern", m_pDirs->kde_default("data") +
                             "kdesktop/patterns");
    m_pConfig = 0L;

    m_Name = name;
    if (m_Name.isEmpty())
        return;

    init();
    readSettings();
}


KBackgroundPattern::~KBackgroundPattern()
{
    delete m_pConfig;
}

void KBackgroundPattern::copyConfig(const KBackgroundPattern *settings)
{
    dirty = hashdirty = true;
    m_Name = settings->m_Name;
    m_Comment = settings->m_Comment;
    m_Pattern = settings->m_Pattern;
    m_File = settings->m_File;
}

void KBackgroundPattern::load(QString name)
{
    m_Name = name;
    init();
    readSettings();
}


void KBackgroundPattern::init(bool force_rw)
{
    delete m_pConfig;

    m_File = m_pDirs->findResource("dtop_pattern", m_Name + ".desktop");
    if (force_rw || m_File.isEmpty()) {
        m_File = m_pDirs->saveLocation("dtop_pattern") + m_Name + ".desktop";
        m_pConfig = new KSimpleConfig(m_File);
    } else
        m_pConfig = new KSimpleConfig(m_File);

    m_pConfig->setGroup("KDE Desktop Pattern");

    QFileInfo fi(m_File);
    m_bReadOnly = !fi.isWritable();
}


void KBackgroundPattern::setComment(const QString &comment)
{
    if (m_Comment == comment)
        return;
    dirty = true;
    m_Comment = comment;
}


void KBackgroundPattern::setPattern(QString pattern)
{
    if (m_Pattern == pattern)
        return;
    dirty = hashdirty = true;
    m_Pattern = pattern;
}


void KBackgroundPattern::readSettings()
{
    dirty = false;
    hashdirty = true;

    m_Pattern = m_pConfig->readPathEntry("File");
    m_Comment = m_pConfig->readEntry("Comment");
    if (m_Comment.isEmpty())
       m_Comment = m_File.mid(m_File.findRev('/')+1);
}


void KBackgroundPattern::writeSettings()
{
    if (!dirty)
        return;
    if (m_bReadOnly)
        init(true);

    if ( !m_pConfig )
        return; // better safe than sorry

    m_pConfig->writePathEntry("File", m_Pattern);
    m_pConfig->writeEntry("Comment", m_Comment);
    m_pConfig->sync();
    dirty = false;
}


bool KBackgroundPattern::isAvailable()
{
    if (m_Pattern.isEmpty())
       return false;
    QString file = m_Pattern;
    if (file.at(0) != '/')
        file = m_pDirs->findResource("dtop_pattern", file);
    QFileInfo fi(file);
    return (fi.exists());
}


bool KBackgroundPattern::remove()
{
    if (m_bReadOnly)
        return false;
    return !unlink(QFile::encodeName(m_File));
}


QString KBackgroundPattern::fingerprint()
{
    return m_File;
}


int KBackgroundPattern::hash()
{
    if (hashdirty) {
	m_Hash = QHash(fingerprint());
	hashdirty = false;
    }
    return m_Hash;
}


/* static */
QStringList KBackgroundPattern::list()
{
    KStandardDirs *dirs = KGlobal::dirs();
    dirs->addResourceType("dtop_pattern", dirs->kde_default("data") +
                          "kdesktop/patterns");
    QStringList lst = dirs->findAllResources("dtop_pattern", "*.desktop",
                                             false, true);
    QStringList::Iterator it;
    for (it=lst.begin(); it!=lst.end(); ++it) {
        // Strip path and suffix
        int pos = (*it).findRev('/');
        if (pos != -1)
            (*it) = (*it).mid(pos+1);
        pos = (*it).findRev('.');
        if (pos != -1)
            (*it) = (*it).left(pos);
    }
    return lst;
}


/**** KBackgroundProgram ****/


KBackgroundProgram::KBackgroundProgram(QString name)
{
    dirty = false;
    hashdirty = true;

    m_pDirs = KGlobal::dirs();
    m_pDirs->addResourceType("dtop_program", m_pDirs->kde_default("data") +
                             "kdesktop/programs");
    m_pConfig = 0L;

    // prevent updates when just constructed.
    m_LastChange = (int) time(0L);

    m_Name = name;
    if (m_Name.isEmpty())
        return;

    init();
    readSettings();
}


KBackgroundProgram::~KBackgroundProgram()
{
    delete m_pConfig;
}

void KBackgroundProgram::copyConfig(const KBackgroundProgram *settings)
{
    dirty = hashdirty = true;
    m_Refresh = settings->m_Refresh;
    m_LastChange = settings->m_LastChange;
    m_Name = settings->m_Name;
    m_Command = settings->m_Command;
    m_PreviewCommand = settings->m_PreviewCommand;
    m_Comment = settings->m_Comment;
    m_Executable = settings->m_Executable;
    m_File = settings->m_File;
}


void KBackgroundProgram::init(bool force_rw)
{
    delete m_pConfig;

    m_File = m_pDirs->findResource("dtop_program", m_Name + ".desktop");
    if (force_rw || m_File.isEmpty()) {
        m_File = m_pDirs->saveLocation("dtop_program") + m_Name + ".desktop";
        m_pConfig = new KSimpleConfig(m_File);
        m_bReadOnly = false;
    } else {
        m_pConfig = new KSimpleConfig(m_File);
        m_bReadOnly = (m_File != locateLocal("dtop_program", m_Name + ".desktop"));
    }
    m_pConfig->setGroup("KDE Desktop Program");
}


void KBackgroundProgram::load(const QString &name)
{
    m_Name = name;
    init();
    readSettings();
}


void KBackgroundProgram::setComment(const QString &comment)
{
    if (m_Comment == comment)
        return;
    dirty = true;
    m_Comment = comment;
}


void KBackgroundProgram::setExecutable(const QString &executable)
{
    if (m_Executable == executable)
        return;
    dirty = true;
    m_Executable = executable;
}


void KBackgroundProgram::setCommand(const QString &command)
{
    if (m_Command == command)
        return;
    dirty = hashdirty = true;
    m_Command = command;
}


void KBackgroundProgram::setPreviewCommand(const QString &command)
{
    if (m_PreviewCommand == command)
        return;
    dirty = true;
    m_PreviewCommand = command;
}


void KBackgroundProgram::setRefresh(int refresh)
{
    if (m_Refresh == refresh)
        return;
    dirty = hashdirty = true;
    m_Refresh = refresh;
}


void KBackgroundProgram::readSettings()
{
    dirty = false;
    hashdirty = true;

    m_Comment = m_pConfig->readEntry("Comment");
    m_Executable = m_pConfig->readPathEntry("Executable");
    m_Command = m_pConfig->readPathEntry("Command");
    m_PreviewCommand = m_pConfig->readPathEntry("PreviewCommand", m_Command);
    m_Refresh = m_pConfig->readNumEntry("Refresh", 300);
}


void KBackgroundProgram::writeSettings()
{
    if (!dirty)
        return;
    if (m_bReadOnly)
        init(true);

    if ( !m_pConfig )
        return; // better safe than sorry

    m_pConfig->writeEntry("Comment", m_Comment);
    m_pConfig->writePathEntry("Executable", m_Executable);
    m_pConfig->writePathEntry("Command", m_Command);
    m_pConfig->writeEntry("PreviewCommand", m_PreviewCommand);
    m_pConfig->writeEntry("Refresh", m_Refresh);
    m_pConfig->sync();
    dirty = false;
}


bool KBackgroundProgram::isAvailable()
{
    return !m_pDirs->findExe(m_Executable).isEmpty();
}


bool KBackgroundProgram::remove()
{
    if (m_bReadOnly)
        return false;
    return !unlink(QFile::encodeName(m_File));
}


bool KBackgroundProgram::needUpdate()
{
    return (m_LastChange + 60*m_Refresh <= time(0L));
}


void KBackgroundProgram::update()
{
    m_LastChange = (int) time(0L);
}


QString KBackgroundProgram::fingerprint()
{
    return QString("co:%1;re:%2").arg(m_Command).arg(m_Refresh);
}


int KBackgroundProgram::hash()
{
    if (hashdirty) {
	m_Hash = QHash(fingerprint());
	hashdirty = false;
    }
    return m_Hash;
}


/* static */
QStringList KBackgroundProgram::list()
{
    KStandardDirs *dirs = KGlobal::dirs();
    dirs->addResourceType("dtop_program", dirs->kde_default("data") +
                          "kdesktop/programs");
    QStringList lst = dirs->findAllResources("dtop_program", "*.desktop",
                                             false, true);
    QStringList::Iterator it;
    for (it=lst.begin(); it!=lst.end(); ++it) {
        // Strip path and suffix
        int pos = (*it).findRev('/');
        if (pos != -1)
            (*it) = (*it).mid(pos+1);
        pos = (*it).findRev('.');
        if (pos != -1)
            (*it) = (*it).left(pos);
    }
    return lst;
}


/**** KBackgroundSettings ****/


KBackgroundSettings::KBackgroundSettings(int desk, int screen, bool drawBackgroundPerScreen, KConfig *config)
    : KBackgroundPattern(),
      KBackgroundProgram()
{
    dirty = false; hashdirty = true;
	m_bDrawBackgroundPerScreen = drawBackgroundPerScreen;
    m_Desk = desk;
    m_Screen = screen;
    m_bEnabled = true;

    // Default values.
    defColorA = _defColorA;
    defColorB = _defColorB;
    if (QPixmap::defaultDepth() > 8)
        defBackgroundMode = _defBackgroundMode;
    else
        defBackgroundMode = Flat;
    defWallpaperMode = _defWallpaperMode;
    defMultiMode = _defMultiMode;
    defBlendMode = _defBlendMode;
    defBlendBalance = _defBlendBalance;
    defReverseBlending = _defReverseBlending;

    m_MinOptimizationDepth = _defMinOptimizationDepth;
    m_bShm = _defShm;

    // Background modes
    #define ADD_STRING(ID) m_BMMap[#ID] = ID; m_BMRevMap[ID] = (char *) #ID;
    ADD_STRING(Flat)
    ADD_STRING(Pattern)
    ADD_STRING(Program)
    ADD_STRING(HorizontalGradient)
    ADD_STRING(VerticalGradient)
    ADD_STRING(PyramidGradient)
    ADD_STRING(PipeCrossGradient)
    ADD_STRING(EllipticGradient)
    #undef ADD_STRING

    // Blend modes
    #define ADD_STRING(ID) m_BlMMap[#ID] = ID; m_BlMRevMap[ID] = (char *) #ID;
    ADD_STRING(NoBlending)
    ADD_STRING(FlatBlending)
    ADD_STRING(HorizontalBlending)
    ADD_STRING(VerticalBlending)
    ADD_STRING(PyramidBlending)
    ADD_STRING(PipeCrossBlending)
    ADD_STRING(EllipticBlending)
    ADD_STRING(IntensityBlending)
    ADD_STRING(SaturateBlending)
    ADD_STRING(ContrastBlending)
    ADD_STRING(HueShiftBlending)
    #undef ADD_STRING

    // Wallpaper modes
    #define ADD_STRING(ID) m_WMMap[#ID] = ID; m_WMRevMap[ID] = (char *) #ID;
    ADD_STRING(NoWallpaper)
    ADD_STRING(Centred)
    ADD_STRING(Tiled)
    ADD_STRING(CenterTiled)
    ADD_STRING(CentredMaxpect)
    ADD_STRING(TiledMaxpect)
    ADD_STRING(Scaled)
    ADD_STRING(CentredAutoFit)
    ADD_STRING(ScaleAndCrop)
    #undef ADD_STRING

    // Multiple wallpaper modes
    #define ADD_STRING(ID) m_MMMap[#ID] = ID; m_MMRevMap[ID] = (char *) #ID;
    ADD_STRING(NoMulti)
    ADD_STRING(InOrder)
    ADD_STRING(Random)
    ADD_STRING(NoMultiRandom)
    #undef ADD_STRING

    m_pDirs = KGlobal::dirs();

    if (!config) {
        int screen_number = 0;
        if (qt_xdisplay())
            screen_number = DefaultScreen(qt_xdisplay());
        QCString configname;
        if (screen_number == 0)
            configname = "kdesktoprc";
        else
            configname.sprintf("kdesktop-screen-%drc", screen_number);

        m_pConfig = new KConfig(configname, false, false);
        m_bDeleteConfig = true;
    } else {
        m_pConfig = config;
        m_bDeleteConfig = false;
    }

    if (m_Desk == -1)
	return;

    readSettings();
}


KBackgroundSettings::~KBackgroundSettings()
{
    if (m_bDeleteConfig)
        delete m_pConfig;
}

void KBackgroundSettings::copyConfig(const KBackgroundSettings *settings)
{
    dirty = true;
    hashdirty = true;

    m_ColorA = settings->m_ColorA;
    m_ColorB = settings->m_ColorB;
    m_Wallpaper = settings->m_Wallpaper;
    m_WallpaperList = settings->m_WallpaperList;
    m_WallpaperFiles = settings->m_WallpaperFiles;

    m_BackgroundMode = settings->m_BackgroundMode;
    m_WallpaperMode = settings->m_WallpaperMode;
    m_BlendMode = settings->m_BlendMode;
    m_BlendBalance = settings->m_BlendBalance;
    m_ReverseBlending = settings->m_ReverseBlending;
    m_MinOptimizationDepth = settings->m_MinOptimizationDepth;
    m_bShm = settings->m_bShm;
    m_MultiMode = settings->m_MultiMode;
    m_Interval = settings->m_Interval;
    m_CurrentWallpaper = settings->m_CurrentWallpaper;
    m_CurrentWallpaperName = settings->m_CurrentWallpaperName;

    KBackgroundPattern::copyConfig(settings);
    KBackgroundProgram::copyConfig(settings);
}


void KBackgroundSettings::load(int desk, int screen, bool drawBackgroundPerScreen, bool reparseConfig)
{
    m_Desk = desk;
    m_Screen = screen;	
    m_bDrawBackgroundPerScreen = drawBackgroundPerScreen;
    readSettings(reparseConfig);
}


void KBackgroundSettings::setColorA(const QColor& color)
{
    if (m_ColorA == color)
        return;
    dirty = hashdirty = true;
    m_ColorA = color;
}


void KBackgroundSettings::setColorB(const QColor& color)
{
    if (m_ColorB == color)
        return;
    dirty = hashdirty = true;
    m_ColorB = color;
}


void KBackgroundSettings::setPatternName(QString name)
{
    int ohash = KBackgroundPattern::hash();
    KBackgroundPattern::load(name);
    if (ohash == KBackgroundPattern::hash())
	return;

    dirty = hashdirty = true;
    return;
}


void KBackgroundSettings::setProgram(QString name)
{
    int ohash = KBackgroundProgram::hash();
    KBackgroundProgram::load(name);
    if (ohash == KBackgroundProgram::hash())
	return;

    dirty = hashdirty = true;
    return;
}


void KBackgroundSettings::setBackgroundMode(int mode)
{
    if (m_BackgroundMode == mode)
	return;
    dirty = hashdirty = true;
    m_BackgroundMode = mode;
}

void KBackgroundSettings::setBlendMode(int mode)
{
    if (m_BlendMode == mode)
	return;
    dirty = hashdirty = true;
    m_BlendMode = mode;
}

void KBackgroundSettings::setBlendBalance(int value)
{
    if (m_BlendBalance == value)
	return;
    dirty = hashdirty = true;
    m_BlendBalance = value;
}

void KBackgroundSettings::setReverseBlending(bool value)
{
    if (m_ReverseBlending == value)
	return;
    dirty = hashdirty = true;
    m_ReverseBlending = value;
}


void KBackgroundSettings::setWallpaper(QString wallpaper)
{
    dirty = hashdirty = true;
    m_Wallpaper = wallpaper;
}


void KBackgroundSettings::setWallpaperMode(int mode)
{
    if (m_WallpaperMode == mode)
        return;
    dirty = hashdirty = true;
    m_WallpaperMode = mode;
}


void KBackgroundSettings::setWallpaperList(QStringList list)
{
    KStandardDirs *d = KGlobal::dirs();
    if (m_WallpaperList == list)
	return;

    dirty = hashdirty = true;
    m_WallpaperList.clear();
    for(QStringList::ConstIterator it = list.begin();
        it != list.end(); ++it)
    {
       QString rpath = d->relativeLocation("wallpaper", *it);
       m_WallpaperList.append( !rpath.isEmpty() ? rpath : *it );
    }
    updateWallpaperFiles();
    // Try to keep the current wallpaper (-1 to set position to one before it)
    m_CurrentWallpaper = m_WallpaperFiles.findIndex(m_CurrentWallpaperName) - 1;
    changeWallpaper(m_CurrentWallpaper < 0);
}


void KBackgroundSettings::setWallpaperChangeInterval(int interval)
{
    if (m_Interval == interval)
	return;
    dirty = hashdirty = true;
    m_Interval = interval;
}


void KBackgroundSettings::setMultiWallpaperMode(int mode)
{
    if (m_MultiMode == mode)
	return;
    dirty = hashdirty = true;
    m_MultiMode = mode;
    changeWallpaper(true);
}


void KBackgroundSettings::setMinOptimizationDepth(int mode)
{
    if (m_MinOptimizationDepth == mode)
	return;
    dirty = hashdirty = true;
    m_MinOptimizationDepth = mode;
}

bool KBackgroundSettings::optimize() const
{
    switch( m_MinOptimizationDepth )
        {
        case AlwaysOpt :
            return true;
        case Opt16bpp :
            return QPixmap::defaultDepth() >= 16;
        case Opt15bpp :
            return QPixmap::defaultDepth() >= 15;
        case NeverOpt :
        default :
            return false;
        }
}

void KBackgroundSettings::setUseShm(bool use)
{
    if (m_bShm == use)
	return;
    dirty = hashdirty = true;
    m_bShm = use;
}

QString KBackgroundSettings::configGroupName() const
{
    QString screenName;
    if (m_bDrawBackgroundPerScreen)
        screenName = QString("Screen%1").arg(QString::number(m_Screen));
    return QString("Desktop%1%2").arg(m_Desk).arg(screenName);
}

void KBackgroundSettings::readSettings(bool reparse)
{
    if (reparse)
        m_pConfig->reparseConfiguration();

    m_pConfig->setGroup(configGroupName());

    // Background mode (Flat, div. Gradients, Pattern or Program)
    m_ColorA = m_pConfig->readColorEntry("Color1", &defColorA);
    m_ColorB = m_pConfig->readColorEntry("Color2", &defColorB);

    QString s = m_pConfig->readPathEntry("Pattern");
    if (!s.isEmpty())
        KBackgroundPattern::load(s);

    s = m_pConfig->readPathEntry("Program");
    if (!s.isEmpty())
        KBackgroundProgram::load(s);

    m_BackgroundMode = defBackgroundMode;
    s = m_pConfig->readEntry("BackgroundMode", "invalid");

    if (m_BMMap.contains(s)) {
        int mode = m_BMMap[s];
        // consistency check
        if  ( ((mode != Pattern) && (mode != Program)) ||
              ((mode == Pattern) && !pattern().isEmpty()) ||
              ((mode == Program) && !command().isEmpty())
            )
            m_BackgroundMode = mode;
    }

    m_BlendMode = defBlendMode;
    s = m_pConfig->readEntry("BlendMode", "invalid");
    if (m_BlMMap.contains(s)) {
      m_BlendMode = m_BlMMap[s];
    }

    m_BlendBalance = defBlendBalance;
    int value = m_pConfig->readNumEntry( "BlendBalance", defBlendBalance);
    if (value > -201 && value < 201)
      m_BlendBalance = value;

    m_ReverseBlending = m_pConfig->readBoolEntry( "ReverseBlending", defReverseBlending);

    // Multiple wallpaper config
    m_WallpaperList = m_pConfig->readPathListEntry("WallpaperList");

    m_Interval = m_pConfig->readNumEntry("ChangeInterval", 60);
    m_LastChange = m_pConfig->readNumEntry("LastChange", 0);
    m_CurrentWallpaper = m_pConfig->readNumEntry("CurrentWallpaper", 0);
    m_CurrentWallpaperName = m_pConfig->readEntry("CurrentWallpaperName");

    m_MultiMode = defMultiMode;
    s = m_pConfig->readEntry("MultiWallpaperMode");
    if (m_MMMap.contains(s)) {
	int mode = m_MMMap[s];
	m_MultiMode = mode;
    }

    updateWallpaperFiles();
    if( !m_CurrentWallpaperName.isEmpty())
        m_CurrentWallpaper = m_WallpaperFiles.findIndex(m_CurrentWallpaperName);
    if(m_CurrentWallpaper < 0)
        m_CurrentWallpaper = 0;

    // Wallpaper mode (NoWallpaper, div. tilings)
    m_WallpaperMode = defWallpaperMode;
    m_Wallpaper = m_pConfig->readPathEntry("Wallpaper");
    s = m_pConfig->readEntry("WallpaperMode", "invalid");
    if (m_WMMap.contains(s)) {
        int mode = m_WMMap[s];
        // consistency check.
        if ((mode == NoWallpaper) || !m_Wallpaper.isEmpty() || (m_MultiMode == InOrder || m_MultiMode == Random))
            m_WallpaperMode = mode;
    }

    m_MinOptimizationDepth = m_pConfig->readNumEntry( "MinOptimizationDepth",
        _defMinOptimizationDepth );
    m_bShm = m_pConfig->readBoolEntry( "UseSHM", _defShm );

    dirty = reparse; hashdirty = true;
}


void KBackgroundSettings::writeSettings()
{
    KBackgroundPattern::writeSettings();
    KBackgroundProgram::writeSettings();

    if (!dirty)
        return;

    m_pConfig->setGroup(configGroupName());
    m_pConfig->writeEntry("Color1", m_ColorA);
    m_pConfig->writeEntry("Color2", m_ColorB);
    m_pConfig->writePathEntry("Pattern", KBackgroundPattern::name());
    m_pConfig->writeEntry("Program", KBackgroundProgram::name());
    m_pConfig->writeEntry("BackgroundMode", m_BMRevMap[m_BackgroundMode]);
    m_pConfig->writePathEntry("Wallpaper", m_Wallpaper);
    m_pConfig->writeEntry("WallpaperMode", m_WMRevMap[m_WallpaperMode]);
    m_pConfig->writeEntry("MultiWallpaperMode", m_MMRevMap[m_MultiMode]);
    m_pConfig->writeEntry("BlendMode", m_BlMRevMap[m_BlendMode]);
    m_pConfig->writeEntry("BlendBalance", m_BlendBalance);
    m_pConfig->writeEntry("ReverseBlending", m_ReverseBlending);
    m_pConfig->writeEntry("MinOptimizationDepth", m_MinOptimizationDepth);
    m_pConfig->writeEntry("UseSHM", m_bShm);

    m_pConfig->writePathEntry("WallpaperList", m_WallpaperList);
    m_pConfig->writeEntry("ChangeInterval", m_Interval);
    m_pConfig->writeEntry("LastChange", m_LastChange);
    m_pConfig->deleteEntry("CurrentWallpaper"); // obsolete, remember name
    m_pConfig->writeEntry("CurrentWallpaperName", m_CurrentWallpaperName);

    m_pConfig->sync();

    dirty = false;
}

/*
 * (re)Build m_WallpaperFiles from m_WallpaperList
 */
void KBackgroundSettings::updateWallpaperFiles()
{
    QStringList::Iterator it;
    m_WallpaperFiles.clear();
    for (it=m_WallpaperList.begin(); it!=m_WallpaperList.end(); ++it) {
        QString file = locate("wallpaper", *it);
        if (file.isEmpty())
            continue;
	QFileInfo fi(file);
	if (!fi.exists())
	    continue;
	if (fi.isFile() && fi.isReadable())
	    m_WallpaperFiles.append(file);
	if (fi.isDir()) {
	    QDir dir(file);
	    QStringList lst = dir.entryList(QDir::Files | QDir::Readable);
	    QStringList::Iterator it;
	    for (it=lst.begin(); it!=lst.end(); ++it)
	    {
		file = dir.absFilePath(*it);
		QFileInfo fi(file);
		if (fi.isFile() && fi.isReadable())
		    m_WallpaperFiles.append(file);
	    }
	}
    }

   if (m_MultiMode == Random)
       randomizeWallpaperFiles();
}

// Randomize the m_WallpaperFiles in a non-repeating method.
void KBackgroundSettings::randomizeWallpaperFiles()
{
   if (m_WallpaperFiles.count() < 4)
      return;

   KRandomSequence rseq;
   QStringList tmpList = m_WallpaperFiles;
   QStringList randomList;
   randomList.append(tmpList.front());
   tmpList.pop_front();
   while(tmpList.count())
   {
      randomList.insert(randomList.at(
         rseq.getLong(randomList.count()+1)),
         1, tmpList.front());

      tmpList.pop_front();
   }
   m_WallpaperFiles = randomList;
}

QStringList KBackgroundSettings::wallpaperList() const
{
    if ( m_WallpaperMode == NoWallpaper )
        return QStringList();
    if ( m_MultiMode == NoMulti || m_MultiMode == NoMultiRandom )
        return QStringList(m_Wallpaper);
    return m_WallpaperList;
}

QStringList KBackgroundSettings::wallpaperFiles() const
{
    if ( m_WallpaperMode == NoWallpaper )
        return QStringList();
    if ( m_MultiMode == NoMulti || m_MultiMode == NoMultiRandom )
        return QStringList(m_Wallpaper);
    return m_WallpaperFiles;
}

/*
 * Select a new wallpaper from the list.
 */
void KBackgroundSettings::changeWallpaper(bool init)
{
    if (m_WallpaperFiles.count() == 0) {
        if( init ) {
	    m_CurrentWallpaper = 0;
            m_CurrentWallpaperName = QString();
        }
        return;
    }

    switch (m_MultiMode) {
    case InOrder:
	m_CurrentWallpaper++;
	if (init || (m_CurrentWallpaper >= (int) m_WallpaperFiles.count()))
	    m_CurrentWallpaper = 0;
	break;

    case Random:
      // Random: m_WallpaperFiles is randomized in a non-repeating
      //  method.  Hence we just increment the index.
      m_CurrentWallpaper++;
      if (init || (m_CurrentWallpaper >= (int) m_WallpaperFiles.count())) {
         m_CurrentWallpaper = 0;
         randomizeWallpaperFiles(); // Get a new random-ordered list.
      }
	break;
    default:
	break;
    }

    m_CurrentWallpaperName = m_WallpaperFiles[ m_CurrentWallpaper ];
    m_LastChange = (int) time(0L);
    m_pConfig->setGroup(configGroupName());
    m_pConfig->deleteEntry("CurrentWallpaper"); // obsolete, remember name
    m_pConfig->writeEntry("CurrentWallpaperName", m_CurrentWallpaperName);
    m_pConfig->writeEntry("LastChange", m_LastChange);
    m_pConfig->sync();

    hashdirty = true;
}


QString KBackgroundSettings::currentWallpaper() const
{
    if ( m_WallpaperMode == NoWallpaper )
	return QString::null;
    if (m_MultiMode == NoMulti || m_MultiMode == NoMultiRandom)
	return m_Wallpaper;

    if (m_CurrentWallpaper >= 0 && m_CurrentWallpaper < (int) m_WallpaperFiles.count())
	return m_WallpaperFiles[m_CurrentWallpaper];
    return QString::null;
}

bool KBackgroundSettings::discardCurrentWallpaper()
{
    if (m_MultiMode == NoMulti || m_MultiMode == NoMultiRandom)
    {
       return false;
    }
    m_WallpaperFiles.remove(m_WallpaperFiles.at(m_CurrentWallpaper));
    --m_CurrentWallpaper;
    changeWallpaper();

    return true;
}


bool KBackgroundSettings::needWallpaperChange()
{
    if (m_MultiMode == NoMulti || m_MultiMode == NoMultiRandom)
	return false;

    return ((m_LastChange + 60*m_Interval) <= time(0L));
}


/*
 * Create a fingerprint string for this config. Be somewhat (overly) carefull
 * that only a different final result will give a different fingerprint.
 */

QString KBackgroundSettings::fingerprint()
{
    QString s = QString("bm:%1;en:%2").arg(m_BackgroundMode).arg(m_bEnabled);
    switch (m_BackgroundMode) {
    case Flat:
        s += QString("ca:%1;").arg(m_ColorA.rgb());
        break;
    case Program:
        s += QString("pr:%1;").arg(KBackgroundProgram::hash());
        break;
    case Pattern:
        s += QString("ca:%1;cb:%2;pt:%3;").arg(m_ColorA.rgb())
	     .arg(m_ColorB.rgb()).arg(KBackgroundPattern::hash());
        break;
    default:
        s += QString("ca:%1;cb:%2;").arg(m_ColorA.rgb()).arg(m_ColorB.rgb());
        break;
    }

    s += QString("wm:%1;").arg(m_WallpaperMode);
    if (m_WallpaperMode != NoWallpaper)
    {
        Q_UINT32 rh = KGlobal::dirs()->calcResourceHash("wallpaper", currentWallpaper(), false);
        s += QString("wp:%2:%1;").arg(rh).arg(currentWallpaper());
        
    }
    s += QString("blm:%1;").arg(m_BlendMode);
    if (m_BlendMode != NoBlending) {
      s += QString("blb:%1;").arg(m_BlendBalance);
      s += QString("rbl:%1;").arg(int(m_ReverseBlending));
    }
    s += QString::number( m_bShm );
    s += QString::number( m_MinOptimizationDepth );

    return s;
}


int KBackgroundSettings::hash()
{
    if (hashdirty) {
        m_Hash = QHash(fingerprint());
	hashdirty = false;
    }
    return m_Hash;
}

void KBackgroundSettings::setEnabled(const bool enable)
{
  if (m_bEnabled == enable)
    return;

  m_bEnabled= enable;
  hashdirty = true;
}

/**** KGlobalBackgroundSettings ****/

KGlobalBackgroundSettings::KGlobalBackgroundSettings(KConfig *_config)
{
    m_pConfig = _config;

    readSettings();
}


QString KGlobalBackgroundSettings::deskName(int desk)
{
    return m_Names[desk];
}


/*
void KGlobalBackgroundSettings::setDeskName(int desk, QString name)
{
    if (name == m_Names[desk])
	return;
    dirty = true;
    m_Names[desk] = name;
}
*/


void KGlobalBackgroundSettings::setCacheSize(int size)
{
    if (size == m_CacheSize)
	return;
    dirty = true;
    m_CacheSize = size;
}


void KGlobalBackgroundSettings::setLimitCache(bool limit)
{
    if (limit == m_bLimitCache)
	return;
    dirty = true;
    m_bLimitCache = limit;
}


bool KGlobalBackgroundSettings::drawBackgroundPerScreen(int desk) const
{
    if ( desk > int(m_bDrawBackgroundPerScreen.size()) )
        return _defDrawBackgroundPerScreen;
    return m_bDrawBackgroundPerScreen[desk];
}


void KGlobalBackgroundSettings::setDrawBackgroundPerScreen(int desk, bool perScreen)
{
    if ( desk >= int(m_bDrawBackgroundPerScreen.size()) )
        return;
    
    if ( m_bDrawBackgroundPerScreen[desk] == perScreen )
        return;
    
    dirty = true;
    m_bDrawBackgroundPerScreen[desk] = perScreen;
}


void KGlobalBackgroundSettings::setCommonScreenBackground(bool common)
{
    if (common == m_bCommonScreen)
	return;
    dirty = true;
    m_bCommonScreen = common;
}


void KGlobalBackgroundSettings::setCommonDeskBackground(bool common)
{
    if (common == m_bCommonDesk)
	return;
    dirty = true;
    m_bCommonDesk = common;
}


void KGlobalBackgroundSettings::setDockPanel(bool dock)
{
    if (dock == m_bDock)
        return;
    dirty = true;
    m_bDock = dock;
}


void KGlobalBackgroundSettings::setExportBackground(bool _export)
{
    if (_export == m_bExport)
        return;
    dirty = true;
    m_bExport = _export;
}

void KGlobalBackgroundSettings::setTextColor(QColor _color)
{
    if (_color == m_TextColor)
        return;
    dirty = true;
    m_TextColor = _color;
}

void KGlobalBackgroundSettings::setTextBackgroundColor(QColor _color)
{
    if (_color == m_TextBackgroundColor)
        return;
    dirty = true;
    m_TextBackgroundColor = _color;
}

void KGlobalBackgroundSettings::setShadowEnabled(bool enabled)
{
    if (enabled == m_shadowEnabled)
        return;
    dirty = true;
    m_shadowEnabled = enabled;
}

void KGlobalBackgroundSettings::setTextLines(int lines)
{
    if (lines == m_textLines)
        return;
    dirty = true;
    m_textLines = lines;
}

void KGlobalBackgroundSettings::setTextWidth(int width)
{
    if (width == m_textWidth)
        return;
    dirty = true;
    m_textWidth = width;
}

void KGlobalBackgroundSettings::readSettings()
{
    m_pConfig->setGroup("Background Common");
    m_bCommonScreen = m_pConfig->readBoolEntry("CommonScreen", _defCommonScreen);
    m_bCommonDesk = m_pConfig->readBoolEntry("CommonDesktop", _defCommonDesk);
    m_bDock = m_pConfig->readBoolEntry("Dock", _defDock);
    m_bExport = m_pConfig->readBoolEntry("Export", _defExport);
    m_bLimitCache = m_pConfig->readBoolEntry("LimitCache", _defLimitCache);
    m_CacheSize = m_pConfig->readNumEntry("CacheSize", _defCacheSize);
    
    m_Names.clear();
    NETRootInfo info( qt_xdisplay(), NET::DesktopNames | NET::NumberOfDesktops );
    m_bDrawBackgroundPerScreen.resize(info.numberOfDesktops());
    for ( int i = 0 ; i < info.numberOfDesktops() ; ++i )
        m_bDrawBackgroundPerScreen[i] = m_pConfig->readBoolEntry( QString("DrawBackgroundPerScreen_%1").arg(i), _defDrawBackgroundPerScreen );

    m_TextColor = KGlobalSettings::textColor();
    m_pConfig->setGroup("FMSettings");
    m_TextColor = m_pConfig->readColorEntry("NormalTextColor", &m_TextColor);
    m_TextBackgroundColor = m_pConfig->readColorEntry("ItemTextBackground");
    m_shadowEnabled = m_pConfig->readBoolEntry("ShadowEnabled", true);
    m_textLines = m_pConfig->readNumEntry("TextHeight", DEFAULT_TEXTHEIGHT);
    m_textWidth = m_pConfig->readNumEntry("TextWidth", DEFAULT_TEXTWIDTH);

    for ( int i = 0 ; i < info.numberOfDesktops() ; ++i )
      m_Names.append( QString::fromUtf8(info.desktopName(i+1)) );

    dirty = false;
}

void KGlobalBackgroundSettings::writeSettings()
{
    if (!dirty)
        return;

    m_pConfig->setGroup("Background Common");
    m_pConfig->writeEntry("CommonScreen", m_bCommonScreen);
    m_pConfig->writeEntry("CommonDesktop", m_bCommonDesk);
    m_pConfig->writeEntry("Dock", m_bDock);
    m_pConfig->writeEntry("Export", m_bExport);
    m_pConfig->writeEntry("LimitCache", m_bLimitCache);
    m_pConfig->writeEntry("CacheSize", m_CacheSize);

    for ( unsigned i = 0 ; i < m_bDrawBackgroundPerScreen.size() ; ++i )
        m_pConfig->writeEntry(QString("DrawBackgroundPerScreen_%1").arg(i), m_bDrawBackgroundPerScreen[i] );

    m_pConfig->setGroup("FMSettings");
    m_pConfig->writeEntry("NormalTextColor", m_TextColor);
    m_pConfig->writeEntry("ItemTextBackground", m_TextBackgroundColor);
    m_pConfig->writeEntry("ShadowEnabled", m_shadowEnabled);
    m_pConfig->writeEntry("TextHeight", m_textLines);
    m_pConfig->writeEntry("TextWidth", m_textWidth);
    
    m_pConfig->sync();
    dirty = false;

    // tell kdesktop to get it's butt in gear and pick up the new settings
    QByteArray data;
    kapp->dcopClient()->send("kdesktop", "KDesktopIface", "configure()", data);
}

