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;
openSUSE Build Service is sponsored by