proc start, .argc, .argv, .argp
.fontlist  dd ?
.fontcount dd ?
begin
        stdcall Xinitialize, strCaption, 10, 20, 400, 200

        ;;; Main Event Loop

.msg_pump:
        cinvoke XNextEvent, [hdisplay], event
        stdcall Xeventhandler
        jmp     .msg_pump

        stdcall Xshutdown

.do_exit:        ; Non-Local for XSetErrorHandler
        xor     eax, eax
        cinvoke exit, eax
        return
endp




proc Xshutdown
begin
        cinvoke XFreeGC, [hdisplay], [hGC]
        cinvoke XDestroyWindow, [hwin], [hdisplay]
        cinvoke XSetErrorHandler, [oError]

        xor     eax, eax
        return
endp


proc Xinitialize, .txt, .x, .y, .w, .h
  .hscreen rd 1
  .hroot   rd 1
begin
        cinvoke XOpenDisplay, 0
        or      eax, eax
        jnz     .display_ok

        cinvoke puts, strErrorDisplay
        jmp     start.do_exit

.display_ok:
        mov     [hdisplay], eax
        cinvoke XDefaultScreen, eax
        mov     [.hscreen], eax

        cinvoke XDefaultRootWindow, [hdisplay]
        mov     [.hroot], eax

        cinvoke XCreateSimpleWindow, [hdisplay], eax, [.x], [.y], [.w], [.h], 0, $000000, $d4d0c8
        or      eax, eax
        jnz     .create_ok

        cinvoke puts, strErrorCreation
        jmp     start.do_exit

.create_ok:
        mov     [hwin], eax
        cinvoke XCreateSimpleWindow, [hdisplay], eax, 10, 10, 64, 24, 0, 606060, $d4d0c8
        mov     [hwin2], eax

        cinvoke XSelectInput, [hdisplay], [hwin], KeyPressMask + KeyReleaseMask + ExposureMask
        cinvoke XSelectInput, [hdisplay], [hwin2], KeyPressMask + KeyReleaseMask + ExposureMask + EnterWindowMask + LeaveWindowMask
        cinvoke XStoreName, [hdisplay], [hwin], [.txt]
        cinvoke XStoreName, [hdisplay], [hwin2], cBtnCaption
        cinvoke XMapRaised, [hdisplay], [hwin]
        cinvoke XMapRaised, [hdisplay], [hwin2]
        or      eax, eax
        jnz     .show_ok

        cinvoke puts, strErrorShow
        jmp     start.do_exit

.show_ok:
        cinvoke XCreateGC, [hdisplay], [hwin], 0, 0
        mov     [hGC], eax

        cinvoke XSetForeground, [hdisplay], [hGC], $000000
        cinvoke XSetBackground, [hdisplay], [hGC], $ffffff

        xor     eax, eax
        return
endp



proc Xdrawscreen
begin
        cinvoke XDrawLine, [hdisplay], [hwin], [hGC], 0, 110, 400, 110
        cinvoke XDrawLine, [hdisplay], [hwin], [hGC], 0, 80, 400, 80
        cinvoke XDrawString, [hdisplay], [hwin], [hGC], 10, 100, strMessage, lenMessage
        return
endp


proc StrLength, .ptrString
begin
        push    esi

        xor     eax, eax

        mov     esi, [.ptrString]
        test    esi, esi
        jz      .exit

        cld
.loop:
        mov     cl, [esi]
        inc     esi
        test    cl, cl
        jz      .exit

        inc     eax
        jmp     .loop

.exit:
        pop     esi
        return
endp

proc DrawBtn, .hwin, .inside
.attr XWindowAttributes
.name dd ?
.font dd ?
.direction dd ?
.ascent    dd ?
.descent   dd ?
.overall   XCharStruct

.Gcontext dd ?
begin
        push    ebx ecx esi edi

        lea     ecx, [.attr]
        cinvoke XGetWindowAttributes, [hdisplay], [.hwin], ecx
        dec     [.attr.width]
        dec     [.attr.height]

        cinvoke XCreateGC, [hdisplay], [.hwin], 0, 0
        mov     ebx, eax

        cinvoke XGContextFromGC, ebx
        mov     [.Gcontext], eax

        cmp     [.inside], 0
        jne     .border_beveled

        cinvoke XSetForeground, [hdisplay], ebx, $606060
        cinvoke XDrawRectangle, [hdisplay], [.hwin], ebx, 0, 0, [.attr.width], [.attr.height]

        sub     [.attr.width], 2
        sub     [.attr.height], 2

        cinvoke XSetForeground, [hdisplay], ebx, $d4d0c8
        cinvoke XDrawRectangle, [hdisplay], [.hwin], ebx, 1, 1, [.attr.width], [.attr.height]
        inc     [.attr.width]
        inc     [.attr.height]
        jmp     .border_ok

.border_beveled:
        cinvoke XSetForeground, [hdisplay], ebx, $ffffff
        cinvoke XDrawLine, [hdisplay], [.hwin], ebx, 0, 0, [.attr.width], 0
        cinvoke XDrawLine, [hdisplay], [.hwin], ebx, 0, 0, 0, [.attr.height]

        cinvoke XSetForeground, [hdisplay], ebx, $404040
        cinvoke XDrawLine, [hdisplay], [.hwin], ebx, 0, [.attr.height], [.attr.width], [.attr.height]
        cinvoke XDrawLine, [hdisplay], [.hwin], ebx, [.attr.width], 0, [.attr.width], [.attr.height]

        dec     [.attr.width]
        dec     [.attr.height]

        cinvoke XSetForeground, [hdisplay], ebx, $808080
        cinvoke XDrawLine, [hdisplay], [.hwin], ebx, 1, [.attr.height], [.attr.width], [.attr.height]
        cinvoke XDrawLine, [hdisplay], [.hwin], ebx, [.attr.width], 1, [.attr.width], [.attr.height]

.border_ok:
        cinvoke XSetForeground, [hdisplay], ebx, $000000

        lea     ecx, [.name]
        cinvoke XFetchName, [hdisplay], [.hwin], ecx

        stdcall StrLength, [.name]
        mov     edi, eax
        lea     ecx, [.direction]
        lea     edx, [.ascent]
        lea     eax, [.descent]
        lea     esi, [.overall]

        cinvoke XQueryTextExtents, [hdisplay], [.Gcontext], [.name], edi, ecx, edx, eax, esi

        xor     eax, eax
        mov     ax, [.overall.ascent]
        add     ax, [.overall.descent]
        movsx   eax, ax
        sub     eax, [.attr.height]
        add     eax, 1
        neg     eax
        sar     eax, 1
        movsx   ecx, [.overall.ascent]
        lea     eax, [eax+ecx+1]  ; this is the baseline.
        mov     [.attr.y], eax

        mov     ax, [.overall.width]
        movsx   eax, ax
        sub     eax, [.attr.width]
        add     eax, 1
        neg     eax
        sar     eax, 1
        add     eax, 1
        cmp     eax, 1
        jge     @f
        mov     eax, 1
@@:
        mov     [.attr.x], eax

        stdcall StrLength, [.name]
        cinvoke XDrawString, [hdisplay], [.hwin], ebx, [.attr.x], [.attr.y], [.name], eax

        cinvoke XFree, [.name]
        cinvoke XFreeGC, [hdisplay], ebx

.finish:
        pop   edi esi ecx  ebx
        return
endp



proc Xeventhandler
begin
        mov     eax, [event]

        cmp     eax, Expose
        je      .on_expose

        cmp     eax, KeyPress
        je      .on_keypress

        cmp     eax, EnterNotify
        je      .on_enter

        cmp     eax, LeaveNotify
        je      .on_leave

        return

.on_leave:
        mov     eax, [event+XEnterWindowEvent.window]
        cmp     eax, [hwin2]
        je      .button_leave

        return

.button_leave:
        stdcall DrawBtn, [event+XEnterWindowEvent.window], 0
        return


.on_enter:
        mov     eax, [event+XEnterWindowEvent.window]
        cmp     eax, [hwin2]
        je      .button_enter
        return

.button_enter:
        stdcall DrawBtn, [event+XEnterWindowEvent.window], 1
        return

.on_expose:
        cmp     [event+XExposeEvent.count], 0
        je      @f

        return
@@:
        mov     eax, [event+XExposeEvent.window]

        cmp     eax, [hwin]
        je      .mainwin

        cmp     eax, [hwin2]
        je      .button

        return

.button:
        stdcall DrawBtn, [hwin2], 0
        return


.mainwin:
        stdcall Xdrawscreen
        return


.on_keypress:
        cinvoke XLookupKeysym, event, 0
        cmp     eax, 'q'
        je      .terminate

        return

.terminate:
; keypress exits the application
        jmp     start.do_exit
endp






iglobal
  strCaption db 'Xlib Fresh!', 0
  strMessage db "This is native assembly language Linux program."
  lenMessage = ($-strMessage)

  cBtnCaption db 'Button',0

  oError           dd 0
  strErrorDisplay  db 'XOpenDisplay: could not open connection to X server.', 0
  strErrorCreation db 'XCreateSimpleWindow: could not create window.', 0
  strErrorShow     db 'XMapRaised: could not display window.', 0

  cNewLine      db $0a, 0

  hGC             dd 0
  hwin            dd 0
  hwin2           dd 0
  hdisplay        dd 0
  event           rd 132
endg
