home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1997 #3
/
amigamamagazinepolishissue03-1
/
ma_1995
/
06
/
ami039.txt
< prev
next >
Wrap
Text File
|
1997-04-07
|
14KB
|
321 lines
******************************************
UWAGA DO SKÎADU: PROSZË PRZY WLEWANIU TEGO TEKSTU WYÎÂCZYÊ KONWERSJË
CUDZYSÎOWÓW, TAK, ABY PAGEMARKER NIE ZMIENIAÎ POCZÂTKOWYCH CUDZYSÎOWÓW
NA DOLNE.
******************************************
C dla kaûdego (cz. 2.)
----------------------
OKNO NA SZARY ÔWIAT
<lead>Najwyûszy czas zabraê sië do konkretnej pracy. Dziô
zajmiemy sië oknami, obracaê sië wiëc bëdziemy w krëgu
biblioteki Intuition, która zarzâdza GUI.
<a>Kamil Iskra, Dariusz Ûbik
<txt>Zacznijmy od, dostëpnych dopiero po otwarciu biblioteki
Intuition, funkcji do otwierania okien. Dawniej istniaîa tylko
jedna taka funkcja:
<l>struct Window *OpenWindow( struct NewWindow *newWindow );
<txt>Obecnie (od systemu 2.0) istnieje teû druga:
<l>struct Window *OpenWindowTagList( struct NewWindow *newWindow, struct TagItem *tagList );
struct Window *OpenWindowTags( struct NewWindow *newWindow, unsigned long tag1Type, ... );
<txt>Pewnie cisnâ sië Wam na usta dwa pytania: co robiâ powyûej
dwa prototypy funkcji, skoro miaî byê tylko jeden, i co oznaczajâ
parametry tych funkcji. Pierwszy parametr to wskaúnik na
zainicjowanâ wczeôniej strukturë informacyjnâ, w której
umieszczaîo sië informacje o tym, jaki miaî byê rozmiar okna,
jakie miaîo mieê ono gadûety, tytuî itp. Piszemy w czasie
przeszîym, poniewaû parametru tego w dzisiejszych czasach juû sië
wîaôciwie nie uûywa (jako pierwszy parametr podaje sië po prostu
NULL, czyli 0). Struktura NewWindow zostaîa wyparta przez tagi.
<sr>Dlaczego tagi?
<txt>System sië rozwija. Od czasu pierwszej Amigi duûo zostaîo
zrobione. Niestety, nawet pomimo duûej liczby "furtek",
pozostawionych przez twórców systemu, niektóre struktury staîy
sië w koïcu zbyt ciasne -- klasycznym przykîadem jest wîaônie
struktura NewWindow. Zastëpowanie ich w kaûdym systemie nowymi
nie ma sensu. Wîaônie dlatego pojawiîy sië tagi. Za ich pomocâ
moûna przekazywaê do funkcji nieograniczone iloôci informacji,
bez posîugiwania sië sztywnymi strukturami, tagi umoûliwiajâ teû
bezproblemowe dodawanie nowych elementów do systemu operacyjnego.
Argumenty podaje sië parami (strukturami TagItem) -- pierwszy
element pary to wîaônie TAG, który jest po prostu staîâ
informujâcâ, co oznacza dana przekazana w drugim elemencie pary,
moûe to byê np. szerokoôê okna, jego tytuî (wskaúnik na nazwë)
itd. Po pierwszej parze moûe nastâpiê druga, trzecia i nastëpne.
Funkcje korzystajâce z tagów mogâ byê wywoîane na dwa sposoby.
Istniejâ dwie deklaracje tej samej funkcji bibliotecznej
(róûniâce sië zwykle koïcówkâ nazwy -- tak jak w wypadku
OpenWindowTagList() i OpenWindowTags()). Pierwszym ze sposobów
wywoîania takiej funkcji jest podanie jej wskaúnika na tablicë
tagów w charakterze argumentu (w naszym wypadku chodzi o ostatni
argument funkcji OpenWindowTagList()). Tablica taka jest
wypeîniona strukturami TagItem. W drugim sposobie
(OpenWindowTags()) zamiast wskaúnika na zdefiniowanâ wczeôniej
tablicë podaje sië po prostu pary jako kolejne parametry do
funkcji o zmiennej liczbie argumentów (na podobnej zasadzie, jak
w "printf()"). Oba sposoby sâ równowaûne, w rzeczywistoôci
funkcja przyjmuje argumenty w tej pierwszej postaci, a druga jest
po prostu "tîumaczona", przez kompilator, na pierwszâ, a istnieje
dlatego, ûe jest wygodniejsza w uûyciu.
Warto wspomnieê o tagu, który MUSI sië pojawiê na koïcu, w
tablicy struktur TagItem, lub jako ostatni argument funkcji. Jest
nim TAG_END, nazywany równieû TAG_DONE (równy 0). Wîaônie ten tag
informuje funkcjë, ûe nie ma juû wiëcej danych. Jeôli go
zabraknie, to nieszczësna funkcja nadal bëdzie czytaê dane z
przypadkowego obszaru pamiëci i moûe sië naczytaê bzdur. Dlatego
uczulamy Was: PAMIËTAJCIE o stawianiu tagu TAG_END. Wykrycie
takiego bîëdu nie zawsze jest proste, gdyû program moûe czasami
"chodziê" caîkiem normalnie (bo akurat znajdzie w pamiëci zero).
Obie opisane powyûej funkcje do otwierania okien zwracajâ adres
struktury opisujâcej otwarte okno (struktura Window) lub NULL, w
wypadku gdy spotka je niepowodzenie.
Zastosowanie tych funkcji moûna zobaczyê w listingu 4.
Przypominamy, ûe listingi nie sâ kompletne! Naleûy doîâczyê
funkcjë check_os() z poprzedniej czëôci kursu oraz definicje
staîych "OS_xx", deklaracjë zmiennej "SysBase" i pliki nagîówkowe
"exec/execbase.h" oraz "stdlib.h".
Warto wytîumaczyê, co oznaczajâ uûyte w tym przykîadzie tagi:
WA_Left -- wspóîrzëdna lewej krawëdzi okna,
WA_Top -- wspóîrzëdna górnej krawëdzi okna,
WA_Width -- rozmiar okna w poziomie,
WA_Height -- rozmiar okna w pionie.
W wypadku Amigi wspóîrzëdne sâ podawane wzglëdem lewego górnego
rogu, który ma wspóîrzëdne (0, 0), ekran zaô jest poîoûony
niejako w czwartej êwiartce ukîadu wspóîrzëdnych. Nie naleûy sië
sugerowaê programami graficznymi, w wypadku których wyôwietlane
wspóîrzëdne sâ przeliczane w taki sposób, ûe ekran jest przez
uûytkownika widziany jako pierwsza êwiartka kartezjaïskiego
ukîadu wspóîrzëdnych. Ta sama zasada obowiâzuje w wypadku okien.
Wspóîrzëdne w oknie oblicza sië wzglëdem lewego górnego rogu
okna.
WA_Title -- tytuî okna (wyôwietlany na jego listwie),
WA_Flags -- flagi dotyczâce gîównie wyglâdu okna:
-- WFLG_SIZEGADGET -- okno ma mieê gadûet do zmieniania wielkoôci,
-- WFLG_DRAGBAR -- okno ma mieê listwë do przesuwania za pomocâ myszy,
-- WFLG_DEPTHGADGET -- okno ma mieê gadûet przód/tyî,
-- WFLG_CLOSEGADGET -- okno ma mieê gadûet zamykania,
-- WFLG_ACTIVATE -- okno ma zostaê automatycznie uaktywnione po
otwarciu,
-- WFLG_RMBTRAP -- naciskanie prawego przycisku menu (RMB --
Right Mouse Button) nie ma powodowaê rysowania listwy menu.
Niektóre flagi majâ swoje odpowiedniki wôród tagów. Moûna je
wywoîywaê bezpoôrednio, podajâc po nich wartoôê TRUE. Przykîadami
takich flag mogâ byê: WA_SizeGadget, WA_DepthGadget,
WA_CloseGadget. Dokîadny ich wykaz, wraz z definicjami staîych,
znajduje sië w pliku "intuition/intuition.h".
WA_ScreenTitle -- napis wyôwietlany na górnej listwie ekranu, gdy
okno jest aktywne.
W programie zostaîa uûyta pewna funkcja z biblioteki "dos.library".
Jej skîadnia jest bardzo prosta:
<l>void Delay( long timeout );
<txt>Za pomocâ tej funkcji moûna chwileczkë odczekaê. Dîugoôê
chwileczki jest podawana w jednostkach nazywanych ticks, 50
takich jednostek to jedna sekunda. Uwaûny Czytelnik zapewne sië
zastanawia, jakim prawem woîamy funkcjë z biblioteki
dos.library bez jej otwarcia. Moûemy pozwoliê sobie na të
"zbrodnië", poniewaû bibliotekë të otwiera dla nas moduî
startowy, doîâczany przez linkera, i podstawia pod zmiennâ
"DOSBase" (wiëcej o module startowym powiemy w przyszîoôci).
Moûna wiëc chyba uznaê, ûe otwarcie okna mamy za sobâ. Teraz
naleûy sië nauczyê z nim komunikowaê. Jest to rozwiâzane za
pomocâ tak zwanych portów (struktur MsgPort), bëdâcych czymô w
rodzaju skrzynek kontaktowych. Jeden program umieszcza w porcie
wiadomoôê (strukturë Message), a drugi po chwili jâ odbiera --
daje sië tu wyraúnie odczuê multitasking.
Program bëdâcy wîaôcicielem okna sam decyduje, jakie wiadomoôci
chce za jego pomocâ uzyskiwaê. Moûe go np. zupeînie nie
interesowaê, czy uûytkownik nacisnâî jakiô klawisz na klawiaturze
albo czy wyjâî dyskietkë ze stacji. To, jakie wiadomoôci program
ma otrzymywaê, ustala sië podczas otwierania okna, za pomocâ tagu
"WA_IDCMP" (ta "wpadajâca w pamiëê" nazwana jest skrótem od
Intuition Direct Communication Message Port). Jako dane dla tego
tagu podaje sië staîe symboliczne, oznaczajâce poszczególne klasy
wiadomoôci, jakie program ma otrzymywaê. Jest ich mnóstwo.
Bëdziemy je podawaê stopniowo (ûeby Was nie dobiê). W tej czëôci
uûyjemy w przykîadach nastëpujâcych klas:
IDCMP_CLOSEWINDOW -- klikniëcie na gadûet zamykania okna.
IDCMP_DISKINSERTED -- wîoûenie dysku.
IDCMP_DISKREMOVED - wyjëcie dysku.
IDCMP_MOUSEBUTTONS -- naciôniëcie bâdú zwolnienie któregoô z
przycisków myszy (tylko przy aktywnym oknie).
W wypadku okien adres portu znajduje sië w strukturze Window, w
polu o nazwie "UserPort". Program pragnâcy otrzymaê wiadomoôê nie
musi co chwilë sprawdzaê, czy uûytkownik wykonaî jakâô operacjë
(np. kliknâî myszâ). Wystarczy, ûe poprosi system o
poinformowanie go, kiedy coô takiego nastâpi. W programach bardzo
czësto zachodzi potrzeba oczekiwania na wydarzenie, do tego celu
sîuûy funkcja Execa:
<l>struct Message *WaitPort( struct MsgPort *port );
<txt>Funkcja ta oczekuje na pojawienie sië jakiejkolwiek
wiadomoôci w podanym porcie, jest ona wykonywana aû do czasu
pojawienia sië wiadomoôci, wówczas przekazuje sterowanie z
powrotem do programu. Funkcja ta zwraca wskaúnik na pierwszâ
wiadomoôê umieszczonâ w porcie, choê moûe byê ich w porcie
wiëcej. Naleûy pamiëtaê, ûe funkcja ta czeka "do upadîego".
Jeôli ûadna wiadomoôê do portu nie dotrze, to program dalej "nie
pójdzie". Nierzadkim bîëdem jest oczekiwanie na wiadomoôci od
okna, które ûadnych wiadomoôci przysîaê nie moûe (ma pole
IDCMPFlags==0). Na szczëôcie trudno taki bîâd przegapiê.
Kiedy juû stwierdzimy, ûe w porcie jest jakaô wiadomoôê, to
naleûy jâ odebraê. Posîuûymy sië w tym celu funkcjâ Execa:
<l>struct Message *GetMsg( struct MsgPort *port );
<txt>Funkcja ta usuwa z portu pierwszâ ze znajdujâcych sië w nim
wiadomoôci i jej adres zwraca naszemu programowi. W wypadku, gdy
port jest pusty, funkcja zwraca NULL.
W otrzymanej w ten sposób wiadomoôci znajdziemy wiele cennych
informacji. Omówimy je za chwilë. W wypadku operacji na portach
waûny jest poôpiech, tak wiëc istotne dla nas informacje naleûy
sobie w pomocniczych zmiennych zapamiëtaê, a wiadomoôê jak
najszybciej zwróciê nadawcy. Naleûy pamiëtaê, aby niczego w
otrzymanej wiadomoôci nie zmieniaê, bo mogâ wystâpiê problemy.
Wiadomoôê odsyîamy za pomocâ funkcji Execa:
<l>void ReplyMsg( struct Message *message );
<txt>Funkcja ta odsyîa wiadomoôê do "macierzystego" portu. Po
odesîaniu wiadomoôci NIE WOLNO juû z niej korzystaê. System moûe
zrobiê z niâ, co zechce, np. zwolniê zajmowanâ przez niâ pamiëê,
przez co dane by po prostu znikîy i naczytalibyômy sië bzdur.
W wypadku wiadomoôci pochodzâcych od okien mamy do czynienia z
rozszerzonymi strukturami Message o nazwie IntuiMessage.
Postëpowanie jest takie samo, jak w wypadku rozszerzonych
struktur Library. I tym razem pierwszym polem struktury
IntuiMessage jest struktura Message, moûna wiëc swobodnie
zastosowaê rzutowanie typów. Zawartoôciâ struktury Message
zajmiemy sië póúniej, przy dokîadnym omawianiu portów (sâ to
zresztâ systemowe zawiîoôci, bez których moûna sië obejôê). Teraz
omówmy pozostaîe pola struktury IntuiMessage. Zajrzyjmy do niej
-- znajduje sië ona w pliku "intuition/intuition.h".
Najwaûniejsze pola to:
ULONG Class -- Informuje o klasie (rodzaju) wiadomoôci, która
dotarîa do portu. Sâ to te same staîe, których uûywa sië
wczeôniej w tagu WA_IDCMP (IDCMP_CLOSEWINDOW itd.).
UWORD Code -- Zawiera dodatkowe informacje, zaleûne od rodzaju
wiadomoôci, np. dla wiadomoôci IDCMP_MOUSEBUTTONS pole to zawiera
informacje o tym, który przycisk myszy zostaî wciôniëty lub
zwolniony (dokîadniej o tym za chwilë). Niektóre rodzaje
wiadomoôci w ogóle nie uûywajâ tego pola, np. IDCMP_CLOSEWINDOW.
UWORD Qualifier -- To pole zawiera nie przetworzone informacje,
dostarczone przez program systemowy o nazwie input.device,
zajmujâcy sië obsîugâ wejôcia/wyjôcia. Jest ono rzadko
wykorzystywane. Moûna tu znaleúê np. informacje o tym, czy gdy
wystâpiîo zdarzenie, byî wciôniëty lewy klawisz [Shift]
(IEQUALIFIER_LSHIFT), albo czy dana cyfra zostaîa wpisana na
klawiaturze numerycznej (IEQUALIFIER_NUMERICPAD) itp. --
odpowiednie staîe sâ zdefiniowane w pliku "devices/inputevent.h".
APTR IAddress -- Zawiera adres obiektu, bëdâcego przyczynâ
wysîania wiadomoôci, jest zaleûne od jej rodzaju, np. w wypadku
wiadomoôci o gadûetach zawiera adres gadûetu.
WORD MouseX, MouseY -- Zawierajâ poîoûenie myszy w chwili
wystâpienia zdarzenia, wspóîrzëdne sâ podawane wzglëdem lewego
górnego rogu okna. Jeôli w polu IDCMPFlags okna byî ustawiony
znacznik IDCMP_DELTAMOVE, wspóîrzëdne bëdâ podawane wzglëdem
poprzednio meldowanego poîoûenia (wektor przesuniëcia).
ULONG Seconds, Micros -- Zawierajâ czas systemowy, w którym
zdarzenie nastâpiîo (bardzo przydatne, gdy chcemy sprawdziê, czy
miaî miejsce tzw. double-click, czyli szybkie, dwukrotne,
klikniëcie myszâ).
Jak juû wczeôniej pisaliômy, wiadomoôci otrzymane od Intuition
naleûy jak najszybciej zwróciê. W zwiâzku z tym najwygodniej jest
skopiowaê caîâ strukturë lub tylko te pola, które nas interesujâ.
Przetrzymywanie informacji od Intuition moûe wpîynâê na
spowolnienie dziaîania systemu. Po wykonaniu kopii i zwróceniu
wiadomoôci moûemy sië swobodnie i bez poôpiechu zastanawiaê, co
poczâê dalej. Nieocenionâ pomocâ jest instrukcja "switch". Na
poczâtku naleûy rozpoznaê rodzaj wiadomoôci, czyli zerknâê do
pola "Class", a nastëpnie, w zaleûnoôci od jego zawartoôci,
analizowaê pozostaîe pola.
W wypadku gdy otrzymamy informacjë typu IDCMP_CLOSEWINDOW, wiemy,
co sygnalizuje uûytkownik -- pozostaîe pola nie zawierajâ
istotnych informacji. Podobnie jest w wypadku IDCMP_DISKINSERTED
i IDCMP_DISKREMOVED -- nie ma sensu patrzeê na zawartoôê
pozostaîych pól (jeûeli ktoô nie pisze programu sprawdzajâcego,
jak szybko moûna zmieniê dyski, wówczas potrzebne byîyby pola
Seconds i Micros, ale sadyzmu nie popieramy).
Zupeînie innaczej wyglâda sytuacja z wiadomoôciami o
"przyciôniëciu myszy" (IDCMP_MOUSEBUTTONS). W tym wypadku pole
"Code" zawiera uûyteczne informacje:
SELECTDOWN -- wciôniëto lewy przycisk myszy,
SELECTUP -- zwolniono lewy przycisk myszy,
MENUDOWN -- wciôniëto prawy przycisk myszy,
MENUUP -- zwolniono prawy przycisk myszy,
MIDDLEDOWN -- wciôniëto ôrodkowy przycisk myszy,
MIDDLEUP -- zwolniono ôrodkowy przycisk myszy.
Wiadomoôci tej klasy docierajâ tylko do jednego okna -- do tego,
które jest aktywne.
Amiga obsîuguje trzeci przycisk myszy, choê czësto go nie ma,
natomiast pecety majâ go prawie zawsze, ale i tak ogromna
wiëkszoôê programów uûywa tylko jednego przycisku -- lewego (dla
zainteresowanych dodam, ûe w Amidze trzeci przycisk myszy naleûy
podîâczyê do wyprowadzenia numer 5 oraz do masy, czyli
wyprowadzenia numer 8).
Za miesiâc przedstawië wykorzystanie portu okna.