summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am.in2
-rw-r--r--kdecore/kdelibs_export.h1
-rw-r--r--krandr/Makefile.am19
-rw-r--r--krandr/configure.in.in21
-rw-r--r--krandr/ktimerdialog.cpp205
-rw-r--r--krandr/ktimerdialog.h170
-rw-r--r--krandr/libkrandr.cc126
-rw-r--r--krandr/libkrandr.h175
-rw-r--r--krandr/lowlevel_randr.c670
-rw-r--r--krandr/lowlevel_randr.h102
-rw-r--r--krandr/randr.cpp703
-rw-r--r--krandr/randr.h235
12 files changed, 2428 insertions, 1 deletions
diff --git a/Makefile.am.in b/Makefile.am.in
index 2cca5003..ba1149e5 100644
--- a/Makefile.am.in
+++ b/Makefile.am.in
@@ -20,7 +20,7 @@
COMPILE_FIRST = dcop libltdl kdefx kdecore kunittest kdeui kdesu kjs kwallet kio kded kded_post
COMPILE_BEFORE_doc = kdoctools
-COMPILE_AFTER_kparts = kspell2 kmdi kdeprint kinit kate interfaces kcert khtml
+COMPILE_AFTER_kparts = kspell2 kmdi kdeprint kinit kate interfaces kcert khtml krandr
COMPILE_AFTER_kdeprint = kate khtml
COMPILE_BEFORE_khtml = kutils
COMPILE_BEFORE_kabc = kab kresources
diff --git a/kdecore/kdelibs_export.h b/kdecore/kdelibs_export.h
index 8f9afad7..8c80f3b6 100644
--- a/kdecore/kdelibs_export.h
+++ b/kdecore/kdelibs_export.h
@@ -52,6 +52,7 @@
#define KATEPARTINTERFACES_EXPORT KDE_EXPORT
#define KATEPART_EXPORT KDE_EXPORT
#define KMID_EXPORT KDE_EXPORT
+#define KRANDR_EXPORT KDE_EXPORT
#define KIMPROXY_EXPORT KDE_EXPORT
#define KDE_ARTS_EXPORT KDE_EXPORT
#define KUNITTEST_EXPORT KDE_EXPORT
diff --git a/krandr/Makefile.am b/krandr/Makefile.am
new file mode 100644
index 00000000..4db082a6
--- /dev/null
+++ b/krandr/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/.. $(all_includes)
+
+# For the future: examine if condensing the tons of *_LDFLAGS variables
+# into $(all_libraries) isn't better
+AM_LDFLAGS = $(LDFLAGS_AS_NEEDED) $(LDFLAGS_NEW_DTAGS)
+
+libkrandrincludedir = $(includedir)/libkrandr
+libkrandrinclude_HEADERS = randr.h lowlevel_randr.h ktimerdialog.h libkrandr.h
+
+lib_LTLIBRARIES = libkrandr.la
+libkrandr_la_SOURCES = randr.cpp lowlevel_randr.c ktimerdialog.cpp libkrandr.cc
+METASOURCES = AUTO
+
+libkrandr_la_LDFLAGS = $(KDE_MT_LDFLAGS) -version-info 0:95 -no-undefined
+libkrandr_la_LIBADD = $(LIBASOUND) ../kdecore/libkdecore.la $(LIB_QT) $(LIB_XRANDR)
+
+DOXYGEN_REFERENCES = kdecore
+include ../admin/Doxyfile.am
diff --git a/krandr/configure.in.in b/krandr/configure.in.in
new file mode 100644
index 00000000..6feca241
--- /dev/null
+++ b/krandr/configure.in.in
@@ -0,0 +1,21 @@
+dnl -----------------------------------------------------
+dnl X Resize and Rotate extension library check
+dnl -----------------------------------------------------
+
+KDE_CHECK_HEADERS(X11/extensions/Xrandr.h, [xrandr_h=yes], [xrandr_h=no], [#include <X11/Xlib.h>])
+if test "$xrandr_h" = yes; then
+ KDE_CHECK_LIB(Xrandr, XRRSetScreenConfigAndRate, [
+ LIB_XRANDR=-lXrandr
+ AC_DEFINE_UNQUOTED(XRANDR_SUPPORT, 1, [Defined if your system has XRandR support])
+ RANDR_SUBDIR="randr"
+ ], [
+ RANDR_SUBDIR=""
+ ], -lXrender -lXext $X_EXTRA_LIBS)
+else
+ LIB_XRANDR=
+fi
+AC_SUBST(LIB_XRANDR)
+AM_CONDITIONAL(system_has_xrandr, test -n "$RANDR_SUBDIR")
+if test $system_has_xrandr = no; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE libkrandr"
+fi
diff --git a/krandr/ktimerdialog.cpp b/krandr/ktimerdialog.cpp
new file mode 100644
index 00000000..071088e9
--- /dev/null
+++ b/krandr/ktimerdialog.cpp
@@ -0,0 +1,205 @@
+/*
+ * This file is part of the KDE Libraries
+ * Copyright (C) 2002 Hamish Rodda <rodda@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <qhbox.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qtimer.h>
+#include <qprogressbar.h>
+#include <qlabel.h>
+
+#include <kwin.h>
+#include <kiconloader.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "ktimerdialog.h"
+#include "ktimerdialog.moc"
+
+KTimerDialog::KTimerDialog( int msec, TimerStyle style, QWidget *parent,
+ const char *name, bool modal,
+ const QString &caption,
+ int buttonMask, ButtonCode defaultButton,
+ bool separator,
+ const KGuiItem &user1,
+ const KGuiItem &user2,
+ const KGuiItem &user3 )
+ : KDialogBase(parent, name, modal, caption, buttonMask, defaultButton,
+ separator, user1, user2, user3 )
+{
+ totalTimer = new QTimer( this );
+ updateTimer = new QTimer( this );
+ msecTotal = msecRemaining = msec;
+ updateInterval = 1000;
+ tStyle = style;
+ KWin::setIcons( winId(), DesktopIcon("randr"), SmallIcon("randr") );
+ // default to cancelling the dialog on timeout
+ if ( buttonMask & Cancel )
+ buttonOnTimeout = Cancel;
+
+ connect( totalTimer, SIGNAL( timeout() ), SLOT( slotInternalTimeout() ) );
+ connect( updateTimer, SIGNAL( timeout() ), SLOT( slotUpdateTime() ) );
+
+ // create the widgets
+ mainWidget = new QVBox( this, "mainWidget" );
+ timerWidget = new QHBox( mainWidget, "timerWidget" );
+ timerLabel = new QLabel( timerWidget );
+ timerProgress = new QProgressBar( timerWidget );
+ timerProgress->setTotalSteps( msecTotal );
+ timerProgress->setPercentageVisible( false );
+
+ KDialogBase::setMainWidget( mainWidget );
+
+ slotUpdateTime( false );
+}
+
+KTimerDialog::~KTimerDialog()
+{
+}
+
+void KTimerDialog::show()
+{
+ KDialogBase::show();
+ totalTimer->start( msecTotal, true );
+ updateTimer->start( updateInterval, false );
+}
+
+int KTimerDialog::exec()
+{
+ totalTimer->start( msecTotal, true );
+ updateTimer->start( updateInterval, false );
+ return KDialogBase::exec();
+}
+
+void KTimerDialog::setMainWidget( QWidget *widget )
+{
+ // yuck, here goes.
+ QVBox *newWidget = new QVBox( this );
+
+ if ( widget->parentWidget() != mainWidget ) {
+ widget->reparent( newWidget, 0, QPoint(0,0) );
+ } else {
+ newWidget->insertChild( widget );
+ }
+
+ timerWidget->reparent( newWidget, 0, QPoint(0, 0) );
+
+ delete mainWidget;
+ mainWidget = newWidget;
+ KDialogBase::setMainWidget( mainWidget );
+}
+
+void KTimerDialog::setRefreshInterval( int msec )
+{
+ updateInterval = msec;
+ if ( updateTimer->isActive() )
+ updateTimer->changeInterval( updateInterval );
+}
+
+int KTimerDialog::timeoutButton() const
+{
+ return buttonOnTimeout;
+}
+
+void KTimerDialog::setTimeoutButton( const ButtonCode newButton )
+{
+ buttonOnTimeout = newButton;
+}
+
+int KTimerDialog::timerStyle() const
+{
+ return tStyle;
+}
+
+void KTimerDialog::setTimerStyle( const TimerStyle newStyle )
+{
+ tStyle = newStyle;
+}
+
+void KTimerDialog::slotUpdateTime( bool update )
+{
+ if ( update )
+ switch ( tStyle ) {
+ case CountDown:
+ msecRemaining -= updateInterval;
+ break;
+ case CountUp:
+ msecRemaining += updateInterval;
+ break;
+ case Manual:
+ break;
+ }
+
+ timerProgress->setProgress( msecRemaining );
+
+ timerLabel->setText( i18n("1 second remaining:","%n seconds remaining:",msecRemaining/1000) );
+}
+
+void KTimerDialog::slotInternalTimeout()
+{
+ emit timerTimeout();
+ switch ( buttonOnTimeout ) {
+ case Help:
+ slotHelp();
+ break;
+ case Default:
+ slotDefault();
+ break;
+ case Ok:
+ slotOk();
+ break;
+ case Apply:
+ applyPressed();
+ break;
+ case Try:
+ slotTry();
+ break;
+ case Cancel:
+ slotCancel();
+ break;
+ case Close:
+ slotClose();
+ break;
+ /*case User1:
+ slotUser1();
+ break;
+ case User2:
+ slotUser2();
+ break;*/
+ case User3:
+ slotUser3();
+ break;
+ case No:
+ slotNo();
+ break;
+ case Yes:
+ slotCancel();
+ break;
+ case Details:
+ slotDetails();
+ break;
+ case Filler:
+ case Stretch:
+ kdDebug() << "Cannot execute button code " << buttonOnTimeout << endl;
+ break;
+ }
+}
diff --git a/krandr/ktimerdialog.h b/krandr/ktimerdialog.h
new file mode 100644
index 00000000..23b4a92b
--- /dev/null
+++ b/krandr/ktimerdialog.h
@@ -0,0 +1,170 @@
+/*
+ * This file is part of the KDE Libraries
+ * Copyright (C) 2002 Hamish Rodda <rodda@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef _KTIMERDIALOG_H_
+#define _KTIMERDIALOG_H_
+
+#include <kdialogbase.h>
+
+class QTimer;
+class QHBox;
+class QProgressBar;
+class QLabel;
+
+/**
+ * Provides a dialog that is only available for a specified amount
+ * of time, and reports the time remaining to the user.
+ *
+ * The timer is capable of counting up or down, for any number of milliseconds.
+ *
+ * The button which is activated upon timeout can be specified, as can the
+ * update interval for the dialog box.
+ *
+ * In addition, this class retains all of the functionality of @see KDialogBase .
+ *
+ * @short A dialog with a time limit and corresponding UI features.
+ * @author Hamish Rodda <rodda@kde.org>
+ */
+class KTimerDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+
+ /**
+ * @li @p CountDown - The timer counts downwards from the seconds given.
+ * @li @p CountUp - The timer counts up to the number of seconds given.
+ * @li @p Manual - The timer is not invoked; the caller must update the
+ * progress.
+ */
+ enum TimerStyle
+ {
+ CountDown,
+ CountUp,
+ Manual
+ };
+
+ /**
+ * Constructor for the standard mode where you must specify the main
+ * widget with @ref setMainWidget() . See @see KDialogBase for further details.
+ *
+ * For the rest of the arguments, See @see KDialogBase .
+ */
+ KTimerDialog( int msec, TimerStyle style=CountDown, QWidget *parent=0,
+ const char *name=0, bool modal=true,
+ const QString &caption=QString::null,
+ int buttonMask=Ok|Apply|Cancel, ButtonCode defaultButton=Ok,
+ bool separator=false,
+ const KGuiItem &user1=KGuiItem(),
+ const KGuiItem &user2=KGuiItem(),
+ const KGuiItem &user3=KGuiItem() );
+
+ /**
+ * Destructor.
+ */
+ ~KTimerDialog();
+
+ /**
+ * Execute the dialog modelessly - see @see QDialog .
+ */
+ virtual void show();
+
+ /**
+ * Set the refresh interval for the timer progress. Defaults to one second.
+ */
+ void setRefreshInterval( int msec );
+
+ /**
+ * Retrieves the @ref ButtonCode which will be activated once the timer
+ * times out. @see setTimeoutButton
+ */
+ int timeoutButton() const;
+
+ /**
+ * Sets the @ref ButtonCode to determine which button will be activated
+ * once the timer times out. @see timeoutButton
+ */
+ void setTimeoutButton( ButtonCode newButton );
+
+ /**
+ * Retrieves the current @ref TimerStyle. @see setTimerStyle
+ */
+ int timerStyle() const;
+
+ /**
+ * Sets the @ref TimerStyle. @see timerStyle
+ */
+ void setTimerStyle( TimerStyle newStyle );
+
+ /**
+ * Overridden function which is used to set the main widget of the dialog.
+ * @see KDialogBase::setMainWidget.
+ */
+ void setMainWidget( QWidget *widget );
+
+ signals:
+ /**
+ * Signal which is emitted once the timer has timed out.
+ */
+ void timerTimeout();
+
+ public slots:
+ /**
+ * Execute the dialog modally - see @see QDialog .
+ */
+ int exec();
+
+ private slots:
+ /**
+ * Updates the dialog with the current progress levels.
+ */
+ void slotUpdateTime( bool update = true );
+
+ /**
+ * The internal
+ */
+ void slotInternalTimeout();
+
+ private:
+ /**
+ * Prepares the layout that manages the widgets of the dialog
+ */
+ void setupLayout();
+
+ QTimer *totalTimer;
+ QTimer *updateTimer;
+ int msecRemaining, updateInterval, msecTotal;
+
+ ButtonCode buttonOnTimeout;
+ TimerStyle tStyle;
+
+ QHBox *timerWidget;
+ QProgressBar *timerProgress;
+ QLabel *timerLabel;
+ QVBox *mainWidget;
+
+ class KTimerDialogPrivate;
+ KTimerDialogPrivate *d;
+};
+
+#endif
+
+
+
diff --git a/krandr/libkrandr.cc b/krandr/libkrandr.cc
new file mode 100644
index 00000000..214e7e7b
--- /dev/null
+++ b/krandr/libkrandr.cc
@@ -0,0 +1,126 @@
+/* libkrandr.cc - class KRandr that makes it easy to use XRandr in KDE
+ This file is part of KRandr 0.9.5
+ Copyright (C) 2010 Timothy Pearson
+ LibKMid's homepage : http://trinity.pearsoncomputing.net
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ Send comments and bug fixes to Timothy Pearson <kb9vqf@pearsoncomputing.net>
+
+***************************************************************************/
+
+#include "libkrandr.h"
+
+ScreenInfo* KRandrSimpleAPI::read_screen_info (Display *display)
+{
+ return read_screen_info(display);
+}
+
+int KRandrSimpleAPI::set_screen_size (ScreenInfo *screen_info)
+{
+ return set_screen_size(screen_info);
+}
+
+void KRandrSimpleAPI::output_auto (ScreenInfo *screen_info, OutputInfo *output_info)
+{
+ output_auto (screen_info, output_info);
+}
+
+void KRandrSimpleAPI::output_off(ScreenInfo *screen_info, OutputInfo *output)
+{
+ output_off(screen_info, output);
+}
+
+CrtcInfo* KRandrSimpleAPI::auto_find_crtc (ScreenInfo *screen_info, OutputInfo *output_info)
+{
+ return auto_find_crtc (screen_info, output_info);
+}
+
+XRRModeInfo *KRandrSimpleAPI::find_mode_by_xid (ScreenInfo *screen_info, RRMode mode_id)
+{
+ return find_mode_by_xid (screen_info, mode_id);
+}
+
+int KRandrSimpleAPI::mode_height (XRRModeInfo *mode_info, Rotation rotation)
+{
+ return mode_height (mode_info, rotation);
+}
+
+int KRandrSimpleAPI::mode_width (XRRModeInfo *mode_info, Rotation rotation)
+{
+ return mode_width (mode_info, rotation);
+}
+
+int KRandrSimpleAPI::get_width_by_output_id (ScreenInfo *screen_info, RROutput output_id)
+{
+ return get_width_by_output_id (screen_info, output_id);
+}
+
+int KRandrSimpleAPI::get_height_by_output_id (ScreenInfo *screen_info, RROutput output_id)
+{
+ return get_height_by_output_id (screen_info, output_id);
+}
+
+char *KRandrSimpleAPI::get_output_name (ScreenInfo *screen_info, RROutput id)
+{
+ return get_output_name (screen_info, id);
+}
+
+Status KRandrSimpleAPI::crtc_apply (CrtcInfo *crtc_info)
+{
+ return crtc_apply (crtc_info);
+}
+
+Status KRandrSimpleAPI::crtc_disable (CrtcInfo *crtc)
+{
+ return crtc_disable (crtc);
+}
+
+int KRandrSimpleAPI::main_low_apply (ScreenInfo *screen_info)
+{
+ return main_low_apply (screen_info);
+}
+
+bool KRandrSimpleAPI::kRandrHasRandr(void)
+{
+ return isValid();
+}
+
+const char *KRandrSimpleAPI::kRandrVersion(void)
+{
+ return "0.9.5";
+}
+
+const char *KRandrSimpleAPI::kRandrCopyright(void)
+{
+ return "LibKRandr 0.9.5 (C)2010 Timothy Pearson <kb9vqf@pearsoncomputing.net>. U.S.A.";
+}
+
+/* * * * * *
+
+ Under this line (------) there's only a C wrapper for the KRandrSimpleAPI class
+
+* * * * * */
+const char *kRandrVersion(void)
+{
+ return KRandrSimpleAPI::kRandrVersion();
+}
+
+const char *kRandrCopyright(void)
+{
+ return KRandrSimpleAPI::kRandrCopyright();
+}
+
diff --git a/krandr/libkrandr.h b/krandr/libkrandr.h
new file mode 100644
index 00000000..e9db64ae
--- /dev/null
+++ b/krandr/libkrandr.h
@@ -0,0 +1,175 @@
+/* libkrandr.h - class KRandr that makes it easy to use XRandr in KDE
+ This file is part of KRandr 0.9.5
+ Copyright (C) 2010 Timothy Pearson
+ LibKMid's homepage : http://trinity.pearsoncomputing.net
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ Send comments and bug fixes to Timothy Pearson <kb9vqf@pearsoncomputing.net>
+
+***************************************************************************/
+#ifndef _LIBKRANDR_H
+#define _LIBKRANDR_H
+
+#include "randr.h"
+#include "lowlevel_randr.h"
+
+#ifdef __cplusplus
+
+#include <kdelibs_export.h>
+
+/**
+ * Simple API covering most of the uses of libkrandr.
+ *
+ * You can use the members of this class in pure C applications, just by using
+ * the same name as the corresponding function member.
+ *
+ * @short A simple API around the rest of libkrandr.
+ * @version 0.9.5 27/04/2010
+ * @author Timothy Pearson <kb9vqf@pearsoncomputing.net>
+ */
+class KRANDR_EXPORT KRandrSimpleAPI : public RandRDisplay
+{
+ private:
+
+ public:
+ /**
+ * Reads current screen information.
+ */
+ ScreenInfo* read_screen_info(Display *display);
+
+ /**
+ * Sets the screen size.
+ */
+ int set_screen_size (ScreenInfo *screen_info);
+
+ /**
+ * Automatically selects an output port.
+ */
+ void output_auto (ScreenInfo *screen_info, OutputInfo *output_info);
+
+ /**
+ * Turns off a specified output on a specified screen.
+ */
+ void output_off(ScreenInfo *screen_info, OutputInfo *output);
+
+ /**
+ * Automatically finds the CRTC structure.
+ */
+ CrtcInfo* auto_find_crtc (ScreenInfo *screen_info, OutputInfo *output_info);
+
+ /**
+ * Finds a mode by XID.
+ */
+ XRRModeInfo *find_mode_by_xid (ScreenInfo *screen_info, RRMode mode_id);
+
+ /**
+ * Returns specified mode height in pixels.
+ */
+ int mode_height (XRRModeInfo *mode_info, Rotation rotation);
+
+ /**
+ * Returns specified mode width in pixels.
+ */
+ int mode_width (XRRModeInfo *mode_info, Rotation rotation);
+
+ /**
+ * Returns specified output width in pixels.
+ */
+ int get_width_by_output_id (ScreenInfo *screen_info, RROutput output_id);
+
+ /**
+ * Returns specified output height in pixels.
+ */
+ int get_height_by_output_id (ScreenInfo *screen_info, RROutput output_id);
+
+ /**
+ * Returns output name.
+ */
+ char *get_output_name (ScreenInfo *screen_info, RROutput id);
+
+ /**
+ * Applies specified CRTC.
+ */
+ Status crtc_apply (CrtcInfo *crtc_info);
+
+ /**
+ * Disables specificed CRTC
+ */
+ Status crtc_disable (CrtcInfo *crtc);
+
+ /**
+ * Applies all previously configured settings to the specified screen.
+ */
+ int main_low_apply (ScreenInfo *screen_info);
+
+ /**
+ * Returns whether or not the system supports XRandR
+ */
+ bool kRandrHasRandr();
+
+ /**
+ * Returns the version number of libkrandr, i.e. "0.9.5" or "1.0 Beta"
+ */
+ static const char *kRandrVersion(void);
+
+ /**
+ * Returns the copyright notice that applications using libkrandr should print
+ * to the user in an about box or somewhere visible.
+ * I.e.
+ *
+ * "LibKRandr 0.9.5 (C) 2010 Timothy Pearson <kb9vqf@pearsoncomputing.net>. U.S.A."
+ */
+ static const char *kRandrCopyright(void);
+
+};
+
+
+
+extern "C" {
+
+#else
+#define KRANDR_EXPORT
+#endif
+
+// KRANDR_EXPORT ScreenInfo* read_screen_info(Display *);
+// KRANDR_EXPORT int set_screen_size (ScreenInfo *screen_info);
+// KRANDR_EXPORT void output_auto (ScreenInfo *screen_info, OutputInfo *output_info);
+// KRANDR_EXPORT void output_off(ScreenInfo *screen_info, OutputInfo *output);
+// KRANDR_EXPORT CrtcInfo* auto_find_crtc (ScreenInfo *screen_info, OutputInfo *output_info);
+// KRANDR_EXPORT XRRModeInfo *find_mode_by_xid (ScreenInfo *screen_info, RRMode mode_id);
+// KRANDR_EXPORT int mode_height (XRRModeInfo *mode_info, Rotation rotation);
+// KRANDR_EXPORT int mode_width (XRRModeInfo *mode_info, Rotation rotation);
+// KRANDR_EXPORT int get_width_by_output_id (ScreenInfo *screen_info, RROutput output_id);
+// KRANDR_EXPORT int get_height_by_output_id (ScreenInfo *screen_info, RROutput output_id);
+// KRANDR_EXPORT char *get_output_name (ScreenInfo *screen_info, RROutput id);
+// KRANDR_EXPORT Status crtc_apply (CrtcInfo *crtc_info);
+// KRANDR_EXPORT Status crtc_disable (CrtcInfo *crtc);
+// KRANDR_EXPORT int main_low_apply (ScreenInfo *screen_info);
+// KRANDR_EXPORT bool kRandrHasRandr();
+
+KRANDR_EXPORT const char *kRandrVersion(void);
+KRANDR_EXPORT const char *kRandrCopyright(void);
+
+#ifdef __cplusplus
+
+}
+
+
+#endif
+
+
+#endif
diff --git a/krandr/lowlevel_randr.c b/krandr/lowlevel_randr.c
new file mode 100644
index 00000000..7f3e890f
--- /dev/null
+++ b/krandr/lowlevel_randr.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright © 2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "lowlevel_randr.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+Status crtc_disable (struct CrtcInfo *crtc);
+
+char * get_output_name (struct ScreenInfo *screen_info, RROutput id)
+{
+ char *output_name = NULL;
+ int i;
+
+ for (i = 0; i < screen_info->n_output; i++) {
+ if (id == screen_info->outputs[i]->id) {
+ output_name = screen_info->outputs[i]->info->name;
+ }
+ }
+
+ if (!output_name) {
+ output_name = "Unknown";
+ }
+
+ return output_name;
+}
+
+XRRModeInfo * find_mode_by_xid (struct ScreenInfo *screen_info, RRMode mode_id)
+{
+ XRRModeInfo *mode_info = NULL;
+ XRRScreenResources *res;
+ int i;
+
+ res = screen_info->res;
+ for (i = 0; i < res->nmode; i++) {
+ if (mode_id == res->modes[i].id) {
+ mode_info = &res->modes[i];
+ break;
+ }
+ }
+
+ return mode_info;
+}
+
+static XRRCrtcInfo * find_crtc_by_xid (struct ScreenInfo *screen_info, RRCrtc crtc_id)
+{
+ XRRCrtcInfo *crtc_info;
+ Display *dpy;
+ XRRScreenResources *res;
+
+ dpy = screen_info->dpy;
+ res = screen_info->res;
+
+ crtc_info = XRRGetCrtcInfo (dpy, res, crtc_id);
+
+ return crtc_info;
+}
+
+int get_width_by_output_id (struct ScreenInfo *screen_info, RROutput output_id)
+{
+ struct OutputInfo *output_info;
+ struct CrtcInfo *crtc_info;
+ RRMode mode_id;
+ XRRModeInfo *mode_info;
+ int i;
+ int width = -1;
+
+ for (i = 0; i < screen_info->n_output; i++) {
+ if (output_id == screen_info->outputs[i]->id) {
+ crtc_info = screen_info->outputs[i]->cur_crtc;
+ if (!crtc_info) {
+ width = 0;
+ break;
+ }
+ mode_id = crtc_info->cur_mode_id;
+ mode_info = find_mode_by_xid (screen_info, mode_id);
+
+ width = mode_width (mode_info, crtc_info->cur_rotation);
+
+ break;
+ }
+ }
+
+ return width;
+}
+
+int get_height_by_output_id (struct ScreenInfo *screen_info, RROutput output_id)
+{
+ struct OutputInfo *output_info;
+ struct CrtcInfo *crtc_info;
+ RRMode mode_id;
+ XRRModeInfo *mode_info;
+ int i;
+ int height = -1;
+
+ for (i = 0; i < screen_info->n_output; i++) {
+ if (output_id == screen_info->outputs[i]->id) {
+ crtc_info = screen_info->outputs[i]->cur_crtc;
+ if (!crtc_info) {
+ height = 0;
+ break;
+ }
+ mode_id = crtc_info->cur_mode_id;
+ mode_info = find_mode_by_xid (screen_info, mode_id);
+
+ height = mode_height (mode_info, crtc_info->cur_rotation);
+
+ break;
+ }
+ }
+
+ return height;
+}
+
+int mode_height (XRRModeInfo *mode_info, Rotation rotation)
+{
+ switch (rotation & 0xf) {
+ case RR_Rotate_0:
+ case RR_Rotate_180:
+ return mode_info->height;
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ return mode_info->width;
+ default:
+ return 0;
+ }
+}
+
+int mode_width (XRRModeInfo *mode_info, Rotation rotation)
+{
+ switch (rotation & 0xf) {
+ case RR_Rotate_0:
+ case RR_Rotate_180:
+ return mode_info->width;
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ return mode_info->height;
+ default:
+ return 0;
+ }
+}
+
+
+static struct CrtcInfo * find_crtc (struct ScreenInfo *screen_info, XRROutputInfo *output)
+{
+ struct CrtcInfo *crtc_info = NULL;
+ int i;
+
+ for (i = 0; i < screen_info->n_crtc; i++) {
+ if (screen_info->crtcs[i]->id == output->crtc) {
+ crtc_info = screen_info->crtcs[i];
+ break;
+ }
+ }
+
+ return crtc_info;
+}
+
+struct CrtcInfo * auto_find_crtc (struct ScreenInfo *screen_info, struct OutputInfo *output_info)
+{
+ struct CrtcInfo *crtc_info = NULL;
+ int i;
+
+ for (i = 0; i < screen_info->n_crtc; i++) {
+ if (0 == screen_info->crtcs[i]->cur_noutput) {
+ crtc_info = screen_info->crtcs[i];
+ break;
+ }
+ }
+
+ if (NULL == crtc_info) {
+ crtc_info = screen_info->crtcs[0];
+ }
+
+ return crtc_info;
+}
+
+int set_screen_size (struct ScreenInfo *screen_info)
+{
+ Display *dpy;
+ int screen;
+ struct CrtcInfo *crtc;
+ XRRModeInfo *mode_info;
+ int cur_x = 0, cur_y = 0;
+ int w = 0, h = 0;
+ int mmW, mmH;
+ int max_width = 0, max_height = 0;
+ int i;
+
+ dpy = screen_info->dpy;
+ screen = DefaultScreen (dpy);
+
+ for (i = 0; i < screen_info->n_crtc; i++) {
+ crtc = screen_info->crtcs[i];
+ if (!crtc->cur_mode_id) {
+ continue;
+ }
+ mode_info = find_mode_by_xid (screen_info, crtc->cur_mode_id);
+ cur_x = crtc->cur_x;
+ cur_y = crtc->cur_y;
+
+ w = mode_width (mode_info, crtc->cur_rotation);
+ h = mode_height (mode_info, crtc->cur_rotation);
+
+ if (cur_x + w > max_width) {
+ max_width = cur_x + w;
+ }
+ if (cur_y + h > max_height) {
+ max_height = cur_y + h;
+ }
+ }
+
+ if (max_width > screen_info->max_width) {
+ #if RANDR_GUI_DEBUG
+ fprintf (stderr, "user set screen width %d, larger than max width %d, set to max width\n",
+ cur_x + w, screen_info->max_width);
+ #endif
+ return 0;
+ } else if (max_width < screen_info->min_width) {
+ screen_info->cur_width = screen_info->min_width;
+ } else {
+ screen_info->cur_width = max_width;
+ }
+
+ if (max_height > screen_info->max_height) {
+ #if RANDR_GUI_DEBUG
+ fprintf (stderr, "user set screen height %d, larger than max height %d, set to max height\n",
+ cur_y + h, screen_info->max_height);
+ #endif
+ return 0;
+ } else if (max_height < screen_info->min_height) {
+ screen_info->cur_height = screen_info->min_height;
+ } else {
+ screen_info->cur_height = max_height;
+ }
+
+ /* calculate mmWidth, mmHeight */
+ if (screen_info->cur_width != DisplayWidth (dpy, screen) ||
+ screen_info->cur_height != DisplayHeight (dpy, screen) ) {
+ double dpi;
+
+ dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen);
+ mmW = (25.4 * screen_info->cur_width) / dpi;
+ mmH = (25.4 * screen_info->cur_height) / dpi;
+ } else {
+ mmW = DisplayWidthMM (dpy, screen);
+ mmH = DisplayHeightMM (dpy, screen);
+ }
+
+ screen_info->cur_mmWidth = mmW;
+ screen_info->cur_mmHeight = mmH;
+
+ return 1;
+}
+
+void screen_apply (struct ScreenInfo *screen_info)
+{
+ int width, height;
+ int mmWidth, mmHeight;
+ Display *dpy, *cur_dpy;
+ Window window;
+ int screen;
+ static int first = 1;
+
+ width = screen_info->cur_width;
+ height = screen_info->cur_height;
+ mmWidth = screen_info->cur_mmWidth;
+ mmHeight = screen_info->cur_mmHeight;
+ dpy = screen_info->dpy;
+ window = screen_info->window;
+ screen = DefaultScreen (dpy);
+
+ cur_dpy = XOpenDisplay (NULL);
+
+ if (width == DisplayWidth (cur_dpy, screen) &&
+ height == DisplayHeight (cur_dpy, screen) &&
+ mmWidth == DisplayWidthMM (cur_dpy, screen) &&
+ mmHeight == DisplayHeightMM (cur_dpy, screen) ) {
+ return;
+ } else {
+ XRRSetScreenSize (dpy, window, width, height, mmWidth, mmHeight);
+ }
+}
+
+Status crtc_apply (struct CrtcInfo *crtc_info)
+{
+ struct ScreenInfo *screen_info;
+ XRRCrtcInfo *rr_crtc_info;
+ Display *dpy;
+ XRRScreenResources *res;
+ RRCrtc crtc_id;
+ int x, y;
+ RRMode mode_id;
+ Rotation rotation;
+ RROutput *outputs;
+ int noutput;
+ Status s;
+ int i;
+
+ /*if (!crtc_info->changed) {
+ return RRSetConfigSuccess;
+ }*/
+
+ screen_info = crtc_info->screen_info;
+ dpy = screen_info->dpy;
+ res = screen_info->res;
+ crtc_id = crtc_info->id;
+ x = crtc_info->cur_x;
+ y = crtc_info->cur_y;
+
+ mode_id = crtc_info->cur_mode_id;
+ rotation = crtc_info->cur_rotation;
+
+ noutput = crtc_info->cur_noutput;
+
+ if (0 == noutput) {
+ return crtc_disable (crtc_info);
+ }
+
+ outputs = malloc (sizeof (RROutput) * noutput);
+ noutput = 0;
+ for (i = 0; i < screen_info->n_output; i++) {
+ struct OutputInfo *output_info = screen_info->outputs[i];
+
+ if (output_info->cur_crtc && crtc_id == output_info->cur_crtc->id) {
+ outputs[noutput++] = output_info->id;
+ }
+ }
+
+
+ s = XRRSetCrtcConfig (dpy, res, crtc_id, CurrentTime,
+ x, y, mode_id, rotation,
+ outputs, noutput);
+
+ if (RRSetConfigSuccess == s) {
+ crtc_info->changed = 0;
+ }
+
+ free (outputs);
+
+ return s;
+}
+
+Status crtc_disable (struct CrtcInfo *crtc)
+{
+ struct ScreenInfo *screen_info;
+
+ screen_info = crtc->screen_info;
+
+ return XRRSetCrtcConfig (screen_info->dpy, screen_info->res, crtc->id, CurrentTime,
+ 0, 0, None, RR_Rotate_0, NULL, 0);
+}
+
+struct ScreenInfo* read_screen_info (Display *display)
+{
+ struct ScreenInfo *screen_info;
+ int screen_num;
+ Window root_window;
+ XRRScreenResources *sr;
+ int i;
+
+ screen_num = DefaultScreen (display);
+ root_window = RootWindow (display, screen_num);
+
+ sr = XRRGetScreenResources (display, root_window);
+
+ screen_info = malloc (sizeof (struct ScreenInfo));
+ screen_info->dpy = display;
+ screen_info->window = root_window;
+ screen_info->res = sr;
+ screen_info->cur_width = DisplayWidth (display, screen_num);
+ screen_info->cur_height = DisplayHeight (display, screen_num);
+ screen_info->cur_mmWidth = DisplayWidthMM (display, screen_num);
+ screen_info->cur_mmHeight = DisplayHeightMM (display, screen_num);
+ screen_info->n_output = sr->noutput;
+ screen_info->n_crtc = sr->ncrtc;
+ screen_info->outputs = malloc (sizeof (struct OutputInfo *) * sr->noutput);
+ screen_info->crtcs = malloc (sizeof (struct CrtcInfo *) * sr->ncrtc);
+ screen_info->clone = 0;
+
+ XRRGetScreenSizeRange (display, root_window, &screen_info->min_width, &screen_info->min_height, &screen_info->max_width, &screen_info->max_height);
+
+ /* get crtc */
+ for (i = 0; i < sr->ncrtc; i++) {
+ struct CrtcInfo *crtc_info;
+ screen_info->crtcs[i] = malloc (sizeof (struct CrtcInfo));
+ crtc_info = screen_info->crtcs[i];
+ XRRCrtcInfo *xrr_crtc_info = XRRGetCrtcInfo (display, sr, sr->crtcs[i]);
+
+ crtc_info->id = sr->crtcs[i];
+ crtc_info->info = xrr_crtc_info;
+ crtc_info->cur_x = xrr_crtc_info->x;
+ crtc_info->cur_y = xrr_crtc_info->y;
+ crtc_info->cur_mode_id = xrr_crtc_info->mode;
+ crtc_info->cur_rotation = xrr_crtc_info->rotation;
+ crtc_info->rotations = xrr_crtc_info->rotations;
+ crtc_info->cur_noutput = xrr_crtc_info->noutput;
+
+ crtc_info->changed = 0;
+ crtc_info->screen_info = screen_info;
+ }
+
+
+ /* get output */
+ for (i = 0; i < sr->noutput; i++) {
+ struct OutputInfo *output;
+ screen_info->outputs[i] = malloc (sizeof (struct OutputInfo));
+ output = screen_info->outputs[i];
+
+ output->id = sr->outputs[i];
+ output->info = XRRGetOutputInfo (display, sr, sr->outputs[i]);
+ output->cur_crtc = find_crtc (screen_info, output->info);
+ output->auto_set = 0;
+ if (output->cur_crtc) {
+ output->off_set = 0;
+ } else {
+ output->off_set = 1;
+ }
+
+ }
+
+ /* set current crtc */
+ screen_info->cur_crtc = screen_info->outputs[0]->cur_crtc;
+ screen_info->primary_crtc = screen_info->cur_crtc;
+ screen_info->cur_output = screen_info->outputs[0];
+
+ return screen_info;
+}
+
+void free_screen_info (struct ScreenInfo *screen_info)
+{
+ free (screen_info->outputs);
+ free (screen_info->crtcs);
+ free (screen_info);
+}
+
+
+
+/*check if other outputs that connected to the same crtc support this mode*/
+static int check_mode (struct ScreenInfo *screen_info, struct OutputInfo *output, RRMode mode_id)
+{
+ XRRCrtcInfo *crtc_info;
+ /* XRR */
+ int i, j;
+ int mode_ok = 1;
+
+ if (!output->cur_crtc) {
+ return 1;
+ }
+
+ crtc_info = output->cur_crtc->info;
+ for (i = 0; i < crtc_info->noutput; i++) {
+ XRROutputInfo *output_info;
+ int nmode;
+
+ if (output->id == crtc_info->outputs[i]) {
+ continue;
+ }
+
+ mode_ok = 0;
+ output_info = XRRGetOutputInfo (screen_info->dpy, screen_info->res, crtc_info->outputs[i]);
+ nmode = output_info->nmode;
+ for (j = 0; j < nmode; j++) {
+ if (mode_id == output_info->modes[j]) {
+ mode_ok = 1;
+ break;
+ }
+ }
+ if (!mode_ok) {
+ break;
+ }
+ }
+
+ return mode_ok;
+}
+
+static RRCrtc get_crtc_id_by_output_id (struct ScreenInfo *screen_info, RROutput output_id)
+{
+ int i;
+ RRCrtc crtc_id = -1;
+
+ for (i = 0; i < screen_info->n_output; i++) {
+ if (output_id == screen_info->outputs[i]->id) {
+ if (screen_info->outputs[i]->cur_crtc) {
+ crtc_id = screen_info->outputs[i]->cur_crtc->id;
+ } else {
+ crtc_id = 0; /* this output is off */
+ }
+ break;
+ }
+ }
+
+ return crtc_id;
+}
+
+static struct CrtcInfo *
+get_crtc_info_by_xid (struct ScreenInfo *screen_info, RRCrtc crtc_id)
+{
+ struct CrtcInfo *crtc_info = NULL;
+ int i;
+
+ for (i = 0; i < screen_info->n_crtc; i++) {
+ if (crtc_id == screen_info->crtcs[i]->id) {
+ crtc_info = screen_info->crtcs[i];
+ break;
+ }
+ }
+
+ return crtc_info;
+}
+
+static XRRModeInfo *
+preferred_mode (struct ScreenInfo *screen_info, struct OutputInfo *output)
+{
+ XRROutputInfo *output_info = output->info;
+ Display *dpy;
+ int screen;
+ int m;
+ XRRModeInfo *best;
+ int bestDist;
+
+ dpy = screen_info->dpy;
+ screen = DefaultScreen (dpy);
+ best = NULL;
+ bestDist = 0;
+ for (m = 0; m < output_info->nmode; m++) {
+ XRRModeInfo *mode_info = find_mode_by_xid (screen_info, output_info->modes[m]);
+ int dist;
+
+ if (m < output_info->npreferred)
+ dist = 0;
+ else if (output_info->mm_height)
+ dist = (1000 * DisplayHeight(dpy, screen) / DisplayHeightMM(dpy, screen) -
+ 1000 * mode_info->height / output_info->mm_height);
+ else
+ dist = DisplayHeight(dpy, screen) - mode_info->height;
+
+ if (dist < 0) dist = -dist;
+ if (!best || dist < bestDist) {
+ best = mode_info;
+ bestDist = dist;
+ }
+ }
+ return best;
+}
+
+int main_low_apply (struct ScreenInfo *screen_info)
+{
+ int i;
+ struct CrtcInfo *crtc_info;
+
+ /* set_positions (screen_info); */
+
+ if (!set_screen_size (screen_info)) {
+ printf("Screen Size FAILURE\n\r");
+ return 0;
+ }
+
+ for (i = 0; i < screen_info->n_crtc; i++) {
+ int old_x, old_y, old_w, old_h;
+
+ XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (screen_info->dpy, screen_info->res, screen_info->crtcs[i]->id);
+ XRRModeInfo *old_mode = find_mode_by_xid (screen_info, crtc_info->mode);
+
+ if (crtc_info->mode == None) {
+ continue;
+ }
+
+ old_x = crtc_info->x;
+ old_y = crtc_info->y;
+ old_w = mode_width (old_mode, crtc_info->rotation);
+ old_h = mode_height (old_mode, crtc_info->rotation);
+
+ if (old_x + old_w <= screen_info->cur_width &&
+ old_y + old_h <= screen_info->cur_height ) {
+ continue;
+ } else {
+ crtc_disable (screen_info->crtcs[i]);
+ }
+ }
+
+ screen_apply (screen_info);
+
+ for (i = 0; i < screen_info->n_crtc; i++) {
+ Status s;
+ crtc_info = screen_info->crtcs[i];
+
+ s = crtc_apply (crtc_info);
+ if (RRSetConfigSuccess != s) {
+ fprintf (stderr, "crtc apply error\n");
+ }
+ }
+
+ return 1;
+}
+
+void output_auto (struct ScreenInfo *screen_info, struct OutputInfo *output_info)
+{
+ XRRModeInfo *mode_info;
+ RRMode mode_id;
+ struct CrtcInfo *crtc_info;
+ XRROutputInfo *probe_output_info;
+
+ if (RR_Disconnected == output_info->info->connection) {
+ XRRScreenResources *cur_res;
+
+ cur_res = XRRGetScreenResources (screen_info->dpy, screen_info->window);
+ probe_output_info = XRRGetOutputInfo (screen_info->dpy, cur_res, output_info->id);
+ if (RR_Disconnected != probe_output_info->connection) {
+ output_info->info = probe_output_info;
+ output_info->cur_crtc = auto_find_crtc (screen_info, output_info);
+ }
+ }
+
+ mode_info = preferred_mode (screen_info, output_info);
+ if (!mode_info) {
+ return;
+ }
+ mode_id = mode_info->id;
+
+ crtc_info = output_info->cur_crtc;
+ if (crtc_info) {
+ crtc_info->cur_mode_id = mode_id;
+ } else {
+ crtc_info = auto_find_crtc (screen_info, output_info);
+ if (!crtc_info) {
+#if RANDR_GUI_DEBUG
+ fprintf (stderr, "Can not find usable CRTC\n");
+#endif
+ return;
+ } else {
+ screen_info->cur_output->cur_crtc = crtc_info;
+ screen_info->cur_crtc = crtc_info;
+ screen_info->cur_crtc->cur_noutput++;
+ fprintf (stderr, "n output: %d\n", screen_info->cur_crtc->cur_noutput);
+ screen_info->cur_crtc->cur_mode_id = mode_id;
+ screen_info->cur_crtc->changed = 1;
+ }
+ }
+
+}
+
+void output_off (struct ScreenInfo *screen_info, struct OutputInfo *output)
+{
+ if (output->cur_crtc) {
+ output->cur_crtc->cur_noutput--;
+ }
+ output->cur_crtc = NULL;
+ screen_info->cur_crtc = NULL;
+ output->off_set = 1;
+}
diff --git a/krandr/lowlevel_randr.h b/krandr/lowlevel_randr.h
new file mode 100644
index 00000000..a9a51912
--- /dev/null
+++ b/krandr/lowlevel_randr.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xrandr.h>
+
+struct ScreenInfo;
+
+struct CrtcInfo {
+ RRCrtc id;
+ XRRCrtcInfo *info;
+ int cur_x;
+ int cur_y;
+ RRMode cur_mode_id;
+ Rotation cur_rotation;
+ Rotation rotations;
+ int cur_noutput;
+
+ int changed;
+
+ struct ScreenInfo *screen_info;
+};
+
+struct OutputInfo {
+ RROutput id;
+ XRROutputInfo *info;
+ struct CrtcInfo *cur_crtc;
+
+ int auto_set;
+ int off_set;
+};
+
+struct ScreenInfo {
+ Display *dpy;
+ Window window;
+ XRRScreenResources *res;
+ int min_width, min_height;
+ int max_width, max_height;
+ int cur_width;
+ int cur_height;
+ int cur_mmWidth;
+ int cur_mmHeight;
+
+ int n_output;
+ int n_crtc;
+ struct OutputInfo **outputs;
+ struct CrtcInfo **crtcs;
+
+ int clone;
+ struct CrtcInfo *primary_crtc;
+
+ struct CrtcInfo *cur_crtc;
+ struct OutputInfo *cur_output;
+};
+
+extern struct ScreenInfo *screen_info;
+extern const uint big_pixbuf[], small_pixbuf[];
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void free_screen_info (struct ScreenInfo *screen_info);
+
+struct ScreenInfo* read_screen_info (Display *);
+
+int set_screen_size (struct ScreenInfo *screen_info);
+void output_auto (struct ScreenInfo *screen_info, struct OutputInfo *output_info);
+void output_off (struct ScreenInfo *screen_info, struct OutputInfo *output);
+struct CrtcInfo* auto_find_crtc (struct ScreenInfo *screen_info, struct OutputInfo *output_info);
+
+XRRModeInfo *find_mode_by_xid (struct ScreenInfo *screen_info, RRMode mode_id);
+int mode_height (XRRModeInfo *mode_info, Rotation rotation);
+int mode_width (XRRModeInfo *mode_info, Rotation rotation);
+int get_width_by_output_id (struct ScreenInfo *screen_info, RROutput output_id);
+int get_height_by_output_id (struct ScreenInfo *screen_info, RROutput output_id);
+char *get_output_name (struct ScreenInfo *screen_info, RROutput id);
+Status crtc_apply (struct CrtcInfo *crtc_info);
+Status crtc_disable (struct CrtcInfo *crtc);
+int main_low_apply (struct ScreenInfo *screen_info);
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/krandr/randr.cpp b/krandr/randr.cpp
new file mode 100644
index 00000000..63c5c045
--- /dev/null
+++ b/krandr/randr.cpp
@@ -0,0 +1,703 @@
+/*
+ * Copyright (c) 2002,2003 Hamish Rodda <rodda@kde.org>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "randr.h"
+
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <dcopclient.h>
+#include <kipc.h>
+#include <kactivelabel.h>
+
+#include "ktimerdialog.h"
+
+#include <X11/Xlib.h>
+#define INT8 _X11INT8
+#define INT32 _X11INT32
+#include <X11/Xproto.h>
+#undef INT8
+#undef INT32
+#include <X11/extensions/Xrandr.h>
+
+class RandRScreenPrivate
+{
+public:
+ RandRScreenPrivate() : config(0L) {};
+ ~RandRScreenPrivate()
+ {
+ if (config)
+ XRRFreeScreenConfigInfo(config);
+ }
+
+ XRRScreenConfiguration* config;
+};
+
+RandRScreen::RandRScreen(int screenIndex)
+ : d(new RandRScreenPrivate())
+ , m_screen(screenIndex)
+ , m_shownDialog(NULL)
+{
+ loadSettings();
+ setOriginal();
+}
+
+RandRScreen::~RandRScreen()
+{
+ delete d;
+}
+
+void RandRScreen::loadSettings()
+{
+ if (d->config)
+ XRRFreeScreenConfigInfo(d->config);
+
+ d->config = XRRGetScreenInfo(qt_xdisplay(), RootWindow(qt_xdisplay(), m_screen));
+ Q_ASSERT(d->config);
+
+ Rotation rotation;
+ m_currentSize = m_proposedSize = XRRConfigCurrentConfiguration(d->config, &rotation);
+ m_currentRotation = m_proposedRotation = rotation;
+
+ m_pixelSizes.clear();
+ m_mmSizes.clear();
+ int numSizes;
+ XRRScreenSize* sizes = XRRSizes(qt_xdisplay(), m_screen, &numSizes);
+ for (int i = 0; i < numSizes; i++) {
+ m_pixelSizes.append(QSize(sizes[i].width, sizes[i].height));
+ m_mmSizes.append(QSize(sizes[i].mwidth, sizes[i].mheight));
+ }
+
+ m_rotations = XRRRotations(qt_xdisplay(), m_screen, &rotation);
+
+ m_currentRefreshRate = m_proposedRefreshRate = refreshRateHzToIndex(m_currentSize, XRRConfigCurrentRate(d->config));
+}
+
+void RandRScreen::setOriginal()
+{
+ m_originalSize = m_currentSize;
+ m_originalRotation = m_currentRotation;
+ m_originalRefreshRate = m_currentRefreshRate;
+}
+
+bool RandRScreen::applyProposed()
+{
+ //kdDebug() << k_funcinfo << " size " << (SizeID)proposedSize() << ", rotation " << proposedRotation() << ", refresh " << refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) << endl;
+
+ Status status;
+
+ if (proposedRefreshRate() < 0)
+ status = XRRSetScreenConfig(qt_xdisplay(), d->config, DefaultRootWindow(qt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), CurrentTime);
+ else {
+ if( refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) <= 0 ) {
+ m_proposedRefreshRate = 0;
+ }
+ status = XRRSetScreenConfigAndRate(qt_xdisplay(), d->config, DefaultRootWindow(qt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), refreshRateIndexToHz(proposedSize(), proposedRefreshRate()), CurrentTime);
+ }
+
+ //kdDebug() << "New size: " << WidthOfScreen(ScreenOfDisplay(QPaintDevice::x11AppDisplay(), screen)) << ", " << HeightOfScreen(ScreenOfDisplay(QPaintDevice::x11AppDisplay(), screen)) << endl;
+
+ if (status == RRSetConfigSuccess) {
+ m_currentSize = m_proposedSize;
+ m_currentRotation = m_proposedRotation;
+ m_currentRefreshRate = m_proposedRefreshRate;
+ return true;
+ }
+
+ return false;
+}
+
+bool RandRScreen::applyProposedAndConfirm()
+{
+ if (proposedChanged()) {
+ setOriginal();
+
+ if (applyProposed()) {
+ if (!confirm()) {
+ proposeOriginal();
+ applyProposed();
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool RandRScreen::confirm()
+{
+ // uncomment the line below and edit out the KTimerDialog stuff to get
+ // a version which works on today's kdelibs (no accept dialog is presented)
+
+ // FIXME remember to put the dialog on the right screen
+
+ KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown,
+ KApplication::kApplication()->mainWidget(),
+ "mainKTimerDialog",
+ true,
+ i18n("Confirm Display Setting Change"),
+ KTimerDialog::Ok|KTimerDialog::Cancel,
+ KTimerDialog::Cancel);
+
+ acceptDialog.setButtonOK(KGuiItem(i18n("&Accept Configuration"), "button_ok"));
+ acceptDialog.setButtonCancel(KGuiItem(i18n("&Return to Previous Configuration"), "button_cancel"));
+
+ KActiveLabel *label = new KActiveLabel(i18n("Your screen orientation, size and refresh rate "
+ "have been changed to the requested settings. Please indicate whether you wish to "
+ "keep this configuration. In 15 seconds the display will revert to your previous "
+ "settings."), &acceptDialog, "userSpecifiedLabel");
+
+ acceptDialog.setMainWidget(label);
+
+ KDialog::centerOnScreen(&acceptDialog, m_screen);
+
+ m_shownDialog = &acceptDialog;
+ connect( m_shownDialog, SIGNAL( destroyed()), this, SLOT( shownDialogDestroyed()));
+ connect( kapp->desktop(), SIGNAL( resized(int)), this, SLOT( desktopResized()));
+
+ return acceptDialog.exec();
+}
+
+void RandRScreen::shownDialogDestroyed()
+{
+ m_shownDialog = NULL;
+ disconnect( kapp->desktop(), SIGNAL( resized(int)), this, SLOT( desktopResized()));
+}
+
+void RandRScreen::desktopResized()
+{
+ if( m_shownDialog != NULL )
+ KDialog::centerOnScreen(m_shownDialog, m_screen);
+}
+
+QString RandRScreen::changedMessage() const
+{
+ if (currentRefreshRate() == -1)
+ return i18n("New configuration:\nResolution: %1 x %2\nOrientation: %3")
+ .arg(currentPixelWidth())
+ .arg(currentPixelHeight())
+ .arg(currentRotationDescription());
+ else
+ return i18n("New configuration:\nResolution: %1 x %2\nOrientation: %3\nRefresh rate: %4")
+ .arg(currentPixelWidth())
+ .arg(currentPixelHeight())
+ .arg(currentRotationDescription())
+ .arg(currentRefreshRateDescription());
+}
+
+bool RandRScreen::changedFromOriginal() const
+{
+ return m_currentSize != m_originalSize || m_currentRotation != m_originalRotation || m_currentRefreshRate != m_originalRefreshRate;
+}
+
+void RandRScreen::proposeOriginal()
+{
+ m_proposedSize = m_originalSize;
+ m_proposedRotation = m_originalRotation;
+ m_proposedRefreshRate = m_originalRefreshRate;
+}
+
+bool RandRScreen::proposedChanged() const
+{
+ return m_currentSize != m_proposedSize || m_currentRotation != m_proposedRotation || m_currentRefreshRate != m_proposedRefreshRate;
+}
+
+QString RandRScreen::rotationName(int rotation, bool pastTense, bool capitalised)
+{
+ if (!pastTense)
+ switch (rotation) {
+ case RR_Rotate_0:
+ return i18n("Normal");
+ case RR_Rotate_90:
+ return i18n("Left (90 degrees)");
+ case RR_Rotate_180:
+ return i18n("Upside-down (180 degrees)");
+ case RR_Rotate_270:
+ return i18n("Right (270 degrees)");
+ case RR_Reflect_X:
+ return i18n("Mirror horizontally");
+ case RR_Reflect_Y:
+ return i18n("Mirror vertically");
+ default:
+ return i18n("Unknown orientation");
+ }
+
+ switch (rotation) {
+ case RR_Rotate_0:
+ return i18n("Normal");
+ case RR_Rotate_90:
+ return i18n("Rotated 90 degrees counterclockwise");
+ case RR_Rotate_180:
+ return i18n("Rotated 180 degrees counterclockwise");
+ case RR_Rotate_270:
+ return i18n("Rotated 270 degrees counterclockwise");
+ default:
+ if (rotation & RR_Reflect_X)
+ if (rotation & RR_Reflect_Y)
+ if (capitalised)
+ return i18n("Mirrored horizontally and vertically");
+ else
+ return i18n("mirrored horizontally and vertically");
+ else
+ if (capitalised)
+ return i18n("Mirrored horizontally");
+ else
+ return i18n("mirrored horizontally");
+ else if (rotation & RR_Reflect_Y)
+ if (capitalised)
+ return i18n("Mirrored vertically");
+ else
+ return i18n("mirrored vertically");
+ else
+ if (capitalised)
+ return i18n("Unknown orientation");
+ else
+ return i18n("unknown orientation");
+ }
+}
+
+QPixmap RandRScreen::rotationIcon(int rotation) const
+{
+ // Adjust icons for current screen orientation
+ if (!(m_currentRotation & RR_Rotate_0) && rotation & (RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270)) {
+ int currentAngle = m_currentRotation & (RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270);
+ switch (currentAngle) {
+ case RR_Rotate_90:
+ rotation <<= 3;
+ break;
+ case RR_Rotate_180:
+ rotation <<= 2;
+ break;
+ case RR_Rotate_270:
+ rotation <<= 1;
+ break;
+ }
+
+ // Fix overflow
+ if (rotation > RR_Rotate_270) {
+ rotation >>= 4;
+ }
+ }
+
+ switch (rotation) {
+ case RR_Rotate_0:
+ return SmallIcon("up");
+ case RR_Rotate_90:
+ return SmallIcon("back");
+ case RR_Rotate_180:
+ return SmallIcon("down");
+ case RR_Rotate_270:
+ return SmallIcon("forward");
+ case RR_Reflect_X:
+ case RR_Reflect_Y:
+ default:
+ return SmallIcon("stop");
+ }
+}
+
+QString RandRScreen::currentRotationDescription() const
+{
+ QString ret = rotationName(m_currentRotation & RotateMask);
+
+ if (m_currentRotation != m_currentRotation & RotateMask)
+ if (m_currentRotation & RR_Rotate_0)
+ ret = rotationName(m_currentRotation & (RR_Reflect_X + RR_Reflect_X), true, true);
+ else
+ ret += ", " + rotationName(m_currentRotation & (RR_Reflect_X + RR_Reflect_X), true, false);
+
+ return ret;
+}
+
+int RandRScreen::rotationIndexToDegree(int rotation) const
+{
+ switch (rotation & RotateMask) {
+ case RR_Rotate_90:
+ return 90;
+
+ case RR_Rotate_180:
+ return 180;
+
+ case RR_Rotate_270:
+ return 270;
+
+ default:
+ return 0;
+ }
+}
+
+int RandRScreen::rotationDegreeToIndex(int degree) const
+{
+ switch (degree) {
+ case 90:
+ return RR_Rotate_90;
+
+ case 180:
+ return RR_Rotate_180;
+
+ case 270:
+ return RR_Rotate_270;
+
+ default:
+ return RR_Rotate_0;
+ }
+}
+
+int RandRScreen::currentPixelWidth() const
+{
+ return m_pixelSizes[m_currentSize].width();
+}
+
+int RandRScreen::currentPixelHeight() const
+{
+ return m_pixelSizes[m_currentSize].height();
+}
+
+int RandRScreen::currentMMWidth() const
+{
+ return m_pixelSizes[m_currentSize].width();
+}
+
+int RandRScreen::currentMMHeight() const
+{
+ return m_pixelSizes[m_currentSize].height();
+}
+
+QStringList RandRScreen::refreshRates(int size) const
+{
+ int nrates;
+ short* rates = XRRRates(qt_xdisplay(), m_screen, (SizeID)size, &nrates);
+
+ QStringList ret;
+ for (int i = 0; i < nrates; i++)
+ ret << refreshRateDirectDescription(rates[i]);
+
+ return ret;
+}
+
+QString RandRScreen::refreshRateDirectDescription(int rate) const
+{
+ return i18n("Refresh rate in Hertz (Hz)", "%1 Hz").arg(rate);
+}
+
+QString RandRScreen::refreshRateIndirectDescription(int size, int index) const
+{
+ return i18n("Refresh rate in Hertz (Hz)", "%1 Hz").arg(refreshRateIndexToHz(size, index));
+}
+
+QString RandRScreen::refreshRateDescription(int size, int index) const
+{
+ return refreshRates(size)[index];
+}
+
+bool RandRScreen::proposeRefreshRate(int index)
+{
+ if (index >= 0 && (int)refreshRates(proposedSize()).count() > index) {
+ m_proposedRefreshRate = index;
+ return true;
+ }
+
+ return false;
+}
+
+int RandRScreen::currentRefreshRate() const
+{
+ return m_currentRefreshRate;
+}
+
+QString RandRScreen::currentRefreshRateDescription() const
+{
+ return refreshRateIndirectDescription(m_currentSize, m_currentRefreshRate);
+}
+
+int RandRScreen::proposedRefreshRate() const
+{
+ return m_proposedRefreshRate;
+}
+
+int RandRScreen::refreshRateHzToIndex(int size, int hz) const
+{
+ int nrates;
+ short* rates = XRRRates(qt_xdisplay(), m_screen, (SizeID)size, &nrates);
+
+ for (int i = 0; i < nrates; i++)
+ if (hz == rates[i])
+ return i;
+
+ if (nrates != 0)
+ // Wrong input Hz!
+ Q_ASSERT(false);
+
+ return -1;
+}
+
+int RandRScreen::refreshRateIndexToHz(int size, int index) const
+{
+ int nrates;
+ short* rates = XRRRates(qt_xdisplay(), m_screen, (SizeID)size, &nrates);
+
+ if (nrates == 0 || index < 0)
+ return 0;
+
+ // Wrong input Hz!
+ if(index >= nrates)
+ return 0;
+
+ return rates[index];
+}
+
+int RandRScreen::numSizes() const
+{
+ return m_pixelSizes.count();
+}
+
+const QSize& RandRScreen::pixelSize(int index) const
+{
+ return m_pixelSizes[index];
+}
+
+const QSize& RandRScreen::mmSize(int index) const
+{
+ return m_mmSizes[index];
+}
+
+int RandRScreen::sizeIndex(QSize pixelSize) const
+{
+ for (uint i = 0; i < m_pixelSizes.count(); i++)
+ if (m_pixelSizes[i] == pixelSize)
+ return i;
+
+ return -1;
+}
+
+int RandRScreen::rotations() const
+{
+ return m_rotations;
+}
+
+int RandRScreen::currentRotation() const
+{
+ return m_currentRotation;
+}
+
+int RandRScreen::currentSize() const
+{
+ return m_currentSize;
+}
+
+int RandRScreen::proposedRotation() const
+{
+ return m_proposedRotation;
+}
+
+void RandRScreen::proposeRotation(int newRotation)
+{
+ m_proposedRotation = newRotation & OrientationMask;
+}
+
+int RandRScreen::proposedSize() const
+{
+ return m_proposedSize;
+}
+
+bool RandRScreen::proposeSize(int newSize)
+{
+ if ((int)m_pixelSizes.count() > newSize) {
+ m_proposedSize = newSize;
+ return true;
+ }
+
+ return false;
+}
+
+void RandRScreen::load(KConfig& config)
+{
+ config.setGroup(QString("Screen%1").arg(m_screen));
+
+ if (proposeSize(sizeIndex(QSize(config.readNumEntry("width", currentPixelWidth()), config.readNumEntry("height", currentPixelHeight())))))
+ proposeRefreshRate(refreshRateHzToIndex(proposedSize(), config.readNumEntry("refresh", currentRefreshRate())));
+
+ proposeRotation(rotationDegreeToIndex(config.readNumEntry("rotation", 0)) + (config.readBoolEntry("reflectX") ? ReflectX : 0) + (config.readBoolEntry("reflectY") ? ReflectY : 0));
+}
+
+void RandRScreen::save(KConfig& config) const
+{
+ config.setGroup(QString("Screen%1").arg(m_screen));
+ config.writeEntry("width", currentPixelWidth());
+ config.writeEntry("height", currentPixelHeight());
+ config.writeEntry("refresh", refreshRateIndexToHz(currentSize(), currentRefreshRate()));
+ config.writeEntry("rotation", rotationIndexToDegree(currentRotation()));
+ config.writeEntry("reflectX", (bool)(currentRotation() & ReflectMask) == ReflectX);
+ config.writeEntry("reflectY", (bool)(currentRotation() & ReflectMask) == ReflectY);
+}
+
+RandRDisplay::RandRDisplay()
+ : m_valid(true)
+{
+ // Check extension
+ Status s = XRRQueryExtension(qt_xdisplay(), &m_eventBase, &m_errorBase);
+ if (!s) {
+ m_errorCode = QString("%1, base %1").arg(s).arg(m_errorBase);
+ m_valid = false;
+ return;
+ }
+
+ int major_version, minor_version;
+ XRRQueryVersion(qt_xdisplay(), &major_version, &minor_version);
+
+ m_version = QString("X Resize and Rotate extension version %1.%1").arg(major_version).arg(minor_version);
+
+ m_numScreens = ScreenCount(qt_xdisplay());
+
+ // This assumption is WRONG with Xinerama
+ // Q_ASSERT(QApplication::desktop()->numScreens() == ScreenCount(qt_xdisplay()));
+
+ m_screens.setAutoDelete(true);
+ for (int i = 0; i < m_numScreens; i++) {
+ m_screens.append(new RandRScreen(i));
+ }
+
+ setCurrentScreen(QApplication::desktop()->primaryScreen());
+}
+
+bool RandRDisplay::isValid() const
+{
+ return m_valid;
+}
+
+const QString& RandRDisplay::errorCode() const
+{
+ return m_errorCode;
+}
+
+int RandRDisplay::eventBase() const
+{
+ return m_eventBase;
+}
+
+int RandRDisplay::screenChangeNotifyEvent() const
+{
+ return m_eventBase + RRScreenChangeNotify;
+}
+
+int RandRDisplay::errorBase() const
+{
+ return m_errorBase;
+}
+
+const QString& RandRDisplay::version() const
+{
+ return m_version;
+}
+
+void RandRDisplay::setCurrentScreen(int index)
+{
+ m_currentScreenIndex = index;
+ m_currentScreen = m_screens.at(m_currentScreenIndex);
+ Q_ASSERT(m_currentScreen);
+}
+
+int RandRDisplay::screenIndexOfWidget(QWidget* widget)
+{
+ int ret = QApplication::desktop()->screenNumber(widget);
+ return ret != -1 ? ret : QApplication::desktop()->primaryScreen();
+}
+
+int RandRDisplay::currentScreenIndex() const
+{
+ return m_currentScreenIndex;
+}
+
+void RandRDisplay::refresh()
+{
+ for (RandRScreen* s = m_screens.first(); s; s = m_screens.next())
+ s->loadSettings();
+}
+
+int RandRDisplay::numScreens() const
+{
+ return m_numScreens;
+}
+
+RandRScreen* RandRDisplay::screen(int index)
+{
+ return m_screens.at(index);
+}
+
+RandRScreen* RandRDisplay::currentScreen()
+{
+ return m_currentScreen;
+}
+
+bool RandRDisplay::loadDisplay(KConfig& config, bool loadScreens)
+{
+ if (loadScreens)
+ for (RandRScreen* s = m_screens.first(); s; s = m_screens.next())
+ s->load(config);
+
+ return applyOnStartup(config);
+}
+
+bool RandRDisplay::applyOnStartup(KConfig& config)
+{
+ config.setGroup("Display");
+ return config.readBoolEntry("ApplyOnStartup", false);
+}
+
+bool RandRDisplay::syncTrayApp(KConfig& config)
+{
+ config.setGroup("Display");
+ return config.readBoolEntry("SyncTrayApp", false);
+}
+
+void RandRDisplay::saveDisplay(KConfig& config, bool applyOnStartup, bool syncTrayApp)
+{
+ Q_ASSERT(!config.isReadOnly());
+
+ config.setGroup("Display");
+ config.writeEntry("ApplyOnStartup", applyOnStartup);
+ config.writeEntry("SyncTrayApp", syncTrayApp);
+
+ for (RandRScreen* s = m_screens.first(); s; s = m_screens.next())
+ s->save(config);
+}
+
+void RandRDisplay::applyProposed(bool confirm)
+{
+ for (int screenIndex = 0; screenIndex < numScreens(); screenIndex++) {
+ if (screen(screenIndex)->proposedChanged()) {
+ if (confirm)
+ screen(screenIndex)->applyProposedAndConfirm();
+ else
+ screen(screenIndex)->applyProposed();
+ }
+ }
+}
+
+int RandRScreen::pixelCount( int index ) const
+{
+ QSize sz = pixelSize(index);
+ return sz.width() * sz.height();
+}
+
+#include "randr.moc"
diff --git a/krandr/randr.h b/krandr/randr.h
new file mode 100644
index 00000000..c7eb240c
--- /dev/null
+++ b/krandr/randr.h
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2002,2003 Hamish Rodda <rodda@kde.org>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __RANDR_H__
+#define __RANDR_H__
+
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+
+#include <kcmodule.h>
+#include <kconfig.h>
+
+class KTimerDialog;
+class RandRScreenPrivate;
+
+class RandRScreen : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum orientations {
+ Rotate0 = 0x1,
+ Rotate90 = 0x2,
+ Rotate180 = 0x4,
+ Rotate270 = 0x8,
+ RotateMask = 15,
+ RotationCount = 4,
+ ReflectX = 0x10,
+ ReflectY = 0x20,
+ ReflectMask = 48,
+ OrientationMask = 63,
+ OrientationCount = 6
+ };
+
+ RandRScreen(int screenIndex);
+ ~RandRScreen();
+
+ void loadSettings();
+ void setOriginal();
+
+ bool applyProposed();
+
+ /**
+ * @returns false if the user did not confirm in time, or cancelled, or the change failed
+ */
+ bool applyProposedAndConfirm();
+
+public slots:
+ bool confirm();
+
+public:
+ QString changedMessage() const;
+
+ bool changedFromOriginal() const;
+ void proposeOriginal();
+
+ bool proposedChanged() const;
+
+ static QString rotationName(int rotation, bool pastTense = false, bool capitalised = true);
+ QPixmap rotationIcon(int rotation) const;
+ QString currentRotationDescription() const;
+
+ int rotationIndexToDegree(int rotation) const;
+ int rotationDegreeToIndex(int degree) const;
+
+ /**
+ * Refresh rate functions.
+ */
+ QStringList refreshRates(int size) const;
+
+ QString refreshRateDirectDescription(int rate) const;
+ QString refreshRateIndirectDescription(int size, int index) const;
+ QString refreshRateDescription(int size, int index) const;
+
+ int currentRefreshRate() const;
+ QString currentRefreshRateDescription() const;
+
+ // Refresh rate hz <==> index conversion
+ int refreshRateHzToIndex(int size, int hz) const;
+ int refreshRateIndexToHz(int size, int index) const;
+
+ /**
+ * Screen size functions.
+ */
+ int numSizes() const;
+ const QSize& pixelSize(int index) const;
+ const QSize& mmSize(int index) const;
+ int pixelCount(int index) const;
+
+ /**
+ * Retrieve the index of a screen size with a specified pixel size.
+ *
+ * @param pixelSize dimensions of the screen in pixels
+ * @returns the index of the requested screen size
+ */
+ int sizeIndex(QSize pixelSize) const;
+
+ int rotations() const;
+
+ /**
+ * Current setting functions.
+ */
+ int currentPixelWidth() const;
+ int currentPixelHeight() const;
+ int currentMMWidth() const;
+ int currentMMHeight() const;
+
+ int currentRotation() const;
+ int currentSize() const;
+
+ /**
+ * Proposed setting functions.
+ */
+ int proposedSize() const;
+ bool proposeSize(int newSize);
+
+ int proposedRotation() const;
+ void proposeRotation(int newRotation);
+
+ int proposedRefreshRate() const;
+ /**
+ * Propose a refresh rate.
+ * Please note that you must propose the target size first for this to work.
+ *
+ * @param index the index of the refresh rate (not a refresh rate in hz!)
+ * @returns true if successful, false otherwise.
+ */
+ bool proposeRefreshRate(int index);
+
+ /**
+ * Configuration functions.
+ */
+ void load(KConfig& config);
+ void save(KConfig& config) const;
+
+private:
+ RandRScreenPrivate* d;
+
+ int m_screen;
+
+ QValueList<QSize> m_pixelSizes;
+ QValueList<QSize> m_mmSizes;
+ int m_rotations;
+
+ int m_originalRotation;
+ int m_originalSize;
+ int m_originalRefreshRate;
+
+ int m_currentRotation;
+ int m_currentSize;
+ int m_currentRefreshRate;
+
+ int m_proposedRotation;
+ int m_proposedSize;
+ int m_proposedRefreshRate;
+
+ KTimerDialog* m_shownDialog;
+
+private slots:
+ void desktopResized();
+ void shownDialogDestroyed();
+};
+
+typedef QPtrList<RandRScreen> ScreenList;
+
+class RandRDisplay
+{
+public:
+ RandRDisplay();
+
+ bool isValid() const;
+ const QString& errorCode() const;
+ const QString& version() const;
+
+ int eventBase() const;
+ int screenChangeNotifyEvent() const;
+ int errorBase() const;
+
+ int screenIndexOfWidget(QWidget* widget);
+
+ int numScreens() const;
+ RandRScreen* screen(int index);
+
+ void setCurrentScreen(int index);
+ int currentScreenIndex() const;
+ RandRScreen* currentScreen();
+
+ void refresh();
+
+ /**
+ * Loads saved settings.
+ *
+ * @param config the KConfig object to load from
+ * @param loadScreens whether to call RandRScreen::load() for each screen
+ * @retuns true if the settings should be applied on KDE startup.
+ */
+ bool loadDisplay(KConfig& config, bool loadScreens = true);
+ void saveDisplay(KConfig& config, bool applyOnStartup, bool syncTrayApp);
+
+ static bool applyOnStartup(KConfig& config);
+ static bool syncTrayApp(KConfig& config);
+
+ void applyProposed(bool confirm = true);
+
+private:
+ int m_numScreens;
+ int m_currentScreenIndex;
+ RandRScreen* m_currentScreen;
+ ScreenList m_screens;
+
+ bool m_valid;
+ QString m_errorCode;
+ QString m_version;
+
+ int m_eventBase;
+ int m_errorBase;
+};
+
+#endif