chjj / compton

A compositor for X11.
Other
2.25k stars 500 forks source link

Window focus tracking in i3 malfunctions #59

Closed daBrado closed 11 years ago

daBrado commented 12 years ago

In i3, when using the "-i" option to make inactive windows have transparency, if I change between windows or between parent and child containers, sometimes a wrong window becomes or is left opaque. Or, when using function keys, all windows get transparency momentarily, as if they all shortly lose focus (even though they don't truely seem to be, e.g. according to the text cursor style in the currently focused window).

It seemed like compton was reacting to the wrong XFocusChangeEvents. So, I tweaked the code a bit to only react to relevent XFocusChangeEvents. It seems to work at least in i3, and from what I can tell from some Xlib docs it should be fine elsewhere, though I'm not certain... anyway, you can see the change here: https://github.com/daBrado/compton/commit/0de213374b7d093c643de14414878d4113081a89

If that looks useful I can submit a pull request. The only other change was that I added a bit more verbosity to the DEBUG_EVENTS messages for XFocusChangeEvent reporting.

richardgv commented 12 years ago

Ah, thanks for your patches, firstly. :-)

The code of focus event handling was written by @chjj a long time ago, and I saw nobody else complained there's a problem... As this could cause some rather severe results, and many distros are pulling from the master branch directly, it's unlikely we will merge your changes into master branch very soon.

I installed i3 myself but probably because I'm just too unfamiliar with tiling window managers, I didn't see anything particularly wrong. Could you please show me the exact steps to reproduce the issue? (Yeah, I know pressing function keys make all window appear inactive, I'm talking about the more severe cases you mentioned.) I looked briefly at the Xlib manual, and my first impression is, we shouldn't monitor NotifyVirtual but only NotifyNonlinear and NotifyNonlinearVirtual. But it's just my first impression. I'm currently playing with the simplistic condition (NotifyNonlinear == ev->detail || NotifyNonlinearVirtual == ev->detail). I need time for further investigation. Are you aware of any good documentation about this, except the Xlib manual, or any a program that does similar jobs?

Or maybe we could switch to relying on _NET_WM_ACTIVE_WINDOW, defined in EWMH standard...

daBrado commented 12 years ago

Understandable. I can just use my fork if/until a fix makes it into master. Thanks for looking into it!

One of the more common triggers was if one created a minimum of 3 windows and switched between two of them while the pointer was sitting in the third, the window with the pointer in it along with the truely focused window would become opaque.

The exact reason for that particular artifact I think is because currently there is no check on the kind of XFocusChangeEvent coming in to ev_focus_in(), and in the above scenario an event with detail NotifyPointer comes in to the window with the mouse pointer, which tricks compton into thinking that that window has focus.

The reason I added the pass-through for NotifyVirtual events may be specific to i3, as that detail type occurs when moving between parent and child containers, which is something i3 does to organize its tree of split windows. This solved an issue where if I moved up the parent heirarchy and then tried to go back to a child window, the focus would get lost by compton. Though this probably only came up once I made ev_focus_in() more restrictive on what events it reacted to.

Also, admittedly, the reason I changed from checking for NotifyGrab to NotifyWhileGrabbed is due to watching the event stream while doing stuff in i3, and the NotifyWhileGrabbed detail events provided the clearest indication of a focus change while navigating with the keyboard, and also filtered out focus changes being registered by function key presses. I thought this might make sense due to the Xlib manual's description of NotifyNormal and NotifyWhileGrabbed seemingly being for typical focus change behavior vs NotifyGrab and NotifyUngrab being for use of the XGrabKeyboard() function... which I suppose might be a valid loss of focus... except at least for i3 means getting flicker while pressing function keys...

I'm sorry, but I currently don't have more info/examples outside of the Xlib manual...

using _NET_WM_ACTIVE_WINDOW could be interesting, though I don't know much about it...

Thanks again for looking into it!

chjj commented 12 years ago

Sorry, yeah, this actually is a problem. I could never quite perfect the focus code and I probably should have created an issue for it. There are situations where two windows may have focus opacity at the same time, etc. Anyway, glad this issue got created.

richardgv commented 12 years ago

@daBrado:

One of the more common triggers was if one created a minimum of 3 windows and switched between two of them while the pointer was sitting in the third, the window with the pointer in it along with the truely focused window would become opaque.

The exact reason for that particular artifact I think is because currently there is no check on the kind of XFocusChangeEvent coming in toev_focus_in(), and in the above scenario an event with detail NotifyPointer comes in to the window with the mouse pointer, which tricks compton into thinking that that window has focus.

Indeed. The fact that compton does not do any check for FocusIn events does not look very sane. Perhaps I don't see the issue because I'm a SloppyFocus user (let focus follows mouse movement, basically).

The reason I added the pass-through for NotifyVirtual events may be specific to i3, as that detail type occurs when moving between parent and child containers, which is something i3 does to organize its tree of split windows. This solved an issue where if I moved up the parent heirarchy and then tried to go back to a child window, the focus would get lost by compton. Though this probably only came up once I made ev_focus_in() more restrictive on what events it reacted to.

As far as I could understand, compton should only be monitoring direct children of the root window (but there's probably a bug in ev_create_notify() that causes it to care about other windows?), so there shouldn't be a situation when compton should care about focus transfer between parent and child windows. But if WM is using virtual root window or subcontainers, things may get more complicated. Well, I will look into this later.

Also, admittedly, the reason I changed from checking for NotifyGrab to NotifyWhileGrabbed is due to watching the event stream while doing stuff in i3, and the NotifyWhileGrabbed detail events provided the clearest indication of a focus change while navigating with the keyboard, and also filtered out focus changes being registered by function key presses. I thought this might make sense due to the Xlib manual's description of NotifyNormal and NotifyWhileGrabbed seemingly being for typical focus change behavior vs NotifyGrab and NotifyUngrab being for use of the XGrabKeyboard() function... which I suppose might be a valid loss of focus... except at least for i3 means getting flicker while pressing function keys...

That's something I'm unsure about...

I'm sorry, but I currently don't have more info/examples outside of the Xlib manual...

Ah, thanks anyway. :-)

using _NET_WM_ACTIVE_WINDOW could be interesting, though I don't know much about it...

http://standards.freedesktop.org/wm-spec/latest/ar01s03.html#id2759547

The problem is it will only for EWMH-compliant window managers.

richardgv commented 12 years ago

Oops, sorry, I made two mistakes in the replies above:

  1. compton is doing the correct thing: it is not caring about CreateNotify if the parent window is not root window. I didn't understand the event mask correctly.
  2. I said "because I'm just too familiar with tiling window managers" in the next-to-last reply, when I actually meant "I'm just too unfamiliar".

@daBrado:

I merged your debugging code into richardgv-dev branch as a0b0ff5d0a. (But written in a more brief way with help from macros.) Thanks. :-) As for the focus event validation change, I will evaluate that tomorrow.

daBrado commented 12 years ago

@richardgv

I merged your debugging code into richardgv-dev branch as a0b0ff5. (But written in a more brief way with help from macros.) Thanks. :-)

You're welcome. I like the macro! :)

As for the focus event validation change, I will evaluate that tomorrow.

Sounds good. Thanks for your effort!

richardgv commented 12 years ago

@daBrado:

Unfortunately, daBrado, the problem is possibly more elaborate that what I initially thought. (And I guess it's beyond your expectation, too.) In essence, I believe i3 has some faults in design, and it could give people the impression that there's a problem in compton's focus detection sometimes. I've added an entry in FAQ explaining why transparency in i3 is broken: https://github.com/chjj/compton/wiki/faq#wiki-_why_transparency_does_not_work_correctly_in_i3

If you really need something like inactive opacity, you could try --inactive-dim, which should not be affected by the design faults in i3.

There could be some issues in how compton detects focus, but within my own test, (NotifyNonlinear == ev->detail || NotifyNonlinearVirtual == ev->detail) does detect focus correctly in i3. I don't see i3 emitting any NotifyVirtual events, and i3 is wrapping each application window into a frame window as a direct children of the root window, as far as I can see, so NotifyVirtual events shouldn't be a concern at all.

I found some code from various WMs that handles FocusIn/Out events (ion-3, wmii, and dwm), but they are filtering FocusIn/Out events in different ways, and I got totally lost. I pushed a commit that changes the filter to (NotifyNonlinear == ev->detail || NotifyNonlinearVirtual == ev->detail) to richardgv-dev branch eventually, after did some tests with fvwm, Openbox, and i3. But the filter may not work as expected, and we need to watch for feedbacks. I hope you could test how the new filter works.

There's indeed a bug in --mark-ovredir-focused that I discovered, but I guess you are not using that, right?

daBrado commented 12 years ago

Oh... that's too bad that i3 seems to be doing weird things... is there anything that can be a bug report for them? I'm not using title bars so perhaps that is why I wasn't noticing some of the things mentioned in the FAQ...

I tried the richardgv-dev branch, and indeed changing window focus seems to track correctly, and there is no flicker while using function keys!

However, the reason I had the NotifyVirtual check was due to events being sent while trying to focus a window after focusing the parent container.

For example, if I open a couple windows, hit mod-a to focus the parent container, then the focused window loses focus but remains opaque. Then, if I, say, use the mouse to select a transparent window, it gains focus, but remains transparent. In these cases a NotifyVirtual event is being sent. If I allow those as well, the foucs tracks. Though that also results in transparency changes while using function keys (which perhaps is technically correct, as key events are no longer going to the "focused" window for that moment). That is why I restriced the types of events to NotifyNormal and NotifyWhileGrabbed, as then it ignored focus changes due to use of the function keys.

I don't know how generally useful that information is, and/or if it the result of some weirdness in i3.

(Perhaps it would be good for me to find a different tiling window manager, hah... I like the manual splitting, though I'm not yet convinced by the containment heirarchy, at least the way I've been using it so far.)

Oh, and no, I was not using --mark-ovredir-focused.

richardgv commented 12 years ago

@daBrado:

Oh... that's too bad that i3 seems to be doing weird things... is there anything that can be a bug report for them?

Apparently they didn't consider a thing called transparency in the design process... You could ask them to draw the titlebar in the way other window managers do (wrap the titlebar window and the application window into a single frame window and stop trying to combine titlebars of two windows). But as this is a design issue I doubt if they will come with a fix any time soon.

I'm not using title bars so perhaps that is why I wasn't noticing some of the things mentioned in the FAQ...

It does not sound too sane, but from my observation, i3 is creating title bar windows even when you turn title bar off... It just resizes the application window slightly larger to hide the titlebar window underneath when you have border none.

However, the reason I had the NotifyVirtual check was due to events being sent while trying to focus a window after focusing the parent container.

For example, if I open a couple windows, hit mod-a to focus the parent container, then the focused window loses focus but remains opaque. Then, if I, say, use the mouse to select a transparent window, it gains focus, but remains transparent. In these cases a NotifyVirtual event is being sent. If I allow those as well, the foucs tracks. Though that also results in transparency changes while using function keys (which perhaps is technically correct, as key events are no longer going to the "focused" window for that moment). That is why I restriced the types of events to NotifyNormal and NotifyWhileGrabbed, as then it ignored focus changes due to use of the function keys.

Now, another... Interesting thing happens. When I focus the parent container with mod+a in i3, I see the actual focused window is the title bar window (which is created even if you turn title bar off, as indicated above) under all those application windows... XGetInputFocus() and _NET_ACTIVE_WINDOW both reports the focused window is the title bar window.

i3 isn't wrapping the windows in the way it appears to. There's not a window of "parent container". As what I've said in the last reply, "i3 is wrapping each application window into a frame window as a direct children of the root window, as far as I can see". So probably i3 is trying to use the titlebar window as a replacement of a "parent container" window... Albeit an awkward replacement at least from the viewpoint of compton.

I did try to let compton listen to NotifyVirtual (although I don't think it makes sense), and that changes nothing, in my test. I suspect the things you saw are caused by the fact the broken part of the titlebar window happens to contain some content that has some particular look. Please try setting -i/--inactive-dim to some extreme values (like, -i 0.1 or --inactive-dim 0.9), and maybe you will spot what's wrong.

So, when you use --inactive-dim in compton, and focus a "parent container" in i3, the expected behavior is all application windows are dimmed because they are not focused (and the actually focused title bar window is hidden under those application windows.). When you use -i in compton with i3 (or when you have any transparent / ARGB window), you will generally see things breaking down (or things appear working but actually is broken). Sorry, but as far as I know, only i3 could provide a sensible cure, and this is beyond our ability.

And I'm using i3-4.3, default configuration.

By the way, I plan to add _NET_ACTIVE_WINDOW support to compton, but I believe this will not help for any of the problems in i3.

richardgv commented 12 years ago

@daBrado:

Please firstly read my last reply above.

I've pushed EWHM _NET_ACTIVE_WINDOW support to richardgv-dev branch (read the commit log for how to enable it). But as expected, it provided no help for those i3 issues. I would like somebody to test for bugs, though.