Mixxc icon indicating copy to clipboard operation
Mixxc copied to clipboard

odd focus and border behaviour when running in xmonad - xubuntu

Open dpnova opened this issue 2 years ago • 20 comments

Needed to sudo apt install libgtk-4-dev

Then installed with: cargo install mixxc --locked --features X11

Window pops up ok:

image

After some time it crashes, and I think if I change focus to another window it crashes instantly - here's the logs:

image

I'm not rust master but very experienced developer, so not afraid to get my hands dirty if required (might need a hand getting dev env set up :sweat_smile: )

dpnova avatar Mar 24 '24 23:03 dpnova

Ehh... Window probably doesn't crash. By default it automatically closes, when it looses focus together with mouse cursor, because under Wayland WM's don't send close request to layer shells like they do for regular windows. You can change this behavior with --keep flag, it's documented in README.md. I understand why you would think so, because of these GtkErrors, but you can safely ignore them, they appear only under X11 and only because i did some "hacks" for X11 to prevent window flickering on resizes.

Not sure why window is so big tho, default sizes even if you didn't specify them through -w and -h shouldn't be as big.

Elvyria avatar Mar 25 '24 01:03 Elvyria

Thanks for the report by the way, i tested Mixxc under X11 only once for I3 and AwesomeWM when i was writing X11 feature. I'll test xmonad and see if there's a need for more atomics for X11, because this window size is not normal and WM shouldn't allow you to resize it manually.

Elvyria avatar Mar 25 '24 01:03 Elvyria

So, the issue with size is related to xmonad's behavior towards windows with _NET_WM_WINDOW_TYPE set to _NET_WM_WINDOW_TYPE_UTILITY, both AwesomeWM and I3 treat _NET_WM_WINDOW_TYPE_UTILITY as floating windows with a free position.

You'll have change window rules inside your ${XDG_CONFIG_HOME:-$HOME/.config}/xmonad/xmonad.hs to something like this:

myManageHook = fullscreenManageHook <+> manageDocks <+> composeAll
    [ className =? "mixxc" --> doFloat, hasBorder False ]

or globally (affects PnP in Firefox)

import XMonad.Hooks.ManageHelpers ( isInProperty )
myManageHook = fullscreenManageHook <+> manageDocks <+> composeAll
    [ isInProperty "_NET_WM_WINDOW_TYPE" "_NET_WM_WINDOW_TYPE_UTILITY" --> doFloat ]

Elvyria avatar Mar 25 '24 03:03 Elvyria

Ehh... Window probably doesn't crash. By default it automatically closes, when it looses focus together with mouse cursor, because under Wayland WM's don't send close request to layer shells like they do for regular windows. You can change this behavior with --keep flag, it's documented in README.md. I understand why you would think so, because of these GtkErrors, but you can safely ignore them, they appear only under X11 and only because i did some "hacks" for X11 to prevent window flickering on resizes.

Not sure why window is so big tho, default sizes even if you didn't specify them through -w and -h shouldn't be as big.

Big window is the xmonad layout I'm using. Opens new windows as the larger middle one :)

Sorry didn't occur to me that it'd auto shut! I will totally add a hook for it. Sorry I rushed this report before work yesterday!

dpnova avatar Mar 25 '24 22:03 dpnova

className =? "mixxc" --> (doFloat <+> hasBorder False)

this did the trick for me, thanks!

I did notice some other weird behaviour, but I suspect that's a result of some weird interplay with layer shells. I've attached a video showing the border and focus behaviour. First I start mixxc which xmonad attempts to control in the current layout, then I use alt-click to drag it out of the layout manager, which makes a huge window :D - then I alt-right click to resize, which seems to trigger the default expect sizing.

I'm used to that stuff as an xmonad user. I think I'd have to stop using focus follows mouse to deal with the other wierdness you'll see in the vid.

https://github.com/Elvyria/Mixxc/assets/229943/4081b08f-9125-4bd3-be42-cd064ddaf39a

dpnova avatar Mar 25 '24 22:03 dpnova

I tested with my mouse follows focus hack disabled, commenting out this:

logHook = updatePointer (0.5, 0.5) (0, 0),

and didn't get the cursor issues, but still have the flickering border - which I guess may be a focus issue from the gtk hacks you mentioned too now that I think about it. 🤔

Either way, I love the widget, I think there's huge potential to combine with eww.

Cheers! (happy to test/hack btw)

dpnova avatar Mar 25 '24 23:03 dpnova

Just noticed that I don't get any of the flickering while the window is "managed" by xmonad - ie I haven't pulled it out of the layout manager. 🤔

noticed because I pulled the code and built locally to have a play with the x protocol

dpnova avatar Mar 26 '24 06:03 dpnova

That's some wild stuff. Looks like WM doesn't accept that window was resized and treats it as a fullscreen? one and it just constantly switches focus as 2 windows are in the same place.

The only thing that i noticed on X11 was a couple of frames of the window in the center of the screen, while it was sending resize+reposition request, but that's cosmetic and should be fixable.

Don't know if this will do anything for this situation, but you could try a different rendering backend, I've seen people mentioning that they have graphical glitches with the modern default one.

GSK_RENDERER=cairo mixxc

You can list everything that's available to you with.

GSK_RENDERER=help mixxc

If you want to try different things yourself you could start gutting out x.rs, maybe some _NET_WM_STATE_ flag is responsible.

I will do some more test with the default xmonad config that i have, but maybe it's something specific with your config and could you post it?

(if you didn't compile with Wayland feature you have no "layer-shell" in your binary to worry about, it's a Wayland specific thing)

Elvyria avatar Mar 26 '24 06:03 Elvyria

I absolutely lied about "default" config btw, i got some random one while trying to get xmonad to my distro :p

This is the one I'm testing with, maybe you can reference some differences that will help you: https://github.com/Axarva/dotfiles-2.0/blob/main/xmonad/xmonad.hs

Elvyria avatar Mar 26 '24 06:03 Elvyria

Seems people have noticed something similar with Reaper: https://www.reddit.com/r/xmonad/comments/18rck0e/reaper_daw_and_xmonad/

EDIT: actually nm - removing ewmh didn't resolve the underlying issue for me

In the mean time when i use mixxc as an xmonad managed window I don't have any problems :) that's my workaround for now.

dpnova avatar Mar 26 '24 23:03 dpnova

That could be xmonad <18.0 behavior.... https://xmonad.org/news/2024/02/03/xmonad-0-18-0.html https://packages.ubuntu.com/search?keywords=xmonad&searchon=names&suite=all&section=all

XMonad.Operations.floatLocation now applies size hints. This means windows will snap to these hints as soon as they’re floated (mouse move, keybinding). Previously that only happened on mouse resize.

Elvyria avatar Mar 27 '24 04:03 Elvyria

That could be xmonad <18.0 behavior.... https://xmonad.org/news/2024/02/03/xmonad-0-18-0.html

interesting - I'll try upgrading from 0.17 and see how I go.

EDIT: new xmonad indeed fixed the initial layout - window goes directly to anchor point. I end up putting it back into the layout manager though because of the border flickering and focus issues.

dpnova avatar Mar 27 '24 06:03 dpnova

Can we close this then? Without a way to reproduce the remaining focus issue (not on xmonad, not on i3 and not on AwesomeWM), i have no idea how to help you further and i don't know if it's related to Mixxc or your config.

Elvyria avatar Mar 27 '24 11:03 Elvyria

Can we close this then? Without a way to reproduce the remaining focus issue (not on xmonad, not on i3 and not on AwesomeWM), i have no idea how to help you further and i don't know if it's related to Mixxc or your config.

Fair point - I'll try create a minimal config to reproduce, or at least isolate the problem to something xmonad specific so we can close this.

btw - i started adding unit tests in my local clone, would you be open to PRs with tests?

dpnova avatar Mar 27 '24 23:03 dpnova

No, i don't need tests atm, there are much more important things to implement.

Elvyria avatar Mar 28 '24 09:03 Elvyria

No, i don't need tests atm, there are much more important things to implement.

Fair enough. I'll likely still do it for the rust learning. I'll keep an eye out for things you may accept contributions for.

dpnova avatar Mar 29 '24 03:03 dpnova

import XMonad

import XMonad.Util.EZConfig

main :: IO ()
main = xmonad def

I can reproduce the behaviour with this xmonad config. Not sure if it matters but I'm using nvidia proprietary drivers in prime mode.

image

I tried with cairo backend and have the same issues. From what I can see, the window is taking focus all the time. With this in mind, I ran xev while observing the behaviour, my log was filled with this whenever I was moving my mouse inside the mixxc window and no music is playing:

PropertyNotify event, serial 30, synthetic NO, window 0xc400001,
    atom 0x1d8 (WM_STATE), time 390186855, state PropertyNewValue

PropertyNotify event, serial 30, synthetic NO, window 0xc400001,
    atom 0x1d8 (WM_STATE), time 390186868, state PropertyNewValue

PropertyNotify event, serial 30, synthetic NO, window 0xc400001,
    atom 0x1d8 (WM_STATE), time 390186903, state PropertyNewValue

PropertyNotify event, serial 30, synthetic NO, window 0xc400001,
    atom 0x1d8 (WM_STATE), time 390187028, state PropertyNewValue

PropertyNotify event, serial 30, synthetic NO, window 0xc400001,
    atom 0x1d8 (WM_STATE), time 390187057, state PropertyNewValue

PropertyNotify event, serial 30, synthetic NO, window 0xc400001,
    atom 0x1d8 (WM_STATE), time 390187104, state PropertyNewValue

PropertyNotify event, serial 30, synthetic NO, window 0xc400001,
    atom 0x1d8 (WM_STATE), time 390187162, state PropertyNewValue

PropertyNotify event, serial 30, synthetic NO, window 0xc400001,
    atom 0x1d8 (WM_STATE), time 390187180, state PropertyNewValue

PropertyNotify event, serial 30, synthetic NO, window 0xc400001,
    atom 0x1d8 (WM_STATE), time 390187198, state PropertyNewValue

PropertyNotify event, serial 30, synthetic NO, window 0xc400001,
    atom 0x1d8 (WM_STATE), time 390187233, state PropertyNewValue

PropertyNotify event, serial 30, synthetic NO, window 0xc400001,
    atom 0x1d8 (WM_STATE), time 390187324, state PropertyNewValue

and when I'm doing something in any other window while music is playing (ie the level bar is animated in the mixxc window):


MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482423, (843,427), root:(1101,592),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482424, (835,425), root:(1093,590),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482425, (829,425), root:(1087,590),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482426, (823,423), root:(1081,588),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482427, (817,423), root:(1075,588),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482428, (811,421), root:(1069,586),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482429, (807,421), root:(1065,586),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482430, (799,419), root:(1057,584),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482431, (795,417), root:(1053,582),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482432, (791,415), root:(1049,580),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482433, (787,413), root:(1045,578),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482434, (785,413), root:(1043,578),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482435, (781,411), root:(1039,576),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482436, (779,419), root:(1037,584),
    state 0x0, is_hint 0, same_screen YES

MotionNotify event, serial 33, synthetic NO, window 0xc000001,
    root 0x973, subw 0x0, time 390482437, (783,421), root:(1041,586),
    state 0x0, is_hint 0, same_screen YES

note - if you'd rather mark this as a gotcha of using xmonad and just refer anyone with issues to this thread - I'm happy to close the ticket.

dpnova avatar Apr 01 '24 22:04 dpnova

After countless attempts and config removals, i was able to reproduce some form of border shimmering, but no focus problems.

import XMonad

import XMonad.Util.SpawnOnce ( spawnOnce )
import XMonad.Util.EZConfig

main :: IO ()
main = xmonad def { 
	manageHook = composeAll [ className =? "mixxc" --> doFloat ], 
	startupHook = do spawnOnce "kitty"
}

So the only thing that affected the behavior was my X11 Nvidia config at /etc/X11/xorg.conf.d/10-nvidia.conf

Section "Device"
	Identifier     "Nvidia Card"
	Driver         "nvidia"
	VendorName     "NVIDIA Corporation"
EndSection

Section "Screen"
	Identifier     "Default Screen"
	Device         "Nvidia Card"
	DefaultDepth    24
	Option         "Coolbits" "28"
	Option         "metamodes" "nvidia-auto-select +0+0 {ForceCompositionPipeline=On}"

	# Legacy option for VSYNC
	Option         "UseNvKmsCompositionPipeline" "false"
EndSection

Removing this option leads to shimmering on window's borders:

Option "metamodes" "nvidia-auto-select +0+0 {ForceCompositionPipeline=On}"

Using picom with glx backend and without composition pipeline also solved the issue $XDG_CONFIG_HOME/picom.conf:

animations: true;
animation-window-mass = 0.2;
animation-dampening = 15;
animation-clamping = true;
animation-for-open-window = "zoom";
animation-for-unmap-window = "zoom";
animation-for-transient-window = "slide-down";
animation-for-workspace-switch-in = "slide-down";
animation-for-workspace-switch-out = "zoom";
animation-for-prev-tag = "minimize";
enable-fading-prev-tag = false;
animation-for-next-tag = "slide-in-center";
enable-fading-next-tag = false;
shadow = true;
shadow-radius = 10;
shadow-opacity = .5;
shadow-offset-x = -5;
shadow-offset-y = -5;
shadow-exclude = [
	"name = 'Notification'",
	"class_g = 'Conky'",
	"class_g = 'flameshot'",
	"class_g = 'firefox'",
	"class_g = 'awesome'",
	"class_g ?= 'Notify-osd'",
	"class_g = 'Cairo-clock'",

	"_GTK_FRAME_EXTENTS@:c"
];
fading = true;
fade-in-step = 0.03;
fade-out-step = 0.03;
fade-delta = 4;
inactive-opacity = 1;
frame-opacity = 1.0;
inactive-opacity-override = false;
inactive-dim = 0.0
focus-exclude = [ "class_g = 'Cairo-clock'" ];
corner-radius = 0
rounded-corners-exclude = [
	"window_type = 'dock'",
	"window_type = 'desktop'"
];
blur: {
	method = "dual_kawase";
	strength = 1;
	background = true;
	background-frame = true;
	background-fixed = true;
}
blur-kern = "3x3box";
blur-background-exclude = [
	"window_type = 'dock'",
	"window_type = 'desktop'",
	"class_g = 'awesome'",
	"class_g = 'flameshot'",
	"class_g = 'xdg-desktop-portal-gnome'",
	"_GTK_FRAME_EXTENTS@:c"
];
backend = "glx"
vsync = false;
mark-wmwin-focused = true;
mark-ovredir-focused = true;
detect-rounded-corners = true;
detect-client-opacity = true;
use-ewmh-active-win = true
unredir-if-possible = true
unredir-if-possible-delay = 1000
detect-transient = true;
detect-client-leader = false;
glx-no-stencil = true;
glx-no-rebind-pixmap = true;
use-damage = true;
xrender-sync-fence = false;
no-ewmh-fullscreen = false
wintypes:
{
	tooltip = { animation = "none"; fade = true; shadow = true; opacity = 0.75; focus = true; full-shadow = false; };
	dock = { shadow = false; clip-shadow-above = true; }
	dnd = { shadow = false; }
	menu = { shadow = false; }
	popup_menu = { shadow = false; }
	dropdown_menu = { shadow = false; }
	utility = { shadow = false; };
};

Yeah, and next time send the minimal config i can actually use to reproduce, because with

import XMonad

import XMonad.Util.EZConfig

main :: IO ()
main = xmonad def

this is not reproducible, because as discussed it doesn't contain the rule for the floating window

manageHook = composeAll [ className =? "mixxc" --> doFloat ]

Elvyria avatar Apr 02 '24 14:04 Elvyria

I posted that config because that's how I reproduced it, I wasn't lying when I said that.

Anyway, it's probably edge case behaviour - close the ticket if it's too much of a pain 🤷

dpnova avatar Jul 09 '24 22:07 dpnova

This is prooooooobably an upstream issue. I tested for a bit in Xorg and aside from your issue, something from Nvidia + GTK::Scale skyrockets Xorg's CPU usage at nvkms_unlocked_ioctl. I'll leave a minimal example to build bellow, and if it causes the same issues, there's probably nothing that i can do. (also can recommend to profile with Sysprof and see what's up)

You could set env var PULSE_PEAK_RATE=0 to disable peakers and it should mitigate the issue.

main.rs

use std::time::Duration;

use rand::Rng;
use relm4::{gtk, ComponentParts, ComponentSender};

use relm4::component::Component;

use gtk::prelude::{GtkWindowExt, RangeExt};

#[tracker::track]
struct App { value: f64, }

#[derive(Debug)]
enum Command { ValueDown, ValueUp(f64), }

#[relm4::component(pub)]
impl Component for App {
    type Init = ();
    type Input = ();
    type Output = ();
    type CommandOutput = Command;

    view! {
        gtk::Window {
            set_resizable:     false,
            set_title:         Some(APP_NAME),
            set_decorated:     false,

            set_default_height: 100,
            set_default_width: 25,

            gtk::Box {
                #[name(scale)]
                gtk::Scale::with_range(gtk::Orientation::Vertical, 0.0, 1.0, 0.005) {
                    #[track = "model.changed(App::value())"]
                    set_value: model.value,
                },
            }
        }
    }

    fn init(_: Self::Init, root: Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self> {
        let model = App { value: 0.0, tracker: 0 };
        let widgets = view_output!();

        sender.command(|sender, shutdown| {
            shutdown.register(async move {
                let mut interval = tokio::time::interval(Duration::from_millis(10));

                loop {
                    interval.tick().await;
                    sender.emit(Command::ValueDown);
                }
            })
            .drop_on_shutdown()
        });

        sender.command(|sender, shutdown| {
            shutdown.register(async move {
                let mut interval = tokio::time::interval(Duration::from_millis(100));

                loop {
                    interval.tick().await;

                    let mut rng = rand::thread_rng();
                    sender.emit(Command::ValueUp(rng.gen_range(0.0..1.0)));
                }
            })
            .drop_on_shutdown()
        });

        ComponentParts { model, widgets }
    }

    fn update_cmd(&mut self, message: Self::CommandOutput, _: ComponentSender<Self>, _: &Self::Root) {
        match message {
            Command::ValueUp(peak) => {
               let peak = peak * 0.9;

               if peak > self.value + 0.035 {
                   self.set_value(peak + 0.015);
               }
            }
            Command::ValueDown => if self.value > 0.0 {
                self.set_value((self.value - 0.01).max(0.0));
            },
        }
    }
}

static APP_NAME: &str = "BITE_ME";

fn main() {
    let app = relm4::RelmApp::new(crate::APP_NAME).with_args(vec![]);

    app.set_global_css("scale { background-color: gray; }");

    app.run::<App>(());
}

Cargo.toml

[package]
name = "bug-debug"
version = "0.1.0"
edition = "2021"

[dependencies]
rand = "0.8.5"
tracker = "0.2"

[dependencies.tokio]
version = "1.37"
features = ["time", "macros"]

[dependencies.relm4]
version = "0.8.1"
default-features = false
features = ["macros"]

Elvyria avatar Jul 10 '24 13:07 Elvyria