Merge branch 'master' into river-tags-monitor-focus
This commit is contained in:
@@ -14,18 +14,17 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Test in FreeBSD VM
|
- name: Test in FreeBSD VM
|
||||||
uses: cross-platform-actions/action@v0.23.0
|
uses: cross-platform-actions/action@v0.25.0
|
||||||
timeout-minutes: 180
|
timeout-minutes: 180
|
||||||
env:
|
env:
|
||||||
CPPFLAGS: '-isystem/usr/local/include'
|
CPPFLAGS: '-isystem/usr/local/include'
|
||||||
LDFLAGS: '-L/usr/local/lib'
|
LDFLAGS: '-L/usr/local/lib'
|
||||||
with:
|
with:
|
||||||
operating_system: freebsd
|
operating_system: freebsd
|
||||||
version: "13.2"
|
version: "14.1"
|
||||||
environment_variables: CPPFLAGS LDFLAGS
|
environment_variables: CPPFLAGS LDFLAGS
|
||||||
sync_files: runner-to-vm
|
sync_files: runner-to-vm
|
||||||
run: |
|
run: |
|
||||||
sudo sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
|
|
||||||
sudo pkg install -y git # subprojects/date
|
sudo pkg install -y git # subprojects/date
|
||||||
sudo pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \
|
sudo pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \
|
||||||
libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \
|
libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \
|
||||||
|
|||||||
Generated
+3
-3
@@ -18,11 +18,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1719506693,
|
"lastModified": 1722185531,
|
||||||
"narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=",
|
"narHash": "sha256-veKR07psFoJjINLC8RK4DiLniGGMgF3QMlS4tb74S6k=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "b2852eb9365c6de48ffb0dc2c9562591f652242a",
|
"rev": "52ec9ac3b12395ad677e8b62106f0b98c1f8569d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
+2
-2
@@ -54,7 +54,7 @@ class BarIpcClient;
|
|||||||
}
|
}
|
||||||
#endif // HAVE_SWAY
|
#endif // HAVE_SWAY
|
||||||
|
|
||||||
class Bar {
|
class Bar : public sigc::trackable {
|
||||||
public:
|
public:
|
||||||
using bar_mode_map = std::map<std::string, struct bar_mode>;
|
using bar_mode_map = std::map<std::string, struct bar_mode>;
|
||||||
static const bar_mode_map PRESET_MODES;
|
static const bar_mode_map PRESET_MODES;
|
||||||
@@ -66,7 +66,7 @@ class Bar {
|
|||||||
~Bar();
|
~Bar();
|
||||||
|
|
||||||
void setMode(const std::string &mode);
|
void setMode(const std::string &mode);
|
||||||
void setVisible(bool visible);
|
void setVisible(bool value);
|
||||||
void toggle();
|
void toggle();
|
||||||
void handleSignal(int);
|
void handleSignal(int);
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ class Config {
|
|||||||
static std::optional<std::string> findConfigPath(
|
static std::optional<std::string> findConfigPath(
|
||||||
const std::vector<std::string> &names, const std::vector<std::string> &dirs = CONFIG_DIRS);
|
const std::vector<std::string> &names, const std::vector<std::string> &dirs = CONFIG_DIRS);
|
||||||
|
|
||||||
|
static std::optional<std::string> tryExpandPath(const std::string &base,
|
||||||
|
const std::string &filename);
|
||||||
|
|
||||||
Config() = default;
|
Config() = default;
|
||||||
|
|
||||||
void load(const std::string &config);
|
void load(const std::string &config);
|
||||||
|
|||||||
+5
-1
@@ -12,7 +12,7 @@ namespace waybar {
|
|||||||
class Group : public AModule {
|
class Group : public AModule {
|
||||||
public:
|
public:
|
||||||
Group(const std::string &, const std::string &, const Json::Value &, bool);
|
Group(const std::string &, const std::string &, const Json::Value &, bool);
|
||||||
virtual ~Group() = default;
|
~Group() override = default;
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
operator Gtk::Widget &() override;
|
operator Gtk::Widget &() override;
|
||||||
|
|
||||||
@@ -25,9 +25,13 @@ class Group : public AModule {
|
|||||||
Gtk::Revealer revealer;
|
Gtk::Revealer revealer;
|
||||||
bool is_first_widget = true;
|
bool is_first_widget = true;
|
||||||
bool is_drawer = false;
|
bool is_drawer = false;
|
||||||
|
bool click_to_reveal = false;
|
||||||
std::string add_class_to_drawer_children;
|
std::string add_class_to_drawer_children;
|
||||||
bool handleMouseEnter(GdkEventCrossing *const &ev) override;
|
bool handleMouseEnter(GdkEventCrossing *const &ev) override;
|
||||||
bool handleMouseLeave(GdkEventCrossing *const &ev) override;
|
bool handleMouseLeave(GdkEventCrossing *const &ev) override;
|
||||||
|
bool handleToggle(GdkEventButton *const &ev) override;
|
||||||
|
void show_group();
|
||||||
|
void hide_group();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class Network : public ALabel {
|
|||||||
void parseEssid(struct nlattr**);
|
void parseEssid(struct nlattr**);
|
||||||
void parseSignal(struct nlattr**);
|
void parseSignal(struct nlattr**);
|
||||||
void parseFreq(struct nlattr**);
|
void parseFreq(struct nlattr**);
|
||||||
|
void parseBssid(struct nlattr**);
|
||||||
bool associatedOrJoined(struct nlattr**);
|
bool associatedOrJoined(struct nlattr**);
|
||||||
bool checkInterface(std::string name);
|
bool checkInterface(std::string name);
|
||||||
auto getInfo() -> void;
|
auto getInfo() -> void;
|
||||||
@@ -69,6 +70,7 @@ class Network : public ALabel {
|
|||||||
|
|
||||||
std::string state_;
|
std::string state_;
|
||||||
std::string essid_;
|
std::string essid_;
|
||||||
|
std::string bssid_;
|
||||||
bool carrier_;
|
bool carrier_;
|
||||||
std::string ifname_;
|
std::string ifname_;
|
||||||
std::string ipaddr_;
|
std::string ipaddr_;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace waybar::modules::sway {
|
|||||||
class Workspaces : public AModule, public sigc::trackable {
|
class Workspaces : public AModule, public sigc::trackable {
|
||||||
public:
|
public:
|
||||||
Workspaces(const std::string&, const waybar::Bar&, const Json::Value&);
|
Workspaces(const std::string&, const waybar::Bar&, const Json::Value&);
|
||||||
virtual ~Workspaces() = default;
|
~Workspaces() override = default;
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -38,10 +38,10 @@ class Workspaces : public AModule, public sigc::trackable {
|
|||||||
Gtk::Button& addButton(const Json::Value&);
|
Gtk::Button& addButton(const Json::Value&);
|
||||||
void onButtonReady(const Json::Value&, Gtk::Button&);
|
void onButtonReady(const Json::Value&, Gtk::Button&);
|
||||||
std::string getIcon(const std::string&, const Json::Value&);
|
std::string getIcon(const std::string&, const Json::Value&);
|
||||||
const std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const;
|
std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const;
|
||||||
uint16_t getWorkspaceIndex(const std::string& name) const;
|
uint16_t getWorkspaceIndex(const std::string& name) const;
|
||||||
std::string trimWorkspaceName(std::string);
|
static std::string trimWorkspaceName(std::string);
|
||||||
bool handleScroll(GdkEventScroll*) override;
|
bool handleScroll(GdkEventScroll* /*unused*/) override;
|
||||||
|
|
||||||
const Bar& bar_;
|
const Bar& bar_;
|
||||||
std::vector<Json::Value> workspaces_;
|
std::vector<Json::Value> workspaces_;
|
||||||
|
|||||||
@@ -24,6 +24,10 @@
|
|||||||
|
|
||||||
namespace waybar::modules::wlr {
|
namespace waybar::modules::wlr {
|
||||||
|
|
||||||
|
struct widget_geometry {
|
||||||
|
int x, y, w, h;
|
||||||
|
};
|
||||||
|
|
||||||
class Taskbar;
|
class Taskbar;
|
||||||
|
|
||||||
class Task {
|
class Task {
|
||||||
@@ -42,6 +46,7 @@ class Task {
|
|||||||
};
|
};
|
||||||
// made public so TaskBar can reorder based on configuration.
|
// made public so TaskBar can reorder based on configuration.
|
||||||
Gtk::Button button;
|
Gtk::Button button;
|
||||||
|
struct widget_geometry minimize_hint;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uint32_t global_id;
|
static uint32_t global_id;
|
||||||
@@ -82,6 +87,8 @@ class Task {
|
|||||||
private:
|
private:
|
||||||
std::string repr() const;
|
std::string repr() const;
|
||||||
std::string state_string(bool = false) const;
|
std::string state_string(bool = false) const;
|
||||||
|
void set_minimize_hint();
|
||||||
|
void on_button_size_allocated(Gtk::Allocation &alloc);
|
||||||
void set_app_info_from_app_id_list(const std::string &app_id_list);
|
void set_app_info_from_app_id_list(const std::string &app_id_list);
|
||||||
bool image_load_icon(Gtk::Image &image, const Glib::RefPtr<Gtk::IconTheme> &icon_theme,
|
bool image_load_icon(Gtk::Image &image, const Glib::RefPtr<Gtk::IconTheme> &icon_theme,
|
||||||
Glib::RefPtr<Gio::DesktopAppInfo> app_info, int size);
|
Glib::RefPtr<Gio::DesktopAppInfo> app_info, int size);
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ struct formatter<pow_format> {
|
|||||||
template <>
|
template <>
|
||||||
struct formatter<Glib::ustring> : formatter<std::string> {
|
struct formatter<Glib::ustring> : formatter<std::string> {
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const Glib::ustring& value, FormatContext& ctx) {
|
auto format(const Glib::ustring& value, FormatContext& ctx) const {
|
||||||
return formatter<std::string>::format(static_cast<std::string>(value), ctx);
|
return formatter<std::string>::format(static_cast<std::string>(value), ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -156,6 +156,8 @@ Addressed by *network*
|
|||||||
|
|
||||||
*{essid}*: Name (SSID) of the wireless network.
|
*{essid}*: Name (SSID) of the wireless network.
|
||||||
|
|
||||||
|
*{bssid}*: MAC address (BSSID) of the wireless access point.
|
||||||
|
|
||||||
*{signalStrength}*: Signal strength of the wireless network.
|
*{signalStrength}*: Signal strength of the wireless network.
|
||||||
|
|
||||||
*{signaldBm}*: Signal strength of the wireless network in dBm.
|
*{signaldBm}*: Signal strength of the wireless network in dBm.
|
||||||
|
|||||||
@@ -39,6 +39,40 @@ You can apply special styling to any module for when the cursor hovers it.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Setting cursor style
|
||||||
|
|
||||||
|
Most, if not all, module types support setting the `cursor` option. This is
|
||||||
|
configured in your `config.jsonc`. If set to `false`, when hovering the module a
|
||||||
|
"pointer"(as commonly known from web CSS styling `cursor: pointer`) style cursor
|
||||||
|
will not be shown. Default behavior is to indicate an interaction event is
|
||||||
|
available.
|
||||||
|
|
||||||
|
There are more cursor types to choose from by setting the `cursor` option to
|
||||||
|
a number, see Gdk3 official docs for all possible cursor types:
|
||||||
|
https://docs.gtk.org/gdk3/enum.CursorType.html.
|
||||||
|
However, note that not all cursor options listed may be available on
|
||||||
|
your system. If you attempt to use a cursor which is not available, the
|
||||||
|
application will crash.
|
||||||
|
|
||||||
|
Example of disabling pointer(`Gdk::Hand2`) cursor type on a custom module:
|
||||||
|
|
||||||
|
```
|
||||||
|
"custom/my-custom-module": {
|
||||||
|
...
|
||||||
|
"cursor": false,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example of setting cursor type to `Gdk::Boat`(according to
|
||||||
|
https://docs.gtk.org/gdk3/enum.CursorType.html#boat):
|
||||||
|
|
||||||
|
```
|
||||||
|
"custom/my-custom-module": {
|
||||||
|
...
|
||||||
|
"cursor": 8,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# SEE ALSO
|
# SEE ALSO
|
||||||
|
|
||||||
- *waybar(5)*
|
- *waybar(5)*
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ warp-on-scroll: ++
|
|||||||
Regex rules to map window class to an icon or preferred method of representation for a workspace's window.
|
Regex rules to map window class to an icon or preferred method of representation for a workspace's window.
|
||||||
Keys are the rules, while the values are the methods of representation.
|
Keys are the rules, while the values are the methods of representation.
|
||||||
Rules may specify `class<...>`, `title<...>`, or both in order to fine-tune the matching.
|
Rules may specify `class<...>`, `title<...>`, or both in order to fine-tune the matching.
|
||||||
|
You may assign an empty value to a rule to have it ignored from generating any representation in workspaces.
|
||||||
|
|
||||||
*window-rewrite-default*:
|
*window-rewrite-default*:
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
|
|||||||
@@ -278,6 +278,11 @@ A group may hide all but one element, showing them only on mouse hover. In order
|
|||||||
default: "hidden" ++
|
default: "hidden" ++
|
||||||
Defines the CSS class to be applied to the hidden elements.
|
Defines the CSS class to be applied to the hidden elements.
|
||||||
|
|
||||||
|
*click-to-reveal*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Whether left click should reveal the content rather than mouse over. Note that grouped modules may still process their own on-click events.
|
||||||
|
|
||||||
*transition-left-to-right*: ++
|
*transition-left-to-right*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: true ++
|
default: true ++
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
project(
|
project(
|
||||||
'waybar', 'cpp', 'c',
|
'waybar', 'cpp', 'c',
|
||||||
version: '0.10.3',
|
version: '0.10.4',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>= 0.59.0',
|
meson_version: '>= 0.59.0',
|
||||||
default_options : [
|
default_options : [
|
||||||
|
|||||||
+11
-1
@@ -6,6 +6,8 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <util/command.hpp>
|
#include <util/command.hpp>
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
ALabel::ALabel(const Json::Value& config, const std::string& name, const std::string& id,
|
ALabel::ALabel(const Json::Value& config, const std::string& name, const std::string& id,
|
||||||
@@ -61,6 +63,14 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
|
|||||||
try {
|
try {
|
||||||
// Check that the file exists
|
// Check that the file exists
|
||||||
std::string menuFile = config_["menu-file"].asString();
|
std::string menuFile = config_["menu-file"].asString();
|
||||||
|
|
||||||
|
// there might be "~" or "$HOME" in original path, try to expand it.
|
||||||
|
auto result = Config::tryExpandPath(menuFile, "");
|
||||||
|
if (!result.has_value()) {
|
||||||
|
throw std::runtime_error("Failed to expand file: " + menuFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
menuFile = result.value();
|
||||||
// Read the menu descriptor file
|
// Read the menu descriptor file
|
||||||
std::ifstream file(menuFile);
|
std::ifstream file(menuFile);
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
@@ -170,7 +180,7 @@ bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
|
|||||||
return AModule::handleToggle(e);
|
return AModule::handleToggle(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ALabel::handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data) {
|
void ALabel::handleGtkMenuEvent(GtkMenuItem* /*menuitem*/, gpointer data) {
|
||||||
waybar::util::command::res res = waybar::util::command::exec((char*)data, "GtkMenu");
|
waybar::util::command::res res = waybar::util::command::exec((char*)data, "GtkMenu");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-4
@@ -1,9 +1,13 @@
|
|||||||
#include "AModule.hpp"
|
#include "AModule.hpp"
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
#include <util/command.hpp>
|
#include <util/command.hpp>
|
||||||
|
|
||||||
|
#include "gdk/gdk.h"
|
||||||
|
#include "gdkmm/cursor.h"
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
AModule::AModule(const Json::Value& config, const std::string& name, const std::string& id,
|
AModule::AModule(const Json::Value& config, const std::string& name, const std::string& id,
|
||||||
@@ -64,6 +68,17 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std::
|
|||||||
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
||||||
event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &AModule::handleScroll));
|
event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &AModule::handleScroll));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Respect user configuration of cursor
|
||||||
|
if (config_.isMember("cursor")) {
|
||||||
|
if (config_["cursor"].isBool() && config_["cursor"].asBool()) {
|
||||||
|
setCursor(Gdk::HAND2);
|
||||||
|
} else if (config_["cursor"].isInt()) {
|
||||||
|
setCursor(Gdk::CursorType(config_["cursor"].asInt()));
|
||||||
|
} else {
|
||||||
|
spdlog::warn("unknown cursor option configured on module {}", name_);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AModule::~AModule() {
|
AModule::~AModule() {
|
||||||
@@ -91,9 +106,20 @@ auto AModule::doAction(const std::string& name) -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AModule::setCursor(Gdk::CursorType const& c) {
|
void AModule::setCursor(Gdk::CursorType const& c) {
|
||||||
auto cursor = Gdk::Cursor::create(c);
|
|
||||||
auto gdk_window = event_box_.get_window();
|
auto gdk_window = event_box_.get_window();
|
||||||
gdk_window->set_cursor(cursor);
|
if (gdk_window) {
|
||||||
|
auto cursor = Gdk::Cursor::create(c);
|
||||||
|
gdk_window->set_cursor(cursor);
|
||||||
|
} else {
|
||||||
|
// window may not be accessible yet, in this case,
|
||||||
|
// schedule another call for setting the cursor in 1 sec
|
||||||
|
Glib::signal_timeout().connect_seconds(
|
||||||
|
[this, c]() {
|
||||||
|
setCursor(c);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AModule::handleMouseEnter(GdkEventCrossing* const& e) {
|
bool AModule::handleMouseEnter(GdkEventCrossing* const& e) {
|
||||||
@@ -101,9 +127,11 @@ bool AModule::handleMouseEnter(GdkEventCrossing* const& e) {
|
|||||||
module->set_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
|
module->set_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasUserEvents_) {
|
// Default behavior indicating event availability
|
||||||
|
if (hasUserEvents_ && !config_.isMember("cursor")) {
|
||||||
setCursor(Gdk::HAND2);
|
setCursor(Gdk::HAND2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,9 +140,11 @@ bool AModule::handleMouseLeave(GdkEventCrossing* const& e) {
|
|||||||
module->unset_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
|
module->unset_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasUserEvents_) {
|
// Default behavior indicating event availability
|
||||||
|
if (hasUserEvents_ && !config_.isMember("cursor")) {
|
||||||
setCursor(Gdk::ARROW);
|
setCursor(Gdk::ARROW);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -404,7 +404,8 @@ void waybar::Bar::onMap(GdkEventAny* /*unused*/) {
|
|||||||
setPassThrough(passthrough_);
|
setPassThrough(passthrough_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::Bar::setVisible(bool visible) {
|
void waybar::Bar::setVisible(bool value) {
|
||||||
|
visible = value;
|
||||||
if (auto mode = config.get("mode", {}); mode.isString()) {
|
if (auto mode = config.get("mode", {}); mode.isString()) {
|
||||||
setMode(visible ? config["mode"].asString() : MODE_INVISIBLE);
|
setMode(visible ? config["mode"].asString() : MODE_INVISIBLE);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+2
-1
@@ -123,7 +123,8 @@ void waybar::Client::handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void waybar::Client::handleMonitorRemoved(Glib::RefPtr<Gdk::Monitor> monitor) {
|
void waybar::Client::handleMonitorRemoved(Glib::RefPtr<Gdk::Monitor> monitor) {
|
||||||
spdlog::debug("Output removed: {} {}", monitor->get_manufacturer().c_str(), monitor->get_model().c_str());
|
spdlog::debug("Output removed: {} {}", monitor->get_manufacturer().c_str(),
|
||||||
|
monitor->get_model().c_str());
|
||||||
/* This event can be triggered from wl_display_roundtrip called by GTK or our code.
|
/* This event can be triggered from wl_display_roundtrip called by GTK or our code.
|
||||||
* Defer destruction of bars for the output to the next iteration of the event loop to avoid
|
* Defer destruction of bars for the output to the next iteration of the event loop to avoid
|
||||||
* deleting objects referenced by currently executed code.
|
* deleting objects referenced by currently executed code.
|
||||||
|
|||||||
+2
-1
@@ -21,7 +21,8 @@ const std::vector<std::string> Config::CONFIG_DIRS = {
|
|||||||
|
|
||||||
const char *Config::CONFIG_PATH_ENV = "WAYBAR_CONFIG_DIR";
|
const char *Config::CONFIG_PATH_ENV = "WAYBAR_CONFIG_DIR";
|
||||||
|
|
||||||
std::optional<std::string> tryExpandPath(const std::string &base, const std::string &filename) {
|
std::optional<std::string> Config::tryExpandPath(const std::string &base,
|
||||||
|
const std::string &filename) {
|
||||||
fs::path path;
|
fs::path path;
|
||||||
|
|
||||||
if (!filename.empty()) {
|
if (!filename.empty()) {
|
||||||
|
|||||||
+29
-4
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
const Gtk::RevealerTransitionType getPreferredTransitionType(bool is_vertical) {
|
Gtk::RevealerTransitionType getPreferredTransitionType(bool is_vertical) {
|
||||||
/* The transition direction of a drawer is not actually determined by the transition type,
|
/* The transition direction of a drawer is not actually determined by the transition type,
|
||||||
* but rather by the order of 'box' and 'revealer_box':
|
* but rather by the order of 'box' and 'revealer_box':
|
||||||
* 'REVEALER_TRANSITION_TYPE_SLIDE_LEFT' and 'REVEALER_TRANSITION_TYPE_SLIDE_RIGHT'
|
* 'REVEALER_TRANSITION_TYPE_SLIDE_LEFT' and 'REVEALER_TRANSITION_TYPE_SLIDE_RIGHT'
|
||||||
@@ -62,6 +62,7 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value&
|
|||||||
const bool left_to_right = (drawer_config["transition-left-to-right"].isBool()
|
const bool left_to_right = (drawer_config["transition-left-to-right"].isBool()
|
||||||
? drawer_config["transition-left-to-right"].asBool()
|
? drawer_config["transition-left-to-right"].asBool()
|
||||||
: true);
|
: true);
|
||||||
|
click_to_reveal = drawer_config["click-to-reveal"].asBool();
|
||||||
|
|
||||||
auto transition_type = getPreferredTransitionType(vertical);
|
auto transition_type = getPreferredTransitionType(vertical);
|
||||||
|
|
||||||
@@ -83,18 +84,42 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value&
|
|||||||
event_box_.add(box);
|
event_box_.add(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Group::handleMouseEnter(GdkEventCrossing* const& e) {
|
void Group::show_group() {
|
||||||
box.set_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
|
box.set_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
|
||||||
revealer.set_reveal_child(true);
|
revealer.set_reveal_child(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::hide_group() {
|
||||||
|
box.unset_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
|
||||||
|
revealer.set_reveal_child(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Group::handleMouseEnter(GdkEventCrossing* const& e) {
|
||||||
|
if (!click_to_reveal) {
|
||||||
|
show_group();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Group::handleMouseLeave(GdkEventCrossing* const& e) {
|
bool Group::handleMouseLeave(GdkEventCrossing* const& e) {
|
||||||
box.unset_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
|
if (!click_to_reveal && e->detail != GDK_NOTIFY_INFERIOR) {
|
||||||
revealer.set_reveal_child(false);
|
hide_group();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Group::handleToggle(GdkEventButton* const& e) {
|
||||||
|
if (!click_to_reveal || e->button != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((box.get_state_flags() & Gtk::StateFlags::STATE_FLAG_PRELIGHT) != 0U) {
|
||||||
|
hide_group();
|
||||||
|
} else {
|
||||||
|
show_group();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
auto Group::update() -> void {
|
auto Group::update() -> void {
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,15 +163,16 @@ auto waybar::modules::Clock::update() -> void {
|
|||||||
// std::vformat doesn't support named arguments.
|
// std::vformat doesn't support named arguments.
|
||||||
m_tlpText_ =
|
m_tlpText_ =
|
||||||
std::regex_replace(m_tlpFmt_, std::regex("\\{" + kTZPlaceholder + "\\}"), tzText_);
|
std::regex_replace(m_tlpFmt_, std::regex("\\{" + kTZPlaceholder + "\\}"), tzText_);
|
||||||
m_tlpText_ =
|
m_tlpText_ = std::regex_replace(
|
||||||
std::regex_replace(m_tlpText_, std::regex("\\{" + kCldPlaceholder + "\\}"), cldText_);
|
m_tlpText_, std::regex("\\{" + kCldPlaceholder + "\\}"),
|
||||||
|
fmt_lib::vformat(m_locale_, cldText_, fmt_lib::make_format_args(shiftedNow)));
|
||||||
m_tlpText_ =
|
m_tlpText_ =
|
||||||
std::regex_replace(m_tlpText_, std::regex("\\{" + kOrdPlaceholder + "\\}"), ordText_);
|
std::regex_replace(m_tlpText_, std::regex("\\{" + kOrdPlaceholder + "\\}"), ordText_);
|
||||||
} else {
|
} else {
|
||||||
m_tlpText_ = m_tlpFmt_;
|
m_tlpText_ = m_tlpFmt_;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_tlpText_ = fmt_lib::vformat(m_locale_, m_tlpText_, fmt_lib::make_format_args(shiftedNow));
|
m_tlpText_ = fmt_lib::vformat(m_locale_, m_tlpText_, fmt_lib::make_format_args(now));
|
||||||
m_tooltip_->set_markup(m_tlpText_);
|
m_tooltip_->set_markup(m_tlpText_);
|
||||||
label_.trigger_tooltip_query();
|
label_.trigger_tooltip_query();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,9 +61,36 @@ std::tuple<std::vector<uint16_t>, std::string> waybar::modules::CpuUsage::getCpu
|
|||||||
std::vector<std::tuple<size_t, size_t>> curr_times = CpuUsage::parseCpuinfo();
|
std::vector<std::tuple<size_t, size_t>> curr_times = CpuUsage::parseCpuinfo();
|
||||||
std::string tooltip;
|
std::string tooltip;
|
||||||
std::vector<uint16_t> usage;
|
std::vector<uint16_t> usage;
|
||||||
|
|
||||||
|
if (curr_times.size() != prev_times.size()) {
|
||||||
|
// The number of CPUs has changed, eg. due to CPU hotplug
|
||||||
|
// We don't know which CPU came up or went down
|
||||||
|
// so only give total usage (if we can)
|
||||||
|
if (!curr_times.empty() && !prev_times.empty()) {
|
||||||
|
auto [curr_idle, curr_total] = curr_times[0];
|
||||||
|
auto [prev_idle, prev_total] = prev_times[0];
|
||||||
|
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);
|
||||||
|
tooltip = fmt::format("Total: {}%\nCores: (pending)", tmp);
|
||||||
|
usage.push_back(tmp);
|
||||||
|
} else {
|
||||||
|
tooltip = "(pending)";
|
||||||
|
usage.push_back(0);
|
||||||
|
}
|
||||||
|
prev_times = curr_times;
|
||||||
|
return {usage, tooltip};
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < curr_times.size(); ++i) {
|
for (size_t i = 0; i < curr_times.size(); ++i) {
|
||||||
auto [curr_idle, curr_total] = curr_times[i];
|
auto [curr_idle, curr_total] = curr_times[i];
|
||||||
auto [prev_idle, prev_total] = prev_times[i];
|
auto [prev_idle, prev_total] = prev_times[i];
|
||||||
|
if (i > 0 && (curr_total == 0 || prev_total == 0)) {
|
||||||
|
// This CPU is offline
|
||||||
|
tooltip = tooltip + fmt::format("\nCore{}: offline", i - 1);
|
||||||
|
usage.push_back(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const float delta_idle = curr_idle - prev_idle;
|
const float delta_idle = curr_idle - prev_idle;
|
||||||
const float delta_total = curr_total - prev_total;
|
const float delta_total = curr_total - prev_total;
|
||||||
uint16_t tmp = 100 * (1 - delta_idle / delta_total);
|
uint16_t tmp = 100 * (1 - delta_idle / delta_total);
|
||||||
|
|||||||
@@ -3,6 +3,23 @@
|
|||||||
#include "modules/cpu_usage.hpp"
|
#include "modules/cpu_usage.hpp"
|
||||||
|
|
||||||
std::vector<std::tuple<size_t, size_t>> waybar::modules::CpuUsage::parseCpuinfo() {
|
std::vector<std::tuple<size_t, size_t>> waybar::modules::CpuUsage::parseCpuinfo() {
|
||||||
|
// Get the "existing CPU count" from /sys/devices/system/cpu/present
|
||||||
|
// Probably this is what the user wants the offline CPUs accounted from
|
||||||
|
// For further details see:
|
||||||
|
// https://www.kernel.org/doc/html/latest/core-api/cpu_hotplug.html
|
||||||
|
const std::string sys_cpu_present_path = "/sys/devices/system/cpu/present";
|
||||||
|
size_t cpu_present_last = 0;
|
||||||
|
std::ifstream cpu_present_file(sys_cpu_present_path);
|
||||||
|
std::string cpu_present_text;
|
||||||
|
if (cpu_present_file.is_open()) {
|
||||||
|
getline(cpu_present_file, cpu_present_text);
|
||||||
|
// This is a comma-separated list of ranges, eg. 0,2-4,7
|
||||||
|
size_t last_separator = cpu_present_text.find_last_of("-,");
|
||||||
|
if (last_separator < cpu_present_text.size()) {
|
||||||
|
std::stringstream(cpu_present_text.substr(last_separator + 1)) >> cpu_present_last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const std::string data_dir_ = "/proc/stat";
|
const std::string data_dir_ = "/proc/stat";
|
||||||
std::ifstream info(data_dir_);
|
std::ifstream info(data_dir_);
|
||||||
if (!info.is_open()) {
|
if (!info.is_open()) {
|
||||||
@@ -10,14 +27,23 @@ std::vector<std::tuple<size_t, size_t>> waybar::modules::CpuUsage::parseCpuinfo(
|
|||||||
}
|
}
|
||||||
std::vector<std::tuple<size_t, size_t>> cpuinfo;
|
std::vector<std::tuple<size_t, size_t>> cpuinfo;
|
||||||
std::string line;
|
std::string line;
|
||||||
|
size_t current_cpu_number = -1; // First line is total, second line is cpu 0
|
||||||
while (getline(info, line)) {
|
while (getline(info, line)) {
|
||||||
if (line.substr(0, 3).compare("cpu") != 0) {
|
if (line.substr(0, 3).compare("cpu") != 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
size_t line_cpu_number;
|
||||||
|
if (current_cpu_number >= 0) {
|
||||||
|
std::stringstream(line.substr(3)) >> line_cpu_number;
|
||||||
|
while (line_cpu_number > current_cpu_number) {
|
||||||
|
// Fill in 0 for offline CPUs missing inside the lines of /proc/stat
|
||||||
|
cpuinfo.emplace_back(0, 0);
|
||||||
|
current_cpu_number++;
|
||||||
|
}
|
||||||
|
}
|
||||||
std::stringstream sline(line.substr(5));
|
std::stringstream sline(line.substr(5));
|
||||||
std::vector<size_t> times;
|
std::vector<size_t> times;
|
||||||
for (size_t time = 0; sline >> time; times.push_back(time))
|
for (size_t time = 0; sline >> time; times.push_back(time));
|
||||||
;
|
|
||||||
|
|
||||||
size_t idle_time = 0;
|
size_t idle_time = 0;
|
||||||
size_t total_time = 0;
|
size_t total_time = 0;
|
||||||
@@ -27,6 +53,14 @@ std::vector<std::tuple<size_t, size_t>> waybar::modules::CpuUsage::parseCpuinfo(
|
|||||||
total_time = std::accumulate(times.begin(), times.end(), 0);
|
total_time = std::accumulate(times.begin(), times.end(), 0);
|
||||||
}
|
}
|
||||||
cpuinfo.emplace_back(idle_time, total_time);
|
cpuinfo.emplace_back(idle_time, total_time);
|
||||||
|
current_cpu_number++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (cpu_present_last >= current_cpu_number) {
|
||||||
|
// Fill in 0 for offline CPUs missing after the lines of /proc/stat
|
||||||
|
cpuinfo.emplace_back(0, 0);
|
||||||
|
current_cpu_number++;
|
||||||
|
}
|
||||||
|
|
||||||
return cpuinfo;
|
return cpuinfo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,30 +148,18 @@ void IPC::unregisterForIPC(EventHandler* ev_handler) {
|
|||||||
std::string IPC::getSocket1Reply(const std::string& rq) {
|
std::string IPC::getSocket1Reply(const std::string& rq) {
|
||||||
// basically hyprctl
|
// basically hyprctl
|
||||||
|
|
||||||
struct addrinfo aiHints;
|
|
||||||
struct addrinfo* aiRes = nullptr;
|
|
||||||
const auto serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
|
const auto serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
|
||||||
if (serverSocket < 0) {
|
if (serverSocket < 0) {
|
||||||
spdlog::error("Hyprland IPC: Couldn't open a socket (1)");
|
throw std::runtime_error("Hyprland IPC: Couldn't open a socket (1)");
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&aiHints, 0, sizeof(struct addrinfo));
|
|
||||||
aiHints.ai_family = AF_UNSPEC;
|
|
||||||
aiHints.ai_socktype = SOCK_STREAM;
|
|
||||||
|
|
||||||
if (getaddrinfo("localhost", nullptr, &aiHints, &aiRes) != 0) {
|
|
||||||
spdlog::error("Hyprland IPC: Couldn't get host (2)");
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the instance signature
|
// get the instance signature
|
||||||
auto* instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
auto* instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||||
|
|
||||||
if (instanceSig == nullptr) {
|
if (instanceSig == nullptr) {
|
||||||
spdlog::error("Hyprland IPC: HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
|
throw std::runtime_error(
|
||||||
return "";
|
"Hyprland IPC: HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
|
||||||
}
|
}
|
||||||
|
|
||||||
sockaddr_un serverAddress = {0};
|
sockaddr_un serverAddress = {0};
|
||||||
@@ -182,14 +170,12 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
|
|||||||
// Use snprintf to copy the socketPath string into serverAddress.sun_path
|
// Use snprintf to copy the socketPath string into serverAddress.sun_path
|
||||||
if (snprintf(serverAddress.sun_path, sizeof(serverAddress.sun_path), "%s", socketPath.c_str()) <
|
if (snprintf(serverAddress.sun_path, sizeof(serverAddress.sun_path), "%s", socketPath.c_str()) <
|
||||||
0) {
|
0) {
|
||||||
spdlog::error("Hyprland IPC: Couldn't copy socket path (6)");
|
throw std::runtime_error("Hyprland IPC: Couldn't copy socket path (6)");
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(serverSocket, reinterpret_cast<sockaddr*>(&serverAddress), sizeof(serverAddress)) <
|
if (connect(serverSocket, reinterpret_cast<sockaddr*>(&serverAddress), sizeof(serverAddress)) <
|
||||||
0) {
|
0) {
|
||||||
spdlog::error("Hyprland IPC: Couldn't connect to " + socketPath + ". (3)");
|
throw std::runtime_error("Hyprland IPC: Couldn't connect to " + socketPath + ". (3)");
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sizeWritten = write(serverSocket, rq.c_str(), rq.length());
|
auto sizeWritten = write(serverSocket, rq.c_str(), rq.length());
|
||||||
|
|||||||
@@ -92,30 +92,39 @@ auto Window::update() -> void {
|
|||||||
|
|
||||||
auto Window::getActiveWorkspace() -> Workspace {
|
auto Window::getActiveWorkspace() -> Workspace {
|
||||||
const auto workspace = gIPC->getSocket1JsonReply("activeworkspace");
|
const auto workspace = gIPC->getSocket1JsonReply("activeworkspace");
|
||||||
assert(workspace.isObject());
|
|
||||||
return Workspace::parse(workspace);
|
if (workspace.isObject()) {
|
||||||
|
return Workspace::parse(workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
|
auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
|
||||||
const auto monitors = gIPC->getSocket1JsonReply("monitors");
|
const auto monitors = gIPC->getSocket1JsonReply("monitors");
|
||||||
assert(monitors.isArray());
|
if (monitors.isArray()) {
|
||||||
auto monitor = std::find_if(monitors.begin(), monitors.end(),
|
auto monitor = std::find_if(monitors.begin(), monitors.end(), [&](Json::Value monitor) {
|
||||||
[&](Json::Value monitor) { return monitor["name"] == monitorName; });
|
return monitor["name"] == monitorName;
|
||||||
if (monitor == std::end(monitors)) {
|
});
|
||||||
spdlog::warn("Monitor not found: {}", monitorName);
|
if (monitor == std::end(monitors)) {
|
||||||
return Workspace{-1, 0, "", ""};
|
spdlog::warn("Monitor not found: {}", monitorName);
|
||||||
}
|
return Workspace{-1, 0, "", ""};
|
||||||
const int id = (*monitor)["activeWorkspace"]["id"].asInt();
|
}
|
||||||
|
const int id = (*monitor)["activeWorkspace"]["id"].asInt();
|
||||||
|
|
||||||
const auto workspaces = gIPC->getSocket1JsonReply("workspaces");
|
const auto workspaces = gIPC->getSocket1JsonReply("workspaces");
|
||||||
assert(workspaces.isArray());
|
if (workspaces.isArray()) {
|
||||||
auto workspace = std::find_if(workspaces.begin(), workspaces.end(),
|
auto workspace = std::find_if(workspaces.begin(), workspaces.end(),
|
||||||
[&](Json::Value workspace) { return workspace["id"] == id; });
|
[&](Json::Value workspace) { return workspace["id"] == id; });
|
||||||
if (workspace == std::end(workspaces)) {
|
if (workspace == std::end(workspaces)) {
|
||||||
spdlog::warn("No workspace with id {}", id);
|
spdlog::warn("No workspace with id {}", id);
|
||||||
return Workspace{-1, 0, "", ""};
|
return Workspace{-1, 0, "", ""};
|
||||||
}
|
}
|
||||||
return Workspace::parse(*workspace);
|
return Workspace::parse(*workspace);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Window::Workspace::parse(const Json::Value& value) -> Window::Workspace {
|
auto Window::Workspace::parse(const Json::Value& value) -> Window::Workspace {
|
||||||
@@ -146,53 +155,54 @@ void Window::queryActiveWorkspace() {
|
|||||||
focused_ = true;
|
focused_ = true;
|
||||||
if (workspace_.windows > 0) {
|
if (workspace_.windows > 0) {
|
||||||
const auto clients = gIPC->getSocket1JsonReply("clients");
|
const auto clients = gIPC->getSocket1JsonReply("clients");
|
||||||
assert(clients.isArray());
|
if (clients.isArray()) {
|
||||||
auto activeWindow = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) {
|
auto activeWindow = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) {
|
||||||
return window["address"] == workspace_.last_window;
|
return window["address"] == workspace_.last_window;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (activeWindow == std::end(clients)) {
|
if (activeWindow == std::end(clients)) {
|
||||||
focused_ = false;
|
focused_ = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
windowData_ = WindowData::parse(*activeWindow);
|
windowData_ = WindowData::parse(*activeWindow);
|
||||||
updateAppIconName(windowData_.class_name, windowData_.initial_class_name);
|
updateAppIconName(windowData_.class_name, windowData_.initial_class_name);
|
||||||
std::vector<Json::Value> workspaceWindows;
|
std::vector<Json::Value> workspaceWindows;
|
||||||
std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspaceWindows),
|
std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspaceWindows),
|
||||||
[&](Json::Value window) {
|
[&](Json::Value window) {
|
||||||
return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool();
|
return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool();
|
||||||
});
|
});
|
||||||
swallowing_ =
|
swallowing_ =
|
||||||
std::any_of(workspaceWindows.begin(), workspaceWindows.end(), [&](Json::Value window) {
|
std::any_of(workspaceWindows.begin(), workspaceWindows.end(), [&](Json::Value window) {
|
||||||
return !window["swallowing"].isNull() && window["swallowing"].asString() != "0x0";
|
return !window["swallowing"].isNull() && window["swallowing"].asString() != "0x0";
|
||||||
});
|
});
|
||||||
std::vector<Json::Value> visibleWindows;
|
std::vector<Json::Value> visibleWindows;
|
||||||
std::copy_if(workspaceWindows.begin(), workspaceWindows.end(),
|
std::copy_if(workspaceWindows.begin(), workspaceWindows.end(),
|
||||||
std::back_inserter(visibleWindows),
|
std::back_inserter(visibleWindows),
|
||||||
[&](Json::Value window) { return !window["hidden"].asBool(); });
|
[&](Json::Value window) { return !window["hidden"].asBool(); });
|
||||||
solo_ = 1 == std::count_if(visibleWindows.begin(), visibleWindows.end(),
|
solo_ = 1 == std::count_if(visibleWindows.begin(), visibleWindows.end(),
|
||||||
[&](Json::Value window) { return !window["floating"].asBool(); });
|
[&](Json::Value window) { return !window["floating"].asBool(); });
|
||||||
allFloating_ = std::all_of(visibleWindows.begin(), visibleWindows.end(),
|
allFloating_ = std::all_of(visibleWindows.begin(), visibleWindows.end(),
|
||||||
[&](Json::Value window) { return window["floating"].asBool(); });
|
[&](Json::Value window) { return window["floating"].asBool(); });
|
||||||
fullscreen_ = windowData_.fullscreen;
|
fullscreen_ = windowData_.fullscreen;
|
||||||
|
|
||||||
// Fullscreen windows look like they are solo
|
// Fullscreen windows look like they are solo
|
||||||
if (fullscreen_) {
|
if (fullscreen_) {
|
||||||
solo_ = true;
|
solo_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grouped windows have a tab bar and therefore don't look fullscreen or solo
|
// Grouped windows have a tab bar and therefore don't look fullscreen or solo
|
||||||
if (windowData_.grouped) {
|
if (windowData_.grouped) {
|
||||||
fullscreen_ = false;
|
fullscreen_ = false;
|
||||||
solo_ = false;
|
solo_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (solo_) {
|
if (solo_) {
|
||||||
soloClass_ = windowData_.class_name;
|
soloClass_ = windowData_.class_name;
|
||||||
} else {
|
} else {
|
||||||
soloClass_ = "";
|
soloClass_ = "";
|
||||||
}
|
}
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
focused_ = false;
|
focused_ = false;
|
||||||
windowData_ = WindowData{};
|
windowData_ = WindowData{};
|
||||||
|
|||||||
+17
-3
@@ -332,8 +332,8 @@ auto waybar::modules::Network::update() -> void {
|
|||||||
getState(signal_strength_);
|
getState(signal_strength_);
|
||||||
|
|
||||||
auto text = fmt::format(
|
auto text = fmt::format(
|
||||||
fmt::runtime(format_), fmt::arg("essid", essid_), fmt::arg("signaldBm", signal_strength_dbm_),
|
fmt::runtime(format_), fmt::arg("essid", essid_), fmt::arg("bssid", bssid_),
|
||||||
fmt::arg("signalStrength", signal_strength_),
|
fmt::arg("signaldBm", signal_strength_dbm_), fmt::arg("signalStrength", signal_strength_),
|
||||||
fmt::arg("signalStrengthApp", signal_strength_app_), fmt::arg("ifname", ifname_),
|
fmt::arg("signalStrengthApp", signal_strength_app_), fmt::arg("ifname", ifname_),
|
||||||
fmt::arg("netmask", netmask_), fmt::arg("ipaddr", ipaddr_), fmt::arg("gwaddr", gwaddr_),
|
fmt::arg("netmask", netmask_), fmt::arg("ipaddr", ipaddr_), fmt::arg("gwaddr", gwaddr_),
|
||||||
fmt::arg("cidr", cidr_), fmt::arg("frequency", fmt::format("{:.1f}", frequency_)),
|
fmt::arg("cidr", cidr_), fmt::arg("frequency", fmt::format("{:.1f}", frequency_)),
|
||||||
@@ -364,7 +364,7 @@ auto waybar::modules::Network::update() -> void {
|
|||||||
}
|
}
|
||||||
if (!tooltip_format.empty()) {
|
if (!tooltip_format.empty()) {
|
||||||
auto tooltip_text = fmt::format(
|
auto tooltip_text = fmt::format(
|
||||||
fmt::runtime(tooltip_format), fmt::arg("essid", essid_),
|
fmt::runtime(tooltip_format), fmt::arg("essid", essid_), fmt::arg("bssid", bssid_),
|
||||||
fmt::arg("signaldBm", signal_strength_dbm_), fmt::arg("signalStrength", signal_strength_),
|
fmt::arg("signaldBm", signal_strength_dbm_), fmt::arg("signalStrength", signal_strength_),
|
||||||
fmt::arg("signalStrengthApp", signal_strength_app_), fmt::arg("ifname", ifname_),
|
fmt::arg("signalStrengthApp", signal_strength_app_), fmt::arg("ifname", ifname_),
|
||||||
fmt::arg("netmask", netmask_), fmt::arg("ipaddr", ipaddr_), fmt::arg("gwaddr", gwaddr_),
|
fmt::arg("netmask", netmask_), fmt::arg("ipaddr", ipaddr_), fmt::arg("gwaddr", gwaddr_),
|
||||||
@@ -407,6 +407,7 @@ void waybar::modules::Network::clearIface() {
|
|||||||
ifid_ = -1;
|
ifid_ = -1;
|
||||||
ifname_.clear();
|
ifname_.clear();
|
||||||
essid_.clear();
|
essid_.clear();
|
||||||
|
bssid_.clear();
|
||||||
ipaddr_.clear();
|
ipaddr_.clear();
|
||||||
gwaddr_.clear();
|
gwaddr_.clear();
|
||||||
netmask_.clear();
|
netmask_.clear();
|
||||||
@@ -481,6 +482,7 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
|
|||||||
} else {
|
} else {
|
||||||
// clear state related to WiFi connection
|
// clear state related to WiFi connection
|
||||||
net->essid_.clear();
|
net->essid_.clear();
|
||||||
|
net->bssid_.clear();
|
||||||
net->signal_strength_dbm_ = 0;
|
net->signal_strength_dbm_ = 0;
|
||||||
net->signal_strength_ = 0;
|
net->signal_strength_ = 0;
|
||||||
net->signal_strength_app_.clear();
|
net->signal_strength_app_.clear();
|
||||||
@@ -772,6 +774,7 @@ int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) {
|
|||||||
net->parseEssid(bss);
|
net->parseEssid(bss);
|
||||||
net->parseSignal(bss);
|
net->parseSignal(bss);
|
||||||
net->parseFreq(bss);
|
net->parseFreq(bss);
|
||||||
|
net->parseBssid(bss);
|
||||||
return NL_OK;
|
return NL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,6 +840,17 @@ void waybar::modules::Network::parseFreq(struct nlattr **bss) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void waybar::modules::Network::parseBssid(struct nlattr **bss) {
|
||||||
|
if (bss[NL80211_BSS_BSSID] != nullptr) {
|
||||||
|
auto bssid = static_cast<uint8_t *>(nla_data(bss[NL80211_BSS_BSSID]));
|
||||||
|
auto bssid_len = nla_len(bss[NL80211_BSS_BSSID]);
|
||||||
|
if (bssid_len == 6) {
|
||||||
|
bssid_ = fmt::format("{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", bssid[0], bssid[1], bssid[2], bssid[3],
|
||||||
|
bssid[4], bssid[5]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool waybar::modules::Network::associatedOrJoined(struct nlattr **bss) {
|
bool waybar::modules::Network::associatedOrJoined(struct nlattr **bss) {
|
||||||
if (bss[NL80211_BSS_STATUS] == nullptr) {
|
if (bss[NL80211_BSS_STATUS] == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ auto waybar::modules::Pulseaudio::update() -> void {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
label_.get_style_context()->remove_class("source-muted");
|
label_.get_style_context()->remove_class("source-muted");
|
||||||
if (config_["format-source-muted"].isString()) {
|
if (config_["format-source"].isString()) {
|
||||||
format_source = config_["format-source"].asString();
|
format_source = config_["format-source"].asString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,14 +14,14 @@
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct fmt::formatter<Glib::VariantBase> : formatter<std::string> {
|
struct fmt::formatter<Glib::VariantBase> : formatter<std::string> {
|
||||||
bool is_printable(const Glib::VariantBase& value) {
|
bool is_printable(const Glib::VariantBase& value) const {
|
||||||
auto type = value.get_type_string();
|
auto type = value.get_type_string();
|
||||||
/* Print only primitive (single character excluding 'v') and short complex types */
|
/* Print only primitive (single character excluding 'v') and short complex types */
|
||||||
return (type.length() == 1 && islower(type[0]) && type[0] != 'v') || value.get_size() <= 32;
|
return (type.length() == 1 && islower(type[0]) && type[0] != 'v') || value.get_size() <= 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const Glib::VariantBase& value, FormatContext& ctx) {
|
auto format(const Glib::VariantBase& value, FormatContext& ctx) const {
|
||||||
if (is_printable(value)) {
|
if (is_printable(value)) {
|
||||||
return formatter<std::string>::format(static_cast<std::string>(value.print()), ctx);
|
return formatter<std::string>::format(static_cast<std::string>(value.print()), ctx);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -67,10 +67,9 @@ gboolean Watcher::handleRegisterHost(Watcher* obj, GDBusMethodInvocation* invoca
|
|||||||
}
|
}
|
||||||
auto watch = gfWatchFind(obj->hosts_, bus_name, object_path);
|
auto watch = gfWatchFind(obj->hosts_, bus_name, object_path);
|
||||||
if (watch != nullptr) {
|
if (watch != nullptr) {
|
||||||
g_dbus_method_invocation_return_error(
|
g_warning("Status Notifier Host with bus name '%s' and object path '%s' is already registered",
|
||||||
invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
bus_name, object_path);
|
||||||
"Status Notifier Host with bus name '%s' and object path '%s' is already registered",
|
sn_watcher_complete_register_item(obj->watcher_, invocation);
|
||||||
bus_name, object_path);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
watch = gfWatchNew(GF_WATCH_TYPE_HOST, service, bus_name, object_path, obj);
|
watch = gfWatchNew(GF_WATCH_TYPE_HOST, service, bus_name, object_path, obj);
|
||||||
|
|||||||
@@ -11,15 +11,14 @@ namespace waybar::modules::sway {
|
|||||||
// Helper function to assign a number to a workspace, just like sway. In fact
|
// Helper function to assign a number to a workspace, just like sway. In fact
|
||||||
// this is taken quite verbatim from `sway/ipc-json.c`.
|
// this is taken quite verbatim from `sway/ipc-json.c`.
|
||||||
int Workspaces::convertWorkspaceNameToNum(std::string name) {
|
int Workspaces::convertWorkspaceNameToNum(std::string name) {
|
||||||
if (isdigit(name[0])) {
|
if (isdigit(name[0]) != 0) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
char *endptr = NULL;
|
char *endptr = nullptr;
|
||||||
long long parsed_num = strtoll(name.c_str(), &endptr, 10);
|
long long parsed_num = strtoll(name.c_str(), &endptr, 10);
|
||||||
if (errno != 0 || parsed_num > INT32_MAX || parsed_num < 0 || endptr == name.c_str()) {
|
if (errno != 0 || parsed_num > INT32_MAX || parsed_num < 0 || endptr == name.c_str()) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
|
||||||
return (int)parsed_num;
|
|
||||||
}
|
}
|
||||||
|
return (int)parsed_num;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -47,7 +46,7 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
|
|||||||
bar_(bar),
|
bar_(bar),
|
||||||
box_(bar.orientation, 0) {
|
box_(bar.orientation, 0) {
|
||||||
if (config["format-icons"]["high-priority-named"].isArray()) {
|
if (config["format-icons"]["high-priority-named"].isArray()) {
|
||||||
for (auto &it : config["format-icons"]["high-priority-named"]) {
|
for (const auto &it : config["format-icons"]["high-priority-named"]) {
|
||||||
high_priority_named_.push_back(it.asString());
|
high_priority_named_.push_back(it.asString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +69,7 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
|
|||||||
|
|
||||||
m_windowRewriteRules = waybar::util::RegexCollection(
|
m_windowRewriteRules = waybar::util::RegexCollection(
|
||||||
windowRewrite, m_windowRewriteDefault,
|
windowRewrite, m_windowRewriteDefault,
|
||||||
[this](std::string &window_rule) { return windowRewritePriorityFunction(window_rule); });
|
[](std::string &window_rule) { return windowRewritePriorityFunction(window_rule); });
|
||||||
ipc_.subscribe(R"(["workspace"])");
|
ipc_.subscribe(R"(["workspace"])");
|
||||||
ipc_.subscribe(R"(["window"])");
|
ipc_.subscribe(R"(["window"])");
|
||||||
ipc_.signal_event.connect(sigc::mem_fun(*this, &Workspaces::onEvent));
|
ipc_.signal_event.connect(sigc::mem_fun(*this, &Workspaces::onEvent));
|
||||||
@@ -125,18 +124,10 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
|
|||||||
std::copy(output["floating_nodes"].begin(), output["floating_nodes"].end(),
|
std::copy(output["floating_nodes"].begin(), output["floating_nodes"].end(),
|
||||||
std::back_inserter(workspaces_));
|
std::back_inserter(workspaces_));
|
||||||
}
|
}
|
||||||
if (config_["persistent_workspaces"].isObject()) {
|
|
||||||
spdlog::warn(
|
|
||||||
"persistent_workspaces is deprecated. Please change config to use "
|
|
||||||
"persistent-workspaces.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// adding persistent workspaces (as per the config file)
|
// adding persistent workspaces (as per the config file)
|
||||||
if (config_["persistent-workspaces"].isObject() ||
|
if (config_["persistent-workspaces"].isObject()) {
|
||||||
config_["persistent_workspaces"].isObject()) {
|
const Json::Value &p_workspaces = config_["persistent-workspaces"];
|
||||||
const Json::Value &p_workspaces = config_["persistent-workspaces"].isObject()
|
|
||||||
? config_["persistent-workspaces"]
|
|
||||||
: config_["persistent_workspaces"];
|
|
||||||
const std::vector<std::string> p_workspaces_names = p_workspaces.getMemberNames();
|
const std::vector<std::string> p_workspaces_names = p_workspaces.getMemberNames();
|
||||||
|
|
||||||
for (const std::string &p_w_name : p_workspaces_names) {
|
for (const std::string &p_w_name : p_workspaces_names) {
|
||||||
@@ -270,13 +261,17 @@ void Workspaces::updateWindows(const Json::Value &node, std::string &windows) {
|
|||||||
node["name"].isString()) {
|
node["name"].isString()) {
|
||||||
std::string title = g_markup_escape_text(node["name"].asString().c_str(), -1);
|
std::string title = g_markup_escape_text(node["name"].asString().c_str(), -1);
|
||||||
std::string windowClass = node["app_id"].asString();
|
std::string windowClass = node["app_id"].asString();
|
||||||
std::string windowReprKey = fmt::format("class<{}> title<{}>", windowClass, title);
|
|
||||||
std::string window = m_windowRewriteRules.get(windowReprKey);
|
// Only add window rewrites that can be looked up
|
||||||
// allow result to have formatting
|
if (!windowClass.empty()) {
|
||||||
window =
|
std::string windowReprKey = fmt::format("class<{}> title<{}>", windowClass, title);
|
||||||
fmt::format(fmt::runtime(window), fmt::arg("name", title), fmt::arg("class", windowClass));
|
std::string window = m_windowRewriteRules.get(windowReprKey);
|
||||||
windows.append(window);
|
// allow result to have formatting
|
||||||
windows.append(m_formatWindowSeperator);
|
window = fmt::format(fmt::runtime(window), fmt::arg("name", title),
|
||||||
|
fmt::arg("class", windowClass));
|
||||||
|
windows.append(window);
|
||||||
|
windows.append(m_formatWindowSeperator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (const Json::Value &child : node["nodes"]) {
|
for (const Json::Value &child : node["nodes"]) {
|
||||||
updateWindows(child, windows);
|
updateWindows(child, windows);
|
||||||
@@ -422,7 +417,7 @@ std::string Workspaces::getIcon(const std::string &name, const Json::Value &node
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Workspaces::handleScroll(GdkEventScroll *e) {
|
bool Workspaces::handleScroll(GdkEventScroll *e) {
|
||||||
if (gdk_event_get_pointer_emulated((GdkEvent *)e)) {
|
if (gdk_event_get_pointer_emulated((GdkEvent *)e) != 0) {
|
||||||
/**
|
/**
|
||||||
* Ignore emulated scroll events on window
|
* Ignore emulated scroll events on window
|
||||||
*/
|
*/
|
||||||
@@ -472,8 +467,7 @@ bool Workspaces::handleScroll(GdkEventScroll *e) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string Workspaces::getCycleWorkspace(std::vector<Json::Value>::iterator it,
|
std::string Workspaces::getCycleWorkspace(std::vector<Json::Value>::iterator it, bool prev) const {
|
||||||
bool prev) const {
|
|
||||||
if (prev && it == workspaces_.begin() && !config_["disable-scroll-wraparound"].asBool()) {
|
if (prev && it == workspaces_.begin() && !config_["disable-scroll-wraparound"].asBool()) {
|
||||||
return (*(--workspaces_.end()))["name"].asString();
|
return (*(--workspaces_.end()))["name"].asString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,7 +163,8 @@ void waybar::modules::Wireplumber::onDefaultNodesApiChanged(waybar::modules::Wir
|
|||||||
"[{}]: (onDefaultNodesApiChanged) - got the following default node: Node(name: {}, id: {})",
|
"[{}]: (onDefaultNodesApiChanged) - got the following default node: Node(name: {}, id: {})",
|
||||||
self->name_, defaultNodeName, defaultNodeId);
|
self->name_, defaultNodeName, defaultNodeId);
|
||||||
|
|
||||||
if (g_strcmp0(self->default_node_name_, defaultNodeName) == 0) {
|
if (g_strcmp0(self->default_node_name_, defaultNodeName) == 0 &&
|
||||||
|
self->node_id_ == defaultNodeId) {
|
||||||
spdlog::debug(
|
spdlog::debug(
|
||||||
"[{}]: (onDefaultNodesApiChanged) - Default node has not changed. Node(name: {}, id: {}). "
|
"[{}]: (onDefaultNodesApiChanged) - Default node has not changed. Node(name: {}, id: {}). "
|
||||||
"Ignoring.",
|
"Ignoring.",
|
||||||
|
|||||||
@@ -387,6 +387,11 @@ void Task::handle_title(const char *title) {
|
|||||||
hide_if_ignored();
|
hide_if_ignored();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Task::set_minimize_hint() {
|
||||||
|
zwlr_foreign_toplevel_handle_v1_set_rectangle(handle_, bar_.surface, minimize_hint.x,
|
||||||
|
minimize_hint.y, minimize_hint.w, minimize_hint.h);
|
||||||
|
}
|
||||||
|
|
||||||
void Task::hide_if_ignored() {
|
void Task::hide_if_ignored() {
|
||||||
if (tbar_->ignore_list().count(app_id_) || tbar_->ignore_list().count(title_)) {
|
if (tbar_->ignore_list().count(app_id_) || tbar_->ignore_list().count(title_)) {
|
||||||
ignored_ = true;
|
ignored_ = true;
|
||||||
@@ -447,6 +452,13 @@ void Task::handle_app_id(const char *app_id) {
|
|||||||
spdlog::debug("Couldn't find icon for {}", app_id_);
|
spdlog::debug("Couldn't find icon for {}", app_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Task::on_button_size_allocated(Gtk::Allocation &alloc) {
|
||||||
|
gtk_widget_translate_coordinates(GTK_WIDGET(button.gobj()), GTK_WIDGET(bar_.window.gobj()), 0, 0,
|
||||||
|
&minimize_hint.x, &minimize_hint.y);
|
||||||
|
minimize_hint.w = button.get_width();
|
||||||
|
minimize_hint.h = button.get_height();
|
||||||
|
}
|
||||||
|
|
||||||
void Task::handle_output_enter(struct wl_output *output) {
|
void Task::handle_output_enter(struct wl_output *output) {
|
||||||
if (ignored_) {
|
if (ignored_) {
|
||||||
spdlog::debug("{} is ignored", repr());
|
spdlog::debug("{} is ignored", repr());
|
||||||
@@ -457,6 +469,8 @@ void Task::handle_output_enter(struct wl_output *output) {
|
|||||||
|
|
||||||
if (!button_visible_ && (tbar_->all_outputs() || tbar_->show_output(output))) {
|
if (!button_visible_ && (tbar_->all_outputs() || tbar_->show_output(output))) {
|
||||||
/* The task entered the output of the current bar make the button visible */
|
/* The task entered the output of the current bar make the button visible */
|
||||||
|
button.signal_size_allocate().connect_notify(
|
||||||
|
sigc::mem_fun(this, &Task::on_button_size_allocated));
|
||||||
tbar_->add_button(button);
|
tbar_->add_button(button);
|
||||||
button.show();
|
button.show();
|
||||||
button_visible_ = true;
|
button_visible_ = true;
|
||||||
@@ -553,9 +567,11 @@ bool Task::handle_clicked(GdkEventButton *bt) {
|
|||||||
return true;
|
return true;
|
||||||
else if (action == "activate")
|
else if (action == "activate")
|
||||||
activate();
|
activate();
|
||||||
else if (action == "minimize")
|
else if (action == "minimize") {
|
||||||
|
set_minimize_hint();
|
||||||
minimize(!minimized());
|
minimize(!minimized());
|
||||||
else if (action == "minimize-raise") {
|
} else if (action == "minimize-raise") {
|
||||||
|
set_minimize_hint();
|
||||||
if (minimized())
|
if (minimized())
|
||||||
minimize(false);
|
minimize(false);
|
||||||
else if (active())
|
else if (active())
|
||||||
|
|||||||
@@ -144,6 +144,12 @@ void AudioBackend::sinkInfoCb(pa_context * /*context*/, const pa_sink_info *i, i
|
|||||||
if (!backend->ignored_sinks_.empty()) {
|
if (!backend->ignored_sinks_.empty()) {
|
||||||
for (const auto &ignored_sink : backend->ignored_sinks_) {
|
for (const auto &ignored_sink : backend->ignored_sinks_) {
|
||||||
if (ignored_sink == i->description) {
|
if (ignored_sink == i->description) {
|
||||||
|
if (i->name == backend->current_sink_name_) {
|
||||||
|
// If the current sink happens to be ignored it is never considered running
|
||||||
|
// so it will be replaced with another sink.
|
||||||
|
backend->current_sink_running_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,14 @@ std::string waybar::CssReloadHelper::findPath(const std::string& filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// File monitor does not work with symlinks, so resolve them
|
// File monitor does not work with symlinks, so resolve them
|
||||||
if (std::filesystem::is_symlink(result)) {
|
std::string original = result;
|
||||||
|
while (std::filesystem::is_symlink(result)) {
|
||||||
result = std::filesystem::read_symlink(result);
|
result = std::filesystem::read_symlink(result);
|
||||||
|
|
||||||
|
// prevent infinite cycle
|
||||||
|
if (result == original) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -52,10 +52,8 @@ TEST_CASE_METHOD(IPCTestFixture, "XDGRuntimeDirExistsNoHyprDir", "[getSocketFold
|
|||||||
REQUIRE(actualPath == expectedPath);
|
REQUIRE(actualPath == expectedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(IPCMock, "getSocket1JsonReply handles empty response", "[getSocket1JsonReply]") {
|
TEST_CASE_METHOD(IPCTestFixture, "getSocket1Reply throws on no socket", "[getSocket1Reply]") {
|
||||||
std::string request = "test_request";
|
std::string request = "test_request";
|
||||||
|
|
||||||
Json::Value jsonResponse = getSocket1JsonReply(request);
|
CHECK_THROWS(getSocket1Reply(request));
|
||||||
|
|
||||||
REQUIRE(jsonResponse.isNull());
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,4 +19,7 @@ class IPCMock : public IPCTestFixture {
|
|||||||
public:
|
public:
|
||||||
// Mock getSocket1Reply to return an empty string
|
// Mock getSocket1Reply to return an empty string
|
||||||
static std::string getSocket1Reply(const std::string& rq) { return ""; }
|
static std::string getSocket1Reply(const std::string& rq) { return ""; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const char* instanceSig = "instance_sig";
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user