Mostrare un'immagine nella finestra di Gedit con funzioni del API di X11 e Imlib2

Da Gambas-it.org - Wikipedia.

Mediante le risorse del API di X11 e di Imlib2, è possibile utilizzare la mera finestra dell'editor di testo Gedit, per mostrare semplicemente un'immagine.

Va precisato che l'immagine non apparirà sul documento di testo di Gedit; pertanto, dopo aver lanciato il programma Gedit, è necessario chiudere il documento di testo, lasciando così la nuda finestra grigia di Gedit.

In via generale, è possibile far mostrare una immagine sulla nuda finestra di ogni altro programma. Gedit, però, si dispone meglio di altri programmi a mostrare e a conservare l'immagine.

Per poter fruire di tali risorse, è necessario richiamare in Gambas le librerie dinamiche e condivise:

  • libX11.so.6.4.0
  • libImlib2.so.1.7.4

Il programma Gedit va lanciato preliminarmente all'avvio della nostra applicazione Gambas, il codice della quale sarà il seguente:

Library "libX11:6.4.0"

Public Struct Visual
  XExtData As Pointer
  visualid As Integer
  classe As Long
  red_mask As Long
  green_mask As Long
  blue_mask As Long
  map_entries As Integer
End Struct

Private Const ZPixmap As Integer = 2
Private Const MAX_PROPERTY_VALUE_LEN As Integer = 4096
Private Const XA_CARDINAL As Integer = 6
Private Const XA_WINDOW As Integer = 33

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

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

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

' Atom XInternAtom(Display *display, char *atom_name, Bool only_if_exists)
' Returns the atom identifier associated with the specified atom_name string.
Private Extern XInternAtom(display As Pointer, atom_name As String, only_if_exists As Boolean) As Integer

' int XGetWindowProperty(Display *display, Window w, Atom property, long long_offset, long long_length, Bool delete, Atom req_type, Atom *actual_type_return, int *actual_format_return, unsigned long *nitems_return, unsigned long *bytes_after_return, unsigned char **prop_return)
' Returns the actual type of the property; the actual format of the property.
Private Extern XGetWindowProperty(display As Pointer, w As Long, py As Integer, lo As Long, ll As Long, d As Boolean, rt As Integer, at As Pointer, af As Pointer, ni As Pointer, ba As Pointer, pr As Pointer) As Integer

' Status XGetWMName(Display *display, Window w, XTextProperty *text_prop_return)
' Calls XGetTextProperty() to obtain the WM_NAME property.
Private Extern XGetWMName(display As Pointer, w As Long, text_prop_return As Pointer) As Integer

' GC XCreateGC(Display *display, Drawable d, unsigned long valuemask, XGCValues *values)
' Creates a graphics context and returns a GC.
Private Extern XCreateGC(display As Pointer, w As Long, valuemask As Long, values As Pointer) As Pointer

' XClearWindow(Display *display, Window w)
' Clears the entire area in the specified window.
Private Extern XClearWindow(display As Pointer, w As Long)

' XPutImage(Display *display, Drawable d, GC gc, XImage *image, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height)
' Combines an image with a rectangle of the specified drawable.
Private Extern XPutImage(display As Pointer, w As Long, gcP As Pointer, image As Pointer, src_x As Integer, src_y As Integer, dest_x As Integer, dest_y As Integer, width As Integer, height As Integer)

' int XDefaultDepth(Display *display, int screen_number)
' Returns the depth (number of planes) of the default root window for the specified screen.
Private Extern XDefaultDepth(display As Pointer, screen_number As Integer) As Integer

' XImage *XCreateImage(Display *display, Visual *visual, unsigned int depth, int format, int offset, char *data, unsigned int width, unsigned int height, int bitmap_pad, int bytes_per_line)
' Allocates the memory needed for an XImage structure for the specified display but does not allocate space for the image itself.
Private Extern XCreateImage(display As Pointer, visu As Visual, depth As Integer, formatI As Integer, offset As Integer, data As Pointer, width As Integer, height As Integer, bitmap_pad As Integer, bytes_per_line As Integer) As Pointer

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

' Status XInitImage(XImage *image)
' Initializes the internal image manipulation routines of an image structure, based on the values of the various structure members.
Private Extern XInitImage(image As Pointer)

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


Library "libImlib2:1.7.4"

' Imlib_Image imlib_load_image_immediately(const char *file)
' Loads an image from disk located at the path specified by file.
Private Extern imlib_load_image_immediately(filename As String) As Pointer

' void imlib_context_set_image(Imlib_Image image)
' Sets the current image Imlib2 will be using with its function calls.
Private Extern imlib_context_set_image(Imlib_Image As Pointer)

' DATA32* imlib_image_get_data(void)
' Returns a pointer to the image data in the image set as the image for the current context.
' The image data is returned in the format of a DATA32 (32 bits) per pixel in a linear array ordered
' from the top left of the image to the bottom right going from left to right each line.
Private Extern imlib_image_get_data() As Pointer

' int imlib_image_get_width(void)
' Returns the width in pixels of the current image in Imlib2's context.
Private Extern imlib_image_get_width() As Integer

' int imlib_image_get_height(void)
' Returns the height in pixels of the current image in Imlib2's context.
Private Extern imlib_image_get_height() As Integer


Public Sub Main()

 Dim screen, prof, w, h As Integer
 Dim id As Long
 Dim disp, gc, img, imago, dati As Pointer
 
 disp = XOpenDisplay(0)
 If disp == 0 Then Error.Raise("Impossibile aprire il display !")
  
 screen = XDefaultScreen(disp)
 prof = XDefaultDepth(disp, screen)
  
 dati = imlib_load_image_immediately("/percorso/del/file/immagine")
 If dati == 0 Then Error.Raise("Errore !")
  
 imlib_context_set_image(dati)
 
 w = imlib_image_get_width()
 h = imlib_image_get_height()
  
 imago = imlib_image_get_data()
 If imago == 0 Then Error.Raise("Errore !")
  
 img = XCreateImage(disp, Null, prof, ZPixmap, 0, imago, w, h, 32, 0)
 If img == 0 Then Error.Raise("Errore !")
  
' Individua l'ID della finestra del programma utilizzato per mostrare l'immagine.
' Inserire quindi il nome della finestra di 'Gedit':
 id = IdFinestra(disp, "gedit")
 
 gc = XCreateGC(disp, id, 0, 0)
 If gc == 0 Then Error.Raise("Impossibile creare un nuovo contesto grafico !")
  
 XClearWindow(disp, id)
  
 XInitImage(img)
   
 XPutImage(disp, id, gc, img, 0, 0, 0, 0, w, h)                    
  
' Va in chiusura:
 XFreeGC(disp, gc)
 XCloseDisplay(disp)
  
End


Private Function IdFinestra(dsp As Pointer, nome_finestra As String) As Long
 
 Dim datID, p As Pointer
 Dim x_num_Atom, tipo, formato As Integer
 Dim err, n_fin, bytes_succ, i As Integer
 Dim rootW As Long
 Dim stId As Stream
 Dim b As Byte
 
 rootW = XDefaultRootWindow(dsp)
  
 x_num_Atom = XInternAtom(dsp, "_NET_CLIENT_LIST", False)
   
 err = XGetWindowProperty(dsp, rootW, x_num_Atom, 0, MAX_PROPERTY_VALUE_LEN / 4, False, XA_WINDOW, VarPtr(tipo), VarPtr(formato), VarPtr(n_fin), VarPtr(bytes_succ), VarPtr(datID))
 If err <> 0 Then Error.Raise("Impossibile ottenere dati dalla funzione 'XGetWindowProperty' !")
   
 If XA_WINDOW <> tipo Then Error.Raise("Tipo invalido di proprietà '_NET_CLIENT_LIST' !")
  
 p = Alloc(SizeOf(gb.Byte), 32)
 stId = Memory datID For Read
   
 For b = 1 To n_fin * 2
   Read #stId, i
   If i > 0 Then
     XGetWMName(dsp, i, p)
     If String@(Pointer@(p)) = nome_finestra Then
       stId.Close
       Free(p)
       Return CLong(i)
     Endif
   Endif  
 Next
   
End