C dla każdego (cz. 3.)

Okno na szary świat

Wykorzystanie portu okna prezentuje listing 5. Użyliśmy w nim następujących, nie opisanych wcześniej, funkcji:

void DisplayBeep(struct Screen *screen);

Zadaniem tej funkcji jest "obudzenie" użytkownika. Polega ono na mignięciu ekranem (jednym lub wszystkimi). Jedyny argument to wskażnik na ekran, w wypadku gdy zostanie tam umieszczone zero, "budzenie" odbędzie się na wszystkich ekranach (o ekranach będzie za mieśiąc). Od WB 2.1 na dyskach systemowych jest obecny program, dodający do standardowego "mignięcia" funkcji DisplayBeep() również efekty dżwiękowe.
Jeśli komuś znudzi się tytuł okna, to powienien skorzystać z usług funkcji Intuition:

void SetWindowTitle(struct Window *window, UBYTE *windowTitle, UBYTE *screenTitle);

Funkcja ta ustawia oba tytuły związane z oknem. Pierwszym argumentem jest okno, w którym mają być dokonane zmiany. Drugi to nowy tytuł okna, wyświetlany na jego listwie tytułowej (odpowiednik tagu WA_Title), a trzeci jest tytułem, ktory będzie wyświetlony na listwie ekranu w czasie, gdy okno będzie aktywne (odbędzie tagu WA_ScreenTitle). Zamiast jednego lub obu napisów można podać zero, wówczas tytuł zostanie wyczyszczony, możliwe jest również pozostawienie tytułu bez zmian, należy wtedy podać zamiast napisu wartość -1 (zrzutowaną xa typ "wskaźnik na znak", a więc "STRPTR" bądź "char*").

Do komunikacji z użytkownikiem istnieje kilka funkcji, zaczniemy od tej, która właściwie jest już zapomniana:

BOOL DisplayAlert(unsigned long alertNumber, UBYTE *string, unsigned long height);

Funkcja ta produkuje komunikaty typu "Guru Meditation" (OS 1.3) lub też "Software Error" dla systemów nowszych. Pierwszy argument to typ komunikatu - jego istnienie wynika z zastosowania funkcji do obwieszczania klęsk żywiołowych przez system, ale nie tym będziemy się zajmować. Z naszego punktu widzenia to pole wpływa na kolor ramki (RECOVERY_ALERT -ramka bursztynowa, DEADEND_ALERT - ramka czerwona). Kolejnu argument to napis - jest to ciekawa kompilacyjka tekstu i kodów sterujących. W pierwszych bajtach są zapisane współrzędne początku napisu - dwa bajty na współrzędną x i jeden bajt na współrzędną y, następnie jest tam umieszczony sam napis, zakończony standardowo - znakiem o kodzie '\0'. Jeżeli po tym znaku wystąpi znak o kodzie różnymu od zera, to oznacza to, że dalej jest kolejny napis w takim samym formacie - w przeciwnym wypadku więcej napisów nie ma. Wygląda to może zawile, ale nie jest trudne - proponuje zajrzeć do przykładu.

Ostatni argument to wysokość ramki. Mówiąc szczerze, długo zastanawialiśmy się czy pisać o tej funkcji. Jej podtawową wadą jest to że wyświetla obraz zawsze w rozdzielczości NTSC lub PAL. Ci, którzy mają podłączone do Amigi monitory VGA, zobaczą w takim wypadku... kaszę (a ponoć niektóre monitory mogą się nawet uszkodzić!). Jednym z atutów tej funkcji w OS 1.3 były jej niewielkie wymagania pamięciowe - na wyświetlenie komunikatu potrzeba było sosłownie kilku kilobajtów. Tymczasem od OS 2.0 wymaga ona raczej powyżej 50 KB RAM! Nie polecamy więc jej używania, opisujemy ją tutaj trochę przez sentyment (mówiąc krótko: Darek się uparł).

UWAGA: w wypadku użycia funkcji DisplayAlert() radzimy dbać o współrzędne, ponieważ jeśli tekst wyjdzie poza ramkę, funkcja może uszkodzić coś w systemie. Do takiego błedu często prowadzi nieostrożna zmiana współrzędnych. Uczulamy: po znaku "\" umieszcza się liczbę w kodzie ÓSEMKOWYM, czyli 0..7 (w czasie pisania tego przykładu przez własną głupote wpisałem \28, bo chciałem, aby tekst był dwa razy niżej niż górna linia. Cóż, spotkało mnie Guru, choć na mojej Amidze już tak się nie nazywa).

Przejdźmy teraz do kolejnej funkcji, służącej do komunikowania się z użytkownikiem. Funkcja ta pojawiła się w systemie operacyjnym 2.0. Są dwa sposoby jej przywołania:

Long EasyRequestArgs(struct Window *window, struct EasyStruct *easyStruct, ULONG *idcmpPtr, APTR args);
Long EasyRequest(struct Window *window, struct EasyStruct *easyStruct, ULONG *idcmpPtr);

Zadaniem tej funkcji jest zapytanie użytkownika o zdanie, lub też przekonanie go do wykonania jakiejś czynności - robi to ona przy użyciu "okna dialogowego", zwanego popularnie requesterem. Funkcja przekazuje sterowanie do programu w chwili, gdy zostanie puszczony gadżet, lub w chwili, gdy nastąpi wydarzenie wskazane przez program.
Struktura "EasyRequest" opisuje requester, można ją znaleźć w pliku "intuition/intuition.h"

struct EasyStruct
{
ULONG es_StructSize;
ULONG es_Flags;
ULONG es_Title;
ULONG es_TextFormat;
ULONG es_GadgetFormat;
};

Pole "es_StructSize" jest przygotowane na wyrost, to znaczy twórcy nastawili się na rozszerzenie tej struktury w przyszłości - należy tam podać rozmiar użytej struktury "EasyRequest", czyli sizeof(struct EasyRequest). Kolejne pole też jest przygotowane "na wyrost", to znaczy, że jeszcze nie jest ono wykorzystywane (OS 3.1), i na razie należy tam trzymać zero.

W polu "es_Title" znajduje się napis, który ma być nazwą okna requestera.

Napis "es_TextFormat" to treść komunikatu, wyświetlana wewnątrz okna. Mogą w niej wystąpić znaki formatujące, podobne jak w przypadku standardowej printf(), właśnie dlatego funkcja EasyRequest ma zmienną liczbę argumentów - po prostu należy gdzieś podać dane do formatowanego napisu (UWAGA: nie są obsługiwane liczby zmiennoprzecinkowe, a aby wyświetlić liczbę całkowitą trzeba użyć "%ld", a nie "%d"). Napis ten może zawierać kilka linii, należy je oddzielić znakiem nowej linii "\n". Napis jest formatowany od lewej krawędzi requestera.

Możliwe odpowiedzi należy umieścić w napisie "es_GadgetFormat", napisy do kolejnych gadżetów oddziela się pionowymi kreskami "|".
Napis ten nie może być pusty, musi zawierać przynajmniej jedną odpowiedż.

Jednym z argumentow funkcji EasyRequest() jest wskaźnik na okno, z którym ma byc związany requester. Podając adres okna, wybiera się ekran, na którym requesterem się ukaże. W wypadku podania wartości NULL requesterem ukaże się na standardowym ekranie publicznym. Gdy pole "es_Title" będzie równe NULL, nazwa okna requestera będzie taka sama, jak okna podanego w parametrze "window" bądź "SystemRequest", gdy i ten parametr będzie równy NULL.

Argument "IDCMP_ptr" to wskaźnik na zmienną typu ULONG, w której przechowywane są flagi, opisujące, jakie wydarzenie ma spowodować automatyczne zamknięcie requestera (bez klikania na którąkolwiek z odpowiedzi).

Wynikiem funkcji jest liczba typu LONG. Jej wartość to numer wybranej odpowiedzi, które są numerowane od lewej do prawej, przy czym ta znajdująca się najbardziej z prawej ma zawsze numer 0 - jest to odpowiedź negatywna. Najlepiej to zobaczyć: 1, 2, ..., N-1, 0 (gdzie N jest liczbą możliwych odpowiedzi). Funkcja może zwrócić wartość równą -1, gdy nastąpiło wydarzenie opisane w parametrze "IDCMPptr".

Warto wpomnieć, że gdy kilka urządzeń logicznych korzysta z jednej stacji (sprzętowo), to włożenie lub wyjęcie dysku powoduje kilkakrotne wygenerowanie wiadomości IDCMP_DISKINSERTED / REMOVED. Zapewne przekonali się o tym Ci z Was, którzy korzystają z "PC0:" bądź "DS0:" - listing 5 każe wtedy kilkakrotnie oddać wyjęty dysk.

Na dziś wystarczy, za miesiąc nauczymy się otwierać ekrany samodzielnie.