Applet til Gnome-panel

Tags:    c++
Skrevet af Bruger #285 @ 14.05.2007
Af: Mikkel Meyer Andersen

Introduktion


Denne artikel vil indeholde en guide til, hvordan man laver sin egen applet til Gnome-panelet (herfra vil det blot blive kaldt applet, men der menes hver gang at det er til et Gnome-panel) i C. Det er forventet, at du kender lidt basal *nix, ved hvad en applet er og samtidig kan en smule XML og C. Hvis du føler dig usikker på om du kan, så læs endelig videre, men hvis de opremsede begreber er som sort magi for dig, er det nok ikke den rigtige artikel at starte med. Som sidebemærkning kan jeg dog hurtigt nævne, at en applet er en lille program, man kan tilføje panelet i Gnome - som f.eks. uret.

Jeg kører selv Debian GNU/Linux, og det er på dette, jeg har testet koden - jeg har ikke prøvet på andre platforme, men der skulle ikke være noget problem på andre *nix'er. Der vil blive brugt et rigtigt eksempel for at lette forståelsen, og gøre det hele lidt mere klart og håndgribeligt. Kort sagt går eksemplet ud på, at jeg ønsker at kunne se tiden i andre tidszoner end min egen i mit panel. Dette eksempel er godt, da det både indeholder lidt parsing af XML i form af konfigurationsfilen (hvilken tidszone og formatet på tiden)

Hello World


Før vi går i gang med selve eksemplet, vil jeg dog lige vise, hvordan man laver en "Hello World"-applet. Det er hovedsageligt taget fra [1], men jeg har alligevel valgt at medtage det her, da jeg synes der mangler et par småting, og for samtidig at holde det på dansk for dem, der har det bedst med det. Derudover skaber det en mere sammenhængende artikel.

Appletter er ikke enkeltstående programmer, og rent teknisk er det noget, der hedder Bonobo kontroller. Det skal du dog ikke spekulere mere over, men du vil støde på navnet Bonobo et par gange (bl.a. i diverse fillokationer).

Som nævnt er appletter ikke enkeltstående programmer, men skal køre i et andet miljø - her er det i Bonobo. For at det kan det, skal Bonobo bruge nogle oplysninger om det, man ønsker at køre for at kunne kalde det ordentligt osv. Det er ene detaljer, du heller ikke skal bekymre dig så meget om - det eneste du skal er at lave en lille fil med bl.a. sti til programmet, navn, beskrivelse osv. Når du først har lavet den en gang, skal der sjældent rettes så meget i den. Et eksempel på en sådan - såkaldt .server-fil - er denne:
Fold kodeboks ind/udKode 


Læg mærke til følgende ting:
- stien til den applet, vi koder (/home/mikl/coding/applets/helloworld)
- stien til det ikon, der skal benyttes i "Add to panel"-funktionen på Gnome-panelet (/home/mikl/coding/applets/someicon.png) - hvis du ikke angiver en sti, bliver der søgt efter filen i /usr/share/pixmaps/
- at man kan angive forskellige navne og beskrivelser (name-da, name-en_GB osv.)

Du kan nu kalde denne fil HelloWorldApplet.server (eller hvad du ellers ønsker, det skal blot ende på ".server"). Læg denne fil i biblioteket /usr/lib/bonobo/servers/ (højst sandsynligt vha. sudo).

Derudover er der ikke så meget andet end nogle teknikaliteter, som indtil videre er fine nok til små, simple appletter. Bemærk dog, at her har jeg sat navnet til det samme alle stederne (fordi jeg er doven), så jeg kunne lige så blot have haft opgivet name og ikke de sprogspecifikke. Jeg har dog valgt at medtage det for at vise, at det er muligt både ved navn (name) og beskrivelse (description).

Så nu har vi altså "de kedelige ting" på plads - lad os se noget kode!

Fold kodeboks ind/udKode 


Læg mærke til følgende ting:
- overensstemmelsen mellem iid'erne i vores .server-fil og i C-koden!
- det er "ligemeget" hvad vi kalder vores "main" (som ikke er main, men blot en funktion med en bestemt prototype, nemlig static gboolean function_name(PanelApplet*, const gchar*, gpointer)), da vi i "PANEL_APPLET_BONOBO_FACTORY" specificerer den funktion, der skal kaldes
- vi benytter GTK i stor stil - dette er en rar iagttagelse, for dette skal vi senere benytte i det praktiske eksempel
- vi benytter appletten som en gtk-container - det er ikke så vigtigt
- vi includer dels panel-applet.h, der giver os nogle ting til appletten, og dels gtk/gtklabel.h så vi kan skrive noget tekst på appletten

Filen skal naturligvis kompileres, og "resultatet" skal hedde "helloworld" og ligge i biblioteket /home/mikl/coding/applets/ jf. vores specifikation i .server-filen. Antag du har gemt overstående kode i filen helloworld.c, så foregår kompileringen således:
gcc $(pkg-config --cflags --libs libpanelapplet-2.0) -o helloworld helloworld.c

Som du kan se, skal du bruge visse development-pakker. Så hvis du får fejl, så vær sikker på, du har dem installeret. Du kan derudover også prøve at køre følgende for at se, om den melder fejl:
pkg-config --cflags --libs libpanelapplet-2.0

Din bruger hedder næppe mikl, så du skal nok vælge noget andet i .server-filen. Normalt plejer man ligeledes ikke at lægge appletter i hjemmebiblioteker, men under udviklingen er det ret behændigt, da det letter mange ting (ikke mindst rettighedsproblematikker).

Nu burde du kunne tilføje appletten til dit panel uden problemer.

Debugging


Og nu til et forholdsvist stort problem - eller udfordring om man vil. Debugging. For du kan måske ikke tilføje appletten uden fejl. Og du kan uden tvivl ikke fremover. Der er altså fejl i det kode, du laver, og det skal rettes gennem en debugging proces. Nogle bruger gdb, andre bruger stadig printf-debugging - uanset hvad, er det stadig svært at debugge. Man kan godt tilføje appletten gennem kommandoer, men mine erfaringer er stadig, at det bliver lidt noget skrammel (for nu at sige det rent ud). Det, der virker bedst for mig (men ikke nødvendigvis for dig), er at jeg splitter koden tilpas meget op, og laver både en konsolversion og en applet-version. Det betyder, at koden der adskiller de to er interfacet, og dermed kan logikken i programmet være fælles. Det gør, at man ved at debugge consolapplikationen (hvilket i mine øjne er langt nemmere), finder mange af fejlene i logikken, og dermed måske dem, der får appletten til at crashe. Så er der udelukkende den smule kode tilbage, der benyttes til at skabe selve appletten tilbage. Det kan stadig være en stor mundfuld, men indtil videre synes jeg den omtalte metode virker fint for mig, og især i disse appletter uden meget interface.

Dette leder videre, da jeg i denne artikel ikke beskæftiger mig med ret meget brugerinterface - der er hverken kontekstmenuer eller lignende på appletten, udelukkende en enkelt label, der kan vise lidt. Det er helt med vilje, da dette dels er en begynderartikel, og dels synes jeg ikke at GUIs er så sjove at lege med; jeg foretrækker de nedre lag, så at sige. Det var blot en sidebemærkning, for det er naturligvis muligt at lave mouse-events, kontekstmenuer osv., hvilket [1] hurtigt viser.

Case-study


Okay, nu er introduktionen overstået, så lad os komme i gang med at kæde lidt flere ting sammen. Grunden til jeg egentlig gik i gang med at lave en applet, var fordi jeg manglede noget (sådan er det jo tit). Jeg må nok også hellere nævne, at det kun er en uge siden jeg begyndte på det her appletprogrammering, så jeg er ikke så rutineret endnu, hvilket jeg ikke håber artiklen bærer alt for meget præg af. Problemet var, at jeg gerne ville kunne se tidspunktet i en anden tidszone i mit panel, men der var ingen eksisterende applet, der kunne det. Jeg fandt dog efter lidt søgen frem til, at man kunne gøre det således:
TZ=America/Los_Angeles date +"Klokken i LA er %R"
Kommandoen gør det, at den først midlertidigt i det efterfølgende kald sætter miljøvariablen TZ til en zone, der er at finde i /usr/share/zoneinfo/zone.tab, og derefter kalder den altså kommandoen date i dette nye miljø. Efter eksekveringen genetableres det oprindelige miljø, og TZ er således ved sin oprindelige værdi før kaldet. Det er altså kun et nyt midlertidigt miljø, man kreerer på denne måde.

Dette kan implementeres i C vha. putenv-funktionen. Man kan også få og formattere tiden med time-, localtime- og strftime-funktionerne. Med disse er det muligt at lave en statisk applet, der viser en fastindkodet tid i en anden tidszone i det øjeblik appletten loades. Nu går tiden jo også i den anden tidszone, hvilket stiller et krav om en timer således vores applet kan blive opdateret løbende med den nye tid. Jeg vil dog også gerne kunne ændre både tidszonen og formatteringen mens appletten kører - dvs. uden at skulle genindlæse appletten, og især uden at skulle renkompilere den. Dette sætter et krav om en konfigurationsfil (jeg har valgt at lave den i XML, hvilket igen kræver noget XML-parsing med libxml2). Det følgende er faktisk min første applet, men jeg synes eksemplet var godt, da det netop skal kombinere nogle ting. Jeg kører faktisk selv med den nu. Jeg har valgt at forklare alle aspekterne, og ikke blot de appletspecifikke elementer. Det er jo ret rart at kunne parse en XML-fil også, så det tager vi med. Det er heller ikke noget, jeg har gjort så meget i C (læs: aldrig), så det er også første gang. Jeg håber nu alligevel det kan bruges, for det er nu meget rart at kunne lave sin egen applet, hvis man pludselig står og mangler noget.

Som tidligere nævnt har jeg fundet frem til, at jeg deler interfacet op i to: en applet og en konsol. Nu da jeg har afsløret, at jeg er nybegynder indenfor det her, så er det meget muligt, at der er meget bedre måder, så hvis der er det, må I endelig sige til! Det fjerner dog ikke den realitet, at denne opsplitning betyder at man er tvunget til at modularisere sin applikation, hvilket er godt! Så på den måde, har metoden om ikke andet retfærdiggjort sig selv.

Projektet har jeg valgt at kalde Freed Clok (eller Befriet Ur, om man vil), og består af følgende filer (husk at du nu både har brug for udviklingsfiler til panels og til libxml2!):
~/.freed-clock (konfigurationsfil)
Freed-Clock-Applet.server
common.h
common.c
freed-clock-applet.c
freed-clock-console.c

Først kommer alt koden til filerne, og derefter kommer jeg med kommentarer til filerne individuelt.

~/.freed-clock ser således ud:
Fold kodeboks ind/udKode 


Freed-Clock-Applet.server ser således ud:
Fold kodeboks ind/udKode 


common.h ser således ud:
Fold kodeboks ind/udKode 


common.c ser således ud:
Fold kodeboks ind/udKode 


freed-clock-applet.c ser således ud:
Fold kodeboks ind/udKode 


freed-clock-console.c ser således ud:
Fold kodeboks ind/udKode 


Og så til kommentarerne.

~/.freed-clock:
Time-zone findes som sagt i /usr/share/zoneinfo/zone.tab (sudo)
Formatet er fastlåst da der i parsningen er brugt en XPath og der bliver søgt efter bestemte elementnavne.

Freed-Clock-Applet.server:
Der er vist ikke så meget anderledes over denne end den, du så i starten.

common.h:
Her defineres nogle stanardværdier, hvis der er problemer med at hente dem fra konfigurationsfilen.

common.c:
Alt logikken er heri. Der er nogle kommentarer i koden, som burde hjælpe lidt. Der er dog et par indforståede ting, som kan være svære at ræsonnere sig frem til. Eksempelvis bliver opdateringsintervallet kun indlæst i starten, og det er således ikke muligt at ændre dette interval mens appletten kører. Det betyder, at hvis du har valgt at intervallet er et minut og har valgt et format med sekunder, så ændres sekundtantallet kun hvert minut - også selvom konfigurationsfilen ændres således den burde opdatere hvert minut. Grunden til det er, at GTK benyttes til at styre denne timer, og hvis man skulle ændre den, ville det kræve noget mere kode, som ville fjerne fokus fra det det egentlige, så derfor har jeg lavet det således. Hvis du er i tvivl om nogle af funktionerne, så søg på nettet - der er rigelig dokumentation tilgængeligt.

freed-clock-applet.c:
Der er nu to funktioner: én til der skal køres ved hver opdatering og så den, der skal startes op sammen med appletten.

freed-clock-console.c
Ele(g/f)ant!

Alt i alt giver det en applet, hvor du, mens den kører, kan ændre både tidszone og formattering, og dette vil så blive benyttet næste gang opdateringen sker (hvert minut eller hvert sekund afhængigt af konfigurationen, da du loadede appletten).

Husk nu at få styr på alle navne, filplaceringer osv. osv., da dette kan give anledning til mange, mange fejl.

Appletten kompileres med følgende (libxml2 skal med denne gang):
Fold kodeboks ind/udKode 


Og tilsvarende for konsollen:
Fold kodeboks ind/udKode 


Kom meget gerne med kommentarer, rettelser, gode forslag osv.

Kilder:
[1]: http://www.gnome.org/projects/ORBit2/appletstutorial.html

Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (1)

User
Bruger #10895 @ 10.07.07 20:14
den er der nogenlune :)
Du skal være logget ind for at skrive en kommentar.
t