From 7086592d87db6ddf1577536ef4c6ad8f0dcdade0 Mon Sep 17 00:00:00 2001 From: Viktar Lukashonak Date: Thu, 31 Oct 2024 18:40:09 +0300 Subject: [PATCH] GTK4. wlr, cffi, hyplrand migration Signed-off-by: Viktar Lukashonak --- include/modules/cffi.hpp | 10 +- include/modules/hyprland/backend.hpp | 7 +- include/modules/hyprland/window.hpp | 5 - .../hyprland/windowcreationpayload.hpp | 16 - include/modules/hyprland/workspace.hpp | 22 +- include/modules/hyprland/workspaces.hpp | 12 - include/modules/wlr/taskbar.hpp | 47 +-- include/modules/wlr/workspace_manager.hpp | 12 +- meson.build | 7 +- resources/custom_modules/cffi_example/main.c | 17 +- .../custom_modules/cffi_example/meson.build | 4 +- .../cffi_example/waybar_cffi_module.h | 2 +- src/modules/cffi.cpp | 8 +- src/modules/hyprland/backend.cpp | 11 - src/modules/hyprland/submap.cpp | 4 +- src/modules/hyprland/window.cpp | 19 +- src/modules/hyprland/workspace.cpp | 61 ++-- src/modules/hyprland/workspaces.cpp | 10 +- src/modules/wlr/taskbar.cpp | 284 +++++++----------- src/modules/wlr/workspace_manager.cpp | 62 ++-- 20 files changed, 231 insertions(+), 389 deletions(-) diff --git a/include/modules/cffi.hpp b/include/modules/cffi.hpp index 7a94f3eff..782533eea 100644 --- a/include/modules/cffi.hpp +++ b/include/modules/cffi.hpp @@ -1,19 +1,21 @@ #pragma once +#include + #include "AModule.hpp" namespace waybar::modules { namespace ffi { extern "C" { -typedef struct wbcffi_module wbcffi_module; +using wbcffi_module = struct wbcffi_module; -typedef struct { +using wbcffi_init_info = struct { wbcffi_module* obj; const char* waybar_version; GtkWidget* (*get_root_widget)(wbcffi_module*); void (*queue_update)(wbcffi_module*); -} wbcffi_init_info; +}; struct wbcffi_config_entry { const char* key; @@ -30,10 +32,12 @@ class CFFI final : public AModule { virtual auto refresh(int signal) -> void override; virtual auto doAction(const std::string& name) -> void override; virtual auto update() -> void override; + operator Gtk::Widget&() override; private: /// void* cffi_instance_ = nullptr; + Glib::RefPtr const box_; typedef void*(InitFn)(const ffi::wbcffi_init_info* init_info, const ffi::wbcffi_config_entry* config_entries, size_t config_entries_len); diff --git a/include/modules/hyprland/backend.hpp b/include/modules/hyprland/backend.hpp index 11e73d8f6..f805c2bb9 100644 --- a/include/modules/hyprland/backend.hpp +++ b/include/modules/hyprland/backend.hpp @@ -1,11 +1,10 @@ #pragma once +#include +#include + #include #include -#include -#include -#include -#include #include "util/json.hpp" diff --git a/include/modules/hyprland/window.hpp b/include/modules/hyprland/window.hpp index f2c266bd2..393ccc3f2 100644 --- a/include/modules/hyprland/window.hpp +++ b/include/modules/hyprland/window.hpp @@ -1,13 +1,8 @@ #pragma once -#include - -#include - #include "AAppIconLabel.hpp" #include "bar.hpp" #include "modules/hyprland/backend.hpp" -#include "util/json.hpp" namespace waybar::modules::hyprland { diff --git a/include/modules/hyprland/windowcreationpayload.hpp b/include/modules/hyprland/windowcreationpayload.hpp index 45229ed42..52d3ba0ec 100644 --- a/include/modules/hyprland/windowcreationpayload.hpp +++ b/include/modules/hyprland/windowcreationpayload.hpp @@ -1,24 +1,8 @@ #pragma once -#include -#include #include -#include -#include -#include -#include -#include -#include -#include #include -#include - -#include "AModule.hpp" -#include "bar.hpp" -#include "modules/hyprland/backend.hpp" -#include "util/enum.hpp" -#include "util/regex_collection.hpp" using WindowAddress = std::string; diff --git a/include/modules/hyprland/workspace.hpp b/include/modules/hyprland/workspace.hpp index f1fea4e8c..6610f1f6a 100644 --- a/include/modules/hyprland/workspace.hpp +++ b/include/modules/hyprland/workspace.hpp @@ -2,24 +2,8 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AModule.hpp" -#include "bar.hpp" -#include "modules/hyprland/backend.hpp" -#include "modules/hyprland/windowcreationpayload.hpp" -#include "util/enum.hpp" -#include "util/regex_collection.hpp" +#include "modules/hyprland/workspaces.hpp" using WindowAddress = std::string; @@ -44,8 +28,7 @@ class Workspace { bool isVisible() const { return m_isVisible; }; bool isEmpty() const { return m_windows == 0; }; bool isUrgent() const { return m_isUrgent; }; - - bool handleClicked(GdkEventButton* bt) const; + void handleToggle(int n_press, double dx, double dy); void setActive(bool value = true) { m_isActive = value; }; void setPersistentRule(bool value = true) { m_isPersistentRule = value; }; void setPersistentConfig(bool value = true) { m_isPersistentConfig = value; }; @@ -83,6 +66,7 @@ class Workspace { Gtk::Button m_button; Gtk::Box m_content; Gtk::Label m_label; + Glib::RefPtr const controllClick_; }; } // namespace waybar::modules::hyprland diff --git a/include/modules/hyprland/workspaces.hpp b/include/modules/hyprland/workspaces.hpp index a9d56b79f..2baaf53ab 100644 --- a/include/modules/hyprland/workspaces.hpp +++ b/include/modules/hyprland/workspaces.hpp @@ -1,17 +1,7 @@ #pragma once -#include -#include #include -#include -#include -#include -#include -#include -#include - -#include "AModule.hpp" #include "bar.hpp" #include "modules/hyprland/backend.hpp" #include "modules/hyprland/windowcreationpayload.hpp" @@ -23,8 +13,6 @@ using WindowAddress = std::string; namespace waybar::modules::hyprland { -class Workspaces; - class Workspaces : public AModule, public EventHandler { public: Workspaces(const std::string&, const waybar::Bar&, const Json::Value&); diff --git a/include/modules/wlr/taskbar.hpp b/include/modules/wlr/taskbar.hpp index 07110ddee..67606199c 100644 --- a/include/modules/wlr/taskbar.hpp +++ b/include/modules/wlr/taskbar.hpp @@ -1,31 +1,21 @@ #pragma once -#include -#include -#include +#include #include #include #include #include -#include -#include -#include -#include #include -#include -#include "AModule.hpp" #include "bar.hpp" -#include "client.hpp" -#include "giomm/desktopappinfo.h" -#include "util/json.hpp" #include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h" namespace waybar::modules::wlr { struct widget_geometry { - int x, y, w, h; + double x, y; + int w, h; }; class Taskbar; @@ -45,13 +35,13 @@ class Task { INVALID = (1 << 4) }; // made public so TaskBar can reorder based on configuration. - Gtk::Button button; + Glib::RefPtr const button; struct widget_geometry minimize_hint; private: static uint32_t global_id; + Glib::RefPtr const controllClick_; - private: const waybar::Bar &bar_; const Json::Value &config_; Taskbar *tbar_; @@ -80,15 +70,9 @@ class Task { std::string app_id_; uint32_t state_ = 0; - int32_t drag_start_x; - int32_t drag_start_y; - int32_t drag_start_button = -1; - - private: std::string repr() const; std::string state_string(bool = false) const; void set_minimize_hint(); - void on_button_size_allocated(Gtk::Allocation &alloc); void set_app_info_from_app_id_list(const std::string &app_id_list); bool image_load_icon(Gtk::Image &image, const Glib::RefPtr &icon_theme, Glib::RefPtr app_info, int size); @@ -105,7 +89,6 @@ class Task { bool active() const { return state_ & ACTIVE; } bool fullscreen() const { return state_ & FULLSCREEN; } - public: /* Callbacks for the wlr protocol */ void handle_title(const char *); void handle_app_id(const char *); @@ -116,22 +99,14 @@ class Task { void handle_closed(); /* Callbacks for Gtk events */ - bool handle_clicked(GdkEventButton *); - bool handle_button_release(GdkEventButton *); - bool handle_motion_notify(GdkEventMotion *); - void handle_drag_data_get(const Glib::RefPtr &context, - Gtk::SelectionData &selection_data, guint info, guint time); - void handle_drag_data_received(const Glib::RefPtr &context, int x, int y, - Gtk::SelectionData selection_data, guint info, guint time); + void handleClick(int n_press, double dx, double dy); + bool handleDropData(const Glib::ValueBase &, double, double); - public: bool operator==(const Task &) const; bool operator!=(const Task &) const; - public: void update(); - public: /* Interaction with the tasks */ void maximize(bool); void minimize(bool); @@ -147,6 +122,7 @@ class Taskbar : public waybar::AModule { Taskbar(const std::string &, const waybar::Bar &, const Json::Value &); ~Taskbar(); void update(); + operator Gtk::Widget &() override; private: const waybar::Bar &bar_; @@ -169,10 +145,9 @@ class Taskbar : public waybar::AModule { void handle_toplevel_create(struct zwlr_foreign_toplevel_handle_v1 *); void handle_finished(); - public: - void add_button(Gtk::Button &); - void move_button(Gtk::Button &, int); - void remove_button(Gtk::Button &); + void add_button(Glib::RefPtr); + void move_button(Glib::RefPtr, int); + void remove_button(Glib::RefPtr); void remove_task(uint32_t); bool show_output(struct wl_output *) const; diff --git a/include/modules/wlr/workspace_manager.hpp b/include/modules/wlr/workspace_manager.hpp index f7cc759ec..4818e58a2 100644 --- a/include/modules/wlr/workspace_manager.hpp +++ b/include/modules/wlr/workspace_manager.hpp @@ -1,16 +1,8 @@ #pragma once -#include #include -#include #include -#include -#include -#include -#include - -#include "AModule.hpp" #include "bar.hpp" #include "ext-workspace-unstable-v1-client-protocol.h" @@ -41,7 +33,7 @@ class Workspace { auto handle_duplicate() -> void; auto handle_done() -> void; - auto handle_clicked(GdkEventButton *bt) -> bool; + void handleClick(int n_press, double dx, double dy); auto show() -> void; auto hide() -> void; auto get_button_ref() -> Gtk::Button & { return button_; } @@ -75,6 +67,7 @@ class Workspace { bool persistent_ = false; Gtk::Button button_; + Glib::RefPtr const controllClick_; Gtk::Box content_; Gtk::Label label_; }; @@ -133,6 +126,7 @@ class WorkspaceManager : public AModule { WorkspaceManager(const std::string &id, const waybar::Bar &bar, const Json::Value &config); ~WorkspaceManager() override; auto update() -> void override; + operator Gtk::Widget &() override; auto all_outputs() const -> bool { return all_outputs_; } auto active_only() const -> bool { return active_only_; } diff --git a/meson.build b/meson.build index 4e8bd8b4e..ee8a6ad39 100644 --- a/meson.build +++ b/meson.build @@ -177,6 +177,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', @@ -262,11 +263,12 @@ man_files += files('man/waybar-sway-language.5.scd', 'man/waybar-sway-scratchpad.5.scd', 'man/waybar-sway-window.5.scd', 'man/waybar-sway-workspaces.5.scd') -if 1 == 0 + add_project_arguments('-DHAVE_WLR_TASKBAR', language: 'cpp') src_files += files('src/modules/wlr/taskbar.cpp') man_files += files('man/waybar-wlr-taskbar.5.scd') +if 1 == 0 add_project_arguments('-DHAVE_RIVER', language: 'cpp') src_files += files('src/modules/river/layout.cpp', 'src/modules/river/mode.cpp', @@ -282,7 +284,7 @@ src_files += files('src/modules/dwl/tags.cpp', 'src/modules/dwl/window.cpp') man_files += files('man/waybar-dwl-tags.5.scd', 'man/waybar-dwl-window.5.scd') -if 1 == 0 + add_project_arguments('-DHAVE_HYPRLAND', language: 'cpp') src_files += files('src/modules/hyprland/backend.cpp', 'src/modules/hyprland/language.cpp', @@ -296,6 +298,7 @@ man_files += files('man/waybar-hyprland-language.5.scd', 'man/waybar-hyprland-window.5.scd', 'man/waybar-hyprland-workspaces.5.scd') +if 1 == 0 if get_option('niri') add_project_arguments('-DHAVE_NIRI', language: 'cpp') src_files += files( diff --git a/resources/custom_modules/cffi_example/main.c b/resources/custom_modules/cffi_example/main.c index ba2c8cf46..4f5f3994b 100644 --- a/resources/custom_modules/cffi_example/main.c +++ b/resources/custom_modules/cffi_example/main.c @@ -3,7 +3,6 @@ typedef struct { wbcffi_module* waybar_module; - GtkBox* container; GtkButton* button; } ExampleMod; @@ -30,24 +29,22 @@ void* wbcffi_init(const wbcffi_init_info* init_info, const wbcffi_config_entry* ExampleMod* inst = malloc(sizeof(ExampleMod)); inst->waybar_module = init_info->obj; - GtkContainer* root = init_info->get_root_widget(init_info->obj); - - // Add a container for displaying the next widgets - inst->container = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5)); - gtk_container_add(GTK_CONTAINER(root), GTK_WIDGET(inst->container)); + GtkWidget* root = init_info->get_root_widget(init_info->obj); + gtk_box_set_spacing(GTK_BOX(root), 5); + gtk_orientable_set_orientation(GTK_ORIENTABLE(root), GTK_ORIENTATION_HORIZONTAL); // Add a label GtkLabel* label = GTK_LABEL(gtk_label_new("[Example C FFI Module:")); - gtk_container_add(GTK_CONTAINER(inst->container), GTK_WIDGET(label)); + gtk_box_append(GTK_BOX(root), GTK_WIDGET(label)); // Add a button inst->button = GTK_BUTTON(gtk_button_new_with_label("click me !")); g_signal_connect(inst->button, "clicked", G_CALLBACK(onclicked), NULL); - gtk_container_add(GTK_CONTAINER(inst->container), GTK_WIDGET(inst->button)); + gtk_box_append(GTK_BOX(root), GTK_WIDGET(inst->button)); // Add a label label = GTK_LABEL(gtk_label_new("]")); - gtk_container_add(GTK_CONTAINER(inst->container), GTK_WIDGET(label)); + gtk_box_append(GTK_BOX(root), GTK_WIDGET(label)); // Return instance object printf("cffi_example inst=%p: init success ! (%d total instances)\n", inst, ++instance_count); @@ -67,4 +64,4 @@ void wbcffi_refresh(void* instance, int signal) { void wbcffi_doaction(void* instance, const char* name) { printf("cffi_example inst=%p: doAction(%s)\n", instance, name); -} \ No newline at end of file +} diff --git a/resources/custom_modules/cffi_example/meson.build b/resources/custom_modules/cffi_example/meson.build index dcde10482..f4adad5e8 100644 --- a/resources/custom_modules/cffi_example/meson.build +++ b/resources/custom_modules/cffi_example/meson.build @@ -1,13 +1,13 @@ project( 'waybar_cffi_example', 'c', - version: '0.1.0', + version: '4.1.0', license: 'MIT', ) shared_library('wb_cffi_example', ['main.c'], dependencies: [ - dependency('gtk+-3.0', version : ['>=3.22.0']) + dependency('gtk4', version : ['>=4.17.0']) ], name_prefix: '' ) diff --git a/resources/custom_modules/cffi_example/waybar_cffi_module.h b/resources/custom_modules/cffi_example/waybar_cffi_module.h index a7886bea4..3f2836c94 100644 --- a/resources/custom_modules/cffi_example/waybar_cffi_module.h +++ b/resources/custom_modules/cffi_example/waybar_cffi_module.h @@ -23,7 +23,7 @@ typedef struct { /// Returns the waybar widget allocated for this module /// @param obj Waybar CFFI object pointer - GtkContainer* (*get_root_widget)(wbcffi_module* obj); + GtkWidget* (*get_root_widget)(wbcffi_module* obj); /// Queues a request for calling wbcffi_update() on the next GTK main event /// loop iteration diff --git a/src/modules/cffi.cpp b/src/modules/cffi.cpp index 0cea9a247..ab566717c 100644 --- a/src/modules/cffi.cpp +++ b/src/modules/cffi.cpp @@ -7,7 +7,8 @@ namespace waybar::modules { CFFI::CFFI(const std::string& name, const std::string& id, const Json::Value& config) - : AModule(config, name, id, true, true) { + : AModule(config, name, id, true, true), box_{new Gtk::Box()} { + box_->set_name(name_); const auto dynlib_path = config_["module_path"].asString(); if (dynlib_path.empty()) { throw std::runtime_error{"Missing or empty 'module_path' in module config"}; @@ -101,6 +102,11 @@ auto CFFI::update() -> void { AModule::update(); } +CFFI::operator Gtk::Widget&() { + assert(box_); + return *box_; +} + auto CFFI::refresh(int signal) -> void { assert(cffi_instance_ != nullptr); hooks_.refresh(cffi_instance_, signal); diff --git a/src/modules/hyprland/backend.cpp b/src/modules/hyprland/backend.cpp index 39341a14b..ce40010fe 100644 --- a/src/modules/hyprland/backend.cpp +++ b/src/modules/hyprland/backend.cpp @@ -1,17 +1,6 @@ #include "modules/hyprland/backend.hpp" -#include -#include #include -#include -#include -#include -#include -#include - -#include -#include -#include namespace waybar::modules::hyprland { diff --git a/src/modules/hyprland/submap.cpp b/src/modules/hyprland/submap.cpp index 96677d127..0178afb90 100644 --- a/src/modules/hyprland/submap.cpp +++ b/src/modules/hyprland/submap.cpp @@ -53,13 +53,13 @@ auto Submap::update() -> void { std::lock_guard lg(mutex_); if (submap_.empty()) { - event_box_.hide(); + label_.hide(); } else { label_.set_markup(fmt::format(fmt::runtime(format_), submap_)); if (tooltipEnabled()) { label_.set_tooltip_text(submap_); } - event_box_.show(); + label_.show(); } // Call parent update ALabel::update(); diff --git a/src/modules/hyprland/window.cpp b/src/modules/hyprland/window.cpp index b5ed8f021..8b31cf1cc 100644 --- a/src/modules/hyprland/window.cpp +++ b/src/modules/hyprland/window.cpp @@ -1,14 +1,7 @@ #include "modules/hyprland/window.hpp" -#include -#include -#include #include -#include -#include - -#include "modules/hyprland/backend.hpp" #include "util/rewrite_string.hpp" #include "util/sanitize_str.hpp" @@ -75,14 +68,14 @@ auto Window::update() -> void { setClass("fullscreen", fullscreen_); if (!lastSoloClass_.empty() && soloClass_ != lastSoloClass_) { - if (bar_.window.get_style_context()->has_class(lastSoloClass_)) { - bar_.window.get_style_context()->remove_class(lastSoloClass_); + if (box_.get_style_context()->has_class(lastSoloClass_)) { + box_.get_style_context()->remove_class(lastSoloClass_); spdlog::trace("Removing solo class: {}", lastSoloClass_); } } if (!soloClass_.empty() && soloClass_ != lastSoloClass_) { - bar_.window.get_style_context()->add_class(soloClass_); + box_.get_style_context()->add_class(soloClass_); spdlog::trace("Adding solo class: {}", soloClass_); } lastSoloClass_ = soloClass_; @@ -222,11 +215,11 @@ void Window::onEvent(const std::string& ev) { void Window::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); + if (!box_.get_style_context()->has_class(classname)) { + box_.get_style_context()->add_class(classname); } } else { - bar_.window.get_style_context()->remove_class(classname); + box_.get_style_context()->remove_class(classname); } } diff --git a/src/modules/hyprland/workspace.cpp b/src/modules/hyprland/workspace.cpp index e575d1c4d..133f1dc49 100644 --- a/src/modules/hyprland/workspace.cpp +++ b/src/modules/hyprland/workspace.cpp @@ -1,10 +1,5 @@ -#include #include -#include -#include -#include - #include "modules/hyprland/workspaces.hpp" namespace waybar::modules::hyprland { @@ -18,7 +13,8 @@ Workspace::Workspace(const Json::Value &workspace_data, Workspaces &workspace_ma m_windows(workspace_data["windows"].asInt()), m_isActive(true), m_isPersistentRule(workspace_data["persistent-rule"].asBool()), - m_isPersistentConfig(workspace_data["persistent-config"].asBool()) { + m_isPersistentConfig(workspace_data["persistent-config"].asBool()), + controllClick_{Gtk::GestureClick::create()} { if (m_name.starts_with("name:")) { m_name = m_name.substr(5); } else if (m_name.starts_with("special")) { @@ -26,13 +22,12 @@ Workspace::Workspace(const Json::Value &workspace_data, Workspaces &workspace_ma m_isSpecial = true; } - m_button.add_events(Gdk::BUTTON_PRESS_MASK); - m_button.signal_button_press_event().connect(sigc::mem_fun(*this, &Workspace::handleClicked), - false); + controllClick_->signal_pressed().connect(sigc::mem_fun(*this, &Workspace::handleToggle), true); + m_button.add_controller(controllClick_); - m_button.set_relief(Gtk::RELIEF_NONE); - m_content.set_center_widget(m_label); - m_button.add(m_content); + m_button.set_has_frame(false); + m_content.append(m_label); + m_button.set_child(m_content); initializeWindowMap(clients_data); } @@ -53,32 +48,28 @@ std::optional Workspace::closeWindow(WindowAddress const &addr) { return std::nullopt; } -bool Workspace::handleClicked(GdkEventButton *bt) const { - if (bt->type == GDK_BUTTON_PRESS) { - try { - if (id() > 0) { // normal - if (m_workspaceManager.moveToMonitor()) { - gIPC->getSocket1Reply("dispatch focusworkspaceoncurrentmonitor " + std::to_string(id())); - } else { - gIPC->getSocket1Reply("dispatch workspace " + std::to_string(id())); - } - } else if (!isSpecial()) { // named (this includes persistent) - if (m_workspaceManager.moveToMonitor()) { - gIPC->getSocket1Reply("dispatch focusworkspaceoncurrentmonitor name:" + name()); - } else { - gIPC->getSocket1Reply("dispatch workspace name:" + name()); - } - } else if (id() != -99) { // named special - gIPC->getSocket1Reply("dispatch togglespecialworkspace " + name()); - } else { // special - gIPC->getSocket1Reply("dispatch togglespecialworkspace"); +void Workspace::handleToggle(int n_press, double dx, double dy) { + try { + if (id() > 0) { // normal + if (m_workspaceManager.moveToMonitor()) { + gIPC->getSocket1Reply("dispatch focusworkspaceoncurrentmonitor " + std::to_string(id())); + } else { + gIPC->getSocket1Reply("dispatch workspace " + std::to_string(id())); + } + } else if (!isSpecial()) { // named (this includes persistent) + if (m_workspaceManager.moveToMonitor()) { + gIPC->getSocket1Reply("dispatch focusworkspaceoncurrentmonitor name:" + name()); + } else { + gIPC->getSocket1Reply("dispatch workspace name:" + name()); } - return true; - } catch (const std::exception &e) { - spdlog::error("Failed to dispatch workspace: {}", e.what()); + } else if (id() != -99) { // named special + gIPC->getSocket1Reply("dispatch togglespecialworkspace " + name()); + } else { // special + gIPC->getSocket1Reply("dispatch togglespecialworkspace"); } + } catch (const std::exception &e) { + spdlog::error("Failed to dispatch workspace: {}", e.what()); } - return false; } void Workspace::initializeWindowMap(const Json::Value &clients_data) { diff --git a/src/modules/hyprland/workspaces.cpp b/src/modules/hyprland/workspaces.cpp index 13364f3f2..df71e621d 100644 --- a/src/modules/hyprland/workspaces.cpp +++ b/src/modules/hyprland/workspaces.cpp @@ -22,7 +22,6 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value m_box.get_style_context()->add_class(id); } m_box.get_style_context()->add_class(MODULE_CLASS); - event_box_.add(m_box); if (!gIPC) { gIPC = std::make_unique(); @@ -100,9 +99,9 @@ void Workspaces::createWorkspace(Json::Value const &workspace_data, // create new workspace m_workspaces.emplace_back(std::make_unique(workspace_data, *this, clients_data)); Gtk::Button &newWorkspaceButton = m_workspaces.back()->button(); - m_box.pack_start(newWorkspaceButton, false, false); + m_box.append(newWorkspaceButton); sortWorkspaces(); - newWorkspaceButton.show_all(); + newWorkspaceButton.show(); } void Workspaces::createWorkspacesToCreate() { @@ -783,7 +782,10 @@ void Workspaces::sortWorkspaces() { }); for (size_t i = 0; i < m_workspaces.size(); ++i) { - m_box.reorder_child(m_workspaces[i]->button(), i); + if (i == 0) + m_box.reorder_child_at_start(m_workspaces[i]->button()); + else + m_box.reorder_child_after(m_workspaces[i]->button(), m_workspaces[i - 1]->button()); } } diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index 30e4ee488..115cee459 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -1,26 +1,13 @@ #include "modules/wlr/taskbar.hpp" -#include -#include #include -#include -#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include - -#include "gdkmm/general.h" -#include "glibmm/error.h" -#include "glibmm/fileutils.h" -#include "glibmm/refptr.h" -#include "util/format.hpp" -#include "util/gtk_icon.hpp" +#include "client.hpp" #include "util/rewrite_string.hpp" #include "util/string.hpp" @@ -55,15 +42,6 @@ static std::vector search_prefix() { return prefixes; } -static Glib::RefPtr load_icon_from_file(std::string icon_path, int size) { - try { - auto pb = Gdk::Pixbuf::create_from_file(icon_path, size, size); - return pb; - } catch (...) { - return {}; - } -} - static Glib::RefPtr get_app_info_by_name(const std::string &app_id) { static std::vector prefixes = search_prefix(); @@ -165,49 +143,25 @@ static std::string get_icon_name_from_icon_theme(const Glib::RefPtr &icon_theme, Glib::RefPtr app_info, int size) { - std::string ret_icon_name = "unknown"; - if (app_info) { - std::string icon_name = - get_icon_name_from_icon_theme(icon_theme, app_info->get_startup_wm_class()); - if (!icon_name.empty()) { - ret_icon_name = icon_name; - } else { - if (app_info->get_icon()) { - ret_icon_name = app_info->get_icon()->to_string(); - } + Glib::ustring iconName{(app_info) ? app_info->get_icon()->to_string() : "unknown"}; + if (app_info && iconName.empty()) + iconName = get_icon_name_from_icon_theme(icon_theme, app_info->get_startup_wm_class()); + if (iconName.empty()) iconName = "unknown"; + + auto themeIcon{ + icon_theme->lookup_icon((icon_theme->has_icon(iconName)) ? iconName : "image-missing", size, + (int)image.get_scale_factor(), Gtk::TextDirection::NONE, + Gtk::IconLookupFlags::FORCE_REGULAR)}; + if (!(icon_theme->has_icon(iconName))) { + if (Glib::file_test(iconName, Glib::FileTest::EXISTS)) { + themeIcon = Gtk::IconPaintable::create(Gio::File::create_for_path(iconName), size, + image.get_scale_factor()); } } - Glib::RefPtr pixbuf; - auto scaled_icon_size = size * image.get_scale_factor(); - - try { - pixbuf = icon_theme->load_icon(ret_icon_name, scaled_icon_size, Gtk::ICON_LOOKUP_FORCE_SIZE); - spdlog::debug("{} Loaded icon '{}'", repr(), ret_icon_name); - } catch (...) { - if (Glib::file_test(ret_icon_name, Glib::FILE_TEST_EXISTS)) { - pixbuf = load_icon_from_file(ret_icon_name, scaled_icon_size); - spdlog::debug("{} Loaded icon from file '{}'", repr(), ret_icon_name); - } else { - try { - pixbuf = DefaultGtkIconThemeWrapper::load_icon( - "image-missing", scaled_icon_size, Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE); - spdlog::debug("{} Loaded icon from resource", repr()); - } catch (...) { - pixbuf = {}; - spdlog::debug("{} Unable to load icon.", repr()); - } - } - } + if (themeIcon) { + image.set(themeIcon); - if (pixbuf) { - if (pixbuf->get_width() != scaled_icon_size) { - int width = scaled_icon_size * pixbuf->get_width() / pixbuf->get_height(); - pixbuf = pixbuf->scale_simple(width, scaled_icon_size, Gdk::InterpType::INTERP_BILINEAR); - } - auto surface = Gdk::Cairo::create_surface_from_pixbuf(pixbuf, image.get_scale_factor(), - image.get_window()); - image.set(surface); return true; } @@ -266,12 +220,11 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_handle_imp .parent = tl_handle_parent, }; -static const std::vector target_entries = { - Gtk::TargetEntry("WAYBAR_TOPLEVEL", Gtk::TARGET_SAME_APP, 0)}; - Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar, struct zwlr_foreign_toplevel_handle_v1 *tl_handle, struct wl_seat *seat) - : bar_{bar}, + : button{new Gtk::Button()}, + controllClick_{Gtk::GestureClick::create()}, + bar_{bar}, config_{config}, tbar_{tbar}, handle_{tl_handle}, @@ -280,14 +233,14 @@ Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar, content_{bar.orientation, 0} { zwlr_foreign_toplevel_handle_v1_add_listener(handle_, &toplevel_handle_impl, this); - button.set_relief(Gtk::RELIEF_NONE); + button->set_has_frame(false); - content_.add(text_before_); - content_.add(icon_); - content_.add(text_after_); + content_.append(text_before_); + content_.append(icon_); + content_.append(text_after_); content_.show(); - button.add(content_); + button->set_child(content_); format_before_.clear(); format_after_.clear(); @@ -331,20 +284,24 @@ Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar, /* Handle click events if configured */ if (config_["on-click"].isString() || config_["on-click-middle"].isString() || config_["on-click-right"].isString()) { - } - - button.add_events(Gdk::BUTTON_PRESS_MASK); - button.signal_button_release_event().connect(sigc::mem_fun(*this, &Task::handle_clicked), false); - - button.signal_motion_notify_event().connect(sigc::mem_fun(*this, &Task::handle_motion_notify), - false); - - button.drag_source_set(target_entries, Gdk::BUTTON1_MASK, Gdk::ACTION_MOVE); - button.drag_dest_set(target_entries, Gtk::DEST_DEFAULT_ALL, Gdk::ACTION_MOVE); - - button.signal_drag_data_get().connect(sigc::mem_fun(*this, &Task::handle_drag_data_get), false); - button.signal_drag_data_received().connect(sigc::mem_fun(*this, &Task::handle_drag_data_received), - false); + controllClick_->set_propagation_phase(Gtk::PropagationPhase::TARGET); + controllClick_->signal_released().connect(sigc::mem_fun(*this, &Task::handleClick), false); + button->add_controller(controllClick_); + } + + // Setup DND source + Glib::Value> buttonValue; + auto source = Gtk::DragSource::create(); + source->set_actions(Gdk::DragAction::COPY); + buttonValue.init(buttonValue.value_type()); + buttonValue.set(button); + source->set_content(Gdk::ContentProvider::create(buttonValue)); + button->add_controller(source); + // Setup DND target + const GType target_type = Glib::Value>::value_type(); + auto target = Gtk::DropTarget::create(target_type, Gdk::DragAction::COPY); + target->signal_drop().connect(sigc::mem_fun(*this, &Task::handleDropData), false); + button->add_controller(target); } Task::~Task() { @@ -452,13 +409,6 @@ void Task::handle_app_id(const char *app_id) { spdlog::debug("Couldn't find icon for {}", app_id_); } -void Task::on_button_size_allocated(Gtk::Allocation &alloc) { - gtk_widget_translate_coordinates(GTK_WIDGET(button.gobj()), GTK_WIDGET(bar_.window.gobj()), 0, 0, - &minimize_hint.x, &minimize_hint.y); - minimize_hint.w = button.get_width(); - minimize_hint.h = button.get_height(); -} - void Task::handle_output_enter(struct wl_output *output) { if (ignored_) { spdlog::debug("{} is ignored", repr()); @@ -469,10 +419,13 @@ void Task::handle_output_enter(struct wl_output *output) { if (!button_visible_ && (tbar_->all_outputs() || tbar_->show_output(output))) { /* The task entered the output of the current bar make the button visible */ - button.signal_size_allocate().connect_notify( - sigc::mem_fun(this, &Task::on_button_size_allocated)); + button->property_width_request().signal_changed().connect( + [&]() { minimize_hint.w = button->get_width(); }); + button->property_height_request().signal_changed().connect( + [&]() { minimize_hint.h = button->get_height(); }); + tbar_->add_button(button); - button.show(); + button->show(); button_visible_ = true; spdlog::debug("{} now visible on {}", repr(), bar_.output->name); } @@ -484,7 +437,7 @@ void Task::handle_output_leave(struct wl_output *output) { if (button_visible_ && !tbar_->all_outputs() && tbar_->show_output(output)) { /* The task left the output of the current bar, make the button invisible */ tbar_->remove_button(button); - button.hide(); + button->hide(); button_visible_ = false; spdlog::debug("{} now invisible on {}", repr(), bar_.output->name); } @@ -506,27 +459,27 @@ void Task::handle_done() { spdlog::debug("{} changed", repr()); if (state_ & MAXIMIZED) { - button.get_style_context()->add_class("maximized"); + button->get_style_context()->add_class("maximized"); } else if (!(state_ & MAXIMIZED)) { - button.get_style_context()->remove_class("maximized"); + button->get_style_context()->remove_class("maximized"); } if (state_ & MINIMIZED) { - button.get_style_context()->add_class("minimized"); + button->get_style_context()->add_class("minimized"); } else if (!(state_ & MINIMIZED)) { - button.get_style_context()->remove_class("minimized"); + button->get_style_context()->remove_class("minimized"); } if (state_ & ACTIVE) { - button.get_style_context()->add_class("active"); + button->get_style_context()->add_class("active"); } else if (!(state_ & ACTIVE)) { - button.get_style_context()->remove_class("active"); + button->get_style_context()->remove_class("active"); } if (state_ & FULLSCREEN) { - button.get_style_context()->add_class("fullscreen"); + button->get_style_context()->add_class("fullscreen"); } else if (!(state_ & FULLSCREEN)) { - button.get_style_context()->remove_class("fullscreen"); + button->get_style_context()->remove_class("fullscreen"); } if (config_["active-first"].isBool() && config_["active-first"].asBool() && active()) @@ -546,25 +499,19 @@ void Task::handle_closed() { tbar_->remove_task(id_); } -bool Task::handle_clicked(GdkEventButton *bt) { - /* filter out additional events for double/triple clicks */ - if (bt->type == GDK_BUTTON_PRESS) { - /* save where the button press occurred in case it becomes a drag */ - drag_start_button = bt->button; - drag_start_x = bt->x; - drag_start_y = bt->y; - } +void Task::handleClick(int n_press, double dx, double dy) { + auto currButton{controllClick_->get_current_button()}; std::string action; - if (config_["on-click"].isString() && bt->button == 1) + if (config_["on-click"].isString() && currButton == 1) action = config_["on-click"].asString(); - else if (config_["on-click-middle"].isString() && bt->button == 2) + else if (config_["on-click-middle"].isString() && currButton == 2) action = config_["on-click-middle"].asString(); - else if (config_["on-click-right"].isString() && bt->button == 3) + else if (config_["on-click-right"].isString() && currButton == 3) action = config_["on-click-right"].asString(); if (action.empty()) - return true; + return; else if (action == "activate") activate(); else if (action == "minimize") { @@ -586,52 +533,34 @@ bool Task::handle_clicked(GdkEventButton *bt) { close(); else spdlog::warn("Unknown action {}", action); - - drag_start_button = -1; - return true; } -bool Task::handle_motion_notify(GdkEventMotion *mn) { - if (drag_start_button == -1) return false; +bool Task::handleDropData(const Glib::ValueBase &value, double, double) { + if (G_VALUE_HOLDS(value.gobj(), Glib::Value>::value_type())) { + // Expand incoming value + Glib::Value> dropValue; + dropValue.init(value.gobj()); + const Glib::RefPtr draggedButton = dropValue.get(); + + if (draggedButton) { + if (draggedButton != this->button) { + auto draggedParent{draggedButton->get_parent()}; + auto droppedParent{this->button->get_parent()}; + if (draggedParent == droppedParent) { + auto draggedBox{(Gtk::Box *)draggedParent}; + // Need to move dragged button before the current + draggedBox->reorder_child_after(*draggedButton, *this->button); + draggedBox->reorder_child_after(*this->button, *draggedButton); + } + } + } - if (button.drag_check_threshold(drag_start_x, drag_start_y, mn->x, mn->y)) { - /* start drag in addition to other assigned action */ - auto target_list = Gtk::TargetList::create(target_entries); - auto refptr = Glib::RefPtr(target_list); - auto drag_context = - button.drag_begin(refptr, Gdk::DragAction::ACTION_MOVE, drag_start_button, (GdkEvent *)mn); + return true; + } else { + spdlog::warn("WLR taskbar. Received unexpected data type {} in button", + G_VALUE_TYPE_NAME(value.gobj())); + return false; } - - return false; -} - -void Task::handle_drag_data_get(const Glib::RefPtr &context, - Gtk::SelectionData &selection_data, guint info, guint time) { - spdlog::debug("drag_data_get"); - void *button_addr = (void *)&this->button; - - selection_data.set("WAYBAR_TOPLEVEL", 32, (const guchar *)&button_addr, sizeof(gpointer)); -} - -void Task::handle_drag_data_received(const Glib::RefPtr &context, int x, int y, - Gtk::SelectionData selection_data, guint info, guint time) { - spdlog::debug("drag_data_received"); - gpointer handle = *(gpointer *)selection_data.get_data(); - auto dragged_button = (Gtk::Button *)handle; - - if (dragged_button == &this->button) return; - - auto parent_of_dragged = dragged_button->get_parent(); - auto parent_of_dest = this->button.get_parent(); - - if (parent_of_dragged != parent_of_dest) return; - - auto box = (Gtk::Box *)parent_of_dragged; - - auto position_prop = box->child_property_position(this->button); - auto position = position_prop.get_value(); - - box->reorder_child(*dragged_button, position); } bool Task::operator==(const Task &o) const { return o.id_ == id_; } @@ -683,9 +612,9 @@ void Task::update() { fmt::arg("app_id", app_id), fmt::arg("state", state_string()), fmt::arg("short_state", state_string(true))); if (markup) - button.set_tooltip_markup(txt); + button->set_tooltip_markup(txt); else - button.set_tooltip_text(txt); + button->set_tooltip_text(txt); } } @@ -749,7 +678,6 @@ Taskbar::Taskbar(const std::string &id, const waybar::Bar &bar, const Json::Valu } box_.get_style_context()->add_class(MODULE_CLASS); box_.get_style_context()->add_class("empty"); - event_box_.add(box_); struct wl_display *display = Client::inst()->wl_display; struct wl_registry *registry = wl_display_get_registry(display); @@ -772,7 +700,7 @@ Taskbar::Taskbar(const std::string &id, const waybar::Bar &bar, const Json::Valu auto it_name = c.asString(); auto it = Gtk::IconTheme::create(); - it->set_custom_theme(it_name); + it->set_theme_name(it_name); spdlog::debug("Use custom icon theme: {}", it_name); icon_themes_.push_back(it); @@ -781,7 +709,7 @@ Taskbar::Taskbar(const std::string &id, const waybar::Bar &bar, const Json::Valu auto it_name = config_["icon-theme"].asString(); auto it = Gtk::IconTheme::create(); - it->set_custom_theme(it_name); + it->set_theme_name(it_name); spdlog::debug("Use custom icon theme: {}", it_name); icon_themes_.push_back(it); @@ -803,7 +731,7 @@ Taskbar::Taskbar(const std::string &id, const waybar::Bar &bar, const Json::Valu } } - icon_themes_.push_back(Gtk::IconTheme::get_default()); + icon_themes_.push_back(Gtk::IconTheme::get_for_display(box_.get_display())); for (auto &t : tasks_) { t->handle_app_id(t->app_id().c_str()); @@ -848,6 +776,8 @@ void Taskbar::update() { AModule::update(); } +Taskbar::operator Gtk::Widget &() { return box_; } + static void tm_handle_toplevel(void *data, struct zwlr_foreign_toplevel_manager_v1 *manager, struct zwlr_foreign_toplevel_handle_v1 *tl_handle) { return static_cast(data)->handle_toplevel_create(tl_handle); @@ -905,15 +835,23 @@ void Taskbar::handle_finished() { manager_ = nullptr; } -void Taskbar::add_button(Gtk::Button &bt) { - box_.pack_start(bt, false, false); +void Taskbar::add_button(Glib::RefPtr bt) { + box_.append(*bt); box_.get_style_context()->remove_class("empty"); } -void Taskbar::move_button(Gtk::Button &bt, int pos) { box_.reorder_child(bt, pos); } +void Taskbar::move_button(Glib::RefPtr bt, int pos) { + try { + const auto sibling{(box_.get_children()).at(pos - 1)}; + + if (sibling) box_.reorder_child_after(*bt, *sibling); + } catch (const std::out_of_range &ex) { + spdlog::error("WLR taskbar. {}", ex.what()); + } +} -void Taskbar::remove_button(Gtk::Button &bt) { - box_.remove(bt); +void Taskbar::remove_button(Glib::RefPtr bt) { + box_.remove(*bt); if (box_.get_children().empty()) { box_.get_style_context()->add_class("empty"); } diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp index 3c630d814..21be8f86e 100644 --- a/src/modules/wlr/workspace_manager.cpp +++ b/src/modules/wlr/workspace_manager.cpp @@ -1,16 +1,8 @@ #include "modules/wlr/workspace_manager.hpp" -#include -#include #include -#include -#include -#include -#include - #include "client.hpp" -#include "gtkmm/widget.h" #include "modules/wlr/workspace_manager_binding.hpp" namespace waybar::modules::wlr { @@ -53,7 +45,6 @@ WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar box_.get_style_context()->add_class(id); } box_.get_style_context()->add_class(MODULE_CLASS); - event_box_.add(box_); add_registry_listener(this); if (!workspace_manager_) { @@ -114,7 +105,11 @@ auto WorkspaceManager::sort_workspaces() -> void { std::sort(all_workspaces.begin(), all_workspaces.end(), workspace_comparator()); for (size_t i = 0; i < all_workspaces.size(); ++i) { - box_.reorder_child(all_workspaces[i].get()->get_button_ref(), i); + if (i == 0) + box_.reorder_child_at_start(all_workspaces[i].get()->get_button_ref()); + else + box_.reorder_child_after(all_workspaces[i].get()->get_button_ref(), + all_workspaces[i - 1].get()->get_button_ref()); } } @@ -161,6 +156,8 @@ auto WorkspaceManager::update() -> void { AModule::update(); } +WorkspaceManager::operator Gtk::Widget &() { return box_; } + WorkspaceManager::~WorkspaceManager() { if (!workspace_manager_) { return; @@ -253,9 +250,7 @@ auto WorkspaceGroup::creation_delayed() const -> bool { return workspace_manager_.creation_delayed(); } -auto WorkspaceGroup::add_button(Gtk::Button &button) -> void { - box_.pack_start(button, false, false); -} +auto WorkspaceGroup::add_button(Gtk::Button &button) -> void { box_.append(button); } WorkspaceGroup::~WorkspaceGroup() { if (!workspace_group_handle_) { @@ -366,7 +361,11 @@ auto WorkspaceGroup::commit() -> void { workspace_manager_.commit(); } auto WorkspaceGroup::sort_workspaces() -> void { std::sort(workspaces_.begin(), workspaces_.end(), workspace_manager_.workspace_comparator()); for (size_t i = 0; i < workspaces_.size(); ++i) { - box_.reorder_child(workspaces_[i]->get_button_ref(), i); + if (i == 0) + box_.reorder_child_at_start(workspaces_[i]->get_button_ref()); + else + box_.reorder_child_after(workspaces_[i]->get_button_ref(), + workspaces_[i - 1]->get_button_ref()); } } @@ -379,7 +378,8 @@ Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup & workspace_group_(workspace_group), workspace_handle_(workspace), id_(id), - name_(name) { + name_(name), + controllClick_{Gtk::GestureClick::create()} { if (workspace) { add_workspace_listener(workspace, this); } else { @@ -401,21 +401,21 @@ Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup & /* Handle click events if configured */ if (config_["on-click"].isString() || config_["on-click-middle"].isString() || config_["on-click-right"].isString()) { - button_.add_events(Gdk::BUTTON_PRESS_MASK); - button_.signal_button_press_event().connect(sigc::mem_fun(*this, &Workspace::handle_clicked), - false); + controllClick_->set_propagation_phase(Gtk::PropagationPhase::TARGET); + controllClick_->signal_released().connect(sigc::mem_fun(*this, &Workspace::handleClick), false); + button_.add_controller(controllClick_); } - button_.set_relief(Gtk::RELIEF_NONE); - content_.set_center_widget(label_); - button_.add(content_); + button_.set_has_frame(false); + content_.append(label_); + button_.set_child(content_); if (!workspace_group.is_visible()) { return; } workspace_group.add_button(button_); - button_.show_all(); + button_.show(); } Workspace::~Workspace() { @@ -484,7 +484,7 @@ auto Workspace::handle_done() -> void { } if (workspace_group_.active_only() && (is_active() || is_urgent())) { - button_.show_all(); + button_.show(); } else if (workspace_group_.active_only() && !(is_active() || is_urgent())) { button_.hide(); } @@ -518,18 +518,20 @@ auto Workspace::get_icon() -> std::string { return name_; } -auto Workspace::handle_clicked(GdkEventButton *bt) -> bool { +void Workspace::handleClick(int n_press, double dx, double dy) { + auto currButton{controllClick_->get_current_button()}; + std::string action; - if (config_["on-click"].isString() && bt->button == 1) { + if (config_["on-click"].isString() && currButton == 1) { action = config_["on-click"].asString(); - } else if (config_["on-click-middle"].isString() && bt->button == 2) { + } else if (config_["on-click-middle"].isString() && currButton == 2) { action = config_["on-click-middle"].asString(); - } else if (config_["on-click-right"].isString() && bt->button == 3) { + } else if (config_["on-click-right"].isString() && currButton == 3) { action = config_["on-click-right"].asString(); } if (action.empty()) - return true; + return; else if (action == "activate") { zext_workspace_handle_v1_activate(workspace_handle_); } else if (action == "close") { @@ -539,11 +541,9 @@ auto Workspace::handle_clicked(GdkEventButton *bt) -> bool { } workspace_group_.commit(); - - return true; } -auto Workspace::show() -> void { button_.show_all(); } +auto Workspace::show() -> void { button_.show(); } auto Workspace::hide() -> void { button_.hide(); } auto Workspace::handle_name(const std::string &name) -> void {