1 #pragma once 2 3 #include <chrono> 4 #include <memory> 5 6 #include "cairo/context.hpp" 7 #include "cairo/surface.hpp" 8 #include "common.hpp" 9 #include "components/logger.hpp" 10 #include "components/types.hpp" 11 #include "events/signal_fwd.hpp" 12 #include "events/signal_receiver.hpp" 13 #include "utils/concurrency.hpp" 14 #include "x11/atoms.hpp" 15 #include "x11/connection.hpp" 16 #include "x11/tray_client.hpp" 17 18 #define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 19 #define _NET_SYSTEM_TRAY_ORIENTATION_VERT 1 20 21 #define SYSTEM_TRAY_REQUEST_DOCK 0 22 #define SYSTEM_TRAY_BEGIN_MESSAGE 1 23 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 24 25 #define TRAY_WM_NAME "Polybar tray window" 26 #define TRAY_WM_CLASS "tray\0Polybar" 27 28 #define TRAY_PLACEHOLDER "<placeholder-systray>" 29 30 POLYBAR_NS 31 32 namespace chrono = std::chrono; 33 using namespace std::chrono_literals; 34 35 // fwd declarations 36 class connection; 37 class background_manager; 38 class bg_slice; 39 40 struct tray_settings { 41 tray_settings() = default; 42 tray_settings& operator=(const tray_settings& o) = default; 43 44 alignment align{alignment::NONE}; 45 bool running{false}; 46 int rel_x{0}; 47 int rel_y{0}; 48 int orig_x{0}; 49 int orig_y{0}; 50 int configured_x{0}; 51 int configured_y{0}; 52 unsigned int configured_w{0U}; 53 unsigned int configured_h{0U}; 54 unsigned int configured_slots{0U}; 55 unsigned int width{0U}; 56 unsigned int width_max{0U}; 57 unsigned int height{0U}; 58 unsigned int height_fill{0U}; 59 unsigned int spacing{0U}; 60 unsigned int sibling{0U}; 61 rgba background{}; 62 bool transparent{false}; 63 bool detached{false}; 64 }; 65 66 class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify, evt::client_message, 67 evt::configure_request, evt::resize_request, evt::selection_clear, evt::property_notify, 68 evt::reparent_notify, evt::destroy_notify, evt::map_notify, evt::unmap_notify>, 69 public signal_receiver<SIGN_PRIORITY_TRAY, signals::ui::visibility_change, signals::ui::dim_window, 70 signals::ui::update_background> { 71 public: 72 using make_type = unique_ptr<tray_manager>; 73 static make_type make(); 74 75 explicit tray_manager(connection& conn, signal_emitter& emitter, const logger& logger, background_manager& back); 76 77 ~tray_manager(); 78 79 const tray_settings settings() const; 80 81 void setup(const bar_settings& bar_opts); 82 void activate(); 83 void activate_delayed(chrono::duration<double, std::milli> delay = 1s); 84 void deactivate(bool clear_selection = true); 85 void reconfigure(); 86 87 protected: 88 void reconfigure_window(); 89 void reconfigure_clients(); 90 void reconfigure_bg(bool realloc = false); 91 void refresh_window(); 92 void redraw_window(bool realloc_bg = false); 93 94 void query_atom(); 95 void create_window(); 96 void create_bg(bool realloc = false); 97 void restack_window(); 98 void set_wm_hints(); 99 void set_tray_colors(); 100 101 void acquire_selection(); 102 void notify_clients(); 103 void notify_clients_delayed(); 104 105 void track_selection_owner(xcb_window_t owner); 106 void process_docking_request(xcb_window_t win); 107 108 int calculate_x(unsigned width, bool abspos = true) const; 109 int calculate_y(bool abspos = true) const; 110 unsigned short int calculate_w() const; 111 unsigned short int calculate_h() const; 112 113 int calculate_client_x(const xcb_window_t& win); 114 int calculate_client_y(); 115 116 bool is_embedded(const xcb_window_t& win) const; 117 shared_ptr<tray_client> find_client(const xcb_window_t& win) const; 118 void remove_client(shared_ptr<tray_client>& client, bool reconfigure = true); 119 void remove_client(xcb_window_t win, bool reconfigure = true); 120 unsigned int mapped_clients() const; 121 122 void handle(const evt::expose& evt); 123 void handle(const evt::visibility_notify& evt); 124 void handle(const evt::client_message& evt); 125 void handle(const evt::configure_request& evt); 126 void handle(const evt::resize_request& evt); 127 void handle(const evt::selection_clear& evt); 128 void handle(const evt::property_notify& evt); 129 void handle(const evt::reparent_notify& evt); 130 void handle(const evt::destroy_notify& evt); 131 void handle(const evt::map_notify& evt); 132 void handle(const evt::unmap_notify& evt); 133 134 bool on(const signals::ui::visibility_change& evt); 135 bool on(const signals::ui::dim_window& evt); 136 bool on(const signals::ui::update_background& evt); 137 138 private: 139 connection& m_connection; 140 signal_emitter& m_sig; 141 const logger& m_log; 142 background_manager& m_background_manager; 143 std::shared_ptr<bg_slice> m_bg_slice; 144 vector<shared_ptr<tray_client>> m_clients; 145 146 tray_settings m_opts{}; 147 148 xcb_gcontext_t m_gc{0}; 149 xcb_pixmap_t m_pixmap{0}; 150 unique_ptr<cairo::surface> m_surface; 151 unique_ptr<cairo::context> m_context; 152 153 unsigned int m_prevwidth{0U}; 154 unsigned int m_prevheight{0U}; 155 156 xcb_atom_t m_atom{0}; 157 xcb_window_t m_tray{0}; 158 xcb_window_t m_othermanager{0}; 159 160 atomic<bool> m_activated{false}; 161 atomic<bool> m_mapped{false}; 162 atomic<bool> m_hidden{false}; 163 atomic<bool> m_acquired_selection{false}; 164 165 thread m_delaythread; 166 167 mutex m_mtx{}; 168 169 bool m_firstactivation{true}; 170 }; 171 172 POLYBAR_NS_END 173