Creare una finestra mediante le funzioni del API di X11

Da Gambas-it.org - Wikipedia.

Con le risorse del API di X11 è possibile creare una finestra ed interagire con essa.

Sarà necessario richiamare la libreria di X attualmente: "libX11.so.6.3.0"

Mostriamo di seguito un breve codice per creare una semplice finestra, nella quale saranno disegnate figure geometriche e caratteri testuali. Sarà, inoltre, possibile intercettare alcuni eventi provenienti dalla tastiera e dal mouse:

Public Struct XEventStruct
  type As Integer
  serial As Long
  send_event As Boolean
  display As Pointer
  windowL As Long
  root As Long
  subwindow As Long
  timeL As Long
  x As Integer
  y As Integer
  x_root As Integer
  y_root As Integer
  state As Integer
  keycode As Integer
  same_screen As Boolean
End Struct

Public Struct XFontStruct
  ext_data As Long
  fid As Pointer
  direction As Byte
  min_char_or_byte2 As Byte
  max_char_or_byte2 As Byte
  min_byte1 As Byte
  max_byte1 As Byte
  all_chars_exist As Boolean
  default_char As Byte
  n_properties As Byte
  properties As Pointer
  min_bounds As Pointer
  max_bounds As Pointer
  per_char As Pointer
  ascent As Integer
  descent As Integer
End Struct


Private Const ExposureMask As Integer = 32768
Private Const KeyPressMask As Byte = 1
Private Const ButtonPressMask As Byte = 4

Private Enum KeyPress = 2, KeyRelease, ButtonPress, ButtonRelease, MotionNotify, EnterNotify, LeaveNotify, FocusIn, FocusOut, KeymapNotify, Expose, GraphicsExpose, NoExpose
Private Enum FillSolid = 0, FillTiled, FillStippled, FillOpaqueStippled   ' fillStyle

Private disp As Pointer
Private cswId As Integer
Private gc As Pointer


Library "libX11:6.3.0"

' Display *XOpenDisplay(disp)
' Opens a connection to the X server that controls a display.
Private Extern XOpenDisplay(display$ As String) As Pointer

' XCloseDisplay(display)
' Closes the connection to the X server for the display specified in the Display structure and destroys all windows.
Private Extern XCloseDisplay(displayP As Pointer)

' int XDefaultScreen (display)
' returns the default screen number referenced by the XOpenDisplay function.
Private Extern XDefaultScreen(displayP As Pointer) As Integer

' unsigned long XWhitePixel (display, screen_number)
' returns the white pixel value for the specified screen.
Private Extern XWhitePixel(displayP As Pointer, screen_number As Integer) As Long

' unsigned long XBlackPixel (display, screen_number)
' returns the black pixel value for the specified screen.
Private Extern XBlackPixel(displayP As Pointer, screen_number As Integer) As Long

' Window XDefaultRootWindow(display)
' Return the root window for the default screen.
Private Extern XDefaultRootWindow(displayP As Pointer) As Integer

' Window XCreateSimpleWindow(display, parent, x, y, width, height, border_width, border, background)
' creates an unmapped InputOutput subwindow for a specified parent window, returns the window ID of the created window.
Private Extern XCreateSimpleWindow(displayP As Pointer, parent As Integer, x As Integer, y As Integer, width As Integer, height As Integer, border_width As Integer, border As Integer, background As Integer) As Integer 

' XSetStandardProperties (display, w, window_name, icon_name, icon_pixmap, argv, argc, hints)
' specifies a minimum set of properties describing the simplest application.
Private Extern XSetStandardProperties(displayP As Pointer, w As Integer, window_name As String, icon_name As String, icon_pixmap As Integer, argv As String, argc As Integer, hints As Pointer)

' XSelectInput (display, w, event_mask)
' requests that the X server report the events associated with the specified Event mask.
Private Extern XSelectInput(displayP As Pointer, w As Integer, event_mask As Long)

' GC XCreateGC(display, d, valuemask, values)
' creates a graphics context and returns a GC.
Private Extern XCreateGC(displayP As Pointer, w As Integer, valuemask As Long, values As Pointer) As Pointer

' XSetForeground (display, gc, foreground)
' sets the foreground.
Private Extern XSetForeground(displayP As Pointer, gc As Pointer, foreground As Integer)

' char * * XListFonts(display, pattern, maxnames, actual_count_return)
' returns an array of available font names.
Private Extern XListFonts(displayP As Pointer, pattern As String, maxnames As Integer, actual_count_return As Pointer) As Pointer

' XFontStruct * XLoadQueryFont(display, name)
' opens(loads)the specified font.
Private Extern XLoadQueryFont(displayP As Pointer, nameFont As String) As XFontStruct

' XSetFont(display, gc, font)
' Assigns a Font to a Graphics Context.
Private Extern XSetFont(displayP As Pointer, gcP As Pointer, fontP As Pointer)

' XSetFillStyle(display, gc, fill_style)
' changes the fill style of GC.
Private Extern XSetFillStyle(displayP As Pointer, gc As Pointer, fill_style As Integer)

' XClearWindow(display, w)
' clears the entire area in the specified window.
Private Extern XClearWindow(displayP As Pointer, w As Integer)

' XMapRaised (display, w)
' raises the specified window to the top of the stack.
Private Extern XMapRaised(displayP As Pointer, w As Integer)

' Cursor XCreateFontCursor(display, shape)
' Provides a set of standard cursor shapes in a special font named cursor.
Private Extern XCreateFontCursor(displayP As Pointer, shape As Integer) As Integer

' XDefineCursor(display, w, cursor)
' If a cursor is set, it will be used when the pointer is in the window.
Private Extern XDefineCursor(displayP As Pointer, w As Integer, cursorI As Integer) As Integer

' XNextEvent (display, event_return)
' gets the next event and remove it from the queue
Private Extern XNextEvent(displayP As Pointer, event_return As XEventStruct)

' int XLookupString(event_struct, buffer_return, bytes_buffer, keysym_return, status_in_out)
' translates a key event to a KeySym and a string.
Private Extern XLookupString(event_struct As XEventStruct, buffer_return As Byte[], bytes_buffer As Integer, keysym_return As Pointer, status_in_out As Pointer) As Integer

' XDrawPoint(display, d, gc, x, y)
' draws a single point into the specified drawable
Private Extern XDrawPoint(displayP As Pointer, w As Integer, gcP As Pointer, x1 As Integer, y1 As Integer)

' XDrawLine(display, d, gc, x1, y1, x2, y2)
' draws a line between the specified set of points (x1, y1) and (x2, y2).
Private Extern XDrawLine(displayP As Pointer, w As Integer, gcP As Pointer, x1 As Integer, y1 As Integer, x2 As Integer, y2 As Integer)

' XDrawRectangle(display, d, gc, x, y, width, height)
' draws the outlines of the specified rectangle.
Private Extern XDrawRectangle(displayP As Pointer, w As Integer, gcP As Pointer, xI As Integer, yI As Integer, widthI As Integer, heightI As Integer)

' XFillRectangle(display, d, gc, x, y, width, height)
' fills the specified rectangle
Private Extern XFillRectangle(displayP As Pointer, w As Integer, gcP As Pointer, xI As Integer, yI As Integer, widthI As Integer, heightI As Integer)

' XDrawArc(display, d, gc, x, y, width, height, angle1, angle2)
' draws an arc.
Private Extern XDrawArc(displayP As Pointer, w As Integer, gcP As Pointer, xI As Integer, yI As Integer, widthI As Integer, heightI As Integer, angle1 As Integer, angle2 As Integer)

' XFillArc(display, d, gc, x, y, width, height, angle1, angle2)
' fills the specified arc.
Private Extern XFillArc(displayP As Pointer, w As Integer, gcP As Pointer, xI As Integer, yI As Integer, widthI As Integer, heightI As Integer, angle1 As Integer, angle2 As Integer)

' XDrawString(display, d, gc, x, y, string, length)
' draws a text.
Private Extern XDrawString(displayP As Pointer, w As Integer, gcP As Pointer, x As Integer, y As Integer, test$ As String, length As Integer)

' XFreeGC(display, gc)
' destroys the specified GC as well as all the associated storage.
Private Extern XFreeGC(displayP As Pointer, gcP As Pointer)

' XDestroyWindow(display, w)
' destroys the specified window as well as all of its subwindows
Private Extern XDestroyWindow(displayP As Pointer, w As Integer)


' void exit(int status)
' Termina il programma. I buffer dei file vengono svuotati, i flussi sono chiusi.
Private Extern exitus(status As Integer) In "libc:6" Exec "exit"


Public Sub Main()

 Dim screen, key, cursor As Integer
 Dim pxW, pxB As Long
 Dim testo As New Byte[255]
 Dim ev As New XEventStruct
 Dim xfon As New XFontStruct
 Dim scriptum As String = "testo qualsiasi"


' Apre la connessione con il server display del sistema grafico X:
   disp = XOpenDisplay(Null)
   If IsNull(disp) Then Error.Raise("Impossibile aprire il server display !")

   screen = XDefaultScreen(disp)

   pxW = XWhitePixel(disp, screen)
    
   pxB = XBlackPixel(disp, screen)
    
' Crea la finestra secondo i parametri previsti dalla funzione.
' L'ultimo parametro imposta il colore di fondo della finestra:
   cswId = XCreateSimpleWindow(disp, XDefaultRootWindow(disp), 0, 0, 300, 200, 5, pxW, &FF0000)
   Print "ID della finestra creata: "; Hex(cswId, 6)
   
   XSetStandardProperties(disp, cswId, "Prova creazione finestra", "Nome icona finestra", 0, Null, 0, Null)
   
' Dice al server display qauli eventi deve vedere:
   XSelectInput(disp, cswId, ExposureMask Or KeyPressMask Or ButtonPressMask)
   
' Crea un nuovo contesto grafico:
   gc = XCreateGC(disp, cswId, 0, Null)
   If IsNull(gc) Then Error.Raise("Impossibile creare un nuovo contesto grafico !")

' Imposta il colore degli elementi grafici all'interno della finestra:
   XSetForeground(disp, gc, &00FF00)

   elencoFont()

' Imposta il font per i caratteri del testo grafico:
   xfon = XLoadQueryFont(disp, "*bitstream*")
   If IsNull(xFon) Then Error.Raise("Impossibile caricare il font !")
 
   XSetFont(disp, gc, xfon.fid)

   XSetFillStyle(disp, gc, FillSolid)
   
   redraw()
   
   XMapRaised(disp, cswId)

' Entrando il cursore del mouse nella finestra, esso cambia aspetto, impostando quello
' che nel file header "x11/cursorfont.h" ha il valore 10 tra quelli visibili nella pagina "http://tronche.com/gui/x/xlib/appendix/b/":
   cursor = XCreateFontCursor(disp, 10)

   XDefineCursor(disp, cswId, cursor)


   While True

     XNextEvent(disp, ev)

     Select Case ev.type
         Case Expose
' La finestra mostrata deve essere ripulita:
           redraw()
' Disegna un punto all'interno del quadrato:
           XDrawPoint(disp, cswId, gc, 70, 120)
' Disegna una linea:
           XDrawLine(disp, cswId, gc, 10, 10, 40, 60)
' In questo caso disegna un quadrato:
           XDrawRectangle(disp, cswId, gc, 50, 100, 40, 40)
' Disegna un rettangolo colorato di bianco:
           XFillRectangle(disp, cswId, gc, 200, 30, 60, 40)
' Disegna un arco:
           XDrawArc(disp, cswId, gc, 100, 150, 60, 40, 0, 360 * 20)
' Disegna un arco riempito di colore bianco:
           XFillArc(disp, cswId, gc, 40, 20, 60, 40, 0, 360 * 20)
' Disegna un cerchio:
           XDrawArc(disp, cswId, gc, 200, 100, 50, 50, 0, 360 * 64)
' Disegna un cerchio riempito di colore bianco:
           XFillArc(disp, cswId, gc, 110, 40, 50, 50, 0, 360 * 64)
' Disegna una stringa di caratteri:
           XDrawString(disp, cswId, gc, 20, 170, scriptum, Len(scriptum))

         Case KeyPress
           XLookupString(ev, testo, 255, VarPtr(key), Null)
           If testo[0] = Asc("q") Then
             chiude_X()
             Print "E' stato premuto il tasto: "; Chr(testo[0]), key
             Else
' Disegna il carattere del tasto premuto alle coordinate del puntatore del mouse:
               XDrawString(disp, cswId, gc, ev.x, ev.y, Chr(key), 1)
           Endif

         Case ButtonPress     ' Indica le coordinate ove è stato premuto il tasto del mouse
           With ev
             Print "E' stato premuto il tasto del mouse alle seguenti coordinate:\n"; .x; " pixel dal margine sinistro della finestra;"
             Print .y; " pixel dal margine superiore della finestra;"
             Print .x_root; " pixel dal margine sinistro dello schermo;"
             Print .y_root; " pixel dal margine superiore dello schermo." 
           End With
           redraw()
       End Select

   Wend
   
End


Private Procedure elencoFont()

 Dim po As Pointer
 Dim num_fonts As Integer
 Dim st As Stream
 Dim j As Short
 Dim b As Byte
  
 
  po = XListFonts(disp, "*itstr*", 8196, VarPtr(num_fonts))
  If IsNull(po) Then Error.Raise("Impossibile caricare i font !")

  po = Pointer@(po)

' Dereferenziamo il "puntatore" mediante i "Memory Stream":
  st = Memory po For Read
 
  For j = 0 To 8196
    Seek #st, j
    Read #st, b
    If b = 0 Then
      Print
    Else
      Print Chr(b);
    Endif
  Next

  st.Close
  Free(po)

End

 
Private Procedure redraw()
 
' Pulisce la superficie della finestra da ogni elemento presente:
 XClearWindow(disp, cswId)
 
End


Public Sub chiude_X()

   XFreeGC(disp, gc)

' Chiude la finestra:
   XDestroyWindow(disp, cswId)

   XCloseDisplay(disp)

   exitus(0)

End


Riferimenti