mirror of
https://github.com/rad4day/Waybar.git
synced 2023-12-21 10:22:59 +01:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
c3bd6da1d0 | |||
e3e099f836 | |||
767d9dd5b4 | |||
d1d51b76aa | |||
cee031d2fa | |||
18c7ad0026 | |||
1555cb71e1 | |||
ea9a08d473 | |||
68f9ea3065 | |||
a423f7032d | |||
01894f18cd | |||
3690e7ac55 | |||
b381e2a596 | |||
67fa8bd4c3 | |||
6ff296a4b0 | |||
8d5b61a9fd | |||
3c66f4baa7 | |||
04183dc696 | |||
14053d61fc | |||
424ebb3c9b | |||
2512d51564 | |||
95f1ab471a | |||
c792871f6e | |||
8b0cdc5f4b | |||
7d05f6c612 | |||
679aafa9e8 | |||
9b2c551f2e | |||
d728de2dd7 | |||
4d3879f26f |
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtkmm.h>
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
class IModule {
|
class IModule {
|
||||||
public:
|
public:
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||||
|
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
@ -17,17 +18,19 @@ namespace waybar {
|
|||||||
struct zwlr_layer_surface_v1 *layerSurface;
|
struct zwlr_layer_surface_v1 *layerSurface;
|
||||||
std::unique_ptr<struct wl_output *> output;
|
std::unique_ptr<struct wl_output *> output;
|
||||||
bool visible = true;
|
bool visible = true;
|
||||||
auto setWidth(int) -> void;
|
std::string outputName;
|
||||||
|
auto setWidth(uint32_t) -> void;
|
||||||
auto toggle() -> void;
|
auto toggle() -> void;
|
||||||
private:
|
private:
|
||||||
static void _handleGeometry(void *data, struct wl_output *wl_output,
|
static void _handleLogicalPosition(void *data,
|
||||||
int32_t x, int32_t y, int32_t physical_width, int32_t physical_height,
|
struct zxdg_output_v1 *zxdg_output_v1, int32_t x, int32_t y);
|
||||||
int32_t subpixel, const char *make, const char *model, int32_t transform);
|
static void _handleLogicalSize(void *data,
|
||||||
static void _handleMode(void *data, struct wl_output *wl_output,
|
struct zxdg_output_v1 *zxdg_output_v1, int32_t width, int32_t height);
|
||||||
uint32_t f, int32_t w, int32_t h, int32_t refresh);
|
static void _handleDone(void *data, struct zxdg_output_v1 *zxdg_output_v1);
|
||||||
static void _handleDone(void *data, struct wl_output *);
|
static void _handleName(void *data, struct zxdg_output_v1 *xdg_output,
|
||||||
static void _handleScale(void *data, struct wl_output *wl_output,
|
const char *name);
|
||||||
int32_t factor);
|
static void _handleDescription(void *data,
|
||||||
|
struct zxdg_output_v1 *zxdg_output_v1, const char *description);
|
||||||
static void _layerSurfaceHandleConfigure(void *data,
|
static void _layerSurfaceHandleConfigure(void *data,
|
||||||
struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t width,
|
struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t width,
|
||||||
uint32_t height);
|
uint32_t height);
|
||||||
@ -36,10 +39,12 @@ namespace waybar {
|
|||||||
auto _setupConfig() -> void;
|
auto _setupConfig() -> void;
|
||||||
auto _setupWidgets() -> void;
|
auto _setupWidgets() -> void;
|
||||||
auto _setupCss() -> void;
|
auto _setupCss() -> void;
|
||||||
int _width = 10;
|
uint32_t _width = 0;
|
||||||
|
uint32_t _height = 30;
|
||||||
Json::Value _config;
|
Json::Value _config;
|
||||||
Glib::RefPtr<Gtk::StyleContext> _styleContext;
|
Glib::RefPtr<Gtk::StyleContext> _styleContext;
|
||||||
Glib::RefPtr<Gtk::CssProvider> _cssProvider;
|
Glib::RefPtr<Gtk::CssProvider> _cssProvider;
|
||||||
|
struct zxdg_output_v1 *_xdgOutput;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,11 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wordexp.h>
|
#include <wordexp.h>
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <gdk/gdk.h>
|
#include <gdk/gdk.h>
|
||||||
#include <gtkmm.h>
|
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
|
|
||||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
|
||||||
#include "idle-client-protocol.h"
|
|
||||||
|
|
||||||
#include "util/ptr_vec.hpp"
|
|
||||||
|
|
||||||
#include <gdk/gdkwayland.h>
|
#include <gdk/gdkwayland.h>
|
||||||
|
|
||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
@ -23,19 +15,19 @@
|
|||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
struct Client {
|
struct Client {
|
||||||
uint32_t height = 30;
|
|
||||||
std::string cssFile;
|
std::string cssFile;
|
||||||
std::string configFile;
|
std::string configFile;
|
||||||
|
|
||||||
Gtk::Main gtk_main;
|
Gtk::Main gtk_main;
|
||||||
|
|
||||||
Glib::RefPtr<Gdk::Display> gdk_display;
|
Glib::RefPtr<Gdk::Display> gdk_display;
|
||||||
struct wl_display *wlDisplay;
|
struct wl_display *wlDisplay = nullptr;
|
||||||
struct wl_registry *registry;
|
struct wl_registry *registry = nullptr;
|
||||||
struct zwlr_layer_shell_v1 *layer_shell;
|
struct zwlr_layer_shell_v1 *layer_shell = nullptr;
|
||||||
struct org_kde_kwin_idle *idle_manager;
|
struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
|
||||||
struct wl_seat *seat;
|
struct wl_seat *seat = nullptr;
|
||||||
util::ptr_vec<Bar> bars;
|
struct wl_output *wlOutput = nullptr;
|
||||||
|
std::vector<std::unique_ptr<Bar>> bars;
|
||||||
|
|
||||||
Client(int argc, char* argv[]);
|
Client(int argc, char* argv[]);
|
||||||
void bind_interfaces();
|
void bind_interfaces();
|
||||||
|
@ -15,7 +15,7 @@ namespace waybar {
|
|||||||
class Factory {
|
class Factory {
|
||||||
public:
|
public:
|
||||||
Factory(Bar &bar, Json::Value config);
|
Factory(Bar &bar, Json::Value config);
|
||||||
IModule &makeModule(std::string name);
|
IModule *makeModule(std::string name);
|
||||||
private:
|
private:
|
||||||
Bar &_bar;
|
Bar &_bar;
|
||||||
Json::Value _config;
|
Json::Value _config;
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <gtkmm.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
#include <algorithm>
|
||||||
#include "util/chrono.hpp"
|
#include "util/chrono.hpp"
|
||||||
#include "IModule.hpp"
|
#include "IModule.hpp"
|
||||||
|
|
||||||
@ -19,6 +20,7 @@ namespace waybar::modules {
|
|||||||
auto update() -> void;
|
auto update() -> void;
|
||||||
operator Gtk::Widget&();
|
operator Gtk::Widget&();
|
||||||
private:
|
private:
|
||||||
|
std::string _getIcon(uint16_t percentage);
|
||||||
static inline const fs::path _data_dir = "/sys/class/power_supply/";
|
static inline const fs::path _data_dir = "/sys/class/power_supply/";
|
||||||
std::vector<fs::path> _batteries;
|
std::vector<fs::path> _batteries;
|
||||||
util::SleeperThread _thread;
|
util::SleeperThread _thread;
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <gtkmm.h>
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <thread>
|
|
||||||
#include "util/chrono.hpp"
|
#include "util/chrono.hpp"
|
||||||
#include "IModule.hpp"
|
#include "IModule.hpp"
|
||||||
|
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <gtkmm.h>
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <sys/sysinfo.h>
|
#include <sys/sysinfo.h>
|
||||||
#include <thread>
|
|
||||||
#include "util/chrono.hpp"
|
#include "util/chrono.hpp"
|
||||||
#include "IModule.hpp"
|
#include "IModule.hpp"
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <gtkmm.h>
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <thread>
|
|
||||||
#include "util/chrono.hpp"
|
#include "util/chrono.hpp"
|
||||||
#include "IModule.hpp"
|
#include "IModule.hpp"
|
||||||
|
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <gtkmm.h>
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <sys/sysinfo.h>
|
#include <sys/sysinfo.h>
|
||||||
#include <thread>
|
|
||||||
#include "util/chrono.hpp"
|
#include "util/chrono.hpp"
|
||||||
#include "IModule.hpp"
|
#include "IModule.hpp"
|
||||||
|
|
||||||
|
@ -5,11 +5,8 @@
|
|||||||
#include <netlink/genl/genl.h>
|
#include <netlink/genl/genl.h>
|
||||||
#include <netlink/genl/ctrl.h>
|
#include <netlink/genl/ctrl.h>
|
||||||
#include <linux/nl80211.h>
|
#include <linux/nl80211.h>
|
||||||
#include <iwlib.h> // TODO
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <gtkmm.h>
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <thread>
|
|
||||||
#include "util/chrono.hpp"
|
#include "util/chrono.hpp"
|
||||||
#include "IModule.hpp"
|
#include "IModule.hpp"
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#include <pulse/pulseaudio.h>
|
#include <pulse/pulseaudio.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <gtkmm.h>
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
#include <algorithm>
|
||||||
#include "IModule.hpp"
|
#include "IModule.hpp"
|
||||||
|
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
@ -14,6 +14,7 @@ namespace waybar::modules {
|
|||||||
auto update() -> void;
|
auto update() -> void;
|
||||||
operator Gtk::Widget &();
|
operator Gtk::Widget &();
|
||||||
private:
|
private:
|
||||||
|
std::string _getIcon(uint16_t percentage);
|
||||||
static void _subscribeCb(pa_context *context,
|
static void _subscribeCb(pa_context *context,
|
||||||
pa_subscription_event_type_t type, uint32_t idx, void *data);
|
pa_subscription_event_type_t type, uint32_t idx, void *data);
|
||||||
static void _contextStateCb(pa_context *c, void *data);
|
static void _contextStateCb(pa_context *c, void *data);
|
||||||
|
@ -4,30 +4,34 @@
|
|||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
#include "util/chrono.hpp"
|
#include "util/chrono.hpp"
|
||||||
|
#include "util/json.hpp"
|
||||||
#include "IModule.hpp"
|
#include "IModule.hpp"
|
||||||
|
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
|
|
||||||
class Workspaces : public IModule {
|
class Workspaces : public IModule {
|
||||||
public:
|
public:
|
||||||
Workspaces(waybar::Bar &bar);
|
Workspaces(waybar::Bar &bar, Json::Value config);
|
||||||
auto update() -> void;
|
auto update() -> void;
|
||||||
operator Gtk::Widget &();
|
operator Gtk::Widget &();
|
||||||
private:
|
private:
|
||||||
void _updateThread();
|
|
||||||
static void _handle_idle(void *data,
|
|
||||||
struct org_kde_kwin_idle_timeout *timer);
|
|
||||||
static void _handle_resume(void *data,
|
|
||||||
struct org_kde_kwin_idle_timeout *timer);
|
|
||||||
void _addWorkspace(Json::Value node);
|
void _addWorkspace(Json::Value node);
|
||||||
Json::Value _getWorkspaces();
|
std::string _getIcon(std::string name);
|
||||||
|
Json::Value _getWorkspaces(const std::string data);
|
||||||
|
bool _handleScroll(GdkEventScroll *e);
|
||||||
|
int _getPrevWorkspace();
|
||||||
|
int _getNextWorkspace();
|
||||||
Bar &_bar;
|
Bar &_bar;
|
||||||
util::SleeperThread *_thread;
|
Json::Value _config;
|
||||||
Gtk::Box *_box;
|
waybar::util::SleeperThread _thread;
|
||||||
|
Gtk::Box _box;
|
||||||
|
util::JsonParser _parser;
|
||||||
|
std::mutex _mutex;
|
||||||
|
bool _scrolling;
|
||||||
std::unordered_map<int, Gtk::Button> _buttons;
|
std::unordered_map<int, Gtk::Button> _buttons;
|
||||||
int _ipcSocketfd;
|
Json::Value _workspaces;
|
||||||
int _ipcEventSocketfd;
|
int _ipcfd;
|
||||||
struct org_kde_kwin_idle_timeout *_idle_timer;
|
int _ipcEventfd;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,823 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <functional>
|
|
||||||
#include <initializer_list>
|
|
||||||
#include <numeric>
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
namespace waybar::util {
|
|
||||||
|
|
||||||
/// Joins a sequence of strings, separating them using `js`
|
|
||||||
template<class StrIterator> // Models InputIterator<std::string>
|
|
||||||
std::string join_strings(StrIterator b, StrIterator e, std::string_view js = ", ")
|
|
||||||
{
|
|
||||||
std::string result;
|
|
||||||
std::for_each(b, e, [&](auto&& s) {
|
|
||||||
if (!result.empty()) {
|
|
||||||
result.append(js);
|
|
||||||
}
|
|
||||||
result.append(s);
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char* nonull(const char* str) {
|
|
||||||
if (str == nullptr) return "";
|
|
||||||
return str;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool iequals(std::string_view a, std::string_view b)
|
|
||||||
{
|
|
||||||
return std::equal(a.begin(), a.end(), b.begin(), b.end(),
|
|
||||||
[](char a, char b) { return tolower(a) == tolower(b); });
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool starts_with(std::string_view prefix, std::string_view a)
|
|
||||||
{
|
|
||||||
return a.compare(0, prefix.size(), prefix) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool ends_with(std::string_view prefix, std::string_view a)
|
|
||||||
{
|
|
||||||
return a.compare(a.size() - prefix.size(), prefix.size(), prefix) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a closure which compares the adress any reference to T to the address of t
|
|
||||||
template<typename T>
|
|
||||||
constexpr auto addr_eq(T&& t) {
|
|
||||||
return [&t] (auto&& t2) {
|
|
||||||
return &t == &t2;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool erase_this(std::vector<T>& cont, T* el)
|
|
||||||
{
|
|
||||||
if (el < cont.data() && el >= cont.data() + cont.size()) return false;
|
|
||||||
cont.erase(cont.begin() + (el - cont.data()));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool erase_this(std::vector<T>& cont, T& el)
|
|
||||||
{
|
|
||||||
return erase_this(cont, &el);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template<class Func, int... ns>
|
|
||||||
constexpr auto generate_array_impl(std::integer_sequence<int, ns...>&&, Func&& gen)
|
|
||||||
{
|
|
||||||
return std::array<std::decay_t<decltype(std::invoke(gen, std::declval<int>()))>,
|
|
||||||
sizeof...(ns)>{{std::invoke(gen, ns)...}};
|
|
||||||
}
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<int n, class Func>
|
|
||||||
constexpr auto generate_array(Func&& gen)
|
|
||||||
{
|
|
||||||
auto intseq = std::make_integer_sequence<int, n>();
|
|
||||||
return detail::generate_array_impl(std::move(intseq), std::forward<Func>(gen));
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace view {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template<typename T>
|
|
||||||
using store_or_ref_t = std::conditional_t<std::is_rvalue_reference_v<T>, std::decay_t<T>, T&>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont>
|
|
||||||
struct reverse {
|
|
||||||
|
|
||||||
reverse(Cont&& cont) noexcept : _container(std::forward<Cont>(cont)) {}
|
|
||||||
|
|
||||||
auto begin()
|
|
||||||
{
|
|
||||||
return std::rbegin(_container);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto end()
|
|
||||||
{
|
|
||||||
return std::rend(_container);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto begin() const
|
|
||||||
{
|
|
||||||
return std::rbegin(_container);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto end() const
|
|
||||||
{
|
|
||||||
return std::rend(_container);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cbegin() const
|
|
||||||
{
|
|
||||||
return std::crbegin(_container);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cend() const
|
|
||||||
{
|
|
||||||
return std::crend(_container);
|
|
||||||
}
|
|
||||||
|
|
||||||
detail::store_or_ref_t<Cont&&> _container;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ContRef>
|
|
||||||
reverse(ContRef&& cont) -> reverse<ContRef&&>;
|
|
||||||
|
|
||||||
template<typename Cont>
|
|
||||||
struct constant {
|
|
||||||
constant(Cont&& cont) noexcept : _container(std::forward<Cont>(cont)){};
|
|
||||||
|
|
||||||
auto begin() const
|
|
||||||
{
|
|
||||||
return std::cbegin(_container);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto end() const
|
|
||||||
{
|
|
||||||
return std::cend(_container);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cbegin() const
|
|
||||||
{
|
|
||||||
return std::cbegin(_container);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cend() const
|
|
||||||
{
|
|
||||||
return std::cend(_container);
|
|
||||||
}
|
|
||||||
|
|
||||||
detail::store_or_ref_t<Cont&&> _container;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ContRef>
|
|
||||||
constant(ContRef&& cont) -> constant<ContRef&&>;
|
|
||||||
|
|
||||||
} // namespace view
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Range algorithms
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<typename InputIt, typename Size, typename F>
|
|
||||||
constexpr InputIt for_each_n(InputIt&& first, Size n, F&& f)
|
|
||||||
{
|
|
||||||
for (Size i = 0; i < n; ++first, ++i) {
|
|
||||||
std::invoke(f, *first);
|
|
||||||
}
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `for_each` with access to an index value. Function called as `f(*it, i)`
|
|
||||||
///
|
|
||||||
/// For each item in range `[first, last)`, invoke `f` with args
|
|
||||||
/// `*iter, i` where `iter` is the current iterator, and `i` is
|
|
||||||
/// an incrementing value, starting at zero. Use this instead of
|
|
||||||
/// raw indexed loops wherever possible.
|
|
||||||
///
|
|
||||||
/// \param first Input iterator to the begining of the range
|
|
||||||
/// \param last Input iterator to the end of the range
|
|
||||||
/// \param f Must be invocable with arguments `value_type`, `std::size_t`
|
|
||||||
/// \returns The number of iterations performed
|
|
||||||
template<typename InputIt, typename F>
|
|
||||||
constexpr std::size_t indexed_for(InputIt&& first, InputIt&& last, F&& f)
|
|
||||||
{
|
|
||||||
std::size_t i = 0;
|
|
||||||
std::for_each(std::forward<InputIt>(first), std::forward<InputIt>(last), [&](auto&& a) {
|
|
||||||
std::invoke(f, a, i);
|
|
||||||
i++;
|
|
||||||
});
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Rng, typename F>
|
|
||||||
constexpr std::size_t indexed_for(Rng&& rng, F&& f)
|
|
||||||
{
|
|
||||||
return indexed_for(std::begin(rng), std::end(rng), std::forward<F>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// `for_each_n` with access to an index value. Function called as `f(*it, i)`
|
|
||||||
///
|
|
||||||
/// for `n` iterations, invoke `f` with args `*iter, i`
|
|
||||||
/// where `iter` is the current iterator starting with `first`,
|
|
||||||
/// and `i` is an incrementing value, starting at zero.
|
|
||||||
/// Use this instead of raw indexed loops wherever possible.
|
|
||||||
///
|
|
||||||
/// \param first Input iterator to the begining of the range
|
|
||||||
/// \param n Number of iterations to go through
|
|
||||||
/// \param f Must be invocable with arguments `value_type`, `std::size_t`
|
|
||||||
/// \returns An iterator one past the last one visited
|
|
||||||
template<class InputIt, class Size, class F>
|
|
||||||
constexpr InputIt indexed_for_n(InputIt first, Size n, F&& f)
|
|
||||||
{
|
|
||||||
for (Size i = 0; i < n; ++first, ++i) {
|
|
||||||
std::invoke(f, *first, i);
|
|
||||||
}
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Rng, class Size, class F>
|
|
||||||
constexpr std::size_t indexed_for_n(Rng&& rng, Size n, F&& f)
|
|
||||||
{
|
|
||||||
return indexed_for_n(std::begin(rng), std::end(rng), n, std::forward<F>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Iter1, typename Iter2, typename F>
|
|
||||||
constexpr void for_both(Iter1&& f1, Iter1&& l1, Iter2&& f2, Iter2&& l2, F&& f)
|
|
||||||
{
|
|
||||||
Iter1 i1 = std::forward<Iter1>(f1);
|
|
||||||
Iter2 i2 = std::forward<Iter2>(f2);
|
|
||||||
for (; i1 != l1 && i2 != l2; i1++, i2++) {
|
|
||||||
std::invoke(f, *i1, *i2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Rng1, typename Rng2, typename F>
|
|
||||||
constexpr void for_both(Rng1&& r1, Rng2&& r2, F&& f)
|
|
||||||
{
|
|
||||||
for_both(std::begin(r1), std::end(r1), std::begin(r2), std::end(r2), std::forward<F>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Range based standard algorithms
|
|
||||||
*
|
|
||||||
* Thanks, chris from SO!
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<typename Cont, typename T>
|
|
||||||
constexpr auto accumulate(Cont&& cont, T&& init)
|
|
||||||
{
|
|
||||||
// TODO C++20: std::accumulate is constexpr
|
|
||||||
using std::begin, std::end;
|
|
||||||
auto first = begin(cont);
|
|
||||||
auto last = end(cont);
|
|
||||||
for (; first != last; ++first) init = init + *first;
|
|
||||||
return init;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename T, typename BinaryOperation>
|
|
||||||
constexpr auto accumulate(Cont&& cont, T&& init, BinaryOperation&& op)
|
|
||||||
{
|
|
||||||
// TODO C++20: std::accumulate is constexpr
|
|
||||||
using std::begin, std::end;
|
|
||||||
auto first = begin(cont);
|
|
||||||
auto last = end(cont);
|
|
||||||
for (; first != last; ++first) init = op(init, *first);
|
|
||||||
return init;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename OutputIterator>
|
|
||||||
decltype(auto) adjacent_difference(Cont&& cont, OutputIterator&& first)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::adjacent_difference(begin(cont), end(cont), std::forward<OutputIterator>(first));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont>
|
|
||||||
decltype(auto) prev_permutation(Cont&& cont)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::prev_permutation(begin(cont), end(cont));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Compare>
|
|
||||||
decltype(auto) prev_permutation(Cont&& cont, Compare&& comp)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::prev_permutation(begin(cont), end(cont), std::forward<Compare>(comp));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont>
|
|
||||||
decltype(auto) push_heap(Cont&& cont)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::push_heap(begin(cont), end(cont));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Compare>
|
|
||||||
decltype(auto) push_heap(Cont&& cont, Compare&& comp)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::push_heap(begin(cont), end(cont), std::forward<Compare>(comp));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename T>
|
|
||||||
decltype(auto) remove(Cont&& cont, T&& value)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::remove(begin(cont), end(cont), std::forward<T>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename OutputIterator, typename T>
|
|
||||||
decltype(auto) remove_copy(Cont&& cont, OutputIterator&& first, T&& value)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::remove_copy(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
||||||
std::forward<T>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename OutputIterator, typename UnaryPredicate>
|
|
||||||
decltype(auto) remove_copy_if(Cont&& cont, OutputIterator&& first, UnaryPredicate&& p)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::remove_copy_if(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
||||||
std::forward<UnaryPredicate>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename UnaryPredicate>
|
|
||||||
decltype(auto) remove_if(Cont&& cont, UnaryPredicate&& p)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::remove_if(begin(cont), end(cont), std::forward<UnaryPredicate>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename T, typename T2>
|
|
||||||
decltype(auto) replace(Cont&& cont, T&& old_value, T2&& new_value)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::replace(begin(cont), end(cont), std::forward<T>(old_value),
|
|
||||||
std::forward<T2>(new_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename OutputIterator, typename T, typename T2>
|
|
||||||
decltype(auto) replace_copy(Cont&& cont, OutputIterator&& first, T&& old_value, T2&& new_value)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::replace_copy(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
||||||
std::forward<T>(old_value), std::forward<T2>(old_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename OutputIterator, typename UnaryPredicate, typename T>
|
|
||||||
decltype(auto) replace_copy_if(Cont&& cont,
|
|
||||||
OutputIterator&& first,
|
|
||||||
UnaryPredicate&& p,
|
|
||||||
T&& new_value)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::replace_copy(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
||||||
std::forward<UnaryPredicate>(p), std::forward<T>(new_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename UnaryPredicate, typename T>
|
|
||||||
decltype(auto) replace_if(Cont&& cont, UnaryPredicate&& p, T&& new_value)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::replace_if(begin(cont), end(cont), std::forward<UnaryPredicate>(p),
|
|
||||||
std::forward<T>(new_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont>
|
|
||||||
decltype(auto) reverse(Cont&& cont)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::reverse(begin(cont), end(cont));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename OutputIterator>
|
|
||||||
decltype(auto) reverse_copy(Cont&& cont, OutputIterator&& first)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::reverse_copy(begin(cont), end(cont), std::forward<OutputIterator>(first));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename ForwardIterator>
|
|
||||||
decltype(auto) rotate(Cont&& cont, ForwardIterator&& new_first)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::rotate(begin(cont), std::forward<ForwardIterator>(new_first), end(cont));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename ForwardIterator, typename OutputIterator>
|
|
||||||
decltype(auto) rotate_copy(Cont&& cont, ForwardIterator&& new_first, OutputIterator&& first)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::rotate_copy(begin(cont), std::forward<ForwardIterator>(new_first), end(cont),
|
|
||||||
std::forward<OutputIterator>(first));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2>
|
|
||||||
decltype(auto) search(Cont&& cont, Cont2&& cont2)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::search(begin(cont), end(cont), begin(cont2), end(cont2));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename BinaryPredicate>
|
|
||||||
decltype(auto) search(Cont&& cont, Cont2&& cont2, BinaryPredicate&& p)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::search(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
||||||
std::forward<BinaryPredicate>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Size, typename T>
|
|
||||||
decltype(auto) search_n(Cont&& cont, Size count, T&& value)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::search_n(begin(cont), end(cont), count, std::forward<T>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Size, typename T, typename BinaryPredicate>
|
|
||||||
decltype(auto) search_n(Cont&& cont, Size count, T&& value, BinaryPredicate&& p)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::search_n(begin(cont), end(cont), count, std::forward<T>(value),
|
|
||||||
std::forward<BinaryPredicate>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename OutputIterator>
|
|
||||||
decltype(auto) set_difference(Cont&& cont, Cont2&& cont2, OutputIterator&& first)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::set_difference(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
||||||
std::forward<OutputIterator>(first));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename OutputIterator, typename Compare>
|
|
||||||
decltype(auto) set_difference(Cont&& cont, Cont2&& cont2, OutputIterator&& first, Compare&& comp)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::set_difference(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
||||||
std::forward<OutputIterator>(first), std::forward<Compare>(comp));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename OutputIterator>
|
|
||||||
decltype(auto) set_intersection(Cont&& cont, Cont2&& cont2, OutputIterator&& first)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::set_intersection(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
||||||
std::forward<OutputIterator>(first));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename OutputIterator, typename Compare>
|
|
||||||
decltype(auto) set_intersection(Cont&& cont,
|
|
||||||
Cont2&& cont2,
|
|
||||||
OutputIterator&& first,
|
|
||||||
Compare&& comp)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::set_intersection(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
||||||
std::forward<OutputIterator>(first), std::forward<Compare>(comp));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename OutputIterator>
|
|
||||||
decltype(auto) set_symmetric_difference(Cont&& cont, Cont2&& cont2, OutputIterator&& first)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::set_symmetric_difference(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
||||||
std::forward<OutputIterator>(first));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename OutputIterator, typename Compare>
|
|
||||||
decltype(auto) set_symmetric_difference(Cont&& cont,
|
|
||||||
Cont2&& cont2,
|
|
||||||
OutputIterator&& first,
|
|
||||||
Compare&& comp)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::set_symmetric_difference(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
||||||
std::forward<OutputIterator>(first),
|
|
||||||
std::forward<Compare>(comp));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename OutputIterator>
|
|
||||||
decltype(auto) set_union(Cont&& cont, Cont2&& cont2, OutputIterator&& first)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::set_union(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
||||||
std::forward<OutputIterator>(first));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename OutputIterator, typename Compare>
|
|
||||||
decltype(auto) set_union(Cont&& cont, Cont2&& cont2, OutputIterator&& first, Compare&& comp)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::set_union(begin(cont), end(cont), begin(cont2), end(cont2),
|
|
||||||
std::forward<OutputIterator>(first), std::forward<Compare>(comp));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename UniformRandomNumberGenerator>
|
|
||||||
decltype(auto) shuffle(Cont&& cont, UniformRandomNumberGenerator&& g)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::shuffle(begin(cont), end(cont), std::forward<UniformRandomNumberGenerator>(g));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont>
|
|
||||||
decltype(auto) sort(Cont&& cont)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::sort(begin(cont), end(cont));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Compare>
|
|
||||||
decltype(auto) sort(Cont&& cont, Compare&& comp)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::sort(begin(cont), end(cont), std::forward<Compare>(comp));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont>
|
|
||||||
decltype(auto) sort_heap(Cont&& cont)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::sort_heap(begin(cont), end(cont));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Compare>
|
|
||||||
decltype(auto) sort_heap(Cont&& cont, Compare&& comp)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::sort_heap(begin(cont), end(cont), std::forward<Compare>(comp));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename UnaryPredicate>
|
|
||||||
decltype(auto) stable_partition(Cont&& cont, UnaryPredicate&& p)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::stable_partition(begin(cont), end(cont), std::forward<UnaryPredicate>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont>
|
|
||||||
decltype(auto) stable_sort(Cont&& cont)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::stable_sort(begin(cont), end(cont));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Compare>
|
|
||||||
decltype(auto) stable_sort(Cont&& cont, Compare&& comp)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::stable_sort(begin(cont), end(cont), std::forward<Compare>(comp));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename ForwardIterator>
|
|
||||||
decltype(auto) swap_ranges(Cont&& cont, ForwardIterator&& first)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::swap_ranges(begin(cont), end(cont), std::forward<ForwardIterator>(first));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename F>
|
|
||||||
auto transform(Cont&& cont, Cont2&& cont2, F&& f) -> decltype(begin(cont2))
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::transform(begin(cont), end(cont), begin(cont2), std::forward<F>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Iter, typename F>
|
|
||||||
decltype(auto) transform(Cont&& cont, Iter&& iter, F&& f)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::transform(begin(cont), end(cont), std::forward<Iter>(iter), std::forward<F>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename Cont3, typename BinaryPredicate>
|
|
||||||
auto transform(Cont&& cont, Cont2&& cont2, Cont3&& cont3, BinaryPredicate&& f)
|
|
||||||
-> decltype(begin(cont2), begin(cont3))
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::transform(begin(cont), end(cont), begin(cont2), begin(cont3),
|
|
||||||
std::forward<BinaryPredicate>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename InputIterator, typename Cont3, typename BinaryPredicate>
|
|
||||||
auto transform(Cont&& cont, InputIterator&& iter, Cont3&& cont3, BinaryPredicate&& f)
|
|
||||||
-> decltype(begin(cont), begin(cont3))
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::transform(begin(cont), end(cont), std::forward<InputIterator>(iter), begin(cont3),
|
|
||||||
std::forward<BinaryPredicate>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Cont2, typename InputIterator, typename BinaryPredicate>
|
|
||||||
auto transform(Cont&& cont, Cont2&& cont2, InputIterator&& iter, BinaryPredicate&& f)
|
|
||||||
-> decltype(begin(cont), begin(cont2), iter)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::transform(begin(cont), end(cont), begin(cont2), std::forward<InputIterator>(iter),
|
|
||||||
std::forward<BinaryPredicate>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename InputIterator, typename OutputIterator, typename BinaryOperation>
|
|
||||||
decltype(auto) transform(Cont&& cont,
|
|
||||||
InputIterator&& firstIn,
|
|
||||||
OutputIterator&& firstOut,
|
|
||||||
BinaryOperation&& op)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::transform(begin(cont), end(cont), std::forward<InputIterator>(firstIn),
|
|
||||||
std::forward<OutputIterator>(firstOut),
|
|
||||||
std::forward<BinaryOperation>(op));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont>
|
|
||||||
decltype(auto) unique(Cont&& cont)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::unique(begin(cont), end(cont));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename BinaryPredicate>
|
|
||||||
decltype(auto) unique(Cont&& cont, BinaryPredicate&& p)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::unique(begin(cont), end(cont), std::forward<BinaryPredicate>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename OutputIterator>
|
|
||||||
decltype(auto) unique_copy(Cont&& cont, OutputIterator&& first)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::unique_copy(begin(cont), end(cont), std::forward<OutputIterator>(first));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename OutputIterator, typename BinaryPredicate>
|
|
||||||
decltype(auto) unique_copy(Cont&& cont, OutputIterator&& first, BinaryPredicate&& p)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::unique_copy(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
||||||
std::forward<BinaryPredicate>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename T>
|
|
||||||
decltype(auto) upper_bound(Cont&& cont, T&& value)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::upper_bound(begin(cont), end(cont), std::forward<T>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename T, typename Compare>
|
|
||||||
decltype(auto) upper_bound(Cont&& cont, T&& value, Compare&& comp)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::upper_bound(begin(cont), end(cont), std::forward<T>(value),
|
|
||||||
std::forward<Compare>(comp));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename OutputIterator>
|
|
||||||
decltype(auto) copy(Cont&& cont, OutputIterator&& first)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::copy(begin(cont), end(cont), std::forward<OutputIterator>(first));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename OutputIterator, typename UnaryPredicate>
|
|
||||||
decltype(auto) copy_if(Cont&& cont, OutputIterator&& first, UnaryPredicate&& p)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::copy_if(begin(cont), end(cont), std::forward<OutputIterator>(first),
|
|
||||||
std::forward<UnaryPredicate>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename T>
|
|
||||||
decltype(auto) fill(Cont&& cont, T&& value)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::fill(begin(cont), end(cont), std::forward<T>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename T>
|
|
||||||
decltype(auto) fill_n(Cont&& cont, std::size_t n, T&& value)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::fill_n(begin(cont), n, std::forward<T>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename UnaryPredicate>
|
|
||||||
decltype(auto) any_of(Cont&& cont, UnaryPredicate&& p)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::any_of(begin(cont), end(cont), std::forward<UnaryPredicate>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename UnaryPredicate>
|
|
||||||
decltype(auto) all_of(Cont&& cont, UnaryPredicate&& p)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::all_of(begin(cont), end(cont), std::forward<UnaryPredicate>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename UnaryPredicate>
|
|
||||||
decltype(auto) none_of(Cont&& cont, UnaryPredicate&& p)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::none_of(begin(cont), end(cont), std::forward<UnaryPredicate>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont>
|
|
||||||
decltype(auto) max_element(Cont&& cont)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::max_element(begin(cont), end(cont));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont>
|
|
||||||
decltype(auto) min_element(Cont&& cont)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::min_element(begin(cont), end(cont));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Compare>
|
|
||||||
decltype(auto) min_element(Cont&& cont, Compare&& f)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::min_element(begin(cont), end(cont), std::forward<Compare>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename Compare>
|
|
||||||
decltype(auto) max_element(Cont&& cont, Compare&& f)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::max_element(begin(cont), end(cont), std::forward<Compare>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename T>
|
|
||||||
decltype(auto) find(Cont&& cont, T&& t)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::find(begin(cont), end(cont), std::forward<T>(t));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Cont, typename UnaryPredicate>
|
|
||||||
decltype(auto) find_if(Cont&& cont, UnaryPredicate&& f)
|
|
||||||
{
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
return std::find_if(begin(cont), end(cont), std::forward<UnaryPredicate>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace waybar::util
|
|
@ -39,7 +39,9 @@ namespace waybar::util {
|
|||||||
func();
|
func();
|
||||||
} while (do_run);
|
} while (do_run);
|
||||||
}}
|
}}
|
||||||
{}
|
{
|
||||||
|
defined = true;
|
||||||
|
}
|
||||||
|
|
||||||
SleeperThread& operator=(std::function<void()> func)
|
SleeperThread& operator=(std::function<void()> func)
|
||||||
{
|
{
|
||||||
@ -48,6 +50,7 @@ namespace waybar::util {
|
|||||||
func();
|
func();
|
||||||
} while (do_run);
|
} while (do_run);
|
||||||
});
|
});
|
||||||
|
defined = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,14 +75,17 @@ namespace waybar::util {
|
|||||||
~SleeperThread()
|
~SleeperThread()
|
||||||
{
|
{
|
||||||
do_run = false;
|
do_run = false;
|
||||||
|
if (defined) {
|
||||||
condvar.notify_all();
|
condvar.notify_all();
|
||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::thread thread;
|
std::thread thread;
|
||||||
std::condition_variable condvar;
|
std::condition_variable condvar;
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
|
bool defined = false;
|
||||||
bool do_run = true;
|
bool do_run = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
34
include/util/json.hpp
Normal file
34
include/util/json.hpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
|
namespace waybar::util {
|
||||||
|
|
||||||
|
struct JsonParser {
|
||||||
|
|
||||||
|
JsonParser()
|
||||||
|
: _reader(_builder.newCharReader())
|
||||||
|
{}
|
||||||
|
|
||||||
|
Json::Value parse(const std::string data)
|
||||||
|
{
|
||||||
|
Json::Value root;
|
||||||
|
std::string err;
|
||||||
|
bool res =
|
||||||
|
_reader->parse(data.c_str(), data.c_str() + data.size(), &root, &err);
|
||||||
|
if (!res)
|
||||||
|
throw std::runtime_error(err);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
~JsonParser()
|
||||||
|
{
|
||||||
|
delete _reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Json::CharReaderBuilder _builder;
|
||||||
|
Json::CharReader *_reader;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -1,581 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <memory>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <vector>
|
|
||||||
#include "algorithm.hpp"
|
|
||||||
|
|
||||||
namespace waybar::util {
|
|
||||||
|
|
||||||
/// An iterator wrapper that dereferences twice.
|
|
||||||
template<typename Iter>
|
|
||||||
struct double_iterator {
|
|
||||||
using wrapped = Iter;
|
|
||||||
|
|
||||||
using value_type = std::decay_t<decltype(*std::declval<typename wrapped::value_type>())>;
|
|
||||||
using difference_type = typename wrapped::difference_type;
|
|
||||||
using reference = value_type&;
|
|
||||||
using pointer = value_type*;
|
|
||||||
using iterator_category = std::random_access_iterator_tag;
|
|
||||||
|
|
||||||
using self_t = double_iterator<Iter>;
|
|
||||||
|
|
||||||
double_iterator(wrapped w) : _iter(std::move(w)) {}
|
|
||||||
double_iterator() : _iter() {}
|
|
||||||
|
|
||||||
reference operator*() const
|
|
||||||
{
|
|
||||||
return (**_iter);
|
|
||||||
}
|
|
||||||
pointer operator->() const
|
|
||||||
{
|
|
||||||
return &(**_iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
self_t& operator++()
|
|
||||||
{
|
|
||||||
_iter.operator++();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
self_t operator++(int i)
|
|
||||||
{
|
|
||||||
return _iter.operator++(i);
|
|
||||||
}
|
|
||||||
self_t& operator--()
|
|
||||||
{
|
|
||||||
_iter.operator--();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
self_t operator--(int i)
|
|
||||||
{
|
|
||||||
return _iter.operator--(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator==(const self_t& rhs) const noexcept
|
|
||||||
{
|
|
||||||
return _iter == rhs._iter;
|
|
||||||
}
|
|
||||||
auto operator!=(const self_t& rhs) const noexcept
|
|
||||||
{
|
|
||||||
return _iter != rhs._iter;
|
|
||||||
}
|
|
||||||
auto operator<(const self_t& rhs) const noexcept
|
|
||||||
{
|
|
||||||
return _iter < rhs._iter;
|
|
||||||
}
|
|
||||||
auto operator>(const self_t& rhs) const noexcept
|
|
||||||
{
|
|
||||||
return _iter > rhs._iter;
|
|
||||||
}
|
|
||||||
auto operator<=(const self_t& rhs) const noexcept
|
|
||||||
{
|
|
||||||
return _iter <= rhs._iter;
|
|
||||||
}
|
|
||||||
auto operator>=(const self_t& rhs) const noexcept
|
|
||||||
{
|
|
||||||
return _iter >= rhs._iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
self_t operator+(difference_type d) const noexcept
|
|
||||||
{
|
|
||||||
return _iter + d;
|
|
||||||
}
|
|
||||||
self_t operator-(difference_type d) const noexcept
|
|
||||||
{
|
|
||||||
return _iter - d;
|
|
||||||
}
|
|
||||||
auto operator-(const self_t& rhs) const noexcept
|
|
||||||
{
|
|
||||||
return _iter - rhs._iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
self_t& operator+=(difference_type d)
|
|
||||||
{
|
|
||||||
_iter += d;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
self_t& operator-=(difference_type d)
|
|
||||||
{
|
|
||||||
_iter -= d;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator wrapped&()
|
|
||||||
{
|
|
||||||
return _iter;
|
|
||||||
}
|
|
||||||
operator const wrapped&() const
|
|
||||||
{
|
|
||||||
return _iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
wrapped& data()
|
|
||||||
{
|
|
||||||
return _iter;
|
|
||||||
}
|
|
||||||
const wrapped& data() const
|
|
||||||
{
|
|
||||||
return _iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
wrapped _iter;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Iter>
|
|
||||||
auto operator+(typename double_iterator<Iter>::difference_type diff, double_iterator<Iter> iter)
|
|
||||||
{
|
|
||||||
return iter + diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// To avoid clients being moved, they are stored in unique_ptrs, which are
|
|
||||||
/// moved around in a vector. This class is purely for convenience, to still
|
|
||||||
/// have iterator semantics, and a few other utility functions
|
|
||||||
template<typename T>
|
|
||||||
struct ptr_vec {
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<value_type>> _order;
|
|
||||||
|
|
||||||
using iterator = double_iterator<typename decltype(_order)::iterator>;
|
|
||||||
using const_iterator = double_iterator<typename decltype(_order)::const_iterator>;
|
|
||||||
|
|
||||||
using reverse_iterator = double_iterator<typename decltype(_order)::reverse_iterator>;
|
|
||||||
using const_reverse_iterator =
|
|
||||||
double_iterator<typename decltype(_order)::const_reverse_iterator>;
|
|
||||||
|
|
||||||
value_type& push_back(const value_type& v)
|
|
||||||
{
|
|
||||||
auto ptr = std::make_unique<value_type>(v);
|
|
||||||
auto res = ptr.get();
|
|
||||||
_order.push_back(std::move(ptr));
|
|
||||||
return *res;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& push_back(value_type&& v)
|
|
||||||
{
|
|
||||||
auto ptr = std::make_unique<value_type>(std::move(v));
|
|
||||||
auto res = ptr.get();
|
|
||||||
_order.push_back(std::move(ptr));
|
|
||||||
return *res;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& push_back(std::unique_ptr<value_type> ptr)
|
|
||||||
{
|
|
||||||
auto res = ptr.get();
|
|
||||||
_order.push_back(std::move(ptr));
|
|
||||||
return *res;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
value_type& emplace_back(Args&&... args)
|
|
||||||
{
|
|
||||||
return push_back(std::make_unique<value_type>(std::forward<Args>(args)...));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<value_type> erase(const value_type& v)
|
|
||||||
{
|
|
||||||
auto iter =
|
|
||||||
std::find_if(_order.begin(), _order.end(), [&v](auto&& uptr) { return uptr.get() == &v; });
|
|
||||||
if (iter != _order.end()) {
|
|
||||||
auto uptr = std::move(*iter);
|
|
||||||
_order.erase(iter);
|
|
||||||
return uptr;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator rotate_to_back(const value_type& v)
|
|
||||||
{
|
|
||||||
auto iter =
|
|
||||||
std::find_if(_order.begin(), _order.end(), [&v](auto&& uptr) { return uptr.get() == &v; });
|
|
||||||
return rotate_to_back(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator rotate_to_back(iterator iter)
|
|
||||||
{
|
|
||||||
if (iter != _order.end()) {
|
|
||||||
{
|
|
||||||
return std::rotate(iter.data(), iter.data() + 1, _order.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return end();
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator rotate_to_front(const value_type& v)
|
|
||||||
{
|
|
||||||
auto iter =
|
|
||||||
std::find_if(_order.begin(), _order.end(), [&v](auto&& uptr) { return uptr.get() == &v; });
|
|
||||||
return rotate_to_front(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator rotate_to_front(iterator iter)
|
|
||||||
{
|
|
||||||
if (iter != _order.end()) {
|
|
||||||
{
|
|
||||||
return std::rotate(_order.begin(), iter.data(), iter.data() + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return end();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t size() const noexcept
|
|
||||||
{
|
|
||||||
return _order.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() const noexcept
|
|
||||||
{
|
|
||||||
return _order.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t capacity() const noexcept
|
|
||||||
{
|
|
||||||
return _order.capacity();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t max_size() const noexcept
|
|
||||||
{
|
|
||||||
return _order.max_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve(std::size_t new_cap)
|
|
||||||
{
|
|
||||||
_order.reserve(new_cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shrink_to_fit()
|
|
||||||
{
|
|
||||||
_order.shrink_to_fit();
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& operator[](std::size_t n)
|
|
||||||
{
|
|
||||||
return *_order[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
const value_type& operator[](std::size_t n) const
|
|
||||||
{
|
|
||||||
return *_order[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& at(std::size_t n)
|
|
||||||
{
|
|
||||||
return *_order.at(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
const value_type& at(std::size_t n) const
|
|
||||||
{
|
|
||||||
return *_order.at(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator begin()
|
|
||||||
{
|
|
||||||
return _order.begin();
|
|
||||||
}
|
|
||||||
iterator end()
|
|
||||||
{
|
|
||||||
return _order.end();
|
|
||||||
}
|
|
||||||
const_iterator begin() const
|
|
||||||
{
|
|
||||||
return _order.begin();
|
|
||||||
}
|
|
||||||
const_iterator end() const
|
|
||||||
{
|
|
||||||
return _order.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse_iterator rbegin()
|
|
||||||
{
|
|
||||||
return _order.rbegin();
|
|
||||||
}
|
|
||||||
reverse_iterator rend()
|
|
||||||
{
|
|
||||||
return _order.rend();
|
|
||||||
}
|
|
||||||
const_reverse_iterator rbegin() const
|
|
||||||
{
|
|
||||||
return _order.rbegin();
|
|
||||||
}
|
|
||||||
const_reverse_iterator rend() const
|
|
||||||
{
|
|
||||||
return _order.rend();
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& front()
|
|
||||||
{
|
|
||||||
return *_order.front();
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& back()
|
|
||||||
{
|
|
||||||
return *_order.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
const value_type& front() const
|
|
||||||
{
|
|
||||||
return *_order.front();
|
|
||||||
}
|
|
||||||
|
|
||||||
const value_type& back() const
|
|
||||||
{
|
|
||||||
return *_order.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<value_type>>& underlying() {
|
|
||||||
return _order;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename T2>
|
|
||||||
std::unique_ptr<T> erase_this(ptr_vec<T>& vec, T2* el)
|
|
||||||
{
|
|
||||||
return vec.erase(*el);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename T2>
|
|
||||||
std::unique_ptr<T> erase_this(ptr_vec<T>& vec, T2& el)
|
|
||||||
{
|
|
||||||
return vec.erase(el);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct non_null_ptr {
|
|
||||||
non_null_ptr() = delete;
|
|
||||||
constexpr non_null_ptr(T* ptr) : _ptr(ptr)
|
|
||||||
{
|
|
||||||
assert(ptr != nullptr);
|
|
||||||
}
|
|
||||||
non_null_ptr(std::nullptr_t) = delete;
|
|
||||||
|
|
||||||
constexpr non_null_ptr(const non_null_ptr&) = default;
|
|
||||||
constexpr non_null_ptr(non_null_ptr&&) = default;
|
|
||||||
constexpr non_null_ptr& operator=(const non_null_ptr&) = default;
|
|
||||||
constexpr non_null_ptr& operator=(non_null_ptr&&) = default;
|
|
||||||
|
|
||||||
constexpr T& operator*() const noexcept
|
|
||||||
{
|
|
||||||
return *_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr T* operator->() const noexcept
|
|
||||||
{
|
|
||||||
return _ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr operator T*() noexcept
|
|
||||||
{
|
|
||||||
return _ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr operator T* const() const noexcept
|
|
||||||
{
|
|
||||||
return _ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
T* _ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct ref_vec {
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
std::vector<value_type*> _order;
|
|
||||||
|
|
||||||
using iterator = double_iterator<typename decltype(_order)::iterator>;
|
|
||||||
using const_iterator = double_iterator<typename decltype(_order)::const_iterator>;
|
|
||||||
|
|
||||||
using reverse_iterator = double_iterator<typename decltype(_order)::reverse_iterator>;
|
|
||||||
using const_reverse_iterator =
|
|
||||||
double_iterator<typename decltype(_order)::const_reverse_iterator>;
|
|
||||||
|
|
||||||
ref_vec() = default;
|
|
||||||
|
|
||||||
ref_vec(std::initializer_list<value_type*> lst) : _order {lst} { };
|
|
||||||
|
|
||||||
template<typename InputIter, typename = std::enable_if_t<std::is_same_v<decltype(*std::declval<InputIter>()), value_type&>>>
|
|
||||||
ref_vec(InputIter iter1, InputIter iter2) {
|
|
||||||
_order.reserve(std::distance(iter1, iter2));
|
|
||||||
std::transform(iter1, iter2, std::back_inserter(_order), [] (auto& v) {return &v; });
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Range, typename = std::enable_if_t<std::is_same_v<decltype(*std::declval<Range>().begin()), value_type&>>>
|
|
||||||
ref_vec(Range&& rng) : ref_vec (std::begin(rng), std::end(rng)) { }
|
|
||||||
|
|
||||||
value_type& push_back(value_type& v)
|
|
||||||
{
|
|
||||||
_order.push_back(&v);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& push_back(non_null_ptr<value_type> ptr)
|
|
||||||
{
|
|
||||||
_order.push_back(ptr);
|
|
||||||
return *ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& emplace_back(value_type& v)
|
|
||||||
{
|
|
||||||
return push_back(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<value_type> erase(const value_type& v)
|
|
||||||
{
|
|
||||||
auto iter =
|
|
||||||
std::find_if(_order.begin(), _order.end(), [&v](auto&& ptr) { return ptr == &v; });
|
|
||||||
if (iter != _order.end()) {
|
|
||||||
auto uptr = std::move(*iter);
|
|
||||||
_order.erase(iter);
|
|
||||||
return uptr;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator rotate_to_back(const value_type& v)
|
|
||||||
{
|
|
||||||
auto iter =
|
|
||||||
std::find_if(_order.begin(), _order.end(), [&v](auto&& ptr) { return ptr == &v; });
|
|
||||||
return rotate_to_back(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator rotate_to_back(iterator iter)
|
|
||||||
{
|
|
||||||
if (iter != _order.end()) {
|
|
||||||
{
|
|
||||||
return std::rotate(iter.data(), iter.data() + 1, _order.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return end();
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator rotate_to_front(const value_type& v)
|
|
||||||
{
|
|
||||||
auto iter =
|
|
||||||
std::find_if(_order.begin(), _order.end(), [&v](auto&& ptr) { return ptr == &v; });
|
|
||||||
return rotate_to_front(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator rotate_to_front(iterator iter)
|
|
||||||
{
|
|
||||||
if (iter != _order.end()) {
|
|
||||||
{
|
|
||||||
return std::rotate(_order.begin(), iter.data(), iter.data() + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return end();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t size() const noexcept
|
|
||||||
{
|
|
||||||
return _order.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() const noexcept
|
|
||||||
{
|
|
||||||
return _order.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t capacity() const noexcept
|
|
||||||
{
|
|
||||||
return _order.capacity();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t max_size() const noexcept
|
|
||||||
{
|
|
||||||
return _order.max_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve(std::size_t new_cap)
|
|
||||||
{
|
|
||||||
_order.reserve(new_cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shrink_to_fit()
|
|
||||||
{
|
|
||||||
_order.shrink_to_fit();
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& operator[](std::size_t n)
|
|
||||||
{
|
|
||||||
return *_order[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
const value_type& operator[](std::size_t n) const
|
|
||||||
{
|
|
||||||
return *_order[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& at(std::size_t n)
|
|
||||||
{
|
|
||||||
return *_order.at(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
const value_type& at(std::size_t n) const
|
|
||||||
{
|
|
||||||
return *_order.at(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator begin()
|
|
||||||
{
|
|
||||||
return _order.begin();
|
|
||||||
}
|
|
||||||
iterator end()
|
|
||||||
{
|
|
||||||
return _order.end();
|
|
||||||
}
|
|
||||||
const_iterator begin() const
|
|
||||||
{
|
|
||||||
return _order.begin();
|
|
||||||
}
|
|
||||||
const_iterator end() const
|
|
||||||
{
|
|
||||||
return _order.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse_iterator rbegin()
|
|
||||||
{
|
|
||||||
return _order.rbegin();
|
|
||||||
}
|
|
||||||
reverse_iterator rend()
|
|
||||||
{
|
|
||||||
return _order.rend();
|
|
||||||
}
|
|
||||||
const_reverse_iterator rbegin() const
|
|
||||||
{
|
|
||||||
return _order.rbegin();
|
|
||||||
}
|
|
||||||
const_reverse_iterator rend() const
|
|
||||||
{
|
|
||||||
return _order.rend();
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& front()
|
|
||||||
{
|
|
||||||
return *_order.front();
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& back()
|
|
||||||
{
|
|
||||||
return *_order.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
const value_type& front() const
|
|
||||||
{
|
|
||||||
return *_order.front();
|
|
||||||
}
|
|
||||||
|
|
||||||
const value_type& back() const
|
|
||||||
{
|
|
||||||
return *_order.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<value_type*>& underlying() {
|
|
||||||
return _order;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace waybar::util
|
|
@ -1,6 +1,6 @@
|
|||||||
project(
|
project(
|
||||||
'waybar', 'cpp', 'c',
|
'waybar', 'cpp', 'c',
|
||||||
version: '0.0.1',
|
version: '0.0.3',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
default_options : ['cpp_std=c++17'],
|
default_options : ['cpp_std=c++17'],
|
||||||
)
|
)
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<protocol name="idle">
|
|
||||||
<copyright><![CDATA[
|
|
||||||
Copyright (C) 2015 Martin Gräßlin
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
the Free Software Foundation, either version 2.1 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
]]></copyright>
|
|
||||||
<interface name="org_kde_kwin_idle" version="1">
|
|
||||||
<description summary="User idle time manager">
|
|
||||||
This interface allows to monitor user idle time on a given seat. The interface
|
|
||||||
allows to register timers which trigger after no user activity was registered
|
|
||||||
on the seat for a given interval. It notifies when user activity resumes.
|
|
||||||
|
|
||||||
This is useful for applications wanting to perform actions when the user is not
|
|
||||||
interacting with the system, e.g. chat applications setting the user as away, power
|
|
||||||
management features to dim screen, etc..
|
|
||||||
</description>
|
|
||||||
<request name="get_idle_timeout">
|
|
||||||
<arg name="id" type="new_id" interface="org_kde_kwin_idle_timeout"/>
|
|
||||||
<arg name="seat" type="object" interface="wl_seat"/>
|
|
||||||
<arg name="timeout" type="uint" summary="The idle timeout in msec"/>
|
|
||||||
</request>
|
|
||||||
</interface>
|
|
||||||
<interface name="org_kde_kwin_idle_timeout" version="1">
|
|
||||||
<request name="release" type="destructor">
|
|
||||||
<description summary="release the timeout object"/>
|
|
||||||
</request>
|
|
||||||
<request name="simulate_user_activity">
|
|
||||||
<description summary="Simulates user activity for this timeout, behaves just like real user activity on the seat"/>
|
|
||||||
</request>
|
|
||||||
<event name="idle">
|
|
||||||
<description summary="Triggered when there has not been any user activity in the requested idle time interval"/>
|
|
||||||
</event>
|
|
||||||
<event name="resumed">
|
|
||||||
<description summary="Triggered on the first user activity after an idle event"/>
|
|
||||||
</event>
|
|
||||||
</interface>
|
|
||||||
</protocol>
|
|
@ -23,8 +23,8 @@ wayland_scanner_client = generator(
|
|||||||
|
|
||||||
client_protocols = [
|
client_protocols = [
|
||||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
||||||
|
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
||||||
['wlr-layer-shell-unstable-v1.xml'],
|
['wlr-layer-shell-unstable-v1.xml'],
|
||||||
['idle.xml'],
|
|
||||||
]
|
]
|
||||||
|
|
||||||
client_protos_src = []
|
client_protos_src = []
|
||||||
|
@ -1,6 +1,21 @@
|
|||||||
{
|
{
|
||||||
|
// "layer": "top", // Waybar at top layer
|
||||||
|
// "position": "bottom", // Waybar at the bottom of your screen
|
||||||
|
// "height": 30, // Waybar height
|
||||||
|
// "width": 1280, // Waybar width
|
||||||
|
// Choose the order of the modules
|
||||||
"modules-left": ["workspaces", "custom/spotify"],
|
"modules-left": ["workspaces", "custom/spotify"],
|
||||||
"modules-right": ["pulseaudio", "network", "cpu", "memory", "battery", "clock"],
|
"modules-right": ["pulseaudio", "network", "cpu", "memory", "battery", "clock"],
|
||||||
|
// Modules configuration
|
||||||
|
"workspaces": {
|
||||||
|
"format-icons": {
|
||||||
|
"1": "",
|
||||||
|
"2": "",
|
||||||
|
"3": "",
|
||||||
|
"4": "",
|
||||||
|
"5": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"cpu": {
|
"cpu": {
|
||||||
"format": "{}% "
|
"format": "{}% "
|
||||||
},
|
},
|
||||||
@ -8,15 +23,17 @@
|
|||||||
"format": "{}% "
|
"format": "{}% "
|
||||||
},
|
},
|
||||||
"battery": {
|
"battery": {
|
||||||
"format": "{}% "
|
"format": "{capacity}% {icon}",
|
||||||
|
"format-icons": ["", "", "", "", ""]
|
||||||
},
|
},
|
||||||
"network": {
|
"network": {
|
||||||
"interface": "wlp2s0",
|
"interface": "wlp2s0",
|
||||||
"format": "{essid} ({signalStrength}%) "
|
"format": "{essid} ({signalStrength}%) "
|
||||||
},
|
},
|
||||||
"pulseaudio": {
|
"pulseaudio": {
|
||||||
"format": "{}% ",
|
"format": "{volume}% {icon}",
|
||||||
"format-muted": ""
|
"format-muted": "",
|
||||||
|
"format-icons": ["", ""]
|
||||||
},
|
},
|
||||||
"custom/spotify": {
|
"custom/spotify": {
|
||||||
"format": " {}",
|
"format": " {}",
|
||||||
|
@ -11,61 +11,82 @@ window {
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspaces button {
|
#workspaces button {
|
||||||
padding: 0 5px;
|
padding: 0 8px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: white;
|
color: white;
|
||||||
border-bottom: 3px solid transparent;
|
border-bottom: 3px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspaces button.current {
|
#workspaces button label {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button.current {
|
||||||
background: #64727D;
|
background: #64727D;
|
||||||
border-bottom: 3px solid white;
|
border-bottom: 3px solid white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.clock, .battery, .cpu, .memory, .network, .pulseaudio, .custom-spotify {
|
#clock, #battery, #cpu, #memory, #network, #pulseaudio, #custom-spotify {
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.clock {
|
#clock {
|
||||||
background-color: #64727D;
|
background-color: #64727D;
|
||||||
}
|
}
|
||||||
|
|
||||||
.battery {
|
#battery {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.battery.charging {
|
#battery.charging {
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #26A65B;
|
background-color: #26A65B;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cpu {
|
@keyframes blink {
|
||||||
|
to {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#battery.warning {
|
||||||
|
background: #f53c3c;
|
||||||
|
color: white;
|
||||||
|
animation-name: blink;
|
||||||
|
animation-duration: 0.5s;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cpu {
|
||||||
background: #2ecc71;
|
background: #2ecc71;
|
||||||
color: #000000;
|
color: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.memory {
|
#memory {
|
||||||
background: #9b59b6;
|
background: #9b59b6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.network {
|
#network {
|
||||||
background: #2980b9;
|
background: #2980b9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pulseaudio {
|
#pulseaudio {
|
||||||
background: #f1c40f;
|
background: #f1c40f;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pulseaudio.muted {
|
#pulseaudio.muted {
|
||||||
background: #90b1b1;
|
background: #90b1b1;
|
||||||
color: #2a5c45;
|
color: #2a5c45;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-spotify {
|
#custom-spotify {
|
||||||
background: #66cc99;
|
background: #66cc99;
|
||||||
color: #2a5c45;
|
color: #2a5c45;
|
||||||
}
|
}
|
||||||
|
101
src/bar.cpp
101
src/bar.cpp
@ -1,42 +1,43 @@
|
|||||||
#include <condition_variable>
|
|
||||||
#include <gdk/gdkwayland.h>
|
|
||||||
#include <thread>
|
|
||||||
#include <fstream>
|
|
||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
#include "factory.hpp"
|
#include "factory.hpp"
|
||||||
#include "util/chrono.hpp"
|
#include "util/json.hpp"
|
||||||
|
|
||||||
waybar::Bar::Bar(Client &client, std::unique_ptr<struct wl_output *> &&p_output)
|
waybar::Bar::Bar(Client &client, std::unique_ptr<struct wl_output *> &&p_output)
|
||||||
: client(client), window{Gtk::WindowType::WINDOW_TOPLEVEL},
|
: client(client), window{Gtk::WindowType::WINDOW_TOPLEVEL},
|
||||||
output(std::move(p_output))
|
output(std::move(p_output))
|
||||||
{
|
{
|
||||||
static const struct wl_output_listener outputListener = {
|
static const struct zxdg_output_v1_listener xdgOutputListener = {
|
||||||
.geometry = _handleGeometry,
|
.logical_position = _handleLogicalPosition,
|
||||||
.mode = _handleMode,
|
.logical_size = _handleLogicalSize,
|
||||||
.done = _handleDone,
|
.done = _handleDone,
|
||||||
.scale = _handleScale,
|
.name = _handleName,
|
||||||
|
.description = _handleDescription,
|
||||||
};
|
};
|
||||||
|
_xdgOutput =
|
||||||
wl_output_add_listener(*output, &outputListener, this);
|
zxdg_output_manager_v1_get_xdg_output(client.xdg_output_manager, *output);
|
||||||
|
zxdg_output_v1_add_listener(_xdgOutput, &xdgOutputListener, this);
|
||||||
window.set_title("waybar");
|
window.set_title("waybar");
|
||||||
window.set_decorated(false);
|
window.set_decorated(false);
|
||||||
_setupConfig();
|
_setupConfig();
|
||||||
_setupCss();
|
_setupCss();
|
||||||
_setupWidgets();
|
_setupWidgets();
|
||||||
bool positionBottom = (_config["position"] == "bottom");
|
if (_config["height"])
|
||||||
|
_height = _config["height"].asUInt();
|
||||||
|
bool positionBottom = _config["position"] == "bottom";
|
||||||
|
bool layerTop = _config["layer"] == "top";
|
||||||
gtk_widget_realize(GTK_WIDGET(window.gobj()));
|
gtk_widget_realize(GTK_WIDGET(window.gobj()));
|
||||||
GdkWindow *gdkWindow = gtk_widget_get_window(GTK_WIDGET(window.gobj()));
|
GdkWindow *gdkWindow = gtk_widget_get_window(GTK_WIDGET(window.gobj()));
|
||||||
gdk_wayland_window_set_use_custom_surface(gdkWindow);
|
gdk_wayland_window_set_use_custom_surface(gdkWindow);
|
||||||
surface = gdk_wayland_window_get_wl_surface(gdkWindow);
|
surface = gdk_wayland_window_get_wl_surface(gdkWindow);
|
||||||
layerSurface = zwlr_layer_shell_v1_get_layer_surface(
|
layerSurface = zwlr_layer_shell_v1_get_layer_surface(
|
||||||
client.layer_shell, surface, *output,
|
client.layer_shell, surface, *output,
|
||||||
(positionBottom ? ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM : ZWLR_LAYER_SHELL_V1_LAYER_TOP),
|
(layerTop ? ZWLR_LAYER_SHELL_V1_LAYER_TOP : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM),
|
||||||
"waybar");
|
"waybar");
|
||||||
zwlr_layer_surface_v1_set_anchor(layerSurface,
|
zwlr_layer_surface_v1_set_anchor(layerSurface,
|
||||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
||||||
(positionBottom ? ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM : ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP));
|
(positionBottom ? ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM : ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP));
|
||||||
zwlr_layer_surface_v1_set_size(layerSurface, _width, client.height);
|
zwlr_layer_surface_v1_set_size(layerSurface, _width, _height);
|
||||||
static const struct zwlr_layer_surface_v1_listener layerSurfaceListener = {
|
static const struct zwlr_layer_surface_v1_listener layerSurfaceListener = {
|
||||||
.configure = _layerSurfaceHandleConfigure,
|
.configure = _layerSurfaceHandleConfigure,
|
||||||
.closed = _layerSurfaceHandleClosed,
|
.closed = _layerSurfaceHandleClosed,
|
||||||
@ -46,27 +47,32 @@ waybar::Bar::Bar(Client &client, std::unique_ptr<struct wl_output *> &&p_output)
|
|||||||
wl_surface_commit(surface);
|
wl_surface_commit(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::Bar::_handleGeometry(void *data, struct wl_output *wl_output,
|
void waybar::Bar::_handleLogicalPosition(void *data,
|
||||||
int32_t x, int32_t y, int32_t physical_width, int32_t physical_height,
|
struct zxdg_output_v1 *zxdg_output_v1, int32_t x, int32_t y)
|
||||||
int32_t subpixel, const char *make, const char *model, int32_t transform)
|
|
||||||
{
|
{
|
||||||
// Nothing here
|
// Nothing here
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::Bar::_handleMode(void *data, struct wl_output *wl_output,
|
void waybar::Bar::_handleLogicalSize(void *data,
|
||||||
uint32_t f, int32_t w, int32_t h, int32_t refresh)
|
struct zxdg_output_v1 *zxdg_output_v1, int32_t width, int32_t height)
|
||||||
|
{
|
||||||
|
// Nothing here
|
||||||
|
}
|
||||||
|
|
||||||
|
void waybar::Bar::_handleDone(void *data, struct zxdg_output_v1 *zxdg_output_v1)
|
||||||
|
{
|
||||||
|
// Nothing here
|
||||||
|
}
|
||||||
|
|
||||||
|
void waybar::Bar::_handleName(void *data, struct zxdg_output_v1 *xdg_output,
|
||||||
|
const char *name)
|
||||||
{
|
{
|
||||||
auto o = reinterpret_cast<waybar::Bar *>(data);
|
auto o = reinterpret_cast<waybar::Bar *>(data);
|
||||||
o->setWidth(w);
|
o->outputName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::Bar::_handleDone(void *data, struct wl_output *)
|
void waybar::Bar::_handleDescription(void *data,
|
||||||
{
|
struct zxdg_output_v1 *zxdg_output_v1, const char *description)
|
||||||
// Nothing here
|
|
||||||
}
|
|
||||||
|
|
||||||
void waybar::Bar::_handleScale(void *data, struct wl_output *wl_output,
|
|
||||||
int32_t factor)
|
|
||||||
{
|
{
|
||||||
// Nothing here
|
// Nothing here
|
||||||
}
|
}
|
||||||
@ -77,12 +83,12 @@ void waybar::Bar::_layerSurfaceHandleConfigure(
|
|||||||
{
|
{
|
||||||
auto o = reinterpret_cast<waybar::Bar *>(data);
|
auto o = reinterpret_cast<waybar::Bar *>(data);
|
||||||
o->window.show_all();
|
o->window.show_all();
|
||||||
|
o->setWidth(o->_config["width"] ? o->_config["width"].asUInt() : width);
|
||||||
zwlr_layer_surface_v1_ack_configure(surface, serial);
|
zwlr_layer_surface_v1_ack_configure(surface, serial);
|
||||||
if (o->client.height != height)
|
if (o->_height != height) {
|
||||||
{
|
height = o->_height;
|
||||||
height = o->client.height;
|
|
||||||
std::cout << fmt::format("New Height: {}", height) << std::endl;
|
std::cout << fmt::format("New Height: {}", height) << std::endl;
|
||||||
zwlr_layer_surface_v1_set_size(surface, width, height);
|
zwlr_layer_surface_v1_set_size(surface, o->_width, height);
|
||||||
zwlr_layer_surface_v1_set_exclusive_zone(surface, o->visible ? height : 0);
|
zwlr_layer_surface_v1_set_exclusive_zone(surface, o->visible ? height : 0);
|
||||||
wl_surface_commit(o->surface);
|
wl_surface_commit(o->surface);
|
||||||
}
|
}
|
||||||
@ -99,40 +105,34 @@ void waybar::Bar::_layerSurfaceHandleClosed(void *data,
|
|||||||
o->window.close();
|
o->window.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::Bar::setWidth(int width) -> void
|
auto waybar::Bar::setWidth(uint32_t width) -> void
|
||||||
{
|
{
|
||||||
if (width == this->_width) return;
|
if (width == this->_width) return;
|
||||||
std::cout << fmt::format("Bar width configured: {}", width) << std::endl;
|
std::cout << fmt::format("Bar width configured: {}", width) << std::endl;
|
||||||
this->_width = width;
|
this->_width = width;
|
||||||
window.set_size_request(width);
|
window.set_size_request(width);
|
||||||
window.resize(width, client.height);
|
window.resize(width, _height);
|
||||||
zwlr_layer_surface_v1_set_size(layerSurface, width, 40);
|
zwlr_layer_surface_v1_set_size(layerSurface, width, _height + 1);
|
||||||
wl_surface_commit(surface);
|
wl_surface_commit(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::Bar::toggle() -> void
|
auto waybar::Bar::toggle() -> void
|
||||||
{
|
{
|
||||||
visible = !visible;
|
visible = !visible;
|
||||||
auto zone = visible ? client.height : 0;
|
auto zone = visible ? _height : 0;
|
||||||
zwlr_layer_surface_v1_set_exclusive_zone(layerSurface, zone);
|
zwlr_layer_surface_v1_set_exclusive_zone(layerSurface, zone);
|
||||||
wl_surface_commit(surface);
|
wl_surface_commit(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::Bar::_setupConfig() -> void
|
auto waybar::Bar::_setupConfig() -> void
|
||||||
{
|
{
|
||||||
Json::Value root;
|
util::JsonParser parser;
|
||||||
Json::CharReaderBuilder builder;
|
|
||||||
Json::CharReader* reader = builder.newCharReader();
|
|
||||||
std::string err;
|
|
||||||
std::ifstream file(client.configFile);
|
std::ifstream file(client.configFile);
|
||||||
if (!file.is_open())
|
if (!file.is_open())
|
||||||
throw std::runtime_error("Can't open config file");
|
throw std::runtime_error("Can't open config file");
|
||||||
std::string str((std::istreambuf_iterator<char>(file)),
|
std::string str((std::istreambuf_iterator<char>(file)),
|
||||||
std::istreambuf_iterator<char>());
|
std::istreambuf_iterator<char>());
|
||||||
bool res = reader->parse(str.c_str(), str.c_str() + str.size(), &_config, &err);
|
_config = parser.parse(str);
|
||||||
delete reader;
|
|
||||||
if (!res)
|
|
||||||
throw std::runtime_error(err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::Bar::_setupCss() -> void
|
auto waybar::Bar::_setupCss() -> void
|
||||||
@ -165,21 +165,24 @@ auto waybar::Bar::_setupWidgets() -> void
|
|||||||
|
|
||||||
if (_config["modules-left"]) {
|
if (_config["modules-left"]) {
|
||||||
for (auto name : _config["modules-left"]) {
|
for (auto name : _config["modules-left"]) {
|
||||||
auto &module = factory.makeModule(name.asString());
|
auto module = factory.makeModule(name.asString());
|
||||||
left.pack_start(module, false, true, 0);
|
if (module)
|
||||||
|
left.pack_start(*module, false, true, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_config["modules-center"]) {
|
if (_config["modules-center"]) {
|
||||||
for (auto name : _config["modules-center"]) {
|
for (auto name : _config["modules-center"]) {
|
||||||
auto &module = factory.makeModule(name.asString());
|
auto module = factory.makeModule(name.asString());
|
||||||
center.pack_start(module, true, false, 10);
|
if (module)
|
||||||
|
center.pack_start(*module, true, false, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_config["modules-right"]) {
|
if (_config["modules-right"]) {
|
||||||
std::reverse(_config["modules-right"].begin(), _config["modules-right"].end());
|
std::reverse(_config["modules-right"].begin(), _config["modules-right"].end());
|
||||||
for (auto name : _config["modules-right"]) {
|
for (auto name : _config["modules-right"]) {
|
||||||
auto &module = factory.makeModule(name.asString());
|
auto module = factory.makeModule(name.asString());
|
||||||
right.pack_end(module, false, false, 0);
|
if (module)
|
||||||
|
right.pack_end(*module, false, false, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,16 +46,25 @@ void waybar::Client::_handle_global(void *data, struct wl_registry *registry,
|
|||||||
o->layer_shell = (zwlr_layer_shell_v1 *)wl_registry_bind(registry, name,
|
o->layer_shell = (zwlr_layer_shell_v1 *)wl_registry_bind(registry, name,
|
||||||
&zwlr_layer_shell_v1_interface, version);
|
&zwlr_layer_shell_v1_interface, version);
|
||||||
} else if (!strcmp(interface, wl_output_interface.name)) {
|
} else if (!strcmp(interface, wl_output_interface.name)) {
|
||||||
auto output = std::make_unique<struct wl_output *>();
|
o->wlOutput = (struct wl_output *)wl_registry_bind(registry, name,
|
||||||
*output = (struct wl_output *)wl_registry_bind(registry, name,
|
|
||||||
&wl_output_interface, version);
|
&wl_output_interface, version);
|
||||||
o->bars.emplace_back(*o, std::move(output));
|
auto output = std::make_unique<struct wl_output *>();
|
||||||
} else if (!strcmp(interface, org_kde_kwin_idle_interface.name)) {
|
*output = o->wlOutput;
|
||||||
o->idle_manager = (org_kde_kwin_idle *)wl_registry_bind(registry, name,
|
if (o->xdg_output_manager)
|
||||||
&org_kde_kwin_idle_interface, version);
|
o->bars.emplace_back(std::make_unique<Bar>(*o, std::move(output)));
|
||||||
} else if (!strcmp(interface, wl_seat_interface.name)) {
|
} else if (!strcmp(interface, wl_seat_interface.name)) {
|
||||||
o->seat = (struct wl_seat *)wl_registry_bind(registry, name,
|
o->seat = (struct wl_seat *)wl_registry_bind(registry, name,
|
||||||
&wl_seat_interface, version);
|
&wl_seat_interface, version);
|
||||||
|
} else if (!strcmp(interface, zxdg_output_manager_v1_interface.name)
|
||||||
|
&& version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
|
||||||
|
o->xdg_output_manager =
|
||||||
|
(struct zxdg_output_manager_v1 *)wl_registry_bind(registry, name,
|
||||||
|
&zxdg_output_manager_v1_interface, ZXDG_OUTPUT_V1_NAME_SINCE_VERSION);
|
||||||
|
if (o->wlOutput) {
|
||||||
|
auto output = std::make_unique<struct wl_output *>();
|
||||||
|
*output = o->wlOutput;
|
||||||
|
o->bars.emplace_back(std::make_unique<Bar>(*o, std::move(output)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,23 +4,32 @@ waybar::Factory::Factory(Bar &bar, Json::Value config)
|
|||||||
: _bar(bar), _config(config)
|
: _bar(bar), _config(config)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
waybar::IModule &waybar::Factory::makeModule(std::string name)
|
waybar::IModule *waybar::Factory::makeModule(std::string name)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
if (name == "battery")
|
if (name == "battery")
|
||||||
return *new waybar::modules::Battery(_config[name]);
|
return new waybar::modules::Battery(_config[name]);
|
||||||
if (name == "workspaces")
|
if (name == "workspaces")
|
||||||
return *new waybar::modules::Workspaces(_bar);
|
return new waybar::modules::Workspaces(_bar, _config[name]);
|
||||||
if (name == "memory")
|
if (name == "memory")
|
||||||
return *new waybar::modules::Memory(_config[name]);
|
return new waybar::modules::Memory(_config[name]);
|
||||||
if (name == "cpu")
|
if (name == "cpu")
|
||||||
return *new waybar::modules::Cpu(_config[name]);
|
return new waybar::modules::Cpu(_config[name]);
|
||||||
if (name == "clock")
|
if (name == "clock")
|
||||||
return *new waybar::modules::Clock(_config[name]);
|
return new waybar::modules::Clock(_config[name]);
|
||||||
if (name == "network")
|
if (name == "network")
|
||||||
return *new waybar::modules::Network(_config[name]);
|
return new waybar::modules::Network(_config[name]);
|
||||||
if (name == "pulseaudio")
|
if (name == "pulseaudio")
|
||||||
return *new waybar::modules::Pulseaudio(_config[name]);
|
return new waybar::modules::Pulseaudio(_config[name]);
|
||||||
if (!name.compare(0, 7, "custom/") && name.size() > 7)
|
if (!name.compare(0, 7, "custom/") && name.size() > 7)
|
||||||
return *new waybar::modules::Custom(name.substr(7), _config[name]);
|
return new waybar::modules::Custom(name.substr(7), _config[name]);
|
||||||
throw std::runtime_error("Unknown module: " + name);
|
std::cerr << "Unknown module: " + name << std::endl;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
auto err = fmt::format("Disabling module \"{}\", {}", name, e.what());
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
} catch (...) {
|
||||||
|
auto err = fmt::format("Disabling module \"{}\", Unknown reason", name);
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -48,10 +48,11 @@ int ipc_open_socket(std::string socket_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ipc_response ipc_recv_response(int socketfd) {
|
struct ipc_response ipc_recv_response(int socketfd) {
|
||||||
|
struct ipc_response response;
|
||||||
char data[ipc_header_size];
|
char data[ipc_header_size];
|
||||||
uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic));
|
uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic));
|
||||||
|
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
|
|
||||||
while (total < ipc_header_size) {
|
while (total < ipc_header_size) {
|
||||||
ssize_t received = recv(socketfd, data + total, ipc_header_size - total, 0);
|
ssize_t received = recv(socketfd, data + total, ipc_header_size - total, 0);
|
||||||
if (received <= 0) {
|
if (received <= 0) {
|
||||||
@ -60,8 +61,6 @@ struct ipc_response ipc_recv_response(int socketfd) {
|
|||||||
total += received;
|
total += received;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ipc_response response;
|
|
||||||
|
|
||||||
total = 0;
|
total = 0;
|
||||||
response.size = data32[0];
|
response.size = data32[0];
|
||||||
response.type = data32[1];
|
response.type = data32[1];
|
||||||
@ -86,16 +85,11 @@ std::string ipc_single_command(int socketfd, uint32_t type, const char *payload,
|
|||||||
data32[0] = *len;
|
data32[0] = *len;
|
||||||
data32[1] = type;
|
data32[1] = type;
|
||||||
|
|
||||||
if (send(socketfd, data, ipc_header_size, 0) == -1) {
|
if (send(socketfd, data, ipc_header_size, 0) == -1)
|
||||||
throw std::runtime_error("Unable to send IPC header");
|
throw std::runtime_error("Unable to send IPC header");
|
||||||
}
|
if (send(socketfd, payload, *len, 0) == -1)
|
||||||
|
|
||||||
if (send(socketfd, payload, *len, 0) == -1) {
|
|
||||||
throw std::runtime_error("Unable to send IPC payload");
|
throw std::runtime_error("Unable to send IPC payload");
|
||||||
}
|
|
||||||
|
|
||||||
struct ipc_response resp = ipc_recv_response(socketfd);
|
struct ipc_response resp = ipc_recv_response(socketfd);
|
||||||
std::string response = resp.payload;
|
|
||||||
*len = resp.size;
|
*len = resp.size;
|
||||||
return response;
|
return resp.payload;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
#include <gtkmm.h>
|
|
||||||
#include <wayland-client.hpp>
|
|
||||||
#include <gdk/gdkwayland.h>
|
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
#include <iostream>
|
||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
@ -15,7 +13,7 @@ int main(int argc, char* argv[])
|
|||||||
waybar::client = &c;
|
waybar::client = &c;
|
||||||
std::signal(SIGUSR1, [] (int signal) {
|
std::signal(SIGUSR1, [] (int signal) {
|
||||||
for (auto& bar : waybar::client->bars) {
|
for (auto& bar : waybar::client->bars) {
|
||||||
bar.toggle();
|
bar.get()->toggle();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,50 +6,75 @@ waybar::modules::Battery::Battery(Json::Value config)
|
|||||||
try {
|
try {
|
||||||
for (auto &node : fs::directory_iterator(_data_dir)) {
|
for (auto &node : fs::directory_iterator(_data_dir)) {
|
||||||
if (fs::is_directory(node) && fs::exists(node / "capacity")
|
if (fs::is_directory(node) && fs::exists(node / "capacity")
|
||||||
&& fs::exists(node / "status")) {
|
&& fs::exists(node / "status") && fs::exists(node / "uevent"))
|
||||||
_batteries.push_back(node);
|
_batteries.push_back(node);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (fs::filesystem_error &e) {
|
} catch (fs::filesystem_error &e) {
|
||||||
std::cerr << e.what() << std::endl;
|
throw std::runtime_error(e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
_label.get_style_context()->add_class("battery");
|
if (!_batteries.size())
|
||||||
|
throw std::runtime_error("No batteries.");
|
||||||
|
|
||||||
_thread = [this] {
|
auto fd = inotify_init();
|
||||||
|
if (fd == -1)
|
||||||
|
throw std::runtime_error("Unable to listen batteries.");
|
||||||
|
for (auto &bat : _batteries)
|
||||||
|
inotify_add_watch(fd, (bat / "uevent").c_str(), IN_ACCESS);
|
||||||
|
// Trigger first value
|
||||||
update();
|
update();
|
||||||
_thread.sleep_for(chrono::minutes(1));
|
_label.set_name("battery");
|
||||||
|
_thread = [this, fd] {
|
||||||
|
struct inotify_event event;
|
||||||
|
int nbytes = read(fd, &event, sizeof(event));
|
||||||
|
if (nbytes != sizeof(event))
|
||||||
|
return;
|
||||||
|
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Battery::update));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::modules::Battery::update() -> void
|
auto waybar::modules::Battery::update() -> void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
int total = 0;
|
uint16_t total = 0;
|
||||||
bool charging = false;
|
bool charging = false;
|
||||||
for (auto &bat : _batteries) {
|
|
||||||
int capacity;
|
|
||||||
std::string status;
|
std::string status;
|
||||||
|
for (auto &bat : _batteries) {
|
||||||
|
uint16_t capacity;
|
||||||
std::ifstream(bat / "capacity") >> capacity;
|
std::ifstream(bat / "capacity") >> capacity;
|
||||||
total += capacity;
|
|
||||||
std::ifstream(bat / "status") >> status;
|
std::ifstream(bat / "status") >> status;
|
||||||
if (status == "Charging") {
|
if (status == "Charging")
|
||||||
charging = true;
|
charging = true;
|
||||||
|
total += capacity;
|
||||||
}
|
}
|
||||||
}
|
uint16_t capacity = total / _batteries.size();
|
||||||
if (charging == true) {
|
auto format = _config["format"]
|
||||||
|
? _config["format"].asString() : "{capacity}%";
|
||||||
|
_label.set_text(fmt::format(format, fmt::arg("capacity", capacity),
|
||||||
|
fmt::arg("icon", _getIcon(capacity))));
|
||||||
|
_label.set_tooltip_text(status);
|
||||||
|
if (charging)
|
||||||
_label.get_style_context()->add_class("charging");
|
_label.get_style_context()->add_class("charging");
|
||||||
} else {
|
else
|
||||||
_label.get_style_context()->remove_class("charging");
|
_label.get_style_context()->remove_class("charging");
|
||||||
}
|
auto critical = _config["critical"] ? _config["critical"].asUInt() : 15;
|
||||||
auto format = _config["format"] ? _config["format"].asString() : "{}%";
|
if (capacity <= critical && !charging)
|
||||||
_label.set_text(fmt::format(format, total / _batteries.size()));
|
_label.get_style_context()->add_class("warning");
|
||||||
_label.set_tooltip_text(charging ? "Charging" : "Discharging");
|
else
|
||||||
} catch (std::exception &e) {
|
_label.get_style_context()->remove_class("warning");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
std::cerr << e.what() << std::endl;
|
std::cerr << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string waybar::modules::Battery::_getIcon(uint16_t percentage)
|
||||||
|
{
|
||||||
|
if (!_config["format-icons"] || !_config["format-icons"].isArray()) return "";
|
||||||
|
auto size = _config["format-icons"].size();
|
||||||
|
auto idx = std::clamp(percentage / (100 / size), 0U, size - 1);
|
||||||
|
return _config["format-icons"][idx].asString();
|
||||||
|
}
|
||||||
|
|
||||||
waybar::modules::Battery::operator Gtk::Widget &()
|
waybar::modules::Battery::operator Gtk::Widget &()
|
||||||
{
|
{
|
||||||
return _label;
|
return _label;
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
waybar::modules::Clock::Clock(Json::Value config)
|
waybar::modules::Clock::Clock(Json::Value config)
|
||||||
: _config(config)
|
: _config(config)
|
||||||
{
|
{
|
||||||
_label.get_style_context()->add_class("clock");
|
_label.set_name("clock");
|
||||||
_thread = [this] {
|
_thread = [this] {
|
||||||
update();
|
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Clock::update));
|
||||||
auto now = waybar::chrono::clock::now();
|
auto now = waybar::chrono::clock::now();
|
||||||
auto timeout =
|
auto timeout =
|
||||||
std::chrono::floor<std::chrono::minutes>(now + std::chrono::minutes(1));
|
std::chrono::floor<std::chrono::minutes>(now + std::chrono::minutes(1));
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
waybar::modules::Cpu::Cpu(Json::Value config)
|
waybar::modules::Cpu::Cpu(Json::Value config)
|
||||||
: _config(config)
|
: _config(config)
|
||||||
{
|
{
|
||||||
_label.get_style_context()->add_class("cpu");
|
_label.set_name("cpu");
|
||||||
_thread = [this] {
|
|
||||||
update();
|
|
||||||
int interval = _config["interval"] ? _config["inveral"].asInt() : 10;
|
int interval = _config["interval"] ? _config["inveral"].asInt() : 10;
|
||||||
|
_thread = [this, interval] {
|
||||||
|
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Cpu::update));
|
||||||
_thread.sleep_for(chrono::seconds(interval));
|
_thread.sleep_for(chrono::seconds(interval));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -4,14 +4,11 @@
|
|||||||
waybar::modules::Custom::Custom(std::string name, Json::Value config)
|
waybar::modules::Custom::Custom(std::string name, Json::Value config)
|
||||||
: _name(name), _config(config)
|
: _name(name), _config(config)
|
||||||
{
|
{
|
||||||
_label.get_style_context()->add_class("custom-" + name);
|
if (!_config["exec"])
|
||||||
if (!_config["exec"]) {
|
throw std::runtime_error(name + " has no exec path.");
|
||||||
std::cerr << name + " has no exec path." << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_thread = [this] {
|
|
||||||
update();
|
|
||||||
int interval = _config["interval"] ? _config["inveral"].asInt() : 30;
|
int interval = _config["interval"] ? _config["inveral"].asInt() : 30;
|
||||||
|
_thread = [this, interval] {
|
||||||
|
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Custom::update));
|
||||||
_thread.sleep_for(chrono::seconds(interval));
|
_thread.sleep_for(chrono::seconds(interval));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -36,9 +33,11 @@ auto waybar::modules::Custom::update() -> void
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hide label if output is empty
|
// Hide label if output is empty
|
||||||
if (output.empty())
|
if (output.empty()) {
|
||||||
|
_label.set_name("");
|
||||||
_label.hide();
|
_label.hide();
|
||||||
else {
|
} else {
|
||||||
|
_label.set_name("custom-" + _name);
|
||||||
auto format = _config["format"] ? _config["format"].asString() : "{}";
|
auto format = _config["format"] ? _config["format"].asString() : "{}";
|
||||||
_label.set_text(fmt::format(format, output));
|
_label.set_text(fmt::format(format, output));
|
||||||
_label.show();
|
_label.show();
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
waybar::modules::Memory::Memory(Json::Value config)
|
waybar::modules::Memory::Memory(Json::Value config)
|
||||||
: _config(config)
|
: _config(config)
|
||||||
{
|
{
|
||||||
_label.get_style_context()->add_class("memory");
|
_label.set_name("memory");
|
||||||
_thread = [this] {
|
|
||||||
update();
|
|
||||||
int interval = _config["interval"] ? _config["inveral"].asInt() : 30;
|
int interval = _config["interval"] ? _config["inveral"].asInt() : 30;
|
||||||
|
_thread = [this, interval] {
|
||||||
|
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Memory::update));
|
||||||
_thread.sleep_for(chrono::seconds(interval));
|
_thread.sleep_for(chrono::seconds(interval));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
#include "modules/network.hpp"
|
#include "modules/network.hpp"
|
||||||
|
|
||||||
waybar::modules::Network::Network(Json::Value config)
|
waybar::modules::Network::Network(Json::Value config)
|
||||||
: _config(config), _ifid(if_nametoindex(config["interface"].asString().c_str()))
|
: _config(config), _ifid(if_nametoindex(config["interface"].asCString()))
|
||||||
{
|
{
|
||||||
_label.get_style_context()->add_class("network");
|
if (_ifid == 0)
|
||||||
_thread = [this] {
|
throw std::runtime_error("Can't found network interface");
|
||||||
update();
|
_label.set_name("network");
|
||||||
|
int interval = _config["interval"] ? _config["inveral"].asInt() : 30;
|
||||||
|
_thread = [this, interval] {
|
||||||
|
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Network::update));
|
||||||
_thread.sleep_for(chrono::minutes(1));
|
_thread.sleep_for(chrono::minutes(1));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -13,7 +16,7 @@ waybar::modules::Network::Network(Json::Value config)
|
|||||||
auto waybar::modules::Network::update() -> void
|
auto waybar::modules::Network::update() -> void
|
||||||
{
|
{
|
||||||
_getInfo();
|
_getInfo();
|
||||||
auto format = _config["format"] ? _config["format"].asString() : "{}";
|
auto format = _config["format"] ? _config["format"].asString() : "{essid}";
|
||||||
_label.set_text(fmt::format(format,
|
_label.set_text(fmt::format(format,
|
||||||
fmt::arg("essid", _essid),
|
fmt::arg("essid", _essid),
|
||||||
fmt::arg("signaldBm", _signalStrengthdBm),
|
fmt::arg("signaldBm", _signalStrengthdBm),
|
||||||
@ -102,8 +105,6 @@ bool waybar::modules::Network::_associatedOrJoined(struct nlattr** bss)
|
|||||||
|
|
||||||
auto waybar::modules::Network::_getInfo() -> void
|
auto waybar::modules::Network::_getInfo() -> void
|
||||||
{
|
{
|
||||||
if (_ifid == 0)
|
|
||||||
return;
|
|
||||||
struct nl_sock *sk = nl_socket_alloc();
|
struct nl_sock *sk = nl_socket_alloc();
|
||||||
if (genl_connect(sk) != 0) {
|
if (genl_connect(sk) != 0) {
|
||||||
nl_socket_free(sk);
|
nl_socket_free(sk);
|
||||||
|
@ -4,14 +4,12 @@ waybar::modules::Pulseaudio::Pulseaudio(Json::Value config)
|
|||||||
: _config(config), _mainloop(nullptr), _mainloop_api(nullptr),
|
: _config(config), _mainloop(nullptr), _mainloop_api(nullptr),
|
||||||
_context(nullptr), _sinkIdx(0), _volume(0), _muted(false)
|
_context(nullptr), _sinkIdx(0), _volume(0), _muted(false)
|
||||||
{
|
{
|
||||||
_label.get_style_context()->add_class("pulseaudio");
|
_label.set_name("pulseaudio");
|
||||||
_mainloop = pa_threaded_mainloop_new();
|
_mainloop = pa_threaded_mainloop_new();
|
||||||
if (!_mainloop)
|
if (!_mainloop)
|
||||||
throw std::runtime_error("pa_mainloop_new() failed.");
|
throw std::runtime_error("pa_mainloop_new() failed.");
|
||||||
pa_threaded_mainloop_lock(_mainloop);
|
pa_threaded_mainloop_lock(_mainloop);
|
||||||
_mainloop_api = pa_threaded_mainloop_get_api(_mainloop);
|
_mainloop_api = pa_threaded_mainloop_get_api(_mainloop);
|
||||||
if (pa_signal_init(_mainloop_api) != 0)
|
|
||||||
throw std::runtime_error("pa_signal_init() failed.");
|
|
||||||
_context = pa_context_new(_mainloop_api, "waybar");
|
_context = pa_context_new(_mainloop_api, "waybar");
|
||||||
if (!_context)
|
if (!_context)
|
||||||
throw std::runtime_error("pa_context_new() failed.");
|
throw std::runtime_error("pa_context_new() failed.");
|
||||||
@ -82,7 +80,7 @@ void waybar::modules::Pulseaudio::_sinkInfoCb(pa_context *context,
|
|||||||
pa->_volume = volume * 100.0f;
|
pa->_volume = volume * 100.0f;
|
||||||
pa->_muted = i->mute;
|
pa->_muted = i->mute;
|
||||||
pa->_desc = i->description;
|
pa->_desc = i->description;
|
||||||
pa->update();
|
Glib::signal_idle().connect_once(sigc::mem_fun(*pa, &Pulseaudio::update));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,18 +97,27 @@ void waybar::modules::Pulseaudio::_serverInfoCb(pa_context *context,
|
|||||||
|
|
||||||
auto waybar::modules::Pulseaudio::update() -> void
|
auto waybar::modules::Pulseaudio::update() -> void
|
||||||
{
|
{
|
||||||
auto format = _config["format"] ? _config["format"].asString() : "{}%";
|
auto format = _config["format"] ? _config["format"].asString() : "{volume}%";
|
||||||
if (_muted) {
|
if (_muted) {
|
||||||
format =
|
format =
|
||||||
_config["format-muted"] ? _config["format-muted"].asString() : format;
|
_config["format-muted"] ? _config["format-muted"].asString() : format;
|
||||||
if (!_label.get_style_context()->has_class("muted"))
|
|
||||||
_label.get_style_context()->add_class("muted");
|
_label.get_style_context()->add_class("muted");
|
||||||
} else if (_label.get_style_context()->has_class("muted"))
|
} else
|
||||||
_label.get_style_context()->remove_class("muted");
|
_label.get_style_context()->remove_class("muted");
|
||||||
_label.set_label(fmt::format(format, _volume));
|
_label.set_label(fmt::format(format,
|
||||||
|
fmt::arg("volume", _volume),
|
||||||
|
fmt::arg("icon", _getIcon(_volume))));
|
||||||
_label.set_tooltip_text(_desc);
|
_label.set_tooltip_text(_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string waybar::modules::Pulseaudio::_getIcon(uint16_t percentage)
|
||||||
|
{
|
||||||
|
if (!_config["format-icons"] || !_config["format-icons"].isArray()) return "";
|
||||||
|
auto size = _config["format-icons"].size();
|
||||||
|
auto idx = std::clamp(percentage / (100 / size), 0U, size - 1);
|
||||||
|
return _config["format-icons"][idx].asString();
|
||||||
|
}
|
||||||
|
|
||||||
waybar::modules::Pulseaudio::operator Gtk::Widget &() {
|
waybar::modules::Pulseaudio::operator Gtk::Widget &() {
|
||||||
return _label;
|
return _label;
|
||||||
}
|
}
|
||||||
|
@ -1,121 +1,184 @@
|
|||||||
#include "modules/workspaces.hpp"
|
#include "modules/workspaces.hpp"
|
||||||
#include "ipc/client.hpp"
|
#include "ipc/client.hpp"
|
||||||
|
|
||||||
waybar::modules::Workspaces::Workspaces(Bar &bar)
|
waybar::modules::Workspaces::Workspaces(Bar &bar, Json::Value config)
|
||||||
: _bar(bar), _thread(nullptr), _box(Gtk::manage(new Gtk::Box))
|
: _bar(bar), _config(config), _scrolling(false)
|
||||||
{
|
{
|
||||||
_box->get_style_context()->add_class("workspaces");
|
_box.set_name("workspaces");
|
||||||
std::string socketPath = get_socketpath();
|
std::string socketPath = get_socketpath();
|
||||||
_ipcSocketfd = ipc_open_socket(socketPath);
|
_ipcfd = ipc_open_socket(socketPath);
|
||||||
_ipcEventSocketfd = ipc_open_socket(socketPath);
|
_ipcEventfd = ipc_open_socket(socketPath);
|
||||||
const char *subscribe = "[ \"workspace\", \"mode\" ]";
|
const char *subscribe = "[ \"workspace\" ]";
|
||||||
uint32_t len = strlen(subscribe);
|
uint32_t len = strlen(subscribe);
|
||||||
ipc_single_command(_ipcEventSocketfd, IPC_SUBSCRIBE, subscribe, &len);
|
ipc_single_command(_ipcEventfd, IPC_SUBSCRIBE, subscribe, &len);
|
||||||
_idle_timer =
|
_thread = [this] {
|
||||||
org_kde_kwin_idle_get_idle_timeout(_bar.client.idle_manager,
|
try {
|
||||||
_bar.client.seat, 10000); // 10 seconds
|
if (_bar.outputName.empty()) {
|
||||||
static const struct org_kde_kwin_idle_timeout_listener idle_timer_listener = {
|
// Wait for the name of the output
|
||||||
.idle = _handle_idle,
|
while (_bar.outputName.empty())
|
||||||
.resumed = _handle_resume,
|
_thread.sleep_for(chrono::milliseconds(150));
|
||||||
|
} else
|
||||||
|
ipc_recv_response(_ipcEventfd);
|
||||||
|
uint32_t len = 0;
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
auto str = ipc_single_command(_ipcfd, IPC_GET_WORKSPACES, nullptr, &len);
|
||||||
|
_workspaces = _getWorkspaces(str);
|
||||||
|
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Workspaces::update));
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
org_kde_kwin_idle_timeout_add_listener(_idle_timer,
|
|
||||||
&idle_timer_listener, this);
|
|
||||||
_updateThread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::modules::Workspaces::update() -> void
|
auto waybar::modules::Workspaces::update() -> void
|
||||||
{
|
{
|
||||||
Json::Value workspaces = _getWorkspaces();
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
bool hided = false;
|
bool needReorder = false;
|
||||||
for (auto it = _buttons.begin(); it != _buttons.end(); ++it) {
|
for (auto it = _buttons.begin(); it != _buttons.end();) {
|
||||||
auto ws = std::find_if(workspaces.begin(), workspaces.end(),
|
auto ws = std::find_if(_workspaces.begin(), _workspaces.end(),
|
||||||
[it](auto node) -> bool { return node["num"].asInt() == it->first; });
|
[it](auto node) -> bool { return node["num"].asInt() == it->first; });
|
||||||
if (ws == workspaces.end()) {
|
if (ws == _workspaces.end()) {
|
||||||
it->second.hide();
|
it = _buttons.erase(it);
|
||||||
hided = true;
|
needReorder = true;
|
||||||
|
} else
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
}
|
for (auto node : _workspaces) {
|
||||||
for (auto node : workspaces) {
|
if (_bar.outputName != node["output"].asString())
|
||||||
|
continue;
|
||||||
auto it = _buttons.find(node["num"].asInt());
|
auto it = _buttons.find(node["num"].asInt());
|
||||||
if (it == _buttons.end()) {
|
if (it == _buttons.end()) {
|
||||||
_addWorkspace(node);
|
_addWorkspace(node);
|
||||||
|
needReorder = true;
|
||||||
} else {
|
} else {
|
||||||
auto styleContext = it->second.get_style_context();
|
auto &button = it->second;
|
||||||
bool isCurrent = node["focused"].asBool();
|
if (node["focused"].asBool())
|
||||||
if (styleContext->has_class("current") && !isCurrent) {
|
button.get_style_context()->add_class("current");
|
||||||
styleContext->remove_class("current");
|
else
|
||||||
} else if (!styleContext->has_class("current") && isCurrent) {
|
button.get_style_context()->remove_class("current");
|
||||||
styleContext->add_class("current");
|
if (needReorder)
|
||||||
}
|
_box.reorder_child(button, node["num"].asInt());
|
||||||
if (hided) {
|
button.show();
|
||||||
_box->reorder_child(it->second, node["num"].asInt() - 1);
|
|
||||||
}
|
|
||||||
it->second.show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (_scrolling)
|
||||||
|
_scrolling = false;
|
||||||
void waybar::modules::Workspaces::_updateThread()
|
|
||||||
{
|
|
||||||
_thread = new waybar::util::SleeperThread([this] {
|
|
||||||
update();
|
|
||||||
_thread->sleep_for(waybar::chrono::milliseconds(150));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void waybar::modules::Workspaces::_handle_idle(void *data,
|
|
||||||
struct org_kde_kwin_idle_timeout *timer) {
|
|
||||||
auto o = reinterpret_cast<waybar::modules::Workspaces *>(data);
|
|
||||||
if (o->_thread) {
|
|
||||||
delete o->_thread;
|
|
||||||
o->_thread = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void waybar::modules::Workspaces::_handle_resume(void *data,
|
|
||||||
struct org_kde_kwin_idle_timeout *timer) {
|
|
||||||
auto o = reinterpret_cast<waybar::modules::Workspaces *>(data);
|
|
||||||
if (!o->_thread) {
|
|
||||||
o->_updateThread();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Workspaces::_addWorkspace(Json::Value node)
|
void waybar::modules::Workspaces::_addWorkspace(Json::Value node)
|
||||||
{
|
{
|
||||||
auto pair = _buttons.emplace(node["num"].asInt(), node["name"].asString());
|
auto pair = _buttons.emplace(node["num"].asInt(),
|
||||||
|
_getIcon(node["name"].asString()));
|
||||||
auto &button = pair.first->second;
|
auto &button = pair.first->second;
|
||||||
|
_box.pack_start(button, false, false, 0);
|
||||||
button.set_relief(Gtk::RELIEF_NONE);
|
button.set_relief(Gtk::RELIEF_NONE);
|
||||||
button.signal_clicked().connect([this, pair] {
|
button.signal_clicked().connect([this, pair] {
|
||||||
|
try {
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
auto value = fmt::format("workspace \"{}\"", pair.first->first);
|
auto value = fmt::format("workspace \"{}\"", pair.first->first);
|
||||||
uint32_t size = value.size();
|
uint32_t size = value.size();
|
||||||
ipc_single_command(_ipcSocketfd, IPC_COMMAND, value.c_str(), &size);
|
ipc_single_command(_ipcfd, IPC_COMMAND, value.c_str(), &size);
|
||||||
});
|
} catch (const std::exception& e) {
|
||||||
_box->pack_start(button, false, false, 0);
|
std::cerr << e.what() << std::endl;
|
||||||
_box->reorder_child(button, node["num"].asInt() - 1);
|
|
||||||
if (node["focused"].asBool()) {
|
|
||||||
button.get_style_context()->add_class("current");
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
button.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
||||||
|
button.signal_scroll_event()
|
||||||
|
.connect(sigc::mem_fun(*this, &Workspaces::_handleScroll));
|
||||||
|
_box.reorder_child(button, node["num"].asInt());
|
||||||
|
if (node["focused"].asBool())
|
||||||
|
button.get_style_context()->add_class("current");
|
||||||
button.show();
|
button.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value waybar::modules::Workspaces::_getWorkspaces()
|
std::string waybar::modules::Workspaces::_getIcon(std::string name)
|
||||||
{
|
{
|
||||||
uint32_t len = 0;
|
if (_config["format-icons"][name])
|
||||||
Json::Value root;
|
return _config["format-icons"][name].asString();
|
||||||
Json::CharReaderBuilder builder;
|
if (_config["format-icons"]["default"])
|
||||||
Json::CharReader* reader = builder.newCharReader();
|
return _config["format-icons"]["default"].asString();
|
||||||
std::string err;
|
return name;
|
||||||
std::string str = ipc_single_command(_ipcSocketfd, IPC_GET_WORKSPACES,
|
}
|
||||||
nullptr, &len);
|
|
||||||
bool res = reader->parse(str.c_str(), str.c_str() + str.size(), &root, &err);
|
bool waybar::modules::Workspaces::_handleScroll(GdkEventScroll *e)
|
||||||
delete reader;
|
{
|
||||||
if (!res) {
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
std::cerr << err << std::endl;
|
// Avoid concurrent scroll event
|
||||||
return nullptr;
|
if (_scrolling)
|
||||||
|
return false;
|
||||||
|
_scrolling = true;
|
||||||
|
int id = -1;
|
||||||
|
uint16_t idx = 0;
|
||||||
|
for (; idx < _workspaces.size(); idx += 1)
|
||||||
|
if (_workspaces[idx]["focused"].asBool()) {
|
||||||
|
id = _workspaces[idx]["num"].asInt();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return root;
|
if (id == -1) {
|
||||||
|
_scrolling = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (e->direction == GDK_SCROLL_UP)
|
||||||
|
id = _getNextWorkspace();
|
||||||
|
if (e->direction == GDK_SCROLL_DOWN)
|
||||||
|
id = _getPrevWorkspace();
|
||||||
|
if (e->direction == GDK_SCROLL_SMOOTH) {
|
||||||
|
gdouble delta_x, delta_y;
|
||||||
|
gdk_event_get_scroll_deltas ((const GdkEvent *) e, &delta_x, &delta_y);
|
||||||
|
if (delta_y < 0)
|
||||||
|
id = _getNextWorkspace();
|
||||||
|
else if (delta_y > 0)
|
||||||
|
id = _getPrevWorkspace();
|
||||||
|
}
|
||||||
|
if (id == _workspaces[idx]["num"].asInt()) {
|
||||||
|
_scrolling = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto value = fmt::format("workspace \"{}\"", id);
|
||||||
|
uint32_t size = value.size();
|
||||||
|
ipc_single_command(_ipcfd, IPC_COMMAND, value.c_str(), &size);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(150));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int waybar::modules::Workspaces::_getPrevWorkspace()
|
||||||
|
{
|
||||||
|
int current = -1;
|
||||||
|
for (uint16_t i = 0; i != _workspaces.size(); i += 1)
|
||||||
|
if (_workspaces[i]["focused"].asBool()) {
|
||||||
|
current = _workspaces[i]["num"].asInt();
|
||||||
|
if (i > 0)
|
||||||
|
return _workspaces[i - 1]["num"].asInt();
|
||||||
|
return _workspaces[_workspaces.size() - 1]["num"].asInt();
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
int waybar::modules::Workspaces::_getNextWorkspace()
|
||||||
|
{
|
||||||
|
int current = -1;
|
||||||
|
for (uint16_t i = 0; i != _workspaces.size(); i += 1)
|
||||||
|
if (_workspaces[i]["focused"].asBool()) {
|
||||||
|
current = _workspaces[i]["num"].asInt();
|
||||||
|
if (i + 1U < _workspaces.size())
|
||||||
|
return _workspaces[i + 1]["num"].asInt();
|
||||||
|
return _workspaces[0]["num"].asInt();
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value waybar::modules::Workspaces::_getWorkspaces(const std::string data)
|
||||||
|
{
|
||||||
|
Json::Value res;
|
||||||
|
try {
|
||||||
|
std::string err;
|
||||||
|
res = _parser.parse(data);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
waybar::modules::Workspaces::operator Gtk::Widget &() {
|
waybar::modules::Workspaces::operator Gtk::Widget &() {
|
||||||
return *_box;
|
return _box;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user