20 #include "lowlevel_randr.h"
26 #include <tdeglobal.h>
27 #include <tdeapplication.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 HotPlugRule::HotPlugRule()
48 HotPlugRule::~HotPlugRule()
53 SingleScreenData::SingleScreenData()
55 generic_screen_detected =
false;
56 screen_connected =
false;
58 current_resolution_index = 0;
59 current_refresh_rate_index = 0;
60 current_color_depth_index = 0;
66 current_rotation_index = ROTATION_0_DEGREES_INDEX;
67 current_orientation_mask = 0;
70 supports_transformations =
false;
74 absolute_x_position = 0;
75 absolute_y_position = 0;
76 current_x_pixel_count = 0;
77 current_y_pixel_count = 0;
81 dpms_standby_delay = 0;
82 dpms_suspend_delay = 0;
86 SingleScreenData::~SingleScreenData()
91 class RandRScreenPrivate
94 RandRScreenPrivate() : config(0L) {};
98 XRRFreeScreenConfigInfo(config);
102 XRRScreenConfiguration* config;
105 TDE_EXPORT RandRScreen::RandRScreen(
int screenIndex)
106 : d(new RandRScreenPrivate())
107 , m_screen(screenIndex)
108 , m_shownDialog(NULL)
114 TDE_EXPORT RandRScreen::~RandRScreen()
119 TDE_EXPORT
void RandRScreen::loadSettings()
122 XRRFreeScreenConfigInfo(d->config);
125 d->config = XRRGetScreenInfo(tqt_xdisplay(), RootWindow(tqt_xdisplay(), m_screen));
129 m_currentSize = m_proposedSize = XRRConfigCurrentConfiguration(d->config, &rotation);
130 m_currentRotation = m_proposedRotation = rotation;
133 m_currentSize = m_proposedSize = 0;
134 m_currentRotation = m_proposedRotation = 0;
137 m_pixelSizes.clear();
142 XRRScreenSize* sizes = XRRSizes(tqt_xdisplay(), m_screen, &numSizes);
143 for (
int i = 0; i < numSizes; i++) {
144 m_pixelSizes.append(TQSize(sizes[i].width, sizes[i].height));
145 m_mmSizes.append(TQSize(sizes[i].mwidth, sizes[i].mheight));
148 m_rotations = XRRRotations(tqt_xdisplay(), m_screen, &rotation);
152 ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay());
153 XRROutputInfo *output_info = screeninfo->outputs[m_screen]->info;
154 CrtcInfo *current_crtc = screeninfo->outputs[m_screen]->cur_crtc;
155 int numSizes = output_info->nmode;
156 for (
int i = 0; i < numSizes; i++) {
157 XRRModeInfo *xrrmode;
158 xrrmode = internal_find_mode_by_xid (screeninfo, output_info->modes[i]);
159 TQSize newSize = TQSize(xrrmode->width, xrrmode->height);
160 if (!m_pixelSizes.contains(newSize)) {
161 m_pixelSizes.append(newSize);
162 m_mmSizes.append(TQSize(output_info->mm_width, output_info->mm_height));
166 m_rotations = current_crtc->rotations;
167 m_currentRotation = m_proposedRotation = current_crtc->cur_rotation;
172 m_currentRefreshRate = m_proposedRefreshRate = refreshRateHzToIndex(m_currentSize, XRRConfigCurrentRate(d->config));
175 m_currentRefreshRate = m_proposedRefreshRate = 0;
179 TDE_EXPORT
void RandRScreen::setOriginal()
181 m_originalSize = m_currentSize;
182 m_originalRotation = m_currentRotation;
183 m_originalRefreshRate = m_currentRefreshRate;
186 TDE_EXPORT
bool RandRScreen::applyProposed()
193 d->config = XRRGetScreenInfo(tqt_xdisplay(), RootWindow(tqt_xdisplay(), m_screen));
198 if (proposedRefreshRate() < 0)
199 status = XRRSetScreenConfig(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), CurrentTime);
201 if( refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) <= 0 ) {
202 m_proposedRefreshRate = 0;
204 status = XRRSetScreenConfigAndRate(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), refreshRateIndexToHz(proposedSize(), proposedRefreshRate()), CurrentTime);
210 ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay());
211 screeninfo->cur_width = (*m_pixelSizes.at(proposedSize())).width();
212 screeninfo->cur_height = (*m_pixelSizes.at(proposedSize())).height();
213 internal_main_low_apply(screeninfo);
215 status = RRSetConfigSuccess;
220 if (status == RRSetConfigSuccess) {
221 m_currentSize = m_proposedSize;
222 m_currentRotation = m_proposedRotation;
223 m_currentRefreshRate = m_proposedRefreshRate;
230 TDE_EXPORT
bool RandRScreen::applyProposedAndConfirm()
232 if (proposedChanged()) {
235 if (applyProposed()) {
249 TDE_EXPORT
bool RandRScreen::confirm()
256 KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown,
260 i18n(
"Confirm Display Setting Change"),
261 KTimerDialog::Ok|KTimerDialog::Cancel,
262 KTimerDialog::Cancel);
264 acceptDialog.setButtonOK(KGuiItem(i18n(
"&Accept Configuration"),
"button_ok"));
265 acceptDialog.setButtonCancel(KGuiItem(i18n(
"&Return to Previous Configuration"),
"button_cancel"));
267 KActiveLabel *
label =
new KActiveLabel(i18n(
"Your screen orientation, size and refresh rate "
268 "have been changed to the requested settings. Please indicate whether you wish to "
269 "keep this configuration. In 15 seconds the display will revert to your previous "
270 "settings."), &acceptDialog,
"userSpecifiedLabel");
272 acceptDialog.setMainWidget(label);
274 KDialog::centerOnScreen(&acceptDialog, m_screen);
276 m_shownDialog = &acceptDialog;
277 connect( m_shownDialog, TQ_SIGNAL( destroyed()),
this, TQ_SLOT( shownDialogDestroyed()));
278 connect( kapp->desktop(), TQ_SIGNAL( resized(
int)),
this, TQ_SLOT( desktopResized()));
280 return acceptDialog.exec();
283 TDE_EXPORT
void RandRScreen::shownDialogDestroyed()
285 m_shownDialog = NULL;
286 disconnect( kapp->desktop(), TQ_SIGNAL( resized(
int)),
this, TQ_SLOT( desktopResized()));
289 TDE_EXPORT
void RandRScreen::desktopResized()
291 if( m_shownDialog != NULL )
292 KDialog::centerOnScreen(m_shownDialog, m_screen);
295 TDE_EXPORT TQString RandRScreen::changedMessage()
const
297 if (currentRefreshRate() == -1)
298 return i18n(
"New configuration:\nResolution: %1 x %2\nOrientation: %3")
299 .arg(currentPixelWidth())
300 .arg(currentPixelHeight())
301 .arg(currentRotationDescription());
303 return i18n(
"New configuration:\nResolution: %1 x %2\nOrientation: %3\nRefresh rate: %4")
304 .arg(currentPixelWidth())
305 .arg(currentPixelHeight())
306 .arg(currentRotationDescription())
307 .arg(currentRefreshRateDescription());
310 TDE_EXPORT
bool RandRScreen::changedFromOriginal()
const
312 return m_currentSize != m_originalSize || m_currentRotation != m_originalRotation || m_currentRefreshRate != m_originalRefreshRate;
315 TDE_EXPORT
void RandRScreen::proposeOriginal()
317 m_proposedSize = m_originalSize;
318 m_proposedRotation = m_originalRotation;
319 m_proposedRefreshRate = m_originalRefreshRate;
322 TDE_EXPORT
bool RandRScreen::proposedChanged()
const
324 return m_currentSize != m_proposedSize || m_currentRotation != m_proposedRotation || m_currentRefreshRate != m_proposedRefreshRate;
327 TDE_EXPORT TQString RandRScreen::rotationName(
int rotation,
bool pastTense,
bool capitalised)
332 return i18n(
"Normal");
334 return i18n(
"Left (90 degrees)");
336 return i18n(
"Upside-down (180 degrees)");
338 return i18n(
"Right (270 degrees)");
340 return i18n(
"Mirror horizontally");
342 return i18n(
"Mirror vertically");
344 return i18n(
"Unknown orientation");
349 return i18n(
"Normal");
351 return i18n(
"Rotated 90 degrees counterclockwise");
353 return i18n(
"Rotated 180 degrees counterclockwise");
355 return i18n(
"Rotated 270 degrees counterclockwise");
357 if (rotation & RR_Reflect_X)
358 if (rotation & RR_Reflect_Y)
360 return i18n(
"Mirrored horizontally and vertically");
362 return i18n(
"mirrored horizontally and vertically");
365 return i18n(
"Mirrored horizontally");
367 return i18n(
"mirrored horizontally");
368 else if (rotation & RR_Reflect_Y)
370 return i18n(
"Mirrored vertically");
372 return i18n(
"mirrored vertically");
375 return i18n(
"Unknown orientation");
377 return i18n(
"unknown orientation");
381 TDE_EXPORT TQPixmap RandRScreen::rotationIcon(
int rotation)
const
384 if (!(m_currentRotation & RR_Rotate_0) && rotation & (RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270)) {
385 int currentAngle = m_currentRotation & (RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270);
386 switch (currentAngle) {
399 if (rotation > RR_Rotate_270) {
406 return SmallIcon(
"go-up");
408 return SmallIcon(
"back");
410 return SmallIcon(
"go-down");
412 return SmallIcon(
"forward");
416 return SmallIcon(
"process-stop");
420 TDE_EXPORT TQString RandRScreen::currentRotationDescription()
const
422 TQString ret = rotationName(m_currentRotation & RotateMask);
424 if (m_currentRotation != (m_currentRotation & RotateMask)) {
425 if (m_currentRotation & RR_Rotate_0) {
426 ret = rotationName(m_currentRotation & (RR_Reflect_X + RR_Reflect_X),
true,
true);
429 ret +=
", " + rotationName(m_currentRotation & (RR_Reflect_X + RR_Reflect_X),
true,
false);
436 TDE_EXPORT
int RandRScreen::rotationIndexToDegree(
int rotation)
const
438 switch (rotation & RotateMask) {
453 TDE_EXPORT
int RandRScreen::rotationDegreeToIndex(
int degree)
const
460 return RR_Rotate_180;
463 return RR_Rotate_270;
470 TDE_EXPORT
int RandRScreen::currentPixelWidth()
const
472 return m_pixelSizes[m_currentSize].width();
475 TDE_EXPORT
int RandRScreen::currentPixelHeight()
const
477 return m_pixelSizes[m_currentSize].height();
480 TDE_EXPORT
int RandRScreen::currentMMWidth()
const
482 return m_pixelSizes[m_currentSize].width();
485 TDE_EXPORT
int RandRScreen::currentMMHeight()
const
487 return m_pixelSizes[m_currentSize].height();
490 TDE_EXPORT TQStringList RandRScreen::refreshRates(
int size)
const
496 short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates);
498 for (
int i = 0; i < nrates; i++)
499 ret << refreshRateDirectDescription(rates[i]);
503 ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay());
504 int numSizes = screeninfo->res->nmode;
505 for (
int i = 0; i < numSizes; i++) {
506 int refresh_rate = ((screeninfo->res->modes[i].dotClock*1.0)/((screeninfo->res->modes[i].hTotal)*(screeninfo->res->modes[i].vTotal)*1.0));
507 TQString newRate = refreshRateDirectDescription(refresh_rate);
508 if (!ret.contains(newRate)) {
517 TDE_EXPORT TQString RandRScreen::refreshRateDirectDescription(
int rate)
const
519 return i18n(
"Refresh rate in Hertz (Hz)",
"%1 Hz").arg(rate);
522 TDE_EXPORT TQString RandRScreen::refreshRateIndirectDescription(
int size,
int index)
const
524 return i18n(
"Refresh rate in Hertz (Hz)",
"%1 Hz").arg(refreshRateIndexToHz(size, index));
527 TDE_EXPORT TQString RandRScreen::refreshRateDescription(
int size,
int index)
const
529 return refreshRates(size)[index];
532 TDE_EXPORT
bool RandRScreen::proposeRefreshRate(
int index)
534 if (index >= 0 && (
int)refreshRates(proposedSize()).count() > index) {
535 m_proposedRefreshRate = index;
542 TDE_EXPORT
int RandRScreen::currentRefreshRate()
const
544 return m_currentRefreshRate;
547 TDE_EXPORT TQString RandRScreen::currentRefreshRateDescription()
const
549 return refreshRateIndirectDescription(m_currentSize, m_currentRefreshRate);
552 TDE_EXPORT
int RandRScreen::proposedRefreshRate()
const
554 return m_proposedRefreshRate;
557 TDE_EXPORT
int RandRScreen::refreshRateHzToIndex(
int size,
int hz)
const
560 short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates);
562 for (
int i = 0; i < nrates; i++)
573 TDE_EXPORT
int RandRScreen::refreshRateIndexToHz(
int size,
int index)
const
576 short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates);
578 if (nrates == 0 || index < 0)
588 TDE_EXPORT
int RandRScreen::numSizes()
const
590 return m_pixelSizes.count();
593 TDE_EXPORT
const TQSize& RandRScreen::pixelSize(
int index)
const
595 return m_pixelSizes[index];
598 TDE_EXPORT
const TQSize& RandRScreen::mmSize(
int index)
const
600 return m_mmSizes[index];
603 TDE_EXPORT
int RandRScreen::sizeIndex(TQSize pixelSize)
const
605 for (uint i = 0; i < m_pixelSizes.count(); i++)
606 if (m_pixelSizes[i] == pixelSize)
612 TDE_EXPORT
int RandRScreen::rotations()
const
617 TDE_EXPORT
int RandRScreen::currentRotation()
const
619 return m_currentRotation;
622 TDE_EXPORT
int RandRScreen::currentSize()
const
624 return m_currentSize;
627 TDE_EXPORT
int RandRScreen::proposedRotation()
const
629 return m_proposedRotation;
632 TDE_EXPORT
void RandRScreen::proposeRotation(
int newRotation)
634 m_proposedRotation = newRotation & OrientationMask;
637 TDE_EXPORT
int RandRScreen::proposedSize()
const
639 return m_proposedSize;
642 TDE_EXPORT
bool RandRScreen::proposeSize(
int newSize)
644 if ((
int)m_pixelSizes.count() > newSize) {
645 m_proposedSize = newSize;
652 TDE_EXPORT
void RandRScreen::load(
TDEConfig& config)
654 config.
setGroup(TQString(
"Screen%1").arg(m_screen));
656 if (proposeSize(sizeIndex(TQSize(config.
readNumEntry(
"width", currentPixelWidth()), config.
readNumEntry(
"height", currentPixelHeight())))))
657 proposeRefreshRate(refreshRateHzToIndex(proposedSize(), config.
readNumEntry(
"refresh", currentRefreshRate())));
662 TDE_EXPORT
void RandRScreen::save(
TDEConfig& config)
const
664 config.
setGroup(TQString(
"Screen%1").arg(m_screen));
665 config.
writeEntry(
"width", currentPixelWidth());
666 config.
writeEntry(
"height", currentPixelHeight());
667 config.
writeEntry(
"refresh", refreshRateIndexToHz(currentSize(), currentRefreshRate()));
668 config.
writeEntry(
"rotation", rotationIndexToDegree(currentRotation()));
669 config.
writeEntry(
"reflectX", (
bool)(currentRotation() & ReflectMask) == ReflectX);
670 config.
writeEntry(
"reflectY", (
bool)(currentRotation() & ReflectMask) == ReflectY);
673 TDE_EXPORT RandRDisplay::RandRDisplay()
677 Status s = XRRQueryExtension(tqt_xdisplay(), &m_eventBase, &m_errorBase);
679 m_errorCode = TQString(
"%1, base %1").arg(s).arg(m_errorBase);
686 Display *randr_display = XOpenDisplay(NULL);
690 screen_num = DefaultScreen (randr_display);
691 root_window = RootWindow (randr_display, screen_num);
692 if (XRRGetScreenResources (randr_display, root_window) == NULL) {
693 m_errorCode = i18n(
"No screens detected");
698 int major_version, minor_version;
699 XRRQueryVersion(tqt_xdisplay(), &major_version, &minor_version);
701 m_version = TQString(
"X Resize and Rotate extension version %1.%1").arg(major_version).arg(minor_version);
703 m_numScreens = ScreenCount(tqt_xdisplay());
708 m_screens.setAutoDelete(
true);
709 for (
int i = 0; i < m_numScreens; i++) {
710 m_screens.append(
new RandRScreen(i));
713 setCurrentScreen(TQApplication::desktop()->primaryScreen());
716 TDE_EXPORT
bool RandRDisplay::isValid()
const
721 TDE_EXPORT
const TQString& RandRDisplay::errorCode()
const
726 TDE_EXPORT
int RandRDisplay::eventBase()
const
731 TDE_EXPORT
int RandRDisplay::screenChangeNotifyEvent()
const
733 return m_eventBase + RRScreenChangeNotify;
736 TDE_EXPORT
int RandRDisplay::errorBase()
const
741 TDE_EXPORT
const TQString& RandRDisplay::version()
const
746 TDE_EXPORT
void RandRDisplay::setCurrentScreen(
int index)
748 m_currentScreenIndex = index;
749 m_currentScreen = m_screens.at(m_currentScreenIndex);
750 Q_ASSERT(m_currentScreen);
753 TDE_EXPORT
int RandRDisplay::screenIndexOfWidget(TQWidget* widget)
755 int ret = TQApplication::desktop()->screenNumber(widget);
756 return ret != -1 ? ret : TQApplication::desktop()->primaryScreen();
759 TDE_EXPORT
int RandRDisplay::currentScreenIndex()
const
761 return m_currentScreenIndex;
764 TDE_EXPORT
void RandRDisplay::refresh()
766 for (RandRScreen* s = m_screens.first(); s; s = m_screens.next())
770 TDE_EXPORT
int RandRDisplay::numScreens()
const
775 TDE_EXPORT RandRScreen* RandRDisplay::screen(
int index)
777 return m_screens.at(index);
780 TDE_EXPORT RandRScreen* RandRDisplay::currentScreen()
782 return m_currentScreen;
785 TDE_EXPORT
bool RandRDisplay::loadDisplay(
TDEConfig& config,
bool loadScreens)
788 for (RandRScreen* s = m_screens.first(); s; s = m_screens.next())
791 return applyOnStartup(config);
794 TDE_EXPORT
bool RandRDisplay::applyOnStartup(
TDEConfig& config)
800 TDE_EXPORT
bool RandRDisplay::syncTrayApp(
TDEConfig& config)
806 TDE_EXPORT
void RandRDisplay::saveDisplay(
TDEConfig& config,
bool applyOnStartup,
bool syncTrayApp)
811 config.
writeEntry(
"ApplyOnStartup", applyOnStartup);
812 config.
writeEntry(
"SyncTrayApp", syncTrayApp);
814 for (RandRScreen* s = m_screens.first(); s; s = m_screens.next())
818 TDE_EXPORT
void RandRDisplay::applyProposed(
bool confirm)
820 for (
int screenIndex = 0; screenIndex < numScreens(); screenIndex++) {
821 if (screen(screenIndex)->proposedChanged()) {
823 screen(screenIndex)->applyProposedAndConfirm();
825 screen(screenIndex)->applyProposed();
830 TDE_EXPORT
bool RandRDisplay::showTestConfigurationDialog()
832 RandRScreen* firstScreen = screen(0);
834 return firstScreen->showTestConfigurationDialog();
841 TDE_EXPORT
bool RandRScreen::showTestConfigurationDialog()
848 KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown,
852 i18n(
"Confirm Display Settings"),
853 KTimerDialog::Ok|KTimerDialog::Cancel,
854 KTimerDialog::Cancel);
856 acceptDialog.setButtonOK(KGuiItem(i18n(
"&Accept Configuration"),
"button_ok"));
857 acceptDialog.setButtonCancel(KGuiItem(i18n(
"&Return to Previous Configuration"),
"button_cancel"));
859 KActiveLabel *
label =
new KActiveLabel(i18n(
"Your display devices has been configured "
860 "to match the settings shown above. Please indicate whether you wish to "
861 "keep this configuration. In 15 seconds the display will revert to your previous "
862 "settings."), &acceptDialog,
"userSpecifiedLabel");
864 acceptDialog.setMainWidget(label);
866 KDialog::centerOnScreen(&acceptDialog, 0);
868 m_shownDialog = &acceptDialog;
869 connect( m_shownDialog, TQ_SIGNAL( destroyed()),
this, TQ_SLOT( shownDialogDestroyed()));
870 connect( kapp->desktop(), TQ_SIGNAL( resized(
int)),
this, TQ_SLOT( desktopResized()));
872 return acceptDialog.exec();
875 TDE_EXPORT
int RandRScreen::pixelCount(
int index )
const
877 TQSize sz = pixelSize(index);
878 return sz.width() * sz.height();
Provides a dialog that is only available for a specified amount of time, and reports the time remaini...
static TDEApplication * kApplication()
int readNumEntry(const TQString &pKey, int nDefault=0) const
bool readBoolEntry(const TQString &pKey, bool bDefault=false) const
void writeEntry(const TQString &pKey, const TQString &pValue, bool bPersistent=true, bool bGlobal=false, bool bNLS=false)
void setGroup(const TQString &group)
TQString label(StdAccel id)