Compare commits

...

29 Commits
0.0.1 ... 0.0.3

Author SHA1 Message Date
c3bd6da1d0 chore: v0.0.3 2018-08-15 14:50:19 +02:00
e3e099f836 feat(workspaces): icons 2018-08-15 14:48:08 +02:00
767d9dd5b4 fix(workspaces): buttons iterator 2018-08-15 14:30:01 +02:00
d1d51b76aa fix(client): try to fix #20 2018-08-15 01:53:43 +02:00
cee031d2fa Workspaces scroll event (#19) 2018-08-14 11:26:06 +02:00
18c7ad0026 fix(workspaces): lock mutex inside click callback 2018-08-13 23:43:35 +02:00
1555cb71e1 feat(pulseaudio): volume icons 2018-08-13 22:33:07 +02:00
ea9a08d473 refactor(workspaces): listen ipc event 2018-08-13 21:23:43 +02:00
68f9ea3065 fix(battery): add check for sys files 2018-08-13 17:11:47 +02:00
a423f7032d Battery event (#18) 2018-08-13 14:05:13 +02:00
01894f18cd chore: clean headers 2018-08-12 20:25:19 +02:00
3690e7ac55 chore: v0.0.2 2018-08-11 13:19:26 +02:00
b381e2a596 feat(battery): capacity icons 2018-08-11 13:15:31 +02:00
67fa8bd4c3 style(battery): animates background when battery is in a critical state 2018-08-11 13:03:35 +02:00
6ff296a4b0 refactor(bar): prefer standard unique_ptr 2018-08-11 12:49:28 +02:00
8d5b61a9fd refactor(bar): default width is 0 2018-08-11 10:25:21 +02:00
3c66f4baa7 feat(config): can force width 2018-08-11 09:59:35 +02:00
04183dc696 refactor(modules): prefer sigc::mem_fun 2018-08-11 02:40:13 +02:00
14053d61fc feat(workspace): catch ipc errors 2018-08-11 02:09:39 +02:00
424ebb3c9b feat(workspace): only show workspaces which are on same output as bar 2018-08-11 00:32:59 +02:00
2512d51564 fix(gtk): use idle to avoid mutex 2018-08-10 23:21:21 +02:00
95f1ab471a feat(config): add some comments 2018-08-10 18:57:46 +02:00
c792871f6e feat(bar): choose height from config file 2018-08-10 18:46:31 +02:00
8b0cdc5f4b feat(bar): choose between layers used 2018-08-10 18:30:13 +02:00
7d05f6c612 fix(bar): now use bottom layer 2018-08-10 18:25:07 +02:00
679aafa9e8 refactor(pulseaudio): remove signal init 2018-08-10 18:16:11 +02:00
9b2c551f2e fix(battery): typo 2018-08-10 18:04:48 +02:00
d728de2dd7 fix(battery): check for battries :( 2018-08-10 18:02:12 +02:00
4d3879f26f refactor: avoid useless has_class check 2018-08-10 17:05:12 +02:00
34 changed files with 544 additions and 1816 deletions

View File

@ -1,5 +1,7 @@
#pragma once
#include <gtkmm.h>
namespace waybar {
class IModule {
public:

View File

@ -3,6 +3,7 @@
#include <json/json.h>
#include <gtkmm.h>
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
namespace waybar {
@ -17,17 +18,19 @@ namespace waybar {
struct zwlr_layer_surface_v1 *layerSurface;
std::unique_ptr<struct wl_output *> output;
bool visible = true;
auto setWidth(int) -> void;
std::string outputName;
auto setWidth(uint32_t) -> void;
auto toggle() -> void;
private:
static void _handleGeometry(void *data, struct wl_output *wl_output,
int32_t x, int32_t y, int32_t physical_width, int32_t physical_height,
int32_t subpixel, const char *make, const char *model, int32_t transform);
static void _handleMode(void *data, struct wl_output *wl_output,
uint32_t f, int32_t w, int32_t h, int32_t refresh);
static void _handleDone(void *data, struct wl_output *);
static void _handleScale(void *data, struct wl_output *wl_output,
int32_t factor);
static void _handleLogicalPosition(void *data,
struct zxdg_output_v1 *zxdg_output_v1, int32_t x, int32_t y);
static void _handleLogicalSize(void *data,
struct zxdg_output_v1 *zxdg_output_v1, int32_t width, int32_t height);
static void _handleDone(void *data, struct zxdg_output_v1 *zxdg_output_v1);
static void _handleName(void *data, struct zxdg_output_v1 *xdg_output,
const char *name);
static void _handleDescription(void *data,
struct zxdg_output_v1 *zxdg_output_v1, const char *description);
static void _layerSurfaceHandleConfigure(void *data,
struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t width,
uint32_t height);
@ -36,10 +39,12 @@ namespace waybar {
auto _setupConfig() -> void;
auto _setupWidgets() -> void;
auto _setupCss() -> void;
int _width = 10;
uint32_t _width = 0;
uint32_t _height = 30;
Json::Value _config;
Glib::RefPtr<Gtk::StyleContext> _styleContext;
Glib::RefPtr<Gtk::CssProvider> _cssProvider;
struct zxdg_output_v1 *_xdgOutput;
};
}

View File

@ -3,19 +3,11 @@
#include <unistd.h>
#include <wordexp.h>
#include <iostream>
#include <fmt/format.h>
#include <gdk/gdk.h>
#include <gtkmm.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 "bar.hpp"
@ -23,19 +15,19 @@
namespace waybar {
struct Client {
uint32_t height = 30;
std::string cssFile;
std::string configFile;
Gtk::Main gtk_main;
Glib::RefPtr<Gdk::Display> gdk_display;
struct wl_display *wlDisplay;
struct wl_registry *registry;
struct zwlr_layer_shell_v1 *layer_shell;
struct org_kde_kwin_idle *idle_manager;
struct wl_seat *seat;
util::ptr_vec<Bar> bars;
struct wl_display *wlDisplay = nullptr;
struct wl_registry *registry = nullptr;
struct zwlr_layer_shell_v1 *layer_shell = nullptr;
struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
struct wl_seat *seat = nullptr;
struct wl_output *wlOutput = nullptr;
std::vector<std::unique_ptr<Bar>> bars;
Client(int argc, char* argv[]);
void bind_interfaces();

View File

@ -15,7 +15,7 @@ namespace waybar {
class Factory {
public:
Factory(Bar &bar, Json::Value config);
IModule &makeModule(std::string name);
IModule *makeModule(std::string name);
private:
Bar &_bar;
Json::Value _config;

View File

@ -3,9 +3,10 @@
#include <json/json.h>
#include <filesystem>
#include <fstream>
#include <gtkmm.h>
#include <iostream>
#include <fmt/format.h>
#include <sys/inotify.h>
#include <algorithm>
#include "util/chrono.hpp"
#include "IModule.hpp"
@ -19,6 +20,7 @@ namespace waybar::modules {
auto update() -> void;
operator Gtk::Widget&();
private:
std::string _getIcon(uint16_t percentage);
static inline const fs::path _data_dir = "/sys/class/power_supply/";
std::vector<fs::path> _batteries;
util::SleeperThread _thread;

View File

@ -1,9 +1,7 @@
#pragma once
#include <json/json.h>
#include <gtkmm.h>
#include <fmt/format.h>
#include <thread>
#include "util/chrono.hpp"
#include "IModule.hpp"

View File

@ -1,10 +1,8 @@
#pragma once
#include <json/json.h>
#include <gtkmm.h>
#include <fmt/format.h>
#include <sys/sysinfo.h>
#include <thread>
#include "util/chrono.hpp"
#include "IModule.hpp"

View File

@ -1,9 +1,7 @@
#pragma once
#include <json/json.h>
#include <gtkmm.h>
#include <fmt/format.h>
#include <thread>
#include "util/chrono.hpp"
#include "IModule.hpp"

View File

@ -1,10 +1,8 @@
#pragma once
#include <json/json.h>
#include <gtkmm.h>
#include <fmt/format.h>
#include <sys/sysinfo.h>
#include <thread>
#include "util/chrono.hpp"
#include "IModule.hpp"

View File

@ -5,11 +5,8 @@
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <linux/nl80211.h>
#include <iwlib.h> // TODO
#include <json/json.h>
#include <gtkmm.h>
#include <fmt/format.h>
#include <thread>
#include "util/chrono.hpp"
#include "IModule.hpp"

View File

@ -2,8 +2,8 @@
#include <pulse/pulseaudio.h>
#include <json/json.h>
#include <gtkmm.h>
#include <fmt/format.h>
#include <algorithm>
#include "IModule.hpp"
namespace waybar::modules {
@ -14,6 +14,7 @@ namespace waybar::modules {
auto update() -> void;
operator Gtk::Widget &();
private:
std::string _getIcon(uint16_t percentage);
static void _subscribeCb(pa_context *context,
pa_subscription_event_type_t type, uint32_t idx, void *data);
static void _contextStateCb(pa_context *c, void *data);

View File

@ -4,30 +4,34 @@
#include "bar.hpp"
#include "client.hpp"
#include "util/chrono.hpp"
#include "util/json.hpp"
#include "IModule.hpp"
namespace waybar::modules {
class Workspaces : public IModule {
public:
Workspaces(waybar::Bar &bar);
Workspaces(waybar::Bar &bar, Json::Value config);
auto update() -> void;
operator Gtk::Widget &();
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);
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;
util::SleeperThread *_thread;
Gtk::Box *_box;
Json::Value _config;
waybar::util::SleeperThread _thread;
Gtk::Box _box;
util::JsonParser _parser;
std::mutex _mutex;
bool _scrolling;
std::unordered_map<int, Gtk::Button> _buttons;
int _ipcSocketfd;
int _ipcEventSocketfd;
struct org_kde_kwin_idle_timeout *_idle_timer;
Json::Value _workspaces;
int _ipcfd;
int _ipcEventfd;
};
}

View File

@ -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

View File

@ -39,7 +39,9 @@ namespace waybar::util {
func();
} while (do_run);
}}
{}
{
defined = true;
}
SleeperThread& operator=(std::function<void()> func)
{
@ -48,6 +50,7 @@ namespace waybar::util {
func();
} while (do_run);
});
defined = true;
return *this;
}
@ -72,14 +75,17 @@ namespace waybar::util {
~SleeperThread()
{
do_run = false;
if (defined) {
condvar.notify_all();
thread.join();
}
}
private:
std::thread thread;
std::condition_variable condvar;
std::mutex mutex;
bool defined = false;
bool do_run = true;
};

34
include/util/json.hpp Normal file
View 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;
};
}

View File

@ -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

View File

@ -1,6 +1,6 @@
project(
'waybar', 'cpp', 'c',
version: '0.0.1',
version: '0.0.3',
license: 'MIT',
default_options : ['cpp_std=c++17'],
)

View File

@ -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>

View File

@ -23,8 +23,8 @@ wayland_scanner_client = generator(
client_protocols = [
[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'],
['idle.xml'],
]
client_protos_src = []

View File

@ -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-right": ["pulseaudio", "network", "cpu", "memory", "battery", "clock"],
// Modules configuration
"workspaces": {
"format-icons": {
"1": "",
"2": "",
"3": "",
"4": "",
"5": ""
}
},
"cpu": {
"format": "{}% "
},
@ -8,15 +23,17 @@
"format": "{}% "
},
"battery": {
"format": "{}% "
"format": "{capacity}% {icon}",
"format-icons": ["", "", "", "", ""]
},
"network": {
"interface": "wlp2s0",
"format": "{essid} ({signalStrength}%) "
},
"pulseaudio": {
"format": "{}% ",
"format-muted": ""
"format": "{volume}% {icon}",
"format-muted": "",
"format-icons": ["", ""]
},
"custom/spotify": {
"format": " {}",

View File

@ -11,61 +11,82 @@ window {
color: white;
}
.workspaces button {
padding: 0 5px;
#workspaces button {
padding: 0 8px;
background: transparent;
color: white;
border-bottom: 3px solid transparent;
}
.workspaces button.current {
#workspaces button label {
font-size: 12px;
}
#workspaces button.current {
background: #64727D;
border-bottom: 3px solid white;
}
.clock, .battery, .cpu, .memory, .network, .pulseaudio, .custom-spotify {
#clock, #battery, #cpu, #memory, #network, #pulseaudio, #custom-spotify {
padding: 0 10px;
margin: 0 5px;
}
.clock {
#clock {
background-color: #64727D;
}
.battery {
#battery {
background-color: #ffffff;
color: black;
}
.battery.charging {
#battery.charging {
color: white;
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;
color: #000000;
}
.memory {
#memory {
background: #9b59b6;
}
.network {
#network {
background: #2980b9;
}
.pulseaudio {
#pulseaudio {
background: #f1c40f;
color: black;
}
.pulseaudio.muted {
#pulseaudio.muted {
background: #90b1b1;
color: #2a5c45;
}
.custom-spotify {
#custom-spotify {
background: #66cc99;
color: #2a5c45;
}

View File

@ -1,42 +1,43 @@
#include <condition_variable>
#include <gdk/gdkwayland.h>
#include <thread>
#include <fstream>
#include "bar.hpp"
#include "client.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)
: client(client), window{Gtk::WindowType::WINDOW_TOPLEVEL},
output(std::move(p_output))
{
static const struct wl_output_listener outputListener = {
.geometry = _handleGeometry,
.mode = _handleMode,
static const struct zxdg_output_v1_listener xdgOutputListener = {
.logical_position = _handleLogicalPosition,
.logical_size = _handleLogicalSize,
.done = _handleDone,
.scale = _handleScale,
.name = _handleName,
.description = _handleDescription,
};
wl_output_add_listener(*output, &outputListener, this);
_xdgOutput =
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_decorated(false);
_setupConfig();
_setupCss();
_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()));
GdkWindow *gdkWindow = gtk_widget_get_window(GTK_WIDGET(window.gobj()));
gdk_wayland_window_set_use_custom_surface(gdkWindow);
surface = gdk_wayland_window_get_wl_surface(gdkWindow);
layerSurface = zwlr_layer_shell_v1_get_layer_surface(
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");
zwlr_layer_surface_v1_set_anchor(layerSurface,
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));
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 = {
.configure = _layerSurfaceHandleConfigure,
.closed = _layerSurfaceHandleClosed,
@ -46,27 +47,32 @@ waybar::Bar::Bar(Client &client, std::unique_ptr<struct wl_output *> &&p_output)
wl_surface_commit(surface);
}
void waybar::Bar::_handleGeometry(void *data, struct wl_output *wl_output,
int32_t x, int32_t y, int32_t physical_width, int32_t physical_height,
int32_t subpixel, const char *make, const char *model, int32_t transform)
void waybar::Bar::_handleLogicalPosition(void *data,
struct zxdg_output_v1 *zxdg_output_v1, int32_t x, int32_t y)
{
// Nothing here
}
void waybar::Bar::_handleMode(void *data, struct wl_output *wl_output,
uint32_t f, int32_t w, int32_t h, int32_t refresh)
void waybar::Bar::_handleLogicalSize(void *data,
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);
o->setWidth(w);
o->outputName = name;
}
void waybar::Bar::_handleDone(void *data, struct wl_output *)
{
// Nothing here
}
void waybar::Bar::_handleScale(void *data, struct wl_output *wl_output,
int32_t factor)
void waybar::Bar::_handleDescription(void *data,
struct zxdg_output_v1 *zxdg_output_v1, const char *description)
{
// Nothing here
}
@ -77,12 +83,12 @@ void waybar::Bar::_layerSurfaceHandleConfigure(
{
auto o = reinterpret_cast<waybar::Bar *>(data);
o->window.show_all();
o->setWidth(o->_config["width"] ? o->_config["width"].asUInt() : width);
zwlr_layer_surface_v1_ack_configure(surface, serial);
if (o->client.height != height)
{
height = o->client.height;
if (o->_height != height) {
height = o->_height;
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);
wl_surface_commit(o->surface);
}
@ -99,40 +105,34 @@ void waybar::Bar::_layerSurfaceHandleClosed(void *data,
o->window.close();
}
auto waybar::Bar::setWidth(int width) -> void
auto waybar::Bar::setWidth(uint32_t width) -> void
{
if (width == this->_width) return;
std::cout << fmt::format("Bar width configured: {}", width) << std::endl;
this->_width = width;
window.set_size_request(width);
window.resize(width, client.height);
zwlr_layer_surface_v1_set_size(layerSurface, width, 40);
window.resize(width, _height);
zwlr_layer_surface_v1_set_size(layerSurface, width, _height + 1);
wl_surface_commit(surface);
}
auto waybar::Bar::toggle() -> void
{
visible = !visible;
auto zone = visible ? client.height : 0;
auto zone = visible ? _height : 0;
zwlr_layer_surface_v1_set_exclusive_zone(layerSurface, zone);
wl_surface_commit(surface);
}
auto waybar::Bar::_setupConfig() -> void
{
Json::Value root;
Json::CharReaderBuilder builder;
Json::CharReader* reader = builder.newCharReader();
std::string err;
util::JsonParser parser;
std::ifstream file(client.configFile);
if (!file.is_open())
throw std::runtime_error("Can't open config file");
std::string str((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
bool res = reader->parse(str.c_str(), str.c_str() + str.size(), &_config, &err);
delete reader;
if (!res)
throw std::runtime_error(err);
_config = parser.parse(str);
}
auto waybar::Bar::_setupCss() -> void
@ -165,21 +165,24 @@ auto waybar::Bar::_setupWidgets() -> void
if (_config["modules-left"]) {
for (auto name : _config["modules-left"]) {
auto &module = factory.makeModule(name.asString());
left.pack_start(module, false, true, 0);
auto module = factory.makeModule(name.asString());
if (module)
left.pack_start(*module, false, true, 0);
}
}
if (_config["modules-center"]) {
for (auto name : _config["modules-center"]) {
auto &module = factory.makeModule(name.asString());
center.pack_start(module, true, false, 10);
auto module = factory.makeModule(name.asString());
if (module)
center.pack_start(*module, true, false, 10);
}
}
if (_config["modules-right"]) {
std::reverse(_config["modules-right"].begin(), _config["modules-right"].end());
for (auto name : _config["modules-right"]) {
auto &module = factory.makeModule(name.asString());
right.pack_end(module, false, false, 0);
auto module = factory.makeModule(name.asString());
if (module)
right.pack_end(*module, false, false, 0);
}
}
}

View File

@ -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,
&zwlr_layer_shell_v1_interface, version);
} else if (!strcmp(interface, wl_output_interface.name)) {
auto output = std::make_unique<struct wl_output *>();
*output = (struct wl_output *)wl_registry_bind(registry, name,
o->wlOutput = (struct wl_output *)wl_registry_bind(registry, name,
&wl_output_interface, version);
o->bars.emplace_back(*o, std::move(output));
} else if (!strcmp(interface, org_kde_kwin_idle_interface.name)) {
o->idle_manager = (org_kde_kwin_idle *)wl_registry_bind(registry, name,
&org_kde_kwin_idle_interface, version);
auto output = std::make_unique<struct wl_output *>();
*output = o->wlOutput;
if (o->xdg_output_manager)
o->bars.emplace_back(std::make_unique<Bar>(*o, std::move(output)));
} else if (!strcmp(interface, wl_seat_interface.name)) {
o->seat = (struct wl_seat *)wl_registry_bind(registry, name,
&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)));
}
}
}

View File

@ -4,23 +4,32 @@ waybar::Factory::Factory(Bar &bar, Json::Value 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")
return *new waybar::modules::Battery(_config[name]);
return new waybar::modules::Battery(_config[name]);
if (name == "workspaces")
return *new waybar::modules::Workspaces(_bar);
return new waybar::modules::Workspaces(_bar, _config[name]);
if (name == "memory")
return *new waybar::modules::Memory(_config[name]);
return new waybar::modules::Memory(_config[name]);
if (name == "cpu")
return *new waybar::modules::Cpu(_config[name]);
return new waybar::modules::Cpu(_config[name]);
if (name == "clock")
return *new waybar::modules::Clock(_config[name]);
return new waybar::modules::Clock(_config[name]);
if (name == "network")
return *new waybar::modules::Network(_config[name]);
return new waybar::modules::Network(_config[name]);
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)
return *new waybar::modules::Custom(name.substr(7), _config[name]);
throw std::runtime_error("Unknown module: " + name);
return new waybar::modules::Custom(name.substr(7), _config[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;
}

View File

@ -48,10 +48,11 @@ int ipc_open_socket(std::string socket_path) {
}
struct ipc_response ipc_recv_response(int socketfd) {
struct ipc_response response;
char data[ipc_header_size];
uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic));
size_t total = 0;
while (total < ipc_header_size) {
ssize_t received = recv(socketfd, data + total, ipc_header_size - total, 0);
if (received <= 0) {
@ -60,8 +61,6 @@ struct ipc_response ipc_recv_response(int socketfd) {
total += received;
}
struct ipc_response response;
total = 0;
response.size = data32[0];
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[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");
}
if (send(socketfd, payload, *len, 0) == -1) {
if (send(socketfd, payload, *len, 0) == -1)
throw std::runtime_error("Unable to send IPC payload");
}
struct ipc_response resp = ipc_recv_response(socketfd);
std::string response = resp.payload;
*len = resp.size;
return response;
return resp.payload;
}

View File

@ -1,7 +1,5 @@
#include <gtkmm.h>
#include <wayland-client.hpp>
#include <gdk/gdkwayland.h>
#include <csignal>
#include <iostream>
#include "client.hpp"
namespace waybar {
@ -15,7 +13,7 @@ int main(int argc, char* argv[])
waybar::client = &c;
std::signal(SIGUSR1, [] (int signal) {
for (auto& bar : waybar::client->bars) {
bar.toggle();
bar.get()->toggle();
}
});

View File

@ -6,50 +6,75 @@ waybar::modules::Battery::Battery(Json::Value config)
try {
for (auto &node : fs::directory_iterator(_data_dir)) {
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);
}
}
} 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();
_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
{
try {
int total = 0;
uint16_t total = 0;
bool charging = false;
for (auto &bat : _batteries) {
int capacity;
std::string status;
for (auto &bat : _batteries) {
uint16_t capacity;
std::ifstream(bat / "capacity") >> capacity;
total += capacity;
std::ifstream(bat / "status") >> status;
if (status == "Charging") {
if (status == "Charging")
charging = true;
total += capacity;
}
}
if (charging == true) {
uint16_t capacity = total / _batteries.size();
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");
} else {
else
_label.get_style_context()->remove_class("charging");
}
auto format = _config["format"] ? _config["format"].asString() : "{}%";
_label.set_text(fmt::format(format, total / _batteries.size()));
_label.set_tooltip_text(charging ? "Charging" : "Discharging");
} catch (std::exception &e) {
auto critical = _config["critical"] ? _config["critical"].asUInt() : 15;
if (capacity <= critical && !charging)
_label.get_style_context()->add_class("warning");
else
_label.get_style_context()->remove_class("warning");
} catch (const std::exception& e) {
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 &()
{
return _label;

View File

@ -3,9 +3,9 @@
waybar::modules::Clock::Clock(Json::Value config)
: _config(config)
{
_label.get_style_context()->add_class("clock");
_label.set_name("clock");
_thread = [this] {
update();
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Clock::update));
auto now = waybar::chrono::clock::now();
auto timeout =
std::chrono::floor<std::chrono::minutes>(now + std::chrono::minutes(1));

View File

@ -3,10 +3,10 @@
waybar::modules::Cpu::Cpu(Json::Value config)
: _config(config)
{
_label.get_style_context()->add_class("cpu");
_thread = [this] {
update();
_label.set_name("cpu");
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));
};
};

View File

@ -4,14 +4,11 @@
waybar::modules::Custom::Custom(std::string name, Json::Value config)
: _name(name), _config(config)
{
_label.get_style_context()->add_class("custom-" + name);
if (!_config["exec"]) {
std::cerr << name + " has no exec path." << std::endl;
return;
}
_thread = [this] {
update();
if (!_config["exec"])
throw std::runtime_error(name + " has no exec path.");
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));
};
};
@ -36,9 +33,11 @@ auto waybar::modules::Custom::update() -> void
}
// Hide label if output is empty
if (output.empty())
if (output.empty()) {
_label.set_name("");
_label.hide();
else {
} else {
_label.set_name("custom-" + _name);
auto format = _config["format"] ? _config["format"].asString() : "{}";
_label.set_text(fmt::format(format, output));
_label.show();

View File

@ -3,10 +3,10 @@
waybar::modules::Memory::Memory(Json::Value config)
: _config(config)
{
_label.get_style_context()->add_class("memory");
_thread = [this] {
update();
_label.set_name("memory");
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));
};
};

View File

@ -1,11 +1,14 @@
#include "modules/network.hpp"
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");
_thread = [this] {
update();
if (_ifid == 0)
throw std::runtime_error("Can't found network interface");
_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));
};
};
@ -13,7 +16,7 @@ waybar::modules::Network::Network(Json::Value config)
auto waybar::modules::Network::update() -> void
{
_getInfo();
auto format = _config["format"] ? _config["format"].asString() : "{}";
auto format = _config["format"] ? _config["format"].asString() : "{essid}";
_label.set_text(fmt::format(format,
fmt::arg("essid", _essid),
fmt::arg("signaldBm", _signalStrengthdBm),
@ -102,8 +105,6 @@ bool waybar::modules::Network::_associatedOrJoined(struct nlattr** bss)
auto waybar::modules::Network::_getInfo() -> void
{
if (_ifid == 0)
return;
struct nl_sock *sk = nl_socket_alloc();
if (genl_connect(sk) != 0) {
nl_socket_free(sk);

View File

@ -4,14 +4,12 @@ waybar::modules::Pulseaudio::Pulseaudio(Json::Value config)
: _config(config), _mainloop(nullptr), _mainloop_api(nullptr),
_context(nullptr), _sinkIdx(0), _volume(0), _muted(false)
{
_label.get_style_context()->add_class("pulseaudio");
_label.set_name("pulseaudio");
_mainloop = pa_threaded_mainloop_new();
if (!_mainloop)
throw std::runtime_error("pa_mainloop_new() failed.");
pa_threaded_mainloop_lock(_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");
if (!_context)
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->_muted = i->mute;
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 format = _config["format"] ? _config["format"].asString() : "{}%";
auto format = _config["format"] ? _config["format"].asString() : "{volume}%";
if (_muted) {
format =
_config["format-muted"] ? _config["format-muted"].asString() : format;
if (!_label.get_style_context()->has_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.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);
}
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 &() {
return _label;
}

View File

@ -1,121 +1,184 @@
#include "modules/workspaces.hpp"
#include "ipc/client.hpp"
waybar::modules::Workspaces::Workspaces(Bar &bar)
: _bar(bar), _thread(nullptr), _box(Gtk::manage(new Gtk::Box))
waybar::modules::Workspaces::Workspaces(Bar &bar, Json::Value config)
: _bar(bar), _config(config), _scrolling(false)
{
_box->get_style_context()->add_class("workspaces");
_box.set_name("workspaces");
std::string socketPath = get_socketpath();
_ipcSocketfd = ipc_open_socket(socketPath);
_ipcEventSocketfd = ipc_open_socket(socketPath);
const char *subscribe = "[ \"workspace\", \"mode\" ]";
_ipcfd = ipc_open_socket(socketPath);
_ipcEventfd = ipc_open_socket(socketPath);
const char *subscribe = "[ \"workspace\" ]";
uint32_t len = strlen(subscribe);
ipc_single_command(_ipcEventSocketfd, IPC_SUBSCRIBE, subscribe, &len);
_idle_timer =
org_kde_kwin_idle_get_idle_timeout(_bar.client.idle_manager,
_bar.client.seat, 10000); // 10 seconds
static const struct org_kde_kwin_idle_timeout_listener idle_timer_listener = {
.idle = _handle_idle,
.resumed = _handle_resume,
ipc_single_command(_ipcEventfd, IPC_SUBSCRIBE, subscribe, &len);
_thread = [this] {
try {
if (_bar.outputName.empty()) {
// Wait for the name of the output
while (_bar.outputName.empty())
_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
{
Json::Value workspaces = _getWorkspaces();
bool hided = false;
for (auto it = _buttons.begin(); it != _buttons.end(); ++it) {
auto ws = std::find_if(workspaces.begin(), workspaces.end(),
std::lock_guard<std::mutex> lock(_mutex);
bool needReorder = false;
for (auto it = _buttons.begin(); it != _buttons.end();) {
auto ws = std::find_if(_workspaces.begin(), _workspaces.end(),
[it](auto node) -> bool { return node["num"].asInt() == it->first; });
if (ws == workspaces.end()) {
it->second.hide();
hided = true;
if (ws == _workspaces.end()) {
it = _buttons.erase(it);
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());
if (it == _buttons.end()) {
_addWorkspace(node);
needReorder = true;
} else {
auto styleContext = it->second.get_style_context();
bool isCurrent = node["focused"].asBool();
if (styleContext->has_class("current") && !isCurrent) {
styleContext->remove_class("current");
} else if (!styleContext->has_class("current") && isCurrent) {
styleContext->add_class("current");
}
if (hided) {
_box->reorder_child(it->second, node["num"].asInt() - 1);
}
it->second.show();
auto &button = it->second;
if (node["focused"].asBool())
button.get_style_context()->add_class("current");
else
button.get_style_context()->remove_class("current");
if (needReorder)
_box.reorder_child(button, node["num"].asInt());
button.show();
}
}
}
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();
}
if (_scrolling)
_scrolling = false;
}
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;
_box.pack_start(button, false, false, 0);
button.set_relief(Gtk::RELIEF_NONE);
button.signal_clicked().connect([this, pair] {
try {
std::lock_guard<std::mutex> lock(_mutex);
auto value = fmt::format("workspace \"{}\"", pair.first->first);
uint32_t size = value.size();
ipc_single_command(_ipcSocketfd, IPC_COMMAND, value.c_str(), &size);
});
_box->pack_start(button, false, false, 0);
_box->reorder_child(button, node["num"].asInt() - 1);
if (node["focused"].asBool()) {
button.get_style_context()->add_class("current");
ipc_single_command(_ipcfd, IPC_COMMAND, value.c_str(), &size);
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
});
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();
}
Json::Value waybar::modules::Workspaces::_getWorkspaces()
std::string waybar::modules::Workspaces::_getIcon(std::string name)
{
uint32_t len = 0;
Json::Value root;
Json::CharReaderBuilder builder;
Json::CharReader* reader = builder.newCharReader();
std::string err;
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);
delete reader;
if (!res) {
std::cerr << err << std::endl;
return nullptr;
if (_config["format-icons"][name])
return _config["format-icons"][name].asString();
if (_config["format-icons"]["default"])
return _config["format-icons"]["default"].asString();
return name;
}
bool waybar::modules::Workspaces::_handleScroll(GdkEventScroll *e)
{
std::lock_guard<std::mutex> lock(_mutex);
// Avoid concurrent scroll event
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 &() {
return *_box;
return _box;
}