Task

Create a simple X11 application,   using an X11 protocol library such as Xlib or XCB,   that draws a box and   "Hello World"   in a window.

Implementations of this task should   avoid using a toolkit   as much as possible.




import x11/[xlib,xutil,x]
 
const
  windowWidth = 1000
  windowHeight = 600
  borderWidth = 5
  eventMask = ButtonPressMask or KeyPressMask or ExposureMask
 
var
  display: PDisplay
  window: Window
  deleteMessage: Atom
  graphicsContext: GC
 
proc init() =
  display = XOpenDisplay(nil)
  if display == nil:
    quit "Failed to open display"
 
  let
    screen = XDefaultScreen(display)
    rootWindow = XRootWindow(display, screen)
    foregroundColor = XBlackPixel(display, screen)
    backgroundColor = XWhitePixel(display, screen)
 
  window = XCreateSimpleWindow(display, rootWindow, -1, -1, windowWidth,
      windowHeight, borderWidth, foregroundColor, backgroundColor)
 
  discard XSetStandardProperties(display, window, "X11 Example", "window", 0,
      nil, 0, nil)
 
  discard XSelectInput(display, window, eventMask)
  discard XMapWindow(display, window)
 
  deleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", false.XBool)
  discard XSetWMProtocols(display, window, deleteMessage.addr, 1)
 
  graphicsContext = XDefaultGC(display, screen)
 
 
proc drawWindow() =
  const text = "Hello, Nim programmers."
  discard XDrawString(display, window, graphicsContext, 10, 50, text, text.len)
  discard XFillRectangle(display, window, graphicsContext, 20, 20, 10, 10)
 
 
proc mainLoop() =
  ## Process events until the quit event is received
  var event: XEvent
  while true:
    discard XNextEvent(display, event.addr)
    case event.theType
    of Expose:
      drawWindow()
    of ClientMessage:
      if cast[Atom](event.xclient.data.l[0]) == deleteMessage:
        break
    of KeyPress:
      let key = XLookupKeysym(cast[PXKeyEvent](event.addr), 0)
      if key != 0:
        echo "Key ", key, " pressed"
    of ButtonPressMask:
      echo "Mouse button ", event.xbutton.button, " pressed at ",
          event.xbutton.x, ",", event.xbutton.y
    else:
      discard
 
 
proc main() =
  init()
  mainLoop()
  discard XDestroyWindow(display, window)
  discard XCloseDisplay(display)
 
 
main()