From af3a602ab34a4d1c0d146f6fe4696b1acdbd9f0d Mon Sep 17 00:00:00 2001 From: tpearson Date: Tue, 23 Aug 2011 22:48:56 +0000 Subject: Large improvements to libkrandr git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1249188 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- krandr/libkrandr.cc | 188 +++++++++++++++++++++++++++++++++++++++++++--------- krandr/libkrandr.h | 9 ++- krandr/randr.cpp | 109 ++++++++++++++++++++++++------ 3 files changed, 252 insertions(+), 54 deletions(-) (limited to 'krandr') diff --git a/krandr/libkrandr.cc b/krandr/libkrandr.cc index 0abe3f6ee..63ac06e62 100644 --- a/krandr/libkrandr.cc +++ b/krandr/libkrandr.cc @@ -28,8 +28,14 @@ #include #include +#include + #include "libkrandr.h" +// FIXME +// For now, just use the standalone xrandr program to apply the display settings +#define USE_XRANDR_PROGRAM + // This routine is courtsey of an answer on "Stack Overflow" // It takes an LSB-first int and makes it an MSB-first int (or vice versa) unsigned int reverse_bits(register unsigned int x) @@ -267,7 +273,7 @@ TQString KRandrSimpleAPI::applyIccConfiguration(TQString profileName, TQString k TQString KRandrSimpleAPI::getEDIDMonitorName(int card, TQString displayname) { TQString edid; - TQByteArray binaryedid = getEDID(card, displayname); + TQByteArray binaryedid = getEDID(card, displayname); if (binaryedid.isNull()) return TQString(); @@ -375,16 +381,25 @@ TQString KRandrSimpleAPI::applySystemWideIccConfiguration(TQString kde_confdir) return ""; } -void KRandrSimpleAPI::saveSystemwideDisplayConfiguration(TQString profilename, TQString kde_confdir, TQPtrList screenInfoArray) { +void KRandrSimpleAPI::saveSystemwideDisplayConfiguration(bool enable, TQString profilename, TQString kde_confdir, TQPtrList screenInfoArray) { int i; TQString filename; + + filename = "displayglobals"; + filename.prepend(kde_confdir.append("/")); + KSimpleConfig* display_config = new KSimpleConfig( filename ); + display_config->setGroup("General"); + display_config->writeEntry("ApplySettingsOnStart", enable); + display_config->sync(); + delete display_config; + filename = profilename; if (filename == "") filename = "default"; filename.prepend(kde_confdir.append("/displayconfig/")); - KSimpleConfig* display_config = new KSimpleConfig( filename ); + display_config = new KSimpleConfig( filename ); i=0; SingleScreenData *screendata; @@ -418,6 +433,22 @@ void KRandrSimpleAPI::saveSystemwideDisplayConfiguration(TQString profilename, T delete display_config; } +void KRandrSimpleAPI::applySystemwideDisplayConfiguration(TQString profilename, TQString kde_confdir) { + TQString filename = "displayglobals"; + filename.prepend(kde_confdir.append("/")); + KSimpleConfig* display_config = new KSimpleConfig( filename ); + display_config->setGroup("General"); + bool enabled = display_config->readBoolEntry("ApplySettingsOnStart", false); + delete display_config; + + if (enabled) { + TQPtrList screenInfoArray; + screenInfoArray = loadSystemwideDisplayConfiguration(profilename, kde_confdir); + applySystemwideDisplayConfiguration(screenInfoArray, FALSE); + destroyScreenInformationObject(screenInfoArray); + } +} + TQPtrList KRandrSimpleAPI::loadSystemwideDisplayConfiguration(TQString profilename, TQString kde_confdir) { int i; @@ -507,6 +538,55 @@ bool KRandrSimpleAPI::applySystemwideDisplayConfiguration(TQPtrListn_output; i++) { + screendata = screenInfoArray.at(i); + output_info = randr_screen_info->outputs[i]->info; + command.append(" --output ").append(output_info->name); + if (screendata->is_primary || screendata->is_extended) { + command.append(TQString(" --mode %1x%2").arg(screendata->current_x_pixel_count).arg(screendata->current_y_pixel_count)); + command.append(TQString(" --pos %1x%2").arg(screendata->absolute_x_position).arg(screendata->absolute_y_position)); + command.append(TQString(" --refresh %1").arg((*screendata->refresh_rates.at(screendata->current_refresh_rate_index)).replace("Hz", ""))); + if (screendata->current_rotation_index == 0) command.append(" --rotate ").append("normal"); + if (screendata->current_rotation_index == 1) command.append(" --rotate ").append("left"); + if (screendata->current_rotation_index == 2) command.append(" --rotate ").append("inverted"); + if (screendata->current_rotation_index == 3) command.append(" --rotate ").append("right"); + if ((screendata->has_x_flip == 0) && (screendata->has_y_flip == 0)) command.append(" --reflect ").append("normal"); + if ((screendata->has_x_flip == 1) && (screendata->has_y_flip == 0)) command.append(" --reflect ").append("x"); + if ((screendata->has_x_flip == 0) && (screendata->has_y_flip == 1)) command.append(" --reflect ").append("y"); + if ((screendata->has_x_flip == 1) && (screendata->has_y_flip == 1)) command.append(" --reflect ").append("xy"); + if (screendata->is_primary) { + command.append(" --primary"); + } + } + else { + command.append(" --off"); + } + } + + system(command.ascii()); + + // HACK + // This is needed because Qt does not properly generate screen + // resize events when switching screens, so KDE gets stuck in the old resolution + // This only seems to happen with more than one screen, so check for that condition... + // FIXME: This also only occurs when the primary display has been changed + // FIXME: Check for that condition as well! + if (kapp->desktop()->numScreens() > 1) { + for (i = 0; i < randr_screen_info->n_output; i++) { + screendata = screenInfoArray.at(i); + if (screendata->is_primary == true) { + kapp->desktop()->emitResizedSignal(i); + } + } + } +#else randr_display = XOpenDisplay(NULL); randr_screen_info = read_screen_info(randr_display); // Turn off all displays @@ -567,10 +647,12 @@ bool KRandrSimpleAPI::applySystemwideDisplayConfiguration(TQPtrListis_primary || screendata->is_extended) { // Set rotation, refresh rate, and size - screen(i)->proposeSize(screendata->current_resolution_index); - screen(i)->proposeRefreshRate(screendata->current_refresh_rate_index); - screen(i)->proposeRotation(getHardwareRotationFlags(screendata)); - screen(i)->applyProposed(); + RandRScreen *cur_screen = new RandRScreen(i); + cur_screen->proposeSize(screendata->current_resolution_index); + cur_screen->proposeRefreshRate(screendata->current_refresh_rate_index); + cur_screen->proposeRotation(getHardwareRotationFlags(screendata)); + cur_screen->applyProposed(); + delete cur_screen; // Force data reload randr_screen_info = read_screen_info(randr_display); @@ -578,11 +660,14 @@ bool KRandrSimpleAPI::applySystemwideDisplayConfiguration(TQPtrListcur_crtc = randr_screen_info->outputs[i]->cur_crtc; - randr_screen_info->cur_crtc->cur_x = screendata->absolute_x_position; - randr_screen_info->cur_crtc->cur_y = screendata->absolute_y_position; - j=main_low_apply(randr_screen_info); + if (randr_screen_info->cur_crtc) { + randr_screen_info->cur_crtc->cur_x = screendata->absolute_x_position; + randr_screen_info->cur_crtc->cur_y = screendata->absolute_y_position; + j=main_low_apply(randr_screen_info); + } } } +#endif } if (test == TRUE) { @@ -629,7 +714,7 @@ void KRandrSimpleAPI::ensureMonitorDataConsistency(TQPtrList s for (i=0;iis_extended) { + if (screendata->screen_connected && screendata->is_extended) { screendata->is_primary = true; screendata->is_extended = true; has_primary_monitor = true; @@ -653,8 +738,6 @@ void KRandrSimpleAPI::ensureMonitorDataConsistency(TQPtrList s for (i=0;iis_primary) { - screendata->absolute_x_position = 0; - screendata->absolute_y_position = 0; screendata->is_extended = true; } } @@ -669,6 +752,25 @@ void KRandrSimpleAPI::ensureMonitorDataConsistency(TQPtrList s screendata->current_y_pixel_count = y_res_string.toInt(); screendata->current_orientation_mask = getHardwareRotationFlags(screendata); } + + // Each screen's absolute position is given relative to the primary monitor + // Fix up the absolute positions + int primary_offset_x = 0; + int primary_offset_y = 0; + for (i=0;iis_primary) { + primary_offset_x = screendata->absolute_x_position; + primary_offset_y = screendata->absolute_y_position; + primary_offset_x = primary_offset_x * (-1); + primary_offset_y = primary_offset_y * (-1); + } + } + for (i=0;iabsolute_x_position = screendata->absolute_x_position + primary_offset_x; + screendata->absolute_y_position = screendata->absolute_y_position + primary_offset_y; + } } TQPtrList KRandrSimpleAPI::readCurrentDisplayConfiguration() { @@ -685,13 +787,14 @@ TQPtrList KRandrSimpleAPI::readCurrentDisplayConfiguration() { // Clear existing info destroyScreenInformationObject(screenInfoArray); - + int numberOfScreens = 0; if (isValid() == true) { randr_display = XOpenDisplay(NULL); randr_screen_info = read_screen_info(randr_display); for (i = 0; i < randr_screen_info->n_output; i++) { output_info = randr_screen_info->outputs[i]->info; + CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc; // Create new data object screendata = new SingleScreenData; @@ -706,26 +809,44 @@ TQPtrList KRandrSimpleAPI::readCurrentDisplayConfiguration() { } // Get resolutions - RandRScreen *cur_screen = screen(i); + bool screen_active; + RandRScreen *cur_screen = 0; + if (RR_Disconnected == randr_screen_info->outputs[i]->info->connection) { + // Output DISCONNECTED + screen_active = false; + } + else { + if (randr_screen_info->outputs[i]->cur_crtc) { + // Output CONNECTED and ON + screen_active = true; + cur_screen = new RandRScreen(i); + } + else { + // Output CONNECTED and OFF + screen_active = false; + cur_screen = new RandRScreen(i); + } + } + if (cur_screen) { screendata->screen_connected = true; for (int j = 0; j < cur_screen->numSizes(); j++) { screendata->resolutions.append(i18n("%1 x %2").tqarg(cur_screen->pixelSize(j).width()).tqarg(cur_screen->pixelSize(j).height())); } screendata->current_resolution_index = cur_screen->proposedSize(); - + // Get refresh rates TQStringList rr = cur_screen->refreshRates(screendata->current_resolution_index); for (TQStringList::Iterator it = rr.begin(); it != rr.end(); ++it) { screendata->refresh_rates.append(*it); } screendata->current_refresh_rate_index = cur_screen->proposedRefreshRate(); - + // Get color depths // [FIXME] screendata->color_depths.append(i18n("Default")); screendata->current_color_depth_index = 0; - + // Get orientation flags // RandRScreen::Rotate0 // RandRScreen::Rotate90 @@ -733,7 +854,7 @@ TQPtrList KRandrSimpleAPI::readCurrentDisplayConfiguration() { // RandRScreen::Rotate270 // RandRScreen::ReflectX // RandRScreen::ReflectY - + screendata->rotations.append(i18n("Normal")); screendata->rotations.append(i18n("Rotate 90 degrees")); screendata->rotations.append(i18n("Rotate 180 degrees")); @@ -760,20 +881,25 @@ TQPtrList KRandrSimpleAPI::readCurrentDisplayConfiguration() { screendata->has_x_flip = (screendata->current_orientation_mask & RandRScreen::ReflectX); screendata->has_y_flip = (screendata->current_orientation_mask & RandRScreen::ReflectY); screendata->supports_transformations = (cur_screen->rotations() != RandRScreen::Rotate0); - + // Determine if this display is primary and/or extended // [FIXME] screendata->is_primary = false; - screendata->is_extended = false; - + screendata->is_extended = screen_active; + // Get this screen's absolute position - // [FIXME] screendata->absolute_x_position = 0; screendata->absolute_y_position = 0; - + if (current_crtc) { + screendata->absolute_x_position = current_crtc->info->x; + screendata->absolute_y_position = current_crtc->info->y; + } + // Get this screen's current resolution screendata->current_x_pixel_count = cur_screen->pixelSize(screendata->current_resolution_index).width(); screendata->current_y_pixel_count = cur_screen->pixelSize(screendata->current_resolution_index).height(); + + delete cur_screen; } else { // Fill in generic data for this disconnected output @@ -784,17 +910,17 @@ TQPtrList KRandrSimpleAPI::readCurrentDisplayConfiguration() { screendata->refresh_rates = i18n("Default"); screendata->color_depths = i18n("Default"); screendata->rotations = i18n("N/A"); - + screendata->current_resolution_index = 0; screendata->current_refresh_rate_index = 0; screendata->current_color_depth_index = 0; - + screendata->current_rotation_index = 0; screendata->current_orientation_mask = 0; screendata->has_x_flip = false; screendata->has_y_flip = false; screendata->supports_transformations = false; - + screendata->is_primary = false; screendata->is_extended = false; screendata->absolute_x_position = 0; @@ -815,22 +941,22 @@ TQPtrList KRandrSimpleAPI::readCurrentDisplayConfiguration() { screendata->screenFriendlyName = i18n("Default output on generic video card"); screendata->generic_screen_detected = true; screendata->screen_connected = true; - + screendata->resolutions = i18n("Default"); screendata->refresh_rates = i18n("Default"); screendata->color_depths = i18n("Default"); screendata->rotations = i18n("N/A"); - + screendata->current_resolution_index = 0; screendata->current_refresh_rate_index = 0; screendata->current_color_depth_index = 0; - + screendata->current_rotation_index = 0; screendata->current_orientation_mask = 0; screendata->has_x_flip = false; screendata->has_y_flip = false; screendata->supports_transformations = false; - + screendata->is_primary = true; screendata->is_extended = true; screendata->absolute_x_position = 0; diff --git a/krandr/libkrandr.h b/krandr/libkrandr.h index d4e9fbea8..352d821c0 100644 --- a/krandr/libkrandr.h +++ b/krandr/libkrandr.h @@ -165,8 +165,9 @@ class KRANDR_EXPORT KRandrSimpleAPI : public RandRDisplay /** * Saves the systemwide display configuration screenInfoArray to the specified profile * If profilename is empty, the default profile is utilized + * If enable is set to true, the default profile will be applied at system startup */ - void saveSystemwideDisplayConfiguration(TQString profilename, TQString kde_confdir, TQPtrList screenInfoArray); + void saveSystemwideDisplayConfiguration(bool enable, TQString profilename, TQString kde_confdir, TQPtrList screenInfoArray); /** * Reads the systemwide display configuration screenInfoArray from the specified profile @@ -175,6 +176,12 @@ class KRANDR_EXPORT KRandrSimpleAPI : public RandRDisplay */ TQPtrList loadSystemwideDisplayConfiguration(TQString profilename, TQString kde_confdir); + /** + * Applies the systemwide display configuration screenInfoArray from the specified profile + * If profilename is empty, the default profile is utilized + */ + void applySystemwideDisplayConfiguration(TQString profilename, TQString kde_confdir); + /** * Applies the systemwide display configuration screenInfoArray to the hardware * If test is true, the new configuration will be loaded for a short period of time, then reverted automatically diff --git a/krandr/randr.cpp b/krandr/randr.cpp index 378a1fdb7..2e3a30eee 100644 --- a/krandr/randr.cpp +++ b/krandr/randr.cpp @@ -17,6 +17,7 @@ */ #include "randr.h" +#include "lowlevel_randr.h" #include @@ -75,21 +76,53 @@ void RandRScreen::loadSettings() Q_ASSERT(d->config); Rotation rotation; - m_currentSize = m_proposedSize = XRRConfigCurrentConfiguration(d->config, &rotation); - m_currentRotation = m_proposedRotation = rotation; + if (d->config) { + m_currentSize = m_proposedSize = XRRConfigCurrentConfiguration(d->config, &rotation); + m_currentRotation = m_proposedRotation = rotation; + } + else { + m_currentSize = m_proposedSize = 0; + m_currentRotation = m_proposedRotation = 0; + } m_pixelSizes.clear(); m_mmSizes.clear(); - int numSizes; - XRRScreenSize* sizes = XRRSizes(qt_xdisplay(), m_screen, &numSizes); - for (int i = 0; i < numSizes; i++) { - m_pixelSizes.append(TQSize(sizes[i].width, sizes[i].height)); - m_mmSizes.append(TQSize(sizes[i].mwidth, sizes[i].mheight)); - } - m_rotations = XRRRotations(qt_xdisplay(), m_screen, &rotation); + if (d->config) { + int numSizes; + XRRScreenSize* sizes = XRRSizes(qt_xdisplay(), m_screen, &numSizes); + for (int i = 0; i < numSizes; i++) { + m_pixelSizes.append(TQSize(sizes[i].width, sizes[i].height)); + m_mmSizes.append(TQSize(sizes[i].mwidth, sizes[i].mheight)); + } + + m_rotations = XRRRotations(qt_xdisplay(), m_screen, &rotation); + } + else { + // Great, now we have to go after the information manually. Ughh. + ScreenInfo *screeninfo = internal_read_screen_info(qt_xdisplay()); + XRROutputInfo *output_info = screeninfo->outputs[m_screen]->info; + CrtcInfo *current_crtc = screeninfo->outputs[m_screen]->cur_crtc; + int numSizes = screeninfo->res->nmode; + for (int i = 0; i < numSizes; i++) { + TQSize newSize = TQSize(screeninfo->res->modes[i].width, screeninfo->res->modes[i].height); + if (!m_pixelSizes.contains(newSize)) { + m_pixelSizes.append(newSize); + m_mmSizes.append(TQSize(output_info->mm_width, output_info->mm_height)); + } + } + if (current_crtc) { + m_rotations = current_crtc->rotations; + m_currentRotation = m_proposedRotation = current_crtc->cur_rotation; + } + } - m_currentRefreshRate = m_proposedRefreshRate = refreshRateHzToIndex(m_currentSize, XRRConfigCurrentRate(d->config)); + if (d->config) { + m_currentRefreshRate = m_proposedRefreshRate = refreshRateHzToIndex(m_currentSize, XRRConfigCurrentRate(d->config)); + } + else { + m_currentRefreshRate = m_proposedRefreshRate = 0; + } } void RandRScreen::setOriginal() @@ -105,13 +138,30 @@ bool RandRScreen::applyProposed() Status status; - if (proposedRefreshRate() < 0) - status = XRRSetScreenConfig(qt_xdisplay(), d->config, DefaultRootWindow(qt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), CurrentTime); - else { - if( refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) <= 0 ) { - m_proposedRefreshRate = 0; + if (!d->config) { + d->config = XRRGetScreenInfo(qt_xdisplay(), RootWindow(qt_xdisplay(), m_screen)); + Q_ASSERT(d->config); + } + + if (d->config) { + if (proposedRefreshRate() < 0) + status = XRRSetScreenConfig(qt_xdisplay(), d->config, DefaultRootWindow(qt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), CurrentTime); + else { + if( refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) <= 0 ) { + m_proposedRefreshRate = 0; + } + status = XRRSetScreenConfigAndRate(qt_xdisplay(), d->config, DefaultRootWindow(qt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), refreshRateIndexToHz(proposedSize(), proposedRefreshRate()), CurrentTime); } - status = XRRSetScreenConfigAndRate(qt_xdisplay(), d->config, DefaultRootWindow(qt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), refreshRateIndexToHz(proposedSize(), proposedRefreshRate()), CurrentTime); + } + else { + // Great, now we have to set the information manually. Ughh. + // FIXME--this does not work! + ScreenInfo *screeninfo = internal_read_screen_info(qt_xdisplay()); + screeninfo->cur_width = (*m_pixelSizes.at(proposedSize())).width(); + screeninfo->cur_height = (*m_pixelSizes.at(proposedSize())).height(); + internal_main_low_apply(screeninfo); + + status = RRSetConfigSuccess; } //kdDebug() << "New size: " << WidthOfScreen(ScreenOfDisplay(TQPaintDevice::x11AppDisplay(), screen)) << ", " << HeightOfScreen(ScreenOfDisplay(TQPaintDevice::x11AppDisplay(), screen)) << endl; @@ -152,7 +202,7 @@ bool RandRScreen::confirm() // FIXME remember to put the dialog on the right screen - KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown, + KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown, KApplication::kApplication()->mainWidget(), "mainKTimerDialog", true, @@ -386,11 +436,26 @@ int RandRScreen::currentMMHeight() const TQStringList RandRScreen::refreshRates(int size) const { int nrates; - short* rates = XRRRates(qt_xdisplay(), m_screen, (SizeID)size, &nrates); - TQStringList ret; - for (int i = 0; i < nrates; i++) - ret << refreshRateDirectDescription(rates[i]); + + if (d->config) { + short* rates = XRRRates(qt_xdisplay(), m_screen, (SizeID)size, &nrates); + + for (int i = 0; i < nrates; i++) + ret << refreshRateDirectDescription(rates[i]); + } + else { + // Great, now we have to go after the information manually. Ughh. + ScreenInfo *screeninfo = internal_read_screen_info(qt_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); + } + } + } return ret; } @@ -720,7 +785,7 @@ bool RandRScreen::showTestConfigurationDialog() // FIXME remember to put the dialog on the right screen - KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown, + KTimerDialog acceptDialog ( 15000, KTimerDialog::CountDown, KApplication::kApplication()->mainWidget(), "mainKTimerDialog", true, -- cgit v1.2.1