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();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
struct reserve_area {
|
||||
edge side{edge::NONE};
|
||||
uint16_t size{0U};
|
||||
};
|
||||
|
||||
private:
|
||||
connection& m_connection;
|
||||
const logger& m_log;
|
||||
@ -66,6 +72,9 @@ class renderer {
|
||||
|
||||
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_colormap_t m_colormap;
|
||||
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();
|
||||
|
||||
uint16_t width() const;
|
||||
uint16_t height() const;
|
||||
void clear_window() const;
|
||||
|
||||
bool match(const xcb_window_t& win) const;
|
||||
bool mapped() const;
|
||||
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_bg(bool realloc = false);
|
||||
void refresh_window();
|
||||
void redraw_window();
|
||||
void redraw_window(bool realloc_bg = false);
|
||||
|
||||
void query_atom();
|
||||
void create_window();
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include "components/renderer.hpp"
|
||||
#include "components/logger.hpp"
|
||||
#include "components/types.hpp"
|
||||
#include "errors.hpp"
|
||||
#include "x11/connection.hpp"
|
||||
#include "x11/draw.hpp"
|
||||
#include "x11/fonts.hpp"
|
||||
#include "x11/generic.hpp"
|
||||
#include "x11/winspec.hpp"
|
||||
#include "x11/xlib.hpp"
|
||||
#include "x11/xutils.hpp"
|
||||
@ -206,7 +208,39 @@ void renderer::flush(bool clear) {
|
||||
right.width += m_bar.borders.at(edge::RIGHT).size;
|
||||
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_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) {
|
||||
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) {
|
||||
case edge::NONE:
|
||||
break;
|
||||
|
@ -52,6 +52,22 @@ tray_client::~tray_client() {
|
||||
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
|
||||
*/
|
||||
@ -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);
|
||||
}
|
||||
|
||||
m_log.trace("tray: rootpixmap=%x (%dx%d+%d+%d), tray=%x, pixmap=%x, gc=%x", m_rootpixmap.pixmap, m_rootpixmap.width,
|
||||
m_rootpixmap.height, m_rootpixmap.x, m_rootpixmap.y, m_tray, m_pixmap, m_gc);
|
||||
if (realloc) {
|
||||
// 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_prevheight = h;
|
||||
@ -411,6 +438,14 @@ void tray_manager::reconfigure_bg(bool realloc) {
|
||||
auto px = m_rootpixmap.x + x;
|
||||
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) {
|
||||
vector<uint8_t> image_data;
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
m_connection.clear_area(1, client->window(), 0, 0, m_opts.width, height);
|
||||
client->clear_window();
|
||||
}
|
||||
|
||||
m_connection.flush();
|
||||
@ -473,9 +508,9 @@ void tray_manager::refresh_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));
|
||||
reconfigure_bg(true);
|
||||
reconfigure_bg(realloc_bg);
|
||||
refresh_window();
|
||||
}
|
||||
|
||||
@ -501,7 +536,9 @@ void tray_manager::create_window() {
|
||||
<< cw_pos(calculate_x(calculate_w()), calculate_y())
|
||||
<< cw_class(XCB_WINDOW_CLASS_INPUT_OUTPUT)
|
||||
<< 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);
|
||||
// clang-format on
|
||||
|
||||
@ -880,7 +917,6 @@ int tray_manager::mapped_clients() const {
|
||||
*/
|
||||
void tray_manager::handle(const evt::expose& evt) {
|
||||
if (m_activated && !m_clients.empty() && evt->count == 0) {
|
||||
reconfigure_window();
|
||||
redraw_window();
|
||||
}
|
||||
}
|
||||
@ -1001,11 +1037,11 @@ void tray_manager::handle(const evt::property_notify& evt) {
|
||||
if (!m_activated) {
|
||||
return;
|
||||
} else if (evt->atom == _XROOTMAP_ID) {
|
||||
redraw_window();
|
||||
redraw_window(true);
|
||||
} else if (evt->atom == _XSETROOT_ID) {
|
||||
redraw_window();
|
||||
redraw_window(true);
|
||||
} else if (evt->atom == ESETROOT_PMAP_ID) {
|
||||
redraw_window();
|
||||
redraw_window(true);
|
||||
} else if (evt->atom == _XEMBED_INFO) {
|
||||
auto client = find_client(evt->window);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user