20 #include "lowlevel_randr.h" 27 #include <kapplication.h> 28 #include <kiconloader.h> 29 #include <dcopclient.h> 31 #include <kactivelabel.h> 33 #include "ktimerdialog.h" 37 #define INT32 _X11INT32 38 #include <X11/Xproto.h> 41 #include <X11/extensions/Xrandr.h> 43 class RandRScreenPrivate
46 RandRScreenPrivate() : config(0L) {};
50 XRRFreeScreenConfigInfo(config);
53 XRRScreenConfiguration* config;
56 KDE_EXPORT RandRScreen::RandRScreen(
int screenIndex)
57 : d(new RandRScreenPrivate())
58 , m_screen(screenIndex)
65 KDE_EXPORT RandRScreen::~RandRScreen()
70 KDE_EXPORT
void RandRScreen::loadSettings()
73 XRRFreeScreenConfigInfo(d->config);
75 d->config = XRRGetScreenInfo(qt_xdisplay(), RootWindow(qt_xdisplay(), m_screen));
79 m_currentSize = m_proposedSize = XRRConfigCurrentConfiguration(d->config, &rotation);
80 m_currentRotation = m_proposedRotation = rotation;
83 m_currentSize = m_proposedSize = 0;
84 m_currentRotation = m_proposedRotation = 0;
92 XRRScreenSize* sizes = XRRSizes(qt_xdisplay(), m_screen, &numSizes);
93 for (
int i = 0; i < numSizes; i++) {
94 m_pixelSizes.append(TQSize(sizes[i].width, sizes[i].height));
95 m_mmSizes.append(TQSize(sizes[i].mwidth, sizes[i].mheight));
98 m_rotations = XRRRotations(qt_xdisplay(), m_screen, &rotation);
102 ScreenInfo *screeninfo = internal_read_screen_info(qt_xdisplay());
103 XRROutputInfo *output_info = screeninfo->outputs[m_screen]->info;
104 CrtcInfo *current_crtc = screeninfo->outputs[m_screen]->cur_crtc;
105 int numSizes = screeninfo->res->nmode;
106 for (
int i = 0; i < numSizes; i++) {
107 TQSize newSize = TQSize(screeninfo->res->modes[i].width, screeninfo->res->modes[i].height);
108 if (!m_pixelSizes.contains(newSize)) {
109 m_pixelSizes.append(newSize);
110 m_mmSizes.append(TQSize(output_info->mm_width, output_info->mm_height));
114 m_rotations = current_crtc->rotations;
115 m_currentRotation = m_proposedRotation = current_crtc->cur_rotation;
120 m_currentRefreshRate = m_proposedRefreshRate = refreshRateHzToIndex(m_currentSize, XRRConfigCurrentRate(d->config));
123 m_currentRefreshRate = m_proposedRefreshRate = 0;
127 KDE_EXPORT
void RandRScreen::setOriginal()
129 m_originalSize = m_currentSize;
130 m_originalRotation = m_currentRotation;
131 m_originalRefreshRate = m_currentRefreshRate;
134 KDE_EXPORT
bool RandRScreen::applyProposed()
141 d->config = XRRGetScreenInfo(qt_xdisplay(), RootWindow(qt_xdisplay(), m_screen));
146 if (proposedRefreshRate() < 0)
147 status = XRRSetScreenConfig(qt_xdisplay(), d->config, DefaultRootWindow(qt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), CurrentTime);
149 if( refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) <= 0 ) {
150 m_proposedRefreshRate = 0;
152 status = XRRSetScreenConfigAndRate(qt_xdisplay(), d->config, DefaultRootWindow(qt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), refreshRateIndexToHz(proposedSize(), proposedRefreshRate()), CurrentTime);
158 ScreenInfo *screeninfo = internal_read_screen_info(qt_xdisplay());
159 screeninfo->cur_width = (*m_pixelSizes.at(proposedSize())).width();
160 screeninfo->cur_height = (*m_pixelSizes.at(proposedSize())).height();
161 internal_main_low_apply(screeninfo);
163 status = RRSetConfigSuccess;
168 if (status == RRSetConfigSuccess) {
169 m_currentSize = m_proposedSize;
170 m_currentRotation = m_proposedRotation;
171 m_currentRefreshRate = m_proposedRefreshRate;
178 KDE_EXPORT
bool RandRScreen::applyProposedAndConfirm()
180 if (proposedChanged()) {
183 if (applyProposed()) {
197 KDE_EXPORT
bool RandRScreen::confirm()
204 KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown,
208 i18n(
"Confirm Display Setting Change"),
209 KTimerDialog::Ok|KTimerDialog::Cancel,
210 KTimerDialog::Cancel);
212 acceptDialog.setButtonOK(KGuiItem(i18n(
"&Accept Configuration"),
"button_ok"));
213 acceptDialog.setButtonCancel(KGuiItem(i18n(
"&Return to Previous Configuration"),
"button_cancel"));
215 KActiveLabel *
label =
new KActiveLabel(i18n(
"Your screen orientation, size and refresh rate " 216 "have been changed to the requested settings. Please indicate whether you wish to " 217 "keep this configuration. In 15 seconds the display will revert to your previous " 218 "settings."), &acceptDialog,
"userSpecifiedLabel");
220 acceptDialog.setMainWidget(label);
222 KDialog::centerOnScreen(&acceptDialog, m_screen);
224 m_shownDialog = &acceptDialog;
225 connect( m_shownDialog, TQT_SIGNAL( destroyed()),
this, TQT_SLOT( shownDialogDestroyed()));
226 connect( kapp->desktop(), TQT_SIGNAL( resized(
int)),
this, TQT_SLOT( desktopResized()));
228 return acceptDialog.exec();
231 KDE_EXPORT
void RandRScreen::shownDialogDestroyed()
233 m_shownDialog = NULL;
234 disconnect( kapp->desktop(), TQT_SIGNAL( resized(
int)),
this, TQT_SLOT( desktopResized()));
237 KDE_EXPORT
void RandRScreen::desktopResized()
239 if( m_shownDialog != NULL )
240 KDialog::centerOnScreen(m_shownDialog, m_screen);
243 KDE_EXPORT TQString RandRScreen::changedMessage()
const 245 if (currentRefreshRate() == -1)
246 return i18n(
"New configuration:\nResolution: %1 x %2\nOrientation: %3")
247 .arg(currentPixelWidth())
248 .arg(currentPixelHeight())
249 .arg(currentRotationDescription());
251 return i18n(
"New configuration:\nResolution: %1 x %2\nOrientation: %3\nRefresh rate: %4")
252 .arg(currentPixelWidth())
253 .arg(currentPixelHeight())
254 .arg(currentRotationDescription())
255 .arg(currentRefreshRateDescription());
258 KDE_EXPORT
bool RandRScreen::changedFromOriginal()
const 260 return m_currentSize != m_originalSize || m_currentRotation != m_originalRotation || m_currentRefreshRate != m_originalRefreshRate;
263 KDE_EXPORT
void RandRScreen::proposeOriginal()
265 m_proposedSize = m_originalSize;
266 m_proposedRotation = m_originalRotation;
267 m_proposedRefreshRate = m_originalRefreshRate;
270 KDE_EXPORT
bool RandRScreen::proposedChanged()
const 272 return m_currentSize != m_proposedSize || m_currentRotation != m_proposedRotation || m_currentRefreshRate != m_proposedRefreshRate;
275 KDE_EXPORT TQString RandRScreen::rotationName(
int rotation,
bool pastTense,
bool capitalised)
280 return i18n(
"Normal");
282 return i18n(
"Left (90 degrees)");
284 return i18n(
"Upside-down (180 degrees)");
286 return i18n(
"Right (270 degrees)");
288 return i18n(
"Mirror horizontally");
290 return i18n(
"Mirror vertically");
292 return i18n(
"Unknown orientation");
297 return i18n(
"Normal");
299 return i18n(
"Rotated 90 degrees counterclockwise");
301 return i18n(
"Rotated 180 degrees counterclockwise");
303 return i18n(
"Rotated 270 degrees counterclockwise");
305 if (rotation & RR_Reflect_X)
306 if (rotation & RR_Reflect_Y)
308 return i18n(
"Mirrored horizontally and vertically");
310 return i18n(
"mirrored horizontally and vertically");
313 return i18n(
"Mirrored horizontally");
315 return i18n(
"mirrored horizontally");
316 else if (rotation & RR_Reflect_Y)
318 return i18n(
"Mirrored vertically");
320 return i18n(
"mirrored vertically");
323 return i18n(
"Unknown orientation");
325 return i18n(
"unknown orientation");
329 KDE_EXPORT TQPixmap RandRScreen::rotationIcon(
int rotation)
const 332 if (!(m_currentRotation & RR_Rotate_0) && rotation & (RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270)) {
333 int currentAngle = m_currentRotation & (RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270);
334 switch (currentAngle) {
347 if (rotation > RR_Rotate_270) {
354 return SmallIcon(
"up");
356 return SmallIcon(
"back");
358 return SmallIcon(
"down");
360 return SmallIcon(
"forward");
364 return SmallIcon(
"stop");
368 KDE_EXPORT TQString RandRScreen::currentRotationDescription()
const 370 TQString ret = rotationName(m_currentRotation & RotateMask);
372 if (m_currentRotation != (m_currentRotation & RotateMask)) {
373 if (m_currentRotation & RR_Rotate_0) {
374 ret = rotationName(m_currentRotation & (RR_Reflect_X + RR_Reflect_X),
true,
true);
377 ret +=
", " + rotationName(m_currentRotation & (RR_Reflect_X + RR_Reflect_X),
true,
false);
384 KDE_EXPORT
int RandRScreen::rotationIndexToDegree(
int rotation)
const 386 switch (rotation & RotateMask) {
401 KDE_EXPORT
int RandRScreen::rotationDegreeToIndex(
int degree)
const 408 return RR_Rotate_180;
411 return RR_Rotate_270;
418 KDE_EXPORT
int RandRScreen::currentPixelWidth()
const 420 return m_pixelSizes[m_currentSize].width();
423 KDE_EXPORT
int RandRScreen::currentPixelHeight()
const 425 return m_pixelSizes[m_currentSize].height();
428 KDE_EXPORT
int RandRScreen::currentMMWidth()
const 430 return m_pixelSizes[m_currentSize].width();
433 KDE_EXPORT
int RandRScreen::currentMMHeight()
const 435 return m_pixelSizes[m_currentSize].height();
438 KDE_EXPORT TQStringList RandRScreen::refreshRates(
int size)
const 444 short* rates = XRRRates(qt_xdisplay(), m_screen, (SizeID)size, &nrates);
446 for (
int i = 0; i < nrates; i++)
447 ret << refreshRateDirectDescription(rates[i]);
451 ScreenInfo *screeninfo = internal_read_screen_info(qt_xdisplay());
452 int numSizes = screeninfo->res->nmode;
453 for (
int i = 0; i < numSizes; i++) {
454 int refresh_rate = ((screeninfo->res->modes[i].dotClock*1.0)/((screeninfo->res->modes[i].hTotal)*(screeninfo->res->modes[i].vTotal)*1.0));
455 TQString newRate = refreshRateDirectDescription(refresh_rate);
456 if (!ret.contains(newRate)) {
465 KDE_EXPORT TQString RandRScreen::refreshRateDirectDescription(
int rate)
const 467 return i18n(
"Refresh rate in Hertz (Hz)",
"%1 Hz").arg(rate);
470 KDE_EXPORT TQString RandRScreen::refreshRateIndirectDescription(
int size,
int index)
const 472 return i18n(
"Refresh rate in Hertz (Hz)",
"%1 Hz").arg(refreshRateIndexToHz(size, index));
475 KDE_EXPORT TQString RandRScreen::refreshRateDescription(
int size,
int index)
const 477 return refreshRates(size)[index];
480 KDE_EXPORT
bool RandRScreen::proposeRefreshRate(
int index)
482 if (index >= 0 && (
int)refreshRates(proposedSize()).count() > index) {
483 m_proposedRefreshRate = index;
490 KDE_EXPORT
int RandRScreen::currentRefreshRate()
const 492 return m_currentRefreshRate;
495 KDE_EXPORT TQString RandRScreen::currentRefreshRateDescription()
const 497 return refreshRateIndirectDescription(m_currentSize, m_currentRefreshRate);
500 KDE_EXPORT
int RandRScreen::proposedRefreshRate()
const 502 return m_proposedRefreshRate;
505 KDE_EXPORT
int RandRScreen::refreshRateHzToIndex(
int size,
int hz)
const 508 short* rates = XRRRates(qt_xdisplay(), m_screen, (SizeID)size, &nrates);
510 for (
int i = 0; i < nrates; i++)
521 KDE_EXPORT
int RandRScreen::refreshRateIndexToHz(
int size,
int index)
const 524 short* rates = XRRRates(qt_xdisplay(), m_screen, (SizeID)size, &nrates);
526 if (nrates == 0 || index < 0)
536 KDE_EXPORT
int RandRScreen::numSizes()
const 538 return m_pixelSizes.count();
541 KDE_EXPORT
const TQSize& RandRScreen::pixelSize(
int index)
const 543 return m_pixelSizes[index];
546 KDE_EXPORT
const TQSize& RandRScreen::mmSize(
int index)
const 548 return m_mmSizes[index];
551 KDE_EXPORT
int RandRScreen::sizeIndex(TQSize pixelSize)
const 553 for (uint i = 0; i < m_pixelSizes.count(); i++)
554 if (m_pixelSizes[i] == pixelSize)
560 KDE_EXPORT
int RandRScreen::rotations()
const 565 KDE_EXPORT
int RandRScreen::currentRotation()
const 567 return m_currentRotation;
570 KDE_EXPORT
int RandRScreen::currentSize()
const 572 return m_currentSize;
575 KDE_EXPORT
int RandRScreen::proposedRotation()
const 577 return m_proposedRotation;
580 KDE_EXPORT
void RandRScreen::proposeRotation(
int newRotation)
582 m_proposedRotation = newRotation & OrientationMask;
585 KDE_EXPORT
int RandRScreen::proposedSize()
const 587 return m_proposedSize;
590 KDE_EXPORT
bool RandRScreen::proposeSize(
int newSize)
592 if ((
int)m_pixelSizes.count() > newSize) {
593 m_proposedSize = newSize;
600 KDE_EXPORT
void RandRScreen::load(
KConfig& config)
602 config.
setGroup(TQString(
"Screen%1").arg(m_screen));
604 if (proposeSize(sizeIndex(TQSize(config.
readNumEntry(
"width", currentPixelWidth()), config.
readNumEntry(
"height", currentPixelHeight())))))
605 proposeRefreshRate(refreshRateHzToIndex(proposedSize(), config.
readNumEntry(
"refresh", currentRefreshRate())));
610 KDE_EXPORT
void RandRScreen::save(
KConfig& config)
const 612 config.
setGroup(TQString(
"Screen%1").arg(m_screen));
613 config.
writeEntry(
"width", currentPixelWidth());
614 config.
writeEntry(
"height", currentPixelHeight());
615 config.
writeEntry(
"refresh", refreshRateIndexToHz(currentSize(), currentRefreshRate()));
616 config.
writeEntry(
"rotation", rotationIndexToDegree(currentRotation()));
617 config.
writeEntry(
"reflectX", (
bool)(currentRotation() & ReflectMask) == ReflectX);
618 config.
writeEntry(
"reflectY", (
bool)(currentRotation() & ReflectMask) == ReflectY);
621 KDE_EXPORT RandRDisplay::RandRDisplay()
625 Status s = XRRQueryExtension(qt_xdisplay(), &m_eventBase, &m_errorBase);
627 m_errorCode = TQString(
"%1, base %1").arg(s).arg(m_errorBase);
634 Display *randr_display = XOpenDisplay(NULL);
638 screen_num = DefaultScreen (randr_display);
639 root_window = RootWindow (randr_display, screen_num);
640 if (XRRGetScreenResources (randr_display, root_window) == NULL) {
641 m_errorCode = i18n(
"No screens detected");
646 int major_version, minor_version;
647 XRRQueryVersion(qt_xdisplay(), &major_version, &minor_version);
649 m_version = TQString(
"X Resize and Rotate extension version %1.%1").arg(major_version).arg(minor_version);
651 m_numScreens = ScreenCount(qt_xdisplay());
656 m_screens.setAutoDelete(
true);
657 for (
int i = 0; i < m_numScreens; i++) {
658 m_screens.append(
new RandRScreen(i));
661 setCurrentScreen(TQApplication::desktop()->primaryScreen());
664 KDE_EXPORT
bool RandRDisplay::isValid()
const 669 KDE_EXPORT
const TQString& RandRDisplay::errorCode()
const 674 KDE_EXPORT
int RandRDisplay::eventBase()
const 679 KDE_EXPORT
int RandRDisplay::screenChangeNotifyEvent()
const 681 return m_eventBase + RRScreenChangeNotify;
684 KDE_EXPORT
int RandRDisplay::errorBase()
const 689 KDE_EXPORT
const TQString& RandRDisplay::version()
const 694 KDE_EXPORT
void RandRDisplay::setCurrentScreen(
int index)
696 m_currentScreenIndex = index;
697 m_currentScreen = m_screens.at(m_currentScreenIndex);
698 Q_ASSERT(m_currentScreen);
701 KDE_EXPORT
int RandRDisplay::screenIndexOfWidget(TQWidget* widget)
703 int ret = TQApplication::desktop()->screenNumber(widget);
704 return ret != -1 ? ret : TQApplication::desktop()->primaryScreen();
707 KDE_EXPORT
int RandRDisplay::currentScreenIndex()
const 709 return m_currentScreenIndex;
712 KDE_EXPORT
void RandRDisplay::refresh()
714 for (RandRScreen* s = m_screens.first(); s; s = m_screens.next())
718 KDE_EXPORT
int RandRDisplay::numScreens()
const 723 KDE_EXPORT RandRScreen* RandRDisplay::screen(
int index)
725 return m_screens.at(index);
728 KDE_EXPORT RandRScreen* RandRDisplay::currentScreen()
730 return m_currentScreen;
733 KDE_EXPORT
bool RandRDisplay::loadDisplay(
KConfig& config,
bool loadScreens)
736 for (RandRScreen* s = m_screens.first(); s; s = m_screens.next())
739 return applyOnStartup(config);
742 KDE_EXPORT
bool RandRDisplay::applyOnStartup(
KConfig& config)
748 KDE_EXPORT
bool RandRDisplay::syncTrayApp(
KConfig& config)
754 KDE_EXPORT
void RandRDisplay::saveDisplay(
KConfig& config,
bool applyOnStartup,
bool syncTrayApp)
759 config.
writeEntry(
"ApplyOnStartup", applyOnStartup);
760 config.
writeEntry(
"SyncTrayApp", syncTrayApp);
762 for (RandRScreen* s = m_screens.first(); s; s = m_screens.next())
766 KDE_EXPORT
void RandRDisplay::applyProposed(
bool confirm)
768 for (
int screenIndex = 0; screenIndex < numScreens(); screenIndex++) {
769 if (screen(screenIndex)->proposedChanged()) {
771 screen(screenIndex)->applyProposedAndConfirm();
773 screen(screenIndex)->applyProposed();
778 KDE_EXPORT
bool RandRDisplay::showTestConfigurationDialog()
780 return screen(0)->showTestConfigurationDialog();
783 KDE_EXPORT
bool RandRScreen::showTestConfigurationDialog()
790 KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown,
794 i18n(
"Confirm Display Settings"),
795 KTimerDialog::Ok|KTimerDialog::Cancel,
796 KTimerDialog::Cancel);
798 acceptDialog.setButtonOK(KGuiItem(i18n(
"&Accept Configuration"),
"button_ok"));
799 acceptDialog.setButtonCancel(KGuiItem(i18n(
"&Return to Previous Configuration"),
"button_cancel"));
801 KActiveLabel *label =
new KActiveLabel(i18n(
"Your display devices has been configured " 802 "to match the settings shown above. Please indicate whether you wish to " 803 "keep this configuration. In 15 seconds the display will revert to your previous " 804 "settings."), &acceptDialog,
"userSpecifiedLabel");
806 acceptDialog.setMainWidget(label);
808 KDialog::centerOnScreen(&acceptDialog, 0);
810 m_shownDialog = &acceptDialog;
811 connect( m_shownDialog, TQT_SIGNAL( destroyed()),
this, TQT_SLOT( shownDialogDestroyed()));
812 connect( kapp->desktop(), TQT_SIGNAL( resized(
int)),
this, TQT_SLOT( desktopResized()));
814 return acceptDialog.exec();
817 KDE_EXPORT
int RandRScreen::pixelCount(
int index )
const 819 TQSize sz = pixelSize(index);
820 return sz.width() * sz.height();
TQString label(StdAccel id)
void writeEntry(const TQString &pKey, const TQString &pValue, bool bPersistent=true, bool bGlobal=false, bool bNLS=false)
void setGroup(const TQString &group)
bool readBoolEntry(const TQString &pKey, bool bDefault=false) const
static KApplication * kApplication()
int readNumEntry(const TQString &pKey, int nDefault=0) const
Provides a dialog that is only available for a specified amount of time, and reports the time remaini...