Compare commits

..

48 Commits

Author SHA1 Message Date
3ecd4030e3 chore: v0.9.20 2023-07-18 08:29:32 +02:00
841a004acd fix: lint 2023-07-18 08:28:19 +02:00
839975c348 Merge pull request #2318 from calvinchd/hyprland-window-remove-empty-css
hyprland/window remove duplicate empty css
2023-07-18 08:22:27 +02:00
185aa104b0 Merge pull request #2326 from czM1K3/master
hyprland/language: Differentiating keyboard layout variants
2023-07-18 08:21:52 +02:00
b2279c9565 Differencing keyboard layout variant for hyprland/language 2023-07-17 22:20:50 +02:00
388912d4a7 Merge pull request #2324 from xytovl/fix-crash-on-resume 2023-07-17 08:26:53 +02:00
f62b3d0e9d Ensure signal is disconnected in destructor 2023-07-16 23:29:28 +02:00
1e2b9cb5ed Merge pull request #2306 from stefonarch/patch-1
Fix wrong name for {name}
2023-07-16 18:21:00 +02:00
85b4ff4f81 Merge pull request #2321 from calvinchd/hyprland-runtime-err 2023-07-16 15:10:03 +02:00
0f6eff1f20 hyprland: fix json parser runtime err from socket read ending early 2023-07-16 22:18:27 +10:00
7a5e702334 Merge pull request #2317 from m4rch3n1ng/backlight-percent 2023-07-16 09:34:47 +02:00
8687ed2068 Update man for hyprland/window to replace #window.empty with window#waybar.empty #window 2023-07-16 16:41:50 +10:00
2be0e966e1 hyprland/window: remove .empty css class for #window 2023-07-16 16:40:54 +10:00
may
facb53e81f backlight: do not convert percent to string in fmt 2023-07-16 04:14:43 +02:00
2211a79840 Merge pull request #2308 from gardenappl/hidden-fix
hyprland/window: rename .hidden to .swallowing (and fix grouped windows)
2023-07-12 18:13:50 +02:00
daca57129f hyprland/window: rename .hidden to .swallowing (and fix grouped windows) 2023-07-12 19:01:45 +03:00
19c7c0763f Merge pull request #2307 from gardenappl/hidden-fix
hyprland/window: Fix overlap with .hidden class from default style
2023-07-12 17:27:37 +02:00
14c6550593 hyprland/window: Fix overlap with .hidden class from default style 2023-07-12 17:56:12 +03:00
7aae93e7ed Fix wrong name for {name} 2023-07-12 16:31:58 +02:00
dffba78401 Merge pull request #2303 from Mr-Pine/hyprland-window-icon 2023-07-11 08:08:20 +02:00
a8a1a4985f Add removed secondary identifier
(class for xwayland under sway)
2023-07-10 23:48:18 +02:00
31683d9e2a Implemented AAppIconLabel for sway/window 2023-07-10 22:55:46 +02:00
00e143d47e Introducce AAppIconLabel class
Implemented for hyprland
2023-07-10 22:50:58 +02:00
6e9ba3fc01 Fix spacing if icon is false 2023-07-10 22:26:02 +02:00
a373f6b654 Icon working 2023-07-10 22:02:03 +02:00
91bd28d410 Merge pull request #2294 from Mr-Pine/hyprland-window-data
`hyprland/window` expose more data
2023-07-09 10:18:26 +02:00
acde076913 Merge pull request #2288 from LukashonakV/arch_cava
Arch CI cava
2023-07-09 10:17:55 +02:00
f5655526d0 Merge pull request #2296 from m-bdf/clock-tz-changes 2023-07-09 04:22:15 +02:00
56f956ff90 clock: handle timezone changes (again) 2023-07-09 01:44:39 +02:00
f97c1c7136 remove getWindowData 2023-07-08 23:22:29 +02:00
9ee883ee1b No dashes is format arg name 2023-07-08 23:11:11 +02:00
1887512ba1 Update scd 2023-07-08 22:40:16 +02:00
2ae13c4092 consitent naming 2023-07-08 22:40:16 +02:00
c5f1771375 Use already existing queryActiveWorkspace() 2023-07-08 22:40:16 +02:00
c4bace504c Separate query and struct 2023-07-08 22:40:16 +02:00
3bfeed31bc Merge pull request #2293 from sigboe/master 2023-07-08 21:47:04 +02:00
d774de6c46 fix, default to true, sway/workspaces: warp-on-scroll 2023-07-08 21:32:19 +02:00
b20041d85d cava dependencies 2023-07-08 08:41:37 +00:00
e4900db9a2 Merge pull request #2286 from calvinchd/hyprland-window-noinfo 2023-07-06 08:24:11 +02:00
e2bfa5e019 hyprland/window: fix no info with separate-outputs=true 2023-07-06 11:01:24 +10:00
423d8495e4 Merge pull request #2284 from jbeich/dbus 2023-07-05 20:17:51 +02:00
1fb2b8efd5 fix(util): don't abort modules from SleeperThread after 3c9cbc99d7
[warning] module sway/workspaces: Disabling module "sway/workspaces", Unable to connect to the SYSTEM Bus!...
[warning] module sway/mode: Disabling module "sway/mode", Unable to connect to the SYSTEM Bus!...
[warning] module sway/scratchpad: Disabling module "sway/scratchpad", Unable to connect to the SYSTEM Bus!...
[warning] module custom/media: Disabling module "custom/media", Unable to connect to the SYSTEM Bus!...
[warning] module sway/window: Disabling module "sway/window", Unable to connect to the SYSTEM Bus!...
[warning] module cpu: Disabling module "cpu", Unable to connect to the SYSTEM Bus!...
[warning] module memory: Disabling module "memory", Unable to connect to the SYSTEM Bus!...
[warning] module temperature: Disabling module "temperature", Unable to connect to the SYSTEM Bus!...
[warning] module sway/language: Disabling module "sway/language", Unable to connect to the SYSTEM Bus!...
[warning] module battery: Disabling module "battery", Unable to connect to the SYSTEM Bus!...
[warning] module battery#bat2: Disabling module "battery#bat2", Unable to connect to the SYSTEM Bus!...
2023-07-05 17:47:24 +00:00
3299d4a25c Merge pull request #2270 from gardenappl/hypr-backend
hyprland/window: Add .hidden CSS class, account for hidden & fullscreen windows
2023-07-05 08:14:49 +02:00
e125bbeb4d hyprland/window: properly check visibility for .floating class 2023-07-05 03:43:03 +03:00
55c59253d6 Update man pages 2023-07-05 03:15:59 +03:00
e7deab92c7 Merge pull request #2282 from zjeffer/fix/build-warnings
Fixed build warnings
2023-07-04 23:09:13 +02:00
d21f29cb14 Fixed build warnings 2023-07-04 23:05:26 +02:00
cdece498c1 hyprland/window: .solo class accounts for hidden & fullscreen windows 2023-07-02 20:58:42 +03:00
19 changed files with 305 additions and 173 deletions

View File

@ -3,5 +3,5 @@
FROM archlinux:base-devel
RUN pacman -Syu --noconfirm && \
pacman -S --noconfirm git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp pugixml scdoc libpulse libdbusmenu-gtk3 libmpdclient gobject-introspection libxkbcommon playerctl && \
pacman -S --noconfirm git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp pugixml scdoc libpulse libdbusmenu-gtk3 libmpdclient gobject-introspection libxkbcommon playerctl iniparser fftw && \
sed -Ei 's/#(en_(US|GB)\.UTF)/\1/' /etc/locale.gen && locale-gen

27
include/AAppIconLabel.hpp Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include <gtkmm/box.h>
#include <gtkmm/image.h>
#include "AIconLabel.hpp"
namespace waybar {
class AAppIconLabel : public AIconLabel {
public:
AAppIconLabel(const Json::Value &config, const std::string &name, const std::string &id,
const std::string &format, uint16_t interval = 0, bool ellipsize = false,
bool enable_click = false, bool enable_scroll = false);
virtual ~AAppIconLabel() = default;
auto update() -> void override;
protected:
void updateAppIconName(const std::string &app_identifier,
const std::string &alternative_app_identifier);
void updateAppIcon();
unsigned app_icon_size_{24};
bool update_app_icon_{true};
std::string app_icon_name_;
};
} // namespace waybar

View File

@ -1,13 +1,13 @@
#include <fmt/format.h>
#include "ALabel.hpp"
#include "AAppIconLabel.hpp"
#include "bar.hpp"
#include "modules/hyprland/backend.hpp"
#include "util/json.hpp"
namespace waybar::modules::hyprland {
class Window : public waybar::ALabel, public EventHandler {
class Window : public waybar::AAppIconLabel, public EventHandler {
public:
Window(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~Window();
@ -24,6 +24,19 @@ class Window : public waybar::ALabel, public EventHandler {
static auto parse(const Json::Value&) -> Workspace;
};
struct WindowData {
bool floating;
int monitor = -1;
std::string class_name;
std::string initial_class_name;
std::string title;
std::string initial_title;
bool fullscreen;
bool grouped;
static auto parse(const Json::Value&) -> WindowData;
};
auto getActiveWorkspace(const std::string&) -> Workspace;
auto getActiveWorkspace() -> Workspace;
void onEvent(const std::string&) override;
@ -34,12 +47,13 @@ class Window : public waybar::ALabel, public EventHandler {
std::mutex mutex_;
const Bar& bar_;
util::JsonParser parser_;
std::string last_title_;
WindowData window_data_;
Workspace workspace_;
std::string solo_class_;
std::string last_solo_class_;
bool solo_;
bool all_floating_;
bool swallowing_;
bool fullscreen_;
};

View File

@ -66,9 +66,9 @@ class Mpris : public ALabel {
int album_len_;
int title_len_;
int dynamic_len_;
std::string dynamic_separator_;
std::vector<std::string> dynamic_order_;
std::vector<std::string> dynamic_prio_;
std::vector<std::string> dynamic_order_;
std::string dynamic_separator_;
bool truncate_hours_;
bool tooltip_len_limits_;
std::string ellipsis_;

View File

@ -4,7 +4,7 @@
#include <tuple>
#include "AIconLabel.hpp"
#include "AAppIconLabel.hpp"
#include "bar.hpp"
#include "client.hpp"
#include "modules/sway/ipc/client.hpp"
@ -12,7 +12,7 @@
namespace waybar::modules::sway {
class Window : public AIconLabel, public sigc::trackable {
class Window : public AAppIconLabel, public sigc::trackable {
public:
Window(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~Window() = default;
@ -25,8 +25,6 @@ class Window : public AIconLabel, public sigc::trackable {
std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string>
getFocusedNode(const Json::Value& nodes, std::string& output);
void getTree();
void updateAppIconName();
void updateAppIcon();
const Bar& bar_;
std::string window_;
@ -37,9 +35,6 @@ class Window : public AIconLabel, public sigc::trackable {
std::string old_app_id_;
std::size_t app_nb_;
std::string shell_;
unsigned app_icon_size_{24};
bool update_app_icon_{true};
std::string app_icon_name_;
int floating_count_;
util::JsonParser parser_;
std::mutex mutex_;

View File

@ -95,6 +95,7 @@ class SleeperThread {
}
~SleeperThread() {
connection_.disconnect();
stop();
if (thread_.joinable()) {
thread_.join();

View File

@ -14,13 +14,28 @@ Addressed by *hyprland/window*
*format*: ++
typeof: string ++
default: {} ++
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*.
*separate-outputs*: ++
typeof: bool ++
Show the active window of the monitor the bar belongs to, instead of the focused window.
# FORMAT REPLACEMENTS
See the output of "hyprctl clients" for examples
*{title}*: The current title of the focused window.
*{initialTitle}*: The initial title of the focused window.
*{class}*: The current class of the focused window.
*{initialClass}*: The initial class of the focused window.
# REWRITE RULES
*rewrite* is an object where keys are regular expressions and values are
@ -48,3 +63,17 @@ Invalid expressions (e.g., mismatched parentheses) are skipped.
# STYLE
- *#window*
- *window#waybar.empty #window* When no windows are in 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 one tiled window is visible in the workspace
(floating windows may be present)
- *window#waybar.<app_id>* Where *<app_id>* is the *class* (e.g. *chromium*) of
the solo tiled window in the workspace (use *hyprctl clients* to see classes)
- *window#waybar.floating* When there are only floating windows in the workspace
- *window#waybar.fullscreen* When there is a fullscreen window in the workspace;
useful with Hyprland's *fullscreen, 1* mode
- *window#waybar.swallowing* When there is a swallowed window in the workspace

View File

@ -84,7 +84,7 @@ Addressed by *sway/window*
typeof: bool ++
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.
*rewrite*: ++
typeof: object ++
Rules to rewrite the module format output. See *rewrite rules*.
@ -136,6 +136,10 @@ Invalid expressions (e.g., mismatched parentheses) are skipped.
# STYLE
- *#window*
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, or screen is not focused and offscreen-css option is not set
- *window#waybar.solo* When one tiled window is in the workspace
- *window#waybar.floating* When there are only floating windows in the workspace

View File

@ -89,7 +89,7 @@ Addressed by *wlr/taskbar*
*{icon}*: The icon of the application.
*{title}*: The application name as in desktop file if appropriate desktop fils found, otherwise same as {app_id}
*{name}*: The application name as in desktop file if appropriate desktop fils found, otherwise same as {app_id}
*{title}*: The title of the application.

View File

@ -1,6 +1,6 @@
project(
'waybar', 'cpp', 'c',
version: '0.9.19',
version: '0.9.20',
license: 'MIT',
meson_version: '>= 0.50.0',
default_options : [
@ -159,6 +159,7 @@ src_files = files(
'src/AModule.cpp',
'src/ALabel.cpp',
'src/AIconLabel.cpp',
'src/AAppIconLabel.cpp',
'src/modules/custom.cpp',
'src/modules/disk.cpp',
'src/modules/idle_inhibitor.cpp',

133
src/AAppIconLabel.cpp Normal file
View File

@ -0,0 +1,133 @@
#include "AAppIconLabel.hpp"
#include <gdkmm/pixbuf.h>
#include <glibmm/fileutils.h>
#include <glibmm/keyfile.h>
#include <glibmm/miscutils.h>
#include <spdlog/spdlog.h>
#include <filesystem>
#include <optional>
#include "util/gtk_icon.hpp"
namespace waybar {
AAppIconLabel::AAppIconLabel(const Json::Value& config, const std::string& name,
const std::string& id, const std::string& format, uint16_t interval,
bool ellipsize, bool enable_click, bool enable_scroll)
: AIconLabel(config, name, id, format, interval, ellipsize, enable_click, enable_scroll) {
// Icon size
if (config["icon-size"].isUInt()) {
app_icon_size_ = config["icon-size"].asUInt();
}
image_.set_pixel_size(app_icon_size_);
}
std::optional<std::string> getDesktopFilePath(const std::string& app_identifier,
const std::string& alternative_app_identifier) {
const auto data_dirs = Glib::get_system_data_dirs();
for (const auto& data_dir : data_dirs) {
const auto data_app_dir = data_dir + "applications/";
auto desktop_file_path = data_app_dir + app_identifier + ".desktop";
if (std::filesystem::exists(desktop_file_path)) {
return desktop_file_path;
}
if (!alternative_app_identifier.empty()) {
desktop_file_path = data_app_dir + alternative_app_identifier + ".desktop";
if (std::filesystem::exists(desktop_file_path)) {
return desktop_file_path;
}
}
}
return {};
}
std::optional<Glib::ustring> getIconName(const std::string& app_identifier,
const std::string& alternative_app_identifier) {
const auto desktop_file_path = getDesktopFilePath(app_identifier, alternative_app_identifier);
if (!desktop_file_path.has_value()) {
// Try some heuristics to find a matching icon
if (DefaultGtkIconThemeWrapper::has_icon(app_identifier)) {
return app_identifier;
}
const auto app_identifier_desktop = app_identifier + "-desktop";
if (DefaultGtkIconThemeWrapper::has_icon(app_identifier_desktop)) {
return app_identifier_desktop;
}
const auto to_lower = [](const std::string& str) {
auto str_cpy = str;
std::transform(str_cpy.begin(), str_cpy.end(), str_cpy.begin(),
[](unsigned char c) { return std::tolower(c); });
return str;
};
const auto first_space = app_identifier.find_first_of(' ');
if (first_space != std::string::npos) {
const auto first_word = to_lower(app_identifier.substr(0, first_space));
if (DefaultGtkIconThemeWrapper::has_icon(first_word)) {
return first_word;
}
}
const auto first_dash = app_identifier.find_first_of('-');
if (first_dash != std::string::npos) {
const auto first_word = to_lower(app_identifier.substr(0, first_dash));
if (DefaultGtkIconThemeWrapper::has_icon(first_word)) {
return first_word;
}
}
return {};
}
try {
Glib::KeyFile desktop_file;
desktop_file.load_from_file(desktop_file_path.value());
return desktop_file.get_string("Desktop Entry", "Icon");
} catch (Glib::FileError& error) {
spdlog::warn("Error while loading desktop file {}: {}", desktop_file_path.value(),
error.what().c_str());
} catch (Glib::KeyFileError& error) {
spdlog::warn("Error while loading desktop file {}: {}", desktop_file_path.value(),
error.what().c_str());
}
return {};
}
void AAppIconLabel::updateAppIconName(const std::string& app_identifier,
const std::string& alternative_app_identifier) {
if (!iconEnabled()) {
return;
}
const auto icon_name = getIconName(app_identifier, alternative_app_identifier);
if (icon_name.has_value()) {
app_icon_name_ = icon_name.value();
} else {
app_icon_name_ = "";
}
update_app_icon_ = true;
}
void AAppIconLabel::updateAppIcon() {
if (update_app_icon_) {
update_app_icon_ = false;
if (app_icon_name_.empty()) {
image_.set_visible(false);
} else {
image_.set_from_icon_name(app_icon_name_, Gtk::ICON_SIZE_INVALID);
image_.set_visible(true);
}
}
}
auto AAppIconLabel::update() -> void {
updateAppIcon();
AIconLabel::update();
}
} // namespace waybar

View File

@ -190,9 +190,8 @@ auto waybar::modules::Backlight::update() -> void {
event_box_.show();
const uint8_t percent =
best->get_max() == 0 ? 100 : round(best->get_actual() * 100.0f / best->get_max());
std::string desc =
fmt::format(fmt::runtime(format_), fmt::arg("percent", std::to_string(percent)),
fmt::arg("icon", getIcon(percent)));
std::string desc = fmt::format(fmt::runtime(format_), fmt::arg("percent", percent),
fmt::arg("icon", getIcon(percent)));
label_.set_markup(desc);
getState(percent);
if (tooltipEnabled()) {
@ -202,7 +201,7 @@ auto waybar::modules::Backlight::update() -> void {
}
if (!tooltip_format.empty()) {
label_.set_tooltip_text(fmt::format(fmt::runtime(tooltip_format),
fmt::arg("percent", std::to_string(percent)),
fmt::arg("percent", percent),
fmt::arg("icon", getIcon(percent))));
} else {
label_.set_tooltip_text(desc);

View File

@ -24,7 +24,8 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
for (const auto& zone_name : config_["timezones"]) {
if (!zone_name.isString()) continue;
if (zone_name.asString().empty())
time_zones_.push_back(date::current_zone());
// nullptr means that local time should be shown
time_zones_.push_back(nullptr);
else
try {
time_zones_.push_back(date::locate_zone(zone_name.asString()));
@ -34,7 +35,8 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
}
} else if (config_["timezone"].isString()) {
if (config_["timezone"].asString().empty())
time_zones_.push_back(date::current_zone());
// nullptr means that local time should be shown
time_zones_.push_back(nullptr);
else
try {
time_zones_.push_back(date::locate_zone(config_["timezone"].asString()));
@ -43,10 +45,10 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
}
}
// If all timezones are parsed and no one is good, add current time zone. nullptr in timezones
// vector means that local time should be shown
// If all timezones are parsed and no one is good
if (!time_zones_.size()) {
time_zones_.push_back(date::current_zone());
// nullptr means that local time should be shown
time_zones_.push_back(nullptr);
}
// Check if a particular placeholder is present in the tooltip format, to know what to calculate
@ -156,8 +158,7 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
}
const date::time_zone* waybar::modules::Clock::current_timezone() {
return time_zones_[current_time_zone_idx_] ? time_zones_[current_time_zone_idx_]
: date::current_zone();
return is_timezone_fixed() ? time_zones_[current_time_zone_idx_] : date::current_zone();
}
bool waybar::modules::Clock::is_timezone_fixed() {

View File

@ -192,7 +192,7 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
return "";
}
response.append(buffer, sizeWritten);
} while (sizeWritten == 8192);
} while (sizeWritten > 0);
close(SERVERSOCKET);
return response;

View File

@ -38,7 +38,10 @@ auto Language::update() -> void {
std::lock_guard<std::mutex> lg(mutex_);
std::string layoutName = std::string{};
if (config_.isMember("format-" + layout_.short_description)) {
if (config_.isMember("format-" + layout_.short_description + "-" + layout_.variant)) {
const auto propName = "format-" + layout_.short_description + "-" + layout_.variant;
layoutName = fmt::format(fmt::runtime(format_), config_[propName].asString());
} else if (config_.isMember("format-" + layout_.short_description)) {
const auto propName = "format-" + layout_.short_description;
layoutName = fmt::format(fmt::runtime(format_), config_[propName].asString());
} else {

View File

@ -1,5 +1,8 @@
#include "modules/hyprland/window.hpp"
#include <glibmm/fileutils.h>
#include <glibmm/keyfile.h>
#include <glibmm/miscutils.h>
#include <spdlog/spdlog.h>
#include <algorithm>
@ -8,13 +11,12 @@
#include <vector>
#include "modules/hyprland/backend.hpp"
#include "util/json.hpp"
#include "util/rewrite_string.hpp"
namespace waybar::modules::hyprland {
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
: ALabel(config, "window", id, "{}", 0, true), bar_(bar) {
: AAppIconLabel(config, "window", id, "{title}", 0, true), bar_(bar) {
modulesReady = true;
separate_outputs = config["separate-outputs"].asBool();
@ -44,28 +46,27 @@ auto Window::update() -> void {
std::lock_guard<std::mutex> lg(mutex_);
std::string window_name = waybar::util::sanitize_string(workspace_.last_window_title);
std::string window_address = workspace_.last_window;
if (window_name != last_title_) {
if (window_name.empty()) {
label_.get_style_context()->add_class("empty");
} else {
label_.get_style_context()->remove_class("empty");
}
last_title_ = window_name;
}
window_data_.title = window_name;
if (!format_.empty()) {
label_.show();
label_.set_markup(fmt::format(fmt::runtime(format_),
waybar::util::rewriteString(window_name, config_["rewrite"])));
label_.set_markup(waybar::util::rewriteString(
fmt::format(fmt::runtime(format_), fmt::arg("title", window_name),
fmt::arg("initialTitle", window_data_.initial_title),
fmt::arg("class", window_data_.class_name),
fmt::arg("initialClass", window_data_.initial_class_name)),
config_["rewrite"]));
} else {
label_.hide();
}
setClass("empty", workspace_.windows == 0);
setClass("solo", solo_);
setClass("fullscreen", fullscreen_);
setClass("floating", all_floating_);
setClass("swallowing", swallowing_);
setClass("fullscreen", fullscreen_);
if (!last_solo_class_.empty() && solo_class_ != last_solo_class_) {
if (bar_.window.get_style_context()->has_class(last_solo_class_)) {
@ -80,7 +81,7 @@ auto Window::update() -> void {
}
last_solo_class_ = solo_class_;
ALabel::update();
AAppIconLabel::update();
}
auto Window::getActiveWorkspace() -> Workspace {
@ -102,9 +103,9 @@ auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
const auto workspaces = gIPC->getSocket1JsonReply("workspaces");
assert(workspaces.isArray());
auto workspace = std::find_if(monitors.begin(), monitors.end(),
auto workspace = std::find_if(workspaces.begin(), workspaces.end(),
[&](Json::Value workspace) { return workspace["id"] == id; });
if (workspace == std::end(monitors)) {
if (workspace == std::end(workspaces)) {
spdlog::warn("No workspace with id {}", id);
return Workspace{-1, 0, "", ""};
}
@ -116,6 +117,13 @@ auto Window::Workspace::parse(const Json::Value& value) -> Window::Workspace {
value["lastwindowtitle"].asString()};
}
auto Window::WindowData::parse(const Json::Value& value) -> Window::WindowData {
return WindowData{value["floating"].asBool(), value["monitor"].asInt(),
value["class"].asString(), value["initialClass"].asString(),
value["title"].asString(), value["initialTitle"].asString(),
value["fullscreen"].asBool(), !value["grouped"].empty()};
}
void Window::queryActiveWorkspace() {
std::lock_guard<std::mutex> lg(mutex_);
@ -126,36 +134,57 @@ void Window::queryActiveWorkspace() {
}
if (workspace_.windows > 0) {
const auto clients = gIPC->getSocket1Reply("j/clients");
Json::Value json = parser_.parse(clients);
assert(json.isArray());
auto active_window = std::find_if(json.begin(), json.end(), [&](Json::Value window) {
const auto clients = gIPC->getSocket1JsonReply("clients");
assert(clients.isArray());
auto active_window = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) {
return window["address"] == workspace_.last_window;
});
if (active_window == std::end(json)) {
if (active_window == std::end(clients)) {
return;
}
if (workspace_.windows == 1 && !(*active_window)["floating"].asBool()) {
solo_class_ = (*active_window)["class"].asString();
} else {
solo_class_ = "";
}
window_data_ = WindowData::parse(*active_window);
updateAppIconName(window_data_.class_name, window_data_.initial_class_name);
std::vector<Json::Value> workspace_windows;
std::copy_if(json.begin(), json.end(), std::back_inserter(workspace_windows),
std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspace_windows),
[&](Json::Value window) {
return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool();
});
solo_ = 1 == std::count_if(workspace_windows.begin(), workspace_windows.end(),
swallowing_ = std::any_of(workspace_windows.begin(), workspace_windows.end(),
[&](Json::Value window) { return !window["swallowing"].isNull(); });
std::vector<Json::Value> visible_windows;
std::copy_if(workspace_windows.begin(), workspace_windows.end(),
std::back_inserter(visible_windows),
[&](Json::Value window) { return !window["hidden"].asBool(); });
solo_ = 1 == std::count_if(visible_windows.begin(), visible_windows.end(),
[&](Json::Value window) { return !window["floating"].asBool(); });
all_floating_ = std::all_of(workspace_windows.begin(), workspace_windows.end(),
all_floating_ = std::all_of(visible_windows.begin(), visible_windows.end(),
[&](Json::Value window) { return window["floating"].asBool(); });
fullscreen_ = (*active_window)["fullscreen"].asBool();
fullscreen_ = window_data_.fullscreen;
// Fullscreen windows look like they are solo
if (fullscreen_) {
solo_ = true;
}
// Grouped windows have a tab bar and therefore don't look fullscreen or solo
if (window_data_.grouped) {
fullscreen_ = false;
solo_ = false;
}
if (solo_) {
solo_class_ = window_data_.class_name;
} else {
solo_class_ = "";
}
} else {
solo_class_ = "";
solo_ = false;
window_data_ = WindowData{};
all_floating_ = false;
swallowing_ = false;
fullscreen_ = false;
solo_ = false;
solo_class_ = "";
}
}

View File

@ -17,13 +17,7 @@
namespace waybar::modules::sway {
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
: AIconLabel(config, "window", id, "{}", 0, true), bar_(bar), windowId_(-1) {
// Icon size
if (config_["icon-size"].isUInt()) {
app_icon_size_ = config["icon-size"].asUInt();
}
image_.set_pixel_size(app_icon_size_);
: AAppIconLabel(config, "window", id, "{}", 0, true), bar_(bar), windowId_(-1) {
ipc_.subscribe(R"(["window","workspace"])");
ipc_.signal_event.connect(sigc::mem_fun(*this, &Window::onEvent));
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Window::onCmd));
@ -49,7 +43,7 @@ void Window::onCmd(const struct Ipc::ipc_response& res) {
auto output = payload["output"].isString() ? payload["output"].asString() : "";
std::tie(app_nb_, floating_count_, windowId_, window_, app_id_, app_class_, shell_, layout_) =
getFocusedNode(payload["nodes"], output);
updateAppIconName();
updateAppIconName(app_id_, app_class_);
dp.emit();
} catch (const std::exception& e) {
spdlog::error("Window: {}", e.what());
@ -57,105 +51,6 @@ void Window::onCmd(const struct Ipc::ipc_response& res) {
}
}
std::optional<std::string> getDesktopFilePath(const std::string& app_id,
const std::string& app_class) {
const auto data_dirs = Glib::get_system_data_dirs();
for (const auto& data_dir : data_dirs) {
const auto data_app_dir = data_dir + "applications/";
auto desktop_file_path = data_app_dir + app_id + ".desktop";
if (std::filesystem::exists(desktop_file_path)) {
return desktop_file_path;
}
if (!app_class.empty()) {
desktop_file_path = data_app_dir + app_class + ".desktop";
if (std::filesystem::exists(desktop_file_path)) {
return desktop_file_path;
}
}
}
return {};
}
std::optional<Glib::ustring> getIconName(const std::string& app_id, const std::string& app_class) {
const auto desktop_file_path = getDesktopFilePath(app_id, app_class);
if (!desktop_file_path.has_value()) {
// Try some heuristics to find a matching icon
if (DefaultGtkIconThemeWrapper::has_icon(app_id)) {
return app_id;
}
const auto app_id_desktop = app_id + "-desktop";
if (DefaultGtkIconThemeWrapper::has_icon(app_id_desktop)) {
return app_id_desktop;
}
const auto to_lower = [](const std::string& str) {
auto str_cpy = str;
std::transform(str_cpy.begin(), str_cpy.end(), str_cpy.begin(),
[](unsigned char c) { return std::tolower(c); });
return str;
};
const auto first_space = app_id.find_first_of(' ');
if (first_space != std::string::npos) {
const auto first_word = to_lower(app_id.substr(0, first_space));
if (DefaultGtkIconThemeWrapper::has_icon(first_word)) {
return first_word;
}
}
const auto first_dash = app_id.find_first_of('-');
if (first_dash != std::string::npos) {
const auto first_word = to_lower(app_id.substr(0, first_dash));
if (DefaultGtkIconThemeWrapper::has_icon(first_word)) {
return first_word;
}
}
return {};
}
try {
Glib::KeyFile desktop_file;
desktop_file.load_from_file(desktop_file_path.value());
return desktop_file.get_string("Desktop Entry", "Icon");
} catch (Glib::FileError& error) {
spdlog::warn("Error while loading desktop file {}: {}", desktop_file_path.value(),
error.what().c_str());
} catch (Glib::KeyFileError& error) {
spdlog::warn("Error while loading desktop file {}: {}", desktop_file_path.value(),
error.what().c_str());
}
return {};
}
void Window::updateAppIconName() {
if (!iconEnabled()) {
return;
}
const auto icon_name = getIconName(app_id_, app_class_);
if (icon_name.has_value()) {
app_icon_name_ = icon_name.value();
} else {
app_icon_name_ = "";
}
update_app_icon_ = true;
}
void Window::updateAppIcon() {
if (update_app_icon_) {
update_app_icon_ = false;
if (app_icon_name_.empty()) {
image_.set_visible(false);
} else {
image_.set_from_icon_name(app_icon_name_, Gtk::ICON_SIZE_INVALID);
image_.set_visible(true);
}
}
}
auto Window::update() -> void {
spdlog::trace("workspace layout {}, tiled count {}, floating count {}", layout_, app_nb_,
floating_count_);
@ -210,7 +105,7 @@ auto Window::update() -> void {
updateAppIcon();
// Call parent update
AIconLabel::update();
AAppIconLabel::update();
}
void Window::setClass(std::string classname, bool enable) {

View File

@ -327,7 +327,7 @@ bool Workspaces::handleScroll(GdkEventScroll *e) {
return true;
}
}
if (!config_["warp-on-scroll"].asBool()) {
if (!config_["warp-on-scroll"].isNull() && !config_["warp-on-scroll"].asBool()) {
ipc_.sendCmd(IPC_COMMAND, fmt::format("mouse_warping none"));
}
try {
@ -335,7 +335,7 @@ bool Workspaces::handleScroll(GdkEventScroll *e) {
} catch (const std::exception &e) {
spdlog::error("Workspaces: {}", e.what());
}
if (!config_["warp-on-scroll"].asBool()) {
if (!config_["warp-on-scroll"].isNull() && !config_["warp-on-scroll"].asBool()) {
ipc_.sendCmd(IPC_COMMAND, fmt::format("mouse_warping container"));
}
return true;

View File

@ -1,6 +1,7 @@
#include "util/prepare_for_sleep.h"
#include <gio/gio.h>
#include <spdlog/spdlog.h>
namespace {
class PrepareForSleep {
@ -9,7 +10,7 @@ class PrepareForSleep {
GError *error = NULL;
login1_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
if (!login1_connection) {
throw std::runtime_error("Unable to connect to the SYSTEM Bus!...");
spdlog::warn("Unable to connect to the SYSTEM Bus!...");
} else {
login1_id = g_dbus_connection_signal_subscribe(
login1_connection, "org.freedesktop.login1", "org.freedesktop.login1.Manager",