diff --git a/.clang-tidy b/.clang-tidy index a12c09fe..b558598b 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -32,8 +32,6 @@ Checks: ' CheckOptions: - key: modernize-loop-convert.NamingStyle value: lower_case - - key: readability-identifier-naming.GlobalConstantPrefix - value: 'g_' - key: readability-identifier-naming.ClassCase value: lower_case - key: readability-identifier-naming.ClassConstantCase diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 449e0921..9ec6ae5c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,8 +33,24 @@ jobs: env: COLOR: "ON" steps: + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + libxcb-composite0-dev \ + libxcb-ewmh-dev \ + libxcb-icccm4-dev \ + libxcb-image0-dev \ + libxcb-randr0-dev \ + libxcb-util0-dev \ + libxcb1-dev \ + libcairo2-dev \ + python3-xcbgen \ + libuv1-dev \ + xcb-proto - uses: actions/checkout@v2 with: + submodules: true ref: ${{ github.event.inputs.ref }} - name: Build polybar-msg run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f3527c6..3b12f450 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 and others will now start producing errors. This does not affect you unless you are producing your own formatting tags (for example in a script) and you are using one of these invalid tags. +- For security reasons, the named pipe at `/tmp/polybar_mqueue.` had its + permission bits changed from `666` to `600` to prevent sending ipc messages + to polybar processes running under a different user. ### Build - New dependency: [libuv](https://github.com/libuv/libuv). At least version 1.3 @@ -68,6 +71,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 bar update. - When not specifying the config file with `--config`, naming your config file `config` is deprecated. Rename your config file to `config.ini`. +- Directly writing ipc messages to `/tmp/polybar_mqueue.` is deprecated, + users should always use `polybar-msg`. As a consequence the message format + used for IPC is deprecated as well. ### Removed - `DEBUG_SHADED` cmake variable and its associated functionality. @@ -142,6 +148,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a new `tray-foreground` setting to give hints to tray icons about what color they should be. ([#2235](https://github.com/polybar/polybar/issues/2235)) +- `polybar-msg`: For module actions, you can now also specify the module name, + action name, and optional data as separate arguments. ### Changed - Polybar now also reads `config.ini` when searching for config files. diff --git a/cmake/01-core.cmake b/cmake/01-core.cmake index fe0032e5..7f8d55ef 100644 --- a/cmake/01-core.cmake +++ b/cmake/01-core.cmake @@ -22,13 +22,13 @@ include(CMakeDependentOption) CMAKE_DEPENDENT_OPTION(BUILD_DOC_HTML "Build HTML documentation" ON "BUILD_DOC" OFF) CMAKE_DEPENDENT_OPTION(BUILD_DOC_MAN "Build manpages" ON "BUILD_DOC" OFF) -if (BUILD_POLYBAR OR BUILD_TESTS) +if (BUILD_POLYBAR OR BUILD_TESTS OR BUILD_POLYBAR_MSG) set(BUILD_LIBPOLY ON) else() set(BUILD_LIBPOLY OFF) endif() -if (BUILD_LIBPOLY OR BUILD_POLYBAR_MSG) +if (BUILD_POLYBAR OR BUILD_POLYBAR_MSG OR BUILD_TESTS) set(HAS_CXX_COMPILATION ON) else() set(HAS_CXX_COMPILATION OFF) diff --git a/doc/conf.py b/doc/conf.py index 656c7291..22c1008e 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -182,6 +182,7 @@ latex_documents = [ # (source start file, name, description, authors, manual section). man_pages = [ ('man/polybar.1', 'polybar', 'A fast and easy-to-use tool status bar', [], 1), + ('man/polybar-msg.1', 'polybar-msg', 'Send IPC messages to polybar', [], 1), ('man/polybar.5', 'polybar', 'configuration file for polybar(1)', [], 5) ] diff --git a/doc/index.rst b/doc/index.rst index 41feece2..b7ca5773 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -13,12 +13,14 @@ Welcome to the official polybar documentation. :caption: Content: user/actions + user/ipc .. toctree:: :maxdepth: 1 :caption: Manual Pages: man/polybar.1 + man/polybar-msg.1 man/polybar.5 .. toctree:: diff --git a/doc/man/polybar-msg.1.rst b/doc/man/polybar-msg.1.rst new file mode 100644 index 00000000..0141b7a9 --- /dev/null +++ b/doc/man/polybar-msg.1.rst @@ -0,0 +1,75 @@ +polybar-msg(1) +============== + +SYNOPSIS +-------- +| **polybar-msg** [*OPTIONS*] **action** *action-string* +| **polybar-msg** [*OPTIONS*] **action** *module* *action* [*data*] +| **polybar-msg** [*OPTIONS*] **cmd** *command* + +DESCRIPTION +----------- +Polybar allows external control through *actions* and *commands*. +Actions control individual modules and commands control the bar itself. + +The full IPC documentation is linked at the end of this document. + +The available actions depend on the target module. +For actions, the payload is either a single action string or the module name, +the action name, and the optional data string specified separately. + +In order for **polybar-msg** being able to send a message to a running +**polybar** process, the bar must have IPC enabled and both **polybar-msg** and +**polybar** must run under the same user. + +OPTIONS +------- + +.. program:: polybar-msg + +.. option:: -h, --help + + Display help text and exit + +.. option:: -p PID + + Send message only to **polybar** process running under the given process ID. + If not specified, the message is sent to all running **polybar** processes. + +EXAMPLES +-------- + +**polybar-msg** **cmd** *quit* + Terminate all running **polybar** instances. + +**polybar-msg** **action** *mymodule* *module_hide* + +**polybar-msg** **action** "*#mymodule.module_hide*" + Hide the module named *mymodule*. + The first variant specifies the module and action names separately, the second uses an action string. + +AUTHORS +------- +| Polybar was created by Michael Carlberg and is currently maintained by Patrick Ziegler. +| Contributors can be listed on GitHub. + +REPORTING BUGS +-------------- +Report issues on GitHub + +SEE ALSO +-------- +.. only:: man + + :manpage:`polybar`\(1), + :manpage:`polybar`\(5) + + | IPC documentation: + + +.. only:: not man + + :doc:`polybar.1`, + :doc:`polybar.5` + + :doc:`/user/ipc` diff --git a/doc/man/polybar.1.rst b/doc/man/polybar.1.rst index a568c838..6df7eeba 100644 --- a/doc/man/polybar.1.rst +++ b/doc/man/polybar.1.rst @@ -66,9 +66,9 @@ OPTIONS Save png snapshot to *FILE* after running for 3 seconds -AUTHOR ------- -| Michael Carlberg +AUTHORS +------- +| Polybar was created by Michael Carlberg and is currently maintained by Patrick Ziegler. | Contributors can be listed on GitHub. REPORTING BUGS @@ -77,13 +77,16 @@ Report issues on GitHub SEE ALSO -------- -| Full documentation at: -| Project wiki: - .. only:: man - :manpage:`polybar(5)` + :manpage:`polybar-msg`\(1), + :manpage:`polybar`\(5) + .. only:: not man + :doc:`polybar-msg.1`, :doc:`polybar.5` + +| Full documentation at: +| Project wiki: diff --git a/doc/man/polybar.5.rst b/doc/man/polybar.5.rst index 9d893c85..659c858f 100644 --- a/doc/man/polybar.5.rst +++ b/doc/man/polybar.5.rst @@ -164,13 +164,21 @@ not affect polybar's behavior. Comment lines start with either the ``;`` or the name = value ; comment +AUTHORS +------- +| Polybar was created by Michael Carlberg and is currently maintained by Patrick Ziegler. +| Contributors can be listed on GitHub. + SEE ALSO -------- .. only:: man - :manpage:`polybar(1)` + :manpage:`polybar`\(1), + :manpage:`polybar-msg`\(1) + .. only:: not man - :doc:`polybar.1` + :doc:`polybar.1`, + :doc:`polybar-msg.1` diff --git a/doc/user/actions.rst b/doc/user/actions.rst index 95ae2a78..850a8c4a 100644 --- a/doc/user/actions.rst +++ b/doc/user/actions.rst @@ -258,6 +258,9 @@ custom/menu The data has the form ``N-M`` and the action will execute the command in ``menu-N-M-exec``. + +.. _actions-ipc: + custom/ipc ^^^^^^^^^^ diff --git a/doc/user/ipc.rst b/doc/user/ipc.rst new file mode 100644 index 00000000..b278ce36 --- /dev/null +++ b/doc/user/ipc.rst @@ -0,0 +1,107 @@ +Inter-process-messaging +======================= + +Polybar supports controlling parts of the bar and its modules from the outside +through inter-process-messaging (IPC). + +IPC is disabled by default and can be enabled by setting ``enable-ipc = true`` +in the bar section. + +By default polybar ships with the ``polybar-msg`` tool that is needed to send +messages to polybar. + +.. note:: Starting with version 3.6.0, the underlying IPC mechanism has been + completely changed. + + Writing directly to the named pipe to send IPC messages has been + deprecated, ``polybar-msg`` should be used exclusively + Everything you could do by directly writing to the named pipe, you + can also do using ``polybar-msg``. + In addition, hook messages are also deprecated; they are replaced by + actions on the :ref:`ipc module `. + + Unless noted otherwise, everything in this guide is still valid for + older versions. + +Sending Messages +---------------- + +``polybar-msg`` can be called on the commandline like this: + +.. code-block:: shell + + polybar-msg [-p ] + +If the ``-p`` argument is specified, the message is only sent to the running +polybar instance with the given process ID. +Otherwise, the message is sent to all running polybar processes that have IPC +enabled. + +.. note:: IPC messages are only sent to polybar instances running under the + same user as ``polybar-msg`` is running as. + +The ```` argument is either :ref:`action ` or +:ref:`cmd `. +The allowed values for ```` depend on the type. + +Message Types +------------- + +.. _ipc-commands: + +Commands +^^^^^^^^ + +Using ``cmd`` for ````, you can control certain aspects of the bar. + +Available values for ```` are: + +* ``quit``: Terminates the bar +* ``restart``: Restarts the bar in-place +* ``hide``: Hides the bar +* ``show``: Makes the bar visible again, if it was hidden +* ``toggle``: Toggles between the hidden and visible state. + +.. _ipc-actions: + +Module Actions +^^^^^^^^^^^^^^ + +For the ```` ``action``, ``polybar-msg`` can execute +:doc:`module actions ` in the bar. + +An action consists of the name of the target module, the name of the action and an optional data string: + +:: + + #.[.] + +More information about action strings and available actions can be found in +:doc:`actions` + +For example, if you have a date module named ``date``, you can toggle between +the regular and alternative label with: + +.. code-block:: shell + + polybar-msg action "#date.toggle" + +As an example for an action with data, say you have a menu module named +``powermenu``, you can open the menu level 0 using: + +.. code-block:: shell + + polybar-msg action "#powermenu.open.0" + + +.. note:: + + For convenience, ``polybar-msg`` also allows you to pass the module name, + action name, and data as separate arguments: + + .. code-block:: shell + + polybar-msg action date toggle + polybar-msg action powermenu open 0 + + .. versionadded:: 3.6.0 diff --git a/include/common.hpp b/include/common.hpp index 6da08c49..3e776f75 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -1,16 +1,15 @@ #pragma once +#include #include #include +#include #include -#include #include "settings.hpp" -#define POLYBAR_NS \ - namespace polybar { -#define POLYBAR_NS_END \ - } +#define POLYBAR_NS namespace polybar { +#define POLYBAR_NS_END } #ifndef PIPE_READ #define PIPE_READ 0 @@ -21,20 +20,20 @@ POLYBAR_NS -using std::string; -using std::size_t; -using std::move; -using std::forward; -using std::pair; -using std::function; -using std::shared_ptr; -using std::unique_ptr; -using std::make_unique; -using std::make_shared; -using std::make_pair; using std::array; -using std::vector; +using std::forward; +using std::function; +using std::make_pair; +using std::make_shared; +using std::make_unique; +using std::move; +using std::pair; +using std::shared_ptr; +using std::size_t; +using std::string; using std::to_string; +using std::unique_ptr; +using std::vector; using namespace std::string_literals; @@ -42,4 +41,13 @@ constexpr size_t operator"" _z(unsigned long long n) { return n; } +/** + * Convert an enum to its underlying type. + */ +template +constexpr auto to_integral(E e) { + static_assert(std::is_enum::value, "only enums are supported"); + return static_cast>(e); +} + POLYBAR_NS_END diff --git a/include/components/bar.hpp b/include/components/bar.hpp index 9e24f222..81ad1df7 100644 --- a/include/components/bar.hpp +++ b/include/components/bar.hpp @@ -63,9 +63,9 @@ class bar : public xpp::event::sink { public: using make_type = unique_ptr; - static make_type make(eventloop&, bool only_initialize_values = false); + static make_type make(eventloop::eventloop&, bool only_initialize_values = false); - explicit bar(connection&, signal_emitter&, const config&, const logger&, eventloop&, unique_ptr&&, + explicit bar(connection&, signal_emitter&, const config&, const logger&, eventloop::eventloop&, unique_ptr&&, unique_ptr&&, unique_ptr&&, unique_ptr&&, bool only_initialize_values); ~bar(); @@ -111,7 +111,7 @@ class bar : public xpp::event::sink m_screen; unique_ptr m_tray; unique_ptr m_renderer; @@ -127,10 +127,10 @@ class bar : public xpp::event::sink()}; + eventloop::TimerHandle& m_middleclick_timer{m_loop.handle()}; + eventloop::TimerHandle& m_rightclick_timer{m_loop.handle()}; + eventloop::TimerHandle& m_dim_timer{m_loop.handle()}; bool m_visible{true}; }; diff --git a/include/components/controller.hpp b/include/components/controller.hpp index 080100f8..526b39f0 100644 --- a/include/components/controller.hpp +++ b/include/components/controller.hpp @@ -25,7 +25,6 @@ class bar; class config; class connection; class inotify_watch; -class ipc; class logger; class signal_emitter; namespace modules { @@ -41,9 +40,9 @@ class controller : public signal_receiver { public: using make_type = unique_ptr; - static make_type make(unique_ptr&& ipc); + static make_type make(bool has_ipc, eventloop::eventloop&); - explicit controller(connection&, signal_emitter&, const logger&, const config&, unique_ptr&&); + explicit controller(connection&, signal_emitter&, const logger&, const config&, bool has_ipc, eventloop::eventloop&); ~controller(); bool run(bool writeback, string snapshot_dst, bool confwatch); @@ -56,8 +55,8 @@ class controller : public signal_receiver m_loop; + eventloop::eventloop& m_loop; unique_ptr m_bar; - unique_ptr m_ipc; - - /** - * Once this is set to true, 'm_loop' and any uv handles can be used. - */ - std::atomic_bool m_loop_ready{false}; + bool m_has_ipc; /** * \brief Async handle to notify the eventloop @@ -114,7 +108,7 @@ class controller : public signal_receiver([this]() { notifier_handler(); })}; /** * Notification data for the controller. diff --git a/include/components/eventloop.hpp b/include/components/eventloop.hpp index 553bdff4..1673910b 100644 --- a/include/components/eventloop.hpp +++ b/include/components/eventloop.hpp @@ -6,160 +6,406 @@ #include "common.hpp" #include "components/logger.hpp" +#include "utils/mixins.hpp" POLYBAR_NS +namespace eventloop { /** * Runs any libuv function with an integer error code return value and throws an * exception on error. */ -#define UV(fun, ...) \ - do { \ - int res = fun(__VA_ARGS__); \ - if (res < 0) { \ - throw std::runtime_error( \ - __FILE__ ":"s + std::to_string(__LINE__) + ": libuv error for '" #fun "': "s + uv_strerror(res)); \ - } \ +#define UV(fun, ...) \ + do { \ + int res = fun(__VA_ARGS__); \ + if (res < 0) { \ + throw std::runtime_error(__FILE__ ":"s + std::to_string(__LINE__) + \ + ": libuv error for '" #fun "(" #__VA_ARGS__ ")': "s + uv_strerror(res)); \ + } \ } while (0); -void close_callback(uv_handle_t*); + using cb_void = function; -/** - * \tparam H Type of the handle - * \tparam I Type of the handle passed to the callback. Often the same as H, but not always (e.g. uv_read_start) - */ -template -struct UVHandleGeneric { - UVHandleGeneric(function fun) { - handle = new H; - handle->data = this; - this->func = fun; - } + template + using cb_event = std::function; - ~UVHandleGeneric() { - close(); - } - - uv_loop_t* loop() const { - return handle->loop; - } - - void close() { - if (!is_closing()) { - uv_close((uv_handle_t*)handle, close_callback); + template + class Handle : public non_copyable_mixin { + public: + Handle(uv_loop_t* l) : uv_loop(l) { + get()->data = this; } - } - bool is_closing() { - return !handle || uv_is_closing((uv_handle_t*)handle); - } - - bool is_active() { - return uv_is_active((uv_handle_t*)handle) != 0; - } - - void cleanup_resources() { - if (handle) { - delete handle; - handle = nullptr; + Self& leak(std::unique_ptr h) { + lifetime_extender = std::move(h); + return *lifetime_extender; } - } - static void callback(I* context, Args... args) { - const auto unpackedThis = static_cast(context->data); - return unpackedThis->func(std::forward(args)...); - } + void unleak() { + lifetime_extender.reset(); + } - H* handle{nullptr}; - function func; -}; + H* raw() { + return get(); + } -template -struct UVHandle : public UVHandleGeneric { - UVHandle(function fun) : UVHandleGeneric(fun) {} -}; + const H* raw() const { + return get(); + } -struct SignalHandle : public UVHandle { - SignalHandle(uv_loop_t* loop, function fun); - void start(int signum); -}; + void close() { + if (!is_closing()) { + uv_close((uv_handle_t*)get(), [](uv_handle_t* handle) { close_callback(*static_cast(handle->data)); }); + } + } -struct PollHandle : public UVHandle { - PollHandle(uv_loop_t* loop, int fd, function fun, function err_cb); - void start(int events); - void poll_cb(int status, int events); + bool is_closing() const { + return uv_is_closing(this->template get()); + } - function func; - function err_cb; -}; + bool is_active() { + return uv_is_active(this->template get()) != 0; + } -struct FSEventHandle : public UVHandle { - FSEventHandle(uv_loop_t* loop, function fun, function err_cb); - void start(const string& path); - void fs_event_cb(const char* path, int events, int status); + protected: + /** + * Generic callback function that can be used for all uv handle callbacks. + * + * \tparam Event Event class/struct. Must have a constructor that takes all arguments passed to the uv callback, + * except for the handle argument. + * \tparam Member Pointer to class member where callback function is stored + * \tparam Args Additional arguments in the uv callback. Inferred by the compiler + */ + template Self::*Member, typename... Args> + static void event_cb(H* handle, Args... args) { + Self& This = *static_cast(handle->data); + (This.*Member)(Event{std::forward(args)...}); + } - function func; - function err_cb; -}; + /** + * Same as event_cb except that no event is constructed. + */ + template + static void void_event_cb(H* handle) { + Self& This = *static_cast(handle->data); + (This.*Member)(); + } -struct PipeHandle : public UVHandleGeneric { - PipeHandle(uv_loop_t* loop, const string& path, function fun, function eof_cb, - function err_cb); - void start(); - void read_cb(ssize_t nread, const uv_buf_t* buf); + static Self& cast(H* handle) { + return *static_cast(handle->data); + } - function func; - function eof_cb; - function err_cb; - int fd; - string path; -}; + template + T* get() { + return reinterpret_cast(&uv_handle); + } -struct TimerHandle : public UVHandle { - TimerHandle(uv_loop_t* loop, function fun); - void start(uint64_t timeout, uint64_t repeat, function new_cb = function(nullptr)); - void stop(); -}; + template + const T* get() const { + return reinterpret_cast(&uv_handle); + } -struct AsyncHandle : public UVHandle { - AsyncHandle(uv_loop_t* loop, function fun); - void send(); -}; + uv_loop_t* loop() const { + return uv_loop; + } -using SignalHandle_t = std::unique_ptr; -using PollHandle_t = std::unique_ptr; -using FSEventHandle_t = std::unique_ptr; -using PipeHandle_t = std::unique_ptr; -// shared_ptr because we also return the pointer in order to call methods on it -using TimerHandle_t = std::shared_ptr; -using AsyncHandle_t = std::shared_ptr; + static void close_callback(Self& self) { + self.unleak(); + } -class eventloop { - public: - eventloop(); - ~eventloop(); - void run(); - void stop(); - void signal_handle(int signum, function fun); - void poll_handle(int events, int fd, function fun, function err_cb); - void fs_event_handle(const string& path, function fun, function err_cb); - void pipe_handle( - const string& path, function fun, function eof_cb, function err_cb); - TimerHandle_t timer_handle(function fun); - AsyncHandle_t async_handle(function fun); + static void alloc_callback(uv_handle_t*, size_t, uv_buf_t* buf) { + buf->base = new char[BUFSIZ]; + buf->len = BUFSIZ; + } - protected: - uv_loop_t* get() const; + private: + H uv_handle; + uv_loop_t* uv_loop; - private: - std::unique_ptr m_loop{nullptr}; + /** + * The handle stores the unique_ptr to itself so that it effectively leaks memory. + * + * This saves us from having to guarantee that the handle's lifetime extends to at least after it is closed. + * + * Once the handle is closed, either explicitly or by walking all handles when the loop shuts down, this reference + * is reset and the object is explicitly destroyed. + */ + std::unique_ptr lifetime_extender; + }; - vector m_sig_handles; - vector m_poll_handles; - vector m_fs_event_handles; - vector m_pipe_handles; - vector m_timer_handles; - vector m_async_handles; -}; + struct ErrorEvent { + int status; + }; + + using cb_error = cb_event; + + class WriteRequest : public non_copyable_mixin { + public: + using cb_write = cb_void; + + WriteRequest(cb_write user_cb, cb_error err_cb) : write_callback(user_cb), write_err_cb(err_cb) { + get()->data = this; + }; + + static WriteRequest& create(cb_write user_cb, cb_error err_cb) { + auto r = std::make_unique(user_cb, err_cb); + return r->leak(std::move(r)); + }; + + uv_write_t* get() { + return &req; + } + + /** + * Trigger the write callback. + * + * After that, this object is destroyed. + */ + void trigger(int status) { + if (status < 0) { + if (write_err_cb) { + write_err_cb(ErrorEvent{status}); + } + } else { + if (write_callback) { + write_callback(); + } + } + + unleak(); + } + + protected: + WriteRequest& leak(std::unique_ptr h) { + lifetime_extender = std::move(h); + return *lifetime_extender; + } + + void unleak() { + lifetime_extender.reset(); + } + + private: + uv_write_t req; + + cb_write write_callback; + cb_error write_err_cb; + + /** + * The handle stores the unique_ptr to itself so that it effectively leaks memory. + * + * This means that each instance manages its own lifetime. + */ + std::unique_ptr lifetime_extender; + }; + + struct SignalEvent { + int signum; + }; + + class SignalHandle : public Handle { + public: + using Handle::Handle; + using cb = cb_event; + + void init(); + void start(int signum, cb user_cb); + + private: + cb callback; + }; + + struct PollEvent { + uv_poll_event event; + }; + + class PollHandle : public Handle { + public: + using Handle::Handle; + using cb = cb_event; + + void init(int fd); + void start(int events, cb user_cb, cb_error err_cb); + static void poll_callback(uv_poll_t*, int status, int events); + + private: + cb callback; + cb_error err_cb; + }; + + struct FSEvent { + const char* path; + uv_fs_event event; + }; + + class FSEventHandle : public Handle { + public: + using Handle::Handle; + using cb = cb_event; + + void init(); + void start(const string& path, int flags, cb user_cb, cb_error err_cb); + static void fs_event_callback(uv_fs_event_t*, const char* path, int events, int status); + + private: + cb callback; + cb_error err_cb; + }; + + class TimerHandle : public Handle { + public: + using Handle::Handle; + using cb = cb_void; + + void init(); + void start(uint64_t timeout, uint64_t repeat, cb user_cb); + void stop(); + + private: + cb callback; + }; + + class AsyncHandle : public Handle { + public: + using Handle::Handle; + using cb = cb_void; + + void init(cb user_cb); + void send(); + + private: + cb callback; + }; + + struct ReadEvent { + const char* data; + size_t len; + }; + + template + class StreamHandle : public Handle { + public: + using Handle::Handle; + using cb_read = cb_event; + using cb_read_eof = cb_void; + using cb_connection = cb_void; + + void listen(int backlog, cb_connection user_cb, cb_error err_cb) { + this->connection_callback = user_cb; + this->connection_err_cb = err_cb; + UV(uv_listen, this->template get(), backlog, connection_cb); + }; + + static void connection_cb(uv_stream_t* server, int status) { + auto& self = Self::cast((H*)server); + + if (status == 0) { + self.connection_callback(); + } else { + self.connection_err_cb(ErrorEvent{status}); + } + } + + template + void accept(StreamHandle& client) { + UV(uv_accept, this->template get(), client.template get()); + } + + void read_start(cb_read fun, cb_void eof_cb, cb_error err_cb) { + this->read_callback = fun; + this->read_eof_cb = eof_cb; + this->read_err_cb = err_cb; + UV(uv_read_start, this->template get(), &this->alloc_callback, read_cb); + }; + + static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { + auto& self = Self::cast((H*)handle); + /* + * Wrap pointer so that it gets automatically freed once the function returns (even with exceptions) + */ + auto buf_ptr = unique_ptr(buf->base); + if (nread > 0) { + self.read_callback(ReadEvent{buf->base, (size_t)nread}); + } else if (nread < 0) { + if (nread != UV_EOF) { + self.read_err_cb(ErrorEvent{(int)nread}); + } else { + self.read_eof_cb(); + } + } + }; + + void write(const vector& data, WriteRequest::cb_write user_cb = {}, cb_error err_cb = {}) { + WriteRequest& req = WriteRequest::create(user_cb, err_cb); + + uv_buf_t buf{(char*)data.data(), data.size()}; + + UV(uv_write, req.get(), this->template get(), &buf, 1, + [](uv_write_t* r, int status) { static_cast(r->data)->trigger(status); }); + } + + private: + /** + * Callback for receiving data + */ + cb_read read_callback; + + /** + * Callback for receiving EOF. + * + * Called after the associated handle has been closed. + */ + cb_read_eof read_eof_cb; + + /** + * Called if an error occurs. + */ + cb_error read_err_cb; + + cb_connection connection_callback; + cb_error connection_err_cb; + }; + + class PipeHandle : public StreamHandle { + public: + using StreamHandle::StreamHandle; + using cb_connect = cb_void; + + void init(bool ipc = false); + void open(int fd); + + void bind(const string& path); + + void connect(const string& name, cb_connect user_cb, cb_error err_cb); + + private: + static void connect_cb(uv_connect_t* req, int status); + + cb_error connect_err_cb; + cb_connect connect_callback; + }; + + class eventloop { + public: + eventloop(); + ~eventloop(); + void run(); + void stop(); + + template + H& handle(Args... args) { + auto ptr = make_unique(get()); + ptr->init(std::forward(args)...); + return ptr->leak(std::move(ptr)); + } + + protected: + uv_loop_t* get() const; + + private: + std::unique_ptr m_loop{nullptr}; + }; + +} // namespace eventloop POLYBAR_NS_END diff --git a/include/components/ipc.hpp b/include/components/ipc.hpp deleted file mode 100644 index 1d376952..00000000 --- a/include/components/ipc.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include - -#include "common.hpp" -#include "settings.hpp" -#include "utils/concurrency.hpp" - -POLYBAR_NS - -class signal_emitter; -class logger; - -/** - * Component used for inter-process communication. - * - * A unique messaging channel will be setup for each - * running process which will allow messages and - * events to be sent to the process externally. - */ -class ipc { - public: - using make_type = unique_ptr; - static make_type make(); - - explicit ipc(signal_emitter& emitter, const logger& logger); - ~ipc(); - - string get_path() const; - - void receive_data(string buf); - void receive_eof(); - - private: - signal_emitter& m_sig; - const logger& m_log; - - string m_path{}; - - /** - * Buffer for the currently received IPC message. - */ - string m_buffer{}; -}; - -POLYBAR_NS_END diff --git a/include/drawtypes/animation.hpp b/include/drawtypes/animation.hpp index 843f9729..5f8066b7 100644 --- a/include/drawtypes/animation.hpp +++ b/include/drawtypes/animation.hpp @@ -13,7 +13,7 @@ POLYBAR_NS namespace chrono = std::chrono; namespace drawtypes { - class animation : public non_copyable_mixin { + class animation : public non_copyable_mixin { public: explicit animation(unsigned int framerate_ms) : m_framerate_ms(framerate_ms) {} explicit animation(vector&& frames, int framerate_ms) diff --git a/include/drawtypes/iconset.hpp b/include/drawtypes/iconset.hpp index 075d4b86..242f2923 100644 --- a/include/drawtypes/iconset.hpp +++ b/include/drawtypes/iconset.hpp @@ -9,7 +9,7 @@ POLYBAR_NS namespace drawtypes { - class iconset : public non_copyable_mixin { + class iconset : public non_copyable_mixin { public: void add(string id, label_t&& icon); bool has(const string& id); @@ -21,6 +21,6 @@ namespace drawtypes { }; using iconset_t = shared_ptr; -} +} // namespace drawtypes POLYBAR_NS_END diff --git a/include/drawtypes/label.hpp b/include/drawtypes/label.hpp index 144446ae..b20b6bca 100644 --- a/include/drawtypes/label.hpp +++ b/include/drawtypes/label.hpp @@ -18,7 +18,7 @@ namespace drawtypes { bool zpad{false}; }; - class label : public non_copyable_mixin