fix(tray): Improve pseudo-transparency handling
- Make sure previously drawn content is cleared - Redraw tray clients on XCB_EXPOSE - Prevent void parts of the root pixmap being copied Ref #187
This commit is contained in:
parent
4c50853044
commit
7f5117b7cc
@ -57,6 +57,12 @@ class renderer {
|
|||||||
void debug_hints();
|
void debug_hints();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct reserve_area {
|
||||||
|
edge side{edge::NONE};
|
||||||
|
uint16_t size{0U};
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
connection& m_connection;
|
connection& m_connection;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
@ -66,6 +72,9 @@ class renderer {
|
|||||||
|
|
||||||
xcb_rectangle_t m_rect{0, 0, 0U, 0U};
|
xcb_rectangle_t m_rect{0, 0, 0U, 0U};
|
||||||
|
|
||||||
|
xcb_rectangle_t m_cleared{0, 0, 0U, 0U};
|
||||||
|
reserve_area m_cleararea{};
|
||||||
|
|
||||||
xcb_window_t m_window;
|
xcb_window_t m_window;
|
||||||
xcb_colormap_t m_colormap;
|
xcb_colormap_t m_colormap;
|
||||||
xcb_visualtype_t* m_visual;
|
xcb_visualtype_t* m_visual;
|
||||||
|
24
include/x11/generic.hpp
Normal file
24
include/x11/generic.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
inline bool operator==(const xcb_rectangle_t& a, const xcb_rectangle_t& b) {
|
||||||
|
return a.width == b.width && a.height == b.height && a.x == b.x && a.y == b.y;
|
||||||
|
}
|
||||||
|
inline bool operator!=(const xcb_rectangle_t& a, const xcb_rectangle_t& b) {
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
inline bool operator==(const xcb_rectangle_t& a, int b) {
|
||||||
|
return a.width == b && a.height == b && a.x == b && a.y == b;
|
||||||
|
}
|
||||||
|
inline bool operator!=(const xcb_rectangle_t& a, int b) {
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
@ -68,6 +68,10 @@ class tray_client {
|
|||||||
|
|
||||||
~tray_client();
|
~tray_client();
|
||||||
|
|
||||||
|
uint16_t width() const;
|
||||||
|
uint16_t height() const;
|
||||||
|
void clear_window() const;
|
||||||
|
|
||||||
bool match(const xcb_window_t& win) const;
|
bool match(const xcb_window_t& win) const;
|
||||||
bool mapped() const;
|
bool mapped() const;
|
||||||
void mapped(bool state);
|
void mapped(bool state);
|
||||||
@ -114,7 +118,7 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
|||||||
void reconfigure_clients();
|
void reconfigure_clients();
|
||||||
void reconfigure_bg(bool realloc = false);
|
void reconfigure_bg(bool realloc = false);
|
||||||
void refresh_window();
|
void refresh_window();
|
||||||
void redraw_window();
|
void redraw_window(bool realloc_bg = false);
|
||||||
|
|
||||||
void query_atom();
|
void query_atom();
|
||||||
void create_window();
|
void create_window();
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
#include "components/renderer.hpp"
|
#include "components/renderer.hpp"
|
||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
|
#include "components/types.hpp"
|
||||||
#include "errors.hpp"
|
#include "errors.hpp"
|
||||||
#include "x11/connection.hpp"
|
#include "x11/connection.hpp"
|
||||||
#include "x11/draw.hpp"
|
#include "x11/draw.hpp"
|
||||||
#include "x11/fonts.hpp"
|
#include "x11/fonts.hpp"
|
||||||
|
#include "x11/generic.hpp"
|
||||||
#include "x11/winspec.hpp"
|
#include "x11/winspec.hpp"
|
||||||
#include "x11/xlib.hpp"
|
#include "x11/xlib.hpp"
|
||||||
#include "x11/xutils.hpp"
|
#include "x11/xutils.hpp"
|
||||||
@ -206,7 +208,39 @@ void renderer::flush(bool clear) {
|
|||||||
right.width += m_bar.borders.at(edge::RIGHT).size;
|
right.width += m_bar.borders.at(edge::RIGHT).size;
|
||||||
right.height += m_bar.size.h;
|
right.height += m_bar.size.h;
|
||||||
|
|
||||||
m_log.trace("renderer: copy pixmap (clear=%i)", clear);
|
// Calculate the area that was reserved so that we
|
||||||
|
// can clear any previous content drawn at the same location
|
||||||
|
xcb_rectangle_t clear_area{0, 0, 0U, 0U};
|
||||||
|
|
||||||
|
if (m_cleararea.size && m_cleararea.side == edge::RIGHT) {
|
||||||
|
clear_area.x = m_bar.size.w - m_cleararea.size;
|
||||||
|
clear_area.y = 0;
|
||||||
|
clear_area.width = m_cleararea.size;
|
||||||
|
clear_area.height = m_bar.size.h;
|
||||||
|
} else if (m_cleararea.size && m_cleararea.side == edge::LEFT) {
|
||||||
|
clear_area.x = m_rect.x;
|
||||||
|
clear_area.y = m_rect.y;
|
||||||
|
clear_area.width = m_cleararea.size;
|
||||||
|
clear_area.height = m_rect.height;
|
||||||
|
} else if (m_cleararea.size && m_cleararea.side == edge::TOP) {
|
||||||
|
clear_area.x = m_rect.x;
|
||||||
|
clear_area.y = m_rect.y;
|
||||||
|
clear_area.width = m_rect.width;
|
||||||
|
clear_area.height = m_cleararea.size;
|
||||||
|
} else if (m_cleararea.size && m_cleararea.side == edge::TOP) {
|
||||||
|
clear_area.x = m_rect.x;
|
||||||
|
clear_area.y = m_rect.y + m_rect.height - m_cleararea.size;
|
||||||
|
clear_area.width = m_rect.width;
|
||||||
|
clear_area.height = m_cleararea.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clear_area != m_cleared && clear_area != 0) {
|
||||||
|
m_log.trace("renderer: clearing area %dx%d+%d+%d", clear_area.width, clear_area.height, clear_area.x, clear_area.y);
|
||||||
|
m_connection.clear_area(0, m_window, clear_area.x, clear_area.y, clear_area.width, clear_area.height);
|
||||||
|
m_cleared = clear_area;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_log.trace("renderer: copy pixmap (clear=%i, geom=%dx%d+%d+%d)", clear, r.width, r.height, r.x, r.y);
|
||||||
m_connection.copy_area(m_pixmap, m_window, m_gcontexts.at(gc::FG), 0, 0, r.x, r.y, r.width, r.height);
|
m_connection.copy_area(m_pixmap, m_window, m_gcontexts.at(gc::FG), 0, 0, r.x, r.y, r.width, r.height);
|
||||||
|
|
||||||
m_log.trace_x("renderer: draw top border (%lupx, %08x)", top.height, m_bar.borders.at(edge::TOP).color);
|
m_log.trace_x("renderer: draw top border (%lupx, %08x)", top.height, m_bar.borders.at(edge::TOP).color);
|
||||||
@ -234,6 +268,9 @@ void renderer::flush(bool clear) {
|
|||||||
void renderer::reserve_space(edge side, uint16_t w) {
|
void renderer::reserve_space(edge side, uint16_t w) {
|
||||||
m_log.trace_x("renderer: reserve_space(%i, %i)", static_cast<uint8_t>(side), w);
|
m_log.trace_x("renderer: reserve_space(%i, %i)", static_cast<uint8_t>(side), w);
|
||||||
|
|
||||||
|
m_cleararea.side = side;
|
||||||
|
m_cleararea.size = w;
|
||||||
|
|
||||||
switch (side) {
|
switch (side) {
|
||||||
case edge::NONE:
|
case edge::NONE:
|
||||||
break;
|
break;
|
||||||
|
@ -52,6 +52,22 @@ tray_client::~tray_client() {
|
|||||||
xembed::unembed(m_connection, window(), m_connection.root());
|
xembed::unembed(m_connection, window(), m_connection.root());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t tray_client::width() const {
|
||||||
|
return m_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t tray_client::height() const {
|
||||||
|
return m_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tray_client::clear_window() const {
|
||||||
|
try {
|
||||||
|
m_connection.clear_area_checked(1, window(), 0, 0, width(), height());
|
||||||
|
} catch (const xpp::x::error::window& err) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Match given window against client window
|
* Match given window against client window
|
||||||
*/
|
*/
|
||||||
@ -399,8 +415,19 @@ void tray_manager::reconfigure_bg(bool realloc) {
|
|||||||
return m_log.err("Failed to get root pixmap for tray background (realloc=%i)", realloc);
|
return m_log.err("Failed to get root pixmap for tray background (realloc=%i)", realloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.trace("tray: rootpixmap=%x (%dx%d+%d+%d), tray=%x, pixmap=%x, gc=%x", m_rootpixmap.pixmap, m_rootpixmap.width,
|
if (realloc) {
|
||||||
m_rootpixmap.height, m_rootpixmap.x, m_rootpixmap.y, m_tray, m_pixmap, m_gc);
|
// clang-format off
|
||||||
|
m_log.info("Tray root pixmap (rootpmap=%s, geom=%dx%d+%d+%d, tray=%s, pmap=%s, gc=%s)",
|
||||||
|
m_connection.id(m_rootpixmap.pixmap),
|
||||||
|
m_rootpixmap.width,
|
||||||
|
m_rootpixmap.height,
|
||||||
|
m_rootpixmap.x,
|
||||||
|
m_rootpixmap.y,
|
||||||
|
m_connection.id(m_tray),
|
||||||
|
m_connection.id(m_pixmap),
|
||||||
|
m_connection.id(m_gc));
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
m_prevwidth = w;
|
m_prevwidth = w;
|
||||||
m_prevheight = h;
|
m_prevheight = h;
|
||||||
@ -411,6 +438,14 @@ void tray_manager::reconfigure_bg(bool realloc) {
|
|||||||
auto px = m_rootpixmap.x + x;
|
auto px = m_rootpixmap.x + x;
|
||||||
auto py = m_rootpixmap.y + y;
|
auto py = m_rootpixmap.y + y;
|
||||||
|
|
||||||
|
// Make sure we don't try to copy void content
|
||||||
|
if (px + w > m_rootpixmap.width) {
|
||||||
|
w -= px + w - m_rootpixmap.width;
|
||||||
|
}
|
||||||
|
if (py + h > m_rootpixmap.height) {
|
||||||
|
h -= py + h - m_rootpixmap.height;
|
||||||
|
}
|
||||||
|
|
||||||
if (realloc) {
|
if (realloc) {
|
||||||
vector<uint8_t> image_data;
|
vector<uint8_t> image_data;
|
||||||
uint8_t image_depth;
|
uint8_t image_depth;
|
||||||
@ -461,10 +496,10 @@ void tray_manager::refresh_window() {
|
|||||||
draw_util::fill(m_connection, m_pixmap, m_gc, 0, 0, width, height);
|
draw_util::fill(m_connection, m_pixmap, m_gc, 0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_connection.clear_area(1, m_tray, 0, 0, width, height);
|
m_connection.clear_area(0, m_tray, 0, 0, width, height);
|
||||||
|
|
||||||
for (auto&& client : m_clients) {
|
for (auto&& client : m_clients) {
|
||||||
m_connection.clear_area(1, client->window(), 0, 0, m_opts.width, height);
|
client->clear_window();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_connection.flush();
|
m_connection.flush();
|
||||||
@ -473,9 +508,9 @@ void tray_manager::refresh_window() {
|
|||||||
/**
|
/**
|
||||||
* Redraw window
|
* Redraw window
|
||||||
*/
|
*/
|
||||||
void tray_manager::redraw_window() {
|
void tray_manager::redraw_window(bool realloc_bg) {
|
||||||
m_log.info("Redraw tray container (id=%s)", m_connection.id(m_tray));
|
m_log.info("Redraw tray container (id=%s)", m_connection.id(m_tray));
|
||||||
reconfigure_bg(true);
|
reconfigure_bg(realloc_bg);
|
||||||
refresh_window();
|
refresh_window();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,7 +536,9 @@ void tray_manager::create_window() {
|
|||||||
<< cw_pos(calculate_x(calculate_w()), calculate_y())
|
<< cw_pos(calculate_x(calculate_w()), calculate_y())
|
||||||
<< cw_class(XCB_WINDOW_CLASS_INPUT_OUTPUT)
|
<< cw_class(XCB_WINDOW_CLASS_INPUT_OUTPUT)
|
||||||
<< cw_params_backing_store(XCB_BACKING_STORE_WHEN_MAPPED)
|
<< cw_params_backing_store(XCB_BACKING_STORE_WHEN_MAPPED)
|
||||||
<< cw_params_event_mask(XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_STRUCTURE_NOTIFY)
|
<< cw_params_event_mask(XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
|
||||||
|
|XCB_EVENT_MASK_STRUCTURE_NOTIFY
|
||||||
|
|XCB_EVENT_MASK_EXPOSURE)
|
||||||
<< cw_params_override_redirect(true);
|
<< cw_params_override_redirect(true);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@ -880,7 +917,6 @@ int tray_manager::mapped_clients() const {
|
|||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::expose& evt) {
|
void tray_manager::handle(const evt::expose& evt) {
|
||||||
if (m_activated && !m_clients.empty() && evt->count == 0) {
|
if (m_activated && !m_clients.empty() && evt->count == 0) {
|
||||||
reconfigure_window();
|
|
||||||
redraw_window();
|
redraw_window();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1001,11 +1037,11 @@ void tray_manager::handle(const evt::property_notify& evt) {
|
|||||||
if (!m_activated) {
|
if (!m_activated) {
|
||||||
return;
|
return;
|
||||||
} else if (evt->atom == _XROOTMAP_ID) {
|
} else if (evt->atom == _XROOTMAP_ID) {
|
||||||
redraw_window();
|
redraw_window(true);
|
||||||
} else if (evt->atom == _XSETROOT_ID) {
|
} else if (evt->atom == _XSETROOT_ID) {
|
||||||
redraw_window();
|
redraw_window(true);
|
||||||
} else if (evt->atom == ESETROOT_PMAP_ID) {
|
} else if (evt->atom == ESETROOT_PMAP_ID) {
|
||||||
redraw_window();
|
redraw_window(true);
|
||||||
} else if (evt->atom == _XEMBED_INFO) {
|
} else if (evt->atom == _XEMBED_INFO) {
|
||||||
auto client = find_client(evt->window);
|
auto client = find_client(evt->window);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user