Es muss nicht immer ein ausgewachsenes Programm sein. Viele kleine Aufgaben lassen sich auch mit Applets erledigen, die im Panel residieren und nur darauf warten, aufgerufen zu werden.
Applets sind klein und knuddelig. Im Gegensatz zu großen Gtk+- oder GNOME-Programmen belegen sie nicht viel Platz auf dem Bildschirm und beanspruchen in den meisten Fällen die Ressourcen auch nicht so stark. Sie eignen sich besonders gut für Statusanzeigen aller Art, also für die Prozessorauslastung, die Batterieanzeige für den Laptop oder eine Wetteransicht, die anzeigt, ob es regnet oder nicht. So muss man sich erst gar nicht von der Tastatur erheben und nachschauen. Das Wetter-Applet ist – neben einigen anderen – in meinem eigenen Panel (Abbildung 1) zu sehen.
In ihrer programmiertechnischen Seite unterscheiden sich Applets nicht wesentlich von normalen GNOME-Programmen. In Listing 1 sehen Sie ein normales Programm für GNOME, das lediglich ein leeres Fenster erzeugt. Es enthält die gewohnten Schritte: Internationalisierung festlegen, Applikationsfenster erzeugen, mit den Standardsignalen verbinden und dann anzeigen. Die Definitionen in den Zeilen 3 bis 5 werden automatisch erzeugt und beim Kompilieren übergeben, wenn man mit einem Quelltextbaum arbeitet, den man sich vorher erzeugt hat.
Durchaus ähnlich verhält sich ein leeres Applet, das ich an dieser Stelle – als Variation über das “Hallo Welt”-Thema sozusagen – das Mahlzeit-Applet nennen möchte. Und dem entsprechend tut es auch erst einmal nichts anderes als Mahlzeit anzeigen. Es ist in Listing 2 zu sehen.
Die Defines in den Zeilen 4 bis 6 haben wieder den gleichen Ursprung wie vorher. In Zeile 2 muss noch die Headerdatei applet-widget.h eingebunden werden, die Zugriff auf die Bibliotheksfunktionen für Applets gestattet.
Der erste wirklich neue Teil ist in Zeile 16 zu sehen: Das Programm wird nicht durch gnome_init() initialisiert, sondern durch einen Aufruf von applet_widget_init(). Die Parameter dieser Funktion sind der Programmname, die Programmversion, die Komandozeilenparameter argc und argv sowie die Argumente für ein Parsen der Kommandozeile durch die Bibliothek libpopt. Dieser Vorgang soll hier allerdings nicht besprochen werden.
Applets sind ein eigener Widget-Typ, was man am Aufruf applet_widget_ new() in Zeile 18 erkennen kann. Das Applet muss mit dem Panel kommunizieren, um sich an eine korrekte Stelle einfügen zu können. Zuweilen scheitert diese Kommunikation schon im Ansatz, so dass kein Applet kreiert werden kann. Ist dies der Fall, dann ist in unserem Beispiel applet ein NULL-Zeiger, den wir in den Zeilen 19 bis 22 abfangen und daraufhin das Applet mit einer Fehlermeldung beenden. In den folgenden Zeilen wird nur noch ein Label erzeugt und in das Applet eingefügt.
Listing 1: Skelett eines normalen GNOME-Programms |
1: #include <gnome.h>
2:
3: #define PACKAGE "gnome-std"
4: #define VERSION "0.1.0"
5: #define GNOMELOCALEDIR "/opt/gnome/share/locale"
6:
7: int main(int argc, char *argv [])
8: {
9: GtkWidget *app;
10:
11: bindtextdomain (PACKAGE, GNOMELOCALEDIR);
12: textdomain (PACKAGE);
13:
14: gnome_init (PACKAGE, VERSION, argc, argv);
15:
16: app = gnome_app_new (PACKAGE, PACKAGE);
17: gtk_signal_connect (GTK_OBJECT (app), "delete_event", gtk_main_quit, NULL);
18: gtk_signal_connect (GTK_OBJECT (app), "destroy_event", gtk_main_quit, NULL);
19:
20: gtk_widget_show_all (app);
21:
22: gtk_main();
23:
24: return TRUE;
25: }
|
Listing 2: Das erste Mahlzeit-Applet |
1: #include <gnome.h>
2: #include <applet-widget.h>
3:
4: #define PACKAGE "mahlzeit-applet"
5: #define VERSION "0.1.0"
6: #define GNOMELOCALEDIR "/opt/gnome/share/locale"
7:
8: int main(int argc, char *argv [])
9: {
10: GtkWidget *applet;
11: GtkWidget *label;
12:
13: bindtextdomain (PACKAGE, GNOMELOCALEDIR);
14: textdomain (PACKAGE);
15:
16: applet_widget_init (PACKAGE, VERSION, argc, argv, NULL, 0, NULL);
17:
18: applet = applet_widget_new (PACKAGE);
19: if (!applet)
20: {
21: g_error ("Kann Applet nicht erstellen.n");
22: }
23:
24: label = gtk_label_new (" Mahlzeit! ");
25: applet_widget_add (APPLET_WIDGET (applet), label);
26:
27: gtk_widget_show_all (applet);
28:
29: gtk_main();
30:
31: return TRUE;
32: }
|
Da das Applet ganz normal als Container-Widget fungiert, lässt sich theoretisch jedes andere Widget einfügen. Es sei aber einmal dahingestellt, bei welchen Widget es Sinn ergeben würde und bei welchen nicht.
Applets benötigen natürlich eigene Parameter beim Kompilieren. Heißt unsere Datei mahlzeit_applet.c, dann ist folgendes Kommando korrekt:
gcc mahlzeit_applet.c `gnome-config libs cflags gnome gnomeui applets` -o mahlzeit_applet
Ist das Applet kompiliert und gestartet, was wie bei einem normalen Programm auch von der Kommandozeile geschehen kann, dann erscheint es wie von Geisterhand gezeichnet im Panel, wie man in Abbildung 2 schön erkennen kann.
Ausstaffierung
Soweit also das erste Applet. Klickt man es mit der rechten Maustaste an, sind zwei Menüpunkte namens Bewegen und Entfernen zu erkennen, die Namen dürften für sich sprechen. Außerdem sieht man noch einen Menüpunkt Panel, hinter dem sich die bekannte Panelkonfiguration verbirgt. An dieser Stelle möchte man eventuell eigene Menüpunkte einfügen – das ist auch ohne weiteres möglich. Mit der Funktion applet_widget_register_stock_callback lassen sich neue Menüpunkte generieren und auch gleich mit Callback-Funktionen verbinden.
Listing 3: Ein ausfühliches Applet |
1: #include <gnome.h>
2: #include <applet-widget.h>
3:
4: #define PACKAGE "mahlzeit-applet"
5: #define VERSION "0.1.0"
6: #define GNOMELOCALEDIR "/opt/gnome/share/locale"
7:
8: void change_pixel_size_callback (AppletWidget *applet, int pixels, gpointer data)
9: {
10: printf ("Das Panel ist %d Pixel groß.n", pixels);
11: }
12:
13: void change_orient_callback (AppletWidget *applet, PanelOrientType orient, gpointer data)
14: {
15: switch (orient)
16: {
17: case ORIENT_UP:
18: printf ("Das Panel befindet sich an der Unterseite.n");
19: break;
20: case ORIENT_DOWN:
21: printf ("Das Panel befindet sich oben.n");
22: break;
23: case ORIENT_LEFT:
24: printf ("Rechts das Panel!n");
25: break;
26: case ORIENT_RIGHT:
27: printf ("Links das Panel!n");
28: break;
29: default:
30: printf ("Keine Orientierung !?!n");
31: break;
32: }
33: }
34:
35: void about_callback (AppletWidget *applet, gpointer data)
36: {
37: GtkWidget *dialog;
38: const gchar *autoren [] = {"Thorsten Fischer @derfrosch.de>", NULL};
39:
40: dialog = gnome_about_new (PACKAGE, VERSION, "(c) 2000 Thorsten Fischer", autoren,
41: "Beispielapplet für das Linux-Magazin.nDer Code unterliegt der GPL.", NULL);
42:
43: gtk_widget_show (dialog);
44:
45: return;
46: }
47:
48: int main(int argc, char *argv [])
49: {
50: GtkWidget *applet;
51: GtkWidget *label;
52: GtkWidget *frame;
53:
54: bindtextdomain (PACKAGE, GNOMELOCALEDIR);
55: textdomain (PACKAGE);
56:
57: applet_widget_init (PACKAGE, NULL, argc, argv, NULL,0,NULL);
58:
59: applet = applet_widget_new (PACKAGE);
60: if (!applet)
61: {
62: g_error ("Kann Applet nicht erstellen.n");
63: }
64: gtk_signal_connect (GTK_OBJECT (applet), "change_orient",
65: GTK_SIGNAL_FUNC (change_orient_callback), NULL);
66: gtk_signal_connect (GTK_OBJECT (applet), "change_pixel_size",
67: GTK_SIGNAL_FUNC (change_pixel_size_callback), NULL);
68: applet_widget_register_stock_callback (APPLET_WIDGET (applet), "about", GNOME_STOCK_MENU_ABOUT,
69: _("About"), about_callback, NULL);
70:
71:
72: frame = gtk_frame_new (NULL);
73: applet_widget_add (APPLET_WIDGET (applet), frame);
74:
75: label = gtk_label_new (" Mahlzeit! ");
76: gtk_container_add (GTK_CONTAINER (frame), label);
77:
78: gtk_widget_show_all (applet);
79:
80: gtk_main();
81:
82: return TRUE;
83: }
|
In unserem Beispiel, das in Listing 3 komplett ausstaffiert ist, gibt es einen Menüpunkt About, der eine entsprechende Box anzeigt. Es gibt auch Funktionen, die Menüpunkte wieder entfernen oder komplette Untermenüs anlegen.
Bekanntmachung
Hat man den Code beisammen und vielleicht sogar in einen eigenen Codebaum eingebaut, mit dessen Hilfe sich die Kompilierung auf beliebigen Systemen recht einfach gestaltet, dann möchte man sicherlich auch, dass das Applet benutzt wird. Dazu sollte es in den Menüs erscheinen, die man als Benutzer zu sehen bekommt, wenn man das Panel mit der rechten Maustaste anklickt und Applet hinzufügen auswählt. Dafür ist im Wesentlichen eine .desktop-Datei erforderlich, die ungefähr so aussehen muss wie in Listing 4. Diese Datei muss in das Verzeichnis
<prefix>/share/applets/<kategorie>
kopiert werden, wobei Prefix das Stammverzeichnis der GNOME-Installation ist – bei SuSE zum Beispiel /opt/gnome – und die Kategorie dem Type-Eintrag in der .desktop-Datei entspricht, hier also Application.
Weiterer Kram
Die Anforderungen an ein Applet sind etwas anders geartet als die an ein gewöhnliches Programm mit Fenster. (An alle Klugen: Natürlich weiß ich, dass im Sinne des X-Servers auch ein Applet ein Fenster hat; schließlich ist ein Window nichts anderes als eine Fläche, in die hineingezeichnet werden kann.)
Beispielsweise sollte es auf vertikale und horizontale Ausrichtungen seiner selbst reagieren können, ebenso auf Größenänderungen, denn immerhin kennt GNOME zwischen 12 und 128 Pixeln Ausdehnung sieben unterschiedliche Größen für ein Applet. Sobald sich die Größe des Panels ändert – sowie beim ersten Start des Applets – wird das Signal change_ pixel_size ausgesandt, das mit einem entsprechenden Callback abgefangen werden kann.
Im Beispiel in Listing 3 geschieht das anhand der Funktion change_pixel_ size_callback. Obwohl man als Programmierer niemals nur von Standardsituationen ausgehen sollte, können Vergleiche mit möglichen Pixelgrößen anhand von Konstanten stattfinden; sie tragen alle als Prefix PIXEL_SIZE_ und sind dann ULTRA_TINY, TINY, SMALL, STANDARD, LARGE, HUGE und RIDICULOUS benannt, mit einer Größe von 12, 24, 36, 48, 64, 80 beziehungsweise 128 Pixeln. Mit der letzten Größe kann kein Mensch etwas anfangen, aber man kann einen schönen Blick auf das Antialiasing der Icons werfen.
Außerdem kann die Darstellung eines Widgets von der Orientierung des Panels abhängen. Es kommt daher gelegen, dass ein Applet immer dann ein Signal vom Panel erhält, wenn es seine Orientierung ändert, und natürlich ebenfalls gleich beim ersten Start des Applets. Es heißt change_orient und wird im Beispiel (Listing 3) mit der Callback-Funktion change_ orient_callback abgefangen.
Listing 4: Die Desktop-Datei für ein Applet |
[Desktop Entry] Name=Mahlzeit Applet Comment=Ein Applet, das Mahlzeit sagt Exec=mahlzeit_applet Icon= Terminal=0 Type=Application |
Es mag wunderlich erscheinen, dass die Konstanten, die als Ergebnis vorliegen können, das genaue Gegenteil dessen ergeben, was sie auf den ersten Blick aussagen. Aber es wird tatsächlich nicht die Position des Panels übergeben, sondern die Richtung, in der ein Menü aufgebaut würde, wenn es erzeugt werden müsste.
Außerdem ist noch zu beachten, dass die Verbindung mit dem Signal stattfinden sollte, bevor mit applet_widget_add() weiterer Inhalt in das noch leere Applet eingefügt wird. Sonst bringt man sich um die Möglichkeit, entsprechend auf die Orientierung reagieren zu können.
Fröhliches Gnomen! (uwo)
Der Autor |
|
Thorsten Fischer studiert Informatik und/oder Medienberatung an der Technischen Universität Berlin. Er ist unter frosch@derfrosch.de per E-Mail zu erreichen. Im Oktober 2000 ist im Verlag SuSE-Press sein Buch “GUI-Programmierung mit GTK+” erschienen. |
Infos |
|
[1] Quelltexte für den Artikel: http://www.derfrosch.de/weichewaren/linux-magazin.html [2] Gnome-core applet writing HOWTO: http://cvs.gnome.org/lxr/source/gnome-core/panel/APPLET_WRITING [3] Gnome Applet Tutorial: http://developer.gnome.org/doc/tutorials/applet/index.html [4] Thorsten Fischer: Punkt, Punkt, Komma, Polygon; Linux Magazin 11/2000 |






