Daniel Taylor

== X11 NASM === Just a code snippet

The NASM code below creates a blank X11 window. No effort was made to make sure that the ‘X’ close button works properly.

Compile and link with:

nasm -f elf64 main.asm -o main.o
ld -melf_x86_64 -o main main.o -lX11 --dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc

The code:

global _start

extern XOpenDisplay
extern XNextEvent
extern XPending
extern XCreateSimpleWindow
extern XMapRaised
extern XSetStandardProperties
extern XCreateGC
extern XSetBackground
extern XSetForeground
extern XClearWindow

section .bss

dis: resq 1
screen: resd 1
win: resq 1
gc: resq 1
black_pixel: resq 1
root_window: resq 1

struc XDisplay
    .trash_1:        resb 224
    .default_screen: resd 1
    .nscreens:       resd 1
    .screens:        resd 1
endstruc

struc XScreen
    .trash_1:      resb 16
    .root:         resq 1
    .trash_2:      resb 64
    .white_pixel:  resq 1
    .black_pixel:  resq 1
    .trash_3:      resb 24
    .SIZE:         resb 0
endstruc


section .text

init_x:

    sub rsp, 8
    xor rdi, rdi
    call XOpenDisplay
    mov qword [dis], rax
    add rsp, 8

    mov rax, qword [dis]
    add rax, XDisplay.default_screen
    mov eax, dword [rax]
    mov dword [screen], eax

    ; black=BlackPixel(dis, screen)
    ; black = ((_XPrivDisplay)(dis))->screens[screen].black_pixel
    mov rax, qword [dis]
    mov rax, qword [rax + XDisplay.screens]
    mov edx, dword [screen]
    imul edx, XScreen.SIZE
    add rax, rdx
    mov rax, [rax + XScreen.black_pixel]
    mov qword [black_pixel], rax

    ; root_window = DefaultRootWindow(dis)
    ; root_window = ((_XPrivDisplay)(dis))->screens[screen].root
    mov rax, qword [dis]
    mov rax, qword [rax + XDisplay.screens]
    mov edx, dword [screen]
    imul edx, XScreen.SIZE
    add rax, rdx
    mov rax, qword [rax + XScreen.root]
    mov qword [root_window], rax

    ; Set up window and related 

    mov rax, [black_pixel]
    push rax
    push rax
    push qword 0 ; I guess supposed to be 0?
    mov rdi, [dis]
    mov rsi, [root_window]
    mov rdx, 0
    mov rcx, 0
    mov r8, 600
    mov r9, 300
    call XCreateSimpleWindow
    mov [win], rax
    pop rax
    pop rax
    pop rax

    ; Give the window a title
    sub rsp, 8
    push qword 0
    push qword 0
    mov rdi, [dis]
    mov rsi, [win]
    mov rdx, window_title
    mov rcx, icon_name
    mov r8, 0
    mov r9, 0
    call XSetStandardProperties
    pop rax
    pop rax
    add rsp, 8

    ; Set background and show window
    sub rsp, 8
    mov rdi, [dis]
    mov rsi, [win]
    mov rdx, 0
    call XCreateGC
    mov qword [gc], rax
    add rsp, 8

    sub rsp, 8
    mov rdi, [dis]
    mov rsi, [gc]
    mov rdx, [black_pixel]
    call XSetBackground
    add rsp, 8

    sub rsp, 8
    mov rdi, [dis]
    mov rsi, [gc]
    mov rdx, [black_pixel]
    call XSetForeground
    add rsp, 8

    sub rsp, 8
    mov rdi, [dis]
    mov rsi, [win]
    call XClearWindow
    add rsp, 8

    sub rsp, 8
    mov rdi, [dis]
    mov rsi, [win]
    call XMapRaised
    add rsp, 8

    ret

_start:
    ; _start has no return address, so no need to align stack before init_x call.
    
    call init_x

    ; event: rsp+0
    sub rsp, 0xc0

.main_loop:

    mov rdi, [dis]
    lea rsi, [rsp+0]
    call XNextEvent

    mov rdi, [dis]
    mov rsi, [win]
    call XClearWindow

    jmp .main_loop
    
    mov rax, 60
    syscall

section .data
    window_title: db "window title", 0
    icon_name: db "", 0 ; icon name? Not sure what this does. But it's part of XSetStandardProperties so...