Tutoriál grafiky pomocí Xlib Projekt do GZN Radek Brich Fakulta informačních technologií Vysoké učení technické v Brně 2006 Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 1 / 26
X Window System (1) Historie 1984 počátek vývoje. 1985 verze 9 licence MIT. 1987 vychází verze 11. Architektura klient server Server kreslí na obrazovku a čte vstup od uživatele. Klient určuje, co kreslit a zpracovává vstup od uživatele. Sít ová transparence. Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 2 / 26
X Window System (2) Hierarchie oken Kořenové okno (root) celá obrazovka. Okna nižších úrovní patří aplikacím. O správu oken první úrovně se stará speciální program Window Manager. S okny dalších úrovní může aplikace nakládat libovolně. Každá událost je propagována hierarchií oken nahoru dokud není zpracována. Klient se serverem komunikuje standardním X protokolem. Ten je implementován v knihovně Xlib. Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 3 / 26
Knihovna Xlib Vrstva mezi X protokolem a aplikací. Obsahuje funkce pro komunikaci s X serverem práce s okny, zpracování událostí, jednoduché kreslení. Xlib má být maximálně univerzální nepodporuje žádné prvky uživatelského rozhraní. Další vrstva nad Xlib knihovny nástrojů. Motif, GTK, Qt,... Obsahují sadu objektů pro tvorbu uživatelského rozhraní a další pomocné funkce. Pomáhají tvořit jednotný vzhled aplikací. Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 4 / 26
Příklad Minimální X klient Následuje ukázka jednoduchého programu s Xlib, který se připojí k X serveru, vytvoří a zobrazí okno, nakreslí do něj čáru. Program naleznete v souboru xlib-minimal.c, přiložen je také Makefile. Při překladu v gcc je nutno přilinkovat knihovnu X11: gcc xlib-minimal.c -o xlib-minimal -lx11 Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 5 / 26
Připojení k X serveru Display *XOpenDisplay(char *display_name) Parametr display_name identifikuje libovolný display v síti, např. "jmeno.pocitace.dom:0". Lze předat také NULL, pak se použije obsah proměnné prostředí DISPLAY. #include <stdio.h> #include <X11/Xlib.h> int main() { Display *display = XOpenDisplay(NULL); if (display == NULL) { fprintf(stderr, "Cannot connect to X server."); return(-1); } } XCloseDisplay(display); return 0; Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 6 / 26
Vytvoření okna Objekt okna se vytváří funkcí XCreateWindow (mnoho parametrů) nebo XCreateSimpleWindow (méně parametrů). XMapWindow okno zobrazí. int screen = DefaultScreen(display); int black = BlackPixel(display, screen); int white = WhitePixel(display, screen); Window window = XCreateSimpleWindow( display, /* display */ DefaultRootWindow(display), /* parent window */ 0, 0, /* x, y */ 160, 100, /* width, height */ 0, /* border_width */ black, black /* border color, background */ ); XMapWindow(display, window); Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 7 / 26
Grafický kontext (1) Grafický kontext (GC) obsahuje různé parametry kreslení. Vytvoříme grafický kontext s bílou barvou popředí: GC gc = XCreateGC(display, window, /* drawable */ 0, /* valuemask */ NULL); /* values[] */ XSetForeground(display, gc, white_pixel); Nebo s použitím posledních dvou parametrů: XGCValues values = {.foreground=white_pixel }; GC gc = XCreateGC(display, window, GCForeground, &values); Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 8 / 26
Grafický kontext (2) Pro všechny atributy GC existují příslušné funkce: XSetForeground, XSetBackground, XSetLineAttributes, XSetDashes, XSetFont,... Atributy čáry (XSetLineAttributes): line_width tloušt ka line_style styl LineSolid (plná čára) LineOnOffDash (střídání barva/nic) LineDoubleDash (barva popředí/pozadí) cap_style zakončení čáry CapButt (kolmé) CapNotLast (při tloušt ce 1 pixel se poslední bod nekreslí) CapRound (zakulacený konec) CapProjecting (prodloužení o polovinu tloušt ky čáry) join_style způsob navázání čáry JoinMiter (ostré) JoinRound (kulaté) JoinBevel (setnuté) Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 9 / 26
Smyčka událostí Události si musíme od X Serveru vyžádat funkcí XSelectInput. Expose je zaslán vždy při ztrátě části obsahu okna požadavek na překreslení. XSelectInput(display, window, ExposureMask); XEvent event; while (1) { XNextEvent(display, &event); switch (event.type) { case Expose: if (event.xexpose.count > 0) xlib-minimal.c break; XDrawLine(display, window, gc, 10, 20, 150, 80); XFlush(display); break; } } Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 10 / 26
Kreslící funkce Bod XDrawPoint(display, drawable, gc, x, y) Čára XDrawLine(display, drawable, gc, x1, y1, x2, y2) Oblouk jednotkou pro zadávání úhlu je 1/64 stupně. XDrawArc(display, drawable, gc, x, y, width, height, angle1, angle2) Obdélník XDrawRectangle(display, drawable, gc, x, y, width, height) Text XDrawString(display, drawable, gc, x, y, char *string, length) Dále varianty: XDrawPoints, XDrawLines, XDrawArcs,... XDrawString16, XDrawImageString (kreslí navíc pozadí),... Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 11 / 26
Složitější program - malování Nyní program rozšíříme: podokna a další události, více barev, výpis textu. Výsledný program je k dispozici v souboru xlib-scrawl.c. Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 12 / 26
Další události Klávesnice: KeyPress, KeyRelease (maska pro XSelectInput: KeyPressMask, KeyReleaseMask). Myš: ButtonPress, ButtonRelease (ButtonPressMask, ButtonReleaseMask), MotionNotify (PointerMotionMask, ButtonMotionMask pohyb myší se stisknutým tlačítkem, Button1MotionMask výběr konkrétního tlačítka, PointerMotionHintMask poslat událost jen když se změní stav tlačítek). Zaměření okna myší či klávesnicí: EnterNotify, LeaveNotify (EnterWindowMask, LeaveWindowMask), FocusIn, FocusOut (FocusChangeMask). Změna stavu okna pozice, velikost, rámeček, vrstva: ConfigureNotify (StructureNotifyMask). Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 13 / 26
Okno pro kreslení (1) Vytvoříme si podokno, do kterého se bude kreslit. Window canvas = XCreateSimpleWindow(display, window,..., 1 /*border_width*/, white_pixel /*border*/, black_pixel /*bground*/); Vyžádáme si pro něj události od myši při stisknutém tlačítku budeme kreslit čáry mezi dvěma posledními pozicemi myši. XSelectInput(display, canvas, ButtonPressMask ButtonReleaseMask ButtonMotionMask ExposureMask); XMapWindow(display, canvas); Také vytvoříme další GC pro kreslení do tohoto okénka. GC canvas_gc = XCreateGC(display, canvas, 0, NULL); XSetForeground(display, canvas_gc, white_pixel); Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 14 / 26
Okno pro kreslení (2) int prev_x = -1, prev_y; switch (event.type)... case ButtonPress: case ButtonRelease: case MotionNotify: if (event.xbutton.window == canvas) { int x = event.xbutton.x; int y = event.xbutton.y; }... if (prev_x > 0) XDrawLine(display, canvas, canvas_gc, prev_x, prev_y, x, y); if (event.type == ButtonRelease) prev_x = -1; else { prev_x = x; prev_y = y; } XFlush(display); break; Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 15 / 26
Pixmapy (1) Nyní po zakrytí a následném odkrytí okna nakreslené čáry mizí. Řešení problému kreslit paralelně také do pixmapy. Do pixmapy lze kreslit stejným způsobem jako do okna, její obsah je ale X Serverem vždy udržován. Při události Expose budeme kopírovat příslušnou část pixmapy do okna canvas. Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 16 / 26
Pixmapy (2) Pixmap canvas_pixmap = XCreatePixmap(display, canvas, 800 /*width*/, 600 /*height*/, DefaultDepth(display, screen));... case Expose: if (event.xexpose.window == canvas) { int x = event.xexpose.x; int y = event.xexpose.y; XCopyArea(display, canvas_pixmap /*src*/, canvas /*dest*/, gc, x, y, /* src x, y */ event.xexpose.width, event.xexpose.height, /* src w, h */ x, y /* dest x, y */); }... case ButtonPress: case ButtonRelease: case MotionNotify:... XDrawLine(display, canvas, canvas_gc, prev_x, prev_y, x, y); XDrawLine(display, canvas_pixmap, canvas_gc, prev_x, prev_y, x, y);... Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 17 / 26
Alokace barev Barva se vybírá z 48-bitového rozsahu. Funkce XAllocColor přiřadí pixelu nejbližší barvu, která je k dispozici. XFreeColors uvolní nepoužívané barvy z palety. Colormap colormap = DefaultColormap(display, screen); XColor green = {.red=0x0000,.green=0xffff,.blue=0x0000}; XAllocColor(display, colormap, &green); XFreeColors(display, colormap, &green.pixel /* pixels[] */, 1 /* npixels */, 0 /* planes */); Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 18 / 26
Fonty a text Font je identifikován řetězcem s parametry fontu. Takový řetězec lze vytvořit programem xselfont. Například Helvetica s českým kódováním o velikosti 12 bodů: "-*-helvetica-medium-r-*-12-*-iso8859-2" Font font = XLoadFont(display, "-*-helvetica-medium-r-*-12-*"); XSetFont(display, gc, font);... case Expose: /* main window */ if (event.xexpose.window == window) { char *s = "Line width:"; XSetForeground(display, gc, white_pixel); XDrawString(display, window, gc, 10, 20, s, strlen(s)); } Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 19 / 26
Atributy okna (1) Každému oknu lze nastavit různé atributy (pozadí, rámeček, gravitace, maska událostí, kurzor a další). Atributy se oknu nastaví bud přímo při vytvoření funkcí XCreateWindow nebo později pomocí XChangeWindowAttributes. Události lze také vybrat funkcí XSelectInput. Struktura XSetWindowAttributes obsahuje všechny atributy okna ty, které chceme skutečně změnit, určíme maskou. Příklad: XSetWindowAttributes attributes = {.win_gravity = SouthWestGravity }; XChangeWindowAttributes(display, window, CWWinGravity, &attributes); Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 20 / 26
Atributy okna (2) Vybrané atributy (v závorce příslušná maska): background_pixmap (CWBackPixmap), background_pixel (CWBackPixel), border_pixmap (CWBorderPixmap), border_pixel (CWBorderPixel) bit_gravity (CWBitGravity) kde zůstane obsah okna při změně jeho velikosti (implicitně ForgetGravity zapomene se), win_gravity (CWWinGravity) kam se přesune okno při změně velikosti rodiče backing_store (CWBackingStore) udržování obsahu okna na straně X Serveru, save_under (CWSaveUnder) pro pop-up okna, pamatují se pixely zakryté tímto oknem event_mask (CWEventMask) množina událostí, které okno přijímá, do_not_propagate_mask (CWDontPropagate) množina událostí, které se nemají předávat rodiči colormap (CWColormap), cursor (CWCursor) Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 21 / 26
Další parametry okna (1) Každému oknu lze přiřadit jméno: XStoreName(display, window, "Scrawl"); U prvního programu nebylo ukončení čisté pokud uživatel zavřel okno, program byl jednoduše zabit window managerem. Řešení vyžádat si od WM událost WM_DELETE_WINDOW. WM pak jen pošle tuto událost a předpokládá, že se program o likvidaci daného okna postará sám. Atom delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 1); XSetWMProtocols(display, window, &delete_window, 1); Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 22 / 26
Další parametry okna (2) WM nemá rezervovány speciální události používá událost ClientMessage (komunikace mezi klienty). int alive = 1; while (alive) { XNextEvent(display, &event); switch (event.type) {... case ClientMessage: if (event.xclient.data.l[0] == delete_window) alive = 0; /* exit program */ break;... } } XDestroyWindow(display, window); XCloseDisplay(display); Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 23 / 26
Výsledný program Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 24 / 26
Závěr Hotový program má po přeložení 15 kb :-) Xlib je nutné použít pro psaní Window Manageru a nových toolkitů. Psát běžné programy přímo v Xlibu se většinou nevyplatí... Budoucnost: XCB (X C Binding) nový projekt (2001), jeho cílem je nahradit Xlib. menší komplexita a velikost knihovny nižší úroveň, blíže k protokolu X11 vhodnější pro PDA apod. Implementace X-Serveru: X.org (původně XFree86) pro unixové systémy. Xming, Cygwin/X X Server pro Microsoft Windows X11.app implementace X Serveru obsažená v MacOS X (založena na XFree86) Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 25 / 26
Literatura The Xlib Manual Dodáván v distribuci X Window System, HTML verze zde: http://tronche.com/gui/x/xlib/ Xlib Programming Manual (O Reilly & Associates, Inc.) http://www.sbin.org/doc/xlib/ Wikipedia http://en.wikipedia.org/wiki/xlib http://en.wikipedia.org/wiki/x_window_system Radek Brich (FIT VUT Brno) Tutoriál grafiky pomocí Xlib 2006 26 / 26