Files
kolibrios/drivers/vboxguest/services/seamless/seamless.inc
2026-03-04 21:16:17 +03:00

266 lines
8.6 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
; =============================================================================
; Модуль : VMMDev Seamless Mode Service
; Назначение : Получение запросов на seamless mode от хоста
; Файл : services/seamless/seamless.inc
; Протокол : VMMDevReq_GetSeamlessChangeRequest (73)
;
; Seamless mode = «бесшовные окна»: окна гостя рисуются как окна хоста,
; без рамки VM. Хост периодически спрашивает гостя: «какие области экрана
; заняты окнами?» (visible region).
;
; Для KolibriOS полный seamless пока невозможен (нет API получения
; регионов окон), но мы:
; 1. Сообщаем хосту VMMDEV_GUEST_SUPPORTS_SEAMLESS → кнопка
; «View → Seamless Mode» в VBox GUI станет активной
; 2. Получаем события SEAMLESS_MODE_CHANGE через IRQ
; 3. Запрашиваем текущий режим через GetSeamlessChangeRequest
; 4. При включении seamless → отправляем visible region = весь экран
; (один прямоугольник 0,0 → width,height)
;
; Архитектура (как display):
; IRQ event → seamless_handle_event → pending=1, timestamp
; Timer tick → seamless_tick → если pending и debounce прошёл → обработать
; =============================================================================
svc_seamless_name db "SEAMLESS", 0
; --- Data ---
align 4
vbox_seamless_enabled dd 0
vbox_seamless_current_mode dd 0 ; VMMDEV_SEAMLESS_*
vbox_seamless_pending dd 0
vbox_seamless_event_time dd 0
; Debounce: 500ms (50 тиков * 10ms)
SEAMLESS_DELAY_TICKS equ 50
; --- Пакет GetSeamlessChangeRequest ---
align 4
vmmdev_seamless_change_s VMMDEV_SEAMLESS_CHANGE_REQUEST \
<sizeof.VMMDEV_SEAMLESS_CHANGE_REQUEST, \
VMMDEV_REQUEST_HEADER_VERSION, \
VMMDEV_REQ_GET_SEAMLESS_CHANGE, \
0, 0, 0>, \
0, \
VMMDEV_EVENT_SEAMLESS_MODE_CHANGE ; eventAck
align 4
seamless_change_virt dd 0
seamless_change_phys dd 0
; --- Пакет VideoSetVisibleRegion (1 прямоугольник) ---
align 4
vmmdev_visible_region_s VMMDEV_VIDEO_SET_VISIBLE_REGION \
<sizeof.VMMDEV_VIDEO_SET_VISIBLE_REGION, \
VMMDEV_REQUEST_HEADER_VERSION, \
VMMDEV_REQ_VIDEO_SET_VISIBLE_REGION, \
0, 0, 0>, \
1, \
<0, 0, 0, 0> ; rect0: заполняется при вызове
align 4
visible_region_virt dd 0
visible_region_phys dd 0
; seamless_init — Инициализация
proc seamless_init uses ebx
DEBUGF 2, "[VBoxGuest] [Seamless] Initializing...\n"
; --- Физические адреса пакетов ---
mov eax, vmmdev_seamless_change_s
mov [seamless_change_virt], eax
invoke GetPhysAddr
test eax, eax
jz .phys_failed
mov [seamless_change_phys], eax
mov eax, vmmdev_visible_region_s
mov [visible_region_virt], eax
invoke GetPhysAddr
test eax, eax
jz .phys_failed
mov [visible_region_phys], eax
DEBUGF __DEBUG_SEAMLESS__, "[VBoxGuest] [Seamless] SeamlessChange pkt: virt=0x%x phys=0x%x\n", \
[seamless_change_virt], [seamless_change_phys]
DEBUGF __DEBUG_SEAMLESS__, "[VBoxGuest] [Seamless] VisibleRegion pkt: virt=0x%x phys=0x%x\n", \
[visible_region_virt], [visible_region_phys]
mov dword [vbox_seamless_enabled], 1
mov dword [vbox_seamless_current_mode], VMMDEV_SEAMLESS_DISABLED
; Сразу запросить текущий режим (может быть уже включен)
call seamless_query_mode
DEBUGF 2, "[VBoxGuest] [Seamless] Initialized OK (mode=%d)\n", \
[vbox_seamless_current_mode]
xor eax, eax
ret
.phys_failed:
DEBUGF 2, "[VBoxGuest] [Seamless] GetPhysAddr failed\n"
mov eax, VERR_GENERAL_FAILURE
ret
endp
; seamless_handle_event — Из IRQ контекста
proc seamless_handle_event
test eax, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE
jz .done
cmp dword [vbox_seamless_enabled], 0
je .done
invoke GetTimerTicks
mov [vbox_seamless_event_time], eax
mov dword [vbox_seamless_pending], 1
DEBUGF __DEBUG_SEAMLESS__, "[VBoxGuest] [Seamless] Event queued\n"
.done:
ret
endp
; seamless_tick — Из таймера, debounce
proc seamless_tick
cmp dword [vbox_seamless_pending], 0
je .done
invoke GetTimerTicks
sub eax, [vbox_seamless_event_time]
cmp eax, SEAMLESS_DELAY_TICKS
jb .done
mov dword [vbox_seamless_pending], 0
DEBUGF __DEBUG_SEAMLESS__, "[VBoxGuest] [Seamless] Processing mode change...\n"
call seamless_query_mode
.done:
ret
endp
; seamless_query_mode — Запросить текущий seamless mode у хоста (req 73)
proc seamless_query_mode uses ebx edi
mov edi, [seamless_change_virt]
test edi, edi
jz .bad_ptr
; Заполнить запрос
mov dword [edi + VMMDEV_SEAMLESS_CHANGE_REQUEST.header.rc], 0
mov dword [edi + VMMDEV_SEAMLESS_CHANGE_REQUEST.mode], 0
mov dword [edi + VMMDEV_SEAMLESS_CHANGE_REQUEST.eventAck], \
VMMDEV_EVENT_SEAMLESS_MODE_CHANGE
; Отправить
stdcall vmmdev_send_request, [seamless_change_phys]
; Проверить rc
mov eax, [edi + VMMDEV_SEAMLESS_CHANGE_REQUEST.header.rc]
test eax, eax
jnz .error
; Прочитать режим
mov eax, [edi + VMMDEV_SEAMLESS_CHANGE_REQUEST.mode]
mov ebx, [vbox_seamless_current_mode]
mov [vbox_seamless_current_mode], eax
DEBUGF 2, "[VBoxGuest] [Seamless] Mode: %d → %d\n", ebx, eax
; Обработать смену режима
cmp eax, VMMDEV_SEAMLESS_DISABLED
je .mode_disabled
cmp eax, VMMDEV_SEAMLESS_VISIBLE_REGION
je .mode_visible_region
cmp eax, VMMDEV_SEAMLESS_HOST_WINDOW
je .mode_host_window
DEBUGF 2, "[VBoxGuest] [Seamless] Unknown mode: %d\n", eax
ret
.mode_disabled:
DEBUGF 2, "[VBoxGuest] [Seamless] Seamless DISABLED\n"
ret
.mode_visible_region:
DEBUGF 2, "[VBoxGuest] [Seamless] Seamless ENABLED (visible region)\n"
; Отправить видимую область = весь экран
call seamless_send_fullscreen_region
ret
.mode_host_window:
DEBUGF 2, "[VBoxGuest] [Seamless] Seamless ENABLED (host window)\n"
call seamless_send_fullscreen_region
ret
.bad_ptr:
DEBUGF 2, "[VBoxGuest] [Seamless] Bad pointer\n"
ret
.error:
DEBUGF 2, "[VBoxGuest] [Seamless] GetSeamlessChange failed: rc=0x%x\n", eax
ret
endp
; seamless_send_fullscreen_region — Отправить visible region = весь экран
proc seamless_send_fullscreen_region uses ebx edi
mov edi, [visible_region_virt]
test edi, edi
jz .bad_ptr
; Получить текущее разрешение из KOS
invoke GetDisplay
test eax, eax
jz .no_display
mov ebx, eax
mov ecx, [ebx + DISPLAY.width]
mov edx, [ebx + DISPLAY.height]
DEBUGF 1, "[VBoxGuest] [Seamless] Sending region: 0,0 → %d,%d\n", ecx, edx
; Заполнить заголовок
mov dword [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.header.rc], 0
; Заполнить прямоугольник
mov dword [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.cRect], 1
mov dword [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.rect0.xLeft], 0
mov dword [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.rect0.yTop], 0
mov [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.rect0.xRight], ecx
mov [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.rect0.yBottom], edx
; Отправить
stdcall vmmdev_send_request, [visible_region_phys]
mov eax, [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.header.rc]
test eax, eax
jnz .error
DEBUGF 1, "[VBoxGuest] [Seamless] Region sent OK\n"
xor eax, eax
ret
.bad_ptr:
DEBUGF 2, "[VBoxGuest] [Seamless] Bad pointer\n"
ret
.no_display:
DEBUGF 2, "[VBoxGuest] [Seamless] No display\n"
ret
.error:
DEBUGF 2, "[VBoxGuest] [Seamless] SetVisibleRegion failed: rc=0x%x\n", eax
ret
endp
; seamless_disable — Выключить seamless
proc seamless_disable
DEBUGF 2, "[VBoxGuest] [Seamless] Disabling...\n"
mov dword [vbox_seamless_enabled], 0
mov dword [vbox_seamless_pending], 0
mov dword [vbox_seamless_current_mode], VMMDEV_SEAMLESS_DISABLED
xor eax, eax
ret
endp
REGISTER_SERVICE svc_seamless_name, SEAMLESS_EVENT_MASK, VMMDEV_GUEST_SUPPORTS_SEAMLESS, \
seamless_init, 0, seamless_disable, seamless_handle_event, seamless_tick, AUTOSTART_SEAMLESS