tray: Cleanup
This commit is contained in:
parent
ca25b5685c
commit
f5d16891dd
@ -7,22 +7,22 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
namespace modules {
|
namespace modules {
|
||||||
class tray_module : public static_module<tray_module> {
|
class tray_module : public static_module<tray_module> {
|
||||||
public:
|
public:
|
||||||
explicit tray_module(const bar_settings& bar_settings, string name_);
|
explicit tray_module(const bar_settings& bar_settings, string name_);
|
||||||
string get_format() const;
|
string get_format() const;
|
||||||
|
|
||||||
void start() override;
|
void start() override;
|
||||||
|
|
||||||
bool build(builder* builder, const string& tag) const;
|
bool build(builder* builder, const string& tag) const;
|
||||||
void update() {}
|
void update() {}
|
||||||
|
|
||||||
static constexpr auto TYPE = "internal/tray";
|
static constexpr auto TYPE = "internal/tray";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr const char* TAG_TRAY{"<tray>"};
|
static constexpr const char* TAG_TRAY{"<tray>"};
|
||||||
|
|
||||||
tray_manager m_tray;
|
tray::manager m_tray;
|
||||||
};
|
};
|
||||||
} // namespace modules
|
} // namespace modules
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -20,11 +20,13 @@ POLYBAR_NS
|
|||||||
// fwd declarations
|
// fwd declarations
|
||||||
class connection;
|
class connection;
|
||||||
|
|
||||||
class tray_client : public non_copyable_mixin, public non_movable_mixin {
|
namespace tray {
|
||||||
|
|
||||||
|
class client : public non_copyable_mixin, public non_movable_mixin {
|
||||||
public:
|
public:
|
||||||
explicit tray_client(
|
explicit client(
|
||||||
const logger& log, connection& conn, xcb_window_t parent, xcb_window_t win, size s, uint32_t desired_background);
|
const logger& log, connection& conn, xcb_window_t parent, xcb_window_t win, size s, uint32_t desired_background);
|
||||||
~tray_client();
|
~client();
|
||||||
|
|
||||||
string name() const;
|
string name() const;
|
||||||
|
|
||||||
@ -44,7 +46,7 @@ class tray_client : public non_copyable_mixin, public non_movable_mixin {
|
|||||||
bool should_be_mapped() const;
|
bool should_be_mapped() const;
|
||||||
|
|
||||||
xcb_window_t embedder() const;
|
xcb_window_t embedder() const;
|
||||||
xcb_window_t client() const;
|
xcb_window_t client_window() const;
|
||||||
|
|
||||||
void query_xembed();
|
void query_xembed();
|
||||||
bool is_xembed_supported() const;
|
bool is_xembed_supported() const;
|
||||||
@ -63,7 +65,6 @@ class tray_client : public non_copyable_mixin, public non_movable_mixin {
|
|||||||
protected:
|
protected:
|
||||||
void observe_background();
|
void observe_background();
|
||||||
|
|
||||||
protected:
|
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
|
|
||||||
connection& m_connection;
|
connection& m_connection;
|
||||||
@ -103,7 +104,7 @@ class tray_client : public non_copyable_mixin, public non_movable_mixin {
|
|||||||
*
|
*
|
||||||
* Only valid if m_xembed_supported == true
|
* Only valid if m_xembed_supported == true
|
||||||
*/
|
*/
|
||||||
xembed::info m_xembed;
|
xembed::info m_xembed{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the wrapper window is currently mapped.
|
* Whether the wrapper window is currently mapped.
|
||||||
@ -125,4 +126,6 @@ class tray_client : public non_copyable_mixin, public non_movable_mixin {
|
|||||||
unique_ptr<cairo::xcb_surface> m_surface;
|
unique_ptr<cairo::xcb_surface> m_surface;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace tray
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -25,14 +25,16 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
namespace chrono = std::chrono;
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
using std::atomic;
|
|
||||||
|
|
||||||
// fwd declarations
|
// fwd declarations
|
||||||
class connection;
|
class connection;
|
||||||
class bg_slice;
|
class bg_slice;
|
||||||
|
|
||||||
|
namespace tray {
|
||||||
|
|
||||||
|
namespace chrono = std::chrono;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
using std::atomic;
|
||||||
|
|
||||||
struct tray_settings {
|
struct tray_settings {
|
||||||
/**
|
/**
|
||||||
* Dimensions for client windows.
|
* Dimensions for client windows.
|
||||||
@ -56,16 +58,16 @@ struct tray_settings {
|
|||||||
|
|
||||||
using on_update = std::function<void(void)>;
|
using on_update = std::function<void(void)>;
|
||||||
|
|
||||||
class tray_manager : public xpp::event::sink<evt::expose, evt::client_message, evt::configure_request,
|
class manager : public xpp::event::sink<evt::expose, evt::client_message, evt::configure_request, evt::resize_request,
|
||||||
evt::resize_request, evt::selection_clear, evt::property_notify, evt::reparent_notify,
|
evt::selection_clear, evt::property_notify, evt::reparent_notify, evt::destroy_notify,
|
||||||
evt::destroy_notify, evt::map_notify, evt::unmap_notify>,
|
evt::map_notify, evt::unmap_notify>,
|
||||||
public signal_receiver<SIGN_PRIORITY_TRAY, signals::ui::update_background,
|
public signal_receiver<SIGN_PRIORITY_TRAY, signals::ui::update_background,
|
||||||
signals::ui_tray::tray_pos_change, signals::ui_tray::tray_visibility> {
|
signals::ui_tray::tray_pos_change, signals::ui_tray::tray_visibility> {
|
||||||
public:
|
public:
|
||||||
explicit tray_manager(connection& conn, signal_emitter& emitter, const logger& logger, const bar_settings& bar_opts,
|
explicit manager(connection& conn, signal_emitter& emitter, const logger& logger, const bar_settings& bar_opts,
|
||||||
on_update on_update);
|
on_update on_update);
|
||||||
|
|
||||||
~tray_manager();
|
~manager() override;
|
||||||
|
|
||||||
unsigned get_width() const;
|
unsigned get_width() const;
|
||||||
|
|
||||||
@ -115,8 +117,8 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::client_message, e
|
|||||||
void update_width();
|
void update_width();
|
||||||
|
|
||||||
bool is_embedded(const xcb_window_t& win);
|
bool is_embedded(const xcb_window_t& win);
|
||||||
tray_client* find_client(const xcb_window_t& win);
|
client* find_client(const xcb_window_t& win);
|
||||||
void remove_client(const tray_client& client);
|
void remove_client(const client& client);
|
||||||
void remove_client(xcb_window_t win);
|
void remove_client(xcb_window_t win);
|
||||||
void clean_clients();
|
void clean_clients();
|
||||||
bool change_visibility(bool visible);
|
bool change_visibility(bool visible);
|
||||||
@ -140,7 +142,7 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::client_message, e
|
|||||||
connection& m_connection;
|
connection& m_connection;
|
||||||
signal_emitter& m_sig;
|
signal_emitter& m_sig;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
vector<unique_ptr<tray_client>> m_clients;
|
vector<unique_ptr<client>> m_clients;
|
||||||
|
|
||||||
tray_settings m_opts{};
|
tray_settings m_opts{};
|
||||||
const bar_settings& m_bar_opts;
|
const bar_settings& m_bar_opts;
|
||||||
@ -200,4 +202,6 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::client_message, e
|
|||||||
bool m_firstactivation{true};
|
bool m_firstactivation{true};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace tray
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -33,31 +33,31 @@ static constexpr uint32_t XEMBED_MAX_VERSION = 0;
|
|||||||
*/
|
*/
|
||||||
namespace xembed {
|
namespace xembed {
|
||||||
|
|
||||||
class info {
|
class info {
|
||||||
public:
|
public:
|
||||||
void set(uint32_t* data);
|
void set(const uint32_t* data);
|
||||||
|
|
||||||
uint32_t get_version() const;
|
uint32_t get_version() const;
|
||||||
uint32_t get_flags() const;
|
uint32_t get_flags() const;
|
||||||
|
|
||||||
bool is_mapped() const;
|
bool is_mapped() const;
|
||||||
|
|
||||||
string to_string() const;
|
string to_string() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool query(connection& conn, xcb_window_t win, info& data);
|
bool query(connection& conn, xcb_window_t win, info& data);
|
||||||
void send_message(connection& conn, xcb_window_t target, uint32_t message, uint32_t d1, uint32_t d2, uint32_t d3);
|
void send_message(connection& conn, xcb_window_t target, uint32_t message, uint32_t d1, uint32_t d2, uint32_t d3);
|
||||||
void send_focus_event(connection& conn, xcb_window_t target);
|
void send_focus_event(connection& conn, xcb_window_t target);
|
||||||
void notify_embedded(connection& conn, xcb_window_t win, xcb_window_t embedder, uint32_t version);
|
void notify_embedded(connection& conn, xcb_window_t win, xcb_window_t embedder, uint32_t version);
|
||||||
void notify_activated(connection& conn, xcb_window_t win);
|
void notify_activated(connection& conn, xcb_window_t win);
|
||||||
void notify_deactivated(connection& conn, xcb_window_t win);
|
void notify_deactivated(connection& conn, xcb_window_t win);
|
||||||
void notify_focused(connection& conn, xcb_window_t win, uint32_t focus_type);
|
void notify_focused(connection& conn, xcb_window_t win, uint32_t focus_type);
|
||||||
void notify_unfocused(connection& conn, xcb_window_t win);
|
void notify_unfocused(connection& conn, xcb_window_t win);
|
||||||
void unembed(connection& conn, xcb_window_t win, xcb_window_t root);
|
void unembed(connection& conn, xcb_window_t win, xcb_window_t root);
|
||||||
} // namespace xembed
|
} // namespace xembed
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
|
namespace tray {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO proper background of wrapper window
|
* TODO proper background of wrapper window
|
||||||
*
|
*
|
||||||
@ -20,7 +22,7 @@ POLYBAR_NS
|
|||||||
* 2. Use pseudo-transparency when activated (make sure the depths match)
|
* 2. Use pseudo-transparency when activated (make sure the depths match)
|
||||||
* 3. Use background color
|
* 3. Use background color
|
||||||
*/
|
*/
|
||||||
tray_client::tray_client(
|
client::client(
|
||||||
const logger& log, connection& conn, xcb_window_t parent, xcb_window_t win, size s, uint32_t desired_background)
|
const logger& log, connection& conn, xcb_window_t parent, xcb_window_t win, size s, uint32_t desired_background)
|
||||||
: m_log(log)
|
: m_log(log)
|
||||||
, m_connection(conn)
|
, m_connection(conn)
|
||||||
@ -88,7 +90,7 @@ tray_client::tray_client(
|
|||||||
xcb_params_gc_t params{};
|
xcb_params_gc_t params{};
|
||||||
uint32_t mask = 0;
|
uint32_t mask = 0;
|
||||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, graphics_exposures, 1);
|
XCB_AUX_ADD_PARAM(&mask, ¶ms, graphics_exposures, 1);
|
||||||
std::array<uint32_t, 32> values;
|
std::array<uint32_t, 32> values{};
|
||||||
connection::pack_values(mask, ¶ms, values);
|
connection::pack_values(mask, ¶ms, values);
|
||||||
m_connection.create_gc_checked(gc, pixmap, mask, values.data());
|
m_connection.create_gc_checked(gc, pixmap, mask, values.data());
|
||||||
} catch (const std::exception& err) {
|
} catch (const std::exception& err) {
|
||||||
@ -108,7 +110,7 @@ tray_client::tray_client(
|
|||||||
observe_background();
|
observe_background();
|
||||||
}
|
}
|
||||||
|
|
||||||
tray_client::~tray_client() {
|
client::~client() {
|
||||||
if (m_client != XCB_NONE) {
|
if (m_client != XCB_NONE) {
|
||||||
xembed::unembed(m_connection, m_client, m_connection.root());
|
xembed::unembed(m_connection, m_client, m_connection.root());
|
||||||
}
|
}
|
||||||
@ -118,19 +120,19 @@ tray_client::~tray_client() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string tray_client::name() const {
|
string client::name() const {
|
||||||
return "tray_client(" + m_connection.id(m_client) + ", " + m_name + ")";
|
return "client(" + m_connection.id(m_client) + ", " + m_name + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int tray_client::width() const {
|
unsigned int client::width() const {
|
||||||
return m_size.w;
|
return m_size.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int tray_client::height() const {
|
unsigned int client::height() const {
|
||||||
return m_size.h;
|
return m_size.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_client::clear_window() const {
|
void client::clear_window() const {
|
||||||
if (!mapped()) {
|
if (!mapped()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -141,19 +143,20 @@ void tray_client::clear_window() const {
|
|||||||
auto send_visibility = [&](uint8_t state) {
|
auto send_visibility = [&](uint8_t state) {
|
||||||
xcb_visibility_notify_event_t evt{};
|
xcb_visibility_notify_event_t evt{};
|
||||||
evt.response_type = XCB_VISIBILITY_NOTIFY;
|
evt.response_type = XCB_VISIBILITY_NOTIFY;
|
||||||
evt.window = client();
|
evt.window = client_window();
|
||||||
evt.state = state;
|
evt.state = state;
|
||||||
|
|
||||||
m_connection.send_event_checked(true, client(), XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char*>(&evt));
|
m_connection.send_event_checked(
|
||||||
|
true, client_window(), XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char*>(&evt));
|
||||||
};
|
};
|
||||||
|
|
||||||
send_visibility(XCB_VISIBILITY_FULLY_OBSCURED);
|
send_visibility(XCB_VISIBILITY_FULLY_OBSCURED);
|
||||||
send_visibility(XCB_VISIBILITY_UNOBSCURED);
|
send_visibility(XCB_VISIBILITY_UNOBSCURED);
|
||||||
|
|
||||||
m_connection.clear_area_checked(1, client(), 0, 0, width(), height());
|
m_connection.clear_area_checked(1, client_window(), 0, 0, width(), height());
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_client::update_client_attributes() const {
|
void client::update_client_attributes() const {
|
||||||
uint32_t configure_mask = 0;
|
uint32_t configure_mask = 0;
|
||||||
std::array<uint32_t, 32> configure_values{};
|
std::array<uint32_t, 32> configure_values{};
|
||||||
xcb_params_cw_t configure_params{};
|
xcb_params_cw_t configure_params{};
|
||||||
@ -164,32 +167,32 @@ void tray_client::update_client_attributes() const {
|
|||||||
connection::pack_values(configure_mask, &configure_params, configure_values);
|
connection::pack_values(configure_mask, &configure_params, configure_values);
|
||||||
|
|
||||||
m_log.trace("%s: Update client window", name());
|
m_log.trace("%s: Update client window", name());
|
||||||
m_connection.change_window_attributes_checked(client(), configure_mask, configure_values.data());
|
m_connection.change_window_attributes_checked(client_window(), configure_mask, configure_values.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_client::reparent() const {
|
void client::reparent() const {
|
||||||
m_log.trace("%s: Reparent client", name());
|
m_log.trace("%s: Reparent client", name());
|
||||||
m_connection.reparent_window_checked(client(), embedder(), 0, 0);
|
m_connection.reparent_window_checked(client_window(), embedder(), 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this the client for the given client window
|
* Is this the client for the given client window
|
||||||
*/
|
*/
|
||||||
bool tray_client::match(const xcb_window_t& win) const {
|
bool client::match(const xcb_window_t& win) const {
|
||||||
return win == m_client;
|
return win == m_client;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get client window mapped state
|
* Get client window mapped state
|
||||||
*/
|
*/
|
||||||
bool tray_client::mapped() const {
|
bool client::mapped() const {
|
||||||
return m_mapped;
|
return m_mapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set client window mapped state
|
* Set client window mapped state
|
||||||
*/
|
*/
|
||||||
void tray_client::mapped(bool state) {
|
void client::mapped(bool state) {
|
||||||
if (m_mapped != state) {
|
if (m_mapped != state) {
|
||||||
m_log.trace("%s: set mapped: %i", name(), state);
|
m_log.trace("%s: set mapped: %i", name(), state);
|
||||||
m_mapped = state;
|
m_mapped = state;
|
||||||
@ -201,14 +204,14 @@ void tray_client::mapped(bool state) {
|
|||||||
*
|
*
|
||||||
* Use this to trigger a mapping/unmapping
|
* Use this to trigger a mapping/unmapping
|
||||||
*/
|
*/
|
||||||
void tray_client::hidden(bool state) {
|
void client::hidden(bool state) {
|
||||||
m_hidden = state;
|
m_hidden = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the current state indicates the client should be mapped.
|
* Whether the current state indicates the client should be mapped.
|
||||||
*/
|
*/
|
||||||
bool tray_client::should_be_mapped() const {
|
bool client::should_be_mapped() const {
|
||||||
if (m_hidden) {
|
if (m_hidden) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -220,15 +223,15 @@ bool tray_client::should_be_mapped() const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_window_t tray_client::embedder() const {
|
xcb_window_t client::embedder() const {
|
||||||
return m_wrapper;
|
return m_wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_window_t tray_client::client() const {
|
xcb_window_t client::client_window() const {
|
||||||
return m_client;
|
return m_client;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_client::query_xembed() {
|
void client::query_xembed() {
|
||||||
m_xembed_supported = xembed::query(m_connection, m_client, m_xembed);
|
m_xembed_supported = xembed::query(m_connection, m_client, m_xembed);
|
||||||
|
|
||||||
if (is_xembed_supported()) {
|
if (is_xembed_supported()) {
|
||||||
@ -238,30 +241,30 @@ void tray_client::query_xembed() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tray_client::is_xembed_supported() const {
|
bool client::is_xembed_supported() const {
|
||||||
return m_xembed_supported;
|
return m_xembed_supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
const xembed::info& tray_client::get_xembed() const {
|
const xembed::info& client::get_xembed() const {
|
||||||
return m_xembed;
|
return m_xembed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_client::notify_xembed() const {
|
void client::notify_xembed() const {
|
||||||
if (is_xembed_supported()) {
|
if (is_xembed_supported()) {
|
||||||
m_log.trace("%s: Send embedded notification to client", name());
|
m_log.trace("%s: Send embedded notification to client", name());
|
||||||
xembed::notify_embedded(m_connection, client(), embedder(), m_xembed.get_version());
|
xembed::notify_embedded(m_connection, client_window(), embedder(), m_xembed.get_version());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_client::add_to_save_set() const {
|
void client::add_to_save_set() const {
|
||||||
m_log.trace("%s: Add client window to the save set", name());
|
m_log.trace("%s: Add client window to the save set", name());
|
||||||
m_connection.change_save_set_checked(XCB_SET_MODE_INSERT, client());
|
m_connection.change_save_set_checked(XCB_SET_MODE_INSERT, client_window());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make sure that the window mapping state is correct
|
* Make sure that the window mapping state is correct
|
||||||
*/
|
*/
|
||||||
void tray_client::ensure_state() const {
|
void client::ensure_state() const {
|
||||||
bool new_state = should_be_mapped();
|
bool new_state = should_be_mapped();
|
||||||
|
|
||||||
if (new_state == m_mapped) {
|
if (new_state == m_mapped) {
|
||||||
@ -273,10 +276,10 @@ void tray_client::ensure_state() const {
|
|||||||
if (new_state) {
|
if (new_state) {
|
||||||
m_log.trace("%s: Map client", name());
|
m_log.trace("%s: Map client", name());
|
||||||
m_connection.map_window_checked(embedder());
|
m_connection.map_window_checked(embedder());
|
||||||
m_connection.map_window_checked(client());
|
m_connection.map_window_checked(client_window());
|
||||||
} else {
|
} else {
|
||||||
m_log.trace("%s: Unmap client", name());
|
m_log.trace("%s: Unmap client", name());
|
||||||
m_connection.unmap_window_checked(client());
|
m_connection.unmap_window_checked(client_window());
|
||||||
m_connection.unmap_window_checked(embedder());
|
m_connection.unmap_window_checked(embedder());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,7 +287,7 @@ void tray_client::ensure_state() const {
|
|||||||
/**
|
/**
|
||||||
* Configure window position
|
* Configure window position
|
||||||
*/
|
*/
|
||||||
void tray_client::set_position(int x, int y) {
|
void client::set_position(int x, int y) {
|
||||||
m_log.trace("%s: moving to (%d, %d)", name(), x, y);
|
m_log.trace("%s: moving to (%d, %d)", name(), x, y);
|
||||||
|
|
||||||
position new_pos{x, y};
|
position new_pos{x, y};
|
||||||
@ -312,12 +315,12 @@ void tray_client::set_position(int x, int y) {
|
|||||||
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, x, 0);
|
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, x, 0);
|
||||||
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, y, 0);
|
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, y, 0);
|
||||||
connection::pack_values(configure_mask, &configure_params, configure_values);
|
connection::pack_values(configure_mask, &configure_params, configure_values);
|
||||||
m_connection.configure_window_checked(client(), configure_mask, configure_values.data());
|
m_connection.configure_window_checked(client_window(), configure_mask, configure_values.data());
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
xcb_size_hints_t size_hints{};
|
xcb_size_hints_t size_hints{};
|
||||||
xcb_icccm_size_hints_set_size(&size_hints, false, m_size.w, m_size.h);
|
xcb_icccm_size_hints_set_size(&size_hints, false, m_size.w, m_size.h);
|
||||||
xcb_icccm_set_wm_size_hints(m_connection, client(), XCB_ATOM_WM_NORMAL_HINTS, &size_hints);
|
xcb_icccm_set_wm_size_hints(m_connection, client_window(), XCB_ATOM_WM_NORMAL_HINTS, &size_hints);
|
||||||
|
|
||||||
// The position has changed, we need a new background slice.
|
// The position has changed, we need a new background slice.
|
||||||
observe_background();
|
observe_background();
|
||||||
@ -326,11 +329,11 @@ void tray_client::set_position(int x, int y) {
|
|||||||
/**
|
/**
|
||||||
* Respond to client resize/move requests
|
* Respond to client resize/move requests
|
||||||
*/
|
*/
|
||||||
void tray_client::configure_notify() const {
|
void client::configure_notify() const {
|
||||||
xcb_configure_notify_event_t notify;
|
xcb_configure_notify_event_t notify;
|
||||||
notify.response_type = XCB_CONFIGURE_NOTIFY;
|
notify.response_type = XCB_CONFIGURE_NOTIFY;
|
||||||
notify.event = client();
|
notify.event = client_window();
|
||||||
notify.window = client();
|
notify.window = client_window();
|
||||||
notify.override_redirect = false;
|
notify.override_redirect = false;
|
||||||
notify.above_sibling = 0;
|
notify.above_sibling = 0;
|
||||||
notify.x = 0;
|
notify.x = 0;
|
||||||
@ -340,13 +343,13 @@ void tray_client::configure_notify() const {
|
|||||||
notify.border_width = 0;
|
notify.border_width = 0;
|
||||||
|
|
||||||
unsigned int mask{XCB_EVENT_MASK_STRUCTURE_NOTIFY};
|
unsigned int mask{XCB_EVENT_MASK_STRUCTURE_NOTIFY};
|
||||||
m_connection.send_event_checked(false, client(), mask, reinterpret_cast<const char*>(¬ify));
|
m_connection.send_event_checked(false, client_window(), mask, reinterpret_cast<const char*>(¬ify));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redraw background using the observed background slice.
|
* Redraw background using the observed background slice.
|
||||||
*/
|
*/
|
||||||
void tray_client::update_bg() const {
|
void client::update_bg() const {
|
||||||
m_log.trace("%s: Update background", name());
|
m_log.trace("%s: Update background", name());
|
||||||
|
|
||||||
// Composite background slice with background color.
|
// Composite background slice with background color.
|
||||||
@ -363,11 +366,13 @@ void tray_client::update_bg() const {
|
|||||||
m_connection.flush();
|
m_connection.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_client::observe_background() {
|
void client::observe_background() {
|
||||||
xcb_rectangle_t rect{0, 0, static_cast<uint16_t>(m_size.w), static_cast<uint16_t>(m_size.h)};
|
xcb_rectangle_t rect{0, 0, static_cast<uint16_t>(m_size.w), static_cast<uint16_t>(m_size.h)};
|
||||||
m_bg_slice = m_background_manager.observe(rect, embedder());
|
m_bg_slice = m_background_manager.observe(rect, embedder());
|
||||||
|
|
||||||
update_bg();
|
update_bg();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace tray
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <xcb/xcb_image.h>
|
#include <xcb/xcb_image.h>
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "cairo/context.hpp"
|
#include "cairo/context.hpp"
|
||||||
#include "cairo/surface.hpp"
|
#include "cairo/surface.hpp"
|
||||||
@ -50,13 +51,15 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
tray_manager::tray_manager(
|
namespace tray {
|
||||||
|
|
||||||
|
manager::manager(
|
||||||
connection& conn, signal_emitter& emitter, const logger& logger, const bar_settings& bar_opts, on_update on_update)
|
connection& conn, signal_emitter& emitter, const logger& logger, const bar_settings& bar_opts, on_update on_update)
|
||||||
: m_connection(conn), m_sig(emitter), m_log(logger), m_bar_opts(bar_opts), m_on_update(on_update) {
|
: m_connection(conn), m_sig(emitter), m_log(logger), m_bar_opts(bar_opts), m_on_update(std::move(on_update)) {
|
||||||
m_connection.attach_sink(this, SINK_PRIORITY_TRAY);
|
m_connection.attach_sink(this, SINK_PRIORITY_TRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
tray_manager::~tray_manager() {
|
manager::~manager() {
|
||||||
if (m_delaythread.joinable()) {
|
if (m_delaythread.joinable()) {
|
||||||
m_delaythread.join();
|
m_delaythread.join();
|
||||||
}
|
}
|
||||||
@ -64,7 +67,7 @@ tray_manager::~tray_manager() {
|
|||||||
deactivate();
|
deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_manager::setup(const config& conf, const string& section_name) {
|
void manager::setup(const config& conf, const string& section_name) {
|
||||||
unsigned client_height = m_bar_opts.inner_area().height;
|
unsigned client_height = m_bar_opts.inner_area().height;
|
||||||
|
|
||||||
// Add user-defined padding
|
// Add user-defined padding
|
||||||
@ -101,30 +104,30 @@ void tray_manager::setup(const config& conf, const string& section_name) {
|
|||||||
activate();
|
activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned tray_manager::get_width() const {
|
unsigned manager::get_width() const {
|
||||||
return m_tray_width;
|
return m_tray_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tray_manager::is_active() const {
|
bool manager::is_active() const {
|
||||||
return m_state == state::ACTIVE;
|
return m_state == state::ACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tray_manager::is_inactive() const {
|
bool manager::is_inactive() const {
|
||||||
return m_state == state::INACTIVE;
|
return m_state == state::INACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tray_manager::is_waiting() const {
|
bool manager::is_waiting() const {
|
||||||
return m_state == state::WAITING;
|
return m_state == state::WAITING;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tray_manager::is_visible() const {
|
bool manager::is_visible() const {
|
||||||
return is_active() && !m_hidden;
|
return is_active() && !m_hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate systray management
|
* Activate systray management
|
||||||
*/
|
*/
|
||||||
void tray_manager::activate() {
|
void manager::activate() {
|
||||||
if (is_active()) {
|
if (is_active()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -173,7 +176,7 @@ void tray_manager::activate() {
|
|||||||
*
|
*
|
||||||
* @param other window id for current selection owner
|
* @param other window id for current selection owner
|
||||||
*/
|
*/
|
||||||
void tray_manager::wait_for_selection(xcb_window_t other) {
|
void manager::wait_for_selection(xcb_window_t other) {
|
||||||
if (is_waiting() || other == XCB_NONE) {
|
if (is_waiting() || other == XCB_NONE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -198,7 +201,7 @@ void tray_manager::wait_for_selection(xcb_window_t other) {
|
|||||||
/**
|
/**
|
||||||
* Deactivate systray management
|
* Deactivate systray management
|
||||||
*/
|
*/
|
||||||
void tray_manager::deactivate() {
|
void manager::deactivate() {
|
||||||
if (is_inactive()) {
|
if (is_inactive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -228,7 +231,7 @@ void tray_manager::deactivate() {
|
|||||||
/**
|
/**
|
||||||
* Reconfigure tray
|
* Reconfigure tray
|
||||||
*/
|
*/
|
||||||
void tray_manager::reconfigure() {
|
void manager::reconfigure() {
|
||||||
if (!m_opts.selection_owner) {
|
if (!m_opts.selection_owner) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -249,7 +252,7 @@ void tray_manager::reconfigure() {
|
|||||||
*
|
*
|
||||||
* TODO should we call update_width directly?
|
* TODO should we call update_width directly?
|
||||||
*/
|
*/
|
||||||
void tray_manager::reconfigure_window() {
|
void manager::reconfigure_window() {
|
||||||
m_log.trace("tray: Reconfigure window (hidden=%i, clients=%i)", m_hidden, m_clients.size());
|
m_log.trace("tray: Reconfigure window (hidden=%i, clients=%i)", m_hidden, m_clients.size());
|
||||||
update_width();
|
update_width();
|
||||||
}
|
}
|
||||||
@ -257,7 +260,7 @@ void tray_manager::reconfigure_window() {
|
|||||||
/**
|
/**
|
||||||
* TODO make sure this is always called when m_clients changes
|
* TODO make sure this is always called when m_clients changes
|
||||||
*/
|
*/
|
||||||
void tray_manager::update_width() {
|
void manager::update_width() {
|
||||||
unsigned new_width = calculate_w();
|
unsigned new_width = calculate_w();
|
||||||
if (m_tray_width != new_width) {
|
if (m_tray_width != new_width) {
|
||||||
m_tray_width = new_width;
|
m_tray_width = new_width;
|
||||||
@ -269,7 +272,7 @@ void tray_manager::update_width() {
|
|||||||
/**
|
/**
|
||||||
* Reconfigure clients
|
* Reconfigure clients
|
||||||
*/
|
*/
|
||||||
void tray_manager::reconfigure_clients() {
|
void manager::reconfigure_clients() {
|
||||||
m_log.trace("tray: Reconfigure clients");
|
m_log.trace("tray: Reconfigure clients");
|
||||||
|
|
||||||
int x = calculate_x() + m_opts.spacing;
|
int x = calculate_x() + m_opts.spacing;
|
||||||
@ -300,7 +303,7 @@ void tray_manager::reconfigure_clients() {
|
|||||||
/**
|
/**
|
||||||
* Redraw client windows.
|
* Redraw client windows.
|
||||||
*/
|
*/
|
||||||
void tray_manager::redraw_clients() {
|
void manager::redraw_clients() {
|
||||||
if (!is_visible()) {
|
if (!is_visible()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -323,7 +326,7 @@ void tray_manager::redraw_clients() {
|
|||||||
/**
|
/**
|
||||||
* Find the systray selection atom
|
* Find the systray selection atom
|
||||||
*/
|
*/
|
||||||
void tray_manager::query_atom() {
|
void manager::query_atom() {
|
||||||
m_log.trace("tray: Find systray selection atom for the default screen");
|
m_log.trace("tray: Find systray selection atom for the default screen");
|
||||||
string name{"_NET_SYSTEM_TRAY_S" + to_string(m_connection.default_screen())};
|
string name{"_NET_SYSTEM_TRAY_S" + to_string(m_connection.default_screen())};
|
||||||
auto reply = m_connection.intern_atom(false, name.length(), name.c_str());
|
auto reply = m_connection.intern_atom(false, name.length(), name.c_str());
|
||||||
@ -333,7 +336,7 @@ void tray_manager::query_atom() {
|
|||||||
/**
|
/**
|
||||||
* Set color atom used by clients when determing icon theme
|
* Set color atom used by clients when determing icon theme
|
||||||
*/
|
*/
|
||||||
void tray_manager::set_tray_colors() {
|
void manager::set_tray_colors() {
|
||||||
m_log.trace("tray: Set _NET_SYSTEM_TRAY_COLORS to 0x%08x", m_opts.foreground);
|
m_log.trace("tray: Set _NET_SYSTEM_TRAY_COLORS to 0x%08x", m_opts.foreground);
|
||||||
|
|
||||||
auto r = m_opts.foreground.red_i();
|
auto r = m_opts.foreground.red_i();
|
||||||
@ -344,21 +347,21 @@ void tray_manager::set_tray_colors() {
|
|||||||
const uint16_t g16 = (g << 8) | g;
|
const uint16_t g16 = (g << 8) | g;
|
||||||
const uint16_t b16 = (b << 8) | b;
|
const uint16_t b16 = (b << 8) | b;
|
||||||
|
|
||||||
const uint32_t colors[12] = {
|
const array<uint32_t, 12> colors = {
|
||||||
r16, g16, b16, // normal
|
r16, g16, b16, // normal
|
||||||
r16, g16, b16, // error
|
r16, g16, b16, // error
|
||||||
r16, g16, b16, // warning
|
r16, g16, b16, // warning
|
||||||
r16, g16, b16, // success
|
r16, g16, b16, // success
|
||||||
};
|
};
|
||||||
|
|
||||||
m_connection.change_property(
|
m_connection.change_property(XCB_PROP_MODE_REPLACE, m_opts.selection_owner, _NET_SYSTEM_TRAY_COLORS,
|
||||||
XCB_PROP_MODE_REPLACE, m_opts.selection_owner, _NET_SYSTEM_TRAY_COLORS, XCB_ATOM_CARDINAL, 32, 12, colors);
|
XCB_ATOM_CARDINAL, 32, colors.size(), colors.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the _NET_SYSTEM_TRAY_ORIENTATION atom
|
* Set the _NET_SYSTEM_TRAY_ORIENTATION atom
|
||||||
*/
|
*/
|
||||||
void tray_manager::set_tray_orientation() {
|
void manager::set_tray_orientation() {
|
||||||
const uint32_t orientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
|
const uint32_t orientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
|
||||||
m_log.trace("tray: Set _NET_SYSTEM_TRAY_ORIENTATION to 0x%x", orientation);
|
m_log.trace("tray: Set _NET_SYSTEM_TRAY_ORIENTATION to 0x%x", orientation);
|
||||||
m_connection.change_property_checked(XCB_PROP_MODE_REPLACE, m_opts.selection_owner, _NET_SYSTEM_TRAY_ORIENTATION,
|
m_connection.change_property_checked(XCB_PROP_MODE_REPLACE, m_opts.selection_owner, _NET_SYSTEM_TRAY_ORIENTATION,
|
||||||
@ -366,7 +369,7 @@ void tray_manager::set_tray_orientation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove
|
// TODO remove
|
||||||
void tray_manager::set_tray_visual() {
|
void manager::set_tray_visual() {
|
||||||
// TODO use bar visual
|
// TODO use bar visual
|
||||||
const uint32_t visualid = m_connection.visual_type(XCB_VISUAL_CLASS_TRUE_COLOR, 32)->visual_id;
|
const uint32_t visualid = m_connection.visual_type(XCB_VISUAL_CLASS_TRUE_COLOR, 32)->visual_id;
|
||||||
m_log.trace("tray: Set _NET_SYSTEM_TRAY_VISUAL to 0x%x", visualid);
|
m_log.trace("tray: Set _NET_SYSTEM_TRAY_VISUAL to 0x%x", visualid);
|
||||||
@ -380,7 +383,7 @@ void tray_manager::set_tray_visual() {
|
|||||||
* @param other_owner is set to the current owner if the function fails
|
* @param other_owner is set to the current owner if the function fails
|
||||||
* @returns Whether we acquired the selection
|
* @returns Whether we acquired the selection
|
||||||
*/
|
*/
|
||||||
bool tray_manager::acquire_selection(xcb_window_t& other_owner) {
|
bool manager::acquire_selection(xcb_window_t& other_owner) {
|
||||||
other_owner = XCB_NONE;
|
other_owner = XCB_NONE;
|
||||||
xcb_window_t owner = m_connection.get_selection_owner(m_atom).owner();
|
xcb_window_t owner = m_connection.get_selection_owner(m_atom).owner();
|
||||||
|
|
||||||
@ -404,7 +407,7 @@ bool tray_manager::acquire_selection(xcb_window_t& other_owner) {
|
|||||||
/**
|
/**
|
||||||
* Notify pending clients about the new systray MANAGER
|
* Notify pending clients about the new systray MANAGER
|
||||||
*/
|
*/
|
||||||
void tray_manager::notify_clients() {
|
void manager::notify_clients() {
|
||||||
if (is_active()) {
|
if (is_active()) {
|
||||||
m_log.info("tray: Notifying pending tray clients");
|
m_log.info("tray: Notifying pending tray clients");
|
||||||
auto message = m_connection.make_client_message(MANAGER, m_connection.root());
|
auto message = m_connection.make_client_message(MANAGER, m_connection.root());
|
||||||
@ -418,7 +421,7 @@ void tray_manager::notify_clients() {
|
|||||||
/**
|
/**
|
||||||
* Send delayed notification to pending clients
|
* Send delayed notification to pending clients
|
||||||
*/
|
*/
|
||||||
void tray_manager::notify_clients_delayed() {
|
void manager::notify_clients_delayed() {
|
||||||
if (m_delaythread.joinable()) {
|
if (m_delaythread.joinable()) {
|
||||||
m_delaythread.join();
|
m_delaythread.join();
|
||||||
}
|
}
|
||||||
@ -432,42 +435,42 @@ void tray_manager::notify_clients_delayed() {
|
|||||||
* Track changes to the given selection owner
|
* Track changes to the given selection owner
|
||||||
* If it gets destroyed or goes away we can reactivate the tray_manager
|
* If it gets destroyed or goes away we can reactivate the tray_manager
|
||||||
*/
|
*/
|
||||||
void tray_manager::track_selection_owner(xcb_window_t owner) {
|
void manager::track_selection_owner(xcb_window_t owner) {
|
||||||
if (owner != XCB_NONE) {
|
if (owner != XCB_NONE) {
|
||||||
const unsigned mask{XCB_CW_EVENT_MASK};
|
const uint32_t mask{XCB_CW_EVENT_MASK};
|
||||||
const unsigned values[]{XCB_EVENT_MASK_STRUCTURE_NOTIFY};
|
const uint32_t value{XCB_EVENT_MASK_STRUCTURE_NOTIFY};
|
||||||
m_connection.change_window_attributes(owner, mask, values);
|
m_connection.change_window_attributes(owner, mask, &value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process client docking request
|
* Process client docking request
|
||||||
*/
|
*/
|
||||||
void tray_manager::process_docking_request(xcb_window_t win) {
|
void manager::process_docking_request(xcb_window_t win) {
|
||||||
m_log.info("tray: Processing docking request from '%s' (%s)", ewmh_util::get_wm_name(win), m_connection.id(win));
|
m_log.info("tray: Processing docking request from '%s' (%s)", ewmh_util::get_wm_name(win), m_connection.id(win));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto client = make_unique<tray_client>(
|
auto cl = make_unique<client>(
|
||||||
m_log, m_connection, m_opts.selection_owner, win, m_opts.client_size, m_bar_opts.background.value());
|
m_log, m_connection, m_opts.selection_owner, win, m_opts.client_size, m_bar_opts.background.value());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
client->query_xembed();
|
cl->query_xembed();
|
||||||
} catch (const xpp::x::error::window& err) {
|
} catch (const xpp::x::error::window& err) {
|
||||||
m_log.err("Failed to query _XEMBED_INFO, removing %s ... (%s)", client->name(), err.what());
|
m_log.err("Failed to query _XEMBED_INFO, removing %s ... (%s)", cl->name(), err.what());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
client->update_client_attributes();
|
cl->update_client_attributes();
|
||||||
|
|
||||||
client->reparent();
|
cl->reparent();
|
||||||
|
|
||||||
client->add_to_save_set();
|
cl->add_to_save_set();
|
||||||
|
|
||||||
client->ensure_state();
|
cl->ensure_state();
|
||||||
|
|
||||||
client->notify_xembed();
|
cl->notify_xembed();
|
||||||
|
|
||||||
m_clients.emplace_back(std::move(client));
|
m_clients.emplace_back(std::move(cl));
|
||||||
} catch (const std::exception& err) {
|
} catch (const std::exception& err) {
|
||||||
m_log.err("tray: Failed to setup tray client removing... (%s)", err.what());
|
m_log.err("tray: Failed to setup tray client removing... (%s)", err.what());
|
||||||
return;
|
return;
|
||||||
@ -477,18 +480,18 @@ void tray_manager::process_docking_request(xcb_window_t win) {
|
|||||||
/**
|
/**
|
||||||
* Calculate x position of tray window
|
* Calculate x position of tray window
|
||||||
*/
|
*/
|
||||||
int tray_manager::calculate_x() const {
|
int manager::calculate_x() const {
|
||||||
return m_bar_opts.inner_area(false).x + m_pos.x;
|
return m_bar_opts.inner_area(false).x + m_pos.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tray_manager::calculate_y() const {
|
int manager::calculate_y() const {
|
||||||
return m_bar_opts.inner_area(false).y + m_pos.y;
|
return m_bar_opts.inner_area(false).y + m_pos.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned tray_manager::calculate_w() const {
|
unsigned manager::calculate_w() const {
|
||||||
unsigned width = m_opts.spacing;
|
unsigned width = m_opts.spacing;
|
||||||
unsigned count{0};
|
unsigned count{0};
|
||||||
for (auto& client : m_clients) {
|
for (const auto& client : m_clients) {
|
||||||
if (client->mapped()) {
|
if (client->mapped()) {
|
||||||
count++;
|
count++;
|
||||||
width += m_opts.spacing + m_opts.client_size.w;
|
width += m_opts.spacing + m_opts.client_size.w;
|
||||||
@ -500,7 +503,7 @@ unsigned tray_manager::calculate_w() const {
|
|||||||
/**
|
/**
|
||||||
* Calculate y position of client window
|
* Calculate y position of client window
|
||||||
*/
|
*/
|
||||||
int tray_manager::calculate_client_y() {
|
int manager::calculate_client_y() {
|
||||||
return (m_bar_opts.inner_area(true).height - m_opts.client_size.h) / 2;
|
return (m_bar_opts.inner_area(true).height - m_opts.client_size.h) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,14 +512,14 @@ int tray_manager::calculate_client_y() {
|
|||||||
*
|
*
|
||||||
* The given window ID can be the ID of the wrapper or the embedded window
|
* The given window ID can be the ID of the wrapper or the embedded window
|
||||||
*/
|
*/
|
||||||
bool tray_manager::is_embedded(const xcb_window_t& win) {
|
bool manager::is_embedded(const xcb_window_t& win) {
|
||||||
return find_client(win) != nullptr;
|
return find_client(win) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find tray client object from the wrapper or embedded window
|
* Find tray client object from the wrapper or embedded window
|
||||||
*/
|
*/
|
||||||
tray_client* tray_manager::find_client(const xcb_window_t& win) {
|
client* manager::find_client(const xcb_window_t& win) {
|
||||||
auto client = std::find_if(m_clients.begin(), m_clients.end(),
|
auto client = std::find_if(m_clients.begin(), m_clients.end(),
|
||||||
[win](const auto& client) { return client->match(win) || client->embedder() == win; });
|
[win](const auto& client) { return client->match(win) || client->embedder() == win; });
|
||||||
|
|
||||||
@ -530,20 +533,20 @@ tray_client* tray_manager::find_client(const xcb_window_t& win) {
|
|||||||
/**
|
/**
|
||||||
* Remove tray client
|
* Remove tray client
|
||||||
*/
|
*/
|
||||||
void tray_manager::remove_client(const tray_client& client) {
|
void manager::remove_client(const client& c) {
|
||||||
remove_client(client.client());
|
remove_client(c.client_window());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove tray client by window
|
* Remove tray client by window
|
||||||
*/
|
*/
|
||||||
void tray_manager::remove_client(xcb_window_t win) {
|
void manager::remove_client(xcb_window_t win) {
|
||||||
auto old_size = m_clients.size();
|
auto old_size = m_clients.size();
|
||||||
m_clients.erase(
|
m_clients.erase(
|
||||||
std::remove_if(m_clients.begin(), m_clients.end(), [win](const auto& client) { return client->match(win); }));
|
std::remove_if(m_clients.begin(), m_clients.end(), [win](const auto& client) { return client->match(win); }));
|
||||||
|
|
||||||
if (old_size != m_clients.size()) {
|
if (old_size != m_clients.size()) {
|
||||||
tray_manager::reconfigure();
|
manager::reconfigure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -554,12 +557,12 @@ void tray_manager::remove_client(xcb_window_t win) {
|
|||||||
* 1. When removing a client during iteration, the unique_ptr is reset.
|
* 1. When removing a client during iteration, the unique_ptr is reset.
|
||||||
* 2. Afterwards all null pointers are removed from the list.
|
* 2. Afterwards all null pointers are removed from the list.
|
||||||
*/
|
*/
|
||||||
void tray_manager::clean_clients() {
|
void manager::clean_clients() {
|
||||||
m_clients.erase(
|
m_clients.erase(
|
||||||
std::remove_if(m_clients.begin(), m_clients.end(), [](const auto& client) { return client.get() == nullptr; }));
|
std::remove_if(m_clients.begin(), m_clients.end(), [](const auto& client) { return client.get() == nullptr; }));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tray_manager::change_visibility(bool visible) {
|
bool manager::change_visibility(bool visible) {
|
||||||
if (!is_active() || m_hidden == !visible) {
|
if (!is_active() || m_hidden == !visible) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -585,7 +588,7 @@ bool tray_manager::change_visibility(bool visible) {
|
|||||||
/**
|
/**
|
||||||
* Event callback : XCB_EXPOSE
|
* Event callback : XCB_EXPOSE
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::expose& evt) {
|
void manager::handle(const evt::expose& evt) {
|
||||||
if (is_active() && !m_clients.empty() && evt->count == 0) {
|
if (is_active() && !m_clients.empty() && evt->count == 0) {
|
||||||
redraw_clients();
|
redraw_clients();
|
||||||
}
|
}
|
||||||
@ -594,7 +597,7 @@ void tray_manager::handle(const evt::expose& evt) {
|
|||||||
/**
|
/**
|
||||||
* Event callback : XCB_CLIENT_MESSAGE
|
* Event callback : XCB_CLIENT_MESSAGE
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::client_message& evt) {
|
void manager::handle(const evt::client_message& evt) {
|
||||||
if (!is_active()) {
|
if (!is_active()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -625,7 +628,7 @@ void tray_manager::handle(const evt::client_message& evt) {
|
|||||||
* wants to reconfigure its window. This is of course nothing we appreciate
|
* wants to reconfigure its window. This is of course nothing we appreciate
|
||||||
* so we return an answer that'll put him in place.
|
* so we return an answer that'll put him in place.
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::configure_request& evt) {
|
void manager::handle(const evt::configure_request& evt) {
|
||||||
if (is_active() && is_embedded(evt->window)) {
|
if (is_active() && is_embedded(evt->window)) {
|
||||||
auto client = find_client(evt->window);
|
auto client = find_client(evt->window);
|
||||||
try {
|
try {
|
||||||
@ -639,9 +642,9 @@ void tray_manager::handle(const evt::configure_request& evt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see tray_manager::handle(const evt::configure_request&);
|
* @see manager::handle(const evt::configure_request&);
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::resize_request& evt) {
|
void manager::handle(const evt::resize_request& evt) {
|
||||||
if (is_active() && is_embedded(evt->window)) {
|
if (is_active() && is_embedded(evt->window)) {
|
||||||
auto client = find_client(evt->window);
|
auto client = find_client(evt->window);
|
||||||
try {
|
try {
|
||||||
@ -657,7 +660,7 @@ void tray_manager::handle(const evt::resize_request& evt) {
|
|||||||
/**
|
/**
|
||||||
* Event callback : XCB_SELECTION_CLEAR
|
* Event callback : XCB_SELECTION_CLEAR
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::selection_clear& evt) {
|
void manager::handle(const evt::selection_clear& evt) {
|
||||||
if (is_inactive()) {
|
if (is_inactive()) {
|
||||||
return;
|
return;
|
||||||
} else if (evt->selection != m_atom) {
|
} else if (evt->selection != m_atom) {
|
||||||
@ -673,7 +676,7 @@ void tray_manager::handle(const evt::selection_clear& evt) {
|
|||||||
/**
|
/**
|
||||||
* Event callback : XCB_PROPERTY_NOTIFY
|
* Event callback : XCB_PROPERTY_NOTIFY
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::property_notify& evt) {
|
void manager::handle(const evt::property_notify& evt) {
|
||||||
if (!is_active()) {
|
if (!is_active()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -708,7 +711,7 @@ void tray_manager::handle(const evt::property_notify& evt) {
|
|||||||
/**
|
/**
|
||||||
* Event callback : XCB_REPARENT_NOTIFY
|
* Event callback : XCB_REPARENT_NOTIFY
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::reparent_notify& evt) {
|
void manager::handle(const evt::reparent_notify& evt) {
|
||||||
if (!is_active()) {
|
if (!is_active()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -729,7 +732,7 @@ void tray_manager::handle(const evt::reparent_notify& evt) {
|
|||||||
/**
|
/**
|
||||||
* Event callback : XCB_DESTROY_NOTIFY
|
* Event callback : XCB_DESTROY_NOTIFY
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::destroy_notify& evt) {
|
void manager::handle(const evt::destroy_notify& evt) {
|
||||||
if (is_waiting() && evt->window == m_othermanager) {
|
if (is_waiting() && evt->window == m_othermanager) {
|
||||||
m_log.info("Systray selection unmanaged... re-activating");
|
m_log.info("Systray selection unmanaged... re-activating");
|
||||||
activate();
|
activate();
|
||||||
@ -743,7 +746,7 @@ void tray_manager::handle(const evt::destroy_notify& evt) {
|
|||||||
/**
|
/**
|
||||||
* Event callback : XCB_MAP_NOTIFY
|
* Event callback : XCB_MAP_NOTIFY
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::map_notify& evt) {
|
void manager::handle(const evt::map_notify& evt) {
|
||||||
if (is_active() && evt->window == m_opts.selection_owner) {
|
if (is_active() && evt->window == m_opts.selection_owner) {
|
||||||
m_log.trace("tray: Received map_notify for selection owner");
|
m_log.trace("tray: Received map_notify for selection owner");
|
||||||
redraw_clients();
|
redraw_clients();
|
||||||
@ -767,7 +770,7 @@ void tray_manager::handle(const evt::map_notify& evt) {
|
|||||||
/**
|
/**
|
||||||
* Event callback : XCB_UNMAP_NOTIFY
|
* Event callback : XCB_UNMAP_NOTIFY
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::unmap_notify& evt) {
|
void manager::handle(const evt::unmap_notify& evt) {
|
||||||
if (is_active() && is_embedded(evt->window)) {
|
if (is_active() && is_embedded(evt->window)) {
|
||||||
auto client = find_client(evt->window);
|
auto client = find_client(evt->window);
|
||||||
|
|
||||||
@ -785,13 +788,13 @@ void tray_manager::handle(const evt::unmap_notify& evt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tray_manager::on(const signals::ui::update_background&) {
|
bool manager::on(const signals::ui::update_background&) {
|
||||||
redraw_clients();
|
redraw_clients();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tray_manager::on(const signals::ui_tray::tray_pos_change& evt) {
|
bool manager::on(const signals::ui_tray::tray_pos_change& evt) {
|
||||||
int new_x = std::max(0, std::min(evt.cast(), (int)(m_bar_opts.size.w - m_tray_width)));
|
int new_x = std::max(0, std::min(evt.cast(), (int)(m_bar_opts.size.w - m_tray_width)));
|
||||||
|
|
||||||
if (new_x != m_pos.x) {
|
if (new_x != m_pos.x) {
|
||||||
@ -802,8 +805,10 @@ bool tray_manager::on(const signals::ui_tray::tray_pos_change& evt) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tray_manager::on(const signals::ui_tray::tray_visibility& evt) {
|
bool manager::on(const signals::ui_tray::tray_visibility& evt) {
|
||||||
return change_visibility(evt.cast());
|
return change_visibility(evt.cast());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace tray
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -11,118 +11,118 @@ POLYBAR_NS
|
|||||||
|
|
||||||
namespace xembed {
|
namespace xembed {
|
||||||
|
|
||||||
void info::set(uint32_t* data) {
|
void info::set(const uint32_t* data) {
|
||||||
version = data[0];
|
version = data[0];
|
||||||
flags = data[1];
|
flags = data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t info::get_version() const {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t info::get_flags() const {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool info::is_mapped() const {
|
||||||
|
return (flags & XEMBED_MAPPED) == XEMBED_MAPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
string info::to_string() const {
|
||||||
|
return sstream() << "xembed(version=0x" << std::hex << get_version() << ", flags=0x" << get_flags()
|
||||||
|
<< ", XEMBED_MAPPED=" << std::dec << is_mapped() << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query _XEMBED_INFO for the given window
|
||||||
|
*
|
||||||
|
* @return Whether valid XEMBED info was found
|
||||||
|
*/
|
||||||
|
bool query(connection& conn, xcb_window_t win, info& data) {
|
||||||
|
auto info = conn.get_property(false, win, _XEMBED_INFO, _XEMBED_INFO, 0L, 2);
|
||||||
|
|
||||||
|
if (info->value_len == 0) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t info::get_version() const {
|
std::vector<uint32_t> xembed_data{info.value<uint32_t>().begin(), info.value<uint32_t>().end()};
|
||||||
return version;
|
data.set(xembed_data.data());
|
||||||
}
|
|
||||||
|
return true;
|
||||||
uint32_t info::get_flags() const {
|
}
|
||||||
return flags;
|
|
||||||
}
|
/**
|
||||||
|
* Send _XEMBED messages
|
||||||
bool info::is_mapped() const {
|
*/
|
||||||
return (flags & XEMBED_MAPPED) == XEMBED_MAPPED;
|
void send_message(connection& conn, xcb_window_t target, uint32_t message, uint32_t d1, uint32_t d2, uint32_t d3) {
|
||||||
}
|
auto msg = conn.make_client_message(_XEMBED, target);
|
||||||
|
msg.data.data32[0] = XCB_CURRENT_TIME;
|
||||||
string info::to_string() const {
|
msg.data.data32[1] = message;
|
||||||
return sstream() << "xembed(version=0x" << std::hex << get_version() << ", flags=0x" << get_flags()
|
msg.data.data32[2] = d1;
|
||||||
<< ", XEMBED_MAPPED=" << std::dec << is_mapped() << ")";
|
msg.data.data32[3] = d2;
|
||||||
}
|
msg.data.data32[4] = d3;
|
||||||
|
conn.send_client_message(msg, target);
|
||||||
/**
|
}
|
||||||
* Query _XEMBED_INFO for the given window
|
|
||||||
*
|
/**
|
||||||
* @return Whether valid XEMBED info was found
|
* Send window focus event
|
||||||
*/
|
*/
|
||||||
bool query(connection& conn, xcb_window_t win, info& data) {
|
void send_focus_event(connection& conn, xcb_window_t target) {
|
||||||
auto info = conn.get_property(false, win, _XEMBED_INFO, _XEMBED_INFO, 0L, 2);
|
auto msg = conn.make_client_message(WM_PROTOCOLS, target);
|
||||||
|
msg.data.data32[0] = WM_TAKE_FOCUS;
|
||||||
if (info->value_len == 0) {
|
msg.data.data32[1] = XCB_CURRENT_TIME;
|
||||||
return false;
|
conn.send_client_message(msg, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint32_t> xembed_data{info.value<uint32_t>().begin(), info.value<uint32_t>().end()};
|
/**
|
||||||
data.set(xembed_data.data());
|
* Acknowledge window embedding
|
||||||
|
*/
|
||||||
return true;
|
void notify_embedded(connection& conn, xcb_window_t win, xcb_window_t embedder, uint32_t version) {
|
||||||
}
|
send_message(conn, win, XEMBED_EMBEDDED_NOTIFY, 0, embedder, std::min(version, XEMBED_MAX_VERSION));
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Send _XEMBED messages
|
/**
|
||||||
*/
|
* Send window activate notification
|
||||||
void send_message(connection& conn, xcb_window_t target, uint32_t message, uint32_t d1, uint32_t d2, uint32_t d3) {
|
*/
|
||||||
auto msg = conn.make_client_message(_XEMBED, target);
|
void notify_activated(connection& conn, xcb_window_t win) {
|
||||||
msg.data.data32[0] = XCB_CURRENT_TIME;
|
send_message(conn, win, XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
|
||||||
msg.data.data32[1] = message;
|
}
|
||||||
msg.data.data32[2] = d1;
|
|
||||||
msg.data.data32[3] = d2;
|
/**
|
||||||
msg.data.data32[4] = d3;
|
* Send window deactivate notification
|
||||||
conn.send_client_message(msg, target);
|
*/
|
||||||
}
|
void notify_deactivated(connection& conn, xcb_window_t win) {
|
||||||
|
send_message(conn, win, XEMBED_WINDOW_DEACTIVATE, 0, 0, 0);
|
||||||
/**
|
}
|
||||||
* Send window focus event
|
|
||||||
*/
|
/**
|
||||||
void send_focus_event(connection& conn, xcb_window_t target) {
|
* Send window focused notification
|
||||||
auto msg = conn.make_client_message(WM_PROTOCOLS, target);
|
*/
|
||||||
msg.data.data32[0] = WM_TAKE_FOCUS;
|
void notify_focused(connection& conn, xcb_window_t win, uint32_t focus_type) {
|
||||||
msg.data.data32[1] = XCB_CURRENT_TIME;
|
send_message(conn, win, XEMBED_FOCUS_IN, focus_type, 0, 0);
|
||||||
conn.send_client_message(msg, target);
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
/**
|
* Send window unfocused notification
|
||||||
* Acknowledge window embedding
|
*/
|
||||||
*/
|
void notify_unfocused(connection& conn, xcb_window_t win) {
|
||||||
void notify_embedded(connection& conn, xcb_window_t win, xcb_window_t embedder, uint32_t version) {
|
send_message(conn, win, XEMBED_FOCUS_OUT, 0, 0, 0);
|
||||||
send_message(conn, win, XEMBED_EMBEDDED_NOTIFY, 0, embedder, std::min(version, XEMBED_MAX_VERSION));
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
/**
|
* Unembed given window
|
||||||
* Send window activate notification
|
*/
|
||||||
*/
|
void unembed(connection& conn, xcb_window_t win, xcb_window_t root) {
|
||||||
void notify_activated(connection& conn, xcb_window_t win) {
|
assert(win != XCB_NONE);
|
||||||
send_message(conn, win, XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
|
try {
|
||||||
}
|
conn.unmap_window_checked(win);
|
||||||
|
conn.reparent_window_checked(win, root, 0, 0);
|
||||||
/**
|
} catch (const xpp::x::error::window& err) {
|
||||||
* Send window deactivate notification
|
// invalid window
|
||||||
*/
|
// TODO
|
||||||
void notify_deactivated(connection& conn, xcb_window_t win) {
|
logger::make().err("tray: Failed to unembed window '%s' (%s)", ewmh_util::get_wm_name(win), conn.id(win));
|
||||||
send_message(conn, win, XEMBED_WINDOW_DEACTIVATE, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send window focused notification
|
|
||||||
*/
|
|
||||||
void notify_focused(connection& conn, xcb_window_t win, uint32_t focus_type) {
|
|
||||||
send_message(conn, win, XEMBED_FOCUS_IN, focus_type, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send window unfocused notification
|
|
||||||
*/
|
|
||||||
void notify_unfocused(connection& conn, xcb_window_t win) {
|
|
||||||
send_message(conn, win, XEMBED_FOCUS_OUT, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unembed given window
|
|
||||||
*/
|
|
||||||
void unembed(connection& conn, xcb_window_t win, xcb_window_t root) {
|
|
||||||
assert(win != XCB_NONE);
|
|
||||||
try {
|
|
||||||
conn.unmap_window_checked(win);
|
|
||||||
conn.reparent_window_checked(win, root, 0, 0);
|
|
||||||
} catch (const xpp::x::error::window& err) {
|
|
||||||
// invalid window
|
|
||||||
// TODO
|
|
||||||
logger::make().err("tray: Failed to unembed window '%s' (%s)", ewmh_util::get_wm_name(win), conn.id(win));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} // namespace xembed
|
} // namespace xembed
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
Loading…
Reference in New Issue
Block a user