mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 04:04:09 +02:00
Add a headless test mode to ft-screens and a throwaway test desktop
ft-screens --no-vr runs without SteamVR and leaves the input relay alone; --control names its control socket; "toplevels" lists KWin's windows with their titles and sizes; "input" feeds pointer events as if from a panel. screens/test/headless.sh starts it with a bare nested KWin next to the running desktop, and loads KWin scripts, runs apps, and takes screenshots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0a88a6b7c9
commit
42a755b9f4
4 files changed
+272
-12
No files matched your search
+13
-1
@@ -206,6 +206,7 @@ constexpr double kRollStep = 5; // degrees per scroll notch on the roll but
|
||||
constexpr float kChromeIdle = 0.55f; // the controls' opacity without a laser on them
|
||||
constexpr long kControlsLinger = 35; // ticks (~0.4 s) the controls stay after a laser leaves
|
||||
long g_tick = 0; // ft_vr_poll calls
|
||||
bool g_vr = false; // connected to SteamVR (ft-screens --no-vr runs without it)
|
||||
constexpr vr::TrackedDeviceIndex_t kNone = vr::k_unTrackedDeviceIndexInvalid;
|
||||
|
||||
struct Screen {
|
||||
@@ -1150,6 +1151,7 @@ bool ft_vr_init(void) {
|
||||
std::fprintf(stderr, "openvr: no IVRIPCResourceManagerClient (SteamVR too old?)\n");
|
||||
return false;
|
||||
}
|
||||
g_vr = true;
|
||||
RefreshPoses();
|
||||
// The catcher (see UpdateCatcher): clear and invisible, but the laser lands on it, and
|
||||
// it keeps SteamVR's laser mouse on while it's up.
|
||||
@@ -1165,6 +1167,7 @@ bool ft_vr_init(void) {
|
||||
}
|
||||
|
||||
void ft_vr_shutdown(void) {
|
||||
if (!g_vr) return;
|
||||
if (g_catcher != vr::k_ulOverlayHandleInvalid) vr::VROverlay()->DestroyOverlay(g_catcher);
|
||||
g_catcher = vr::k_ulOverlayHandleInvalid;
|
||||
for (auto &[i, s] : g_screens)
|
||||
@@ -1179,14 +1182,20 @@ void ft_vr_shutdown(void) {
|
||||
}
|
||||
|
||||
int ft_vr_modifiers(uint32_t format, uint64_t *out, int max) {
|
||||
if (!g_vr) { // --no-vr: nothing imports the buffers, so any layout KWin can draw
|
||||
if (max < 1) return 0;
|
||||
out[0] = 0; // DRM_FORMAT_MOD_LINEAR
|
||||
return 1;
|
||||
}
|
||||
uint32_t n = uint32_t(max);
|
||||
if (!vr::VRIPCResourceManager()->GetDmabufModifiers(vr::VRApplication_Overlay, format, &n, out)) return 0;
|
||||
return int(n < uint32_t(max) ? n : uint32_t(max));
|
||||
}
|
||||
|
||||
bool ft_vr_screens_shown(void) { return ModeVisible(); }
|
||||
bool ft_vr_screens_shown(void) { return g_vr && ModeVisible(); }
|
||||
|
||||
void ft_vr_screen_create(int index, double metres, int count) {
|
||||
if (!g_vr) return;
|
||||
Screen &s = g_screens[index];
|
||||
s.metres = metres;
|
||||
char key[64], name[64];
|
||||
@@ -1237,6 +1246,7 @@ void ft_vr_screen_destroy(int index) {
|
||||
}
|
||||
|
||||
bool ft_vr_screen_present(int index, const void *key, const struct ft_dmabuf *b) {
|
||||
if (!g_vr) return false;
|
||||
auto sit = g_screens.find(index);
|
||||
if (sit == g_screens.end()) return false;
|
||||
Screen &s = sit->second;
|
||||
@@ -1284,6 +1294,7 @@ void ft_vr_forget(const void *key) {
|
||||
}
|
||||
|
||||
void ft_vr_poll(void (*handle)(const struct ft_event *, void *), void *data) {
|
||||
if (!g_vr) return;
|
||||
RefreshPoses();
|
||||
for (auto &[index, s] : g_screens) {
|
||||
vr::VREvent_t ev;
|
||||
@@ -1438,6 +1449,7 @@ void ft_vr_poll(void (*handle)(const struct ft_event *, void *), void *data) {
|
||||
// (size <screen> <w> <h> and key <code> <value> are handled in compositor.c.) Screens are
|
||||
// numbered from 1 here, like everywhere the user sees them.
|
||||
void ft_vr_command(const char *cmd, char *reply, int size) {
|
||||
if (!g_vr) return (void)std::snprintf(reply, size, "error no SteamVR (--no-vr)");
|
||||
RefreshPoses();
|
||||
int n;
|
||||
double x, y, z, yaw, pitch, roll, w;
|
||||
|
||||
Reference in new issue
Block a user