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(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