mirror of https://github.com/qt/qtbase.git
Introduce QXcbXSettings
This allows you to easily retrieve properties in the XSETTINGS specification. It is also possible to add listeners to get notified when a specific property changes. XSETTINGS is lazy initialized, so it will not be instansiated before someone uses it. For now the intended use is a fallback for finding cursor theme Change-Id: Id47f0613f5876424cd47d721b40da17d3f63429e Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
This commit is contained in:
parent
3c69751ef2
commit
0f31a5d91f
|
@ -1397,6 +1397,7 @@ static const char * xcb_atomnames = {
|
|||
#if XCB_USE_MAEMO_WINDOW_PROPERTIES
|
||||
"_MEEGOTOUCH_ORIENTATION_ANGLE\0"
|
||||
#endif
|
||||
"_XSETTINGS_SETTINGS"
|
||||
};
|
||||
|
||||
xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom)
|
||||
|
|
|
@ -269,6 +269,7 @@ namespace QXcbAtom {
|
|||
#if XCB_USE_MAEMO_WINDOW_PROPERTIES
|
||||
MeegoTouchOrientationAngle,
|
||||
#endif
|
||||
_XSETTINGS_SETTINGS,
|
||||
|
||||
NPredefinedAtoms,
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "qxcbcursor.h"
|
||||
#include "qxcbimage.h"
|
||||
#include "qnamespace.h"
|
||||
#include "qxcbxsettings.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -68,6 +69,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
|
|||
, m_refreshRate(60)
|
||||
, m_forcedDpi(-1)
|
||||
, m_hintStyle(QFontEngine::HintStyle(-1))
|
||||
, m_xSettings(0)
|
||||
{
|
||||
if (connection->hasXRandr())
|
||||
xcb_randr_select_input(xcb_connection(), screen()->root, true);
|
||||
|
@ -580,4 +582,12 @@ void QXcbScreen::readXResources()
|
|||
}
|
||||
}
|
||||
|
||||
QXcbXSettings *QXcbScreen::xSettings() const
|
||||
{
|
||||
if (!m_xSettings) {
|
||||
QXcbScreen *self = const_cast<QXcbScreen *>(this);
|
||||
self->m_xSettings = new QXcbXSettings(self);
|
||||
}
|
||||
return m_xSettings;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE
|
|||
|
||||
class QXcbConnection;
|
||||
class QXcbCursor;
|
||||
class QXcbXSettings;
|
||||
|
||||
class QXcbScreen : public QXcbObject, public QPlatformScreen
|
||||
{
|
||||
|
@ -102,6 +103,9 @@ public:
|
|||
void readXResources();
|
||||
|
||||
QFontEngine::HintStyle hintStyle() const { return m_hintStyle; }
|
||||
|
||||
QXcbXSettings *xSettings() const;
|
||||
|
||||
private:
|
||||
static bool xResource(const QByteArray &identifier,
|
||||
const QByteArray &expectedIdentifier,
|
||||
|
@ -127,6 +131,7 @@ private:
|
|||
int m_refreshRate;
|
||||
int m_forcedDpi;
|
||||
QFontEngine::HintStyle m_hintStyle;
|
||||
QXcbXSettings *m_xSettings;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -0,0 +1,280 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qxcbxsettings.h"
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
#include <X11/extensions/XIproto.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
/* Implementation of http://standards.freedesktop.org/xsettings-spec/xsettings-0.5.html */
|
||||
|
||||
enum XSettingsType {
|
||||
XSettingsTypeInteger = 0,
|
||||
XSettingsTypeString = 1,
|
||||
XSettingsTypeColor = 2
|
||||
};
|
||||
|
||||
class QXcbXSettingsCallback
|
||||
{
|
||||
public:
|
||||
QXcbXSettings::PropertyChangeFunc func;
|
||||
void *handle;
|
||||
};
|
||||
|
||||
class QXcbXSettingsPropertyValue
|
||||
{
|
||||
public:
|
||||
QXcbXSettingsPropertyValue()
|
||||
: last_change_serial(-1)
|
||||
{}
|
||||
|
||||
void updateValue(QXcbScreen *screen, const QByteArray &name, const QVariant &value, int last_change_serial)
|
||||
{
|
||||
if (last_change_serial <= this->last_change_serial)
|
||||
return;
|
||||
this->value = value;
|
||||
this->last_change_serial = last_change_serial;
|
||||
QLinkedList<QXcbXSettingsCallback>::const_iterator it = callback_links.begin();
|
||||
for (;it != callback_links.end();++it) {
|
||||
it->func(screen,name,value,it->handle);
|
||||
}
|
||||
}
|
||||
|
||||
void addCallback(QXcbXSettings::PropertyChangeFunc func, void *handle)
|
||||
{
|
||||
QXcbXSettingsCallback callback;
|
||||
callback.func = func;
|
||||
callback.handle = handle;
|
||||
callback_links.append(callback);
|
||||
}
|
||||
|
||||
QVariant value;
|
||||
int last_change_serial;
|
||||
QLinkedList<QXcbXSettingsCallback> callback_links;
|
||||
|
||||
};
|
||||
|
||||
class QXcbXSettingsPrivate
|
||||
{
|
||||
public:
|
||||
QXcbXSettingsPrivate(QXcbScreen *screen)
|
||||
: screen(screen)
|
||||
{
|
||||
}
|
||||
|
||||
QByteArray getSettings()
|
||||
{
|
||||
QXcbConnectionGrabber connectionGrabber(screen->connection());
|
||||
|
||||
int offset = 0;
|
||||
QByteArray settings;
|
||||
xcb_atom_t _xsettings_atom = screen->connection()->atom(QXcbAtom::_XSETTINGS_SETTINGS);
|
||||
while (1) {
|
||||
xcb_get_property_cookie_t get_prop_cookie =
|
||||
xcb_get_property_unchecked(screen->xcb_connection(),
|
||||
false,
|
||||
x_settings_window,
|
||||
_xsettings_atom,
|
||||
_xsettings_atom,
|
||||
offset/4,
|
||||
8192);
|
||||
xcb_get_property_reply_t *reply = xcb_get_property_reply(screen->xcb_connection(), get_prop_cookie, NULL);
|
||||
bool more = false;
|
||||
if (!reply)
|
||||
return settings;
|
||||
|
||||
settings += QByteArray((const char *)xcb_get_property_value(reply), xcb_get_property_value_length(reply));
|
||||
offset += xcb_get_property_value_length(reply);
|
||||
more = reply->bytes_after != 0;
|
||||
|
||||
free(reply);
|
||||
|
||||
if (!more)
|
||||
break;
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
static int round_to_nearest_multiple_of_4(int value)
|
||||
{
|
||||
int remainder = value % 4;
|
||||
if (!remainder)
|
||||
return value;
|
||||
return value + 4 - remainder;
|
||||
}
|
||||
|
||||
void populateSettings(const QByteArray &xSettings)
|
||||
{
|
||||
if (xSettings.length() < 12)
|
||||
return;
|
||||
// we ignore byteorder for now
|
||||
char byteOrder = xSettings.at(1);
|
||||
Q_UNUSED(byteOrder);
|
||||
uint serial = *reinterpret_cast<const uint *>(xSettings.mid(4,4).constData());
|
||||
serial = serial;
|
||||
uint number_of_settings = *reinterpret_cast<const uint *>(xSettings.mid(8,4).constData());
|
||||
|
||||
const char *data = xSettings.constData() + 12;
|
||||
size_t offset = 0;
|
||||
for (uint i = 0; i < number_of_settings; i++) {
|
||||
int local_offset = 0;
|
||||
XSettingsType type = static_cast<XSettingsType>(*reinterpret_cast<const quint8 *>(data + offset));
|
||||
local_offset += 2;
|
||||
|
||||
quint16 name_len = *reinterpret_cast<const quint16 *>(data + offset + local_offset);
|
||||
local_offset += 2;
|
||||
|
||||
QByteArray name(data + offset + local_offset, name_len);
|
||||
local_offset += round_to_nearest_multiple_of_4(name_len);
|
||||
|
||||
int last_change_serial = *reinterpret_cast<const int *>(data + offset + local_offset);
|
||||
Q_UNUSED(last_change_serial);
|
||||
local_offset += 4;
|
||||
|
||||
QVariant value;
|
||||
if (type == XSettingsTypeString) {
|
||||
int value_length = *reinterpret_cast<const int *>(data + offset + local_offset);
|
||||
local_offset+=4;
|
||||
QByteArray value_string(data + offset + local_offset, value_length);
|
||||
value.setValue(value_string);
|
||||
local_offset += round_to_nearest_multiple_of_4(value_length);
|
||||
} else if (type == XSettingsTypeInteger) {
|
||||
int value_length = *reinterpret_cast<const int *>(data + offset + local_offset);
|
||||
local_offset += 4;
|
||||
value.setValue(value_length);
|
||||
} else if (type == XSettingsTypeColor) {
|
||||
quint16 red = *reinterpret_cast<const quint16 *>(data + offset + local_offset);
|
||||
local_offset += 2;
|
||||
quint16 green = *reinterpret_cast<const quint16 *>(data + offset + local_offset);
|
||||
local_offset += 2;
|
||||
quint16 blue = *reinterpret_cast<const quint16 *>(data + offset + local_offset);
|
||||
local_offset += 2;
|
||||
quint16 alpha= *reinterpret_cast<const quint16 *>(data + offset + local_offset);
|
||||
local_offset += 2;
|
||||
QColor color_value(red,green,blue,alpha);
|
||||
value.setValue(color_value);
|
||||
}
|
||||
offset += local_offset;
|
||||
settings[name].updateValue(screen,name,value,last_change_serial);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QXcbScreen *screen;
|
||||
xcb_window_t x_settings_window;
|
||||
int serial;
|
||||
QMap<QByteArray, QXcbXSettingsPropertyValue> settings;
|
||||
};
|
||||
|
||||
|
||||
QXcbXSettings::QXcbXSettings(QXcbScreen *screen)
|
||||
: d_ptr(new QXcbXSettingsPrivate(screen))
|
||||
{
|
||||
QByteArray settings_atom_for_screen("_XSETTINGS_S");
|
||||
settings_atom_for_screen.append(QByteArray::number(screen->screenNumber()));
|
||||
xcb_intern_atom_cookie_t atom_cookie = xcb_intern_atom(screen->xcb_connection(),
|
||||
false,
|
||||
settings_atom_for_screen.length(),
|
||||
settings_atom_for_screen.constData());
|
||||
xcb_intern_atom_reply_t *atom_reply = xcb_intern_atom_reply(screen->xcb_connection(),atom_cookie,NULL);
|
||||
xcb_atom_t selection_owner_atom = atom_reply->atom;
|
||||
free(atom_reply);
|
||||
|
||||
xcb_get_selection_owner_cookie_t selection_cookie =
|
||||
xcb_get_selection_owner(screen->xcb_connection(), selection_owner_atom);
|
||||
xcb_get_selection_owner_reply_t *selection_result =
|
||||
xcb_get_selection_owner_reply(screen->xcb_connection(), selection_cookie, NULL);
|
||||
|
||||
d_ptr->x_settings_window = selection_result->owner;
|
||||
free(selection_result);
|
||||
|
||||
const uint32_t event_mask[] = { XCB_EVENT_MASK_STRUCTURE_NOTIFY|XCB_EVENT_MASK_PROPERTY_CHANGE };
|
||||
xcb_change_window_attributes(screen->xcb_connection(),d_ptr->x_settings_window,XCB_CW_EVENT_MASK,event_mask);
|
||||
|
||||
d_ptr->populateSettings(d_ptr->getSettings());
|
||||
}
|
||||
|
||||
void QXcbXSettings::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event)
|
||||
{
|
||||
Q_D(QXcbXSettings);
|
||||
if (event->window != d->x_settings_window)
|
||||
return;
|
||||
d->populateSettings(d->getSettings());
|
||||
}
|
||||
|
||||
void QXcbXSettings::registerCallbackForProperty(const QByteArray &property, QXcbXSettings::PropertyChangeFunc func, void *handle)
|
||||
{
|
||||
Q_D(QXcbXSettings);
|
||||
d->settings[property].addCallback(func,handle);
|
||||
}
|
||||
|
||||
void QXcbXSettings::removeCallbackForHandle(const QByteArray &property, void *handle)
|
||||
{
|
||||
Q_D(QXcbXSettings);
|
||||
QXcbXSettingsPropertyValue &value = d->settings[property];
|
||||
QLinkedList<QXcbXSettingsCallback>::iterator it = value.callback_links.begin();
|
||||
while (it != value.callback_links.end()) {
|
||||
if (it->handle == handle)
|
||||
it = value.callback_links.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void QXcbXSettings::removeCallbackForHandle(void *handle)
|
||||
{
|
||||
Q_D(QXcbXSettings);
|
||||
for (QMap<QByteArray, QXcbXSettingsPropertyValue>::const_iterator it = d->settings.cbegin();
|
||||
it != d->settings.cend(); ++it) {
|
||||
removeCallbackForHandle(it.key(),handle);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant QXcbXSettings::setting(const QByteArray &property) const
|
||||
{
|
||||
Q_D(const QXcbXSettings);
|
||||
return d->settings.value(property).value;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
|
@ -0,0 +1,71 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QXCBXSETTINGS_H
|
||||
#define QXCBXSETTINGS_H
|
||||
|
||||
#include "qxcbscreen.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QXcbXSettingsPrivate;
|
||||
|
||||
class QXcbXSettings : public QXcbWindowEventListener
|
||||
{
|
||||
Q_DECLARE_PRIVATE(QXcbXSettings)
|
||||
public:
|
||||
QXcbXSettings(QXcbScreen *screen);
|
||||
|
||||
QVariant setting(const QByteArray &property) const;
|
||||
|
||||
typedef void (*PropertyChangeFunc)(QXcbScreen *screen, const QByteArray &name, const QVariant &property, void *handle);
|
||||
void registerCallbackForProperty(const QByteArray &property, PropertyChangeFunc func, void *handle);
|
||||
void removeCallbackForHandle(const QByteArray &property, void *handle);
|
||||
void removeCallbackForHandle(void *handle);
|
||||
|
||||
void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) Q_DECL_OVERRIDE;
|
||||
private:
|
||||
QXcbXSettingsPrivate *d_ptr;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QXCBXSETTINGS_H
|
|
@ -20,7 +20,8 @@ SOURCES = \
|
|||
main.cpp \
|
||||
qxcbnativeinterface.cpp \
|
||||
qxcbcursor.cpp \
|
||||
qxcbimage.cpp
|
||||
qxcbimage.cpp \
|
||||
qxcbxsettings.cpp
|
||||
|
||||
HEADERS = \
|
||||
qxcbclipboard.h \
|
||||
|
@ -36,7 +37,8 @@ HEADERS = \
|
|||
qxcbwmsupport.h \
|
||||
qxcbnativeinterface.h \
|
||||
qxcbcursor.h \
|
||||
qxcbimage.h
|
||||
qxcbimage.h \
|
||||
qxcbxsettings.h
|
||||
|
||||
LIBS += -ldl
|
||||
|
||||
|
|
Loading…
Reference in New Issue