Xlib - základní aplikace s jedním oknem
20.11.2020
V předchozích jsme si ukázali jak vytvořit jednoduchou aplikaci v GDK. Pro ty kteří chtějí jít ještě "níž", ukážeme si základní okenní aplikaci napsanou v Xlib, což je "low-level" knihovna zabalující komunikaci s X11 serverem a vytvářet aplikace s grafickým uživatelským rozhraním.
Samozřejmě že v současné době v naprosté většině případů použijeme pro vytvoření nové GUI aplikace nějakou komplexní knihovnu/framework, jako je GTK, wxWidgets nebo Qt. Nicméně pro nějaké malé utility, pluginy pro panely nástrojů apod. kde "odlehčenost" může mít význam, je stále Xlib variantou k uvážení. Navíc stále jsou udržované aplikace napsané v Xlib a pokud hledáme inspiraci v jejich zdrojovém kódu, alespoň základní znalost Xlib se jistě hodí. Kromě toho mnozí programátoři rádi vidí pod povrch jak věci fungují.
Nejprve se musíme připojit k X serveru. Na to použijeme funkci XOpenDisplay. Pokud neurčíme parametr, resp. zadáme NULL, získáme připojení k výchozímu serveru. Poté co získáme číslo výchozí obrazovky pomocí funkce XDefaultScreen, popř. makrem DefaultScreen, můžeme vytvořit okno:
Window window = XCreateSimpleWindow(display, RootWindow(display, screen), 10, 10, 800, 600, 1, BlackPixel(display, screen), WhitePixel(display, screen));
Jako parametry zde zadáváme získané připojení k X serveru, rodičovské okno (pro "top-level" okna použijeme hlavní kořenové okno), dále požadované souřadnice, tj. pozice a rozměry a barvu okraje a pozadí.
Abychom byli schopni následně zachytit a reagovat na vstupní události klávesnice a myši, zavoláme funkci XSelectInput, v jejímž 3. parametru zkombinujeme požadované masky, mezi kterými musí být KeyPressMask a ButtonPressMask. V ukázkovém kódu je dále uvedena hodnota ExposureMask, která zajistí že dostaneme událost požadavku na překreslení okna, kterou sice v našem základním programu nemáme implementovanou, ale v praxi ji samozřejmě budeme využívat, a tom někdy příště.
Aby se okno zobrazilo, namapujeme ho na server přes dříve získané připojení (Display*), a nastavíme jeho název.
Pak už zbývá implementovat smyčku/cyklus ve které budeme přijímat události týkající se okna a podle potřeby na některé reagovat. V každém cyklu vždy nejprve zavoláme funkci XNextEvent, která čeká než se ve frontě objeví nějaká událost a tuto zkopíruje do struktury typu XEvent. V položce type této struktury máme typ události. Další položky pak obsahují data specifická pro konkrétní typ události, jako je např. tlačítko myši nebo klávesa která byla stisknuta/uvolněna.
V našem případě budeme chtít při stisknutí jakékoliv klávesy nebo kliknutí myší okno zrušit a ukončit aplikaci. Proto při detekci zmíněných událostí vyskočíme z cyklu, po kterém před ukončením funkce main zrušíme okno funkcí XDestroyWindow a uvolníme získané spojení na X server funkcí XCloseDisplay.
Pokud používáme správce oken s plovoucími a dekorovanými okny, tj. která mají titulkový pruh s tlačítky pro zavření, minimalizaci (a popř. další akce), budeme také chtít reagovat na požadavek na zrušení okna tímto tlačítkem. Proto použijeme funkci XSetWMProtocols, ve které zadáme atom WM_DELETE_WINDOW (získaný funkcí XInternAtom). Poté můžeme v cyklu zachytit také událost ClientMessage, a data události otestovat na WM_DELETE_WINDOW, a při rovnosti také ukončit cyklus na následně aplikaci.
Na závěr celý výpis ukázkového programu, který lze sestavit překladačem GCC následujícím příkazem:
gcc xlib-okno.c -lX11 -oxlib-okno
#include <stdlib.h> #include <stdio.h> #include <X11/Xlib.h> int main(int argc, char const *argv[]) { Display* display = XOpenDisplay(NULL); if (NULL == display) { printf("Chyba XOpenDisplay\n"); return EXIT_FAILURE; } int screen = DefaultScreen(display); Window window = XCreateSimpleWindow(display, RootWindow(display, screen), 10, 10, 800, 600, 1, BlackPixel(display, screen), WhitePixel(display, screen)); XSelectInput(display, window, ExposureMask | KeyPressMask | ButtonPressMask); XMapWindow(display, window); XStoreName(display, window, "X11 window"); Atom WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", False); XSetWMProtocols(display, window, &WM_DELETE_WINDOW, 1); XEvent event; while(1) { XNextEvent(display, &event); if (event.type == KeyPress) break; if (event.type == ButtonPress) break; if ((event.type == ClientMessage) && ((unsigned int)(event.xclient.data.l[0]) == WM_DELETE_WINDOW)) break; } XDestroyWindow(display, window); XCloseDisplay(display); return EXIT_SUCCESS; }
Nové články
Souborové operace na Linuxu v jazyce C
Využívejte Midnight Commander naplno
Procesor a jádra, běh na určeném jádru v C.
picom - kompozitor pro odlehčená Linuxová prostředí
Kontakt
739 219 991
live:radekchalupa_1