# Руководство &ksplash;

&Teemu.Rytilahti; &Teemu.Rytilahti.mail;
&Brian.C.Ledbetter; &Brian.C.Ledbetter.mail;
&Ravikiran.Rajagopal; &Ravikiran.Rajagopal.mail;
Иван
Кашуков

    dolphin210@yandex.ru

Перевод на русский
2003
Teemu Rytilahti
2003
Ravikiran Rajagopal
&FDLNotice;
2003-01-10
1.01.00

Симпатичный экран &ksplash; показывает процесс загрузки приложения.

KDE
kdebase
ksplash
ksplashml
splashscreen
eye candy

## Введение

Симпатичный экран &ksplash; показывает процесс загрузки приложения. Вопросы и пожелания отправляйте в списки рассылки &kde;. Отличительные особенности &ksplash;:

- Возможность применения тем
- Высокая гибкость в настройке обеспечивается использованием подключаемых модулей
- Программа может быть использована любым приложением, которое работает с DCOP

Это руководство объясняет, как создавать темы для использования с уже доступными подключаемыми модулями. Если ни один из доступных модулей не удовлетворяет вашему вкусу, вы можете научиться полностью настраивать внешний вид &ksplash;, создавая подключаемые модули на C++.

## Использование тем

Чтобы использовать темы с KDE-Look, скопируйте их в `~/.kde/apps/ksplash/Themes/` (для одного пользователя) или в `$`KDEDIR`/share/apps/ksplash/Themes/` (чтобы сделать их доступными для всех пользователей вашей системы). Чтобы сделать это автоматически, используйте модуль Экран загрузки раздела Внешний вид Центра управления &kde;.

## Как создавать темы для &ksplash;

### Основные положения

Создавать свои собственные темы для &ksplash; достаточно легко. Когда вы закончили свою тему, вы можете отослать её в KDE-Look, чтобы её могли использовать другие.

#### Определение своей темы

Давайте создадим тему под названием `MyCoolTheme`. Чтобы тема была распознана &ksplash;, следует поместить её в папку `MyCoolTheme` в каталоге `~/.kde/apps/ksplash/Themes/`. В ней должен содержаться файл `Theme.rc`, содержащий настройки темы. Вы можете установить множество особенностей для темы, изменить движок подключаемых модулей и т. д. Не обязательно использовать все доступные настройки, обычно используются только некоторые. Синтаксис записей файла `Theme.rc`: `[опция] = [значение]`. В последующих секциях определяется множество опций.

##### Простой файл `Theme.rc`

    [KSplash Theme: MyCoolTheme]
    Name = MyCoolTheme
    Description = Симпатичная тема, использующая движок XpLike
    Version = 1.0
    Author = Настоящее имя <имя_пользователя@имя_сервера.домен>
    ## Use the XpLike engine for this theme.
    Engine = XpLike
    Show Icon = false
    Welcome Text = Загрузка KDE

После того как вы задали имя, описание и автора темы, вам следует выбрать движок темы (подключаемый модуль). Затем вы сможете настроить разнообразные характеристики движка темы, устанавливая пары опция=значение, как в вышеприведённом файле.

#### Файлы фона

При запуске &ksplash; пытается найти файл фона, соответствующий текущему разрешению экрана (если файл используется движком темы). Формат названия файла фона: `Background-WWWxHHH.png`.

Например, вам надо использовать файл `Background-1024x768`. Если файл, соответствующий текущему разрешению экрана, не найден, программа пытается изменить размер файла `Background.png` (или другого, заданного в `Theme.rc`) так, чтобы он соответствовал разрешению. Изменение размера на лету занимает некоторое время, так что вам следует создать файлы как минимум для следующих разрешений экрана: 1280x1024, 1024x768 и 800x600.

### Опции движков тем

#### Стандартная тема

##### Опции стандартной темы

Название | Аргумент | Значение
Statusbar Position | [top/bottom] | Определяет расположение индикатора состояния на экране. Значение по умолчанию - bottom (внизу).
Statusbar Visible | [true/false] | Определяет, будет ли индикатор состояния видимым. Значение по умолчанию - true (истина).
Progress Visible | [true/false] | Определяет, будет ли показан прогресс загрузки. Значение по умолчанию - true.
Statusbar Font | [название_шрифта] | Шрифт, используемый в индикаторе состояния (по умолчанию - Helvetica).
Statusbar Font Size | [размер] | Размер шрифта индикатора состояния (по умолчанию - 16).
Statusbar Font Bold | [true/false] | Определяет, будет ли шрифт индикатора состояния полужирным (по умолчанию - true).
Statusbar Font Italic | [true/false] | Определяет, будет ли шрифт индикатора состояния наклонным (по умолчанию -true).
Statusbar Foreground | [цвет] | Цвет переднего плана индикатора состояния. Значение по умолчанию - white (белый).
Statusbar Background | [цвет] | Цвет фона индикатора состояния. Значение по умолчанию - black (чёрный).
Statusbar Icon | [true/false] | Определяет, будет ли пиктограмма у индикатора состояния.
Icons Visible | [true/false] | Определяет, будут ли пиктограммы видимыми. Значение по умолчанию - true.
Icons Jumping | [true/false] | Определяет, будут ли пиктограммы прыгающими. Значение по умолчанию - true.
Icon Position | [0-3, 10-13] | Расположение пиктограмм (по умолчанию - вверху слева).
Splash Screen | [название] | Изменяет образ отображаемого экрана.

#### Тема Redmond

##### Опции темы Redmond

Название | Аргумент | Значение
Background Image | [имя_файла] | Определяемый пользователем фоновый рисунок.
User Icon | [название] | Название пиктограммы, отображаемой для пользователя. По умолчанию - `go`.
Welcome Text | [текст] | Текст, отображающийся на экране. По умолчанию - "Добро пожаловать".
Username Text | [текст] | Текст, замещающий имя пользователя.
Welcome Text Position | [x,y] | Область экрана, в которой отображается текст приглашения (определяемый опцией Welcome Text).
Username Text Position | [x,y] | Область экрана, в которой отображается имя пользователя.
Action Text Position | [x,y] | Область экрана, в которой отображается текущее действие.
Icon Position | [x,y] | Область экрана, в которой отображается пиктограмма пользователя.
Show Welcome Text | [true/false] | Определяет, будет ли отображаться текст приглашения (значение по умолчанию - true).
Show Welcome Shadow | [true/false] | Определяет, будет ли отображаться тень текста приглашения (значение по умолчанию - true).
Show Username | [true/false] | Определяет, будет ли отображаться имя пользователя (значение по умолчанию - true).
Show Action | [true/false] | Определяет, будет ли отображаться действие, выполняемое в данный момент. Значение по умолчанию - true.
Show Icon | [true/false] | Определяет, будет ли отображаться пиктограмма. Значение по умолчанию - true.
Use KDM User Icon | [true/false] | Определяет, будет ли использоваться пиктограмма, соответствующая пользователю при входе в систему. Значение по умолчанию - true.

#### Тема MacX

##### Опции темы MacX

Название | Аргумент | Значение
Icon Size Minimum | [размер] | Минимальный размер пиктограммы (по умолчанию - 16).
Icon Size Maximum | [размер] | Максимальный размер пиктограммы (по умолчанию - 64).
Optimized Icon Rendering | [true/false] | Будет ли оптимизироваться отрисовка пиктограмм (значение по умолчанию - true).
Progress Bar Visible | [true/false] | По умолчанию - true.
Progress Bar Position | [top/bottom] | Определяет расположение индикатора состояния (внизу или вверху). По умолчанию - bottom (внизу).
Icons Jumping | [true/false] | Определяет, будут ли пиктограммы прыгающими (по умолчанию - false).

#### Тема MacClassic

##### Опции темы MacClassic

Название | Аргумент | Значение
Icon Position | [0-3, 10-13] | Расположение пиктограмм на экране, по умолчанию - внизу слева.
Icons Jumping | [true/false] | Определяет, будут ли пиктограммы прыгающими (по умолчанию - false).
Icons Visible | [true/false] | Определяет, будут ли пиктограммы видимыми. Значение по умолчанию - true.
Splash Screen | [название] | Изменяет образ отображаемого экрана.

#### Тема 2k

##### Опции темы 2k

Название | Аргумент | Значение
Title Background Color | [цвет] | Фоновый цвет заголовка, по умолчанию - dark blue (тёмно-синий).
Title Foreground Color | [цвет] | Цвет переднего плана заголовка. По умолчанию - white (белый).
Status Text Color | [цвет] | Цвет текста состояния. По умолчанию соответствует фоновому тексту заголовка (определяемому опцией Title Background Color).
Rotator Color 1 | [цвет] | Определяет цвет индикатора 1. По умолчанию - dark blue, тёмно-синий.
Rotator Color 2 | [цвет] | Определяет цвет индикатора 2, по умолчанию - светло-серый (cyan).
Rotator Speed | [значение] | Определяет скорость индикатора, по умолчанию - 30.
Window Title | [текст] | Определяет текст заголовка окна.
Logo File | [имя_файла] | Определяет используемый логотип.

## Использование &ksplash; в вашем собственном приложении

В этой главе описывается простой метод использования &ksplash; в качестве окна-показателя загрузки в вашем приложении для &kde;. Если вы не разрабатываете приложения для &kde;, вы можете опустить эту главу.

### Основные требования

Ваше приложение &kde; должно работать с &DCOP;. &DCOP; - это технология &kde;, использующаяся для коммуникации между приложениями. Если вы используете стандартную структуру приложения &kde;, это обеспечивается автоматически. Чтобы получить информацию о &DCOP; и связанных технологиях &kde;, посетите сайт разработчиков &kde;.

### Запуск &ksplash;

До того, как ваше приложение начнёт вычисления, загрузку подключаемых модулей и т. д., запустите &ksplash;. Образец:

    DCOPClient *c = kapp->dcopClient();
    QString error;
    QCString KSplashName;
    int pid = 0;
    QStringList args;
    args << "--theme=MyCoolTheme" << "--managed";
    if (kapp->startServiceByDesktopName("ksplash", args, &error, &KSplashName, &pid))
    {
      KMessageBox::sorry(0, error, "Unable to invoke KSplash");
      // Some error processing here.
    }

Мы предполагаем, что запущено только одно окно &ksplash;. Другие случаи немного более сложны. Разъяснения см. в документации &DCOP;.

### Отображение сообщений

Перед отображением сообщений вам необходимо установить число шагов. Например, процедура запуска &kde; включает 7 этапов.

    QByteArray data;
        QDataStream arg(data,IO_WriteOnly);
        arg << someNumber;
        if (!(c->send(KSplashName, "KSplashIface", "setStartupItemCount(int)", data))
          // Здесь проявляется некоторая ошибка.

Если вы хотите, чтобы сообщение отображалось с пиктограммой или без неё, используйте

    arg << QString("название_пиктограммы") << QString("название_программы") << QString("некоторое описание");
        if (!(c->send(KSplashName, "KSplashIface", "programStarted(QString,QString,QString)", data))
        {
          // Здесь проявляется некоторая ошибка.
        }

Каждый раз, когда вы вызываете `programStarted`, шаги заканчиваются. Когда ваша программа закончила запуск, выполните следующие команды, чтобы убрать экран загрузки:

    if (!(c->send(KSplashName, "KSplashIface", "startupComplete()", data))
        {
          // Здесь проявляется некоторая ошибка.
        }

Это всё, что вам необходимо, чтобы использовать все преимущества &ksplash;.

## Создание новых подключаемых модулей &ksplash;

Создавать подключаемые модули &ksplash; нетрудно. В этой главе мы напишем простой модуль, который эмулирует экран загрузки одной очень известной операционой системы. Предполагается, что вы знакомы с основами языка C++, и хотя бы немного - с программированием для KDE/Qt.

### Основные требования

Мы создадим модуль с названием `2k`. Название используется во многих местах. Важмо не исказить его, чтобы модуль был распознан &ksplash;. Модули &ksplash; являются динамически загружаемыми библиотеками со следующими объявлениями:

- Библиотеку следует называть по обзазцу: `libksplash+название_темы_в_нижнем_регистре`. В нашем случае название будет `libksplash2k`.
- Тема должна иметь свой desktop-файл, который следует назвать `ksplash+название_темы_в_нижмем_регистре.desktop`. В нашем случае - `ksplash2k.desktop`.
- Наконец, библиотека должна возвращать класс с названием `Theme+название_темы`, в нашем случае - `Theme2k`.

Не беспокойтесь, если вы не поняли всё вышесказанное. Далее мы рассмотрим каждый шаг в деталях. Важной деталью является то, что класс модуля вы должны взять из `ThemeEngine`.

### Создание основы

При создании модуля мы будем использовать основу для приложения &kde;, которая обеспечит независимость от платформы во всех частях нашей работы. Убедитесь, что в вашей системе установлен пакет `kdesdk`. Выполните команду `kapptemplate`, чтобы создать приложение с названием "2k". Будет создана папка, содержащая основные файлы (такие как AUTHORS и т. п.). Нам нужен подкаталог `2k`. Удалите все файлы в нём, и основа готова.

На следующем этапе вы должны создать файл `.desktop`, который, после установки, сообщит &ksplash;, что подключаемый модуль доступен. В соответствии с правилами наименования файлов, которые даны в предыдущей секции, создайте файл `ksplash2k.desktop` (в каталоге /2k). Он должен содержать следующие строки:

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

Опции `Encoding`, `Type`, `Comment` и `ServiceTypes` одинаковы для всех подключаемых модулей. Название модуля и библиотеки следуют вышеописанным правилам. Опция `X-KSplash-Default` может принимать одно из двух значений (true или false). Она определяет, будет ли этот модуль показан в Центре управления как модуль по умолчанию. За исключением некоторых очень редких случаев, его значение должно быть `true`.

### Объявление класса подключаемого модуля

Теперь, когда мы закончили подготовительную работу, начинается действительно интересная часть - создание класса, который обеспечивает нужное поведение модуля. Хотя мы вольны делать с этим классом всё, что хотим, существует несколько ограничений.

1. Классы модуля должны соответствовать классу `ThemeEngine`.

2. Классы модуля следует называть в соответствии с правилом: `Тема+название_модуля`.

3. Классы модуля должны обеспечивать `статическую` функцию с названием `names`, которая возвращает список названий, под которыми она может быть задействована.

4. Чтобы модуль можно было настраивать из Центра управления, он должен включать класс, основанный на классе `ThemeEngineConfig`.

5. Классы модуля должны перекрывать хотя бы одну из следующих виртуальных функций: `slotSetText`, `slotSetPixmap`, `slotUpdateProgress` и `slotUpdateSteps`, чтобы обеспечить возможность использования.

6. Рабработчик должен использовать форму `ThemeEngine( QWidget *parent, символьную постоянную *name, постоянную QStringList &args )`, чтобы модуль можно было использовать с `KGenericFactory`.

Последнее требование может показаться сложным, но, как мы увидим позже, вы можете обычно игнорировать его, добавив одну строку к исходным кодам.

### Код файла заголовка

Присвоив значения константам, мы увидим, что файл заголовков `theme2k.h` приобретёт вид вроде этого:

#### Файл `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

Давайте проанализируем вышеприведённое. Класс `Theme2k`, произведённый от `ThemeEngine` удовлетворяет объявлениям. Он обеспечивает метод `Theme2k::names()`, и имеет конструктор, который принимает необходимые параметры: `Theme2k( QWidget *, const char *, const QStringList& );`, и к тому же обеспечивает простой метод `Theme2k::slotSetText()`. На данном этапе вам не следует беспокоиться насчёт класса `RotWidget`. Это небольшой элемент графического интерфейса, который делает программу более наглядной для пользователя. Наш подключаемый модуль очень прост: он не отображает ни пиктограмм, ни шкалы загрузки. Если вы хотите использовать пиктограммы, перекройте функцию `slotSetPixmap`. Подобные функции есть для установки шкалы загрузки (`slotUpdateSteps`) и увеличения счётчика (`slotUpdateProgress`) текущего шага.

### Реализация подключаемого модуля

Мы проверим только связанные части реализации. В приложении находится описание всей реализации. В первую очередь нам необходимо удовлетворить требованиям библиотеки:

#### Требования библиотеки

    K_EXPORT_COMPONENT_FACTORY( libksplash2k, KGenericFactory<Theme2k> );

Объявление макроса `K_EXPORT_COMPONENT_FACTORY` содержится в файле `kgenericfactory.h`. Теперь перейдём к конструктору. Так как подключаемый модуль совсем прост, конструктор тоже несложен.

#### Конструктор подключаемого модуля

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

Метод `readSettings()` является иллюстрацией подходящего способа получить настройки темы (вы ведь хотите, чтобы люди могли использовать ваш модуль для своих тем?)

#### Получение настроек темы

    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 );
    }

Так как мы работаем для пользователей, следует обеспечить подходящие настройки по умолчанию для параметров, которые не представлены в файле темы. Обратите внимание, что группу следует устанавливать следующим образом: "KSplash Theme: название_темы", чтобы обеспечить совместимость с будущими спецификациями темы. Метод `initUI()` не представляет большого интереса, он просто организует элементы графического интерфейса. Детали см. в приложении.

### Компиляция подключаемого модуля

Для компиляции модуля мы решили использовать основу &kde;, поэтому необходимо создать файл `Makefile.am`. Он должен выглядеть следующим образом:

#### Файл `Makefile.am`

    INCLUDES = $(all_includes)

    kde_module_LTLIBRARIES = libksplash2k.la

    libksplash2k_la_SOURCES = theme2k.cpp rotwidget.cpp
    libksplash2k_la_LDFLAGS = $(all_libraries) $(KDE_RPATH)
    libksplash2k_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

Чтобы получить дальнейшую информацию по созданию `Makefile.am`, загляните на веб-сайт разработчиков &kde;. Заметим, что мы создаём тему по умолчанию, основанную на этом модуле, и прилагаем к нему графический файл фона. В качестве жеста вежливости по отношению к пользователям создайте файл `Theme.rc`, являющийся примером использования опций.

## Вопросы и ответы

&reporting.bugs; &updating.documentation;

Я не могу найти ни одной темы, которая работала бы с &ksplash;. Почему?

Возможно, у вас нет соответствующих подключаемых модулей для тем. Модули содержатся в пакете `kde-artwork`. Скачайте, установите его и попытайтесь запустить темы снова.

Что такое файл `Theme.rc` и как его создать?

`Theme.rc` - это файл, где вы можете задать настройки темы. Информация по нему находится в разделе Как создавать темы для &ksplash;.

## Благодарности и лицензирование

&ksplash;

Авторские права на программу принадлежат © 2003 &Ravikiran.Rajagopal; &Ravikiran.Rajagopal.mail;

### Помощь в разработке

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

Авторские права на документацию принадлежат © 2003 &Teemu.Rytilahti; &Teemu.Rytilahti.mail;

&underFDL; &underGPL;

## Установка

### Системные требования

Чтобы иметь возможность использовать возможности &ksplash; вам необходим оконный менеджер &kde; версии 3.2 или выше. Если тема не работает, свяжитесь с её автором, чтобы выяснить, где можно взять подходящий подключаемый модуль.

### Компиляция и установка

&install.compile.documentation;

## Исходные коды

### Файл `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( libksplash2k, 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 );
    }

### Файл `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

### Файл `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;