Foxe Chen | b90c239 | 2025-06-27 21:10:35 +0200 | [diff] [blame] | 1 | source check.vim |
| 2 | source shared.vim |
| 3 | |
| 4 | CheckFeature job |
| 5 | CheckUnix |
| 6 | |
| 7 | let g:xdisplay_num = 100 |
| 8 | |
| 9 | " Each key is the display name and its value is the compositor/wm job |
| 10 | let s:wayland_displays = {} |
| 11 | let s:x11_displays = {} |
| 12 | |
| 13 | command -nargs=0 CheckWaylandCompositor call CheckWaylandCompositor() |
| 14 | command -nargs=0 CheckXServer call CheckXServer() |
| 15 | |
| 16 | func CheckWaylandCompositor() |
| 17 | CheckFeature wayland |
| 18 | |
| 19 | if executable("labwc") != 1 |
| 20 | throw "Skipped: labwc is not available" |
| 21 | endif |
| 22 | endfunc |
| 23 | |
| 24 | func CheckXServer() |
| 25 | CheckFeature x11 |
| 26 | |
| 27 | if executable("Xvfb") != 1 |
| 28 | throw "Skipped: Xvfb is not available" |
| 29 | endif |
| 30 | if executable("xdpyinfo") != 1 |
| 31 | throw "Skipped: xdpyinfo is not available" |
| 32 | endif |
| 33 | endfunc |
| 34 | |
| 35 | func s:StartCompositorOutput(channel, msg) |
| 36 | let l:display = matchstr(a:msg, 'WAYLAND_DISPLAY=\zs.\+') |
| 37 | |
| 38 | if !empty(l:display) |
| 39 | let s:wayland_display_name = l:display |
| 40 | endif |
| 41 | endfunc |
| 42 | |
| 43 | func s:StartCompositorExit(job, status) |
| 44 | if s:wayland_display_name == "" |
| 45 | throw "Error: Wayland compositor exited when starting up" |
| 46 | endif |
| 47 | endfunc |
| 48 | |
| 49 | func StartWaylandCompositor() |
| 50 | let s:wayland_display_name = "" |
| 51 | |
| 52 | let l:wayland_compositor_job = job_start( |
| 53 | \ ['labwc', '-c', 'NONE', '-d'], { |
| 54 | \ 'err_io': 'pipe', |
| 55 | \ 'err_cb': function('s:StartCompositorOutput'), |
| 56 | \ 'err_mode': 'nl', |
| 57 | \ 'exit_cb': function('s:StartCompositorExit'), |
| 58 | \ 'env': { 'WLR_BACKENDS': 'headless' } |
| 59 | \ }) |
| 60 | |
| 61 | call WaitForAssert({-> assert_equal("run", |
| 62 | \ job_status(l:wayland_compositor_job))}) |
| 63 | call WaitForAssert({-> assert_match('.\+', s:wayland_display_name)}) |
| 64 | |
| 65 | let s:wayland_displays[s:wayland_display_name] = l:wayland_compositor_job |
| 66 | |
| 67 | return s:wayland_display_name |
| 68 | endfunc |
| 69 | |
| 70 | func EndWaylandCompositor(display) |
| 71 | let l:job = s:wayland_displays[a:display] |
| 72 | |
| 73 | call job_stop(l:job, 'term') |
| 74 | |
| 75 | " Block until compositor is actually gone |
| 76 | call WaitForAssert({-> assert_equal("dead", job_status(l:job))}) |
| 77 | |
| 78 | unlet s:wayland_displays[a:display] |
| 79 | endfunc |
| 80 | |
| 81 | " Start a separate X11 server instance |
| 82 | func StartXServer() |
| 83 | let l:xdisplay = ':' .. g:xdisplay_num |
| 84 | |
| 85 | let l:x11_server_job = job_start(['Xvfb', l:xdisplay], {}) |
| 86 | |
| 87 | call WaitForAssert({-> assert_equal("run", job_status(l:x11_server_job))}) |
| 88 | " Check if server is ready. Not sure if this is the best way though... |
| 89 | call WaitFor({-> system("DISPLAY=" .. l:xdisplay .. " xdpyinfo 2> /dev/null") |
| 90 | \ =~? '.\+'}) |
| 91 | |
| 92 | g:xdisplay_num += 1 |
| 93 | |
| 94 | let s:x11_displays[l:xdisplay] = l:x11_server_job |
| 95 | |
| 96 | return l:xdisplay |
| 97 | endfunc |
| 98 | |
| 99 | func EndXServer(display) |
| 100 | let l:job = s:x11_displays[a:display] |
| 101 | |
| 102 | call job_stop(l:job) |
| 103 | |
| 104 | " Block until X server is actually gone |
| 105 | call WaitForAssert({-> assert_equal("dead", job_status(l:job))}) |
| 106 | |
| 107 | unlet s:x11_displays[a:display] |
| 108 | endfunc |
| 109 | |
| 110 | " vim: shiftwidth=2 sts=2 expandtab |