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;