|
|
|
/***************************************************************************
|
|
|
|
* Copyright Brian Ledbetter 2001-2003 <brian@shadowcom.net> *
|
|
|
|
* Copyright Ravikiran Rajagopal 2003 <ravi@kde.org> *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License (version 2) as *
|
|
|
|
* published by the Free Software Foundation. (The original KSplash/ML *
|
|
|
|
* codebase (upto version 0.95.3) is BSD-licensed.) *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <kcursor.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <klibloader.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <ktrader.h>
|
|
|
|
#include <kwin.h>
|
|
|
|
#include <dcopclient.h>
|
|
|
|
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <tqpixmap.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
|
|
|
|
#include "objkstheme.h"
|
|
|
|
#include "wndmain.h"
|
|
|
|
#include "wndmain.moc"
|
|
|
|
|
|
|
|
#include "themeengine.h"
|
|
|
|
#include "themelegacy.h"
|
|
|
|
|
|
|
|
// KSplash::KSplash(): This is a hidden object. Its sole purpose
|
|
|
|
// is to manage the other objects, which are presented on the screen.
|
|
|
|
KSplash::KSplash(const char *name)
|
|
|
|
: DCOPObject( name ), TQWidget( 0, name, (WFlags)(WStyle_Customize|WStyle_NoBorder|WX11BypassWM) ),
|
|
|
|
mState( 0 ), mMaxProgress( 0 ), mStep( 0 )
|
|
|
|
{
|
|
|
|
hide(); // We never show this object.
|
|
|
|
mThemeLibName = TQString::null;
|
|
|
|
mSessMgrCalled = false;
|
|
|
|
mTimeToGo = false;
|
|
|
|
|
|
|
|
KConfig * config = kapp->config();
|
|
|
|
slotReadProperties(config);
|
|
|
|
|
|
|
|
prepareSplashScreen();
|
|
|
|
prepareIconList();
|
|
|
|
|
|
|
|
mCurrentAction = mActionList.first();
|
|
|
|
|
|
|
|
config->setGroup( "General" );
|
|
|
|
if ( config->readBoolEntry( "CloseOnClick", TRUE ) )
|
|
|
|
mThemeEngine->installEventFilter( this );
|
|
|
|
|
|
|
|
connect( mThemeEngine, TQT_SIGNAL(destroyed()), this, TQT_SLOT(close()) );
|
|
|
|
connect( this, TQT_SIGNAL(stepsChanged(int)), TQT_SLOT(slotUpdateSteps(int)) );
|
|
|
|
connect( this, TQT_SIGNAL(progressChanged(int)), TQT_SLOT(slotUpdateProgress(int)) );
|
|
|
|
|
|
|
|
if( mKsTheme->testing() )
|
|
|
|
{
|
|
|
|
slotUpdateSteps(7);
|
|
|
|
TQTimer::singleShot( 1000, this, TQT_SLOT(slotExec()));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
TQTimer::singleShot( 100, this, TQT_SLOT(initDcop()));
|
|
|
|
|
|
|
|
// Make sure we don't stay up forever.
|
|
|
|
if (!mKsTheme->managedMode())
|
|
|
|
{
|
|
|
|
close_timer = new TQTimer( this );
|
|
|
|
connect( close_timer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( close() ) );
|
|
|
|
close_timer->start( 60000, TRUE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KSplash::~KSplash()
|
|
|
|
{
|
|
|
|
delete mThemeEngine;
|
|
|
|
delete mKsTheme;
|
|
|
|
delete close_timer;
|
|
|
|
if (!mThemeLibName.isEmpty())
|
|
|
|
KLibLoader::self()->unloadLibrary( mThemeLibName.latin1() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::slotReadProperties( KConfig *config )
|
|
|
|
{
|
|
|
|
KCmdLineArgs *arg = KCmdLineArgs::parsedArgs();
|
|
|
|
mTheme = arg->getOption("theme");
|
|
|
|
if (mTheme.isEmpty())
|
|
|
|
{
|
|
|
|
config->setGroup( "KSplash" );
|
|
|
|
mTheme = config->readEntry( "Theme", "Default" );
|
|
|
|
}
|
|
|
|
loadTheme( mTheme ); // Guaranteed to return a valid theme.
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::prepareIconList()
|
|
|
|
{
|
|
|
|
// Managed mode icons are specified via DCOP.
|
|
|
|
if( mKsTheme->managedMode() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
slotInsertAction( mKsTheme->icon( 1 ), mKsTheme->text( 1 ) );
|
|
|
|
|
|
|
|
mCurrentAction = mActionList.first();
|
|
|
|
slotSetText( mCurrentAction->ItemText );
|
|
|
|
slotSetPixmap( mCurrentAction->ItemPixmap );
|
|
|
|
emit progressChanged( mStep );
|
|
|
|
|
|
|
|
for (int indx = 2; indx <= 8; indx++)
|
|
|
|
slotInsertAction( mKsTheme->icon( indx ), mKsTheme->text( indx ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::prepareSplashScreen()
|
|
|
|
{
|
|
|
|
mThemeEngine->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::slotInsertAction( const TQString& pix, const TQString& msg )
|
|
|
|
{
|
|
|
|
Action *a = new Action;
|
|
|
|
a->ItemText = msg;
|
|
|
|
a->ItemPixmap = pix;
|
|
|
|
mActionList.append( a );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::slotExec()
|
|
|
|
{
|
|
|
|
TQTimer::singleShot( 200, this, TQT_SLOT(nextIcon()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::nextIcon()
|
|
|
|
{
|
|
|
|
if( !mCurrentAction || mTimeToGo )
|
|
|
|
{
|
|
|
|
TQTimer::singleShot( 1000, this, TQT_SLOT(close()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mCurrentAction = mActionList.next();
|
|
|
|
|
|
|
|
if( mCurrentAction )
|
|
|
|
{
|
|
|
|
slotSetText( mCurrentAction->ItemText );
|
|
|
|
slotSetPixmap( mCurrentAction->ItemPixmap );
|
|
|
|
emit progressChanged( ++mStep );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( mKsTheme->testing() )
|
|
|
|
TQTimer::singleShot( 1000, this, TQT_SLOT(nextIcon()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::initDcop()
|
|
|
|
{
|
|
|
|
disconnect( kapp->dcopClient(), TQT_SIGNAL( attachFailed(const TQString&) ), kapp, TQT_SLOT( dcopFailure(const TQString&) ) );
|
|
|
|
|
|
|
|
if ( kapp->dcopClient()->isAttached() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( kapp->dcopClient()->attach() )
|
|
|
|
{
|
|
|
|
if(!mKsTheme->managedMode())
|
|
|
|
upAndRunning( "dcop" );
|
|
|
|
kapp->dcopClient()->registerAs( "ksplash", false );
|
|
|
|
kapp->dcopClient()->setDefaultObject( objId() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TQTimer::singleShot( 100, this, TQT_SLOT(initDcop()) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::updateState( unsigned int state )
|
|
|
|
{
|
|
|
|
// The whole state updating in ksplashml is simply weird,
|
|
|
|
// nextIcon() and also the themes naively assume all states
|
|
|
|
// will come, and will come in the expected order, which
|
|
|
|
// is not guaranteed, and can happen easily with faster machines.
|
|
|
|
// And upAndRunning() even is written to handle it gracefully.
|
|
|
|
while( state > mState )
|
|
|
|
{
|
|
|
|
++mState;
|
|
|
|
nextIcon();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// For KDE startup only.
|
|
|
|
void KSplash::upAndRunning( TQString s )
|
|
|
|
{
|
|
|
|
// This code is written to match ksmserver. Touch it without knowing
|
|
|
|
// what you are doing and prepare to bite the dust.
|
|
|
|
bool update = true;
|
|
|
|
static bool firstTime = true;
|
|
|
|
|
|
|
|
if (firstTime)
|
|
|
|
{
|
|
|
|
emit stepsChanged(7);
|
|
|
|
firstTime = false;
|
|
|
|
}
|
|
|
|
if ( close_timer->isActive() )
|
|
|
|
close_timer->start( 60000, TRUE );
|
|
|
|
|
|
|
|
if( s == "dcop" )
|
|
|
|
{
|
|
|
|
if( mState > 1 ) return;
|
|
|
|
updateState( 1 );
|
|
|
|
mStep = 1;
|
|
|
|
}
|
|
|
|
else if( s == "kded" )
|
|
|
|
{
|
|
|
|
if( mState > 2 ) return;
|
|
|
|
updateState( 2 );
|
|
|
|
mStep = 2;
|
|
|
|
}
|
|
|
|
else if( s == "kcminit" )
|
|
|
|
; // No icon
|
|
|
|
else if( s == "ksmserver" )
|
|
|
|
{
|
|
|
|
if( mState > 3 ) return;
|
|
|
|
updateState( 3 );
|
|
|
|
mStep = 3;
|
|
|
|
}
|
|
|
|
else if( s == "wm started" )
|
|
|
|
{
|
|
|
|
if( mState > 4 ) return;
|
|
|
|
updateState( 4 );
|
|
|
|
mStep = 4;
|
|
|
|
}
|
|
|
|
else if( s == "kdesktop" )
|
|
|
|
{
|
|
|
|
if( mState > 5 ) return;
|
|
|
|
updateState( 5 );
|
|
|
|
mStep = 5;
|
|
|
|
}
|
|
|
|
else if( s == "kicker" || s == "session ready" )
|
|
|
|
{
|
|
|
|
updateState( 7 );
|
|
|
|
mStep = 9;
|
|
|
|
//if(!mSessMgrCalled) emit nextIcon();
|
|
|
|
mTimeToGo = true;
|
|
|
|
close_timer->stop();
|
|
|
|
TQTimer::singleShot( 1000, this, TQT_SLOT(close()));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdDebug() << "KSplash::upAndRunning(): bad s: " << s << endl;
|
|
|
|
update = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// For KDE startup only.
|
|
|
|
void KSplash::setMaxProgress(int max)
|
|
|
|
{
|
|
|
|
if( max < 1 )
|
|
|
|
max = 1;
|
|
|
|
if( mThemeEngine && mState >= 6 ) // show the progressbar only after kicker is ready
|
|
|
|
mThemeEngine->slotUpdateSteps( max );
|
|
|
|
mMaxProgress = max;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For KDE startup only.
|
|
|
|
void KSplash::setProgress(int step)
|
|
|
|
{
|
|
|
|
if( mThemeEngine )
|
|
|
|
mThemeEngine->slotUpdateProgress( mMaxProgress - step );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When a program starts, it sends a generic signal to KSplash indicating
|
|
|
|
* (a) which icon is to be displayed to the user //OR// a generic token-name
|
|
|
|
* indicating that KSplash can load a pre-configured icon, (b) the textual
|
|
|
|
* name of the process being started, and (c) a description of what the
|
|
|
|
* process is handling. Some examples:
|
|
|
|
*
|
|
|
|
* programStarted( TQString("desktop"), TQString("kdesktop"), TQString("Preparing your desktop..."));
|
|
|
|
*/
|
|
|
|
void KSplash::programStarted( TQString icon, TQString name, TQString desc )
|
|
|
|
{
|
|
|
|
if (mTimeToGo)
|
|
|
|
return;
|
|
|
|
// No isEmpty() here: empty strings are handled by the plugins and can be passed to update the counter.
|
|
|
|
if (name.isNull() && icon.isNull() && desc.isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
slotInsertAction( icon, desc );
|
|
|
|
mCurrentAction = mActionList.next();
|
|
|
|
slotSetText( desc );
|
|
|
|
slotSetPixmap( icon );
|
|
|
|
emit progressChanged( ++mStep );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::setStartupItemCount( int count )
|
|
|
|
{
|
|
|
|
emit stepsChanged( count );
|
|
|
|
emit progressChanged( mStep );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::startupComplete()
|
|
|
|
{
|
|
|
|
mTimeToGo = true;
|
|
|
|
TQTimer::singleShot( 1000, this, TQT_SLOT(close()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::close()
|
|
|
|
{
|
|
|
|
TQWidget::close();
|
|
|
|
#ifdef USE_QT4
|
|
|
|
exit(0);
|
|
|
|
#endif // USE_QT4
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::hide()
|
|
|
|
{
|
|
|
|
TQWidget::hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::show()
|
|
|
|
{
|
|
|
|
TQWidget::show();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Guaranteed to return a valid theme.
|
|
|
|
void KSplash::loadTheme( const TQString& theme )
|
|
|
|
{
|
|
|
|
mKsTheme = new ObjKsTheme( theme );
|
|
|
|
// kdDebug() << "KSplash::loadTheme: " << theme << " : "<< mKsTheme->themeEngine() << endl;
|
|
|
|
mThemeEngine = _loadThemeEngine( mKsTheme->themeEngine(), theme );
|
|
|
|
if (!mThemeEngine)
|
|
|
|
{
|
|
|
|
mThemeEngine = new ThemeDefault( this, "", theme );
|
|
|
|
kdDebug() << "Standard theme loaded." << endl;
|
|
|
|
}
|
|
|
|
// The theme engine we get may not be the theme engine we requested.
|
|
|
|
delete mKsTheme;
|
|
|
|
mKsTheme = mThemeEngine->ksTheme();
|
|
|
|
}
|
|
|
|
|
|
|
|
ThemeEngine *KSplash::_loadThemeEngine( const TQString& pluginName, const TQString& theme )
|
|
|
|
{
|
|
|
|
// Since we may be called before the DCOP server is active, we cannot use the KTrader framework for obtaining plugins. In its
|
|
|
|
// place, we use the following naive heuristic to locate plugins. If we are not in managed mode, and we are not in testing mode
|
|
|
|
// either, we assume that we have been called by startkde. In this case, we simply try to load the library whose name should
|
|
|
|
// conform to the following specification:
|
|
|
|
// TQString("ksplash") + pluginName.lower()
|
|
|
|
// The object should be called as follows:
|
|
|
|
// TQString("Theme") + pluginName
|
|
|
|
KLibFactory *factory = 0L;
|
|
|
|
TQString libName;
|
|
|
|
TQString objName;
|
|
|
|
// Replace this test by a "nodcop" command line option.
|
|
|
|
if ( /*!mKsTheme->managedMode() ||*/ !KCmdLineArgs::parsedArgs()->isSet( "dcop" ) )
|
|
|
|
{
|
|
|
|
libName = TQString("ksplash%1").arg(pluginName.lower());
|
|
|
|
objName = TQString("Theme%1").arg(pluginName);
|
|
|
|
// kdDebug() << "*KSplash::_loadThemeEngine: Loading " << objName << " from " << libName << endl;
|
|
|
|
// libname.latin1() instead of TQFile::encodeName() because these are not user-modifiable files.
|
|
|
|
if ( (factory = KLibLoader::self()->factory ( libName.latin1() )) )
|
|
|
|
mThemeLibName = libName;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Fancier way of locating plugins.
|
|
|
|
KService::List list= KTrader::self()->query("KSplash/Plugin", TQString("[X-KSplash-PluginName] == '%1'").arg(pluginName));
|
|
|
|
KService::Ptr ptr;
|
|
|
|
if (!list.isEmpty())
|
|
|
|
{
|
|
|
|
ptr = list.first();
|
|
|
|
// libname.latin1() instead of TQFile::encodeName() because these are not user-modifiable files.
|
|
|
|
if( (factory = KLibLoader::self()->factory( ptr->library().latin1() )) )
|
|
|
|
{
|
|
|
|
mThemeLibName = ptr->library();
|
|
|
|
objName = ptr->property("X-KSplash-ObjectName").toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (factory)
|
|
|
|
{
|
|
|
|
TQStringList themeTitle;
|
|
|
|
themeTitle << theme;
|
|
|
|
return static_cast<ThemeEngine *>(TQT_TQWIDGET(factory->create(TQT_TQOBJECT(this), "theme", objName.latin1(), themeTitle)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::slotSetText( const TQString& s )
|
|
|
|
{
|
|
|
|
if( mThemeEngine )
|
|
|
|
mThemeEngine->slotSetText( s );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::slotSetPixmap( const TQString& px )
|
|
|
|
{
|
|
|
|
if( mThemeEngine )
|
|
|
|
mThemeEngine->slotSetPixmap( px );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::slotUpdateSteps( int )
|
|
|
|
{
|
|
|
|
// ??
|
|
|
|
}
|
|
|
|
|
|
|
|
void KSplash::slotUpdateProgress( int )
|
|
|
|
{
|
|
|
|
// ??
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPtrList<Action> KSplash::actionList()
|
|
|
|
{
|
|
|
|
return mActionList;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KSplash::eventFilter( TQObject *o, TQEvent *e )
|
|
|
|
{
|
|
|
|
if ( ( e->type() == TQEvent::MouseButtonRelease ) && ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(mThemeEngine) ) )
|
|
|
|
{
|
|
|
|
TQTimer::singleShot( 0, this, TQT_SLOT(close()));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|