Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qxcbxsettings.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtCore/QByteArray>
8#include <QtCore/QtEndian>
9
10#include <vector>
11#include <algorithm>
12
13QT_BEGIN_NAMESPACE
14/* Implementation of http://standards.freedesktop.org/xsettings-spec/xsettings-0.5.html */
15
16enum XSettingsType {
17 XSettingsTypeInteger = 0,
18 XSettingsTypeString = 1,
19 XSettingsTypeColor = 2
20};
21
27
29{
30public:
34
35 void updateValue(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &value, int last_change_serial)
36 {
37 if (last_change_serial <= this->last_change_serial)
38 return;
39 this->value = value;
40 this->last_change_serial = last_change_serial;
41 for (const auto &callback : callback_links)
42 callback.func(screen, name, value, callback.handle);
43 }
44
46 {
47 QXcbXSettingsCallback callback = { func, handle };
48 callback_links.push_back(callback);
49 }
50
54
55};
56
58{
59public:
61 : screen(screen)
62 , initialized(false)
63 {
64 }
65
67 {
68 QXcbConnectionGrabber connectionGrabber(screen->connection());
69
70 int offset = 0;
71 QByteArray settings;
72 xcb_atom_t _xsettings_atom = screen->connection()->atom(QXcbAtom::Atom_XSETTINGS_SETTINGS);
73 while (1) {
74 auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property,
76 false,
77 x_settings_window,
78 _xsettings_atom,
79 _xsettings_atom,
80 offset/4,
81 8192);
82 bool more = false;
83 if (!reply)
84 return settings;
85
86 const auto property_value_length = xcb_get_property_value_length(reply.get());
87 settings.append(static_cast<const char *>(xcb_get_property_value(reply.get())), property_value_length);
88 offset += property_value_length;
89 more = reply->bytes_after != 0;
90
91 if (!more)
92 break;
93 }
94
95 return settings;
96 }
97
98 static int round_to_nearest_multiple_of_4(int value)
99 {
100 int remainder = value % 4;
101 if (!remainder)
102 return value;
103 return value + 4 - remainder;
104 }
105
106 void populateSettings(const QByteArray &xSettings)
107 {
108 if (xSettings.size() < 12)
109 return;
110 char byteOrder = xSettings.at(0);
111 if (byteOrder != XCB_IMAGE_ORDER_LSB_FIRST && byteOrder != XCB_IMAGE_ORDER_MSB_FIRST) {
112 qWarning("ByteOrder byte %d not 0 or 1", byteOrder);
113 return;
114 }
115
116#define ADJUST_BO(b, t, x)
117 ((b == XCB_IMAGE_ORDER_LSB_FIRST) ?
118 qFromLittleEndian<t>(x) :
119 qFromBigEndian<t>(x))
120#define VALIDATE_LENGTH(x)
121 if ((size_t)xSettings.length() < (offset + local_offset + 12 + x)) {
122 qWarning("Length %d runs past end of data", x);
123 return;
124 }
125
126 uint number_of_settings = ADJUST_BO(byteOrder, quint32, xSettings.mid(8,4).constData());
127 const char *data = xSettings.constData() + 12;
128 size_t offset = 0;
129 for (uint i = 0; i < number_of_settings; i++) {
130 int local_offset = 0;
132 XSettingsType type = static_cast<XSettingsType>(*reinterpret_cast<const quint8 *>(data + offset));
133 local_offset += 2;
134
136 quint16 name_len = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
137 local_offset += 2;
138
139 VALIDATE_LENGTH(name_len);
140 QByteArray name(data + offset + local_offset, name_len);
141 local_offset += round_to_nearest_multiple_of_4(name_len);
142
144 int last_change_serial = ADJUST_BO(byteOrder, qint32, data + offset + local_offset);
145 Q_UNUSED(last_change_serial);
146 local_offset += 4;
147
148 QVariant value;
149 if (type == XSettingsTypeString) {
151 int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset);
152 local_offset+=4;
153 VALIDATE_LENGTH(value_length);
154 QByteArray value_string(data + offset + local_offset, value_length);
155 value.setValue(value_string);
156 local_offset += round_to_nearest_multiple_of_4(value_length);
157 } else if (type == XSettingsTypeInteger) {
159 int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset);
160 local_offset += 4;
161 value.setValue(value_length);
162 } else if (type == XSettingsTypeColor) {
163 VALIDATE_LENGTH(2*4);
164 quint16 red = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
165 local_offset += 2;
166 quint16 green = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
167 local_offset += 2;
168 quint16 blue = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
169 local_offset += 2;
170 quint16 alpha= ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
171 local_offset += 2;
172 QColor color_value(red,green,blue,alpha);
173 value.setValue(color_value);
174 }
175 offset += local_offset;
176 settings[name].updateValue(screen,name,value,last_change_serial);
177 }
178
179 }
180
182 xcb_window_t x_settings_window;
185};
186
187
188QXcbXSettings::QXcbXSettings(QXcbVirtualDesktop *screen)
189 : d_ptr(new QXcbXSettingsPrivate(screen))
190{
191 QByteArray settings_atom_for_screen("_XSETTINGS_S");
192 settings_atom_for_screen.append(QByteArray::number(screen->number()));
193 auto atom_reply = Q_XCB_REPLY(xcb_intern_atom,
194 screen->xcb_connection(),
195 true,
196 settings_atom_for_screen.size(),
197 settings_atom_for_screen.constData());
198 if (!atom_reply)
199 return;
200
201 xcb_atom_t selection_owner_atom = atom_reply->atom;
202
203 xcb_window_t owner = screen->connection()->selectionOwner(selection_owner_atom);
204 if (owner == XCB_NONE)
205 return;
206
207 d_ptr->x_settings_window = owner;
208 if (!d_ptr->x_settings_window)
209 return;
210
211 screen->connection()->addWindowEventListener(d_ptr->x_settings_window, this);
212 const uint32_t event = XCB_CW_EVENT_MASK;
213 const uint32_t event_mask[] = { XCB_EVENT_MASK_STRUCTURE_NOTIFY|XCB_EVENT_MASK_PROPERTY_CHANGE };
214 xcb_change_window_attributes(screen->xcb_connection(),d_ptr->x_settings_window,event,event_mask);
215
216 d_ptr->populateSettings(d_ptr->getSettings());
217 d_ptr->initialized = true;
218}
219
221{
222 delete d_ptr;
223 d_ptr = nullptr;
224}
225
227{
228 Q_D(const QXcbXSettings);
229 return d->initialized;
230}
231
232void QXcbXSettings::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event)
233{
234 Q_D(QXcbXSettings);
235 if (event->window != d->x_settings_window)
236 return;
237
238 d->populateSettings(d->getSettings());
239}
240
241void QXcbXSettings::registerCallbackForProperty(const QByteArray &property, QXcbXSettings::PropertyChangeFunc func, void *handle)
242{
243 Q_D(QXcbXSettings);
244 d->settings[property].addCallback(func,handle);
245}
246
247void QXcbXSettings::removeCallbackForHandle(const QByteArray &property, void *handle)
248{
249 Q_D(QXcbXSettings);
250 auto &callbacks = d->settings[property].callback_links;
251
252 auto isCallbackForHandle = [handle](const QXcbXSettingsCallback &cb) { return cb.handle == handle; };
253
254 callbacks.erase(std::remove_if(callbacks.begin(), callbacks.end(),
255 isCallbackForHandle),
256 callbacks.end());
257}
258
260{
261 Q_D(QXcbXSettings);
262 for (QMap<QByteArray, QXcbXSettingsPropertyValue>::const_iterator it = d->settings.cbegin();
263 it != d->settings.cend(); ++it) {
264 removeCallbackForHandle(it.key(),handle);
265 }
266}
267
268QVariant QXcbXSettings::setting(const QByteArray &property) const
269{
270 Q_D(const QXcbXSettings);
271 return d->settings.value(property).value;
272}
273
274QT_END_NAMESPACE
@ Atom_XSETTINGS_SETTINGS
Definition qxcbatom.h:198
QXcbConnection * connection() const
Definition qxcbobject.h:17
xcb_connection_t * xcb_connection() const
Definition qxcbobject.h:20
void populateSettings(const QByteArray &xSettings)
QXcbVirtualDesktop * screen
QXcbXSettingsPrivate(QXcbVirtualDesktop *screen)
QMap< QByteArray, QXcbXSettingsPropertyValue > settings
xcb_window_t x_settings_window
static int round_to_nearest_multiple_of_4(int value)
void updateValue(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &value, int last_change_serial)
std::vector< QXcbXSettingsCallback > callback_links
void addCallback(QXcbXSettings::PropertyChangeFunc func, void *handle)
void removeCallbackForHandle(const QByteArray &property, void *handle)
void removeCallbackForHandle(void *handle)
void registerCallbackForProperty(const QByteArray &property, PropertyChangeFunc func, void *handle)
QVariant setting(const QByteArray &property) const
bool initialized() const
void(* PropertyChangeFunc)(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle)
void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) override
#define Q_XCB_REPLY(call,...)
#define Q_XCB_REPLY_UNCHECKED(call,...)
#define VALIDATE_LENGTH(x)
#define ADJUST_BO(b, t, x)
QXcbXSettings::PropertyChangeFunc func