Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a taskbar squash option #3740

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions include/modules/wlr/taskbar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <map>
#include <memory>
#include <ranges>
#include <string>
#include <unordered_set>
#include <vector>
Expand Down Expand Up @@ -67,6 +68,7 @@ class Task {
Glib::RefPtr<Gio::DesktopAppInfo> app_info_;
bool button_visible_ = false;
bool ignored_ = false;
bool squashed_ = false;

bool with_icon_ = false;
bool with_name_ = false;
Expand All @@ -93,6 +95,7 @@ class Task {
bool image_load_icon(Gtk::Image &image, const Glib::RefPtr<Gtk::IconTheme> &icon_theme,
Glib::RefPtr<Gio::DesktopAppInfo> app_info, int size);
void hide_if_ignored();
void hide_if_duplicate();

public:
/* Getter functions */
Expand Down Expand Up @@ -155,6 +158,7 @@ class Taskbar : public waybar::AModule {

std::vector<Glib::RefPtr<Gtk::IconTheme>> icon_themes_;
std::unordered_set<std::string> ignore_list_;
std::unordered_set<std::string> squash_list_;
std::map<std::string, std::string> app_ids_replace_map_;

struct zwlr_foreign_toplevel_manager_v1 *manager_;
Expand All @@ -180,7 +184,14 @@ class Taskbar : public waybar::AModule {

const std::vector<Glib::RefPtr<Gtk::IconTheme>> &icon_themes() const;
const std::unordered_set<std::string> &ignore_list() const;
const std::unordered_set<std::string> &squash_list() const;
const std::map<std::string, std::string> &app_ids_replace_map() const;
std::size_t task_id_count(std::string_view id) const;
std::size_t task_title_count(std::string_view title) const;

auto tasks() {
return tasks_ | std::views::transform([](auto &task) -> Task & { return *task; });
}
};

} /* namespace waybar::modules::wlr */
69 changes: 68 additions & 1 deletion src/modules/wlr/taskbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,21 +385,44 @@ std::string Task::state_string(bool shortened) const {
void Task::handle_title(const char *title) {
title_ = title;
hide_if_ignored();
hide_if_duplicate();
}

void Task::set_minimize_hint() {
zwlr_foreign_toplevel_handle_v1_set_rectangle(handle_, bar_.surface, minimize_hint.x,
minimize_hint.y, minimize_hint.w, minimize_hint.h);
}

void Task::hide_if_duplicate() {
const auto &squash_list = tbar_->squash_list();
bool contains_app =
squash_list.contains("*") || squash_list.contains(title_) || squash_list.contains(app_id_);

// Squashes if the app is in the squash list and more than 1 instance is open
if (contains_app && (tbar_->task_id_count(app_id_) > 1 || tbar_->task_title_count(title_) > 1)) {
squashed_ = true;
if (button_visible_) {
auto output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj());
handle_output_leave(output);
}
}

if (!squashed_ && !ignored_) {
auto output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj());
handle_output_enter(output);
}
}

void Task::hide_if_ignored() {
if (tbar_->ignore_list().count(app_id_) || tbar_->ignore_list().count(title_)) {
ignored_ = true;
if (button_visible_) {
auto output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj());
handle_output_leave(output);
}
} else {
}

if (!ignored_ && !squashed_) {
bool is_was_ignored = ignored_;
ignored_ = false;
if (is_was_ignored) {
Expand All @@ -417,6 +440,7 @@ void Task::handle_app_id(const char *app_id) {
}
app_id_ = app_id;
hide_if_ignored();
hide_if_duplicate();

auto ids_replace_map = tbar_->app_ids_replace_map();
if (ids_replace_map.count(app_id_)) {
Expand Down Expand Up @@ -464,6 +488,10 @@ void Task::handle_output_enter(struct wl_output *output) {
spdlog::debug("{} is ignored", repr());
return;
}
if (squashed_) {
spdlog::debug("{} was squashed", repr());
return;
}

spdlog::debug("{} entered output {}", repr(), (void *)output);

Expand Down Expand Up @@ -543,6 +571,28 @@ void Task::handle_closed() {
tbar_->remove_button(button);
button_visible_ = false;
}

const auto &squash_list = tbar_->squash_list();
const bool in_squash_list =
squash_list.contains("*") || squash_list.contains(title_) || squash_list.contains(app_id_);
if (in_squash_list && !squashed_ &&
(tbar_->task_id_count(app_id_) > 1 || tbar_->task_title_count(title_) > 1)) {
// Find next squashed task with same title or id (excluding ourselves)
auto tasks = tbar_->tasks();
const auto it = std::ranges::find_if(tasks, [this](auto &&task) {
return &task != this && task.squashed_ &&
(task.app_id() == app_id_ || task.title() == title_);
});

if (it != tasks.end() && !(*it).ignored_) {
Task &task = *it;
task.squashed_ = false;
tbar_->add_button(task.button);
task.button.show();
task.button_visible_ = true;
}
}

tbar_->remove_task(id_);
}

Expand Down Expand Up @@ -794,6 +844,13 @@ Taskbar::Taskbar(const std::string &id, const waybar::Bar &bar, const Json::Valu
}
}

// Load squash-list
if (config_["squash-list"].isArray()) {
for (auto &app_name : config_["squash-list"]) {
squash_list_.emplace(app_name.asString());
}
}

// Load app_id remappings
if (config_["app_ids-mapping"].isObject()) {
const Json::Value &mapping = config_["app_ids-mapping"];
Expand Down Expand Up @@ -945,8 +1002,18 @@ const std::vector<Glib::RefPtr<Gtk::IconTheme>> &Taskbar::icon_themes() const {

const std::unordered_set<std::string> &Taskbar::ignore_list() const { return ignore_list_; }

const std::unordered_set<std::string> &Taskbar::squash_list() const { return squash_list_; }

const std::map<std::string, std::string> &Taskbar::app_ids_replace_map() const {
return app_ids_replace_map_;
}

std::size_t Taskbar::task_id_count(std::string_view id) const {
return std::ranges::count_if(tasks_, [=](auto &&task) { return id == task->app_id(); });
}

std::size_t Taskbar::task_title_count(std::string_view title) const {
return std::ranges::count_if(tasks_, [=](auto &&task) { return title == task->title(); });
}

} /* namespace waybar::modules::wlr */