Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic Status Bars support for XMonad.Hooks.StatusBar #463

Merged
merged 2 commits into from
May 28, 2021

Conversation

TheMC47
Copy link
Member

@TheMC47 TheMC47 commented Feb 7, 2021

Description

This provides dynamic status bars, that react to screen configuration changes. This needs the new interface from #443 and the splitting from #465, so I'm marking the PR as a draft till that's resolved.

Heavily inspired by "XMonad.Hooks.DynamicBars"

Checklist

  • I've read CONTRIBUTING.md

  • I tested my changes with xmonad-testing

  • I updated the CHANGES.md file

  • I updated the XMonad.Doc.Extending file (if appropriate)

@TheMC47 TheMC47 marked this pull request as draft February 7, 2021 19:51
Copy link
Member

@liskin liskin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First glance: nice. I love the simplicity of the user interface. I'll need to take a closer look at the internals later.

XMonad/Hooks/DynamicStatusBarConfigs.hs Outdated Show resolved Hide resolved
XMonad/Hooks/DynamicStatusBarConfigs.hs Outdated Show resolved Hide resolved
*> cleanAll
*> updateSBs f
, logHook = logHook conf *> logSBs
, handleEventHook = eventHookSBs f <> handleEventHook conf
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably won't interact well with #460. :-/
And that's partly my fault, as my Rescreen module doesn't compose very well. On the other hand it abstracts away the peculiarities of the X server sending multiple Configure and RRScreenChangeNotify events in a strange order. We'll need to think about this some more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could maybe synthesize the RRScreenChangeNotify event that was discarded by Rescreen and explicitly invoke handleEventHook on it. It's a horrible hack, though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only took that event because it was the one used in DynamicBars, but I don't really know if it's the best choice...

What's the problem here?

Copy link
Member

@liskin liskin Feb 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that my X.H.Rescreen module completely replaces xmonad's handling of Configure and RRScreenChangeNotify events in a way that doesn't compose well with other hooks (prevents other hooks from seeing all the events, prevents xmonad core from handling any of the events). It needs to do this because the X server sends several such events on every xrandr change, so

  1. if one wants to attach a hook that restarts something (bars that don't reposition themselves, for example), the events need to be debounced for the hook to be invoked only once
  2. if one wants to attach two different hooks, one for actual screen layout reconfiguration, another for just connect/disconnect of outputs, we need to look at all the events to detect which of the two situations it was

If this went into the core with two additional hooks in XConfig, everything would then compose nicely, but the xmonad philosophy (as I see it) has always been to keep the core minimal and try to do as much as possible in optional contrib modules. It usually works well, it just sometimes gets awkward if contrib modules interact/overlap as we never know if the user will use one, the other, or both.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I follow, don't all event handlers that are composed with <> see the same events? I think the All False will only prevent the xmonad default handler from being dispatched, and it doesn't affect the other events right?

Copy link
Member

@liskin liskin Feb 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All events handlers do see the same events, but X.H.Rescreen looks into the X event queue directly and discards duplicate events, so other hooks only see the first Configure or RRScreenChangeNotify event, whichever comes first, and all the other events are discarded. I should probably explain this more clearly in the documentation there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright that makes sense now

Well, I guess we should export the event handler (and the other hooks) from this module and explain how to make it work with X.H.Rescreen (Adding it to the RescreenConfig, and manually add the startup hook). I'm not sure that calling the handleEvent on it manually is a good idea

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@liskin so what should we do here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing for now. :-)

I got an idea that might improve composability of stuff like this (something like extensible state, just for XConfig, an "extensible config"). But I'd like to finish other stuff first, so let's not worry about the interaction here and deal with it later. I don't really need X.H.Rescreen in my config, auto-xrandr is more trouble than it's worth, so I'll just try using your code and see how it behaves. (But I won't get to it sooner than end of this week.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not at all urgent, so take your time!

XMonad/Hooks/DynamicStatusBarConfigs.hs Outdated Show resolved Hide resolved
XMonad/Hooks/DynamicStatusBarConfigs.hs Outdated Show resolved Hide resolved
XMonad/Hooks/DynamicStatusBarConfigs.hs Outdated Show resolved Hide resolved
CHANGES.md Outdated Show resolved Hide resolved
@TheMC47 TheMC47 mentioned this pull request Feb 12, 2021
4 tasks
@TheMC47 TheMC47 force-pushed the dynamic-status-bar-configs branch from 1174e81 to 68b72b0 Compare February 27, 2021 18:04
@TheMC47 TheMC47 changed the title New Module: "XMonad.Hooks.DynamicStatusBarConfigs" Dynamic Status Bars support for XMonad.Hooks.StatusBar Feb 27, 2021
@TheMC47 TheMC47 force-pushed the dynamic-status-bar-configs branch 2 times, most recently from 8b91e49 to cb0a409 Compare March 21, 2021 17:40
@TheMC47 TheMC47 added this to the v0.17 milestone Mar 26, 2021
@TheMC47 TheMC47 force-pushed the dynamic-status-bar-configs branch 3 times, most recently from ae38e7f to 2e6687d Compare April 2, 2021 22:10
@TheMC47 TheMC47 marked this pull request as ready for review April 2, 2021 22:17
@TheMC47 TheMC47 force-pushed the dynamic-status-bar-configs branch 2 times, most recently from 1d3ae60 to bcf376c Compare April 5, 2021 17:11
@TheMC47
Copy link
Member Author

TheMC47 commented May 1, 2021

Alright, I've been using this for a couple of months now, and it's been working great. Except for a minor issue: sometimes, some bars don't get started. Not sure why, it doesn't seem like a problem with the code itself.
Here are the logs from restarting xmonad. For the record, I restarted it like 5 times in a row to get it misbehaving.

XMonad will use build script at "/home/yecinem/.xmonad/build" to recompile.
XMonad recompilation process exited with success!
XMonad is recompiling and replacing itself with another XMonad process because the current process is called "xmonad" but the compiled configuration should be called "xmonad-x86_64-linux"
XMonad will use build script at "/home/yecinem/.xmonad/build" to recompile.
XMonad recompilation process exited with success!
xxmmoobbaarr::  CCaauugghhtt  ssiiggnnaall  1155;;  eexxiittiinngg......

xmonad-x86_64-linux: failed to create OS thread: Resource temporarily unavailable
Bad _NET_DESKTOP with data[0]=-1
Bad _NET_DESKTOP with data[0]=-1
Bad _NET_DESKTOP with data[0]=-1

@TheMC47 TheMC47 force-pushed the dynamic-status-bar-configs branch from bcf376c to 073a3ae Compare May 1, 2021 12:44
@TheMC47
Copy link
Member Author

TheMC47 commented May 2, 2021

Alright, I've been using this for a couple of months now, and it's been working great. Except for a minor issue: sometimes, some bars don't get started. Not sure why, it doesn't seem like a problem with the code itself.
Here are the logs from restarting xmonad. For the record, I restarted it like 5 times in a row to get it misbehaving.

XMonad will use build script at "/home/yecinem/.xmonad/build" to recompile.
XMonad recompilation process exited with success!
XMonad is recompiling and replacing itself with another XMonad process because the current process is called "xmonad" but the compiled configuration should be called "xmonad-x86_64-linux"
XMonad will use build script at "/home/yecinem/.xmonad/build" to recompile.
XMonad recompilation process exited with success!
xxmmoobbaarr::  CCaauugghhtt  ssiiggnnaall  1155;;  eexxiittiinngg......

xmonad-x86_64-linux: failed to create OS thread: Resource temporarily unavailable
Bad _NET_DESKTOP with data[0]=-1
Bad _NET_DESKTOP with data[0]=-1
Bad _NET_DESKTOP with data[0]=-1

As we discussed on the IRC, this was because of -rtsopts -with-rtsopts=-N

@oogeek
Copy link
Contributor

oogeek commented May 2, 2021

Overall it looks good. But I have a issue here.
Use-case example:

Two monitors:
laptop 1920x1080 
2K display 2560x1440 (external)

And set external monitor to be primary.
Then in the definition of barspawner:

barSpawner :: ScreenId -> IO StatusBarConfig
barSpawner 0 = pure xmobar0  
barSpawner 1 = pure xmobar1
barSpawner _ = Data.Monoid.mempty -- nothing on the rest of the screens

xmobar0 is used for external display.
But after unplugging the external display, the primary display becomes the laptop. But xmobar0 is for external display.

@TheMC47
Copy link
Member Author

TheMC47 commented May 2, 2021

Thanks for your feedback! For your use case, I think this is out of the scope of this PR (and I guess of xmonad? not sure). We can't control which id is given to which screen. But maybe I'm wrong, I know very little about X.

@oogeek
Copy link
Contributor

oogeek commented May 2, 2021

Thanks for your feedback! For your use case, I think this is out of the scope of this PR (and I guess of xmonad? not sure). We can't control which id is given to which screen. But maybe I'm wrong, I know very little about X.

So I think for my use-case, I need to do a bit of hack. Let me see. :)

Copy link
Member

@slotThe slotThe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks cool 👍

I'll play around with the actual functionality a bit more in the coming days

XMonad/Hooks/StatusBar.hs Outdated Show resolved Hide resolved
XMonad/Hooks/StatusBar.hs Outdated Show resolved Hide resolved
XMonad/Hooks/StatusBar.hs Show resolved Hide resolved
XMonad/Hooks/StatusBar.hs Outdated Show resolved Hide resolved
@TheMC47 TheMC47 force-pushed the dynamic-status-bar-configs branch from 073a3ae to 751e440 Compare May 2, 2021 22:38
@slotThe slotThe mentioned this pull request May 4, 2021
3 tasks
liskin added a commit to liskin/xmonad-contrib that referenced this pull request May 17, 2021
It's often difficult to make contrib modules work together. When one
depends on a functionality of another, it is often necessary to expose
lots of low-level functions and hooks and have the user combine these
into a complex configuration that works. This is error-prone, and
arguably a bad UX in general.

This commit presents a simple solution to that problem inspired by
"extensible state": extensible config. It allows contrib modules to
store custom configuration values inside XConfig. This lets them create
custom hooks, ensure they hook into xmonad core only once, and possibly
other use cases I haven't thought of yet.

This requires changes to xmonad core: xmonad/xmonad#294

A couple examples of what this gives us:

* [X.H.RescreenHook](xmonad#460)
  can be made safe to apply multiple times, making it composable and
  usable in other contrib modules like X.H.StatusBar

* `withSB` from X.H.StatusBar can also be made safe to apply multiple
  times, and we can even provide an API [similar to what we had
  before](https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-DynamicLog.html#v:statusBar)
  if we want (probably not, consistency with the new dynamic status bars
  of xmonad#463 is more important)

* The [X.H.EwmhDesktops refactor](xmonad#399)
  can possibly be made without breaking the `ewmh`/`ewmhFullscreen` API.
  And we will finally be able to have composable EWMH hooks.

Related: xmonad/xmonad#294
liskin added a commit to liskin/xmonad-contrib that referenced this pull request May 17, 2021
It's often difficult to make contrib modules work together. When one
depends on a functionality of another, it is often necessary to expose
lots of low-level functions and hooks and have the user combine these
into a complex configuration that works. This is error-prone, and
arguably a bad UX in general.

This commit presents a simple solution to that problem inspired by
"extensible state": extensible config. It allows contrib modules to
store custom configuration values inside XConfig. This lets them create
custom hooks, ensure they hook into xmonad core only once, and possibly
other use cases I haven't thought of yet.

This requires changes to xmonad core: xmonad/xmonad#294

A couple examples of what this gives us:

* [X.H.RescreenHook](xmonad#460)
  can be made safe to apply multiple times, making it composable and
  usable in other contrib modules like X.H.StatusBar

* `withSB` from X.H.StatusBar can also be made safe to apply multiple
  times, and we can even provide an API [similar to what we had
  before](https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-DynamicLog.html#v:statusBar)
  if we want (probably not, consistency with the new dynamic status bars
  of xmonad#463 is more important)

* The [X.H.EwmhDesktops refactor](xmonad#399)
  can possibly be made without breaking the `ewmh`/`ewmhFullscreen` API.
  And we will finally be able to have composable EWMH hooks.

Related: xmonad/xmonad#294
@TheMC47 TheMC47 force-pushed the dynamic-status-bar-configs branch from 6043ae8 to ca21c3f Compare May 21, 2021 09:48
liskin added a commit to liskin/xmonad-contrib that referenced this pull request May 21, 2021
It's often difficult to make contrib modules work together. When one
depends on a functionality of another, it is often necessary to expose
lots of low-level functions and hooks and have the user combine these
into a complex configuration that works. This is error-prone, and
arguably a bad UX in general.

This commit presents a simple solution to that problem inspired by
"extensible state": extensible config. It allows contrib modules to
store custom configuration values inside XConfig. This lets them create
custom hooks, ensure they hook into xmonad core only once, and possibly
other use cases I haven't thought of yet.

This requires changes to xmonad core: xmonad/xmonad#294

A couple examples of what this gives us:

* [X.H.RescreenHook](xmonad#460)
  can be made safe to apply multiple times, making it composable and
  usable in other contrib modules like X.H.StatusBar

* `withSB` from X.H.StatusBar can also be made safe to apply multiple
  times, and we can even provide an API [similar to what we had
  before](https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-DynamicLog.html#v:statusBar)
  if we want (probably not, consistency with the new dynamic status bars
  of xmonad#463 is more important)

* The [X.H.EwmhDesktops refactor](xmonad#399)
  can possibly be made without breaking the `ewmh`/`ewmhFullscreen` API.
  And we will finally be able to have composable EWMH hooks.

Related: xmonad/xmonad#294
@TheMC47
Copy link
Member Author

TheMC47 commented May 28, 2021

As we spoke in the IRC, I mentioned that the commands themselves are used to keep track of what's launched. If someone could give it a proof read, we can merge this tonight 🎉

XMonad/Hooks/StatusBar.hs Outdated Show resolved Hide resolved
XMonad/Hooks/StatusBar.hs Outdated Show resolved Hide resolved
XMonad/Hooks/StatusBar.hs Outdated Show resolved Hide resolved
Copy link
Member

@liskin liskin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No further suggestions :-)

TheMC47 added 2 commits May 28, 2021 18:47
command specific

- The names were awfully long. spawnStatusBar and killStatusBar are
perfectly fine alternatives.
- It's more flexible to have killStatusBar command specific. Also added
killAllStatusBars to provide the old functionality
This is heavily inspired by "XMonad.Hooks.DynamicBars", but it can be
used with any status-bar.
@TheMC47 TheMC47 force-pushed the dynamic-status-bar-configs branch from 101a18f to d2f3a8d Compare May 28, 2021 16:48
@TheMC47 TheMC47 merged commit 5c73845 into xmonad:master May 28, 2021
liskin added a commit to liskin/xmonad-contrib that referenced this pull request Jun 1, 2021
It's often difficult to make contrib modules work together. When one
depends on a functionality of another, it is often necessary to expose
lots of low-level functions and hooks and have the user combine these
into a complex configuration that works. This is error-prone, and
arguably a bad UX in general.

This commit presents a simple solution to that problem inspired by
"extensible state": extensible config. It allows contrib modules to
store custom configuration values inside XConfig. This lets them create
custom hooks, ensure they hook into xmonad core only once, and possibly
other use cases I haven't thought of yet.

This requires changes to xmonad core: xmonad/xmonad#294

A couple examples of what this gives us:

* [X.H.RescreenHook](xmonad#460)
  can be made safe to apply multiple times, making it composable and
  usable in other contrib modules like X.H.StatusBar

* `withSB` from X.H.StatusBar can also be made safe to apply multiple
  times, and we can even provide an API [similar to what we had
  before](https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-DynamicLog.html#v:statusBar)
  if we want (probably not, consistency with the new dynamic status bars
  of xmonad#463 is more important)

* The [X.H.EwmhDesktops refactor](xmonad#399)
  can possibly be made without breaking the `ewmh`/`ewmhFullscreen` API.
  And we will finally be able to have composable EWMH hooks.

Related: xmonad/xmonad#294
liskin added a commit to liskin/xmonad-contrib that referenced this pull request Jun 3, 2021
`statusBarGeneric`: A generic `StatusBarConfig` that launches a status
bar but takes a generic `X ()` logging function instead of a `PP`. This
has several uses:

 * With `xmonadPropLog` or `xmonadPropLog'` in the logging function, a
   custom non-`PP`-based logger can be used for logging into an `xmobar`.

 * With `mempty` as the logging function, it's possible to manage a status
   bar that reads information from EWMH properties like `taffybar`.

 * With `mempty` as the logging function, any other dock like `trayer` or
   `stalonetray` can be managed by this module.

Related: xmonad#463
slotThe pushed a commit to oogeek/xmonad-contrib that referenced this pull request Jun 10, 2021
This is a function that takes a pretty-printer and makes it aware of
copies of the currently focused window.  This is particularly nice when
using it with a StatusBarConfig.

Related: xmonad#463
@TheMC47 TheMC47 deleted the dynamic-status-bar-configs branch January 1, 2022 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants