Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Trouble with KDE/Plasma window movement/snapping behavior
Forum Updated to NodeBB v4.3 + New Features

Trouble with KDE/Plasma window movement/snapping behavior

Scheduled Pinned Locked Moved Unsolved General and Desktop
1 Posts 1 Posters 329 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • W Offline
    W Offline
    William_Kappler
    wrote on last edited by
    #1

    I'm having this problem with Pyside6, but I suspect the same would affect a C++ program.

    I have a small frameless (Qt.FramelessWindowHint) window populated with a single QLabel displaying an image. I intend for this window to be movable by clicking anywhere on it and dragging.

    On most systems, that's not done by default, so I added handlers for mouse press/move/release on the window to emulate it moving. That works correctly.

    However, in at least some KDE/Plasma configurations (including mine), behavior similar to this is implemented by the window manager, along with window-to-window edge snapping. That would be fine, except my cross-platform manual movement conflicts with it.

    The KDE/Plasma move events cause the window to snap; however, my own do not, and it seems my own come after the KDE/Plasma on release. The result is my window LOOKS snapped, but then it jolts out of place. It also seems like there is some kind of disagreement over where the window should go beyond just the snapping, as the window moves on release even if it doesn't snap before or after release.

    Demo

    I have been largely unsuccessful finding information about this online, other than one Stack Overflow post essentially saying the behavior exists, which I already knew. However, through experimentation, I found the following:

    • Window flag Qt.Popup stops the default movement and snapping, but as a result, my window behaves differently to all the others on the system (it's the only one that WON'T snap at all).
    • Window flag Qt.X11BypassWindowManagerHint functionally does the same as Popup for my purposes, but with more side-effects.
    • Sticking in an event filter to see if I could tell which events were which showed that my own move events and the ones originating from the window manager looked effectively identical.
    • "accept()"ing the various mouse events doesn't stop the KDE behavior.
    • Implementing moveEvent() and having it do nothing other than accept() the event didn't seem to do anything.

    What I want: my window to behave like all other windows within the window manager (with or without snapping per window manager rules), but WITH the click-anywhere-and-drag movement behavior, and without weird secondary snapping/moving to the wrong location on mouse release.

    I think if I could just identify if this behavior exists or not in the given window manager, I would be fine. But it seems like there is no mechanism to do that. I can't go off the window manager being KDE/Plasma alone because it isn't universal behavior, it's configurable.

    Here's a cut down version of my window and how it's made. The program is quite a bit more complicated, but the full thing is here if you want to see it.

    class Viewer(QMainWindow):
        def __init__(self, app, filepath):
            super().__init__(None)
            self.setWindowFlag(Qt.FramelessWindowHint)
    #        self.setWindowFlag(Qt.Popup) # Bypass KDE movement and snapping if present
            ...
            self.drag_down_window_offset = None
            ...
            self.label = QLabel(self)
            self.setCentralWidget(self.label)
    ...
        def updateQtImage(self):
            pixmap = QPixmap.fromImage(self.image_layers.getQtImage(self.current_frame))
    
            first_update = self.label.pixmap is None
    
            self.label.setPixmap(pixmap)
    
            previous_size = self.size()
    
            # Needed to keep the image in its current size from blocking shrinking the window.
            self.setMinimumSize(0, 0)
    
            # Undo the max size that would be set below from a previous update.
            self.setMaximumSize(self.maximumWidth(), self.maximumHeight())
    
            self.resize(pixmap.width(), pixmap.height())
    
            # Prevent maximize or other window size changes.
            self.setMinimumSize(pixmap.width(), pixmap.height())
            self.setMaximumSize(pixmap.width(), pixmap.height())
    
            new_size = self.size()
    
            if not first_update:
                resize_offset = (previous_size - new_size) / 2
                self.move(self.pos() + QPoint(resize_offset.width(), resize_offset.height()))
    ...
        def mousePressEvent(self, event):
            if event.button() is Qt.MouseButton.LeftButton and Qt.ControlModifier in event.modifiers():
                ...
            elif event.button() is Qt.MouseButton.LeftButton:
                self.drag_down_window_offset = self.pos() - event.globalPosition().toPoint()
    
        def mouseMoveEvent(self, event):
            if self.drawing_crop:
                pos = event.position().toPoint()
                self.rubber_band.setGeometry(QRect(self.drawing_crop_origin, pos).normalized())
            elif self.drag_down_window_offset:
                self.move(self.drag_down_window_offset + event.globalPosition().toPoint())
    
        def mouseReleaseEvent(self, event):
            if event.button() is Qt.MouseButton.MiddleButton:
                self.close()
            elif event.button() is Qt.MouseButton.LeftButton and self.drawing_crop:
                ...
            elif event.button() is Qt.MouseButton.LeftButton and Qt.AltModifier in event.modifiers():
                self.resetImageScale()
            elif event.button() is Qt.MouseButton.LeftButton and self.drag_down_window_offset:
                self.drag_down_window_offset = None
    ...
    class ViewerApplication(QApplication):
        def __init__(self, args):
            super().__init__(args)
            # Does nothing relevant
    ...
        def openImageFile(self, path):
            viewer = Viewer(self, path)
    
            viewer.setWindowIcon(self.application_icon)
    
            viewer.show()
    
            # Sidestep the window getting "stuck" to the screen edges if too large.
            # See: https://stackoverflow.com/a/68477844
            viewer.updateQtImage()
            viewer.activateWindow()
    
            self.windows.append(viewer)
    
    1 Reply Last reply
    0

    • Login

    • Login or register to search.
    • First post
      Last post
    0
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Get Qt Extensions
    • Unsolved