; _______________________________________________________________________________________
;| |
;| ..::FreshLib::.. Free, open source. Licensed under "Fresh artistic license." |
;|_______________________________________________________________________________________|
;
; Description: Main procedure of GUI application library.
;
; Target OS: Linux
;
; Dependencies:
;
; Notes: Organize the main message/event loop needed by every GUI engine.
;_________________________________________________________________________________________
uglobal
if used fGlobalTerminate
fGlobalTerminate dd ?
end if
endg
proc ProcessSystemEvents
.event XEvent
begin
push ebx ecx edx
.event_loop:
; check for quit
mov eax, [Application]
mov eax, [eax+TApplication.MainWindow]
test eax, eax
jz .continue ; ???????????
cmp dword [eax], 0
jne .continue
cinvoke XFlush, [hApplicationDisplay]
xor eax, eax
mov [fGlobalTerminate], 1
stc
pop edx ecx ebx
return
.continue:
cinvoke XPending, [hApplicationDisplay]
test eax, eax
jz .noevents
lea ebx, [.event]
cinvoke XNextEvent, [hApplicationDisplay], ebx
stdcall __ProcessOneSystemEvent, ebx
jmp .event_loop
.noevents:
clc
pop edx ecx ebx
return
endp
proc WaitForSystemEvent
.event XEvent
begin
push eax ecx edx
lea eax, [.event]
cinvoke XPeekEvent, [hApplicationDisplay], eax
pop edx ecx eax
return
endp
;proc EventsQueued, .pWin
;begin
; push eax ecx edx
; cinvoke XQLength, [hApplicationDisplay]
; test eax, eax
; clc
; jz @f
; stc
;@@:
; pop edx ecx eax
; return
;endp
proc __ProcessOneSystemEvent, .linux_event
.event rd 64
begin
push eax ebx ecx edx esi edi
mov ebx, [.linux_event]
stdcall _GetWindowStruct, [ebx+XEvent.window]
test eax, eax
jz .notprocessed
mov esi, eax
lea edi, [.event]
mov eax, [ebx+XEvent.type]
cmp eax, MotionNotify
je .mousemove
cmp eax, EnterNotify
je .mouseenter
cmp eax, LeaveNotify
je .mouseleave
cmp eax, ButtonPress
je .mouse_btn_press
cmp eax, ButtonRelease
je .mouse_btn_release
cmp eax, Expose
je .paint_window
cmp eax, ClientMessage ; event from the window manager - button close for example.
je .clientmessage
cmp eax, DestroyNotify
je .destroy
cmp eax, KeyPress
je .key_press
cmp eax, KeyRelease
je .key_release
cmp eax, MappingNotify
je .mapping_notify
cmp eax, FocusIn
je .focusin
cmp eax, FocusOut
je .focusout
cmp eax, ConfigureNotify
je .moveresize
.notprocessed:
pop edi esi edx ecx ebx eax
stc
return
.exec_event:
pushad
stdcall ExecEvent, esi, edi
popad
.finish:
pop edi esi edx ecx ebx eax
clc
return
;.........................................................................
; Resize events
.moveresize:
locals
.xevent XConfigureEvent
endl
lea eax, [.xevent]
cinvoke XCheckTypedWindowEvent, [hApplicationDisplay], [ebx+XConfigureEvent.window], ConfigureNotify, eax
test eax, eax
jz .process
lea eax, [.xevent]
cinvoke XPutBackEvent, [hApplicationDisplay], eax
mov eax, [.xevent.x]
cmp eax, [ebx+XConfigureEvent.x]
jne .finish
mov eax, [.xevent.y]
cmp eax, [ebx+XConfigureEvent.y]
jne .finish
mov eax, [.xevent.width]
cmp eax, [ebx+XConfigureEvent.width]
jne .finish
mov eax, [.xevent.height]
cmp eax, [ebx+XConfigureEvent.height]
jne .finish
.process:
mov [edi+TMoveResizeEvent.event], seMoveResize
mov eax, [ebx+XConfigureEvent.x]
mov ecx, [ebx+XConfigureEvent.y]
mov [edi+TMoveResizeEvent.newX], eax
mov [edi+TMoveResizeEvent.newY], ecx
cmp [ebx+XConfigureEvent.height], 100
jl @f
DebugMsg "NewX NewY"
OutputRegister regEAX, 10
OutputRegister regECX, 10
@@:
mov eax, [ebx+XConfigureEvent.width]
mov ecx, [ebx+XConfigureEvent.height]
mov [edi+TMoveResizeEvent.newWidth], eax
mov [edi+TMoveResizeEvent.newHeight], ecx
cmp [ebx+XConfigureEvent.height], 100
jl @f
DebugMsg "NewW NewH"
OutputRegister regEAX, 10
OutputRegister regECX, 10
@@:
jmp .exec_event
;.........................................................................
; Focus events
.focusout:
mov [edi+TFocusOutEvent.event], seFocusOut
jmp .setIC
.focusin:
mov [edi+TFocusInEvent.event], seFocusIn
.setIC:
cinvoke XSetICValues, [hInputContext], XNFocusWindow, [esi+TWindow.handle], 0
jmp .exec_event
;.........................................................................
; DestroyNotify handler it invalidates the handle in TWindow structure and then destroys TWindow.
.destroy:
mov [esi+TWindow.handle], 0
stdcall Destroy, esi
jmp .finish
;.........................................................................
; Mouse event handlers
.mouseleave:
mov [edi+TMouseEnterEvent.event], seMouseLeave
jmp .exec_event
.mouseenter:
mov [edi+TMouseEnterEvent.event], seMouseEnter
jmp .exec_event
.mousemove:
mov [edi+TMouseMoveEvent.event], seMouseMove
mov eax, [ebx+XMotionEvent.x]
mov ecx, [ebx+XMotionEvent.y]
mov [edi+TMouseMoveEvent.x], eax
mov [edi+TMouseMoveEvent.y], ecx
jmp .exec_event
.mouse_btn_press:
.mouse_btn_release:
mov eax, [ebx+XButtonEvent.type]
mov [edi+TMouseButtonEvent.event], eax ; seMouseBtnPress=ButtonPress and seMouseBtnRelease = ButtonRelease
mov eax, [ebx+XButtonEvent.button]
dec eax
cmp [edi+TScrollEvent.event], seMouseBtnRelease
je @f
cmp eax, 3
jge .wheelscroll
@@:
mov [edi+TMouseButtonEvent.Button], eax
mov eax, [ebx+XButtonEvent.state]
mov [edi+TMouseButtonEvent.kbdStatus], eax
mov eax, [ebx+XButtonEvent.x]
mov ecx, [ebx+XButtonEvent.y]
mov [edi+TMouseButtonEvent.x], eax
mov [edi+TMouseButtonEvent.y], ecx
jmp .exec_event
.wheelscroll:
mov ecx, scWheelUp
je @f
mov ecx, scWheelDn
@@:
mov [edi+TScrollEvent.event], seScroll
mov [edi+TScrollEvent.ScrollBar], scrollY
mov [edi+TScrollEvent.ScrollCmd], ecx
mov [edi+TScrollEvent.Value], 1
jmp .exec_event
;.........................................................................
; Window paint event
.paint_window:
; cmp [ebx+XExposeEvent.count], 0
; jne .finish
lea eax, [ebx+XExposeEvent.x]
stdcall __PaintWindow, esi, eax
jmp .finish
;.........................................................................
; Keyboard events.
locals
.utf8buff rb 16
endl
.key_press:
mov ecx, seKbdKeyPress
mov [edi+TKeyboardEvent.event], ecx
mov ecx, [ebx+XKeyEvent.state]
mov [edi+TKeyboardEvent.kbdStatus], ecx
mov dword [.utf8buff], 0
lea eax, [.utf8buff]
cinvoke Xutf8LookupString, [hInputContext], ebx, eax, 16, 0, 0
; here, .utg8buff contains the utf-8 string with the character typed on the keyboard.
mov eax, dword [.utf8buff]
mov [edi+TKeyboardEvent.key], eax
.scancode:
mov eax, [ebx+XKeyEvent.keycode]
cinvoke XKeycodeToKeysym, [hApplicationDisplay], eax, 0
mov [edi+TKeyboardEvent.scancode], eax
jmp .exec_event
.key_release:
mov ecx, seKbdKeyRelease
mov eax, [ebx+XKeyEvent.state]
mov [edi+TKeyboardEvent.event], ecx
mov [edi+TKeyboardEvent.kbdStatus], eax
mov [edi+TKeyboardEvent.key], 0
jmp .scancode
; refreshes keyboard mapping information, stored locally in XLib.
.mapping_notify:
cinvoke XRefreshKeyboardMapping, ebx
jmp .finish
;.........................................................................
; This event is sent from the window manager, when the user click on the close button of the
; window or close it some other way. So, the window have to decide whether to close or not.
.clientmessage:
mov eax, dword [ebx+XClientMessageEvent.data]
cmp eax, [atomWMDelete]
jne .finish
; The window is closed by click on close button or by pressing Alt+F4 or by other WM method
.close_from_wm:
mov [edi+TCloseEvent.event], seCloseRequest
mov [edi+TCloseEvent.reason], cerFromUser
jmp .exec_event
endp
proc __PaintWindow, .pWindow, .ptrBounds
.event TPaintEvent
.caret dd ?
begin
push eax ebx ecx edx esi edi
lea edi, [.event]
mov esi, [.pWindow]
if defined Caret
mov [.caret], -1
cmp esi, [Caret.pWindow]
jne @f
stdcall CaretShow, FALSE
mov [.caret], eax
@@:
end if
mov [edi+TPaintEvent.event], sePaint
stdcall AllocateContext, [esi+TWindow.handle]
mov ebx, eax
mov [edi+TPaintEvent.context], eax
xor eax, eax
mov [edi+TPaintEvent.rect.left], eax
mov [edi+TPaintEvent.rect.top], eax
mov eax, $7fffffff
mov [edi+TPaintEvent.rect.right], eax
mov [edi+TPaintEvent.rect.bottom], eax
mov edx, [.ptrBounds]
test edx, edx
jz .rectok
mov eax, [edx+TBounds.x]
mov ecx, [edx+TBounds.y]
mov [edi+TPaintEvent.rect.left], eax
mov [edi+TPaintEvent.rect.top], ecx
mov eax, [edx+TBounds.width]
mov ecx, [edx+TBounds.height]
add eax, [edi+TPaintEvent.rect.left]
add ecx, [edi+TPaintEvent.rect.top]
mov [edi+TPaintEvent.rect.right], eax
mov [edi+TPaintEvent.rect.bottom], ecx
.rectok:
pushad
stdcall ExecEvent, esi, edi
popad
stdcall ReleaseContext, ebx
if defined Caret
cmp [.caret], -1
je @f
stdcall CaretShow, [.caret]
@@:
end if
pop edi esi edx ecx ebx eax
return
endp