hyprwm / Hyprland

Hyprland is an independent, highly customizable, dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
https://hyprland.org
BSD 3-Clause "New" or "Revised" License
21.48k stars 898 forks source link

Window focus change unexpectedly with QCompleter #7374

Open shouya opened 2 months ago

shouya commented 2 months ago

Regression?

No

System Info and Version

System/Version info ```sh Hyprland, built from branch at commit 918d8340afd652b011b937d29d5eea0be08467f5 (flake.lock: update). Date: Tue Jun 25 12:06:02 2024 Tag: v0.41.2, commits: 4886 flags: (if any) System Information: System name: Linux Node name: herbian Release: 6.9.12-amd64 Version: #1 SMP PREEMPT_DYNAMIC Debian 6.9.12-1 (2024-07-27) GPU information: 00:02.0 VGA compatible controller [0300]: Intel Corporation TigerLake-H GT1 [UHD Graphics] [8086:9a60] (rev 01) (prog-if 00 [VGA controller]) 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GA104M [GeForce RTX 3070 Mobile / Max-Q] [10de:249d] (rev a1) (prog-if 00 [VGA controller]) os-release: PRETTY_NAME="Debian GNU/Linux trixie/sid" NAME="Debian GNU/Linux" VERSION_CODENAME=trixie ID=debian HOME_URL="https://www.debian.org/" SUPPORT_URL="https://www.debian.org/support" BUG_REPORT_URL="https://bugs.debian.org/" plugins: ======Config-Start====== Config File: /home/shou/.config/hypr/hyprland.conf: Read Succeeded ################ ### MONITORS ### ################ # See https://wiki.hyprland.org/Configuring/Monitors/ $monitorL = eDP-1 $monitorR = DP-5 monitor=$monitorL,preferred,auto,2 monitor=$monitorR,preferred,auto,2 ################ ### COMPAT ### ################ env = XDG_CURRENT_DESKTOP,Hyprland env = XDG_SESSION_TYPE,wayland env = XDG_SESSION_DESKTOP,Hyprland env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1 env = QT_QPA_PLATFORM,wayland;xcb env = GDK_BACKEND,wayland,x11,* env = SDL_VIDEODRIVER,wayland env = ELECTRON_OZONE_PLATFORM_HINT,auto ### IME ### # refer to https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland#TL.3BDR_Do_we_still_need_XMODIFIERS.2C_GTK_IM_MODULE_and_QT_IM_MODULE.3F env = QT_IM_MODULES,wayland;fcitx;ibus env = QT_IM_MODULE,fcitx env = GTK_IM_MODULE,fcitx env = XMODIFIERS,@im=fcitx ### PATHS #### env = PATH,/home/shou/.asdf/shims:/home/shou/.asdf/bin:/home/shou/.cargo/bin:/home/shou/.local/bin:/home/shou/.elan/bin:/home/shou/.cabal/bin:/home/shou/.shell/bin:/home/shou/.nix-profile/bin:/home/shou/.local/share/pnpm:/home/shou/.bun/bin:dddddxs/home/shou/projects/user-config/xdg/xmonad/target:/usr/local/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/bin:/bin ################### ### MY PROGRAMS ### ################### # See https://wiki.hyprland.org/Configuring/Keywords/ # Set programs that you use $terminal = alacritty $fileManager = pcmanfm # $menu = wofi --show run # use custom built rofi-wayland $menu = ~/.local/bin/rofi -show combi -combi-modes "run,drun" -modes combi $scripts = ~/.config/hypr/scripts ################# ### AUTOSTART ### ################# # Autostart necessary processes (like notifications daemons, status bars, etc.) # Or execute your favorite apps at launch like this: # sync environment variables to xdg-desktop-portal exec-once=dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP exec-once = $terminal exec-once = nm-applet & exec-once = $scripts/wallpaper.sh & exec-once = eww open main-window exec-once = copyq --start-server exec-once = fcitx5 -d -r exec-once = $scripts/sleep.sh # exec-once = waybar & hyprpaper & firefox ############################# ### ENVIRONMENT VARIABLES ### ############################# # See https://wiki.hyprland.org/Configuring/Environment-variables/ env = XCURSOR_SIZE,24 env = HYPRCURSOR_SIZE,24 ############## ### NVIDIA ### ############## # env = LIBVA_DRIVER_NAME,nvidia # env = GBM_BACKEND,nvidia-drm # env = __GLX_VENDOR_LIBRARY_NAME,nvidia env = NVD_BACKEND,direct # va-api env = AQ_DRM_DEVICES,/dev/dri/card0:/dev/dri/card1 env = WLR_DRM_DEVICES,/dev/dri/card0:/dev/dri/card1 opengl { # or else the fps on external screen seems to be capped at 30 nvidia_anti_flicker = false } ##################### ### LOOK AND FEEL ### ##################### # Refer to https://wiki.hyprland.org/Configuring/Variables/ # https://wiki.hyprland.org/Configuring/Variables/#general general { gaps_in = 2 gaps_out = 0 border_size = 2 # https://wiki.hyprland.org/Configuring/Variables/#variable-types for info about colors col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg col.inactive_border = rgba(595959aa) # Set to true enable resizing windows by clicking and dragging on borders and gaps resize_on_border = false # only resize from lower right corner resize_corner = 3 # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on allow_tearing = true layout = master } # https://wiki.hyprland.org/Configuring/Variables/#decoration decoration { rounding = 5 # Change transparency of focused and unfocused windows active_opacity = 1.0 inactive_opacity = 1.0 drop_shadow = true shadow_range = 20 shadow_render_power = 4 col.shadow = rgba(1a1a1a6f) # https://wiki.hyprland.org/Configuring/Variables/#blur blur { enabled = false size = 3 passes = 1 vibrancy = 0.1696 } } # https://wiki.hyprland.org/Configuring/Variables/#animations animations { enabled = true # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more bezier = myBezier, 0.05, 0.9, 0.1, 1.05 animation = windows, 1, 3, myBezier animation = windowsOut, 1, 3, default, popin 80% animation = border, 1, 3, default animation = borderangle, 1, 3, default animation = fade, 1, 3, default animation = workspaces, 1, 3, default } # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more dwindle { pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below preserve_split = true # You probably want this } # See https://wiki.hyprland.org/Configuring/Master-Layout/ for more master { # new window should be opened as slave new_status = slave # resize window based on window's tiling location smart_resizing = false } # https://wiki.hyprland.org/Configuring/Variables/#misc misc { force_default_wallpaper = 0 disable_hyprland_logo = true disable_splash_rendering = true # allow variable refresh rate vfr = true # enable adaptive sync vrr = 1 # wake up from dpms on mouse move or key press mouse_move_enables_dpms = true key_press_enables_dpms = true # render directly to display to reduce latency no_direct_scanout = false # mouse move across monitor should not change focus mouse_move_focuses_monitor = false focus_on_activate = true } ############# ### INPUT ### ############# # https://wiki.hyprland.org/Configuring/Variables/#input input { kb_layout = us kb_options = ctrl:nocaps,altwin:swap_lalt_lwin repeat_rate = 45 repeat_delay = 200 # allow using mouse buttons on unfocused windows # and leave keyboard focus unchanged follow_mouse = 0 # so that the mouse focus won't switch to the hovered window mouse_refocus = false # do not switch focus when moving in/out floating windows float_switch_override_focus = 0 sensitivity = 0 # -1.0 - 1.0, 0 means no modification. touchpad { natural_scroll = false } accel_profile = flat } cursor { no_hardware_cursors = true min_refresh_rate = 60 # do not move cursor to newly focused window no_warps = true } # https://wiki.hyprland.org/Configuring/Variables/#gestures gestures { workspace_swipe = false } # Example per-device config # See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more device { name = syna8013:00-06cb:ce69-touchpad natural_scroll = true } device { name = logitech-g403-1 sensitivity = 0 } #################### ### KEYBINDINGSS ### #################### # See https://wiki.hyprland.org/Configuring/Keywords/ $mod = SUPER bind = $mod, Return, exec, alacritty bind = $mod SHIFT, Q, killactive, bind = $mod CTRL, F, togglefloating bind = $mod, Space, exec, $menu bind = $mod, V, exec, copyq show # App keys bind = $mod, F1, exec, wlrctl window focus firefox || firefox bind = $mod, F2, exec, wlrctl window focus emacs || emacs bind = $mod, F4, exec, wlrctl window focus title:malakal || malakal # Scratchpad apps bind = $mod, D, exec, $scripts/scratchpad.sh "goldendict -platform wayland" "com/xiaoyifang/goldendict-ng.https://github.goldendict" bind = $mod, M, exec, $scripts/scratchpad.sh "alacritty --class scratch-term" "scratch-term" bind = $mod, C, exec, $scripts/scratchpad.sh "qalculate-gtk" "qalculate-gtk" # Multi-media keys (bindl = works even when lock screen is on) $playsound = aplay /usr/share/sounds/sound-icons/percussion-10.wav bindl = , XF86AudioRaiseVolume, exec, amixer set Master 5%+; $playsound bindl = , XF86AudioLowerVolume, exec, amixer set Master 5%-; $playsound bindl = , XF86AudioMicMute, exec, amixer set Capture toggle bindl = , XF86AudioMute, exec, ~/.xmonad/scripts/toggle-mute.sh; $playsound bindl = , XF86AudioPlay, exec, playerctl play-pause bindl = , XF86AudioPause, exec, playerctl play-pause bindl = , XF86AudioNext, exec, playerctl next bindl = , XF86AudioPrev, exec, playerctl previous bindl = , XF86Display, exec, $scripts/reset-displays.sh bind = , Print, exec, grim -g "$(slurp -d)" - | wl-copy; notify-send "Screenshot copied to clipboard" # Move focus with mainMod + arrow keys bind = $mod, left, movefocus, l bind = $mod, right, movefocus, r bind = $mod, up, movefocus, u bind = $mod, down, movefocus, d # Master layout mode bind = $mod, H, layoutmsg, mfact -0.05 bind = $mod, L, layoutmsg, mfact +0.05 bind = $mod, J, exec, $scripts/cycle.sh next bind = $mod, K, exec, $scripts/cycle.sh prev bind = $mod SHIFT, J, layoutmsg, swapnext bind = $mod SHIFT, K, layoutmsg, swapprev bind = $mod, COMMA, layoutmsg, addmaster bind = $mod, PERIOD, layoutmsg, removemaster bind = $mod, Q, focusmonitor, $monitorL bind = $mod, E, focusmonitor, $monitorR # Switch workspaces with mainMod + [0-9] bind = $mod, 1, workspace, 1 bind = $mod, 2, workspace, 2 bind = $mod, 3, workspace, 3 bind = $mod, 4, workspace, 4 bind = $mod, 5, workspace, 5 bind = $mod, 6, workspace, 6 bind = $mod, 7, workspace, 7 bind = $mod, 8, workspace, 8 bind = $mod, 9, workspace, 9 bind = $mod, 0, workspace, 10 # Move active window to a workspace with mainMod + SHIFT + [0-9] bind = $mod SHIFT, 1, movetoworkspacesilent, 1 bind = $mod SHIFT, 2, movetoworkspacesilent, 2 bind = $mod SHIFT, 3, movetoworkspacesilent, 3 bind = $mod SHIFT, 4, movetoworkspacesilent, 4 bind = $mod SHIFT, 5, movetoworkspacesilent, 5 bind = $mod SHIFT, 6, movetoworkspacesilent, 6 bind = $mod SHIFT, 7, movetoworkspacesilent, 7 bind = $mod SHIFT, 8, movetoworkspacesilent, 8 bind = $mod SHIFT, 9, movetoworkspacesilent, 9 bind = $mod SHIFT, 0, movetoworkspacesilent, 10 # Example special workspace (scratchpad) bind = $mod, S, togglespecialworkspace, magic bind = $mod SHIFT, S, movetoworkspace, special:magic # Scroll through existing workspaces with mainMod + scroll bind = $mod, mouse_down, workspace, e+1 bind = $mod, mouse_up, workspace, e-1 # Move/resize windows with mainMod + LMB/RMB and dragging bindm = $mod, mouse:272, movewindow bindm = $mod, mouse:273, resizewindow # Utility keys bind = ALT CTRL, V, exec, calibre-to-anki.sh ############################## ### XWAYLAND ### ############################## xwayland { force_zero_scaling = true } # highlight xwayland windows windowrulev2 = bordercolor rgb(ff0000), xwayland:1 ############################## ### WINDOWS AND WORKSPACES ### ############################## # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more # See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules # range syntax r[1-9] does not work as expected probably because # they're created lazily. workspace = 1, monitor:$monitorL workspace = 2, monitor:$monitorL workspace = 3, monitor:$monitorL workspace = 4, monitor:$monitorL workspace = 5, monitor:$monitorL workspace = 6, monitor:$monitorL workspace = 7, monitor:$monitorL workspace = 8, monitor:$monitorR workspace = 9, monitor:$monitorR workspace = special:magic, floating # Example windowrule v1 # windowrule = float, ^(kitty)$ # Example windowrule v2 # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ # floating rules windowrulev2 = float, class:com.github.hluk.copyq windowrulev2 = float, class:com/xiaoyifang/goldendict-ng.https://github.goldendict windowrule = float, cs5610 windowrulev2 = suppressevent maximize, class:.* # You'll probably like this. # no shadow on tiled windowsg windowrulev2 = noshadow, floating:0 # enabling debugging can greatly affect performance debug { overlay = false damage_blink = false } ======Config-End======== ```

Description

I have configured Hyprland so that the mouse movement will never change keyboard focused window unless I click on a window. However, I found a scenario in ebook-viewer (a component of of Calibre) where the window focus is moved when it shouldn't.

I initially thought it's a bug with ebook-viewer, but when I browsed through the relevant code in Calibre, I now tend to believe the bug is from the compositor. I have distilled a minimal demo code to elicit the behavior.

How to reproduce

Setup:

  1. Download the attached bug-demo.py and install PyQt6 (pip install PyQt6)
  2. Apply the Hyprland config I provided.
  3. On an empty workspace, create two terminal window, let's call them A and B.
  4. Confirm that moving the mouse cursor around won't change windows focus

Reproduction:

  1. On A, run python ./bug-demo.py
  2. Click on the launched window (name it C) to focus it. Click on the input box to start typing.
  3. Move the mouse cursor outside window C. For example, let's say we hover over window B. Do not click so the focus stays on C.
  4. Type "app", notice the completion list shows up on C
  5. Type "x", now the completion list is hidden because of no matching entries
  6. Notice that the window focus moves from C to B without mouse clicking. Further keyboard typing events are dispatched to B instead of C.

Expected behavior:

Focus remains on C.


bug-demo.py:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QCompleter, QLineEdit
from PyQt6.QtCore import Qt, QStringListModel

class CompletionLineEdit(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        layout = QVBoxLayout()
        self.setLayout(layout)

        # Create the line edit
        self.line_edit = CustomLineEdit(self)
        layout.addWidget(self.line_edit)

        # Set up the completer
        self.completer = QCompleter()
        self.completer.setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
        self.line_edit.setCompleter(self.completer)

        # Dummy history for completion
        self.history = ["apple", "banana", "cherry", "date", "elderberry", "fig", "grape"]
        self.model = QStringListModel()
        self.model.setStringList(self.history)
        self.completer.setModel(self.model)

        self.setGeometry(300, 300, 250, 50)
        self.setWindowTitle('Completion Bug Demo')
        self.show()

class CustomLineEdit(QLineEdit):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.textChanged.connect(self.on_text_changed)

    def on_text_changed(self, text):
        print(f"Text changed: {text}")
        print(f"Completer popup visible: {self.completer().popup().isVisible()}")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = CompletionLineEdit()
    sys.exit(app.exec())

Crash reports, logs, images, videos

No response

MightyPlaza commented 2 months ago

is the B window floating? if so do you have float_switch_override_focus set?

shouya commented 2 months ago

No. All three windows are tiled.