Bug 350876 - After RandR changes, windows get lost (become hidden)
Summary: After RandR changes, windows get lost (become hidden)
Status: RESOLVED UPSTREAM
Alias: None
Product: plasmashell
Classification: Plasma
Component: Task Manager and Icons-Only Task Manager widgets (show other bugs)
Version: 5.3.2
Platform: Arch Linux Linux
: NOR normal
Target Milestone: 1.0
Assignee: Eike Hein
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-08-02 09:22 UTC by Peter Wu
Modified: 2015-10-29 12:02 UTC (History)
5 users (show)

See Also:
Latest Commit:
Version Fixed In:
Sentry Crash Report:


Attachments
xprop windows list + annotated gdb log (see ### markers) (65.35 KB, text/plain)
2015-08-02 10:37 UTC, Peter Wu
Details
xscope output showing DestroyNotify+CreateNotify (2.64 KB, text/plain)
2015-08-04 10:57 UTC, Peter Wu
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Peter Wu 2015-08-02 09:22:29 UTC
When toggling an external monitor via xrandr (iirc also Display Settings), windows would be hidden and unavailable via the Task Manager and Alt-Tab. The location of windows (which of the two monitors) do not seem to have an effect on the victim selection.

Reproducible: Always

Steps to Reproduce:
1. Open a few windows (for example, konsole with journalctl, another konsole window, System Settings)
2. Invoke this command:
xrandr --output HDMI1 --off && sleep 4 &&
xrandr --output HDMI1 --mode 2560x1440_30 --left-of LVDS1

Actual Results:  
Some windows get lost from the Task Manager.

Expected Results:  
All windows are still available in the Task Manager (or Tab Box), somewhere.

Package versions on Arch Linux (recompiled to include debugging symbols):
Qt 5.5.0 (with two patches applied to fix crashes on multi-monitor handling, https://bugs.archlinux.org/task/43986#comment137773).
plasma-frameworks 5.12.0
plasma-workspace 5.3.2

These packages were built with -DCMAKE_BUILD_TYPE=Debug
kwindowsystem 5.12.0
kwin 5.3.2

Once such a situation happens, windows can be "recovered" usings its Window Id.
$ xdotool search --pid `pidof konsole` | xargs -tn1 xprop _NET_WM_NAME -id
xprop _NET_WM_NAME -id 4194414
_NET_WM_NAME(UTF8_STRING) = "peter : bash"
xprop _NET_WM_NAME -id 4194417
_NET_WM_NAME(UTF8_STRING) = "peter : journalctl"
xprop _NET_WM_NAME -id 4194438
_NET_WM_NAME(UTF8_STRING) = "peter : screen"
xprop _NET_WM_NAME -id 4194510
...
$ xdotool windowmap 4194438
Comment 1 Peter Wu 2015-08-02 10:37:34 UTC
Created attachment 93843 [details]
xprop windows list + annotated gdb log (see ### markers)

It sounds like this bug:
FS#1155 - Windows not managed after changing resolution through RandR in 3.5.1
https://awesome.naquadah.org/bugs/index.php?do=details&task_id=1155

Using this GDB script I am able to track the changes (see attachment) to the windows list (p->clients):
```
set pagination off
set logging file ~/kwin-gdb.txt
set logging on

break netwm.cpp:2222
commands
info locals
p clientsToRemove
bt
c
end

break netwm.cpp:847
commands
p count
p *windows@count
bt
c
end
```

Observation: the windows that get lost (kate, konsole, systemsettings5) have their Window Id changed. Note that in this particular trace, the plasma panel was already hidden/gone. Perhaps by coincidence, only one of the windows per process were gone (in the past I had cases where multiple konsole windows were gone).
Comment 2 Peter Wu 2015-08-04 10:57:04 UTC
Created attachment 93883 [details]
xscope output showing DestroyNotify+CreateNotify

Tried to reproduce it again and now I lost 7 windows at once (just a browser window remained). Did a tap on kwin_x11 (see the attachment for a partial log):
xauth -n list :0 | sed s/:0/:1/ | xargs xauth add
xscope > xscope.txt
DISPLAY=:1 kwin_x11 --replace

Notice that the window one of the victims (kate) got destroyed and created again. Its source is via SendEvent, but cannot find a trace in the xscope log between kwin_x11 and Xorg. I thought that Qt is to be blamed, but Firefox is a GTK+ app.

Breakpoint 1, NETRootInfo::update (this=0x280e650, properties=..., properties@entry=..., properties2=..., properties2@entry=...) at kwindowsystem-5.12.0/src/netwm.cpp:
2223                delete [] p->clients;
[561780.868708]
### Argh, lost 7 windows! Lost! LOST!
#  0xa00007 "peter : screen"          # 10485767
#  0xa0001d "peter : bash"            # 10485789
# 0x1200006 "ps-mem  — Kate"          # 18874374
# 0x1800006 "Untitled  — Kate"        # 25165830
# 0x2800010 "Desktop — Plasma"        # 41943056
# 0x280001b "Plasma"                  # 41943067
# 0x280009a "Desktop — Plasma"        # 41943194
clientsToRemove = {10485767, 10485789, 18874374, 25165830, 41943056, 41943067, 41943194}
Comment 3 Peter Wu 2015-08-04 22:18:35 UTC
Okay, it looks like Qt is responsible for unmapping the window and the two merged Qt patches (https://bugreports.qt.io/browse/QTBUG-44158, https://codereview.qt-project.org/114796, https://codereview.qt-project.org/120700) do have an effect here which is not handled by kwin_x11.

kwin_x11 assumes that the Window ID never changes, but this is not true afer this Qt change since it destroys a window for RandR changes. I've yet to check why this happens so randomly and whether this event always occurs (or whether it is bound to a window).

Breaking on UnmapWindow xscope and triggering the condition with xrandr gives this kate gdb backtrace on the bottom. It looks intentional...

qt-everywhere-opensource-src-5.5.0/qtbase/src/plugins/platforms/xcb/qxcbconnection.cpp (+two patches)
 238         } else if (!screen && output.connection == XCB_RANDR_CONNECTION_CONNECTED) {
 239             // New XRandR output is available and it's enabled
 240             if (output.crtc != XCB_NONE && output.mode != XCB_NONE) {
 241                 xcb_randr_get_output_info_cookie_t outputInfoCookie =
 242                     xcb_randr_get_output_info(xcb_connection(), output.output, output.config_timestamp);
 243                 QScopedPointer<xcb_randr_get_output_info_reply_t, QScopedPointerPodDeleter> outputInfo(
 244                     xcb_randr_get_output_info_reply(xcb_connection(), outputInfoCookie, NULL));
 245
 246                 screen = createScreen(virtualDesktop, output.output, outputInfo.data());
 247                 qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled";
 248
 249                 screen->setPrimary(checkOutputIsPrimary(output.window, output.output));
 250                 foreach (QXcbScreen *otherScreen, m_screens)
 251                     if (otherScreen->root() == output.window)
 252                         otherScreen->addVirtualSibling(screen);
 253                 m_screens << screen;
 254                 QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary());
 255
 256                 // Windows which had null screens have already had expose events by now. <------ change 120700
 257                 // They need to be told the screen is back, it's OK to render.
 258                 foreach (QWindow *window, QGuiApplication::topLevelWindows()) {
 259                     QXcbWindow *xcbWin = static_cast<QXcbWindow*>(window->handle());
 260                     if (xcbWin)
 261                         xcbWin->maybeSetScreen(screen);
 262                 } // <------------------------------- end of change 120700
 263             }
 264             // else ignore disabled screens
 265         } else if (screen) {                                                                      
 266             // Screen has been disabled -> remove
 267             if (output.crtc == XCB_NONE && output.mode == XCB_NONE) {
 268                 xcb_randr_get_output_info_cookie_t outputInfoCookie = // <------- modified by change 114796
 269                     xcb_randr_get_output_info(xcb_connection(), output.output, output.config_timestamp);
 270                 QScopedPointer<xcb_randr_get_output_info_reply_t, QScopedPointerPodDeleter> outputInfo(
 271                     xcb_randr_get_output_info_reply(xcb_connection(), outputInfoCookie, NULL));
 272                 if (outputInfo->crtc == XCB_NONE) {
 273                     qCDebug(lcQpaScreen) << "output" << screen->name() << "has been disabled";
 274                     m_screens.removeOne(screen);
 275                     foreach (QXcbScreen *otherScreen, m_screens)
 276                         otherScreen->removeVirtualSibling((QPlatformScreen *) screen);
 277                     QXcbIntegration::instance()->destroyScreen(screen); // <----------------------------------- gdb frame 15
 278                 } else {
 279                     qCDebug(lcQpaScreen) << "output" << screen->name() << "has been temporarily disabled for the mode switch";
 280                 } // <---- end of modification by change 114796
 281             } else {
 282                 // Just update existing screen

gdb backtrace for kate
#0  0x00007fffeea7196f in pthread_cond_wait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
#1  0x00007fffef0a5c49 in _xcb_conn_wait (c=c@entry=0x62d100, cond=cond@entry=0x7fffffffcdf0, vector=vector@entry=0x0, count=count@entry=0x0) at xcb_conn.c:427
#2  0x00007fffef0a7317 in wait_for_reply (c=c@entry=0x62d100, request=1053, e=e@entry=0x0) at xcb_in.c:491
#3  0x00007fffef0a7421 in xcb_wait_for_reply (c=0x62d100, request=1053, e=e@entry=0x0) at xcb_in.c:521
#4  0x00007fffef0abb05 in xcb_get_property_reply (c=<optimized out>, cookie=..., e=e@entry=0x0) at xproto.c:2566
#5  0x00007fffe2e24f91 in xcb_icccm_get_wm_hints_reply (c=<optimized out>, cookie=..., hints=hints@entry=0x7fffffffcec0, e=e@entry=0x0) at icccm.c:778
#6  0x00007fffe36a1682 in QXcbWindow::updateDoesNotAcceptFocus (this=this@entry=0xaa9a70, doesNotAcceptFocus=doesNotAcceptFocus@entry=false) at qxcbwindow.cpp:1492
#7  0x00007fffe36a4549 in QXcbWindow::setWindowFlags (this=this@entry=0xaa9a70, flags=...) at qxcbwindow.cpp:1147
#8  0x00007fffe36a5f29 in QXcbWindow::create (this=0xaa9a70) at qxcbwindow.cpp:643
#9  0x00007fffe3692661 in QXcbIntegration::createPlatformWindow (this=<optimized out>, window=0xaeb340) at qxcbintegration.cpp:201
#10 0x00007ffff357ce34 in QWindowPrivate::create (this=this@entry=0xceab40, recursive=recursive@entry=true) at kernel/qwindow.cpp:392
#11 0x00007ffff357dc00 in QWindowPrivate::setTopLevelScreen (this=0xceab40, newScreen=0x63d900, recreate=<optimized out>) at kernel/qwindow.cpp:383
#12 0x00007ffff359b1ac in QScreen::~QScreen (this=0xd1c9f0, __in_chrg=<optimized out>) at kernel/qscreen.cpp:97
#13 0x00007ffff359b2a9 in QScreen::~QScreen (this=0xd1c9f0, __in_chrg=<optimized out>) at kernel/qscreen.cpp:104
#14 0x00007ffff3561bc9 in QPlatformIntegration::destroyScreen (this=<optimized out>, screen=0x1126330) at kernel/qplatformintegration.cpp:473
#15 0x00007fffe368d72c in QXcbConnection::updateScreens (this=this@entry=0x62ac10, event=event@entry=0x7fffdc003530) at qxcbconnection.cpp:277
#16 0x00007fffe368eea3 in QXcbConnection::handleXcbEvent (this=this@entry=0x62ac10, event=event@entry=0x7fffdc003530) at qxcbconnection.cpp:1112
#17 0x00007fffe368f303 in QXcbConnection::processXcbEvents (this=0x62ac10) at qxcbconnection.cpp:1434
#18 0x00007ffff3045eb1 in QObject::event (this=0x62ac10, e=<optimized out>) at kernel/qobject.cpp:1246
#19 0x00007ffff3d5000c in QApplicationPrivate::notify_helper (this=this@entry=0x620ad0, receiver=receiver@entry=0x62ac10, e=e@entry=0x7fffdc003a20)
    at kernel/qapplication.cpp:3717
#20 0x00007ffff3d554e6 in QApplication::notify (this=0x7fffffffdc80, receiver=0x62ac10, e=0x7fffdc003a20) at kernel/qapplication.cpp:3500
#21 0x00007ffff301689b in QCoreApplication::notifyInternal (this=0x7fffffffdc80, receiver=0x62ac10, event=event@entry=0x7fffdc003a20) at kernel/qcoreapplication.cpp:965
#22 0x00007ffff3018c96 in sendEvent (event=0x7fffdc003a20, receiver=<optimized out>) at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:224
#23 QCoreApplicationPrivate::sendPostedEvents (receiver=receiver@entry=0x0, event_type=event_type@entry=0, data=0x620540) at kernel/qcoreapplication.cpp:1593
#24 0x00007ffff3019178 in QCoreApplication::sendPostedEvents (receiver=receiver@entry=0x0, event_type=event_type@entry=0) at kernel/qcoreapplication.cpp:1451
#25 0x00007ffff306ce33 in postEventSourceDispatch (s=0x655d90) at kernel/qeventdispatcher_glib.cpp:271
#26 0x00007fffedee7a17 in g_main_dispatch (context=0x7fffdc0016f0) at gmain.c:3122
#27 g_main_context_dispatch (context=context@entry=0x7fffdc0016f0) at gmain.c:3737
#28 0x00007fffedee7c70 in g_main_context_iterate (context=context@entry=0x7fffdc0016f0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3808
#29 0x00007fffedee7d1c in g_main_context_iteration (context=0x7fffdc0016f0, may_block=may_block@entry=1) at gmain.c:3869
#30 0x00007ffff306d23f in QEventDispatcherGlib::processEvents (this=0x655d70, flags=...) at kernel/qeventdispatcher_glib.cpp:418
#31 0x00007ffff301426a in QEventLoop::exec (this=this@entry=0x7fffffffd9c0, flags=..., flags@entry=...) at kernel/qeventloop.cpp:204
#32 0x00007ffff301c20c in QCoreApplication::exec () at kernel/qcoreapplication.cpp:1229
#33 0x00007ffff7ba8d04 in kdemain () from /usr/lib/libkdeinit5_kate.so
#34 0x00007ffff779c790 in __libc_start_main () from /usr/lib/libc.so.6
#35 0x0000000000400779 in _start ()
Comment 4 Martin Flöser 2015-08-10 07:40:23 UTC
reassigning to Plasma as it's taskmanager related. (KWin handles changing window IDs just fine - it's a different Client for KWin, though)
Comment 5 Eike Hein 2015-09-01 10:07:07 UTC
If it also happens in the Tab Box it may not be libtm.
Comment 6 Christoph Cullmann 2015-10-05 11:51:42 UTC
Qt has a bug for exactly that: either crash or no longer visible updated windows after change of screen layout.

https://bugreports.qt.io/browse/QTBUG-42985

Better report all stuff there to escalate that, thought even silver support people didn't get any fix that works...