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