summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp1
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h1
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp10
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbxsettings.cpp280
-rw-r--r--src/plugins/platforms/xcb/qxcbxsettings.h71
-rw-r--r--src/plugins/platforms/xcb/xcb-plugin.pro6
7 files changed, 372 insertions, 2 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 7381c8c886..db2179c73f 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -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)
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 3aa13a8b3a..cba26e148c 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -269,6 +269,7 @@ namespace QXcbAtom {
#if XCB_USE_MAEMO_WINDOW_PROPERTIES
MeegoTouchOrientationAngle,
#endif
+ _XSETTINGS_SETTINGS,
NPredefinedAtoms,
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index a6ead49a27..37c6c97bc4 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -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
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index 0382be8a29..c36492db64 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -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
diff --git a/src/plugins/platforms/xcb/qxcbxsettings.cpp b/src/plugins/platforms/xcb/qxcbxsettings.cpp
new file mode 100644
index 0000000000..7ffd3e105f
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbxsettings.cpp
@@ -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
diff --git a/src/plugins/platforms/xcb/qxcbxsettings.h b/src/plugins/platforms/xcb/qxcbxsettings.h
new file mode 100644
index 0000000000..16fed862bc
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbxsettings.h
@@ -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
diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro
index f01fa90e2d..82995286c4 100644
--- a/src/plugins/platforms/xcb/xcb-plugin.pro
+++ b/src/plugins/platforms/xcb/xcb-plugin.pro
@@ -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