randr.cpp
00001 /* 00002 * Copyright (c) 2002,2003 Hamish Rodda <rodda@kde.org> 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 #include "randr.h" 00020 #include "lowlevel_randr.h" 00021 00022 #include <tqtimer.h> 00023 00024 #include <kdebug.h> 00025 #include <tdelocale.h> 00026 #include <tdeglobal.h> 00027 #include <tdeapplication.h> 00028 #include <kiconloader.h> 00029 #include <dcopclient.h> 00030 #include <kipc.h> 00031 #include <kactivelabel.h> 00032 00033 #include "ktimerdialog.h" 00034 00035 #include <X11/Xlib.h> 00036 #define INT8 _X11INT8 00037 #define INT32 _X11INT32 00038 #include <X11/Xproto.h> 00039 #undef INT8 00040 #undef INT32 00041 #include <X11/extensions/Xrandr.h> 00042 00043 HotPlugRule::HotPlugRule() 00044 { 00045 // 00046 } 00047 00048 HotPlugRule::~HotPlugRule() 00049 { 00050 // 00051 } 00052 00053 SingleScreenData::SingleScreenData() 00054 { 00055 generic_screen_detected = false; 00056 screen_connected = false; 00057 00058 current_resolution_index = 0; 00059 current_refresh_rate_index = 0; 00060 current_color_depth_index = 0; 00061 00062 gamma_red = 0.0; 00063 gamma_green = 0.0; 00064 gamma_blue = 0.0; 00065 00066 current_rotation_index = 0; 00067 current_orientation_mask = 0; 00068 has_x_flip = false; 00069 has_y_flip = false; 00070 supports_transformations = false; 00071 00072 is_primary = false; 00073 is_extended = false; 00074 absolute_x_position = 0; 00075 absolute_y_position = 0; 00076 current_x_pixel_count = 0; 00077 current_y_pixel_count = 0; 00078 00079 has_dpms = false; 00080 enable_dpms = false; 00081 dpms_standby_delay = 0; 00082 dpms_suspend_delay = 0; 00083 dpms_off_delay = 0; 00084 } 00085 00086 SingleScreenData::~SingleScreenData() 00087 { 00088 // 00089 } 00090 00091 class RandRScreenPrivate 00092 { 00093 public: 00094 RandRScreenPrivate() : config(0L) {}; 00095 ~RandRScreenPrivate() 00096 { 00097 if (config) { 00098 XRRFreeScreenConfigInfo(config); 00099 } 00100 } 00101 00102 XRRScreenConfiguration* config; 00103 }; 00104 00105 KDE_EXPORT RandRScreen::RandRScreen(int screenIndex) 00106 : d(new RandRScreenPrivate()) 00107 , m_screen(screenIndex) 00108 , m_shownDialog(NULL) 00109 { 00110 loadSettings(); 00111 setOriginal(); 00112 } 00113 00114 KDE_EXPORT RandRScreen::~RandRScreen() 00115 { 00116 delete d; 00117 } 00118 00119 KDE_EXPORT void RandRScreen::loadSettings() 00120 { 00121 if (d->config) { 00122 XRRFreeScreenConfigInfo(d->config); 00123 } 00124 00125 d->config = XRRGetScreenInfo(tqt_xdisplay(), RootWindow(tqt_xdisplay(), m_screen)); 00126 00127 Rotation rotation; 00128 if (d->config) { 00129 m_currentSize = m_proposedSize = XRRConfigCurrentConfiguration(d->config, &rotation); 00130 m_currentRotation = m_proposedRotation = rotation; 00131 } 00132 else { 00133 m_currentSize = m_proposedSize = 0; 00134 m_currentRotation = m_proposedRotation = 0; 00135 } 00136 00137 m_pixelSizes.clear(); 00138 m_mmSizes.clear(); 00139 00140 if (d->config) { 00141 int numSizes; 00142 XRRScreenSize* sizes = XRRSizes(tqt_xdisplay(), m_screen, &numSizes); 00143 for (int i = 0; i < numSizes; i++) { 00144 m_pixelSizes.append(TQSize(sizes[i].width, sizes[i].height)); 00145 m_mmSizes.append(TQSize(sizes[i].mwidth, sizes[i].mheight)); 00146 } 00147 00148 m_rotations = XRRRotations(tqt_xdisplay(), m_screen, &rotation); 00149 } 00150 else { 00151 // Great, now we have to go after the information manually. Ughh. 00152 ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay()); 00153 XRROutputInfo *output_info = screeninfo->outputs[m_screen]->info; 00154 CrtcInfo *current_crtc = screeninfo->outputs[m_screen]->cur_crtc; 00155 int numSizes = output_info->nmode; 00156 for (int i = 0; i < numSizes; i++) { 00157 XRRModeInfo *xrrmode; 00158 xrrmode = internal_find_mode_by_xid (screeninfo, output_info->modes[i]); 00159 TQSize newSize = TQSize(xrrmode->width, xrrmode->height); 00160 if (!m_pixelSizes.contains(newSize)) { 00161 m_pixelSizes.append(newSize); 00162 m_mmSizes.append(TQSize(output_info->mm_width, output_info->mm_height)); 00163 } 00164 } 00165 if (current_crtc) { 00166 m_rotations = current_crtc->rotations; 00167 m_currentRotation = m_proposedRotation = current_crtc->cur_rotation; 00168 } 00169 } 00170 00171 if (d->config) { 00172 m_currentRefreshRate = m_proposedRefreshRate = refreshRateHzToIndex(m_currentSize, XRRConfigCurrentRate(d->config)); 00173 } 00174 else { 00175 m_currentRefreshRate = m_proposedRefreshRate = 0; 00176 } 00177 } 00178 00179 KDE_EXPORT void RandRScreen::setOriginal() 00180 { 00181 m_originalSize = m_currentSize; 00182 m_originalRotation = m_currentRotation; 00183 m_originalRefreshRate = m_currentRefreshRate; 00184 } 00185 00186 KDE_EXPORT bool RandRScreen::applyProposed() 00187 { 00188 //kdDebug() << k_funcinfo << " size " << (SizeID)proposedSize() << ", rotation " << proposedRotation() << ", refresh " << refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) << endl; 00189 00190 Status status; 00191 00192 if (!d->config) { 00193 d->config = XRRGetScreenInfo(tqt_xdisplay(), RootWindow(tqt_xdisplay(), m_screen)); 00194 Q_ASSERT(d->config); 00195 } 00196 00197 if (d->config) { 00198 if (proposedRefreshRate() < 0) 00199 status = XRRSetScreenConfig(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), CurrentTime); 00200 else { 00201 if( refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) <= 0 ) { 00202 m_proposedRefreshRate = 0; 00203 } 00204 status = XRRSetScreenConfigAndRate(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), refreshRateIndexToHz(proposedSize(), proposedRefreshRate()), CurrentTime); 00205 } 00206 } 00207 else { 00208 // Great, now we have to set the information manually. Ughh. 00209 // FIXME--this does not work! 00210 ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay()); 00211 screeninfo->cur_width = (*m_pixelSizes.at(proposedSize())).width(); 00212 screeninfo->cur_height = (*m_pixelSizes.at(proposedSize())).height(); 00213 internal_main_low_apply(screeninfo); 00214 00215 status = RRSetConfigSuccess; 00216 } 00217 00218 //kdDebug() << "New size: " << WidthOfScreen(ScreenOfDisplay(TQPaintDevice::x11AppDisplay(), screen)) << ", " << HeightOfScreen(ScreenOfDisplay(TQPaintDevice::x11AppDisplay(), screen)) << endl; 00219 00220 if (status == RRSetConfigSuccess) { 00221 m_currentSize = m_proposedSize; 00222 m_currentRotation = m_proposedRotation; 00223 m_currentRefreshRate = m_proposedRefreshRate; 00224 return true; 00225 } 00226 00227 return false; 00228 } 00229 00230 KDE_EXPORT bool RandRScreen::applyProposedAndConfirm() 00231 { 00232 if (proposedChanged()) { 00233 setOriginal(); 00234 00235 if (applyProposed()) { 00236 if (!confirm()) { 00237 proposeOriginal(); 00238 applyProposed(); 00239 return false; 00240 } 00241 } else { 00242 return false; 00243 } 00244 } 00245 00246 return true; 00247 } 00248 00249 KDE_EXPORT bool RandRScreen::confirm() 00250 { 00251 // uncomment the line below and edit out the KTimerDialog stuff to get 00252 // a version which works on today's tdelibs (no accept dialog is presented) 00253 00254 // FIXME remember to put the dialog on the right screen 00255 00256 KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown, 00257 TDEApplication::kApplication()->mainWidget(), 00258 "mainKTimerDialog", 00259 true, 00260 i18n("Confirm Display Setting Change"), 00261 KTimerDialog::Ok|KTimerDialog::Cancel, 00262 KTimerDialog::Cancel); 00263 00264 acceptDialog.setButtonOK(KGuiItem(i18n("&Accept Configuration"), "button_ok")); 00265 acceptDialog.setButtonCancel(KGuiItem(i18n("&Return to Previous Configuration"), "button_cancel")); 00266 00267 KActiveLabel *label = new KActiveLabel(i18n("Your screen orientation, size and refresh rate " 00268 "have been changed to the requested settings. Please indicate whether you wish to " 00269 "keep this configuration. In 15 seconds the display will revert to your previous " 00270 "settings."), &acceptDialog, "userSpecifiedLabel"); 00271 00272 acceptDialog.setMainWidget(label); 00273 00274 KDialog::centerOnScreen(&acceptDialog, m_screen); 00275 00276 m_shownDialog = &acceptDialog; 00277 connect( m_shownDialog, TQT_SIGNAL( destroyed()), this, TQT_SLOT( shownDialogDestroyed())); 00278 connect( kapp->desktop(), TQT_SIGNAL( resized(int)), this, TQT_SLOT( desktopResized())); 00279 00280 return acceptDialog.exec(); 00281 } 00282 00283 KDE_EXPORT void RandRScreen::shownDialogDestroyed() 00284 { 00285 m_shownDialog = NULL; 00286 disconnect( kapp->desktop(), TQT_SIGNAL( resized(int)), this, TQT_SLOT( desktopResized())); 00287 } 00288 00289 KDE_EXPORT void RandRScreen::desktopResized() 00290 { 00291 if( m_shownDialog != NULL ) 00292 KDialog::centerOnScreen(m_shownDialog, m_screen); 00293 } 00294 00295 KDE_EXPORT TQString RandRScreen::changedMessage() const 00296 { 00297 if (currentRefreshRate() == -1) 00298 return i18n("New configuration:\nResolution: %1 x %2\nOrientation: %3") 00299 .arg(currentPixelWidth()) 00300 .arg(currentPixelHeight()) 00301 .arg(currentRotationDescription()); 00302 else 00303 return i18n("New configuration:\nResolution: %1 x %2\nOrientation: %3\nRefresh rate: %4") 00304 .arg(currentPixelWidth()) 00305 .arg(currentPixelHeight()) 00306 .arg(currentRotationDescription()) 00307 .arg(currentRefreshRateDescription()); 00308 } 00309 00310 KDE_EXPORT bool RandRScreen::changedFromOriginal() const 00311 { 00312 return m_currentSize != m_originalSize || m_currentRotation != m_originalRotation || m_currentRefreshRate != m_originalRefreshRate; 00313 } 00314 00315 KDE_EXPORT void RandRScreen::proposeOriginal() 00316 { 00317 m_proposedSize = m_originalSize; 00318 m_proposedRotation = m_originalRotation; 00319 m_proposedRefreshRate = m_originalRefreshRate; 00320 } 00321 00322 KDE_EXPORT bool RandRScreen::proposedChanged() const 00323 { 00324 return m_currentSize != m_proposedSize || m_currentRotation != m_proposedRotation || m_currentRefreshRate != m_proposedRefreshRate; 00325 } 00326 00327 KDE_EXPORT TQString RandRScreen::rotationName(int rotation, bool pastTense, bool capitalised) 00328 { 00329 if (!pastTense) 00330 switch (rotation) { 00331 case RR_Rotate_0: 00332 return i18n("Normal"); 00333 case RR_Rotate_90: 00334 return i18n("Left (90 degrees)"); 00335 case RR_Rotate_180: 00336 return i18n("Upside-down (180 degrees)"); 00337 case RR_Rotate_270: 00338 return i18n("Right (270 degrees)"); 00339 case RR_Reflect_X: 00340 return i18n("Mirror horizontally"); 00341 case RR_Reflect_Y: 00342 return i18n("Mirror vertically"); 00343 default: 00344 return i18n("Unknown orientation"); 00345 } 00346 00347 switch (rotation) { 00348 case RR_Rotate_0: 00349 return i18n("Normal"); 00350 case RR_Rotate_90: 00351 return i18n("Rotated 90 degrees counterclockwise"); 00352 case RR_Rotate_180: 00353 return i18n("Rotated 180 degrees counterclockwise"); 00354 case RR_Rotate_270: 00355 return i18n("Rotated 270 degrees counterclockwise"); 00356 default: 00357 if (rotation & RR_Reflect_X) 00358 if (rotation & RR_Reflect_Y) 00359 if (capitalised) 00360 return i18n("Mirrored horizontally and vertically"); 00361 else 00362 return i18n("mirrored horizontally and vertically"); 00363 else 00364 if (capitalised) 00365 return i18n("Mirrored horizontally"); 00366 else 00367 return i18n("mirrored horizontally"); 00368 else if (rotation & RR_Reflect_Y) 00369 if (capitalised) 00370 return i18n("Mirrored vertically"); 00371 else 00372 return i18n("mirrored vertically"); 00373 else 00374 if (capitalised) 00375 return i18n("Unknown orientation"); 00376 else 00377 return i18n("unknown orientation"); 00378 } 00379 } 00380 00381 KDE_EXPORT TQPixmap RandRScreen::rotationIcon(int rotation) const 00382 { 00383 // Adjust icons for current screen orientation 00384 if (!(m_currentRotation & RR_Rotate_0) && rotation & (RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270)) { 00385 int currentAngle = m_currentRotation & (RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270); 00386 switch (currentAngle) { 00387 case RR_Rotate_90: 00388 rotation <<= 3; 00389 break; 00390 case RR_Rotate_180: 00391 rotation <<= 2; 00392 break; 00393 case RR_Rotate_270: 00394 rotation <<= 1; 00395 break; 00396 } 00397 00398 // Fix overflow 00399 if (rotation > RR_Rotate_270) { 00400 rotation >>= 4; 00401 } 00402 } 00403 00404 switch (rotation) { 00405 case RR_Rotate_0: 00406 return SmallIcon("go-up"); 00407 case RR_Rotate_90: 00408 return SmallIcon("back"); 00409 case RR_Rotate_180: 00410 return SmallIcon("go-down"); 00411 case RR_Rotate_270: 00412 return SmallIcon("forward"); 00413 case RR_Reflect_X: 00414 case RR_Reflect_Y: 00415 default: 00416 return SmallIcon("process-stop"); 00417 } 00418 } 00419 00420 KDE_EXPORT TQString RandRScreen::currentRotationDescription() const 00421 { 00422 TQString ret = rotationName(m_currentRotation & RotateMask); 00423 00424 if (m_currentRotation != (m_currentRotation & RotateMask)) { 00425 if (m_currentRotation & RR_Rotate_0) { 00426 ret = rotationName(m_currentRotation & (RR_Reflect_X + RR_Reflect_X), true, true); 00427 } 00428 else { 00429 ret += ", " + rotationName(m_currentRotation & (RR_Reflect_X + RR_Reflect_X), true, false); 00430 } 00431 } 00432 00433 return ret; 00434 } 00435 00436 KDE_EXPORT int RandRScreen::rotationIndexToDegree(int rotation) const 00437 { 00438 switch (rotation & RotateMask) { 00439 case RR_Rotate_90: 00440 return 90; 00441 00442 case RR_Rotate_180: 00443 return 180; 00444 00445 case RR_Rotate_270: 00446 return 270; 00447 00448 default: 00449 return 0; 00450 } 00451 } 00452 00453 KDE_EXPORT int RandRScreen::rotationDegreeToIndex(int degree) const 00454 { 00455 switch (degree) { 00456 case 90: 00457 return RR_Rotate_90; 00458 00459 case 180: 00460 return RR_Rotate_180; 00461 00462 case 270: 00463 return RR_Rotate_270; 00464 00465 default: 00466 return RR_Rotate_0; 00467 } 00468 } 00469 00470 KDE_EXPORT int RandRScreen::currentPixelWidth() const 00471 { 00472 return m_pixelSizes[m_currentSize].width(); 00473 } 00474 00475 KDE_EXPORT int RandRScreen::currentPixelHeight() const 00476 { 00477 return m_pixelSizes[m_currentSize].height(); 00478 } 00479 00480 KDE_EXPORT int RandRScreen::currentMMWidth() const 00481 { 00482 return m_pixelSizes[m_currentSize].width(); 00483 } 00484 00485 KDE_EXPORT int RandRScreen::currentMMHeight() const 00486 { 00487 return m_pixelSizes[m_currentSize].height(); 00488 } 00489 00490 KDE_EXPORT TQStringList RandRScreen::refreshRates(int size) const 00491 { 00492 int nrates; 00493 TQStringList ret; 00494 00495 if (d->config) { 00496 short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates); 00497 00498 for (int i = 0; i < nrates; i++) 00499 ret << refreshRateDirectDescription(rates[i]); 00500 } 00501 else { 00502 // Great, now we have to go after the information manually. Ughh. 00503 ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay()); 00504 int numSizes = screeninfo->res->nmode; 00505 for (int i = 0; i < numSizes; i++) { 00506 int refresh_rate = ((screeninfo->res->modes[i].dotClock*1.0)/((screeninfo->res->modes[i].hTotal)*(screeninfo->res->modes[i].vTotal)*1.0)); 00507 TQString newRate = refreshRateDirectDescription(refresh_rate); 00508 if (!ret.contains(newRate)) { 00509 ret.append(newRate); 00510 } 00511 } 00512 } 00513 00514 return ret; 00515 } 00516 00517 KDE_EXPORT TQString RandRScreen::refreshRateDirectDescription(int rate) const 00518 { 00519 return i18n("Refresh rate in Hertz (Hz)", "%1 Hz").arg(rate); 00520 } 00521 00522 KDE_EXPORT TQString RandRScreen::refreshRateIndirectDescription(int size, int index) const 00523 { 00524 return i18n("Refresh rate in Hertz (Hz)", "%1 Hz").arg(refreshRateIndexToHz(size, index)); 00525 } 00526 00527 KDE_EXPORT TQString RandRScreen::refreshRateDescription(int size, int index) const 00528 { 00529 return refreshRates(size)[index]; 00530 } 00531 00532 KDE_EXPORT bool RandRScreen::proposeRefreshRate(int index) 00533 { 00534 if (index >= 0 && (int)refreshRates(proposedSize()).count() > index) { 00535 m_proposedRefreshRate = index; 00536 return true; 00537 } 00538 00539 return false; 00540 } 00541 00542 KDE_EXPORT int RandRScreen::currentRefreshRate() const 00543 { 00544 return m_currentRefreshRate; 00545 } 00546 00547 KDE_EXPORT TQString RandRScreen::currentRefreshRateDescription() const 00548 { 00549 return refreshRateIndirectDescription(m_currentSize, m_currentRefreshRate); 00550 } 00551 00552 KDE_EXPORT int RandRScreen::proposedRefreshRate() const 00553 { 00554 return m_proposedRefreshRate; 00555 } 00556 00557 KDE_EXPORT int RandRScreen::refreshRateHzToIndex(int size, int hz) const 00558 { 00559 int nrates; 00560 short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates); 00561 00562 for (int i = 0; i < nrates; i++) 00563 if (hz == rates[i]) 00564 return i; 00565 00566 if (nrates != 0) 00567 // Wrong input Hz! 00568 Q_ASSERT(false); 00569 00570 return -1; 00571 } 00572 00573 KDE_EXPORT int RandRScreen::refreshRateIndexToHz(int size, int index) const 00574 { 00575 int nrates; 00576 short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates); 00577 00578 if (nrates == 0 || index < 0) 00579 return 0; 00580 00581 // Wrong input Hz! 00582 if(index >= nrates) 00583 return 0; 00584 00585 return rates[index]; 00586 } 00587 00588 KDE_EXPORT int RandRScreen::numSizes() const 00589 { 00590 return m_pixelSizes.count(); 00591 } 00592 00593 KDE_EXPORT const TQSize& RandRScreen::pixelSize(int index) const 00594 { 00595 return m_pixelSizes[index]; 00596 } 00597 00598 KDE_EXPORT const TQSize& RandRScreen::mmSize(int index) const 00599 { 00600 return m_mmSizes[index]; 00601 } 00602 00603 KDE_EXPORT int RandRScreen::sizeIndex(TQSize pixelSize) const 00604 { 00605 for (uint i = 0; i < m_pixelSizes.count(); i++) 00606 if (m_pixelSizes[i] == pixelSize) 00607 return i; 00608 00609 return -1; 00610 } 00611 00612 KDE_EXPORT int RandRScreen::rotations() const 00613 { 00614 return m_rotations; 00615 } 00616 00617 KDE_EXPORT int RandRScreen::currentRotation() const 00618 { 00619 return m_currentRotation; 00620 } 00621 00622 KDE_EXPORT int RandRScreen::currentSize() const 00623 { 00624 return m_currentSize; 00625 } 00626 00627 KDE_EXPORT int RandRScreen::proposedRotation() const 00628 { 00629 return m_proposedRotation; 00630 } 00631 00632 KDE_EXPORT void RandRScreen::proposeRotation(int newRotation) 00633 { 00634 m_proposedRotation = newRotation & OrientationMask; 00635 } 00636 00637 KDE_EXPORT int RandRScreen::proposedSize() const 00638 { 00639 return m_proposedSize; 00640 } 00641 00642 KDE_EXPORT bool RandRScreen::proposeSize(int newSize) 00643 { 00644 if ((int)m_pixelSizes.count() > newSize) { 00645 m_proposedSize = newSize; 00646 return true; 00647 } 00648 00649 return false; 00650 } 00651 00652 KDE_EXPORT void RandRScreen::load(TDEConfig& config) 00653 { 00654 config.setGroup(TQString("Screen%1").arg(m_screen)); 00655 00656 if (proposeSize(sizeIndex(TQSize(config.readNumEntry("width", currentPixelWidth()), config.readNumEntry("height", currentPixelHeight()))))) 00657 proposeRefreshRate(refreshRateHzToIndex(proposedSize(), config.readNumEntry("refresh", currentRefreshRate()))); 00658 00659 proposeRotation(rotationDegreeToIndex(config.readNumEntry("rotation", 0)) + (config.readBoolEntry("reflectX") ? ReflectX : 0) + (config.readBoolEntry("reflectY") ? ReflectY : 0)); 00660 } 00661 00662 KDE_EXPORT void RandRScreen::save(TDEConfig& config) const 00663 { 00664 config.setGroup(TQString("Screen%1").arg(m_screen)); 00665 config.writeEntry("width", currentPixelWidth()); 00666 config.writeEntry("height", currentPixelHeight()); 00667 config.writeEntry("refresh", refreshRateIndexToHz(currentSize(), currentRefreshRate())); 00668 config.writeEntry("rotation", rotationIndexToDegree(currentRotation())); 00669 config.writeEntry("reflectX", (bool)(currentRotation() & ReflectMask) == ReflectX); 00670 config.writeEntry("reflectY", (bool)(currentRotation() & ReflectMask) == ReflectY); 00671 } 00672 00673 KDE_EXPORT RandRDisplay::RandRDisplay() 00674 : m_valid(true) 00675 { 00676 // Check extension 00677 Status s = XRRQueryExtension(tqt_xdisplay(), &m_eventBase, &m_errorBase); 00678 if (!s) { 00679 m_errorCode = TQString("%1, base %1").arg(s).arg(m_errorBase); 00680 m_valid = false; 00681 return; 00682 } 00683 00684 // Sometimes the extension is available but does not return any screens (!) 00685 // Check for that case 00686 Display *randr_display = XOpenDisplay(NULL); 00687 int screen_num; 00688 Window root_window; 00689 00690 screen_num = DefaultScreen (randr_display); 00691 root_window = RootWindow (randr_display, screen_num); 00692 if (XRRGetScreenResources (randr_display, root_window) == NULL) { 00693 m_errorCode = i18n("No screens detected"); 00694 m_valid = false; 00695 return; 00696 } 00697 00698 int major_version, minor_version; 00699 XRRQueryVersion(tqt_xdisplay(), &major_version, &minor_version); 00700 00701 m_version = TQString("X Resize and Rotate extension version %1.%1").arg(major_version).arg(minor_version); 00702 00703 m_numScreens = ScreenCount(tqt_xdisplay()); 00704 00705 // This assumption is WRONG with Xinerama 00706 // Q_ASSERT(TQApplication::desktop()->numScreens() == ScreenCount(tqt_xdisplay())); 00707 00708 m_screens.setAutoDelete(true); 00709 for (int i = 0; i < m_numScreens; i++) { 00710 m_screens.append(new RandRScreen(i)); 00711 } 00712 00713 setCurrentScreen(TQApplication::desktop()->primaryScreen()); 00714 } 00715 00716 KDE_EXPORT bool RandRDisplay::isValid() const 00717 { 00718 return m_valid; 00719 } 00720 00721 KDE_EXPORT const TQString& RandRDisplay::errorCode() const 00722 { 00723 return m_errorCode; 00724 } 00725 00726 KDE_EXPORT int RandRDisplay::eventBase() const 00727 { 00728 return m_eventBase; 00729 } 00730 00731 KDE_EXPORT int RandRDisplay::screenChangeNotifyEvent() const 00732 { 00733 return m_eventBase + RRScreenChangeNotify; 00734 } 00735 00736 KDE_EXPORT int RandRDisplay::errorBase() const 00737 { 00738 return m_errorBase; 00739 } 00740 00741 KDE_EXPORT const TQString& RandRDisplay::version() const 00742 { 00743 return m_version; 00744 } 00745 00746 KDE_EXPORT void RandRDisplay::setCurrentScreen(int index) 00747 { 00748 m_currentScreenIndex = index; 00749 m_currentScreen = m_screens.at(m_currentScreenIndex); 00750 Q_ASSERT(m_currentScreen); 00751 } 00752 00753 KDE_EXPORT int RandRDisplay::screenIndexOfWidget(TQWidget* widget) 00754 { 00755 int ret = TQApplication::desktop()->screenNumber(widget); 00756 return ret != -1 ? ret : TQApplication::desktop()->primaryScreen(); 00757 } 00758 00759 KDE_EXPORT int RandRDisplay::currentScreenIndex() const 00760 { 00761 return m_currentScreenIndex; 00762 } 00763 00764 KDE_EXPORT void RandRDisplay::refresh() 00765 { 00766 for (RandRScreen* s = m_screens.first(); s; s = m_screens.next()) 00767 s->loadSettings(); 00768 } 00769 00770 KDE_EXPORT int RandRDisplay::numScreens() const 00771 { 00772 return m_numScreens; 00773 } 00774 00775 KDE_EXPORT RandRScreen* RandRDisplay::screen(int index) 00776 { 00777 return m_screens.at(index); 00778 } 00779 00780 KDE_EXPORT RandRScreen* RandRDisplay::currentScreen() 00781 { 00782 return m_currentScreen; 00783 } 00784 00785 KDE_EXPORT bool RandRDisplay::loadDisplay(TDEConfig& config, bool loadScreens) 00786 { 00787 if (loadScreens) 00788 for (RandRScreen* s = m_screens.first(); s; s = m_screens.next()) 00789 s->load(config); 00790 00791 return applyOnStartup(config); 00792 } 00793 00794 KDE_EXPORT bool RandRDisplay::applyOnStartup(TDEConfig& config) 00795 { 00796 config.setGroup("Display"); 00797 return config.readBoolEntry("ApplyOnStartup", false); 00798 } 00799 00800 KDE_EXPORT bool RandRDisplay::syncTrayApp(TDEConfig& config) 00801 { 00802 config.setGroup("Display"); 00803 return config.readBoolEntry("SyncTrayApp", false); 00804 } 00805 00806 KDE_EXPORT void RandRDisplay::saveDisplay(TDEConfig& config, bool applyOnStartup, bool syncTrayApp) 00807 { 00808 Q_ASSERT(!config.isReadOnly()); 00809 00810 config.setGroup("Display"); 00811 config.writeEntry("ApplyOnStartup", applyOnStartup); 00812 config.writeEntry("SyncTrayApp", syncTrayApp); 00813 00814 for (RandRScreen* s = m_screens.first(); s; s = m_screens.next()) 00815 s->save(config); 00816 } 00817 00818 KDE_EXPORT void RandRDisplay::applyProposed(bool confirm) 00819 { 00820 for (int screenIndex = 0; screenIndex < numScreens(); screenIndex++) { 00821 if (screen(screenIndex)->proposedChanged()) { 00822 if (confirm) 00823 screen(screenIndex)->applyProposedAndConfirm(); 00824 else 00825 screen(screenIndex)->applyProposed(); 00826 } 00827 } 00828 } 00829 00830 KDE_EXPORT bool RandRDisplay::showTestConfigurationDialog() 00831 { 00832 RandRScreen* firstScreen = screen(0); 00833 if (firstScreen) { 00834 return firstScreen->showTestConfigurationDialog(); 00835 } 00836 else { 00837 return false; 00838 } 00839 } 00840 00841 KDE_EXPORT bool RandRScreen::showTestConfigurationDialog() 00842 { 00843 // uncomment the line below and edit out the KTimerDialog stuff to get 00844 // a version which works on today's tdelibs (no accept dialog is presented) 00845 00846 // FIXME remember to put the dialog on the right screen 00847 00848 KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown, 00849 TDEApplication::kApplication()->mainWidget(), 00850 "mainKTimerDialog", 00851 true, 00852 i18n("Confirm Display Settings"), 00853 KTimerDialog::Ok|KTimerDialog::Cancel, 00854 KTimerDialog::Cancel); 00855 00856 acceptDialog.setButtonOK(KGuiItem(i18n("&Accept Configuration"), "button_ok")); 00857 acceptDialog.setButtonCancel(KGuiItem(i18n("&Return to Previous Configuration"), "button_cancel")); 00858 00859 KActiveLabel *label = new KActiveLabel(i18n("Your display devices has been configured " 00860 "to match the settings shown above. Please indicate whether you wish to " 00861 "keep this configuration. In 15 seconds the display will revert to your previous " 00862 "settings."), &acceptDialog, "userSpecifiedLabel"); 00863 00864 acceptDialog.setMainWidget(label); 00865 00866 KDialog::centerOnScreen(&acceptDialog, 0); 00867 00868 m_shownDialog = &acceptDialog; 00869 connect( m_shownDialog, TQT_SIGNAL( destroyed()), this, TQT_SLOT( shownDialogDestroyed())); 00870 connect( kapp->desktop(), TQT_SIGNAL( resized(int)), this, TQT_SLOT( desktopResized())); 00871 00872 return acceptDialog.exec(); 00873 } 00874 00875 KDE_EXPORT int RandRScreen::pixelCount( int index ) const 00876 { 00877 TQSize sz = pixelSize(index); 00878 return sz.width() * sz.height(); 00879 } 00880 00881 #include "randr.moc"