"""Standalone harness for windows/webview2_browser.py — no Kivy, no player. Creates a plain Win32 window, embeds WebView2 in it via the same WebView2Browser class the player uses, navigates to a page, checks that the page actually becomes visible, then resizes and tears down. Run: windows\\venv\\Scripts\\python.exe windows\\test_webview2_embed.py Exit code 0 = embedded engine works. """ import ctypes import os import sys import time from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) URL = os.environ.get('KIWY_TEST_URL', 'https://example.com/') user32 = ctypes.windll.user32 kernel32 = ctypes.windll.kernel32 WNDPROC = ctypes.WINFUNCTYPE( ctypes.c_int64, ctypes.c_void_p, # HWND ctypes.c_uint, # UINT msg ctypes.c_void_p, # WPARAM ctypes.c_void_p, # LPARAM ) _messages = [] @WNDPROC def _wnd_proc(hwnd, msg, wparam, lparam): _messages.append(msg) if msg == 0x0002: # WM_DESTROY user32.PostQuitMessage(0) return 0 user32.DefWindowProcW.restype = ctypes.c_int64 user32.DefWindowProcW.argtypes = [ ctypes.c_void_p, ctypes.c_uint, ctypes.c_void_p, ctypes.c_void_p, ] return user32.DefWindowProcW(hwnd, msg, wparam, lparam) def _make_window(width=1280, height=720): """Register a class and create a visible top-level window.""" hinstance = kernel32.GetModuleHandleW(None) class_name = 'KiwyWebView2Test' class WNDCLASSEX(ctypes.Structure): _fields_ = [ ('cbSize', ctypes.c_uint), ('style', ctypes.c_uint), ('lpfnWndProc', WNDPROC), ('cbClsExtra', ctypes.c_int), ('cbWndExtra', ctypes.c_int), ('hInstance', ctypes.c_void_p), ('hIcon', ctypes.c_void_p), ('hCursor', ctypes.c_void_p), ('hbrBackground', ctypes.c_void_p), ('lpszMenuName', ctypes.c_wchar_p), ('lpszClassName', ctypes.c_wchar_p), ('hIconSm', ctypes.c_void_p), ] wc = WNDCLASSEX() wc.cbSize = ctypes.sizeof(WNDCLASSEX) wc.style = 0x0002 | 0x0001 # CS_HREDRAW | CS_VREDRAW wc.lpfnWndProc = _wnd_proc wc.hInstance = hinstance wc.hbrBackground = ctypes.c_void_p(6) # COLOR_WINDOW+1 wc.lpszClassName = class_name user32.RegisterClassExW(ctypes.byref(wc)) hwnd = user32.CreateWindowExW( 0, class_name, 'Kiwy WebView2 Embed Test', 0x00CF0000 | 0x10000000, # WS_OVERLAPPEDWINDOW | WS_VISIBLE 100, 100, width, height, 0, 0, hinstance, 0, ) if not hwnd: raise RuntimeError(f'CreateWindowExW failed (err={kernel32.GetLastError()})') user32.UpdateWindow(hwnd) return hwnd def _pump(seconds): """Pump Win32 messages — WebView2 needs this to deliver its callbacks.""" deadline = time.monotonic() + seconds while time.monotonic() < deadline: msg = ctypes.wintypes.MSG() if hasattr(ctypes, 'wintypes') else None import ctypes.wintypes as wt msg = wt.MSG() while user32.PeekMessageW(ctypes.byref(msg), None, 0, 0, 1): user32.TranslateMessage(ctypes.byref(msg)) user32.DispatchMessageW(ctypes.byref(msg)) time.sleep(0.02) def main(): print('=' * 68) print(' WebView2 embedded-engine test') print('=' * 68) from webview2_browser import WebView2Browser print(f'SDK dir : {WebView2Browser.__module__}') available = WebView2Browser.is_available() print(f'available: {available}') if not available: print(f'REASON: {WebView2Browser._import_error}') return 1 hwnd = _make_window() print(f'window : hwnd=0x{hwnd:x}') browser = WebView2Browser(hwnd_provider=lambda: hwnd) started = time.monotonic() ok = browser.show(URL) print(f'show() : {ok}') if not ok: print(f'FAILED : {browser.failed_reason}') return 1 # Drive the Kivy-style Clock poll manually while pumping messages. visible = False while time.monotonic() - started < 25: browser._tick(0) # consume the async task _pump(0.1) if browser.failed_reason: print(f'FAILED : {browser.failed_reason}') return 1 if browser.is_showing(): visible = True break print(f'visible : {visible} after {time.monotonic() - started:.1f}s') if not visible: print('FAILED : page never became visible') return 1 # Resize to the signage resolution and confirm it is applied. browser.resize(1920, 1080) _pump(1.0) print(f'resized : 1920x1080 (bounds={browser._size})') # Hide, then re-show to prove the controller survives a transition. browser.hide() _pump(0.5) print(f'after hide -> is_showing={browser.is_showing()}') browser.show(URL) _pump(2.0) print(f'after re-show -> is_showing={browser.is_showing()}') browser.shutdown() print('shutdown: ok') print('=' * 68) print(' RESULT: PASS') print('=' * 68) return 0 if __name__ == '__main__': sys.exit(main())