• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tderandr
 

tderandr

libtderandr.cc

00001 /*  libtderandr.cc     - class KRandr that makes it easy to use XRandr in KDE
00002     This file is part of KRandr 0.9.5
00003     Copyright (C) 2010  Timothy Pearson
00004     LibKRandr's homepage : http://www.trinitydesktop.org
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020 
00021     Send comments and bug fixes to Timothy Pearson <kb9vqf@pearsoncomputing.net>
00022 
00023 ***************************************************************************/
00024 
00025 #include <tqdir.h>
00026 #include <tqtimer.h>
00027 #include <tqstringlist.h>
00028 #include <tqregexp.h>
00029 
00030 #include <tdelocale.h>
00031 #include <tdemessagebox.h>
00032 #include <tdeapplication.h>
00033 
00034 #include <stdlib.h>
00035 #include <unistd.h>
00036 #include <cmath>
00037 
00038 #include "libtderandr.h"
00039 
00040 #include <X11/extensions/dpms.h>
00041 
00042 // FIXME
00043 // For now, just use the standalone xrandr program to apply the display settings
00044 #define USE_XRANDR_PROGRAM
00045 
00046 // This routine is courtsey of an answer on "Stack Overflow"
00047 // It takes an LSB-first int and makes it an MSB-first int (or vice versa)
00048 unsigned int reverse_bits(register unsigned int x)
00049 {
00050     x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
00051     x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
00052     x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
00053     x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
00054     return((x >> 16) | (x << 16));
00055 }
00056 
00057 // This routine returns the output of an arbitrary Bash command
00058 TQString exec(const char * cmd) {
00059     TQString bashcommand = cmd;
00060     bashcommand = bashcommand.replace("\"", "\\\"");
00061     bashcommand = TQString("/bin/bash -c \"%1\" 2>&1").arg(bashcommand);
00062     FILE* pipe = popen(bashcommand.ascii(), "r");
00063     if (!pipe) return "ERROR";
00064     char buffer[128];
00065     TQString result = "";
00066     while(!feof(pipe)) {
00067         if(fgets(buffer, 128, pipe) != NULL) {
00068             result += buffer;
00069         }
00070     }
00071     pclose(pipe);
00072     result.remove(result.length(), 1);
00073     return result;
00074 }
00075 
00076 TQString capitalizeString(TQString in) {
00077     return in.left(1).upper() + in.right(in.length()-1);
00078 }
00079 
00080 TQString KRandrSimpleAPI::getIccFileName(TQString profileName, TQString screenName, TQString kde_confdir) {
00081     KSimpleConfig *t_config = NULL;
00082     KSimpleConfig *t_systemconfig = NULL;
00083     int t_numberOfProfiles;
00084     TQStringList t_cfgProfiles;
00085     TQString retval;
00086 
00087     if ((profileName != NULL) && (profileName != "")) {
00088         t_config = new KSimpleConfig( TQString::fromLatin1( "kiccconfigrc" ));
00089         t_config->setGroup(NULL);
00090         if (t_config->readBoolEntry("EnableICC", false) == true) {
00091             t_config->setGroup(profileName);
00092             retval = t_config->readEntry(screenName);
00093         }
00094         else {
00095             retval = "";
00096         }
00097         delete t_config;
00098     }
00099     else {
00100         t_systemconfig = new KSimpleConfig( kde_confdir + TQString("/kicc/kiccconfigrc") );
00101         t_systemconfig->setGroup(NULL);
00102         if (t_systemconfig->readBoolEntry("EnableICC", false) == true) {
00103             retval = t_systemconfig->readEntry("ICCFile");
00104         }
00105         else {
00106             retval = "";
00107         }
00108         delete t_systemconfig;
00109     }
00110 
00111     return retval;
00112 }
00113 
00114 TQString KRandrSimpleAPI::applyIccFile(TQString screenName, TQString fileName) {
00115     int i;
00116     int j;
00117     Display *randr_display;
00118     ScreenInfo *randr_screen_info;
00119     XRROutputInfo *output_info;
00120 
00121     int screenNumber = 0;
00122 
00123     if (fileName != "") {
00124         // FIXME
00125         // This should use the RRSetCrtcGamma function when available
00126         // That is the only way to get proper setting when two output are active at the same time
00127         // (otherwise in clone mode only one screen is available)
00128 
00129         // HACK
00130         // For now, simply exit with no changes if screenName is not an active output
00131 
00132         if (isValid() == true) {
00133             screenNumber = -1;
00134             randr_display = tqt_xdisplay();
00135             randr_screen_info = read_screen_info(randr_display);
00136             if (randr_screen_info == NULL) {
00137                 return "";
00138             }
00139             j=0;
00140             for (i = 0; i < randr_screen_info->n_output; i++) {
00141                 output_info = randr_screen_info->outputs[i]->info;
00142                 // Look for ON outputs...
00143                 if (!randr_screen_info->outputs[i]->cur_crtc) {
00144                     continue;
00145                 }
00146                 // ...that are connected
00147                 if (RR_Disconnected == randr_screen_info->outputs[i]->info->connection) {
00148                     continue;
00149                 }
00150                 if (output_info->name == screenName) {
00151                     screenNumber = j;
00152                 }
00153                 j++;
00154             }
00155             freeScreenInfoStructure(randr_screen_info);
00156         }
00157 
00158         if (screenNumber >= 0) {
00159             // Apply ICC settings with XCalib
00160             TQString icc_command;
00161             FILE *pipe_xcalib;
00162             char xcalib_result[2048];
00163             int i;
00164             xcalib_result[0]=0;
00165 
00166             icc_command = TQString("xcalib \"%1\"").arg(fileName);
00167             if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
00168             {
00169                 printf("Xcalib pipe error\n [xcalib apply]");
00170             }
00171             else {
00172                 if (fgets(xcalib_result, 2048, pipe_xcalib)) {
00173                     pclose(pipe_xcalib);
00174                     for (i=1;i<2048;i++) {
00175                         if (xcalib_result[i] == 0) {
00176                             xcalib_result[i-1]=0;
00177                             i=2048;
00178                         }
00179                     }
00180                     if (strlen(xcalib_result) > 2) {
00181                         return xcalib_result;
00182                     }
00183                 }
00184                 else {
00185                     return "";
00186                 }
00187             }
00188         }
00189     }
00190     else {
00191         // Reset ICC profile on this screen
00192 
00193         // FIXME
00194         // This should use the RRSetCrtcGamma function when available
00195         // That is the only way to get proper setting when two output are active at the same time
00196         // (otherwise in clone mode only one screen is available)
00197 
00198         // HACK
00199         // For now, simply exit with no changes if screenName is not an active output
00200 
00201         if (isValid() == true) {
00202             screenNumber = -1;
00203             randr_display = tqt_xdisplay();
00204             randr_screen_info = read_screen_info(randr_display);
00205             if (randr_screen_info == NULL) {
00206                 return "";
00207             }
00208             j=0;
00209             for (i = 0; i < randr_screen_info->n_output; i++) {
00210                 output_info = randr_screen_info->outputs[i]->info;
00211                 // Look for ON outputs...
00212                 if (!randr_screen_info->outputs[i]->cur_crtc) {
00213                     continue;
00214                 }
00215                 // ...that are connected
00216                 if (RR_Disconnected == randr_screen_info->outputs[i]->info->connection) {
00217                     continue;
00218                 }
00219                 if (output_info->name == screenName) {
00220                     screenNumber = j;
00221                 }
00222                 j++;
00223             }
00224             freeScreenInfoStructure(randr_screen_info);
00225         }
00226 
00227         if (screenNumber >= 0) {
00228             // Apply ICC settings with XCalib
00229             TQString icc_command;
00230             FILE *pipe_xcalib;
00231             char xcalib_result[2048];
00232             int i;
00233             xcalib_result[0]=0;
00234 
00235             icc_command = TQString("xcalib -c");
00236             if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
00237             {
00238                 printf("Xcalib pipe error\n [xcalib clear]");
00239             }
00240             else {
00241                 if (fgets(xcalib_result, 2048, pipe_xcalib)) {
00242                     pclose(pipe_xcalib);
00243                     for (i=1;i<2048;i++) {
00244                         if (xcalib_result[i] == 0) {
00245                             xcalib_result[i-1]=0;
00246                             i=2048;
00247                         }
00248                     }
00249                     if (strlen(xcalib_result) > 2) {
00250                         return xcalib_result;
00251                     }
00252                 }
00253                 else {
00254                     return "";
00255                 }
00256             }
00257         }
00258     }
00259     return "";
00260 }
00261 
00262 TQString KRandrSimpleAPI::applyIccConfiguration(TQString profileName, TQString kde_confdir) {
00263     int i;
00264     Display *randr_display;
00265     ScreenInfo *randr_screen_info;
00266     XRROutputInfo *output_info;
00267     KSimpleConfig *t_config;
00268 
00269     int screenNumber = 0;
00270     TQString errorstr = "";
00271 
00272     t_config = new KSimpleConfig( TQString::fromLatin1( "kiccconfigrc" ));
00273 
00274     // Find all screens
00275     if (isValid() == true) {
00276         randr_display = tqt_xdisplay();
00277         randr_screen_info = read_screen_info(randr_display);
00278         if (randr_screen_info == NULL) {
00279             return "";
00280         }
00281         for (i = 0; i < randr_screen_info->n_output; i++) {
00282             output_info = randr_screen_info->outputs[i]->info;
00283             errorstr = applyIccFile(output_info->name, getIccFileName(profileName, output_info->name, kde_confdir));
00284             if (errorstr != "") {
00285                 return errorstr;
00286             }
00287         }
00288         freeScreenInfoStructure(randr_screen_info);
00289     }
00290     else {
00291         return applyIccFile(getIccFileName(profileName, "Default", kde_confdir), "Default");
00292     }
00293 
00294     t_config->writeEntry("CurrentProfile", profileName);
00295     t_config->sync();
00296     delete t_config;
00297 
00298     return "";
00299 }
00300 
00301 TQString KRandrSimpleAPI::getEDIDMonitorName(int card, TQString displayname) {
00302     TQString edid;
00303     TQByteArray binaryedid = getEDID(card, displayname);
00304     if (binaryedid.isNull())
00305         return TQString();
00306 
00307     // Get the manufacturer ID
00308     unsigned char letter_1 = ((binaryedid[8]>>2) & 0x1F) + 0x40;
00309     unsigned char letter_2 = (((binaryedid[8] & 0x03) << 3) | ((binaryedid[9]>>5) & 0x07)) + 0x40;
00310     unsigned char letter_3 = (binaryedid[9] & 0x1F) + 0x40;
00311     TQChar qletter_1 = TQChar(letter_1);
00312     TQChar qletter_2 = TQChar(letter_2);
00313     TQChar qletter_3 = TQChar(letter_3);
00314     TQString manufacturer_id = TQString("%1%2%3").arg(qletter_1).arg(qletter_2).arg(qletter_3);
00315 
00316     // Get the model ID
00317     unsigned int raw_model_id = (((binaryedid[10] << 8) | binaryedid[11]) << 16) & 0xFFFF0000;
00318     // Reverse the bit order
00319     unsigned int model_id = reverse_bits(raw_model_id);
00320 
00321     // Try to get the model name
00322     bool has_friendly_name = false;
00323     unsigned char descriptor_block[18];
00324     int i;
00325     for (i=72;i<90;i++) {
00326         descriptor_block[i-72] = binaryedid[i] & 0xFF;
00327     }
00328     if ((descriptor_block[0] != 0) || (descriptor_block[1] != 0) || (descriptor_block[3] != 0xFC)) {
00329         for (i=90;i<108;i++) {
00330             descriptor_block[i-90] = binaryedid[i] & 0xFF;
00331         }
00332         if ((descriptor_block[0] != 0) || (descriptor_block[1] != 0) || (descriptor_block[3] != 0xFC)) {
00333             for (i=108;i<126;i++) {
00334                 descriptor_block[i-108] = binaryedid[i] & 0xFF;
00335             }
00336         }
00337     }
00338 
00339     TQString monitor_name;
00340     if ((descriptor_block[0] == 0) && (descriptor_block[1] == 0) && (descriptor_block[3] == 0xFC)) {
00341         char* pos = strchr((char *)(descriptor_block+5), '\n');
00342         if (pos) {
00343             *pos = 0;
00344             has_friendly_name = true;
00345             monitor_name = TQString((char *)(descriptor_block+5));
00346         }
00347         else {
00348             has_friendly_name = false;
00349         }
00350     }
00351 
00352     // [FIXME]
00353     // Look up manudacturer names if possible!
00354 
00355     if (has_friendly_name)
00356         edid = TQString("%1 %2").arg(manufacturer_id).arg(monitor_name);
00357     else
00358         edid = TQString("%1 0x%2").arg(manufacturer_id).arg(model_id, 0, 16);
00359 
00360     return edid;
00361 }
00362 
00363 TQByteArray KRandrSimpleAPI::getEDID(int card, TQString displayname) {
00364     TQFile file(TQString("/sys/class/drm/card%1-%2/edid").arg(card).arg(displayname));
00365     if (!file.open (IO_ReadOnly))
00366         return TQByteArray();
00367     TQByteArray binaryedid = file.readAll();
00368     file.close();
00369     return binaryedid;
00370 }
00371 
00372 TQString KRandrSimpleAPI::getCurrentProfile () {
00373     TQString profileName;
00374     KSimpleConfig *t_config;
00375 
00376     t_config = new KSimpleConfig( TQString::fromLatin1( "kiccconfigrc" ));
00377     profileName = t_config->readEntry("CurrentProfile");
00378     delete t_config;
00379     return profileName;
00380 }
00381 
00382 TQString KRandrSimpleAPI::applySystemWideIccConfiguration(TQString kde_confdir) {
00383     // Apply ICC settings with XCalib
00384     TQString icc_command;
00385     FILE *pipe_xcalib;
00386     char xcalib_result[2048];
00387     int i;
00388     xcalib_result[0]=0;
00389 
00390     icc_command = TQString("xcalib \"%1\"").arg(getIccFileName(NULL, "Default", kde_confdir));
00391     if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
00392     {
00393         printf("Xcalib pipe error [xcalib apply]\n");
00394     }
00395     else {
00396         if (fgets(xcalib_result, 2048, pipe_xcalib)) {
00397             pclose(pipe_xcalib);
00398             for (i=1;i<2048;i++) {
00399                 if (xcalib_result[i] == 0) {
00400                     xcalib_result[i-1]=0;
00401                     i=2048;
00402                 }
00403             }
00404             if (strlen(xcalib_result) > 2) {
00405                 return xcalib_result;
00406             }
00407         }
00408         else {
00409             return "";
00410         }
00411     }
00412     return "";
00413 }
00414 
00415 TQStringList KRandrSimpleAPI::getDisplayConfigurationProfiles(TQString kde_confdir) {
00416     TQStringList ret;
00417 
00418     TQDir d(kde_confdir + "/displayconfig/");
00419     d.setFilter(TQDir::Files);
00420     d.setSorting(TQDir::Name);
00421 
00422     const TQFileInfoList *list = d.entryInfoList();
00423     if (list) {
00424         TQFileInfoListIterator it(*list);
00425         TQFileInfo *fi;
00426 
00427         while ((fi = it.current()) != 0) {
00428             if (fi->fileName() != "default") {
00429                 ret.append(fi->fileName());
00430             }
00431             ++it;
00432         }
00433     }
00434 
00435     return ret;
00436 }
00437 
00438 bool KRandrSimpleAPI::deleteDisplayConfiguration(TQString profilename, TQString kde_confdir) {
00439     TQString fileName = kde_confdir + "/displayconfig/";
00440     fileName.append(profilename);
00441     return (!unlink(fileName.ascii()));
00442 }
00443 
00444 bool KRandrSimpleAPI::renameDisplayConfiguration(TQString profilename, TQString newprofilename, TQString kde_confdir) {
00445     TQString fileName = kde_confdir + "/displayconfig/";
00446     TQString newFileName = fileName;
00447     fileName.append(profilename);
00448     newFileName.append(newprofilename);
00449     TQDir d(kde_confdir + "/displayconfig/");
00450     return (d.rename(fileName, newFileName));
00451 }
00452 
00453 void KRandrSimpleAPI::saveDisplayConfiguration(bool enable, bool applyonstart, TQString profilename, TQString defaultprofilename, TQString kde_confdir, TQPtrList<SingleScreenData> screenInfoArray) {
00454     int i;
00455 
00456     TQString filename;
00457 
00458     filename = "displayglobals";
00459     filename.prepend(kde_confdir.append("/"));
00460     KSimpleConfig* display_config = new KSimpleConfig( filename );
00461     display_config->setGroup("General");
00462     display_config->writeEntry("EnableDisplayControl", enable);
00463     display_config->writeEntry("ApplySettingsOnStart", applyonstart);
00464     display_config->writeEntry("StartupProfileName", defaultprofilename);
00465     display_config->sync();
00466     delete display_config;
00467 
00468     filename = profilename;
00469     if (filename == "") {
00470         filename = "default";
00471     }
00472     filename.prepend(kde_confdir.append("/displayconfig/"));
00473 
00474     display_config = new KSimpleConfig( filename );
00475 
00476     i=0;
00477     SingleScreenData *screendata;
00478     for ( screendata=screenInfoArray.first(); screendata; screendata=screenInfoArray.next() ) {
00479         display_config->setGroup(TQString("SCREEN %1").arg(i));
00480         display_config->writeEntry("ScreenUniqueName", screendata->screenUniqueName);
00481         display_config->writeEntry("ScreenFriendlyName", screendata->screenFriendlyName);
00482         display_config->writeEntry("GenericScreenDetected", screendata->generic_screen_detected);
00483         display_config->writeEntry("ScreenConnected", screendata->screen_connected);
00484         display_config->writeEntry("Resolutions", screendata->resolutions);
00485         display_config->writeEntry("RefreshRates", screendata->refresh_rates);
00486         display_config->writeEntry("ColorDepths", screendata->color_depths);
00487         display_config->writeEntry("AvailableRotations", screendata->rotations);
00488         display_config->writeEntry("CurrentResolution", screendata->current_resolution_index);
00489         display_config->writeEntry("CurrentRefreshRate", screendata->current_refresh_rate_index);
00490         display_config->writeEntry("CurrentColorDepth", screendata->current_color_depth_index);
00491         display_config->writeEntry("CurrentRotation", screendata->current_rotation_index);
00492         display_config->writeEntry("CurrentOrientiation", screendata->current_orientation_mask);
00493         display_config->writeEntry("GammaRed", screendata->gamma_red);
00494         display_config->writeEntry("GammaGreen", screendata->gamma_green);
00495         display_config->writeEntry("GammaBlue", screendata->gamma_blue);
00496         display_config->writeEntry("CurrentXFlip", screendata->has_x_flip);
00497         display_config->writeEntry("CurrentYFlip", screendata->has_y_flip);
00498         display_config->writeEntry("SupportsTransformation", screendata->supports_transformations);
00499         display_config->writeEntry("IsPrimary", screendata->is_primary);
00500         display_config->writeEntry("IsExtended", screendata->is_extended);
00501         display_config->writeEntry("AbsXPos", screendata->absolute_x_position);
00502         display_config->writeEntry("AbsYPos", screendata->absolute_y_position);
00503         display_config->writeEntry("CurrentXPixelCount", screendata->current_x_pixel_count);
00504         display_config->writeEntry("CurrentYPixelCount", screendata->current_y_pixel_count);
00505         display_config->writeEntry("HasDPMS", screendata->has_dpms);
00506         display_config->writeEntry("EnableDPMS", screendata->enable_dpms);
00507         display_config->writeEntry("DPMSStandbyDelay", screendata->dpms_standby_delay);
00508         display_config->writeEntry("DPMSSuspendDelay", screendata->dpms_suspend_delay);
00509         display_config->writeEntry("DPMSPowerDownDelay", screendata->dpms_off_delay);
00510         i++;
00511     }
00512 
00513     display_config->sync();
00514     delete display_config;
00515 }
00516 
00517 TQPoint KRandrSimpleAPI::applyStartupDisplayConfiguration(TQString kde_confdir) {
00518     bool applyonstart = getDisplayConfigurationStartupAutoApplyEnabled(kde_confdir);
00519     if (applyonstart) {
00520         TQString profilename = getDisplayConfigurationStartupAutoApplyName(kde_confdir);
00521         return applyDisplayConfiguration(profilename, kde_confdir);
00522     }
00523     else {
00524         return TQPoint();
00525     }
00526 }
00527 
00528 TQPoint KRandrSimpleAPI::applyDisplayConfiguration(TQString profilename, TQString kde_confdir) {
00529     TQPoint ret;
00530 
00531     bool enabled = getDisplayConfigurationEnabled(kde_confdir);
00532     if (profilename == "") {
00533         profilename = "default";
00534     }
00535 
00536     if (enabled) {
00537         TQPtrList<SingleScreenData> screenInfoArray;
00538         screenInfoArray = loadDisplayConfiguration(profilename, kde_confdir);
00539         if (screenInfoArray.count() > 0) {
00540             applyDisplayConfiguration(screenInfoArray, FALSE, kde_confdir);
00541         }
00542         destroyScreenInformationObject(screenInfoArray);
00543         screenInfoArray = readCurrentDisplayConfiguration();
00544         ensureMonitorDataConsistency(screenInfoArray);
00545         ret = primaryScreenOffsetFromTLC(screenInfoArray);
00546         destroyScreenInformationObject(screenInfoArray);
00547     }
00548 
00549     return ret;
00550 }
00551 
00552 TQPtrList<SingleScreenData> KRandrSimpleAPI::loadDisplayConfiguration(TQString profilename, TQString kde_confdir) {
00553     int i;
00554 
00555     TQString filename;
00556     filename = profilename;
00557     if (filename == "") {
00558         filename = "default";
00559     }
00560     filename.prepend(kde_confdir.append("/displayconfig/"));
00561 
00562     KSimpleConfig* display_config = new KSimpleConfig( filename );
00563 
00564     TQStringList grouplist = display_config->groupList();
00565     SingleScreenData *screendata;
00566     TQPtrList<SingleScreenData> screenInfoArray;
00567     for ( TQStringList::Iterator it = grouplist.begin(); it != grouplist.end(); ++it ) {
00568         if ((*it).startsWith("SCREEN ")) {
00569             display_config->setGroup(*it);
00570             i = ((*it).remove("SCREEN ")).toInt();
00571             screendata = new SingleScreenData;
00572             screenInfoArray.append(screendata);
00573             screendata->screenUniqueName = display_config->readEntry("ScreenUniqueName");
00574             screendata->screenFriendlyName = display_config->readEntry("ScreenFriendlyName");
00575             screendata->generic_screen_detected = display_config->readBoolEntry("GenericScreenDetected");
00576             screendata->screen_connected = display_config->readBoolEntry("ScreenConnected");
00577             screendata->resolutions = display_config->readListEntry("Resolutions");
00578             screendata->refresh_rates = display_config->readListEntry("RefreshRates");
00579             screendata->color_depths = display_config->readListEntry("ColorDepths");
00580             screendata->rotations = display_config->readListEntry("AvailableRotations");
00581             screendata->current_resolution_index = display_config->readNumEntry("CurrentResolution");
00582             screendata->current_refresh_rate_index = display_config->readNumEntry("CurrentRefreshRate");
00583             screendata->current_color_depth_index = display_config->readNumEntry("CurrentColorDepth");
00584             screendata->current_rotation_index = display_config->readNumEntry("CurrentRotation");
00585             screendata->current_orientation_mask = display_config->readNumEntry("CurrentOrientiation");
00586             screendata->gamma_red = display_config->readDoubleNumEntry("GammaRed");
00587             screendata->gamma_green = display_config->readDoubleNumEntry("GammaGreen");
00588             screendata->gamma_blue = display_config->readDoubleNumEntry("GammaBlue");
00589             screendata->has_x_flip = display_config->readBoolEntry("CurrentXFlip");
00590             screendata->has_y_flip = display_config->readBoolEntry("CurrentYFlip");
00591             screendata->supports_transformations = display_config->readBoolEntry("SupportsTransformation");
00592             screendata->is_primary = display_config->readBoolEntry("IsPrimary");
00593             screendata->is_extended = display_config->readBoolEntry("IsExtended");
00594             screendata->absolute_x_position = display_config->readNumEntry("AbsXPos");
00595             screendata->absolute_y_position = display_config->readNumEntry("AbsYPos");
00596             screendata->current_x_pixel_count = display_config->readNumEntry("CurrentXPixelCount");
00597             screendata->current_y_pixel_count = display_config->readNumEntry("CurrentYPixelCount");
00598             screendata->has_dpms = display_config->readBoolEntry("HasDPMS");
00599             screendata->enable_dpms = display_config->readBoolEntry("EnableDPMS");
00600             screendata->dpms_standby_delay = display_config->readNumEntry("DPMSStandbyDelay");
00601             screendata->dpms_suspend_delay = display_config->readNumEntry("DPMSSuspendDelay");
00602             screendata->dpms_off_delay = display_config->readNumEntry("DPMSPowerDownDelay");
00603         }
00604     }
00605 
00606     delete display_config;
00607 
00608     return screenInfoArray;
00609 }
00610 
00611 int KRandrSimpleAPI::getHardwareRotationFlags(SingleScreenData* screendata) {
00612     int rotationFlags = 0;
00613     TQString rotationDesired = *screendata->rotations.at(screendata->current_rotation_index);
00614     if (rotationDesired == ROTATION_0_DEGREES_STRING) {
00615         rotationFlags = rotationFlags | RandRScreen::Rotate0;
00616     }
00617     else if (rotationDesired == ROTATION_90_DEGREES_STRING) {
00618         rotationFlags = rotationFlags | RandRScreen::Rotate90;
00619     }
00620     else if (rotationDesired == ROTATION_180_DEGREES_STRING) {
00621         rotationFlags = rotationFlags | RandRScreen::Rotate180;
00622     }
00623     else if (rotationDesired == ROTATION_270_DEGREES_STRING) {
00624         rotationFlags = rotationFlags | RandRScreen::Rotate270;
00625     }
00626     if (screendata->has_x_flip) {
00627         rotationFlags = rotationFlags | RandRScreen::ReflectX;
00628     }
00629     if (screendata->has_y_flip) {
00630         rotationFlags = rotationFlags | RandRScreen::ReflectY;
00631     }
00632     return rotationFlags;
00633 }
00634 
00635 #define USE_XRANDR_PROGRAM
00636 
00637 bool KRandrSimpleAPI::applyDisplayConfiguration(TQPtrList<SingleScreenData> screenInfoArray, bool test, TQString kde_confdir) {
00638     int i;
00639     int j;
00640     bool accepted = true;
00641     Display *randr_display;
00642     XRROutputInfo *output_info;
00643     ScreenInfo *randr_screen_info;
00644 
00645     SingleScreenData *screendata;
00646 
00647     TQPtrList<SingleScreenData> oldconfig;
00648     if (test == TRUE) {
00649         oldconfig = readCurrentDisplayConfiguration();
00650     }
00651 
00652     if (isValid() == true) {
00653 #ifdef USE_XRANDR_PROGRAM
00654         // Assemble the command string for xrandr
00655         TQString command;
00656         command = "xrandr";
00657 
00658         randr_display = tqt_xdisplay();
00659         randr_screen_info = read_screen_info(randr_display);
00660         for (i = 0; i < screenInfoArray.count(); i++) {
00661             screendata = screenInfoArray.at(i);
00662             if (screendata) {
00663                 output_info = randr_screen_info->outputs[i]->info;
00664                 command.append(" --output ").append(output_info->name);
00665                 if (screendata->is_primary || screendata->is_extended) {
00666                     command.append(TQString(" --mode %1x%2").arg(screendata->current_x_pixel_count).arg(screendata->current_y_pixel_count));
00667                     command.append(TQString(" --pos %1x%2").arg(screendata->absolute_x_position).arg(screendata->absolute_y_position));
00668                     command.append(TQString(" --refresh %1").arg(atoi((*screendata->refresh_rates.at(screendata->current_refresh_rate_index)).ascii())));
00669                     command.append(TQString(" --gamma %1:%2:%3").arg(screendata->gamma_red).arg(screendata->gamma_green).arg(screendata->gamma_blue));
00670                     if (screendata->current_rotation_index == 0) command.append(" --rotate ").append("normal");
00671                     if (screendata->current_rotation_index == 1) command.append(" --rotate ").append("left");
00672                     if (screendata->current_rotation_index == 2) command.append(" --rotate ").append("inverted");
00673                     if (screendata->current_rotation_index == 3) command.append(" --rotate ").append("right");
00674                     if ((screendata->has_x_flip == 0) && (screendata->has_y_flip == 0)) command.append(" --reflect ").append("normal");
00675                     if ((screendata->has_x_flip == 1) && (screendata->has_y_flip == 0)) command.append(" --reflect ").append("x");
00676                     if ((screendata->has_x_flip == 0) && (screendata->has_y_flip == 1)) command.append(" --reflect ").append("y");
00677                     if ((screendata->has_x_flip == 1) && (screendata->has_y_flip == 1)) command.append(" --reflect ").append("xy");
00678                     if (screendata->is_primary) {
00679                         command.append(" --primary");
00680                     }
00681                 }
00682                 else {
00683                     command.append(" --off");
00684                 }
00685             }
00686             else {
00687                 printf("[WARNING] Unable to find configuration for monitor %d; settings may not be correctly applied...\n", i); fflush(stdout);
00688             }
00689         }
00690         freeScreenInfoStructure(randr_screen_info);
00691 
00692         TQString xrandr_command_output = exec(command.ascii());
00693         xrandr_command_output = xrandr_command_output.stripWhiteSpace();
00694         if (test) {
00695             // In case gamma settings is not supported, try again without '--gamma' parameter
00696             if (xrandr_command_output == "xrandr: Gamma size is 0.") {
00697                 command = command.replace(TQRegExp("--gamma [0-9\\.]*:[0-9\\.]*:[0-9\\.]*"), "");
00698                 xrandr_command_output = exec(command.ascii());
00699                 xrandr_command_output = xrandr_command_output.stripWhiteSpace();
00700             }
00701             
00702             if(xrandr_command_output.startsWith("xrandr: Failed to get size of gamma for output")) {
00703                 KMessageBox::sorry(0, xrandr_command_output, i18n("Setting gamma failed."));
00704             } else if (xrandr_command_output != "") {
00705                 applyDisplayConfiguration(oldconfig, FALSE, kde_confdir);
00706                 accepted = false;
00707                 destroyScreenInformationObject(oldconfig);
00708                 KMessageBox::sorry(0, xrandr_command_output, i18n("XRandR encountered a problem"));
00709                 return accepted;
00710             }
00711         }
00712 #else
00713         randr_display = tqt_xdisplay();
00714         randr_screen_info = read_screen_info(randr_display);
00715         // Turn off all displays
00716         for (i = 0; i < screenInfoArray.count(); i++) {
00717             screendata = screenInfoArray.at(i);
00718             output_info = randr_screen_info->outputs[i]->info;
00719 
00720             randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
00721             randr_screen_info->cur_output = randr_screen_info->outputs[i];
00722             randr_screen_info->cur_output->auto_set = 0;
00723             randr_screen_info->cur_output->off_set = 1;
00724             output_off (randr_screen_info, randr_screen_info->cur_output);
00725             j=main_low_apply(randr_screen_info);
00726         }
00727         freeScreenInfoStructure(randr_screen_info);
00728         randr_screen_info = read_screen_info(randr_display);
00729         // Turn on the primary display
00730         for (i = 0; i < screenInfoArray.count(); i++) {
00731             screendata = screenInfoArray.at(i);
00732             output_info = randr_screen_info->outputs[i]->info;
00733 
00734             if (screendata->is_primary == true) {
00735                 randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
00736                 randr_screen_info->cur_output = randr_screen_info->outputs[i];
00737                 randr_screen_info->cur_output->auto_set = 1;
00738                 randr_screen_info->cur_output->off_set = 0;
00739                 output_auto (randr_screen_info, randr_screen_info->cur_output);
00740                 j=main_low_apply(randr_screen_info);
00741             }
00742         }
00743         freeScreenInfoStructure(randr_screen_info);
00744         // Handle the remaining displays
00745         randr_screen_info = read_screen_info(randr_display);
00746         for (i = 0; i < screenInfoArray.count(); i++) {
00747             screendata = screenInfoArray.at(i);
00748             output_info = randr_screen_info->outputs[i]->info;
00749 
00750             // Activate or deactivate the screens as necessary
00751             randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
00752             randr_screen_info->cur_output = randr_screen_info->outputs[i];
00753             if (screendata->is_primary == false) {
00754                 if (screendata->is_primary || screendata->is_extended) {
00755                     randr_screen_info->cur_output->auto_set = 1;
00756                     randr_screen_info->cur_output->off_set = 0;
00757                     output_auto (randr_screen_info, randr_screen_info->cur_output);
00758                     j=main_low_apply(randr_screen_info);
00759                 }
00760                 else {
00761                     randr_screen_info->cur_output->auto_set = 0;
00762                     randr_screen_info->cur_output->off_set = 1;
00763                     output_off (randr_screen_info, randr_screen_info->cur_output);
00764                     j=main_low_apply(randr_screen_info);
00765                 }
00766             }
00767         }
00768         freeScreenInfoStructure(randr_screen_info);
00769         randr_screen_info = read_screen_info(randr_display);
00770         for (i = 0; i < screenInfoArray.count(); i++) {
00771             screendata = screenInfoArray.at(i);
00772             output_info = randr_screen_info->outputs[i]->info;
00773 
00774             if (screendata->is_primary || screendata->is_extended) {
00775                 // Set rotation, refresh rate, and size
00776                 RandRScreen *cur_screen = new RandRScreen(i);
00777                 cur_screen->proposeSize(screendata->current_resolution_index);
00778                 cur_screen->proposeRefreshRate(screendata->current_refresh_rate_index);
00779                 cur_screen->proposeRotation(getHardwareRotationFlags(screendata));
00780                 cur_screen->applyProposed();
00781                 delete cur_screen;
00782 
00783                 // Force data reload
00784                 randr_screen_info = read_screen_info(randr_display);
00785                 output_info = randr_screen_info->outputs[i]->info;
00786 
00787                 // Finally, set the screen's position
00788                 randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
00789                 if (randr_screen_info->cur_crtc) {
00790                     randr_screen_info->cur_crtc->cur_x = screendata->absolute_x_position;
00791                     randr_screen_info->cur_crtc->cur_y = screendata->absolute_y_position;
00792                     j=main_low_apply(randr_screen_info);
00793                 }
00794             }
00795         }
00796         freeScreenInfoStructure(randr_screen_info);
00797 #endif
00798     }
00799 
00800     applyDisplayGamma(screenInfoArray);
00801     applyDisplayDPMS(screenInfoArray);
00802     TQString current_icc_profile = getCurrentProfile();
00803     applySystemWideIccConfiguration(kde_confdir);
00804     applyIccConfiguration(current_icc_profile, kde_confdir);
00805 
00806     if (test == TRUE) {
00807         int ret = showTestConfigurationDialog();
00808         if (!ret) {
00809             applyDisplayConfiguration(oldconfig, FALSE, kde_confdir);
00810             accepted = false;
00811         }
00812         destroyScreenInformationObject(oldconfig);
00813     }
00814 
00815     return accepted;
00816 }
00817 
00818 TQPtrList<SingleScreenData> KRandrSimpleAPI::copyScreenInformationObject(TQPtrList<SingleScreenData> screenInfoArray) {
00819     SingleScreenData *origscreendata;
00820     SingleScreenData *copyscreendata;
00821     TQPtrList<SingleScreenData> retArray;
00822     for ( origscreendata = screenInfoArray.first(); origscreendata; origscreendata = screenInfoArray.next() ) {
00823         copyscreendata = new SingleScreenData;
00824         *copyscreendata = *origscreendata;
00825         retArray.append(copyscreendata);
00826     }
00827     return retArray;
00828 }
00829 
00830 void KRandrSimpleAPI::destroyScreenInformationObject(TQPtrList<SingleScreenData> screenInfoArray) {
00831     SingleScreenData *screendata;
00832     for ( screendata = screenInfoArray.first(); screendata; screendata = screenInfoArray.next() ) {
00833         screenInfoArray.remove(screendata);
00834         delete screendata;
00835     }
00836 }
00837 
00838 void KRandrSimpleAPI::ensureMonitorDataConsistency(TQPtrList<SingleScreenData> screenInfoArray) {
00839     int i;
00840     SingleScreenData *screendata;
00841 
00842     int numberOfScreens = screenInfoArray.count();
00843 
00844     for (i=0;i<numberOfScreens;i++) {
00845         screendata = screenInfoArray.at(i);
00846         if (!screendata->screen_connected) {
00847             screendata->is_primary = false;
00848             screendata->is_extended = false;
00849         }
00850     }
00851 
00852     bool has_primary_monitor = false;
00853     for (i=0;i<numberOfScreens;i++) {
00854         screendata = screenInfoArray.at(i);
00855         if (screendata->is_primary) {
00856             has_primary_monitor = true;
00857         }
00858     }
00859     if (!has_primary_monitor) {
00860         for (i=0;i<numberOfScreens;i++) {
00861             screendata = screenInfoArray.at(i);
00862             if (!has_primary_monitor) {
00863                 if (screendata->screen_connected && screendata->is_extended) {
00864                     screendata->is_primary = true;
00865                     screendata->is_extended = true;
00866                     has_primary_monitor = true;
00867                 }
00868             }
00869         }
00870     }
00871     if (!has_primary_monitor) {
00872         for (i=0;i<numberOfScreens;i++) {
00873             screendata = screenInfoArray.at(i);
00874             if (!has_primary_monitor) {
00875                 if (screendata->screen_connected) {
00876                     screendata->is_primary = true;
00877                     screendata->is_extended = true;
00878                     has_primary_monitor = true;
00879                 }
00880             }
00881         }
00882     }
00883 
00884     bool found_first_primary_monitor = false;
00885     for (i=0;i<numberOfScreens;i++) {
00886         screendata = screenInfoArray.at(i);
00887         if (screendata->is_primary) {
00888             if (!found_first_primary_monitor) {
00889                 found_first_primary_monitor = true;
00890             }
00891             else {
00892                 screendata->is_primary = false;
00893             }
00894         }
00895     }
00896 
00897     for (i=0;i<numberOfScreens;i++) {
00898         screendata = screenInfoArray.at(i);
00899         if (screendata->is_primary) {
00900             screendata->is_extended = true;
00901         }
00902     }
00903 
00904     for (i=0;i<numberOfScreens;i++) {
00905         screendata = screenInfoArray.at(i);
00906         TQString resolutionstring = screendata->resolutions[screendata->current_resolution_index];
00907         int separator_pos = resolutionstring.find(" x ");
00908         TQString x_res_string = resolutionstring.left(separator_pos);
00909         TQString y_res_string = resolutionstring.right(resolutionstring.length()-separator_pos-3);
00910         screendata->current_x_pixel_count = x_res_string.toInt();
00911         screendata->current_y_pixel_count = y_res_string.toInt();
00912         screendata->current_orientation_mask = getHardwareRotationFlags(screendata);
00913     }
00914 
00915     // Each screen's absolute position is given relative to the primary monitor
00916     // Fix up the absolute positions
00917     int primary_offset_x = 0;
00918     int primary_offset_y = 0;
00919     for (i=0;i<numberOfScreens;i++) {
00920         screendata = screenInfoArray.at(i);
00921         if (screendata->is_primary) {
00922             primary_offset_x = screendata->absolute_x_position;
00923             primary_offset_y = screendata->absolute_y_position;
00924             primary_offset_x = primary_offset_x * (-1);
00925             primary_offset_y = primary_offset_y * (-1);
00926         }
00927     }
00928     for (i=0;i<numberOfScreens;i++) {
00929         screendata = screenInfoArray.at(i);
00930         screendata->absolute_x_position = screendata->absolute_x_position + primary_offset_x;
00931         screendata->absolute_y_position = screendata->absolute_y_position + primary_offset_y;
00932     }
00933 }
00934 
00935 TQPoint KRandrSimpleAPI::primaryScreenOffsetFromTLC(TQPtrList<SingleScreenData> screenInfoArray) {
00936     int i;
00937     SingleScreenData *screendata;
00938     int numberOfScreens = screenInfoArray.count();
00939 
00940     int primary_offset_x = 0;
00941     int primary_offset_y = 0;
00942     for (i=0;i<numberOfScreens;i++) {
00943         screendata = screenInfoArray.at(i);
00944         if (screendata->absolute_x_position < primary_offset_x) {
00945             primary_offset_x = screendata->absolute_x_position;
00946         }
00947         if (screendata->absolute_y_position < primary_offset_y) {
00948             primary_offset_y = screendata->absolute_y_position;
00949         }
00950     }
00951     primary_offset_x = primary_offset_x * (-1);
00952     primary_offset_y = primary_offset_y * (-1);
00953 
00954     return TQPoint(primary_offset_x, primary_offset_y);
00955 }
00956 
00957 HotPlugRulesList KRandrSimpleAPI::getHotplugRules(TQString kde_confdir) {
00958     int i;
00959     TQString filename;
00960     HotPlugRulesList ret;
00961 
00962     filename = "displayglobals";
00963     filename.prepend(kde_confdir.append("/"));
00964     KSimpleConfig* display_config = new KSimpleConfig( filename );
00965 
00966     TQStringList grouplist = display_config->groupList();
00967     for ( TQStringList::Iterator it = grouplist.begin(); it != grouplist.end(); ++it ) {
00968         if (!(*it).startsWith("Hotplug-Rule")) {
00969             continue;
00970         }
00971         HotPlugRule rule;
00972         display_config->setGroup(*it);
00973         rule.outputs = display_config->readListEntry("Outputs");
00974         rule.states = display_config->readIntListEntry("States");
00975         rule.profileName = display_config->readEntry("Profile");
00976         ret.append(rule);
00977     }
00978     delete display_config;
00979 
00980     return ret;
00981 }
00982 
00983 void KRandrSimpleAPI::saveHotplugRules(HotPlugRulesList rules, TQString kde_confdir) {
00984     int i;
00985     TQString filename;
00986 
00987     filename = "displayglobals";
00988     filename.prepend(kde_confdir.append("/"));
00989     KSimpleConfig* display_config = new KSimpleConfig( filename );
00990     TQStringList grouplist = display_config->groupList();
00991     for ( TQStringList::Iterator it = grouplist.begin(); it != grouplist.end(); ++it ) {
00992         if (!(*it).startsWith("Hotplug-Rule")) {
00993             continue;
00994         }
00995         display_config->deleteGroup(*it, true, false);
00996     }
00997     HotPlugRulesList::Iterator it;
00998     i=0;
00999     for (it=rules.begin(); it != rules.end(); ++it) {
01000         display_config->setGroup(TQString("Hotplug-Rule%1").arg(i));
01001         display_config->writeEntry("Outputs", (*it).outputs);
01002         display_config->writeEntry("States", (*it).states);
01003         display_config->writeEntry("Profile", (*it).profileName);
01004         i++;
01005     }
01006     display_config->sync();
01007     delete display_config;
01008 }
01009 
01010 bool KRandrSimpleAPI::getDisplayConfigurationEnabled(TQString kde_confdir) {
01011     TQString filename = "displayglobals";
01012     filename.prepend(kde_confdir.append("/"));
01013     KSimpleConfig* display_config = new KSimpleConfig( filename );
01014     display_config->setGroup("General");
01015     bool enabled = display_config->readBoolEntry("EnableDisplayControl", false);
01016     delete display_config;
01017 
01018     return enabled;
01019 }
01020 
01021 bool KRandrSimpleAPI::getDisplayConfigurationStartupAutoApplyEnabled(TQString kde_confdir) {
01022     TQString filename = "displayglobals";
01023     filename.prepend(kde_confdir.append("/"));
01024     KSimpleConfig* display_config = new KSimpleConfig( filename );
01025     display_config->setGroup("General");
01026     bool applyonstart = display_config->readBoolEntry("ApplySettingsOnStart", false);
01027     delete display_config;
01028 
01029     return applyonstart;
01030 }
01031 
01032 TQString KRandrSimpleAPI::getDisplayConfigurationStartupAutoApplyName(TQString kde_confdir) {
01033     TQString filename = "displayglobals";
01034     filename.prepend(kde_confdir.append("/"));
01035     KSimpleConfig* display_config = new KSimpleConfig( filename );
01036     display_config->setGroup("General");
01037     TQString profilename = display_config->readEntry("StartupProfileName", "");
01038     delete display_config;
01039 
01040     return profilename;
01041 }
01042 
01043 void KRandrSimpleAPI::applyHotplugRules(TQString kde_confdir) {
01044     bool enabled = getDisplayConfigurationEnabled(kde_confdir);
01045     if (!enabled) {
01046         return;
01047     }
01048 
01049     HotPlugRulesList rules = getHotplugRules(kde_confdir);
01050     TQPtrList<SingleScreenData> screenInfoArray = readCurrentDisplayConfiguration();
01051 
01052     int i;
01053     int j;
01054     TQString bestRule;
01055     int bestRuleMatchCount = 0;
01056     SingleScreenData *screendata = NULL;
01057     HotPlugRulesList::Iterator it;
01058     for (it=rules.begin(); it != rules.end(); ++it) {
01059         // Compare each rule against the current display configuration
01060         // It an output matches the state given in the rule, increment matchCount
01061         HotPlugRule rule = *it;
01062         int matchCount = 0;
01063         int numberOfScreens = screenInfoArray.count();
01064         for (i=0;i<numberOfScreens;i++) {
01065             screendata = screenInfoArray.at(i);
01066             for (j=0; j<(*it).outputs.count(); j++) {
01067                 if ((*it).outputs[j] != screendata->screenUniqueName) {
01068                     continue;
01069                 }
01070                 if ((*it).states[j] == HotPlugRule::Connected) {
01071                     if (screendata->screen_connected) {
01072                         matchCount++;
01073                     }
01074                 }
01075                 else if ((*it).states[j] == HotPlugRule::Disconnected) {
01076                     if (!screendata->screen_connected) {
01077                         matchCount++;
01078                     }
01079                 }
01080             }
01081         }
01082 
01083         if (matchCount > bestRuleMatchCount) {
01084             bestRuleMatchCount = matchCount;
01085             bestRule = rule.profileName;
01086         }
01087     }
01088 
01089     destroyScreenInformationObject(screenInfoArray);
01090 
01091     if (bestRuleMatchCount > 0) {
01092         // At least one rule matched...
01093         // Apply the profile name in bestRule to the display hardware
01094         applyDisplayConfiguration(bestRule, kde_confdir);
01095     }
01096 }
01097 
01098 void KRandrSimpleAPI::applyDisplayGamma(TQPtrList<SingleScreenData> screenInfoArray) {
01099     int i;
01100     Display *randr_display;
01101     XRROutputInfo *output_info;
01102     ScreenInfo *randr_screen_info;
01103     XRRCrtcGamma *gamma;
01104 
01105     SingleScreenData *screendata;
01106 
01107     if (isValid() == true) {
01108         randr_display = tqt_xdisplay();
01109         randr_screen_info = read_screen_info(randr_display);
01110         for (i = 0; i < screenInfoArray.count(); i++) {
01111             screendata = screenInfoArray.at(i);
01112             output_info = randr_screen_info->outputs[i]->info;
01113             CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
01114             if (!current_crtc) {
01115                 continue;
01116             }
01117             // vvvvvvvvv This chunk of code is borrowed from xrandr vvvvvvvvvv
01118             int size = XRRGetCrtcGammaSize(randr_display, current_crtc->id);
01119             if (!size) {
01120                 continue;
01121             }
01122             gamma = XRRAllocGamma(size);
01123             if (!gamma) {
01124                 continue;
01125             }
01126             for (i = 0; i < size; i++) {
01127                 if (screendata->gamma_red == 1.0)
01128                     gamma->red[i] = i << 8;
01129                 else
01130                     gamma->red[i] = (pow((double)i/(double)(size-1), (double)screendata->gamma_red) * (double)(size-1)*256);
01131 
01132                 if (screendata->gamma_green == 1.0)
01133                     gamma->green[i] = i << 8;
01134                 else
01135                     gamma->green[i] = (pow((double)i/(double)(size-1), (double)screendata->gamma_green) * (double)(size-1)*256);
01136 
01137                 if (screendata->gamma_blue == 1.0)
01138                     gamma->blue[i] = i << 8;
01139                 else
01140                     gamma->blue[i] = (pow((double)i/(double)(size-1), (double)screendata->gamma_blue) * (double)(size-1)*256);
01141             }
01142             XRRSetCrtcGamma(randr_display, current_crtc->id, gamma);
01143             free(gamma);
01144             // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
01145         }
01146         freeScreenInfoStructure(randr_screen_info);
01147     }
01148 }
01149 
01150 void KRandrSimpleAPI::applyDisplayDPMS(TQPtrList<SingleScreenData> screenInfoArray) {
01151     int i;
01152     Display *randr_display;
01153     XRROutputInfo *output_info;
01154     ScreenInfo *randr_screen_info;
01155     XRRCrtcGamma *gamma;
01156 
01157     SingleScreenData *screendata;
01158 
01159     if (isValid() == true) {
01160         randr_display = tqt_xdisplay();
01161         randr_screen_info = read_screen_info(randr_display);
01162         for (i = 0; i < screenInfoArray.count(); i++) {
01163             screendata = screenInfoArray.at(i);
01164             output_info = randr_screen_info->outputs[i]->info;
01165             CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
01166             if (!current_crtc) {
01167                 continue;
01168             }
01169             if (!screendata->has_dpms) {
01170                 continue;
01171             }
01172             if (screendata->enable_dpms) {
01173                 DPMSSetTimeouts(randr_display, screendata->dpms_standby_delay, screendata->dpms_suspend_delay, screendata->dpms_off_delay);
01174                 DPMSEnable(randr_display);
01175             }
01176             else {
01177                 DPMSDisable(randr_display);
01178             }
01179         }
01180         freeScreenInfoStructure(randr_screen_info);
01181     }
01182 }
01183 
01184 void KRandrSimpleAPI::freeScreenInfoStructure(ScreenInfo* screen_info) {
01185     int i;
01186 
01187     for (i=0; i<screen_info->n_crtc; i++) {
01188         free(screen_info->crtcs[i]);
01189     }
01190     for (i=0; i<screen_info->n_output; i++) {
01191         free(screen_info->outputs[i]);
01192     }
01193     free(screen_info->outputs);
01194     free(screen_info->crtcs);
01195     free(screen_info);
01196 }
01197 
01198 TQPtrList<SingleScreenData> KRandrSimpleAPI::readCurrentDisplayConfiguration() {
01199     // Discover display information
01200     int i;
01201     int j;
01202 
01203     XRROutputInfo *output_info;
01204     SingleScreenData *screendata;
01205     TQPtrList<SingleScreenData> screenInfoArray;
01206 
01207     Display *randr_display;
01208     ScreenInfo *randr_screen_info;
01209 
01210     // Clear existing info
01211     destroyScreenInformationObject(screenInfoArray);
01212 
01213     int numberOfScreens = 0;
01214     if (isValid() == true) {
01215         randr_display = tqt_xdisplay();
01216         randr_screen_info = read_screen_info(randr_display);
01217         for (i = 0; i < randr_screen_info->n_output; i++) {
01218             output_info = randr_screen_info->outputs[i]->info;
01219             CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
01220 
01221             // Create new data object
01222             screendata = new SingleScreenData;
01223             screenInfoArray.append(screendata);
01224             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?
01225             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?
01226             screendata->generic_screen_detected = false;
01227 
01228             // Attempt to use KMS to find screen EDID and name
01229             TQString edid = getEDIDMonitorName(0, output_info->name);   // [FIXME] Don't hardwire to card 0!
01230             if (!edid.isNull()) {
01231                 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?
01232             }
01233 
01234             // Get resolutions
01235             bool screen_active;
01236             RandRScreen *cur_screen = 0;
01237             if (RR_Disconnected == randr_screen_info->outputs[i]->info->connection) {
01238                 // Output DISCONNECTED
01239                 screen_active = false;
01240             }
01241             else {
01242                 if (randr_screen_info->outputs[i]->cur_crtc) {
01243                     // Output CONNECTED and ON
01244                     screen_active = true;
01245                     cur_screen = new RandRScreen(i);
01246                 }
01247                 else {
01248                     // Output CONNECTED and OFF
01249                     screen_active = false;
01250                     cur_screen = new RandRScreen(i);
01251                 }
01252             }
01253 
01254             // Get DPMS information
01255             screendata->has_dpms = 1;   // [FIXME] Master Xorg check for global DPMS support should go here if possible
01256             if (screendata->has_dpms) {
01257                 CARD16 dpms_standby_delay;
01258                 CARD16 dpms_suspend_delay;
01259                 CARD16 dpms_off_delay;
01260                 screendata->has_dpms = DPMSGetTimeouts(randr_display, &dpms_standby_delay, &dpms_suspend_delay, &dpms_off_delay);
01261                 screendata->dpms_standby_delay = dpms_standby_delay;
01262                 screendata->dpms_suspend_delay = dpms_suspend_delay;
01263                 screendata->dpms_off_delay = dpms_off_delay;
01264                 if (screendata->has_dpms) {
01265                     CARD16 power_level;
01266                     BOOL enable_dpms;
01267                     screendata->has_dpms = DPMSInfo(randr_display, &power_level, &enable_dpms);
01268                     screendata->enable_dpms = enable_dpms;
01269                 }
01270             }
01271             if (!screendata->has_dpms) {
01272                 screendata->enable_dpms = false;
01273                 screendata->dpms_standby_delay = 0;
01274                 screendata->dpms_suspend_delay = 0;
01275                 screendata->dpms_off_delay = 0;
01276             }
01277 
01278             if (cur_screen) {
01279                 screendata->screen_connected = true;
01280                 for (int j = 0; j < cur_screen->numSizes(); j++) {
01281                     screendata->resolutions.append(i18n("%1 x %2").arg(cur_screen->pixelSize(j).width()).arg(cur_screen->pixelSize(j).height()));
01282                 }
01283                 screendata->current_resolution_index = 0;
01284                 if (current_crtc) {
01285                     screendata->current_resolution_index = screendata->resolutions.findIndex(i18n("%1 x %2").arg(current_crtc->info->width).arg(current_crtc->info->height));
01286                 }
01287                 if (screendata->current_resolution_index < 0) {
01288                     screendata->current_resolution_index = cur_screen->proposedSize();
01289                 }
01290 
01291                 // Get refresh rates
01292                 TQStringList rr = cur_screen->refreshRates(screendata->current_resolution_index);
01293                 for (TQStringList::Iterator it = rr.begin(); it != rr.end(); ++it) {
01294                     screendata->refresh_rates.append(*it);
01295                 }
01296                 screendata->current_refresh_rate_index = cur_screen->proposedRefreshRate();
01297 
01298                 // Get color depths
01299                 // [FIXME]
01300                 screendata->color_depths.append(i18n("Default"));
01301                 screendata->current_color_depth_index = 0;
01302 
01303                 // Get orientation flags
01304                 // RandRScreen::Rotate0
01305                 // RandRScreen::Rotate90
01306                 // RandRScreen::Rotate180
01307                 // RandRScreen::Rotate270
01308                 // RandRScreen::ReflectX
01309                 // RandRScreen::ReflectY
01310 
01311                 screendata->rotations.append(i18n(ROTATION_0_DEGREES_STRING));
01312                 screendata->rotations.append(i18n(ROTATION_90_DEGREES_STRING));
01313                 screendata->rotations.append(i18n(ROTATION_180_DEGREES_STRING));
01314                 screendata->rotations.append(i18n(ROTATION_270_DEGREES_STRING));
01315                 screendata->supports_transformations = (cur_screen->rotations() != RandRScreen::Rotate0);
01316                 if (screendata->supports_transformations) {
01317                     screendata->current_orientation_mask = cur_screen->proposedRotation();
01318                     switch (screendata->current_orientation_mask & RandRScreen::RotateMask) {
01319                         case RandRScreen::Rotate0:
01320                             screendata->current_rotation_index = 0;
01321                             break;
01322                         case RandRScreen::Rotate90:
01323                             screendata->current_rotation_index = 1;
01324                             break;
01325                         case RandRScreen::Rotate180:
01326                             screendata->current_rotation_index = 2;
01327                             break;
01328                         case RandRScreen::Rotate270:
01329                             screendata->current_rotation_index = 3;
01330                             break;
01331                         default:
01332                             // Shouldn't hit this one
01333                             Q_ASSERT(screendata->current_orientation_mask & RandRScreen::RotateMask);
01334                             screendata->current_rotation_index = 0;
01335                             break;
01336                     }
01337                     screendata->has_x_flip = (screendata->current_orientation_mask & RandRScreen::ReflectX);
01338                     screendata->has_y_flip = (screendata->current_orientation_mask & RandRScreen::ReflectY);
01339                 }
01340                 else {
01341                     screendata->has_x_flip = false;
01342                     screendata->has_y_flip = false;
01343                     screendata->current_rotation_index = 0;
01344                 }
01345 
01346                 // Determine if this display is primary and/or extended
01347                 RROutput primaryoutput = XRRGetOutputPrimary(tqt_xdisplay(), DefaultRootWindow(tqt_xdisplay()));
01348                 if (primaryoutput == randr_screen_info->outputs[i]->id) {
01349                     screendata->is_primary = false;
01350                 }
01351                 else {
01352                     screendata->is_primary = true;
01353                 }
01354                 screendata->is_extended = screen_active;
01355                 if (!screendata->is_extended) {
01356                     screendata->is_primary = false;
01357                 }
01358 
01359                 // Get this screen's absolute position
01360                 screendata->absolute_x_position = 0;
01361                 screendata->absolute_y_position = 0;
01362                 if (current_crtc) {
01363                     screendata->absolute_x_position = current_crtc->info->x;
01364                     screendata->absolute_y_position = current_crtc->info->y;
01365                 }
01366 
01367                 // Get this screen's current resolution
01368                 screendata->current_x_pixel_count = cur_screen->pixelSize(screendata->current_resolution_index).width();
01369                 screendata->current_y_pixel_count = cur_screen->pixelSize(screendata->current_resolution_index).height();
01370 
01371                 // Get this screen's current gamma values
01372                 // [FIXME]
01373                 // This attempts to guess a gamma value based on the LUT settings at 50%
01374                 // It may not always be 100% correct, or even anywhere close...
01375                 // Essentially it "undoes" the LUT gamma calculation from xrandr
01376                 // lut_gamma->green[i] = (pow(i/(size - 1), desired_gamma.green) * (size - 1) * 256);
01377                 screendata->gamma_red = 2.2;
01378                 screendata->gamma_green = 2.2;
01379                 screendata->gamma_blue = 2.2;
01380                 if (current_crtc) {
01381                     //int slot = 127;
01382                     int slot = 7;
01383                     int size = XRRGetCrtcGammaSize(randr_display, current_crtc->id);
01384                     if(size>0) {
01385                         XRRCrtcGamma *gammastruct = XRRGetCrtcGamma (randr_display, current_crtc->id);
01386                         screendata->gamma_red = log(gammastruct->red[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
01387                         screendata->gamma_green = log(gammastruct->green[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
01388                         screendata->gamma_blue = log(gammastruct->blue[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
01389                     }
01390                 }
01391                 // Round off the gamma to one decimal place
01392                 screendata->gamma_red = floorf(screendata->gamma_red * 10 + 0.5) / 10;
01393                 screendata->gamma_green = floorf(screendata->gamma_green * 10 + 0.5) / 10;
01394                 screendata->gamma_blue = floorf(screendata->gamma_blue * 10 + 0.5) / 10;
01395 
01396                 delete cur_screen;
01397             }
01398             else {
01399                 // Fill in generic data for this disconnected output
01400                 screendata->screenFriendlyName = screendata->screenFriendlyName + TQString(" (") + i18n("disconnected") + TQString(")");
01401                 screendata->screen_connected = false;
01402 
01403                 screendata->resolutions = i18n("Default");
01404                 screendata->refresh_rates = i18n("Default");
01405                 screendata->color_depths = i18n("Default");
01406                 screendata->rotations = i18n("N/A");
01407 
01408                 screendata->current_resolution_index = 0;
01409                 screendata->current_refresh_rate_index = 0;
01410                 screendata->current_color_depth_index = 0;
01411 
01412                 screendata->gamma_red = 2.2;
01413                 screendata->gamma_green = 2.2;
01414                 screendata->gamma_blue = 2.2;
01415 
01416                 screendata->current_rotation_index = 0;
01417                 screendata->current_orientation_mask = 0;
01418                 screendata->has_x_flip = false;
01419                 screendata->has_y_flip = false;
01420                 screendata->supports_transformations = false;
01421 
01422                 screendata->is_primary = false;
01423                 screendata->is_extended = false;
01424                 screendata->absolute_x_position = 0;
01425                 screendata->absolute_y_position = 0;
01426                 screendata->current_x_pixel_count = 640;
01427                 screendata->current_y_pixel_count = 480;
01428             }
01429 
01430             // Check for more screens...
01431             numberOfScreens++;
01432         }
01433 
01434         freeScreenInfoStructure(randr_screen_info);
01435     }
01436     else {
01437         screendata = new SingleScreenData;
01438         screenInfoArray.append(screendata);
01439 
01440         // Fill in a bunch of generic data
01441         screendata->screenFriendlyName = i18n("Default output on generic video card");
01442         screendata->generic_screen_detected = true;
01443         screendata->screen_connected = true;
01444 
01445         screendata->resolutions = i18n("Default");
01446         screendata->refresh_rates = i18n("Default");
01447         screendata->color_depths = i18n("Default");
01448         screendata->rotations = i18n("N/A");
01449 
01450         screendata->current_resolution_index = 0;
01451         screendata->current_refresh_rate_index = 0;
01452         screendata->current_color_depth_index = 0;
01453 
01454         screendata->gamma_red = 2.2;
01455         screendata->gamma_green = 2.2;
01456         screendata->gamma_blue = 2.2;
01457 
01458         screendata->current_rotation_index = 0;
01459         screendata->current_orientation_mask = 0;
01460         screendata->has_x_flip = false;
01461         screendata->has_y_flip = false;
01462         screendata->supports_transformations = false;
01463 
01464         screendata->is_primary = true;
01465         screendata->is_extended = true;
01466         screendata->absolute_x_position = 0;
01467         screendata->absolute_y_position = 0;
01468         screendata->current_x_pixel_count = 640;
01469         screendata->current_y_pixel_count = 480;
01470 
01471         numberOfScreens++;
01472     }
01473 
01474     bool primary_set = false;
01475     for ( screendata=screenInfoArray.first(); screendata; screendata=screenInfoArray.next() ) {
01476         if (screendata->is_primary) {
01477             primary_set = true;
01478             break;
01479         }
01480     }
01481     // If there is no primary monitor set, xrandr is probably not functioning correctly!
01482     Q_ASSERT(primary_set);
01483     if (!primary_set) {
01484         // [FIXME]
01485         // Set this on the real primary monitor only!
01486         screendata = screenInfoArray.at(0);
01487         screendata->is_primary = true;
01488     }
01489 
01490     return screenInfoArray;
01491 }
01492 
01493 TQString KRandrSimpleAPI::clearIccConfiguration() {
01494     // Clear ICC settings with XCalib
01495     TQString icc_command;
01496     FILE *pipe_xcalib;
01497     char xcalib_result[2048];
01498     int i;
01499     xcalib_result[0]=0;
01500 
01501     icc_command = TQString("xcalib -c");
01502     if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
01503     {
01504         printf("Xcalib pipe error [xcalib clear]\n");
01505     }
01506     else {
01507         if (fgets(xcalib_result, 2048, pipe_xcalib)) {
01508             pclose(pipe_xcalib);
01509             for (i=1;i<2048;i++) {
01510                 if (xcalib_result[i] == 0) {
01511                     xcalib_result[i-1]=0;
01512                     i=2048;
01513                 }
01514             }
01515             if (strlen(xcalib_result) > 2) {
01516                 return xcalib_result;
01517             }
01518         }
01519         else {
01520             return "";
01521         }
01522     }
01523     return "";
01524 }
01525 
01526 ScreenInfo* KRandrSimpleAPI::read_screen_info (Display *display)
01527 {
01528     return internal_read_screen_info(display);
01529 }
01530 
01531 int KRandrSimpleAPI::set_screen_size (ScreenInfo *screen_info)
01532 {
01533     return internal_set_screen_size(screen_info);
01534 }
01535 
01536 void KRandrSimpleAPI::output_auto (ScreenInfo *screen_info, OutputInfo *output_info)
01537 {
01538     internal_output_auto (screen_info, output_info);
01539 }
01540 
01541 void KRandrSimpleAPI::output_off(ScreenInfo *screen_info, OutputInfo *output)
01542 {
01543     internal_output_off(screen_info, output);
01544 }
01545 
01546 CrtcInfo* KRandrSimpleAPI::auto_find_crtc (ScreenInfo *screen_info, OutputInfo *output_info)
01547 {
01548     return internal_auto_find_crtc (screen_info, output_info);
01549 }
01550 
01551 XRRModeInfo *KRandrSimpleAPI::find_mode_by_xid (ScreenInfo *screen_info, RRMode mode_id)
01552 {
01553     return internal_find_mode_by_xid (screen_info, mode_id);
01554 }
01555 
01556 int KRandrSimpleAPI::mode_height (XRRModeInfo *mode_info, Rotation rotation)
01557 {
01558     return internal_mode_height (mode_info, rotation);
01559 }
01560 
01561 int KRandrSimpleAPI::mode_width (XRRModeInfo *mode_info, Rotation rotation)
01562 {
01563     return internal_mode_width (mode_info, rotation);
01564 }
01565 
01566 int KRandrSimpleAPI::get_width_by_output_id (ScreenInfo *screen_info, RROutput output_id)
01567 {
01568     return internal_get_width_by_output_id (screen_info, output_id);
01569 }
01570 
01571 int KRandrSimpleAPI::get_height_by_output_id (ScreenInfo *screen_info, RROutput output_id)
01572 {
01573     return internal_get_height_by_output_id (screen_info, output_id);
01574 }
01575 
01576 char *KRandrSimpleAPI::get_output_name (ScreenInfo *screen_info, RROutput id)
01577 {
01578     return internal_get_output_name (screen_info, id);
01579 }
01580 
01581 Status KRandrSimpleAPI::crtc_apply (CrtcInfo *crtc_info)
01582 {
01583     return internal_crtc_apply (crtc_info);
01584 }
01585 
01586 Status KRandrSimpleAPI::crtc_disable (CrtcInfo *crtc)
01587 {
01588     return internal_crtc_disable (crtc);
01589 }
01590 
01591 int KRandrSimpleAPI::main_low_apply (ScreenInfo *screen_info)
01592 {
01593     return internal_main_low_apply (screen_info);
01594 }
01595 
01596 void KRandrSimpleAPI::set_primary_output (ScreenInfo *screen_info, RROutput output_id)
01597 {
01598     internal_output_set_primary(screen_info, output_id);
01599 }
01600 
01601 bool KRandrSimpleAPI::kRandrHasRandr(void)
01602 {
01603     return isValid();
01604 }
01605 
01606 const char *KRandrSimpleAPI::kRandrVersion(void)
01607 {
01608     return "0.9.5";
01609 }
01610 
01611 const char *KRandrSimpleAPI::kRandrCopyright(void)
01612 {
01613    return "LibKRandr 0.9.5 (C)2010 Timothy Pearson <kb9vqf@pearsoncomputing.net>. U.S.A.";
01614 }
01615 
01616 /* * * * * *
01617 
01618  Under this line (------) there's only a C wrapper for the KRandrSimpleAPI class
01619 
01620 * * * * * */
01621 const char *kRandrVersion(void)
01622 {
01623   return KRandrSimpleAPI::kRandrVersion();
01624 }
01625 
01626 const char *kRandrCopyright(void)
01627 {
01628   return KRandrSimpleAPI::kRandrCopyright();
01629 }
01630 

tderandr

Skip menu "tderandr"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

tderandr

Skip menu "tderandr"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tderandr by doxygen 1.6.3
This website is maintained by Timothy Pearson.