2 * Copyright (c) 2008 Harry Bock <hbock@providence.edu>
3 * Copyright (c) 2007 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
4 * Copyright (c) 2002,2003 Hamish Rodda <rodda@kde.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <KConfigGroup>
24 #include <QApplication>
25 #include <QDesktopWidget>
28 #include "randrdisplay.h"
30 #include "randrscreen.h"
32 #include "legacyrandrscreen.h"
33 #include <config-randr.h>
35 RandRDisplay::RandRDisplay()
38 m_dpy
= QX11Info::display();
41 if(XRRQueryExtension(m_dpy
, &m_eventBase
, &m_errorBase
) == False
) {
46 int major_version
, minor_version
;
47 XRRQueryVersion(m_dpy
, &major_version
, &minor_version
);
49 m_version
= i18n("X Resize and Rotate extension version %1.%2",
50 major_version
,minor_version
);
52 // check if we have the new version of the XRandR extension
53 RandR::has_1_2
= (major_version
> 1 || (major_version
== 1 && minor_version
>= 2));
56 kDebug() << "Using XRANDR extension 1.2 or greater.";
57 else kDebug() << "Using legacy XRANDR extension (1.1 or earlier).";
59 kDebug() << "XRANDR error base: " << m_errorBase
;
60 m_numScreens
= ScreenCount(m_dpy
);
61 m_currentScreenIndex
= 0;
63 // set the timestamp to 0
66 // This assumption is WRONG with Xinerama
67 // Q_ASSERT(QApplication::desktop()->numScreens() == ScreenCount(QX11Info::display()));
69 for (int i
= 0; i
< m_numScreens
; i
++) {
72 m_screens
.append(new RandRScreen(i
));
75 m_legacyScreens
.append(new LegacyRandRScreen(i
));
79 //#ifdef HAS_RANDR_1_2
80 // check if we have more than one output, if no, revert to the legacy behavior
84 foreach(RandRScreen
*screen
, m_screens
)
85 count
+= screen
->outputs().count();
89 RandR::has_1_2
= false;
90 for (int i
= 0; i
< m_numScreens
; ++i
)
93 m_legacyScreens
.append(new LegacyRandRScreen(i
));
99 setCurrentScreen(DefaultScreen(QX11Info::display()));
102 RandRDisplay::~RandRDisplay()
104 qDeleteAll(m_legacyScreens
);
106 qDeleteAll(m_screens
);
110 bool RandRDisplay::isValid() const
115 const QString
& RandRDisplay::errorCode() const
120 int RandRDisplay::eventBase() const
125 int RandRDisplay::errorBase() const
130 const QString
& RandRDisplay::version() const
135 void RandRDisplay::setCurrentScreen(int index
)
137 Q_ASSERT(index
< ScreenCount(m_dpy
));
138 m_currentScreenIndex
= index
;
141 int RandRDisplay::screenIndexOfWidget(QWidget
* widget
)
143 //int ret = QApplication::desktop()->screenNumber(widget);
144 //return ret != -1 ? ret : QApplication::desktop()->primaryScreen();
146 // get info from Qt's X11 info directly; QDesktopWidget seems to use
147 // Xinerama by default, which doesn't work properly with randr.
148 // It will return more screens than exist for the display, causing
149 // a crash in the screen/currentScreen methods.
151 return widget
->x11Info().screen();
156 int RandRDisplay::currentScreenIndex() const
158 return m_currentScreenIndex
;
161 bool RandRDisplay::needsRefresh() const
163 Time time
, config_timestamp
;
164 time
= XRRTimes(m_dpy
, m_currentScreenIndex
, &config_timestamp
);
166 kDebug() << "Cache:" << RandR::timestamp
<< "Server:" << time
<< "Config:" << config_timestamp
;
167 return (RandR::timestamp
< time
);
170 void RandRDisplay::refresh()
173 if (RandR::has_1_2
) {
174 for (int i
= 0; i
< m_screens
.count(); ++i
) {
175 RandRScreen
* s
= m_screens
.at(i
);
182 for (int i
= 0; i
< m_legacyScreens
.size(); ++i
) {
183 LegacyRandRScreen
* s
= m_legacyScreens
.at(i
);
189 bool RandRDisplay::canHandle(const XEvent
*e
) const
191 if (e
->type
== m_eventBase
+ RRScreenChangeNotify
)
194 else if (e
->type
== m_eventBase
+ RRNotify
)
201 void RandRDisplay::handleEvent(XEvent
*e
)
203 if (e
->type
== m_eventBase
+ RRScreenChangeNotify
) {
205 if (RandR::has_1_2
) {
206 XRRScreenChangeNotifyEvent
*event
= (XRRScreenChangeNotifyEvent
*)(e
);
207 for (int i
=0; i
< m_screens
.count(); ++i
) {
208 RandRScreen
*screen
= m_screens
.at(i
);
209 if (screen
->rootWindow() == event
->root
)
210 screen
->handleEvent(event
);
221 else if (e
->type
== m_eventBase
+ RRNotify
) {
222 //forward the event to the right screen
223 XRRNotifyEvent
*event
= (XRRNotifyEvent
*)e
;
224 for (int i
=0; i
< m_screens
.count(); ++i
) {
225 RandRScreen
*screen
= m_screens
.at(i
);
226 if ( screen
->rootWindow() == event
->window
) {
227 screen
->handleRandREvent(event
);
234 int RandRDisplay::numScreens() const
236 Q_ASSERT(ScreenCount(QX11Info::display()) == m_numScreens
);
240 LegacyRandRScreen
* RandRDisplay::legacyScreen(int index
)
242 return m_legacyScreens
.at(index
);
245 LegacyRandRScreen
* RandRDisplay::currentLegacyScreen()
247 return m_legacyScreens
.at(m_currentScreenIndex
);
251 RandRScreen
* RandRDisplay::screen(int index
)
253 return m_screens
.at(index
);
256 RandRScreen
* RandRDisplay::currentScreen()
258 return m_screens
.at(m_currentScreenIndex
);
262 bool RandRDisplay::loadDisplay(KConfig
& config
, bool loadScreens
)
269 foreach(RandRScreen
*s
, m_screens
)
276 foreach(LegacyRandRScreen
* s
, m_legacyScreens
)
280 return applyOnStartup(config
);
283 bool RandRDisplay::applyOnStartup(KConfig
& config
)
285 return config
.group("Display").readEntry("ApplyOnStartup", false);
288 bool RandRDisplay::syncTrayApp(KConfig
& config
)
290 return config
.group("Display").readEntry("SyncTrayApp", false);
293 void RandRDisplay::saveDisplay(KConfig
& config
, bool applyOnStartup
, bool syncTrayApp
)
295 KConfigGroup group
= config
.group("Display");
296 group
.writeEntry("ApplyOnStartup", applyOnStartup
);
297 group
.writeEntry("SyncTrayApp", syncTrayApp
);
302 foreach(RandRScreen
*s
, m_screens
)
308 foreach(LegacyRandRScreen
*s
, m_legacyScreens
)
313 void RandRDisplay::applyProposed(bool confirm
)
318 foreach(RandRScreen
*s
, m_screens
)
319 s
->applyProposed(confirm
);
323 foreach(LegacyRandRScreen
*s
, m_legacyScreens
)
325 if (s
->proposedChanged()) {
327 s
->applyProposedAndConfirm();