# &ksplash;-håndbogen

## Indledning

&ksplash; er en opstartsskærm der viser fremskridt for et program der er ved at blive indlæst. Rapportér venligst om problemer eller ønsker om nye egenskaber til &kde;'s e-mail-lister. &ksplash;'s hovedegenskaber er:

- Kan påvirkes af temaer
- Bruger plugin til fuldstændig brugerinderetning
- Kan bruges af et vilkårligt program der bruger DCOP

Denne håndbog vil vise dig hvordan man laver temaer til brug med plugin der allerede findes. Hvis ingen af de tilgængelige plugin tilfredsstiller din smag, kan du lære hvordan du brugerindstiller &ksplash;'s udseende fuldstændigt ved at skrive et plugin i C++.

## brug af temaer

For at bruge temaer fra KDE-Look, pakkes de ud til `~/.kde/share/apps/ksplash/Themes/` for en enkelt bruger, eller til `$`KDEDIR`/share/apps/ksplash/Themes/` for at gøre dem tilgængelige for alle brugerne på dit system.

Du kan også bruge Opstartsskærm-modulet under Udseende i &kde;'s kontrolcenter til at gøre dette automatisk.

### Ved brug af &kcontrol;-modulet

Dette module tillader dig at installere, teste og fjerne &ksplash;-temaer.

Nede langs siden af modulet er en liste af de for øjeblikket tilgængelige &ksplash;-temaer. Når du vælger en, vil en forhåndsvisning blive vist i hoveddelen af vinduet. Når du har valgt den du ønsker at bruge, tryk så på O.k. eller Anvend. Tryk på Annullér for at afslutte modulet uden at lave ændringer, og Standard for at genoprette systemets standard-opstartsskærm.

Fro at installere nye moduler, trykkes på Tilføj..., og find temaet på din computer. Du behøver ikke at pakke temafiler ud, du kan blot vælge den komprimerede temafil. Installering af et tema gør det ikke til det tema der bruges før du vælger det på listen og trykker enten på O.k. eller Anvend.

Selvom du kan se en forhåndsvisning af opstartsskærmen, vil du måske gerne se hvordan det ser ud i rigtigt brug, for eksempel for at se hvordan animeringen ser ud. Du kan teste temaer ved at vælge dem på listen og klikke på Test-knappen.

Du kan også fjerne de temaer du ikke længere ønsker at bruge, ved at vælge dem og trykke på Fjern-knappen. bemærk at din brugerkonto måske ikke har lov til at fjerne temaer der er installeret systemomfattende. Det anbefales også at du ikke afinstallerer Standard-opstartskærmen.

## Hvordan man laver temaer for &ksplash;

### Generelt

Det er nemt at lave dine egne temaer for &ksplash;. Efter du er færdig med dine temaer kan du sende dem til KDE-Look så andre kan bruge dem.

#### Identificering af dit tema

Lad os lave et tema der hedder `MitHeltEget`. For at temaet skal blive genkendt af &ksplash;, skal det gemmes i en mappe der hedder `MitHelEget` under `~/.kde/apps/ksplash/Themes/`. Det skal have en fil der hedder `Theme.rc`, der indeholder opsætningen af temaet. Du kan angive mange specielle ting i temaet, ændre den plugin-maskine der bruges, og så videre. Du behøver ikke at bruge alle de mulige indstillinger; sædvanligvis har indstillingerne en acceptabel standardværdi. Den basale syntaks for indgange i `Theme.rc`-filen er `[option] = [value]` Du kan finde definitionerne på de forskellige muligheder i de følgende afsnit.

##### Simpel `Theme.rc` fil

    [KSplash Theme: MitHeltEget]
    Name = MitHeltEget
    Description = Et lækkert tema der bruger XpLike-maskinen
    Version = 1.0
    Author = Rigtigt navn <rigtigpost@post.dk>
    ## Brug XpLike-maskinen til dette tema.
    Engine = XpLike
    Show Icon = false
    Welcome Text = Indlæser KDE

Efter at have angivet navnet, beskrivelsen og forfatteren for temaet, skal du først vælge en tema-maskine (også kendt som et plugin). Så kan du brugerindstille forskellige egenskaber af tema-maskinen ved at tilknytte nøgle-værdi par som i eksempel-filen ovenfor.

Det er vigtigt at navnet på mappen hvori temafilerne opbevares (`~/.kde/apps/ksplash/Themes/MitHeltEget` i vores tilfælde) og identifikatoren (`[KSplash Tema: MitHeltEget]` i vores tilfælde) for temaet i `Theme.rc`-filen er identiske.Ellers vil &ksplash; ikke genkende temaet.

#### Baggrundsfiler

Når &ksplash; starter, prøver den at finde et baggrundsbillede der passer til skærmens opløsning hvis tema-maskinen bruger et. Baggrundsbilledfilen skan navngives i følgende: `Background-`WWWxHHH`.png`.

For eksempel vil du måske bruge en fil der hedder `Background-1024x768`. Hvis baggrundsbilledet for din skærms opløsning ikke kan findes, prøver den at ændre størrelse på den originale `Background.png` eller filen angivet i `Theme.rc` til at passe med den nuværende opløsning. Ændring af størrelse uden-videre vil selvfølgelig tage et stykke tid, så du bør sørge for baggrundsbilleder i det mindste i følgende størrelser: 1280x1024, 1024x768 og 800x600.

### Valgmuligheder for tema-maskiner

#### Standard-tema

#### Valgmuligheder for standard-tema

Navn | Argument | Forklaring
Placering af statuslinje | [top/bund] | Skifter positionen af statuslinjen på skærmen. Standard er for neden.
Synlig statuslinje | [sand/falsk] | Indikerer om statuslinjen skal vises. Standard er sand.
Fremgang synlig | [sand/falsk] | Indikerer om indlæsningsfremgang skal vises. Standard er sand.
Skrifttype for statuslinje | [skrifttypenavn] | Den skrifttype der bruges i statuslinjen. Standard er Helvetica.
Skrifttypestørrelse for statuslinje | [størrelse] | Skrifttypens størrelse på statuslinjen. Standard er 16.
Fed skrifttype på statuslinje | [sand/falsk] | Indikerer om skrifttypen på statuslinjen skal være fed. Standard er sand.
Kursiv skrifttype for statuslinje | [sand/falsk] | Indikere om statuslinjen skrifttype skal være kursiv. Standard er falsk.
Forgrund for statuslinje | [farve] | Forgrundsfarven på statuslinjen. Standard er hvid.
Baggrund for statuslinje | [farve] | Baggrundsfarve for statuslinjen. Standard er sort.
Ikon for statuslinje | [sand/falsk] | Indikerer om statuslinjen skal have en ikon.
Ikoner synlige | [sand/falsk] | Indikerer om ikoner skal være synlige. Standard er sand.
Ikoner hopper | [sand/falsk] | Indikerer om ikoner skal hoppe. Standard er sand.
Ikonplacering | [0-3,10-13] | Position hvor ikonerne vises. Standard er for neden til venstre.
Opstartskærm | [navn] | Ændrer det billede der vises i opstartsskærmen.

#### Redmond tema

#### Indstillinger for Redmond tema

Navn | Argument | Forklaring
Baggrundsbillede | [filnavn] | Brugerdefineret baggrundsbillede der skal bruges.
Bruger-ikon | [Ikonnavn] | Navn på standard-ikon at vise til brugeren. Standard er `kør`.
Velkomsttekst | [tekst] | Tekst der vises i opstartsskærmen. Standard er "Velkommen".
Tekst for brugernavn | [tekst] | Tekst der vises i stedet for brugerens rigtige navn.
Placering af velkomsttekst | [x,y] | Position på skærmen hvor velkomstteksten vises.
Tekst-position for brugernavn | [x,y] | Position på skærmen hvor brugernavnet vises.
Placering af handlingstekst | [x,y] | Position på skærmen hvor den nuværende handling vises.
Ikonplacering | [x,y] | Position på skærmen hvor brugerikonen vises.
Vis velkomsttekst | [sand/falsk] | Slår visning af velkomsttekst til og fra. Standard er sand.
Vis velkomstskygge | [sand/falsk] | Slår visning af velkomsttekstens skygge til og fra. Standard er sand.
Vis brugernavn | [sand/falsk] | Slår visning af brugernavn til og fra. Standard er sand.
Vis handling | [sand/falsk] | Slår visning af den handling der udføres lige nu til og fra. Standard er sand.
Vis ikon | [sand/falsk] | Indikerer om ikon skal vises. Standard er sand
Brug KDM's bruger-ikon | [sand/falsk] | Vis brugerens login-ikon. Standard er sand.

#### MacX tema

#### Indstillinger for MacX tema

Navn | Argument | Forklaring
Minimum ikonstørrelse | [størrelse] | Tilknyt en minimumstørrelse for ikoner. Standard er 16.
Maksimal ikonstørrelse | [størrelse] | Tilknyt maksimum størrelse for ikoner. Standard er 64.
Optimeret ikonvisning | [sand/falsk] | Optimér ikonvisning. Standard er sand.
Synlig fremgangslinje | [sand/falsk] | Standard er sand.
Placering af fremgangslinje | [top/bund] | Skifter mellem om statuslinjen skal være foroven eller forneden. Standard er forneden.
Ikoner hopper | [sand/falsk] | Indikerer om ikoner skal hoppe. Standard er falsk.

#### MacClassic tema

#### Indstillinger af MacClassic tema

Navn | Argument | Forklaring
Ikonplacering | [0-3,10-13] | Placering af ikonerne på skærmen. Standard er forneden til venstre.
Ikoner hopper | [sand/falsk] | Indikerer om ikoner skal hoppe. Standard er falsk.
Ikoner synlige | [sand/falsk] | Indikerer om ikoner skal være synlige. Standard er sand.
Opstartskærm | [navn] | Ændrer det billede der vises i opstartsskærmen.

#### 2k tema

#### Indstillinger af 2k tema

Navn | Argument | Forklaring
Baggrundsfarve for titel | [farve] | Baggrundsfarven for titlen. Standard er mørkeblå.
Forgrundsfarve for titel | [farve] | Forgrundsfarve for titlen. Standard er hvid.
Tekstfarve for status | [farve] | Farven på statustekster. Standard er den samme som titelens baggrundsfarve.
Rotator-farve 1 | [farve] | Definerer farven på rotator 1. Standard er mørkeblå.
Rotator-farve 1 | [farve] | Definerer farven på rotator 1. Standard er cyan.
Rotatorhastighed | [værdi] | Definerer rotatorens hastighed. Standard er 30.
Vinduestitel | [tekst] | Angiver titelens tekst i vinduet.
Logo-fil | [filnavn] | Definerer det logo der bruges.

## Brug af &ksplash; indefra dit eget program

I dette kapitel beskriver en simpel metode at bruge &ksplash; som opstartskærm for dit &kde;-program. Hvis du ikke udvikler programmer for &kde;, kan du springe over dette kapitel.

### Basale krav

Dit &kde;-program skal være klar over &DCOP;. &DCOP; er den teknik &kde; bruger til at kommunikere mellem programmer. Hvis du bruger &kde; application framework, sker dette automatisk. For information om &DCOP; og relaterede &kde; teknologier, besøg venligst &kde; developers' corner.

### Start af &ksplash;

Før dit program starter sit beregningsintensive arbejde, eller før det begynder med at indlæse plugin, &etc;, startes &ksplash; som følger:

    DCOPClient *c = kapp->dcopClient();
    QString error;
    QCString KSplashName;
    int pid = 0;
    QStringList args;
    args << "--theme=MitEgetTema" << "--managed";
    if (kapp->startServiceByDesktopName("ksplash", args, &error, &KSplashName, &pid))
    {
      KMessageBox::sorry(0, error, "Kan ikke starte KSplash");
      // Noget fejlbehandling her.
    }

Vi vil antage at der kun er én udgave af &ksplash; der kører. Andre tilfælde er en smule mere komplicerede. Se venligst &DCOP;-dokumentationen for yderligere detaljer.

### Viser beskeder

Før du viser nogen beskeder, skal du indstille det antal skridt du vil vise. For eksempel bruger &kde;'s opstartsprocedure 7 skridt.

    QByteArray data;
        QDataStream arg(data,IO_WriteOnly);
        arg << someNumber;
        if (!(c->send(KSplashName, "KSplashIface", "setStartupItemCount(int)", data))
          // Noget fejlbehandling her.

Når du ønsker at vise en besked med eller uden ikon bruges

    arg << QString("iconName") << QString("programName") << QString("Some description");
        if (!(c->send(KSplashName, "KSplashIface", "programStarted(QString,QString,QString)", data))
        {
          // Noget fejlbehandling her.
        }

Hver gang du kalder `programStarted`, forøges antallet af færdige skridt. Når dit program er færdig med sin opstart, så gør følgende for at få opstartskærmen til at gå væk:

    if (!(c->send(KSplashName, "KSplashIface", "startupComplete()", data))
        {
          // Noget fejlbehandling her.
        }

Det er det hele! Du behøver ikke andet for kunne udnytte alt hvad &ksplash; har at tilbyde.

## Skriv nye &ksplash;-plugin

Det er ikke svært at skrive et nyt plugin for &ksplash;. I dette kapitel vil vi skrive et simpelt plugin der vil emulere opstartsskærmen for et velkendt operativsystem. Denne øvelse antager at du kender til basal C++, og en smule om KDE/Qt programmering.

### Basale krav

Vi vil lave et plugin der hedder `2k`. Navnet på et plugin bruges forskellige steder, og det er vigtigt at du er konsistent i dets brug så dit plugin bliver genkendt af &ksplash;. &ksplash; plugin er rent faktisk dynamisk indlæsbare biblioteker med følgende navnekonvention:

- Biblioteket skal hedde `ksplash+temanavnmedsmaabogstaver`. For vore tema, vil et være `ksplash2k`.
- Det skal have en tilsvarende desktop-fil som hedder `ksplash+temanavnmedsmaabogstaver.desktop`. For vores tema vil det være `ksplash2k.desktop`.
- Endelig skal objektet der returneres af biblioteket være en klasse som hedder `Theme+temanavnet`. For vores eksempel vil det være `Theme2k`.

Du skal ikke bekymre dig om du forstår alt dette. Vi vil betragte hvert af punkterne i detalje senere. Den anden meget vigtige detalje er at plugin-klassen skal være afledt fra `ThemeEngine`.

### Bygning af skelet-ramme

Vi vil bruge &kde;'s program-ramme som vil tage sig af at bygge dit plugin og vil sørge for uafhængighed af platform uden at vi skal gøre noget. For at gøre dette sørg for at du har `kdesdk`-pakken installeret. Kør kommandoen `kapptemplate` for at producere et program der hedder "2k". Det vil lave en mappe på topniveau som indeholder generiske filer såsom AUTHORS, &etc;. Vi er mest interesseret i undermappen der hedder `2k`. Gå ind i den undermappe og slet alle filerne der. Nu har vi det krævede skelet.

Næste skridt er at lave en `.desktop`-fil som, når den er installeret, vil fortælle &ksplash; at vores plugin er tilstede. Konsistent med navngivningkonventionerne lagt ud i det foregående afsnit, laves en fil der hedder `ksplash2k.desktop` i den mappe. Den skal indeholde følgende linjer:

    [Desktop Entry]
    Encoding=UTF-8
    Type=Service
    Comment=KSplash Plugin
    Name=KSplash2k
    ServiceTypes=KSplash/Plugin
    X-KDE-Library=ksplash2k
    X-KSplash-Default=true
    X-KSplash-PluginName=2k
    X-KSplash-ObjectName=Theme2k

`Encoding`, `Type`, `Comment` og `ServiceTypes` er det samme for alle plugin. Navnet på dit plugin og biblioteksnavnet følger de konventioner ve bemærkede tidligere. Indgangen `X-KSplash-Default` tager en boolesk værdi som afgør om det vises som standard i kontrolpanelets indstillingsmodul. Undtagen i meget sjældne tilfælde skal det være `true`.

### Deklaration af plugin-klasse

Nu da vi er færdige med det indledende arbejde, lad os begynde med den morsomme del - at lave en klasse der vil sørge for den opførsel vi ønsker. Mens vi er fire til at få denne klasse til at gøre næsten hvadsomhelst vi ønsker den skal gøre, er der nogle få begrænsninger.

1. Plugin-klasser skal arve `ThemeEngine`-klassen.

2. Plugin-klasser skal navngives efter reglen: `Tema+PluginNavn`.

3. Plugin-klasser skal sørge for en `statisk` funktion der hedder `names` der returnerer en liste af navne ved hvilke de kan startes.

4. Hvis dit plugin kan indstilles i kontrolcenter-modulet, skal det sørge for en `ThemeEngineConfig`-baseret klasse for indstillingen.

5. Plugin-klasser skal gå forud for mindst en af de virtuelle funktioner `slotSetText`, `slotSetPixmap`, `slotUpdateProgress` og `slotUpdateSteps` for at være brugbare.

6. Konstruktøren skal være på formen `ThemeEngine( QWidget *parent, const char *name, const QStringList &args )` så den kan bruges med `KGenericFactory`.

Det sidste krav synes måske kompliceret, men, som vi skal se senere, du kan sædvanligvis ignorere det ved at tilføje en enkelt linje til din kildefil.

### Kode for header-filen

Givet disse begrænsninger vil vi nu se at header-filen `theme2k.h` ser sådan her ud:

#### Visning af `theme2k.h`

    #ifndef __THEME2K_H__
    #define __THEME2K_H__

    #include <qlabel.h>
    #include <qwidget.h>

    #include <kdialogbase.h>
    #include <kpixmap.h>
    #include <ksplash/themeengine.h>

    class RotWidget;

    class Cfg2k: public ThemeEngineConfig
    {
      Q_OBJECT
    public:
      Cfg2k( KConfig * );
    };

    class ObjKsTheme;
    class Theme2k: public ThemeEngine
    {
      Q_OBJECT
    public:
      Theme2k( QWidget *, const char *, const QStringList& );

      inline const QString name()
      {
        return( QString("KSplash2k") );
      }
      inline const KDialogBase *config( KConfig *kc )
      {
        return new Cfg2k( kc );
      }
      static QStringList names()
      {
        QStringList Names;
        Names << "KSplash2k";
        Names << "ks2k";
        Names << "2k";
        Names << "2000";
        return( Names );
      };

    public slots:
      inline void slotSetText( const QString& s )
      {
        if( mText && mText->text() != s ) mText->setText( s );
      };

    private:
      void initUi();
      void readSettings();

      QLabel *mText;
      RotWidget *mRotator;
      QColor mTBgColor, mTFgColor, mRotColor1, mRotColor2, mStatusColor;
      int mRotSpeed;
      QString mWndTitle, mLogoFile;
    };

    #endif

Lad os analysere ovenstående. `Theme2k`-klassen tilfredsstiller navnekonventionerne, og er arvet fra `ThemeEngine`. Den sørger for en `Theme2k::names()`, og har en konstruktør der tager de krævede parametre: `Theme2k( QWidget *, const char *, const QStringList& );` og sørger også for en simpel `Theme2k::slotSetText()` metode. Indtil videre bekymrer vi os ikke om `RotWidget`-klassen. Det er en lille kontrol der sørger for nogle øjenlækkerier for brugeren. Vores plugin er meget simpelt og viser ikke nogen ikoner og har ingen fremgangslinje. Hvis du gerne vil vise ikoner, så sæt `slotSetPixmap`-funktionen ud af kraft. Lignende funktioner eksisterer til at sætte fremgangslinjens område (`slotUpdateSteps`) og til at forøge (`slotUpdateProgress`) det nuværende skridt.

### Implementation af plugin

Vi vil kun undersøge de relevante dele af implementationen. For en liste af hele implementationen, kig venligst i appendiks. Det første vi vil gøre er at bibliotekskravene til en side:

#### Bibliotekskrav

    K_EXPORT_COMPONENT_FACTORY( ksplash2k, KGenericFactory<Theme2k> );

Makroen `K_EXPORT_COMPONENT_FACTORY` erklæres i `kgenericfactory.h`. Videre til konstruktøren! Da dette er et meget simpelt plugin, er konstruktøren temmelig ligetil.

#### Plugin-konstruktør

    Theme2k::Theme2k( QWidget *parent, const char *name, const QStringList &args  )
        :ThemeEngine( parent, name, args )
    {
      readSettings();
      initUi();
    }

Metoden `readSettings()` illustrerer den rigtige måde at opnå din temaopsætning. (Du ønsker at folk skal bruge dit plugin i deres temaer, ikke sandt?)

#### Opnået temaopsætning

    void Theme2k::readSettings()
    {
      if( !mTheme )
        return;

      KConfig *cfg = mTheme->themeConfig();
      if( !cfg )
        return;

      cfg->setGroup( QString("KSplash Theme: %1").arg(mTheme->theme()) );

      QColor DefaultTBgColor( Qt::darkBlue );
      QColor DefaultTFgColor( Qt::white );

      mTBgColor = cfg->readColorEntry( "Title Background Color", &DefaultTBgColor );
      mTFgColor = cfg->readColorEntry( "Title Foreground Color", &DefaultTFgColor );
      mStatusColor = cfg->readColorEntry("Status Text Color", &mTBgColor );

      QColor DefaultRot1( Qt::darkBlue );
      QColor DefaultRot2( Qt::cyan );
      mRotColor1 = cfg->readColorEntry( "Rotator Color 1", &DefaultRot1 );
      mRotColor2 = cfg->readColorEntry( "Rotator Color 2", &DefaultRot2 );

      mRotSpeed = cfg->readNumEntry( "Rotator Speed", 30 );
      mWndTitle = cfg->readEntry( "Window Title", i18n("Please wait...") );
      mLogoFile = cfg->readEntry( "Logo File", QString::null );
    }

Da vi kan lide vore brugere, sørger vi for rimelige standardværdier for parametre der ikke er tilstede i temafilen. Bemærk at vi altid skal sætte vores gruppe til "KSplash Theme: themename" for at forblive kompatible med fremtidige tema-specifikationer. `initUI()`-metoden er ikke særlig interessant, da den blot opbygger kontrollerne. Se venligst appendiks for detaljer.

### Kompilering af plugin

Da vi besluttede os for at bruge &kde;'s rammer til at kompilere vores plugin, må vi lave en `Makefile.am`. Den skal se sådan her ud:

#### Visning af `Makefile.am`

    INCLUDES = $(all_includes)

    kde_module_LTLIBRARIES = ksplash2k.la

    ksplash2k_la_SOURCES = theme2k.cpp rotwidget.cpp
    ksplash2k_la_LDFLAGS = $(all_libraries) $(KDE_RPATH)
    ksplash2k_la_LIBADD = $(LIB_KDEUI) -lksplashthemes

    METASOURCES = AUTO

    noinst_HEADERS        = theme2k.h rotwidget.h

    servicesdir = $(kde_servicesdir)
    services_DATA = ksplash2k.desktop

    themedir = $(kde_datadir)/ksplash/Themes/2k
    theme_DATA = Theme.rc Preview.png

For yderligere oplysninger om at skrive `Makefile.am`-filer for &kde;, se venligst &kde;-udviklernes' netside. Det eneste der skal bemærkes er at vi sørger for et standardtema baseret på dette plugin, og vi sørger for et forhåndsbillede for det. Som en venlighed overfor dine brugere, bør du sørge for et eksempel på en `Theme.rc`-fil der illustrerer brugen af de forskellige tilvalg.

## Spørgsmål og svar

&reporting.bugs; &updating.documentation;

Jeg kan ikke finde nogen temaer der virker i &ksplash;. Hvorfor er det?

Du har formodentlig ikke de rigtige plugin for temaet. Plugin er i `kde-artwork` pakken. Hent den og installér den, og prøv så igen.

Hvad er filen `Theme.rc` og hvordan laver jeg én?

`Theme.rc` er filen hvor du kan specificere temaets opsætning. For yderligere oplysninger kig i Hvordan laver jeg temaer for &ksplash;.

## Medvirkende og licens

&ksplash;

Program ophavsret © 2003 &Ravikiran.Rajagopal; &Ravikiran.Rajagopal.mail;

## Bidragydere

- &Brian.C.Ledbetter; &Brian.C.Ledbetter.mail;

Dokumentation ophavsret © 2003 &Teemu.Rytilahti; &Teemu.Rytilahti.mail;

&underFDL; &underGPL;

## Installation

### Krav

For at det skal lykkes at bruge &ksplash;, har du brug for &kde; version 3.2 eller højere. Nogle temaer vil måske kræve bestemte plugin. Hvis et tema ikke virker, så kontakt venligst temaets forfatter for at finde ud af hvor man får fat i et passende plugin.

### Kompilering og installation

&install.compile.documentation;

## Kildekode

### Visning af `theme2k.cpp`

    #include <qlabel.h>
    #include <qwidget.h>

    #include <kapplication.h>
    #include <kconfig.h>
    #include <kdebug.h>
    #include <kdialogbase.h>
    #include <kgenericfactory.h>
    #include <kglobalsettings.h>
    #include <klocale.h>
    #include <ksplash/objkstheme.h>
    #include <kstandarddirs.h>

    #include "rotwidget.h"
    #include "theme2k.h"
    #include "theme2k.moc"

    K_EXPORT_COMPONENT_FACTORY( ksplash2k, KGenericFactory<Theme2k> );

    Cfg2k::Cfg2k( KConfig * )
    {}

    Theme2k::Theme2k( QWidget *parent, const char *name, const QStringList &args  )
        :ThemeEngine( parent, name, args )
    {
      readSettings();
      initUi();
    }

    void Theme2k::initUi()
    {
      QVBox *vbox = new QVBox( this );
      vbox->setFrameShape( QFrame::WinPanel );
      vbox->setFrameShadow( QFrame::Raised );

      QHBox *labelBox = new QHBox( vbox );
      labelBox->setPalette( mTBgColor );
      labelBox->setMargin( 1 );
      QLabel *lbl = new QLabel( mWndTitle, labelBox );
      lbl->setFont( QFont( "Arial", 12, QFont::Bold ) );
      lbl->setPaletteForegroundColor( mTFgColor );

      QLabel *logo = new QLabel( vbox );
      logo->setPalette( Qt::white );

      QString px( locate( "appdata", mTheme->themeDir() + (mLogoFile.isNull()?QString("/Logo.png"):mLogoFile) ) );
      if (px.isNull())
        px = locate("appdata","Themes/Default/splash_top.png");
      if( !px.isNull() )
      {
        QPixmap pix( px );
        logo->setPixmap( pix );
      }
      else
      {
        logo->setText( "<B>KDE</B>2000" );
        logo->setAlignment( AlignCenter|AlignVCenter );
      }

      mRotator = new RotWidget( vbox, mRotColor1, mRotColor2, mRotSpeed );

      QHBox *hbox = new QHBox( vbox );
      labelBox->setSpacing( 4 );
      labelBox->setMargin( 4 );

      mText = new QLabel( hbox );
      mText->setPaletteForegroundColor( mStatusColor );
      mText->setPaletteBackgroundColor( mTFgColor );
      mText->setText( mWndTitle );
      mText->setFixedHeight( 48 );

      setFixedSize( vbox->sizeHint() );
      QRect rect(KGlobalSettings::splashScreenDesktopGeometry());
      move( rect.x() + (rect.width() - size().width())/2,
            rect.y() + (rect.height() - size().height())/2 );
    }

    void Theme2k::readSettings()
    {
      if( !mTheme )
        return;

      KConfig *cfg = mTheme->themeConfig();
      if( !cfg )
        return;

      cfg->setGroup( QString("KSplash Theme: %1").arg(mTheme->theme()) );

      QColor DefaultTBgColor( Qt::darkBlue );
      QColor DefaultTFgColor( Qt::white );

      mTBgColor = cfg->readColorEntry( "Title Background Color", &DefaultTBgColor );
      mTFgColor = cfg->readColorEntry( "Title Foreground Color", &DefaultTFgColor );
      mStatusColor = cfg->readColorEntry("Status Text Color", &mTBgColor );

      QColor DefaultRot1( Qt::darkBlue );
      QColor DefaultRot2( Qt::cyan );
      mRotColor1 = cfg->readColorEntry( "Rotator Color 1", &DefaultRot1 );
      mRotColor2 = cfg->readColorEntry( "Rotator Color 2", &DefaultRot2 );

      mRotSpeed = cfg->readNumEntry( "Rotator Speed", 30 );
      mWndTitle = cfg->readEntry( "Window Title", i18n("Please wait...") );
      mLogoFile = cfg->readEntry( "Logo File", QString::null );
    }

### Visning af `rotwidget.h`

    #ifndef         __ROTWIDGET_H__
    #define         __ROTWIDGET_H__

    #include <qlabel.h>
    #include <qtimer.h>
    #include <qwidget.h>

    #include <kdialogbase.h>
    #include <kpixmap.h>

    /**
     * @short Display a rotating-gradient widget.
     */
    class         RotWidget: public QWidget
    {
      Q_OBJECT
    public:
      RotWidget( QWidget *, const QColor&, const QColor&, int );
      ~RotWidget();

    private slots:
      void stepEvent();

    protected:
      void        preparePixmap( int );
      void        paintEvent( QPaintEvent * );
      void        resizeEvent( QResizeEvent * );

      QColor m_color1, m_color2;
      int m_step, m_speed;
      QTimer *m_stepTimer;

      QList<KPixmap> m_stepPixmap;
    };

    #endif

### Visning af `rotwidget.cpp`

    #include <kdebug.h>
    #include <kdialogbase.h>
    #include <kpixmapeffect.h>

    #include <qlabel.h>
    #include <qpainter.h>
    #include <qwidget.h>

    #include "rotwidget.h"
    #include "rotwidget.moc"

    RotWidget::RotWidget( QWidget *parent, const QColor& c1, const QColor& c2, int sp )
        :QWidget(parent), m_color1(c1), m_color2(c2), m_step(0), m_speed(sp)
    {
      if( (m_speed <= 0) || (m_speed > 20) )
        m_speed = 1;
      setFixedHeight( 6 );

      for( int i = 0; i <= width(); i++ )
        preparePixmap( i );

      m_stepTimer = new QTimer( this );
      connect(m_stepTimer, SIGNAL(timeout()), this, SLOT(stepEvent()));
      m_stepTimer->start( 50 );
    }

    RotWidget::~RotWidget()
    {
    }

    void RotWidget::stepEvent()
    {
      // This is inefficient as we create too many pixmaps, optimize later.
      m_step += m_speed;
      if( m_step > width() )
        m_step = 0;
      repaint( true );
    }

    // Todo: Optimize drawing.
    void RotWidget::paintEvent( QPaintEvent *pe )
    {
      QPainter p;
      p.begin( this );

      QRect r = pe->rect();

      if( m_stepPixmap.at( m_step ) )
        bitBlt( this, r.x(), r.y(), m_stepPixmap.at( m_step ), r.x(), r.y(), r.width(), r.height() );
      else
        p.fillRect( rect(), Qt::black );
      p.end();
    }

    void RotWidget::resizeEvent( QResizeEvent *re )
    {
      m_stepPixmap.clear();
      for( int i = 0; i <= re->size().width(); i++ )
        preparePixmap( i );
    }

    void RotWidget::preparePixmap( int step )
    {
      if( step < 0 )
        return;

      // Explicitly draw our first pixmap. The rest we will bitBlt() from here.
      if( step == 0 )
      {
        KPixmap tmp; tmp.resize( size().width() / 2, size().height() );
        KPixmap tmp2(tmp);
        KPixmapEffect::gradient( tmp, m_color1, m_color2, KPixmapEffect::HorizontalGradient );
        KPixmapEffect::gradient( tmp2, m_color2, m_color1, KPixmapEffect::HorizontalGradient );
        KPixmap *px = new KPixmap( size() );
        QPainter p;
        p.begin( px );
        p.drawPixmap( 0, 0, tmp );
        p.drawPixmap( size().width()/2, 0, tmp2 );
        p.end();
        m_stepPixmap.append( px );
      }
      else if( m_stepPixmap.at( step-1 ) )
      {
        QPixmap *prev = m_stepPixmap.at( step-1 );
        QPixmap next; next.resize( size() );
        // convert
        // prev = "[------------]"
        // to
        // next = "------------]["
        bitBlt( &next, 0, 0, prev, 1, 0, prev->width()-1, prev->height() );
        bitBlt( &next, width()-1, 0, prev, 0, 0, 1, prev->height() );
        KPixmap *n = new KPixmap( next );
        m_stepPixmap.append( n );
      }
    }

&documentation.index;