comparison src/sys/x11/settings.cc @ 379:5eaafed6c10b

*: clang-format
author Paper <paper@tflc.us>
date Wed, 05 Nov 2025 12:59:46 -0500
parents 99c961c91809
children
comparison
equal deleted inserted replaced
378:5912dafc6e28 379:5eaafed6c10b
1 #include "sys/x11/settings.h" 1 #include "sys/x11/settings.h"
2 #include "core/byte_stream.h" 2 #include "core/byte_stream.h"
3 3
4 #include <array>
4 #include <cassert> 5 #include <cassert>
6 #include <climits>
7 #include <cstdint>
5 #include <cstring> 8 #include <cstring>
6 #include <cstdint> 9 #include <map>
7 #include <climits> 10 #include <memory>
11 #include <optional>
8 #include <string_view> 12 #include <string_view>
9 #include <memory>
10 #include <array>
11 #include <optional>
12 #include <map>
13 13
14 #include <xcb/xcb.h> 14 #include <xcb/xcb.h>
15 15
16 #include "fmt/core.h" 16 #include "fmt/core.h"
17 17
18 namespace x11 { 18 namespace x11 {
19 19
20 bool SettingsItem::VerifyType() { 20 bool SettingsItem::VerifyType()
21 {
21 switch (type) { 22 switch (type) {
22 case SettingsItem::TypeInt: 23 case SettingsItem::TypeInt:
23 case SettingsItem::TypeStr: 24 case SettingsItem::TypeStr:
24 case SettingsItem::TypeRgba: 25 case SettingsItem::TypeRgba: return true;
25 return true; 26 default: return false;
26 default:
27 return false;
28 } 27 }
29 } 28 }
30 29
31 /* -------------------------------------------------------------------------- */ 30 /* -------------------------------------------------------------------------- */
32 /* xsettings parser */ 31 /* xsettings parser */
33 32
34 static constexpr std::size_t GetPadding(std::size_t length, std::size_t increment) { 33 static constexpr std::size_t GetPadding(std::size_t length, std::size_t increment)
34 {
35 /* ripped from xsettingsd */ 35 /* ripped from xsettingsd */
36 return (increment - (length % increment)) % increment; 36 return (increment - (length % increment)) % increment;
37 } 37 }
38 38
39 class Parser { 39 class Parser {
56 /* parsed in the constructor */ 56 /* parsed in the constructor */
57 std::uint32_t serial_ = 0; 57 std::uint32_t serial_ = 0;
58 std::uint32_t total_items_ = 0; 58 std::uint32_t total_items_ = 0;
59 }; 59 };
60 60
61 std::uint32_t Parser::GetTotalItems(void) { 61 std::uint32_t Parser::GetTotalItems(void)
62 {
62 return total_items_; 63 return total_items_;
63 } 64 }
64 65
65 Parser::Parser(std::uint8_t *bytes, std::size_t size) : stream(bytes, size) { 66 Parser::Parser(std::uint8_t *bytes, std::size_t size) : stream(bytes, size)
66 } 67 {
67 68 }
68 bool Parser::ParseHeader(void) { 69
70 bool Parser::ParseHeader(void)
71 {
69 std::uint8_t byte_order; 72 std::uint8_t byte_order;
70 if (!stream.ReadBinary<std::uint8_t>(byte_order)) 73 if (!stream.ReadBinary<std::uint8_t>(byte_order))
71 return false; 74 return false;
72 75
73 switch (byte_order) { 76 switch (byte_order) {
74 case MSBFirst: 77 case MSBFirst: stream.SetEndianness(ByteStream::ByteOrder::Big); break;
75 stream.SetEndianness(ByteStream::ByteOrder::Big); 78 case LSBFirst: stream.SetEndianness(ByteStream::ByteOrder::Little); break;
76 break; 79 default: return false; /* errr */
77 case LSBFirst:
78 stream.SetEndianness(ByteStream::ByteOrder::Little);
79 break;
80 default:
81 return false; /* errr */
82 } 80 }
83 81
84 stream.Advance(3); 82 stream.Advance(3);
85 83
86 if (!stream.ReadInt<std::uint32_t>(serial_)) 84 if (!stream.ReadInt<std::uint32_t>(serial_))
90 return false; 88 return false;
91 89
92 return true; 90 return true;
93 } 91 }
94 92
95 std::optional<SettingsItem> Parser::ParseNextItem(void) { 93 std::optional<SettingsItem> Parser::ParseNextItem(void)
94 {
96 SettingsItem item; 95 SettingsItem item;
97 96
98 /* read one byte */ 97 /* read one byte */
99 if (!stream.ReadInt<std::uint8_t>(item.type)) 98 if (!stream.ReadInt<std::uint8_t>(item.type))
100 return std::nullopt; 99 return std::nullopt;
143 142
144 break; 143 break;
145 } 144 }
146 case SettingsItem::TypeRgba: { 145 case SettingsItem::TypeRgba: {
147 /* it's actually RBGA, but whatever. */ 146 /* it's actually RBGA, but whatever. */
148 if (!stream.ReadInt<std::uint16_t>(item.data.rgba.red) 147 if (!stream.ReadInt<std::uint16_t>(item.data.rgba.red) ||
149 || !stream.ReadInt<std::uint16_t>(item.data.rgba.blue) 148 !stream.ReadInt<std::uint16_t>(item.data.rgba.blue) ||
150 || !stream.ReadInt<std::uint16_t>(item.data.rgba.green) 149 !stream.ReadInt<std::uint16_t>(item.data.rgba.green) ||
151 || !stream.ReadInt<std::uint16_t>(item.data.rgba.alpha)) 150 !stream.ReadInt<std::uint16_t>(item.data.rgba.alpha))
152 return std::nullopt; 151 return std::nullopt;
153 152
154 break; 153 break;
155 } 154 }
156 default: 155 default:
178 177
179 using XcbConnectionPtr = std::unique_ptr<xcb_connection_t, XcbConnectionDestructor>; 178 using XcbConnectionPtr = std::unique_ptr<xcb_connection_t, XcbConnectionDestructor>;
180 179
181 /* RAII is nice */ 180 /* RAII is nice */
182 struct XcbGrabber { 181 struct XcbGrabber {
183 XcbGrabber(::xcb_connection_t *conn) { ::xcb_grab_server(conn); conn_ = conn; } 182 XcbGrabber(::xcb_connection_t *conn)
183 {
184 ::xcb_grab_server(conn);
185 conn_ = conn;
186 }
184 ~XcbGrabber() { ::xcb_ungrab_server(conn_); } 187 ~XcbGrabber() { ::xcb_ungrab_server(conn_); }
185 188
186 private: 189 private:
187 ::xcb_connection_t *conn_; 190 ::xcb_connection_t *conn_;
188 }; 191 };
189 192
190 static ::xcb_window_t GetSelectionOwner(::xcb_connection_t *conn, ::xcb_atom_t selection) { 193 static ::xcb_window_t GetSelectionOwner(::xcb_connection_t *conn, ::xcb_atom_t selection)
194 {
191 ::xcb_window_t owner = XCB_NONE; 195 ::xcb_window_t owner = XCB_NONE;
192 MallocPtr<::xcb_get_selection_owner_reply_t> reply(::xcb_get_selection_owner_reply(conn, ::xcb_get_selection_owner(conn, selection), nullptr)); 196 MallocPtr<::xcb_get_selection_owner_reply_t> reply(
193 197 ::xcb_get_selection_owner_reply(conn, ::xcb_get_selection_owner(conn, selection), nullptr));
198
194 if (reply) 199 if (reply)
195 owner = reply->owner; 200 owner = reply->owner;
196 201
197 return owner; 202 return owner;
198 } 203 }
199 204
200 static bool GetRawSettingsData(std::vector<uint8_t>& bytes) { 205 static bool GetRawSettingsData(std::vector<uint8_t> &bytes)
206 {
201 int screen; 207 int screen;
202 208
203 XcbConnectionPtr conn(::xcb_connect(nullptr, &screen)); 209 XcbConnectionPtr conn(::xcb_connect(nullptr, &screen));
204 if (::xcb_connection_has_error(conn.get())) 210 if (::xcb_connection_has_error(conn.get()))
205 return false; 211 return false;
211 }; 217 };
212 218
213 std::map<Atom, ::xcb_atom_t> atoms; 219 std::map<Atom, ::xcb_atom_t> atoms;
214 { 220 {
215 std::map<Atom, std::string> names = { 221 std::map<Atom, std::string> names = {
216 {XSETTINGS_SCREEN, fmt::format("_XSETTINGS_S{}", screen)}, 222 {XSETTINGS_SCREEN, fmt::format("_XSETTINGS_S{}", screen)},
217 {XSETTINGS_SETTINGS, "_XSETTINGS_SETTINGS"}, 223 {XSETTINGS_SETTINGS, "_XSETTINGS_SETTINGS"},
218 }; 224 };
219 225
220 std::map<Atom, ::xcb_intern_atom_cookie_t> atom_cookies; 226 std::map<Atom, ::xcb_intern_atom_cookie_t> atom_cookies;
221 for (const auto& name : names) 227 for (const auto &name : names)
222 atom_cookies[name.first] = ::xcb_intern_atom(conn.get(), false, name.second.size(), name.second.data()); 228 atom_cookies[name.first] = ::xcb_intern_atom(conn.get(), false, name.second.size(), name.second.data());
223 229
224 for (const auto& cookie : atom_cookies) { 230 for (const auto &cookie : atom_cookies) {
225 MallocPtr<::xcb_intern_atom_reply_t> reply(::xcb_intern_atom_reply(conn.get(), cookie.second, nullptr)); 231 MallocPtr<::xcb_intern_atom_reply_t> reply(::xcb_intern_atom_reply(conn.get(), cookie.second, nullptr));
226 if (!reply || reply->atom == XCB_NONE) 232 if (!reply || reply->atom == XCB_NONE)
227 return false; 233 return false;
228 234
229 atoms[cookie.first] = reply->atom; 235 atoms[cookie.first] = reply->atom;
237 243
238 ::xcb_window_t win = GetSelectionOwner(conn.get(), atoms[XSETTINGS_SCREEN]); 244 ::xcb_window_t win = GetSelectionOwner(conn.get(), atoms[XSETTINGS_SCREEN]);
239 if (win == XCB_NONE) 245 if (win == XCB_NONE)
240 return false; 246 return false;
241 247
242 reply.reset(::xcb_get_property_reply(conn.get(), ::xcb_get_property(conn.get(), 0, win, atoms[XSETTINGS_SETTINGS], XCB_ATOM_ANY, 0L, UINT_MAX), nullptr)); 248 reply.reset(::xcb_get_property_reply(
249 conn.get(), ::xcb_get_property(conn.get(), 0, win, atoms[XSETTINGS_SETTINGS], XCB_ATOM_ANY, 0L, UINT_MAX),
250 nullptr));
243 }; 251 };
244 if (!reply) 252 if (!reply)
245 return false; 253 return false;
246 254
247 uint8_t *data = reinterpret_cast<uint8_t *>(xcb_get_property_value(reply.get())); 255 uint8_t *data = reinterpret_cast<uint8_t *>(xcb_get_property_value(reply.get()));
255 } 263 }
256 264
257 /* ------------------------------------------------------------------------- */ 265 /* ------------------------------------------------------------------------- */
258 /* now for the actual all-important public API stringing all this together */ 266 /* now for the actual all-important public API stringing all this together */
259 267
260 bool GetSettings(std::vector<SettingsItem>& settings) { 268 bool GetSettings(std::vector<SettingsItem> &settings)
269 {
261 std::vector<std::uint8_t> xsettings_raw; 270 std::vector<std::uint8_t> xsettings_raw;
262 if (!GetRawSettingsData(xsettings_raw)) 271 if (!GetRawSettingsData(xsettings_raw))
263 return false; 272 return false;
264 273
265 Parser parser(xsettings_raw.data(), xsettings_raw.size()); 274 Parser parser(xsettings_raw.data(), xsettings_raw.size());
277 } 286 }
278 287
279 return true; 288 return true;
280 } 289 }
281 290
282 bool FindSetting(const std::string& name, SettingsItem& setting) { 291 bool FindSetting(const std::string &name, SettingsItem &setting)
292 {
283 std::vector<std::uint8_t> xsettings_raw; 293 std::vector<std::uint8_t> xsettings_raw;
284 if (!GetRawSettingsData(xsettings_raw)) 294 if (!GetRawSettingsData(xsettings_raw))
285 return false; 295 return false;
286 296
287 Parser parser(xsettings_raw.data(), xsettings_raw.size()); 297 Parser parser(xsettings_raw.data(), xsettings_raw.size());
293 while (total--) { 303 while (total--) {
294 std::optional<SettingsItem> opt_item = parser.ParseNextItem(); 304 std::optional<SettingsItem> opt_item = parser.ParseNextItem();
295 if (!opt_item) 305 if (!opt_item)
296 return false; 306 return false;
297 307
298 SettingsItem& item = opt_item.value(); 308 SettingsItem &item = opt_item.value();
299 if (item.name == name) { 309 if (item.name == name) {
300 setting = item; 310 setting = item;
301 return true; 311 return true;
302 } 312 }
303 } 313 }