You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kgamma/kcmkgamma/kgamma.cpp

626 lines
19 KiB

/***************************************************************************
kgamma.cpp - description
-------------------
begin : Sun Dec 16 13:52:24 CET 2001
copyright : (C) 2001 by Michael v.Ostheim
email : MvOstheim@web.de
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include <unistd.h>
#include <tqlabel.h>
#include <tqpixmap.h>
#include <tqstring.h>
#include <layout.h>
#include <tqstringlist.h>
#include <tqdir.h>
#include <tqcheckbox.h>
#include <tqcombobox.h>
#include <tqwidgetstack.h>
#include <kstandarddirs.h>
#include <kconfig.h>
#include <klocale.h>
#include <kglobal.h>
#include <kprocess.h>
#include <kdialog.h>
#include <kgenericfactory.h>
#include "config.h"
#include "xf86configpath.h"
#include "gammactrl.h"
#include "xvidextwrap.h"
#include "kgamma.h"
#include "kgamma.moc"
typedef KGenericFactory<KGamma, TQWidget> KGammaFactory;
K_EXPORT_COMPONENT_FACTORY ( kcm_kgamma, KGammaFactory( "kgamma" ) )
extern "C"
{
bool test_kgamma()
{
bool retval;
(void) new XVidExtWrap(&retval, NULL);
return retval;
}
}
KGamma::KGamma(TQWidget *parent, const char *name, const TQStringList&)
:KCModule(parent,name)
{
bool ok;
GammaCorrection = true;
xv = new XVidExtWrap(&ok, NULL);
if (ok) { /* KDE 4: Uneccessary test, when all KCM wrappers do conditional loading */
xv->getGamma(XVidExtWrap::Red, &ok);
if (ok) {
ScreenCount = xv->_ScreenCount();
currentScreen = xv->getScreen();
xv->setGammaLimits(0.4, 3.5);
for (int i = 0; i < ScreenCount; i++ ) {
assign << 0;
rgamma << "";
ggamma << "";
bgamma << "";
// Store the current gamma values
xv->setScreen(i);
rbak << xv->getGamma(XVidExtWrap::Red);
gbak << xv->getGamma(XVidExtWrap::Green);
bbak << xv->getGamma(XVidExtWrap::Blue);
}
xv->setScreen(currentScreen);
rootProcess = new KProcess;
setupUI();
saved = false;
if (!loadSettings()) { //try to load gamma values from config file
// if failed, take current gamma values
for (int i = 0; i < ScreenCount; i++ ) {
rgamma[i].setNum(rbak[i], 'f', 2);
ggamma[i].setNum(gbak[i], 'f', 2);
bgamma[i].setNum(bbak[i], 'f', 2);
}
}
load();
}
else { //something is wrong, show only error message
GammaCorrection = false;
setupUI();
}
}
}
KGamma::~KGamma() {
// Restore the old gamma settings, if the user has not saved
// and there is no valid kgammarc.
// Existing user settings overwrite system settings
if (GammaCorrection) {
if ( loadUserSettings() ) load();
else if ( !saved )
for (int i = 0; i < ScreenCount; i++ ) {
xv->setScreen(i);
xv->setGamma( XVidExtWrap::Red, rbak[i] );
xv->setGamma( XVidExtWrap::Green, gbak[i] );
xv->setGamma( XVidExtWrap::Blue, bbak[i] );
}
delete rootProcess;
}
delete xv;
}
/** User interface */
void KGamma::setupUI() {
TQBoxLayout *topLayout = new TQVBoxLayout(this, 0, KDialog::spacingHint());
if (GammaCorrection) {
TQHBoxLayout *hbox = new TQHBoxLayout( topLayout );
TQLabel *label = new TQLabel( i18n( "&Select test picture:" ) , this);
TQComboBox *combo = new TQComboBox( this );
label->setBuddy( combo );
TQStringList list;
list << i18n( "Gray Scale" )
<< i18n( "RGB Scale" )
<< i18n( "CMY Scale" )
<< i18n( "Dark Gray" )
<< i18n( "Mid Gray" )
<< i18n( "Light Gray" );
combo->insertStringList( list );
hbox->addWidget( label );
hbox->addWidget( combo );
hbox->addStretch();
TQWidgetStack *stack = new TQWidgetStack( this );
stack->setFrameStyle( TQFrame::Box | TQFrame::Raised );
connect( combo, TQT_SIGNAL( activated( int ) ),
stack, TQT_SLOT( raiseWidget( int ) ) );
TQPixmap background;
background.load(locate("data", "kgamma/pics/background.png"));
TQLabel *pic1 = new TQLabel(stack);
pic1->setMinimumSize(530, 171);
pic1->setBackgroundPixmap(background);
pic1->setPixmap(TQPixmap(locate("data", "kgamma/pics/greyscale.png")));
pic1->setAlignment(AlignCenter);
stack->addWidget( pic1, 0 );
TQLabel *pic2 = new TQLabel(stack);
pic2->setBackgroundPixmap(background);
pic2->setPixmap(TQPixmap(locate("data", "kgamma/pics/rgbscale.png")));
pic2->setAlignment(AlignCenter);
stack->addWidget( pic2, 1 );
TQLabel *pic3 = new TQLabel(stack);
pic3->setBackgroundPixmap(background);
pic3->setPixmap(TQPixmap(locate("data", "kgamma/pics/cmyscale.png")));
pic3->setAlignment(AlignCenter);
stack->addWidget( pic3, 2 );
TQLabel *pic4 = new TQLabel(stack);
pic4->setBackgroundPixmap(background);
pic4->setPixmap(TQPixmap(locate("data", "kgamma/pics/darkgrey.png")));
pic4->setAlignment(AlignCenter);
stack->addWidget( pic4, 3 );
TQLabel *pic5 = new TQLabel(stack);
pic5->setBackgroundPixmap(background);
pic5->setPixmap(TQPixmap(locate("data", "kgamma/pics/midgrey.png")));
pic5->setAlignment(AlignCenter);
stack->addWidget( pic5, 4 );
TQLabel *pic6 = new TQLabel(stack);
pic6->setBackgroundPixmap(background);
pic6->setPixmap(TQPixmap(locate("data", "kgamma/pics/lightgrey.png")));
pic6->setAlignment(AlignCenter);
stack->addWidget( pic6, 5 );
topLayout->addWidget(stack, 10);
//Sliders for gamma correction
TQFrame *frame1 = new TQFrame(this);
frame1->setFrameStyle( TQFrame::GroupBoxPanel | TQFrame::Plain );
TQFrame *frame2 = new TQFrame(this);
frame2->setFrameStyle( TQFrame::GroupBoxPanel | TQFrame::Plain );
TQLabel *gammalabel = new TQLabel(this);
gammalabel->setText(i18n("Gamma:"));
TQLabel *redlabel = new TQLabel(this);
redlabel->setText(i18n("Red:"));
TQLabel *greenlabel = new TQLabel(this);
greenlabel->setText(i18n("Green:"));
TQLabel *bluelabel = new TQLabel(this);
bluelabel->setText(i18n("Blue:"));
gctrl = new GammaCtrl(this, xv);
connect(gctrl, TQT_SIGNAL(gammaChanged(int)), TQT_SLOT(Changed()));
connect(gctrl, TQT_SIGNAL(gammaChanged(int)), TQT_SLOT(SyncScreens()));
gammalabel->setBuddy( gctrl );
rgctrl = new GammaCtrl(this, xv, XVidExtWrap::Red);
connect(rgctrl, TQT_SIGNAL(gammaChanged(int)), TQT_SLOT(Changed()));
connect(rgctrl, TQT_SIGNAL(gammaChanged(int)), TQT_SLOT(SyncScreens()));
connect(gctrl, TQT_SIGNAL(gammaChanged(int)), rgctrl, TQT_SLOT(setCtrl(int)));
connect(rgctrl, TQT_SIGNAL(gammaChanged(int)), gctrl, TQT_SLOT(suspend()));
redlabel->setBuddy( rgctrl );
ggctrl = new GammaCtrl(this, xv, XVidExtWrap::Green);
connect(ggctrl, TQT_SIGNAL(gammaChanged(int)), TQT_SLOT(Changed()));
connect(ggctrl, TQT_SIGNAL(gammaChanged(int)), TQT_SLOT(SyncScreens()));
connect(gctrl, TQT_SIGNAL(gammaChanged(int)), ggctrl, TQT_SLOT(setCtrl(int)));
connect(ggctrl, TQT_SIGNAL(gammaChanged(int)), gctrl, TQT_SLOT(suspend()));
greenlabel->setBuddy( ggctrl );
bgctrl = new GammaCtrl(this, xv, XVidExtWrap::Blue);
connect(bgctrl, TQT_SIGNAL(gammaChanged(int)), TQT_SLOT(Changed()));
connect(bgctrl, TQT_SIGNAL(gammaChanged(int)), TQT_SLOT(SyncScreens()));
connect(gctrl, TQT_SIGNAL(gammaChanged(int)), bgctrl, TQT_SLOT(setCtrl(int)));
connect(bgctrl, TQT_SIGNAL(gammaChanged(int)), gctrl, TQT_SLOT(suspend()));
bluelabel->setBuddy( bgctrl );
TQGridLayout *grid = new TQGridLayout(4, 9);
grid->setSpacing(8);
grid->addMultiCellWidget(frame1, 0, 2, 0, 3);
grid->addMultiCellWidget(frame2, 4, 8, 0, 3);
grid->addWidget(gammalabel, 1, 1, TQt::AlignRight);
grid->addWidget(redlabel, 5, 1, TQt::AlignRight);
grid->addWidget(greenlabel, 6, 1, TQt::AlignRight);
grid->addWidget(bluelabel, 7, 1, TQt::AlignRight);
grid->addWidget(gctrl, 1, 2);
grid->addWidget(rgctrl, 5, 2);
grid->addWidget(ggctrl, 6, 2);
grid->addWidget(bgctrl, 7, 2);
topLayout->addLayout(grid);
//Options
TQHBox *options = new TQHBox(this);
xf86cfgbox = new TQCheckBox( i18n("Save settings to XF86Config"), options );
connect(xf86cfgbox, TQT_SIGNAL(clicked()), TQT_SLOT(changeConfig()));
syncbox = new TQCheckBox( i18n("Sync screens"), options );
connect(syncbox, TQT_SIGNAL(clicked()), TQT_SLOT(SyncScreens()));
connect(syncbox, TQT_SIGNAL(clicked()), TQT_SLOT(Changed()));
screenselect = new TQComboBox( options );
for ( int i = 0; i < ScreenCount; i++ )
screenselect->insertItem( i18n("Screen %1").arg(i+1) );
screenselect->setCurrentItem(currentScreen);
connect(screenselect, TQT_SIGNAL(activated(int)), TQT_SLOT(changeScreen(int)));
options->setSpacing( 10 );
options->setStretchFactor( xf86cfgbox, 10 );
options->setStretchFactor( syncbox, 1 );
options->setStretchFactor( screenselect, 1 );
topLayout->addWidget(options);
}
else {
TQLabel *error = new TQLabel(this);
error->setText(i18n("Gamma correction is not supported by your"
" graphics hardware or driver."));
error->setAlignment(AlignCenter);
topLayout->addWidget(error);
}
}
void KGamma::load() {
load( false );
}
/** Restore latest saved gamma values */
void KGamma::load(bool useDefaults) {
if (GammaCorrection) {
KConfig *config = new KConfig("kgammarc");
config->setReadDefaults( useDefaults );
config->setGroup("ConfigFile");
// save checkbox status
if ( xf86cfgbox->isChecked() ) config->writeEntry("use", "XF86Config");
else config->writeEntry("use", "kgammarc");
// load syncbox status
config->setGroup("SyncBox");
if ( config->readEntry("sync") == "yes" ) syncbox->setChecked(true);
else syncbox->setChecked(false);
config->sync();
delete config;
for (int i = 0; i < ScreenCount; i++) {
xv->setScreen(i);
if (rgamma[i] == ggamma[i] && rgamma[i] == bgamma[i])
if (i == currentScreen) gctrl->setGamma(rgamma[i]);
else xv->setGamma(XVidExtWrap::Value, rgamma[i].toFloat());
else {
if (i == currentScreen) {
rgctrl->setGamma(rgamma[i]);
ggctrl->setGamma(ggamma[i]);
bgctrl->setGamma(bgamma[i]);
gctrl->suspend();
}
else {
xv->setGamma(XVidExtWrap::Red, rgamma[i].toFloat());
xv->setGamma(XVidExtWrap::Green, ggamma[i].toFloat());
xv->setGamma(XVidExtWrap::Blue, bgamma[i].toFloat());
}
}
}
xv->setScreen(currentScreen);
emit changed(useDefaults);
}
}
void KGamma::save() {
if (GammaCorrection) {
for (int i = 0; i < ScreenCount; i++) {
xv->setScreen(i);
rgamma[i] = rgctrl->gamma(2);
ggamma[i] = ggctrl->gamma(2);
bgamma[i] = bgctrl->gamma(2);
}
xv->setScreen(currentScreen);
KConfig *config = new KConfig("kgammarc");
config->setGroup("SyncBox");
if ( syncbox->isChecked() ) config->writeEntry("sync", "yes");
else config->writeEntry("sync", "no");
if ( !xf86cfgbox->isChecked() ) { //write gamma settings to the users config
for (int i = 0; i < ScreenCount; i++) {
config->setGroup( TQString("Screen %1").arg(i) );
config->writeEntry("rgamma", rgamma[i]);
config->writeEntry("ggamma", ggamma[i]);
config->writeEntry("bgamma", bgamma[i]);
}
config->setGroup("ConfigFile");
config->writeEntry("use", "kgammarc");
}
else { // write gamma settings to section "Monitor" of XF86Config
config->setGroup("ConfigFile");
config->writeEntry("use", "XF86Config");
if ( !rootProcess->isRunning() ) {
TQString Arguments = "xf86gammacfg ";
for (int i = 0; i < ScreenCount; i++)
Arguments += rgamma[assign[i]] + " " + ggamma[assign[i]] + " " + \
bgamma[assign[i]] + " ";
rootProcess->clearArguments();
*rootProcess << "tdesu" << Arguments;
rootProcess->start();
}
}
config->sync();
delete config;
saved = true;
emit changed(false);
}
}
void KGamma::defaults() {
load( true );
}
bool KGamma::loadSettings() {
KConfig *config = new KConfig("kgammarc");
config->setGroup("ConfigFile");
TQString ConfigFile( config->readEntry("use") );
config->setGroup("SyncBox");
if ( config->readEntry("sync") == "yes" ) syncbox->setChecked(true);
delete config;
if ( ConfigFile == "XF86Config" ) { // parse XF86Config
xf86cfgbox->setChecked(true);
return( loadSystemSettings() );
}
else { //get gamma settings from user config
return( loadUserSettings() );
}
}
bool KGamma::loadUserSettings() {
KConfig *config = new KConfig("kgammarc");
for (int i = 0; i < ScreenCount; i++) {
config->setGroup(TQString( "Screen %1" ).arg(i) );
rgamma[i] = config->readEntry("rgamma");
ggamma[i] = config->readEntry("ggamma");
bgamma[i] = config->readEntry("bgamma");
}
delete config;
return( validateGammaValues() );
}
bool KGamma::loadSystemSettings() {
TQStringList Monitor, Screen, ScreenLayout, ScreenMonitor, Gamma;
TQValueList<int> ScreenNr;
TQString Section;
XF86ConfigPath Path;
TQFile f( Path.get() );
if ( f.open(IO_ReadOnly) ) {
TQTextStream t( &f );
TQString s;
int sn = 0;
bool gm = false;
// Analyse Screen<->Monitor assignments of multi-head configurations
while ( !t.eof() ) {
s = (t.readLine()).simplifyWhiteSpace();
TQStringList words = TQStringList::split(' ', s);
if ( !words.empty() ) {
if ( words[0] == "Section" && words.size() > 1 ) {
if ( (Section = words[1]) == "\"Monitor\"" ) gm = false;
}
else if ( words[0] == "EndSection" ) {
if ( Section == "\"Monitor\"" && !gm ) {
Gamma << "";
gm = false;
}
Section = "";
}
else if ( words[0] == "Identifier" && words.size() > 1 ) {
if ( Section == "\"Monitor\"" ) Monitor << words[1];
else if ( Section == "\"Screen\"" ) Screen << words[1];
}
else if ( words[0] == "Screen" && words.size() > 1 ) {
if ( Section == "\"ServerLayout\"" ) {
bool ok;
int i = words[1].toInt(&ok);
if ( ok && words.size() > 2 ) {
ScreenNr << i;
ScreenLayout << words[2];
}
else {
ScreenNr << sn++;
ScreenLayout << words[1];
}
}
}
else if ( words[0] == "Monitor" && words.size() > 1 ) {
if ( Section == "\"Screen\"" )
ScreenMonitor << words[1];
}
else if ( words[0] == "Gamma" ) {
if ( Section == "\"Monitor\"" ) {
Gamma << s;
gm = true;
}
}
}
} // End while
f.close();
for ( int i = 0; i < ScreenCount; i++ ) {
for ( int j = 0; j < ScreenCount; j++ ) {
if ( ScreenLayout[i] == Screen[j] ) {
for ( int k = 0; k < ScreenCount; k++ ) {
if ( Monitor[k] == ScreenMonitor[j] )
assign[ScreenNr[i]] = k;
}
}
}
}
// Extract gamma values
for ( int i = 0; i < ScreenCount; i++) {
rgamma[i] = ggamma[i] = bgamma[i] = "";
TQStringList words = TQStringList::split(' ', Gamma[assign[i]]);
TQStringList::ConstIterator it = words.begin();
if ( words.size() < 4 )
rgamma[i] = ggamma[i] = bgamma[i] = *(++it); // single gamma value
else {
rgamma[i] = *(++it); // eventually rgb gamma values
ggamma[i] = *(++it);
bgamma[i] = *(++it);
}
}
}
return( validateGammaValues() );
}
bool KGamma::validateGammaValues() {
bool rOk, gOk, bOk, result;
result = true;
for (int i = 0; i < ScreenCount; i++ ) {
rgamma[i].toFloat( &rOk );
ggamma[i].toFloat( &gOk );
bgamma[i].toFloat( &bOk );
if ( !(rOk && gOk && bOk) ) {
if ( rOk ) ggamma[i] = bgamma[i] = rgamma[i];
else result = false;
}
}
return(result);
}
void KGamma::changeConfig() {
bool Ok = false;
if ( xf86cfgbox->isChecked() ) Ok = loadSystemSettings();
else Ok = loadUserSettings();
if ( !Ok ) {
for (int i = 0; i < ScreenCount; i++ ) {
xv->setScreen(i);
rgamma[i].setNum(xv->getGamma(XVidExtWrap::Red), 'f', 2);
ggamma[i].setNum(xv->getGamma(XVidExtWrap::Green), 'f', 2);
bgamma[i].setNum(xv->getGamma(XVidExtWrap::Blue), 'f', 2);
}
xv->setScreen(currentScreen);
}
load();
}
void KGamma::SyncScreens() {
if ( syncbox->isChecked() ) {
float rg = xv->getGamma(XVidExtWrap::Red);
float gg = xv->getGamma(XVidExtWrap::Green);
float bg = xv->getGamma(XVidExtWrap::Blue);
for (int i = 0; i < ScreenCount; i++ ) {
if ( i != currentScreen ) {
xv->setScreen(i);
xv->setGamma(XVidExtWrap::Red, rg);
xv->setGamma(XVidExtWrap::Green, gg);
xv->setGamma(XVidExtWrap::Blue, bg);
}
}
xv->setScreen(currentScreen);
}
}
void KGamma::changeScreen(int sn) {
TQString red, green, blue;
xv->setScreen(sn);
currentScreen = sn;
red.setNum(xv->getGamma(XVidExtWrap::Red), 'f', 2);
green.setNum(xv->getGamma(XVidExtWrap::Green), 'f', 2);
blue.setNum(xv->getGamma(XVidExtWrap::Blue), 'f', 2);
gctrl->setControl(red);
rgctrl->setControl(red);
ggctrl->setControl(green);
bgctrl->setControl(blue);
if (red != green || red != blue) gctrl->suspend();
}
int KGamma::buttons () {
return Default|Apply|Help;
}
TQString KGamma::quickHelp() const
{
return i18n("<h1>Monitor Gamma</h1> This is a tool for changing monitor gamma"
" correction. Use the four sliders to define the gamma correction either"
" as a single value, or separately for the red, green and blue components."
" You may need to correct the brightness and contrast settings of your"
" monitor for good results. The test images help you to find proper"
" settings.<br> You can save them system-wide to XF86Config (root access"
" is required for that) or to your own KDE settings. On multi head"
" systems you can correct the gamma values separately for all screens.");
}
// ------------------------------------------------------------------------
extern "C"
{
// Restore the user gamma settings
void init_kgamma()
{
bool ok;
XVidExtWrap xv(&ok);
if (ok) {
xv.setGammaLimits(0.4, 3.5);
float rgamma, ggamma, bgamma;
KConfig *config = new KConfig("kgammarc");
for (int i = 0; i < xv._ScreenCount(); i++) {
xv.setScreen(i);
config->setGroup( TQString("Screen %1").arg(i) );
if ((rgamma = config->readEntry("rgamma").toFloat()))
xv.setGamma(XVidExtWrap::Red, rgamma);
if ((ggamma = config->readEntry("ggamma").toFloat()))
xv.setGamma(XVidExtWrap::Green, ggamma);
if ((bgamma = config->readEntry("bgamma").toFloat()))
xv.setGamma(XVidExtWrap::Blue, bgamma);
}
delete config;
}
}
}