Absolute File Name: | /home/qt/qt5_coco/qt5/qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /**************************************************************************** | - | ||||||||||||
2 | ** | - | ||||||||||||
3 | ** Copyright (C) 2016 The Qt Company Ltd. | - | ||||||||||||
4 | ** Contact: https://www.qt.io/licensing/ | - | ||||||||||||
5 | ** | - | ||||||||||||
6 | ** This file is part of the plugins of the Qt Toolkit. | - | ||||||||||||
7 | ** | - | ||||||||||||
8 | ** $QT_BEGIN_LICENSE:LGPL$ | - | ||||||||||||
9 | ** Commercial License Usage | - | ||||||||||||
10 | ** Licensees holding valid commercial Qt licenses may use this file in | - | ||||||||||||
11 | ** accordance with the commercial license agreement provided with the | - | ||||||||||||
12 | ** Software or, alternatively, in accordance with the terms contained in | - | ||||||||||||
13 | ** a written agreement between you and The Qt Company. For licensing terms | - | ||||||||||||
14 | ** and conditions see https://www.qt.io/terms-conditions. For further | - | ||||||||||||
15 | ** information use the contact form at https://www.qt.io/contact-us. | - | ||||||||||||
16 | ** | - | ||||||||||||
17 | ** GNU Lesser General Public License Usage | - | ||||||||||||
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | - | ||||||||||||
19 | ** General Public License version 3 as published by the Free Software | - | ||||||||||||
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | - | ||||||||||||
21 | ** packaging of this file. Please review the following information to | - | ||||||||||||
22 | ** ensure the GNU Lesser General Public License version 3 requirements | - | ||||||||||||
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | - | ||||||||||||
24 | ** | - | ||||||||||||
25 | ** GNU General Public License Usage | - | ||||||||||||
26 | ** Alternatively, this file may be used under the terms of the GNU | - | ||||||||||||
27 | ** General Public License version 2.0 or (at your option) the GNU General | - | ||||||||||||
28 | ** Public license version 3 or any later version approved by the KDE Free | - | ||||||||||||
29 | ** Qt Foundation. The licenses are as published by the Free Software | - | ||||||||||||
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | - | ||||||||||||
31 | ** included in the packaging of this file. Please review the following | - | ||||||||||||
32 | ** information to ensure the GNU General Public License requirements will | - | ||||||||||||
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | - | ||||||||||||
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | - | ||||||||||||
35 | ** | - | ||||||||||||
36 | ** $QT_END_LICENSE$ | - | ||||||||||||
37 | ** | - | ||||||||||||
38 | ****************************************************************************/ | - | ||||||||||||
39 | - | |||||||||||||
40 | #include "qxcbxsettings.h" | - | ||||||||||||
41 | - | |||||||||||||
42 | #include <QtCore/QByteArray> | - | ||||||||||||
43 | #include <QtCore/QtEndian> | - | ||||||||||||
44 | - | |||||||||||||
45 | #include <vector> | - | ||||||||||||
46 | #include <algorithm> | - | ||||||||||||
47 | - | |||||||||||||
48 | #ifdef XCB_USE_XLIB | - | ||||||||||||
49 | #include <X11/extensions/XIproto.h> | - | ||||||||||||
50 | #endif //XCB_USE_XLIB | - | ||||||||||||
51 | - | |||||||||||||
52 | QT_BEGIN_NAMESPACE | - | ||||||||||||
53 | /* Implementation of http://standards.freedesktop.org/xsettings-spec/xsettings-0.5.html */ | - | ||||||||||||
54 | - | |||||||||||||
55 | enum XSettingsType { | - | ||||||||||||
56 | XSettingsTypeInteger = 0, | - | ||||||||||||
57 | XSettingsTypeString = 1, | - | ||||||||||||
58 | XSettingsTypeColor = 2 | - | ||||||||||||
59 | }; | - | ||||||||||||
60 | - | |||||||||||||
classstruct QXcbXSettingsCallback | ||||||||||||||
62 | { | - | ||||||||||||
63 | public:QXcbXSettings::PropertyChangeFunc func; | - | ||||||||||||
64 | void *handle; | - | ||||||||||||
65 | }; | - | ||||||||||||
66 | - | |||||||||||||
67 | class QXcbXSettingsPropertyValue | - | ||||||||||||
68 | { | - | ||||||||||||
69 | public: | - | ||||||||||||
70 | QXcbXSettingsPropertyValue() | - | ||||||||||||
71 | : last_change_serial(-1) | - | ||||||||||||
72 | {} | - | ||||||||||||
73 | - | |||||||||||||
74 | void updateValue(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &value, int last_change_serial) | - | ||||||||||||
75 | { | - | ||||||||||||
76 | if (last_change_serial <= this->last_change_serial)
| 0-950 | ||||||||||||
77 | return; never executed: return; | 0 | ||||||||||||
78 | this->value = value; | - | ||||||||||||
79 | this->last_change_serial = last_change_serial; | - | ||||||||||||
80 | QLinkedList<QXcbXSettingsCallback>::const_iterator it = callback_links.begin();for (;it !=(const auto &callback : callback_links.end();++it) | - | ||||||||||||
81 | { never executed: callback.func(screen, name, value, callback.handle); | 0 | ||||||||||||
it-> never executed: callback.func(screen, name, value, it->callback.handle);callback.func(screen, name, value, callback.handle); never executed: callback.func(screen, name, value, callback.handle); | ||||||||||||||
82 | }} executed 950 times by 19 tests: end of block Executed by:
| 950 | ||||||||||||
83 | - | |||||||||||||
84 | void addCallback(QXcbXSettings::PropertyChangeFunc func, void *handle) | - | ||||||||||||
85 | { | - | ||||||||||||
86 | QXcbXSettingsCallback callback;callback .func= { func; | - | ||||||||||||
callback.handle =, handle ;}; | ||||||||||||||
87 | callback_links.appendpush_back(callback); | - | ||||||||||||
88 | } executed 19 times by 19 tests: end of block Executed by:
| 19 | ||||||||||||
89 | - | |||||||||||||
90 | QVariant value; | - | ||||||||||||
91 | int last_change_serial; | - | ||||||||||||
92 | QLinkedListstd::vector<QXcbXSettingsCallback> callback_links; | - | ||||||||||||
93 | - | |||||||||||||
94 | }; | - | ||||||||||||
95 | - | |||||||||||||
96 | class QXcbXSettingsPrivate | - | ||||||||||||
97 | { | - | ||||||||||||
98 | public: | - | ||||||||||||
99 | QXcbXSettingsPrivate(QXcbVirtualDesktop *screen) | - | ||||||||||||
100 | : screen(screen) | - | ||||||||||||
101 | , initialized(false) | - | ||||||||||||
102 | { | - | ||||||||||||
103 | } | - | ||||||||||||
104 | - | |||||||||||||
105 | QByteArray getSettings() | - | ||||||||||||
106 | { | - | ||||||||||||
107 | QXcbConnectionGrabber connectionGrabber(screen->connection()); | - | ||||||||||||
108 | - | |||||||||||||
109 | int offset = 0; | - | ||||||||||||
110 | QByteArray settings; | - | ||||||||||||
111 | xcb_atom_t _xsettings_atom = screen->connection()->atom(QXcbAtom::_XSETTINGS_SETTINGS); | - | ||||||||||||
112 | while (1) { | - | ||||||||||||
113 | xcb_get_property_cookie_t get_prop_cookie = | - | ||||||||||||
114 | xcb_get_property_unchecked(screen->xcb_connection(), | - | ||||||||||||
115 | false, | - | ||||||||||||
116 | x_settings_window, | - | ||||||||||||
117 | _xsettings_atom, | - | ||||||||||||
118 | _xsettings_atom, | - | ||||||||||||
119 | offset/4, | - | ||||||||||||
120 | 8192); | - | ||||||||||||
121 | xcb_get_property_reply_t *reply = xcb_get_property_reply(screen->xcb_connection(), get_prop_cookie, NULL); | - | ||||||||||||
122 | bool more = false; | - | ||||||||||||
123 | if (!reply)
| 0-19 | ||||||||||||
124 | return settings; never executed: return settings; | 0 | ||||||||||||
125 | - | |||||||||||||
126 | const auto property_value_length = xcb_get_property_value_length(reply); | - | ||||||||||||
127 | settings+= QByteArray((.append(static_cast<const char *)*>(xcb_get_property_value(reply), xcb_get_property_value_length(reply));)), property_value_length); | - | ||||||||||||
128 | offset += xcb_get_property_value_length(reply);property_value_length; | - | ||||||||||||
129 | more = reply->bytes_after != 0; | - | ||||||||||||
130 | - | |||||||||||||
131 | free(reply); | - | ||||||||||||
132 | - | |||||||||||||
133 | if (!more)
| 0-19 | ||||||||||||
134 | break; executed 19 times by 19 tests: break; Executed by:
| 19 | ||||||||||||
135 | } never executed: end of block | 0 | ||||||||||||
136 | - | |||||||||||||
137 | return settings; executed 19 times by 19 tests: return settings; Executed by:
| 19 | ||||||||||||
138 | } | - | ||||||||||||
139 | - | |||||||||||||
140 | static int round_to_nearest_multiple_of_4(int value) | - | ||||||||||||
141 | { | - | ||||||||||||
142 | int remainder = value % 4; | - | ||||||||||||
143 | if (!remainder) | - | ||||||||||||
144 | return value; | - | ||||||||||||
145 | return value + 4 - remainder; | - | ||||||||||||
146 | } | - | ||||||||||||
147 | - | |||||||||||||
148 | #ifdef XCB_USE_XLIB | - | ||||||||||||
149 | void populateSettings(const QByteArray &xSettings) | - | ||||||||||||
150 | { | - | ||||||||||||
151 | if (xSettings.length() < 12)
| 0-19 | ||||||||||||
152 | return; never executed: return; | 0 | ||||||||||||
153 | char byteOrder = xSettings.at(0); | - | ||||||||||||
154 | if (byteOrder != LSBFirst && byteOrder != MSBFirst) {
| 0-19 | ||||||||||||
155 | qWarning("ByteOrder byte %d not 0 or 1", byteOrder); | - | ||||||||||||
156 | return; never executed: return; | 0 | ||||||||||||
157 | } | - | ||||||||||||
158 | - | |||||||||||||
159 | #define ADJUST_BO(b, t, x) \ | - | ||||||||||||
160 | ((b == LSBFirst) ? \ | - | ||||||||||||
161 | qFromLittleEndian<t>((const uchar *)(>(x))) : \ | - | ||||||||||||
162 | qFromBigEndian<t>((const uchar *)(>(x))))) | - | ||||||||||||
163 | #define VALIDATE_LENGTH(x) \ | - | ||||||||||||
164 | if ((size_t)xSettings.length() < (offset + local_offset + 12 + x)) { \ | - | ||||||||||||
165 | qWarning("Length %d runs past end of data", x); \ | - | ||||||||||||
166 | return; \ | - | ||||||||||||
167 | } | - | ||||||||||||
168 | - | |||||||||||||
169 | uint number_of_settings = ADJUST_BO(byteOrder, quint32, xSettings.mid(8,4).constData());
| 0-19 | ||||||||||||
170 | const char *data = xSettings.constData() + 12; | - | ||||||||||||
171 | size_t offset = 0; | - | ||||||||||||
172 | for (uint i = 0; i < number_of_settings; i++) {
| 19-950 | ||||||||||||
173 | int local_offset = 0; | - | ||||||||||||
174 | VALIDATE_LENGTH(2); never executed: return;
| 0-950 | ||||||||||||
175 | XSettingsType type = static_cast<XSettingsType>(*reinterpret_cast<const quint8 *>(data + offset)); | - | ||||||||||||
176 | local_offset += 2; | - | ||||||||||||
177 | - | |||||||||||||
178 | VALIDATE_LENGTH(2); never executed: return;
| 0-950 | ||||||||||||
179 | quint16 name_len = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
| 0-950 | ||||||||||||
180 | local_offset += 2; | - | ||||||||||||
181 | - | |||||||||||||
182 | VALIDATE_LENGTH(name_len); never executed: return;
| 0-950 | ||||||||||||
183 | QByteArray name(data + offset + local_offset, name_len); | - | ||||||||||||
184 | local_offset += round_to_nearest_multiple_of_4(name_len); | - | ||||||||||||
185 | - | |||||||||||||
186 | VALIDATE_LENGTH(4); never executed: return;
| 0-950 | ||||||||||||
187 | int last_change_serial = ADJUST_BO(byteOrder, qint32, data + offset + local_offset);
| 0-950 | ||||||||||||
188 | Q_UNUSED(last_change_serial); | - | ||||||||||||
189 | local_offset += 4; | - | ||||||||||||
190 | - | |||||||||||||
191 | QVariant value; | - | ||||||||||||
192 | if (type == XSettingsTypeString) {
| 418-532 | ||||||||||||
193 | VALIDATE_LENGTH(4); never executed: return;
| 0-418 | ||||||||||||
194 | int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset);
| 0-418 | ||||||||||||
195 | local_offset+=4; | - | ||||||||||||
196 | VALIDATE_LENGTH(value_length); never executed: return;
| 0-418 | ||||||||||||
197 | QByteArray value_string(data + offset + local_offset, value_length); | - | ||||||||||||
198 | value.setValue(value_string); | - | ||||||||||||
199 | local_offset += round_to_nearest_multiple_of_4(value_length); | - | ||||||||||||
200 | } else if (type == XSettingsTypeInteger) { executed 418 times by 19 tests: end of block Executed by:
| 0-532 | ||||||||||||
201 | VALIDATE_LENGTH(4); never executed: return;
| 0-532 | ||||||||||||
202 | int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset);
| 0-532 | ||||||||||||
203 | local_offset += 4; | - | ||||||||||||
204 | value.setValue(value_length); | - | ||||||||||||
205 | } else if (type == XSettingsTypeColor) { executed 532 times by 19 tests: end of block Executed by:
| 0-532 | ||||||||||||
206 | VALIDATE_LENGTH(2*4); never executed: return;
| 0 | ||||||||||||
207 | quint16 red = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
| 0 | ||||||||||||
208 | local_offset += 2; | - | ||||||||||||
209 | quint16 green = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
| 0 | ||||||||||||
210 | local_offset += 2; | - | ||||||||||||
211 | quint16 blue = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
| 0 | ||||||||||||
212 | local_offset += 2; | - | ||||||||||||
213 | quint16 alpha= ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
| 0 | ||||||||||||
214 | local_offset += 2; | - | ||||||||||||
215 | QColor color_value(red,green,blue,alpha); | - | ||||||||||||
216 | value.setValue(color_value); | - | ||||||||||||
217 | } never executed: end of block | 0 | ||||||||||||
218 | offset += local_offset; | - | ||||||||||||
219 | settings[name].updateValue(screen,name,value,last_change_serial); | - | ||||||||||||
220 | } executed 950 times by 19 tests: end of block Executed by:
| 950 | ||||||||||||
221 | - | |||||||||||||
222 | } executed 19 times by 19 tests: end of block Executed by:
| 19 | ||||||||||||
223 | #endif //XCB_USE_XLIB | - | ||||||||||||
224 | - | |||||||||||||
225 | QXcbVirtualDesktop *screen; | - | ||||||||||||
226 | xcb_window_t x_settings_window; | - | ||||||||||||
227 | QMap<QByteArray, QXcbXSettingsPropertyValue> settings; | - | ||||||||||||
228 | bool initialized; | - | ||||||||||||
229 | }; | - | ||||||||||||
230 | - | |||||||||||||
231 | - | |||||||||||||
232 | QXcbXSettings::QXcbXSettings(QXcbVirtualDesktop *screen) | - | ||||||||||||
233 | : d_ptr(new QXcbXSettingsPrivate(screen)) | - | ||||||||||||
234 | { | - | ||||||||||||
235 | QByteArray settings_atom_for_screen("_XSETTINGS_S"); | - | ||||||||||||
236 | settings_atom_for_screen.append(QByteArray::number(screen->number())); | - | ||||||||||||
237 | xcb_intern_atom_cookie_t atom_cookie = xcb_intern_atom(screen->xcb_connection(), | - | ||||||||||||
238 | true, | - | ||||||||||||
239 | settings_atom_for_screen.length(), | - | ||||||||||||
240 | settings_atom_for_screen.constData()); | - | ||||||||||||
241 | xcb_generic_error_t *error = 0; | - | ||||||||||||
242 | xcb_intern_atom_reply_t *atom_reply = xcb_intern_atom_reply(screen->xcb_connection(),atom_cookie,&error); | - | ||||||||||||
243 | if (error) { | - | ||||||||||||
244 | free(error); | - | ||||||||||||
245 | return; | - | ||||||||||||
246 | } | - | ||||||||||||
247 | xcb_atom_t selection_owner_atom = atom_reply->atom; | - | ||||||||||||
248 | free(atom_reply); | - | ||||||||||||
249 | - | |||||||||||||
250 | xcb_get_selection_owner_cookie_t selection_cookie = | - | ||||||||||||
251 | xcb_get_selection_owner(screen->xcb_connection(), selection_owner_atom); | - | ||||||||||||
252 | - | |||||||||||||
253 | xcb_get_selection_owner_reply_t *selection_result = | - | ||||||||||||
254 | xcb_get_selection_owner_reply(screen->xcb_connection(), selection_cookie, &error); | - | ||||||||||||
255 | if (error) { | - | ||||||||||||
256 | free(error); | - | ||||||||||||
257 | return; | - | ||||||||||||
258 | } | - | ||||||||||||
259 | - | |||||||||||||
260 | d_ptr->x_settings_window = selection_result->owner; | - | ||||||||||||
261 | free(selection_result); | - | ||||||||||||
262 | if (!d_ptr->x_settings_window) { | - | ||||||||||||
263 | return; | - | ||||||||||||
264 | } | - | ||||||||||||
265 | - | |||||||||||||
266 | const uint32_t event = XCB_CW_EVENT_MASK; | - | ||||||||||||
267 | const uint32_t event_mask[] = { XCB_EVENT_MASK_STRUCTURE_NOTIFY|XCB_EVENT_MASK_PROPERTY_CHANGE }; | - | ||||||||||||
268 | xcb_change_window_attributes(screen->xcb_connection(),d_ptr->x_settings_window,event,event_mask); | - | ||||||||||||
269 | - | |||||||||||||
270 | #ifdef XCB_USE_XLIB | - | ||||||||||||
271 | d_ptr->populateSettings(d_ptr->getSettings()); | - | ||||||||||||
272 | d_ptr->initialized = true; | - | ||||||||||||
273 | #endif //XCB_USE_XLIB | - | ||||||||||||
274 | } | - | ||||||||||||
275 | - | |||||||||||||
276 | QXcbXSettings::~QXcbXSettings() | - | ||||||||||||
277 | { | - | ||||||||||||
278 | delete d_ptr; | - | ||||||||||||
279 | d_ptr = 0; | - | ||||||||||||
280 | } | - | ||||||||||||
281 | - | |||||||||||||
282 | bool QXcbXSettings::initialized() const | - | ||||||||||||
283 | { | - | ||||||||||||
284 | Q_D(const QXcbXSettings); | - | ||||||||||||
285 | return d->initialized; | - | ||||||||||||
286 | } | - | ||||||||||||
287 | - | |||||||||||||
288 | void QXcbXSettings::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) | - | ||||||||||||
289 | { | - | ||||||||||||
290 | Q_D(QXcbXSettings); | - | ||||||||||||
291 | if (event->window != d->x_settings_window) | - | ||||||||||||
292 | return; | - | ||||||||||||
293 | #ifdef XCB_USE_XLIB | - | ||||||||||||
294 | d->populateSettings(d->getSettings()); | - | ||||||||||||
295 | #endif //XCB_USE_XLIB | - | ||||||||||||
296 | } | - | ||||||||||||
297 | - | |||||||||||||
298 | void QXcbXSettings::registerCallbackForProperty(const QByteArray &property, QXcbXSettings::PropertyChangeFunc func, void *handle) | - | ||||||||||||
299 | { | - | ||||||||||||
300 | Q_D(QXcbXSettings); | - | ||||||||||||
301 | d->settings[property].addCallback(func,handle); | - | ||||||||||||
302 | } | - | ||||||||||||
303 | - | |||||||||||||
304 | void QXcbXSettings::removeCallbackForHandle(const QByteArray &property, void *handle) | - | ||||||||||||
305 | { | - | ||||||||||||
306 | Q_D(QXcbXSettings); | - | ||||||||||||
307 | QXcbXSettingsPropertyValue &valueauto &callbacks = d->settings[property]; | - | ||||||||||||
QLinkedList<QXcbXSettingsCallback>::iterator it = value.callback_links.begin(); | ||||||||||||||
while (it != value.].callback_links.end()); | ||||||||||||||
308 | - | |||||||||||||
309 | auto isCallbackForHandle = [handle](const QXcbXSettingsCallback &cb) executed 19 times by 19 tests: { if (it->return cb.handle == handle)return cb.handle == handle; Executed by:
executed 19 times by 19 tests: return cb.handle == handle; Executed by:
| 19 | ||||||||||||
it = value.callback_links executed 19 times by 19 tests: ; };return cb.handle == handle; Executed by:
executed 19 times by 19 tests: return cb.handle == handle; Executed by:
| ||||||||||||||
310 | - | |||||||||||||
311 | callbacks.erase(it); | - | ||||||||||||
else | ||||||||||||||
++it; | ||||||||||||||
}std::remove_if(callbacks.begin(), callbacks.end(), | ||||||||||||||
312 | isCallbackForHandle), | - | ||||||||||||
313 | callbacks.end()); | - | ||||||||||||
314 | } executed 950 times by 19 tests: end of block Executed by:
| 950 | ||||||||||||
315 | - | |||||||||||||
316 | void QXcbXSettings::removeCallbackForHandle(void *handle) | - | ||||||||||||
317 | { | - | ||||||||||||
318 | Q_D(QXcbXSettings); | - | ||||||||||||
319 | for (QMap<QByteArray, QXcbXSettingsPropertyValue>::const_iterator it = d->settings.cbegin(); | - | ||||||||||||
320 | it != d->settings.cend(); ++it) { | - | ||||||||||||
321 | removeCallbackForHandle(it.key(),handle); | - | ||||||||||||
322 | } | - | ||||||||||||
323 | } | - | ||||||||||||
324 | - | |||||||||||||
325 | QVariant QXcbXSettings::setting(const QByteArray &property) const | - | ||||||||||||
326 | { | - | ||||||||||||
327 | Q_D(const QXcbXSettings); | - | ||||||||||||
328 | return d->settings.value(property).value; | - | ||||||||||||
329 | } | - | ||||||||||||
330 | - | |||||||||||||
331 | QT_END_NAMESPACE | - | ||||||||||||
Source code | Switch to Preprocessed file |