diff --git a/include/atoms.xmacro b/include/atoms.xmacro index 205efa17..ac32d8da 100644 --- a/include/atoms.xmacro +++ b/include/atoms.xmacro @@ -15,8 +15,8 @@ xmacro(_NET_WM_STRUT_PARTIAL) xmacro(_NET_CLIENT_LIST_STACKING) xmacro(_NET_CURRENT_DESKTOP) xmacro(_NET_ACTIVE_WINDOW) -xmacro(_NET_WORKAREA) xmacro(_NET_STARTUP_ID) +xmacro(_NET_WORKAREA) xmacro(WM_PROTOCOLS) xmacro(WM_DELETE_WINDOW) xmacro(UTF8_STRING) diff --git a/include/ewmh.h b/include/ewmh.h index 07ef6614..c36eaeb0 100644 --- a/include/ewmh.h +++ b/include/ewmh.h @@ -46,4 +46,21 @@ void ewmh_update_client_list_stacking(xcb_window_t *stack, int num_windows); */ void ewmh_setup_hints(void); +/** + * i3 currently does not support _NET_WORKAREA, because it does not correspond + * to i3’s concept of workspaces. See also: + * http://bugs.i3wm.org/539 + * http://bugs.i3wm.org/301 + * http://bugs.i3wm.org/1038 + * + * We need to actively delete this property because some display managers (e.g. + * LightDM) set it. + * + * EWMH: Contains a geometry for each desktop. These geometries specify an area + * that is completely contained within the viewport. Work area SHOULD be used by + * desktop applications to place desktop icons appropriately. + * + */ +void ewmh_update_workarea(void); + #endif diff --git a/src/ewmh.c b/src/ewmh.c index 9021e1c5..0298de3d 100644 --- a/src/ewmh.c +++ b/src/ewmh.c @@ -50,11 +50,14 @@ void ewmh_update_active_window(xcb_window_t window) { } /* - * Updates the workarea for each desktop. - * - * This function is not called at the moment due to: + * i3 currently does not support _NET_WORKAREA, because it does not correspond + * to i3’s concept of workspaces. See also: * http://bugs.i3wm.org/539 * http://bugs.i3wm.org/301 + * http://bugs.i3wm.org/1038 + * + * We need to actively delete this property because some display managers (e.g. + * LightDM) set it. * * EWMH: Contains a geometry for each desktop. These geometries specify an area * that is completely contained within the viewport. Work area SHOULD be used by @@ -62,55 +65,7 @@ void ewmh_update_active_window(xcb_window_t window) { * */ void ewmh_update_workarea(void) { - int num_workspaces = 0, count = 0; - Rect last_rect = {0, 0, 0, 0}; - Con *output; - - TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { - Con *ws; - TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) { - /* Check if we need to initialize last_rect. The case that the - * first workspace is all-zero may happen when the user - * assigned workspace 2 for his first screen, for example. Thus - * we need an initialized last_rect in the very first run of - * the following loop. */ - if (last_rect.width == 0 && last_rect.height == 0 && - ws->rect.width != 0 && ws->rect.height != 0) { - memcpy(&last_rect, &(ws->rect), sizeof(Rect)); - } - num_workspaces++; - } - } - - DLOG("Got %d workspaces\n", num_workspaces); - uint8_t *workarea = smalloc(sizeof(Rect) * num_workspaces); - TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { - Con *ws; - TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) { - DLOG("storing %d: %dx%d with %d x %d\n", count, ws->rect.x, - ws->rect.y, ws->rect.width, ws->rect.height); - /* If a workspace is not yet initialized and thus its - * dimensions are zero, we will instead put the dimensions - * of the last workspace in the list. For example firefox - * intersects all workspaces and does not cope so well with - * an all-zero workspace. */ - if (ws->rect.width == 0 || ws->rect.height == 0) { - DLOG("re-using last_rect (%dx%d, %d, %d)\n", - last_rect.x, last_rect.y, last_rect.width, - last_rect.height); - memcpy(workarea + (sizeof(Rect) * count++), &last_rect, sizeof(Rect)); - continue; - } - memcpy(workarea + (sizeof(Rect) * count++), &(ws->rect), sizeof(Rect)); - memcpy(&last_rect, &(ws->rect), sizeof(Rect)); - } - } - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, - A__NET_WORKAREA, XCB_ATOM_CARDINAL, 32, - num_workspaces * (sizeof(Rect) / sizeof(uint32_t)), - workarea); - free(workarea); - xcb_flush(conn); + xcb_delete_property(conn, root, A__NET_WORKAREA); } /* @@ -164,5 +119,5 @@ void ewmh_setup_hints(void) { /* I’m not entirely sure if we need to keep _NET_WM_NAME on root. */ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3"); - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 19, supported_atoms); + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 18, supported_atoms); } diff --git a/src/main.c b/src/main.c index bc3bb634..aac73883 100644 --- a/src/main.c +++ b/src/main.c @@ -729,6 +729,7 @@ int main(int argc, char *argv[]) { /* Set up i3 specific atoms like I3_SOCKET_PATH and I3_CONFIG_PATH */ x_set_i3_atoms(); + ewmh_update_workarea(); struct ev_io *xcb_watcher = scalloc(sizeof(struct ev_io)); struct ev_io *xkb = scalloc(sizeof(struct ev_io)); diff --git a/testcases/t/209-ewmh-net-workarea.t b/testcases/t/209-ewmh-net-workarea.t new file mode 100644 index 00000000..34309828 --- /dev/null +++ b/testcases/t/209-ewmh-net-workarea.t @@ -0,0 +1,71 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Please read the following documents before working on tests: +# • http://build.i3wm.org/docs/testsuite.html +# (or docs/testsuite) +# +# • http://build.i3wm.org/docs/lib-i3test.html +# (alternatively: perldoc ./testcases/lib/i3test.pm) +# +# • http://build.i3wm.org/docs/ipc.html +# (or docs/ipc) +# +# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf +# (unless you are already familiar with Perl) +# +# Verifies the _NET_WORKAREA hint is deleted in case it is already set on the +# root window. +# Ticket: #1038 +# Bug still in: 4.5.1-103-g1f8a860 +use i3test i3_autostart => 0; +use X11::XCB qw(PROP_MODE_REPLACE); + +my $atom_cookie = $x->intern_atom( + 0, # create! + length('_NET_WORKAREA'), + '_NET_WORKAREA', +); + +my $_net_workarea_id = $x->intern_atom_reply($atom_cookie->{sequence})->{atom}; + +$x->change_property( + PROP_MODE_REPLACE, + $x->get_root_window(), + $_net_workarea_id, + $x->atom(name => 'CARDINAL')->id, + 32, + 4, + pack('L4', 0, 0, 1024, 768)); +$x->flush; + +sub is_net_workarea_set { + my $cookie = $x->get_property( + 0, + $x->get_root_window(), + $x->atom(name => '_NET_WORKAREA')->id, + $x->atom(name => 'CARDINAL')->id, + 0, + 4096, + ); + my $reply = $x->get_property_reply($cookie->{sequence}); + return 0 if $reply->{value_len} == 0; + return 0 if $reply->{format} == 0; + return 1 +} + +ok(is_net_workarea_set(), '_NET_WORKAREA is set before starting i3'); + +my $config = <