Bug 350876 - After RandR changes, windows get lost (become hidden)
Summary: After RandR changes, windows get lost (become hidden)
Alias: None
Product: plasmashell
Classification: Unclassified
Component: Task Manager and Icons-Only Task Manager (show other bugs)
Version: 5.3.2
Platform: Archlinux Packages Linux
: NOR normal
Target Milestone: 1.0
Assignee: Eike Hein
Depends on:
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:

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

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

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
info locals
p clientsToRemove

break netwm.cpp:847
p count
p *windows@count

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;
### 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));
 246                 screen = createScreen(virtualDesktop, output.output, outputInfo.data());
 247                 qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled";
 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());
 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.


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