Mercurial > minori
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 } |
