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