ponydos/shell.asm

808 lines
12 KiB
NASM
Raw Normal View History

2023-03-18 13:55:53 +00:00
%include "ponydos.inc"
2023-03-20 18:18:49 +00:00
struc window
.next resw 1
.width resw 1
.height resw 1
.x resw 1
.y resw 1
.data resw 1
2023-03-22 18:41:02 +00:00
.icon resb 1
.mouse_released_inside resb 1
2023-03-20 18:18:49 +00:00
.size:
endstruc
2023-03-18 13:55:53 +00:00
cpu 8086
bits 16
2023-03-17 23:05:32 +00:00
org 0
2023-03-18 13:55:53 +00:00
; 0x0000
jmp near process_event
2023-03-18 13:55:53 +00:00
; 0x0003
initialize:
push ds
2023-03-19 18:50:24 +00:00
push cs
2023-03-18 13:55:53 +00:00
pop ds
; Has shell been started already?
mov bp, PONYDOS_SEG
mov es, bp
cmp word [es:GLOBAL_WINDOW_CHAIN_HEAD], 0
je .not_relaunch
.relaunch:
; TODO: Display an alert if trying to re-run shell
; Clean up memory when exiting
mov bx, cs
mov cl, 12
shr bx, cl
mov byte [es:GLOBAL_MEMORY_ALLOCATION_MAP + bx], 0
jmp .end
.not_relaunch:
2023-03-18 13:55:53 +00:00
; Set wallpaper
2023-03-22 22:54:35 +00:00
call set_wallpaper
2023-03-18 13:55:53 +00:00
2023-03-22 18:41:02 +00:00
; Create icon for the disk on the desktop
2023-03-19 18:50:24 +00:00
mov ax, cs
2023-03-20 18:18:49 +00:00
add ax, 0x000
2023-03-19 18:50:24 +00:00
xchg [es:GLOBAL_WINDOW_CHAIN_HEAD], ax
2023-03-20 18:18:49 +00:00
mov [windows + 0*window.size + window.next], ax
2023-03-22 18:41:02 +00:00
mov word [windows + 0*window.size + window.width], 5
mov word [windows + 0*window.size + window.height], 3
mov word [windows + 0*window.size + window.x], 1
mov word [windows + 0*window.size + window.y], 1
mov word [windows + 0*window.size + window.data], disk_icon
mov byte [windows + 0*window.size + window.icon], 1
mov byte [windows + 0*window.size + window.mouse_released_inside], 0
; Initialize file window but don't show it
2023-03-20 18:18:49 +00:00
mov word [windows + 1*window.size + window.width], 40
mov word [windows + 1*window.size + window.height], 16
mov word [windows + 1*window.size + window.x], 10
mov word [windows + 1*window.size + window.y], 4
2023-03-22 18:41:02 +00:00
mov word [windows + 1*window.size + window.data], file_window
mov byte [windows + 1*window.size + window.icon], 0
mov byte [windows + 1*window.size + window.mouse_released_inside], 0
2023-03-19 18:50:24 +00:00
2023-03-20 18:18:49 +00:00
call request_redraw
2023-03-20 16:17:45 +00:00
.end:
pop ds
retf
process_event:
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
mov bp, cs
mov ds, bp
mov es, bp
2023-03-20 18:46:29 +00:00
cmp al, WM_PAINT
jne .not_paint
call paint
2023-03-20 18:53:13 +00:00
jmp .end
.not_paint:
2023-03-20 18:46:29 +00:00
cmp al, WM_MOUSE
2023-03-20 18:18:49 +00:00
jne .not_mouse
call mouse
2023-03-20 18:53:13 +00:00
jmp .end
2023-03-20 18:18:49 +00:00
.not_mouse:
2023-03-20 18:53:13 +00:00
cmp al, WM_KEYBOARD
jne .not_keyboard
call keyboard
2023-03-20 19:42:59 +00:00
jmp .end
.not_keyboard:
cmp al, WM_UNHOOK
jne .not_remove
call unhook
.not_remove:
2023-03-20 18:53:13 +00:00
.end:
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
retf
2023-03-19 18:50:24 +00:00
2023-03-22 18:41:02 +00:00
; in:
; al = WM_PAINT
; bx = window ID
; out:
; clobbers everything
2023-03-19 18:50:24 +00:00
paint:
2023-03-20 18:18:49 +00:00
call get_window
2023-03-19 18:50:24 +00:00
2023-03-20 18:18:49 +00:00
mov bx, [si + window.next]
call forward_event
2023-03-19 18:50:24 +00:00
2023-03-20 18:18:49 +00:00
; Draw a rectangle on-screen
mov bx, [si + window.width]
mov cx, bx
mov dx, [si + window.height]
mov di, [si + window.x]
mov bp, [si + window.y]
mov si, [si + window.data]
call PONYDOS_SEG:SYS_DRAW_RECT
2023-03-19 18:50:24 +00:00
2023-03-20 18:18:49 +00:00
ret
2023-03-19 18:50:24 +00:00
2023-03-22 18:41:02 +00:00
; in:
; al = WM_MOUSE
; bx = window ID
; cl = X
; ch = Y
; dl = mouse buttons held down
; out:
; clobbers everything
2023-03-20 18:18:49 +00:00
mouse:
call get_window
2023-03-19 14:23:30 +00:00
2023-03-22 18:41:02 +00:00
mov ax, bx
2023-03-19 18:50:24 +00:00
2023-03-22 18:41:02 +00:00
push cx
2023-03-20 19:42:59 +00:00
2023-03-20 18:18:49 +00:00
; Y
xor bx, bx
mov bl, ch
; X
xor ch, ch
cmp cx, [si + window.x]
jl .outside
cmp bx, [si + window.y]
jl .outside
sub cx, [si + window.x]
cmp [si + window.width], cx
jle .outside
2023-03-22 18:54:57 +00:00
add cx, [si + window.x]
2023-03-20 18:18:49 +00:00
sub bx, [si + window.y]
cmp [si + window.height], bx
jle .outside
2023-03-22 18:54:57 +00:00
add bx, [si + window.y]
2023-03-20 18:18:49 +00:00
2023-03-22 18:41:02 +00:00
cmp byte [si + window.mouse_released_inside], 0
je .not_clicking
test dl, MOUSE_PRIMARY | MOUSE_SECONDARY
2023-03-20 18:18:49 +00:00
jz .not_clicking
.clicking:
2023-03-22 18:41:02 +00:00
call click
2023-03-20 18:18:49 +00:00
.not_clicking:
2023-03-22 18:41:02 +00:00
test dl, MOUSE_PRIMARY | MOUSE_SECONDARY
jz .not_buttons_held
.buttons_held:
2023-03-22 18:41:02 +00:00
mov byte [si + window.mouse_released_inside], 0
jmp .inside
.not_buttons_held:
2023-03-22 18:41:02 +00:00
mov byte [si + window.mouse_released_inside], 1
.inside:
2023-03-20 18:18:49 +00:00
pop cx
2023-03-22 18:41:02 +00:00
; Use coördinates (255,255) to make sure other windows in
; the chain don't think the cursor is inside them
mov cx, 0xffff
mov bx, [si + window.next]
mov al, WM_MOUSE
call forward_event
2023-03-19 18:50:24 +00:00
ret
2023-03-20 18:18:49 +00:00
.outside:
2023-03-22 18:41:02 +00:00
mov byte [si + window.mouse_released_inside], 0
2023-03-20 18:18:49 +00:00
pop cx
mov bx, [si + window.next]
2023-03-22 18:41:02 +00:00
mov al, WM_MOUSE
2023-03-19 18:50:24 +00:00
call forward_event
2023-03-20 18:18:49 +00:00
ret
2023-03-19 18:50:24 +00:00
2023-03-22 18:41:02 +00:00
; in:
; ax = window ID
2023-03-22 18:54:57 +00:00
; bx = Y coördinate
; cx = X coördinate
2023-03-22 18:41:02 +00:00
; dl = which buttons are held down
; si = pointer to window structure
; out:
; dl = which buttons are held down
; si = pointer to window structure
; clobbers everything else
2023-03-22 18:41:02 +00:00
click:
push dx
push si
2023-03-22 18:41:02 +00:00
cmp byte [si + window.icon], 0
je .file_window
.icon:
call show_file_window
jmp .end
.file_window:
call raise_window
2023-03-22 18:54:57 +00:00
; If clicked the window close button
cmp bx, [si + window.y]
jne .not_close
mov ax, [si + window.x]
add ax, [si + window.width]
dec ax
cmp ax, cx
jne .not_close
.close:
call hide_file_window
jmp .end
2023-03-22 18:54:57 +00:00
.not_close:
; If clicked within the content area
mov ax, bx
sub ax, [si + window.y]
jz .end
; Find the start of the line user clicked on
mov bx, [si + window.width]
shl bx, 1
mul bx
mov si, [si + window.data]
add si, ax
; Zero out launch_filename
mov di, launch_filename
mov cx, FS_DIRENT_NAME_SIZE
xor al, al
rep stosb
; Copy file name to launch_filename
mov di, launch_filename
.copy_filename_loop:
lodsw
test al, al
jz .copy_filename_loop_end
stosb
jmp .copy_filename_loop
.copy_filename_loop_end:
call launch
2023-03-22 18:41:02 +00:00
.end:
pop si
pop dx
2023-03-22 18:41:02 +00:00
ret
show_file_window:
cmp byte [file_window_visible], 0
jne .already_visible
push ax
mov ax, PONYDOS_SEG
mov es, ax
mov ax, cs
add ax, 0x001
xchg [es:GLOBAL_WINDOW_CHAIN_HEAD], ax
mov [windows + 1*window.size + window.next], ax
2023-03-22 18:57:19 +00:00
; Populate file window contents
2023-03-22 19:17:02 +00:00
mov ax, cs
2023-03-22 18:57:19 +00:00
mov es, ax
2023-03-22 19:17:02 +00:00
mov di, file_window
add di, [windows + 1*window.size + window.width]
add di, [windows + 1*window.size + window.width]
mov cx, [windows + 1*window.size + window.height]
dec cx
mov dx, [windows + 1*window.size + window.width]
2023-03-22 18:57:19 +00:00
call print_ls
2023-03-22 18:41:02 +00:00
pop ax
mov byte [file_window_visible], 1
call request_redraw
.already_visible:
ret
2023-03-22 18:54:57 +00:00
hide_file_window:
mov cx, cs
add cx, 0x001
call unhook_window
mov byte [file_window_visible], 0
call request_redraw
ret
; out:
; clobbers everything
launch:
mov si, launch_filename
2023-03-22 22:54:35 +00:00
; Is it a .wall file?
call strlen
2023-03-22 22:54:35 +00:00
cmp cx, 5
jb .not_wall
add si, cx
sub si, 5
mov di, wall_extension
call strcmp
jne .not_wall
mov ax, cs
mov es, ax
mov si, launch_filename
mov di, wallpaper_name
mov cx, FS_DIRENT_NAME_SIZE
rep movsb
call set_wallpaper
call request_redraw
jmp .end
.not_wall:
; Is it a .bin file?
cmp cx, 4
jb .end ; No, too short
2023-03-22 22:54:35 +00:00
mov si, launch_filename
add si, cx
sub si, 4
mov di, bin_extension
call strcmp
jne .end ; No, wrong extension
mov si, launch_filename
mov dx, 1 ; Don't create a new file if not found
call PONYDOS_SEG:SYS_OPEN_FILE
test ax, ax
; TODO: Display an alert on file not being found
jz .end
push ax
push cx
; Allocate a segment
mov ax, PONYDOS_SEG
mov es, ax
mov si, GLOBAL_MEMORY_ALLOCATION_MAP
mov cx, MEM_ALLOCATION_MAP_SIZE
.find_free_segment:
mov al, [es:si]
test al, al
jz .found_free_segment
inc si
loop .find_free_segment
; TODO: Display an alert on OOM error
pop cx
pop ax
jmp .end
.found_free_segment:
mov byte [es:si], 1 ; Mark as used
; Set up es to point to the allocated segment
sub si, GLOBAL_MEMORY_ALLOCATION_MAP
mov cl, 12
shl si, cl
mov es, si
pop cx
pop ax
xor bx, bx ; Load at the start of the segment
xor di, di ; Read
call PONYDOS_SEG:SYS_MODIFY_SECTORS
; Transfer control to the newly loaded binary
push cs ; Return segment
mov ax, .end
push ax ; Return offset
push es ; Call segment
mov ax, PROC_INITIALIZE_ENTRYPOINT
push ax ; Call offset
retf
.end:
ret
2023-03-22 22:54:35 +00:00
; out:
; clobbers everything
set_wallpaper:
mov ax, PONYDOS_SEG
mov es, ax
mov si, wallpaper_name
xor dx, dx
call PONYDOS_SEG:SYS_OPEN_FILE
mov bx, GLOBAL_WALLPAPER
xor di, di ; read
call PONYDOS_SEG:SYS_MODIFY_SECTORS
ret
2023-03-22 18:41:02 +00:00
; in:
; al = WM_KEYBOARD
; bx = window ID
; cl = typed character
; cl = typed key
; out:
; clobbers everything
2023-03-20 18:53:13 +00:00
keyboard:
call get_window
mov si, [si + window.data]
add si, 20
mov [si], cl
call request_redraw
ret
2023-03-22 18:41:02 +00:00
; in:
; al = WM_UNHOOK
; bx = window ID
; cx = window to unhook
; out:
; ax = own ID if not the window to unhook
; next ID if the window to unhook
; clobbers everything else
2023-03-20 19:42:59 +00:00
unhook:
call get_window
cmp bx, cx
je .match
push bx
; Forward the event
mov bx, [si + window.next]
call forward_event
; Update next ID
; If window.next was zero, forward_event will also return zero so
; this is safe in all cases
mov [si + window.next], ax
; Return own ID to keep self in the chain
pop ax
ret
.match:
; Return next ID in the chain to unhook
mov ax, [si + window.next]
ret
2023-03-20 18:18:49 +00:00
; in:
; bx = valid window id for this process
; out:
; si = pointer to window's data block
get_window:
2023-03-20 19:42:59 +00:00
push bx
2023-03-20 18:18:49 +00:00
mov si, cs
sub bx, si
2023-03-19 18:50:24 +00:00
2023-03-20 18:18:49 +00:00
mov si, windows
2023-03-19 18:50:24 +00:00
2023-03-20 18:18:49 +00:00
push ax
push dx
mov ax, window.size
mul bx
add si, ax
pop dx
pop ax
2023-03-20 19:42:59 +00:00
pop bx
2023-03-20 18:18:49 +00:00
ret
request_redraw:
push es
push bp
mov bp, PONYDOS_SEG
mov es, bp
mov byte [es:GLOBAL_REDRAW], 1
pop bp
pop es
ret
2023-03-19 18:50:24 +00:00
2023-03-20 19:42:59 +00:00
; in:
; cx = window ID to unhook
unhook_window:
push ax
push bx
push es
mov bx, PONYDOS_SEG
mov es, bx
mov bx, [es:GLOBAL_WINDOW_CHAIN_HEAD]
mov al, WM_UNHOOK
call forward_event
mov [es:GLOBAL_WINDOW_CHAIN_HEAD], ax
pop es
pop bx
pop ax
ret
; in:
2023-03-22 18:41:02 +00:00
; ax = window ID to raise
2023-03-20 19:42:59 +00:00
raise_window:
push cx
push si
push es
2023-03-22 18:41:02 +00:00
mov cx, PONYDOS_SEG
mov es, cx
cmp [es:GLOBAL_WINDOW_CHAIN_HEAD], ax
je .already_top
2023-03-20 19:42:59 +00:00
call get_window
2023-03-22 18:41:02 +00:00
mov cx, ax
2023-03-20 19:42:59 +00:00
call unhook_window
xchg [es:GLOBAL_WINDOW_CHAIN_HEAD], cx
mov [si + window.next], cx
2023-03-22 18:41:02 +00:00
call request_redraw
.already_top:
2023-03-20 19:42:59 +00:00
pop es
pop si
pop cx
ret
2023-03-20 09:00:57 +00:00
; in
; cx = height of window (>= 1)
; dx = width of window in characters
; es:di = start of output
print_ls:
2023-03-20 10:41:46 +00:00
push ax
2023-03-20 09:00:57 +00:00
push bx
push cx
push si
push di
push bp
push ds
mov bp, PONYDOS_SEG
mov ds, bp
2023-03-20 10:41:46 +00:00
push cx
push di
2023-03-20 09:00:57 +00:00
mov si, GLOBAL_DIRENTS + 2
2023-03-20 10:41:46 +00:00
xor ax, ax ; Maximum filename size
.name_loop:
2023-03-20 09:00:57 +00:00
cmp word [ds:si - 2], 0
2023-03-20 10:41:46 +00:00
je .done_names
2023-03-20 09:00:57 +00:00
push cx
call strlen
mov bx, cx
pop cx
cmp bx, dx
jle .not_long_filename
mov bx, dx
.not_long_filename:
2023-03-20 10:41:46 +00:00
cmp ax, bx
jge .not_new_max
mov ax, bx
.not_new_max:
2023-03-20 09:00:57 +00:00
push si
push di
.copy:
movsb
inc di ; Formatting
dec bx
jnz .copy
pop di
pop si
; Move to next line
add di, dx
add di, dx
2023-03-20 10:41:46 +00:00
add si, FS_DIRENT_SIZE
cmp si, GLOBAL_DIRENTS + 0x200
jge .done_names
dec cx
jnz .name_loop
.done_names:
pop di
pop cx
; Don't print sizes for too short a window
cmp dx, 10
jle .done
add ax, 5 ; 1 whitespace, 4 length
cmp ax, dx
jle .not_truncate
mov ax, dx
.not_truncate:
sub ax, 5 ; Go to start of where to put the file length
add di, ax
add di, ax
mov si, GLOBAL_DIRENTS
.size_loop:
mov ax, word [ds:si]
test ax, ax
jz .done
mov byte [es:di + 8], 'K'
shr ax, 1
aam ; mango
add ax, 0x3030
cmp ah, 0x30
je .one_digit
mov byte [es:di + 2], ' '
mov [es:di + 4], ah
jmp .one_digit_print
.one_digit:
test word [ds:si], 1
jnz .one_and_half_digit
mov byte [es:di + 4], ' '
.one_digit_print:
mov [es:di + 6], al
jmp .next_iter_size_loop
.one_and_half_digit:
mov byte [es:di], ' '
mov byte [es:di + 2], al
mov byte [es:di + 4], '.'
mov byte [es:di + 6], '5'
.next_iter_size_loop:
; Move to next line
add di, dx
add di, dx
2023-03-20 09:00:57 +00:00
add si, FS_DIRENT_SIZE
cmp si, GLOBAL_DIRENTS + 0x200
jge .done
dec cx
2023-03-20 10:41:46 +00:00
jnz .size_loop
2023-03-20 09:00:57 +00:00
.done:
pop ds
pop bp
pop di
pop si
pop cx
pop bx
2023-03-20 10:41:46 +00:00
pop ax
2023-03-20 09:00:57 +00:00
ret
; in:
; ds:si = string
; out:
; cx = stlen
strlen:
push ax
push di
push es
mov cx, ds
mov es, cx
mov di, si
mov cx, -1
xor ax, ax
repne scasb
not cx
dec cx
pop es
pop di
pop ax
ret
; in:
; ds:si = string1
; ds:di = string2
; out:
; zf(ef) = strings are equal
strcmp:
push si
push di
.loop:
lodsb
cmp [di], al
jne .end
test al, al
jz .end
inc di
jmp .loop
.end:
pop di
pop si
ret
2023-03-19 18:50:24 +00:00
; in:
; bx = window ID
; out:
2023-03-20 19:42:59 +00:00
; ax = return value of event handler; 0 if window ID is 0
2023-03-19 18:50:24 +00:00
forward_event:
2023-03-20 19:42:59 +00:00
push bp
2023-03-19 18:50:24 +00:00
cmp bx, 0
2023-03-20 19:42:59 +00:00
je .id_is_zero
2023-03-19 18:50:24 +00:00
push cs ; Return segment
2023-03-20 18:18:49 +00:00
mov bp, .end
push bp ; Return offset
mov bp, 0xf000
and bp, bx
push bp ; Call segment
xor bp, bp
push bp ; Call offset
2023-03-19 18:50:24 +00:00
retf
2023-03-20 19:42:59 +00:00
.id_is_zero:
; This gets skipped over in normal execution, because it
; explicitly returns to .end
xor ax, ax
2023-03-19 18:50:24 +00:00
.end:
2023-03-20 19:42:59 +00:00
pop bp
2023-03-18 13:55:53 +00:00
ret
2023-03-22 22:54:35 +00:00
wallpaper_name db 'ponydos.wall'
times FS_DIRENT_NAME_SIZE-12 db 0
2023-03-19 14:23:30 +00:00
bin_extension db '.bin', 0
2023-03-22 22:54:35 +00:00
wall_extension db '.wall', 0
2023-03-19 14:23:30 +00:00
%include "debug.inc"
2023-03-22 18:41:02 +00:00
file_window_visible db 0
disk_icon:
db 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f
db 0x00, 0x0f, 0x00, 0x0f, 0x09, 0x0f, 0x00, 0x0f, 0x00, 0x0f
db 0x00, 0x0f, 0x00, 0x0f, '|', 0x0f, 0x00, 0x0f, 0x00, 0x0f
2023-03-20 09:00:57 +00:00
2023-03-22 18:41:02 +00:00
file_window:
db 'A', 0x0f, ':', 0x0f
2023-03-22 18:54:57 +00:00
times 37 db ' ', 0x0f
db 'x', 0x0f
times 15*40 db 0, 0xf0
2023-03-20 18:18:49 +00:00
windows:
times window.size db 0
times window.size db 0
launch_filename times FS_DIRENT_NAME_SIZE db 0