Confessioni About Copertina Yacc & Lex |
Articoli
Programmazione sotto X con X-Lib
Un esempio di sorgente C che esemplifica le funzioni base per programmare sotto X con le librerie Xlib.
Devo premettere che non sono un esperto nè di C e C++, nè tantomeno di Xlib, tutto quello che so viene da esperienza personale. Ho scritto un semplice programma, appwin.c, che mi accingo a descrivere:
Codice introduttivo |
|
---|---|
#include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xos.h> #include <X11/Xatom.h> #include <X11/keysym.h> #include <X11/Xproto.h> | Header delle librerie Xlib |
#include <stdio.h> #include <stdlib.h> #include "logo.xbm" | Questo è un semplice file xbm che serve per definire l' icona. |
void inializzazione(); void disegna(); int Controllo_degli_eventi(); #define TRUE (1) #define FALSE (0) | Prototipi di funzioni e di void. |
Display *display; GC gc1, gc2; Window window, parent, root; int depth, screen, visibility; | Queste sono le definizioni delle variabili che poi servono per le Xlib. |
char *host = NULL; int windowwidth = 400, windowheight = 300, window_x_pos = 200, window_y_pos = 200; int col1=1, col2=4, col3=7, col4=9; int tmp1, tmp2, tmp3, tmp4; | |
Funzione main |
|
main(int argc, char *argv[]) { | |
if (host == NULL) if ((host = (char *) getenv("DISPLAY")) == NULL) { fprintf(stderr, "%s", "Error: No environment variable DISPLAY\n"); } | Questo if controlla il valore della variabile d'ambiente DISPLAY. |
inizializzazione(); | |
gc1 = XCreateGC(display, window, 0, NULL); gc2 = XCreateGC(display, window, 0, NULL); | Creazione di un graphic context. |
XSetForeground(display, gc1, BlackPixel(display, screen)); disegna(); } | |
Inizializzazione |
|
void inializzazione() { XSetWindowAttributes attr; char *naAme; Pixmap iconPixmap; XWMHints xwmhints; if((display = XOpenDisplay(host)) == NULL) { fprintf(stderr,"Error: Connection could not be made.\n"); exit(1); } | In questa void si settano alcune propietà della finestra. Ad esempio: su che display la si deve creare, qual'è il suo nome, la dimensione, eccetera. |
screen = DefaultScreen(display); root = parent = RootWindow(display,screen); | Vede il numero del display su cui state mandando la finestra (per capirci: quando usate il comando export DISPLAY=display:0.x, x è il valore di screen che in genere è zero). |
depth = DefaultDepth(display,screen); | Serve per vedere quanti planes usa il terminale dove state mandando la finestra. |
XSelectInput(display,root,SubstructureNotifyMask); attr.event_mask = StructureNotifyMask | SubstructureNotifyMask | VisibilityChangeMask | ExposureMask; attr.background_pixel = BlackPixel(display,screen); | Queste funzioni sappiate solo che esistono. |
window = XCreateWindow(display, root, window_x_pos, window_y_pos, windowwidth, windowheight, 0, depth, InputOutput, DefaultVisual(display,screen), CWEventMask|CWBackPixel, &attr); | Qui veniamo alla creazione della finestra, anche se non fisicamente, poichè dopo bisogna "mapparla" sul display con la funzione XMapWindow(). |
name = "Appwin"; XChangeProperty(display, window, XA_WM_NAME, XA_STRING, 8, PropModeReplace, name, strlen(name)); XMapWindow(display,window); | Con la funzione XChangeProperty si modificano le propietà della finestra, in questo caso il nome dell'icona e della finestra. |
iconPixmap = XCreateBitmapFromData(display, window, logo_bits,logo_width,logo_height); xwmhints.icon_pixmap = iconPixmap; xwmhints.initial_state = NormalState; xwmhints.flags = IconPixmapHint | StateHint; XSetWMHints(display, window, &xwmhints ); | Creazione dell 'icona dal file logo.xbm |
N.B. I file .xbm sono dei semplici file testo in C, nelle cui prime righe vengono definite le variabili logo_height eccetera. In genere se salvate un file con il nome pluto in formato xbm, avrete come variabili nelle prime linee pluto_height ... Quindi se volete cambiare icona non vi resta che provare. |
|
XClearWindow(display,window); XSync(display, 0); } | |
Funzione disegna |
|
void disegna() { | In questa void si disegna un rettangolo, 4 quadrati che si invertono i colori, ed una serie di linee. |
while(TRUE) { Controllo_degli_eventi(); | Il while ci vuole altrimenti vedreste la finestra per un tempo piccolissimo. |
XSetForeground(display, gc2, 1); | Disegna delle linee con il colore definito da XSetForeground, dove il colore si definisce con il terzo argomento (che deve essere un intero) della funzione. |
XDrawLine(display,window,gc2,10,20,300,20); | Disegna una linea dal punto (10,20) a (300,20). |
XSetForeground(display, gc2, 2); XDrawLine(display, window, gc2, 300, 20, 300, 200); XSetForeground(display, gc2, 9); XFillRectangle(display, window, gc2, 254, 102, 45, 99); | Disegna un rettangolo dal punto (254,102) con 45 di larghezza e 99 di altezza. |
tmp1=col1; tmp2=col2; tmp3=col3; tmp4=col4; col1=tmp3; col2=tmp1; col3=tmp4; col4=tmp2; XSetForeground(display, gc2, col1); XFillRectangle(display,window,gc2,30,160,50,50); XSetForeground(display, gc2, col2); XFillRectangle(display,window,gc2,81,160,50,50); XSetForeground(display, gc2, col3); XFillRectangle(display,window,gc2,30,211,50,50); XSetForeground(display, gc2, col4); XFillRectangle(display,window,gc2,81,211,50,50); | |
usleep(500000); } } | Serve per ritardare la rotazione dei colori altrimenti non si vede niente (per essere precisi si vede il bianco, come la fisica cerca di insegnare). |
N.B. Vorrei far notare si può sfruttare le potenzialità del C++ in ambiente grafico senza complicarsi la vita. Infatti definendo una classe rettangolo, si può usare per avere (derivando) un rettangolo con scritta, un bottone che è un rettangolo "attivo" e così altri classi generiche da cui poi derivare. Con questo non voglio dire che per programmare sotto X bisogna usare il C++, infatti questo programma è scritto in C, ma può essere utile per non incasinarsi se si scrive un programma molto complesso. |
|
Controllo degli eventi |
|
int Controllo_degli_eventi() { XEvent event; int block = FALSE; int status = 0; while((XPending(display) > 0) || (block == TRUE)) { XNextEvent(display,&event); switch(event.type) { case ReparentNotify: if(event.xreparent.window != window ) break; XSelectInput(display, event.xreparent.parent, StructureNotifyMask); XSelectInput(display,parent,0); parent = event.xreparent.parent; break; case UnmapNotify: if ((event.xunmap.window != window) && (event.xunmap.window != parent)) break; block = TRUE; break; case VisibilityNotify: if (event.xvisibility.window != window) break; if (event.xvisibility.state == VisibilityFullyObscured) { block = TRUE; break; } if ((event.xvisibility.state == VisibilityUnobscured) && (visibility == 1)) { visibility = 0; block = FALSE; break; } if (event.xvisibility.state == VisibilityPartiallyObscured) { visibility = 1; block = FALSE; } break; case Expose: block = FALSE; break; case MapNotify: if ((event.xmap.window != window) && (event.xmap.window != parent)) break; block = FALSE; break; case ConfigureNotify: if (event.xconfigure.window != window) break; if ((windowwidth == event.xconfigure.width) && (windowheight == event.xconfigure.height)) break; windowwidth = event.xconfigure.width; windowheight = event.xconfigure.height; XClearWindow(display, window); block = FALSE; status = 1; break; default: break; } } return(status); } | Questa è la funzione più complicata. Bisogna dire che X gestisce degli eventi che possono essere di vario tipo. Non mi permetto di descrivere tutti i tipi di eventi che X può gestire o generare, ma se volete vedere quando un determinato evento si verifica potete usare il programma xev. Prendete questa funzione per buona, magari ne parlerò in un prossimo articolo. |
Confessioni About Copertina Yacc & Lex |