not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / libs / kephal / outputs / xrandr / xrandroutputs.cpp
blob4cdfad17239ecd2bdbcd3e6df0ef96abae1a372a
1 /*
2 * Copyright 2008 Aike J Sommer <dev@aikesommer.name>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2,
7 * or (at your option) any later version.
9 * This program 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
12 * GNU General Public License for more details
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "xrandroutputs.h"
22 #include "edid.h"
24 #include "xrandr12/randrscreen.h"
25 #include "xrandr12/randroutput.h"
27 #include <X11/Xatom.h>
30 namespace Kephal {
32 XRandROutputs::XRandROutputs(QObject * parent, RandRDisplay * display)
33 : BackendOutputs(parent)
35 m_display = display;
36 init();
39 QList<Output *> XRandROutputs::outputs() {
40 QList<Output *> result;
41 foreach (XRandROutput * output, m_outputs) {
42 result.append(output);
44 return result;
47 void XRandROutputs::init() {
48 qDebug() << "XRandROutputs::init";
49 RandRScreen * screen = m_display->screen(0);
50 foreach (RandROutput * output, screen->outputs()) {
51 XRandROutput * o = new XRandROutput(this, output->id());
52 qDebug() << " added output " << output->id();
53 m_outputs.insert(o->id(), o);
57 RandROutput * XRandROutputs::output(RROutput rrId) {
58 return m_display->screen(0)->outputs()[rrId];
61 RandRDisplay * XRandROutputs::display() {
62 return m_display;
65 XRandROutput::XRandROutput(XRandROutputs * parent, RROutput rrId)
66 : BackendOutput(parent)
68 m_outputs = parent;
69 m_rrId = rrId;
71 parseEdid();
73 saveAsPrevious();
75 connect(this, SIGNAL(outputConnected(Kephal::Output *)), parent, SIGNAL(outputConnected(Kephal::Output *)));
76 connect(this, SIGNAL(outputDisconnected(Kephal::Output *)), parent, SIGNAL(outputDisconnected(Kephal::Output *)));
77 connect(this, SIGNAL(outputActivated(Kephal::Output *)), parent, SIGNAL(outputActivated(Kephal::Output *)));
78 connect(this, SIGNAL(outputDeactivated(Kephal::Output *)), parent, SIGNAL(outputDeactivated(Kephal::Output *)));
79 connect(this, SIGNAL(outputResized(Kephal::Output *, QSize, QSize)), parent, SIGNAL(outputResized(Kephal::Output *, QSize, QSize)));
80 connect(this, SIGNAL(outputMoved(Kephal::Output *, QPoint, QPoint)), parent, SIGNAL(outputMoved(Kephal::Output *, QPoint, QPoint)));
81 connect(this, SIGNAL(outputRateChanged(Kephal::Output *, float, float)), parent, SIGNAL(outputRateChanged(Kephal::Output *, float, float)));
82 connect(this, SIGNAL(outputRotated(Kephal::Output *, Kephal::Rotation, Kephal::Rotation)), parent, SIGNAL(outputRotated(Kephal::Output *, Kephal::Rotation, Kephal::Rotation)));
83 connect(this, SIGNAL(outputReflected(Kephal::Output *, bool, bool, bool, bool)), parent, SIGNAL(outputReflected(Kephal::Output *, bool, bool, bool, bool)));
85 connect(output(), SIGNAL(outputChanged(RROutput, int)), this, SLOT(outputChanged(RROutput, int)));
86 //connect(this, SLOT(_activate()), output(), SLOT(slotEnable()));
87 //connect(this, SLOT(_deactivate()), output(), SLOT(slotDisable()));
90 void XRandROutput::parseEdid() {
91 m_vendor = "";
92 m_productId = -1;
93 m_serialNumber = 0;
95 Atom atom = XInternAtom (QX11Info::display(), "EDID_DATA", false);
96 Atom type;
97 unsigned char * data;
98 unsigned long size;
99 unsigned long after;
100 int format;
102 XRRGetOutputProperty(QX11Info::display(), m_rrId, atom, 0, 100,
103 False, False, AnyPropertyType,
104 &type, &format, &size, &after, &data);
106 if (type == XA_INTEGER && format == 8 && EDID_TEST_HEADER(data)) {
107 qDebug() << "got a valid edid block...";
110 * parse the 3 letter vendor code
112 char * vendor = new char[4];
114 vendor[0] = EDID_VENDOR_1(data);
115 vendor[1] = EDID_VENDOR_2(data);
116 vendor[2] = EDID_VENDOR_3(data);
117 vendor[3] = 0x00;
118 m_vendor = vendor;
120 qDebug() << "vendor code:" << m_vendor;
122 delete[] vendor;
125 * parse the 16bit product id
127 m_productId = EDID_PRODUCT_ID(data);
129 qDebug() << "product id:" << m_productId;
132 * parse the 32bit serial number
134 m_serialNumber = EDID_SERIAL_NUMBER(data);
136 qDebug() << "serial number:" << m_serialNumber;
137 } else {
138 m_vendor = "";
139 m_productId = -1;
140 m_serialNumber = 0;
143 XFree(data);
146 void XRandROutput::outputChanged(RROutput id, int changes) {
147 Q_ASSERT(id == m_rrId);
148 qDebug() << "XRandROutput::outputChanged" << isConnected() << isActivated() << geom();
149 if (isConnected() != m_previousConnected) {
150 if (isConnected()) {
151 saveAsPrevious();
152 parseEdid();
153 emit outputConnected(this);
154 if (isActivated()) {
155 emit outputActivated(this);
157 } else {
158 if (m_previousActivated) {
159 saveAsPrevious();
160 emit outputDeactivated(this);
162 saveAsPrevious();
163 emit outputDisconnected(this);
165 return;
167 if (! isConnected()) {
168 return;
170 if (isActivated() != m_previousActivated) {
171 saveAsPrevious();
172 if (isActivated()) {
173 emit outputActivated(this);
174 } else {
175 emit outputDeactivated(this);
177 return;
180 QRect previousGeom = m_previousGeom;
181 Rotation previousRotation = m_previousRotation;
182 float previousRate = m_previousRate;
183 bool previousReflectX = m_previousReflectX;
184 bool previousReflectY = m_previousReflectY;
185 saveAsPrevious();
186 if (size() != previousGeom.size()) {
187 emit outputResized(this, previousGeom.size(), size());
189 if (position() != previousGeom.topLeft()) {
190 emit outputMoved(this, previousGeom.topLeft(), position());
192 if (rotation() != previousRotation) {
193 emit outputRotated(this, previousRotation, rotation());
195 if (rate() != previousRate) {
196 emit outputRateChanged(this, previousRate, rate());
198 if ((reflectX() != previousReflectX) || (reflectY() != previousReflectY)) {
199 emit outputReflected(this, previousReflectX, previousReflectY, reflectX(), reflectY());
203 void XRandROutput::saveAsPrevious() {
204 m_previousConnected = isConnected();
205 m_previousActivated = isActivated();
206 m_previousGeom = geom();
207 m_previousRotation = rotation();
208 m_previousRate = rate();
209 m_previousReflectX = reflectX();
210 m_previousReflectY = reflectY();
213 bool XRandROutput::applyGeom(const QRect & geom, float rate) {
214 if ((geom == this->geom()) && ((rate < 1) || (qFuzzyCompare(rate, this->rate())))) {
215 return true;
218 output()->proposeRect(geom);
219 if (rate < 1) {
220 rate = output()->refreshRate();
222 bool found = false;
223 QList<float> rates = output()->refreshRates(geom.size());
224 foreach (float r, rates) {
225 if (qFuzzyCompare(rate, r)) {
226 rate = r;
227 found = true;
228 break;
231 if ((! found) && (! rates.empty())) {
232 rate = rates[0];
234 if (rate > 1) {
235 output()->proposeRefreshRate(rate);
238 return output()->applyProposed();
241 bool XRandROutput::applyOrientation(Rotation rotation, bool reflectX, bool reflectY) {
242 if ((rotation == this->rotation()) && (reflectX == this->reflectX()) && (reflectY == this->reflectY())) {
243 return true;
246 int orientation = 0;
248 switch (rotation) {
249 case RotateRight:
250 orientation |= RandR::Rotate90;
251 break;
252 case RotateLeft:
253 orientation |= RandR::Rotate270;
254 break;
255 case RotateInverted:
256 orientation |= RandR::Rotate180;
257 break;
258 default:
259 orientation |= RandR::Rotate0;
262 if (reflectX) {
263 orientation |= RandR::ReflectX;
265 if (reflectY) {
266 orientation |= RandR::ReflectY;
269 output()->proposeRotation(orientation);
270 return output()->applyProposed();
273 void XRandROutput::deactivate() {
274 output()->slotDisable();
277 RandROutput * XRandROutput::output() {
278 return m_outputs->output(m_rrId);
281 QString XRandROutput::id() {
282 return output()->name();
285 QSize XRandROutput::size() {
286 return output()->rect().size();
289 QSize XRandROutput::preferredSize() {
290 if (! output()->preferredMode().size().isEmpty()) {
291 return output()->preferredMode().size();
293 return QSize(800, 600);
296 QList<QSize> XRandROutput::availableSizes() {
297 QList<QSize> sizes = output()->sizes();
298 return sizes;
301 QPoint XRandROutput::position() {
302 return output()->rect().topLeft();
305 bool XRandROutput::isConnected() {
306 return output()->isConnected();
309 bool XRandROutput::isActivated() {
310 return output()->isActive();
313 QString XRandROutput::vendor() {
314 return m_vendor;
317 int XRandROutput::productId() {
318 return m_productId;
321 unsigned int XRandROutput::serialNumber() {
322 return m_serialNumber;
325 RROutput XRandROutput::_id() {
326 return m_rrId;
329 Rotation XRandROutput::rotation() {
330 switch (output()->rotation() & RandR::RotateMask) {
331 case RandR::Rotate90:
332 return RotateRight;
333 case RandR::Rotate180:
334 return RotateInverted;
335 case RandR::Rotate270:
336 return RotateLeft;
337 default:
338 return RotateNormal;
342 bool XRandROutput::reflectX() {
343 if (output()->rotation() & RandR::ReflectX) {
344 return true;
346 return false;
349 bool XRandROutput::reflectY() {
350 if (output()->rotation() & RandR::ReflectY) {
351 return true;
353 return false;
356 float XRandROutput::rate() {
357 return output()->refreshRate();
360 QList<float> XRandROutput::availableRates() {
361 return output()->refreshRates(size());