X Windows alapismeretek

Budapesti Műszaki Egyetem Elektronikus Eszközök Tanszék

1999.

Tartalom

Előszó ii

1 Bevezetés 1

2 Az X Window System 2

2.1 X koncepciók . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.1.1 Az X protokoll . . . . . . . . . . . . . . . . . . . . . . 5 2.1.2 Erőforrások . . . . . . . . . . . . . . . . . . . . . . . . 6 2.1.3 A szerver–kliens modell . . . . . . . . . . . . . . . . . 6 2.1.4 Ablakkezelés . . . . . . . . . . . . . . . . . . . . . . . 8 2.1.5 Eseménykezelés . . . . . . . . . . . . . . . . . . . . . . 9 2.1.6 Objektum orientált programozási stílus . . . . . . . . 10

2.2 Xlib függvénycsomag . . . . . . . . . . . . . . . . . . . . . . . 10 2.3 Xt Toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.4 XView Toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.4.1 OPENLOOK grafikus felhasználói felület . . . . . . . 13

3 Az XView Toolkit 14 3.1 A vezérlés szervezése . . . . . . . . . . . . . . . . . . . . . . . 14 3.2 XView eseménykezelés . . . . . . . . . . . . . . . . . . . . . . 17 3.3 XView függvények . . . . . . . . . . . . . . . . . . . . . . . . 20 3.4 Objektumosztályok hierarchiája . . . . . . . . . . . . . . . . . 24 3.5 Objektumok típusai . . . . . . . . . . . . . . . . . . . . . . . 24

3.5.1 Frame . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.5.2 Panel . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.5.3 Canvas . . . . . . . . . . . . . . . . . . . . . . . . . . 28 3.5.4 Notice . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

3.6 Programfejlesztés az XView Toolkittel . . . . . . . . . . . . . 31 3.7 Egy teljes példaprogram . . . . . . . . . . . . . . . . . . . . . 33

4 Az X grafika 35 4.1 Színek használata . . . . . . . . . . . . . . . . . . . . . . . . . 36 4.2 A GC adatstruktúra . . . . . . . . . . . . . . . . . . . . . . . 39 4.3 Rajzoló alapfüggvények . . . . . . . . . . . . . . . . . . . . . 41 4.4 Image-ek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

Irodalomjegyzék 47

Előszó

Jelen füzet a BME Elektronikus Eszközök Tanszékének tapasztalatait öszszegzi SUN munkaállomásokon történt X programfejlesztések kapcsán. Leírásunk alapjául szolgáló X környezet a UNIX alatt futó OpenWindows 2.0 verziója.

E füzet összeállításakor arra törekedtünk, hogy benne minél többet viszszaadjunk abból, amit az X Window System^{1} működéséről, programozásáról megismertünk. A leírtakat megpróbáltuk minél gyakrabban példákkal is illusztrálni, így téve szemléletesebbé, könnyebben érthetővé. Ezek a példák általában csak rövid programrészletek, önállóan nem futtathatók, csak az adott probléma szempontjából fontos részekre koncentrálnak. A példaprogramok C nyelven íródtak, ennek megfelelően feltételezzük az olvasótól a C nyelv alapfokú ismeretét. Nem szükséges azonban profi C programozónak lennie, mivel a példaprogramok egyszerűek, főleg az X függvények és adatstruktúrák használatát hivatottak szemléltetni. Az X Windows-ról jelenleg elérhető irodalom nagyrészt angol nyelvű. Ezért a bizonyos angol kifejezésekre, a megfelelő magyar fordítás helyett az angol eredetit használjuk. Sok angol szó átkerült már a magyar nyelvbe, ezeknél az angol szót magyarul leírva használjuk (pl. kurzor). Más szavaknál az eredeti írásmódot is megtartottuk, viszont ilyen esetekben általában más betűtípust használunk (pl. toolkit). Az olyan szavaknál, ahol a magyar fordítás jelentése nem fedi pontosan az angol szó jelentését, az első előfordulásnál megadjuk az angol szót is. Leírásunkban használunk olyan rövidítéseket is, amelyek széles körben elterjedtek. Ezek első előfordulásánál is megadjuk a teljes kifejezést.

Alkalmaztunk bizonyos formai konvenciókat is. Az X függvények neveit, X attribútumokat ’typewriter’ betűtípussal írtuk, mint például ezt: XV WIDTH. Az először előforduló fontos fogalmakat pedig vastag betű használatával emeltük ki. Ez segít, hogy az olvasó később visszalapozva gyorsabban megtalálja egy-egy fogalom jelentését.

Laírásunk a következő fejezetekre tagolódik:

Az 1. röviden ismerteti, mi is az X Window System.

A 2. fejezet az X felépítésének, működésének alapjait írja le. Részletezi az X összetevőit, tulajdonságait.

A 3. fejezet az XView Toolkit használatát, felépítését mondja el.

A 4. fejezet arról ír, miképpen használható grafika az X programokban. Mivel az X toolkitek általában nem tartalmaznak megfelelő rutinokat a grafika használatához, ezért az ilyen jellegű programozáshoz szükség van alacsonyabb szintű grafikai függvények használatára. Ez a fejezet a grafika használatához szükséges magasabb szintű és alacsonyabb szintű eszközöket is ismerteti.

1X ablakkezelő rendszer, a továbbiakban általában csak X-ként vagy X Windows-ként hivatkozunk rá.

1 Bevezetés

Az X gyors elterjedését magyarázza, hogy a tervezőinek sikerült egy olyan rendszert kialakítani, ami nem tesz megkötéseket az alapul szolgáló számítógépre, a grafikus kártyára, a gépeket összekötő hálózatra, és nem köti meg az alkalmazott user interface stílust sem. Ezáltal készíthető X Windows implementáció a legkülönfélébb géptípusokra, a PC kategóriától a nagyszámítógépekig. Az X tervezői a hagyományos függvényhívásos, illetve kernelhívásos felületet felváltották egy hálózati protokollal. Mivel pedig ez a protokoll kötött, ezért az egy hálózatra kapcsolódó különböző típusú számítógépek különböző X megvalósításai tudnak egymással kommunikálni, lehetővé téve, hogy az egyik gépen futó program a másik gépről kapja inputját, és ott jelenítse meg outputját. A hálózati összeköttetés lehetősége nagymértékben növeli az X használhatóságát anélkül, hogy jelentősen befolyásolná a teljesítőképességét.

Az ablakkezelő rendszerek egyik nagy előnye a hagyományos felületekkel szemben, hogy lehetővé teszik párhuzamosan futó alkalmazások számára a képernyő egyidejű használatát. Az X képes változtatható méretű ablakok egész hierarchiáját kezelni, és egy alkalmazás is létrehozhat egyidejűleg több ablakot. Az ablakok átfedhetik egymást, és egy program outputja mehet egy éppen nem látható ablakba is.

Az X-ről rövid összefoglalóként ajánljuk [1]-et. Ennek két szerzője vezette azt a csoportot, amelyik az X-et kifejlesztette. Mivel az X-nek újabb verziói is megjelentek azóta, hogy ez a cikk íródott, a benne található információ nem felel meg mindenben a mai helyzetnek, de azért kellő áttekintést ad az alapkoncepciókról.

2 Az X Window System

Az X Windows fejlesztőinek számos követelményt kellett kielégíteniük a fejlesztés során. Ezek közül a fontosabbak:

• A rendszer bittérképes kijelzőkre készüljön.

• Támogassa grafika használatát.

• A képernyőn a program inputja és outputja számára közös területek legyenek: az ablakok.

• A felhasználói felület egy ún. pointer deviceon (mutató eszközön) alapuljon^{2}.

• A pointer device vezérelje a billentyűzet input ablakokhoz való hozzárendelését is.

• Több program legyen képes egyidejűleg ugyanarra a kijelzőre dolgozni.

• A rendszer hálózati protokollon alapuljon.

• A protokoll implementálható legyen különböző számítógép architektúrák és operációs rendszerekre: legyen eszközfüggetlen.

• Legyen lehetőség egy programot egyik gépen futtatni, miközben egy másik gép kijelzőjét használja.

Ezen követelmények kielégítése tette az X-et olyan népszerűvé, hogy mára majdnem minden munkaállomás gyártó szabványként kezeli az ablakkezelő rendszerek közt. Az alapkoncepciókról szól a 2.1 alfejezet.

Az X egy többrétegű struktúra szerint épül fel. Ez látható az 1. ábrán. Az X egyes rétegei adott szintű programozói interface-t definiálnak, de nem tesznek megkötéseket a réteget megvalósító kódra. Az X protokollról a 2.1.1, az X szerverről pedig a 2.1.3 alfejezetben lesz szó.

A legalsó réteg, az Xlib egy C nyelvű programozói felületet biztosít az X magját képező hálózati protokollhoz^{3}. Ez a réteg alacsonyszintű X programozási lehetőségeket biztosít. Az Xlib réteg az X rendszerben exkluzív

2A gyakorlatban ez az eszköz majdnem mindig egy egér.

3Az X protokollhoz több nyelven is létezik programozói interface. Ezek közül a legelterjedtebb az Xlib, mivel a C széles körben hozzáférhető.

[figure: X Szerver; X Protokoll; Xlib; Xt Intrinsics; Widget Set; XView Toolkit; (AT&T és Sun); X Alkalmazás]

1. ábra. Az X Windows felépítése

szabvány. Ez azt jelenti, hogy aki X implementációt készít, az köteles biztosítani az Xlib réteget, és helyette nem biztosíthat más C nyelvű interface-t az X protokollhoz. Erről a rétegről lesz szó a 2.2 alfejezetben.

Az Xlib rutinokra épülve magasabb szintű programozói felületeket találunk, az ún. toolkiteket. Ezek olyan rétegek, amelyek egy bizonyos User Interface^{4} (UI) stílus megvalósítására készültek. A toolkitek biztosítanak a programozónak előregyártott UI építőelemeket és valamilyen függvénycsomagot, aminek segítségével az építőelemekből egy teljes UI építhető objektum orientált programozási technikák használatával. Egy építőelemet hívnak widgetnek.

A toolkitek között van egy kiemelkedő fontosságú, az Xt Toolkit. Ez két részből áll, az Xt Intrinsics-ből és egy tetszőleges widget setből (építőelem készlet). E két rész közül az első, az Xt Intrinsics az X rendszerben nem-exkluzív szabvány, azaz aki X implementációt készít, az köteles elkészíteni ezt a programozói felületet is, de emellett biztosíthat más toolkitet is. A második összetevő, a widget set az alkalmazott UI stílustól függően változhat. Az Xt Toolkitről a 2.3 alfejezetben lesz szó.

4Felhasználói felület.

Egy másik toolkit az XView. Ez funkcionálisan az Xt Intrinsics és az OPENLOOK UI stílust megvalósító widget set megfelelője, az általa biztosított programozói felület azonban eltér az Xt Intrinsics felületétől. Erről a rétegről rövid áttekintést nyújt a 2.4 alfejezet.

Az X programok épülhetnek csupán az Xlib-re, vagy használhatják valamelyik toolkitet is. Az Xlib működésének megértése a második esetben is hasznos, mivel a toolkitek is az Xlib-en alapulnak. A toolkitek használata mindenképpen ajánlott, mivel jelentősen megkönnyíti a programozást. Ezekben beépítve található a kód, ami a Window Managerrel^{5} való kommunikációt elvégzi, és ezzel rengeteg fáradságot takarítanak meg a programozónak. A toolkitek használatának hátránya, hogy a futtatható programkód nagyobb terjedelmű lesz, mint egy ugyanolyan funkciókat megvalósító, Xlib szinten megírt program kódja. Ez a különbség azonban nem túl nagy programoknál elhanyagolható. (Nagy programokat pedig csak jelentős többlet munkával lehetne Xlib szinten megírni.)

Egy másik hátránya a toolkit szintű programozásnak, hogy be kell tartani bizonyos objektum orientált programozási (OOP) konvenciókat egy nem OOP nyelvben. Ennek megtanulása időbe telhet. A toolkitek használatának egy további hátrányáról a 2.3 alfejezetben írunk.

2.1 X koncepciók

Az X Windows tervezésekor rengeteg szempontot kellett figyelembe venni. Ezek közül a legfontosabbak:

1. Az X-et bittérképes terminálokhoz tervezték. Arra törekedtek, hogy az X használata biztosítsa a programok teljes függetlenségét a grafikus környezettől és az operációs rendszertől.

2. Fontos tervezési szempont volt az is, hogy az X lehetővé tegye különböző típusú gépek azonos hálózaton történő együttműködését. Erre a célra alkották meg a hálózati protokollt, ami képes az ablakkezelő rendszert vezérelni.

5Lásd 2.1.4 fejezet.

3. Az X fejlesztői nem akarták a létrehozandó rendszert egyféle UI stílushoz kötni. Ehelyett olyan programozói felület kialakítására törekedtek, amivel tetszőleges felhasználói felület megvalósítható.

A hordozhatóságnak az X-ben kétféle értelmezése lehet. Az egyik a forrásprogram hordozhatósága, amit 1 és bizonyos mértékig 3 bitosít. A hordozhatóság másik jelentése a hálózat átlátszósága, ami 2-ből következik.

A következő néhány alfejezetben az X alapkoncepciókról lesz szó.

2.1.1 Az X protokoll

Az X Windows magja, az X protokoll teszi lehetővé, hogy az X hálózatokon is tudjon futni. Ez határozza meg, hogy milyen részekből épül fel a szerver^{6} és az Xlib közt átvitt információcsomag. A protokollt az X akkor is használja, ha a szerver és az Xlib ugyanazon a gépen fut.

A protokoll négyféle csomagtípust különböztet meg:

• Kérelem (request): Az Xlib küldi a szervernek. Nagyon sokféle információt tartalmazhat, pl. egy ablak átméretezését, egy egyenes rajzolásának adatait, stb. A legtöbb Xlib függvényhívás protokoll kérelmet eredményez.

• Válasz (reply): A szerver küldi az Xlib-nek bizonyos kérelmeket követően. Az alkalmazásokban lehetőleg minimalizálni kell az olyan kérelmek számát, amik válaszra várnak, mert ez erősen csökkentheti a program hatásfokát.

• Esemény (event): A szerver küldi az Xlib-nek, információt tartalmaz valamilyen eszközről, vagy valamilyen megelőző kérelem mellékhatásáról. Az Xlib-nél az események egy pufferben gyűlnek fel, arra várva, hogy a program kiolvassa őket.

• Hiba (error): A szerver jelzi az alkalmazásnak, hogy valamelyik megelőző kérelem hibás volt. Ezek az üzenetek az eseményekhez hasonlóan lekezelhetők. Ha a program nem törődik velük, akkor a beépített hibakezelő kiír egy hibaüzenetet, és a program futása befejeződik.

A hálózaton való futtathatóság által biztosított előnyök mellett a hálózati protokoll használatának hátrányai is lehetnek. Egyik ezek közül, hogy a program veszíthet a sebességéből a gyakori hálózati adatforgalom miatt. Ezen a problémán az X tervezői úgy próbáltak segíteni, hogy bevezették a kérelmek pufferelését. Az Xlib a kérelmeket csokorba gyűjti és együtt küldi el a szervernek. Így a hálózat kihasználtságának hatásfoka nőhet. Az Xlib a csokorba gyűjtött kérelmeket három esetben küldi el a szervernek:

6Lásd 2.1.3 fejezet.

• Ha a program egy olyan eseményre vár, amilyen nincs az Xlib eseménypufferében.

• Ha olyan Xlib hívás történik, ami válaszra vár.

• Néha a program maga akarja elküldeni a kérelmeket, ha nem várható esemény vagy adatkérelem. Ilyenkor az XFlush, vagy az XSync függvények használhatók. Ez az eset a gyakorlatban ritkán használt. Egyik jelentős alkalmazása lehet, amikor nyomkövetés (debugging) során a pufferelés zavaró hatását akarja a programozó megszüntetni.

2.1.2 Erőforrások

Az X számos módszerrel csökkenti a hálózat terhelését. Ezek egyike volt az előbb látott pufferelés. Egy másik módszer, hogy a komplex adatstruktúrákat (ablakokat, betűkészleteket, stb.) a szerver kezeli, és a program csak azonosítókkal hivatkozik rájuk. Ezáltal valahányszor a program valamilyen műveletet végez egy objektumon, a hálózaton egy komplex adatstruktúra helyett csak egy azonosító megy át. Ezeket az adatstruktúrákat hívják erőforrásnak.

Hátránya viszont ennek a megoldásnak, hogy ha a program az erőforrásról információt kér, akkor azt a hálózaton kell átküldeni, nem lehet helyi adatstruktúrából megszerezni.

Valójában az X terminológia egy másik dolgot is erőforrásnak nevez, az alkalmazás által létrehozott ablak jellemzőit. Szerencsére ez a két fogalom általában az X teljesen eltérő részeinél merül fel, így nehéz összekeverni őket.

2.1.3 A szerver–kliens modell

Az X szóhasználatában különbség van a display és a screen szavak közt. A számítógépes nyelvben általában mindkét szó a képernyőre utal, az X-ben viszont csak a screen szó hordozza ezt a jelentést. A display X-es jelentését én inkább kijelzőnek fordíthatnánk, ami alatt egy billentyűzetből, egérből és egy vagy több képernyőből (screenből) álló munkaállomást kell érteni.

Xlib X Toolkit X Application

X11 Server Device drivers Screen Mouse Keyboard

Window Manager

[figure] [figure] [figure]

2. ábra. A szerver–kliens modell

Több képernyő (screen) mindaddig egyetlen kijelzőt (display-t) alkot, amíg egy felhasználó egy billentyűzettel és egérrel használja őket.

Az X hálózaton alapuló ablakkezelő rendszer: egy program nem kell, hogy ugyanazon a gépen fusson, mint amelyik gép kijelzőjét használja. A kijelzőt felügyelő programot hívják szervernek, ez a program választja el az eszközfüggő kódot a felhasználói programtól (kliens vagy alkalmazás). A hálózatokat ismerők furcsának találhatják, hogy egy lokális gépen futó programot szervernek hívhatnak, de ha figyelembe vesszük, hogy a lokális gép kijelzője is egy olyan erőforrás, ami bármely más gép számára elérhető, akkor érthetővé válik az analógia a már ismert file-, list-, mail-, és printerszerverekkel. A szerver és a kliens kapcsolatát mutatja a 2. ábra.

A szerver a közvetítő a felhasználói programok, és a lokális gép erőforrásai között. A szerver a következő feladatokat látja el:

• Lehetővé teszi több program számára egy kijelző használatát.

• Értelemezi a hálózati üzeneteket a kliensek számára.

• A felhasználótól érkező inputot a hálózaton át továbbítja a kliensek-

nek.

• Két dimenziós rajzolást végez.

• Komplex adatstruktúrákat (ablakokat, kurzorokat, stb.) mint erőforrásokat kezel, amelyeket megosztva használhat több alkalmazás is. Ezekre az adatstruktúrákra a programok azonosítókkal hivatkoznak. Ez a technika jelentősen csökkentheti a hálózaton átküldendő adatmennyiséget.

A gyakorlatban a rendszert általában úgy használják, hogy minden felhasználó egy szervernél ül, és programokat indíthat akár lokálisan, amikor is az eredmény a helyi kijelzőn jelenik meg, vagy egy távoli gépen, az eredményt átirányítva a helyi gépre.

A lehetőségek kihasználásának egy szélsőséges példája, amikor a felhasználó egy olyan PC előtt ül, amin csak az X szerver fut, és távoli gépeken futó programok eredménye jelenik meg a képernyőn. Ilyenkor a PC úgy néz ki, és úgy is viselkedik, mint egy multitaszkos munkaállomás.

2.1.4 Ablakkezelés

Minden futó X-ben egy kiemelt jelentőségű program a window manager. Ez is egy X program, hasonlóan épül fel, mint bármelyik másik X alkalmazás, de ez a program speciális jogokkal rendelkezik. Ez a program kezeli a képernyőn megjelenő összes ablakot. Ez határozza meg a helyüket létrehozáskor, ez teszi lehetővé, hogy a felhasználó tetszőleges ablakot átméretezzen, ikonizáljon, egyéb paramétereiket állítsa.

A különböző X megvalósítások window managerei jelentősen eltérhetnek egymástól. Például egyik jellemző tulajdonságuk, hogy miképpen rendelik hozzá a billentyűzetinputot az ablakokhoz. Erre kétféle módszer terjedt el:

• Egér követő (follow mouse vagy real-estate-driven): A billentyűzetről érkező karaktereket mindig az az ablak kapja meg, amelyik felett a kurzor van.

• Kiválasztásos (listener vagy click-to-type): A billentyűzet ahhoz az ablakhoz van rendelve, amelyik utoljára ki lett választva az egérrel. Ez az interface stílus ismerős lehet az Apple Macintosh felhasználóknak.

Az OPENLOOK window manager mindkét módszert ismeri, a felhasználó választhatja ki a neki jobban megfelelőt.

Az X alkalmazásokat úgy kell megírni, hogy tetszőleges window managerrel együtt tudjanak működni. Csak úgy biztosított a program hordozhatósága, ha nem függ a window manager által alkalmazott UI stílustól.

2.1.5 Eseménykezelés

Az események az X filozófia nagyon fontos részét képezik, ezért nélkülözhetetlen a megértésük. Az egér mozgatása, vagy egy billentyű leütése input eseményt vált ki. Ezek a legegyszerűbb és leggyakrabban előforduló események, amelyekkel találkozhatunk. Általánosságban egy esemény egy olyan információcsomag, amit a szerver küld a programnak bizonyos történések bekövetkezésekor.

Az események egy részét a felhasználói input adja. Ezek főleg az egérrel és a billentyűzettel kapcsolatosak.

Egy másik csoport az ablakkezelő műveletek mellékhatásaként generálódik. Erre például említhetjük azt az esetet, amikor egy előzőleg elfedett ablak láthatóvá válik, ami egy Expose eseményt vált ki.

Az események harmadik csoportja a különböző alkalmazások közti kommunikáció eredménye. Így például egy A ablak értesülhet róla, ha egy B ablak kéri, hogy az egér pozíciójától és a kiválasztástól függetlenül minden billentyűzet-inputot ő, a B ablak kapjon meg.

A felhasználói program minden egyes ablakhoz megadhatja, hogy az adott ablak milyen eseményei érdeklik őt. Ennek módja Xlib és toolkit szinten különböző. Hasonlóan eltér az események kezelésének módja is a különböző szinteken. Annyit el lehet mondani általánosságban, hogy minden X program tartalmaz egy eseményciklust (event loop). Általában ez a programok központi része, innen ágazik szét a vezérlés a különböző eseményeket kezelő részekre. Xlib szintű programokban az eseményciklus általában egy olyan végtelen ciklus, ami egy switch utasítással ágazik szét a beolvasott eseménytől függően. A toolkiteket használó programokban az eseményciklus egy függvényhívással érhető el, ami az előzőleg beállított ún. callback függvényeket hívja meg a megfelelő esemény bekövetkezésekor.

Az eseménykezelés szükségessége jelentősen eltérő programozási módszereket kíván, mint amit egy hagyományos, UNIX vagy DOS alatti program készítésekor alkalmazunk. Az X programok nem használják a hagyományos billentyűzet olvasó funkciókat, és nem várakoznak a felhasználói inputra. Ehelyett állandóan késznek kell lenniük arra, hogy bármilyen eseményre válaszoljanak. A különböző típusú események tetszőleges időben és sorrendben jelentkezhetnek.

2.1.6 Objektum orientált programozási stílus

A widget setek felépítése és használata nagyon sok objektum orientált vonást mutat. Mivel azonban a C nyelv nem támogatja az objektum orientált programozási stílust, ezért a programozó felelősége, hogy betartsa a szabályokat. Ezekről lesz szó a következőkben.

A widget set objektumosztályokat definiál, amikből a widgetek létrehozásakor keletkeznek objektumok. Az objektumok két részből állnak:

• Adat: az objektum adatai az őt leíró attribútumok értékei. Ezek lehetnek nyilvános és privát attribútumok. A privát attribútumokat a programozó nem állíthatja.

• Kód: Függvények az objektumokon belül az adatok kezelésére. Erre példa lehet minden widgethez egy olyan függvény, ami az adott widget megsemmisítéséhez szükséges műveleteket elvégzi.

Az X toolkitek további objektum orientált jellemzőkkel rendelkeznek. Ezeket sorolom fel a következőkben.

Üzenetek (messages): Az objektumok közti kommunikáció eszköze. Ide tartoznak az események, a toolkit függvényhívások, a callback rutinok.

Beágyazottság (encapsulation): A widgeteknek definiált a viselkedésük (programozói felület), de a belső megvalósítás rejtve marad a programozó elől.

Alosztályok (subclassing): A widget set hierarchikusan épül fel. Egy osztály objektumai mind rendelkeznek az osztály attribútumaival.

Öröklődés (inheritance): Minden osztály örökli a szülőosztály attribútumait.

2.2 Xlib függvénycsomag

A toolkit szintű programozáshoz nem szükséges az Xlib-et ismerni, de hasznos lehet, mivel a toolkitek is az Xlib-en alapulnak, sőt szükséges is lehet, ha a program grafikát használ.

Az Xlib függvénycsomag az X protokollhoz nyújt C nyelvű programozói interface-t. Ennek megfelelően az Xlib függvények nagy része egy protokoll hívássá fordul. Az Xlib szintű programozás előnye, hogy a kód gyorsabb, tömörebb, hátránya viszont, hogy hasonlóan az alacsony szintű programnyelvekhez, az Xlib programok fejlesztése több időt és energiát igényel.

Az Xlib függvénycsomag széleskörű lehetőségeket biztosít az ablakok, az események, a képernyő használatához. Nem segíti elő viszont egy adott UI stílus megvalósítását. Az Xlib által nyújtott eszközök ennél alacsonyabb szintűek, a UI-t Xlib-ben a legalapvetőbb elemekből kell felépíteni, külön megrajzolva minden egyes részletet. Ezért is ajánlott a toolkitek használata.

Az Xlib függvényekkel leírásunkban részletesen nem foglalkozunk, de a grafika kapcsán a 4. fejezetben találhatók az általános Xlib függvényekre is érvényes információk.

2.3 Xt Toolkit

Az Xt Toolkit talán a legszélesebb körben használt X toolkit. Ebben nagy szerepe van annak, hogy ez része az X szabványnak, azaz minden X megvalósításban megtalálható.

Az Xt Intrinsics réteg egy olyan függvénycsomagot tartalmaz, ami a widget set által biztosított UI építőelem objektumok kezelésére szolgál. A függvénycsomag teljesen független az építőelemkészlettől, és így az alkalmazott UI stílustól is.

A widget set olyan objektumokat tartalmaz, amelyekből felépíthető egy felhasználói felület. Ezek határozzák meg az alkalmazott UI stílust. Néhány létező widget set:

Athena Ezt a widget setet az MIT fejlesztette ki demonstrációs célokra. Nem nyújt annyi lehetőséget, mint a kereskedelemben elérhető elemkészletek.

MOTIF Az OSF (Open Software Foundation) fejlesztése, széles körben elterjedt.

OPENLOOK Az AT&T és a Sun Microsystems fejlesztette ki, ennek megfelelően az általunk használt munkaállomásokon is ez a widget set volt megtalálható.

Az Xt Toolkitet használó X programok jellegzetes struktúrával rendelkeznek. Egy ilyen program általános felépítését írjuk le a következőkben.

  1. Az <X11/Intrinsic.h> és az <X11/StringDefs.h> beolvasása. Ezt

a két include file-t minden program köteles beolvasni.

2. A használt widgetekhez tartozó nyilvános include file-ok beolvasása. Ezeknek a file-oknak a neve megegyezik a widget osztály nevével. Például az <Xol/StaticText.h> file-t be kell olvasni minden programnak, amelyik használja a StaticText osztályt.

3. A Toolkit inicializálása az XtAppInitialize vagy az XtVaAppInitialize függvényhívással.

4. Widgetek létrehozása az XtCreateManagedWidget függvény hívásával.

5. Eseménykezelő rutinok bejegyzése.

6. Widgetek felélesztése: XtRealizeWidget.

7. Eseményciklus kezdése: XtAppMainLoop.

Pl. SUN-OS környezetben a /usr/openwin/include alkönyvtár tartalmazza az include file-okat. Ezen belül az X11 alkönyvtárban vannak az Xlib include file-ok, az Xol alkönyvtárban pedig az OPENLOOK widget set include file-ai.

Összehasonlítva a MOTIF és az OPENLOOK widget seteket, nagyon sok hasonló funkciójú widgetet találunk. Viszont ezek a különböző készletekben általában eltérő néven szerepelnek, sőt van olyan objektumnév, ami a két készletben két különböző funkciójú objektumot takar.

Az Xt függvények UI stílustól való függetlensége nagy előny olyan szempontból, hogy ahogy idővel a felhasználói ízlést követve változnak a UI stílusok, az X szabványt nem kell megváltoztatni. Azt viszont, hogy a widget setek nem rendelkeznek rögzített programozói interface-szel, a forrásprogram hordozhatóság elvesztését jelenti. Így ugyanis csak a tisztán Xlib szintű függvényeket használó programokat lehet egy másik környezetben változtatás nélkül lefordítani és futtatni. Az ilyen programokkal viszont az a probléma, hogy egyrészt nagy alkalmazások megvalósítása nagyon nagy munkába telik, másrészt egy ilyen program nem fog illeszkedni minden rendszerben az ott használt UI stílushoz.

2.4 XView Toolkit

Az XView Toolkit egy alternatívája az Xt Toolkitnek, amit az AT&T és a Sun Microsystems cégek fejlesztettek ki. Az XView-t eredetileg azért fejlesztették ki, hogy létező SunView alkalmazásokat X alá át lehessen vinni. A SunView ablakkezelő rendszer az X kifejlesztése előtt is létezett, és sok alkalmazás futott alatta. Az XView megalkotásával lehetővé vált, hogy a SunView-t kiszorító X szabvány szerinti ablakkezelő rendszerekre át lehessen vinni a már létező és elterjedt SunView programokat. Az Xview azonban támogatja új programok írását is. Ehhez számos eszközt biztosítanak. Segítik például az XView és az Xlib együttes használatát, függvényeket biztosítanak az Xlib lehetőségeinek kihasználására XView-ból.

Az XView Toolkitről részletesen írunk a 3. fejezetben.

2.4.1 OPENLOOK grafikus felhasználói felület

Az XView Toolkit az OPENLOOK grafikus User Interface (UI) stílust valósítja meg. Ez a UI egy egyszerű, konzisztens és hatásos felületet próbál biztosítani a felhasználónak. Az OPENLOOK fejlesztői az AT&T és a Sun Microsystems, akik ezt a stílust szabványosították a UNIX System V. Release 4. grafikus felhasználói felületének. Az OPENLOOK használatával a programozó a program fejlesztésének funkcionális részeire koncentrálhat és nem kell egy UI megvalósításával vesződnie.

Egy jól megtervezett UI elég általános ahhoz, hogy tetszőleges operációs rendszerhez, ablakkezelő rendszerhez vagy grafikus kijelzőhöz illeszthető legyen. Mivel az OPENLOOK megvalósítását nem korlátozza a fentiek egyike sem, ezért az XView is olyan specifikációkon alapszik, amelyeket könnyedén át lehetett tenni X Windows alá.

Az OPENLOOK vizuális tervezése egy egyszerű, de kényelmes, esztétikus környezetet teremtett. A felület tervezésekor néhány egyszerű alapelv betartására törekedtek, ami egy könnyen megtanulható és kezelhető UI-t eredményezett.

Programozói oldalról az OPENLOOK widget set olyan eszközkészletet biztosít, amelyben nagyon sokféle input és output funkció megvalósítására beépített elemet találhatunk. Válogathatunk a legkülönfélébb adatbeviteli eszközök közt, a pop-up, pull-down, pull-right menük közt.

Az eszközök megjelenése, viselkedése nagy mértékben konfigurálható a felhasználó által. Például választani lehet, hogy az ablak melyik oldalán legyen a scrollbar, állítani lehet a színeket, megcserélhetők az egér gombjaihoz rendelt funkciók.

3 Az XView Toolkit

Az XView név az X Window-System-based Visual/Integrated Environment for Workstations (X ablakkezelő rendszerre alapuló vizuális/integrált környezet munkaállomásokra) kifejezés rövidítéseként keletkezett. Az XView olyan UI építőelemeket tartalmaz, amelyek támogatják interaktív, grafikára alapuló alkalmazások fejlesztését X Windows alá. Az építőelemek megjelenése és viselkedése az OPENLOOK grafikus UI specifikációnak felel meg.

Az eseményvezérelt programozás egészen más programstruktúra kialakítását igényli, mint a hagyományos módszerek. Az XView-ban használt vezérlési szerkezetekről számol be a 3.1 alfejezet. Az XView eseménykezelés módját írja le a 3.2 rész.

Az XView egyik jellemzője, hogy nagyon kevés függvény használatával lehet programokat írni. Ez abból adódik, hogy ez a toolkit is rendelkezik bizonyos objektum orientált programozási vonásokkal. Ezért például ugyanaz a függvény alkalmazható az összes objektum létrehozására, paraméterként megadva az objektum típusát. A legfontosabb függvények leírása a 3.3 alfejezetben található.

A kevés függvényt nagyon sokféle objektumosztály egészíti ki, amikből változatos UI-k építhetők fel. Az objektumok jellemzőit az objektumhoz tartozó attribútumok értékének állításával lehet magváltoztatni. Egy objektum létrehozásakor fel lehet sorolni, hogy az objektum mely attribútumát hogyan kívánjuk beállítani. Az attribútumoknak általában van valamilyen (jól megválasztott) default értéke, ezért elég azokat állítani, amik eltérnek ettől. Az attribútumok állíthatók az objektum létrehozásakor, vagy később, egy másik függvényt használva. Az objektumokról, attribútumaikról a 3.4 és a 3.5 alfejezetekben lesz szó.

A 3.6 részben a toolkit használatához szükséges általános információk kaptak helyet. Itt írunkk egy XView program lefordításának, nyomkövetésének módjáról, a program általános felépítéséről, és hasonló, máshonnan kiszorult részekről.

A fejezet végén egy teljes példaprogramot közlünk, ami demonstrálja az XView objektumok használatát.

3.1 A vezérlés szervezése

Az eseményvezéreltség egészen más programozási technikákat igényel az XView-ban, mint a hagyományos programírás. Ennek oka, hogy az eseményvezérelt program nem várakozhat felhasználói inputra, ehelyett átadja Vége

[figure]

[figure]

[figure]

[figure]

Kilépés ?

Input feldolgozása Input olvasása Start

nem igen

3. ábra. Hagyományos program vezérlése

a vezérlést az ún. Notifiernek, ami aztán értesíti őt, ha esemény történik.

Egy hagyományos program struktúrája látható a 3. ábrán. Példaként nézzünk egy szövegszerkesztőt. A program billentyűolvasásra várakozik az ideje nagy részében. Ha a felhasználó ír valamit, akkor ezt a program feldolgozza, és az eredménytől függően kilép, vagy újra billentyűre vár.

Az eseményvezérelt megoldás a 4. ábra szerint működik. A Notifier érzékeli az eseményeket, és azokat elosztja a megfelelő ablakokhoz tartozó callback rutinok közt. Ha valamelyik függvény kilépést kért, akkor a Notifier visszaadja a vezérlést az alkalmazásnak.

A szövegszerkesztőnk a kezdeti beállítások elvégzése után átadja a vezérlést a Notifiernek. Ezután minden billentyűnyomás után a megfelelő callback rutin feldolgozza az inputot, majd visszatér a Notifierhez. Ez a struktúra lehetőséget teremt arra, hogy a felhasználó szerkesztés közben például átméretezze az ablakokat, vagy magára hagyhassa a szövegszerkesztőt és más programra térjen át.

Fontos tudni, hogy ha egy callback rutin törzse új objektumot hoz létre, vagy megsemmisít egy létező objektumot, semmi nem fog történni a képernyőn mindaddig, amíg a rutin vissza nem adja a vezérlést a Notifiernek.

Ez a tulajdonság az X-et kimondottan kényelmetlenné teszi, ha a programunk hosszabb számolásokat, adatfeldolgozást végez. Ugyanis ha eközben a program a felhasználóval is kapcsolatot akar tartani, akkor kénytelen időről Visszatérés az alkalmazáshoz igen

[figure] [figure] [figure] [figure]

Kért a callback rutin

kilépést ?

A megfelelő callback rutin

hívása Input olvasása

nem Esemény feldolgozása Vége Notifier hívása Beállítások Start Alkalmazás

Notifier

4. ábra. Eseményeken alapuló program vezérlése időre meghívni a Notifiert, ami esetenként elég csúnya programstruktúrát eredményez. Az XView Toolkit az olyan programokat “szereti”, amelyek interaktívak, azaz gyakran várakoznak a felhasználó parancsaira.

Ha mégis olyan programot akarunk X alatt implementálni, ami hosszabb ideig magánál tartja a vezérlést, akkor speciális függvényeket kell használnunk. Ugyanis nincs arra lehetőség, hogy egy callback rutinban maradva végezze a program az időigényes tevékenységét, és közben az eseményeket is kezelje. Az ilyen probléma megoldásának helyes módja a következő:

A callback rutinban a program kiad egy notify stop() függvényhívást és visszatér. Ennek hatására a Notifier visszadja a vezérlést az alkalmazásnak, ami elkezdheti a kívánt tevékenységet. Annak érdekében, hogy a felhasználóval való kapcsolattartás ne szűnjön meg, és a képernyőre is írni lehessen, a programnak időnként meg kell hívnia a Notifiert. Ez a notify dispatch() függvénnyel megy, ami egyetlen eseménykezelő ciklust hajt végre és visszatér.

Léteznek még az XView-ban más módszerek is az eseményciklus megvalósítására, ezekre itt nem térünk ki, megtalálhatók [2]-ban és [3]-ben.

A gyakorlatban egy ilyen struktúra megvalósításánál törekedni kell arra, hogy legalább másodpercenként végezzen a program eseménykezelést, mert egyébként a felhasználó érzékelheti, hogy a program nem válaszol azonnal az ő tevékenységére.

3.2 XView eseménykezelés

Az esemény egy olyan adatstruktúra, amit a szerver küld az alkalmazásank, és valami olyasmiről hordoz információt, ami éppen most történt, és ami érdekli az alkalmazást. A program első fázisában, a beállítási fázisban a programozó létrehozhat objektumokat, és meghatározhatja, hogy ezek hogyan fognak együttműködni az alkalmazással. Ezután a program belép az eseményciklusba, és innentől kezdve a Notifier veszi át a vezérlést. A program csak azokról az eseményekről fog értesülni, amelyeket a Notifiernek a beállítási fázisban megadott. Az alkalmazás a feladatát az eseményekre való válaszai által hajtja végre.

Az ablakkezelő rendszer határozza meg, hogy egy eseményt melyik ablak kap meg. Ha egy ablak az adott eseményt nem kívánja kezelni, választhat, hogy eldobja az eseményt, vagy továbbadja az alatta fekvő ablaknak, ami általában a szülője.

Az XView-ban minden ablakhoz rendelhetünk egy callback rutint, és megadhatunk egy maszkot, ami definiálja azokat az eseményeket, amelyek hatására, az adott callback rutin megkapja a vezérlést.

Az általános eseménykezelő rutin megadásakor a WIN EVENT PROC attribútumhoz kell rendelni a callback rutint. Az ezt kiváltó események maszkját a WIN CONSUME EVENTS attribútum után kell felsorolni, egy NULL-al lezárva.

Vannak bizonyos események, amelyek speciális eseménykezelő rutint igényelnek. Erre a leggyakoribb példa az ablakok újrafestését végző függvény. Ennek megadásához az objektum egyedi attribútumát kell használni.

A következő programrészletben példát mutatunk az általános, és az újrafestő callback rutinra is.

void my_repaint_proc(canvas, paint_win, area)
Canvas canvas;
Xv_Window paint_win;
Rectlist *area;
{
/* Rajzolás ...  */
}
void my_event_proc(window, event)
Xv_Window window;
Event *event;
{
    switch(event_action(event)) {
        case ACTION_SELECT:
        case MS_LEFT:
            if (event_is_down(event))
                break;
/* Baloldali gomb fel lett engedve ...  */
            break;
        default:
            break;
    }
}
main()
{

/* Inicializálások, deklarációk ...  */
    canvas = (Canvas)xv_create(frame, CANVAS,
        CANVAS_REPAINT_PROC,         my_repaint_proc,
        CANVAS_PAINTWINDOW_ATTRS,
            WIN_EVENT_PROC,          my_event_proc,
            WIN_CONSUME_EVENTS,
                WIN_MOUSE_BUTTONS, NULL,
            NULL,
        NULL);
/* Eseményciklus ...  */
}

A programrészlet a létrehozott canvas-hoz^{7} beállítja a repaint proc-ot, ami akkor hívódik meg, ha a canvas-t újra kell festeni. Beállít egy eseménykezelő callback rutint is, ami az egér billentyűk állapotának változásakor aktivizálódik. Az eseményeket kezelő rutinban látható az ilyan callback függvények váza.

Az XView események kezelésére számos makró van definiálva. Ezek a paraméterként kapott eseményből bizonyos információrészleteket szűrnek ki. A összes ilyen makró leírását semelyik irodalom sem közli, az egyetlen hely, ahol megtaláltók felsorolva, az xview/win input.h include file. Ezek közül most az általunk legfontosabbnak ítéltek következnek:

event action() : Az XView esemény azonosítójával tér vissza.

event x() : A kurzor X pozíciója az esemény bekövetkeztekor.

event y() : A kurzor Y pozíciója az esemény bekövetkeztekor.

event time() : Az esemény időpecsétjét adja vissza.

event window() : Az eseménnyel kapcsolatos ablak azonosítóját adja viszsza.

event is up() : Visszaadja, hogy az esemény egy felfelé történő átmenet volt-e.

event is down() : Visszaadja, hogy az esemény egy lefelé történő átmenet volt-e. event shift is down() : Visszaadja, hogy a Shift billentyű le volt-e nyom-

7Lásd 3.5.3 fejezt.

va az esemény bekövetkeztekor.

event ctrl is down() : Visszaadja, hogy a Control billentyű le volt-e nyomva az esemény bekövetkeztekor.

3.3 XView függvények

Az Xview nagyon kevés függvényt és nagyon sok attribútumot használ. A függvények egy része változó paraméterszámmal hívható, ilyenkor a programozó felelősége, hogy megfelelő hosszú paraméterlistát használjon. A függvények két csoportba oszthatók:

• Általános célú függvények: tetszőleges típusú objektumok kezelésére használhatók.

• Speciális függvények: egy-egy objektum jellemzőinek állítására, lekérdezésére használhatók.

Ez a fejezet az első csoportba tartozó függvényekkel foglalkozik. A második csoport függvényeiről a 3.5 alfejezetben a megfelelő objektumnál írok.

xv init() : Ez a függvény három dolgot végez el:

• Megteremti a kapcsolatot a szerverrel.

• Inicializálja a Notifiert.

• Inicializálja az erőforrásokat.

A függvény hívásának két formája lehetséges:

       • xv init(XV INIT ARGC PTR ARGV, &argc, argv, NULL)

Ebben a formájában a függvény a program parancssor argumentumaiból kiszűri az XView-nak szólókat, és ezeknek megfelelően állítja az erőforrásokat. A felhasznált argumentumokat eltávolítja az argv tömbből, és argc értékét is ennek megfelelően csökkenti.

       • xv init(XV INIT ARGS, argc, argv, NULL)

Ez a függvényhívás értelmezi a program parancssor argumentumaiból az XView-nak szólókat, de nem változtatja meg a paraméterlistát.

A függvényt a programnak minden más XView függvényhívást megelőzően kell meghívnia. Ha ezt nem teszi, akkor az első XView függvényhíváskor automatikusan elvégződik az inicializálás, de ilyenkor a parancssor argumentumok figyelmen kívül hagyódnak. Az első hívás után minden további hívás hatástalan marad.

main(argc, argv)
int        argc;
char       *argv[];
{
/* inicializálások, deklarációk ...  */
    (void)xv_init(XV_INIT_ARGS, argc, argv, NULL);
    frame = xv_create(NULL, FRAME, NULL);
}

xv create() : Létrehoz egy objektumot.

A függvény deklarációja:

Xv opaque xv create(owner, package, attrs)
Xv object owner;
Xv pkg package;
<attribútum-érték lista> attrs;

owner A létrehozandó objektum tulajdonosa. Ha NULL-t adunk meg, a default tulajdonos használódik.

package A létrehozandó objektum osztálya.

attrs Egy attribútum-érték lista. A végén NULL-al van lezárva.

A függvény visszatérési értéke az újonnan létrehozott objektum azonosítója.

    frame = xv_create(NULL, FRAME,
        XV_WIDTH,        200,
        XV_HEIGHT,       150,
        FRAME_LABEL,     "Sample Frame",
        NULL);

xv find() : Megkeresi a specifikációknak megfelelő objektumot, és annak az azonosítóját adja vissza. Ha nem talál ilyen objektumot, létrehoz egyet.

A függvény deklarációja analóg az xv create() deklarációjával.

xv destroy() vagy

xv destroy safe() : Megsemmisít egy objektumot, és minden ablakot, aminek ez volt a tulajdonosa. A második alak előbb meggyőződik róla, hogy ez biztonságos-e. (callback rutin belsejében az eseményt kiváltó objektumot csak a második alakkal szabad megsemmisíteni.)

A függvények deklarációja:

int xv destroy(object)
Xv object object;
int xv destroy safe(object)
Xv object object;

object: A megsemmisítendő objektum azonosítója.

A függvények visszatérési értéke XV ERROR vagy XV OK.

    ercode = xv_destroy_safe(frame);

xv set() : Egy tetszőleges objektum attribútumainak értékét állítja.

A függvény deklarációja:

Xv opaque xv set(object, attrs)
Xv object object;
<attribútum-érték lista> attrs;

object Az objektum, amelyikhez tartozó attribútumokat állítani szeretnénk.

attrs Mint xv create-nél.

A függvény visszatérési értéke XV OK, ha sikeres volt az állítás, egyébként egy hibakód, ami arra az attribútumra utal, amelyikkel kapcsolatban a hiba felmerült.

    ercode = xv_set(frame,
        FRAME_SHOW_FOOTER,   TRUE,
        NULL);

xv get() : Egy tetszőleges objektum egy attribútumának értékét kérdezi le.

A függvény deklarációja:

Xv opaque xv get(object, attrs)
Xv object object;
Attr attribute attr;

object Az objektum, amelyiknek egy attribútumát lekérdezni szeret-

nénk. attr Az attribútum, amire kíváncsiak vagyunk. Ezen a helyen előfor-

dulhat több attribútum is, néhány kivételes esetben.

A függvény az attribútum értékével tér vissza ha sikeres volt az állítás, egyébként nullával. Ebből következik, hogy nem detektálható a hiba, ha a nulla érvényes értéke az attribútumnak.

    label = (char *)xv_get(frame, FRAME_LEFT_FOOTER);
    value = (int)xv_get(button,
                     XV_KEY_DATA, MY_BUTTON_VALUE);

A második példa egy olyan attribútum lekérdezését mutatja, ami két értéket vesz fel. Az első érték, amelyiket lekérdezéskor is meg kell adni, a programozó által megadott azonosító, a második pedig az ehhez rendelt érték. Ezzel a módszerrel a programozó az objektumokhoz hozzárendelhet bizonyos értékeket, amit később le tud kérdezni.

xv main loop() : Ez a függvényhívás elindítja a Notifiert. A program által korábban létrehozott objektumok valójában ekkor jönnek létre, és ettől kezdve kap a program eseményeket. Ez a függvény mindaddig nem lép ki, amíg valamelyik callback rutin egy notify stop() függvényhívást nem végez, vagy ki nem lép. A függvény paramétere egy objektum, általában a base frame^{8}.

8Lásd 3.5.1 fejezet.

3.4 Objektumosztályok hierarchiája

Az XView sokféle ablakot tartalmaz, ezek közül a fontosabbak:

• Frame: Ez az alap ablak, ami más ablakokat tartalmazhat.

• Canvas: Ezekre lehet a programból rajzolni. (Festővászon.)

• Text subwin: Beépített szövegszerkesztői funkciókat tartalmaz.

• Panel: Erre lehet olyan elemeket felhelyezni, mint gombok, menük, stb.

Az objektumok megjelenésének, viselkedésének állítására szolgálnak az attribútumok. Ezekből három különböző típusú létezik:

• Általános (generic): Ezek az attribútumok minden XView objektumra vonatkoznak. A nevük XV -vel kezdődik.

• Közös (common): Sok, de nem az összes objektumra vonatkoznak.

• Egyedi (specific): Csak egy bizonyos objektumosztályokra vonatkozó attribútumok. A nevük általában az osztály nevével kezdődik, például MENU . A csak ablakokra vonatkozó attribútumok a WIN előtaggal kezdődnek.

Az attribútumok állítására lehetőség van az objektum létrehozásakor az xv create függvénnyel, vagy később, az xv set függvénnyel. Az attribútumok lekérdezésére szolgál az xv get függvény. A legtöbb attribútum értéke állítható és le is kérdezhető. Vannak azonban olyanok, amelyek csak állíthatók (pl. SERVER IMAGE BITS), illetve csak lekérdezhetők (pl. WIN FRAME).

Az összes XView objektumosztály hierarchiája látható az 5. ábrán. A hierarchiában alacsonyabban levő objektumok öröklik az őseik attribútumait. Az ábrán található Generic Object, Drawable és Openwin objektumokhoz nem tartozik funkció, csak az öröklődési logika fenntartását szolgálják.

3.5 Objektumok típusai

Az XView objektumok kezelésekor használt attribútumok legnagyobb része általános, minden objektumra érvényes hatású. Ezek közül sorolom fel itt a legfontosabbakat.

Panel Canvas Text (Openwin)

Tty

Frame Scrollbar

Icon Window Server image (Drawable)

Cursor Screen Server

Fullscreen Font Menu

Generic Object

5. ábra. Az XView osztályok hierarchiája XV X : Egy objektum x koordinátáját adja meg, relatívan a szülő objektum-

hoz.

XV Y : Egy objektum y koordinátáját adja meg, relatívan a szülő objektumhoz.

XV WIDTH : Az objektum szélessége pixelekben.

XV HEIGHT : Az objektum magassága pixelekben.

XV SHOW : Azt állítja vagy adja vissza, hogy az objektum látható-e.

A következő néhány alfejezetben a leggyakrabban használt objektumtípusokról írunk. Leírjuk az adott objektum funkcióját, jellemzőit, fontosabb attribútumait. Általában megpróbáljuk példákkal is szemléltetni a használatukat. Az ikon (icon), kurzor (cursor) és image (Server image) objektumokról majd csak a 4. fejezetben, a grafika keretén belül esik szó.

3.5.1 Frame

A frame a XView programok egyik legfontosabb objektuma. A frame-ek fő funkciója más ablakok tárolása, felügyelete. Két típusuk létezik, a base frame és a command frame. Az elsőből legalább egyet minden programnak tartalmaznia kell, erre építheti fel az ablakokat és egyéb objektumokat. A második típus rövid ideig létező objektumok megjelenítését szolgálja. Az OPENLOOK megvalósításban a command frame egy rajzszöggel (push-pin) van “feltűzve” a háttérre, ennek kihúzásakor általában eltűnik.

A programozáskor fontos tudni, hogy a command frame létrehozásakor az XV SHOW argumentum értéke FALSE és hogy a frame-hez automatikusan létrejön egy hozzá tartozó panel is. A framek néhány speciális attribútuma:

FRAME ICON : A frame-hez tartozó ikont adja meg.

FRAME CLOSED : Azt adja meg, hogy a frame ikonizált állapotban van-e.

FRAME BUSY : Ha TRUE, akkor a frame fejléce beszürkül, és a kurzor átvált egy óraalakra.

FRAME LABEL : A frame fejlécébe kerülő szöveg.

FRAME CMD PANEL : A command frame default panele.

FRAME CMD PUSHPIN IN : A command frame rajzszögének állapotát állítja, kérdezi le.

FRAME DONE PROC : A command frame megsemmisítésekor meghívott callback rutin.

    frame = (Frame)xv_create(NULL, FRAME,
        FRAME_LABEL,      "Sample Frame",
        NULL);
    popup = (Frame)xv_create(frame, FRAME_CMD,
        FRAME_DONE_PROC,  done_proc,
        NULL);

3.5.2 Panel

A panel az XView vezérlési funkciókat megvalósító ablaka. Ezen lehet létrehozni nyomógombokat, menüket, stb. A panel legfontosabb attribútuma:

PANEL LAYOUT : A panelre felvitt objektumok elhelyezésének sorrendjét adja

     meg. Értéke lehet PANEL HORIZONTAL vagy PANEL VERTICAL.

A panelekre elhelyezhető objektumok közül a gyakran használtak a következők:

button : Software nyomógomb, felirat vagy image lehet rajta, megnyomása eseményt vált ki.

menu : Menü, több fajtája létezik. Közös bennük, hogy lehetőséget biztosítanak több tétel közüli választásra.

Létezik egy gyakran hasznos makró a panelekhez, ami az összes panelre felhelyezett objektum azonosítóját adja vissza. Az első paramétere bemenő, a panel azonosítója, a másodikban pedig visszaadja egyenként az objektumok azonosítóit. Ennek használatára látható példa a következőkben:

    Panel panel;
    Panel_item item;
    PANEL_EACH_ITEM(panel, item)
        xv_set(item, PANEL_INACTIVE, TRUE, NULL);
    PANEL_END_EACH

A programrészlet egy panel összes objektumát inaktívvá teszi.

3.5.3 Canvas

A canvas az az ablaktípus, ami a legalkalmasabb grafika megjelenítésére és események fogadására. Amikor egy canvas-ról beszélünk, akkor igazából három objektumot értünk alatta:

Canvas subwindow : Ez az ablak az, ami a frame leszármazottja, és ez tartalmaz egy vagy több view window-t. Ez tulajdonképpen egy keret, ami lehetővé teszi, hogy egy objektumként hivatkozhassunk a canvasra.

View window : Ezt az ablakot úgy kell elképzelni, mint egy átlátszó keretet, amin keresztül látható a paint window egy része. Ilyenből egy canvas egyidejűleg többet is tartalmazhat, és ilyenkor egyszerre több részlete látható a rajznak.

Paint window : Ebbe az ablakba kerül a grafika, és ide érkeznek az események. Ezt az objektumot egy nagy festővászonként lehet elképzelni, amire tetszés szerint festhetünk, de a képernyőn csak azok a részei fognak látszani, amelyek felett van egy view window.

Nagyon fontos, hogy a rajzolórutinok használatánál, az események kiválasztásánál, kurzor hozzárendelésénél és a callback rutin megadásánál ne a canvas-t, hanem a paint window-t használjuk! A paint window azonosítóját a canvas paint window(canvas) függvényhívással kaphatjuk meg.

A paint window paramétereinek beállítására rendelkezésre áll egy attribútum. Ez a CANVAS PAINTWINDOW ATTRS, ami után attribútum-érték párokkal lehet megadni a paint window attribútumait, a végén egy NULL-al lezárva.

A következőkben néhány fontos canvas attribútumot részletezünk.

CANVAS WIDTH és

CANVAS HEIGHT : A paint window méreteit állítják. A canvas subwindow mérteinek állítására az XV WIDTH és XV HEIGHT attribútumokat kell használni.

CANVAS REPAINT PROC : A paint window újrafestését végző callback rutin. A canvas-hoz kell rendelni.

CANVAS X PAINT WINDOW : Amikor az értéke TRUE, további paramétereket ad az újrafestést végző függvény hívásához. Ez különösen akkor hasznos, ha az újrafestés során Xlib szintű grafikát használ a program, mert a hozzáadott paraméterek ezt könnyítik meg. A kétféle újrafestő rutin fejléce:

Ha a fenti attribútum értéke TRUE:

void repaint_proc(canvas, paint_win, area)
Canvas canvas;
Xv_Window paint_win;
Rectlist *area;

Ha pedig az attribútum értéke FALSE:

void repaint_proc(canvas, paint_win, dpy, xwin, xrects)
Canvas canvas;
Xv_Window paint_win;
Display *dpy;
Window xwin;
Xv_xrectlist *xrects;

A canvas-okkal gyakran együtt használnak egy másik objektumot, a scrollbart. Ez lehetővé teszi, hogy a paint window-t a view window alatt elmozgassuk, és láthassuk minden részét. Enélkül a paint window nem lehetne nagyobb méretű, mint a view window. A scrollbart létrehozásakor tudjuk a canvas-hoz rendelni azzal, hogy szülő objektumként a canvas-t tüntetjük fel.

A scrollbar egyik legfontosabb attribútuma a SCROLLBAR DIRECTION, ami a fekvését határozza meg. Ez két értéket vehet fel:

SCROLLBAR HORIZONTAL
SCROLLBAR VERTICAL

A következő programrészlet egy canvas létrehozását mutatja be néhány attribútum állításával, és két scrollbar hozzáadásával.

canvas = (Canvas)xv_create(frame, CANVAS,
   XV_WIDTH,             100,
   XV_HEIGHT,            100,
   CANVAS_WIDTH,         200,

        CANVAS_HEIGHT,        200,
        CANVAS_REPAINT_PROC,  my_repaint,
        CANVAS_PAINTWINDOW_ATTRS,
            WIN_EVENT_PROC,   my_event,
            WIN_CONSUME_EVENTS,
                WIN_MOUSE_BUTTONS, LOC_MOVE, NULL,
            NULL,
        NULL);
    xv_create(canvas, SCROLLBAR,
        SCROLLBAR_DIRECTION,  SCROLLBAR_HORIZONTAL,
        NULL);
    xv_create(canvas, SCROLLBAR,
        SCROLLBAR_DIRECTION,  SCROLLBAR_VERTICAL,
        NULL);

3.5.4 Notice

A notice egy speciális XView objektum, abban az értelemben, hogy teljesen eltérő módon kell kezelni, mint az egyéb objektumokat. A notice-t nem lehet létrehozni az xv create függvénnyel, és az xv get és xv set sem alkalmazható rá. Ez az objektum az egyetlen nem téglalap alakú XView ablak. Erre az sem igaz, hogy csak a Notifierhez való visszatérés után jön létre. A programban bármikor létrehozható, és a program addig áll, amíg a notice meg nem semmisült, azaz a felhasználó meg nem nyomja a notice valamelyik nyomógombját. A notice a Fullscreen osztályba tartozik, ezért megjelenésekor a képernyő összes eseményét ő kapja. Emiatt ilyenkor a felhasználó nem tehet mást, mint hogy válaszol a notice-ra.

A fenti tulajdonságokból következik, hogy a notice objektum ideális hibaüzenetek megjelenítésére, és egyéb azonnal megválaszolandó kérdések feltevésére.

A notice létrehozása a notice prompt függvénnyel lehetséges. Erre mutat példát a következő programrészlet.

    notice_prompt(frame, NULL,
        NOTICE_MESSAGE_STRINGS,    "Invalid position.",
                                   NULL,
        NOTICE_BUTTON,             "OK",
        NULL);

3.6 Programfejlesztés az XView Toolkittel

Egy általános XView program a következőképpen épül fel:

• Az XView inicializálása egy xv init() függvényhívással.

• Egy legfelső szintű ablak (frame) létrehozása.

• Ablakok létrehozása a frame-re.

• Objektumok létrehozása az ablakokra.

• Callback rutinok megadása és az input események kiválasztása.

• A Notifier hívása.

Az első lépés elhagyása nem okoz hibát, de az X elveket sérti (a felhasználónak joga van a program bizonyos jellemzőit parancssorból állítani, amit az xv init() hívása biztosít).

Az XView programok kötelesek beolvasni (#include directívával) az xview/xview.h file-t. Ezenkívül be kell olvasniuk minden felhasznált objektumosztályhoz tartozó include file-t. Például ha egy program használ canvas-t, akkor szerepeljen benne a következő sor:

#include <xview/canvas.h>

Az XView programok fordítása UNIX operációs rendszeren a következő módon történik, feltételezve, hogy a forrásprogram neve myprog.c:

cc -I$OPENWINHOME/include myprog.c -o myprog
                               -lxview -lolgx -lX11

A file-ban használt $OPENWINHOME UNIX rendszerváltozó tartalmazza az OpenWindows gyökérkönyvtárát. A fordítónak megadott könyvtárak:

xview : Az XView könyvtár

olgx : Az OPENLOOK grafikus könyvtár

X11 : Az Xlib könyvtár

A következőkben egy példa Makefile-t mutatunkk be, ami XView programok fordítását teszi kényelmesebbé.

#
# Makefile for compiling XView programs
#
INCLUDE         = -I${OPENWINHOME}/include
#
# Change -O to -g below to compile for debugging
#
CFLAGS          = ${INCLUDE} -O
XVIEW_LIBS      = -L${OPENWINHOME}/lib \
                  -lxview -lolgx -lX11
CFILE           = sample.c
OBJS            = $(CFILE:.c=.o)
PROGRAM         = sample
all:  ${PROGRAM}
${PROGRAM}: ${OBJS}
        ${CC} ${CFLAGS} -o $@ ${OBJS} ${XVIEW_LIBS}
.c.o:
        ${CC} ${CFLAGS} -o $@ -c $<
clean:
        rm -f core ${OBJS} *.o

A példafile egy sample.c forrásfile-ból készít egy sample nevű futtatható file-t. A Makefile-ok készítésével szinte minden UNIX-ról szóló könyv foglalkozik, így erre itt nem térünkk ki.

A programfejlesztés során gyakori művelet a nyomkövetés. Ennél a műveletnél nagyon zavaró lehet, hogy az Xlib a protokoll kérelmeket puffereli. Emiatt a lépésenkénti végrehajtás során az adott lépés eredménye nem mindig jelenik meg a képernyőn. Ennek kiküszöbölésére ajánljuk az XFlush(display) függvényhívást, ami kényszeríti az Xlib-et, hogy küldje el a kérelmet.

3.7 Egy teljes példaprogram

Ebben a részben egy teljes példaprogramot mutatunk be. A program létrehoz egy frame-et, azon belül egy panelt, majd a panelre egy nyomógombot. A gomb megnyomásakor megerősítést vár, majd kilép.

#include <xview/xview.h>
#include <xview/frame.h>
#include <xview/panel.h>
#include <xview/notice.h>
Frame frame;
Xv_opaque my_notify_proc(item, event)
Panel_item item;
Event *event;
{
    if (NOTIFY_YES == notice_prompt(frame, NULL,
            NOTICE_FOCUS_XY,           event_x(event),
                                       event_y(event),
            NOTICE_MESSAGE_STRINGS,    "Really quit ?",
                                       NULL,
            NOTICE_BUTTON_YES,         "Yes",
            NOTICE_BUTTON_NO,          "No",
            NULL))
        xv_destroy_safe(frame);
}
main(argc, argv)
int argc;
char *argv[];
{
    Panel    panel;
    xv_init(XV_INIT_ARGS, argc, argv, NULL);
    frame = (Frame)xv_create(NULL, FRAME, NULL);
    panel = (Panel)xv_create(frame, PANEL, NULL);
    xv_create(panel, PANEL_BUTTON,
        PANEL_LABEL_STRING,   "Quit",

        PANEL_NOTIFY_PROC,    my_notify_proc,
        NULL);
    window_fit(panel);
    window_fit(frame);
    xv_main_loop(frame);
}

A program a gomb megnyomásához hozzárendel egy saját eseménykezelő rutint. Ez a rutin megerősítést kér egy notice-t használva, majd ha a felhasználó továbbra is ki akar lépni, megsemmisíti a frame-et. Fontos, hogy mivel az eseménykezelő rutinból visszatérve a Notifier még hivatkozik a frame-re, ezért azt a callback rutinban csak az xv destroy safe függvénynyel szabad megsemmisíteni. Ha ehelyett az xv destroy függvényt hívná meg a program, az futási hibát okozna. (UNIX alatt a programból core file keletkezik.)

A window fit függvény eddig nem szerepelt. Ez a rutin a paramétereként megadott ablak méretét az ablak tartalmától függően állítja be.

4 Az X grafika

Az X Windows-t bittérképes grafikus kijelzőkhöz fejlesztették ki. A fejlesztéskor egy teljesen hordozható grafikus felület kialakítására törekedtek, hogy az X egyaránt képes legyen kezelni színes, monokróm és szürkeárnyalatos kijelzőket.

Az X grafika egyik jellemzője, hogy a legtöbb lehetőség csak az Xlib szintű függvények használatával érhető el. Ezért egy grafikát is használó, de alapvetően valamelyik (pl. XView) toolkitre épülő X programban gyakran találni olyan programrészeket, ahol Xlib és toolkit szintű függvényhívások váltják egymást. Mivel ezek ugyanazokat az objektumokat használhatják, ezért az XView objektumokhoz elő kell állítani az Xlib szintű azonosítót. Ennek módjára mutat példát a következő programrészlet.

void repaint_proc(canvas, paint_win, repaint_area)
Canvas canvas;
Xv_Window paint_win;    /* XView window */
Rectlist *repaint_area;
{
    Window xwin;        /* Xlib window */
    xwin = xv_get(paint_win, XV_XID);
    XDrawPoint(display, xwin, gc, 0, 0);
}

A display és gc változókról a 4.2 és 4.3 fejezetekben lesz szó. Ami most számunkra érdekes, az az XV XID attribútum, amivel az XView objektumok Xlib azonosítóját lehet lekérdezni.

A bittérképes grafika alapeleme a pixel (képernyőpont). Egy pixel a memóriában n biten tárolódik. Ezt az n számot nevezik a képernyő mélységének. A legegyszerűbb fekete-fehér kijelzőn n értéke 1, és ez az egy bit határozza meg, hogy az adott pont a képernyőn fekete vagy fehér. Színes, ill. szürkeárnyalatos kijelzőkön egy pixel több bitnyi helyet is elfoglal. Ezek a bitek nem közvetlenül határozzák meg a képernyőpont színét, ill. árnyalatát. Ehelyett az X egy index-ként kezeli őket, aminek segítségével a colormapnak nevezett táblázatból lehet a tényleges színt, ill. árnyalatot megkapni. Ennek részleteiről és a színes grafikai lehetőségek használatáról a 4.1 fejezetben írunk.

Az X Windows fejlesztése során szempont volt az is, hogy az X adatforgalom minél kevésbé terhelje le a számítógéphálózatot. De mivel a grafika általában nagyon sok paramétertől függ, ez sok adat átvitelét jelentené a hálózaton. Ezt a problémát az X tervezői úgy oldották meg, hogy bevezettek egy komplex adatstruktúrát, az ún. Graphics Contextet. Erről a struktúráról, használatáról szól a 4.2 fejezet.

Az X grafika használatát rengeteg Xlib szintű rajzoló alapfüggvény teszi kényelmessé. Ezek használatával lehet rajzolni pontokat, vonalakat, köríveket, ellipsziseket, lehet területeket kitölteni előre megadott mintákkal és lehet szöveget megjeleníteni. Ezeknek a függvényeknek a használatáról szól a 4.3 fejezet.

Az Xlib rajzoló függvényeinek egyik jellemzője, hogy nem csak a képernyőre, ablakokba lehet velük rajzolni, hanem image-ekbe is. Az image-et úgy lehet elképzelni, mint egy olyan ablakot, ami nem látható a képernyőn. Ezek segítségével lehet létrehozni színes ikonokat, software gombokat (buttonokat). Ezekről lesz szó a 4.4 fejezetben.

4.1 Színek használata

Az X színkezelésében alapvető szerepe van az ún. colormapnek. Ez egy struktúratömb, az elemeit celláknak (colorcell) hívják. Színes display esetén minden cella három mezőből áll, amik a három alapszín (vörös, zöld, kék) intenzitásértékét adják meg.

Az X egyetlen colormapet kezel, ezt használja az összes program. Minden egyes ablak létrehozhatja a saját virtuális colormap-jét, felhasználva bizonyos számú cellát. Természetesen felmerül a kérdés, mi történik, ha megtelik a colormap. Az X régebbi verzióinál ilyenkor nem lehetett további cellákat foglalni. Az újabb verziókban úgy oldották meg ezt a problémát, hogy ilyen esetben a kért színhez legközelebb álló színt tartalmazó cellát kapja meg a kérelmező. Ezáltal ugyan előfordul, hogy nem minden alkalmazás használ helyes színeket, de legalább nem okoz hibát túl sok szín használata.

Az X háromféle displaytípust képes kezelni:

1. Monochrom: Minden pixel egy biten tárolódik a memóriában. Ez a bit határozza meg, hogy az adott képernyőpont fekete vagy fehér színű.

2. Pseudo-color: Tipikusan egy pixelnek négy és tizenkettő közötti bitszám felel meg. A pixelérték egy index-ként kezelődik, ami alapján a colormap három mezője határozza meg a képernyőpont színösszetevőit, a vörös, zöld és kék intenzitást. A szürkeárnyalatos display a

              index  vörös  zöld   kék
                0     0x00   0x00  0x00
                1     0xf0   0x00  0x00
                2     0x00   0xe0  0x00
                3     0x00   0x00  0xd0
                4     0x80   0x90  0xa0
                5     0x4c   0x5e  0x6b
                6     0x70   0x68  0x60
                7     0xff   0xff  0xff

1. táblázat. A colormap első nyolc cellája

pseudo-color típusú display elfajult változatának tekinthető. Ilyenkor a colormap egyetlen mezőből áll, ami az intenzitást adja meg.

3. Direct-color: Egy pixel tipikusan tizenkettő és harminchat közötti számú biten tárolódik. A pixelérték három mezőből áll, amelyek különkülön indexekként kezelődnek. Ebben az esetben célszerűbb a colormap három mezőjét úgy elképzelni, mintha három független colormap lenne, minden alapszínhez egy, és ezekbe indexelne bele a pixelérték három mezője.

Színes displayt feltételezve a colormap indexelését a következő példa szemlélteti:

Tegyük fel, hogy a colormap első nyolc cellája az 1. táblázat szerint van kitöltve.

Pseudo-color típusú displayt feltételezve legyen a pixelérték 0x01. Ekkor a három intenzitásérték a következő lesz: piros — 0x0f, zöld — 0x00, kék — 0x00.

Ha a display direct-color típusú, és a pixelérték 0x040603 (három 8 bites mezővel), akkor a három intenzitásérték a következő lesz: piros — 0x80, zöld — 0x68, kék — 0xd0.

A színek használatára az XView toolkit is biztosít kényelmes eszközöket. Lehetőség van saját colormap szegmens létrehozására, aminek a kezelése nagyon egyszerű. A következő programrészlet erre mutat példát. Tegyük fel, hogy a programunk a grafikához négy színt használ: feketét, fehéret, pirosat és kéket.

Xv_singlecolor cms_colors[] = {
    {   0,   0,   0 },
    { 255, 255, 255 },
    { 255,   0,   0 },
    {   0,   0, 255 }};
Cms cms;
unsigned long *cmit;
main()
{
/* XView inicializálás ...  */
    cms = (Cms)xv_create(NULL, CMS,
        CMS_COLORS,   cms_colors,
        CMS_SIZE,     4,
        NULL);
    cmit = (unsigned long *)xv_get(cms, CMS_INDEX_TABLE);
/* Ablakok létrehozása, eseményciklus ...  */
}
void set_color(dpy, gc, color)
Display *dpy;
GC gc;
int color;                   /* 0 <= color <= 3 */
{
    XSetForeground(dpy, gc, cmit[color]);
}

A program az inicializálás során létrehoz egy saját colormap szegmenst (cms), majd lekérdezi az ehhez tartozó indextáblázatot (cmit). Ezután minden rajzolás előtt, amikor a GC (4.2) előtérszínét állítja, a szín értékét indexként használva az indextáblázat adott elemének értékére állítja be az előtérszínt.

4.2 A GC adatstruktúra

Mint bármely grafikát támogató nyelvben, az X-ben is találhatunk függvényeket pontok, vonalak rajzolásához. Ezeknek az Xlib szintű függvényeknek egyik sajátossága, hogy nem igénylik paraméterként az összes rajzoláshoz szükséges információ átadását. Ehelyett az X egy olyan erőforrást vezetett be, ami meghatározza a rajz összes jellemzőjét (színek, vonalvastagság, stb.). Ez az erőforrás a GC, Graphics Context (grafikus környezet). Mivel minden rajzolórutin egyik paramétere egy GC típusú adat, ezért a programnak létre kell hoznia egy ilyet az első grafikus függvényhívást megelőzően. A GC létrehozására szolgál az XCreateGC függvény. A következő programrészlet ennek használatát mutatja be.

    GC gc;
    XGCValues values;
    unsigned long valuemask;
    values.foreground = BlackPixel(display, screen_num);
    values.background = WhitePixel(display, screen_num);
    gc = XCreateGC(display, RootWindow(display, screen_num),
            (GCForeground | GCBackground), &values);

A programrészlet egy olyan GC-t hoz létre, aminek az előtérszíne fekete, a háttérszíne pedig fehér. A fekete és fehér színnek megfelelő indexek lekérdezésére két makrót használ. Az XCreateGC másoodik paraméterének a helyére bármilyen ablak azonosítóját beírhatnánk, ami őse a rajzolás céljául szolgáló ablakunknak. A RootWindow makró azt az ablakot adja vissza, ami minden ablak őse, így ez mindig használható ezen a helyen. A display és screen num változókról a 4.3 alfejezetben lesz szó.

Az XCreateGC harmadik paramétere egy maszk, ami megadja, hogy a negyedik paraméterben átadott struktúra mely mezői vannak kitöltve.

A GC tartalmát a szerver tárolja, ily módon is csökkentve a hálózaton átküldendő adatmennyiséget. A program egy azonosítót kap vissza a GC létrehozásakor, ezzel lehet később hivatkozni rá, akár rajzoláskor, akár a rajzolás paramétereinek megváltoztatásakor. Lehetőség van egyidejűleg több GC használatára is, amelyek egymástól eltérő értékekre vannak beállítva. Ily módon ugyanazzal a szubrutinnal különböző hatásokat lehet elérni attól függően, hogy melyik GC-t kapja meg paraméterként.

A GC segítségével a rajz nagyon sok paraméterét lehet változtatni. A következőkben ezek közül a leggyajoribbakkal foglalkozunk. Így például nem tér-nk ki a szövegek jellemzőinek állítására, a területkitöltés paramétereinek meghatározására, stb. A GC használatáról részletes leírás található [4]-ben, rövid referenciaként pedig [5] használható.

Logikai funkció Ez a mező határozza meg, hogy a rajzoláskor hogyan keletkezik az új pixelérték a GC előtérszín mezőjéből és az előző pixelértékből. A leggyakrabban használt értékek a GXcopy (default érték) és GXxor. Az előbbi figyelmen kívül hagyja az előző pixelértéket és az előtérszínre állítja a pont színét, az utóbbinál pedig a két érték kizáró-vagy kapcsolata lesz az új érték.

A mező az XSetFunction függvénnyel állítható.

Előtérszín, Háttérszín Ezek a mezők határozzák meg a rajzolás színeit. A szín értéke egy index lesz a colormapbe. A két mező értéke az XSetForeground illetve XSetBackground függvényekkel állítható.

Vonaljellemzők Ez alatt a GC négy mezőjét értjük, amelyek egyetlen függvényhívással állíthatók.

line width Vonalvastagság pixelekben. Ha ez az érték 0, akkor az X a leggyorsabb vonalhúzó algoritmust fogja használni, ami az adott gépen elérhető. (Bizonyos gépek biztosítanak gyors hardware vonalrajzolási lehetőséget, ennek kihasználását jelenti a 0 érték.)

line style A vonal stílusa, default értéke a folytonos vonal, de meg lehet adni szaggatott vonalat is, sőt lehetőség van a szaggatottság módjának beállítására is.

cap style A vonalvég stílusa, default értéke merőlegesen levágott, de be lehet például állítani lekerekített vonalvéget is. Csak akkor van értelme, ha a vonalvastagság nagyobb mint 1.

join style A csatlakozó vonalvégek csatlakozásának módját adja meg. Lehet szögletes, lekerekített, stb. Ennek a mezőnek is csak akkor van értelme, ha a vonalvastagság legalább 2.

A négy mező az XSetLineAttributes függvénnyel állítható.

A GC mezőinek értékét be lehet állítani a GC létrehozásakor, mint azt a fejezet elején láttuk, vagy utólag, amint a következő programrészlet mutatja:

    unsigned int line_width = 6;
    int line_style = LineOnOffDash;
    int cap_style = CapRound;
    int join_style = JoinRound;
    int dash_offset = 0;
    static char dash_list[] = {12, 24};
    int list_length = 2;
    XsetForeground(display, gc,
            BlackPixel(display, screen_num));
    XSetLineAttributes(display, gc, line_width,
            line_style, cap_style, join_style);
    XSetDashes(display, gc, dash_offset,
            dash_list, list_length);

Ez a programrészlet úgy állítja be a GC-t, hogy az ezt követő vonalrajzolások fekete színű, hat pixel vastag szaggatott vonalat rajzolnak lekerekített végekkel és csatlakozásokkal. A szaggatottságot a dash list tömb írja le.

4.3 Rajzoló alapfüggvények

Az X rajzoló alaprutinjai nagyon egyszerűen használhatók pontok, vonalak, téglalapok, körívek rajzolására. Ebben a fejezetrészben nem kívánjuk bemutatni az összes rutint vagy akár csak egy részüket. Szeretnénk ehelyett általános elvekről írni, a használatukról, paraméterezésükről. Az összes függvény felsorolása paraméterekkel, azok lehetséges értékeivel [5]-ban található meg. Akinek pedig programozás közben csak a függvények hívási formájára van szüksége és [5] nincs kéznél, azoknak ajánljuk, hogy használják az Xlib.h include file-t.

Egy toolkitre épülő programban grafikát használni kicsit olyan, mintha egy magasszintű programnyelvben assembler utasításokat használnánk. A toolkitek általában nem biztosítanak olyan lehetőségeket a rajzolásra, mint az Xlib függvények. Ezért általános az Xlib rajzoló függvényeinek használata a grafikát megvalósító részeknél. Arról már szóltunk ezen fejezet elején, hogy miképpen lehet az XView objektumok azonosítóit Xlib azonosítókká konvertálni. Most az Xlib rajzoló függvényeinek három állandóan szereplő paraméteréről, előállításukról lesz szó.

display `Display *' típusú paraméter. Nem csak a rajzoló, hanem az összes Xlib függvény első paramétere. Azt az X szervert adja meg, amelyiknek a protokoll kérelmet küldeni kell. Mivel egy program általában egy kijelzőre dolgozik, ezért ez a paraméter egy programon belül állandó érték. Xlib szintű programokban a szerverhez való csatlakozáskor adódik vissza, XView szinten pedig a következő függvényhívással állítható elő tetszőleges ablak azonosítójából:

         display = XV_DISPLAY_FROM_WINDOW(frame);

drawable Drawable típusú paraméter. Ez a típus a Window és Pixmap típusok összessége. Ez határozza meg a rajzolás célját, ami lehet ablak vagy pixmap. Egy XView ablak vagy egy Server image azonosítójából a fejezet elején leírt módon lehet előállítani.

gc GC típusú paraméter. A rajzolás jellemzőit (vonalvastagság, színek, stb.) határozza meg. A 4.2 alfejezetben részletezett módon lehet előállítani.

Az Xlib tartalmaz olyan makrókat, amelyekkel a képernyő jellemzőiről nyerhetünk információt (pl. DisplayWidth), vagy különböző azonosítókat kaphatunk meg (pl. RootWindow). Ezek a makrók gyakran kérnek olyan paramétert, ami a képernyőt azonosítja^{9}. Ez a paraméter is egy makróhívással állítható elő a következő módon:

    int scr_num;
    scr_num = DefaultScreen(display);

A rajzoló függvények többi paraméterének beállítása egyedi, a rajzolás céljától függ (pl. egy vonalrajzoláskor a vonal végpontjai). A következő programrészlet az XDrawRectangle függvény használatára mutat példát.

void draw_graphics(win, gc, win_width, win_height)
Window win;
GC gc;
unsigned int win_width, win_height;
{
    int x, y;
    unsigned int width, height;
    height = win_height/2;

9Ennek akkor van különös jelentősége, amikor egy szerver több képernyőt is kezel.

    width = 3 * win_width/2;
    x = win_width/2 - width/2;        /* Centered */
    y = win_height/2 - height/2;
    XDrawRectangle(display, win, gc, x, y, width, height);
}

Ez a programrészlet egy téglalapot rajzol a win paraméterben kapott ablakba. Mint látható, a pozíció pontos beállítása teszi ki a rutin nagyobbik részét, a rajzolás maga nagyon egyszerű.

4.4 Image-ek

Az X kétféle képernyőn kívüli (off-screen) képet ismer, a bitmapet és a pixmapet. Ezek nagyon hasonló adatstruktúrák azzal a különbséggel, hogy a bitmap 1 bit mélységű téglalap, míg a pixmap mélysége nagyobb is lehet. A kettőt közös néven image-nek hívják. Egy image-et elő lehet állítani úgy, hogy a tartalmát elküldjük a szervernek, vagy pedig a képernyő megfelelő méretű darabját belemásoljuk. Még egy lehetőség van image-ek létrehozására, ez a rajzoló függvények használata.

Az image-eket általában egy ábrarészlet ablakban történő megjelenítésére használják, pl. ikonok, kurzorok és nyomógombokok létrehozására. A nyomógombokról már volt szó a 3.5.2 fejezetben, a másik két objektumfajtáról néhány szó:

ikon Ahhoz, hogy a rendelkezésünkre álló képernyőfelület átlátható maradjon és ne zsúfolódjon tele egymást átfedő ablakokkal, az éppen nem használt ablakokat célszerű bezárni. Az ikon egy olyan kisméretű ablak, ami egy frame zárt állapotára utal.

kurzor A kurzor egy olyan szimbólum, ami a képernyőn az egér mozgását követi^{10}. Ez eltér a más típusú képernyő-outputoktól, mivel átlátszó, és úgy mozog a képernyőterület felett, hogy nem változtatja meg azt. A programozó minden ablakhoz más alakú kurzort rendelhet, ennek módjára később mutatunk példát.

A kurzort több jellemző határozza meg:

10Az X szóhasználat különbséget tesz kétféle pozíciót jelző objektum közt. A kurzor (cursor) az egeret képviseli a képernyőn, ebből egy kijelzőn egy van. A caret általában szövegszerkesztő, szövegbeviteli funkciókhoz kapcsolódik, azt mutatja, hogy melyik pozícióba kerül a következő karakter. Ilyenből minden ablakhoz tartozhat egy.

Alak A kurzor alakját egy a CURSOR IMAGE attribútumhoz rendelt bitmappel lehet megadni.

Maszk A kurzor maszkja azokat a pixeleket adja meg, amelyeket a kurzor módosít a képernyőn.

Szín A kurzorhoz rendelhetünk előtérszínt és háttérszínt. Ezek az alakot leíró bitmap 1 és 0 bitjeihez rendelődnek, ha az adott pont maszk bitje egy.

Hotspot A kurzor hotspotja annak a pontnak a helyét adja meg az image-en belül, aminek a koordinátáit kurzor-koordinátákként megkapja a program.

A következő programrészlet egy ikon létrehozására mutat példát.

short closed_bits[] = {
#include "my.icon"
};
main()
{
    Server_image closed_im;
    Icon icon;
/* frame létrehozása ...  */
    closed_im = (Server_image)xv_create(NULL, SERVER_IMAGE,
        XV_WIDTH,             64,
        XV_HEIGHT,            64,
        SERVER_IMAGE_BITS,    closed_bits,
        NULL);
    icon = (Icon)xv_create(frame, ICON,
        ICON_IMAGE,       closed_im,
        NULL);
    xv_set(frame, FRAME_ICON, icon, NULL);
/* Eseményciklus ...  */
}

A példa elején szereplő #include direktíva által beolvasott file tartalmazza az ikon képét. Ilyen file-t OpenWindows környezetben legegyszerűbben az Icon Editor program segítségével lehet előállítani, ami a következő formátumot használja:

    0x0000,0x0000,0x0000,0x0000,
    0x00E0,0x01F3,0x0000,0x0000,
...
    0x0000,0x00A0,0x0040,0x0000

Az ilyen file-okkal létrehozott image-eket tetszőleges célra lehet használni, nem csak ikon létrehozására. Hátránya viszont ezeknek a file-oknak, hogy színes image nem készíthető velük (Depth=1). Ennek a problémának egy lehetséges megkerülése az Xlib rajzolófüggvények használata. Ilyenkor az Xlib függvények második paraméterének nem Window, hanem Pixmap típusú paramétert kell megadni, amit a létrehozott Server image-ből a fejezet elején leírt módon lehet előállítani.

A teljesség kedvéért egy-egy példát mutatunk egy kurzor és egy nyomógomb képének megadására is:

    cursor = (Cursor)xv_create(NULL, CURSOR,
        CURSOR_IMAGE,        crs_image,
        CURSOR_XHOT,         15,
        CURSOR_YHOT,         15,
        NULL);
    button = (Panel_item)xv_create(panel, PANEL_BUTTON,
        PANEL_LABEL_IMAGE,   button_im,
        NULL);

A kurzor létrehozásánál látható példa a korábban felsorolt kurzorjellemzők állítására is. A maszkot nem állítja a program, ennek default értéke az image bitmapje.

Bizonyos alakú kurzorokat más módszerrel is létre lehet hozni, image használata nélkül. Léteznek karakterként előre definiált OPENLOOK kurzorok, ezek a következőképpen használhatók:

    cursor = (Cursor)xv_create(NULL, CURSOR,
        CURSOR_SRC_CHAR,    OLC_BASIC_PTR,
        CURSOR_MASK_CHAR,   OLC_BASIC_MASK_PTR,
        NULL);

A példában szereplő kurzor a standard OPENLOOK kurzor.

Miután létrehoztuk a kurzort, azt használni is akarjuk. Ennek módjára mutat példát a következő programrészlet.

    canvas = (Canvas)xv_create(frame, CANVAS,
        CANVAS_PAINTWINDOW_ATTRS,
            WIN_CURSOR,     cursor,
            NULL,
        NULL);

Ez a függvényhívás a canvas-hoz hozzárendeli a korábban létrehozott kurzort. Ezután valahányszor úgy mozgatjuk az egeret, hogy a kurzor a canvas fölé kerül, az a cursor változóhoz rendelt kurzorrá fog átváltozni.

Irodalom

[1] Robert W. Scheifler & Jim Gettys. The X Window System. MIT, Cambridge, Massachusetts, July 1986.

[2] Dan Heller. The X Window System, XView Programming Manual. O’Reilly & Associates, Inc. New Jersey, 1990.

[3] AT&T Bell Laboratories Staff. UNIX System V, Release 4: Programmer’s guide: X11/NeWS graphical windowing system XView: UNIX software operation. Prentice-Hall, AT&T-Englewood Cliffs, N. J., 1990.

[4] Adrian Nye. The X Window System, Xlib Programming Manual. O’Reilly & Associates, Inc. New Jersey, 1990.

[5] Adrian Nye. The X Window System, Xlib Reference Manual. O’Reilly & Associates, Inc. New Jersey, 1990.