Compare commits

..

81 Commits
0.1.2 ... 0.2.1

Author SHA1 Message Date
33f138c16e chore: v0.2.1 2018-11-16 10:15:27 +01:00
01692b719a chore: update README 2018-11-16 10:07:20 +01:00
8c26a6aab7 chore: update README 2018-11-16 10:06:24 +01:00
e42fae32ab feat(network): network info interval 2018-11-16 10:02:12 +01:00
c910767378 refactor: remove usless using 2018-11-15 14:48:49 +01:00
94b9f0a399 feat(cpu): add both usage and load 2018-11-15 14:44:43 +01:00
1665003d23 fix: sigsev 2018-11-14 19:14:51 +01:00
e5573c20e6 Merge pull request #96 from Robinhuett/module_network_ipaddr
Module network ipaddr
2018-11-14 10:44:27 +01:00
75cc1bc318 refactor(network): codestyle and error handling 2018-11-14 10:31:17 +01:00
50e782e028 chore: update example config 2018-11-13 21:40:47 +01:00
5c66b1a770 feat(network): display ip address and subnetmask 2018-11-13 21:31:26 +01:00
3dc0f7ccf9 Merge pull request #94 from Robinhuett/cpu_fix
Use /proc/stat for cpu load
2018-11-11 13:41:11 +01:00
e1d98f0ad9 fix(cpu): show correct load
feat(cpu): show cores in tooltip
2018-11-11 03:11:32 +01:00
7222668326 refactor: disable battery timer stop on inotify event for now 2018-11-09 23:02:46 +01:00
315e2defde Merge pull request #93 from Robinhuett/pulseaudio_scroll
Add config option for volume change scroll step size
2018-11-09 22:55:51 +01:00
45bb8b1a1f refactor: simpler memory code 2018-11-09 22:55:25 +01:00
e21df5ae36 Add config option for volume change scroll step size 2018-11-09 22:48:27 +01:00
a5bca24f9b Merge pull request #91 from Robinhuett/ram_free_used
Use /proc/meminfo for Memory module
2018-11-09 22:34:11 +01:00
c07037d6b8 Update README.md 2018-11-09 17:27:35 +01:00
a9751545fa fix: update travis 2018-11-09 17:15:19 +01:00
9ea0815dea Use ifstream to reaad /proc/meminfo 2018-11-09 16:24:13 +01:00
b8b799a187 [ci skip] remove .SRCINFO at root 2018-11-09 15:36:21 +01:00
39dfa66261 feat(ci): archlinux 2018-11-09 15:19:17 +01:00
13702012a4 CI (#90) 2018-11-09 12:07:16 +01:00
6b62079d8a rewind stream instead of opening a new one 2018-11-09 00:17:30 +01:00
ac0963c608 Use /proc/meminfo for Memory module 2018-11-08 21:09:56 +01:00
2d2fb88040 fix: fmt 2018-11-08 09:57:24 +01:00
0933aad75f Merge pull request #87 from David96/master
Fix workspaces not being removed from bar when moved to another output
2018-11-05 21:06:53 +01:00
adcd956c24 Fix workspaces not being removed from bar when moved to another output 2018-11-05 20:59:28 +01:00
6c9e37699b Merge pull request #86 from David96/master
Fix clicking and scrolling through workspaces
2018-11-05 20:35:48 +01:00
168415440f Fix clicking and scrolling through workspaces
The way waybar used the workspace "num", clicking a workspace called "1:
something" resulted in going to a newly created workspace called "1",
because the workspace ipc command expects the workspace name, not its number.
2018-11-05 20:16:19 +01:00
d6af63d84a chore: add travis 2018-11-05 11:59:05 +01:00
26182c222b Merge pull request #79 from vberger/master
Don't call layer_surface.set_size on configure
2018-11-03 13:36:04 +01:00
43cd80fb31 chore: 0.2.0 2018-11-03 13:20:05 +01:00
2f6abfda59 Don't call layer_surface.set_size on configure 2018-11-03 13:16:13 +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
3f2eb0b492 chore: 0.1.3 2018-10-28 08:39:33 +01:00
4f773ea268 Merge pull request #65 from maxice8/fix-musl
add missing <cstring> include for strncpy, fixes musl
2018-10-28 08:29:56 +01:00
047473e5a4 add missing <cstring> include for strncpy, fixes musl
I/usr/include/libdbusmenu-glib-0.4 -flto -fdiagnostics-color=always -DNDEBUG -pipe -D_FILE_OFFSET_BITS=64 -std=c++17 -DHAVE_SWAY -DHAVE_LIBPULSE -DHAVE_DBUSMENU -D_FORTIFY_SOURCE=2 -mtune=generic -O2 -D_REENTRANT -pthread  -MD -MQ 'waybar@exe/src_modules_sway_ipc_client.cpp.o' -MF 'waybar@exe/src_modules_sway_ipc_client.cpp.o.d' -o 'waybar@exe/src_modules_sway_ipc_client.cpp.o' -c ../src/modules/sway/ipc/client.cpp
../src/modules/sway/ipc/client.cpp: In member function 'int waybar::modules::sway::Ipc::open(const string&) const':
../src/modules/sway/ipc/client.cpp:47:3: error: 'strncpy' was not declared in this scope
   strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1);
   ^~~~~~~
../src/modules/sway/ipc/client.cpp:47:3: note: 'strncpy' is defined in header '<cstring>'; did you forget to '#include <cstring>'?
../src/modules/sway/ipc/client.cpp:2:1:
+#include <cstring>

../src/modules/sway/ipc/client.cpp:47:3:
   strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1);
   ^~~~~~~
[36/44] Compiling C++ object 'waybar@exe/src_modules_custom.cpp.o'.
[37/44] Compiling C++ object 'waybar@exe/src_client.cpp.o'.
[38/44] Compiling C++ object 'waybar@exe/src_modules_cpu.cpp.o'.
ninja: build stopped: subcommand failed.
2018-10-28 04:06:07 -03:00
ed3e4b1395 fix(pulseaudio): check active_port is set 2018-10-27 11:23:43 +02:00
16b01e1059 Merge pull request #62 from colemickens/giounix20
meson: fix 'gio-unix-2.0' dependency
2018-10-27 09:35:47 +02:00
1ae490c8f7 Merge pull request #61 from colemickens/outdir
meson: make extra output directory configurable
2018-10-27 09:16:11 +02:00
0d0a3be483 meson: fix 'gio-unix-2.0' dependency 2018-10-26 23:21:03 -07:00
a1c4b9bb0c meson: make extra output directory configurable 2018-10-26 23:20:38 -07:00
a55a1ae866 fix(tray): icons size 2018-10-26 14:53:39 +02:00
07d8dfb3d6 feat(tray): spacing config 2018-10-26 12:08:50 +02:00
5010227e6b fix(tray): icons 2018-10-26 11:59:03 +02:00
44 changed files with 881 additions and 223 deletions

View File

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

17
.travis.yml Normal file
View File

@ -0,0 +1,17 @@
sudo: false
services:
- docker
env:
- distro: debian
- distro: archlinux
before_install:
- docker pull alexays/waybar:${distro}
script:
- echo FROM alexays/waybar:${distro} > Dockerfile
- echo ADD . /root >> Dockerfile
- docker build -t waybar .
- docker run waybar /bin/sh -c "cd /root && git clone https://github.com/swaywm/wlroots subprojects/wlroots && meson build && ninja -C build"

4
Dockerfiles/archlinux Normal file
View File

@ -0,0 +1,4 @@
FROM archlinux/base:latest
RUN pacman -Syu --noconfirm && \
pacman -S git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp --noconfirm

5
Dockerfiles/debian Normal file
View File

@ -0,0 +1,5 @@
FROM debian:sid
RUN apt-get update && \
apt-get install -y build-essential meson ninja-build git pkg-config libinput10 libinput-dev wayland-protocols libwayland-client0 libwayland-cursor0 libwayland-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libxkbcommon-dev libudev-dev libpixman-1-dev libgtkmm-3.0-dev libjsoncpp-dev && \
apt-get clean

View File

@ -1,12 +1,11 @@
# Waybar [![Licence](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)<br>![Waybar](https://raw.githubusercontent.com/alexays/waybar/master/preview-2.png) # Waybar [![Travis](https://travis-ci.org/Alexays/Waybar.svg?branch=master)](https://travis-ci.org/Alexays/Waybar) [![Licence](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)<br>![Waybar](https://raw.githubusercontent.com/alexays/waybar/master/preview-2.png)
**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/)
**Current features** **Current features**
- Sway Workspaces - Sway (Workspaces, Binding mode, Focused window name)
- Sway focused window name
- Tray (Beta) [#21](https://github.com/Alexays/Waybar/issues/21) - Tray (Beta) [#21](https://github.com/Alexays/Waybar/issues/21)
- Local time - Local time
- Battery - Battery
@ -25,6 +24,7 @@
```bash ```bash
$ git clone https://github.com/Alexays/Waybar $ git clone https://github.com/Alexays/Waybar
$ cd Waybar
$ meson build $ meson build
$ ninja -C build $ ninja -C build
$ ./build/waybar $ ./build/waybar

View File

@ -6,21 +6,25 @@
namespace waybar { namespace waybar {
class ALabel : public IModule { class ALabel : public IModule {
public: public:
ALabel(const Json::Value&, const std::string format); ALabel(const Json::Value&, const std::string format);
virtual ~ALabel() = default; virtual ~ALabel() = default;
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:
Gtk::EventBox event_box_; protected:
Gtk::Label label_; Gtk::EventBox event_box_;
const Json::Value& config_; Gtk::Label label_;
std::string format_; const Json::Value& config_;
private: std::string format_;
bool handleToggle(GdkEventButton* const& ev); std::mutex mutex_;
bool alt = false;
const std::string default_format_; private:
bool handleToggle(GdkEventButton* const& ev);
bool handleScroll(GdkEventScroll*);
bool alt = false;
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
#include <filesystem> #ifdef FILESYSTEM_EXPERIMENTAL
#include <experimental/filesystem>
#else
#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 thread_timer_;
std::vector<fs::path> batteries_; std::vector<fs::path> batteries_;
int fd_; int fd_;
std::string old_status_;
}; };
} }

View File

@ -2,6 +2,10 @@
#include <fmt/format.h> #include <fmt/format.h>
#include <sys/sysinfo.h> #include <sys/sysinfo.h>
#include <fstream>
#include <vector>
#include <numeric>
#include <iostream>
#include "util/chrono.hpp" #include "util/chrono.hpp"
#include "ALabel.hpp" #include "ALabel.hpp"
@ -12,6 +16,12 @@ class Cpu : public ALabel {
Cpu(const Json::Value&); Cpu(const Json::Value&);
auto update() -> void; auto update() -> void;
private: private:
static inline const std::string data_dir_ = "/proc/stat";
uint16_t getCpuLoad();
std::tuple<uint16_t, std::string> getCpuUsage();
std::vector<std::tuple<size_t, size_t>> parseCpuinfo();
std::vector<std::tuple<size_t, size_t>> prev_times_;
waybar::util::SleeperThread thread_; waybar::util::SleeperThread thread_;
}; };

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,7 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <sys/sysinfo.h> #include <fstream>
#include "util/chrono.hpp" #include "util/chrono.hpp"
#include "ALabel.hpp" #include "ALabel.hpp"
@ -12,6 +12,10 @@ class Memory : public ALabel {
Memory(const Json::Value&); Memory(const Json::Value&);
auto update() -> void; auto update() -> void;
private: private:
static inline const std::string data_dir_ = "/proc/meminfo";
unsigned long memtotal_;
unsigned long memfree_;
void parseMeminfo();
waybar::util::SleeperThread thread_; waybar::util::SleeperThread thread_;
}; };

View File

@ -1,6 +1,8 @@
#pragma once #pragma once
#include <net/if.h> #include <net/if.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <netlink/netlink.h> #include <netlink/netlink.h>
#include <netlink/genl/genl.h> #include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h> #include <netlink/genl/ctrl.h>
@ -21,24 +23,30 @@ class Network : public ALabel {
static int netlinkResponse(int, void*, uint32_t, uint32_t groups = 0); static int netlinkResponse(int, void*, uint32_t, uint32_t groups = 0);
static int scanCb(struct nl_msg*, void*); static int scanCb(struct nl_msg*, void*);
void worker();
void disconnected(); void disconnected();
void initNL80211(); void initNL80211();
int getExternalInterface(); int getExternalInterface();
void getInterfaceAddress();
void parseEssid(struct nlattr**); void parseEssid(struct nlattr**);
void parseSignal(struct nlattr**); void parseSignal(struct nlattr**);
bool associatedOrJoined(struct nlattr**); bool associatedOrJoined(struct nlattr**);
auto getInfo() -> void; auto getInfo() -> void;
waybar::util::SleeperThread thread_; waybar::util::SleeperThread thread_;
waybar::util::SleeperThread thread_timer_;
int ifid_; int ifid_;
sa_family_t family_; sa_family_t family_;
int sock_fd_; int sock_fd_;
struct sockaddr_nl nladdr_ = {}; struct sockaddr_nl nladdr_ = {0};
struct nl_sock* sk_ = nullptr; struct nl_sock* sk_ = nullptr;
int nl80211_id_; int nl80211_id_;
std::string essid_; std::string essid_;
std::string ifname_; std::string ifname_;
std::string ipaddr_;
std::string netmask_;
int cidr_;
int signal_strength_dbm_; int signal_strength_dbm_;
uint16_t signal_strength_; uint16_t signal_strength_;
}; };

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

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <gtkmm.h> #include <gtkmm.h>
#include <json/json.h>
#include <tuple> #include <tuple>
#include <dbus-status-notifier-watcher.h> #include <dbus-status-notifier-watcher.h>
#include "modules/sni/sni.hpp" #include "modules/sni/sni.hpp"
@ -10,7 +10,7 @@ namespace waybar::modules::SNI {
class Host { class Host {
public: public:
Host(Glib::Dispatcher*); Host(Glib::Dispatcher*, const Json::Value&);
std::vector<Item> items; std::vector<Item> items;
private: private:
static void busAcquired(GDBusConnection*, const gchar*, gpointer); static void busAcquired(GDBusConnection*, const gchar*, gpointer);
@ -32,6 +32,7 @@ class Host {
Glib::Dispatcher* dp_; Glib::Dispatcher* dp_;
GCancellable* cancellable_ = nullptr; GCancellable* cancellable_ = nullptr;
SnWatcher* watcher_ = nullptr; SnWatcher* watcher_ = nullptr;
const Json::Value &config_;
}; };
} }

View File

@ -2,12 +2,18 @@
#include <dbus-status-notifier-item.h> #include <dbus-status-notifier-item.h>
#include <gtkmm.h> #include <gtkmm.h>
#include <json/json.h>
#ifdef FILESYSTEM_EXPERIMENTAL
#include <experimental/filesystem>
#else
#include <filesystem>
#endif
namespace waybar::modules::SNI { namespace waybar::modules::SNI {
class Item { class Item {
public: public:
Item(std::string, std::string, Glib::Dispatcher *); Item(std::string, std::string, Glib::Dispatcher*, Json::Value);
std::string bus_name; std::string bus_name;
std::string object_path; std::string object_path;
@ -39,6 +45,7 @@ private:
static void handleSecondaryActivate(GObject *, GAsyncResult *, gpointer); static void handleSecondaryActivate(GObject *, GAsyncResult *, gpointer);
void updateImage(); void updateImage();
void updateMenu();
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant *variant); Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant *variant);
Glib::RefPtr<Gdk::Pixbuf> getIconByName(std::string name, int size); Glib::RefPtr<Gdk::Pixbuf> getIconByName(std::string name, int size);
bool handleClick(GdkEventButton *const & /*ev*/); bool handleClick(GdkEventButton *const & /*ev*/);
@ -46,6 +53,7 @@ private:
Glib::Dispatcher *dp_; Glib::Dispatcher *dp_;
GCancellable *cancellable_ = nullptr; GCancellable *cancellable_ = nullptr;
SnItem *proxy_ = nullptr; SnItem *proxy_ = nullptr;
Json::Value config_;
}; };
} // namespace waybar::modules::SNI } // namespace waybar::modules::SNI

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <iostream> #include <iostream>
#include <cstring>
#include <unistd.h> #include <unistd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>

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

@ -20,8 +20,8 @@ class Workspaces : public IModule {
void addWorkspace(Json::Value); void addWorkspace(Json::Value);
std::string getIcon(std::string, Json::Value); std::string getIcon(std::string, Json::Value);
bool handleScroll(GdkEventScroll*); bool handleScroll(GdkEventScroll*);
int getPrevWorkspace(); std::string getPrevWorkspace();
int getNextWorkspace(); std::string getNextWorkspace();
Bar& bar_; Bar& bar_;
const Json::Value& config_; const Json::Value& config_;
@ -30,7 +30,7 @@ class Workspaces : public IModule {
util::JsonParser parser_; util::JsonParser parser_;
std::mutex mutex_; std::mutex mutex_;
bool scrolling_; bool scrolling_;
std::unordered_map<int, Gtk::Button> buttons_; std::unordered_map<std::string, Gtk::Button> buttons_;
Json::Value workspaces_; Json::Value workspaces_;
Ipc ipc_; Ipc ipc_;
}; };

View File

@ -29,7 +29,23 @@ inline struct res exec(const std::string cmd)
output.erase(output.length()-1); output.erase(output.length()-1);
} }
int exit_code = WEXITSTATUS(pclose(fp)); int exit_code = WEXITSTATUS(pclose(fp));
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,10 +1,11 @@
project( project(
'waybar', 'cpp', 'c', 'waybar', 'cpp', 'c',
version: '0.1.2', version: '0.2.1',
license: 'MIT', license: 'MIT',
default_options : [ default_options : [
'cpp_std=c++17', 'cpp_std=c++17',
'buildtype=release' 'buildtype=release',
'default_library=static'
], ],
) )
@ -17,22 +18,28 @@ if false # libc++
cpp_link_args += ['-lc++fs'] cpp_link_args += ['-lc++fs']
else else
# TODO: For std::filesystem in libstdc++. Still unstable? Or why is it not in libstdc++ proper yet?
cpp_link_args += ['-lstdc++fs'] cpp_link_args += ['-lstdc++fs']
endif endif
compiler = meson.get_compiler('cpp')
if not compiler.has_header('filesystem')
add_project_arguments('-DFILESYSTEM_EXPERIMENTAL', language: 'cpp')
endif
add_global_arguments(cpp_args, language : 'cpp') add_global_arguments(cpp_args, language : 'cpp')
add_global_link_arguments(cpp_link_args, language : 'cpp') add_global_link_arguments(cpp_link_args, language : 'cpp')
thread_dep = dependency('threads') thread_dep = dependency('threads')
libinput = dependency('libinput') libinput = dependency('libinput')
fmt = dependency('fmt', fallback: ['fmtlib', 'fmt_dep']) fmt = dependency('fmt', version : ['>=5.2.1'], fallback : ['fmt', 'fmt_dep'])
wayland_client = dependency('wayland-client') wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor') wayland_cursor = dependency('wayland-cursor')
wayland_protos = dependency('wayland-protocols') wayland_protos = dependency('wayland-protocols')
wlroots = dependency('wlroots', fallback: ['wlroots', 'wlroots']) wlroots = dependency('wlroots', fallback: ['wlroots', 'wlroots'])
gtkmm = dependency('gtkmm-3.0') gtkmm = dependency('gtkmm-3.0')
dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk')) dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk'))
giounix = dependency('gio-unix-2.0', required: get_option('dbusmenu-gtk'))
jsoncpp = dependency('jsoncpp') jsoncpp = dependency('jsoncpp')
sigcpp = dependency('sigc++-2.0') sigcpp = dependency('sigc++-2.0')
libnl = dependency('libnl-3.0', required: get_option('libnl')) libnl = dependency('libnl-3.0', required: get_option('libnl'))
@ -56,6 +63,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'
] ]
@ -98,6 +106,7 @@ executable(
wayland_cursor, wayland_cursor,
gtkmm, gtkmm,
dbusmenu_gtk, dbusmenu_gtk,
giounix,
libnl, libnl,
libnlgen, libnlgen,
libpulse libpulse
@ -109,7 +118,7 @@ executable(
install_data( install_data(
'./resources/config', './resources/config',
'./resources/style.css', './resources/style.css',
install_dir: '/etc/xdg/waybar', install_dir: join_paths(get_option('out'), 'etc/xdg/waybar')
) )
clangtidy = find_program('clang-tidy', required: false) clangtidy = find_program('clang-tidy', required: false)

View File

@ -1,3 +1,4 @@
option('libnl', type: 'feature', value: 'auto', description: 'Enable libnl support for network related features') option('libnl', type: 'feature', value: 'auto', description: 'Enable libnl support for network related features')
option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio') option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio')
option('dbusmenu-gtk', type: 'feature', value: 'auto', description: 'Enable support for tray') option('dbusmenu-gtk', type: 'feature', value: 'auto', description: 'Enable support for tray')
option('out', type: 'string', value : '/', description: 'output prefix directory')

View File

@ -38,31 +38,63 @@ endforeach
gdbus_codegen = find_program('gdbus-codegen') gdbus_codegen = find_program('gdbus-codegen')
gdbus_code = generator( r = run_command(gdbus_codegen, '--body', '--output', '/dev/null')
gdbus_codegen, if r.returncode() != 0
output: '@BASENAME@.c', gdbus_code_dsnw = custom_target(
arguments: ['--c-namespace', 'Sn', '--body', '--output', '@OUTPUT@', '@INPUT@'] '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_header = generator( gdbus_code_dsni = custom_target(
gdbus_codegen, 'dbus-status-notifier-item.[ch]',
output: '@BASENAME@.h', output: ['@BASENAME@.c','@BASENAME@.h'],
arguments: ['--c-namespace', 'Sn', '--header', '--output', '@OUTPUT@', '@INPUT@'] input: './dbus-status-notifier-item.xml',
) command: [gdbus_codegen,'--c-namespace', 'Sn', '--generate-c-code', 'protocol/@BASENAME@', '@INPUT@'],
)
client_protos_src += gdbus_code.process('./dbus-status-notifier-watcher.xml') gdbus_code_dm = custom_target(
client_protos_headers += gdbus_header.process('./dbus-status-notifier-watcher.xml') '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.process('./dbus-status-notifier-item.xml') client_protos_src += gdbus_code_dsnw[0]
client_protos_headers += gdbus_header.process('./dbus-status-notifier-item.xml') 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_codegen,
output: '@BASENAME@.c',
arguments: ['--c-namespace', 'Sn', '--body', '--output', '@OUTPUT@', '@INPUT@']
)
gdbus_header = generator(
gdbus_codegen,
output: '@BASENAME@.h',
arguments: ['--c-namespace', 'Sn', '--header', '--output', '@OUTPUT@', '@INPUT@']
)
client_protos_src += gdbus_code.process('./dbus-status-notifier-watcher.xml')
client_protos_headers += gdbus_header.process('./dbus-status-notifier-watcher.xml')
client_protos_src += gdbus_code.process('./dbus-status-notifier-item.xml')
client_protos_headers += gdbus_header.process('./dbus-status-notifier-item.xml')
client_protos_src += gdbus_code.process('./dbus-menu.xml')
client_protos_headers += gdbus_header.process('./dbus-menu.xml')
endif
client_protos_src += gdbus_code.process('./dbus-menu.xml')
client_protos_headers += gdbus_header.process('./dbus-menu.xml')
lib_client_protos = static_library( lib_client_protos = static_library(
'client_protos', 'client_protos',
client_protos_src + client_protos_headers, client_protos_src + client_protos_headers,
dependencies: [wayland_client, gtkmm], dependencies: [wayland_client, gtkmm, giounix],
include_directories: include_directories('..'), include_directories: include_directories('..'),
) # for the include directory ) # for the include directory

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,20 +23,34 @@
// "default": "" // "default": ""
// } // }
// }, // },
"sway/mode": {
"format": "{}"
},
"sway/window": { "sway/window": {
"max-length": 50 "max-length": 50
}, },
"tray": {
// "icon-size": 21,
"spacing": 10
},
"clock": { "clock": {
"format-alt": "{:%Y-%m-%d}" "format-alt": "{:%Y-%m-%d}"
}, },
"cpu": { "cpu": {
"format": "{}% " "format": "{usage}% "
}, },
"memory": { "memory": {
"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": {
@ -45,10 +59,11 @@
"network": { "network": {
// "interface": "wlp2s0", // (Optional) To force the use of this interface // "interface": "wlp2s0", // (Optional) To force the use of this interface
"format-wifi": "{essid} ({signalStrength}%) ", "format-wifi": "{essid} ({signalStrength}%) ",
"format-ethernet": "{ifname} ", "format-ethernet": "{ifname}: {ipaddr}/{cidr} ",
"format-disconnected": "Disconnected ⚠" "format-disconnected": "Disconnected ⚠"
}, },
"pulseaudio": { "pulseaudio": {
//"scroll-step": 1,
"format": "{volume}% {icon}", "format": "{volume}% {icon}",
"format-bluetooth": "{volume}% {icon}", "format-bluetooth": "{volume}% {icon}",
"format-muted": "", "format-muted": "",
@ -60,13 +75,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) {
alt = !alt; waybar::util::command::forkExec(config_["on-click"].asString());
if (alt) {
format_ = config_["format-alt"].asString();
} else { } else {
format_ = default_format_; alt = !alt;
if (alt) {
format_ = config_["format-alt"].asString();
} else {
format_ = default_format_;
}
}
dp.emit();
return true;
}
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(); dp.emit();
return true; return true;
} }
std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt) 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,13 +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_size(surface, o->width_, o->height_);
wl_surface_commit(o->surface); wl_surface_commit(o->surface);
} }
} }

View File

@ -1,4 +1,5 @@
#include "client.hpp" #include "client.hpp"
#include <iostream>
waybar::Client::Client(int argc, char* argv[]) waybar::Client::Client(int argc, char* argv[])
: gtk_app(Gtk::Application::create(argc, argv, "fr.arouillard.waybar")), : gtk_app(Gtk::Application::create(argc, argv, "fr.arouillard.waybar")),
@ -40,7 +41,7 @@ waybar::Client::Client(int argc, char* argv[])
"/etc/xdg/waybar/style.css", "/etc/xdg/waybar/style.css",
"./resources/style.css", "./resources/style.css",
}); });
std::cout << "Resources files: " + config_file + ", " + css_file << std::endl;
} }
void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, void waybar::Client::handleGlobal(void *data, struct wl_registry *registry,
@ -89,6 +90,10 @@ void waybar::Client::bindInterfaces()
}; };
wl_registry_add_listener(registry, &registry_listener, this); wl_registry_add_listener(registry, &registry_listener, this);
wl_display_roundtrip(wl_display); wl_display_roundtrip(wl_display);
if (!layer_shell || !seat || !xdg_output_manager) {
throw std::runtime_error("Failed to acquire required resources.");
}
wl_display_roundtrip(wl_display);
} }
int waybar::Client::main(int /*argc*/, char* /*argv*/[]) int waybar::Client::main(int /*argc*/, char* /*argv*/[])

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();
} }
@ -48,7 +47,7 @@ void waybar::modules::Battery::worker()
// Trigger first values // Trigger first values
update(); update();
uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 60; uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 60;
threadTimer_ = [this, interval] { thread_timer_ = [this, interval] {
thread_.sleep_for(chrono::seconds(interval)); thread_.sleep_for(chrono::seconds(interval));
dp.emit(); dp.emit();
}; };
@ -58,16 +57,17 @@ void waybar::modules::Battery::worker()
if (nbytes != sizeof(event)) { if (nbytes != sizeof(event)) {
return; return;
} }
threadTimer_.stop(); // TODO: don't stop timer for now since there is some bugs :?
// thread_timer_.stop();
dp.emit(); dp.emit();
}; };
} }
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 +79,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

@ -1,7 +1,7 @@
#include "modules/cpu.hpp" #include "modules/cpu.hpp"
waybar::modules::Cpu::Cpu(const Json::Value& config) waybar::modules::Cpu::Cpu(const Json::Value& config)
: ALabel(config, "{}%") : ALabel(config, "{usage}%")
{ {
label_.set_name("cpu"); label_.set_name("cpu");
uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 10; uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 10;
@ -13,10 +13,78 @@ waybar::modules::Cpu::Cpu(const Json::Value& config)
auto waybar::modules::Cpu::update() -> void auto waybar::modules::Cpu::update() -> void
{ {
struct sysinfo info = {}; try {
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
auto cpu_load = getCpuLoad();
auto [cpu_usage, tooltip] = getCpuUsage();
label_.set_tooltip_text(tooltip);
label_.set_text(fmt::format(format_,
fmt::arg("load", cpu_load), fmt::arg("usage", cpu_usage)));
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
}
uint16_t waybar::modules::Cpu::getCpuLoad()
{
struct sysinfo info = {0};
if (sysinfo(&info) == 0) { if (sysinfo(&info) == 0) {
float f_load = 1.f / (1u << SI_LOAD_SHIFT); float f_load = 1.f / (1u << SI_LOAD_SHIFT);
uint16_t load = info.loads[0] * f_load * 100 / get_nprocs(); uint16_t load = info.loads[0] * f_load * 100 / get_nprocs();
label_.set_text(fmt::format(format_, load)); return load;
} }
throw std::runtime_error("Can't get Cpu load");
}
std::tuple<uint16_t, std::string> waybar::modules::Cpu::getCpuUsage()
{
if (prev_times_.empty()) {
prev_times_ = parseCpuinfo();
std::this_thread::sleep_for(chrono::milliseconds(100));
}
std::vector<std::tuple<size_t, size_t>> curr_times = parseCpuinfo();
std::string tooltip;
uint16_t usage = 0;
for (size_t i = 0; i < curr_times.size(); ++i) {
auto [curr_idle, curr_total] = curr_times[i];
auto [prev_idle, prev_total] = prev_times_[i];
const float delta_idle = curr_idle - prev_idle;
const float delta_total = curr_total - prev_total;
uint16_t tmp = 100 * (1 - delta_idle / delta_total);
if (i == 0) {
usage = tmp;
tooltip = fmt::format("Total: {}%", tmp);
} else {
tooltip = tooltip + fmt::format("\nCore{}: {}%", i - 1, tmp);
}
}
prev_times_ = curr_times;
return {usage, tooltip};
}
std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo()
{
std::ifstream info(data_dir_);
if (!info.is_open()) {
throw std::runtime_error("Can't open " + data_dir_);
}
std::vector< std::tuple<size_t, size_t> > cpuinfo;
std::string line;
while (getline(info, line)) {
if (line.substr(0,3).compare("cpu") != 0) {
break;
}
std::stringstream sline(line.substr(5));
std::vector<size_t> times;
for (size_t time; sline >> time; times.push_back(time));
size_t idle_time = 0;
size_t total_time = 0;
if (times.size() >= 4) {
idle_time = times[3];
total_time = std::accumulate(times.begin(), times.end(), 0);
}
cpuinfo.push_back({idle_time, total_time});
}
return cpuinfo;
} }

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);
label_.set_tooltip_text(str); if (text_ == tooltip_) {
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

@ -3,7 +3,6 @@
waybar::modules::Memory::Memory(const Json::Value& config) waybar::modules::Memory::Memory(const Json::Value& config)
: ALabel(config, "{}%") : ALabel(config, "{}%")
{ {
label_.set_name("memory");
uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 30; uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 30;
thread_ = [this, interval] { thread_ = [this, interval] {
dp.emit(); dp.emit();
@ -13,13 +12,51 @@ waybar::modules::Memory::Memory(const Json::Value& config)
auto waybar::modules::Memory::update() -> void auto waybar::modules::Memory::update() -> void
{ {
struct sysinfo info = {}; parseMeminfo();
if (sysinfo(&info) == 0) { if (memtotal_ > 0 && memfree_ >= 0) {
auto total = info.totalram * info.mem_unit; int used_ram_percentage = 100 * (memtotal_ - memfree_) / memtotal_;
auto freeram = info.freeram * info.mem_unit;
int used_ram_percentage = 100 * (total - freeram) / total;
label_.set_text(fmt::format(format_, used_ram_percentage)); label_.set_text(fmt::format(format_, used_ram_percentage));
auto used_ram_gigabytes = (total - freeram) / std::pow(1024, 3); auto used_ram_gigabytes = (memtotal_ - memfree_) / std::pow(1024, 2);
label_.set_tooltip_text(fmt::format("{:.{}f}Gb used", used_ram_gigabytes, 1)); label_.set_tooltip_text(fmt::format("{:.{}f}Gb used", used_ram_gigabytes, 1));
label_.set_name("memory");
label_.show();
} else {
label_.set_name("");
label_.hide();
} }
} }
void waybar::modules::Memory::parseMeminfo()
{
long memfree = -1, membuffer = -1, memcache = -1, memavail = -1;
std::ifstream info(data_dir_);
if (!info.is_open()) {
throw std::runtime_error("Can't open " + data_dir_);
}
std::string line;
while (getline(info, line)) {
auto posDelim = line.find(":");
if (posDelim == std::string::npos) {
continue;
}
std::string name = line.substr(0, posDelim);
long value = std::stol(line.substr(posDelim + 1));
if (name.compare("MemTotal") == 0) {
memtotal_ = value;
} else if (name.compare("MemAvailable") == 0) {
memavail = value;
} else if (name.compare("MemFree") == 0) {
memfree = value;
} else if (name.compare("Buffers") == 0) {
membuffer = value;
} else if (name.compare("Cached") == 0) {
memcache = value;
}
if (memtotal_ > 0 &&
(memavail >= 0 || (memfree > -1 && membuffer > -1 && memcache > -1))) {
break;
}
}
memfree_ = memavail >= 0 ? memavail : memfree + membuffer + memcache;
}

View File

@ -26,6 +26,7 @@ waybar::modules::Network::Network(const Json::Value& config)
char ifname[IF_NAMESIZE]; char ifname[IF_NAMESIZE];
if_indextoname(ifid_, ifname); if_indextoname(ifid_, ifname);
ifname_ = ifname; ifname_ = ifname;
getInterfaceAddress();
} }
} }
initNL80211(); initNL80211();
@ -33,6 +34,17 @@ waybar::modules::Network::Network(const Json::Value& config)
// Trigger first values // Trigger first values
getInfo(); getInfo();
update(); update();
worker();
}
waybar::modules::Network::~Network()
{
close(sock_fd_);
nl_socket_free(sk_);
}
void waybar::modules::Network::worker()
{
thread_ = [this] { thread_ = [this] {
char buf[4096]; char buf[4096];
uint64_t len = netlinkResponse(sock_fd_, buf, sizeof(buf), uint64_t len = netlinkResponse(sock_fd_, buf, sizeof(buf),
@ -64,6 +76,7 @@ waybar::modules::Network::Network(const Json::Value& config)
char ifname[IF_NAMESIZE]; char ifname[IF_NAMESIZE];
if_indextoname(ifid_, ifname); if_indextoname(ifid_, ifname);
ifname_ = ifname; ifname_ = ifname;
getInterfaceAddress();
need_update = true; need_update = true;
} }
} }
@ -72,12 +85,14 @@ waybar::modules::Network::Network(const Json::Value& config)
dp.emit(); dp.emit();
} }
}; };
} uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 60;
thread_timer_ = [this, interval] {
waybar::modules::Network::~Network() thread_.sleep_for(std::chrono::seconds(interval));
{ if (ifid_ > 0) {
close(sock_fd_); getInfo();
nl_socket_free(sk_); dp.emit();
}
};
} }
auto waybar::modules::Network::update() -> void auto waybar::modules::Network::update() -> void
@ -101,7 +116,10 @@ auto waybar::modules::Network::update() -> void
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_),
fmt::arg("ifname", ifname_) fmt::arg("ifname", ifname_),
fmt::arg("netmask", netmask_),
fmt::arg("ipaddr", ipaddr_),
fmt::arg("cidr", cidr_)
)); ));
} }
@ -110,6 +128,9 @@ void waybar::modules::Network::disconnected()
essid_.clear(); essid_.clear();
signal_strength_dbm_ = 0; signal_strength_dbm_ = 0;
signal_strength_ = 0; signal_strength_ = 0;
ipaddr_.clear();
netmask_.clear();
cidr_ = 0;
ifname_.clear(); ifname_.clear();
ifid_ = -1; ifid_ = -1;
} }
@ -255,6 +276,36 @@ out:
return ifidx; return ifidx;
} }
void waybar::modules::Network::getInterfaceAddress() {
unsigned int cidrRaw;
struct ifaddrs *ifaddr, *ifa;
int success = getifaddrs(&ifaddr);
if (success == 0) {
ifa = ifaddr;
while (ifa != nullptr && ipaddr_.empty() && netmask_.empty()) {
if (ifa->ifa_addr != nullptr && ifa->ifa_addr->sa_family == family_) {
if (strcmp(ifa->ifa_name, ifname_.c_str()) == 0) {
ipaddr_ = inet_ntoa(((struct sockaddr_in*)ifa->ifa_addr)->sin_addr);
netmask_ = inet_ntoa(((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr);
cidrRaw = ((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr.s_addr;
unsigned int cidr = 0;
while (cidrRaw) {
cidr += cidrRaw & 1;
cidrRaw >>= 1;
}
cidr_ = cidr;
}
}
ifa = ifa->ifa_next;
}
freeifaddrs(ifaddr);
} else {
ipaddr_.clear();
netmask_.clear();
cidr_ = 0;
}
}
int waybar::modules::Network::netlinkRequest(int fd, void *req, int waybar::modules::Network::netlinkRequest(int fd, void *req,
uint32_t reqlen, uint32_t groups) uint32_t reqlen, uint32_t groups)
{ {

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,46 @@ 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;
uint16_t change = config_["scroll-step"].isUInt() ? config_["scroll-step"].asUInt() * 100 : 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,21 +128,34 @@ 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;
pa->desc_ = i->description; pa->desc_ = i->description;
pa->port_name_ = i->active_port->name; pa->port_name_ = i->active_port ? i->active_port->name : "Unknown";
pa->dp.emit(); pa->dp.emit();
} }
} }
@ -141,8 +207,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

@ -4,8 +4,8 @@
using namespace waybar::modules::SNI; using namespace waybar::modules::SNI;
Host::Host(Glib::Dispatcher* dp) Host::Host(Glib::Dispatcher* dp, const Json::Value &config)
: dp_(dp) : dp_(dp), config_(config)
{ {
GBusNameOwnerFlags flags = static_cast<GBusNameOwnerFlags>( GBusNameOwnerFlags flags = static_cast<GBusNameOwnerFlags>(
G_BUS_NAME_OWNER_FLAGS_NONE); G_BUS_NAME_OWNER_FLAGS_NONE);
@ -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(
@ -146,5 +147,5 @@ std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(
void Host::addRegisteredItem(const gchar* service) void Host::addRegisteredItem(const gchar* service)
{ {
auto [bus_name, object_path] = getBusNameAndObjectPath(service); auto [bus_name, object_path] = getBusNameAndObjectPath(service);
items.emplace_back(bus_name, object_path, dp_); items.emplace_back(bus_name, object_path, dp_, config_);
} }

View File

@ -4,9 +4,14 @@
#include <libdbusmenu-gtk/dbusmenu-gtk.h> #include <libdbusmenu-gtk/dbusmenu-gtk.h>
waybar::modules::SNI::Item::Item(std::string bn, std::string op, waybar::modules::SNI::Item::Item(std::string bn, std::string op,
Glib::Dispatcher *dp) 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())), dp_(dp) { effective_icon_size(0), image(Gtk::manage(new Gtk::Image())),
dp_(dp), config_(config)
{
if (config_["icon-size"].isUInt()) {
icon_size = config_["icon-size"].asUInt();
}
event_box.add(*image); event_box.add(*image);
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(
@ -20,8 +25,7 @@ waybar::modules::SNI::Item::Item(std::string bn, std::string op,
void waybar::modules::SNI::Item::proxyReady(GObject *obj, GAsyncResult *res, void waybar::modules::SNI::Item::proxyReady(GObject *obj, GAsyncResult *res,
gpointer data) { gpointer data) {
GError *error = nullptr; GError *error = nullptr;
SnItem *proxy = SnItem *proxy = sn_item_proxy_new_for_bus_finish(res, &error);
sn_item_proxy_new_for_bus_finish(res, &error);
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
g_error_free(error); g_error_free(error);
return; return;
@ -113,6 +117,7 @@ void waybar::modules::SNI::Item::getAll(GObject *obj, GAsyncResult *res,
item->icon_theme_path.c_str()); item->icon_theme_path.c_str());
} }
item->updateImage(); item->updateImage();
item->updateMenu();
item->dp_->emit(); item->dp_->emit();
// TODO: handle change // TODO: handle change
} }
@ -165,45 +170,56 @@ waybar::modules::SNI::Item::extractPixBuf(GVariant *variant) {
return Glib::RefPtr<Gdk::Pixbuf>{}; return Glib::RefPtr<Gdk::Pixbuf>{};
} }
void waybar::modules::SNI::Item::updateMenu()
{
event_box.set_tooltip_text(title);
if (gtk_menu == nullptr && !menu.empty()) {
auto dbmenu = dbusmenu_gtkmenu_new(bus_name.data(), menu.data());
if (dbmenu != nullptr) {
g_object_ref_sink(dbmenu);
gtk_menu = Glib::wrap(GTK_MENU(dbmenu), false);
gtk_menu->attach_to_widget(event_box);
}
}
}
void waybar::modules::SNI::Item::updateImage() void waybar::modules::SNI::Item::updateImage()
{ {
image->set_from_icon_name("image-missing", Gtk::ICON_SIZE_MENU);
image->set_pixel_size(icon_size);
if (!icon_name.empty()) { if (!icon_name.empty()) {
auto pixbuf = getIconByName(icon_name, icon_size); try {
if (pixbuf->gobj() == nullptr) {
// Try to find icons specified by path and filename // Try to find icons specified by path and filename
try { #ifdef FILESYSTEM_EXPERIMENTAL
pixbuf = Gdk::Pixbuf::create_from_file(icon_name); if (std::experimental::filesystem::exists(icon_name)) {
#else
if (std::filesystem::exists(icon_name)) {
#endif
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
// the tray // the tray
pixbuf->scale_simple(icon_size - 2, icon_size - 2, pixbuf = pixbuf->scale_simple(icon_size, icon_size,
Gdk::InterpType::INTERP_BILINEAR); Gdk::InterpType::INTERP_BILINEAR);
image->set(pixbuf);
} }
} catch (Glib::Error &e) { } else {
std::cerr << "Exception: " << e.what() << std::endl; image->set(getIconByName(icon_name, icon_size));
pixbuf = getIconByName("image-missing", icon_size);
} }
} catch (Glib::Error &e) {
std::cerr << "Exception: " << e.what() << std::endl;
} }
if (pixbuf->gobj() == nullptr) {
pixbuf = getIconByName("image-missing", icon_size);
}
image->set(pixbuf);
} else if (icon_pixmap) { } else if (icon_pixmap) {
// An icon extracted may be the wrong size for the tray
icon_pixmap = icon_pixmap->scale_simple(icon_size, icon_size,
Gdk::InterpType::INTERP_BILINEAR);
image->set(icon_pixmap); image->set(icon_pixmap);
} else {
image->set_from_icon_name("image-missing", Gtk::ICON_SIZE_MENU);
image->set_pixel_size(icon_size);
}
if (!menu.empty()) {
auto *dbmenu = dbusmenu_gtkmenu_new(bus_name.data(), menu.data());
if (dbmenu)
gtk_menu = Glib::wrap(GTK_MENU(dbmenu), false);
} }
} }
Glib::RefPtr<Gdk::Pixbuf> Glib::RefPtr<Gdk::Pixbuf>
waybar::modules::SNI::Item::getIconByName(std::string name, int request_size) { waybar::modules::SNI::Item::getIconByName(std::string name, int request_size) {
int icon_size = 0; int tmp_size = 0;
Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_default(); Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_default();
icon_theme->rescan_if_needed(); icon_theme->rescan_if_needed();
auto sizes = icon_theme->get_icon_sizes(name.c_str()); auto sizes = icon_theme->get_icon_sizes(name.c_str());
@ -211,41 +227,43 @@ waybar::modules::SNI::Item::getIconByName(std::string name, int request_size) {
for (auto const &size : sizes) { for (auto const &size : sizes) {
// -1 == scalable // -1 == scalable
if (size == request_size || size == -1) { if (size == request_size || size == -1) {
icon_size = request_size; tmp_size = request_size;
break; break;
} else if (size < request_size || size > icon_size) { } else if (size < request_size || size > tmp_size) {
icon_size = size; tmp_size = size;
} }
} }
if (icon_size == 0) { if (tmp_size == 0) {
icon_size = request_size; tmp_size = request_size;
} }
return icon_theme->load_icon(name.c_str(), icon_size, return icon_theme->load_icon(name.c_str(), tmp_size,
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE); Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);
} }
void waybar::modules::SNI::Item::handleActivate(GObject *src, GAsyncResult *res, void waybar::modules::SNI::Item::handleActivate(GObject *src, GAsyncResult *res,
gpointer data) { gpointer data) {
auto item = static_cast<SNI::Item *>(data); auto item = static_cast<SNI::Item *>(data);
sn_item_call_activate_finish(item->proxy_, res, sn_item_call_activate_finish(item->proxy_, res, nullptr);
nullptr);
} }
void waybar::modules::SNI::Item::handleSecondaryActivate(GObject *src, void waybar::modules::SNI::Item::handleSecondaryActivate(GObject *src,
GAsyncResult *res, GAsyncResult *res,
gpointer data) { gpointer data) {
auto item = static_cast<SNI::Item *>(data); auto item = static_cast<SNI::Item *>(data);
sn_item_call_secondary_activate_finish(item->proxy_, sn_item_call_secondary_activate_finish(item->proxy_, res, nullptr);
res, nullptr);
} }
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

@ -3,11 +3,18 @@
#include <iostream> #include <iostream>
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), 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()) {
box_.set_spacing(config_["spacing"].asUInt());
}
}
auto waybar::modules::SNI::Tray::update() -> void { auto waybar::modules::SNI::Tray::update() -> void {
auto childrens = box_.get_children();
childrens.erase(childrens.begin(), childrens.end());
for (auto &item : host_.items) { for (auto &item : host_.items) {
item.event_box.set_tooltip_text(item.title);
box_.pack_start(item.event_box); box_.pack_start(item.event_box);
} }
if (box_.get_children().size() > 0) { if (box_.get_children().size() > 0) {
@ -18,4 +25,6 @@ auto waybar::modules::SNI::Tray::update() -> void {
} }
} }
waybar::modules::SNI::Tray::operator Gtk::Widget &() { return box_; } waybar::modules::SNI::Tray::operator Gtk::Widget &() {
return box_;
}

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

@ -41,8 +41,10 @@ auto waybar::modules::sway::Workspaces::update() -> void
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
for (auto it = buttons_.begin(); it != buttons_.end();) { for (auto it = buttons_.begin(); it != buttons_.end();) {
auto ws = std::find_if(workspaces_.begin(), workspaces_.end(), auto ws = std::find_if(workspaces_.begin(), workspaces_.end(),
[it](auto node) -> bool { return node["num"].asInt() == it->first; }); [it](auto node) -> bool { return node["name"].asString() == it->first; });
if (ws == workspaces_.end()) { if (ws == workspaces_.end() ||
(!config_["all-outputs"].asBool() &&
(*ws)["output"].asString() != bar_.output_name)) {
it = buttons_.erase(it); it = buttons_.erase(it);
needReorder = true; needReorder = true;
} else { } else {
@ -54,7 +56,7 @@ auto waybar::modules::sway::Workspaces::update() -> void
&& bar_.output_name != node["output"].asString()) { && bar_.output_name != node["output"].asString()) {
continue; continue;
} }
auto it = buttons_.find(node["num"].asInt()); auto it = buttons_.find(node["name"].asString());
if (it == buttons_.end()) { if (it == buttons_.end()) {
addWorkspace(node); addWorkspace(node);
needReorder = true; needReorder = true;
@ -103,7 +105,7 @@ void waybar::modules::sway::Workspaces::addWorkspace(Json::Value node)
fmt::arg("name", node["name"].asString()), fmt::arg("name", node["name"].asString()),
fmt::arg("index", node["num"].asString())) fmt::arg("index", node["num"].asString()))
: icon; : icon;
auto pair = buttons_.emplace(node["num"].asInt(), format); auto pair = buttons_.emplace(node["name"].asString(), format);
auto &button = pair.first->second; auto &button = pair.first->second;
box_.pack_start(button, false, false, 0); box_.pack_start(button, false, false, 0);
button.set_relief(Gtk::RELIEF_NONE); button.set_relief(Gtk::RELIEF_NONE);
@ -158,73 +160,73 @@ bool waybar::modules::sway::Workspaces::handleScroll(GdkEventScroll *e)
return false; return false;
} }
scrolling_ = true; scrolling_ = true;
int id = -1; std::string name;
uint16_t idx = 0; uint16_t idx = 0;
{ {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
for (; idx < workspaces_.size(); idx += 1) { for (; idx < workspaces_.size(); idx += 1) {
if (workspaces_[idx]["focused"].asBool()) { if (workspaces_[idx]["focused"].asBool()) {
id = workspaces_[idx]["num"].asInt(); name = workspaces_[idx]["name"].asString();
break; break;
} }
} }
} }
if (id == -1) { if (name.empty()) {
scrolling_ = false; scrolling_ = false;
return false; return false;
} }
if (e->direction == GDK_SCROLL_UP) { if (e->direction == GDK_SCROLL_UP) {
id = getNextWorkspace(); name = getNextWorkspace();
} }
if (e->direction == GDK_SCROLL_DOWN) { if (e->direction == GDK_SCROLL_DOWN) {
id = getPrevWorkspace(); name = getPrevWorkspace();
} }
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) {
id = getNextWorkspace(); name = getNextWorkspace();
} else if (delta_y > 0) { } else if (delta_y > 0) {
id = getPrevWorkspace(); name = getPrevWorkspace();
} }
} }
{ if (!name.empty()) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
if (id == workspaces_[idx]["num"].asInt()) { if (name == workspaces_[idx]["name"].asString()) {
scrolling_ = false; scrolling_ = false;
return false; return false;
} }
ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace \"{}\"", id)); ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace \"{}\"", name));
std::this_thread::sleep_for(std::chrono::milliseconds(150)); std::this_thread::sleep_for(std::chrono::milliseconds(150));
} }
return true; return true;
} }
int waybar::modules::sway::Workspaces::getPrevWorkspace() std::string waybar::modules::sway::Workspaces::getPrevWorkspace()
{ {
for (uint16_t i = 0; i != workspaces_.size(); i += 1) { for (uint16_t i = 0; i != workspaces_.size(); i += 1) {
if (workspaces_[i]["focused"].asBool()) { if (workspaces_[i]["focused"].asBool()) {
if (i > 0) { if (i > 0) {
return workspaces_[i - 1]["num"].asInt(); return workspaces_[i - 1]["name"].asString();
} }
return workspaces_[workspaces_.size() - 1]["num"].asInt(); return workspaces_[workspaces_.size() - 1]["name"].asString();
} }
} }
return -1; return "";
} }
int waybar::modules::sway::Workspaces::getNextWorkspace() std::string waybar::modules::sway::Workspaces::getNextWorkspace()
{ {
for (uint16_t i = 0; i != workspaces_.size(); i += 1) { for (uint16_t i = 0; i != workspaces_.size(); i += 1) {
if (workspaces_[i]["focused"].asBool()) { if (workspaces_[i]["focused"].asBool()) {
if (i + 1U < workspaces_.size()) { if (i + 1U < workspaces_.size()) {
return workspaces_[i + 1]["num"].asInt(); return workspaces_[i + 1]["name"].asString();
} }
return workspaces_[0]["num"].asInt(); return workspaces_[0]["String"].asString();
} }
} }
return -1; return "";
} }
waybar::modules::sway::Workspaces::operator Gtk::Widget &() { waybar::modules::sway::Workspaces::operator Gtk::Widget &() {

10
subprojects/fmt.wrap Normal file
View File

@ -0,0 +1,10 @@
[wrap-file]
directory = fmt-5.2.1
source_url = https://github.com/fmtlib/fmt/archive/5.2.1.tar.gz
source_filename = fmt-5.2.1.tar.gz
source_hash = 3c812a18e9f72a88631ab4732a97ce9ef5bcbefb3235e9fd465f059ba204359b
patch_url = https://wrapdb.mesonbuild.com/v1/projects/fmt/5.2.1/1/get_zip
patch_filename = fmt-5.2.1-1-wrap.zip
patch_hash = 7add08bb4e168c0809e88c6aa64ed5c3494b74deb6be12a93e1e4dc5bb3a1fc1

View File

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