Merge remote-tracking branch 'upstream/master'
This commit is contained in:
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
@ -14,14 +14,14 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Test in FreeBSD VM
|
- name: Test in FreeBSD VM
|
||||||
uses: cross-platform-actions/action@v0.25.0
|
uses: cross-platform-actions/action@v0.28.0
|
||||||
timeout-minutes: 180
|
timeout-minutes: 180
|
||||||
env:
|
env:
|
||||||
CPPFLAGS: '-isystem/usr/local/include'
|
CPPFLAGS: '-isystem/usr/local/include'
|
||||||
LDFLAGS: '-L/usr/local/lib'
|
LDFLAGS: '-L/usr/local/lib'
|
||||||
with:
|
with:
|
||||||
operating_system: freebsd
|
operating_system: freebsd
|
||||||
version: "14.1"
|
version: "14.2"
|
||||||
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
|
||||||
|
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": 1745391562,
|
"lastModified": 1751011381,
|
||||||
"narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=",
|
"narHash": "sha256-krGXKxvkBhnrSC/kGBmg5MyupUUT5R6IBCLEzx9jhMM=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7",
|
"rev": "30e2e2857ba47844aa71991daa6ed1fc678bcbb7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -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_;
|
||||||
|
@ -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, const time_zone* tz)
|
auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd,
|
||||||
-> 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();
|
||||||
|
40
include/modules/gps.hpp
Normal file
40
include/modules/gps.hpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
|
||||||
|
#ifdef WANT_RFKILL
|
||||||
|
#include "util/rfkill.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <gps.h>
|
||||||
|
|
||||||
|
#include "ALabel.hpp"
|
||||||
|
#include "util/sleeper_thread.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules {
|
||||||
|
|
||||||
|
class Gps : public ALabel {
|
||||||
|
public:
|
||||||
|
Gps(const std::string&, const Json::Value&);
|
||||||
|
virtual ~Gps();
|
||||||
|
auto update() -> void override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef WANT_RFKILL
|
||||||
|
util::Rfkill rfkill_;
|
||||||
|
#endif
|
||||||
|
const std::string getFixModeName() const;
|
||||||
|
const std::string getFixModeString() const;
|
||||||
|
|
||||||
|
const std::string getFixStatusString() const;
|
||||||
|
|
||||||
|
util::SleeperThread thread_, gps_thread_;
|
||||||
|
gps_data_t gps_data_;
|
||||||
|
std::string state_;
|
||||||
|
|
||||||
|
bool hideDisconnected = true;
|
||||||
|
bool hideNoFix = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules
|
@ -46,4 +46,5 @@ class IPC {
|
|||||||
};
|
};
|
||||||
|
|
||||||
inline bool modulesReady = false;
|
inline bool modulesReady = false;
|
||||||
|
inline std::unique_ptr<IPC> gIPC;
|
||||||
}; // namespace waybar::modules::hyprland
|
}; // namespace waybar::modules::hyprland
|
||||||
|
41
include/modules/hyprland/windowcount.hpp
Normal file
41
include/modules/hyprland/windowcount.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "AAppIconLabel.hpp"
|
||||||
|
#include "bar.hpp"
|
||||||
|
#include "modules/hyprland/backend.hpp"
|
||||||
|
#include "util/json.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::hyprland {
|
||||||
|
|
||||||
|
class WindowCount : public waybar::AAppIconLabel, public EventHandler {
|
||||||
|
public:
|
||||||
|
WindowCount(const std::string&, const waybar::Bar&, const Json::Value&);
|
||||||
|
~WindowCount() override;
|
||||||
|
|
||||||
|
auto update() -> void override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Workspace {
|
||||||
|
int id;
|
||||||
|
int windows;
|
||||||
|
bool hasfullscreen;
|
||||||
|
static auto parse(const Json::Value& value) -> Workspace;
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto getActiveWorkspace(const std::string&) -> Workspace;
|
||||||
|
static auto getActiveWorkspace() -> Workspace;
|
||||||
|
void onEvent(const std::string& ev) override;
|
||||||
|
void queryActiveWorkspace();
|
||||||
|
void setClass(const std::string&, bool enable);
|
||||||
|
|
||||||
|
bool separateOutputs_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
const Bar& bar_;
|
||||||
|
Workspace workspace_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::hyprland
|
@ -55,7 +55,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();
|
||||||
|
@ -58,11 +58,11 @@ class Workspace {
|
|||||||
return std::ranges::any_of(m_windowMap,
|
return std::ranges::any_of(m_windowMap,
|
||||||
[&addr](const auto& window) { return window.address == addr; });
|
[&addr](const auto& window) { return window.address == addr; });
|
||||||
};
|
};
|
||||||
void insertWindow(WindowCreationPayload create_window_paylod);
|
void insertWindow(WindowCreationPayload create_window_payload);
|
||||||
void initializeWindowMap(const Json::Value& clients_data);
|
void initializeWindowMap(const Json::Value& clients_data);
|
||||||
void setActiveWindow(WindowAddress const& addr);
|
void setActiveWindow(WindowAddress const& addr);
|
||||||
|
|
||||||
bool onWindowOpened(WindowCreationPayload const& create_window_paylod);
|
bool onWindowOpened(WindowCreationPayload const& create_window_payload);
|
||||||
std::optional<WindowRepr> closeWindow(WindowAddress const& addr);
|
std::optional<WindowRepr> closeWindow(WindowAddress const& addr);
|
||||||
|
|
||||||
void update(const std::string& workspace_icon);
|
void update(const std::string& workspace_icon);
|
||||||
|
@ -39,6 +39,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 enableTaskbar() const -> bool { return m_enableTaskbar; }
|
auto enableTaskbar() const -> bool { return m_enableTaskbar; }
|
||||||
auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; }
|
auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; }
|
||||||
@ -63,6 +64,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
private:
|
private:
|
||||||
void onEvent(const std::string& e) override;
|
void onEvent(const std::string& e) override;
|
||||||
void updateWindowCount();
|
void updateWindowCount();
|
||||||
|
void sortSpecialCentered();
|
||||||
void sortWorkspaces();
|
void sortWorkspaces();
|
||||||
void createWorkspace(Json::Value const& workspace_data,
|
void createWorkspace(Json::Value const& workspace_data,
|
||||||
Json::Value const& clients_data = Json::Value::nullRef);
|
Json::Value const& clients_data = Json::Value::nullRef);
|
||||||
@ -137,20 +139,22 @@ 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, WindowRepr, std::less<>> m_orphanWindowMap;
|
std::map<WindowAddress, WindowRepr, std::less<>> m_orphanWindowMap;
|
||||||
|
|
||||||
enum class SortMethod { ID, NAME, NUMBER, DEFAULT };
|
enum class SortMethod { ID, NAME, NUMBER, SPECIAL_CENTERED, DEFAULT };
|
||||||
util::EnumParser<SortMethod> m_enumParser;
|
util::EnumParser<SortMethod> m_enumParser;
|
||||||
SortMethod m_sortBy = SortMethod::DEFAULT;
|
SortMethod m_sortBy = SortMethod::DEFAULT;
|
||||||
std::map<std::string, SortMethod> m_sortMap = {{"ID", SortMethod::ID},
|
std::map<std::string, SortMethod> m_sortMap = {{"ID", SortMethod::ID},
|
||||||
{"NAME", SortMethod::NAME},
|
{"NAME", SortMethod::NAME},
|
||||||
{"NUMBER", SortMethod::NUMBER},
|
{"NUMBER", SortMethod::NUMBER},
|
||||||
|
{"SPECIAL-CENTERED", SortMethod::SPECIAL_CENTERED},
|
||||||
{"DEFAULT", SortMethod::DEFAULT}};
|
{"DEFAULT", SortMethod::DEFAULT}};
|
||||||
|
|
||||||
std::string m_formatBefore;
|
std::string m_formatBefore;
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
122
include/modules/wayfire/backend.hpp
Normal file
122
include/modules/wayfire/backend.hpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <json/json.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace waybar::modules::wayfire {
|
||||||
|
|
||||||
|
using EventHandler = std::function<void(const std::string& event)>;
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
/*
|
||||||
|
┌───────────┐ ┌───────────┐
|
||||||
|
│ output #1 │ │ output #2 │
|
||||||
|
└─────┬─────┘ └─────┬─────┘
|
||||||
|
└─┐ └─────┐─ ─ ─ ─ ─ ─ ─ ─ ┐
|
||||||
|
┌───────┴───────┐ ┌───────┴──────┐ ┌───────┴───────┐
|
||||||
|
│ wset #1 │ │ wset #2 │ │ wset #3 │
|
||||||
|
│┌────────────┐ │ │┌────────────┐│ │┌────────────┐ │
|
||||||
|
││ workspaces │ │ ││ workspaces ││ ││ workspaces │ │
|
||||||
|
│└─┬──────────┘ │ │└────────────┘│ │└─┬──────────┘ │
|
||||||
|
│ │ ┌─────────┐│ └──────────────┘ │ │ ┌─────────┐│
|
||||||
|
│ ├─┤ view #1 ││ │ └─┤ view #3 ││
|
||||||
|
│ │ └─────────┘│ │ └─────────┘│
|
||||||
|
│ │ ┌─────────┐│ └───────────────┘
|
||||||
|
│ └─┤ view #2 ││
|
||||||
|
│ └─────────┘│
|
||||||
|
└───────────────┘
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct Output {
|
||||||
|
size_t id;
|
||||||
|
size_t w, h;
|
||||||
|
size_t wset_idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Workspace {
|
||||||
|
size_t num_views;
|
||||||
|
size_t num_sticky_views;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Wset {
|
||||||
|
std::optional<std::reference_wrapper<Output>> output;
|
||||||
|
std::vector<Workspace> wss;
|
||||||
|
size_t ws_w, ws_h, ws_x, ws_y;
|
||||||
|
size_t focused_view_id;
|
||||||
|
|
||||||
|
auto ws_idx() const { return ws_w * ws_y + ws_x; }
|
||||||
|
auto count_ws(const Json::Value& pos) -> Workspace&;
|
||||||
|
auto locate_ws(const Json::Value& geo) -> Workspace&;
|
||||||
|
auto locate_ws(const Json::Value& geo) const -> const Workspace&;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, Output> outputs;
|
||||||
|
std::unordered_map<size_t, Wset> wsets;
|
||||||
|
std::unordered_map<size_t, Json::Value> views;
|
||||||
|
std::string focused_output_name;
|
||||||
|
size_t maybe_empty_focus_wset_idx = {};
|
||||||
|
size_t vswitch_sticky_view_id = {};
|
||||||
|
bool new_output_detected = {};
|
||||||
|
bool vswitching = {};
|
||||||
|
|
||||||
|
auto update_view(const Json::Value& view) -> void;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sock {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
Sock(int fd) : fd{fd} {}
|
||||||
|
~Sock() { close(fd); }
|
||||||
|
Sock(const Sock&) = delete;
|
||||||
|
auto operator=(const Sock&) = delete;
|
||||||
|
Sock(Sock&& rhs) noexcept {
|
||||||
|
fd = rhs.fd;
|
||||||
|
rhs.fd = -1;
|
||||||
|
}
|
||||||
|
auto& operator=(Sock&& rhs) noexcept {
|
||||||
|
fd = rhs.fd;
|
||||||
|
rhs.fd = -1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class IPC {
|
||||||
|
static std::weak_ptr<IPC> instance;
|
||||||
|
Json::CharReaderBuilder reader_builder;
|
||||||
|
Json::StreamWriterBuilder writer_builder;
|
||||||
|
std::list<std::pair<std::string, std::reference_wrapper<const EventHandler>>> handlers;
|
||||||
|
std::mutex handlers_mutex;
|
||||||
|
State state;
|
||||||
|
std::mutex state_mutex;
|
||||||
|
|
||||||
|
IPC() { start(); }
|
||||||
|
|
||||||
|
static auto connect() -> Sock;
|
||||||
|
auto receive(Sock& sock) -> Json::Value;
|
||||||
|
auto start() -> void;
|
||||||
|
auto root_event_handler(const std::string& event, const Json::Value& data) -> void;
|
||||||
|
auto update_state_handler(const std::string& event, const Json::Value& data) -> void;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static auto get_instance() -> std::shared_ptr<IPC>;
|
||||||
|
auto send(const std::string& method, Json::Value&& data) -> Json::Value;
|
||||||
|
auto register_handler(const std::string& event, const EventHandler& handler) -> void;
|
||||||
|
auto unregister_handler(EventHandler& handler) -> void;
|
||||||
|
|
||||||
|
auto lock_state() -> std::lock_guard<std::mutex> { return std::lock_guard{state_mutex}; }
|
||||||
|
auto& get_outputs() const { return state.outputs; }
|
||||||
|
auto& get_wsets() const { return state.wsets; }
|
||||||
|
auto& get_views() const { return state.views; }
|
||||||
|
auto& get_focused_output_name() const { return state.focused_output_name; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::wayfire
|
24
include/modules/wayfire/window.hpp
Normal file
24
include/modules/wayfire/window.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AAppIconLabel.hpp"
|
||||||
|
#include "bar.hpp"
|
||||||
|
#include "modules/wayfire/backend.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::wayfire {
|
||||||
|
|
||||||
|
class Window : public AAppIconLabel {
|
||||||
|
std::shared_ptr<IPC> ipc;
|
||||||
|
EventHandler handler;
|
||||||
|
|
||||||
|
const Bar& bar_;
|
||||||
|
std::string old_app_id_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Window(const std::string& id, const Bar& bar, const Json::Value& config);
|
||||||
|
~Window() override;
|
||||||
|
|
||||||
|
auto update() -> void override;
|
||||||
|
auto update_icon_label() -> void;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::wayfire
|
32
include/modules/wayfire/workspaces.hpp
Normal file
32
include/modules/wayfire/workspaces.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtkmm/button.h>
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "AModule.hpp"
|
||||||
|
#include "bar.hpp"
|
||||||
|
#include "modules/wayfire/backend.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::wayfire {
|
||||||
|
|
||||||
|
class Workspaces : public AModule {
|
||||||
|
std::shared_ptr<IPC> ipc;
|
||||||
|
EventHandler handler;
|
||||||
|
|
||||||
|
const Bar& bar_;
|
||||||
|
Gtk::Box box_;
|
||||||
|
std::vector<Gtk::Button> buttons_;
|
||||||
|
|
||||||
|
auto handleScroll(GdkEventScroll* e) -> bool override;
|
||||||
|
auto update() -> void override;
|
||||||
|
auto update_box() -> void;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Workspaces(const std::string& id, const Bar& bar, const Json::Value& config);
|
||||||
|
~Workspaces() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::wayfire
|
@ -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
|
||||||
|
111
man/waybar-gps.5.scd
Normal file
111
man/waybar-gps.5.scd
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
waybar-gps(5) "waybar-gps" "User Manual"
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
|
||||||
|
waybar - gps module
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
*gps* module for gpsd.
|
||||||
|
|
||||||
|
|
||||||
|
# FILES
|
||||||
|
|
||||||
|
$XDG_CONFIG_HOME/waybar/config ++
|
||||||
|
Per user configuration file
|
||||||
|
|
||||||
|
# ADDITIONAL FILES
|
||||||
|
|
||||||
|
libgps lives in:
|
||||||
|
|
||||||
|
. /usr/lib/libgps.so or /usr/lib64/libgps.so
|
||||||
|
. /usr/lib/pkgconfig/libgps.pc or /usr/lib64/pkgconfig/libgps.pc
|
||||||
|
. /usr/include/gps
|
||||||
|
|
||||||
|
# CONFIGURATION
|
||||||
|
|
||||||
|
*format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: {glyph} ++
|
||||||
|
The text format.
|
||||||
|
|
||||||
|
*tooltip*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
Option to disable tooltip on hover.
|
||||||
|
|
||||||
|
*tooltip-format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: Games running: {glyph} ++
|
||||||
|
The text format of the tooltip.
|
||||||
|
|
||||||
|
*interval*: ++
|
||||||
|
typeof: integer ++
|
||||||
|
default: 5 ++
|
||||||
|
The interval in which the GPS information gets polled (e.g. current speed).
|
||||||
|
Significant updates (e.g. the current fix mode) are updated immediately.
|
||||||
|
|
||||||
|
*hide-disconnected*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
Defines if the module should be hidden if there is no GPS receiver.
|
||||||
|
|
||||||
|
*hide-no-fix*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Defines if the module should be hidden if there is no GPS fix.
|
||||||
|
|
||||||
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
|
*{mode}*: Fix mode
|
||||||
|
|
||||||
|
*{status}*: Technology used for GPS fix. Not all GPS receivers report this.
|
||||||
|
|
||||||
|
*{latitude}*: Latitude, decimal degrees. Can be NaN.
|
||||||
|
|
||||||
|
*{latitude_error}*: Latitude uncertainty, meters. Can be NaN.
|
||||||
|
|
||||||
|
*{longitude}*: Longitude, decimal degrees. Can be NaN.
|
||||||
|
|
||||||
|
*{longitude_error}*: Longitude uncertainty, meters. Can be NaN.
|
||||||
|
|
||||||
|
*{altitude_hae}*: Altitude, height above ellipsoid, meters. Can be NaN.
|
||||||
|
|
||||||
|
*{altitude_msl}*: Longitude, MSL, meters. Can be NaN.
|
||||||
|
|
||||||
|
*{altitude_error}*: Altitude uncertainty, meters. Can be NaN.
|
||||||
|
|
||||||
|
*{speed}*: Speed over ground, meters/sec. Can be NaN.
|
||||||
|
|
||||||
|
*{speed_error}*: Speed uncertainty, meters/sec. Can be NaN.
|
||||||
|
|
||||||
|
*{climb}*: Vertical speed, meters/sec. Can be NaN.
|
||||||
|
|
||||||
|
*{climb_error}*: Vertical speed uncertainty, meters/sec. Can be NaN.
|
||||||
|
|
||||||
|
*{satellites_visible}*: Number of satellites visible from the GPS receiver.
|
||||||
|
|
||||||
|
*{satellites_used}*: Number of satellites used for the GPS fix.
|
||||||
|
|
||||||
|
# EXAMPLES
|
||||||
|
|
||||||
|
```
|
||||||
|
"gps": {
|
||||||
|
"format": "{mode}",
|
||||||
|
"format-disabled": "", // an empty format will hide the module
|
||||||
|
"format-no-fix": "No fix",
|
||||||
|
"format-fix-3d": "{status}",
|
||||||
|
"tooltip-format": "{mode}",
|
||||||
|
"tooltip-format-no-fix": "{satellites_visible} satellites visible",
|
||||||
|
"tooltip-format-fix-2d": "{satellites_used}/{satellites_visible} satellites used",
|
||||||
|
"tooltip-format-fix-3d": "Altitude: {altitude_hae}m",
|
||||||
|
"hide-disconnected": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
# STYLE
|
||||||
|
|
||||||
|
- *#gps*
|
||||||
|
- *#gps.disabled* Applied when GPS is disabled.
|
||||||
|
- *#gps.fix-none* Applied when GPS is present, but there is no fix.
|
||||||
|
- *#gps.fix-2d* Applied when there is a 2D fix.
|
||||||
|
- *#gps.fix-3d* Applied when there is a 3D fix.
|
46
man/waybar-hyprland-windowcount.5.scd
Normal file
46
man/waybar-hyprland-windowcount.5.scd
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
waybar-hyprland-windowcount(5)
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
|
||||||
|
waybar - hyprland window count module
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
The *windowcount* module displays the number of windows in the current Hyprland workspace.
|
||||||
|
|
||||||
|
# CONFIGURATION
|
||||||
|
|
||||||
|
Addressed by *hyprland/windowcount*
|
||||||
|
|
||||||
|
*format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: {} ++
|
||||||
|
The format for how information should be displayed. On {} the current workspace window count is displayed.
|
||||||
|
|
||||||
|
*format-empty*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Override the format when the workspace contains no windows window
|
||||||
|
|
||||||
|
*format-windowed*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Override the format when the workspace contains no fullscreen windows
|
||||||
|
|
||||||
|
*format-fullscreen*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Override the format when the workspace contains a fullscreen window
|
||||||
|
|
||||||
|
*separate-outputs*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
Show the active workspace window count of the monitor the bar belongs to, instead of the focused workspace.
|
||||||
|
|
||||||
|
# STYLE
|
||||||
|
|
||||||
|
- *#windowcount*
|
||||||
|
|
||||||
|
The following classes are applied to the entire Waybar rather than just the
|
||||||
|
windowcount widget:
|
||||||
|
|
||||||
|
- *window#waybar.empty* When no windows are in the workspace
|
||||||
|
- *window#waybar.fullscreen* When there is a fullscreen window in the workspace;
|
||||||
|
useful with Hyprland's *fullscreen, 1* mode
|
@ -80,6 +80,11 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
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 ++
|
||||||
@ -108,6 +113,7 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
If set to number, workspaces will sort by number.
|
If set to number, workspaces will sort by number.
|
||||||
If set to name, workspaces will sort by name.
|
If set to name, workspaces will sort by name.
|
||||||
If set to id, workspaces will sort by id.
|
If set to id, workspaces will sort by id.
|
||||||
|
If set to special-centered, workspaces will sort by default with special workspaces in the center.
|
||||||
If none of those, workspaces will sort with default behavior.
|
If none of those, workspaces will sort with default behavior.
|
||||||
|
|
||||||
*expand*: ++
|
*expand*: ++
|
||||||
|
@ -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
|
||||||
|
@ -171,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,8 @@ 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.
|
||||||
|
- *urgent*: Will be shown, when workspace has urgent windows.
|
||||||
|
- *empty*: Will be shown, when workspace is empty.
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
@ -95,6 +97,7 @@ Additional to workspace name matching, the following *format-icons* can be set.
|
|||||||
- *#workspaces button*
|
- *#workspaces button*
|
||||||
- *#workspaces button.focused*: The single focused workspace.
|
- *#workspaces button.focused*: The single focused workspace.
|
||||||
- *#workspaces button.active*: The workspace is active (visible) on its output.
|
- *#workspaces button.active*: The workspace is active (visible) on its output.
|
||||||
|
- *#workspaces button.urgent*: The workspace has one or more urgent windows.
|
||||||
- *#workspaces button.empty*: The workspace is empty.
|
- *#workspaces button.empty*: The workspace is empty.
|
||||||
- *#workspaces button.current_output*: The workspace is from the same output as
|
- *#workspaces button.current_output*: The workspace is from the same output as
|
||||||
the bar that it is displayed on.
|
the bar that it is displayed on.
|
||||||
|
@ -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"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
```
|
```
|
||||||
|
@ -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
|
||||||
|
|
||||||
```
|
```
|
||||||
|
82
man/waybar-wayfire-window.5.scd
Normal file
82
man/waybar-wayfire-window.5.scd
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
waybar-wayfire-window(5)
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
|
||||||
|
waybar - wayfire window module
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
The *window* module displays the title of the currently focused window in wayfire.
|
||||||
|
|
||||||
|
# CONFIGURATION
|
||||||
|
|
||||||
|
Addressed by *wayfire/window*
|
||||||
|
|
||||||
|
*format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: {title} ++
|
||||||
|
The format, how information should be displayed. On {} the current window title is displayed.
|
||||||
|
|
||||||
|
*rewrite*: ++
|
||||||
|
typeof: object ++
|
||||||
|
Rules to rewrite window title. See *rewrite rules*.
|
||||||
|
|
||||||
|
*icon*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Option to hide the application icon.
|
||||||
|
|
||||||
|
*icon-size*: ++
|
||||||
|
typeof: integer ++
|
||||||
|
default: 24 ++
|
||||||
|
Option to change the size of the application icon.
|
||||||
|
|
||||||
|
*expand*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Enables this module to consume all left over space dynamically.
|
||||||
|
|
||||||
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
|
See the output of "wayfire msg windows" for examples
|
||||||
|
|
||||||
|
*{title}*: The current title of the focused window.
|
||||||
|
|
||||||
|
*{app_id}*: The current app ID of the focused window.
|
||||||
|
|
||||||
|
# REWRITE RULES
|
||||||
|
|
||||||
|
*rewrite* is an object where keys are regular expressions and values are
|
||||||
|
rewrite rules if the expression matches. Rules may contain references to
|
||||||
|
captures of the expression.
|
||||||
|
|
||||||
|
Regular expression and replacement follow ECMA-script rules.
|
||||||
|
|
||||||
|
If no expression matches, the title is left unchanged.
|
||||||
|
|
||||||
|
Invalid expressions (e.g., mismatched parentheses) are skipped.
|
||||||
|
|
||||||
|
# EXAMPLES
|
||||||
|
|
||||||
|
```
|
||||||
|
"wayfire/window": {
|
||||||
|
"format": "{}",
|
||||||
|
"rewrite": {
|
||||||
|
"(.*) - Mozilla Firefox": "🌎 $1",
|
||||||
|
"(.*) - zsh": "> [$1]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# STYLE
|
||||||
|
|
||||||
|
- *#window*
|
||||||
|
- *window#waybar.empty #window* When no windows are on the workspace
|
||||||
|
|
||||||
|
The following classes are applied to the entire Waybar rather than just the
|
||||||
|
window widget:
|
||||||
|
|
||||||
|
- *window#waybar.empty* When no windows are in the workspace
|
||||||
|
- *window#waybar.solo* When only one window is on the workspace
|
||||||
|
- *window#waybar.<app-id>* Where *app-id* is the app ID of the only window on
|
||||||
|
the workspace
|
86
man/waybar-wayfire-workspaces.5.scd
Normal file
86
man/waybar-wayfire-workspaces.5.scd
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
waybar-wayfire-workspaces(5)
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
|
||||||
|
waybar - wayfire workspaces module
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
The *workspaces* module displays the currently used workspaces in wayfire.
|
||||||
|
|
||||||
|
# CONFIGURATION
|
||||||
|
|
||||||
|
Addressed by *wayfire/workspaces*
|
||||||
|
|
||||||
|
*format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: {value} ++
|
||||||
|
The format, how information should be displayed.
|
||||||
|
|
||||||
|
*format-icons*: ++
|
||||||
|
typeof: array ++
|
||||||
|
Based on the workspace name, index and state, the corresponding icon gets selected. See *icons*.
|
||||||
|
|
||||||
|
*disable-click*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
If set to false, you can click to change workspace. If set to true this behaviour is disabled.
|
||||||
|
|
||||||
|
*disable-markup*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
If set to true, button label will escape pango markup.
|
||||||
|
|
||||||
|
*current-only*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
If set to true, only the active or focused workspace will be shown.
|
||||||
|
|
||||||
|
*on-update*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when the module is updated.
|
||||||
|
|
||||||
|
*expand*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Enables this module to consume all left over space dynamically.
|
||||||
|
|
||||||
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
|
*{icon}*: Icon, as defined in *format-icons*.
|
||||||
|
|
||||||
|
*{index}*: Index of the workspace on its output.
|
||||||
|
|
||||||
|
*{output}*: Output where the workspace is located.
|
||||||
|
|
||||||
|
# ICONS
|
||||||
|
|
||||||
|
Additional to workspace name matching, the following *format-icons* can be set.
|
||||||
|
|
||||||
|
- *default*: Will be shown, when no string matches are found.
|
||||||
|
- *focused*: Will be shown, when workspace is focused.
|
||||||
|
|
||||||
|
# EXAMPLES
|
||||||
|
|
||||||
|
```
|
||||||
|
"wayfire/workspaces": {
|
||||||
|
"format": "{icon}",
|
||||||
|
"format-icons": {
|
||||||
|
"1": "",
|
||||||
|
"2": "",
|
||||||
|
"3": "",
|
||||||
|
"4": "",
|
||||||
|
"5": "",
|
||||||
|
"focused": "",
|
||||||
|
"default": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Style
|
||||||
|
|
||||||
|
- *#workspaces button*
|
||||||
|
- *#workspaces button.focused*: The single focused workspace.
|
||||||
|
- *#workspaces button.empty*: The workspace is empty.
|
||||||
|
- *#workspaces button.current_output*: The workspace is from the same output as
|
||||||
|
the bar that it is displayed on.
|
@ -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.
|
||||||
|
22
meson.build
22
meson.build
@ -1,6 +1,6 @@
|
|||||||
project(
|
project(
|
||||||
'waybar', 'cpp', 'c',
|
'waybar', 'cpp', 'c',
|
||||||
version: '0.12.0',
|
version: '0.13.0',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>= 0.59.0',
|
meson_version: '>= 0.59.0',
|
||||||
default_options : [
|
default_options : [
|
||||||
@ -93,6 +93,7 @@ libmpdclient = dependency('libmpdclient', required: get_option('mpd'))
|
|||||||
xkbregistry = dependency('xkbregistry')
|
xkbregistry = dependency('xkbregistry')
|
||||||
libjack = dependency('jack', required: get_option('jack'))
|
libjack = dependency('jack', required: get_option('jack'))
|
||||||
libwireplumber = dependency('wireplumber-0.5', required: get_option('wireplumber'))
|
libwireplumber = dependency('wireplumber-0.5', required: get_option('wireplumber'))
|
||||||
|
libgps = dependency('libgps', required: get_option('gps'))
|
||||||
|
|
||||||
libsndio = compiler.find_library('sndio', required: get_option('sndio'))
|
libsndio = compiler.find_library('sndio', required: get_option('sndio'))
|
||||||
if libsndio.found()
|
if libsndio.found()
|
||||||
@ -307,6 +308,7 @@ if true
|
|||||||
'src/modules/hyprland/language.cpp',
|
'src/modules/hyprland/language.cpp',
|
||||||
'src/modules/hyprland/submap.cpp',
|
'src/modules/hyprland/submap.cpp',
|
||||||
'src/modules/hyprland/window.cpp',
|
'src/modules/hyprland/window.cpp',
|
||||||
|
'src/modules/hyprland/windowcount.cpp',
|
||||||
'src/modules/hyprland/workspace.cpp',
|
'src/modules/hyprland/workspace.cpp',
|
||||||
'src/modules/hyprland/workspaces.cpp',
|
'src/modules/hyprland/workspaces.cpp',
|
||||||
'src/modules/hyprland/windowcreationpayload.cpp',
|
'src/modules/hyprland/windowcreationpayload.cpp',
|
||||||
@ -334,6 +336,15 @@ if get_option('niri')
|
|||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if true
|
||||||
|
add_project_arguments('-DHAVE_WAYFIRE', language: 'cpp')
|
||||||
|
src_files += files(
|
||||||
|
'src/modules/wayfire/backend.cpp',
|
||||||
|
'src/modules/wayfire/window.cpp',
|
||||||
|
'src/modules/wayfire/workspaces.cpp',
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
if get_option('login-proxy')
|
if get_option('login-proxy')
|
||||||
add_project_arguments('-DHAVE_LOGIN_PROXY', language: 'cpp')
|
add_project_arguments('-DHAVE_LOGIN_PROXY', language: 'cpp')
|
||||||
endif
|
endif
|
||||||
@ -498,6 +509,12 @@ if cava.found()
|
|||||||
man_files += files('man/waybar-cava.5.scd')
|
man_files += files('man/waybar-cava.5.scd')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if libgps.found()
|
||||||
|
add_project_arguments('-DHAVE_LIBGPS', language: 'cpp')
|
||||||
|
src_files += files('src/modules/gps.cpp')
|
||||||
|
man_files += files('man/waybar-gps.5.scd')
|
||||||
|
endif
|
||||||
|
|
||||||
subdir('protocol')
|
subdir('protocol')
|
||||||
|
|
||||||
app_resources = []
|
app_resources = []
|
||||||
@ -536,7 +553,8 @@ executable(
|
|||||||
libsndio,
|
libsndio,
|
||||||
tz_dep,
|
tz_dep,
|
||||||
xkbregistry,
|
xkbregistry,
|
||||||
cava
|
cava,
|
||||||
|
libgps
|
||||||
],
|
],
|
||||||
include_directories: inc_dirs,
|
include_directories: inc_dirs,
|
||||||
install: true,
|
install: true,
|
||||||
|
@ -21,3 +21,4 @@ option('wireplumber', type: 'feature', value: 'auto', description: 'Enable suppo
|
|||||||
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')
|
option('login-proxy', type: 'boolean', description: 'Enable interfacing with dbus login interface')
|
||||||
|
option('gps', type: 'feature', value: 'auto', description: 'Enable support for gps')
|
||||||
|
@ -30,8 +30,12 @@ in
|
|||||||
# nixpkgs checks version, no need when building locally
|
# nixpkgs checks version, no need when building locally
|
||||||
nativeInstallCheckInputs = [ ];
|
nativeInstallCheckInputs = [ ];
|
||||||
|
|
||||||
buildInputs = (builtins.filter (p: p.pname != "wireplumber") oldAttrs.buildInputs) ++ [
|
buildInputs = (builtins.filter (p:
|
||||||
|
p.pname != "wireplumber" &&
|
||||||
|
p.pname != "gps"
|
||||||
|
) oldAttrs.buildInputs) ++ [
|
||||||
pkgs.wireplumber
|
pkgs.wireplumber
|
||||||
|
pkgs.gpsd
|
||||||
];
|
];
|
||||||
|
|
||||||
postUnpack = ''
|
postUnpack = ''
|
||||||
|
@ -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_);
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "modules/hyprland/language.hpp"
|
#include "modules/hyprland/language.hpp"
|
||||||
#include "modules/hyprland/submap.hpp"
|
#include "modules/hyprland/submap.hpp"
|
||||||
#include "modules/hyprland/window.hpp"
|
#include "modules/hyprland/window.hpp"
|
||||||
|
#include "modules/hyprland/windowcount.hpp"
|
||||||
#include "modules/hyprland/workspaces.hpp"
|
#include "modules/hyprland/workspaces.hpp"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_NIRI
|
#ifdef HAVE_NIRI
|
||||||
@ -41,6 +42,10 @@
|
|||||||
#include "modules/niri/window.hpp"
|
#include "modules/niri/window.hpp"
|
||||||
#include "modules/niri/workspaces.hpp"
|
#include "modules/niri/workspaces.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_WAYFIRE
|
||||||
|
#include "modules/wayfire/window.hpp"
|
||||||
|
#include "modules/wayfire/workspaces.hpp"
|
||||||
|
#endif
|
||||||
#if defined(__FreeBSD__) || defined(__linux__)
|
#if defined(__FreeBSD__) || defined(__linux__)
|
||||||
#include "modules/battery.hpp"
|
#include "modules/battery.hpp"
|
||||||
#endif
|
#endif
|
||||||
@ -109,6 +114,9 @@
|
|||||||
#ifdef HAVE_SYSTEMD_MONITOR
|
#ifdef HAVE_SYSTEMD_MONITOR
|
||||||
#include "modules/systemd_failed_units.hpp"
|
#include "modules/systemd_failed_units.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_LIBGPS
|
||||||
|
#include "modules/gps.hpp"
|
||||||
|
#endif
|
||||||
#include "modules/cffi.hpp"
|
#include "modules/cffi.hpp"
|
||||||
#include "modules/custom.hpp"
|
#include "modules/custom.hpp"
|
||||||
#include "modules/image.hpp"
|
#include "modules/image.hpp"
|
||||||
@ -201,6 +209,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
|
|||||||
if (ref == "hyprland/window") {
|
if (ref == "hyprland/window") {
|
||||||
return new waybar::modules::hyprland::Window(id, bar_, config_[name]);
|
return new waybar::modules::hyprland::Window(id, bar_, config_[name]);
|
||||||
}
|
}
|
||||||
|
if (ref == "hyprland/windowcount") {
|
||||||
|
return new waybar::modules::hyprland::WindowCount(id, bar_, config_[name]);
|
||||||
|
}
|
||||||
if (ref == "hyprland/language") {
|
if (ref == "hyprland/language") {
|
||||||
return new waybar::modules::hyprland::Language(id, bar_, config_[name]);
|
return new waybar::modules::hyprland::Language(id, bar_, config_[name]);
|
||||||
}
|
}
|
||||||
@ -221,6 +232,14 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
|
|||||||
if (ref == "niri/workspaces") {
|
if (ref == "niri/workspaces") {
|
||||||
return new waybar::modules::niri::Workspaces(id, bar_, config_[name]);
|
return new waybar::modules::niri::Workspaces(id, bar_, config_[name]);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_WAYFIRE
|
||||||
|
if (ref == "wayfire/window") {
|
||||||
|
return new waybar::modules::wayfire::Window(id, bar_, config_[name]);
|
||||||
|
}
|
||||||
|
if (ref == "wayfire/workspaces") {
|
||||||
|
return new waybar::modules::wayfire::Workspaces(id, bar_, config_[name]);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (ref == "idle_inhibitor") {
|
if (ref == "idle_inhibitor") {
|
||||||
return new waybar::modules::IdleInhibitor(id, bar_, config_[name]);
|
return new waybar::modules::IdleInhibitor(id, bar_, config_[name]);
|
||||||
@ -331,6 +350,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
|
|||||||
if (ref == "systemd-failed-units") {
|
if (ref == "systemd-failed-units") {
|
||||||
return new waybar::modules::SystemdFailedUnits(id, config_[name]);
|
return new waybar::modules::SystemdFailedUnits(id, config_[name]);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_LIBGPS
|
||||||
|
if (ref == "gps") {
|
||||||
|
return new waybar::modules::Gps(id, config_[name]);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (ref == "temperature") {
|
if (ref == "temperature") {
|
||||||
return new waybar::modules::Temperature(id, config_[name]);
|
return new waybar::modules::Temperature(id, config_[name]);
|
||||||
|
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 {
|
||||||
|
@ -687,8 +687,11 @@ auto waybar::modules::Battery::update() -> void {
|
|||||||
std::string tooltip_text_default;
|
std::string tooltip_text_default;
|
||||||
std::string tooltip_format = "{timeTo}";
|
std::string tooltip_format = "{timeTo}";
|
||||||
if (time_remaining != 0) {
|
if (time_remaining != 0) {
|
||||||
std::string time_to = std::string("Time to ") + ((time_remaining > 0) ? "empty" : "full");
|
if (time_remaining > 0) {
|
||||||
tooltip_text_default = time_to + ": " + time_remaining_formatted;
|
tooltip_text_default = std::string("Empty in ") + time_remaining_formatted;
|
||||||
|
} else {
|
||||||
|
tooltip_text_default = std::string("Full in ") + time_remaining_formatted;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tooltip_text_default = status_pretty;
|
tooltip_text_default = status_pretty;
|
||||||
}
|
}
|
||||||
|
@ -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} {
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
216
src/modules/gps.cpp
Normal file
216
src/modules/gps.cpp
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
#include "modules/gps.hpp"
|
||||||
|
|
||||||
|
#include <gps.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
// In the 80000 version of fmt library authors decided to optimize imports
|
||||||
|
// and moved declarations required for fmt::dynamic_format_arg_store in new
|
||||||
|
// header fmt/args.h
|
||||||
|
#if (FMT_VERSION >= 80000)
|
||||||
|
#include <fmt/args.h>
|
||||||
|
#else
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using namespace waybar::util;
|
||||||
|
constexpr const char* DEFAULT_FORMAT = "{mode}";
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
waybar::modules::Gps::Gps(const std::string& id, const Json::Value& config)
|
||||||
|
: ALabel(config, "gps", id, "{}", 5)
|
||||||
|
#ifdef WANT_RFKILL
|
||||||
|
,
|
||||||
|
rfkill_{RFKILL_TYPE_GPS}
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
thread_ = [this] {
|
||||||
|
dp.emit();
|
||||||
|
thread_.sleep_for(interval_);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (0 != gps_open("localhost", "2947", &gps_data_)) {
|
||||||
|
throw std::runtime_error("Can't open gpsd socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_["hide-disconnected"].isBool()) {
|
||||||
|
hideDisconnected = config_["hide-disconnected"].asBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_["hide-no-fix"].isBool()) {
|
||||||
|
hideNoFix = config_["hide-no-fix"].asBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
gps_thread_ = [this] {
|
||||||
|
dp.emit();
|
||||||
|
gps_stream(&gps_data_, WATCH_ENABLE, NULL);
|
||||||
|
int last_gps_mode = 0;
|
||||||
|
|
||||||
|
while (gps_waiting(&gps_data_, 5000000)) {
|
||||||
|
if (gps_read(&gps_data_, NULL, 0) == -1) {
|
||||||
|
throw std::runtime_error("Can't read data from gpsd.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MODE_SET != (MODE_SET & gps_data_.set)) {
|
||||||
|
// did not even get mode, nothing to see here
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gps_data_.fix.mode != last_gps_mode) {
|
||||||
|
// significant update
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
last_gps_mode = gps_data_.fix.mode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef WANT_RFKILL
|
||||||
|
rfkill_.on_update.connect(sigc::hide(sigc::mem_fun(*this, &Gps::update)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string waybar::modules::Gps::getFixModeName() const {
|
||||||
|
switch (gps_data_.fix.mode) {
|
||||||
|
case MODE_NO_FIX:
|
||||||
|
return "fix-none";
|
||||||
|
case MODE_2D:
|
||||||
|
return "fix-2d";
|
||||||
|
case MODE_3D:
|
||||||
|
return "fix-3d";
|
||||||
|
default:
|
||||||
|
#ifdef WANT_RFKILL
|
||||||
|
if (rfkill_.getState()) return "disabled";
|
||||||
|
#endif
|
||||||
|
return "disconnected";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string waybar::modules::Gps::getFixModeString() const {
|
||||||
|
switch (gps_data_.fix.mode) {
|
||||||
|
case MODE_NO_FIX:
|
||||||
|
return "No fix";
|
||||||
|
case MODE_2D:
|
||||||
|
return "2D Fix";
|
||||||
|
case MODE_3D:
|
||||||
|
return "3D Fix";
|
||||||
|
default:
|
||||||
|
return "Disconnected";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string waybar::modules::Gps::getFixStatusString() const {
|
||||||
|
switch (gps_data_.fix.status) {
|
||||||
|
case STATUS_GPS:
|
||||||
|
return "GPS";
|
||||||
|
case STATUS_DGPS:
|
||||||
|
return "DGPS";
|
||||||
|
case STATUS_RTK_FIX:
|
||||||
|
return "RTK Fixed";
|
||||||
|
case STATUS_RTK_FLT:
|
||||||
|
return "RTK Float";
|
||||||
|
case STATUS_DR:
|
||||||
|
return "Dead Reckoning";
|
||||||
|
case STATUS_GNSSDR:
|
||||||
|
return "GNSS + Dead Reckoning";
|
||||||
|
case STATUS_TIME:
|
||||||
|
return "Time Only";
|
||||||
|
case STATUS_PPS_FIX:
|
||||||
|
return "PPS Fix";
|
||||||
|
default:
|
||||||
|
|
||||||
|
#ifdef WANT_RFKILL
|
||||||
|
if (rfkill_.getState()) return "Disabled";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto waybar::modules::Gps::update() -> void {
|
||||||
|
sleep(0); // Wait for gps status change
|
||||||
|
|
||||||
|
if ((gps_data_.fix.mode == MODE_NOT_SEEN && hideDisconnected) ||
|
||||||
|
(gps_data_.fix.mode == MODE_NO_FIX && hideNoFix)) {
|
||||||
|
event_box_.set_visible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the module
|
||||||
|
if (!event_box_.get_visible()) event_box_.set_visible(true);
|
||||||
|
|
||||||
|
std::string tooltip_format;
|
||||||
|
|
||||||
|
if (!alt_) {
|
||||||
|
auto state = getFixModeName();
|
||||||
|
if (!state_.empty() && label_.get_style_context()->has_class(state_)) {
|
||||||
|
label_.get_style_context()->remove_class(state_);
|
||||||
|
}
|
||||||
|
if (config_["format-" + state].isString()) {
|
||||||
|
default_format_ = config_["format-" + state].asString();
|
||||||
|
} else if (config_["format"].isString()) {
|
||||||
|
default_format_ = config_["format"].asString();
|
||||||
|
} else {
|
||||||
|
default_format_ = DEFAULT_FORMAT;
|
||||||
|
}
|
||||||
|
if (config_["tooltip-format-" + state].isString()) {
|
||||||
|
tooltip_format = config_["tooltip-format-" + state].asString();
|
||||||
|
}
|
||||||
|
if (!label_.get_style_context()->has_class(state)) {
|
||||||
|
label_.get_style_context()->add_class(state);
|
||||||
|
}
|
||||||
|
format_ = default_format_;
|
||||||
|
state_ = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto format = format_;
|
||||||
|
|
||||||
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
|
store.push_back(fmt::arg("mode", getFixModeString()));
|
||||||
|
store.push_back(fmt::arg("status", getFixStatusString()));
|
||||||
|
|
||||||
|
store.push_back(fmt::arg("latitude", gps_data_.fix.latitude));
|
||||||
|
store.push_back(fmt::arg("latitude_error", gps_data_.fix.epy));
|
||||||
|
|
||||||
|
store.push_back(fmt::arg("longitude", gps_data_.fix.longitude));
|
||||||
|
store.push_back(fmt::arg("longitude_error", gps_data_.fix.epx));
|
||||||
|
|
||||||
|
store.push_back(fmt::arg("altitude_hae", gps_data_.fix.altHAE));
|
||||||
|
store.push_back(fmt::arg("altitude_msl", gps_data_.fix.altMSL));
|
||||||
|
store.push_back(fmt::arg("altitude_error", gps_data_.fix.epv));
|
||||||
|
|
||||||
|
store.push_back(fmt::arg("speed", gps_data_.fix.speed));
|
||||||
|
store.push_back(fmt::arg("speed_error", gps_data_.fix.eps));
|
||||||
|
|
||||||
|
store.push_back(fmt::arg("climb", gps_data_.fix.climb));
|
||||||
|
store.push_back(fmt::arg("climb_error", gps_data_.fix.epc));
|
||||||
|
|
||||||
|
store.push_back(fmt::arg("satellites_used", gps_data_.satellites_used));
|
||||||
|
store.push_back(fmt::arg("satellites_visible", gps_data_.satellites_visible));
|
||||||
|
|
||||||
|
auto text = fmt::vformat(format, store);
|
||||||
|
|
||||||
|
if (tooltipEnabled()) {
|
||||||
|
if (tooltip_format.empty() && config_["tooltip-format"].isString()) {
|
||||||
|
tooltip_format = config_["tooltip-format"].asString();
|
||||||
|
}
|
||||||
|
if (!tooltip_format.empty()) {
|
||||||
|
auto tooltip_text = fmt::vformat(tooltip_format, store);
|
||||||
|
if (label_.get_tooltip_text() != tooltip_text) {
|
||||||
|
label_.set_tooltip_markup(tooltip_text);
|
||||||
|
}
|
||||||
|
} else if (label_.get_tooltip_text() != text) {
|
||||||
|
label_.set_tooltip_markup(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
label_.set_markup(text);
|
||||||
|
// Call parent update
|
||||||
|
ALabel::update();
|
||||||
|
}
|
||||||
|
|
||||||
|
waybar::modules::Gps::~Gps() {
|
||||||
|
gps_stream(&gps_data_, WATCH_DISABLE, NULL);
|
||||||
|
gps_close(&gps_data_);
|
||||||
|
}
|
@ -66,7 +66,18 @@ auto Language::update() -> void {
|
|||||||
void Language::onEvent(const std::string& ev) {
|
void Language::onEvent(const std::string& ev) {
|
||||||
std::lock_guard<std::mutex> lg(mutex_);
|
std::lock_guard<std::mutex> lg(mutex_);
|
||||||
std::string kbName(begin(ev) + ev.find_last_of('>') + 1, begin(ev) + ev.find_first_of(','));
|
std::string kbName(begin(ev) + ev.find_last_of('>') + 1, begin(ev) + ev.find_first_of(','));
|
||||||
auto layoutName = ev.substr(ev.find_last_of(',') + 1);
|
|
||||||
|
// Last comma before variants parenthesis, eg:
|
||||||
|
// activelayout>>micro-star-int'l-co.,-ltd.-msi-gk50-elite-gaming-keyboard,English (US, intl.,
|
||||||
|
// with dead keys)
|
||||||
|
std::string beforeParenthesis;
|
||||||
|
auto parenthesisPos = ev.find_last_of('(');
|
||||||
|
if (parenthesisPos == std::string::npos) {
|
||||||
|
beforeParenthesis = ev;
|
||||||
|
} else {
|
||||||
|
beforeParenthesis = std::string(begin(ev), begin(ev) + parenthesisPos);
|
||||||
|
}
|
||||||
|
auto layoutName = ev.substr(beforeParenthesis.find_last_of(',') + 1);
|
||||||
|
|
||||||
if (config_.isMember("keyboard-name") && kbName != config_["keyboard-name"].asString())
|
if (config_.isMember("keyboard-name") && kbName != config_["keyboard-name"].asString())
|
||||||
return; // ignore
|
return; // ignore
|
||||||
|
@ -16,7 +16,7 @@ Submap::Submap(const std::string& id, const Bar& bar, const Json::Value& config)
|
|||||||
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_);
|
||||||
@ -68,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_);
|
||||||
|
142
src/modules/hyprland/windowcount.cpp
Normal file
142
src/modules/hyprland/windowcount.cpp
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#include "modules/hyprland/windowcount.hpp"
|
||||||
|
|
||||||
|
#include <glibmm/fileutils.h>
|
||||||
|
#include <glibmm/keyfile.h>
|
||||||
|
#include <glibmm/miscutils.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "modules/hyprland/backend.hpp"
|
||||||
|
#include "util/sanitize_str.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::hyprland {
|
||||||
|
|
||||||
|
WindowCount::WindowCount(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||||
|
: AAppIconLabel(config, "windowcount", id, "{count}", 0, true), bar_(bar) {
|
||||||
|
modulesReady = true;
|
||||||
|
separateOutputs_ =
|
||||||
|
config.isMember("separate-outputs") ? config["separate-outputs"].asBool() : true;
|
||||||
|
|
||||||
|
if (!gIPC) {
|
||||||
|
gIPC = std::make_unique<IPC>();
|
||||||
|
}
|
||||||
|
|
||||||
|
queryActiveWorkspace();
|
||||||
|
update();
|
||||||
|
dp.emit();
|
||||||
|
|
||||||
|
// register for hyprland ipc
|
||||||
|
gIPC->registerForIPC("fullscreen", this);
|
||||||
|
gIPC->registerForIPC("workspace", this);
|
||||||
|
gIPC->registerForIPC("focusedmon", this);
|
||||||
|
gIPC->registerForIPC("openwindow", this);
|
||||||
|
gIPC->registerForIPC("closewindow", this);
|
||||||
|
gIPC->registerForIPC("movewindow", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowCount::~WindowCount() {
|
||||||
|
gIPC->unregisterForIPC(this);
|
||||||
|
// wait for possible event handler to finish
|
||||||
|
std::lock_guard<std::mutex> lg(mutex_);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto WindowCount::update() -> void {
|
||||||
|
std::lock_guard<std::mutex> lg(mutex_);
|
||||||
|
|
||||||
|
std::string format = config_["format"].asString();
|
||||||
|
std::string formatEmpty = config_["format-empty"].asString();
|
||||||
|
std::string formatWindowed = config_["format-windowed"].asString();
|
||||||
|
std::string formatFullscreen = config_["format-fullscreen"].asString();
|
||||||
|
|
||||||
|
setClass("empty", workspace_.windows == 0);
|
||||||
|
setClass("fullscreen", workspace_.hasfullscreen);
|
||||||
|
|
||||||
|
if (workspace_.windows == 0 && !formatEmpty.empty()) {
|
||||||
|
label_.set_markup(fmt::format(fmt::runtime(formatEmpty), workspace_.windows));
|
||||||
|
} else if (!workspace_.hasfullscreen && !formatWindowed.empty()) {
|
||||||
|
label_.set_markup(fmt::format(fmt::runtime(formatWindowed), workspace_.windows));
|
||||||
|
} else if (workspace_.hasfullscreen && !formatFullscreen.empty()) {
|
||||||
|
label_.set_markup(fmt::format(fmt::runtime(formatFullscreen), workspace_.windows));
|
||||||
|
} else if (!format.empty()) {
|
||||||
|
label_.set_markup(fmt::format(fmt::runtime(format), workspace_.windows));
|
||||||
|
} else {
|
||||||
|
label_.set_text(fmt::format("{}", workspace_.windows));
|
||||||
|
}
|
||||||
|
|
||||||
|
label_.show();
|
||||||
|
AAppIconLabel::update();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto WindowCount::getActiveWorkspace() -> Workspace {
|
||||||
|
const auto workspace = gIPC->getSocket1JsonReply("activeworkspace");
|
||||||
|
|
||||||
|
if (workspace.isObject()) {
|
||||||
|
return Workspace::parse(workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto WindowCount::getActiveWorkspace(const std::string& monitorName) -> Workspace {
|
||||||
|
const auto monitors = gIPC->getSocket1JsonReply("monitors");
|
||||||
|
if (monitors.isArray()) {
|
||||||
|
auto monitor = std::find_if(monitors.begin(), monitors.end(), [&](Json::Value monitor) {
|
||||||
|
return monitor["name"] == monitorName;
|
||||||
|
});
|
||||||
|
if (monitor == std::end(monitors)) {
|
||||||
|
spdlog::warn("Monitor not found: {}", monitorName);
|
||||||
|
return Workspace{-1, 0, false};
|
||||||
|
}
|
||||||
|
const int id = (*monitor)["activeWorkspace"]["id"].asInt();
|
||||||
|
|
||||||
|
const auto workspaces = gIPC->getSocket1JsonReply("workspaces");
|
||||||
|
if (workspaces.isArray()) {
|
||||||
|
auto workspace = std::find_if(workspaces.begin(), workspaces.end(),
|
||||||
|
[&](Json::Value workspace) { return workspace["id"] == id; });
|
||||||
|
if (workspace == std::end(workspaces)) {
|
||||||
|
spdlog::warn("No workspace with id {}", id);
|
||||||
|
return Workspace{-1, 0, false};
|
||||||
|
}
|
||||||
|
return Workspace::parse(*workspace);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto WindowCount::Workspace::parse(const Json::Value& value) -> WindowCount::Workspace {
|
||||||
|
return Workspace{
|
||||||
|
value["id"].asInt(),
|
||||||
|
value["windows"].asInt(),
|
||||||
|
value["hasfullscreen"].asBool(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowCount::queryActiveWorkspace() {
|
||||||
|
std::lock_guard<std::mutex> lg(mutex_);
|
||||||
|
|
||||||
|
if (separateOutputs_) {
|
||||||
|
workspace_ = getActiveWorkspace(this->bar_.output->name);
|
||||||
|
} else {
|
||||||
|
workspace_ = getActiveWorkspace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowCount::onEvent(const std::string& ev) {
|
||||||
|
queryActiveWorkspace();
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowCount::setClass(const std::string& classname, bool enable) {
|
||||||
|
if (enable) {
|
||||||
|
if (!bar_.window.get_style_context()->has_class(classname)) {
|
||||||
|
bar_.window.get_style_context()->add_class(classname);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bar_.window.get_style_context()->remove_class(classname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace waybar::modules::hyprland
|
@ -89,7 +89,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,12 +109,12 @@ void Workspace::setActiveWindow(WindowAddress const &addr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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() || m_workspaceManager.enableTaskbar()) {
|
if (!repr.empty() || m_workspaceManager.enableTaskbar()) {
|
||||||
auto addr = create_window_paylod.getAddress();
|
auto addr = create_window_payload.getAddress();
|
||||||
auto it = std::ranges::find_if(
|
auto it = std::ranges::find_if(
|
||||||
m_windowMap, [&addr](const auto &window) { return window.address == addr; });
|
m_windowMap, [&addr](const auto &window) { return window.address == addr; });
|
||||||
// If the vector contains the address, update the window representation, otherwise insert it
|
// If the vector contains the address, update the window representation, otherwise insert it
|
||||||
@ -127,9 +127,9 @@ void Workspace::insertWindow(WindowCreationPayload create_window_paylod) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
@ -193,6 +193,10 @@ std::string &Workspace::selectIcon(std::map<std::string, std::string> &icons_map
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::update(const std::string &workspace_icon) {
|
void Workspace::update(const std::string &workspace_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() && \
|
||||||
|
@ -518,7 +518,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -623,6 +623,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);
|
||||||
|
|
||||||
@ -866,6 +867,40 @@ void Workspaces::setCurrentMonitorId() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Workspaces::sortSpecialCentered() {
|
||||||
|
std::vector<std::unique_ptr<Workspace>> specialWorkspaces;
|
||||||
|
std::vector<std::unique_ptr<Workspace>> hiddenWorkspaces;
|
||||||
|
std::vector<std::unique_ptr<Workspace>> normalWorkspaces;
|
||||||
|
|
||||||
|
for (auto &workspace : m_workspaces) {
|
||||||
|
if (workspace->isSpecial()) {
|
||||||
|
specialWorkspaces.push_back(std::move(workspace));
|
||||||
|
} else {
|
||||||
|
if (workspace->button().is_visible()) {
|
||||||
|
normalWorkspaces.push_back(std::move(workspace));
|
||||||
|
} else {
|
||||||
|
hiddenWorkspaces.push_back(std::move(workspace));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_workspaces.clear();
|
||||||
|
|
||||||
|
size_t center = normalWorkspaces.size() / 2;
|
||||||
|
|
||||||
|
m_workspaces.insert(m_workspaces.end(), std::make_move_iterator(normalWorkspaces.begin()),
|
||||||
|
std::make_move_iterator(normalWorkspaces.begin() + center));
|
||||||
|
|
||||||
|
m_workspaces.insert(m_workspaces.end(), std::make_move_iterator(specialWorkspaces.begin()),
|
||||||
|
std::make_move_iterator(specialWorkspaces.end()));
|
||||||
|
|
||||||
|
m_workspaces.insert(m_workspaces.end(),
|
||||||
|
std::make_move_iterator(normalWorkspaces.begin() + center),
|
||||||
|
std::make_move_iterator(normalWorkspaces.end()));
|
||||||
|
|
||||||
|
m_workspaces.insert(m_workspaces.end(), std::make_move_iterator(hiddenWorkspaces.begin()),
|
||||||
|
std::make_move_iterator(hiddenWorkspaces.end()));
|
||||||
|
}
|
||||||
|
|
||||||
void Workspaces::sortWorkspaces() {
|
void Workspaces::sortWorkspaces() {
|
||||||
std::ranges::sort( //
|
std::ranges::sort( //
|
||||||
m_workspaces, [&](std::unique_ptr<Workspace> &a, std::unique_ptr<Workspace> &b) {
|
m_workspaces, [&](std::unique_ptr<Workspace> &a, std::unique_ptr<Workspace> &b) {
|
||||||
@ -924,6 +959,9 @@ void Workspaces::sortWorkspaces() {
|
|||||||
// Return a default value if none of the cases match.
|
// Return a default value if none of the cases match.
|
||||||
return isNameLess; // You can adjust this to your specific needs.
|
return isNameLess; // You can adjust this to your specific needs.
|
||||||
});
|
});
|
||||||
|
if (m_sortBy == SortMethod::SPECIAL_CENTERED) {
|
||||||
|
this->sortSpecialCentered();
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
@ -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);
|
||||||
|
@ -223,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_);
|
||||||
};
|
};
|
||||||
@ -271,12 +271,10 @@ 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() && ifid_ == -1) return "disabled";
|
||||||
#endif
|
#endif
|
||||||
return "disconnected";
|
if (ifid_ == -1) return "disconnected";
|
||||||
}
|
|
||||||
if (!carrier_) return "disconnected";
|
if (!carrier_) return "disconnected";
|
||||||
if (ipaddr_.empty() && ipaddr6_.empty()) return "linked";
|
if (ipaddr_.empty() && ipaddr6_.empty()) return "linked";
|
||||||
if (essid_.empty()) return "ethernet";
|
if (essid_.empty()) return "ethernet";
|
||||||
|
@ -147,6 +147,17 @@ void IPC::parseIPC(const std::string &line) {
|
|||||||
} else {
|
} else {
|
||||||
spdlog::error("Active window changed on unknown workspace");
|
spdlog::error("Active window changed on unknown workspace");
|
||||||
}
|
}
|
||||||
|
} else if (const auto &payload = ev["WorkspaceUrgencyChanged"]) {
|
||||||
|
const auto id = payload["id"].asUInt64();
|
||||||
|
const auto urgent = payload["urgent"].asBool();
|
||||||
|
auto it = std::find_if(workspaces_.begin(), workspaces_.end(),
|
||||||
|
[id](const auto &ws) { return ws["id"].asUInt64() == id; });
|
||||||
|
if (it != workspaces_.end()) {
|
||||||
|
auto &ws = *it;
|
||||||
|
ws["is_urgent"] = urgent;
|
||||||
|
} else {
|
||||||
|
spdlog::error("Urgency changed for unknown workspace");
|
||||||
|
}
|
||||||
} else if (const auto &payload = ev["KeyboardLayoutsChanged"]) {
|
} else if (const auto &payload = ev["KeyboardLayoutsChanged"]) {
|
||||||
const auto &layouts = payload["keyboard_layouts"];
|
const auto &layouts = payload["keyboard_layouts"];
|
||||||
const auto &names = layouts["names"];
|
const auto &names = layouts["names"];
|
||||||
|
@ -20,6 +20,7 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
|
|||||||
gIPC->registerForIPC("WorkspacesChanged", this);
|
gIPC->registerForIPC("WorkspacesChanged", this);
|
||||||
gIPC->registerForIPC("WorkspaceActivated", this);
|
gIPC->registerForIPC("WorkspaceActivated", this);
|
||||||
gIPC->registerForIPC("WorkspaceActiveWindowChanged", this);
|
gIPC->registerForIPC("WorkspaceActiveWindowChanged", this);
|
||||||
|
gIPC->registerForIPC("WorkspaceUrgencyChanged", this);
|
||||||
|
|
||||||
dp.emit();
|
dp.emit();
|
||||||
}
|
}
|
||||||
@ -67,6 +68,11 @@ void Workspaces::doUpdate() {
|
|||||||
else
|
else
|
||||||
style_context->remove_class("active");
|
style_context->remove_class("active");
|
||||||
|
|
||||||
|
if (ws["is_urgent"].asBool())
|
||||||
|
style_context->add_class("urgent");
|
||||||
|
else
|
||||||
|
style_context->remove_class("urgent");
|
||||||
|
|
||||||
if (ws["output"]) {
|
if (ws["output"]) {
|
||||||
if (ws["output"].asString() == bar_.output->name)
|
if (ws["output"].asString() == bar_.output->name)
|
||||||
style_context->add_class("current_output");
|
style_context->add_class("current_output");
|
||||||
@ -166,6 +172,10 @@ 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["is_urgent"].asBool() && icons["urgent"]) return icons["urgent"].asString();
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@ -74,6 +74,24 @@ Privacy::Privacy(const std::string& id, const Json::Value& config, Gtk::Orientat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
@ -88,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"
|
||||||
@ -96,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);
|
||||||
|
@ -388,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() {
|
||||||
|
@ -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()) {
|
||||||
|
@ -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_);
|
||||||
|
445
src/modules/wayfire/backend.cpp
Normal file
445
src/modules/wayfire/backend.cpp
Normal file
@ -0,0 +1,445 @@
|
|||||||
|
#include "modules/wayfire/backend.hpp"
|
||||||
|
|
||||||
|
#include <json/json.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <bit>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <exception>
|
||||||
|
#include <ranges>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace waybar::modules::wayfire {
|
||||||
|
|
||||||
|
std::weak_ptr<IPC> IPC::instance;
|
||||||
|
|
||||||
|
// C++23: std::byteswap
|
||||||
|
inline auto byteswap(uint32_t x) -> uint32_t {
|
||||||
|
return (x & 0xff000000) >> 24 | (x & 0x00ff0000) >> 8 | (x & 0x0000ff00) << 8 |
|
||||||
|
(x & 0x000000ff) << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pack_and_write(Sock& sock, std::string&& buf) -> void {
|
||||||
|
uint32_t len = buf.size();
|
||||||
|
if constexpr (std::endian::native != std::endian::little) len = byteswap(len);
|
||||||
|
(void)write(sock.fd, &len, 4);
|
||||||
|
(void)write(sock.fd, buf.data(), buf.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto read_exact(Sock& sock, size_t n) -> std::string {
|
||||||
|
auto buf = std::string(n, 0);
|
||||||
|
for (size_t i = 0; i < n;) i += read(sock.fd, &buf[i], n - i);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/WayfireWM/pywayfire/blob/69b7c21/wayfire/ipc.py#L438
|
||||||
|
inline auto is_mapped_toplevel_view(const Json::Value& view) -> bool {
|
||||||
|
return view["mapped"].asBool() && view["role"] != "desktop-environment" &&
|
||||||
|
view["pid"].asInt() != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto State::Wset::count_ws(const Json::Value& pos) -> Workspace& {
|
||||||
|
auto x = pos["x"].asInt();
|
||||||
|
auto y = pos["y"].asInt();
|
||||||
|
return wss.at(ws_w * y + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto State::Wset::locate_ws(const Json::Value& geo) -> Workspace& {
|
||||||
|
return const_cast<Workspace&>(std::as_const(*this).locate_ws(geo));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto State::Wset::locate_ws(const Json::Value& geo) const -> const Workspace& {
|
||||||
|
const auto& out = output.value().get();
|
||||||
|
auto [qx, rx] = std::div(geo["x"].asInt(), out.w);
|
||||||
|
auto [qy, ry] = std::div(geo["y"].asInt(), out.h);
|
||||||
|
auto x = std::max(0, (int)ws_x + qx - int{rx < 0});
|
||||||
|
auto y = std::max(0, (int)ws_y + qy - int{ry < 0});
|
||||||
|
return wss.at(ws_w * y + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto State::update_view(const Json::Value& view) -> void {
|
||||||
|
auto id = view["id"].asUInt();
|
||||||
|
|
||||||
|
// erase old view information
|
||||||
|
if (views.contains(id)) {
|
||||||
|
auto& old_view = views.at(id);
|
||||||
|
auto& ws = wsets.at(old_view["wset-index"].asUInt()).locate_ws(old_view["geometry"]);
|
||||||
|
ws.num_views--;
|
||||||
|
if (old_view["sticky"].asBool()) ws.num_sticky_views--;
|
||||||
|
views.erase(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert or assign new view information
|
||||||
|
if (is_mapped_toplevel_view(view)) {
|
||||||
|
try {
|
||||||
|
// view["wset-index"] could be messed up
|
||||||
|
auto& ws = wsets.at(view["wset-index"].asUInt()).locate_ws(view["geometry"]);
|
||||||
|
ws.num_views++;
|
||||||
|
if (view["sticky"].asBool()) ws.num_sticky_views++;
|
||||||
|
views.emplace(id, view);
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IPC::get_instance() -> std::shared_ptr<IPC> {
|
||||||
|
auto p = instance.lock();
|
||||||
|
if (!p) instance = p = std::shared_ptr<IPC>(new IPC);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IPC::connect() -> Sock {
|
||||||
|
auto* path = std::getenv("WAYFIRE_SOCKET");
|
||||||
|
if (path == nullptr) {
|
||||||
|
throw std::runtime_error{"Wayfire IPC: ipc not available"};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sock == -1) {
|
||||||
|
throw std::runtime_error{"Wayfire IPC: socket() failed"};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto addr = sockaddr_un{.sun_family = AF_UNIX};
|
||||||
|
std::strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
|
||||||
|
addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
|
||||||
|
|
||||||
|
if (::connect(sock, (const sockaddr*)&addr, sizeof(addr)) == -1) {
|
||||||
|
close(sock);
|
||||||
|
throw std::runtime_error{"Wayfire IPC: connect() failed"};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {sock};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IPC::receive(Sock& sock) -> Json::Value {
|
||||||
|
auto len = *reinterpret_cast<uint32_t*>(read_exact(sock, 4).data());
|
||||||
|
if constexpr (std::endian::native != std::endian::little) len = byteswap(len);
|
||||||
|
auto buf = read_exact(sock, len);
|
||||||
|
|
||||||
|
Json::Value json;
|
||||||
|
std::string err;
|
||||||
|
auto* reader = reader_builder.newCharReader();
|
||||||
|
if (!reader->parse(&*buf.begin(), &*buf.end(), &json, &err)) {
|
||||||
|
throw std::runtime_error{"Wayfire IPC: parse json failed: " + err};
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IPC::send(const std::string& method, Json::Value&& data) -> Json::Value {
|
||||||
|
spdlog::debug("Wayfire IPC: send method \"{}\"", method);
|
||||||
|
auto sock = connect();
|
||||||
|
|
||||||
|
Json::Value json;
|
||||||
|
json["method"] = method;
|
||||||
|
json["data"] = std::move(data);
|
||||||
|
|
||||||
|
pack_and_write(sock, Json::writeString(writer_builder, json));
|
||||||
|
auto res = receive(sock);
|
||||||
|
root_event_handler(method, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IPC::start() -> void {
|
||||||
|
spdlog::info("Wayfire IPC: starting");
|
||||||
|
|
||||||
|
// init state
|
||||||
|
send("window-rules/list-outputs", {});
|
||||||
|
send("window-rules/list-wsets", {});
|
||||||
|
send("window-rules/list-views", {});
|
||||||
|
send("window-rules/get-focused-view", {});
|
||||||
|
send("window-rules/get-focused-output", {});
|
||||||
|
|
||||||
|
std::thread([&] {
|
||||||
|
auto sock = connect();
|
||||||
|
|
||||||
|
{
|
||||||
|
Json::Value json;
|
||||||
|
json["method"] = "window-rules/events/watch";
|
||||||
|
|
||||||
|
pack_and_write(sock, Json::writeString(writer_builder, json));
|
||||||
|
if (receive(sock)["result"] != "ok") {
|
||||||
|
spdlog::error(
|
||||||
|
"Wayfire IPC: method \"window-rules/events/watch\""
|
||||||
|
" have failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (auto json = receive(sock)) {
|
||||||
|
auto ev = json["event"].asString();
|
||||||
|
spdlog::debug("Wayfire IPC: received event \"{}\"", ev);
|
||||||
|
root_event_handler(ev, json);
|
||||||
|
}
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IPC::register_handler(const std::string& event, const EventHandler& handler) -> void {
|
||||||
|
auto _ = std::lock_guard{handlers_mutex};
|
||||||
|
handlers.emplace_back(event, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IPC::unregister_handler(EventHandler& handler) -> void {
|
||||||
|
auto _ = std::lock_guard{handlers_mutex};
|
||||||
|
handlers.remove_if([&](auto& e) { return &e.second.get() == &handler; });
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IPC::root_event_handler(const std::string& event, const Json::Value& data) -> void {
|
||||||
|
bool new_output_detected;
|
||||||
|
{
|
||||||
|
auto _ = lock_state();
|
||||||
|
update_state_handler(event, data);
|
||||||
|
new_output_detected = state.new_output_detected;
|
||||||
|
state.new_output_detected = false;
|
||||||
|
}
|
||||||
|
if (new_output_detected) {
|
||||||
|
send("window-rules/list-outputs", {});
|
||||||
|
send("window-rules/list-wsets", {});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto _ = std::lock_guard{handlers_mutex};
|
||||||
|
for (const auto& [_event, handler] : handlers)
|
||||||
|
if (_event == event) handler(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IPC::update_state_handler(const std::string& event, const Json::Value& data) -> void {
|
||||||
|
// IPC events
|
||||||
|
// https://github.com/WayfireWM/wayfire/blob/053b222/plugins/ipc-rules/ipc-events.hpp#L108-L125
|
||||||
|
/*
|
||||||
|
[x] view-mapped
|
||||||
|
[x] view-unmapped
|
||||||
|
[-] view-set-output // for detect new output
|
||||||
|
[ ] view-geometry-changed // -> view-workspace-changed
|
||||||
|
[x] view-wset-changed
|
||||||
|
[x] view-focused
|
||||||
|
[x] view-title-changed
|
||||||
|
[x] view-app-id-changed
|
||||||
|
[x] plugin-activation-state-changed
|
||||||
|
[x] output-gain-focus
|
||||||
|
|
||||||
|
[ ] view-tiled
|
||||||
|
[ ] view-minimized
|
||||||
|
[ ] view-fullscreened
|
||||||
|
[x] view-sticky
|
||||||
|
[x] view-workspace-changed
|
||||||
|
[x] output-wset-changed
|
||||||
|
[x] wset-workspace-changed
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (event == "view-mapped") {
|
||||||
|
// data: { event, view }
|
||||||
|
state.update_view(data["view"]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "view-unmapped") {
|
||||||
|
// data: { event, view }
|
||||||
|
try {
|
||||||
|
// data["view"]["wset-index"] could be messed up
|
||||||
|
state.update_view(data["view"]);
|
||||||
|
state.maybe_empty_focus_wset_idx = data["view"]["wset-index"].asUInt();
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "view-set-output") {
|
||||||
|
// data: { event, output?, view }
|
||||||
|
// new output event
|
||||||
|
if (!state.outputs.contains(data["view"]["output-name"].asString())) {
|
||||||
|
state.new_output_detected = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "view-wset-changed") {
|
||||||
|
// data: { event, old-wset: wset, new-wset: wset, view }
|
||||||
|
state.maybe_empty_focus_wset_idx = data["old-wset"]["index"].asUInt();
|
||||||
|
state.update_view(data["view"]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "view-focused") {
|
||||||
|
// data: { event, view? }
|
||||||
|
if (const auto& view = data["view"]) {
|
||||||
|
try {
|
||||||
|
// view["wset-index"] could be messed up
|
||||||
|
auto& wset = state.wsets.at(view["wset-index"].asUInt());
|
||||||
|
wset.focused_view_id = view["id"].asUInt();
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// focused to null
|
||||||
|
if (state.wsets.contains(state.maybe_empty_focus_wset_idx))
|
||||||
|
state.wsets.at(state.maybe_empty_focus_wset_idx).focused_view_id = {};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "view-title-changed" || event == "view-app-id-changed" || event == "view-sticky") {
|
||||||
|
// data: { event, view }
|
||||||
|
state.update_view(data["view"]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "plugin-activation-state-changed") {
|
||||||
|
// data: { event, plugin: name, state: bool, output: id, output-data: output }
|
||||||
|
auto plugin = data["plugin"].asString();
|
||||||
|
auto plugin_state = data["state"].asBool();
|
||||||
|
|
||||||
|
if (plugin == "vswitch") {
|
||||||
|
state.vswitching = plugin_state;
|
||||||
|
if (plugin_state) {
|
||||||
|
state.maybe_empty_focus_wset_idx = data["output-data"]["wset-index"].asUInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "output-gain-focus") {
|
||||||
|
// data: { event, output }
|
||||||
|
state.focused_output_name = data["output"]["name"].asString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "view-workspace-changed") {
|
||||||
|
// data: { event, from: point, to: point, view }
|
||||||
|
if (state.vswitching) {
|
||||||
|
if (state.vswitch_sticky_view_id == 0) {
|
||||||
|
auto& wset = state.wsets.at(data["view"]["wset-index"].asUInt());
|
||||||
|
auto& old_ws = wset.locate_ws(state.views.at(data["view"]["id"].asUInt())["geometry"]);
|
||||||
|
auto& new_ws = wset.count_ws(data["to"]);
|
||||||
|
old_ws.num_views--;
|
||||||
|
new_ws.num_views++;
|
||||||
|
if (data["view"]["sticky"].asBool()) {
|
||||||
|
old_ws.num_sticky_views--;
|
||||||
|
new_ws.num_sticky_views++;
|
||||||
|
}
|
||||||
|
state.update_view(data["view"]);
|
||||||
|
state.vswitch_sticky_view_id = data["view"]["id"].asUInt();
|
||||||
|
} else {
|
||||||
|
state.vswitch_sticky_view_id = {};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.update_view(data["view"]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "output-wset-changed") {
|
||||||
|
// data: { event, new-wset: wset.name, output: id, new-wset-data: wset, output-data: output }
|
||||||
|
auto& output = state.outputs.at(data["output-data"]["name"].asString());
|
||||||
|
auto wset_idx = data["new-wset-data"]["index"].asUInt();
|
||||||
|
state.wsets.at(wset_idx).output = output;
|
||||||
|
output.wset_idx = wset_idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "wset-workspace-changed") {
|
||||||
|
// data: { event, previous-workspace: point, new-workspace: point,
|
||||||
|
// output: id, wset: wset.name, output-data: output, wset-data: wset }
|
||||||
|
auto wset_idx = data["wset-data"]["index"].asUInt();
|
||||||
|
auto& wset = state.wsets.at(wset_idx);
|
||||||
|
wset.ws_x = data["new-workspace"]["x"].asUInt();
|
||||||
|
wset.ws_y = data["new-workspace"]["y"].asUInt();
|
||||||
|
|
||||||
|
// correct existing views geometry
|
||||||
|
auto& out = wset.output.value().get();
|
||||||
|
auto dx = (int)out.w * ((int)wset.ws_x - data["previous-workspace"]["x"].asInt());
|
||||||
|
auto dy = (int)out.h * ((int)wset.ws_y - data["previous-workspace"]["y"].asInt());
|
||||||
|
for (auto& [_, view] : state.views) {
|
||||||
|
if (view["wset-index"].asUInt() == wset_idx &&
|
||||||
|
view["id"].asUInt() != state.vswitch_sticky_view_id) {
|
||||||
|
view["geometry"]["x"] = view["geometry"]["x"].asInt() - dx;
|
||||||
|
view["geometry"]["y"] = view["geometry"]["y"].asInt() - dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPC responses
|
||||||
|
// https://github.com/WayfireWM/wayfire/blob/053b222/plugins/ipc-rules/ipc-rules.cpp#L27-L37
|
||||||
|
|
||||||
|
if (event == "window-rules/list-views") {
|
||||||
|
// data: [ view ]
|
||||||
|
state.views.clear();
|
||||||
|
for (auto& [_, wset] : state.wsets) std::ranges::fill(wset.wss, State::Workspace{});
|
||||||
|
for (const auto& view : data | std::views::filter(is_mapped_toplevel_view)) {
|
||||||
|
state.update_view(view);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "window-rules/list-outputs") {
|
||||||
|
// data: [ output ]
|
||||||
|
state.outputs.clear();
|
||||||
|
for (const auto& output_data : data) {
|
||||||
|
state.outputs.emplace(output_data["name"].asString(),
|
||||||
|
State::Output{
|
||||||
|
.id = output_data["id"].asUInt(),
|
||||||
|
.w = output_data["geometry"]["width"].asUInt(),
|
||||||
|
.h = output_data["geometry"]["height"].asUInt(),
|
||||||
|
.wset_idx = output_data["wset-index"].asUInt(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "window-rules/list-wsets") {
|
||||||
|
// data: [ wset ]
|
||||||
|
std::unordered_map<size_t, State::Wset> wsets;
|
||||||
|
for (const auto& wset_data : data) {
|
||||||
|
auto wset_idx = wset_data["index"].asUInt();
|
||||||
|
|
||||||
|
auto output_name = wset_data["output-name"].asString();
|
||||||
|
auto output = state.outputs.contains(output_name)
|
||||||
|
? std::optional{std::ref(state.outputs.at(output_name))}
|
||||||
|
: std::nullopt;
|
||||||
|
|
||||||
|
const auto& ws_data = wset_data["workspace"];
|
||||||
|
auto ws_w = ws_data["grid_width"].asUInt();
|
||||||
|
auto ws_h = ws_data["grid_height"].asUInt();
|
||||||
|
|
||||||
|
wsets.emplace(wset_idx, State::Wset{
|
||||||
|
.output = output,
|
||||||
|
.wss = std::vector<State::Workspace>(ws_w * ws_h),
|
||||||
|
.ws_w = ws_w,
|
||||||
|
.ws_h = ws_h,
|
||||||
|
.ws_x = ws_data["x"].asUInt(),
|
||||||
|
.ws_y = ws_data["y"].asUInt(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (state.wsets.contains(wset_idx)) {
|
||||||
|
auto& old_wset = state.wsets.at(wset_idx);
|
||||||
|
auto& new_wset = wsets.at(wset_idx);
|
||||||
|
new_wset.wss = std::move(old_wset.wss);
|
||||||
|
new_wset.focused_view_id = old_wset.focused_view_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.wsets = std::move(wsets);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "window-rules/get-focused-view") {
|
||||||
|
// data: { ok, info: view? }
|
||||||
|
if (const auto& view = data["info"]) {
|
||||||
|
auto& wset = state.wsets.at(view["wset-index"].asUInt());
|
||||||
|
wset.focused_view_id = view["id"].asUInt();
|
||||||
|
state.update_view(view);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == "window-rules/get-focused-output") {
|
||||||
|
// data: { ok, info: output }
|
||||||
|
state.focused_output_name = data["info"]["name"].asString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace waybar::modules::wayfire
|
77
src/modules/wayfire/window.cpp
Normal file
77
src/modules/wayfire/window.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include "modules/wayfire/window.hpp"
|
||||||
|
|
||||||
|
#include <gtkmm/button.h>
|
||||||
|
#include <gtkmm/label.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include "util/rewrite_string.hpp"
|
||||||
|
#include "util/sanitize_str.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::wayfire {
|
||||||
|
|
||||||
|
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||||
|
: AAppIconLabel(config, "window", id, "{title}", 0, true),
|
||||||
|
ipc{IPC::get_instance()},
|
||||||
|
handler{[this](const auto&) { dp.emit(); }},
|
||||||
|
bar_{bar} {
|
||||||
|
ipc->register_handler("view-unmapped", handler);
|
||||||
|
ipc->register_handler("view-focused", handler);
|
||||||
|
ipc->register_handler("view-title-changed", handler);
|
||||||
|
ipc->register_handler("view-app-id-changed", handler);
|
||||||
|
|
||||||
|
ipc->register_handler("window-rules/get-focused-view", handler);
|
||||||
|
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::~Window() { ipc->unregister_handler(handler); }
|
||||||
|
|
||||||
|
auto Window::update() -> void {
|
||||||
|
update_icon_label();
|
||||||
|
AAppIconLabel::update();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Window::update_icon_label() -> void {
|
||||||
|
auto _ = ipc->lock_state();
|
||||||
|
|
||||||
|
const auto& output = ipc->get_outputs().at(bar_.output->name);
|
||||||
|
const auto& wset = ipc->get_wsets().at(output.wset_idx);
|
||||||
|
const auto& views = ipc->get_views();
|
||||||
|
auto ctx = bar_.window.get_style_context();
|
||||||
|
|
||||||
|
if (views.contains(wset.focused_view_id)) {
|
||||||
|
const auto& view = views.at(wset.focused_view_id);
|
||||||
|
auto title = view["title"].asString();
|
||||||
|
auto app_id = view["app-id"].asString();
|
||||||
|
|
||||||
|
// update label
|
||||||
|
label_.set_markup(waybar::util::rewriteString(
|
||||||
|
fmt::format(fmt::runtime(format_), fmt::arg("title", waybar::util::sanitize_string(title)),
|
||||||
|
fmt::arg("app_id", waybar::util::sanitize_string(app_id))),
|
||||||
|
config_["rewrite"]));
|
||||||
|
|
||||||
|
// update window#waybar.solo
|
||||||
|
if (wset.locate_ws(view["geometry"]).num_views > 1)
|
||||||
|
ctx->remove_class("solo");
|
||||||
|
else
|
||||||
|
ctx->add_class("solo");
|
||||||
|
|
||||||
|
// update window#waybar.<app_id>
|
||||||
|
ctx->remove_class(old_app_id_);
|
||||||
|
ctx->add_class(old_app_id_ = app_id);
|
||||||
|
|
||||||
|
// update window#waybar.empty
|
||||||
|
ctx->remove_class("empty");
|
||||||
|
|
||||||
|
//
|
||||||
|
updateAppIconName(app_id, "");
|
||||||
|
label_.show();
|
||||||
|
} else {
|
||||||
|
ctx->add_class("empty");
|
||||||
|
|
||||||
|
updateAppIconName("", "");
|
||||||
|
label_.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace waybar::modules::wayfire
|
183
src/modules/wayfire/workspaces.cpp
Normal file
183
src/modules/wayfire/workspaces.cpp
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
#include "modules/wayfire/workspaces.hpp"
|
||||||
|
|
||||||
|
#include <gtkmm/button.h>
|
||||||
|
#include <gtkmm/label.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "modules/wayfire/backend.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::wayfire {
|
||||||
|
|
||||||
|
Workspaces::Workspaces(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||||
|
: AModule{config, "workspaces", id, false, !config["disable-scroll"].asBool()},
|
||||||
|
ipc{IPC::get_instance()},
|
||||||
|
handler{[this](const auto&) { dp.emit(); }},
|
||||||
|
bar_{bar} {
|
||||||
|
// init box_
|
||||||
|
box_.set_name("workspaces");
|
||||||
|
if (!id.empty()) box_.get_style_context()->add_class(id);
|
||||||
|
box_.get_style_context()->add_class(MODULE_CLASS);
|
||||||
|
event_box_.add(box_);
|
||||||
|
|
||||||
|
// scroll events
|
||||||
|
if (!config_["disable-scroll"].asBool()) {
|
||||||
|
auto& target = config_["enable-bar-scroll"].asBool() ? const_cast<Bar&>(bar_).window
|
||||||
|
: dynamic_cast<Gtk::Widget&>(box_);
|
||||||
|
target.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
||||||
|
target.signal_scroll_event().connect(sigc::mem_fun(*this, &Workspaces::handleScroll));
|
||||||
|
}
|
||||||
|
|
||||||
|
// listen events
|
||||||
|
ipc->register_handler("view-mapped", handler);
|
||||||
|
ipc->register_handler("view-unmapped", handler);
|
||||||
|
ipc->register_handler("view-wset-changed", handler);
|
||||||
|
ipc->register_handler("output-gain-focus", handler);
|
||||||
|
ipc->register_handler("view-sticky", handler);
|
||||||
|
ipc->register_handler("view-workspace-changed", handler);
|
||||||
|
ipc->register_handler("output-wset-changed", handler);
|
||||||
|
ipc->register_handler("wset-workspace-changed", handler);
|
||||||
|
|
||||||
|
ipc->register_handler("window-rules/list-views", handler);
|
||||||
|
ipc->register_handler("window-rules/list-outputs", handler);
|
||||||
|
ipc->register_handler("window-rules/list-wsets", handler);
|
||||||
|
ipc->register_handler("window-rules/get-focused-output", handler);
|
||||||
|
|
||||||
|
// initial render
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Workspaces::~Workspaces() { ipc->unregister_handler(handler); }
|
||||||
|
|
||||||
|
auto Workspaces::handleScroll(GdkEventScroll* e) -> bool {
|
||||||
|
// Ignore emulated scroll events on window
|
||||||
|
if (gdk_event_get_pointer_emulated((GdkEvent*)e) != 0) return false;
|
||||||
|
|
||||||
|
auto dir = AModule::getScrollDir(e);
|
||||||
|
if (dir == SCROLL_DIR::NONE) return true;
|
||||||
|
|
||||||
|
int delta;
|
||||||
|
if (dir == SCROLL_DIR::DOWN || dir == SCROLL_DIR::RIGHT)
|
||||||
|
delta = 1;
|
||||||
|
else if (dir == SCROLL_DIR::UP || dir == SCROLL_DIR::LEFT)
|
||||||
|
delta = -1;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// cycle workspace
|
||||||
|
Json::Value data;
|
||||||
|
{
|
||||||
|
auto _ = ipc->lock_state();
|
||||||
|
const auto& output = ipc->get_outputs().at(bar_.output->name);
|
||||||
|
const auto& wset = ipc->get_wsets().at(output.wset_idx);
|
||||||
|
auto n = wset.ws_w * wset.ws_h;
|
||||||
|
auto i = (wset.ws_idx() + delta + n) % n;
|
||||||
|
data["x"] = i % wset.ws_w;
|
||||||
|
data["y"] = i / wset.ws_h;
|
||||||
|
data["output-id"] = output.id;
|
||||||
|
}
|
||||||
|
ipc->send("vswitch/set-workspace", std::move(data));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Workspaces::update() -> void {
|
||||||
|
update_box();
|
||||||
|
AModule::update();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Workspaces::update_box() -> void {
|
||||||
|
auto _ = ipc->lock_state();
|
||||||
|
|
||||||
|
const auto& output_name = bar_.output->name;
|
||||||
|
const auto& output = ipc->get_outputs().at(output_name);
|
||||||
|
const auto& wset = ipc->get_wsets().at(output.wset_idx);
|
||||||
|
|
||||||
|
auto output_focused = ipc->get_focused_output_name() == output_name;
|
||||||
|
auto ws_w = wset.ws_w;
|
||||||
|
auto ws_h = wset.ws_h;
|
||||||
|
auto num_wss = ws_w * ws_h;
|
||||||
|
|
||||||
|
// add buttons for new workspaces
|
||||||
|
for (auto i = buttons_.size(); i < num_wss; i++) {
|
||||||
|
auto& btn = buttons_.emplace_back("");
|
||||||
|
box_.pack_start(btn, false, false, 0);
|
||||||
|
btn.set_relief(Gtk::RELIEF_NONE);
|
||||||
|
if (!config_["disable-click"].asBool()) {
|
||||||
|
btn.signal_pressed().connect([=, this] {
|
||||||
|
Json::Value data;
|
||||||
|
data["x"] = i % ws_w;
|
||||||
|
data["y"] = i / ws_h;
|
||||||
|
data["output-id"] = output.id;
|
||||||
|
ipc->send("vswitch/set-workspace", std::move(data));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove buttons for removed workspaces
|
||||||
|
buttons_.resize(num_wss);
|
||||||
|
|
||||||
|
// update buttons
|
||||||
|
for (size_t i = 0; i < num_wss; i++) {
|
||||||
|
const auto& ws = wset.wss[i];
|
||||||
|
auto& btn = buttons_[i];
|
||||||
|
auto ctx = btn.get_style_context();
|
||||||
|
auto ws_focused = i == wset.ws_idx();
|
||||||
|
auto ws_empty = ws.num_views == 0;
|
||||||
|
|
||||||
|
// update #workspaces button.focused
|
||||||
|
if (ws_focused)
|
||||||
|
ctx->add_class("focused");
|
||||||
|
else
|
||||||
|
ctx->remove_class("focused");
|
||||||
|
|
||||||
|
// update #workspaces button.empty
|
||||||
|
if (ws_empty)
|
||||||
|
ctx->add_class("empty");
|
||||||
|
else
|
||||||
|
ctx->remove_class("empty");
|
||||||
|
|
||||||
|
// update #workspaces button.current_output
|
||||||
|
if (output_focused)
|
||||||
|
ctx->add_class("current_output");
|
||||||
|
else
|
||||||
|
ctx->remove_class("current_output");
|
||||||
|
|
||||||
|
// update label
|
||||||
|
auto label = std::to_string(i + 1);
|
||||||
|
if (config_["format"].isString()) {
|
||||||
|
auto format = config_["format"].asString();
|
||||||
|
auto ws_idx = std::to_string(i + 1);
|
||||||
|
|
||||||
|
const auto& icons = config_["format-icons"];
|
||||||
|
std::string icon;
|
||||||
|
if (!icons)
|
||||||
|
icon = ws_idx;
|
||||||
|
else if (ws_focused && icons["focused"])
|
||||||
|
icon = icons["focused"].asString();
|
||||||
|
else if (icons[ws_idx])
|
||||||
|
icon = icons[ws_idx].asString();
|
||||||
|
else if (icons["default"])
|
||||||
|
icon = icons["default"].asString();
|
||||||
|
else
|
||||||
|
icon = ws_idx;
|
||||||
|
|
||||||
|
label = fmt::format(fmt::runtime(format), fmt::arg("icon", icon), fmt::arg("index", ws_idx),
|
||||||
|
fmt::arg("output", output_name));
|
||||||
|
}
|
||||||
|
if (!config_["disable-markup"].asBool())
|
||||||
|
static_cast<Gtk::Label*>(btn.get_children()[0])->set_markup(label);
|
||||||
|
else
|
||||||
|
btn.set_label(label);
|
||||||
|
|
||||||
|
//
|
||||||
|
if (config_["current-only"].asBool() && i != wset.ws_idx())
|
||||||
|
btn.hide();
|
||||||
|
else
|
||||||
|
btn.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace waybar::modules::wayfire
|
@ -503,6 +503,9 @@ void Task::update() {
|
|||||||
fmt::format(fmt::runtime(format_tooltip_), fmt::arg("title", title), fmt::arg("name", name),
|
fmt::format(fmt::runtime(format_tooltip_), fmt::arg("title", title), fmt::arg("name", name),
|
||||||
fmt::arg("app_id", app_id), fmt::arg("state", state_string()),
|
fmt::arg("app_id", app_id), fmt::arg("state", state_string()),
|
||||||
fmt::arg("short_state", state_string(true)));
|
fmt::arg("short_state", state_string(true)));
|
||||||
|
|
||||||
|
txt = waybar::util::rewriteString(txt, config_["rewrite"]);
|
||||||
|
|
||||||
if (markup)
|
if (markup)
|
||||||
button.set_tooltip_markup(txt);
|
button.set_tooltip_markup(txt);
|
||||||
else
|
else
|
||||||
|
@ -15,11 +15,24 @@ bool DefaultGtkIconThemeWrapper::has_icon(const std::string& value) {
|
|||||||
return Gtk::IconTheme::get_default()->has_icon(value);
|
return Gtk::IconTheme::get_default()->has_icon(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::RefPtr<Gdk::Pixbuf> DefaultGtkIconThemeWrapper::load_icon(const char* name, int tmp_size,
|
Glib::RefPtr<Gdk::Pixbuf> DefaultGtkIconThemeWrapper::load_icon(
|
||||||
Gtk::IconLookupFlags flags) {
|
const char* name, int tmp_size, Gtk::IconLookupFlags flags,
|
||||||
|
Glib::RefPtr<Gtk::StyleContext> style) {
|
||||||
const std::lock_guard<std::mutex> lock(default_theme_mutex);
|
const std::lock_guard<std::mutex> lock(default_theme_mutex);
|
||||||
|
|
||||||
auto default_theme = Gtk::IconTheme::get_default();
|
auto default_theme = Gtk::IconTheme::get_default();
|
||||||
default_theme->rescan_if_needed();
|
default_theme->rescan_if_needed();
|
||||||
return default_theme->load_icon(name, tmp_size, flags);
|
|
||||||
|
auto icon_info = default_theme->lookup_icon(name, tmp_size, flags);
|
||||||
|
|
||||||
|
if (icon_info == nullptr) {
|
||||||
|
return default_theme->load_icon(name, tmp_size, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style.get() == nullptr) {
|
||||||
|
return icon_info.load_icon();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_sym = false;
|
||||||
|
return icon_info.load_symbolic(style, is_sym);
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,8 @@ void PrivacyNodeInfo::handleNodeEventInfo(const struct pw_node_info *info) {
|
|||||||
pipewire_access_portal_app_id = item->value;
|
pipewire_access_portal_app_id = item->value;
|
||||||
} else if (strcmp(item->key, PW_KEY_APP_ICON_NAME) == 0) {
|
} else if (strcmp(item->key, PW_KEY_APP_ICON_NAME) == 0) {
|
||||||
application_icon_name = item->value;
|
application_icon_name = item->value;
|
||||||
|
} else if (strcmp(item->key, "stream.monitor") == 0) {
|
||||||
|
is_monitor = strcmp(item->value, "true") == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,6 @@ static constexpr const char* PORTAL_NAMESPACE = "org.freedesktop.appearance";
|
|||||||
static constexpr const char* PORTAL_KEY = "color-scheme";
|
static constexpr const char* PORTAL_KEY = "color-scheme";
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|
||||||
using namespace Gio;
|
|
||||||
|
|
||||||
auto fmt::formatter<waybar::Appearance>::format(waybar::Appearance c, format_context& ctx) const {
|
auto fmt::formatter<waybar::Appearance>::format(waybar::Appearance c, format_context& ctx) const {
|
||||||
string_view name;
|
string_view name;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
@ -36,8 +34,8 @@ auto fmt::formatter<waybar::Appearance>::format(waybar::Appearance c, format_con
|
|||||||
}
|
}
|
||||||
|
|
||||||
waybar::Portal::Portal()
|
waybar::Portal::Portal()
|
||||||
: DBus::Proxy(DBus::Connection::get_sync(DBus::BusType::BUS_TYPE_SESSION), PORTAL_BUS_NAME,
|
: Gio::DBus::Proxy(Gio::DBus::Connection::get_sync(Gio::DBus::BusType::BUS_TYPE_SESSION),
|
||||||
PORTAL_OBJ_PATH, PORTAL_INTERFACE),
|
PORTAL_BUS_NAME, PORTAL_OBJ_PATH, PORTAL_INTERFACE),
|
||||||
currentMode(Appearance::UNKNOWN) {
|
currentMode(Appearance::UNKNOWN) {
|
||||||
refreshAppearance();
|
refreshAppearance();
|
||||||
};
|
};
|
||||||
|
@ -18,8 +18,10 @@
|
|||||||
return
|
return
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using namespace date;
|
||||||
using namespace std::literals::chrono_literals;
|
using namespace std::literals::chrono_literals;
|
||||||
namespace fmt_lib = waybar::util::date::format;
|
namespace fmt_lib = waybar::util::date::format;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that the date/time formatter with locale and timezone support is working as expected.
|
* Check that the date/time formatter with locale and timezone support is working as expected.
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user