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"
24 #include "xrandr12/randrscreen.h"
25 #include "xrandr12/randroutput.h"
27 #include <X11/Xatom.h>
32 XRandROutputs::XRandROutputs(QObject
* parent
, RandRDisplay
* display
)
33 : BackendOutputs(parent
)
39 QList
<Output
*> XRandROutputs::outputs() {
40 QList
<Output
*> result
;
41 foreach (XRandROutput
* output
, m_outputs
) {
42 result
.append(output
);
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() {
65 XRandROutput::XRandROutput(XRandROutputs
* parent
, RROutput rrId
)
66 : BackendOutput(parent
)
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() {
95 Atom atom
= XInternAtom (QX11Info::display(), "EDID_DATA", false);
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
);
120 qDebug() << "vendor code:" << m_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
;
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
) {
153 emit
outputConnected(this);
155 emit
outputActivated(this);
158 if (m_previousActivated
) {
160 emit
outputDeactivated(this);
163 emit
outputDisconnected(this);
167 if (! isConnected()) {
170 if (isActivated() != m_previousActivated
) {
173 emit
outputActivated(this);
175 emit
outputDeactivated(this);
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
;
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())))) {
218 output()->proposeRect(geom
);
220 rate
= output()->refreshRate();
223 QList
<float> rates
= output()->refreshRates(geom
.size());
224 foreach (float r
, rates
) {
225 if (qFuzzyCompare(rate
, r
)) {
231 if ((! found
) && (! rates
.empty())) {
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())) {
250 orientation
|= RandR::Rotate90
;
253 orientation
|= RandR::Rotate270
;
256 orientation
|= RandR::Rotate180
;
259 orientation
|= RandR::Rotate0
;
263 orientation
|= RandR::ReflectX
;
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();
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() {
317 int XRandROutput::productId() {
321 unsigned int XRandROutput::serialNumber() {
322 return m_serialNumber
;
325 RROutput
XRandROutput::_id() {
329 Rotation
XRandROutput::rotation() {
330 switch (output()->rotation() & RandR::RotateMask
) {
331 case RandR::Rotate90
:
333 case RandR::Rotate180
:
334 return RotateInverted
;
335 case RandR::Rotate270
:
342 bool XRandROutput::reflectX() {
343 if (output()->rotation() & RandR::ReflectX
) {
349 bool XRandROutput::reflectY() {
350 if (output()->rotation() & RandR::ReflectY
) {
356 float XRandROutput::rate() {
357 return output()->refreshRate();
360 QList
<float> XRandROutput::availableRates() {
361 return output()->refreshRates(size());