%include "ponydos.inc" struc window .next resw 1 .width resw 1 .height resw 1 .x resw 1 .y resw 1 .data resw 1 .icon resb 1 .mouse_released_inside resb 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 icon for the disk on the desktop 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], 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 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 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 call request_redraw 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 ; in: ; al = WM_PAINT ; bx = window ID ; out: ; trashes everything 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 ; in: ; al = WM_MOUSE ; bx = window ID ; cl = X ; ch = Y ; dl = mouse buttons held down ; out: ; trashes everything mouse: call get_window mov ax, bx push cx ; 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 add cx, [si + window.x] sub bx, [si + window.y] cmp [si + window.height], bx jle .outside add bx, [si + window.y] cmp byte [si + window.mouse_released_inside], 0 je .not_clicking test dl, MOUSE_PRIMARY | MOUSE_SECONDARY jz .not_clicking .clicking: call click .not_clicking: test dl, MOUSE_PRIMARY | MOUSE_SECONDARY jz .not_primary_held .primary_held: mov byte [si + window.mouse_released_inside], 0 jmp .inside .not_primary_held: mov byte [si + window.mouse_released_inside], 1 .inside: pop cx ; 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 ret .outside: mov byte [si + window.mouse_released_inside], 0 pop cx mov bx, [si + window.next] mov al, WM_MOUSE call forward_event ret ; in: ; ax = window ID ; bx = Y coördinate ; cx = X coördinate ; dl = which buttons are held down ; si = pointer to window structure ; out: ; trashes everything click: cmp byte [si + window.icon], 0 je .file_window .icon: call show_file_window jmp .end .file_window: call raise_window ; 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 .not_close: .end: 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 ; Populate file window contents mov ax, cs mov es, ax 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] call print_ls pop ax mov byte [file_window_visible], 1 call request_redraw .already_visible: ret hide_file_window: mov cx, cs add cx, 0x001 call unhook_window mov byte [file_window_visible], 0 call request_redraw ret ; in: ; al = WM_KEYBOARD ; bx = window ID ; cl = typed character ; cl = typed key ; out: ; trashes everything keyboard: call get_window mov si, [si + window.data] add si, 20 mov [si], cl call request_redraw ret ; 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 ; trashes everything else 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: ; ax = window ID to raise raise_window: push cx push si push es mov cx, PONYDOS_SEG mov es, cx cmp [es:GLOBAL_WINDOW_CHAIN_HEAD], ax je .already_top call get_window mov cx, ax call unhook_window xchg [es:GLOBAL_WINDOW_CHAIN_HEAD], cx mov [si + window.next], cx call request_redraw .already_top: 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" 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 file_window: db 'A', 0x0f, ':', 0x0f times 37 db ' ', 0x0f db 'x', 0x0f times 15*40 db ' ', 0xf0 windows: times window.size db 0 times window.size db 0