Imported Upstream version 0.9.0
[platform/upstream/libjxl.git] / tools / icc_detect / icc_detect_x11.cc
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