From ef2d570845f0347b16dad26f9f4403c0b11c17f2 Mon Sep 17 00:00:00 2001 From: Lena Date: Fri, 20 Sep 2024 17:40:43 +0200 Subject: [PATCH 1/3] Start GPS module --- include/modules/gps.hpp | 31 ++++++++++++ man/waybar-gps.5.scd | 41 ++++++++++++++++ meson.build | 10 +++- meson_options.txt | 1 + src/factory.cpp | 8 ++++ src/modules/gps.cpp | 101 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 include/modules/gps.hpp create mode 100644 man/waybar-gps.5.scd create mode 100644 src/modules/gps.cpp diff --git a/include/modules/gps.hpp b/include/modules/gps.hpp new file mode 100644 index 000000000..20bf02e48 --- /dev/null +++ b/include/modules/gps.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include +#include + +#include "ALabel.hpp" +#include "util/format.hpp" +#include "util/sleeper_thread.hpp" + +namespace waybar::modules { + + class Gps : public ALabel { + public: + Gps(const std::string&, const Json::Value&); + virtual ~Gps(); + auto update() -> void override; + + private: + const int getFixState() const; + const std::string getFixStateName() const; + const std::string getFixStateString() const; + + util::SleeperThread thread_; + gps_data_t gps_data_; + std::string state_; + }; + +} // namespace waybar::modules diff --git a/man/waybar-gps.5.scd b/man/waybar-gps.5.scd new file mode 100644 index 000000000..dfa91c270 --- /dev/null +++ b/man/waybar-gps.5.scd @@ -0,0 +1,41 @@ +waybar-gps(5) "waybar-gps" "User Manual" + +# NAME + +waybar - gps module + +# DESCRIPTION + +*gps* module for gpsd. + + +# FILES + +$XDG_CONFIG_HOME/waybar/config ++ + Per user configuration file + +# ADDITIONAL FILES + +libgps lives in: + +. /usr/lib/libgps.so or /usr/lib64/libgps.so +. /usr/lib/pkgconfig/libgps.pc or /usr/lib64/pkgconfig/libgps.pc +. /usr/include/gps + +# CONFIGURATION + + + +# EXAMPLES + +``` +"gps": { + +}, +``` +# STYLE + +- *#gps* +- *#gps.fix-none* Applied when GPS is present, but there is no fix. +- *#gps.fix-2d* Applied when there is a 2D fix. +- *#gps.fix-3d* Applied when there is a 3D fix. diff --git a/meson.build b/meson.build index f4941c8fa..45fb9970f 100644 --- a/meson.build +++ b/meson.build @@ -93,6 +93,7 @@ libmpdclient = dependency('libmpdclient', required: get_option('mpd')) xkbregistry = dependency('xkbregistry') libjack = dependency('jack', required: get_option('jack')) libwireplumber = dependency('wireplumber-0.5', required: get_option('wireplumber')) +libgps = dependency('libgps', required: get_option('gps')) libsndio = compiler.find_library('sndio', required: get_option('sndio')) if libsndio.found() @@ -493,6 +494,12 @@ if cava.found() man_files += files('man/waybar-cava.5.scd') endif +if libgps.found() + add_project_arguments('-DHAVE_LIBGPS', language: 'cpp') + src_files += files('src/modules/gps.cpp') + man_files += files('man/waybar-gps.5.scd') +endif + subdir('protocol') app_resources = [] @@ -531,7 +538,8 @@ executable( libsndio, tz_dep, xkbregistry, - cava + cava, + libgps ], include_directories: inc_dirs, install: true, diff --git a/meson_options.txt b/meson_options.txt index 303ef038e..db836f2e9 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -20,3 +20,4 @@ option('jack', type: 'feature', value: 'auto', description: 'Enable support for option('wireplumber', type: 'feature', value: 'auto', description: 'Enable support for WirePlumber') option('cava', type: 'feature', value: 'auto', description: 'Enable support for Cava') option('niri', type: 'boolean', description: 'Enable support for niri') +option('gps', type: 'feature', value: 'auto', description: 'Enable support for gps') diff --git a/src/factory.cpp b/src/factory.cpp index 6c2313e38..22ac0dc3b 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -109,6 +109,9 @@ #ifdef HAVE_SYSTEMD_MONITOR #include "modules/systemd_failed_units.hpp" #endif +#ifdef HAVE_LIBGPS +#include "modules/gps.hpp" +#endif #include "modules/cffi.hpp" #include "modules/custom.hpp" #include "modules/image.hpp" @@ -331,6 +334,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name, if (ref == "systemd-failed-units") { return new waybar::modules::SystemdFailedUnits(id, config_[name]); } +#endif +#ifdef HAVE_LIBCAVA + if (ref == "gps") { + return new waybar::modules::Gps(id, config_[name]); + } #endif if (ref == "temperature") { return new waybar::modules::Temperature(id, config_[name]); diff --git a/src/modules/gps.cpp b/src/modules/gps.cpp new file mode 100644 index 000000000..52217e0a3 --- /dev/null +++ b/src/modules/gps.cpp @@ -0,0 +1,101 @@ +#include "modules/gps.hpp" + +#include + +// In the 80000 version of fmt library authors decided to optimize imports +// and moved declarations required for fmt::dynamic_format_arg_store in new +// header fmt/args.h +#if (FMT_VERSION >= 80000) +#include +#else +#include +#endif + +namespace { + using namespace waybar::util; + constexpr const char *DEFAULT_FORMAT = "{status}"; +} // namespace + + +waybar::modules::Gps::Gps(const std::string& id, const Json::Value& config) +: ALabel(config, "gps", id, "{}", 30) { + thread_ = [this] { + dp.emit(); + thread_.sleep_for(interval_); + }; + // TODO: connect to gpsd socket + + if (0 != gps_open("localhost", "2947", &gps_data_)) { + throw std::runtime_error("Can't open gpsd socket"); + } + +} + +const int waybar::modules::Gps::getFixState() const { +0 +} + +const std::string waybar::modules::Gps::getFixStateName() const { + switch (getFixState()) { + case 1: + return "fix-2d"; + case 2: + return "fix-3d"; + default: + return "fix-none"; + } +} + +const std::string waybar::modules::Gps::getFixStateString() const { + switch (getFixState()) { + case 1: + return "2D Fix"; + case 2: + return "3D Fix"; + default: + return "No fix"; + } +} + +auto waybar::modules::Gps::update() -> void { + + std::string tooltip_format; + + if (!alt_) { + auto state = getFixStateName(); + if (!state_.empty() && label_.get_style_context()->has_class(state_)) { + label_.get_style_context()->remove_class(state_); + } + if (config_["format-" + state].isString()) { + default_format_ = config_["format-" + state].asString(); + } else if (config_["format"].isString()) { + default_format_ = config_["format"].asString(); + } else { + default_format_ = DEFAULT_FORMAT; + } + if (config_["tooltip-format-" + state].isString()) { + tooltip_format = config_["tooltip-format-" + state].asString(); + } + if (!label_.get_style_context()->has_class(state)) { + label_.get_style_context()->add_class(state); + } + format_ = default_format_; + state_ = state; + } + + + auto format = format_; + + fmt::dynamic_format_arg_store store; + store.push_back(fmt::arg("status", getFixStateString())); + + label_.set_markup(fmt::vformat(format, store)); +// Call parent update +ALabel::update(); +} + +waybar::modules::Gps::~Gps() { + gps_close(&gps_data_); +} + + From d50064b0e2a9881d6a7beb0d73410c9f4fc156f5 Mon Sep 17 00:00:00 2001 From: Lena Date: Fri, 20 Sep 2024 19:05:26 +0200 Subject: [PATCH 2/3] add all arguments --- include/modules/gps.hpp | 7 +-- src/modules/gps.cpp | 106 ++++++++++++++++++++++++++++++++-------- 2 files changed, 90 insertions(+), 23 deletions(-) diff --git a/include/modules/gps.hpp b/include/modules/gps.hpp index 20bf02e48..a3335a106 100644 --- a/include/modules/gps.hpp +++ b/include/modules/gps.hpp @@ -19,9 +19,10 @@ namespace waybar::modules { auto update() -> void override; private: - const int getFixState() const; - const std::string getFixStateName() const; - const std::string getFixStateString() const; + const std::string getFixModeName() const; + const std::string getFixModeString() const; + + const std::string getFixStatusString() const; util::SleeperThread thread_; gps_data_t gps_data_; diff --git a/src/modules/gps.cpp b/src/modules/gps.cpp index 52217e0a3..e2367c41e 100644 --- a/src/modules/gps.cpp +++ b/src/modules/gps.cpp @@ -1,6 +1,8 @@ #include "modules/gps.hpp" +#include #include +#include // In the 80000 version of fmt library authors decided to optimize imports // and moved declarations required for fmt::dynamic_format_arg_store in new @@ -13,56 +15,84 @@ namespace { using namespace waybar::util; - constexpr const char *DEFAULT_FORMAT = "{status}"; + constexpr const char *DEFAULT_FORMAT = "{mode}"; } // namespace waybar::modules::Gps::Gps(const std::string& id, const Json::Value& config) -: ALabel(config, "gps", id, "{}", 30) { +: ALabel(config, "gps", id, "{}", 1) { thread_ = [this] { dp.emit(); thread_.sleep_for(interval_); }; - // TODO: connect to gpsd socket if (0 != gps_open("localhost", "2947", &gps_data_)) { throw std::runtime_error("Can't open gpsd socket"); } + gps_stream(&gps_data_, WATCH_ENABLE, NULL); } -const int waybar::modules::Gps::getFixState() const { -0 -} - -const std::string waybar::modules::Gps::getFixStateName() const { - switch (getFixState()) { - case 1: +const std::string waybar::modules::Gps::getFixModeName() const { + switch (gps_data_.fix.mode) { + case MODE_NO_FIX: + return "fix-none"; + case MODE_2D: return "fix-2d"; - case 2: + case MODE_3D: return "fix-3d"; default: - return "fix-none"; + return "disconnected"; } } -const std::string waybar::modules::Gps::getFixStateString() const { - switch (getFixState()) { - case 1: +const std::string waybar::modules::Gps::getFixModeString() const { + switch (gps_data_.fix.mode) { + case MODE_NO_FIX: + return "No fix"; + case MODE_2D: return "2D Fix"; - case 2: + case MODE_3D: return "3D Fix"; default: - return "No fix"; + return "Disconnected"; + } +} + +const std::string waybar::modules::Gps::getFixStatusString() const { + switch (gps_data_.fix.status) { + case STATUS_UNK: + return "Unknown"; + case STATUS_GPS: + return "GPS"; + case STATUS_DGPS: + return "DGPS"; + case STATUS_RTK_FIX: + return "RTK Fixed"; + case STATUS_RTK_FLT: + return "RTK Float"; + case STATUS_DR: + return "Dead Reckoning"; + case STATUS_GNSSDR: + return "GNSS + Dead Reckoning"; + case STATUS_TIME: + return "Time Only"; + case STATUS_PPS_FIX: + return "PPS Fix"; + default: + return "Unknown"; } } auto waybar::modules::Gps::update() -> void { + if (gps_read(&gps_data_, NULL, 0) == -1) { + throw std::runtime_error("Can't read data from gpsd."); + } std::string tooltip_format; if (!alt_) { - auto state = getFixStateName(); + auto state = getFixModeName(); if (!state_.empty() && label_.get_style_context()->has_class(state_)) { label_.get_style_context()->remove_class(state_); } @@ -87,14 +117,50 @@ auto waybar::modules::Gps::update() -> void { auto format = format_; fmt::dynamic_format_arg_store store; - store.push_back(fmt::arg("status", getFixStateString())); + store.push_back(fmt::arg("mode", getFixModeString())); + store.push_back(fmt::arg("status", getFixStatusString())); - label_.set_markup(fmt::vformat(format, store)); + store.push_back(fmt::arg("latitude", gps_data_.fix.latitude)); + store.push_back(fmt::arg("latitude_error", gps_data_.fix.epy)); + + store.push_back(fmt::arg("longitude", gps_data_.fix.longitude)); + store.push_back(fmt::arg("longitude_error", gps_data_.fix.epx)); + + store.push_back(fmt::arg("altitude_hae", gps_data_.fix.altHAE)); + store.push_back(fmt::arg("altitude_msl", gps_data_.fix.altMSL)); + store.push_back(fmt::arg("altitude_error", gps_data_.fix.epv)); + + store.push_back(fmt::arg("speed", gps_data_.fix.speed)); + store.push_back(fmt::arg("speed_error", gps_data_.fix.eps)); + + store.push_back(fmt::arg("climb", gps_data_.fix.climb)); + store.push_back(fmt::arg("climb_error", gps_data_.fix.epc)); + + store.push_back(fmt::arg("satellites_used", gps_data_.satellites_used)); + store.push_back(fmt::arg("satellites_visible", gps_data_.satellites_visible)); + + auto text = fmt::vformat(format, store); + + if (tooltipEnabled()) { + if (tooltip_format.empty() && config_["tooltip-format"].isString()) { + tooltip_format = config_["tooltip-format"].asString(); + } + if (!tooltip_format.empty()) { + auto tooltip_text = fmt::vformat(tooltip_format, store); + if (label_.get_tooltip_text() != tooltip_text) { + label_.set_tooltip_markup(tooltip_text); + } + } else if (label_.get_tooltip_text() != text) { + label_.set_tooltip_markup(text); + } + } + label_.set_markup(text); // Call parent update ALabel::update(); } waybar::modules::Gps::~Gps() { + gps_stream(&gps_data_, WATCH_DISABLE, NULL); gps_close(&gps_data_); } From 63d33953222b2850b85d0cc441e98e2166450adc Mon Sep 17 00:00:00 2001 From: Lena Date: Fri, 20 Sep 2024 19:56:16 +0200 Subject: [PATCH 3/3] add manpage --- include/modules/gps.hpp | 3 ++ man/waybar-gps.5.scd | 71 +++++++++++++++++++++++++++++++++++++++-- src/modules/gps.cpp | 18 ++++++++++- 3 files changed, 89 insertions(+), 3 deletions(-) diff --git a/include/modules/gps.hpp b/include/modules/gps.hpp index a3335a106..6c2e980e7 100644 --- a/include/modules/gps.hpp +++ b/include/modules/gps.hpp @@ -27,6 +27,9 @@ namespace waybar::modules { util::SleeperThread thread_; gps_data_t gps_data_; std::string state_; + + bool hideDisconnected = true; + bool hideNoFix = false; }; } // namespace waybar::modules diff --git a/man/waybar-gps.5.scd b/man/waybar-gps.5.scd index dfa91c270..cf5faf42e 100644 --- a/man/waybar-gps.5.scd +++ b/man/waybar-gps.5.scd @@ -24,14 +24,81 @@ libgps lives in: # CONFIGURATION +*format*: ++ + typeof: string ++ + default: {glyph} ++ + The text format. +*tooltip*: ++ + typeof: bool ++ + default: true ++ + Option to disable tooltip on hover. + +*tooltip-format*: ++ + typeof: string ++ + default: Games running: {glyph} ++ + The text format of the tooltip. + +*interval*: ++ + typeof: integer ++ + default: 5 ++ + The interval in which the GPS information gets polled (e.g. fix status). + +*hide-disconnected*: ++ + typeof: bool ++ + default: true ++ + Defines if the module should be hidden if there is no GPS receiver. + +*hide-no-fix*: ++ + typeof: bool ++ + default: false ++ + Defines if the module should be hidden if there is no GPS fix. + +# FORMAT REPLACEMENTS + +*{mode}*: Fix mode + +*{status}*: Technology used for GPS fix. Not all GPS receivers report this. + +*{latitude}*: Latitude, decimal degrees. Can be NaN. + +*{latitude_error}*: Latitude uncertainty, meters. Can be NaN. + +*{longitude}*: Longitude, decimal degrees. Can be NaN. + +*{longitude_error}*: Longitude uncertainty, meters. Can be NaN. + +*{altitude_hae}*: Altitude, height above ellipsoid, meters. Can be NaN. + +*{altitude_msl}*: Longitude, MSL, meters. Can be NaN. + +*{altitude_error}*: Altitude uncertainty, meters. Can be NaN. + +*{speed}*: Speed over ground, meters/sec. Can be NaN. + +*{speed_error}*: Speed uncertainty, meters/sec. Can be NaN. + +*{climb}*: Vertical speed, meters/sec. Can be NaN. + +*{climb_error}*: Vertical speed uncertainty, meters/sec. Can be NaN. + +*{satellites_visible}*: Number of satellites visible from the GPS receiver. + +*{satellites_used}*: Number of satellites used for the GPS fix. # EXAMPLES ``` "gps": { - -}, + "format": "{mode}", + "format-no-fix": "No fix", + "format-fix-3d": "{status}", + "tooltip-format": "{mode}", + "tooltip-format-no-fix": "{satellites_visible} satellites visible", + "tooltip-format-fix-2d": "{satellites_used}/{satellites_visible} satellites used", + "tooltip-format-fix-3d": "Altitude: {altitude_hae}m", + "hide-disconnected": false +} ``` # STYLE diff --git a/src/modules/gps.cpp b/src/modules/gps.cpp index e2367c41e..12e01ac48 100644 --- a/src/modules/gps.cpp +++ b/src/modules/gps.cpp @@ -20,7 +20,7 @@ namespace { waybar::modules::Gps::Gps(const std::string& id, const Json::Value& config) -: ALabel(config, "gps", id, "{}", 1) { +: ALabel(config, "gps", id, "{}", 5) { thread_ = [this] { dp.emit(); thread_.sleep_for(interval_); @@ -30,6 +30,14 @@ waybar::modules::Gps::Gps(const std::string& id, const Json::Value& config) throw std::runtime_error("Can't open gpsd socket"); } + if (config_["hide-disconnected"].isBool()) { + hideDisconnected = config_["hide-disconnected"].asBool(); + } + + if (config_["hide-no-fix"].isBool()) { + hideNoFix = config_["hide-no-fix"].asBool(); + } + gps_stream(&gps_data_, WATCH_ENABLE, NULL); } @@ -89,6 +97,14 @@ auto waybar::modules::Gps::update() -> void { throw std::runtime_error("Can't read data from gpsd."); } + if ((gps_data_.fix.mode == MODE_NOT_SEEN && hideDisconnected) || (gps_data_.fix.mode == MODE_NO_FIX && hideNoFix)) { + event_box_.set_visible(false); + return; + } + + // Show the module + if (!event_box_.get_visible()) event_box_.set_visible(true); + std::string tooltip_format; if (!alt_) {