Start working on a very basic window manager

This commit is contained in:
Ry 2022-10-05 16:15:36 -07:00
parent fecf74b652
commit 89ee1342fe
6 changed files with 760 additions and 55 deletions

View File

@ -1,19 +1,30 @@
; fox32os routine definitions
; system jump table
get_os_version: jmp [0x00000810]
get_os_version: jmp [0x00000810]
; FXF jump table
parse_fxf_binary: jmp [0x00000910]
parse_fxf_binary: jmp [0x00000910]
; task jump table
new_task: jmp [0x00000A10]
yield_task: jmp [0x00000A14]
end_current_task: jmp [0x00000A18]
get_current_task_id: jmp [0x00000A1C]
get_unused_task_id: jmp [0x00000A20]
is_task_id_used: jmp [0x00000A24]
new_task: jmp [0x00000A10]
yield_task: jmp [0x00000A14]
end_current_task: jmp [0x00000A18]
get_current_task_id: jmp [0x00000A1C]
get_unused_task_id: jmp [0x00000A20]
is_task_id_used: jmp [0x00000A24]
; memory jump table
allocate_memory: jmp [0x00000B10]
free_memory: jmp [0x00000B14]
allocate_memory: jmp [0x00000B10]
free_memory: jmp [0x00000B14]
; window jump table
new_window: jmp [0x00000C10]
destroy_window: jmp [0x00000C14]
new_window_event: jmp [0x00000C18]
get_next_window_event: jmp [0x00000C1C]
draw_title_bar_to_window: jmp [0x00000C20]
move_window: jmp [0x00000C24]
fill_window: jmp [0x00000C28]
get_window_overlay_number: jmp [0x00000C2C]
start_dragging_window: jmp [0x00000C30]

View File

@ -35,6 +35,18 @@ jump_table:
data.32 allocate_memory
data.32 free_memory
; window jump table
org.pad 0x00000C10
data.32 new_window
data.32 destroy_window
data.32 new_window_event
data.32 get_next_window_event
data.32 draw_title_bar_to_window
data.32 move_window
data.32 fill_window
data.32 get_window_overlay_number
data.32 start_dragging_window
; initialization code
entry:
mov rsp, SYSTEM_STACK
@ -57,6 +69,12 @@ entry:
mov r12, FOX32OS_VERSION_PATCH
call draw_format_str_to_background
; check if a disk is inserted as disk 1
; if so, skip checking startup.cfg and just run disk 1
in r31, 0x80001001
cmp r31, 0
ifnz jmp boot_disk_1
; open startup.cfg
mov r0, startup_cfg
mov r1, 0
@ -135,6 +153,9 @@ load_startup_task:
jmp load_startup_task
no_other_tasks:
; start the event manager task
call start_event_manager_task
; jump back to it without adding this "task" (not really a task) into the queue.
; end_current_task_no_mark_no_free is used specifically because it doesn't mark
; the current task (still set to 0) as unused, and it doesn't free the memory
@ -225,6 +246,7 @@ get_os_version:
#include "allocator.asm"
#include "fxf/fxf.asm"
#include "task.asm"
#include "window/window.asm"
startup_str: data.str "fox32 - OS version %u.%u.%u" data.8 0
startup_error_str: data.str "fox32 - OS version %u.%u.%u - startup.cfg is invalid!" data.8 0

136
kernel/window/event.asm Normal file
View File

@ -0,0 +1,136 @@
; window event routines
const WINDOW_EVENT_SIZE: 32
; get the next window event and remove it from the event queue
; inputs:
; r0: pointer to window struct
; outputs:
; r0: event type
; r1-r7: event parameters
get_next_window_event:
push r10
push r11
; r10: event_queue_ptr
mov r10, r0
add r10, 4
; r11: event_queue_bottom
mov r11, r0
add r11, 8
cmp [r10], [r11]
ifz pop r11
ifz pop r10
ifz jmp window_event_empty
get_next_window_event_0:
push r8
push r9
mov r8, [r11]
call window_event_load
mov r8, window_event_temp
call window_event_store
mov r9, [r11]
get_next_window_event_1:
add r9, WINDOW_EVENT_SIZE
cmp [r10], r9
ifz jmp get_next_window_event_2
mov r8, r9
call window_event_load
mov r8, r9
sub r8, WINDOW_EVENT_SIZE
call window_event_store
jmp get_next_window_event_1
get_next_window_event_2:
mov r8, window_event_temp
call window_event_load
sub [r10], WINDOW_EVENT_SIZE
pop r9
pop r8
pop r11
pop r10
ret
; add an event to a window's event queue
; inputs:
; r0: event type
; r1-r7: event parameters
; r8: pointer to window struct
; outputs:
; none
new_window_event:
push r8
push r9
mov r9, r8
add r9, 4 ; point to event_queue_ptr in the window struct
mov r8, [r9]
call window_event_store
mov [r9], r8
pop r9
pop r8
ret
window_event_load:
mov r0, [r8]
add r8, 4
mov r1, [r8]
add r8, 4
mov r2, [r8]
add r8, 4
mov r3, [r8]
add r8, 4
mov r4, [r8]
add r8, 4
mov r5, [r8]
add r8, 4
mov r6, [r8]
add r8, 4
mov r7, [r8]
add r8, 4
ret
window_event_store:
mov [r8], r0
add r8, 4
mov [r8], r1
add r8, 4
mov [r8], r2
add r8, 4
mov [r8], r3
add r8, 4
mov [r8], r4
add r8, 4
mov [r8], r5
add r8, 4
mov [r8], r6
add r8, 4
mov [r8], r7
add r8, 4
ret
window_event_empty:
mov r0, EVENT_TYPE_EMPTY
mov r1, 0
mov r2, 0
mov r3, 0
mov r4, 0
mov r5, 0
mov r6, 0
mov r7, 0
ret
window_event_temp: data.fill 0, 32 ; 8 entries * 4 bytes per word

View File

@ -0,0 +1,54 @@
; task that manages window events
; start a task which handles passing system events into the correct window event queue
; inputs:
; none
; outputs:
; none
start_event_manager_task:
; allocate 256 bytes for the stack
mov r0, 256
call allocate_memory
add r0, 256 ; add 256 so the stach pointer is at the end of the stack block (stack grows down)
mov r10, r0
; then start the task
call get_unused_task_id
mov r1, event_manager_task_loop ; initial instruction pointer
mov r2, r10 ; initial stack pointer
mov r3, 0 ; pointer to task code block to free when task ends
; (zero since we don't want to free any code blocks when the task ends)
mov r4, r10 ; pointer to task stack block to free when task ends
sub r4, 256 ; point to the start of the stack block that we allocated above
call new_task
ret
event_manager_task_loop:
call get_next_event
; HACK: put menu bar events back into the system event queue
cmp r0, EVENT_TYPE_MENU_BAR_CLICK
ifz call new_event
cmp r0, EVENT_TYPE_MENU_CLICK
ifz call new_event
cmp r0, EVENT_TYPE_MENU_UPDATE
ifz call new_event
cmp [active_window], 0
ifz rjmp event_manager_task_loop_end
; mouse
cmp r0, EVENT_TYPE_MOUSE_CLICK
ifz call add_mouse_event_to_active_window
cmp r0, EVENT_TYPE_MOUSE_RELEASE
ifz call add_mouse_event_to_active_window
; keyboard
cmp r0, EVENT_TYPE_KEY_DOWN
ifz call add_event_to_active_window
cmp r0, EVENT_TYPE_KEY_UP
ifz call add_event_to_active_window
event_manager_task_loop_end:
call yield_task
rjmp event_manager_task_loop

437
kernel/window/window.asm Normal file
View File

@ -0,0 +1,437 @@
; window management routines
; window struct:
; data.32 framebuffer_ptr - pointer to this window's framebuffer
; data.32 event_queue_ptr - current event queue pointer
; data.32 event_queue_bottom - pointer to beginning of this window's event queue
; data.32 title_ptr - pointer to null-terminated title string
; data.16 width - width of this window
; data.16 height - height of this window, not including the title bar
; data.16 x_pos - X coordinate of this window (top left corner of title bar)
; data.16 y_pos - Y coordinate of this window (top left corner of title bar)
; data.8 overlay - overlay number of this window
; data.8 reserved_1
; data.16 reserved_2
; data.32 reserved_3
const WINDOW_STRUCT_SIZE: 32 ; 8 words = 32 bytes
const TITLE_BAR_HEIGHT: 16
; create a new window and allocate memory as required
; inputs:
; r0: pointer to empty 32 byte window struct
; r1: pointer to null-terminated title string
; r2: window width
; r3: window height, not including the title bar
; r4: initial X coordinate (top left corner of title bar)
; r5: initial Y coordinate (top left corner of title bar)
; outputs:
; none
new_window:
push r1
push r2
push r3
push r4
push r5
push r10
push r11
push r12
; first, set up the initial struct values
; title string
mov r10, r0
add r10, 12
mov [r10], r1
; window size
add r10, 4
mov.16 [r10], r2
add r10, 2
mov.16 [r10], r3
; window position
add r10, 2
mov.16 [r10], r4
add r10, 2
mov.16 [r10], r5
; then, allocate memory for the framebuffer
; the space required is width * (height + TITLE_BAR_HEIGHT) * 4
mov r10, r2
mov r11, r3
add r11, TITLE_BAR_HEIGHT
mul r10, r11
mul r10, 4
push r0
mov r0, r10
call allocate_memory
cmp r0, 0
ifz jmp memory_error
mov r10, r0
pop r0
mov [r0], r10
mov r12, r10
; then, allocate memory for the event queue
; 32 events * 8 entries per event * 4 bytes per word = 1024 bytes
push r0
mov r0, 1024
call allocate_memory
cmp r0, 0
ifz jmp memory_error
mov r11, r0
pop r0
mov r10, r0
add r10, 8
mov [r10], r11
sub r10, 4
mov [r10], r11
; then, find an overlay to use for this window
push r0
call get_unused_overlay
mov r11, r0
pop r0
mov r10, r0
add r10, 24
mov.8 [r10], r11
; finally, set the properties of the overlay
push r0
push r1
push r2
mov r0, r4
mov r1, r5
mov r2, r11
call move_overlay
pop r2
pop r1
mov r0, r2
mov r1, r3
add r1, TITLE_BAR_HEIGHT
mov r2, r11
call resize_overlay
mov r0, r12
mov r1, r11
call set_overlay_framebuffer_pointer
mov r0, r11
call enable_overlay
mov r0, 0xFF000000
mov r1, r11
call fill_overlay
pop r0
mov [active_window], r0
call draw_title_bar_to_window
pop r12
pop r11
pop r10
pop r5
pop r4
pop r3
pop r2
pop r1
ret
; destroy a window and free memory used by it
; note that this does not free the memory used by the window struct itself
; inputs:
; r0: pointer to window struct
; outputs:
; none
destroy_window:
push r0
push r1
mov r1, r0
; free framebuffer memory
mov r0, [r1]
call free_memory
; free event queue memory
add r1, 8
mov r0, [r1]
call free_memory
add r1, 16
movz.8 r0, [r1]
call disable_overlay
pop r1
pop r0
ret
; call this if the user clicks on a window's title bar
; inputs:
; r0: pointer to window struct
; outputs:
; none
start_dragging_window:
push r0
push r1
push r2
push r4
mov r2, r0
mov r4, r0
add r4, 16
movz.16 r4, [r4]
div r4, 2
start_dragging_window_loop:
call get_mouse_position
sub r0, r4
sub r1, 8
call move_window
call get_mouse_button
bts r0, 2
ifnz jmp start_dragging_window_loop
pop r4
pop r2
pop r1
pop r0
ret
; move a window
; r0: X position
; r1: Y position
; r2: pointer to window struct
move_window:
push r2
add r2, 20
mov.16 [r2], r0
add r2, 2
mov.16 [r2], r1
add r2, 2
movz.8 r2, [r2]
call move_overlay
pop r2
ret
; fill a whole window with a color
; inputs:
; r0: color
; r1: pointer to window struct
; outputs:
; none
fill_window:
push r1
push r2
mov r2, r1
add r1, 24
movz.8 r1, [r1]
call fill_overlay
mov r0, r2
call draw_title_bar_to_window
pop r2
pop r1
ret
; get the overlay used by a window
; DO NOT CACHE THIS VALUE, it can change any time the window order changes
; inputs:
; r0: pointer to window struct
; outputs:
; r0: overlay number
get_window_overlay_number:
add r0, 24
movz.8 r0, [r0]
ret
; draw a window's title bar
; inputs:
; r0: pointer to window struct
; outputs:
; none
draw_title_bar_to_window:
push r0
push r3
push r4
push r10
push r11
push r12
push r31
; get the title string
add r0, 12
mov r12, [r0]
; get the width of this window
add r0, 4
movz.16 r11, [r0]
; get overlay number of this window
add r0, 8
movz.8 r10, [r0]
; save the old tilemap
call get_tilemap
push r0
push r1
push r2
; set the tilemap to our 1x16 tile patterns
mov r0, window_title_bar_patterns
mov r1, 1
mov r2, 16
call set_tilemap
mov r1, 0
mov r2, 0
mov r3, r10
mov r31, r11
draw_title_bar_to_window_loop:
mov r4, r31
rem r4, 2
cmp r4, 0
ifz mov r0, 0
ifnz mov r0, 1
call draw_tile_to_overlay
inc r1
loop draw_title_bar_to_window_loop
; restore the old tilemap
pop r2
pop r1
pop r0
call set_tilemap
; draw the title text
mov r0, r12
mov r1, 8
mov r2, 0
mov r3, 0xFF000000
mov r4, 0xFFFFFFFF
mov r5, r10
call draw_str_to_overlay
; draw the close button
mov r0, 1
mov r1, 4
mov r2, 6
mov r3, 8
mov r4, 0xFFFFFFFF
mov r5, r10
call draw_filled_rectangle_to_overlay
mov r0, 2
mov r1, 5
mov r2, 4
mov r3, 6
mov r4, 0xFF000000
mov r5, r10
call draw_filled_rectangle_to_overlay
pop r31
pop r12
pop r11
pop r10
pop r4
pop r3
pop r0
ret
; add an event to the active window
; inputs:
; r0-r7: event
; outputs:
; none
add_event_to_active_window:
mov r8, [active_window]
call new_window_event
ret
; add a mouse event to the active window if the mouse was clicked inside the active window
; if so, automatically convert the X and Y coords to be relative to the window
; inputs:
; r0-r7: event
; outputs:
; none
add_mouse_event_to_active_window:
push r0
push r2
push r10
push r11
push r12
; save X and Y coords of the click and the event type
mov r10, r1
mov r11, r2
mov r12, r0
; get the window's overlay number
mov r0, [active_window]
call get_window_overlay_number
; check if the window's overlay covers the clicked position
mov r2, r0
mov r0, r10
mov r1, r11
call check_if_overlay_covers_position
; if it doesn't, then end here
ifnz jmp add_mouse_event_to_active_window_end
; if it does, then make the X and Y coords relative to the overlay
call make_coordinates_relative_to_overlay
; add the event
mov r2, r1
mov r1, r0
mov r0, r12
call add_event_to_active_window
add_mouse_event_to_active_window_end:
pop r12
pop r11
pop r10
pop r2
pop r0
ret
window_title_bar_patterns:
; 1x16 tile
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
; 1x16 tile
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
data.32 0xFFFFFFFF
data.32 0xFF000000
active_window: data.32 0
#include "window/event.asm"
#include "window/event_manager_task.asm"

View File

@ -1,63 +1,108 @@
; about dialog
const BACKGROUND_COLOR: 0xFF674764
; show the about dialog
; inputs:
; none
; outputs:
; none
about_dialog:
; return if the dialog overlay is already enabled
in r0, 0x80000300
cmp r0, 0
ifnz ret
call disable_menu_bar
; set overlay position
mov r0, 64
mov r1, 64
mov r2, 0
call move_overlay
; create the window
mov r0, about_dialog_window_struct
mov r1, about_dialog_window_title
mov r2, 288
mov r3, 128
mov r4, 64
mov r5, 64
call new_window
; set overlay size
mov r0, 256
mov r1, 128
mov r2, 0
call resize_overlay
; fill the window with the fox32 purple color
mov r0, BACKGROUND_COLOR
mov r1, about_dialog_window_struct
call fill_window
; allocate memory for the overlay framebuffer
mov r0, 131072 ; 256x128x4
call allocate_memory
cmp r0, 0
ifz jmp allocate_error
mov [about_dialog_framebuffer_ptr], r0
mov r1, 0
call set_overlay_framebuffer_pointer
mov r0, about_dialog_window_struct
call get_window_overlay_number
; fill the overlay with all black
mov r0, 0xFF000000
mov r1, 0
call fill_overlay
; enable it!!
mov r0, 0
call enable_overlay
; draw strings
mov r5, r0
mov r0, about_dialog_window_launcher_string
mov r1, 4
mov r2, 20
mov r3, 0xFFFFFFFF
mov r4, BACKGROUND_COLOR
call draw_str_to_overlay
call get_os_version
mov r10, r0
mov r11, r1
mov r12, r2
mov r0, about_dialog_window_os_version_string
mov r1, 4
mov r2, 36
mov r3, 0xFFFFFFFF
mov r4, BACKGROUND_COLOR
call draw_format_str_to_overlay
call get_rom_version
mov r10, r0
mov r11, r1
mov r12, r2
mov r0, about_dialog_window_rom_version_string
mov r1, 4
mov r2, 52
mov r3, 0xFFFFFFFF
mov r4, BACKGROUND_COLOR
call draw_format_str_to_overlay
mov r0, about_dialog_window_made_by_string_1
mov r1, 4
mov r2, 104
mov r3, 0xFFFFFFFF
mov r4, BACKGROUND_COLOR
call draw_str_to_overlay
mov r0, about_dialog_window_made_by_string_2
mov r1, 180
mov r2, 120
mov r3, 0xFFFFFFFF
mov r4, BACKGROUND_COLOR
call draw_str_to_overlay
about_dialog_event_loop:
call get_next_event
mov r0, about_dialog_window_struct
call get_next_window_event
; did the user click the menu bar?
cmp r0, EVENT_TYPE_MENU_BAR_CLICK
ifz mov r0, menu_items_root
ifz call menu_bar_click_event
; is the user in a menu?
cmp r0, EVENT_TYPE_MENU_UPDATE
ifz call menu_update_event
; did the user click a menu item?
cmp r0, EVENT_TYPE_MENU_CLICK
ifz call menu_click_event
cmp r0, EVENT_TYPE_MOUSE_CLICK
ifz jmp about_dialog_mouse_down
about_dialog_event_loop_end:
call yield_task
jmp about_dialog_event_loop
rjmp about_dialog_event_loop
about_dialog_framebuffer_ptr: data.32 0
about_dialog_mouse_down:
; check if we are attempting to drag or close the window
cmp r2, 16
iflteq jmp about_dialog_drag_or_close_window
jmp about_dialog_event_loop_end
about_dialog_drag_or_close_window:
cmp r1, 8
iflteq jmp about_dialog_close_window
mov r0, about_dialog_window_struct
call start_dragging_window
jmp about_dialog_event_loop_end
about_dialog_close_window:
mov r0, about_dialog_window_struct
call destroy_window
call enable_menu_bar
jmp event_loop
about_dialog_window_title: data.str "About" data.8 0
about_dialog_window_struct: data.fill 0, 32
about_dialog_window_launcher_string: data.str "Launcher - the fox32os FXF launcher" data.8 0
about_dialog_window_made_by_string_1: data.str "fox32 - the computer made with love" data.8 0
about_dialog_window_made_by_string_2: data.str "by Ry and Lua" data.8 0
about_dialog_window_os_version_string: data.str "fox32os version %u.%u.%u" data.8 0
about_dialog_window_rom_version_string: data.str "fox32rom version %u.%u.%u" data.8 0