You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdemultimedia/noatun/modules/kjofol-skin/kjloader.cpp

833 lines
21 KiB

/***************************************************************************
kjloader.cpp - The KJöfol-GUI itself
--------------------------------------
Maintainer: Stefan Gehn <sgehn@gmx.net>
***************************************************************************/
// local includes
#include "kjloader.h"
#include "kjloader.moc"
#include "kjwidget.h"
#include "kjbackground.h"
#include "kjbutton.h"
#include "kjfont.h"
#include "kjseeker.h"
#include "kjsliders.h"
#include "kjtextdisplay.h"
#include "kjvis.h"
#include "kjprefs.h"
#include "kjequalizer.h"
#include "helpers.cpp"
// arts-includes, needed for pitch
#include <artsmodules.h>
#include <reference.h>
#include <soundserver.h>
#include <kmedia2.h>
// noatun-specific includes
#include <noatun/engine.h>
#include <noatunarts/noatunarts.h>
#include <noatun/stdaction.h>
#include <noatun/app.h>
#include <noatun/player.h>
#include <noatun/vequalizer.h>
// system includes
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <tqdragobject.h>
#include <tqimage.h>
#include <tqbitmap.h>
#include <tqpixmap.h>
#include <tqcursor.h>
#include <tqpainter.h>
#include <tqtooltip.h>
#include <tqptrvector.h>
#include <tqvbox.h>
#include <tqlabel.h>
#include <kaction.h>
#include <kdebug.h>
#include <kfiledialog.h>
#include <khelpmenu.h>
#include <kstdaction.h>
#include <kpopupmenu.h>
#include <klocale.h>
#include <kglobalsettings.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <knotifyclient.h>
#include <kpixmapeffect.h>
#include <kurldrag.h>
#include <kwin.h>
#include <kiconloader.h>
class KJToolTip : public QToolTip
{
public:
KJToolTip(KJLoader *parent)
: TQToolTip(parent), mParent(parent)
{}
protected:
virtual void maybeTip(const TQPoint &p)
{
if ( !mParent->prefs()->displayTooltips() )
return;
TQPtrList<KJWidget> things=mParent->widgetsAt(p);
for (KJWidget *i=things.first(); i!=0; i=things.next())
{
TQString string=i->tip();
if (string.length())
{
tip(i->rect(), string);
return;
}
}
}
private:
KJLoader *mParent;
};
KJLoader *KJLoader::kjofol=0;
KJLoader::KJLoader()
: TQWidget(0, "NoatunKJLoader",
WType_TopLevel | WStyle_NoBorder | WRepaintNoErase ),
UserInterface(),
moving(false),
mClickedIn(0),
mText(0),
mNumbers(0),
mVolumeFont(0),
mPitchFont(0),
splashScreen(0)
{
kjofol = this;
mTooltips = new KJToolTip(this);
// Windowname and Icon
setCaption(i18n("Noatun"));
setIcon(SmallIcon("noatun"));
setAcceptDrops(true);
// We're going to draw over everything, there is no point in drawing the grey background first
setBackgroundMode(NoBackground);
// used for dockmode
mWin = new KWinModule();
subwidgets.setAutoDelete(true);
mPrefs = new KJPrefs(this);
connect ( mPrefs, TQT_SIGNAL(configChanged()), this, TQT_SLOT(readConfig()) );
TQString skin = mPrefs->skin();
if ( TQFile(skin).exists() )
{
loadSkin(skin);
}
else
{
KNotifyClient::event(winId(), "warning",
i18n("There was trouble loading skin %1. Please select another skin file.").arg(skin));
napp->preferences();
}
mHelpMenu = new KHelpMenu(this, kapp->aboutData());
connect(napp->player(), TQT_SIGNAL(timeout()), TQT_SLOT(timeUpdate()));
connect(napp->player(), TQT_SIGNAL(stopped()), TQT_SLOT(timeUpdate()));
connect(napp->player(), TQT_SIGNAL(newSong()), TQT_SLOT(newSong()));
connect(napp, TQT_SIGNAL(hideYourself()), TQT_SLOT(hide()));
connect(napp, TQT_SIGNAL(showYourself()), TQT_SLOT(show()));
// KStdAction::quit(napp, TQT_SLOT(quit()), actionCollection());
TQApplication::restoreOverrideCursor();
// newSong();
}
TQPtrList<KJWidget> KJLoader::widgetsAt(const TQPoint &pt) const
{
TQPtrList<KJWidget> things;
for ( TQPtrListIterator<KJWidget> i(subwidgets); i.current(); ++i )
if ( (*i)->rect().contains(pt) )
things.append((*i));
return things;
}
void KJLoader::removeChild(KJWidget *c)
{
if ( mClickedIn == c )
mClickedIn = 0;
if (subwidgets.findRef(c) != -1)
subwidgets.take();
}
void KJLoader::addChild(KJWidget *c)
{
subwidgets.append(c);
}
// The BIG one ;)
// this methode does all the hard work on loading these weird skins
void KJLoader::loadSkin(const TQString &file)
{
// kdDebug(66666) << "<KJLoader::loadSkin(const TQString &file)>" << endl;
// kdDebug(66666) << " file = " << file.latin1() << endl;
if ( file == mCurrentSkin ) // we don't load the same skin again
return;
mCurrentSkin = file;
// don't overwrite path to *.rc when we are loading dock- or winshade-mode
if ( (file != mCurrentWinshadeModeSkin) && (file != mCurrentDockModeSkin) )
{
mCurrentDefaultSkin = file;
// kdDebug(66666) << " setting mCurrentDefaultSkin: '" << file.latin1() << "'" << endl;
}
unloadSkin();
Parser::open( filenameNoCase(file) );
KJPitchText *pitchText=0;
KJVolumeText *volumeText=0;
mText = 0;
mNumbers = 0;
mVolumeFont = 0;
mPitchFont = 0;
if ( exist("splashscreen") && mPrefs->displaySplash() )
showSplash();
if ( (file != mCurrentWinshadeModeSkin) && (file != mCurrentDockModeSkin) )
{
if ( exist("dockmodercfile") )
{
// set path to dockmode rc-file (its not always skinname.dck)
mCurrentDockModeSkin = file.left(file.findRev("/")+1) + (item("dockmodercfile")[1]);
mDockPosition = item("dockmodeposition")[1].toInt();
mDockPositionX = item("dockmodepositionxy")[1].toInt();
mDockPositionY = item("dockmodepositionxy")[2].toInt();
}
else // NO DockMode
mCurrentDockModeSkin="";
if ( exist("winshademodercfile") )
mCurrentWinshadeModeSkin = file.left(file.findRev("/")+1) + (item("winshademodercfile")[1]);
else // no WinshadeMode
mCurrentWinshadeModeSkin="";
}
// Font-loading
if ( exist("fontimage") )
mText = new KJFont("font", this);
if ( exist("timefontimage") )
mNumbers = new KJFont("timefont", this);
if (exist("volumefontimage"))
mVolumeFont = new KJFont("volumefont", this);
// our skin-background, There has to be one so no check with exist()
subwidgets.append( new KJBackground(this) );
if ( exist("pitchtext") )
{
if (exist("pitchfontimage"))
{
mPitchFont = new KJFont("pitchfont", this);
}
else
{
mPitchFont = mNumbers;
kdDebug(66666) << "no pitchfont but pitchtext!" << endl;
kdDebug(66666) << "replacing pitchfont with timefont" << endl;
}
subwidgets.append( pitchText=new KJPitchText(item("pitchtext"), this) );
}
if (exist("volumetext"))
subwidgets.append(volumeText=new KJVolumeText(item("volumetext"), this));
if ( exist("volumecontroltype") )
{
if ( item("volumecontroltype")[1] == "bmp" )
{
KJVolumeBMP *b;
subwidgets.append(b=new KJVolumeBMP(item("volumecontrolbutton"), this));
b->setText(volumeText);
}
else if ( item("volumecontroltype")[1] == "bar" )
{
KJVolumeBar *b;
subwidgets.append(b=new KJVolumeBar(item("volumecontrolbutton"), this));
b->setText(volumeText);
}
/* else
{
kdDebug(66666) << "unknown volumecontrol: " << item("volumecontroltype")[1].latin1() << endl;
} */
}
else
{
kdDebug(66666) << "guessing type of volumecontrol" << endl;
if (exist("volumecontrolbutton") &&
exist("volumecontrolimage") &&
exist("volumecontrolimagexsize") &&
exist("volumecontrolimageposition") &&
exist("volumecontrolimagenb") )
{
KJVolumeBMP *b;
subwidgets.append(b=new KJVolumeBMP(item("volumecontrolbutton"), this));
b->setText(volumeText);
}
else if (exist("volumecontrolimage") &&
exist("volumecontrolbutton") )
{
KJVolumeBar *b;
subwidgets.append(b=new KJVolumeBar(item("volumecontrolbutton"), this));
b->setText(volumeText);
}
/* else
{
kdDebug(66666) << " no volumecontrol" << endl;
} */
}
if (exist("pitchcontrolbutton") &&
exist("pitchcontrolimage") &&
exist("pitchcontrolimagexsize") &&
exist("pitchcontrolimageposition") &&
exist("pitchcontrolimagenb") )
{
// kdDebug(66666) << "added KJPitchBMP" << endl;
KJPitchBMP *b;
subwidgets.append(b=new KJPitchBMP(item("pitchcontrolbutton"), this));
b->setText(pitchText);
}
else
{
// make sure we reset speed to 100% as the user won't be able
// to reset it without a pitchcontrol
Arts::PlayObject playobject = napp->player()->engine()->playObject();
Arts::PitchablePlayObject pitchable = Arts::DynamicCast(playobject);
if ( !pitchable.isNull() )
{
if ( pitchable.speed() > 1.0f )
pitchable.speed(1.0f);
}
}
if (exist("filenamewindow"))
subwidgets.append(new KJFilename(item("filenamewindow"), this));
if (exist("mp3timewindow"))
subwidgets.append(new KJTime(item("mp3timewindow"), this));
if (exist("mp3kbpswindow"))
subwidgets.append(new KJFileInfo(item("mp3kbpswindow"), this));
if (exist("mp3khzwindow"))
subwidgets.append(new KJFileInfo(item("mp3khzwindow"), this));
if (exist("analyzerwindow"))
{
int vistype = mPrefs->visType();
switch ( vistype )
{
case KJVisScope::Null:
subwidgets.append(new KJNullScope(item("analyzerwindow"), this));
break;
case KJVisScope::FFT:
subwidgets.append(new KJFFT(item("analyzerwindow"), this));
break;
case KJVisScope::StereoFFT:
subwidgets.append(new KJStereoFFT(item("analyzerwindow"), this));
break;
case KJVisScope::Mono:
subwidgets.append(new KJScope(item("analyzerwindow"), this));
break;
}
}
if (exist("EqualizerWindow"))
subwidgets.append(new KJEqualizer(item("EqualizerWindow"), this));
// I cant believe it, there are skins without a seeker, now THATS stupid :)
if (exist("seekregion"))
TQTimer::singleShot(0, this, TQT_SLOT(loadSeeker()));
// all the regular buttons
for (TQDictIterator<TQStringList> i(*this); i.current(); ++i)
{
TQString d=i.currentKey();
if(d.contains("button") &&
!d.startsWith("playlistwindow") && // don't add buttons that belong to the playlistwindow
d != "pitchcontrolbutton" && // both already handled above as they aren't buttons but sliders
d != "volumecontrolbutton" &&
d != "spectrumanalyzerbutton" && // FIXME: unsupported button
d != "oscilloscopebutton" && // FIXME: unsupported button
i.count() >= 7 )
{
subwidgets.append(new KJButton(*(*i), this));
}
}
show();
conserveMemory();
repaint();
// update displays if we are already playing
// This happens while changing skins
if (napp->player()->isPlaying())
newSong();
// kdDebug(66666) << "</KJLoader::loadSkin(const TQString &file)>" << endl;
}
void KJLoader::loadSeeker()
{
subwidgets.append(new KJSeeker(item("seekregion"), this));
}
void KJLoader::unloadSkin()
{
// kdDebug(66666) << "<KJLoader::unloadSkin()>" << endl;
KWin::clearState(winId(), NET::SkipTaskbar);
// kdDebug(66666) << " freeing subwidgets" << endl;
subwidgets.clear();
// This is special because mPitchfont can also point to mNumbers
// as some skins use the NumberFont for pitchtext
if ( mPitchFont && mPitchFont != mNumbers )
{
// kdDebug(66666) << " freeing mPitchFont" << endl;
delete mPitchFont;
}
if ( mText )
{
// kdDebug(66666) << " freeing mText" << endl;
delete mText;
}
if ( mNumbers )
{
// kdDebug(66666) << " freeing mNumbers" << endl;
delete mNumbers;
}
if ( mVolumeFont )
{
// kdDebug(66666) << " freeing mVolumeFont" << endl;
delete mVolumeFont;
}
// kdDebug(66666) << "</KJLoader::unloadSkin()>" << endl;
}
void KJLoader::minimize()
{
// kdDebug(66666) << "KJLoader::minimize()" << endl;
showMinimized();
}
void KJLoader::closeEvent(TQCloseEvent*)
{
// kdDebug(66666) << "KJLoader::closeEvent(TQCloseEvent*)" << endl;
unload();
}
void KJLoader::dragEnterEvent(TQDragEnterEvent *event)
{
// accept uri drops only
event->accept(KURLDrag::canDecode(event));
}
void KJLoader::dropEvent(TQDropEvent *event)
{
KURL::List urls;
if ( KURLDrag::decode(event,urls) )
{
for ( KURL::List::iterator it = urls.begin(); it != urls.end(); ++it )
napp->player()->openFile((*it), false);
}
}
void KJLoader::wheelEvent(TQWheelEvent *e)
{ // from QT-Docu: delta() is 120 for one step
if (e->state() & ControlButton)
napp->player()->setVolume ( napp->player()->volume() + (e->delta()/8) ); // 15% volumechange
else
napp->player()->setVolume ( napp->player()->volume() + (e->delta()/24) ); // 5% volumechange
}
// now for some dockmode stuff
void KJLoader::switchToDockmode()
{
// kdDebug(66666) << "KJLoader::switchToDockmode()" << endl;
loadSkin( mCurrentDockModeSkin );
connect(mWin, TQT_SIGNAL(activeWindowChanged(WId)), this, TQT_SLOT(slotWindowActivate(WId)));
connect(mWin, TQT_SIGNAL(windowRemoved(WId)), this, TQT_SLOT(slotWindowRemove(WId)));
connect(mWin, TQT_SIGNAL(stackingOrderChanged()), this, TQT_SLOT(slotStackingChanged()));
connect(mWin, TQT_SIGNAL(windowChanged(WId)), this, TQT_SLOT(slotWindowChange(WId)));
connect(mWin, TQT_SIGNAL(currentDesktopChanged(int)), this, TQT_SLOT(slotDesktopChange(int)));
WId activeWin = mWin->activeWindow();
if (activeWin && (activeWin != winId()))
{
KWin::WindowInfo winInf = KWin::windowInfo(activeWin, NET::WMKDEFrameStrut);
if(winInf.valid())
{
mDockToWin = activeWin;
mDockWindowRect = winInf.frameGeometry();
slotWindowActivate(mDockToWin);
hide();
restack();
}
}
}
void KJLoader::returnFromDockmode()
{
// kdDebug(66666) << "KJLoader::returnFromDockmode()" << endl;
mWin->disconnect();
loadSkin(mCurrentDefaultSkin);
}
void KJLoader::slotWindowActivate(WId win)
{
if(mCurrentSkin != mCurrentDockModeSkin)
return;
KWin::WindowInfo winInf = KWin::windowInfo(
win, NET::WMWindowType);
if((win != winId()) && winInf.valid())
{
// ensure we dock to the active window _except_ our own
// and stick to the last window if the NEW current one is a desktop
NET::WindowType winType = winInf.windowType(
NET::NormalMask|NET::DesktopMask|NET::DockMask|
NET::ToolbarMask|NET::MenuMask|NET::DialogMask|
NET::OverrideMask|NET::TopMenuMask|NET::UtilityMask|
NET::SplashMask);
if(winType == NET::Unknown || winType == NET::Normal || winType == NET::Dialog)
{
//kdDebug(66666) << k_funcinfo << "Now docking to window: " << win << endl;
mDockToWin = win;
}
}
if(mDockToWin != 0)
{
mDockWindowRect = KWin::windowInfo(mDockToWin, NET::WMKDEFrameStrut).frameGeometry();
/*kdDebug(66666) << k_funcinfo << "winrect: " << mDockWindowRect.x() << ", " <<
mDockWindowRect.y() << endl;*/
switch ( mDockPosition )
{
case 0:
move( mDockWindowRect.x() + mDockPositionX, mDockWindowRect.y() + mDockPositionY );
break;
case 2:
move( mDockWindowRect.x() + mDockPositionX, mDockWindowRect.y() + mDockWindowRect.height() + mDockPositionY );
break;
}
if(!isVisible())
{
show();
KWin::setState(winId(), NET::SkipTaskbar);
}
restack();
}
else
{
// We don't want to do anything until a window comes into
// focus.
//kdDebug(66666) << "No window having focus, hiding" << endl;
hide();
}
// kdDebug(66666) << "END slotWindowActivate()" << endl;
}
void KJLoader::slotWindowRemove(WId win)
{
// kdDebug(66666) << "START slotWindowRemove()" << endl;
if ( mCurrentSkin != mCurrentDockModeSkin )
return;
if (win == mDockToWin)
{
// kdDebug(66666) << "our window removed: " << win << endl;
hide();
mDockToWin = 0;
}
// kdDebug(66666) << "END slotWindowRemove()" << endl;
}
void KJLoader::slotWindowChange(WId win)
{
// kdDebug(66666) << "START slotWindowChange()" << endl;
if ( mCurrentSkin != mCurrentDockModeSkin )
return;
if ( win == mDockToWin )
{
// kdDebug(66666) << "changed our window:" << win << endl;
KWin::WindowInfo winInf = KWin::windowInfo(
mDockToWin, NET::WMKDEFrameStrut|NET::WMWindowType|
NET::WMState|NET::XAWMState|NET::WMDesktop);
if(!winInf.valid())
{
/*kdDebug(66666) << k_funcinfo <<
"No valid WindowInfo for tracked window: " << win << endl;*/
hide();
mDockToWin = 0;
return;
}
NET::WindowType winType = winInf.windowType(
NET::NormalMask|NET::DesktopMask|NET::DockMask|
NET::ToolbarMask|NET::MenuMask|NET::DialogMask|
NET::OverrideMask|NET::TopMenuMask|NET::UtilityMask|
NET::SplashMask);
if (
(winInf.state() & NET::Hidden) ||
(winInf.state() & NET::FullScreen) ||
(winType != NET::Unknown && winType != NET::Normal && winType != NET::Dialog)
)
{
/*kdDebug(66666) << k_funcinfo <<
"Our window changed: " << win <<
". Either iconified or special window" << endl;*/
// target-window has been iconified or window is desktop
hide();
mDockToWin = 0;
return;
}
// Size or position of target-window changed.
mDockWindowRect = winInf.frameGeometry();
/*kdDebug(66666) << k_funcinfo << "winrect: " << mDockWindowRect.x() << ", " <<
mDockWindowRect.y() << endl;*/
// Ensure we are still on the window.
switch(mDockPosition)
{
case 0:
{
move(
mDockWindowRect.x() + mDockPositionX,
mDockWindowRect.y() + mDockPositionY);
break;
}
case 2:
{
move(
mDockWindowRect.x() + mDockPositionX,
mDockWindowRect.y() + mDockWindowRect.height() + mDockPositionY);
break;
}
}
restack();
}
}
void KJLoader::slotDesktopChange(int)
{
// kdDebug(66666) << "START slotDesktopChange()" << endl;
if ( mCurrentSkin != mCurrentDockModeSkin )
return;
hide();
mDockToWin = 0L;
// kdDebug(66666) << "END slotDesktopChange()" << endl;
}
void KJLoader::slotStackingChanged()
{
// kdDebug(66666) << "START slotStackingChanged()" << endl;
if ( mCurrentSkin != mCurrentDockModeSkin )
return;
// We seem to get this signal before the window has been restacked,
// so we just schedule a restack.
TQTimer::singleShot ( 10, this, TQT_SLOT(restack()) );
// kdDebug(66666) << "END slotStackingChanged()" << endl;
}
// Set the animation's stacking order to be just above the target window's
// window decoration, or on top.
void KJLoader::restack()
{
// kdDebug(66666) << "START restack()" << endl;
if ( !mDockToWin )
{
// kdDebug(66666) << "No window to dock to, no restacking" << endl;
hide();
return;
}
// simply raise ourselves to the top
raise();
// and then ensure our target-window gets focus
// NET::setActiveWindow (mDockToWin);
// kdDebug(66666) << "END restack()" << endl;
}
KJLoader::~KJLoader()
{
// kdDebug(66666) << "KJLoader::~KJLoader()" << endl;
delete mWin;
}
void KJLoader::paintEvent(TQPaintEvent *e)
{
TQPainter p(this);
for (KJWidget* i=subwidgets.first(); i!=0; i=subwidgets.next())
if (i->rect().intersects(e->rect()))
i->paint(&p, e->rect().intersect(i->rect()));
// TQWidget::paintEvent(e);
}
void KJLoader::mouseMoveEvent(TQMouseEvent *e)
{
if (moving)
{
move ( TQCursor::pos()-mMousePoint );
return;
}
// TQWidget::mouseMoveEvent(e);
// not on background but on a widget: pass event to subwidget
if ( !moving && mClickedIn && subwidgets.findRef(mClickedIn) != -1 )
{
mClickedIn->mouseMove (
e->pos()-mClickedIn->rect().topLeft(),
mClickedIn->rect().contains(mapFromGlobal(TQCursor::pos())) );
}
}
void KJLoader::mousePressEvent(TQMouseEvent *e)
{
// kdDebug(66666) << "KJLoader::mousePressEvent(TQMouseEvent *e)" << endl;
// TQWidget::mousePressEvent(e);
if ( e->button()==RightButton )
NoatunStdAction::ContextMenu::showContextMenu();
else /* if ( e->button()==LeftButton ) */
{
mMousePoint = mapFromGlobal(TQCursor::pos());
// try to find a KJWidget that is here
for (KJWidget* i=subwidgets.first(); i!=0; i=subwidgets.next())
if (i->rect().contains(mMousePoint))
{
if (i->mousePress(mMousePoint-i->rect().topLeft()))
{
mClickedIn=i;
return;
}
}
// can't find a widget, so move the window
if ( mCurrentSkin != mCurrentDockModeSkin)
moving = true;
}
}
void KJLoader::mouseReleaseEvent(TQMouseEvent */*e*/)
{
// kdDebug(66666) << "KJLoader::mouseReleaseEvent(TQMouseEvent *e)" << endl;
// TQWidget::mouseReleaseEvent(e);
if (!moving && mClickedIn && subwidgets.findRef(mClickedIn)!=-1)
{
mClickedIn->mouseRelease(mapFromGlobal(TQCursor::pos())-
mClickedIn->rect().topLeft(),
mClickedIn->rect().contains(
mapFromGlobal(TQCursor::pos())));
mClickedIn=0;
}
moving = false;
}
void KJLoader::timeUpdate()
{
for (KJWidget* widget=subwidgets.first(); widget; widget=subwidgets.next())
widget->timeUpdate(napp->player()->getTime()/1000); // pass seconds to all Widgets
}
void KJLoader::newSong()
{
if (!napp->player()->current())
return;
for ( KJWidget* i=subwidgets.first(); i!=0; i=subwidgets.next() )
i->newFile();
}
void KJLoader::readConfig()
{
// kdDebug(66666) << "KJLoader::readConfig()" << endl;
for (KJWidget* i=subwidgets.first(); i!=0; i=subwidgets.next())
i->readConfig();
}
void KJLoader::showSplash()
{
splashScreen = new TQLabel( 0L, "SplashScreen",
WType_TopLevel | WStyle_NoBorder | WRepaintNoErase | WX11BypassWM );
TQPixmap splashPix = pixmap(item("splashscreen")[1]);
splashScreen->setPixmap( splashPix );
splashScreen->setBackgroundMode ( NoBackground );
splashScreen->setMask( KJWidget::getMask(image(item("splashscreen")[1])) );
TQSize sh = splashScreen->sizeHint();
TQRect desk = KGlobalSettings::splashScreenDesktopGeometry();
splashScreen->move (desk.x() + (desk.width() - sh.width())/2,
desk.y() + (desk.height() - sh.height())/2 );
splashScreen->setFixedSize(sh);
splashScreen->show();
napp->processEvents(); // we want this one time to get the splash actually displayed ASAP
TQTimer::singleShot(3000, this, TQT_SLOT(hideSplash()) );
}
void KJLoader::hideSplash()
{
splashScreen->hide();
delete splashScreen;
}