diff options
40 files changed, 914 insertions, 314 deletions
diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml new file mode 100644 index 0000000..f67eda7 --- /dev/null +++ b/.forgejo/workflows/test.yml @@ -0,0 +1,32 @@ +on: + pull_request: + types: [opened, synchronize, reopened] + + push: + branches: + - 'master' + +jobs: + actions: + strategy: + matrix: + - version: [9.6, 9.4, 8] + + runs-on: docker + container: + image: haskell:${{ matrix.version }} + + steps: + - name: apt ${{ matrix.version }} + run: | + apt-get update + apt-get install -y xorg-dev libxrandr-dev libpango1.0-dev + apt-get install -y libasound2-dev libxpm-dev libmpd-dev + apt-get install -y hspec-discover hlint + - name: hlint ${{ matrix.version }} + run: hlint ./src + - name: cabal tests ${{ matrix.version }} + run: | + cabal update + cabal test --enable-tests -fall_extensions + cabal test --enable-tests -fall_extensions -f-with_xrender diff --git a/.woodpecker.yml b/.woodpecker.yml deleted file mode 100644 index f8aeae3..0000000 --- a/.woodpecker.yml +++ /dev/null @@ -1,20 +0,0 @@ -matrix: - GHC_VERSION: - - 9.6 - - 9.4 - - 8 - -steps: - test: - image: haskell:${GHC_VERSION} - commands: - - apt-get update - - apt-get install -y xorg-dev libxrandr-dev libpango1.0-dev - - apt-get install -y libasound2-dev libxpm-dev libmpd-dev - - apt-get install -y hspec-discover hlint - - - hlint src - - - cabal update - - cabal test --enable-tests -fall_extensions - - cabal test --enable-tests -fall_extensions -f-with_xrender diff --git a/changelog.md b/changelog.md index b7bfcfd..36f0c52 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,42 @@ +## Version 0.50 (unreleased) + +- New plugins: `PacmanUpdates` +- `ArchUpdates` deprecated in favor of `PacmanUpdates` + - a deprecation notice will be shown to users of that plugin in the bar in + the zero updates case + +## Version 0.49 (April, 2025) + +- New plugins: `ArchUpdates` and `Accordion` (thanks, Enrico Maria) +- New template variable `weatherS` for `WeatherX`. +- New Nix flake (thanks, refaelsh) +- `MPRIS`: Fix for duration reported by Spotify (thanks, Claudio) +- Base dep up to 4.20 (thanks, Alexander) + +## Version 0.48.1 (May, 2024) + +- Removing for now mouse support for `Kbd`, which can be recovered by + interested users using regular actions (see issue #703 for further details). + +## Version 0.48 (April, 2024) + +- The `Kbd` monitor is now clickable (thanks, Enrico Maria) +- Fix zombie processes left by `<action>` tag and low battery action (thanks, + Ulrik) +- Fix plugins such as `Alsa` and `Com` not working when configuration is + recompiled (#657, ditto) +- New `Lock'` monitor with configurable labels (thanks, Enrico Maria) + +## Version 0.47.4 (March, 2024) + +- Bug fixes (launching processes from self-compiled instances) + +## Version 0.47.3 (February, 2024) + +- New flag `with_shared` to use xmobar with dynamic linking (see PR #690) +- Fix for actions invoked from recompiled xmobar instances (issue #688) +- Maximum base version bumped to 4.20 + ## Version 0.47.2 (November, 2023) - Compatibility with GHC 9.6 diff --git a/doc/accordion.gif b/doc/accordion.gif Binary files differnew file mode 100644 index 0000000..c21d2b0 --- /dev/null +++ b/doc/accordion.gif diff --git a/doc/plugins.org b/doc/plugins.org index 2199659..6f474e1 100644 --- a/doc/plugins.org +++ b/doc/plugins.org @@ -16,11 +16,11 @@ to a certain monitor. All Monitors accept a common set of arguments, described below in - [[Default Monitor Arguments]]. Some monitors also accept additional + [[#default-arguments][Default Monitor Arguments]]. Some monitors also accept additional options that are specific to them. When specifying the list of arguments in your configuration, the common options come first, followed by =--=, followed by any monitor-specific options. For - example, the following [[=Battery Args RefreshRate=][Battery]] configuration first sets the global + example, the following [[#batteryp-dirs-args-refreshrate][Battery]] configuration first sets the global =template= and =Low= arguments and then specifies the battery-specific =off= option. @@ -60,6 +60,9 @@ brightness value. ** Default monitor arguments + :PROPERTIES: + :CUSTOM_ID: default-arguments + :END: These are the options available for all monitors: @@ -694,18 +697,37 @@ #+begin_src haskell Run Brightness ["-t", "<bar>"] 60 #+end_src + *** =Locks= - Displays the status of Caps Lock, Num Lock and Scroll Lock. - Aliases to =locks= + - Contructors: + + - =Locks= is nullary and uses the strings =CAPS=, =NUM=, =SCROLL= to signal + that a lock is enabled (and empty strings to signal it's disabled) + + - =Locks'= allow customizing the strings for the enabled/disabled states + of the 3 locks by accepting an assoc list of type =[(String, (String, String))]=, + which is expected to contain exactly 3 elements with keys + ="CAPS"=, ="NUM"=, ="SCROLL"=. + - Example: #+begin_src haskell + -- using default labels Run Locks #+end_src + #+begin_src haskell + -- using custom labels + Run $ Locks' [("CAPS" , ("<fc=#00ff00>\xf023</fc>", "<fc=#777777>\xf09c</fc>") ) + ,("NUM" , ("<fc=#777777>\xf047</fc>", "<fc=#00ff00>\xf047</fc>" ) ) + ,("SCROLL", ("SlOCK", "" ))] + #+end_src + ** Load and Process monitors *** =Load Args RefreshRate= @@ -814,6 +836,9 @@ ** Volume monitors *** =Volume Mixer Element Args RefreshRate= + :PROPERTIES: + :CUSTOM_ID: volume + :END: - Aliases to the mixer name and element name separated by a colon. Thus, =Volume "default" "Master" [] 10= can be used as @@ -889,7 +914,7 @@ *** =Alsa Mixer Element Args= - Like [[=Volume Mixer Element Args RefreshRate=][Volume]] but with the following differences: + Like [[#volume][Volume]] but with the following differences: - Uses event-based refreshing via =alsactl monitor= instead of polling, so it will refresh instantly when there's a volume change, and won't @@ -1243,9 +1268,11 @@ - Works in the same way as =Weather=, but takes an additional argument, a list of pairs from sky conditions to their replacement (typically a unicode string or an icon specification). - - Use the variable =skyConditionS= to display the replacement of the - corresponding sky condition. All other =Weather= template variables - are available as well. + - Use the variable =skyConditionS= or =weatherS= to display the replacement of + the corresponding sky condition. =weatherS= uses the string returned by + =weather= to look up a replacement, and, if that one is not found, it + looks up the value of =skyConditionS=. All other =Weather= template + variables are available as well. For example: @@ -1296,7 +1323,7 @@ #+begin_src haskell Run UVMeter "Brisbane" ["-H", "3", "-L", "3", "--low", "green", "--high", "red"] 900 #+end_src -** Other monitors +** Other monitors and plugins *** =CatInt n filename= - Reads and displays an integer from the file whose path is =filename= @@ -1326,6 +1353,59 @@ the display of those numeric fields. - Default template: =Up: <days>d <hours>h <minutes>m= +*** =PacmanUpdates (Zero, One, Many, Error) Rate= + + - Aliases to =pacman= + - =Zero=: a =String= to use when the system is up to date. + - =One=: a =String= to use when only one update is available. + - =Many=: a =String= to use when several updates are available; it can contain + a =?= character as a placeholder for the number of updates. + - =Error=: a =String= to use when pacman fails for unkown reasons (e.g. + network error) + - Example: + #+begin_src haskell + ArchUpdates ("<fc=green>up to date</fc>", + "<fc=yellow>1 update</fc>, + "<fc=red>? updates</fc>", + "<fc=red>!Pacman Error!</fc>") + 600 + #+end_src + +*** =ArchUpdates (Zero, One, Many) Rate= + + - *This plugin is deprecated. Use =PacmanUpdates= instead.* + - Aliases to =arch= + - Same As: + #+begin_src haskell + PacmanUpdates (Zero, + One, + Many, + "pacman: Unknown cause of failure.") + Rate + #+end_src + +*** =makeAccordion Tuning [Runnable]= + + - Wraps other =Runnable= plugins and makes them all collapsible to a single string: + + [[file:accordion.gif]] + + - Aliases to =alias' tuning=, being =tuning= of type =Tuning=, so one can use multiple such "accordions" + - **Disclaimer**: This only works for Haskell =xmobar.hs= + - =Tuning=: the "settings", for which a default value is provided, + #+begin_src haskell + defaultTuning = Tuning { + alias' = "accordion" + , initial = True + , expand = "<>" + , shrink = "><" + } + #+end_src + - =expand=: =String= shown when the accordion is contracted (defaults to ="<>"=). + - =shrink=: =String= shown when the accordion is expanded (defaults to ="><"=). + - =initial=: =Bool= to tell whether the accordion is initially expanded (defaults to =True=). + - =[Runnable]=: a list of =Runnable= plugins + * Interfacing with window managers :PROPERTIES: :CUSTOM_ID: interfacing-with-window-managers @@ -1355,6 +1435,9 @@ (re)start xmobar outside xmonad. *** =UnsafeXMonadLog= + :PROPERTIES: + :CUSTOM_ID: UnsafeXMonadLog + :END: - Aliases to UnsafeXMonadLog - Displays any text received by xmobar on the =_XMONAD_LOG= atom. @@ -1385,7 +1468,7 @@ - Aliases to =PropName= - Reads the X property named by =PropName= (a string) and displays its - value. The [[../etc/xmonadpropwrite.hs][etc/xmonadpropwrite.hs script]] in xmobar's distribution can be + value. The [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmonadpropwrite.hs][etc/xmonadpropwrite.hs script]] in xmobar's distribution can be used to set the given property from the output of any other program or script. @@ -1421,7 +1504,7 @@ - Aliases to UnsafeStdinReader - Displays any text received by xmobar on its standard input. - - Similar to [[=UnsafeXMonadLog=][UnsafeXMonadLog]], in the sense that it does not strip any + - Similar to [[#UnsafeXMonadLog][UnsafeXMonadLog]], in the sense that it does not strip any actions from the received text, only using =stdin= and not a property atom of the root window. Please be equally carefully when using this as when using =UnsafeXMonadLog=! @@ -1480,7 +1563,7 @@ =/tmp/xmobar_status= will reveal xmonad for 1.5 seconds and temporarily overwrite the window titles. - - Take a look at [[../etc/status.sh][etc/status.sh]] + - Take a look at [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/status.sh][etc/status.sh]] - Expands environment variables for the pipe path @@ -1547,8 +1630,6 @@ xmonad configuration (=xmonad.hs=), e.g. by using a custom =~/.xmonad/build= script. - - * Executing external commands In order to execute an external command you can either write the diff --git a/doc/quick-start.org b/doc/quick-start.org index 3f381fe..fecd953 100644 --- a/doc/quick-start.org +++ b/doc/quick-start.org @@ -1,10 +1,10 @@ #+title: Quick start: using xmobar -Xmobar can either be configured using the configuration language, or [[file:using-haskell.org][used as a +Xmobar can either be configured using the configuration language, or [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/using-haskell.org][used as a Haskell library]] (similar to xmonad) and compiled with your specific configuration. For an example of a configuration file using the plain -configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you can have a look at -[[../etc/xmobar.hs][etc/xmobar.hs]] for an example of how to write your own xmobar using Haskell. +configuration language, see [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.config][etc/xmobar.config]], and you can have a look at +[[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.hs][etc/xmobar.hs]] for an example of how to write your own xmobar using Haskell. * Command line options @@ -314,7 +314,7 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you *** Commands and monitors - =commands= The list of monitors and plugins to run, together with their - individual configurations. The [[./plugins.org][plugin documentation]] details all the + individual configurations. The [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/plugins.org][plugin documentation]] details all the available monitors, and you can also create new ones using Haskell. See the [[#commands-list][commands list section]] below for more. @@ -381,7 +381,7 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you will parse the template and search for the command to be executed in the =commands= configuration option. First an =alias= will be searched (some plugins, such as =Weather= or =Network=, have default - aliases, see the [[./plugins.org][plugin documentation]]). After that, the command + aliases, see the [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/plugins.org][plugin documentation]]). After that, the command name will be tried. If a command is found, the arguments specified in the =commands= list will be used. @@ -585,7 +585,7 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you Other options are ~Ansi~, ~Pango~, and ~Swaybar~. ** Showing xmobar output in Emacs tab or mode line Using xmobar's ANSI color text ouput, one can plug it inside Emacs, and - display your monitors in the mode line or the tab bar. The [[../etc/xmobar.el][xmobar.el + display your monitors in the mode line or the tab bar. The [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.el][xmobar.el package]] provides a simple way of doing it. ** Using xmobar in wayland with swaybar or waybar :PROPERTIES: @@ -629,7 +629,7 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you dynamically xmobar's size and run it alongside a system tray widget such as trayer or stalonetray (although the idea is not limited to trays, really). For your convenience, there is a version of Jonas' script in - [[../etc/padding-icon.sh][etc/padding-icon.sh]]. + [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/padding-icon.sh][etc/padding-icon.sh]]. ** Signal handling @@ -642,7 +642,7 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you * The DBus interface When compiled with the optional =with_dbus= flag, xmobar can be controlled - over dbus. All signals defined in [[../src/Xmobar/System/Signal.hs][src/Signal.hs]] as =data SignalType= can now + over dbus. All signals defined in [[https://codeberg.org/xmobar/xmobar/src/branch/master/src/Xmobar/System/Signal.hs][src/Signal.hs]] as =data SignalType= can now be sent over dbus to xmobar. Due to current limitations of the implementation only one process of xmobar diff --git a/doc/using-haskell.org b/doc/using-haskell.org index 33228c7..9fd3d88 100644 --- a/doc/using-haskell.org +++ b/doc/using-haskell.org @@ -49,6 +49,14 @@ system-wide xmobar, it will notice that you have your own implementation and (re)compile and run it as needed. +* Using dynamic linking + + Setting the =with_shared= flag, which is off by default, enables (re)building + of xmobar with shared libraries. By default, =xmobar= rebuilds itself with + static linking, as is the common practice with Haskell programs, but some + distributions use dynamic linking in their packages, or you might also be so + inclined. If so, this is your flag. + * Writing a plugin :PROPERTIES: :CUSTOM_ID: writing-a-plugin @@ -75,8 +83,8 @@ =run= can be used for simpler plugins. If you define only =run= the plugin will be run every second. To overwrite this default you just need to implement =rate=, which must return the number of tenth of seconds between - every successive runs. See [[../etc/xmobar.hs][etc/xmobar.hs]] for an example of a plugin - that runs just once, and [[../src/Xmobar/Plugins/Date.hs][src/Xmobar/Plugins/Date.hs]] for one that + every successive runs. See [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.hs][etc/xmobar.hs]] for an example of a plugin + that runs just once, and [[https://codeberg.org/xmobar/xmobar/src/branch/master/src/Xmobar/Plugins/Date.hs][src/Xmobar/Plugins/Date.hs]] for one that implements =rate=. Notice that Date could be implemented as: @@ -107,14 +115,14 @@ If your plugin only implements =alias= and =start=, then it is advisable to put it into the =Xmobar/Plugins/Monitors= directory and use one of the many - =run*= functions in [[../src/Xmobar/Plugins/Monitors/Common/Run.hs][Xmobar.Plugins.Monitors.Run]] in order to define - =start=. The =Exec= instance should then live in [[../src/Xmobar/Plugins/Monitors.hs][Xmobar.Plugins.Monitors]]. + =run*= functions in [[https://codeberg.org/xmobar/xmobar/src/branch/master/src/Xmobar/Plugins/Monitors/Common/Run.hs][Xmobar.Plugins.Monitors.Run]] in order to define + =start=. The =Exec= instance should then live in [[https://codeberg.org/xmobar/xmobar/src/branch/master/src/Xmobar/Plugins/Monitors.hs][Xmobar.Plugins.Monitors]]. * Using a plugin To use your new plugin, you just need to use a pure Haskell configuration for xmobar (as explained [[#xmobar-in-haskell][above]]) and load your definitions in your =xmobar.hs= - file. You can see an example in [[../etc/xmobar.hs][etc/xmobar.hs]] showing you how to write + file. You can see an example in [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.hs][etc/xmobar.hs]] showing you how to write a Haskell configuration that uses a new plugin, all in one file. When xmobar runs with the full path to that Haskell file as its argument diff --git a/flake.lock b/flake.lock deleted file mode 100644 index e60d10e..0000000 --- a/flake.lock +++ /dev/null @@ -1,75 +0,0 @@ -{ - "nodes": { - "flake-utils": { - "locked": { - "lastModified": 1653893745, - "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "git-ignore-nix": { - "inputs": { - "nixpkgs": "nixpkgs" - }, - "locked": { - "lastModified": 1646480205, - "narHash": "sha256-kekOlTlu45vuK2L9nq8iVN17V3sB0WWPqTTW3a2SQG0=", - "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "bff2832ec341cf30acb3a4d3e2e7f1f7b590116a", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "ref": "master", - "repo": "gitignore.nix", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1632846328, - "narHash": "sha256-sFi6YtlGK30TBB9o6CW7LG9mYHkgtKeWbSLAjjrNTX0=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "2b71ddd869ad592510553d09fe89c9709fa26b2b", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1654398695, - "narHash": "sha256-Kw/KeoFXszNsF5mORP45mrxCP+k9Aq03hWcuWCL9sdI=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "c5d810f4c74c824ae0fb788103003c6c9d366a08", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "root": { - "inputs": { - "flake-utils": "flake-utils", - "git-ignore-nix": "git-ignore-nix", - "nixpkgs": "nixpkgs_2" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 7471fb9..0000000 --- a/flake.nix +++ /dev/null @@ -1,45 +0,0 @@ -{ - inputs = { - git-ignore-nix.url = "github:hercules-ci/gitignore.nix/master"; - flake-utils.url = "github:numtide/flake-utils"; - }; - outputs = { self, nixpkgs, flake-utils, git-ignore-nix }: - let - overlay = final: prev: { - haskellPackages = prev.haskellPackages.override (old: { - overrides = prev.lib.composeExtensions (old.overrides or (_: _: { })) - (hself: hsuper: { - xmobar = prev.haskell.lib.compose.dontCheck (hself.callCabal2nix "xmobar" - (git-ignore-nix.lib.gitignoreSource ./.) { }); - }); - }); - }; - overlays = [ overlay ]; - in flake-utils.lib.eachDefaultSystem (system: - let pkgs = import nixpkgs { inherit system overlays; }; - dynamicLibraries = with pkgs; [ - xorg.libX11 - xorg.libXrandr - xorg.libXrender - xorg.libXScrnSaver - xorg.libXext - xorg.libXft - xorg.libXpm.out - xorg.libXrandr - xorg.libXrender - ]; - in rec { - devShell = pkgs.haskellPackages.shellFor { - packages = p: [ p.xmobar ]; - buildInputs = with pkgs; [ - haskellPackages.cabal-install - #haskellPackages.haskell-language-server - ] ++ dynamicLibraries; - - LD_LIBRARY_PATH = pkgs.lib.strings.makeLibraryPath dynamicLibraries; - }; - defaultPackage = pkgs.haskellPackages.xmobar; - }) // { - inherit overlay overlays; - }; -} diff --git a/nix/default.nix b/nix/default.nix new file mode 100644 index 0000000..aea52ed --- /dev/null +++ b/nix/default.nix @@ -0,0 +1,130 @@ +{ + config, + lib, + pkgs, + ... +}: +with lib; +let + cfg = config.programs.nixmobar; +in +{ + options.programs.nixmobar = { + enable = mkEnableOption (mdDoc "Xmobar, a minimalistic status bar"); + + font = mkOption { + type = types.str; + default = "Fira Code 13"; + description = mdDoc "Main font for Xmobar."; + }; + + additionalFonts = mkOption { + type = types.listOf types.str; + default = [ "Fira Code 22" ]; + description = mdDoc "Additional fonts for use in Xmobar."; + }; + + bgColor = mkOption { + type = types.str; + default = "#282a36"; + description = mdDoc "Background color of Xmobar."; + }; + + fgColor = mkOption { + type = types.str; + default = "#f8f8f2"; + description = mdDoc "Foreground (text) color of Xmobar."; + }; + + textOffset = mkOption { + type = types.int; + default = 2; + description = mdDoc "Offset of the text from the edge."; + }; + + verbose = mkOption { + type = types.bool; + default = true; + description = mdDoc "Enable verbose mode for Xmobar."; + }; + + allDesktops = mkOption { + type = types.bool; + default = true; + description = mdDoc "Show Xmobar on all desktops."; + }; + + lowerOnStart = mkOption { + type = types.bool; + default = true; + description = mdDoc "Whether Xmobar should be lowered on start."; + }; + + overrideRedirect = mkOption { + type = types.bool; + default = true; + description = mdDoc "If true, Xmobar will bypass window manager redirection."; + }; + + position = mkOption { + type = types.str; + default = "BottomH 26"; + description = mdDoc "Position of Xmobar on the screen."; + }; + + alpha = mkOption { + type = types.int; + default = 200; + description = mdDoc "Transparency level of Xmobar (0-255)."; + }; + + commands = mkOption { + type = types.lines; + default = '' + Run XMonadLog + Run DiskU ["/", "<fc=#bd93f9><fn=1>\\xf0a0</fn></fc> <free>"] [] 50 + Run DiskIO ["/", "<read><fc=#bd93f9> R</fc> <fc=#bd93f9>W</fc> <write>"] ["-t", "", "-w", "4"] 10 + Run Date "%a %_d %b %H:%M:%S" "date" 10 + # Add more commands here, one per line + ''; + description = mdDoc "List of commands to run in Xmobar, each on a new line."; + }; + + alignSep = mkOption { + type = types.str; + default = "}{"; + description = mdDoc "Separators for alignment left and right."; + }; + + template = mkOption { + type = types.str; + default = "<hspace=8/>%XMonadLog% }{ %load%|%disku%|%diskio%|<fc=#bd93f9><fn=1></fn></fc>%wifi_signal%|%dynnetwork%|<fc=#bd93f9><fn=1></fn></fc>%cat0%|%multicoretemp%|%cpufreq%|%multicpu%|<fc=#bd93f9><fn=1></fn></fc>%kbd%|%memory% %swap%|%battery%|%alsa:default:Master%|<fc=#bd93f9><fn=1></fn></fc>%kernel_version%|%date%|%_XMONAD_TRAYPAD%"; + description = mdDoc "Template string for Xmobar layout."; + }; + }; + + config = mkIf cfg.enable { + home.packages = [ pkgs.xmobar ]; + xdg.configFile."xmobar/.xmobarrc" = { + text = # haskell + '' + Config { + font = "${cfg.font}", + additionalFonts = [${lib.concatMapStringsSep ", " (s: "\"" + s + "\"") cfg.additionalFonts}], + bgColor = "${cfg.bgColor}", + fgColor = "${cfg.fgColor}", + textOffset = ${toString cfg.textOffset}, + verbose = ${if cfg.verbose then "True" else "False"}, + allDesktops = ${if cfg.allDesktops then "True" else "False"}, + lowerOnStart = ${if cfg.lowerOnStart then "True" else "False"}, + overrideRedirect = ${if cfg.overrideRedirect then "True" else "False"}, + position = ${cfg.position}, + alpha = ${toString cfg.alpha}, + commands = [${cfg.commands}], + alignSep = "${cfg.alignSep}", + template = "${cfg.template}" + } + ''; + }; + }; +} diff --git a/nix/flake.lock b/nix/flake.lock new file mode 100644 index 0000000..3f272ee --- /dev/null +++ b/nix/flake.lock @@ -0,0 +1,95 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "git-ignore-nix": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "ref": "master", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1666603677, + "narHash": "sha256-apAEIj+z1iwMaMJ4tB21r/VTetfGDLDzuhXRHJknIAU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "074da18a72269cc5a6cf444dce42daea5649b2fe", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1728018373, + "narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bc947f541ae55e999ffdb4013441347d83b00feb", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "git-ignore-nix": "git-ignore-nix", + "nixpkgs": "nixpkgs_2" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/nix/flake.nix b/nix/flake.nix new file mode 100644 index 0000000..b422c9a --- /dev/null +++ b/nix/flake.nix @@ -0,0 +1,64 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + git-ignore-nix.url = "github:hercules-ci/gitignore.nix/master"; + flake-utils.url = "github:numtide/flake-utils"; + }; + outputs = + { + self, + nixpkgs, + flake-utils, + git-ignore-nix, + }: + let + overlay = final: prev: { + haskellPackages = prev.haskellPackages.override (old: { + overrides = prev.lib.composeExtensions (old.overrides or (_: _: { })) ( + hself: hsuper: { + xmobar = prev.haskell.lib.compose.dontCheck ( + hself.callCabal2nix "xmobar" (git-ignore-nix.lib.gitignoreSource ./.) { } + ); + } + ); + }); + }; + overlays = [ overlay ]; + + homeModules.mainmodule = import ./default.nix; + in + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { inherit system overlays; }; + dynamicLibraries = with pkgs; [ + xorg.libX11 + xorg.libXrandr + xorg.libXrender + xorg.libXScrnSaver + xorg.libXext + xorg.libXft + xorg.libXpm.out + xorg.libXrandr + xorg.libXrender + ]; + in + { + devShell = pkgs.haskellPackages.shellFor { + packages = p: [ p.xmobar ]; + buildInputs = + with pkgs; + [ + haskellPackages.cabal-install + ] + ++ dynamicLibraries; + + LD_LIBRARY_PATH = pkgs.lib.strings.makeLibraryPath dynamicLibraries; + }; + defaultPackage = pkgs.haskellPackages.xmobar; + } + ) + // { + inherit overlay overlays homeModules; + }; +} diff --git a/nix/readme.org b/nix/readme.org new file mode 100644 index 0000000..d83d232 --- /dev/null +++ b/nix/readme.org @@ -0,0 +1,80 @@ +* Nix flake for Xmobar +This flake exposes a module to use with home-manager. +Here is how to set it up: + +1. Add the nixmobar flake as an input to your NiOS flake: + #+BEGIN_SRC nix + inputs = { + nixmobar.url = "git+https://codeberg.org/xmobar/xmobar.git/?dir=nix"; + }; + #+END_SRC + +2. And then, where you import your `home.nix`, add `extraSpecialArgs` like this: + #+BEGIN_SRC nix + home-manager = { + extraSpecialArgs = { + inherit inputs nixmobar; + }; + users.refaelsh = import ./home.nix; + }; + #+END_SRC + +3. Final step, use the module in `home.nix`: + #+BEGIN_SRC nix + { + inputs, + ... + }: + { + home.stateversion = "24.05"; + + imports = [ + inputs.nixmobar.homemodules.mainmodule + # Other imports go here. + ]; + + } + #+END_SRC + +* Example usage +#+BEGIN_SRC haskell +{ + programs.nixmobar = { + enable = true; + font = "Fira Code 13"; + additionalFonts = [ "Fira Code 22" ]; + bgColor = "#282A36"; + fgColor = "#F8F8F2"; + textOffset = 2; + verbose = true; + allDesktops = true; + lowerOnStart = true; + overrideRedirect = true; + position = "BottomH 26"; + alpha = 200; + alignSep = "}{"; + template = "<hspace=8/>%XMonadLog% }{ %load%|%disku%|%diskio%|<fc=#bd93f9><fn=1></fn></fc>%wifi_signal%|%dynnetwork%|<fc=#bd93f9><fn=1></fn></fc>%cat0%|%multicoretemp%|%cpufreq%|%multicpu%|<fc=#bd93f9><fn=1></fn></fc>%kbd%|%memory% %swap%|%battery%|%alsa:default:Master%|<fc=#bd93f9><fn=1></fn></fc>%kernel_version%|%date%|%_XMONAD_TRAYPAD%"; + commands = # haskell + '' + Run XMonadLog, + Run DiskU [("/", "<fc=#bd93f9><fn=1>\xf0a0</fn></fc> <free>")] [] 50, + Run DiskIO [("/", "<read><fc=#bd93f9> R</fc> <fc=#bd93f9>W</fc> <write>")] ["-t", "", "-w", "4"] 10, + Run DynNetwork ["-t", "<rx>KB/s<fc=#bd93f9><fn=1>\x1F89B</fn></fc><fc=#bd93f9><fn=1>\x1F899</fn></fc><tx>KB/s", "-w", "5"] 10, + Run Memory ["-t", "<fc=#bd93f9><fn=1>\xE266</fn></fc><usedratio>%"] 10, + Run Swap ["-t", "<fc=#bd93f9>S</fc><usedratio>%"] 10, + Run Kbd [], + Run CpuFreq ["-t", "<avg>GHz"] 50, + Run MultiCoreTemp ["-t", "<fc=#bd93f9><fn=1>\xf2c9</fn></fc><avg>°", "-L", "60", "-H", "95", "-l", "white", "-n", "white", "-h", "red"] 50, + Run CatInt 0 "/sys/class/hwmon/hwmon4/fan1_input" [] 50, + Run MultiCpu ["-t", "<fc=#bd93f9><fn=1>\xf4bc</fn></fc> <vbar0><vbar1><vbar2><vbar3><vbar4><vbar5><vbar6><vbar7>", "-w", "99", "-L", "3", "-H", "50", "--normal", "green", "--high", "red"] 10, + Run BatteryP ["BAT0"] ["-t", "<fc=#bd93f9><fn=1></fn></fc><left>%", "-L", "10", "-H", "80", "-p", "3", "--", "-O", "<fc=green>On</fc> - ", "-i", "", "-L", "-15", "-H", "-5", "-l", "red", "-m", "blue", "-h", "green", "-a", "notify-send -u critical 'Battery running out!!'", "-A", "3"] 600, + Run Alsa "default" "Master" ["-t", "<fc=#bd93f9><fn=1>\xf028</fn></fc> <volume>%"], + Run Date "%a %_d %b %H:%M:%S" "date" 10, + Run Load ["-t", "<fc=#bd93f9><fn=0>L</fn></fc><load1>", "-L", "1", "-H", "3", "-d", "2"] 300, + Run ComX "nmcli" ["-t", "-f", "SIGNAL", "dev", "wifi"] "N/A" "wifi_signal" 50, + Run Com "uname" ["-r"] "kernel_version" 3600, + Run XPropertyLog "_XMONAD_TRAYPAD" + ''; + }; +} +#+END_SRC @@ -5,9 +5,6 @@ <a href="http://hackage.haskell.org/package/xmobar"> <img src="https://img.shields.io/hackage/v/xmobar.svg" alt="hackage"/> </a> - <a href="https://ci.codeberg.org/xmobar/xmobar"> - <img src="https://ci.codeberg.org/api/badges/xmobar/xmobar/status.svg" alt="ci"/> - </a> </p> #+end_export @@ -26,7 +23,7 @@ output, in a variety of formats. [[file:doc/screenshots/xmobar-exwm.png]] -Check [[./changelog.md][the change log]] for our release history. We also have an IRC +Check [[https://codeberg.org/xmobar/xmobar/src/branch/master/changelog.md][the change log]] for our release history. We also have an IRC channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]]. * Breaking news @@ -43,9 +40,9 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]]. should be mostly transparent, except for the facts that it's allowed fixing quite a few bugs and that your /font names/ in your configuration, if you used ~xft~ ones, might need to be adapted to Pango's syntax: please see - [[./doc/quick-start.org#fonts][this section of the documentation]] for all the details. If you're + [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/quick-start.org#fonts][this section of the documentation]] for all the details. If you're compiling your own xmobar, there's a new dependency on libpango (see - [[./doc/compiling.org#c-libraries][C library dependencies]]). + [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/compiling.org#c-libraries][C library dependencies]]). * Installation :PROPERTIES: @@ -90,7 +87,7 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]]. ** Using cabal or stack Xmobar is available from [[http://hackage.haskell.org/package/xmobar/][Hackage]], and you can compile and install it using - =cabal-install=, making sure the [[doc/compiling.org#c-libraries][required C libraries]] are in place. For a + =cabal-install=, making sure the [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/compiling.org#c-libraries][required C libraries]] are in place. For a full build with all available extensions: #+begin_src shell @@ -105,10 +102,10 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]]. Starting with version 0.35.1, xmobar requires at least GHC version 8.4.x. to build. See [[https://codeberg.org/xmobar/xmobar/issues/461][this issue]] for more information. - See [[file:doc/compiling.org#optional-features][here]] for a list of optional compilation flags that will enable some + See [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/compiling.org#optional-features][here]] for a list of optional compilation flags that will enable some optional plugins. - See [[file:doc/compiling.org][compiling]] for full compilation instructions starting from source. + See [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/compiling.org][compiling]] for full compilation instructions starting from source. * Running xmobar ** Running xmobar with a configuration file @@ -129,7 +126,7 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]]. or =~/.xmobarrc=. All the available command line switches and configuration parameters are - described in [[file:doc/quick-start.org][the quick start guide]] and [[file:doc/plugins.org][the plugins index]]. + described in [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/quick-start.org][the quick start guide]] and [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/plugins.org][the plugins index]]. ** Writing your own xmobar in Haskell @@ -139,7 +136,7 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]]. Haskell instead of using a configuration file. (This is very similar to how [[http://xmonad.org][xmonad]] works.) That gives you the ability of using Haskell and its libraries to extend xmobar to your heart's content. If you are a - programmer, take a look [[file:doc/using-haskell.org][here]] to learn more. + programmer, take a look [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/using-haskell.org][here]] to learn more. ** Running xmobar in text mode @@ -147,24 +144,24 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]]. it is possible to redirect xmobar's output to the standard output, optionally with color escape sequences. In this mode, xmobar can be run inside a terminal o console, or its output piped to other applications, and - there is no need for an X11 display. See [[./doc/quick-start.org#text-mode][Running xmobar in text mode]] for - details. Using this mode, you could [[file:doc/quick-start.org#wayland][pipe xmobar's output to, say, swaybar]], - and use it in wayland, or, with the [[./etc/xmobar.el][xmobar.el]] package, show it in Emacs's + there is no need for an X11 display. See [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/quick-start.org#text-mode][Running xmobar in text mode]] for + details. Using this mode, you could [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/quick-start.org#wayland][pipe xmobar's output to, say, swaybar]], + and use it in wayland, or, with the [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.el][xmobar.el]] package, show it in Emacs's tab bar. * Configuration and further documentation - If you want to jump straight into running xmobar, head over to the - [[./doc/quick-start.org][quick start guide]]. + [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/quick-start.org][quick start guide]]. - If you want to get a detailed overview of all available plugins and - monitors, visit the [[./doc/plugins.org][plugins index]]. + monitors, visit the [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/plugins.org][plugins index]]. - For more information on how to use xmobar as a Haskell library see the - [[file:doc/using-haskell.org][using Haskell guide]]. + [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/using-haskell.org][using Haskell guide]]. - If you want to know how to contribute to the xmobar project, check out - [[contributing.org][contributing]]. + [[https://codeberg.org/xmobar/xmobar/src/branch/master/contributing.org][contributing]]. * Authors and credits @@ -173,23 +170,24 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]]. the greater xmobar and Haskell communities. In particular, xmobar incorporates patches by Kostas Agnantis, Mohammed - Alshiekh, Alex Ameen, Axel Angel, Dhananjay Balan, Claudio Bley, Dragos - Boca, Ben Boeckel, Ivan Brennan, Duncan Burke, Roman Cheplyaka, Patrick - Chilton, Antoine Eiche, Nathaniel Wesley Filardo, Guy Gastineau, John - Goerzen, Jonathan Grochowski, Patrick Günther, Reto Hablützel, Juraj Hercek, - Tomáš Janoušek, Ada Joule, Spencer Janssen, Roman Joost, Pavel Kalugin, - Jochen Keil, Sam Kirby, Lennart Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry - Kurochkin, Todd Lunter, Vanessa McHale, Robert J. Macomber, Dmitry Malikov, - David McLean, Joan Milev, Marcin Mikołajczyk, Dino Morelli, Tony Morris, - Eric Mrak, Thiago Negri, Edward O'Callaghan, Svein Ove, Martin Perner, Jens - Petersen, Alexander Polakov, Sibi Prabakaran, Pavan Rikhi, Petr Rockai, - Andrew Emmanuel Rosa, Sackville-West, Amir Saeid, Markus Scherer, Daniel - Schüssler, Olivier Schneider, Alexander Shabalin, Valentin Shirokov, Peter - Simons, Alexander Solovyov, Will Song, John Soo, John Soros, Felix Springer, - Travis Staton, Artem Tarasov, Samuli Thomasson, Edward Tjörnhammar, Sergei - Trofimovich, Thomas Tuegel, John Tyree, Jan Vornberger, Anton Vorontsov, - Daniel Wagner, Zev Weiss, Phil Xiaojun Hu, Nikolay Yakimov, Edward Z. Yang, - Leo Zhang, Norbert Zeh, and Michał Zielonka. + Alshiekh, Alex Ameen, Axel Angel, Enrico Maria De Angelis, Dhananjay Balan, + Claudio Bley, Dragos Boca, Ben Boeckel, Ivan Brennan, Duncan Burke, Roman + Cheplyaka, Patrick Chilton, Antoine Eiche, Nathaniel Wesley Filardo, Guy + Gastineau, John Goerzen, Jonathan Grochowski, Patrick Günther, Reto + Hablützel, Corey Halpin, Juraj Hercek, Jaroslaw Jantura, Tomáš Janoušek, Ada + Joule, Spencer Janssen, Roman Joost, Pavel Kalugin, Jochen Keil, Sam Kirby, + Lennart Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Todd Lunter, + Vanessa McHale, Robert J. Macomber, Dmitry Malikov, David McLean, Ulrik de + Muelenaere, Joan Milev, Marcin Mikołajczyk, Dino Morelli, Tony Morris, Eric + Mrak, Thiago Negri, Edward O'Callaghan, Svein Ove, Martin Perner, Alexander + Pankoff, Jens Petersen, Alexander Polakov, Sibi Prabakaran, Pavan Rikhi, + Petr Rockai, Andrew Emmanuel Rosa, Sackville-West, Amir Saeid, Markus + Scherer, Daniel Schüssler, Olivier Schneider, Alexander Shabalin, Valentin + Shirokov, Peter Simons, Alexander Solovyov, Will Song, John Soo, John Soros, + Felix Springer, Travis Staton, Artem Tarasov, Samuli Thomasson, Edward + Tjörnhammar, Sergei Trofimovich, Thomas Tuegel, John Tyree, Jan Vornberger, + Anton Vorontsov, Daniel Wagner, Zev Weiss, Phil Xiaojun Hu, Nikolay Yakimov, + Edward Z. Yang, Leo Zhang, Norbert Zeh, and Michał Zielonka. Andrea wants to thank Robert Manea and Spencer Janssen for their help in understanding how X works. They gave him suggestions on how to solve many @@ -202,6 +200,6 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]]. This software is released under a BSD-style license. See [[https://codeberg.org/xmobar/xmobar/src/branch/master/license][license]] for more details. - Copyright © 2010-2023 Jose Antonio Ortega Ruiz + Copyright © 2010-2025 Jose Antonio Ortega Ruiz Copyright © 2007-2010 Andrea Rossato diff --git a/src/Xmobar.hs b/src/Xmobar.hs index ced40a5..664d86c 100644 --- a/src/Xmobar.hs +++ b/src/Xmobar.hs @@ -26,6 +26,8 @@ module Xmobar (xmobar , SignalType (..) , module Xmobar.Config.Types , module Xmobar.Config.Parse + , module Xmobar.Plugins.Accordion + , module Xmobar.Plugins.ArchUpdates , module Xmobar.Plugins.BufferedPipeReader , module Xmobar.Plugins.CommandReader , module Xmobar.Plugins.Date @@ -43,6 +45,7 @@ module Xmobar (xmobar #endif , module Xmobar.Plugins.NotmuchMail , module Xmobar.Plugins.Monitors + , module Xmobar.Plugins.PacmanUpdates , module Xmobar.Plugins.PipeReader , module Xmobar.Plugins.MarqueePipeReader , module Xmobar.Plugins.StdinReader @@ -53,6 +56,8 @@ import Xmobar.Run.Runnable import Xmobar.Run.Exec import Xmobar.Config.Types import Xmobar.Config.Parse +import Xmobar.Plugins.Accordion +import Xmobar.Plugins.ArchUpdates import Xmobar.Plugins.Command import Xmobar.Plugins.BufferedPipeReader import Xmobar.Plugins.CommandReader @@ -70,6 +75,7 @@ import Xmobar.Plugins.Mail import Xmobar.Plugins.MBox #endif import Xmobar.Plugins.Monitors +import Xmobar.Plugins.PacmanUpdates import Xmobar.Plugins.PipeReader import Xmobar.Plugins.StdinReader import Xmobar.Plugins.MarqueePipeReader diff --git a/src/Xmobar/App/Compile.hs b/src/Xmobar/App/Compile.hs index 80dbac7..5d1f48d 100644 --- a/src/Xmobar/App/Compile.hs +++ b/src/Xmobar/App/Compile.hs @@ -20,20 +20,17 @@ module Xmobar.App.Compile(recompile, trace, xmessage) where import Control.Monad.IO.Class -import Control.Monad.Fix (fix) -import Control.Exception.Extensible (try, bracket, SomeException(..)) +import Control.Exception.Extensible (bracket, SomeException(..)) import qualified Control.Exception.Extensible as E import Control.Monad (filterM, when) import Data.List ((\\)) -import Data.Maybe (isJust) import System.FilePath((</>), takeExtension) import System.IO import System.Directory import System.Process import System.Exit -import System.Posix.Process(executeFile, forkProcess, getAnyProcessStatus) +import System.Posix.Process(executeFile, forkProcess) import System.Posix.Types(ProcessID) -import System.Posix.Signals isExecutable :: FilePath -> IO Bool isExecutable f = @@ -144,14 +141,12 @@ recompile confDir dataDir execName force verb = liftIO $ do else shouldRecompile verb src bin lib if sc then do - uninstallSignalHandlers status <- bracket (openFile err WriteMode) hClose $ \errHandle -> waitForProcess =<< if useScript then runScript script bin confDir errHandle else runGHC bin confDir errHandle - installSignalHandlers if status == ExitSuccess then trace verb "Xmobar recompilation process exited with success!" else do @@ -168,24 +163,9 @@ recompile confDir dataDir execName force verb = liftIO $ do #ifdef RTSOPTS ++ ["-rtsopts", "-with-rtsopts", "-V0"] #endif +#ifdef SHARED_LIBRARIES + ++ ["-dynamic"] +#endif ++ ["-o", bin] runGHC bin = runProc "ghc" (opts bin) runScript script bin = runProc script [bin] - --- | Ignore SIGPIPE to avoid termination when a pipe is full, and SIGCHLD to --- avoid zombie processes, and clean up any extant zombie processes. -installSignalHandlers :: MonadIO m => m () -installSignalHandlers = liftIO $ do - installHandler openEndedPipe Ignore Nothing - installHandler sigCHLD Ignore Nothing - (try :: IO a -> IO (Either SomeException a)) - $ fix $ \more -> do - x <- getAnyProcessStatus False False - when (isJust x) more - return () - -uninstallSignalHandlers :: MonadIO m => m () -uninstallSignalHandlers = liftIO $ do - installHandler openEndedPipe Default Nothing - installHandler sigCHLD Default Nothing - return () diff --git a/src/Xmobar/App/Opts.hs b/src/Xmobar/App/Opts.hs index 7e42374..0c3fee8 100644 --- a/src/Xmobar/App/Opts.hs +++ b/src/Xmobar/App/Opts.hs @@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.App.Opts --- Copyright: (c) 2018, 2019, 2020, 2022, 2023 Jose Antonio Ortega Ruiz +-- Copyright: (c) 2018, 2019, 2020, 2022, 2023, 2024, 2025 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org @@ -116,7 +116,7 @@ usage = usageInfo header options ++ footer info :: String info = "xmobar " ++ showVersion version - ++ "\n (C) 2010 - 2023 Jose A Ortega Ruiz" + ++ "\n (C) 2010 - 2025 Jose A Ortega Ruiz" ++ "\n (C) 2007 - 2010 Andrea Rossato\n " ++ mail ++ "\n" ++ license ++ "\n" diff --git a/src/Xmobar/Draw/Boxes.hs b/src/Xmobar/Draw/Boxes.hs index 692e232..ff55ab3 100644 --- a/src/Xmobar/Draw/Boxes.hs +++ b/src/Xmobar/Draw/Boxes.hs @@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.X11.Boxes --- Copyright: (c) 2022 Jose Antonio Ortega Ruiz +-- Copyright: (c) 2022, 2024 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org @@ -43,11 +43,10 @@ boxLines (T.Box bd offset lw _ margins) ht x0 x1 = T.C -> (ma, -ma) T.R -> (ma, 0) lc = fromIntegral lw / 2 - [mt, mr, mb, ml] = map fromIntegral [top, right, bot, left] - xmin = x0 - ml - lc - xmax = x1 + mr + lc - ymin = mt + lc - ymax = ht - mb - lc + xmin = x0 - fromIntegral left - lc + xmax = x1 + fromIntegral right + lc + ymin = fromIntegral top + lc + ymax = ht - fromIntegral bot - lc rtop = (xmin + p0, ymin, xmax + p1, ymin) rbot = (xmin + p0, ymax, xmax + p1, ymax) rleft = (xmin, ymin + p0, xmin, ymax + p1) diff --git a/src/Xmobar/Draw/Cairo.hs b/src/Xmobar/Draw/Cairo.hs index 8dcda5d..2338b10 100644 --- a/src/Xmobar/Draw/Cairo.hs +++ b/src/Xmobar/Draw/Cairo.hs @@ -2,7 +2,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.X11.Cairo --- Copyright: (c) 2022, 2023 Jose Antonio Ortega Ruiz +-- Copyright: (c) 2022, 2023, 2024 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org @@ -169,21 +169,22 @@ drawCairoBackground dctx surf = do drawSegments :: T.DrawContext -> Surface -> IO T.Actions drawSegments dctx surf = do - let [left, center, right] = take 3 $ T.dcSegments dctx ++ repeat [] + let segs = take 3 $ T.dcSegments dctx ++ repeat [] dh = T.dcHeight dctx dw = T.dcWidth dctx conf = T.dcConfig dctx sWidth = foldl (\a (_,_,w) -> a + w) 0 ctx <- Pango.cairoCreateContext Nothing Pango.cairoContextSetResolution ctx $ C.dpi conf - llyts <- mapM (withRenderinfo ctx dctx) left - rlyts <- mapM (withRenderinfo ctx dctx) right - clyts <- mapM (withRenderinfo ctx dctx) center + llyts <- mapM (withRenderinfo ctx dctx) (head segs) + rlyts <- mapM (withRenderinfo ctx dctx) (segs !! 2) + clyts <- mapM (withRenderinfo ctx dctx) (segs !! 1) #ifndef XRENDER drawCairoBackground dctx surf #endif (lend, as, bx) <- foldM (drawSegment dctx surf dw) (0, [], []) llyts - let [rw, cw] = map sWidth [rlyts, clyts] + let rw = sWidth rlyts + cw = sWidth clyts rstart = max lend (dw - rw) cstart = if lend > 1 || rw == 0 then max lend ((dw - cw) / 2.0) else lend (_, as', bx') <- if cw > 0 diff --git a/src/Xmobar/Plugins/Accordion.hs b/src/Xmobar/Plugins/Accordion.hs new file mode 100644 index 0000000..6377928 --- /dev/null +++ b/src/Xmobar/Plugins/Accordion.hs @@ -0,0 +1,97 @@ +{-# LANGUAGE TupleSections, FlexibleContexts #-} + +----------------------------------------------------------------------------- +-- | +-- Module : Plugins.Monitors.Accordion +-- Copyright : (c) 2024 Enrico Maria De Angelis +-- License : BSD-style (see LICENSE) +-- +-- Maintainer : Enrico Maria De Angelis <enricomaria.dean6elis@gmail.com> +-- Stability : unstable +-- Portability : unportable +-- +-- A plugin to group adjacent plugins and make them, as a whole, shrinkable to +-- an alternate text upon clicking. +-- +----------------------------------------------------------------------------- + +module Xmobar.Plugins.Accordion (defaultTuning, makeAccordion, Tuning(..)) where + +import Control.Concurrent.Async (withAsync) +import Control.Exception (finally) +import Control.Monad (forever, join, when) +import Control.Monad.IO.Class (liftIO) +import Control.Monad.Reader (runReaderT, ask) +import Control.Monad.State.Strict (evalStateT, get, modify') +import Data.IORef (atomicModifyIORef', newIORef, readIORef) +import Data.Maybe (isJust) +import System.Directory (removeFile) +import System.Exit (ExitCode(..)) +import System.Process (readProcessWithExitCode) +import Xmobar.Run.Exec (Exec(..), tenthSeconds) + +-- TODO: Ideally, I'd have just `Accordion`, and not `Tuning`, but since +-- `Accordion` is polymorphic, I can't have a `defaultAccordion` constructor +-- with `plugins = []`, because that leaves `a` undetermined. +-- So I have move all non-polymorphic typed members in `Tuning`, allowing for +-- default values at least for those members. +data Accordion a = Accordion { + tuning :: Tuning + , plugins :: [a] +} deriving (Show, Read) + +makeAccordion :: Exec a => Tuning -> [a] -> Accordion a +makeAccordion t rs = Accordion { tuning = t, plugins = rs } + +data Tuning = Tuning { + alias' :: String + , initial :: Bool + , expand :: String + , shrink :: String +} deriving (Read, Show) + +defaultTuning :: Tuning +defaultTuning = Tuning { + alias' = "accordion" + , initial = True + , expand = "<>" + , shrink = "><" +} + +instance (Exec a, Read a, Show a) => Exec (Accordion a) where + alias (Accordion Tuning { alias' = name } _) = name + start (Accordion Tuning { initial = initial' + , expand = expand' + , shrink = shrink' } + runnables) + cb = do + clicked <- newIORef Nothing + (_, n, _) <- readProcessWithExitCode "uuidgen" [] "" + let pipe = "/tmp/accordion-" ++ removeLinebreak n + (_, _, _) <- readProcessWithExitCode "mkfifo" [pipe] "" + withAsync (forever $ do (ret, _, _) <- readProcessWithExitCode "cat" [pipe] "" + case ret of + ExitSuccess -> atomicModifyIORef' clicked (const (Just (), ())) + ExitFailure _ -> error "how is this possible?") + (const $ do + srefs <- mapM (newIORef . const "") runnables + foldr (\(runnable, sref) acc -> withAsync (start runnable (writeToRef sref)) (const acc)) + (forever (do liftIO (tenthSeconds 1) + clicked' <- liftIO $ readIORef clicked + when (isJust clicked') + (do liftIO $ clear clicked + modify' not) + b <- get + if b then loop pipe else liftIO $ cb (click pipe expand')) + `runReaderT` srefs `evalStateT` initial') + (zip runnables srefs)) + `finally` removeFile pipe + where + click file icon = "<action=`echo 1 > " ++ file ++ "`>" ++ icon ++ "</action>" + clear = (`atomicModifyIORef'` const (Nothing, ())) + removeLinebreak = init + writeToRef strRef = atomicModifyIORef' strRef . const . (,()) + loop p = do + srefs <- ask + text <- join <$> mapM (liftIO . readIORef) srefs + liftIO $ cb $ text ++ click p shrink' diff --git a/src/Xmobar/Plugins/ArchUpdates.hs b/src/Xmobar/Plugins/ArchUpdates.hs new file mode 100644 index 0000000..0dcfd04 --- /dev/null +++ b/src/Xmobar/Plugins/ArchUpdates.hs @@ -0,0 +1,36 @@ +{-# LANGUAGE CPP #-} + +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + +{- | +Module : Plugins.Monitors.ArchUpdates +Copyright : (c) 2024 Enrico Maria De Angelis +License : BSD-style (see LICENSE) + +Maintainer : Enrico Maria De Angelis <enricomaria.dean6elis@gmail.com> +Stability : unstable +Portability : unportable + +An ArchLinux updates availablility plugin for Xmobar +-} +module Xmobar.Plugins.ArchUpdates (ArchUpdates (..)) where + +import Xmobar.Plugins.Command (Rate) +import Xmobar.Plugins.PacmanUpdates (PacmanUpdates (PacmanUpdates)) +import Xmobar.Run.Exec + +data ArchUpdates = ArchUpdates (String, String, String) Rate + deriving (Read, Show) + +intoPacmanUpdates :: ArchUpdates -> PacmanUpdates +intoPacmanUpdates (ArchUpdates (z, o, m) r) = + PacmanUpdates (z <> deprecation, o, m, "pacman: Unknown cause of failure.") r + where + deprecation = " <fc=#ff0000>(<action=`xdg-open https://codeberg.org/xmobar/xmobar/pulls/723`>deprecated plugin, click here</action>)</fc>" + +instance Exec ArchUpdates where + alias = const "arch" + rate = rate . intoPacmanUpdates + run = run . intoPacmanUpdates diff --git a/src/Xmobar/Plugins/Locks.hs b/src/Xmobar/Plugins/Locks.hs index 9176312..35a3f97 100644 --- a/src/Xmobar/Plugins/Locks.hs +++ b/src/Xmobar/Plugins/Locks.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE TupleSections #-} ----------------------------------------------------------------------------- -- | -- Module : Plugins.Locks @@ -16,45 +17,70 @@ module Xmobar.Plugins.Locks(Locks(..)) where import Graphics.X11 import Data.List +import Data.List.Extra (trim) import Data.Bits +import Data.Maybe (fromJust) import Control.Monad +import Control.Monad.Extra (ifM) import Graphics.X11.Xlib.Extras import Xmobar.Run.Exec import Xmobar.System.Kbd import Xmobar.X11.Events (nextEvent') -data Locks = Locks +data Locks = Locks | Locks' [(String, (String, String))] deriving (Read, Show) locks :: [ ( KeySym, String )] -locks = [ ( xK_Caps_Lock, "CAPS" ) - , ( xK_Num_Lock, "NUM" ) +locks = [ ( xK_Caps_Lock, "CAPS" ) + , ( xK_Num_Lock, "NUM" ) , ( xK_Scroll_Lock, "SCROLL" ) ] -run' :: Display -> Window -> IO String -run' d root = do +type Labels = [ ( String, (String, String) )] +defaultLabels :: Labels +defaultLabels = let nms = map snd locks + in zip nms (map (, mempty) nms) + +type LabelledLock = (KeySym, String, String, String) + +attach :: (KeySym, String) -> Labels -> LabelledLock +(key, lock) `attach` lbls = let (enb, dis) = fromJust $ lookup lock lbls + in (key, lock, enb, dis) + +enabled :: (a, b, c, d) -> c +enabled (_, _, c, _) = c +disabled :: (a, b, c, d) -> d +disabled (_, _, _, d) = d + +isEnabled :: (Bits a1, Foldable t, Foldable t1, Integral a) + => Display -> t (a, t1 KeyCode) -> a1 -> (KeySym, b, c, d) -> IO Bool +isEnabled d modMap m ( ks, _, _, _ ) = do + kc <- keysymToKeycode d ks + return $ case find (elem kc . snd) modMap of + Nothing -> False + Just ( i, _ ) -> testBit m (fromIntegral i) + +run' :: Display -> Window -> Labels -> IO String +run' d root labels = do modMap <- getModifierMapping d ( _, _, _, _, _, _, _, m ) <- queryPointer d root - ls <- filterM ( \( ks, _ ) -> do - kc <- keysymToKeycode d ks - return $ case find (elem kc . snd) modMap of - Nothing -> False - Just ( i, _ ) -> testBit m (fromIntegral i) - ) locks - - return $ unwords $ map snd ls + ls' <- forM (map (`attach` labels) locks) + (\l -> ifM (isEnabled d modMap m l) + (return (enabled l)) + (return (disabled l))) + return $ trim $ unwords ls' instance Exec Locks where - alias Locks = "locks" - start Locks cb = do + alias _ = "locks" + start Locks cb = start (Locks' defaultLabels) cb + start (Locks' labels) cb = do d <- openDisplay "" root <- rootWindow d (defaultScreen d) _ <- xkbSelectEventDetails d xkbUseCoreKbd xkbIndicatorStateNotify m m allocaXEvent $ \ep -> forever $ do - cb =<< run' d root + cb =<< run' d root labels nextEvent' d ep getEvent ep diff --git a/src/Xmobar/Plugins/MarqueePipeReader.hs b/src/Xmobar/Plugins/MarqueePipeReader.hs index 075503c..a6d590e 100644 --- a/src/Xmobar/Plugins/MarqueePipeReader.hs +++ b/src/Xmobar/Plugins/MarqueePipeReader.hs @@ -60,7 +60,7 @@ writer txt sep len rate chan cb = do Nothing -> tenthSeconds rate >> writer (drop 1 txt) sep len rate chan cb toInfTxt :: String -> String -> String -toInfTxt line sep = concat (repeat $ line ++ " " ++ sep ++ " ") +toInfTxt line sep = cycle (line ++ " " ++ sep ++ " ") checkPipe :: FilePath -> IO () checkPipe file = handle (\(SomeException _) -> waitForPipe) $ do diff --git a/src/Xmobar/Plugins/Monitors/Alsa.hs b/src/Xmobar/Plugins/Monitors/Alsa.hs index dfc7329..8d02931 100644 --- a/src/Xmobar/Plugins/Monitors/Alsa.hs +++ b/src/Xmobar/Plugins/Monitors/Alsa.hs @@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Alsa --- Copyright : (c) 2018 Daniel Schüssler +-- Copyright : (c) 2018, 2024 Daniel Schüssler -- License : BSD-style (see LICENSE) -- -- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org> @@ -25,6 +25,7 @@ import Control.Concurrent.Async import Control.Exception import Control.Monad import Data.IORef +import Data.Maybe (fromJust) import Data.Time.Clock import Xmobar.Plugins.Monitors.Common import qualified Xmobar.Plugins.Monitors.Volume as Volume; @@ -129,7 +130,8 @@ alsaReaderThread mixerName alsaCtlPath outputCallback mvar = {std_out = CreatePipe} runAlsaOnce = - withCreateProcess createProc $ \_ (Just alsaOut) _ _ -> do + withCreateProcess createProc $ \_ out _ _ -> do + let alsaOut = fromJust out hSetBuffering alsaOut LineBuffering tryPutMVar mvar () -- Refresh immediately after restarting alsactl diff --git a/src/Xmobar/Plugins/Monitors/Batt/Common.hs b/src/Xmobar/Plugins/Monitors/Batt/Common.hs index 3262b78..ddb2b8c 100644 --- a/src/Xmobar/Plugins/Monitors/Batt/Common.hs +++ b/src/Xmobar/Plugins/Monitors/Batt/Common.hs @@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Batt.Common --- Copyright : (c) 2010, 2011, 2012, 2013, 2015, 2016, 2018, 2019 Jose A Ortega +-- Copyright : (c) 2010-2016, 2018, 2019, 2024 Jose A Ortega -- (c) 2010 Andrea Rossato, Petr Rockai -- License : BSD-style (see LICENSE) -- @@ -18,7 +18,7 @@ module Xmobar.Plugins.Monitors.Batt.Common (BattOpts(..) , Status(..) , maybeAlert) where -import System.Process (system) +import System.Process (spawnCommand, waitForProcess) import Control.Monad (unless, void) import Xmobar.Plugins.Monitors.Common @@ -54,4 +54,4 @@ maybeAlert opts left = case onLowAction opts of Nothing -> return () Just x -> unless (isNaN left || actionThreshold opts < 100 * left) - $ void $ system x + $ void $ spawnCommand (x ++ " &") >>= waitForProcess diff --git a/src/Xmobar/Plugins/Monitors/Common/Output.hs b/src/Xmobar/Plugins/Monitors/Common/Output.hs index 2d0e194..c0a00ab 100644 --- a/src/Xmobar/Plugins/Monitors/Common/Output.hs +++ b/src/Xmobar/Plugins/Monitors/Common/Output.hs @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Plugins.Monitors.Strings --- Copyright: (c) 2018, 2019, 2020, 2022 Jose Antonio Ortega Ruiz +-- Copyright: (c) 2018, 2019, 2020, 2022, 2024 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org @@ -88,9 +88,9 @@ pShowWithColors p f x = do pColorizeString :: (Num a, Ord a, MonadIO m) => MonitorConfig -> a -> String -> m String pColorizeString p x s = do let col = pSetColor p s - [ll,hh] = map fromIntegral $ sort [pLow p, pHigh p] -- consider high < low - pure $ head $ [col pHighColor | x > hh ] ++ - [col pNormalColor | x > ll ] ++ + cols = map fromIntegral $ sort [pLow p, pHigh p] -- consider high < low + pure $ head $ [col pHighColor | x > (cols !! 1) ] ++ + [col pNormalColor | x > head cols ] ++ [col pLowColor | True] pSetColor :: MonitorConfig -> String -> PSelector (Maybe String) -> String @@ -197,9 +197,9 @@ colorizeString x s = do h <- getConfigValue high l <- getConfigValue low let col = setColor s - [ll,hh] = map fromIntegral $ sort [l, h] -- consider high < low - head $ [col highColor | x > hh ] ++ - [col normalColor | x > ll ] ++ + cols = map fromIntegral $ sort [l, h] -- consider high < low + head $ [col highColor | x > cols !! 1 ] ++ + [col normalColor | x > head cols ] ++ [col lowColor | True] showWithColors :: (Num a, Ord a) => (a -> String) -> a -> Monitor String @@ -260,11 +260,11 @@ logScaling f v = do h <- fromIntegral `fmap` getConfigValue high l <- fromIntegral `fmap` getConfigValue low bw <- fromIntegral `fmap` getConfigValue barWidth - let [ll, hh] = sort [l, h] + let ws = sort [l, h] bw' = if bw > 0 then bw else 10 scaled x | x == 0.0 = 0 - | x <= ll = 1 / bw' - | otherwise = f + logBase 2 (x / hh) / bw' + | x <= head ws = 1 / bw' + | otherwise = f + logBase 2 (x / ws !! 1) / bw' return $ scaled v showLogBar :: Float -> Float -> Monitor String diff --git a/src/Xmobar/Plugins/Monitors/Disk.hs b/src/Xmobar/Plugins/Monitors/Disk.hs index 47d1eac..95bcff6 100644 --- a/src/Xmobar/Plugins/Monitors/Disk.hs +++ b/src/Xmobar/Plugins/Monitors/Disk.hs @@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Disk --- Copyright : (c) 2010, 2011, 2012, 2014, 2018, 2019 Jose A Ortega Ruiz +-- Copyright : (c) 2010-2012, 2014, 2018, 2019, 2024 Jose A Ortega Ruiz -- License : BSD-style (see LICENSE) -- -- Maintainer : Jose A Ortega Ruiz <jao@gnu.org> @@ -131,10 +131,9 @@ startDiskIO disks args rate cb = do runM args diskIOConfig (runDiskIO dref disks) rate cb runDiskU' :: DiskUOpts -> String -> [Integer] -> Monitor String -runDiskU' opts tmp stat = do +runDiskU' opts tmp (total:free:diff:_) = do setConfigValue tmp template - let [total, free, diff] = stat - strs = map sizeToStr [free, diff] + let strs = map sizeToStr [free, diff] freep = if total > 0 then free * 100 `div` total else 0 fr = fromIntegral freep / 100 s <- zipWithM showWithColors' strs [freep, 100 - freep] @@ -146,6 +145,7 @@ runDiskU' opts tmp stat = do uvb <- showVerticalBar (fromIntegral $ 100 - freep) (1 - fr) uipat <- showIconPattern (usedIconPattern opts) (1 - fr) parseTemplate $ [sizeToStr total] ++ s ++ sp ++ [fb,fvb,fipat,ub,uvb,uipat] +runDiskU' _ _ _ = return "" runDiskU :: [(String, String)] -> [String] -> Monitor String runDiskU disks argv = do diff --git a/src/Xmobar/Plugins/Monitors/Mem/Linux.hs b/src/Xmobar/Plugins/Monitors/Mem/Linux.hs index 79dcc9d..7a81c6d 100644 --- a/src/Xmobar/Plugins/Monitors/Mem/Linux.hs +++ b/src/Xmobar/Plugins/Monitors/Mem/Linux.hs @@ -25,9 +25,13 @@ parseMEM = let content = map words $ take 8 $ lines file info = M.fromList $ map ( \line -> (head line, (read $ line !! 1 :: Float) / 1024)) content - [total, free, buffer, cache] = - map (info M.!) ["MemTotal:", "MemFree:", "Buffers:", "Cached:"] - available = M.findWithDefault (free + buffer + cache) "MemAvailable:" info + info' x = info M.! (x ++ ":") + total = info' "MemTotal" + free = info' "MemFree" + buffer = info' "Buffers" + cache = info' "Cached" + available = + M.findWithDefault (free + buffer + cache) "MemAvailable:" info used = total - available usedratio = used / total freeratio = free / total diff --git a/src/Xmobar/Plugins/Monitors/Mpris.hs b/src/Xmobar/Plugins/Monitors/Mpris.hs index ee30ad3..eb9595b 100644 --- a/src/Xmobar/Plugins/Monitors/Mpris.hs +++ b/src/Xmobar/Plugins/Monitors/Mpris.hs @@ -28,7 +28,7 @@ import qualified DBus.Client as DC import Control.Arrow ((***)) import Data.Maybe ( fromJust ) import Data.Int ( Int32, Int64 ) -import Data.Word ( Word32 ) +import Data.Word ( Word32, Word64 ) import System.IO.Unsafe ( unsafePerformIO ) import Control.Exception (try) @@ -136,17 +136,17 @@ makeList version md = map getStr (fieldsList version) where "xesam:trackNumber" -> printf "%02d" num _ -> (show::Int32 -> String) num pw32 v = printf "%02d" (fromVar v::Word32) - plen str v = let num = fromVar v in - case str of + plen str num = case str of "mpris:length" -> formatTime (num `div` 1000000) - _ -> (show::Int64 -> String) num + _ -> show num getStr str = case lookup str md of Nothing -> "" Just v -> case variantType v of TypeString -> fromVar v TypeInt32 -> pInt str v TypeWord32 -> pw32 v - TypeInt64 -> plen str v + TypeWord64 -> plen str (fromVar v :: Word64) + TypeInt64 -> plen str (fromVar v :: Int64) TypeArray TypeString -> let x = arrayItems (fromVar v) in if null x then "" else fromVar (head x) diff --git a/src/Xmobar/Plugins/Monitors/Net/Linux.hs b/src/Xmobar/Plugins/Monitors/Net/Linux.hs index 9306497..f9cbc28 100644 --- a/src/Xmobar/Plugins/Monitors/Net/Linux.hs +++ b/src/Xmobar/Plugins/Monitors/Net/Linux.hs @@ -47,7 +47,10 @@ isUp d = flip catchIOError (const $ return False) $ do return $! (head . B.lines) operstate `elem` ["up", "unknown"] readNetDev :: [String] -> IO NetDevRawTotal -readNetDev ~[d, x, y] = do +readNetDev ds = do + let (d, x, y) = case ds of + d':x':y':_ -> (d', x', y') + _ -> ("", "", "") up <- unsafeInterleaveIO $ isUp d return $ N d (if up then ND (r x) (r y) else NI) where r s | s == "" = 0 diff --git a/src/Xmobar/Plugins/Monitors/Top.hs b/src/Xmobar/Plugins/Monitors/Top.hs index 3bfe6fd..b2e573b 100644 --- a/src/Xmobar/Plugins/Monitors/Top.hs +++ b/src/Xmobar/Plugins/Monitors/Top.hs @@ -3,7 +3,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Top --- Copyright : (c) 2010, 2011, 2012, 2013, 2014, 2018, 2022 Jose A Ortega Ruiz +-- Copyright : (c) 2010-2014, 2018, 2022, 2025 Jose A Ortega Ruiz -- License : BSD-style (see LICENSE) -- -- Maintainer : Jose A Ortega Ruiz <jao@gnu.org> @@ -20,7 +20,7 @@ import Xmobar.Plugins.Monitors.Common import Data.IORef (newIORef, readIORef, writeIORef) import Data.List (sortBy) -import Data.Ord (comparing) +import Data.Ord (comparing, Down (..)) import Data.Time.Clock (getCurrentTime, diffUTCTime) import Xmobar.Plugins.Monitors.Top.Common ( @@ -66,7 +66,7 @@ showInfo nm sms mms = do sortTop :: [(String, Float)] -> [(String, Float)] -sortTop = sortBy (flip (comparing snd)) +sortTop = sortBy (comparing (Down . snd)) showMemInfo :: Float -> MemInfo -> Monitor [String] showMemInfo scale (nm, rss) = diff --git a/src/Xmobar/Plugins/Monitors/Weather.hs b/src/Xmobar/Plugins/Monitors/Weather.hs index e71de10..6b5c353 100644 --- a/src/Xmobar/Plugins/Monitors/Weather.hs +++ b/src/Xmobar/Plugins/Monitors/Weather.hs @@ -66,6 +66,7 @@ weatherConfig = mkMConfig , "skyCondition" , "skyConditionS" , "weather" + , "weatherS" , "tempC" , "tempF" , "dewPointC" @@ -221,23 +222,23 @@ getData station = CE.catch errHandler :: CE.SomeException -> IO String errHandler _ = return "<Could not retrieve data>" -formatSk :: Eq p => [(p, p)] -> p -> p -formatSk ((a,b):sks) sk = if a == sk then b else formatSk sks sk -formatSk [] sk = sk - formatWeather :: WeatherOpts -- ^ Formatting options from the cfg file -> [(String,String)] -- ^ 'SkyConditionS' for 'WeatherX' -> [WeatherInfo] -- ^ The actual weather info -> Monitor String -formatWeather opts sks [WI st ss y m d h (WindInfo wc wa wm wk wkh wms) v sk we tC tF dC dF r p] = - do cel <- showWithColors show tC +formatWeather opts sks [WI st ss y m d h wind v sk we tC tF dC dF r p] = + do let WindInfo wc wa wm wk wkh wms = wind + cel <- showWithColors show tC far <- showWithColors show tF - let sk' = formatSk sks (map toLower sk) - we' = showWeather (weatherString opts) we + let we' = showWeather (weatherString opts) we + sk' = findSk sks (map toLower sk) we' + we'' = findSk sks (map toLower we') sk' parseTemplate [st, ss, y, m, d, h, wc, wa, wm, wk, wkh - , wms, v, sk, sk', we', cel, far + , wms, v, sk, sk', we', we'', cel, far , show dC, show dF, show r , show p ] + where findSk ((a,b):xs) x df = if a == x then b else findSk xs x df + findSk [] _ df = df formatWeather _ _ _ = getConfigValue naString -- | Show the 'weather' field with a default string in case it was empty. diff --git a/src/Xmobar/Plugins/PacmanUpdates.hs b/src/Xmobar/Plugins/PacmanUpdates.hs new file mode 100644 index 0000000..1e8a8fc --- /dev/null +++ b/src/Xmobar/Plugins/PacmanUpdates.hs @@ -0,0 +1,43 @@ +{-# LANGUAGE CPP #-} + +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + +{- | +Module : Plugins.Monitors.PacmanUpdates +Copyright : (c) 2024 Enrico Maria De Angelis + , (c) 2025 Alexander Pankoff +License : BSD-style (see LICENSE) + +Maintainer : Enrico Maria De Angelis <enricomaria.dean6elis@gmail.com> +Stability : unstable +Portability : unportable + +A Pacman updates availablility plugin for Xmobar +-} +module Xmobar.Plugins.PacmanUpdates (PacmanUpdates (..)) where + +import System.Exit (ExitCode (..)) +import System.Process (readProcessWithExitCode) +import Xmobar.Plugins.Command (Rate) +import Xmobar.Run.Exec + +data PacmanUpdates = PacmanUpdates (String, String, String, String) Rate + deriving (Read, Show) + +instance Exec PacmanUpdates where + alias = const "pacman" + rate (PacmanUpdates _ r) = r + run (PacmanUpdates (z, o, m, e) _) = do + (exit, stdout, _) <- readProcessWithExitCode "checkupdates" [] "" + return $ case exit of + ExitFailure 2 -> z -- ero updates + ExitFailure 1 -> e + ExitSuccess -> case length $ lines stdout of + 0 -> impossible + 1 -> o + n -> m >>= \c -> if c == '?' then show n else pure c + _ -> impossible + where + impossible = error "This is impossible based on pacman manpage" diff --git a/src/Xmobar/Run/Actions.hs b/src/Xmobar/Run/Actions.hs index 2a49312..cbc10c5 100644 --- a/src/Xmobar/Run/Actions.hs +++ b/src/Xmobar/Run/Actions.hs @@ -16,7 +16,7 @@ module Xmobar.Run.Actions ( Button , runAction' , stripActions) where -import System.Process (system) +import System.Process (spawnCommand, waitForProcess) import Control.Monad (void) import Text.Regex (Regex, subRegex, mkRegex, matchRegex) import Data.Word (Word32) @@ -26,11 +26,11 @@ type Button = Word32 data Action = Spawn [Button] String deriving (Eq, Read, Show) runAction :: Action -> IO () -runAction (Spawn _ s) = void $ system (s ++ "&") +runAction (Spawn _ s) = void $ spawnCommand (s ++ " &") >>= waitForProcess -- | Run action with stdout redirected to stderr runAction' :: Action -> IO () -runAction' (Spawn _ s) = void $ system (s ++ " 1>&2 &") +runAction' (Spawn _ s) = void $ spawnCommand (s ++ " 1>&2 &") >>= waitForProcess stripActions :: String -> String stripActions s = case matchRegex actionRegex s of diff --git a/src/Xmobar/Run/Template.hs b/src/Xmobar/Run/Template.hs index 87c84d3..68feacb 100644 --- a/src/Xmobar/Run/Template.hs +++ b/src/Xmobar/Run/Template.hs @@ -77,5 +77,6 @@ splitTemplate alignSep template = (ce,_:ri) -> [le, ce, ri] _ -> def _ -> def - where [l, r] = if length alignSep == 2 then alignSep else defaultAlign + where sep = if length alignSep == 2 then alignSep else defaultAlign + (l, r) = (head sep, sep !! 1) def = [template, "", ""] diff --git a/src/Xmobar/Run/Types.hs b/src/Xmobar/Run/Types.hs index 69406bb..bb573c8 100644 --- a/src/Xmobar/Run/Types.hs +++ b/src/Xmobar/Run/Types.hs @@ -19,6 +19,7 @@ module Xmobar.Run.Types(runnableTypes) where import {-# SOURCE #-} Xmobar.Run.Runnable() +import Xmobar.Plugins.ArchUpdates import Xmobar.Plugins.Command import Xmobar.Plugins.Monitors import Xmobar.Plugins.Date @@ -59,6 +60,7 @@ infixr :*: runnableTypes :: Command :*: Monitors :*: Date :*: PipeReader :*: BufferedPipeReader :*: CommandReader :*: StdinReader :*: XMonadLog :*: EWMH :*: Kbd :*: Locks :*: NotmuchMail :*: + ArchUpdates :*: #ifdef INOTIFY Mail :*: MBox :*: #endif diff --git a/src/Xmobar/System/Environment.hs b/src/Xmobar/System/Environment.hs index 42483ca..0491bcc 100644 --- a/src/Xmobar/System/Environment.hs +++ b/src/Xmobar/System/Environment.hs @@ -36,12 +36,13 @@ expandEnv (c:s) = case c of False -> do remainder <- expandEnv $ drop 1 s return $ escString s ++ remainder - where escString s' = let (cc:_) = s' in + where escString (cc:_) = case cc of 't' -> "\t" 'n' -> "\n" '$' -> "$" _ -> [cc] + escString [] = "" _ -> do remainder <- expandEnv s diff --git a/src/Xmobar/X11/Bitmap.hs b/src/Xmobar/X11/Bitmap.hs index b14356f..c5304d9 100644 --- a/src/Xmobar/X11/Bitmap.hs +++ b/src/Xmobar/X11/Bitmap.hs @@ -2,7 +2,7 @@ ----------------------------------------------------------------------------- -- | -- Module : X11.Bitmap --- Copyright : (C) 2013, 2015, 2017, 2018, 2022 Alexander Polakov +-- Copyright : (C) 2013, 2015, 2017, 2018, 2022, 2024 Alexander Polakov -- License : BSD3 -- -- Maintainer : jao@gnu.org @@ -116,8 +116,9 @@ loadBitmap d w p = do drawBitmap :: Display -> Drawable -> GC -> String -> String -> Position -> Position -> Bitmap -> IO () drawBitmap d p gc fc bc x y i = - withColors d [fc, bc] $ \[fc', bc'] -> do - let w = width i + withColors d [fc, bc] $ \cs -> do + let (fc', bc') = (head cs, cs !! 1) + w = width i h = height i y' = 1 + y - fromIntegral h `div` 2 setForeground d gc fc' diff --git a/src/Xmobar/X11/Loop.hs b/src/Xmobar/X11/Loop.hs index 6ddb693..0425cff 100644 --- a/src/Xmobar/X11/Loop.hs +++ b/src/Xmobar/X11/Loop.hs @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.App.X11EventLoop --- Copyright: (c) 2018, 2020, 2022, 2023 Jose Antonio Ortega Ruiz +-- Copyright: (c) 2018, 2020, 2022, 2023, 2024 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org @@ -149,8 +149,7 @@ signalLoop xc@(T.XConf d r w fs is cfg) actions signalv strs = do parseSegments :: C.Config -> STM.TVar [String] -> IO [[C.Segment]] parseSegments conf v = do s <- STM.readTVarIO v - let l:c:r:_ = s ++ repeat "" - return $ map (CT.parseString conf) [l, c, r] + return $ map (CT.parseString conf) (take 3 $ s ++ repeat "") updateIconCache :: T.XConf -> [[C.Segment]] -> IO T.XConf updateIconCache xc@(T.XConf d _ w _ c cfg) segs = do @@ -171,7 +170,7 @@ updateConfigPosition disp cfg = runActions :: D.Actions -> A.Button -> X11.Position -> IO () runActions actions button pos = mapM_ A.runAction $ - filter (\(A.Spawn b _) -> button `elem` b) $ - concatMap (\(a,_,_) -> a) $ - filter (\(_, from, to) -> pos' >= from && pos' <= to) actions + concatMap + (filter (\ (A.Spawn b _) -> button `elem` b) . (\ (a, _, _) -> a)) + (filter (\ (_, from, to) -> pos' >= from && pos' <= to) actions) where pos' = fromIntegral pos diff --git a/xmobar.cabal b/xmobar.cabal index 1b603ef..a413c29 100644 --- a/xmobar.cabal +++ b/xmobar.cabal @@ -1,5 +1,5 @@ name: xmobar -version: 0.47.2 +version: 0.49 homepage: https://codeberg.org/xmobar/xmobar synopsis: A Minimalistic Text Based Status Bar description: Xmobar is a minimalistic text based status bar. @@ -84,6 +84,10 @@ flag with_rtsopts description: Use -with-rtsopts=-V0 to reduce wakeups. default: True +flag with_shared + description: Use shared libraries. Required when dependencies are built as shared libraries. + default: False + flag with_weather description: Enable weather plugin. default: True @@ -101,6 +105,7 @@ library hs-source-dirs: src exposed-modules: Xmobar, + Xmobar.Plugins.Accordion, Xmobar.Plugins.Monitors.Common.Types, Xmobar.Plugins.Monitors.Common.Run, Xmobar.Plugins.Monitors.Common, @@ -145,6 +150,7 @@ library Xmobar.X11.Text, Xmobar.X11.Types, Xmobar.X11.Window, + Xmobar.Plugins.ArchUpdates, Xmobar.Plugins.Command, Xmobar.Plugins.BufferedPipeReader, Xmobar.Plugins.CommandReader, @@ -152,6 +158,7 @@ library Xmobar.Plugins.EWMH, Xmobar.Plugins.HandleReader, Xmobar.Plugins.QueueReader, + Xmobar.Plugins.PacmanUpdates, Xmobar.Plugins.PipeReader, Xmobar.Plugins.MarqueePipeReader, Xmobar.Plugins.StdinReader, @@ -194,15 +201,16 @@ library build-depends: aeson >= 1.4.7.1, async, - base >= 4.11.0 && < 4.19, + base >= 4.11.0 && < 4.21, bytestring >= 0.10.8.2, cairo >= 0.13, colour >= 2.3.6, containers, directory, + extra, extensible-exceptions == 0.1.*, filepath, - mtl >= 2.1 && < 2.3, + mtl >= 2.1 && < 2.4, old-locale, pango >= 0.13, parsec == 3.1.*, @@ -232,6 +240,9 @@ library if flag(with_rtsopts) cpp-options: -DRTSOPTS + if flag(with_shared) + cpp-options: -DSHARED_LIBRARIES + if flag(with_xrender) build-depends: X11-xft >= 0.2 other-modules: Xmobar.X11.XRender |