~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kcontrol/randr/module/randrmonitor.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/********************************************************************
 
2
 
 
3
Copyright (C) 2008 Lubos Lunak <l.lunak@suse.cz>
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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
*********************************************************************/
 
18
 
 
19
#include "randrmonitor.h"
 
20
 
 
21
#include <kaction.h>
 
22
#include <kactioncollection.h>
 
23
#include <kapplication.h>
 
24
#include <kdebug.h>
 
25
#include <klocale.h>
 
26
#include <kmessagebox.h>
 
27
#include <kpluginfactory.h>
 
28
#include <kpluginloader.h>
 
29
#include <ktoolinvocation.h>
 
30
 
 
31
#include <qdbusconnection.h>
 
32
#include <qdbusconnectioninterface.h>
 
33
#include <qtimer.h>
 
34
#include <qx11info_x11.h>
 
35
 
 
36
#include <randrdisplay.h>
 
37
#include <randrscreen.h>
 
38
#include <randroutput.h>
 
39
 
 
40
K_PLUGIN_FACTORY(RandrMonitorModuleFactory,
 
41
                 registerPlugin<RandrMonitorModule>();
 
42
    )
 
43
K_EXPORT_PLUGIN(RandrMonitorModuleFactory("randrmonitor"))
 
44
 
 
45
RandrMonitorModule::RandrMonitorModule( QObject* parent, const QList<QVariant>& )
 
46
    : KDEDModule( parent )
 
47
    , have_randr( false )
 
48
    {
 
49
    setModuleName( "randrmonitor" );
 
50
    initRandr();
 
51
    }
 
52
 
 
53
RandrMonitorModule::~RandrMonitorModule()
 
54
    {
 
55
    if( have_randr )
 
56
        {
 
57
        Display* dpy = QX11Info::display();
 
58
        XDestroyWindow( dpy, window );
 
59
        delete helper;
 
60
        delete dialog;
 
61
        have_randr = false;
 
62
        }
 
63
    }
 
64
 
 
65
void RandrMonitorModule::initRandr()
 
66
    {
 
67
    Display* dpy = QX11Info::display();
 
68
    if( !XRRQueryExtension( dpy, &randr_base, &randr_error ))
 
69
        return;
 
70
    int major = 1;
 
71
    int minor = 2;
 
72
    if( !XRRQueryVersion( dpy, &major, &minor ) || major < 1 || (major == 1 && minor < 2 ))
 
73
        return;
 
74
    have_randr = true;
 
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 :(
 
80
    // HACK: see poll()
 
81
    QTimer* timer = new QTimer( this );
 
82
    timer->start( 10000 ); // 10 s
 
83
    connect( timer, SIGNAL( timeout()), this, SLOT( poll()));
 
84
#endif
 
85
    helper = new RandrMonitorHelper( this );
 
86
    kapp->installX11EventFilter( helper );
 
87
    dialog = NULL;
 
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()));
 
94
    }
 
95
 
 
96
void RandrMonitorModule::poll()
 
97
    {
 
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.
 
100
    int dummy;
 
101
    XRRGetScreenSizeRange( QX11Info::display(), window, &dummy, &dummy, &dummy, &dummy );
 
102
    }
 
103
 
 
104
void RandrMonitorModule::processX11Event( XEvent* e )
 
105
    {
 
106
    if( e->xany.type == randr_base + RRNotify )
 
107
        {
 
108
        XRRNotifyEvent* e2 = reinterpret_cast< XRRNotifyEvent* >( e );
 
109
        if( e2->subtype == RRNotify_OutputChange ) // TODO && e2->window == window )
 
110
            {
 
111
            kDebug() << "Monitor change detected";
 
112
            QStringList newMonitors = connectedMonitors();
 
113
            if( newMonitors == currentMonitors )
 
114
                return;
 
115
            if( QDBusConnection::sessionBus().interface()->isServiceRegistered(
 
116
                "org.kde.internal.KSettingsWidget-kcm_display" ))
 
117
                { // already running
 
118
                return;
 
119
                }
 
120
            kapp->updateUserTimestamp(); // well, let's say plugging in a monitor is a user activity
 
121
#warning Modal dialog, stupid, fix.
 
122
            QString change;
 
123
            QString question =
 
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 )
 
132
                {
 
133
                KToolInvocation::kdeinitExec( "kcmshell4", QStringList() << "display" );
 
134
                }
 
135
            }
 
136
        }
 
137
    }
 
138
 
 
139
QStringList RandrMonitorModule::connectedMonitors() const
 
140
    {
 
141
    QStringList ret;
 
142
    Display* dpy = QX11Info::display();
 
143
    XRRScreenResources* resources = XRRGetScreenResources( dpy, window );
 
144
    for( int i = 0;
 
145
         i < resources->noutput;
 
146
         ++i )
 
147
        {
 
148
        XRROutputInfo* info = XRRGetOutputInfo( dpy, resources, resources->outputs[ i ] );
 
149
        QString name = QString::fromUtf8( info->name );
 
150
        if( info->connection == RR_Connected )
 
151
            ret.append( name );
 
152
        XRRFreeOutputInfo( info );
 
153
        }
 
154
    XRRFreeScreenResources( resources );
 
155
    return ret;
 
156
    }
 
157
 
 
158
void RandrMonitorModule::switchDisplay()
 
159
    {
 
160
    QList< RandROutput* > outputs;
 
161
    RandRDisplay display;
 
162
    for( int scr = 0;
 
163
         scr < display.numScreens();
 
164
         ++scr )
 
165
        {
 
166
        foreach( RandROutput* output, display.screen( scr )->outputs())
 
167
            {
 
168
            if( !output->isConnected())
 
169
                continue;
 
170
            if( !outputs.contains( output ))
 
171
                outputs.append( output );
 
172
            }
 
173
        }
 
174
    if( outputs.count() <= 1 ) // just one, do nothing
 
175
        return;
 
176
    if( outputs.count() == 2 ) // alternative between one, second, both
 
177
        {
 
178
        if( outputs[ 0 ]->isActive() && !outputs[ 1 ]->isActive())
 
179
            {
 
180
            enableOutput( outputs[ 1 ], true );
 
181
            enableOutput( outputs[ 0 ], false );
 
182
            }
 
183
        else if( !outputs[ 0 ]->isActive() && outputs[ 1 ]->isActive())
 
184
            {
 
185
            enableOutput( outputs[ 1 ], true );
 
186
            enableOutput( outputs[ 0 ], true );
 
187
            }
 
188
        else
 
189
            {
 
190
            enableOutput( outputs[ 0 ], true );
 
191
            enableOutput( outputs[ 1 ], false );
 
192
            }
 
193
        return;
 
194
        }
 
195
    // no idea what to do here
 
196
    KToolInvocation::kdeinitExec( "kcmshell4", QStringList() << "display" );
 
197
    }
 
198
 
 
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" ));
 
202
    }
 
203
 
 
204
bool RandrMonitorHelper::x11Event( XEvent* e )
 
205
    {
 
206
    module->processX11Event( e );
 
207
    return QWidget::x11Event( e );
 
208
    }
 
209
 
 
210
#include "randrmonitor.moc"