dla programistów Zobacz w: Aplety dla GNOME Marek Sawerwain edną z ciekawszych funkcji nowoczesnego środowiska pracy jest możliwość umieszczania na ekranie małych programów nazywanych apletami. W wielu graficz- J nych środowiskach pracy, działających pod kontrolą systemu X Window, istnieje możliwość umieszczenia takie- go apletu. Nie inaczej jest w GNOME, które od pradawnych wersji posiada taką cechę. Zastosowania takich apletów wbrew pozorom są bardzo szerokie. Można w nich umiesz- czać przydatne programy, np. do sprawdzania poczty albo monitorowania stanu baterii w notebooku. Napisanie apletu w przypadku GNOME nie jest zada- niem trudnym, szczególnie w najnowszej wersji 2.4. Środo- wisko GNOME zawsze oferowało API łatwe do opanowa- nia. W tym artykule chciałbym przedstawić sposób two- Rysunek 1. Konfiguracja APM w jądrze 2.4.23 rzenia takiego małego programu na praktycznym przykła- dzie apletu przeznaczonego do monitorowania stanu bate- Jeśli APM jest obsługiwane przez nas system, to na ekranie rii w komputerach przenośnych, czyli różnego rodzaju note- terminala zobaczymy następującą linijkę tekstu (są to infor- bookach. macje odczytane z komputera stacjonarnego): Artykuł, jak myślę, będzie tym bardziej przydatny, ponieważ nawet na stronie GNOME Developer's Home 1.16 1.2 0x07 0x01 0xff 0x80 -1% -1 ? Page osobiście nie mogłem odszukać aktualnych informacji o tworzeniu apletów do najnowszej wersji 2.4 środowiska. Gdy plik apm nie istnieje w katalogu proc, można spróbo- Istnieje tam podręcznik opisujący tworzenie apletów, ale wać poleceniem modprobe apm załadować moduł obsługi z roku 1999, a od tego czasu GNOME znacznie się zmieni- tego standardu. Jeśli i ten krok nie powiedzie się, czeka nas ło, na lepsze oczywiście. rekompilacja jądra. W procesie konfiguracji jądra najważniejsza opcja to Czy jądro systemu obsługuje APM? Advanced Power Management BIOS support w sekcji Ge- Zanim zaczniemy pisać sam aplet, należy odpowiedzieć sobie na wyżej postawione pytanie. Znacząca większość notebooków obsługuje oczywiście ten standard, jak rów- Czym są aplety? nież jądro Linuksa. Jeśli korzystamy z jądra zawartego Aplet to mały/niewielki program. Takie określenie pojawi- w określonej dystrybucji, to zazwyczaj obsługa APM jest ło wraz z pierwszą wersją Javy. Zastosowanie apletów Javy umożliwia dołączanie do strony WWW nawet bardzo skom- włączona. W razie wątpliwości wystarczy wydać następu- plikowanych programów. Pomimo tego, pojęcie apletu doty- jące polecenie: czy raczej małych, ale bardzo przydatnych programów, np. przeznaczonych do sterowania odtwarzaniem płyt CD Audio. cat /proc/apm Typowym przykładem apletu jest nasz aplet do monitorowania stanu baterii. Środowisko GNOME posiada kilkanaście przy- datnych apletów, np. do sprawdzania, czy w skrzynce pocz- towej znajdują się nowe listy. Oczywiście GNOME posia- O autorze: da gotowy aplet do monitorowania baterii. Stan baterii jest Autor zajmuje się tworzeniem oprogramowania dla przedstawiany graficznie, co powoduje, że kod zródłowy liczy WIN32 i Linuksa. Zainteresowania: teoria języków pro- prawie 40kB. Nasz aplet jest równie przydatny, choć to tylko gramowania oraz dobra literatura. Kontakt z autorem: autorzy@linux.com.pl. 4kB tekstu zródłowego. 58 luty 2004 aplety dla gnome Listing 1. Postać pliku /etc/apm w zależności od typu komputera i sposobu jego zasilania Zawartość pliku dla komputera stacjonarnego: 1.16 1.2 0x07 0x01 0xff 0x80 -1% -1 ? Dla komputera przenośnego z zasilaniem zewnętrznym (220V): 1.16 1.2 0x02 0x01 0x03 0x09 92% 125 min Dla komputera przenośnego z zasilaniem z baterii: 1.16 1.2 0x02 0x00 0x00 0x01 92% 122 min neral setup . Warto wsparcie dla APM skompilować jako moduł, tak jak pokazuje to Rysunek 1. Odczytanie informacji o stanie baterii Ponieważ plik /proc/apm to tylko jedna linia tekstu, to zadanie odczytania informacji jest bardzo łatwe. Wystarczy skorzystać z typowej funkcji do skanowania ciągu znaków, np. sscanf albo plikowej odmiany fscanf. Listing 1 prezentuje postać pliku /proc/apm w trzech różnych przypadkach: dla komputera stacjonarnego, prze- nośnego z zasilaniem z sieci 220V oraz z zasilaniem z bate- rii. Nas najbardziej interesują trzy ostatnie wartości, np. Tabela 1. Znaczenie poszczególnych parametrów APM z pliku /proc/apm Kolejna wartość z Opis pliku /proc/apm driver_version, numer wersji sterownika np. 1.16 apm_version major numer wersji standardu APM Rysunek 2. Schemat czynności wykonywanych w aplecie and minor, np. 1.2 92% , 122 oraz min . Są to potrzebne nam informa- apm_flags, np. 0x02 dodatkowe wartości apm cje, czyli stopień naładowania baterii, przewidywany czas ac_line_status, zasilanie zewnętrzne: wartość pracy oraz jednostka, w jakiej mierzony jest czas pracy np. 0x00 0x00 oznacz brak, a 0x01 zasi- (zazwyczaj minuty). Dla komputera stacjonarnego te para- lanie z sieci 220V metry przyjmują wartości: -1 i znak zapytania. Z tego battery_status, dodatkowe informacje o bate- powodu dość łatwo rozróżnić, czy nasz komputer posiada np. 0x00 riach nie wykorzystywane baterie, czy też nie. w naszym aplecie: jeśli kompu- Procedura wyciągnięcia informacji z pliku sprowadza ter jest w nie wyposażony, przyj- się jedynie do otwarcia pliku /proc/apm w trybie do odczy- mie wartość 0x00, a przy ich tu oraz zastosowanie funkcji fscanf. Prezentuje to Listing 2. braku 0xff W naszym aplecie będziemy jednak korzystać z gotowych battery_flags, dodatkowa wartość o bateriach, funkcji zawartych w plikach apmlib.c oraz apm.h, które np. 0x01 np. czy są ładowane: pole przyj- wieki temu zostały opracowane przez Rickarda E. Faitha. muje w takim przypadku war- tość 0x9 Zaczynamy pisać aplet Pisanie apletu warto rozpocząć od krótkiej chwili refleksji battery_percentage, stopień naładowania baterii, i zastanowienia się, co ma przedstawiać nasz aplet. Ponie- np. 92% a -1% przy ich braku waż aplet ma pokazywać stan baterii w komputerach prze- battery_time, przewidywany czas pracy na nośnych, to najłatwiej będzie zrealizować to wyświetlając np. 122 bateriach, a -1 przy ich braku komunikaty tekstowe. Można oczywiście wykorzystać ele- using_minutes, jednostka czasu menty graficzne, lecz nasz aplet ma pełnić głównie funk- np. min cje edukacyjne. www.linux.com.pl 59 dla programistów Zobacz w: Listing 3. Postać pliku (z usuniętymi tłumaczeniami) Listing 2. Odczytanie parametrów z /proc/apm GNOME_BatteryApplet.server char driver_version[10]; int apm_version_major, apm_version_minor, apm_flags; int ac_line_status, battery_status, battery_flags, battery_percentage; type="exe" int battery_time; location="/opt/libexec/battery-applet-2"> char units[10]; memset(&units[0], 10, sizeof(char)); FILE *f=NULL; f=fopen("/proc/apm", "r"); fscanf(f, "%s %d.%d %x %x %x %x %d%% %d %s\n", (char *) driver_version, value="Battery Factory"/> &apm_version_major, &apm_version_minor, value="Battery Factory"/> &apm_flags, &ac_line_status, &battery_status, type="factory" &battery_flags, location="OAFIID:GNOME_BatteryApplet_Factory"> &battery_percentage, &battery_time, units); if(strncmp(units, "min", 3)==1) using_minutes=1; else using_minutes=0; value="Battery Charge Monitor"/> Wewnętrzna architektura GNOME może przyprawić o solidny ból głowy początkującego programistę. Może to value="Monitor laptop's and być nawet mur nie do pokonania. Poszczególne elemen- notebook's baterry remaining ty GNOME 2.4 (dla tego środowiska piszemy nasz aplet) są power"/> oparte o definicję obiektu z biblioteki GLIB. Do tego docho- dzi jeszcze standard CORBA, który poprzez BONOBO jest value="Utility"/> stosowany w implementacji komponentów oraz modelu value="battstat.png"/>
dokument/widok. Ponieważ podstawowym językiem jest C, a nie C++, to obiektowość środowiska nie jest tak oczy- wista jak w systemie, w którym do implementacji zastoso- wano C++. Ma to jednak swoje zalety GNOME 2.4 uru- chamia się dosłownie w parę sekund, a KDE ponad pół minuty (tak przynajmniej przedstawia się to na moim oso- bistym komputerze). Autorom wielkiej stopy udało się stworzyć bardzo łatwe do opanowania API, które pozwala tworzyć progra- my w GNOME niemal bez wstępnej nauki. Widać to szcze- gólnie w przypadku GTK+. Podobnie jest w przypadku apletów. Skomplikowane mechanizmy zostały ukryte przed programistą i może on skupić się na tworzeniu samego apletu. Gdy istnieje potrzeba, zawsze można sięgnąć bez- pośrednio do wewnętrznej architektury. Zanim zaczniemy pisać aplet, warto wiedzieć, że GNOME posiada specjalny program panel-test-applets. Przy Rysunek 3. Obiekty apletu do monitorowania stanu baterii pomocy tej małej aplikacji można testować działanie apletu. 60 luty 2004 aplety dla gnome fejsów korzystamy, czyli utworzyć tzw. repo_ids. W każdym Listing 4. Funkcja fabryki odpowiedzialna za wywołanie aplecie wygląda to zawsze tak samo. Ważnym parametrem funkcji tworzącej interfejs apletu jest location, bowiem tu trzeba podać pełną ścieżkę do pliku wykonywalnego apletu. W naszym przypadku jest to gboolean battery_app_factory (PanelApplet *applet, const gchar *iid, gpointer data) { katalog /opt/libexec/battery-applet-2 może to być również gboolean retval = FALSE; /usr/libexec. Lepiej utworzyć własny katalog, aby nie two- if(!strcmp(iid, "OAFIID:GNOME_BatteryApplet )) rzyć bałaganu w oryginalnych plikach GNOME. W przy- retval=create_applet (applet); padku jakichś kłopotów, łatwiej będzie usunąć plik z aple- return retval; tem. } Istotniejsza jest deklaracja drugiego obiektu o nazwie OAFIID:GNOME_BatteryApplet, bowiem to on reprezentu- GNOME podczas instalacji nowej wersji apletu nie wymaga je właściwy aplet. Zwróćmy uwagę na parametr loca- restartu należy zadbać, aby nie była uruchomiona żadna tion. O ile w poprzednim przypadku podaliśmy ścież- kopia apletu, a wtedy można bez kłopotów podmienić plik kę do pliku, to tym razem podajemy identyfikator fabry- binarny. ki, która utworzy obiekt apletu. Tutaj znów podajemy Zanim zaczniemy pisać kod, trzeba zorientować się, zestaw interfejsów, które muszą znalezć się w definicji jakie czynności będziemy wykonywać. Schemat operacji każdego apletu. Ważniejsze są dodatkowe atrybuty, takie wykonywanych w aplecie prezentuje Rysunek 2. Zwróć- jak nazwa (name), opis (description) oraz kategoria my uwagę na dwa pierwsze żądania. Są one wysuwane w panelu (panel:category). Wpisujemy tu nazwę przez obiekt panel i nasz aplet musi na nie reagować. Auto- menu, w którym zostanie umieszczony aplet. Określi- rzy GNOME uprościli podstawowe czynności, więc two- my też plik ikonki, która zostanie wyświetlona w menu rzenie fabryki sprowadza się do zastosowania makra. Two- (plik battstat.png znajduje się w każdym GNOME, rzenie apletu polega tylko na sprawdzeniu identyfikatora. bowiem jest to ikona dołączonego do systemu domyślne- Naszym zadaniem będzie głównie implementacja funkcji go monitora stopnia naładowania baterii). Definicje tych create_applet oraz update_status. parametrów w polskim tłumaczeniu, czyli z przyrostka- mi -pl , prezentują się następująco: Przygotowanie pliku server Pierwszą czynnością, którą wystarczy wykonać tylko raz, jest przygotowanie specjalnego pliku o rozszerze- value="Monitoruje stan bateri"/> niu server. Jego pełna nazwa to GNOME_BatteryAp- plet.server. W tym pliku znajdą się podstawowe informa- value="Monitor stanu baterii w komputerach przenosnych"/> cje o naszym aplecie: pełna ścieżka oraz krótkie opisy i pozycja w menu apletów. Plik server to plik tekstowy value="Narzędzia"/> w języku XML, którego treść przedstawia Listing 3. W stosunku do wersji zamieszczonej na płycie CD, nie ma Gdy już dysponujemy napisanym plikiem, pozostaje go w nim tłumaczenia na język polski każdy atrybut, taki jak tylko przegrać do katalogu, np. /usr/lib/bonobo/servers, name, description czy panel:category, powinien posiadać a mówiąc ogólnie, do miejsca, w którym znajdują się inne swoją odmianę dla różnych języków. Jest to dość ważne, pliki o rozszerzeniu server. bowiem jeśli GNOME będzie używać polskiego interfej- su, to aplet może nie zostać umieszczony w menu albo Implementacja apletu nie będzie dostępny opis, a nawet sama nazwa w menu W pisanym przez nas aplecie występują cztery obiekty, (wyświetli się tylko pusta linia). które należy zaimplementować. Przede wszystkim należy Utworzenie tych tłumaczeń jest bardzo proste. Parametr dokonać implementacji fabryki oraz utworzyć komponent (bądz atrybut) z dowolnej sekcji rożni się przyrostkami, np. reprezentujący aplet. Prezentuje to Rysunek 3, na którym name-pl oznacza nazwę obiektu w języku polskim, podob- znajduje się schemat logiczny obiektów naszego apletu. nie description-pl oznacza opis w języku polskim. Dla Widać na nim także komponent reprezentujący panel, na obiektu fabryki OAFIID:GNOME_BatteryApplet_Factory tłu- którym znajdzie się nasz aplet. Oczywiście tym obiektem maczenia raczej nie mają dużego znaczenia, więc najlepiej nie musimy się zajmować, ponieważ to obiekt panel będzie pozostać przy oryginalnych nazwach. ładował nasz aplet. Struktura pliku server wymaga obecności defini- Jak wcześniej napisałem, implementacja fabryki spro- cji dwóch serwerów, w tym tzw. fabryki, która utworzy wadza się do zastosowania makra. Podobnie jest w przy- obiekt apletu. padku obiektu apletu w rzeczywistości jest to tylko Definicja fabryki jest obowiązkowa, ale ponieważ do identyfikator, który służy do wywołania funkcji create_ definicji wystarczy zastosowanie odpowiedniego makra, applet (w niej następuje utworzenie interfejsu apletu). my nie będziemy się tym szeroko zajmowali. W pliku server W tej funkcji następuje także jeszcze jedna istotna czyn- wystarczy podać nazwę fabryki oraz opisać, z jakich inter- ność. Otóż rejestrujemy w niej następną funkcję update_ www.linux.com.pl 61 dla programistów Zobacz w: cy obiekt apletu, to nastąpi wywołanie następnej funkcji Listing 5. Tworzenie interfejsu apletu create_applet, tworzącej interfejs apletu. Funkcja realizu- jąca takie zadanie o nazwie battery_app_factory zosta- gboolean create_applet(PanelApplet *applet) { ła przedstawiona na Listingu 4. Jak widać, sprawdza się GtkWidget *w, *vbox, *hbox; w = GTK_WIDGET(applet); tam tylko, czy identyfikator przekazywany przez iid jest gtk_widget_realize(w); różny od identyfikatora obiektu apletu. Jeśli tak jest, to is_apm=0; należy utworzyć ten obiekt. W każdym innym przypad- if(apm_exists()==0) is_apm=1; ku będzie to oznaczać, że obiekt apletu został już wcze- vbox=gtk_vbox_new(FALSE,1); śniej utworzony. hbox=gtk_hbox_new(FALSE,1); label=gtk_label_new(NULL); Zadaniem ostatniego argumentu makra PANEL_APPLET_ g_signal_connect(G_OBJECT(label), "destroy", BONOBO_FACTORY jest przekazanie dodatkowych informacji, G_CALLBACK(destroy_monitor), NULL); które pózniej zostaną przekazane funkcji create_applet. bat_status=gtk_label_new(NULL); W naszym przypadku nie ma takiej potrzeby, więc podawa- mesg=gtk_label_new(NULL); na jest wartość NULL. gtk_box_pack_start(GTK_BOX(vbox), label, 1,1,0); // pozostałe operacje pakowania gtk_container_add(GTK_CONTAINER(w), hbox); Tworzenie interfejsu funkcja timer=gtk_timeout_add(1000, update_status, NULL); create_applet gtk_widget_show_all(w); Gdyby omawiać zawartość funkcji tworzącej interfejs panel_applet_setup_menu(PANEL_APPLET(applet), apletu nie wskazując, iż chodzi o aplet, to można by xml_dsc, battery_menu_verbs, applet); return TRUE; o niej powiedzieć, że jest to typowa funkcji tworząca wid- } gety dla aplikacji GTK+. Nasz aplet wszystkie komunikaty przekazuje w formie tekstowej, dlatego w funkcji tworzy- my tylko etykiety, odpowiednio umieszczając je w pudeł- status, której zadaniem jest uaktualnianie naszego apletu, kach . Ustalaniem treści komunikatów zajmuje się funkcja tak aby użytkownik komputera widział zmieniający się update_status. stan naładowania baterii. W funkcji create_applet sprawdzamy, czy program może korzystać z APM. Za test odpowiedzialna jest funkcja Implementacja fabryki apm_exists, która pochodzi z pliku apmlib.c. Cały proces implementacji fabryki sprowadza się do zasto- Ze względu na specyfikę naszego apletu należy cyklicz- sowania jednego makra. Najważniejsze są oczywiście para- nie odświeżać informacje, które wyświetla. Z tego powodu metry, a wygląda to następująco: rejestrujemy funkcję update_status funkcją gtk_time- out_add. Pierwszym parametrem określamy czas odświeża- PANEL_APPLET_BONOBO_FACTORY nia w milisekundach. Podana wartość 1000 oznacza jedną ("OAFIID:GNOME_BatteryApplet_Factory", sekundę. Wywołanie wygląda tak: PANEL_TYPE_APPLET, "battery", timer=gtk_timeout_add(1000, update_status, NULL); "0", (PanelAppletFactoryCallback)battery_app_factory, Oczywiście podczas usuwania apletu z panelu należy NULL) usunąć zarejestrowaną funkcję. Z tego powodu do jednej z etykiet podłączana jest obsługa sygnału destroy. Jak widać, mamy sześć parametrów. Jako pierwszy poda- jemy identyfikator naszej fabryki jest on oczywiście identyczny z identyfikatorem podanym w pliku server. Potem musimy podać typ obiektu, który jest tworzo- ny przez fabrykę. Tutaj znów korzystamy z gotowej pre- definicji i podajemy PANEL_TYPE_APPLET. W trzecim para- metrze podajemy identyfikator obiektu może to być, tak jak w przykładzie, nazwa naszego apletu albo nazwa pliku binarnego. Następny parametr powinien zawie- rać numer wersji apletu. W naszym przypadku jest to po prostu zero, ale można w tym miejscu podać numer wersji, np. 1.0 . W piątym co do kolejności parametrze należy podać funkcję, która zostanie wywołana w momencie tworzenia fabryki. Ta czynność jest bardzo istotna, ponieważ gdy fabryce zostanie przekazany identyfikator reprezentują- Rysunek 4. Aplet w akcji 62 luty 2004 aplety dla gnome Pod koniec budowania interfejsu apletu rejestrowane jest Listing 6. Tworzenie interfejsu apletu również menu, które można uzyskać klikając prawym przy- ciskiem na aplecie. Nasz aplet nie oferuje wyrafinowa- gint update_status(gpointer d) { apm_info ai; nych możliwości, więc w dodatkowym menu znajduje się char txt[127]; tylko opcja About . Oprócz opcji About , w wyświetlo- if(is_apm==1){ nym menu znajdują się trzy inne domyślne opcje, zawsze apm_read(&ai); obecne w każdym aplecie, takie jak usuń z panelu , zablo- if(ai.ac_line_status==1) kuj (blokowanie pozycji apletu) oraz przesuń . gtk_label_set_text(GTK_LABEL(label), "Zasilanie AC"); Chcąc dołączyć własne opcje do menu apletu, należy else przygotować opis elementów menu jako tabelę o typie gtk_label_set_text(GTK_LABEL(label), BonoboUIVerb. Tabela dla naszego apletu przedstawia się "Zasilanie z baterii"); następująco: if((ai.battery_flags & 0x8)==1){ gtk_label_set_text(GTK_LABEL(bat_status), "Aadowanie baterii"); static const BonoboUIVerb battery_menu_verbs [] = { } BONOBO_UI_UNSAFE_VERB ("BatteryAbout", about_win), if(ai.battery_percentage==-1){ BONOBO_UI_VERB_END gtk_label_set_text(GTK_LABEL(bat_status), }; "Brak baterii"); } else Element menu jest reprezentowany przez makra BONOBO_UI_ { UNSAFE_VERB, w którym mamy tylko dwa parametry: symbo- sprintf(&txt[0],"stopien naładowania %d%%", liczną nazwę oraz nazwę funkcji, która zostanie wywołana, ai.battery_percentage); jeśli dana opcja zostanie wskazana przez użytkownika. gtk_label_set_text(GTK_LABEL(bat_status), GNOME oferuje dość sporo możliwości w deklaracji &txt[0]); if(ai.battery_percentage>50) wyglądu menu, więc opis, jaka ikonka ma się pokazać sprintf(&txt[0], "oraz sam tekst w menu określa się przy pomocy języka weight=\"bold\" color=\"black\"> XML. Opis dla naszej opcji About przedstawia się nastę- OK"); pująco: if(ai.battery_percentage>=25 && ai.battery_ percentage<=50) sprintf(&txt[0], " weight=\"bold\" color=\"blue\"> "); _label="_About..." if(ai.battery_percentage<25) pixtype="stock" pixname="gnome-stock-about"/> sprintf(&txt[0], " weight=\"bold\" color=\"red\"> UWAGA!!! Baterie\n bliskie rozładowania!!!"); W atrybucie verb musimy podać taką samą wartość jak we gtk_label_set_justify (GTK_LABEL(mesg), wcześniej zadeklarowanej tablicy. Rejestrację tego menu GTK_JUSTIFY_CENTER); dokonuje funkcja panel_applet_setup_menu. W drugim gtk_label_set_markup(GTK_LABEL(mesg), argumencie przekazujemy zmienną xml_dsc typu gchar* , &txt[0]); } zawierającą opis w XML-u, a w trzecim nazwę zmiennej } zawierającej tabelę z elementami menu. Wywołanie funk- else { cji jest następujące: gtk_label_set_text(GTK_LABEL(label), "Brak dostępu do APM!!!"); panel_applet_setup_menu(PANEL_APPLET(applet), } } xml_dsc, battery_menu_verbs, applet); Istnieje także możliwość zdefiniowania menu w pliku. Funkcja wywołana w wyniku odpowiedzi na ten sygnał Na płycie CD znajduje się plik xml, który definiuje takie wyrejestruje obsługę odświeżania oraz dodatkowo menu. Rejestrację menu opisanego w pliku wykonuje się wygeneruje sygnał dzwiękowy. Treść tej funkcji jest przy pomocy funkcji panel_applet_setup_menu_from_file, bardzo krótka: podając w jednym z argumentów nazwę pliku. Sam plik definiujący menu o nazwie GNOME_BatteryApplet.xml void destroy_monitor(GtkWidget *w, gpointer d) { należy umieścić np. w katalogu /usr/share/gnome-2.0/ui. gtk_timeout_remove(timer); Zawartość funkcji about_win nie będzie tu przytaczana, gdk_beep(); ponieważ tworzy ona tylko okno (funkcja gnome_about_ } new), wykorzystując dostępny w GNOME widget okna infor- macyjnego. www.linux.com.pl 63 dla programistów Zobacz w: Funkcja update_status Dzięki cyklicznym wywołaniom tej funkcji nasz aplet dobrze pełni swoją rolę, bowiem pozwala na czujne śledzenie stanu naładowania baterii (działający aplet można zobaczyć na Rysunku 4). Jak postanowiliśmy wcześniej, ta funkcja jest wywoływana raz na sekundę. Jej działanie polega tylko na odczytaniu stanu APM oraz uaktualnieniu wartości etykiet. Ponieważ GNOME oferuje formatowanie tekstu przy pomocy znaczników, to wykorzystamy tę możliwość, aby wytłuścić etykietę i nadać jej kolor czerwony, gdy stan baterii jest bardzo niski, niebieski, gdy stan będzie średni, bądz czarny, gdy stopień naładowania baterii jest wysoki. Pełny kod tej funkcji zawiera Listing 6. Odczytanie parametrów z pliku /etc/apm realizuje funkcja apm_read, pochodząca z pliku apmlib.c. Następ- nie, w zależności od stanu poszczególnych pól, ustalane są komunikaty w etykie- tach. Jedna z etykiet pokazuje komunikat w zależności od stopnia naładowania baterii zmieniając także kolor. Do ustalenia odpowiedniego koloru trzeba zastoso- wać znacznik span. Dla niskiego stanu, czyli dla stanu naładowania baterii poniżej 25%, przygotowanie ciągu formatującego wygląda następująco: sprintf(&txt[0], " UWAGA!!! Baterie\n bliskie rozładowania!!!"); W ciągu formatującym możemy stosować również sekwencje ESCAPE, np. \n, która poprawnie zostanie zinterpretowana. W znaczniku zastosowaliśmy atrybuty weight oraz color. Tak przygotowany komunikat wyświetlamy na ekranie stosując funkcję gtk_label_set_markup zamiast gtk_label_set_text. W kodzie używamy funkcji gtk_label_set_justify, aby wyśrodkować tekst w etykiecie. Instalacja apletu Po przygotowaniu kodu zródłowego apletu, możemy przystąpić do kompilacji, którą dokonujemy następującym poleceniem: S gcc -o battery-applet-2 battery_app.c apmlib.c `pkg-config --cflags --libs libgnomeui-2.0 libgnome-2.0 libpanelapplet-2.0` Po udanej kompilacji plik binarny kopiujemy do katalogu, który został wyszcze- gólniony w pliku server. Natomiast sam plik server, czyli GNOME_BatteryAp- plet.server do katalogu /usr/lib/bonobo/servers. Katalog docelowy także może zostać zmieniony. Wymaga to już niestety modyfikacji plików konfiguracyjnych podsystemu bonobo-activation. Konfiguracja jest zapisana w pliku o nieco długiej ścieżce: /usr/etc/bonobo-activation/bonobo-activation-config.xml. Po uruchomieniu środowiska GNOME, aplet powinien być dostępny z menu apletów wywoływanych prawym przyciskiem myszy nad dowolnym panelem. Podsumowanie Tworzenie apletów w GNOME nie wymaga specjalnych zabiegów poza przygotowa- niem dodatkowych plików oraz użyciu makra zamiast funkcji main (makro można pominąć i napisać stosowny kod samodzielnie). Pozostałą część apletu pisze się w taki sam sposób, jak zwykłą aplikację GNOME czy GTK+. Ponadto, nasz aplet, cho- ciaż napisany dla wersji 2.4, powinien bez kłopotów pracować także w wersji 2.2. W Sieci: " Główna strona GNOME: http://www.gnome.org/ " Strona przeznaczona dla programistów piszących w GNOME: http://developer.gnome.org/ 64 luty 2004