summaryrefslogtreecommitdiffstats
path: root/tderandr
diff options
context:
space:
mode:
Diffstat (limited to 'tderandr')
-rw-r--r--tderandr/CMakeLists.txt48
-rw-r--r--tderandr/Mainpage.dox18
-rw-r--r--tderandr/Makefile.am19
-rw-r--r--tderandr/configure.in.in21
-rw-r--r--tderandr/ktimerdialog.cpp205
-rw-r--r--tderandr/ktimerdialog.h170
-rw-r--r--tderandr/libtderandr.cc1634
-rw-r--r--tderandr/libtderandr.h359
-rw-r--r--tderandr/lowlevel_randr.c680
-rw-r--r--tderandr/lowlevel_randr.h103
-rw-r--r--tderandr/randr.cpp881
-rw-r--r--tderandr/randr.h302
12 files changed, 4440 insertions, 0 deletions
diff --git a/tderandr/CMakeLists.txt b/tderandr/CMakeLists.txt
new file mode 100644
index 000000000..efcd8519d
--- /dev/null
+++ b/tderandr/CMakeLists.txt
@@ -0,0 +1,48 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${XRANDR_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/dcop
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeui
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+ ${XRANDR_LIBRARY_DIRS}
+)
+
+
+##### headers ###################################
+
+install( FILES
+ randr.h lowlevel_randr.h ktimerdialog.h libtderandr.h
+ DESTINATION ${INCLUDE_INSTALL_DIR}/libtderandr )
+
+
+##### tderandr ####################################
+
+set( target tderandr )
+
+set( ${target}_SRCS
+ randr.cpp lowlevel_randr.c ktimerdialog.cpp libtderandr.cc
+)
+
+tde_add_library( ${target} SHARED AUTOMOC
+ SOURCES ${${target}_SRCS}
+ VERSION 0.0.95
+ LINK tdeui-shared ${XRANDR_LIBRARIES} Xext
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/tderandr/Mainpage.dox b/tderandr/Mainpage.dox
new file mode 100644
index 000000000..c173d52aa
--- /dev/null
+++ b/tderandr/Mainpage.dox
@@ -0,0 +1,18 @@
+/** \mainpage XRandr Interface for Trinity Applications
+
+The \b KRandr library adds the ability for %Trinity applications to easily configure an Xorg display via XRandr.
+
+@authors
+Timothy Pearson \<kb9vqf@pearsoncomputing.net\>
+
+@maintainers
+Timothy Pearson \<kb9vqf@pearsoncomputing.net\>
+
+@licenses
+@gpl
+
+*/
+
+// DOXYGEN_REFERENCES = tdecore tdeui
+// DOXYGEN_SET_PROJECT_NAME = KRandr
+// vim:ts=4:sw=4:expandtab:filetype=doxygen
diff --git a/tderandr/Makefile.am b/tderandr/Makefile.am
new file mode 100644
index 000000000..7818014df
--- /dev/null
+++ b/tderandr/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)
+
+libtderandrincludedir = $(includedir)/libtderandr
+libtderandrinclude_HEADERS = randr.h lowlevel_randr.h ktimerdialog.h libtderandr.h
+
+lib_LTLIBRARIES = libtderandr.la
+libtderandr_la_SOURCES = randr.cpp lowlevel_randr.c ktimerdialog.cpp libtderandr.cc
+METASOURCES = AUTO
+
+libtderandr_la_LDFLAGS = $(KDE_MT_LDFLAGS) -version-info 0:95 -no-undefined
+libtderandr_la_LIBADD = $(LIBASOUND) ../tdecore/libtdecore.la $(LIB_QT) $(LIB_XRANDR)
+
+DOXYGEN_REFERENCES = tdecore
+include ../admin/Doxyfile.am
diff --git a/tderandr/configure.in.in b/tderandr/configure.in.in
new file mode 100644
index 000000000..3dd4a9319
--- /dev/null
+++ b/tderandr/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 libtderandr"
+fi
diff --git a/tderandr/ktimerdialog.cpp b/tderandr/ktimerdialog.cpp
new file mode 100644
index 000000000..0be416be7
--- /dev/null
+++ b/tderandr/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 <tqhbox.h>
+#include <tqlayout.h>
+#include <tqvbox.h>
+#include <tqtimer.h>
+#include <tqprogressbar.h>
+#include <tqlabel.h>
+
+#include <twin.h>
+#include <kiconloader.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "ktimerdialog.h"
+#include "ktimerdialog.moc"
+
+KTimerDialog::KTimerDialog( int msec, TimerStyle style, TQWidget *parent,
+ const char *name, bool modal,
+ const TQString &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 TQTimer( this );
+ updateTimer = new TQTimer( 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, TQT_SIGNAL( timeout() ), TQT_SLOT( slotInternalTimeout() ) );
+ connect( updateTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotUpdateTime() ) );
+
+ // create the widgets
+ mainWidget = new TQVBox( this, "mainWidget" );
+ timerWidget = new TQHBox( mainWidget, "timerWidget" );
+ timerLabel = new TQLabel( timerWidget );
+ timerProgress = new TQProgressBar( 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( TQWidget *widget )
+{
+ // yuck, here goes.
+ TQVBox *newWidget = new TQVBox( this );
+
+ if ( widget->parentWidget() != mainWidget ) {
+ widget->reparent( newWidget, 0, TQPoint(0,0) );
+ } else {
+ newWidget->insertChild( TQT_TQOBJECT(widget) );
+ }
+
+ timerWidget->reparent( newWidget, 0, TQPoint(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/tderandr/ktimerdialog.h b/tderandr/ktimerdialog.h
new file mode 100644
index 000000000..965a72393
--- /dev/null
+++ b/tderandr/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 TQTimer;
+class TQHBox;
+class TQProgressBar;
+class TQLabel;
+
+/**
+ * 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, TQWidget *parent=0,
+ const char *name=0, bool modal=true,
+ const TQString &caption=TQString::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 TQDialog .
+ */
+ 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( TQWidget *widget );
+
+ signals:
+ /**
+ * Signal which is emitted once the timer has timed out.
+ */
+ void timerTimeout();
+
+ public slots:
+ /**
+ * Execute the dialog modally - see @see TQDialog .
+ */
+ 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();
+
+ TQTimer *totalTimer;
+ TQTimer *updateTimer;
+ int msecRemaining, updateInterval, msecTotal;
+
+ ButtonCode buttonOnTimeout;
+ TimerStyle tStyle;
+
+ TQHBox *timerWidget;
+ TQProgressBar *timerProgress;
+ TQLabel *timerLabel;
+ TQVBox *mainWidget;
+
+ class KTimerDialogPrivate;
+ KTimerDialogPrivate *d;
+};
+
+#endif
+
+
+
diff --git a/tderandr/libtderandr.cc b/tderandr/libtderandr.cc
new file mode 100644
index 000000000..65005f91e
--- /dev/null
+++ b/tderandr/libtderandr.cc
@@ -0,0 +1,1634 @@
+/* libtderandr.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
+ LibKRandr's homepage : http://www.trinitydesktop.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.
+
+ Send comments and bug fixes to Timothy Pearson <kb9vqf@pearsoncomputing.net>
+
+***************************************************************************/
+
+#include <tqdir.h>
+#include <tqtimer.h>
+#include <tqstringlist.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kapplication.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <cmath>
+
+#include "libtderandr.h"
+
+#include <X11/extensions/dpms.h>
+
+// FIXME
+// For now, just use the standalone xrandr program to apply the display settings
+#define USE_XRANDR_PROGRAM
+
+// This routine is courtsey of an answer on "Stack Overflow"
+// It takes an LSB-first int and makes it an MSB-first int (or vice versa)
+unsigned int reverse_bits(register unsigned int x)
+{
+ x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
+ x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
+ x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
+ x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
+ return((x >> 16) | (x << 16));
+}
+
+// This routine returns the output of an arbitrary Bash command
+TQString exec(const char * cmd) {
+ TQString bashcommand = cmd;
+ bashcommand = bashcommand.replace("\"", "\\\"");
+ bashcommand = TQString("/bin/bash -c \"%1\" 2>&1").arg(bashcommand);
+ FILE* pipe = popen(bashcommand.ascii(), "r");
+ if (!pipe) return "ERROR";
+ char buffer[128];
+ TQString result = "";
+ while(!feof(pipe)) {
+ if(fgets(buffer, 128, pipe) != NULL) {
+ result += buffer;
+ }
+ }
+ pclose(pipe);
+ result.remove(result.length(), 1);
+ return result;
+}
+
+TQString capitalizeString(TQString in) {
+ return in.left(1).upper() + in.right(in.length()-1);
+}
+
+TQString KRandrSimpleAPI::getIccFileName(TQString profileName, TQString screenName, TQString kde_confdir) {
+ KSimpleConfig *t_config = NULL;
+ KSimpleConfig *t_systemconfig = NULL;
+ int t_numberOfProfiles;
+ TQStringList t_cfgProfiles;
+ TQString retval;
+
+ if (profileName != NULL) {
+ t_config = new KSimpleConfig( TQString::fromLatin1( "kiccconfigrc" ));
+ }
+ else {
+ t_systemconfig = new KSimpleConfig( kde_confdir + TQString("/kicc/kiccconfigrc") );
+ }
+
+ if (profileName != NULL) {
+ t_config->setGroup(NULL);
+ if (t_config->readBoolEntry("EnableICC", false) == true) {
+ t_config->setGroup(profileName);
+ retval = t_config->readEntry(screenName);
+ }
+ else {
+ retval = "";
+ }
+ }
+ else {
+ t_systemconfig->setGroup(NULL);
+ if (t_systemconfig->readBoolEntry("EnableICC", false) == true) {
+ retval = t_systemconfig->readEntry("ICCFile");
+ }
+ else {
+ retval = "";
+ }
+ }
+
+ if (profileName != "") {
+ if (t_config) {
+ delete t_config;
+ }
+ }
+ else {
+ if (t_systemconfig) {
+ delete t_systemconfig;
+ }
+ }
+
+ return retval;
+}
+
+TQString KRandrSimpleAPI::applyIccFile(TQString screenName, TQString fileName) {
+ int i;
+ int j;
+ Display *randr_display;
+ ScreenInfo *randr_screen_info;
+ XRROutputInfo *output_info;
+
+ int screenNumber = 0;
+
+ if (fileName != "") {
+ // FIXME
+ // This should use the RRSetCrtcGamma function when available
+ // That is the only way to get proper setting when two output are active at the same time
+ // (otherwise in clone mode only one screen is available)
+
+ // HACK
+ // For now, simply exit with no changes if screenName is not an active output
+
+ if (isValid() == true) {
+ screenNumber = -1;
+ randr_display = tqt_xdisplay();
+ randr_screen_info = read_screen_info(randr_display);
+ if (randr_screen_info == NULL) {
+ return "";
+ }
+ j=0;
+ for (i = 0; i < randr_screen_info->n_output; i++) {
+ output_info = randr_screen_info->outputs[i]->info;
+ // Look for ON outputs...
+ if (!randr_screen_info->outputs[i]->cur_crtc) {
+ continue;
+ }
+ // ...that are connected
+ if (RR_Disconnected == randr_screen_info->outputs[i]->info->connection) {
+ continue;
+ }
+ if (output_info->name == screenName) {
+ screenNumber = j;
+ }
+ j++;
+ }
+ freeScreenInfoStructure(randr_screen_info);
+ }
+
+ if (screenNumber >= 0) {
+ // Apply ICC settings with XCalib
+ TQString icc_command;
+ FILE *pipe_xcalib;
+ char xcalib_result[2048];
+ int i;
+ xcalib_result[0]=0;
+
+ icc_command = TQString("xcalib \"%1\"").arg(fileName);
+ if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
+ {
+ printf("Xcalib pipe error\n\r [xcalib apply]");
+ }
+ else {
+ if (fgets(xcalib_result, 2048, pipe_xcalib)) {
+ pclose(pipe_xcalib);
+ for (i=1;i<2048;i++) {
+ if (xcalib_result[i] == 0) {
+ xcalib_result[i-1]=0;
+ i=2048;
+ }
+ }
+ if (strlen(xcalib_result) > 2) {
+ return xcalib_result;
+ }
+ }
+ else {
+ return "";
+ }
+ }
+ }
+ }
+ else {
+ // Reset ICC profile on this screen
+
+ // FIXME
+ // This should use the RRSetCrtcGamma function when available
+ // That is the only way to get proper setting when two output are active at the same time
+ // (otherwise in clone mode only one screen is available)
+
+ // HACK
+ // For now, simply exit with no changes if screenName is not an active output
+
+ if (isValid() == true) {
+ screenNumber = -1;
+ randr_display = tqt_xdisplay();
+ randr_screen_info = read_screen_info(randr_display);
+ if (randr_screen_info == NULL) {
+ return "";
+ }
+ j=0;
+ for (i = 0; i < randr_screen_info->n_output; i++) {
+ output_info = randr_screen_info->outputs[i]->info;
+ // Look for ON outputs...
+ if (!randr_screen_info->outputs[i]->cur_crtc) {
+ continue;
+ }
+ // ...that are connected
+ if (RR_Disconnected == randr_screen_info->outputs[i]->info->connection) {
+ continue;
+ }
+ if (output_info->name == screenName) {
+ screenNumber = j;
+ }
+ j++;
+ }
+ freeScreenInfoStructure(randr_screen_info);
+ }
+
+ if (screenNumber >= 0) {
+ // Apply ICC settings with XCalib
+ TQString icc_command;
+ FILE *pipe_xcalib;
+ char xcalib_result[2048];
+ int i;
+ xcalib_result[0]=0;
+
+ icc_command = TQString("xcalib -c");
+ if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
+ {
+ printf("Xcalib pipe error\n\r [xcalib clear]");
+ }
+ else {
+ if (fgets(xcalib_result, 2048, pipe_xcalib)) {
+ pclose(pipe_xcalib);
+ for (i=1;i<2048;i++) {
+ if (xcalib_result[i] == 0) {
+ xcalib_result[i-1]=0;
+ i=2048;
+ }
+ }
+ if (strlen(xcalib_result) > 2) {
+ return xcalib_result;
+ }
+ }
+ else {
+ return "";
+ }
+ }
+ }
+ }
+ return "";
+}
+
+TQString KRandrSimpleAPI::applyIccConfiguration(TQString profileName, TQString kde_confdir) {
+ int i;
+ Display *randr_display;
+ ScreenInfo *randr_screen_info;
+ XRROutputInfo *output_info;
+ KSimpleConfig *t_config;
+
+ int screenNumber = 0;
+ TQString errorstr = "";
+
+ t_config = new KSimpleConfig( TQString::fromLatin1( "kiccconfigrc" ));
+
+ // Find all screens
+ if (isValid() == true) {
+ randr_display = tqt_xdisplay();
+ randr_screen_info = read_screen_info(randr_display);
+ if (randr_screen_info == NULL) {
+ return "";
+ }
+ for (i = 0; i < randr_screen_info->n_output; i++) {
+ output_info = randr_screen_info->outputs[i]->info;
+ errorstr = applyIccFile(output_info->name, getIccFileName(profileName, output_info->name, kde_confdir));
+ if (errorstr != "") {
+ return errorstr;
+ }
+ }
+ freeScreenInfoStructure(randr_screen_info);
+ }
+ else {
+ return applyIccFile(getIccFileName(profileName, "Default", kde_confdir), "Default");
+ }
+
+ t_config->writeEntry("CurrentProfile", profileName);
+ t_config->sync();
+ delete t_config;
+
+ return "";
+}
+
+TQString KRandrSimpleAPI::getEDIDMonitorName(int card, TQString displayname) {
+ TQString edid;
+ TQByteArray binaryedid = getEDID(card, displayname);
+ if (binaryedid.isNull())
+ return TQString();
+
+ // Get the manufacturer ID
+ unsigned char letter_1 = ((binaryedid[8]>>2) & 0x1F) + 0x40;
+ unsigned char letter_2 = (((binaryedid[8] & 0x03) << 3) | ((binaryedid[9]>>5) & 0x07)) + 0x40;
+ unsigned char letter_3 = (binaryedid[9] & 0x1F) + 0x40;
+ TQChar qletter_1 = TQChar(letter_1);
+ TQChar qletter_2 = TQChar(letter_2);
+ TQChar qletter_3 = TQChar(letter_3);
+ TQString manufacturer_id = TQString("%1%2%3").arg(qletter_1).arg(qletter_2).arg(qletter_3);
+
+ // Get the model ID
+ unsigned int raw_model_id = (((binaryedid[10] << 8) | binaryedid[11]) << 16) & 0xFFFF0000;
+ // Reverse the bit order
+ unsigned int model_id = reverse_bits(raw_model_id);
+
+ // Try to get the model name
+ bool has_friendly_name = false;
+ unsigned char descriptor_block[18];
+ int i;
+ for (i=72;i<90;i++) {
+ descriptor_block[i-72] = binaryedid[i] & 0xFF;
+ }
+ if ((descriptor_block[0] != 0) || (descriptor_block[1] != 0) || (descriptor_block[3] != 0xFC)) {
+ for (i=90;i<108;i++) {
+ descriptor_block[i-90] = binaryedid[i] & 0xFF;
+ }
+ if ((descriptor_block[0] != 0) || (descriptor_block[1] != 0) || (descriptor_block[3] != 0xFC)) {
+ for (i=108;i<126;i++) {
+ descriptor_block[i-108] = binaryedid[i] & 0xFF;
+ }
+ }
+ }
+
+ TQString monitor_name;
+ if ((descriptor_block[0] == 0) && (descriptor_block[1] == 0) && (descriptor_block[3] == 0xFC)) {
+ char* pos = strchr((char *)(descriptor_block+5), '\n');
+ if (pos) {
+ *pos = 0;
+ has_friendly_name = true;
+ monitor_name = TQString((char *)(descriptor_block+5));
+ }
+ else {
+ has_friendly_name = false;
+ }
+ }
+
+ // [FIXME]
+ // Look up manudacturer names if possible!
+
+ if (has_friendly_name)
+ edid = TQString("%1 %2").arg(manufacturer_id).arg(monitor_name);
+ else
+ edid = TQString("%1 0x%2").arg(manufacturer_id).arg(model_id, 0, 16);
+
+ return edid;
+}
+
+TQByteArray KRandrSimpleAPI::getEDID(int card, TQString displayname) {
+ TQFile file(TQString("/sys/class/drm/card%1-%2/edid").arg(card).arg(displayname));
+ if (!file.open (IO_ReadOnly))
+ return TQByteArray();
+ TQByteArray binaryedid = file.readAll();
+ file.close();
+ return binaryedid;
+}
+
+TQString KRandrSimpleAPI::getCurrentProfile () {
+ TQString profileName;
+ KSimpleConfig *t_config;
+
+ t_config = new KSimpleConfig( TQString::fromLatin1( "kiccconfigrc" ));
+ profileName = t_config->readEntry("CurrentProfile");
+ delete t_config;
+ return profileName;
+}
+
+TQString KRandrSimpleAPI::applySystemWideIccConfiguration(TQString kde_confdir) {
+ // Apply ICC settings with XCalib
+ TQString icc_command;
+ FILE *pipe_xcalib;
+ char xcalib_result[2048];
+ int i;
+ xcalib_result[0]=0;
+
+ icc_command = TQString("xcalib \"%1\"").arg(getIccFileName(NULL, "Default", kde_confdir));
+ if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
+ {
+ printf("Xcalib pipe error [xcalib apply]\n\r");
+ }
+ else {
+ if (fgets(xcalib_result, 2048, pipe_xcalib)) {
+ pclose(pipe_xcalib);
+ for (i=1;i<2048;i++) {
+ if (xcalib_result[i] == 0) {
+ xcalib_result[i-1]=0;
+ i=2048;
+ }
+ }
+ if (strlen(xcalib_result) > 2) {
+ return xcalib_result;
+ }
+ }
+ else {
+ return "";
+ }
+ }
+ return "";
+}
+
+TQStringList KRandrSimpleAPI::getDisplayConfigurationProfiles(TQString kde_confdir) {
+ TQStringList ret;
+
+ TQDir d(kde_confdir + "/displayconfig/");
+ d.setFilter(TQDir::Files);
+ d.setSorting(TQDir::Name);
+
+ const TQFileInfoList *list = d.entryInfoList();
+ if (list) {
+ TQFileInfoListIterator it(*list);
+ TQFileInfo *fi;
+
+ while ((fi = it.current()) != 0) {
+ if (fi->fileName() != "default") {
+ ret.append(fi->fileName());
+ }
+ ++it;
+ }
+ }
+
+ return ret;
+}
+
+bool KRandrSimpleAPI::deleteDisplayConfiguration(TQString profilename, TQString kde_confdir) {
+ TQString fileName = kde_confdir + "/displayconfig/";
+ fileName.append(profilename);
+ return (!unlink(fileName.ascii()));
+}
+
+bool KRandrSimpleAPI::renameDisplayConfiguration(TQString profilename, TQString newprofilename, TQString kde_confdir) {
+ TQString fileName = kde_confdir + "/displayconfig/";
+ TQString newFileName = fileName;
+ fileName.append(profilename);
+ newFileName.append(newprofilename);
+ TQDir d(kde_confdir + "/displayconfig/");
+ return (d.rename(fileName, newFileName));
+}
+
+void KRandrSimpleAPI::saveDisplayConfiguration(bool enable, bool applyonstart, TQString profilename, TQString defaultprofilename, TQString kde_confdir, TQPtrList<SingleScreenData> screenInfoArray) {
+ int i;
+
+ TQString filename;
+
+ filename = "displayglobals";
+ filename.prepend(kde_confdir.append("/"));
+ KSimpleConfig* display_config = new KSimpleConfig( filename );
+ display_config->setGroup("General");
+ display_config->writeEntry("EnableDisplayControl", enable);
+ display_config->writeEntry("ApplySettingsOnStart", applyonstart);
+ display_config->writeEntry("StartupProfileName", defaultprofilename);
+ display_config->sync();
+ delete display_config;
+
+ filename = profilename;
+ if (filename == "") {
+ filename = "default";
+ }
+ filename.prepend(kde_confdir.append("/displayconfig/"));
+
+ display_config = new KSimpleConfig( filename );
+
+ i=0;
+ SingleScreenData *screendata;
+ for ( screendata=screenInfoArray.first(); screendata; screendata=screenInfoArray.next() ) {
+ display_config->setGroup(TQString("SCREEN %1").arg(i));
+ display_config->writeEntry("ScreenUniqueName", screendata->screenUniqueName);
+ display_config->writeEntry("ScreenFriendlyName", screendata->screenFriendlyName);
+ display_config->writeEntry("GenericScreenDetected", screendata->generic_screen_detected);
+ display_config->writeEntry("ScreenConnected", screendata->screen_connected);
+ display_config->writeEntry("Resolutions", screendata->resolutions);
+ display_config->writeEntry("RefreshRates", screendata->refresh_rates);
+ display_config->writeEntry("ColorDepths", screendata->color_depths);
+ display_config->writeEntry("AvailableRotations", screendata->rotations);
+ display_config->writeEntry("CurrentResolution", screendata->current_resolution_index);
+ display_config->writeEntry("CurrentRefreshRate", screendata->current_refresh_rate_index);
+ display_config->writeEntry("CurrentColorDepth", screendata->current_color_depth_index);
+ display_config->writeEntry("CurrentRotation", screendata->current_rotation_index);
+ display_config->writeEntry("CurrentOrientiation", screendata->current_orientation_mask);
+ display_config->writeEntry("GammaRed", screendata->gamma_red);
+ display_config->writeEntry("GammaGreen", screendata->gamma_green);
+ display_config->writeEntry("GammaBlue", screendata->gamma_blue);
+ display_config->writeEntry("CurrentXFlip", screendata->has_x_flip);
+ display_config->writeEntry("CurrentYFlip", screendata->has_y_flip);
+ display_config->writeEntry("SupportsTransformation", screendata->supports_transformations);
+ display_config->writeEntry("IsPrimary", screendata->is_primary);
+ display_config->writeEntry("IsExtended", screendata->is_extended);
+ display_config->writeEntry("AbsXPos", screendata->absolute_x_position);
+ display_config->writeEntry("AbsYPos", screendata->absolute_y_position);
+ display_config->writeEntry("CurrentXPixelCount", screendata->current_x_pixel_count);
+ display_config->writeEntry("CurrentYPixelCount", screendata->current_y_pixel_count);
+ display_config->writeEntry("HasDPMS", screendata->has_dpms);
+ display_config->writeEntry("EnableDPMS", screendata->enable_dpms);
+ display_config->writeEntry("DPMSStandbyDelay", screendata->dpms_standby_delay);
+ display_config->writeEntry("DPMSSuspendDelay", screendata->dpms_suspend_delay);
+ display_config->writeEntry("DPMSPowerDownDelay", screendata->dpms_off_delay);
+ i++;
+ }
+
+ display_config->sync();
+ delete display_config;
+}
+
+TQPoint KRandrSimpleAPI::applyStartupDisplayConfiguration(TQString kde_confdir) {
+ bool applyonstart = getDisplayConfigurationStartupAutoApplyEnabled(kde_confdir);
+ if (applyonstart) {
+ TQString profilename = getDisplayConfigurationStartupAutoApplyName(kde_confdir);
+ return applyDisplayConfiguration(profilename, kde_confdir);
+ }
+ else {
+ return TQPoint();
+ }
+}
+
+TQPoint KRandrSimpleAPI::applyDisplayConfiguration(TQString profilename, TQString kde_confdir) {
+ TQPoint ret;
+
+ bool enabled = getDisplayConfigurationEnabled(kde_confdir);
+ if (profilename == "") {
+ profilename = "default";
+ }
+
+ if (enabled) {
+ TQPtrList<SingleScreenData> screenInfoArray;
+ screenInfoArray = loadDisplayConfiguration(profilename, kde_confdir);
+ if (screenInfoArray.count() > 0) {
+ applyDisplayConfiguration(screenInfoArray, FALSE, kde_confdir);
+ }
+ destroyScreenInformationObject(screenInfoArray);
+ screenInfoArray = readCurrentDisplayConfiguration();
+ ensureMonitorDataConsistency(screenInfoArray);
+ ret = primaryScreenOffsetFromTLC(screenInfoArray);
+ destroyScreenInformationObject(screenInfoArray);
+ }
+
+ return ret;
+}
+
+TQPtrList<SingleScreenData> KRandrSimpleAPI::loadDisplayConfiguration(TQString profilename, TQString kde_confdir) {
+ int i;
+
+ TQString filename;
+ filename = profilename;
+ if (filename == "") {
+ filename = "default";
+ }
+ filename.prepend(kde_confdir.append("/displayconfig/"));
+
+ KSimpleConfig* display_config = new KSimpleConfig( filename );
+
+ TQStringList grouplist = display_config->groupList();
+ SingleScreenData *screendata;
+ TQPtrList<SingleScreenData> screenInfoArray;
+ for ( TQStringList::Iterator it = grouplist.begin(); it != grouplist.end(); ++it ) {
+ if ((*it).startsWith("SCREEN ")) {
+ display_config->setGroup(*it);
+ i = ((*it).remove("SCREEN ")).toInt();
+ screendata = new SingleScreenData;
+ screenInfoArray.append(screendata);
+ screendata->screenUniqueName = display_config->readEntry("ScreenUniqueName");
+ screendata->screenFriendlyName = display_config->readEntry("ScreenFriendlyName");
+ screendata->generic_screen_detected = display_config->readBoolEntry("GenericScreenDetected");
+ screendata->screen_connected = display_config->readBoolEntry("ScreenConnected");
+ screendata->resolutions = display_config->readListEntry("Resolutions");
+ screendata->refresh_rates = display_config->readListEntry("RefreshRates");
+ screendata->color_depths = display_config->readListEntry("ColorDepths");
+ screendata->rotations = display_config->readListEntry("AvailableRotations");
+ screendata->current_resolution_index = display_config->readNumEntry("CurrentResolution");
+ screendata->current_refresh_rate_index = display_config->readNumEntry("CurrentRefreshRate");
+ screendata->current_color_depth_index = display_config->readNumEntry("CurrentColorDepth");
+ screendata->current_rotation_index = display_config->readNumEntry("CurrentRotation");
+ screendata->current_orientation_mask = display_config->readNumEntry("CurrentOrientiation");
+ screendata->gamma_red = display_config->readDoubleNumEntry("GammaRed");
+ screendata->gamma_green = display_config->readDoubleNumEntry("GammaGreen");
+ screendata->gamma_blue = display_config->readDoubleNumEntry("GammaBlue");
+ screendata->has_x_flip = display_config->readBoolEntry("CurrentXFlip");
+ screendata->has_y_flip = display_config->readBoolEntry("CurrentYFlip");
+ screendata->supports_transformations = display_config->readBoolEntry("SupportsTransformation");
+ screendata->is_primary = display_config->readBoolEntry("IsPrimary");
+ screendata->is_extended = display_config->readBoolEntry("IsExtended");
+ screendata->absolute_x_position = display_config->readNumEntry("AbsXPos");
+ screendata->absolute_y_position = display_config->readNumEntry("AbsYPos");
+ screendata->current_x_pixel_count = display_config->readNumEntry("CurrentXPixelCount");
+ screendata->current_y_pixel_count = display_config->readNumEntry("CurrentYPixelCount");
+ screendata->has_dpms = display_config->readBoolEntry("HasDPMS");
+ screendata->enable_dpms = display_config->readBoolEntry("EnableDPMS");
+ screendata->dpms_standby_delay = display_config->readNumEntry("DPMSStandbyDelay");
+ screendata->dpms_suspend_delay = display_config->readNumEntry("DPMSSuspendDelay");
+ screendata->dpms_off_delay = display_config->readNumEntry("DPMSPowerDownDelay");
+ }
+ }
+
+ delete display_config;
+
+ return screenInfoArray;
+}
+
+int KRandrSimpleAPI::getHardwareRotationFlags(SingleScreenData* screendata) {
+ int rotationFlags = 0;
+ TQString rotationDesired = *screendata->rotations.at(screendata->current_rotation_index);
+ if (rotationDesired == ROTATION_0_DEGREES_STRING) {
+ rotationFlags = rotationFlags | RandRScreen::Rotate0;
+ }
+ else if (rotationDesired == ROTATION_90_DEGREES_STRING) {
+ rotationFlags = rotationFlags | RandRScreen::Rotate90;
+ }
+ else if (rotationDesired == ROTATION_180_DEGREES_STRING) {
+ rotationFlags = rotationFlags | RandRScreen::Rotate180;
+ }
+ else if (rotationDesired == ROTATION_270_DEGREES_STRING) {
+ rotationFlags = rotationFlags | RandRScreen::Rotate270;
+ }
+ if (screendata->has_x_flip) {
+ rotationFlags = rotationFlags | RandRScreen::ReflectX;
+ }
+ if (screendata->has_y_flip) {
+ rotationFlags = rotationFlags | RandRScreen::ReflectY;
+ }
+ return rotationFlags;
+}
+
+#define USE_XRANDR_PROGRAM
+
+bool KRandrSimpleAPI::applyDisplayConfiguration(TQPtrList<SingleScreenData> screenInfoArray, bool test, TQString kde_confdir) {
+ int i;
+ int j;
+ bool accepted = true;
+ Display *randr_display;
+ XRROutputInfo *output_info;
+ ScreenInfo *randr_screen_info;
+
+ SingleScreenData *screendata;
+
+ TQPtrList<SingleScreenData> oldconfig;
+ if (test == TRUE) {
+ oldconfig = readCurrentDisplayConfiguration();
+ }
+
+ if (isValid() == true) {
+#ifdef USE_XRANDR_PROGRAM
+ // Assemble the command string for xrandr
+ TQString command;
+ command = "xrandr";
+
+ randr_display = tqt_xdisplay();
+ randr_screen_info = read_screen_info(randr_display);
+ for (i = 0; i < screenInfoArray.count(); i++) {
+ screendata = screenInfoArray.at(i);
+ if (screendata) {
+ output_info = randr_screen_info->outputs[i]->info;
+ command.append(" --output ").append(output_info->name);
+ if (screendata->is_primary || screendata->is_extended) {
+ command.append(TQString(" --mode %1x%2").arg(screendata->current_x_pixel_count).arg(screendata->current_y_pixel_count));
+ command.append(TQString(" --pos %1x%2").arg(screendata->absolute_x_position).arg(screendata->absolute_y_position));
+ command.append(TQString(" --refresh %1").arg((*screendata->refresh_rates.at(screendata->current_refresh_rate_index)).replace("Hz", "")));
+ command.append(TQString(" --gamma %1:%2:%3").arg(screendata->gamma_red).arg(screendata->gamma_green).arg(screendata->gamma_blue));
+ if (screendata->current_rotation_index == 0) command.append(" --rotate ").append("normal");
+ if (screendata->current_rotation_index == 1) command.append(" --rotate ").append("left");
+ if (screendata->current_rotation_index == 2) command.append(" --rotate ").append("inverted");
+ if (screendata->current_rotation_index == 3) command.append(" --rotate ").append("right");
+ if ((screendata->has_x_flip == 0) && (screendata->has_y_flip == 0)) command.append(" --reflect ").append("normal");
+ if ((screendata->has_x_flip == 1) && (screendata->has_y_flip == 0)) command.append(" --reflect ").append("x");
+ if ((screendata->has_x_flip == 0) && (screendata->has_y_flip == 1)) command.append(" --reflect ").append("y");
+ if ((screendata->has_x_flip == 1) && (screendata->has_y_flip == 1)) command.append(" --reflect ").append("xy");
+ if (screendata->is_primary) {
+ command.append(" --primary");
+ }
+ }
+ else {
+ command.append(" --off");
+ }
+ }
+ else {
+ printf("[WARNING] Unable to find configuration for monitor %d; settings may not be correctly applied...\n\r", i); fflush(stdout);
+ }
+ }
+ freeScreenInfoStructure(randr_screen_info);
+
+ TQString xrandr_command_output = exec(command.ascii());
+ xrandr_command_output = xrandr_command_output.stripWhiteSpace();
+ if (test) {
+ if (xrandr_command_output != "") {
+ applyDisplayConfiguration(oldconfig, FALSE, kde_confdir);
+ accepted = false;
+ destroyScreenInformationObject(oldconfig);
+ KMessageBox::sorry(0, xrandr_command_output, i18n("XRandR encountered a problem"));
+ return accepted;
+ }
+ }
+#else
+ randr_display = tqt_xdisplay();
+ randr_screen_info = read_screen_info(randr_display);
+ // Turn off all displays
+ for (i = 0; i < screenInfoArray.count(); i++) {
+ screendata = screenInfoArray.at(i);
+ output_info = randr_screen_info->outputs[i]->info;
+
+ randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
+ randr_screen_info->cur_output = randr_screen_info->outputs[i];
+ randr_screen_info->cur_output->auto_set = 0;
+ randr_screen_info->cur_output->off_set = 1;
+ output_off (randr_screen_info, randr_screen_info->cur_output);
+ j=main_low_apply(randr_screen_info);
+ }
+ freeScreenInfoStructure(randr_screen_info);
+ randr_screen_info = read_screen_info(randr_display);
+ // Turn on the primary display
+ for (i = 0; i < screenInfoArray.count(); i++) {
+ screendata = screenInfoArray.at(i);
+ output_info = randr_screen_info->outputs[i]->info;
+
+ if (screendata->is_primary == true) {
+ randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
+ randr_screen_info->cur_output = randr_screen_info->outputs[i];
+ randr_screen_info->cur_output->auto_set = 1;
+ randr_screen_info->cur_output->off_set = 0;
+ output_auto (randr_screen_info, randr_screen_info->cur_output);
+ j=main_low_apply(randr_screen_info);
+ }
+ }
+ freeScreenInfoStructure(randr_screen_info);
+ // Handle the remaining displays
+ randr_screen_info = read_screen_info(randr_display);
+ for (i = 0; i < screenInfoArray.count(); i++) {
+ screendata = screenInfoArray.at(i);
+ output_info = randr_screen_info->outputs[i]->info;
+
+ // Activate or deactivate the screens as necessary
+ randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
+ randr_screen_info->cur_output = randr_screen_info->outputs[i];
+ if (screendata->is_primary == false) {
+ if (screendata->is_primary || screendata->is_extended) {
+ randr_screen_info->cur_output->auto_set = 1;
+ randr_screen_info->cur_output->off_set = 0;
+ output_auto (randr_screen_info, randr_screen_info->cur_output);
+ j=main_low_apply(randr_screen_info);
+ }
+ else {
+ randr_screen_info->cur_output->auto_set = 0;
+ randr_screen_info->cur_output->off_set = 1;
+ output_off (randr_screen_info, randr_screen_info->cur_output);
+ j=main_low_apply(randr_screen_info);
+ }
+ }
+ }
+ freeScreenInfoStructure(randr_screen_info);
+ randr_screen_info = read_screen_info(randr_display);
+ for (i = 0; i < screenInfoArray.count(); i++) {
+ screendata = screenInfoArray.at(i);
+ output_info = randr_screen_info->outputs[i]->info;
+
+ if (screendata->is_primary || screendata->is_extended) {
+ // Set rotation, refresh rate, and size
+ RandRScreen *cur_screen = new RandRScreen(i);
+ cur_screen->proposeSize(screendata->current_resolution_index);
+ cur_screen->proposeRefreshRate(screendata->current_refresh_rate_index);
+ cur_screen->proposeRotation(getHardwareRotationFlags(screendata));
+ cur_screen->applyProposed();
+ delete cur_screen;
+
+ // Force data reload
+ randr_screen_info = read_screen_info(randr_display);
+ output_info = randr_screen_info->outputs[i]->info;
+
+ // Finally, set the screen's position
+ randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
+ if (randr_screen_info->cur_crtc) {
+ randr_screen_info->cur_crtc->cur_x = screendata->absolute_x_position;
+ randr_screen_info->cur_crtc->cur_y = screendata->absolute_y_position;
+ j=main_low_apply(randr_screen_info);
+ }
+ }
+ }
+ freeScreenInfoStructure(randr_screen_info);
+#endif
+ }
+
+ applyDisplayGamma(screenInfoArray);
+ applyDisplayDPMS(screenInfoArray);
+ TQString current_icc_profile = getCurrentProfile();
+ applySystemWideIccConfiguration(kde_confdir);
+ applyIccConfiguration(current_icc_profile, kde_confdir);
+
+ if (test == TRUE) {
+ int ret = showTestConfigurationDialog();
+ if (!ret) {
+ applyDisplayConfiguration(oldconfig, FALSE, kde_confdir);
+ accepted = false;
+ }
+ destroyScreenInformationObject(oldconfig);
+ }
+
+ return accepted;
+}
+
+TQPtrList<SingleScreenData> KRandrSimpleAPI::copyScreenInformationObject(TQPtrList<SingleScreenData> screenInfoArray) {
+ SingleScreenData *origscreendata;
+ SingleScreenData *copyscreendata;
+ TQPtrList<SingleScreenData> retArray;
+ for ( origscreendata = screenInfoArray.first(); origscreendata; origscreendata = screenInfoArray.next() ) {
+ copyscreendata = new SingleScreenData;
+ *copyscreendata = *origscreendata;
+ retArray.append(copyscreendata);
+ }
+ return retArray;
+}
+
+void KRandrSimpleAPI::destroyScreenInformationObject(TQPtrList<SingleScreenData> screenInfoArray) {
+ SingleScreenData *screendata;
+ for ( screendata = screenInfoArray.first(); screendata; screendata = screenInfoArray.next() ) {
+ screenInfoArray.remove(screendata);
+ delete screendata;
+ }
+}
+
+void KRandrSimpleAPI::ensureMonitorDataConsistency(TQPtrList<SingleScreenData> screenInfoArray) {
+ int i;
+ SingleScreenData *screendata;
+
+ int numberOfScreens = screenInfoArray.count();
+
+ for (i=0;i<numberOfScreens;i++) {
+ screendata = screenInfoArray.at(i);
+ if (!screendata->screen_connected) {
+ screendata->is_primary = false;
+ screendata->is_extended = false;
+ }
+ }
+
+ bool has_primary_monitor = false;
+ for (i=0;i<numberOfScreens;i++) {
+ screendata = screenInfoArray.at(i);
+ if (screendata->is_primary) {
+ has_primary_monitor = true;
+ }
+ }
+ if (!has_primary_monitor) {
+ for (i=0;i<numberOfScreens;i++) {
+ screendata = screenInfoArray.at(i);
+ if (!has_primary_monitor) {
+ if (screendata->screen_connected && screendata->is_extended) {
+ screendata->is_primary = true;
+ screendata->is_extended = true;
+ has_primary_monitor = true;
+ }
+ }
+ }
+ }
+ if (!has_primary_monitor) {
+ for (i=0;i<numberOfScreens;i++) {
+ screendata = screenInfoArray.at(i);
+ if (!has_primary_monitor) {
+ if (screendata->screen_connected) {
+ screendata->is_primary = true;
+ screendata->is_extended = true;
+ has_primary_monitor = true;
+ }
+ }
+ }
+ }
+
+ bool found_first_primary_monitor = false;
+ for (i=0;i<numberOfScreens;i++) {
+ screendata = screenInfoArray.at(i);
+ if (screendata->is_primary) {
+ if (!found_first_primary_monitor) {
+ found_first_primary_monitor = true;
+ }
+ else {
+ screendata->is_primary = false;
+ }
+ }
+ }
+
+ for (i=0;i<numberOfScreens;i++) {
+ screendata = screenInfoArray.at(i);
+ if (screendata->is_primary) {
+ screendata->is_extended = true;
+ }
+ }
+
+ for (i=0;i<numberOfScreens;i++) {
+ screendata = screenInfoArray.at(i);
+ TQString resolutionstring = screendata->resolutions[screendata->current_resolution_index];
+ int separator_pos = resolutionstring.find(" x ");
+ TQString x_res_string = resolutionstring.left(separator_pos);
+ TQString y_res_string = resolutionstring.right(resolutionstring.length()-separator_pos-3);
+ screendata->current_x_pixel_count = x_res_string.toInt();
+ screendata->current_y_pixel_count = y_res_string.toInt();
+ screendata->current_orientation_mask = getHardwareRotationFlags(screendata);
+ }
+
+ // Each screen's absolute position is given relative to the primary monitor
+ // Fix up the absolute positions
+ int primary_offset_x = 0;
+ int primary_offset_y = 0;
+ for (i=0;i<numberOfScreens;i++) {
+ screendata = screenInfoArray.at(i);
+ if (screendata->is_primary) {
+ primary_offset_x = screendata->absolute_x_position;
+ primary_offset_y = screendata->absolute_y_position;
+ primary_offset_x = primary_offset_x * (-1);
+ primary_offset_y = primary_offset_y * (-1);
+ }
+ }
+ for (i=0;i<numberOfScreens;i++) {
+ screendata = screenInfoArray.at(i);
+ screendata->absolute_x_position = screendata->absolute_x_position + primary_offset_x;
+ screendata->absolute_y_position = screendata->absolute_y_position + primary_offset_y;
+ }
+}
+
+TQPoint KRandrSimpleAPI::primaryScreenOffsetFromTLC(TQPtrList<SingleScreenData> screenInfoArray) {
+ int i;
+ SingleScreenData *screendata;
+ int numberOfScreens = screenInfoArray.count();
+
+ int primary_offset_x = 0;
+ int primary_offset_y = 0;
+ for (i=0;i<numberOfScreens;i++) {
+ screendata = screenInfoArray.at(i);
+ if (screendata->absolute_x_position < primary_offset_x) {
+ primary_offset_x = screendata->absolute_x_position;
+ }
+ if (screendata->absolute_y_position < primary_offset_y) {
+ primary_offset_y = screendata->absolute_y_position;
+ }
+ }
+ primary_offset_x = primary_offset_x * (-1);
+ primary_offset_y = primary_offset_y * (-1);
+
+ return TQPoint(primary_offset_x, primary_offset_y);
+}
+
+HotPlugRulesList KRandrSimpleAPI::getHotplugRules(TQString kde_confdir) {
+ int i;
+ TQString filename;
+ HotPlugRulesList ret;
+
+ filename = "displayglobals";
+ filename.prepend(kde_confdir.append("/"));
+ KSimpleConfig* display_config = new KSimpleConfig( filename );
+
+ TQStringList grouplist = display_config->groupList();
+ for ( TQStringList::Iterator it = grouplist.begin(); it != grouplist.end(); ++it ) {
+ if (!(*it).startsWith("Hotplug-Rule")) {
+ continue;
+ }
+ HotPlugRule rule;
+ display_config->setGroup(*it);
+ rule.outputs = display_config->readListEntry("Outputs");
+ rule.states = display_config->readIntListEntry("States");
+ rule.profileName = display_config->readEntry("Profile");
+ ret.append(rule);
+ }
+ delete display_config;
+
+ return ret;
+}
+
+void KRandrSimpleAPI::saveHotplugRules(HotPlugRulesList rules, TQString kde_confdir) {
+ int i;
+ TQString filename;
+
+ filename = "displayglobals";
+ filename.prepend(kde_confdir.append("/"));
+ KSimpleConfig* display_config = new KSimpleConfig( filename );
+ TQStringList grouplist = display_config->groupList();
+ for ( TQStringList::Iterator it = grouplist.begin(); it != grouplist.end(); ++it ) {
+ if (!(*it).startsWith("Hotplug-Rule")) {
+ continue;
+ }
+ display_config->deleteGroup(*it, true, false);
+ }
+ HotPlugRulesList::Iterator it;
+ i=0;
+ for (it=rules.begin(); it != rules.end(); ++it) {
+ display_config->setGroup(TQString("Hotplug-Rule%1").arg(i));
+ display_config->writeEntry("Outputs", (*it).outputs);
+ display_config->writeEntry("States", (*it).states);
+ display_config->writeEntry("Profile", (*it).profileName);
+ i++;
+ }
+ display_config->sync();
+ delete display_config;
+}
+
+bool KRandrSimpleAPI::getDisplayConfigurationEnabled(TQString kde_confdir) {
+ TQString filename = "displayglobals";
+ filename.prepend(kde_confdir.append("/"));
+ KSimpleConfig* display_config = new KSimpleConfig( filename );
+ display_config->setGroup("General");
+ bool enabled = display_config->readBoolEntry("EnableDisplayControl", false);
+ delete display_config;
+
+ return enabled;
+}
+
+bool KRandrSimpleAPI::getDisplayConfigurationStartupAutoApplyEnabled(TQString kde_confdir) {
+ TQString filename = "displayglobals";
+ filename.prepend(kde_confdir.append("/"));
+ KSimpleConfig* display_config = new KSimpleConfig( filename );
+ display_config->setGroup("General");
+ bool applyonstart = display_config->readBoolEntry("ApplySettingsOnStart", false);
+ delete display_config;
+
+ return applyonstart;
+}
+
+TQString KRandrSimpleAPI::getDisplayConfigurationStartupAutoApplyName(TQString kde_confdir) {
+ TQString filename = "displayglobals";
+ filename.prepend(kde_confdir.append("/"));
+ KSimpleConfig* display_config = new KSimpleConfig( filename );
+ display_config->setGroup("General");
+ TQString profilename = display_config->readEntry("StartupProfileName", "");
+ delete display_config;
+
+ return profilename;
+}
+
+void KRandrSimpleAPI::applyHotplugRules(TQString kde_confdir) {
+ bool enabled = getDisplayConfigurationEnabled(kde_confdir);
+ if (!enabled) {
+ return;
+ }
+
+ HotPlugRulesList rules = getHotplugRules(kde_confdir);
+ TQPtrList<SingleScreenData> screenInfoArray = readCurrentDisplayConfiguration();
+
+ int i;
+ int j;
+ TQString bestRule;
+ int bestRuleMatchCount = 0;
+ SingleScreenData *screendata = NULL;
+ HotPlugRulesList::Iterator it;
+ for (it=rules.begin(); it != rules.end(); ++it) {
+ // Compare each rule against the current display configuration
+ // It an output matches the state given in the rule, increment matchCount
+ HotPlugRule rule = *it;
+ int matchCount = 0;
+ int numberOfScreens = screenInfoArray.count();
+ for (i=0;i<numberOfScreens;i++) {
+ screendata = screenInfoArray.at(i);
+ for (j=0; j<(*it).outputs.count(); j++) {
+ if ((*it).outputs[j] != screendata->screenUniqueName) {
+ continue;
+ }
+ if ((*it).states[j] == HotPlugRule::Connected) {
+ if (screendata->screen_connected) {
+ matchCount++;
+ }
+ }
+ else if ((*it).states[j] == HotPlugRule::Disconnected) {
+ if (!screendata->screen_connected) {
+ matchCount++;
+ }
+ }
+ }
+ }
+
+ if (matchCount > bestRuleMatchCount) {
+ bestRuleMatchCount = matchCount;
+ bestRule = rule.profileName;
+ }
+ }
+
+ destroyScreenInformationObject(screenInfoArray);
+
+ if (bestRuleMatchCount > 0) {
+ // At least one rule matched...
+ // Apply the profile name in bestRule to the display hardware
+ applyDisplayConfiguration(bestRule, kde_confdir);
+ }
+}
+
+void KRandrSimpleAPI::applyDisplayGamma(TQPtrList<SingleScreenData> screenInfoArray) {
+ int i;
+ Display *randr_display;
+ XRROutputInfo *output_info;
+ ScreenInfo *randr_screen_info;
+ XRRCrtcGamma *gamma;
+
+ SingleScreenData *screendata;
+
+ if (isValid() == true) {
+ randr_display = tqt_xdisplay();
+ randr_screen_info = read_screen_info(randr_display);
+ for (i = 0; i < screenInfoArray.count(); i++) {
+ screendata = screenInfoArray.at(i);
+ output_info = randr_screen_info->outputs[i]->info;
+ CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
+ if (!current_crtc) {
+ continue;
+ }
+ // vvvvvvvvv This chunk of code is borrowed from xrandr vvvvvvvvvv
+ int size = XRRGetCrtcGammaSize(randr_display, current_crtc->id);
+ if (!size) {
+ continue;
+ }
+ gamma = XRRAllocGamma(size);
+ if (!gamma) {
+ continue;
+ }
+ for (i = 0; i < size; i++) {
+ if (screendata->gamma_red == 1.0)
+ gamma->red[i] = i << 8;
+ else
+ gamma->red[i] = (pow((double)i/(double)(size-1), (double)screendata->gamma_red) * (double)(size-1)*256);
+
+ if (screendata->gamma_green == 1.0)
+ gamma->green[i] = i << 8;
+ else
+ gamma->green[i] = (pow((double)i/(double)(size-1), (double)screendata->gamma_green) * (double)(size-1)*256);
+
+ if (screendata->gamma_blue == 1.0)
+ gamma->blue[i] = i << 8;
+ else
+ gamma->blue[i] = (pow((double)i/(double)(size-1), (double)screendata->gamma_blue) * (double)(size-1)*256);
+ }
+ XRRSetCrtcGamma(randr_display, current_crtc->id, gamma);
+ free(gamma);
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ }
+ freeScreenInfoStructure(randr_screen_info);
+ }
+}
+
+void KRandrSimpleAPI::applyDisplayDPMS(TQPtrList<SingleScreenData> screenInfoArray) {
+ int i;
+ Display *randr_display;
+ XRROutputInfo *output_info;
+ ScreenInfo *randr_screen_info;
+ XRRCrtcGamma *gamma;
+
+ SingleScreenData *screendata;
+
+ if (isValid() == true) {
+ randr_display = tqt_xdisplay();
+ randr_screen_info = read_screen_info(randr_display);
+ for (i = 0; i < screenInfoArray.count(); i++) {
+ screendata = screenInfoArray.at(i);
+ output_info = randr_screen_info->outputs[i]->info;
+ CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
+ if (!current_crtc) {
+ continue;
+ }
+ if (!screendata->has_dpms) {
+ continue;
+ }
+ if (screendata->enable_dpms) {
+ DPMSSetTimeouts(randr_display, screendata->dpms_standby_delay, screendata->dpms_suspend_delay, screendata->dpms_off_delay);
+ DPMSEnable(randr_display);
+ }
+ else {
+ DPMSDisable(randr_display);
+ }
+ }
+ freeScreenInfoStructure(randr_screen_info);
+ }
+}
+
+void KRandrSimpleAPI::freeScreenInfoStructure(ScreenInfo* screen_info) {
+ int i;
+
+ for (i=0; i<screen_info->n_crtc; i++) {
+ free(screen_info->crtcs[i]);
+ }
+ for (i=0; i<screen_info->n_output; i++) {
+ free(screen_info->outputs[i]);
+ }
+ free(screen_info->outputs);
+ free(screen_info->crtcs);
+ free(screen_info);
+}
+
+TQPtrList<SingleScreenData> KRandrSimpleAPI::readCurrentDisplayConfiguration() {
+ // Discover display information
+ int i;
+ int j;
+
+ XRROutputInfo *output_info;
+ SingleScreenData *screendata;
+ TQPtrList<SingleScreenData> screenInfoArray;
+
+ Display *randr_display;
+ ScreenInfo *randr_screen_info;
+
+ // Clear existing info
+ destroyScreenInformationObject(screenInfoArray);
+
+ int numberOfScreens = 0;
+ if (isValid() == true) {
+ randr_display = tqt_xdisplay();
+ randr_screen_info = read_screen_info(randr_display);
+ for (i = 0; i < randr_screen_info->n_output; i++) {
+ output_info = randr_screen_info->outputs[i]->info;
+ CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
+
+ // Create new data object
+ screendata = new SingleScreenData;
+ screenInfoArray.append(screendata);
+ screendata->screenUniqueName = TQString(i18n("%1:%2")).arg(":0").arg(capitalizeString(output_info->name)); // [FIXME] How can I get the name of the Xorg graphics driver currently in use?
+ screendata->screenFriendlyName = TQString(i18n("%1. %2 output on %3")).arg(i+1).arg(capitalizeString(output_info->name)).arg(":0"); // [FIXME] How can I get the name of the Xorg graphics driver currently in use?
+ screendata->generic_screen_detected = false;
+
+ // Attempt to use KMS to find screen EDID and name
+ TQString edid = getEDIDMonitorName(0, output_info->name); // [FIXME] Don't hardwire to card 0!
+ if (!edid.isNull()) {
+ screendata->screenFriendlyName = TQString(i18n("%1. %2 on %3 on card %4")).arg(i+1).arg(edid).arg(capitalizeString(output_info->name)).arg("0"); // [FIXME] How can I get the name of the Xorg graphics driver currently in use?
+ }
+
+ // Get resolutions
+ bool screen_active;
+ RandRScreen *cur_screen = 0;
+ if (RR_Disconnected == randr_screen_info->outputs[i]->info->connection) {
+ // Output DISCONNECTED
+ screen_active = false;
+ }
+ else {
+ if (randr_screen_info->outputs[i]->cur_crtc) {
+ // Output CONNECTED and ON
+ screen_active = true;
+ cur_screen = new RandRScreen(i);
+ }
+ else {
+ // Output CONNECTED and OFF
+ screen_active = false;
+ cur_screen = new RandRScreen(i);
+ }
+ }
+
+ // Get DPMS information
+ screendata->has_dpms = 1; // [FIXME] Master Xorg check for global DPMS support should go here if possible
+ if (screendata->has_dpms) {
+ CARD16 dpms_standby_delay;
+ CARD16 dpms_suspend_delay;
+ CARD16 dpms_off_delay;
+ screendata->has_dpms = DPMSGetTimeouts(randr_display, &dpms_standby_delay, &dpms_suspend_delay, &dpms_off_delay);
+ screendata->dpms_standby_delay = dpms_standby_delay;
+ screendata->dpms_suspend_delay = dpms_suspend_delay;
+ screendata->dpms_off_delay = dpms_off_delay;
+ if (screendata->has_dpms) {
+ CARD16 power_level;
+ BOOL enable_dpms;
+ screendata->has_dpms = DPMSInfo(randr_display, &power_level, &enable_dpms);
+ screendata->enable_dpms = enable_dpms;
+ }
+ }
+ if (!screendata->has_dpms) {
+ screendata->enable_dpms = false;
+ screendata->dpms_standby_delay = 0;
+ screendata->dpms_suspend_delay = 0;
+ screendata->dpms_off_delay = 0;
+ }
+
+ if (cur_screen) {
+ screendata->screen_connected = true;
+ for (int j = 0; j < cur_screen->numSizes(); j++) {
+ screendata->resolutions.append(i18n("%1 x %2").arg(cur_screen->pixelSize(j).width()).arg(cur_screen->pixelSize(j).height()));
+ }
+ screendata->current_resolution_index = 0;
+ if (current_crtc) {
+ screendata->current_resolution_index = screendata->resolutions.findIndex(i18n("%1 x %2").arg(current_crtc->info->width).arg(current_crtc->info->height));
+ }
+ if (screendata->current_resolution_index < 0) {
+ screendata->current_resolution_index = cur_screen->proposedSize();
+ }
+
+ // Get refresh rates
+ TQStringList rr = cur_screen->refreshRates(screendata->current_resolution_index);
+ for (TQStringList::Iterator it = rr.begin(); it != rr.end(); ++it) {
+ screendata->refresh_rates.append(*it);
+ }
+ screendata->current_refresh_rate_index = cur_screen->proposedRefreshRate();
+
+ // Get color depths
+ // [FIXME]
+ screendata->color_depths.append(i18n("Default"));
+ screendata->current_color_depth_index = 0;
+
+ // Get orientation flags
+ // RandRScreen::Rotate0
+ // RandRScreen::Rotate90
+ // RandRScreen::Rotate180
+ // RandRScreen::Rotate270
+ // RandRScreen::ReflectX
+ // RandRScreen::ReflectY
+
+ screendata->rotations.append(i18n(ROTATION_0_DEGREES_STRING));
+ screendata->rotations.append(i18n(ROTATION_90_DEGREES_STRING));
+ screendata->rotations.append(i18n(ROTATION_180_DEGREES_STRING));
+ screendata->rotations.append(i18n(ROTATION_270_DEGREES_STRING));
+ screendata->supports_transformations = (cur_screen->rotations() != RandRScreen::Rotate0);
+ if (screendata->supports_transformations) {
+ screendata->current_orientation_mask = cur_screen->proposedRotation();
+ switch (screendata->current_orientation_mask & RandRScreen::RotateMask) {
+ case RandRScreen::Rotate0:
+ screendata->current_rotation_index = 0;
+ break;
+ case RandRScreen::Rotate90:
+ screendata->current_rotation_index = 1;
+ break;
+ case RandRScreen::Rotate180:
+ screendata->current_rotation_index = 2;
+ break;
+ case RandRScreen::Rotate270:
+ screendata->current_rotation_index = 3;
+ break;
+ default:
+ // Shouldn't hit this one
+ Q_ASSERT(screendata->current_orientation_mask & RandRScreen::RotateMask);
+ screendata->current_rotation_index = 0;
+ break;
+ }
+ screendata->has_x_flip = (screendata->current_orientation_mask & RandRScreen::ReflectX);
+ screendata->has_y_flip = (screendata->current_orientation_mask & RandRScreen::ReflectY);
+ }
+ else {
+ screendata->has_x_flip = false;
+ screendata->has_y_flip = false;
+ screendata->current_rotation_index = 0;
+ }
+
+ // Determine if this display is primary and/or extended
+ RROutput primaryoutput = XRRGetOutputPrimary(tqt_xdisplay(), DefaultRootWindow(tqt_xdisplay()));
+ if (primaryoutput == randr_screen_info->outputs[i]->id) {
+ screendata->is_primary = false;
+ }
+ else {
+ screendata->is_primary = true;
+ }
+ screendata->is_extended = screen_active;
+ if (!screendata->is_extended) {
+ screendata->is_primary = false;
+ }
+
+ // Get this screen's absolute position
+ screendata->absolute_x_position = 0;
+ screendata->absolute_y_position = 0;
+ if (current_crtc) {
+ screendata->absolute_x_position = current_crtc->info->x;
+ screendata->absolute_y_position = current_crtc->info->y;
+ }
+
+ // Get this screen's current resolution
+ screendata->current_x_pixel_count = cur_screen->pixelSize(screendata->current_resolution_index).width();
+ screendata->current_y_pixel_count = cur_screen->pixelSize(screendata->current_resolution_index).height();
+
+ // Get this screen's current gamma values
+ // [FIXME]
+ // This attempts to guess a gamma value based on the LUT settings at 50%
+ // It may not always be 100% correct, or even anywhere close...
+ // Essentially it "undoes" the LUT gamma calculation from xrandr
+ // lut_gamma->green[i] = (pow(i/(size - 1), desired_gamma.green) * (size - 1) * 256);
+ if (current_crtc) {
+ //int slot = 127;
+ int slot = 7;
+ int size = XRRGetCrtcGammaSize(randr_display, current_crtc->id);
+ XRRCrtcGamma *gammastruct = XRRGetCrtcGamma (randr_display, current_crtc->id);
+ screendata->gamma_red = log(gammastruct->red[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
+ screendata->gamma_green = log(gammastruct->green[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
+ screendata->gamma_blue = log(gammastruct->blue[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
+ }
+ else {
+ screendata->gamma_red = 2.2;
+ screendata->gamma_green = 2.2;
+ screendata->gamma_blue = 2.2;
+ }
+ // Round off the gamma to one decimal place
+ screendata->gamma_red = floorf(screendata->gamma_red * 10 + 0.5) / 10;
+ screendata->gamma_green = floorf(screendata->gamma_green * 10 + 0.5) / 10;
+ screendata->gamma_blue = floorf(screendata->gamma_blue * 10 + 0.5) / 10;
+
+ delete cur_screen;
+ }
+ else {
+ // Fill in generic data for this disconnected output
+ screendata->screenFriendlyName = screendata->screenFriendlyName + TQString(" (") + i18n("disconnected") + TQString(")");
+ screendata->screen_connected = false;
+
+ screendata->resolutions = i18n("Default");
+ screendata->refresh_rates = i18n("Default");
+ screendata->color_depths = i18n("Default");
+ screendata->rotations = i18n("N/A");
+
+ screendata->current_resolution_index = 0;
+ screendata->current_refresh_rate_index = 0;
+ screendata->current_color_depth_index = 0;
+
+ screendata->gamma_red = 2.2;
+ screendata->gamma_green = 2.2;
+ screendata->gamma_blue = 2.2;
+
+ screendata->current_rotation_index = 0;
+ screendata->current_orientation_mask = 0;
+ screendata->has_x_flip = false;
+ screendata->has_y_flip = false;
+ screendata->supports_transformations = false;
+
+ screendata->is_primary = false;
+ screendata->is_extended = false;
+ screendata->absolute_x_position = 0;
+ screendata->absolute_y_position = 0;
+ screendata->current_x_pixel_count = 640;
+ screendata->current_y_pixel_count = 480;
+ }
+
+ // Check for more screens...
+ numberOfScreens++;
+ }
+
+ freeScreenInfoStructure(randr_screen_info);
+ }
+ else {
+ screendata = new SingleScreenData;
+ screenInfoArray.append(screendata);
+
+ // Fill in a bunch of generic data
+ screendata->screenFriendlyName = i18n("Default output on generic video card");
+ screendata->generic_screen_detected = true;
+ screendata->screen_connected = true;
+
+ screendata->resolutions = i18n("Default");
+ screendata->refresh_rates = i18n("Default");
+ screendata->color_depths = i18n("Default");
+ screendata->rotations = i18n("N/A");
+
+ screendata->current_resolution_index = 0;
+ screendata->current_refresh_rate_index = 0;
+ screendata->current_color_depth_index = 0;
+
+ screendata->gamma_red = 2.2;
+ screendata->gamma_green = 2.2;
+ screendata->gamma_blue = 2.2;
+
+ screendata->current_rotation_index = 0;
+ screendata->current_orientation_mask = 0;
+ screendata->has_x_flip = false;
+ screendata->has_y_flip = false;
+ screendata->supports_transformations = false;
+
+ screendata->is_primary = true;
+ screendata->is_extended = true;
+ screendata->absolute_x_position = 0;
+ screendata->absolute_y_position = 0;
+ screendata->current_x_pixel_count = 640;
+ screendata->current_y_pixel_count = 480;
+
+ numberOfScreens++;
+ }
+
+ bool primary_set = false;
+ for ( screendata=screenInfoArray.first(); screendata; screendata=screenInfoArray.next() ) {
+ if (screendata->is_primary) {
+ primary_set = true;
+ break;
+ }
+ }
+ // If there is no primary monitor set, xrandr is probably not functioning correctly!
+ Q_ASSERT(primary_set);
+ if (!primary_set) {
+ // [FIXME]
+ // Set this on the real primary monitor only!
+ screendata = screenInfoArray.at(0);
+ screendata->is_primary = true;
+ }
+
+ return screenInfoArray;
+}
+
+TQString KRandrSimpleAPI::clearIccConfiguration() {
+ // Clear ICC settings with XCalib
+ TQString icc_command;
+ FILE *pipe_xcalib;
+ char xcalib_result[2048];
+ int i;
+ xcalib_result[0]=0;
+
+ icc_command = TQString("xcalib -c");
+ if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
+ {
+ printf("Xcalib pipe error [xcalib clear]\n\r");
+ }
+ else {
+ if (fgets(xcalib_result, 2048, pipe_xcalib)) {
+ pclose(pipe_xcalib);
+ for (i=1;i<2048;i++) {
+ if (xcalib_result[i] == 0) {
+ xcalib_result[i-1]=0;
+ i=2048;
+ }
+ }
+ if (strlen(xcalib_result) > 2) {
+ return xcalib_result;
+ }
+ }
+ else {
+ return "";
+ }
+ }
+ return "";
+}
+
+ScreenInfo* KRandrSimpleAPI::read_screen_info (Display *display)
+{
+ return internal_read_screen_info(display);
+}
+
+int KRandrSimpleAPI::set_screen_size (ScreenInfo *screen_info)
+{
+ return internal_set_screen_size(screen_info);
+}
+
+void KRandrSimpleAPI::output_auto (ScreenInfo *screen_info, OutputInfo *output_info)
+{
+ internal_output_auto (screen_info, output_info);
+}
+
+void KRandrSimpleAPI::output_off(ScreenInfo *screen_info, OutputInfo *output)
+{
+ internal_output_off(screen_info, output);
+}
+
+CrtcInfo* KRandrSimpleAPI::auto_find_crtc (ScreenInfo *screen_info, OutputInfo *output_info)
+{
+ return internal_auto_find_crtc (screen_info, output_info);
+}
+
+XRRModeInfo *KRandrSimpleAPI::find_mode_by_xid (ScreenInfo *screen_info, RRMode mode_id)
+{
+ return internal_find_mode_by_xid (screen_info, mode_id);
+}
+
+int KRandrSimpleAPI::mode_height (XRRModeInfo *mode_info, Rotation rotation)
+{
+ return internal_mode_height (mode_info, rotation);
+}
+
+int KRandrSimpleAPI::mode_width (XRRModeInfo *mode_info, Rotation rotation)
+{
+ return internal_mode_width (mode_info, rotation);
+}
+
+int KRandrSimpleAPI::get_width_by_output_id (ScreenInfo *screen_info, RROutput output_id)
+{
+ return internal_get_width_by_output_id (screen_info, output_id);
+}
+
+int KRandrSimpleAPI::get_height_by_output_id (ScreenInfo *screen_info, RROutput output_id)
+{
+ return internal_get_height_by_output_id (screen_info, output_id);
+}
+
+char *KRandrSimpleAPI::get_output_name (ScreenInfo *screen_info, RROutput id)
+{
+ return internal_get_output_name (screen_info, id);
+}
+
+Status KRandrSimpleAPI::crtc_apply (CrtcInfo *crtc_info)
+{
+ return internal_crtc_apply (crtc_info);
+}
+
+Status KRandrSimpleAPI::crtc_disable (CrtcInfo *crtc)
+{
+ return internal_crtc_disable (crtc);
+}
+
+int KRandrSimpleAPI::main_low_apply (ScreenInfo *screen_info)
+{
+ return internal_main_low_apply (screen_info);
+}
+
+void KRandrSimpleAPI::set_primary_output (ScreenInfo *screen_info, RROutput output_id)
+{
+ internal_output_set_primary(screen_info, output_id);
+}
+
+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/tderandr/libtderandr.h b/tderandr/libtderandr.h
new file mode 100644
index 000000000..b2b362a90
--- /dev/null
+++ b/tderandr/libtderandr.h
@@ -0,0 +1,359 @@
+/* libtderandr.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
+ LibKRandr's homepage : http://www.trinitydesktop.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.
+
+ 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 <tqfile.h>
+
+#include <kconfig.h>
+#include <ksimpleconfig.h>
+#include <tdelibs_export.h>
+
+#define ROTATION_0_DEGREES_STRING "0 degrees"
+#define ROTATION_90_DEGREES_STRING "90 degrees"
+#define ROTATION_180_DEGREES_STRING "180 degrees"
+#define ROTATION_270_DEGREES_STRING "270 degrees"
+
+/**
+ * Simple API covering most of the uses of libtderandr.
+ *
+ * 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 libtderandr.
+ * @version 0.9.5 27/04/2010
+ * @author Timothy Pearson <kb9vqf@pearsoncomputing.net>
+ */
+class KRANDR_EXPORT KRandrSimpleAPI : public RandRDisplay
+{
+ private:
+
+ public:
+ /**
+ * Retrieves the specificed ICC profile filename from the configuration database
+ */
+ TQString getIccFileName(TQString profileName, TQString screenName, TQString kde_confdir);
+
+ /**
+ * Applies the specificed ICC profile filename to the specified RandR output
+ * If RandR is not available, the specified file is applied to the current display
+ */
+ TQString applyIccFile(TQString screenName, TQString fileName);
+
+ /**
+ * Applies all saved ICC profile settings to all RandR outputs
+ * If RandR is not available, the settings are applied to the current display
+ */
+ TQString applyIccConfiguration(TQString profileName, TQString kde_confdir);
+
+ /**
+ * Applies saved system wide settings to the current display
+ */
+ TQString applySystemWideIccConfiguration(TQString kde_confdir);
+
+ /**
+ * Resets the current display
+ */
+ TQString clearIccConfiguration(void);
+
+ /**
+ * Retrieves current profile name
+ */
+ TQString getCurrentProfile(void);
+
+ /**
+ * Reads current screen information.
+ * NOTE: The caller is responsible for calling freeScreenInfoStructure() when done
+ */
+ ScreenInfo* read_screen_info(Display *display);
+
+ /**
+ * Frees the ScreenInfo structure
+ */
+ void freeScreenInfoStructure(ScreenInfo* screen_info);
+
+ /**
+ * 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);
+
+ /**
+ * Sets the primary output device to the specified output_id
+ */
+ void set_primary_output (ScreenInfo *screen_info, RROutput output_id);
+
+ /**
+ * Gets the binary monitor EDID for the specified card and display
+ */
+ TQByteArray getEDID(int card, TQString displayname);
+
+ /**
+ * Gets the monitor EDID name for the specified card and display
+ */
+ TQString getEDIDMonitorName(int card, TQString displayname);
+
+ /**
+ * Returns true if the specified configuration directory has enabled display configuration
+ */
+ bool getDisplayConfigurationEnabled(TQString kde_confdir);
+
+ /**
+ * Returns true if the specified configuration directory has enabled automatic profile application on startup
+ */
+ bool getDisplayConfigurationStartupAutoApplyEnabled(TQString kde_confdir);
+
+ /**
+ * Returns the name of the automatically applied startup profile in the specified configuration directory
+ */
+ TQString getDisplayConfigurationStartupAutoApplyName(TQString kde_confdir);
+
+ /**
+ * Returns a HotPlugRulesList containing all hotplug rules from the specified configuration directory
+ */
+ HotPlugRulesList getHotplugRules(TQString kde_confdir);
+
+ /**
+ * Saves a HotPlugRulesList containing all hotplug rules to the specified configuration directory
+ */
+ void saveHotplugRules(HotPlugRulesList rules, TQString kde_confdir);
+
+ /**
+ * Applies all hotplug rules in the specified configuration directory to the current display configuration
+ */
+ void applyHotplugRules(TQString kde_confdir);
+
+ /**
+ * Returns a list of all profiles available in the specified configuration directory
+ * This list does not include the default ("") profile
+ */
+ TQStringList getDisplayConfigurationProfiles(TQString kde_confdir);
+
+ /**
+ * Deletes the specified profile from the specified configuration directory
+ * Returns true on success, false on failure
+ */
+ bool deleteDisplayConfiguration(TQString profilename, TQString kde_confdir);
+
+ /**
+ * Renames the specified profile in the specified configuration directory
+ * Returns true on success, false on failure
+ */
+ bool renameDisplayConfiguration(TQString profilename, TQString newprofilename, TQString kde_confdir);
+
+ /**
+ * Saves the systemwide display configuration screenInfoArray to the specified profile
+ * If profilename is empty, the default profile is utilized
+ * If enable is set to true, the default profile will be applied at system startup
+ */
+ void saveDisplayConfiguration(bool enable, bool applyonstart, TQString profilename, TQString defaultprofilename, TQString kde_confdir, TQPtrList<SingleScreenData> screenInfoArray);
+
+ /**
+ * Reads the systemwide display configuration screenInfoArray from the specified profile
+ * If profilename is empty, the default profile is utilized
+ * WARNING: The calling application must free the returned objects when it is done using them
+ */
+ TQPtrList<SingleScreenData> loadDisplayConfiguration(TQString profilename, TQString kde_confdir);
+
+ /**
+ * Applies the startup display configuration profile if enabled
+ * Returns the offset of the primary screen's top left corner
+ */
+ TQPoint applyStartupDisplayConfiguration(TQString kde_confdir);
+
+ /**
+ * Applies the systemwide display configuration screenInfoArray from the specified profile
+ * If profilename is empty, the default profile is utilized
+ * Returns the offset of the primary screen's top left corner
+ */
+ TQPoint applyDisplayConfiguration(TQString profilename, TQString kde_confdir);
+
+ /**
+ * Applies the systemwide display configuration screenInfoArray to the hardware
+ * If test is true, the new configuration will be loaded for a short period of time, then reverted automatically
+ * Returns true if configuration was accepted; false if not
+ */
+ bool applyDisplayConfiguration(TQPtrList<SingleScreenData> screenInfoArray, bool test=TRUE, TQString kde_confdir="");
+
+ /**
+ * Applies the gamma contained within the systemwide display configuration screenInfoArray to the hardware
+ */
+ void applyDisplayGamma(TQPtrList<SingleScreenData> screenInfoArray);
+
+ /**
+ * Applies the DPMS settings contained within the systemwide display configuration screenInfoArray to the hardware
+ */
+ void applyDisplayDPMS(TQPtrList<SingleScreenData> screenInfoArray);
+
+ /**
+ * Copies a screen information object
+ */
+ TQPtrList<SingleScreenData> copyScreenInformationObject(TQPtrList<SingleScreenData> screenInfoArray);
+
+ /**
+ * Destroys a screen information object
+ */
+ void destroyScreenInformationObject(TQPtrList<SingleScreenData> screenInfoArray);
+
+ /**
+ * Returns the offset of the primary screen's Top Left Corner
+ */
+ TQPoint primaryScreenOffsetFromTLC(TQPtrList<SingleScreenData> screenInfoArray);
+
+ /**
+ * Ensures that the data contained within screenInfoArray is self consistent
+ */
+ void ensureMonitorDataConsistency(TQPtrList<SingleScreenData> screenInfoArray);
+
+ /**
+ * Reads the current display configuration screenInfoArray from the hardware
+ */
+ TQPtrList<SingleScreenData> readCurrentDisplayConfiguration();
+
+ /**
+ * Returns the hardware rotation flags given a valid SingleScreenData structure
+ */
+ int getHardwareRotationFlags(SingleScreenData*);
+
+ /**
+ * Returns whether or not the system supports XRandR
+ */
+ bool kRandrHasRandr();
+
+ /**
+ * Returns the version number of libtderandr, i.e. "0.9.5" or "1.0 Beta"
+ */
+ static const char *kRandrVersion(void);
+
+ /**
+ * Returns the copyright notice that applications using libtderandr 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/tderandr/lowlevel_randr.c b/tderandr/lowlevel_randr.c
new file mode 100644
index 000000000..c7a2edc2a
--- /dev/null
+++ b/tderandr/lowlevel_randr.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright © 2010 Raptor Engineering
+ * 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 internal_crtc_disable (struct CrtcInfo *crtc);
+
+char * internal_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 * internal_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 * internal_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 internal_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 = internal_find_mode_by_xid (screen_info, mode_id);
+
+ width = internal_mode_width (mode_info, crtc_info->cur_rotation);
+
+ break;
+ }
+ }
+
+ return width;
+}
+
+int internal_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 = internal_find_mode_by_xid (screen_info, mode_id);
+
+ height = internal_mode_height (mode_info, crtc_info->cur_rotation);
+
+ break;
+ }
+ }
+
+ return height;
+}
+
+int internal_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 internal_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 * internal_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 * internal_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 internal_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 = internal_find_mode_by_xid (screen_info, crtc->cur_mode_id);
+ cur_x = crtc->cur_x;
+ cur_y = crtc->cur_y;
+
+ w = internal_mode_width (mode_info, crtc->cur_rotation);
+ h = internal_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 internal_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 internal_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 internal_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 internal_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* internal_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);
+
+ if (sr == NULL) {
+ return NULL;
+ }
+
+ 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 = internal_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 internal_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 internal_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 internal_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 *
+internal_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 *
+internal_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 = internal_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 internal_main_low_apply (struct ScreenInfo *screen_info)
+{
+ int i;
+ struct CrtcInfo *crtc_info;
+
+ /* set_positions (screen_info); */
+
+ if (!internal_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 = internal_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 = internal_mode_width (old_mode, crtc_info->rotation);
+ old_h = internal_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 {
+ internal_crtc_disable (screen_info->crtcs[i]);
+ }
+ }
+
+ internal_screen_apply (screen_info);
+
+ for (i = 0; i < screen_info->n_crtc; i++) {
+ Status s;
+ crtc_info = screen_info->crtcs[i];
+
+ s = internal_crtc_apply (crtc_info);
+ if (RRSetConfigSuccess != s) {
+ fprintf (stderr, "crtc apply error\n");
+ }
+ }
+
+ return 1;
+}
+
+void internal_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 = internal_auto_find_crtc (screen_info, output_info);
+ }
+ }
+
+ mode_info = internal_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 = internal_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 internal_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;
+}
+
+void internal_output_set_primary (struct ScreenInfo *screen_info, RROutput output_id)
+{
+ XRRSetOutputPrimary(screen_info->dpy, screen_info->window, output_id);
+} \ No newline at end of file
diff --git a/tderandr/lowlevel_randr.h b/tderandr/lowlevel_randr.h
new file mode 100644
index 000000000..b5825e450
--- /dev/null
+++ b/tderandr/lowlevel_randr.h
@@ -0,0 +1,103 @@
+/*
+ * 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* internal_read_screen_info (Display *);
+
+int internal_set_screen_size (struct ScreenInfo *screen_info);
+void internal_output_auto (struct ScreenInfo *screen_info, struct OutputInfo *output_info);
+void internal_output_off (struct ScreenInfo *screen_info, struct OutputInfo *output);
+void internal_output_set_primary (struct ScreenInfo *screen_info, RROutput output_id);
+struct CrtcInfo* internal_auto_find_crtc (struct ScreenInfo *screen_info, struct OutputInfo *output_info);
+
+XRRModeInfo *internal_find_mode_by_xid (struct ScreenInfo *screen_info, RRMode mode_id);
+int internal_mode_height (XRRModeInfo *mode_info, Rotation rotation);
+int internal_mode_width (XRRModeInfo *mode_info, Rotation rotation);
+int internal_get_width_by_output_id (struct ScreenInfo *screen_info, RROutput output_id);
+int internal_get_height_by_output_id (struct ScreenInfo *screen_info, RROutput output_id);
+char *internal_get_output_name (struct ScreenInfo *screen_info, RROutput id);
+Status internal_crtc_apply (struct CrtcInfo *crtc_info);
+Status internal_crtc_disable (struct CrtcInfo *crtc);
+int internal_main_low_apply (struct ScreenInfo *screen_info);
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/tderandr/randr.cpp b/tderandr/randr.cpp
new file mode 100644
index 000000000..334da5a79
--- /dev/null
+++ b/tderandr/randr.cpp
@@ -0,0 +1,881 @@
+/*
+ * 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 "lowlevel_randr.h"
+
+#include <tqtimer.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>
+
+HotPlugRule::HotPlugRule()
+{
+ //
+}
+
+HotPlugRule::~HotPlugRule()
+{
+ //
+}
+
+SingleScreenData::SingleScreenData()
+{
+ generic_screen_detected = false;
+ screen_connected = false;
+
+ current_resolution_index = 0;
+ current_refresh_rate_index = 0;
+ current_color_depth_index = 0;
+
+ gamma_red = 0.0;
+ gamma_green = 0.0;
+ gamma_blue = 0.0;
+
+ current_rotation_index = 0;
+ current_orientation_mask = 0;
+ has_x_flip = false;
+ has_y_flip = false;
+ supports_transformations = false;
+
+ is_primary = false;
+ is_extended = false;
+ absolute_x_position = 0;
+ absolute_y_position = 0;
+ current_x_pixel_count = 0;
+ current_y_pixel_count = 0;
+
+ has_dpms = false;
+ enable_dpms = false;
+ dpms_standby_delay = 0;
+ dpms_suspend_delay = 0;
+ dpms_off_delay = 0;
+}
+
+SingleScreenData::~SingleScreenData()
+{
+ //
+}
+
+class RandRScreenPrivate
+{
+public:
+ RandRScreenPrivate() : config(0L) {};
+ ~RandRScreenPrivate()
+ {
+ if (config) {
+ XRRFreeScreenConfigInfo(config);
+ }
+ }
+
+ XRRScreenConfiguration* config;
+};
+
+KDE_EXPORT RandRScreen::RandRScreen(int screenIndex)
+ : d(new RandRScreenPrivate())
+ , m_screen(screenIndex)
+ , m_shownDialog(NULL)
+{
+ loadSettings();
+ setOriginal();
+}
+
+KDE_EXPORT RandRScreen::~RandRScreen()
+{
+ delete d;
+}
+
+KDE_EXPORT void RandRScreen::loadSettings()
+{
+ if (d->config) {
+ XRRFreeScreenConfigInfo(d->config);
+ }
+
+ d->config = XRRGetScreenInfo(tqt_xdisplay(), RootWindow(tqt_xdisplay(), m_screen));
+
+ Rotation rotation;
+ if (d->config) {
+ m_currentSize = m_proposedSize = XRRConfigCurrentConfiguration(d->config, &rotation);
+ m_currentRotation = m_proposedRotation = rotation;
+ }
+ else {
+ m_currentSize = m_proposedSize = 0;
+ m_currentRotation = m_proposedRotation = 0;
+ }
+
+ m_pixelSizes.clear();
+ m_mmSizes.clear();
+
+ if (d->config) {
+ int numSizes;
+ XRRScreenSize* sizes = XRRSizes(tqt_xdisplay(), m_screen, &numSizes);
+ for (int i = 0; i < numSizes; i++) {
+ m_pixelSizes.append(TQSize(sizes[i].width, sizes[i].height));
+ m_mmSizes.append(TQSize(sizes[i].mwidth, sizes[i].mheight));
+ }
+
+ m_rotations = XRRRotations(tqt_xdisplay(), m_screen, &rotation);
+ }
+ else {
+ // Great, now we have to go after the information manually. Ughh.
+ ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay());
+ XRROutputInfo *output_info = screeninfo->outputs[m_screen]->info;
+ CrtcInfo *current_crtc = screeninfo->outputs[m_screen]->cur_crtc;
+ int numSizes = output_info->nmode;
+ for (int i = 0; i < numSizes; i++) {
+ XRRModeInfo *xrrmode;
+ xrrmode = internal_find_mode_by_xid (screeninfo, output_info->modes[i]);
+ TQSize newSize = TQSize(xrrmode->width, xrrmode->height);
+ if (!m_pixelSizes.contains(newSize)) {
+ m_pixelSizes.append(newSize);
+ m_mmSizes.append(TQSize(output_info->mm_width, output_info->mm_height));
+ }
+ }
+ if (current_crtc) {
+ m_rotations = current_crtc->rotations;
+ m_currentRotation = m_proposedRotation = current_crtc->cur_rotation;
+ }
+ }
+
+ if (d->config) {
+ m_currentRefreshRate = m_proposedRefreshRate = refreshRateHzToIndex(m_currentSize, XRRConfigCurrentRate(d->config));
+ }
+ else {
+ m_currentRefreshRate = m_proposedRefreshRate = 0;
+ }
+}
+
+KDE_EXPORT void RandRScreen::setOriginal()
+{
+ m_originalSize = m_currentSize;
+ m_originalRotation = m_currentRotation;
+ m_originalRefreshRate = m_currentRefreshRate;
+}
+
+KDE_EXPORT bool RandRScreen::applyProposed()
+{
+ //kdDebug() << k_funcinfo << " size " << (SizeID)proposedSize() << ", rotation " << proposedRotation() << ", refresh " << refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) << endl;
+
+ Status status;
+
+ if (!d->config) {
+ d->config = XRRGetScreenInfo(tqt_xdisplay(), RootWindow(tqt_xdisplay(), m_screen));
+ Q_ASSERT(d->config);
+ }
+
+ if (d->config) {
+ if (proposedRefreshRate() < 0)
+ status = XRRSetScreenConfig(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), CurrentTime);
+ else {
+ if( refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) <= 0 ) {
+ m_proposedRefreshRate = 0;
+ }
+ status = XRRSetScreenConfigAndRate(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), refreshRateIndexToHz(proposedSize(), proposedRefreshRate()), CurrentTime);
+ }
+ }
+ else {
+ // Great, now we have to set the information manually. Ughh.
+ // FIXME--this does not work!
+ ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay());
+ screeninfo->cur_width = (*m_pixelSizes.at(proposedSize())).width();
+ screeninfo->cur_height = (*m_pixelSizes.at(proposedSize())).height();
+ internal_main_low_apply(screeninfo);
+
+ status = RRSetConfigSuccess;
+ }
+
+ //kdDebug() << "New size: " << WidthOfScreen(ScreenOfDisplay(TQPaintDevice::x11AppDisplay(), screen)) << ", " << HeightOfScreen(ScreenOfDisplay(TQPaintDevice::x11AppDisplay(), screen)) << endl;
+
+ if (status == RRSetConfigSuccess) {
+ m_currentSize = m_proposedSize;
+ m_currentRotation = m_proposedRotation;
+ m_currentRefreshRate = m_proposedRefreshRate;
+ return true;
+ }
+
+ return false;
+}
+
+KDE_EXPORT bool RandRScreen::applyProposedAndConfirm()
+{
+ if (proposedChanged()) {
+ setOriginal();
+
+ if (applyProposed()) {
+ if (!confirm()) {
+ proposeOriginal();
+ applyProposed();
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+KDE_EXPORT bool RandRScreen::confirm()
+{
+ // uncomment the line below and edit out the KTimerDialog stuff to get
+ // a version which works on today's tdelibs (no accept dialog is presented)
+
+ // FIXME remember to put the dialog on the right screen
+
+ KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown,
+ TDEApplication::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, TQT_SIGNAL( destroyed()), this, TQT_SLOT( shownDialogDestroyed()));
+ connect( kapp->desktop(), TQT_SIGNAL( resized(int)), this, TQT_SLOT( desktopResized()));
+
+ return acceptDialog.exec();
+}
+
+KDE_EXPORT void RandRScreen::shownDialogDestroyed()
+{
+ m_shownDialog = NULL;
+ disconnect( kapp->desktop(), TQT_SIGNAL( resized(int)), this, TQT_SLOT( desktopResized()));
+}
+
+KDE_EXPORT void RandRScreen::desktopResized()
+{
+ if( m_shownDialog != NULL )
+ KDialog::centerOnScreen(m_shownDialog, m_screen);
+}
+
+KDE_EXPORT TQString 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());
+}
+
+KDE_EXPORT bool RandRScreen::changedFromOriginal() const
+{
+ return m_currentSize != m_originalSize || m_currentRotation != m_originalRotation || m_currentRefreshRate != m_originalRefreshRate;
+}
+
+KDE_EXPORT void RandRScreen::proposeOriginal()
+{
+ m_proposedSize = m_originalSize;
+ m_proposedRotation = m_originalRotation;
+ m_proposedRefreshRate = m_originalRefreshRate;
+}
+
+KDE_EXPORT bool RandRScreen::proposedChanged() const
+{
+ return m_currentSize != m_proposedSize || m_currentRotation != m_proposedRotation || m_currentRefreshRate != m_proposedRefreshRate;
+}
+
+KDE_EXPORT TQString 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");
+ }
+}
+
+KDE_EXPORT TQPixmap 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");
+ }
+}
+
+KDE_EXPORT TQString RandRScreen::currentRotationDescription() const
+{
+ TQString 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;
+}
+
+KDE_EXPORT 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;
+ }
+}
+
+KDE_EXPORT 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;
+ }
+}
+
+KDE_EXPORT int RandRScreen::currentPixelWidth() const
+{
+ return m_pixelSizes[m_currentSize].width();
+}
+
+KDE_EXPORT int RandRScreen::currentPixelHeight() const
+{
+ return m_pixelSizes[m_currentSize].height();
+}
+
+KDE_EXPORT int RandRScreen::currentMMWidth() const
+{
+ return m_pixelSizes[m_currentSize].width();
+}
+
+KDE_EXPORT int RandRScreen::currentMMHeight() const
+{
+ return m_pixelSizes[m_currentSize].height();
+}
+
+KDE_EXPORT TQStringList RandRScreen::refreshRates(int size) const
+{
+ int nrates;
+ TQStringList ret;
+
+ if (d->config) {
+ short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates);
+
+ for (int i = 0; i < nrates; i++)
+ ret << refreshRateDirectDescription(rates[i]);
+ }
+ else {
+ // Great, now we have to go after the information manually. Ughh.
+ ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay());
+ int numSizes = screeninfo->res->nmode;
+ for (int i = 0; i < numSizes; i++) {
+ int refresh_rate = ((screeninfo->res->modes[i].dotClock*1.0)/((screeninfo->res->modes[i].hTotal)*(screeninfo->res->modes[i].vTotal)*1.0));
+ TQString newRate = refreshRateDirectDescription(refresh_rate);
+ if (!ret.contains(newRate)) {
+ ret.append(newRate);
+ }
+ }
+ }
+
+ return ret;
+}
+
+KDE_EXPORT TQString RandRScreen::refreshRateDirectDescription(int rate) const
+{
+ return i18n("Refresh rate in Hertz (Hz)", "%1 Hz").arg(rate);
+}
+
+KDE_EXPORT TQString RandRScreen::refreshRateIndirectDescription(int size, int index) const
+{
+ return i18n("Refresh rate in Hertz (Hz)", "%1 Hz").arg(refreshRateIndexToHz(size, index));
+}
+
+KDE_EXPORT TQString RandRScreen::refreshRateDescription(int size, int index) const
+{
+ return refreshRates(size)[index];
+}
+
+KDE_EXPORT bool RandRScreen::proposeRefreshRate(int index)
+{
+ if (index >= 0 && (int)refreshRates(proposedSize()).count() > index) {
+ m_proposedRefreshRate = index;
+ return true;
+ }
+
+ return false;
+}
+
+KDE_EXPORT int RandRScreen::currentRefreshRate() const
+{
+ return m_currentRefreshRate;
+}
+
+KDE_EXPORT TQString RandRScreen::currentRefreshRateDescription() const
+{
+ return refreshRateIndirectDescription(m_currentSize, m_currentRefreshRate);
+}
+
+KDE_EXPORT int RandRScreen::proposedRefreshRate() const
+{
+ return m_proposedRefreshRate;
+}
+
+KDE_EXPORT int RandRScreen::refreshRateHzToIndex(int size, int hz) const
+{
+ int nrates;
+ short* rates = XRRRates(tqt_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;
+}
+
+KDE_EXPORT int RandRScreen::refreshRateIndexToHz(int size, int index) const
+{
+ int nrates;
+ short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates);
+
+ if (nrates == 0 || index < 0)
+ return 0;
+
+ // Wrong input Hz!
+ if(index >= nrates)
+ return 0;
+
+ return rates[index];
+}
+
+KDE_EXPORT int RandRScreen::numSizes() const
+{
+ return m_pixelSizes.count();
+}
+
+KDE_EXPORT const TQSize& RandRScreen::pixelSize(int index) const
+{
+ return m_pixelSizes[index];
+}
+
+KDE_EXPORT const TQSize& RandRScreen::mmSize(int index) const
+{
+ return m_mmSizes[index];
+}
+
+KDE_EXPORT int RandRScreen::sizeIndex(TQSize pixelSize) const
+{
+ for (uint i = 0; i < m_pixelSizes.count(); i++)
+ if (m_pixelSizes[i] == pixelSize)
+ return i;
+
+ return -1;
+}
+
+KDE_EXPORT int RandRScreen::rotations() const
+{
+ return m_rotations;
+}
+
+KDE_EXPORT int RandRScreen::currentRotation() const
+{
+ return m_currentRotation;
+}
+
+KDE_EXPORT int RandRScreen::currentSize() const
+{
+ return m_currentSize;
+}
+
+KDE_EXPORT int RandRScreen::proposedRotation() const
+{
+ return m_proposedRotation;
+}
+
+KDE_EXPORT void RandRScreen::proposeRotation(int newRotation)
+{
+ m_proposedRotation = newRotation & OrientationMask;
+}
+
+KDE_EXPORT int RandRScreen::proposedSize() const
+{
+ return m_proposedSize;
+}
+
+KDE_EXPORT bool RandRScreen::proposeSize(int newSize)
+{
+ if ((int)m_pixelSizes.count() > newSize) {
+ m_proposedSize = newSize;
+ return true;
+ }
+
+ return false;
+}
+
+KDE_EXPORT void RandRScreen::load(TDEConfig& config)
+{
+ config.setGroup(TQString("Screen%1").arg(m_screen));
+
+ if (proposeSize(sizeIndex(TQSize(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));
+}
+
+KDE_EXPORT void RandRScreen::save(TDEConfig& config) const
+{
+ config.setGroup(TQString("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);
+}
+
+KDE_EXPORT RandRDisplay::RandRDisplay()
+ : m_valid(true)
+{
+ // Check extension
+ Status s = XRRQueryExtension(tqt_xdisplay(), &m_eventBase, &m_errorBase);
+ if (!s) {
+ m_errorCode = TQString("%1, base %1").arg(s).arg(m_errorBase);
+ m_valid = false;
+ return;
+ }
+
+ // Sometimes the extension is available but does not return any screens (!)
+ // Check for that case
+ Display *randr_display = XOpenDisplay(NULL);
+ int screen_num;
+ Window root_window;
+
+ screen_num = DefaultScreen (randr_display);
+ root_window = RootWindow (randr_display, screen_num);
+ if (XRRGetScreenResources (randr_display, root_window) == NULL) {
+ m_errorCode = i18n("No screens detected");
+ m_valid = false;
+ return;
+ }
+
+ int major_version, minor_version;
+ XRRQueryVersion(tqt_xdisplay(), &major_version, &minor_version);
+
+ m_version = TQString("X Resize and Rotate extension version %1.%1").arg(major_version).arg(minor_version);
+
+ m_numScreens = ScreenCount(tqt_xdisplay());
+
+ // This assumption is WRONG with Xinerama
+ // Q_ASSERT(TQApplication::desktop()->numScreens() == ScreenCount(tqt_xdisplay()));
+
+ m_screens.setAutoDelete(true);
+ for (int i = 0; i < m_numScreens; i++) {
+ m_screens.append(new RandRScreen(i));
+ }
+
+ setCurrentScreen(TQApplication::desktop()->primaryScreen());
+}
+
+KDE_EXPORT bool RandRDisplay::isValid() const
+{
+ return m_valid;
+}
+
+KDE_EXPORT const TQString& RandRDisplay::errorCode() const
+{
+ return m_errorCode;
+}
+
+KDE_EXPORT int RandRDisplay::eventBase() const
+{
+ return m_eventBase;
+}
+
+KDE_EXPORT int RandRDisplay::screenChangeNotifyEvent() const
+{
+ return m_eventBase + RRScreenChangeNotify;
+}
+
+KDE_EXPORT int RandRDisplay::errorBase() const
+{
+ return m_errorBase;
+}
+
+KDE_EXPORT const TQString& RandRDisplay::version() const
+{
+ return m_version;
+}
+
+KDE_EXPORT void RandRDisplay::setCurrentScreen(int index)
+{
+ m_currentScreenIndex = index;
+ m_currentScreen = m_screens.at(m_currentScreenIndex);
+ Q_ASSERT(m_currentScreen);
+}
+
+KDE_EXPORT int RandRDisplay::screenIndexOfWidget(TQWidget* widget)
+{
+ int ret = TQApplication::desktop()->screenNumber(widget);
+ return ret != -1 ? ret : TQApplication::desktop()->primaryScreen();
+}
+
+KDE_EXPORT int RandRDisplay::currentScreenIndex() const
+{
+ return m_currentScreenIndex;
+}
+
+KDE_EXPORT void RandRDisplay::refresh()
+{
+ for (RandRScreen* s = m_screens.first(); s; s = m_screens.next())
+ s->loadSettings();
+}
+
+KDE_EXPORT int RandRDisplay::numScreens() const
+{
+ return m_numScreens;
+}
+
+KDE_EXPORT RandRScreen* RandRDisplay::screen(int index)
+{
+ return m_screens.at(index);
+}
+
+KDE_EXPORT RandRScreen* RandRDisplay::currentScreen()
+{
+ return m_currentScreen;
+}
+
+KDE_EXPORT bool RandRDisplay::loadDisplay(TDEConfig& config, bool loadScreens)
+{
+ if (loadScreens)
+ for (RandRScreen* s = m_screens.first(); s; s = m_screens.next())
+ s->load(config);
+
+ return applyOnStartup(config);
+}
+
+KDE_EXPORT bool RandRDisplay::applyOnStartup(TDEConfig& config)
+{
+ config.setGroup("Display");
+ return config.readBoolEntry("ApplyOnStartup", false);
+}
+
+KDE_EXPORT bool RandRDisplay::syncTrayApp(TDEConfig& config)
+{
+ config.setGroup("Display");
+ return config.readBoolEntry("SyncTrayApp", false);
+}
+
+KDE_EXPORT void RandRDisplay::saveDisplay(TDEConfig& 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);
+}
+
+KDE_EXPORT 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();
+ }
+ }
+}
+
+KDE_EXPORT bool RandRDisplay::showTestConfigurationDialog()
+{
+ RandRScreen* firstScreen = screen(0);
+ if (firstScreen) {
+ return firstScreen->showTestConfigurationDialog();
+ }
+ else {
+ return false;
+ }
+}
+
+KDE_EXPORT bool RandRScreen::showTestConfigurationDialog()
+{
+ // uncomment the line below and edit out the KTimerDialog stuff to get
+ // a version which works on today's tdelibs (no accept dialog is presented)
+
+ // FIXME remember to put the dialog on the right screen
+
+ KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown,
+ TDEApplication::kApplication()->mainWidget(),
+ "mainKTimerDialog",
+ true,
+ i18n("Confirm Display Settings"),
+ 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 display devices has been configured "
+ "to match the settings shown above. 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, 0);
+
+ m_shownDialog = &acceptDialog;
+ connect( m_shownDialog, TQT_SIGNAL( destroyed()), this, TQT_SLOT( shownDialogDestroyed()));
+ connect( kapp->desktop(), TQT_SIGNAL( resized(int)), this, TQT_SLOT( desktopResized()));
+
+ return acceptDialog.exec();
+}
+
+KDE_EXPORT int RandRScreen::pixelCount( int index ) const
+{
+ TQSize sz = pixelSize(index);
+ return sz.width() * sz.height();
+}
+
+#include "randr.moc"
diff --git a/tderandr/randr.h b/tderandr/randr.h
new file mode 100644
index 000000000..af3712e71
--- /dev/null
+++ b/tderandr/randr.h
@@ -0,0 +1,302 @@
+/*
+ * 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 <tqobject.h>
+#include <tqstringlist.h>
+#include <tqptrlist.h>
+
+#include <tdecmodule.h>
+#include <kconfig.h>
+
+class KTimerDialog;
+class RandRScreenPrivate;
+
+class KRANDR_EXPORT HotPlugRule {
+ public:
+ enum states {
+ AnyState = 0,
+ Connected = 1,
+ Disconnected = 2
+ };
+
+ public:
+ HotPlugRule();
+ virtual ~HotPlugRule();
+
+ public:
+ TQStringList outputs;
+ TQValueList< int > states;
+ TQString profileName;
+};
+
+typedef TQValueList< HotPlugRule > HotPlugRulesList;
+
+class KRANDR_EXPORT SingleScreenData {
+ public:
+ SingleScreenData();
+ virtual ~SingleScreenData();
+
+ public:
+ TQString screenUniqueName;
+ TQString screenFriendlyName;
+ bool generic_screen_detected;
+ bool screen_connected;
+
+ TQStringList resolutions;
+ TQStringList refresh_rates;
+ TQStringList color_depths;
+ TQStringList rotations;
+
+ int current_resolution_index;
+ int current_refresh_rate_index;
+ int current_color_depth_index;
+
+ float gamma_red;
+ float gamma_green;
+ float gamma_blue;
+
+ int current_rotation_index;
+ int current_orientation_mask;
+ bool has_x_flip;
+ bool has_y_flip;
+ bool supports_transformations;
+
+ bool is_primary;
+ bool is_extended;
+ int absolute_x_position;
+ int absolute_y_position;
+ int current_x_pixel_count;
+ int current_y_pixel_count;
+
+ bool has_dpms;
+ bool enable_dpms;
+ unsigned int dpms_standby_delay;
+ unsigned int dpms_suspend_delay;
+ unsigned int dpms_off_delay;
+};
+
+class RandRScreen : public TQObject
+{
+ 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();
+ bool showTestConfigurationDialog();
+
+public:
+ TQString changedMessage() const;
+
+ bool changedFromOriginal() const;
+ void proposeOriginal();
+
+ bool proposedChanged() const;
+
+ static TQString rotationName(int rotation, bool pastTense = false, bool capitalised = true);
+ TQPixmap rotationIcon(int rotation) const;
+ TQString currentRotationDescription() const;
+
+ int rotationIndexToDegree(int rotation) const;
+ int rotationDegreeToIndex(int degree) const;
+
+ /**
+ * Refresh rate functions.
+ */
+ TQStringList refreshRates(int size) const;
+
+ TQString refreshRateDirectDescription(int rate) const;
+ TQString refreshRateIndirectDescription(int size, int index) const;
+ TQString refreshRateDescription(int size, int index) const;
+
+ int currentRefreshRate() const;
+ TQString 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 TQSize& pixelSize(int index) const;
+ const TQSize& 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(TQSize 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(TDEConfig& config);
+ void save(TDEConfig& config) const;
+
+private:
+ RandRScreenPrivate* d;
+
+ int m_screen;
+
+ TQValueList<TQSize> m_pixelSizes;
+ TQValueList<TQSize> 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 TQPtrList<RandRScreen> ScreenList;
+
+class RandRDisplay
+{
+public:
+ RandRDisplay();
+
+ bool isValid() const;
+ const TQString& errorCode() const;
+ const TQString& version() const;
+
+ int eventBase() const;
+ int screenChangeNotifyEvent() const;
+ int errorBase() const;
+
+ int screenIndexOfWidget(TQWidget* 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 TDEConfig 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(TDEConfig& config, bool loadScreens = true);
+ void saveDisplay(TDEConfig& config, bool applyOnStartup, bool syncTrayApp);
+
+ static bool applyOnStartup(TDEConfig& config);
+ static bool syncTrayApp(TDEConfig& config);
+
+ void applyProposed(bool confirm = true);
+
+ bool showTestConfigurationDialog();
+
+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