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));
54
RandR::has_1_3 = (major_version > 1 || (major_version == 1 && minor_version >= 3));
57
kDebug() << "Using XRANDR extension 1.3 or greater.";
58
else if(RandR::has_1_2)
59
kDebug() << "Using XRANDR extension 1.2.";
60
else kDebug() << "Using legacy XRANDR extension (1.1 or earlier).";
62
kDebug() << "XRANDR error base: " << m_errorBase;
63
m_numScreens = ScreenCount(m_dpy);
64
m_currentScreenIndex = 0;
66
// set the timestamp to 0
69
// This assumption is WRONG with Xinerama
70
// Q_ASSERT(QApplication::desktop()->numScreens() == ScreenCount(QX11Info::display()));
72
for (int i = 0; i < m_numScreens; i++) {
75
m_screens.append(new RandRScreen(i));
78
m_legacyScreens.append(new LegacyRandRScreen(i));
82
//#ifdef HAS_RANDR_1_2
83
// check if we have more than one output, if no, revert to the legacy behavior
87
foreach(RandRScreen *screen, m_screens)
88
count += screen->outputs().count();
92
RandR::has_1_2 = false;
93
for (int i = 0; i < m_numScreens; ++i)
96
m_legacyScreens.append(new LegacyRandRScreen(i));
102
setCurrentScreen(DefaultScreen(QX11Info::display()));
105
RandRDisplay::~RandRDisplay()
107
qDeleteAll(m_legacyScreens);
109
qDeleteAll(m_screens);
113
bool RandRDisplay::isValid() const
118
const QString& RandRDisplay::errorCode() const
123
int RandRDisplay::eventBase() const
128
int RandRDisplay::errorBase() const
133
const QString& RandRDisplay::version() const
138
void RandRDisplay::setCurrentScreen(int index)
140
Q_ASSERT(index < ScreenCount(m_dpy));
141
m_currentScreenIndex = index;
144
int RandRDisplay::screenIndexOfWidget(QWidget* widget)
146
//int ret = QApplication::desktop()->screenNumber(widget);
147
//return ret != -1 ? ret : QApplication::desktop()->primaryScreen();
149
// get info from Qt's X11 info directly; QDesktopWidget seems to use
150
// Xinerama by default, which doesn't work properly with randr.
151
// It will return more screens than exist for the display, causing
152
// a crash in the screen/currentScreen methods.
154
return widget->x11Info().screen();
159
int RandRDisplay::currentScreenIndex() const
161
return m_currentScreenIndex;
164
bool RandRDisplay::needsRefresh() const
166
Time time, config_timestamp;
167
time = XRRTimes(m_dpy, m_currentScreenIndex, &config_timestamp);
169
kDebug() << "Cache:" << RandR::timestamp << "Server:" << time << "Config:" << config_timestamp;
170
return (RandR::timestamp < time);
173
void RandRDisplay::refresh()
176
if (RandR::has_1_2) {
177
for (int i = 0; i < m_screens.count(); ++i) {
178
RandRScreen* s = m_screens.at(i);
185
for (int i = 0; i < m_legacyScreens.size(); ++i) {
186
LegacyRandRScreen* s = m_legacyScreens.at(i);
192
bool RandRDisplay::canHandle(const XEvent *e) const
194
if (e->type == m_eventBase + RRScreenChangeNotify)
197
else if (e->type == m_eventBase + RRNotify)
204
void RandRDisplay::handleEvent(XEvent *e)
206
if (e->type == m_eventBase + RRScreenChangeNotify) {
208
if (RandR::has_1_2) {
209
XRRScreenChangeNotifyEvent *event = (XRRScreenChangeNotifyEvent*)(e);
210
for (int i=0; i < m_screens.count(); ++i) {
211
RandRScreen *screen = m_screens.at(i);
212
if (screen->rootWindow() == event->root)
213
screen->handleEvent(event);
224
else if (e->type == m_eventBase + RRNotify) {
225
//forward the event to the right screen
226
XRRNotifyEvent *event = (XRRNotifyEvent*)e;
227
for (int i=0; i < m_screens.count(); ++i) {
228
RandRScreen *screen = m_screens.at(i);
229
if ( screen->rootWindow() == event->window ) {
230
screen->handleRandREvent(event);
237
int RandRDisplay::numScreens() const
239
Q_ASSERT(ScreenCount(QX11Info::display()) == m_numScreens);
243
LegacyRandRScreen* RandRDisplay::legacyScreen(int index)
245
return m_legacyScreens.at(index);
248
LegacyRandRScreen* RandRDisplay::currentLegacyScreen()
250
return m_legacyScreens.at(m_currentScreenIndex);
254
RandRScreen* RandRDisplay::screen(int index)
256
return m_screens.at(index);
259
RandRScreen* RandRDisplay::currentScreen()
261
return m_screens.at(m_currentScreenIndex);
265
bool RandRDisplay::loadDisplay(KConfig& config, bool loadScreens)
272
foreach(RandRScreen *s, m_screens)
279
foreach(LegacyRandRScreen* s, m_legacyScreens)
283
return applyOnStartup(config);
286
bool RandRDisplay::applyOnStartup(KConfig& config)
288
return config.group("Display").readEntry("ApplyOnStartup", false);
291
bool RandRDisplay::syncTrayApp(KConfig& config)
293
return config.group("Display").readEntry("SyncTrayApp", false);
296
void RandRDisplay::saveDisplay(KConfig& config, bool syncTrayApp)
298
KConfigGroup group = config.group("Display");
299
group.writeEntry("SyncTrayApp", syncTrayApp);
304
foreach(RandRScreen *s, m_screens)
310
foreach(LegacyRandRScreen *s, m_legacyScreens)
315
// to be used during desktop startup, make all screens provide the shell commands
316
// (using xrandr cli tool), save them here and a script will perform these commands
317
// early during desktop startup
318
void RandRDisplay::saveStartup(KConfig& config)
320
KConfigGroup group = config.group("Display");
321
group.writeEntry("ApplyOnStartup", true);
322
QStringList commands;
326
foreach(RandRScreen *s, m_screens)
327
commands += s->startupCommands();
332
foreach(LegacyRandRScreen *s, m_legacyScreens)
333
commands += s->startupCommands();
335
group.writeEntry( "StartupCommands", commands.join( "\n" ));
338
void RandRDisplay::disableStartup(KConfig& config)
340
KConfigGroup group = config.group("Display");
341
group.writeEntry("ApplyOnStartup", false);
342
group.deleteEntry( "StartupCommands" );
345
void RandRDisplay::applyProposed(bool confirm)
350
foreach(RandRScreen *s, m_screens)
351
s->applyProposed(confirm);
355
foreach(LegacyRandRScreen *s, m_legacyScreens)
357
if (s->proposedChanged()) {
359
s->applyProposedAndConfirm();
367
// vim:noet:sts=8:sw=8: