From a68e584c82c56e888e28a73e084447577b5542cd Mon Sep 17 00:00:00 2001 From: Ry Date: Fri, 23 Dec 2022 22:26:16 -0800 Subject: [PATCH] kernel: A more complete window manager implementation It's currently pretty buggy, but at least it's better than what we had before :P --- kernel/window/event_manager_task.asm | 78 ++++++++++- kernel/window/overlay.asm | 95 ++++++++++++++ kernel/window/window.asm | 188 ++++++++++++++++++++++++++- 3 files changed, 353 insertions(+), 8 deletions(-) create mode 100644 kernel/window/overlay.asm diff --git a/kernel/window/event_manager_task.asm b/kernel/window/event_manager_task.asm index 4eb8c53..eaa7ec1 100644 --- a/kernel/window/event_manager_task.asm +++ b/kernel/window/event_manager_task.asm @@ -35,14 +35,14 @@ event_manager_task_loop: cmp r0, EVENT_TYPE_MENU_UPDATE ifz call new_event - cmp [active_window], 0 + cmp.8 [active_window_offset], 0xFF ifz rjmp event_manager_task_loop_end ; mouse cmp r0, EVENT_TYPE_MOUSE_CLICK - ifz call add_mouse_event_to_active_window + ifz call event_manager_task_mouse_event cmp r0, EVENT_TYPE_MOUSE_RELEASE - ifz call add_mouse_event_to_active_window + ifz call event_manager_task_mouse_event ; keyboard cmp r0, EVENT_TYPE_KEY_DOWN @@ -52,3 +52,75 @@ event_manager_task_loop: event_manager_task_loop_end: call yield_task rjmp event_manager_task_loop + +event_manager_task_mouse_event: + push r0 + push r1 + push r2 + + ; find which overlay was clicked on + mov r0, r1 + mov r1, r2 + call find_overlay_convering_position + cmp r0, 0xFFFFFFFF + ifz pop r2 + ifz pop r1 + ifz pop r0 + ifz ret + push r0 + + ; get the overlay number of the active window + movz.8 r0, [active_window_offset] + call window_list_offset_to_struct + call get_window_overlay_number + + ; check if the click was inside the active window + ; otherwise, activate the clicked window + pop r1 + cmp r0, r1 + ifnz jmp event_manager_task_mouse_event_inactive_window_was_clicked + + pop r2 + pop r1 + pop r0 + call add_mouse_event_to_active_window + ret +event_manager_task_mouse_event_inactive_window_was_clicked: + mov r2, r1 + mov r1, r0 + mov r0, r2 + + ; r0: clicked window overlay number + ; r1: currently active window overlay number + + ; get the window structs of the two windows + call get_window_with_overlay + mov r2, r0 + mov r0, r1 + call get_window_with_overlay + mov r1, r2 + + ; give up if a window was not found for this overlay + cmp r0, 0x00000000 + ifz pop r2 + ifz pop r1 + ifz pop r0 + ifz ret + cmp r1, 0x00000000 + ifz pop r2 + ifz pop r1 + ifz pop r0 + ifz ret + + ; swap the two + call swap_windows + + ; mark the clicked window as the active window + mov r0, r1 + call search_for_window_list_entry + mov.8 [active_window_offset], r0 + + pop r2 + pop r1 + pop r0 + ret diff --git a/kernel/window/overlay.asm b/kernel/window/overlay.asm new file mode 100644 index 0000000..7739339 --- /dev/null +++ b/kernel/window/overlay.asm @@ -0,0 +1,95 @@ +; overlay routines for window management + +; given a position on screen, find which enabled overlay (if any) is covering it +; if multiple overlays are covering the same position, the highest priority one will be returned +; overlay 31 (the mouse cursor) is ignored +; inputs: +; r0: X coordinate +; r1: Y coordinate +; outputs: +; r0: overlay number, or 0xFFFFFFFF if none +find_overlay_convering_position: + push r2 + push r31 + + mov r31, 31 +find_overlay_convering_position_loop: + mov r2, r31 + dec r2 + call check_if_enabled_overlay_covers_position + ifz jmp find_overlay_convering_position_found + loop find_overlay_convering_position_loop + ; none found, return 0xFFFFFFFF + mov r0, 0xFFFFFFFF + pop r31 + pop r2 + ret +find_overlay_convering_position_found: + ; found one, return its overlay number + mov r0, r2 + pop r31 + pop r2 + ret + +; swap two overlays. this has the effect of swapping their priorities +; this does *not* effect the enable status of either overlay +; FIXME: this could use the stack instead +; inputs: +; r0: overlay number +; r1: overlay number +; outputs: +; none +swap_overlays: + push r10 + + ; save first overlay + mov r10, r0 + or r10, 0x80000000 + in [overlay_0_position], r10 + mov r10, r0 + or r10, 0x80000100 + in [overlay_0_size], r10 + mov r10, r0 + or r10, 0x80000200 + in [overlay_0_ptr], r10 + + ; save second overlay + mov r10, r1 + or r10, 0x80000000 + in [overlay_1_position], r10 + mov r10, r1 + or r10, 0x80000100 + in [overlay_1_size], r10 + mov r10, r1 + or r10, 0x80000200 + in [overlay_1_ptr], r10 + + ; swap + mov r10, r1 + or r10, 0x80000000 + out r10, [overlay_0_position] + mov r10, r1 + or r10, 0x80000100 + out r10, [overlay_0_size] + mov r10, r1 + or r10, 0x80000200 + out r10, [overlay_0_ptr] + mov r10, r0 + or r10, 0x80000000 + out r10, [overlay_1_position] + mov r10, r0 + or r10, 0x80000100 + out r10, [overlay_1_size] + mov r10, r0 + or r10, 0x80000200 + out r10, [overlay_1_ptr] + + pop r10 + ret + +overlay_0_position: data.32 0x00000000 +overlay_0_size: data.32 0x00000000 +overlay_0_ptr: data.32 0x00000000 +overlay_1_position: data.32 0x00000000 +overlay_1_size: data.32 0x00000000 +overlay_1_ptr: data.32 0x00000000 diff --git a/kernel/window/window.asm b/kernel/window/window.asm index 9b8896f..12a8110 100644 --- a/kernel/window/window.asm +++ b/kernel/window/window.asm @@ -94,7 +94,7 @@ new_window: add r10, 24 mov.8 [r10], r11 - ; finally, set the properties of the overlay + ; then, set the properties of the overlay push r0 push r1 push r2 @@ -119,9 +119,19 @@ new_window: call fill_overlay pop r0 - mov [active_window], r0 + ; then, draw the title bar call draw_title_bar_to_window + ; finally, add this window to the window list + push r0 + mov r0, 0x00000000 + call search_for_window_list_entry + mov.8 [active_window_offset], r0 + mul r0, 4 + add r0, window_list + pop r1 + mov [r0], r1 + pop r12 pop r11 pop r10 @@ -153,10 +163,23 @@ destroy_window: mov r0, [r1] call free_memory + ; disable the window's overlay add r1, 16 movz.8 r0, [r1] call disable_overlay + ; remove the window from the window list + sub r1, 24 + mov r0, r1 + call search_for_window_list_entry + mul r0, 4 + add r0, window_list + mov [r0], 0 + + ; set the active window to whatever entry is found first + call search_for_nonempty_window_list_entry + mov.8 [active_window_offset], r0 + pop r1 pop r0 ret @@ -244,6 +267,35 @@ move_window: pop r0 ret +; swap two windows +; inputs: +; r0: pointer to window struct +; r1: pointer to window struct +; outputs: +; none +swap_windows: + push r0 + push r1 + push r2 + push r3 + + mov r2, r0 + mov r3, r1 + + add r2, 24 + movz.8 r0, [r2] + add r3, 24 + movz.8 r1, [r3] + call swap_overlays + movz.8 [r2], r1 + movz.8 [r3], r0 + + pop r3 + pop r2 + pop r1 + pop r0 + ret + ; fill a whole window with a color ; inputs: ; r0: color @@ -377,7 +429,11 @@ draw_title_bar_to_window_loop: ; outputs: ; none add_event_to_active_window: - mov r8, [active_window] + push r0 + movz.8 r0, [active_window_offset] + call window_list_offset_to_struct + mov r8, r0 + pop r0 call new_window_event ret @@ -401,7 +457,8 @@ add_mouse_event_to_active_window: mov r12, r0 ; get the window's overlay number - mov r0, [active_window] + movz.8 r0, [active_window_offset] + call window_list_offset_to_struct call get_window_overlay_number ; check if the window's overlay covers the clicked position @@ -427,6 +484,125 @@ add_mouse_event_to_active_window_end: pop r0 ret +; search for an entry in the window list +; inputs: +; r0: entry (pointer to window struct) +; outputs: +; r0: window list offset, or 0xFFFFFFFF if not found +search_for_window_list_entry: + push r1 + push r2 + push r31 + + mov r1, window_list + mov r2, 0 + mov r31, 31 +search_for_window_list_entry_loop: + cmp [r1], r0 + ifz jmp search_for_window_list_entry_found + inc r2 + add r1, 4 + loop search_for_window_list_entry_loop + ; not found, return 0xFFFFFFFF + mov r0, 0xFFFFFFFF + + pop r31 + pop r2 + pop r1 + ret +search_for_window_list_entry_found: + ; found the entry, return its offset + mov r0, r2 + + pop r31 + pop r2 + pop r1 + ret + +; search for the first non-empty entry in the window list +; inputs: +; none +; outputs: +; r0: window list offset, or 0xFFFFFFFF if not found +search_for_nonempty_window_list_entry: + push r1 + push r2 + push r31 + + mov r1, window_list + mov r2, 0 + mov r31, 31 +search_for_nonempty_window_list_entry_loop: + cmp [r1], 0 + ifnz jmp search_for_nonempty_window_list_entry_found + inc r2 + add r1, 4 + loop search_for_nonempty_window_list_entry_loop + ; not found, return 0xFFFFFFFF + mov r0, 0xFFFFFFFF + + pop r31 + pop r2 + pop r1 + ret +search_for_nonempty_window_list_entry_found: + ; found the entry, return its offset + mov r0, r2 + + pop r31 + pop r2 + pop r1 + ret + +; given an overlay number, get the window struct of the window associated with that overlay +; inputs: +; r0: overlay number +; outputs: +; r0: pointer to window struct, or 0x00000000 if not found +get_window_with_overlay: + push r1 + push r2 + push r3 + push r31 + + mov r1, window_list + mov r31, 31 +get_window_with_overlay_loop: + mov r2, [r1] + add r2, 24 + cmp.8 [r2], r0 + ifz jmp get_window_with_overlay_found + add r1, 4 + loop get_window_with_overlay_loop + ; not found, return 0 + mov r0, 0 + + pop r31 + pop r3 + pop r2 + pop r1 + ret +get_window_with_overlay_found: + ; found the entry, return the pointer to its struct + mov r0, [r1] + + pop r31 + pop r3 + pop r2 + pop r1 + ret + +; get a window struct pointer from the window list +; inputs: +; r0: window list offset +; outputs: +; r0: pointer to window struct +window_list_offset_to_struct: + mul r0, 4 + add r0, window_list + mov r0, [r0] + ret + window_title_bar_patterns: ; 1x16 tile data.32 0x00000000 @@ -464,7 +640,9 @@ window_title_bar_patterns: data.32 0xFFFFFFFF data.32 0x00000000 -active_window: data.32 0 +active_window_offset: data.8 0xFF +window_list: data.fill 0, 124 ; 31 window structs * 4 bytes each #include "window/event.asm" #include "window/event_manager_task.asm" + #include "window/overlay.asm"