Merge remote-tracking branch 'upstream/master'
This commit is contained in:
6
.github/workflows/clang-format.yml
vendored
6
.github/workflows/clang-format.yml
vendored
@ -7,11 +7,13 @@ concurrency:
|
|||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: DoozyX/clang-format-lint-action@v0.16.2
|
# TODO: bump to clang 19 release
|
||||||
|
# - uses: DoozyX/clang-format-lint-action@v0.18.2
|
||||||
|
- uses: DoozyX/clang-format-lint-action@558090054b3f39e3d6af24f0cd73b319535da809
|
||||||
name: clang-format
|
name: clang-format
|
||||||
with:
|
with:
|
||||||
source: "."
|
source: "."
|
||||||
|
2
.github/workflows/clang-tidy.yml.bak
vendored
2
.github/workflows/clang-tidy.yml.bak
vendored
@ -7,7 +7,7 @@ concurrency:
|
|||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: alexays/waybar:debian
|
image: alexays/waybar:debian
|
||||||
|
2
.github/workflows/freebsd.yml
vendored
2
.github/workflows/freebsd.yml
vendored
@ -7,7 +7,7 @@ concurrency:
|
|||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
clang:
|
build:
|
||||||
# Run actions in a FreeBSD VM on the ubuntu runner
|
# Run actions in a FreeBSD VM on the ubuntu runner
|
||||||
# https://github.com/actions/runner/issues/385 - for FreeBSD runner support
|
# https://github.com/actions/runner/issues/385 - for FreeBSD runner support
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
19
default.nix
19
default.nix
@ -1,10 +1,9 @@
|
|||||||
(import
|
(import (
|
||||||
(
|
let
|
||||||
let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in
|
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
||||||
fetchTarball {
|
in
|
||||||
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
fetchTarball {
|
||||||
sha256 = lock.nodes.flake-compat.locked.narHash;
|
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||||
}
|
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||||
)
|
}
|
||||||
{ src = ./.; }
|
) { src = ./.; }).defaultNix
|
||||||
).defaultNix
|
|
||||||
|
6
flake.lock
generated
6
flake.lock
generated
@ -18,11 +18,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1738142207,
|
"lastModified": 1745391562,
|
||||||
"narHash": "sha256-NGqpVVxNAHwIicXpgaVqJEJWeyqzoQJ9oc8lnK9+WC4=",
|
"narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "9d3ae807ebd2981d593cddd0080856873139aa40",
|
"rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
129
flake.nix
129
flake.nix
@ -9,47 +9,96 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, ... }:
|
outputs =
|
||||||
|
{ self, nixpkgs, ... }:
|
||||||
let
|
let
|
||||||
inherit (nixpkgs) lib;
|
inherit (nixpkgs) lib;
|
||||||
genSystems = func: lib.genAttrs [
|
genSystems =
|
||||||
"x86_64-linux"
|
func:
|
||||||
"aarch64-linux"
|
lib.genAttrs
|
||||||
]
|
[
|
||||||
(system: func (import nixpkgs {
|
"x86_64-linux"
|
||||||
inherit system;
|
"aarch64-linux"
|
||||||
overlays = with self.overlays; [
|
]
|
||||||
waybar
|
(
|
||||||
];
|
system:
|
||||||
}));
|
func (
|
||||||
|
import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
overlays = with self.overlays; [
|
||||||
|
waybar
|
||||||
|
];
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
mkDate = longDate: (lib.concatStringsSep "-" [
|
mkDate =
|
||||||
(builtins.substring 0 4 longDate)
|
longDate:
|
||||||
(builtins.substring 4 2 longDate)
|
(lib.concatStringsSep "-" [
|
||||||
(builtins.substring 6 2 longDate)
|
(builtins.substring 0 4 longDate)
|
||||||
]);
|
(builtins.substring 4 2 longDate)
|
||||||
|
(builtins.substring 6 2 longDate)
|
||||||
|
]);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
devShells = genSystems
|
devShells = genSystems (pkgs: {
|
||||||
(pkgs:
|
default = pkgs.mkShell {
|
||||||
{
|
name = "waybar-shell";
|
||||||
default =
|
|
||||||
pkgs.mkShell
|
|
||||||
{
|
|
||||||
name = "waybar-shell";
|
|
||||||
|
|
||||||
# inherit attributes from upstream nixpkgs derivation
|
# inherit attributes from upstream nixpkgs derivation
|
||||||
inherit (pkgs.waybar) buildInputs depsBuildBuild depsBuildBuildPropagated depsBuildTarget
|
inherit (pkgs.waybar)
|
||||||
depsBuildTargetPropagated depsHostHost depsHostHostPropagated depsTargetTarget
|
buildInputs
|
||||||
depsTargetTargetPropagated propagatedBuildInputs propagatedNativeBuildInputs strictDeps;
|
depsBuildBuild
|
||||||
|
depsBuildBuildPropagated
|
||||||
|
depsBuildTarget
|
||||||
|
depsBuildTargetPropagated
|
||||||
|
depsHostHost
|
||||||
|
depsHostHostPropagated
|
||||||
|
depsTargetTarget
|
||||||
|
depsTargetTargetPropagated
|
||||||
|
propagatedBuildInputs
|
||||||
|
propagatedNativeBuildInputs
|
||||||
|
strictDeps
|
||||||
|
;
|
||||||
|
|
||||||
# overrides for local development
|
# overrides for local development
|
||||||
nativeBuildInputs = pkgs.waybar.nativeBuildInputs ++ (with pkgs; [
|
nativeBuildInputs =
|
||||||
clang-tools
|
pkgs.waybar.nativeBuildInputs
|
||||||
gdb
|
++ (with pkgs; [
|
||||||
]);
|
nixfmt-rfc-style
|
||||||
|
clang-tools
|
||||||
|
gdb
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
formatter = genSystems (
|
||||||
|
pkgs:
|
||||||
|
pkgs.treefmt.withConfig {
|
||||||
|
settings = [
|
||||||
|
{
|
||||||
|
formatter = {
|
||||||
|
clang-format = {
|
||||||
|
options = [ "-i" ];
|
||||||
|
command = lib.getExe' pkgs.clang-tools "clang-format";
|
||||||
|
excludes = [ ];
|
||||||
|
includes = [
|
||||||
|
"*.c"
|
||||||
|
"*.cpp"
|
||||||
|
"*.h"
|
||||||
|
"*.hpp"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
});
|
nixfmt = {
|
||||||
|
command = lib.getExe pkgs.nixfmt-rfc-style;
|
||||||
|
includes = [ "*.nix" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
tree-root-file = ".git/index";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
overlays = {
|
overlays = {
|
||||||
default = self.overlays.waybar;
|
default = self.overlays.waybar;
|
||||||
@ -58,11 +107,15 @@
|
|||||||
waybar = prev.waybar;
|
waybar = prev.waybar;
|
||||||
# take the first "version: '...'" from meson.build
|
# take the first "version: '...'" from meson.build
|
||||||
version =
|
version =
|
||||||
(builtins.head (builtins.split "'"
|
(builtins.head (
|
||||||
(builtins.elemAt
|
builtins.split "'" (
|
||||||
(builtins.split " version: '" (builtins.readFile ./meson.build))
|
builtins.elemAt (builtins.split " version: '" (builtins.readFile ./meson.build)) 2
|
||||||
2)))
|
)
|
||||||
+ "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
|
))
|
||||||
|
+ "+date="
|
||||||
|
+ (mkDate (self.lastModifiedDate or "19700101"))
|
||||||
|
+ "_"
|
||||||
|
+ (self.shortRev or "dirty");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,16 @@
|
|||||||
|
|
||||||
namespace cava {
|
namespace cava {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
// Need sdl_glsl output feature to be enabled on libcava
|
||||||
|
#ifndef SDL_GLSL
|
||||||
|
#define SDL_GLSL
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <cava/common.h>
|
#include <cava/common.h>
|
||||||
|
|
||||||
|
#ifdef SDL_GLSL
|
||||||
|
#undef SDL_GLSL
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace cava
|
} // namespace cava
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -67,7 +68,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
|
|
||||||
static Json::Value createMonitorWorkspaceData(std::string const& name,
|
static Json::Value createMonitorWorkspaceData(std::string const& name,
|
||||||
std::string const& monitor);
|
std::string const& monitor);
|
||||||
void removeWorkspace(std::string const& name);
|
void removeWorkspace(std::string const& workspaceString);
|
||||||
void setUrgentWorkspace(std::string const& windowaddress);
|
void setUrgentWorkspace(std::string const& windowaddress);
|
||||||
|
|
||||||
// Config
|
// Config
|
||||||
@ -87,10 +88,11 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
void onWorkspaceActivated(std::string const& payload);
|
void onWorkspaceActivated(std::string const& payload);
|
||||||
void onSpecialWorkspaceActivated(std::string const& payload);
|
void onSpecialWorkspaceActivated(std::string const& payload);
|
||||||
void onWorkspaceDestroyed(std::string const& payload);
|
void onWorkspaceDestroyed(std::string const& payload);
|
||||||
void onWorkspaceCreated(std::string const& workspaceName,
|
void onWorkspaceCreated(std::string const& payload,
|
||||||
Json::Value const& clientsData = Json::Value::nullRef);
|
Json::Value const& clientsData = Json::Value::nullRef);
|
||||||
void onWorkspaceMoved(std::string const& payload);
|
void onWorkspaceMoved(std::string const& payload);
|
||||||
void onWorkspaceRenamed(std::string const& payload);
|
void onWorkspaceRenamed(std::string const& payload);
|
||||||
|
static std::optional<int> parseWorkspaceId(std::string const& workspaceIdStr);
|
||||||
|
|
||||||
// monitor events
|
// monitor events
|
||||||
void onMonitorFocused(std::string const& payload);
|
void onMonitorFocused(std::string const& payload);
|
||||||
@ -106,11 +108,18 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
|
|
||||||
int windowRewritePriorityFunction(std::string const& window_rule);
|
int windowRewritePriorityFunction(std::string const& window_rule);
|
||||||
|
|
||||||
|
// event payload management
|
||||||
|
template <typename... Args>
|
||||||
|
static std::string makePayload(Args const&... args);
|
||||||
|
static std::pair<std::string, std::string> splitDoublePayload(std::string const& payload);
|
||||||
|
static std::tuple<std::string, std::string, std::string> splitTriplePayload(
|
||||||
|
std::string const& payload);
|
||||||
|
|
||||||
// Update methods
|
// Update methods
|
||||||
void doUpdate();
|
void doUpdate();
|
||||||
void removeWorkspacesToRemove();
|
void removeWorkspacesToRemove();
|
||||||
void createWorkspacesToCreate();
|
void createWorkspacesToCreate();
|
||||||
static std::vector<std::string> getVisibleWorkspaces();
|
static std::vector<int> getVisibleWorkspaces();
|
||||||
void updateWorkspaceStates();
|
void updateWorkspaceStates();
|
||||||
bool updateWindowsToCreate();
|
bool updateWindowsToCreate();
|
||||||
|
|
||||||
@ -152,7 +161,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
|
|
||||||
bool m_withIcon;
|
bool m_withIcon;
|
||||||
uint64_t m_monitorId;
|
uint64_t m_monitorId;
|
||||||
std::string m_activeWorkspaceName;
|
int m_activeWorkspaceId;
|
||||||
std::string m_activeSpecialWorkspaceName;
|
std::string m_activeSpecialWorkspaceName;
|
||||||
std::vector<std::unique_ptr<Workspace>> m_workspaces;
|
std::vector<std::unique_ptr<Workspace>> m_workspaces;
|
||||||
std::vector<std::pair<Json::Value, Json::Value>> m_workspacesToCreate;
|
std::vector<std::pair<Json::Value, Json::Value>> m_workspacesToCreate;
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
#include "util/rfkill.hpp"
|
#include "util/rfkill.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum ip_addr_pref : uint8_t { IPV4, IPV6, IPV4_6 };
|
||||||
|
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
|
|
||||||
class Network : public ALabel {
|
class Network : public ALabel {
|
||||||
@ -50,6 +52,7 @@ class Network : public ALabel {
|
|||||||
std::optional<std::pair<unsigned long long, unsigned long long>> readBandwidthUsage();
|
std::optional<std::pair<unsigned long long, unsigned long long>> readBandwidthUsage();
|
||||||
|
|
||||||
int ifid_;
|
int ifid_;
|
||||||
|
ip_addr_pref addr_pref_;
|
||||||
struct sockaddr_nl nladdr_ = {0};
|
struct sockaddr_nl nladdr_ = {0};
|
||||||
struct nl_sock* sock_ = nullptr;
|
struct nl_sock* sock_ = nullptr;
|
||||||
struct nl_sock* ev_sock_ = nullptr;
|
struct nl_sock* ev_sock_ = nullptr;
|
||||||
@ -73,9 +76,12 @@ class Network : public ALabel {
|
|||||||
bool carrier_;
|
bool carrier_;
|
||||||
std::string ifname_;
|
std::string ifname_;
|
||||||
std::string ipaddr_;
|
std::string ipaddr_;
|
||||||
|
std::string ipaddr6_;
|
||||||
std::string gwaddr_;
|
std::string gwaddr_;
|
||||||
std::string netmask_;
|
std::string netmask_;
|
||||||
|
std::string netmask6_;
|
||||||
int cidr_;
|
int cidr_;
|
||||||
|
int cidr6_;
|
||||||
int32_t signal_strength_dbm_;
|
int32_t signal_strength_dbm_;
|
||||||
uint8_t signal_strength_;
|
uint8_t signal_strength_;
|
||||||
std::string signal_strength_app_;
|
std::string signal_strength_app_;
|
||||||
|
@ -13,7 +13,7 @@ namespace waybar::modules::privacy {
|
|||||||
|
|
||||||
class Privacy : public AModule {
|
class Privacy : public AModule {
|
||||||
public:
|
public:
|
||||||
Privacy(const std::string &, const Json::Value &, const std::string &pos);
|
Privacy(const std::string &, const Json::Value &, Gtk::Orientation, const std::string &pos);
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
|
||||||
void onPrivacyNodesChanged();
|
void onPrivacyNodesChanged();
|
||||||
|
@ -17,8 +17,8 @@ namespace waybar::modules::privacy {
|
|||||||
class PrivacyItem : public Gtk::Revealer {
|
class PrivacyItem : public Gtk::Revealer {
|
||||||
public:
|
public:
|
||||||
PrivacyItem(const Json::Value &config_, enum PrivacyNodeType privacy_type_,
|
PrivacyItem(const Json::Value &config_, enum PrivacyNodeType privacy_type_,
|
||||||
std::list<PrivacyNodeInfo *> *nodes, const std::string &pos, const uint icon_size,
|
std::list<PrivacyNodeInfo *> *nodes, Gtk::Orientation orientation,
|
||||||
const uint transition_duration);
|
const std::string &pos, const uint icon_size, const uint transition_duration);
|
||||||
|
|
||||||
enum PrivacyNodeType privacy_type;
|
enum PrivacyNodeType privacy_type;
|
||||||
|
|
||||||
|
43
include/modules/sni/icon_manager.hpp
Normal file
43
include/modules/sni/icon_manager.hpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <json/json.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class IconManager {
|
||||||
|
public:
|
||||||
|
static IconManager& instance() {
|
||||||
|
static IconManager instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIconsConfig(const Json::Value& icons_config) {
|
||||||
|
if (icons_config.isObject()) {
|
||||||
|
for (const auto& key : icons_config.getMemberNames()) {
|
||||||
|
std::string app_name = key;
|
||||||
|
const Json::Value& icon_value = icons_config[key];
|
||||||
|
|
||||||
|
if (icon_value.isString()) {
|
||||||
|
std::string icon_path = icon_value.asString();
|
||||||
|
icons_map_[app_name] = icon_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
spdlog::warn("Invalid icon config format.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getIconForApp(const std::string& app_name) const {
|
||||||
|
auto it = icons_map_.find(app_name);
|
||||||
|
if (it != icons_map_.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
IconManager() = default;
|
||||||
|
std::unordered_map<std::string, std::string> icons_map_;
|
||||||
|
};
|
@ -62,6 +62,7 @@ class Item : public sigc::trackable {
|
|||||||
void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result);
|
void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result);
|
||||||
void setProperty(const Glib::ustring& name, Glib::VariantBase& value);
|
void setProperty(const Glib::ustring& name, Glib::VariantBase& value);
|
||||||
void setStatus(const Glib::ustring& value);
|
void setStatus(const Glib::ustring& value);
|
||||||
|
void setCustomIcon(const std::string& id);
|
||||||
void getUpdatedProperties();
|
void getUpdatedProperties();
|
||||||
void processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& result);
|
void processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& result);
|
||||||
void onSignal(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
|
void onSignal(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
|
||||||
|
@ -18,7 +18,7 @@ class Wireplumber : public ALabel {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void asyncLoadRequiredApiModules();
|
void asyncLoadRequiredApiModules();
|
||||||
void prepare();
|
void prepare(waybar::modules::Wireplumber* self);
|
||||||
void activatePlugins();
|
void activatePlugins();
|
||||||
static void updateVolume(waybar::modules::Wireplumber* self, uint32_t id);
|
static void updateVolume(waybar::modules::Wireplumber* self, uint32_t id);
|
||||||
static void updateNodeName(waybar::modules::Wireplumber* self, uint32_t id);
|
static void updateNodeName(waybar::modules::Wireplumber* self, uint32_t id);
|
||||||
@ -32,6 +32,8 @@ class Wireplumber : public ALabel {
|
|||||||
|
|
||||||
bool handleScroll(GdkEventScroll* e) override;
|
bool handleScroll(GdkEventScroll* e) override;
|
||||||
|
|
||||||
|
static std::list<waybar::modules::Wireplumber*> modules;
|
||||||
|
|
||||||
WpCore* wp_core_;
|
WpCore* wp_core_;
|
||||||
GPtrArray* apis_;
|
GPtrArray* apis_;
|
||||||
WpObjectManager* om_;
|
WpObjectManager* om_;
|
||||||
@ -44,6 +46,7 @@ class Wireplumber : public ALabel {
|
|||||||
double min_step_;
|
double min_step_;
|
||||||
uint32_t node_id_{0};
|
uint32_t node_id_{0};
|
||||||
std::string node_name_;
|
std::string node_name_;
|
||||||
|
gchar* type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
|
@ -40,7 +40,7 @@ The brightness can be controlled by dragging the slider across the bar or clicki
|
|||||||
|
|
||||||
```
|
```
|
||||||
"modules-right": [
|
"modules-right": [
|
||||||
"backlight-slider",
|
"backlight/slider",
|
||||||
],
|
],
|
||||||
"backlight/slider": {
|
"backlight/slider": {
|
||||||
"min": 0,
|
"min": 0,
|
||||||
|
@ -117,7 +117,7 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
|
|||||||
:[ 3
|
:[ 3
|
||||||
:[ Relevant for *mode=year*. Count of months per row
|
:[ Relevant for *mode=year*. Count of months per row
|
||||||
|[ *weeks-pos*
|
|[ *weeks-pos*
|
||||||
:[ integer
|
:[ string
|
||||||
:[
|
:[
|
||||||
:[ The position where week numbers should be displayed. Disabled when is empty.
|
:[ The position where week numbers should be displayed. Disabled when is empty.
|
||||||
Possible values: left|right
|
Possible values: left|right
|
||||||
|
@ -24,7 +24,7 @@ Addressed by *network*
|
|||||||
*family*: ++
|
*family*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: *ipv4* ++
|
default: *ipv4* ++
|
||||||
The address family that is used for the format replacement {ipaddr} and to determine if a network connection is present.
|
The address family that is used for the format replacement {ipaddr} and to determine if a network connection is present. Set it to ipv4_6 to display both.
|
||||||
|
|
||||||
*format*: ++
|
*format*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
@ -155,9 +155,13 @@ Addressed by *network*
|
|||||||
|
|
||||||
*{gwaddr}*: The default gateway for the interface
|
*{gwaddr}*: The default gateway for the interface
|
||||||
|
|
||||||
*{netmask}*: The subnetmask corresponding to the IP.
|
*{netmask}*: The subnetmask corresponding to the IP(V4).
|
||||||
|
|
||||||
*{cidr}*: The subnetmask corresponding to the IP in CIDR notation.
|
*{netmask6}*: The subnetmask corresponding to the IP(V6).
|
||||||
|
|
||||||
|
*{cidr}*: The subnetmask corresponding to the IP(V4) in CIDR notation.
|
||||||
|
|
||||||
|
*{cidr6}*: The subnetmask corresponding to the IP(V6) in CIDR notation.
|
||||||
|
|
||||||
*{essid}*: Name (SSID) of the wireless network.
|
*{essid}*: Name (SSID) of the wireless network.
|
||||||
|
|
||||||
|
@ -47,7 +47,11 @@ Addressed by *tray*
|
|||||||
```
|
```
|
||||||
"tray": {
|
"tray": {
|
||||||
"icon-size": 21,
|
"icon-size": 21,
|
||||||
"spacing": 10
|
"spacing": 10,
|
||||||
|
"icons": {
|
||||||
|
"blueman": "bluetooth",
|
||||||
|
"TelegramDesktop": "$HOME/.local/share/icons/hicolor/16x16/apps/telegram.png"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -19,6 +19,11 @@ The *wireplumber* module displays the current volume reported by WirePlumber.
|
|||||||
typeof: string ++
|
typeof: string ++
|
||||||
This format is used when the sound is muted.
|
This format is used when the sound is muted.
|
||||||
|
|
||||||
|
*node-type*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: *Audio/Sink* ++
|
||||||
|
The WirePlumber node type to attach to. Use *Audio/Source* to manage microphones etc.
|
||||||
|
|
||||||
*tooltip*: ++
|
*tooltip*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: *true* ++
|
default: *true* ++
|
||||||
@ -108,6 +113,8 @@ The *wireplumber* module displays the current volume reported by WirePlumber.
|
|||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
|
## Basic:
|
||||||
|
|
||||||
```
|
```
|
||||||
"wireplumber": {
|
"wireplumber": {
|
||||||
"format": "{volume}%",
|
"format": "{volume}%",
|
||||||
@ -116,6 +123,26 @@ The *wireplumber* module displays the current volume reported by WirePlumber.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Separate Sink and Source Widgets
|
||||||
|
|
||||||
|
```
|
||||||
|
"wireplumber#sink": {
|
||||||
|
"format": "{volume}% {icon}",
|
||||||
|
"format-muted": "",
|
||||||
|
"format-icons": ["", "", ""],
|
||||||
|
"on-click": "helvum",
|
||||||
|
"on-click-right": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle",
|
||||||
|
"scroll-step": 5
|
||||||
|
},
|
||||||
|
"wireplumber#source": {
|
||||||
|
"node-type": "Audio/Source",
|
||||||
|
"format": "{volume}% ",
|
||||||
|
"format-muted": "",
|
||||||
|
"on-click-right": "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle",
|
||||||
|
"scroll-step": 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# STYLE
|
# STYLE
|
||||||
|
|
||||||
- *#wireplumber*
|
- *#wireplumber*
|
||||||
|
@ -334,6 +334,10 @@ if get_option('niri')
|
|||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if get_option('login-proxy')
|
||||||
|
add_project_arguments('-DHAVE_LOGIN_PROXY', language: 'cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
if libnl.found() and libnlgen.found()
|
if libnl.found() and libnlgen.found()
|
||||||
add_project_arguments('-DHAVE_LIBNL', language: 'cpp')
|
add_project_arguments('-DHAVE_LIBNL', language: 'cpp')
|
||||||
src_files += files('src/modules/network.cpp')
|
src_files += files('src/modules/network.cpp')
|
||||||
@ -483,7 +487,7 @@ if get_option('experimental')
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
cava = dependency('cava',
|
cava = dependency('cava',
|
||||||
version : '>=0.10.3',
|
version : '>=0.10.4',
|
||||||
required: get_option('cava'),
|
required: get_option('cava'),
|
||||||
fallback : ['cava', 'cava_dep'],
|
fallback : ['cava', 'cava_dep'],
|
||||||
not_found_message: 'cava is not found. Building waybar without cava')
|
not_found_message: 'cava is not found. Building waybar without cava')
|
||||||
|
@ -20,3 +20,4 @@ option('jack', type: 'feature', value: 'auto', description: 'Enable support for
|
|||||||
option('wireplumber', type: 'feature', value: 'auto', description: 'Enable support for WirePlumber')
|
option('wireplumber', type: 'feature', value: 'auto', description: 'Enable support for WirePlumber')
|
||||||
option('cava', type: 'feature', value: 'auto', description: 'Enable support for Cava')
|
option('cava', type: 'feature', value: 'auto', description: 'Enable support for Cava')
|
||||||
option('niri', type: 'boolean', description: 'Enable support for niri')
|
option('niri', type: 'boolean', description: 'Enable support for niri')
|
||||||
|
option('login-proxy', type: 'boolean', description: 'Enable interfacing with dbus login interface')
|
||||||
|
@ -1,42 +1,43 @@
|
|||||||
{ lib
|
{
|
||||||
, pkgs
|
lib,
|
||||||
, waybar
|
pkgs,
|
||||||
, version
|
waybar,
|
||||||
|
version,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
libcava = rec {
|
libcava = rec {
|
||||||
version = "0.10.3";
|
version = "0.10.4";
|
||||||
src = pkgs.fetchFromGitHub {
|
src = pkgs.fetchFromGitHub {
|
||||||
owner = "LukashonakV";
|
owner = "LukashonakV";
|
||||||
repo = "cava";
|
repo = "cava";
|
||||||
rev = version;
|
tag = version;
|
||||||
hash = "sha256-ZDFbI69ECsUTjbhlw2kHRufZbQMu+FQSMmncCJ5pagg=";
|
hash = "sha256-9eTDqM+O1tA/3bEfd1apm8LbEcR9CVgELTIspSVPMKM=";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
(waybar.overrideAttrs (
|
(waybar.overrideAttrs (oldAttrs: {
|
||||||
oldAttrs: {
|
inherit version;
|
||||||
inherit version;
|
|
||||||
|
|
||||||
src = lib.cleanSourceWith {
|
src = lib.cleanSourceWith {
|
||||||
filter = name: type: type != "regular" || !lib.hasSuffix ".nix" name;
|
filter = name: type: type != "regular" || !lib.hasSuffix ".nix" name;
|
||||||
src = lib.cleanSource ../.;
|
src = lib.cleanSource ../.;
|
||||||
};
|
};
|
||||||
|
|
||||||
mesonFlags = lib.remove "-Dgtk-layer-shell=enabled" oldAttrs.mesonFlags;
|
mesonFlags = lib.remove "-Dgtk-layer-shell=enabled" oldAttrs.mesonFlags;
|
||||||
|
|
||||||
# downstream patch should not affect upstream
|
# downstream patch should not affect upstream
|
||||||
patches = [];
|
patches = [ ];
|
||||||
|
# nixpkgs checks version, no need when building locally
|
||||||
|
nativeInstallCheckInputs = [ ];
|
||||||
|
|
||||||
buildInputs = (builtins.filter (p: p.pname != "wireplumber") oldAttrs.buildInputs) ++ [
|
buildInputs = (builtins.filter (p: p.pname != "wireplumber") oldAttrs.buildInputs) ++ [
|
||||||
pkgs.wireplumber
|
pkgs.wireplumber
|
||||||
];
|
];
|
||||||
|
|
||||||
postUnpack = ''
|
postUnpack = ''
|
||||||
pushd "$sourceRoot"
|
pushd "$sourceRoot"
|
||||||
cp -R --no-preserve=mode,ownership ${libcava.src} subprojects/cava-${libcava.version}
|
cp -R --no-preserve=mode,ownership ${libcava.src} subprojects/cava-${libcava.version}
|
||||||
patchShebangs .
|
patchShebangs .
|
||||||
popd
|
popd
|
||||||
'';
|
'';
|
||||||
}
|
}))
|
||||||
))
|
|
||||||
|
@ -104,7 +104,11 @@
|
|||||||
},
|
},
|
||||||
"tray": {
|
"tray": {
|
||||||
// "icon-size": 21,
|
// "icon-size": 21,
|
||||||
"spacing": 10
|
"spacing": 10,
|
||||||
|
// "icons": {
|
||||||
|
// "blueman": "bluetooth",
|
||||||
|
// "TelegramDesktop": "$HOME/.local/share/icons/hicolor/16x16/apps/telegram.png"
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
"clock": {
|
"clock": {
|
||||||
// "timezone": "America/New_York",
|
// "timezone": "America/New_York",
|
||||||
|
@ -17,7 +17,7 @@ void onclicked(GtkButton* button) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// You must
|
// You must
|
||||||
const size_t wbcffi_version = 1;
|
const size_t wbcffi_version = 2;
|
||||||
|
|
||||||
void* wbcffi_init(const wbcffi_init_info* init_info, const wbcffi_config_entry* config_entries,
|
void* wbcffi_init(const wbcffi_init_info* init_info, const wbcffi_config_entry* config_entries,
|
||||||
size_t config_entries_len) {
|
size_t config_entries_len) {
|
||||||
@ -67,4 +67,4 @@ void wbcffi_refresh(void* instance, int signal) {
|
|||||||
|
|
||||||
void wbcffi_doaction(void* instance, const char* name) {
|
void wbcffi_doaction(void* instance, const char* name) {
|
||||||
printf("cffi_example inst=%p: doAction(%s)\n", instance, name);
|
printf("cffi_example inst=%p: doAction(%s)\n", instance, name);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Waybar ABI version. 1 is the latest version
|
/// Waybar ABI version. 2 is the latest version
|
||||||
extern const size_t wbcffi_version;
|
extern const size_t wbcffi_version;
|
||||||
|
|
||||||
/// Private Waybar CFFI module
|
/// Private Waybar CFFI module
|
||||||
@ -35,7 +35,13 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
/// Entry key
|
/// Entry key
|
||||||
const char* key;
|
const char* key;
|
||||||
/// Entry value as string. JSON object and arrays are serialized.
|
/// Entry value
|
||||||
|
///
|
||||||
|
/// In ABI version 1, this may be either a bare string if the value is a
|
||||||
|
/// string, or the JSON representation of any other JSON object as a string.
|
||||||
|
///
|
||||||
|
/// From ABI version 2 onwards, this is always the JSON representation of the
|
||||||
|
/// value as a string.
|
||||||
const char* value;
|
const char* value;
|
||||||
} wbcffi_config_entry;
|
} wbcffi_config_entry;
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
|
|||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_PIPEWIRE
|
#ifdef HAVE_PIPEWIRE
|
||||||
if (ref == "privacy") {
|
if (ref == "privacy") {
|
||||||
return new waybar::modules::privacy::Privacy(id, config_[name], pos);
|
return new waybar::modules::privacy::Privacy(id, config_[name], bar_.orientation, pos);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_MPRIS
|
#ifdef HAVE_MPRIS
|
||||||
|
@ -28,7 +28,7 @@ CFFI::CFFI(const std::string& name, const std::string& id, const Json::Value& co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch functions
|
// Fetch functions
|
||||||
if (*wbcffi_version == 1) {
|
if (*wbcffi_version == 1 || *wbcffi_version == 2) {
|
||||||
// Mandatory functions
|
// Mandatory functions
|
||||||
hooks_.init = reinterpret_cast<InitFn*>(dlsym(handle, "wbcffi_init"));
|
hooks_.init = reinterpret_cast<InitFn*>(dlsym(handle, "wbcffi_init"));
|
||||||
if (!hooks_.init) {
|
if (!hooks_.init) {
|
||||||
@ -58,10 +58,14 @@ CFFI::CFFI(const std::string& name, const std::string& id, const Json::Value& co
|
|||||||
const auto& keys = config.getMemberNames();
|
const auto& keys = config.getMemberNames();
|
||||||
for (size_t i = 0; i < keys.size(); i++) {
|
for (size_t i = 0; i < keys.size(); i++) {
|
||||||
const auto& value = config[keys[i]];
|
const auto& value = config[keys[i]];
|
||||||
if (value.isConvertibleTo(Json::ValueType::stringValue)) {
|
if (*wbcffi_version == 1) {
|
||||||
config_entries_stringstor.push_back(config[keys[i]].asString());
|
if (value.isConvertibleTo(Json::ValueType::stringValue)) {
|
||||||
|
config_entries_stringstor.push_back(value.asString());
|
||||||
|
} else {
|
||||||
|
config_entries_stringstor.push_back(value.toStyledString());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
config_entries_stringstor.push_back(config[keys[i]].toStyledString());
|
config_entries_stringstor.push_back(value.toStyledString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ Workspaces::~Workspaces() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::init() {
|
void Workspaces::init() {
|
||||||
m_activeWorkspaceName = (m_ipc.getSocket1JsonReply("activeworkspace"))["name"].asString();
|
m_activeWorkspaceId = m_ipc.getSocket1JsonReply("activeworkspace")["id"].asInt();
|
||||||
|
|
||||||
initializeWorkspaces();
|
initializeWorkspaces();
|
||||||
dp.emit();
|
dp.emit();
|
||||||
@ -50,13 +51,12 @@ Json::Value Workspaces::createMonitorWorkspaceData(std::string const &name,
|
|||||||
std::string const &monitor) {
|
std::string const &monitor) {
|
||||||
spdlog::trace("Creating persistent workspace: {} on monitor {}", name, monitor);
|
spdlog::trace("Creating persistent workspace: {} on monitor {}", name, monitor);
|
||||||
Json::Value workspaceData;
|
Json::Value workspaceData;
|
||||||
try {
|
|
||||||
// numbered persistent workspaces get the name as ID
|
auto workspaceId = parseWorkspaceId(name);
|
||||||
workspaceData["id"] = name == "special" ? -99 : std::stoi(name);
|
if (!workspaceId.has_value()) {
|
||||||
} catch (const std::exception &e) {
|
workspaceId = 0;
|
||||||
// named persistent workspaces start with ID=0
|
|
||||||
workspaceData["id"] = 0;
|
|
||||||
}
|
}
|
||||||
|
workspaceData["id"] = *workspaceId;
|
||||||
workspaceData["name"] = name;
|
workspaceData["name"] = name;
|
||||||
workspaceData["monitor"] = monitor;
|
workspaceData["monitor"] = monitor;
|
||||||
workspaceData["windows"] = 0;
|
workspaceData["windows"] = 0;
|
||||||
@ -69,9 +69,8 @@ void Workspaces::createWorkspace(Json::Value const &workspace_data,
|
|||||||
spdlog::debug("Creating workspace {}", workspaceName);
|
spdlog::debug("Creating workspace {}", workspaceName);
|
||||||
|
|
||||||
// avoid recreating existing workspaces
|
// avoid recreating existing workspaces
|
||||||
auto workspace = std::find_if(
|
auto workspace =
|
||||||
m_workspaces.begin(), m_workspaces.end(),
|
std::ranges::find_if(m_workspaces, [workspaceName](std::unique_ptr<Workspace> const &w) {
|
||||||
[workspaceName](std::unique_ptr<Workspace> const &w) {
|
|
||||||
return (workspaceName.starts_with("special:") && workspaceName.substr(8) == w->name()) ||
|
return (workspaceName.starts_with("special:") && workspaceName.substr(8) == w->name()) ||
|
||||||
workspaceName == w->name();
|
workspaceName == w->name();
|
||||||
});
|
});
|
||||||
@ -81,14 +80,14 @@ void Workspaces::createWorkspace(Json::Value const &workspace_data,
|
|||||||
const auto keys = workspace_data.getMemberNames();
|
const auto keys = workspace_data.getMemberNames();
|
||||||
|
|
||||||
const auto *k = "persistent-rule";
|
const auto *k = "persistent-rule";
|
||||||
if (std::find(keys.begin(), keys.end(), k) != keys.end()) {
|
if (std::ranges::find(keys, k) != keys.end()) {
|
||||||
spdlog::debug("Set dynamic persistency of workspace {} to: {}", workspaceName,
|
spdlog::debug("Set dynamic persistency of workspace {} to: {}", workspaceName,
|
||||||
workspace_data[k].asBool() ? "true" : "false");
|
workspace_data[k].asBool() ? "true" : "false");
|
||||||
(*workspace)->setPersistentRule(workspace_data[k].asBool());
|
(*workspace)->setPersistentRule(workspace_data[k].asBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
k = "persistent-config";
|
k = "persistent-config";
|
||||||
if (std::find(keys.begin(), keys.end(), k) != keys.end()) {
|
if (std::ranges::find(keys, k) != keys.end()) {
|
||||||
spdlog::debug("Set config persistency of workspace {} to: {}", workspaceName,
|
spdlog::debug("Set config persistency of workspace {} to: {}", workspaceName,
|
||||||
workspace_data[k].asBool() ? "true" : "false");
|
workspace_data[k].asBool() ? "true" : "false");
|
||||||
(*workspace)->setPersistentConfig(workspace_data[k].asBool());
|
(*workspace)->setPersistentConfig(workspace_data[k].asBool());
|
||||||
@ -159,18 +158,18 @@ std::string Workspaces::getRewrite(std::string window_class, std::string window_
|
|||||||
fmt::arg("title", window_title));
|
fmt::arg("title", window_title));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> Workspaces::getVisibleWorkspaces() {
|
std::vector<int> Workspaces::getVisibleWorkspaces() {
|
||||||
std::vector<std::string> visibleWorkspaces;
|
std::vector<int> visibleWorkspaces;
|
||||||
auto monitors = IPC::inst().getSocket1JsonReply("monitors");
|
auto monitors = IPC::inst().getSocket1JsonReply("monitors");
|
||||||
for (const auto &monitor : monitors) {
|
for (const auto &monitor : monitors) {
|
||||||
auto ws = monitor["activeWorkspace"];
|
auto ws = monitor["activeWorkspace"];
|
||||||
if (ws.isObject() && ws["name"].isString()) {
|
if (ws.isObject() && ws["id"].isInt()) {
|
||||||
visibleWorkspaces.push_back(ws["name"].asString());
|
visibleWorkspaces.push_back(ws["id"].asInt());
|
||||||
}
|
}
|
||||||
auto sws = monitor["specialWorkspace"];
|
auto sws = monitor["specialWorkspace"];
|
||||||
auto name = sws["name"].asString();
|
auto name = sws["name"].asString();
|
||||||
if (sws.isObject() && sws["name"].isString() && !name.empty()) {
|
if (sws.isObject() && sws["id"].isInt() && !name.empty()) {
|
||||||
visibleWorkspaces.push_back(!name.starts_with("special:") ? name : name.substr(8));
|
visibleWorkspaces.push_back(sws["id"].asInt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return visibleWorkspaces;
|
return visibleWorkspaces;
|
||||||
@ -181,7 +180,7 @@ void Workspaces::initializeWorkspaces() {
|
|||||||
|
|
||||||
// if the workspace rules changed since last initialization, make sure we reset everything:
|
// if the workspace rules changed since last initialization, make sure we reset everything:
|
||||||
for (auto &workspace : m_workspaces) {
|
for (auto &workspace : m_workspaces) {
|
||||||
m_workspacesToRemove.push_back(workspace->name());
|
m_workspacesToRemove.push_back(std::to_string(workspace->id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// get all current workspaces
|
// get all current workspaces
|
||||||
@ -233,7 +232,7 @@ void Workspaces::loadPersistentWorkspacesFromConfig(Json::Value const &clientsJs
|
|||||||
std::vector<std::string> persistentWorkspacesToCreate;
|
std::vector<std::string> persistentWorkspacesToCreate;
|
||||||
|
|
||||||
const std::string currentMonitor = m_bar.output->name;
|
const std::string currentMonitor = m_bar.output->name;
|
||||||
const bool monitorInConfig = std::find(keys.begin(), keys.end(), currentMonitor) != keys.end();
|
const bool monitorInConfig = std::ranges::find(keys, currentMonitor) != keys.end();
|
||||||
for (const std::string &key : keys) {
|
for (const std::string &key : keys) {
|
||||||
// only add if either:
|
// only add if either:
|
||||||
// 1. key is the current monitor name
|
// 1. key is the current monitor name
|
||||||
@ -248,7 +247,7 @@ void Workspaces::loadPersistentWorkspacesFromConfig(Json::Value const &clientsJs
|
|||||||
int amount = value.asInt();
|
int amount = value.asInt();
|
||||||
spdlog::debug("Creating {} persistent workspaces for monitor {}", amount, currentMonitor);
|
spdlog::debug("Creating {} persistent workspaces for monitor {}", amount, currentMonitor);
|
||||||
for (int i = 0; i < amount; i++) {
|
for (int i = 0; i < amount; i++) {
|
||||||
persistentWorkspacesToCreate.emplace_back(std::to_string(m_monitorId * amount + i + 1));
|
persistentWorkspacesToCreate.emplace_back(std::to_string((m_monitorId * amount) + i + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (value.isArray() && !value.empty()) {
|
} else if (value.isArray() && !value.empty()) {
|
||||||
@ -307,6 +306,7 @@ void Workspaces::loadPersistentWorkspacesFromWorkspaceRules(const Json::Value &c
|
|||||||
workspaceData["persistent-rule"] = true;
|
workspaceData["persistent-rule"] = true;
|
||||||
m_workspacesToCreate.emplace_back(workspaceData, clientsJson);
|
m_workspacesToCreate.emplace_back(workspaceData, clientsJson);
|
||||||
} else {
|
} else {
|
||||||
|
// This can be any workspace selector.
|
||||||
m_workspacesToRemove.emplace_back(workspace);
|
m_workspacesToRemove.emplace_back(workspace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,29 +317,29 @@ void Workspaces::onEvent(const std::string &ev) {
|
|||||||
std::string eventName(begin(ev), begin(ev) + ev.find_first_of('>'));
|
std::string eventName(begin(ev), begin(ev) + ev.find_first_of('>'));
|
||||||
std::string payload = ev.substr(eventName.size() + 2);
|
std::string payload = ev.substr(eventName.size() + 2);
|
||||||
|
|
||||||
if (eventName == "workspace") {
|
if (eventName == "workspacev2") {
|
||||||
onWorkspaceActivated(payload);
|
onWorkspaceActivated(payload);
|
||||||
} else if (eventName == "activespecial") {
|
} else if (eventName == "activespecial") {
|
||||||
onSpecialWorkspaceActivated(payload);
|
onSpecialWorkspaceActivated(payload);
|
||||||
} else if (eventName == "destroyworkspace") {
|
} else if (eventName == "destroyworkspacev2") {
|
||||||
onWorkspaceDestroyed(payload);
|
onWorkspaceDestroyed(payload);
|
||||||
} else if (eventName == "createworkspace") {
|
} else if (eventName == "createworkspacev2") {
|
||||||
onWorkspaceCreated(payload);
|
onWorkspaceCreated(payload);
|
||||||
} else if (eventName == "focusedmon") {
|
} else if (eventName == "focusedmonv2") {
|
||||||
onMonitorFocused(payload);
|
onMonitorFocused(payload);
|
||||||
} else if (eventName == "moveworkspace") {
|
} else if (eventName == "moveworkspacev2") {
|
||||||
onWorkspaceMoved(payload);
|
onWorkspaceMoved(payload);
|
||||||
} else if (eventName == "openwindow") {
|
} else if (eventName == "openwindow") {
|
||||||
onWindowOpened(payload);
|
onWindowOpened(payload);
|
||||||
} else if (eventName == "closewindow") {
|
} else if (eventName == "closewindow") {
|
||||||
onWindowClosed(payload);
|
onWindowClosed(payload);
|
||||||
} else if (eventName == "movewindow") {
|
} else if (eventName == "movewindowv2") {
|
||||||
onWindowMoved(payload);
|
onWindowMoved(payload);
|
||||||
} else if (eventName == "urgent") {
|
} else if (eventName == "urgent") {
|
||||||
setUrgentWorkspace(payload);
|
setUrgentWorkspace(payload);
|
||||||
} else if (eventName == "renameworkspace") {
|
} else if (eventName == "renameworkspace") {
|
||||||
onWorkspaceRenamed(payload);
|
onWorkspaceRenamed(payload);
|
||||||
} else if (eventName == "windowtitle") {
|
} else if (eventName == "windowtitlev2") {
|
||||||
onWindowTitleEvent(payload);
|
onWindowTitleEvent(payload);
|
||||||
} else if (eventName == "configreloaded") {
|
} else if (eventName == "configreloaded") {
|
||||||
onConfigReloaded();
|
onConfigReloaded();
|
||||||
@ -349,7 +349,11 @@ void Workspaces::onEvent(const std::string &ev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onWorkspaceActivated(std::string const &payload) {
|
void Workspaces::onWorkspaceActivated(std::string const &payload) {
|
||||||
m_activeWorkspaceName = payload;
|
const auto [workspaceIdStr, workspaceName] = splitDoublePayload(payload);
|
||||||
|
const auto workspaceId = parseWorkspaceId(workspaceIdStr);
|
||||||
|
if (workspaceId.has_value()) {
|
||||||
|
m_activeWorkspaceId = *workspaceId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onSpecialWorkspaceActivated(std::string const &payload) {
|
void Workspaces::onSpecialWorkspaceActivated(std::string const &payload) {
|
||||||
@ -358,42 +362,55 @@ void Workspaces::onSpecialWorkspaceActivated(std::string const &payload) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onWorkspaceDestroyed(std::string const &payload) {
|
void Workspaces::onWorkspaceDestroyed(std::string const &payload) {
|
||||||
if (!isDoubleSpecial(payload)) {
|
const auto [workspaceId, workspaceName] = splitDoublePayload(payload);
|
||||||
m_workspacesToRemove.push_back(payload);
|
if (!isDoubleSpecial(workspaceName)) {
|
||||||
|
m_workspacesToRemove.push_back(workspaceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onWorkspaceCreated(std::string const &workspaceName,
|
void Workspaces::onWorkspaceCreated(std::string const &payload, Json::Value const &clientsData) {
|
||||||
Json::Value const &clientsData) {
|
spdlog::debug("Workspace created: {}", payload);
|
||||||
spdlog::debug("Workspace created: {}", workspaceName);
|
|
||||||
|
const auto [workspaceIdStr, _] = splitDoublePayload(payload);
|
||||||
|
|
||||||
|
const auto workspaceId = parseWorkspaceId(workspaceIdStr);
|
||||||
|
if (!workspaceId.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const workspaceRules = m_ipc.getSocket1JsonReply("workspacerules");
|
||||||
auto const workspacesJson = m_ipc.getSocket1JsonReply("workspaces");
|
auto const workspacesJson = m_ipc.getSocket1JsonReply("workspaces");
|
||||||
|
|
||||||
if (!isWorkspaceIgnored(workspaceName)) {
|
for (Json::Value workspaceJson : workspacesJson) {
|
||||||
auto const workspaceRules = m_ipc.getSocket1JsonReply("workspacerules");
|
const auto currentId = workspaceJson["id"].asInt();
|
||||||
for (Json::Value workspaceJson : workspacesJson) {
|
if (currentId == *workspaceId) {
|
||||||
std::string name = workspaceJson["name"].asString();
|
std::string workspaceName = workspaceJson["name"].asString();
|
||||||
if (name == workspaceName) {
|
// This workspace name is more up-to-date than the one in the event payload.
|
||||||
if ((allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
|
if (isWorkspaceIgnored(workspaceName)) {
|
||||||
(showSpecial() || !name.starts_with("special")) && !isDoubleSpecial(workspaceName)) {
|
spdlog::trace("Not creating workspace because it is ignored: id={} name={}", *workspaceId,
|
||||||
for (Json::Value const &rule : workspaceRules) {
|
workspaceName);
|
||||||
auto ruleWorkspaceName = rule.isMember("defaultName")
|
break;
|
||||||
? rule["defaultName"].asString()
|
|
||||||
: rule["workspaceString"].asString();
|
|
||||||
if (ruleWorkspaceName == workspaceName) {
|
|
||||||
workspaceJson["persistent-rule"] = rule["persistent"].asBool();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_workspacesToCreate.emplace_back(workspaceJson, clientsData);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
extendOrphans(workspaceJson["id"].asInt(), clientsData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
|
||||||
|
(showSpecial() || !workspaceName.starts_with("special")) &&
|
||||||
|
!isDoubleSpecial(workspaceName)) {
|
||||||
|
for (Json::Value const &rule : workspaceRules) {
|
||||||
|
auto ruleWorkspaceName = rule.isMember("defaultName")
|
||||||
|
? rule["defaultName"].asString()
|
||||||
|
: rule["workspaceString"].asString();
|
||||||
|
if (ruleWorkspaceName == workspaceName) {
|
||||||
|
workspaceJson["persistent-rule"] = rule["persistent"].asBool();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_workspacesToCreate.emplace_back(workspaceJson, clientsData);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
extendOrphans(*workspaceId, clientsData);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
spdlog::trace("Not creating workspace because it is ignored: {}", workspaceName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,32 +418,34 @@ void Workspaces::onWorkspaceMoved(std::string const &payload) {
|
|||||||
spdlog::debug("Workspace moved: {}", payload);
|
spdlog::debug("Workspace moved: {}", payload);
|
||||||
|
|
||||||
// Update active workspace
|
// Update active workspace
|
||||||
m_activeWorkspaceName = (m_ipc.getSocket1JsonReply("activeworkspace"))["name"].asString();
|
m_activeWorkspaceId = (m_ipc.getSocket1JsonReply("activeworkspace"))["id"].asInt();
|
||||||
|
|
||||||
if (allOutputs()) return;
|
if (allOutputs()) return;
|
||||||
|
|
||||||
std::string workspaceName = payload.substr(0, payload.find(','));
|
const auto [workspaceIdStr, workspaceName, monitorName] = splitTriplePayload(payload);
|
||||||
std::string monitorName = payload.substr(payload.find(',') + 1);
|
|
||||||
|
const auto subPayload = makePayload(workspaceIdStr, workspaceName);
|
||||||
|
|
||||||
if (m_bar.output->name == monitorName) {
|
if (m_bar.output->name == monitorName) {
|
||||||
Json::Value clientsData = m_ipc.getSocket1JsonReply("clients");
|
Json::Value clientsData = m_ipc.getSocket1JsonReply("clients");
|
||||||
onWorkspaceCreated(workspaceName, clientsData);
|
onWorkspaceCreated(subPayload, clientsData);
|
||||||
} else {
|
} else {
|
||||||
spdlog::debug("Removing workspace because it was moved to another monitor: {}");
|
spdlog::debug("Removing workspace because it was moved to another monitor: {}", subPayload);
|
||||||
onWorkspaceDestroyed(workspaceName);
|
onWorkspaceDestroyed(subPayload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onWorkspaceRenamed(std::string const &payload) {
|
void Workspaces::onWorkspaceRenamed(std::string const &payload) {
|
||||||
spdlog::debug("Workspace renamed: {}", payload);
|
spdlog::debug("Workspace renamed: {}", payload);
|
||||||
std::string workspaceIdStr = payload.substr(0, payload.find(','));
|
const auto [workspaceIdStr, newName] = splitDoublePayload(payload);
|
||||||
int workspaceId = workspaceIdStr == "special" ? -99 : std::stoi(workspaceIdStr);
|
|
||||||
std::string newName = payload.substr(payload.find(',') + 1);
|
const auto workspaceId = parseWorkspaceId(workspaceIdStr);
|
||||||
|
if (!workspaceId.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &workspace : m_workspaces) {
|
for (auto &workspace : m_workspaces) {
|
||||||
if (workspace->id() == workspaceId) {
|
if (workspace->id() == *workspaceId) {
|
||||||
if (workspace->name() == m_activeWorkspaceName) {
|
|
||||||
m_activeWorkspaceName = newName;
|
|
||||||
}
|
|
||||||
workspace->setName(newName);
|
workspace->setName(newName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -436,11 +455,19 @@ void Workspaces::onWorkspaceRenamed(std::string const &payload) {
|
|||||||
|
|
||||||
void Workspaces::onMonitorFocused(std::string const &payload) {
|
void Workspaces::onMonitorFocused(std::string const &payload) {
|
||||||
spdlog::trace("Monitor focused: {}", payload);
|
spdlog::trace("Monitor focused: {}", payload);
|
||||||
m_activeWorkspaceName = payload.substr(payload.find(',') + 1);
|
|
||||||
|
const auto [monitorName, workspaceIdStr] = splitDoublePayload(payload);
|
||||||
|
|
||||||
|
const auto workspaceId = parseWorkspaceId(workspaceIdStr);
|
||||||
|
if (!workspaceId.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_activeWorkspaceId = *workspaceId;
|
||||||
|
|
||||||
for (Json::Value &monitor : m_ipc.getSocket1JsonReply("monitors")) {
|
for (Json::Value &monitor : m_ipc.getSocket1JsonReply("monitors")) {
|
||||||
if (monitor["name"].asString() == payload.substr(0, payload.find(','))) {
|
if (monitor["name"].asString() == monitorName) {
|
||||||
auto name = monitor["specialWorkspace"]["name"].asString();
|
const auto name = monitor["specialWorkspace"]["name"].asString();
|
||||||
m_activeSpecialWorkspaceName = !name.starts_with("special:") ? name : name.substr(8);
|
m_activeSpecialWorkspaceName = !name.starts_with("special:") ? name : name.substr(8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -480,11 +507,7 @@ void Workspaces::onWindowClosed(std::string const &addr) {
|
|||||||
void Workspaces::onWindowMoved(std::string const &payload) {
|
void Workspaces::onWindowMoved(std::string const &payload) {
|
||||||
spdlog::trace("Window moved: {}", payload);
|
spdlog::trace("Window moved: {}", payload);
|
||||||
updateWindowCount();
|
updateWindowCount();
|
||||||
size_t lastCommaIdx = 0;
|
auto [windowAddress, _, workspaceName] = splitTriplePayload(payload);
|
||||||
size_t nextCommaIdx = payload.find(',');
|
|
||||||
std::string windowAddress = payload.substr(lastCommaIdx, nextCommaIdx - lastCommaIdx);
|
|
||||||
|
|
||||||
std::string workspaceName = payload.substr(nextCommaIdx + 1, payload.length() - nextCommaIdx);
|
|
||||||
|
|
||||||
WindowRepr windowRepr;
|
WindowRepr windowRepr;
|
||||||
|
|
||||||
@ -521,13 +544,15 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) {
|
|||||||
spdlog::trace("Window title changed: {}", payload);
|
spdlog::trace("Window title changed: {}", payload);
|
||||||
std::optional<std::function<void(WindowCreationPayload)>> inserter;
|
std::optional<std::function<void(WindowCreationPayload)>> inserter;
|
||||||
|
|
||||||
|
const auto [windowAddress, _] = splitDoublePayload(payload);
|
||||||
|
|
||||||
// If the window was an orphan, rename it at the orphan's vector
|
// If the window was an orphan, rename it at the orphan's vector
|
||||||
if (m_orphanWindowMap.contains(payload)) {
|
if (m_orphanWindowMap.contains(windowAddress)) {
|
||||||
inserter = [this](WindowCreationPayload wcp) { this->registerOrphanWindow(std::move(wcp)); };
|
inserter = [this](WindowCreationPayload wcp) { this->registerOrphanWindow(std::move(wcp)); };
|
||||||
} else {
|
} else {
|
||||||
auto windowWorkspace =
|
auto windowWorkspace = std::ranges::find_if(m_workspaces, [windowAddress](auto &workspace) {
|
||||||
std::find_if(m_workspaces.begin(), m_workspaces.end(),
|
return workspace->containsWindow(windowAddress);
|
||||||
[payload](auto &workspace) { return workspace->containsWindow(payload); });
|
});
|
||||||
|
|
||||||
// If the window exists on a workspace, rename it at the workspace's window
|
// If the window exists on a workspace, rename it at the workspace's window
|
||||||
// map
|
// map
|
||||||
@ -536,9 +561,9 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) {
|
|||||||
(*windowWorkspace)->insertWindow(std::move(wcp));
|
(*windowWorkspace)->insertWindow(std::move(wcp));
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
auto queuedWindow = std::find_if(
|
auto queuedWindow = std::ranges::find_if(m_windowsToCreate, [payload](auto &windowPayload) {
|
||||||
m_windowsToCreate.begin(), m_windowsToCreate.end(),
|
return windowPayload.getAddress() == payload;
|
||||||
[payload](auto &windowPayload) { return windowPayload.getAddress() == payload; });
|
});
|
||||||
|
|
||||||
// If the window was queued, rename it in the queue
|
// If the window was queued, rename it in the queue
|
||||||
if (queuedWindow != m_windowsToCreate.end()) {
|
if (queuedWindow != m_windowsToCreate.end()) {
|
||||||
@ -551,8 +576,8 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) {
|
|||||||
Json::Value clientsData = m_ipc.getSocket1JsonReply("clients");
|
Json::Value clientsData = m_ipc.getSocket1JsonReply("clients");
|
||||||
std::string jsonWindowAddress = fmt::format("0x{}", payload);
|
std::string jsonWindowAddress = fmt::format("0x{}", payload);
|
||||||
|
|
||||||
auto client = std::ranges::find_if(clientsData, [&jsonWindowAddress](auto &c) {
|
auto client = std::ranges::find_if(clientsData, [jsonWindowAddress](auto &client) {
|
||||||
return c["address"].asString() == jsonWindowAddress;
|
return client["address"].asString() == jsonWindowAddress;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (client != clientsData.end() && !client->empty()) {
|
if (client != clientsData.end() && !client->empty()) {
|
||||||
@ -721,40 +746,58 @@ void Workspaces::registerOrphanWindow(WindowCreationPayload create_window_payloa
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Workspaces::registerIpc() -> void {
|
auto Workspaces::registerIpc() -> void {
|
||||||
m_ipc.registerForIPC("workspace", this);
|
m_ipc.registerForIPC("workspacev2", this);
|
||||||
m_ipc.registerForIPC("activespecial", this);
|
m_ipc.registerForIPC("activespecial", this);
|
||||||
m_ipc.registerForIPC("createworkspace", this);
|
m_ipc.registerForIPC("createworkspacev2", this);
|
||||||
m_ipc.registerForIPC("destroyworkspace", this);
|
m_ipc.registerForIPC("destroyworkspacev2", this);
|
||||||
m_ipc.registerForIPC("focusedmon", this);
|
m_ipc.registerForIPC("focusedmonv2", this);
|
||||||
m_ipc.registerForIPC("moveworkspace", this);
|
m_ipc.registerForIPC("moveworkspacev2", this);
|
||||||
m_ipc.registerForIPC("renameworkspace", this);
|
m_ipc.registerForIPC("renameworkspace", this);
|
||||||
m_ipc.registerForIPC("openwindow", this);
|
m_ipc.registerForIPC("openwindow", this);
|
||||||
m_ipc.registerForIPC("closewindow", this);
|
m_ipc.registerForIPC("closewindow", this);
|
||||||
m_ipc.registerForIPC("movewindow", this);
|
m_ipc.registerForIPC("movewindowv2", this);
|
||||||
m_ipc.registerForIPC("urgent", this);
|
m_ipc.registerForIPC("urgent", this);
|
||||||
m_ipc.registerForIPC("configreloaded", this);
|
m_ipc.registerForIPC("configreloaded", this);
|
||||||
|
|
||||||
if (windowRewriteConfigUsesTitle() || m_taskbarWithTitle) {
|
if (windowRewriteConfigUsesTitle() || m_taskbarWithTitle) {
|
||||||
spdlog::info(
|
spdlog::info(
|
||||||
"Registering for Hyprland's 'windowtitle' events because a user-defined window "
|
"Registering for Hyprland's 'windowtitlev2' events because a user-defined window "
|
||||||
"rewrite rule uses the 'title' field.");
|
"rewrite rule uses the 'title' field.");
|
||||||
m_ipc.registerForIPC("windowtitle", this);
|
m_ipc.registerForIPC("windowtitlev2", this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::removeWorkspacesToRemove() {
|
void Workspaces::removeWorkspacesToRemove() {
|
||||||
for (const auto &workspaceName : m_workspacesToRemove) {
|
for (const auto &workspaceString : m_workspacesToRemove) {
|
||||||
removeWorkspace(workspaceName);
|
removeWorkspace(workspaceString);
|
||||||
}
|
}
|
||||||
m_workspacesToRemove.clear();
|
m_workspacesToRemove.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::removeWorkspace(std::string const &name) {
|
void Workspaces::removeWorkspace(std::string const &workspaceString) {
|
||||||
spdlog::debug("Removing workspace {}", name);
|
spdlog::debug("Removing workspace {}", workspaceString);
|
||||||
auto workspace =
|
|
||||||
std::find_if(m_workspaces.begin(), m_workspaces.end(), [&](std::unique_ptr<Workspace> &x) {
|
// If this succeeds, we have a workspace ID.
|
||||||
return (name.starts_with("special:") && name.substr(8) == x->name()) || name == x->name();
|
const auto workspaceId = parseWorkspaceId(workspaceString);
|
||||||
});
|
|
||||||
|
std::string name;
|
||||||
|
// TODO: At some point we want to support all workspace selectors
|
||||||
|
// This is just a subset.
|
||||||
|
// https://wiki.hyprland.org/Configuring/Workspace-Rules/#workspace-selectors
|
||||||
|
if (workspaceString.starts_with("special:")) {
|
||||||
|
name = workspaceString.substr(8);
|
||||||
|
} else if (workspaceString.starts_with("name:")) {
|
||||||
|
name = workspaceString.substr(5);
|
||||||
|
} else {
|
||||||
|
name = workspaceString;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto workspace = std::ranges::find_if(m_workspaces, [&](std::unique_ptr<Workspace> &x) {
|
||||||
|
if (workspaceId.has_value()) {
|
||||||
|
return *workspaceId == x->id();
|
||||||
|
}
|
||||||
|
return name == x->name();
|
||||||
|
});
|
||||||
|
|
||||||
if (workspace == m_workspaces.end()) {
|
if (workspace == m_workspaces.end()) {
|
||||||
// happens when a workspace on another monitor is destroyed
|
// happens when a workspace on another monitor is destroyed
|
||||||
@ -762,7 +805,8 @@ void Workspaces::removeWorkspace(std::string const &name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((*workspace)->isPersistentConfig()) {
|
if ((*workspace)->isPersistentConfig()) {
|
||||||
spdlog::trace("Not removing config persistent workspace {}", name);
|
spdlog::trace("Not removing config persistent workspace id={} name={}", (*workspace)->id(),
|
||||||
|
(*workspace)->name());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -774,9 +818,9 @@ void Workspaces::setCurrentMonitorId() {
|
|||||||
// get monitor ID from name (used by persistent workspaces)
|
// get monitor ID from name (used by persistent workspaces)
|
||||||
m_monitorId = 0;
|
m_monitorId = 0;
|
||||||
auto monitors = m_ipc.getSocket1JsonReply("monitors");
|
auto monitors = m_ipc.getSocket1JsonReply("monitors");
|
||||||
auto currentMonitor = std::find_if(
|
auto currentMonitor = std::ranges::find_if(monitors, [this](const Json::Value &m) {
|
||||||
monitors.begin(), monitors.end(),
|
return m["name"].asString() == m_bar.output->name;
|
||||||
[this](const Json::Value &m) { return m["name"].asString() == m_bar.output->name; });
|
});
|
||||||
if (currentMonitor == monitors.end()) {
|
if (currentMonitor == monitors.end()) {
|
||||||
spdlog::error("Monitor '{}' does not have an ID? Using 0", m_bar.output->name);
|
spdlog::error("Monitor '{}' does not have an ID? Using 0", m_bar.output->name);
|
||||||
} else {
|
} else {
|
||||||
@ -786,62 +830,63 @@ void Workspaces::setCurrentMonitorId() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::sortWorkspaces() {
|
void Workspaces::sortWorkspaces() {
|
||||||
std::sort(m_workspaces.begin(), m_workspaces.end(),
|
std::ranges::sort( //
|
||||||
[&](std::unique_ptr<Workspace> &a, std::unique_ptr<Workspace> &b) {
|
m_workspaces, [&](std::unique_ptr<Workspace> &a, std::unique_ptr<Workspace> &b) {
|
||||||
// Helper comparisons
|
// Helper comparisons
|
||||||
auto isIdLess = a->id() < b->id();
|
auto isIdLess = a->id() < b->id();
|
||||||
auto isNameLess = a->name() < b->name();
|
auto isNameLess = a->name() < b->name();
|
||||||
|
|
||||||
switch (m_sortBy) {
|
switch (m_sortBy) {
|
||||||
case SortMethod::ID:
|
case SortMethod::ID:
|
||||||
return isIdLess;
|
return isIdLess;
|
||||||
case SortMethod::NAME:
|
case SortMethod::NAME:
|
||||||
return isNameLess;
|
return isNameLess;
|
||||||
case SortMethod::NUMBER:
|
case SortMethod::NUMBER:
|
||||||
try {
|
try {
|
||||||
return std::stoi(a->name()) < std::stoi(b->name());
|
return std::stoi(a->name()) < std::stoi(b->name());
|
||||||
} catch (const std::invalid_argument &) {
|
} catch (const std::invalid_argument &) {
|
||||||
// Handle the exception if necessary.
|
// Handle the exception if necessary.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SortMethod::DEFAULT:
|
case SortMethod::DEFAULT:
|
||||||
default:
|
default:
|
||||||
// Handle the default case here.
|
// Handle the default case here.
|
||||||
// normal -> named persistent -> named -> special -> named special
|
// normal -> named persistent -> named -> special -> named special
|
||||||
|
|
||||||
// both normal (includes numbered persistent) => sort by ID
|
// both normal (includes numbered persistent) => sort by ID
|
||||||
if (a->id() > 0 && b->id() > 0) {
|
if (a->id() > 0 && b->id() > 0) {
|
||||||
return isIdLess;
|
return isIdLess;
|
||||||
}
|
}
|
||||||
|
|
||||||
// one normal, one special => normal first
|
// one normal, one special => normal first
|
||||||
if ((a->isSpecial()) ^ (b->isSpecial())) {
|
if ((a->isSpecial()) ^ (b->isSpecial())) {
|
||||||
return b->isSpecial();
|
return b->isSpecial();
|
||||||
}
|
}
|
||||||
|
|
||||||
// only one normal, one named
|
// only one normal, one named
|
||||||
if ((a->id() > 0) ^ (b->id() > 0)) {
|
if ((a->id() > 0) ^ (b->id() > 0)) {
|
||||||
return a->id() > 0;
|
return a->id() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// both special
|
// both special
|
||||||
if (a->isSpecial() && b->isSpecial()) {
|
if (a->isSpecial() && b->isSpecial()) {
|
||||||
// if one is -99 => put it last
|
// if one is -99 => put it last
|
||||||
if (a->id() == -99 || b->id() == -99) {
|
if (a->id() == -99 || b->id() == -99) {
|
||||||
return b->id() == -99;
|
return b->id() == -99;
|
||||||
}
|
|
||||||
// both are 0 (not yet named persistents) / named specials (-98 <= ID <= -1)
|
|
||||||
return isNameLess;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort non-special named workspaces by name (ID <= -1377)
|
|
||||||
return isNameLess;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
// both are 0 (not yet named persistents) / named specials
|
||||||
|
// (-98 <= ID <= -1)
|
||||||
|
return isNameLess;
|
||||||
|
}
|
||||||
|
|
||||||
// Return a default value if none of the cases match.
|
// sort non-special named workspaces by name (ID <= -1377)
|
||||||
return isNameLess; // You can adjust this to your specific needs.
|
return isNameLess;
|
||||||
});
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a default value if none of the cases match.
|
||||||
|
return isNameLess; // You can adjust this to your specific needs.
|
||||||
|
});
|
||||||
|
|
||||||
for (size_t i = 0; i < m_workspaces.size(); ++i) {
|
for (size_t i = 0; i < m_workspaces.size(); ++i) {
|
||||||
m_box.reorder_child(m_workspaces[i]->button(), i);
|
m_box.reorder_child(m_workspaces[i]->button(), i);
|
||||||
@ -859,9 +904,9 @@ void Workspaces::setUrgentWorkspace(std::string const &windowaddress) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto workspace =
|
auto workspace = std::ranges::find_if(m_workspaces, [workspaceId](std::unique_ptr<Workspace> &x) {
|
||||||
std::find_if(m_workspaces.begin(), m_workspaces.end(),
|
return x->id() == workspaceId;
|
||||||
[workspaceId](std::unique_ptr<Workspace> &x) { return x->id() == workspaceId; });
|
});
|
||||||
if (workspace != m_workspaces.end()) {
|
if (workspace != m_workspaces.end()) {
|
||||||
workspace->get()->setUrgent();
|
workspace->get()->setUrgent();
|
||||||
}
|
}
|
||||||
@ -875,11 +920,10 @@ auto Workspaces::update() -> void {
|
|||||||
void Workspaces::updateWindowCount() {
|
void Workspaces::updateWindowCount() {
|
||||||
const Json::Value workspacesJson = m_ipc.getSocket1JsonReply("workspaces");
|
const Json::Value workspacesJson = m_ipc.getSocket1JsonReply("workspaces");
|
||||||
for (auto &workspace : m_workspaces) {
|
for (auto &workspace : m_workspaces) {
|
||||||
auto workspaceJson =
|
auto workspaceJson = std::ranges::find_if(workspacesJson, [&](Json::Value const &x) {
|
||||||
std::find_if(workspacesJson.begin(), workspacesJson.end(), [&](Json::Value const &x) {
|
return x["name"].asString() == workspace->name() ||
|
||||||
return x["name"].asString() == workspace->name() ||
|
(workspace->isSpecial() && x["name"].asString() == "special:" + workspace->name());
|
||||||
(workspace->isSpecial() && x["name"].asString() == "special:" + workspace->name());
|
});
|
||||||
});
|
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
if (workspaceJson != workspacesJson.end()) {
|
if (workspaceJson != workspacesJson.end()) {
|
||||||
try {
|
try {
|
||||||
@ -919,26 +963,26 @@ bool Workspaces::updateWindowsToCreate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::updateWorkspaceStates() {
|
void Workspaces::updateWorkspaceStates() {
|
||||||
const std::vector<std::string> visibleWorkspaces = getVisibleWorkspaces();
|
const std::vector<int> visibleWorkspaces = getVisibleWorkspaces();
|
||||||
auto updatedWorkspaces = m_ipc.getSocket1JsonReply("workspaces");
|
auto updatedWorkspaces = m_ipc.getSocket1JsonReply("workspaces");
|
||||||
for (auto &workspace : m_workspaces) {
|
for (auto &workspace : m_workspaces) {
|
||||||
workspace->setActive(workspace->name() == m_activeWorkspaceName ||
|
workspace->setActive(
|
||||||
workspace->name() == m_activeSpecialWorkspaceName);
|
workspace->id() == m_activeWorkspaceId ||
|
||||||
|
(workspace->isSpecial() && workspace->name() == m_activeSpecialWorkspaceName));
|
||||||
if (workspace->isActive() && workspace->isUrgent()) {
|
if (workspace->isActive() && workspace->isUrgent()) {
|
||||||
workspace->setUrgent(false);
|
workspace->setUrgent(false);
|
||||||
}
|
}
|
||||||
workspace->setVisible(std::find(visibleWorkspaces.begin(), visibleWorkspaces.end(),
|
workspace->setVisible(std::ranges::find(visibleWorkspaces, workspace->id()) !=
|
||||||
workspace->name()) != visibleWorkspaces.end());
|
visibleWorkspaces.end());
|
||||||
std::string &workspaceIcon = m_iconsMap[""];
|
std::string &workspaceIcon = m_iconsMap[""];
|
||||||
if (m_withIcon) {
|
if (m_withIcon) {
|
||||||
workspaceIcon = workspace->selectIcon(m_iconsMap);
|
workspaceIcon = workspace->selectIcon(m_iconsMap);
|
||||||
}
|
}
|
||||||
auto updatedWorkspace = std::find_if(
|
auto updatedWorkspace = std::ranges::find_if(updatedWorkspaces, [&workspace](const auto &w) {
|
||||||
updatedWorkspaces.begin(), updatedWorkspaces.end(), [&workspace](const auto &w) {
|
auto wNameRaw = w["name"].asString();
|
||||||
auto wNameRaw = w["name"].asString();
|
auto wName = wNameRaw.starts_with("special:") ? wNameRaw.substr(8) : wNameRaw;
|
||||||
auto wName = wNameRaw.starts_with("special:") ? wNameRaw.substr(8) : wNameRaw;
|
return wName == workspace->name();
|
||||||
return wName == workspace->name();
|
});
|
||||||
});
|
|
||||||
if (updatedWorkspace != updatedWorkspaces.end()) {
|
if (updatedWorkspace != updatedWorkspaces.end()) {
|
||||||
workspace->setOutput((*updatedWorkspace)["monitor"].asString());
|
workspace->setOutput((*updatedWorkspace)["monitor"].asString());
|
||||||
}
|
}
|
||||||
@ -966,4 +1010,39 @@ int Workspaces::windowRewritePriorityFunction(std::string const &window_rule) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::string Workspaces::makePayload(Args const &...args) {
|
||||||
|
std::ostringstream result;
|
||||||
|
bool first = true;
|
||||||
|
((result << (first ? "" : ",") << args, first = false), ...);
|
||||||
|
return result.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::string, std::string> Workspaces::splitDoublePayload(std::string const &payload) {
|
||||||
|
const std::string part1 = payload.substr(0, payload.find(','));
|
||||||
|
const std::string part2 = payload.substr(part1.size() + 1);
|
||||||
|
return {part1, part2};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<std::string, std::string, std::string> Workspaces::splitTriplePayload(
|
||||||
|
std::string const &payload) {
|
||||||
|
const size_t firstComma = payload.find(',');
|
||||||
|
const size_t secondComma = payload.find(',', firstComma + 1);
|
||||||
|
|
||||||
|
const std::string part1 = payload.substr(0, firstComma);
|
||||||
|
const std::string part2 = payload.substr(firstComma + 1, secondComma - (firstComma + 1));
|
||||||
|
const std::string part3 = payload.substr(secondComma + 1);
|
||||||
|
|
||||||
|
return {part1, part2, part3};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> Workspaces::parseWorkspaceId(std::string const &workspaceIdStr) {
|
||||||
|
try {
|
||||||
|
return workspaceIdStr == "special" ? -99 : std::stoi(workspaceIdStr);
|
||||||
|
} catch (std::exception const &e) {
|
||||||
|
spdlog::error("Failed to parse workspace ID: {}", e.what());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace waybar::modules::hyprland
|
} // namespace waybar::modules::hyprland
|
||||||
|
@ -80,6 +80,7 @@ waybar::modules::Network::readBandwidthUsage() {
|
|||||||
waybar::modules::Network::Network(const std::string &id, const Json::Value &config)
|
waybar::modules::Network::Network(const std::string &id, const Json::Value &config)
|
||||||
: ALabel(config, "network", id, DEFAULT_FORMAT, 60),
|
: ALabel(config, "network", id, DEFAULT_FORMAT, 60),
|
||||||
ifid_(-1),
|
ifid_(-1),
|
||||||
|
addr_pref_(IPV4),
|
||||||
efd_(-1),
|
efd_(-1),
|
||||||
ev_fd_(-1),
|
ev_fd_(-1),
|
||||||
want_route_dump_(false),
|
want_route_dump_(false),
|
||||||
@ -88,6 +89,7 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf
|
|||||||
dump_in_progress_(false),
|
dump_in_progress_(false),
|
||||||
is_p2p_(false),
|
is_p2p_(false),
|
||||||
cidr_(0),
|
cidr_(0),
|
||||||
|
cidr6_(0),
|
||||||
signal_strength_dbm_(0),
|
signal_strength_dbm_(0),
|
||||||
signal_strength_(0),
|
signal_strength_(0),
|
||||||
#ifdef WANT_RFKILL
|
#ifdef WANT_RFKILL
|
||||||
@ -101,6 +103,12 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf
|
|||||||
// the module start with no text, but the event_box_ is shown.
|
// the module start with no text, but the event_box_ is shown.
|
||||||
label_.set_markup("<s></s>");
|
label_.set_markup("<s></s>");
|
||||||
|
|
||||||
|
if (config_["family"] == "ipv6") {
|
||||||
|
addr_pref_ = IPV6;
|
||||||
|
} else if (config["family"] == "ipv4_6") {
|
||||||
|
addr_pref_ = IPV4_6;
|
||||||
|
}
|
||||||
|
|
||||||
auto bandwidth = readBandwidthUsage();
|
auto bandwidth = readBandwidthUsage();
|
||||||
if (bandwidth.has_value()) {
|
if (bandwidth.has_value()) {
|
||||||
bandwidth_down_total_ = (*bandwidth).first;
|
bandwidth_down_total_ = (*bandwidth).first;
|
||||||
@ -270,7 +278,7 @@ const std::string waybar::modules::Network::getNetworkState() const {
|
|||||||
return "disconnected";
|
return "disconnected";
|
||||||
}
|
}
|
||||||
if (!carrier_) return "disconnected";
|
if (!carrier_) return "disconnected";
|
||||||
if (ipaddr_.empty()) return "linked";
|
if (ipaddr_.empty() && ipaddr6_.empty()) return "linked";
|
||||||
if (essid_.empty()) return "ethernet";
|
if (essid_.empty()) return "ethernet";
|
||||||
return "wifi";
|
return "wifi";
|
||||||
}
|
}
|
||||||
@ -316,12 +324,24 @@ auto waybar::modules::Network::update() -> void {
|
|||||||
}
|
}
|
||||||
getState(signal_strength_);
|
getState(signal_strength_);
|
||||||
|
|
||||||
|
std::string final_ipaddr_;
|
||||||
|
if (addr_pref_ == ip_addr_pref::IPV4) {
|
||||||
|
final_ipaddr_ = ipaddr_;
|
||||||
|
} else if (addr_pref_ == ip_addr_pref::IPV6) {
|
||||||
|
final_ipaddr_ = ipaddr6_;
|
||||||
|
} else if (addr_pref_ == ip_addr_pref::IPV4_6) {
|
||||||
|
final_ipaddr_ = ipaddr_;
|
||||||
|
final_ipaddr_ += '\n';
|
||||||
|
final_ipaddr_ += ipaddr6_;
|
||||||
|
}
|
||||||
|
|
||||||
auto text = fmt::format(
|
auto text = fmt::format(
|
||||||
fmt::runtime(format_), fmt::arg("essid", essid_), fmt::arg("bssid", bssid_),
|
fmt::runtime(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("netmask6", netmask6_),
|
||||||
fmt::arg("cidr", cidr_), fmt::arg("frequency", fmt::format("{:.1f}", frequency_)),
|
fmt::arg("ipaddr", final_ipaddr_), fmt::arg("gwaddr", gwaddr_), fmt::arg("cidr", cidr_),
|
||||||
|
fmt::arg("cidr6", cidr6_), fmt::arg("frequency", fmt::format("{:.1f}", frequency_)),
|
||||||
fmt::arg("icon", getIcon(signal_strength_, state_)),
|
fmt::arg("icon", getIcon(signal_strength_, state_)),
|
||||||
fmt::arg("bandwidthDownBits", pow_format(bandwidth_down * 8ull / interval_.count(), "b/s")),
|
fmt::arg("bandwidthDownBits", pow_format(bandwidth_down * 8ull / interval_.count(), "b/s")),
|
||||||
fmt::arg("bandwidthUpBits", pow_format(bandwidth_up * 8ull / interval_.count(), "b/s")),
|
fmt::arg("bandwidthUpBits", pow_format(bandwidth_up * 8ull / interval_.count(), "b/s")),
|
||||||
@ -352,8 +372,9 @@ auto waybar::modules::Network::update() -> void {
|
|||||||
fmt::runtime(tooltip_format), fmt::arg("essid", essid_), fmt::arg("bssid", bssid_),
|
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("netmask6", netmask6_),
|
||||||
fmt::arg("cidr", cidr_), fmt::arg("frequency", fmt::format("{:.1f}", frequency_)),
|
fmt::arg("ipaddr", final_ipaddr_), fmt::arg("gwaddr", gwaddr_), fmt::arg("cidr", cidr_),
|
||||||
|
fmt::arg("cidr6", cidr6_), fmt::arg("frequency", fmt::format("{:.1f}", frequency_)),
|
||||||
fmt::arg("icon", getIcon(signal_strength_, state_)),
|
fmt::arg("icon", getIcon(signal_strength_, state_)),
|
||||||
fmt::arg("bandwidthDownBits",
|
fmt::arg("bandwidthDownBits",
|
||||||
pow_format(bandwidth_down * 8ull / interval_.count(), "b/s")),
|
pow_format(bandwidth_down * 8ull / interval_.count(), "b/s")),
|
||||||
@ -394,10 +415,13 @@ void waybar::modules::Network::clearIface() {
|
|||||||
essid_.clear();
|
essid_.clear();
|
||||||
bssid_.clear();
|
bssid_.clear();
|
||||||
ipaddr_.clear();
|
ipaddr_.clear();
|
||||||
|
ipaddr6_.clear();
|
||||||
gwaddr_.clear();
|
gwaddr_.clear();
|
||||||
netmask_.clear();
|
netmask_.clear();
|
||||||
|
netmask6_.clear();
|
||||||
carrier_ = false;
|
carrier_ = false;
|
||||||
cidr_ = 0;
|
cidr_ = 0;
|
||||||
|
cidr6_ = 0;
|
||||||
signal_strength_dbm_ = 0;
|
signal_strength_dbm_ = 0;
|
||||||
signal_strength_ = 0;
|
signal_strength_ = 0;
|
||||||
signal_strength_app_.clear();
|
signal_strength_app_.clear();
|
||||||
@ -521,7 +545,6 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
|
|||||||
if (ifa->ifa_scope >= RT_SCOPE_LINK) {
|
if (ifa->ifa_scope >= RT_SCOPE_LINK) {
|
||||||
return NL_OK;
|
return NL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; RTA_OK(ifa_rta, attrlen); ifa_rta = RTA_NEXT(ifa_rta, attrlen)) {
|
for (; RTA_OK(ifa_rta, attrlen); ifa_rta = RTA_NEXT(ifa_rta, attrlen)) {
|
||||||
switch (ifa_rta->rta_type) {
|
switch (ifa_rta->rta_type) {
|
||||||
case IFA_ADDRESS:
|
case IFA_ADDRESS:
|
||||||
@ -529,8 +552,20 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
|
|||||||
case IFA_LOCAL:
|
case IFA_LOCAL:
|
||||||
char ipaddr[INET6_ADDRSTRLEN];
|
char ipaddr[INET6_ADDRSTRLEN];
|
||||||
if (!is_del_event) {
|
if (!is_del_event) {
|
||||||
net->ipaddr_ = inet_ntop(ifa->ifa_family, RTA_DATA(ifa_rta), ipaddr, sizeof(ipaddr));
|
if ((net->addr_pref_ == ip_addr_pref::IPV4 ||
|
||||||
net->cidr_ = ifa->ifa_prefixlen;
|
net->addr_pref_ == ip_addr_pref::IPV4_6) &&
|
||||||
|
net->cidr_ == 0 && ifa->ifa_family == AF_INET) {
|
||||||
|
net->ipaddr_ =
|
||||||
|
inet_ntop(ifa->ifa_family, RTA_DATA(ifa_rta), ipaddr, sizeof(ipaddr));
|
||||||
|
net->cidr_ = ifa->ifa_prefixlen;
|
||||||
|
} else if ((net->addr_pref_ == ip_addr_pref::IPV6 ||
|
||||||
|
net->addr_pref_ == ip_addr_pref::IPV4_6) &&
|
||||||
|
net->cidr6_ == 0 && ifa->ifa_family == AF_INET6) {
|
||||||
|
net->ipaddr6_ =
|
||||||
|
inet_ntop(ifa->ifa_family, RTA_DATA(ifa_rta), ipaddr, sizeof(ipaddr));
|
||||||
|
net->cidr6_ = ifa->ifa_prefixlen;
|
||||||
|
}
|
||||||
|
|
||||||
switch (ifa->ifa_family) {
|
switch (ifa->ifa_family) {
|
||||||
case AF_INET: {
|
case AF_INET: {
|
||||||
struct in_addr netmask;
|
struct in_addr netmask;
|
||||||
@ -538,21 +573,24 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
|
|||||||
net->netmask_ = inet_ntop(ifa->ifa_family, &netmask, ipaddr, sizeof(ipaddr));
|
net->netmask_ = inet_ntop(ifa->ifa_family, &netmask, ipaddr, sizeof(ipaddr));
|
||||||
}
|
}
|
||||||
case AF_INET6: {
|
case AF_INET6: {
|
||||||
struct in6_addr netmask;
|
struct in6_addr netmask6;
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
int v = (i + 1) * 8 - ifa->ifa_prefixlen;
|
int v = (i + 1) * 8 - ifa->ifa_prefixlen;
|
||||||
if (v < 0) v = 0;
|
if (v < 0) v = 0;
|
||||||
if (v > 8) v = 8;
|
if (v > 8) v = 8;
|
||||||
netmask.s6_addr[i] = ~0 << v;
|
netmask6.s6_addr[i] = ~0 << v;
|
||||||
}
|
}
|
||||||
net->netmask_ = inet_ntop(ifa->ifa_family, &netmask, ipaddr, sizeof(ipaddr));
|
net->netmask6_ = inet_ntop(ifa->ifa_family, &netmask6, ipaddr, sizeof(ipaddr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spdlog::debug("network: {}, new addr {}/{}", net->ifname_, net->ipaddr_, net->cidr_);
|
spdlog::debug("network: {}, new addr {}/{}", net->ifname_, net->ipaddr_, net->cidr_);
|
||||||
} else {
|
} else {
|
||||||
net->ipaddr_.clear();
|
net->ipaddr_.clear();
|
||||||
|
net->ipaddr6_.clear();
|
||||||
net->cidr_ = 0;
|
net->cidr_ = 0;
|
||||||
|
net->cidr6_ = 0;
|
||||||
net->netmask_.clear();
|
net->netmask_.clear();
|
||||||
|
net->netmask6_.clear();
|
||||||
spdlog::debug("network: {} addr deleted {}/{}", net->ifname_,
|
spdlog::debug("network: {} addr deleted {}/{}", net->ifname_,
|
||||||
inet_ntop(ifa->ifa_family, RTA_DATA(ifa_rta), ipaddr, sizeof(ipaddr)),
|
inet_ntop(ifa->ifa_family, RTA_DATA(ifa_rta), ipaddr, sizeof(ipaddr)),
|
||||||
ifa->ifa_prefixlen);
|
ifa->ifa_prefixlen);
|
||||||
|
@ -15,13 +15,14 @@ using util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_OUTPUT;
|
|||||||
using util::PipewireBackend::PRIVACY_NODE_TYPE_NONE;
|
using util::PipewireBackend::PRIVACY_NODE_TYPE_NONE;
|
||||||
using util::PipewireBackend::PRIVACY_NODE_TYPE_VIDEO_INPUT;
|
using util::PipewireBackend::PRIVACY_NODE_TYPE_VIDEO_INPUT;
|
||||||
|
|
||||||
Privacy::Privacy(const std::string& id, const Json::Value& config, const std::string& pos)
|
Privacy::Privacy(const std::string& id, const Json::Value& config, Gtk::Orientation orientation,
|
||||||
|
const std::string& pos)
|
||||||
: AModule(config, "privacy", id),
|
: AModule(config, "privacy", id),
|
||||||
nodes_screenshare(),
|
nodes_screenshare(),
|
||||||
nodes_audio_in(),
|
nodes_audio_in(),
|
||||||
nodes_audio_out(),
|
nodes_audio_out(),
|
||||||
visibility_conn(),
|
visibility_conn(),
|
||||||
box_(Gtk::ORIENTATION_HORIZONTAL, 0) {
|
box_(orientation, 0) {
|
||||||
box_.set_name(name_);
|
box_.set_name(name_);
|
||||||
|
|
||||||
event_box_.add(box_);
|
event_box_.add(box_);
|
||||||
@ -67,8 +68,8 @@ Privacy::Privacy(const std::string& id, const Json::Value& config, const std::st
|
|||||||
auto iter = typeMap.find(type);
|
auto iter = typeMap.find(type);
|
||||||
if (iter != typeMap.end()) {
|
if (iter != typeMap.end()) {
|
||||||
auto& [nodePtr, nodeType] = iter->second;
|
auto& [nodePtr, nodeType] = iter->second;
|
||||||
auto* item = Gtk::make_managed<PrivacyItem>(module, nodeType, nodePtr, pos, iconSize,
|
auto* item = Gtk::make_managed<PrivacyItem>(module, nodeType, nodePtr, orientation, pos,
|
||||||
transition_duration);
|
iconSize, transition_duration);
|
||||||
box_.add(*item);
|
box_.add(*item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,9 @@
|
|||||||
namespace waybar::modules::privacy {
|
namespace waybar::modules::privacy {
|
||||||
|
|
||||||
PrivacyItem::PrivacyItem(const Json::Value &config_, enum PrivacyNodeType privacy_type_,
|
PrivacyItem::PrivacyItem(const Json::Value &config_, enum PrivacyNodeType privacy_type_,
|
||||||
std::list<PrivacyNodeInfo *> *nodes_, const std::string &pos,
|
std::list<PrivacyNodeInfo *> *nodes_, Gtk::Orientation orientation,
|
||||||
const uint icon_size, const uint transition_duration)
|
const std::string &pos, const uint icon_size,
|
||||||
|
const uint transition_duration)
|
||||||
: Gtk::Revealer(),
|
: Gtk::Revealer(),
|
||||||
privacy_type(privacy_type_),
|
privacy_type(privacy_type_),
|
||||||
nodes(nodes_),
|
nodes(nodes_),
|
||||||
@ -40,16 +41,24 @@ PrivacyItem::PrivacyItem(const Json::Value &config_, enum PrivacyNodeType privac
|
|||||||
|
|
||||||
// Set the reveal transition to not look weird when sliding in
|
// Set the reveal transition to not look weird when sliding in
|
||||||
if (pos == "modules-left") {
|
if (pos == "modules-left") {
|
||||||
set_transition_type(Gtk::REVEALER_TRANSITION_TYPE_SLIDE_RIGHT);
|
set_transition_type(orientation == Gtk::ORIENTATION_HORIZONTAL
|
||||||
|
? Gtk::REVEALER_TRANSITION_TYPE_SLIDE_RIGHT
|
||||||
|
: Gtk::REVEALER_TRANSITION_TYPE_SLIDE_DOWN);
|
||||||
} else if (pos == "modules-center") {
|
} else if (pos == "modules-center") {
|
||||||
set_transition_type(Gtk::REVEALER_TRANSITION_TYPE_CROSSFADE);
|
set_transition_type(Gtk::REVEALER_TRANSITION_TYPE_CROSSFADE);
|
||||||
} else if (pos == "modules-right") {
|
} else if (pos == "modules-right") {
|
||||||
set_transition_type(Gtk::REVEALER_TRANSITION_TYPE_SLIDE_LEFT);
|
set_transition_type(orientation == Gtk::ORIENTATION_HORIZONTAL
|
||||||
|
? Gtk::REVEALER_TRANSITION_TYPE_SLIDE_LEFT
|
||||||
|
: Gtk::REVEALER_TRANSITION_TYPE_SLIDE_UP);
|
||||||
}
|
}
|
||||||
set_transition_duration(transition_duration);
|
set_transition_duration(transition_duration);
|
||||||
|
|
||||||
box_.set_name("privacy-item");
|
box_.set_name("privacy-item");
|
||||||
box_.add(icon_);
|
|
||||||
|
// We use `set_center_widget` instead of `add` to make sure the icon is
|
||||||
|
// centered even if the orientation is vertical
|
||||||
|
box_.set_center_widget(icon_);
|
||||||
|
|
||||||
icon_.set_pixel_size(icon_size);
|
icon_.set_pixel_size(icon_size);
|
||||||
add(box_);
|
add(box_);
|
||||||
|
|
||||||
|
@ -5,10 +5,12 @@
|
|||||||
#include <gtkmm/tooltip.h>
|
#include <gtkmm/tooltip.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "gdk/gdk.h"
|
#include "gdk/gdk.h"
|
||||||
|
#include "modules/sni/icon_manager.hpp"
|
||||||
#include "util/format.hpp"
|
#include "util/format.hpp"
|
||||||
#include "util/gtk_icon.hpp"
|
#include "util/gtk_icon.hpp"
|
||||||
|
|
||||||
@ -138,6 +140,7 @@ void Item::setProperty(const Glib::ustring& name, Glib::VariantBase& value) {
|
|||||||
category = get_variant<std::string>(value);
|
category = get_variant<std::string>(value);
|
||||||
} else if (name == "Id") {
|
} else if (name == "Id") {
|
||||||
id = get_variant<std::string>(value);
|
id = get_variant<std::string>(value);
|
||||||
|
setCustomIcon(id);
|
||||||
} else if (name == "Title") {
|
} else if (name == "Title") {
|
||||||
title = get_variant<std::string>(value);
|
title = get_variant<std::string>(value);
|
||||||
if (tooltip.text.empty()) {
|
if (tooltip.text.empty()) {
|
||||||
@ -199,6 +202,19 @@ void Item::setStatus(const Glib::ustring& value) {
|
|||||||
style->add_class(lower);
|
style->add_class(lower);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Item::setCustomIcon(const std::string& id) {
|
||||||
|
std::string custom_icon = IconManager::instance().getIconForApp(id);
|
||||||
|
if (!custom_icon.empty()) {
|
||||||
|
if (std::filesystem::exists(custom_icon)) {
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> custom_pixbuf = Gdk::Pixbuf::create_from_file(custom_icon);
|
||||||
|
icon_name = ""; // icon_name has priority over pixmap
|
||||||
|
icon_pixmap = custom_pixbuf;
|
||||||
|
} else { // if file doesn't exist it's most likely an icon_name
|
||||||
|
icon_name = custom_icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Item::getUpdatedProperties() {
|
void Item::getUpdatedProperties() {
|
||||||
auto params = Glib::VariantContainerBase::create_tuple(
|
auto params = Glib::VariantContainerBase::create_tuple(
|
||||||
{Glib::Variant<Glib::ustring>::create(SNI_INTERFACE_NAME)});
|
{Glib::Variant<Glib::ustring>::create(SNI_INTERFACE_NAME)});
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include "modules/sni/icon_manager.hpp"
|
||||||
|
|
||||||
namespace waybar::modules::SNI {
|
namespace waybar::modules::SNI {
|
||||||
|
|
||||||
Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
|
Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||||
@ -20,6 +22,9 @@ Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
|
|||||||
box_.set_spacing(config_["spacing"].asUInt());
|
box_.set_spacing(config_["spacing"].asUInt());
|
||||||
}
|
}
|
||||||
nb_hosts_ += 1;
|
nb_hosts_ += 1;
|
||||||
|
if (config_["icons"].isObject()) {
|
||||||
|
IconManager::instance().setIconsConfig(config_["icons"]);
|
||||||
|
}
|
||||||
dp.emit();
|
dp.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,16 +494,34 @@ std::string Workspaces::trimWorkspaceName(std::string name) {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_focused_recursive(const Json::Value& node) {
|
||||||
|
// If a workspace has a focused container then get_tree will say
|
||||||
|
// that the workspace itself isn't focused. Therefore we need to
|
||||||
|
// check if any of its nodes are focused as well.
|
||||||
|
// some layouts like tabbed have many nested nodes
|
||||||
|
// all nested nodes must be checked for focused flag
|
||||||
|
if (node["focused"].asBool()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& child : node["nodes"]) {
|
||||||
|
if (is_focused_recursive(child)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& child : node["floating_nodes"]) {
|
||||||
|
if (is_focused_recursive(child)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Workspaces::onButtonReady(const Json::Value &node, Gtk::Button &button) {
|
void Workspaces::onButtonReady(const Json::Value &node, Gtk::Button &button) {
|
||||||
if (config_["current-only"].asBool()) {
|
if (config_["current-only"].asBool()) {
|
||||||
// If a workspace has a focused container then get_tree will say
|
if (is_focused_recursive(node)) {
|
||||||
// that the workspace itself isn't focused. Therefore we need to
|
|
||||||
// check if any of its nodes are focused as well.
|
|
||||||
bool focused = node["focused"].asBool() ||
|
|
||||||
std::any_of(node["nodes"].begin(), node["nodes"].end(),
|
|
||||||
[](const auto &child) { return child["focused"].asBool(); });
|
|
||||||
|
|
||||||
if (focused) {
|
|
||||||
button.show();
|
button.show();
|
||||||
} else {
|
} else {
|
||||||
button.hide();
|
button.hide();
|
||||||
|
@ -114,13 +114,17 @@ float waybar::modules::Temperature::getTemperature() {
|
|||||||
|
|
||||||
auto zone = config_["thermal-zone"].isInt() ? config_["thermal-zone"].asInt() : 0;
|
auto zone = config_["thermal-zone"].isInt() ? config_["thermal-zone"].asInt() : 0;
|
||||||
|
|
||||||
if (sysctlbyname(fmt::format("hw.acpi.thermal.tz{}.temperature", zone).c_str(), &temp, &size,
|
// First, try with dev.cpu
|
||||||
NULL, 0) != 0) {
|
if ((sysctlbyname(fmt::format("dev.cpu.{}.temperature", zone).c_str(), &temp, &size, NULL, 0) ==
|
||||||
throw std::runtime_error(fmt::format(
|
0) ||
|
||||||
"sysctl hw.acpi.thermal.tz{}.temperature or dev.cpu.{}.temperature failed", zone, zone));
|
(sysctlbyname(fmt::format("hw.acpi.thermal.tz{}.temperature", zone).c_str(), &temp, &size,
|
||||||
|
NULL, 0) == 0)) {
|
||||||
|
auto temperature_c = ((float)temp - 2732) / 10;
|
||||||
|
return temperature_c;
|
||||||
}
|
}
|
||||||
auto temperature_c = ((float)temp - 2732) / 10;
|
|
||||||
return temperature_c;
|
throw std::runtime_error(fmt::format(
|
||||||
|
"sysctl hw.acpi.thermal.tz{}.temperature and dev.cpu.{}.temperature failed", zone, zone));
|
||||||
|
|
||||||
#else // Linux
|
#else // Linux
|
||||||
std::ifstream temp(file_path_);
|
std::ifstream temp(file_path_);
|
||||||
@ -148,4 +152,4 @@ bool waybar::modules::Temperature::isWarning(uint16_t temperature_c) {
|
|||||||
bool waybar::modules::Temperature::isCritical(uint16_t temperature_c) {
|
bool waybar::modules::Temperature::isCritical(uint16_t temperature_c) {
|
||||||
return config_["critical-threshold"].isInt() &&
|
return config_["critical-threshold"].isInt() &&
|
||||||
temperature_c >= config_["critical-threshold"].asInt();
|
temperature_c >= config_["critical-threshold"].asInt();
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
bool isValidNodeId(uint32_t id) { return id > 0 && id < G_MAXUINT32; }
|
bool isValidNodeId(uint32_t id) { return id > 0 && id < G_MAXUINT32; }
|
||||||
|
|
||||||
|
std::list<waybar::modules::Wireplumber*> waybar::modules::Wireplumber::modules;
|
||||||
|
|
||||||
waybar::modules::Wireplumber::Wireplumber(const std::string& id, const Json::Value& config)
|
waybar::modules::Wireplumber::Wireplumber(const std::string& id, const Json::Value& config)
|
||||||
: ALabel(config, "wireplumber", id, "{volume}%"),
|
: ALabel(config, "wireplumber", id, "{volume}%"),
|
||||||
wp_core_(nullptr),
|
wp_core_(nullptr),
|
||||||
@ -16,22 +18,28 @@ waybar::modules::Wireplumber::Wireplumber(const std::string& id, const Json::Val
|
|||||||
muted_(false),
|
muted_(false),
|
||||||
volume_(0.0),
|
volume_(0.0),
|
||||||
min_step_(0.0),
|
min_step_(0.0),
|
||||||
node_id_(0) {
|
node_id_(0),
|
||||||
|
type_(nullptr) {
|
||||||
|
waybar::modules::Wireplumber::modules.push_back(this);
|
||||||
|
|
||||||
wp_init(WP_INIT_PIPEWIRE);
|
wp_init(WP_INIT_PIPEWIRE);
|
||||||
wp_core_ = wp_core_new(nullptr, nullptr, nullptr);
|
wp_core_ = wp_core_new(nullptr, nullptr, nullptr);
|
||||||
apis_ = g_ptr_array_new_with_free_func(g_object_unref);
|
apis_ = g_ptr_array_new_with_free_func(g_object_unref);
|
||||||
om_ = wp_object_manager_new();
|
om_ = wp_object_manager_new();
|
||||||
|
|
||||||
prepare();
|
type_ = g_strdup(config_["node-type"].isString() ? config_["node-type"].asString().c_str()
|
||||||
|
: "Audio/Sink");
|
||||||
|
|
||||||
spdlog::debug("[{}]: connecting to pipewire...", name_);
|
prepare(this);
|
||||||
|
|
||||||
|
spdlog::debug("[{}]: connecting to pipewire: '{}'...", name_, type_);
|
||||||
|
|
||||||
if (wp_core_connect(wp_core_) == 0) {
|
if (wp_core_connect(wp_core_) == 0) {
|
||||||
spdlog::error("[{}]: Could not connect to PipeWire", name_);
|
spdlog::error("[{}]: Could not connect to PipeWire: '{}'", name_, type_);
|
||||||
throw std::runtime_error("Could not connect to PipeWire\n");
|
throw std::runtime_error("Could not connect to PipeWire\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::debug("[{}]: connected!", name_);
|
spdlog::debug("[{}]: {} connected!", name_, type_);
|
||||||
|
|
||||||
g_signal_connect_swapped(om_, "installed", (GCallback)onObjectManagerInstalled, this);
|
g_signal_connect_swapped(om_, "installed", (GCallback)onObjectManagerInstalled, this);
|
||||||
|
|
||||||
@ -39,6 +47,7 @@ waybar::modules::Wireplumber::Wireplumber(const std::string& id, const Json::Val
|
|||||||
}
|
}
|
||||||
|
|
||||||
waybar::modules::Wireplumber::~Wireplumber() {
|
waybar::modules::Wireplumber::~Wireplumber() {
|
||||||
|
waybar::modules::Wireplumber::modules.remove(this);
|
||||||
wp_core_disconnect(wp_core_);
|
wp_core_disconnect(wp_core_);
|
||||||
g_clear_pointer(&apis_, g_ptr_array_unref);
|
g_clear_pointer(&apis_, g_ptr_array_unref);
|
||||||
g_clear_object(&om_);
|
g_clear_object(&om_);
|
||||||
@ -46,13 +55,15 @@ waybar::modules::Wireplumber::~Wireplumber() {
|
|||||||
g_clear_object(&mixer_api_);
|
g_clear_object(&mixer_api_);
|
||||||
g_clear_object(&def_nodes_api_);
|
g_clear_object(&def_nodes_api_);
|
||||||
g_free(default_node_name_);
|
g_free(default_node_name_);
|
||||||
|
g_free(type_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Wireplumber::updateNodeName(waybar::modules::Wireplumber* self, uint32_t id) {
|
void waybar::modules::Wireplumber::updateNodeName(waybar::modules::Wireplumber* self, uint32_t id) {
|
||||||
spdlog::debug("[{}]: updating node name with node.id {}", self->name_, id);
|
spdlog::debug("[{}]: updating '{}' node name with node.id {}", self->name_, self->type_, id);
|
||||||
|
|
||||||
if (!isValidNodeId(id)) {
|
if (!isValidNodeId(id)) {
|
||||||
spdlog::warn("[{}]: '{}' is not a valid node ID. Ignoring node name update.", self->name_, id);
|
spdlog::warn("[{}]: '{}' is not a valid node ID. Ignoring '{}' node name update.", self->name_,
|
||||||
|
id, self->type_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +91,7 @@ void waybar::modules::Wireplumber::updateNodeName(waybar::modules::Wireplumber*
|
|||||||
self->node_name_ = nick != nullptr ? nick
|
self->node_name_ = nick != nullptr ? nick
|
||||||
: description != nullptr ? description
|
: description != nullptr ? description
|
||||||
: "Unknown node name";
|
: "Unknown node name";
|
||||||
spdlog::debug("[{}]: Updating node name to: {}", self->name_, self->node_name_);
|
spdlog::debug("[{}]: Updating '{}' node name to: {}", self->name_, self->type_, self->node_name_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Wireplumber::updateVolume(waybar::modules::Wireplumber* self, uint32_t id) {
|
void waybar::modules::Wireplumber::updateVolume(waybar::modules::Wireplumber* self, uint32_t id) {
|
||||||
@ -88,7 +99,8 @@ void waybar::modules::Wireplumber::updateVolume(waybar::modules::Wireplumber* se
|
|||||||
GVariant* variant = nullptr;
|
GVariant* variant = nullptr;
|
||||||
|
|
||||||
if (!isValidNodeId(id)) {
|
if (!isValidNodeId(id)) {
|
||||||
spdlog::error("[{}]: '{}' is not a valid node ID. Ignoring volume update.", self->name_, id);
|
spdlog::error("[{}]: '{}' is not a valid '{}' node ID. Ignoring volume update.", self->name_,
|
||||||
|
id, self->type_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,13 +121,22 @@ void waybar::modules::Wireplumber::updateVolume(waybar::modules::Wireplumber* se
|
|||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Wireplumber::onMixerChanged(waybar::modules::Wireplumber* self, uint32_t id) {
|
void waybar::modules::Wireplumber::onMixerChanged(waybar::modules::Wireplumber* self, uint32_t id) {
|
||||||
spdlog::debug("[{}]: (onMixerChanged) - id: {}", self->name_, id);
|
|
||||||
|
|
||||||
g_autoptr(WpNode) node = static_cast<WpNode*>(wp_object_manager_lookup(
|
g_autoptr(WpNode) node = static_cast<WpNode*>(wp_object_manager_lookup(
|
||||||
self->om_, WP_TYPE_NODE, WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", id, nullptr));
|
self->om_, WP_TYPE_NODE, WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", id, nullptr));
|
||||||
|
|
||||||
if (node == nullptr) {
|
if (node == nullptr) {
|
||||||
spdlog::warn("[{}]: (onMixerChanged) - Object with id {} not found", self->name_, id);
|
// log a warning only if no other widget is targeting the id.
|
||||||
|
// this reduces log spam when multiple instances of the module are used on different node types.
|
||||||
|
if (id != self->node_id_) {
|
||||||
|
for (auto const& module : waybar::modules::Wireplumber::modules) {
|
||||||
|
if (module->node_id_ == id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spdlog::warn("[{}]: (onMixerChanged: {}) - Object with id {} not found", self->name_,
|
||||||
|
self->type_, id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,26 +144,27 @@ void waybar::modules::Wireplumber::onMixerChanged(waybar::modules::Wireplumber*
|
|||||||
|
|
||||||
if (self->node_id_ != id) {
|
if (self->node_id_ != id) {
|
||||||
spdlog::debug(
|
spdlog::debug(
|
||||||
"[{}]: (onMixerChanged) - ignoring mixer update for node: id: {}, name: {} as it is not "
|
"[{}]: (onMixerChanged: {}) - ignoring mixer update for node: id: {}, name: {} as it is "
|
||||||
"the default node: {} with id: {}",
|
"not the default node: {} with id: {}",
|
||||||
self->name_, id, name, self->default_node_name_, self->node_id_);
|
self->name_, self->type_, id, name, self->default_node_name_, self->node_id_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::debug("[{}]: (onMixerChanged) - Need to update volume for node with id {} and name {}",
|
spdlog::debug(
|
||||||
self->name_, id, name);
|
"[{}]: (onMixerChanged: {}) - Need to update volume for node with id {} and name {}",
|
||||||
|
self->name_, self->type_, id, name);
|
||||||
updateVolume(self, id);
|
updateVolume(self, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Wireplumber::onDefaultNodesApiChanged(waybar::modules::Wireplumber* self) {
|
void waybar::modules::Wireplumber::onDefaultNodesApiChanged(waybar::modules::Wireplumber* self) {
|
||||||
spdlog::debug("[{}]: (onDefaultNodesApiChanged)", self->name_);
|
spdlog::debug("[{}]: (onDefaultNodesApiChanged: {})", self->name_, self->type_);
|
||||||
|
|
||||||
uint32_t defaultNodeId;
|
uint32_t defaultNodeId;
|
||||||
g_signal_emit_by_name(self->def_nodes_api_, "get-default-node", "Audio/Sink", &defaultNodeId);
|
g_signal_emit_by_name(self->def_nodes_api_, "get-default-node", self->type_, &defaultNodeId);
|
||||||
|
|
||||||
if (!isValidNodeId(defaultNodeId)) {
|
if (!isValidNodeId(defaultNodeId)) {
|
||||||
spdlog::warn("[{}]: '{}' is not a valid node ID. Ignoring node change.", self->name_,
|
spdlog::warn("[{}]: '{}' is not a valid node ID. Ignoring '{}' node change.", self->name_,
|
||||||
defaultNodeId);
|
defaultNodeId, self->type_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,8 +173,8 @@ void waybar::modules::Wireplumber::onDefaultNodesApiChanged(waybar::modules::Wir
|
|||||||
"=u", defaultNodeId, nullptr));
|
"=u", defaultNodeId, nullptr));
|
||||||
|
|
||||||
if (node == nullptr) {
|
if (node == nullptr) {
|
||||||
spdlog::warn("[{}]: (onDefaultNodesApiChanged) - Object with id {} not found", self->name_,
|
spdlog::warn("[{}]: (onDefaultNodesApiChanged: {}) - Object with id {} not found", self->name_,
|
||||||
defaultNodeId);
|
self->type_, defaultNodeId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,21 +182,22 @@ void waybar::modules::Wireplumber::onDefaultNodesApiChanged(waybar::modules::Wir
|
|||||||
wp_pipewire_object_get_property(WP_PIPEWIRE_OBJECT(node), "node.name");
|
wp_pipewire_object_get_property(WP_PIPEWIRE_OBJECT(node), "node.name");
|
||||||
|
|
||||||
spdlog::debug(
|
spdlog::debug(
|
||||||
"[{}]: (onDefaultNodesApiChanged) - got the following default node: Node(name: {}, id: {})",
|
"[{}]: (onDefaultNodesApiChanged: {}) - got the following default node: Node(name: {}, id: "
|
||||||
self->name_, defaultNodeName, defaultNodeId);
|
"{})",
|
||||||
|
self->name_, self->type_, defaultNodeName, defaultNodeId);
|
||||||
|
|
||||||
if (g_strcmp0(self->default_node_name_, defaultNodeName) == 0 &&
|
if (g_strcmp0(self->default_node_name_, defaultNodeName) == 0 &&
|
||||||
self->node_id_ == defaultNodeId) {
|
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.",
|
||||||
self->name_, self->default_node_name_, defaultNodeId);
|
self->name_, self->type_, self->default_node_name_, defaultNodeId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::debug(
|
spdlog::debug(
|
||||||
"[{}]: (onDefaultNodesApiChanged) - Default node changed to -> Node(name: {}, id: {})",
|
"[{}]: (onDefaultNodesApiChanged: {}) - Default node changed to -> Node(name: {}, id: {})",
|
||||||
self->name_, defaultNodeName, defaultNodeId);
|
self->name_, self->type_, defaultNodeName, defaultNodeId);
|
||||||
|
|
||||||
g_free(self->default_node_name_);
|
g_free(self->default_node_name_);
|
||||||
self->default_node_name_ = g_strdup(defaultNodeName);
|
self->default_node_name_ = g_strdup(defaultNodeName);
|
||||||
@ -200,13 +223,14 @@ void waybar::modules::Wireplumber::onObjectManagerInstalled(waybar::modules::Wir
|
|||||||
throw std::runtime_error("Mixer api is not loaded\n");
|
throw std::runtime_error("Mixer api is not loaded\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
g_signal_emit_by_name(self->def_nodes_api_, "get-default-configured-node-name", "Audio/Sink",
|
g_signal_emit_by_name(self->def_nodes_api_, "get-default-configured-node-name", self->type_,
|
||||||
&self->default_node_name_);
|
&self->default_node_name_);
|
||||||
g_signal_emit_by_name(self->def_nodes_api_, "get-default-node", "Audio/Sink", &self->node_id_);
|
g_signal_emit_by_name(self->def_nodes_api_, "get-default-node", self->type_, &self->node_id_);
|
||||||
|
|
||||||
if (self->default_node_name_ != nullptr) {
|
if (self->default_node_name_ != nullptr) {
|
||||||
spdlog::debug("[{}]: (onObjectManagerInstalled) - default configured node name: {} and id: {}",
|
spdlog::debug(
|
||||||
self->name_, self->default_node_name_, self->node_id_);
|
"[{}]: (onObjectManagerInstalled: {}) - default configured node name: {} and id: {}",
|
||||||
|
self->name_, self->type_, self->default_node_name_, self->node_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateVolume(self, self->node_id_);
|
updateVolume(self, self->node_id_);
|
||||||
@ -243,10 +267,10 @@ void waybar::modules::Wireplumber::activatePlugins() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Wireplumber::prepare() {
|
void waybar::modules::Wireplumber::prepare(waybar::modules::Wireplumber* self) {
|
||||||
spdlog::debug("[{}]: preparing object manager", name_);
|
spdlog::debug("[{}]: preparing object manager: '{}'", name_, self->type_);
|
||||||
wp_object_manager_add_interest(om_, WP_TYPE_NODE, WP_CONSTRAINT_TYPE_PW_PROPERTY, "media.class",
|
wp_object_manager_add_interest(om_, WP_TYPE_NODE, WP_CONSTRAINT_TYPE_PW_PROPERTY, "media.class",
|
||||||
"=s", "Audio/Sink", nullptr);
|
"=s", self->type_, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Wireplumber::onDefaultNodesApiLoaded(WpObject* p, GAsyncResult* res,
|
void waybar::modules::Wireplumber::onDefaultNodesApiLoaded(WpObject* p, GAsyncResult* res,
|
||||||
@ -275,7 +299,7 @@ void waybar::modules::Wireplumber::onMixerApiLoaded(WpObject* p, GAsyncResult* r
|
|||||||
gboolean success = FALSE;
|
gboolean success = FALSE;
|
||||||
g_autoptr(GError) error = nullptr;
|
g_autoptr(GError) error = nullptr;
|
||||||
|
|
||||||
success = wp_core_load_component_finish(self->wp_core_, res, nullptr);
|
success = wp_core_load_component_finish(self->wp_core_, res, &error);
|
||||||
|
|
||||||
if (success == FALSE) {
|
if (success == FALSE) {
|
||||||
spdlog::error("[{}]: mixer API load failed", self->name_);
|
spdlog::error("[{}]: mixer API load failed", self->name_);
|
||||||
|
@ -190,8 +190,38 @@ std::string Task::state_string(bool shortened) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Task::handle_title(const char *title) {
|
void Task::handle_title(const char *title) {
|
||||||
|
if (title_.empty()) {
|
||||||
|
spdlog::debug(fmt::format("Task ({}) setting title to {}", id_, title_));
|
||||||
|
} else {
|
||||||
|
spdlog::debug(fmt::format("Task ({}) overwriting title '{}' with '{}'", id_, title_, title));
|
||||||
|
}
|
||||||
title_ = title;
|
title_ = title;
|
||||||
hide_if_ignored();
|
hide_if_ignored();
|
||||||
|
|
||||||
|
if (!with_icon_ && !with_name_ || app_info_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_app_info_from_app_id_list(title_);
|
||||||
|
name_ = app_info_ ? app_info_->get_display_name() : title;
|
||||||
|
|
||||||
|
if (!with_icon_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int icon_size = config_["icon-size"].isInt() ? config_["icon-size"].asInt() : 16;
|
||||||
|
bool found = false;
|
||||||
|
for (auto &icon_theme : tbar_->icon_themes()) {
|
||||||
|
if (image_load_icon(icon_, icon_theme, app_info_, icon_size)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
icon_.show();
|
||||||
|
else
|
||||||
|
spdlog::debug("Couldn't find icon for {}", title_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Task::set_minimize_hint() {
|
void Task::set_minimize_hint() {
|
||||||
|
@ -24,6 +24,8 @@ AudioBackend::AudioBackend(std::function<void()> on_updated_cb, private_construc
|
|||||||
source_volume_(0),
|
source_volume_(0),
|
||||||
source_muted_(false),
|
source_muted_(false),
|
||||||
on_updated_cb_(std::move(on_updated_cb)) {
|
on_updated_cb_(std::move(on_updated_cb)) {
|
||||||
|
// Initialize pa_volume_ with safe defaults
|
||||||
|
pa_cvolume_init(&pa_volume_);
|
||||||
mainloop_ = pa_threaded_mainloop_new();
|
mainloop_ = pa_threaded_mainloop_new();
|
||||||
if (mainloop_ == nullptr) {
|
if (mainloop_ == nullptr) {
|
||||||
throw std::runtime_error("pa_mainloop_new() failed.");
|
throw std::runtime_error("pa_mainloop_new() failed.");
|
||||||
@ -131,7 +133,12 @@ void AudioBackend::subscribeCb(pa_context *context, pa_subscription_event_type_t
|
|||||||
void AudioBackend::volumeModifyCb(pa_context *c, int success, void *data) {
|
void AudioBackend::volumeModifyCb(pa_context *c, int success, void *data) {
|
||||||
auto *backend = static_cast<AudioBackend *>(data);
|
auto *backend = static_cast<AudioBackend *>(data);
|
||||||
if (success != 0) {
|
if (success != 0) {
|
||||||
pa_context_get_sink_info_by_index(backend->context_, backend->sink_idx_, sinkInfoCb, data);
|
if ((backend->context_ != nullptr) &&
|
||||||
|
pa_context_get_state(backend->context_) == PA_CONTEXT_READY) {
|
||||||
|
pa_context_get_sink_info_by_index(backend->context_, backend->sink_idx_, sinkInfoCb, data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
spdlog::debug("Volume modification failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,11 +187,20 @@ void AudioBackend::sinkInfoCb(pa_context * /*context*/, const pa_sink_info *i, i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (backend->current_sink_name_ == i->name) {
|
if (backend->current_sink_name_ == i->name) {
|
||||||
backend->pa_volume_ = i->volume;
|
// Safely copy the volume structure
|
||||||
float volume =
|
if (pa_cvolume_valid(&i->volume) != 0) {
|
||||||
static_cast<float>(pa_cvolume_avg(&(backend->pa_volume_))) / float{PA_VOLUME_NORM};
|
backend->pa_volume_ = i->volume;
|
||||||
backend->sink_idx_ = i->index;
|
float volume =
|
||||||
backend->volume_ = std::round(volume * 100.0F);
|
static_cast<float>(pa_cvolume_avg(&(backend->pa_volume_))) / float{PA_VOLUME_NORM};
|
||||||
|
backend->sink_idx_ = i->index;
|
||||||
|
backend->volume_ = std::round(volume * 100.0F);
|
||||||
|
} else {
|
||||||
|
spdlog::error("Invalid volume structure received from PulseAudio");
|
||||||
|
// Initialize with safe defaults
|
||||||
|
pa_cvolume_init(&backend->pa_volume_);
|
||||||
|
backend->volume_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
backend->muted_ = i->mute != 0;
|
backend->muted_ = i->mute != 0;
|
||||||
backend->desc_ = i->description;
|
backend->desc_ = i->description;
|
||||||
backend->monitor_ = i->monitor_source_name;
|
backend->monitor_ = i->monitor_source_name;
|
||||||
@ -230,43 +246,109 @@ void AudioBackend::serverInfoCb(pa_context *context, const pa_server_info *i, vo
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioBackend::changeVolume(uint16_t volume, uint16_t min_volume, uint16_t max_volume) {
|
void AudioBackend::changeVolume(uint16_t volume, uint16_t min_volume, uint16_t max_volume) {
|
||||||
double volume_tick = static_cast<double>(PA_VOLUME_NORM) / 100;
|
// Early return if context is not ready
|
||||||
pa_cvolume pa_volume = pa_volume_;
|
if ((context_ == nullptr) || pa_context_get_state(context_) != PA_CONTEXT_READY) {
|
||||||
|
spdlog::error("PulseAudio context not ready");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare volume structure
|
||||||
|
pa_cvolume pa_volume;
|
||||||
|
|
||||||
|
pa_cvolume_init(&pa_volume);
|
||||||
|
|
||||||
|
// Use existing volume structure if valid, otherwise create a safe default
|
||||||
|
if ((pa_cvolume_valid(&pa_volume_) != 0) && (pa_channels_valid(pa_volume_.channels) != 0)) {
|
||||||
|
pa_volume = pa_volume_;
|
||||||
|
} else {
|
||||||
|
// Set stereo as a safe default
|
||||||
|
pa_volume.channels = 2;
|
||||||
|
spdlog::debug("Using default stereo volume structure");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the volume safely
|
||||||
volume = std::clamp(volume, min_volume, max_volume);
|
volume = std::clamp(volume, min_volume, max_volume);
|
||||||
pa_cvolume_set(&pa_volume, pa_volume_.channels, volume * volume_tick);
|
pa_volume_t vol = volume * (static_cast<double>(PA_VOLUME_NORM) / 100);
|
||||||
|
|
||||||
|
// Set all channels to the same volume manually to avoid pa_cvolume_set
|
||||||
|
for (uint8_t i = 0; i < pa_volume.channels; i++) {
|
||||||
|
pa_volume.values[i] = vol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the volume change
|
||||||
pa_threaded_mainloop_lock(mainloop_);
|
pa_threaded_mainloop_lock(mainloop_);
|
||||||
pa_context_set_sink_volume_by_index(context_, sink_idx_, &pa_volume, volumeModifyCb, this);
|
pa_context_set_sink_volume_by_index(context_, sink_idx_, &pa_volume, volumeModifyCb, this);
|
||||||
pa_threaded_mainloop_unlock(mainloop_);
|
pa_threaded_mainloop_unlock(mainloop_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioBackend::changeVolume(ChangeType change_type, double step, uint16_t max_volume) {
|
void AudioBackend::changeVolume(ChangeType change_type, double step, uint16_t max_volume) {
|
||||||
double volume_tick = static_cast<double>(PA_VOLUME_NORM) / 100;
|
// Early return if context is not ready
|
||||||
pa_volume_t change = volume_tick;
|
if ((context_ == nullptr) || pa_context_get_state(context_) != PA_CONTEXT_READY) {
|
||||||
pa_cvolume pa_volume = pa_volume_;
|
spdlog::error("PulseAudio context not ready");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare volume structure
|
||||||
|
pa_cvolume pa_volume;
|
||||||
|
pa_cvolume_init(&pa_volume);
|
||||||
|
|
||||||
|
// Use existing volume structure if valid, otherwise create a safe default
|
||||||
|
if ((pa_cvolume_valid(&pa_volume_) != 0) && (pa_channels_valid(pa_volume_.channels) != 0)) {
|
||||||
|
pa_volume = pa_volume_;
|
||||||
|
} else {
|
||||||
|
// Set stereo as a safe default
|
||||||
|
pa_volume.channels = 2;
|
||||||
|
spdlog::debug("Using default stereo volume structure");
|
||||||
|
|
||||||
|
// Initialize all channels to current volume level
|
||||||
|
double volume_tick = static_cast<double>(PA_VOLUME_NORM) / 100;
|
||||||
|
pa_volume_t vol = volume_ * volume_tick;
|
||||||
|
for (uint8_t i = 0; i < pa_volume.channels; i++) {
|
||||||
|
pa_volume.values[i] = vol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to continue with volume change if we had to create a new structure
|
||||||
|
pa_threaded_mainloop_lock(mainloop_);
|
||||||
|
pa_context_set_sink_volume_by_index(context_, sink_idx_, &pa_volume, volumeModifyCb, this);
|
||||||
|
pa_threaded_mainloop_unlock(mainloop_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate volume change
|
||||||
|
double volume_tick = static_cast<double>(PA_VOLUME_NORM) / 100;
|
||||||
|
pa_volume_t change;
|
||||||
max_volume = std::min(max_volume, static_cast<uint16_t>(PA_VOLUME_UI_MAX));
|
max_volume = std::min(max_volume, static_cast<uint16_t>(PA_VOLUME_UI_MAX));
|
||||||
|
|
||||||
if (change_type == ChangeType::Increase) {
|
if (change_type == ChangeType::Increase && volume_ < max_volume) {
|
||||||
if (volume_ < max_volume) {
|
// Calculate how much to increase
|
||||||
if (volume_ + step > max_volume) {
|
if (volume_ + step > max_volume) {
|
||||||
change = round((max_volume - volume_) * volume_tick);
|
change = round((max_volume - volume_) * volume_tick);
|
||||||
} else {
|
} else {
|
||||||
change = round(step * volume_tick);
|
change = round(step * volume_tick);
|
||||||
}
|
|
||||||
pa_cvolume_inc(&pa_volume, change);
|
|
||||||
}
|
}
|
||||||
} else if (change_type == ChangeType::Decrease) {
|
|
||||||
if (volume_ > 0) {
|
// Manually increase each channel's volume
|
||||||
if (volume_ - step < 0) {
|
for (uint8_t i = 0; i < pa_volume.channels; i++) {
|
||||||
change = round(volume_ * volume_tick);
|
pa_volume.values[i] = std::min(pa_volume.values[i] + change, PA_VOLUME_MAX);
|
||||||
} else {
|
|
||||||
change = round(step * volume_tick);
|
|
||||||
}
|
|
||||||
pa_cvolume_dec(&pa_volume, change);
|
|
||||||
}
|
}
|
||||||
|
} else if (change_type == ChangeType::Decrease && volume_ > 0) {
|
||||||
|
// Calculate how much to decrease
|
||||||
|
if (volume_ - step < 0) {
|
||||||
|
change = round(volume_ * volume_tick);
|
||||||
|
} else {
|
||||||
|
change = round(step * volume_tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manually decrease each channel's volume
|
||||||
|
for (uint8_t i = 0; i < pa_volume.channels; i++) {
|
||||||
|
pa_volume.values[i] = (pa_volume.values[i] > change) ? (pa_volume.values[i] - change) : 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No change needed
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply the volume change
|
||||||
pa_threaded_mainloop_lock(mainloop_);
|
pa_threaded_mainloop_lock(mainloop_);
|
||||||
pa_context_set_sink_volume_by_index(context_, sink_idx_, &pa_volume, volumeModifyCb, this);
|
pa_context_set_sink_volume_by_index(context_, sink_idx_, &pa_volume, volumeModifyCb, this);
|
||||||
pa_threaded_mainloop_unlock(mainloop_);
|
pa_threaded_mainloop_unlock(mainloop_);
|
||||||
|
@ -150,6 +150,7 @@ BacklightBackend::BacklightBackend(std::chrono::milliseconds interval,
|
|||||||
throw std::runtime_error("No backlight found");
|
throw std::runtime_error("No backlight found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LOGIN_PROXY
|
||||||
// Connect to the login interface
|
// Connect to the login interface
|
||||||
login_proxy_ = Gio::DBus::Proxy::create_for_bus_sync(
|
login_proxy_ = Gio::DBus::Proxy::create_for_bus_sync(
|
||||||
Gio::DBus::BusType::BUS_TYPE_SYSTEM, "org.freedesktop.login1",
|
Gio::DBus::BusType::BUS_TYPE_SYSTEM, "org.freedesktop.login1",
|
||||||
@ -160,6 +161,7 @@ BacklightBackend::BacklightBackend(std::chrono::milliseconds interval,
|
|||||||
Gio::DBus::BusType::BUS_TYPE_SYSTEM, "org.freedesktop.login1",
|
Gio::DBus::BusType::BUS_TYPE_SYSTEM, "org.freedesktop.login1",
|
||||||
"/org/freedesktop/login1/session/self", "org.freedesktop.login1.Session");
|
"/org/freedesktop/login1/session/self", "org.freedesktop.login1.Session");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
udev_thread_ = [this] {
|
udev_thread_ = [this] {
|
||||||
std::unique_ptr<udev, UdevDeleter> udev{udev_new()};
|
std::unique_ptr<udev, UdevDeleter> udev{udev_new()};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[wrap-file]
|
[wrap-file]
|
||||||
directory = cava-0.10.3
|
directory = cava-0.10.4
|
||||||
source_url = https://github.com/LukashonakV/cava/archive/0.10.3.tar.gz
|
source_url = https://github.com/LukashonakV/cava/archive/0.10.4.tar.gz
|
||||||
source_filename = cava-0.10.3.tar.gz
|
source_filename = cava-0.10.4.tar.gz
|
||||||
source_hash = aab0a4ed3f999e8461ad9de63ef8a77f28b6b2011f7dd0c69ba81819d442f6f9
|
source_hash =7bc1c1f9535f2bcc5cd2ae8a2434a2e3a05f5670b1c96316df304137ffc65756
|
||||||
[provide]
|
[provide]
|
||||||
cava = cava_dep
|
cava = cava_dep
|
||||||
|
Reference in New Issue
Block a user