Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Raku NativeCall to LibX11 screen and display

Fedora 33 Raku

I am trying to use Raku's NativeCall to talk to libX11.so to print out both my screen and my display:

use NativeCall;

class Display is repr('CStruct') { has Pointer $.DisplayPtr };

# libX11.so --> X11
sub XOpenDisplay(Str $name = ':0') returns Display is native('X11') { * }
sub XDefaultScreen(Display $) returns int32 is native('X11') { * }

my Display $display = XOpenDisplay()
    or die "Can not open display";
 
my int $screen = XDefaultScreen($display);

print "display = <" ~ $display ~ ">\n";
print "screen =  <" ~ $screen  ~ ">\n";


$ libX11.pl6
display = <Display<90201160>>
screen =  <0>

Problem. I am missing something about the class syntax as it is showing me a pointer address instead of my display, which I presume to be ":0". Also I thing the class declaration should show a string somewhere.

like image 217
Todd Avatar asked Dec 13 '22 07:12

Todd


2 Answers

You're confusing somewhat a Display, which is an object that you use to interact with X, and a display name, which is a string that you can use to identify and connect to a Display.

Also, you're best off using repr('CPointer'), not repr('CStruct') for an XDisplay *, since the Xlib documentation says that it should be treated as an opaque pointer and everything accessed through functions, and translating the whole struct to Raku would be laborious (and not very useful).

Since it is like an object in that way, you have the option of encapsulating all of the Xlib functions inside of the Display class, and wrapping them in methods, as shown in the pointers section of the NativeCall docs. My translation of the code you have so far to this style would be:

use NativeCall;

class Display is repr('CPointer') {
  sub XOpenDisplay(Str) returns Display is native('X11') { * }
  method new(Str $name = ':0') {
    XOpenDisplay($name);
  }

  # You can wrap a libX11 function in a method explicitly, like this...
  sub XDisplayString(Display) returns Str is native('X11') { * }
  method DisplayString {
    XDisplayString(self);
  }

  # Or implicitly, by putting 'is native' on a method declaration 
  # and using 'is symbol' to match the names
  # (self will be passed as the first argument to the libX11 function)
  method DefaultScreen() returns int32 is native('X11') 
    is symbol('XDefaultScreen') { * }

  method Str {
    "Display({ self.DisplayString })";
  }
}

my Display $display .= new
    or die "Can not open display";

my int $screen = $display.DefaultScreen;

print "display = <" ~ $display ~ ">\n";
print "screen =  <" ~ $screen  ~ ">\n";

I provided a method Str for Display, so that it can be printed directly, but again, don't confuse the object with the string that you use to get hold of one. You would go on from here by adding more methods to Display, as well as defining Screen, Window, etc. in the same way. You don't have to do it this way -- you're free to define the subs publicly and use calls to XOpenDisplay and everything else, as if you were writing C, but the OO style tends to be a bit cleaner. The choice is yours.

like image 187
hobbs Avatar answered Jan 20 '23 14:01

hobbs


In the comments @hobbs has pointed me in the right direction, by suggesting a new function, XDisplayString, that can actually be used to turn a pointer into a string describing the display, without actually needing to go into the full structure of the pointer. So this is how it would go:

use NativeCall;

class Display is repr('CPointer') {};

# libX11.so --> X11
sub XOpenDisplay(str $name = ':0') returns Display is native('X11') { * }
sub XDefaultScreen(Str $) returns int32 is native('X11') { * }
sub XDisplayString(Display $display) returns Str is native('X11') { * }

my $display = XOpenDisplay() or die "Can not open display";
my Str $displayStr = XDisplayString($display);
my int $screen = XDefaultScreen( $displayStr );

print "display = <" ~ $displayStr ~ ">\n";
print "screen =  <" ~ $screen  ~ ">\n";

That would return:

display = <:0>
screen =  <64>

At least in my machine. The key here is that you're actually ising the right way of describing the screen, at least as far as XDisplayString is concerned, so you turn the original Pointer into a Str, and then you sna use it in whatever X* need a string description of the display.

like image 32
jjmerelo Avatar answered Jan 20 '23 12:01

jjmerelo