forked from KolibriOS/kolibrios
266 lines
8.6 KiB
HTML
266 lines
8.6 KiB
HTML
; =============================================================================
|
||
; Модуль : 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
|