<!doctype linuxdoc system>

<article>

<title>X Window System FAQ
<author>
 Codematic, Przemek Borys
<date>wersja 25.12.2000 15:25
<abstract>
 Ten dokument byc moze pomoze Ci w znalezieniu odpowiedzi na pytania 
 dotyczace uzytkowania, konfigurowania oraz programowania X Window System.
</abstract>

<toc>
<sect>Informacje o XFAQ
<p>
<tscreen><verb>
/*
 * pl.comp.sys.xwindow
 *
 * X Window System FAQ
 *
 *
 * Autorzy:
 *  Codematic - mmochol@elka.pw.edu.pl - pierwszy opiekun FAQ
 *  Przemek Borys - pborys@dione.ids.pl - obecny opiekun FAQ
 *  Gwidon S. Naskrent - naskrent@hoth.amu.edu.pl
 *  Michał Kuratczyk - kura13@kki.net.pl - Afterstep
 *  Marcin Lewandowski (jaskier@mat.uni.torun.pl) - KDE FAQ
 *
 *
 * wersja 25.12.2000 15:25
 *
 * Zawsze aktualną wersję FAQ możesz znaleźć na:
 *  http://xfaq.linux.pl/
 */
</verb></tscreen>

<P>
<tscreen>
Codematic
</tscreen>

<p>
	FAQ (ang. Frequently Asked Questions) wlasnie w tej chwili czytasz.
Znajdziesz w nim opis systemu X Window System w pytaniach i odpowiedziach, 
ktory byc moze pomoze Ci w zrozumieniu/skonfigurowaniu/wykorzystaniu X-ow.

<p>
	Wszelkie komentarze, artykuły i sugestie prosimy kierować e-mailem
na w/w adresy autorów. Nie chcemy żeby to było lame-faq, więc jeśli
znajdziesz tu jakiś błąd lub nieścisłość, to proszę nie wyśmiewaj się z
naszej indolencji, tylko po prostu prześlij nam info.

<p>
	Od niedawna FAQ jest też dostępne na CVS cvs.pld.org.pl
(repozytorium xfaq); jeśli masz w repozytorium dostęp r/w, przeczytaj
instrukcje CZYTAJ.CVS, która pokazuje jak dodawać nowe artykuły do FAQ.

<p>
	Najświeższą wersję FAQ znajdziesz na:

<tscreen>
	<tt/http://xfaq.linux.pl/
</tscreen>

<sect>Ogólnie o X
<sect1>
<P>
<tscreen>
Nie podano autora</tscreen>
<sect1>Co to jest X Window System
<P>
<tscreen>
Codematic
</tscreen>
<P>

	Cytat z mana:
"X Window System jest 'przezroczystym sieciowo' systemem okienkowym, 
który działa na dużej liczbie komputerowych i graficznych maszyn.
Powinno być stosunkowo prosto skompilować oprogramowanie z X Consortium
na większosci systemow zgodnych z C i POSIX. Dostępne są rownież
komercyjne implementacje na dużej liczbie platform.".
<P>
	Mam nadzieję, że ten opis jest stosunkowo przejrzysty.
Zapraszam tez do pierwszej części tutoriala "X Window System dla 
opornych" umieszczonego w tym FAQ, ktory - być może - wprowadzi
Was w X Window System.
<P>
	Wyjaśnić też trzeba na początku, że X to nie jest jakiś
program, albo system operacyjny. X to jest zbiór protokołów, tak jak
telnet, ftp, http, ktore pozwalają na zbudowanie rozproszonego 
systemu okienkowego. Musimy tez powiedziec że X jest oparty na 
technologii klient-serwer. X Server to program, ktory działa na 
Maszynie użytkownika. Akceptuje on połączenia z różnych maszyn,
wyświetlając okienka. Po sieci przekazywane są informacje o kliknięciu
myszką, zdarzeniach klawiatury - od X Servera do X Clienta. X Client
to jest program napisany dla X. On z kolei wysyła do X Servera polecenia
narysowania okienka, itd. X Server i X Client moga oczywiscie byc na
różnych maszynach. No, to tyle jesli chodzi o podstawy.
<P>
	I nie należy pisać X-Windows.
<P>
Aha, chciałbym również powiedzieć co jest - moim zdaniem - największą
wadą X. Otóż, sądzę że największą wadą X jest to, że jest ... za darmo.
Tak tak, zerowy marketing i reklama spowodowały że jest to naprawdę
dobry, ale niedoceniony system. W chwili powstawania wyprzedzał swoją
epokę (podobnie jak MacIntosh). Wlaściwie bez większych zmian ta sama
specyfikacja, te same kody źródłowe sprzed 10 lat (!) są wykorzystywane 
do czegoś, co z powodzeniem konkuruje z dzisiejszymi, firmowymi systemami.
Wydaje mi się, że z chwilą upowszechnienia się Linuxa/FreeBSD, gdy sami
dowiecie się więcej o X, zaczniecie się zastanawiać nad tym paradoksem.

<sect1>Na jakich platformach działa X
<P>
<tscreen>
Codematic
</tscreen>
<P>
	Jak już wspomniałem - na dużej liczbie platform. To znaczy
na większości. Będąc bardziej precyzyjnym - trudno znaleźć platformę,
na której X nie działa. Systemy zgodne z C i POSIX oznaczają praktycznie
wszystkie poważniejsze Unixy. Sa X Serwery dla DOS, Windows (95/NT),
OS/2. X działa na QNX. Czyli wlaściwie wszystkie liczące się systemy 
dla platformy Intela. Natomiast na innych procesorach X jest najczęściej
dostarczane razem z systemem operacyjnym przez producenta - po co 
wyważac otwarte drzwi i tworzyć GUI od nowa.



<sect1>Czy X może się przydać w domu
<P>
<tscreen>
Codematic
</tscreen>
<P>
	Oczywiście że X może się przydać w domu. Mimo, że jest to
w zasadzie system sieciowy, to jednak nic nie stoi na przeszkodzie,
żeby używać go na jednej maszynie. W praktyce X nazwano okienkami
dla Unixa - nieco niepoprawnie wprawdzie, jednakże dobrze to oddaje
czym jest X. X w domu może slużyć do zabawy, pracy i w ogole do 
korzystania z komputera.
<P>
	X jest bardzo zaawansowany graficznie. Jest naprawdę dobry
do np. zastosowań CAD, ze względu na wykorzystanie mozliwosci
akcelelatorów sprzętowych na większości X Serwerów. X przewiduje
również protokół PEX do grafiki 3D - który tym się różni od np. 
OpenGL i DirectX - ze jest na niższym poziomie. Niestety mało kto
słyszał o PEX i nie widziałem na niego żadnej gry :-(

<sect1>Dlaczego warto postawić na X w mojej firmie
<P>
<tscreen>
Codematic
</tscreen>
<P>
	X to nie to samo, z czym powszechnie kojarzy sie nam Windows.
Windows byl to na poczatku graficzny interfejs uzytkownika, o sieci
wtedy nikt nie myslal. Natomiast X to zupelnie co innego. X jest
sieciowy. Wiekszosc z Was slyszala zapewne o Javie oraz o idei komputera
sieciowego (NetPC, NC, Network Computer). Wiecie dlaczego te pomysly sa
tak atrakcyjne ? Bo pozwalaja zapomniec o klopotach z konfiguracja dla
poszczegolnych uzytkownikow. Pozwalaja tez zaoszczedzic na twardych
dyskach. Mowimy wiec o braku klopotow z awariami i konfiguracja.
<P>
	X tym sie rozni od Javy, ze na komputerze uzytkownika nie musza
byc uruchamiane zadne programy. Oznacza to oszczednosc - wystarczy nam
zwykly i386, zeby uruchomic np. XAppeal i uzyskac w pelni funkcjonalna
stacje robocza. Mowimy zatem o kosztach. Pokazmy na przykladzie malutkiej
sieci jak przedstawiaja sie typowe rozwiazania w firmach, a jak mogly by
byc rozwiazane przy uzyciu X. Jako system operacyjny w tym drugim
przypadku niech to bedzie Linux (badz FreeBSD).
<P>
	[... Jeszcze coś tu napiszę...]

<sect1>Czym różni się X od Ms Windows i dlaczego to nie to samo
<P>
<tscreen>
Codematic
</tscreen>
<P>
	Podstawową różnicą jest to, że X'y są sieciowe, a Windows nie.
Jak to ? - krzykną windziarze - przecież Windows mają obsługę sieci !
Ale nie o to chodzi. X Window jest rozproszone, programy dla X mogą
się wykonywać na innej maszynie, niż tej przy której siedzi użytkownik.
<P>
	Po drugie, Windows jest raczej interfejsem użytkownika, środowiskiem
dla programów, taką "nakładką" na system operacyjny (DOS lub NT). 
Natomiast X to protokól sieciowy, pozwalający na zbudowanie takiego 
interfejsu. X'y są bardzo elastyczne, można w nich zmienić dokładnie
wszystko, od kursora po kształt okienek (nazywa się to Shape Extensions).
<P>
	Najbardziej mi się podoba to, że X'y mogą wyglądać jak dowolne 
inne srodowisko. Wystarczy, że zmienimy Window Managera i mamy coś, co
do złudzenia przypomina nam Microsoft. Instalujemy CDE lub KDE i 
otrzymujemy coś absolutnie innego, zupełnie niepodobnego do poprzedniego
środowiska. X'y mogą wyglądać jak NextStep, jak Amiga, albo jak konsola
Enterprise ze StarTrek - jeśli tylko chciało by się Wam napisać
odpowiednie GUI ;-)
<P>
	Poza tym X'y nic nie wymuszają. Programy dla X mogą teoretycznie
dzialać na różnych maszynach, na dowolnym systemie operacyjnym. Powtarzam,
X to protokół, a nie OS ! Tak jak ftp, klient X Window teoretycznie 
może działać na dowolnym systemie operacyjnym. Teoretycznie, bo ja słyszałem 
tylko o wersjach na różne Unixy oraz OS/2. Ale jest to możliwe. 
Open standard... Programy dla X mogą dowolnie korzystać ze środowiska 
w którym pracują. Np. jednocześnie mogą wyświetlać okienka na ekranie 
OS/2 ...
<P>
	Nie inaczej się rzecz ma z Xserwerem. Odsyłam do odpowiedniego
pytania w FAQ (Chcę X'y pod...). Sa X Servery dla najróżniejszych
systemów operacyjnych i tu się rzecz ma zdecydowanie lepiej niz z
xclientami. 
<P>
	Powtórzę jeszcze jedną myśl: X'y nie są interfejsem użytkownika.
Natomiast można sobie na nich taki interfejs zbudować.
<sect1>Co to jest XFree86 1 2 3 4 5 6
<P>
<tscreen>
Codematic
</tscreen>
<p>
	Oryginalny kod systemu X Window został stworzony W MIT,
później komercyjne firmy zaakceptowały go jako przemysłowy standard
na platformę Unix. XFree86 jest darmowym, do dowolnego rozpowszechniania
przeniesieniem (port) MIT X Window System X11R6 na systemy 80386/80486/
Pentium, pierwotnie zaprojektowanym przez zespół programistów pod 
przewodnictwem Davida Wexelblata &lt;dwex@XFree86.org>. Implementacja ta 
znana jako XFree86 jest dostępna na SystemV/386, 386BSD, oraz innych
Unixow x86, w tym Linuxa. Dystrybucja zawiera wszystkie potrzebne narzędzia,
biblioteki i pliki. Więcej informacji znajdziecie na

	&lt;http://www.XFree86.org>

Większość informacji w tym FAQ odnosi się właśnie do tej implementacji
X-ow.

<sect>Instalacja i konfiguracja X Window System
<sect1>
<P>
<tscreen>
Nie podano autora</tscreen>
<sect1>Skąd wziąć X
<P>
<tscreen>
Gwidon</tscreen>
<p>
X-y (darmowe!) można pobrać z www.xfree86.org lub polskich ftp
z dystrybucjami Linuxa (polecam sunsite.icm.edu.pl/pub/Linux lub
ftp.pwr.wroc.pl/pub/Linux)

Typowa instalacja wymaga około 8-10 MB: około 2 MB na serwer (plik
XF86_xxx, zależy od karty graficznej), tyle samo na różne dodatki
obsługujące serwer, 3-4 MB na fonty. Przydadzą się też contriby, jakiś
window manager, no i oczywiście xterm (niektóre dystrybucje mają go
już załączonego). W przypadku źródeł potrzebne będzie niestety znacznie
więcej miejsca :-(

Alternatywnie - kupić płytkę CD dołączaną do któregoś z czasopism
komputerowych, najpewniej Linux+ (są tam źródła).

/* Text under construction */

Serwerów X można szukać również na http://www.suse.de. /* ad. PB */<sect1>Jak zrobic zeby cos zaczelo dzialac
<P>
<tscreen>
Gwidon
</tscreen>
<p>
Żeby wszystko działało, potrzeba odpowiednio rozmieścić katalogi. W
przypadku dystrybucji binarnych najczęściej wszystko rozpakuje się samo
gdzie trza. Jeśli przetwarzaliśmy źródła - make install, ewentualnie
jeśli nie mamy tej możliwości:

* tworzymy sobie $XDIR, np. /usr/X11R6/. Na systemach U**ixowych dobrze
jest ustawić /usr/X11/ jako link symboliczny do w/w.

* binaria idą do $XDIR/bin, biblioteki do ../lib, includes do .../include,
fonty do   ../lib/fonts/&lt;katalogi>

* to co jest oznaczone jako &lt;share> ląduje w /usr/share/X11(R6).

Żeby uruchomić X, musimy jeszcze mieć XF86Config, .xinitrc, a najlepiej
także jakiegoś window managera.

<sect1>O co chodzi w XF86Config
<P>
<tscreen>
Przemek Borys
</tscreen>
<p>

0. Do wielu zastosowań nie potrzebujesz zagłębiać się w ten plik
samodzielnie. Możesz użyć programu XF86Setup, który zautomatyzuje proces
konfiguracji, uruchomiając roboczo X-y w najsłabszej możliwej konfiguracji.
Możesz tam swobodnie wybrać sobie kartę video, typ monitora, klawiaturę itd.
Iście po windziarsku :)
Możesz także użyć programu "xf86config", który przeprowadza konfigurację w
trybie tekstowym. (ma niezbyt ładny interfejs).

Poza tym, musisz wiedzieć, że plik konfiguracyjny to nie wszystko.
Ostatnie produkcje kart wideo wykazują spore różnice w obsłudze chipsetów,
a co za tym idzie, być może będziesz musiał dla swojej karty poszukać
osobnego serwera X. (patrz rozdział `Skąd wziąć X').

1. Teraz zrobimy sobie mały spacerek po żywym pliku XF86Config, i omówimy
wszystko co tam jest. Zaczynamy.

<verb>
#
# Copyright (c) 1995 by The XFree86 Project, Inc.
#
</verb>

Na początek, jak zresztą nietrudno się domyślić, powiedzmy że znaczek '#'
oznacza początek komentarza, który kończy się na końcu linii.

<verb>
Section "Files"
</verb>

Tu widzimy pewne słówko kluczowe. Mianowicie "Section". Wszystko w pliku
XF86Config jest zgrupowane w sekcje. Jest sekcja opisująca pliki, sekcja
opisująca klawiaturę, itd. Nazwy sekcji (tu "Files") są też ważne - dzięki
nim konfigurator orientuje się co chcemy definiować. Sekcja "Files" służy 
do zdefiniowania ścieżek do różnych ważnych plików, tj. bazy kolorów 
zdefiniowanych przez RGB, oraz ścieżki do fontów. Np:

<verb>
    RgbPath	"/usr/X11R6/lib/X11/rgb"
    FontPath   "/usr/X11R6/lib/X11/fonts/misc/"
    FontPath   "/usr/X11R6/lib/X11/fonts/75dpi/:unscaled"
    FontPath   "/usr/X11R6/lib/X11/fonts/Type1/"
    FontPath   "/usr/X11R6/lib/X11/fonts/Speedo/"
    FontPath   "/usr/X11R6/lib/X11/fonts/75dpi/"
</verb>

Można opcjonalnie tez zdefiniować ścieżkę do modułów ładowanych dynamicznie,
np:

<verb>
    ModulePath "/usr/X11R6/lib/modules"
</verb>

Po zakończeniu definiowania określonej sekcji, uzywamy słówka kluczowego
"EndSection", np:

<verb>
EndSection
</verb>

Przejdźmy do następnego elementu naszego spaceru - opcjonalny fragment:

<verb>
# Section "Module"
# Load "xf86Jstk.so"
# EndSection
</verb>

Sekcja ta umożliwia doładowywanie dynamicznych modułów (driverów) w sposób
pokazany dla modułu o nazwie "xf86Jstk.so" (moduł obsługi joysticka).

Kolejna sekcja to

<verb>
Section "ServerFlags"
</verb>

Która opisuje różne właściwości serwera. Są to kolejno:

<verb>
#    NoTrapSignals
</verb>

Powoduje uwrażliwienie serwera na nieprzewidywane sygnały i zarzucanie core.
Przydatne do debugowania programów.

<verb>
#    DontZap
</verb>

Powoduje wyłączenie sekwencji ctrl+alt+bckspc killującej serwer.

<verb>
#    DontZoom
</verb>

Powoduje wyłączenie przełączania się między trybami video z pomocą szarego
plusa i minusa.

<verb>
#       DisableVidModeExtension
</verb>

Uniemożliwia dostrajanie trybu video za pomocą "xvidtune".

<verb>
#       AllowNonLocalXvidtune
</verb>

Umożliwia wywołanie "xvidtune" z maszyny innej niż lokalna. Domyślnie jest
to zabronione.

<verb>
#       DisableModInDev
</verb>

Uniemożliwia dynamiczne modyfikowanie urządzeń wejściowych (myszy lub
klawiatury).

<verb>
#       AllowNonLocalModInDev
</verb>

Uniemożliwia dokonywania zdalnych modyfikacji urządzeń wejściowych.


Teraz skręćmy w ulicę (pamiętajmy że spacerujemy ;) o nazwie

<verb>
#Section "Keyboard"
</verb>

Jak widać, sekcja ta opisuje parametry klawiatury i rzeczy z nią związanych.
Oto one:

<verb>
#    Protocol	"Standard"
</verb>

Definiuje to protokół, w jakim obsługiwana jest klawiatura. Poza "Standard",
może być jeszcze "XQueue". (używane na SVR4 i SVR5).

<verb>
#    AutoRepeat	500 5
</verb>

Określa częstość samopowtarzania klawiatury (tu cyfra 5), oraz opóźnienie 
przed rozpoczęciem samopowtarzania (tu 500). Czasem to nie działa.

<verb>
#    ServerNumLock
</verb>

Serwer obsługując klawiaturę przy ustawionej tej opcji, w zależności od
stanu num-locka, traktuje keypad jako keypad, lub klawiaturę numeryczną.

[komentarz od Gwidona S. Naskrenta]
Jeśli chcemy wprowadzać znaki z Altem, musimy wyłączyć ServerNumlock.
Niestety nie da się łatwo wymusić działania NumLocka jak w Win, bowiem
może mu (klawiszowi) być przypisany dowolny klawsym, nie tylko NumLock.
[koniec komentarza]

<verb>
#    Xleds      1 2 3
</verb>

Ta opcja występuje z parametrem (parametrami) liczbowymi, określającymi
numer diody (Scroll Lock, Caps Lock, Num Lock), którą serwer ma oddać do 
użytku klientom (programom pod X), zamiast samodzielnie korzystać z jej
standardowej funkcji.

<verb>
     LeftAlt	Meta
     RightAlt	ModeShift
     ScrollLock Compose
     RightCtl  Control
</verb>

Te opcje umożliwiają przemapowywanie funkcji klawiszy. Np. lewy alt
traktowany jest jako klawisz "meta" - tj. normalny alt, a prawy alt jest
używany do np. pisania polskimi literkami.

<verb>
#   XkbDisable
</verb>

Wyłącza rozszerzenia XKEYBOARD

<verb>
#    XkbRules    "xfree86"
</verb>

Definiuje plik z regułami, na podstawie którego korzystać z komend dla
niektórych pól sekcji keyboard.

<verb>
#    XkbModel    "pc102"
</verb>

Ustawia model klawiatury. Może być np. "pc102", "pc101", "microsoft" itd.
Sprawdź najlepiej plik /usr/X11R6/lib/xkb/rules/xfree86 (sekcja "model"). 

<verb>
#    XkbLayout   "de"
</verb>

Ustawia układ klawiatury. W tym wypadku niemiecki. Może być też "us" -
amerykański. Znowu - definicje są w pliku /usr/X11R6/lib/xkb/rules/xfree86
(sekcja "model layout").

<verb>
#    XkbVariant  "nodeadkeys"
</verb>

[Odpowiada Gwidon S. Naskrent]
Wariant 'nodeadkeys': wyłączone jest ustawienie klawsymów typu deadacute
(tu domyślnie Control - '). Deadkeys pozwalają uzyskać akcentowane znaki
poprzez złożenie akcentu i litery. Definicje są identyczne jak na konsoli
(patrz źródła programu loadkeys).
[koniec]

<verb>
#    XkbOptions  "grp:toggle"
</verb>

Definiuje różne opcje klawiaturowe. Jak zwykle dostępne są zdefiniowane w
pliku z regułami (/usr/X11R6/lib/xkb/rules/xfree86) jako odnośniki do pliku
z symbolami. Przykład powyżej przełącza pod prawym altem klawiaturę z grupy
znaków podstawowego zbioru na zbiór drugi i na odwrót. (wszystko jest
napisane w odpowiednich plikach z symbolami).

<verb>
#    XkbKeymap   "xfree86(us)"
</verb>

Ustala mapowanie klawiszy na określone symbole.


Czas przejść do następnej sekcji. Będzie to

<verb>
Section "Pointer"
</verb>

sekcja opisująca urządzenie wskazujące - tj. w większości wypadków myszkę.

<verb>
    Protocol    "Microsoft"
</verb>

Protokół według którego X-y mają się porozumiewać z myszką. (może być
"Microsoft", "BusMouse", "Logitech", "MMSeries", "Mouseman", "MouseSystems",
"PS/2", "MMHitTab", "GlidePoint", "XQueue", "OSMouse"). Zazwyczaj mamy do
czynienia z myszami "Microsoft".

<verb>
    Device      "/dev/mouse"
</verb>

Określa urządzenie przez które komunikujemy się z myszą. Tu "/dev/mouse".

<verb>
#    BaudRate	9600
#    SampleRate	150
</verb>

Te wartości potrzebne są tylko niektórym myszom Logitech. Baudrate określa
szybkość transmisji danych między myszką a komputerem. Standard to 1200.
Samplerate określa częstość wywoływania zdarzeń poruszenia myszą/naciśnięcia
guzika w systemie.

<verb>
# Emulate3Buttons
</verb>

Emuluje trzeci guzik na dwuguzikowych myszkach poprzez naciśnięcie ich obu
naraz.

<verb>
# Emulate3Timeout 50
</verb>

Określa czas po którym serwer stwierdza, że dwa klawisze rzeczywiście były
wciśnięte razem. Czas podaje się w milisekundach.

<verb>
#    ChordMiddle
</verb>

Trzeba ustawić tą opcję przy myszach Logitech, które wciśnięcie środkowego
klawisza traktują jako wciśnięcie naraz lewego i prawego.


Teraz przejdziemy do kolejnej sekcji - opcjonalnej - konfigurującej
dodatkowe urządzenia wejściowe, np. joystick.

<verb>
# Section "Xinput" 
</verb>

Ta sekcja nazywa się jak widać "Xinput". Wszelkie urządzenia wejściowe
konfigurujemy dalej w _podsekcjach_, nie w ciele nadrzędnej sekcji. Np:

<verb>
Subsection "Joystick"
Endsubsection
</verb>

Dalsze opisy będą bazować na konfiguracji joysticka - poza nim X-y obsługują
również urządzenia takie jak "WacomStylus", "WacomCursor", "WacomEraser",
"Elographics", "Mouse". Tak! Można tu skonfigurować również mysz :) (na
zasadach takich jak w sekcji "Pointer".
Wróćmy jednak do konfiguracji joysticka.

<verb>
#        Port "/dev/joy0"
</verb>

Określa urządzenie z którego korzystać do komunikowania się z joystickiem.

<verb>
#        DeviceName "Joystick"
</verb>

Ustawia nazwę dla tego X-urządzenia.

<verb>
#        TimeOut 10
</verb>

Milisekundowy okres między kolejnymi akcjami sterownika joysticka.

<verb>
#        MinimumXPosition 100
#        MaximumXPosition 1300
#        MinimumYPosition 100
#        MaximumYPosition 1100
#        # CenterX 700
#        # CenterY 600
</verb>

Określa współrzędne zwracane przez sterownik zależnie od wychylenia
joysticka.

<verb>
#        Delta 20
</verb>

Określa czułość joysticka.


A teraz zaczyna się dopiero zabawa. Przechodzimy do pierwszej sekcji 
definiującej wizję.

<verb>
Section "Monitor"
</verb>

Jest to sekcja opisująca monitor.

<verb>
    Identifier  "My Monitor"
</verb>

Tu podajemy identyfikator, którym będzie się można później posługiwać w tym
pliku. (Można zdefiniować wiele monitorów, więc trzeba je jakoś rozróżnić).

<verb>
    VendorName  "Unknown"
    ModelName   "Unknown"
</verb>

Opcjonalne pola, określające producenta i model sprzętu.

<verb>
    HorizSync   31.5, 35.15, 37.8
</verb>

Określa dostępne częstotliwości poziome monitora w kHz. (Częstotliwość
pozioma, to ilość rysowanych linii poziomych na sekundę). Musisz sprawdzić
jak pisze w dokumentacji twojego monitora.

<verb>
#    HorizSync	30-64         # multisync
</verb>

Tak (z kreseczką) podajemy te wartości dla monitorów multisync.

<verb>
    VertRefresh 50-90
</verb>

Częstotliwość pionowa monitora w Hz. Częstotliwość pionowa to ilość
rysowanych ekranów obrazu na sekundę.

<verb>
#    ModeLine "1024x768" 45 1024 1048 1208 1264 768 776 784 817 Interlace
</verb>

Określa przykładowy tryb video dla danego monitora. Kolejne parametry tego
pola to:

"1724x768" - nazwa trybu (używana wewnątrz pliku konfiguracyjnego)
45         - impuls punktu - Częstotliwość w MHz z jaką stawiane są punkty.
1024       - szerokość widzialnego obrazu.
1048       - początek repozycjonowania (synchronizacji - stąd sync) poziomego.
1208       - koniec repozycjonowania poziomego.
1264       - całkowita długość linii.
768        - wysokość widzialnego obrazu.
776        - początek repozycjonowania pionowego wiązki elektronów.
784        - koniec repozycjonowania pionowego.
817        - całkowita wysokość obrazu.
Interlace  - włącza tryb interlaced dla danego trybu video. Gdy tej opcji
             nie będzie, tryb będzie normalny, nie-interlaced. Poza
             "interlace" są jeszcze inne flagi, np. "DoubleScan",
	     określający, że każda linia jest podwojona, i inne. (man
	     XF86Config)

<verb>
    Mode "1024x768"
        DotClock	45
        HTimings	1024 1048 1208 1264
        VTimings	768 776 784 817
        Flags		"Interlace"
    EndMode
</verb>

Powyżej mamy alternatywną formę jednoliniowej definicji trybu video.


Monitor mamy z głowy. Teraz przejdźmy do następnej sekcji,

<verb>
Section "Device"
</verb>

do określenia urządzenia video, karty graficznej.

<verb>
    Identifier	"Generic VGA"
</verb>

Identyfikator, którym będziemy się posługiwać wewnątrz pliku
konfiguracyjengo. (można zdefiniować wiele kart graficznych, i wtedy trzeba
je jakoś rozróżnić).

<verb>
    VendorName	"Unknown"
    BoardName	"Unknown"
</verb>

Opcjonalne pola określające producenta i nazwę karty graficznej.

<verb>
    Chipset	"generic"
</verb>

To pole określa, z jakiego chipsetu korzystać. Jest to opcjonalne -
normalnie serwer sam to sprawdza.

<verb>
#    VideoRam	256
</verb>

Wielkość pamięci RAM karty video.

<verb>
#    Clocks	25.2 28.3
</verb>

Dopuszczalne impulsy punktu oferowane przez kartę.

A oto dodatkowe, opcjonalne pola dopuszczalne w tej sekcji:

<verb>
#    Ramdac	"ATT20C490"
</verb>

Określa model RAMDAC-a (przetwornika video RAM na sygnał dla monitora) 
używanego na karcie. Normalnie X serwer wykrywa go automatycznie.

<verb>
#    Dacspeed	110
</verb>

Szybkość RAMDAC-a w MHz. To pole jest również domyślnie wykrywane
automatycznie.

<verb>
#    Option	"dac_8_bit"
</verb>

To pole umożliwia wykorzystanie opcji dawanych przez konkretny sterownik.
Można używać wielu takich pól w sekcji.

Poza wyżej wymienionymi polami, jest ich jeszcze kilka opisanych w manualu
od XF86Config, ale chyba nie są one zbyt istotne, skoro nie ma ich w
przykładowym pliku konfiguracyjnym, po którym właśnie robimy spacerek. :)


Pozostała nam już ostatnia sekcja - sekcja opisująca ekran. Nie kartę video,
nie monitor, lecz to co się liczy dla użytkownika - obraz na ekranie.

<verb>
Section "Screen"
</verb>

Sekcja ta nazywa się "Screen". Oto pola w niej dostępne:

<verb>
    Driver      "svga"
</verb>

Definiuje z jakiego serwera korzystamy w tej sekcji (bo znowu - sekcji
"screen" może być wiele). Może to być "svga", "accel", "mono", "vga2", 
"vga16".

<verb>
    Device      "Trident 8900/9000 (generic)"
</verb>

Tutaj określamy, z jakiej karty graficznej chcemy korzystać. Jako parametr
pola "Device" podajemy identyfikator karty video, który zdefiniowaliśmy
wcześniej w sekcji "Device".

<verb>
    Monitor     "My Monitor"
</verb>

Tu określamy, z jakiego monitora chcemy korzystać. Jako parametr pola
"Monitor" podajemy identyfikator monitora, który wcześniej zdefiniowaliśmy w
sekcji "Monitor".

<verb>
   DefaultColorDepth	8
</verb>

Ten parametr określa domyślną głębie koloru. Tu ustawiono kolor 8-bitowy.

<verb>
   BlankTime	       10
</verb>

Określa okres (w minutach) po którym włączyć wygaszacz ekranu.

<verb>
    Subsection "Display"
</verb>

Sekcja "Screen" jest tak obszera, że potrzebuje podsekcji. W podsekcji
"display", definiujemy z jakich trybów video i w jaki sposób można korzystać
dla danego zestawu sprzętowego.

<verb>
        Depth       8
</verb>

Określa głębię koloru dla tej podsekcji. (tu 8-bitowy).

<verb>
        Modes       "800x600" "640x480"
</verb>

Określa tryby, jakie są dostępne w tej podsekcji.

<verb>
        ViewPort    0 0
</verb>

Określa, jakie współrzędne ekranu mają się znaleźć w lewym górnym rogu (to
pole istnieje z uwagi na pole następne).

<verb>
        Virtual     800 600
</verb>

Określa wirtualny ekran, większy od tego, który widać na monitorze, który
można programowo przesuwać na fizyczny monitor.
<sect1>Czy jest jakas alternatywa dla recznego klepania pliku XF86Config 1 2 3 4 5 6 7 8 9
<P>
<tscreen>
Codematic
</tscreen>
<p>
	I owszem. Po pierwsze xf86config - ktory jest niezbyt "user
friendly". Trzeba po prostu odpowiadac na pytania. Po drugie XF86Setup, 
ktory jest "user friendly" i nie trzeba byc zbytnim ekspertem zeby
z niego korzystac...

Poza tym, w redhatach można spotkać programik Xconfigurator. /* ad PB */<sect1>Co zrobic kiedy obraz na monitorze brzydko sie zachowuje (za szeroki, nie miesci sie) i co ma do tego xvidtune 1 2 3 4 5 6 7 8 9
<P>
<tscreen>
Codematic
</tscreen>
<p>
	W pliku XF86Config jest taka sekcja Monitor. W tej sekcji mamy
takie linijki: Modeline i rozne cyferki. Widzicie ? To sa parametry 
danego trybu, czestotliwosc odswiezania pionowego, poziomego i rozne 
takie. Na monitorach cyfrowych mozemy sobie ustawic dla kazdego trybu
te parametry, przesunac obraz w lewo, rozciagnac, etc. i w ten sposob
dopasowac ekran do X'ow. Natomiast na monitorach analogowych - owszem -
tez sobie mozna przesuwac ekran, ale - gdy wyjdziemy z X to tryb
tekstowy bardzo brzydko nam zjedzie... Wiec trzeba dopasowac X'y do 
monitora: uruchamiamy xvidtune i ustawiamy obraz tak aby sie nam spodobal
dla kazdego trybu - 640x480, 800x600, itd. Nastepnie widzimy ze xvidtune
pokazal nam rzad cyferek, zadziwiajaco podobnych do tych z XF86Config...
Wiec wpisujemy je do wlasciwej Modeline i zapisujemy XF86Config. Po
nastepnym uruchomieniu X powinno byc ok.
<sect1>Wlaczam X i mam szary ekran z krzyzykiem
<P>
<tscreen>
Gwidon
</tscreen>
<p>
Jeśli uruchomiłeś X-y przez X, to nie tak. X jest symlinkiem do domyślnego
serwera (u mnie XF86_SVGA), i samo jego wywołanie nie da nam nic. Trzeba
użyć xinit /* lub startx - ad. Codematic */ /* które uruchomią podstawowych
klientów dla naszego serwera - Przemek Borys */.

Domyślnie xinit wywoła jeden xterm i twm jako managera (dokładna
składnia w man xinit). Możemy mu wyperswadować to co chcemy używając
pliku ~/.xinitrc. Bardzo prosty plik może wyglądać tak:
<verb>
#!/bin.sh
xfstt --multi --unstrap & # jeśli mamy xfstt, p. niżej
xterm --geometry 80x20+100+100 --fn fixed & # pamiętaj o &
(tu wstawiamy window managera - exec fvwm, fvwm-95, mwm, kde)
</verb>
Pamiętaj żeby window manager wywołany był z .xinitrc przez exec;
inaczej serwer zakończy pracę tuż po starcie.

<sect1>Moje Xy są brzydkie... Buuu...
<P>
<tscreen>
Codematic
</tscreen>
<p>
	Kilka sposobów aby temu zaradzić:

1) Zainstaluj klon widgetów Atheny - Xaw3d, Xaw95 badz XawXPM.
 Ta ostatnia jest najładniejsza. W ten sposób starsze Xowe
 programy, beznadziejnie brzydkie, zaczynają powalać z nóg...

2) Zainstaluj jakiś fajny wm - polecam KDE, GNOME, Fvwm2, Afterstep.
 Odsyłam do odpowiedniego kawałka w FAQ.

3) Możesz pobawić się w zasoby. Pamiętaj że w X można zmienić wszystko,
 od kolorów i grubości kresek, po kształt okienek. Zasoby są w plikach
 w katalogach bieżących, domowych, lub app-defaults. Ich format jest w
 następnym pytaniu.
<sect1>Co to sa zasoby (resources)
<P>
<tscreen>
Codematic
</tscreen>
<p>
	Jest to sposób w jaki konfiguruje się wygląd programów
Xowych. Są trzymane w plikach w specjalnym formacie, albo w pamięci
Xservera. Z pliku do pamięci Xservera możemy wczytać zasoby poleceniem
xrdb -load "nazwapliku". Brak zasobów może spowodować że aplikacja 
zachowuje się dziwnie - ma beznadziejne kolorki, okienko monstrualnych 
rozmiarów, nieczytelne napisy, itp.

Rozważmy przykładowy plik zasobów:
<verb>
----------------------------------------------
! Plik Chooser z /usr/X11/lib/X11/app-defaults:

*ShapeStyle:		Oval
*cursor:		left_ptr
*allowShellResize:	true
*label.label:		XDMCP Host Menu
*label.borderWidth:	0
*label.skipAdjust:	true
*paned*showGrip:	false
!*viewport.horizDistance:	20
!*viewport.height:	200
*viewport.width:	400
*viewport.height:	50
*viewport.allowVert:	true
*viewport.fromVert:	label
*viewport.resizeable:	true
*viewport.allowResize:	true

*list.translations:	#override \
	&lt;BtnDown>:	Set() CheckWilling() \n\
	&lt;BtnUp>(2):	Accept()
*list.defaultColumns:	1
*list.forceFolumns:	true

*box.skipAdjust:	true
*cancel.fromHoriz:	viewport
*cancel.fromVert:	label
*cancel.vertDistance:	100
*cancel.bottom:		ChainBottom
*cancel.top:		ChainBottom
*cancel.left:		ChainRight
*cancel.right:		ChainRight

*accept.fromHoriz:	viewport
*accept.fromVert:	cancel
*accept.bottom:		ChainBottom
*accept.top:		ChainBottom
*accept.left:		ChainRight
*accept.right:		ChainRight

*cancel.translations:	#override \
	&lt;BtnUp>:		Cancel() unset()
*accept.translations:	#override \
	&lt;BtnUp>:		Accept() unset()
*ping.translations:	#override \
	&lt;BtnUp>:		Ping() unset()

--------------------------------------------------
</verb>

Widzicie ? Przydało by się wiedzieć co to jest widget. Jeśli tego nie
wiecie odsylam do "Co to są widgety (łopatologicznie) i jak je 
poustawiać". * pasuje do każdego tekstu, powoduje że można daną wartość
ustawić globalnie. Tzn.:

*foreground - mowi o tle gdziekolwiek, w każdym okienku, czy widgecie.

Natomiast np.

box.leftform.cancelpopup.foreground - mowi tylko o jednym tle, okienka
dialogowego cancel, wystepującego w jakimś okienku dialogowym w danej
aplikacji.

Zatem w zasobach można ustawić zarówno kolory, teksty na napisach, 
jak również "akcelelatory" - sekwencje z klawiatury.

I teraz kilka podstawowych nazw dla zasobow:

foreground, background - kolory tla.

width, height - szerokosc, wysokosc (okienka, widgetu)

borderWidth - grubosc ramki

label - tekst, napis
<sect1>Ogonki w X
<P>
<tscreen>
Gwidon
</tscreen>
<p>
Potrzebne są fonty. Dość poręczne można dostać ze strony Tomasza Kłoczko,
niestety bitmapowe mają tylko znaki polskie, nie całe iso-8859-2 (fonty
Type1 mają całość). Rozmiar około 3 MB. Fonty były na krążku Chipa 12/97
i sporadycznie w Linux+.

Rozpakujemy fonty (rpm -ivh) /* Jeśli mamy rpm'a - ad. Codematic */. 
Kasujemy te których nie chcemy używać (75 albo 100 dpi, zależnie od 
rozdzielczości). Istotne katalogi z fontami poza 100 czy 75dpi to misc, w
którym znajduje się m.in. najważniejszy font fixed. /* ad. PB */ Jeśli
mieliśmy fonty w .tar.gz, musimy w każdym katalogu dorobić wpisy do
font.dir (uruchamiając mkfontdir). Jeśli fonty nasze były w formacie bdf, to
powinniśmy je skonwertować do pcf używając programu <it/bdftopcf/. /* ad. PB */
Następnie poprawiamy  aliasy (zwłaszcza w katalogu misc). Na początek
wystarczy zmienić dwie pierwsze definicje (fixed i variable) zastępując 1 w
ostatniej kolumnie przez 2. Przydaje się też dopisać ścieżkę do nowych
fontów do pliku /etc/XF86Config. /* ad PB */

Odpalamy X i puszczamy jakiś plik tekstowy z ósmym bitem. Jeśli widzimy
polskie znaki, możemy już spróbować zmusić X (czy raczej część aplikacji)
do ich wprowadzania.

Piszemy sobie plik dla xmodmap. Podaję przykładowy niżej (dla wersji
starszych od 3.1.3 - dlaczego, patrz pod spodem). Uwagę należy zwrócić
na to że polskie znaczki oznaczone są przez 0xhh (hh - liczba
szesnastkowa).

W starszych wersjach jest to jedyna metoda wmówienia Xom o co
chodzi. Jeśli jednak ktoś ma Xy które rozumieją polskie locale
(od wersji 3.2), niech lepiej skorzysta z klawsymów (aogonek itp. -
pomocny może być program xkeycaps) - Z WYJĄTKIEM oacute, które
należy zakodować jako 0x1f3 0x1d3.

<verb>
!==========================================================================
!
! Polish keyboard (sort of). Variants for XFree86 > 3.2 included
!
! (with dead keys on ^'"`~ - use R_Alt+(Shift)+key
! Made by GSN (naskrent@hoth.amu.edu.pl)
! All suggestions welcome
!
!==========================================================================
clear Mod1
clear Mod2
keycode   9 = Escape Escape
keycode  10 = 1 exclam
keycode  11 = 2 quotedbl
keycode  12 = 3 numbersign
keycode  13 = 4 dollar
keycode  14 = 5 percent
keycode  15 = 6 asciicircum dead_circumflex
keycode  16 = 7 ampersand
keycode  17 = 8 asterisk
keycode  18 = 9 parenleft
keycode  19 = 0 parenright
keycode  20 = minus underscore
keycode  21 = equal plus
keycode  22 = BackSpace BackSpace
keycode  23 = Tab Tab
keycode  24 = q Q
keycode  25 = w W
! od 3.2 eogonek itd. (uw. na ż - zabovedot, nie zdot, per postscript)
keycode  26 = e E 0xea 0xca
keycode  27 = r R
keycode  28 = t T
keycode  29 = y Y
keycode  30 = u U
keycode  31 = i I
! od 3.2 wpisz 0x1f3 0x1d3
keycode  32 = o O 0xf3 0xd3
keycode  33 = p P
keycode  34 = bracketleft braceleft
keycode  35 = bracketright braceright
keycode  36 = Return
keycode  37 = Control_L
keycode  38 = a A 0xb1 0xa1
keycode  39 = s S 0xb6 0xa6
keycode  40 = d D
keycode  41 = f F
keycode  42 = g G
keycode  43 = h H
keycode  44 = j J
keycode  45 = k K
keycode  46 = l L 0xb3 0xa3
keycode  47 = semicolon colon
keycode  48 = apostrophe quotedbl dead_acute dead_diaeresis
keycode  49 = grave asciitilde dead_grave dead_tilde
keycode  50 = Shift_L
keycode  51 = backslash bar
keycode  52 = z Z 0xbc 0xac
keycode  53 = x X 0xbf 0xaf
keycode  54 = c C 0xe6 0xc6
keycode  55 = v V
keycode  56 = b B
keycode  57 = n N 0xf2 0xd2
keycode  58 = m M
keycode  59 = comma less
keycode  60 = period greater
keycode  61 = slash question
keycode  62 = Shift_R
keycode  63 = KP_Multiply
keycode  64 = Alt_L
keycode  65 = space space Multi_key
keycode  66 = Caps_Lock
keycode  67 = F1 F11
keycode  68 = F2 F12
keycode  69 = F3 F13
keycode  70 = F4 F14
keycode  71 = F5 F15
keycode  72 = F6 F16
keycode  73 = F7 F17
keycode  74 = F8 F18
keycode  75 = F9 F19
keycode  76 = F10 F20
keycode  77 = Num_Lock
keycode  78 = Help
keycode  79 = KP_7
keycode  80 = KP_8
keycode  81 = KP_9
keycode  82 = KP_Subtract
keycode  83 = KP_4
keycode  84 = KP_5
keycode  85 = KP_6
keycode  86 = KP_Add
keycode  87 = KP_1
keycode  88 = KP_2
keycode  89 = KP_3
keycode  90 = KP_0
keycode  91 = KP_Decimal
keycode  94 = less greater backslash
keycode  95 = F11 F11
keycode  96 = F12 F12
keycode  97 = Home
keycode  98 = Up
keycode  99 = Prior
keycode 100 = Left
keycode 101 = Begin
keycode 102 = Right
keycode 103 = End
keycode 104 = Down
keycode 105 = Next
keycode 106 = Insert
keycode 107 = Delete
keycode 108 = KP_Enter
keycode 109 = Control_R
keycode 110 = Pause
keycode 111 = Print
keycode 112 = KP_Divide
keycode 113 = Mode_switch
keycode 114 = Break

clear Shift
clear Control
clear Lock
clear Mod1
clear Mod2
clear Mod3
clear Mod4
clear Mod5

add Shift = Shift_L Shift_R
add Lock = Caps_Lock
add Control = Control_L
add Mod1 = Alt_L
add Mod2 = Mode_switch
=====================
</verb>

BTW: P. wyżej na rozwiązanie alternatywne w stosunku do ModeShift (Mod1 i
Mod2).

Plik ten trzeba wstawić do /usr/X11R6/lib/xinit/.Xmodmap, co ustawi tą mapę
globalnie, lub lokalnie .Xmodmap w katalogu domowym. /* ad. PB */

Taka zaimprowizowana klawiatura powinna działać we wszystkich programach
które nie są jakoś udziwnione (XEmacsa trzeba skonfigurować żeby dawał
ósmy bit, a nie jakieś meta-escape, ale to inny temat).

Co się zmieniło od wersji 3.2?

Przede wszystkim X rozumie że pracujemy 'po polsku', o ile poprawnie
ustawiliśmy zmienne LANG i LC_ALL. W związku z tym xmodmap nie chce już
przyjmować kodów ośmiobitowych jako oznaczeń klawsymów, lecz tylko
ich opisy (aogonek itd.). Wyjątkiem jest oacute, które występuje także
w ISO-8859-1 - dlatego wpisanie oacute do naszego pliku wywołałoby
znaczący sprzeciw Xserwera :) Prowizorycznie umówiono się że znaki z
ISO-8859-2 = znaki z ISO-8859-1 + 0x100h, i takie też wartości należy
tu wpisać.

Jak ustawić polską klawiaturę bez xmodmap?

Można użyć rozszerzeń xkb. Wystarczy użyc instrukcji `setxkbmap pl' lub
ustawić XkbLayout &dquot;pl&dquot; w pliku XF86Config w sekcji Keyboard.<sect1>Co to są widgety (łopatologicznie) i jak je poustawiać
<P>
<tscreen>
Codematic
</tscreen>
<p>
	Widget - łopatologicznie - to może być przycisk (button),
okienko dialogowe, lista, suwak, czyli po prostu element GUI.
Widgety mają strukturę drzewiastą. Ustawia je albo sama aplikacja,
albo można to zrobić w pliku zasobów danej aplikacji. Widget jest
obiektem, i zazwyczaj związane są z nim jakieś parametry. Np. dla
przycisku parametrami będą kolor tła, napisu, sam napis, wysokość i
szerokość. Wszystko to możemy ustawić nie zmieniając aplikacji.
	Jeżeli chcemy ustawić coś ręcznie, pomocny będzie program
editres. Jeśli tylko aplikacja korzysta z jakiegoś sensownego 
zestawu widgetów, który obsługuje protokół editres, to możemy
wyświetlić nazwę danego zasobu. Potem tę nazwę można tymczasowo
zmienić w samym editres, bądź na stałe w odpowiednim pliku zasobów.

	Weźmy przykład samego editres. Ma menu - Commands i Tree.
Chcemy żeby Commands nie nazywało się Commands, tylko Komendy. Więc szukamy.
Odpalamy dwie kopie editres, potem Commands/Refresh Current Widgets Tree. 
I klikamy na drugim editres. Pokazuje sie nam drzewko widgetow. Po niedlugim
szukaniu mozna zauważyć, że od widgetu 'box' odchodzą dwie gałęzie -
commands i commandsTree. Więc pewnie to jest nasze menu. Klikamy na
commands. Potem Commands/Show Resource Box. Widzimy listę parametrów
tego widgetu, więc klikamy na 'label', wpisujemy "Komendy", i Apply.
Hurra !!! :) Jeśli trafiliśmy, to widzimy że zasób nazywa się

>>>> .editres.paned.box.commands.label:

	Wystarczy wpisac do pliku z zasobami editresa:
(u mnie /usr/X11/lib/X11/app-defaults/Editres) linijkę

>>>> .editres.paned.box.commands.label:	Komendy

I już zawsze editres będzie pokazywał w menu: 'Komendy'.
<sect1>Metodologia w plikach: .xinit, .Xresource, startx, openwin
<P>
<tscreen>
Gwidon</tscreen>
<p>
----------------------------------------------
xinit - skrypt shella, poniżej mój przykładowy
<verb>
===========
#!/bin/sh
# $XConsortium: xinitrc.cpp,v 1.4 91/08/22 11:41:34 rws Exp $

userresources=$HOME/.Xresources
usermodmap=$HOME/.Xmodmap.pl
sysresources=/usr/X11R6/lib/X11/xinit/.Xresources
sysmodmap=/usr/X11R6/lib/X11/xinit/.Xmodmap

# update'ujemy domyślne zasoby

if [ -f $sysresources ]; then
    xrdb -merge $sysresources
fi

# i ładujemy klawiaturę

if [ -f $sysmodmap ]; then
    xmodmap $sysmodmap
fi

# jw., jeśli user ma swoje własne ustawienia

if [ -f $userresources ]; then
    xrdb -merge $userresources
fi

if [ -f $usermodmap ]; then
    xmodmap $usermodmap
fi

# startujemy co trza:

       xclock -geometry 50x50-1+1 &
       xterm -geometry 80x20+87+51 &
       xfstt --unstrap --sync &     #  serwer dla fontów TrueType

# startujemy wm-a

       if [ -f /usr/X11R6/bin/mwm ]; then
               exec mwm
       else
               exec twm
       fi
=============
</verb>
BTW: i dodatkowo...
<sect1>Co to jest xdm i do czego sluzy
<P>
<tscreen>
Nie podano autora</tscreen>
<p>

xdm jest managerem wyświetlaczy X-owych. Załóżmy przykładowy scenariusz:
na komputerze a uruchamiam xdm

a# xdm

po tej operacji na komputerze b wykonuję operację

X -query a

w ten sposób łączę się z xdm na hoscie a i loguję się na serwer a. Następnie
mogę swobodnie korzystać z programów klienckich na komputerze a, które mogą
wyświetlać swoje wyniki bez ograniczeń (zob. rozdział o xhost) na moim X
serwerze z komputera b.

Jeśli nie chcemy, by na komputerze a ładowało się okienko zgłoszeniowe xdm,
to możemy w pliku konfiguracyjnym /etc/X11/xdm/Xservers skasować
(zakomentować) wpis dla hosta lokalnego.
<sect1>Chce X-y pod: a) DOSem b) Win/Win95/WinNT c) OS/2
<P>
<tscreen>
Przemek Borys, złożone na podstawie artykułów z pl.comp.sys.xwindow
</tscreen>
<p>
DOS/WINDOWS

<itemize>
<item>X Appeal. Dostępny jako 30 dniowe shareware z
ftp://ftp.xtreme.it/pub/xappeal lub 
ftp://sunsite.icm.edu.pl/pub/msdos/simtelnet/xwindows.

<item>XWin32. Demo wyłącza się po 2 godzinach. Komercyjnie kosztuje $200 na
pojedyncze stanowisko. Obsługuje sporo rozszerzeń XFree86.
<item>MiX. Freeware. "Nawet KDE pójdzie"
<item>XFree86 dla Windows. Wymaga środowiska cygwin (dawniej cygwin32)
Cyganusa.
</itemize>

Odnośniki do serwerów można znaleźć pod adresem tucows.icm.edu.pl

<sect1>Jakie sa różne fajne desktopy/window managery 1 2 3 4 5 6 7 8 9 a) FVWM/FVWM2/FVWM95 b) Afterstep c) Enlightenment d) KDE (nowość ! KDE-FAQ!) e) CDE f) GNOME
<P>
<tscreen>
Codematic, Michał Kuratczyk, Marcin Lewandowski</tscreen>
<p>
a) FVWM/FVWM2/FVWM95

	Jest to grupa wm, które są bardzo popularne. FVWM powstał
na bazie kodu twm (jak zresztą chyba wszystkie wm'y), a jego następcą
został fvwm2. Są one bardzo dobre, na bazie kodu fvwm2 z kolei powstało
wiele różnych odmian fvwm, m.in. fvwm95 - który do złudzenia przypomina
Windows 95 i jest bardzo popularny, choć ma wielu przeciwników 
(zgadnijcie dlaczego :) ) Najciekawszą cechą fvwm2 jest jego modułowość,
ma on opracowany protokół komunikacji między menedżerem a modułem. 
Są różne moduły - od standardowego "pagera" - czyli podziału biurka na
kilka okien, po "fvwmtalk" - który pozwala na wydawanie poleceń fvwm
w czymś co przypomina konsolę. Polecam. Jest możliwe np. takie
skonfigurowanie tego wm'a aby wydawał dźwięki przy różnych operacjach :)

b) Afterstep

Opisał: Michał Kuratczyk &lt;kura13@kki.net.pl>

	AfterStep to bardzo ładny i wygodny wm. Powstał na podstawie kodu
fvwm, który jest jednym z najpopularniejszych window managerów. Jak nazwa
wskazuje ma on wiele wspólnego ze środowiskiem NextStep(tm), które uchodzi za
jeden z najlepszych interface'ów jakie kiedykolwiek stworzono. Główną cechą
AfterStepa jest Wharf - odpowiednik GoodStuff'a z fvwm. Jest to pasek ikon -
- skrótów do najczęściej używanych programów. Można na nim także umieścić
kalendarz, zegarek lub całe rozwijalne menu programów.

	AfterStep ma bardzo małe wymagania i pracuje bardzo szybko nawet na
przeciętnej klasy komputerze. Jego niewątpliwą zaletą jest łatwość
konfiguracji. Plik &tilde/.steprc jest opatrzony wyczerpującymi komentarzami. Można
w nim ustawić niemal wszystko - począwszy od kolorów paska tytułowego okna
(jeden kolor płynnie przechodzi w drugi), poprzez ikony Wharf'a, zawartość
menu kontekstowych, skróty klawiszowe, a skończywszy na dzwiękach wydawanych
przy różnych akcjach ze strony użytkownika. Możemy nawet określić co to
znaczy maksymalizacja okna (jakich rozmiarów ma być okno po tej operacji), a
przetłumaczenie sobie całego interface'u to zaledwie kilka minut roboty :).

Razem z AfterStepem otrzymujemy spory zestaw ikon (.xpm), obrazów JPG,
których możemy użyć jako teł oraz kilkanaście prostych, ale ładnych wygaszaczy
ekranu. Jeżeli chcemy zrobić wrażenie na kolegach windowsowcach to możemy
sobie nawet wybrać jedną z kilku animowanych tapet :).

	Polecam AfterStepa wszystkim, a zwłaszcza tym, którzy lubią czasem
zapatrzyć się w swoje X-okienka i powspominać stare niedobre czasy, kiedy
wygląd naszy okienek był ustalany za wielką wodą ;).

c) Enlightenment

 	/* under construction */

d) KDE

========================
 Wstęp by Codematic
========================

	Wow ! Można by o nim pisać i pisać, to przebój roku 97/98.
Jest to desktop, a nie tylko wm. Czym się różni desktop od wm ?
Otóż wm to jeden program do zarządzania okienkami, ich ładnego 
wyglądu, oraz ew. jakiegoś fajnego menu aby szybko uruchomić swój
ulubiony program X-owy. Desktop to dużo więcej. To jest cały zestaw 
programów, stanowiących wszystko, co kojarzy się nam z GUI. A więc 
jest to często drag&amp;drop, rozbudowany system pomocy, jakiś sposób
na komunikację między aplikacjami typu np. clipboard, poza tym
często coś w rodzaju OLE, słowem można się rozwodzić.
	KDE ma to wszystko.
	Składa się on z zestawu bibliotek, programów "newralgicznych"
jak np. kwm (KDE window manager) oraz mnóstwa programów napisanych 
specjalnie dla KDE - np. kterm, keditor, ojej, jest ich od groma...
KDE powstało w C++ na bazie biblioteki Qt, która w chwili pisania tego
FAQ ma niestety jeszcze tę beznadziejną licencję (szerzej o biblitece
qt w innej części tego FAQ). Ma swoją własną przeglądarkę WWW, i -
UWAGA - JEST PO POLSKU !!! Naprawde po polsku, to pierwszy tak duży
projekt który zakłada tak daleko posuniętą internacjonalizację...
Po polsku jest pomoc, nazwy w menu, napisy na paskach, wszystko...
Ja najbardziej lubię KDE za to, że ma przeraźliwie wygodny interfejs
do czytania info. Po prostu w przegladarce wpisujemy URL...
	Poza tym są typowe dla Windows gierki - saper, itd. Linux
naprawdę można teraz postawić na biurku. Na dodatek KDE jest całkiem
ładne, podstawową wadą KDE są jego wymagania sprzętowe. Optymalna
konfiguracja to Pentium i 32 MB RAMu. Dlatego ma również wielu 
przeciwników, którzy są przeciwni rozwojowi w tym kierunku, razi ich
również podobieństwo pewnych elementów do Windows. Hmm, uważam że to
przesada. 

<sect2>Co to jest KDE.
<p>
======================================================
K Desktop Environment FAQ

autor: Marcin Lewandowski (jaskier@mat.uni.torun.pl)
======================================================


<sect3>Co oznacza nazwa KDE i skąd się to wzięło.
<p>
	K Desktop Environment. Tak brzmi oficjalne rozszerzenie tego skrótu.
Jak widać litera K nie ma tu rozwinięcia, co daje duże pole do
popisu dla róznych dociekliwych ludzi. Niestety została ona tak
sprytnie dobrana, że prawie nic się z nią nie kojarzy. Jedyne znane
mi propozycje to: KOOL (właściwie cool, czyli... jak to
przetłumaczyć na polski?) oraz KOMMON (common czyli wspólny, ogólny,
powszechny). Obydwie te propozycje chyba dobrze oddają ideę
przyświecającą programistom KDE, więc przy nich pozostaniemy.

	Historia powstania KDE sięga grudnia 1996 roku. Wtedy to właśnie
grupa ludzi postanowiła stworzyć środowisko graficzne dla komputerów
pracujących pod systemem Linux/Unix. Ideą przeświecającą im, była
chęć stworzenia oprogramowania wygodnego i łatwego w obsłudze, który
byliby w stanie obsługiwać ludzie zupełnie nie znający się na
komputerach, obecnie skazani na produkty firmy Microsoft.

	Już mniej więcej po roku, bo na jesieni 1997 roku była gotowa
pierwsza wersja próbna, zaś po następnych 6 miesiącach w archiwach
ftp na całym świecie z dumą rozpierała się wersja 1.0.

	Wchwili obecnej trwają wytężone prace nad następną wersją. Jaki
będzie ich wynik... Poczekamy, zobaczymy.

<sect3>Czym jest KDE.
<p>
	Jak sama nazwa wskazuje, KDE to zestaw programów definiujących (lub,
jak kto woli, za pomocą których można zdefiniować sobie) środowisko
użytkownika. Innymi słowy, za pomocą KDE, każdy jest w stanie
dopasować sobie system do własnych potrzeb, ustalić wygląd ekranu,
sposób działania, wygląd aplikacji itd. Ściślej: w skład KDE wchodzą
programy, za pomocą których można to zrobić.

	Jeżeli w tej chwili masz uruchomione X-y, to zapewne jesteś
użytkownikiem jakiegoś menedżera okien. Zapewne więc stwierdziłeś
już, że wszystko to, o czym mówiliśmy w poprzednim punkcie, możesz
zrobić bądź za jego pomocą, bądź w najzwyczajniejszy sposób,
edytując pliki tekstowe. W czym więc tkwi różnica? Odpowiedź jest
prosta. Zainstaluj KDE to zobaczysz.

	A mówiąc poważnie. W skład typowego menedżera okien wchodzi zwykle
sam menadżer okien i... niewiele więcej. Zwykle trochę plików
konfiguracyjnych, które najpewniej trzeba będzie ręcznie edytować
(vi), prócz tego drobne dodatki jak pagery (za ich pomocą
przełączasz się między wirtualnymi desktopami). Tak przynajmniej to
wygląda w najprostszych z nich: twm, fvwm, fvwm2. W przypadku
bardziej skomplikowanych: AfterStep czy Lestiff, dodatków tych jest
trochę więcej. Czym więc KDE się wyróżnia? Do niego dodatków jest
najwięcej.

	No, może nie tak. Nie o to dokładnie chodzi. Istotą jest, aby
zrozumieć w czym tkwi różnica pomiędzy menedżerem okien a KDE.
Wypiszmy to w punktach:

	a) menedżer okien, czyli program, za pomocą którego możemy (w
	skrócie rzecz biorąc) chwycić okno za pasek i je przenieść gdzie
	indziej jest częścią KDE.

	b) programy pod KDE używają jednej
	wspólnej biblioteki graficznej: Qt. Spójrz w tej chwili na swój
	ekran. Aplikacje, które tam zobaczysz wyglądają jakby każda była z
	innej partafii. Czy to estetyczne? Czy nie lepiej aby miały wygląd
	dopasowany do siebie? Nawet jeśli uważasz, że nie, to pomyśl o czymś
	innym: każda biblioteka musi być załadowana do pamięci i zajmuje w
	niej miejsce. A bibliotek tych może być sporo: Athena widgets (Xaw),
	Xaw3d, xforms, a jeśli jeszcze uruchomicie Gimp-a, to gtk. Jeśli
	używa się tylko jednej biblioteki, to tylko ona siedzi w pamięci. 

	c) wraz z KDE dostarczony jest zbiór różnych bibliotek. Dzięki nim,
	programista pracujący pod KDE nie musi tworzyć dawno już zrobionych
	rzeczy od nowa, ale skupić się na istocie swego programu. Docenicie
	to, gdy zaczniecie pisać programy pod KDE. Istnienie tych bibliotek,
	ma też inną zaletę. Ponieważ wszystkie programy korzystają z tych
	samych procedur, wszystkie obsługuje się tak samo. NIe trzeba się od
	nowa uczyć obsługi każdego z nich.

	d) wszystkie programy są
	konfigurowalne za pomocą graficznego interfejsu. Nie trzeba już do
	konfigurowania programów korzystać z edytora. (Chociaż jak kto chce,
	to może.)

	e) w wielu aplikacjach działa technika "przeciągnij i
	upuść", dzięki czemu obsługa programów jest prawie intuicyjna.  f)
	KDE jest po polsku.

<sect2>Instalacja KDE.
<p>
<sect3>Jak zainstalować KDE.
<p>
	No właśnie jak? Właściwie tak samo jak instaluje się każdy inny
program, ale nie uprzedzajmy faktów.

	Po pierwsze musimy KDE skądś ściągnąć, chociażby wprost ze źródła:
ftp://ftp.kde.org/pub/kde. Lepiej jednak poszukać jakiegoś bliższego
mirrora.

	Następnie musimy ściągnąć i zainstalować bibliotekę Qt. Skąd i
jak... patrz punkt 2.

<sect3>Instalacja skompilowanego programu.
<p>
	W zależności od posiadanego systemu i formatu posiadanych przez nas
plików używamy rpm-a, glint-a (Red Hat), dpkg (Debian), gunzip-a i
tar-a, czy czegokolwiek innego. Najpierw (koniecznie) musimy
zainstalować pakiety:

		kdesupport
		kdelibs
		kdebase

	Dwie pierwsze zawierają biblioteki specyficzne dla
KDE, bez których nie ruszy właściwie żadna aplikacja z KDE. Ostatnia
zaś zawiera podstawowe programy do pracy i konfiguracji KDE.

	Pozostałe pakiety są opcjonalne. Nie musimy ich instalować.
Zawierają one aplikacje dedykowane do pracy z KDE. Nazwa pakietu w
pełni odpowiada jego zawartości.

	kdeutils - kalkulator, edytor, notes etc.
	kdemultimedia - CD player, midi player, mixer etc.
	kdenetwork - klient mail, news i inne programy.
	kdeadmin - dla lubiących działać z prawami root-a.
	kdegraphisc - przeglądaczki dvi, ps i innych formatów.
	kdegames - yeeeeaaaah!!!

<sect3>Co zrobić kiedy ma się tylko źródła?
<p>
	Należy pogratulować odwagi. Instalacja programu ze źródeł, to
najlepsze, co można zrobić. Standardowo bowiem, skompilowany
wcześniej program, został przygotowany tak, aby działać na każdej
maszynie, nawet 386SX 33MHZ (chociaż chciałbym sprawdzić jak KDE
będzie działać na tak szybkim sprzęcie). Kompilując na własnym
sprzęcie możemy dopasować je do własnych potrzeb. Czyżbyś się bał.
Czyżbyś nie wiedział jak to zrobić? Oto sposób:

	configure
	make
	make install

	i już!!!

	No, może nie tak szybko. Sprawa wymaga lekkich wyjaśnień:

	a) configure : skrypt ten konfiguruje pakiet, tak aby mógł się on
	skompilować bez względu na konfigurację. Kompilując kdeadmin
	będziemy musieli najprzypuszczalniej uruchomić go z opcją
	--with-pam. Opcja ta włącza użycie PAM, czyli Pluggable
	Authentication Modules. Są one używane przy odczytywania hasła
	użytkownika z /etc/shadow zamiast z /etc/passwd. Tej samej opcji
	możemy użyć przy kdebase.

	b) make : kompiluje pakiet.

	c) make install : instaluje programy. Standardowo programy będą
	zainstalowane w podkatalogach katalogu /usr/local/kde. Jeśli chcemy
	to zmienić na przykład na /opt/kde, to musimy uruchomić configure z
	opcja --prefix=/opt/kde.

	d) make check : w kdelibs kompiluje kilka testowych programików,
	które siedzą w podkatalogu kdetest.

	e) po zainstalowaniu kdesupport i kdelibs, nalezy wyedytować plik
	/etc/ld.so.conf, dodając do niego linię ze ścieżką do tych bibliotek
	(np. /opt/kde/lib lub /usr/local/kde/lib) i uruchomić program
	ldconfig, który pozlicza wszystkie znajdujące się w systemie
	biblioteki. (W zależności od posiadanego systemu możliwe, że zamiast
	tego będziemy musieli zmienić zmienną LD_LIBRARY_PATH.) Ponadto
	warto już teraz ustawić zmienną KDEDIR na katalog z KDE np.
	/opt/kde, oraz dodać do PATH katalog z binarkami KDE (/opt/kde/bin).

	f) trzeba upewnić się, że mamy odpowiednią ilość wolnej pamięci i
	swap-u. Kampilator kompilując niktóre pliki potrafi zająć nawet
	ponad 20MB.

	Jak więc widać kompilacja KDE to sprawa bardzo prosta. U mnie (AMD
	75MHz, 16MB RAM) kompilacja poszczególnych pakietów zajęła:

	Qt:		40min
	kdesupport:	20min
	kdelibs:	35min
	kdebase:	90min
	kdeadmin:	10min
	kdeutils:	25min
	kdegames:	20min
	kdegraph:	25min
	kdemedia:	25min
	kdenetwork:	50min

	Czyżbym mówił, że kompilacja jest szybka? Tak? No cóż, kłamałem.

<sect2>Jak uruchomić?
<p>
	Można to zrobić na 100 i 7 sposobów. W skrócie rzecz biorąc trzeba
uruchomić X-y (xinit) i spowodować, aby uruchamianym przez niego
plikiem byl startkde z katalogu z binarkami KDE. Oto kilka sposobów:

a) najprymitywniejszy:

	xinit /usr/local/kde/bin/startkde

	niestety w ten sposób nie mamy polskiej klawiatury, a KDE mimo iż
	tak graficznie konfigurowalne nie daje nam narzędzia do zrobienia
	tego.

b) nieco mniej prymitywny:

	Do pliku startkde dodajemy ustawienie polskiej klawiatury (jak to
	zrobić... patrz FAQ o X Window.) Jeżeli dodatkowo będziemy mieli
	ustawioną zmienną LANG=pl_PL, to KDE przywita nas ślicznie po
	polsku. Czy to rozwiązanie ma jakieś wady? Właściwie nie. Wszystkie
	te sztuczki ze skryptem startx, oraz plikami .xinitrc, .XClients i
	całą stertą innych sprowadzają się właściwie w końcowym efekcie do
	tego, że uruchomiony zostanie właśnie xinit z odpowiednim plikiem do
	zastartowania.

c) nieprymitywny:

	Wykorzystujemy standardowe skrypty inicjujące edytując któryś z
	nich, wstawiając do niego uruchomienie pliku startkde. Nie
	zapomnijmy o polskiej klawiaturze.

d) mój własny:

	Często zdarza mi się, że właczając X-y nie chce mi się uruchamiać
takiej kobyły, jaką jest KDE. Wolę zwykły twm, albo coś niewile
większego... fvwm, fvwm2, AfterStep. Jeśli masz podobne problemy,
zrób to co ja: skopiuj plik startx na kde i wyedytuj go tak, aby
korzystał z innych skryptów inicjalizacyjnych niż startx (np..xinitrc-kde
zamiast .xinitrc). Później wyedytuj te pliki,
wstawiając do nich ustawienie polskiej klawiatury i wywołanie
startkde. (Uwaga: jeżeli zwykłeś w tych skryptach włączać również
screensaver, to nie rób tego. KDE ma własny.)

<sect2>Biblioteka Qt.
<p>
<sect3>Co to jest Qt.
<p>
	No właśnie. W końcu trzeba to wyjaśnić. Poprzednio już mówiłem, że
	programy KDE korzystają z tej właśnie biblioteki. Co to jednak jest
	biblioteka? Przecież nie mogą sie w niej znajdować książki.
	Oczywiście nie. W realnej bibliotece znajują się książki. Każdy kto
	chce może przyjść i przeczytać jakąś. W bibliotece komputerowej
	znajdują się procedury. Każdy program może którejkolwiek z nich
	użyć.

	Wbrew pozorom nie jest to taka trywialna sprawa. To czy dany program
	korzysta z jakiejś biblioteki czy nie, w znaczący sposób wpływa na
	jego funkcjonalność. Programista korzystający z jakiejś biblioteki
	graficznej nie musi się martwić o jego wygląd. Dzięki temu jego
	program może być lepszy. Ponadto dzięki istnieniu na
	Linux-ie/Unix-ie mechanizmu dzielonych bibliotek, dana biblioteka
	znajduje się w pamięci tylko raz, bez względu na to ile programów z
	niej korzysta. Gdyby każdy programista osobno dbał o wygląd swego
	programu, to takie same procedury znajdowały by się po wielokroć w
	pamięci. Zauważmy ponadto, że biblioteki piszą ludzie znający się na
	rzeczy, którzy tylko temu się poświęcają. Dzięki temu procedury
	znajdujące się w tych bibliotekach są znacznie lepsze od tych, które
	sami byśmy napisali. I to jest właśnie najważniejsze. Jakość
	bibliotek wyznacza jakość używanych programów. Bez przesady można
	powiedzieć, że nie byłoby KDE bez Qt.

<sect3>Jak zainstalować Qt.
<p>
	Po pierwsze musimy je ściągnąc. Najświeższa wersja z całą pewnością
	znajdować się będzie pod adresem:

	ftp://ftp.troll.no/qt/

	Zbyt starych wersji nie warto instalować, gdyż nowsze programy mogą
	nie dać się uruchomić. W szczególności nie warto brać wersji
	wcześniejszych niż 1.40, gdyż mogą być na nich kłopoty z uzyskaniem
	polskich fontów. Wersje te bowiem przyjmowały za domyślny zestaw
	znaków Latin1. Nowsze za domyślny zestaw znaków przyjmują zestaw
	taki, jaki jest w foncie domyślnym. Jeśli ktoś nie chce ściągać
	nowszej wrsji wystarczy, że przekompiluje aktualną wersję zmieniając
	odpowiednią linię w pliku src/kernel/qfont.cpp (Metoda QFont::init)

	Jeżeli udało nam się ściągnąć wersję skompilowaną to ją po prostu
	instalujemy w sposób zależny od ściągniętej postaci (rpm, deb,
	tar.gz). Ewentualnie trzeba będzie po instalacji wykonać ldconfig.

	Jeżeli zaś (co bardziej prawdopodobne) ściągneliście wersję
	źródłową, to musicie ją skompilować. Należy wykonać kolejno:

	gunzip qt.tar.gz
	tar xf qt.tar
	cd nowo_utworzony_katalog

	export QTDIR=ścieżka_do_aktualnego_katalogu (jeśli używamy csh lub
	tcsh musimy napisać: setenv QTDIR ścieżka)

	make (wyświetlony zostanie spis możliwych konfiguracji. Wybieramy
	jedną z nich zależną od systemu na jakim pracujemy)

	make wybrana_konfiguracja (najprzypuszczalniej linux-g++-shared)

	Program został już skompilowany. Teraz należy go zainstalować.
	Niestety twórcy nie przewidują na to żadnej rozsądnej metody.
	Proponowany przez nich sposób to ustawienie katalogów bibliotek,
	manuali i plików nagłówkowych na podkatalogi qt. Sposób mocno
	idiotyczny. Najlepiej więc ręcznie przekopiować odpowiednie pliki do
	standardowych katalogów:

	cp lib/libqt.so.1.40 /usr/lib
	cp -r man /usr/man
	mkdir /usr/lib/qt
	cp -r include /usr/lib/qt
	ldconfig



e) CDE

	Czyli Common Desktop Environment... Jest to zestandaryzowany
desktop, niestety komercyjny. Zaletą jego jest to, że jest powszechnie
używany na Sunach, wyparł bowiem jego OpenLooka i OpenWindows...
Jest dostępna wersja na Linuxa, i muszę stwierdzić że CDE jest całkiem
ładne.

f) GNOME

	Desktop który jest moim faworytem. Dziwne że tak mało się o 
nim słyszy. Na razie jest w stadium zaawansowania słabszym niż KDE.
Powstało na bazie gtk, i w ogóle jest tworzone przez tych samych 
ludzi, co stworzyli GIMPa. GNOME jest częściowo zrobione w Scheme,
języku wyższego poziomu niż C/C++ (obsługuje go biblioteka guile).
Desktop ten będzie rozproszony, zakłada bowiem użycie CORBY. Ma również
powstać coś w rodzaju OLE, i są to moim zdaniem najważniejsze rzeczy,
dla których GNOME jest dla mnie najciekawszym projektem. W przyszłych
wersjach FAQ napiszę coś więcej na ten temat.<sect1>Co to jest lbxproxy 1 2 3 4 5 6 7 8 9
<P>
<tscreen>
Nie podano autora</tscreen>
<p>
LBX to Low Bandwidth X. Jest to mechanizm proxy, zajmujący się kompresją i
cachowaniem połączeń sieciowych X poprzez łącza o wąskim paśmie, tzn. o
niewielkiej przepustowości.
<sect1>Ja chcę fonty TrueType pod X!
<P>
<tscreen>
Gwidon
</tscreen>
<p>
/* original by Gwidon Naskrent, modified by Codematic */

Są na to dwa sposoby: xfsft (autorstwa Juliusza Chroboczka, autora
ogonkify) oraz xfstt.

a) xfstt

Trzeba postarać się o xfstt (źródła są na SunSite, najnowsza wersja
0.99). Po skompilowaniu i przeniesieniu do odpowiedniego katalogu (make
install) odpalamy X i uruchamiamy skrypt testowy. Jeśli wszystko pójdzie
dobrze i będziemy mogli puszczać ten serwer na porcie 7100, tworzymy katalog
/usr/ttfonts/winfonts i czynimy go symlinkiem do zbioru naszych fontów TT
(np. /dos/Windows/Fonts). Uwaga: dopóki istnieje plik /tmp/font-unix/7100
i wpis ścieżki w konfigu, nie będziemy mogli uruchomić X jeśli nie
odpaliliśmy wcześniej xfstt!

Polecam opcję --multi, włącza ona pełną obsługę znaków > 255 w fontach, co
w praktyce oznacza Unicode. Ładnie to wygląda w programie xfd, gorzej
z wykorzystaniem - Netscape w każdym razie kleci własny font z bitmap
i za nic ma nasze piękne skalowalne unikody.

Opcja --sync każe serwerowi od nowa stworzyć plik fontdir (czy jak to
się tam) z poindeksowanymi fontami. Uwaga: w przeciwieństwie do fonts.dir
tworzonego mkfontdir jest to plik binarny!

Opcja --encoding pozwala oszukać Xserwer co do tego że jeden plik
występuje jako kilka fontów z różnymi kodowaniami (oczywiście ów font
musi zawierać unikody). Przydatne do lepszego ISO-8859-2 i cyrylicy
w Netscape (skladnia więc: --encoding iso-8559-2 koi8-r)

Jeśli masz słabą kartę graficzną, rozważ uruchamianie Xów z opcją
-deferglyphs x (x - ilość kB przeznaczanych na cacheowanie wyświetlanych
fontów, domyślnie 8). W przeciwnym razie wyświetlenie zbyt wielu naraz 
albo zbyt dużych znaków na ekranie może skończyć się brakiem pamięci i 
totalną kaszą.

Patrz README co do szczegółów i nazewnictwa fontów pod X. Pamiętaj że nazwy
ze spacjami (np. -winfonts-times new roman-*) trzeba ująć w większości
wypadków w cudzysłowy.

Czego xfstt nie potrafi:

* poprawnego hintingu, przez co małe stopnie fontów wyglądają niemiło
* nie radzi sobie (to znaczy aplikacje sobie nie radzą) ze znakami
  o ujemnej szerokości, zwłaszcza jeśli font jest proporcjonalny
* ma kłopoty z obracaniem znaków, zwłaszcza jeśli chodzi o poprawne spacjowan
ie
* nie polepsza sytuacji co do drukowania. Na szczęście ghostscript od
  wersji 5.0 rozumie fonty TT

b) xfsft

	/* under construction */<sect1>Jak przełączać się między konsolami, mając włączony X?
<P>
<tscreen>
Przemek Borys
</tscreen>
<p>
Przełączamy się na inne konsole, korzystając z kombinacji ctrl+alt+Fx, gdzie
x to numer konsoli, która nas interesuje.

Powrót do odpalonego X jest trochę dziwniejszy; X instaluje się na n+1
zdefiniowanej konsoli (np. jeśli w inittabie zdefiniowanych jest 6 konsoli,
to będzie on na siódmej). Tak więc musimy po prostu nacisnąć
ctrl+alt+F[numer konsoli z X] i gotowe. W naszym przykładzie, naciśniemy
ctrl+alt+F7. (przełączając się z konsoli wystarcza też samo alt+F7)
<sect1>Myszka z rolkami
<P>
<tscreen>
Nie podano autora</tscreen>
<p>
Można np. zainstalować program imwheel. Do znalezienia na http://freshmeat.net.

/* Poszukujemy chętnych posiadaczy myszki z rolkami do rozwinięcia tego
artykułu */
<sect1>Przydatne skróty klawiszowe
<P>
<tscreen>
Przemek Borys
</tscreen>
<p>
<itemize>
<item> <bf/ctrl+alt+backspace/: ubicie serwera.
<item> <bf/ctrl+alt+`szary+'/: podbicie rozdzielczości w aktualnie
obsługiwanej głębi koloru.
<item> <bf/ctrl+alt+`szary-'/: obniżenie rozdzielczości w aktualnie
obsługiwanej głębi koloru.
<item> Przełączanie mięzy konsolami opisane jest gdzie indziej w tym
dokumencie.
</itemize><sect>Bezpieczeństwo w X
<sect1>
<P>
<tscreen>
Nie podano autora</tscreen>
<sect1>Dlaczego potrzebne są w X mechanizmy bezpieczeństwa 1 2 3 4 5
<P>
<tscreen>
Codematic
</tscreen>
<p>
	Ponieważ - gdyby ich nie było - każdy mógłby "podłączyć" się
do terminala przy którym pracujecie, i wyświetlić wam jakies okienka.
Co więcej mógłby przechwycić zdarzenia z klawiatury i myszki, a nawet
"zobaczyć" co macie na ekranie - i np. przeczytać waszą pocztę. Wskazane
jest zatem zabezpieczenie się przed intruzami.<sect1>Jakie mechanizmy bezpieczeństwa są w X-ach 1 2 3 4 5
<P>
<tscreen>
Nie podano autora</tscreen>
<P>
	Rozne.
<sect1>"Client is not authorized to access X Server" - xhost
<P>
<tscreen>
Codematic
</tscreen>
<p>
	Czasem sie zdarza, że klient pokaże taki komunikat. Problem
w tym, że XServer odrzuca nieautoryzowane połączenia i po prostu Was
nie dopuszcza. Należy wtedy na maszynie XServera uruchomić program xhost:

	xhost +maszynaklienta

np. xhost +elektron.elka.pw.edu.pl.

Można też napisać xhost +, ale powoduje to __wyłączenie__ wszystkich 
zabezpieczeń i każdy będzie mógł połączyć się z tym XServerem.
<sect1>xauth, .Xauthority
<P>
<tscreen>
Nie podano autora</tscreen>
<p>
	Brak opisu.<sect1>Czy juz jestem bezpieczny(a) 1 2 3 4 5
<P>
<tscreen>
Codematic
</tscreen>
<p>
	Nie. Opisane wyżej mechanizmy to jedynie autoryzacja. Tymczasem
znane są np. techniki spoofingu, tak że na różne sposoby można to 
oszukać. Niestety kanał XServer-XClient nie jest kodowany, i nie przewiduje
tego standard Xow. Pewnie jeszcze długo nie będzie przewidywał, ale można
temu zaradzić stosując tunelowanie.

	/* under construction */<sect>Programowanie w X - problemy i sztuczki
<sect1>
<P>
<tscreen>
Nie podano autora</tscreen>
<sect1>Od czego zaczac
<P>
<tscreen>
Codematic
</tscreen>
<P>
	Yeah. To pytanie bylo pierwszym, ktore sobie zadalem przerazony
spogladajac na __MEGABAJTY__ dokumentacji z X Consortium i kilogramy
ksiazek w rodzaju serii z ORA. No coz... Dobrym pomyslem jest przeczytanie
w calosci tego FAQ. Nastepnie rozwoj uzalezniony jest od znajomosci
jezyka. Niestety nie znalazlem zbyt wielu dokumentow po polsku o X'ach,
a o programowaniu tym bardziej... Prawde mowiac zadnego nie widzialem,
oprocz XFree86 HowTo, przetlumaczonego przez Piotra Teczynskiego w
ramach projektu JTZ. Nie wiem jakich rad moglbym udzielic zielonym,
ja zawsze uwazalem ze najlepiej i najszybciej jest zajrzec do kodu
zrodlowego. Sciagnijcie sobie prosciutkie programiki, jakies proste
gierki w rodzaju xbill, przegladarki - np. xpdf. Ta ostatnia zreszta
jest bardzo fajnie napisana. Kodow z X Consortium do celow edukacyjnych
w fazie poczatkowej nie polecam. Nawet taki programik jak xlogo,
wydawalo by sie banalny, tworzy skubany wlasny widget, korzysta z jakichs
dziwnych bibliotek, ee tam... Za madre jak dla mnie. Mozecie tez poszukac
na sieci Motif-FAQ:

<tscreen>
      ftp://ftp.cen.com/pub/Motif-FAQ     or
      ftp://ftp.cen.com/pub/Motif-FAQ.gz  or
      ftp://ftp.cen.com/pub/Motif-FAQ.Z
      http://www.cen.com/mw3/faq/motif-faq.html         [NEW Nov. 1996]
</tscreen>

<P>
 jesli chcecie od razu rozpoczac nauke od X Toolkitu. Oczywiscie FAQ
to odnosi sie rowniez do Lesstifa, darmowego klona Motifa (w wiekszosci
w kazdym razie).
<P>
	No wlasnie.
<P>
	Pozostaje kwestia na co wlasciwie postawic. Mysle ze nie 
warto uczyc sie Xlib, przynajmniej na poczatku. Wiekszosc z Was zapewne
zna C++ lub Turbo Pascala, ma wiec niejakie pojecie o programowaniu
obiektowym. Na tym zasadza sie idea XtIntrinsics, a co za tym idzie
wiekszosci toolkitow w rodzaju Motifa czy OpenLooka. I jest to raczej
proste programowanie obiektowe.
<P>
	Prawde powiedziawszy programowanie w X przy pomocy X Toolkitow
jest nietrudne, przy pewnym oblataniu w programowaniu Unixowym i znajomosci
takich zagadnien jak kompilacja, laczenie, etc. kazdy moze spokojnie w 
tydzien nauczyc sie tworzyc samodzielnie wlasne programy. 
<P>
	Co innego jednak jest korzystac z X Toolkitu, a pisac wlasne
widgety. To drugie to wyzsza szkola jazdy i trzeba wtedy znac mechanizmy
Intrinsics, Xlib i w ogole wiedziec o co chodzi w te klocki. Najprosciej
i najlepiej jednak sciagnac sobie z Sieci wlasciwy widget, o ktory nam
chodzi. A jest ich mnostwo. Wystarczy poszukac. Jest nawet taka organizacja
Free Widget Foundation, nie wiem jednak nic wiecej. Mozna spojrzec na

<tscreen>
<tt/ftp://ftp.icm.edu.pl/
</tscreen>

Tam w odpowiednim katalogu sa rozne ciekawe rzeczy.

<P>
	Konkurencja dla widgetow jest np. biblioteka xforms. Jest tez
wiele konkurencyjnych bibliotek, niektore oparte sa na C++. Ostatnio
wiele sie slyszy o Qt i KDE. Jest to naprawde dobry pomysl na nauczenie
sie tego. Ciekawa propozycja jest tez toolkit Gtk+, napisany przez autorow
GIMPa na potrzeby tego programu, a ktory sie okazal tak dobry, ze powstaje
teraz przy jego uzyciu kilka ciekawych projektow. Zapraszam na 

<tscreen>
<tt/http://www.gnome.org/.
</tscreen>

<P>
	Zapraszam też do oglądnięcia kodów Netscape Navigatora 5.0.
W ciągu 5 dni powstała QtScape, klon Netscape przepisany dla biblioteki
Qt przez ludzi związanych z KDE i Qt, po to aby udowodnić że Qt jest
lepsza od Motifa :)
<P>
	No, to tyle. Zycze sukcesow ;-)

<sect>Programowanie w X - tutoriale
<sect1>
<P>
<tscreen>
Nie podano autora</tscreen>
<P>
<sect1>X Window dla opornych - short lame ;-) tutorial
<P>
<tscreen>
Codematic</tscreen>
<P>
<p>
<tscreen>
Copyright &lt;c> 11.1997 by Codematic
All Rights Reserved
</tscreen>

<P>
Autor nie odpowiada za ewentualne uszkodzenia danych, sprzetu, zdrowia
czy czegokolwiek powstale w wyniku lektury czy tez innych sposobow
wykorzystania tego artykulu.

<P>
Autor nie zezwala na modyfikacje bez jego zgody. Kopiowanie, rozpowszechnianie
dozwolone, a odczyty publiczne wrecz zalecane :)

<tscreen>
                        XWindow dla opornych, cz I
</tscreen>

<P>
        Poniewaz jest to artykul dla opornych, wiec bede mowil tu o rzeczach
ktore zapewne wielu wydadza sie oczywiste. Zaczne wiec od tego

<sect2>CO TO JEST X WINDOW SYSTEM ?

<P>
Nie sa to zadne okienka dla Unixa (Linuxa) jak wielu powszechnie uwaza.
Jest to rozproszony, potezny graficzny system sieciowy. Wiecej informacji
w man X :) No nie, jednak powiem cos wiecej.
Po pierwsze trzeba wiedziec ze Xy sa oparte na technologii klient-serwer,
ktora moze sie wydac dosyc dziwna dla osob ktore sie juz z tym styknely.
A mianowicie ze na terminalu pracuje serwer, natomiast na tym co powszechnie
wiekszosc utozsamialaby z serwerem pracuje XClient. Dla wyjasnienia posluze
sie odpowiednim przykladem.

<P>
Jestem na komputerze lamebox.com.pl. Mam przed soba X okienka. Telnetuje sie
na maszyne lamer.chaker.zgroza.pl. Ustawiam sobie wtedy zmienna

<tscreen><verb>
DISPLAY=lamebox.com.pl:0.0 (dla przykladu, ale tak jest najczesciej).
</verb></tscreen>

I odpalam jakis program Xowy, np. xpaint. I co sie dzieje ?
Na lamebox pojawia sie okienko z xpaintem ! Tym, ktorzy jeszcze na to nie
wpadli uprzejmie wyjasniam ze xpaint jest w tym przypadku xclientem.
Chetnym wyprobowac ten przyklad przypominam ze na lamebox trzeba najpierw
uruchomic program xhost i dodac do niego maszyne lamer.chaker.zgroza.pl.

<P>
I to jest caly power X-ow, takie proste, a takie potezne. Na przyklad na
Sun Enterprise 10000 odpalam netscape, a na kompie klasy 386DX pojawia sie
okienko z mozilla pracujaca z sila wodospadu. Na Sunie pracuje xclient,
na 386 xserwer.

<P>
Teraz podam kilka ciekawostek, ktore byc moze zburza pare mitow.

<P>
Pierwsza ciekawostka to taka ze ani X-client, ani X-serwer nie musza byc
programami unixowymi. Jest kilka serwerow X dla DOS, Windows, Macintoshy,
zarowno komercyjnych jak i pol-darmowych. Jednym z bardziej znanych jest
XAppeal, ale nie jest jedyny. Tak samo X klienci. Podobno (nie widzialem
zadnego, ale musze kiedys poszukac) jest nawet xclient dla Windows !
Bardzo fajne, odpalam np. M$Worda i pracuje sobie na nim na zupelnie innej
maszynie.

<P>
Druga ciekawostka to taka, ze X-y nie definiuja interfejsu uzytkownika.
Natomiast mozna sobie na nich taki interfejs zbudowac. Jest cos takiego
jak Window Manager, xclient ktory zarzadza okienkami. To on jest
odpowiedzialny za wyglad np. ramek, przyciskow, itp. - a nie XSerwer.
Oznacza to ze mozemy sobie dowolnie wybierac pomiedzy naszymi ulubionymi
okienkami. Sa rozne window managery, najbardziej znane to olwm (Open Look
Window Manager ktory jest produktem Suna), mwm (Motif Window Manager),
fvwm95 (a la W95) i jeszcze kilka (twm, enlightenment i jeszcze jakis co
do zludzenia przypomina W95, ale zapomnialem jak sie nazywa). W kazdym razie
jest ich wiele.
<P>
Krotki komentarz nalezy sie rowniez KDE - ktory jest nie tylko wm'em, ale
wspanialym desktopem. Czym to sie rozni ? Otoz desktop to caloksztalt,
file manager, integracja wszystkiego, a nawet specjalne API dla
programistow, ktorzy - jesli chca wykorzystac mozliwosci danego desktopu -
moga np. spowodowac wywolanie okienka z helpem. KDE jest za darmo, po
_polsku_, polecam jego sciagniecie.

<P>
/* Commment by Bohdan R. &lt;ethanak@free.com.pl> */
Dodatkowo: amiwm, oferujacy rowniez bezbolesne przejscie z Amiga Workbench,
zachowuje sie pratkycznie tak samo, nawet wady ma te same :)


<sect2>KROTKA HISTORIA X

<P>
X powstal dawno temu w M.I.T, i po jakims czasie jego istnienia powolano
MIT CONSORTIUM ktore mialo sie opiekowac rozwojem X'ow. Pozniej prawa
autorskie MIT CONSORTIUM przekazano XConsortium ktore wniosly wspanialy
wklad w rozwoj X. XConsortium przestalo istniec w koncu 1996 roku (jak
wyczytalem z powodu odejscia wielu najwazniejszych czlonkow na emeryture)
i przekazalo swoje prawa Open Software Foundation. Wszystkie te organizacje
byly niedochodowe i nie zadaly zadnych oplat licencyjnych za swoje dzielo.
X dla Linuxa sa dzielem XFreeProject. Najlepiej wiecej informacji szukac
na: 
<tscreen>
http://www.opengroup.org/x/, http://www.xfree86.com.
</tscreen>

<sect2>X FREE

<P>
To jest sprawa bardzo extra. Po prostu dostajemy cale Xy, z kodem zrodlowym,
dokumentacja i narzedziami gratis. Zwlaszcza dokumentacja jest extra. 
Jest instalowana w katalogu xbooks i sa to __MEGABAJTY__ tekstu, z ktorego
sie mozna dowiedziec wszystkiego. Sa tam rowniez many do X.

<sect2>PROTOKOLY I STANDARDY

<P>
Poniewaz Xy sa systemem sieciowym, wiec autorzy lubia protokoly. W zasadzie
w x-ach jest wiele protokolow-standardow. Najwazniejszy to oczywiscie 

<tscreen>
X Protocol.
</tscreen>

<P>
Jest to protokol ktorym XClient dogaduje sie z XSerwerem. Wiecej informacji
bedzie w czesci II.

<P>
O innych standardach mozna sie dowiedziec w "man XStandards". Sa tam m.in.
protokoly obslugi bitmap, fontow, komunikacji miedzy klientami, obslugi
wejscia, klawiatury, protokol rozszerzen Xserwera, protokol XWindow Manager
i rozne inne. 

<P>
Warto tez poczytac o XDM (protokol XDCMP), oraz o rstartd czyli zdalnym
uruchamianiu programow X-owych.


<sect2>NAJNOWSZE X

<P>
Czyli Broadway. Nie wiem dlaczego o nim tak cicho (moze ja slabo slucham).
Glowne zmiany to wprowadzenie protokolu do obslugi nisko-przepustowych lacz,
czyli ni mniej ni wiecej tylko X-y przez modem. Innym niezmiernie waznym
rozszerzeniem jest integracja X z WWW. Autorzy na swojej stronie
(zajrzyjcie na www.opengroup.org/x/, tam bedzie odnosnik) pokazali demonstracje tej 
techniki. Jest tam mianowicie pare pluginow, ktore trzeba wczytac do netscape
i mozna zagrac w szachy z BigBlue.

<P>
Ciekawa rzecza na ktora sie natknalem jest standard PEX5. Jak zobaczylem
plik naglowkowy &lt;X11/PEX5/PEXlib.h> to mnie zamurowalo. 100 kb deklaracji,
a wszystko to do obslugi grafiki 3D przez XServer. Dokumentacja prezentuje
sie jeszcze ciekawiej, zachecam do lektury w xbooks. Polecam w tym celu
Ghostview, no chyba ze macie duzo papieru (tak z tone :)).

<P>
To by bylo na tyle. W nastepnej czesci bedzie o Xprotokole, Xlib,
Xtoolkitach, Motifie, OpenLook, Athena Widgets, Xaw3d, xforms oraz jak
nauczyc sie robic dzialajace okienkowe programy w tydzien. Albo w dwa dni,
zalezy ile kto spi :)

<tt/code/

<tscreen>
                        XWindow dla opornych, cz II
</tscreen>

<P>
	No dobra, czas przejsc do spraw praktycznych, czyli jak szybko sie
nauczyc programowac w X-ach.

<sect2>X-protocol

<P>
	Mam nadzieje ze rozumiecie idee X'ow i cos wyniesliscie z
I-ej czesci. Podstawa calego systemu jest X-protocol, jezyk w ktorym
"dogaduja sie" X-clienci z X-serwerem. Nie bede go tutaj szerzej opisywal.
Mozecie sobie jednak wyobrazic analogie z procesorem. X-protocol 
porownuje sie z kodem maszynowym, czystymi liczbami szesnastkowymi.
Asemblerem jest biblioteka Xlib o ktorej za chwile. Jezykami wysokiego
poziomu sa X-toolkity o ktorych na koncu. Od razu widac, ze programowanie
w czystym X-protocole - chociaz mozliwe - jest trudne i bez sensu. Jedyne
co potrzeba zeby napisac program dla Xow dzialajacy na zasadzie Xprotokolu
to jakas implementacja TCP/IP w jakimkolwiek systemie operacyjnym. Po
prostu laczycie sie z serwerem i slecie rozne szesnastki :)
Tak na powaznie jedyne co warto wiedziec o tym protokole jest to ze jego
podstawa sa tzw. requesty. X-client wysyla np. request narysowania 
okienka - i serwer rysuje okienko. Sa rozne requesty, jak widac request
dziala w strone od clienta do servera. W druga strone sa eventy. Event jest
wtedy jak sie cos stanie po stronie serwera, np. user kliknie myszka albo
nacisnie klawisz. Oprocz eventow i request sa jeszcze errory. Error jest
wtedy jak cos serwerowi nie wyszlo, np. nie mial pamieci do narysowania 
okienka. Jest jeszcze cos czwarte, ale zapomnialem co. Nevermind.

<P>
No dobra, uproszczony schemat dzialania programu Xowego mozemy juz
przytoczyc. Niech to bedzie program, ktory bedzie pokazywal okienko,
na ktorym bedzie napisane "Lamer", a potem bedzie czekal az user nacisnie
enter zeby zmazac okienko.

<P>
1. Nasz program - Xclient - wysyla request do serwera OpenDisplay. To jest
zawsze pierwszy request. Potem czeka na odpowiedz, jesli nie bedzie
odpowiedzi to sie wysypie z napisem "cannot open display". To jest
standardowy komunikat ktory wkurza wszystkich lamerow, mysla wtedy ze 
to jest cos w rodzaju "core dumped". Madrzejsi juz wiedza, ze trzeba wtedy
ustawic zmienna DISPLAY (np. set DISPLAY=lamer.lamenet.com.pl:0.0).

<P>
2. Zalozmy ze sie udalo, czyli program polaczyl sie z serwerem. To teraz
wysyla request CreateWindow (zgadnijcie po co). Teraz jeszcze okienka nie
widac. Potem OpenFont (czy jakos tak), potem rysuje w tym okienku napis.
Potem MapWindow (chyba). Pewnie nie wiecie po co to Map. Otoz po zrobieniu 
CreateWindow serwer owszem, utworzy okienko, ale niewidzialne. Zeby je
pokazac trzeba wlasnie zrobic MapWindow. Zeby schowac, trzeba je odmapowac
(UnmapWindow).

<P>
3. To byly caly czas requesty. W tej chwili mamy na ekranie okienko z
napisem. Program przechodzi wiec w faze nasluchiwania eventow, czy czasem
user nie nacisnie entera. Nasluchiwanie eventow jest banalne:

<tscreen><verb>
do {
 event = ListenForEvent();
 switch (event) {
  case ...
 }
} while (event != kb_enter)
</verb></tscreen>

<P>
Oczywiscie to by sie wam nie skompilowalo, ale mam nadzieje ze kumacie.

<P>
4. User nacisnal enter, program dostal event, teraz wiec usuwamy okienko
i konczymy zabawe.

<sect2>X-lib

<P>
Czyli ten asembler. Ma ona postac zwyklej biblioteki C. Czyli zeby napisac
program dla X przy uzyciu Xlib potrzeba nam tak:

1) Checi ;-)
2) Kompilator C
3) Xlib (zatem musi to byc Unix, np. Linux, albo jakis system w ktorym jest
Xlib, w praktyce nie widzialem zadnej implementacji Xlib na cos innego).
Dalej wiec bede mowil o Linuxie i o X-ach dla Linuxa - XFree.

<P>
Musimy w tym celu wlaczyc odpowiednie naglowki. Siedza one w 
/usr/X11/include/. Kompilator zreszta powinien znac sciezki, wiec w 
programie wystarczy zeby bylo:

<tscreen><verb>
#include <X11/X.h> /* np. X.h - opis X-protokolu */
</verb></tscreen>

<P>
Program nalezy skompilowac:

<tscreen><verb>
gcc -L/usr/X11/lib -lX11 -o cos cos.c 
</verb></tscreen>

-L musi byc jezeli sa problemy z odczytywaniem tych bibliotek (cos skopane
w konfiguracji ldconfig). 
-lX11 - to oznacza ze kompilator ma wlaczyc biblioteke libX11.so, ktora
wlasnie jest biblioteka Xlib.

<P>
Programowanie w Xlib jest problematyczne, a mowiac dosadnie - pojebane.
W jakims podreczniku do X-ow program okienkowa wersja "hello world" napisana
dla Xlib zajmowala 3 strony ! 

<P>
O Xlib warto wiedziec to, ze czasem sie jej uzywa jak trzeba zrobic cos
niestandardowego. Standardowo robi sie okienka, przyciski, czyli w ogole
GUI. Z Xlib korzysta sie wtedy gdy chcemy np. narysowac kreske w okienku.
Xlib jest zbudowana w ten sposob ze jej funkcje to sa w zasadzie
odpowiedniki requestow. Po prostu typowa funkcja Xlib pobiera argumenty,
pakuje je do bufora i sle do serwera. Jest jeszcze taka sprawa, ze requesty
sa buforowane. To znaczy wywolacie np. 5 funkcji Xlib i nic do serwera wam
nie dojdzie. Dlaczego ? Trzeba ten bufor oproznic (flush). Flush bufora
nastepuje w 4 przypadkach:

1) Jest przepelnienie
2) Wywolalismy funkcje Flush cos tam
3) Wywolalismy jakas funkcje ktora czeka na argument
4) cos tam jeszcze


<sect2>X-toolkit's, Intrinsics

<P>
To jest to od czego nalezy rozpoczac nauke programowania w X-ach. Jest to
biblioteka, podobnie jak Xlib, oparta na zasadach programowania obiektowego.
Pojeciem kluczowym jest widget. Widget jest to obiekt przedstawiajacy soba
jakis element GUI, np. przycisk, lista, itp. Xtoolkit (zawarty w bibliotece
libXt.so, wiec trzeba kompilowac z opcja -lXt) mozna podzielic na dwie
czesci: jedna przeznaczona dla projektantow bibliotek, tworcow widgetow,
czyli ta ktora was nie obchodzi. Druga jest dla programistow-uzytkownikow.
Xtoolkit ma taka przyjemna wlasciwosc ze jest jakby nadwarstwa. Po prostu 
niezaleznie jakiego toolkitu uzywacie, Atheny, Motifa czy czegokolwiek
programuje sie w ten sam sposob i uzywa sie tych samych procedur. 

<sect2>Athena widgets, Xaw3d

<P>
Athena widgets to zestaw widgetow opracowanych na potrzeby XtIntrinsics
(czyli Xtoolkit) w ramach Project Athena. Byl to chyba pierwszy toolkit
dla X, jest dostepny za darmo i dostarczany bezplatnie z kazda dystrybucja
Xow. Jest w bibliotece  libXaw.so (jak sie domyslacie trzeba kompilowac
-lXt -lXaw). Jego charakterystyczna cecha jest to, ze jest okropnie brzydki,
te przyciski i w ogole wyglad interfejsu jest tak dretwy ze mozna sie 
poplakac. Rozwiazaniem na to jest Xaw3d. Athena Widgets 3D to ladny, mily,
kolorowy xtoolkit majacy te przyjemna ceche ze jest calkowicie zgodny z 
Xaw. Programuje sie go zatem tak samo. Jedyne co trzeba zrobic to zamienic
libXaw.so na libXaw3d.so, albo wrecz fizycznie przemianowac ten plik. Wtedy
wszystkie aplikacje Atheny beda ladne i kolorowe.

<sect2>Motif

<P>
To bardzo znany produkt OSF. Sklada sie z Xtoolkitu, Motif Window Managera
(mwm), FileManagera. Jest dobry ale ma ewidentna wade - nie jest za darmo.
Jest inicjatywa FSF (free software foundation - powinna sie wam kojarzyc),
nazywa sie lesstif. Teraz rozwijaja go - zdaje sie - Hungry Programmers.
Calkiem spoko.

<sect2>OpenLook

<P>
To sa widgety i window manager (olwm) Suna. Nie wiem jak jest z licencjami,
programy najczesciej z tego nie korzystaja. 

<sect2>Jak sie w tym programuje

<P>
Podstawa jest XtIntrinsics czyli to co jest w Intrinsic.h. Nie wdajac sie 
zbytnio w szczegoly pokaze wam wersje hello world dla Atheny:

<tscreen><verb>
/* xwhello.c by Codematic 11.1997 */

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/XawInit.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>

static Arg args[10];

Widget main_widget, form_widget, hello_message, exit_button, op_button;

static void FuncQuit(Widget w,caddr_t client_data,XtPointer p)
{
 XtCloseDisplay(XtDisplay(w));
 exit(0);
}

void setup_main_widgets()
{
 form_widget = XtCreateManagedWidget("Form", boxWidgetClass, main_widget, 
   NULL, 0);
 
 XtSetArg(args[0],XtNlabel,"OK");              
 exit_button = XtCreateManagedWidget("Exit",commandWidgetClass, form_widget, 
  (ArgList) args, 1);

 XtSetArg(args[0],XtNlabel,"Wyjscie");              
 op_button = XtCreateManagedWidget("Op",commandWidgetClass, form_widget, 
  (ArgList) args, 1);  
 XtAddCallback(op_button,"callback",(XtCallbackProc) FuncQuit,NULL);
}

void main(int argc, char **argv)
{
 main_widget = XtInitialize(argv[0], "XMHello",NULL,0,&amp;argc,argv);
 XtSetArg(args[0],XtNheight,200);
 XtSetArg(args[1],XtNwidth,100);
 XtSetValues(main_widget, args, 2);

 setup_main_widgets();
 
 XtRealizeWidget(main_widget);
 XtMainLoop();
}
</verb></tscreen>

<P>
Co to cos robi ? Opisze krok po kroku. Nie bede analizowal wszystkich 
parametrow, jak czegos nie wiecie to man "nazwa funkcji".

<P>
Najpierw deklarujemy glowny widget aplikacji, "krol" wszystkich widgetow.
Poniewaz widgety sa obiektowe, wiec jest tu zachowana hierarchia drzewiasta.
Po prostu kazdy widget moze miec swojego rodzica (parent) lub dzieci.
XtInitialize jest pierwsza funkcja wywolywana przez program korzystajacy
z Intrinsics. Argumenty chyba rozumiecie, jak nie to man.

<P>
XtSetArg jest podstawowa funkcja uzywana do konfigurowania widgetow.
Chodzi o to ze kazdy widget ma swoje parametry. Sa one najczesciej ustawiane
defaultowo i odpowiadaja roznym wlasciwosciom obiektow na ekranie (np. kolor
przycisku, tlo, tekst, itp). Zeby konfigurowac widgety deklarujemy sobie
tablice odpowiednia duza elementow typu Arg. Potem te elementy ustawiamy
XtSetArg. A na koncu robimy XtSetValue podajac jako parametry ta tablice
oraz widget ktory chcemy skonfigurowac. Parametry widgetu sa identyfikowane
poprzez stringi; XtNheight, XtNwidth sa to stale - lancuchy znakow.
Jak widac ustawiamy w ten sposob dlugosc i szerokosc okienka.

<P>
Potem jest setup_main_widgets. O tym dalej.

<P>
XtRealizeWidget wyswietla wam to wszystko na ekranie i w ogole uruchamia
cala maszynerie.

<P>
XtMainLoop to glowna petla, zawsze jako ostatnia wywolana powoduje ze
wszystko ladnie dziala.

<P>
Co sie teraz dzieje w setup_main_widget ? Jak mogliscie zauwazyc i/lub
domyslic sie programowanie w Xtoolkicie jest podobne do budowania wiezy 
z klockow. Po prostu dodajemy widgety do hierarchii, konfigurujemy je
i puszczamy petle. No i dodajemy, no wlasnie, callbacki. Callback jest
funkcja ktora jest parametrem widgetu, jest wywolana kiedy user cos 
zadziala. Np. dla przycisku jest definiowany callback, ktory jest generowany
jak user nacisnie "OK". Domyslnie nie ma zadnego callbacka, widget po prostu
nie reaguje. My mozemy dodawac wlasne akcje. Jeden widget moze miec
oczywiscie wiele callbackow.

<P>
Na poczatku dodajemy form_widget typu boxWidgetClass. Jest on pojemnikiem,
po prostu polem na okienku na ktorym dodajemy nowe widgety. Widgety tworzy
sie funkcja XtCreateWidget, jednakze potem trzeba nimi zarzadzic - 
XtManageWidget. DLa prostoty wiec uruchamiamy XtCreateManagedWidget ktora
robi obie rzeczy naraz. Potem dodajemy dwa buttony. Jak widzicie dodajemy 
je juz nie do main_widget tylko do form_widget - on jest rodzicem.
Ustawiamy w nich parametr XtNlabel - czyli tekst na klawiszu. Do ostatniego
buttona dodajemy callback funkcja XtAddCallback ktora konczy cala zabawe. 
Jak widzicie jest to banalne.

<P>
W praktyce robi sie tak. Otwiera sie jedna konsole ze swoim programem,
druga do mana a trzecia z shellem w ktorym biezaca sciezka jest
/usr/X11/include/Xaw/ (albo Xm/ dla Motifa). Potem myslimy co ma byc w tej 
aplikacji wiec wybieramy widgety. Kazdy widget ma swoj wlasny plik 
naglowkowy, np. Box. Tam sa takie fajne opiski parametrow kazdego widgetu,
nie trzeba szukac po manach zeby wiedziec ze tekst na buttonie to XtNlabel.
Sa tam tez #define'y takie jak XtNlabel, ktore ulatwiaja programowanie.
Zamiast XtNlabel mozna bowiem napisac "label", ale po co. Oprocz kazdego
parametru jest jego wartosc domyslna, typ i klasa. To wszystko jest w 
takiej fajnej tabelce.

<P>
Motifa programuje sie w zasadzie tak samo, tyle ze ma wiecej widgetow i
inaczej sie nazywaja. Zasada jest ta sama. 

<P>
HINT: jesli chcecie sie nauczyc dokladniej zapraszam do lektury kodu gierki
xbill, szczegolnie pliki widgets.h, widgets.c, athenawidgets.c,
motifwidgets.c (sorki jak sie pomyslilem, ale jakos tak). Tam jest bardzo
fajnie zrobiony interfejs do Motifa i Atheny, takze te zestawy mozna sobie
wybrac przy kompilacji. Zobaczcie jak tam to autor zrobil.

<sect2>X-forms

<P>
To jest fajna sprawa. Autorzy omineli cala maszyne Xtoolkitu i napisali 
wszystko od podstaw w Xlib. Nie opisze tu jak to programowac, ale zobaczcie
przyklady w /usr/doc/xforms. Sa naprawde za*******. Calosc ma tylko jeden
plik naglowkowy "forms.h" i do tego jest dolaczony wizualny generator
fdesign. Potrafi on stworzyc kod w c wiec formsy moga byc naprawde szybkim
sposobem na programowanie w X. Zaleta widgetow jest jednak to ze sa bardziej
popularne.

<P>
No to by bylo na tyle. Mam nadzieje ze doszliscie do konca.
<tt/Codematic/.

<sect1>Motif (na podstawie lesstifa)
<P>
<tscreen>
Przemek Borys</tscreen>
<P>
<sect2>Przedwstęp<label id="przedwstep">
<p>
    Teoretycznie, tekst ten opisuje programowanie pod <it/motifa/, lecz w
rzeczywistości, przedstawione tu techniki programowania są identyczne w 
każdej bibliotece <it/widgetów/ (powtarzam - <it/widgetów/ - bo są też
biblioteki  obiektowe). Trzeba do szczęścia znać po prosto kilka
strategicznych funkcji z pakietu <it/Xtoolkit/ (standardowo dostarczany
z X-ami) na krzyż i już. Opisy poszczególnych widgetów dla każdej biblioteki
<it/widgetów/ (jeśli brakuje dokumentacji) można znaleźć w plikach
nagłówkowych.

<sect2>Wstęp<label id="wstep">
<p>
    Męczę się już z programowaniem pod X od jakiegoś czasu. Nie ma nigdzie
niestety odpowiednich podręczników, czy choćby tutoriali w sieci. Tzn. są,
ale mówią tyle co nic. Dlatego teraz uszczęśliwię świat pierwszym polskim 
HOWTO o programowaniu pod X Window System.

    Programowanie to zademonstruję na najwyższym poziomie pisania aplikacji - 
na poziomie biblioteki <it/GUI/ (ang. <it/Graphical User Interface/).
Jest wiele bibliotek <it/GUI/ dla X, np. <it/XForms/ (darmowa biblioteka z
wizualnymi narzędziami), <it/qt/ (biblioteka różnych użytecznych klas
zawierających najważniejsze narzędzia - darmowa dla projektów niekomercyjnych),
<it/Athena/ (darmowa biblioteka <it/widgetów/ (co to jest <it/widget/ napiszę
dalej) - standardowo dostarczana w dystrybucjach X - ma swoje odmiany:
<it/Xaw/ - zwykła (brzydka) Athena, <it/Xaw3d/ - Athena z trójwymiarowymi
obiektami, <it/Xaw95/ - klon <it/GUI/ z Windows95).

    Jednak <it/Open Software Foundation/ wylansowała zupełnie inną bibliotekę, 
która króluje obecnie wśród programów pisanych pod X. Jest nią <it/Motif/. 
Niestety nie jest darmowy - kosztuje ok 100$. Na szczęście jednak, niedawno 
(jesień 1995) powstał darmowy klon <it/motifa/ - <it/lesstif/. Ma on pewne wady 
(m.in jest zaimplementowany na niewielu /w porównaniu z oryginalnym motifem/
platformach - różne unixy i OS/2), ale ogólnie nadaje się do użytku.

    Jeszcze jedno - na końcu tego tekstu znajduje się przykładowy programik
pod motifa - jeśli należysz do tych osób, które lubią widzieć najpierw kod,
potem teorię, to informuję cię o jego istnieniu :) (sekcja 
<ref id="przykladowy_program">)

<sect2>Filozofia systemu X<label id="filozofia_systemu_x">
<p>
    System X jest odmienny niż to co znamy z firmy M$. Jest to system w 
pełni sieciowy - co za tym idzie, może być w dużej mierze niezależny od 
sprzętu.

    X również nie oferuje standardowo takich obiektów, jak suwaki,
guziki, menu itd. Tego w podstawowym API (ang. <it/Application Programming
Interface/) czyli bibliotece <it/Xlib/ nie ma.

	Zamiast tego, w X postawiono na inną filozofię - na <it/widgety/.
<it/Widgety/ to tak jakby klasy definiujące określone obiekty. (np. guzik,
suwak, tabela, pole tekstowe, itd.) Dobre jest to, że można definiować
własne <it/widgety/.

    Mówiąc o <it/widgetach/, muszę jeszcze powiedzieć, czym one się 
charakteryzują. <it/Widgety/ mają dwie ważne własności - mają definiowalne
zasoby (ang. <it/resources/), oraz <it/callbacki/.

    Zasoby to takie rzeczy, jak np. kolor, współrzędne obiektu na ekranie,
jego szerokość, wysokość, sposób buczenia (jeśli takowy istnieje), itd. 
Słowem, są to zależności, określające właściwości obiektu.

    <it/Callbacki/ określają akcje na zdarzenia, na jakie reaguje
<it/widget/. Np. guzik można nacisnąć, co spowoduje wywołanie takiej a
takiej funkcji (która to funkcja właśnie jest <it/callbackiem/) itd.

    Na koniec, muszę jeszcze powiedzieć, że <it/widgety/ w aplikacji są zawsze
uporządkowane hierarchicznie. Każdy <it/widget/ ma swój <it/widget/
macierzysty, oraz (opcjonalnie) swoje własne potomstwo. Np. taka aplikacja:
<verb>
      ______________________
     |-|    aplikacja   |#|.|
     |   _box______         |
     |  |          |        |
     |  | [guzik1] |        |
     |  | [guzik2] |        |
     |  |__________|[guzik3]|
     |______________________|
</verb>

Będzie miała następującą strukturę widgetów:
<verb>
                                               /-guzik3
    Okno główne&lt;-aplikacja&lt;-tablica ogłoszeń&lt;-+
                                               \        /- guzik1
					        \-box&lt;-+
                                                        \- guzik2
</verb>

Gdzie <bf/Okno główne/, to okno, w którym są uruchamiane aplikacje (np.
<it/window manager/), <bf/aplikacja/, to <it/widget/ aplikacji (nie
posiadający konkretnej reprezentacji na ekranie), <bf/tablica ogłoszeń/, to
taki specjalny <it/widget/ (nazywa się <it/BulletinBoard/), który jest po
prostu "tablicą ogłoszeń", czyli pustą planszą, na której można coś ustawiać
- w naszym konkretnym wypadku ustawiamy na nim <bf/guzik3/, oraz ramkę
<bf/box/, a w tej ramce <bf/box/ tworzymy dwa guziki.
<footnote>Właściwie niektóryzy powiedzą, że to nie do końca tak, ale widget jest dość
płynnym pojęciem</footnote>

<sect2>Parę funkcji i zmiennych<label id="pare_funkcji_i_zmiennych">
<p>
    Na cóż by się zdało to HOWTO, jeśli bym nie poruszył tego tematu. Zacznijmy 
od zmiennych. Jednym z najważniejszych typów w programowaniu pod X jest typ
<bf/Widget/. Zmienne tego typu identyfikują potem wszelkie <it/widgety/, jakie
tylko zdefiniujemy sobie na ekranie. Np. deklaracja:
<verb>
Widget aplikacja, guzik;
</verb>
po odpowiednim zainicjalizowaniu (o czym będzie dalej), stworzy nam
"deskryptory" dwóch <it/widgetów/ - np. <it/widget/ <bf/aplikacja/ możemy
zainicjalizować tak by był <it/widgetem/ (obiektem) aplikacji, a <it/widget/
<bf/guzik/ możemy zainicjalizować tak, by był guzikiem na ekranie.

    <it/Widget/ aplikacji (czyli ten najwyższy z którym coś można robić),
inicjalizuje się w następujący sposób, korzystając z funkcji 
<bf/XtVaAppInitialize/ o prototypie:
<verb>
       Widget XtVaAppInitialize(app_context_return, applica-
       tion_class, options, num_options, argc_in_out,
       argv_in_out, fallback_resources, ...)
             XtAppContext app_context_return;
             String application_class;
             XrmOptionDescRec* options;
             Cardinal num_options;
             int* argc_in_out;
             String* argv_in_out;
             String* fallback_resources;
</verb>
Gdzie <bf/app_context_return/, to zmienna typu <bf/XtAppContext/, która
zostanie załadowana kontekstem nowo utworzonej aplikacji,
<bf/application_class/ oznacza nazwę zasobu aplikacji. (dzięki której będzie
można konfigurować z poziomu pliku <it/.Xdefaults/ wszelkie widgety aplikacji).
Dalsze parametry: <bf/options/ zawiera tablicę określającą akcje na podane
w <it/command-line/ argumenty. Tablica ta składa się z rekordów w postaci:
<verb>
typedef struct {
    char            *option;        /* Option abbreviation in argv*/
    char            *specifier;     /* Resource specifier*/
    XrmOptionKind   argKind;        /* Which style of option it is*/
    XPointer        value;          /* Value to provide if XrmoptionNoArg*/
} XrmOptionDescRec, *XrmOptionDescList;
</verb>
Gdzie string <bf/option/ określa opcję podawaną w <it/command-line/, np.
"-help", jeśli program wywołujemy właśnie z takim parametrem, <bf/specifier/
określa, który z zasobów będzie modyfikowany, <bf/argKind/ mówi, jaki jest
format tej opcji podanej w <it/command-line/ (może być format &dquot;opcja
argument&dquot;, lub po prostu &dquot;opcja&dquot; itp.) Można użyć jednego z
następujących określeń:
<verb>
typedef enum {
    XrmoptionNoArg,     /* Value is specified in OptionDescRec.value*/
    XrmoptionIsArg,     /* Value is the option string itself*/
    XrmoptionStickyArg, /* Value is characters immediately following option*/
    XrmoptionSepArg,    /* Value is next argument in argv*/
    XrmoptionResArg,    /* Resource and value in next argument in argv*/
    XrmoptionSkipArg,   /* Ignore this option and the next argument in argv*/
    XrmoptionSkipLine,  /* Ignore this option and the rest of argv*/
    XrmoptionSkipNArgs  /* Ignore this option and the next                           OptionDescRes.value arguments in argv */
} XrmOptionKind;
</verb>
Kolejny parametr funkcji <bf/XtVaAppInitialize/, <bf/num_options/, określa ile
wpisów jest zrobionych w powyższej tablicy z opcjami. Parametry
<bf/argc_in_out/ oraz <bf/argv_in_out/ okeślają argumenty funkcji <it/main(int argc,char *argv[])/. Ostatni parametr - <bf/fallback_resources/, określa zasoby,
z jakich korzystać, gdy nastąpi błąd w tworzeniu kontekstu aplikacji. (można
zostawić jako NULL).

Oto przykład inicjalizacji aplikacji powyższą funkcją:

<verb>
Widget aplikacja;
XtAppContext kontekst_aplikacji;

aplikacja=XtVaAppInitialize(&amp;kontekst_aplikacji,&dquot;zasob_aplikacji&dquot;,
                            NULL,0,
                            &amp;argc,argv,
                            NULL,NULL);
</verb>

    Po utworzeniu <it/widgetu/ aplikacji, zazwyczaj następuje konstrukcja
<it/widgetów/ podrzędnych, oraz ich powiązań (tj. np. tego, że wciśnięcie
guzika powoduje otwarcie dialogu, itp.). Po zakończeniu tych wszystkich
definicji, pod koniec programu uruchomiamy tą naszą całą konstrukcję. Jak
to robimy? Uruchomiamy po prostu najbardziej nadrzędny <it/widget/ (powyżej
był to widget <it/aplikacja/). Robi się to funkcją
<bf/XtRealizeWidget(Widget)/, np:

<verb>
XtRealizeWidget(aplikacja)
</verb>

Istnieje też funkcja podobna do tej, która nazywa się 

<verb>
void XtManageChild(Widget)
</verb>

    Po uruchomieniu struktury, mamy jednak jeszcze pewien problem. Załóżmy,
że cała nasza konstrukcja <it/widgetów/ się wykona (np. użytkownik wciśnie
guzik i wykona się cały ciąg akcji, w ten sposób, że już żaden <it/widget/
nie pozostanie do wykonania). Nasz program się wtedy zakończy. Zazwyczaj nie
jest to pożądane, więc stosuje się następującą funkcję:

<verb>
void XtAppMainLoop(XtAppContext)
</verb>

Czyli, posługując się zmiennymi z przykładu do funkcji
<bf/XtVaAppInitialize/, może to wyglądać w praktyce np. tak:

<verb>
XtAppMainLoop(kontekst_aplikacji);
</verb>

Zpętli nam to strukturę widgetów na zawsze (chyba, że umyślnie zakończymy
program np. standardową funkcją <bf/exit/, lub korzystając z menu systemowego
okienka). Teraz już nasz hipotetyczny program z guziczkiem nie zakończy
działania po jego wciśnięciu.

<sect2>Tworzenie widgetów i callback'ów<label id="tworzenie_widgetow_i_callbackow">
<p>
    Wśród tego całego pisania, nie powiedzieliśmy sobie jeszcze, jak 
utworzyć <it/widget/ i jak sprawić, by wywoływał on jakąś akcję (np. wciskany 
guzik).

    <it/Widgety/ tworzymy bardzo prosto, korzystając z rodziny funkcji 
<bf/XtCreateWidget/ - najuniwersalniejsza jest chyba
<bf/XtVaCreateManagedWidget/ (tworzy ona <it/widget/, na którym od razu
wywołuje się funkcję <bf/XtRealizeWidget/, tak że później nie trzeba już
ręcznie tego <it/widgetu/ uruchamiać):

<verb>
       Widget XtVaCreateManagedWidget(name, widget_class, parent, ...)
             String name;
             WidgetClass widget_class;
             Widget parent;
</verb>
Gdzie <bf/name/ określa nazwę zasobu (do którego potem można się dostać w pliku
<it>&tilde/.Xdefaults</it> lub <it>&tilde/.Xresources</it>, np. w następujący sposób (np.
gdy  name=&dquot;zasob&dquot;):
<verb>
aplikacja*zasob.fontList: -*-helvetica-bold-r-*-*-17-*-*-*-*-*-*-*
</verb>
Gdzie <it/aplikacja/ to specyfikator zasobu, ustalany w funkcji
<bf/XtVaAppInitialize/.

Dalsze parametry <bf/XtVaCreateManagedWidget/, to <bf/widget_class/ - który
określa klasę <it/widgetu/ (tzn. to, czy jest on guzikiem, menu, scrollbarem,
czy jeszcze czymś innym, <bf/parent/ określa <bf/rodzica/ - <it/widget/
nadrzędny nowo tworzonego <it/widgetu/, a wielokropek umożliwia
przedefiniowywanie zasobów (o tym poniżej). Teraz przykład utworzenia
<it/widgetu/:

<verb>
Widget guzik;

guzik=XtVaCreateManagedWidget("wcisnij",xmPushButtonWidgetClass,
                                aplikacja,
                                XmNx,10,
                                XmNy,5,
                                NULL);
</verb>

    Co tutaj się dzieje? Tworzymy widget o nazwie zasobu <it/wcisnij/,
należący  do klasy <bf/xmPushButtonWidgetClass/ (czyli guzik do wciskania),
który jest potomkiem <it/widgetu/ aplikacji (co niesie za sobą specjalne
własności, konkretnie potomkowie tego widgetu są samodzielnymi oknami), i
który ma przedefiniowane dwa zasoby położenia - <bf/XmNx/ współrzędna x)
- ustawiony na 10, i <bf/XmNy/ (współrzędna y) - ustawiony na 5. Można w tej
funkcji przedefiniowywać dowolnie wiele zasobów - a gdy przedefiniujemy co 
potrzebowaliśmy, na koniec zwyczajnie dodać NULL. Np. gdybym chciał ten sam 
guzik zrobić dodatkowo z określoną szerokością,  to definicja wyszłaby tak:

<verb>
guzik=XtVaCreateManagedWidget("wcisnij",xmPushButtonWidgetClass,
                                aplikacja,
                                XmNx,10,
                                XmNy,5,
                                XmNwidth,40,
                                NULL);
</verb>
   
    Poza tą metodą ustawiania argumentów, można je ustawiać też później, po
utworzeniu widgetu. Służy do tego funkcja <bf/XtSetArg/ oraz
<bf/XtSetValues/. <bf/XtSetArg/ działa następująco:
<verb>
       XtSetArg(arg, name, value)
             Arg arg;
             String name;
             XtArgVal value;
</verb>
Ustawia zmienną <bf/arg/ (którą później przekazuje się do <bf/XtSetValues/),
tak że zmienna ta określa ustawienie zasobu <bf/name/ na <bf/value/. Np:

<verb>
Arg arg[1];
//...
XtSetArg(arg[0],XmNx,10);
</verb>

Po załadowaniu tablicy argumentów (w przykładzie <bf/arg/), korzystając z
funkcji <bf/XtSetValues/, włączamy je do <it/widgetu/.
<verb>
       void XtSetValues(w, args, num_args)
             Widget w;
             ArgList args;
             Cardinal num_args;
</verb>
<bf/w/ określa tutaj <it/widget/, którego zasoby ustawiamy, <bf/args/, to
tablica argumentów, ustawiona przez <bf/XtSetArg/, a <bf/num_args/, to liczba
argumentów w tablicy <bf/args/.

    To jeszcze nie wszystko jeśli chodzi o tworzenie <it/widgetów/. Nie całkiem. 
Teoretycznie wszystkie możliwe <it/widgety/ można skonstruować w taki sposób. 
Jednak czasem po prostu szkoda czasu. Dlatego większość <it/widgetów/ posiada 
swoje funkcje publiczne, które umożliwiają szybkie tworzenie
&dquot;wyrafionowanych&dquot; <it/widgetów/. I tak, np. menu można stworzyć,
korzystając z widgetu &dquot;tabelki&dquot; (klasa <bf/XRowColumn/),
korzystając z funkcji np.
<verb>
   Widget XmCreateMenuBar(Widget Parent,char *Name,Arg *arglist,
				Cardinal count)
</verb>
itd. (patrz <it/Lessdox/, choć jeśli chodzi o tworzenie menu, to wrócę jeszcze
do tego na końcu).


    Zostało nam jeszcze definiowanie <it/callback'ów/. <it/Callbacki/ określają
nam, jakie funkcje mają być wywoływane, gdy <it/widgetowi/ przytrafi się
określone zdarzenie. Np. ustawmy <it/callback/, powodujący zakończenie programu
pod <it/widget/ wyżej zdefiniowanego guzika. <it/Callbacki/ ustawiamy funkcją
<bf/XtAddCallback/.
<verb>
       void XtAddCallback(w, callback_name, callback, client_data)
             Widget w;
             String callback_name;
             XtCallbackProc callback;
             XtPointer client_data;
</verb>
Gdzie <bf/w/ określa <it/widget/, któremu nadajemy <it/callback/,
<bf/callback_name/ określa rodzaj <it/eventu/ (zdarzenia), na który reagujemy,
<bf/callback/ to procedura która będzie wywoływana jako <it/callback/ w
odpowiedzi na ten <it/event/, <bf/client_data/ to wskaźnik,
przekazujący procedurze callbackowej określone dane (gdy nie przekazujemy
danych, może to być NULL).
Jeszcze tylko jedna uwaga co do procedur callbackowych. Są to funkcje
następującego formatu:

<verb>
void funkcja_callbackowa(Widget w, XtPointer dane_klienta,
                         XtPointer dane_eventu);
</verb>

Parametr <bf/w/ określa tutaj <it/widget/, na którym zachodzi <it/callback/,
<bf/dane_klienta/, to omówiony przy opisie funkcji <bf/XtAddCallback/ wskaźnik
<bf/client_data/, a <bf/dane_eventu/ to dane związane z eventem, np. wskaźnik
do <bf/XmPushButtonCallbackStruct/, itp. (patrz pliki nagłówkowe).

    A oto przykład ustawiania callback'u:

<verb>
void koniec(Widget w, XtPointer dane_klienta, Xtpointer dane_eventu)
    {
    exit(0);
    }
/*
[...]
*/

XtAddCallback(guzik,XmNactivateCallback,koniec,NULL);
</verb>

    Co my tutaj mamy? Pierwszy parametr funkcji, to <it/widget/, któremu 
ustawiamy <it/callback/ (utworzony ostatnio guzik). Drugi, to zdarzenie, które 
wywołuje <it/callback/. W tym wypadku jest to wciśnięcie guzika. (jeśli masz
wątpliwości, sprawdź w dokumentacji <it/lesstifa/ przy opisie tego
<it/widgetu/) Trzeci parametr, to funkcja callback'owa. Żadnych specjalnych
danych funkcji callbackowej nie przekazujemy - więc ostatni parametr to NULL.

<sect2>Obiecany paragraf o tworzeniu menu<label id="obiecany_paragraf_o_tworzeniu_menu">
<p>
    Menu tworzymy bardzo łatwo. Najpierw, korzystając z funkcji
<bf/XmCreateMenuBar/, tworzymy <it/widget/ paska menu. Później, korzystając z
funkcji <bf/XmCreatePulldownMenu/, tworzymy <it/widgety/, odpowiadające
poszczególnym "submenus" paska menu. Potem, mając <it/widget/ submenu,
tworzymy <it/widgety/ jemu potomne (np. guziki <it/pushbutton/ (normalne opcje),
lub kolejne <it/widgety submenu/). Później, korzystając z widgetu tworzenia
kaskady guzików (<bf/xmCascadeButtonWidgetClass/), powodujemy, że menu
fizycznie zaczyna istnieć.
Zresztą ten akurat problem ładnie jest pokazany w załączonym przykładzie.

<sect2>Przykładowy program<label id="przykladowy_program">
<p>
Wiemy wszystko!

    No, nie wszystko, ale z grubsza już wiadomo o co chodzi w <it/motifie/.
Spis wszystkich <it/widgetów/ wraz z ich przedefinowywanymi zasobami, oraz
<it/eventami/ można znaleźć w dokumentacji (<it/lessdox/ -
<htmlurl url="ftp://sunsite.icm.edu.pl/pub/Linux/Lesstif/lessdox.tar.gz" name="sunsite.icm.edu.pl/pub/Linux/Lesstif/lessdox.tar.gz">).
Teraz pozostaje  nam już tylko składać (jak klocki ;) widgety i tworzyć
aplikacje... Oto przykład prostego programiku pod <it/motifa/ wraz z
Makefile'em.

<sect3>Kod programu<label id="kod_programu">
<p>
<verb>
------- początek test.c -------
/*
Otwieramy niezbędne nagłówki biblioteki
*/

//Biblioteka podstawowa motifa - Xm.h
#include &lt;Xm/Xm.h>
//Biblioteka zawierająca prototyp widgetu BulletinBoard
#include &lt;Xm/BulletinB.h>
//Biblioteka zawierająca prototyp widgetu PushButton
#include &lt;Xm/PushB.h>
//Biblioteka zawierająca prototyp widgetu DialogShell
#include &lt;Xm/DialogS.h>
//Biblioteka zaiwerająca prototyp widgetu RowColumn
#include &lt;Xm/RowColumn.h>
//Biblioteka zawierająca prototyp widgetu CascadeButton
#include &lt;Xm/CascadeB.h>

Widget aplikacja;  			//deklaracja widgetu aplikacji
/*
deklaracja funkcji callbackowej, reagującej na guzik [koniec]
funkcja ta tworzy dialog, w ktorym sie pyta czy naprawde chcesz zakonczyc
aplikacje
*/
void Wyjscie(Widget w, XtPointer dane_klienta, XtPointer dane_eventu);

/*
deklaracja funkcji callbackowej, wywoływanej z dialogu funkcji wyjscie
*/
void ZakonczProgram(Widget w, XtPointer dane_klienta, XtPointer dane_eventu);

void main(int argc, char *argv[])
	{
	/*
	Deklaracje widgetów. Poszczególne widgety będą:
	
	guzik_wyjscia - będzie widgetem guzika [koniec]
	shell - będzie planszą okna programu
	pasek_menu - będzie paskiem menu
	podmenu - będzie to submenu dla jedynej zdefiniowanej opcji paska menu
	podpodmenu - będzie to submenu, wywoływane z widgetu podmenu
	kaskada1 - będzie to wizualny obraz podmenu
	kaskada2 - będzie to wizualny obraz podpodmenu
	opcja1 - będzie to opcja 1 w podmenu
	opcja2 - będzie to opcja 3 w podmenu
	opcja3 - będzie to opcja w podpodmenu
	
	Wizualnie aplikacja będzie wyglądać tak:
	 __________________             _______________
	|-|____________|#|.|           |-| Koniec? |#|.|
	|[pasek menu]      |	       |               |
	|[opcja1      ]    |           | [tak]   [nie] |
	|[podpodmenu >][opcja3]        |_______________| (to okienko po
	|[opcja2      ]    |				  wciśnięciu guzika
	|                  |				  [koniec])
	| [koniec]         |
 	|__________________|
	*/
	
	Widget guzik_wyjscia, shell;
	Widget pasek_menu,podmenu,podpodmenu,okno_dla_menu;
	Widget kaskada1,kaskada2,opcja1,opcja2,opcja3;

	XtAppContext kontekst_aplikacji; //deklaracja kontekstu aplikacji

	/*
	Zadeklarowanie zmiennej typu XmString. W celu nadania nazwy (tej 
	widzianej przez użytkownika) guzikowi [koniec]. Właściwie, nie jest to 
	konieczne (normalnie ta nazwa jest taka, jak nazwa zasobu), ale
	typ XmString ma kilka właściwości, np. przechowuje font, itd.
	*/

	XmString napis_na_guziku;	 
	
	/*
	Inicjalizacja aplikacji. Ładujemy zmienną kontekst_aplikacji,
	nadajemy kwalifikatorowi zasobu aplikacji nazwę &dquot;test1&dquot;, itd.
	*/
	
	aplikacja=XtVaAppInitialize(&amp;kontekst_aplikacji,&dquot;test1&dquot;,
					NULL,0,&amp;argc,argv,NULL,NULL);
	
	/*
	Tworzymy widget planszy okna głównego aplikacji. Na nim będziemy 
	teraz ustawiać menu i guzik (nasze widgety)
	*/				
						
	shell=XtVaCreateWidget(&dquot;test!&dquot;,xmBulletinBoardWidgetClass,
					aplikacja,
					XmNwidth, 200,
					XmNheight,150,
					NULL);
	/*
	Tworzymy widget paska menu
	*/					
					
	pasek_menu=XmCreateMenuBar(shell,&dquot;pasekmenu&dquot;,NULL,0);
	
	/*
	Tworzymy widget submenu
	*/
	
	podmenu=XmCreatePulldownMenu(pasek_menu,&dquot;podmenu&dquot;,NULL,0);
	
	/*
	Tworzymy widget kaskady guzików i wiążemy go z połączeniem 
	menu-podmenu (zasób XmNsubMenuId)
	*/
	
	kaskada1=XtVaCreateManagedWidget(&dquot;Podmenu&dquot;,xmCascadeButtonWidgetClass,
					pasek_menu,
					XmNsubMenuId,podmenu,
					NULL);

	/*
	Tworzymy guzik - opcję submenu
	*/					
					
	opcja1=XtVaCreateManagedWidget(&dquot;opcja1&dquot;,xmPushButtonWidgetClass,
					podmenu,
					NULL);
	/*
	Tworzymy podpodmenu - zagnieżdżone submenu w istniejącym submenu
	*/

	podpodmenu=XmCreatePulldownMenu(podmenu,&dquot;podpodmenu&dquot;,NULL,0);
	
	/*
	Wiążemy podpodmenu z podmenu, tworząc kaskadę guzików (tak jak 
	poprzednio)
	*/
		
	kaskada2=XtVaCreateManagedWidget(&dquot;podpodmenu&dquot;,xmCascadeButtonWidgetClass,
					podmenu,
					XmNsubMenuId,podpodmenu,
					NULL);
	
	/*
	Tworzymy resztę widgetów guzikowych opcji dla potrzeb menu
	*/

	opcja2=XtVaCreateManagedWidget(&dquot;opcja2&dquot;,xmPushButtonWidgetClass,
					podmenu,
					NULL);
	opcja3=XtVaCreateManagedWidget(&dquot;opcja3&dquot;,xmPushButtonWidgetClass,
					podpodmenu,
					NULL);
	
	/*
	Tworzymy string, który będzie wyświetlony na guziku [koniec].
	Korzystamy z najprostszej funkcji, nie ruszamy w ogóle fontu itd.
	*/ 
						
	napis_na_guziku=XmStringCreateSimple(&dquot;Koniec&dquot;);
	
	/*
	Tworzymy widget guzika koniec i nakładamy na niego wcześniej utworzony 
	string (zasób XmNlabel). Poza tym, pozycjujemy guzik 50 pikseli od 
	górnej części widgetu planszy okna.
	*/
	
	guzik_wyjscia=XtVaCreateManagedWidget(&dquot;wyjscie&dquot;,xmPushButtonWidgetClass,
					shell,
					XmNlabelString, napis_na_guziku,
					XmNy,50,
					NULL);
					
	/*
	Zwalniamy string, który został już skopiowany do wnętrza widgetu 
	guzik_wyjscia
	*/
	
	XmStringFree(napis_na_guziku);

	/*
	Zakładamy callback na guzik [koniec] - funkcję callbackową 
	ZakonczProgram
	*/

	XtAddCallback(guzik_wyjscia,XmNactivateCallback,ZakonczProgram,NULL);
	
	/*
	Widgety shell i pasek_menu zostały utworzone funkcją, która ich nie 
	uruchomiła, więc musimy to zrobić ręcznie
	*/
	
	XtManageChild(shell);
	XtManageChild(pasek_menu);
	
	/*
	I... odpalamy aplikację
	*/
	
	XtRealizeWidget(aplikacja);
	
	/*
	oraz zapętlamy ją na wieki wieków
	*/
	
	XtAppMainLoop(kontekst_aplikacji);
	}

void Wyjscie(Widget w, XtPointer dane_klienta, XtPointer dane_eventu)
	{
	exit(0);
	}
void ZakonczProgram(Widget w, XtPointer dane_klienta, XtPointer dane_eventu)
	{
	/*
	Deklaracja widgetów. Poszczególne z nich to:
	
	shell - okno dialogowe
	okienko - plansza na której układamy następne widgety (w sumie 
		  niepotrzebna (można bezpośrednio na shell), ale już 
		  nie będę zmieniać ;)
	tak - guzik tak
	nie - guzik nie	
	*/
	
	Widget shell, okienko, tak, nie;
	
	/*
	Tworzymy okienko dialogowe (widget DialogShell) o wymiarach 100x50
	*/

	shell=XtVaCreateWidget(&dquot;Koniec?&dquot;,xmDialogShellWidgetClass,
					aplikacja,
					XmNwidth, 100,
					XmNheight,50,
					NULL);

	/*
	Tworzymy planszę, nałożoną na widget shell
	*/				
						
	okienko=XtVaCreateWidget(&dquot;okienko&dquot;,xmBulletinBoardWidgetClass,
					shell,
					NULL);

	/*
	Tworzymy guziki ``tak'' i ``nie'' oraz dodajemy na ``tak'' callback do
	funkcji ``Wyjscie'', która wywołuje ``exit(0)''
	*/
						
	tak=XtVaCreateManagedWidget(&dquot;tak&dquot;,xmPushButtonWidgetClass,
					okienko,
					XmNx, 10,
					NULL);
	XtAddCallback(tak,XmNactivateCallback,Wyjscie,NULL);
	nie=XtVaCreateManagedWidget(&dquot;nie&dquot;,xmPushButtonWidgetClass,
					okienko,
					XmNx, 60,
					NULL);
	/*
	Uruchamiamy akcję okienka dialogowego
	*/
	
	XtManageChild(okienko);
	}

-------- koniec test.c ----------
</verb>

<sect3>Makefile<label id="makefile">
<p>
Uwaga! W poniższym Makefile, kolejność bibliotek w zmiennej LIBS jest istotna!
Przy jej zaburzeniu, mogą się zdarzyć dziwne rzeczy (np. program nie ruszy).

<verb>
------- początek Makefile -------
LIBS= -L/usr/X11R6/lib -L/usr/lesstif/lib -lXm -lXt -lX11
INCLUDE= -I/usr/include/X11 -I/usr/lesstif/include

all: test.o
	gcc test.o $(LIBS) -otest

test.o: test.c
	gcc -c $(INCLUDE) test.c
-------- koniec Makefile --------
</verb>

<sect1>Przykladowa aplikacja w Motifie
<P>
<tscreen>
Codematic</tscreen>
<P>
<p>

<verb>
====================================
  DrawStat by Codematic 26.05.1998
====================================

Jest to przykładowa aplikacja w Motifie. Nie chciało mi się
pisać opisu - jak ktoś się wysili i wyśle do mnie maila z 
prośbą o wyjaśnienie o co w tym chodzi, to wtedy ja się wysilę
i zrobię jakiś doc. (Codematic - mmochol@elka.pw.edu.pl)
</verb>

<verb>
-----------Makefile------------
# DrawStat Makefile by Codematic 

CC = gcc -g -L/usr/X11/lib

projekt: draw monitor

monitor: monitor.o ipctools.o makestat.o
	$(CC) monitor.o ipctools.o makestat.o -o monitor

table: ipctools.o table.o
	$(CC)  ipctools.o table.o -o table

draw: draw.o ipctools.o
	$(CC) draw.o ipctools.o -lXm -lXpm -lXt -lX11 -o draw

&dot;c.o:
	$(CC) -c $&lt;

clean:
	rm -f *.o *~ core monitor table draw
--------------------------------
</verb>
<verb>
-----------statistc.h------------
/* Struktura z danymi pomiarowymi */

#ifndef _STATISTC_H_
#define _STATISTC_H_

typedef struct _StatsData
          {
            float  sec;
            int packet_size;
          } StatsData;

/* Prototyp funkcji dokonujacej pomiarow */

void Statistics(StatsData *, int);

#endif
--------------------------------
</verb>
<verb>
----------ipctools.h-------------
#include &dquot;statistc.h&dquot;
#include &lt;sys/ipc.h>

#ifndef _IPCTOOLS_H_
#define _IPCTOOLS_H_


#define MAX_UDP_DATA_SIZE 4200
#define MIN_UDP_DATA_SIZE 2

/* Struktury dzielone */

struct _BufEntry {
 int ready_flag; /* 0 - trwa wczytywanie danych */
 time_t Pomiar;
 float Srednia;
 int len; /* dlugosc tablicy */
 int current; /* najnowszy element */
 StatsData tab[0]; /* trick */
};
typedef struct _BufEntry BufEntry;


/* Funkcje dla monitora */

int InitServer(key_t k); /* Utworzenie semafora */
void DoneServer(int semdes); /* Skasowanie semafora */
int ipcCreateTab(key_t key, int entries, int *size);
void ipcGetWrInto(int semdes); /* Wejscie dla zapisu do ipc */
void ipcGetWrOut(int semdes); /* Dwuelementowe semafory - 1 - odczyt, 2 - zapis*/
void ipcDestroyTab(int shmdes);

/* Funkcje dla klientow monitora */

int InitClient(key_t k); /* Podlaczenie sie do semafora */
void DoneClient(int semdes); /* Odlaczenie sie od semafora*/
int ipcGetTab(key_t key);
void ipcGetRdInto(int semdes); /* Wejscie dla odczytu */
void ipcGetRdOut(int semdes); 

/* Log */

void Log(char *txt);

#endif
--------------------------------
</verb>
<verb>
-----------ipctools.c-----------
/*
 * Codematic 23.04.98
 * DrawStat
 * ipctools.c
 */

#include &dquot;statistc.h&dquot;
#include &dquot;ipctools.h&dquot;
#include &lt;sys/ipc.h>
#include &lt;sys/shm.h>
#include &lt;sys/sem.h>
#include &lt;stdio.h>

/* Funkcje dla monitora */

int InitServer(key_t k)
{
 return semget(k, 2, IPC_CREAT | 00666);
}

void DoneServer(int semdes)
{
 semctl(semdes, 0, IPC_RMID, NULL);
}

int ipcCreateTab(key_t key, int entries, int *size)
{
 int _size;
 _size = sizeof(BufEntry) + entries * sizeof(StatsData);
 *size = _size;
 return shmget(key, _size, 00666 | IPC_CREAT);
}

void ipcGetWrInto(int semdes)
{
 struct sembuf Sem[2];

 Sem[0].sem_flg = Sem[1].sem_flg = SEM_UNDO;
 Sem[0].sem_num = 0; /* Semafor odczytu */
 Sem[0].sem_op = 0; /* Czeka az skonczy sie odczyt */
 Sem[1].sem_num = 1; /* Semafor zapisu */ 
 Sem[1].sem_op = 1; /* Ustawia zapis */
 semop(semdes, Sem, 2);
}

void ipcGetWrOut(int semdes)
{
 struct sembuf Sem[2];

 Sem[0].sem_num = 1; /* Semafor zapisu */ 
 Sem[0].sem_op = -1; /* Zeruje zapis */
 semop(semdes, Sem, 1);
}

void ipcDestroyTab(int shmdes)
{
 if (shmctl(shmdes, IPC_RMID, (struct shmid_ds *) 0) &lt; 0)
  Log(&dquot;Cannot remove shared memory !&dquot;);
}

/* Funkcje dla klientow monitora */

int InitClient(key_t k)
{
 return semget(k, 2, 00666);
}

void DoneClient(int semdes)
{
 /* Nie trzeba nic robic */
}

int ipcGetTab(key_t key)
{
 return shmget(key, 0, 0);
}

void ipcGetRdInto(int semdes)
{
 struct sembuf Sem[2];

 Sem[0].sem_flg = Sem[1].sem_flg = SEM_UNDO;
 Sem[0].sem_num = 1; /* Semafor zapisu */
 Sem[0].sem_op = 0; /* Czeka az skonczy sie zapis */
 Sem[1].sem_num = 0; /* Semafor odczytu */ 
 Sem[1].sem_op = 1; /* Ustawia odczyt */
 semop(semdes, Sem, 2);
}

void ipcGetRdOut(int semdes)
{
 struct sembuf Sem[2];

 Sem[0].sem_num = 0; /* Semafor odczytu */ 
 Sem[0].sem_op = -1; /* Zeruje odczyt */
 semop(semdes, Sem, 1);
}

/* Log */

void Log(char *s)
{
 fprintf(stderr, &dquot;%s\n&dquot;, s);
}
--------------------------------
</verb>
<verb>
----------makestat.c------------

#include        &lt;stdlib.h>
#include        &dquot;statistc.h&dquot;

void Statistics(StatsData *Dt, int packetsize)
 {
   if (!Dt) return;   
   Dt->packet_size = packetsize;
   Dt->sec = (packetsize + ((float) packetsize * rand() / (RAND_MAX+1.0))) \
    / 1000.0;
   if (packetsize % 100 == 0) sleep(1);
 }

---------------------------------
</verb>
<verb>
------------monitor.c------------
/*
 * Codematic 23.04.98
 * DrawStat
 * monitor.c
 */

#include &lt;unistd.h>
#include &lt;stdio.h>
#include &lt;signal.h>
#include &lt;sys/ipc.h>
#include &lt;sys/shm.h>
#include &dquot;statistc.h&dquot;
#include &dquot;ipctools.h&dquot;

#define KEY ((key_t) 1234)
#define SKEY ((key_t) 4321)

int tab_des, sem_des;

void GoDaemon()
{
 if (fork() > 0) exit(0);
 setpgrp();
 signal(SIGHUP, SIG_IGN);
 if (fork() > 0) exit(0);
 chdir(&dquot;/&dquot;);
 umask(0);
 signal(SIGCLD, SIG_IGN);
}

void WhileExit()
{
 Log(&dquot;Removing !&dquot;);
 ipcDestroyTab(tab_des);
 DoneServer(sem_des);
}

void Terminate()
{
 exit(-1);
}

void Fatal(char *s)
{
 Log(s);
 exit(-1);
}

void SolveFactors(BufEntry *tab)
{
 float sum;
 int i;
 
 if (!tab->current) return;
 for (i = 0; i &lt; tab->current; i++)
  sum += tab->tab[i].sec;
 tab->Srednia = sum / tab->current;
}

void RunStats(BufEntry *tab)
{
 int data_size;
 StatsData sd;

 printf(&dquot;Pomiar begin\n&dquot;);
 
 ipcGetWrInto(sem_des);
 bzero(tab, sizeof(BufEntry) +
   ((MAX_UDP_DATA_SIZE - MIN_UDP_DATA_SIZE) / 2) * sizeof(StatsData));
 tab->len = (MAX_UDP_DATA_SIZE - MIN_UDP_DATA_SIZE) / 2; 
 ipcGetWrOut(sem_des);

 data_size = MIN_UDP_DATA_SIZE;

 do {
  Statistics(&amp;sd, data_size);
  ipcGetWrInto(sem_des);
  tab->current = (data_size - MIN_UDP_DATA_SIZE) / 2;  
  tab->tab[tab->current] = sd;
  SolveFactors(tab);
  time(&amp;(tab->Pomiar));
  ipcGetWrOut(sem_des);
  data_size += 2;
 } while (data_size &lt;= MAX_UDP_DATA_SIZE);
 
 ipcGetWrInto(sem_des);
 tab->ready_flag = 1;
 ipcGetWrOut(sem_des);
 
 printf(&dquot;Pomiar end\n&dquot;);
}

main()
{
 int i, tab_size;
 BufEntry *tab;
 struct sigaction Act;
 
/* GoDaemon(); */ /* Chce byc demonem */

 tab_des = ipcCreateTab(KEY, 
  (MAX_UDP_DATA_SIZE - MIN_UDP_DATA_SIZE) / 2, &amp;tab_size); 

 if (tab_des &lt; 0) Fatal(&dquot;Cannot create shared segment !&dquot;);
 
 atexit(WhileExit);
 Act.sa_handler=Terminate;
 Act.sa_flags=SA_RESTART|SA_RESETHAND;
 sigaction(SIGTERM,&amp;Act,NULL);
 sigaction(SIGINT,&amp;Act,NULL);
          
 tab = (BufEntry *) shmat(tab_des, (void *) 0, 0); 
 if ((int) tab == -1) Fatal(&dquot;Cannot attach shared segment !&dquot;);

 sem_des = InitServer(SKEY);

 do {
  Log(&dquot;Monitor by Codematic&dquot;);
  RunStats(tab);
  sleep(30); /* Czekaj 1/2 minuty */
 } while(1);
}
---------------------------------
</verb>
<verb>
-------------draw.res-------------
draw*foreground: black
draw*background: gray
draw.title: DrawStat by Codematic
draw.height: 400
draw.width: 500
draw.form.subform.button1.labelString: Wyjscie
draw.form.subform.button2.labelString: Wykres

draw.bigfont: 12x24
draw.middlefont: 6x13bold

draw.form.subform.WykresPopup_popup.height: 200
draw.form.subform.WykresPopup_popup.width: 300
draw*WykresPopup_popup.title: Typ wykresu
draw*WykresPopup.pane.form1.form0.label1.labelString: Podaj typ wykresu:
draw*WykresPopup*One.labelString: Czas/Odchylenia
draw*WykresPopup*Two.labelString: Wariancja
draw*WykresPopup*button1.labelString: OK
draw*WykresPopup*button2.labelString: Anuluj
-----------------------------------
</verb>
<verb>
--------------draw.c---------------
/*
 * Codematic 23.04.98
 * draw.c
 * DrawStat 
 */

#include &lt;stdio.h>
#include &lt;Xm/Xm.h>
#include &lt;Xm/DrawingA.h>
#include &lt;Xm/Label.h>
#include &lt;Xm/PanedW.h>
#include &lt;Xm/PushB.h>
#include &lt;Xm/PushBG.h>
#include &lt;Xm/RowColumn.h>
#include &lt;Xm/Form.h>
#include &lt;Xm/ToggleBG.h>

#include &lt;errno.h>
#include &lt;sys/ipc.h>
#include &lt;stdlib.h>
#include &lt;string.h>
#include &lt;time.h>
#include &dquot;ipctools.h&dquot;
#include &dquot;statistc.h&dquot;

#define KEY ((key_t) 1234)
#define SKEY ((key_t) 4321)

typedef struct _MapStruct {
 Dimension xp, yp, xk, yk; /* parametry okna do mapowania */
 float x_zakresp, y_zakresp; /* parametry okna mapowanego */
 float x_zakresk, y_zakresk; /* parametry okna mapowanego */
} MapStruct;

extern int errno;

void Fatal(char *s)
{
 Log(s);
 exit(0);
}

/* Globals */

Widget toplevel, form, subform, drawingArea, 
 button, button1;
int wykres_type = 0; /* 0 - czasy, 1 - wariancja */

time_t laststamp; /* ostatnia probka */

BufEntry *tab = NULL;
int sem_des;

Font bigfont, middlefont;

GC gc = 0;

/* Resources */

typedef struct AppData {
 char *bigfont;
 char *middlefont;
} APPDATA, *PAPPDATA;

XtResource resources[] = 
{
 {&dquot;bigfont&dquot;, &dquot;BigFont&dquot;, XtRString, sizeof(String),
  XtOffset(PAPPDATA, bigfont), XtRString, &dquot;12x24&dquot;},
 {&dquot;middlefont&dquot;, &dquot;MiddleFont&dquot;, XtRString, sizeof(String),
  XtOffset(PAPPDATA, middlefont), XtRString, &dquot;8x13&dquot;}
};

/* colors */

int colortable[10];

#define RED colortable[0]
#define BLUE colortable[1]
#define BLACK colortable[2]
#define GREEN colortable[3]



/* prototypes */

void on_expose(Widget w, XtPointer client, XtPointer call);
Widget CreateWykresPopup(Widget w);

/* misc */

void create_gc(Widget w)
{
	XGCValues       values;
	XColor          screen_def, exact_def;
	Display        *display = XtDisplay(w);
	Colormap        cmap = XDefaultColormapOfScreen(XtScreen(w));
	int             mask = 0, i;
	char *colors[] = {&dquot;red&dquot;, &dquot;blue&dquot;, &dquot;black&dquot;, &dquot;green&dquot;};

	if (gc != 0) return;
	
	for (i = 0; i &lt; 4; i++)
	 {
          XAllocNamedColor(display, cmap, colors[i], &amp;screen_def, &amp;exact_def);
          colortable[i] = screen_def.pixel; 
         }

        values.foreground = RED;
	values.line_width= 2;
	mask|=GCLineWidth;
	gc = XCreateGC(display, XtWindow(w), mask, &amp;values);
}

void MapIntoWindow(MapStruct *mp, float x, float y,
 Dimension *xout, Dimension *yout)
{
 *xout = (x / (mp->x_zakresk - mp->x_zakresp))
   * (mp->xk - mp->xp) + mp->xp;
 *yout = (y / (mp->y_zakresk - mp->y_zakresp)) 
   * (mp->yk - mp->yp) + mp->yp;
}

void Draw_Czas(Widget w, int now)
{
 struct tm t;
 int i;
 char *c, buf[128];
 Arg args[2];
 Dimension wi, he, xp, xk, yp, yk;
 MapStruct mp;
 float max, min;

 XtSetArg(args[0], XmNwidth, &amp;wi);
 XtSetArg(args[1], XmNheight, &amp;he);
 
 XtGetValues(w, args, 2);
 XSetForeground(XtDisplay(w), gc, BLACK);

 ipcGetRdInto(sem_des);  
 if (errno || tab->current == 0) {
  if (bigfont)
   XSetFont(XtDisplay(w), gc, bigfont);

  XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, False);
  XDrawString(XtDisplay(w), XtWindow(w), gc, 
   wi / 10 , 20 + he / 10 , &dquot;Brak danych&dquot;, strlen(&dquot;Brak danych&dquot;));
  if (!errno) ipcGetRdOut(sem_des);  
  return;
 }
 
 if (tab->Pomiar == laststamp &amp;&amp; !now) {
  ipcGetRdOut(sem_des);  
  return;
 }
 laststamp = tab->Pomiar;

  if (middlefont)
   XSetFont(XtDisplay(w), gc, middlefont);

 t = *localtime(&amp;(tab->Pomiar));
 c = asctime(&amp;t);


 XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, False);

 sprintf(buf, &dquot;CZAS - pomiar: %s&dquot;, c);
 XDrawString(XtDisplay(w), XtWindow(w), gc, 
  10 , 14 , buf, strlen(buf)-1);

 sprintf(buf, &dquot;Srednia: %f [ms] Ilosc probek: %d&dquot;, tab->Srednia*1000, 
  tab->current);
 XDrawString(XtDisplay(w), XtWindow(w), gc, 
  10 , 30 , buf, strlen(buf));

 /* mapowanie wykresu*/
 mp.x_zakresp = 0.0;
 mp.y_zakresp = 0.0;
 mp.x_zakresk = 1.0; /* kwadrat 1x1 */
 mp.y_zakresk = 1.0;
 mp.xp = 40;
 mp.yp = 40;
 mp.xk = wi - 10;
 mp.yk = he - 30;

 MapIntoWindow(&amp;mp, 0.0, 0.0, &amp;xp, &amp;yp);
 MapIntoWindow(&amp;mp, 0.0, 1.0, &amp;xk, &amp;yk);

 XDrawLine(XtDisplay(w), XtWindow(w), gc, xp, yp, xk, yk); 

 MapIntoWindow(&amp;mp, 0.0, 1.0, &amp;xp, &amp;yp);
 MapIntoWindow(&amp;mp, 1.0, 1.0, &amp;xk, &amp;yk);

 XDrawLine(XtDisplay(w), XtWindow(w), gc, xp, yp, xk, yk); 


 XSetForeground(XtDisplay(w), gc, GREEN);

 min = max = tab->tab[0].sec;
 
 for (i = 0; i &lt;= tab->current; i++)
  {
   if (max &lt; tab->tab[i].sec) max = tab->tab[i].sec;
   if (min > tab->tab[i].sec) min = tab->tab[i].sec;   
  }

 mp.x_zakresp = 0; /* mapujemy wykres */
 mp.x_zakresk = tab->tab[tab->current].packet_size;
 mp.y_zakresp = min;
 mp.y_zakresk = max;

 for (i = 0; i &lt; tab->current; i++)
  {
   MapIntoWindow(&amp;mp, tab->tab[i].packet_size, 
    mp.y_zakresk - tab->tab[i].sec, &amp;xp, &amp;yp);
   MapIntoWindow(&amp;mp, tab->tab[i+1].packet_size, 
    mp.y_zakresk - tab->tab[i+1].sec, &amp;xk, &amp;yk);

   XSetForeground(XtDisplay(w), gc, GREEN);
   XDrawLine(XtDisplay(w), XtWindow(w), gc, xp, yp, xk, yk); 
   XSetForeground(XtDisplay(w), gc, RED);
   XDrawRectangle(XtDisplay(w), XtWindow(w), gc, xp, yp, 1, 1);
  }

 XSetForeground(XtDisplay(w), gc, BLACK);
 sprintf(buf, &dquot;%2.3f&dquot;, min * 1000); /* Os Y */
 XDrawString(XtDisplay(w), XtWindow(w), gc, 
  5 , he-30 , buf, strlen(buf));
 sprintf(buf, &dquot;%2.3f&dquot;, max * 1000);
 XDrawString(XtDisplay(w), XtWindow(w), gc, 
  5 , 50, buf, strlen(buf));

 sprintf(buf, &dquot;%d&dquot;, 2); /* Os X */
 XDrawString(XtDisplay(w), XtWindow(w), gc, 
  40 , he-15 , buf, strlen(buf));
 sprintf(buf, &dquot;%d&dquot;, tab->current); /* Os X */
 XDrawString(XtDisplay(w), XtWindow(w), gc, 
  wi-40 , he-15 , buf, strlen(buf));

 
 if (tab->Srednia >= min || tab->Srednia &lt;= max)
  {
   MapIntoWindow(&amp;mp, mp.x_zakresp, mp.y_zakresk - tab->Srednia, &amp;xp, &amp;yp);
   XSetForeground(XtDisplay(w), gc, BLUE);
   XDrawLine(XtDisplay(w), XtWindow(w), gc, mp.xp, yp, mp.xk, yp);   
  }
 
 ipcGetRdOut(sem_des);  
}

void Draw_Wariancja(Widget w, int now)
{
 struct tm t;
 int i;
 char *c, buf[128];
 Arg args[2];
 Dimension wi, he, xp, xk, yp, yk;
 MapStruct mp;
 float max, min;
 float *wariancja;

 XtSetArg(args[0], XmNwidth, &amp;wi);
 XtSetArg(args[1], XmNheight, &amp;he);
 
 XtGetValues(w, args, 2);
 XSetForeground(XtDisplay(w), gc, BLACK);

 ipcGetRdInto(sem_des);  
 if (errno || tab->current == 0) {
  if (bigfont)
   XSetFont(XtDisplay(w), gc, bigfont);

  XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, False);
  XDrawString(XtDisplay(w), XtWindow(w), gc, 
   wi / 10 , 20 + he / 10 , &dquot;Brak danych&dquot;, strlen(&dquot;Brak danych&dquot;));
  if (!errno) ipcGetRdOut(sem_des);  
  return;
 }
 
 if (tab->Pomiar == laststamp &amp;&amp; !now) {
  ipcGetRdOut(sem_des);  
  return;
 }
 laststamp = tab->Pomiar;

  if (middlefont)
   XSetFont(XtDisplay(w), gc, middlefont);

 t = *localtime(&amp;(tab->Pomiar));
 c = asctime(&amp;t);


 XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, False);

 sprintf(buf, &dquot;WARIANCJA - pomiar: %s&dquot;, c);
 XDrawString(XtDisplay(w), XtWindow(w), gc, 
  10 , 14 , buf, strlen(buf)-1);

 sprintf(buf, &dquot;Ilosc probek: %d&dquot;, tab->current);
 XDrawString(XtDisplay(w), XtWindow(w), gc, 
  10 , 30 , buf, strlen(buf));

 /* mapowanie wykresu*/
 mp.x_zakresp = 0.0;
 mp.y_zakresp = 0.0;
 mp.x_zakresk = 1.0; /* kwadrat 1x1 */
 mp.y_zakresk = 1.0;
 mp.xp = 60;
 mp.yp = 40;
 mp.xk = wi - 10;
 mp.yk = he - 30;

 MapIntoWindow(&amp;mp, 0.0, 0.0, &amp;xp, &amp;yp);
 MapIntoWindow(&amp;mp, 0.0, 1.0, &amp;xk, &amp;yk);

 XDrawLine(XtDisplay(w), XtWindow(w), gc, xp, yp, xk, yk); 

 MapIntoWindow(&amp;mp, 0.0, 1.0, &amp;xp, &amp;yp);
 MapIntoWindow(&amp;mp, 1.0, 1.0, &amp;xk, &amp;yk);

 XDrawLine(XtDisplay(w), XtWindow(w), gc, xp, yp, xk, yk); 


 XSetForeground(XtDisplay(w), gc, GREEN);

/* obliczenie wariancji */
 wariancja = calloc(tab->current+1, sizeof(float));
 for (i = 0; i &lt;= tab->current; i++)
  {
   wariancja[i] = ((float) tab->tab[i].sec - tab->Srednia);
   wariancja[i] *= wariancja[i];
  }

 min = max = wariancja[0];
 
 for (i = 0; i &lt;= tab->current; i++)
  {
   if (max &lt; wariancja[i]) max = wariancja[i]; 
   if (min > wariancja[i]) min = wariancja[i]; 
  }

 mp.x_zakresp = 0; /* mapujemy wykres */
 mp.x_zakresk = tab->tab[tab->current].packet_size;
 mp.y_zakresp = min;
 mp.y_zakresk = max;

 for (i = 0; i &lt; tab->current; i++)
  {
   MapIntoWindow(&amp;mp, tab->tab[i].packet_size, 
    mp.y_zakresk - wariancja[i], &amp;xp, &amp;yp);
   MapIntoWindow(&amp;mp, tab->tab[i+1].packet_size,
    mp.y_zakresk - wariancja[i+1], &amp;xk, &amp;yk);

   XSetForeground(XtDisplay(w), gc, GREEN);
   XDrawLine(XtDisplay(w)