日本語 English


GNOME スクリーンセーバの作り方

Last modified: 2009/03/10

Linux 上で GNOME を使い始めて、一番の不満だったのが、アナログ時計のスクリーンセーバがないことだった。これじゃ、夜中に目が覚めても時間がわからない。KDE にはあったのに……。ググってみても、GLText を設定してデジタル時計にするくらいしか手がないらしい。そこで、作ってみることにした。

ところが今度は、GNOME スクリーンセーバの作り方が見つからない(少なくとも日本語では)。Microsoft Windows のスクリーンセーバのように自前のウィンドウに描画するのではだめで、GNOME が用意したスクリーンセーバウィンドウに描画しなければならないらしい。しょうがないので、gnome-screensaver のソースを見てみることにした。

でも、私はまったくの GTK+ 初心者。というより、C で GUI プログラミングをしたこともない。ほとんど、「GTK+入門(現在はオフリンク)」(の中の GDK のページ)のみを先達として、コードを削っていった。だから、以下のプログラムには、どこか間違いがあるに違いない。GNOME の偉い人、宜しくご指導下さい。

閑話休題

GNOME スクリーンセーバとして最低限動作するスケルトンを作成する。

まず、gnome-screensaver のソースを解凍し、savers/ の中の gs-theme-window.cgs-theme-window.h を取ってくる。
この 2つのファイルのライセンスは LGPL なので、作成したアプリケーションを公開する際には留意して欲しい。

そして、空の config.h を作る(touch config.h)。
gs-theme-window.cconfig.hinclude しているので存在しないとコンパイルが通らないのだが、実は gs-theme-window.cconfig.h に一切依存していない(本稿執筆時点)。

次に、スクリーンセーバの本体を作る。

gs-base.c
#include <sysexits.h>
#include "gs-theme-window.h"

GOptionEntry options[] = { {NULL} };

static void configure_event (GtkWidget *widget, GdkEventConfigure *event, gpointer data)
{
}

static void expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
}

int main (int argc, char **argv)
{
  GtkWidget *window;
  GtkWidget *drawing_area;
  GError *error = NULL;

  gtk_set_locale ();

  gtk_init_with_args (&argc, &argv,
                      "",
                      options,
                      "gnome-screensaver",
                      &error);

  if (error != NULL)
    {
      g_printerr ("%s. See --help for usage information.\n",
                  error->message);
      g_error_free (error);
      return EX_SOFTWARE;
    }

  window = gs_theme_window_new ();
  g_signal_connect (G_OBJECT (window), "delete-event",
                    G_CALLBACK (gtk_main_quit), NULL);

  drawing_area = gtk_drawing_area_new ();
  gtk_signal_connect (GTK_OBJECT (drawing_area), "configure_event",
                      GTK_SIGNAL_FUNC (configure_event), NULL);
  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
                      GTK_SIGNAL_FUNC (expose_event), NULL);

  gtk_widget_show (drawing_area);
  gtk_container_add (GTK_CONTAINER (window), drawing_area);

  gtk_widget_show (window);

  gtk_main ();

  return EX_OK;
}

見てわかる通り、window = gtk_window_new (GTK_WINDOW_TOPLEVEL); の替わりに window = gs_theme_window_new (); を使っている以外は、ごく普通の GTK+ アプリケーションだ。

次に、skeleton.desktop を作成する。
というより、pkg-config gtk+-2.0 --variable=themesdir gnome-screensaverで取得できるディレクトリ(多分、/usr/share/applications/screensavers)にあるファイルをコピーして編集する。
ASCII 文字以外を使うなら、文字コードは UTF-8 で。

skeleton.desktop
[Desktop Entry]
Encoding=UTF-8
Name=Skeleton
Name[ja]=スケルトン
Comment=Skeleton screen saver
Comment[ja]=スケルトンスクリーンセーバ
Exec=skeleton
TryExec=skeleton
StartupNotify=false
Terminal=false
Type=Application
Categories=GNOME;Screensaver;
OnlyShowIn=GNOME;

最後に、Makefile を作る。

Makefile
CC = gcc
PKG_CONFIG = pkg-config
GTK_METADATA = gtk+-2.0
INSTALL = install
GS_LIBEXEC_DIR = `${PKG_CONFIG} --variable=privlibexecdir gnome-screensaver`
GS_DESKTOP_DIR = `${PKG_CONFIG} --variable=themesdir gnome-screensaver`

SOURCES = gs-theme-window.c gs-base.c
TARGET = skeleton
DESKTOP = ${TARGET}.desktop

OBJECTS = $(SOURCES:.c=.o)
CFLAGS = `${PKG_CONFIG} ${GTK_METADATA} --cflags` -Wall
LIBS = `${PKG_CONFIG} ${GTK_METADATA} --libs`

$(TARGET): $(OBJECTS)
<--TAB-->$(CC) $(CFLAGS) -o $@ $(OBJECTS) $(LIBS)
.c.o:
<--TAB-->$(CC) $(CFLAGS) -c $< -o $@
clean:
<--TAB-->rm -f $(OBJECTS) $(TARGET) core* *.o *~
install:
<--TAB-->${INSTALL} -s ${TARGET} ${GS_LIBEXEC_DIR}
<--TAB-->${INSTALL} -m 644 ${DESKTOP} ${GS_DESKTOP_DIR}

make
su
make install
で、GNOME スクリーンセーバとして設定できる。

あとは、configure_eventexpose_event でお絵描きをして、タイマーでアニメーションにすれば、カスタムスクリーンセーバができあがる(はず)。

Happy hacking!

おまけ

MATE 用 時計のスクリーンセーバ


Valid HTML 4.01 Strict Valid CSS 2.1