%include "ponydos.inc" cpu 8086 bits 16 %ifdef BLINKY TITLEBAR_ATTRIBUTE equ 0x07 WINDOW_ATTRIBUTE equ 0x70 DISK_ATTRIBUTE equ 0x07 %else TITLEBAR_ATTRIBUTE equ 0x0f WINDOW_ATTRIBUTE equ 0xf0 DISK_ATTRIBUTE equ 0x0f %endif struc window .next resw 1 .width resw 1 .height resw 1 .x resw 1 .y resw 1 .data resw 1 .icon resb 1 .visible resb 1 .resizable resb 1 .mouse_released_inside resb 1 .status resb 1 .res_x resw 1 .res_y resw 1 .size: endstruc WINDOW_ID_ICON equ 0 WINDOW_ID_FILE_WINDOW equ 1 WINDOW_ID_OOM_ERROR equ 2 WINDOW_ID_LAUNCH_ERROR equ 3 WINDOW_MOVE equ 1 WINDOW_RESIZE equ 2 WINDOW_MIN_WIDTH equ 5 WINDOW_MIN_HEIGHT equ 2 cpu 8086 bits 16 org 0 ; 0x0000 jmp near process_event ; 0x0003 ; out: ; clobbers everything but ds initialize: push ds push cs pop ds ; Has shell been started already? mov bp, PONYDOS_SEG mov es, bp xor bp, bp cmp word [es:GLOBAL_WINDOW_CHAIN_HEAD], 0 je .not_relaunch mov bp, 1 jmp .skip_desktop .not_relaunch: ; Set wallpaper call set_wallpaper ; Create icon for the disk on the desktop mov word [windows + WINDOW_ID_ICON*window.size + window.width], 5 mov word [windows + WINDOW_ID_ICON*window.size + window.height], 3 mov word [windows + WINDOW_ID_ICON*window.size + window.x], 1 mov word [windows + WINDOW_ID_ICON*window.size + window.y], 1 mov word [windows + WINDOW_ID_ICON*window.size + window.data], disk_icon mov byte [windows + WINDOW_ID_ICON*window.size + window.icon], 1 mov ax, cs add ax, WINDOW_ID_ICON mov si, windows + WINDOW_ID_ICON*window.size call show_window .skip_desktop: ; Initialize file window but don't show it mov word [windows + WINDOW_ID_FILE_WINDOW*window.size + window.width], 40 mov word [windows + WINDOW_ID_FILE_WINDOW*window.size + window.height], 17 mov word [windows + WINDOW_ID_FILE_WINDOW*window.size + window.x], 10 mov word [windows + WINDOW_ID_FILE_WINDOW*window.size + window.y], 4 mov word [windows + WINDOW_ID_FILE_WINDOW*window.size + window.data], file_window mov byte [windows + WINDOW_ID_FILE_WINDOW*window.size + window.resizable], 1 test bp, bp jz .no_file_window_on_start .file_window_on_start: ; Offset the window so that it's clearly another window mov word [windows + WINDOW_ID_FILE_WINDOW*window.size + window.x], 7 mov word [windows + WINDOW_ID_FILE_WINDOW*window.size + window.y], 3 mov ax, cs add ax, WINDOW_ID_FILE_WINDOW mov si, windows + WINDOW_ID_FILE_WINDOW*window.size call show_window .no_file_window_on_start: ; Initialize error dialogs mov word [windows + WINDOW_ID_OOM_ERROR*window.size + window.width], 13 mov word [windows + WINDOW_ID_OOM_ERROR*window.size + window.height], 2 mov word [windows + WINDOW_ID_OOM_ERROR*window.size + window.x], 30 mov word [windows + WINDOW_ID_OOM_ERROR*window.size + window.y], 10 mov word [windows + WINDOW_ID_OOM_ERROR*window.size + window.data], oom_error_dialog mov word [windows + WINDOW_ID_LAUNCH_ERROR*window.size + window.width], FS_DIRENT_NAME_SIZE-1 ; Size includes null terminator mov word [windows + WINDOW_ID_LAUNCH_ERROR*window.size + window.height], 3 mov word [windows + WINDOW_ID_LAUNCH_ERROR*window.size + window.x], 24 mov word [windows + WINDOW_ID_LAUNCH_ERROR*window.size + window.y], 11 mov word [windows + WINDOW_ID_LAUNCH_ERROR*window.size + window.data], launch_error_dialog call request_redraw .end: pop ds retf ; in: ; al = event ; bx = window ID ; cx, dx = event specific ; out: ; ax = event specific 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 jmp .end .not_remove: ; We ignore WM_OPEN_FILE .end: cmp byte [open_windows], 0 jne .windows_open call deallocate_own_memory .windows_open: pop es pop ds pop bp pop di pop si pop dx pop cx pop bx retf ; ------------------------------------------------------------------ ; Event handlers ; ------------------------------------------------------------------ ; in: ; al = WM_PAINT ; bx = window ID ; out: ; clobbers everything paint: call get_window mov bx, [si + window.next] call send_event cmp si, windows + WINDOW_ID_FILE_WINDOW*window.size jne .not_file_window .file_window: ; See if the dirents have changed since we rendered the ; window contents. If yes, rerender. push si mov bp, PONYDOS_SEG mov es, bp mov si, dirents mov di, GLOBAL_DIRENTS mov cx, FS_DIRENT_SIZE*FS_DIRECTORY_DIRENTS repe cmpsb pop si je .no_rerender call render_file_window .no_rerender: .not_file_window: ; Draw a rectangle on-screen mov bx, [si + window.width] mov dx, [si + window.height] mov di, [si + window.x] mov bp, [si + window.y] mov si, [si + window.data] add dx, bp cmp dx, ROWS jle .no_clipping_height mov dx, ROWS .no_clipping_height: sub dx, bp mov cx, bx add cx, di cmp cx, COLUMNS jle .no_clipping_width_right mov cx, COLUMNS .no_clipping_width_right: sub cx, di cmp di, 0 jge .no_clipping_width_left sub si, di sub si, di add cx, di xor di, di .no_clipping_width_left: call PONYDOS_SEG:SYS_DRAW_RECT ret ; in: ; al = WM_MOUSE ; bx = window ID ; cl = X ; ch = Y ; dl = mouse buttons held down ; out: ; clobbers everything mouse: call get_window test dl, MOUSE_PRIMARY | MOUSE_SECONDARY jnz .any_buttons_held mov byte [si + window.status], 0 .any_buttons_held: mov ax, bx push cx ; Y xor bx, bx mov bl, ch ; X xor ch, ch cmp byte [si + window.status], WINDOW_MOVE jne .not_move call move .not_move: cmp byte [si + window.status], WINDOW_RESIZE jne .not_resize call resize .not_resize: cmp cx, [si + window.x] jl .outside ; x < window_x cmp bx, [si + window.y] jl .outside ; y < window_y mov bp, [si + window.x] add bp, [si + window.width] cmp bp, cx jle .outside ; window_x + window_width <= x mov bp, [si + window.y] add bp, [si + window.height] cmp bp, bx jle .outside ; window_y + window_height <= 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_buttons_held .buttons_held: mov byte [si + window.mouse_released_inside], 0 jmp .inside .not_buttons_held: mov byte [si + window.mouse_released_inside], 1 .inside: pop cx xor dx, dx ; 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 send_event ret .outside: mov byte [si + window.mouse_released_inside], 0 pop cx mov bx, [si + window.next] mov al, WM_MOUSE call send_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: ; dl = which buttons are held down ; si = pointer to window structure ; clobbers everything else click: push dx push si cmp byte [si + window.icon], 0 je .file_window .icon: mov ax, cs add ax, WINDOW_ID_FILE_WINDOW mov si, windows + WINDOW_ID_FILE_WINDOW*window.size call show_window call render_file_window jmp .end .file_window: call raise_window ; Save window ID mov bp, ax cmp bx, [si + window.y] jne .not_title_bar ; Resize button mov ax, [si + window.x] cmp byte [si + window.resizable], 0 je .not_resizable cmp ax, cx je .resize .not_resizable: ; Window close button add ax, [si + window.width] dec ax cmp ax, cx je .close .move: mov byte [si + window.status], WINDOW_MOVE sub cx, [si + window.x] mov [si + window.res_x], cx ; In-window x-coordinate of press jmp .end .resize: mov byte [si + window.status], WINDOW_RESIZE add cx, [si + window.width] mov [si + window.res_x], cx ; Lower right corner + 1 add bx, [si + window.height] mov [si + window.res_y], bx ; Lower right corner + 1 jmp .end .close: call hide_window jmp .end .not_title_bar: ; If clicked within the content area mov ax, bx sub ax, [si + window.y] jz .end dec ax cmp ax, FS_DIRECTORY_DIRENTS jae .end mov bp, FS_DIRENT_SIZE mul bp mov si, dirents add si, ax cmp word [si], 0 je .end ; Copy file name to launch_filename add si, FS_DIRENT_NAME_OFFSET mov di, launch_filename mov cx, FS_DIRENT_NAME_SIZE rep movsb call launch .end: pop si pop dx ret ; in: ; al = WM_KEYBOARD ; bx = window ID ; cl = typed character ; cl = typed key ; out: ; clobbers everything keyboard: 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 ; clobbers everything else unhook: call get_window cmp bx, cx je .match push bx ; Forward the event mov bx, [si + window.next] call send_event ; Update next ID ; If window.next was zero, send_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 ; ------------------------------------------------------------------ ; Event handler subroutines ; ------------------------------------------------------------------ ; in: ; ax = window ID ; bx = Y coördinate ; cx = X coördinate ; si = pointer to window structure resize: push dx push bp xor bp, bp ; Change? mov dx, [si + window.res_y] sub dx, bx jc .end_y cmp dx, WINDOW_MIN_HEIGHT jl .end_y cmp dx, ROWS jg .end_y cmp [si + window.y], bx je .end_y inc bp mov [si + window.y], bx mov [si + window.height], dx .end_y: mov dx, [si + window.res_x] sub dx, cx jc .end_x cmp dx, WINDOW_MIN_WIDTH jl .end_x cmp dx, COLUMNS jg .end_x cmp [si + window.x], cx je .end_x inc bp mov [si + window.x], cx mov [si + window.width], dx .end_x: test bp, bp jz .end call render_file_window call request_redraw .end: pop bp pop dx ret ; in: ; ax = window ID ; bx = Y coördinate ; cx = X coördinate ; si = pointer to window structure move: push dx mov dx, cx sub dx, [si + window.res_x] cmp [si + window.y], bx jne .change cmp [si + window.x], dx jne .change jmp .end .change: mov [si + window.y], bx mov [si + window.x], dx call request_redraw .end: pop dx ret ; ------------------------------------------------------------------ ; Launching ; ------------------------------------------------------------------ ; out: ; clobbers everything launch: mov si, launch_filename ; 4 letter file extension? call strlen cmp cx, 5 jb .less_than_5_chars add si, cx sub si, 5 ; .text mov di, text_extension call strcmp je .text_file ; .wall mov di, wall_extension call strcmp je .wallpaper .less_than_5_chars: ; 3 letter file extension? cmp cx, 4 jb .not_launchable ; No, too short mov si, launch_filename add si, cx sub si, 4 ; .asm mov di, asm_extension call strcmp je .text_file ; .txt mov di, txt_extension call strcmp je .text_file ; .bin mov di, bin_extension call strcmp jne .not_launchable ; No extension matched mov si, launch_filename call launch_binary ret .wallpaper: 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 ret .not_launchable: ; Copy filename into the launch error dialog mov si, launch_filename call show_launch_error ret .text_file: ; Launch viewer.bin if it exists mov si, viewer_file_name call launch_binary jc .viewer_not_found ; Send the WM_OPEN_FILE event to tell viewer the file we ; want it to open. launch_binary returned its segment in bx ; so we can just pass that to send_event, as window IDs are ; of the form segment | internal_id. mov al, WM_OPEN_FILE mov cx, launch_filename call send_event .viewer_not_found: ret ; in: ; si = name of file not launchable ; out: ; clobbers everything show_launch_error: mov di, launch_error_dialog.filename mov cx, FS_DIRENT_NAME_SIZE-1 mov ah, WINDOW_ATTRIBUTE .copy: lodsb test al, al je .copy_end stosw loop .copy .copy_end: ; Zero out the rest xor al, al rep stosw ; Show dialog mov ax, cs add ax, WINDOW_ID_LAUNCH_ERROR mov si, windows + WINDOW_ID_LAUNCH_ERROR*window.size call show_window ret ; in: ; si = name of the binary to launch ; out: ; cf = error occured when launching binary ; bx = segment of the launched binary ; clobbers everything else launch_binary: mov dx, 1 ; Don't create a new file if not found call PONYDOS_SEG:SYS_OPEN_FILE test ax, ax jz .file_not_found 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 jmp .out_of_memory .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 push es ; Save the segment for return value ; Transfer control to the newly loaded binary push cs ; Return segment mov ax, .success push ax ; Return offset push es ; Call segment mov ax, PROC_INITIALIZE_ENTRYPOINT push ax ; Call offset retf .success: pop bx clc ret .file_not_found: call show_launch_error jmp .error .out_of_memory: ; Display an error dialog if we can't allocate a segment mov ax, cs add ax, WINDOW_ID_OOM_ERROR mov si, windows + WINDOW_ID_OOM_ERROR*window.size call show_window pop cx pop ax .error: stc ret ; 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 ; ------------------------------------------------------------------ ; Windows ; ------------------------------------------------------------------ ; in: ; bx = window ID ; out: ; ax = return value of event handler; 0 if window ID is 0 send_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 ; in: ; bx = valid window id for this process ; out: ; si = pointer to window structure 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 ; in: ; ax = window ID ; si = pointer to window structure show_window: push ax cmp byte [si + window.visible], 0 je .not_yet_visible call raise_window jmp .end .not_yet_visible: call hook_window mov [si + window.next], ax mov byte [si + window.visible], 1 call request_redraw inc byte [open_windows] .end: pop ax ret ; in: ; bp = window ID ; si = pointer to window structure hide_window: push cx mov cx, bp call unhook_window mov byte [si + window.visible], 0 call request_redraw dec byte [open_windows] pop cx ret ; in: ; ax = window ID to hook ; out: ; ax = next window ID hook_window: push bp push es mov bp, PONYDOS_SEG mov es, bp xchg [es:GLOBAL_WINDOW_CHAIN_HEAD], ax pop es pop bp 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 send_event mov [es:GLOBAL_WINDOW_CHAIN_HEAD], ax pop es pop bx pop ax ret ; in: ; ax = window ID to raise raise_window: push ax push bx push cx push si push es mov cx, PONYDOS_SEG mov es, cx cmp [es:GLOBAL_WINDOW_CHAIN_HEAD], ax je .already_top mov bx, ax call get_window mov cx, ax call unhook_window call hook_window mov [si + window.next], ax call request_redraw .already_top: pop es pop si pop cx pop bx pop ax ret ; ------------------------------------------------------------------ ; Painting ; ------------------------------------------------------------------ ; in ; si = pointer to window structure render_file_window: call copy_dirents push ax push cx push dx push di push es mov ax, cs mov es, ax mov di, [si + window.data] mov cx, [si + window.width] mov ax, TITLEBAR_ATTRIBUTE<<8 rep stosw mov cx, (ROWS-1)*COLUMNS mov ax, WINDOW_ATTRIBUTE<<8 rep stosw mov di, [si + window.data] mov byte [di], 0x17 mov byte [di + 2], 'A' mov byte [di + 4], ':' add di, [si + window.width] add di, [si + window.width] mov byte [di - 2], 'x' mov cx, [si + window.height] dec cx mov dx, [si + window.width] call print_ls pop es pop di pop dx pop cx pop ax ret request_redraw: push es push ax mov ax, PONYDOS_SEG mov es, ax mov byte [es:GLOBAL_REDRAW], 1 pop ax pop es ret ; ------------------------------------------------------------------ ; File access ; ------------------------------------------------------------------ ; 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 cx push di mov si, dirents + FS_DIRENT_NAME_OFFSET xor ax, ax ; Maximum filename size .name_loop: cmp word [si - FS_DIRENT_NAME_OFFSET], 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, dirents + FS_DIRECTORY_DIRENTS*FS_DIRENT_SIZE 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, dirents .size_loop: mov ax, word [si] test ax, ax jz .done mov byte [di + 8], 'K' shr ax, 1 aam ; mango add ax, 0x3030 cmp ah, 0x30 je .one_digit mov byte [di + 2], ' ' mov [di + 4], ah jmp .one_digit_print .one_digit: test word [si], 1 jnz .one_and_half_digit mov byte [di + 4], ' ' .one_digit_print: mov [di + 6], al jmp .next_iter_size_loop .one_and_half_digit: mov byte [di], ' ' mov byte [di + 2], al mov byte [di + 4], '.' mov byte [di + 6], '5' .next_iter_size_loop: ; Move to next line add di, dx add di, dx add si, FS_DIRENT_SIZE cmp si, dirents + FS_DIRECTORY_DIRENTS*FS_DIRENT_SIZE jge .done dec cx jnz .size_loop .done: pop bp pop di pop si pop cx pop bx pop ax ret copy_dirents: push cx push si push di push ds push es mov bp, PONYDOS_SEG mov ds, bp mov bp, cs mov es, bp mov si, GLOBAL_DIRENTS mov di, dirents mov cx, FS_DIRENT_SIZE*FS_DIRECTORY_DIRENTS rep movsb pop es pop ds pop di pop si pop cx ret ; ------------------------------------------------------------------ ; Memory management ; ------------------------------------------------------------------ deallocate_own_memory: push bx push cx push es mov bx, PONYDOS_SEG mov es, bx ; Segment 0xn000 corresponds to slot n in the allocation table mov bx, cs mov cl, 12 shr bx, cl mov byte [es:GLOBAL_MEMORY_ALLOCATION_MAP + bx], 0 pop es pop cx pop bx ret ; ------------------------------------------------------------------ ; String routines ; ------------------------------------------------------------------ ; in: ; ds:si = string ; out: ; cx = strlen 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 ; ------------------------------------------------------------------ ; Constants ; ------------------------------------------------------------------ asm_extension db '.asm', 0 bin_extension db '.bin', 0 txt_extension db '.txt', 0 text_extension db '.text', 0 wall_extension db '.wall', 0 viewer_file_name db 'viewer.bin', 0 ; ------------------------------------------------------------------ ; Variables ; ------------------------------------------------------------------ disk_icon: db 0x00, DISK_ATTRIBUTE, 0x00, DISK_ATTRIBUTE, 0x00, DISK_ATTRIBUTE, 0x00, DISK_ATTRIBUTE, 0x00, DISK_ATTRIBUTE db 0x00, DISK_ATTRIBUTE, 0x00, DISK_ATTRIBUTE, 0x09, DISK_ATTRIBUTE, 0x00, DISK_ATTRIBUTE, 0x00, DISK_ATTRIBUTE db 0x00, DISK_ATTRIBUTE, 0x00, DISK_ATTRIBUTE, '|', DISK_ATTRIBUTE, 0x00, DISK_ATTRIBUTE, 0x00, DISK_ATTRIBUTE oom_error_dialog: db 'E', TITLEBAR_ATTRIBUTE, 'r', TITLEBAR_ATTRIBUTE, 'r', TITLEBAR_ATTRIBUTE, 'o', TITLEBAR_ATTRIBUTE, 'r', TITLEBAR_ATTRIBUTE times 13-5-1 db 0x00, TITLEBAR_ATTRIBUTE db 'x', TITLEBAR_ATTRIBUTE db 'O', WINDOW_ATTRIBUTE, 'u', WINDOW_ATTRIBUTE, 't', WINDOW_ATTRIBUTE, ' ', WINDOW_ATTRIBUTE, 'o', WINDOW_ATTRIBUTE, 'f', WINDOW_ATTRIBUTE db ' ', WINDOW_ATTRIBUTE, 'm', WINDOW_ATTRIBUTE, 'e', WINDOW_ATTRIBUTE, 'm', WINDOW_ATTRIBUTE, 'o', WINDOW_ATTRIBUTE, 'r', WINDOW_ATTRIBUTE db 'y', WINDOW_ATTRIBUTE launch_error_dialog: db 'E', TITLEBAR_ATTRIBUTE, 'r', TITLEBAR_ATTRIBUTE, 'r', TITLEBAR_ATTRIBUTE, 'o', TITLEBAR_ATTRIBUTE, 'r', TITLEBAR_ATTRIBUTE times FS_DIRENT_NAME_SIZE-1-5-1 db 0x00, TITLEBAR_ATTRIBUTE db 'x', TITLEBAR_ATTRIBUTE db 'C', WINDOW_ATTRIBUTE, 'a', WINDOW_ATTRIBUTE, 'n', WINDOW_ATTRIBUTE, 'n', WINDOW_ATTRIBUTE, 'o', WINDOW_ATTRIBUTE, 't', WINDOW_ATTRIBUTE db ' ', WINDOW_ATTRIBUTE, 'l', WINDOW_ATTRIBUTE, 'a', WINDOW_ATTRIBUTE, 'u', WINDOW_ATTRIBUTE, 'n', WINDOW_ATTRIBUTE, 'c', WINDOW_ATTRIBUTE db 'h', WINDOW_ATTRIBUTE, ' ', WINDOW_ATTRIBUTE, 'f', WINDOW_ATTRIBUTE, 'i', WINDOW_ATTRIBUTE, 'l', WINDOW_ATTRIBUTE, 'e', WINDOW_ATTRIBUTE db ':', WINDOW_ATTRIBUTE times FS_DIRENT_NAME_SIZE-1-19 db 0x00, WINDOW_ATTRIBUTE .filename times FS_DIRENT_NAME_SIZE-1 db 0x00, WINDOW_ATTRIBUTE windows: times window.size db 0 times window.size db 0 times window.size db 0 times window.size db 0 open_windows db 0 wallpaper_name db 'ponydos.wall' times FS_DIRENT_NAME_SIZE-12 db 0 launch_filename times FS_DIRENT_NAME_SIZE db 0 section .bss dirents: resb FS_DIRENT_SIZE*FS_DIRECTORY_DIRENTS file_window: resw ROWS*COLUMNS