Compare commits

..

45 Commits
0.2.1 ... 0.2.3

Author SHA1 Message Date
3691d84543 chore: v0.2.3 2018-12-18 17:42:35 +01:00
b554094c7e feat: args && class id 2018-12-18 17:30:54 +01:00
66ad2864c2 fix(Pulseaudio): use markup 2018-12-17 09:00:40 +01:00
c7b0639f32 fix(workspaces): check thread is running 2018-12-09 10:49:28 +01:00
0acc50264e fix(custom): failed getline after closed pipe 2018-12-08 13:57:56 +01:00
1b13f9e38c fix(custom): close endless scripts 2018-12-08 12:58:47 +01:00
7befd27059 fix: clock interval 2018-12-04 09:38:08 +01:00
2ec34e4adb feat: add $HOME to valid path 2018-12-03 20:12:34 +01:00
812a7a9861 fix: typo 2018-12-03 11:13:56 +01:00
1d96d57b75 feat: warn user about stopped endless custom module 2018-12-03 09:35:10 +01:00
691fb88057 refactor(modules): const bar 2018-12-01 00:10:41 +01:00
281bab4943 feat(ci): opensuse 2018-11-30 21:48:42 +01:00
8e93fd3ae0 revert: Update to new Sway IPC protocol 2018-11-29 09:50:00 +01:00
37c7e586d6 Merge pull request #110 from tokyovigilante/ipc-fix
Update to new Sway IPC protocol
2018-11-29 00:40:57 +01:00
3a5a470d90 Update to new Sway IPC protocol 2018-11-28 22:27:06 +00:00
c051b517ca Merge pull request #108 from SibrenVasse/spotify
fix(custom): fix conditional statement
2018-11-26 20:09:21 +01:00
a0cdef569b fix(custom): fix conditional statement 2018-11-26 19:35:03 +01:00
a123711a8d fix(network): disconnected forced interface 2018-11-25 21:32:50 +01:00
391a7de94a fix(window): escape window name 2018-11-25 15:21:00 +01:00
952d877652 Merge pull request #103 from SibrenVasse/spotify
Event based mediaplayer script
2018-11-24 18:13:08 +01:00
5356d25a9b Merge branch 'master' into spotify 2018-11-24 18:11:48 +01:00
65b9911df4 Merge pull request #105 from David96/master
Allow custom plugins that don't execute anything
2018-11-24 18:01:31 +01:00
2aed121903 Allow custom plugins that don't execute anything 2018-11-24 17:24:02 +01:00
08bfdda4cb revert(network): wait interface 2018-11-24 16:01:22 +01:00
8f8ec3b999 feat(Label): on-click-right 2018-11-24 15:56:16 +01:00
a17220054d feat(client): pefix module name on update error 2018-11-24 11:20:03 +01:00
4cc48b3cfd fix(client): catch error on update 2018-11-24 11:13:52 +01:00
087de4e956 refactor(client): lambda to method 2018-11-24 11:04:56 +01:00
2c2a0473f4 feat(client): throw when we don't have required resources files 2018-11-23 19:31:40 +01:00
2e1f8b2fc5 fix(network): check len of netlinkResponse 2018-11-23 17:52:10 +01:00
686bc4828e refactor(network): only get info when there is an interface 2018-11-23 17:46:14 +01:00
f6c2a8d9b7 fix(network): free the message instead of the socket 2018-11-23 17:42:26 +01:00
baa7f52e21 refactor(network): wait for new address 2018-11-23 16:04:29 +01:00
c4c0c01a2f feat(custom): event based mediaplayer script 2018-11-23 12:08:15 +01:00
2b05b8e69a chore: v0.2.2 2018-11-23 12:03:23 +01:00
ad7400d5ce refactor(ALabel): add interval 2018-11-23 11:57:37 +01:00
36652158ad refactor(tray): more cpp binding 2018-11-23 10:46:58 +01:00
8db94f7efd revert(ALabel): ref on format 2018-11-22 16:50:42 +01:00
aaaa17d94f fix(config): remove duplicate tray 2018-11-22 16:21:46 +01:00
0b1b0eb1a7 feat(tray): multiple hosts 2018-11-22 16:20:49 +01:00
f00be0b552 refactor(tray): remove useless variable 2018-11-22 15:51:55 +01:00
ba79b4d397 refactor(tray): cleanup and fixes 2018-11-22 15:47:23 +01:00
bd62c4cbc5 feat(Label): use set_markup 2018-11-21 20:49:09 +01:00
b3559328f1 fix(window): ellipsize 2018-11-20 23:24:33 +01:00
69fceb1c92 fix(tray): sigsev on click when multiple icons is available 2018-11-16 12:01:03 +01:00
47 changed files with 1863 additions and 513 deletions

View File

@ -6,6 +6,7 @@ services:
env:
- distro: debian
- distro: archlinux
- distro: opensuse
before_install:
- docker pull alexays/waybar:${distro}

5
Dockerfiles/opensuse Normal file
View File

@ -0,0 +1,5 @@
FROM opensuse/tumbleweed:latest
RUN zypper -n up && \
zypper -n install -t pattern devel_C_C++ && \
zypper -n install git meson clang libinput-devel libwayland-client0 libwayland-cursor0 wayland-protocols-devel wayland-devel Mesa-libEGL-devel Mesa-libGLESv2-devel libgbm-devel libxkbcommon-devel libudev-devel libpixman-1-0-devel gtkmm3-devel jsoncpp-devel

View File

@ -6,25 +6,26 @@
namespace waybar {
class ALabel : public IModule {
public:
ALabel(const Json::Value&, const std::string format);
public:
ALabel(const Json::Value &, const std::string format, uint16_t interval = 0);
virtual ~ALabel() = default;
virtual auto update() -> void;
virtual std::string getIcon(uint16_t, const std::string& alt = "");
virtual operator Gtk::Widget&();
virtual std::string getIcon(uint16_t, const std::string &alt = "");
virtual operator Gtk::Widget &();
protected:
protected:
Gtk::EventBox event_box_;
Gtk::Label label_;
const Json::Value& config_;
const Json::Value &config_;
std::string format_;
std::mutex mutex_;
const std::chrono::seconds interval_;
private:
bool handleToggle(GdkEventButton* const& ev);
bool handleScroll(GdkEventScroll*);
private:
bool handleToggle(GdkEventButton *const &ev);
bool handleScroll(GdkEventScroll *);
bool alt = false;
const std::string default_format_;
};
} // namespace waybar
} // namespace waybar

View File

@ -15,7 +15,7 @@ class Client {
Client(int argc, char *argv[]);
int main(int argc, char *argv[]);
Glib::RefPtr<Gtk::Application> gtk_app;
Gtk::Main gtk_main;
std::string css_file;
std::string config_file;
Glib::RefPtr<Gdk::Display> gdk_display;
@ -27,8 +27,9 @@ class Client {
std::vector<std::unique_ptr<Bar>> bars;
private:
void setupConfigs(const std::string& config, const std::string& style);
void bindInterfaces();
auto setupCss();
const std::string getValidPath(std::vector<std::string> paths);
static void handleGlobal(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version);

View File

@ -27,10 +27,10 @@ class Bar;
class Factory {
public:
Factory(Bar& bar, const Json::Value& config);
Factory(const Bar& bar, const Json::Value& config);
IModule* makeModule(const std::string &name) const;
private:
Bar& bar_;
const Bar& bar_;
const Json::Value& config_;
};

View File

@ -1,9 +1,9 @@
#pragma once
#ifdef FILESYSTEM_EXPERIMENTAL
#include <experimental/filesystem>
#include <experimental/filesystem>
#else
#include <filesystem>
#include <filesystem>
#endif
#include <fstream>
#include <iostream>
@ -23,15 +23,15 @@ namespace fs = std::filesystem;
class Battery : public ALabel {
public:
Battery(const Json::Value&);
Battery(const std::string&, const Json::Value&);
~Battery();
auto update() -> void;
private:
static inline const fs::path data_dir_ = "/sys/class/power_supply/";
void worker();
std::tuple<uint16_t, std::string> getInfos();
std::string getState(uint16_t);
const std::tuple<uint8_t, std::string> getInfos() const;
const std::string getState(uint8_t) const;
util::SleeperThread thread_;
util::SleeperThread thread_timer_;

View File

@ -9,7 +9,7 @@ namespace waybar::modules {
class Clock : public ALabel {
public:
Clock(const Json::Value&);
Clock(const std::string&, const Json::Value&);
auto update() -> void;
private:
waybar::util::SleeperThread thread_;

View File

@ -13,7 +13,7 @@ namespace waybar::modules {
class Cpu : public ALabel {
public:
Cpu(const Json::Value&);
Cpu(const std::string&, const Json::Value&);
auto update() -> void;
private:
static inline const std::string data_dir_ = "/proc/stat";

View File

@ -11,7 +11,8 @@ namespace waybar::modules {
class Custom : public ALabel {
public:
Custom(const std::string, const Json::Value&);
Custom(const std::string&, const Json::Value&);
~Custom();
auto update() -> void;
private:
void delayWorker();
@ -27,6 +28,7 @@ class Custom : public ALabel {
waybar::util::SleeperThread thread_;
waybar::util::command::res output_;
waybar::util::JsonParser parser_;
FILE* fp_;
};
}

View File

@ -9,7 +9,7 @@ namespace waybar::modules {
class Memory : public ALabel {
public:
Memory(const Json::Value&);
Memory(const std::string&, const Json::Value&);
auto update() -> void;
private:
static inline const std::string data_dir_ = "/proc/meminfo";

View File

@ -15,7 +15,7 @@ namespace waybar::modules {
class Network : public ALabel {
public:
Network(const Json::Value&);
Network(const std::string&, const Json::Value&);
~Network();
auto update() -> void;
private:

View File

@ -10,7 +10,7 @@ namespace waybar::modules {
class Pulseaudio : public ALabel {
public:
Pulseaudio(const Json::Value&);
Pulseaudio(const std::string&, const Json::Value&);
~Pulseaudio();
auto update() -> void;
private:

View File

@ -0,0 +1,41 @@
#pragma once
#include <gtkmm.h>
#include <json/json.h>
#include <tuple>
#include <dbus-status-notifier-watcher.h>
#include "modules/sni/item.hpp"
namespace waybar::modules::SNI {
class Host {
public:
Host(const std::size_t id, const Json::Value&,
const std::function<void(std::unique_ptr<Item>&)>&,
const std::function<void(std::unique_ptr<Item>&)>&);
~Host();
private:
void busAcquired(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring);
void nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring, const Glib::ustring&);
void nameVanished(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring);
static void proxyReady(GObject*, GAsyncResult*, gpointer);
static void registerHost(GObject*, GAsyncResult*, gpointer);
static void itemRegistered(SnWatcher*, const gchar*, gpointer);
static void itemUnregistered(SnWatcher*, const gchar*, gpointer);
std::tuple<std::string, std::string> getBusNameAndObjectPath(const std::string);
void addRegisteredItem(std::string service);
std::vector<std::unique_ptr<Item>> items_;
const std::string bus_name_;
const std::string object_path_;
std::size_t bus_name_id_;
std::size_t watcher_id_;
GCancellable* cancellable_ = nullptr;
SnWatcher* watcher_ = nullptr;
const Json::Value &config_;
const std::function<void(std::unique_ptr<Item>&)> on_add_;
const std::function<void(std::unique_ptr<Item>&)> on_remove_;
};
}

View File

@ -3,26 +3,27 @@
#include <dbus-status-notifier-item.h>
#include <gtkmm.h>
#include <json/json.h>
#include <libdbusmenu-gtk/dbusmenu-gtk.h>
#ifdef FILESYSTEM_EXPERIMENTAL
#include <experimental/filesystem>
#include <experimental/filesystem>
#else
#include <filesystem>
#include <filesystem>
#endif
namespace waybar::modules::SNI {
class Item {
public:
Item(std::string, std::string, Glib::Dispatcher*, Json::Value);
Item(std::string, std::string, const Json::Value&);
~Item() = default;
std::string bus_name;
std::string object_path;
Gtk::EventBox event_box;
int icon_size;
int effective_icon_size;
Gtk::Image *image;
Gtk::Menu *gtk_menu = nullptr;
Gtk::Image image;
Gtk::EventBox event_box;
std::string category;
std::string id;
std::string status;
@ -36,24 +37,23 @@ public:
std::string attention_movie_name;
std::string icon_theme_path;
std::string menu;
DbusmenuGtkMenu *dbus_menu = nullptr;
Gtk::Menu *gtk_menu = nullptr;
bool item_is_menu;
private:
static void proxyReady(GObject *obj, GAsyncResult *res, gpointer data);
static void getAll(GObject *obj, GAsyncResult *res, gpointer data);
static void handleActivate(GObject *, GAsyncResult *, gpointer);
static void handleSecondaryActivate(GObject *, GAsyncResult *, gpointer);
void updateImage();
void updateMenu();
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant *variant);
Glib::RefPtr<Gdk::Pixbuf> getIconByName(std::string name, int size);
static void onMenuDestroyed(Item *self);
bool makeMenu(GdkEventButton *const &ev);
bool handleClick(GdkEventButton *const & /*ev*/);
Glib::Dispatcher *dp_;
GCancellable *cancellable_ = nullptr;
SnItem *proxy_ = nullptr;
Json::Value config_;
};
} // namespace waybar::modules::SNI

View File

@ -1,38 +0,0 @@
#pragma once
#include <gtkmm.h>
#include <json/json.h>
#include <tuple>
#include <dbus-status-notifier-watcher.h>
#include "modules/sni/sni.hpp"
namespace waybar::modules::SNI {
class Host {
public:
Host(Glib::Dispatcher*, const Json::Value&);
std::vector<Item> items;
private:
static void busAcquired(GDBusConnection*, const gchar*, gpointer);
static void nameAppeared(GDBusConnection*, const gchar*, const gchar*,
gpointer);
static void nameVanished(GDBusConnection*, const gchar*, gpointer);
static void proxyReady(GObject*, GAsyncResult*, gpointer);
static void registerHost(GObject*, GAsyncResult*, gpointer);
static void itemRegistered(SnWatcher*, const gchar*, gpointer);
static void itemUnregistered(SnWatcher*, const gchar*, gpointer);
std::tuple<std::string, std::string> getBusNameAndObjectPath(const gchar*);
void addRegisteredItem(const gchar* service);
uint32_t bus_name_id_;
uint32_t watcher_id_;
std::string bus_name_;
std::string object_path_;
Glib::Dispatcher* dp_;
GCancellable* cancellable_ = nullptr;
SnWatcher* watcher_ = nullptr;
const Json::Value &config_;
};
}

View File

@ -2,19 +2,24 @@
#include <fmt/format.h>
#include <thread>
#include "bar.hpp"
#include "util/json.hpp"
#include "IModule.hpp"
#include "modules/sni/snw.hpp"
#include "modules/sni/snh.hpp"
#include "modules/sni/watcher.hpp"
#include "modules/sni/host.hpp"
namespace waybar::modules::SNI {
class Tray : public IModule {
public:
Tray(const Json::Value&);
Tray(const std::string&, const Json::Value&);
auto update() -> void;
operator Gtk::Widget &();
private:
void onAdd(std::unique_ptr<Item>& item);
void onRemove(std::unique_ptr<Item>& item);
static inline std::size_t nb_hosts_ = 0;
std::thread thread_;
const Json::Value& config_;
Gtk::Box box_;

View File

@ -8,7 +8,7 @@ namespace waybar::modules::SNI {
class Watcher {
public:
Watcher();
~Watcher();
~Watcher() = default;
private:
typedef enum { GF_WATCH_TYPE_HOST, GF_WATCH_TYPE_ITEM } GfWatchType;
@ -22,7 +22,7 @@ private:
guint watch_id;
} GfWatch;
static void busAcquired(GDBusConnection *, const gchar *, gpointer);
void busAcquired(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring);
static gboolean handleRegisterHost(Watcher *, GDBusMethodInvocation *,
const gchar *);
static gboolean handleRegisterItem(Watcher *, GDBusMethodInvocation *,

View File

@ -12,12 +12,12 @@ namespace waybar::modules::sway {
class Mode : public ALabel {
public:
Mode(waybar::Bar&, const Json::Value&);
Mode(const std::string&, const waybar::Bar&, const Json::Value&);
auto update() -> void;
private:
void worker();
Bar& bar_;
const Bar& bar_;
waybar::util::SleeperThread thread_;
util::JsonParser parser_;
Ipc ipc_;

View File

@ -13,14 +13,14 @@ namespace waybar::modules::sway {
class Window : public ALabel {
public:
Window(waybar::Bar&, const Json::Value&);
Window(const std::string&, const waybar::Bar&, const Json::Value&);
auto update() -> void;
private:
void worker();
std::tuple<int, std::string> getFocusedNode(Json::Value nodes);
void getFocusedWindow();
Bar& bar_;
const Bar& bar_;
waybar::util::SleeperThread thread_;
util::JsonParser parser_;
Ipc ipc_;

View File

@ -12,7 +12,7 @@ namespace waybar::modules::sway {
class Workspaces : public IModule {
public:
Workspaces(waybar::Bar&, const Json::Value&);
Workspaces(const std::string&, const waybar::Bar&, const Json::Value&);
auto update() -> void;
operator Gtk::Widget &();
private:
@ -23,7 +23,7 @@ class Workspaces : public IModule {
std::string getPrevWorkspace();
std::string getNextWorkspace();
Bar& bar_;
const Bar& bar_;
const Json::Value& config_;
waybar::util::SleeperThread thread_;
Gtk::Box box_;

View File

@ -23,35 +23,24 @@ struct SleeperThread {
SleeperThread() = default;
SleeperThread(std::function<void()> func)
: thread_{[this, func] {
while(true) {
{
std::lock_guard<std::mutex> lock(mutex_);
if (!do_run_) {
break;
}
}
func();
}
: do_run_(true), thread_{[this, func] {
while (do_run_) func();
}}
{}
SleeperThread& operator=(std::function<void()> func)
{
do_run_ = true;
thread_ = std::thread([this, func] {
while(true) {
{
std::lock_guard<std::mutex> lock(mutex_);
if (!do_run_) {
break;
}
}
func();
}
while (do_run_) func();
});
return *this;
}
bool isRunnging() const
{
return do_run_;
}
auto sleep_for(chrono::duration dur)
{
@ -74,21 +63,21 @@ struct SleeperThread {
{
do_run_ = false;
condvar_.notify_all();
if (thread_.joinable()) {
thread_.detach();
}
}
~SleeperThread()
{
stop();
if (thread_.joinable()) {
thread_.detach();
}
}
private:
bool do_run_ = false;
std::thread thread_;
std::condition_variable condvar_;
std::mutex mutex_;
bool do_run_ = true;
};
}

1264
include/util/clara.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
project(
'waybar', 'cpp', 'c',
version: '0.2.1',
version: '0.2.3',
license: 'MIT',
default_options : [
'cpp_std=c++17',
@ -9,7 +9,7 @@ project(
],
)
cpp_args = []
cpp_args = ['-DVERSION="@0@"'.format(meson.project_version())]
cpp_link_args = []
if false # libc++
@ -83,9 +83,9 @@ if dbusmenu_gtk.found()
add_project_arguments('-DHAVE_DBUSMENU', language: 'cpp')
src_files += files(
'src/modules/sni/tray.cpp',
'src/modules/sni/snw.cpp',
'src/modules/sni/snh.cpp',
'src/modules/sni/sni.cpp'
'src/modules/sni/watcher.cpp',
'src/modules/sni/host.cpp',
'src/modules/sni/item.cpp'
)
endif

View File

@ -1,78 +1,47 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.kde.StatusNotifierItem">
<interface name='org.kde.StatusNotifierItem'>
<annotation name="org.gtk.GDBus.C.Name" value="Item" />
<property name="Category" type="s" access="read"/>
<property name="Id" type="s" access="read"/>
<property name="Title" type="s" access="read"/>
<property name="Status" type="s" access="read"/>
<property name="WindowId" type="i" access="read"/>
<property name="Menu" type="o" access="read" />
<!-- main icon -->
<!-- names are preferred over pixmaps -->
<property name="IconName" type="s" access="read" />
<property name="IconThemePath" type="s" access="read" />
<!-- struct containing width, height and image data-->
<!-- implementation has been dropped as of now -->
<property name="IconPixmap" type="a(iiay)" access="read" />
<!-- not used in ayatana code, no test case so far -->
<property name="OverlayIconName" type="s" access="read"/>
<property name="OverlayIconPixmap" type="a(iiay)" access="read" />
<!-- Requesting attention icon -->
<property name="AttentionIconName" type="s" access="read"/>
<!--same definition as image-->
<property name="AttentionIconPixmap" type="a(iiay)" access="read" />
<!-- tooltip data -->
<!-- unimplemented as of now -->
<!--(iiay) is an image-->
<property name="ToolTip" type="(sa(iiay)ss)" access="read" />
<!-- interaction: actually, we do not use them. -->
<method name="Activate">
<arg name="x" type="i" direction="in"/>
<arg name="y" type="i" direction="in"/>
<method name='ContextMenu'>
<arg type='i' direction='in' name='x'/>
<arg type='i' direction='in' name='y'/>
</method>
<method name="SecondaryActivate">
<arg name="x" type="i" direction="in"/>
<arg name="y" type="i" direction="in"/>
<method name='Activate'>
<arg type='i' direction='in' name='x'/>
<arg type='i' direction='in' name='y'/>
</method>
<method name="Scroll">
<arg name="delta" type="i" direction="in"/>
<arg name="dir" type="s" direction="in"/>
<method name='SecondaryActivate'>
<arg type='i' direction='in' name='x'/>
<arg type='i' direction='in' name='y'/>
</method>
<!-- Signals: the client wants to change something in the status-->
<signal name="NewTitle"></signal>
<signal name="NewIcon"></signal>
<signal name="NewIconThemePath">
<arg type="s" name="icon_theme_path" direction="out" />
<method name='Scroll'>
<arg type='i' direction='in' name='delta'/>
<arg type='s' direction='in' name='orientation'/>
</method>
<signal name='NewTitle'/>
<signal name='NewIcon'/>
<signal name='NewAttentionIcon'/>
<signal name='NewOverlayIcon'/>
<signal name='NewToolTip'/>
<signal name='NewStatus'>
<arg type='s' name='status'/>
</signal>
<signal name="NewAttentionIcon"></signal>
<signal name="NewOverlayIcon"></signal>
<signal name="NewToolTip"></signal>
<signal name="NewStatus">
<arg name="status" type="s" />
</signal>
<!-- ayatana labels -->
<!-- These are commented out because GDBusProxy would otherwise require them,
but they are not available for KDE indicators
-->
<!--<signal name="XAyatanaNewLabel">
<arg type="s" name="label" direction="out" />
<arg type="s" name="guide" direction="out" />
</signal>
<property name="XAyatanaLabel" type="s" access="read" />
<property name="XAyatanaLabelGuide" type="s" access="read" />-->
</interface>
<property name='Category' type='s' access='read'/>
<property name='Id' type='s' access='read'/>
<property name='Title' type='s' access='read'/>
<property name='Status' type='s' access='read'/>
<property name='WindowId' type='u' access='read'/>
<property name='IconThemePath' type='s' access='read'/>
<property name='IconName' type='s' access='read'/>
<property name='IconPixmap' type='a(iiay)' access='read'/>
<property name='OverlayIconName' type='s' access='read'/>
<property name='OverlayIconPixmap' type='a(iiay)' access='read'/>
<property name='AttentionIconName' type='s' access='read'/>
<property name='AttentionIconPixmap' type='a(iiay)' access='read'/>
<property name='AttentionMovieName' type='s' access='read'/>
<property name='ToolTip' type='(sa(iiay)ss)' access='read'/>
<property name='Menu' type='o' access='read'/>
<property name='ItemIsMenu' type='b' access='read'/>
</interface>
</node>

View File

@ -24,10 +24,7 @@
// }
// },
"sway/mode": {
"format": "{}"
},
"sway/window": {
"max-length": 50
"format": "<span style=\"italic\">{}</span>"
},
"tray": {
// "icon-size": 21,
@ -81,8 +78,6 @@
"custom/spotify": {
"format": " {}",
"max-length": 40,
"interval": 30, // Remove this if your script is endless and write in loop
"exec": "$HOME/.config/waybar/mediaplayer.sh 2> /dev/null", // Script in resources folder
"exec-if": "pgrep spotify"
"exec": "$HOME/.config/waybar/mediaplayer.py 2> /dev/null" // Script in resources folder
}
}

View File

@ -0,0 +1,71 @@
#!/usr/bin/env python3
import sys
import signal
import gi
gi.require_version('Playerctl', '2.0')
from gi.repository import Playerctl, GLib
manager = Playerctl.PlayerManager()
loop = GLib.MainLoop()
def on_play(player, status, manager):
on_metadata(player, player.props.metadata, manager)
def on_metadata(player, metadata, manager):
track_info = ''
if player.props.player_name == 'spotify' and \
'mpris:trackid' in metadata.keys() and \
':ad:' in player.props.metadata['mpris:trackid']:
track_info = 'AD PLAYING'
elif player.get_artist() != '' and player.get_title() != '':
track_info = '{artist} - {title}'.format(artist=player.get_artist(),
title=player.get_title())
else:
sys.stdout.write('\n')
sys.stdout.flush()
return
if player.props.status == 'Playing':
sys.stdout.write(track_info + '\n')
else:
sys.stdout.write('' + track_info + '\n')
sys.stdout.flush()
def on_name_appeared(manager, name):
init_player(name)
def on_player_vanished(manager, player):
sys.stdout.write("\n")
sys.stdout.flush()
def init_player(name):
player = Playerctl.Player.new_from_name(name)
player.connect('playback-status', on_play, manager)
player.connect('metadata', on_metadata, manager)
manager.manage_player(player)
on_metadata(player, player.props.metadata, manager)
def signal_handler(sig, frame):
sys.stdout.write("\n")
sys.stdout.flush()
loop.quit()
sys.exit(0)
manager.connect('name-appeared', on_name_appeared)
manager.connect('player-vanished', on_player_vanished)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
for player in manager.props.player_names:
init_player(player)
loop.run()

View File

@ -1,7 +0,0 @@
#!/bin/sh
player_status=$(playerctl status 2> /dev/null)
if [ "$player_status" = "Playing" ]; then
echo "$(playerctl metadata artist) - $(playerctl metadata title)"
elif [ "$player_status" = "Paused" ]; then
echo "$(playerctl metadata artist) - $(playerctl metadata title)"
fi

View File

@ -3,10 +3,11 @@
#include <iostream>
waybar::ALabel::ALabel(const Json::Value& config, const std::string format)
waybar::ALabel::ALabel(const Json::Value& config, const std::string format, uint16_t interval)
: config_(config),
format_(config_["format"].isString() ? config_["format"].asString() : format),
default_format_(format_)
interval_(std::chrono::seconds(config_["interval"].isUInt()
? config_["interval"].asUInt() : interval)), default_format_(format_)
{
event_box_.add(label_);
if (config_["max-length"].isUInt()) {
@ -20,17 +21,12 @@ waybar::ALabel::ALabel(const Json::Value& config, const std::string format)
}
// configure events' user commands
if (config_["on-click"].isString()) {
if (config_["on-click"].isString() || config_["on-click-right"].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()) {
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, &ALabel::handleScroll));
@ -44,6 +40,8 @@ auto waybar::ALabel::update() -> void {
bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
if (config_["on-click"].isString() && e->button == 1) {
waybar::util::command::forkExec(config_["on-click"].asString());
} else if (config_["on-click-right"].isString() && e->button == 3) {
waybar::util::command::forkExec(config_["on-click-right"].asString());
} else {
alt = !alt;
if (alt) {

View File

@ -184,7 +184,13 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos)
if (pos == "modules-right") {
modules_right_.emplace_back(module);
}
module->dp.connect([module] { module->update(); });
module->dp.connect([module, &name] {
try {
module->update();
} catch (const std::exception& e) {
std::cerr << name.asString() + ": " + e.what() << std::endl;
}
});
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}

View File

@ -1,8 +1,9 @@
#include "client.hpp"
#include "util/clara.hpp"
#include <iostream>
waybar::Client::Client(int argc, char* argv[])
: gtk_app(Gtk::Application::create(argc, argv, "fr.arouillard.waybar")),
: gtk_main(argc, argv),
gdk_display(Gdk::Display::get_default())
{
if (!gdk_display) {
@ -12,36 +13,24 @@ waybar::Client::Client(int argc, char* argv[])
throw std::runtime_error("Bar need to run under Wayland");
}
wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj());
auto getFirstValidPath = [] (std::vector<std::string> possiblePaths) {
wordexp_t p;
}
for (const std::string &path: possiblePaths) {
if (wordexp(path.c_str(), &p, 0) == 0) {
if (access(*p.we_wordv, F_OK) == 0) {
std::string result = *p.we_wordv;
wordfree(&p);
return result;
}
const std::string waybar::Client::getValidPath(std::vector<std::string> paths)
{
wordexp_t p;
for (const std::string &path: paths) {
if (wordexp(path.c_str(), &p, 0) == 0) {
if (access(*p.we_wordv, F_OK) == 0) {
std::string result = *p.we_wordv;
wordfree(&p);
return result;
}
wordfree(&p);
}
}
return std::string();
};
config_file = getFirstValidPath({
"$XDG_CONFIG_HOME/waybar/config",
"$HOME/waybar/config",
"/etc/xdg/waybar/config",
"./resources/config",
});
css_file = getFirstValidPath({
"$XDG_CONFIG_HOME/waybar/style.css",
"$HOME/waybar/style.css",
"/etc/xdg/waybar/style.css",
"./resources/style.css",
});
std::cout << "Resources files: " + config_file + ", " + css_file << std::endl;
return std::string();
}
void waybar::Client::handleGlobal(void *data, struct wl_registry *registry,
@ -81,6 +70,28 @@ void waybar::Client::handleGlobalRemove(void* data,
}
}
void waybar::Client::setupConfigs(const std::string& config, const std::string& style)
{
config_file = config.empty() ? getValidPath({
"$XDG_CONFIG_HOME/waybar/config",
"$HOME/.config/waybar/config",
"$HOME/waybar/config",
"/etc/xdg/waybar/config",
"./resources/config",
}) : config;
css_file = style.empty() ? getValidPath({
"$XDG_CONFIG_HOME/waybar/style.css",
"$HOME/.config/waybar/style.css",
"$HOME/waybar/style.css",
"/etc/xdg/waybar/style.css",
"./resources/style.css",
}) : style;
if (css_file.empty() || config_file.empty()) {
throw std::runtime_error("Missing required resources files");
}
std::cout << "Resources files: " + config_file + ", " + css_file << std::endl;
}
void waybar::Client::bindInterfaces()
{
registry = wl_display_get_registry(wl_display);
@ -96,11 +107,32 @@ void waybar::Client::bindInterfaces()
wl_display_roundtrip(wl_display);
}
int waybar::Client::main(int /*argc*/, char* /*argv*/[])
int waybar::Client::main(int argc, char* argv[])
{
bool show_help = false;
bool show_version = false;
std::string config;
std::string style;
auto cli = clara::detail::Help(show_help)
| clara::detail::Opt(show_version)["-v"]["--version"]("Show version")
| clara::detail::Opt(config, "config")["-c"]["--config"]("Config path")
| clara::detail::Opt(style, "style")["-s"]["--style"]("Style path");
auto res = cli.parse(clara::detail::Args(argc, argv));
if (!res) {
std::cerr << "Error in command line: " << res.errorMessage() << std::endl;
return 1;
}
if (show_help) {
std::cout << cli << std::endl;
return 0;
}
if (show_version) {
std::cout << "Waybar v" << VERSION << std::endl;
return 0;
}
setupConfigs(config, style);
bindInterfaces();
gtk_app->hold();
gtk_app->run();
gtk_main.run();
bars.clear();
zxdg_output_manager_v1_destroy(xdg_output_manager);
zwlr_layer_shell_v1_destroy(layer_shell);

View File

@ -1,49 +1,51 @@
#include "factory.hpp"
waybar::Factory::Factory(Bar& bar, const Json::Value& config)
waybar::Factory::Factory(const Bar& bar, const Json::Value& config)
: bar_(bar), config_(config)
{}
waybar::IModule* waybar::Factory::makeModule(const std::string &name) const
{
try {
auto ref = name.substr(0, name.find("#"));
auto hash_pos = name.find("#");
auto ref = name.substr(0, hash_pos);
auto id = hash_pos != std::string::npos ? name.substr(hash_pos + 1) : "";
if (ref == "battery") {
return new waybar::modules::Battery(config_[name]);
return new waybar::modules::Battery(id, config_[name]);
}
#ifdef HAVE_SWAY
if (ref == "sway/mode") {
return new waybar::modules::sway::Mode(bar_, config_[name]);
return new waybar::modules::sway::Mode(id, bar_, config_[name]);
}
if (ref == "sway/workspaces") {
return new waybar::modules::sway::Workspaces(bar_, config_[name]);
return new waybar::modules::sway::Workspaces(id, bar_, config_[name]);
}
if (ref == "sway/window") {
return new waybar::modules::sway::Window(bar_, config_[name]);
return new waybar::modules::sway::Window(id, bar_, config_[name]);
}
#endif
if (ref == "memory") {
return new waybar::modules::Memory(config_[name]);
return new waybar::modules::Memory(id, config_[name]);
}
if (ref == "cpu") {
return new waybar::modules::Cpu(config_[name]);
return new waybar::modules::Cpu(id, config_[name]);
}
if (ref == "clock") {
return new waybar::modules::Clock(config_[name]);
return new waybar::modules::Clock(id, config_[name]);
}
#ifdef HAVE_DBUSMENU
if (ref == "tray") {
return new waybar::modules::SNI::Tray(config_[name]);
return new waybar::modules::SNI::Tray(id, config_[name]);
}
#endif
#ifdef HAVE_LIBNL
if (ref == "network") {
return new waybar::modules::Network(config_[name]);
return new waybar::modules::Network(id, config_[name]);
}
#endif
#ifdef HAVE_LIBPULSE
if (ref == "pulseaudio") {
return new waybar::modules::Pulseaudio(config_[name]);
return new waybar::modules::Pulseaudio(id, config_[name]);
}
#endif
if (ref.compare(0, 7, "custom/") == 0 && ref.size() > 7) {

View File

@ -15,7 +15,7 @@ int main(int argc, char* argv[])
waybar::client = &c;
std::signal(SIGUSR1, [] (int /*signal*/) {
for (auto& bar : waybar::client->bars) {
(*bar).toggle();
bar->toggle();
}
});

View File

@ -1,8 +1,12 @@
#include "modules/battery.hpp"
waybar::modules::Battery::Battery(const Json::Value& config)
: ALabel(config, "{capacity}%")
waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config)
: ALabel(config, "{capacity}%", 60)
{
label_.set_name("battery");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
try {
if (config_["bat"].isString()) {
auto dir = data_dir_ / config_["bat"].asString();
@ -46,9 +50,8 @@ void waybar::modules::Battery::worker()
{
// Trigger first values
update();
uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 60;
thread_timer_ = [this, interval] {
thread_.sleep_for(chrono::seconds(interval));
thread_timer_ = [this] {
thread_.sleep_for(interval_);
dp.emit();
};
thread_ = [this] {
@ -63,7 +66,7 @@ void waybar::modules::Battery::worker()
};
}
std::tuple<uint16_t, std::string> waybar::modules::Battery::getInfos()
const std::tuple<uint8_t, std::string> waybar::modules::Battery::getInfos() const
{
try {
uint16_t total = 0;
@ -86,10 +89,10 @@ std::tuple<uint16_t, std::string> waybar::modules::Battery::getInfos()
}
}
std::string waybar::modules::Battery::getState(uint16_t capacity)
const std::string waybar::modules::Battery::getState(uint8_t capacity) const
{
// Get current state
std::vector<std::pair<std::string, uint16_t>> states;
std::vector<std::pair<std::string, uint8_t>> states;
if (config_["states"].isObject()) {
for (auto it = config_["states"].begin(); it != config_["states"].end(); ++it) {
if (it->isUInt() && it.key().isString()) {
@ -101,16 +104,16 @@ std::string waybar::modules::Battery::getState(uint16_t capacity)
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()) {
std::string valid_state;
for (auto const& state : states) {
if (capacity <= state.second && valid_state.empty()) {
label_.get_style_context()->add_class(state.first);
validState = state.first;
valid_state = state.first;
} else {
label_.get_style_context()->remove_class(state.first);
}
}
return validState;
return valid_state;
}
auto waybar::modules::Battery::update() -> void
@ -132,11 +135,9 @@ auto waybar::modules::Battery::update() -> void
}
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),
label_.set_markup(fmt::format(format, fmt::arg("capacity", capacity),
fmt::arg("icon", getIcon(capacity))));
}
}

View File

@ -1,21 +1,25 @@
#include "modules/clock.hpp"
waybar::modules::Clock::Clock(const Json::Value& config)
: ALabel(config, "{:%H:%M}")
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
: ALabel(config, "{:%H:%M}", 60)
{
label_.set_name("clock");
uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 60;
thread_ = [this, interval] {
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
thread_ = [this] {
auto now = waybar::chrono::clock::now();
dp.emit();
auto timeout = std::chrono::floor<std::chrono::seconds>(now
+ std::chrono::seconds(interval));
thread_.sleep_until(timeout);
auto timeout = std::chrono::floor<std::chrono::seconds>(now + interval_);
auto time_s = std::chrono::time_point_cast<std::chrono::seconds>(timeout);
auto sub_m =
std::chrono::duration_cast<std::chrono::seconds>(time_s.time_since_epoch()).count() % interval_.count();
thread_.sleep_until(timeout - std::chrono::seconds(sub_m - 1));
};
}
auto waybar::modules::Clock::update() -> void
{
auto localtime = fmt::localtime(std::time(nullptr));
label_.set_text(fmt::format(format_, localtime));
label_.set_markup(fmt::format(format_, localtime));
}

View File

@ -1,28 +1,26 @@
#include "modules/cpu.hpp"
waybar::modules::Cpu::Cpu(const Json::Value& config)
: ALabel(config, "{usage}%")
waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config)
: ALabel(config, "{usage}%", 10)
{
label_.set_name("cpu");
uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 10;
thread_ = [this, interval] {
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
thread_ = [this] {
dp.emit();
thread_.sleep_for(chrono::seconds(interval));
thread_.sleep_for(interval_);
};
}
auto waybar::modules::Cpu::update() -> void
{
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;
}
// 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_markup(fmt::format(format_,
fmt::arg("load", cpu_load), fmt::arg("usage", cpu_usage)));
}
uint16_t waybar::modules::Cpu::getCpuLoad()

View File

@ -1,54 +1,65 @@
#include "modules/custom.hpp"
waybar::modules::Custom::Custom(const std::string name,
waybar::modules::Custom::Custom(const std::string& name,
const Json::Value& config)
: ALabel(config, "{}"), name_(name)
: ALabel(config, "{}"), name_(name), fp_(nullptr)
{
if (!config_["exec"].isString()) {
throw std::runtime_error(name_ + " has no exec path.");
label_.set_name("custom-" + name_);
if (config_["exec"].isString()) {
if (interval_.count() > 0) {
delayWorker();
} else {
continuousWorker();
}
}
if (config_["interval"].isUInt()) {
delayWorker();
} else {
continuousWorker();
dp.emit();
}
waybar::modules::Custom::~Custom()
{
if (fp_) {
pclose(fp_);
fp_ = nullptr;
}
}
void waybar::modules::Custom::delayWorker()
{
auto interval = config_["interval"].asUInt();
thread_ = [this, interval] {
thread_ = [this] {
bool can_update = true;
if (config_["exec-if"].isString()) {
auto res = waybar::util::command::exec(config_["exec-if"].asString());
if (res.exit_code != 0) {
can_update = false;
label_.hide();
label_.set_name("");
event_box_.hide();
}
}
if (can_update) {
output_ = waybar::util::command::exec(config_["exec"].asString());
dp.emit();
}
thread_.sleep_for(chrono::seconds(interval));
thread_.sleep_for(interval_);
};
}
void waybar::modules::Custom::continuousWorker()
{
auto cmd = config_["exec"].asString();
FILE* fp(popen(cmd.c_str(), "r"));
if (!fp) {
fp_ = popen(cmd.c_str(), "r");
if (!fp_) {
throw std::runtime_error("Unable to open " + cmd);
}
thread_ = [this, fp] {
thread_ = [this] {
char* buff = nullptr;
size_t len = 0;
if (getline(&buff, &len, fp) == -1) {
pclose(fp);
if (getline(&buff, &len, fp_) == -1) {
if (fp_) {
pclose(fp_);
fp_ = nullptr;
}
thread_.stop();
output_ = { 1, "" };
std::cerr << name_ + " just stopped, is it endless?" << std::endl;
dp.emit();
return;
}
@ -67,12 +78,9 @@ void waybar::modules::Custom::continuousWorker()
auto waybar::modules::Custom::update() -> void
{
// Hide label if output is empty
if (output_.out.empty() || output_.exit_code != 0) {
label_.hide();
label_.set_name("");
if (config_["exec"].isString() && (output_.out.empty() || output_.exit_code != 0)) {
event_box_.hide();
} else {
label_.set_name("custom-" + name_);
if (config_["return-type"].asString() == "json") {
parseOutputJson();
} else {
@ -80,7 +88,7 @@ auto waybar::modules::Custom::update() -> void
}
auto str = fmt::format(format_, text_);
label_.set_text(str);
label_.set_markup(str);
if (text_ == tooltip_) {
label_.set_tooltip_text(str);
} else {
@ -97,7 +105,7 @@ auto waybar::modules::Custom::update() -> void
prevclass_ = "";
}
label_.show();
event_box_.show();
}
}
@ -133,4 +141,4 @@ void waybar::modules::Custom::parseOutputJson()
class_ = parsed["class"].asString();
break;
}
}
}

View File

@ -1,12 +1,15 @@
#include "modules/memory.hpp"
waybar::modules::Memory::Memory(const Json::Value& config)
: ALabel(config, "{}%")
waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config)
: ALabel(config, "{}%", 30)
{
uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 30;
thread_ = [this, interval] {
label_.set_name("memory");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
thread_ = [this] {
dp.emit();
thread_.sleep_for(chrono::seconds(interval));
thread_.sleep_for(interval_);
};
}
@ -15,14 +18,12 @@ auto waybar::modules::Memory::update() -> void
parseMeminfo();
if (memtotal_ > 0 && memfree_ >= 0) {
int used_ram_percentage = 100 * (memtotal_ - memfree_) / memtotal_;
label_.set_text(fmt::format(format_, used_ram_percentage));
label_.set_markup(fmt::format(format_, used_ram_percentage));
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_name("memory");
label_.show();
event_box_.show();
} else {
label_.set_name("");
label_.hide();
event_box_.hide();
}
}

View File

@ -1,9 +1,13 @@
#include "modules/network.hpp"
waybar::modules::Network::Network(const Json::Value& config)
: ALabel(config, "{ifname}"), family_(AF_INET),
signal_strength_dbm_(0), signal_strength_(0)
waybar::modules::Network::Network(const std::string& id, const Json::Value& config)
: ALabel(config, "{ifname}", 60), family_(AF_INET),
cidr_(-1), signal_strength_dbm_(0), signal_strength_(0)
{
label_.set_name("network");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
sock_fd_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock_fd_ < 0) {
throw std::runtime_error("Can't open network socket");
@ -26,14 +30,12 @@ waybar::modules::Network::Network(const Json::Value& config)
char ifname[IF_NAMESIZE];
if_indextoname(ifid_, ifname);
ifname_ = ifname;
getInterfaceAddress();
}
}
initNL80211();
label_.set_name("network");
// Trigger first values
getInfo();
update();
dp.emit();
worker();
}
@ -47,8 +49,10 @@ void waybar::modules::Network::worker()
{
thread_ = [this] {
char buf[4096];
uint64_t len = netlinkResponse(sock_fd_, buf, sizeof(buf),
RTMGRP_LINK | RTMGRP_IPV4_IFADDR);
auto len = netlinkResponse(sock_fd_, buf, sizeof(buf), RTMGRP_LINK | RTMGRP_IPV4_IFADDR);
if (len == 0) {
return;
}
bool need_update = false;
for (auto nh = reinterpret_cast<struct nlmsghdr *>(buf); NLMSG_OK(nh, len);
nh = NLMSG_NEXT(nh, len)) {
@ -58,6 +62,9 @@ void waybar::modules::Network::worker()
if (nh->nlmsg_type == NLMSG_ERROR) {
continue;
}
if (nh->nlmsg_type == RTM_NEWADDR) {
need_update = true;
}
if (nh->nlmsg_type < RTM_NEWADDR) {
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
if (rtif->ifi_index == static_cast<int>(ifid_)) {
@ -76,18 +83,18 @@ void waybar::modules::Network::worker()
char ifname[IF_NAMESIZE];
if_indextoname(ifid_, ifname);
ifname_ = ifname;
getInterfaceAddress();
need_update = true;
}
}
if (need_update) {
getInfo();
if (ifid_ > 0) {
getInfo();
}
dp.emit();
}
};
uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 60;
thread_timer_ = [this, interval] {
thread_.sleep_for(std::chrono::seconds(interval));
thread_timer_ = [this] {
thread_.sleep_for(interval_);
if (ifid_ > 0) {
getInfo();
dp.emit();
@ -98,7 +105,7 @@ void waybar::modules::Network::worker()
auto waybar::modules::Network::update() -> void
{
auto format = format_;
if (ifid_ <= 0) {
if (ifid_ <= 0 || ipaddr_.empty()) {
format = config_["format-disconnected"].isString()
? config_["format-disconnected"].asString() : format;
label_.get_style_context()->add_class("disconnected");
@ -112,7 +119,7 @@ auto waybar::modules::Network::update() -> void
}
label_.get_style_context()->remove_class("disconnected");
}
label_.set_text(fmt::format(format,
label_.set_markup(fmt::format(format,
fmt::arg("essid", essid_),
fmt::arg("signaldBm", signal_strength_dbm_),
fmt::arg("signalStrength", signal_strength_),
@ -131,8 +138,12 @@ void waybar::modules::Network::disconnected()
ipaddr_.clear();
netmask_.clear();
cidr_ = 0;
ifname_.clear();
ifid_ = -1;
if (!config_["interface"].isString()) {
ifname_.clear();
ifid_ = -1;
}
// Need to wait otherwise we'll have the same information
thread_.sleep_for(std::chrono::seconds(1));
}
void waybar::modules::Network::initNL80211()
@ -320,13 +331,12 @@ int waybar::modules::Network::netlinkRequest(int fd, void *req,
int waybar::modules::Network::netlinkResponse(int fd, void *resp,
uint32_t resplen, uint32_t groups)
{
int ret;
struct sockaddr_nl sa = {};
sa.nl_family = AF_NETLINK;
sa.nl_groups = groups;
struct iovec iov = { resp, resplen };
struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 };
ret = recvmsg(fd, &msg, 0);
auto ret = recvmsg(fd, &msg, 0);
if (msg.msg_flags & MSG_TRUNC) {
return -1;
}
@ -419,9 +429,10 @@ bool waybar::modules::Network::associatedOrJoined(struct nlattr** bss)
auto waybar::modules::Network::getInfo() -> void
{
getInterfaceAddress();
struct nl_msg* nl_msg = nlmsg_alloc();
if (nl_msg == nullptr) {
nl_socket_free(sk_);
nlmsg_free(nl_msg);
return;
}
if (genlmsg_put(nl_msg, NL_AUTO_PORT, NL_AUTO_SEQ, nl80211_id_, 0, NLM_F_DUMP,

View File

@ -1,6 +1,6 @@
#include "modules/pulseaudio.hpp"
waybar::modules::Pulseaudio::Pulseaudio(const Json::Value &config)
waybar::modules::Pulseaudio::Pulseaudio(const std::string& id, const Json::Value &config)
: ALabel(config, "{volume}%"),
mainloop_(nullptr),
mainloop_api_(nullptr),
@ -10,6 +10,9 @@ waybar::modules::Pulseaudio::Pulseaudio(const Json::Value &config)
muted_(false),
scrolling_(false) {
label_.set_name("pulseaudio");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
mainloop_ = pa_threaded_mainloop_new();
if (mainloop_ == nullptr) {
throw std::runtime_error("pa_mainloop_new() failed.");
@ -207,7 +210,7 @@ auto waybar::modules::Pulseaudio::update() -> void
label_.get_style_context()->remove_class("muted");
label_.get_style_context()->add_class("bluetooth");
}
label_.set_label(
label_.set_markup(
fmt::format(format, fmt::arg("volume", volume_),
fmt::arg("icon", getIcon(volume_, getPortIcon()))));
label_.set_tooltip_text(desc_);

View File

@ -1,57 +1,53 @@
#include "modules/sni/snh.hpp"
#include "modules/sni/host.hpp"
#include <iostream>
using namespace waybar::modules::SNI;
Host::Host(Glib::Dispatcher* dp, const Json::Value &config)
: dp_(dp), config_(config)
Host::Host(const std::size_t id, const Json::Value &config,
const std::function<void(std::unique_ptr<Item>&)>& on_add,
const std::function<void(std::unique_ptr<Item>&)>& on_remove)
: bus_name_("org.kde.StatusNotifierHost-" + std::to_string(getpid()) + "-" + std::to_string(id)),
object_path_("/StatusNotifierHost/" + std::to_string(id)),
bus_name_id_(Gio::DBus::own_name(Gio::DBus::BusType::BUS_TYPE_SESSION, bus_name_,
sigc::mem_fun(*this, &Host::busAcquired))),
config_(config), on_add_(on_add), on_remove_(on_remove)
{
GBusNameOwnerFlags flags = static_cast<GBusNameOwnerFlags>(
G_BUS_NAME_OWNER_FLAGS_NONE);
bus_name_ = "org.kde.StatusNotifierHost-" + std::to_string(getpid());
object_path_ = "/StatusNotifierHost";
bus_name_id_ = g_bus_own_name(G_BUS_TYPE_SESSION,
bus_name_.c_str(), flags,
&Host::busAcquired, nullptr, nullptr, this, nullptr);
}
void Host::busAcquired(GDBusConnection* connection,
const gchar* name, gpointer data)
Host::~Host()
{
auto host = static_cast<SNI::Host *>(data);
host->watcher_id_ = g_bus_watch_name(
G_BUS_TYPE_SESSION,
"org.kde.StatusNotifierWatcher",
G_BUS_NAME_WATCHER_FLAGS_NONE,
&Host::nameAppeared, &Host::nameVanished, data, nullptr);
Gio::DBus::unwatch_name(bus_name_id_);
}
void Host::nameAppeared(GDBusConnection* connection,
const gchar* name, const gchar* name_owner, gpointer data)
void Host::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib::ustring name)
{
auto host = static_cast<SNI::Host *>(data);
if (host->cancellable_ != nullptr) {
watcher_id_ = Gio::DBus::watch_name(conn, "org.kde.StatusNotifierWatcher",
sigc::mem_fun(*this, &Host::nameAppeared), sigc::mem_fun(*this, &Host::nameVanished));
}
void Host::nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>& conn, const Glib::ustring name,
const Glib::ustring& name_owner)
{
if (cancellable_ != nullptr) {
// TODO
return;
}
host->cancellable_ = g_cancellable_new();
cancellable_ = g_cancellable_new();
sn_watcher_proxy_new(
connection,
conn->gobj(),
G_DBUS_PROXY_FLAGS_NONE,
"org.kde.StatusNotifierWatcher",
"/StatusNotifierWatcher",
host->cancellable_, &Host::proxyReady, data);
cancellable_, &Host::proxyReady, this);
}
void Host::nameVanished(GDBusConnection* connection,
const gchar* name, gpointer data)
void Host::nameVanished(const Glib::RefPtr<Gio::DBus::Connection>& conn, const Glib::ustring name)
{
auto host = static_cast<SNI::Host *>(data);
g_cancellable_cancel(host->cancellable_);
g_clear_object(&host->cancellable_);
g_clear_object(&host->watcher_);
host->items.clear();
g_cancellable_cancel(cancellable_);
g_clear_object(&cancellable_);
g_clear_object(&watcher_);
items_.clear();
}
void Host::proxyReady(GObject* src, GAsyncResult* res,
@ -105,8 +101,7 @@ void Host::registerHost(GObject* src, GAsyncResult* res,
g_strfreev(items);
}
void Host::itemRegistered(
SnWatcher* watcher, const gchar* service, gpointer data)
void Host::itemRegistered(SnWatcher* watcher, const gchar* service, gpointer data)
{
auto host = static_cast<SNI::Host *>(data);
host->addRegisteredItem(service);
@ -117,35 +112,28 @@ void Host::itemUnregistered(
{
auto host = static_cast<SNI::Host *>(data);
auto [bus_name, object_path] = host->getBusNameAndObjectPath(service);
for (auto it = host->items.begin(); it != host->items.end(); ++it) {
if (it->bus_name == bus_name && it->object_path == object_path) {
host->items.erase(it);
for (auto it = host->items_.begin(); it != host->items_.end(); ++it) {
if ((*it)->bus_name == bus_name && (*it)->object_path == object_path) {
host->on_remove_(*it);
host->items_.erase(it);
break;
}
}
host->dp_->emit();
}
std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(
const gchar* service)
const std::string service)
{
std::string bus_name;
std::string object_path;
gchar* tmp = g_strstr_len(service, -1, "/");
if (tmp != nullptr) {
gchar** str = g_strsplit(service, "/", 2);
bus_name = str[0];
object_path = tmp;
g_strfreev(str);
} else {
bus_name = service;
object_path = "/StatusNotifierItem";
auto it = service.find("/");
if (it != std::string::npos) {
return {service.substr(0, it), service.substr(it)};
}
return { bus_name, object_path };
return {service, "/StatusNotifierItem"};
}
void Host::addRegisteredItem(const gchar* service)
void Host::addRegisteredItem(std::string service)
{
auto [bus_name, object_path] = getBusNameAndObjectPath(service);
items.emplace_back(bus_name, object_path, dp_, config_);
items_.emplace_back(new Item(bus_name, object_path, config_));
on_add_(items_.back());
}

View File

@ -1,18 +1,14 @@
#include "modules/sni/sni.hpp"
#include "modules/sni/item.hpp"
#include <iostream>
#include <libdbusmenu-gtk/dbusmenu-gtk.h>
waybar::modules::SNI::Item::Item(std::string bn, std::string op,
Glib::Dispatcher *dp, Json::Value config)
: bus_name(bn), object_path(op), event_box(), icon_size(16),
effective_icon_size(0), image(Gtk::manage(new Gtk::Image())),
dp_(dp), config_(config)
waybar::modules::SNI::Item::Item(std::string bn, std::string op, const Json::Value& config)
: bus_name(bn), object_path(op), icon_size(16), effective_icon_size(0)
{
if (config_["icon-size"].isUInt()) {
icon_size = config_["icon-size"].asUInt();
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.signal_button_press_event().connect(
sigc::mem_fun(*this, &Item::handleClick));
@ -40,11 +36,10 @@ void waybar::modules::SNI::Item::proxyReady(GObject *obj, GAsyncResult *res,
auto conn = g_dbus_proxy_get_connection(G_DBUS_PROXY(proxy));
g_dbus_connection_call(conn, item->bus_name.c_str(),
item->object_path.c_str(),
"org.freedesktop.DBus.Properties", "GetAll",
g_variant_new("(s)", "org.kde.StatusNotifierItem"),
G_VARIANT_TYPE("(a{sv})"), G_DBUS_CALL_FLAGS_NONE, -1,
item->cancellable_, &Item::getAll, data);
item->object_path.c_str(), "org.freedesktop.DBus.Properties", "GetAll",
g_variant_new("(s)", "org.kde.StatusNotifierItem"),
G_VARIANT_TYPE("(a{sv})"), G_DBUS_CALL_FLAGS_NONE, -1, item->cancellable_,
&Item::getAll, data);
}
void waybar::modules::SNI::Item::getAll(GObject *obj, GAsyncResult *res,
@ -107,18 +102,16 @@ void waybar::modules::SNI::Item::getAll(GObject *obj, GAsyncResult *res,
g_variant_unref(properties);
if (item->id.empty() || item->category.empty() || item->status.empty()) {
std::cerr << "Invalid Status Notifier Item: " + item->bus_name + "," +
item->object_path
<< std::endl;
item->object_path << std::endl;
return;
}
if (!item->icon_theme_path.empty()) {
GtkIconTheme *icon_theme = gtk_icon_theme_get_default();
gtk_icon_theme_append_search_path(icon_theme,
item->icon_theme_path.c_str());
item->icon_theme_path.c_str());
}
item->updateImage();
item->updateMenu();
item->dp_->emit();
// item->event_box.set_tooltip_text(item->title);
// TODO: handle change
}
@ -170,23 +163,10 @@ waybar::modules::SNI::Item::extractPixBuf(GVariant *variant) {
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()
{
image->set_from_icon_name("image-missing", Gtk::ICON_SIZE_MENU);
image->set_pixel_size(icon_size);
image.set_from_icon_name("image-missing", Gtk::ICON_SIZE_MENU);
image.set_pixel_size(icon_size);
if (!icon_name.empty()) {
try {
// Try to find icons specified by path and filename
@ -201,10 +181,10 @@ void waybar::modules::SNI::Item::updateImage()
// the tray
pixbuf = pixbuf->scale_simple(icon_size, icon_size,
Gdk::InterpType::INTERP_BILINEAR);
image->set(pixbuf);
image.set(pixbuf);
}
} else {
image->set(getIconByName(icon_name, icon_size));
image.set(getIconByName(icon_name, icon_size));
}
} catch (Glib::Error &e) {
std::cerr << "Exception: " << e.what() << std::endl;
@ -213,7 +193,7 @@ void waybar::modules::SNI::Item::updateImage()
// 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);
}
}
@ -237,42 +217,49 @@ waybar::modules::SNI::Item::getIconByName(std::string name, int request_size) {
tmp_size = request_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,
gpointer data) {
auto item = static_cast<SNI::Item *>(data);
sn_item_call_activate_finish(item->proxy_, res, nullptr);
void waybar::modules::SNI::Item::onMenuDestroyed(Item *self)
{
self->gtk_menu = nullptr;
self->dbus_menu = nullptr;
}
void waybar::modules::SNI::Item::handleSecondaryActivate(GObject *src,
GAsyncResult *res,
gpointer data) {
auto item = static_cast<SNI::Item *>(data);
sn_item_call_secondary_activate_finish(item->proxy_, res, nullptr);
bool waybar::modules::SNI::Item::makeMenu(GdkEventButton *const &ev)
{
if (gtk_menu == nullptr) {
if (!menu.empty()) {
dbus_menu = dbusmenu_gtkmenu_new(bus_name.data(), menu.data());
if (dbus_menu != nullptr) {
g_object_ref_sink(G_OBJECT(dbus_menu));
g_object_weak_ref(G_OBJECT(dbus_menu), (GWeakNotify)onMenuDestroyed, this);
gtk_menu = Glib::wrap(GTK_MENU(dbus_menu));
gtk_menu->attach_to_widget(event_box);
}
}
}
if (gtk_menu != nullptr) {
#if GTK_CHECK_VERSION(3, 22, 0)
gtk_menu->popup_at_pointer(reinterpret_cast<GdkEvent*>(ev));
#else
gtk_menu->popup(ev->button, ev->time);
#endif
return true;
}
return false;
}
bool waybar::modules::SNI::Item::handleClick(GdkEventButton *const &ev) {
if (ev->type == GDK_BUTTON_PRESS) {
if (gtk_menu && gtk_menu->get_children().size() > 0) {
#if GTK_CHECK_VERSION(3, 22, 0)
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);
#endif
gtk_menu->set_state_flags(Gtk::STATE_FLAG_ACTIVE, false);
} else {
sn_item_call_activate(
proxy_, ev->x, ev->y, nullptr, &Item::handleActivate, this);
if ((ev->button == 1 && item_is_menu) || ev->button == 3) {
if (!makeMenu(ev)) {
return sn_item_call_context_menu_sync(proxy_, ev->x, ev->y, nullptr, nullptr);
}
} else if (ev->type == GDK_2BUTTON_PRESS) {
sn_item_call_secondary_activate(
proxy_, ev->x, ev->y, nullptr, &Item::handleSecondaryActivate, this);
} else {
return false;
} else if (ev->button == 1) {
return sn_item_call_activate_sync(proxy_, ev->x, ev->y, nullptr, nullptr);
} else if (ev->button == 2) {
return sn_item_call_secondary_activate_sync(proxy_, ev->x, ev->y,
nullptr, nullptr);
}
return true;
return false;
}

View File

@ -2,21 +2,31 @@
#include <iostream>
waybar::modules::SNI::Tray::Tray(const Json::Value &config)
: config_(config), watcher_(), host_(&dp, config)
waybar::modules::SNI::Tray::Tray(const std::string& id, const Json::Value &config)
: config_(config), watcher_(), host_(nb_hosts_, config,
std::bind(&Tray::onAdd, this, std::placeholders::_1),
std::bind(&Tray::onRemove, this, std::placeholders::_1))
{
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());
}
nb_hosts_ += 1;
}
void waybar::modules::SNI::Tray::onAdd(std::unique_ptr<Item>& item)
{
box_.pack_start(item->event_box);
dp.emit();
}
void waybar::modules::SNI::Tray::onRemove(std::unique_ptr<Item>& item)
{
box_.remove(item->event_box);
dp.emit();
}
auto waybar::modules::SNI::Tray::update() -> void {
auto childrens = box_.get_children();
childrens.erase(childrens.begin(), childrens.end());
for (auto &item : host_.items) {
box_.pack_start(item.event_box);
}
if (box_.get_children().size() > 0) {
box_.set_name("tray");
box_.show_all();

View File

@ -1,41 +1,32 @@
#include "modules/sni/snw.hpp"
#include "modules/sni/watcher.hpp"
#include <iostream>
using namespace waybar::modules::SNI;
Watcher::Watcher()
{
GBusNameOwnerFlags flags = static_cast<GBusNameOwnerFlags>(
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT
| G_BUS_NAME_OWNER_FLAGS_REPLACE);
bus_name_id_ = g_bus_own_name(G_BUS_TYPE_SESSION,
"org.kde.StatusNotifierWatcher", flags,
&Watcher::busAcquired, nullptr, nullptr, this, nullptr);
watcher_ = sn_watcher_skeleton_new();
sn_watcher_set_protocol_version(watcher_, 1);
}
Watcher::~Watcher()
: bus_name_id_(Gio::DBus::own_name(Gio::DBus::BusType::BUS_TYPE_SESSION,
"org.kde.StatusNotifierWatcher", sigc::mem_fun(*this, &Watcher::busAcquired),
Gio::DBus::SlotNameAcquired(), Gio::DBus::SlotNameLost(),
Gio::DBus::BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | Gio::DBus::BUS_NAME_OWNER_FLAGS_REPLACE)),
watcher_(sn_watcher_skeleton_new())
{
}
void Watcher::busAcquired(GDBusConnection* connection, const gchar* name,
gpointer data)
void Watcher::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib::ustring name)
{
GError* error = nullptr;
auto host = static_cast<SNI::Watcher*>(data);
g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(host->watcher_),
connection, "/StatusNotifierWatcher", &error);
g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(watcher_),
conn->gobj(), "/StatusNotifierWatcher", &error);
if (error != nullptr) {
std::cerr << error->message << std::endl;
g_error_free(error);
return;
}
g_signal_connect_swapped(host->watcher_, "handle-register-item",
G_CALLBACK(&Watcher::handleRegisterItem), data);
g_signal_connect_swapped(host->watcher_, "handle-register-host",
G_CALLBACK(&Watcher::handleRegisterHost), data);
g_signal_connect_swapped(watcher_, "handle-register-item",
G_CALLBACK(&Watcher::handleRegisterItem), this);
g_signal_connect_swapped(watcher_, "handle-register-host",
G_CALLBACK(&Watcher::handleRegisterHost), this);
}
gboolean Watcher::handleRegisterHost(Watcher* obj,

View File

@ -69,8 +69,7 @@ struct waybar::modules::sway::Ipc::ipc_response
size_t total = 0;
while (total < ipc_header_size_) {
ssize_t res =
::recv(fd, header.data() + total, ipc_header_size_ - total, 0);
auto res = ::recv(fd, header.data() + total, ipc_header_size_ - total, 0);
if (res <= 0) {
throw std::runtime_error("Unable to receive IPC response");
}
@ -81,8 +80,7 @@ struct waybar::modules::sway::Ipc::ipc_response
std::string payload;
payload.reserve(data32[0] + 1);
while (total < data32[0]) {
ssize_t res =
::recv(fd, payload.data() + total, data32[0] - total, 0);
auto res = ::recv(fd, payload.data() + total, data32[0] - total, 0);
if (res < 0) {
throw std::runtime_error("Unable to receive IPC response");
}
@ -131,4 +129,4 @@ struct waybar::modules::sway::Ipc::ipc_response
waybar::modules::sway::Ipc::handleEvent() const
{
return recv(fd_event_);
}
}

View File

@ -1,12 +1,17 @@
#include "modules/sway/mode.hpp"
waybar::modules::sway::Mode::Mode(Bar& bar, const Json::Value& config)
waybar::modules::sway::Mode::Mode(const std::string& id, const Bar& bar, const Json::Value& config)
: ALabel(config, "{}"), bar_(bar)
{
label_.set_name("mode");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
ipc_.connect();
ipc_.subscribe("[ \"mode\" ]");
// Launch worker
worker();
dp.emit();
}
void waybar::modules::sway::Mode::worker()
@ -24,7 +29,7 @@ void waybar::modules::sway::Mode::worker()
dp.emit();
}
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
std::cerr << "Mode: " << e.what() << std::endl;
}
};
}
@ -32,12 +37,10 @@ void waybar::modules::sway::Mode::worker()
auto waybar::modules::sway::Mode::update() -> void
{
if (mode_.empty()) {
label_.set_name("");
label_.hide();
event_box_.hide();
} else {
label_.set_name("mode");
label_.set_text(fmt::format(format_, mode_));
label_.set_markup(fmt::format(format_, mode_));
label_.set_tooltip_text(mode_);
label_.show();
event_box_.show();
}
}

View File

@ -1,9 +1,16 @@
#include "modules/sway/window.hpp"
waybar::modules::sway::Window::Window(Bar &bar, const Json::Value& config)
waybar::modules::sway::Window::Window(const std::string& id, const Bar &bar, const Json::Value& config)
: ALabel(config, "{}"), bar_(bar), windowId_(-1)
{
label_.set_name("window");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
if (label_.get_max_width_chars() == -1) {
label_.set_hexpand(true);
label_.set_ellipsize(Pango::EllipsizeMode::ELLIPSIZE_END);
}
ipc_.connect();
ipc_.subscribe("[\"window\",\"workspace\"]");
getFocusedWindow();
@ -19,7 +26,7 @@ void waybar::modules::sway::Window::worker()
auto parsed = parser_.parse(res.payload);
if ((parsed["change"] == "focus" || parsed["change"] == "title")
&& parsed["container"]["focused"].asBool()) {
window_ = parsed["container"]["name"].asString();
window_ = Glib::Markup::escape_text(parsed["container"]["name"].asString());
windowId_ = parsed["container"]["id"].asInt();
dp.emit();
} else if ((parsed["change"] == "close"
@ -32,14 +39,14 @@ void waybar::modules::sway::Window::worker()
dp.emit();
}
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
std::cerr << "Window: " << e.what() << std::endl;
}
};
}
auto waybar::modules::sway::Window::update() -> void
{
label_.set_text(fmt::format(format_, window_));
label_.set_markup(fmt::format(format_, window_));
label_.set_tooltip_text(window_);
}

View File

@ -1,10 +1,13 @@
#include "modules/sway/workspaces.hpp"
waybar::modules::sway::Workspaces::Workspaces(Bar& bar,
waybar::modules::sway::Workspaces::Workspaces(const std::string& id, const Bar& bar,
const Json::Value& config)
: bar_(bar), config_(config), scrolling_(false)
{
box_.set_name("workspaces");
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
ipc_.connect();
ipc_.subscribe("[ \"workspace\" ]");
// Launch worker
@ -20,7 +23,7 @@ void waybar::modules::sway::Workspaces::worker()
while (bar_.output_name.empty()) {
thread_.sleep_for(chrono::milliseconds(150));
}
} else if (!workspaces_.empty()) {
} else if (thread_.isRunnging() && !workspaces_.empty()) {
ipc_.handleEvent();
}
{
@ -30,7 +33,7 @@ void waybar::modules::sway::Workspaces::worker()
}
dp.emit();
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
std::cerr << "Workspaces: " << e.what() << std::endl;
}
};
}