Merge branch 'master' into master
This commit is contained in:
		
						commit
						1c08d26af0
					
				|  | @ -2,4 +2,4 @@ | |||
| 
 | ||||
| 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 pugixml-dev libnl3-dev pulseaudio-dev libmpdclient-dev sndio-dev scdoc libxkbcommon | ||||
| 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 pugixml-dev libnl3-dev pulseaudio-dev libmpdclient-dev sndio-dev scdoc libxkbcommon tzdata | ||||
|  |  | |||
|  | @ -1,21 +1,14 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <fmt/format.h> | ||||
| #if FMT_VERSION < 60000 | ||||
| #include <fmt/time.h> | ||||
| #else | ||||
| #include <fmt/chrono.h> | ||||
| #endif | ||||
| #include <date/tz.h> | ||||
| #include "ALabel.hpp" | ||||
| #include "util/sleeper_thread.hpp" | ||||
| 
 | ||||
| namespace waybar::modules { | ||||
| namespace waybar { | ||||
| 
 | ||||
| struct waybar_time { | ||||
|   std::locale locale; | ||||
|   date::zoned_seconds ztime; | ||||
| }; | ||||
| struct waybar_time; | ||||
| 
 | ||||
| namespace modules { | ||||
| 
 | ||||
| const std::string kCalendarPlaceholder = "calendar"; | ||||
| 
 | ||||
|  | @ -43,4 +36,5 @@ class Clock : public ALabel { | |||
|   bool is_timezone_fixed(); | ||||
| }; | ||||
| 
 | ||||
| }  // namespace waybar::modules
 | ||||
| }  // namespace modules
 | ||||
| }  // namespace waybar
 | ||||
|  |  | |||
|  | @ -0,0 +1,39 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <date/tz.h> | ||||
| #include <fmt/format.h> | ||||
| 
 | ||||
| namespace waybar { | ||||
| 
 | ||||
| struct waybar_time { | ||||
|   std::locale         locale; | ||||
|   date::zoned_seconds ztime; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace waybar
 | ||||
| 
 | ||||
| template <> | ||||
| struct fmt::formatter<waybar::waybar_time> { | ||||
|   std::string_view specs; | ||||
| 
 | ||||
|   template <typename ParseContext> | ||||
|   constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     auto it = ctx.begin(); | ||||
|     if (it != ctx.end() && *it == ':') { | ||||
|       ++it; | ||||
|     } | ||||
|     auto end = it; | ||||
|     while (end != ctx.end() && *end != '}') { | ||||
|       ++end; | ||||
|     } | ||||
|     if (end != it) { | ||||
|       specs = {it, std::string_view::size_type(end - it)}; | ||||
|     } | ||||
|     return end; | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(const waybar::waybar_time& t, FormatContext& ctx) { | ||||
|     return format_to(ctx.out(), "{}", date::format(t.locale, fmt::to_string(specs), t.ztime)); | ||||
|   } | ||||
| }; | ||||
|  | @ -84,12 +84,20 @@ Addressed by *memory* | |||
| 
 | ||||
| *{percentage}*: Percentage of memory in use. | ||||
| 
 | ||||
| *{swapPercentage}*: Percentage of swap in use. | ||||
| 
 | ||||
| *{total}*: Amount of total memory available in GiB. | ||||
| 
 | ||||
| *{swapTotal}*: Amount of total swap available in GiB. | ||||
| 
 | ||||
| *{used}*: Amount of used memory in GiB. | ||||
| 
 | ||||
| *{swapUsed}*: Amount of used swap in GiB. | ||||
| 
 | ||||
| *{avail}*: Amount of available memory in GiB. | ||||
| 
 | ||||
| *{swapAvail}*: Amount of available swap in GiB. | ||||
| 
 | ||||
| # EXAMPLES | ||||
| 
 | ||||
| ``` | ||||
|  |  | |||
|  | @ -93,10 +93,15 @@ Addressed by *wlr/taskbar* | |||
| # CLICK ACTIONS | ||||
| 
 | ||||
| *activate*: Bring the application into foreground. | ||||
| 
 | ||||
| *minimize*: Toggle application's minimized state. | ||||
| 
 | ||||
| *minimize-raise*: Bring the application into foreground or toggle its minimized state. | ||||
| 
 | ||||
| *maximize*: Toggle application's maximized state. | ||||
| 
 | ||||
| *fullscreen*: Toggle application's fullscreen state. | ||||
| 
 | ||||
| *close*: Close the application. | ||||
| 
 | ||||
| # EXAMPLES | ||||
|  |  | |||
|  | @ -52,6 +52,7 @@ Addressed by *wlr/workspaces* | |||
| # CLICK ACTIONS | ||||
| 
 | ||||
| *activate*: Switch to workspace. | ||||
| 
 | ||||
| *close*: Close the workspace. | ||||
| 
 | ||||
| # ICONS | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| project( | ||||
|     'waybar', 'cpp', 'c', | ||||
|     version: '0.9.8', | ||||
|     version: '0.9.9', | ||||
|     license: 'MIT', | ||||
|     meson_version: '>= 0.49.0', | ||||
|     default_options : [ | ||||
|  | @ -79,7 +79,7 @@ is_netbsd = host_machine.system() == 'netbsd' | |||
| is_openbsd = host_machine.system() == 'openbsd' | ||||
| 
 | ||||
| thread_dep = dependency('threads') | ||||
| fmt = dependency('fmt', version : ['>=5.3.0'], fallback : ['fmt', 'fmt_dep']) | ||||
| fmt = dependency('fmt', version : ['>=7.0.0'], fallback : ['fmt', 'fmt_dep']) | ||||
| spdlog = dependency('spdlog', version : ['>=1.8.5'], fallback : ['spdlog', 'spdlog_dep'], default_options : ['external_fmt=true']) | ||||
| wayland_client = dependency('wayland-client') | ||||
| wayland_cursor = dependency('wayland-cursor') | ||||
|  |  | |||
|  | @ -1,10 +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; | ||||
| } | ||||
| 
 | ||||
| window#waybar { | ||||
|  | @ -43,6 +40,9 @@ window#waybar.chromium { | |||
|     color: #ffffff; | ||||
|     /* Use box-shadow instead of border so the text isn't offset */ | ||||
|     box-shadow: inset 0 -3px transparent; | ||||
|     /* Avoid rounded borders under each workspace name */ | ||||
|     border: none; | ||||
|     border-radius: 0; | ||||
| } | ||||
| 
 | ||||
| /* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ | ||||
|  |  | |||
|  | @ -161,7 +161,7 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g | |||
|       uint32_t    energy_now; | ||||
|       uint32_t    energy_full_design; | ||||
|       std::string _status; | ||||
|       std::ifstream(bat / "status") >> _status; | ||||
|       std::getline(std::ifstream(bat / "status"), _status); | ||||
| 
 | ||||
|       // Some battery will report current and charge in μA/μAh.
 | ||||
|       // Scale these by the voltage to get μW/μWh.
 | ||||
|  |  | |||
|  | @ -1,17 +1,24 @@ | |||
| #include "modules/clock.hpp" | ||||
| 
 | ||||
| #include <time.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #if FMT_VERSION < 60000 | ||||
| #include <fmt/time.h> | ||||
| #else | ||||
| #include <fmt/chrono.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <ctime> | ||||
| #include <sstream> | ||||
| #include <type_traits> | ||||
| 
 | ||||
| #include "util/ustring_clen.hpp" | ||||
| #include "util/waybar_time.hpp" | ||||
| #ifdef HAVE_LANGINFO_1STDAY | ||||
| #include <langinfo.h> | ||||
| #include <locale.h> | ||||
| #endif | ||||
| 
 | ||||
| using waybar::modules::waybar_time; | ||||
| using waybar::waybar_time; | ||||
| 
 | ||||
| waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) | ||||
|     : ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true), | ||||
|  | @ -92,7 +99,7 @@ auto waybar::modules::Clock::update() -> void { | |||
|     // As date dep is not fully compatible, prefer fmt
 | ||||
|     tzset(); | ||||
|     auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now)); | ||||
|     text = fmt::format(format_, localtime); | ||||
|     text = fmt::format(locale_, format_, localtime); | ||||
|   } else { | ||||
|     text = fmt::format(format_, wtime); | ||||
|   } | ||||
|  | @ -227,14 +234,3 @@ auto waybar::modules::Clock::first_day_of_week() -> date::weekday { | |||
| #endif | ||||
|   return date::Sunday; | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| struct fmt::formatter<waybar_time> : fmt::formatter<std::tm> { | ||||
|   template <typename FormatContext> | ||||
|   auto format(const waybar_time& t, FormatContext& ctx) { | ||||
| #if FMT_VERSION >= 80000 | ||||
|   auto& tm_format = specs; | ||||
| #endif | ||||
|     return format_to(ctx.out(), "{}", date::format(t.locale, fmt::to_string(tm_format), t.ztime)); | ||||
|   } | ||||
| }; | ||||
|  |  | |||
|  | @ -12,7 +12,15 @@ auto waybar::modules::Memory::update() -> void { | |||
|   parseMeminfo(); | ||||
| 
 | ||||
|   unsigned long memtotal = meminfo_["MemTotal"]; | ||||
|   unsigned long swaptotal = 0; | ||||
|   if (meminfo_.count("SwapTotal")) { | ||||
|     swaptotal = meminfo_["SwapTotal"]; | ||||
|   } | ||||
|   unsigned long memfree; | ||||
|   unsigned long swapfree = 0; | ||||
|   if (meminfo_.count("SwapFree")) { | ||||
|     swapfree = meminfo_["SwapFree"]; | ||||
|   } | ||||
|   if (meminfo_.count("MemAvailable")) { | ||||
|     // New kernels (3.4+) have an accurate available memory field.
 | ||||
|     memfree = meminfo_["MemAvailable"] + meminfo_["zfs_size"]; | ||||
|  | @ -24,9 +32,16 @@ auto waybar::modules::Memory::update() -> void { | |||
| 
 | ||||
|   if (memtotal > 0 && memfree >= 0) { | ||||
|     auto total_ram_gigabytes = memtotal / std::pow(1024, 2); | ||||
|     auto total_swap_gigabytes = swaptotal / std::pow(1024, 2); | ||||
|     int  used_ram_percentage = 100 * (memtotal - memfree) / memtotal; | ||||
|     int  used_swap_percentage = 0; | ||||
|     if (swaptotal && swapfree) { | ||||
|       used_swap_percentage = 100 * (swaptotal - swapfree) / swaptotal; | ||||
|     } | ||||
|     auto used_ram_gigabytes = (memtotal - memfree) / std::pow(1024, 2); | ||||
|     auto used_swap_gigabytes = (swaptotal - swapfree) / std::pow(1024, 2); | ||||
|     auto available_ram_gigabytes = memfree / std::pow(1024, 2); | ||||
|     auto available_swap_gigabytes = swapfree / std::pow(1024, 2); | ||||
| 
 | ||||
|     auto format = format_; | ||||
|     auto state = getState(used_ram_percentage); | ||||
|  | @ -43,9 +58,13 @@ auto waybar::modules::Memory::update() -> void { | |||
|                                     used_ram_percentage, | ||||
|                                     fmt::arg("icon", getIcon(used_ram_percentage, icons)), | ||||
|                                     fmt::arg("total", total_ram_gigabytes), | ||||
|                                     fmt::arg("swapTotal", total_swap_gigabytes), | ||||
|                                     fmt::arg("percentage", used_ram_percentage), | ||||
|                                     fmt::arg("swapPercentage", used_swap_percentage), | ||||
|                                     fmt::arg("used", used_ram_gigabytes), | ||||
|                                     fmt::arg("avail", available_ram_gigabytes))); | ||||
|                                     fmt::arg("swapUsed", used_swap_gigabytes), | ||||
|                                     fmt::arg("avail", available_ram_gigabytes), | ||||
|                                     fmt::arg("swapAvail", available_swap_gigabytes))); | ||||
|     } | ||||
| 
 | ||||
|     if (tooltipEnabled()) { | ||||
|  | @ -54,9 +73,13 @@ auto waybar::modules::Memory::update() -> void { | |||
|         label_.set_tooltip_text(fmt::format(tooltip_format, | ||||
|                                             used_ram_percentage, | ||||
|                                             fmt::arg("total", total_ram_gigabytes), | ||||
|                                             fmt::arg("swapTotal", total_swap_gigabytes), | ||||
|                                             fmt::arg("percentage", used_ram_percentage), | ||||
|                                             fmt::arg("swapPercentage", used_swap_percentage), | ||||
|                                             fmt::arg("used", used_ram_gigabytes), | ||||
|                                             fmt::arg("avail", available_ram_gigabytes))); | ||||
|                                             fmt::arg("swapUsed", used_swap_gigabytes), | ||||
|                                             fmt::arg("avail", available_ram_gigabytes), | ||||
|                                             fmt::arg("swapAvail", available_swap_gigabytes))); | ||||
|       } else { | ||||
|         label_.set_tooltip_text(fmt::format("{:.{}f}GiB used", used_ram_gigabytes, 1)); | ||||
|       } | ||||
|  |  | |||
|  | @ -1,4 +1,3 @@ | |||
| #define CATCH_CONFIG_RUNNER | ||||
| #include "util/SafeSignal.hpp" | ||||
| 
 | ||||
| #include <glibmm.h> | ||||
|  | @ -138,8 +137,3 @@ TEST_CASE_METHOD(GlibTestsFixture, "SafeSignal copy/move counter", "[signal][thr | |||
|   producer.join(); | ||||
|   REQUIRE(count == NUM_EVENTS); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char* argv[]) { | ||||
|   Glib::init(); | ||||
|   return Catch::Session().run(argc, argv); | ||||
| } | ||||
|  |  | |||
|  | @ -1,4 +1,3 @@ | |||
| #define CATCH_CONFIG_MAIN | ||||
| #include "config.hpp" | ||||
| 
 | ||||
| #include <catch2/catch.hpp> | ||||
|  |  | |||
|  | @ -0,0 +1,26 @@ | |||
| #define CATCH_CONFIG_RUNNER | ||||
| #include <glibmm.h> | ||||
| #include <spdlog/sinks/stdout_sinks.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| 
 | ||||
| #include <catch2/catch.hpp> | ||||
| #include <catch2/catch_reporter_tap.hpp> | ||||
| #include <memory> | ||||
| 
 | ||||
| int main(int argc, char* argv[]) { | ||||
|   Catch::Session session; | ||||
|   Glib::init(); | ||||
| 
 | ||||
|   session.applyCommandLine(argc, argv); | ||||
|   const auto  logger = spdlog::default_logger(); | ||||
|   const auto& reporter_name = session.config().getReporterName(); | ||||
|   if (reporter_name == "tap") { | ||||
|     spdlog::set_pattern("# [%l] %v"); | ||||
|   } else if (reporter_name == "compact") { | ||||
|     logger->sinks().clear(); | ||||
|   } else { | ||||
|     logger->sinks().assign({std::make_shared<spdlog::sinks::stderr_sink_st>()}); | ||||
|   } | ||||
| 
 | ||||
|   return session.run(); | ||||
| } | ||||
|  | @ -6,30 +6,27 @@ test_dep = [ | |||
|     jsoncpp, | ||||
|     spdlog, | ||||
| ] | ||||
| 
 | ||||
| config_test = executable( | ||||
|     'config_test', | ||||
| test_src = files( | ||||
|     'main.cpp', | ||||
|     'SafeSignal.cpp', | ||||
|     'config.cpp', | ||||
|     '../src/config.cpp', | ||||
|     dependencies: test_dep, | ||||
|     include_directories: test_inc, | ||||
| ) | ||||
| 
 | ||||
| safesignal_test = executable( | ||||
|     'safesignal_test', | ||||
|     'SafeSignal.cpp', | ||||
| if tz_dep.found() | ||||
|   test_dep += tz_dep | ||||
|   test_src += files('waybar_time.cpp') | ||||
| endif | ||||
| 
 | ||||
| waybar_test = executable( | ||||
|     'waybar_test', | ||||
|     test_src, | ||||
|     dependencies: test_dep, | ||||
|     include_directories: test_inc, | ||||
| ) | ||||
| 
 | ||||
| test( | ||||
|     'Configuration test', | ||||
|     config_test, | ||||
|     workdir: meson.source_root(), | ||||
| ) | ||||
| 
 | ||||
| test( | ||||
|     'SafeSignal test', | ||||
|     safesignal_test, | ||||
|     'waybar', | ||||
|     waybar_test, | ||||
|     workdir: meson.source_root(), | ||||
| ) | ||||
|  |  | |||
|  | @ -0,0 +1,90 @@ | |||
| #include "util/waybar_time.hpp" | ||||
| 
 | ||||
| #include <date/date.h> | ||||
| #include <date/tz.h> | ||||
| 
 | ||||
| #include <catch2/catch.hpp> | ||||
| #include <chrono> | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| using namespace std::literals::chrono_literals; | ||||
| 
 | ||||
| /*
 | ||||
|  * Check that the date/time formatter with locale and timezone support is working as expected. | ||||
|  */ | ||||
| 
 | ||||
| const date::zoned_time<std::chrono::seconds> TEST_TIME = date::make_zoned( | ||||
|     "UTC", date::local_days{date::Monday[1] / date::January / 2022} + 13h + 4min + 5s); | ||||
| 
 | ||||
| TEST_CASE("Format UTC time", "[clock][util]") { | ||||
|   waybar::waybar_time tm{std::locale("C"), TEST_TIME}; | ||||
| 
 | ||||
|   REQUIRE(fmt::format("{}", tm).empty());  // no format specified
 | ||||
|   REQUIRE(fmt::format("{:%c %Z}", tm) == "Mon Jan  3 13:04:05 2022 UTC"); | ||||
|   REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405"); | ||||
| 
 | ||||
|   /* Test a few locales that are most likely to be present */ | ||||
|   SECTION("US locale") { | ||||
|     try { | ||||
|       tm.locale = std::locale("en_US"); | ||||
| 
 | ||||
|       REQUIRE(fmt::format("{}", tm).empty());  // no format specified
 | ||||
|       REQUIRE_THAT(fmt::format("{:%c}", tm),   // HowardHinnant/date#704
 | ||||
|                    Catch::Matchers::StartsWith("Mon 03 Jan 2022 01:04:05 PM")); | ||||
|       REQUIRE(fmt::format("{:%x %X}", tm) == "01/03/2022 01:04:05 PM"); | ||||
|       REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405"); | ||||
|     } catch (const std::runtime_error&) { | ||||
|       // locale not found; ignore
 | ||||
|     } | ||||
|   } | ||||
|   SECTION("GB locale") { | ||||
|     try { | ||||
|       tm.locale = std::locale("en_GB"); | ||||
| 
 | ||||
|       REQUIRE(fmt::format("{}", tm).empty());  // no format specified
 | ||||
|       REQUIRE_THAT(fmt::format("{:%c}", tm),   // HowardHinnant/date#704
 | ||||
|                    Catch::Matchers::StartsWith("Mon 03 Jan 2022 13:04:05")); | ||||
|       REQUIRE(fmt::format("{:%x %X}", tm) == "03/01/22 13:04:05"); | ||||
|       REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405"); | ||||
|     } catch (const std::runtime_error&) { | ||||
|       // locale not found; ignore
 | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| TEST_CASE("Format zoned time", "[clock][util]") { | ||||
|   waybar::waybar_time tm{std::locale("C"), date::make_zoned("America/New_York", TEST_TIME)}; | ||||
| 
 | ||||
|   REQUIRE(fmt::format("{}", tm).empty());  // no format specified
 | ||||
|   REQUIRE(fmt::format("{:%c %Z}", tm) == "Mon Jan  3 08:04:05 2022 EST"); | ||||
|   REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405"); | ||||
| 
 | ||||
|   /* Test a few locales that are most likely to be present */ | ||||
|   SECTION("US locale") { | ||||
|     try { | ||||
|       tm.locale = std::locale("en_US"); | ||||
| 
 | ||||
|       REQUIRE(fmt::format("{}", tm).empty());  // no format specified
 | ||||
|       REQUIRE_THAT(fmt::format("{:%c}", tm),   // HowardHinnant/date#704
 | ||||
|                    Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05 AM")); | ||||
|       REQUIRE(fmt::format("{:%x %X}", tm) == "01/03/2022 08:04:05 AM"); | ||||
|       REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405"); | ||||
|     } catch (const std::runtime_error&) { | ||||
|       // locale not found; ignore
 | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   SECTION("GB locale") { | ||||
|     try { | ||||
|       tm.locale = std::locale("en_GB"); | ||||
| 
 | ||||
|       REQUIRE(fmt::format("{}", tm).empty());  // no format specified
 | ||||
|       REQUIRE_THAT(fmt::format("{:%c}", tm),   // HowardHinnant/date#704
 | ||||
|                    Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05")); | ||||
|       REQUIRE(fmt::format("{:%x %X}", tm) == "03/01/22 08:04:05"); | ||||
|       REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405"); | ||||
|     } catch (const std::runtime_error&) { | ||||
|       // locale not found; ignore
 | ||||
|     } | ||||
|   } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue