icc_detect_x11.cc (2529B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 // clang-format off 7 #include "tools/icc_detect/icc_detect.h" 8 // clang-format on 9 10 #include <stdint.h> 11 #include <stdlib.h> 12 #include <xcb/xcb.h> 13 14 #include <memory> 15 16 // clang-format off 17 #include <QApplication> 18 #include <X11/Xlib.h> 19 // clang-format on 20 21 namespace jpegxl { 22 namespace tools { 23 24 namespace { 25 26 constexpr char kIccProfileAtomName[] = "_ICC_PROFILE"; 27 constexpr uint32_t kMaxIccProfileSize = 1 << 24; 28 29 struct FreeDeleter { 30 void operator()(void* const p) const { std::free(p); } 31 }; 32 template <typename T> 33 using XcbUniquePtr = std::unique_ptr<T, FreeDeleter>; 34 35 } // namespace 36 37 QByteArray GetMonitorIccProfile(const QWidget* const widget) { 38 Q_UNUSED(widget) 39 auto* const qX11App = 40 qGuiApp->nativeInterface<QNativeInterface::QX11Application>(); 41 if (qX11App == nullptr) { 42 return QByteArray(); 43 } 44 xcb_connection_t* const connection = qX11App->connection(); 45 if (connection == nullptr) { 46 return QByteArray(); 47 } 48 49 const int screenNumber = DefaultScreen(qX11App->display()); 50 51 const xcb_intern_atom_cookie_t atomRequest = 52 xcb_intern_atom(connection, /*only_if_exists=*/1, 53 sizeof kIccProfileAtomName - 1, kIccProfileAtomName); 54 const XcbUniquePtr<xcb_intern_atom_reply_t> atomReply( 55 xcb_intern_atom_reply(connection, atomRequest, nullptr)); 56 if (atomReply == nullptr) { 57 return QByteArray(); 58 } 59 const xcb_atom_t iccProfileAtom = atomReply->atom; 60 61 const xcb_screen_t* screen = nullptr; 62 int i = 0; 63 for (xcb_screen_iterator_t it = 64 xcb_setup_roots_iterator(xcb_get_setup(connection)); 65 it.rem; xcb_screen_next(&it)) { 66 if (i == screenNumber) { 67 screen = it.data; 68 break; 69 } 70 ++i; 71 } 72 if (screen == nullptr) { 73 return QByteArray(); 74 } 75 const xcb_get_property_cookie_t profileRequest = xcb_get_property( 76 connection, /*_delete=*/0, screen->root, iccProfileAtom, 77 XCB_GET_PROPERTY_TYPE_ANY, /*long_offset=*/0, kMaxIccProfileSize); 78 const XcbUniquePtr<xcb_get_property_reply_t> profile( 79 xcb_get_property_reply(connection, profileRequest, nullptr)); 80 if (profile == nullptr || profile->bytes_after > 0) { 81 return QByteArray(); 82 } 83 84 return QByteArray( 85 reinterpret_cast<const char*>(xcb_get_property_value(profile.get())), 86 xcb_get_property_value_length(profile.get())); 87 } 88 89 } // namespace tools 90 } // namespace jpegxl