diff --git a/include/components/controller.hpp b/include/components/controller.hpp index 3b25b099..e6e14aa1 100644 --- a/include/components/controller.hpp +++ b/include/components/controller.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -9,6 +10,7 @@ #include "events/signal_receiver.hpp" #include "events/types.hpp" #include "utils/file.hpp" +#include "utils/plugin.hpp" #include "x11/types.hpp" POLYBAR_NS @@ -142,6 +144,11 @@ class controller : public signal_receiver m_threads; + + /** + * @brief Loaded plugins + */ + std::list m_plugins; }; POLYBAR_NS_END diff --git a/include/modules/meta/factory.hpp b/include/modules/meta/factory.hpp index 8d140e1c..9e8e3f89 100644 --- a/include/modules/meta/factory.hpp +++ b/include/modules/meta/factory.hpp @@ -7,23 +7,25 @@ POLYBAR_NS namespace modules { - using factory_map = std::unordered_map>; + using factory_function = module_interface* (*)(const bar_settings&, string); + using factory_map = std::unordered_map; factory_map& get_factory_map(); template class module_registration { public: - module_registration(string name) { - get_factory_map()[std::move(name)] = [](const bar_settings& bar, string module_name) { - return new Module(bar, std::move(module_name)); - }; + module_registration(string name, factory_function ff) { + get_factory_map()[std::move(name)] = ff; } }; module_interface* make_module(string&& name, const bar_settings& bar, string module_name); } // namespace modules -#define POLYBAR_MODULE(MODULE_TYPE, MODULE_NAME) \ - module_registration MODULE_TYPE ## _registration{MODULE_NAME} +#define POLYBAR_MODULE(MODULE_TYPE, MODULE_NAME) \ + module_interface* MODULE_TYPE##_create(const bar_settings& bar, std::string module_name) { \ + return new MODULE_TYPE(bar, std::move(module_name)); \ + } \ + module_registration MODULE_TYPE##_registration(MODULE_NAME, &MODULE_TYPE##_create) POLYBAR_NS_END diff --git a/include/utils/plugin.hpp b/include/utils/plugin.hpp new file mode 100644 index 00000000..853cdf58 --- /dev/null +++ b/include/utils/plugin.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include "common.hpp" +#include "components/logger.hpp" + +POLYBAR_NS + +class plugin_handle { + public: + plugin_handle(const char* libname); + ~plugin_handle(); + + plugin_handle(const plugin_handle&) = delete; + plugin_handle& operator=(const plugin_handle&) = delete; + + plugin_handle(plugin_handle&&); + plugin_handle& operator=(plugin_handle&&); + + private: + void* m_handle = nullptr; +}; + +// clang-format off +const static std::array plugin_names = { + "libpolybar-utils-i3.so", + "libpolybar-modules-alsa.so", + "libpolybar-modules-github.so", + "libpolybar-modules-i3.so", + "libpolybar-modules-mpd.so", + "libpolybar-modules-network.so", + "libpolybar-modules-pulseaudio.so", + "libpolybar-modules-xkeyboard.so" +}; +// clang-format on + +POLYBAR_NS_END diff --git a/include/utils/restack.hpp b/include/utils/restack.hpp new file mode 100644 index 00000000..067be38e --- /dev/null +++ b/include/utils/restack.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include + +#include "common.hpp" +#include "components/types.hpp" +#include "x11/extensions/randr.hpp" + +POLYBAR_NS + +class connection; +class logger; + +namespace restack { + + struct wm_restacker { + virtual void operator()(connection& conn, const bar_settings& opts, const logger& log) const = 0; + }; + + using restacker_map = std::unordered_map>; + + restacker_map& get_restacker_map(); + + const wm_restacker* get_restacker(const std::string& name); + + template + struct restacker_registration { + restacker_registration(std::string name) { + get_restacker_map()[std::move(name)] = std::make_unique(); + } + }; + +#define POLYBAR_RESTACKER(RESTACKER_TYPE, RESTACKER_NAME) \ + restacker_registration RESTACKER_TYPE##_registration(RESTACKER_NAME) + +} // namespace restack + +POLYBAR_NS_END diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index ed5c9204..a089a1aa 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -39,8 +39,6 @@ list(APPEND dirs ${XPP_INCLUDE_DIRS}) if(ENABLE_I3) add_subdirectory(i3ipcpp) - list(APPEND libs ${I3IPCPP_LIBRARIES}) - list(APPEND dirs ${I3IPCPP_INCLUDE_DIRS}) set_property(TARGET i3ipc++ PROPERTY POSITION_INDEPENDENT_CODE ON) set(I3IPCPP_LIBRARIES ${I3IPCPP_LIBRARIES} PARENT_SCOPE) set(I3IPCPP_INCLUDE_DIRS ${I3IPCPP_INCLUDE_DIRS} PARENT_SCOPE) diff --git a/lib/i3ipcpp b/lib/i3ipcpp index d4e4786b..21ce9060 160000 --- a/lib/i3ipcpp +++ b/lib/i3ipcpp @@ -1 +1 @@ -Subproject commit d4e4786be35b48d72dc7e59cf85ec34a90d129b5 +Subproject commit 21ce9060ac7c502225fdbd2f200b1cbdd8eca08d diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 146644c1..35371390 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,7 +23,7 @@ make_executable(polybar INCLUDE_DIRS ${dirs} TARGET_DEPENDS - ${shared_modules} + polybar-modules-internal_shared polybar-components_static polybar-drawtypes_static polybar-events_static diff --git a/src/components/CMakeLists.txt b/src/components/CMakeLists.txt index a64403d6..efd4e70c 100644 --- a/src/components/CMakeLists.txt +++ b/src/components/CMakeLists.txt @@ -13,11 +13,8 @@ make_library(polybar-components renderer.cpp screen.cpp taskqueue.cpp - ../utils/i3.cpp INCLUDE_DIRS ${dirs} - ${I3IPCPP_INCLUDE_DIRS} RAW_DEPENDS ${libs} - polybar-cairo_static - ${I3IPCPP_LIBRARIES}) + polybar-cairo_static) diff --git a/src/components/bar.cpp b/src/components/bar.cpp index cbd9ad13..2c80a11c 100644 --- a/src/components/bar.cpp +++ b/src/components/bar.cpp @@ -9,7 +9,7 @@ #include "components/types.hpp" #include "events/signal.hpp" #include "events/signal_emitter.hpp" -#include "utils/bspwm.hpp" +#include "utils/restack.hpp" #include "utils/color.hpp" #include "utils/factory.hpp" #include "utils/math.hpp" @@ -25,10 +25,6 @@ #include "x11/cursor.hpp" #endif -#if ENABLE_I3 -#include "utils/i3.hpp" -#endif - POLYBAR_NS using namespace signals::ui; @@ -437,26 +433,10 @@ void bar::restack_window() { return; } - auto restacked = false; - - if (wm_restack == "bspwm") { - restacked = bspwm_util::restack_to_root(m_connection, m_opts.monitor, m_opts.window); -#if ENABLE_I3 - } else if (wm_restack == "i3" && m_opts.override_redirect) { - restacked = i3_util::restack_to_root(m_connection, m_opts.window); - } else if (wm_restack == "i3" && !m_opts.override_redirect) { - m_log.warn("Ignoring restack of i3 window (not needed when `override-redirect = false`)"); - wm_restack.clear(); -#endif + if (auto restacker = restack::get_restacker(wm_restack)) { + (*restacker)(m_connection, m_opts, m_log); } else { m_log.warn("Ignoring unsupported wm-restack option '%s'", wm_restack); - wm_restack.clear(); - } - - if (restacked) { - m_log.info("Successfully restacked bar window"); - } else if (!wm_restack.empty()) { - m_log.err("Failed to restack bar window"); } } diff --git a/src/components/controller.cpp b/src/components/controller.cpp index 6a9bdc25..dd55972d 100644 --- a/src/components/controller.cpp +++ b/src/components/controller.cpp @@ -8,13 +8,14 @@ #include "components/types.hpp" #include "events/signal.hpp" #include "events/signal_emitter.hpp" +#include "modules/ipc.hpp" #include "modules/meta/event_handler.hpp" #include "modules/meta/factory.hpp" #include "modules/meta/input_handler.hpp" -#include "modules/ipc.hpp" #include "utils/command.hpp" #include "utils/factory.hpp" #include "utils/inotify.hpp" +#include "utils/plugin.hpp" #include "utils/string.hpp" #include "utils/time.hpp" #include "x11/connection.hpp" @@ -76,6 +77,15 @@ controller::controller(connection& conn, signal_emitter& emitter, const logger& sigaction(SIGUSR1, &act, nullptr); sigaction(SIGALRM, &act, nullptr); + m_log.trace("controller: Load plugins"); + for (const auto name : plugin_names) { + try { + m_plugins.emplace_back(name); + } catch (const application_error& err) { + m_log.warn("Failed to load plugin '%s': %s", name, err.what()); + } + } + m_log.trace("controller: Setup user-defined modules"); size_t created_modules{0}; diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt index b2b967ea..186f34e2 100644 --- a/src/modules/CMakeLists.txt +++ b/src/modules/CMakeLists.txt @@ -1,6 +1,6 @@ if(ENABLE_ALSA) make_library(polybar-modules-alsa - SHARED + MODULE SOURCES ../adapters/alsa/control.cpp ../adapters/alsa/mixer.cpp @@ -10,12 +10,11 @@ if(ENABLE_ALSA) ${alsa-dirs} RAW_DEPENDS ${alsa-libs}) - list(APPEND shared_modules polybar-modules-alsa_shared) endif() if(ENABLE_CURL) make_library(polybar-modules-github - SHARED + MODULE SOURCES ../utils/http.cpp github.cpp @@ -24,12 +23,11 @@ if(ENABLE_CURL) ${curl-dirs} RAW_DEPENDS ${curl-libs}) - list(APPEND shared_modules polybar-modules-github_shared) endif() if(ENABLE_MPD) make_library(polybar-modules-mpd - SHARED + MODULE SOURCES ../adapters/mpd.cpp mpd.cpp @@ -38,13 +36,12 @@ if(ENABLE_MPD) ${mpd-dirs} RAW_DEPENDS ${mpd-libs}) - list(APPEND shared_modules polybar-modules-mpd_shared) endif() if(ENABLE_NETWORK) list(APPEND net-src ../adapters/net.cpp network.cpp) make_library(polybar-modules-network - SHARED + MODULE SOURCES ${net-src} INCLUDE_DIRS @@ -52,26 +49,21 @@ if(ENABLE_NETWORK) ${net-dirs} RAW_DEPENDS ${net-libs}) - list(APPEND shared_modules polybar-modules-network_shared) endif() if(ENABLE_I3) make_library(polybar-modules-i3 - SHARED + MODULE SOURCES - ../utils/i3.cpp i3.cpp INCLUDE_DIRS ${dirs} - ${I3IPCPP_INCLUDE_DIRS} - RAW_DEPENDS - ${I3IPCPP_LIBRARIES}) - list(APPEND shared_modules polybar-modules-i3_shared) + ${I3IPCPP_INCLUDE_DIRS}) endif() if(ENABLE_PULSEAUDIO) make_library(polybar-modules-pulseaudio - SHARED + MODULE SOURCES ../adapters/pulseaudio.cpp pulseaudio.cpp @@ -80,12 +72,11 @@ if(ENABLE_PULSEAUDIO) ${pulse-dirs} RAW_DEPENDS ${pulse-libs}) - list(APPEND shared_modules polybar-modules-pulseaudio_shared) endif() if(WITH_XKB) make_library(polybar-modules-xkeyboard - SHARED + MODULE SOURCES ../x11/extensions/xkb.cpp xkeyboard.cpp @@ -94,7 +85,6 @@ if(WITH_XKB) ${xkb-dirs} RAW_DEPENDS ${xkb-libs}) - list(APPEND shared_modules polybar-modules-xkeyboard_shared) endif() make_library(polybar-modules-internal @@ -120,7 +110,6 @@ make_library(polybar-modules-internal xwindow.cpp xworkspaces.cpp INCLUDE_DIRS - ${dirs}) -list(APPEND shared_modules polybar-modules-internal_shared) - -set(shared_modules ${shared_modules} PARENT_SCOPE) + ${dirs} + RAW_DEPENDS + polybar-utils-bspwm_shared) diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 2cd955d6..0f64482a 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -2,7 +2,6 @@ make_library(polybar-utils STATIC INTERNAL SOURCES - bspwm.cpp command.cpp concurrency.cpp env.cpp @@ -10,11 +9,35 @@ make_library(polybar-utils file.cpp inotify.cpp io.cpp + plugin.cpp process.cpp + restack.cpp socket.cpp string.cpp throttle.cpp INCLUDE_DIRS ${dirs} + RAW_DEPENDS + ${libs} + ${CMAKE_DL_LIBS}) + +make_library(polybar-utils-bspwm + SHARED + SOURCES + bspwm.cpp + INCLUDE_DIRS + ${dirs} RAW_DEPENDS ${libs}) + +if(ENABLE_I3) + make_library(polybar-utils-i3 + SHARED + SOURCES + i3.cpp + INCLUDE_DIRS + ${dirs} + ${I3IPCPP_INCLUDE_DIRS} + RAW_DEPENDS + ${I3IPCPP_LIBRARIES}) +endif() diff --git a/src/utils/bspwm.cpp b/src/utils/bspwm.cpp index 570b1753..783a3838 100644 --- a/src/utils/bspwm.cpp +++ b/src/utils/bspwm.cpp @@ -1,8 +1,10 @@ #include +#include "components/logger.hpp" #include "errors.hpp" #include "utils/bspwm.hpp" #include "utils/env.hpp" +#include "utils/restack.hpp" #include "x11/connection.hpp" POLYBAR_NS @@ -146,6 +148,21 @@ namespace bspwm_util { } return conn; } -} +} // namespace bspwm_util + +namespace restack { + struct bspwm_restacker : public wm_restacker { + void operator()(connection& conn, const bar_settings& opts, const logger& log) const override { + auto restacked = bspwm_util::restack_to_root(conn, opts.monitor, opts.window); + if (restacked) { + log.info("Successfully restacked bar window"); + } else { + log.err("Failed to restack bar window"); + } + } + }; + + POLYBAR_RESTACKER(bspwm_restacker, "bspwm"); +} // namespace restack POLYBAR_NS_END diff --git a/src/utils/i3.cpp b/src/utils/i3.cpp index d78f2fb2..32a4af72 100644 --- a/src/utils/i3.cpp +++ b/src/utils/i3.cpp @@ -2,8 +2,10 @@ #include #include "common.hpp" +#include "components/logger.hpp" #include "settings.hpp" #include "utils/i3.hpp" +#include "utils/restack.hpp" #include "utils/socket.hpp" #include "utils/string.hpp" #include "x11/connection.hpp" @@ -78,6 +80,25 @@ namespace i3_util { } return false; } -} +} // namespace i3_util + +namespace restack { + struct i3_restacker : public wm_restacker { + void operator()(connection& conn, const bar_settings& opts, const logger& log) const override { + if (opts.override_redirect) { + auto restacked = i3_util::restack_to_root(conn, opts.window); + if (restacked) { + log.info("Successfully restacked bar window"); + } else { + log.err("Failed to restack bar window"); + } + } else { + log.warn("Ignoring restack of i3 window (not needed when `override-redirect = false`)"); + } + } + }; + + POLYBAR_RESTACKER(i3_restacker, "i3"); +} // namespace restack POLYBAR_NS_END diff --git a/src/utils/plugin.cpp b/src/utils/plugin.cpp new file mode 100644 index 00000000..f078e937 --- /dev/null +++ b/src/utils/plugin.cpp @@ -0,0 +1,35 @@ +#include + +#include "components/logger.hpp" +#include "errors.hpp" +#include "utils/plugin.hpp" + +POLYBAR_NS + +plugin_handle::plugin_handle(const char* libname) { + m_handle = ::dlopen(libname, RTLD_NOW | RTLD_GLOBAL); + if (!m_handle) + throw application_error(::dlerror()); +} + +plugin_handle::~plugin_handle() { + if (m_handle) { + ::dlclose(m_handle); + } +} + +plugin_handle::plugin_handle(plugin_handle&& ph) { + m_handle = ph.m_handle; + ph.m_handle = nullptr; +} + +plugin_handle& plugin_handle::operator=(plugin_handle&& ph) { + if (m_handle) { + ::dlclose(m_handle); + } + m_handle = ph.m_handle; + ph.m_handle = nullptr; + return *this; +} + +POLYBAR_NS_END diff --git a/src/utils/restack.cpp b/src/utils/restack.cpp new file mode 100644 index 00000000..822337ec --- /dev/null +++ b/src/utils/restack.cpp @@ -0,0 +1,24 @@ +#include "utils/restack.hpp" + +POLYBAR_NS + +namespace restack { + + restacker_map& get_restacker_map() { + static restacker_map rmap; + return rmap; + } + + const wm_restacker* get_restacker(const std::string& name) { + const auto& rmap = get_restacker_map(); + auto it = rmap.find(name); + if (it != rmap.end()) { + return it->second.get(); + } else { + return nullptr; + } + } + +} // namespace restack + +POLYBAR_NS_END