kolibrios/kernel/trunk/gui/window.inc
Mihail Semenyako (mike.dld) 892d2df51e * gui/window.inc refactoring
git-svn-id: svn://kolibrios.org@1362 a494cfbc-eb01-0410-851d-a64ba20cac60
2010-01-05 01:28:11 +00:00

1825 lines
53 KiB
PHP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;;
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$
;==============================================================================
;///// public functions ///////////////////////////////////////////////////////
;==============================================================================
macro FuncTable name, [label]
{
common
align 4
\label name#.ftable dword
forward
dd name#.#label
common
name#.sizeof.ftable = $ - name#.ftable
}
iglobal
FuncTable syscall_display_settings, \
00, 01, 02, 03, 04, 05, 06, 07, 08
endg
uglobal
common_colours rd 32
new_window_starting dd ?
latest_window_touch dd ?
latest_window_touch_delta dd ?
old_window_pos BOX
new_window_pos BOX
draw_limits RECT
bPressedMouseXY_W db ?
do_resize db ?
do_resize_from_corner db ?
reposition db ?
endg
align 4
;------------------------------------------------------------------------------
syscall_display_settings: ;///// system function 48 ///////////////////////////
;------------------------------------------------------------------------------
;; Redraw screen:
;< ebx = 0
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Set button style:
;< ebx = 1
;< ecx = 0 (flat) or 1 (with gradient)
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Set system color palette:
;< ebx = 2
;< ecx = pointer to color table
;< edx = size of color table
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Get system color palette:
;< ebx = 3
;< ecx = pointer to color table buffer
;< edx = size of color table buffer
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Get skinned caption height:
;< ebx = 4
;> eax = height in pixels
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Get screen working area:
;< ebx = 5
;> eax = pack[16(left), 16(right)]
;> ebx = pack[16(top), 16(bottom)]
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Set screen working area:
;< ebx = 6
;< ecx = pack[16(left), 16(right)]
;< edx = pack[16(top), 16(bottom)]
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Get skin margins:
;< ebx = 7
;> eax = pack[16(left), 16(right)]
;> ebx = pack[16(top), 16(bottom)]
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Set skin:
;< ebx = 8
;< ecx = pointer to FileInfoBlock struct
;> eax = FS error code
;------------------------------------------------------------------------------
cmp ebx, .sizeof.ftable / 4
ja @f
jmp [.ftable + ebx * 4]
@@: ret
align 4
syscall_display_settings.00:
xor eax, eax
inc ebx
cmp [windowtypechanged], ebx
jne .exit
mov [windowtypechanged], eax
jmp syscall_display_settings._.redraw_whole_screen
.exit:
ret
align 4
syscall_display_settings.01:
and ecx, 1
cmp ecx, [buttontype]
je .exit
mov [buttontype], ecx
mov [windowtypechanged], ebx
.exit:
ret
align 4
syscall_display_settings.02:
dec ebx
mov esi, ecx
and edx, 127
mov edi, common_colours
mov ecx, edx
rep movsb
mov [windowtypechanged], ebx
ret
align 4
syscall_display_settings.03:
mov edi, ecx
and edx, 127
mov esi, common_colours
mov ecx, edx
rep movsb
ret
align 4
syscall_display_settings.04:
mov eax, [_skinh]
mov [esp + 32], eax
ret
align 4
syscall_display_settings.05:
mov eax, [screen_workarea.left - 2]
mov ax, word[screen_workarea.right]
mov [esp + 32], eax
mov eax, [screen_workarea.top - 2]
mov ax, word[screen_workarea.bottom]
mov [esp + 20], eax
ret
align 4
syscall_display_settings.06:
xor esi, esi
mov edi, [Screen_Max_X]
mov eax, ecx
movsx ebx, ax
sar eax, 16
cmp eax, ebx
jge .check_horizontal
inc esi
or eax, eax
jge @f
xor eax, eax
@@: mov [screen_workarea.left], eax
cmp ebx, edi
jle @f
mov ebx, edi
@@: mov [screen_workarea.right], ebx
.check_horizontal:
mov edi, [Screen_Max_Y]
mov eax, edx
movsx ebx, ax
sar eax, 16
cmp eax, ebx
jge .check_if_redraw_needed
inc esi
or eax, eax
jge @f
xor eax, eax
@@: mov [screen_workarea.top], eax
cmp ebx, edi
jle @f
mov ebx, edi
@@: mov [screen_workarea.bottom], ebx
.check_if_redraw_needed:
or esi, esi
jz .exit
call repos_windows
jmp syscall_display_settings._.calculate_whole_screen
.exit:
ret
align 4
syscall_display_settings.07:
mov eax, [_skinmargins + 0]
mov [esp + 32], eax
mov eax, [_skinmargins + 4]
mov [esp + 20], eax
ret
align 4
syscall_display_settings.08:
mov ebx, ecx
call read_skin_file
mov [esp + 32], eax
test eax, eax
jnz .exit
call syscall_display_settings._.calculate_whole_screen
jmp syscall_display_settings._.redraw_whole_screen
.exit:
ret
syscall_display_settings._.calculate_whole_screen:
xor eax, eax
xor ebx, ebx
mov ecx, [Screen_Max_X]
mov edx, [Screen_Max_Y]
jmp calculatescreen
syscall_display_settings._.redraw_whole_screen:
xor eax, eax
mov [draw_limits.left], eax
mov [draw_limits.top], eax
mov eax, [Screen_Max_X]
mov [draw_limits.right], eax
mov eax, [Screen_Max_Y]
mov [draw_limits.bottom], eax
mov eax, window_data
jmp redrawscreen
align 4
;------------------------------------------------------------------------------
syscall_set_window_shape: ;///// system function 50 ///////////////////////////
;------------------------------------------------------------------------------
;; Set window shape address:
;> eax = 0
;> ebx = shape data address
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Set window shape scale:
;> eax = 1
;> ebx = scale power (resulting scale is 2^ebx)
;------------------------------------------------------------------------------
mov edi, [current_slot]
test eax, eax
jne .shape_scale
mov [edi + APPDATA.wnd_shape], ebx
.shape_scale:
dec eax
jnz .exit
mov [edi + APPDATA.wnd_shape_scale], ebx
.exit:
ret
align 4
;------------------------------------------------------------------------------
set_window_defaults: ;/////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
push eax ecx
xor eax, eax
mov ecx, WIN_STACK
@@: inc eax
add ecx, 2
; process no
mov [ecx + 0x000], ax
; positions in stack
mov [ecx + 0x400], ax
cmp ecx, WIN_POS - 2
jne @b
pop ecx eax
ret
align 4
;------------------------------------------------------------------------------
calculatescreen: ;/////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Scan all windows from bottom to top, calling `setscreen` for each one
;? intersecting given screen area
;------------------------------------------------------------------------------
;> eax = left
;> ebx = top
;> ecx = right
;> edx = bottom
;------------------------------------------------------------------------------
push esi
pushfd
cli
mov esi, 1
call window._.set_screen
push ebp
mov ebp, [TASK_COUNT]
cmp ebp, 1
jbe .exit
push edx ecx ebx eax
.next_window:
movzx edi, word[WIN_POS + esi * 2]
shl edi, 5
cmp [CURRENT_TASK + edi + TASKDATA.state], TSTATE_FREE
je .skip_window
add edi, window_data
test [edi + WDATA.fl_wstate], WSTATE_MINIMIZED
jnz .skip_window
mov eax, [edi + WDATA.box.left]
cmp eax, [esp + RECT.right]
ja .skip_window
mov ebx, [edi + WDATA.box.top]
cmp ebx, [esp + RECT.bottom]
ja .skip_window
mov ecx, [edi + WDATA.box.width]
add ecx, eax
cmp ecx, [esp + RECT.left]
jb .skip_window
mov edx, [edi + WDATA.box.height]
add edx, ebx
cmp edx, [esp + RECT.top]
jb .skip_window
cmp eax, [esp + RECT.left]
jae @f
mov eax, [esp + RECT.left]
@@: cmp ebx, [esp + RECT.top]
jae @f
mov ebx, [esp + RECT.top]
@@: cmp ecx, [esp + RECT.right]
jbe @f
mov ecx, [esp + RECT.right]
@@: cmp edx, [esp + RECT.bottom]
jbe @f
mov edx, [esp + RECT.bottom]
@@: push esi
movzx esi, word[WIN_POS + esi * 2]
call window._.set_screen
pop esi
.skip_window:
inc esi
dec ebp
jnz .next_window
pop eax ebx ecx edx
.exit:
pop ebp
popfd
pop esi
ret
align 4
;------------------------------------------------------------------------------
repos_windows: ;///////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
mov ecx, [TASK_COUNT]
mov edi, window_data + WDATA.sizeof * 2
call force_redraw_background
dec ecx
jle .exit
.next_window:
mov [edi + WDATA.fl_redraw], 1
test [edi + WDATA.fl_wstate], WSTATE_MAXIMIZED
jnz .fix_maximized
mov eax, [edi + WDATA.box.left]
add eax, [edi + WDATA.box.width]
mov ebx, [Screen_Max_X]
cmp eax, ebx
jle .fix_vertical
mov eax, [edi + WDATA.box.width]
sub eax, ebx
jle @f
mov [edi + WDATA.box.width], ebx
@@: sub ebx, [edi + WDATA.box.width]
mov [edi + WDATA.box.left], ebx
.fix_vertical:
mov eax, [edi + WDATA.box.top]
add eax, [edi + WDATA.box.height]
mov ebx, [Screen_Max_Y]
cmp eax, ebx
jle .fix_client_box
mov eax, [edi + WDATA.box.height]
sub eax, ebx
jle @f
mov [edi + WDATA.box.height], ebx
@@: sub ebx, [edi + WDATA.box.height]
mov [edi + WDATA.box.top], ebx
jmp .fix_client_box
.fix_maximized:
mov eax, [screen_workarea.left]
mov [edi + WDATA.box.left], eax
sub eax, [screen_workarea.right]
neg eax
mov [edi + WDATA.box.width], eax
mov eax, [screen_workarea.top]
mov [edi + WDATA.box.top], eax
test [edi + WDATA.fl_wstate], WSTATE_ROLLEDUP
jnz .fix_client_box
sub eax, [screen_workarea.bottom]
neg eax
mov [edi + WDATA.box.height], eax
.fix_client_box:
call set_window_clientbox
add edi, WDATA.sizeof
loop .next_window
.exit:
ret
align 4
;------------------------------------------------------------------------------
check_window_position: ;///////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Check if window is inside screen area
;------------------------------------------------------------------------------
;> edi = pointer to WDATA
;------------------------------------------------------------------------------
push eax ebx ecx edx esi
mov eax, [edi + WDATA.box.left]
mov ebx, [edi + WDATA.box.top]
mov ecx, [edi + WDATA.box.width]
mov edx, [edi + WDATA.box.height]
mov esi, [Screen_Max_X]
cmp ecx, esi
jbe .check_left
mov ecx, esi
mov [edi + WDATA.box.width], esi
.check_left:
or eax, eax
jg @f
xor eax, eax
jmp .fix_left
@@: add eax, ecx
cmp eax, esi
jle .check_height
mov eax, esi
sub eax, ecx
.fix_left:
mov [edi + WDATA.box.left], eax
.check_height:
mov esi, [Screen_Max_Y]
cmp edx, esi
jbe .check_top
mov edx, esi
mov [edi + WDATA.box.height], esi
.check_top:
or ebx, ebx
jg @f
xor ebx, ebx
jmp .fix_top
@@: add ebx, edx
cmp ebx, esi
jle .exit
mov ebx, esi
sub ebx, edx
.fix_top:
mov [edi + WDATA.box.top], ebx
.exit:
pop esi edx ecx ebx eax
ret
align 4
;------------------------------------------------------------------------------
sys_window_mouse: ;////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
push eax
mov eax, [timer_ticks]
cmp [new_window_starting], eax
jb .exit
mov byte[MOUSE_BACKGROUND], 0
mov byte[DONT_DRAW_MOUSE], 0
mov [new_window_starting], eax
.exit:
pop eax
ret
align 4
;------------------------------------------------------------------------------
draw_rectangle: ;//////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;> eax = pack[16(left), 16(right)]
;> ebx = pack[16(top), 16(bottom)]
;> esi = color
;------------------------------------------------------------------------------
push eax ebx ecx edi
xor edi, edi
.flags_set:
push ebx
; set line color
mov ecx, esi
; draw top border
rol ebx, 16
push ebx
rol ebx, 16
pop bx
call [draw_line]
; draw bottom border
mov ebx, [esp - 2]
pop bx
call [draw_line]
pop ebx
add ebx, 1 * 65536 - 1
; draw left border
rol eax, 16
push eax
rol eax, 16
pop ax
call [draw_line]
; draw right border
mov eax, [esp - 2]
pop ax
call [draw_line]
pop edi ecx ebx eax
ret
.forced:
push eax ebx ecx edi
xor edi, edi
inc edi
jmp .flags_set
align 4
;------------------------------------------------------------------------------
drawwindow_I_caption: ;////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
push [edx + WDATA.cl_titlebar]
mov esi, edx
mov edx, [esi + WDATA.box.top]
mov eax, edx
lea ebx, [edx + 21]
inc edx
add eax, [esi + WDATA.box.height]
cmp ebx, eax
jbe @f
mov ebx, eax
@@: push ebx
xor edi, edi
.next_line:
mov ebx, edx
shl ebx, 16
add ebx, edx
mov eax, [esi + WDATA.box.left]
inc eax
shl eax, 16
add eax, [esi + WDATA.box.left]
add eax, [esi + WDATA.box.width]
dec eax
mov ecx, [esi + WDATA.cl_titlebar]
test ecx, 0x80000000
jz @f
sub ecx, 0x00040404
mov [esi + WDATA.cl_titlebar], ecx
@@: and ecx, 0x00ffffff
call [draw_line]
inc edx
cmp edx, [esp]
jb .next_line
add esp, 4
pop [esi + WDATA.cl_titlebar]
ret
align 4
;------------------------------------------------------------------------------
drawwindow_I: ;////////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
pushad
; window border
mov eax, [edx + WDATA.box.left - 2]
mov ax, word[edx + WDATA.box.left]
add ax, word[edx + WDATA.box.width]
mov ebx, [edx + WDATA.box.top - 2]
mov bx, word[edx + WDATA.box.top]
add bx, word[edx + WDATA.box.height]
mov esi, [edx + WDATA.cl_frames]
call draw_rectangle
; window caption
call drawwindow_I_caption
; window client area
; do we need to draw it?
mov edi, [esi + WDATA.cl_workarea]
test edi, 0x40000000
jnz .exit
; does client area have a positive size on screen?
mov edx, [esi + WDATA.box.top]
add edx, 21 + 5
mov ebx, [esi + WDATA.box.top]
add ebx, [esi + WDATA.box.height]
cmp edx, ebx
jg .exit
; okay, let's draw it
mov eax, 1
mov ebx, 21
mov ecx, [esi + WDATA.box.width]
mov edx, [esi + WDATA.box.height]
call [drawbar]
.exit:
popad
ret
align 4
;------------------------------------------------------------------------------
drawwindow_III_caption: ;/////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
mov ecx, [edx + WDATA.cl_titlebar]
push ecx
mov esi, edx
mov edx, [esi + WDATA.box.top]
add edx, 4
mov ebx, [esi + WDATA.box.top]
add ebx, 20
mov eax, [esi + WDATA.box.top]
add eax, [esi + WDATA.box.height]
cmp ebx, eax
jb @f
mov ebx, eax
@@: push ebx
xor edi, edi
.next_line:
mov ebx, edx
shl ebx, 16
add ebx, edx
mov eax, [esi + WDATA.box.left]
shl eax, 16
add eax, [esi + WDATA.box.left]
add eax, [esi + WDATA.box.width]
add eax, 4 * 65536 - 4
mov ecx, [esi + WDATA.cl_titlebar]
test ecx, 0x40000000
jz @f
add ecx, 0x00040404
@@: test ecx, 0x80000000
jz @f
sub ecx, 0x00040404
@@: mov [esi + WDATA.cl_titlebar], ecx
and ecx, 0x00ffffff
call [draw_line]
inc edx
cmp edx, [esp]
jb .next_line
add esp, 4
pop [esi + WDATA.cl_titlebar]
ret
align 4
;------------------------------------------------------------------------------
drawwindow_III: ;//////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
pushad
; window border
mov eax, [edx + WDATA.box.left - 2]
mov ax, word[edx + WDATA.box.left]
add ax, word[edx + WDATA.box.width]
mov ebx, [edx + WDATA.box.top - 2]
mov bx, word[edx + WDATA.box.top]
add bx, word[edx + WDATA.box.height]
mov esi, [edx + WDATA.cl_frames]
shr esi, 1
and esi, 0x007f7f7f
call draw_rectangle
push esi
mov ecx, 3
mov esi, [edx + WDATA.cl_frames]
.next_frame:
add eax, 1 * 65536 - 1
add ebx, 1 * 65536 - 1
call draw_rectangle
dec ecx
jnz .next_frame
pop esi
add eax, 1 * 65536 - 1
add ebx, 1 * 65536 - 1
call draw_rectangle
; window caption
call drawwindow_III_caption
; window client area
; do we need to draw it?
mov edi, [esi + WDATA.cl_workarea]
test edi, 0x40000000
jnz .exit
; does client area have a positive size on screen?
mov edx, [esi + WDATA.box.top]
add edx, 21 + 5
mov ebx, [esi + WDATA.box.top]
add ebx, [esi + WDATA.box.height]
cmp edx, ebx
jg .exit
; okay, let's draw it
mov eax, 5
mov ebx, 20
mov ecx, [esi + WDATA.box.width]
mov edx, [esi + WDATA.box.height]
sub ecx, 4
sub edx, 4
call [drawbar]
.exit:
popad
ret
align 4
;------------------------------------------------------------------------------
waredraw: ;////////////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Activate window, redrawing if necessary
;------------------------------------------------------------------------------
; is it overlapped by another window now?
push ecx
call window._.check_window_draw
test ecx, ecx
pop ecx
jz .do_not_draw
; yes it is, activate and update screen buffer
mov byte[MOUSE_DOWN], 1
call window._.window_activate
pushad
mov edi, [TASK_COUNT]
movzx esi, word[WIN_POS + edi * 2]
shl esi, 5
add esi, window_data
mov eax, [esi + WDATA.box.left]
mov ebx, [esi + WDATA.box.top]
mov ecx, [esi + WDATA.box.width]
mov edx, [esi + WDATA.box.height]
add ecx, eax
add edx, ebx
mov edi, [TASK_COUNT]
movzx esi, word[WIN_POS + edi * 2]
call window._.set_screen
popad
; tell application to redraw itself
mov [edi + WDATA.fl_redraw], 1
mov byte[MOUSE_DOWN], 0
ret
.do_not_draw:
; no it's not, just activate the window
call window._.window_activate
mov byte[MOUSE_DOWN], 0
mov byte[MOUSE_BACKGROUND], 0
mov byte[DONT_DRAW_MOUSE], 0
ret
align 4
;------------------------------------------------------------------------------
minimize_window: ;/////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;> eax = window number on screen
;------------------------------------------------------------------------------
;# corrupts [dl*]
;------------------------------------------------------------------------------
push edi
pushfd
cli
; is it already minimized?
movzx edi, word[WIN_POS + eax * 2]
shl edi, 5
add edi, window_data
test [edi + WDATA.fl_wstate], WSTATE_MINIMIZED
jnz .exit
push eax ebx ecx edx esi
; no it's not, let's do that
or [edi + WDATA.fl_wstate], WSTATE_MINIMIZED
mov eax, [edi + WDATA.box.left]
mov [draw_limits.left], eax
mov ecx, eax
add ecx, [edi + WDATA.box.width]
mov [draw_limits.right], ecx
mov ebx, [edi + WDATA.box.top]
mov [draw_limits.top], ebx
mov edx, ebx
add edx, [edi + WDATA.box.height]
mov [draw_limits.bottom], edx
call calculatescreen
xor esi, esi
xor eax, eax
call redrawscreen
pop esi edx ecx ebx eax
.exit:
popfd
pop edi
ret
align 4
;------------------------------------------------------------------------------
restore_minimized_window: ;////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;> eax = window number on screen
;------------------------------------------------------------------------------
;# corrupts [dl*]
;------------------------------------------------------------------------------
pushad
pushfd
cli
; is it already restored?
movzx esi, word[WIN_POS + eax * 2]
mov edi, esi
shl edi, 5
add edi, window_data
test [edi + WDATA.fl_wstate], WSTATE_MINIMIZED
jz .exit
; no it's not, let's do that
mov [edi + WDATA.fl_redraw], 1
and [edi + WDATA.fl_wstate], not WSTATE_MINIMIZED
mov ebp, window._.set_screen
cmp eax, [TASK_COUNT]
jz @f
mov ebp, calculatescreen
@@: mov eax, [edi + WDATA.box.left]
mov ebx, [edi + WDATA.box.top]
mov ecx, [edi + WDATA.box.width]
mov edx, [edi + WDATA.box.height]
add ecx, eax
add edx, ebx
call ebp
mov byte[MOUSE_BACKGROUND], 0
.exit:
popfd
popad
ret
align 4
;------------------------------------------------------------------------------
checkwindows: ;////////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Check for user-initiated window operations
;------------------------------------------------------------------------------
pushad
; do we have window minimize/restore request?
cmp [window_minimize], 0
je .check_for_mouse_buttons_state
; okay, minimize or restore top-most window and exit
mov eax, [TASK_COUNT]
mov bl, 0
xchg [window_minimize], bl
dec bl
jnz @f
call minimize_window
jmp .check_for_mouse_buttons_state
@@: call restore_minimized_window
.check_for_mouse_buttons_state:
; do we have any mouse buttons pressed?
cmp byte[BTN_DOWN], 0
jne .mouse_buttons_pressed
mov [bPressedMouseXY_W], 0
jmp .exit
.mouse_buttons_pressed:
; yes we do, iterate and ...
mov esi, [TASK_COUNT]
inc esi
cmp [bPressedMouseXY_W], 1
ja .next_window
inc [bPressedMouseXY_W]
jnc .next_window
push dword[MOUSE_X]
pop dword[mx]
.next_window:
cmp esi, 2
jb .exit
dec esi
; is that window not minimized?
movzx edi, word[WIN_POS + esi * 2]
shl edi, 5
add edi, window_data
test [edi + WDATA.fl_wstate], WSTATE_MINIMIZED
jnz .next_window
movzx eax, [mx]
movzx ebx, [my]
; is the cursor inside screen bounds of that window?
mov ecx, [edi + WDATA.box.left]
mov edx, [edi + WDATA.box.top]
cmp eax, ecx
jl .next_window
cmp ebx, edx
jl .next_window
add ecx, [edi + WDATA.box.width]
add edx, [edi + WDATA.box.height]
cmp eax, ecx
jge .next_window
cmp ebx, edx
jge .next_window
; is that a top-most (which means active) window?
cmp esi, [TASK_COUNT]
je .check_for_moving_or_resizing
; no it's not, did we just press mouse button down above it or was it
; already pressed before?
cmp [bPressedMouseXY_W], 1
ja .exit
; okay, we just pressed the button, activate this window and exit
lea esi, [WIN_POS + esi * 2]
call waredraw
jmp .exit
.check_for_moving_or_resizing:
; is that window movable?
test byte[edi + WDATA.cl_titlebar + 3], 0x01
jnz .exit
; yes it is, is it rolled up?
test [edi + WDATA.fl_wstate], WSTATE_ROLLEDUP
jnz .check_for_cursor_on_caption
; no it's not, can it be resized then?
mov [do_resize_from_corner], 0
mov dl, [edi + WDATA.fl_wstyle]
and dl, 0x0f
cmp dl, 0x00
je .check_for_cursor_on_caption
cmp dl, 0x01
je .check_for_cursor_on_caption
cmp dl, 0x04
je .check_for_cursor_on_caption
; are we going to resize it?
mov edx, [edi + WDATA.box.top]
add edx, [edi + WDATA.box.height]
sub edx, 6
cmp ebx, edx
jl .check_for_cursor_on_caption
; yes we do, remember that
mov [do_resize_from_corner], 1
jmp .set_move_resize_flag
.check_for_cursor_on_caption:
; is the cursor inside window titlebar?
push eax
call window._.get_titlebar_height
add eax, [edi + WDATA.box.top]
cmp ebx, eax
pop eax
jge .exit
; calculate duration between two clicks
mov ecx, [timer_ticks]
mov edx, ecx
sub edx, [latest_window_touch]
mov [latest_window_touch], ecx
mov [latest_window_touch_delta], edx
.set_move_resize_flag:
mov cl, [BTN_DOWN]
mov [do_resize], cl
mov ecx, [edi + WDATA.box.left]
mov edx, [edi + WDATA.box.top]
push ecx edx
mov [draw_limits.left], ecx
mov [draw_limits.top], edx
add ecx, [edi + WDATA.box.width]
add edx, [edi + WDATA.box.height]
mov [draw_limits.right], ecx
mov [draw_limits.bottom], edx
pop edx ecx
; calculate window-relative cursor coordinates
sub eax, ecx
sub ebx, edx
push dword[MOUSE_X]
pop dword[WIN_TEMP_XY]
; save old window coordinates
push eax
mov eax, [edi + WDATA.box.left]
mov [old_window_pos.left], eax
mov [new_window_pos.left], eax
mov eax, [edi + WDATA.box.top]
mov [old_window_pos.top], eax
mov [new_window_pos.top], eax
mov eax, [edi + WDATA.box.width]
mov [old_window_pos.width], eax
mov [new_window_pos.width], eax
mov eax, [edi + WDATA.box.height]
mov [old_window_pos.height], eax
mov [new_window_pos.height], eax
pop eax
; draw negative moving/sizing frame
call window._.draw_window_frames
mov [reposition], 0
mov byte[MOUSE_DOWN], 1
.next_mouse_state_check:
; process OS events
mov byte[DONT_DRAW_MOUSE], 1
call checkidle
call checkVga_N13
mov byte[MOUSE_BACKGROUND], 0
call [draw_pointer]
pushad
call stack_handler
popad
; did cursor position change?
mov esi, [WIN_TEMP_XY]
cmp esi, [MOUSE_X]
je .check_for_new_mouse_buttons_state
; yes it did, calculate window-relative cursor coordinates
movzx ecx, word[MOUSE_X]
movzx edx, word[MOUSE_Y]
sub ecx, eax
sub edx, ebx
push eax ebx
; we're going to draw new frame, erasing the old one
call window._.draw_window_frames
; are we moving it right now?
cmp [do_resize_from_corner], 0
jne .resize_window
; yes we do, check if it's inside the screen area
mov eax, [Screen_Max_X]
mov ebx, [Screen_Max_Y]
mov [new_window_pos.left], 0
or ecx, ecx
jle .check_for_new_vert_cursor_pos
mov [reposition], 1
sub eax, [new_window_pos.width]
mov [new_window_pos.left], eax
cmp ecx, eax
jge .check_for_new_vert_cursor_pos
mov [new_window_pos.left], ecx
.check_for_new_vert_cursor_pos:
mov [new_window_pos.top], 0
or edx, edx
jle .draw_new_window_frame
mov [reposition], 1
sub ebx, [new_window_pos.height]
mov [new_window_pos.top], ebx
cmp edx, ebx
jge .draw_new_window_frame
mov [new_window_pos.top], edx
jmp .draw_new_window_frame
.resize_window:
push eax ebx edx
mov edx, edi
sub edx, window_data
lea edx, [SLOT_BASE + edx * 8]
movzx eax, word[MOUSE_X]
cmp eax, [edi + WDATA.box.left]
jb .fix_new_vert_size
sub eax, [edi + WDATA.box.left]
cmp eax, 32
jge @f
mov eax, 32
@@: mov [new_window_pos.width], eax
.fix_new_vert_size:
call window._.get_rolledup_height
mov ebx, eax
movzx eax, word[MOUSE_Y]
cmp eax, [edi + WDATA.box.top]
jb .set_reposition_flag
sub eax, [edi + WDATA.box.top]
cmp eax, ebx
jge @f
mov eax, ebx
@@: mov [new_window_pos.height], eax
.set_reposition_flag:
mov [reposition], 1
pop edx ebx eax
.draw_new_window_frame:
pop ebx eax
; draw new window moving/sizing frame
call window._.draw_window_frames
mov esi, [MOUSE_X]
mov [WIN_TEMP_XY], esi
.check_for_new_mouse_buttons_state:
; did user release mouse button(s)?
cmp byte[BTN_DOWN], 0
jne .next_mouse_state_check
; yes he did, moving/sizing is over
mov byte[DONT_DRAW_MOUSE], 1
mov cl, 0
test [edi + WDATA.fl_wstate], WSTATE_MAXIMIZED
jnz .check_other_actions
mov cl, [reposition]
; draw negative frame once again to hide it
call window._.draw_window_frames
; save new window bounds
mov eax, [new_window_pos.left]
mov [edi + WDATA.box.left], eax
mov eax, [new_window_pos.top]
mov [edi + WDATA.box.top], eax
mov eax, [new_window_pos.width]
mov [edi + WDATA.box.width], eax
mov eax, [new_window_pos.height]
mov [edi + WDATA.box.height], eax
call set_window_clientbox
cmp cl, 1
jne .check_other_actions
push esi edi ecx
mov esi, edi
mov ecx, 2
test [edi + WDATA.fl_wstate], WSTATE_ROLLEDUP or WSTATE_MAXIMIZED
jnz @f
add ecx, 2
@@: sub edi, window_data
shr edi, 5
shl edi, 8
add edi, SLOT_BASE + APPDATA.saved_box
cld
rep movsd
pop ecx edi esi
.check_other_actions:
mov [reposition], cl
pushad
mov dl, [edi + WDATA.fl_wstyle]
and dl, 0x0f
cmp dl, 0x00
je .check_if_window_fits_screen
cmp dl, 0x01
je .check_if_window_fits_screen
cmp cl, 1
je .no_window_sizing
mov edx, edi
sub edx, window_data
shr edx, 5
shl edx, 8
add edx, SLOT_BASE
; did we right-click on titlebar?
cmp [do_resize], 2
jne .check_maximization_request
; yes we did, toggle normal/rolled up window state
xor [edi + WDATA.fl_wstate], WSTATE_ROLLEDUP
mov [reposition], 1
; calculate and set appropriate window height
test [edi + WDATA.fl_wstate], WSTATE_ROLLEDUP
jz @f
call window._.get_rolledup_height
jmp .set_new_window_height
@@: mov eax, [edx + APPDATA.saved_box.height]
test [edi + WDATA.fl_wstate], WSTATE_MAXIMIZED
jz .set_new_window_height
mov eax, [screen_workarea.bottom]
sub eax, [screen_workarea.top]
.set_new_window_height:
mov [edi + WDATA.box.height], eax
add eax, [edi + WDATA.box.top]
cmp eax, [Screen_Max_Y]
jbe @f
mov eax, [Screen_Max_Y]
sub eax, [edi + WDATA.box.height]
mov [edi + WDATA.box.top], eax
@@: call check_window_position
call set_window_clientbox
.check_maximization_request:
; can window change its height?
push edx
mov dl, [edi + WDATA.fl_wstyle]
and dl, 0x0f
cmp dl, 0x04
pop edx
je .check_if_window_fits_screen
; was it really a maximize/restore request?
cmp [do_resize], 1
jne .check_if_window_fits_screen
cmp [do_resize_from_corner], 0
jne .check_if_window_fits_screen
cmp [latest_window_touch_delta], 50
jg .check_if_window_fits_screen
; yes is was, toggle normal/maximized window state
xor [edi + WDATA.fl_wstate], WSTATE_MAXIMIZED
mov [reposition], 1
; calculate and set appropriate window bounds
test [edi + WDATA.fl_wstate], WSTATE_MAXIMIZED
jz .restore_normal_window_size
mov eax, [screen_workarea.left]
mov [edi + WDATA.box.left], eax
sub eax, [screen_workarea.right]
neg eax
mov [edi + WDATA.box.width], eax
mov eax, [screen_workarea.top]
mov [edi + WDATA.box.top], eax
test [edi + WDATA.fl_wstate], WSTATE_ROLLEDUP
jnz .calculate_window_client_area
sub eax, [screen_workarea.bottom]
neg eax
mov [edi + WDATA.box.height], eax
jmp .calculate_window_client_area
.restore_normal_window_size:
push [edi + WDATA.box.height]
push edi
lea esi, [edx + APPDATA.saved_box]
mov ecx, 4
cld
rep movsd
pop edi
pop eax
test [edi + WDATA.fl_wstate], WSTATE_ROLLEDUP
jz .calculate_window_client_area
mov [edi + WDATA.box.height], eax
.calculate_window_client_area:
call set_window_clientbox
.check_if_window_fits_screen:
; does window fit into screen area?
mov eax, [edi + WDATA.box.top]
add eax, [edi + WDATA.box.height]
cmp eax, [Screen_Max_Y]
jbe .no_window_sizing
mov eax, [edi + WDATA.box.left]
add eax, [edi + WDATA.box.width]
cmp eax, [Screen_Max_X]
jbe .no_window_sizing
; no it doesn't, fix that
mov eax, [Screen_Max_X]
sub eax, [edi + WDATA.box.width]
mov [edi + WDATA.box.left], eax
mov eax, [Screen_Max_Y]
sub eax, [edi + WDATA.box.height]
mov [edi + WDATA.box.top], eax
call set_window_clientbox
.no_window_sizing:
popad
; did somethins actually change its place?
cmp [reposition], 0
je .reset_vars
mov byte[DONT_DRAW_MOUSE], 1
push eax ebx ecx edx
; recalculate screen buffer at new position
mov eax, [edi + WDATA.box.left]
mov ebx, [edi + WDATA.box.top]
mov ecx, [edi + WDATA.box.width]
mov edx, [edi + WDATA.box.height]
add ecx, eax
add edx, ebx
call calculatescreen
; recalculate screen buffer at old position
mov eax, [old_window_pos.left]
mov ebx, [old_window_pos.top]
mov ecx, [old_window_pos.width]
mov edx, [old_window_pos.height]
add ecx, eax
add edx, ebx
call calculatescreen
pop edx ecx ebx eax
mov eax, edi
call redrawscreen
; tell window to redraw itself
mov [edi + WDATA.fl_redraw], 1
; wait a bit for window to redraw itself
mov ecx, 100
.next_idle_cycle:
mov byte[DONT_DRAW_MOUSE], 1
call checkidle
cmp [edi + WDATA.fl_redraw], 0
jz .reset_vars
loop .next_idle_cycle
.reset_vars:
mov byte[DONT_DRAW_MOUSE], 0 ; mouse pointer
mov byte[MOUSE_BACKGROUND], 0 ; no mouse under
mov byte[MOUSE_DOWN], 0 ; react to mouse up/down
.exit:
popad
ret
;==============================================================================
;///// private functions //////////////////////////////////////////////////////
;==============================================================================
align 4
;------------------------------------------------------------------------------
window._.get_titlebar_height: ;////////////////////////////////////////////////
;------------------------------------------------------------------------------
;> edi = pointer to WDATA
;------------------------------------------------------------------------------
mov al, [edi + WDATA.fl_wstyle]
and al, 0x0f
cmp al, 0x03
jne @f
mov eax, [_skinh]
ret
@@: mov eax, 21
ret
align 4
;------------------------------------------------------------------------------
window._.get_rolledup_height: ;////////////////////////////////////////////////
;------------------------------------------------------------------------------
;> edi = pointer to WDATA
;------------------------------------------------------------------------------
mov al, [edi + WDATA.fl_wstyle]
and al, 0x0f
cmp al, 0x03
jb @f
mov eax, [_skinh]
add eax, 3
ret
@@: or al, al
jnz @f
mov eax, 21
ret
@@: mov eax, 21 + 2
ret
align 4
;------------------------------------------------------------------------------
window._.set_screen: ;/////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Reserve window area in screen buffer
;------------------------------------------------------------------------------
;> eax = left
;> ebx = top
;> ecx = right
;> edx = bottom
;> esi = process number
;------------------------------------------------------------------------------
virtual at esp
ff_x dd ?
ff_y dd ?
ff_width dd ?
ff_xsz dd ?
ff_ysz dd ?
ff_scale dd ?
end virtual
pushad
cmp esi, 1
jz .check_for_shaped_window
mov edi, esi
shl edi, 5
cmp [window_data + edi + WDATA.box.width], 0
jnz .check_for_shaped_window
cmp [window_data + edi + WDATA.box.height], 0
jz .exit
.check_for_shaped_window:
mov edi, esi
shl edi, 8
add edi, SLOT_BASE
cmp [edi + APPDATA.wnd_shape], 0
jne .shaped_window
; get x&y size
sub ecx, eax
sub edx, ebx
inc ecx
inc edx
; get WinMap start
mov edi, [Screen_Max_X]
inc edi
imul edi, ebx
add edi, eax
add edi, [_WinMapAddress]
mov eax, esi
.next_line:
push ecx
rep stosb
pop ecx
add edi, [Screen_Max_X]
inc edi
sub edi, ecx
dec edx
jnz .next_line
jmp .exit
.shaped_window:
; for (y=0; y <= x_size; y++)
; for (x=0; x <= x_size; x++)
; if (shape[coord(x,y,scale)]==1)
; set_pixel(x, y, process_number);
sub ecx, eax
sub edx, ebx
inc ecx
inc edx
push [edi + APPDATA.wnd_shape_scale] ; push scale first -> for loop
; get WinMap start -> ebp
push eax
mov eax, [Screen_Max_X] ; screen_sx
inc eax
imul eax, ebx
add eax, [esp]
add eax, [_WinMapAddress]
mov ebp, eax
mov edi, [edi + APPDATA.wnd_shape]
pop eax
; eax = x_start
; ebx = y_start
; ecx = x_size
; edx = y_size
; esi = process_number
; edi = &shape
; [scale]
push edx ecx ; for loop - x,y size
mov ecx, esi
shl ecx, 5
mov edx, [window_data + ecx + WDATA.box.top]
push [window_data + ecx + WDATA.box.width] ; for loop - width
mov ecx, [window_data + ecx + WDATA.box.left]
sub ebx, edx
sub eax, ecx
push ebx eax ; for loop - x,y
add [ff_xsz], eax
add [ff_ysz], ebx
mov ebx, [ff_y]
.ff_new_y:
mov edx, [ff_x]
.ff_new_x:
; -- body --
mov ecx, [ff_scale]
mov eax, [ff_width]
inc eax
shr eax, cl
push ebx edx
shr ebx, cl
shr edx, cl
imul eax, ebx
add eax, edx
pop edx ebx
add eax, edi
call .read_byte
test al,al
jz @f
mov eax, esi
mov [ebp], al
; -- end body --
@@: inc ebp
inc edx
cmp edx, [ff_xsz]
jb .ff_new_x
sub ebp, [ff_xsz]
add ebp, [ff_x]
add ebp, [Screen_Max_X] ; screen.x
inc ebp
inc ebx
cmp ebx, [ff_ysz]
jb .ff_new_y
add esp, 24
.exit:
popad
ret
.read_byte:
; eax - address
; esi - slot
push eax ecx edx esi
xchg eax, esi
lea ecx, [esp + 12]
mov edx, 1
call read_process_memory
pop esi edx ecx eax
ret
align 4
;------------------------------------------------------------------------------
window._.window_activate: ;////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Activate window
;------------------------------------------------------------------------------
;> esi = pointer to WIN_POS+ window data
;------------------------------------------------------------------------------
push eax ebx
; if type of current active window is 3 or 4, it must be redrawn
mov eax, [TASK_COUNT]
movzx eax, word[WIN_POS + eax * 2]
shl eax, 5
add eax, window_data
mov bl, [eax + WDATA.fl_wstyle]
and bl, 0x0f
cmp bl, 0x03
je .set_window_redraw_flag
cmp bl, 0x04
je .set_window_redraw_flag
jmp .move_others_down
.set_window_redraw_flag:
mov [eax + WDATA.fl_redraw], 1
.move_others_down:
; ax <- process no
movzx eax, word[esi]
; ax <- position in window stack
movzx eax, word[WIN_STACK + eax * 2]
; drop others
xor ebx, ebx
.next_stack_window:
cmp ebx, [TASK_COUNT]
jae .move_self_up
inc ebx
cmp [WIN_STACK + ebx * 2], ax
jbe .next_stack_window
dec word[WIN_STACK + ebx * 2]
jmp .next_stack_window
.move_self_up:
movzx eax, word[esi]
; number of processes
mov bx, [TASK_COUNT]
; this is the last (and the upper)
mov [WIN_STACK + eax * 2], bx
; update on screen - window stack
xor ebx, ebx
.next_window_pos:
cmp ebx, [TASK_COUNT]
jae .reset_vars
inc ebx
movzx eax, word[WIN_STACK + ebx * 2]
mov [WIN_POS + eax * 2], bx
jmp .next_window_pos
.reset_vars:
mov byte[KEY_COUNT], 0
mov byte[BTN_COUNT], 0
mov word[MOUSE_SCROLL_H], 0
mov word[MOUSE_SCROLL_V], 0
pop ebx eax
ret
align 4
;------------------------------------------------------------------------------
window._.check_window_draw: ;//////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Check if window is necessary to draw
;------------------------------------------------------------------------------
;> edi = pointer to WDATA
;------------------------------------------------------------------------------
mov cl, [edi + WDATA.fl_wstyle]
and cl, 0x0f
cmp cl, 0x03
je .exit.redraw ; window type 3
cmp cl, 0x04
je .exit.redraw ; window type 4
push eax ebx edx esi
mov eax, edi
sub eax, window_data
shr eax, 5
; esi = process number
movzx eax, word[WIN_STACK + eax * 2] ; get value of the curr process
lea esi, [WIN_POS + eax * 2] ; get address of this process at 0xC400
.next_window:
add esi, 2
mov eax, [TASK_COUNT]
lea eax, word[WIN_POS + eax * 2] ; number of the upper window
cmp esi, eax
ja .exit.no_redraw
movzx edx, word[esi]
shl edx, 5
cmp [CURRENT_TASK + edx + TASKDATA.state], TSTATE_FREE
je .next_window
mov eax, [edi + WDATA.box.top]
mov ebx, [edi + WDATA.box.height]
add ebx, eax
mov ecx, [window_data + edx + WDATA.box.top]
cmp ecx, ebx
jge .next_window
add ecx, [window_data + edx + WDATA.box.height]
cmp eax, ecx
jge .next_window
mov eax, [edi + WDATA.box.left]
mov ebx, [edi + WDATA.box.width]
add ebx, eax
mov ecx, [window_data + edx + WDATA.box.left]
cmp ecx, ebx
jge .next_window
add ecx, [window_data + edx + WDATA.box.width]
cmp eax, ecx
jge .next_window
pop esi edx ebx eax
.exit.redraw:
xor ecx, ecx
inc ecx
ret
.exit.no_redraw:
pop esi edx ebx eax
xor ecx, ecx
ret
align 4
;------------------------------------------------------------------------------
window._.draw_window_frames: ;/////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Draw negative window frames
;------------------------------------------------------------------------------
;> edi = pointer to WDATA
;------------------------------------------------------------------------------
push eax
cli
test [edi + WDATA.fl_wstate], WSTATE_MAXIMIZED
jnz .exit
mov eax, [new_window_pos.left]
cmp eax, [edi + WDATA.box.left]
jnz .draw
mov eax, [new_window_pos.width]
cmp eax, [edi + WDATA.box.width]
jnz .draw
mov eax, [new_window_pos.top]
cmp eax, [edi + WDATA.box.top]
jnz .draw
mov eax, [new_window_pos.height]
cmp eax, [edi + WDATA.box.height]
jnz .draw
xor [edi + WDATA.fl_wdrawn], 2
.draw:
push ebx esi
mov eax, [new_window_pos.left - 2]
mov ax, word[new_window_pos.left]
add ax, word[new_window_pos.width]
mov ebx, [new_window_pos.top - 2]
mov bx, word[new_window_pos.top]
add bx, word[new_window_pos.height]
mov esi, 0x01000000
call draw_rectangle.forced
pop esi ebx
.exit:
sti
pop eax
ret
.forced:
push eax
cli
jmp .draw