Bug 349400

Summary: Plasmashell does not update panel struct after monitor disconnect
Product: [Plasma] plasmashell Reporter: Andrew Chen <andrew>
Component: PanelAssignee: Plasma Bugs List <plasma-bugs>
Status: RESOLVED FIXED    
Severity: normal CC: bugs, kde, kde, marcus
Priority: NOR    
Version: 5.4.0   
Target Milestone: 1.0   
Platform: Arch Linux   
OS: Linux   
See Also: https://bugs.kde.org/show_bug.cgi?id=349123
Latest Commit: Version Fixed In:
Sentry Crash Report:
Attachments: possible fix

Description Andrew Chen 2015-06-19 22:47:01 UTC
Causes https://bugs.kde.org/show_bug.cgi?id=349123

Reproducible: Always

Steps to Reproduce:
(Assuming the panel is on the primary monitor and is at the bottom of the screen)
1. Connect a secondary monitor of a larger height that the primary one.
2. Resize the panel to force a recalculation of the strut.
3. Record the panel strut (xprop | grep _NET_WM_STRUT)
4. Disconnect the secondary monitor.
5. Record the panel strut again

Actual Results:  
The panel strut is not updated, causing maximized windows to be restrained to a smaller height.

Expected Results:  
The panel strut is updated according to the new screen size.

> If plasmashell notices the screen count change and the desktop is resized but doesn't update struts, that's a plasmashell bug.
> I could assume the fast updates (2 screens -> 1 screen on oversized root -> 1 screen) could make it miss the 2nd step because it's still occupied by reacting to the 1st step, but neither know, nor can't even test (until Qt 5.5 will hopefully stop those nasty no-screen segfaults)
> => please file a bug against plasmashell, panel component (reg. above thoughts, this could be timing related)

A workaround is manually force a strut recalculation (by resizing the panel or restarting plasmashell) after screen disconnect (or connect).

$ xrandr 
Screen 0: minimum 8 x 8, current 3286 x 1080, maximum 32767 x 32767
eDP1 connected primary 1366x768+0+0 (normal left inverted right x axis y axis) 293mm x 165mm
   1366x768      59.97*+
HDMI1 connected 1920x1080+1366+0 (normal left inverted right x axis y axis) 509mm x 286mm
   1920x1080     60.00*+
(some unused configurations omitted)

(before disconnect)
$ xprop | grep _NET_WM_STRUT
_NET_WM_STRUT(CARDINAL) = 0, 0, 0, 344
_NET_WM_STRUT_PARTIAL(CARDINAL) = 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 1365

(after disconnect and a panel resize)
$ xprop | grep _NET_WM_STRUT
_NET_WM_STRUT(CARDINAL) = 0, 0, 0, 32
_NET_WM_STRUT_PARTIAL(CARDINAL) = 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 1365
Comment 1 David Edmundson 2015-06-20 04:08:14 UTC
Created attachment 93254 [details]
possible fix
Comment 2 David Edmundson 2015-06-20 04:09:40 UTC
PanelView is watching for kscreen changing to call updateStruts, but updateStruts is using QScreen's internals knowledge, which has the /potential/ to be off.

I don't have access to another monitor for 10 days, would anyone be able to try this patch out ^
Comment 3 Andrew Chen 2015-06-20 10:35:21 UTC
Hi,
I tested your patch (applied on version 5.3.1). It works for the majority of the times, but it sometimes doesn't work. 3 out of the 10 times I tested it, it didn't work.
Comment 4 David Edmundson 2015-06-20 16:13:39 UTC
OK, sorry about that. I guess I need to debug what's going on a bit more.

If you want to help, you can add some debug into PanelView.cpp line 894 adding

qDebug() << "Updating struts: " << thisScreen << wholeScreen;

or I'll do it when I return.
Comment 5 Andrew Chen 2015-07-04 07:23:28 UTC
DRAFT:

Hi,
Sorry, I have been busy with exams for the past two weeks, so I didn't have time to respond.
I have debuged it a bit, and I found out a few things:

1. The first disconnect after (re)starting plasmashell never works. updateStruts() isn't even called in this case.
1435993121: ===Plasmashell starting up===
1435993125: Updating struts: QRect(0,0 1366x768) QRect(0,0 3286x1080)
# Screen disconnected, waited a few seconds, screen reconnected
1435993153: Updating struts: QRect(0,0 1366x768) QRect(0,0 1366x768)
1435993154: Updating struts: QRect(0,0 1366x768) QRect(0,0 3286x1080)
1435993154: Updating struts: QRect(0,0 1366x768) QRect(0,0 3286x1080)
1435993154: Updating struts: QRect(0,0 1366x768) QRect(0,0 3286x1080)

2. When it does work, updateStruts() is called twice, first with the old screen size, then again with the new screen size.
1435994121: Updating struts:  QRect(0,0 1366x768) QRect(0,0 3286x1080)
1435994122: Updating struts:  QRect(0,0 1366x768) QRect(0,0 1366x768)
# Screen disconnected, waited a few seconds, screen reconnected
1435994132: Updating struts:  QRect(0,0 1366x768) QRect(0,0 3286x1080)
1435994132: Updating struts:  QRect(0,0 1366x768) QRect(0,0 3286x1080)

3. When it does not work, updateStruts() is called once, but with the old screen size.
1435994301: Updating struts:  QRect(0,0 1366x768) QRect(0,0 3286x1080)
# Screen disconnected, waited a few seconds, screen reconnected
1435994307: Updating struts:  QRect(0,0 1366x768) QRect(0,0 1366x768)
1435994308: Updating struts:  QRect(0,0 1366x768) QRect(0,0 3286x1080)
1435994308: Updating struts:  QRect(0,0 1366x768) QRect(0,0 3286x1080)
1435994308: Updating struts:  QRect(0,0 1366x768) QRect(0,0 3286x1080)
Comment 6 Andrew Chen 2015-07-04 07:24:07 UTC
Oops, that "DRAFT" is not supposed to be there.
Comment 7 David Edmundson 2015-07-04 08:07:16 UTC
Is that with my possible fix patch applied or without?
Comment 8 Andrew Chen 2015-07-04 08:23:25 UTC
Oh, forgot to mention, all of the things described above are with your patch applied. I just tested and found out that without your patch, updateStruts() isn't called either on connecting or disconnecting the display.
Comment 9 Andrew Chen 2015-08-30 01:23:21 UTC
I figured out what's going on:

1) In the original code, panelview is listing to KScreen's outputAdded and outputRemoved, however, the output isn't 'added'/'removed' when it's connected/disconnected, it is mearly marked as (dis)connected.

2) Your patch listens to QScreen's virtualGeometryChanged, but that isn't always notified when it changes (I don't know why, might be a QScreen bug).

3) KScreen::Screen has a currentSize, but that's also broken. It is not updated by Screen::apply when it should really be. I filled the bug as https://bugs.kde.org/show_bug.cgi?id=352001 The bright side is that with that bug fixed, currentSizeChanged is usable. Therefore, I propose a fix based on it:



diff --git a/shell/panelview.cpp b/shell/panelview.cpp
index f67ae7d..c9b1968 100644
--- a/shell/panelview.cpp
+++ b/shell/panelview.cpp
@@ -106,14 +106,9 @@ PanelView::PanelView(ShellCorona *corona, QScreen *targetScreen, QWindow *parent
     m_strutsTimer.setSingleShot(true);
     connect(&m_strutsTimer, &QTimer::timeout,
             this, &PanelView::updateStruts);
-    connect(m_corona->screensConfiguration().data(), &KScreen::Config::outputAdded,
-            this, [this] (const KScreen::OutputPtr &) {
-                updateStruts();
-            });
-    connect(m_corona->screensConfiguration().data(), &KScreen::Config::outputRemoved,
-            this, [this] (int) {
-                updateStruts();
-            });
+
+    connect(m_corona->screensConfiguration()->screen().data(), &KScreen::Screen::currentSizeChanged,
+            this, &PanelView::updateStruts);
 
     qmlRegisterType<QScreen>();
     engine()->rootContext()->setContextProperty("panel", this);



I have tested that it works on my computer. Just a reminder, it only works if libkscreen is patched with the patch in Bug 352001.
Comment 10 David Edmundson 2015-08-30 14:32:08 UTC
>2) Your patch listens to QScreen's virtualGeometryChanged, but that isn't always notified when it changes (I don't know why, might be a QScreen bug).

Seems so; Qt has a /lot/ of bugs with QScreen
Will be worth fixing that long term

Patch seems OK, can you put it on reviewboard like you have for your kscreen one?
Comment 11 David Edmundson 2015-08-31 00:58:45 UTC
Now you're an expert at panel struts; do you think these two bugs are the same as this:

https://bugs.kde.org/show_bug.cgi?id=347195
https://bugs.kde.org/show_bug.cgi?id=349094
Comment 12 Andrew Chen 2015-08-31 06:40:30 UTC
Submitted: https://git.reviewboard.kde.org/r/124996/

Bug 349094 is the same as this bug, basically it is the reverse of the scenario in the description: the strut doesn't update and becomes thinner than it should be.
Bug 347195 looks related, but it might be caused by bugs in updateStruts. Disconnecting the primary output seems to cause a lot of problems. My simple testing (disconencting the primary output and then reconnecting) causes an integer overflow in the struts. Reconnecting it again causes even more problems (I've even seen windows disappearing).
I'll look into these problems.
Comment 13 David Edmundson 2015-08-31 07:33:01 UTC
*** Bug 349094 has been marked as a duplicate of this bug. ***
Comment 14 David Edmundson 2015-08-31 08:09:55 UTC
Git commit d66d6d57d34f3fc46a1cb7886f06dfe5b7a61763 by David Edmundson, on behalf of Andrew Chen.
Committed on 31/08/2015 at 08:09.
Pushed by davidedmundson into branch 'Plasma/5.4'.

Update struts on screen size change

Calls updateStruts on KScreen::Screen::currentSizeChanged instead of
KScreen::Config::outputAdded/outputRemoved.
When an output is (dis)conencted, it isn't added/removed, it is mearly
marked as (dis)connected. Therefore, updating struts on
outputAdded/outputRemoved doesn't work.
REVIEW: 124996

M  +3    -8    shell/panelview.cpp

http://commits.kde.org/plasma-workspace/d66d6d57d34f3fc46a1cb7886f06dfe5b7a61763
Comment 15 DrSlony 2015-09-01 18:12:12 UTC
Hello

Using plasma-5.4.0:

Disconnected:
$ xrandr -q 
Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 8192 x 8192
DVI-I-0 disconnected (normal left inverted right x axis y axis)
LVDS-0 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 382mm x 215mm
   1920x1080     60.01*+
HDMI-0 disconnected (normal left inverted right x axis y axis)
DVI-I-1 disconnected (normal left inverted right x axis y axis)

Connected:
$ xrandr -q 
Screen 0: minimum 8 x 8, current 3840 x 1200, maximum 8192 x 8192
DVI-I-0 disconnected (normal left inverted right x axis y axis)
LVDS-0 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 382mm x 215mm
   1920x1080     60.01*+
HDMI-0 disconnected (normal left inverted right x axis y axis)
DVI-I-1 connected 1920x1200+1920+0 (normal left inverted right x axis y axis) 519mm x 324mm
   1920x1200     59.95*+
   1920x1080     59.93  
   1680x1050     59.95  
   1600x1200     60.00  
   1280x1024     60.02  
   1280x960      60.00  
   1024x768      60.00  
   800x600       60.32  
   640x480       59.94  

Disconnected
$ xrandr -q 
Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 8192 x 8192
DVI-I-0 disconnected (normal left inverted right x axis y axis)
LVDS-0 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 382mm x 215mm
   1920x1080     60.01*+
HDMI-0 disconnected (normal left inverted right x axis y axis)
DVI-I-1 disconnected (normal left inverted right x axis y axis)