Ricerca tra la vecchia roba

X Window system

Posted: Agosto 10th, 2007 | Author: | Filed under: Guide, Programmazione | Commenti disabilitati su X Window system

( GUIDA IN VIA DI COMPLETAMENTO)

Xorg logo.

Nei sistemi Unix-like il gestore grafico standard è il cosidetto X Window system, sistema nato nel 1984 al MIT (da cui eredita la licenza), successore del gestore grafico W il quale girava sul sistema operativo V (notare come le lettere siano in successione). In linux si ha avuto la possibilità di usarlo dalla versione 0.95 della primavera del 1992 grazie alla implementazione (primitiva ai tempi) dei socket fatta da Orest Zborowsky[1].

Le caratteristiche fondamentali di queso sistema di gestione di finestre sono

  • Viene fornito solo l’ambiente base, cioé la gestione delle routine grafiche di disegno, creazione e spostamento delle finestre, interazione con tastiera, mouse ed altre periferiche.
  • Trasparenza di rete: il sistema si basa su una architettura client-server ed in particolare il server può controllare finestre che provengono da più computer remoti oppure localmente. 
  • Il server è stateless, cioé non "ricorda" la configurazione delle operazioni grafiche avvenute in precedenza (colore, spessore linee etc…) quindi esistono delle variabil, chiamate "contesti grafici" con le quali effettuare operazioni.
  • Facilmente estendibile per fornire nuove funzionalità.

Ecco uno schema rubato a wikipedia per farvi capire come agiscono i vari pezzi assieme:
 

X window system

Il lettore più attento avrà capito che parlando di comunicazione anche remota, questo gestore implementa un vero e proprio protocollo da rispettare per voler gestire le applicazioni all’interno delle finestre, ma ci viene in aiuto la Xlib, una libreria che si preoccupa di nascondere all’utente/programmatore i dettagli noiosi e mette a disposizione un numero variegato di API con le quali sbizzarrirsi; forse solo chi deve programmare un Window manager o uno screensaver ha bisogno di esse in quanto esistono un insieme di librerie grafiche, i cosidetti toolkit tramite cui poter creare e gestire le cosidette Graphical user interface (GUI per gli amici) in maniera più user friendly. Altro schemino rubato a wikipedia

 

Xlib wikipedia

 

 

 Ma se siete così pazzi da volerlo fare lo stesso, questa guida forse/spero farà per voi.

Comandi

 Prima di tutto bisogna capire che per far partire il server grafico, dobbiamo eseguire il comando /usr/bin/Xorg il quale leggerà il file di configurazione situato in /etc/X11/xorg.conf, proprio il file che i possessori di schede grafiche accelerate conoscono bene…. solo che così avete solo uno schermo grigio a pallini neri con il quale non esiste interazione! come nelle buone e vecchie scuole di magia, passiamo alla nuova formula magica che usa il mirabolante xinit, il quale si preoccupa di eseguire oltre al server anche un client che di default è xterm.  La sintassi è

xinit [client [opzioni]] — [server [display] [opzioni]] 

 notare che appena il client termina, anche il server viene chiuso. Ovviamente esiste il file di configurazione .xinitrc. posto nella HOME, in cui potete inserire i parametri con cui intendete lanciarlo, così da non dover scrivere tutte le opzioni a mano.

Esiste un ulteriore comando che si preoccupa  di un ulteriore livello: startx; esso ha la stessa sintassi di xinit e adesso me ne sfugge la differenza.

Una delle opzioni più interessanti riguarda il display: esso viene indicato con il seguente schema

 host:display_number.screen_number

come indicato nella sezione  DISPLAY NAMES della pagina di manuale di X. Se host non è indicato si presuppone il localhost, mentre con display_number si indica appunto in quale display si è avviato il server X (o lo si vuole avviare, visto che è una opzione di xinit); ovviamente funziona anche con i client basta preporre la variabile DISPLAY al lancio del client stesso come nel caso

DISPLAY=:1 xeyes

e se esiste un server in ascolto (e se si hanno i permessi) allora si aprirà una finestra su quel display.

Il server si apre  sul primo terminate virtuale che trova e come tutti sanno si passa da uno all’altro con la combinazione

Ctrl-Alt-Fn

dove con n bisogna sostituire il numero corrispondente alla console che ci interessa. 

Getting Started

Questo programma (rubato a wikipedia) apre una finestra

 

				/*
	Simple Xlib application drawing a box in a window.
	*/
	#include<X11/Xlib.h>
	#include<stdio.h>
	#include<stdlib.h>
	int main() {
	Display *d;
	int s;
	Window w;
	XEvent e;
	/* open connection with the server */
	d = XOpenDisplay(NULL);
	if(d == NULL) {
	printf("Cannot open displayn");
	exit(1);
	}
	s = DefaultScreen(d);
	/* create window */
	w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1,
	BlackPixel(d, s), WhitePixel(d, s));
	/* select kind of events we are interested in */
	XSelectInput(d, w, ExposureMask | KeyPressMask);
	/* map (show) the window */
	XMapWindow(d, w);
	/* event loop */
	while(1) {
	XNextEvent(d, &e);
	/* draw or redraw the window */
	if(e.type == Expose) {
	XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
	}
	/* exit on key press */
	if(e.type == KeyPress)
	break;
	}
	/* close connection to server */
	XCloseDisplay(d);
	return 0;
	}
	

Prima di tutto un minimo di nomenclatura: con display si intende l’insieme costituito da periferiche di input e da uno o più screen (da capire se intende Xinerama per più screen).  La prima cosa da fare è collegarsi all’X server tramite

						Display* XOpenDisplay(char* display_name) 
	

dove con display_name dovete indicare il particolare display a cui volete collegarvi: se ponete NULL si userà la variabile di ambiente DISPLAY; restituirà una struttura Display definita in Xlib.h con le quali referenziarsi per le successive connessioni.

Ovviamente la cosa più utile è ottenere una finestra su cui lavorare e per questo ci sono due funzioni che fanno al caso nostro

Window XCreateWindow(Display *display, Window parent, int x, int y,
              unsigned int width, unsigned int height, unsigned int border_width,
              int depth, unsigned int class, Visual *visual,
              unsigned long valuemask, XSetWindowAttributes *attributes);

Window XCreateSimpleWindow(Display *display, Window parent, int x, int y,
              unsigned int width, unsigned int height, unsigned int border_width,
              unsigned long border, unsigned long background);

Passo successivo è impostare "l’interesse" a certe classi di eventi quali tasti premuti, mouse in movimento etc… nel nostro caso ci interessiamo al Expose della finestra e all’interazione con la tastiera; per fare ciò useremo la funzione

						XSelectInput(d, w, ExposureMask | KeyPressMask);
	
 

Eventi 

Gli eventi a cui deve rispondere la finestra e che devono essere controllati dall’X server, come abbiamo visto, vengono scelti tramite la chiamata di funzione

int XSelectInput(Display* dpy,Window w,long event_mask)

dove la parte relativa aggli eventi è la event_mask, unione tramite OR delle seguenti maschere: 

Event Mask Symbol        Circumstances
————————————————————-
NoEventMask              No events
KeyPressMask             Keyboard down events
KeyReleaseMask           Keyboard up events
ButtonPressMask          Pointer button down events
ButtonReleaseMask        Pointer button up events
EnterWindowMask          Pointer window entry events
LeaveWindowMask          Pointer window leave events
PointerMotionMask        All pointer motion events
PointerMotionHintMask    Fewer pointer motion events
Button1MotionMask        Pointer motion while button 1 down
Button2MotionMask        Pointer motion while button 2 down
Button3MotionMask        Pointer motion while button 3 down
Button4MotionMask        Pointer motion while button 4 down
Button5MotionMask        Pointer motion while button 5 down
ButtonMotionMask         Pointer motion while any button down
KeymapStateMask          Any keyboard state change on EnterNotify , LeaveNotify , FocusIn or
ExposureMask             Any exposure (except GraphicsExpose and NoExpose )
VisibilityChangeMask     Any change in visibility
StructureNotifyMask      Any change in window configuration.
ResizeRedirectMask       Redirect resize of this window
SubstructureNotifyMask   Notify about reconfiguration of children
SubstructureRedirectMask Redirect reconfiguration of children
FocusChangeMask          Any change in keyboard focus
PropertyChangeMask       Any change in property
ColormapChangeMask       Any change in colormap
OwnerGrabButtonMask      Modifies handling of pointer events

Poi probabilmente il codice sarà costituito da un loop iin cui sarà contenuta una chiamata a

XNextEvent(Display* dpy,XEvent* event) 

in cui è implicita una chiamata a XFlush(). XEvent è un datatype definito come

typedef union _XEvent {
   int type;   /* Must not be changed; first member */
   XAnyEvent xany;
   XButtonEvent xbutton;
   XCirculateEvent xcirculate;
   XCirculateRequestEvent xcirculaterequest;
   XClientMessageEvent xclient;
   XColormapEvent xcolormap;
   XConfigureEvent xconfigure;
   XConfigureRequestEvent xconfigurerequest;
   XCreateWindowEvent xcreatewindow;
   XDestroyWindowEvent xdestroywindow;
   XCrossingEvent xcrossing;
   XExposeEvent xexpose;
   XFocusChangeEvent xfocus;
   XNoExposeEvent xnoexpose;
   XGraphicsExposeEvent xgraphicsexpose;
   XGravityEvent xgravity;
   XKeymapEvent xkeymap;
   XKeyEvent xkey;
   XMapEvent xmap;
   XUnmapEvent xunmap;
   XMappingEvent xmapping;
   XMapRequestEvent xmaprequest;
   XMotionEvent xmotion;
   XPropertyEvent xproperty;
   XReparentEvent xreparent;
   XResizeRequestEvent xresizerequest;
   XSelectionClearEvent xselectionclear;
   XSelectionEvent xselection;
   XSelectionRequestEvent xselectionrequest;
   XVisibilityEvent xvisibility;
} XEvent;

 Ciò nonostante quella appena citata non è l’unica funzione utilizzabile per gestire gli eventi: l’elenco è più o meno questo

  • int XPeekEvent(Display *display, XEvent *event_return);
    Come XNext ma non rimuove gli eventi dalla coda e attende.
  • int XWindowEvent(Display *display, Window w, long event_mask, XEvent* event_return);
    Ricerca nella coda eventi per eventi che rientrano nella maschera e nella finestra passata. Se la trova restituisce l’evento rimuovendolo dalla coda, mentre gli altri eventi sono mantenuti.
  • Bool XCheckWindowEvent(Display *display, Window w, long event_mask,XEvent *event_return);
    Ricerca nella coda eventi per il primo che coincide con la finestra e la maschera passata; se la trova restituisce TRUE e rimuove solo quell’evento dalla coda. Nel caso non ci sia l’evento desiderato restituisce FALSE e il buffer di uscita è svuotato (?).
  • int XMaskEvent(Display *display, long event_mask, XEvent*event_return);
    Ricerca nella coda un evento che coincida con la maschera event_mask e nel caso la trovi lo restituisce senza eliminare gli altri eventi; nel caso non lo trovi, il buffer è svuotato e si blocca (ma anche se non lo svuotasse? tanto poi lo riempie con i nuovi dati!).
  • Bool XCheckMaskEvent(Display *display, long event_mask, XEvent*event_return);
    Come sopra, semplicemente restituisce TRUE o FALSE senza essere bloccante.
  • Bool XCheckTypedEvent(Display *display, int event_type, XEvent*event_return);
    Ricerca nella coda per eventi che rispecchino event_type e nel caso li trovi lo restituisce in XEvent e non tocca gli altri eventi; nel caso non li trovi si blocca.
  • Bool XCheckTypedWindowEvent(Display *display, Window w, int event_type,XEvent *event_return);
    Come sopra ma non bloccante.

Tastiera

Molto importante è la interazione con la testiera a cui dedico una sezione a parte: essa insieme al cursore (probabilmente controllato dal mouse) permette l’interazione tra il client, il server ed il mondo esterno; in maniera analoga al kernel linux (probabilmente anche a tutti i sistemi che si trovano a gestire una tastiera) esiste una distinzione in due livelli sull’identificazione di un tasto all’interno di una tastiera

  • keycode: codice numerico (da 8 a 255) che si riferisce all’identità fisica (logica) di un tasto.
  • keysym: associa al keycode un significato esplicito tenendo conto anche dei modificatori premuti

Esistono funzioni per mappare fra loro keysym e keycode et altro

KeySym XKeycodeToKeysym(Display* d,int keycode, int index)
KeySym XStringToKeysym(char* string);
char* XKeysymToString(KeySym keysym);
Keycode XKeysymToKeycode(Display* dpy, KeySym keysym);

da notare come per le conversioni tra keycode e keysym serva un collegamento al server, questo in quanto la tabella di conversione è immagazzinata nel server anche se la traslazione viene effettuata a livello client.

È possibile da parte di un cliente chiedere il controllo totale della tastiera tramite le funzioni

XGrabKeyboard(Display* d, Window w, Bool owner, int pointer_mode,
            int keyboard_mode,Time time);

XGrabKey(Display* d,int keycode, unsigned int modifier, Window grab_window,
            Bool owner, int pointer_mode, int keyboard_mode);

 

Eccovi un bel esempio di codice che esegue un grab completo della tastiera restituendo a schermo i dati dei tasti premuti (keycode, keysym, modificatori etc…), premete il tasto ‘q’ quando vi siete stufati

#include<stdio.h>
#include<stdlib.h>
#include<X11/Xlib.h>
#include<X11/keysym.h>/*it contains the KeySym definitions*/

#define is_press_also(mask) (modifier_state & (mask))

int main(int argc, char **argv){
  Display* dpy;
  Window root;

  dpy = XOpenDisplay(NULL);
  if(!dpy){
    fprintf(stderr , "I could not open displayn");
    exit(EXIT_FAILURE);
  }
  root = DefaultRootWindow(dpy);
  /*it’s not necessary*/
  //XSelectInput(dpy, root, KeyPress);
  //
  /*check for options*/
  KeySym key_grabbed;
  if(argc > 1){
    key_grabbed = XStringToKeysym(argv[0]);
    XGrabKey(dpy, key_grabbed, 0, root, False, GrabModeAsync,GrabModeAsync);
  }else
    XGrabKeyboard(dpy, root, False, GrabModeAsync,GrabModeAsync,CurrentTime);

  /*message for you rudy…*/
  fprintf(stderr , "this application grab exclusively the keyboard, press ‘q’ to exitn");

  XEvent e;
  KeySym ks;
  int modifier_state;
  while(1){
    XNextEvent(dpy,&e);
    switch(e.type){
      case KeyPress:
        /*last argument is 0, why?*/
        ks = XKeycodeToKeysym(dpy, e.xkey.keycode, 0);
        modifier_state = e.xkey.state;
        /*looking for KeySyms*/
        switch(ks){
          case XK_q:
            fprintf(stderr , "now exit from this helln");
            exit(EXIT_SUCCESS);
            break;
          default:
            fprintf(stderr , "keycode %02d keysym %02d", e.xkey.keycode, ks);
        }
        /*looking for modifiers*/
        if(is_press_also(ShiftMask))
          fprintf(stderr , " shift pressed");
        if(is_press_also(LockMask))
          fprintf(stderr , " lock pressed");
        if(is_press_also(ControlMask))
          fprintf(stderr , " control pressed");
        if(is_press_also(Mod1Mask))
          fprintf(stderr , " mod1 pressed");
        if(is_press_also(Mod2Mask))
          fprintf(stderr , " mod2 pressed");
        if(is_press_also(Mod3Mask))
          fprintf(stderr , " mod3 pressed");
        if(is_press_also(Mod4Mask))
          fprintf(stderr , " mod4 pressed");
        if(is_press_also(Mod5Mask))
          fprintf(stderr , " mod5 pressed");

        /*i have style…*/
        fprintf(stderr , "n");
        break;
    }

  }

  return EXIT_SUCCESS;
}

 

Estensioni 

Il server X ha la capacità di estendere tramite appunto extensions le sue capacità per adeguarsi per esempio alle nuove tecnologie; nel seguente codice vengono elencate tutte le estensioni all’interno del sistema:

#include<stdio.h>
#include<X11/Xlib.h>

int main(){
    int n_exts,ciclo;
    Display* dpy = XOpenDisplay(NULL);

    char** exts = XListExtensions(dpy,&n_exts);

    fprintf(stdout,"There are %d extensions present in this X servern",n_exts);
    for(ciclo=0;ciclo < n_exts;ciclo++)
        fprintf(stdout,"t%sn",exts[ciclo]);

}

Cosa utile da sapere è che in generale bisogna aggiungere come flag di compilazione -lXext per usare queste funzionalità.

Double Buffer 

Una delle prime cose che ho imparato nella programmazione (ai tempi dell’amiga 600) era la tecnica del double buffering: se si cerca di creare una animazione ridisegnando ad ogni frame da zero la finestra, si ha il cosiddetto sfarfallio che risulta fastidioso da vedere, quindi urge una tecnica che permetta alla nostra animazione di risultare più uniforme ed è proprio qui che entra in gioco il double buffering. Si tratta in pratica di creare una seconda superficie (non visibile, residente solo in memoria) dove effettuare "di nascosto" le operazione grafiche necessarie, per poi effetturare uno scambio con la superficie visibile la quale diventerà a sua volta quella nascosta.

Nativamente X non ha questa capacità,  ma tramite l’estensione appropriata tutto è possibile. Prima di tutto vi è da includere il giusto header

 #include <X11/extensions/Xdbe.h>

poi boh…. appena la provo meglio vi dico…

XInput extension 

Nata per permettere di usare tramite X anche periferiche di input di moderna invenzione, quali touchscreen, joystick e dildi… in questo codice vengono elencate le periferiche collegate (aggiungere flag -lXi)

#include<stdio.h>
#include<stdlib.h>
#include<X11/Xlib.h>
#include<X11/extensions/XInput.h>

int main(){
    XDeviceInfo* info = malloc(sizeof(XDeviceInfo));
    XDeviceInfo* dummy_info_node;
    int n_info;
    int ciclo;

    Display* dpy = XOpenDisplay(NULL);
    if(dpy == NULL){
        fprintf(stderr , "Errore nell’apertura del displayn");
        return EXIT_FAILURE;
    }

    info = XListInputDevices(dpy,&n_info);
    fprintf(stdout,"There are present %d input devicesn",n_info);
    for(ciclo = 0 ; ciclo < n_info; ciclo++){
        dummy_info_node = info + ciclo;
        fprintf(stderr ,
                "Device number %dn"
                "tid:%dn"
                "tname:%sn"
                ,
                ciclo,
                dummy_info_node->id,
                dummy_info_node->name
                );
    }
    return EXIT_SUCCESS;
}

La chiamata ad XListInputDevices restituisce un puntatore ad una lista di XDeviceInfo, una struct cioé avente la seguente definizione

typedef struct _XDeviceInfo
{
    XID       id;
    Atom      type;
    char      *name;
    int       num_classes;
    int       use;
    XAnyClassPtr   inputclassinfo
 } XDeviceInfo;

ed inoltre inserisce in n_info il numero di elementi presenti nella lista. Il problema con questa estensione, è che non esistono modo per usare più cursori contemporaneamente (almeno nel server X classico), cioé esiste sempre e comunque un core pointer ed una core keyboard e cambia il modo di riconoscere gli eventi (un pochino incasinato): siccome ci possono essere a questo punto più periferiche che danno origine allo stesso evento, si necessita di qualcosa di diverso per gestire l’interazione rispetto alla trattazione normale. Ci sono sempre le classificazioni basate sugli event type, ma vengono aggiunti le Event Classes, numeri interi (non costanti al contrario dei core events) che identificano un determinato evento 

XShape extension

È anche possibile creare finestre con una forma non rettangolare tramite la estensione XShape; qui di seguito un codice che prende una immagine png e la copia come sfondo nella finestra usando le parti trasparenti di questa come maschera per la propria (cazzo ho scritto?)

/*
 * Using the X11 shape extension, draw a window with transparent part
 *
 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<cairo.h>
#include<cairo-xlib.h>
#include<X11/extensions/shape.h>

#define SABCAT_PATH "/home/packz/Image/sabcat.png"

int main(){
        Display* dpy;
        Window window,root;
        Visual* visual;
        Colormap colormap;
        unsigned int depth;
        int screen;
        Screen* schermo;

        /*apriamo il collegamento*/
        dpy = XOpenDisplay(NULL);
        if(dpy == NULL){
                fprintf(stderr , "(E) errore apertura displayn");
                return EXIT_FAILURE;
        }

        /*qualche variabile utile*/
        root = DefaultRootWindow(dpy);
        screen = DefaultScreen(dpy);
        depth = DefaultDepth(dpy,screen);
        visual = DefaultVisual(dpy,screen);
        colormap = XDefaultColormap(dpy,screen);
        schermo = ScreenOfDisplay(dpy,screen);
        int black = BlackPixel(dpy,screen);

        cairo_t* cr;

        cairo_surface_t* sabcat_srf =
                cairo_image_surface_create_from_png(SABCAT_PATH);
       
        int width = cairo_image_surface_get_width(sabcat_srf);
        int height = cairo_image_surface_get_height(sabcat_srf);

        window = XCreateSimpleWindow(dpy,root,
                        0,0,width,height,
                        0, 0, black);

        XSelectInput(dpy, window, StructureNotifyMask|ExposureMask);
        XMapWindow(dpy,window);

        cairo_surface_t* backbuffer =
            cairo_xlib_surface_create(dpy,window,visual,width,height);
        cr = cairo_create(backbuffer);
        cairo_set_source_rgb(cr,1,0,0);
        cairo_paint(cr);
        cairo_surface_destroy(backbuffer);
        cairo_destroy(cr);

        Pixmap sabcat_pixmap = /*for use as Mask (depth = 1)*/
            XCreatePixmap(dpy,window, width,height,1);

        cairo_surface_t* mask_surface =
            cairo_xlib_surface_create_for_bitmap(dpy,sabcat_pixmap,schermo,width,height);
        cr = cairo_create(mask_surface);
        cairo_set_source_rgb(cr,0,0,0);
        cairo_set_operator(cr,CAIRO_OPERATOR_CLEAR);
        cairo_paint(cr);
        cairo_set_operator(cr,CAIRO_OPERATOR_OVER);
        cairo_set_source_surface(cr,sabcat_srf,0,0);
        cairo_paint(cr);

        /*this is the magic call*/       
        XShapeCombineMask(dpy,window,ShapeBounding,0,0,sabcat_pixmap,ShapeSet);
        XFlush(dpy);

        /*from http://www.archivum.info/comp.os.linux.x/2005-11/msg00121.html*/
         /*i dont know because works*/

#if 1
#define MWM_HINTS_FUNCTIONS    (1L << 0)
#define MWM_HINTS_DECORATIONS   (1L << 1)
#define MWM_HINTS_INPUT_MODE    (1L << 2)
#define MWM_FUNC_MOVE           (1L << 2)
#define MWM_INPUT_MODELESS      0
        struct {
                long flags;
                long functions;
                long decorations;
                long inputmode;
        } prop;

        prop.flags=MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS|MWM_HINTS_INPUT_MODE;
        prop.decorations=0;
        prop.functions=MWM_FUNC_MOVE;
        prop.inputmode=MWM_INPUT_MODELESS;

        Atom a = XInternAtom(dpy,"_MOTIF_WM_HINTS",0);

        XChangeProperty( dpy, window, a, a, 32, PropModeReplace, (unsigned char*)&prop, 4);

#endif

        XEvent evt;
        /*looping over events*/
        while(1){
                XNextEvent( dpy, &evt );   // calls XFlush()
                switch(evt.type){
                        case KeyPress:
                        if(evt.xkey.keycode == XKeysymToKeycode(dpy, XStringToKeysym("Q")))
                                return EXIT_SUCCESS;
                        break;
                        default:
                        fprintf(stderr ,"Eventon");
                }
        }

        /*exit routine*/
        XDestroyWindow( dpy, window );
        XCloseDisplay(dpy);

        return EXIT_SUCCESS;
}

Usa anche le librerie cairo, ma fate finta di sapere cosa fa… per compilarlo usate

gcc transparent.c -o transparent -lX11 -lXext `pkg-config cairo –cflags –libs`

e lanciatelo per stupirvi.. ovviamente dovete mettere una immagine che possedete nella define SABCAT_PATH, basta che sia png. 

Futuro

 Parrebbe che ci sia una attiva riscrittura delle routine per la interazione con X attraverso la nuova libreria xcb la quale eviterebbe molti tempi morti rispetto alla Xlib: infatti quando effettuiamo una richiesta al server, il client si blocca in attesa di una risposta e se si hanno molte richieste da effettuare di seguito, comunque il sistema deve attendere per la risposta una alla volta: lo schema può essere riassunto così

  W-----RW-----RW-----RW-----R

  • W: Writing request
  • -: Stalled, waiting for data
  • R: Reading reply

The total time is N * (T_write + T_round_trip + T_read). Con Xcb si avrebbe invece

WWWW--RRRR

The total time is N * T_write + max (0, T_round_trip – (N-1) *T_write) + N * T_read. Which can be considerably faster than all those Xlib round-trips.

Linkografia&Ulteriori informazioni


[1] Da "Just for fun" (in italiano "Rivoluzionario per caso" edito sempre in italia da Garzanti).


Comments are closed.