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
)
71 kDebug() << "Querying information about CRTC" << m_id
;
74 XRRCrtcInfo
*info
= XRRGetCrtcInfo(QX11Info::display(), m_screen
->resources(), m_id
);
77 if (RandR::timestamp
!= info
->timestamp
)
78 RandR::timestamp
= info
->timestamp
;
80 QRect rect
= QRect(info
->x
, info
->y
, info
->width
, info
->height
);
81 if (rect
!= m_currentRect
)
84 changes
|= RandR::ChangeRect
;
87 // get all connected outputs
88 // and create a list of modes that are available in all connected outputs
91 for (int i
= 0; i
< info
->noutput
; ++i
) {
92 outputs
.append(info
->outputs
[i
]);
95 // check if the list changed from the original one
96 if (outputs
!= m_connectedOutputs
)
98 changes
|= RandR::ChangeOutputs
;
99 m_connectedOutputs
= outputs
;
102 // get all outputs this crtc can be connected to
104 for (int i
= 0; i
< info
->npossible
; ++i
)
105 outputs
.append(info
->possible
[i
]);
107 if (outputs
!= m_possibleOutputs
)
109 changes
|= RandR::ChangeOutputs
;
110 m_possibleOutputs
= outputs
;
114 m_rotations
= info
->rotations
;
115 if (m_currentRotation
!= info
->rotation
)
117 m_currentRotation
= info
->rotation
;
118 changes
|= RandR::ChangeRotation
;
121 // check if the current mode has changed
122 if (m_currentMode
!= info
->mode
)
124 m_currentMode
= info
->mode
;
125 changes
|= RandR::ChangeMode
;
128 RandRMode m
= m_screen
->mode(m_currentMode
);
129 if (m_currentRate
!= m
.refreshRate())
131 m_currentRate
= m
.refreshRate();
132 changes
|= RandR::ChangeRate
;
135 // just to make sure it gets initialized
136 m_proposedRect
= m_currentRect
;
137 m_proposedRotation
= m_currentRotation
;
138 m_proposedRate
= m_currentRate
;
141 XRRFreeCrtcInfo(info
);
143 if (changes
&& notify
)
144 emit
crtcChanged(m_id
, changes
);
147 void RandRCrtc::handleEvent(XRRCrtcChangeNotifyEvent
*event
)
149 kDebug() << "[CRTC] Event...";
152 if (event
->mode
!= m_currentMode
)
154 kDebug() << " Changed mode";
155 changed
|= RandR::ChangeMode
;
156 m_currentMode
= event
->mode
;
159 if (event
->rotation
!= m_currentRotation
)
161 kDebug() << " Changed rotation: " << event
->rotation
;
162 changed
|= RandR::ChangeRotation
;
163 m_currentRotation
= event
->rotation
;
165 if (event
->x
!= m_currentRect
.x() || event
->y
!= m_currentRect
.y())
167 kDebug() << " Changed position: " << event
->x
<< "," << event
->y
;
168 changed
|= RandR::ChangeRect
;
169 m_currentRect
.moveTopLeft(QPoint(event
->x
, event
->y
));
172 RandRMode mode
= m_screen
->mode(m_currentMode
);
173 if (mode
.size() != m_currentRect
.size())
175 kDebug() << " Changed size: " << mode
.size();
176 changed
|= RandR::ChangeRect
;
177 m_currentRect
.setSize(mode
.size());
178 //Do NOT use event->width and event->height here, as it is being returned wrongly
182 emit
crtcChanged(m_id
, changed
);
185 RandRMode
RandRCrtc::mode() const
187 return m_screen
->mode(m_currentMode
);
190 QRect
RandRCrtc::rect() const
192 return m_currentRect
;
195 float RandRCrtc::refreshRate() const
197 return m_currentRate
;
200 bool RandRCrtc::applyProposed()
202 kDebug() << "Applying proposed changes for CRTC" << m_id
<< "...";
203 kDebug() << " Current Screen rect:" << m_screen
->rect();
204 kDebug() << " Current CRTC rect:" << m_currentRect
;
205 kDebug() << " Current rotation:" << m_currentRotation
;
206 kDebug() << " Proposed CRTC rect:" << m_proposedRect
;
207 kDebug() << " Proposed rotation:" << m_proposedRotation
;
208 kDebug() << " Proposed refresh rate:" << m_proposedRate
;
209 kDebug() << " Enabled outputs:";
210 if (m_connectedOutputs
.isEmpty())
211 kDebug() << " - none";
212 for (int i
= 0; i
< m_connectedOutputs
.count(); ++i
)
213 kDebug() << " -" << m_screen
->output(m_connectedOutputs
.at(i
))->name();
216 if (m_proposedRect
.size() == m_currentRect
.size() && m_proposedRate
== m_currentRate
)
218 mode
= m_screen
->mode(m_currentMode
);
222 // find a mode that has the desired size and is supported
223 // by all connected outputs
224 ModeList modeList
= modes();
227 foreach(RRMode m
, modeList
)
229 RandRMode mode
= m_screen
->mode(m
);
230 if (mode
.size() == m_proposedRect
.size())
231 matchModes
.append(m
);
234 // if no matching modes were found, disable output
235 // else set the mode to the first mode in the list. If no refresh rate was given
236 // or no mode was found matching the given refresh rate, the first mode of the
238 if (!matchModes
.count())
241 mode
= m_screen
->mode(matchModes
.first());
243 foreach(RRMode m
, matchModes
)
245 RandRMode testMode
= m_screen
->mode(m
);
246 if (testMode
.refreshRate() == m_proposedRate
)
254 // if no output was connected, set the mode to None
255 if (!m_connectedOutputs
.count())
257 else if (!mode
.isValid())
262 if (m_currentRotation
== m_proposedRotation
||
263 (m_currentRotation
== RandR::Rotate0
&& m_proposedRotation
== RandR::Rotate180
) ||
264 (m_currentRotation
== RandR::Rotate180
&& m_proposedRotation
== RandR::Rotate0
) ||
265 (m_currentRotation
== RandR::Rotate90
&& m_proposedRotation
== RandR::Rotate270
) ||
266 (m_currentRotation
== RandR::Rotate270
&& m_proposedRotation
== RandR::Rotate90
))
268 QRect r
= QRect(0,0,0,0).united(m_proposedRect
);
269 if (r
.width() > m_screen
->maxSize().width() || r
.height() > m_screen
->maxSize().height())
272 // if the desired mode is bigger than the current screen size, first change the
273 // screen size, and then the crtc size
274 if (!m_screen
->rect().contains(r
))
276 // try to adjust the screen size
277 if (!m_screen
->adjustSize(r
))
285 QRect
r(m_proposedRect
.topLeft(), QSize(m_proposedRect
.height(), m_proposedRect
.width()));
286 if (!m_screen
->rect().contains(r
))
288 // check if the rotated rect is smaller than the max screen size
289 r
= m_screen
->rect().united(r
);
290 if (r
.width() > m_screen
->maxSize().width() || r
.height() > m_screen
->maxSize().height())
293 // adjust the screen size
294 r
= r
.united(m_currentRect
);
295 if (!m_screen
->adjustSize(r
))
301 RROutput
*outputs
= new RROutput
[m_connectedOutputs
.count()];
302 for (int i
= 0; i
< m_connectedOutputs
.count(); ++i
)
303 outputs
[i
] = m_connectedOutputs
.at(i
);
305 Status s
= XRRSetCrtcConfig(QX11Info::display(), m_screen
->resources(), m_id
,
306 RandR::timestamp
, m_proposedRect
.x(), m_proposedRect
.y(), mode
.id(),
307 m_proposedRotation
, outputs
, m_connectedOutputs
.count());
312 if (s
== RRSetConfigSuccess
)
314 kDebug() << "Changes for CRTC" << m_id
<< "successfully applied.";
315 m_currentMode
= mode
.id();
316 m_currentRotation
= m_proposedRotation
;
317 m_currentRect
= m_proposedRect
;
318 m_currentRate
= mode
.refreshRate();
319 emit
crtcChanged(m_id
, RandR::ChangeMode
);
324 kDebug() << "Failed to apply changes for CRTC" << m_id
;
326 // Invalidate the XRRScreenResources cache
327 if(s
== RRSetConfigInvalidConfigTime
)
328 m_screen
->loadSettings(true);
331 m_screen
->adjustSize();
335 bool RandRCrtc::proposeSize(const QSize
&s
)
337 m_proposedRect
.setSize(s
);
342 bool RandRCrtc::proposePosition(const QPoint
&p
)
344 m_proposedRect
.moveTopLeft(p
);
348 bool RandRCrtc::proposeRotation(int rotation
)
350 // check if this crtc supports the asked rotation
351 if (!rotation
& m_rotations
)
354 m_proposedRotation
= rotation
;
359 bool RandRCrtc::proposeRefreshRate(float rate
)
361 m_proposedRate
= rate
;
365 void RandRCrtc::proposeOriginal()
367 m_proposedRotation
= m_originalRotation
;
368 m_proposedRect
= m_originalRect
;
369 m_proposedRate
= m_originalRate
;
372 void RandRCrtc::setOriginal()
374 m_originalRotation
= m_currentRotation
;
375 m_originalRect
= m_currentRect
;
376 m_originalRate
= m_currentRate
;
379 bool RandRCrtc::proposedChanged()
381 return (m_proposedRotation
!= m_currentRotation
||
382 m_proposedRect
!= m_currentRect
||
383 m_proposedRate
!= m_currentRate
);
386 bool RandRCrtc::addOutput(RROutput output
, const QSize
&s
)
389 // if no mode was given, use the current one
391 size
= m_currentRect
.size();
393 // check if this output is not already on this crtc
395 if (m_connectedOutputs
.indexOf(output
) == -1)
397 // the given output is not possible
398 if (m_possibleOutputs
.indexOf(output
) == -1)
401 m_connectedOutputs
.append(output
);
403 m_proposedRect
= QRect(m_proposedRect
.topLeft(), s
);
407 bool RandRCrtc::removeOutput(RROutput output
)
409 int index
= m_connectedOutputs
.indexOf(output
);
413 m_connectedOutputs
.removeAt(index
);
417 OutputList
RandRCrtc::connectedOutputs() const
419 return m_connectedOutputs
;
422 ModeList
RandRCrtc::modes() const
428 foreach(RROutput o
, m_connectedOutputs
)
430 RandROutput
*output
= m_screen
->output(o
);
433 modeList
= output
->modes();
438 foreach(RRMode m
, modeList
)
440 if (output
->modes().indexOf(m
) == -1)
441 modeList
.removeAll(m
);
449 #include "randrcrtc.moc"