~ubuntu-branches/ubuntu/wily/libkscreen/wily-proposed

« back to all changes in this revision

Viewing changes to backends/xrandr/xrandrxcbhelper.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2014-10-01 15:47:21 UTC
  • Revision ID: package-import@ubuntu.com-20141001154721-96ng88bgtxpj8sjv
Tags: upstream-5.1.0.1
Import upstream version 5.1.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*************************************************************************************
 
2
 *  Copyright 2012, 2013  Daniel Vrátil <dvratil@redhat.com>                         *
 
3
 *                                                                                   *
 
4
 *  This library is free software; you can redistribute it and/or                    *
 
5
 *  modify it under the terms of the GNU Lesser General Public                       *
 
6
 *  License as published by the Free Software Foundation; either                     *
 
7
 *  version 2.1 of the License, or (at your option) any later version.               *
 
8
 *                                                                                   *
 
9
 *  This library is distributed in the hope that it will be useful,                  *
 
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
 
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                *
 
12
 *  Lesser General Public License for more details.                                  *
 
13
 *                                                                                   *
 
14
 *  You should have received a copy of the GNU Lesser General Public                 *
 
15
 *  License along with this library; if not, write to the Free Software              *
 
16
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA       *
 
17
 *************************************************************************************/
 
18
 
 
19
#include "xrandrxcbhelper.h"
 
20
#include "xrandr.h"
 
21
#include "xlibandxrandr.h"
 
22
 
 
23
#include <xcb/randr.h>
 
24
 
 
25
#include <QX11Info>
 
26
#include <QGuiApplication>
 
27
 
 
28
Q_LOGGING_CATEGORY(KSCREEN_XCB_HELPER, "kscreen.xcb.helper")
 
29
XRandRXCBHelper::XRandRXCBHelper():
 
30
    QObject(),
 
31
    m_isRandrPresent(false),
 
32
    m_event11(false),
 
33
    m_randrBase(0),
 
34
    m_randrErrorBase(0),
 
35
    m_majorOpcode(0),
 
36
    m_eventType(0),
 
37
    m_versionMajor(0),
 
38
    m_versionMinor(0),
 
39
    m_window(0)
 
40
{
 
41
    QLoggingCategory::setFilterRules(QStringLiteral("kscreen.xcb.helper = true"));
 
42
 
 
43
    xcb_connection_t* c = QX11Info::connection();
 
44
    xcb_prefetch_extension_data(c, &xcb_randr_id);
 
45
    xcb_randr_query_version_cookie_t cookie = xcb_randr_query_version(c,
 
46
                                                                      XCB_RANDR_MAJOR_VERSION,
 
47
                                                                      XCB_RANDR_MINOR_VERSION
 
48
                                                                     );
 
49
    const xcb_query_extension_reply_t *queryExtension = xcb_get_extension_data(c, &xcb_randr_id);
 
50
    if (!queryExtension) {
 
51
        qCDebug(KSCREEN_XCB_HELPER) << "Fail to query for xrandr extension";
 
52
        return;
 
53
    }
 
54
    if (!queryExtension->present) {
 
55
        qCDebug(KSCREEN_XCB_HELPER) << "XRandR extension is not present at all";
 
56
        return;
 
57
    }
 
58
 
 
59
    m_isRandrPresent = queryExtension->present;
 
60
    m_randrBase = queryExtension->first_event;
 
61
    m_randrErrorBase = queryExtension->first_error;
 
62
    m_majorOpcode = queryExtension->major_opcode;
 
63
 
 
64
    xcb_generic_error_t *error = NULL;
 
65
    xcb_randr_query_version_reply_t* versionReply = xcb_randr_query_version_reply(c, cookie, &error);
 
66
    Q_ASSERT_X(versionReply, "xrandrxcbhelper", "Query to fetch xrandr version failed");
 
67
    if (error) {
 
68
        qFatal("Error while querying for xrandr version: %d", error->error_code);
 
69
    }
 
70
    m_versionMajor = versionReply->major_version;
 
71
    m_versionMinor = versionReply->minor_version;
 
72
    free(versionReply);
 
73
 
 
74
    if (m_versionMajor == 1 && m_versionMinor <= 1) {
 
75
        m_event11 = true;
 
76
    }
 
77
    qCDebug(KSCREEN_XCB_HELPER).nospace() << "Detected XRandR " << m_versionMajor << "." << m_versionMinor;
 
78
    qCDebug(KSCREEN_XCB_HELPER) << "Event Base: " << m_randrBase;
 
79
    qCDebug(KSCREEN_XCB_HELPER) << "Event Error: "<< m_randrErrorBase;
 
80
 
 
81
    uint32_t rWindow = QX11Info::appRootWindow();
 
82
    m_window = xcb_generate_id(c);
 
83
    xcb_create_window(c, XCB_COPY_FROM_PARENT, m_window,
 
84
                      rWindow,
 
85
                      0, 0, 1, 1, 0, XCB_COPY_FROM_PARENT,
 
86
                      XCB_COPY_FROM_PARENT, 0, NULL);
 
87
 
 
88
    xcb_randr_select_input(c, m_window,
 
89
            XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE |
 
90
            XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE |
 
91
            XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE |
 
92
            XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY
 
93
    );
 
94
 
 
95
    qApp->installNativeEventFilter(this);
 
96
}
 
97
 
 
98
XRandRXCBHelper::~XRandRXCBHelper()
 
99
{
 
100
    if (m_window && QX11Info::connection()) {
 
101
        xcb_destroy_window(QX11Info::connection(), m_window);
 
102
    }
 
103
}
 
104
 
 
105
QString XRandRXCBHelper::rotationToString(Rotation rotation)
 
106
{
 
107
    switch (rotation) {
 
108
        case RR_Rotate_0:
 
109
            return "RR_Rotate_0";
 
110
        case RR_Rotate_90:
 
111
            return "RR_Rotate_90";
 
112
        case RR_Rotate_180:
 
113
            return "RR_Rotate_180";
 
114
        case RR_Rotate_270:
 
115
            return "RR_Rotate_270";
 
116
    }
 
117
 
 
118
    return QString("invalid value (%1)").arg(rotation);
 
119
}
 
120
 
 
121
QString XRandRXCBHelper::connectionToString(Connection connection)
 
122
{
 
123
    switch (connection) {
 
124
        case RR_Connected:
 
125
            return "RR_Connected";
 
126
        case RR_Disconnected:
 
127
            return "RR_Disconnected";
 
128
        case RR_UnknownConnection:
 
129
            return "RR_UnknownConnection";
 
130
    }
 
131
 
 
132
    return QString("invalid value (%1)").arg(connection);
 
133
}
 
134
 
 
135
bool XRandRXCBHelper::nativeEventFilter(const QByteArray& eventType, void* message, long int* result)
 
136
{
 
137
    Q_UNUSED(result);
 
138
 
 
139
    if (eventType != "xcb_generic_event_t") {
 
140
        return false;
 
141
    }
 
142
 
 
143
    xcb_generic_event_t* e = static_cast<xcb_generic_event_t *>(message);
 
144
    const uint8_t xEventType = e->response_type & ~0x80;
 
145
 
 
146
    //If this event is not xcb_randr_notify, we don't want it
 
147
    if (xEventType == m_randrBase + XCB_RANDR_SCREEN_CHANGE_NOTIFY && m_event11) {
 
148
        handleScreenChange(e);
 
149
    }
 
150
    if (xEventType == m_randrBase + XCB_RANDR_NOTIFY) {
 
151
        handleXRandRNotify(e);
 
152
    }
 
153
 
 
154
    return false;
 
155
}
 
156
 
 
157
void XRandRXCBHelper::handleScreenChange(xcb_generic_event_t* e)
 
158
{
 
159
    xcb_randr_screen_change_notify_event_t *e2 =
 
160
        (xcb_randr_screen_change_notify_event_t *) e;
 
161
    qCDebug(KSCREEN_XCB_HELPER) << "Timestamp: " << e2->timestamp;
 
162
    qCDebug(KSCREEN_XCB_HELPER) << "Window: " << e2->request_window;
 
163
    qCDebug(KSCREEN_XCB_HELPER) << "Root: "<< e2->root;
 
164
    qCDebug(KSCREEN_XCB_HELPER) << "Subpixel Order:" << e2->subpixel_order;
 
165
    qCDebug(KSCREEN_XCB_HELPER) << "Rotation: " << rotationToString(e2->rotation);
 
166
    qCDebug(KSCREEN_XCB_HELPER) << "Size: " << e2->width << e2->height;
 
167
    qCDebug(KSCREEN_XCB_HELPER) << "SizeMM: " << e2->mwidth << e2->mheight;
 
168
 
 
169
    Q_EMIT outputsChanged();
 
170
}
 
171
 
 
172
void XRandRXCBHelper::handleXRandRNotify(xcb_generic_event_t* e)
 
173
{
 
174
    xcb_randr_notify_event_t*
 
175
    randrEvent = reinterpret_cast<xcb_randr_notify_event_t*>(e);
 
176
 
 
177
    if (randrEvent->subCode == XCB_RANDR_NOTIFY_CRTC_CHANGE) {
 
178
        xcb_randr_crtc_change_t crtc = randrEvent->u.cc;
 
179
        qCDebug(KSCREEN_XCB_HELPER) << "CRTC CHANGE";
 
180
        qCDebug(KSCREEN_XCB_HELPER) << "CRTC: " << crtc.crtc;
 
181
        qCDebug(KSCREEN_XCB_HELPER) << "Mode: " << crtc.mode;
 
182
        qCDebug(KSCREEN_XCB_HELPER) << "Rotation: " << rotationToString(crtc.rotation);
 
183
        qCDebug(KSCREEN_XCB_HELPER) << "Geometry: " << crtc.x << crtc.y << crtc.width << crtc.height;
 
184
 
 
185
        Q_EMIT crtcChanged(crtc.crtc);
 
186
    } else if(randrEvent->subCode == XCB_RANDR_NOTIFY_OUTPUT_CHANGE) {
 
187
        xcb_randr_output_change_t output = randrEvent->u.oc;
 
188
        qCDebug(KSCREEN_XCB_HELPER) << "OUTPUT CHANGE";
 
189
        qCDebug(KSCREEN_XCB_HELPER) << "Output: " << output.output;
 
190
        qCDebug(KSCREEN_XCB_HELPER) << "CRTC: " << output.crtc;
 
191
        qCDebug(KSCREEN_XCB_HELPER) << "Mode: " << output.mode;
 
192
        qCDebug(KSCREEN_XCB_HELPER) << "Rotation: " << rotationToString(output.rotation);
 
193
        qCDebug(KSCREEN_XCB_HELPER) << "Connection: " << connectionToString(output.connection);
 
194
        qCDebug(KSCREEN_XCB_HELPER) << "Subpixel Order: " << output.subpixel_order;
 
195
 
 
196
        Q_EMIT outputChanged(output.output);
 
197
    } else if(randrEvent->subCode == XCB_RANDR_NOTIFY_OUTPUT_PROPERTY) {
 
198
        xcb_randr_output_property_t property = randrEvent->u.op;
 
199
 
 
200
        xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(QX11Info::connection(), xcb_get_atom_name(QX11Info::connection(), property.atom), NULL) ;
 
201
 
 
202
        qCDebug(KSCREEN_XCB_HELPER) << "OUTPUT PROPERTY";
 
203
        qCDebug(KSCREEN_XCB_HELPER) << "Output: " << property.output;
 
204
        qCDebug(KSCREEN_XCB_HELPER) << "Property: " << xcb_get_atom_name_name(reply);
 
205
        qCDebug(KSCREEN_XCB_HELPER) << "State (newValue, Deleted): " << property.status;
 
206
        free(reply);
 
207
    }
 
208
}
 
209
 
 
210
 
 
211
bool XRandRXCBHelper::x11Event(XEvent *event)
 
212
{
 
213
    /* XRandR <= 1.1 */
 
214
    if (m_versionMajor == 1 && m_versionMinor <= 1) {
 
215
        if (event->xany.type == m_randrBase + RRScreenChangeNotify) {
 
216
 
 
217
            XRRScreenChangeNotifyEvent* e2 = reinterpret_cast< XRRScreenChangeNotifyEvent* >(event);
 
218
 
 
219
            qCDebug(KSCREEN_XCB_HELPER) << "Timestamp: " << e2->timestamp;
 
220
            qCDebug(KSCREEN_XCB_HELPER) << "Window: " << e2->window;
 
221
            qCDebug(KSCREEN_XCB_HELPER) << "Root: "<< e2->root;
 
222
            qCDebug(KSCREEN_XCB_HELPER) << "Size Index: " << e2->size_index;
 
223
            qCDebug(KSCREEN_XCB_HELPER) << "Subpixel Order:" << e2->subpixel_order;
 
224
            qCDebug(KSCREEN_XCB_HELPER) << "Rotation: " << rotationToString(e2->rotation);
 
225
            qCDebug(KSCREEN_XCB_HELPER) << "Size: " << e2->width << e2->height;
 
226
            qCDebug(KSCREEN_XCB_HELPER) << "SizeMM: " << e2->mwidth << e2->mheight;
 
227
 
 
228
            Q_EMIT outputsChanged();
 
229
        }
 
230
 
 
231
        return false;
 
232
    }
 
233
 
 
234
    /* XRandR >= 1.2 */
 
235
    if (event->xany.type == m_randrBase + RRNotify) {
 
236
        XRRNotifyEvent* e2 = reinterpret_cast< XRRNotifyEvent* >(event);
 
237
        if (e2->subtype == RRNotify_CrtcChange) {
 
238
            XRRCrtcChangeNotifyEvent* e2 = reinterpret_cast< XRRCrtcChangeNotifyEvent* >(event);
 
239
 
 
240
            qCDebug(KSCREEN_XCB_HELPER) << "CRTC: " << e2->crtc;
 
241
            qCDebug(KSCREEN_XCB_HELPER) << "Mode: " << e2->mode;
 
242
            qCDebug(KSCREEN_XCB_HELPER) << "Rotation: " << rotationToString(e2->rotation);
 
243
            qCDebug(KSCREEN_XCB_HELPER) << "Geometry: " << e2->x << e2->y << e2->width << e2->height;
 
244
 
 
245
            Q_EMIT crtcChanged(e2->crtc);
 
246
 
 
247
        } else if (e2->subtype == RRNotify_OutputChange) {
 
248
            XRROutputChangeNotifyEvent* e2 = reinterpret_cast< XRROutputChangeNotifyEvent* >(event);
 
249
 
 
250
            qCDebug(KSCREEN_XCB_HELPER) << "Output: " << e2->output;
 
251
            qCDebug(KSCREEN_XCB_HELPER) << "CRTC: " << e2->crtc;
 
252
            qCDebug(KSCREEN_XCB_HELPER) << "Mode: " << e2->mode;
 
253
            qCDebug(KSCREEN_XCB_HELPER) << "Rotation: " << rotationToString(e2->rotation);
 
254
            qCDebug(KSCREEN_XCB_HELPER) << "Connection: " << connectionToString(e2->connection);
 
255
            qCDebug(KSCREEN_XCB_HELPER) << "Subpixel Order: " << e2->subpixel_order;
 
256
 
 
257
            Q_EMIT outputChanged(e2->output);
 
258
 
 
259
        } else if (e2->subtype == RRNotify_OutputProperty) {
 
260
            XRROutputPropertyNotifyEvent* e2 = reinterpret_cast< XRROutputPropertyNotifyEvent* >(event);
 
261
 
 
262
            char *atom_name = XGetAtomName(QX11Info::display(), e2->property);
 
263
            qCDebug(KSCREEN_XCB_HELPER) << "Timestamp: " << e2->timestamp;
 
264
            qCDebug(KSCREEN_XCB_HELPER) << "Output: " << e2->output;
 
265
            qCDebug(KSCREEN_XCB_HELPER) << "Property: " << XGetAtomName(QX11Info::display(), e2->property);
 
266
            qCDebug(KSCREEN_XCB_HELPER) << "State (newValue, Deleted): " << e2->state;
 
267
            XFree(atom_name);
 
268
        }
 
269
    }
 
270
 
 
271
    return false;
 
272
}
 
273
 
 
274
#include "xrandrxcbhelper.moc"