2 * Copyright (c) 2007 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
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 published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (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 General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "randrcrtc.h"
20 #include "randrscreen.h"
21 #include "randroutput.h"
22 #include "randrmode.h"
24 RandRCrtc::RandRCrtc(RandRScreen
*parent
, RRCrtc id
)
26 m_currentRect(0, 0, 0, 0),
27 m_originalRect(m_currentRect
),
28 m_proposedRect(m_originalRect
)
33 m_currentRotation
= m_originalRotation
= m_proposedRotation
= RandR::Rotate0
;
34 m_currentRate
= m_originalRate
= m_proposedRate
= 0;
36 m_rotations
= RandR::Rotate0
;
41 RandRCrtc::~RandRCrtc()
46 RRCrtc
RandRCrtc::id() const
51 int RandRCrtc::rotations() const
56 int RandRCrtc::rotation() const
58 return m_currentRotation
;
61 bool RandRCrtc::isValid(void) const
66 void RandRCrtc::loadSettings(bool notify
)
72 XRRCrtcInfo
*info
= XRRGetCrtcInfo(QX11Info::display(), m_screen
->resources(), m_id
);
75 if (RandR::timestamp
!= info
->timestamp
)
76 RandR::timestamp
= info
->timestamp
;
78 QRect rect
= QRect(info
->x
, info
->y
, info
->width
, info
->height
);
79 if (rect
!= m_currentRect
)
82 changes
|= RandR::ChangeRect
;
85 // get all connected outputs
86 // and create a list of modes that are available in all connected outputs
89 for (int i
= 0; i
< info
->noutput
; ++i
)
90 outputs
.append(info
->outputs
[i
]);
92 // check if the list changed from the original one
93 if (outputs
!= m_connectedOutputs
)
95 changes
|= RandR::ChangeOutputs
;
96 m_connectedOutputs
= outputs
;
99 // get all outputs this crtc can be connected to
101 for (int i
= 0; i
< info
->npossible
; ++i
)
102 outputs
.append(info
->possible
[i
]);
104 if (outputs
!= m_possibleOutputs
)
106 changes
|= RandR::ChangeOutputs
;
107 m_possibleOutputs
= outputs
;
109 //qDebug() << "loaded possible outputs:" << m_id << m_possibleOutputs;
112 m_rotations
= info
->rotations
;
113 if (m_currentRotation
!= info
->rotation
)
115 m_currentRotation
= info
->rotation
;
116 changes
|= RandR::ChangeRotation
;
119 // check if the current mode has changed
120 if (m_currentMode
!= info
->mode
)
122 m_currentMode
= info
->mode
;
123 changes
|= RandR::ChangeMode
;
126 RandRMode m
= m_screen
->mode(m_currentMode
);
127 if (m_currentRate
!= m
.refreshRate())
129 m_currentRate
= m
.refreshRate();
130 changes
|= RandR::ChangeRate
;
133 // just to make sure it gets initialized
134 m_proposedRect
= m_currentRect
;
135 m_proposedRotation
= m_currentRotation
;
136 m_proposedRate
= m_currentRate
;
139 XRRFreeCrtcInfo(info
);
141 if (changes
&& notify
)
142 emit
crtcChanged(m_id
, changes
);
145 void RandRCrtc::handleEvent(XRRCrtcChangeNotifyEvent
*event
)
147 qDebug() << "[CRTC" << m_id
<< "] Event...";
148 qDebug() << " mode: " << event
->mode
<< "(current " << m_currentMode
<< ")";
149 qDebug() << " pos: (" << event
->x
<< "," << event
->y
<< ")";
150 qDebug() << " size: " << event
->width
<< "x" << event
->height
;
151 qDebug() << " rotation: " << event
->rotation
;
155 if (event
->mode
!= m_currentMode
)
157 qDebug() << " Changed mode - old " << m_currentMode
<< " - new " << event
->mode
;
158 changed
|= RandR::ChangeMode
;
159 m_currentMode
= event
->mode
;
162 if (event
->rotation
!= m_currentRotation
)
164 qDebug() << " Changed rotation: " << event
->rotation
;
165 changed
|= RandR::ChangeRotation
;
166 m_currentRotation
= event
->rotation
;
168 if (event
->x
!= m_currentRect
.x() || event
->y
!= m_currentRect
.y())
170 qDebug() << " Changed position: " << event
->x
<< "," << event
->y
;
171 changed
|= RandR::ChangeRect
;
172 m_currentRect
.moveTopLeft(QPoint(event
->x
, event
->y
));
175 RandRMode mode
= m_screen
->mode(m_currentMode
);
176 QSize newSize
= mode
.size();
178 if (m_currentRotation
== RandR::Rotate90
|| m_currentRotation
== RandR::Rotate270
)
180 // in rotated modes leaving the screen on its "side" exchange width<->height
181 newSize
= QSize(newSize
.height(), newSize
.width());
184 if (newSize
!= m_currentRect
.size())
186 qDebug() << " Changed size: " << mode
.size();
187 changed
|= RandR::ChangeRect
;
188 m_currentRect
.setSize(mode
.size());
189 //Do NOT use event->width and event->height here, as it is being returned wrongly
193 emit
crtcChanged(m_id
, changed
);
196 RandRMode
RandRCrtc::mode() const
198 return m_screen
->mode(m_currentMode
);
201 QRect
RandRCrtc::rect() const
203 return m_currentRect
;
206 float RandRCrtc::refreshRate() const
208 return m_currentRate
;
211 bool RandRCrtc::applyProposed()
213 qDebug() << "[CRTC] Going to apply (" << m_id
<< ") ....";
214 qDebug() << " Current Screen rect: " << m_screen
->rect();
215 qDebug() << " Current CRTC Rect: " << m_currentRect
;
216 qDebug() << " Current Rotation: " << m_currentRotation
;
217 qDebug() << " Proposed rect: " << m_proposedRect
;
218 qDebug() << " Proposed rotation: " << m_proposedRotation
;
219 qDebug() << " Proposed refresh rate: " << m_proposedRate
;
220 qDebug() << " Outputs: ";
221 for (int i
= 0; i
< m_connectedOutputs
.count(); ++i
)
222 qDebug() << " - " << m_screen
->output(m_connectedOutputs
.at(i
))->name();
225 if (m_proposedRect
.size() == m_currentRect
.size() && m_proposedRate
== m_currentRate
)
227 mode
= m_screen
->mode(m_currentMode
);
231 // find a mode that has the desired size and is supported
232 // by all connected outputs
233 ModeList modeList
= modes();
236 foreach(const RRMode
& m
, modeList
)
238 RandRMode mode
= m_screen
->mode(m
);
239 if (mode
.size() == m_proposedRect
.size())
240 matchModes
.append(m
);
243 // if no matching modes were found, disable output
244 // else set the mode to the first mode in the list. If no refresh rate was given
245 // or no mode was found matching the given refresh rate, the first mode of the
247 if (!matchModes
.count())
250 mode
= m_screen
->mode(matchModes
.first());
252 foreach(const RRMode
& m
, matchModes
)
254 RandRMode testMode
= m_screen
->mode(m
);
255 if (testMode
.refreshRate() == m_proposedRate
)
263 // if no output was connected, set the mode to None
264 if (!m_connectedOutputs
.count())
266 else if (!mode
.isValid())
269 RROutput
*outputs
= new RROutput
[m_connectedOutputs
.count()];
270 for (int i
= 0; i
< m_connectedOutputs
.count(); ++i
)
271 outputs
[i
] = m_connectedOutputs
.at(i
);
275 int currentRotation
= m_currentRotation
& RandR::RotateMask
;
276 int proposedRotation
= m_proposedRotation
& RandR::RotateMask
;
277 if (currentRotation
== proposedRotation
||
278 (currentRotation
== RandR::Rotate0
&& proposedRotation
== RandR::Rotate180
) ||
279 (currentRotation
== RandR::Rotate180
&& proposedRotation
== RandR::Rotate0
) ||
280 (currentRotation
== RandR::Rotate90
&& proposedRotation
== RandR::Rotate270
) ||
281 (currentRotation
== RandR::Rotate270
&& proposedRotation
== RandR::Rotate90
))
283 QRect r
= QRect(0,0,0,0).united(m_proposedRect
);
284 if (r
.width() > m_screen
->maxSize().width() || r
.height() > m_screen
->maxSize().height())
287 // if the desired mode is bigger than the current screen size, first change the
288 // screen size, and then the crtc size
289 if (!m_screen
->rect().contains(r
))
291 // try to adjust the screen size
292 if (!m_screen
->adjustSize(r
))
300 QRect
r(m_proposedRect
.topLeft(), QSize(m_proposedRect
.height(), m_proposedRect
.width()));
301 if (!m_screen
->rect().contains(r
))
303 // check if the rotated rect is smaller than the max screen size
304 r
= m_screen
->rect().united(r
);
305 if (r
.width() > m_screen
->maxSize().width() || r
.height() > m_screen
->maxSize().height())
308 // adjust the screen size
309 r
= r
.united(m_currentRect
);
310 if (!m_screen
->adjustSize(r
))
317 qDebug() << "calling XRRSetCrtcConfig()";
318 Status s
= XRRSetCrtcConfig(QX11Info::display(), m_screen
->resources(), m_id
,
319 RandR::timestamp
, m_proposedRect
.x(), m_proposedRect
.y(), mode
.id(),
320 m_proposedRotation
, outputs
, m_connectedOutputs
.count());
325 if (s
== RRSetConfigSuccess
)
327 m_currentMode
= mode
.id();
328 m_currentRotation
= m_proposedRotation
;
329 m_currentRect
= m_proposedRect
;
330 m_currentRate
= mode
.refreshRate();
331 emit
crtcChanged(m_id
, RandR::ChangeMode
);
337 // Invalidate the XRRScreenResources cache
338 if(s
== RRSetConfigInvalidConfigTime
)
339 m_screen
->loadSettings(true);
342 m_screen
->adjustSize();
346 bool RandRCrtc::proposeSize(const QSize
&s
)
348 m_proposedRect
.setSize(s
);
353 bool RandRCrtc::proposePosition(const QPoint
&p
)
355 m_proposedRect
.moveTopLeft(p
);
359 bool RandRCrtc::proposeRotation(int rotation
)
361 // check if this crtc supports the asked rotation
362 if (!rotation
& m_rotations
)
365 m_proposedRotation
= rotation
;
370 bool RandRCrtc::proposeRefreshRate(float rate
)
372 m_proposedRate
= rate
;
376 void RandRCrtc::proposeOriginal()
378 m_proposedRotation
= m_originalRotation
;
379 m_proposedRect
= m_originalRect
;
380 m_proposedRate
= m_originalRate
;
383 void RandRCrtc::setOriginal()
385 m_originalRotation
= m_currentRotation
;
386 m_originalRect
= m_currentRect
;
387 m_originalRate
= m_currentRate
;
390 bool RandRCrtc::proposedChanged()
392 return (m_proposedRotation
!= m_currentRotation
||
393 m_proposedRect
!= m_currentRect
||
394 m_proposedRate
!= m_currentRate
);
397 bool RandRCrtc::addOutput(RROutput output
, const QSize
&s
)
400 // if no mode was given, use the current one
402 size
= m_currentRect
.size();
404 // check if this output is not already on this crtc
406 if (m_connectedOutputs
.indexOf(output
) == -1)
408 qDebug() << "possible:" << m_possibleOutputs
;
409 // the given output is not possible
410 if (m_possibleOutputs
.indexOf(output
) == -1)
413 m_connectedOutputs
.append(output
);
415 m_proposedRect
= QRect(m_proposedRect
.topLeft(), s
);
419 bool RandRCrtc::removeOutput(RROutput output
)
421 int index
= m_connectedOutputs
.indexOf(output
);
425 m_connectedOutputs
.removeAt(index
);
429 OutputList
RandRCrtc::connectedOutputs() const
431 return m_connectedOutputs
;
434 ModeList
RandRCrtc::modes() const
440 foreach(const RROutput
& o
, m_connectedOutputs
)
442 RandROutput
*output
= m_screen
->output(o
);
445 modeList
= output
->modes();
450 foreach(const RRMode
& m
, modeList
)
452 if (output
->modes().indexOf(m
) == -1)
453 modeList
.removeAll(m
);