1
/*************************************************************************************
2
* Copyright 2012, 2013 Daniel Vrátil <dvratil@redhat.com> *
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. *
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. *
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
*************************************************************************************/
19
#include "xrandrxcbhelper.h"
21
#include "xlibandxrandr.h"
23
#include <xcb/randr.h>
26
#include <QGuiApplication>
28
Q_LOGGING_CATEGORY(KSCREEN_XCB_HELPER, "kscreen.xcb.helper")
29
XRandRXCBHelper::XRandRXCBHelper():
31
m_isRandrPresent(false),
41
QLoggingCategory::setFilterRules(QStringLiteral("kscreen.xcb.helper = true"));
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
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";
54
if (!queryExtension->present) {
55
qCDebug(KSCREEN_XCB_HELPER) << "XRandR extension is not present at all";
59
m_isRandrPresent = queryExtension->present;
60
m_randrBase = queryExtension->first_event;
61
m_randrErrorBase = queryExtension->first_error;
62
m_majorOpcode = queryExtension->major_opcode;
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");
68
qFatal("Error while querying for xrandr version: %d", error->error_code);
70
m_versionMajor = versionReply->major_version;
71
m_versionMinor = versionReply->minor_version;
74
if (m_versionMajor == 1 && m_versionMinor <= 1) {
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;
81
uint32_t rWindow = QX11Info::appRootWindow();
82
m_window = xcb_generate_id(c);
83
xcb_create_window(c, XCB_COPY_FROM_PARENT, m_window,
85
0, 0, 1, 1, 0, XCB_COPY_FROM_PARENT,
86
XCB_COPY_FROM_PARENT, 0, NULL);
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
95
qApp->installNativeEventFilter(this);
98
XRandRXCBHelper::~XRandRXCBHelper()
100
if (m_window && QX11Info::connection()) {
101
xcb_destroy_window(QX11Info::connection(), m_window);
105
QString XRandRXCBHelper::rotationToString(Rotation rotation)
109
return "RR_Rotate_0";
111
return "RR_Rotate_90";
113
return "RR_Rotate_180";
115
return "RR_Rotate_270";
118
return QString("invalid value (%1)").arg(rotation);
121
QString XRandRXCBHelper::connectionToString(Connection connection)
123
switch (connection) {
125
return "RR_Connected";
126
case RR_Disconnected:
127
return "RR_Disconnected";
128
case RR_UnknownConnection:
129
return "RR_UnknownConnection";
132
return QString("invalid value (%1)").arg(connection);
135
bool XRandRXCBHelper::nativeEventFilter(const QByteArray& eventType, void* message, long int* result)
139
if (eventType != "xcb_generic_event_t") {
143
xcb_generic_event_t* e = static_cast<xcb_generic_event_t *>(message);
144
const uint8_t xEventType = e->response_type & ~0x80;
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);
150
if (xEventType == m_randrBase + XCB_RANDR_NOTIFY) {
151
handleXRandRNotify(e);
157
void XRandRXCBHelper::handleScreenChange(xcb_generic_event_t* e)
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;
169
Q_EMIT outputsChanged();
172
void XRandRXCBHelper::handleXRandRNotify(xcb_generic_event_t* e)
174
xcb_randr_notify_event_t*
175
randrEvent = reinterpret_cast<xcb_randr_notify_event_t*>(e);
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;
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;
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;
200
xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(QX11Info::connection(), xcb_get_atom_name(QX11Info::connection(), property.atom), NULL) ;
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;
211
bool XRandRXCBHelper::x11Event(XEvent *event)
214
if (m_versionMajor == 1 && m_versionMinor <= 1) {
215
if (event->xany.type == m_randrBase + RRScreenChangeNotify) {
217
XRRScreenChangeNotifyEvent* e2 = reinterpret_cast< XRRScreenChangeNotifyEvent* >(event);
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;
228
Q_EMIT outputsChanged();
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);
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;
245
Q_EMIT crtcChanged(e2->crtc);
247
} else if (e2->subtype == RRNotify_OutputChange) {
248
XRROutputChangeNotifyEvent* e2 = reinterpret_cast< XRROutputChangeNotifyEvent* >(event);
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;
257
Q_EMIT outputChanged(e2->output);
259
} else if (e2->subtype == RRNotify_OutputProperty) {
260
XRROutputPropertyNotifyEvent* e2 = reinterpret_cast< XRROutputPropertyNotifyEvent* >(event);
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;
274
#include "xrandrxcbhelper.moc"