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