2715 lines
113 KiB
Python
2715 lines
113 KiB
Python
from stdint import *
|
|
import asm
|
|
import drivers.video.vesafb.gfx as gfx
|
|
import drivers.video.vesafb.vga as vga
|
|
import drivers.input.mouse.mouse as mouse
|
|
import drivers.input.keyboard.keyboard as keyboard
|
|
import drivers.usb.hid.usb_mouse as usb_mouse
|
|
import drivers.usb.hid.usb_kbd as usb_kbd
|
|
import drivers.serial.uart.serial as serial
|
|
import platform.pch.pic as pic
|
|
import platform.pch.timer as timer
|
|
import platform.pch.rtc as rtc
|
|
import sched.sched as sched
|
|
import sched.process as process
|
|
import mm.mm as mm
|
|
import string
|
|
import viperlib
|
|
import t, c
|
|
|
|
|
|
TASKBAR_HEIGHT: t.CDefine = 50
|
|
CURSOR_SIZE: t.CDefine = 16
|
|
CURSOR_W: t.CDefine = 16
|
|
CURSOR_H: t.CDefine = 16
|
|
CURSOR_SAVE_SIZE: t.CDefine = 256
|
|
TITLE_HEIGHT_CLASSIC: t.CDefine = 24
|
|
TITLE_HEIGHT_WIN: t.CDefine = 32
|
|
MAX_APP_WINDOWS: t.CDefine = 16
|
|
CLOSE_BTN_SIZE: t.CDefine = 16
|
|
CLOSE_BTN_W_WIN: t.CDefine = 46
|
|
CLOSE_BTN_W7_W: t.CDefine = 28
|
|
CLOSE_BTN_W7_H: t.CDefine = 20
|
|
CLOSE_BTN_W7_R: t.CDefine = 3
|
|
CLOSE_BTN_XP_SZ: t.CDefine = 21
|
|
TITLE_BTN_W_WIN: t.CDefine = 46
|
|
TITLE_BTN_W7: t.CDefine = 28
|
|
TITLE_BTN_XP: t.CDefine = 21
|
|
TASKBAR_ICON_SZ: t.CDefine = 36
|
|
TASKBAR_ICON_PAD: t.CDefine = 6
|
|
TASKBAR_LOGO_SZ: t.CDefine = 32
|
|
WIN_RADIUS: t.CDefine = 8
|
|
SHADOW_ENABLED: t.CDefine = False
|
|
SHADOW_LEFT: t.CDefine = 8
|
|
SHADOW_RIGHT: t.CDefine = 12
|
|
SHADOW_TOP: t.CDefine = 4
|
|
SHADOW_BOTTOM: t.CDefine = 14
|
|
SHADOW_ALPHA: t.CDefine = 100
|
|
CURSOR_SHADOW_ALPHA: t.CDefine = 50
|
|
|
|
STYLE_CLASSIC: t.CDefine = 0
|
|
STYLE_WIN10: t.CDefine = 1
|
|
STYLE_WIN11: t.CDefine = 2
|
|
STYLE_WIN7: t.CDefine = 3
|
|
STYLE_WINXP: t.CDefine = 4
|
|
|
|
_fb: UINT32PTR
|
|
_screen_w: t.CInt = 0
|
|
_screen_h: t.CInt = 0
|
|
_fb_pitch: t.CInt = 0
|
|
_cursor_x: t.CInt = 512
|
|
_cursor_y: t.CInt = 300
|
|
_cursor_buttons: t.CUInt8T = 0
|
|
_back_fb: UINT32PTR
|
|
_last_time_sec: t.CUInt32T = 0
|
|
_row_buf: UINT32PTR
|
|
_bg_row_buf: UINT32PTR
|
|
@t.Object
|
|
class AppWindow:
|
|
active: t.CInt
|
|
x: t.CInt
|
|
y: t.CInt
|
|
w: t.CInt
|
|
h: t.CInt
|
|
title: t.CArray[t.CChar, 32]
|
|
orig_title: t.CArray[t.CChar, 32]
|
|
content_h: t.CInt
|
|
fb: UINT32PTR
|
|
fb_w: t.CInt
|
|
fb_h: t.CInt
|
|
z_order: t.CInt
|
|
style: t.CInt
|
|
close_hover: t.CInt
|
|
min_hover: t.CInt
|
|
max_hover: t.CInt
|
|
is_maximized: t.CInt
|
|
orig_x: t.CInt
|
|
orig_y: t.CInt
|
|
orig_w: t.CInt
|
|
orig_h: t.CInt
|
|
pid: t.CInt
|
|
cursor_type: t.CInt
|
|
app_cursor_type: t.CInt
|
|
ping_pending: t.CInt
|
|
no_resp: t.CInt
|
|
no_resp_sec: t.CUInt32T
|
|
minimized: t.CInt
|
|
resizable_w: t.CInt
|
|
resizable_h: t.CInt
|
|
resize_w: t.CInt
|
|
resize_h: t.CInt
|
|
old_fb: UINT32PTR
|
|
|
|
_wins: t.CArray[AppWindow, MAX_APP_WINDOWS]
|
|
_win_count: t.CInt = 0
|
|
_next_z: t.CInt = 1
|
|
_current_app_pid: t.CInt = 0
|
|
HB_INTERVAL_SEC: t.CUInt32T = 5
|
|
HB_NO_RESP_SEC: t.CUInt32T = 30
|
|
_hb_last_sec: t.CUInt32T = 0
|
|
_dirty_rows: t.CUInt8T | t.CPtr = t.CUInt8T(0, t.CPtr)
|
|
_dirty_count: t.CInt = 0
|
|
_dirty_y_min: t.CInt = 0
|
|
_dirty_y_max: t.CInt = -1
|
|
_vblank_ok: t.CInt = -1
|
|
_prev_cursor_x: t.CInt = 512
|
|
_prev_cursor_y: t.CInt = 300
|
|
_cursor_save_buf: t.CArray[t.CUInt32T, 256]
|
|
_cursor_saved: t.CInt = 0
|
|
|
|
_CURSOR_ARROW: t.CArray[t.CUInt8T, 256] = [
|
|
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
1,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,
|
|
1,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,
|
|
1,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,
|
|
1,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,
|
|
1,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,
|
|
1,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,
|
|
1,2,2,2,1,1,1,1,1,1,0,0,0,0,0,0,
|
|
1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
]
|
|
|
|
_CURSOR_IBEAM: t.CArray[t.CUInt8T, 256] = [
|
|
0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,
|
|
0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,
|
|
0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,
|
|
]
|
|
|
|
_CURSOR_RESIZE_EW: t.CArray[t.CUInt8T, 256] = [
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,1,1,1,0,0,0,0,0,
|
|
0,0,0,1,2,2,1,1,1,2,2,1,0,0,0,0,
|
|
0,0,1,2,2,2,2,2,2,2,2,2,1,0,0,0,
|
|
0,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,
|
|
0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,
|
|
0,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,
|
|
0,0,1,2,2,2,2,2,2,2,2,2,1,0,0,0,
|
|
0,0,0,1,2,2,1,1,1,2,2,1,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,1,1,1,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
]
|
|
|
|
_CURSOR_RESIZE_NS: t.CArray[t.CUInt8T, 256] = [
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,1,2,2,2,2,1,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,1,2,2,2,2,1,0,0,0,0,0,0,0,0,
|
|
0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
]
|
|
|
|
_CURSOR_RESIZE_NWSE: t.CArray[t.CUInt8T, 256] = [
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,1,2,1,1,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,1,2,2,1,1,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,1,2,2,1,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
]
|
|
_last_clock_sec: t.CUInt32T = 0
|
|
_prev_btn: t.CUInt8T = 0
|
|
|
|
EVENT_QUEUE_SIZE: t.CDefine = 32
|
|
EVENT_TYPE_NONE: t.CDefine = 0
|
|
EVENT_TYPE_CLICK: t.CDefine = 1
|
|
EVENT_TYPE_HOVER: t.CDefine = 2
|
|
EVENT_TYPE_RELEASE: t.CDefine = 3
|
|
EVENT_TYPE_HOVER_LEAVE: t.CDefine = 4
|
|
EVENT_TYPE_KEY: t.CDefine = 5
|
|
EVENT_TYPE_KEY_RELEASE: t.CDefine = 6
|
|
EVENT_TYPE_PING: t.CDefine = 7
|
|
EVENT_TYPE_RESIZE: t.CDefine = 8
|
|
|
|
RESIZE_EDGE_NONE: t.CDefine = 0
|
|
RESIZE_EDGE_RIGHT: t.CDefine = 1
|
|
RESIZE_EDGE_BOTTOM: t.CDefine = 2
|
|
RESIZE_EDGE_CORNER: t.CDefine = 3
|
|
RESIZE_BORDER: t.CDefine = 6
|
|
RESIZE_MIN_W: t.CDefine = 100
|
|
RESIZE_MIN_H: t.CDefine = 60
|
|
|
|
CURSOR_DEFAULT: t.CDefine = 0
|
|
CURSOR_IBEAM: t.CDefine = 1
|
|
CURSOR_RESIZE_EW: t.CDefine = 2
|
|
CURSOR_RESIZE_NS: t.CDefine = 3
|
|
CURSOR_RESIZE_NWSE: t.CDefine = 4
|
|
|
|
KEY_STATE_PRESS: t.CDefine = 1
|
|
KEY_STATE_RELEASE: t.CDefine = 2
|
|
KEY_STATE_REPEAT: t.CDefine = 3
|
|
|
|
TYPEMATIC_DELAY: t.CDefine = 500
|
|
TYPEMATIC_RATE: t.CDefine = 40
|
|
|
|
HELD_KEY_MAX: t.CDefine = 8
|
|
|
|
class held_key_info(t.CStruct):
|
|
keycode: t.CUInt8T
|
|
is_usb: t.CUInt8T
|
|
press_time: t.CUInt64T
|
|
last_repeat: t.CUInt64T
|
|
|
|
_held_keys: t.CArray[held_key_info, HELD_KEY_MAX]
|
|
_held_key_count: t.CInt = 0
|
|
|
|
@c.Attribute(t.attr.packed)
|
|
class InputEvent:
|
|
type: t.CUInt32T
|
|
win_id: t.CInt
|
|
x: t.CInt
|
|
y: t.CInt
|
|
button: t.CUInt8T
|
|
_pad0: t.CUInt8T
|
|
_pad1: t.CUInt8T
|
|
_pad2: t.CUInt8T
|
|
|
|
INPUT_EVENT_SIZE: t.CDefine = 20
|
|
|
|
_event_queue: t.CArray[InputEvent, EVENT_QUEUE_SIZE]
|
|
_event_head: t.CInt = 0
|
|
_event_tail: t.CInt = 0
|
|
_last_hover_win: t.CInt = -1
|
|
_focused_win: t.CInt = -1
|
|
|
|
KBD_DEV_PS2: t.CDefine = 0
|
|
KBD_DEV_USB: t.CDefine = 1
|
|
|
|
_ps2_shift_l: t.CUInt8T = 0
|
|
_ps2_shift_r: t.CUInt8T = 0
|
|
_ps2_caps: t.CUInt8T = 0
|
|
_ps2_e0_pending: t.CUInt8T = 0
|
|
_kbd_irq_masked: t.CInt = 0
|
|
|
|
VK_LEFT: t.CDefine = -1
|
|
VK_RIGHT: t.CDefine = -2
|
|
VK_UP: t.CDefine = -3
|
|
VK_DOWN: t.CDefine = -4
|
|
VK_HOME: t.CDefine = -5
|
|
VK_END: t.CDefine = -6
|
|
VK_DELETE: t.CDefine = -7
|
|
|
|
_ps2_set1: t.CArray[t.CChar, 128] = [
|
|
'\0', '\x1b', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
|
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
|
'\0', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", '`', '\0',
|
|
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0', ' ',
|
|
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '\0', '\0', '\0', '\0',
|
|
'\0', '+', '\0', '\0', '\0', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
|
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
|
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
|
'\0'
|
|
]
|
|
|
|
_ps2_set1_shift: t.CArray[t.CChar, 128] = [
|
|
'\0', '\x1b', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
|
|
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
|
|
'\0', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', '\0',
|
|
'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '\0', '\0', '\0', ' ',
|
|
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '\0', '\0', '\0', '\0',
|
|
'\0', '+', '\0', '\0', '\0', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
|
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
|
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
|
'\0'
|
|
]
|
|
|
|
def _ps2_scancode_to_ascii(scancode: t.CUInt8T) -> t.CInt:
|
|
code: t.CUInt8T = scancode & t.CUInt8T(0x7F)
|
|
if code >= 128: return 0
|
|
shifted: t.CInt = 0
|
|
if (_ps2_shift_l or _ps2_shift_r) != 0:
|
|
shifted = 1
|
|
if _ps2_caps != 0:
|
|
if code >= 0x10 and code <= 0x32:
|
|
shifted = shifted ^ 1
|
|
if shifted:
|
|
return t.CInt(_ps2_set1_shift[code])
|
|
return t.CInt(_ps2_set1[code])
|
|
|
|
|
|
def _push_event(evt: InputEvent):
|
|
global _event_head, _event_tail
|
|
if evt.type == EVENT_TYPE_RESIZE:
|
|
i: t.CInt = _event_head
|
|
while i != _event_tail:
|
|
if _event_queue[i].type == EVENT_TYPE_RESIZE and _event_queue[i].win_id == evt.win_id:
|
|
_event_queue[i].type = EVENT_TYPE_NONE
|
|
i = (i + 1) % EVENT_QUEUE_SIZE
|
|
next_tail: t.CInt = (_event_tail + 1) % EVENT_QUEUE_SIZE
|
|
if next_tail == _event_head:
|
|
_event_head = (_event_head + 1) % EVENT_QUEUE_SIZE
|
|
string.memcpy(c.Addr(_event_queue[_event_tail]), c.Addr(evt), INPUT_EVENT_SIZE)
|
|
_event_tail = next_tail
|
|
|
|
def poll_event(buf_ptr: t.CVoid | t.CPtr, caller_pid: t.CInt) -> t.CInt:
|
|
global _event_head, _event_tail
|
|
while _event_head != _event_tail:
|
|
if _event_queue[_event_head].type == EVENT_TYPE_NONE:
|
|
_event_head = (_event_head + 1) % EVENT_QUEUE_SIZE
|
|
continue
|
|
evt_win: t.CInt = _event_queue[_event_head].win_id
|
|
evt_pid: t.CInt = 0
|
|
win_ok: t.CInt = 0
|
|
if evt_win >= 0 and evt_win < _win_count:
|
|
evt_pid = _wins[evt_win].pid
|
|
win_ok = 1
|
|
if evt_pid == caller_pid:
|
|
string.memcpy(buf_ptr, c.Addr(_event_queue[_event_head]), INPUT_EVENT_SIZE)
|
|
_event_head = (_event_head + 1) % EVENT_QUEUE_SIZE
|
|
return 1
|
|
if win_ok and not _wins[evt_win].active:
|
|
_event_head = (_event_head + 1) % EVENT_QUEUE_SIZE
|
|
continue
|
|
scan: t.CInt = (_event_head + 1) % EVENT_QUEUE_SIZE
|
|
while scan != _event_tail:
|
|
if _event_queue[scan].type == EVENT_TYPE_NONE:
|
|
scan = (scan + 1) % EVENT_QUEUE_SIZE
|
|
continue
|
|
evt_win2: t.CInt = _event_queue[scan].win_id
|
|
evt_pid2: t.CInt = 0
|
|
if evt_win2 >= 0 and evt_win2 < _win_count:
|
|
evt_pid2 = _wins[evt_win2].pid
|
|
if evt_pid2 == caller_pid:
|
|
string.memcpy(buf_ptr, c.Addr(_event_queue[scan]), INPUT_EVENT_SIZE)
|
|
i: t.CInt = scan
|
|
while i != _event_tail:
|
|
next_i: t.CInt = (i + 1) % EVENT_QUEUE_SIZE
|
|
if next_i != _event_head:
|
|
string.memcpy(c.Addr(_event_queue[i]), c.Addr(_event_queue[next_i]), INPUT_EVENT_SIZE)
|
|
i = next_i
|
|
if _event_tail == 0:
|
|
_event_tail = EVENT_QUEUE_SIZE - 1
|
|
else:
|
|
_event_tail = _event_tail - 1
|
|
return 1
|
|
scan = (scan + 1) % EVENT_QUEUE_SIZE
|
|
break
|
|
return 0
|
|
|
|
def _get_title_height(style: t.CInt) -> t.CInt:
|
|
if style == STYLE_CLASSIC:
|
|
return TITLE_HEIGHT_CLASSIC
|
|
return TITLE_HEIGHT_WIN
|
|
|
|
def _mark_rows_dirty(start_y: t.CInt, count: t.CInt):
|
|
global _dirty_count, _dirty_y_min, _dirty_y_max
|
|
for i in range(start_y, start_y + count):
|
|
if i >= 0 and i < _screen_h:
|
|
if not _dirty_rows[i]:
|
|
_dirty_rows[i] = 1
|
|
_dirty_count += 1
|
|
if i < _dirty_y_min or _dirty_count == 1:
|
|
_dirty_y_min = i
|
|
if i > _dirty_y_max or _dirty_count == 1:
|
|
_dirty_y_max = i
|
|
|
|
def _mark_all_dirty():
|
|
global _dirty_count, _dirty_y_min, _dirty_y_max
|
|
string.memset(_dirty_rows, 1, _screen_h)
|
|
_dirty_count = _screen_h
|
|
_dirty_y_min = 0
|
|
_dirty_y_max = _screen_h - 1
|
|
|
|
def _has_dirty_rows() -> t.CInt:
|
|
return _dirty_count
|
|
|
|
def _clear_dirty_flags():
|
|
global _dirty_count, _dirty_y_min, _dirty_y_max
|
|
string.memset(_dirty_rows, 0, _screen_h)
|
|
_dirty_count = 0
|
|
_dirty_y_min = _screen_h
|
|
_dirty_y_max = -1
|
|
|
|
def _wait_vblank():
|
|
global _vblank_ok
|
|
if _vblank_ok == 0:
|
|
return
|
|
timeout: t.CInt = 50000
|
|
while (asm.inb(0x3DA) & 0x08) != 0:
|
|
timeout -= 1
|
|
if timeout <= 0:
|
|
_vblank_ok = 0
|
|
return
|
|
while (asm.inb(0x3DA) & 0x08) == 0:
|
|
timeout -= 1
|
|
if timeout <= 0:
|
|
_vblank_ok = 0
|
|
return
|
|
_vblank_ok = 1
|
|
|
|
def _fill_rect(buf: UINT32PTR, bw: t.CInt, bh: t.CInt, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T):
|
|
if rx < 0: rw += rx; rx = 0
|
|
if ry < 0: rh += ry; ry = 0
|
|
if rx + rw > bw: rw = bw - rx
|
|
if ry + rh > bh: rh = bh - ry
|
|
if rw <= 0 or rh <= 0: return
|
|
if _row_buf:
|
|
for i in range(rw):
|
|
_row_buf[i] = color
|
|
row_bytes: t.CInt = rw * 4
|
|
for py in range(ry, ry + rh):
|
|
string.memcpy(t.CVoid(t.CUInt64T(buf) + (py * bw + rx) * 4, t.CPtr), _row_buf, row_bytes)
|
|
|
|
def _alpha_blend(bg: t.CUInt32T, fg: t.CUInt32T, alpha: t.CInt) -> t.CUInt32T:
|
|
a: t.CInt = alpha
|
|
ia: t.CInt = 255 - a
|
|
bg_r: t.CInt = t.CInt(bg & 0xFF)
|
|
bg_g: t.CInt = t.CInt((bg >> 8) & 0xFF)
|
|
bg_b: t.CInt = t.CInt((bg >> 16) & 0xFF)
|
|
fg_r: t.CInt = t.CInt(fg & 0xFF)
|
|
fg_g: t.CInt = t.CInt((fg >> 8) & 0xFF)
|
|
fg_b: t.CInt = t.CInt((fg >> 16) & 0xFF)
|
|
r: t.CInt = (fg_r * a + bg_r * ia) >> 8
|
|
g: t.CInt = (fg_g * a + bg_g * ia) >> 8
|
|
b: t.CInt = (fg_b * a + bg_b * ia) >> 8
|
|
return t.CUInt32T(r | (g << 8) | (b << 16) | 0xFF000000)
|
|
|
|
def _is_in_corner(px: t.CInt, py: t.CInt, cx: t.CInt, cy: t.CInt, r: t.CInt) -> t.CInt:
|
|
dx: t.CInt = px - cx
|
|
dy: t.CInt = py - cy
|
|
if dx < 0: dx = -dx
|
|
if dy < 0: dy = -dy
|
|
if dx <= r and dy <= r:
|
|
dist2: t.CInt = dx * dx + dy * dy
|
|
r2: t.CInt = r * r
|
|
if dist2 > r2:
|
|
return 0
|
|
return 1
|
|
|
|
def _is_on_border(rx: t.CInt, ry: t.CInt, ww: t.CInt, wh: t.CInt, r: t.CInt) -> t.CInt:
|
|
if rx == 0 or rx == ww - 1 or ry == 0 or ry == wh - 1:
|
|
return 1
|
|
if ry < r:
|
|
if rx < r:
|
|
dx: t.CInt = rx - r
|
|
dy: t.CInt = ry - r
|
|
dist2: t.CInt = dx * dx + dy * dy
|
|
if dist2 >= (r - 1) * (r - 1): return 1
|
|
elif rx >= ww - r:
|
|
dx = rx - (ww - r - 1)
|
|
dy = ry - r
|
|
dist2 = dx * dx + dy * dy
|
|
if dist2 >= (r - 1) * (r - 1): return 1
|
|
elif ry >= wh - r:
|
|
if rx < r:
|
|
dx = rx - r
|
|
dy = ry - (wh - r - 1)
|
|
dist2 = dx * dx + dy * dy
|
|
if dist2 >= (r - 1) * (r - 1): return 1
|
|
elif rx >= ww - r:
|
|
dx = rx - (ww - r - 1)
|
|
dy = ry - (wh - r - 1)
|
|
dist2 = dx * dx + dy * dy
|
|
if dist2 >= (r - 1) * (r - 1): return 1
|
|
return 0
|
|
|
|
def _corner_alpha(px: t.CInt, py: t.CInt, cx: t.CInt, cy: t.CInt, r: t.CInt) -> t.CInt:
|
|
dx: t.CInt = px - cx
|
|
dy: t.CInt = py - cy
|
|
if dx < 0: dx = -dx
|
|
if dy < 0: dy = -dy
|
|
if dx <= r and dy <= r:
|
|
dist2: t.CInt = dx * dx + dy * dy
|
|
r2: t.CInt = r * r
|
|
if dist2 > r2:
|
|
return 0
|
|
outer: t.CInt = (r + 1) * (r + 1)
|
|
if dist2 >= outer:
|
|
return 160
|
|
return 255
|
|
return 255
|
|
|
|
def _draw_char(buf: UINT32PTR, bw: t.CInt, bh: t.CInt, x: t.CInt, y: t.CInt, ch: t.CChar, color: t.CUInt32T):
|
|
cval: t.CUInt8T = t.CUInt8T(ch)
|
|
if cval >= 128: cval = 0
|
|
for fy in range(16):
|
|
if y + fy < 0 or y + fy >= bh: continue
|
|
row: t.CUInt8T = vga.font[cval][fy]
|
|
if row == 0: continue
|
|
for fx in range(8):
|
|
if row & (0x80 >> fx):
|
|
px: t.CInt = x + fx
|
|
if px >= 0 and px < bw:
|
|
buf[(y + fy) * bw + px] = color
|
|
|
|
def _draw_text(buf: UINT32PTR, bw: t.CInt, bh: t.CInt, x: t.CInt, y: t.CInt, s: t.CConst | str, color: t.CUInt32T):
|
|
cx: t.CInt = x
|
|
cy: t.CInt = y
|
|
for ch in s:
|
|
if ch == 10:
|
|
cy += 16
|
|
cx = x
|
|
else:
|
|
_draw_char(buf, bw, bh, cx, cy, ch, color)
|
|
cx += 8
|
|
|
|
_drag_idx: t.CInt = -1
|
|
|
|
def _eff_w(aw2: AppWindow | t.CPtr) -> t.CInt:
|
|
if aw2.resize_w != 0: return aw2.resize_w
|
|
return aw2.w
|
|
|
|
def _eff_h(aw2: AppWindow | t.CPtr) -> t.CInt:
|
|
if aw2.resize_h != 0: return aw2.resize_h
|
|
return aw2.content_h
|
|
_drag_off_x: t.CInt = 0
|
|
_drag_off_y: t.CInt = 0
|
|
_rsz_drag_idx: t.CInt = -1
|
|
_rsz_edge: t.CInt = 0
|
|
_rsz_start_x: t.CInt = 0
|
|
_rsz_start_y: t.CInt = 0
|
|
_rsz_start_w: t.CInt = 0
|
|
_rsz_start_h: t.CInt = 0
|
|
_rsz_last_w: t.CInt = 0
|
|
_rsz_last_h: t.CInt = 0
|
|
_rsz_last_tick: t.CUInt64T = 0
|
|
_mouse_moved: t.CInt = 0
|
|
|
|
def _bring_to_front(idx: t.CInt):
|
|
global _next_z
|
|
if idx < 0 or idx >= _win_count: return
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[idx])
|
|
if not aw.active or aw.minimized: return
|
|
_next_z += 1
|
|
aw.z_order = _next_z
|
|
|
|
def _hit_test_window(mx: t.CInt, my: t.CInt) -> t.CInt:
|
|
best: t.CInt = -1
|
|
best_z: t.CInt = -1
|
|
for ai in range(_win_count):
|
|
if _wins[ai].active and not _wins[ai].minimized:
|
|
ax: t.CInt = _wins[ai].x
|
|
ay: t.CInt = _wins[ai].y
|
|
aw: t.CInt = _eff_w(c.Addr(_wins[ai]))
|
|
ah: t.CInt = _wins[ai].h
|
|
if mx >= ax and mx < ax + aw and my >= ay and my < ay + ah:
|
|
z: t.CInt = _wins[ai].z_order
|
|
if z > best_z:
|
|
best_z = z
|
|
best = ai
|
|
return best
|
|
|
|
def _hit_test_resize(mx: t.CInt, my: t.CInt, idx: t.CInt) -> t.CInt:
|
|
if idx < 0 or idx >= _win_count: return RESIZE_EDGE_NONE
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[idx])
|
|
if not aw.active or aw.minimized: return RESIZE_EDGE_NONE
|
|
if not aw.resizable_w and not aw.resizable_h: return RESIZE_EDGE_NONE
|
|
on_right: t.CInt = 0
|
|
on_bottom: t.CInt = 0
|
|
if aw.resizable_w:
|
|
if mx >= aw.x + _eff_w(aw) - RESIZE_BORDER and mx < aw.x + _eff_w(aw):
|
|
on_right = 1
|
|
if aw.resizable_h:
|
|
if my >= aw.y + aw.h - RESIZE_BORDER and my < aw.y + aw.h:
|
|
on_bottom = 1
|
|
if on_right and on_bottom: return RESIZE_EDGE_CORNER
|
|
if on_right: return RESIZE_EDGE_RIGHT
|
|
if on_bottom: return RESIZE_EDGE_BOTTOM
|
|
return RESIZE_EDGE_NONE
|
|
|
|
def _hid_to_ascii(keycode: t.CUInt8T, modifier: t.CUInt8T) -> t.CInt:
|
|
global _ps2_caps
|
|
shift: t.CInt = 0
|
|
if (modifier & 0x22) != 0:
|
|
shift = 1
|
|
kc: t.CInt = t.CInt(keycode)
|
|
if kc >= 4 and kc <= 29:
|
|
if _ps2_caps != 0:
|
|
shift = shift ^ 1
|
|
if shift:
|
|
return kc - 4 + 65
|
|
return kc - 4 + 97
|
|
if kc >= 30 and kc <= 38:
|
|
if shift:
|
|
shifts9: t.CArray[t.CInt, 9]
|
|
shifts9[0] = 33; shifts9[1] = 64; shifts9[2] = 35
|
|
shifts9[3] = 36; shifts9[4] = 37; shifts9[5] = 94
|
|
shifts9[6] = 38; shifts9[7] = 42; shifts9[8] = 40
|
|
return shifts9[kc - 30]
|
|
return kc - 30 + 49
|
|
if kc == 39:
|
|
if shift: return 41
|
|
return 48
|
|
if kc == 44: return 32
|
|
if kc == 40: return 13
|
|
if kc == 42: return 8
|
|
if kc == 43: return 9
|
|
if kc == 41: return 27
|
|
if kc == 45:
|
|
if shift: return 95
|
|
return 45
|
|
if kc == 46:
|
|
if shift: return 43
|
|
return 61
|
|
if kc == 47:
|
|
if shift: return 123
|
|
return 91
|
|
if kc == 48:
|
|
if shift: return 125
|
|
return 93
|
|
if kc == 49:
|
|
if shift: return 124
|
|
return 92
|
|
if kc == 51:
|
|
if shift: return 58
|
|
return 59
|
|
if kc == 52:
|
|
if shift: return 34
|
|
return 39
|
|
if kc == 53:
|
|
if shift: return 126
|
|
return 96
|
|
if kc == 54:
|
|
if shift: return 60
|
|
return 44
|
|
if kc == 55:
|
|
if shift: return 62
|
|
return 46
|
|
if kc == 56:
|
|
if shift: return 63
|
|
return 47
|
|
return 0
|
|
|
|
def _held_key_add(keycode: t.CUInt8T, is_usb: t.CUInt8T):
|
|
global _held_key_count
|
|
if _held_key_count >= HELD_KEY_MAX: return
|
|
for i in range(_held_key_count):
|
|
if _held_keys[i].keycode == keycode and _held_keys[i].is_usb == is_usb:
|
|
return
|
|
now: t.CUInt64T = timer.timer_get_ticks()
|
|
_held_keys[_held_key_count].keycode = keycode
|
|
_held_keys[_held_key_count].is_usb = is_usb
|
|
_held_keys[_held_key_count].press_time = now
|
|
_held_keys[_held_key_count].last_repeat = now
|
|
_held_key_count += 1
|
|
|
|
def _held_key_remove(keycode: t.CUInt8T, is_usb: t.CUInt8T):
|
|
global _held_key_count
|
|
for i in range(_held_key_count):
|
|
if _held_keys[i].keycode == keycode and _held_keys[i].is_usb == is_usb:
|
|
for j in range(i, _held_key_count - 1):
|
|
_held_keys[j].keycode = _held_keys[j + 1].keycode
|
|
_held_keys[j].is_usb = _held_keys[j + 1].is_usb
|
|
_held_keys[j].press_time = _held_keys[j + 1].press_time
|
|
_held_keys[j].last_repeat = _held_keys[j + 1].last_repeat
|
|
_held_key_count -= 1
|
|
return
|
|
|
|
def _check_key_repeat():
|
|
global _held_key_count
|
|
if _focused_win < 0 or _focused_win >= _win_count: return
|
|
if not _wins[_focused_win].active: return
|
|
now: t.CUInt64T = timer.timer_get_ticks()
|
|
for i in range(_held_key_count):
|
|
hk: held_key_info | t.CPtr = c.Addr(_held_keys[i])
|
|
elapsed: t.CUInt64T = now - hk.press_time
|
|
if elapsed < t.CUInt64T(TYPEMATIC_DELAY):
|
|
continue
|
|
since_last: t.CUInt64T = now - hk.last_repeat
|
|
if since_last >= t.CUInt64T(TYPEMATIC_RATE):
|
|
hk.last_repeat = now
|
|
ascii_ch: t.CInt = 0
|
|
if hk.is_usb:
|
|
mod: t.CUInt8T = 0
|
|
if _ps2_shift_l or _ps2_shift_r:
|
|
mod = mod | 0x22
|
|
if _ps2_caps:
|
|
mod = mod | 0x01
|
|
ascii_ch = _hid_to_ascii(hk.keycode, mod)
|
|
else:
|
|
ascii_ch = _ps2_scancode_to_ascii(hk.keycode)
|
|
if ascii_ch != 0:
|
|
rep_evt: InputEvent
|
|
rep_evt.type = EVENT_TYPE_KEY
|
|
rep_evt.win_id = _focused_win
|
|
rep_evt.x = ascii_ch
|
|
rep_evt.y = t.CInt(hk.keycode)
|
|
rep_evt.button = KEY_STATE_REPEAT
|
|
rep_evt._pad0 = 0
|
|
rep_evt._pad1 = 0
|
|
rep_evt._pad2 = 0
|
|
_push_event(rep_evt)
|
|
|
|
def _update_keyboard():
|
|
global _focused_win, _kbd_irq_masked
|
|
global _ps2_shift_l, _ps2_shift_r, _ps2_caps
|
|
global _ps2_e0_pending
|
|
# Quick check: skip if no PS/2 data and no USB data
|
|
ps2_status: t.CUInt8T = asm.inb(0x64)
|
|
if (ps2_status & 0x01) == 0 and not usb_kbd.has_data():
|
|
_check_key_repeat()
|
|
return
|
|
if _kbd_irq_masked == 0:
|
|
pic.clearMask(1)
|
|
_kbd_irq_masked = 1
|
|
kbd_cnt: t.CInt = 0
|
|
while usb_kbd.has_data() and kbd_cnt < 32:
|
|
kbd_cnt += 1
|
|
kevt: usb_kbd.usb_kbd_event
|
|
usb_kbd.read_event(c.Addr(kevt))
|
|
if kevt.keycode == 0x39 and kevt.event_type == usb_kbd.KBD_EVT_PRESS:
|
|
_ps2_caps = _ps2_caps ^ t.CUInt8T(1)
|
|
if kevt.event_type == usb_kbd.KBD_EVT_PRESS:
|
|
_held_key_add(kevt.keycode, 1)
|
|
usb_ascii: t.CInt = _hid_to_ascii(kevt.keycode, kevt.modifier)
|
|
if usb_ascii == 0:
|
|
kc2: t.CInt = t.CInt(kevt.keycode)
|
|
if kc2 == 0x50: usb_ascii = VK_LEFT
|
|
elif kc2 == 0x4F: usb_ascii = VK_RIGHT
|
|
elif kc2 == 0x52: usb_ascii = VK_UP
|
|
elif kc2 == 0x51: usb_ascii = VK_DOWN
|
|
elif kc2 == 0x4A: usb_ascii = VK_HOME
|
|
elif kc2 == 0x4D: usb_ascii = VK_END
|
|
elif kc2 == 0x4C: usb_ascii = VK_DELETE
|
|
if usb_ascii != 0 and _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
|
|
usb_evt: InputEvent
|
|
usb_evt.type = EVENT_TYPE_KEY
|
|
usb_evt.win_id = _focused_win
|
|
usb_evt.x = usb_ascii
|
|
usb_evt.y = t.CInt(kevt.keycode)
|
|
usb_evt.button = KEY_STATE_PRESS
|
|
usb_evt._pad0 = 0
|
|
usb_evt._pad1 = 0
|
|
usb_evt._pad2 = 0
|
|
_push_event(usb_evt)
|
|
elif kevt.event_type == usb_kbd.KBD_EVT_RELEASE:
|
|
_held_key_remove(kevt.keycode, 1)
|
|
if _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
|
|
rel_evt: InputEvent
|
|
rel_evt.type = EVENT_TYPE_KEY_RELEASE
|
|
rel_evt.win_id = _focused_win
|
|
rel_evt.x = 0
|
|
rel_evt.y = t.CInt(kevt.keycode)
|
|
rel_evt.button = KEY_STATE_RELEASE
|
|
rel_evt._pad0 = 0
|
|
rel_evt._pad1 = 0
|
|
rel_evt._pad2 = 0
|
|
_push_event(rel_evt)
|
|
ps2_poll_count: t.CInt = 0
|
|
while ps2_poll_count < 16:
|
|
ps2_status: t.CUInt8T = asm.inb(0x64)
|
|
if (ps2_status & 0x01) == 0:
|
|
break
|
|
if (ps2_status & 0x20) != 0:
|
|
asm.inb(0x60)
|
|
ps2_poll_count += 1
|
|
continue
|
|
sc: t.CUInt8T = asm.inb(0x60)
|
|
ps2_poll_count += 1
|
|
if sc == 0x00 or sc == 0xFA or sc == 0xFE or sc == 0xFF:
|
|
_ps2_e0_pending = 0
|
|
continue
|
|
if sc == 0xE0:
|
|
_ps2_e0_pending = 1
|
|
continue
|
|
if sc == 0xE1:
|
|
_ps2_e0_pending = 0
|
|
continue
|
|
if _ps2_e0_pending != 0:
|
|
_ps2_e0_pending = 0
|
|
e0_code: t.CUInt8T = sc & t.CUInt8T(0x7F)
|
|
if (sc & 0x80) != 0:
|
|
_held_key_remove(e0_code | 0x80, 0)
|
|
if _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
|
|
ps2_rel2: InputEvent
|
|
ps2_rel2.type = EVENT_TYPE_KEY_RELEASE
|
|
ps2_rel2.win_id = _focused_win
|
|
ps2_rel2.x = 0
|
|
ps2_rel2.y = t.CInt(e0_code | 0x80)
|
|
ps2_rel2.button = KEY_STATE_RELEASE
|
|
ps2_rel2._pad0 = 0
|
|
ps2_rel2._pad1 = 0
|
|
ps2_rel2._pad2 = 0
|
|
_push_event(ps2_rel2)
|
|
continue
|
|
vk: t.CInt = 0
|
|
if e0_code == 0x4B: vk = VK_LEFT
|
|
elif e0_code == 0x4D: vk = VK_RIGHT
|
|
elif e0_code == 0x48: vk = VK_UP
|
|
elif e0_code == 0x50: vk = VK_DOWN
|
|
elif e0_code == 0x47: vk = VK_HOME
|
|
elif e0_code == 0x4F: vk = VK_END
|
|
elif e0_code == 0x53: vk = VK_DELETE
|
|
if vk != 0:
|
|
_held_key_add(e0_code | 0x80, 0)
|
|
if _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
|
|
e0_evt: InputEvent
|
|
e0_evt.type = EVENT_TYPE_KEY
|
|
e0_evt.win_id = _focused_win
|
|
e0_evt.x = vk
|
|
e0_evt.y = t.CInt(e0_code | 0x80)
|
|
e0_evt.button = KEY_STATE_PRESS
|
|
e0_evt._pad0 = 0
|
|
e0_evt._pad1 = 0
|
|
e0_evt._pad2 = 0
|
|
_push_event(e0_evt)
|
|
continue
|
|
if sc == 0x2A:
|
|
_ps2_shift_l = 1
|
|
continue
|
|
if sc == 0xAA:
|
|
_ps2_shift_l = 0
|
|
continue
|
|
if sc == 0x36:
|
|
_ps2_shift_r = 1
|
|
continue
|
|
if sc == 0xB6:
|
|
_ps2_shift_r = 0
|
|
continue
|
|
if sc == 0x3A:
|
|
_ps2_caps = _ps2_caps ^ t.CUInt8T(1)
|
|
continue
|
|
if (sc & 0x80) != 0:
|
|
release_sc: t.CUInt8T = sc & t.CUInt8T(0x7F)
|
|
_held_key_remove(release_sc, 0)
|
|
if _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
|
|
ps2_rel: InputEvent
|
|
ps2_rel.type = EVENT_TYPE_KEY_RELEASE
|
|
ps2_rel.win_id = _focused_win
|
|
ps2_rel.x = 0
|
|
ps2_rel.y = t.CInt(release_sc)
|
|
ps2_rel.button = KEY_STATE_RELEASE
|
|
ps2_rel._pad0 = 0
|
|
ps2_rel._pad1 = 0
|
|
ps2_rel._pad2 = 0
|
|
_push_event(ps2_rel)
|
|
continue
|
|
_held_key_add(sc, 0)
|
|
ascii_ch: t.CInt = _ps2_scancode_to_ascii(sc)
|
|
if ascii_ch != 0 and _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
|
|
push_evt: InputEvent
|
|
push_evt.type = EVENT_TYPE_KEY
|
|
push_evt.win_id = _focused_win
|
|
push_evt.x = ascii_ch
|
|
push_evt.y = t.CInt(sc)
|
|
push_evt.button = KEY_STATE_PRESS
|
|
push_evt._pad0 = 0
|
|
push_evt._pad1 = 0
|
|
push_evt._pad2 = 0
|
|
_push_event(push_evt)
|
|
_check_key_repeat()
|
|
|
|
def set_cursor_type(win_id: t.CInt, cursor_t: t.CInt):
|
|
if win_id >= 0 and win_id < _win_count:
|
|
_wins[win_id].app_cursor_type = cursor_t
|
|
_wins[win_id].cursor_type = cursor_t
|
|
|
|
def _update_mouse() -> t.CInt:
|
|
global _cursor_x, _cursor_y, _cursor_buttons
|
|
global _drag_idx, _drag_off_x, _drag_off_y
|
|
global _mouse_moved, _prev_btn, _last_hover_win, _focused_win
|
|
global _rsz_drag_idx, _rsz_edge, _rsz_start_x, _rsz_start_y
|
|
global _rsz_start_w, _rsz_start_h, _rsz_last_w, _rsz_last_h, _rsz_last_tick
|
|
moved: t.CInt = 0
|
|
poll_cnt: t.CInt = 0
|
|
while (mouse.has_data() or usb_mouse.has_data()) and poll_cnt < 32:
|
|
poll_cnt += 1
|
|
pkt_dx: t.CInt32T = 0
|
|
pkt_dy: t.CInt32T = 0
|
|
pkt_btn: t.CUInt8T = 0
|
|
if mouse.has_data():
|
|
pkt: mouse.mouse_packet
|
|
mouse.read_packet(c.Addr(pkt))
|
|
pkt_dx = t.CInt32T(pkt.dx)
|
|
pkt_dy = -t.CInt32T(pkt.dy)
|
|
pkt_btn = pkt.buttons
|
|
elif usb_mouse.has_data():
|
|
upkt: usb_mouse.usb_mouse_packet
|
|
usb_mouse.read_packet(c.Addr(upkt))
|
|
pkt_dx = t.CInt32T(upkt.dx)
|
|
pkt_dy = -t.CInt32T(upkt.dy)
|
|
pkt_btn = upkt.buttons
|
|
if pkt_dx != 0 or pkt_dy != 0:
|
|
_cursor_x = _cursor_x + pkt_dx
|
|
_cursor_y = _cursor_y + pkt_dy
|
|
if _cursor_x < 0: _cursor_x = 0
|
|
if _cursor_y < 0: _cursor_y = 0
|
|
if _cursor_x >= _screen_w: _cursor_x = _screen_w - 1
|
|
if _cursor_y >= _screen_h: _cursor_y = _screen_h - 1
|
|
moved = 1
|
|
_mouse_moved = 1
|
|
btn_down: t.CUInt8T = pkt_btn & 0x01
|
|
prev_down: t.CUInt8T = _prev_btn & 0x01
|
|
_cursor_buttons = pkt_btn
|
|
_prev_btn = pkt_btn
|
|
if btn_down and not prev_down:
|
|
hit_app: t.CInt = _hit_test_window(_cursor_x, _cursor_y)
|
|
if hit_app >= 0:
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[hit_app])
|
|
th: t.CInt = _get_title_height(aw.style)
|
|
btn_w: t.CInt = CLOSE_BTN_SIZE
|
|
btn_h: t.CInt = CLOSE_BTN_SIZE
|
|
ew: t.CInt = _eff_w(aw)
|
|
btn_x: t.CInt = aw.x + ew - btn_w - 4
|
|
btn_y: t.CInt = aw.y + (th - btn_h) // 2
|
|
if aw.style == STYLE_WIN7:
|
|
btn_w = CLOSE_BTN_W7_W
|
|
btn_h = CLOSE_BTN_W7_H
|
|
btn_x = aw.x + ew - btn_w - 5
|
|
btn_y = aw.y + (th - btn_h) // 2
|
|
elif aw.style == STYLE_WINXP:
|
|
btn_w = CLOSE_BTN_XP_SZ
|
|
btn_h = CLOSE_BTN_XP_SZ
|
|
btn_x = aw.x + ew - btn_w - 5
|
|
btn_y = aw.y + (th - btn_h) // 2
|
|
elif aw.style == STYLE_WIN10 or aw.style == STYLE_WIN11:
|
|
btn_w = CLOSE_BTN_W_WIN
|
|
btn_h = th - 2
|
|
btn_x = aw.x + ew - btn_w
|
|
btn_y = aw.y + 1
|
|
if _cursor_x >= btn_x and _cursor_x < btn_x + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
|
|
aw.active = 0
|
|
if _focused_win == hit_app:
|
|
_focused_win = -1
|
|
j: t.CInt = _win_count - 1
|
|
while j >= 0:
|
|
if _wins[j].active and not _wins[j].minimized:
|
|
_focused_win = j
|
|
break
|
|
j -= 1
|
|
if _last_hover_win == hit_app:
|
|
_last_hover_win = -1
|
|
_mark_all_dirty()
|
|
else:
|
|
max_bx2: t.CInt = btn_x - btn_w
|
|
if aw.style == STYLE_WIN7 or aw.style == STYLE_WINXP:
|
|
max_bx2 = btn_x - btn_w - 1
|
|
if _cursor_x >= max_bx2 and _cursor_x < max_bx2 + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
|
|
if aw.is_maximized:
|
|
aw.is_maximized = 0
|
|
aw.x = aw.orig_x
|
|
aw.y = aw.orig_y
|
|
aw.h = aw.orig_h
|
|
aw.resize_w = aw.orig_w
|
|
aw.resize_h = aw.orig_h - _get_title_height(aw.style) - 2
|
|
else:
|
|
aw.is_maximized = 1
|
|
aw.orig_x = aw.w
|
|
aw.orig_y = aw.y
|
|
aw.orig_w = aw.w
|
|
aw.orig_h = aw.h
|
|
aw.x = 0
|
|
aw.y = 0
|
|
tb_h_mx: t.CInt = TASKBAR_HEIGHT
|
|
aw.h = _screen_h - tb_h_mx
|
|
aw.resize_w = _screen_w
|
|
aw.resize_h = _screen_h - tb_h_mx - _get_title_height(aw.style) - 2
|
|
rs_evt3: InputEvent
|
|
rs_evt3.type = EVENT_TYPE_RESIZE
|
|
rs_evt3.win_id = hit_app
|
|
rs_evt3.x = aw.resize_w
|
|
rs_evt3.y = aw.resize_h
|
|
rs_evt3.button = 0
|
|
rs_evt3._pad0 = 0
|
|
rs_evt3._pad1 = 0
|
|
rs_evt3._pad2 = 0
|
|
_push_event(rs_evt3)
|
|
_mark_all_dirty()
|
|
else:
|
|
min_bx2: t.CInt = max_bx2 - btn_w
|
|
if aw.style == STYLE_WIN7 or aw.style == STYLE_WINXP:
|
|
min_bx2 = max_bx2 - btn_w - 1
|
|
if _cursor_x >= min_bx2 and _cursor_x < min_bx2 + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
|
|
aw.minimized = 1
|
|
if _focused_win == hit_app:
|
|
_focused_win = -1
|
|
j2: t.CInt = _win_count - 1
|
|
while j2 >= 0:
|
|
if _wins[j2].active and not _wins[j2].minimized:
|
|
_focused_win = j2
|
|
break
|
|
j2 -= 1
|
|
_mark_all_dirty()
|
|
else:
|
|
re: t.CInt = _hit_test_resize(_cursor_x, _cursor_y, hit_app)
|
|
if re != RESIZE_EDGE_NONE:
|
|
_rsz_drag_idx = hit_app
|
|
_rsz_edge = re
|
|
_rsz_start_x = _cursor_x
|
|
_rsz_start_y = _cursor_y
|
|
_rsz_start_w = _eff_w(aw)
|
|
_rsz_start_h = aw.h
|
|
_rsz_last_w = _eff_w(aw)
|
|
_rsz_last_h = aw.h
|
|
_rsz_last_tick = timer.timer_get_ticks()
|
|
_bring_to_front(hit_app)
|
|
_focused_win = hit_app
|
|
_mark_all_dirty()
|
|
elif _cursor_y >= aw.y and _cursor_y < aw.y + th:
|
|
_drag_idx = hit_app
|
|
_drag_off_x = _cursor_x - aw.x
|
|
_drag_off_y = _cursor_y - aw.y
|
|
_bring_to_front(hit_app)
|
|
_focused_win = hit_app
|
|
_mark_all_dirty()
|
|
else:
|
|
_bring_to_front(hit_app)
|
|
_focused_win = hit_app
|
|
_mark_all_dirty()
|
|
evt: InputEvent
|
|
evt.type = EVENT_TYPE_CLICK
|
|
evt.win_id = hit_app
|
|
evt.x = _cursor_x - aw.x
|
|
evt.y = _cursor_y - aw.y - _get_title_height(aw.style)
|
|
evt.button = 1
|
|
evt._pad0 = 0
|
|
evt._pad1 = 0
|
|
evt._pad2 = 0
|
|
_push_event(evt)
|
|
else:
|
|
tb_h_cl: t.CInt = TASKBAR_HEIGHT
|
|
bar_y2: t.CInt = _screen_h - tb_h_cl
|
|
if _cursor_y >= bar_y2:
|
|
logo_x2: t.CInt = 4
|
|
logo_sz2: t.CInt = TASKBAR_LOGO_SZ
|
|
logo_r2: t.CInt = logo_x2 + logo_sz2
|
|
logo_b2: t.CInt = bar_y2 + tb_h_cl
|
|
if _cursor_x >= logo_x2 and _cursor_x < logo_r2 and _cursor_y >= bar_y2 and _cursor_y < logo_b2:
|
|
if _focused_win >= 0 and _focused_win < _win_count:
|
|
if _wins[_focused_win].active:
|
|
_wins[_focused_win].active = 0
|
|
_focused_win = -1
|
|
_mark_all_dirty()
|
|
else:
|
|
icon_sz2: t.CInt = TASKBAR_ICON_SZ
|
|
icon_pad2: t.CInt = TASKBAR_ICON_PAD
|
|
icon_x2: t.CInt = logo_x2 + logo_sz2 + 80
|
|
icon_cnt2: t.CInt = 0
|
|
for ti2 in range(_win_count):
|
|
if _wins[ti2].active:
|
|
ix2: t.CInt = icon_x2 + icon_cnt2 * (icon_sz2 + icon_pad2)
|
|
iy2: t.CInt = bar_y2 + (tb_h_cl - icon_sz2) // 2
|
|
if _cursor_x >= ix2 and _cursor_x < ix2 + icon_sz2 and _cursor_y >= iy2 and _cursor_y < iy2 + icon_sz2:
|
|
if _wins[ti2].minimized:
|
|
_wins[ti2].minimized = 0
|
|
_bring_to_front(ti2)
|
|
_focused_win = ti2
|
|
elif _focused_win == ti2:
|
|
_wins[ti2].minimized = 1
|
|
_focused_win = -1
|
|
for j3 in range(_win_count - 1, -1, -1):
|
|
if _wins[j3].active and not _wins[j3].minimized:
|
|
_focused_win = j3
|
|
break
|
|
else:
|
|
_bring_to_front(ti2)
|
|
_focused_win = ti2
|
|
_mark_all_dirty()
|
|
break
|
|
icon_cnt2 += 1
|
|
if not btn_down:
|
|
if prev_down:
|
|
if _rsz_drag_idx >= 0:
|
|
rs_aw: AppWindow | t.CPtr = c.Addr(_wins[_rsz_drag_idx])
|
|
final_w: t.CInt = _rsz_last_w
|
|
final_h: t.CInt = _rsz_last_h
|
|
old_h_mu: t.CInt = _eff_h(rs_aw) + _get_title_height(rs_aw.style) + 2
|
|
_mark_rows_dirty(rs_aw.y, old_h_mu)
|
|
final_ch: t.CInt = final_h - _get_title_height(rs_aw.style) - 2
|
|
rs_aw.resize_w = final_w
|
|
rs_aw.resize_h = final_ch
|
|
rs_aw.h = final_h
|
|
_mark_rows_dirty(rs_aw.y, final_h)
|
|
rs_evt: InputEvent
|
|
rs_evt.type = EVENT_TYPE_RESIZE
|
|
rs_evt.win_id = _rsz_drag_idx
|
|
rs_evt.x = final_w
|
|
rs_evt.y = final_ch
|
|
rs_evt.button = 0
|
|
rs_evt._pad0 = 0
|
|
rs_evt._pad1 = 0
|
|
rs_evt._pad2 = 0
|
|
_push_event(rs_evt)
|
|
_rsz_drag_idx = -1
|
|
_rsz_edge = RESIZE_EDGE_NONE
|
|
else:
|
|
rel_hit: t.CInt = _hit_test_window(_cursor_x, _cursor_y)
|
|
if rel_hit >= 0:
|
|
aw_rel: AppWindow | t.CPtr = c.Addr(_wins[rel_hit])
|
|
rel_evt: InputEvent
|
|
rel_evt.type = EVENT_TYPE_RELEASE
|
|
rel_evt.win_id = rel_hit
|
|
rel_evt.x = _cursor_x - aw_rel.x
|
|
rel_evt.y = _cursor_y - aw_rel.y - _get_title_height(aw_rel.style)
|
|
rel_evt.button = 0
|
|
rel_evt._pad0 = 0
|
|
rel_evt._pad1 = 0
|
|
rel_evt._pad2 = 0
|
|
_push_event(rel_evt)
|
|
if _drag_idx >= 0:
|
|
moved = 1
|
|
_mark_rows_dirty(_wins[_drag_idx].y, _wins[_drag_idx].h)
|
|
_drag_idx = -1
|
|
if moved and _drag_idx < 0:
|
|
hit_hov: t.CInt = _hit_test_window(_cursor_x, _cursor_y)
|
|
if hit_hov >= 0:
|
|
if _last_hover_win >= 0 and _last_hover_win != hit_hov and _last_hover_win < _win_count:
|
|
if _wins[_last_hover_win].active:
|
|
leave_evt3: InputEvent
|
|
leave_evt3.type = EVENT_TYPE_HOVER_LEAVE
|
|
leave_evt3.win_id = _last_hover_win
|
|
leave_evt3.x = -1
|
|
leave_evt3.y = -1
|
|
leave_evt3.button = 0
|
|
leave_evt3._pad0 = 0
|
|
leave_evt3._pad1 = 0
|
|
leave_evt3._pad2 = 0
|
|
_push_event(leave_evt3)
|
|
aw_hov: AppWindow | t.CPtr = c.Addr(_wins[hit_hov])
|
|
th_hov: t.CInt = _get_title_height(aw_hov.style)
|
|
hov_evt: InputEvent
|
|
hov_evt.type = EVENT_TYPE_HOVER
|
|
hov_evt.win_id = hit_hov
|
|
hov_evt.x = _cursor_x - aw_hov.x
|
|
hov_evt.y = _cursor_y - aw_hov.y - th_hov
|
|
hov_evt.button = 0
|
|
hov_evt._pad0 = 0
|
|
hov_evt._pad1 = 0
|
|
hov_evt._pad2 = 0
|
|
_push_event(hov_evt)
|
|
_last_hover_win = hit_hov
|
|
re_hov: t.CInt = _hit_test_resize(_cursor_x, _cursor_y, hit_hov)
|
|
if re_hov == RESIZE_EDGE_RIGHT:
|
|
aw_hov.cursor_type = CURSOR_RESIZE_EW
|
|
elif re_hov == RESIZE_EDGE_BOTTOM:
|
|
aw_hov.cursor_type = CURSOR_RESIZE_NS
|
|
elif re_hov == RESIZE_EDGE_CORNER:
|
|
aw_hov.cursor_type = CURSOR_RESIZE_NWSE
|
|
else:
|
|
aw_hov.cursor_type = aw_hov.app_cursor_type
|
|
else:
|
|
if _last_hover_win >= 0 and _last_hover_win < _win_count:
|
|
if _wins[_last_hover_win].active:
|
|
leave_evt: InputEvent
|
|
leave_evt.type = EVENT_TYPE_HOVER_LEAVE
|
|
leave_evt.win_id = _last_hover_win
|
|
leave_evt.x = -1
|
|
leave_evt.y = -1
|
|
leave_evt.button = 0
|
|
leave_evt._pad0 = 0
|
|
leave_evt._pad1 = 0
|
|
leave_evt._pad2 = 0
|
|
_push_event(leave_evt)
|
|
_last_hover_win = -1
|
|
if _drag_idx >= 0:
|
|
aw2: AppWindow | t.CPtr = c.Addr(_wins[_drag_idx])
|
|
_drag_old_y: t.CInt = aw2.y
|
|
_mark_rows_dirty(_drag_old_y, aw2.h)
|
|
aw2.x = _cursor_x - _drag_off_x
|
|
aw2.y = _cursor_y - _drag_off_y
|
|
_mark_rows_dirty(aw2.y, aw2.h)
|
|
if _rsz_drag_idx >= 0:
|
|
rs_aw2: AppWindow | t.CPtr = c.Addr(_wins[_rsz_drag_idx])
|
|
dx: t.CInt = _cursor_x - _rsz_start_x
|
|
dy: t.CInt = _cursor_y - _rsz_start_y
|
|
new_w: t.CInt = _rsz_start_w
|
|
new_h: t.CInt = _rsz_start_h
|
|
if _rsz_edge == RESIZE_EDGE_RIGHT or _rsz_edge == RESIZE_EDGE_CORNER:
|
|
new_w = _rsz_start_w + dx
|
|
if new_w < RESIZE_MIN_W: new_w = RESIZE_MIN_W
|
|
if _rsz_edge == RESIZE_EDGE_BOTTOM or _rsz_edge == RESIZE_EDGE_CORNER:
|
|
new_h = _rsz_start_h + dy
|
|
if new_h < RESIZE_MIN_H: new_h = RESIZE_MIN_H
|
|
if new_w != rs_aw2.w or new_h != rs_aw2.h:
|
|
dw: t.CInt = new_w - _rsz_last_w
|
|
if dw < 0: dw = -dw
|
|
dh: t.CInt = new_h - _rsz_last_h
|
|
if dh < 0: dh = -dh
|
|
now_tick: t.CUInt64T = timer.timer_get_ticks()
|
|
elapsed: t.CUInt64T = now_tick - _rsz_last_tick
|
|
need_update: t.CInt = 0
|
|
if dw >= 32 or dh >= 32:
|
|
need_update = 1
|
|
elif elapsed >= 100 and (dw >= 4 or dh >= 4):
|
|
need_update = 1
|
|
if need_update:
|
|
_rsz_last_w = new_w
|
|
_rsz_last_h = new_h
|
|
_rsz_last_tick = now_tick
|
|
old_h_rs: t.CInt = _eff_h(rs_aw2) + _get_title_height(rs_aw2.style) + 2
|
|
_mark_rows_dirty(rs_aw2.y, old_h_rs)
|
|
new_ch: t.CInt = new_h - _get_title_height(rs_aw2.style) - 2
|
|
rs_aw2.resize_w = new_w
|
|
rs_aw2.resize_h = new_ch
|
|
rs_aw2.h = new_h
|
|
_mark_rows_dirty(rs_aw2.y, new_h)
|
|
rs_evt2: InputEvent
|
|
rs_evt2.type = EVENT_TYPE_RESIZE
|
|
rs_evt2.win_id = _rsz_drag_idx
|
|
rs_evt2.x = new_w
|
|
rs_evt2.y = new_ch
|
|
rs_evt2.button = 0
|
|
rs_evt2._pad0 = 0
|
|
rs_evt2._pad1 = 0
|
|
rs_evt2._pad2 = 0
|
|
_push_event(rs_evt2)
|
|
if not moved and _last_hover_win < 0:
|
|
hit_hov2: t.CInt = _hit_test_window(_cursor_x, _cursor_y)
|
|
if hit_hov2 >= 0 and _wins[hit_hov2].active:
|
|
aw_hov2: AppWindow | t.CPtr = c.Addr(_wins[hit_hov2])
|
|
th_hov2: t.CInt = _get_title_height(aw_hov2.style)
|
|
hov_evt2: InputEvent
|
|
hov_evt2.type = EVENT_TYPE_HOVER
|
|
hov_evt2.win_id = hit_hov2
|
|
hov_evt2.x = _cursor_x - aw_hov2.x
|
|
hov_evt2.y = _cursor_y - aw_hov2.y - th_hov2
|
|
hov_evt2.button = 0
|
|
hov_evt2._pad0 = 0
|
|
hov_evt2._pad1 = 0
|
|
hov_evt2._pad2 = 0
|
|
_push_event(hov_evt2)
|
|
_last_hover_win = hit_hov2
|
|
if not moved and _last_hover_win >= 0:
|
|
if _last_hover_win >= _win_count or not _wins[_last_hover_win].active:
|
|
leave_evt2: InputEvent
|
|
leave_evt2.type = EVENT_TYPE_HOVER_LEAVE
|
|
leave_evt2.win_id = _last_hover_win
|
|
leave_evt2.x = -1
|
|
leave_evt2.y = -1
|
|
leave_evt2.button = 0
|
|
leave_evt2._pad0 = 0
|
|
leave_evt2._pad1 = 0
|
|
leave_evt2._pad2 = 0
|
|
_push_event(leave_evt2)
|
|
_last_hover_win = -1
|
|
return moved
|
|
|
|
_render_count: t.CInt = 0
|
|
_cached_top_win: t.CInt = -1
|
|
_perf_t_mouse: t.CUInt64T = 0
|
|
_perf_t_kbd: t.CUInt64T = 0
|
|
_perf_t_render: t.CUInt64T = 0
|
|
_perf_t_flush: t.CUInt64T = 0
|
|
_perf_t_total: t.CUInt64T = 0
|
|
_perf_frames: t.CUInt32T = 0
|
|
_perf_start_ticks: t.CUInt64T = 0
|
|
_perf_t_bg: t.CUInt64T = 0
|
|
_perf_t_win: t.CUInt64T = 0
|
|
_perf_t_cur: t.CUInt64T = 0
|
|
_perf_t_fb: t.CUInt64T = 0
|
|
|
|
def _render():
|
|
global _render_count, _cached_top_win
|
|
global _perf_t_bg, _perf_t_win, _perf_t_cur, _perf_t_fb
|
|
w: t.CInt = _screen_w
|
|
h: t.CInt = _screen_h
|
|
pitch: t.CInt = _fb_pitch
|
|
back: UINT32PTR = _back_fb
|
|
|
|
_cached_top_win = _get_top_window()
|
|
|
|
# No need to erase cursor - dirty row mechanism redraws background + windows from scratch
|
|
|
|
t0: t.CUInt64T = timer.timer_get_ticks()
|
|
row_bytes: t.CInt = w * 4
|
|
if _bg_row_buf and _dirty_count > 0:
|
|
py_bg: t.CInt = _dirty_y_min
|
|
while py_bg <= _dirty_y_max:
|
|
if _dirty_rows[py_bg]:
|
|
string.memcpy(t.CVoid(t.CUInt64T(back) + py_bg * row_bytes, t.CPtr), _bg_row_buf, row_bytes)
|
|
py_bg += 1
|
|
t1: t.CUInt64T = timer.timer_get_ticks()
|
|
_perf_t_bg += (t1 - t0)
|
|
|
|
_draw_taskbar(back)
|
|
|
|
t2: t.CUInt64T = timer.timer_get_ticks()
|
|
sorted: t.CArray[t.CInt, MAX_APP_WINDOWS]
|
|
cnt: t.CInt = 0
|
|
for si in range(_win_count):
|
|
if _wins[si].active and not _wins[si].minimized:
|
|
sorted[cnt] = si
|
|
cnt += 1
|
|
for si in range(cnt - 1):
|
|
for sj in range(si + 1, cnt):
|
|
zi: t.CInt = _wins[sorted[si]].z_order
|
|
zj: t.CInt = _wins[sorted[sj]].z_order
|
|
if zi > zj:
|
|
tmp: t.CInt = sorted[si]
|
|
sorted[si] = sorted[sj]
|
|
sorted[sj] = tmp
|
|
for si in range(cnt):
|
|
_draw_app_window(back, c.Addr(_wins[sorted[si]]))
|
|
t3: t.CUInt64T = timer.timer_get_ticks()
|
|
_perf_t_win += (t3 - t2)
|
|
|
|
# Mark cursor rows as dirty so cursor gets flushed to framebuffer
|
|
_mark_rows_dirty(_cursor_y, CURSOR_H)
|
|
|
|
_draw_cursor(back)
|
|
t4: t.CUInt64T = timer.timer_get_ticks()
|
|
_perf_t_cur += (t4 - t3)
|
|
|
|
_wait_vblank()
|
|
if _dirty_count > 0:
|
|
py_fb: t.CInt = _dirty_y_min
|
|
while py_fb <= _dirty_y_max:
|
|
if _dirty_rows[py_fb]:
|
|
run_start: t.CInt = py_fb
|
|
while py_fb <= _dirty_y_max and _dirty_rows[py_fb]:
|
|
py_fb += 1
|
|
run_bytes: t.CInt = (py_fb - run_start) * row_bytes
|
|
string.memcpy(t.CVoid(t.CUInt64T(_fb) + run_start * pitch, t.CPtr), t.CVoid(t.CUInt64T(back) + run_start * row_bytes, t.CPtr), run_bytes)
|
|
else:
|
|
py_fb += 1
|
|
t5: t.CUInt64T = timer.timer_get_ticks()
|
|
_perf_t_fb += (t5 - t4)
|
|
|
|
_render_count += 1
|
|
|
|
def _draw_taskbar(back: UINT32PTR):
|
|
w: t.CInt = _screen_w
|
|
h: t.CInt = _screen_h
|
|
tb_h: t.CInt = TASKBAR_HEIGHT
|
|
bar_y: t.CInt = h - tb_h
|
|
if bar_y + tb_h <= _dirty_y_min or bar_y > _dirty_y_max:
|
|
return
|
|
bar_col: t.CUInt32T = gfx.COLOR_RGB(32, 32, 32)
|
|
line_col: t.CUInt32T = gfx.COLOR_RGB(60, 60, 60)
|
|
|
|
_fill_rect(back, w, h, 0, bar_y, w, tb_h, bar_col)
|
|
_fill_rect(back, w, h, 0, bar_y, w, 1, line_col)
|
|
|
|
logo_x: t.CInt = 4
|
|
logo_sz: t.CInt = TASKBAR_LOGO_SZ
|
|
logo_y: t.CInt = bar_y + (tb_h - logo_sz) // 2
|
|
lc1: t.CUInt32T = gfx.COLOR_RGB(80, 120, 220)
|
|
lc2: t.CUInt32T = gfx.COLOR_RGB(50, 80, 180)
|
|
lc3: t.CUInt32T = gfx.COLOR_RGB(100, 160, 255)
|
|
for lx in range(logo_sz):
|
|
for ly in range(logo_sz):
|
|
px: t.CInt = logo_x + lx
|
|
py: t.CInt = logo_y + ly
|
|
if px >= 0 and px < w and py >= 0 and py < h:
|
|
col: t.CUInt32T = lc2
|
|
cx: t.CInt = logo_sz // 2
|
|
cy: t.CInt = logo_sz // 2
|
|
dx: t.CInt = lx - cx
|
|
dy: t.CInt = ly - cy
|
|
dist: t.CInt = dx * dx + dy * dy
|
|
r2: t.CInt = cx * cx
|
|
if dist <= r2:
|
|
col = lc1
|
|
if dist <= r2 // 2:
|
|
col = lc3
|
|
back[py * w + px] = col
|
|
|
|
_draw_text(back, w, h, logo_x + logo_sz + 8, bar_y + (tb_h - 16) // 2, "ViperOS", 0xFFFFFFFF)
|
|
|
|
icon_sz: t.CInt = TASKBAR_ICON_SZ
|
|
icon_pad: t.CInt = TASKBAR_ICON_PAD
|
|
icon_x: t.CInt = logo_x + logo_sz + 80
|
|
icon_cnt: t.CInt = 0
|
|
for ti in range(_win_count):
|
|
if _wins[ti].active:
|
|
ix: t.CInt = icon_x + icon_cnt * (icon_sz + icon_pad)
|
|
iy: t.CInt = bar_y + (tb_h - icon_sz) // 2
|
|
is_focused: t.CInt = 1 if ti == _focused_win else 0
|
|
is_minimized: t.CInt = _wins[ti].minimized
|
|
ic_bg: t.CUInt32T = gfx.COLOR_RGB(40, 40, 70)
|
|
if is_focused:
|
|
ic_bg = gfx.COLOR_RGB(60, 60, 120)
|
|
elif is_minimized:
|
|
ic_bg = gfx.COLOR_RGB(30, 30, 50)
|
|
_fill_rect(back, w, h, ix, iy, icon_sz, icon_sz, ic_bg)
|
|
ic_border: t.CUInt32T = gfx.COLOR_RGB(80, 80, 140)
|
|
if is_focused:
|
|
ic_border = gfx.COLOR_RGB(120, 120, 220)
|
|
_fill_rect(back, w, h, ix, iy, icon_sz, 1, ic_border)
|
|
_fill_rect(back, w, h, ix, iy + icon_sz - 1, icon_sz, 1, ic_border)
|
|
_fill_rect(back, w, h, ix, iy, 1, icon_sz, ic_border)
|
|
_fill_rect(back, w, h, ix + icon_sz - 1, iy, 1, icon_sz, ic_border)
|
|
if _wins[ti].title[0] != 0:
|
|
first_ch: t.CChar = _wins[ti].title[0]
|
|
ch_col: t.CUInt32T = 0xFFFFFFFF
|
|
if not is_focused:
|
|
ch_col = gfx.COLOR_RGB(180, 180, 200)
|
|
ch_x: t.CInt = ix + (icon_sz - 8) // 2
|
|
ch_y: t.CInt = iy + (icon_sz - 16) // 2
|
|
_draw_char(back, w, h, ch_x, ch_y, first_ch, ch_col)
|
|
icon_cnt += 1
|
|
|
|
if _render_count % 30 == 0:
|
|
rtc.rtc_read_time()
|
|
|
|
hr: t.CUInt8T = rtc.rtc_get_hours()
|
|
mn: t.CUInt8T = rtc.rtc_get_minutes()
|
|
sc: t.CUInt8T = rtc.rtc_get_seconds()
|
|
day: t.CUInt8T = rtc.rtc_get_day()
|
|
mon: t.CUInt8T = rtc.rtc_get_month()
|
|
yr: t.CUInt16T = rtc.rtc_get_year()
|
|
time_buf: t.CArray[t.CChar, 64]
|
|
string.memset(c.Addr(time_buf), 0, 64)
|
|
viperlib.snprintf(c.Addr(time_buf), 64, "%04u-%02u-%02u %02u:%02u:%02u", t.CUnsignedInt(yr), t.CUnsignedInt(mon), t.CUnsignedInt(day), t.CUnsignedInt(hr), t.CUnsignedInt(mn), t.CUnsignedInt(sc))
|
|
time_str_x: t.CInt = w - 180
|
|
_draw_text(back, w, h, time_str_x, bar_y + (tb_h - 16) // 2, time_buf, 0xFFFFFFFF)
|
|
|
|
def _draw_window_shadow(back: UINT32PTR, bw: t.CInt, bh: t.CInt, wx: t.CInt, wy: t.CInt, ww: t.CInt, wh: t.CInt, is_rounded: t.CInt, rad: t.CInt):
|
|
if not SHADOW_ENABLED: return
|
|
sl: t.CInt = SHADOW_LEFT
|
|
sr: t.CInt = SHADOW_RIGHT
|
|
st: t.CInt = SHADOW_TOP
|
|
sb: t.CInt = SHADOW_BOTTOM
|
|
sa: t.CInt = SHADOW_ALPHA
|
|
shadow_col: t.CUInt32T = gfx.COLOR_RGB(0, 0, 0)
|
|
for py in range(wy - st, wy + wh + sb):
|
|
if py >= 0 and py < bh:
|
|
if not _dirty_rows[py]:
|
|
continue
|
|
for px in range(wx - sl, wx + ww + sr):
|
|
if px >= 0 and px < bw:
|
|
in_win: t.CInt = 0
|
|
if px >= wx and px < wx + ww and py >= wy and py < wy + wh:
|
|
in_win = 1
|
|
if is_rounded:
|
|
rx: t.CInt = px - wx
|
|
ry: t.CInt = py - wy
|
|
if rx < rad and ry < rad:
|
|
if (rx - rad) * (rx - rad) + (ry - rad) * (ry - rad) > rad * rad:
|
|
in_win = 0
|
|
elif rx >= ww - rad and ry < rad:
|
|
if (rx - (ww - rad - 1)) * (rx - (ww - rad - 1)) + (ry - rad) * (ry - rad) > rad * rad:
|
|
in_win = 0
|
|
elif rx < rad and ry >= wh - rad:
|
|
if (rx - rad) * (rx - rad) + (ry - (wh - rad - 1)) * (ry - (wh - rad - 1)) > rad * rad:
|
|
in_win = 0
|
|
elif rx >= ww - rad and ry >= wh - rad:
|
|
if (rx - (ww - rad - 1)) * (rx - (ww - rad - 1)) + (ry - (wh - rad - 1)) * (ry - (wh - rad - 1)) > rad * rad:
|
|
in_win = 0
|
|
if in_win:
|
|
continue
|
|
cpx: t.CInt = px
|
|
if cpx < wx: cpx = wx
|
|
elif cpx > wx + ww - 1: cpx = wx + ww - 1
|
|
cpy: t.CInt = py
|
|
if cpy < wy: cpy = wy
|
|
elif cpy > wy + wh - 1: cpy = wy + wh - 1
|
|
if is_rounded and rad > 0:
|
|
if cpx < wx + rad and cpy < wy + rad:
|
|
acx: t.CInt = wx + rad
|
|
acy: t.CInt = wy + rad
|
|
adx: t.CInt = cpx - acx
|
|
ady: t.CInt = cpy - acy
|
|
ad_sq: t.CInt = adx * adx + ady * ady
|
|
if ad_sq > rad * rad and ad_sq > 0:
|
|
aax: t.CInt = adx
|
|
if aax < 0: aax = 0 - aax
|
|
aay: t.CInt = ady
|
|
if aay < 0: aay = 0 - aay
|
|
am: t.CInt = aax
|
|
if aay > am: am = aay
|
|
an: t.CInt = aax
|
|
if aay < an: an = aay
|
|
ad: t.CInt = am + (an * 3) / 8
|
|
if ad > 0:
|
|
cpx = acx + (adx * rad) / ad
|
|
cpy = acy + (ady * rad) / ad
|
|
elif cpx >= wx + ww - rad and cpy < wy + rad:
|
|
acx = wx + ww - rad - 1
|
|
acy = wy + rad
|
|
adx = cpx - acx
|
|
ady = cpy - acy
|
|
ad_sq = adx * adx + ady * ady
|
|
if ad_sq > rad * rad and ad_sq > 0:
|
|
aax = adx
|
|
if aax < 0: aax = 0 - aax
|
|
aay = ady
|
|
if aay < 0: aay = 0 - aay
|
|
am = aax
|
|
if aay > am: am = aay
|
|
an = aax
|
|
if aay < an: an = aay
|
|
ad = am + (an * 3) / 8
|
|
if ad > 0:
|
|
cpx = acx + (adx * rad) / ad
|
|
cpy = acy + (ady * rad) / ad
|
|
elif cpx < wx + rad and cpy >= wy + wh - rad:
|
|
acx = wx + rad
|
|
acy = wy + wh - rad - 1
|
|
adx = cpx - acx
|
|
ady = cpy - acy
|
|
ad_sq = adx * adx + ady * ady
|
|
if ad_sq > rad * rad and ad_sq > 0:
|
|
aax = adx
|
|
if aax < 0: aax = 0 - aax
|
|
aay = ady
|
|
if aay < 0: aay = 0 - aay
|
|
am = aax
|
|
if aay > am: am = aay
|
|
an = aax
|
|
if aay < an: an = aay
|
|
ad = am + (an * 3) / 8
|
|
if ad > 0:
|
|
cpx = acx + (adx * rad) / ad
|
|
cpy = acy + (ady * rad) / ad
|
|
elif cpx >= wx + ww - rad and cpy >= wy + wh - rad:
|
|
acx = wx + ww - rad - 1
|
|
acy = wy + wh - rad - 1
|
|
adx = cpx - acx
|
|
ady = cpy - acy
|
|
ad_sq = adx * adx + ady * ady
|
|
if ad_sq > rad * rad and ad_sq > 0:
|
|
aax = adx
|
|
if aax < 0: aax = 0 - aax
|
|
aay = ady
|
|
if aay < 0: aay = 0 - aay
|
|
am = aax
|
|
if aay > am: am = aay
|
|
an = aax
|
|
if aay < an: an = aay
|
|
ad = am + (an * 3) / 8
|
|
if ad > 0:
|
|
cpx = acx + (adx * rad) / ad
|
|
cpy = acy + (ady * rad) / ad
|
|
dx: t.CInt = px - cpx
|
|
dy: t.CInt = py - cpy
|
|
adx_d: t.CInt = dx
|
|
if adx_d < 0: adx_d = 0 - adx_d
|
|
ady_d: t.CInt = dy
|
|
if ady_d < 0: ady_d = 0 - ady_d
|
|
dist: t.CInt = adx_d
|
|
if ady_d > dist: dist = ady_d
|
|
dist = dist + ((adx_d + ady_d - dist) * 3) / 8
|
|
me_x: t.CInt = sl
|
|
if dx > 0: me_x = sr
|
|
me_y: t.CInt = st
|
|
if dy > 0: me_y = sb
|
|
me: t.CInt = me_x
|
|
if adx_d + ady_d > 0:
|
|
me = (me_x * adx_d + me_y * ady_d) / (adx_d + ady_d)
|
|
if me > 0 and dist > 0 and dist < me:
|
|
t_val: t.CInt = (256 * dist) / me
|
|
t_inv: t.CInt = 256 - t_val
|
|
a: t.CInt = (sa * t_inv * t_inv) / 65536
|
|
if a > 0:
|
|
back[py * bw + px] = _alpha_blend(back[py * bw + px], shadow_col, a)
|
|
|
|
def _cursor_save_bg(back: UINT32PTR, cx: t.CInt, cy: t.CInt, w: t.CInt, h: t.CInt):
|
|
global _cursor_saved
|
|
cw: t.CInt = CURSOR_W
|
|
ch: t.CInt = CURSOR_H
|
|
for dy in range(ch):
|
|
for dx in range(cw):
|
|
sx: t.CInt = cx + dx
|
|
sy: t.CInt = cy + dy
|
|
if sx >= 0 and sx < w and sy >= 0 and sy < h:
|
|
_cursor_save_buf[dy * cw + dx] = back[sy * w + sx]
|
|
else:
|
|
_cursor_save_buf[dy * cw + dx] = 0
|
|
_cursor_saved = 1
|
|
|
|
def _cursor_restore_bg(back: UINT32PTR, cx: t.CInt, cy: t.CInt, w: t.CInt, h: t.CInt):
|
|
global _cursor_saved
|
|
if _cursor_saved == 0: return
|
|
cw: t.CInt = CURSOR_W
|
|
ch: t.CInt = CURSOR_H
|
|
for dy in range(ch):
|
|
for dx in range(cw):
|
|
sx: t.CInt = cx + dx
|
|
sy: t.CInt = cy + dy
|
|
if sx >= 0 and sx < w and sy >= 0 and sy < h:
|
|
back[sy * w + sx] = _cursor_save_buf[dy * cw + dx]
|
|
_cursor_saved = 0
|
|
|
|
def _cursor_draw_bitmap(back: UINT32PTR, cx: t.CInt, cy: t.CInt, w: t.CInt, h: t.CInt, bmp: t.CArray[t.CUInt8T, 256]):
|
|
cw: t.CInt = CURSOR_W
|
|
ch: t.CInt = CURSOR_H
|
|
white: t.CUInt32T = gfx.COLOR_RGB(255, 255, 255)
|
|
black: t.CUInt32T = gfx.COLOR_RGB(0, 0, 0)
|
|
for dy in range(ch):
|
|
for dx in range(cw):
|
|
pixel: t.CUInt8T = bmp[dy * cw + dx]
|
|
if pixel != 0:
|
|
px: t.CInt = cx + dx
|
|
py: t.CInt = cy + dy
|
|
if px >= 0 and px < w and py >= 0 and py < h:
|
|
if pixel == 1:
|
|
back[py * w + px] = black
|
|
elif pixel == 2:
|
|
back[py * w + px] = white
|
|
|
|
def _cursor_draw_xor(back: UINT32PTR, cx: t.CInt, cy: t.CInt, w: t.CInt, h: t.CInt, bmp: t.CArray[t.CUInt8T, 256]):
|
|
cw: t.CInt = CURSOR_W
|
|
ch: t.CInt = CURSOR_H
|
|
xor_val: t.CUInt32T = t.CUInt32T(0x00FFFFFF)
|
|
for dy in range(ch):
|
|
for dx in range(cw):
|
|
pixel: t.CUInt8T = bmp[dy * cw + dx]
|
|
if pixel != 0:
|
|
px: t.CInt = cx + dx
|
|
py: t.CInt = cy + dy
|
|
if px >= 0 and px < w and py >= 0 and py < h:
|
|
back[py * w + px] = back[py * w + px] ^ xor_val
|
|
|
|
def _draw_cursor(back: UINT32PTR):
|
|
cx: t.CInt = _cursor_x
|
|
cy: t.CInt = _cursor_y
|
|
w: t.CInt = _screen_w
|
|
h: t.CInt = _screen_h
|
|
cur_type: t.CInt = CURSOR_DEFAULT
|
|
if _last_hover_win >= 0 and _last_hover_win < _win_count:
|
|
cur_type = _wins[_last_hover_win].cursor_type
|
|
if cur_type == CURSOR_IBEAM:
|
|
_cursor_draw_bitmap(back, cx, cy, w, h, _CURSOR_IBEAM)
|
|
elif cur_type == CURSOR_RESIZE_EW:
|
|
_cursor_draw_bitmap(back, cx, cy, w, h, _CURSOR_RESIZE_EW)
|
|
elif cur_type == CURSOR_RESIZE_NS:
|
|
_cursor_draw_bitmap(back, cx, cy, w, h, _CURSOR_RESIZE_NS)
|
|
elif cur_type == CURSOR_RESIZE_NWSE:
|
|
_cursor_draw_bitmap(back, cx, cy, w, h, _CURSOR_RESIZE_NWSE)
|
|
else:
|
|
_cursor_draw_bitmap(back, cx, cy, w, h, _CURSOR_ARROW)
|
|
|
|
def _erase_cursor(back: UINT32PTR):
|
|
global _cursor_saved
|
|
if _cursor_saved == 0: return
|
|
_cursor_restore_bg(back, _prev_cursor_x, _prev_cursor_y, _screen_w, _screen_h)
|
|
|
|
def desktop_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
|
|
global _last_clock_sec, _mouse_moved
|
|
global _prev_cursor_x, _prev_cursor_y
|
|
global _perf_t_mouse, _perf_t_kbd, _perf_t_render, _perf_t_flush, _perf_t_total, _perf_frames, _perf_start_ticks
|
|
global _perf_t_bg, _perf_t_win, _perf_t_cur, _perf_t_fb
|
|
serial.puts("[desktop] thread started\n")
|
|
_mark_all_dirty()
|
|
_dt_hb_sec: t.CUInt32T = 0
|
|
tb_h_dt: t.CInt = TASKBAR_HEIGHT
|
|
_perf_buf: t.CArray[t.CChar, 256]
|
|
_perf_start_ticks = timer.timer_get_ticks()
|
|
_kbd_poll_ticks: t.CUInt64T = 0
|
|
_mouse_poll_ticks: t.CUInt64T = 0
|
|
while True:
|
|
_loop_t0: t.CUInt64T = timer.timer_get_ticks()
|
|
# Poll mouse at most every 4ms to avoid excessive I/O port overhead
|
|
_now_ticks: t.CUInt64T = timer.timer_get_ticks()
|
|
if _now_ticks - _mouse_poll_ticks >= 4:
|
|
_mouse_poll_ticks = _now_ticks
|
|
_mt0: t.CUInt64T = timer.timer_get_ticks()
|
|
mouse_active: t.CInt = _update_mouse()
|
|
_mt1: t.CUInt64T = timer.timer_get_ticks()
|
|
_perf_t_mouse += (_mt1 - _mt0)
|
|
# Poll keyboard at most every 4ms to avoid excessive I/O port overhead
|
|
if _now_ticks - _kbd_poll_ticks >= 4:
|
|
_kbd_poll_ticks = _now_ticks
|
|
_kt0: t.CUInt64T = timer.timer_get_ticks()
|
|
_update_keyboard()
|
|
_kt1: t.CUInt64T = timer.timer_get_ticks()
|
|
_perf_t_kbd += (_kt1 - _kt0)
|
|
_heartbeat_check()
|
|
sched.Scheduler.try_reschedule()
|
|
_dt_cur_sec: t.CUInt32T = timer.timer_get_seconds()
|
|
if _dt_cur_sec != _dt_hb_sec:
|
|
_dt_hb_sec = _dt_cur_sec
|
|
cur_sec: t.CUInt32T = timer.timer_get_seconds()
|
|
if cur_sec != _last_clock_sec:
|
|
_last_clock_sec = cur_sec
|
|
_mark_rows_dirty(_screen_h - tb_h_dt, tb_h_dt)
|
|
if _mouse_moved:
|
|
_mouse_moved = 0
|
|
sz: t.CInt = CURSOR_H
|
|
_mark_rows_dirty(_prev_cursor_y, sz)
|
|
_mark_rows_dirty(_cursor_y, sz)
|
|
_prev_cursor_x = _cursor_x
|
|
_prev_cursor_y = _cursor_y
|
|
top_win: t.CInt = _hit_test_window(_cursor_x, _cursor_y)
|
|
for ai in range(_win_count):
|
|
if _wins[ai].active and not _wins[ai].minimized:
|
|
th: t.CInt = _get_title_height(_wins[ai].style)
|
|
btn_w: t.CInt = CLOSE_BTN_SIZE
|
|
btn_h: t.CInt = CLOSE_BTN_SIZE
|
|
ew_hov: t.CInt = _eff_w(c.Addr(_wins[ai]))
|
|
btn_x: t.CInt = _wins[ai].x + ew_hov - btn_w - 4
|
|
btn_y: t.CInt = _wins[ai].y + (th - btn_h) // 2
|
|
if _wins[ai].style == STYLE_WIN7:
|
|
btn_w = CLOSE_BTN_W7_W
|
|
btn_h = CLOSE_BTN_W7_H
|
|
btn_x = _wins[ai].x + ew_hov - btn_w - 5
|
|
btn_y = _wins[ai].y + (th - btn_h) // 2
|
|
elif _wins[ai].style == STYLE_WINXP:
|
|
btn_w = CLOSE_BTN_XP_SZ
|
|
btn_h = CLOSE_BTN_XP_SZ
|
|
btn_x = _wins[ai].x + ew_hov - btn_w - 5
|
|
btn_y = _wins[ai].y + (th - btn_h) // 2
|
|
elif _wins[ai].style == STYLE_WIN10 or _wins[ai].style == STYLE_WIN11:
|
|
btn_w = CLOSE_BTN_W_WIN
|
|
btn_h = th - 2
|
|
btn_x = _wins[ai].x + ew_hov - btn_w
|
|
btn_y = _wins[ai].y + 1
|
|
max_bx3: t.CInt = btn_x - btn_w
|
|
if _wins[ai].style == STYLE_WIN7 or _wins[ai].style == STYLE_WINXP:
|
|
max_bx3 = btn_x - btn_w - 1
|
|
min_bx3: t.CInt = max_bx3 - btn_w
|
|
if _wins[ai].style == STYLE_WIN7 or _wins[ai].style == STYLE_WINXP:
|
|
min_bx3 = max_bx3 - btn_w - 1
|
|
is_over_close: t.CInt = 0
|
|
is_over_max: t.CInt = 0
|
|
is_over_min: t.CInt = 0
|
|
if ai == top_win:
|
|
if _cursor_x >= btn_x and _cursor_x < btn_x + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
|
|
is_over_close = 1
|
|
elif _cursor_x >= max_bx3 and _cursor_x < max_bx3 + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
|
|
is_over_max = 1
|
|
elif _cursor_x >= min_bx3 and _cursor_x < min_bx3 + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
|
|
is_over_min = 1
|
|
if is_over_close and _wins[ai].close_hover < 255:
|
|
_old_hov: t.CInt = _wins[ai].close_hover
|
|
_wins[ai].close_hover += 60
|
|
if _wins[ai].close_hover > 255:
|
|
_wins[ai].close_hover = 255
|
|
if _wins[ai].close_hover != _old_hov:
|
|
_mark_rows_dirty(btn_y, btn_h)
|
|
elif not is_over_close and _wins[ai].close_hover > 0:
|
|
_old_hov2: t.CInt = _wins[ai].close_hover
|
|
_wins[ai].close_hover -= 45
|
|
if _wins[ai].close_hover < 0:
|
|
_wins[ai].close_hover = 0
|
|
if _wins[ai].close_hover != _old_hov2:
|
|
_mark_rows_dirty(btn_y, btn_h)
|
|
if is_over_max and _wins[ai].max_hover < 255:
|
|
_old_mh: t.CInt = _wins[ai].max_hover
|
|
_wins[ai].max_hover += 60
|
|
if _wins[ai].max_hover > 255:
|
|
_wins[ai].max_hover = 255
|
|
if _wins[ai].max_hover != _old_mh:
|
|
_mark_rows_dirty(btn_y, btn_h)
|
|
elif not is_over_max and _wins[ai].max_hover > 0:
|
|
_old_mh2: t.CInt = _wins[ai].max_hover
|
|
_wins[ai].max_hover -= 45
|
|
if _wins[ai].max_hover < 0:
|
|
_wins[ai].max_hover = 0
|
|
if _wins[ai].max_hover != _old_mh2:
|
|
_mark_rows_dirty(btn_y, btn_h)
|
|
if is_over_min and _wins[ai].min_hover < 255:
|
|
_old_nh: t.CInt = _wins[ai].min_hover
|
|
_wins[ai].min_hover += 60
|
|
if _wins[ai].min_hover > 255:
|
|
_wins[ai].min_hover = 255
|
|
if _wins[ai].min_hover != _old_nh:
|
|
_mark_rows_dirty(btn_y, btn_h)
|
|
elif not is_over_min and _wins[ai].min_hover > 0:
|
|
_old_nh2: t.CInt = _wins[ai].min_hover
|
|
_wins[ai].min_hover -= 45
|
|
if _wins[ai].min_hover < 0:
|
|
_wins[ai].min_hover = 0
|
|
if _wins[ai].min_hover != _old_nh2:
|
|
_mark_rows_dirty(btn_y, btn_h)
|
|
if _has_dirty_rows():
|
|
_rt0: t.CUInt64T = timer.timer_get_ticks()
|
|
_render()
|
|
_rt1: t.CUInt64T = timer.timer_get_ticks()
|
|
_perf_t_render += (_rt1 - _rt0)
|
|
_ft0: t.CUInt64T = timer.timer_get_ticks()
|
|
_clear_dirty_flags()
|
|
_ft1: t.CUInt64T = timer.timer_get_ticks()
|
|
_perf_t_flush += (_ft1 - _ft0)
|
|
_perf_frames += 1
|
|
_loop_t1: t.CUInt64T = timer.timer_get_ticks()
|
|
_perf_t_total += (_loop_t1 - _loop_t0)
|
|
_now_ticks: t.CUInt64T = timer.timer_get_ticks()
|
|
_elapsed_ms: t.CUInt64T = _now_ticks - _perf_start_ticks
|
|
if _elapsed_ms >= 1000:
|
|
_fps_val: t.CUInt32T = 0
|
|
if _elapsed_ms > 0:
|
|
_fps_val = t.CUInt32T(t.CUInt64T(_perf_frames) * 1000 / _elapsed_ms)
|
|
string.memset(c.Addr(_perf_buf), 0, 256)
|
|
viperlib.snprintf(c.Addr(_perf_buf), 256, "[perf] fps=%u wall=%lu work=%lu mouse=%lu kbd=%lu render=%lu(bg=%lu win=%lu cur=%lu fb=%lu) dirty=%d vsync=%d\n", _fps_val, t.CUInt64T(_elapsed_ms), t.CUInt64T(_perf_t_total), t.CUInt64T(_perf_t_mouse), t.CUInt64T(_perf_t_kbd), t.CUInt64T(_perf_t_render), t.CUInt64T(_perf_t_bg), t.CUInt64T(_perf_t_win), t.CUInt64T(_perf_t_cur), t.CUInt64T(_perf_t_fb), _dirty_count, _vblank_ok)
|
|
serial.puts(c.Addr(_perf_buf))
|
|
_perf_t_mouse = 0
|
|
_perf_t_kbd = 0
|
|
_perf_t_render = 0
|
|
_perf_t_flush = 0
|
|
_perf_t_total = 0
|
|
_perf_t_bg = 0
|
|
_perf_t_win = 0
|
|
_perf_t_cur = 0
|
|
_perf_t_fb = 0
|
|
_perf_frames = 0
|
|
_perf_start_ticks = _now_ticks
|
|
sched.Scheduler.try_reschedule()
|
|
return 0
|
|
|
|
def start(fb_ptr: t.CVoid | t.CPtr, w: t.CInt, h: t.CInt, pitch: t.CInt = 0) -> sched.Thread | t.CPtr:
|
|
global _fb, _screen_w, _screen_h, _fb_pitch, _cursor_x, _cursor_y
|
|
global _back_fb, _row_buf
|
|
global _dirty_rows, _prev_cursor_x, _prev_cursor_y
|
|
_fb = fb_ptr
|
|
_screen_w = w
|
|
_screen_h = h
|
|
if pitch > 0:
|
|
_fb_pitch = pitch
|
|
else:
|
|
_fb_pitch = w * 4
|
|
_cursor_x = w // 2
|
|
_cursor_y = h // 2
|
|
_prev_cursor_x = _cursor_x
|
|
_prev_cursor_y = _cursor_y
|
|
|
|
_dirty_rows = mm.malloc(h)
|
|
if _dirty_rows:
|
|
string.memset(_dirty_rows, 0, h)
|
|
else:
|
|
serial.puts("[desktop] dirty_rows malloc FAILED\n")
|
|
return None
|
|
|
|
_back_fb = mm.malloc(w * h * 4)
|
|
if _back_fb:
|
|
string.memset(_back_fb, 0, w * h * 4)
|
|
else:
|
|
serial.puts("[desktop] back_fb malloc FAILED\n")
|
|
return None
|
|
|
|
_row_buf = mm.malloc(w * 4)
|
|
if _row_buf:
|
|
string.memset(_row_buf, 0, w * 4)
|
|
else:
|
|
serial.puts("[desktop] row_buf malloc FAILED!\n")
|
|
|
|
_bg_row_buf = mm.malloc(w * 4)
|
|
if _bg_row_buf:
|
|
desktop_init_col: t.CUInt32T = gfx.COLOR_RGB(25, 25, 35)
|
|
for ri in range(w):
|
|
_bg_row_buf[ri] = desktop_init_col
|
|
else:
|
|
serial.puts("[desktop] bg_row_buf malloc FAILED!\n")
|
|
|
|
_mark_all_dirty()
|
|
p: process.Process | t.CPtr = process.ProcessManager.create_process("desktop", None)
|
|
desktop_pid: t.CInt = 0
|
|
if p:
|
|
desktop_pid = p.pid
|
|
th: sched.Thread | t.CPtr = sched.Scheduler.create_thread(desktop_thread, None, desktop_pid)
|
|
if p and th:
|
|
p.addThread(th.tid)
|
|
return th
|
|
|
|
def _get_top_window() -> t.CInt:
|
|
best: t.CInt = -1
|
|
best_z: t.CInt = -1
|
|
for ai in range(_win_count):
|
|
if _wins[ai].active and not _wins[ai].minimized:
|
|
z: t.CInt = _wins[ai].z_order
|
|
if z > best_z:
|
|
best_z = z
|
|
best = ai
|
|
return best
|
|
|
|
def _draw_min_btn(back: UINT32PTR, bw: t.CInt, bh: t.CInt, bx: t.CInt, by: t.CInt, btn_w: t.CInt, btn_h: t.CInt, hover_alpha: t.CInt, style: t.CInt):
|
|
if hover_alpha > 0:
|
|
hover_col: t.CUInt32T = gfx.COLOR_RGB(80, 80, 80)
|
|
if style == STYLE_WIN7:
|
|
hover_col = gfx.COLOR_RGB(200, 220, 240)
|
|
elif style == STYLE_WINXP:
|
|
hover_col = gfx.COLOR_RGB(180, 210, 240)
|
|
for py in range(by, by + btn_h):
|
|
if py >= 0 and py < bh:
|
|
for px in range(bx, bx + btn_w):
|
|
if px >= 0 and px < bw:
|
|
bg_pixel: t.CUInt32T = back[py * bw + px]
|
|
back[py * bw + px] = _alpha_blend(bg_pixel, hover_col, hover_alpha)
|
|
line_col: t.CUInt32T = gfx.COLOR_RGB(180, 180, 180)
|
|
if hover_alpha > 0:
|
|
line_col = gfx.COLOR_RGB(255, 255, 255)
|
|
cx: t.CInt = bx + btn_w // 2
|
|
cy: t.CInt = by + btn_h // 2
|
|
lw: t.CInt = 5
|
|
if btn_w >= 30:
|
|
lw = 8
|
|
ly: t.CInt = cy + 3
|
|
if ly >= 0 and ly < bh:
|
|
for lx in range(cx - lw, cx + lw + 1):
|
|
if lx >= 0 and lx < bw:
|
|
back[ly * bw + lx] = line_col
|
|
|
|
def _draw_max_btn(back: UINT32PTR, bw: t.CInt, bh: t.CInt, bx: t.CInt, by: t.CInt, btn_w: t.CInt, btn_h: t.CInt, hover_alpha: t.CInt, style: t.CInt, is_maximized: t.CInt):
|
|
if hover_alpha > 0:
|
|
hover_col2: t.CUInt32T = gfx.COLOR_RGB(80, 80, 80)
|
|
if style == STYLE_WIN7:
|
|
hover_col2 = gfx.COLOR_RGB(200, 220, 240)
|
|
elif style == STYLE_WINXP:
|
|
hover_col2 = gfx.COLOR_RGB(180, 210, 240)
|
|
for py2 in range(by, by + btn_h):
|
|
if py2 >= 0 and py2 < bh:
|
|
for px2 in range(bx, bx + btn_w):
|
|
if px2 >= 0 and px2 < bw:
|
|
bg_pixel2: t.CUInt32T = back[py2 * bw + px2]
|
|
back[py2 * bw + px2] = _alpha_blend(bg_pixel2, hover_col2, hover_alpha)
|
|
rect_col: t.CUInt32T = gfx.COLOR_RGB(180, 180, 180)
|
|
if hover_alpha > 0:
|
|
rect_col = gfx.COLOR_RGB(255, 255, 255)
|
|
cx2: t.CInt = bx + btn_w // 2
|
|
cy2: t.CInt = by + btn_h // 2
|
|
sz: t.CInt = 4
|
|
if btn_w >= 30:
|
|
sz = 6
|
|
if is_maximized:
|
|
off: t.CInt = 2
|
|
for ry1 in range(cy2 - sz + off, cy2 + sz + off + 1):
|
|
if ry1 >= 0 and ry1 < bh:
|
|
for rx1 in range(cx2 - sz + off, cx2 + sz + off + 1):
|
|
if rx1 >= 0 and rx1 < bw:
|
|
is_top: t.CInt = 0
|
|
if ry1 == cy2 - sz + off or ry1 == cy2 - sz + off + 1:
|
|
is_top = 1
|
|
is_border: t.CInt = 0
|
|
if ry1 == cy2 - sz + off or ry1 == cy2 + sz + off or rx1 == cx2 - sz + off or rx1 == cx2 + sz + off:
|
|
is_border = 1
|
|
if is_top or is_border:
|
|
back[ry1 * bw + rx1] = rect_col
|
|
for ry2 in range(cy2 - sz, cy2 + sz + 1):
|
|
if ry2 >= 0 and ry2 < bh:
|
|
for rx2 in range(cx2 - sz, cx2 + sz + 1):
|
|
if rx2 >= 0 and rx2 < bw:
|
|
if ry2 == cy2 - sz or ry2 == cy2 - sz + 1 or rx2 == cx2 - sz or rx2 == cx2 + sz:
|
|
back[ry2 * bw + rx2] = rect_col
|
|
else:
|
|
for ry3 in range(cy2 - sz, cy2 + sz + 1):
|
|
if ry3 >= 0 and ry3 < bh:
|
|
for rx3 in range(cx2 - sz, cx2 + sz + 1):
|
|
if rx3 >= 0 and rx3 < bw:
|
|
if ry3 == cy2 - sz or ry3 == cy2 + sz or rx3 == cx2 - sz or rx3 == cx2 + sz:
|
|
back[ry3 * bw + rx3] = rect_col
|
|
top_y: t.CInt = cy2 - sz
|
|
if top_y >= 0 and top_y < bh:
|
|
for tx in range(cx2 - sz, cx2 + sz + 1):
|
|
if tx >= 0 and tx < bw:
|
|
back[top_y * bw + tx] = rect_col
|
|
if top_y + 1 < bh:
|
|
for tx2 in range(cx2 - sz, cx2 + sz + 1):
|
|
if tx2 >= 0 and tx2 < bw:
|
|
back[(top_y + 1) * bw + tx2] = rect_col
|
|
|
|
def _draw_close_btn(back: UINT32PTR, bw: t.CInt, bh: t.CInt, bx: t.CInt, by: t.CInt, btn_w: t.CInt, btn_h: t.CInt, hover_alpha: t.CInt, style: t.CInt, clip_wx: t.CInt, clip_wy: t.CInt, clip_ww: t.CInt, clip_r: t.CInt):
|
|
x_col: t.CUInt32T = gfx.COLOR_RGB(200, 200, 200)
|
|
if style == STYLE_CLASSIC:
|
|
bg: t.CUInt32T = gfx.COLOR_RGB(40, 40, 70)
|
|
if hover_alpha > 0:
|
|
red: t.CUInt32T = gfx.COLOR_RGB(200, 50, 50)
|
|
bg = _alpha_blend(bg, red, hover_alpha)
|
|
_fill_rect(back, bw, bh, bx, by, btn_w, btn_h, bg)
|
|
if hover_alpha > 128:
|
|
x_col = gfx.COLOR_RGB(255, 255, 255)
|
|
elif style == STYLE_WIN7:
|
|
br: t.CInt = CLOSE_BTN_W7_R
|
|
bg_r: t.CInt = 200
|
|
bg_g: t.CInt = 50
|
|
bg_b: t.CInt = 50
|
|
if hover_alpha > 0:
|
|
bg_r = 200 + ((232 - 200) * hover_alpha) / 255
|
|
bg_g = 50 + ((17 - 50) * hover_alpha) / 255
|
|
bg_b = 50 + ((35 - 50) * hover_alpha) / 255
|
|
bg_col7: t.CUInt32T = gfx.COLOR_RGB(bg_r, bg_g, bg_b)
|
|
for py2 in range(by, by + btn_h):
|
|
if py2 >= 0 and py2 < bh:
|
|
for px2 in range(bx, bx + btn_w):
|
|
if px2 >= 0 and px2 < bw:
|
|
lrx: t.CInt = px2 - bx
|
|
lry: t.CInt = py2 - by
|
|
if lry < br:
|
|
if lrx < br:
|
|
if (lrx - br) * (lrx - br) + (lry - br) * (lry - br) > br * br:
|
|
continue
|
|
elif lrx >= btn_w - br:
|
|
if (lrx - (btn_w - br - 1)) * (lrx - (btn_w - br - 1)) + (lry - br) * (lry - br) > br * br:
|
|
continue
|
|
elif lry >= btn_h - br:
|
|
if lrx < br:
|
|
if (lrx - br) * (lrx - br) + (lry - (btn_h - br - 1)) * (lry - (btn_h - br - 1)) > br * br:
|
|
continue
|
|
elif lrx >= btn_w - br:
|
|
if (lrx - (btn_w - br - 1)) * (lrx - (btn_w - br - 1)) + (lry - (btn_h - br - 1)) * (lry - (btn_h - br - 1)) > br * br:
|
|
continue
|
|
if clip_r > 0:
|
|
crx: t.CInt = px2 - clip_wx
|
|
cry: t.CInt = py2 - clip_wy
|
|
if cry < clip_r and crx >= clip_ww - clip_r:
|
|
cdx: t.CInt = crx - (clip_ww - clip_r - 1)
|
|
cdy: t.CInt = cry - clip_r
|
|
if cdx * cdx + cdy * cdy > clip_r * clip_r:
|
|
continue
|
|
back[py2 * bw + px2] = bg_col7
|
|
x_col = gfx.COLOR_RGB(255, 255, 255)
|
|
if hover_alpha > 0:
|
|
x_col = _alpha_blend(gfx.COLOR_RGB(255, 255, 255), gfx.COLOR_RGB(255, 240, 240), hover_alpha)
|
|
elif style == STYLE_WINXP:
|
|
br_xp: t.CInt = 3
|
|
bg_r_xp: t.CInt = 200
|
|
bg_g_xp: t.CInt = 50
|
|
bg_b_xp: t.CInt = 50
|
|
if hover_alpha > 0:
|
|
bg_r_xp = 200 + ((232 - 200) * hover_alpha) / 255
|
|
bg_g_xp = 50 + ((17 - 50) * hover_alpha) / 255
|
|
bg_b_xp = 50 + ((35 - 50) * hover_alpha) / 255
|
|
bg_col_xp: t.CUInt32T = gfx.COLOR_RGB(bg_r_xp, bg_g_xp, bg_b_xp)
|
|
for py_xp in range(by, by + btn_h):
|
|
if py_xp >= 0 and py_xp < bh:
|
|
for px_xp in range(bx, bx + btn_w):
|
|
if px_xp >= 0 and px_xp < bw:
|
|
lrx_xp: t.CInt = px_xp - bx
|
|
lry_xp: t.CInt = py_xp - by
|
|
if lry_xp < br_xp:
|
|
if lrx_xp < br_xp:
|
|
if (lrx_xp - br_xp) * (lrx_xp - br_xp) + (lry_xp - br_xp) * (lry_xp - br_xp) > br_xp * br_xp:
|
|
continue
|
|
elif lrx_xp >= btn_w - br_xp:
|
|
if (lrx_xp - (btn_w - br_xp - 1)) * (lrx_xp - (btn_w - br_xp - 1)) + (lry_xp - br_xp) * (lry_xp - br_xp) > br_xp * br_xp:
|
|
continue
|
|
elif lry_xp >= btn_h - br_xp:
|
|
if lrx_xp < br_xp:
|
|
if (lrx_xp - br_xp) * (lrx_xp - br_xp) + (lry_xp - (btn_h - br_xp - 1)) * (lry_xp - (btn_h - br_xp - 1)) > br_xp * br_xp:
|
|
continue
|
|
elif lrx_xp >= btn_w - br_xp:
|
|
if (lrx_xp - (btn_w - br_xp - 1)) * (lrx_xp - (btn_w - br_xp - 1)) + (lry_xp - (btn_h - br_xp - 1)) * (lry_xp - (btn_h - br_xp - 1)) > br_xp * br_xp:
|
|
continue
|
|
back[py_xp * bw + px_xp] = bg_col_xp
|
|
x_col = gfx.COLOR_RGB(255, 255, 255)
|
|
if hover_alpha > 0:
|
|
x_col = _alpha_blend(gfx.COLOR_RGB(255, 255, 255), gfx.COLOR_RGB(255, 240, 240), hover_alpha)
|
|
else:
|
|
if hover_alpha > 0:
|
|
red = gfx.COLOR_RGB(232, 17, 35)
|
|
for py3 in range(by, by + btn_h):
|
|
if py3 >= 0 and py3 < bh:
|
|
for px3 in range(bx, bx + btn_w):
|
|
if px3 >= 0 and px3 < bw:
|
|
if clip_r > 0:
|
|
crx3: t.CInt = px3 - clip_wx
|
|
cry3: t.CInt = py3 - clip_wy
|
|
if cry3 < clip_r and crx3 >= clip_ww - clip_r:
|
|
cdx3: t.CInt = crx3 - (clip_ww - clip_r - 1)
|
|
cdy3: t.CInt = cry3 - clip_r
|
|
if cdx3 * cdx3 + cdy3 * cdy3 > clip_r * clip_r:
|
|
continue
|
|
bg_pixel: t.CUInt32T = back[py3 * bw + px3]
|
|
back[py3 * bw + px3] = _alpha_blend(bg_pixel, red, hover_alpha)
|
|
x_col = gfx.COLOR_RGB(150, 150, 150)
|
|
if hover_alpha > 0:
|
|
x_col = _alpha_blend(gfx.COLOR_RGB(150, 150, 150), gfx.COLOR_RGB(255, 255, 255), hover_alpha)
|
|
cx: t.CInt = bx + btn_w // 2
|
|
cy: t.CInt = by + btn_h // 2
|
|
d: t.CInt = 3
|
|
if btn_w >= 30:
|
|
d = 4
|
|
i: t.CInt = -d
|
|
while i <= d:
|
|
px1: t.CInt = cx + i
|
|
py1: t.CInt = cy + i
|
|
px2b: t.CInt = cx + i
|
|
py2b: t.CInt = cy - i
|
|
if px1 >= 0 and px1 < bw and py1 >= 0 and py1 < bh:
|
|
if clip_r > 0:
|
|
crx1: t.CInt = px1 - clip_wx
|
|
cry1: t.CInt = py1 - clip_wy
|
|
if cry1 < clip_r and crx1 >= clip_ww - clip_r:
|
|
cdx1: t.CInt = crx1 - (clip_ww - clip_r - 1)
|
|
cdy1: t.CInt = cry1 - clip_r
|
|
if cdx1 * cdx1 + cdy1 * cdy1 > clip_r * clip_r:
|
|
i += 1
|
|
continue
|
|
back[py1 * bw + px1] = x_col
|
|
if px2b >= 0 and px2b < bw and py2b >= 0 and py2b < bh:
|
|
if clip_r > 0:
|
|
crx2: t.CInt = px2b - clip_wx
|
|
cry2: t.CInt = py2b - clip_wy
|
|
if cry2 < clip_r and crx2 >= clip_ww - clip_r:
|
|
cdx2: t.CInt = crx2 - (clip_ww - clip_r - 1)
|
|
cdy2: t.CInt = cry2 - clip_r
|
|
if cdx2 * cdx2 + cdy2 * cdy2 > clip_r * clip_r:
|
|
i += 1
|
|
continue
|
|
back[py2b * bw + px2b] = x_col
|
|
i += 1
|
|
|
|
def _draw_app_window(back: UINT32PTR, win: AppWindow | t.CPtr):
|
|
w: t.CInt = _screen_w
|
|
h: t.CInt = _screen_h
|
|
wx: t.CInt = win.x
|
|
wy: t.CInt = win.y
|
|
ww: t.CInt = _eff_w(win)
|
|
wh: t.CInt = win.h
|
|
ch: t.CInt = _eff_h(win)
|
|
style: t.CInt = win.style
|
|
th: t.CInt = _get_title_height(style)
|
|
|
|
if wy + wh <= _dirty_y_min or wy > _dirty_y_max:
|
|
return
|
|
|
|
top_idx: t.CInt = _cached_top_win
|
|
is_active: t.CInt = 0
|
|
if top_idx >= 0:
|
|
top_z: t.CInt = _wins[top_idx].z_order
|
|
if win.z_order == top_z:
|
|
is_active = 1
|
|
|
|
title_col: t.CUInt32T = gfx.COLOR_RGB(50, 50, 90)
|
|
border_col: t.CUInt32T = gfx.COLOR_RGB(100, 100, 180)
|
|
content_col: t.CUInt32T = gfx.COLOR_RGB(30, 30, 50)
|
|
outline_col: t.CUInt32T = gfx.COLOR_RGB(100, 100, 180)
|
|
title_alpha: t.CInt = 255
|
|
has_separator: t.CInt = 1
|
|
if style == STYLE_WIN10:
|
|
has_separator = 0
|
|
if is_active:
|
|
title_col = gfx.COLOR_RGB(0, 0, 0)
|
|
border_col = gfx.COLOR_RGB(0, 0, 0)
|
|
content_col = gfx.COLOR_RGB(32, 32, 32)
|
|
outline_col = gfx.COLOR_RGB(80, 80, 80)
|
|
else:
|
|
title_col = gfx.COLOR_RGB(32, 32, 32)
|
|
border_col = gfx.COLOR_RGB(32, 32, 32)
|
|
content_col = gfx.COLOR_RGB(24, 24, 24)
|
|
outline_col = gfx.COLOR_RGB(60, 60, 60)
|
|
elif style == STYLE_WIN11:
|
|
has_separator = 0
|
|
if is_active:
|
|
title_col = gfx.COLOR_RGB(32, 32, 32)
|
|
border_col = gfx.COLOR_RGB(32, 32, 32)
|
|
content_col = gfx.COLOR_RGB(32, 32, 32)
|
|
outline_col = gfx.COLOR_RGB(70, 70, 70)
|
|
else:
|
|
title_col = gfx.COLOR_RGB(40, 40, 40)
|
|
border_col = gfx.COLOR_RGB(40, 40, 40)
|
|
content_col = gfx.COLOR_RGB(40, 40, 40)
|
|
outline_col = gfx.COLOR_RGB(60, 60, 60)
|
|
elif style == STYLE_WIN7:
|
|
has_separator = 0
|
|
if is_active:
|
|
title_col = gfx.COLOR_RGB(156, 181, 209)
|
|
border_col = gfx.COLOR_RGB(156, 181, 209)
|
|
content_col = gfx.COLOR_RGB(240, 240, 240)
|
|
outline_col = gfx.COLOR_RGB(100, 130, 170)
|
|
else:
|
|
title_col = gfx.COLOR_RGB(180, 195, 210)
|
|
border_col = gfx.COLOR_RGB(180, 195, 210)
|
|
content_col = gfx.COLOR_RGB(240, 240, 240)
|
|
outline_col = gfx.COLOR_RGB(140, 155, 175)
|
|
title_alpha = 102
|
|
elif style == STYLE_WINXP:
|
|
has_separator = 0
|
|
if is_active:
|
|
title_col = gfx.COLOR_RGB(107, 158, 212)
|
|
border_col = gfx.COLOR_RGB(107, 158, 212)
|
|
content_col = gfx.COLOR_RGB(235, 235, 235)
|
|
outline_col = gfx.COLOR_RGB(43, 87, 151)
|
|
else:
|
|
title_col = gfx.COLOR_RGB(140, 160, 195)
|
|
border_col = gfx.COLOR_RGB(140, 160, 195)
|
|
content_col = gfx.COLOR_RGB(235, 235, 235)
|
|
outline_col = gfx.COLOR_RGB(100, 115, 145)
|
|
else:
|
|
if is_active:
|
|
title_col = gfx.COLOR_RGB(70, 70, 130)
|
|
border_col = gfx.COLOR_RGB(130, 130, 220)
|
|
outline_col = gfx.COLOR_RGB(130, 130, 220)
|
|
|
|
rounded: t.CInt = 0
|
|
if style == STYLE_WIN11 or style == STYLE_WIN7 or style == STYLE_WINXP:
|
|
rounded = 1
|
|
r: t.CInt = WIN_RADIUS
|
|
|
|
_draw_window_shadow(back, w, h, wx, wy, ww, wh, rounded, r)
|
|
|
|
if rounded:
|
|
for py in range(wy, wy + wh):
|
|
if py < 0 or py >= h: continue
|
|
if not _dirty_rows[py]: continue
|
|
ry: t.CInt = py - wy
|
|
row_col: t.CUInt32T = content_col
|
|
row_is_title: t.CInt = 0
|
|
row_is_sep: t.CInt = 0
|
|
if ry < th:
|
|
row_is_title = 1
|
|
if style == STYLE_WIN7:
|
|
ratio: t.CInt = (ry * 100) / th
|
|
if ratio > 100: ratio = 100
|
|
if is_active:
|
|
gr: t.CInt = 156 + ((186 - 156) * ratio) / 100
|
|
gg: t.CInt = 181 + ((209 - 181) * ratio) / 100
|
|
gb: t.CInt = 209 + ((233 - 209) * ratio) / 100
|
|
else:
|
|
gr = 180 + ((200 - 180) * ratio) / 100
|
|
gg = 195 + ((210 - 195) * ratio) / 100
|
|
gb = 210 + ((225 - 210) * ratio) / 100
|
|
row_col = gfx.COLOR_RGB(gr, gg, gb)
|
|
if ry == 0:
|
|
row_col = _alpha_blend(row_col, gfx.COLOR_RGB(220, 235, 255), 50)
|
|
elif ry == 1:
|
|
row_col = _alpha_blend(row_col, gfx.COLOR_RGB(210, 225, 250), 20)
|
|
if ry == th - 1:
|
|
row_col = _alpha_blend(row_col, gfx.COLOR_RGB(130, 160, 200), 25)
|
|
elif style == STYLE_WINXP:
|
|
ratio = (ry * 100) / th
|
|
if ratio > 100: ratio = 100
|
|
if is_active:
|
|
gr = 107 + ((58 - 107) * ratio) / 100
|
|
gg = 158 + ((124 - 158) * ratio) / 100
|
|
gb = 212 + ((195 - 212) * ratio) / 100
|
|
else:
|
|
gr = 150 + ((115 - 150) * ratio) / 100
|
|
gg = 170 + ((135 - 170) * ratio) / 100
|
|
gb = 205 + ((175 - 205) * ratio) / 100
|
|
row_col = gfx.COLOR_RGB(gr, gg, gb)
|
|
if ry == 0:
|
|
row_col = _alpha_blend(row_col, gfx.COLOR_RGB(200, 225, 255), 50)
|
|
elif ry == 1:
|
|
row_col = _alpha_blend(row_col, gfx.COLOR_RGB(200, 225, 255), 25)
|
|
if ry == th - 1:
|
|
row_col = _alpha_blend(row_col, gfx.COLOR_RGB(100, 160, 230), 40)
|
|
else:
|
|
row_col = title_col
|
|
elif ry == th and has_separator:
|
|
row_is_sep = 1
|
|
row_col = outline_col
|
|
in_corner_zone: t.CInt = 0
|
|
if ry < r or ry >= wh - r:
|
|
in_corner_zone = 1
|
|
if not in_corner_zone:
|
|
left_border: t.CInt = wx
|
|
right_border: t.CInt = wx + ww - 1
|
|
if left_border >= 0 and left_border < w:
|
|
back[py * w + left_border] = outline_col
|
|
if right_border >= 0 and right_border < w:
|
|
back[py * w + right_border] = outline_col
|
|
fill_left: t.CInt = wx + 1
|
|
fill_right: t.CInt = wx + ww - 1
|
|
if fill_left < 0: fill_left = 0
|
|
if fill_right > w: fill_right = w
|
|
fill_w: t.CInt = fill_right - fill_left
|
|
if fill_w > 0:
|
|
if row_is_title and (style == STYLE_WIN7 or style == STYLE_WINXP) and title_alpha < 255:
|
|
for fx in range(fill_left, fill_right):
|
|
bg_p: t.CUInt32T = back[py * w + fx]
|
|
back[py * w + fx] = _alpha_blend(bg_p, row_col, title_alpha)
|
|
else:
|
|
_fill_rect(back, w, h, fill_left, py, fill_w, 1, row_col)
|
|
else:
|
|
for px in range(wx, wx + ww):
|
|
if px < 0 or px >= w: continue
|
|
rx: t.CInt = px - wx
|
|
in_corner: t.CInt = 1
|
|
on_border: t.CInt = 0
|
|
if ry < r:
|
|
if rx < r:
|
|
in_corner = _is_in_corner(rx, ry, r, r, r)
|
|
elif rx >= ww - r:
|
|
in_corner = _is_in_corner(rx, ry, ww - r - 1, r, r)
|
|
elif ry >= wh - r:
|
|
if rx < r:
|
|
in_corner = _is_in_corner(rx, ry, r, wh - r - 1, r)
|
|
elif rx >= ww - r:
|
|
in_corner = _is_in_corner(rx, ry, ww - r - 1, wh - r - 1, r)
|
|
if not in_corner:
|
|
on_border = _is_on_border(rx, ry, ww, wh, r)
|
|
if not on_border:
|
|
continue
|
|
col: t.CUInt32T = row_col
|
|
is_border_pixel: t.CInt = 0
|
|
if on_border or _is_on_border(rx, ry, ww, wh, r):
|
|
col = outline_col
|
|
is_border_pixel = 1
|
|
ca: t.CInt = 255
|
|
if ry < r:
|
|
if rx < r:
|
|
ca = _corner_alpha(rx, ry, r, r, r)
|
|
elif rx >= ww - r:
|
|
ca = _corner_alpha(rx, ry, ww - r - 1, r, r)
|
|
elif ry >= wh - r:
|
|
if rx < r:
|
|
ca = _corner_alpha(rx, ry, r, wh - r - 1, r)
|
|
elif rx >= ww - r:
|
|
ca = _corner_alpha(rx, ry, ww - r - 1, wh - r - 1, r)
|
|
if is_border_pixel and ca > 0 and ca < 255:
|
|
ca = 255
|
|
if row_is_title and (style == STYLE_WIN7 or style == STYLE_WINXP) and ry >= 1 and rx >= 1 and rx < ww - 1 and ca == 255 and not is_border_pixel:
|
|
ca = title_alpha
|
|
if ca < 255:
|
|
bg_pixel: t.CUInt32T = back[py * w + px]
|
|
col = _alpha_blend(bg_pixel, col, ca)
|
|
back[py * w + px] = col
|
|
else:
|
|
_fill_rect(back, w, h, wx, wy, ww, th, title_col)
|
|
_fill_rect(back, w, h, wx, wy + th + 1, ww, ch, content_col)
|
|
if not has_separator:
|
|
_fill_rect(back, w, h, wx, wy + th, ww, 1, content_col)
|
|
if wx >= 0 and wx < w:
|
|
for py in range(wy, wy + wh):
|
|
if py >= 0 and py < h:
|
|
back[py * w + wx] = border_col
|
|
if wx + ww - 1 >= 0 and wx + ww - 1 < w:
|
|
for py in range(wy, wy + wh):
|
|
if py >= 0 and py < h:
|
|
back[py * w + wx + ww - 1] = border_col
|
|
_fill_rect(back, w, h, wx, wy, ww, 1, border_col)
|
|
_fill_rect(back, w, h, wx, wy + wh - 1, ww, 1, border_col)
|
|
if has_separator:
|
|
_fill_rect(back, w, h, wx, wy + th, ww, 1, border_col)
|
|
|
|
win_fb: UINT32PTR = win.fb
|
|
if win_fb:
|
|
fb_stride: t.CInt = win.fb_w
|
|
fbh: t.CInt = win.fb_h
|
|
if fb_stride <= 0 or fbh <= 0:
|
|
win_fb = t.CVoid(0, t.CPtr)
|
|
if win_fb:
|
|
draw_rows: t.CInt = ch
|
|
if draw_rows > fbh: draw_rows = fbh
|
|
if draw_rows < 0: draw_rows = 0
|
|
content_y: t.CInt = wy + th + 1
|
|
fb_total: t.CInt = fb_stride * fbh
|
|
for row in range(draw_rows):
|
|
dst_y: t.CInt = content_y + row
|
|
if dst_y < 0 or dst_y >= h: continue
|
|
if not _dirty_rows[dst_y]: continue
|
|
ry: t.CInt = th + 1 + row
|
|
if rounded:
|
|
if ry >= r and ry < wh - r:
|
|
src_x: t.CInt = 1
|
|
dst_x: t.CInt = wx + 1
|
|
if dst_x < 0:
|
|
src_x = src_x - dst_x
|
|
dst_x = 0
|
|
end_x: t.CInt = wx + ww - 1
|
|
if end_x > w: end_x = w
|
|
actual_w: t.CInt = end_x - dst_x
|
|
if actual_w <= 0: continue
|
|
if src_x + actual_w > fb_stride: actual_w = fb_stride - src_x
|
|
if actual_w <= 0: continue
|
|
src_off: t.CInt = row * fb_stride + src_x
|
|
if src_off + actual_w > fb_total: continue
|
|
string.memcpy(t.CVoid(t.CUInt64T(back) + (dst_y * w + dst_x) * 4, t.CPtr), t.CVoid(t.CUInt64T(win_fb) + src_off * 4, t.CPtr), actual_w * 4)
|
|
else:
|
|
copy_w: t.CInt = fb_stride - 1
|
|
if copy_w > ww - 1: copy_w = ww - 1
|
|
for col_px in range(1, copy_w):
|
|
if ry < r:
|
|
if col_px < r:
|
|
if not _is_in_corner(col_px, ry, r, r, r): continue
|
|
elif col_px >= ww - r:
|
|
if not _is_in_corner(col_px, ry, ww - r - 1, r, r): continue
|
|
elif ry >= wh - r:
|
|
if col_px < r:
|
|
if not _is_in_corner(col_px, ry, r, wh - r - 1, r): continue
|
|
elif col_px >= ww - r:
|
|
if not _is_in_corner(col_px, ry, ww - r - 1, wh - r - 1, r): continue
|
|
if _is_on_border(col_px, ry, ww, wh, r): continue
|
|
dst_x2: t.CInt = wx + col_px
|
|
if dst_x2 < 0 or dst_x2 >= w: continue
|
|
if col_px >= fb_stride: continue
|
|
px_off: t.CInt = row * fb_stride + col_px
|
|
if px_off < 0 or px_off >= fb_total: continue
|
|
back[dst_y * w + dst_x2] = win_fb[px_off]
|
|
else:
|
|
src_x2: t.CInt = 1
|
|
dst_x3: t.CInt = wx + 1
|
|
if dst_x3 < 0:
|
|
src_x2 = src_x2 - dst_x3
|
|
dst_x3 = 0
|
|
end_x2: t.CInt = wx + ww - 1
|
|
if end_x2 > w: end_x2 = w
|
|
actual_w2: t.CInt = end_x2 - dst_x3
|
|
if actual_w2 <= 0: continue
|
|
if src_x2 + actual_w2 > fb_stride: actual_w2 = fb_stride - src_x2
|
|
if actual_w2 <= 0: continue
|
|
src_off2: t.CInt = row * fb_stride + src_x2
|
|
if src_off2 + actual_w2 > fb_total: continue
|
|
string.memcpy(t.CVoid(t.CUInt64T(back) + (dst_y * w + dst_x3) * 4, t.CPtr), t.CVoid(t.CUInt64T(win_fb) + src_off2 * 4, t.CPtr), actual_w2 * 4)
|
|
|
|
btn_w: t.CInt = CLOSE_BTN_SIZE
|
|
btn_h: t.CInt = CLOSE_BTN_SIZE
|
|
btn_x: t.CInt = wx + ww - btn_w - 4
|
|
btn_y: t.CInt = wy + (th - btn_h) // 2
|
|
clip_r: t.CInt = 0
|
|
if style == STYLE_WIN7:
|
|
btn_w = CLOSE_BTN_W7_W
|
|
btn_h = CLOSE_BTN_W7_H
|
|
btn_x = wx + ww - btn_w - 5
|
|
btn_y = wy + (th - btn_h) // 2
|
|
if rounded:
|
|
clip_r = r
|
|
elif style == STYLE_WINXP:
|
|
btn_w = CLOSE_BTN_XP_SZ
|
|
btn_h = CLOSE_BTN_XP_SZ
|
|
btn_x = wx + ww - btn_w - 5
|
|
btn_y = wy + (th - btn_h) // 2
|
|
elif style == STYLE_WIN10 or style == STYLE_WIN11:
|
|
btn_w = CLOSE_BTN_W_WIN
|
|
btn_h = th - 2
|
|
btn_x = wx + ww - btn_w
|
|
btn_y = wy + 1
|
|
if rounded:
|
|
clip_r = r
|
|
_draw_close_btn(back, w, h, btn_x, btn_y, btn_w, btn_h, win.close_hover, style, wx, wy, ww, clip_r)
|
|
max_bx: t.CInt = btn_x - btn_w
|
|
if style == STYLE_WIN7 or style == STYLE_WINXP:
|
|
max_bx = btn_x - btn_w - 1
|
|
_draw_max_btn(back, w, h, max_bx, btn_y, btn_w, btn_h, win.max_hover, style, win.is_maximized)
|
|
min_bx: t.CInt = max_bx - btn_w
|
|
if style == STYLE_WIN7 or style == STYLE_WINXP:
|
|
min_bx = max_bx - btn_w - 1
|
|
_draw_min_btn(back, w, h, min_bx, btn_y, btn_w, btn_h, win.min_hover, style)
|
|
|
|
text_col: t.CUInt32T = 0xFFFFFFFF
|
|
if not is_active:
|
|
text_col = gfx.COLOR_RGB(170, 170, 170)
|
|
text_y: t.CInt = wy + (th - 16) // 2
|
|
_draw_text(back, w, h, wx + 8, text_y, c.Addr(win.title[0]), text_col)
|
|
|
|
def create(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | t.CChar | t.CPtr, style: t.CInt) -> t.CInt:
|
|
global _win_count, _next_z, _focused_win
|
|
if _win_count >= MAX_APP_WINDOWS: return -1
|
|
idx: t.CInt = _win_count
|
|
_win_count += 1
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[idx])
|
|
aw.active = 1
|
|
aw.x = x
|
|
aw.y = y
|
|
aw.w = w
|
|
aw.h = h
|
|
aw.content_h = h - _get_title_height(style) - 2
|
|
_next_z += 1
|
|
aw.z_order = _next_z
|
|
aw.style = style
|
|
aw.close_hover = 0
|
|
aw.min_hover = 0
|
|
aw.max_hover = 0
|
|
aw.is_maximized = 0
|
|
aw.orig_x = x
|
|
aw.orig_y = y
|
|
aw.orig_w = w
|
|
aw.orig_h = h
|
|
aw.pid = _current_app_pid
|
|
aw.cursor_type = 0
|
|
aw.app_cursor_type = 0
|
|
aw.fb_w = 0
|
|
aw.fb_h = 0
|
|
aw.old_fb = t.CVoid(0, t.CPtr)
|
|
aw.ping_pending = 0
|
|
aw.no_resp = 0
|
|
aw.no_resp_sec = 0
|
|
aw.minimized = 0
|
|
aw.resizable_w = 1
|
|
aw.resizable_h = 1
|
|
aw.resize_w = 0
|
|
aw.resize_h = 0
|
|
string.memset(c.Addr(aw.title), 0, 32)
|
|
string.memset(c.Addr(aw.orig_title), 0, 32)
|
|
for i in range(31):
|
|
ch: t.CChar = title[i]
|
|
if ch == 0: break
|
|
aw.title[i] = ch
|
|
aw.orig_title[i] = ch
|
|
aw.fb = mm.malloc(w * aw.content_h * 4)
|
|
aw.fb_w = w
|
|
aw.fb_h = aw.content_h
|
|
if aw.fb:
|
|
bg_col: t.CUInt32T = gfx.COLOR_RGB(25, 25, 35)
|
|
fb_size: t.CInt = w * aw.content_h
|
|
for fi in range(fb_size):
|
|
aw.fb[fi] = bg_col
|
|
_mark_rows_dirty(y, h)
|
|
_focused_win = idx
|
|
return idx
|
|
|
|
def draw_text(win_id: t.CInt, x: t.CInt, y: t.CInt, text: t.CConst | t.CChar | t.CPtr, color: t.CUInt32T) -> t.CInt:
|
|
if win_id < 0 or win_id >= _win_count: return -1
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
|
|
if not aw.active: return -1
|
|
win_fb: UINT32PTR = aw.fb
|
|
if not win_fb: return -1
|
|
fbw: t.CInt = aw.fb_w
|
|
fbh: t.CInt = aw.fb_h
|
|
_draw_text(win_fb, fbw, fbh, x, y, text, color)
|
|
_mark_rows_dirty(aw.y + _get_title_height(aw.style) + 1 + y, 16)
|
|
return 0
|
|
|
|
def set_app_pid(pid: t.CInt):
|
|
global _current_app_pid
|
|
_current_app_pid = pid
|
|
|
|
def is_active(win_id: t.CInt) -> t.CInt:
|
|
if win_id < 0 or win_id >= _win_count: return 0
|
|
return _wins[win_id].active
|
|
|
|
def get_fb(win_id: t.CInt) -> UINT32PTR:
|
|
if win_id < 0 or win_id >= _win_count: return t.CVoid(0, t.CPtr)
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
|
|
if not aw.active: return t.CVoid(0, t.CPtr)
|
|
if aw.old_fb:
|
|
mm.free(aw.old_fb)
|
|
aw.old_fb = t.CVoid(0, t.CPtr)
|
|
if aw.resize_w != 0 and (aw.fb_w != aw.resize_w or aw.fb_h != aw.resize_h):
|
|
target_w: t.CInt = aw.resize_w
|
|
target_h: t.CInt = aw.resize_h
|
|
if target_w <= 0 or target_h <= 0:
|
|
aw.resize_w = 0
|
|
aw.resize_h = 0
|
|
return aw.fb
|
|
new_fb_sz_gf: t.CInt = target_w * target_h
|
|
new_fb_gf: UINT32PTR = mm.malloc(new_fb_sz_gf * 4)
|
|
if not new_fb_gf:
|
|
aw.resize_w = 0
|
|
aw.resize_h = 0
|
|
return aw.fb
|
|
old_fb_gf: UINT32PTR = aw.fb
|
|
old_fbw_gf: t.CInt = aw.fb_w
|
|
old_fbh_gf: t.CInt = aw.fb_h
|
|
aw.fb = new_fb_gf
|
|
aw.fb_w = target_w
|
|
aw.fb_h = target_h
|
|
aw.w = target_w
|
|
aw.content_h = target_h
|
|
aw.resize_w = 0
|
|
aw.resize_h = 0
|
|
bg_gf: t.CUInt32T = gfx.COLOR_RGB(30, 30, 50)
|
|
for fi_gf in range(new_fb_sz_gf):
|
|
aw.fb[fi_gf] = bg_gf
|
|
if old_fb_gf:
|
|
cph_gf: t.CInt = old_fbh_gf
|
|
if cph_gf > target_h: cph_gf = target_h
|
|
for ri_gf in range(cph_gf):
|
|
rb_gf: t.CInt = old_fbw_gf
|
|
if rb_gf > target_w: rb_gf = target_w
|
|
string.memcpy(t.CVoid(t.CUInt64T(aw.fb) + ri_gf * target_w * 4, t.CPtr), t.CVoid(t.CUInt64T(old_fb_gf) + ri_gf * old_fbw_gf * 4, t.CPtr), rb_gf * 4)
|
|
if aw.old_fb:
|
|
mm.free(aw.old_fb)
|
|
aw.old_fb = old_fb_gf
|
|
return aw.fb
|
|
|
|
def get_size(win_id: t.CInt) -> t.CInt:
|
|
if win_id < 0 or win_id >= _win_count: return 0
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
|
|
if not aw.active: return 0
|
|
return (aw.fb_w << 16) | (aw.fb_h & 0xFFFF)
|
|
|
|
_NO_RESP_SUFFIX: t.CArray[t.CChar, 14] = " - (No Resp)"
|
|
|
|
def _update_no_resp_title(win_id: t.CInt, mark: t.CInt):
|
|
if win_id < 0 or win_id >= _win_count: return
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
|
|
if not aw.active: return
|
|
string.memset(c.Addr(aw.title), 0, 32)
|
|
if mark:
|
|
j: t.CInt = 0
|
|
for ch in aw.orig_title:
|
|
if j >= 31: break
|
|
if ch == 0: break
|
|
aw.title[j] = ch
|
|
j += 1
|
|
for sc in _NO_RESP_SUFFIX:
|
|
if j >= 13: break
|
|
if sc == 0: break
|
|
if j < 31:
|
|
aw.title[j] = sc
|
|
j += 1
|
|
else:
|
|
j2: t.CInt = 0
|
|
for ch2 in aw.orig_title:
|
|
if j2 >= 31: break
|
|
if ch2 == 0: break
|
|
aw.title[j2] = ch2
|
|
j2 += 1
|
|
_mark_rows_dirty(aw.y, _get_title_height(aw.style) + 2)
|
|
|
|
def _heartbeat_check():
|
|
global _hb_last_sec
|
|
cur_sec: t.CUInt32T = timer.timer_get_seconds()
|
|
if cur_sec - _hb_last_sec < HB_INTERVAL_SEC: return
|
|
_hb_last_sec = cur_sec
|
|
for i in range(_win_count):
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[i])
|
|
if not aw.active:
|
|
continue
|
|
if aw.pid == 0:
|
|
continue
|
|
if aw.ping_pending:
|
|
if not aw.no_resp:
|
|
aw.no_resp = 1
|
|
aw.no_resp_sec = cur_sec
|
|
_update_no_resp_title(i, 1)
|
|
else:
|
|
elapsed: t.CUInt32T = cur_sec - aw.no_resp_sec
|
|
if elapsed >= HB_NO_RESP_SEC:
|
|
aw.active = 0
|
|
_mark_rows_dirty(aw.y, aw.h)
|
|
p_ref: process.Process | t.CPtr = process.ProcessManager.get_process(aw.pid)
|
|
if p_ref is not None:
|
|
p_ref.exit()
|
|
else:
|
|
aw.ping_pending = 1
|
|
evt: InputEvent
|
|
string.memset(c.Addr(evt), 0, INPUT_EVENT_SIZE)
|
|
evt.type = EVENT_TYPE_PING
|
|
evt.win_id = i
|
|
_push_event(evt)
|
|
|
|
def flush(win_id: t.CInt):
|
|
if win_id < 0 or win_id >= _win_count: return
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
|
|
if not aw.active: return
|
|
if aw.old_fb:
|
|
mm.free(aw.old_fb)
|
|
aw.old_fb = t.CVoid(0, t.CPtr)
|
|
if aw.ping_pending:
|
|
aw.ping_pending = 0
|
|
if aw.no_resp:
|
|
aw.no_resp = 0
|
|
aw.no_resp_sec = 0
|
|
_update_no_resp_title(win_id, 0)
|
|
_mark_rows_dirty(aw.y + _get_title_height(aw.style) + 1, _eff_h(aw))
|
|
|
|
def set_title(win_id: t.CInt, title: t.CConst | t.CChar | t.CPtr) -> t.CInt:
|
|
if win_id < 0 or win_id >= _win_count: return -1
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
|
|
if not aw.active: return -1
|
|
string.memset(c.Addr(aw.title), 0, 32)
|
|
string.memset(c.Addr(aw.orig_title), 0, 32)
|
|
for i in range(31):
|
|
ch: t.CChar = title[i]
|
|
if ch == 0: break
|
|
aw.title[i] = ch
|
|
aw.orig_title[i] = ch
|
|
_mark_rows_dirty(aw.y, _get_title_height(aw.style) + 2)
|
|
return 0
|
|
|
|
def set_geometry(win_id: t.CInt, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.CInt:
|
|
if win_id < 0 or win_id >= _win_count: return -1
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
|
|
if not aw.active: return -1
|
|
old_y: t.CInt = aw.y
|
|
old_h: t.CInt = aw.h
|
|
aw.x = x
|
|
aw.y = y
|
|
aw.resize_w = w
|
|
aw.resize_h = h - _get_title_height(aw.style) - 2
|
|
aw.h = h
|
|
_mark_rows_dirty(old_y, old_h)
|
|
_mark_rows_dirty(y, h)
|
|
return 0
|
|
|
|
def set_resizable(win_id: t.CInt, rw: t.CInt, rh: t.CInt) -> t.CInt:
|
|
if win_id < 0 or win_id >= _win_count: return -1
|
|
aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
|
|
if not aw.active: return -1
|
|
aw.resizable_w = rw
|
|
aw.resizable_h = rh
|
|
return 0
|
|
|
|
def destroy_by_pid(pid: t.CInt):
|
|
global _focused_win, _last_hover_win
|
|
for i in range(_win_count):
|
|
if _wins[i].pid == pid and _wins[i].active:
|
|
_wins[i].active = 0
|
|
_mark_rows_dirty(_wins[i].y, _wins[i].h)
|
|
if _focused_win == i:
|
|
_focused_win = -1
|
|
if _last_hover_win == i:
|
|
_last_hover_win = -1
|
|
if _focused_win < 0:
|
|
for j in range(_win_count - 1, -1, -1):
|
|
if _wins[j].active and not _wins[j].minimized:
|
|
_focused_win = j
|
|
break
|