Running X11 Applications on macOS

Running X11 Applications on macOS

X11R6 Basics

Hello World Basic Programming Knowledge about X11

If you want to run for example 2D vector application like InkScape (https://inkscape.org) on your Mac you need to install X11.

How to install X11R6 (and InkScape) on your Mac

  1. Download XQuarz here: http://xquartz.macosforge.org
  2. Install it
  3. Logout and login again to make X11 active
  4. Put InkSapce App in Applications folder
  5. If asked for permission "from a unsigned developer" to go /Applications folder, right click, choose "open"

(Read more on that here: https://inkscape.org/en/download/mac-os/)

 

 

Where is X11R6?

/usr/X11R6/

/usr/X11R6/lib/

/usr/X11R6/include/X11/

 

Sample X11 program

/*
  * Simple Xlib application drawing a box in a window.
  * gcc input.c -o output -lX11
  */
 
/* /1/ */
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(void)
{
    Display *display;
    Window window;
    XEvent event;
    char *msg = "Hello, World!";
    int s;

    /* /2/ some basic X11 setup */
    /* open connection with the server */
    display = XOpenDisplay(NULL);
    if (display == NULL)
    {
        fprintf(stderr, "Cannot open display\n");
        exit(1);
    }
 
    s = DefaultScreen(display);
 
    /* create window */
    window = XCreateSimpleWindow(display, RootWindow(display, s), 10, 10, 200, 200, 1,
                           BlackPixel(display, s), WhitePixel(display, s));
 
    /* select kind of events we are interested in */
    XSelectInput(display, window, ExposureMask | KeyPressMask);
 
    /* map (show) the window */
    XMapWindow(display, window);
 
    /* /3/ event loop */
    for (;;)
    {
        XNextEvent(display, &event);
 
        /* /4/ draw or redraw the window */
        if (event.type == Expose)
        {
            XFillRectangle(display, window, DefaultGC(display, s), 20, 20, 10, 10);
            XDrawString(display, window, DefaultGC(display, s), 50, 50, msg, strlen(msg));
        }
        /* /5/ exit on key press */
        if (event.type == KeyPress)
            break;
    }
 
    /* /6/ close connection to server */
    XCloseDisplay(display);
 
    return 0;
 }

 

/1/ We use X11/Xlib.h basic X11 lib here. #include <X11/Xlib.h>

/2/ Some basic X11 setup, create a X11 window, etc.

/3/ As you can can see, everything interactive is within a so called event loop. It loops forever until something happens: An event.

/4/ Check for event

/5/ Event for exit (break) the event loop, which terminates the event loop, and ...

/6/ ... finally closes the created X window

 

Compile

gcc main.c 
main.c:6:10: fatal error: 'X11/Xlib.h' file not found
#include <X11/Xlib.h>
         ^
1 error generated.

 

 

Where is Xlib.h?

$ find /usr/ -name "*Xlib.h"
/usr/X11R6/include/X11/Xlib.h

-> So add /usr/X11R6/include/ to your include path (-I):

-I/usr/X11R6/include/

 

List undefined (-u) symbols:

$ nm   main.o
 U _XCloseDisplay
 U _XCreateSimpleWindow
 U _XDrawString
 U _XFillRectangle
 U _XMapWindow
 U _XNextEvent
 U _XOpenDisplay
 U _XSelectInput
 U ___stderrp
 U _exit
 U _fprintf
 0000000000000000 T _main
 U _strlen

 

These Xnnnn functions like XCloseDisplay are X11 functions pointing to X11R6 libs because they are implemented there within the X11 libs.

Linking

X11 libs are in /usr/X11R6/lib so add -L Library search path to it (/usr/X11R6/lib) and the library itself (X11) like so:

$ gcc -L/usr/X11R6/lib -lX11 -I/usr/X11R6/include/ main.c
$

 

Makefile

A Makefile could look like this:

## -- just for compiling, C needs the path to the .h files
X11_INC_PATH  = -I/usr/X11R6/include/

## -- library
X11_LIBS_PATH = -L/usr/X11R6/lib/
X11_LIBS      = -lX11


default:    main

main:   main.c
    gcc -Wall $(X11_INC_PATH) $(X11_LIBS_PATH) $(X11_LIBS)  main.c -o main


#clean:
#    rm -r main.o main

 

$ make

$

 

Which shared libraries are used / linked to my executable? (otool, ldd)

An a Mac, otool is what ldd is on Linux.

$ otool -L ./main
 ./main:
 /opt/X11/lib/libX11.6.dylib (compatibility version 10.0.0, current version 10.0.0)
 /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1225.1.1)
$

 

 

Run it!

$ ./main

I replaced KeyPress to KeyRelease to that I can take a screenshot.

if (event.type == KeyRelease)

More on that, see http://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html

 

Ported CPC 464 for X11 on OS X: