diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 7381c8c886e2b2a985cd387e95c26d4231cd8b62..db2179c73f581b9d70ac3cafdda2b3987cbbc3c7 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 3aa13a8b3a5377dd12d9073d9295502fe81e2343..cba26e148cc1365be0e5a0d43de47a7cd6d380ee 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 a6ead49a278efbfaea5b8775f3c5884726f1668d..37c6c97bc4c710721cd768a5a9d4271df3654cc6 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 0382be8a29a35bcc24a5d85feff181f5ae2aa0bb..c36492db6451396a7f26f72ffea6f701a64b0f62 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 0000000000000000000000000000000000000000..7ffd3e105fd61683b23e17cbd26a22ec27897261
--- /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 0000000000000000000000000000000000000000..16fed862bcf66fc5de23609e19a69336c655e934
--- /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 f01fa90e2d33f5e991667efbb9051686c2e298c3..82995286c40002b068a9b174419dd3fcda508c54 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