Merge branch 'master' into darkmode
This commit is contained in:
commit
fc67558717
|
@ -91,6 +91,9 @@ class Bar {
|
|||
bool vertical = false;
|
||||
Gtk::Window window;
|
||||
|
||||
int x_global;
|
||||
int y_global;
|
||||
|
||||
#ifdef HAVE_SWAY
|
||||
std::string bar_id;
|
||||
#endif
|
||||
|
@ -102,11 +105,16 @@ class Bar {
|
|||
void setupAltFormatKeyForModule(const std::string &module_name);
|
||||
void setupAltFormatKeyForModuleList(const char *module_list_name);
|
||||
void setMode(const bar_mode &);
|
||||
void onConfigure(GdkEventConfigure *ev);
|
||||
void configureGlobalOffset(int width, int height);
|
||||
void onOutputGeometryChanged();
|
||||
|
||||
/* Copy initial set of modes to allow customization */
|
||||
bar_mode_map configured_modes = PRESET_MODES;
|
||||
std::string last_mode_{MODE_DEFAULT};
|
||||
|
||||
struct bar_margins margins_;
|
||||
|
||||
std::unique_ptr<BarSurface> surface_impl_;
|
||||
Gtk::Box left_;
|
||||
Gtk::Box center_;
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "util/json.hpp"
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ALabel.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "modules/hyprland/backend.hpp"
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ALabel.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "modules/hyprland/backend.hpp"
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "AAppIconLabel.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "modules/hyprland/backend.hpp"
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <gtkmm/button.h>
|
||||
#include <gtkmm/label.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "AModule.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "modules/hyprland/backend.hpp"
|
||||
#include "util/enum.hpp"
|
||||
|
||||
namespace waybar::modules::hyprland {
|
||||
|
||||
class Workspaces;
|
||||
|
||||
class Workspace {
|
||||
public:
|
||||
Workspace(const Json::Value& workspace_data);
|
||||
explicit Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager);
|
||||
std::string& select_icon(std::map<std::string, std::string>& icons_map);
|
||||
Gtk::Button& button() { return button_; };
|
||||
|
||||
|
@ -21,6 +29,7 @@ class Workspace {
|
|||
bool active() const { return active_; };
|
||||
bool is_special() const { return is_special_; };
|
||||
bool is_persistent() const { return is_persistent_; };
|
||||
bool is_visible() const { return is_visible_; };
|
||||
bool is_empty() const { return windows_ == 0; };
|
||||
bool is_urgent() const { return is_urgent_; };
|
||||
|
||||
|
@ -28,11 +37,15 @@ class Workspace {
|
|||
void set_active(bool value = true) { active_ = value; };
|
||||
void set_persistent(bool value = true) { is_persistent_ = value; };
|
||||
void set_urgent(bool value = true) { is_urgent_ = value; };
|
||||
void set_visible(bool value = true) { is_visible_ = value; };
|
||||
void set_windows(uint value) { windows_ = value; };
|
||||
void set_name(std::string value) { name_ = value; };
|
||||
|
||||
void update(const std::string& format, const std::string& icon);
|
||||
|
||||
private:
|
||||
Workspaces& workspace_manager_;
|
||||
|
||||
int id_;
|
||||
std::string name_;
|
||||
std::string output_;
|
||||
|
@ -41,6 +54,7 @@ class Workspace {
|
|||
bool is_special_ = false;
|
||||
bool is_persistent_ = false;
|
||||
bool is_urgent_ = false;
|
||||
bool is_visible_ = false;
|
||||
|
||||
Gtk::Button button_;
|
||||
Gtk::Box content_;
|
||||
|
@ -56,6 +70,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||
|
||||
auto all_outputs() const -> bool { return all_outputs_; }
|
||||
auto show_special() const -> bool { return show_special_; }
|
||||
auto active_only() const -> bool { return active_only_; }
|
||||
|
||||
auto get_bar_output() const -> std::string { return bar_.output->name; }
|
||||
|
||||
|
@ -66,9 +81,20 @@ class Workspaces : public AModule, public EventHandler {
|
|||
void create_workspace(Json::Value& value);
|
||||
void remove_workspace(std::string name);
|
||||
void set_urgent_workspace(std::string windowaddress);
|
||||
void parse_config(const Json::Value& config);
|
||||
void register_ipc();
|
||||
|
||||
bool all_outputs_ = false;
|
||||
bool show_special_ = false;
|
||||
bool active_only_ = false;
|
||||
|
||||
enum class SORT_METHOD { ID, NAME, NUMBER, DEFAULT };
|
||||
util::EnumParser<SORT_METHOD> enum_parser_;
|
||||
SORT_METHOD sort_by_ = SORT_METHOD::DEFAULT;
|
||||
std::map<std::string, SORT_METHOD> sort_map_ = {{"ID", SORT_METHOD::ID},
|
||||
{"NAME", SORT_METHOD::NAME},
|
||||
{"NUMBER", SORT_METHOD::NUMBER},
|
||||
{"DEFAULT", SORT_METHOD::DEFAULT}};
|
||||
|
||||
void fill_persistent_workspaces();
|
||||
void create_persistent_workspaces();
|
||||
|
|
|
@ -84,6 +84,8 @@ class Item : public sigc::trackable {
|
|||
// visibility of items with Status == Passive
|
||||
bool show_passive_ = false;
|
||||
|
||||
const Bar& bar_;
|
||||
|
||||
Glib::RefPtr<Gio::DBus::Proxy> proxy_;
|
||||
Glib::RefPtr<Gio::Cancellable> cancellable_;
|
||||
std::set<std::string_view> update_pending_;
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace waybar::util {
|
||||
|
||||
template <typename EnumType>
|
||||
struct EnumParser {
|
||||
public:
|
||||
EnumParser();
|
||||
~EnumParser();
|
||||
|
||||
EnumType parseStringToEnum(const std::string& str,
|
||||
const std::map<std::string, EnumType>& enumMap);
|
||||
};
|
||||
|
||||
} // namespace waybar::util
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
const std::string WHITESPACE = " \n\r\t\f\v";
|
||||
|
@ -15,3 +16,10 @@ inline std::string rtrim(const std::string& s) {
|
|||
}
|
||||
|
||||
inline std::string trim(const std::string& s) { return rtrim(ltrim(s)); }
|
||||
|
||||
inline std::string capitalize(const std::string& str) {
|
||||
std::string result = str;
|
||||
std::transform(result.begin(), result.end(), result.begin(),
|
||||
[](unsigned char c) { return std::toupper(c); });
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -24,13 +24,26 @@ Addressed by *hyprland/workspaces*
|
|||
*show-special*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to true special workspaces will be shown.
|
||||
If set to true, special workspaces will be shown.
|
||||
|
||||
*all-outputs*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to false workspaces group will be shown only in assigned output. Otherwise all workspace groups are shown.
|
||||
|
||||
*active-only*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to true, only the active workspace will be shown.
|
||||
|
||||
*sort-by*: ++
|
||||
typeof: string ++
|
||||
default: "default" ++
|
||||
If set to number, workspaces will sort by number.
|
||||
If set to name, workspaces will sort by name.
|
||||
If set to id, workspaces will sort by id.
|
||||
If none of those, workspaces will sort with default behavior.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{id}*: id of workspace assigned by compositor
|
||||
|
@ -43,10 +56,11 @@ Addressed by *hyprland/workspaces*
|
|||
|
||||
Additional to workspace name matching, the following *format-icons* can be set.
|
||||
|
||||
- *default*: Will be shown, when no string match is found.
|
||||
- *default*: Will be shown, when no string match is found and none of the below conditions have defined icons.
|
||||
- *active*: Will be shown, when workspace is active
|
||||
- *special*: Will be shown on non-active special workspaces
|
||||
- *empty*: Will be shown on empty persistent workspaces
|
||||
- *empty*: Will be shown on non-active, non-special empty persistent workspaces
|
||||
- *visible*: Will be shown on workspaces that are visible but not active. For example: this is useful if you want your visible workspaces on other monitors to have the same look as active.
|
||||
- *persistent*: Will be shown on non-empty persistent workspaces
|
||||
|
||||
# EXAMPLES
|
||||
|
@ -63,7 +77,7 @@ Additional to workspace name matching, the following *format-icons* can be set.
|
|||
"active": "",
|
||||
"default": ""
|
||||
},
|
||||
"persistent_workspaces": {
|
||||
"persistent-workspaces": {
|
||||
"*": 5, // 5 workspaces by default on every monitor
|
||||
"HDMI-A-1": 3 // but only three on HDMI-A-1
|
||||
}
|
||||
|
@ -82,7 +96,7 @@ Additional to workspace name matching, the following *format-icons* can be set.
|
|||
"active": "",
|
||||
"default": ""
|
||||
},
|
||||
"persistent_workspaces": {
|
||||
"persistent-workspaces": {
|
||||
"*": [ 2,3,4,5 ], // 2-5 on every monitor
|
||||
"HDMI-A-1": [ 1 ] // but only workspace 1 on HDMI-A-1
|
||||
}
|
||||
|
@ -95,6 +109,7 @@ Additional to workspace name matching, the following *format-icons* can be set.
|
|||
- *#workspaces button*
|
||||
- *#workspaces button.active*
|
||||
- *#workspaces button.empty*
|
||||
- *#workspaces button.visible*
|
||||
- *#workspaces button.persistent*
|
||||
- *#workspaces button.special*
|
||||
- *#workspaces button.urgent*
|
||||
|
|
|
@ -60,7 +60,7 @@ Addressed by *sway/workspaces*
|
|||
default: false ++
|
||||
If set to true. Only focused workspaces will be shown.
|
||||
|
||||
*persistent_workspaces*: ++
|
||||
*persistent-workspaces*: ++
|
||||
typeof: json (see below) ++
|
||||
default: empty ++
|
||||
Lists workspaces that should always be shown, even when non existent
|
||||
|
@ -112,7 +112,7 @@ an empty list denoting all outputs.
|
|||
|
||||
```
|
||||
"sway/workspaces": {
|
||||
"persistent_workspaces": {
|
||||
"persistent-workspaces": {
|
||||
"3": [], // Always show a workspace with name '3', on all outputs if it does not exists
|
||||
"4": ["eDP-1"], // Always show a workspace with name '4', on output 'eDP-1' if it does not exists
|
||||
"5": ["eDP-1", "DP-2"] // Always show a workspace with name '5', on outputs 'eDP-1' and 'DP-2' if it does not exists
|
||||
|
|
|
@ -273,28 +273,39 @@ Valid options for the (optional) "orientation" property are: "horizontal", "vert
|
|||
- *waybar-cpu(5)*
|
||||
- *waybar-custom(5)*
|
||||
- *waybar-disk(5)*
|
||||
- *waybar-dwl-tags(5)*
|
||||
- *waybar-gamemode(5)*
|
||||
- *waybar-hyprland-language(5)*
|
||||
- *waybar-hyprland-submap(5)*
|
||||
- *waybar-hyprland-window(5)*
|
||||
- *waybar-hyprland-workspaces(5)*
|
||||
- *waybar-idle-inhibitor(5)*
|
||||
- *waybar-image(5)*
|
||||
- *waybar-inhibitor(5)*
|
||||
- *waybar-jack(5)*
|
||||
- *waybar-keyboard-state(5)*
|
||||
- *waybar-memory(5)*
|
||||
- *waybar-mpd(5)*
|
||||
- *waybar-mpris(5)*
|
||||
- *waybar-network(5)*
|
||||
- *waybar-pulseaudio(5)*
|
||||
- *waybar-river-layout(5)*
|
||||
- *waybar-river-mode(5)*
|
||||
- *waybar-river-tags(5)*
|
||||
- *waybar-river-window(5)*
|
||||
- *waybar-river-layout(5)*
|
||||
- *waybar-sndio(5)*
|
||||
- *waybar-states(5)*
|
||||
- *waybar-sway-language(5)*
|
||||
- *waybar-sway-mode(5)*
|
||||
- *waybar-sway-scratchpad(5)*
|
||||
- *waybar-sway-window(5)*
|
||||
- *waybar-sway-workspaces(5)*
|
||||
- *waybar-temperature(5)*
|
||||
- *waybar-tray(5)*
|
||||
- *waybar-upower(5)*
|
||||
- *waybar-wireplumber(5)*
|
||||
- *waybar-wlr-taskbar(5)*
|
||||
- *waybar-wlr-workspaces(5)*
|
||||
- *waybar-temperature(5)*
|
||||
- *waybar-tray(5)*
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
|
|
|
@ -172,6 +172,7 @@ src_files = files(
|
|||
'src/config.cpp',
|
||||
'src/group.cpp',
|
||||
'src/util/portal.cpp',
|
||||
'src/util/enum.cpp',
|
||||
'src/util/prepare_for_sleep.cpp',
|
||||
'src/util/ustring_clen.cpp',
|
||||
'src/util/sanitize_str.cpp',
|
||||
|
|
54
src/bar.cpp
54
src/bar.cpp
|
@ -481,6 +481,9 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
|||
: output(w_output),
|
||||
config(w_config),
|
||||
window{Gtk::WindowType::WINDOW_TOPLEVEL},
|
||||
x_global(0),
|
||||
y_global(0),
|
||||
margins_{.top = 0, .right = 0, .bottom = 0, .left = 0},
|
||||
left_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||
center_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||
right_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||
|
@ -516,8 +519,6 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
|||
uint32_t height = config["height"].isUInt() ? config["height"].asUInt() : 0;
|
||||
uint32_t width = config["width"].isUInt() ? config["width"].asUInt() : 0;
|
||||
|
||||
struct bar_margins margins_;
|
||||
|
||||
if (config["margin-top"].isInt() || config["margin-right"].isInt() ||
|
||||
config["margin-bottom"].isInt() || config["margin-left"].isInt()) {
|
||||
margins_ = {
|
||||
|
@ -563,6 +564,10 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
|||
margins_ = {.top = gaps, .right = gaps, .bottom = gaps, .left = gaps};
|
||||
}
|
||||
|
||||
window.signal_configure_event().connect_notify(sigc::mem_fun(*this, &Bar::onConfigure));
|
||||
output->monitor->property_geometry().signal_changed().connect(
|
||||
sigc::mem_fun(*this, &Bar::onOutputGeometryChanged));
|
||||
|
||||
#ifdef HAVE_GTK_LAYER_SHELL
|
||||
bool use_gls = config["gtk-layer-shell"].isBool() ? config["gtk-layer-shell"].asBool() : true;
|
||||
if (use_gls) {
|
||||
|
@ -674,6 +679,7 @@ void waybar::Bar::onMap(GdkEventAny*) {
|
|||
*/
|
||||
auto gdk_window = window.get_window()->gobj();
|
||||
surface = gdk_wayland_window_get_wl_surface(gdk_window);
|
||||
configureGlobalOffset(gdk_window_get_width(gdk_window), gdk_window_get_height(gdk_window));
|
||||
}
|
||||
|
||||
void waybar::Bar::setVisible(bool value) {
|
||||
|
@ -815,3 +821,47 @@ auto waybar::Bar::setupWidgets() -> void {
|
|||
right_.pack_end(*module, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
void waybar::Bar::onConfigure(GdkEventConfigure* ev) {
|
||||
configureGlobalOffset(ev->width, ev->height);
|
||||
}
|
||||
|
||||
void waybar::Bar::configureGlobalOffset(int width, int height) {
|
||||
auto monitor_geometry = *output->monitor->property_geometry().get_value().gobj();
|
||||
auto position = config["position"].asString();
|
||||
int x;
|
||||
int y;
|
||||
if (position == "bottom") {
|
||||
if (width + margins_.left + margins_.right >= monitor_geometry.width)
|
||||
x = margins_.left;
|
||||
else
|
||||
x = (monitor_geometry.width - width) / 2;
|
||||
y = monitor_geometry.height - height - margins_.bottom;
|
||||
} else if (position == "left") {
|
||||
x = margins_.left;
|
||||
if (height + margins_.top + margins_.bottom >= monitor_geometry.height)
|
||||
y = margins_.top;
|
||||
else
|
||||
y = (monitor_geometry.height - height) / 2;
|
||||
} else if (position == "right") {
|
||||
x = monitor_geometry.width - width - margins_.right;
|
||||
if (height + margins_.top + margins_.bottom >= monitor_geometry.height)
|
||||
y = margins_.top;
|
||||
else
|
||||
y = (monitor_geometry.height - height) / 2;
|
||||
} else {
|
||||
// position is top
|
||||
if (width + margins_.left + margins_.right >= monitor_geometry.width)
|
||||
x = margins_.left;
|
||||
else
|
||||
x = (monitor_geometry.width - width) / 2;
|
||||
y = margins_.top;
|
||||
}
|
||||
|
||||
x_global = x + monitor_geometry.x;
|
||||
y_global = y + monitor_geometry.y;
|
||||
}
|
||||
|
||||
void waybar::Bar::onOutputGeometryChanged() {
|
||||
configureGlobalOffset(window.get_width(), window.get_height());
|
||||
}
|
||||
|
|
|
@ -534,6 +534,13 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
|
|||
}
|
||||
}
|
||||
|
||||
// Handle weighted-average
|
||||
if ((config_["weighted-average"].isBool() ? config_["weighted-average"].asBool() : false) &&
|
||||
total_energy_exists && total_energy_full_exists) {
|
||||
if (total_energy_full > 0.0f)
|
||||
calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full);
|
||||
}
|
||||
|
||||
// Handle design-capacity
|
||||
if ((config_["design-capacity"].isBool() ? config_["design-capacity"].asBool() : false) &&
|
||||
total_energy_exists && total_energy_full_design_exists) {
|
||||
|
|
|
@ -166,9 +166,15 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
|
|||
|
||||
std::string socketPath = "/tmp/hypr/" + instanceSigStr + "/.socket.sock";
|
||||
|
||||
strcpy(serverAddress.sun_path, socketPath.c_str());
|
||||
// Use snprintf to copy the socketPath string into serverAddress.sun_path
|
||||
if (snprintf(serverAddress.sun_path, sizeof(serverAddress.sun_path), "%s", socketPath.c_str()) <
|
||||
0) {
|
||||
spdlog::error("Hyprland IPC: Couldn't copy socket path (6)");
|
||||
return "";
|
||||
}
|
||||
|
||||
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
|
||||
if (connect(SERVERSOCKET, reinterpret_cast<sockaddr*>(&serverAddress), sizeof(serverAddress)) <
|
||||
0) {
|
||||
spdlog::error("Hyprland IPC: Couldn't connect to " + socketPath + ". (3)");
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbregistry.h>
|
||||
|
||||
#include <util/sanitize_str.hpp>
|
||||
|
||||
#include "util/sanitize_str.hpp"
|
||||
#include "util/string.hpp"
|
||||
|
||||
namespace waybar::modules::hyprland {
|
||||
|
@ -97,7 +96,6 @@ void Language::initLanguage() {
|
|||
spdlog::debug("hyprland language initLanguage found {}", layout_.full_name);
|
||||
|
||||
dp.emit();
|
||||
|
||||
} catch (std::exception& e) {
|
||||
spdlog::error("hyprland language initLanguage failed with {}", e.what());
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <util/sanitize_str.hpp>
|
||||
#include "util/sanitize_str.hpp"
|
||||
|
||||
namespace waybar::modules::hyprland {
|
||||
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
#include <util/sanitize_str.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include "modules/hyprland/backend.hpp"
|
||||
#include "util/rewrite_string.hpp"
|
||||
#include "util/sanitize_str.hpp"
|
||||
|
||||
namespace waybar::modules::hyprland {
|
||||
|
||||
|
|
|
@ -14,6 +14,20 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
|
|||
: AModule(config, "workspaces", id, false, false),
|
||||
bar_(bar),
|
||||
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) {
|
||||
parse_config(config);
|
||||
|
||||
box_.set_name("workspaces");
|
||||
if (!id.empty()) {
|
||||
box_.get_style_context()->add_class(id);
|
||||
}
|
||||
event_box_.add(box_);
|
||||
|
||||
register_ipc();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
auto Workspaces::parse_config(const Json::Value &config) -> void {
|
||||
Json::Value config_format = config["format"];
|
||||
|
||||
format_ = config_format.isString() ? config_format.asString() : "{name}";
|
||||
|
@ -38,23 +52,37 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
|
|||
show_special_ = config_show_special.asBool();
|
||||
}
|
||||
|
||||
box_.set_name("workspaces");
|
||||
if (!id.empty()) {
|
||||
box_.get_style_context()->add_class(id);
|
||||
auto config_active_only = config_["active-only"];
|
||||
if (config_active_only.isBool()) {
|
||||
active_only_ = config_active_only.asBool();
|
||||
}
|
||||
event_box_.add(box_);
|
||||
|
||||
auto config_sort_by = config_["sort-by"];
|
||||
if (config_sort_by.isString()) {
|
||||
auto sort_by_str = config_sort_by.asString();
|
||||
try {
|
||||
sort_by_ = enum_parser_.parseStringToEnum(sort_by_str, sort_map_);
|
||||
} catch (const std::invalid_argument &e) {
|
||||
// Handle the case where the string is not a valid enum representation.
|
||||
sort_by_ = SORT_METHOD::DEFAULT;
|
||||
g_warning("Invalid string representation for sort-by. Falling back to default sort method.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Workspaces::register_ipc() -> void {
|
||||
modulesReady = true;
|
||||
|
||||
if (!gIPC) {
|
||||
gIPC = std::make_unique<IPC>();
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
gIPC->registerForIPC("workspace", this);
|
||||
gIPC->registerForIPC("createworkspace", this);
|
||||
gIPC->registerForIPC("destroyworkspace", this);
|
||||
gIPC->registerForIPC("focusedmon", this);
|
||||
gIPC->registerForIPC("moveworkspace", this);
|
||||
gIPC->registerForIPC("renameworkspace", this);
|
||||
gIPC->registerForIPC("openwindow", this);
|
||||
gIPC->registerForIPC("closewindow", this);
|
||||
gIPC->registerForIPC("movewindow", this);
|
||||
|
@ -74,11 +102,29 @@ auto Workspaces::update() -> void {
|
|||
|
||||
workspaces_to_create_.clear();
|
||||
|
||||
// get all active workspaces
|
||||
auto monitors = gIPC->getSocket1JsonReply("monitors");
|
||||
std::vector<std::string> visible_workspaces;
|
||||
for (Json::Value &monitor : monitors) {
|
||||
auto ws = monitor["activeWorkspace"];
|
||||
if (ws.isObject() && (ws["name"].isString())) {
|
||||
visible_workspaces.push_back(ws["name"].asString());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &workspace : workspaces_) {
|
||||
// active
|
||||
workspace->set_active(workspace->name() == active_workspace_name_);
|
||||
if (workspace->name() == active_workspace_name_ && workspace.get()->is_urgent()) {
|
||||
// disable urgency if workspace is active
|
||||
if (workspace->name() == active_workspace_name_ && workspace->is_urgent()) {
|
||||
workspace->set_urgent(false);
|
||||
}
|
||||
|
||||
// visible
|
||||
workspace->set_visible(std::find(visible_workspaces.begin(), visible_workspaces.end(),
|
||||
workspace->name()) != visible_workspaces.end());
|
||||
|
||||
// set workspace icon
|
||||
std::string &workspace_icon = icons_map_[""];
|
||||
if (with_icon_) {
|
||||
workspace_icon = workspace->select_icon(icons_map_);
|
||||
|
@ -102,9 +148,10 @@ void Workspaces::onEvent(const std::string &ev) {
|
|||
} else if (eventName == "createworkspace") {
|
||||
const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces");
|
||||
for (Json::Value workspace_json : workspaces_json) {
|
||||
if (workspace_json["name"].asString() == payload &&
|
||||
std::string name = workspace_json["name"].asString();
|
||||
if (name == payload &&
|
||||
(all_outputs() || bar_.output->name == workspace_json["monitor"].asString()) &&
|
||||
(show_special() || !workspace_json["name"].asString().starts_with("special"))) {
|
||||
(show_special() || !name.starts_with("special"))) {
|
||||
workspaces_to_create_.push_back(workspace_json);
|
||||
break;
|
||||
}
|
||||
|
@ -119,8 +166,8 @@ void Workspaces::onEvent(const std::string &ev) {
|
|||
if (bar_.output->name == new_output) { // TODO: implement this better
|
||||
const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces");
|
||||
for (Json::Value workspace_json : workspaces_json) {
|
||||
if (workspace_json["name"].asString() == workspace &&
|
||||
bar_.output->name == workspace_json["monitor"].asString()) {
|
||||
std::string name = workspace_json["name"].asString();
|
||||
if (name == workspace && bar_.output->name == workspace_json["monitor"].asString()) {
|
||||
workspaces_to_create_.push_back(workspace_json);
|
||||
break;
|
||||
}
|
||||
|
@ -132,6 +179,19 @@ void Workspaces::onEvent(const std::string &ev) {
|
|||
update_window_count();
|
||||
} else if (eventName == "urgent") {
|
||||
set_urgent_workspace(payload);
|
||||
} else if (eventName == "renameworkspace") {
|
||||
std::string workspace_id_str = payload.substr(0, payload.find(','));
|
||||
int workspace_id = workspace_id_str == "special" ? -99 : std::stoi(workspace_id_str);
|
||||
std::string new_name = payload.substr(payload.find(',') + 1);
|
||||
for (auto &workspace : workspaces_) {
|
||||
if (workspace->id() == workspace_id) {
|
||||
if (workspace->name() == active_workspace_name_) {
|
||||
active_workspace_name_ = new_name;
|
||||
}
|
||||
workspace->set_name(new_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dp.emit();
|
||||
|
@ -143,15 +203,15 @@ void Workspaces::update_window_count() {
|
|||
auto workspace_json = std::find_if(
|
||||
workspaces_json.begin(), workspaces_json.end(),
|
||||
[&](Json::Value const &x) { return x["name"].asString() == workspace->name(); });
|
||||
uint32_t count = 0;
|
||||
if (workspace_json != workspaces_json.end()) {
|
||||
try {
|
||||
workspace->set_windows((*workspace_json)["windows"].asUInt());
|
||||
count = (*workspace_json)["windows"].asUInt();
|
||||
} catch (const std::exception &e) {
|
||||
spdlog::error("Failed to update window count: {}", e.what());
|
||||
}
|
||||
} else {
|
||||
workspace->set_windows(0);
|
||||
}
|
||||
workspace->set_windows(count);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,7 +230,7 @@ void Workspaces::create_workspace(Json::Value &value) {
|
|||
}
|
||||
|
||||
// create new workspace
|
||||
workspaces_.emplace_back(std::make_unique<Workspace>(value));
|
||||
workspaces_.emplace_back(std::make_unique<Workspace>(value, *this));
|
||||
Gtk::Button &new_workspace_button = workspaces_.back()->button();
|
||||
box_.pack_start(new_workspace_button, false, false);
|
||||
sort_workspaces();
|
||||
|
@ -196,8 +256,15 @@ void Workspaces::remove_workspace(std::string name) {
|
|||
}
|
||||
|
||||
void Workspaces::fill_persistent_workspaces() {
|
||||
if (config_["persistent_workspaces"].isObject() && !all_outputs()) {
|
||||
const Json::Value persistent_workspaces = config_["persistent_workspaces"];
|
||||
if (config_["persistent_workspaces"].isObject()) {
|
||||
spdlog::warn(
|
||||
"persistent_workspaces is deprecated. Please change config to use persistent-workspaces.");
|
||||
}
|
||||
|
||||
if (config_["persistent-workspaces"].isObject() || config_["persistent_workspaces"].isObject()) {
|
||||
const Json::Value persistent_workspaces = config_["persistent-workspaces"].isObject()
|
||||
? config_["persistent-workspaces"]
|
||||
: config_["persistent_workspaces"];
|
||||
const std::vector<std::string> keys = persistent_workspaces.getMemberNames();
|
||||
|
||||
for (const std::string &key : keys) {
|
||||
|
@ -286,8 +353,9 @@ void Workspaces::init() {
|
|||
const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces");
|
||||
for (Json::Value workspace_json : workspaces_json) {
|
||||
if ((all_outputs() || bar_.output->name == workspace_json["monitor"].asString()) &&
|
||||
(!workspace_json["name"].asString().starts_with("special") || show_special()))
|
||||
(!workspace_json["name"].asString().starts_with("special") || show_special())) {
|
||||
create_workspace(workspace_json);
|
||||
}
|
||||
}
|
||||
|
||||
update_window_count();
|
||||
|
@ -303,8 +371,9 @@ Workspaces::~Workspaces() {
|
|||
std::lock_guard<std::mutex> lg(mutex_);
|
||||
}
|
||||
|
||||
Workspace::Workspace(const Json::Value &workspace_data)
|
||||
: id_(workspace_data["id"].asInt()),
|
||||
Workspace::Workspace(const Json::Value &workspace_data, Workspaces &workspace_manager)
|
||||
: workspace_manager_(workspace_manager),
|
||||
id_(workspace_data["id"].asInt()),
|
||||
name_(workspace_data["name"].asString()),
|
||||
output_(workspace_data["monitor"].asString()), // TODO:allow using monitor desc
|
||||
windows_(workspace_data["windows"].asInt()),
|
||||
|
@ -327,7 +396,7 @@ Workspace::Workspace(const Json::Value &workspace_data)
|
|||
button_.set_relief(Gtk::RELIEF_NONE);
|
||||
content_.set_center_widget(label_);
|
||||
button_.add(content_);
|
||||
};
|
||||
}
|
||||
|
||||
void add_or_remove_class(const Glib::RefPtr<Gtk::StyleContext> &context, bool condition,
|
||||
const std::string &class_name) {
|
||||
|
@ -339,12 +408,26 @@ void add_or_remove_class(const Glib::RefPtr<Gtk::StyleContext> &context, bool co
|
|||
}
|
||||
|
||||
void Workspace::update(const std::string &format, const std::string &icon) {
|
||||
// clang-format off
|
||||
if (this->workspace_manager_.active_only() && \
|
||||
!this->active() && \
|
||||
!this->is_persistent() && \
|
||||
!this->is_visible() && \
|
||||
!this->is_special()) {
|
||||
// clang-format on
|
||||
// if active_only is true, hide if not active, persistent, visible or special
|
||||
button_.hide();
|
||||
return;
|
||||
}
|
||||
button_.show();
|
||||
|
||||
auto style_context = button_.get_style_context();
|
||||
add_or_remove_class(style_context, active(), "active");
|
||||
add_or_remove_class(style_context, is_special(), "special");
|
||||
add_or_remove_class(style_context, is_empty(), "empty");
|
||||
add_or_remove_class(style_context, is_persistent(), "persistent");
|
||||
add_or_remove_class(style_context, is_urgent(), "urgent");
|
||||
add_or_remove_class(style_context, is_visible(), "visible");
|
||||
|
||||
label_.set_markup(fmt::format(fmt::runtime(format), fmt::arg("id", id()),
|
||||
fmt::arg("name", name()), fmt::arg("icon", icon)));
|
||||
|
@ -352,36 +435,62 @@ void Workspace::update(const std::string &format, const std::string &icon) {
|
|||
|
||||
void Workspaces::sort_workspaces() {
|
||||
std::sort(workspaces_.begin(), workspaces_.end(),
|
||||
[](std::unique_ptr<Workspace> &a, std::unique_ptr<Workspace> &b) {
|
||||
// normal -> named persistent -> named -> special -> named special
|
||||
[&](std::unique_ptr<Workspace> &a, std::unique_ptr<Workspace> &b) {
|
||||
// Helper comparisons
|
||||
auto is_id_less = a->id() < b->id();
|
||||
auto is_name_less = a->name() < b->name();
|
||||
auto is_number_less = std::stoi(a->name()) < std::stoi(b->name());
|
||||
|
||||
// both normal (includes numbered persistent) => sort by ID
|
||||
if (a->id() > 0 && b->id() > 0) {
|
||||
return a->id() < b->id();
|
||||
switch (sort_by_) {
|
||||
case SORT_METHOD::ID:
|
||||
return is_id_less;
|
||||
case SORT_METHOD::NAME:
|
||||
return is_name_less;
|
||||
case SORT_METHOD::NUMBER:
|
||||
try {
|
||||
return is_number_less;
|
||||
} catch (const std::invalid_argument &) {
|
||||
// Handle the exception if necessary.
|
||||
break;
|
||||
}
|
||||
case SORT_METHOD::DEFAULT:
|
||||
default:
|
||||
// Handle the default case here.
|
||||
// normal -> named persistent -> named -> special -> named special
|
||||
|
||||
// both normal (includes numbered persistent) => sort by ID
|
||||
if (a->id() > 0 && b->id() > 0) {
|
||||
return is_id_less;
|
||||
}
|
||||
|
||||
// one normal, one special => normal first
|
||||
if ((a->is_special()) ^ (b->is_special())) {
|
||||
return b->is_special();
|
||||
}
|
||||
|
||||
// only one normal, one named
|
||||
if ((a->id() > 0) ^ (b->id() > 0)) {
|
||||
return a->id() > 0;
|
||||
}
|
||||
|
||||
// both special
|
||||
if (a->is_special() && b->is_special()) {
|
||||
// if one is -99 => put it last
|
||||
if (a->id() == -99 || b->id() == -99) {
|
||||
return b->id() == -99;
|
||||
}
|
||||
// both are 0 (not yet named persistents) / both are named specials (-98 <= ID
|
||||
// <=-1)
|
||||
return is_name_less;
|
||||
}
|
||||
|
||||
// sort non-special named workspaces by name (ID <= -1377)
|
||||
return is_name_less;
|
||||
break;
|
||||
}
|
||||
|
||||
// one normal, one special => normal first
|
||||
if ((a->is_special()) ^ (b->is_special())) {
|
||||
return b->is_special();
|
||||
}
|
||||
|
||||
// only one normal, one named
|
||||
if ((a->id() > 0) ^ (b->id() > 0)) {
|
||||
return a->id() > 0;
|
||||
}
|
||||
|
||||
// both special
|
||||
if (a->is_special() && b->is_special()) {
|
||||
// if one is -99 => put it last
|
||||
if (a->id() == -99 || b->id() == -99) {
|
||||
return b->id() == -99;
|
||||
}
|
||||
// both are 0 (not yet named persistents) / both are named specials (-98 <= ID <=-1)
|
||||
return a->name() < b->name();
|
||||
}
|
||||
|
||||
// sort non-special named workspaces by name (ID <= -1377)
|
||||
return a->name() < b->name();
|
||||
// Return a default value if none of the cases match.
|
||||
return is_name_less; // You can adjust this to your specific needs.
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < workspaces_.size(); ++i) {
|
||||
|
@ -390,6 +499,13 @@ void Workspaces::sort_workspaces() {
|
|||
}
|
||||
|
||||
std::string &Workspace::select_icon(std::map<std::string, std::string> &icons_map) {
|
||||
if (is_urgent()) {
|
||||
auto urgent_icon_it = icons_map.find("urgent");
|
||||
if (urgent_icon_it != icons_map.end()) {
|
||||
return urgent_icon_it->second;
|
||||
}
|
||||
}
|
||||
|
||||
if (active()) {
|
||||
auto active_icon_it = icons_map.find("active");
|
||||
if (active_icon_it != icons_map.end()) {
|
||||
|
@ -409,6 +525,13 @@ std::string &Workspace::select_icon(std::map<std::string, std::string> &icons_ma
|
|||
return named_icon_it->second;
|
||||
}
|
||||
|
||||
if (is_visible()) {
|
||||
auto visible_icon_it = icons_map.find("visible");
|
||||
if (visible_icon_it != icons_map.end()) {
|
||||
return visible_icon_it->second;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_empty()) {
|
||||
auto empty_icon_it = icons_map.find("empty");
|
||||
if (empty_icon_it != icons_map.end()) {
|
||||
|
@ -450,7 +573,7 @@ auto Workspace::handle_clicked(GdkEventButton *bt) -> bool {
|
|||
|
||||
void Workspaces::set_urgent_workspace(std::string windowaddress) {
|
||||
const Json::Value clients_json = gIPC->getSocket1JsonReply("clients");
|
||||
int workspace_id;
|
||||
int workspace_id = -1;
|
||||
|
||||
for (Json::Value client_json : clients_json) {
|
||||
if (client_json["address"].asString().ends_with(windowaddress)) {
|
||||
|
@ -462,7 +585,7 @@ void Workspaces::set_urgent_workspace(std::string windowaddress) {
|
|||
auto workspace =
|
||||
std::find_if(workspaces_.begin(), workspaces_.end(),
|
||||
[&](std::unique_ptr<Workspace> &x) { return x->id() == workspace_id; });
|
||||
if (workspace->get() != nullptr) {
|
||||
if (workspace != workspaces_.end()) {
|
||||
workspace->get()->set_urgent();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@ Item::Item(const std::string& bn, const std::string& op, const Json::Value& conf
|
|||
object_path(op),
|
||||
icon_size(16),
|
||||
effective_icon_size(0),
|
||||
icon_theme(Gtk::IconTheme::create()) {
|
||||
icon_theme(Gtk::IconTheme::create()),
|
||||
bar_(bar) {
|
||||
if (config["icon-size"].isUInt()) {
|
||||
icon_size = config["icon-size"].asUInt();
|
||||
}
|
||||
|
@ -410,7 +411,8 @@ void Item::makeMenu() {
|
|||
|
||||
bool Item::handleClick(GdkEventButton* const& ev) {
|
||||
auto parameters = Glib::VariantContainerBase::create_tuple(
|
||||
{Glib::Variant<int>::create(ev->x), Glib::Variant<int>::create(ev->y)});
|
||||
{Glib::Variant<int>::create(ev->x_root + bar_.x_global),
|
||||
Glib::Variant<int>::create(ev->y_root + bar_.y_global)});
|
||||
if ((ev->button == 1 && item_is_menu) || ev->button == 3) {
|
||||
makeMenu();
|
||||
if (gtk_menu != nullptr) {
|
||||
|
|
|
@ -79,9 +79,18 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
|
|||
: true;
|
||||
});
|
||||
|
||||
// adding persistent workspaces (as per the config file)
|
||||
if (config_["persistent_workspaces"].isObject()) {
|
||||
const Json::Value &p_workspaces = config_["persistent_workspaces"];
|
||||
spdlog::warn(
|
||||
"persistent_workspaces is deprecated. Please change config to use "
|
||||
"persistent-workspaces.");
|
||||
}
|
||||
|
||||
// adding persistent workspaces (as per the config file)
|
||||
if (config_["persistent-workspaces"].isObject() ||
|
||||
config_["persistent_workspaces"].isObject()) {
|
||||
const Json::Value &p_workspaces = config_["persistent-workspaces"].isObject()
|
||||
? config_["persistent-workspaces"]
|
||||
: config_["persistent_workspaces"];
|
||||
const std::vector<std::string> p_workspaces_names = p_workspaces.getMemberNames();
|
||||
|
||||
for (const std::string &p_w_name : p_workspaces_names) {
|
||||
|
|
|
@ -209,8 +209,17 @@ WorkspaceGroup::WorkspaceGroup(const Bar &bar, Gtk::Box &box, const Json::Value
|
|||
}
|
||||
|
||||
auto WorkspaceGroup::fill_persistent_workspaces() -> void {
|
||||
if (config_["persistent_workspaces"].isObject() && !workspace_manager_.all_outputs()) {
|
||||
const Json::Value &p_workspaces = config_["persistent_workspaces"];
|
||||
if (config_["persistent_workspaces"].isObject()) {
|
||||
spdlog::warn(
|
||||
"persistent_workspaces is deprecated. Please change config to use persistent-workspaces.");
|
||||
}
|
||||
|
||||
if ((config_["persistent-workspaces"].isObject() ||
|
||||
config_["persistent_workspaces"].isObject()) &&
|
||||
!workspace_manager_.all_outputs()) {
|
||||
const Json::Value &p_workspaces = config_["persistent-workspaces"].isObject()
|
||||
? config_["persistent-workspaces"]
|
||||
: config_["persistent_workspaces"];
|
||||
const std::vector<std::string> p_workspaces_names = p_workspaces.getMemberNames();
|
||||
|
||||
for (const std::string &p_w_name : p_workspaces_names) {
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
#include "util/enum.hpp"
|
||||
|
||||
#include <algorithm> // for std::transform
|
||||
#include <cctype> // for std::toupper
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "modules/hyprland/workspaces.hpp"
|
||||
#include "util/string.hpp"
|
||||
|
||||
namespace waybar::util {
|
||||
|
||||
template <typename EnumType>
|
||||
EnumParser<EnumType>::EnumParser() = default;
|
||||
|
||||
template <typename EnumType>
|
||||
EnumParser<EnumType>::~EnumParser() = default;
|
||||
|
||||
template <typename EnumType>
|
||||
EnumType EnumParser<EnumType>::parseStringToEnum(const std::string& str,
|
||||
const std::map<std::string, EnumType>& enumMap) {
|
||||
// Convert the input string to uppercase
|
||||
std::string uppercaseStr = capitalize(str);
|
||||
|
||||
// Capitalize the map keys before searching
|
||||
std::map<std::string, EnumType> capitalizedEnumMap;
|
||||
std::transform(
|
||||
enumMap.begin(), enumMap.end(), std::inserter(capitalizedEnumMap, capitalizedEnumMap.end()),
|
||||
[this](const auto& pair) { return std::make_pair(capitalize(pair.first), pair.second); });
|
||||
|
||||
// Return enum match of string
|
||||
auto it = capitalizedEnumMap.find(uppercaseStr);
|
||||
if (it != capitalizedEnumMap.end()) return it->second;
|
||||
|
||||
// Throw error if it doesn't return
|
||||
throw std::invalid_argument("Invalid string representation for enum");
|
||||
}
|
||||
|
||||
// Explicit instantiations for specific EnumType types you intend to use
|
||||
// Add explicit instantiations for all relevant EnumType types
|
||||
template struct EnumParser<modules::hyprland::Workspaces::SORT_METHOD>;
|
||||
|
||||
} // namespace waybar::util
|
Loading…
Reference in New Issue