Bug#1031953: libkf5screen8: Second monitor issues with NVIDIA
Package: libkf5screen8
Version: 4:5.27.0-1
Severity: normal
Tags: patch upstream
This is to note that the upstream bug titled "On X11 with proprietary NVIDIA
GPU drivers, external monitor disabled after reboot or wake-from-sleep" applies
to Debian package 4.27.0-1.
See https://bugs.kde.org/show_bug.cgi?id=460341
Today a fix has finally been found. There are at least a few reports that it
solves the issue -- I've tested it myself and it does solve the symptom I've
been having since October 2022.
The patch is:
https://invent.kde.org/plasma/libkscreen/-/commit/1d237c29655c7e3fb15fb9b71e5f167bd207593f
I'd love to see it applied before the release. Happy to do an upload myself if
that's preferred.
-Steve
-- System Information:
Debian Release: bookworm/sid
APT prefers unstable
APT policy: (700, 'unstable'), (500, 'testing')
Architecture: amd64 (x86_64)
Foreign Architectures: i386
Kernel: Linux 6.1.0-5-amd64 (SMP w/16 CPU threads; PREEMPT)
Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=en_CA.UTF-8, LC_CTYPE=en_CA.UTF-8 (charmap=UTF-8), LANGUAGE=en_CA:en
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
Versions of packages libkf5screen8 depends on:
ii libc6 2.36-8
ii libkf5screen-data 4:5.27.0-1.1
ii libqt5core5a 5.15.8+dfsg-2
ii libqt5dbus5 5.15.8+dfsg-2
ii libqt5gui5 5.15.8+dfsg-2
ii libqt5x11extras5 5.15.8-2
ii libstdc++6 12.2.0-14
Versions of packages libkf5screen8 recommends:
ii hwdata 0.367-1
libkf5screen8 suggests no packages.
-- no debconf information
diff --git a/backends/xrandr/xrandrconfig.cpp b/backends/xrandr/xrandrconfig.cpp
index 4ab5b3c4e1f49752c80eb6fca4f39691954024f9..50910d44f766b755208c28bfdccee4821e9ed7e3 100644
--- a/backends/xrandr/xrandrconfig.cpp
+++ b/backends/xrandr/xrandrconfig.cpp
@@ -128,11 +128,16 @@ void XRandRConfig::applyKScreenConfig(const KScreen::ConfigPtr &config)
const QSize newScreenSize = screenSize(config);
const QSize currentScreenSize = m_screen->currentSize();
- // Previously we initially set such screen size, that it can take the current
- // as well as the new configuration, then we apply the output changes,
- // and finally then (if necessary) we reduce the screen size to
- // fix the new configuration precisely.Now we initially disable the output,
- // then set the target screen size, and finally we apply the output changes.
+ // When the current screen configuration is bigger than the new size (like
+ // when rotating an output), the XSetScreenSize can fail or apply the smaller
+ // size only partially, because we apply the size (we have to) before the
+ // output changes. To prevent all kinds of weird screen sizes from happening,
+ // we initially set such screen size, that it can take the current as well
+ // as the new configuration, then we apply the output changes, and finally then
+ // (if necessary) we reduce the screen size to fix the new configuration precisely.
+ const QSize intermediateScreenSize =
+ QSize(qMax(newScreenSize.width(), currentScreenSize.width()), qMax(newScreenSize.height(), currentScreenSize.height()));
+
int neededCrtcs = 0;
// pairs of before/after
@@ -246,6 +251,7 @@ void XRandRConfig::applyKScreenConfig(const KScreen::ConfigPtr &config)
qCDebug(KSCREEN_XRANDR) << "\tChange Screen Size:" << (newScreenSize != currentScreenSize);
if (newScreenSize != currentScreenSize) {
qCDebug(KSCREEN_XRANDR) << "\t\tOld:" << currentScreenSize << "\n"
+ << "\t\tIntermediate:" << intermediateScreenSize << "\n"
<< "\t\tNew:" << newScreenSize;
}
@@ -280,14 +286,24 @@ void XRandRConfig::applyKScreenConfig(const KScreen::ConfigPtr &config)
disableOutput(output);
}
- if (currentScreenSize != newScreenSize) {
- for (const KScreen::OutputPtr &output : toChange) {
- disableOutput(output);
- }
+ if (intermediateScreenSize != currentScreenSize) {
+ setScreenSize(intermediateScreenSize);
}
bool forceScreenSizeUpdate = false;
+ for (const KScreen::OutputPtr &output : toChange) {
+ if (!changeOutput(output)) {
+ /* If we disabled the output before changing it and XRandR failed
+ * to re-enable it, then update screen size too */
+ if (toDisable.contains(output->id())) {
+ output->setEnabled(false);
+ qCDebug(KSCREEN_XRANDR) << "Output failed to change: " << output->name();
+ forceScreenSizeUpdate = true;
+ }
+ }
+ }
+
for (const KScreen::OutputPtr &output : toEnable) {
if (!enableOutput(output)) {
qCDebug(KSCREEN_XRANDR) << "Output failed to be Enabled: " << output->name();
@@ -302,7 +318,7 @@ void XRandRConfig::applyKScreenConfig(const KScreen::ConfigPtr &config)
setOutputPriority(outputId, priority);
}
- if (forceScreenSizeUpdate || currentScreenSize != newScreenSize) {
+ if (forceScreenSizeUpdate || intermediateScreenSize != newScreenSize) {
QSize newSize = newScreenSize;
if (forceScreenSizeUpdate) {
newSize = screenSize(config);
@@ -310,17 +326,6 @@ void XRandRConfig::applyKScreenConfig(const KScreen::ConfigPtr &config)
}
setScreenSize(newSize);
}
-
- for (const KScreen::OutputPtr &output : toChange) {
- if (!changeOutput(output)) {
- /* If we disabled the output before changing it and XRandR failed
- * to re-enable it, then update screen size too */
- if (toDisable.contains(output->id())) {
- output->setEnabled(false);
- qCDebug(KSCREEN_XRANDR) << "Output failed to change: " << output->name();
- }
- }
- }
}
void XRandRConfig::printConfig(const ConfigPtr &config) const
diff --git a/backends/xrandr/xrandrconfig.cpp b/backends/xrandr/xrandrconfig.cpp
index 4ab5b3c4e1f49752c80eb6fca4f39691954024f9..50910d44f766b755208c28bfdccee4821e9ed7e3 100644
--- a/backends/xrandr/xrandrconfig.cpp
+++ b/backends/xrandr/xrandrconfig.cpp
@@ -128,11 +128,16 @@ void XRandRConfig::applyKScreenConfig(const KScreen::ConfigPtr &config)
const QSize newScreenSize = screenSize(config);
const QSize currentScreenSize = m_screen->currentSize();
- // Previously we initially set such screen size, that it can take the current
- // as well as the new configuration, then we apply the output changes,
- // and finally then (if necessary) we reduce the screen size to
- // fix the new configuration precisely.Now we initially disable the output,
- // then set the target screen size, and finally we apply the output changes.
+ // When the current screen configuration is bigger than the new size (like
+ // when rotating an output), the XSetScreenSize can fail or apply the smaller
+ // size only partially, because we apply the size (we have to) before the
+ // output changes. To prevent all kinds of weird screen sizes from happening,
+ // we initially set such screen size, that it can take the current as well
+ // as the new configuration, then we apply the output changes, and finally then
+ // (if necessary) we reduce the screen size to fix the new configuration precisely.
+ const QSize intermediateScreenSize =
+ QSize(qMax(newScreenSize.width(), currentScreenSize.width()), qMax(newScreenSize.height(), currentScreenSize.height()));
+
int neededCrtcs = 0;
// pairs of before/after
@@ -246,6 +251,7 @@ void XRandRConfig::applyKScreenConfig(const KScreen::ConfigPtr &config)
qCDebug(KSCREEN_XRANDR) << "\tChange Screen Size:" << (newScreenSize != currentScreenSize);
if (newScreenSize != currentScreenSize) {
qCDebug(KSCREEN_XRANDR) << "\t\tOld:" << currentScreenSize << "\n"
+ << "\t\tIntermediate:" << intermediateScreenSize << "\n"
<< "\t\tNew:" << newScreenSize;
}
@@ -280,14 +286,24 @@ void XRandRConfig::applyKScreenConfig(const KScreen::ConfigPtr &config)
disableOutput(output);
}
- if (currentScreenSize != newScreenSize) {
- for (const KScreen::OutputPtr &output : toChange) {
- disableOutput(output);
- }
+ if (intermediateScreenSize != currentScreenSize) {
+ setScreenSize(intermediateScreenSize);
}
bool forceScreenSizeUpdate = false;
+ for (const KScreen::OutputPtr &output : toChange) {
+ if (!changeOutput(output)) {
+ /* If we disabled the output before changing it and XRandR failed
+ * to re-enable it, then update screen size too */
+ if (toDisable.contains(output->id())) {
+ output->setEnabled(false);
+ qCDebug(KSCREEN_XRANDR) << "Output failed to change: " << output->name();
+ forceScreenSizeUpdate = true;
+ }
+ }
+ }
+
for (const KScreen::OutputPtr &output : toEnable) {
if (!enableOutput(output)) {
qCDebug(KSCREEN_XRANDR) << "Output failed to be Enabled: " << output->name();
@@ -302,7 +318,7 @@ void XRandRConfig::applyKScreenConfig(const KScreen::ConfigPtr &config)
setOutputPriority(outputId, priority);
}
- if (forceScreenSizeUpdate || currentScreenSize != newScreenSize) {
+ if (forceScreenSizeUpdate || intermediateScreenSize != newScreenSize) {
QSize newSize = newScreenSize;
if (forceScreenSizeUpdate) {
newSize = screenSize(config);
@@ -310,17 +326,6 @@ void XRandRConfig::applyKScreenConfig(const KScreen::ConfigPtr &config)
}
setScreenSize(newSize);
}
-
- for (const KScreen::OutputPtr &output : toChange) {
- if (!changeOutput(output)) {
- /* If we disabled the output before changing it and XRandR failed
- * to re-enable it, then update screen size too */
- if (toDisable.contains(output->id())) {
- output->setEnabled(false);
- qCDebug(KSCREEN_XRANDR) << "Output failed to change: " << output->name();
- }
- }
- }
}
void XRandRConfig::printConfig(const ConfigPtr &config) const
Reply to: