tderandr: workaround for tde/75

Some videocards' drivers (most notably propryetary nvidia) report
incorrect screen refresh rate via XRRRates(). Use
XRRGetScreenResources() + some math borrowed from xrandr instead.

Bug: https://mirror.git.trinitydesktop.org/gitea/TDE/tde/issues/75
Signed-off-by: Alexander Golubev <fatzer2@gmail.com>
fix/tde-75
Alexander Golubev 4 months ago
parent ac6c53f3fa
commit d32b076ae6

@ -40,6 +40,10 @@
#undef INT32
#include <X11/extensions/Xrandr.h>
static int refreshRateForModeInfo (const XRRModeInfo *mode_info);
static int refreshRateIndexToXRR(int screen, int size, int index);
static int refreshRateXRRToIndex(int screen, int size, int hz);
HotPlugRule::HotPlugRule()
{
//
@ -169,7 +173,8 @@ KDE_EXPORT void RandRScreen::loadSettings()
}
if (d->config) {
m_currentRefreshRate = m_proposedRefreshRate = refreshRateHzToIndex(m_currentSize, XRRConfigCurrentRate(d->config));
m_currentRefreshRate = m_proposedRefreshRate =
refreshRateXRRToIndex(m_screen, m_currentSize, XRRConfigCurrentRate(d->config));
}
else {
m_currentRefreshRate = m_proposedRefreshRate = 0;
@ -185,8 +190,12 @@ KDE_EXPORT void RandRScreen::setOriginal()
KDE_EXPORT bool RandRScreen::applyProposed()
{
//kdDebug() << k_funcinfo << " size " << (SizeID)proposedSize() << ", rotation " << proposedRotation() << ", refresh " << refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) << endl;
#if 0
kdDebug() << k_funcinfo << " size " << (SizeID)proposedSize() <<
", rotation " << proposedRotation() <<
", refresh " << refreshRateIndexToHz(proposedSize(), proposedRefreshRate())
<< " (" << refreshRateIndexToXRR(m_screen, proposedSize(), proposedRefreshRate()) << ")" << endl;
#endif
Status status;
if (!d->config) {
@ -198,10 +207,11 @@ KDE_EXPORT bool RandRScreen::applyProposed()
if (proposedRefreshRate() < 0)
status = XRRSetScreenConfig(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), CurrentTime);
else {
if( refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) <= 0 ) {
int hz = refreshRateIndexToXRR(m_screen, proposedSize(), proposedRefreshRate());
if( hz <= 0 ) {
m_proposedRefreshRate = 0;
}
status = XRRSetScreenConfigAndRate(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), refreshRateIndexToHz(proposedSize(), proposedRefreshRate()), CurrentTime);
status = XRRSetScreenConfigAndRate(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), hz, CurrentTime);
}
}
else {
@ -487,26 +497,22 @@ KDE_EXPORT int RandRScreen::currentMMHeight() const
return m_pixelSizes[m_currentSize].height();
}
KDE_EXPORT TQStringList RandRScreen::refreshRates(int size) const
KDE_EXPORT TQValueVector<int> RandRScreen::refreshRatesValues(int size) const
{
int nrates;
TQStringList ret;
ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay());
int numSizes = screeninfo->res->nmode;
TQValueVector<int> ret;
if (d->config) {
short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates);
for (int i = 0; i < nrates; i++)
ret << refreshRateDirectDescription(rates[i]);
if (size > numSizes-1) { // out of range
return ret;
}
else {
// Great, now we have to go after the information manually. Ughh.
ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay());
int numSizes = screeninfo->res->nmode;
for (int i = 0; i < numSizes; i++) {
int refresh_rate = ((screeninfo->res->modes[i].dotClock*1.0)/((screeninfo->res->modes[i].hTotal)*(screeninfo->res->modes[i].vTotal)*1.0));
TQString newRate = refreshRateDirectDescription(refresh_rate);
if (!ret.contains(newRate)) {
ret.append(newRate);
char * currentModeName = screeninfo->res->modes[size].name;
for (int i = 0; i < numSizes; i++) {
if (strcmp(currentModeName, screeninfo->res->modes[i].name) == 0) {
int rate = refreshRateForModeInfo(&screeninfo->res->modes[i]);
if (rate!=0) {
ret.append(rate);
}
}
}
@ -514,6 +520,17 @@ KDE_EXPORT TQStringList RandRScreen::refreshRates(int size) const
return ret;
}
KDE_EXPORT TQStringList RandRScreen::refreshRates(int size) const
{
TQStringList ret;
for (int rate: refreshRatesValues(size)) {
ret.append(refreshRateDirectDescription(rate));
}
return ret;
}
KDE_EXPORT TQString RandRScreen::refreshRateDirectDescription(int rate) const
{
return i18n("Refresh rate in Hertz (Hz)", "%1 Hz").arg(rate);
@ -521,7 +538,7 @@ KDE_EXPORT TQString RandRScreen::refreshRateDirectDescription(int rate) const
KDE_EXPORT TQString RandRScreen::refreshRateIndirectDescription(int size, int index) const
{
return i18n("Refresh rate in Hertz (Hz)", "%1 Hz").arg(refreshRateIndexToHz(size, index));
return refreshRateDirectDescription(refreshRateIndexToHz(size, index));
}
KDE_EXPORT TQString RandRScreen::refreshRateDescription(int size, int index) const
@ -556,30 +573,28 @@ KDE_EXPORT int RandRScreen::proposedRefreshRate() const
KDE_EXPORT int RandRScreen::refreshRateHzToIndex(int size, int hz) const
{
int nrates;
short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates);
for (int i = 0; i < nrates; i++)
if (hz == rates[i])
TQValueVector<int> rates = refreshRatesValues(size);
for (size_t i=0; i<rates.size(); i++) {
if ( (int) (rates[i] + 0.5) == hz) {
return i;
}
}
if (nrates != 0)
if (rates.size() != 0)
// Wrong input Hz!
Q_ASSERT(false);
return -1;
}
KDE_EXPORT int RandRScreen::refreshRateIndexToHz(int size, int index) const
{
int nrates;
short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates);
KDE_EXPORT int RandRScreen::refreshRateIndexToHz(int size, int index) const {
TQValueVector<int> rates = refreshRatesValues(size);
if (nrates == 0 || index < 0)
if (rates.size() == 0 || index < 0)
return 0;
// Wrong input Hz!
if(index >= nrates)
// Wrong input index!
if(index >= (ssize_t)rates.size())
return 0;
return rates[index];
@ -880,4 +895,72 @@ KDE_EXPORT int RandRScreen::pixelCount( int index ) const
return sz.width() * sz.height();
}
// Calculates refresh rate for modeinfo
// snatch from xrandr-1.5
static int refreshRateForModeInfo(const XRRModeInfo *mode_info)
{
double rate;
double vTotal = mode_info->vTotal;
if (mode_info->modeFlags & RR_DoubleScan) {
/* doublescan doubles the number of lines */
vTotal *= 2;
}
if (mode_info->modeFlags & RR_Interlace) {
/* interlace splits the frame into two fields */
/* the field rate is what is typically reported by monitors */
vTotal /= 2;
}
if (mode_info->hTotal && vTotal)
rate = ((double) mode_info->dotClock /
((double) mode_info->hTotal * (double) vTotal));
else
rate = 0;
return (int) (rate+0.5);
}
// On some video drivers (e.g. proprietary nvidia) XRandR returns incorrect
// readings for refresh rate[1], when read via XRRRates(), so for display
// purposes we will use data from XRRGetScreenResources() and some fancy
// calculations (see internal_read_screen_info() and refreshRateForModeInfo()).
// Unfortunately, other XRandR functions (like XRRConfigCurrentRate() and
// XRRSetScreenConfigAndRate()) expect the data reported by XRRRates(). So,
// in order to be able to correctly set a refresh rate we have to request
// it via XRRRates() anyway.
//
// [1]: see https://mirror.git.trinitydesktop.org/gitea/TDE/tde/issues/75
static int refreshRateXRRToIndex(int screen, int size, int hz)
{
int nrates;
short* rates = XRRRates(tqt_xdisplay(), screen, (SizeID)size, &nrates);
for (int i = 0; i < nrates; i++)
if (hz == rates[i])
return i;
if (nrates != 0)
// Wrong input Hz!
Q_ASSERT(false);
return -1;
}
static int refreshRateIndexToXRR(int screen, int size, int index)
{
int nrates;
short* rates = XRRRates(tqt_xdisplay(), screen, (SizeID)size, &nrates);
if (nrates == 0 || index < 0)
return 0;
// Wrong input Hz!
if(index >= nrates)
return 0;
return rates[index];
}
#include "randr.moc"

@ -21,6 +21,7 @@
#include <tqobject.h>
#include <tqstringlist.h>
#include <tqvaluevector.h>
#include <tqptrlist.h>
#include <tdecmodule.h>
@ -152,6 +153,7 @@ public:
/**
* Refresh rate functions.
*/
TQValueVector<int> refreshRatesValues(int size) const;
TQStringList refreshRates(int size) const;
TQString refreshRateDirectDescription(int rate) const;

Loading…
Cancel
Save