Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Evergreen:11.1
kdebase4-workspace
randr12.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File randr12.diff of Package kdebase4-workspace
Index: outputgraphicsitem.cpp =================================================================== --- kcontrol/randr/outputgraphicsitem.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/outputgraphicsitem.cpp (.../work/~seli/randr) (revision 895733) @@ -17,7 +17,7 @@ */ #include "outputgraphicsitem.h" -#include "randroutput.h" +#include "outputconfig.h" #include "randr.h" #include <QPen> @@ -26,39 +26,24 @@ #include <QGraphicsScene> #include <KGlobalSettings> -OutputGraphicsItem::OutputGraphicsItem(RandROutput *output) - : QGraphicsRectItem(output->rect()) +OutputGraphicsItem::OutputGraphicsItem(OutputConfig *config) + : QGraphicsRectItem(config->rect()) + , m_config( config ) { m_left = m_right = m_top = m_bottom = NULL; setPen(QPen(Qt::black)); - if(output->isActive()) - setBrush(QColor(0, 255, 0, 128)); - else setBrush(QColor(128, 128, 128, 0)); setFlag(QGraphicsItem::ItemIsMovable, false); - setFlag(QGraphicsItem::ItemIsSelectable, true); +// FIXME not implemented yet setFlag(QGraphicsItem::ItemIsSelectable, true); - // An example of this description text with radeonhd on randr 1.2: - // DVI-I_2/digital - // 1680x1050 (60.0 Hz) - int w = output->rect().width(), h = output->rect().height(); - QString refresh = QString::number(output->refreshRate(), 'f', 1); - QString desc = output->name() + '\n' + - QString("%1x%2 (%3 Hz)").arg(w).arg(h).arg(refresh); - - m_text = new QGraphicsTextItem(desc, this); + m_text = new QGraphicsTextItem(QString(), this); QFont font = KGlobalSettings::generalFont(); font.setPixelSize(72); m_text->setFont(font); - - QRectF textRect = m_text->boundingRect(); - QRect outRect = output->rect(); - - // more accurate text centering - m_text->setPos((outRect.width() - textRect.width()) / 2, - (outRect.height() - textRect.height()) / 2); + setVisible( false ); + m_text->setVisible( false ); } OutputGraphicsItem::~OutputGraphicsItem() @@ -66,6 +51,30 @@ disconnect(); } +void OutputGraphicsItem::configUpdated() +{ + if( !m_config->isActive()) { + setVisible( false ); + m_text->setVisible( false ); + return; + } + setVisible( true ); + m_text->setVisible( true ); + setRect( m_config->rect()); + setBrush(QColor(0, 255, 0, 128)); + // An example of this description text with radeonhd on randr 1.2: + // DVI-I_2/digital + // 1680x1050 (60.0 Hz) + QString refresh = QString::number(m_config->refreshRate(), 'f', 1); + QString desc = m_config->output()->name() + '\n' + + QString("%1x%2 (%3 Hz)").arg(rect().width()).arg(rect().height()).arg(refresh); + m_text->setPlainText( desc ); + // more accurate text centering + QRectF textRect = m_text->boundingRect(); + m_text->setPos( rect().x() + (rect().width() - textRect.width()) / 2, + rect().y() + (rect().height() - textRect.height()) / 2); +} + OutputGraphicsItem *OutputGraphicsItem::left() const { return m_left; Index: randrconfig.h =================================================================== --- kcontrol/randr/randrconfig.h (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/randrconfig.h (.../work/~seli/randr) (revision 895733) @@ -22,8 +22,10 @@ #include "ui_randrconfigbase.h" #include "randr.h" +#include "outputconfig.h" #include <QWidget> +#include <QTimer> class QGraphicsScene; class SettingsContainer; @@ -50,10 +52,13 @@ public slots: void slotUpdateView(); + void slotDelayedUpdateView(); protected slots: void slotChanged(void); void slotAdjustOutput(OutputGraphicsItem *o); + void identifyOutputs(); + void clearIndicators(); signals: void changed(bool change); @@ -62,6 +67,7 @@ virtual void resizeEvent(QResizeEvent *event); private: + void insufficientVirtualSize(); RandRDisplay *m_display; bool m_changed; bool m_firstLoad; @@ -70,6 +76,10 @@ QList<CollapsibleWidget*> m_outputList; QGraphicsScene *m_scene; LayoutManager *m_layoutManager; + QList<QWidget*> m_indicators; + QTimer identifyTimer; + OutputConfigList m_configs; + QTimer compressUpdateViewTimer; }; Index: layoutmanager.cpp =================================================================== --- kcontrol/randr/layoutmanager.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/layoutmanager.cpp (.../work/~seli/randr) (revision 895733) @@ -148,3 +148,13 @@ } } + +GraphicsView::GraphicsView( QWidget* parent ) + : QGraphicsView( parent ) + { + } + +QSize GraphicsView::sizeHint() const + { + return QSize( 200, 200 ); + } Index: randr.h =================================================================== --- kcontrol/randr/randr.h (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/randr.h (.../work/~seli/randr) (revision 895733) @@ -39,6 +39,8 @@ #include <X11/extensions/Xrandr.h> } +#include <fixx11h.h> + #ifdef HAS_RANDR_1_2 class RandRScreen; class RandRCrtc; Index: krandrtray.cpp =================================================================== --- kcontrol/randr/krandrtray.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/krandrtray.cpp (.../work/~seli/randr) (revision 895733) @@ -468,4 +468,5 @@ kcm->setPlainCaption( i18n( "Configure Display" ) ); kcm->addModule( "display" ); kcm->exec(); + delete kcm; } Index: randrconfigbase.ui =================================================================== --- kcontrol/randr/randrconfigbase.ui (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/randrconfigbase.ui (.../work/~seli/randr) (revision 895733) @@ -12,28 +12,46 @@ <property name="windowTitle" > <string>Display Configuration (X11 Resize, Rotate and Reflect)</string> </property> - <layout class="QHBoxLayout" > + <layout class="QHBoxLayout" name="horizontalLayout" > <item> - <widget class="QWidget" native="1" name="outputList" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Expanding" hsizetype="MinimumExpanding" > - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize" > - <size> - <width>150</width> - <height>0</height> - </size> - </property> - </widget> + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="QWidget" native="1" name="outputList" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Expanding" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize" > + <size> + <width>150</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="identifyOutputsButton" > + <property name="text" > + <string>Identify Outputs</string> + </property> + </widget> + </item> + </layout> </item> <item> - <widget class="QGraphicsView" name="screenView" /> + <widget class="GraphicsView" name="screenView" /> </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>GraphicsView</class> + <extends>QGraphicsView</extends> + <header>layoutmanager.h</header> + </customwidget> + </customwidgets> <resources/> <connections/> </ui> Index: outputconfig.cpp =================================================================== --- kcontrol/randr/outputconfig.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/outputconfig.cpp (.../work/~seli/randr) (revision 895733) @@ -24,15 +24,13 @@ #include "randrmode.h" #include <kdebug.h> -OutputConfig::OutputConfig(QWidget *parent, RandROutput *output, OutputGraphicsItem *item) +OutputConfig::OutputConfig(QWidget *parent, RandROutput *output, OutputConfigList preceding) : QWidget(parent) + , precedingOutputConfigs( preceding ) { m_output = output; Q_ASSERT(output); - m_item = item; - Q_ASSERT(item); - setupUi(this); // connect signals @@ -40,6 +38,10 @@ this, SLOT(positionComboChanged(int))); connect(sizeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRateList(int))); + connect(sizeCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(updatePositionList())); + connect(sizeCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(updateRotationList())); connect(m_output, SIGNAL(outputChanged(RROutput, int)), this, SLOT(outputChanged(RROutput, int))); @@ -48,7 +50,19 @@ connect(orientationCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty())); connect(positionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty())); connect(positionOutputCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty())); - + connect(sizeCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateView())); + connect(orientationCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateView())); + connect(positionCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateView())); + connect(positionOutputCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateView())); + connect(absolutePosX, SIGNAL(textChanged(const QString&)), this, SIGNAL(updateView())); + connect(absolutePosY, SIGNAL(textChanged(const QString&)), this, SIGNAL(updateView())); + // make sure to update option for relative position when other outputs get enabled/disabled + foreach( OutputConfig* config, precedingOutputConfigs ) + connect( config, SIGNAL( updateView()), this, SLOT( updatePositionList())); + + updatePositionListTimer.setSingleShot( true ); + connect( &updatePositionListTimer, SIGNAL( timeout()), SLOT( updatePositionListDelayed())); + load(); } @@ -63,20 +77,56 @@ QPoint OutputConfig::position(void) const { + if( !isActive()) + return QPoint(); int index = positionCombo->currentIndex(); if((Relation)positionCombo->itemData(index).toInt() == Absolute) return QPoint(absolutePosX->text().toInt(), absolutePosY->text().toInt()); + foreach(OutputConfig *config, precedingOutputConfigs) { + if( config->output()->id() + == positionOutputCombo->itemData( positionOutputCombo->currentIndex()).toUInt()) { + QPoint pos = config->position(); + switch( (Relation)positionCombo->itemData(index).toInt()) { + case LeftOf: + return QPoint( pos.x() - resolution().width(), pos.y()); + case RightOf: + return QPoint( pos.x() + config->resolution().width(), pos.y()); + case Over: + return QPoint( pos.x(), pos.y() - resolution().height()); + case Under: + return QPoint( pos.x(), pos.y() + config->resolution().height()); + case SameAs: + return pos; + default: + abort(); + } + } + } return QPoint(0, 0); } QSize OutputConfig::resolution(void) const { + if( sizeCombo->count() == 0 ) + return QSize(); return sizeCombo->itemData(sizeCombo->currentIndex()).toSize(); } +QRect OutputConfig::rect() const +{ + return QRect( position(), resolution()); +} + +bool OutputConfig::isActive() const +{ + return sizeCombo->count() != 0 && !resolution().isEmpty(); +} + float OutputConfig::refreshRate(void) const { + if( !isActive()) + return 0; float rate = float(refreshCombo->itemData(refreshCombo->currentIndex()).toDouble()); if(rate == 0.0f) { RateList rates = m_output->refreshRates(resolution()); @@ -87,20 +137,36 @@ int OutputConfig::rotation(void) const { + if( !isActive()) + return 0; return orientationCombo->itemData(orientationCombo->currentIndex()).toInt(); } +bool OutputConfig::hasPendingChanges( const QPoint& normalizePos ) const +{ + if (m_output->rect().translated( -normalizePos ) != QRect(position(), resolution())) { + return true; + } + else if (m_output->rotation() != rotation()) { + return true; + } + else if (m_output->refreshRate() != refreshRate()) { + return true; + } + return false; +} + void OutputConfig::outputChanged(RROutput output, int changes) { Q_ASSERT(m_output->id() == output); - kDebug() << "Output " << m_output->name() << " changed. (mask = " << changes << ")"; + kDebug() << "Output" << m_output->name() << "changed. ( mask =" << QString::number(changes) << ")"; if(changes & RandR::ChangeOutputs) { - kDebug() << "Outputs changed"; + kDebug() << "Outputs changed."; } if(changes & RandR::ChangeCrtc) { - kDebug() << "Output CRTC changed"; + kDebug() << "Output CRTC changed."; updateSizeList(); updateRateList(); @@ -109,29 +175,28 @@ if(changes & RandR::ChangeRect) { QRect r = m_output->rect(); - kDebug() << "Output rect changed: " << r; - //m_item->setRect(0, 0, r.width(), r.height()); - m_item->setRect(r); - //m_item->setPos + kDebug() << "Output rect changed:" << r; } if(changes & RandR::ChangeRotation) { - kDebug() << "Output rotation changed"; + kDebug() << "Output rotation changed."; updateRotationList(); } if(changes & RandR::ChangeConnection) { - kDebug() << "Output connection status changed"; + kDebug() << "Output connection status changed."; setEnabled(m_output->isConnected()); } if(changes & RandR::ChangeRate) { - kDebug() << "Output rate changed"; + kDebug() << "Output rate changed."; updateRateList(); } if(changes & RandR::ChangeMode) { kDebug() << "Output mode changed."; + updateSizeList(); + // This NEEDS to be fixed.. //QSize modeSize = m_output->screen()->mode(m_output->mode()).size(); QSize modeSize = m_output->mode().size(); @@ -155,13 +220,11 @@ void OutputConfig::load() { - kDebug() << "Loading output configuration for " << m_output->name(); + kDebug() << "Loading output configuration for" << m_output->name(); setEnabled( m_output->isConnected() ); - sizeCombo->clear(); orientationCombo->clear(); - m_item->setVisible(m_output->isActive()); if (!m_output->isConnected()) return; @@ -172,11 +235,6 @@ updateRotationList(); updatePositionList(); - // update the item - m_item->setRect( 0, 0, m_output->rect().width(), m_output->rect().height()); - kDebug() << " Setting graphic rect pos: " << m_output->rect().topLeft(); - m_item->setPos( m_output->rect().topLeft() ); - emit updateView(); } @@ -186,6 +244,25 @@ emit optionChanged(); } +bool OutputConfig::isRelativeTo( QRect rect, QRect to, Relation rel ) +{ + switch( rel ) { + case LeftOf: + return rect.x() + rect.width() == to.x() && rect.y() == to.y(); + case RightOf: + return rect.x() == to.x() + to.width() && rect.y() == to.y(); + case Over: + return rect.x() == to.x() && rect.y() + rect.height() == to.y(); + case Under: + return rect.x() == to.x() && rect.y() == to.y() + to.height(); + case SameAs: + return rect.topLeft() == to.topLeft(); + case Absolute: + default: + return false; + } +} + void OutputConfig::positionComboChanged(int item) { Relation rel; @@ -208,7 +285,27 @@ void OutputConfig::updatePositionList(void) { - Relation rel = SameAs; + // Delay because + // a) this is an optimization + // b) this can be called in the middle of changing configuration and can + // lead to the comboboxes being setup to wrong values + updatePositionListTimer.start( 0 ); +} + +void OutputConfig::updatePositionListDelayed() +{ + bool enable = !resolution().isEmpty(); + positionCombo->setEnabled( enable ); + positionLabel->setEnabled( enable ); + positionOutputCombo->setEnabled( enable ); + absolutePosX->setEnabled( enable ); + absolutePosY->setEnabled( enable ); + // when updating, use previously set value, otherwise read it from the output + QRect rect = positionCombo->count() > 0 ? QRect( position(), resolution()) : m_output->rect(); + positionCombo->clear(); + positionOutputCombo->clear(); + + Relation rel = Absolute; // FIXME: get default value from KConfig for(int i = -1; i < 5; i++) positionCombo->addItem(OutputConfig::positionName((Relation)i), i); @@ -218,24 +315,37 @@ positionCombo->setCurrentIndex(index); /* Relative Output Name Configuration */ - OutputMap outputs = m_output->screen()->outputs(); - foreach(RandROutput *output, outputs) + foreach(OutputConfig *config, precedingOutputConfigs) { + RandROutput* output = config->output(); + if( config->resolution().isEmpty()) + continue; // ignore disabled outputs positionOutputCombo->addItem(QIcon(output->icon()), output->name(), (int)output->id()); + for( int rel = -1; rel < 5; ++rel ) { + if( isRelativeTo( rect, QRect( config->position(), config->resolution()), (Relation) rel )) { + positionCombo->setCurrentIndex( positionCombo->findData( rel )); + } + } + } + if( positionOutputCombo->count() == 0 ) { + positionOutputCombo->setEnabled( false ); + while( positionCombo->count() > 1 ) // keep only 'Absolute' + positionCombo->removeItem( positionCombo->count() - 1 ); + } // FIXME: get this from Kconfig again /*if(m_output->relation(0) != m_output) { index = positionOutputCombo->findData((int)m_output->relation(0)->id()); if(index != -1) positionOutputCombo->setCurrentIndex(index); - } else*/ if(m_output->screen()->activeCount() < 2) { - positionLabel->setEnabled(false); - positionCombo->setEnabled(false); - positionOutputCombo->setEnabled(false); - } + }*/ } void OutputConfig::updateRotationList(void) { + bool enable = !resolution().isEmpty(); + orientationCombo->setEnabled( enable ); + orientationLabel->setEnabled( enable ); + orientationCombo->clear(); int rotations = m_output->rotations(); for(int i =0; i < 6; ++i) { int rot = (1 << i); @@ -251,15 +361,17 @@ } void OutputConfig::updateSizeList(void) -{ +{ SizeList sizes = m_output->sizes(); + RandRMode preferredMode = m_output->preferredMode(); + sizeCombo->clear(); sizeCombo->addItem( i18n("Disabled"), QSize(0, 0) ); foreach (QSize s, sizes) { - QString sizeDesc = QString("%1x%2").arg(s.width()).arg(s.height()); - if(s == m_output->preferredMode().size()) + QString sizeDesc = QString("%1x%2").arg(s.width()).arg(s.height()); + if (preferredMode.isValid() && s == preferredMode.size()) { sizeDesc += i18nc("Automatic (native resolution)", " (Auto)"); - + } sizeCombo->addItem( sizeDesc, s ); } @@ -277,6 +389,7 @@ QSize resolution = sizeCombo->itemData(resolutionIndex).toSize(); if((resolution == QSize(0, 0)) || !resolution.isValid()) { refreshCombo->setEnabled(false); + rateLabel->setEnabled(false); return; } @@ -285,6 +398,7 @@ refreshCombo->clear(); refreshCombo->addItem(i18nc("Automatic configuration", "Auto"), 0.0f); refreshCombo->setEnabled(true); + rateLabel->setEnabled(true); foreach(RRMode m, modeList) { RandRMode outMode = m_output->screen()->mode(m); if(outMode.isValid() && outMode.size() == resolution) { Index: krandrmodule.cpp =================================================================== --- kcontrol/randr/krandrmodule.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/krandrmodule.cpp (.../work/~seli/randr) (revision 895733) @@ -96,7 +96,7 @@ void KRandRModule::load() { - kDebug() << "Loading KRandRMode..."; + kDebug() << "Loading KRandRModule..."; #ifdef HAS_RANDR_1_2 if (RandR::has_1_2) Index: randroutput.cpp =================================================================== --- kcontrol/randr/randroutput.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/randroutput.cpp (.../work/~seli/randr) (revision 895733) @@ -71,18 +71,29 @@ m_connected = (info->connection == RR_Connected); m_name = info->name; + kDebug() << "XID" << m_id << "is output" << m_name << + (isConnected() ? "(connected)" : "(not connected)"); + setCrtc(m_screen->crtc(info->crtc)); - m_crtc->loadSettings(false); - - for(int i = 0; i < info->ncrtc; ++i) + kDebug() << "Possible CRTCs for output" << m_name << ":"; + + if (!info->ncrtc) { + kDebug() << " - none"; + } + for(int i = 0; i < info->ncrtc; ++i) { + kDebug() << " - CRTC" << info->crtcs[i]; m_possibleCrtcs.append(info->crtcs[i]); + } //TODO: is it worth notifying changes on mode list changing? m_modes.clear(); - m_preferredMode = m_screen->mode(info->modes[info->npreferred]); - for (int i = 0; i < info->nmode; ++i) + for (int i = 0; i < info->nmode; ++i) { + if (i < info->npreferred) { + m_preferredMode = m_screen->mode(info->modes[i]); + } m_modes.append(info->modes[i]); + } //get all possible rotations m_rotations = 0; @@ -97,10 +108,10 @@ m_originalRect = m_crtc->rect(); if(isConnected()) { - kDebug() << "Output name:" << m_name; - kDebug() << "Output refresh rate:" << m_originalRate; - kDebug() << "Output rect:" << m_originalRect; - kDebug() << "Output rotation:" << m_originalRotation; + kDebug() << "Current configuration for output" << m_name << ":"; + kDebug() << " - Refresh rate:" << m_originalRate; + kDebug() << " - Rect:" << m_originalRect; + kDebug() << " - Rotation:" << m_originalRotation; } XRRFreeOutputInfo(info); @@ -220,18 +231,17 @@ QString RandROutput::icon() const { - // FIXME: check what names we should use and what kind of outputs randr can - // report. It would also be interesting to be able to get the monitor name + // http://www.thinkwiki.org/wiki/Xorg_RandR_1.2#Output_port_names has a + // list of possible output names, at least for the intel and radeon drivers + // that support RandR 1.2. (nVidia drivers are not yet there at the time + // of writing, 2008.) + // FIXME: It would also be interesting to be able to get the monitor name // using EDID or something like that, just don't know if it is even possible. - if (m_name.contains("VGA")) + if (m_name.contains("VGA") || m_name.contains("DVI") || m_name.contains("TMDS")) return "video-display"; else if (m_name.contains("LVDS")) return "video-display"; - - // I doubt this is a good choice; can't find anything better in the spec. - // video-x-generic might work, but that's a mimetype, which is inappropriate - // for an output connection type. - else if (m_name.contains("TV")) + else if (m_name.contains("TV") || m_name.contains("S-video")) return "multimedia-player"; return "video-display"; @@ -340,6 +350,10 @@ void RandROutput::proposeOriginal() { + m_proposedRect = m_originalRect; + m_proposedRate = m_originalRate; + m_proposedRotation = m_originalRotation; + if (m_crtc->id() != None) m_crtc->proposeOriginal(); } @@ -449,6 +463,8 @@ void RandROutput::slotDisable() { + proposeRect(QRect()); + proposeRefreshRate(0); setCrtc(m_screen->crtc(None)); } @@ -457,7 +473,7 @@ if(!m_connected) return; - kDebug() << "Attempting to enable " << m_name; + kDebug() << "Attempting to enable" << m_name; RandRCrtc *crtc = findEmptyCrtc(); if(crtc) @@ -480,6 +496,7 @@ bool RandROutput::tryCrtc(RandRCrtc *crtc, int changes) { + kDebug() << "Trying to change output" << m_name << "to CRTC" << crtc->id() << "..."; RandRCrtc *oldCrtc = m_crtc; // if we are not yet using this crtc, switch to use it @@ -498,29 +515,42 @@ if (changes & RandR::ChangeRate) crtc->proposeRefreshRate(m_proposedRate); - if (crtc->applyProposed()) + if (crtc->applyProposed()) { + kDebug() << "Changed output" << m_name << "to CRTC" << crtc->id(); + kDebug() << " ( from old CRTC" << oldCrtc->id() << ")"; return true; + } // revert changes if we didn't succeed crtc->proposeOriginal(); crtc->applyProposed(); // switch back to the old crtc + kDebug() << "Failed to change output" << m_name << "to CRTC" << crtc->id(); + kDebug() << " Switching back to old CRTC" << oldCrtc->id(); setCrtc(oldCrtc); return false; } bool RandROutput::applyProposed(int changes, bool confirm) { + // Don't try to disable an already disabled output. + if (!m_proposedRect.isValid() && !m_crtc->isValid()) { + return true; + } + // Don't try to change an enabled output if there is nothing to change. + if (m_crtc->isValid() + && (m_crtc->rect() == m_proposedRect || !(changes & RandR::ChangeRect)) + && (m_crtc->rotation() == m_proposedRotation || !(changes & RandR::ChangeRotation)) + && ((m_crtc->refreshRate() == m_proposedRate || !m_proposedRate || !(changes & RandR::ChangeRate)))) + { + return true; + } + kDebug() << "Applying proposed changes for output" << m_name << "..."; + KConfig cfg("krandrrc"); RandRCrtc *crtc; - QRect r; - - if (changes & RandR::ChangeRect) - r = m_proposedRect; - - // first try to apply to the already attached crtc if any if (m_crtc->isValid()) { @@ -548,7 +578,7 @@ // connection if (!crtc) return false; - + // try the crtc, and if no confirmation is needed or the user confirm, save the new settings if (tryCrtc(crtc, changes)) { @@ -570,18 +600,20 @@ bool RandROutput::setCrtc(RandRCrtc *crtc, bool applyNow) { - Q_UNUSED(applyNow); if( !crtc || (m_crtc && crtc->id() == m_crtc->id()) ) return false; - kDebug() << "Setting CRTC" << crtc->id() << "on output" << m_name; + kDebug() << "Setting CRTC" << crtc->id() + << (crtc->isValid() ? "(enabled)" : "(disabled)") + << "on output" << m_name; if(m_crtc && m_crtc->isValid()) { disconnect(m_crtc, SIGNAL(crtcChanged(RRCrtc, int)), this, SLOT(slotCrtcChanged(RRCrtc, int))); m_crtc->removeOutput(m_id); - m_crtc->applyProposed(); + if( applyNow ) + m_crtc->applyProposed(); } m_crtc = crtc; if (!m_crtc->isValid()) @@ -594,6 +626,11 @@ return true; } +void RandROutput::disconnectFromCrtc() +{ // but don't apply now + setCrtc(m_screen->crtc(None), false); +} + void RandROutput::slotCrtcChanged(RRCrtc c, int changes) { Q_UNUSED(c); Index: CMakeLists.txt =================================================================== --- kcontrol/randr/CMakeLists.txt (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/CMakeLists.txt (.../work/~seli/randr) (revision 895733) @@ -1,5 +1,9 @@ include_directories( ${X11_Xrandr_INCLUDE_PATH} ) +if( XRANDR_1_2_FOUND ) + macro_optional_add_subdirectory(module) +endif( XRANDR_1_2_FOUND ) + configure_file (config-randr.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-randr.h ) Index: randrconfig.cpp =================================================================== --- kcontrol/randr/randrconfig.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/randrconfig.cpp (.../work/~seli/randr) (revision 895733) @@ -28,6 +28,10 @@ #include "randrdisplay.h" #include "randrscreen.h" +#include <kglobalsettings.h> +#include <kmessagebox.h> +#include <kprocess.h> + RandRConfig::RandRConfig(QWidget *parent, RandRDisplay *display) : QWidget(parent), Ui::RandRConfigBase() { @@ -35,7 +39,6 @@ Q_ASSERT(m_display); m_changed = false; - m_firstLoad = true; if (!m_display->isValid()) { // FIXME: this needs much better handling of this error... @@ -44,6 +47,12 @@ setupUi(this); + connect( identifyOutputsButton, SIGNAL( clicked()), SLOT( identifyOutputs())); + connect( &identifyTimer, SIGNAL( timeout()), SLOT( clearIndicators())); + connect( &compressUpdateViewTimer, SIGNAL( timeout()), SLOT( slotDelayedUpdateView())); + identifyTimer.setSingleShot( true ); + compressUpdateViewTimer.setSingleShot( true ); + // create the container for the settings widget QHBoxLayout *layout = new QHBoxLayout(outputList); layout->setSpacing(0); @@ -62,6 +71,7 @@ RandRConfig::~RandRConfig() { + clearIndicators(); } void RandRConfig::load(void) @@ -70,44 +80,39 @@ kDebug() << "Invalid display! Aborting config load."; return; } + + m_scene->clear(); + qDeleteAll(m_outputList); + m_outputList.clear(); + m_configs.clear(); // objects deleted above - if(!m_firstLoad) { - qDeleteAll(m_outputList); - m_outputList.clear(); - - QList<QGraphicsItem*> items = m_scene->items(); - foreach(QGraphicsItem *i, items) { - if(i->scene() == m_scene) - m_scene->removeItem(i); - } - } - - m_firstLoad = false; - OutputMap outputs = m_display->currentScreen()->outputs(); // FIXME: adjust it to run on a multi screen system CollapsibleWidget *w; OutputGraphicsItem *o; + OutputConfigList preceding; foreach(RandROutput *output, outputs) { - o = new OutputGraphicsItem(output); - m_scene->addItem(o); + OutputConfig *config = new OutputConfig(this, output, preceding); + m_configs.append( config ); + preceding.append( config ); - connect(o, SIGNAL(itemChanged(OutputGraphicsItem*)), - this, SLOT(slotAdjustOutput(OutputGraphicsItem*))); - - OutputConfig *config = new OutputConfig(0, output, o); - QString description = output->name() + (output->isConnected() ? " (Connected)" : ""); w = m_container->insertWidget(config, description); if(output->isConnected()) { w->setExpanded(true); - kDebug() << "Output rect: " << output->rect(); + kDebug() << "Output rect:" << output->rect(); } m_outputList.append(w); + o = new OutputGraphicsItem(config); + m_scene->addItem(o); + + connect(o, SIGNAL(itemChanged(OutputGraphicsItem*)), + this, SLOT(slotAdjustOutput(OutputGraphicsItem*))); + connect(config, SIGNAL(updateView()), this, SLOT(slotUpdateView())); connect(config, SIGNAL(optionChanged()), this, SLOT(slotChanged())); } @@ -129,31 +134,61 @@ void RandRConfig::apply() { - kDebug() << "Applying settings... "; + kDebug() << "Applying settings..."; + + // normalize positions so that the coordinate system starts at (0,0) + QPoint normalizePos; + bool first = true; foreach(CollapsibleWidget *w, m_outputList) { OutputConfig *config = static_cast<OutputConfig *>(w->innerWidget()); + if( config->isActive()) { + QPoint pos = config->position(); + if( first ) { + normalizePos = pos; + first = false; + } else { + if( pos.x() < normalizePos.x()) + normalizePos.setX( pos.x()); + if( pos.y() < normalizePos.y()) + normalizePos.setY( pos.y()); + } + } + } + normalizePos = -normalizePos; + kDebug() << "Normalizing positions by" << normalizePos; + + foreach(CollapsibleWidget *w, m_outputList) { + OutputConfig *config = static_cast<OutputConfig *>(w->innerWidget()); RandROutput *output = config->output(); if(!output->isConnected()) continue; QSize res = config->resolution(); - QRect configuredRect(config->position(), res); if(!res.isNull()) { - if(output->rect() == configuredRect) { - kDebug() << "Ignoring identical config for " << output->name(); + if(!config->hasPendingChanges( normalizePos )) { + kDebug() << "Ignoring identical config for" << output->name(); continue; } + QRect configuredRect(config->position(), res); - kDebug() << "Output config: rect =" << configuredRect << ", rot = " - << config->rotation() << ", rate =" << config->refreshRate(); - - output->proposeRect(configuredRect); + kDebug() << "Output config for" << output->name() << ":\n" + " rect =" << configuredRect + << ", rot =" << config->rotation() + << ", rate =" << config->refreshRate(); + + // Break the connection with the previous CRTC for changed outputs, since + // otherwise the code could try to use the same CRTC for two different outputs. + // This is probably rather hackish and may not always work, but I don't see + // a better way with this codebase, definitely not with the time I have now. + output->disconnectFromCrtc(); + + output->proposeRect(configuredRect.translated( normalizePos )); output->proposeRotation(config->rotation()); output->proposeRefreshRate(config->refreshRate()); } else { // user wants to disable this output - kDebug() << "Disabling " << output->name(); + kDebug() << "Disabling" << output->name(); output->slotDisable(); } } @@ -184,27 +219,33 @@ void RandRConfig::slotAdjustOutput(OutputGraphicsItem *o) { Q_UNUSED(o); - kDebug() << "Output graphics item changed: "; + kDebug() << "Output graphics item changed:"; // TODO: Implement } void RandRConfig::slotUpdateView() { + compressUpdateViewTimer.start( 0 ); +} + +#include <typeinfo> + +void RandRConfig::slotDelayedUpdateView() +{ QRect r; bool first = true; // updates the graphics view so that all outputs fit inside of it - OutputMap outputs = m_display->currentScreen()->outputs(); - foreach(RandROutput *output, outputs) + foreach(OutputConfig *config, m_configs) { if (first) { first = false; - r = output->rect(); + r = config->rect(); } else - r = r.united(output->rect()); + r = r.united(config->rect()); } // scale the total bounding rectangle for all outputs to fit // 80% of the containing QGraphicsView @@ -217,7 +258,74 @@ screenView->scale(scale,scale); screenView->ensureVisible(r); screenView->setSceneRect(r); + + foreach( QGraphicsItem* item, m_scene->items()) { + if( OutputGraphicsItem* itemo = dynamic_cast< OutputGraphicsItem* >( item )) + itemo->configUpdated(); + } + screenView->update(); } +uint qHash( const QPoint& p ) +{ + return p.x() * 10000 + p.y(); +} + +void RandRConfig::identifyOutputs() +{ + identifyTimer.stop(); + clearIndicators(); + QHash< QPoint, QStringList > ids; // outputs at centers of screens (can be more in case of clone mode) + OutputMap outputs = m_display->currentScreen()->outputs(); + foreach(RandROutput *output, outputs) + { + if( !output->isConnected() || output->rect().isEmpty()) + continue; + ids[ output->rect().center() ].append( output->name()); + } + for( QHash< QPoint, QStringList >::ConstIterator it = ids.begin(); + it != ids.end(); + ++it ) + { + QLabel *si = new QLabel(it->join("\n"), NULL, Qt::X11BypassWindowManagerHint); + QFont fnt = KGlobalSettings::generalFont(); + fnt.setPixelSize(100); + si->setFont(fnt); + si->setFrameStyle(QFrame::Panel); + si->setFrameShadow(QFrame::Plain); + si->setAlignment(Qt::AlignCenter); + QRect targetGeometry(QPoint(0,0), si->sizeHint()); + targetGeometry.moveCenter(it.key()); + si->setGeometry(targetGeometry); + si->show(); + m_indicators.append( si ); + } + identifyTimer.start( 1500 ); +} + +void RandRConfig::clearIndicators() +{ + qDeleteAll( m_indicators ); + m_indicators.clear(); +} + +void RandRConfig::insufficientVirtualSize() +{ + if( KMessageBox::questionYesNo( this, + i18n( "Insufficient virtual size for the total screen size.\n" + "The configured virtual size of your X server is insufficient for this setup. " + "This configuration needs to be adjusted.\n" + "Do you wish to run a tool to adjust the configuration?" )) == KMessageBox::Yes ) + { + KProcess proc; + // TODO + if( proc.execute() == 0 ) + KMessageBox::information( this, i18n( "Configuration has been adjusted. Please restart " + "your session for this change to take effect." )); + else + KMessageBox::sorry( this, i18n( "Changing configuration failed. Please adjust your xorg.conf manually." )); + } +} + #include "randrconfig.moc" Index: randrdisplay.h =================================================================== --- kcontrol/randr/randrdisplay.h (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/randrdisplay.h (.../work/~seli/randr) (revision 895733) @@ -25,6 +25,7 @@ #include "randr.h" #include <X11/Xlib.h> +#include <fixx11h.h> class RandRDisplay { Index: module/randrmonitor.cpp =================================================================== --- kcontrol/randr/module/randrmonitor.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 0) +++ kcontrol/randr/module/randrmonitor.cpp (.../work/~seli/randr) (revision 895733) @@ -0,0 +1,210 @@ +/******************************************************************** + +Copyright (C) 2008 Lubos Lunak <l.lunak@suse.cz> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*********************************************************************/ + +#include "randrmonitor.h" + +#include <kaction.h> +#include <kactioncollection.h> +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpluginfactory.h> +#include <kpluginloader.h> +#include <ktoolinvocation.h> + +#include <qdbusconnection.h> +#include <qdbusconnectioninterface.h> +#include <qtimer.h> +#include <qx11info_x11.h> + +#include <randrdisplay.h> +#include <randrscreen.h> +#include <randroutput.h> + +K_PLUGIN_FACTORY(RandrMonitorModuleFactory, + registerPlugin<RandrMonitorModule>(); + ) +K_EXPORT_PLUGIN(RandrMonitorModuleFactory("randrmonitor")) + +RandrMonitorModule::RandrMonitorModule( QObject* parent, const QList<QVariant>& ) + : KDEDModule( parent ) + , have_randr( false ) + { + setModuleName( "randrmonitor" ); + initRandr(); + } + +RandrMonitorModule::~RandrMonitorModule() + { + if( have_randr ) + { + Display* dpy = QX11Info::display(); + XDestroyWindow( dpy, window ); + delete helper; + delete dialog; + have_randr = false; + } + } + +void RandrMonitorModule::initRandr() + { + Display* dpy = QX11Info::display(); + if( !XRRQueryExtension( dpy, &randr_base, &randr_error )) + return; + int major = 1; + int minor = 2; + if( !XRRQueryVersion( dpy, &major, &minor ) || major < 1 || (major == 1 && minor < 2 )) + return; + have_randr = true; + // It looks like we need a separate window for getting the events, so that we don't + // change e.g. Qt's event mask. + window = XCreateSimpleWindow( dpy, DefaultRootWindow( dpy ), 0, 0, 1, 1, 0, 0, 0 ); + XRRSelectInput( dpy, window, RROutputChangeNotifyMask ); +#if 0 // xrandr apparently can't detect hw changes and on some systems polling freezes X :( + // HACK: see poll() + QTimer* timer = new QTimer( this ); + timer->start( 10000 ); // 10 s + connect( timer, SIGNAL( timeout()), this, SLOT( poll())); +#endif + helper = new RandrMonitorHelper( this ); + kapp->installX11EventFilter( helper ); + dialog = NULL; + currentMonitors = connectedMonitors(); + KActionCollection* coll = new KActionCollection( this ); + KAction* act = coll->addAction( "display" ); + act->setText( i18n( "Switch Display" )); + act->setGlobalShortcut( KShortcut( Qt::Key_Display )); + connect( act, SIGNAL( triggered( bool )), SLOT( switchDisplay())); + } + +void RandrMonitorModule::poll() + { + // HACK: It seems that RRNotify/RRNotify_OutputChange event (i.e. detecting a newly + // plugged or unplugged monitor) does not work without polling some randr functionality. + int dummy; + XRRGetScreenSizeRange( QX11Info::display(), window, &dummy, &dummy, &dummy, &dummy ); + } + +void RandrMonitorModule::processX11Event( XEvent* e ) + { + if( e->xany.type == randr_base + RRNotify ) + { + XRRNotifyEvent* e2 = reinterpret_cast< XRRNotifyEvent* >( e ); + if( e2->subtype == RRNotify_OutputChange ) // TODO && e2->window == window ) + { + kDebug() << "Monitor change detected"; + QStringList newMonitors = connectedMonitors(); + if( newMonitors == currentMonitors ) + return; + if( QDBusConnection::sessionBus().interface()->isServiceRegistered( + "org.kde.internal.KSettingsWidget-kcm_display" )) + { // already running + return; + } + kapp->updateUserTimestamp(); // well, let's say plugging in a monitor is a user activity +#warning Modal dialog, stupid, fix. + QString change; + QString question = + ( newMonitors.count() < currentMonitors.count() + ? i18n( "A monitor output has been disconnected." ) + : i18n( "A new monitor output has been connected." )) + + "\n\n" + i18n( "Do you wish to run a configuration tool to adjust the monitor setup?" ); + currentMonitors = newMonitors; + if( KMessageBox::questionYesNo( NULL, question, i18n( "Monitor setup has changed" ), + KGuiItem( "Con&figure" ), KGuiItem( "&Ignore" ), "randrmonitorchange" ) + == KMessageBox::Yes ) + { + KToolInvocation::kdeinitExec( "kcmshell4", QStringList() << "display" ); + } + } + } + } + +QStringList RandrMonitorModule::connectedMonitors() const + { + QStringList ret; + Display* dpy = QX11Info::display(); + XRRScreenResources* resources = XRRGetScreenResources( dpy, window ); + for( int i = 0; + i < resources->noutput; + ++i ) + { + XRROutputInfo* info = XRRGetOutputInfo( dpy, resources, resources->outputs[ i ] ); + QString name = QString::fromUtf8( info->name ); + if( info->connection == RR_Connected ) + ret.append( name ); + XRRFreeOutputInfo( info ); + } + XRRFreeScreenResources( resources ); + return ret; + } + +void RandrMonitorModule::switchDisplay() + { + QList< RandROutput* > outputs; + RandRDisplay display; + for( int scr = 0; + scr < display.numScreens(); + ++scr ) + { + foreach( RandROutput* output, display.screen( scr )->outputs()) + { + if( !output->isConnected()) + continue; + if( !outputs.contains( output )) + outputs.append( output ); + } + } + if( outputs.count() <= 1 ) // just one, do nothing + return; + if( outputs.count() == 2 ) // alternative between one, second, both + { + if( outputs[ 0 ]->isActive() && !outputs[ 1 ]->isActive()) + { + enableOutput( outputs[ 1 ], true ); + enableOutput( outputs[ 0 ], false ); + } + else if( !outputs[ 0 ]->isActive() && outputs[ 1 ]->isActive()) + { + enableOutput( outputs[ 1 ], true ); + enableOutput( outputs[ 0 ], true ); + } + else + { + enableOutput( outputs[ 0 ], true ); + enableOutput( outputs[ 1 ], false ); + } + return; + } + // no idea what to do here + KToolInvocation::kdeinitExec( "kcmshell4", QStringList() << "display" ); + } + +void RandrMonitorModule::enableOutput( RandROutput* output, bool enable ) + { // a bit lame, but I don't know how to do this easily with this codebase :-/ + KProcess::execute( QStringList() << "xrandr" << "--output" << output->name() << ( enable ? "--auto" : "--off" )); + } + +bool RandrMonitorHelper::x11Event( XEvent* e ) + { + module->processX11Event( e ); + return QWidget::x11Event( e ); + } + +#include "randrmonitor.moc" Index: module/randrmonitor.h =================================================================== --- kcontrol/randr/module/randrmonitor.h (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 0) +++ kcontrol/randr/module/randrmonitor.h (.../work/~seli/randr) (revision 895733) @@ -0,0 +1,78 @@ +/******************************************************************** + +Copyright (C) 2008 Lubos Lunak <l.lunak@suse.cz> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*********************************************************************/ + +#ifndef RANDRMONITOR_H +#define RANDRMONITOR_H + +#include <kdedmodule.h> +#include <kprocess.h> +#include <qwidget.h> + +#include <X11/Xlib.h> +#include <X11/extensions/Xrandr.h> +#include <fixx11h.h> + +class RandROutput; + +class RandrMonitorHelper; + +class RandrMonitorModule + : public KDEDModule + { + Q_OBJECT + public: + RandrMonitorModule(QObject* parent, const QList<QVariant>&); + virtual ~RandrMonitorModule(); + void processX11Event( XEvent* e ); + private slots: + void poll(); + void switchDisplay(); + private: + void initRandr(); + void getRandrInfo( XRROutputChangeNotifyEvent* e, QString* change, QRect* rect ); + QStringList connectedMonitors() const; + void enableOutput( RandROutput* output, bool enable ); + bool have_randr; + int randr_base; + int randr_error; + Window window; + QStringList currentMonitors; + RandrMonitorHelper* helper; + QDialog* dialog; + }; + +class RandrMonitorHelper + : public QWidget + { + Q_OBJECT + public: + RandrMonitorHelper( RandrMonitorModule* module ); + protected: + virtual bool x11Event( XEvent* e ); + private: + RandrMonitorModule* module; + }; + + +inline +RandrMonitorHelper::RandrMonitorHelper( RandrMonitorModule* m ) + : module( m ) + { + } + +#endif Index: module/TODO =================================================================== --- kcontrol/randr/module/TODO (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 0) +++ kcontrol/randr/module/TODO (.../work/~seli/randr) (revision 895733) @@ -0,0 +1,7 @@ +- zrusit ten modalni dialog +- zkontrolovat, ze tohle opravdu nerusi randr eventmask pro Qt + - plus zkontrolovat, jak se tedy pouziva to window pro events +- musi se dialog zobrazit na spravnem monitoru (tj. ne na vypnutem) +- Hidden[$e]= v .desktop nefunguje +- kdyz se detekuje zmena, kcm sam o sobe nic(?) neudela, takze musi byt nejake 'suggest'? +- zkontrolovat nastaveni po startu KDE Index: module/randrmonitor.desktop =================================================================== --- kcontrol/randr/module/randrmonitor.desktop (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 0) +++ kcontrol/randr/module/randrmonitor.desktop (.../work/~seli/randr) (revision 895733) @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=Detecting RANDR (monitor) changes +Type=Service +X-KDE-ServiceTypes=KDEDModule +X-KDE-Library=randrmonitor +X-KDE-DBus-ModuleName=randrmonitor +X-KDE-Kded-autoload=true +OnlyShowIn=KDE; Index: module/CMakeLists.txt =================================================================== --- kcontrol/randr/module/CMakeLists.txt (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 0) +++ kcontrol/randr/module/CMakeLists.txt (.../work/~seli/randr) (revision 895733) @@ -0,0 +1,25 @@ +include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ) + +########### next target ############### + +set(kded_randrmonitor_PART_SRCS + randrmonitor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../randrdisplay.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../randrscreen.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../randroutput.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../randrcrtc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../randrmode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../randr.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../legacyrandrscreen.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../ktimerdialog.cpp + ) + +kde4_add_plugin(kded_randrmonitor ${kded_randrmonitor_PART_SRCS}) + +target_link_libraries(kded_randrmonitor ${KDE4_KDEUI_LIBS} ${X11_Xrandr_LIB} ${X11_LIBRARIES}) + +install(TARGETS kded_randrmonitor DESTINATION ${PLUGIN_INSTALL_DIR} ) + +########### install files ############### + +install( FILES randrmonitor.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded ) Index: module/randrpolltest.cpp =================================================================== --- kcontrol/randr/module/randrpolltest.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 0) +++ kcontrol/randr/module/randrpolltest.cpp (.../work/~seli/randr) (revision 895733) @@ -0,0 +1,63 @@ +#include <X11/Xlib.h> +#include <X11/extensions/Xrandr.h> +#include <stdio.h> +#include <unistd.h> + +int main( int argc, char* argv[] ) + { + Display* dpy = XOpenDisplay( NULL ); + XSetWindowAttributes attrs; + Window w = XCreateWindow( dpy, DefaultRootWindow( dpy ), 0, 0, 100, 100, 0, CopyFromParent, CopyFromParent, + CopyFromParent, 0, &attrs ); +// XMapWindow( dpy, w ); + int base, error; + if( !XRRQueryExtension( dpy, &base, &error )) + return 1; + int major = 1; + int minor = 2; + if( !XRRQueryVersion( dpy, &major, &minor ) || major < 1 || (major == 1 && minor < 2 )) + return 2; + XRRSelectInput( dpy, w, + RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RROutputPropertyNotifyMask ); + for(;;) + { + XEvent ev; + int a, b, c, d; + static int cnt = 0; + if( ++cnt % 30 == 0 ) + { +// XRRFreeScreenResources(XRRGetScreenResources( dpy, w )); + XRRGetScreenSizeRange( dpy, w, &a, &b, &c, &d ); +// XSync( dpy, False ); + printf( "Poll\n" ); + } + sleep( 1 ); + if( !XPending( dpy )) + continue; + XNextEvent( dpy, &ev ); + if( ev.xany.type == base + RRScreenChangeNotify ) + { + printf( "Screen Change\n" ); + } + if( ev.xany.type == base + RRNotify ) + { + XRRNotifyEvent* e = reinterpret_cast< XRRNotifyEvent* >( &ev ); + switch( e->subtype ) + { + case RRNotify_CrtcChange: + printf( "Crtc Change\n" ); + break; + case RRNotify_OutputChange: + printf( "Output Change\n" ); + break; + case RRNotify_OutputProperty: + printf( "Output Property Change\n" ); + break; + default: + printf( "Unknown Notify\n" ); + break; + } + } + } + XCloseDisplay( dpy ); + } Index: outputgraphicsitem.h =================================================================== --- kcontrol/randr/outputgraphicsitem.h (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/outputgraphicsitem.h (.../work/~seli/randr) (revision 895733) @@ -24,15 +24,17 @@ #include "randr.h" -class RandROutput; +class OutputConfig; class OutputGraphicsItem : public QObject, public QGraphicsRectItem { Q_OBJECT public: - OutputGraphicsItem(RandROutput *output); + OutputGraphicsItem(OutputConfig *config); ~OutputGraphicsItem(); + void configUpdated(); // updates from OutputConfig + OutputGraphicsItem *left() const; OutputGraphicsItem *right() const; OutputGraphicsItem *top() const; @@ -59,7 +61,7 @@ OutputGraphicsItem *m_top; OutputGraphicsItem *m_bottom; - RandROutput *m_output; + OutputConfig *m_config; QGraphicsTextItem *m_text; Index: randrscreen.cpp =================================================================== --- kcontrol/randr/randrscreen.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/randrscreen.cpp (.../work/~seli/randr) (revision 895733) @@ -111,6 +111,7 @@ } //get all crtcs + kDebug() << "Creating CRTC object for XID 0 (\"None\")"; RandRCrtc *c_none = new RandRCrtc(this, None); m_crtcs[None] = c_none; @@ -120,9 +121,11 @@ m_crtcs[m_resources->crtcs[i]]->loadSettings(notify); else { + kDebug() << "Creating CRTC object for XID" << m_resources->crtcs[i]; RandRCrtc *c = new RandRCrtc(this, m_resources->crtcs[i]); connect(c, SIGNAL(crtcChanged(RRCrtc, int)), this, SIGNAL(configChanged())); connect(c, SIGNAL(crtcChanged(RRCrtc, int)), this, SLOT(save())); + c->loadSettings(notify); m_crtcs[m_resources->crtcs[i]] = c; changed = true; } @@ -135,6 +138,7 @@ ;//m_outputs[m_resources->outputs[i]]->loadSettings(notify); else { + kDebug() << "Creating output object for XID" << m_resources->outputs[i]; RandROutput *o = new RandROutput(this, m_resources->outputs[i]); connect(o, SIGNAL(outputChanged(RROutput, int)), this, SLOT(slotOutputChanged(RROutput, int))); @@ -389,7 +393,7 @@ m_unifiedRect = group.readEntry("UnifiedRect", QRect()); m_unifiedRotation = group.readEntry("UnifiedRotation", (int) RandR::Rotate0); - slotUnifyOutputs(m_outputsUnified); +// slotUnifyOutputs(m_outputsUnified); foreach(RandROutput *output, m_outputs) { @@ -426,6 +430,8 @@ bool RandRScreen::applyProposed(bool confirm) { + kDebug() << "Applying proposed changes for screen" << m_index << "..."; + bool succeed = true; QRect r; @@ -476,6 +482,8 @@ } }*/ + kDebug() << "Changes have been applied to all outputs."; + // if we could apply the config clean, ask for confirmation if (succeed && confirm) succeed = RandR::confirm(r); @@ -485,6 +493,8 @@ if (succeed) return true; + kDebug() << "Changes canceled, reverting to original setup."; + //Revert changes if not succeed foreach(RandROutput *o, m_outputs) { @@ -532,8 +542,7 @@ //o->load(cfg); o->proposeRect(m_unifiedRect); o->proposeRotation(m_unifiedRotation); - o->applyProposed(RandR::ChangeRect | - RandR::ChangeRotation, false); + o->applyProposed(RandR::ChangeRect | RandR::ChangeRotation, false); } // FIXME: if by any reason we were not able to unify the outputs, we should Index: BRANCH =================================================================== --- kcontrol/randr/BRANCH (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 0) +++ kcontrol/randr/BRANCH (.../work/~seli/randr) (revision 895733) @@ -0,0 +1,8 @@ +last sync: +r883104 (4.1) +r883800 (4.2) + + + +- co to dela po startu? +- zkontrolovat kwin a plasma, jestli nepadaji atd. Index: layoutmanager.h =================================================================== --- kcontrol/randr/layoutmanager.h (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/layoutmanager.h (.../work/~seli/randr) (revision 895733) @@ -21,6 +21,7 @@ #include <QObject> #include "randr.h" +#include <qgraphicsview.h> class RandRScreen; class QGraphicsScene; @@ -45,4 +46,12 @@ }; +class GraphicsView : public QGraphicsView +{ + Q_OBJECT +public: + GraphicsView( QWidget* parent ); + virtual QSize sizeHint() const; +}; + #endif Index: randrcrtc.cpp =================================================================== --- kcontrol/randr/randrcrtc.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/randrcrtc.cpp (.../work/~seli/randr) (revision 895733) @@ -68,6 +68,8 @@ if(m_id == None) return; + kDebug() << "Querying information about CRTC" << m_id; + int changes = 0; XRRCrtcInfo *info = XRRGetCrtcInfo(QX11Info::display(), m_screen->resources(), m_id); Q_ASSERT(info); @@ -86,8 +88,9 @@ // and create a list of modes that are available in all connected outputs OutputList outputs; - for (int i = 0; i < info->noutput; ++i) + for (int i = 0; i < info->noutput; ++i) { outputs.append(info->outputs[i]); + } // check if the list changed from the original one if (outputs != m_connectedOutputs) @@ -196,16 +199,18 @@ bool RandRCrtc::applyProposed() { - kDebug() << "[CRTC] Going to apply (" << m_id << ") ...."; - kDebug() << " Current Screen rect: " << m_screen->rect(); - kDebug() << " Current CRTC Rect: " << m_currentRect; - kDebug() << " Current Rotation: " << m_currentRotation; - kDebug() << " Proposed rect: " << m_proposedRect; - kDebug() << " Proposed rotation: " << m_proposedRotation; - kDebug() << " Proposed refresh rate: " << m_proposedRate; - kDebug() << " Outputs: "; + kDebug() << "Applying proposed changes for CRTC" << m_id << "..."; + kDebug() << " Current Screen rect:" << m_screen->rect(); + kDebug() << " Current CRTC rect:" << m_currentRect; + kDebug() << " Current rotation:" << m_currentRotation; + kDebug() << " Proposed CRTC rect:" << m_proposedRect; + kDebug() << " Proposed rotation:" << m_proposedRotation; + kDebug() << " Proposed refresh rate:" << m_proposedRate; + kDebug() << " Connected outputs:"; + if (m_connectedOutputs.isEmpty()) + kDebug() << " - none"; for (int i = 0; i < m_connectedOutputs.count(); ++i) - kDebug() << " - " << m_screen->output(m_connectedOutputs.at(i))->name(); + kDebug() << " -" << m_screen->output(m_connectedOutputs.at(i))->name(); RandRMode mode; if (m_proposedRect.size() == m_currentRect.size() && m_proposedRate == m_currentRate) @@ -252,10 +257,6 @@ else if (!mode.isValid()) return false; - RROutput *outputs = new RROutput[m_connectedOutputs.count()]; - for (int i = 0; i < m_connectedOutputs.count(); ++i) - outputs[i] = m_connectedOutputs.at(i); - if (mode.isValid()) { if (m_currentRotation == m_proposedRotation || @@ -296,8 +297,11 @@ } } } - - + + RROutput *outputs = new RROutput[m_connectedOutputs.count()]; + for (int i = 0; i < m_connectedOutputs.count(); ++i) + outputs[i] = m_connectedOutputs.at(i); + Status s = XRRSetCrtcConfig(QX11Info::display(), m_screen->resources(), m_id, RandR::timestamp, m_proposedRect.x(), m_proposedRect.y(), mode.id(), m_proposedRotation, outputs, m_connectedOutputs.count()); @@ -307,6 +311,7 @@ bool ret; if (s == RRSetConfigSuccess) { + kDebug() << "Changes for CRTC" << m_id << "successfully applied."; m_currentMode = mode.id(); m_currentRotation = m_proposedRotation; m_currentRect = m_proposedRect; @@ -316,6 +321,7 @@ } else { + kDebug() << "Failed to apply changes for CRTC" << m_id; ret = false; // Invalidate the XRRScreenResources cache if(s == RRSetConfigInvalidConfigTime) Index: outputconfig.h =================================================================== --- kcontrol/randr/outputconfig.h (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/outputconfig.h (.../work/~seli/randr) (revision 895733) @@ -22,18 +22,21 @@ #include <QWidget> #include <QTextStream> +#include <QTimer> #include "ui_outputconfigbase.h" #include "randr.h" #include "randroutput.h" class RandROutput; -class OutputGraphicsItem; +class OutputConfig; +typedef QList<OutputConfig*> OutputConfigList; + class OutputConfig : public QWidget, public Ui::OutputConfigBase { Q_OBJECT public: - OutputConfig(QWidget *parent, RandROutput *output, OutputGraphicsItem *item); + OutputConfig(QWidget *parent, RandROutput *output, OutputConfigList preceding); ~OutputConfig(); /** Enumeration describing two related outputs (i.e. VGA LeftOf TMDS) */ @@ -48,13 +51,17 @@ // NOTE: I'd love to have used Above and Below but Xlib already defines them // and that confuses GCC. + bool isActive() const; QPoint position(void) const; QSize resolution(void) const; + QRect rect() const; float refreshRate(void) const; int rotation(void) const; static QString positionName(Relation position); RandROutput *output(void) const; + + bool hasPendingChanges( const QPoint& normalizePos ) const; public slots: void load(); @@ -63,6 +70,7 @@ void setConfigDirty(void); void updatePositionList(void); + void updatePositionListDelayed(void); void updateRotationList(void); void updateSizeList(void); void updateRateList(void); @@ -77,12 +85,16 @@ private: + static bool isRelativeTo( QRect rect, QRect to, Relation rel ); int m_changes; bool m_changed; QPoint m_pos; + QTimer updatePositionListTimer; RandROutput *m_output; - OutputGraphicsItem *m_item; + // List of configs shown before this one. Relative positions may be given only + // relative to these in order to avoid cycles. + OutputConfigList precedingOutputConfigs; }; Index: randrdisplay.cpp =================================================================== --- kcontrol/randr/randrdisplay.cpp (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/randrdisplay.cpp (.../work/~seli/randr) (revision 895733) @@ -223,9 +223,9 @@ XRRNotifyEvent *event = (XRRNotifyEvent*)e; for (int i=0; i < m_screens.count(); ++i) { RandRScreen *screen = m_screens.at(i); - // FIXME: check which screen should receive the event - // this needs a dual-head setup - screen->handleRandREvent(event); + if ( screen->rootWindow() == event->window ) { + screen->handleRandREvent(event); + } } } #endif Index: randroutput.h =================================================================== --- kcontrol/randr/randroutput.h (.../KDE/4.1/kdebase/workspace/kcontrol/randr) (revision 895733) +++ kcontrol/randr/randroutput.h (.../work/~seli/randr) (revision 895733) @@ -69,14 +69,17 @@ /** Returns the current CRTC for this output. */ RandRCrtc *crtc() const; + void disconnectFromCrtc(); + /** Returns a list of all RRModes supported by this output. */ ModeList modes() const; /** Returns the current mode for this output. */ RandRMode mode() const; - /** Returns the preferred mode for this output. */ - RandRMode preferredMode(void) const; + /** Returns the preferred mode for this output, + * or an invalid mode if no preferred mode is known. */ + RandRMode preferredMode() const; /** The list of supported sizes */ SizeList sizes() const;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor