Hello community,

here is the log from the commit of package waybar for openSUSE:Factory checked 
in at 2020-01-04 19:21:07
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/waybar (Old)
 and      /work/SRC/openSUSE:Factory/.waybar.new.6675 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "waybar"

Sat Jan  4 19:21:07 2020 rev:17 rq:759783 version:0.9.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/waybar/waybar.changes    2019-12-23 
22:48:39.750094641 +0100
+++ /work/SRC/openSUSE:Factory/.waybar.new.6675/waybar.changes  2020-01-04 
19:21:07.625131543 +0100
@@ -1,0 +2,27 @@
+Sat Dec 28 13:26:47 UTC 2019 - Michael Vetter <[email protected]>
+
+- Add dependency on systemd and new gtk-layer-shell-devel
+
+-------------------------------------------------------------------
+Sat Dec 28 12:17:51 UTC 2019 - Michael Vetter <[email protected]>
+
+- Update to 0.9.0:
+  Added:
+  * Use GTK Layer Shell for working Popups #441
+  * Disk module #471
+  * Man pages option #443
+  * Battery: format time #455
+  * Systemd user unit #460
+  * Detect timezone changes #480
+  * Pulseaudio: export desc as a format #507
+  * Toggle opacity #510
+  Changed:
+  * Fix man memory description #444
+  * Fix output typo #445
+  * Fix typo: persistant -> persistent #446
+  * Fix exclusive zone #447
+  * Network: clamp signal strength 334bc1e
+  * MPD: take lock in waitForEvent to prevent SIGABORT #467
+  * Pulseaudio: audio scroll bound #475
+
+-------------------------------------------------------------------

Old:
----
  0.8.0.tar.gz

New:
----
  0.9.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ waybar.spec ++++++
--- /var/tmp/diff_new_pack.w4dwf5/_old  2020-01-04 19:21:08.145131774 +0100
+++ /var/tmp/diff_new_pack.w4dwf5/_new  2020-01-04 19:21:08.153131777 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package waybar
 #
-# Copyright (c) 2019 SUSE LLC
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,39 +17,42 @@
 
 
 Name:           waybar
-Version:        0.8.0
+Version:        0.9.0
 Release:        0
 Summary:        Customizable Wayland bar for Sway and Wlroots based compositors
 License:        MIT
 Group:          System/GUI/Other
 URL:            https://github.com/Alexays/Waybar
 Source:         %{url}/archive/%{version}.tar.gz
+BuildRequires:  cmake
 BuildRequires:  gcc-c++
+BuildRequires:  gtk-layer-shell-devel
 BuildRequires:  meson
 BuildRequires:  ninja
 BuildRequires:  pkgconfig
+# optional: man pages
+BuildRequires:  scdoc
+# optional: tray module
+BuildRequires:  pkgconfig(dbusmenu-gtk3-0.4)
 BuildRequires:  pkgconfig(fmt)
 BuildRequires:  pkgconfig(gio-unix-2.0)
 BuildRequires:  pkgconfig(gtkmm-3.0)
 BuildRequires:  pkgconfig(jsoncpp)
 BuildRequires:  pkgconfig(libinput)
+# optional: mpd module
+BuildRequires:  pkgconfig(libmpdclient)
+# optional: network
+BuildRequires:  pkgconfig(libnl-3.0)
+BuildRequires:  pkgconfig(libnl-genl-3.0)
+# optional: audio
+BuildRequires:  pkgconfig(libpulse)
 BuildRequires:  pkgconfig(libudev)
 BuildRequires:  pkgconfig(sigc++-2.0)
 BuildRequires:  pkgconfig(spdlog)
+BuildRequires:  pkgconfig(systemd)
 BuildRequires:  pkgconfig(wayland-client)
 BuildRequires:  pkgconfig(wayland-cursor)
 BuildRequires:  pkgconfig(wayland-protocols)
-# optional: man pages
-BuildRequires:  scdoc
-# optional: tray module
-BuildRequires:  pkgconfig(dbusmenu-gtk3-0.4)
-# optional: network
-BuildRequires:  pkgconfig(libnl-3.0)
-BuildRequires:  pkgconfig(libnl-genl-3.0)
-# optional: audio
-BuildRequires:  pkgconfig(libpulse)
-# optional: mpd module
-BuildRequires:  pkgconfig(libmpdclient)
 # optional: sway integration
 Recommends:     sway
 
@@ -70,5 +73,6 @@
 %{_sysconfdir}/xdg/waybar/
 %{_bindir}/waybar
 %{_mandir}/man?/%{name}*
+%{_prefix}/lib/systemd/user/waybar.service
 
 %changelog

++++++ 0.8.0.tar.gz -> 0.9.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/.travis.yml new/Waybar-0.9.0/.travis.yml
--- old/Waybar-0.8.0/.travis.yml        2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/.travis.yml        2019-12-28 12:35:09.000000000 +0100
@@ -3,18 +3,21 @@
 services:
     - docker
 
+git:
+    submodules: false
+
 env:
     - distro: debian
     - distro: archlinux
-    - distro: opensuse
     - distro: fedora
     - distro: alpine
 
 before_install:
     - docker pull alexays/waybar:${distro}
+    - find . -type f \( -name '*.cpp' -o -name '*.h' \) -print0 | xargs -r0 
clang-format -i
 
 script:
     - echo FROM alexays/waybar:${distro} > Dockerfile
     - echo ADD . /root >> Dockerfile
     - docker build -t waybar .
-    - docker run waybar /bin/sh -c "cd /root && meson build && ninja -C build"
\ No newline at end of file
+    - docker run waybar /bin/sh -c "cd /root && meson build 
-Dman-pages=enabled && ninja -C build"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/Dockerfiles/alpine 
new/Waybar-0.9.0/Dockerfiles/alpine
--- old/Waybar-0.8.0/Dockerfiles/alpine 2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/Dockerfiles/alpine 2019-12-28 12:35:09.000000000 +0100
@@ -1,3 +1,5 @@
+# vim: ft=Dockerfile
+
 FROM alpine:latest
 
 RUN apk add --no-cache git meson alpine-sdk libinput-dev wayland-dev 
wayland-protocols mesa-dev libxkbcommon-dev eudev-dev pixman-dev gtkmm3-dev 
jsoncpp-dev libnl3-dev pulseaudio-dev libmpdclient-dev scdoc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/Dockerfiles/archlinux 
new/Waybar-0.9.0/Dockerfiles/archlinux
--- old/Waybar-0.8.0/Dockerfiles/archlinux      2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/Dockerfiles/archlinux      2019-12-28 12:35:09.000000000 
+0100
@@ -1,3 +1,5 @@
+# vim: ft=Dockerfile
+
 FROM archlinux/base:latest
 
 RUN pacman -Syu --noconfirm && \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/Dockerfiles/debian 
new/Waybar-0.9.0/Dockerfiles/debian
--- old/Waybar-0.8.0/Dockerfiles/debian 2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/Dockerfiles/debian 2019-12-28 12:35:09.000000000 +0100
@@ -1,3 +1,5 @@
+# vim: ft=Dockerfile
+
 FROM debian:sid
 
 RUN apt-get update && \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/Dockerfiles/fedora 
new/Waybar-0.9.0/Dockerfiles/fedora
--- old/Waybar-0.8.0/Dockerfiles/fedora 2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/Dockerfiles/fedora 2019-12-28 12:35:09.000000000 +0100
@@ -1,3 +1,5 @@
+# vim: ft=Dockerfile
+
 FROM fedora:30
 
 RUN dnf install sway meson git libinput-devel wayland-devel 
wayland-protocols-devel egl-wayland-devel mesa-libEGL-devel mesa-libGLES-devel 
mesa-libgbm-devel libxkbcommon-devel libudev-devel pixman-devel gtkmm30-devel 
jsoncpp-devel scdoc -y && \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/Dockerfiles/opensuse 
new/Waybar-0.9.0/Dockerfiles/opensuse
--- old/Waybar-0.8.0/Dockerfiles/opensuse       2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/Dockerfiles/opensuse       2019-12-28 12:35:09.000000000 
+0100
@@ -1,3 +1,5 @@
+# vim: ft=Dockerfile
+
 FROM opensuse/tumbleweed:latest
 
 RUN zypper -n up && \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/README.md new/Waybar-0.9.0/README.md
--- old/Waybar-0.8.0/README.md  2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/README.md  2019-12-28 12:35:09.000000000 +0100
@@ -2,7 +2,7 @@
 
 > Highly customizable Wayland bar for Sway and Wlroots based compositors.<br>
 > Available in Arch 
 > [community](https://www.archlinux.org/packages/community/x86_64/waybar/) or
-[AUR](https://aur.archlinux.org/packages/waybar-git/) and 
[openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar)<br>
+[AUR](https://aur.archlinux.org/packages/waybar-git/), 
[openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar), and 
[Alpine Linux](https://pkgs.alpinelinux.org/packages?name=waybar)<br>
 > *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*
 
 **Current features**
@@ -12,6 +12,7 @@
 - Battery
 - Network
 - Pulseaudio
+- Disk
 - Memory
 - Cpu load average
 - Temperature
@@ -55,6 +56,13 @@
 libmpdclient [MPD module]
 ```
 
+On Ubuntu 19.10 you can install all the relevant dependencies using this 
command:
+
+```
+sudo apt install libgtkmm-3.0-dev libjsoncpp-dev libinput-dev 
libsigc++-2.0-dev libpulse-dev libnl-3-dev libdbusmenu-gtk3-dev 
libnl-genl-3-dev libfmt-dev clang-tidy scdoc libmpdclient-dev
+```
+
+
 Contributions welcome! - have fun :)<br>
 The style guidelines is 
[Google's](https://google.github.io/styleguide/cppguide.html)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/include/AModule.hpp 
new/Waybar-0.9.0/include/AModule.hpp
--- old/Waybar-0.8.0/include/AModule.hpp        2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/include/AModule.hpp        2019-12-28 12:35:09.000000000 
+0100
@@ -26,7 +26,6 @@
 
   const Json::Value &config_;
   Gtk::EventBox      event_box_;
-  std::string        click_param_;
 
   virtual bool handleToggle(GdkEventButton *const &ev);
   virtual bool handleScroll(GdkEventScroll *);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/include/bar.hpp 
new/Waybar-0.9.0/include/bar.hpp
--- old/Waybar-0.8.0/include/bar.hpp    2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/include/bar.hpp    2019-12-28 12:35:09.000000000 +0100
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <gdkmm/monitor.h>
 #include <glibmm/refptr.h>
 #include <gtkmm/box.h>
 #include <gtkmm/cssprovider.h>
@@ -15,10 +16,11 @@
 
 class Factory;
 struct waybar_output {
-  struct wl_output *     output = nullptr;
-  std::string            name;
-  uint32_t               wl_name;
-  struct zxdg_output_v1 *xdg_output = nullptr;
+  Glib::RefPtr<Gdk::Monitor> monitor;
+  std::string                name;
+
+  std::unique_ptr<struct zxdg_output_v1, decltype(&zxdg_output_v1_destroy)> 
xdg_output = {
+      nullptr, &zxdg_output_v1_destroy};
 };
 
 class Bar {
@@ -30,13 +32,12 @@
   auto toggle() -> void;
   void handleSignal(int);
 
-  struct waybar_output *        output;
-  Json::Value                   config;
-  Gtk::Window                   window;
-  struct wl_surface *           surface;
-  struct zwlr_layer_surface_v1 *layer_surface;
-  bool                          visible = true;
-  bool                          vertical = false;
+  struct waybar_output *output;
+  Json::Value           config;
+  Gtk::Window           window;
+  struct wl_surface *   surface;
+  bool                  visible = true;
+  bool                  vertical = false;
 
  private:
   static constexpr const char *MIN_HEIGHT_MSG =
@@ -51,11 +52,14 @@
                                           uint32_t, uint32_t);
   static void layerSurfaceHandleClosed(void *, struct zwlr_layer_surface_v1 *);
 
-  void destroyOutput();
+#ifdef HAVE_GTK_LAYER_SHELL
+  void initGtkLayerShell();
+#endif
   void onConfigure(GdkEventConfigure *ev);
   void onRealize();
   void onMap(GdkEventAny *ev);
-  void setMarginsAndZone(uint32_t height, uint32_t width);
+  void setExclusiveZone(uint32_t width, uint32_t height);
+  void setSurfaceSize(uint32_t width, uint32_t height);
   auto setupWidgets() -> void;
   void getModules(const Factory &, const std::string &);
   void setupAltFormatKeyForModule(const std::string &module_name);
@@ -67,6 +71,9 @@
     int bottom = 0;
     int left = 0;
   } margins_;
+  struct zwlr_layer_surface_v1 *layer_surface_;
+  // use gtk-layer-shell instead of handling layer surfaces directly
+  bool                                          use_gls_ = false;
   uint32_t                                      width_ = 0;
   uint32_t                                      height_ = 1;
   uint8_t                                       anchor_;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/include/client.hpp 
new/Waybar-0.9.0/include/client.hpp
--- old/Waybar-0.8.0/include/client.hpp 2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/include/client.hpp 2019-12-28 12:35:09.000000000 +0100
@@ -34,17 +34,15 @@
   bool isValidOutput(const Json::Value &config, std::unique_ptr<struct 
waybar_output> &output);
   auto setupConfig(const std::string &config_file) -> void;
   auto setupCss(const std::string &css_file) -> void;
-  std::unique_ptr<struct waybar_output> &getOutput(uint32_t wl_name);
+  std::unique_ptr<struct waybar_output> &getOutput(void *);
   std::vector<Json::Value> getOutputConfigs(std::unique_ptr<struct 
waybar_output> &output);
 
   static void handleGlobal(void *data, struct wl_registry *registry, uint32_t 
name,
                            const char *interface, uint32_t version);
   static void handleGlobalRemove(void *data, struct wl_registry *registry, 
uint32_t name);
-  static void handleLogicalPosition(void *, struct zxdg_output_v1 *, int32_t, 
int32_t);
-  static void handleLogicalSize(void *, struct zxdg_output_v1 *, int32_t, 
int32_t);
-  static void handleDone(void *, struct zxdg_output_v1 *);
-  static void handleName(void *, struct zxdg_output_v1 *, const char *);
-  static void handleDescription(void *, struct zxdg_output_v1 *, const char *);
+  static void handleOutputName(void *, struct zxdg_output_v1 *, const char *);
+  void        handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor);
+  void        handleMonitorRemoved(Glib::RefPtr<Gdk::Monitor> monitor);
 
   Json::Value                                        config_;
   Glib::RefPtr<Gtk::StyleContext>                    style_context_;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/include/factory.hpp 
new/Waybar-0.9.0/include/factory.hpp
--- old/Waybar-0.8.0/include/factory.hpp        2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/include/factory.hpp        2019-12-28 12:35:09.000000000 
+0100
@@ -13,6 +13,7 @@
 #include "modules/cpu.hpp"
 #include "modules/idle_inhibitor.hpp"
 #include "modules/memory.hpp"
+#include "modules/disk.hpp"
 #if defined(HAVE_DBUSMENU) && !defined(NO_FILESYSTEM)
 #include "modules/sni/tray.hpp"
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/include/modules/disk.hpp 
new/Waybar-0.9.0/include/modules/disk.hpp
--- old/Waybar-0.8.0/include/modules/disk.hpp   1970-01-01 01:00:00.000000000 
+0100
+++ new/Waybar-0.9.0/include/modules/disk.hpp   2019-12-28 12:35:09.000000000 
+0100
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <fmt/format.h>
+#include <fstream>
+#include <sys/statvfs.h>
+#include "ALabel.hpp"
+#include "util/sleeper_thread.hpp"
+#include "util/format.hpp"
+
+namespace waybar::modules {
+
+class Disk : public ALabel {
+ public:
+  Disk(const std::string&, const Json::Value&);
+  ~Disk() = default;
+  auto update() -> void;
+
+ private:
+  util::SleeperThread thread_;
+  std::string path_;
+};
+
+}  // namespace waybar::modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/include/modules/mpd.hpp 
new/Waybar-0.9.0/include/modules/mpd.hpp
--- old/Waybar-0.8.0/include/modules/mpd.hpp    2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/include/modules/mpd.hpp    2019-12-28 12:35:09.000000000 
+0100
@@ -65,6 +65,9 @@
   unique_status status_;
   mpd_state     state_;
   unique_song   song_;
+
+  // To make sure the previous periodic_updater stops before creating a new one
+  std::mutex periodic_lock_;
 };
 
 }  // namespace waybar::modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/include/modules/network.hpp 
new/Waybar-0.9.0/include/modules/network.hpp
--- old/Waybar-0.8.0/include/modules/network.hpp        2019-08-29 
11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/include/modules/network.hpp        2019-12-28 
12:35:09.000000000 +0100
@@ -39,7 +39,7 @@
   void              parseFreq(struct nlattr**);
   bool              associatedOrJoined(struct nlattr**);
   bool              checkInterface(struct ifinfomsg* rtif, std::string name);
-  int               getPreferredIface(int skip_idx = -1) const;
+  int               getPreferredIface(int skip_idx = -1, bool wait = true) 
const;
   auto              getInfo() -> void;
   void              checkNewInterface(struct ifinfomsg* rtif);
   const std::string getNetworkState() const;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/include/util/format.hpp 
new/Waybar-0.9.0/include/util/format.hpp
--- old/Waybar-0.8.0/include/util/format.hpp    1970-01-01 01:00:00.000000000 
+0100
+++ new/Waybar-0.9.0/include/util/format.hpp    2019-12-28 12:35:09.000000000 
+0100
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <fmt/format.h>
+
+class pow_format {
+  public:
+    pow_format(long long val, std::string&& unit, bool binary = false):
+      val_(val), unit_(unit), binary_(binary) { };
+
+    long long val_;
+    std::string unit_;
+    bool binary_;
+};
+
+
+namespace fmt {
+  template <>
+    struct formatter<pow_format> {
+      char spec = 0;
+      int width = 0;
+
+      template <typename ParseContext>
+        constexpr auto parse(ParseContext& ctx) -> decltype (ctx.begin()) {
+          auto it = ctx.begin(), end = ctx.end();
+          if (it != end && *it == ':') ++it;
+          if (*it == '>' || *it == '<' || *it == '=') {
+            spec = *it;
+            ++it;
+          }
+          if (it == end || *it == '}') return it;
+          if ('0' <= *it && *it <= '9') {
+            // We ignore it for now, but keep it for compatibility with
+            // existing configs where the format for pow_format'ed numbers was
+            // 'string' and specifications such as {:>9} were valid.
+            // The rationale for ignoring it is that the only reason to specify
+            // an alignment and a with is to get a fixed width bar, and ">" is
+            // sufficient in this implementation.
+            width = parse_nonnegative_int(it, end, ctx);
+          }
+          return it;
+        }
+
+      template<class FormatContext>
+        auto format(const pow_format& s, FormatContext &ctx) -> decltype 
(ctx.out()) {
+          const char* units[] = { "", "k",  "M",  "G",  "T",  "P",  nullptr};
+
+          auto base = s.binary_ ? 1024ull : 1000ll;
+          auto fraction = (double) s.val_;
+
+          int pow;
+          for (pow = 0; units[pow+1] != nullptr && fraction / base >= 1; 
++pow) {
+            fraction /= base;
+          }
+
+          auto max_width = 4                  // coeff in {:.3g} format
+                         + 1                  // prefix from units array
+                         + s.binary_          // for the 'i' in GiB.
+                         + s.unit_.length();
+
+          const char * format;
+          std::string string;
+          switch (spec) {
+            case '>':
+              return format_to(ctx.out(), "{:>{}}", fmt::format("{}", s), 
max_width);
+            case '<':
+              return format_to(ctx.out(), "{:<{}}", fmt::format("{}", s), 
max_width);
+            case '=':
+              format = "{coefficient:<4.3g}{padding}{prefix}{unit}";
+              break;
+            case 0:
+            default:
+              format = "{coefficient:.3g}{prefix}{unit}";
+              break;
+          }
+          return format_to(ctx.out(), format
+              , fmt::arg("coefficient", fraction)
+              , fmt::arg("prefix", std::string() + units[pow] + ((s.binary_ && 
pow) ? "i" : ""))
+              , fmt::arg("unit", s.unit_)
+              , fmt::arg("padding", pow ? "" : s.binary_ ? "  " : " ")
+            );
+        }
+    };
+}
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/man/waybar-battery.5.scd 
new/Waybar-0.9.0/man/waybar-battery.5.scd
--- old/Waybar-0.8.0/man/waybar-battery.5.scd   2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/man/waybar-battery.5.scd   2019-12-28 12:35:09.000000000 
+0100
@@ -32,6 +32,11 @@
        default: {capacity}% ++
        The format, how the time should be displayed.
 
+*format-time* ++
+       typeof: string ++
+       default: {H} h {M} min ++
+       The format, how the time should be displayed.
+
 *format-icons*
        typeof: array/object
        Based on the current capacity, the corresponding icon gets selected. ++
@@ -78,6 +83,14 @@
 
 *{time}*: Estimate of time until full or empty. Note that this is based on the 
power draw at the last refresh time, not an average.
 
+# TIME FORMAT
+
+The *battery* module allows you to define how time should be formatted via 
*format-time*.
+
+The two arguments are:
+*{H}*: Hours
+*{M}*: Minutes
+
 # CUSTOM FORMATS
 
 The *battery* module allows to define custom formats based on up to two 
factors. The best fitting format will be selected.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/man/waybar-disk.5.scd 
new/Waybar-0.9.0/man/waybar-disk.5.scd
--- old/Waybar-0.8.0/man/waybar-disk.5.scd      1970-01-01 01:00:00.000000000 
+0100
+++ new/Waybar-0.9.0/man/waybar-disk.5.scd      2019-12-28 12:35:09.000000000 
+0100
@@ -0,0 +1,93 @@
+waybar-disk(5)
+
+# NAME
+
+waybar - disk module
+
+# DESCRIPTION
+
+The *disk* module displays the current disk space used.
+
+# CONFIGURATION
+
+Addressed by *disk*
+
+*path*: ++
+       typeof: string ++
+       default: "/" ++
+       Any path residing in the filesystem or mountpoint for which the 
information should be displayed.
+
+*interval*: ++
+       typeof: integer++
+       default: 30 ++
+       The interval in which the information gets polled.
+
+*format*: ++
+       typeof: string ++
+       default: "{percentage_used}%" ++
+       The format, how information should be displayed.
+
+*rotate*: ++
+       typeof: integer ++
+       Positive value to rotate the text label.
+
+*max-length*: ++
+       typeof: integer ++
+       The maximum length in character the module should display.
+
+*on-click*: ++
+       typeof: string ++
+       Command to execute when clicked on the module.
+
+*on-click-right*: ++
+       typeof: string ++
+       Command to execute when you right clicked on the module.
+
+*on-scroll-up*: ++
+       typeof: string ++
+       Command to execute when scrolling up on the module.
+
+*on-scroll-down*: ++
+       typeof: string ++
+       Command to execute when scrolling down on the module.
+
+*smooth-scrolling-threshold*: ++
+       typeof: double ++
+       Threshold to be used when scrolling.
+
+*tooltip*: ++
+       typeof: bool ++
+       default: true ++
+       Option to disable tooltip on hover.
+
+*tooltip-format*: ++
+       typeof: string ++
+       default: "{used} out of {total} used ({percentage_used}%)" ++
+       The format of the information displayed in the tooltip.
+
+# FORMAT REPLACEMENTS
+
+*{percentage_used}*: Percentage of disk in use.
+
+*{percentage_free}*: Percentage of free disk space
+
+*{total}*: Total amount of space on the disk, partition or mountpoint.
+
+*{used}*: Amount of used disk space.
+
+*{free}*: Amount of available disk space for normal users.
+
+*{path}*: The path specified in the configuration.
+
+# EXAMPLES
+
+```
+"disk": {
+       "interval": 30,
+       "format": "{percentage_free}% free on {path}",
+}
+```
+
+# STYLE
+
+- *#disk*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/man/waybar-memory.5.scd 
new/Waybar-0.9.0/man/waybar-memory.5.scd
--- old/Waybar-0.8.0/man/waybar-memory.5.scd    2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/man/waybar-memory.5.scd    2019-12-28 12:35:09.000000000 
+0100
@@ -6,7 +6,7 @@
 
 # DESCRIPTION
 
-The *memory* module displays the current date and time.
+The *memory* module displays the current memory utilization.
 
 # CONFIGURATION
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/man/waybar-pulseaudio.5.scd 
new/Waybar-0.9.0/man/waybar-pulseaudio.5.scd
--- old/Waybar-0.8.0/man/waybar-pulseaudio.5.scd        2019-08-29 
11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/man/waybar-pulseaudio.5.scd        2019-12-28 
12:35:09.000000000 +0100
@@ -36,7 +36,7 @@
 
 *format-icons*: ++
        typeof: array ++
-       Based on the current port-name and volume, the corresponding icon gets 
selected. The order is *low* to *high*. See 
[`Icons`](#module-pulseaudio-config-icons)
+       Based on the current port-name and volume, the corresponding icon gets 
selected. The order is *low* to *high*. See *Icons*.
 
 *rotate*: ++
        typeof: integer ++
@@ -82,15 +82,17 @@
 
 # FORMAT REPLACEMENTS
 
+*{desc}*: Pulseaudio port's description, for bluetooth it'll be the device 
name.
+
 *{volume}*: Volume in percentage.
 
-*{icon}*: Icon, as defined in `format-icons`.
+*{icon}*: Icon, as defined in *format-icons*.
 
-*{format_source}*: Source format, `format-source`, `format-source-muted`.
+*{format_source}*: Source format, *format-source*, *format-source-muted*.
 
 # ICONS:
 
-The following strings for `format-icons` are supported.
+The following strings for *format-icons* are supported.
 If they are found in the current PulseAudio port name, the corresponding icons 
will be selected.
 
 - *default* (Shown, when no other port is found)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/man/waybar-states.5.scd 
new/Waybar-0.9.0/man/waybar-states.5.scd
--- old/Waybar-0.8.0/man/waybar-states.5.scd    2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/man/waybar-states.5.scd    2019-12-28 12:35:09.000000000 
+0100
@@ -7,7 +7,7 @@
 
 # STATES
 
-- Every entry (*state*) consits of a *<name>* (typeof: *string*) and a 
*<value>* (typeof: *integer*).
+- Every entry (*state*) consists of a *<name>* (typeof: *string*) and a 
*<value>* (typeof: *integer*).
 
        - The state can be addressed as a CSS class in the *style.css*. The 
name of the CSS class is the *<name>* of the state.
          Each class gets activated when the current capacity is equal or below 
the configured *<value>*.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/man/waybar-sway-workspaces.5.scd 
new/Waybar-0.9.0/man/waybar-sway-workspaces.5.scd
--- old/Waybar-0.8.0/man/waybar-sway-workspaces.5.scd   2019-08-29 
11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/man/waybar-sway-workspaces.5.scd   2019-12-28 
12:35:09.000000000 +0100
@@ -76,15 +76,15 @@
 - *urgent*: Will be shown, when workspace is flagged as urgent
 - *focused*: Will be shown, when workspace is focused
 
-# PERSISTANT WORKSPACES
+# PERSISTENT WORKSPACES
 
-Each entry of *persistant_workspace* names a workspace that should always be 
shown.
+Each entry of *persistent_workspace* names a workspace that should always be 
shown.
 Associated with that value is a list of outputs indicating *where* the 
workspace should be shown,
 an empty list denoting all outputs.
 
 ```
 "sway/workspaces": {
-    "persistant_workspaces": {
+    "persistent_workspaces": {
         "3": [], // Always show a workspace with name '3', on all outputs if 
it does not exists
         "4": ["eDP-1"], // Always show a workspace with name '4', on output 
'eDP-1' if it does not exists
         "5": ["eDP-1", "DP-2"] // Always show a workspace with name '5', on 
outputs 'eDP-1' and 'DP-2' if it does not exists
@@ -120,4 +120,4 @@
 - *#workspaces button.visible*
 - *#workspaces button.focused*
 - *#workspaces button.urgent*
-- *#workspaces button.persistant*
+- *#workspaces button.persistent*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/meson.build new/Waybar-0.9.0/meson.build
--- old/Waybar-0.8.0/meson.build        2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/meson.build        2019-12-28 12:35:09.000000000 +0100
@@ -1,6 +1,6 @@
 project(
     'waybar', 'cpp', 'c',
-    version: '0.8.0',
+    version: '0.9.0',
     license: 'MIT',
     default_options : [
         'cpp_std=c++17',
@@ -52,7 +52,7 @@
 wayland_client = dependency('wayland-client')
 wayland_cursor = dependency('wayland-cursor')
 wayland_protos = dependency('wayland-protocols')
-gtkmm = dependency('gtkmm-3.0')
+gtkmm = dependency('gtkmm-3.0', version : ['>=3.22.0'])
 dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: 
get_option('dbusmenu-gtk'))
 giounix = dependency('gio-unix-2.0', required: get_option('dbusmenu-gtk'))
 jsoncpp = dependency('jsoncpp')
@@ -62,6 +62,25 @@
 libpulse = dependency('libpulse', required: get_option('pulseaudio'))
 libudev = dependency('libudev', required: get_option('libudev'))
 libmpdclient = dependency('libmpdclient', required: get_option('mpd'))
+gtk_layer_shell = dependency('gtk-layer-shell-0',
+        required: get_option('gtk-layer-shell'),
+        fallback : ['gtk-layer-shell', 'gtk_layer_shell_dep'])
+systemd = dependency('systemd', required: get_option('systemd'))
+
+prefix = get_option('prefix')
+conf_data = configuration_data()
+conf_data.set('prefix', prefix)
+
+if systemd.found()
+  user_units_dir = systemd.get_pkgconfig_variable('systemduserunitdir')
+
+  configure_file(
+    configuration: conf_data,
+    input: './resources/waybar.service.in',
+    output: '@BASENAME@',
+    install_dir: user_units_dir
+  )
+endif
 
 src_files = files(
     'src/factory.cpp',
@@ -72,6 +91,7 @@
     'src/modules/clock.cpp',
     'src/modules/custom.cpp',
     'src/modules/cpu.cpp',
+    'src/modules/disk.cpp',
     'src/modules/idle_inhibitor.cpp',
     'src/modules/temperature.cpp',
     'src/main.cpp',
@@ -119,6 +139,10 @@
     src_files += 'src/modules/mpd.cpp'
 endif
 
+if gtk_layer_shell.found()
+    add_project_arguments('-DHAVE_GTK_LAYER_SHELL', language: 'cpp')
+endif
+
 subdir('protocol')
 
 executable(
@@ -141,7 +165,8 @@
         libnlgen,
         libpulse,
         libudev,
-        libmpdclient
+        libmpdclient,
+        gtk_layer_shell
     ],
     include_directories: [include_directories('include')],
     install: true,
@@ -153,7 +178,7 @@
     install_dir: join_paths(get_option('out'), 'etc/xdg/waybar')
 )
 
-scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: false)
+scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: 
get_option('man-pages'))
 
 if scdoc.found()
     scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: 
true)
@@ -166,6 +191,7 @@
         'waybar-clock.5.scd',
         'waybar-cpu.5.scd',
         'waybar-custom.5.scd',
+        'waybar-disk.5.scd',
         'waybar-idle-inhibitor.5.scd',
         'waybar-memory.5.scd',
         'waybar-mpd.5.scd',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/meson_options.txt 
new/Waybar-0.9.0/meson_options.txt
--- old/Waybar-0.8.0/meson_options.txt  2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/meson_options.txt  2019-12-28 12:35:09.000000000 +0100
@@ -2,6 +2,9 @@
 option('libnl', type: 'feature', value: 'auto', description: 'Enable libnl 
support for network related features')
 option('libudev', type: 'feature', value: 'auto', description: 'Enable libudev 
support for udev related features')
 option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable 
support for pulseaudio')
+option('systemd', type: 'feature', value: 'auto', description: 'Install 
systemd user service unit')
 option('dbusmenu-gtk', type: 'feature', value: 'auto', description: 'Enable 
support for tray')
+option('man-pages', type: 'feature', value: 'auto', description: 'Generate and 
install man pages')
 option('mpd', type: 'feature', value: 'auto', description: 'Enable support for 
the Music Player Daemon')
 option('out', type: 'string', value : '/', description: 'output prefix 
directory')
+option('gtk-layer-shell', type: 'feature', value: 'auto', description: 'Use 
gtk-layer-shell library for popups support')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/resources/style.css 
new/Waybar-0.9.0/resources/style.css
--- old/Waybar-0.8.0/resources/style.css        2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/resources/style.css        2019-12-28 12:35:09.000000000 
+0100
@@ -1,6 +1,7 @@
 * {
     border: none;
     border-radius: 0;
+    /* `otf-font-awesome` is required to be installed for icons */
     font-family: Roboto, Helvetica, Arial, sans-serif;
     font-size: 13px;
     min-height: 0;
@@ -75,7 +76,8 @@
 #custom-media,
 #tray,
 #mode,
-#idle_inhibitor {
+#idle_inhibitor,
+#mpd {
     padding: 0 10px;
     margin: 0 4px;
     color: #ffffff;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/resources/waybar.service.in 
new/Waybar-0.9.0/resources/waybar.service.in
--- old/Waybar-0.8.0/resources/waybar.service.in        1970-01-01 
01:00:00.000000000 +0100
+++ new/Waybar-0.9.0/resources/waybar.service.in        2019-12-28 
12:35:09.000000000 +0100
@@ -0,0 +1,12 @@
+[Unit]
+Description=Highly customizable Wayland bar for Sway and Wlroots based 
compositors.
+Documentation=https://github.com/Alexays/Waybar/wiki/
+PartOf=wayland-session.target
+
+[Service]
+Type=dbus
+BusName=fr.arouillard.waybar
+ExecStart=@prefix@/bin/waybar
+
+[Install]
+WantedBy=wayland-session.target
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/AModule.cpp 
new/Waybar-0.9.0/src/AModule.cpp
--- old/Waybar-0.8.0/src/AModule.cpp    2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/src/AModule.cpp    2019-12-28 12:35:09.000000000 +0100
@@ -46,7 +46,7 @@
     format = config_["on-click-forward"].asString();
   }
   if (!format.empty()) {
-    pid_.push_back(util::command::forkExec(fmt::format(format, fmt::arg("arg", 
click_param_))));
+    pid_.push_back(util::command::forkExec(format));
   }
   dp.emit();
   return true;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/bar.cpp new/Waybar-0.9.0/src/bar.cpp
--- old/Waybar-0.8.0/src/bar.cpp        2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/src/bar.cpp        2019-12-28 12:35:09.000000000 +0100
@@ -1,3 +1,7 @@
+#ifdef HAVE_GTK_LAYER_SHELL
+#include <gtk-layer-shell.h>
+#endif
+
 #include "bar.hpp"
 #include "client.hpp"
 #include "factory.hpp"
@@ -8,7 +12,7 @@
       config(w_config),
       window{Gtk::WindowType::WINDOW_TOPLEVEL},
       surface(nullptr),
-      layer_surface(nullptr),
+      layer_surface_(nullptr),
       anchor_(ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP),
       left_(Gtk::ORIENTATION_HORIZONTAL, 0),
       center_(Gtk::ORIENTATION_HORIZONTAL, 0),
@@ -28,11 +32,6 @@
   height_ = config["height"].isUInt() ? config["height"].asUInt() : height_;
   width_ = config["width"].isUInt() ? config["width"].asUInt() : width_;
 
-  window.signal_realize().connect_notify(sigc::mem_fun(*this, 
&Bar::onRealize));
-  window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap));
-  window.signal_configure_event().connect_notify(sigc::mem_fun(*this, 
&Bar::onConfigure));
-  window.set_size_request(width_, height_);
-
   if (config["position"] == "bottom") {
     anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
   } else if (config["position"] == "left") {
@@ -53,6 +52,62 @@
     vertical = true;
   }
 
+  if (config["margin-top"].isInt() || config["margin-right"].isInt() ||
+      config["margin-bottom"].isInt() || config["margin-left"].isInt()) {
+    margins_ = {
+        config["margin-top"].isInt() ? config["margin-top"].asInt() : 0,
+        config["margin-right"].isInt() ? config["margin-right"].asInt() : 0,
+        config["margin-bottom"].isInt() ? config["margin-bottom"].asInt() : 0,
+        config["margin-left"].isInt() ? config["margin-left"].asInt() : 0,
+    };
+  } else if (config["margin"].isString()) {
+    std::istringstream       iss(config["margin"].asString());
+    std::vector<std::string> margins{std::istream_iterator<std::string>(iss), 
{}};
+    try {
+      if (margins.size() == 1) {
+        auto gaps = std::stoi(margins[0], nullptr, 10);
+        margins_ = {.top = gaps, .right = gaps, .bottom = gaps, .left = gaps};
+      }
+      if (margins.size() == 2) {
+        auto vertical_margins = std::stoi(margins[0], nullptr, 10);
+        auto horizontal_margins = std::stoi(margins[1], nullptr, 10);
+        margins_ = {.top = vertical_margins,
+                    .right = horizontal_margins,
+                    .bottom = vertical_margins,
+                    .left = horizontal_margins};
+      }
+      if (margins.size() == 3) {
+        auto horizontal_margins = std::stoi(margins[1], nullptr, 10);
+        margins_ = {.top = std::stoi(margins[0], nullptr, 10),
+                    .right = horizontal_margins,
+                    .bottom = std::stoi(margins[2], nullptr, 10),
+                    .left = horizontal_margins};
+      }
+      if (margins.size() == 4) {
+        margins_ = {.top = std::stoi(margins[0], nullptr, 10),
+                    .right = std::stoi(margins[1], nullptr, 10),
+                    .bottom = std::stoi(margins[2], nullptr, 10),
+                    .left = std::stoi(margins[3], nullptr, 10)};
+      }
+    } catch (...) {
+      spdlog::warn("Invalid margins: {}", config["margin"].asString());
+    }
+  } else if (config["margin"].isInt()) {
+    auto gaps = config["margin"].asInt();
+    margins_ = {.top = gaps, .right = gaps, .bottom = gaps, .left = gaps};
+  }
+
+#ifdef HAVE_GTK_LAYER_SHELL
+  use_gls_ = config["gtk-layer-shell"].isBool() ? 
config["gtk-layer-shell"].asBool() : true;
+  if (use_gls_) {
+    initGtkLayerShell();
+  }
+#endif
+
+  window.signal_realize().connect_notify(sigc::mem_fun(*this, 
&Bar::onRealize));
+  window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap));
+  window.signal_configure_event().connect_notify(sigc::mem_fun(*this, 
&Bar::onConfigure));
+  window.set_size_request(width_, height_);
   setupWidgets();
 
   if (window.get_realized()) {
@@ -86,11 +141,43 @@
       tmp_width = ev->width;
     }
   }
-  if (tmp_width != width_ || tmp_height != height_) {
-    zwlr_layer_surface_v1_set_size(layer_surface, tmp_width, tmp_height);
+  if (use_gls_) {
+    width_ = tmp_width;
+    height_ = tmp_height;
+    spdlog::debug("Set surface size {}x{} for output {}", width_, height_, 
output->name);
+    setExclusiveZone(tmp_width, tmp_height);
+  } else if (tmp_width != width_ || tmp_height != height_) {
+    setSurfaceSize(tmp_width, tmp_height);
   }
 }
 
+#ifdef HAVE_GTK_LAYER_SHELL
+void waybar::Bar::initGtkLayerShell() {
+  auto gtk_window = window.gobj();
+  // this has to be executed before GtkWindow.realize
+  gtk_layer_init_for_window(gtk_window);
+  gtk_layer_set_keyboard_interactivity(gtk_window, FALSE);
+  auto layer = config["layer"] == "top" ? GTK_LAYER_SHELL_LAYER_TOP : 
GTK_LAYER_SHELL_LAYER_BOTTOM;
+  gtk_layer_set_layer(gtk_window, layer);
+  gtk_layer_set_monitor(gtk_window, output->monitor->gobj());
+  gtk_layer_set_namespace(gtk_window, "waybar");
+
+  gtk_layer_set_anchor(
+      gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, anchor_ & 
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
+  gtk_layer_set_anchor(
+      gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, anchor_ & 
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
+  gtk_layer_set_anchor(
+      gtk_window, GTK_LAYER_SHELL_EDGE_TOP, anchor_ & 
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP);
+  gtk_layer_set_anchor(
+      gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, anchor_ & 
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM);
+
+  gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, margins_.left);
+  gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, margins_.right);
+  gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_TOP, margins_.top);
+  gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, 
margins_.bottom);
+}
+#endif
+
 void waybar::Bar::onRealize() {
   auto gdk_window = window.get_window()->gobj();
   gdk_wayland_window_set_use_custom_surface(gdk_window);
@@ -100,75 +187,74 @@
   auto gdk_window = window.get_window()->gobj();
   surface = gdk_wayland_window_get_wl_surface(gdk_window);
 
+  if (use_gls_) {
+    return;
+  }
+
   auto client = waybar::Client::inst();
+  // owned by output->monitor; no need to destroy
+  auto wl_output = gdk_wayland_monitor_get_wl_output(output->monitor->gobj());
   auto layer =
       config["layer"] == "top" ? ZWLR_LAYER_SHELL_V1_LAYER_TOP : 
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
-  layer_surface = zwlr_layer_shell_v1_get_layer_surface(
-      client->layer_shell, surface, output->output, layer, "waybar");
+  layer_surface_ = zwlr_layer_shell_v1_get_layer_surface(
+      client->layer_shell, surface, wl_output, layer, "waybar");
+
+  zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface_, false);
+  zwlr_layer_surface_v1_set_anchor(layer_surface_, anchor_);
+  zwlr_layer_surface_v1_set_margin(
+      layer_surface_, margins_.top, margins_.right, margins_.bottom, 
margins_.left);
+  setSurfaceSize(width_, height_);
+  setExclusiveZone(width_, height_);
 
-  zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface, false);
-  zwlr_layer_surface_v1_set_anchor(layer_surface, anchor_);
-  zwlr_layer_surface_v1_set_size(layer_surface, width_, height_);
-  setMarginsAndZone(height_, width_);
   static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
       .configure = layerSurfaceHandleConfigure,
       .closed = layerSurfaceHandleClosed,
   };
-  zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, 
this);
+  zwlr_layer_surface_v1_add_listener(layer_surface_, &layer_surface_listener, 
this);
 
   wl_surface_commit(surface);
   wl_display_roundtrip(client->wl_display);
 }
 
-void waybar::Bar::setMarginsAndZone(uint32_t height, uint32_t width) {
-  if (config["margin-top"].isInt() || config["margin-right"].isInt() ||
-      config["margin-bottom"].isInt() || config["margin-left"].isInt()) {
-    margins_ = {
-        config["margin-top"].isInt() ? config["margin-top"].asInt() : 0,
-        config["margin-right"].isInt() ? config["margin-right"].asInt() : 0,
-        config["margin-bottom"].isInt() ? config["margin-bottom"].asInt() : 0,
-        config["margin-left"].isInt() ? config["margin-left"].asInt() : 0,
-    };
-  } else if (config["margin"].isString()) {
-    std::istringstream       iss(config["margin"].asString());
-    std::vector<std::string> margins{std::istream_iterator<std::string>(iss), 
{}};
-    try {
-      if (margins.size() == 1) {
-        auto gaps = std::stoi(margins[0], nullptr, 10);
-        margins_ = {.top = gaps, .right = gaps, .bottom = gaps, .left = gaps};
-      }
-      if (margins.size() == 2) {
-        auto vertical_margins = std::stoi(margins[0], nullptr, 10);
-        auto horizontal_margins = std::stoi(margins[1], nullptr, 10);
-        margins_ = {.top = vertical_margins,
-                    .right = horizontal_margins,
-                    .bottom = vertical_margins,
-                    .left = horizontal_margins};
-      }
-      if (margins.size() == 3) {
-        auto horizontal_margins = std::stoi(margins[1], nullptr, 10);
-        margins_ = {.top = std::stoi(margins[0], nullptr, 10),
-                    .right = horizontal_margins,
-                    .bottom = std::stoi(margins[2], nullptr, 10),
-                    .left = horizontal_margins};
-      }
-      if (margins.size() == 4) {
-        margins_ = {.top = std::stoi(margins[0], nullptr, 10),
-                    .right = std::stoi(margins[1], nullptr, 10),
-                    .bottom = std::stoi(margins[2], nullptr, 10),
-                    .left = std::stoi(margins[3], nullptr, 10)};
-      }
-    } catch (...) {
-      spdlog::warn("Invalid margins: {}", config["margin"].asString());
+void waybar::Bar::setExclusiveZone(uint32_t width, uint32_t height) {
+  auto zone = 0;
+  if (visible) {
+    // exclusive zone already includes margin for anchored edge,
+    // only opposite margin should be added
+    if (vertical) {
+      zone += width;
+      zone += (anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) ? margins_.right : 
margins_.left;
+    } else {
+      zone += height;
+      zone += (anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) ? margins_.bottom : 
margins_.top;
     }
-  } else if (config["margin"].isInt()) {
-    auto gaps = config["margin"].asInt();
-    margins_ = {.top = gaps, .right = gaps, .bottom = gaps, .left = gaps};
   }
-  zwlr_layer_surface_v1_set_margin(
-      layer_surface, margins_.top, margins_.right, margins_.bottom, 
margins_.left);
-  auto zone = vertical ? width + margins_.right : height + margins_.bottom;
-  zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, zone);
+  spdlog::debug("Set exclusive zone {} for output {}", zone, output->name);
+
+#ifdef HAVE_GTK_LAYER_SHELL
+  if (use_gls_) {
+    gtk_layer_set_exclusive_zone(window.gobj(), zone);
+  } else
+#endif
+  {
+    zwlr_layer_surface_v1_set_exclusive_zone(layer_surface_, zone);
+  }
+}
+
+void waybar::Bar::setSurfaceSize(uint32_t width, uint32_t height) {
+  /* If the client is anchored to two opposite edges, layer_surface.configure 
will return
+   * size without margins for the axis.
+   * layer_surface.set_size, however, expects size with margins for the 
anchored axis.
+   * This is not specified by wlr-layer-shell and based on actual behavior of 
sway.
+   */
+  if (vertical && height > 1) {
+    height += margins_.top + margins_.bottom;
+  }
+  if (!vertical && width > 1) {
+    width += margins_.right + margins_.left;
+  }
+  spdlog::debug("Set surface size {}x{} for output {}", width, height, 
output->name);
+  zwlr_layer_surface_v1_set_size(layer_surface_, width, height);
 }
 
 // Converting string to button code rn as to avoid doing it later
@@ -240,8 +326,7 @@
     o->height_ = height;
     o->window.set_size_request(o->width_, o->height_);
     o->window.resize(o->width_, o->height_);
-    auto zone = o->vertical ? width + o->margins_.right : height + 
o->margins_.bottom;
-    zwlr_layer_surface_v1_set_exclusive_zone(o->layer_surface, zone);
+    o->setExclusiveZone(width, height);
     spdlog::info(BAR_SIZE_MSG,
                  o->width_ == 1 ? "auto" : std::to_string(o->width_),
                  o->height_ == 1 ? "auto" : std::to_string(o->height_),
@@ -253,9 +338,9 @@
 
 void waybar::Bar::layerSurfaceHandleClosed(void* data, struct 
zwlr_layer_surface_v1* /*surface*/) {
   auto o = static_cast<waybar::Bar*>(data);
-  if (o->layer_surface) {
-    zwlr_layer_surface_v1_destroy(o->layer_surface);
-    o->layer_surface = nullptr;
+  if (o->layer_surface_) {
+    zwlr_layer_surface_v1_destroy(o->layer_surface_);
+    o->layer_surface_ = nullptr;
   }
   o->modules_left_.clear();
   o->modules_center_.clear();
@@ -264,13 +349,14 @@
 
 auto waybar::Bar::toggle() -> void {
   visible = !visible;
-  auto zone = visible ? height_ : 0;
   if (!visible) {
     window.get_style_context()->add_class("hidden");
+    window.set_opacity(0);
   } else {
     window.get_style_context()->remove_class("hidden");
+    window.set_opacity(1);
   }
-  zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, zone);
+  setExclusiveZone(width_, height_);
   wl_surface_commit(surface);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/client.cpp 
new/Waybar-0.9.0/src/client.cpp
--- old/Waybar-0.8.0/src/client.cpp     2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/src/client.cpp     2019-12-28 12:35:09.000000000 +0100
@@ -1,4 +1,5 @@
 #include "client.hpp"
+#include <fmt/ostream.h>
 #include <spdlog/spdlog.h>
 #include <fstream>
 #include <iostream>
@@ -33,11 +34,6 @@
   if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
     client->layer_shell = static_cast<struct zwlr_layer_shell_v1 *>(
         wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 
version));
-  } else if (strcmp(interface, wl_output_interface.name) == 0) {
-    auto wl_output = static_cast<struct wl_output *>(
-        wl_registry_bind(registry, name, &wl_output_interface, version));
-    client->outputs_.emplace_back(new struct waybar_output({wl_output, "", 
name, nullptr}));
-    client->handleOutput(client->outputs_.back());
   } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 &&
              version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
     client->xdg_output_manager = static_cast<struct zxdg_output_manager_v1 
*>(wl_registry_bind(
@@ -50,58 +46,21 @@
 
 void waybar::Client::handleGlobalRemove(void *   data, struct wl_registry * 
/*registry*/,
                                         uint32_t name) {
-  auto client = static_cast<Client *>(data);
-  for (auto it = client->bars.begin(); it != client->bars.end();) {
-    if ((*it)->output->wl_name == name) {
-      auto output_name = (*it)->output->name;
-      (*it)->window.close();
-      it = client->bars.erase(it);
-      spdlog::info("Bar removed from output: {}", output_name);
-    } else {
-      ++it;
-    }
-  }
-  auto it = std::find_if(client->outputs_.begin(),
-                         client->outputs_.end(),
-                         [&name](const auto &output) { return output->wl_name 
== name; });
-  if (it != client->outputs_.end()) {
-    if ((*it)->xdg_output != nullptr) {
-      zxdg_output_v1_destroy((*it)->xdg_output);
-      (*it)->xdg_output = nullptr;
-    }
-    if ((*it)->output != nullptr) {
-      wl_output_destroy((*it)->output);
-      (*it)->output = nullptr;
-    }
-    client->outputs_.erase(it);
-  }
+  // Nothing here
 }
 
 void waybar::Client::handleOutput(std::unique_ptr<struct waybar_output> 
&output) {
   static const struct zxdg_output_v1_listener xdgOutputListener = {
-      .logical_position = handleLogicalPosition,
-      .logical_size = handleLogicalSize,
-      .done = handleDone,
-      .name = handleName,
-      .description = handleDescription,
+      .logical_position = [](void *, struct zxdg_output_v1 *, int32_t, 
int32_t) {},
+      .logical_size = [](void *, struct zxdg_output_v1 *, int32_t, int32_t) {},
+      .done = [](void *, struct zxdg_output_v1 *) {},
+      .name = &handleOutputName,
+      .description = [](void *, struct zxdg_output_v1 *, const char *) {},
   };
-  output->xdg_output = 
zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, output->output);
-  zxdg_output_v1_add_listener(output->xdg_output, &xdgOutputListener, 
&output->wl_name);
-}
-
-void waybar::Client::handleLogicalPosition(void * /*data*/,
-                                           struct zxdg_output_v1 * 
/*zxdg_output_v1*/,
-                                           int32_t /*x*/, int32_t /*y*/) {
-  // Nothing here
-}
-
-void waybar::Client::handleLogicalSize(void * /*data*/, struct zxdg_output_v1 
* /*zxdg_output_v1*/,
-                                       int32_t /*width*/, int32_t /*height*/) {
-  // Nothing here
-}
-
-void waybar::Client::handleDone(void * /*data*/, struct zxdg_output_v1 * 
/*zxdg_output_v1*/) {
-  // Nothing here
+  // owned by output->monitor; no need to destroy
+  auto wl_output = gdk_wayland_monitor_get_wl_output(output->monitor->gobj());
+  
output->xdg_output.reset(zxdg_output_manager_v1_get_xdg_output(xdg_output_manager,
 wl_output));
+  zxdg_output_v1_add_listener(output->xdg_output.get(), &xdgOutputListener, 
output.get());
 }
 
 bool waybar::Client::isValidOutput(const Json::Value &                    
config,
@@ -123,9 +82,9 @@
   return found;
 }
 
-std::unique_ptr<struct waybar::waybar_output> 
&waybar::Client::getOutput(uint32_t wl_name) {
-  auto it = std::find_if(outputs_.begin(), outputs_.end(), [&wl_name](const 
auto &output) {
-    return output->wl_name == wl_name;
+std::unique_ptr<struct waybar::waybar_output> &waybar::Client::getOutput(void 
*addr) {
+  auto it = std::find_if(outputs_.begin(), outputs_.end(), [&addr](const auto 
&output) {
+    return output.get() == addr;
   });
   if (it == outputs_.end()) {
     throw std::runtime_error("Unable to find valid output");
@@ -148,23 +107,19 @@
   return configs;
 }
 
-void waybar::Client::handleName(void *      data, struct zxdg_output_v1 * 
/*xdg_output*/,
-                                const char *name) {
-  auto wl_name = *static_cast<uint32_t *>(data);
+void waybar::Client::handleOutputName(void *      data, struct zxdg_output_v1 
* /*xdg_output*/,
+                                      const char *name) {
   auto client = waybar::Client::inst();
   try {
-    auto &output = client->getOutput(wl_name);
+    auto &output = client->getOutput(data);
     output->name = name;
+    spdlog::debug("Output detected: {} ({} {})",
+                  name,
+                  output->monitor->get_manufacturer(),
+                  output->monitor->get_model());
     auto configs = client->getOutputConfigs(output);
     if (configs.empty()) {
-      if (output->output != nullptr) {
-        wl_output_destroy(output->output);
-        output->output = nullptr;
-      }
-      if (output->xdg_output != nullptr) {
-        zxdg_output_v1_destroy(output->xdg_output);
-        output->xdg_output = nullptr;
-      }
+      output->xdg_output.reset();
     } else {
       wl_display_roundtrip(client->wl_display);
       for (const auto &config : configs) {
@@ -179,9 +134,26 @@
   }
 }
 
-void waybar::Client::handleDescription(void * /*data*/, struct zxdg_output_v1 
* /*zxdg_output_v1*/,
-                                       const char * /*description*/) {
-  // Nothing here
+void waybar::Client::handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor) {
+  auto &output = outputs_.emplace_back(new struct waybar_output({monitor}));
+  handleOutput(output);
+}
+
+void waybar::Client::handleMonitorRemoved(Glib::RefPtr<Gdk::Monitor> monitor) {
+  spdlog::debug("Output removed: {} {}", monitor->get_manufacturer(), 
monitor->get_model());
+  for (auto it = bars.begin(); it != bars.end();) {
+    if ((*it)->output->monitor == monitor) {
+      auto output_name = (*it)->output->name;
+      (*it)->window.close();
+      it = bars.erase(it);
+      spdlog::info("Bar removed from output: {}", output_name);
+    } else {
+      ++it;
+    }
+  }
+  std::remove_if(outputs_.begin(), outputs_.end(), [&monitor](const auto 
&output) {
+    return output->monitor == monitor;
+  });
 }
 
 std::tuple<const std::string, const std::string> waybar::Client::getConfigs(
@@ -240,6 +212,14 @@
   if (layer_shell == nullptr || xdg_output_manager == nullptr) {
     throw std::runtime_error("Failed to acquire required resources.");
   }
+  // add existing outputs and subscribe to updates
+  for (auto i = 0; i < gdk_display->get_n_monitors(); ++i) {
+    auto monitor = gdk_display->get_monitor(i);
+    handleMonitorAdded(monitor);
+  }
+  gdk_display->signal_monitor_added().connect(sigc::mem_fun(*this, 
&Client::handleMonitorAdded));
+  gdk_display->signal_monitor_removed().connect(
+      sigc::mem_fun(*this, &Client::handleMonitorRemoved));
 }
 
 int waybar::Client::main(int argc, char *argv[]) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/factory.cpp 
new/Waybar-0.9.0/src/factory.cpp
--- old/Waybar-0.8.0/src/factory.cpp    2019-08-29 11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/src/factory.cpp    2019-12-28 12:35:09.000000000 +0100
@@ -35,6 +35,9 @@
     if (ref == "clock") {
       return new waybar::modules::Clock(id, config_[name]);
     }
+    if (ref == "disk") {
+      return new waybar::modules::Disk(id, config_[name]);
+    }
 #if defined(HAVE_DBUSMENU) && !defined(NO_FILESYSTEM)
     if (ref == "tray") {
       return new waybar::modules::SNI::Tray(id, bar_, config_[name]);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/modules/battery.cpp 
new/Waybar-0.9.0/src/modules/battery.cpp
--- old/Waybar-0.8.0/src/modules/battery.cpp    2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/src/modules/battery.cpp    2019-12-28 12:35:09.000000000 
+0100
@@ -130,7 +130,7 @@
       return "Full";
     }
     if (online) {
-      return "Charging";
+      return "Plugged";
     }
     return "Discharging";
   }
@@ -141,7 +141,11 @@
   hoursRemaining = std::fabs(hoursRemaining);
   uint16_t full_hours = static_cast<uint16_t>(hoursRemaining);
   uint16_t minutes = static_cast<uint16_t>(60 * (hoursRemaining - full_hours));
-  return std::to_string(full_hours) + " h " + std::to_string(minutes) + " min";
+  auto format = std::string("{H} h {M} min");
+  if (config_["format-time"].isString()) {
+    format = config_["format-time"].asString();
+  }
+  return fmt::format(format, fmt::arg("H", full_hours), fmt::arg("M", 
minutes));
 }
 
 auto waybar::modules::Battery::update() -> void {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/modules/clock.cpp 
new/Waybar-0.9.0/src/modules/clock.cpp
--- old/Waybar-0.8.0/src/modules/clock.cpp      2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/src/modules/clock.cpp      2019-12-28 12:35:09.000000000 
+0100
@@ -1,4 +1,5 @@
 #include "modules/clock.hpp"
+#include <time.h>
 
 waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
     : ALabel(config, "clock", id, "{:%H:%M}", 60) {
@@ -12,6 +13,7 @@
 }
 
 auto waybar::modules::Clock::update() -> void {
+  tzset(); // Update timezone information
   auto now = std::chrono::system_clock::now();
   auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
   auto text = fmt::format(format_, localtime);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/modules/disk.cpp 
new/Waybar-0.9.0/src/modules/disk.cpp
--- old/Waybar-0.8.0/src/modules/disk.cpp       1970-01-01 01:00:00.000000000 
+0100
+++ new/Waybar-0.9.0/src/modules/disk.cpp       2019-12-28 12:35:09.000000000 
+0100
@@ -0,0 +1,76 @@
+#include "modules/disk.hpp"
+
+using namespace waybar::util;
+
+waybar::modules::Disk::Disk(const std::string& id, const Json::Value& config)
+    : ALabel(config, "disk", id, "{}%", 30)
+    , path_("/")
+{
+  thread_ = [this] {
+    dp.emit();
+    thread_.sleep_for(interval_);
+  };
+  if (config["path"].isString()) {
+    path_ = config["path"].asString();
+  }
+}
+
+auto waybar::modules::Disk::update() -> void {
+  struct statvfs /* {
+      unsigned long  f_bsize;    // filesystem block size
+      unsigned long  f_frsize;   // fragment size
+      fsblkcnt_t     f_blocks;   // size of fs in f_frsize units
+      fsblkcnt_t     f_bfree;    // # free blocks
+      fsblkcnt_t     f_bavail;   // # free blocks for unprivileged users
+      fsfilcnt_t     f_files;    // # inodes
+      fsfilcnt_t     f_ffree;    // # free inodes
+      fsfilcnt_t     f_favail;   // # free inodes for unprivileged users
+      unsigned long  f_fsid;     // filesystem ID
+      unsigned long  f_flag;     // mount flags
+      unsigned long  f_namemax;  // maximum filename length
+  }; */ stats;
+  int err = statvfs(path_.c_str(), &stats);
+
+  /* Conky options
+    fs_bar - Bar that shows how much space is used
+    fs_free - Free space on a file system
+    fs_free_perc - Free percentage of space
+    fs_size - File system size
+    fs_used - File system used space
+  */
+
+  if (err != 0) {
+    event_box_.hide();
+    return;
+  }
+
+  auto free = pow_format(stats.f_bavail * stats.f_bsize, "B", true);
+  auto used = pow_format((stats.f_blocks - stats.f_bavail) * stats.f_bsize, 
"B", true);
+  auto total = pow_format(stats.f_blocks * stats.f_bsize, "B", true);
+
+  label_.set_markup(fmt::format(format_
+      , stats.f_bavail * 100 / stats.f_blocks
+      , fmt::arg("free", free)
+      , fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks)
+      , fmt::arg("used", used)
+      , fmt::arg("percentage_used", (stats.f_blocks - stats.f_bavail) * 100 / 
stats.f_blocks)
+      , fmt::arg("total", total)
+      , fmt::arg("path", path_)
+      ));
+  if (tooltipEnabled()) {
+    std::string tooltip_format = "{used} used out of {total} on {path} 
({percentage_used}%)";
+    if (config_["tooltip-format"].isString()) {
+      tooltip_format = config_["tooltip-format"].asString();
+    }
+    label_.set_tooltip_text(fmt::format(tooltip_format
+      , stats.f_bavail * 100 / stats.f_blocks
+      , fmt::arg("free", free)
+      , fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks)
+      , fmt::arg("used", used)
+      , fmt::arg("percentage_used", (stats.f_blocks - stats.f_bavail) * 100 / 
stats.f_blocks)
+      , fmt::arg("total", total)
+      , fmt::arg("path", path_)
+      ));
+  }
+  event_box_.show();
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/modules/mpd.cpp 
new/Waybar-0.9.0/src/modules/mpd.cpp
--- old/Waybar-0.8.0/src/modules/mpd.cpp        2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/src/modules/mpd.cpp        2019-12-28 12:35:09.000000000 
+0100
@@ -41,6 +41,10 @@
   if (connection_ != nullptr) {
     try {
       bool wasPlaying = playing();
+      if(!wasPlaying) {
+        // Wait until the periodic_updater has stopped
+        std::lock_guard periodic_guard(periodic_lock_);
+      }
       fetchState();
       if (!wasPlaying && playing()) {
         periodic_updater().detach();
@@ -75,6 +79,7 @@
 
 std::thread waybar::modules::MPD::periodic_updater() {
   return std::thread([this] {
+    std::lock_guard guard(periodic_lock_);
     while (connection_ != nullptr && playing()) {
       dp.emit();
       std::this_thread::sleep_for(std::chrono::seconds(1));
@@ -297,7 +302,7 @@
   // Wait for a player (play/pause), option (random, shuffle, etc.), or 
playlist
   // change
   if (!mpd_send_idle_mask(
-          conn, static_cast<mpd_idle>(MPD_IDLE_PLAYER | MPD_IDLE_OPTIONS | 
MPD_IDLE_PLAYLIST))) {
+          conn, static_cast<mpd_idle>(MPD_IDLE_PLAYER | MPD_IDLE_OPTIONS | 
MPD_IDLE_QUEUE))) {
     checkErrors(conn);
     return;
   }
@@ -306,6 +311,10 @@
   // See issue #277:
   // https://github.com/Alexays/Waybar/issues/277
   mpd_recv_idle(conn, /* disable_timeout = */ false);
+  // See issue #281:
+  // https://github.com/Alexays/Waybar/issues/281
+  std::lock_guard guard(connection_lock_);
+
   checkErrors(conn);
   mpd_response_finish(conn);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/modules/network.cpp 
new/Waybar-0.9.0/src/modules/network.cpp
--- old/Waybar-0.8.0/src/modules/network.cpp    2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/src/modules/network.cpp    2019-12-28 12:35:09.000000000 
+0100
@@ -2,9 +2,13 @@
 #include <spdlog/spdlog.h>
 #include <sys/eventfd.h>
 #include <fstream>
+#include "util/format.hpp"
+
 
 namespace {
 
+using namespace waybar::util;
+
 constexpr const char *NETSTAT_FILE =
     "/proc/net/netstat";  // std::ifstream does not take std::string_view as 
param
 constexpr std::string_view BANDWIDTH_CATEGORY = "IpExt";
@@ -98,7 +102,7 @@
 
   createEventSocket();
   createInfoSocket();
-  auto default_iface = getPreferredIface();
+  auto default_iface = getPreferredIface(-1, false);
   if (default_iface != -1) {
     ifid_ = default_iface;
     char ifname[IF_NAMESIZE];
@@ -259,26 +263,6 @@
   }
   getState(signal_strength_);
 
-  auto pow_format = [](unsigned long long value, const std::string &unit) {
-    if (value > 2000ull * 1000ull * 1000ull) {  // > 2G
-      auto go = value / (1000 * 1000 * 1000);
-      return std::to_string(go) + "." +
-             std::to_string((value - go * 1000 * 1000 * 1000) / (100 * 1000 * 
1000)) + "G" + unit;
-
-    } else if (value > 2000ull * 1000ull) {  // > 2M
-      auto mo = value / (1000 * 1000);
-      return std::to_string(mo) + "." + std::to_string((value - mo * 1000 * 
1000) / (100 * 1000)) +
-             "M" + unit;
-
-    } else if (value > 2000ull) {  // > 2k
-      auto ko = value / 1000;
-      return std::to_string(ko) + "." + std::to_string((value - ko * 1000) / 
100) + "k" + unit;
-
-    } else {
-      return std::to_string(value) + unit;
-    }
-  };
-
   auto text = fmt::format(
       format_,
       fmt::arg("essid", essid_),
@@ -531,7 +515,7 @@
   return false;
 }
 
-int waybar::modules::Network::getPreferredIface(int skip_idx) const {
+int waybar::modules::Network::getPreferredIface(int skip_idx, bool wait) const 
{
   int ifid = -1;
   if (config_["interface"].isString()) {
     ifid = if_nametoindex(config_["interface"].asCString());
@@ -563,7 +547,9 @@
     if (ifid > 0) {
       return ifid;
     }
-    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+    if (wait) {
+      std::this_thread::sleep_for(std::chrono::milliseconds(500));
+    }
   }
   return -1;
 }
@@ -717,8 +703,9 @@
     // WiFi-hardware usually operates in the range -90 to -20dBm.
     const int hardwareMax = -20;
     const int hardwareMin = -90;
-    signal_strength_ =
-        ((signal_strength_dbm_ - hardwareMin) / double{hardwareMax - 
hardwareMin}) * 100;
+    const int strength =
+      ((signal_strength_dbm_ - hardwareMin) / double{hardwareMax - 
hardwareMin}) * 100;
+    signal_strength_ = std::clamp(strength, 0, 100);
   }
   if (bss[NL80211_BSS_SIGNAL_UNSPEC] != nullptr) {
     signal_strength_ = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/modules/pulseaudio.cpp 
new/Waybar-0.9.0/src/modules/pulseaudio.cpp
--- old/Waybar-0.8.0/src/modules/pulseaudio.cpp 2019-08-29 11:56:57.000000000 
+0200
+++ new/Waybar-0.9.0/src/modules/pulseaudio.cpp 2019-12-28 12:35:09.000000000 
+0100
@@ -86,7 +86,7 @@
     change = round(config_["scroll-step"].asDouble() * volume_tick);
   }
   if (dir == SCROLL_DIR::UP) {
-    if (volume_ + 1 < 100) {
+    if (volume_ + 1 <= 100) {
       pa_cvolume_inc(&pa_volume, change);
     }
   } else if (dir == SCROLL_DIR::DOWN) {
@@ -221,6 +221,7 @@
   }
   format_source = fmt::format(format_source, fmt::arg("volume", 
source_volume_));
   label_.set_markup(fmt::format(format,
+                                fmt::arg("desc", desc_),
                                 fmt::arg("volume", volume_),
                                 fmt::arg("format_source", format_source),
                                 fmt::arg("icon", getIcon(volume_, 
getPortIcon()))));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/modules/sway/window.cpp 
new/Waybar-0.9.0/src/modules/sway/window.cpp
--- old/Waybar-0.8.0/src/modules/sway/window.cpp        2019-08-29 
11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/src/modules/sway/window.cpp        2019-12-28 
12:35:09.000000000 +0100
@@ -20,7 +20,7 @@
   try {
     std::lock_guard<std::mutex> lock(mutex_);
     auto payload = parser_.parse(res.payload);
-    auto output = payload["ouput"].isString() ? payload["output"].asString() : 
"";
+    auto output = payload["output"].isString() ? payload["output"].asString() 
: "";
     std::tie(app_nb_, windowId_, window_, app_id_) = 
getFocusedNode(payload["nodes"], output);
     dp.emit();
   } catch (const std::exception& e) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/src/modules/sway/workspaces.cpp 
new/Waybar-0.9.0/src/modules/sway/workspaces.cpp
--- old/Waybar-0.8.0/src/modules/sway/workspaces.cpp    2019-08-29 
11:56:57.000000000 +0200
+++ new/Waybar-0.9.0/src/modules/sway/workspaces.cpp    2019-12-28 
12:35:09.000000000 +0100
@@ -49,9 +49,9 @@
                                   : true;
                      });
 
-        // adding persistant workspaces (as per the config file)
-        if (config_["persistant_workspaces"].isObject()) {
-          const Json::Value &            p_workspaces = 
config_["persistant_workspaces"];
+        // adding persistent workspaces (as per the config file)
+        if (config_["persistent_workspaces"].isObject()) {
+          const Json::Value &            p_workspaces = 
config_["persistent_workspaces"];
           const std::vector<std::string> p_workspaces_names = 
p_workspaces.getMemberNames();
 
           for (const std::string &p_w_name : p_workspaces_names) {
@@ -88,6 +88,9 @@
           std::sort(workspaces_.begin(),
                     workspaces_.end(),
                     [](const Json::Value &lhs, const Json::Value &rhs) {
+                      if (lhs["name"].isInt() && rhs["name"].isInt()) {
+                        return lhs["name"].asInt() < rhs["name"].asInt();
+                      }
                       return lhs["name"].asString() < rhs["name"].asString();
                     });
         }
@@ -151,9 +154,9 @@
       button.get_style_context()->remove_class("urgent");
     }
     if ((*it)["target_output"].isString()) {
-      button.get_style_context()->add_class("persistant");
+      button.get_style_context()->add_class("persistent");
     } else {
-      button.get_style_context()->remove_class("persistant");
+      button.get_style_context()->remove_class("persistent");
     }
     if (needReorder) {
       box_.reorder_child(button, it - workspaces_.begin());
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Waybar-0.8.0/subprojects/gtk-layer-shell.wrap 
new/Waybar-0.9.0/subprojects/gtk-layer-shell.wrap
--- old/Waybar-0.8.0/subprojects/gtk-layer-shell.wrap   1970-01-01 
01:00:00.000000000 +0100
+++ new/Waybar-0.9.0/subprojects/gtk-layer-shell.wrap   2019-12-28 
12:35:09.000000000 +0100
@@ -0,0 +1,5 @@
+[wrap-file]
+directory = gtk-layer-shell-0.1.0
+source_filename = gtk-layer-shell-0.1.0.tar.gz
+source_hash = f7569e27ae30b1a94c3ad6c955cf56240d6bc272b760d9d266ce2ccdb94a5cf0
+source_url = 
https://github.com/wmww/gtk-layer-shell/archive/v0.1.0/gtk-layer-shell-0.1.0.tar.gz


Reply via email to