Merge branch 'master' into wayfire
This commit is contained in:
8
.github/workflows/clang-format.yml
vendored
8
.github/workflows/clang-format.yml
vendored
@ -7,14 +7,16 @@ 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: "."
|
||||||
extensions: "hpp,h,cpp,c"
|
extensions: "hpp,h,cpp,c"
|
||||||
style: "file:.clang-format"
|
style: "file:.clang-format"
|
||||||
clangFormatVersion: 18
|
clangFormatVersion: 19
|
||||||
|
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
|
||||||
|
7
.github/workflows/docker.yml
vendored
7
.github/workflows/docker.yml
vendored
@ -1,14 +1,15 @@
|
|||||||
name: Build and Push Docker Image
|
name: Build and Push Docker Image
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
# run every night at midnight
|
# run monthly
|
||||||
- cron: '0 0 * * *'
|
- cron: '0 0 1 * *'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push:
|
build-and-push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.repository == 'Alexays/Waybar'
|
if: github.event_name != 'schedule' || github.repository == 'Alexays/Waybar'
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false # don't fail the other jobs if one of the images fails to build
|
fail-fast: false # don't fail the other jobs if one of the images fails to build
|
||||||
matrix:
|
matrix:
|
||||||
|
4
.github/workflows/freebsd.yml
vendored
4
.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
|
||||||
@ -21,7 +21,7 @@ jobs:
|
|||||||
LDFLAGS: '-L/usr/local/lib'
|
LDFLAGS: '-L/usr/local/lib'
|
||||||
with:
|
with:
|
||||||
operating_system: freebsd
|
operating_system: freebsd
|
||||||
version: "14.1"
|
version: "14.3"
|
||||||
environment_variables: CPPFLAGS LDFLAGS
|
environment_variables: CPPFLAGS LDFLAGS
|
||||||
sync_files: runner-to-vm
|
sync_files: runner-to-vm
|
||||||
run: |
|
run: |
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=Dockerfile
|
# vim: ft=Dockerfile
|
||||||
|
|
||||||
FROM debian:sid
|
FROM debian:sid-slim
|
||||||
|
|
||||||
RUN apt update && \
|
RUN apt update && \
|
||||||
apt install --no-install-recommends --no-install-suggests -y \
|
apt install --no-install-recommends --no-install-suggests -y \
|
||||||
|
@ -6,6 +6,6 @@ RUN export FEATURES="-ipc-sandbox -network-sandbox -pid-sandbox -sandbox -usersa
|
|||||||
emerge --sync && \
|
emerge --sync && \
|
||||||
eselect news read --quiet new 1>/dev/null 2>&1 && \
|
eselect news read --quiet new 1>/dev/null 2>&1 && \
|
||||||
emerge --verbose --update --deep --with-bdeps=y --backtrack=30 --newuse @world && \
|
emerge --verbose --update --deep --with-bdeps=y --backtrack=30 --newuse @world && \
|
||||||
USE="wayland gtk3 gtk -doc X pulseaudio minimal" emerge dev-vcs/git dev-libs/wayland dev-libs/wayland-protocols =dev-cpp/gtkmm-3.24.6 x11-libs/libxkbcommon \
|
USE="wayland gtk3 gtk -doc X pulseaudio minimal" emerge dev-vcs/git dev-libs/wayland dev-libs/wayland-protocols dev-cpp/gtkmm:3.0 x11-libs/libxkbcommon \
|
||||||
x11-libs/gtk+:3 dev-libs/libdbusmenu dev-libs/libnl sys-power/upower media-libs/libpulse dev-libs/libevdev media-libs/libmpdclient \
|
x11-libs/gtk+:3 dev-libs/libdbusmenu dev-libs/libnl sys-power/upower media-libs/libpulse dev-libs/libevdev media-libs/libmpdclient \
|
||||||
media-sound/sndio gui-libs/gtk-layer-shell app-text/scdoc media-sound/playerctl dev-libs/iniparser sci-libs/fftw
|
media-sound/sndio gui-libs/gtk-layer-shell app-text/scdoc media-sound/playerctl dev-libs/iniparser sci-libs/fftw
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
- River (Mapping mode, Tags, Focused window name)
|
- River (Mapping mode, Tags, Focused window name)
|
||||||
- Hyprland (Window Icons, Workspaces, Focused window name)
|
- Hyprland (Window Icons, Workspaces, Focused window name)
|
||||||
- Niri (Workspaces, Focused window name, Language)
|
- Niri (Workspaces, Focused window name, Language)
|
||||||
- DWL (Tags, Focused window name) [requires dwl ipc patch](https://github.com/djpohly/dwl/wiki/ipc)
|
- DWL (Tags, Focused window name) [requires dwl ipc patch](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/ipc)
|
||||||
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
|
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
|
||||||
- Local time
|
- Local time
|
||||||
- Battery
|
- Battery
|
||||||
|
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
|
|
||||||
|
12
flake.lock
generated
12
flake.lock
generated
@ -3,11 +3,11 @@
|
|||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1733328505,
|
"lastModified": 1747046372,
|
||||||
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -18,11 +18,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1735471104,
|
"lastModified": 1748460289,
|
||||||
"narHash": "sha256-0q9NGQySwDQc7RhAV2ukfnu7Gxa5/ybJ2ANT8DQrQrs=",
|
"narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "88195a94f390381c6afcdaa933c2f6ff93959cb4",
|
"rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102",
|
||||||
"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");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -36,6 +36,7 @@ class AModule : public IModule {
|
|||||||
SCROLL_DIR getScrollDir(GdkEventScroll *e);
|
SCROLL_DIR getScrollDir(GdkEventScroll *e);
|
||||||
bool tooltipEnabled() const;
|
bool tooltipEnabled() const;
|
||||||
|
|
||||||
|
std::vector<int> pid_children_;
|
||||||
const std::string name_;
|
const std::string name_;
|
||||||
const Json::Value &config_;
|
const Json::Value &config_;
|
||||||
Gtk::EventBox event_box_;
|
Gtk::EventBox event_box_;
|
||||||
@ -54,7 +55,6 @@ class AModule : public IModule {
|
|||||||
const bool isTooltip;
|
const bool isTooltip;
|
||||||
const bool isExpand;
|
const bool isExpand;
|
||||||
bool hasUserEvents_;
|
bool hasUserEvents_;
|
||||||
std::vector<int> pid_;
|
|
||||||
gdouble distance_scrolled_y_;
|
gdouble distance_scrolled_y_;
|
||||||
gdouble distance_scrolled_x_;
|
gdouble distance_scrolled_x_;
|
||||||
std::map<std::string, std::string> eventActionMap_;
|
std::map<std::string, std::string> eventActionMap_;
|
||||||
|
@ -20,8 +20,8 @@ class Config {
|
|||||||
static std::optional<std::string> findConfigPath(
|
static std::optional<std::string> findConfigPath(
|
||||||
const std::vector<std::string> &names, const std::vector<std::string> &dirs = CONFIG_DIRS);
|
const std::vector<std::string> &names, const std::vector<std::string> &dirs = CONFIG_DIRS);
|
||||||
|
|
||||||
static std::optional<std::string> tryExpandPath(const std::string &base,
|
static std::vector<std::string> tryExpandPath(const std::string &base,
|
||||||
const std::string &filename);
|
const std::string &filename);
|
||||||
|
|
||||||
Config() = default;
|
Config() = default;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
@ -23,11 +32,11 @@ class Cava final : public ALabel {
|
|||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
util::SleeperThread thread_fetch_input_;
|
util::SleeperThread thread_fetch_input_;
|
||||||
|
|
||||||
struct cava::error_s error_ {}; // cava errors
|
struct cava::error_s error_{}; // cava errors
|
||||||
struct cava::config_params prm_ {}; // cava parameters
|
struct cava::config_params prm_{}; // cava parameters
|
||||||
struct cava::audio_raw audio_raw_ {}; // cava handled raw audio data(is based on audio_data)
|
struct cava::audio_raw audio_raw_{}; // cava handled raw audio data(is based on audio_data)
|
||||||
struct cava::audio_data audio_data_ {}; // cava audio data
|
struct cava::audio_data audio_data_{}; // cava audio data
|
||||||
struct cava::cava_plan* plan_; //{new cava_plan{}};
|
struct cava::cava_plan* plan_; //{new cava_plan{}};
|
||||||
// Cava API to read audio source
|
// Cava API to read audio source
|
||||||
cava::ptr input_source_;
|
cava::ptr input_source_;
|
||||||
// Delay to handle audio source
|
// Delay to handle audio source
|
||||||
@ -44,7 +53,7 @@ class Cava final : public ALabel {
|
|||||||
// Cava method
|
// Cava method
|
||||||
void pause_resume();
|
void pause_resume();
|
||||||
// ModuleActionMap
|
// ModuleActionMap
|
||||||
static inline std::map<const std::string, void (waybar::modules::Cava::*const)()> actionMap_{
|
static inline std::map<const std::string, void (waybar::modules::Cava::* const)()> actionMap_{
|
||||||
{"mode", &waybar::modules::Cava::pause_resume}};
|
{"mode", &waybar::modules::Cava::pause_resume}};
|
||||||
};
|
};
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
|
@ -38,39 +38,39 @@ class Clock final : public ALabel {
|
|||||||
5 - tooltip-format
|
5 - tooltip-format
|
||||||
*/
|
*/
|
||||||
std::map<int, std::string const> fmtMap_;
|
std::map<int, std::string const> fmtMap_;
|
||||||
uint cldMonCols_{3}; // calendar count month columns
|
uint cldMonCols_{3}; // calendar count month columns
|
||||||
int cldWnLen_{3}; // calendar week number length
|
int cldWnLen_{3}; // calendar week number length
|
||||||
const int cldMonColLen_{20}; // calendar month column length
|
const int cldMonColLen_{20}; // calendar month column length
|
||||||
WS cldWPos_{WS::HIDDEN}; // calendar week side to print
|
WS cldWPos_{WS::HIDDEN}; // calendar week side to print
|
||||||
months cldCurrShift_{0}; // calendar months shift
|
date::months cldCurrShift_{0}; // calendar months shift
|
||||||
int cldShift_{1}; // calendar months shift factor
|
int cldShift_{1}; // calendar months shift factor
|
||||||
year_month_day cldYearShift_; // calendar Year mode. Cached ymd
|
date::year_month_day cldYearShift_; // calendar Year mode. Cached ymd
|
||||||
std::string cldYearCached_; // calendar Year mode. Cached calendar
|
std::string cldYearCached_; // calendar Year mode. Cached calendar
|
||||||
year_month cldMonShift_; // calendar Month mode. Cached ym
|
date::year_month cldMonShift_; // calendar Month mode. Cached ym
|
||||||
std::string cldMonCached_; // calendar Month mode. Cached calendar
|
std::string cldMonCached_; // calendar Month mode. Cached calendar
|
||||||
day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight)
|
date::day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight)
|
||||||
std::string cldText_{""}; // calendar text to print
|
std::string cldText_{""}; // calendar text to print
|
||||||
CldMode cldMode_{CldMode::MONTH};
|
CldMode cldMode_{CldMode::MONTH};
|
||||||
auto get_calendar(const year_month_day& today, const year_month_day& ymd,
|
auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd,
|
||||||
const time_zone* tz) -> const std::string;
|
const date::time_zone* tz) -> const std::string;
|
||||||
|
|
||||||
// get local time zone
|
// get local time zone
|
||||||
auto local_zone() -> const time_zone*;
|
auto local_zone() -> const date::time_zone*;
|
||||||
|
|
||||||
// time zoned time in tooltip
|
// time zoned time in tooltip
|
||||||
const bool tzInTooltip_; // if need to print time zones text
|
const bool tzInTooltip_; // if need to print time zones text
|
||||||
std::vector<const time_zone*> tzList_; // time zones list
|
std::vector<const date::time_zone*> tzList_; // time zones list
|
||||||
int tzCurrIdx_; // current time zone index for tzList_
|
int tzCurrIdx_; // current time zone index for tzList_
|
||||||
std::string tzText_{""}; // time zones text to print
|
std::string tzText_{""}; // time zones text to print
|
||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
|
|
||||||
// ordinal date in tooltip
|
// ordinal date in tooltip
|
||||||
const bool ordInTooltip_;
|
const bool ordInTooltip_;
|
||||||
std::string ordText_{""};
|
std::string ordText_{""};
|
||||||
auto get_ordinal_date(const year_month_day& today) -> std::string;
|
auto get_ordinal_date(const date::year_month_day& today) -> std::string;
|
||||||
|
|
||||||
auto getTZtext(sys_seconds now) -> std::string;
|
auto getTZtext(date::sys_seconds now) -> std::string;
|
||||||
auto first_day_of_week() -> weekday;
|
auto first_day_of_week() -> date::weekday;
|
||||||
// Module actions
|
// Module actions
|
||||||
void cldModeSwitch();
|
void cldModeSwitch();
|
||||||
void cldShift_up();
|
void cldShift_up();
|
||||||
@ -79,7 +79,7 @@ class Clock final : public ALabel {
|
|||||||
void tz_up();
|
void tz_up();
|
||||||
void tz_down();
|
void tz_down();
|
||||||
// Module Action Map
|
// Module Action Map
|
||||||
static inline std::map<const std::string, void (waybar::modules::Clock::*const)()> actionMap_{
|
static inline std::map<const std::string, void (waybar::modules::Clock::* const)()> actionMap_{
|
||||||
{"mode", &waybar::modules::Clock::cldModeSwitch},
|
{"mode", &waybar::modules::Clock::cldModeSwitch},
|
||||||
{"shift_up", &waybar::modules::Clock::cldShift_up},
|
{"shift_up", &waybar::modules::Clock::cldShift_up},
|
||||||
{"shift_down", &waybar::modules::Clock::cldShift_down},
|
{"shift_down", &waybar::modules::Clock::cldShift_down},
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "util/json.hpp"
|
#include "util/json.hpp"
|
||||||
@ -19,7 +19,9 @@ class EventHandler {
|
|||||||
|
|
||||||
class IPC {
|
class IPC {
|
||||||
public:
|
public:
|
||||||
IPC() { startIPC(); }
|
IPC();
|
||||||
|
~IPC();
|
||||||
|
static IPC& inst();
|
||||||
|
|
||||||
void registerForIPC(const std::string& ev, EventHandler* ev_handler);
|
void registerForIPC(const std::string& ev, EventHandler* ev_handler);
|
||||||
void unregisterForIPC(EventHandler* handler);
|
void unregisterForIPC(EventHandler* handler);
|
||||||
@ -32,14 +34,16 @@ class IPC {
|
|||||||
static std::filesystem::path socketFolder_;
|
static std::filesystem::path socketFolder_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void startIPC();
|
void socketListener();
|
||||||
void parseIPC(const std::string&);
|
void parseIPC(const std::string&);
|
||||||
|
|
||||||
|
std::thread ipcThread_;
|
||||||
std::mutex callbackMutex_;
|
std::mutex callbackMutex_;
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
std::list<std::pair<std::string, EventHandler*>> callbacks_;
|
std::list<std::pair<std::string, EventHandler*>> callbacks_;
|
||||||
|
int socketfd_; // the hyprland socket file descriptor
|
||||||
|
bool running_ = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::unique_ptr<IPC> gIPC;
|
|
||||||
inline bool modulesReady = false;
|
inline bool modulesReady = false;
|
||||||
}; // namespace waybar::modules::hyprland
|
}; // namespace waybar::modules::hyprland
|
||||||
|
@ -37,6 +37,8 @@ class Language : public waybar::ALabel, public EventHandler {
|
|||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
|
|
||||||
Layout layout_;
|
Layout layout_;
|
||||||
|
|
||||||
|
IPC& m_ipc;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::hyprland
|
} // namespace waybar::modules::hyprland
|
||||||
|
@ -28,6 +28,8 @@ class Submap : public waybar::ALabel, public EventHandler {
|
|||||||
std::string submap_;
|
std::string submap_;
|
||||||
bool always_on_ = false;
|
bool always_on_ = false;
|
||||||
std::string default_submap_ = "Default";
|
std::string default_submap_ = "Default";
|
||||||
|
|
||||||
|
IPC& m_ipc;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::hyprland
|
} // namespace waybar::modules::hyprland
|
||||||
|
@ -60,6 +60,8 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
|
|||||||
bool swallowing_;
|
bool swallowing_;
|
||||||
bool fullscreen_;
|
bool fullscreen_;
|
||||||
bool focused_;
|
bool focused_;
|
||||||
|
|
||||||
|
IPC& m_ipc;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::hyprland
|
} // namespace waybar::modules::hyprland
|
||||||
|
@ -42,7 +42,7 @@ class WindowCreationPayload {
|
|||||||
std::string getWorkspaceName() const { return m_workspaceName; }
|
std::string getWorkspaceName() const { return m_workspaceName; }
|
||||||
WindowAddress getAddress() const { return m_windowAddress; }
|
WindowAddress getAddress() const { return m_windowAddress; }
|
||||||
|
|
||||||
void moveToWorksace(std::string& new_workspace_name);
|
void moveToWorkspace(std::string& new_workspace_name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void clearAddr();
|
void clearAddr();
|
||||||
|
@ -55,11 +55,11 @@ class Workspace {
|
|||||||
void setName(std::string const& value) { m_name = value; };
|
void setName(std::string const& value) { m_name = value; };
|
||||||
void setOutput(std::string const& value) { m_output = value; };
|
void setOutput(std::string const& value) { m_output = value; };
|
||||||
bool containsWindow(WindowAddress const& addr) const { return m_windowMap.contains(addr); }
|
bool containsWindow(WindowAddress const& addr) const { return m_windowMap.contains(addr); }
|
||||||
void insertWindow(WindowCreationPayload create_window_paylod);
|
void insertWindow(WindowCreationPayload create_window_payload);
|
||||||
std::string removeWindow(WindowAddress const& addr);
|
std::string removeWindow(WindowAddress const& addr);
|
||||||
void initializeWindowMap(const Json::Value& clients_data);
|
void initializeWindowMap(const Json::Value& clients_data);
|
||||||
|
|
||||||
bool onWindowOpened(WindowCreationPayload const& create_window_paylod);
|
bool onWindowOpened(WindowCreationPayload const& create_window_payload);
|
||||||
std::optional<std::string> closeWindow(WindowAddress const& addr);
|
std::optional<std::string> closeWindow(WindowAddress const& addr);
|
||||||
|
|
||||||
void update(const std::string& format, const std::string& icon);
|
void update(const std::string& format, const std::string& icon);
|
||||||
@ -83,6 +83,7 @@ class Workspace {
|
|||||||
Gtk::Button m_button;
|
Gtk::Button m_button;
|
||||||
Gtk::Box m_content;
|
Gtk::Box m_content;
|
||||||
Gtk::Label m_label;
|
Gtk::Label m_label;
|
||||||
|
IPC& m_ipc;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::hyprland
|
} // namespace waybar::modules::hyprland
|
||||||
|
@ -7,6 +7,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>
|
||||||
@ -36,6 +37,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
auto showSpecial() const -> bool { return m_showSpecial; }
|
auto showSpecial() const -> bool { return m_showSpecial; }
|
||||||
auto activeOnly() const -> bool { return m_activeOnly; }
|
auto activeOnly() const -> bool { return m_activeOnly; }
|
||||||
auto specialVisibleOnly() const -> bool { return m_specialVisibleOnly; }
|
auto specialVisibleOnly() const -> bool { return m_specialVisibleOnly; }
|
||||||
|
auto persistentOnly() const -> bool { return m_persistentOnly; }
|
||||||
auto moveToMonitor() const -> bool { return m_moveToMonitor; }
|
auto moveToMonitor() const -> bool { return m_moveToMonitor; }
|
||||||
|
|
||||||
auto getBarOutput() const -> std::string { return m_bar.output->name; }
|
auto getBarOutput() const -> std::string { return m_bar.output->name; }
|
||||||
@ -55,14 +57,14 @@ 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
|
||||||
void parseConfig(const Json::Value& config);
|
void parseConfig(const Json::Value& config);
|
||||||
auto populateIconsMap(const Json::Value& formatIcons) -> void;
|
auto populateIconsMap(const Json::Value& formatIcons) -> void;
|
||||||
static auto populateBoolConfig(const Json::Value& config, const std::string& key,
|
static auto populateBoolConfig(const Json::Value& config, const std::string& key, bool& member)
|
||||||
bool& member) -> void;
|
-> void;
|
||||||
auto populateSortByConfig(const Json::Value& config) -> void;
|
auto populateSortByConfig(const Json::Value& config) -> void;
|
||||||
auto populateIgnoreWorkspacesConfig(const Json::Value& config) -> void;
|
auto populateIgnoreWorkspacesConfig(const Json::Value& config) -> void;
|
||||||
auto populateFormatWindowSeparatorConfig(const Json::Value& config) -> void;
|
auto populateFormatWindowSeparatorConfig(const Json::Value& config) -> void;
|
||||||
@ -74,10 +76,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);
|
||||||
@ -93,11 +96,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();
|
||||||
|
|
||||||
@ -113,12 +123,13 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
bool m_showSpecial = false;
|
bool m_showSpecial = false;
|
||||||
bool m_activeOnly = false;
|
bool m_activeOnly = false;
|
||||||
bool m_specialVisibleOnly = false;
|
bool m_specialVisibleOnly = false;
|
||||||
|
bool m_persistentOnly = false;
|
||||||
bool m_moveToMonitor = false;
|
bool m_moveToMonitor = false;
|
||||||
Json::Value m_persistentWorkspaceConfig;
|
Json::Value m_persistentWorkspaceConfig;
|
||||||
|
|
||||||
// Map for windows stored in workspaces not present in the current bar.
|
// Map for windows stored in workspaces not present in the current bar.
|
||||||
// This happens when the user has multiple monitors (hence, multiple bars)
|
// This happens when the user has multiple monitors (hence, multiple bars)
|
||||||
// and doesn't share windows accross bars (a.k.a `all-outputs` = false)
|
// and doesn't share windows across bars (a.k.a `all-outputs` = false)
|
||||||
std::map<WindowAddress, std::string> m_orphanWindowMap;
|
std::map<WindowAddress, std::string> m_orphanWindowMap;
|
||||||
|
|
||||||
enum class SortMethod { ID, NAME, NUMBER, DEFAULT };
|
enum class SortMethod { ID, NAME, NUMBER, DEFAULT };
|
||||||
@ -138,7 +149,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;
|
||||||
@ -150,6 +161,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
const Bar& m_bar;
|
const Bar& m_bar;
|
||||||
Gtk::Box m_box;
|
Gtk::Box m_box;
|
||||||
|
IPC& m_ipc;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::hyprland
|
} // namespace waybar::modules::hyprland
|
||||||
|
@ -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();
|
||||||
@ -31,6 +31,8 @@ class Privacy : public AModule {
|
|||||||
uint iconSpacing = 4;
|
uint iconSpacing = 4;
|
||||||
uint iconSize = 20;
|
uint iconSize = 20;
|
||||||
uint transition_duration = 250;
|
uint transition_duration = 250;
|
||||||
|
std::set<std::pair<PrivacyNodeType, std::string>> ignore;
|
||||||
|
bool ignore_monitor = true;
|
||||||
|
|
||||||
std::shared_ptr<util::PipewireBackend::PipewireBackend> backend = nullptr;
|
std::shared_ptr<util::PipewireBackend::PipewireBackend> backend = nullptr;
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
|
@ -21,7 +21,7 @@ class Language : public ALabel, public sigc::trackable {
|
|||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class DispayedShortFlag { None = 0, ShortName = 1, ShortDescription = 1 << 1 };
|
enum class DisplayedShortFlag { None = 0, ShortName = 1, ShortDescription = 1 << 1 };
|
||||||
|
|
||||||
struct Layout {
|
struct Layout {
|
||||||
std::string full_name;
|
std::string full_name;
|
||||||
@ -58,7 +58,7 @@ class Language : public ALabel, public sigc::trackable {
|
|||||||
std::map<std::string, Layout> layouts_map_;
|
std::map<std::string, Layout> layouts_map_;
|
||||||
bool hide_single_;
|
bool hide_single_;
|
||||||
bool is_variant_displayed;
|
bool is_variant_displayed;
|
||||||
std::byte displayed_short_flag = static_cast<std::byte>(DispayedShortFlag::None);
|
std::byte displayed_short_flag = static_cast<std::byte>(DisplayedShortFlag::None);
|
||||||
|
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
|
@ -19,10 +19,11 @@ class Window : public AAppIconLabel, public sigc::trackable {
|
|||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setClass(std::string classname, bool enable);
|
void setClass(const std::string& classname, bool enable);
|
||||||
void onEvent(const struct Ipc::ipc_response&);
|
void onEvent(const struct Ipc::ipc_response&);
|
||||||
void onCmd(const struct Ipc::ipc_response&);
|
void onCmd(const struct Ipc::ipc_response&);
|
||||||
std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string>
|
std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string,
|
||||||
|
std::string>
|
||||||
getFocusedNode(const Json::Value& nodes, std::string& output);
|
getFocusedNode(const Json::Value& nodes, std::string& output);
|
||||||
void getTree();
|
void getTree();
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ class Window : public AAppIconLabel, public sigc::trackable {
|
|||||||
std::string old_app_id_;
|
std::string old_app_id_;
|
||||||
std::size_t app_nb_;
|
std::size_t app_nb_;
|
||||||
std::string shell_;
|
std::string shell_;
|
||||||
|
std::string marks_;
|
||||||
int floating_count_;
|
int floating_count_;
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
|
@ -48,7 +48,7 @@ class Workspaces : public AModule, public sigc::trackable {
|
|||||||
std::vector<std::string> high_priority_named_;
|
std::vector<std::string> high_priority_named_;
|
||||||
std::vector<std::string> workspaces_order_;
|
std::vector<std::string> workspaces_order_;
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
std::string m_formatWindowSeperator;
|
std::string m_formatWindowSeparator;
|
||||||
util::RegexCollection m_windowRewriteRules;
|
util::RegexCollection m_windowRewriteRules;
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
std::unordered_map<std::string, Gtk::Button> buttons_;
|
std::unordered_map<std::string, Gtk::Button> buttons_;
|
||||||
|
@ -19,12 +19,15 @@ class SystemdFailedUnits : public ALabel {
|
|||||||
std::string format_ok;
|
std::string format_ok;
|
||||||
|
|
||||||
bool update_pending;
|
bool update_pending;
|
||||||
uint32_t nr_failed_system, nr_failed_user;
|
std::string system_state, user_state, overall_state;
|
||||||
|
uint32_t nr_failed_system, nr_failed_user, nr_failed;
|
||||||
std::string last_status;
|
std::string last_status;
|
||||||
Glib::RefPtr<Gio::DBus::Proxy> system_proxy, user_proxy;
|
Glib::RefPtr<Gio::DBus::Proxy> system_proxy, user_proxy;
|
||||||
|
|
||||||
void notify_cb(const Glib::ustring &sender_name, const Glib::ustring &signal_name,
|
void notify_cb(const Glib::ustring &sender_name, const Glib::ustring &signal_name,
|
||||||
const Glib::VariantContainerBase &arguments);
|
const Glib::VariantContainerBase &arguments);
|
||||||
|
void RequestFailedUnits();
|
||||||
|
void RequestSystemState();
|
||||||
void updateData();
|
void updateData();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -622,8 +622,8 @@ inline auto convertInto(std::string const &source, bool &target) -> ParserResult
|
|||||||
}
|
}
|
||||||
#ifdef CLARA_CONFIG_OPTIONAL_TYPE
|
#ifdef CLARA_CONFIG_OPTIONAL_TYPE
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline auto convertInto(std::string const &source,
|
inline auto convertInto(std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T> &target)
|
||||||
CLARA_CONFIG_OPTIONAL_TYPE<T> &target) -> ParserResult {
|
-> ParserResult {
|
||||||
T temp;
|
T temp;
|
||||||
auto result = convertInto(source, temp);
|
auto result = convertInto(source, temp);
|
||||||
if (result) target = std::move(temp);
|
if (result) target = std::move(temp);
|
||||||
@ -751,8 +751,8 @@ class ParserBase {
|
|||||||
public:
|
public:
|
||||||
virtual ~ParserBase() = default;
|
virtual ~ParserBase() = default;
|
||||||
virtual auto validate() const -> Result { return Result::ok(); }
|
virtual auto validate() const -> Result { return Result::ok(); }
|
||||||
virtual auto parse(std::string const &exeName,
|
virtual auto parse(std::string const &exeName, TokenStream const &tokens) const
|
||||||
TokenStream const &tokens) const -> InternalParseResult = 0;
|
-> InternalParseResult = 0;
|
||||||
virtual auto cardinality() const -> size_t { return 1; }
|
virtual auto cardinality() const -> size_t { return 1; }
|
||||||
|
|
||||||
auto parse(Args const &args) const -> InternalParseResult {
|
auto parse(Args const &args) const -> InternalParseResult {
|
||||||
@ -1098,8 +1098,8 @@ struct Parser : ParserBase {
|
|||||||
|
|
||||||
using ParserBase::parse;
|
using ParserBase::parse;
|
||||||
|
|
||||||
auto parse(std::string const &exeName,
|
auto parse(std::string const &exeName, TokenStream const &tokens) const
|
||||||
TokenStream const &tokens) const -> InternalParseResult override {
|
-> InternalParseResult override {
|
||||||
struct ParserInfo {
|
struct ParserInfo {
|
||||||
ParserBase const *parser = nullptr;
|
ParserBase const *parser = nullptr;
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
namespace date {
|
namespace date {
|
||||||
#if HAVE_CHRONO_TIMEZONES
|
#if HAVE_CHRONO_TIMEZONES
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using namespace std;
|
using std::format;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
using system_clock = std::chrono::system_clock;
|
using system_clock = std::chrono::system_clock;
|
||||||
@ -73,5 +73,3 @@ struct fmt::formatter<date::zoned_time<Duration, TimeZonePtr>> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace date;
|
|
||||||
|
@ -10,5 +10,7 @@ class DefaultGtkIconThemeWrapper {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static bool has_icon(const std::string&);
|
static bool has_icon(const std::string&);
|
||||||
static Glib::RefPtr<Gdk::Pixbuf> load_icon(const char*, int, Gtk::IconLookupFlags);
|
static Glib::RefPtr<Gdk::Pixbuf> load_icon(
|
||||||
|
const char*, int, Gtk::IconLookupFlags,
|
||||||
|
Glib::RefPtr<Gtk::StyleContext> style = Glib::RefPtr<Gtk::StyleContext>());
|
||||||
};
|
};
|
||||||
|
@ -25,6 +25,7 @@ class PrivacyNodeInfo {
|
|||||||
std::string media_name;
|
std::string media_name;
|
||||||
std::string node_name;
|
std::string node_name;
|
||||||
std::string application_name;
|
std::string application_name;
|
||||||
|
bool is_monitor = false;
|
||||||
|
|
||||||
std::string pipewire_access_portal_app_id;
|
std::string pipewire_access_portal_app_id;
|
||||||
std::string application_icon_name;
|
std::string application_icon_name;
|
||||||
|
@ -6,14 +6,12 @@
|
|||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
using namespace Gio;
|
|
||||||
|
|
||||||
enum class Appearance {
|
enum class Appearance {
|
||||||
UNKNOWN = 0,
|
UNKNOWN = 0,
|
||||||
DARK = 1,
|
DARK = 1,
|
||||||
LIGHT = 2,
|
LIGHT = 2,
|
||||||
};
|
};
|
||||||
class Portal : private DBus::Proxy {
|
class Portal : private Gio::DBus::Proxy {
|
||||||
public:
|
public:
|
||||||
Portal();
|
Portal();
|
||||||
void refreshAppearance();
|
void refreshAppearance();
|
||||||
|
@ -4,6 +4,6 @@
|
|||||||
|
|
||||||
namespace waybar::util {
|
namespace waybar::util {
|
||||||
|
|
||||||
// Get a signal emited with value true when entering sleep, and false when exiting
|
// Get a signal emitted with value true when entering sleep, and false when exiting
|
||||||
SafeSignal<bool>& prepare_for_sleep();
|
SafeSignal<bool>& prepare_for_sleep();
|
||||||
} // namespace waybar::util
|
} // namespace waybar::util
|
||||||
|
@ -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
|
||||||
|
@ -59,9 +59,9 @@ Addressed by *hyprland/language*
|
|||||||
|
|
||||||
```
|
```
|
||||||
"hyprland/language": {
|
"hyprland/language": {
|
||||||
"format": "Lang: {long}"
|
"format": "Lang: {long}",
|
||||||
"format-en": "AMERICA, HELL YEAH!"
|
"format-en": "AMERICA, HELL YEAH!",
|
||||||
"format-tr": "As bayrakları"
|
"format-tr": "As bayrakları",
|
||||||
"keyboard-name": "at-translated-set-2-keyboard"
|
"keyboard-name": "at-translated-set-2-keyboard"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -48,6 +48,11 @@ Addressed by *hyprland/workspaces*
|
|||||||
default: false ++
|
default: false ++
|
||||||
If this and show-special are to true, special workspaces will be shown only if visible.
|
If this and show-special are to true, special workspaces will be shown only if visible.
|
||||||
|
|
||||||
|
*persistent-only*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
If set to true, only persistent workspaces will be shown on bar.
|
||||||
|
|
||||||
*all-outputs*: ++
|
*all-outputs*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
|
@ -125,3 +125,9 @@ screensaver, also known as "presentation mode".
|
|||||||
"timeout": 30.5
|
"timeout": 30.5
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# STYLE
|
||||||
|
|
||||||
|
- *#idle_inhibitor*
|
||||||
|
- *#idle_inhibitor.activated*
|
||||||
|
- *#idle_inhibitor.deactivated*
|
||||||
|
@ -120,6 +120,8 @@ Addressed by *memory*
|
|||||||
|
|
||||||
*{swapAvail}*: Amount of available swap in GiB.
|
*{swapAvail}*: Amount of available swap in GiB.
|
||||||
|
|
||||||
|
*{swapState}*: Signals if swap is activated or not
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -7,7 +7,7 @@ waybar - menu property
|
|||||||
# OVERVIEW
|
# OVERVIEW
|
||||||
|
|
||||||
|
|
||||||
Some modules support a 'menu', which allows to have a popup menu whan a defined
|
Some modules support a 'menu', which allows to have a popup menu when a defined
|
||||||
click is done over the module.
|
click is done over the module.
|
||||||
|
|
||||||
# PROPERTIES
|
# PROPERTIES
|
||||||
|
@ -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.
|
||||||
|
|
||||||
@ -167,7 +171,7 @@ Addressed by *network*
|
|||||||
|
|
||||||
*{signaldBm}*: Signal strength of the wireless network in dBm.
|
*{signaldBm}*: Signal strength of the wireless network in dBm.
|
||||||
|
|
||||||
*{frequency}*: Frequency of the wireless network in MHz.
|
*{frequency}*: Frequency of the wireless network in GHz.
|
||||||
|
|
||||||
*{bandwidthUpBits}*: Instant up speed in bits/seconds.
|
*{bandwidthUpBits}*: Instant up speed in bits/seconds.
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ Additional to workspace name matching, the following *format-icons* can be set.
|
|||||||
- *default*: Will be shown, when no string matches are found.
|
- *default*: Will be shown, when no string matches are found.
|
||||||
- *focused*: Will be shown, when workspace is focused.
|
- *focused*: Will be shown, when workspace is focused.
|
||||||
- *active*: Will be shown, when workspace is active on its output.
|
- *active*: Will be shown, when workspace is active on its output.
|
||||||
|
- *empty*: Will be shown, when workspace is empty.
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
|
@ -37,6 +37,17 @@ the screen or playing audio.
|
|||||||
default: false ++
|
default: false ++
|
||||||
Enables this module to consume all left over space dynamically.
|
Enables this module to consume all left over space dynamically.
|
||||||
|
|
||||||
|
*ignore-monitor* ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
Ignore streams with *stream.monitor* property.
|
||||||
|
|
||||||
|
*ignore* ++
|
||||||
|
typeof: array of objects ++
|
||||||
|
default: [] ++
|
||||||
|
Additional streams to be ignored. See *IGNORE CONFIGURATION* for++
|
||||||
|
more information.
|
||||||
|
|
||||||
# MODULES CONFIGURATION
|
# MODULES CONFIGURATION
|
||||||
|
|
||||||
*type*: ++
|
*type*: ++
|
||||||
@ -54,6 +65,14 @@ the screen or playing audio.
|
|||||||
default: 24 ++
|
default: 24 ++
|
||||||
The size of each icon in the tooltip.
|
The size of each icon in the tooltip.
|
||||||
|
|
||||||
|
# IGNORE CONFIGURATION
|
||||||
|
|
||||||
|
*type*: ++
|
||||||
|
typeof: string
|
||||||
|
|
||||||
|
*name*: ++
|
||||||
|
typeof: string
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -77,6 +96,17 @@ the screen or playing audio.
|
|||||||
"tooltip": true,
|
"tooltip": true,
|
||||||
"tooltip-icon-size": 24
|
"tooltip-icon-size": 24
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"ignore-monitor": true,
|
||||||
|
"ignore": [
|
||||||
|
{
|
||||||
|
"type": "audio-in",
|
||||||
|
"name": "cava"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "screenshare",
|
||||||
|
"name": "obs"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
```
|
```
|
||||||
|
@ -31,6 +31,11 @@ Addressed by *river/tags*
|
|||||||
default: false ++
|
default: false ++
|
||||||
Enables this module to consume all left over space dynamically.
|
Enables this module to consume all left over space dynamically.
|
||||||
|
|
||||||
|
*hide-vacant*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Only show relevant tags: tags that are either focused or have a window on them.
|
||||||
|
|
||||||
# EXAMPLE
|
# EXAMPLE
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -89,6 +89,11 @@ Addressed by *sway/window*
|
|||||||
default: false ++
|
default: false ++
|
||||||
If the workspace itself is focused and the workspace contains nodes or floating_nodes, show the workspace name. If not set, text remains empty but styles according to nodes in the workspace are still applied.
|
If the workspace itself is focused and the workspace contains nodes or floating_nodes, show the workspace name. If not set, text remains empty but styles according to nodes in the workspace are still applied.
|
||||||
|
|
||||||
|
*show-hidden-marks*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
For the *{marks}* format replacement, include hidden marks that start with an underscore.
|
||||||
|
|
||||||
*rewrite*: ++
|
*rewrite*: ++
|
||||||
typeof: object ++
|
typeof: object ++
|
||||||
Rules to rewrite the module format output. See *rewrite rules*.
|
Rules to rewrite the module format output. See *rewrite rules*.
|
||||||
@ -117,6 +122,8 @@ Addressed by *sway/window*
|
|||||||
*{shell}*: The shell of the focused window. It's 'xwayland' when the window is
|
*{shell}*: The shell of the focused window. It's 'xwayland' when the window is
|
||||||
running through xwayland, otherwise, it's 'xdg-shell'.
|
running through xwayland, otherwise, it's 'xdg-shell'.
|
||||||
|
|
||||||
|
*{marks}*: Marks of the window.
|
||||||
|
|
||||||
# REWRITE RULES
|
# REWRITE RULES
|
||||||
|
|
||||||
*rewrite* is an object where keys are regular expressions and values are
|
*rewrite* is an object where keys are regular expressions and values are
|
||||||
|
@ -62,6 +62,12 @@ Addressed by *systemd-failed-units*
|
|||||||
|
|
||||||
*{nr_failed}*: Number of total failed units.
|
*{nr_failed}*: Number of total failed units.
|
||||||
|
|
||||||
|
*{systemd_state}:* State of the systemd system session
|
||||||
|
|
||||||
|
*{user_state}:* State of the systemd user session
|
||||||
|
|
||||||
|
*{overall_state}:* Overall state of the systemd and user session. ("Ok" or "Degraded")
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -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*
|
||||||
|
@ -86,7 +86,7 @@ The visual display elements for waybar use a CSS stylesheet, see *waybar-styles(
|
|||||||
*no-center* ++
|
*no-center* ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
Option to disable the center modules fully usefull together with expand-\*.
|
Option to disable the center modules fully useful together with expand-\*.
|
||||||
|
|
||||||
*spacing* ++
|
*spacing* ++
|
||||||
typeof: integer ++
|
typeof: integer ++
|
||||||
@ -272,6 +272,17 @@ When positioning Waybar on the left or right side of the screen, sometimes it's
|
|||||||
|
|
||||||
Valid options for the "rotate" property are: 0, 90, 180, and 270.
|
Valid options for the "rotate" property are: 0, 90, 180, and 270.
|
||||||
|
|
||||||
|
## Swapping icon and label
|
||||||
|
|
||||||
|
If a module displays both a label and an icon, it might be desirable to swap them (for instance, for panels on the left or right of the screen, or for user adopting a right-to-left script). This can be achieved with the "swap-icon-label" property, taking a boolean. Example:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"sway/window": {
|
||||||
|
"swap-icon-label": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Grouping modules
|
## Grouping modules
|
||||||
|
|
||||||
Module groups allow stacking modules in any direction. By default, when the bar is positioned on the top or bottom of the screen, modules in a group are stacked vertically. Likewise, when positioned on the left or right, modules in a group are stacked horizontally. This can be changed with the "orientation" property.
|
Module groups allow stacking modules in any direction. By default, when the bar is positioned on the top or bottom of the screen, modules in a group are stacked vertically. Likewise, when positioned on the left or right, modules in a group are stacked horizontally. This can be changed with the "orientation" property.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
project(
|
project(
|
||||||
'waybar', 'cpp', 'c',
|
'waybar', 'cpp', 'c',
|
||||||
version: '0.11.0',
|
version: '0.12.0',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>= 0.59.0',
|
meson_version: '>= 0.59.0',
|
||||||
default_options : [
|
default_options : [
|
||||||
@ -342,6 +342,10 @@ if true
|
|||||||
)
|
)
|
||||||
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')
|
||||||
@ -491,7 +495,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;
|
||||||
|
|
||||||
|
@ -112,6 +112,7 @@ class PlayerManager:
|
|||||||
logger.debug(f"Metadata changed for player {player.props.player_name}")
|
logger.debug(f"Metadata changed for player {player.props.player_name}")
|
||||||
player_name = player.props.player_name
|
player_name = player.props.player_name
|
||||||
artist = player.get_artist()
|
artist = player.get_artist()
|
||||||
|
artist = artist.replace("&", "&")
|
||||||
title = player.get_title()
|
title = player.get_title()
|
||||||
title = title.replace("&", "&")
|
title = title.replace("&", "&")
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Highly customizable Wayland bar for Sway and Wlroots based compositors.
|
Description=Highly customizable Wayland bar for Sway and Wlroots based compositors
|
||||||
Documentation=https://github.com/Alexays/Waybar/wiki/
|
Documentation=https://github.com/Alexays/Waybar/wiki/
|
||||||
PartOf=graphical-session.target
|
PartOf=graphical-session.target
|
||||||
After=graphical-session.target
|
After=graphical-session.target
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "AIconLabel.hpp"
|
#include "AIconLabel.hpp"
|
||||||
|
|
||||||
#include <gdkmm/pixbuf.h>
|
#include <gdkmm/pixbuf.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
@ -17,14 +18,36 @@ AIconLabel::AIconLabel(const Json::Value &config, const std::string &name, const
|
|||||||
box_.get_style_context()->add_class(id);
|
box_.get_style_context()->add_class(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
box_.set_orientation(Gtk::Orientation::ORIENTATION_HORIZONTAL);
|
int rot = 0;
|
||||||
|
|
||||||
|
if (config_["rotate"].isUInt()) {
|
||||||
|
rot = config["rotate"].asUInt() % 360;
|
||||||
|
if ((rot % 90) != 00) rot = 0;
|
||||||
|
rot /= 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rot % 2) == 0)
|
||||||
|
box_.set_orientation(Gtk::Orientation::ORIENTATION_HORIZONTAL);
|
||||||
|
else
|
||||||
|
box_.set_orientation(Gtk::Orientation::ORIENTATION_VERTICAL);
|
||||||
box_.set_name(name);
|
box_.set_name(name);
|
||||||
|
|
||||||
int spacing = config_["icon-spacing"].isInt() ? config_["icon-spacing"].asInt() : 8;
|
int spacing = config_["icon-spacing"].isInt() ? config_["icon-spacing"].asInt() : 8;
|
||||||
box_.set_spacing(spacing);
|
box_.set_spacing(spacing);
|
||||||
|
|
||||||
box_.add(image_);
|
bool swap_icon_label = false;
|
||||||
box_.add(label_);
|
if (not config_["swap-icon-label"].isBool())
|
||||||
|
spdlog::warn("'swap-icon-label' must be a bool.");
|
||||||
|
else
|
||||||
|
swap_icon_label = config_["swap-icon-label"].asBool();
|
||||||
|
|
||||||
|
if ((rot == 0 || rot == 3) ^ swap_icon_label) {
|
||||||
|
box_.add(image_);
|
||||||
|
box_.add(label_);
|
||||||
|
} else {
|
||||||
|
box_.add(label_);
|
||||||
|
box_.add(image_);
|
||||||
|
}
|
||||||
|
|
||||||
event_box_.add(box_);
|
event_box_.add(box_);
|
||||||
}
|
}
|
||||||
|
@ -68,11 +68,11 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
|
|||||||
|
|
||||||
// there might be "~" or "$HOME" in original path, try to expand it.
|
// there might be "~" or "$HOME" in original path, try to expand it.
|
||||||
auto result = Config::tryExpandPath(menuFile, "");
|
auto result = Config::tryExpandPath(menuFile, "");
|
||||||
if (!result.has_value()) {
|
if (result.empty()) {
|
||||||
throw std::runtime_error("Failed to expand file: " + menuFile);
|
throw std::runtime_error("Failed to expand file: " + menuFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
menuFile = result.value();
|
menuFile = result.front();
|
||||||
// Read the menu descriptor file
|
// Read the menu descriptor file
|
||||||
std::ifstream file(menuFile);
|
std::ifstream file(menuFile);
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
|
@ -83,7 +83,7 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std::
|
|||||||
}
|
}
|
||||||
|
|
||||||
AModule::~AModule() {
|
AModule::~AModule() {
|
||||||
for (const auto& pid : pid_) {
|
for (const auto& pid : pid_children_) {
|
||||||
if (pid != -1) {
|
if (pid != -1) {
|
||||||
killpg(pid, SIGTERM);
|
killpg(pid, SIGTERM);
|
||||||
}
|
}
|
||||||
@ -93,15 +93,15 @@ AModule::~AModule() {
|
|||||||
auto AModule::update() -> void {
|
auto AModule::update() -> void {
|
||||||
// Run user-provided update handler if configured
|
// Run user-provided update handler if configured
|
||||||
if (config_["on-update"].isString()) {
|
if (config_["on-update"].isString()) {
|
||||||
pid_.push_back(util::command::forkExec(config_["on-update"].asString()));
|
pid_children_.push_back(util::command::forkExec(config_["on-update"].asString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get mapping between event name and module action name
|
// Get mapping between event name and module action name
|
||||||
// Then call overrided doAction in order to call appropriate module action
|
// Then call overridden doAction in order to call appropriate module action
|
||||||
auto AModule::doAction(const std::string& name) -> void {
|
auto AModule::doAction(const std::string& name) -> void {
|
||||||
if (!name.empty()) {
|
if (!name.empty()) {
|
||||||
const std::map<std::string, std::string>::const_iterator& recA{eventActionMap_.find(name)};
|
const std::map<std::string, std::string>::const_iterator& recA{eventActionMap_.find(name)};
|
||||||
// Call overrided action if derrived class has implemented it
|
// Call overridden action if derived class has implemented it
|
||||||
if (recA != eventActionMap_.cend() && name != recA->second) this->doAction(recA->second);
|
if (recA != eventActionMap_.cend() && name != recA->second) this->doAction(recA->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +182,7 @@ bool AModule::handleUserEvent(GdkEventButton* const& e) {
|
|||||||
format.clear();
|
format.clear();
|
||||||
}
|
}
|
||||||
if (!format.empty()) {
|
if (!format.empty()) {
|
||||||
pid_.push_back(util::command::forkExec(format));
|
pid_children_.push_back(util::command::forkExec(format));
|
||||||
}
|
}
|
||||||
dp.emit();
|
dp.emit();
|
||||||
return true;
|
return true;
|
||||||
@ -267,7 +267,7 @@ bool AModule::handleScroll(GdkEventScroll* e) {
|
|||||||
this->AModule::doAction(eventName);
|
this->AModule::doAction(eventName);
|
||||||
// Second call user scripts
|
// Second call user scripts
|
||||||
if (config_[eventName].isString())
|
if (config_[eventName].isString())
|
||||||
pid_.push_back(util::command::forkExec(config_[eventName].asString()));
|
pid_children_.push_back(util::command::forkExec(config_[eventName].asString()));
|
||||||
|
|
||||||
dp.emit();
|
dp.emit();
|
||||||
return true;
|
return true;
|
||||||
|
@ -545,7 +545,6 @@ auto waybar::Bar::setupWidgets() -> void {
|
|||||||
if (config["fixed-center"].isBool() ? config["fixed-center"].asBool() : true) {
|
if (config["fixed-center"].isBool() ? config["fixed-center"].asBool() : true) {
|
||||||
box_.set_center_widget(center_);
|
box_.set_center_widget(center_);
|
||||||
} else {
|
} else {
|
||||||
spdlog::error("No fixed center_");
|
|
||||||
box_.pack_start(center_, true, expand_center);
|
box_.pack_start(center_, true, expand_center);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -569,13 +568,13 @@ auto waybar::Bar::setupWidgets() -> void {
|
|||||||
|
|
||||||
if (!no_center) {
|
if (!no_center) {
|
||||||
for (auto const& module : modules_center_) {
|
for (auto const& module : modules_center_) {
|
||||||
center_.pack_start(*module, false, false);
|
center_.pack_start(*module, module->expandEnabled(), module->expandEnabled());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::reverse(modules_right_.begin(), modules_right_.end());
|
std::reverse(modules_right_.begin(), modules_right_.end());
|
||||||
for (auto const& module : modules_right_) {
|
for (auto const& module : modules_right_) {
|
||||||
right_.pack_end(*module, false, false);
|
right_.pack_end(*module, module->expandEnabled(), module->expandEnabled());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ void waybar::Client::handleOutputDone(void *data, struct zxdg_output_v1 * /*xdg_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cerr << e.what() << '\n';
|
spdlog::warn("caught exception in zxdg_output_v1_listener::done: {}", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ void waybar::Client::handleOutputName(void *data, struct zxdg_output_v1 * /*xdg_
|
|||||||
auto &output = client->getOutput(data);
|
auto &output = client->getOutput(data);
|
||||||
output.name = name;
|
output.name = name;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cerr << e.what() << '\n';
|
spdlog::warn("caught exception in zxdg_output_v1_listener::name: {}", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,13 +106,13 @@ void waybar::Client::handleOutputDescription(void *data, struct zxdg_output_v1 *
|
|||||||
auto *client = waybar::Client::inst();
|
auto *client = waybar::Client::inst();
|
||||||
try {
|
try {
|
||||||
auto &output = client->getOutput(data);
|
auto &output = client->getOutput(data);
|
||||||
const char *open_paren = strrchr(description, '(');
|
|
||||||
|
|
||||||
// Description format: "identifier (name)"
|
// Description format: "identifier (name)"
|
||||||
size_t identifier_length = open_paren - description;
|
auto s = std::string(description);
|
||||||
output.identifier = std::string(description, identifier_length - 1);
|
auto pos = s.find(" (");
|
||||||
|
output.identifier = pos != std::string::npos ? s.substr(0, pos) : s;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cerr << e.what() << '\n';
|
spdlog::warn("caught exception in zxdg_output_v1_listener::description: {}", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ const std::vector<std::string> Config::CONFIG_DIRS = {
|
|||||||
|
|
||||||
const char *Config::CONFIG_PATH_ENV = "WAYBAR_CONFIG_DIR";
|
const char *Config::CONFIG_PATH_ENV = "WAYBAR_CONFIG_DIR";
|
||||||
|
|
||||||
std::optional<std::string> Config::tryExpandPath(const std::string &base,
|
std::vector<std::string> Config::tryExpandPath(const std::string &base,
|
||||||
const std::string &filename) {
|
const std::string &filename) {
|
||||||
fs::path path;
|
fs::path path;
|
||||||
|
|
||||||
if (!filename.empty()) {
|
if (!filename.empty()) {
|
||||||
@ -33,33 +33,35 @@ std::optional<std::string> Config::tryExpandPath(const std::string &base,
|
|||||||
|
|
||||||
spdlog::debug("Try expanding: {}", path.string());
|
spdlog::debug("Try expanding: {}", path.string());
|
||||||
|
|
||||||
|
std::vector<std::string> results;
|
||||||
wordexp_t p;
|
wordexp_t p;
|
||||||
if (wordexp(path.c_str(), &p, 0) == 0) {
|
if (wordexp(path.c_str(), &p, 0) == 0) {
|
||||||
if (access(*p.we_wordv, F_OK) == 0) {
|
for (size_t i = 0; i < p.we_wordc; i++) {
|
||||||
std::string result = *p.we_wordv;
|
if (access(p.we_wordv[i], F_OK) == 0) {
|
||||||
wordfree(&p);
|
results.emplace_back(p.we_wordv[i]);
|
||||||
spdlog::debug("Found config file: {}", path.string());
|
spdlog::debug("Found config file: {}", p.we_wordv[i]);
|
||||||
return result;
|
}
|
||||||
}
|
}
|
||||||
wordfree(&p);
|
wordfree(&p);
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> Config::findConfigPath(const std::vector<std::string> &names,
|
std::optional<std::string> Config::findConfigPath(const std::vector<std::string> &names,
|
||||||
const std::vector<std::string> &dirs) {
|
const std::vector<std::string> &dirs) {
|
||||||
if (const char *dir = std::getenv(Config::CONFIG_PATH_ENV)) {
|
if (const char *dir = std::getenv(Config::CONFIG_PATH_ENV)) {
|
||||||
for (const auto &name : names) {
|
for (const auto &name : names) {
|
||||||
if (auto res = tryExpandPath(dir, name); res) {
|
if (auto res = tryExpandPath(dir, name); !res.empty()) {
|
||||||
return res;
|
return res.front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &dir : dirs) {
|
for (const auto &dir : dirs) {
|
||||||
for (const auto &name : names) {
|
for (const auto &name : names) {
|
||||||
if (auto res = tryExpandPath(dir, name); res) {
|
if (auto res = tryExpandPath(dir, name); !res.empty()) {
|
||||||
return res;
|
return res.front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,11 +94,15 @@ void Config::resolveConfigIncludes(Json::Value &config, int depth) {
|
|||||||
if (includes.isArray()) {
|
if (includes.isArray()) {
|
||||||
for (const auto &include : includes) {
|
for (const auto &include : includes) {
|
||||||
spdlog::info("Including resource file: {}", include.asString());
|
spdlog::info("Including resource file: {}", include.asString());
|
||||||
setupConfig(config, tryExpandPath(include.asString(), "").value_or(""), ++depth);
|
for (const auto &match : tryExpandPath(include.asString(), "")) {
|
||||||
|
setupConfig(config, match, depth + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (includes.isString()) {
|
} else if (includes.isString()) {
|
||||||
spdlog::info("Including resource file: {}", includes.asString());
|
spdlog::info("Including resource file: {}", includes.asString());
|
||||||
setupConfig(config, tryExpandPath(includes.asString(), "").value_or(""), ++depth);
|
for (const auto &match : tryExpandPath(includes.asString(), "")) {
|
||||||
|
setupConfig(config, match, depth + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,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
|
||||||
|
170
src/main.cpp
170
src/main.cpp
@ -1,3 +1,4 @@
|
|||||||
|
#include <fcntl.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
@ -7,66 +8,115 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
|
#include "util/SafeSignal.hpp"
|
||||||
|
|
||||||
std::mutex reap_mtx;
|
std::mutex reap_mtx;
|
||||||
std::list<pid_t> reap;
|
std::list<pid_t> reap;
|
||||||
volatile bool reload;
|
|
||||||
|
|
||||||
void* signalThread(void* args) {
|
static int signal_pipe_write_fd;
|
||||||
int err;
|
|
||||||
int signum;
|
// Write a single signal to `signal_pipe_write_fd`.
|
||||||
sigset_t mask;
|
// This function is set as a signal handler, so it must be async-signal-safe.
|
||||||
sigemptyset(&mask);
|
static void writeSignalToPipe(int signum) {
|
||||||
sigaddset(&mask, SIGCHLD);
|
ssize_t amt = write(signal_pipe_write_fd, &signum, sizeof(int));
|
||||||
|
|
||||||
|
// There's not much we can safely do inside of a signal handler.
|
||||||
|
// Let's just ignore any errors.
|
||||||
|
(void)amt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This initializes `signal_pipe_write_fd`, and sets up signal handlers.
|
||||||
|
//
|
||||||
|
// This function will run forever, emitting every `SIGUSR1`, `SIGUSR2`,
|
||||||
|
// `SIGINT`, `SIGCHLD`, and `SIGRTMIN + 1`...`SIGRTMAX` signal received
|
||||||
|
// to `signal_handler`.
|
||||||
|
static void catchSignals(waybar::SafeSignal<int>& signal_handler) {
|
||||||
|
int fd[2];
|
||||||
|
pipe(fd);
|
||||||
|
|
||||||
|
int signal_pipe_read_fd = fd[0];
|
||||||
|
signal_pipe_write_fd = fd[1];
|
||||||
|
|
||||||
|
// This pipe should be able to buffer ~thousands of signals. If it fills up,
|
||||||
|
// we'll drop signals instead of blocking.
|
||||||
|
|
||||||
|
// We can't allow the write end to block because we'll be writing to it in a
|
||||||
|
// signal handler, which could interrupt the loop that's reading from it and
|
||||||
|
// deadlock.
|
||||||
|
|
||||||
|
fcntl(signal_pipe_write_fd, F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
|
std::signal(SIGUSR1, writeSignalToPipe);
|
||||||
|
std::signal(SIGUSR2, writeSignalToPipe);
|
||||||
|
std::signal(SIGINT, writeSignalToPipe);
|
||||||
|
std::signal(SIGCHLD, writeSignalToPipe);
|
||||||
|
|
||||||
|
for (int sig = SIGRTMIN + 1; sig <= SIGRTMAX; ++sig) {
|
||||||
|
std::signal(sig, writeSignalToPipe);
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
err = sigwait(&mask, &signum);
|
int signum;
|
||||||
if (err != 0) {
|
ssize_t amt = read(signal_pipe_read_fd, &signum, sizeof(int));
|
||||||
spdlog::error("sigwait failed: {}", strerror(errno));
|
if (amt < 0) {
|
||||||
|
spdlog::error("read from signal pipe failed with error {}, closing thread", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amt != sizeof(int)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (signum) {
|
signal_handler.emit(signum);
|
||||||
case SIGCHLD:
|
|
||||||
spdlog::debug("Received SIGCHLD in signalThread");
|
|
||||||
if (!reap.empty()) {
|
|
||||||
reap_mtx.lock();
|
|
||||||
for (auto it = reap.begin(); it != reap.end(); ++it) {
|
|
||||||
if (waitpid(*it, nullptr, WNOHANG) == *it) {
|
|
||||||
spdlog::debug("Reaped child with PID: {}", *it);
|
|
||||||
it = reap.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reap_mtx.unlock();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
spdlog::debug("Received signal with number {}, but not handling", signum);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void startSignalThread() {
|
// Must be called on the main thread.
|
||||||
int err;
|
//
|
||||||
sigset_t mask;
|
// If this signal should restart or close the bar, this function will write
|
||||||
sigemptyset(&mask);
|
// `true` or `false`, respectively, into `reload`.
|
||||||
sigaddset(&mask, SIGCHLD);
|
static void handleSignalMainThread(int signum, bool& reload) {
|
||||||
|
if (signum >= SIGRTMIN + 1 && signum <= SIGRTMAX) {
|
||||||
|
for (auto& bar : waybar::Client::inst()->bars) {
|
||||||
|
bar->handleSignal(signum);
|
||||||
|
}
|
||||||
|
|
||||||
// Block SIGCHLD so it can be handled by the signal thread
|
return;
|
||||||
// Any threads created by this one (the main thread) should not
|
|
||||||
// modify their signal mask to unblock SIGCHLD
|
|
||||||
err = pthread_sigmask(SIG_BLOCK, &mask, nullptr);
|
|
||||||
if (err != 0) {
|
|
||||||
spdlog::error("pthread_sigmask failed in startSignalThread: {}", strerror(err));
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_t thread_id;
|
switch (signum) {
|
||||||
err = pthread_create(&thread_id, nullptr, signalThread, nullptr);
|
case SIGUSR1:
|
||||||
if (err != 0) {
|
spdlog::debug("Visibility toggled");
|
||||||
spdlog::error("pthread_create failed in startSignalThread: {}", strerror(err));
|
for (auto& bar : waybar::Client::inst()->bars) {
|
||||||
exit(1);
|
bar->toggle();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SIGUSR2:
|
||||||
|
spdlog::info("Reloading...");
|
||||||
|
reload = true;
|
||||||
|
waybar::Client::inst()->reset();
|
||||||
|
break;
|
||||||
|
case SIGINT:
|
||||||
|
spdlog::info("Quitting.");
|
||||||
|
reload = false;
|
||||||
|
waybar::Client::inst()->reset();
|
||||||
|
break;
|
||||||
|
case SIGCHLD:
|
||||||
|
spdlog::debug("Received SIGCHLD in signalThread");
|
||||||
|
if (!reap.empty()) {
|
||||||
|
reap_mtx.lock();
|
||||||
|
for (auto it = reap.begin(); it != reap.end(); ++it) {
|
||||||
|
if (waitpid(*it, nullptr, WNOHANG) == *it) {
|
||||||
|
spdlog::debug("Reaped child with PID: {}", *it);
|
||||||
|
it = reap.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reap_mtx.unlock();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
spdlog::debug("Received signal with number {}, but not handling", signum);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,32 +124,16 @@ int main(int argc, char* argv[]) {
|
|||||||
try {
|
try {
|
||||||
auto* client = waybar::Client::inst();
|
auto* client = waybar::Client::inst();
|
||||||
|
|
||||||
std::signal(SIGUSR1, [](int /*signal*/) {
|
bool reload;
|
||||||
for (auto& bar : waybar::Client::inst()->bars) {
|
|
||||||
bar->toggle();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
std::signal(SIGUSR2, [](int /*signal*/) {
|
waybar::SafeSignal<int> posix_signal_received;
|
||||||
spdlog::info("Reloading...");
|
posix_signal_received.connect([&](int signum) { handleSignalMainThread(signum, reload); });
|
||||||
reload = true;
|
|
||||||
waybar::Client::inst()->reset();
|
|
||||||
});
|
|
||||||
|
|
||||||
std::signal(SIGINT, [](int /*signal*/) {
|
std::thread signal_thread([&]() { catchSignals(posix_signal_received); });
|
||||||
spdlog::info("Quitting.");
|
|
||||||
reload = false;
|
|
||||||
waybar::Client::inst()->reset();
|
|
||||||
});
|
|
||||||
|
|
||||||
for (int sig = SIGRTMIN + 1; sig <= SIGRTMAX; ++sig) {
|
// Every `std::thread` must be joined or detached.
|
||||||
std::signal(sig, [](int sig) {
|
// This thread should run forever, so detach it.
|
||||||
for (auto& bar : waybar::Client::inst()->bars) {
|
signal_thread.detach();
|
||||||
bar->handleSignal(sig);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
startSignalThread();
|
|
||||||
|
|
||||||
auto ret = 0;
|
auto ret = 0;
|
||||||
do {
|
do {
|
||||||
|
@ -273,14 +273,18 @@ waybar::modules::Battery::getInfos() {
|
|||||||
// Scale these by the voltage to get μW/μWh.
|
// Scale these by the voltage to get μW/μWh.
|
||||||
|
|
||||||
uint32_t current_now = 0;
|
uint32_t current_now = 0;
|
||||||
|
int32_t _current_now_int = 0;
|
||||||
bool current_now_exists = false;
|
bool current_now_exists = false;
|
||||||
if (fs::exists(bat / "current_now")) {
|
if (fs::exists(bat / "current_now")) {
|
||||||
current_now_exists = true;
|
current_now_exists = true;
|
||||||
std::ifstream(bat / "current_now") >> current_now;
|
std::ifstream(bat / "current_now") >> _current_now_int;
|
||||||
} else if (fs::exists(bat / "current_avg")) {
|
} else if (fs::exists(bat / "current_avg")) {
|
||||||
current_now_exists = true;
|
current_now_exists = true;
|
||||||
std::ifstream(bat / "current_avg") >> current_now;
|
std::ifstream(bat / "current_avg") >> _current_now_int;
|
||||||
}
|
}
|
||||||
|
// Documentation ABI allows a negative value when discharging, positive
|
||||||
|
// value when charging.
|
||||||
|
current_now = std::abs(_current_now_int);
|
||||||
|
|
||||||
if (fs::exists(bat / "time_to_empty_now")) {
|
if (fs::exists(bat / "time_to_empty_now")) {
|
||||||
time_to_empty_now_exists = true;
|
time_to_empty_now_exists = true;
|
||||||
@ -324,11 +328,15 @@ waybar::modules::Battery::getInfos() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t power_now = 0;
|
uint32_t power_now = 0;
|
||||||
|
int32_t _power_now_int = 0;
|
||||||
bool power_now_exists = false;
|
bool power_now_exists = false;
|
||||||
if (fs::exists(bat / "power_now")) {
|
if (fs::exists(bat / "power_now")) {
|
||||||
power_now_exists = true;
|
power_now_exists = true;
|
||||||
std::ifstream(bat / "power_now") >> power_now;
|
std::ifstream(bat / "power_now") >> _power_now_int;
|
||||||
}
|
}
|
||||||
|
// Some drivers (example: Qualcomm) exposes use a negative value when
|
||||||
|
// discharging, positive value when charging.
|
||||||
|
power_now = std::abs(_power_now_int);
|
||||||
|
|
||||||
uint32_t energy_now = 0;
|
uint32_t energy_now = 0;
|
||||||
bool energy_now_exists = false;
|
bool energy_now_exists = false;
|
||||||
|
@ -49,8 +49,8 @@ auto getBoolProperty(GDBusProxy* proxy, const char* property_name) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto getOptionalStringProperty(GDBusProxy* proxy,
|
auto getOptionalStringProperty(GDBusProxy* proxy, const char* property_name)
|
||||||
const char* property_name) -> std::optional<std::string> {
|
-> std::optional<std::string> {
|
||||||
auto gvar = g_dbus_proxy_get_cached_property(proxy, property_name);
|
auto gvar = g_dbus_proxy_get_cached_property(proxy, property_name);
|
||||||
if (gvar) {
|
if (gvar) {
|
||||||
std::string property_value = g_variant_get_string(gvar, NULL);
|
std::string property_value = g_variant_get_string(gvar, NULL);
|
||||||
@ -345,8 +345,8 @@ auto waybar::modules::Bluetooth::onInterfaceAddedOrRemoved(GDBusObjectManager* m
|
|||||||
|
|
||||||
auto waybar::modules::Bluetooth::onInterfaceProxyPropertiesChanged(
|
auto waybar::modules::Bluetooth::onInterfaceProxyPropertiesChanged(
|
||||||
GDBusObjectManagerClient* manager, GDBusObjectProxy* object_proxy, GDBusProxy* interface_proxy,
|
GDBusObjectManagerClient* manager, GDBusObjectProxy* object_proxy, GDBusProxy* interface_proxy,
|
||||||
GVariant* changed_properties, const gchar* const* invalidated_properties,
|
GVariant* changed_properties, const gchar* const* invalidated_properties, gpointer user_data)
|
||||||
gpointer user_data) -> void {
|
-> void {
|
||||||
std::string interface_name = g_dbus_proxy_get_interface_name(interface_proxy);
|
std::string interface_name = g_dbus_proxy_get_interface_name(interface_proxy);
|
||||||
std::string object_path = g_dbus_object_get_object_path(G_DBUS_OBJECT(object_proxy));
|
std::string object_path = g_dbus_object_get_object_path(G_DBUS_OBJECT(object_proxy));
|
||||||
|
|
||||||
@ -395,8 +395,8 @@ auto waybar::modules::Bluetooth::getDeviceBatteryPercentage(GDBusObject* object)
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::modules::Bluetooth::getDeviceProperties(GDBusObject* object,
|
auto waybar::modules::Bluetooth::getDeviceProperties(GDBusObject* object, DeviceInfo& device_info)
|
||||||
DeviceInfo& device_info) -> bool {
|
-> bool {
|
||||||
GDBusProxy* proxy_device = G_DBUS_PROXY(g_dbus_object_get_interface(object, "org.bluez.Device1"));
|
GDBusProxy* proxy_device = G_DBUS_PROXY(g_dbus_object_get_interface(object, "org.bluez.Device1"));
|
||||||
|
|
||||||
if (proxy_device != NULL) {
|
if (proxy_device != NULL) {
|
||||||
@ -462,8 +462,9 @@ auto waybar::modules::Bluetooth::findCurController() -> std::optional<Controller
|
|||||||
return controller_info;
|
return controller_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::modules::Bluetooth::findConnectedDevices(
|
auto waybar::modules::Bluetooth::findConnectedDevices(const std::string& cur_controller_path,
|
||||||
const std::string& cur_controller_path, std::vector<DeviceInfo>& connected_devices) -> void {
|
std::vector<DeviceInfo>& connected_devices)
|
||||||
|
-> void {
|
||||||
GList* objects = g_dbus_object_manager_get_objects(manager_.get());
|
GList* objects = g_dbus_object_manager_get_objects(manager_.get());
|
||||||
for (GList* l = objects; l != NULL; l = l->next) {
|
for (GList* l = objects; l != NULL; l = l->next) {
|
||||||
GDBusObject* object = G_DBUS_OBJECT(l->data);
|
GDBusObject* object = G_DBUS_OBJECT(l->data);
|
||||||
|
@ -139,7 +139,7 @@ auto waybar::modules::Cava::update() -> void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (silence_ && prm_.sleep_timer) {
|
if (silence_ && prm_.sleep_timer != 0) {
|
||||||
if (sleep_counter_ <=
|
if (sleep_counter_ <=
|
||||||
(int)(std::chrono::milliseconds(prm_.sleep_timer * 1s) / frame_time_milsec_)) {
|
(int)(std::chrono::milliseconds(prm_.sleep_timer * 1s) / frame_time_milsec_)) {
|
||||||
++sleep_counter_;
|
++sleep_counter_;
|
||||||
@ -147,7 +147,7 @@ auto waybar::modules::Cava::update() -> void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!silence_) {
|
if (!silence_ || prm_.sleep_timer == 0) {
|
||||||
downThreadDelay(frame_time_milsec_, suspend_silence_delay_);
|
downThreadDelay(frame_time_milsec_, suspend_silence_delay_);
|
||||||
// Process: execute cava
|
// Process: execute cava
|
||||||
pthread_mutex_lock(&audio_data_.lock);
|
pthread_mutex_lock(&audio_data_.lock);
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "modules/clock.hpp"
|
#include "modules/clock.hpp"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
#include <gtkmm/tooltip.h>
|
#include <gtkmm/tooltip.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
@ -16,6 +17,7 @@
|
|||||||
#include <clocale>
|
#include <clocale>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using namespace date;
|
||||||
namespace fmt_lib = waybar::util::date::format;
|
namespace fmt_lib = waybar::util::date::format;
|
||||||
|
|
||||||
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
|
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
|
||||||
@ -25,6 +27,7 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
|
|||||||
m_tooltip_{new Gtk::Label()},
|
m_tooltip_{new Gtk::Label()},
|
||||||
cldInTooltip_{m_tlpFmt_.find("{" + kCldPlaceholder + "}") != std::string::npos},
|
cldInTooltip_{m_tlpFmt_.find("{" + kCldPlaceholder + "}") != std::string::npos},
|
||||||
cldYearShift_{January / 1 / 1900},
|
cldYearShift_{January / 1 / 1900},
|
||||||
|
cldMonShift_{year(1900) / January},
|
||||||
tzInTooltip_{m_tlpFmt_.find("{" + kTZPlaceholder + "}") != std::string::npos},
|
tzInTooltip_{m_tlpFmt_.find("{" + kTZPlaceholder + "}") != std::string::npos},
|
||||||
tzCurrIdx_{0},
|
tzCurrIdx_{0},
|
||||||
ordInTooltip_{m_tlpFmt_.find("{" + kOrdPlaceholder + "}") != std::string::npos} {
|
ordInTooltip_{m_tlpFmt_.find("{" + kOrdPlaceholder + "}") != std::string::npos} {
|
||||||
@ -199,8 +202,8 @@ const unsigned cldRowsInMonth(const year_month& ym, const weekday& firstdow) {
|
|||||||
return 2u + ceil<weeks>((weekday{ym / 1} - firstdow) + ((ym / last).day() - day{0})).count();
|
return 2u + ceil<weeks>((weekday{ym / 1} - firstdow) + ((ym / last).day() - day{0})).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cldGetWeekForLine(const year_month& ym, const weekday& firstdow,
|
auto cldGetWeekForLine(const year_month& ym, const weekday& firstdow, const unsigned line)
|
||||||
const unsigned line) -> const year_month_weekday {
|
-> const year_month_weekday {
|
||||||
unsigned index{line - 2};
|
unsigned index{line - 2};
|
||||||
if (weekday{ym / 1} == firstdow) ++index;
|
if (weekday{ym / 1} == firstdow) ++index;
|
||||||
return ym / firstdow[index];
|
return ym / firstdow[index];
|
||||||
@ -348,9 +351,9 @@ auto waybar::modules::Clock::get_calendar(const year_month_day& today, const yea
|
|||||||
m_locale_, fmtMap_[4],
|
m_locale_, fmtMap_[4],
|
||||||
fmt_lib::make_format_args(
|
fmt_lib::make_format_args(
|
||||||
(line == 2)
|
(line == 2)
|
||||||
? static_cast<const date::zoned_seconds&&>(
|
? static_cast<const zoned_seconds&&>(
|
||||||
zoned_seconds{tz, local_days{ymTmp / 1}})
|
zoned_seconds{tz, local_days{ymTmp / 1}})
|
||||||
: static_cast<const date::zoned_seconds&&>(zoned_seconds{
|
: static_cast<const zoned_seconds&&>(zoned_seconds{
|
||||||
tz, local_days{cldGetWeekForLine(ymTmp, firstdow, line)}})))
|
tz, local_days{cldGetWeekForLine(ymTmp, firstdow, line)}})))
|
||||||
<< ' ';
|
<< ' ';
|
||||||
} else
|
} else
|
||||||
@ -358,10 +361,23 @@ auto waybar::modules::Clock::get_calendar(const year_month_day& today, const yea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
os << Glib::ustring::format((cldWPos_ != WS::LEFT || line == 0) ? std::left : std::right,
|
// Count wide characters to avoid extra padding
|
||||||
std::setfill(L' '),
|
size_t wideCharCount = 0;
|
||||||
std::setw(cldMonColLen_ + ((line < 2) ? cldWnLen_ : 0)),
|
std::string calendarLine = getCalendarLine(today, ymTmp, line, firstdow, &m_locale_);
|
||||||
getCalendarLine(today, ymTmp, line, firstdow, &m_locale_));
|
if (line < 2) {
|
||||||
|
for (gchar *data = calendarLine.data(), *end = data + calendarLine.size();
|
||||||
|
data != nullptr;) {
|
||||||
|
gunichar c = g_utf8_get_char_validated(data, end - data);
|
||||||
|
if (g_unichar_iswide(c)) {
|
||||||
|
wideCharCount++;
|
||||||
|
}
|
||||||
|
data = g_utf8_find_next_char(data, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << Glib::ustring::format(
|
||||||
|
(cldWPos_ != WS::LEFT || line == 0) ? std::left : std::right, std::setfill(L' '),
|
||||||
|
std::setw(cldMonColLen_ + ((line < 2) ? cldWnLen_ - wideCharCount : 0)),
|
||||||
|
calendarLine);
|
||||||
|
|
||||||
// Week numbers on the right
|
// Week numbers on the right
|
||||||
if (cldWPos_ == WS::RIGHT && line > 0) {
|
if (cldWPos_ == WS::RIGHT && line > 0) {
|
||||||
@ -371,9 +387,9 @@ auto waybar::modules::Clock::get_calendar(const year_month_day& today, const yea
|
|||||||
<< fmt_lib::vformat(
|
<< fmt_lib::vformat(
|
||||||
m_locale_, fmtMap_[4],
|
m_locale_, fmtMap_[4],
|
||||||
fmt_lib::make_format_args(
|
fmt_lib::make_format_args(
|
||||||
(line == 2) ? static_cast<const date::zoned_seconds&&>(
|
(line == 2) ? static_cast<const zoned_seconds&&>(
|
||||||
zoned_seconds{tz, local_days{ymTmp / 1}})
|
zoned_seconds{tz, local_days{ymTmp / 1}})
|
||||||
: static_cast<const date::zoned_seconds&&>(
|
: static_cast<const zoned_seconds&&>(
|
||||||
zoned_seconds{tz, local_days{cldGetWeekForLine(
|
zoned_seconds{tz, local_days{cldGetWeekForLine(
|
||||||
ymTmp, firstdow, line)}})));
|
ymTmp, firstdow, line)}})));
|
||||||
else
|
else
|
||||||
|
@ -35,6 +35,13 @@ waybar::modules::Custom::~Custom() {
|
|||||||
|
|
||||||
void waybar::modules::Custom::delayWorker() {
|
void waybar::modules::Custom::delayWorker() {
|
||||||
thread_ = [this] {
|
thread_ = [this] {
|
||||||
|
for (int i: this->pid_children_) {
|
||||||
|
int status;
|
||||||
|
waitpid(i, &status, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->pid_children_.clear();
|
||||||
|
|
||||||
bool can_update = true;
|
bool can_update = true;
|
||||||
if (config_["exec-if"].isString()) {
|
if (config_["exec-if"].isString()) {
|
||||||
output_ = util::command::execNoRead(config_["exec-if"].asString());
|
output_ = util::command::execNoRead(config_["exec-if"].asString());
|
||||||
@ -62,7 +69,7 @@ void waybar::modules::Custom::continuousWorker() {
|
|||||||
}
|
}
|
||||||
thread_ = [this, cmd] {
|
thread_ = [this, cmd] {
|
||||||
char* buff = nullptr;
|
char* buff = nullptr;
|
||||||
waybar::util::ScopeGuard buff_deleter([buff]() {
|
waybar::util::ScopeGuard buff_deleter([&buff]() {
|
||||||
if (buff) {
|
if (buff) {
|
||||||
free(buff);
|
free(buff);
|
||||||
}
|
}
|
||||||
|
@ -98,13 +98,9 @@ Window::~Window() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::handle_title(const char *title) {
|
void Window::handle_title(const char *title) { title_ = Glib::Markup::escape_text(title); }
|
||||||
title_ = Glib::Markup::escape_text(title);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::handle_appid(const char *appid) {
|
void Window::handle_appid(const char *appid) { appid_ = Glib::Markup::escape_text(appid); }
|
||||||
appid_ = Glib::Markup::escape_text(appid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::handle_layout_symbol(const char *layout_symbol) {
|
void Window::handle_layout_symbol(const char *layout_symbol) {
|
||||||
layout_symbol_ = Glib::Markup::escape_text(layout_symbol);
|
layout_symbol_ = Glib::Markup::escape_text(layout_symbol);
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
namespace waybar::modules::hyprland {
|
namespace waybar::modules::hyprland {
|
||||||
|
|
||||||
@ -44,71 +43,96 @@ std::filesystem::path IPC::getSocketFolder(const char* instanceSig) {
|
|||||||
return socketFolder_;
|
return socketFolder_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IPC::startIPC() {
|
IPC::IPC() {
|
||||||
// will start IPC and relay events to parseIPC
|
// will start IPC and relay events to parseIPC
|
||||||
|
ipcThread_ = std::thread([this]() { socketListener(); });
|
||||||
|
}
|
||||||
|
|
||||||
std::thread([&]() {
|
IPC::~IPC() {
|
||||||
// check for hyprland
|
running_ = false;
|
||||||
const char* his = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
spdlog::info("Hyprland IPC stopping...");
|
||||||
|
if (socketfd_ != -1) {
|
||||||
if (his == nullptr) {
|
spdlog::trace("Shutting down socket");
|
||||||
spdlog::warn("Hyprland is not running, Hyprland IPC will not be available.");
|
if (shutdown(socketfd_, SHUT_RDWR) == -1) {
|
||||||
return;
|
spdlog::error("Hyprland IPC: Couldn't shutdown socket");
|
||||||
}
|
}
|
||||||
|
spdlog::trace("Closing socket");
|
||||||
if (!modulesReady) return;
|
if (close(socketfd_) == -1) {
|
||||||
|
spdlog::error("Hyprland IPC: Couldn't close socket");
|
||||||
spdlog::info("Hyprland IPC starting");
|
|
||||||
|
|
||||||
struct sockaddr_un addr;
|
|
||||||
int socketfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
|
|
||||||
if (socketfd == -1) {
|
|
||||||
spdlog::error("Hyprland IPC: socketfd failed");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
ipcThread_.join();
|
||||||
|
}
|
||||||
|
|
||||||
addr.sun_family = AF_UNIX;
|
IPC& IPC::inst() {
|
||||||
|
static IPC ipc;
|
||||||
|
return ipc;
|
||||||
|
}
|
||||||
|
|
||||||
auto socketPath = IPC::getSocketFolder(his) / ".socket2.sock";
|
void IPC::socketListener() {
|
||||||
strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1);
|
// check for hyprland
|
||||||
|
const char* his = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||||
|
|
||||||
addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
|
if (his == nullptr) {
|
||||||
|
spdlog::warn("Hyprland is not running, Hyprland IPC will not be available.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int l = sizeof(struct sockaddr_un);
|
if (!modulesReady) return;
|
||||||
|
|
||||||
if (connect(socketfd, (struct sockaddr*)&addr, l) == -1) {
|
spdlog::info("Hyprland IPC starting");
|
||||||
spdlog::error("Hyprland IPC: Unable to connect?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* file = fdopen(socketfd, "r");
|
struct sockaddr_un addr;
|
||||||
|
socketfd_ = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
|
||||||
while (true) {
|
if (socketfd_ == -1) {
|
||||||
std::array<char, 1024> buffer; // Hyprland socket2 events are max 1024 bytes
|
spdlog::error("Hyprland IPC: socketfd failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto* receivedCharPtr = fgets(buffer.data(), buffer.size(), file);
|
addr.sun_family = AF_UNIX;
|
||||||
|
|
||||||
if (receivedCharPtr == nullptr) {
|
auto socketPath = IPC::getSocketFolder(his) / ".socket2.sock";
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string messageReceived(buffer.data());
|
addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
|
||||||
messageReceived = messageReceived.substr(0, messageReceived.find_first_of('\n'));
|
|
||||||
spdlog::debug("hyprland IPC received {}", messageReceived);
|
|
||||||
|
|
||||||
try {
|
int l = sizeof(struct sockaddr_un);
|
||||||
parseIPC(messageReceived);
|
|
||||||
} catch (std::exception& e) {
|
|
||||||
spdlog::warn("Failed to parse IPC message: {}, reason: {}", messageReceived, e.what());
|
|
||||||
} catch (...) {
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (connect(socketfd_, (struct sockaddr*)&addr, l) == -1) {
|
||||||
|
spdlog::error("Hyprland IPC: Unable to connect?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto* file = fdopen(socketfd_, "r");
|
||||||
|
if (file == nullptr) {
|
||||||
|
spdlog::error("Hyprland IPC: Couldn't open file descriptor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (running_) {
|
||||||
|
std::array<char, 1024> buffer; // Hyprland socket2 events are max 1024 bytes
|
||||||
|
|
||||||
|
auto* receivedCharPtr = fgets(buffer.data(), buffer.size(), file);
|
||||||
|
|
||||||
|
if (receivedCharPtr == nullptr) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}).detach();
|
|
||||||
|
std::string messageReceived(buffer.data());
|
||||||
|
messageReceived = messageReceived.substr(0, messageReceived.find_first_of('\n'));
|
||||||
|
spdlog::debug("hyprland IPC received {}", messageReceived);
|
||||||
|
|
||||||
|
try {
|
||||||
|
parseIPC(messageReceived);
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
spdlog::warn("Failed to parse IPC message: {}, reason: {}", messageReceived, e.what());
|
||||||
|
} catch (...) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
spdlog::debug("Hyprland IPC stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IPC::parseIPC(const std::string& ev) {
|
void IPC::parseIPC(const std::string& ev) {
|
||||||
|
@ -10,13 +10,9 @@
|
|||||||
namespace waybar::modules::hyprland {
|
namespace waybar::modules::hyprland {
|
||||||
|
|
||||||
Language::Language(const std::string& id, const Bar& bar, const Json::Value& config)
|
Language::Language(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||||
: ALabel(config, "language", id, "{}", 0, true), bar_(bar) {
|
: ALabel(config, "language", id, "{}", 0, true), bar_(bar), m_ipc(IPC::inst()) {
|
||||||
modulesReady = true;
|
modulesReady = true;
|
||||||
|
|
||||||
if (!gIPC) {
|
|
||||||
gIPC = std::make_unique<IPC>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the active layout when open
|
// get the active layout when open
|
||||||
initLanguage();
|
initLanguage();
|
||||||
|
|
||||||
@ -24,11 +20,11 @@ Language::Language(const std::string& id, const Bar& bar, const Json::Value& con
|
|||||||
update();
|
update();
|
||||||
|
|
||||||
// register for hyprland ipc
|
// register for hyprland ipc
|
||||||
gIPC->registerForIPC("activelayout", this);
|
m_ipc.registerForIPC("activelayout", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Language::~Language() {
|
Language::~Language() {
|
||||||
gIPC->unregisterForIPC(this);
|
m_ipc.unregisterForIPC(this);
|
||||||
// wait for possible event handler to finish
|
// wait for possible event handler to finish
|
||||||
std::lock_guard<std::mutex> lg(mutex_);
|
std::lock_guard<std::mutex> lg(mutex_);
|
||||||
}
|
}
|
||||||
@ -85,7 +81,7 @@ void Language::onEvent(const std::string& ev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Language::initLanguage() {
|
void Language::initLanguage() {
|
||||||
const auto inputDevices = gIPC->getSocket1Reply("devices");
|
const auto inputDevices = m_ipc.getSocket1Reply("devices");
|
||||||
|
|
||||||
const auto kbName = config_["keyboard-name"].asString();
|
const auto kbName = config_["keyboard-name"].asString();
|
||||||
|
|
||||||
|
@ -7,32 +7,28 @@
|
|||||||
namespace waybar::modules::hyprland {
|
namespace waybar::modules::hyprland {
|
||||||
|
|
||||||
Submap::Submap(const std::string& id, const Bar& bar, const Json::Value& config)
|
Submap::Submap(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||||
: ALabel(config, "submap", id, "{}", 0, true), bar_(bar) {
|
: ALabel(config, "submap", id, "{}", 0, true), bar_(bar), m_ipc(IPC::inst()) {
|
||||||
modulesReady = true;
|
modulesReady = true;
|
||||||
|
|
||||||
parseConfig(config);
|
parseConfig(config);
|
||||||
|
|
||||||
if (!gIPC) {
|
|
||||||
gIPC = std::make_unique<IPC>();
|
|
||||||
}
|
|
||||||
|
|
||||||
label_.hide();
|
label_.hide();
|
||||||
ALabel::update();
|
ALabel::update();
|
||||||
|
|
||||||
// Displays widget immediately if always_on_ assuming default submap
|
// Displays widget immediately if always_on_ assuming default submap
|
||||||
// Needs an actual way to retrive current submap on startup
|
// Needs an actual way to retrieve current submap on startup
|
||||||
if (always_on_) {
|
if (always_on_) {
|
||||||
submap_ = default_submap_;
|
submap_ = default_submap_;
|
||||||
label_.get_style_context()->add_class(submap_);
|
label_.get_style_context()->add_class(submap_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// register for hyprland ipc
|
// register for hyprland ipc
|
||||||
gIPC->registerForIPC("submap", this);
|
m_ipc.registerForIPC("submap", this);
|
||||||
dp.emit();
|
dp.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Submap::~Submap() {
|
Submap::~Submap() {
|
||||||
gIPC->unregisterForIPC(this);
|
m_ipc.unregisterForIPC(this);
|
||||||
// wait for possible event handler to finish
|
// wait for possible event handler to finish
|
||||||
std::lock_guard<std::mutex> lg(mutex_);
|
std::lock_guard<std::mutex> lg(mutex_);
|
||||||
}
|
}
|
||||||
@ -72,8 +68,7 @@ void Submap::onEvent(const std::string& ev) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto submapName = ev.substr(ev.find_last_of('>') + 1);
|
auto submapName = ev.substr(ev.find_first_of('>') + 2);
|
||||||
submapName = waybar::util::sanitize_string(submapName);
|
|
||||||
|
|
||||||
if (!submap_.empty()) {
|
if (!submap_.empty()) {
|
||||||
label_.get_style_context()->remove_class(submap_);
|
label_.get_style_context()->remove_class(submap_);
|
||||||
|
@ -6,37 +6,30 @@
|
|||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <shared_mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "modules/hyprland/backend.hpp"
|
#include "modules/hyprland/backend.hpp"
|
||||||
#include "util/rewrite_string.hpp"
|
#include "util/rewrite_string.hpp"
|
||||||
#include "util/sanitize_str.hpp"
|
#include "util/sanitize_str.hpp"
|
||||||
|
|
||||||
#include <shared_mutex>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
namespace waybar::modules::hyprland {
|
namespace waybar::modules::hyprland {
|
||||||
|
|
||||||
std::shared_mutex windowIpcSmtx;
|
std::shared_mutex windowIpcSmtx;
|
||||||
|
|
||||||
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
|
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||||
: AAppIconLabel(config, "window", id, "{title}", 0, true), bar_(bar) {
|
: AAppIconLabel(config, "window", id, "{title}", 0, true), bar_(bar), m_ipc(IPC::inst()) {
|
||||||
|
|
||||||
std::unique_lock<std::shared_mutex> windowIpcUniqueLock(windowIpcSmtx);
|
std::unique_lock<std::shared_mutex> windowIpcUniqueLock(windowIpcSmtx);
|
||||||
|
|
||||||
modulesReady = true;
|
modulesReady = true;
|
||||||
separateOutputs_ = config["separate-outputs"].asBool();
|
separateOutputs_ = config["separate-outputs"].asBool();
|
||||||
|
|
||||||
if (!gIPC) {
|
|
||||||
gIPC = std::make_unique<IPC>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// register for hyprland ipc
|
// register for hyprland ipc
|
||||||
gIPC->registerForIPC("activewindow", this);
|
m_ipc.registerForIPC("activewindow", this);
|
||||||
gIPC->registerForIPC("closewindow", this);
|
m_ipc.registerForIPC("closewindow", this);
|
||||||
gIPC->registerForIPC("movewindow", this);
|
m_ipc.registerForIPC("movewindow", this);
|
||||||
gIPC->registerForIPC("changefloatingmode", this);
|
m_ipc.registerForIPC("changefloatingmode", this);
|
||||||
gIPC->registerForIPC("fullscreen", this);
|
m_ipc.registerForIPC("fullscreen", this);
|
||||||
|
|
||||||
windowIpcUniqueLock.unlock();
|
windowIpcUniqueLock.unlock();
|
||||||
|
|
||||||
@ -47,11 +40,10 @@ Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
|
|||||||
|
|
||||||
Window::~Window() {
|
Window::~Window() {
|
||||||
std::unique_lock<std::shared_mutex> windowIpcUniqueLock(windowIpcSmtx);
|
std::unique_lock<std::shared_mutex> windowIpcUniqueLock(windowIpcSmtx);
|
||||||
gIPC->unregisterForIPC(this);
|
m_ipc.unregisterForIPC(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Window::update() -> void {
|
auto Window::update() -> void {
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> windowIpcShareLock(windowIpcSmtx);
|
std::shared_lock<std::shared_mutex> windowIpcShareLock(windowIpcSmtx);
|
||||||
|
|
||||||
std::string windowName = waybar::util::sanitize_string(workspace_.last_window_title);
|
std::string windowName = waybar::util::sanitize_string(workspace_.last_window_title);
|
||||||
@ -59,18 +51,36 @@ auto Window::update() -> void {
|
|||||||
|
|
||||||
windowData_.title = windowName;
|
windowData_.title = windowName;
|
||||||
|
|
||||||
|
std::string label_text;
|
||||||
if (!format_.empty()) {
|
if (!format_.empty()) {
|
||||||
label_.show();
|
label_.show();
|
||||||
label_.set_markup(waybar::util::rewriteString(
|
label_text = waybar::util::rewriteString(
|
||||||
fmt::format(fmt::runtime(format_), fmt::arg("title", windowName),
|
fmt::format(fmt::runtime(format_), fmt::arg("title", windowName),
|
||||||
fmt::arg("initialTitle", windowData_.initial_title),
|
fmt::arg("initialTitle", windowData_.initial_title),
|
||||||
fmt::arg("class", windowData_.class_name),
|
fmt::arg("class", windowData_.class_name),
|
||||||
fmt::arg("initialClass", windowData_.initial_class_name)),
|
fmt::arg("initialClass", windowData_.initial_class_name)),
|
||||||
config_["rewrite"]));
|
config_["rewrite"]);
|
||||||
|
label_.set_markup(label_text);
|
||||||
} else {
|
} else {
|
||||||
label_.hide();
|
label_.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tooltipEnabled()) {
|
||||||
|
std::string tooltip_format;
|
||||||
|
if (config_["tooltip-format"].isString()) {
|
||||||
|
tooltip_format = config_["tooltip-format"].asString();
|
||||||
|
}
|
||||||
|
if (!tooltip_format.empty()) {
|
||||||
|
label_.set_tooltip_text(
|
||||||
|
fmt::format(fmt::runtime(tooltip_format), fmt::arg("title", windowName),
|
||||||
|
fmt::arg("initialTitle", windowData_.initial_title),
|
||||||
|
fmt::arg("class", windowData_.class_name),
|
||||||
|
fmt::arg("initialClass", windowData_.initial_class_name)));
|
||||||
|
} else if (!label_text.empty()) {
|
||||||
|
label_.set_tooltip_text(label_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (focused_) {
|
if (focused_) {
|
||||||
image_.show();
|
image_.show();
|
||||||
} else {
|
} else {
|
||||||
@ -100,7 +110,7 @@ auto Window::update() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Window::getActiveWorkspace() -> Workspace {
|
auto Window::getActiveWorkspace() -> Workspace {
|
||||||
const auto workspace = gIPC->getSocket1JsonReply("activeworkspace");
|
const auto workspace = IPC::inst().getSocket1JsonReply("activeworkspace");
|
||||||
|
|
||||||
if (workspace.isObject()) {
|
if (workspace.isObject()) {
|
||||||
return Workspace::parse(workspace);
|
return Workspace::parse(workspace);
|
||||||
@ -110,24 +120,33 @@ auto Window::getActiveWorkspace() -> Workspace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
|
auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
|
||||||
const auto monitors = gIPC->getSocket1JsonReply("monitors");
|
const auto monitors = IPC::inst().getSocket1JsonReply("monitors");
|
||||||
if (monitors.isArray()) {
|
if (monitors.isArray()) {
|
||||||
auto monitor = std::find_if(monitors.begin(), monitors.end(), [&](Json::Value monitor) {
|
auto monitor = std::ranges::find_if(
|
||||||
return monitor["name"] == monitorName;
|
monitors, [&](Json::Value monitor) { return monitor["name"] == monitorName; });
|
||||||
});
|
|
||||||
if (monitor == std::end(monitors)) {
|
if (monitor == std::end(monitors)) {
|
||||||
spdlog::warn("Monitor not found: {}", monitorName);
|
spdlog::warn("Monitor not found: {}", monitorName);
|
||||||
return Workspace{-1, 0, "", ""};
|
return Workspace{
|
||||||
|
.id = -1,
|
||||||
|
.windows = 0,
|
||||||
|
.last_window = "",
|
||||||
|
.last_window_title = "",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
const int id = (*monitor)["activeWorkspace"]["id"].asInt();
|
const int id = (*monitor)["activeWorkspace"]["id"].asInt();
|
||||||
|
|
||||||
const auto workspaces = gIPC->getSocket1JsonReply("workspaces");
|
const auto workspaces = IPC::inst().getSocket1JsonReply("workspaces");
|
||||||
if (workspaces.isArray()) {
|
if (workspaces.isArray()) {
|
||||||
auto workspace = std::find_if(workspaces.begin(), workspaces.end(),
|
auto workspace = std::ranges::find_if(
|
||||||
[&](Json::Value workspace) { return workspace["id"] == id; });
|
workspaces, [&](Json::Value workspace) { return workspace["id"] == id; });
|
||||||
if (workspace == std::end(workspaces)) {
|
if (workspace == std::end(workspaces)) {
|
||||||
spdlog::warn("No workspace with id {}", id);
|
spdlog::warn("No workspace with id {}", id);
|
||||||
return Workspace{-1, 0, "", ""};
|
return Workspace{
|
||||||
|
.id = -1,
|
||||||
|
.windows = 0,
|
||||||
|
.last_window = "",
|
||||||
|
.last_window_title = "",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return Workspace::parse(*workspace);
|
return Workspace::parse(*workspace);
|
||||||
};
|
};
|
||||||
@ -138,22 +157,25 @@ auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
|
|||||||
|
|
||||||
auto Window::Workspace::parse(const Json::Value& value) -> Window::Workspace {
|
auto Window::Workspace::parse(const Json::Value& value) -> Window::Workspace {
|
||||||
return Workspace{
|
return Workspace{
|
||||||
value["id"].asInt(),
|
.id = value["id"].asInt(),
|
||||||
value["windows"].asInt(),
|
.windows = value["windows"].asInt(),
|
||||||
value["lastwindow"].asString(),
|
.last_window = value["lastwindow"].asString(),
|
||||||
value["lastwindowtitle"].asString(),
|
.last_window_title = value["lastwindowtitle"].asString(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Window::WindowData::parse(const Json::Value& value) -> Window::WindowData {
|
auto Window::WindowData::parse(const Json::Value& value) -> Window::WindowData {
|
||||||
return WindowData{value["floating"].asBool(), value["monitor"].asInt(),
|
return WindowData{.floating = value["floating"].asBool(),
|
||||||
value["class"].asString(), value["initialClass"].asString(),
|
.monitor = value["monitor"].asInt(),
|
||||||
value["title"].asString(), value["initialTitle"].asString(),
|
.class_name = value["class"].asString(),
|
||||||
value["fullscreen"].asBool(), !value["grouped"].empty()};
|
.initial_class_name = value["initialClass"].asString(),
|
||||||
|
.title = value["title"].asString(),
|
||||||
|
.initial_title = value["initialTitle"].asString(),
|
||||||
|
.fullscreen = value["fullscreen"].asBool(),
|
||||||
|
.grouped = !value["grouped"].empty()};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::queryActiveWorkspace() {
|
void Window::queryActiveWorkspace() {
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> windowIpcShareLock(windowIpcSmtx);
|
std::shared_lock<std::shared_mutex> windowIpcShareLock(windowIpcSmtx);
|
||||||
|
|
||||||
if (separateOutputs_) {
|
if (separateOutputs_) {
|
||||||
@ -164,11 +186,10 @@ void Window::queryActiveWorkspace() {
|
|||||||
|
|
||||||
focused_ = true;
|
focused_ = true;
|
||||||
if (workspace_.windows > 0) {
|
if (workspace_.windows > 0) {
|
||||||
const auto clients = gIPC->getSocket1JsonReply("clients");
|
const auto clients = m_ipc.getSocket1JsonReply("clients");
|
||||||
if (clients.isArray()) {
|
if (clients.isArray()) {
|
||||||
auto activeWindow = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) {
|
auto activeWindow = std::ranges::find_if(
|
||||||
return window["address"] == workspace_.last_window;
|
clients, [&](Json::Value window) { return window["address"] == workspace_.last_window; });
|
||||||
});
|
|
||||||
|
|
||||||
if (activeWindow == std::end(clients)) {
|
if (activeWindow == std::end(clients)) {
|
||||||
focused_ = false;
|
focused_ = false;
|
||||||
@ -178,22 +199,19 @@ void Window::queryActiveWorkspace() {
|
|||||||
windowData_ = WindowData::parse(*activeWindow);
|
windowData_ = WindowData::parse(*activeWindow);
|
||||||
updateAppIconName(windowData_.class_name, windowData_.initial_class_name);
|
updateAppIconName(windowData_.class_name, windowData_.initial_class_name);
|
||||||
std::vector<Json::Value> workspaceWindows;
|
std::vector<Json::Value> workspaceWindows;
|
||||||
std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspaceWindows),
|
std::ranges::copy_if(clients, std::back_inserter(workspaceWindows), [&](Json::Value window) {
|
||||||
[&](Json::Value window) {
|
return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool();
|
||||||
return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool();
|
});
|
||||||
});
|
swallowing_ = std::ranges::any_of(workspaceWindows, [&](Json::Value window) {
|
||||||
swallowing_ =
|
return !window["swallowing"].isNull() && window["swallowing"].asString() != "0x0";
|
||||||
std::any_of(workspaceWindows.begin(), workspaceWindows.end(), [&](Json::Value window) {
|
});
|
||||||
return !window["swallowing"].isNull() && window["swallowing"].asString() != "0x0";
|
|
||||||
});
|
|
||||||
std::vector<Json::Value> visibleWindows;
|
std::vector<Json::Value> visibleWindows;
|
||||||
std::copy_if(workspaceWindows.begin(), workspaceWindows.end(),
|
std::ranges::copy_if(workspaceWindows, std::back_inserter(visibleWindows),
|
||||||
std::back_inserter(visibleWindows),
|
[&](Json::Value window) { return !window["hidden"].asBool(); });
|
||||||
[&](Json::Value window) { return !window["hidden"].asBool(); });
|
|
||||||
solo_ = 1 == std::count_if(visibleWindows.begin(), visibleWindows.end(),
|
solo_ = 1 == std::count_if(visibleWindows.begin(), visibleWindows.end(),
|
||||||
[&](Json::Value window) { return !window["floating"].asBool(); });
|
[&](Json::Value window) { return !window["floating"].asBool(); });
|
||||||
allFloating_ = std::all_of(visibleWindows.begin(), visibleWindows.end(),
|
allFloating_ = std::ranges::all_of(
|
||||||
[&](Json::Value window) { return window["floating"].asBool(); });
|
visibleWindows, [&](Json::Value window) { return window["floating"].asBool(); });
|
||||||
fullscreen_ = windowData_.fullscreen;
|
fullscreen_ = windowData_.fullscreen;
|
||||||
|
|
||||||
// Fullscreen windows look like they are solo
|
// Fullscreen windows look like they are solo
|
||||||
@ -206,7 +224,7 @@ void Window::queryActiveWorkspace() {
|
|||||||
} else {
|
} else {
|
||||||
soloClass_ = "";
|
soloClass_ = "";
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
} else {
|
} else {
|
||||||
focused_ = false;
|
focused_ = false;
|
||||||
windowData_ = WindowData{};
|
windowData_ = WindowData{};
|
||||||
|
@ -88,7 +88,7 @@ bool WindowCreationPayload::isEmpty(Workspaces &workspace_manager) {
|
|||||||
|
|
||||||
int WindowCreationPayload::incrementTimeSpentUncreated() { return m_timeSpentUncreated++; }
|
int WindowCreationPayload::incrementTimeSpentUncreated() { return m_timeSpentUncreated++; }
|
||||||
|
|
||||||
void WindowCreationPayload::moveToWorksace(std::string &new_workspace_name) {
|
void WindowCreationPayload::moveToWorkspace(std::string &new_workspace_name) {
|
||||||
m_workspaceName = new_workspace_name;
|
m_workspaceName = new_workspace_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,8 @@ Workspace::Workspace(const Json::Value &workspace_data, Workspaces &workspace_ma
|
|||||||
m_windows(workspace_data["windows"].asInt()),
|
m_windows(workspace_data["windows"].asInt()),
|
||||||
m_isActive(true),
|
m_isActive(true),
|
||||||
m_isPersistentRule(workspace_data["persistent-rule"].asBool()),
|
m_isPersistentRule(workspace_data["persistent-rule"].asBool()),
|
||||||
m_isPersistentConfig(workspace_data["persistent-config"].asBool()) {
|
m_isPersistentConfig(workspace_data["persistent-config"].asBool()),
|
||||||
|
m_ipc(IPC::inst()) {
|
||||||
if (m_name.starts_with("name:")) {
|
if (m_name.starts_with("name:")) {
|
||||||
m_name = m_name.substr(5);
|
m_name = m_name.substr(5);
|
||||||
} else if (m_name.starts_with("special")) {
|
} else if (m_name.starts_with("special")) {
|
||||||
@ -58,20 +59,20 @@ bool Workspace::handleClicked(GdkEventButton *bt) const {
|
|||||||
try {
|
try {
|
||||||
if (id() > 0) { // normal
|
if (id() > 0) { // normal
|
||||||
if (m_workspaceManager.moveToMonitor()) {
|
if (m_workspaceManager.moveToMonitor()) {
|
||||||
gIPC->getSocket1Reply("dispatch focusworkspaceoncurrentmonitor " + std::to_string(id()));
|
m_ipc.getSocket1Reply("dispatch focusworkspaceoncurrentmonitor " + std::to_string(id()));
|
||||||
} else {
|
} else {
|
||||||
gIPC->getSocket1Reply("dispatch workspace " + std::to_string(id()));
|
m_ipc.getSocket1Reply("dispatch workspace " + std::to_string(id()));
|
||||||
}
|
}
|
||||||
} else if (!isSpecial()) { // named (this includes persistent)
|
} else if (!isSpecial()) { // named (this includes persistent)
|
||||||
if (m_workspaceManager.moveToMonitor()) {
|
if (m_workspaceManager.moveToMonitor()) {
|
||||||
gIPC->getSocket1Reply("dispatch focusworkspaceoncurrentmonitor name:" + name());
|
m_ipc.getSocket1Reply("dispatch focusworkspaceoncurrentmonitor name:" + name());
|
||||||
} else {
|
} else {
|
||||||
gIPC->getSocket1Reply("dispatch workspace name:" + name());
|
m_ipc.getSocket1Reply("dispatch workspace name:" + name());
|
||||||
}
|
}
|
||||||
} else if (id() != -99) { // named special
|
} else if (id() != -99) { // named special
|
||||||
gIPC->getSocket1Reply("dispatch togglespecialworkspace " + name());
|
m_ipc.getSocket1Reply("dispatch togglespecialworkspace " + name());
|
||||||
} else { // special
|
} else { // special
|
||||||
gIPC->getSocket1Reply("dispatch togglespecialworkspace");
|
m_ipc.getSocket1Reply("dispatch togglespecialworkspace");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
@ -90,19 +91,19 @@ void Workspace::initializeWindowMap(const Json::Value &clients_data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::insertWindow(WindowCreationPayload create_window_paylod) {
|
void Workspace::insertWindow(WindowCreationPayload create_window_payload) {
|
||||||
if (!create_window_paylod.isEmpty(m_workspaceManager)) {
|
if (!create_window_payload.isEmpty(m_workspaceManager)) {
|
||||||
auto repr = create_window_paylod.repr(m_workspaceManager);
|
auto repr = create_window_payload.repr(m_workspaceManager);
|
||||||
|
|
||||||
if (!repr.empty()) {
|
if (!repr.empty()) {
|
||||||
m_windowMap[create_window_paylod.getAddress()] = repr;
|
m_windowMap[create_window_payload.getAddress()] = repr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Workspace::onWindowOpened(WindowCreationPayload const &create_window_paylod) {
|
bool Workspace::onWindowOpened(WindowCreationPayload const &create_window_payload) {
|
||||||
if (create_window_paylod.getWorkspaceName() == name()) {
|
if (create_window_payload.getWorkspaceName() == name()) {
|
||||||
insertWindow(create_window_paylod);
|
insertWindow(create_window_payload);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -172,6 +173,10 @@ std::string &Workspace::selectIcon(std::map<std::string, std::string> &icons_map
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::update(const std::string &format, const std::string &icon) {
|
void Workspace::update(const std::string &format, const std::string &icon) {
|
||||||
|
if (this->m_workspaceManager.persistentOnly() && !this->isPersistent()) {
|
||||||
|
m_button.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
// clang-format off
|
// clang-format off
|
||||||
if (this->m_workspaceManager.activeOnly() && \
|
if (this->m_workspaceManager.activeOnly() && \
|
||||||
!this->isActive() && \
|
!this->isActive() && \
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -13,7 +14,10 @@
|
|||||||
namespace waybar::modules::hyprland {
|
namespace waybar::modules::hyprland {
|
||||||
|
|
||||||
Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value &config)
|
Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value &config)
|
||||||
: AModule(config, "workspaces", id, false, false), m_bar(bar), m_box(bar.orientation, 0) {
|
: AModule(config, "workspaces", id, false, false),
|
||||||
|
m_bar(bar),
|
||||||
|
m_box(bar.orientation, 0),
|
||||||
|
m_ipc(IPC::inst()) {
|
||||||
modulesReady = true;
|
modulesReady = true;
|
||||||
parseConfig(config);
|
parseConfig(config);
|
||||||
|
|
||||||
@ -24,23 +28,19 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
|
|||||||
m_box.get_style_context()->add_class(MODULE_CLASS);
|
m_box.get_style_context()->add_class(MODULE_CLASS);
|
||||||
event_box_.add(m_box);
|
event_box_.add(m_box);
|
||||||
|
|
||||||
if (!gIPC) {
|
|
||||||
gIPC = std::make_unique<IPC>();
|
|
||||||
}
|
|
||||||
|
|
||||||
setCurrentMonitorId();
|
setCurrentMonitorId();
|
||||||
init();
|
init();
|
||||||
registerIpc();
|
registerIpc();
|
||||||
}
|
}
|
||||||
|
|
||||||
Workspaces::~Workspaces() {
|
Workspaces::~Workspaces() {
|
||||||
gIPC->unregisterForIPC(this);
|
m_ipc.unregisterForIPC(this);
|
||||||
// wait for possible event handler to finish
|
// wait for possible event handler to finish
|
||||||
std::lock_guard<std::mutex> lg(m_mutex);
|
std::lock_guard<std::mutex> lg(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::init() {
|
void Workspaces::init() {
|
||||||
m_activeWorkspaceName = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString();
|
m_activeWorkspaceId = m_ipc.getSocket1JsonReply("activeworkspace")["id"].asInt();
|
||||||
|
|
||||||
initializeWorkspaces();
|
initializeWorkspaces();
|
||||||
dp.emit();
|
dp.emit();
|
||||||
@ -50,13 +50,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 +68,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 +79,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 +157,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 = gIPC->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,12 +179,12 @@ 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
|
||||||
auto const workspacesJson = gIPC->getSocket1JsonReply("workspaces");
|
auto const workspacesJson = m_ipc.getSocket1JsonReply("workspaces");
|
||||||
auto const clientsJson = gIPC->getSocket1JsonReply("clients");
|
auto const clientsJson = m_ipc.getSocket1JsonReply("clients");
|
||||||
|
|
||||||
for (Json::Value workspaceJson : workspacesJson) {
|
for (Json::Value workspaceJson : workspacesJson) {
|
||||||
std::string workspaceName = workspaceJson["name"].asString();
|
std::string workspaceName = workspaceJson["name"].asString();
|
||||||
@ -233,7 +231,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 +246,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()) {
|
||||||
@ -285,7 +283,7 @@ void Workspaces::loadPersistentWorkspacesFromConfig(Json::Value const &clientsJs
|
|||||||
void Workspaces::loadPersistentWorkspacesFromWorkspaceRules(const Json::Value &clientsJson) {
|
void Workspaces::loadPersistentWorkspacesFromWorkspaceRules(const Json::Value &clientsJson) {
|
||||||
spdlog::info("Loading persistent workspaces from Hyprland workspace rules");
|
spdlog::info("Loading persistent workspaces from Hyprland workspace rules");
|
||||||
|
|
||||||
auto const workspaceRules = gIPC->getSocket1JsonReply("workspacerules");
|
auto const workspaceRules = m_ipc.getSocket1JsonReply("workspacerules");
|
||||||
for (Json::Value const &rule : workspaceRules) {
|
for (Json::Value const &rule : workspaceRules) {
|
||||||
if (!rule["workspaceString"].isString()) {
|
if (!rule["workspaceString"].isString()) {
|
||||||
spdlog::warn("Workspace rules: invalid workspaceString, skipping: {}", rule);
|
spdlog::warn("Workspace rules: invalid workspaceString, skipping: {}", rule);
|
||||||
@ -294,7 +292,8 @@ void Workspaces::loadPersistentWorkspacesFromWorkspaceRules(const Json::Value &c
|
|||||||
if (!rule["persistent"].asBool()) {
|
if (!rule["persistent"].asBool()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto const &workspace = rule["workspaceString"].asString();
|
auto const &workspace = rule.isMember("defaultName") ? rule["defaultName"].asString()
|
||||||
|
: rule["workspaceString"].asString();
|
||||||
auto const &monitor = rule["monitor"].asString();
|
auto const &monitor = rule["monitor"].asString();
|
||||||
// create this workspace persistently if:
|
// create this workspace persistently if:
|
||||||
// 1. the allOutputs config option is enabled
|
// 1. the allOutputs config option is enabled
|
||||||
@ -306,6 +305,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,29 +316,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();
|
||||||
@ -348,7 +348,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) {
|
||||||
@ -357,39 +361,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);
|
|
||||||
auto const workspacesJson = gIPC->getSocket1JsonReply("workspaces");
|
|
||||||
|
|
||||||
if (!isWorkspaceIgnored(workspaceName)) {
|
const auto [workspaceIdStr, _] = splitDoublePayload(payload);
|
||||||
auto const workspaceRules = gIPC->getSocket1JsonReply("workspacerules");
|
|
||||||
for (Json::Value workspaceJson : workspacesJson) {
|
|
||||||
std::string name = workspaceJson["name"].asString();
|
|
||||||
if (name == workspaceName) {
|
|
||||||
if ((allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
|
|
||||||
(showSpecial() || !name.starts_with("special")) && !isDoubleSpecial(workspaceName)) {
|
|
||||||
for (Json::Value const &rule : workspaceRules) {
|
|
||||||
if (rule["workspaceString"].asString() == workspaceName) {
|
|
||||||
workspaceJson["persistent-rule"] = rule["persistent"].asBool();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_workspacesToCreate.emplace_back(workspaceJson, clientsData);
|
const auto workspaceId = parseWorkspaceId(workspaceIdStr);
|
||||||
break;
|
if (!workspaceId.has_value()) {
|
||||||
}
|
return;
|
||||||
} else {
|
}
|
||||||
extendOrphans(workspaceJson["id"].asInt(), clientsData);
|
|
||||||
|
auto const workspaceRules = m_ipc.getSocket1JsonReply("workspacerules");
|
||||||
|
auto const workspacesJson = m_ipc.getSocket1JsonReply("workspaces");
|
||||||
|
|
||||||
|
for (Json::Value workspaceJson : workspacesJson) {
|
||||||
|
const auto currentId = workspaceJson["id"].asInt();
|
||||||
|
if (currentId == *workspaceId) {
|
||||||
|
std::string workspaceName = workspaceJson["name"].asString();
|
||||||
|
// This workspace name is more up-to-date than the one in the event payload.
|
||||||
|
if (isWorkspaceIgnored(workspaceName)) {
|
||||||
|
spdlog::trace("Not creating workspace because it is ignored: id={} name={}", *workspaceId,
|
||||||
|
workspaceName);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,32 +417,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 = (gIPC->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 = gIPC->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;
|
||||||
}
|
}
|
||||||
@ -432,11 +454,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);
|
|
||||||
|
|
||||||
for (Json::Value &monitor : gIPC->getSocket1JsonReply("monitors")) {
|
const auto [monitorName, workspaceIdStr] = splitDoublePayload(payload);
|
||||||
if (monitor["name"].asString() == payload.substr(0, payload.find(','))) {
|
|
||||||
auto name = monitor["specialWorkspace"]["name"].asString();
|
const auto workspaceId = parseWorkspaceId(workspaceIdStr);
|
||||||
|
if (!workspaceId.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_activeWorkspaceId = *workspaceId;
|
||||||
|
|
||||||
|
for (Json::Value &monitor : m_ipc.getSocket1JsonReply("monitors")) {
|
||||||
|
if (monitor["name"].asString() == monitorName) {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -475,11 +505,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);
|
|
||||||
|
|
||||||
std::string windowRepr;
|
std::string windowRepr;
|
||||||
|
|
||||||
@ -487,7 +513,7 @@ void Workspaces::onWindowMoved(std::string const &payload) {
|
|||||||
// and exit
|
// and exit
|
||||||
for (auto &window : m_windowsToCreate) {
|
for (auto &window : m_windowsToCreate) {
|
||||||
if (window.getAddress() == windowAddress) {
|
if (window.getAddress() == windowAddress) {
|
||||||
window.moveToWorksace(workspaceName);
|
window.moveToWorkspace(workspaceName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -515,13 +541,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
|
||||||
@ -530,9 +558,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()) {
|
||||||
@ -542,15 +570,14 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (inserter.has_value()) {
|
if (inserter.has_value()) {
|
||||||
Json::Value clientsData = gIPC->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 =
|
auto client = std::ranges::find_if(clientsData, [jsonWindowAddress](auto &client) {
|
||||||
std::find_if(clientsData.begin(), clientsData.end(), [jsonWindowAddress](auto &client) {
|
return client["address"].asString() == jsonWindowAddress;
|
||||||
return client["address"].asString() == jsonWindowAddress;
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if (!client->empty()) {
|
if (client != clientsData.end() && !client->empty()) {
|
||||||
(*inserter)({*client});
|
(*inserter)({*client});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -573,6 +600,7 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void {
|
|||||||
populateBoolConfig(config, "all-outputs", m_allOutputs);
|
populateBoolConfig(config, "all-outputs", m_allOutputs);
|
||||||
populateBoolConfig(config, "show-special", m_showSpecial);
|
populateBoolConfig(config, "show-special", m_showSpecial);
|
||||||
populateBoolConfig(config, "special-visible-only", m_specialVisibleOnly);
|
populateBoolConfig(config, "special-visible-only", m_specialVisibleOnly);
|
||||||
|
populateBoolConfig(config, "persistent-only", m_persistentOnly);
|
||||||
populateBoolConfig(config, "active-only", m_activeOnly);
|
populateBoolConfig(config, "active-only", m_activeOnly);
|
||||||
populateBoolConfig(config, "move-to-monitor", m_moveToMonitor);
|
populateBoolConfig(config, "move-to-monitor", m_moveToMonitor);
|
||||||
|
|
||||||
@ -590,8 +618,8 @@ auto Workspaces::populateIconsMap(const Json::Value &formatIcons) -> void {
|
|||||||
m_iconsMap.emplace("", "");
|
m_iconsMap.emplace("", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Workspaces::populateBoolConfig(const Json::Value &config, const std::string &key,
|
auto Workspaces::populateBoolConfig(const Json::Value &config, const std::string &key, bool &member)
|
||||||
bool &member) -> void {
|
-> void {
|
||||||
const auto &configValue = config[key];
|
const auto &configValue = config[key];
|
||||||
if (configValue.isBool()) {
|
if (configValue.isBool()) {
|
||||||
member = configValue.asBool();
|
member = configValue.asBool();
|
||||||
@ -660,40 +688,58 @@ void Workspaces::registerOrphanWindow(WindowCreationPayload create_window_payloa
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Workspaces::registerIpc() -> void {
|
auto Workspaces::registerIpc() -> void {
|
||||||
gIPC->registerForIPC("workspace", this);
|
m_ipc.registerForIPC("workspacev2", this);
|
||||||
gIPC->registerForIPC("activespecial", this);
|
m_ipc.registerForIPC("activespecial", this);
|
||||||
gIPC->registerForIPC("createworkspace", this);
|
m_ipc.registerForIPC("createworkspacev2", this);
|
||||||
gIPC->registerForIPC("destroyworkspace", this);
|
m_ipc.registerForIPC("destroyworkspacev2", this);
|
||||||
gIPC->registerForIPC("focusedmon", this);
|
m_ipc.registerForIPC("focusedmonv2", this);
|
||||||
gIPC->registerForIPC("moveworkspace", this);
|
m_ipc.registerForIPC("moveworkspacev2", this);
|
||||||
gIPC->registerForIPC("renameworkspace", this);
|
m_ipc.registerForIPC("renameworkspace", this);
|
||||||
gIPC->registerForIPC("openwindow", this);
|
m_ipc.registerForIPC("openwindow", this);
|
||||||
gIPC->registerForIPC("closewindow", this);
|
m_ipc.registerForIPC("closewindow", this);
|
||||||
gIPC->registerForIPC("movewindow", this);
|
m_ipc.registerForIPC("movewindowv2", this);
|
||||||
gIPC->registerForIPC("urgent", this);
|
m_ipc.registerForIPC("urgent", this);
|
||||||
gIPC->registerForIPC("configreloaded", this);
|
m_ipc.registerForIPC("configreloaded", this);
|
||||||
|
|
||||||
if (windowRewriteConfigUsesTitle()) {
|
if (windowRewriteConfigUsesTitle()) {
|
||||||
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.");
|
||||||
gIPC->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
|
||||||
@ -701,7 +747,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,10 +759,10 @@ void Workspaces::removeWorkspace(std::string const &name) {
|
|||||||
void Workspaces::setCurrentMonitorId() {
|
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 = gIPC->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 {
|
||||||
@ -725,62 +772,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);
|
||||||
@ -788,7 +836,7 @@ void Workspaces::sortWorkspaces() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::setUrgentWorkspace(std::string const &windowaddress) {
|
void Workspaces::setUrgentWorkspace(std::string const &windowaddress) {
|
||||||
const Json::Value clientsJson = gIPC->getSocket1JsonReply("clients");
|
const Json::Value clientsJson = m_ipc.getSocket1JsonReply("clients");
|
||||||
int workspaceId = -1;
|
int workspaceId = -1;
|
||||||
|
|
||||||
for (Json::Value clientJson : clientsJson) {
|
for (Json::Value clientJson : clientsJson) {
|
||||||
@ -798,9 +846,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();
|
||||||
}
|
}
|
||||||
@ -812,13 +860,12 @@ auto Workspaces::update() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::updateWindowCount() {
|
void Workspaces::updateWindowCount() {
|
||||||
const Json::Value workspacesJson = gIPC->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 {
|
||||||
@ -858,26 +905,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 = gIPC->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 ||
|
||||||
if (workspace->name() == m_activeWorkspaceName && workspace->isUrgent()) {
|
(workspace->isSpecial() && workspace->name() == m_activeSpecialWorkspaceName));
|
||||||
|
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());
|
||||||
}
|
}
|
||||||
@ -905,4 +952,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
|
||||||
|
@ -60,6 +60,7 @@ auto waybar::modules::Memory::update() -> void {
|
|||||||
fmt::arg("icon", getIcon(used_ram_percentage, icons)),
|
fmt::arg("icon", getIcon(used_ram_percentage, icons)),
|
||||||
fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes),
|
fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes),
|
||||||
fmt::arg("percentage", used_ram_percentage),
|
fmt::arg("percentage", used_ram_percentage),
|
||||||
|
fmt::arg("swapState", swaptotal == 0 ? "Off" : "On"),
|
||||||
fmt::arg("swapPercentage", used_swap_percentage), fmt::arg("used", used_ram_gigabytes),
|
fmt::arg("swapPercentage", used_swap_percentage), fmt::arg("used", used_ram_gigabytes),
|
||||||
fmt::arg("swapUsed", used_swap_gigabytes), fmt::arg("avail", available_ram_gigabytes),
|
fmt::arg("swapUsed", used_swap_gigabytes), fmt::arg("avail", available_ram_gigabytes),
|
||||||
fmt::arg("swapAvail", available_swap_gigabytes)));
|
fmt::arg("swapAvail", available_swap_gigabytes)));
|
||||||
@ -72,6 +73,7 @@ auto waybar::modules::Memory::update() -> void {
|
|||||||
fmt::runtime(tooltip_format), used_ram_percentage,
|
fmt::runtime(tooltip_format), used_ram_percentage,
|
||||||
fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes),
|
fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes),
|
||||||
fmt::arg("percentage", used_ram_percentage),
|
fmt::arg("percentage", used_ram_percentage),
|
||||||
|
fmt::arg("swapState", swaptotal == 0 ? "Off" : "On"),
|
||||||
fmt::arg("swapPercentage", used_swap_percentage), fmt::arg("used", used_ram_gigabytes),
|
fmt::arg("swapPercentage", used_swap_percentage), fmt::arg("used", used_ram_gigabytes),
|
||||||
fmt::arg("swapUsed", used_swap_gigabytes), fmt::arg("avail", available_ram_gigabytes),
|
fmt::arg("swapUsed", used_swap_gigabytes), fmt::arg("avail", available_ram_gigabytes),
|
||||||
fmt::arg("swapAvail", available_swap_gigabytes)));
|
fmt::arg("swapAvail", available_swap_gigabytes)));
|
||||||
|
@ -14,7 +14,6 @@ extern "C" {
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
namespace waybar::modules::mpris {
|
namespace waybar::modules::mpris {
|
||||||
|
|
||||||
const std::string DEFAULT_FORMAT = "{player} ({status}): {dynamic}";
|
const std::string DEFAULT_FORMAT = "{player} ({status}): {dynamic}";
|
||||||
@ -425,9 +424,11 @@ auto Mpris::onPlayerNameVanished(PlayerctlPlayerManager* manager, PlayerctlPlaye
|
|||||||
auto* mpris = static_cast<Mpris*>(data);
|
auto* mpris = static_cast<Mpris*>(data);
|
||||||
if (!mpris) return;
|
if (!mpris) return;
|
||||||
|
|
||||||
spdlog::debug("mpris: player-vanished callback: {}", player_name->name);
|
spdlog::debug("mpris: name-vanished callback: {}", player_name->name);
|
||||||
|
|
||||||
if (std::string(player_name->name) == mpris->player_) {
|
if (mpris->player_ == "playerctld") {
|
||||||
|
mpris->dp.emit();
|
||||||
|
} else if (mpris->player_ == player_name->name) {
|
||||||
mpris->player = nullptr;
|
mpris->player = nullptr;
|
||||||
mpris->event_box_.set_visible(false);
|
mpris->event_box_.set_visible(false);
|
||||||
mpris->dp.emit();
|
mpris->dp.emit();
|
||||||
@ -498,7 +499,10 @@ auto Mpris::getPlayerInfo() -> std::optional<PlayerInfo> {
|
|||||||
// > get the list of players [..] in order of activity
|
// > get the list of players [..] in order of activity
|
||||||
// https://github.com/altdesktop/playerctl/blob/b19a71cb9dba635df68d271bd2b3f6a99336a223/playerctl/playerctl-common.c#L248-L249
|
// https://github.com/altdesktop/playerctl/blob/b19a71cb9dba635df68d271bd2b3f6a99336a223/playerctl/playerctl-common.c#L248-L249
|
||||||
players = g_list_first(players);
|
players = g_list_first(players);
|
||||||
if (players) player_name = static_cast<PlayerctlPlayerName*>(players->data)->name;
|
if (players)
|
||||||
|
player_name = static_cast<PlayerctlPlayerName*>(players->data)->name;
|
||||||
|
else
|
||||||
|
return std::nullopt; // no players found, hide the widget
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::any_of(ignored_players_.begin(), ignored_players_.end(),
|
if (std::any_of(ignored_players_.begin(), ignored_players_.end(),
|
||||||
@ -584,38 +588,45 @@ errorexit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Mpris::handleToggle(GdkEventButton* const& e) {
|
bool Mpris::handleToggle(GdkEventButton* const& e) {
|
||||||
|
if (!e || e->type != GdkEventType::GDK_BUTTON_PRESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto info = getPlayerInfo();
|
||||||
|
if (!info) return false;
|
||||||
|
|
||||||
|
struct ButtonAction {
|
||||||
|
guint button;
|
||||||
|
const char* config_key;
|
||||||
|
std::function<void()> builtin_action;
|
||||||
|
};
|
||||||
|
|
||||||
GError* error = nullptr;
|
GError* error = nullptr;
|
||||||
waybar::util::ScopeGuard error_deleter([error]() {
|
waybar::util::ScopeGuard error_deleter([&error]() {
|
||||||
if (error) {
|
if (error) {
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
auto info = getPlayerInfo();
|
// Command pattern: encapsulate each button's action
|
||||||
if (!info) return false;
|
const ButtonAction actions[] = {
|
||||||
|
{1, "on-click", [&]() { playerctl_player_play_pause(player, &error); }},
|
||||||
|
{2, "on-click-middle", [&]() { playerctl_player_previous(player, &error); }},
|
||||||
|
{3, "on-click-right", [&]() { playerctl_player_next(player, &error); }},
|
||||||
|
{8, "on-click-backward", [&]() { playerctl_player_previous(player, &error); }},
|
||||||
|
{9, "on-click-forward", [&]() { playerctl_player_next(player, &error); }},
|
||||||
|
};
|
||||||
|
|
||||||
if (e->type == GdkEventType::GDK_BUTTON_PRESS) {
|
for (const auto& action : actions) {
|
||||||
switch (e->button) {
|
if (e->button == action.button) {
|
||||||
case 1: // left-click
|
if (config_[action.config_key].isString()) {
|
||||||
if (config_["on-click"].isString()) {
|
return ALabel::handleToggle(e);
|
||||||
return ALabel::handleToggle(e);
|
}
|
||||||
}
|
action.builtin_action();
|
||||||
playerctl_player_play_pause(player, &error);
|
break;
|
||||||
break;
|
|
||||||
case 2: // middle-click
|
|
||||||
if (config_["on-click-middle"].isString()) {
|
|
||||||
return ALabel::handleToggle(e);
|
|
||||||
}
|
|
||||||
playerctl_player_previous(player, &error);
|
|
||||||
break;
|
|
||||||
case 3: // right-click
|
|
||||||
if (config_["on-click-right"].isString()) {
|
|
||||||
return ALabel::handleToggle(e);
|
|
||||||
}
|
|
||||||
playerctl_player_next(player, &error);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
spdlog::error("mpris[{}]: error running builtin on-click action: {}", (*info).name,
|
spdlog::error("mpris[{}]: error running builtin on-click action: {}", (*info).name,
|
||||||
error->message);
|
error->message);
|
||||||
|
@ -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;
|
||||||
@ -215,8 +223,8 @@ void waybar::modules::Network::worker() {
|
|||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
if (ifid_ > 0) {
|
if (ifid_ > 0) {
|
||||||
getInfo();
|
getInfo();
|
||||||
dp.emit();
|
|
||||||
}
|
}
|
||||||
|
dp.emit();
|
||||||
}
|
}
|
||||||
thread_timer_.sleep_for(interval_);
|
thread_timer_.sleep_for(interval_);
|
||||||
};
|
};
|
||||||
@ -263,14 +271,14 @@ void waybar::modules::Network::worker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::string waybar::modules::Network::getNetworkState() const {
|
const std::string waybar::modules::Network::getNetworkState() const {
|
||||||
if (ifid_ == -1) {
|
|
||||||
#ifdef WANT_RFKILL
|
#ifdef WANT_RFKILL
|
||||||
if (rfkill_.getState()) return "disabled";
|
if (rfkill_.getState()) return "disabled";
|
||||||
#endif
|
#endif
|
||||||
|
if (ifid_ == -1) {
|
||||||
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);
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
namespace waybar::modules::niri {
|
namespace waybar::modules::niri {
|
||||||
|
|
||||||
Language::Language(const std::string &id, const Bar &bar, const Json::Value &config)
|
Language::Language(const std::string &id, const Bar &bar, const Json::Value &config)
|
||||||
: ALabel(config, "language", id, "{}", 0, true), bar_(bar) {
|
: ALabel(config, "language", id, "{}", 0, false), bar_(bar) {
|
||||||
label_.hide();
|
label_.hide();
|
||||||
|
|
||||||
if (!gIPC) gIPC = std::make_unique<IPC>();
|
if (!gIPC) gIPC = std::make_unique<IPC>();
|
||||||
|
@ -166,6 +166,8 @@ std::string Workspaces::getIcon(const std::string &value, const Json::Value &ws)
|
|||||||
const auto &icons = config_["format-icons"];
|
const auto &icons = config_["format-icons"];
|
||||||
if (!icons) return value;
|
if (!icons) return value;
|
||||||
|
|
||||||
|
if (ws["active_window_id"].isNull() && icons["empty"]) return icons["empty"].asString();
|
||||||
|
|
||||||
if (ws["is_focused"].asBool() && icons["focused"]) return icons["focused"].asString();
|
if (ws["is_focused"].asBool() && icons["focused"]) return icons["focused"].asString();
|
||||||
|
|
||||||
if (ws["is_active"].asBool() && icons["active"]) return icons["active"].asString();
|
if (ws["is_active"].asBool() && icons["active"]) return icons["active"].asString();
|
||||||
|
@ -29,14 +29,14 @@ PowerProfilesDaemon::PowerProfilesDaemon(const std::string& id, const Json::Valu
|
|||||||
// method on the proxy to see whether or not something's responding
|
// method on the proxy to see whether or not something's responding
|
||||||
// on the other side.
|
// on the other side.
|
||||||
|
|
||||||
// NOTE: the DBus adresses are under migration. They should be
|
// NOTE: the DBus addresses are under migration. They should be
|
||||||
// changed to org.freedesktop.UPower.PowerProfiles at some point.
|
// changed to org.freedesktop.UPower.PowerProfiles at some point.
|
||||||
//
|
//
|
||||||
// See
|
// See
|
||||||
// https://gitlab.freedesktop.org/upower/power-profiles-daemon/-/releases/0.20
|
// https://gitlab.freedesktop.org/upower/power-profiles-daemon/-/releases/0.20
|
||||||
//
|
//
|
||||||
// The old name is still announced for now. Let's rather use the old
|
// The old name is still announced for now. Let's rather use the old
|
||||||
// adresses for compatibility sake.
|
// addresses for compatibility sake.
|
||||||
//
|
//
|
||||||
// Revisit this in 2026, systems should be updated by then.
|
// Revisit this in 2026, systems should be updated by then.
|
||||||
|
|
||||||
|
@ -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,12 +68,30 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& ignore_item : config_["ignore"]) {
|
||||||
|
if (!ignore_item.isObject() || !ignore_item["type"].isString() ||
|
||||||
|
!ignore_item["name"].isString())
|
||||||
|
continue;
|
||||||
|
const std::string type = ignore_item["type"].asString();
|
||||||
|
const std::string name = ignore_item["name"].asString();
|
||||||
|
|
||||||
|
auto iter = typeMap.find(type);
|
||||||
|
if (iter != typeMap.end()) {
|
||||||
|
auto& [_, nodeType] = iter->second;
|
||||||
|
ignore.emplace(nodeType, std::move(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_["ignore-monitor"].isBool()) {
|
||||||
|
ignore_monitor = config_["ignore-monitor"].asBool();
|
||||||
|
}
|
||||||
|
|
||||||
backend = util::PipewireBackend::PipewireBackend::getInstance();
|
backend = util::PipewireBackend::PipewireBackend::getInstance();
|
||||||
backend->privacy_nodes_changed_signal_event.connect(
|
backend->privacy_nodes_changed_signal_event.connect(
|
||||||
sigc::mem_fun(*this, &Privacy::onPrivacyNodesChanged));
|
sigc::mem_fun(*this, &Privacy::onPrivacyNodesChanged));
|
||||||
@ -87,6 +106,11 @@ void Privacy::onPrivacyNodesChanged() {
|
|||||||
nodes_screenshare.clear();
|
nodes_screenshare.clear();
|
||||||
|
|
||||||
for (auto& node : backend->privacy_nodes) {
|
for (auto& node : backend->privacy_nodes) {
|
||||||
|
if (ignore_monitor && node.second->is_monitor) continue;
|
||||||
|
|
||||||
|
auto iter = ignore.find(std::pair(node.second->type, node.second->node_name));
|
||||||
|
if (iter != ignore.end()) continue;
|
||||||
|
|
||||||
switch (node.second->state) {
|
switch (node.second->state) {
|
||||||
case PW_NODE_STATE_RUNNING:
|
case PW_NODE_STATE_RUNNING:
|
||||||
switch (node.second->type) {
|
switch (node.second->type) {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "modules/privacy/privacy_item.hpp"
|
#include "modules/privacy/privacy_item.hpp"
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "glibmm/main.h"
|
#include "glibmm/main.h"
|
||||||
@ -11,8 +13,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 +43,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_);
|
||||||
|
|
||||||
@ -87,20 +98,22 @@ PrivacyItem::PrivacyItem(const Json::Value &config_, enum PrivacyNodeType privac
|
|||||||
void PrivacyItem::update_tooltip() {
|
void PrivacyItem::update_tooltip() {
|
||||||
// Removes all old nodes
|
// Removes all old nodes
|
||||||
for (auto *child : tooltip_window.get_children()) {
|
for (auto *child : tooltip_window.get_children()) {
|
||||||
|
tooltip_window.remove(*child);
|
||||||
|
// despite the remove, still needs a delete to prevent memory leak. Speculating that this might
|
||||||
|
// work differently in GTK4.
|
||||||
delete child;
|
delete child;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto *node : *nodes) {
|
for (auto *node : *nodes) {
|
||||||
Gtk::Box *box = new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 4);
|
auto *box = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_HORIZONTAL, 4);
|
||||||
|
|
||||||
// Set device icon
|
// Set device icon
|
||||||
Gtk::Image *node_icon = new Gtk::Image();
|
auto *node_icon = Gtk::make_managed<Gtk::Image>();
|
||||||
node_icon->set_pixel_size(tooltipIconSize);
|
node_icon->set_pixel_size(tooltipIconSize);
|
||||||
node_icon->set_from_icon_name(node->getIconName(), Gtk::ICON_SIZE_INVALID);
|
node_icon->set_from_icon_name(node->getIconName(), Gtk::ICON_SIZE_INVALID);
|
||||||
box->add(*node_icon);
|
box->add(*node_icon);
|
||||||
|
|
||||||
// Set model
|
// Set model
|
||||||
auto *nodeName = new Gtk::Label(node->getName());
|
auto *nodeName = Gtk::make_managed<Gtk::Label>(node->getName());
|
||||||
box->add(*nodeName);
|
box->add(*nodeName);
|
||||||
|
|
||||||
tooltip_window.add(*box);
|
tooltip_window.add(*box);
|
||||||
|
@ -189,10 +189,20 @@ bool Tags::handle_button_press(GdkEventButton *event_button, uint32_t tag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Tags::handle_focused_tags(uint32_t tags) {
|
void Tags::handle_focused_tags(uint32_t tags) {
|
||||||
|
auto hide_vacant = config_["hide-vacant"].asBool();
|
||||||
for (size_t i = 0; i < buttons_.size(); ++i) {
|
for (size_t i = 0; i < buttons_.size(); ++i) {
|
||||||
|
bool visible = buttons_[i].is_visible();
|
||||||
|
bool occupied = buttons_[i].get_style_context()->has_class("occupied");
|
||||||
|
bool urgent = buttons_[i].get_style_context()->has_class("urgent");
|
||||||
if ((1 << i) & tags) {
|
if ((1 << i) & tags) {
|
||||||
|
if (hide_vacant && !visible) {
|
||||||
|
buttons_[i].set_visible(true);
|
||||||
|
}
|
||||||
buttons_[i].get_style_context()->add_class("focused");
|
buttons_[i].get_style_context()->add_class("focused");
|
||||||
} else {
|
} else {
|
||||||
|
if (hide_vacant && !(occupied || urgent)) {
|
||||||
|
buttons_[i].set_visible(false);
|
||||||
|
}
|
||||||
buttons_[i].get_style_context()->remove_class("focused");
|
buttons_[i].get_style_context()->remove_class("focused");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,20 +215,40 @@ void Tags::handle_view_tags(struct wl_array *view_tags) {
|
|||||||
for (; view_tag < end; ++view_tag) {
|
for (; view_tag < end; ++view_tag) {
|
||||||
tags |= *view_tag;
|
tags |= *view_tag;
|
||||||
}
|
}
|
||||||
|
auto hide_vacant = config_["hide-vacant"].asBool();
|
||||||
for (size_t i = 0; i < buttons_.size(); ++i) {
|
for (size_t i = 0; i < buttons_.size(); ++i) {
|
||||||
|
bool visible = buttons_[i].is_visible();
|
||||||
|
bool focused = buttons_[i].get_style_context()->has_class("focused");
|
||||||
|
bool urgent = buttons_[i].get_style_context()->has_class("urgent");
|
||||||
if ((1 << i) & tags) {
|
if ((1 << i) & tags) {
|
||||||
|
if (hide_vacant && !visible) {
|
||||||
|
buttons_[i].set_visible(true);
|
||||||
|
}
|
||||||
buttons_[i].get_style_context()->add_class("occupied");
|
buttons_[i].get_style_context()->add_class("occupied");
|
||||||
} else {
|
} else {
|
||||||
|
if (hide_vacant && !(focused || urgent)) {
|
||||||
|
buttons_[i].set_visible(false);
|
||||||
|
}
|
||||||
buttons_[i].get_style_context()->remove_class("occupied");
|
buttons_[i].get_style_context()->remove_class("occupied");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tags::handle_urgent_tags(uint32_t tags) {
|
void Tags::handle_urgent_tags(uint32_t tags) {
|
||||||
|
auto hide_vacant = config_["hide-vacant"].asBool();
|
||||||
for (size_t i = 0; i < buttons_.size(); ++i) {
|
for (size_t i = 0; i < buttons_.size(); ++i) {
|
||||||
|
bool visible = buttons_[i].is_visible();
|
||||||
|
bool occupied = buttons_[i].get_style_context()->has_class("occupied");
|
||||||
|
bool focused = buttons_[i].get_style_context()->has_class("focused");
|
||||||
if ((1 << i) & tags) {
|
if ((1 << i) & tags) {
|
||||||
|
if (hide_vacant && !visible) {
|
||||||
|
buttons_[i].set_visible(true);
|
||||||
|
}
|
||||||
buttons_[i].get_style_context()->add_class("urgent");
|
buttons_[i].get_style_context()->add_class("urgent");
|
||||||
} else {
|
} else {
|
||||||
|
if (hide_vacant && !(occupied || focused)) {
|
||||||
|
buttons_[i].set_visible(false);
|
||||||
|
}
|
||||||
buttons_[i].get_style_context()->remove_class("urgent");
|
buttons_[i].get_style_context()->remove_class("urgent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
|
||||||
@ -124,7 +126,8 @@ ToolTip get_variant<ToolTip>(const Glib::VariantBase& value) {
|
|||||||
result.text = get_variant<Glib::ustring>(container.get_child(2));
|
result.text = get_variant<Glib::ustring>(container.get_child(2));
|
||||||
auto description = get_variant<Glib::ustring>(container.get_child(3));
|
auto description = get_variant<Glib::ustring>(container.get_child(3));
|
||||||
if (!description.empty()) {
|
if (!description.empty()) {
|
||||||
result.text = fmt::format("<b>{}</b>\n{}", result.text, description);
|
auto escapedDescription = Glib::Markup::escape_text(description);
|
||||||
|
result.text = fmt::format("<b>{}</b>\n{}", result.text, escapedDescription);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -137,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()) {
|
||||||
@ -198,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)});
|
||||||
@ -371,14 +388,17 @@ Glib::RefPtr<Gdk::Pixbuf> Item::getIconPixbuf() {
|
|||||||
Glib::RefPtr<Gdk::Pixbuf> Item::getIconByName(const std::string& name, int request_size) {
|
Glib::RefPtr<Gdk::Pixbuf> Item::getIconByName(const std::string& name, int request_size) {
|
||||||
icon_theme->rescan_if_needed();
|
icon_theme->rescan_if_needed();
|
||||||
|
|
||||||
if (!icon_theme_path.empty() &&
|
if (!icon_theme_path.empty()) {
|
||||||
icon_theme->lookup_icon(name.c_str(), request_size,
|
auto icon_info = icon_theme->lookup_icon(name.c_str(), request_size,
|
||||||
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE)) {
|
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);
|
||||||
return icon_theme->load_icon(name.c_str(), request_size,
|
if (icon_info) {
|
||||||
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);
|
bool is_sym = false;
|
||||||
|
return icon_info.load_symbolic(event_box.get_style_context(), is_sym);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return DefaultGtkIconThemeWrapper::load_icon(name.c_str(), request_size,
|
return DefaultGtkIconThemeWrapper::load_icon(name.c_str(), request_size,
|
||||||
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);
|
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE,
|
||||||
|
event_box.get_style_context());
|
||||||
}
|
}
|
||||||
|
|
||||||
double Item::getScaledIconSize() {
|
double Item::getScaledIconSize() {
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@ Language::Language(const std::string& id, const Json::Value& config)
|
|||||||
hide_single_ = config["hide-single-layout"].isBool() && config["hide-single-layout"].asBool();
|
hide_single_ = config["hide-single-layout"].isBool() && config["hide-single-layout"].asBool();
|
||||||
is_variant_displayed = format_.find("{variant}") != std::string::npos;
|
is_variant_displayed = format_.find("{variant}") != std::string::npos;
|
||||||
if (format_.find("{}") != std::string::npos || format_.find("{short}") != std::string::npos) {
|
if (format_.find("{}") != std::string::npos || format_.find("{short}") != std::string::npos) {
|
||||||
displayed_short_flag |= static_cast<std::byte>(DispayedShortFlag::ShortName);
|
displayed_short_flag |= static_cast<std::byte>(DisplayedShortFlag::ShortName);
|
||||||
}
|
}
|
||||||
if (format_.find("{shortDescription}") != std::string::npos) {
|
if (format_.find("{shortDescription}") != std::string::npos) {
|
||||||
displayed_short_flag |= static_cast<std::byte>(DispayedShortFlag::ShortDescription);
|
displayed_short_flag |= static_cast<std::byte>(DisplayedShortFlag::ShortDescription);
|
||||||
}
|
}
|
||||||
if (config.isMember("tooltip-format")) {
|
if (config.isMember("tooltip-format")) {
|
||||||
tooltip_format_ = config["tooltip-format"].asString();
|
tooltip_format_ = config["tooltip-format"].asString();
|
||||||
|
@ -41,8 +41,8 @@ void Window::onCmd(const struct Ipc::ipc_response& res) {
|
|||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
auto payload = parser_.parse(res.payload);
|
auto payload = parser_.parse(res.payload);
|
||||||
auto output = payload["output"].isString() ? payload["output"].asString() : "";
|
auto output = payload["output"].isString() ? payload["output"].asString() : "";
|
||||||
std::tie(app_nb_, floating_count_, windowId_, window_, app_id_, app_class_, shell_, layout_) =
|
std::tie(app_nb_, floating_count_, windowId_, window_, app_id_, app_class_, shell_, layout_,
|
||||||
getFocusedNode(payload["nodes"], output);
|
marks_) = getFocusedNode(payload["nodes"], output);
|
||||||
updateAppIconName(app_id_, app_class_);
|
updateAppIconName(app_id_, app_class_);
|
||||||
dp.emit();
|
dp.emit();
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
@ -96,7 +96,7 @@ auto Window::update() -> void {
|
|||||||
|
|
||||||
label_.set_markup(waybar::util::rewriteString(
|
label_.set_markup(waybar::util::rewriteString(
|
||||||
fmt::format(fmt::runtime(format_), fmt::arg("title", window_), fmt::arg("app_id", app_id_),
|
fmt::format(fmt::runtime(format_), fmt::arg("title", window_), fmt::arg("app_id", app_id_),
|
||||||
fmt::arg("shell", shell_)),
|
fmt::arg("shell", shell_), fmt::arg("marks", marks_)),
|
||||||
config_["rewrite"]));
|
config_["rewrite"]));
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
label_.set_tooltip_text(window_);
|
label_.set_tooltip_text(window_);
|
||||||
@ -108,7 +108,7 @@ auto Window::update() -> void {
|
|||||||
AAppIconLabel::update();
|
AAppIconLabel::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::setClass(std::string classname, bool enable) {
|
void Window::setClass(const std::string& classname, bool enable) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
if (!bar_.window.get_style_context()->has_class(classname)) {
|
if (!bar_.window.get_style_context()->has_class(classname)) {
|
||||||
bar_.window.get_style_context()->add_class(classname);
|
bar_.window.get_style_context()->add_class(classname);
|
||||||
@ -169,17 +169,31 @@ std::optional<std::reference_wrapper<const Json::Value>> getSingleChildNode(
|
|||||||
return {getSingleChildNode(child)};
|
return {getSingleChildNode(child)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<std::string, std::string, std::string> getWindowInfo(const Json::Value& node) {
|
std::tuple<std::string, std::string, std::string, std::string> getWindowInfo(
|
||||||
|
const Json::Value& node, bool showHidden) {
|
||||||
const auto app_id = node["app_id"].isString() ? node["app_id"].asString()
|
const auto app_id = node["app_id"].isString() ? node["app_id"].asString()
|
||||||
: node["window_properties"]["instance"].asString();
|
: node["window_properties"]["instance"].asString();
|
||||||
const auto app_class = node["window_properties"]["class"].isString()
|
const auto app_class = node["window_properties"]["class"].isString()
|
||||||
? node["window_properties"]["class"].asString()
|
? node["window_properties"]["class"].asString()
|
||||||
: "";
|
: "";
|
||||||
const auto shell = node["shell"].isString() ? node["shell"].asString() : "";
|
const auto shell = node["shell"].isString() ? node["shell"].asString() : "";
|
||||||
return {app_id, app_class, shell};
|
std::string marks = "";
|
||||||
|
if (node["marks"].isArray()) {
|
||||||
|
for (const auto& m : node["marks"]) {
|
||||||
|
if (!m.isString() || (!showHidden && m.asString().at(0) == '_')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!marks.empty()) {
|
||||||
|
marks += ',';
|
||||||
|
}
|
||||||
|
marks += m.asString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {app_id, app_class, shell, marks};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string>
|
std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string,
|
||||||
|
std::string>
|
||||||
gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Value& config_,
|
gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Value& config_,
|
||||||
const Bar& bar_, Json::Value& parentWorkspace,
|
const Bar& bar_, Json::Value& parentWorkspace,
|
||||||
const Json::Value& immediateParent) {
|
const Json::Value& immediateParent) {
|
||||||
@ -207,7 +221,8 @@ gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Valu
|
|||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
node["layout"].asString()};
|
node["layout"].asString(),
|
||||||
|
""};
|
||||||
}
|
}
|
||||||
parentWorkspace = node;
|
parentWorkspace = node;
|
||||||
} else if ((node["type"].asString() == "con" || node["type"].asString() == "floating_con") &&
|
} else if ((node["type"].asString() == "con" || node["type"].asString() == "floating_con") &&
|
||||||
@ -215,7 +230,8 @@ gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Valu
|
|||||||
// found node
|
// found node
|
||||||
spdlog::trace("actual output {}, output found {}, node (focused) found {}", bar_.output->name,
|
spdlog::trace("actual output {}, output found {}, node (focused) found {}", bar_.output->name,
|
||||||
output, node["name"].asString());
|
output, node["name"].asString());
|
||||||
const auto [app_id, app_class, shell] = getWindowInfo(node);
|
const auto [app_id, app_class, shell, marks] =
|
||||||
|
getWindowInfo(node, config_["show-hidden-marks"].asBool());
|
||||||
int nb = node.size();
|
int nb = node.size();
|
||||||
int floating_count = 0;
|
int floating_count = 0;
|
||||||
std::string workspace_layout = "";
|
std::string workspace_layout = "";
|
||||||
@ -232,20 +248,21 @@ gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Valu
|
|||||||
app_id,
|
app_id,
|
||||||
app_class,
|
app_class,
|
||||||
shell,
|
shell,
|
||||||
workspace_layout};
|
workspace_layout,
|
||||||
|
marks};
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate
|
// iterate
|
||||||
auto [nb, f, id, name, app_id, app_class, shell, workspace_layout] =
|
auto [nb, f, id, name, app_id, app_class, shell, workspace_layout, marks] =
|
||||||
gfnWithWorkspace(node["nodes"], output, config_, bar_, parentWorkspace, node);
|
gfnWithWorkspace(node["nodes"], output, config_, bar_, parentWorkspace, node);
|
||||||
auto [nb2, f2, id2, name2, app_id2, app_class2, shell2, workspace_layout2] =
|
auto [nb2, f2, id2, name2, app_id2, app_class2, shell2, workspace_layout2, marks2] =
|
||||||
gfnWithWorkspace(node["floating_nodes"], output, config_, bar_, parentWorkspace, node);
|
gfnWithWorkspace(node["floating_nodes"], output, config_, bar_, parentWorkspace, node);
|
||||||
|
|
||||||
// if ((id > 0 || ((id2 < 0 || name2.empty()) && id > -1)) && !name.empty()) {
|
// if ((id > 0 || ((id2 < 0 || name2.empty()) && id > -1)) && !name.empty()) {
|
||||||
if ((id > 0) || (id2 < 0 && id > -1)) {
|
if ((id > 0) || (id2 < 0 && id > -1)) {
|
||||||
return {nb, f, id, name, app_id, app_class, shell, workspace_layout};
|
return {nb, f, id, name, app_id, app_class, shell, workspace_layout, marks};
|
||||||
} else if (id2 > 0 && !name2.empty()) {
|
} else if (id2 > 0 && !name2.empty()) {
|
||||||
return {nb2, f2, id2, name2, app_id2, app_class, shell2, workspace_layout2};
|
return {nb2, f2, id2, name2, app_id2, app_class, shell2, workspace_layout2, marks2};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,10 +275,12 @@ gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Valu
|
|||||||
std::string app_id = "";
|
std::string app_id = "";
|
||||||
std::string app_class = "";
|
std::string app_class = "";
|
||||||
std::string workspace_layout = "";
|
std::string workspace_layout = "";
|
||||||
|
std::string marks = "";
|
||||||
if (all_leaf_nodes.first == 1) {
|
if (all_leaf_nodes.first == 1) {
|
||||||
const auto single_child = getSingleChildNode(immediateParent);
|
const auto single_child = getSingleChildNode(immediateParent);
|
||||||
if (single_child.has_value()) {
|
if (single_child.has_value()) {
|
||||||
std::tie(app_id, app_class, workspace_layout) = getWindowInfo(single_child.value());
|
std::tie(app_id, app_class, workspace_layout, marks) =
|
||||||
|
getWindowInfo(single_child.value(), config_["show-hidden-marks"].asBool());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {all_leaf_nodes.first,
|
return {all_leaf_nodes.first,
|
||||||
@ -273,13 +292,15 @@ gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Valu
|
|||||||
app_id,
|
app_id,
|
||||||
app_class,
|
app_class,
|
||||||
workspace_layout,
|
workspace_layout,
|
||||||
immediateParent["layout"].asString()};
|
immediateParent["layout"].asString(),
|
||||||
|
marks};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {0, 0, -1, "", "", "", "", ""};
|
return {0, 0, -1, "", "", "", "", "", ""};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string>
|
std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string,
|
||||||
|
std::string>
|
||||||
Window::getFocusedNode(const Json::Value& nodes, std::string& output) {
|
Window::getFocusedNode(const Json::Value& nodes, std::string& output) {
|
||||||
Json::Value placeholder = Json::Value::null;
|
Json::Value placeholder = Json::Value::null;
|
||||||
return gfnWithWorkspace(nodes, output, config_, bar_, placeholder, placeholder);
|
return gfnWithWorkspace(nodes, output, config_, bar_, placeholder, placeholder);
|
||||||
|
@ -57,9 +57,9 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
|
|||||||
box_.get_style_context()->add_class(MODULE_CLASS);
|
box_.get_style_context()->add_class(MODULE_CLASS);
|
||||||
event_box_.add(box_);
|
event_box_.add(box_);
|
||||||
if (config_["format-window-separator"].isString()) {
|
if (config_["format-window-separator"].isString()) {
|
||||||
m_formatWindowSeperator = config_["format-window-separator"].asString();
|
m_formatWindowSeparator = config_["format-window-separator"].asString();
|
||||||
} else {
|
} else {
|
||||||
m_formatWindowSeperator = " ";
|
m_formatWindowSeparator = " ";
|
||||||
}
|
}
|
||||||
const Json::Value &windowRewrite = config["window-rewrite"];
|
const Json::Value &windowRewrite = config["window-rewrite"];
|
||||||
if (windowRewrite.isObject()) {
|
if (windowRewrite.isObject()) {
|
||||||
@ -271,7 +271,7 @@ void Workspaces::updateWindows(const Json::Value &node, std::string &windows) {
|
|||||||
window = fmt::format(fmt::runtime(window), fmt::arg("name", title),
|
window = fmt::format(fmt::runtime(window), fmt::arg("name", title),
|
||||||
fmt::arg("class", windowClass));
|
fmt::arg("class", windowClass));
|
||||||
windows.append(window);
|
windows.append(window);
|
||||||
windows.append(m_formatWindowSeperator);
|
windows.append(m_formatWindowSeparator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const Json::Value &child : node["nodes"]) {
|
for (const Json::Value &child : node["nodes"]) {
|
||||||
@ -340,7 +340,7 @@ auto Workspaces::update() -> void {
|
|||||||
fmt::runtime(format), fmt::arg("icon", getIcon(output, *it)), fmt::arg("value", output),
|
fmt::runtime(format), fmt::arg("icon", getIcon(output, *it)), fmt::arg("value", output),
|
||||||
fmt::arg("name", trimWorkspaceName(output)), fmt::arg("index", (*it)["num"].asString()),
|
fmt::arg("name", trimWorkspaceName(output)), fmt::arg("index", (*it)["num"].asString()),
|
||||||
fmt::arg("windows",
|
fmt::arg("windows",
|
||||||
windows.substr(0, windows.length() - m_formatWindowSeperator.length())),
|
windows.substr(0, windows.length() - m_formatWindowSeparator.length())),
|
||||||
fmt::arg("output", (*it)["output"].asString()));
|
fmt::arg("output", (*it)["output"].asString()));
|
||||||
}
|
}
|
||||||
if (!config_["disable-markup"].asBool()) {
|
if (!config_["disable-markup"].asBool()) {
|
||||||
@ -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();
|
||||||
|
@ -16,6 +16,7 @@ SystemdFailedUnits::SystemdFailedUnits(const std::string& id, const Json::Value&
|
|||||||
update_pending(false),
|
update_pending(false),
|
||||||
nr_failed_system(0),
|
nr_failed_system(0),
|
||||||
nr_failed_user(0),
|
nr_failed_user(0),
|
||||||
|
nr_failed(0),
|
||||||
last_status() {
|
last_status() {
|
||||||
if (config["hide-on-ok"].isBool()) {
|
if (config["hide-on-ok"].isBool()) {
|
||||||
hide_on_ok = config["hide-on-ok"].asBool();
|
hide_on_ok = config["hide-on-ok"].asBool();
|
||||||
@ -67,11 +68,38 @@ auto SystemdFailedUnits::notify_cb(const Glib::ustring& sender_name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemdFailedUnits::updateData() {
|
void SystemdFailedUnits::RequestSystemState() {
|
||||||
update_pending = false;
|
auto load = [](const char* kind, Glib::RefPtr<Gio::DBus::Proxy>& proxy) -> std::string {
|
||||||
|
try {
|
||||||
|
if (!proxy) return "unknown";
|
||||||
|
auto parameters = Glib::VariantContainerBase(
|
||||||
|
g_variant_new("(ss)", "org.freedesktop.systemd1.Manager", "SystemState"));
|
||||||
|
Glib::VariantContainerBase data = proxy->call_sync("Get", parameters);
|
||||||
|
if (data && data.is_of_type(Glib::VariantType("(v)"))) {
|
||||||
|
Glib::VariantBase variant;
|
||||||
|
g_variant_get(data.gobj_copy(), "(v)", &variant);
|
||||||
|
if (variant && variant.is_of_type(Glib::VARIANT_TYPE_STRING)) {
|
||||||
|
return g_variant_get_string(variant.gobj_copy(), NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Glib::Error& e) {
|
||||||
|
spdlog::error("Failed to get {} state: {}", kind, e.what().c_str());
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
};
|
||||||
|
|
||||||
|
system_state = load("systemwide", system_proxy);
|
||||||
|
user_state = load("user", user_proxy);
|
||||||
|
if (system_state == "running" && user_state == "running")
|
||||||
|
overall_state = "ok";
|
||||||
|
else
|
||||||
|
overall_state = "degraded";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemdFailedUnits::RequestFailedUnits() {
|
||||||
auto load = [](const char* kind, Glib::RefPtr<Gio::DBus::Proxy>& proxy) -> uint32_t {
|
auto load = [](const char* kind, Glib::RefPtr<Gio::DBus::Proxy>& proxy) -> uint32_t {
|
||||||
try {
|
try {
|
||||||
|
if (!proxy) return 0;
|
||||||
auto parameters = Glib::VariantContainerBase(
|
auto parameters = Glib::VariantContainerBase(
|
||||||
g_variant_new("(ss)", "org.freedesktop.systemd1.Manager", "NFailedUnits"));
|
g_variant_new("(ss)", "org.freedesktop.systemd1.Manager", "NFailedUnits"));
|
||||||
Glib::VariantContainerBase data = proxy->call_sync("Get", parameters);
|
Glib::VariantContainerBase data = proxy->call_sync("Get", parameters);
|
||||||
@ -79,9 +107,7 @@ void SystemdFailedUnits::updateData() {
|
|||||||
Glib::VariantBase variant;
|
Glib::VariantBase variant;
|
||||||
g_variant_get(data.gobj_copy(), "(v)", &variant);
|
g_variant_get(data.gobj_copy(), "(v)", &variant);
|
||||||
if (variant && variant.is_of_type(Glib::VARIANT_TYPE_UINT32)) {
|
if (variant && variant.is_of_type(Glib::VARIANT_TYPE_UINT32)) {
|
||||||
uint32_t value = 0;
|
return g_variant_get_uint32(variant.gobj_copy());
|
||||||
g_variant_get(variant.gobj_copy(), "u", &value);
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Glib::Error& e) {
|
} catch (Glib::Error& e) {
|
||||||
@ -90,40 +116,46 @@ void SystemdFailedUnits::updateData() {
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (system_proxy) {
|
nr_failed_system = load("systemwide", system_proxy);
|
||||||
nr_failed_system = load("systemwide", system_proxy);
|
nr_failed_user = load("user", user_proxy);
|
||||||
}
|
nr_failed = nr_failed_system + nr_failed_user;
|
||||||
if (user_proxy) {
|
}
|
||||||
nr_failed_user = load("user", user_proxy);
|
|
||||||
}
|
void SystemdFailedUnits::updateData() {
|
||||||
|
update_pending = false;
|
||||||
|
|
||||||
|
RequestSystemState();
|
||||||
|
if (overall_state == "degraded") RequestFailedUnits();
|
||||||
|
|
||||||
dp.emit();
|
dp.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SystemdFailedUnits::update() -> void {
|
auto SystemdFailedUnits::update() -> void {
|
||||||
uint32_t nr_failed = nr_failed_system + nr_failed_user;
|
if (last_status == overall_state) return;
|
||||||
|
|
||||||
// Hide if needed.
|
// Hide if needed.
|
||||||
if (nr_failed == 0 && hide_on_ok) {
|
if (overall_state == "ok" && hide_on_ok) {
|
||||||
event_box_.set_visible(false);
|
event_box_.set_visible(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!event_box_.get_visible()) {
|
|
||||||
event_box_.set_visible(true);
|
event_box_.set_visible(true);
|
||||||
}
|
|
||||||
|
|
||||||
// Set state class.
|
// Set state class.
|
||||||
const std::string status = nr_failed == 0 ? "ok" : "degraded";
|
|
||||||
if (!last_status.empty() && label_.get_style_context()->has_class(last_status)) {
|
if (!last_status.empty() && label_.get_style_context()->has_class(last_status)) {
|
||||||
label_.get_style_context()->remove_class(last_status);
|
label_.get_style_context()->remove_class(last_status);
|
||||||
}
|
}
|
||||||
if (!label_.get_style_context()->has_class(status)) {
|
if (!label_.get_style_context()->has_class(overall_state)) {
|
||||||
label_.get_style_context()->add_class(status);
|
label_.get_style_context()->add_class(overall_state);
|
||||||
}
|
}
|
||||||
last_status = status;
|
|
||||||
|
last_status = overall_state;
|
||||||
|
|
||||||
label_.set_markup(fmt::format(
|
label_.set_markup(fmt::format(
|
||||||
fmt::runtime(nr_failed == 0 ? format_ok : format_), fmt::arg("nr_failed", nr_failed),
|
fmt::runtime(nr_failed == 0 ? format_ok : format_), fmt::arg("nr_failed", nr_failed),
|
||||||
fmt::arg("nr_failed_system", nr_failed_system), fmt::arg("nr_failed_user", nr_failed_user)));
|
fmt::arg("nr_failed_system", nr_failed_system), fmt::arg("nr_failed_user", nr_failed_user),
|
||||||
|
fmt::arg("system_state", system_state), fmt::arg("user_state", user_state),
|
||||||
|
fmt::arg("overall_state", overall_state)));
|
||||||
ALabel::update();
|
ALabel::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ waybar::modules::Temperature::Temperature(const std::string& id, const Json::Val
|
|||||||
file_path_ = fmt::format("/sys/class/thermal/thermal_zone{}/temp", zone);
|
file_path_ = fmt::format("/sys/class/thermal/thermal_zone{}/temp", zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if file_path_ can be used to retrive the temperature
|
// check if file_path_ can be used to retrieve the temperature
|
||||||
std::ifstream temp(file_path_);
|
std::ifstream temp(file_path_);
|
||||||
if (!temp.is_open()) {
|
if (!temp.is_open()) {
|
||||||
throw std::runtime_error("Can't open " + file_path_);
|
throw std::runtime_error("Can't open " + file_path_);
|
||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -358,10 +358,12 @@ void UPower::resetDevices() {
|
|||||||
void UPower::setDisplayDevice() {
|
void UPower::setDisplayDevice() {
|
||||||
std::lock_guard<std::mutex> guard{mutex_};
|
std::lock_guard<std::mutex> guard{mutex_};
|
||||||
|
|
||||||
if (nativePath_.empty() && model_.empty()) {
|
if (upDevice_.upDevice != NULL) {
|
||||||
// Unref current upDevice
|
g_object_unref(upDevice_.upDevice);
|
||||||
if (upDevice_.upDevice != NULL) g_object_unref(upDevice_.upDevice);
|
upDevice_.upDevice = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nativePath_.empty() && model_.empty()) {
|
||||||
upDevice_.upDevice = up_client_get_display_device(upClient_);
|
upDevice_.upDevice = up_client_get_display_device(upClient_);
|
||||||
getUpDeviceInfo(upDevice_);
|
getUpDeviceInfo(upDevice_);
|
||||||
} else {
|
} else {
|
||||||
@ -386,7 +388,6 @@ void UPower::setDisplayDevice() {
|
|||||||
}
|
}
|
||||||
// Unref current upDevice if it exists
|
// Unref current upDevice if it exists
|
||||||
if (displayDevice.upDevice != NULL) {
|
if (displayDevice.upDevice != NULL) {
|
||||||
if (thisPtr->upDevice_.upDevice != NULL) g_object_unref(thisPtr->upDevice_.upDevice);
|
|
||||||
thisPtr->upDevice_ = displayDevice;
|
thisPtr->upDevice_ = displayDevice;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user