Compare commits

..

36 Commits
0.1.3 ... 0.2.0

Author SHA1 Message Date
43cd80fb31 chore: 0.2.0 2018-11-03 13:20:05 +01:00
5ece0d98ee Merge pull request #78 from mithodin/filesystem-experimental
add option for when filesystem still lives in the experimental namespace
2018-11-03 13:00:04 +01:00
0637888460 even simpler check 2018-11-03 12:44:15 +01:00
ebbdaa168c automatically detect where filesystem lives 2018-11-02 23:15:42 +01:00
6ab01b1ad4 fix(style): not charging 2018-11-02 23:00:38 +01:00
cf921a5e14 Merge pull request #76 from mithodin/charging-full
Add class for full battery and give option to interpret unknown as full
2018-11-02 22:51:57 +01:00
25f31b19f6 formatting is hard. 2018-11-02 22:50:01 +01:00
d8b6201632 ...and fix the function signature in the header 2018-11-02 22:15:54 +01:00
123ce083b4 fix typo and initialize old_status_ 2018-11-02 22:08:55 +01:00
0522577fe5 make status and state fully configurable formats 2018-11-02 22:04:43 +01:00
1ff9fd06af Merge pull request #77 from mithodin/old-gdbus-codegen
fix compilation on systems with old gdbus-codegen
2018-11-02 21:23:10 +01:00
b6cad05489 fix formatting 2018-11-02 21:13:57 +01:00
236be90c2f add option for when filesystem still lives in the experimental namespace 2018-11-02 20:59:41 +01:00
f137090d55 fix compilation on systems with old gdbus-codegen 2018-11-02 20:13:09 +01:00
9c57df505c Add class for full battery and give option to interpret unknown as full 2018-11-02 19:41:00 +01:00
00e7e87f55 fix: style 2018-11-02 17:39:00 +01:00
836c543c62 fix: style 2018-11-02 17:07:51 +01:00
7bca5fd6bd feat(Bar): add a warning about minimum height 2018-11-02 12:35:26 +01:00
61e9f0803d Merge pull request #75 from ForTheReallys/proper_height
Fix #54
2018-11-02 12:26:14 +01:00
9b201c77d7 feat: battery states && format-full/charging 2018-11-02 11:23:29 +01:00
4b68840212 Fix #54 2018-11-01 16:00:38 -05:00
9d4048983d refactor: remove useless tmp variable 2018-11-01 09:27:00 +01:00
0670225e69 Merge pull request #72 from Robinhuett/custom_module_states
Custom modules can control tooltip and CSS class
2018-11-01 09:11:15 +01:00
e23fbd0add Added return-type json to custom module 2018-11-01 00:40:44 +01:00
341d3300fa Custom modules can control tooltip and CSS class 2018-10-30 21:28:31 +01:00
c3e185546d Merge pull request #68 from harishkrupo/master
Add configuration options for widgets on mouse events
2018-10-30 16:32:37 +01:00
0e93de9c0a Merge pull request #71 from Robinhuett/configurable_battery_levels
Added second warning stage to battery module
2018-10-30 16:31:01 +01:00
3e34137ac7 pulseaudio: Change volume on scroll event
Subscribe for mouse scroll events on the pulseaudio widget
and change volume when event is received.
Scroll up increments the volume and scroll down decrements it.
These events are only subscibed when there are no user defined
commands present for them.

Signed-off-by: Harish Krupo <harishkrupo@gmail.com>
2018-10-30 20:53:43 +05:30
4c8621c7a5 Added second warning stage to battery module
Also naming is a bit more consistent
2018-10-30 16:23:36 +01:00
d7d1ebd736 ALabel: Add support for configurable mouse events
This patch adds 3 new configuration options applicable for
subclasses of ALabel. The options can be used to execute
user defined code in response to the 3 mouse events:
* on-click: The left mouse button click
* on-scroll-up
* on-scroll-down
This patch also modifies the behaviour of the format-alt toggle
such that when the on-click event is configured, format-alt is
toggled on any mouse click other than left click. When on-click
is not defined, any mouse button would toggle format-alt.

Signed-off-by: Harish Krupo <harishkrupo@gmail.com>
2018-10-30 20:52:23 +05:30
e93c5e7957 Merge pull request #70 from Robinhuett/mode_module
Add module to show sway binding mode
2018-10-30 14:26:43 +01:00
668b7b736c Added default config for sway binding mode 2018-10-30 13:44:44 +01:00
a042eea384 Add module to show sway binding mode 2018-10-30 13:39:30 +01:00
c9a8a07976 fix(window): title on new workspace 2018-10-29 21:52:53 +01:00
4307e4fd8e chore: upgrade fmt to 5.2.0 2018-10-28 14:40:25 +01:00
daf613f8ca feat: add debug about tray beta 2018-10-28 08:43:48 +01:00
26 changed files with 539 additions and 119 deletions

2
.gitignore vendored
View File

@ -4,7 +4,7 @@ vgcore.*
/.vscode /.vscode
*.swp *.swp
packagecache packagecache
/subprojects/fmt-4.1.0 /subprojects/**/
/build /build
/dist /dist
/meson.egg-info /meson.egg-info

View File

@ -12,15 +12,19 @@ class ALabel : public IModule {
virtual auto update() -> void; virtual auto update() -> void;
virtual std::string getIcon(uint16_t, const std::string& alt = ""); virtual std::string getIcon(uint16_t, const std::string& alt = "");
virtual operator Gtk::Widget&(); virtual operator Gtk::Widget&();
protected: protected:
Gtk::EventBox event_box_; Gtk::EventBox event_box_;
Gtk::Label label_; Gtk::Label label_;
const Json::Value& config_; const Json::Value& config_;
std::string format_; std::string format_;
std::mutex mutex_;
private: private:
bool handleToggle(GdkEventButton* const& ev); bool handleToggle(GdkEventButton* const& ev);
bool handleScroll(GdkEventScroll*);
bool alt = false; bool alt = false;
const std::string default_format_; const std::string default_format_;
}; };
} } // namespace waybar

View File

@ -3,6 +3,7 @@
#include <json/json.h> #include <json/json.h>
#include "modules/clock.hpp" #include "modules/clock.hpp"
#ifdef HAVE_SWAY #ifdef HAVE_SWAY
#include "modules/sway/mode.hpp"
#include "modules/sway/workspaces.hpp" #include "modules/sway/workspaces.hpp"
#include "modules/sway/window.hpp" #include "modules/sway/window.hpp"
#endif #endif

View File

@ -1,6 +1,10 @@
#pragma once #pragma once
#ifdef FILESYSTEM_EXPERIMENTAL
#include <experimental/filesystem>
#else
#include <filesystem> #include <filesystem>
#endif
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <fmt/format.h> #include <fmt/format.h>
@ -11,7 +15,11 @@
namespace waybar::modules { namespace waybar::modules {
#ifdef FILESYSTEM_EXPERIMENTAL
namespace fs = std::experimental::filesystem;
#else
namespace fs = std::filesystem; namespace fs = std::filesystem;
#endif
class Battery : public ALabel { class Battery : public ALabel {
public: public:
@ -22,11 +30,14 @@ class Battery : public ALabel {
static inline const fs::path data_dir_ = "/sys/class/power_supply/"; static inline const fs::path data_dir_ = "/sys/class/power_supply/";
void worker(); void worker();
std::tuple<uint16_t, std::string> getInfos();
std::string getState(uint16_t);
util::SleeperThread thread_; util::SleeperThread thread_;
util::SleeperThread threadTimer_; util::SleeperThread threadTimer_;
std::vector<fs::path> batteries_; std::vector<fs::path> batteries_;
int fd_; int fd_;
std::string old_status_;
}; };
} }

View File

@ -4,6 +4,7 @@
#include <iostream> #include <iostream>
#include "util/chrono.hpp" #include "util/chrono.hpp"
#include "util/command.hpp" #include "util/command.hpp"
#include "util/json.hpp"
#include "ALabel.hpp" #include "ALabel.hpp"
namespace waybar::modules { namespace waybar::modules {
@ -15,10 +16,17 @@ class Custom : public ALabel {
private: private:
void delayWorker(); void delayWorker();
void continuousWorker(); void continuousWorker();
void parseOutputRaw();
void parseOutputJson();
const std::string name_; const std::string name_;
std::string text_;
std::string tooltip_;
std::string class_;
std::string prevclass_;
waybar::util::SleeperThread thread_; waybar::util::SleeperThread thread_;
waybar::util::command::res output_; waybar::util::command::res output_;
waybar::util::JsonParser parser_;
}; };
} }

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
#include <pulse/pulseaudio.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <pulse/pulseaudio.h>
#include <pulse/volume.h>
#include <algorithm> #include <algorithm>
#include "ALabel.hpp" #include "ALabel.hpp"
@ -18,6 +19,8 @@ class Pulseaudio : public ALabel {
static void contextStateCb(pa_context*, void*); static void contextStateCb(pa_context*, void*);
static void sinkInfoCb(pa_context*, const pa_sink_info*, int, void*); static void sinkInfoCb(pa_context*, const pa_sink_info*, int, void*);
static void serverInfoCb(pa_context*, const pa_server_info*, void*); static void serverInfoCb(pa_context*, const pa_server_info*, void*);
static void volumeModifyCb(pa_context*, int, void*);
bool handleScroll(GdkEventScroll* e);
const std::string getPortIcon() const; const std::string getPortIcon() const;
@ -26,9 +29,11 @@ class Pulseaudio : public ALabel {
pa_context* context_; pa_context* context_;
uint32_t sink_idx_{0}; uint32_t sink_idx_{0};
uint16_t volume_; uint16_t volume_;
pa_cvolume pa_volume_;
bool muted_; bool muted_;
std::string port_name_; std::string port_name_;
std::string desc_; std::string desc_;
bool scrolling_;
}; };
} } // namespace waybar::modules

View File

@ -3,7 +3,11 @@
#include <dbus-status-notifier-item.h> #include <dbus-status-notifier-item.h>
#include <gtkmm.h> #include <gtkmm.h>
#include <json/json.h> #include <json/json.h>
#ifdef FILESYSTEM_EXPERIMENTAL
#include <experimental/filesystem>
#else
#include <filesystem> #include <filesystem>
#endif
namespace waybar::modules::SNI { namespace waybar::modules::SNI {

View File

@ -0,0 +1,27 @@
#pragma once
#include <fmt/format.h>
#include "bar.hpp"
#include "client.hpp"
#include "util/chrono.hpp"
#include "util/json.hpp"
#include "ALabel.hpp"
#include "modules/sway/ipc/client.hpp"
namespace waybar::modules::sway {
class Mode : public ALabel {
public:
Mode(waybar::Bar&, const Json::Value&);
auto update() -> void;
private:
void worker();
Bar& bar_;
waybar::util::SleeperThread thread_;
util::JsonParser parser_;
Ipc ipc_;
std::string mode_;
};
}

View File

@ -32,4 +32,20 @@ inline struct res exec(const std::string cmd)
return {exit_code, output}; return {exit_code, output};
} }
inline bool forkExec(std::string cmd) {
if (cmd == "") return true;
int32_t pid = fork();
if (pid < 0) {
printf("Unable to exec cmd %s, error %s", cmd.c_str(), strerror(errno));
return false;
} }
// Child executes the command
if (!pid) execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
return true;
}
} // namespace waybar::util::command

View File

@ -1,6 +1,6 @@
project( project(
'waybar', 'cpp', 'c', 'waybar', 'cpp', 'c',
version: '0.1.3', version: '0.2.0',
license: 'MIT', license: 'MIT',
default_options : [ default_options : [
'cpp_std=c++17', 'cpp_std=c++17',
@ -57,6 +57,7 @@ if find_program('sway', required : false).found()
add_project_arguments('-DHAVE_SWAY', language: 'cpp') add_project_arguments('-DHAVE_SWAY', language: 'cpp')
src_files += [ src_files += [
'src/modules/sway/ipc/client.cpp', 'src/modules/sway/ipc/client.cpp',
'src/modules/sway/mode.cpp',
'src/modules/sway/window.cpp', 'src/modules/sway/window.cpp',
'src/modules/sway/workspaces.cpp' 'src/modules/sway/workspaces.cpp'
] ]
@ -82,6 +83,12 @@ if dbusmenu_gtk.found()
) )
endif endif
compiler = meson.get_compiler('cpp')
if not compiler.has_header('filesystem')
add_project_arguments('-DFILESYSTEM_EXPERIMENTAL', language: 'cpp')
endif
subdir('protocol') subdir('protocol')
executable( executable(

View File

@ -38,6 +38,36 @@ endforeach
gdbus_codegen = find_program('gdbus-codegen') gdbus_codegen = find_program('gdbus-codegen')
r = run_command(gdbus_codegen, '--body', '--output', '/dev/null')
if r.returncode() != 0
gdbus_code_dsnw = custom_target(
'dbus-status-notifier-watcher.[ch]',
output: ['@BASENAME@.c','@BASENAME@.h'],
input: './dbus-status-notifier-watcher.xml',
command: [gdbus_codegen,'--c-namespace', 'Sn', '--generate-c-code', 'protocol/@BASENAME@', '@INPUT@'],
)
gdbus_code_dsni = custom_target(
'dbus-status-notifier-item.[ch]',
output: ['@BASENAME@.c','@BASENAME@.h'],
input: './dbus-status-notifier-item.xml',
command: [gdbus_codegen,'--c-namespace', 'Sn', '--generate-c-code', 'protocol/@BASENAME@', '@INPUT@'],
)
gdbus_code_dm = custom_target(
'dbus-menu.[ch]',
output: ['@BASENAME@.c','@BASENAME@.h'],
input: './dbus-menu.xml',
command: [gdbus_codegen,'--c-namespace', 'Sn', '--generate-c-code', 'protocol/@BASENAME@', '@INPUT@'],
)
client_protos_src += gdbus_code_dsnw[0]
client_protos_headers += gdbus_code_dsnw[1]
client_protos_src += gdbus_code_dsni[0]
client_protos_headers += gdbus_code_dsni[1]
client_protos_src += gdbus_code_dm[0]
client_protos_headers += gdbus_code_dm[1]
else
gdbus_code = generator( gdbus_code = generator(
gdbus_codegen, gdbus_codegen,
output: '@BASENAME@.c', output: '@BASENAME@.c',
@ -58,6 +88,8 @@ client_protos_headers += gdbus_header.process('./dbus-status-notifier-item.xml')
client_protos_src += gdbus_code.process('./dbus-menu.xml') client_protos_src += gdbus_code.process('./dbus-menu.xml')
client_protos_headers += gdbus_header.process('./dbus-menu.xml') client_protos_headers += gdbus_header.process('./dbus-menu.xml')
endif
lib_client_protos = static_library( lib_client_protos = static_library(
'client_protos', 'client_protos',

View File

@ -4,7 +4,7 @@
// "height": 30, // Waybar height // "height": 30, // Waybar height
// "width": 1280, // Waybar width // "width": 1280, // Waybar width
// Choose the order of the modules // Choose the order of the modules
"modules-left": ["sway/workspaces", "custom/spotify"], "modules-left": ["sway/workspaces", "sway/mode", "custom/spotify"],
"modules-center": ["sway/window"], "modules-center": ["sway/window"],
"modules-right": ["pulseaudio", "network", "cpu", "memory", "battery", "battery#bat2", "clock", "tray"], "modules-right": ["pulseaudio", "network", "cpu", "memory", "battery", "battery#bat2", "clock", "tray"],
// Modules configuration // Modules configuration
@ -23,6 +23,9 @@
// "default": "" // "default": ""
// } // }
// }, // },
"sway/mode": {
"format": "{}"
},
"sway/window": { "sway/window": {
"max-length": 50 "max-length": 50
}, },
@ -40,7 +43,14 @@
"format": "{}% " "format": "{}% "
}, },
"battery": { "battery": {
"states": {
// "good": 95,
"warning": 30,
"critical": 15
},
"format": "{capacity}% {icon}", "format": "{capacity}% {icon}",
// "format-good": "", // An empty format will hide the module
// "format-full": "",
"format-icons": ["", "", "", "", ""] "format-icons": ["", "", "", "", ""]
}, },
"battery#bat2": { "battery#bat2": {
@ -64,13 +74,14 @@
"portable": "", "portable": "",
"car": "", "car": "",
"default": ["", ""] "default": ["", ""]
} },
"on-click": "pavucontrol"
}, },
"custom/spotify": { "custom/spotify": {
"format": " {}", "format": " {}",
"max-length": 40, "max-length": 40,
"interval": 30, // Remove this if your script is endless and write in loop "interval": 30, // Remove this if your script is endless and write in loop
"exec": "$HOME/.config/waybar/mediaplayer.sh", // Script in resources folder "exec": "$HOME/.config/waybar/mediaplayer.sh 2> /dev/null", // Script in resources folder
"exec-if": "pgrep spotify" "exec-if": "pgrep spotify"
} }
} }

View File

@ -3,6 +3,7 @@
border-radius: 0; border-radius: 0;
font-family: Roboto, Helvetica, Arial, sans-serif; font-family: Roboto, Helvetica, Arial, sans-serif;
font-size: 13px; font-size: 13px;
min-height: 0;
} }
window#waybar { window#waybar {
@ -23,7 +24,12 @@ window#waybar {
border-bottom: 3px solid white; border-bottom: 3px solid white;
} }
#clock, #battery, #cpu, #memory, #network, #pulseaudio, #custom-spotify, #tray { #mode {
background: #64727D;
border-bottom: 3px solid white;
}
#clock, #battery, #cpu, #memory, #network, #pulseaudio, #custom-spotify, #tray, #mode {
padding: 0 10px; padding: 0 10px;
margin: 0 5px; margin: 0 5px;
} }
@ -49,7 +55,7 @@ window#waybar {
} }
} }
#battery.warning { #battery.warning:not(.charging) {
background: #f53c3c; background: #f53c3c;
color: white; color: white;
animation-name: blink; animation-name: blink;

View File

@ -1,4 +1,5 @@
#include "ALabel.hpp" #include "ALabel.hpp"
#include <util/command.hpp>
#include <iostream> #include <iostream>
@ -14,30 +15,81 @@ waybar::ALabel::ALabel(const Json::Value& config, const std::string format)
} }
if (config_["format-alt"].isString()) { if (config_["format-alt"].isString()) {
event_box_.add_events(Gdk::BUTTON_PRESS_MASK); event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
event_box_.signal_button_press_event() event_box_.signal_button_press_event().connect(
.connect(sigc::mem_fun(*this, &ALabel::handleToggle)); sigc::mem_fun(*this, &ALabel::handleToggle));
}
// configure events' user commands
if (config_["on-click"].isString()) {
event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
event_box_.signal_button_press_event().connect(
sigc::mem_fun(*this, &ALabel::handleToggle));
}
if (config_["on-scroll-up"].isString()) {
event_box_.add_events(Gdk::SCROLL_MASK);
event_box_.signal_scroll_event().connect(
sigc::mem_fun(*this, &ALabel::handleScroll));
}
if (config_["on-scroll-down"].isString()) {
event_box_.add_events(Gdk::SCROLL_MASK);
event_box_.signal_scroll_event().connect(
sigc::mem_fun(*this, &ALabel::handleScroll));
} }
} }
auto waybar::ALabel::update() -> void auto waybar::ALabel::update() -> void {
{
// Nothing here // Nothing here
} }
bool waybar::ALabel::handleToggle(GdkEventButton* const& /*ev*/) bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
{ if (config_["on-click"].isString() && e->button == 1) {
waybar::util::command::forkExec(config_["on-click"].asString());
} else {
alt = !alt; alt = !alt;
if (alt) { if (alt) {
format_ = config_["format-alt"].asString(); format_ = config_["format-alt"].asString();
} else { } else {
format_ = default_format_; format_ = default_format_;
} }
}
dp.emit(); dp.emit();
return true; return true;
} }
std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt) bool waybar::ALabel::handleScroll(GdkEventScroll* e) {
{
// Avoid concurrent scroll event
std::lock_guard<std::mutex> lock(mutex_);
bool direction_up = false;
if (e->direction == GDK_SCROLL_UP) {
direction_up = true;
}
if (e->direction == GDK_SCROLL_DOWN) {
direction_up = false;
}
if (e->direction == GDK_SCROLL_SMOOTH) {
gdouble delta_x, delta_y;
gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent*>(e),
&delta_x, &delta_y);
if (delta_y < 0) {
direction_up = true;
} else if (delta_y > 0) {
direction_up = false;
}
}
if (direction_up && config_["on-scroll-up"].isString()) {
waybar::util::command::forkExec(config_["on-scroll-up"].asString());
} else if (config_["on-scroll-down"].isString()) {
waybar::util::command::forkExec(config_["on-scroll-down"].asString());
}
dp.emit();
return true;
}
std::string waybar::ALabel::getIcon(uint16_t percentage,
const std::string& alt) {
auto format_icons = config_["format-icons"]; auto format_icons = config_["format-icons"];
if (format_icons.isObject()) { if (format_icons.isObject()) {
if (!alt.empty() && format_icons[alt].isString()) { if (!alt.empty() && format_icons[alt].isString()) {
@ -57,6 +109,4 @@ std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt)
return ""; return "";
} }
waybar::ALabel::operator Gtk::Widget &() { waybar::ALabel::operator Gtk::Widget&() { return event_box_; }
return event_box_;
}

View File

@ -20,16 +20,15 @@ waybar::Bar::Bar(const Client& client,
zxdg_output_manager_v1_get_xdg_output(client.xdg_output_manager, *output); zxdg_output_manager_v1_get_xdg_output(client.xdg_output_manager, *output);
zxdg_output_v1_add_listener(xdg_output_, &xdgOutputListener, this); zxdg_output_v1_add_listener(xdg_output_, &xdgOutputListener, this);
window.set_title("waybar"); window.set_title("waybar");
window.set_decorated(false);
window.set_name("waybar"); window.set_name("waybar");
window.set_decorated(false);
window.set_resizable(false); window.set_resizable(false);
setupConfig(); setupConfig();
setupCss(); setupCss();
setupWidgets();
Gtk::Widget& wrap(window); auto wrap = reinterpret_cast<GtkWidget*>(window.gobj());
gtk_widget_realize(wrap.gobj()); gtk_widget_realize(wrap);
GdkWindow *gdk_window = gtk_widget_get_window(wrap.gobj()); GdkWindow *gdk_window = gtk_widget_get_window(wrap);
gdk_wayland_window_set_use_custom_surface(gdk_window); gdk_wayland_window_set_use_custom_surface(gdk_window);
surface = gdk_wayland_window_get_wl_surface(gdk_window); surface = gdk_wayland_window_get_wl_surface(gdk_window);
@ -60,6 +59,8 @@ waybar::Bar::Bar(const Client& client,
zwlr_layer_surface_v1_set_size(layer_surface, width, height); zwlr_layer_surface_v1_set_size(layer_surface, width, height);
wl_surface_commit(surface); wl_surface_commit(surface);
setupWidgets();
} }
void waybar::Bar::handleLogicalPosition(void* /*data*/, void waybar::Bar::handleLogicalPosition(void* /*data*/,
@ -104,11 +105,20 @@ void waybar::Bar::layerSurfaceHandleConfigure(void* data,
if (width != o->width_ || height != o->height_) { if (width != o->width_ || height != o->height_) {
o->width_ = width; o->width_ = width;
o->height_ = height; o->height_ = height;
o->window.set_size_request(o->width_, o->height_);
o->window.resize(o->width_, o->height_);
int dummy_width, min_height;
o->window.get_size(dummy_width, min_height);
if (o->height_ < static_cast<uint32_t>(min_height)) {
std::cout << fmt::format("Requested height: {} exceeds the minimum \
height: {} required by the modules", o->height_, min_height) << std::endl;
o->height_ = min_height;
}
std::cout << fmt::format( std::cout << fmt::format(
"Bar configured (width: {}, height: {}) for output: {}", "Bar configured (width: {}, height: {}) for output: {}",
o->width_, o->height_, o->output_name) << std::endl; o->width_, o->height_, o->output_name) << std::endl;
o->window.set_size_request(o->width_, o->height_);
o->window.resize(o->width_, o->height_);
zwlr_layer_surface_v1_set_exclusive_zone(surface, o->height_); zwlr_layer_surface_v1_set_exclusive_zone(surface, o->height_);
zwlr_layer_surface_v1_set_size(surface, o->width_, o->height_); zwlr_layer_surface_v1_set_size(surface, o->width_, o->height_);
wl_surface_commit(o->surface); wl_surface_commit(o->surface);

View File

@ -12,6 +12,9 @@ waybar::IModule* waybar::Factory::makeModule(const std::string &name) const
return new waybar::modules::Battery(config_[name]); return new waybar::modules::Battery(config_[name]);
} }
#ifdef HAVE_SWAY #ifdef HAVE_SWAY
if (ref == "sway/mode") {
return new waybar::modules::sway::Mode(bar_, config_[name]);
}
if (ref == "sway/workspaces") { if (ref == "sway/workspaces") {
return new waybar::modules::sway::Workspaces(bar_, config_[name]); return new waybar::modules::sway::Workspaces(bar_, config_[name]);
} }

View File

@ -34,7 +34,6 @@ waybar::modules::Battery::Battery(const Json::Value& config)
for (auto const& bat : batteries_) { for (auto const& bat : batteries_) {
inotify_add_watch(fd_, (bat / "uevent").c_str(), IN_ACCESS); inotify_add_watch(fd_, (bat / "uevent").c_str(), IN_ACCESS);
} }
label_.set_name("battery");
worker(); worker();
} }
@ -63,11 +62,11 @@ void waybar::modules::Battery::worker()
}; };
} }
auto waybar::modules::Battery::update() -> void std::tuple<uint16_t, std::string> waybar::modules::Battery::getInfos()
{ {
try { try {
uint16_t total = 0; uint16_t total = 0;
std::string status; std::string status = "Unknown";
for (auto const& bat : batteries_) { for (auto const& bat : batteries_) {
uint16_t capacity; uint16_t capacity;
std::string _status; std::string _status;
@ -79,22 +78,64 @@ auto waybar::modules::Battery::update() -> void
total += capacity; total += capacity;
} }
uint16_t capacity = total / batteries_.size(); uint16_t capacity = total / batteries_.size();
label_.set_text(fmt::format(format_, fmt::arg("capacity", capacity), return {capacity, status};
fmt::arg("icon", getIcon(capacity))));
label_.set_tooltip_text(status);
bool charging = status == "Charging";
if (charging) {
label_.get_style_context()->add_class("charging");
} else {
label_.get_style_context()->remove_class("charging");
}
auto critical = config_["critical"].isUInt() ? 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) { } catch (const std::exception& e) {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
return {0, "Unknown"};
}
}
std::string waybar::modules::Battery::getState(uint16_t capacity)
{
// Get current state
std::vector<std::pair<std::string, uint16_t>> states;
if (config_["states"].isObject()) {
for (auto it = config_["states"].begin(); it != config_["states"].end(); ++it) {
if (it->isUInt() && it.key().isString()) {
states.push_back({it.key().asString(), it->asUInt()});
}
}
}
// Sort states
std::sort(states.begin(), states.end(), [](auto &a, auto &b) {
return a.second < b.second;
});
std::string validState = "";
for (auto state : states) {
if (capacity <= state.second && validState.empty()) {
label_.get_style_context()->add_class(state.first);
validState = state.first;
} else {
label_.get_style_context()->remove_class(state.first);
}
}
return validState;
}
auto waybar::modules::Battery::update() -> void
{
auto [capacity, status] = getInfos();
label_.set_tooltip_text(status);
std::transform(status.begin(), status.end(), status.begin(), ::tolower);
auto format = format_;
auto state = getState(capacity);
label_.get_style_context()->remove_class(old_status_);
label_.get_style_context()->add_class(status);
old_status_ = status;
if (!state.empty() && config_["format-" + status + "-" + state].isString()) {
format = config_["format-" + status + "-" + state].asString();
} else if (config_["format-" + status].isString()) {
format = config_["format-" + status].asString();
} else if (!state.empty() && config_["format-" + state].isString()) {
format = config_["format-" + state].asString();
}
if (format.empty()) {
event_box_.hide();
label_.set_name("");
} else {
event_box_.show();
label_.set_name("battery");
label_.set_text(fmt::format(format, fmt::arg("capacity", capacity),
fmt::arg("icon", getIcon(capacity))));
} }
} }

View File

@ -72,9 +72,65 @@ auto waybar::modules::Custom::update() -> void
label_.set_name(""); label_.set_name("");
} else { } else {
label_.set_name("custom-" + name_); label_.set_name("custom-" + name_);
auto str = fmt::format(format_, output_.out);
if (config_["return-type"].asString() == "json") {
parseOutputJson();
} else {
parseOutputRaw();
}
auto str = fmt::format(format_, text_);
label_.set_text(str); label_.set_text(str);
if (text_ == tooltip_) {
label_.set_tooltip_text(str); label_.set_tooltip_text(str);
} else {
label_.set_tooltip_text(tooltip_);
}
if (class_ != "") {
if (prevclass_ != "") {
label_.get_style_context()->remove_class(prevclass_);
}
label_.get_style_context()->add_class(class_);
prevclass_ = class_;
} else {
label_.get_style_context()->remove_class(prevclass_);
prevclass_ = "";
}
label_.show(); label_.show();
} }
} }
void waybar::modules::Custom::parseOutputRaw()
{
std::istringstream output(output_.out);
std::string line;
int i = 0;
while (getline(output, line)) {
if (i == 0) {
text_ = line;
tooltip_ = line;
class_ = "";
} else if (i == 1) {
tooltip_ = line;
} else if (i == 2) {
class_ = line;
} else {
break;
}
i++;
}
}
void waybar::modules::Custom::parseOutputJson()
{
std::istringstream output(output_.out);
std::string line;
while (getline(output, line)) {
auto parsed = parser_.parse(line);
text_ = parsed["text"].asString();
tooltip_ = parsed["tooltip"].asString();
class_ = parsed["class"].asString();
break;
}
}

View File

@ -1,9 +1,14 @@
#include "modules/pulseaudio.hpp" #include "modules/pulseaudio.hpp"
waybar::modules::Pulseaudio::Pulseaudio(const Json::Value &config) waybar::modules::Pulseaudio::Pulseaudio(const Json::Value &config)
: ALabel(config, "{volume}%"), mainloop_(nullptr), mainloop_api_(nullptr), : ALabel(config, "{volume}%"),
context_(nullptr), sink_idx_(0), volume_(0), muted_(false) mainloop_(nullptr),
{ mainloop_api_(nullptr),
context_(nullptr),
sink_idx_(0),
volume_(0),
muted_(false),
scrolling_(false) {
label_.set_name("pulseaudio"); label_.set_name("pulseaudio");
mainloop_ = pa_threaded_mainloop_new(); mainloop_ = pa_threaded_mainloop_new();
if (mainloop_ == nullptr) { if (mainloop_ == nullptr) {
@ -26,10 +31,18 @@ waybar::modules::Pulseaudio::Pulseaudio(const Json::Value& config)
throw std::runtime_error("pa_mainloop_run() failed."); throw std::runtime_error("pa_mainloop_run() failed.");
} }
pa_threaded_mainloop_unlock(mainloop_); pa_threaded_mainloop_unlock(mainloop_);
// define the pulse scroll events only when no user provided
// events are configured
if (!config["on-scroll-up"].isString() &&
!config["on-scroll-down"].isString()) {
event_box_.add_events(Gdk::SCROLL_MASK);
event_box_.signal_scroll_event().connect(
sigc::mem_fun(*this, &Pulseaudio::handleScroll));
}
} }
waybar::modules::Pulseaudio::~Pulseaudio() waybar::modules::Pulseaudio::~Pulseaudio() {
{
mainloop_api_->quit(mainloop_api_, 0); mainloop_api_->quit(mainloop_api_, 0);
pa_threaded_mainloop_stop(mainloop_); pa_threaded_mainloop_stop(mainloop_);
pa_threaded_mainloop_free(mainloop_); pa_threaded_mainloop_free(mainloop_);
@ -58,6 +71,47 @@ void waybar::modules::Pulseaudio::contextStateCb(pa_context *c, void *data)
} }
} }
bool waybar::modules::Pulseaudio::handleScroll(GdkEventScroll *e) {
// Avoid concurrent scroll event
bool direction_up = false;
// XXX/TODO: Change of 100 corresponds to 1%, does that always hold true?
uint16_t change = 100;
pa_cvolume pa_volume = pa_volume_;
if (scrolling_) {
return false;
}
scrolling_ = true;
if (e->direction == GDK_SCROLL_UP) {
direction_up = true;
}
if (e->direction == GDK_SCROLL_DOWN) {
direction_up = false;
}
if (e->direction == GDK_SCROLL_SMOOTH) {
gdouble delta_x, delta_y;
gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent *>(e), &delta_x,
&delta_y);
if (delta_y < 0) {
direction_up = true;
} else if (delta_y > 0) {
direction_up = false;
}
}
if (direction_up) {
if (volume_ + 1 < 100) pa_cvolume_inc(&pa_volume, change);
} else {
if (volume_ - 1 > 0) pa_cvolume_dec(&pa_volume, change);
}
pa_context_set_sink_volume_by_index(context_, sink_idx_, &pa_volume,
volumeModifyCb, this);
return true;
}
/* /*
* Called when an event we subscribed to occurs. * Called when an event we subscribed to occurs.
*/ */
@ -75,16 +129,29 @@ void waybar::modules::Pulseaudio::subscribeCb(pa_context* context,
} }
} }
/*
* Called in response to a volume change request
*/
void waybar::modules::Pulseaudio::volumeModifyCb(pa_context *c, int success,
void *data) {
auto pa = static_cast<waybar::modules::Pulseaudio *>(data);
if (success) {
pa_context_get_sink_info_by_index(pa->context_, pa->sink_idx_, sinkInfoCb,
data);
}
}
/* /*
* Called when the requested sink information is ready. * Called when the requested sink information is ready.
*/ */
void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/,
const pa_sink_info* i, int /*eol*/, void* data) const pa_sink_info *i, int /*eol*/,
{ void *data) {
if (i != nullptr) { if (i != nullptr) {
auto pa = static_cast<waybar::modules::Pulseaudio *>(data); auto pa = static_cast<waybar::modules::Pulseaudio *>(data);
float volume = static_cast<float>(pa_cvolume_avg(&(i->volume))) pa->pa_volume_ = i->volume;
/ float{PA_VOLUME_NORM}; float volume = static_cast<float>(pa_cvolume_avg(&(pa->pa_volume_))) /
float{PA_VOLUME_NORM};
pa->sink_idx_ = i->index; pa->sink_idx_ = i->index;
pa->volume_ = std::round(volume * 100.0f); pa->volume_ = std::round(volume * 100.0f);
pa->muted_ = i->mute != 0; pa->muted_ = i->mute != 0;
@ -141,8 +208,11 @@ auto waybar::modules::Pulseaudio::update() -> void
label_.get_style_context()->remove_class("muted"); label_.get_style_context()->remove_class("muted");
label_.get_style_context()->add_class("bluetooth"); label_.get_style_context()->add_class("bluetooth");
} }
label_.set_label(fmt::format(format, label_.set_label(
fmt::arg("volume", volume_), fmt::format(format, fmt::arg("volume", volume_),
fmt::arg("icon", getIcon(volume_, getPortIcon())))); fmt::arg("icon", getIcon(volume_, getPortIcon()))));
label_.set_tooltip_text(desc_); label_.set_tooltip_text(desc_);
if (scrolling_) {
scrolling_ = false;
}
} }

View File

@ -33,6 +33,7 @@ void Host::nameAppeared(GDBusConnection* connection,
auto host = static_cast<SNI::Host *>(data); auto host = static_cast<SNI::Host *>(data);
if (host->cancellable_ != nullptr) { if (host->cancellable_ != nullptr) {
// TODO // TODO
return;
} }
host->cancellable_ = g_cancellable_new(); host->cancellable_ = g_cancellable_new();
sn_watcher_proxy_new( sn_watcher_proxy_new(

View File

@ -7,7 +7,8 @@ waybar::modules::SNI::Item::Item(std::string bn, std::string op,
Glib::Dispatcher *dp, Json::Value config) Glib::Dispatcher *dp, Json::Value config)
: bus_name(bn), object_path(op), event_box(), icon_size(16), : bus_name(bn), object_path(op), event_box(), icon_size(16),
effective_icon_size(0), image(Gtk::manage(new Gtk::Image())), effective_icon_size(0), image(Gtk::manage(new Gtk::Image())),
dp_(dp), config_(config) { dp_(dp), config_(config)
{
if (config_["icon-size"].isUInt()) { if (config_["icon-size"].isUInt()) {
icon_size = config_["icon-size"].asUInt(); icon_size = config_["icon-size"].asUInt();
} }
@ -172,10 +173,12 @@ waybar::modules::SNI::Item::extractPixBuf(GVariant *variant) {
void waybar::modules::SNI::Item::updateMenu() void waybar::modules::SNI::Item::updateMenu()
{ {
event_box.set_tooltip_text(title); event_box.set_tooltip_text(title);
if (!menu.empty()) { if (gtk_menu == nullptr && !menu.empty()) {
auto *dbmenu = dbusmenu_gtkmenu_new(bus_name.data(), menu.data()); auto dbmenu = dbusmenu_gtkmenu_new(bus_name.data(), menu.data());
if (dbmenu) { if (dbmenu != nullptr) {
g_object_ref_sink(dbmenu);
gtk_menu = Glib::wrap(GTK_MENU(dbmenu), false); gtk_menu = Glib::wrap(GTK_MENU(dbmenu), false);
gtk_menu->attach_to_widget(event_box);
} }
} }
} }
@ -187,7 +190,11 @@ void waybar::modules::SNI::Item::updateImage()
if (!icon_name.empty()) { if (!icon_name.empty()) {
try { try {
// Try to find icons specified by path and filename // Try to find icons specified by path and filename
#ifdef FILESYSTEM_EXPERIMENTAL
if (std::experimental::filesystem::exists(icon_name)) {
#else
if (std::filesystem::exists(icon_name)) { if (std::filesystem::exists(icon_name)) {
#endif
auto pixbuf = Gdk::Pixbuf::create_from_file(icon_name); auto pixbuf = Gdk::Pixbuf::create_from_file(icon_name);
if (pixbuf->gobj() != nullptr) { if (pixbuf->gobj() != nullptr) {
// An icon specified by path and filename may be the wrong size for // An icon specified by path and filename may be the wrong size for
@ -248,11 +255,15 @@ void waybar::modules::SNI::Item::handleSecondaryActivate(GObject *src,
bool waybar::modules::SNI::Item::handleClick(GdkEventButton *const &ev) { bool waybar::modules::SNI::Item::handleClick(GdkEventButton *const &ev) {
if (ev->type == GDK_BUTTON_PRESS) { if (ev->type == GDK_BUTTON_PRESS) {
if (gtk_menu) { if (gtk_menu && gtk_menu->get_children().size() > 0) {
if (!gtk_menu->get_attach_widget()) { #if GTK_CHECK_VERSION(3, 22, 0)
gtk_menu->attach_to_widget(event_box); gtk_menu->popup_at_widget(reinterpret_cast<Gtk::Widget*>(&event_box),
} Gdk::GRAVITY_NORTH_WEST, Gdk::GRAVITY_NORTH_WEST,
reinterpret_cast<GdkEvent*>(ev));
#else
gtk_menu->popup(ev->button, ev->time); gtk_menu->popup(ev->button, ev->time);
#endif
gtk_menu->set_state_flags(Gtk::STATE_FLAG_ACTIVE, false);
} else { } else {
sn_item_call_activate( sn_item_call_activate(
proxy_, ev->x, ev->y, nullptr, &Item::handleActivate, this); proxy_, ev->x, ev->y, nullptr, &Item::handleActivate, this);

View File

@ -5,6 +5,7 @@
waybar::modules::SNI::Tray::Tray(const Json::Value &config) waybar::modules::SNI::Tray::Tray(const Json::Value &config)
: config_(config), watcher_(), host_(&dp, config) : config_(config), watcher_(), host_(&dp, config)
{ {
std::cout << "Tray is in beta, so there may be bugs or even be unusable." << std::endl;
if (config_["spacing"].isUInt()) { if (config_["spacing"].isUInt()) {
box_.set_spacing(config_["spacing"].asUInt()); box_.set_spacing(config_["spacing"].asUInt());
} }

43
src/modules/sway/mode.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "modules/sway/mode.hpp"
waybar::modules::sway::Mode::Mode(Bar& bar, const Json::Value& config)
: ALabel(config, "{}"), bar_(bar)
{
ipc_.connect();
ipc_.subscribe("[ \"mode\" ]");
// Launch worker
worker();
}
void waybar::modules::sway::Mode::worker()
{
thread_ = [this] {
try {
auto res = ipc_.handleEvent();
auto parsed = parser_.parse(res.payload);
if ((parsed["change"]) != "default" ) {
mode_ = parsed["change"].asString();
dp.emit();
}
else if ((parsed["change"]) == "default" ) {
mode_.clear();
dp.emit();
}
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
};
}
auto waybar::modules::sway::Mode::update() -> void
{
if (mode_.empty()) {
label_.set_name("");
label_.hide();
} else {
label_.set_name("mode");
label_.set_text(fmt::format(format_, mode_));
label_.set_tooltip_text(mode_);
label_.show();
}
}

View File

@ -5,7 +5,7 @@ waybar::modules::sway::Window::Window(Bar &bar, const Json::Value& config)
{ {
label_.set_name("window"); label_.set_name("window");
ipc_.connect(); ipc_.connect();
ipc_.subscribe("[ \"window\" ]"); ipc_.subscribe("[\"window\",\"workspace\"]");
getFocusedWindow(); getFocusedWindow();
// Launch worker // Launch worker
worker(); worker();
@ -22,9 +22,11 @@ void waybar::modules::sway::Window::worker()
window_ = parsed["container"]["name"].asString(); window_ = parsed["container"]["name"].asString();
windowId_ = parsed["container"]["id"].asInt(); windowId_ = parsed["container"]["id"].asInt();
dp.emit(); dp.emit();
} else if (parsed["change"] == "close" } else if ((parsed["change"] == "close"
&& parsed["container"]["focused"].asBool() && parsed["container"]["focused"].asBool()
&& windowId_ == parsed["container"]["id"].asInt()) { && windowId_ == parsed["container"]["id"].asInt())
|| (parsed["change"] == "focus" && parsed["current"]["focus"].isArray()
&& parsed["current"]["focus"].empty())) {
window_.clear(); window_.clear();
windowId_ = -1; windowId_ = -1;
dp.emit(); dp.emit();

View File

@ -1,10 +1,10 @@
[wrap-file] [wrap-file]
directory = fmt-4.1.0 directory = fmt-5.2.0
source_url = https://github.com/fmtlib/fmt/archive/4.1.0.tar.gz source_url = https://github.com/fmtlib/fmt/archive/5.2.0.tar.gz
source_filename = fmt-4.1.0.tar.gz source_filename = fmt-5.2.0.tar.gz
source_hash = 46628a2f068d0e33c716be0ed9dcae4370242df135aed663a180b9fd8e36733d source_hash = b0e8c71a8fb906123966686f788e83cd95ae499afe9c25ff6284f624488435ac
patch_url = https://wrapdb.mesonbuild.com/v1/projects/fmt/4.1.0/1/get_zip patch_url = https://wrapdb.mesonbuild.com/v1/projects/fmt/5.2.0/1/get_zip
patch_filename = fmt-4.1.0-1-wrap.zip patch_filename = fmt-5.2.0-1-wrap.zip
patch_hash = 741931f01e558491724fc1c67bff996d1df79c0277626fc463de138052c9ecc0 patch_hash = 04005310ad939bc640ca0eb918e6b5390dbd5b5cb9d58636eb7c442306aa14cd