ponydos/shell.asm

524 lines
7.2 KiB
NASM

%include "ponydos.inc"
struc window
.next resw 1
.width resw 1
.height resw 1
.x resw 1
.y resw 1
.data resw 1
.size:
endstruc
cpu 8086
bits 16
org 0
; 0x0000
jmp near process_event
; 0x0003
initialize:
push ds
push cs
pop ds
; Set wallpaper
mov si, wallpaper_name
xor dx, dx
call PONYDOS_SEG:SYS_OPEN_FILE
mov bp, PONYDOS_SEG
mov es, bp
mov bx, GLOBAL_WALLPAPER
xor di, di ; read
call PONYDOS_SEG:SYS_MODIFY_SECTORS
; Create window 1
mov ax, cs
add ax, 0x000
xchg [es:GLOBAL_WINDOW_CHAIN_HEAD], ax
mov [windows + 0*window.size + window.next], ax
mov word [windows + 0*window.size + window.width], 16
mov word [windows + 0*window.size + window.height], 4
mov word [windows + 0*window.size + window.x], 10
mov word [windows + 0*window.size + window.y], 3
mov word [windows + 0*window.size + window.data], window_1
; Create window 2
mov ax, cs
add ax, 0x001
xchg [es:GLOBAL_WINDOW_CHAIN_HEAD], ax
mov [windows + 1*window.size + window.next], ax
mov word [windows + 1*window.size + window.width], 40
mov word [windows + 1*window.size + window.height], 4
mov word [windows + 1*window.size + window.x], 14
mov word [windows + 1*window.size + window.y], 6
mov word [windows + 1*window.size + window.data], window_2
call request_redraw
; Temporary testing
mov ax, cs
mov es, ax
mov di, window_1 + 32
mov cx, 3
mov dx, 16
call print_ls
mov di, window_2 + 80
mov cx, 3
mov dx, 40
call print_ls
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
cmp al, WM_PAINT
jne .not_paint
call paint
jmp .end
.not_paint:
cmp al, WM_MOUSE
jne .not_mouse
call mouse
jmp .end
.not_mouse:
cmp al, WM_KEYBOARD
jne .not_keyboard
call keyboard
jmp .end
.not_keyboard:
cmp al, WM_UNHOOK
jne .not_remove
call unhook
.not_remove:
.end:
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
retf
paint:
call get_window
mov bx, [si + window.next]
call forward_event
; 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
ret
mouse:
call get_window
push cx
push bx
; 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
sub bx, [si + window.y]
cmp [si + window.height], bx
jle .outside
pop bx
mov si, [si + window.data]
add si, 18
test dl, MOUSE_PRIMARY
jz .not_clicking
.clicking:
call raise_window
mov al, '*'
xchg byte [si], al
cmp al, '*'
je .end
call request_redraw
jmp .end
.not_clicking:
mov al, ' '
xchg byte [si], al
cmp al, ' '
je .end
call request_redraw
.end:
pop cx
ret
.outside:
pop bx
pop cx
mov bx, [si + window.next]
call forward_event
ret
keyboard:
call get_window
mov si, [si + window.data]
add si, 20
mov [si], cl
call request_redraw
ret
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
; in:
; bx = valid window id for this process
; out:
; si = pointer to window's data block
get_window:
push bx
mov si, cs
sub bx, si
mov si, windows
push ax
push dx
mov ax, window.size
mul bx
add si, ax
pop dx
pop ax
pop bx
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
; 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:
; bx = window ID to raise
raise_window:
push cx
push si
push es
call get_window
mov cx, bx
call unhook_window
mov cx, PONYDOS_SEG
mov es, cx
mov cx, bx
xchg [es:GLOBAL_WINDOW_CHAIN_HEAD], cx
mov [si + window.next], cx
pop es
pop si
pop cx
ret
; in
; cx = height of window (>= 1)
; dx = width of window in characters
; es:di = start of output
print_ls:
push ax
push bx
push cx
push si
push di
push bp
push ds
mov bp, PONYDOS_SEG
mov ds, bp
push cx
push di
mov si, GLOBAL_DIRENTS + 2
xor ax, ax ; Maximum filename size
.name_loop:
cmp word [ds:si - 2], 0
je .done_names
push cx
call strlen
mov bx, cx
pop cx
cmp bx, dx
jle .not_long_filename
mov bx, dx
.not_long_filename:
cmp ax, bx
jge .not_new_max
mov ax, bx
.not_new_max:
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
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
add si, FS_DIRENT_SIZE
cmp si, GLOBAL_DIRENTS + 0x200
jge .done
dec cx
jnz .size_loop
.done:
pop ds
pop bp
pop di
pop si
pop cx
pop bx
pop ax
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:
; bx = window ID
; out:
; ax = return value of event handler; 0 if window ID is 0
forward_event:
push bp
cmp bx, 0
je .id_is_zero
push cs ; Return segment
mov bp, .end
push bp ; Return offset
mov bp, 0xf000
and bp, bx
push bp ; Call segment
xor bp, bp
push bp ; Call offset
retf
.id_is_zero:
; This gets skipped over in normal execution, because it
; explicitly returns to .end
xor ax, ax
.end:
pop bp
ret
wallpaper_name db 'ponydos.wall', 0
%include "debug.inc"
window_1:
db 'W', 0x0f, 'i', 0x0f, 'n', 0x0f, 'd', 0x0f, 'o', 0x0f, 'w', 0x0f, ' ', 0x0f, '1', 0x0f
times 8 db ' ', 0x0f
times 16 db ' ', 0xf0
times 16 db ' ', 0xf0
times 16 db ' ', 0xf0
window_2:
db 'W', 0x0f, 'i', 0x0f, 'n', 0x0f, 'd', 0x0f, 'o', 0x0f, 'w', 0x0f, ' ', 0x0f, '2', 0x0f
times 32 db ' ', 0x0f
times 40 db ' ', 0xf0
times 40 db ' ', 0xf0
times 40 db ' ', 0xf0
windows:
times window.size db 0
times window.size db 0