odd focus and border behaviour when running in xmonad - xubuntu
Needed to sudo apt install libgtk-4-dev
Then installed with: cargo install mixxc --locked --features X11
Window pops up ok:
After some time it crashes, and I think if I change focus to another window it crashes instantly - here's the logs:
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: )
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.
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.
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 ]
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
--keepflag, it's documented inREADME.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
-wand-hshouldn'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!
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
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)
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
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)
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
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.
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§ion=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.
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.
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.
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?
No, i don't need tests atm, there are much more important things to implement.
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.
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.
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.
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 ]
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 🤷
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"]