1

I called the resize-method of the modal QDialog. I expected this to not affect its always-on-top behaviour, but instead it is now possible to bring the parent window to the front again.

The parent window is still not accessible for interactions (in this case the X/C/Ctrl+Q keybinds) while the modal is open.

Why does this happen?

My window manager is a twm-derivative (ctwm-4.0.3) running on X11, and it does not happen on xfce4.

I press X to open the resized dialog, and press C to open the "normal" one.

Additionally, the issue is reproducible also if I am the one to manually resize the modal and then try to raise the parent above it, with some caveats outlined further below.

import sys
from PyQt5.QtCore import QSize
from PyQt5.QtWidgets import QApplication, QWidget, QShortcut, QDialog

class Dialog(QDialog):
    def __init__(self, parent, resize):
        super().__init__(parent)
        self.setModal(True)
        if resize:
            self.setWindowTitle("Not on top")
            self.setStyleSheet("QDialog {background: magenta}")
            self.resize(QSize(600,600))
        else:
            self.setWindowTitle("Always on top")
            self.setStyleSheet("QDialog {background: purple}")

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Parent window")
        self.setStyleSheet("MainWindow {background: orange}")

        shortcut = QShortcut("Ctrl+Q", self)
        shortcut.activated.connect(self.close)

        shortcut = QShortcut("X", self)
        shortcut.activated.connect(self.show_resized_dialog)

        shortcut = QShortcut("C", self)
        shortcut.activated.connect(self.show_dialog)

        self.show()

    def show_resized_dialog(self):
        dialog = Dialog(self, True)
        dialog.show()
        self.raise_()

    def show_dialog(self):
        dialog = Dialog(self, False)
        dialog.show()
        self.raise_()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainwindow = MainWindow()
    sys.exit(app.exec_())

From some additional experimenting, including commenting out all resize and raise_-calls from the code and then manually resizing the modal myself by hand, it seems the issue starts happening once the modal grows to a certain size. This size (width,height) appears extremely consistent, but does not appear to be a function solely of the width or solely the height.

For example, (width,height)=(300,300) causes it, as does (300,299) and (299,300) -- but (299,299) does not and neither does (300,298) -- but (301,298) does cause it.

(200,460) causes it but (200,459) does not -- and as a last example (800,100) causes the issue while (100,800) does not.

Meowf
  • 65
  • 7
  • Well, *almost* always on top. My window manager can explicitly tell the purple always-on-top modal window to lower itself behind the other windows, but it can not raise the parent window on top by moving it or giving it focus or by telling it to raise itself. And if I then try to interact with the parent window the always-on-top modal immediately comes to the front again. These comments are all asides and not relevant to the original question. – Meowf Oct 18 '21 at 03:27
  • Please [edit] the question to add more details. It seems more of a wm bug; even if the main window can be raised, is it possible to interact with it? – musicamante Oct 18 '21 at 05:09
  • Nope, no interactions beyond the modal losing its always-on-top behaviour. I added that information to the OP. – Meowf Oct 18 '21 at 05:56
  • I can't reproduce this on archlinux with X11 and openbox. It could be a quirk of twm/ctwm, or perhaps whatever display server, compositor, etc you are using. There's a somewhat similar-looking issue here: [QTBUG-75144](https://bugreports.qt.io/browse/QTBUG-75144), which is linked to [Wayland issue-231](https://gitlab.freedesktop.org/wayland/weston/-/issues/231). PS: Does the problem still occur if `self.raise_()` is omitted or executed before the dialog is shown? – ekhumoro Oct 18 '21 at 11:24
  • it occurs without `self.raise_()`, that was just to automate it to more quickly reproduce the issue. It also happens if I manually resize -- but not always, and in fact it seems there is more to it than I at first thought (running out of characters so I will add it in a second comment and also in the original question). – Meowf Oct 18 '21 at 12:02
  • Automatically and manually resizing the modal to (600,600) always causes the issue. As does all sizes I tried above 300 pixels in both dimensions. Small sizes seem to never cause the issue. There seems to be a relationship between the width and the height at where it happens and where it does not happen, but I have not found what the relationship is. – Meowf Oct 18 '21 at 12:05
  • So it appears to be related to an option in my window manager (ctwm) as was suggested. How should this be documented with regards to the question? It sounds like a bug, so perhaps the question should be deleted as it would need some heavy editing to reflect the solution and probably is not limited to PyQt. – Meowf Oct 18 '21 at 13:03
  • @Meowf Are you using Wayland or X11 (or some other display server)? – ekhumoro Oct 18 '21 at 14:13
  • X11 (xorg-server-1.20.13) – Meowf Oct 18 '21 at 14:23
  • @Meowf You should turn your latest edit into an anwer and accept it, as other ctwm users may well find it useful. – ekhumoro Oct 18 '21 at 14:28
  • Should I edit the question first to be more explicit about it being a ctwm issue? I will probably post to the ctwm mailing list anyway as well. – Meowf Oct 18 '21 at 14:33
  • @Meowf Your question/answer look fine. (You could add a link to your mailing list thread, if you decide to start one). – ekhumoro Oct 18 '21 at 16:19

1 Answers1

1

As it was not reproducible on xfce4, it was likely a window-manager issue (ctwm in this case).

Toggling various configuraiton options in .twmrc off and on, the issue in this case looks like it is caused by ctwm-variable NoRaiseOnWarp being set.

If this variable is unset (by commenting it out), the modal window will stay on top as it does in xfce4 (except for while the parent window is being dragged around in ctwm, but the modal will immediately raise to the top and remain on top again after the drag-operation finishes).

The description of the variable from the ctwm manpage is:

NoRaiseOnWarp

This variable indicates that windows should not be raised when the 
pointer is warped into them with the f.warpto function. If this option 
is set, warping to an occluded window may result in the pointer ending
up in the occluding window instead the desired window (which causes 
unexpected behavior with f.warpring).

it is not clear to me from the description of the variable why this behaviour would arise with e.g. modals, and making a post on the ctwm mailing list about it may be a good idea.

Meowf
  • 65
  • 7