bakkeby / dwm-flexipatch

A dwm build with preprocessor directives to decide which patches to include during build time
MIT License
1.18k stars 238 forks source link

focused window on top #56

Closed chhajedji closed 4 years ago

chhajedji commented 4 years ago

Hi, This is not exactly an issue but an inquiry or a feature request.

Is there a way I can put focused window on top of other windows? This is useful when I have some floating windows and some tilled windows. For example if there's 1 floating window and 1 tilled window, then floating window is always on top, irrespective of what window I am focused on. Although this is not the case with multiple floating windows. In that case, focused window is always on top.

Please help how can I overcome this issue. Thanks.

bakkeby commented 4 years ago

Hi @chhajedji,

that floating windows are fully displayed on top of tiled windows is an intentional design choice I believe, but this is fairly straightforward to change actually.

This is the default focus function:

void
focus(Client *c)
{
    if (!c || !ISVISIBLE(c))
        for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
    if (selmon->sel && selmon->sel != c)
        unfocus(selmon->sel, 0);
    if (c) {
        if (c->mon != selmon)
            selmon = c->mon;
        if (c->isurgent)
            seturgent(c, 0);
        detachstack(c);
        attachstack(c);
        grabbuttons(c, 1);
        XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
        setfocus(c);
    } else {
        XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
        XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
    }
    selmon->sel = c;
    drawbars();
}

after setfocus(c); the only thing you need to add is a line

XRaiseWindow(dpy, c->win);

and you have the behaviour you ask for.

The caveat with this is that the floating window can end up being completely below other tiled windows and can be slightly more complicated to get to.

Alternatively you can make the floating windows pop straight up afterwards by explicitly raising floating windows beforehand.

        Client *f;
        for (f = c->mon->stack; f; f = f->snext)
            if (f != c && ISVISIBLE(f) && f->isfloating)
                XRaiseWindow(dpy, f->win);
        XRaiseWindow(dpy, c->win);

(in principle the for loop could also be in the unfocus function, but it's probably just fine to keep these together)

This feels unfamiliar to me, but seems to work well.

Now if you use scratchpads then you may want to keep those on top despite a tiled window below having focus.

bakkeby commented 4 years ago

I should add that this do interfere with dialog boxes, etc., so one should likely look for a way to keep transient windows, dialog boxes, toolbars, splash and utility windows on top.

chhajedji commented 4 years ago

Hi @bakkeby,

I tried adding XRaiseWindow(dpy, c->win) inside focus() as you suggested, but still behavior remains same as earlier. I understand all the caveats coming with this changes. This feature is actually handy for me and I used to use it with i3wm. I think there it's the default behavior.

Also I am not familiar with the dwm code. So can you tell where do you suggest to add second snippet?

bakkeby commented 4 years ago

Hi @chhajedji,

the second snippet would be in place of the first snippet, so you would end up with something like

void
focus(Client *c)
{
    Client *f;
    if (!c || !ISVISIBLE(c))
        for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
    if (selmon->sel && selmon->sel != c)
        unfocus(selmon->sel, 0);
    if (c) {
        if (c->mon != selmon)
            selmon = c->mon;
        if (c->isurgent)
            seturgent(c, 0);
        detachstack(c);
        attachstack(c);
        grabbuttons(c, 1);
        XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
        setfocus(c);
        for (f = c->mon->stack; f; f = f->snext)
            if (f != c && ISVISIBLE(f) && f->isfloating)
                XRaiseWindow(dpy, f->win);
        XRaiseWindow(dpy, c->win);
    } else {
        XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
        XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
    }
    selmon->sel = c;
    drawbars();
}

I was playing around with this yesterday and there are many flaws doing it like this. I got it to a pretty workable state, but that involves having to mark certain windows to always be displayed on top (primarily dialog boxes and the like, but also browser pop-ups).

Without that it becomes pretty much unusable with a Save As dialog disappearing beneath the main window simply because you moved your mouse.

I may be able to provide a more complete solution. Do you use dwm-flexipatch or are you more looking for a standalone patch on top of dwm 6.2?

chhajedji commented 4 years ago

Hi,

I use some patches from dwm-flexipatch but all standalone. It would be better if you can give a standalone patch for this also. Yes you are right, many handy pop ups might disappear just because of casual mouse slip. That's why I am not very rigid about this feature.

--

Regards, Chinmay Chhajed


From: Stein Gunnar Bakkeby notifications@github.com Sent: Thursday, October 8, 2020 2:33 PM To: bakkeby/dwm-flexipatch dwm-flexipatch@noreply.github.com Cc: Chinmay Chhajed chinmay.chhajed@espressif.com; Mention mention@noreply.github.com Subject: Re: [bakkeby/dwm-flexipatch] focused window on top (#56)

[External: This email originated outside Espressif]

Hi @chhajedjihttps://github.com/chhajedji,

the second snippet would be in place of the first snippet, so you would end up with something like

void focus(Client c) { Client f; if (!c || !ISVISIBLE(c)) for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); if (selmon->sel && selmon->sel != c) unfocus(selmon->sel, 0); if (c) { if (c->mon != selmon) selmon = c->mon; if (c->isurgent) seturgent(c, 0); detachstack(c); attachstack(c); grabbuttons(c, 1); XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); setfocus(c); for (f = c->mon->stack; f; f = f->snext) if (f != c && ISVISIBLE(f) && f->isfloating) XRaiseWindow(dpy, f->win); XRaiseWindow(dpy, c->win); } else { XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); XDeleteProperty(dpy, root, netatom[NetActiveWindow]); } selmon->sel = c; drawbars(); }

I was playing around with this yesterday and there are many flaws doing it like this. I got it to a pretty workable state, but that involves having to mark certain windows to always be displayed on top (primarily dialog boxes and the like, but also browser pop-ups).

Without that it becomes pretty much unusable with a Save As dialog disappearing beneath the main window simply because you moved your mouse.

I may be able to provide a more complete solution. Do you use dwm-flexipatch or are you more looking for a standalone patch on top of dwm 6.2?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/bakkeby/dwm-flexipatch/issues/56#issuecomment-705434530, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AKF4R5AWVR5YTBW4STFKHA3SJV55RANCNFSM4SHHMAEA.

bakkeby commented 4 years ago

Hi @chhajedji,

could you try out this patch dwm-focusedontop-6.2_full.diff?

It might need some further polishing, but should be a good starting point I'd think.

It's a combination of three patches, the two first are primarily there to have more control over which clients can be marked as being always on top.

\ Thanks,

-Stein

chhajedji commented 4 years ago

Hi @bakkeby,

This patch works fine most of the time, but sometimes it is misbehaving. For example as you can see in screenshot, some floating windows which are by default floating only, like pop ups for bluetooth, notifications etc are not coming on top when focused even though alwaysontop for firefox is set to 0. But yeah, on other hand for other floating windows it is working fine!

image

bakkeby commented 4 years ago

Yes setting alwaysontop to 0 just means that it is not always on top. As such you'd have to specifically set rules to say that the pop-ups for bluetooth, notifications etc. are alwaysontop = 1.

I'm considering checking for the _NET_WM_STATE_ABOVE window property and set that alwaysontop flag to true for any windows that has that set. That should hopefully sort out a few cases automatically.

bakkeby commented 4 years ago

Hi @chhajedji,

alright, I added some code for checking for the _NET_WM_STATE_ABOVE window property, but I am not entirely sure if that works as intended.

I was checking notification windows through Dunst and I found that these notifications are not handled as clients within dwm which means that one has no direct control over them as far as I can see.

So to avoid explicitly placing the currently focused window on top of everything else I came up with a different strategy for raising and lowering windows.

Could you try out the latest version of this patch and see if that sorts out a few of the issues you have observed?

\ Thanks,

-Stein

chhajedji commented 4 years ago

Hey @bakkeby

Thanks for this patch, it works for me, dunst notifications were also visible over other floating window. One issue I observed is I cannot see my clickable icons in my dwmbar. Icons for nm-applet, parcellite and all other apps have disappeared as seen in previous screenshot. Ideally they are present there in bottom right corner in my config as shown below. Other than this, this patch works fine I guess.

image

bakkeby commented 4 years ago

So the systray itself is presumably below the bar, hmm.

bakkeby commented 4 years ago

@chhajedji you say dwmbar, is that a standalone application? or do you use the built-in bar in dwm + the systray patch?

chhajedji commented 4 years ago

I use xsetroot to set bar with the systray patch.

bakkeby commented 4 years ago

Hi @chhajedji,

do you have a branch running with the focusedontop patch on your build?

I had a look at your https://github.com/chhajedji/dwm, but didn't spot it there. I am not entirely sure why systray icons would disappear with this patch. Would like to have a closer look though.

\ Thanks,

-Stein

chhajedji commented 4 years ago

HI @bakkeby I have pushed my dwm built with focusedontop patch. You can checkout this commit.

bakkeby commented 4 years ago

Hi @chhajedji,

I had a play around, but I couldn't get the systray to disappear - do you need to do anything special to make that happen?

One observation is that this is the traditional systray patch which resizes the bar to give room for the systray, while in the screenshot the bar goes to the far right. You don't use systraypinning and it is also not possible to toggle systray on and off as it is a const in config.h. As far as I can see the systray window itself should exist as otherwise I'd expect dwm to crash when trying to get the width of the systray.

It could be that the last systray icon to start crashed somehow and the remaining icons are no longer reachable, but that's just speculation on my part.

\ Thanks,

-Stein

chhajedji commented 4 years ago

@bakkeby ,

I don't know if anything is crashing. Generally I have nm-applet, parcellite and occasionally Microsoft Teams and blueman icon in my systray. But all of them seems to be working modules on restarting dwm. Also without focusedontop patch, if I press CTRL+MOD+r (keybinding to call quit(1) to restart dwm), I can see all icons. Just an FYI, this is my start up script which runs when starting a new session or restarting dwm.

On another note, if this is taking much of your time, you can close this issue as it was something which I thought it could be present and I am missing. And since I am following you for some time, I thought if anyone knows, it could be you. Hence raised an issue here. It was more of an inquiry, rather than an issue! :smiley:

bakkeby commented 4 years ago

One thing you can try is in the unmapnotify function (search for KLUDGE) add a call to removesystrayicon(c);.

void
unmapnotify(XEvent *e)
{
    Client *c;
    XUnmapEvent *ev = &e->xunmap;

    if ((c = wintoclient(ev->window))) {
        if (ev->send_event)
            setclientstate(c, WithdrawnState);
        else
            unmanage(c, 0);
    }
    else if ((c = wintosystrayicon(ev->window))) {
        /* KLUDGE! sometimes icons occasionally unmap their windows, but do
         * _not_ destroy them. We map those windows back */
        XMapRaised(dpy, c->win);
        removesystrayicon(c); // <--- try adding this
        updatesystray();
    }
}

I don't remember the exact reason for adding that, but I think it was a fix for icons disappearing and not showing up again.

chhajedji commented 4 years ago

Still same, icons are gone.

bakkeby commented 4 years ago

Can you try it without running your dwmbar?

chhajedji commented 4 years ago

Without dwmbar running also same result.

--

Thanks, Chinmay Chhajed


From: Stein Gunnar Bakkeby notifications@github.com Sent: Tuesday, October 20, 2020 3:06 PM To: bakkeby/dwm-flexipatch dwm-flexipatch@noreply.github.com Cc: Chinmay Chhajed chinmay.chhajed@espressif.com; Mention mention@noreply.github.com Subject: Re: [bakkeby/dwm-flexipatch] focused window on top (#56)

[External: This email originated outside Espressif]

Can you try it without running your dwmbar?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/bakkeby/dwm-flexipatch/issues/56#issuecomment-712725015, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AKF4R5CF76FPKWXKAKDKKILSLVKYXANCNFSM4SHHMAEA.

bakkeby commented 4 years ago

Oh right, I see what you mean. The icons appear when you restart dwm using MOD+Ctrl+r, I'll get back to you.

bakkeby commented 4 years ago

Hi @chhajedji,

worked it out, delete the XSync(dpy, True); line in the focus function.

This was something that was needed for earlier versions of this patch as you could get into an issue where two floating windows would complete for the focus and flood the event queue with enter notify requests (and that line ensured to clear the queue). This line had the side effect of clearing notifications relating to systray icons, hence these would silently disappear when doing a restart.

It looks like the latest approach for handling focused window on top doesn't run into that issue of windows competing for focus, so the line is no longer needed. Do let me know if you spot anything like that though.

\ Thanks,

-Stein

chhajedji commented 4 years ago

Oh finally, everything seems to be perfect :tada: I can now finally see icons in bar and floating windows are also working pretty fine! Thanks for the help! Closing this issue now. :smiley: