Compare commits

..

34 Commits
0.4.0 ... 0.5.0

Author SHA1 Message Date
f700319d7f chore: v0.5.0 2019-03-20 10:51:40 +01:00
418767c405 Merge pull request #228 from hoellen/feat-rtsignal
Add pkill signals to custom modules
2019-03-18 19:53:02 +01:00
1f924c9c06 Merge branch 'master' into feat-rtsignal 2019-03-18 19:04:11 +01:00
38fa7ceab1 add signalhandler for module update 2019-03-18 18:46:44 +01:00
22cddc5e26 refactor(workspaces): scroll output aware 2019-03-18 14:44:07 +01:00
1ccf372f8e refactor(network): fix skipped messages 2019-03-18 11:07:36 +01:00
3257968a28 Merge pull request #222 from alebastr/pulseaudio-ci-icon-lookup
fix(pulseaudio) use case-insensitive comparison for icon lookup
2019-03-15 09:43:02 +01:00
6fc06fe9db Merge branch 'master' into pulseaudio-ci-icon-lookup 2019-03-15 09:41:40 +01:00
75afcd3ad1 Merge pull request #221 from alebastr/sway-ipc-string-assertion
fix(sway): ipc client crash when compiled with -D_GLIBCXX_ASSERTIONS
2019-03-15 09:40:41 +01:00
9ad80849b1 fix(pulseaudio): Avoid allocation of string vector on every call of getPortIcon() 2019-03-14 18:35:16 -07:00
492d151079 fix(pulseaudio) use case-insensitive comparison for icon lookup 2019-03-14 18:08:12 -07:00
00176c9514 fix(sway): ipc client crash when compiled with -D_GLIBCXX_ASSERTIONS
reserve() does not change string size and any access beyond data() + size() is UB
2019-03-14 17:53:45 -07:00
6d2dcd8ac7 fix(temperature): default thermal zone 2019-03-14 14:01:10 +01:00
7d6079bb06 style: update default temperature style/config 2019-03-13 22:39:39 +01:00
c820ed3495 Merge pull request #216 from Groggy/temperature
Add temperature module
2019-03-13 22:21:11 +01:00
0314bf70b3 feat(temperature): update README 2019-03-13 16:56:13 +01:00
7ae549dc9e Add temperature module 2019-03-13 13:35:43 +01:00
cd13180199 Merge pull request #213 from jubalh/rdmos
Add available on openSUSE
2019-03-12 11:41:05 +01:00
8d6d8e8210 Add available on openSUSE 2019-03-12 11:01:18 +01:00
2995da845d fix: config per output 2019-03-10 10:34:56 +01:00
973cec1713 feat(idle): add status class 2019-03-10 10:29:06 +01:00
94d7b083c5 fix(Pulseaudio): switch case 2019-03-08 15:30:41 +01:00
ef88f0a223 fix: clock rounding 2019-03-07 12:34:21 +01:00
ab0dcbfb2e Merge pull request #204 from Organic-Code/master
Improving mouse buttons support
2019-03-05 10:16:19 +01:00
1974766125 Merge branch 'master' into master 2019-03-05 10:15:05 +01:00
9c0c0d262e Using "inclusive or" for format-alt-click and other click events
c.f. https://github.com/Alexays/Waybar/pull/204#discussion_r262009635

Co-Authored-By: Organic-Code <Lazarelucas@yahoo.fr>
2019-03-04 15:00:44 -05:00
768e57dd37 Merge pull request #208 from jonfin/idle_inhibitor_bugfix
[bugfix] idle_inhibitor: handle click events correctly
2019-03-04 11:20:23 +01:00
67c756b28e Merge branch 'master' into idle_inhibitor_bugfix 2019-03-04 11:19:14 +01:00
584750d0fe Merge pull request #207 from jonfin/tooltip-network
Add custom tooltip format for network module
2019-03-04 11:17:52 +01:00
80ef63791d [bugfix] idle_inhibitor handles click events correctly
- Declare event handler in ALabel virtual so the idle_inhibitor can
  overriding them
- Handle the right click event in idle_inhibitor and call ALabel handler if needed
2019-03-03 22:02:34 +01:00
a9f680b06e Add custom tooltip format for network module 2019-03-03 21:35:35 +01:00
7e4fed8218 Merge pull request #206 from dikeert/issue/205-add-option-to-show-current-workspace-only
resolves #205
2019-03-03 18:04:03 +01:00
737da3615f resolves #205 2019-03-03 21:35:32 +11:00
d0f56b7bdd Improving mouse buttons support
Adding support for middle, backward, and forward mouse buttons click events, adds config keys : "on-click-middle", "on-click-forward" and "on-click-backward"
Adding the key "format-alt-click" to choose what mouse clicks toggles the alternative format, when present. Possible values (in config): "click-right", "click-left", "click-middle", "click-forward", "click-backward". Other values have the same effect than "click-left". Previous behaviour was to toggle it whenever any click was registered and any click that was not handled by "on-click-right" or "on-click-left" occurred
2019-03-02 14:07:12 -05:00
26 changed files with 437 additions and 178 deletions

View File

@ -2,7 +2,7 @@
**Proof of concept** **Proof of concept**
> Highly customizable Wayland bar for Sway and Wlroots based compositors.<br> > Highly customizable Wayland bar for Sway and Wlroots based compositors.<br>
> Available on [AUR](https://aur.archlinux.org/packages/waybar-git/) > Available on [AUR](https://aur.archlinux.org/packages/waybar-git/) and [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar)
**Current features** **Current features**
- Sway (Workspaces, Binding mode, Focused window name) - Sway (Workspaces, Binding mode, Focused window name)
@ -13,6 +13,7 @@
- Pulseaudio - Pulseaudio
- Memory - Memory
- Cpu load average - Cpu load average
- Temperature
- Custom scripts - Custom scripts
- Multiple output configuration - Multiple output configuration
- And much more customizations - And much more customizations

View File

@ -28,9 +28,8 @@ protected:
bool alt_ = false; bool alt_ = false;
std::string default_format_; std::string default_format_;
private: virtual bool handleToggle(GdkEventButton *const &ev);
bool handleToggle(GdkEventButton *const &ev); virtual bool handleScroll(GdkEventScroll *);
bool handleScroll(GdkEventScroll *);
}; };
} // namespace waybar } // namespace waybar

View File

@ -22,6 +22,7 @@ class Bar {
~Bar() = default; ~Bar() = default;
auto toggle() -> void; auto toggle() -> void;
void handleSignal(int);
const Client& client; const Client& client;
Gtk::Window window; Gtk::Window window;

View File

@ -23,6 +23,7 @@
#ifdef HAVE_LIBPULSE #ifdef HAVE_LIBPULSE
#include "modules/pulseaudio.hpp" #include "modules/pulseaudio.hpp"
#endif #endif
#include "modules/temperature.hpp"
#include "modules/custom.hpp" #include "modules/custom.hpp"
namespace waybar { namespace waybar {

View File

@ -2,6 +2,7 @@
#include <fmt/format.h> #include <fmt/format.h>
#include <iostream> #include <iostream>
#include <csignal>
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
#include "util/command.hpp" #include "util/command.hpp"
#include "util/json.hpp" #include "util/json.hpp"
@ -14,6 +15,7 @@ class Custom : public ALabel {
Custom(const std::string&, const Json::Value&); Custom(const std::string&, const Json::Value&);
~Custom(); ~Custom();
auto update() -> void; auto update() -> void;
void refresh(int /*signal*/);
private: private:
void delayWorker(); void delayWorker();
void continuousWorker(); void continuousWorker();

View File

@ -13,7 +13,7 @@ class IdleInhibitor: public ALabel {
~IdleInhibitor(); ~IdleInhibitor();
auto update() -> void; auto update() -> void;
private: private:
bool onClick(GdkEventButton* const& ev); bool handleToggle(GdkEventButton* const& e);
const Bar& bar_; const Bar& bar_;
std::string status_; std::string status_;

View File

@ -21,8 +21,8 @@ class Network : public ALabel {
auto update() -> void; auto update() -> void;
private: private:
static const uint8_t MAX_RETRY = 5; static const uint8_t MAX_RETRY = 5;
static const uint8_t EPOLL_MAX = 255;
static int handleEvents(struct nl_msg*, void*);
static int handleScan(struct nl_msg*, void*); static int handleScan(struct nl_msg*, void*);
void worker(); void worker();
@ -31,6 +31,7 @@ class Network : public ALabel {
void createEventSocket(); void createEventSocket();
int getExternalInterface(); int getExternalInterface();
void getInterfaceAddress(); void getInterfaceAddress();
void handleEvents();
int netlinkRequest(void*, uint32_t, uint32_t groups = 0); int netlinkRequest(void*, uint32_t, uint32_t groups = 0);
int netlinkResponse(void*, uint32_t, uint32_t groups = 0); int netlinkResponse(void*, uint32_t, uint32_t groups = 0);
void parseEssid(struct nlattr**); void parseEssid(struct nlattr**);
@ -44,7 +45,7 @@ class Network : public ALabel {
sa_family_t family_; sa_family_t family_;
struct sockaddr_nl nladdr_ = {0}; struct sockaddr_nl nladdr_ = {0};
struct nl_sock* sk_ = nullptr; struct nl_sock* sk_ = nullptr;
struct nl_sock* info_sock_ = nullptr; int info_sock_;
int efd_; int efd_;
int ev_fd_; int ev_fd_;
int nl80211_id_; int nl80211_id_;

View File

@ -20,11 +20,11 @@ class Workspaces : public IModule {
private: private:
void worker(); void worker();
void addWorkspace(const Json::Value&); void addWorkspace(const Json::Value&);
void onButtonReady(const Json::Value&, Gtk::Button&);
std::string getIcon(const std::string&, const Json::Value&); std::string getIcon(const std::string&, const Json::Value&);
bool handleScroll(GdkEventScroll*); bool handleScroll(GdkEventScroll*);
std::string getPrevWorkspace(); const std::string getCycleWorkspace(uint8_t current, bool prev) const;
std::string getNextWorkspace(); uint16_t getWorkspaceIndex(const std::string &name) const;
uint16_t getWorkspaceIndex(const std::string &name);
std::string trimWorkspaceName(std::string); std::string trimWorkspaceName(std::string);
const Bar& bar_; const Bar& bar_;

View File

@ -0,0 +1,23 @@
#pragma once
#include <fmt/format.h>
#include <fstream>
#include "util/sleeper_thread.hpp"
#include "ALabel.hpp"
namespace waybar::modules {
class Temperature : public ALabel {
public:
Temperature(const std::string&, const Json::Value&);
~Temperature() = default;
auto update() -> void;
private:
std::tuple<uint16_t, uint16_t> getTemperature();
bool isCritical(uint16_t);
std::string file_path_;
waybar::util::SleeperThread thread_;
};
}

View File

@ -21,7 +21,10 @@ public:
SleeperThread& operator=(std::function<void()> func) SleeperThread& operator=(std::function<void()> func)
{ {
thread_ = std::thread([this, func] { thread_ = std::thread([this, func] {
while (do_run_) func(); while (do_run_) {
signal_ = false;
func();
}
}); });
return *this; return *this;
} }
@ -34,18 +37,19 @@ public:
auto sleep_for(std::chrono::system_clock::duration dur) auto sleep_for(std::chrono::system_clock::duration dur)
{ {
std::unique_lock lk(mutex_); std::unique_lock lk(mutex_);
return condvar_.wait_for(lk, dur, [this] { return !do_run_; }); return condvar_.wait_for(lk, dur, [this] { return signal_ || !do_run_; });
} }
auto sleep_until(std::chrono::time_point<std::chrono::system_clock, auto sleep_until(std::chrono::time_point<std::chrono::system_clock,
std::chrono::system_clock::duration> time_point) std::chrono::system_clock::duration> time_point)
{ {
std::unique_lock lk(mutex_); std::unique_lock lk(mutex_);
return condvar_.wait_until(lk, time_point, [this] { return !do_run_; }); return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; });
} }
auto wake_up() auto wake_up()
{ {
signal_ = true;
condvar_.notify_all(); condvar_.notify_all();
} }
@ -53,6 +57,7 @@ public:
{ {
{ {
std::lock_guard<std::mutex> lck(mutex_); std::lock_guard<std::mutex> lck(mutex_);
signal_ = true;
do_run_ = false; do_run_ = false;
} }
condvar_.notify_all(); condvar_.notify_all();
@ -71,6 +76,7 @@ private:
std::condition_variable condvar_; std::condition_variable condvar_;
std::mutex mutex_; std::mutex mutex_;
bool do_run_ = true; bool do_run_ = true;
bool signal_ = false;
}; };
} }

View File

@ -1,6 +1,6 @@
project( project(
'waybar', 'cpp', 'c', 'waybar', 'cpp', 'c',
version: '0.4.0', version: '0.5.0',
license: 'MIT', license: 'MIT',
default_options : [ default_options : [
'cpp_std=c++17', 'cpp_std=c++17',
@ -66,6 +66,7 @@ src_files = files(
'src/modules/custom.cpp', 'src/modules/custom.cpp',
'src/modules/cpu.cpp', 'src/modules/cpu.cpp',
'src/modules/idle_inhibitor.cpp', 'src/modules/idle_inhibitor.cpp',
'src/modules/temperature.cpp',
'src/main.cpp', 'src/main.cpp',
'src/bar.cpp', 'src/bar.cpp',
'src/client.cpp' 'src/client.cpp'

View File

@ -6,7 +6,7 @@
// Choose the order of the modules // Choose the order of the modules
"modules-left": ["sway/workspaces", "sway/mode", "custom/spotify"], "modules-left": ["sway/workspaces", "sway/mode", "custom/spotify"],
"modules-center": ["sway/window"], "modules-center": ["sway/window"],
"modules-right": ["idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "backlight", "battery", "battery#bat2", "clock", "tray"], "modules-right": ["idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "battery", "battery#bat2", "clock", "tray"],
// Modules configuration // Modules configuration
// "sway/workspaces": { // "sway/workspaces": {
// "disable-scroll": true, // "disable-scroll": true,
@ -47,6 +47,13 @@
"memory": { "memory": {
"format": "{}% " "format": "{}% "
}, },
"temperature": {
// "thermal-zone": 2,
// "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
"critical-threshold": 80,
// "format-critical": "{temperatureC}°C ",
"format": "{temperatureC}°C "
},
"backlight": { "backlight": {
// "device": "acpi_video1", // "device": "acpi_video1",
"format": "{percent}% {icon}", "format": "{percent}% {icon}",

View File

@ -9,28 +9,28 @@
window#waybar { window#waybar {
background: rgba(43, 48, 59, 0.5); background: rgba(43, 48, 59, 0.5);
border-bottom: 3px solid rgba(100, 114, 125, 0.5); border-bottom: 3px solid rgba(100, 114, 125, 0.5);
color: white; color: #ffffff;
} }
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ /* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
#workspaces button { #workspaces button {
padding: 0 5px; padding: 0 5px;
background: transparent; background: transparent;
color: white; color: #ffffff;
border-bottom: 3px solid transparent; border-bottom: 3px solid transparent;
} }
#workspaces button.focused { #workspaces button.focused {
background: #64727D; background: #64727D;
border-bottom: 3px solid white; border-bottom: 3px solid #ffffff;
} }
#mode { #mode {
background: #64727D; background: #64727D;
border-bottom: 3px solid white; border-bottom: 3px solid #ffffff;
} }
#clock, #battery, #cpu, #memory, #backlight, #network, #pulseaudio, #custom-spotify, #tray, #mode, #idle_inhibitor { #clock, #battery, #cpu, #memory, #temperature, #backlight, #network, #pulseaudio, #custom-spotify, #tray, #mode, #idle_inhibitor {
padding: 0 10px; padding: 0 10px;
margin: 0 5px; margin: 0 5px;
} }
@ -41,24 +41,24 @@ window#waybar {
#battery { #battery {
background-color: #ffffff; background-color: #ffffff;
color: black; color: #000000;
} }
#battery.charging { #battery.charging {
color: white; color: #ffffff;
background-color: #26A65B; background-color: #26A65B;
} }
@keyframes blink { @keyframes blink {
to { to {
background-color: #ffffff; background-color: #ffffff;
color: black; color: #000000;
} }
} }
#battery.critical:not(.charging) { #battery.critical:not(.charging) {
background: #f53c3c; background: #f53c3c;
color: white; color: #ffffff;
animation-name: blink; animation-name: blink;
animation-duration: 0.5s; animation-duration: 0.5s;
animation-timing-function: linear; animation-timing-function: linear;
@ -89,7 +89,7 @@ window#waybar {
#pulseaudio { #pulseaudio {
background: #f1c40f; background: #f1c40f;
color: black; color: #000000;
} }
#pulseaudio.muted { #pulseaudio.muted {
@ -102,6 +102,14 @@ window#waybar {
color: #2a5c45; color: #2a5c45;
} }
#temperature {
background: #f0932b;
}
#temperature.critical {
background: #eb4d4b;
}
#tray { #tray {
background-color: #2980b9; background-color: #2980b9;
} }
@ -109,3 +117,8 @@ window#waybar {
#idle_inhibitor { #idle_inhibitor {
background-color: #2d3436; background-color: #2d3436;
} }
#idle_inhibitor.activated {
background-color: #ecf0f1;
color: #2d3436;
}

View File

@ -6,8 +6,9 @@
waybar::ALabel::ALabel(const Json::Value& config, const std::string format, uint16_t interval) waybar::ALabel::ALabel(const Json::Value& config, const std::string format, uint16_t interval)
: config_(config), : config_(config),
format_(config_["format"].isString() ? config_["format"].asString() : format), format_(config_["format"].isString() ? config_["format"].asString() : format),
interval_(std::chrono::seconds(config_["interval"].isUInt() interval_(config_["interval"] == "once" ? std::chrono::seconds(100000000) :
? config_["interval"].asUInt() : interval)), default_format_(format_) std::chrono::seconds(config_["interval"].isUInt() ?
config_["interval"].asUInt() : interval)), default_format_(format_)
{ {
event_box_.add(label_); event_box_.add(label_);
if (config_["max-length"].isUInt()) { if (config_["max-length"].isUInt()) {
@ -40,11 +41,20 @@ auto waybar::ALabel::update() -> void {
bool waybar::ALabel::handleToggle(GdkEventButton* const& e) { bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
if (config_["on-click"].isString() && e->button == 1) { if (config_["on-click"].isString() && e->button == 1) {
waybar::util::command::forkExec(config_["on-click"].asString()); waybar::util::command::forkExec(config_["on-click"].asString());
} else if (config_["on-click-middle"].isString() && e->button == 2) {
waybar::util::command::forkExec(config_["on-click-middle"].asString());
} else if (config_["on-click-right"].isString() && e->button == 3) { } else if (config_["on-click-right"].isString() && e->button == 3) {
waybar::util::command::forkExec(config_["on-click-right"].asString()); waybar::util::command::forkExec(config_["on-click-right"].asString());
} else { } else if (config_["on-click-forward"].isString() && e->button == 8) {
waybar::util::command::forkExec(config_["on-click-backward"].asString());
} else if (config_["on-click-backward"].isString() && e->button == 9) {
waybar::util::command::forkExec(config_["on-click-forward"].asString());
}
if (config_["format-alt-click"].isUInt() && e->button == config_["format-alt-click"].asUInt()) {
alt_ = !alt_; alt_ = !alt_;
if (alt_) { if (alt_ && config_["format-alt"].isString()) {
format_ = config_["format-alt"].asString(); format_ = config_["format-alt"].asString();
} else { } else {
format_ = default_format_; format_ = default_format_;

View File

@ -37,7 +37,54 @@ waybar::Bar::Bar(const Client& client,
void waybar::Bar::initBar() void waybar::Bar::initBar()
{ {
std::size_t layer_top = config_["layer"] == "top" // Converting string to button code rn as to avoid doing it later
auto setupAltFormatKeyForModule = [this](const std::string& module_name){
if (config_.isMember(module_name)) {
Json::Value& module = config_[module_name];
if (module.isMember("format-alt")) {
if (module.isMember("format-alt-click")) {
Json::Value& click = module["format-alt-click"];
if (click.isString()) {
std::string str_click = click.asString();
if (str_click == "click-right") {
module["format-alt-click"] = 3u;
} else if (str_click == "click-middle") {
module["format-alt-click"] = 2u;
} else if (str_click == "click-backward") {
module["format-alt-click"] = 8u;
} else if (str_click == "click-forward") {
module["format-alt-click"] = 9u;
} else {
module["format-alt-click"] = 1u; // default click-left
}
} else {
module["format-alt-click"] = 1u;
}
} else {
module["format-alt-click"] = 1u;
}
}
}
};
auto setupAltFormatKeyForModuleList = [this, &setupAltFormatKeyForModule](const char* module_list_name) {
if (config_.isMember(module_list_name)) {
Json::Value& modules = config_[module_list_name];
for (const Json::Value& module_name : modules) {
if (module_name.isString()) {
setupAltFormatKeyForModule(module_name.asString());
}
}
}
};
// Convert to button code for every module that is used.
setupAltFormatKeyForModuleList("modules-left");
setupAltFormatKeyForModuleList("modules-right");
setupAltFormatKeyForModuleList("modules-center");
std::size_t layer_top = config_["layer"] == "top"
? ZWLR_LAYER_SHELL_V1_LAYER_TOP : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; ? ZWLR_LAYER_SHELL_V1_LAYER_TOP : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
layer_surface = zwlr_layer_shell_v1_get_layer_surface( layer_surface = zwlr_layer_shell_v1_get_layer_surface(
client.layer_shell, surface, *output, layer_top, "waybar"); client.layer_shell, surface, *output, layer_top, "waybar");
@ -138,6 +185,22 @@ void waybar::Bar::handleDescription(void* /*data*/,
// Nothing here // Nothing here
} }
void waybar::Bar::handleSignal(int signal)
{
for (auto& module : modules_left_) {
auto* custom = dynamic_cast<waybar::modules::Custom*>(module.get());
if(custom) custom->refresh(signal);
}
for (auto& module : modules_center_) {
auto* custom = dynamic_cast<waybar::modules::Custom*>(module.get());
if(custom) custom->refresh(signal);
}
for (auto& module : modules_right_) {
auto* custom = dynamic_cast<waybar::modules::Custom*>(module.get());
if(custom) custom->refresh(signal);
}
}
void waybar::Bar::layerSurfaceHandleConfigure(void* data, void waybar::Bar::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)
@ -169,7 +232,6 @@ void waybar::Bar::layerSurfaceHandleClosed(void* data,
struct zwlr_layer_surface_v1* /*surface*/) struct zwlr_layer_surface_v1* /*surface*/)
{ {
auto o = static_cast<waybar::Bar *>(data); auto o = static_cast<waybar::Bar *>(data);
std::cout << "Bar removed from output: " + o->output_name << std::endl;
zwlr_layer_surface_v1_destroy(o->layer_surface); zwlr_layer_surface_v1_destroy(o->layer_surface);
wl_output_destroy(*o->output); wl_output_destroy(*o->output);
zxdg_output_v1_destroy(o->xdg_output_); zxdg_output_v1_destroy(o->xdg_output_);

View File

@ -67,8 +67,10 @@ void waybar::Client::handleGlobalRemove(void* data,
{ {
auto o = static_cast<waybar::Client *>(data); auto o = static_cast<waybar::Client *>(data);
for (auto it = o->bars.begin(); it != o->bars.end(); ++it) { for (auto it = o->bars.begin(); it != o->bars.end(); ++it) {
if ((**it).wl_name == name) { if ((*it)->wl_name == name) {
auto output_name = (*it)->output_name;
o->bars.erase(it); o->bars.erase(it);
std::cout << "Bar removed from output: " + output_name << std::endl;
break; break;
} }
} }

View File

@ -56,6 +56,9 @@ waybar::IModule* waybar::Factory::makeModule(const std::string &name) const
return new waybar::modules::Pulseaudio(id, config_[name]); return new waybar::modules::Pulseaudio(id, config_[name]);
} }
#endif #endif
if (ref == "temperature") {
return new waybar::modules::Temperature(id, config_[name]);
}
if (ref.compare(0, 7, "custom/") == 0 && ref.size() > 7) { if (ref.compare(0, 7, "custom/") == 0 && ref.size() > 7) {
return new waybar::modules::Custom(ref.substr(7), config_[name]); return new waybar::modules::Custom(ref.substr(7), config_[name]);
} }

View File

@ -19,6 +19,14 @@ int main(int argc, char* argv[])
} }
}); });
for (int sig = SIGRTMIN + 1; sig <= SIGRTMAX; ++sig) {
std::signal(sig, [] (int sig/*signal*/) {
for (auto& bar : waybar::client->bars) {
bar->handleSignal(sig);
}
});
}
return c.main(argc, argv); return c.main(argc, argv);
} catch (const std::exception& e) { } catch (const std::exception& e) {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;

View File

@ -8,13 +8,14 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
label_.get_style_context()->add_class(id); label_.get_style_context()->add_class(id);
} }
thread_ = [this] { thread_ = [this] {
auto now = std::chrono::system_clock::now();
dp.emit(); dp.emit();
auto now = std::chrono::system_clock::now();
auto timeout = std::chrono::floor<std::chrono::seconds>(now + interval_); auto timeout = std::chrono::floor<std::chrono::seconds>(now + interval_);
auto time_s = std::chrono::time_point_cast<std::chrono::seconds>(timeout); auto time_s = std::chrono::time_point_cast<std::chrono::seconds>(timeout);
auto sub_m = auto sub_m =
std::chrono::duration_cast<std::chrono::seconds>(time_s.time_since_epoch()).count() % interval_.count(); std::chrono::duration_cast<std::chrono::seconds>(time_s.time_since_epoch()).count() % interval_.count();
thread_.sleep_until(timeout - std::chrono::seconds(sub_m - 1)); if (sub_m > 0) thread_.sleep_until(timeout - std::chrono::seconds(sub_m - 1));
else thread_.sleep_until(timeout - std::chrono::seconds(sub_m));
}; };
} }

View File

@ -66,7 +66,6 @@ void waybar::modules::Custom::continuousWorker()
} }
return; return;
} }
std::string output = buff; std::string output = buff;
// Remove last newline // Remove last newline
@ -78,6 +77,13 @@ void waybar::modules::Custom::continuousWorker()
}; };
} }
void waybar::modules::Custom::refresh(int sig /*signal*/)
{
if(sig == SIGRTMIN + config_["signal"].asInt()) {
thread_.wake_up();
}
}
auto waybar::modules::Custom::update() -> void auto waybar::modules::Custom::update() -> void
{ {
// Hide label if output is empty // Hide label if output is empty

View File

@ -1,5 +1,5 @@
#include "modules/idle_inhibitor.hpp" #include "modules/idle_inhibitor.hpp"
#include "util/command.hpp"
waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar& bar, const Json::Value& config) waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar& bar, const Json::Value& config)
: ALabel(config, "{status}"), bar_(bar), status_("deactivated"), idle_inhibitor_(nullptr) : ALabel(config, "{status}"), bar_(bar), status_("deactivated"), idle_inhibitor_(nullptr)
@ -10,7 +10,7 @@ waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar&
} }
event_box_.add_events(Gdk::BUTTON_PRESS_MASK); event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
event_box_.signal_button_press_event().connect( event_box_.signal_button_press_event().connect(
sigc::mem_fun(*this, &IdleInhibitor::onClick)); sigc::mem_fun(*this, &IdleInhibitor::handleToggle));
dp.emit(); dp.emit();
} }
@ -27,14 +27,15 @@ auto waybar::modules::IdleInhibitor::update() -> void
label_.set_markup( label_.set_markup(
fmt::format(format_, fmt::arg("status", status_), fmt::format(format_, fmt::arg("status", status_),
fmt::arg("icon", getIcon(0, status_)))); fmt::arg("icon", getIcon(0, status_))));
label_.get_style_context()->add_class(status_);
if(tooltipEnabled()) { if(tooltipEnabled()) {
label_.set_tooltip_text(status_); label_.set_tooltip_text(status_);
} }
} }
bool waybar::modules::IdleInhibitor::onClick(GdkEventButton* const& e) bool waybar::modules::IdleInhibitor::handleToggle(GdkEventButton* const& e) {
{ if (e->button == 1) {
if(e->button == 1) { label_.get_style_context()->remove_class(status_);
if (idle_inhibitor_) { if (idle_inhibitor_) {
zwp_idle_inhibitor_v1_destroy(idle_inhibitor_); zwp_idle_inhibitor_v1_destroy(idle_inhibitor_);
idle_inhibitor_ = nullptr; idle_inhibitor_ = nullptr;
@ -44,7 +45,13 @@ bool waybar::modules::IdleInhibitor::onClick(GdkEventButton* const& e)
bar_.client.idle_inhibit_manager, bar_.surface); bar_.client.idle_inhibit_manager, bar_.surface);
status_ = "activated"; status_ = "activated";
} }
if (config_["on-click"].isString() && e->button == 1) {
waybar::util::command::forkExec(config_["on-click"].asString());
}
} else {
ALabel::handleToggle(e);
} }
dp.emit(); dp.emit();
return true; return true;
} }

View File

@ -2,8 +2,8 @@
#include "modules/network.hpp" #include "modules/network.hpp"
waybar::modules::Network::Network(const std::string& id, const Json::Value& config) waybar::modules::Network::Network(const std::string& id, const Json::Value& config)
: ALabel(config, "{ifname}", 60), family_(AF_INET), efd_(-1), ev_fd_(-1), : ALabel(config, "{ifname}", 60), family_(AF_INET), info_sock_(-1), efd_(-1),
cidr_(-1), signal_strength_dbm_(0), signal_strength_(0) ev_fd_(-1), cidr_(-1), signal_strength_dbm_(0), signal_strength_(0)
{ {
label_.set_name("network"); label_.set_name("network");
if (!id.empty()) { if (!id.empty()) {
@ -39,11 +39,8 @@ waybar::modules::Network::~Network()
if (efd_ > -1) { if (efd_ > -1) {
close(efd_); close(efd_);
} }
if (info_sock_ != nullptr) { if (info_sock_ != -1) {
nl_socket_drop_membership(info_sock_, RTMGRP_LINK); close(info_sock_);
nl_socket_drop_membership(info_sock_, RTMGRP_IPV4_IFADDR);
nl_close(info_sock_);
nl_socket_free(info_sock_);
} }
if (sk_ != nullptr) { if (sk_ != nullptr) {
nl_close(sk_); nl_close(sk_);
@ -53,19 +50,18 @@ waybar::modules::Network::~Network()
void waybar::modules::Network::createInfoSocket() void waybar::modules::Network::createInfoSocket()
{ {
info_sock_ = nl_socket_alloc(); struct sockaddr_nl sa;
if (nl_connect(info_sock_, NETLINK_ROUTE) != 0) { info_sock_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
throw std::runtime_error("Can't connect network socket"); if (info_sock_ < 0) {
} throw std::runtime_error("Can't connect network socket");
if (nl_socket_add_membership(info_sock_, RTMGRP_LINK) != 0) { }
sa.nl_family = AF_NETLINK;
sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE
| RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
auto ret = bind(info_sock_, (struct sockaddr *)&sa, sizeof(sa));
if (ret < 0) {
throw std::runtime_error("Can't add membership"); throw std::runtime_error("Can't add membership");
} }
if (nl_socket_add_membership(info_sock_, RTMGRP_IPV4_IFADDR) != 0) {
throw std::runtime_error("Can't add membership");
}
nl_socket_disable_seq_check(info_sock_);
nl_socket_set_nonblocking(info_sock_);
nl_socket_modify_cb(info_sock_, NL_CB_VALID, NL_CB_CUSTOM, handleEvents, this);
efd_ = epoll_create1(0); efd_ = epoll_create1(0);
if (efd_ < 0) { if (efd_ < 0) {
throw std::runtime_error("Can't create epoll"); throw std::runtime_error("Can't create epoll");
@ -80,11 +76,10 @@ void waybar::modules::Network::createInfoSocket()
} }
} }
{ {
auto fd = nl_socket_get_fd(info_sock_);
struct epoll_event event; struct epoll_event event;
event.events = EPOLLIN | EPOLLET | EPOLLRDHUP; event.events = EPOLLIN | EPOLLET;
event.data.fd = fd; event.data.fd = info_sock_;
if (epoll_ctl(efd_, EPOLL_CTL_ADD, fd, &event) == -1) { if (epoll_ctl(efd_, EPOLL_CTL_ADD, info_sock_, &event) == -1) {
throw std::runtime_error("Can't add epoll event"); throw std::runtime_error("Can't add epoll event");
} }
} }
@ -93,7 +88,7 @@ void waybar::modules::Network::createInfoSocket()
void waybar::modules::Network::createEventSocket() void waybar::modules::Network::createEventSocket()
{ {
sk_ = nl_socket_alloc(); sk_ = nl_socket_alloc();
if (genl_connect(sk_) != 0) { if (genl_connect(sk_) != 0) {
throw std::runtime_error("Can't connect to netlink socket"); throw std::runtime_error("Can't connect to netlink socket");
} }
if (nl_socket_modify_cb(sk_, NL_CB_VALID, NL_CB_CUSTOM, handleScan, this) < 0) { if (nl_socket_modify_cb(sk_, NL_CB_VALID, NL_CB_CUSTOM, handleScan, this) < 0) {
@ -114,16 +109,15 @@ void waybar::modules::Network::worker()
} }
thread_timer_.sleep_for(interval_); thread_timer_.sleep_for(interval_);
}; };
thread_ = [this] { struct epoll_event events[EPOLL_MAX] = {0};
struct epoll_event events[16]; thread_ = [this, &events] {
int ec = epoll_wait(efd_, events, 16, -1); int ec = epoll_wait(efd_, events, EPOLL_MAX, -1);
if (ec > 0) { if (ec > 0) {
for (auto i = 0; i < ec; i++) { for (auto i = 0; i < ec; i++) {
if (events[i].data.fd == nl_socket_get_fd(info_sock_)) { if (events[i].data.fd == ev_fd_) {
nl_recvmsgs_default(info_sock_);
} else {
thread_.stop(); thread_.stop();
break; } else if (events[i].events & EPOLLIN) {
handleEvents();
} }
} }
} else if (ec == -1) { } else if (ec == -1) {
@ -135,10 +129,17 @@ void waybar::modules::Network::worker()
auto waybar::modules::Network::update() -> void auto waybar::modules::Network::update() -> void
{ {
std::string connectiontype; std::string connectiontype;
std::string tooltip_format = "";
if (config_["tooltip-format"].isString()) {
tooltip_format = config_["tooltip-format"].asString();
}
if (ifid_ <= 0 || ipaddr_.empty()) { if (ifid_ <= 0 || ipaddr_.empty()) {
if (config_["format-disconnected"].isString()) { if (config_["format-disconnected"].isString()) {
default_format_ = config_["format-disconnected"].asString(); default_format_ = config_["format-disconnected"].asString();
} }
if (config_["tooltip-format-disconnected"].isString()) {
tooltip_format = config_["tooltip-format-disconnected"].asString();
}
label_.get_style_context()->add_class("disconnected"); label_.get_style_context()->add_class("disconnected");
connectiontype = "disconnected"; connectiontype = "disconnected";
} else { } else {
@ -146,11 +147,17 @@ auto waybar::modules::Network::update() -> void
if (config_["format-ethernet"].isString()) { if (config_["format-ethernet"].isString()) {
default_format_ = config_["format-ethernet"].asString(); default_format_ = config_["format-ethernet"].asString();
} }
if (config_["tooltip-format-ethernet"].isString()) {
tooltip_format = config_["tooltip-format-ethernet"].asString();
}
connectiontype = "ethernet"; connectiontype = "ethernet";
} else { } else {
if (config_["format-wifi"].isString()) { if (config_["format-wifi"].isString()) {
default_format_ = config_["format-wifi"].asString(); default_format_ = config_["format-wifi"].asString();
} }
if (config_["tooltip-format-wifi"].isString()) {
tooltip_format = config_["tooltip-format-wifi"].asString();
}
connectiontype = "wifi"; connectiontype = "wifi";
} }
label_.get_style_context()->remove_class("disconnected"); label_.get_style_context()->remove_class("disconnected");
@ -158,7 +165,7 @@ auto waybar::modules::Network::update() -> void
if (!alt_) { if (!alt_) {
format_ = default_format_; format_ = default_format_;
} }
label_.set_markup(fmt::format(format_, auto text = fmt::format(format_,
fmt::arg("essid", essid_), fmt::arg("essid", essid_),
fmt::arg("signaldBm", signal_strength_dbm_), fmt::arg("signaldBm", signal_strength_dbm_),
fmt::arg("signalStrength", signal_strength_), fmt::arg("signalStrength", signal_strength_),
@ -167,7 +174,25 @@ auto waybar::modules::Network::update() -> void
fmt::arg("ipaddr", ipaddr_), fmt::arg("ipaddr", ipaddr_),
fmt::arg("cidr", cidr_), fmt::arg("cidr", cidr_),
fmt::arg("icon", getIcon(signal_strength_, connectiontype)) fmt::arg("icon", getIcon(signal_strength_, connectiontype))
)); );
label_.set_markup(text);
if (tooltipEnabled()) {
if (!tooltip_format.empty()) {
auto tooltip_text = fmt::format(tooltip_format,
fmt::arg("essid", essid_),
fmt::arg("signaldBm", signal_strength_dbm_),
fmt::arg("signalStrength", signal_strength_),
fmt::arg("ifname", ifname_),
fmt::arg("netmask", netmask_),
fmt::arg("ipaddr", ipaddr_),
fmt::arg("cidr", cidr_),
fmt::arg("icon", getIcon(signal_strength_, connectiontype))
);
label_.set_tooltip_text(tooltip_text);
} else {
label_.set_tooltip_text(text);
}
}
} }
void waybar::modules::Network::disconnected() void waybar::modules::Network::disconnected()
@ -346,7 +371,7 @@ int waybar::modules::Network::netlinkRequest(void *req,
sa.nl_groups = groups; sa.nl_groups = groups;
struct iovec iov = { req, reqlen }; struct iovec iov = { req, reqlen };
struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 }; struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 };
return sendmsg(nl_socket_get_fd(info_sock_), &msg, 0); return sendmsg(info_sock_, &msg, 0);
} }
int waybar::modules::Network::netlinkResponse(void *resp, int waybar::modules::Network::netlinkResponse(void *resp,
@ -357,53 +382,64 @@ int waybar::modules::Network::netlinkResponse(void *resp,
sa.nl_groups = groups; sa.nl_groups = groups;
struct iovec iov = { resp, resplen }; struct iovec iov = { resp, resplen };
struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 }; struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 };
auto ret = recvmsg(nl_socket_get_fd(info_sock_), &msg, 0); auto ret = recvmsg(info_sock_, &msg, 0);
if (msg.msg_flags & MSG_TRUNC) { if (msg.msg_flags & MSG_TRUNC) {
return -1; return -1;
} }
return ret; return ret;
} }
int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { void waybar::modules::Network::handleEvents() {
auto net = static_cast<waybar::modules::Network *>(data); struct sockaddr_nl addr;
bool need_update = false; char buff[2048] = {0};
nlmsghdr *nh = nlmsg_hdr(msg); socklen_t len = 0;
if (nh->nlmsg_type == RTM_NEWADDR) {
need_update = true; while (true) {
} len = sizeof(addr);
if (nh->nlmsg_type < RTM_NEWADDR) { auto ret = recvfrom(info_sock_, (void *)buff, sizeof(buff), 0,
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh)); (struct sockaddr *)&addr, &len);
if (rtif->ifi_index == static_cast<int>(net->ifid_)) { auto nh = (struct nlmsghdr *)buff;
need_update = true; for(; NLMSG_OK(nh, ret); nh = NLMSG_NEXT(nh, ret)) {
if (!(rtif->ifi_flags & IFF_RUNNING)) { bool need_update = false;
net->disconnected(); if (nh->nlmsg_type == RTM_NEWADDR) {
net->dp.emit(); need_update = true;
} }
} if (nh->nlmsg_type < RTM_NEWADDR) {
} auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
if (net->ifid_ <= 0 && !net->config_["interface"].isString()) { if (rtif->ifi_index == static_cast<int>(ifid_)) {
for (uint8_t i = 0; i < MAX_RETRY; i += 1) { need_update = true;
net->ifid_ = net->getExternalInterface(); if (!(rtif->ifi_flags & IFF_RUNNING)) {
if (net->ifid_ > 0) { disconnected();
break; dp.emit();
return;
}
}
} }
// Need to wait before get external interface if (ifid_ <= 0 && !config_["interface"].isString()) {
net->thread_.sleep_for(std::chrono::seconds(1)); for (uint8_t i = 0; i < MAX_RETRY; i += 1) {
} ifid_ = getExternalInterface();
if (net->ifid_ > 0) { if (ifid_ > 0) {
char ifname[IF_NAMESIZE]; break;
if_indextoname(net->ifid_, ifname); }
net->ifname_ = ifname; // Need to wait before get external interface
need_update = true; thread_.sleep_for(std::chrono::seconds(1));
}
if (ifid_ > 0) {
char ifname[IF_NAMESIZE];
if_indextoname(ifid_, ifname);
ifname_ = ifname;
need_update = true;
}
}
if (need_update) {
if (ifid_ > 0) {
getInfo();
}
dp.emit();
}
break;
} }
} }
if (need_update) {
if (net->ifid_ > 0) {
net->getInfo();
}
net->dp.emit();
}
return NL_SKIP;
} }
int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) { int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) {

View File

@ -1,4 +1,5 @@
#include "modules/pulseaudio.hpp" #include "modules/pulseaudio.hpp"
#include <array>
waybar::modules::Pulseaudio::Pulseaudio(const std::string& id, const Json::Value &config) waybar::modules::Pulseaudio::Pulseaudio(const std::string& id, const Json::Value &config)
: ALabel(config, "{volume}%"), : ALabel(config, "{volume}%"),
@ -63,13 +64,13 @@ void waybar::modules::Pulseaudio::contextStateCb(pa_context *c, void *data)
pa_context_set_subscribe_callback(c, subscribeCb, data); pa_context_set_subscribe_callback(c, subscribeCb, data);
pa_context_subscribe(c, PA_SUBSCRIPTION_MASK_SINK, nullptr, nullptr); pa_context_subscribe(c, PA_SUBSCRIPTION_MASK_SINK, nullptr, nullptr);
break; break;
case PA_CONTEXT_FAILED:
pa->mainloop_api_->quit(pa->mainloop_api_, 1);
break;
case PA_CONTEXT_CONNECTING: case PA_CONTEXT_CONNECTING:
case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_AUTHORIZING:
case PA_CONTEXT_SETTING_NAME: case PA_CONTEXT_SETTING_NAME:
break;
case PA_CONTEXT_FAILED:
default: default:
pa->mainloop_api_->quit(pa->mainloop_api_, 1);
break; break;
} }
} }
@ -174,21 +175,24 @@ void waybar::modules::Pulseaudio::serverInfoCb(pa_context *context,
sinkInfoCb, data); sinkInfoCb, data);
} }
static const std::array<std::string, 9> ports = {
"headphones",
"speaker",
"hdmi",
"headset",
"handsfree",
"portable",
"car",
"hifi",
"phone",
};
const std::string waybar::modules::Pulseaudio::getPortIcon() const const std::string waybar::modules::Pulseaudio::getPortIcon() const
{ {
std::vector<std::string> ports = { std::string nameLC = port_name_;
"headphones", std::transform(nameLC.begin(), nameLC.end(), nameLC.begin(), ::tolower);
"speaker",
"hdmi",
"headset",
"handsfree",
"portable",
"car",
"hifi",
"phone",
};
for (auto const& port : ports) { for (auto const& port : ports) {
if (port_name_.find(port) != std::string::npos) { if (nameLC.find(port) != std::string::npos) {
return port; return port;
} }
} }

View File

@ -64,7 +64,7 @@ struct waybar::modules::sway::Ipc::ipc_response
waybar::modules::sway::Ipc::recv(int fd) const waybar::modules::sway::Ipc::recv(int fd) const
{ {
std::string header; std::string header;
header.reserve(ipc_header_size_); header.resize(ipc_header_size_);
auto data32 = reinterpret_cast<uint32_t *>(header.data() + ipc_magic_.size()); auto data32 = reinterpret_cast<uint32_t *>(header.data() + ipc_magic_.size());
size_t total = 0; size_t total = 0;
@ -83,7 +83,7 @@ struct waybar::modules::sway::Ipc::ipc_response
total = 0; total = 0;
std::string payload; std::string payload;
payload.reserve(data32[0] + 1); payload.resize(data32[0]);
while (total < data32[0]) { while (total < data32[0]) {
auto res = ::recv(fd, payload.data() + total, data32[0] - total, 0); auto res = ::recv(fd, payload.data() + total, data32[0] - total, 0);
if (res < 0) { if (res < 0) {
@ -91,7 +91,6 @@ struct waybar::modules::sway::Ipc::ipc_response
} }
total += res; total += res;
} }
payload[data32[0]] = 0;
return { data32[0], data32[1], &payload.front() }; return { data32[0], data32[1], &payload.front() };
} }
@ -100,7 +99,7 @@ struct waybar::modules::sway::Ipc::ipc_response
const std::string& payload) const const std::string& payload) const
{ {
std::string header; std::string header;
header.reserve(ipc_header_size_); header.resize(ipc_header_size_);
auto data32 = reinterpret_cast<uint32_t *>(header.data() + ipc_magic_.size()); auto data32 = reinterpret_cast<uint32_t *>(header.data() + ipc_magic_.size());
memcpy(header.data(), ipc_magic_.c_str(), ipc_magic_.size()); memcpy(header.data(), ipc_magic_.c_str(), ipc_magic_.size());
data32[0] = payload.size(); data32[0] = payload.size();

View File

@ -87,7 +87,7 @@ auto waybar::modules::sway::Workspaces::update() -> void
} else { } else {
button.set_label(icon); button.set_label(icon);
} }
button.show(); onButtonReady(node, button);
} }
} }
if (scrolling_) { if (scrolling_) {
@ -116,8 +116,8 @@ void waybar::modules::sway::Workspaces::addWorkspace(const Json::Value &node)
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
} }
}); });
button.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
if (!config_["disable-scroll"].asBool()) { if (!config_["disable-scroll"].asBool()) {
button.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
button.signal_scroll_event() button.signal_scroll_event()
.connect(sigc::mem_fun(*this, &Workspaces::handleScroll)); .connect(sigc::mem_fun(*this, &Workspaces::handleScroll));
} }
@ -131,7 +131,8 @@ void waybar::modules::sway::Workspaces::addWorkspace(const Json::Value &node)
if (node["urgent"].asBool()) { if (node["urgent"].asBool()) {
button.get_style_context()->add_class("urgent"); button.get_style_context()->add_class("urgent");
} }
button.show();
onButtonReady(node, button);
} }
std::string waybar::modules::sway::Workspaces::getIcon(const std::string &name, std::string waybar::modules::sway::Workspaces::getIcon(const std::string &name,
@ -156,86 +157,78 @@ bool waybar::modules::sway::Workspaces::handleScroll(GdkEventScroll *e)
if (scrolling_) { if (scrolling_) {
return false; return false;
} }
std::lock_guard<std::mutex> lock(mutex_);
uint8_t idx;
scrolling_ = true; scrolling_ = true;
std::string name; for (idx = 0; idx < workspaces_.size(); idx += 1) {
uint16_t idx = 0; if (workspaces_[idx]["focused"].asBool()) {
{ break;
std::lock_guard<std::mutex> lock(mutex_);
for (; idx < workspaces_.size(); idx += 1) {
if (workspaces_[idx]["focused"].asBool()) {
name = workspaces_[idx]["name"].asString();
break;
}
} }
} }
if (name.empty()) { if (idx == workspaces_.size()) {
scrolling_ = false; scrolling_ = false;
return false; return false;
} }
std::string name;
if (e->direction == GDK_SCROLL_UP) { if (e->direction == GDK_SCROLL_UP) {
name = getNextWorkspace(); name = getCycleWorkspace(idx, false);
} }
if (e->direction == GDK_SCROLL_DOWN) { if (e->direction == GDK_SCROLL_DOWN) {
name = getPrevWorkspace(); name = getCycleWorkspace(idx, true);
} }
if (e->direction == GDK_SCROLL_SMOOTH) { if (e->direction == GDK_SCROLL_SMOOTH) {
gdouble delta_x, delta_y; gdouble delta_x, delta_y;
gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent *>(e), gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent *>(e),
&delta_x, &delta_y); &delta_x, &delta_y);
if (delta_y < 0) { if (delta_y < 0) {
name = getNextWorkspace(); name = getCycleWorkspace(idx, false);
} else if (delta_y > 0) { } else if (delta_y > 0) {
name = getPrevWorkspace(); name = getCycleWorkspace(idx, true);
} }
} }
if (!name.empty()) { if (name.empty() || name == workspaces_[idx]["name"].asString()) {
std::lock_guard<std::mutex> lock(mutex_); scrolling_ = false;
if (name == workspaces_[idx]["name"].asString()) { return false;
scrolling_ = false;
return false;
}
ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace \"{}\"", name));
std::this_thread::sleep_for(std::chrono::milliseconds(150));
} }
ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace \"{}\"", name));
std::this_thread::sleep_for(std::chrono::milliseconds(150));
return true; return true;
} }
std::string waybar::modules::sway::Workspaces::getPrevWorkspace() const std::string waybar::modules::sway::Workspaces::getCycleWorkspace(
uint8_t focused_workspace, bool prev) const
{ {
for (uint16_t i = 0; i < workspaces_.size(); i += 1) { auto inc = prev ? -1 : 1;
if (workspaces_[i]["focused"].asBool()) { int size = workspaces_.size();
if (i > 0) { uint8_t idx = 0;
return workspaces_[i - 1]["name"].asString(); for (int i = focused_workspace; i < size && i >= 0; i += inc) {
} bool same_output = (workspaces_[i]["output"].asString() == bar_.output_name
return workspaces_[workspaces_.size() - 1]["name"].asString(); && !config_["all-outputs"].asBool()) || config_["all-outputs"].asBool();
bool same_name =
workspaces_[i]["name"].asString() == workspaces_[focused_workspace]["name"].asString();
if (same_output && !same_name) {
return workspaces_[i]["name"].asString();
} }
if (prev && i - 1 < 0) {
i = size;
} else if (!prev && i + 1 >= size) {
i = -1;
} else if (idx >= workspaces_.size()) {
return "";
}
idx += 1;
} }
return ""; return "";
} }
std::string waybar::modules::sway::Workspaces::getNextWorkspace() uint16_t waybar::modules::sway::Workspaces::getWorkspaceIndex(const std::string &name) const
{
for (uint16_t i = 0; i < workspaces_.size(); i += 1) {
if (workspaces_[i]["focused"].asBool()) {
if (i + 1U < workspaces_.size()) {
return workspaces_[i + 1]["name"].asString();
}
return workspaces_[0]["String"].asString();
}
}
return "";
}
uint16_t waybar::modules::sway::Workspaces::getWorkspaceIndex(const std::string &name)
{ {
uint16_t idx = 0; uint16_t idx = 0;
for (const auto &workspace : workspaces_) { for (const auto &workspace : workspaces_) {
if (workspace["name"].asString() == name) { if (workspace["name"].asString() == name) {
return idx; return idx;
} }
if (!config_["all-outputs"].asBool() && workspace["output"].asString() != bar_.output_name) { if (!(!config_["all-outputs"].asBool() && workspace["output"].asString() != bar_.output_name)) {
// Nothing here
} else {
idx += 1; idx += 1;
} }
} }
@ -251,6 +244,19 @@ std::string waybar::modules::sway::Workspaces::trimWorkspaceName(std::string nam
return name; return name;
} }
void waybar::modules::sway::Workspaces::onButtonReady(const Json::Value& node, Gtk::Button& button)
{
if (config_["current-only"].asBool()) {
if (node["focused"].asBool()) {
button.show();
} else {
button.hide();
}
} else {
button.show();
}
}
waybar::modules::sway::Workspaces::operator Gtk::Widget &() { waybar::modules::sway::Workspaces::operator Gtk::Widget &() {
return box_; return box_;
} }

View File

@ -0,0 +1,60 @@
#include "modules/temperature.hpp"
waybar::modules::Temperature::Temperature(const std::string& id, const Json::Value& config)
: ALabel(config, "{temperatureC}°C", 10)
{
if (config_["hwmon-path"].isString()) {
file_path_ = config_["hwmon-path"].asString();
} else {
auto zone =
config_["thermal-zone"].isInt() ? config_["thermal-zone"].asInt() : 0;
file_path_ = fmt::format("/sys/class/thermal/thermal_zone{}/temp", zone);
}
label_.set_name("temperature");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
thread_ = [this] {
dp.emit();
thread_.sleep_for(interval_);
};
}
auto waybar::modules::Temperature::update() -> void
{
auto [temperature_c, temperature_f] = getTemperature();
auto critical = isCritical(temperature_c);
auto format = format_;
if (critical) {
format =
config_["format-critical"].isString() ? config_["format-critical"].asString() : format;
label_.get_style_context()->add_class("critical");
} else {
label_.get_style_context()->remove_class("critical");
}
label_.set_markup(fmt::format(format,
fmt::arg("temperatureC", temperature_c), fmt::arg("temperatureF", temperature_f)));
}
std::tuple<uint16_t, uint16_t> waybar::modules::Temperature::getTemperature()
{
std::ifstream temp(file_path_);
if (!temp.is_open()) {
throw std::runtime_error("Can't open " + file_path_);
}
std::string line;
if (temp.good()) {
getline(temp, line);
}
temp.close();
auto temperature_c = std::strtol(line.c_str(), nullptr, 10) / 1000.0;
auto temperature_f = temperature_c * 1.8 + 32;
std::tuple<uint16_t, uint16_t> temperatures(std::round(temperature_c), std::round(temperature_f));
return temperatures;
}
bool waybar::modules::Temperature::isCritical(uint16_t temperature_c)
{
return config_["critical-threshold"].isInt() && temperature_c >= config_["critical-threshold"].asInt();
}