1
/********************************************************************
3
Copyright (C) 2008 Lubos Lunak <l.lunak@suse.cz>
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*********************************************************************/
19
#include "randrmonitor.h"
22
#include <kactioncollection.h>
23
#include <kapplication.h>
26
#include <kmessagebox.h>
27
#include <kpluginfactory.h>
28
#include <kpluginloader.h>
29
#include <ktoolinvocation.h>
31
#include <qdbusconnection.h>
32
#include <qdbusconnectioninterface.h>
34
#include <qx11info_x11.h>
36
#include <randrdisplay.h>
37
#include <randrscreen.h>
38
#include <randroutput.h>
40
K_PLUGIN_FACTORY(RandrMonitorModuleFactory,
41
registerPlugin<RandrMonitorModule>();
43
K_EXPORT_PLUGIN(RandrMonitorModuleFactory("randrmonitor"))
45
RandrMonitorModule::RandrMonitorModule( QObject* parent, const QList<QVariant>& )
46
: KDEDModule( parent )
49
setModuleName( "randrmonitor" );
53
RandrMonitorModule::~RandrMonitorModule()
57
Display* dpy = QX11Info::display();
58
XDestroyWindow( dpy, window );
65
void RandrMonitorModule::initRandr()
67
Display* dpy = QX11Info::display();
68
if( !XRRQueryExtension( dpy, &randr_base, &randr_error ))
72
if( !XRRQueryVersion( dpy, &major, &minor ) || major < 1 || (major == 1 && minor < 2 ))
75
// It looks like we need a separate window for getting the events, so that we don't
76
// change e.g. Qt's event mask.
77
window = XCreateSimpleWindow( dpy, DefaultRootWindow( dpy ), 0, 0, 1, 1, 0, 0, 0 );
78
XRRSelectInput( dpy, window, RROutputChangeNotifyMask );
79
#if 0 // xrandr apparently can't detect hw changes and on some systems polling freezes X :(
81
QTimer* timer = new QTimer( this );
82
timer->start( 10000 ); // 10 s
83
connect( timer, SIGNAL( timeout()), this, SLOT( poll()));
85
helper = new RandrMonitorHelper( this );
86
kapp->installX11EventFilter( helper );
88
currentMonitors = connectedMonitors();
89
KActionCollection* coll = new KActionCollection( this );
90
KAction* act = coll->addAction( "display" );
91
act->setText( i18n( "Switch Display" ));
92
act->setGlobalShortcut( KShortcut( Qt::Key_Display ));
93
connect( act, SIGNAL( triggered( bool )), SLOT( switchDisplay()));
96
void RandrMonitorModule::poll()
98
// HACK: It seems that RRNotify/RRNotify_OutputChange event (i.e. detecting a newly
99
// plugged or unplugged monitor) does not work without polling some randr functionality.
101
XRRGetScreenSizeRange( QX11Info::display(), window, &dummy, &dummy, &dummy, &dummy );
104
void RandrMonitorModule::processX11Event( XEvent* e )
106
if( e->xany.type == randr_base + RRNotify )
108
XRRNotifyEvent* e2 = reinterpret_cast< XRRNotifyEvent* >( e );
109
if( e2->subtype == RRNotify_OutputChange ) // TODO && e2->window == window )
111
kDebug() << "Monitor change detected";
112
QStringList newMonitors = connectedMonitors();
113
if( newMonitors == currentMonitors )
115
if( QDBusConnection::sessionBus().interface()->isServiceRegistered(
116
"org.kde.internal.KSettingsWidget-kcm_display" ))
120
kapp->updateUserTimestamp(); // well, let's say plugging in a monitor is a user activity
121
#warning Modal dialog, stupid, fix.
124
( newMonitors.count() < currentMonitors.count()
125
? i18n( "A monitor output has been disconnected." )
126
: i18n( "A new monitor output has been connected." ))
127
+ "\n\n" + i18n( "Do you wish to run a configuration tool to adjust the monitor setup?" );
128
currentMonitors = newMonitors;
129
if( KMessageBox::questionYesNo( NULL, question, i18n( "Monitor setup has changed" ),
130
KGuiItem( i18n( "Con&figure" ) ), KGuiItem( i18n( "&Ignore" ) ), "randrmonitorchange" )
131
== KMessageBox::Yes )
133
KToolInvocation::kdeinitExec( "kcmshell4", QStringList() << "display" );
139
QStringList RandrMonitorModule::connectedMonitors() const
142
Display* dpy = QX11Info::display();
143
XRRScreenResources* resources = XRRGetScreenResources( dpy, window );
145
i < resources->noutput;
148
XRROutputInfo* info = XRRGetOutputInfo( dpy, resources, resources->outputs[ i ] );
149
QString name = QString::fromUtf8( info->name );
150
if( info->connection == RR_Connected )
152
XRRFreeOutputInfo( info );
154
XRRFreeScreenResources( resources );
158
void RandrMonitorModule::switchDisplay()
160
QList< RandROutput* > outputs;
161
RandRDisplay display;
163
scr < display.numScreens();
166
foreach( RandROutput* output, display.screen( scr )->outputs())
168
if( !output->isConnected())
170
if( !outputs.contains( output ))
171
outputs.append( output );
174
if( outputs.count() <= 1 ) // just one, do nothing
176
if( outputs.count() == 2 ) // alternative between one, second, both
178
if( outputs[ 0 ]->isActive() && !outputs[ 1 ]->isActive())
180
enableOutput( outputs[ 1 ], true );
181
enableOutput( outputs[ 0 ], false );
183
else if( !outputs[ 0 ]->isActive() && outputs[ 1 ]->isActive())
185
enableOutput( outputs[ 1 ], true );
186
enableOutput( outputs[ 0 ], true );
190
enableOutput( outputs[ 0 ], true );
191
enableOutput( outputs[ 1 ], false );
195
// no idea what to do here
196
KToolInvocation::kdeinitExec( "kcmshell4", QStringList() << "display" );
199
void RandrMonitorModule::enableOutput( RandROutput* output, bool enable )
200
{ // a bit lame, but I don't know how to do this easily with this codebase :-/
201
KProcess::execute( QStringList() << "xrandr" << "--output" << output->name() << ( enable ? "--auto" : "--off" ));
204
bool RandrMonitorHelper::x11Event( XEvent* e )
206
module->processX11Event( e );
207
return QWidget::x11Event( e );
210
#include "randrmonitor.moc"