X11 under cover #3: Graficke toolkity ponukaju svoje nastroje

04.08.2008 23:59 | blackhole_ventYl

Ak by programator kazdej aplikacie mal rozumiet tomu, ako X11 funguje, pre kazde okno osobitne nastavovat, ktore udalosti ho zaujimaju a pre kazde okno osobitne vykreslovat to, co sa v nom ma zobrazit, tak by aj napisanie obycajneho textoveho editora bola cinnost minimalne na par mesiacov. Prave preto sa medzi X server a aplikacie vkladaju graficke toolkity.

Prvym existujucim toolkitom bol toolkit Athena (dnes znamy skor pod nazvom Xaw), ktory vznikol ako sucast rovnomenneho projektu, ktoreho sucastou boli aj samotne X-Window. Tento toolkit vyzeral na beznom pocitaci naozaj odporne, ale co bol vaznejsi problem, mal ovladanie extremne odlisne od ovladania vtedy uz dost rozsirenych Windows. Preto vznikol a v priebehu rokov sa masivne rozsiril toolkit Motif. Toolkit Motif bol prelomovy z toho hladiska, ze okrem samotneho grafickeho toolkitu bol k dispozicii aj windowmanager (MWM - Motif Window Manager) a neskor vzniklo cele desktopove prostredie okolo tohto toolkitu s nazvom CDE (Common Desktop Environment). Windowmanager a toolkit poznali sadu dohovorov, ktorymi bolo mozne realizovat niektore cinnosti, ako napriklad Drag&Drop, nastavenie titulkoveho okna. Z tohto konceptu neskor vysiel ICCCM (Inter Client Communication Conventions Manual), ktory obsahuje zakladne postupy pre zabezpecenie prenositelnosti aplikacii. Neskor pocas vyvoja aplikacie GIMP vznikol toolkit GTK, ktory dnes pouziva mnoho aplikacii a firma Trolltech vytvorila vlastny toolkit, zvany Qt, ktory sa stal velmi uspesnym a jeho pouzivanost nadalej rastie.

Tolko zo strucneho prierezu najpouzivanejsimi grafickymi toolkitmi. Netreba to vsak brat ako historiu X11, ta je krapatko bohatsia. Popisovat tu jednotlive toolkity by bolo mrhanie casom, klavesnicou a inymi prostriedkami, pretoze jednotlive toolkity snad okrem toho, ze kecaju s X serverom (aj to nie je tak celkom pravda, lebo Qt existuje v mutacii, kedy keca so specialnym na mieru sitym prostredim a Xka nepotrebuje) nemaju niekedy vobec nic spolocne. Pripadny popis by sa potom zvrhol na tutorial programovania toho, ci onoho grafickeho toolkitu a podobnych uchylnosti, co jednak nie je predmetom tohto serialu a jednak nie som sposobily na taky ukon, kedze s tymito toolkitmi skoro vobec neviem pracovat. Taky graficky toolkit v podstate nie je nic komplikovane. Graficky toolkit si moze vytvorit kazdy sam doma na kolene a zalezi len od neho, ako sa bude chovat a ako sa bude programovat.

Ako som v prvej casti napisal, oknom je pre X server kazda pravouhla oblast, ktora je umiestnena v nejakej inej pravouhlej oblasti, ma nejaky rozmer, nejaku poziciu a je v nejakej vrstve oproti ostatnym oknam s rovnakym rodicom. Okno z pohladu X servera nema ziadnu informaciu o tom, co za typ grafickeho prvku reprezentuje, teda X server nevie nic o tom, ako ma interpretovat udalosti, ktore sa s prvkom deju. O toto sa stara windowmanager. Akymsi abstraktnym objektom, ktory reprezentuje graficke prvky na obrazovke tak, ako ich vnimaju graficke toolkity je cosi, co sa nazyva widget. Widget je z pohladu aplikacie samotnej konkretnym prvkom grafickeho rozhrania, ktory sa nejako konkretne nastavuje a nejako konkretne chova (trebars je nim tlacidlo, ktoremu sa da nastavit rozmer, pozicia a text, ktory zobrazuje a tlacidlo sa da stlacit). Z pohladu samotneho grafickeho toolkitu je vsak widget uz len X-kove okno, ktore ma priradeny kus arbitrujuceho kodu. Tento kod dostava k spracovaniu vsetky udalosti, ktore k danemu oknu prisluchaju a na zaklade toho, aky konkretny prvok grafickeho rozhrania okno reprezentuje, vytvara pre aplikaciu chovanie. Velmi casto su programatorsky toolkity riesene objektovym pristupom, pretoze je to v tomto pripade extremne vhodne.

Aby na tomto mieste tento diel serialu nemusel skoncit, pozrieme sa na zopar dalsich zvrhlosti v X serveri, ktore som doposial nepopisal, ale ktore graficke toolkity vyuzivaju a pripravim si ihrisko pre dalsi diel, ktory by mal pojednavat o windowmanageroch. Mat windowmanager je sice pekne, ale ked mu nic nepripravi informacie k jeho cinnosti (zas tak uplne sebestacny nie je), tak je to v podstate naprd. Preto existuje takzvany ICCCM (Inter Client Communication Conventions Manual), ktory upravuje to, akym sposobom medzi sebou klienti (teda jednak aplikacia s aplikaciou, ale aj aplikacia s windowmanagerom) komunikuju. V dnesnom diele popisem, tu cast komunikacie klient - window manager, ktoru vykonava povacsinou graficky toolkit. V nasledujucom pokracovani sa zameriam na to, ako sa taky windowmanager k tymto datam dostane a co s nimi spravi.

Komunikacia ale nie je len tak, preto musi existovat nejaky mechanizmus, ktory by ju umoznil. A ten teda (na pocudovanie) aj existuje. Ako som v niektorom z predoslych dielov spominal, ku kazdemu oknu je mozne "pripichnut" doplnkove udaje. Tieto udaje sa nazyvaju properties (vlastnosti). Samotny X server ma vcelku v pazi, ake properties su k oknu pripichnute, v podstate sa obsahom ziadnej z nich neriadi. Su dolezite len pre jednotlive aplikacie. Properties sa ukladaju vo forme NAZOV=HODNOTA, pricom kazda hodnota ma typ. Plati pravidlo, ze k jednemu oknu je mozne pripichnut len jednu property daneho nazvu. Aby to nebolo zas tak jednoduche, X server pouziva na ukladanie nazvov a typov mechanizmus tzv. Atomov.

Co to ten Atom vlastne je? Velmi zjednodusene povedane, je Atom cosi ako dynamicky alokovana konstanta. Jedine, co X server garantuje, ze od startu po vypnutie X servera atom bud neexistuje, alebo ma konstantnu hodnotu. Hodnota medzi restartmi servera garantovana nie je. A aka je hodnota atomu? Atom je v podstate bezznamienkove 32bitove cislo.

Demonstrujme si pouzitie atomu na pridani novej property k oknu. Povedzme, ze mame okno, ktoremu chceme nastavit titulok v titulkovom pruhu. Prezradim vam, ze podla ICCCM sa tato property ma nazyvat WM_NAME (myslim, ze to ukradli Motifu). Aby ale X server dookola neprenasal takmer staticku informaciu, ktora je v tomto pripade 7 bytov dlha, aplikacia namiesto nazvu WM_NAME poziada server, aby jej k tomuto nazvu vytvoril Atom. Ak uz niektora ina aplikacia poziadala o vytvorenie atomu pre tento identifikator, vrati server tu istu hodnotu, ktoru vratil prvy krat. Preto pri vsetkych volaniach "Atomizovania" identifikatora WM_NAME dojde k vrateniu rovnakeho cisla (teoreticky az kym sa server nerestartne). To znamena, ze ak nejaka aplikacia nesvindluje a neuchovava si medzi spusteniami cislo atomu, vsetci pripojeni na server vedia, ze WM_NAME je trebars cislo 37 a 37 vzdy znamena WM_NAME (samotne cislo nie je dolezite). Bezznamienkove 32 bitove cislo ma presne 32 bitov, preto akykolvek dlhy identifikator, ktory je v podstate konstantny sa reprezentuje konstantnym identifikatorom konstantnej dlzky.

Druhym pouzitim Atomov su datove typy. Tam je situacia v podstate cez kopirak, jediny rozdiel je v tom, ze Atomy prisluchajuce k typom definuje samotny X server a ked tam, kde X server ocakava identifikator Atomu typu hodite nejaku somarinu, pekne vam za to vynada. X server definuje niekolko zakladnych datovych typov, ako su 8-bitova hodnota, 16-bitova hodnota, 32-bitova hodnota, string, multibyte string a podobne. Postup pre zistovanie Atomov typov je zhodny, ako zistovanie Atomov identifikatorov. Nech sa typ vola STRING, ak si nechame zistit aky Atom tomuto typu prislucha, dostaneme nejake cislo. Jediny rozdiel je v tom, ze ak ako typ dame nieco, co X server nedefinoval ako Atom typu, server vrati chybu. Aky ma vyznam s property ukladat aj jej typ? X server je sietova aplikacia. A kedze sa dodnes vyrobcovia pocitacovych cipov nedohodli, ci je dobre mat prdel na zaciatku, alebo na konci (litle endian vs. big endian), niektore platformy ukladaju cisla inac, nez ine. Nikde ale nie je napisane, ze k jednemu X serveru sa mozu pripajat klienti len jednej endianity, pripadne, ze sa smu pripajat len klienti tej endianity, ktorej je server. Preto spolu s property treba vzdy uviest aj typ, aby v pripade, ze je to potrebne, vedel server obsah property zmasakrovat do podoby, ktoru koncovy klient vie pozuvat.

Kedze X server v pripade typu kontroluje, ci sme nezadali blud, novy typ nemoze vzniknut tak, ze si aplikacia necha vytvorit Atom k lubovolnemu identifikatoru a ten potom pouzije, ako novy typ, pretoze neexistuje ziadny sposob, ako by lubovolny klient pripojeny k X serveru vedel serveru povedat, ako tento typ vnutri vyzera. Preto nove typy moze definovat len samotny X server, pripadne falatky kodu, ktore sa volaju rozsirenia. Niektore atomy definuju aj rozsirenia standardne vstavane do servera. Typom identifikovanym Atomom je trebars aj popisny blok pisma, ktory obsahuje informacie o tom, co za pismo sa klient chysta pouzit.

Pre potreby grafickych toolkitov je dolezitych zopar typov, ktore definuje v podstate priamo X server. Jednym z nich je typ WM_SIZE_HINTS, ktory sa pouziva pre property WM_NORMAL_HINTS. Definuje strukturu, ktorej C-ckovu reprezentaciu odraza struktura XSizeHints (pre sturalov deklarovana v subore /X11/Xutil.h). Obsahuje polia, ktorymi aplikacia dohodnutym sposobom oznami windowmanageru, ake rozmery by si priala pre svoje aplikacne okno. Toto pole obsahuje okrem zelanej polohy okna aj zelanu minimalnu velkost (pod ktoru uz nema zmysel okno zobrazovat), maximalnu velkost (kde uz nema zmysel roztahovat), zelany pomer stran, ktory sa ma dodrzat (vhodne napriklad pre multimedialne prehravace, a velkost kroku v ktorom sa ma okno zmensovat / zvacsovat (vhodne napriklad pre terminalove aplikacie). Vsetky tieto informacie aplikacia napeckuje do struktury, omarkuje typom WM_SIZE_HINTS a prilepi ako WM_NORMAL_HINTS k oknu.

To, ze tieto informacie maju vlastny typ umoznuje existenciu funkcie, ktora dokaze s touto strukturou pracovat a tak programator nemusi pracne strukturu alokovat, vyplnat a k oknu menit, ale funkcia to spravi zanho. Rovnako, ak by niektory klient bezal na stroji s inou endianitou, vie prenho X server zabezpecit prehodenie bytov tak, aby sa unho tieto cisla interpretovali spravne. Toto plati obecne pre vsetky property, s ktorymi sa pracuje, takze sa teraz skor vrhnem na vyznam jednotlivych property, ktore sa daju pouzit.

Vyssie popisana struktura WM_SIZE_HINTS, ako uz jej nazov napoveda, je len hintom pre windowmanager. Aplikacia si moze vybrat, ktore z hintov chce uviest, trebars ju nezaujima, kde sa okno objavi, ale je pre aplikaciu podstatne, ake velke okno bude. Rozhodujuce slovo ma ale windowmanager. Totizto ten je kralom desktopu a ak by sa on nemohol rozhodovat, co s oknami spravi, bola by to anarchia. Preto aplikacia vobec nemoze mat za zle windowmanageru, ak jej okno nezobrazi tam, kde by si to aplikacia priala a take velke, ako by si to aplikacia priala (typickym prikladom je, ze aplikacia to s velkostou okna prezenie a spravi okno vacsie, ako je velkost pracovnej plochy). Preto windowmanager po zvazeni tychto aplikacnych hintov, nastaveni uzivatela a sucasneho stavu plochy zvazi, kam a ake velke okno umiestni. Jedine 2 parametre, ktorymi by bolo dobre, aby sa riadil pre zlepsenie spoluprace s aplikaciami su pomer stran okna a velkost kroku pri zmene velkosti.

Dalsou zalezitostou, ktoru aplikacia moze windowmanageru poskytnut, su hinty k nazvu okna. Vo svete X11 existuju tieto hinty 2, ale bezne obsahuju rovnaku hodnotu. Hint WM_NAME typu STRING obsahuje nazov okna, ktory windowmanager moze zobrazit, ked je okno maximalizovane, alebo normalnej velkosti. Naproti tomu, hint WM_ICON_NAME taktiez typu STRING obsahuje nazov okna, ktory windowmanager moze zobrazit, ked je okno minimalizovane do ikony (pamatate si skaredu ikonkovu plochu windows 3.11 bez taskbaru iba s program managerom? tak z tohto toto rozdelenie na WM_NAME a WM_ICON_NAME vychadzalo). A ked sme uz pri tej ikone, tak samozrejme aplikacia nejako musi dodat aj samotnu ikonu. To sa robi v dalsej strukture WM_HINTS typu WM_HINTS (hej hej dobre citate). Ten obsahuje dalsie zaujimave informacie o okne, ktore by si aplikacia zelala:

Je mozne identifikovat zdroj ikony a zdroj masky ikony. Ako zdroj ikony moze posluzit nejake existujuce okno, ktore nutne nemusi byt namapovane. V tomto okne moze byt nieco nakreslene a podla tohto nakresu sa moze windowmanager riadit. Ak by ale ikona nemala priesvitnost, bola by len pravouhlym frasom na obrazovke, co ale samozrejme nechceme, preto je dobre, ked ikone mozno dat aj tvar. To sa robi pomocou tzv. masky. Maska je ciernobiely obrazok. Tam, kde je v maske cierna, ikona je, tam, kde je v maske biela, ikona uplne presvita. Zdrojom pre masku moze byt iba Pixmapa. Pixmapa je obrazok ulozeny v X serveri. Pre zdroj ikony je este mozne urcit jej rozmery a kde v zdrojovom obrazku ikona zacina.

Takto je mozne pomerne jednoducho vytvarat aplikaciu s animovanou ikonou. Do X servera sa loadne pixmapa o rozmere napriklad n*32 x 32. Kazdy snimok animovanej ikony ma rozmer 32x32 a vedla seba je ich naskladanych n. Potom pri kazdom prehodeni snimku aplikacii staci aktualizovat pociatocnu polohu ikony v pixmape a nemusi nic ine menit. Ked dojde na koniec obrazka, skoci opat na zaciatok. Windowmanager pri kazdej zmene zareaguje a ikonu zmeni.

V tejto strukture aplikacia takisto moze windowmanageru odovzdat informaciu o tom, v akom stave si zela, aby sa okno vytvorilo. Napriklad si aplikacia moze zazelat, aby sa okno vytvorilo, ale nevytvorilo. Hovori sa tomu withdrawn state, kedy okno sice existuje, ale nie je zobrazene. Dalej je tam stav normalny (ten zahrna aj maximalizovany stav) a dalej je stav ikonizovany (v podstate zahrna stav minimalizacie do ikony / tlacidla na paneli). Poslednou vyznamnou zalezitostou najdenou v tejto strukture je urgencia. Ak windowmanager tuto funkciu podporuje, mal by nejako zvyraznit okno, ktore ma tento flag nastaveny na hodnotu true. Trebars rozblika tlacidlo, alebo okno posunie na popredie. To je na vybere windowmanagera.

Dalsou zaujimavou vlastnostou okien je vlastnost WM_CLASS, ktora je typu array of STRING. Obsahuje dva retazce. Prvym je genericky nazov aplikacie, ktory nutne nemusi byt rovnaky, ako je nazov binarneho spustacieho programu, ale mal by byt zhodny pre vsetky instancie programu. Druhym je trieda okna, ktora je obvykle pre kazde okno danej aplikacie odlisna. To je trocha v rozpore s predoslym tvrdenim, ze samotne okna nemaju typ a su v podstate len pravouhlymi oblastami na obrazovke. Z pohladu X servera to tak aj je. Nazov aplikacie a trieda okna sa vyuzivaju len v pripade windowmanagerov. Tie napriklad na zaklade per window nastaveni vedia niektorym aplikaciam, alebo niektorym typom okien upravit ich chovanie, alebo vzhlad. Trebars je mozne nastavit, ze vsetky okna firefoxu identifikovane nazvom aplikacie sa budu nachadzat na druhom desktope. Aplikacia tychto nastaveni je uz ale cisto ulohou windowmanagera.

Tolko k strucnemu popisu toho, ako graficky toolkit (v uchylnom pripade samotna aplikacia) moze komunikovat s windowmanagerom, aby pre svoje okna zabezpecila co najviac. Co sa tyka spracovania klavesnicoveho vstupu, existuje stav X servera, ktory hovori, ktore okno ma focus. Focus si okno moze vyziadat, pripadne ho moze dostat. Ak je focus zamiereny na niektore okno, vsetok klavesnicovy vstup, ktory nie je nejako grabovany (vid predosly clanok) je presmerovany do tohto okna. Ak okno focus strati v dosledku svojho zaniku, v zavislosti od nastavenia focusu pri jeho zmene sa bud moze focus premiestnit na predosly prvok, ktory focus mal, alebo sa moze focus uplne stratit. V takom pripade dochadza k tzv. sloppy focusu, kedy vstup je smerovany tam, kde sa prave nachadza mys.

Je ale dolezite si uvedomit, ze focus, ako ho vnima clovek (teda obvykle graficke zvyraznenie vstupneho pola, kde sa pise, zdvihnutie okna, ktore je aktivne, pripadne prefarbenie ramceka) a focus tak, ako ho vnima X server su 2 odlisne veci. Ak aplikacia ziska focus na niektore svoje okno, je o tom informovana udalostou FocusIn. Graficky toolkit obvykle pri doruceni tejto aplikacie zaisti vykreslenie kurzora a vykreslenie zvyrazneneho ramceka a windowmanager zaisti vykreslenie odlisne ofarbeneho ramceka pre dane okno spolu s jeho vyzdvihnutim. Zvyraznenie okna, ktore ma focus, pripadne zdvihnutie okna, ktore ma focus nie je ziadnou podmienkou pre to, aby mohol mat nejaky prvok vstupny focus a "citat z klavesnice".

Rovnako, ako reakciu na input focus, tak aj dalsie bezne akcie, ako napriklad hover tlacidla pri prejazde mysou, zatlacenie tlacidla, ofarbenie vybranej polozky menu, ofarbenie vybranych ikon, prepinanie radio buttonov a dalsie graficke odozvy vykresluje samotny toolkit na zaklade prislych udalosti a dat, ktore ma k dispozicii o widgetoch. To, ze sa viacmenej vsetky toolkity chovaju rovnako (na tlacidlo sa klika jedenkrat lavym tlacidlom mysi, za scrollovaciu listu sa taha) je len snahou o zjednotenie ovladania.

Mnoho z toho, co som dnes napisal, suviselo s grafickymi toolkitmi len okrajovo, boli to vsak vsetko vlastnosti, ktore priamo aplikacie (ale castejsie graficke toolkity) nastavuju svojim top-level oknam, aby boli windowmanagery schopne s oknami riadne pracovat. Spisal som to sem hlavne preto, ze o samotnych toolkitoch sa bez toho, aby som zachadzal do podrobnosti neda moc o com kecat a jednak preto, ze keby som si tento obkec nechal na clanok o windowmanageroch, tak ten by sa mohol neumerne predlzit. Zoznam vlastnosti, ktore som teraz popisal, nie je konecny a v priebehu rokov doslo k rozsireniu poctu vlastnosti, ktore sa oknam ukladaju o niekolko dalsich. Ak vas zaujima, ktore dalsie vlastnosti to su, skuste si v terminali spustit aplikaciu xprop a kliknut na niektore okno. Tato aplikacia vam o aplikacnom okne prezradi, ake vsetky properties su k nemu pripojene.

V dalsom dieli sa budem podrobnejsie zaoberat mechanizmami, ktore pouzivaju windowmanagery k tomu, aby dokazali informacie ulozene toolkitmi ziskat a hlavne ich drzat cerstve a takisto sa blizsie pozrieme na to, ako windowmanagery zabezpecuju ramceky okien, virtualne plochy, spravu okien a zopar dalsich vychytavok.

    • Re: X11 under cover #3: Graficke toolkity ponukaju svoje nastroj 11.08.2008 | 12:23
      lynch   Návštevník

      Programming X-Windows is like trying to find the square root of pi using roman numerals.

      - Unknown

      • Re: X11 under cover #3: Graficke toolkity ponukaju svoje nastroj 11.08.2008 | 12:57
        Avatar blackhole_ventYl   Používateľ

        ano, to je sice mudre tvrdenie, ale tu asi naprosto nevhodne. ak si vsimnes, ani v jednom z troch dielov nie je uvedeny ani riadok zdrojoveho kodu. cielom nie je naucit ludi pouzivat Xlib, ale toho, kto ma zaujem, zasvatit do toho, ako to funguje. konieckoncov, aj vsetky nadstavbove prostredia sa musia riadit tymito pravidlami...
        ---
        Cuchat s nadchou, to je ako sniffovat bez promiscu.

        --- Cuchat s nadchou, to je ako sniffovat bez promiscu.
    • Jak si ktomu prisel 21.09.2008 | 16:06
      snop   Návštevník

      Ahoj x-men ;),

      mna by zajimalo, kde si vsetky tyto vlastnosti nadobudol. Pri praci na nejake x aplikacii alebo z manualu,... ?

      • Re: Jak si ktomu prisel 30.09.2008 | 10:19
        Avatar blackhole_ventYl   Používateľ

        prva moznost je spravna a kedze aplikaciu na zelenej luke nenapises, potrebujes sa riadit manualom, konkretne ja som pouzil zrejme render oficialneho Xlib manualu do HTML na http://tronche.com/
        ---
        Cuchat s nadchou, to je ako sniffovat bez promiscu.

        --- Cuchat s nadchou, to je ako sniffovat bez promiscu.