The open source OpenXR runtime
1#!/usr/bin/env luajit
2-- Copyright 2020-2023, Collabora, Ltd.
3-- SPDX-License-Identifier: BSL-1.0
4-- Author: Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
5
6local ffi = require("ffi")
7
8ffi.cdef[[
9typedef enum mnd_result
10{
11 MND_SUCCESS = 0,
12 MND_ERROR_INVALID_VERSION = -1,
13 MND_ERROR_INVALID_VALUE = -2,
14 MND_ERROR_CONNECTING_FAILED = -3,
15 MND_ERROR_OPERATION_FAILED = -4,
16} mnd_result_t;
17
18typedef enum mnd_client_flags
19{
20 MND_CLIENT_PRIMARY_APP = (1u << 0u),
21 MND_CLIENT_SESSION_ACTIVE = (1u << 1u),
22 MND_CLIENT_SESSION_VISIBLE = (1u << 2u),
23 MND_CLIENT_SESSION_FOCUSED = (1u << 3u),
24 MND_CLIENT_SESSION_OVERLAY = (1u << 4u),
25 MND_CLIENT_IO_ACTIVE = (1u << 5u),
26} mnd_client_flags_t;
27
28typedef struct mnd_root mnd_root_t;
29
30void
31mnd_api_get_version(uint32_t *out_major, uint32_t *out_minor, uint32_t *out_patch);
32
33mnd_result_t
34mnd_root_create(mnd_root_t **out_root);
35
36void
37mnd_root_destroy(mnd_root_t **root_ptr);
38
39mnd_result_t
40mnd_root_update_client_list(mnd_root_t *root);
41
42mnd_result_t
43mnd_root_get_number_clients(mnd_root_t *root, uint32_t *out_num);
44
45mnd_result_t
46mnd_root_get_client_id_at_index(mnd_root_t *root, uint32_t index, uint32_t *out_client_id);
47
48mnd_result_t
49mnd_root_get_client_name(mnd_root_t *root, uint32_t client_id, const char **out_name);
50
51mnd_result_t
52mnd_root_get_client_state(mnd_root_t *root, uint32_t client_id, uint32_t *out_flags);
53
54mnd_result_t
55mnd_root_set_client_primary(mnd_root_t *root, uint32_t client_id);
56
57mnd_result_t
58mnd_root_set_client_focused(mnd_root_t *root, uint32_t client_id);
59
60mnd_result_t
61mnd_root_toggle_client_io_active(mnd_root_t *root, uint32_t client_id);
62]]
63
64local status, lib = pcall(ffi.load, "libmonado.so")
65if not status then
66 print("Could not find an installed libmonado.so in your path.")
67 print("Add the Monado build directory to your LD_LIBRARY_PATH:")
68 print(string.format("LD_LIBRARY_PATH=/home/user/monado/build/src/xrt/targets/libmonado/ %s", arg[0]))
69 os.exit(1)
70end
71
72-- Parse arguments
73local args = {...}
74for i=1, #args, 1 do
75 if args[i] == "-f" or args[i] == "--focused" then
76 args_focused = tonumber(args[i+1])
77 elseif args[i] == "-p" or args[i] == "--primary" then
78 args_primary = tonumber(args[i+1])
79 elseif args[i] == "-i" or args[i] == "--input" then
80 args_input = tonumber(args[i+1])
81 end
82end
83
84-- Using ** doesn't work here, it hits an assertion in moando due being NULL
85local root_ptr = ffi.new("mnd_root_t*[1]")
86
87function create_root()
88 local ret = lib.mnd_root_create(root_ptr)
89 if ret ~= 0 then
90 error("Could not create root")
91 end
92 return root_ptr[0]
93end
94
95local root = create_root()
96
97function update_clients()
98 local ret = lib.mnd_root_update_client_list(root)
99 if ret ~= 0 then
100 error("Could not update clients")
101 end
102end
103
104function get_client_count()
105 client_count_ptr = ffi.new("uint32_t[1]")
106 ret = lib.mnd_root_get_number_clients(root, client_count_ptr)
107 if ret ~= 0 then
108 error("Could not get number of clients")
109 end
110 return client_count_ptr[0]
111end
112
113function get_client_id_at_index(index)
114 client_id_ptr = ffi.new("uint32_t[1]")
115 local ret = lib.mnd_root_get_client_id_at_index(root, index, client_id_ptr)
116 if ret ~= 0 then
117 error("Could not get client id at index.")
118 end
119 return client_id_ptr[0]
120end
121
122function get_client_name(client_id)
123 name_ptr = ffi.new("const char*[1]")
124 local ret = lib.mnd_root_get_client_name(root, client_id, name_ptr)
125 if ret ~= 0 then
126 error("Could not get client name.")
127 end
128 return name_ptr[0]
129end
130
131function get_client_flags(client_id)
132 flags_ptr = ffi.new("uint32_t[1]")
133 local ret = lib.mnd_root_get_client_state(root, client_id, flags_ptr)
134 if ret ~= 0 then
135 error("Could not get client flags.")
136 end
137 return flags_ptr[0]
138end
139
140function set_primary(client_id)
141 local ret = lib.mnd_root_set_client_primary(root, client_id)
142 if ret ~= 0 then
143 error("Failed to set primary client to client id", client_id)
144 end
145end
146
147function set_focused(client_id)
148 ret = lib.mnd_root_set_client_focused(root, client_id)
149 if ret ~= 0 then
150 error("Failed to set focused client to client id", client_id)
151 end
152end
153
154function toggle_io(client_id)
155 ret = lib.mnd_root_toggle_client_io_active(root, client_id)
156 if ret ~= 0 then
157 error("Failed to toggle io for client client id", client_id)
158 end
159end
160
161if args_primary then
162 set_primary(args_primary)
163end
164if args_focused then
165 set_focused(args_focused)
166end
167if args_input then
168 toggle_io(args_input)
169end
170
171update_clients(root)
172print("Client count:", get_client_count())
173
174for i = 0, get_client_count() - 1 do
175 local client_id = get_client_id_at_index(i)
176 local name = get_client_name(client_id)
177 local flags = get_client_flags(client_id)
178 local primary = bit.band(flags, lib.MND_CLIENT_PRIMARY_APP) ~= 0
179 local active = bit.band(flags, lib.MND_CLIENT_SESSION_ACTIVE) ~= 0
180 local visible = bit.band(flags, lib.MND_CLIENT_SESSION_VISIBLE) ~= 0
181 local focused = bit.band(flags, lib.MND_CLIENT_SESSION_FOCUSED) ~= 0
182 local overlay = bit.band(flags, lib.MND_CLIENT_SESSION_OVERLAY) ~= 0
183 local io_active = bit.band(flags, lib.MND_CLIENT_IO_ACTIVE) ~= 0
184 print(string.format("id: %d primary: %5s active: %5s visible: %5s focused: %5s io: %5s overlay: %5s name: %s",
185 client_id, tostring(primary), tostring(active), tostring(visible), tostring(focused),
186 tostring(io_active), tostring(overlay), ffi.string(name)))
187end
188
189lib.mnd_root_destroy(root_ptr)