Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Systray composition support #3664

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/apidoc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ jobs:
libxcb-shape0-dev \
libxcb-util0-dev \
libxcb-xfixes0-dev \
libxcb-composite0-dev \
libxcb-damage0-dev \
libxcb-xinerama0-dev \
libxcb-xkb-dev \
libxcb-xrm-dev \
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ jobs:
libxcb-shape0-dev \
libxcb-util0-dev \
libxcb-xfixes0-dev \
libxcb-composite0-dev \
libxcb-damage0-dev \
libxcb-xinerama0-dev \
libxcb-xkb-dev \
libxcb-xrm-dev \
Expand Down
18 changes: 18 additions & 0 deletions awesome.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
#include <xcb/xtest.h>
#include <xcb/shape.h>
#include <xcb/xfixes.h>
#include <xcb/composite.h>
#include <xcb/damage.h>

#include <glib-unix.h>

Expand Down Expand Up @@ -725,6 +727,8 @@ main(int argc, char **argv)
xcb_prefetch_extension_data(globalconf.connection, &xcb_xinerama_id);
xcb_prefetch_extension_data(globalconf.connection, &xcb_shape_id);
xcb_prefetch_extension_data(globalconf.connection, &xcb_xfixes_id);
xcb_prefetch_extension_data(globalconf.connection, &xcb_composite_id);
xcb_prefetch_extension_data(globalconf.connection, &xcb_damage_id);

if (xcb_cursor_context_new(globalconf.connection, globalconf.screen, &globalconf.cursor_ctx) < 0)
fatal("Failed to initialize xcb-cursor");
Expand Down Expand Up @@ -793,6 +797,20 @@ main(int argc, char **argv)
xcb_discard_reply(globalconf.connection,
xcb_xfixes_query_version(globalconf.connection, 1, 0).sequence);

query = xcb_get_extension_data(globalconf.connection, &xcb_composite_id);
globalconf.have_composite = query && query->present;
if (globalconf.have_composite)
xcb_discard_reply(globalconf.connection,
xcb_composite_query_version(globalconf.connection, 0, 3).sequence);
xinhaoyuan marked this conversation as resolved.
Show resolved Hide resolved

query = xcb_get_extension_data(globalconf.connection, &xcb_damage_id);
globalconf.have_damage = query && query->present;
if (globalconf.have_damage)
xcb_discard_reply(globalconf.connection,
xcb_damage_query_version(globalconf.connection, 1, 0).sequence);

globalconf.is_compositing = globalconf.have_composite && globalconf.have_damage;

event_init();

/* Allocate the key symbols */
Expand Down
2 changes: 2 additions & 0 deletions awesomeConfig.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ set(AWESOME_DEPENDENCIES
xcb-icccm
xcb-icccm>=0.3.8
xcb-xfixes
xcb-composite
xcb-damage
xinhaoyuan marked this conversation as resolved.
Show resolved Hide resolved
# NOTE: it's not clear what version is required, but 1.10 works at least.
# See https://github.com/awesomeWM/awesome/pull/149#issuecomment-94208356.
xcb-xkb
Expand Down
1 change: 1 addition & 0 deletions common/atoms.list
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ ESETROOT_PMAP_ID
WM_STATE
_NET_WM_WINDOW_OPACITY
_NET_SYSTEM_TRAY_ORIENTATION
_NET_SYSTEM_TRAY_VISUAL
WM_CHANGE_STATE
WM_WINDOW_ROLE
WM_CLIENT_LEADER
Expand Down
1 change: 1 addition & 0 deletions common/xembed.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ typedef struct xembed_window xembed_window_t;
struct xembed_window
{
xcb_window_t win;
uint8_t depth;
xembed_info_t info;
};

Expand Down
2 changes: 2 additions & 0 deletions docs/10-building-and-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ environment):
- [libxcb-keysyms >= 0.3.4](https://xcb.freedesktop.org/)
- [libxcb-icccm >= 0.3.8](https://xcb.freedesktop.org/)
- [libxcb-xfixes](https://xcb.freedesktop.org/)
- [libxcb-composite](https://xcb.freedesktop.org/)
- [libxcb-damage](https://xcb.freedesktop.org/)
- [xcb-util-xrm >= 1.0](https://github.com/Airblader/xcb-util-xrm)
- [libxkbcommon](http://xkbcommon.org/) with X11 support enabled
- [libstartup-notification >=
Expand Down
14 changes: 14 additions & 0 deletions event.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <xcb/xcb_event.h>
#include <xcb/xkb.h>
#include <xcb/xfixes.h>
#include <xcb/damage.h>

#define DO_EVENT_HOOK_CALLBACK(type, xcbtype, xcbeventprefix, arraytype, match) \
static void \
Expand Down Expand Up @@ -1023,6 +1024,14 @@ event_handle_selectionclear(xcb_selection_clear_event_t *ev)
selection_handle_selectionclear(ev);
}

static void
event_handle_damage_notify(xcb_damage_notify_event_t *ev) {
if (ev->drawable == globalconf.systray.window) {
luaA_systray_invalidate();
xcb_damage_subtract(globalconf.connection, ev->damage, None, None);
}
}

/** \brief awesome xerror function.
* There's no way to check accesses to destroyed windows, thus those cases are
* ignored (especially on UnmapNotify's).
Expand Down Expand Up @@ -1143,6 +1152,7 @@ void event_handle(xcb_generic_event_t *event)
EXTENSION_EVENT(shape, XCB_SHAPE_NOTIFY, event_handle_shape_notify);
EXTENSION_EVENT(xkb, 0, event_handle_xkb_notify);
EXTENSION_EVENT(xfixes, XCB_XFIXES_SELECTION_NOTIFY, event_handle_xfixes_selection_notify);
EXTENSION_EVENT(damage, XCB_DAMAGE_NOTIFY, event_handle_damage_notify);
#undef EXTENSION_EVENT
}

Expand All @@ -1165,6 +1175,10 @@ void event_init(void)
reply = xcb_get_extension_data(globalconf.connection, &xcb_xfixes_id);
if (reply && reply->present)
globalconf.event_base_xfixes = reply->first_event;

reply = xcb_get_extension_data(globalconf.connection, &xcb_damage_id);
if (reply && reply->present)
globalconf.event_base_damage = reply->first_event;
}

// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
7 changes: 7 additions & 0 deletions globalconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ typedef struct
bool have_xkb;
/** Check for XFixes extension */
bool have_xfixes;
/** Check for Composite extension */
bool have_composite;
/** Check for Damage extenion */
bool have_damage;
/** Enable compositing features? */
bool is_compositing;
/** Custom searchpaths are present, the runtime is tinted */
bool have_searchpaths;
/** When --no-argb is used in the modeline or command line */
Expand All @@ -134,6 +140,7 @@ typedef struct
uint8_t event_base_xkb;
uint8_t event_base_randr;
uint8_t event_base_xfixes;
uint8_t event_base_damage;
/** Clients list */
client_array_t clients;
/** Embedded windows */
Expand Down
24 changes: 24 additions & 0 deletions lib/wibox/widget/systray.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

local wbase = require("wibox.widget.base")
local drawable = require("wibox.drawable")
local cairo = require("lgi").cairo
local beautiful = require("beautiful")
local gcolor = require("gears.color")
local gtable = require("gears.table")
local capi = {
awesome = awesome,
Expand Down Expand Up @@ -42,6 +44,11 @@ local display_on_screen = "primary"
-- @beautiful beautiful.systray_icon_spacing
-- @tparam[opt=0] integer The icon spacing

--- Whether to skip drawing the systray background when compositing the systray icons.
--
-- @beautiful beautiful.systray_skip_bg
-- @tparam[opt=0] boolean Whether to skip drawing the systray background

local function should_display_on(s)
if display_on_screen == "primary" then
return s == capi.screen.primary
Expand Down Expand Up @@ -90,6 +97,23 @@ function systray:draw(context, cr, width, height)
end
capi.awesome.systray(context.wibox.drawin, math.ceil(x), math.ceil(y),
base, is_rotated, bg, reverse, spacing, rows)

local surf_width, surf_height =
base * rows + spacing * (rows - 1),
base * cols + spacing * (cols - 1)
if is_rotated then
surf_width, surf_height = surf_height, surf_width
end
local surf_raw = capi.awesome.systray_surface(surf_width, surf_height)
if surf_raw then
local surf = cairo.Surface(surf_raw, true)
if not beautiful.systray_skip_bg then
cr:set_source(gcolor(bg))
cr:paint()
end
cr:set_source_surface(surf, 0, 0)
cr:paint()
end
end

-- Private API. Does not appear in LDoc on purpose. This function is called
Expand Down
1 change: 1 addition & 0 deletions luaa.c
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,7 @@ luaA_init(xdgHandle* xdg, string_array_t *searchpath)
{ "disconnect_signal", luaA_awesome_disconnect_signal },
{ "emit_signal", luaA_awesome_emit_signal },
{ "systray", luaA_systray },
{ "systray_surface", luaA_systray_surface },
{ "load_image", luaA_load_image },
{ "pixbuf_to_surface", luaA_pixbuf_to_surface },
{ "set_preferred_icon_size", luaA_set_preferred_icon_size },
Expand Down
3 changes: 3 additions & 0 deletions objects/drawin.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

#include <cairo-xcb.h>
#include <xcb/shape.h>
#include <xcb/composite.h>

lua_class_t drawin_class;

Expand Down Expand Up @@ -451,6 +452,8 @@ drawin_allocator(lua_State *L)
globalconf.default_cmap,
xcursor_new(globalconf.cursor_ctx, xcursor_font_fromstr(w->cursor))
});
if (globalconf.is_compositing)
xcb_composite_redirect_subwindows(globalconf.connection, w->window, XCB_COMPOSITE_REDIRECT_MANUAL);
psychon marked this conversation as resolved.
Show resolved Hide resolved
xwindow_set_class_instance(w->window);
xwindow_set_name_static(w->window, "Awesome drawin");

Expand Down
5 changes: 4 additions & 1 deletion spec/wibox/widget/systray_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ _G.awesome = {
systray_arguments = { first_arg, ... }
end
return num_systray_icons
end
end,
systray_surface = function()
return nil
end,
}
_G.screen = {
connect_signal = function() end
Expand Down
95 changes: 82 additions & 13 deletions systray.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <xcb/xcb.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xcb_atom.h>
#include <xcb/damage.h>
#include <cairo-xcb.h>

#define SYSTEM_TRAY_REQUEST_DOCK 0 /* Begin icon docking */

Expand All @@ -44,13 +46,29 @@

globalconf.systray.window = xcb_generate_id(globalconf.connection);
globalconf.systray.background_pixel = xscreen->black_pixel;
xcb_create_window(globalconf.connection, xscreen->root_depth,
globalconf.systray.window,
xscreen->root,
-1, -1, 1, 1, 0,
XCB_COPY_FROM_PARENT, xscreen->root_visual,
XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, (const uint32_t [])
{ xscreen->black_pixel, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT });
if (globalconf.is_compositing) {
xcb_create_window(globalconf.connection, globalconf.default_depth,
globalconf.systray.window,
xscreen->root,
-1, -1, 1, 1, 0,
XCB_COPY_FROM_PARENT, globalconf.visual->visual_id,
XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP,
(const uint32_t [])
{ xscreen->black_pixel, xscreen->black_pixel, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, globalconf.default_cmap });
xcb_damage_create(globalconf.connection, xcb_generate_id(globalconf.connection), globalconf.systray.window, XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
globalconf.systray.window, _NET_SYSTEM_TRAY_VISUAL,
XCB_ATOM_VISUALID, 32, 1, (const uint32_t [])
{ globalconf.visual->visual_id });
} else {
xcb_create_window(globalconf.connection, xscreen->root_depth,

Check warning on line 64 in systray.c

View check run for this annotation

Codecov / codecov/patch

systray.c#L64

Added line #L64 was not covered by tests
globalconf.systray.window,
xscreen->root,
-1, -1, 1, 1, 0,
XCB_COPY_FROM_PARENT, xscreen->root_visual,
XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, (const uint32_t [])
{ xscreen->black_pixel, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT });

Check warning on line 70 in systray.c

View check run for this annotation

Codecov / codecov/patch

systray.c#L70

Added line #L70 was not covered by tests
}
xwindow_set_class_instance(globalconf.systray.window);
xwindow_set_name_static(globalconf.systray.window, "Awesome systray window");

Expand Down Expand Up @@ -130,6 +148,8 @@
systray_request_handle(xcb_window_t embed_win)
{
xembed_window_t em;
xcb_get_geometry_cookie_t geom_c;
xcb_get_geometry_reply_t *geom_r;
xcb_get_property_cookie_t em_cookie;
const uint32_t select_input_val[] =
{
Expand All @@ -142,13 +162,28 @@
if(xembed_getbywin(&globalconf.embedded, embed_win))
return -1;

geom_c = xcb_get_geometry(globalconf.connection, embed_win);
if(!(geom_r = xcb_get_geometry_reply(globalconf.connection, geom_c, NULL)))
return -1;
em.depth = geom_r->depth;
p_delete(&geom_r);

p_clear(&em_cookie, 1);

em_cookie = xembed_info_get_unchecked(globalconf.connection, embed_win);

xcb_change_window_attributes(globalconf.connection, embed_win, XCB_CW_EVENT_MASK,
select_input_val);


if (globalconf.is_compositing && em.depth != globalconf.default_depth) {
/* Disable the message because the test runner is not happy with warnings. This should rarely happen anyway. */
/* warn("Fixing the background of the systray window 0x%x possibly because the client does not support composition.", embed_win); */
xcb_change_window_attributes(globalconf.connection, embed_win, XCB_CW_BACK_PIXEL,
(const uint32_t []){ globalconf.systray.background_pixel });
xcb_clear_area(globalconf.connection, 1, embed_win, 0, 0, 0, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhm, what? I do not understand the reason behind this whole code block. If some window has a different depth.... so be it. I do not see anything in https://specifications.freedesktop.org/systemtray-spec/systemtray-spec-0.3.html or https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html allowing to do this. Do other tray compositing managers do this?

(Basically same comment below to the code that handles changes to globalconf.systray.background_pixel)

Oh also: This might warrant a comment in the code. It just occurred to me that:

  • legacy systray clients use a ParentRelative backgroud
  • reparenting such a window into a window with a different depth does not work
  • thus, this is here to "make things work"

(But what about all the other window properties that are needed for a different depth window? According to https://stackoverflow.com/questions/3645632/how-to-create-a-window-with-a-bit-depth-of-32, one also needs to set a colormap and a border pixel/border pixmap. Why doesn't this code need that?)

}

/* we grab the window, but also make sure it's automatically reparented back
* to the root window if we should die.
*/
Expand Down Expand Up @@ -376,12 +411,21 @@
&& globalconf.systray.background_pixel != bg_color.pixel)
{
uint32_t config_back[] = { bg_color.pixel };
globalconf.systray.background_pixel = bg_color.pixel;
xcb_change_window_attributes(globalconf.connection,
globalconf.systray.window,
XCB_CW_BACK_PIXEL, config_back);
xcb_clear_area(globalconf.connection, 1, globalconf.systray.window, 0, 0, 0, 0);
force_redraw = true;
if (globalconf.is_compositing) {
foreach(em, globalconf.embedded)
if (em->depth != globalconf.default_depth) {
xcb_change_window_attributes(
globalconf.connection, em->win, XCB_CW_BACK_PIXEL, config_back);
xcb_clear_area(globalconf.connection, 1, em->win, 0, 0, 0, 0);
}
} else {
globalconf.systray.background_pixel = bg_color.pixel;
xcb_change_window_attributes(globalconf.connection,

Check warning on line 423 in systray.c

View check run for this annotation

Codecov / codecov/patch

systray.c#L422-L423

Added lines #L422 - L423 were not covered by tests
globalconf.systray.window,
XCB_CW_BACK_PIXEL, config_back);
xcb_clear_area(globalconf.connection, 1, globalconf.systray.window, 0, 0, 0, 0);
force_redraw = true;

Check warning on line 427 in systray.c

View check run for this annotation

Codecov / codecov/patch

systray.c#L426-L427

Added lines #L426 - L427 were not covered by tests
}
}

if(globalconf.systray.parent != w)
Expand Down Expand Up @@ -413,4 +457,29 @@
return 2;
}

/** Return the native surface of the systray if composite is enabled.
* \param L The Lua VM state.
* \return the number of element returned. (1)
* \luastack
* \lparam width The width of the systray surface.
* \lparam height The height of the systray surface.
*/
int
luaA_systray_surface(lua_State *L)
{
if (!globalconf.is_compositing) {
lua_pushnil(L);
return 1;

Check warning on line 472 in systray.c

View check run for this annotation

Codecov / codecov/patch

systray.c#L471-L472

Added lines #L471 - L472 were not covered by tests
}

int width = luaL_checkinteger(L, 1);
int height = luaL_checkinteger(L, 2);
/* Lua has to make sure to free the ref or we have a leak */
lua_pushlightuserdata(
L, cairo_xcb_surface_create(
globalconf.connection, globalconf.systray.window, globalconf.visual,
width, height));
psychon marked this conversation as resolved.
Show resolved Hide resolved
return 1;
}

// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
1 change: 1 addition & 0 deletions systray.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ bool systray_iskdedockapp(xcb_window_t);
int systray_process_client_message(xcb_client_message_event_t *);
int xembed_process_client_message(xcb_client_message_event_t *);
int luaA_systray(lua_State *);
int luaA_systray_surface(lua_State *);

#endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
Loading
Loading