From 24f0ea2f24661932e9e5055beeda7650621d5db0 Mon Sep 17 00:00:00 2001 From: Deiz Date: Wed, 25 Mar 2015 22:40:59 -0400 Subject: [PATCH 001/243] Make center coordinates relative to current workspace Fixes #1211 --- src/commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands.c b/src/commands.c index 9b51b3ec..2121fc66 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1761,8 +1761,8 @@ void cmd_move_window_to_center(I3_CMD, char *method) { Rect newrect = focused->parent->rect; DLOG("moving to center\n"); - newrect.x = wsrect->width / 2 - newrect.width / 2; - newrect.y = wsrect->height / 2 - newrect.height / 2; + newrect.x = wsrect->x + wsrect->width / 2 - newrect.width / 2; + newrect.y = wsrect->y + wsrect->height / 2 - newrect.height / 2; floating_reposition(focused->parent, newrect); } From 43f65e1d2b5662602785a7b8ca991014761ee335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 27 Mar 2015 08:44:00 +0100 Subject: [PATCH 002/243] Compile xcb-randr support into i3-nagbar --- i3-nagbar/i3-nagbar.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i3-nagbar/i3-nagbar.mk b/i3-nagbar/i3-nagbar.mk index e54aa654..53adc4ab 100644 --- a/i3-nagbar/i3-nagbar.mk +++ b/i3-nagbar/i3-nagbar.mk @@ -4,8 +4,8 @@ CLEAN_TARGETS += clean-i3-nagbar i3_nagbar_SOURCES := $(wildcard i3-nagbar/*.c) i3_nagbar_HEADERS := $(wildcard i3-nagbar/*.h) -i3_nagbar_CFLAGS = $(XCB_CFLAGS) $(PANGO_CFLAGS) -i3_nagbar_LIBS = $(XCB_LIBS) $(PANGO_LIBS) +i3_nagbar_CFLAGS = $(XCB_CFLAGS) $(XCB_WB_CFLAGS) $(PANGO_CFLAGS) +i3_nagbar_LIBS = $(XCB_LIBS) $(XCB_WM_LIBS) $(PANGO_LIBS) i3_nagbar_OBJECTS := $(i3_nagbar_SOURCES:.c=.o) From bae66a9dae68870491be50b9fb1d5adf23d7f99c Mon Sep 17 00:00:00 2001 From: Deiz Date: Fri, 27 Mar 2015 14:29:53 -0400 Subject: [PATCH 003/243] Add a test case for #1211 --- testcases/t/523-move-position-center.t | 63 ++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 testcases/t/523-move-position-center.t diff --git a/testcases/t/523-move-position-center.t b/testcases/t/523-move-position-center.t new file mode 100644 index 00000000..6b584245 --- /dev/null +++ b/testcases/t/523-move-position-center.t @@ -0,0 +1,63 @@ +#!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 that 'move position center' moves floating cons to the center of +# the appropriate output. +# Ticket: #1211 +# Bug still in: 4.9.1-108-g037cb31 +use i3test i3_autostart => 0; + +my $config = <{floating_nodes}}, 1, 'one floating node on left ws'); +is(scalar @{get_ws('right')->{floating_nodes}}, 0, 'no floating nodes on right ws'); + +# Center the window on the right workspace +cmd 'move workspace right; workspace right; move position center'; +sync_with_i3; + +is(scalar @{get_ws('left')->{floating_nodes}}, 0, 'no floating nodes on left ws'); +is(scalar @{get_ws('right')->{floating_nodes}}, 1, 'one floating node on right ws'); + +exit_gracefully($pid); + +done_testing; From 48d2acd8f6580b4185c8f945ddd4ce5f91b0e666 Mon Sep 17 00:00:00 2001 From: Deiz Date: Fri, 27 Mar 2015 22:20:28 -0400 Subject: [PATCH 004/243] Fix percents when attaching a window to a ws creates a new split con Fixes #1484 and includes a test case. --- src/workspace.c | 3 ++ .../t/240-tabbed-floating-disable-crash.t | 44 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 testcases/t/240-tabbed-floating-disable-crash.t diff --git a/src/workspace.c b/src/workspace.c index f55c920e..4a16f3d1 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -846,6 +846,9 @@ Con *workspace_attach_to(Con *ws) { DLOG("Attaching new split %p to workspace %p\n", new, ws); con_attach(new, ws, false); + /* 5: fix the percentages */ + con_fix_percent(ws); + return new; } diff --git a/testcases/t/240-tabbed-floating-disable-crash.t b/testcases/t/240-tabbed-floating-disable-crash.t new file mode 100644 index 00000000..7947158c --- /dev/null +++ b/testcases/t/240-tabbed-floating-disable-crash.t @@ -0,0 +1,44 @@ +#!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 that i3 does not crash when floating and then unfloating an +# unfocused window within a tabbed container. +# Ticket: #1484 +# Bug still in: 4.9.1-124-g856e1f9 +use i3test i3_autostart => 0; + +my $config = < Date: Sat, 28 Mar 2015 18:29:34 +0100 Subject: [PATCH 005/243] Move urgency hint when moving container When an urgent container is moved to another workspace, the urgency hint 1) is unset on the source workspace and 2) set on the target workspace fixes #1187 --- src/con.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/con.c b/src/con.c index b610b0c6..41dd0196 100644 --- a/src/con.c +++ b/src/con.c @@ -736,6 +736,9 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool } } + /* Save the urgency state so that we can restore it. */ + bool urgent = con->urgent; + /* Save the current workspace. So we can call workspace_show() by the end * of this function. */ Con *current_ws = con_get_workspace(focused); @@ -843,7 +846,7 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool if (source_ws == current_ws) con_focus(con_descend_focused(focus_next)); - /* If anything within the container is associated with a startup sequence, + /* 9. If anything within the container is associated with a startup sequence, * delete it so child windows won't be created on the old workspace. */ struct Startup_Sequence *sequence; xcb_get_property_cookie_t cookie; @@ -877,6 +880,12 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool CALL(parent, on_remove_child); + /* 10. If the container was marked urgent, move the urgency hint. */ + if (urgent) { + workspace_update_urgent_flag(source_ws); + con_set_urgency(con, true); + } + ipc_send_window_event("move", con); } From c5fad4f5792729491267aaca8516e6ad96cf1e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sat, 28 Mar 2015 19:23:59 +0100 Subject: [PATCH 006/243] Added a regression test for #1187 --- testcases/t/113-urgent.t | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/testcases/t/113-urgent.t b/testcases/t/113-urgent.t index bb913819..3b82fe22 100644 --- a/testcases/t/113-urgent.t +++ b/testcases/t/113-urgent.t @@ -307,6 +307,33 @@ for ($type = 1; $type <= 2; $type++) { my $ws = get_ws($tmp); ok(!$ws->{urgent}, 'urgent flag not set on workspace'); +############################################################################## +# Regression test for #1187: Urgency hint moves to new workspace when moving +# a container to another workspace. +############################################################################## + + my $tmp_source = fresh_workspace; + my $tmp_target = fresh_workspace; + cmd 'workspace ' . $tmp_source; + sync_with_i3; + my $w1 = open_window; + my $w2 = open_window; + sync_with_i3; + cmd '[id="' . $w1->id . '"] focus'; + sync_with_i3; + cmd 'mark urgent_con'; + cmd '[id="' . $w2->id . '"] focus'; + set_urgency($w1, 1, $type); + sync_with_i3; + cmd '[con_mark="urgent_con"] move container to workspace ' . $tmp_target; + sync_with_i3; + my $source_ws = get_ws($tmp_source); + my $target_ws = get_ws($tmp_target); + ok(!$source_ws->{urgent}, 'Source workspace is no longer marked urgent'); + is($target_ws->{urgent}, 1, 'Target workspace is now marked urgent'); + +############################################################################## + exit_gracefully($pid); } From 0ad926825394f17e556a65d8a6ca83afd0822ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 27 Mar 2015 09:20:03 +0100 Subject: [PATCH 007/243] Open i3-nagbar on the primary screen If a primary screen is set and the CRTC information can be retrieved, i3-nagbar will now open on the primary screen. Otherwise, the old (fixed) position will be used as a fallback. fixes #1405 --- i3-nagbar/i3-nagbar.mk | 2 +- i3-nagbar/main.c | 65 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/i3-nagbar/i3-nagbar.mk b/i3-nagbar/i3-nagbar.mk index 53adc4ab..e98d6582 100644 --- a/i3-nagbar/i3-nagbar.mk +++ b/i3-nagbar/i3-nagbar.mk @@ -4,7 +4,7 @@ CLEAN_TARGETS += clean-i3-nagbar i3_nagbar_SOURCES := $(wildcard i3-nagbar/*.c) i3_nagbar_HEADERS := $(wildcard i3-nagbar/*.h) -i3_nagbar_CFLAGS = $(XCB_CFLAGS) $(XCB_WB_CFLAGS) $(PANGO_CFLAGS) +i3_nagbar_CFLAGS = $(XCB_CFLAGS) $(XCB_WM_CFLAGS) $(PANGO_CFLAGS) i3_nagbar_LIBS = $(XCB_LIBS) $(XCB_WM_LIBS) $(PANGO_LIBS) i3_nagbar_OBJECTS := $(i3_nagbar_SOURCES:.c=.o) diff --git a/i3-nagbar/main.c b/i3-nagbar/main.c index 805066f8..ecccd363 100644 --- a/i3-nagbar/main.c +++ b/i3-nagbar/main.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "libi3.h" #include "i3-nagbar.h" @@ -286,6 +287,60 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { return 1; } +/** + * Return the position and size the i3-nagbar window should use. + * This will be the primary output or a fallback if it cannot be determined. + */ +static xcb_rectangle_t get_window_position(void) { + /* Default values if we cannot determine the primary output or its CRTC info. */ + xcb_rectangle_t result = (xcb_rectangle_t){50, 50, 500, font.height + logical_px(8) + logical_px(8)}; + + xcb_randr_get_screen_resources_current_cookie_t rcookie = xcb_randr_get_screen_resources_current(conn, root); + xcb_randr_get_output_primary_cookie_t pcookie = xcb_randr_get_output_primary(conn, root); + + xcb_randr_get_output_primary_reply_t *primary; + xcb_randr_get_screen_resources_current_reply_t *res; + + if ((primary = xcb_randr_get_output_primary_reply(conn, pcookie, NULL)) == NULL) { + DLOG("Could not determine the primary output.\n"); + goto free_resources; + } + + if ((res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL)) == NULL) { + goto free_resources; + } + + xcb_randr_get_output_info_reply_t *output = + xcb_randr_get_output_info_reply(conn, + xcb_randr_get_output_info(conn, primary->output, res->config_timestamp), + NULL); + if (output == NULL || output->crtc == XCB_NONE) + goto free_resources; + + xcb_randr_get_crtc_info_reply_t *crtc = + xcb_randr_get_crtc_info_reply(conn, + xcb_randr_get_crtc_info(conn, output->crtc, res->config_timestamp), + NULL); + if (crtc == NULL) + goto free_resources; + + DLOG("Found primary output on position x = %i / y = %i / w = %i / h = %i", + crtc->x, crtc->y, crtc->width, crtc->height); + if (crtc->width == 0 || crtc->height == 0) { + DLOG("Primary output is not active, ignoring it.\n"); + goto free_resources; + } + + result.x = crtc->x; + result.y = crtc->y; + goto free_resources; + +free_resources: + FREE(res); + FREE(primary); + return result; +} + int main(int argc, char *argv[]) { /* The following lines are a terribly horrible kludge. Because terminal * emulators have different ways of interpreting the -e command line @@ -408,16 +463,18 @@ int main(int argc, char *argv[]) { font = load_font(pattern, true); set_font(&font); + xcb_rectangle_t win_pos = get_window_position(); + /* Open an input window */ win = xcb_generate_id(conn); xcb_create_window( conn, XCB_COPY_FROM_PARENT, - win, /* the window id */ - root, /* parent == root */ - 50, 50, 500, font.height + logical_px(8) + logical_px(8) /* 8 px padding */, /* dimensions */ - 0, /* x11 border = 0, we draw our own */ + win, /* the window id */ + root, /* parent == root */ + win_pos.x, win_pos.y, win_pos.width, win_pos.height, /* dimensions */ + 0, /* x11 border = 0, we draw our own */ XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */ XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, From 3360ba7212408f2f17b25a29cd5874282432536e Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 29 Mar 2015 19:10:41 +0200 Subject: [PATCH 008/243] update debian/changelog --- debian/changelog | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index cc0e5328..183e5940 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,14 @@ -i3-wm (4.10.1-1) experimental; urgency=medium +i3-wm (4.10.2-1) experimental; urgency=medium * NOT YET RELEASED. - -- Michael Stapelberg Sun, 29 Mar 2015 18:08:13 +0200 + -- Michael Stapelberg Sun, 29 Mar 2015 19:10:38 +0200 + +i3-wm (4.10.1-1) experimental; urgency=medium + + * New upstream release. + + -- Michael Stapelberg Sun, 29 Mar 2015 18:54:07 +0200 i3-wm (4.10-1) experimental; urgency=medium From fe8003ef4ff0e04a926414e15a9a79ac37797442 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 29 Mar 2015 19:22:29 +0200 Subject: [PATCH 009/243] release.sh: set up git remotes appropriately --- release.sh | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/release.sh b/release.sh index 646034a6..3c7ddd85 100755 --- a/release.sh +++ b/release.sh @@ -82,6 +82,12 @@ else git merge --no-ff next -m "Merge branch 'next' into master" fi +git remote remove origin +git remote add origin git@github.com:i3/i3.git +git config --add remote.origin.push "+refs/tags/*:refs/tags/*" +git config --add remote.origin.push "+refs/heads/next:refs/heads/next" +git config --add remote.origin.push "+refs/heads/master:refs/heads/master" + ################################################################################ # Section 2: Debian packaging ################################################################################ @@ -164,6 +170,9 @@ done git commit -a -m "update docs for ${RELEASE_VERSION}" +git remote remove origin +git remote add origin git@github.com:i3/i3.github.io.git + ################################################################################ # Section 4: final push instructions ################################################################################ @@ -174,14 +183,10 @@ echo "When satisfied, run:" echo " cd ${TMPDIR}/i3" echo " git checkout next" echo " vi debian/changelog" -# TODO: can we just set up the remote spec properly? -echo " git push git@github.com:i3/i3 next" -echo " git push git@github.com:i3/i3 master" -echo " git push git@github.com:i3/i3 --tags" +echo " git push" echo "" echo " cd ${TMPDIR}/i3.github.io" -# TODO: can we just set up the remote spec properly? -echo " git push git@github.com:i3/i3.github.io master" +echo " git push" echo "" echo " cd ${TMPDIR}/debian" echo " dput *.changes" From 3163ca33853c3b92ecec973a00e80377005bcf6d Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 29 Mar 2015 19:34:33 +0200 Subject: [PATCH 010/243] release.sh: add release announcement email to avoid mistakes --- release.sh | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/release.sh b/release.sh index 3c7ddd85..631ff425 100755 --- a/release.sh +++ b/release.sh @@ -174,7 +174,23 @@ git remote remove origin git remote add origin git@github.com:i3/i3.github.io.git ################################################################################ -# Section 4: final push instructions +# Section 4: prepare release announcement email +################################################################################ + +cd ${TMPDIR} +cat >email.txt < +To: i3-announce@i3.zekjur.net +Subject: i3 v${RELEASE_VERSION} released + +Hi, + +I just released i3 v${RELEASE_VERSION}. Release notes follow: +EOT +cat ${TMPDIR}/i3/RELEASE-NOTES-${RELEASE_VERSION}.txt >>email.txt + +################################################################################ +# Section 5: final push instructions ################################################################################ echo "As a final sanity check, install the debian package and see whether i3 works." @@ -191,6 +207,9 @@ echo "" echo " cd ${TMPDIR}/debian" echo " dput *.changes" echo "" +echo " cd ${TMPDIR}" +echo " sendmail < email.txt" +echo "" echo "Announce on:" echo " twitter" echo " google+" From 4daed31c3e0bfb314f83050fe77a310eec11eb5a Mon Sep 17 00:00:00 2001 From: Deiz Date: Sat, 28 Mar 2015 14:30:35 -0400 Subject: [PATCH 011/243] Move resolve_tilde and get_config_path into libi3 --- i3-config-wizard/main.c | 32 --------------- include/libi3.h | 18 ++++++++ include/util.h | 8 ---- libi3/get_config_path.c | 91 +++++++++++++++++++++++++++++++++++++++++ libi3/resolve_tilde.c | 45 ++++++++++++++++++++ src/config.c | 74 +++------------------------------ src/util.c | 32 --------------- 7 files changed, 160 insertions(+), 140 deletions(-) create mode 100644 libi3/get_config_path.c create mode 100644 libi3/resolve_tilde.c diff --git a/i3-config-wizard/main.c b/i3-config-wizard/main.c index 35770dc9..673259b9 100644 --- a/i3-config-wizard/main.c +++ b/i3-config-wizard/main.c @@ -461,38 +461,6 @@ void errorlog(char *fmt, ...) { void debuglog(char *fmt, ...) { } -/* - * This function resolves ~ in pathnames. - * It may resolve wildcards in the first part of the path, but if no match - * or multiple matches are found, it just returns a copy of path as given. - * - */ -static char *resolve_tilde(const char *path) { - static glob_t globbuf; - char *head, *tail, *result; - - tail = strchr(path, '/'); - head = strndup(path, tail ? (size_t)(tail - path) : strlen(path)); - - int res = glob(head, GLOB_TILDE, NULL, &globbuf); - free(head); - /* no match, or many wildcard matches are bad */ - if (res == GLOB_NOMATCH || globbuf.gl_pathc != 1) - result = strdup(path); - else if (res != 0) { - err(1, "glob() failed"); - } else { - head = globbuf.gl_pathv[0]; - result = calloc(1, strlen(head) + (tail ? strlen(tail) : 0) + 1); - strncpy(result, head, strlen(head)); - if (tail) - strncat(result, tail, strlen(tail)); - } - globfree(&globbuf); - - return result; -} - /* * Handles expose events, that is, draws the window contents. * diff --git a/include/libi3.h b/include/libi3.h index 3a125827..82c46fce 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -434,3 +434,21 @@ char *get_exe_path(const char *argv0); * */ int logical_px(const int logical); + +/** + * This function resolves ~ in pathnames. + * It may resolve wildcards in the first part of the path, but if no match + * or multiple matches are found, it just returns a copy of path as given. + * + */ +char *resolve_tilde(const char *path); + +/** + * Get the path of the first configuration file found. If override_configpath + * is specified, that path is returned and saved for further calls. Otherwise, + * checks the home directory first, then the system directory first, always + * taking into account the XDG Base Directory Specification ($XDG_CONFIG_HOME, + * $XDG_CONFIG_DIRS) + * + */ +char *get_config_path(const char *override_configpath, bool use_system_paths); diff --git a/include/util.h b/include/util.h index dec68116..270b2f22 100644 --- a/include/util.h +++ b/include/util.h @@ -106,14 +106,6 @@ void exec_i3_utility(char *name, char *argv[]); void check_error(xcb_connection_t *conn, xcb_void_cookie_t cookie, char *err_message); -/** - * This function resolves ~ in pathnames. - * It may resolve wildcards in the first part of the path, but if no match - * or multiple matches are found, it just returns a copy of path as given. - * - */ -char *resolve_tilde(const char *path); - /** * Checks if the given path exists by calling stat(). * diff --git a/libi3/get_config_path.c b/libi3/get_config_path.c new file mode 100644 index 00000000..8b6eeb7c --- /dev/null +++ b/libi3/get_config_path.c @@ -0,0 +1,91 @@ +/* + * vim:ts=4:sw=4:expandtab + * + * i3 - an improved dynamic tiling window manager + * © 2009-2015 Michael Stapelberg and contributors (see also: LICENSE) + * + */ +#include "libi3.h" +#include +#include +#include + +/* + * Checks if the given path exists by calling stat(). + * + */ +static bool path_exists(const char *path) { + struct stat buf; + return (stat(path, &buf) == 0); +} + +/* + * Get the path of the first configuration file found. If override_configpath + * is specified, that path is returned and saved for further calls. Otherwise, + * checks the home directory first, then the system directory first, always + * taking into account the XDG Base Directory Specification ($XDG_CONFIG_HOME, + * $XDG_CONFIG_DIRS) + * + */ +char *get_config_path(const char *override_configpath, bool use_system_paths) { + char *xdg_config_home, *xdg_config_dirs, *config_path; + + static const char *saved_configpath = NULL; + + if (override_configpath != NULL) { + saved_configpath = override_configpath; + return sstrdup(saved_configpath); + } + + if (saved_configpath != NULL) + return sstrdup(saved_configpath); + + /* 1: check the traditional path under the home directory */ + config_path = resolve_tilde("~/.i3/config"); + if (path_exists(config_path)) + return config_path; + free(config_path); + + /* 2: check for $XDG_CONFIG_HOME/i3/config */ + if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL) + xdg_config_home = "~/.config"; + + xdg_config_home = resolve_tilde(xdg_config_home); + sasprintf(&config_path, "%s/i3/config", xdg_config_home); + free(xdg_config_home); + + if (path_exists(config_path)) + return config_path; + free(config_path); + + /* The below paths are considered system-level, and can be skipped if the + * caller only wants user-level configs. */ + if (!use_system_paths) + return NULL; + + /* 3: check the traditional path under /etc */ + config_path = SYSCONFDIR "/i3/config"; + if (path_exists(config_path)) + return sstrdup(config_path); + + /* 4: check for $XDG_CONFIG_DIRS/i3/config */ + if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL) + xdg_config_dirs = "/etc/xdg"; + + char *buf = sstrdup(xdg_config_dirs); + char *tok = strtok(buf, ":"); + while (tok != NULL) { + tok = resolve_tilde(tok); + sasprintf(&config_path, "%s/i3/config", tok); + free(tok); + if (path_exists(config_path)) { + free(buf); + return config_path; + } + free(config_path); + tok = strtok(NULL, ":"); + } + free(buf); + + return NULL; +} diff --git a/libi3/resolve_tilde.c b/libi3/resolve_tilde.c new file mode 100644 index 00000000..a4e82873 --- /dev/null +++ b/libi3/resolve_tilde.c @@ -0,0 +1,45 @@ +/* + * vim:ts=4:sw=4:expandtab + * + * i3 - an improved dynamic tiling window manager + * © 2009-2015 Michael Stapelberg and contributors (see also: LICENSE) + * + */ + +#include "libi3.h" +#include +#include +#include +#include + +/* + * This function resolves ~ in pathnames. + * It may resolve wildcards in the first part of the path, but if no match + * or multiple matches are found, it just returns a copy of path as given. + * + */ +char *resolve_tilde(const char *path) { + static glob_t globbuf; + char *head, *tail, *result; + + tail = strchr(path, '/'); + head = strndup(path, tail ? (size_t)(tail - path) : strlen(path)); + + int res = glob(head, GLOB_TILDE, NULL, &globbuf); + free(head); + /* no match, or many wildcard matches are bad */ + if (res == GLOB_NOMATCH || globbuf.gl_pathc != 1) + result = sstrdup(path); + else if (res != 0) { + err(EXIT_FAILURE, "glob() failed"); + } else { + head = globbuf.gl_pathv[0]; + result = scalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1); + strncpy(result, head, strlen(head)); + if (tail) + strncat(result, tail, strlen(tail)); + } + globfree(&globbuf); + + return result; +} diff --git a/src/config.c b/src/config.c index 6f906b8c..36b7a163 100644 --- a/src/config.c +++ b/src/config.c @@ -39,73 +39,6 @@ void update_barconfig() { } } -/* - * Get the path of the first configuration file found. If override_configpath - * is specified, that path is returned and saved for further calls. Otherwise, - * checks the home directory first, then the system directory first, always - * taking into account the XDG Base Directory Specification ($XDG_CONFIG_HOME, - * $XDG_CONFIG_DIRS) - * - */ -static char *get_config_path(const char *override_configpath) { - char *xdg_config_home, *xdg_config_dirs, *config_path; - - static const char *saved_configpath = NULL; - - if (override_configpath != NULL) { - saved_configpath = override_configpath; - return sstrdup(saved_configpath); - } - - if (saved_configpath != NULL) - return sstrdup(saved_configpath); - - /* 1: check the traditional path under the home directory */ - config_path = resolve_tilde("~/.i3/config"); - if (path_exists(config_path)) - return config_path; - free(config_path); - - /* 2: check for $XDG_CONFIG_HOME/i3/config */ - if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL) - xdg_config_home = "~/.config"; - - xdg_config_home = resolve_tilde(xdg_config_home); - sasprintf(&config_path, "%s/i3/config", xdg_config_home); - free(xdg_config_home); - - if (path_exists(config_path)) - return config_path; - free(config_path); - - /* 3: check the traditional path under /etc */ - config_path = SYSCONFDIR "/i3/config"; - if (path_exists(config_path)) - return sstrdup(config_path); - - /* 4: check for $XDG_CONFIG_DIRS/i3/config */ - if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL) - xdg_config_dirs = "/etc/xdg"; - - char *buf = sstrdup(xdg_config_dirs); - char *tok = strtok(buf, ":"); - while (tok != NULL) { - tok = resolve_tilde(tok); - sasprintf(&config_path, "%s/i3/config", tok); - free(tok); - if (path_exists(config_path)) { - free(buf); - return config_path; - } - free(config_path); - tok = strtok(NULL, ":"); - } - free(buf); - - die("Unable to find the configuration file (looked at " - "~/.i3/config, $XDG_CONFIG_HOME/i3/config, " SYSCONFDIR "/i3/config and $XDG_CONFIG_DIRS/i3/config)"); -} - /* * Finds the configuration file to use (either the one specified by * override_configpath), the user’s one or the system default) and calls @@ -113,7 +46,12 @@ static char *get_config_path(const char *override_configpath) { * */ bool parse_configuration(const char *override_configpath, bool use_nagbar) { - char *path = get_config_path(override_configpath); + char *path = get_config_path(override_configpath, true); + if (path == NULL) { + die("Unable to find the configuration file (looked at " + "~/.i3/config, $XDG_CONFIG_HOME/i3/config, " SYSCONFDIR "/i3/config and $XDG_CONFIG_DIRS/i3/config)"); + } + LOG("Parsing configfile %s\n", path); FREE(current_configpath); current_configpath = path; diff --git a/src/util.c b/src/util.c index 5760ae72..c891a6bc 100644 --- a/src/util.c +++ b/src/util.c @@ -159,38 +159,6 @@ void check_error(xcb_connection_t *conn, xcb_void_cookie_t cookie, char *err_mes } } -/* - * This function resolves ~ in pathnames. - * It may resolve wildcards in the first part of the path, but if no match - * or multiple matches are found, it just returns a copy of path as given. - * - */ -char *resolve_tilde(const char *path) { - static glob_t globbuf; - char *head, *tail, *result; - - tail = strchr(path, '/'); - head = strndup(path, tail ? (size_t)(tail - path) : strlen(path)); - - int res = glob(head, GLOB_TILDE, NULL, &globbuf); - free(head); - /* no match, or many wildcard matches are bad */ - if (res == GLOB_NOMATCH || globbuf.gl_pathc != 1) - result = sstrdup(path); - else if (res != 0) { - die("glob() failed"); - } else { - head = globbuf.gl_pathv[0]; - result = scalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1); - strncpy(result, head, strlen(head)); - if (tail) - strncat(result, tail, strlen(tail)); - } - globfree(&globbuf); - - return result; -} - /* * Checks if the given path exists by calling stat(). * From dfefb10d367312db1c60a0a29c251e170cd0a93e Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 29 Mar 2015 20:57:20 +0200 Subject: [PATCH 012/243] initialize variables to NULL to avoid invalid free() on error --- i3-nagbar/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i3-nagbar/main.c b/i3-nagbar/main.c index eacdca19..83389b34 100644 --- a/i3-nagbar/main.c +++ b/i3-nagbar/main.c @@ -300,8 +300,8 @@ static xcb_rectangle_t get_window_position(void) { xcb_randr_get_screen_resources_current_cookie_t rcookie = xcb_randr_get_screen_resources_current(conn, root); xcb_randr_get_output_primary_cookie_t pcookie = xcb_randr_get_output_primary(conn, root); - xcb_randr_get_output_primary_reply_t *primary; - xcb_randr_get_screen_resources_current_reply_t *res; + xcb_randr_get_output_primary_reply_t *primary = NULL; + xcb_randr_get_screen_resources_current_reply_t *res = NULL; if ((primary = xcb_randr_get_output_primary_reply(conn, pcookie, NULL)) == NULL) { DLOG("Could not determine the primary output.\n"); From d51d6d730eb9e832e56ca1558b1a945dbf88869f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sat, 28 Mar 2015 19:12:25 +0100 Subject: [PATCH 013/243] Added a --toggle switch to "mark [--toggle] " This option allows toggling marks on a window without knowing whether the mark is already set or not. It behaves as follows: 1) If the matched window has no mark, the new mark is set. 2) If the matched window has another mark, the old mark is removed and the new mark is set. 3) If the matched window already has the mark, the mark is removed. The behavior that all non-matched windows have this mark removed is kept. fixes #1463 --- include/commands.h | 4 ++-- parser-specs/commands.spec | 6 ++++-- src/commands.c | 42 +++++++++++++++++++++++++------------- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/include/commands.h b/include/commands.h index 780a9e8e..0f7e3635 100644 --- a/include/commands.h +++ b/include/commands.h @@ -109,10 +109,10 @@ void cmd_workspace_back_and_forth(I3_CMD); void cmd_workspace_name(I3_CMD, char *name); /** - * Implementation of 'mark ' + * Implementation of 'mark [--toggle] ' * */ -void cmd_mark(I3_CMD, char *mark); +void cmd_mark(I3_CMD, char *mark, char *toggle); /** * Implementation of 'unmark [mark]' diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec index 315a9218..87db6cf0 100644 --- a/parser-specs/commands.spec +++ b/parser-specs/commands.spec @@ -189,10 +189,12 @@ state FLOATING: floating = 'enable', 'disable', 'toggle' -> call cmd_floating($floating) -# mark +# mark [--toggle] state MARK: + toggle = '--toggle' + -> mark = string - -> call cmd_mark($mark) + -> call cmd_mark($mark, $toggle) # unmark [mark] state UNMARK: diff --git a/src/commands.c b/src/commands.c index 9b51b3ec..46c75c43 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1037,26 +1037,40 @@ void cmd_workspace_name(I3_CMD, char *name) { } /* - * Implementation of 'mark ' + * Implementation of 'mark [--toggle] ' * */ -void cmd_mark(I3_CMD, char *mark) { - DLOG("Clearing all windows which have that mark first\n"); - - Con *con; - TAILQ_FOREACH(con, &all_cons, all_cons) { - if (con->mark && strcmp(con->mark, mark) == 0) - FREE(con->mark); - } - - DLOG("marking window with str %s\n", mark); - owindow *current; - +void cmd_mark(I3_CMD, char *mark, char *toggle) { HANDLE_EMPTY_MATCH; + owindow *current; TAILQ_FOREACH(current, &owindows, owindows) { DLOG("matching: %p / %s\n", current->con, current->con->name); - current->con->mark = sstrdup(mark); + if (toggle != NULL && current->con->mark && strcmp(current->con->mark, mark) == 0) { + DLOG("removing window mark %s\n", mark); + FREE(current->con->mark); + } else { + DLOG("marking window with str %s\n", mark); + FREE(current->con->mark); + current->con->mark = sstrdup(mark); + } + } + + DLOG("Clearing all non-matched windows with this mark\n"); + Con *con; + TAILQ_FOREACH(con, &all_cons, all_cons) { + /* Skip matched windows, we took care of them already. */ + bool matched = false; + TAILQ_FOREACH(current, &owindows, owindows) + if (current->con == con) { + matched = true; + break; + } + if (matched) + continue; + + if (con->mark && strcmp(con->mark, mark) == 0) + FREE(con->mark); } cmd_output->needs_tree_render = true; From 47222ab2610db8cec9f6549ff00823effd47c008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sat, 28 Mar 2015 19:12:31 +0100 Subject: [PATCH 014/243] Updated docs for #1463 --- docs/userguide | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/userguide b/docs/userguide index 3d935e40..d6dbde00 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1857,9 +1857,13 @@ window, you cannot simply bind it to a key. +i3-input+ is a tool created for this purpose: It lets you input a command and sends the command to i3. It can also prefix this command and display a custom prompt for the input dialog. +The additional +--toggle+ option will remove the mark if the window already has +this mark, add it if the window has none or replace the current mark if it has +another mark. + *Syntax*: ------------------------------ -mark identifier +mark [--toggle] identifier [con_mark="identifier"] focus unmark identifier ------------------------------ From 7a75cb7e0ba20f373e9340f6c75ad873fa4b75fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sat, 28 Mar 2015 23:14:59 +0100 Subject: [PATCH 015/243] Added test cases for 'mark --toggle' (#1463) --- src/commands.c | 9 ++--- testcases/t/210-mark-unmark.t | 65 +++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/commands.c b/src/commands.c index 46c75c43..ea0b9032 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1061,10 +1061,11 @@ void cmd_mark(I3_CMD, char *mark, char *toggle) { TAILQ_FOREACH(con, &all_cons, all_cons) { /* Skip matched windows, we took care of them already. */ bool matched = false; - TAILQ_FOREACH(current, &owindows, owindows) - if (current->con == con) { - matched = true; - break; + TAILQ_FOREACH(current, &owindows, owindows) { + if (current->con == con) { + matched = true; + break; + } } if (matched) continue; diff --git a/testcases/t/210-mark-unmark.t b/testcases/t/210-mark-unmark.t index f285338b..0083547f 100644 --- a/testcases/t/210-mark-unmark.t +++ b/testcases/t/210-mark-unmark.t @@ -16,11 +16,19 @@ # # checks if mark and unmark work correctly use i3test; +use List::Util qw(first); sub get_marks { return i3(get_socket_path())->get_marks->recv; } +sub get_mark_for_window_on_workspace { + my ($ws, $con) = @_; + + my $current = first { $_->{window} == $con->{id} } @{get_ws_content($ws)}; + return $current->{mark}; +} + ############################################################## # 1: check that there are no marks set yet ############################################################## @@ -76,4 +84,61 @@ cmd 'unmark'; is_deeply(get_marks(), [], 'all marks removed'); +############################################################## +# 4: mark a con, use same mark to mark another con, +# check that only the latter is marked +############################################################## + +my $first = open_window; +my $second = open_window; + +cmd 'mark important'; +cmd 'focus left'; +cmd 'mark important'; + +is(get_mark_for_window_on_workspace($tmp, $first), 'important', 'first container now has the mark'); +ok(!get_mark_for_window_on_workspace($tmp, $second), 'second container lost the mark'); + +############################################################## +# 5: mark a con, toggle the mark, check that the mark is gone +############################################################## + +my $con = open_window; +cmd 'mark important'; +cmd 'mark --toggle important'; +ok(!get_mark_for_window_on_workspace($tmp, $con), 'container no longer has the mark'); + +############################################################## +# 6: toggle a mark on an unmarked con, check it is marked +############################################################## + +my $con = open_window; +cmd 'mark --toggle important'; +is(get_mark_for_window_on_workspace($tmp, $con), 'important', 'container now has the mark'); + +############################################################## +# 7: mark a con, toggle a different mark, check it is marked +# with the new mark +############################################################## + +my $con = open_window; +cmd 'mark boring'; +cmd 'mark --toggle important'; +is(get_mark_for_window_on_workspace($tmp, $con), 'important', 'container has the most recent mark'); + +############################################################## +# 8: mark a con, toggle the mark on another con, +# check only the latter has the mark +############################################################## + +my $first = open_window; +my $second = open_window; + +cmd 'mark important'; +cmd 'focus left'; +cmd 'mark --toggle important'; + +is(get_mark_for_window_on_workspace($tmp, $first), 'important', 'left container has the mark now'); +ok(!get_mark_for_window_on_workspace($tmp, $second), 'second containr no longer has the mark'); + done_testing; From e622c42ef087e50bbf9666b794b9601788029873 Mon Sep 17 00:00:00 2001 From: Deiz Date: Sun, 29 Mar 2015 17:18:00 -0400 Subject: [PATCH 016/243] Move mkdirp into libi3 --- include/ipc.h | 6 ------ include/libi3.h | 6 ++++++ libi3/mkdirp.c | 38 ++++++++++++++++++++++++++++++++++++++ src/ipc.c | 30 ------------------------------ 4 files changed, 44 insertions(+), 36 deletions(-) create mode 100644 libi3/mkdirp.c diff --git a/include/ipc.h b/include/ipc.h index 96a60a1f..4eed319a 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -50,12 +50,6 @@ typedef void (*handler_t)(int, uint8_t *, int, uint32_t, uint32_t); int size, uint32_t message_size, \ uint32_t message_type) -/** - * Emulates mkdir -p (creates any missing folders) - * - */ -bool mkdirp(const char *path); - /** * Handler for activity on the listening socket, meaning that a new client * has just connected and we should accept() him. Sets up the event handler diff --git a/include/libi3.h b/include/libi3.h index 82c46fce..da8c8a42 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -452,3 +452,9 @@ char *resolve_tilde(const char *path); * */ char *get_config_path(const char *override_configpath, bool use_system_paths); + +/** + * Emulates mkdir -p (creates any missing folders) + * + */ +bool mkdirp(const char *path); diff --git a/libi3/mkdirp.c b/libi3/mkdirp.c new file mode 100644 index 00000000..a0d35f96 --- /dev/null +++ b/libi3/mkdirp.c @@ -0,0 +1,38 @@ +#include "libi3.h" +#include +#include +#include +#include + +/* + * Emulates mkdir -p (creates any missing folders) + * + */ +bool mkdirp(const char *path) { + if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0) + return true; + if (errno != ENOENT) { + ELOG("mkdir(%s) failed: %s\n", path, strerror(errno)); + return false; + } + char *copy = sstrdup(path); + /* strip trailing slashes, if any */ + while (copy[strlen(copy) - 1] == '/') + copy[strlen(copy) - 1] = '\0'; + + char *sep = strrchr(copy, '/'); + if (sep == NULL) { + if (copy != NULL) { + free(copy); + copy = NULL; + } + return false; + } + *sep = '\0'; + bool result = false; + if (mkdirp(copy)) + result = mkdirp(path); + free(copy); + + return result; +} diff --git a/src/ipc.c b/src/ipc.c index 52f7db2e..8fed75f1 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -37,36 +37,6 @@ static void set_nonblock(int sockfd) { err(-1, "Could not set O_NONBLOCK"); } -/* - * Emulates mkdir -p (creates any missing folders) - * - */ -bool mkdirp(const char *path) { - if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0) - return true; - if (errno != ENOENT) { - ELOG("mkdir(%s) failed: %s\n", path, strerror(errno)); - return false; - } - char *copy = sstrdup(path); - /* strip trailing slashes, if any */ - while (copy[strlen(copy) - 1] == '/') - copy[strlen(copy) - 1] = '\0'; - - char *sep = strrchr(copy, '/'); - if (sep == NULL) { - FREE(copy); - return false; - } - *sep = '\0'; - bool result = false; - if (mkdirp(copy)) - result = mkdirp(path); - free(copy); - - return result; -} - /* * Sends the specified event to all IPC clients which are currently connected * and subscribed to this kind of event. From 9b8c2b1d1a1af95dc010bb9f2e4c8d5a7c1ac208 Mon Sep 17 00:00:00 2001 From: Deiz Date: Wed, 25 Mar 2015 21:00:18 -0400 Subject: [PATCH 017/243] Respect XDG config directories in i3-config-wizard $XDG_CONFIG_HOME is used for the config's write path, and the wizard terminates if a config is found in ~/.i3 or $XDG_CONFIG_HOME/i3 --- i3-config-wizard/main.c | 47 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/i3-config-wizard/main.c b/i3-config-wizard/main.c index 673259b9..9c9241cd 100644 --- a/i3-config-wizard/main.c +++ b/i3-config-wizard/main.c @@ -482,17 +482,23 @@ static int handle_expose() { set_font_colors(pixmap_gc, get_colorpixel("#FFFFFF"), get_colorpixel("#000000")); txt(logical_px(10), 2, "You have not configured i3 yet."); - txt(logical_px(10), 3, "Do you want me to generate ~/.i3/config?"); - txt(logical_px(85), 5, "Yes, generate ~/.i3/config"); - txt(logical_px(85), 7, "No, I will use the defaults"); + txt(logical_px(10), 3, "Do you want me to generate a config at"); + + char *msg; + sasprintf(&msg, "%s?", config_path); + txt(logical_px(10), 4, msg); + free(msg); + + txt(logical_px(85), 6, "Yes, generate the config"); + txt(logical_px(85), 8, "No, I will use the defaults"); /* green */ set_font_colors(pixmap_gc, get_colorpixel("#00FF00"), get_colorpixel("#000000")); - txt(logical_px(25), 5, ""); + txt(logical_px(25), 6, ""); /* red */ set_font_colors(pixmap_gc, get_colorpixel("#FF0000"), get_colorpixel("#000000")); - txt(logical_px(31), 7, ""); + txt(logical_px(31), 8, ""); } if (current_step == STEP_GENERATE) { @@ -502,7 +508,7 @@ static int handle_expose() { txt(logical_px(85), 4, "Win as default modifier"); txt(logical_px(85), 5, "Alt as default modifier"); txt(logical_px(10), 7, "Afterwards, press"); - txt(logical_px(85), 9, "to write ~/.i3/config"); + txt(logical_px(85), 9, "to write the config"); txt(logical_px(85), 10, "to abort"); /* the not-selected modifier */ @@ -740,7 +746,7 @@ static void finish() { } int main(int argc, char *argv[]) { - config_path = resolve_tilde("~/.i3/config"); + char *xdg_config_home; socket_path = getenv("I3SOCK"); char *pattern = "pango:monospace 8"; char *patternbold = "pango:monospace bold 8"; @@ -774,20 +780,29 @@ int main(int argc, char *argv[]) { } } - /* Check if the destination config file does not exist but the path is - * writable. If not, exit now, this program is not useful in that case. */ - struct stat stbuf; - if (stat(config_path, &stbuf) == 0) { - printf("The config file \"%s\" already exists. Exiting.\n", config_path); + char *path = get_config_path(NULL, false); + if (path != NULL) { + printf("The config file \"%s\" already exists. Exiting.\n", path); + free(path); return 0; } - /* Create ~/.i3 if it does not yet exist */ - char *config_dir = resolve_tilde("~/.i3"); + /* Always write to $XDG_CONFIG_HOME/i3/config by default. */ + if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL) + xdg_config_home = "~/.config"; + + xdg_config_home = resolve_tilde(xdg_config_home); + sasprintf(&config_path, "%s/i3/config", xdg_config_home); + + /* Create $XDG_CONFIG_HOME/i3 if it does not yet exist */ + char *config_dir; + struct stat stbuf; + sasprintf(&config_dir, "%s/i3", xdg_config_home); if (stat(config_dir, &stbuf) != 0) - if (mkdir(config_dir, 0755) == -1) - err(1, "mkdir(%s) failed", config_dir); + if (!mkdirp(config_dir)) + err(EXIT_FAILURE, "mkdirp(%s) failed", config_dir); free(config_dir); + free(xdg_config_home); int fd; if ((fd = open(config_path, O_CREAT | O_RDWR, 0644)) == -1) { From 54dc87fb83bdfbc8d09bfab039cc0b5a72fa8f04 Mon Sep 17 00:00:00 2001 From: Michael Hofmann Date: Mon, 30 Mar 2015 08:22:03 +0200 Subject: [PATCH 018/243] Testcase for #1607. - crash in startup_sequence_rename_workspace because of NULL old_name --- testcases/t/175-startup-notification.t | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/testcases/t/175-startup-notification.t b/testcases/t/175-startup-notification.t index 4ca41799..b27bed53 100644 --- a/testcases/t/175-startup-notification.t +++ b/testcases/t/175-startup-notification.t @@ -155,6 +155,11 @@ cmd "rename workspace temp to $first_ws"; is_num_children($first_ws, 3, 'three containers on the first workspace'); +# empty 'from' workspaces should not crash the renaming of startup sequences +cmd "workspace $first_ws"; +cmd "rename workspace to temp"; +cmd "rename workspace to $first_ws"; + # Switch to the first workspace and move the focused window to the # second workspace. cmd "workspace $first_ws"; From f76e6c2bb1ea4a29429f009758b85185e2989464 Mon Sep 17 00:00:00 2001 From: Michael Hofmann Date: Mon, 30 Mar 2015 08:23:00 +0200 Subject: [PATCH 019/243] Get workspace name when renaming current workspace. - fixes #1607 --- src/commands.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands.c b/src/commands.c index ea0b9032..589c49ad 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1851,6 +1851,7 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) { !strcasecmp(child->name, old_name)); } else { workspace = con_get_workspace(focused); + old_name = workspace->name; } if (!workspace) { From e6267a684cb41e34ee929809683748c3675ca630 Mon Sep 17 00:00:00 2001 From: Michael Hofmann Date: Sun, 29 Mar 2015 18:52:03 +0200 Subject: [PATCH 020/243] Testcase for non-null-terminated WM_CLASS. - fails most of the time --- testcases/t/235-wm-class-change-handler.t | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/testcases/t/235-wm-class-change-handler.t b/testcases/t/235-wm-class-change-handler.t index e6cacded..3685b30c 100644 --- a/testcases/t/235-wm-class-change-handler.t +++ b/testcases/t/235-wm-class-change-handler.t @@ -31,16 +31,17 @@ EOT my $pid = launch_with_config($config); sub change_window_class { - my ($window, $class) = @_; + my ($window, $class, $length) = @_; my $atomname = $x->atom(name => 'WM_CLASS'); my $atomtype = $x->atom(name => 'STRING'); + $length ||= length($class) + 1; $x->change_property( PROP_MODE_REPLACE, $window->id, $atomname->id, $atomtype->id, 8, - length($class) + 1, + $length, $class ); sync_with_i3; @@ -65,6 +66,13 @@ is($con->{window_properties}->{instance}, 'special', is($con->{mark}, 'special_class_mark', 'A `for_window` assignment should run for a match when the window changes class'); +change_window_class($win, "abcdefghijklmnopqrstuv\0abcd", 24); + +$con = @{get_ws_content($ws)}[0]; + +is($con->{window_properties}->{class}, 'a', + 'Non-null-terminated strings should be handled correctly'); + exit_gracefully($pid); done_testing; From eb84281f8c0dbf945f8cf99bfe527340dc154ea1 Mon Sep 17 00:00:00 2001 From: Michael Hofmann Date: Sun, 29 Mar 2015 15:15:12 +0200 Subject: [PATCH 021/243] Cope with non-null-terminated x class properties. - fixes #1605 --- src/window.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/window.c b/src/window.c index ace109e3..5485bcc3 100644 --- a/src/window.c +++ b/src/window.c @@ -26,13 +26,16 @@ void window_update_class(i3Window *win, xcb_get_property_reply_t *prop, bool bef /* We cannot use asprintf here since this property contains two * null-terminated strings (for compatibility reasons). Instead, we * use strdup() on both strings */ - char *new_class = xcb_get_property_value(prop); + const size_t prop_length = xcb_get_property_value_length(prop); + char *new_class = smalloc(prop_length + 1); + memcpy(new_class, xcb_get_property_value(prop), prop_length); + new_class[prop_length] = '\0'; FREE(win->class_instance); FREE(win->class_class); win->class_instance = sstrdup(new_class); - if ((strlen(new_class) + 1) < (size_t)xcb_get_property_value_length(prop)) + if ((strlen(new_class) + 1) < prop_length) win->class_class = sstrdup(new_class + strlen(new_class) + 1); else win->class_class = NULL; @@ -40,12 +43,14 @@ void window_update_class(i3Window *win, xcb_get_property_reply_t *prop, bool bef win->class_instance, win->class_class); if (before_mgmt) { + free(new_class); free(prop); return; } run_assignments(win); + free(new_class); free(prop); } From e3ad16e65f13ea02e764d761b376c82925bc9882 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 30 Mar 2015 11:04:45 -0400 Subject: [PATCH 022/243] complete-run: fix pod errors Close `=over` with `=back` and use ascii apostrophe for "don't" to avoid pod errors on `complete-run` docs. --- testcases/complete-run.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testcases/complete-run.pl b/testcases/complete-run.pl index eaf57bde..9710017d 100755 --- a/testcases/complete-run.pl +++ b/testcases/complete-run.pl @@ -395,8 +395,10 @@ Exits i3 cleanly (instead of kill -9) to make coverage testing work properly. =item B<--parallel> -Number of Xephyr instances to start (if you don’t want to start num_cores * 2 +Number of Xephyr instances to start (if you don't want to start num_cores * 2 instances for some reason). # Run all tests on a single Xephyr instance ./complete-run.pl -p 1 + +=back From c6581a5fd650a94b3d3228f53fa6975801ff5d1e Mon Sep 17 00:00:00 2001 From: Deiz Date: Mon, 30 Mar 2015 03:10:40 -0400 Subject: [PATCH 023/243] Handle floating centering in one function and test for consistency --- include/floating.h | 6 ++ src/commands.c | 13 +--- src/floating.c | 18 +++-- src/scratchpad.c | 5 +- testcases/t/241-consistent-center.t | 106 ++++++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 20 deletions(-) create mode 100644 testcases/t/241-consistent-center.t diff --git a/include/floating.h b/include/floating.h index bea5f7a2..8330b6ac 100644 --- a/include/floating.h +++ b/include/floating.h @@ -64,6 +64,12 @@ void floating_raise_con(Con *con); */ bool floating_maybe_reassign_ws(Con *con); +/** + * Centers a floating con above the specified rect. + * + */ +void floating_center(Con *con, Rect rect); + #if 0 /** * Removes the floating client from its workspace and attaches it to the new diff --git a/src/commands.c b/src/commands.c index 2c709aef..2aa1f537 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1761,25 +1761,18 @@ void cmd_move_window_to_center(I3_CMD, char *method) { } if (strcmp(method, "absolute") == 0) { - Rect *rect = &focused->parent->rect; - DLOG("moving to absolute center\n"); - rect->x = croot->rect.width / 2 - rect->width / 2; - rect->y = croot->rect.height / 2 - rect->height / 2; + floating_center(focused->parent, croot->rect); floating_maybe_reassign_ws(focused->parent); cmd_output->needs_tree_render = true; } if (strcmp(method, "position") == 0) { - Rect *wsrect = &con_get_workspace(focused)->rect; - Rect newrect = focused->parent->rect; - DLOG("moving to center\n"); - newrect.x = wsrect->x + wsrect->width / 2 - newrect.width / 2; - newrect.y = wsrect->y + wsrect->height / 2 - newrect.height / 2; + floating_center(focused->parent, con_get_workspace(focused)->rect); - floating_reposition(focused->parent, newrect); + cmd_output->needs_tree_render = true; } // XXX: default reply for now, make this a better reply diff --git a/src/floating.c b/src/floating.c index e6ca2d71..d01cb43d 100644 --- a/src/floating.c +++ b/src/floating.c @@ -246,12 +246,10 @@ void floating_enable(Con *con, bool automatic) { if (con->window && con->window->leader != XCB_NONE && (leader = con_by_window_id(con->window->leader)) != NULL) { DLOG("Centering above leader\n"); - nc->rect.x = leader->rect.x + (leader->rect.width / 2) - (nc->rect.width / 2); - nc->rect.y = leader->rect.y + (leader->rect.height / 2) - (nc->rect.height / 2); + floating_center(nc, leader->rect); } else { /* center the window on workspace as fallback */ - nc->rect.x = ws->rect.x + (ws->rect.width / 2) - (nc->rect.width / 2); - nc->rect.y = ws->rect.y + (ws->rect.height / 2) - (nc->rect.height / 2); + floating_center(nc, ws->rect); } } @@ -310,8 +308,7 @@ void floating_enable(Con *con, bool automatic) { } ELOG("No output found at destination coordinates, centering floating window on current ws\n"); - nc->rect.x = ws->rect.x + (ws->rect.width / 2) - (nc->rect.width / 2); - nc->rect.y = ws->rect.y + (ws->rect.height / 2) - (nc->rect.height / 2); + floating_center(nc, ws->rect); ipc_send_window_event("floating", con); } @@ -420,6 +417,15 @@ bool floating_maybe_reassign_ws(Con *con) { return true; } +/* + * Centers a floating con above the specified rect. + * + */ +void floating_center(Con *con, Rect rect) { + con->rect.x = rect.x + (rect.width / 2) - (con->rect.width / 2); + con->rect.y = rect.y + (rect.height / 2) - (con->rect.height / 2); +} + DRAGGING_CB(drag_window_callback) { const struct xcb_button_press_event_t *event = extra; diff --git a/src/scratchpad.c b/src/scratchpad.c index 3b7c2a72..75b8e56c 100644 --- a/src/scratchpad.c +++ b/src/scratchpad.c @@ -198,10 +198,7 @@ void scratchpad_show(Con *con) { con->rect.width = output->rect.width * 0.5; con->rect.height = output->rect.height * 0.75; floating_check_size(con); - con->rect.x = output->rect.x + - ((output->rect.width / 2.0) - (con->rect.width / 2.0)); - con->rect.y = output->rect.y + - ((output->rect.height / 2.0) - (con->rect.height / 2.0)); + floating_center(con, con_get_workspace(con)->rect); } /* Activate active workspace if window is from another workspace to ensure diff --git a/testcases/t/241-consistent-center.t b/testcases/t/241-consistent-center.t new file mode 100644 index 00000000..283d1731 --- /dev/null +++ b/testcases/t/241-consistent-center.t @@ -0,0 +1,106 @@ +#!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 that most of i3's centering methods produce consistent results. +# Decorations are disabled to avoid floating_enable's logic which shifts +# windows upwards dependent on their decoration height. +# +use i3test i3_autostart => 0; + +my $config = <rect; +is(int($initial->{x} + $initial->{width} / 2), int($x->root->rect->width / 2), + 'x coordinates match'); +is(int($initial->{y} + $initial->{height} / 2), int($x->root->rect->height / 2), + 'y coordinates match'); + +cmd 'move position center'; + +my $new = $first->rect; +is($initial->{x}, $new->{x}, 'x coordinates match'); +is($initial->{y}, $new->{y}, 'y coordinates match'); + +cmd 'move absolute position center'; + +$new = $first->rect; +is($initial->{x}, $new->{x}, 'x coordinates match'); +is($initial->{y}, $new->{y}, 'y coordinates match'); + +##################################################################### +# Create a second window and move it into and out of the scratchpad. +# Because it hasn't been moved or resized, it should be floated in +# the center of the screen when pulled out of the scratchpad. +##################################################################### + +my $second = open_window; + +cmd 'move scratchpad, scratchpad show'; + +$new = $second->rect; +my $mid_init = $initial->{x} + int($initial->{width} / 2); +my $mid_new = $new->{x} + int($new->{width} / 2); +is($mid_init, $mid_new, 'x midpoint is ws center'); + +$mid_init = $initial->{y} + int($initial->{height} / 2); +$mid_new = $new->{y} + int($new->{height} / 2); +is($mid_init, $mid_new, 'y midpoint is ws center'); + +##################################################################### +# Verify that manually floating a tiled window results in proper +# centering. +##################################################################### + +my $third = open_window; + +cmd 'floating enable'; + +$new = $third->rect; +is($initial->{x}, $new->{x}, 'x coordinates match'); +is($initial->{y}, $new->{y}, 'y coordinates match'); + +##################################################################### +# Create a child window of the previous window, which should result +# in the new window being centered over the last one. +##################################################################### + +my $fourth = open_window( dont_map => 1, client_leader => $third ); +$fourth->map; +sync_with_i3; + +my $child = $fourth->rect; +is($new->{x}, $child->{x}, 'x coordinates match'); +is($new->{y}, $child->{y}, 'y coordinates match'); + +exit_gracefully($pid); + +done_testing; From 9bf161710b20238d377e8f14c29539e8d7e16e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Mon, 30 Mar 2015 22:07:48 +0200 Subject: [PATCH 024/243] Added 'focus_on_window_activation' directive When a window receives a _NET_ACTIVE_WINDOW message, it can steal the focus. This may not be preferable to all users. With this directive, the user can choose from one of the following: 1) 'smart' - focus the container if its workspace is visible, otherwise set the urgency flag (default) 2) 'urgent' - always set the urgency flag, do not steal focus 3) 'focus' - always switch focus, never set the urgency hint 4) 'none' - ignore the request entirely (do not switch focus, nor set the urgency hint) fixes #1426 --- include/config.h | 12 ++++++++++++ include/config_directives.h | 1 + parser-specs/config.spec | 6 ++++++ src/config_directives.c | 17 +++++++++++++++++ src/handlers.c | 15 ++++++++------- testcases/t/201-config-parser.t | 2 +- 6 files changed, 45 insertions(+), 8 deletions(-) diff --git a/include/config.h b/include/config.h index 9a0af0e6..5b534fb7 100644 --- a/include/config.h +++ b/include/config.h @@ -167,6 +167,18 @@ struct Config { * flag can be delayed using an urgency timer. */ float workspace_urgency_timer; + /** Behavior when a window sends a NET_ACTIVE_WINDOW message. */ + enum { + /* Focus if the target workspace is visible, set urgency hint otherwise. */ + FOWA_SMART, + /* Always set the urgency hint. */ + FOWA_URGENT, + /* Always focus the window. */ + FOWA_FOCUS, + /* Ignore the request (no focus, no urgency hint). */ + FOWA_NONE + } focus_on_window_activation; + /** The default border style for new windows. */ border_style_t default_border; diff --git a/include/config_directives.h b/include/config_directives.h index 6c960b1f..8f99e648 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -51,6 +51,7 @@ CFGFUN(force_focus_wrapping, const char *value); CFGFUN(force_xinerama, const char *value); CFGFUN(fake_outputs, const char *outputs); CFGFUN(force_display_urgency_hint, const long duration_ms); +CFGFUN(focus_on_window_activation, const char *mode); CFGFUN(hide_edge_borders, const char *borders); CFGFUN(assign, const char *workspace); CFGFUN(ipc_socket, const char *path); diff --git a/parser-specs/config.spec b/parser-specs/config.spec index 25be5cf1..e23c37c8 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -38,6 +38,7 @@ state INITIAL: 'workspace_auto_back_and_forth' -> WORKSPACE_BACK_AND_FORTH 'fake_outputs', 'fake-outputs' -> FAKE_OUTPUTS 'force_display_urgency_hint' -> FORCE_DISPLAY_URGENCY_HINT + 'focus_on_window_activation' -> FOCUS_ON_WINDOW_ACTIVATION 'workspace' -> WORKSPACE 'ipc_socket', 'ipc-socket' -> IPC_SOCKET 'restart_state' -> RESTART_STATE @@ -210,6 +211,11 @@ state FORCE_DISPLAY_URGENCY_HINT_MS: end -> call cfg_force_display_urgency_hint(&duration_ms) +# focus_on_window_activation +state FOCUS_ON_WINDOW_ACTIVATION: + mode = word + -> call cfg_focus_on_window_activation($mode) + # workspace output state WORKSPACE: workspace = word diff --git a/src/config_directives.c b/src/config_directives.c index c8b25c76..039cb29e 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -329,6 +329,23 @@ CFGFUN(force_display_urgency_hint, const long duration_ms) { config.workspace_urgency_timer = duration_ms / 1000.0; } +CFGFUN(focus_on_window_activation, const char *mode) { + if (strcmp(mode, "smart") == 0) + config.focus_on_window_activation = FOWA_SMART; + else if (strcmp(mode, "urgent") == 0) + config.focus_on_window_activation = FOWA_URGENT; + else if (strcmp(mode, "focus") == 0) + config.focus_on_window_activation = FOWA_FOCUS; + else if (strcmp(mode, "none") == 0) + config.focus_on_window_activation = FOWA_NONE; + else { + ELOG("Unknown focus_on_window_activation mode \"%s\", ignoring it.\n", mode); + return; + } + + DLOG("Set new focus_on_window_activation mode = %i", config.focus_on_window_activation); +} + CFGFUN(workspace, const char *workspace, const char *output) { DLOG("Assigning workspace \"%s\" to output \"%s\"\n", workspace, output); /* Check for earlier assignments of the same workspace so that we diff --git a/src/handlers.c b/src/handlers.c index 041f7e36..c80c279e 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -743,16 +743,17 @@ static void handle_client_message(xcb_client_message_event_t *event) { workspace_show(ws); con_focus(con); } else { - /* If the request is from an application, only focus if the - * workspace is visible. Otherwise set the urgency hint. */ - if (workspace_is_visible(ws)) { - DLOG("Request to focus con on a visible workspace. Focusing con = %p\n", con); + /* Request is from an application. */ + + if (config.focus_on_window_activation == FOWA_FOCUS || (config.focus_on_window_activation == FOWA_SMART && workspace_is_visible(ws))) { + DLOG("Focusing con = %p\n", con); workspace_show(ws); con_focus(con); - } else { - DLOG("Request to focus con on a hidden workspace. Setting urgent con = %p\n", con); + } else if (config.focus_on_window_activation == FOWA_URGENT || (config.focus_on_window_activation == FOWA_SMART && !workspace_is_visible(ws))) { + DLOG("Marking con = %p urgent\n", con); con_set_urgency(con, true); - } + } else + DLOG("Ignoring request for con = %p", con); } tree_render(); diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 1e91d47f..a6b1fe0c 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -433,7 +433,7 @@ client.focused #4c7899 #285577 #ffffff #2e9ef4 EOT my $expected_all_tokens = <<'EOT'; -ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' +ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' EOT my $expected_end = <<'EOT'; From e28893876951f34ba1dc51292124079d1da697c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Mon, 30 Mar 2015 22:08:02 +0200 Subject: [PATCH 025/243] Added testcases for #1426 --- testcases/t/240-focus-on-window-activation.t | 206 +++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 testcases/t/240-focus-on-window-activation.t diff --git a/testcases/t/240-focus-on-window-activation.t b/testcases/t/240-focus-on-window-activation.t new file mode 100644 index 00000000..5f0b6e1c --- /dev/null +++ b/testcases/t/240-focus-on-window-activation.t @@ -0,0 +1,206 @@ +#!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) +# +# Tests for the focus_on_window_activation directive +# Ticket: #1426 +use i3test i3_autostart => 0; +use List::Util qw(first); + +sub send_net_active_window { + my ($id) = @_; + + my $msg = pack "CCSLLLLLLL", + X11::XCB::CLIENT_MESSAGE, # response_type + 32, # format + 0, # sequence + $id, # destination window + $x->atom(name => '_NET_ACTIVE_WINDOW')->id, + 0, # source + 0, 0, 0, 0; + + $x->send_event(0, $x->get_root_window(), X11::XCB::EVENT_MASK_SUBSTRUCTURE_REDIRECT, $msg); +} + +sub get_urgency_for_window_on_workspace { + my ($ws, $con) = @_; + + my $current = first { $_->{window} == $con->{id} } @{get_ws_content($ws)}; + return $current->{urgent}; +} + +##################################################################### +# 1: If mode is set to 'urgent' and the target workspace is visible, +# check that the urgent flag is set and focus is not lost. +##################################################################### + +my $config = <id); +sync_with_i3; + +is($x->input_focus, $second->id, 'second window is still focused'); +is(get_urgency_for_window_on_workspace($ws, $first), 1, 'first window is marked urgent'); + +exit_gracefully($pid); + +##################################################################### +# 2: If mode is set to 'urgent' and the target workspace is not +# visible, check that the urgent flag is set and focus is not lost. +##################################################################### + +my $config = <id); +sync_with_i3; + +is(focused_ws(), $ws2, 'second workspace is still focused'); +is($x->input_focus, $second->id, 'second window is still focused'); +is(get_urgency_for_window_on_workspace($ws1, $first), 1, 'first window is marked urgent'); + +exit_gracefully($pid); + +##################################################################### +# 3: If mode is set to 'focus' and the target workspace is visible, +# check that the focus is switched. +##################################################################### + +my $config = <id); +sync_with_i3; + +is($x->input_focus, $first->id, 'first window is now focused'); +ok(!get_urgency_for_window_on_workspace($ws, $first), 'first window is not marked urgent'); + +exit_gracefully($pid); + +##################################################################### +# 4: If mode is set to 'focus' and the target workspace is not +# visible, check that the focus switched. +##################################################################### + +my $config = <id); +sync_with_i3; + +is(focused_ws(), $ws1, 'first workspace is now focused'); +is($x->input_focus, $first->id, 'first window is now focused'); +ok(!get_urgency_for_window_on_workspace($ws1, $first), 'first window is not marked urgent'); + +exit_gracefully($pid); + +##################################################################### +# 5: If mode is set to 'none' and the target workspace is visible, +# check that nothing happens. +##################################################################### + +my $config = <id); +sync_with_i3; + +is($x->input_focus, $second->id, 'second window is still focused'); +ok(!get_urgency_for_window_on_workspace($ws, $first), 'first window is not marked urgent'); + +exit_gracefully($pid); + +##################################################################### +# 6: If mode is set to 'none' and the target workspace is not +# visible, check that nothing happens. +##################################################################### + +my $config = <id); +sync_with_i3; + +is(focused_ws(), $ws2, 'second workspace is still focused'); +is($x->input_focus, $second->id, 'second window is still focused'); +ok(!get_urgency_for_window_on_workspace($ws1, $first), 'first window is not marked urgent'); + +exit_gracefully($pid); + +done_testing; From 195acb4911e844f51ed2bcd2a1120a1c332a33da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Mon, 30 Mar 2015 22:05:51 +0200 Subject: [PATCH 026/243] Updated userguide for the directive focus_on_window_activation introduced in #1426. --- docs/userguide | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/userguide b/docs/userguide index d6dbde00..5eb48554 100644 --- a/docs/userguide +++ b/docs/userguide @@ -981,6 +981,31 @@ force_display_urgency_hint ms force_display_urgency_hint 500 ms --------------------------------- +=== Focus on window activation + +If a window is activated, e.g., via +google-chrome www.google.com+, it may request +to take focus. Since this may not preferable, different reactions can be configured. + +Note that this does not apply to any window that is opened, i.e., typically opening +an application will focus that window independent of this configuration. + +*Syntax*: +---------------------------------------------------- +focus_on_window_activation +---------------------------------------------------- + +The different modes will act as follows: + +smart:: + This is the default behavior. If the window requesting focus is on an active + workspace, it will receive the focus. Otherwise, the urgency hint will be set. +urgent:: + The window will always be marked urgent, but the focus will not be stolen. +focus:: + The window will always be focused and not be marked urgent. +none:: + The window will neither be focused, nor be marked urgent. + == Configuring i3bar The bar at the bottom of your monitor is drawn by a separate process called From 1e89a301d5b25a819e8fc5042cc38d497837dcd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 29 Mar 2015 00:09:10 +0100 Subject: [PATCH 027/243] Draw marks in window decoration If a window has a mark set, e.g., "example", it will be printed on the right side of the window decorations. The format is "[example]" and the name of the window is truncated if necessary. Marks starting with an underscore ("_") will be ignored. --- src/x.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/x.c b/src/x.c index 9dd09117..a3810942 100644 --- a/src/x.c +++ b/src/x.c @@ -531,10 +531,25 @@ void x_draw_decoration(Con *con) { //DLOG("indent_level = %d, indent_mult = %d\n", indent_level, indent_mult); int indent_px = (indent_level * 5) * indent_mult; + int mark_width = 0; + if (con->mark != NULL && (con->mark)[0] != '_') { + char *formatted_mark; + sasprintf(&formatted_mark, "[%s]", con->mark); + i3String *mark = i3string_from_utf8(formatted_mark); + FREE(formatted_mark); + mark_width = predict_text_width(mark) + logical_px(2); + + draw_text(mark, parent->pixmap, parent->pm_gc, + con->deco_rect.x + con->deco_rect.width - mark_width, + con->deco_rect.y + text_offset_y, mark_width - logical_px(2)); + + I3STRING_FREE(mark); + } + draw_text(win->name, parent->pixmap, parent->pm_gc, - con->deco_rect.x + 2 + indent_px, con->deco_rect.y + text_offset_y, - con->deco_rect.width - 2 - indent_px); + con->deco_rect.x + logical_px(2) + indent_px, con->deco_rect.y + text_offset_y, + con->deco_rect.width - logical_px(2) - indent_px - mark_width); after_title: /* Since we don’t clip the text at all, it might in some cases be painted From 2af1a800283b20b3fa0c5d0791ee1083fc9d207d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 29 Mar 2015 00:13:44 +0100 Subject: [PATCH 028/243] Introduce a cached boolean for changes to the mark of a window. This is necessary to correctly redraw window decorations when the mark of a window is added or removed. --- include/data.h | 2 ++ src/commands.c | 13 +++++++++++-- src/x.c | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/data.h b/include/data.h index cec571e9..d40ed292 100644 --- a/include/data.h +++ b/include/data.h @@ -543,6 +543,8 @@ struct Con { /* user-definable mark to jump to this container later */ char *mark; + /* cached to decide whether a redraw is needed */ + bool mark_changed; double percent; diff --git a/src/commands.c b/src/commands.c index 2aa1f537..6c24e24d 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1046,6 +1046,7 @@ void cmd_mark(I3_CMD, char *mark, char *toggle) { owindow *current; TAILQ_FOREACH(current, &owindows, owindows) { DLOG("matching: %p / %s\n", current->con, current->con->name); + current->con->mark_changed=true; if (toggle != NULL && current->con->mark && strcmp(current->con->mark, mark) == 0) { DLOG("removing window mark %s\n", mark); FREE(current->con->mark); @@ -1070,8 +1071,10 @@ void cmd_mark(I3_CMD, char *mark, char *toggle) { if (matched) continue; - if (con->mark && strcmp(con->mark, mark) == 0) + if (con->mark && strcmp(con->mark, mark) == 0) { FREE(con->mark); + con->mark_changed = true; + } } cmd_output->needs_tree_render = true; @@ -1087,14 +1090,20 @@ void cmd_unmark(I3_CMD, char *mark) { if (mark == NULL) { Con *con; TAILQ_FOREACH(con, &all_cons, all_cons) { + if (con->mark == NULL) + continue; + FREE(con->mark); + con->mark_changed = true; } DLOG("removed all window marks"); } else { Con *con; TAILQ_FOREACH(con, &all_cons, all_cons) { - if (con->mark && strcmp(con->mark, mark) == 0) + if (con->mark && strcmp(con->mark, mark) == 0) { FREE(con->mark); + con->mark_changed = true; + } } DLOG("removed window mark %s\n", mark); } diff --git a/src/x.c b/src/x.c index a3810942..1d4bfdf1 100644 --- a/src/x.c +++ b/src/x.c @@ -363,6 +363,7 @@ void x_draw_decoration(Con *con) { (con->window == NULL || !con->window->name_x_changed) && !parent->pixmap_recreated && !con->pixmap_recreated && + !con->mark_changed && memcmp(p, con->deco_render_params, sizeof(struct deco_render_params)) == 0) { free(p); goto copy_pixmaps; @@ -381,6 +382,7 @@ void x_draw_decoration(Con *con) { parent->pixmap_recreated = false; con->pixmap_recreated = false; + con->mark_changed = false; /* 2: draw the client.background, but only for the parts around the client_rect */ if (con->window != NULL) { From 245a29e2337fe1cf67eaae5e095cee4f8e440dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 29 Mar 2015 00:26:49 +0100 Subject: [PATCH 029/243] Make show_marks configurable Introduce a config directive "show_marks [yes|no]" to en- or disable drawing marks on window decorations. To not change the look & feel of existing configurations, the default is "no". --- docs/userguide | 20 ++++++++++++++++++++ include/config.h | 4 ++++ include/config_directives.h | 1 + parser-specs/config.spec | 6 ++++++ src/config_directives.c | 4 ++++ src/x.c | 10 +++++----- testcases/t/201-config-parser.t | 2 +- 7 files changed, 41 insertions(+), 6 deletions(-) diff --git a/docs/userguide b/docs/userguide index 5eb48554..921a8628 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1006,6 +1006,24 @@ focus:: none:: The window will neither be focused, nor be marked urgent. +=== Drawing marks on window decoration + +If activated, marks on windows are drawn in their window decoration. However, +any mark starting with an underscore in its name (+_+) will not be drawn even if +this option is activated. + +The default for this option is +no+. + +*Syntax*: +------------------- +show_marks [yes|no] +------------------- + +*Example*: +-------------- +show_marks yes +-------------- + == Configuring i3bar The bar at the bottom of your monitor is drawn by a separate process called @@ -1886,6 +1904,8 @@ The additional +--toggle+ option will remove the mark if the window already has this mark, add it if the window has none or replace the current mark if it has another mark. +Refer to +show_marks+ if you want marks to be shown in the window decoration. + *Syntax*: ------------------------------ mark [--toggle] identifier diff --git a/include/config.h b/include/config.h index 5b534fb7..fb11cbe3 100644 --- a/include/config.h +++ b/include/config.h @@ -179,6 +179,10 @@ struct Config { FOWA_NONE } focus_on_window_activation; + /** Specifies whether or not marks should be displayed in the window + * decoration. Marks starting with a "_" will be ignored either way. */ + bool show_marks; + /** The default border style for new windows. */ border_style_t default_border; diff --git a/include/config_directives.h b/include/config_directives.h index 8f99e648..b9189b2c 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -52,6 +52,7 @@ CFGFUN(force_xinerama, const char *value); CFGFUN(fake_outputs, const char *outputs); CFGFUN(force_display_urgency_hint, const long duration_ms); CFGFUN(focus_on_window_activation, const char *mode); +CFGFUN(show_marks, const char *value); CFGFUN(hide_edge_borders, const char *borders); CFGFUN(assign, const char *workspace); CFGFUN(ipc_socket, const char *path); diff --git a/parser-specs/config.spec b/parser-specs/config.spec index e23c37c8..81357206 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -39,6 +39,7 @@ state INITIAL: 'fake_outputs', 'fake-outputs' -> FAKE_OUTPUTS 'force_display_urgency_hint' -> FORCE_DISPLAY_URGENCY_HINT 'focus_on_window_activation' -> FOCUS_ON_WINDOW_ACTIVATION + 'show_marks' -> SHOW_MARKS 'workspace' -> WORKSPACE 'ipc_socket', 'ipc-socket' -> IPC_SOCKET 'restart_state' -> RESTART_STATE @@ -205,6 +206,11 @@ state FORCE_DISPLAY_URGENCY_HINT: duration_ms = number -> FORCE_DISPLAY_URGENCY_HINT_MS +# show_marks +state SHOW_MARKS: + value = word + -> call cfg_show_marks($value) + state FORCE_DISPLAY_URGENCY_HINT_MS: 'ms' -> diff --git a/src/config_directives.c b/src/config_directives.c index 039cb29e..eddfaa3d 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -346,6 +346,10 @@ CFGFUN(focus_on_window_activation, const char *mode) { DLOG("Set new focus_on_window_activation mode = %i", config.focus_on_window_activation); } +CFGFUN(show_marks, const char *value) { + config.show_marks = eval_boolstr(value); +} + CFGFUN(workspace, const char *workspace, const char *output) { DLOG("Assigning workspace \"%s\" to output \"%s\"\n", workspace, output); /* Check for earlier assignments of the same workspace so that we diff --git a/src/x.c b/src/x.c index 1d4bfdf1..d29d4bef 100644 --- a/src/x.c +++ b/src/x.c @@ -534,16 +534,16 @@ void x_draw_decoration(Con *con) { int indent_px = (indent_level * 5) * indent_mult; int mark_width = 0; - if (con->mark != NULL && (con->mark)[0] != '_') { + if (config.show_marks && con->mark != NULL && (con->mark)[0] != '_') { char *formatted_mark; sasprintf(&formatted_mark, "[%s]", con->mark); i3String *mark = i3string_from_utf8(formatted_mark); FREE(formatted_mark); - mark_width = predict_text_width(mark) + logical_px(2); + mark_width = predict_text_width(mark); draw_text(mark, parent->pixmap, parent->pm_gc, - con->deco_rect.x + con->deco_rect.width - mark_width, - con->deco_rect.y + text_offset_y, mark_width - logical_px(2)); + con->deco_rect.x + con->deco_rect.width - mark_width - logical_px(2), + con->deco_rect.y + text_offset_y, mark_width); I3STRING_FREE(mark); } @@ -551,7 +551,7 @@ void x_draw_decoration(Con *con) { draw_text(win->name, parent->pixmap, parent->pm_gc, con->deco_rect.x + logical_px(2) + indent_px, con->deco_rect.y + text_offset_y, - con->deco_rect.width - logical_px(2) - indent_px - mark_width); + con->deco_rect.width - logical_px(2) - indent_px - mark_width - logical_px(2)); after_title: /* Since we don’t clip the text at all, it might in some cases be painted diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index a6b1fe0c..3314aaf7 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -433,7 +433,7 @@ client.focused #4c7899 #285577 #ffffff #2e9ef4 EOT my $expected_all_tokens = <<'EOT'; -ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' +ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'show_marks', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' EOT my $expected_end = <<'EOT'; From 6036d4e5066d29afc5a4628f0f62606767d3d349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Mon, 30 Mar 2015 22:16:05 +0200 Subject: [PATCH 030/243] Changed the default for show_marks from "no" to "yes" --- docs/userguide | 4 ++-- src/commands.c | 2 +- src/config.c | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/userguide b/docs/userguide index 921a8628..2e42493c 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1012,7 +1012,7 @@ If activated, marks on windows are drawn in their window decoration. However, any mark starting with an underscore in its name (+_+) will not be drawn even if this option is activated. -The default for this option is +no+. +The default for this option is +yes+. *Syntax*: ------------------- @@ -1904,7 +1904,7 @@ The additional +--toggle+ option will remove the mark if the window already has this mark, add it if the window has none or replace the current mark if it has another mark. -Refer to +show_marks+ if you want marks to be shown in the window decoration. +Refer to +show_marks+ if you don't want marks to be shown in the window decoration. *Syntax*: ------------------------------ diff --git a/src/commands.c b/src/commands.c index 6c24e24d..dc60e974 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1046,7 +1046,7 @@ void cmd_mark(I3_CMD, char *mark, char *toggle) { owindow *current; TAILQ_FOREACH(current, &owindows, owindows) { DLOG("matching: %p / %s\n", current->con, current->con->name); - current->con->mark_changed=true; + current->con->mark_changed = true; if (toggle != NULL && current->con->mark && strcmp(current->con->mark, mark) == 0) { DLOG("removing window mark %s\n", mark); FREE(current->con->mark); diff --git a/src/config.c b/src/config.c index 36b7a163..8a1cb99c 100644 --- a/src/config.c +++ b/src/config.c @@ -190,6 +190,8 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, INIT_COLOR(config.bar.unfocused, "#333333", "#222222", "#888888", "#000000"); INIT_COLOR(config.bar.urgent, "#2f343a", "#900000", "#ffffff", "#000000"); + config.show_marks = true; + config.default_border = BS_NORMAL; config.default_floating_border = BS_NORMAL; config.default_border_width = logical_px(2); From 4e88c10564ca5366c2578908f62ec56625a26718 Mon Sep 17 00:00:00 2001 From: Deiz Date: Tue, 31 Mar 2015 13:29:43 -0400 Subject: [PATCH 031/243] Allow single-child non-default layout cons to be moved between outputs Includes a test case to verify the behaviour of 'move '. Fixes #1603. --- src/move.c | 8 ++++ testcases/t/524-move.t | 99 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 testcases/t/524-move.t diff --git a/src/move.c b/src/move.c index 1999a1fe..e4da191a 100644 --- a/src/move.c +++ b/src/move.c @@ -249,6 +249,14 @@ void tree_move(Con *con, int direction) { ? AFTER : BEFORE); insert_con_into(con, target, position); + } else if (con->parent->parent->type == CT_WORKSPACE && + con->parent->layout != L_DEFAULT && + con_num_children(con->parent) == 1) { + /* Con is the lone child of a non-default layout container at the edge + * of the workspace. Treat it as though the workspace is its parent + * and move it to the next output. */ + DLOG("Grandparent is workspace\n"); + move_to_output_directed(con, direction); } else { DLOG("Moving into container above\n"); position = (direction == D_UP || direction == D_LEFT ? BEFORE : AFTER); diff --git a/testcases/t/524-move.t b/testcases/t/524-move.t new file mode 100644 index 00000000..473bf235 --- /dev/null +++ b/testcases/t/524-move.t @@ -0,0 +1,99 @@ +#!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) +# +# Tests the behaviour of 'move ' when moving containers across +# outputs on workspaces that have non-default layouts. +# Ticket: #1603 +# Bug still in: 4.10.1-40-g0ad097e +use List::Util qw(first); +use i3test i3_autostart => 0; + +my $config = < 'first'); +my $second = open_window(wm_class => 'second'); + +is_num_children('left-top', 1, 'one child on left-top'); +is_num_children('right-top', 0, 'no children on right-top'); + +# Move the second window into its own stacked container. +cmd 'move right'; +is_num_children('left-top', 2, 'two children on left-top'); + +# Move the second window onto the upper right workspace. +cmd 'move right'; +is_num_children('left-top', 1, 'one child on left-top'); +is_num_children('right-top', 1, 'one child on right-top'); + +# Move the first window onto the upper right workspace. +cmd '[class="first"] move right'; +is_num_children('left-top', 0, 'no children on left-top'); +is_num_children('right-top', 2, 'two children on right-top'); + +# Move the second window onto the lower right workspace. +cmd '[class="second"] move down, move down'; +is_num_children('right-top', 1, 'one child on right-top'); +is_num_children('right-bottom', 1, 'two children on right-bottom'); + +# Move the first window onto the lower right workspace. +cmd '[class="first"] move down'; +is_num_children('right-top', 0, 'no children on right-top'); +is_num_children('right-bottom', 2, 'two children on right-bottom'); + +# Move the second windo onto the lower left workspace. +cmd '[class="second"] move left, move left'; +is_num_children('right-bottom', 1, 'one child on right-bottom'); +is_num_children('left-bottom', 1, 'one on left-bottom'); + +# Move the first window onto the lower left workspace. +cmd '[class="first"] move left'; +is_num_children('right-bottom', 0, 'no children on right-bottom'); +is_num_children('left-bottom', 2, 'two children on left-bottom'); + +# Move the second window onto the upper left workspace. +cmd '[class="second"] move up, move up'; +is_num_children('left-bottom', 1, 'one child on left-bottom'); +is_num_children('left-top', 1, 'one child on left-top'); + +# Move the first window onto the upper left workspace. +cmd '[class="first"] move up'; +is_num_children('left-bottom', 0, 'no children on left-bottom'); +is_num_children('left-top', 2, 'two children on left-top'); + +exit_gracefully($pid); + +done_testing; From 43204b43fdab6a1949169c0d5ee3a91247a379bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 31 Mar 2015 20:45:37 +0200 Subject: [PATCH 032/243] Added a testcase for #1614 --- testcases/lib/i3test.pm | 2 +- testcases/t/210-mark-unmark.t | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/testcases/lib/i3test.pm b/testcases/lib/i3test.pm index c149cbd1..ac1a26ca 100644 --- a/testcases/lib/i3test.pm +++ b/testcases/lib/i3test.pm @@ -606,7 +606,7 @@ sub get_dock_clients { =head2 cmd($command) -Sends the specified command to i3. +Sends the specified command to i3 and returns the output. my $ws = unused_workspace; cmd "workspace $ws"; diff --git a/testcases/t/210-mark-unmark.t b/testcases/t/210-mark-unmark.t index 0083547f..99fc92c8 100644 --- a/testcases/t/210-mark-unmark.t +++ b/testcases/t/210-mark-unmark.t @@ -141,4 +141,21 @@ cmd 'mark --toggle important'; is(get_mark_for_window_on_workspace($tmp, $first), 'important', 'left container has the mark now'); ok(!get_mark_for_window_on_workspace($tmp, $second), 'second containr no longer has the mark'); +############################################################## +# 9: try to mark two cons with the same mark and check that +# it fails +############################################################## + +my $first = open_window(wm_class => 'iamnotunique'); +my $second = open_window(wm_class => 'iamnotunique'); + +my $result = cmd "[instance=iamnotunique] mark important"; + +is($result->[0]->{success}, 0, 'command was unsuccessful'); +is($result->[0]->{error}, 'A mark must not be put onto more than one window', 'correct error is returned'); +ok(!get_mark_for_window_on_workspace($tmp, $first), 'first container is not marked'); +ok(!get_mark_for_window_on_workspace($tmp, $second), 'second containr is not marked'); + +############################################################## + done_testing; From 2e4fac61d2b6ec488bc476230655baaa12fc394e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 31 Mar 2015 20:47:22 +0200 Subject: [PATCH 033/243] Only mark a window if only one window is matched We only support unique marks, so looping over all matched windows must be prevented. If more than one window is matched, we reject it with an error message. fixes #1614 --- src/commands.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/commands.c b/src/commands.c index dc60e974..79071d6b 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1043,32 +1043,34 @@ void cmd_workspace_name(I3_CMD, char *name) { void cmd_mark(I3_CMD, char *mark, char *toggle) { HANDLE_EMPTY_MATCH; - owindow *current; - TAILQ_FOREACH(current, &owindows, owindows) { - DLOG("matching: %p / %s\n", current->con, current->con->name); - current->con->mark_changed = true; - if (toggle != NULL && current->con->mark && strcmp(current->con->mark, mark) == 0) { - DLOG("removing window mark %s\n", mark); - FREE(current->con->mark); - } else { - DLOG("marking window with str %s\n", mark); - FREE(current->con->mark); - current->con->mark = sstrdup(mark); - } + owindow *current = TAILQ_FIRST(&owindows); + if (current == NULL) { + ysuccess(false); + return; + } + + /* Marks must be unique, i.e., no two windows must have the same mark. */ + if (current != TAILQ_LAST(&owindows, owindows_head)) { + yerror("A mark must not be put onto more than one window"); + return; + } + + DLOG("matching: %p / %s\n", current->con, current->con->name); + current->con->mark_changed = true; + if (toggle != NULL && current->con->mark && strcmp(current->con->mark, mark) == 0) { + DLOG("removing window mark %s\n", mark); + FREE(current->con->mark); + } else { + DLOG("marking window with str %s\n", mark); + FREE(current->con->mark); + current->con->mark = sstrdup(mark); } DLOG("Clearing all non-matched windows with this mark\n"); Con *con; TAILQ_FOREACH(con, &all_cons, all_cons) { - /* Skip matched windows, we took care of them already. */ - bool matched = false; - TAILQ_FOREACH(current, &owindows, owindows) { - if (current->con == con) { - matched = true; - break; - } - } - if (matched) + /* Skip matched window, we took care of it already. */ + if (current->con == con) continue; if (con->mark && strcmp(con->mark, mark) == 0) { From f13b7ebaea8f263fd28b1288271fd0e25b028965 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 1 Apr 2015 12:31:32 -0400 Subject: [PATCH 034/243] Remove unused `tests` dir --- tests/queue.h | 543 --------------------------------------------- tests/swap.c | 224 ------------------- tests/test_table.c | 29 --- 3 files changed, 796 deletions(-) delete mode 100644 tests/queue.h delete mode 100644 tests/swap.c delete mode 100644 tests/test_table.c diff --git a/tests/queue.h b/tests/queue.h deleted file mode 100644 index 0b3a9c0b..00000000 --- a/tests/queue.h +++ /dev/null @@ -1,543 +0,0 @@ -/* $OpenBSD: queue.h,v 1.1 2007/10/26 03:14:08 niallo Exp $ */ -/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - */ - -#pragma once - -/* - * This file defines five types of data structures: singly-linked lists, - * lists, simple queues, tail queues, and circular queues. - * - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A simple queue is headed by a pair of pointers, one the head of the - * list and the other to the tail of the list. The elements are singly - * linked to save space, so elements can only be removed from the - * head of the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the - * list. A simple queue may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * - * For details on the use of these macros, see the queue(3) manual page. - */ - -#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) -#define _Q_INVALIDATE(a) (a) = ((void *)-1) -#else -#define _Q_INVALIDATE(a) -#endif - -/* - * Singly-linked List definitions. - */ -#define SLIST_HEAD(name, type) \ - struct name { \ - struct type *slh_first; /* first element */ \ - } - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define SLIST_ENTRY(type) \ - struct { \ - struct type *sle_next; /* next element */ \ - } - -/* - * Singly-linked List access methods. - */ -#define SLIST_FIRST(head) ((head)->slh_first) -#define SLIST_END(head) NULL -#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_FOREACH(var, head, field) \ - for ((var) = SLIST_FIRST(head); \ - (var) != SLIST_END(head); \ - (var) = SLIST_NEXT(var, field)) - -#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ - for ((varp) = &SLIST_FIRST((head)); \ - ((var) = *(varp)) != SLIST_END(head); \ - (varp) = &SLIST_NEXT((var), field)) - -/* - * Singly-linked List functions. - */ -#define SLIST_INIT(head) \ - { \ - SLIST_FIRST(head) = SLIST_END(head); \ - } - -#define SLIST_INSERT_AFTER(slistelm, elm, field) \ - do { \ - (elm)->field.sle_next = (slistelm)->field.sle_next; \ - (slistelm)->field.sle_next = (elm); \ - } while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) \ - do { \ - (elm)->field.sle_next = (head)->slh_first; \ - (head)->slh_first = (elm); \ - } while (0) - -#define SLIST_REMOVE_NEXT(head, elm, field) \ - do { \ - (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ - } while (0) - -#define SLIST_REMOVE_HEAD(head, field) \ - do { \ - (head)->slh_first = (head)->slh_first->field.sle_next; \ - } while (0) - -#define SLIST_REMOVE(head, elm, type, field) \ - do { \ - if ((head)->slh_first == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } else { \ - struct type *curelm = (head)->slh_first; \ - \ - while (curelm->field.sle_next != (elm)) \ - curelm = curelm->field.sle_next; \ - curelm->field.sle_next = curelm->field.sle_next->field.sle_next; \ - _Q_INVALIDATE((elm)->field.sle_next); \ - } \ - } while (0) - -/* - * List definitions. - */ -#define LIST_HEAD(name, type) \ - struct name { \ - struct type *lh_first; /* first element */ \ - } - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ - struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ - } - -/* - * List access methods - */ -#define LIST_FIRST(head) ((head)->lh_first) -#define LIST_END(head) NULL -#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = LIST_FIRST(head); \ - (var) != LIST_END(head); \ - (var) = LIST_NEXT(var, field)) - -/* - * List functions. - */ -#define LIST_INIT(head) \ - do { \ - LIST_FIRST(head) = LIST_END(head); \ - } while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) \ - do { \ - if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ - (listelm)->field.le_next->field.le_prev = &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ - } while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) \ - do { \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - (elm)->field.le_next = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &(elm)->field.le_next; \ - } while (0) - -#define LIST_INSERT_HEAD(head, elm, field) \ - do { \ - if (((elm)->field.le_next = (head)->lh_first) != NULL) \ - (head)->lh_first->field.le_prev = &(elm)->field.le_next; \ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ - } while (0) - -#define LIST_REMOVE(elm, field) \ - do { \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ - _Q_INVALIDATE((elm)->field.le_prev); \ - _Q_INVALIDATE((elm)->field.le_next); \ - } while (0) - -#define LIST_REPLACE(elm, elm2, field) \ - do { \ - if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ - (elm2)->field.le_next->field.le_prev = &(elm2)->field.le_next; \ - (elm2)->field.le_prev = (elm)->field.le_prev; \ - *(elm2)->field.le_prev = (elm2); \ - _Q_INVALIDATE((elm)->field.le_prev); \ - _Q_INVALIDATE((elm)->field.le_next); \ - } while (0) - -/* - * Simple queue definitions. - */ -#define SIMPLEQ_HEAD(name, type) \ - struct name { \ - struct type *sqh_first; /* first element */ \ - struct type **sqh_last; /* addr of last next element */ \ - } - -#define SIMPLEQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).sqh_first } - -#define SIMPLEQ_ENTRY(type) \ - struct { \ - struct type *sqe_next; /* next element */ \ - } - -/* - * Simple queue access methods. - */ -#define SIMPLEQ_FIRST(head) ((head)->sqh_first) -#define SIMPLEQ_END(head) NULL -#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) -#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) - -#define SIMPLEQ_FOREACH(var, head, field) \ - for ((var) = SIMPLEQ_FIRST(head); \ - (var) != SIMPLEQ_END(head); \ - (var) = SIMPLEQ_NEXT(var, field)) - -/* - * Simple queue functions. - */ -#define SIMPLEQ_INIT(head) \ - do { \ - (head)->sqh_first = NULL; \ - (head)->sqh_last = &(head)->sqh_first; \ - } while (0) - -#define SIMPLEQ_INSERT_HEAD(head, elm, field) \ - do { \ - if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (head)->sqh_first = (elm); \ - } while (0) - -#define SIMPLEQ_INSERT_TAIL(head, elm, field) \ - do { \ - (elm)->field.sqe_next = NULL; \ - *(head)->sqh_last = (elm); \ - (head)->sqh_last = &(elm)->field.sqe_next; \ - } while (0) - -#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) \ - do { \ - if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (listelm)->field.sqe_next = (elm); \ - } while (0) - -#define SIMPLEQ_REMOVE_HEAD(head, field) \ - do { \ - if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ - (head)->sqh_last = &(head)->sqh_first; \ - } while (0) - -/* - * Tail queue definitions. - */ -#define TAILQ_HEAD(name, type) \ - struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ - } - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define TAILQ_ENTRY(type) \ - struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ - } - -/* - * tail queue access methods - */ -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_END(head) NULL -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) -/* XXX */ -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) -#define TAILQ_EMPTY(head) \ - (TAILQ_FIRST(head) == TAILQ_END(head)) - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST(head); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_NEXT(var, field)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = TAILQ_LAST(head, headname); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_PREV(var, headname, field)) - -/* - * Tail queue functions. - */ -#define TAILQ_INIT(head) \ - do { \ - (head)->tqh_first = NULL; \ - (head)->tqh_last = &(head)->tqh_first; \ - } while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) \ - do { \ - if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ - (head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ - } while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) \ - do { \ - (elm)->field.tqe_next = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - } while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) \ - do { \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ - } while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) \ - do { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ - } while (0) - -#define TAILQ_REMOVE(head, elm, field) \ - do { \ - if (((elm)->field.tqe_next) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ - _Q_INVALIDATE((elm)->field.tqe_prev); \ - _Q_INVALIDATE((elm)->field.tqe_next); \ - } while (0) - -#define TAILQ_REPLACE(head, elm, elm2, field) \ - do { \ - if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ - (elm2)->field.tqe_next->field.tqe_prev = &(elm2)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm2)->field.tqe_next; \ - (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ - *(elm2)->field.tqe_prev = (elm2); \ - _Q_INVALIDATE((elm)->field.tqe_prev); \ - _Q_INVALIDATE((elm)->field.tqe_next); \ - } while (0) - -/* - * Circular queue definitions. - */ -#define CIRCLEQ_HEAD(name, type) \ - struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ - } - -#define CIRCLEQ_HEAD_INITIALIZER(head) \ - { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } - -#define CIRCLEQ_ENTRY(type) \ - struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ - } - -/* - * Circular queue access methods - */ -#define CIRCLEQ_FIRST(head) ((head)->cqh_first) -#define CIRCLEQ_LAST(head) ((head)->cqh_last) -#define CIRCLEQ_END(head) ((void *)(head)) -#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) -#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) -#define CIRCLEQ_EMPTY(head) \ - (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) - -#define CIRCLEQ_FOREACH(var, head, field) \ - for ((var) = CIRCLEQ_FIRST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_NEXT(var, field)) - -#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ - for ((var) = CIRCLEQ_LAST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_PREV(var, field)) - -/* - * Circular queue functions. - */ -#define CIRCLEQ_INIT(head) \ - do { \ - (head)->cqh_first = CIRCLEQ_END(head); \ - (head)->cqh_last = CIRCLEQ_END(head); \ - } while (0) - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) \ - do { \ - (elm)->field.cqe_next = (listelm)->field.cqe_next; \ - (elm)->field.cqe_prev = (listelm); \ - if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm); \ - else \ - (listelm)->field.cqe_next->field.cqe_prev = (elm); \ - (listelm)->field.cqe_next = (elm); \ - } while (0) - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) \ - do { \ - (elm)->field.cqe_next = (listelm); \ - (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ - if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm); \ - else \ - (listelm)->field.cqe_prev->field.cqe_next = (elm); \ - (listelm)->field.cqe_prev = (elm); \ - } while (0) - -#define CIRCLEQ_INSERT_HEAD(head, elm, field) \ - do { \ - (elm)->field.cqe_next = (head)->cqh_first; \ - (elm)->field.cqe_prev = CIRCLEQ_END(head); \ - if ((head)->cqh_last == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm); \ - else \ - (head)->cqh_first->field.cqe_prev = (elm); \ - (head)->cqh_first = (elm); \ - } while (0) - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) \ - do { \ - (elm)->field.cqe_next = CIRCLEQ_END(head); \ - (elm)->field.cqe_prev = (head)->cqh_last; \ - if ((head)->cqh_first == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm); \ - else \ - (head)->cqh_last->field.cqe_next = (elm); \ - (head)->cqh_last = (elm); \ - } while (0) - -#define CIRCLEQ_REMOVE(head, elm, field) \ - do { \ - if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm)->field.cqe_prev; \ - else \ - (elm)->field.cqe_next->field.cqe_prev = (elm)->field.cqe_prev; \ - if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm)->field.cqe_next; \ - else \ - (elm)->field.cqe_prev->field.cqe_next = (elm)->field.cqe_next; \ - _Q_INVALIDATE((elm)->field.cqe_prev); \ - _Q_INVALIDATE((elm)->field.cqe_next); \ - } while (0) - -#define CIRCLEQ_REPLACE(head, elm, elm2, field) \ - do { \ - if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm2); \ - else \ - (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ - if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm2); \ - else \ - (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ - _Q_INVALIDATE((elm)->field.cqe_prev); \ - _Q_INVALIDATE((elm)->field.cqe_next); \ - } while (0) diff --git a/tests/swap.c b/tests/swap.c deleted file mode 100644 index abc3b3b5..00000000 --- a/tests/swap.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * vim:ts=4:sw=4:expandtab - */ -#include -#include -#include -#include -#include -#include - -#include "queue.h" - -struct obj { - int abc; - TAILQ_ENTRY(obj) entry; -}; - -TAILQ_HEAD(objhead, obj) head; - -void dump() { - struct obj *e; - printf("dump:\n"); - e = TAILQ_FIRST(&head); - printf("first: %d\n", e->abc); - e = TAILQ_LAST(&head, objhead); - printf("last: %d\n", e->abc); - TAILQ_FOREACH(e, &head, entry) { - printf(" %d\n", e->abc); - } - printf("again, but reverse:\n"); - TAILQ_FOREACH_REVERSE(e, &head, objhead, entry) { - printf(" %d\n", e->abc); - } - printf("done\n\n"); -} - -#define TAILQ_SWAP(first, second, head, field) \ - do { \ - *((first)->field.tqe_prev) = (second); \ - (second)->field.tqe_prev = (first)->field.tqe_prev; \ - (first)->field.tqe_prev = &((second)->field.tqe_next); \ - (first)->field.tqe_next = (second)->field.tqe_next; \ - if ((second)->field.tqe_next) \ - (second)->field.tqe_next->field.tqe_prev = &((first)->field.tqe_next); \ - (second)->field.tqe_next = first; \ - if ((head)->tqh_last == &((second)->field.tqe_next)) \ - (head)->tqh_last = &((first)->field.tqe_next); \ - } while (0) - -void _TAILQ_SWAP(struct obj *first, struct obj *second, struct objhead *head) { - struct obj **tqe_prev = first->entry.tqe_prev; - *tqe_prev = second; - - second->entry.tqe_prev = first->entry.tqe_prev; - - first->entry.tqe_prev = &(second->entry.tqe_next); - - first->entry.tqe_next = second->entry.tqe_next; - - if (second->entry.tqe_next) { - struct obj *tqe_next = second->entry.tqe_next; - tqe_next->entry.tqe_prev = &(first->entry.tqe_next); - } - - second->entry.tqe_next = first; - - if (head->tqh_last == &(second->entry.tqe_next)) - head->tqh_last = &(first->entry.tqe_next); -} - -int main() { - printf("hello\n"); - - TAILQ_INIT(&head); - - struct obj first; - first.abc = 123; - - struct obj second; - second.abc = 456; - - struct obj third; - third.abc = 789; - - struct obj fourth; - fourth.abc = 999; - - struct obj fifth; - fifth.abc = 5555; - - /* - * ************************************************ - */ - printf("swapping first two elements:\n"); - - TAILQ_INSERT_TAIL(&head, &first, entry); - TAILQ_INSERT_TAIL(&head, &second, entry); - TAILQ_INSERT_TAIL(&head, &third, entry); - - dump(); - - TAILQ_SWAP(&first, &second, &head, entry); - - dump(); - - /* - * ************************************************ - */ - printf("swapping last two elements:\n"); - - TAILQ_INIT(&head); - - TAILQ_INSERT_TAIL(&head, &first, entry); - TAILQ_INSERT_TAIL(&head, &second, entry); - TAILQ_INSERT_TAIL(&head, &third, entry); - - dump(); - - TAILQ_SWAP(&second, &third, &head, entry); - - dump(); - - /* - * ************************************************ - */ - printf("longer list:\n"); - - TAILQ_INIT(&head); - - TAILQ_INSERT_TAIL(&head, &first, entry); - TAILQ_INSERT_TAIL(&head, &second, entry); - TAILQ_INSERT_TAIL(&head, &third, entry); - TAILQ_INSERT_TAIL(&head, &fourth, entry); - - dump(); - - TAILQ_SWAP(&first, &second, &head, entry); - - dump(); - - /* - * ************************************************ - */ - printf("longer list 2:\n"); - - TAILQ_INIT(&head); - - TAILQ_INSERT_TAIL(&head, &first, entry); - TAILQ_INSERT_TAIL(&head, &second, entry); - TAILQ_INSERT_TAIL(&head, &third, entry); - TAILQ_INSERT_TAIL(&head, &fourth, entry); - - dump(); - - TAILQ_SWAP(&second, &third, &head, entry); - - dump(); - - /* - * ************************************************ - */ - printf("longer list, swap, then insert:\n"); - - TAILQ_INIT(&head); - - TAILQ_INSERT_TAIL(&head, &first, entry); - TAILQ_INSERT_TAIL(&head, &second, entry); - TAILQ_INSERT_TAIL(&head, &third, entry); - TAILQ_INSERT_TAIL(&head, &fourth, entry); - - dump(); - - TAILQ_SWAP(&second, &third, &head, entry); - - dump(); - - TAILQ_INSERT_AFTER(&head, &third, &fifth, entry); - - dump(); - - /* - * ************************************************ - */ - printf("longer list, swap, then append:\n"); - - TAILQ_INIT(&head); - - TAILQ_INSERT_TAIL(&head, &first, entry); - TAILQ_INSERT_TAIL(&head, &second, entry); - TAILQ_INSERT_TAIL(&head, &third, entry); - TAILQ_INSERT_TAIL(&head, &fourth, entry); - - dump(); - - TAILQ_SWAP(&second, &third, &head, entry); - - dump(); - - TAILQ_INSERT_TAIL(&head, &fifth, entry); - - dump(); - - /* - * ************************************************ - */ - printf("longer list, swap, then remove:\n"); - - TAILQ_INIT(&head); - - TAILQ_INSERT_TAIL(&head, &first, entry); - TAILQ_INSERT_TAIL(&head, &second, entry); - TAILQ_INSERT_TAIL(&head, &third, entry); - TAILQ_INSERT_TAIL(&head, &fourth, entry); - - dump(); - - TAILQ_SWAP(&second, &third, &head, entry); - - dump(); - - TAILQ_REMOVE(&head, &second, entry); - - dump(); -} diff --git a/tests/test_table.c b/tests/test_table.c deleted file mode 100644 index 554be3e7..00000000 --- a/tests/test_table.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include "table.h" - -void print_table() { - int r, c; - printf("printing table...\n"); - for (c = 0; c < table_dims.x; c++) - for (r = 0; r < table_dims.y; r++) - printf("table[%d][%d] = %p\n", c, r, table[c][r]); - printf("done\n"); -} - -int main() { - printf("table.c tests\n"); - printf("table_dimensions = %d, %d\n", table_dims.x, table_dims.y); - init_table(); - printf("table_dimensions = %d, %d\n", table_dims.x, table_dims.y); - print_table(); - - printf("expand_table_cols()\n"); - expand_table_cols(); - printf("table_dimensions = %d, %d\n", table_dims.x, table_dims.y); - print_table(); - - printf("expand_table_rows()\n"); - expand_table_rows(); - printf("table_dimensions = %d, %d\n", table_dims.x, table_dims.y); - print_table(); -} From e1554479326b1e9bd280187f7978e3b5b5a98baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 29 Mar 2015 17:29:21 +0200 Subject: [PATCH 035/243] Added assignment type 'A_NO_FOCUS' (#1416) Any assignment with type 'A_NO_FOCUS' will cause the matched window to not be focused by i3 when it is managed. --- include/data.h | 4 +++- src/manage.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/data.h b/include/data.h index d40ed292..50e1f180 100644 --- a/include/data.h +++ b/include/data.h @@ -460,6 +460,7 @@ struct Assignment { * * A_COMMAND = run the specified command for the matching window * A_TO_WORKSPACE = assign the matching window to the specified workspace + * A_NO_FOCUS = don't focus matched window when it is managed * * While the type is a bitmask, only one value can be set at a time. It is * a bitmask to allow filtering for multiple types, for example in the @@ -469,7 +470,8 @@ struct Assignment { enum { A_ANY = 0, A_COMMAND = (1 << 0), - A_TO_WORKSPACE = (1 << 1) + A_TO_WORKSPACE = (1 << 1), + A_NO_FOCUS = (1 << 2) } type; /** the criteria to check if a window matches */ diff --git a/src/manage.c b/src/manage.c index 2b3c6743..3499963b 100644 --- a/src/manage.c +++ b/src/manage.c @@ -512,8 +512,10 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki /* Defer setting focus after the 'new' event has been sent to ensure the * proper window event sequence. */ if (set_focus && !nc->window->doesnt_accept_focus && nc->mapped) { - DLOG("Now setting focus.\n"); - con_focus(nc); + if (assignment_for(cwindow, A_NO_FOCUS) == NULL) { + DLOG("Now setting focus.\n"); + con_focus(nc); + } } tree_render(); From b5f7c132fccfa8bd9909377bb8a0b0d3b930a099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 29 Mar 2015 17:30:14 +0200 Subject: [PATCH 036/243] Added config directive 'no_focus ' (#1416) --- include/config_directives.h | 1 + parser-specs/config.spec | 10 ++++++++++ src/config_directives.c | 13 +++++++++++++ testcases/t/201-config-parser.t | 2 +- 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/include/config_directives.h b/include/config_directives.h index b9189b2c..f5039624 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -55,6 +55,7 @@ CFGFUN(focus_on_window_activation, const char *mode); CFGFUN(show_marks, const char *value); CFGFUN(hide_edge_borders, const char *borders); CFGFUN(assign, const char *workspace); +CFGFUN(no_focus); CFGFUN(ipc_socket, const char *path); CFGFUN(restart_state, const char *path); CFGFUN(popup_during_fullscreen, const char *value); diff --git a/parser-specs/config.spec b/parser-specs/config.spec index 81357206..433e1d11 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -31,6 +31,7 @@ state INITIAL: 'hide_edge_borders' -> HIDE_EDGE_BORDERS 'for_window' -> FOR_WINDOW 'assign' -> ASSIGN + 'no_focus' -> NO_FOCUS 'focus_follows_mouse' -> FOCUS_FOLLOWS_MOUSE 'mouse_warping' -> MOUSE_WARPING 'force_focus_wrapping' -> FORCE_FOCUS_WRAPPING @@ -150,6 +151,15 @@ state ASSIGN_WORKSPACE: workspace = string -> call cfg_assign($workspace) +# no_focus +state NO_FOCUS: + '[' + -> call cfg_criteria_init(NO_FOCUS_END); CRITERIA + +state NO_FOCUS_END: + end + -> call cfg_no_focus() + # Criteria: Used by for_window and assign. state CRITERIA: ctype = 'class' -> CRITERION diff --git a/src/config_directives.c b/src/config_directives.c index eddfaa3d..398e53bb 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -431,6 +431,19 @@ CFGFUN(assign, const char *workspace) { TAILQ_INSERT_TAIL(&assignments, assignment, assignments); } +CFGFUN(no_focus) { + if (match_is_empty(current_match)) { + ELOG("Match is empty, ignoring this assignment\n"); + return; + } + + DLOG("new assignment, using above criteria, to ignore focus on manage"); + Assignment *assignment = scalloc(sizeof(Assignment)); + match_copy(&(assignment->match), current_match); + assignment->type = A_NO_FOCUS; + TAILQ_INSERT_TAIL(&assignments, assignment, assignments); +} + /******************************************************************************* * Bar configuration (i3bar) ******************************************************************************/ diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 3314aaf7..0f22878d 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -433,7 +433,7 @@ client.focused #4c7899 #285577 #ffffff #2e9ef4 EOT my $expected_all_tokens = <<'EOT'; -ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'show_marks', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' +ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'no_focus', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'show_marks', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' EOT my $expected_end = <<'EOT'; From 18d6b24f8deab27bd596e96cad0fac42150554bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 31 Mar 2015 21:22:34 +0200 Subject: [PATCH 037/243] Added testcase for the no_focus directive (#1416) --- testcases/t/242-no-focus.t | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 testcases/t/242-no-focus.t diff --git a/testcases/t/242-no-focus.t b/testcases/t/242-no-focus.t new file mode 100644 index 00000000..b3983436 --- /dev/null +++ b/testcases/t/242-no-focus.t @@ -0,0 +1,66 @@ +#!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) +# +# Test the 'no_focus' directive. +# Ticket: #1416 +use i3test i3_autostart => 0; + +##################################################################### +# 1: open a window and check that it takes focus +##################################################################### + +my $config = < 'notme'); + +is(get_focused($ws), $focused, 'focus has not changed'); + +exit_gracefully($pid); + +##################################################################### + +done_testing; From 0788f43db757bf2ee301af22cf80abb85477f505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 1 Apr 2015 13:59:24 +0200 Subject: [PATCH 038/243] Updates userguide for 'no_focus ' (#1416) --- docs/userguide | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/userguide b/docs/userguide index 2e42493c..98629761 100644 --- a/docs/userguide +++ b/docs/userguide @@ -589,6 +589,27 @@ for_window [title="x200: ~/work"] floating enable The valid criteria are the same as those for commands, see <>. +=== Don't focus window upon opening + +[[no_focus]] + +When a new window appears, it will be focused. The +no_focus+ directive allows preventing +this from happening and can be used in combination with <>. + +Note that this does not apply to all cases, e.g., when feeding data into a running application +causing it to request being focused. To configure the behavior in such cases, refer to +<>. + +*Syntax*: +------------------- +no_focus +------------------- + +*Example*: +------------------------------- +no_focus [window_role="pop-up"] +------------------------------- + === Variables As you learned in the section about keyboard bindings, you will have @@ -983,11 +1004,13 @@ force_display_urgency_hint 500 ms === Focus on window activation +[[focus_on_window_activation]] + If a window is activated, e.g., via +google-chrome www.google.com+, it may request to take focus. Since this may not preferable, different reactions can be configured. -Note that this does not apply to any window that is opened, i.e., typically opening -an application will focus that window independent of this configuration. +Note that this may not affect windows that are being opened. To prevent new windows +from being focused, see <>. *Syntax*: ---------------------------------------------------- From d2d72acac4481043fcef011ab533289795e7710a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 1 Apr 2015 15:10:27 -0400 Subject: [PATCH 039/243] complete-run: add coverage report generation When `complete-run.pl` is given `--coverage-testing`, try to generate an html coverage testing report for the run. This requires i3 to be compiled with coverage testing support. --- testcases/complete-run.pl | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/testcases/complete-run.pl b/testcases/complete-run.pl index 9710017d..8a3b89f0 100755 --- a/testcases/complete-run.pl +++ b/testcases/complete-run.pl @@ -86,6 +86,16 @@ foreach my $binary (@binaries) { die "$binary is not an executable" unless -x $binary; } +if ($options{coverage}) { + qx(command -v lcov &> /dev/null); + die "Cannot find lcov needed for coverage testing." if $?; + qx(command -v genhtml &> /dev/null); + die "Cannot find genhtml needed for coverage testing." if $?; + + # clean out the counters that may be left over from previous tests. + qx(lcov -d ../ --zerocounters &> /dev/null); +} + qx(Xephyr -help 2>&1); die "Xephyr was not found in your path. Please install Xephyr (xserver-xephyr on Debian)." if $?; @@ -227,6 +237,17 @@ if ($numtests == 1) { END { cleanup() } +if ($options{coverage}) { + print("\nGenerating test coverage report...\n"); + qx(lcov -d ../ -b ../ --capture -o latest/i3-coverage.info); + qx(genhtml -o latest/i3-coverage latest/i3-coverage.info); + if ($?) { + print("Could not generate test coverage html. Did you compile i3 with test coverage support?\n"); + } else { + print("Test coverage report generated in latest/i3-coverage\n"); + } +} + exit ($aggregator->failed > 0); # @@ -391,7 +412,8 @@ available in C. =item B<--coverage-testing> -Exits i3 cleanly (instead of kill -9) to make coverage testing work properly. +Generates a test coverage report at C. Exits i3 cleanly +during tests (instead of kill -9) to make coverage testing work properly. =item B<--parallel> From 74abd8cd507cc6e8de3b7e940204333e94b45dc3 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 1 Apr 2015 17:36:32 -0400 Subject: [PATCH 040/243] makefile: allow COVERAGE to be configurable If COVERAGE=1 during build, i3 will be compiled for coverage testing. --- common.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/common.mk b/common.mk index b9e15a28..dcc90c96 100644 --- a/common.mk +++ b/common.mk @@ -1,6 +1,5 @@ UNAME=$(shell uname) DEBUG=1 -COVERAGE=0 INSTALL=install LN=ln ifndef PREFIX From c50ec2e4dcf1e15e063f2c7d021108ad51e4f27b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 1 Apr 2015 18:19:18 -0400 Subject: [PATCH 041/243] Document test coverage reporting for testcases --- docs/testsuite | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/testsuite b/docs/testsuite index 29a35218..8fdb9635 100644 --- a/docs/testsuite +++ b/docs/testsuite @@ -160,6 +160,27 @@ $ ./complete-run.pl --parallel=1 --keep-xserver-output This will show the output of Xephyr, which is the X server implementation we use for testing. +==== Coverage testing + +Coverage testing is possible with +lcov+, the front-end for GCC's coverage +testing tool +gcov+. The testcases can generate a nice html report that tells +you which functions and lines were covered during a run of the tests. You can +use this tool to judge how effective your tests are. + +To use test coverage tools, first compile with coverage enabled. + +--------------------------------------------------- +COVERAGE=1 make +--------------------------------------------------- + +Then run the tests with the +--coverage-testing+ flag. + +--------------------------------------------------- +./complete-run.pl --coverage-testing +--------------------------------------------------- + +Then open +latest/i3-coverage/index.html+ in your web browser. + ==== IPC interface The testsuite makes extensive use of the IPC (Inter-Process Communication) From 947c67a62716d4732e12119b8d813af6ef8a3832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 1 Apr 2015 14:35:49 +0200 Subject: [PATCH 042/243] Position i3-input at window with input focus This positions the i3-input window at the window holding the input focus' position, plus a small offset. fixes #1058 --- i3-input/main.c | 54 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/i3-input/main.c b/i3-input/main.c index 996fc0ea..b32d7b66 100644 --- a/i3-input/main.c +++ b/i3-input/main.c @@ -314,6 +314,50 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press return 1; } +static xcb_rectangle_t get_window_position(void) { + xcb_rectangle_t result = (xcb_rectangle_t){logical_px(50), logical_px(50), logical_px(500), font.height + logical_px(8)}; + + xcb_get_input_focus_reply_t *input_focus = NULL; + xcb_get_geometry_reply_t *geometry = NULL; + xcb_translate_coordinates_reply_t *coordinates = NULL; + + /* In rare cases, the window holding the input focus might disappear while we are figuring out its + * position. To avoid this, we grab the server in the meantime. */ + xcb_grab_server(conn); + + input_focus = xcb_get_input_focus_reply(conn, xcb_get_input_focus(conn), NULL); + if (input_focus == NULL || input_focus->focus == XCB_NONE) { + DLOG("Failed to receive the current input focus or no window has the input focus right now.\n"); + goto free_resources; + } + + geometry = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, input_focus->focus), NULL); + if (geometry == NULL) { + DLOG("Failed to received window geometry.\n"); + goto free_resources; + } + + coordinates = xcb_translate_coordinates_reply( + conn, xcb_translate_coordinates(conn, input_focus->focus, root, geometry->x, geometry->y), NULL); + if (coordinates == NULL) { + DLOG("Failed to translate coordinates.\n"); + goto free_resources; + } + + DLOG("Determined coordinates of window with input focus at x = %i / y = %i", coordinates->dst_x, coordinates->dst_y); + result.x += coordinates->dst_x; + result.y += coordinates->dst_y; + +free_resources: + xcb_ungrab_server(conn); + xcb_flush(conn); + + FREE(input_focus); + FREE(geometry); + FREE(coordinates); + return result; +} + int main(int argc, char *argv[]) { format = strdup("%s"); socket_path = getenv("I3SOCK"); @@ -402,15 +446,17 @@ int main(int argc, char *argv[]) { if (prompt != NULL) prompt_offset = predict_text_width(prompt); + const xcb_rectangle_t win_pos = get_window_position(); + /* Open an input window */ win = xcb_generate_id(conn); xcb_create_window( conn, XCB_COPY_FROM_PARENT, - win, /* the window id */ - root, /* parent == root */ - logical_px(50), logical_px(50), logical_px(500), font.height + logical_px(8), /* dimensions */ - 0, /* X11 border = 0, we draw our own */ + win, /* the window id */ + root, /* parent == root */ + win_pos.x, win_pos.y, win_pos.width, win_pos.height, /* dimensions */ + 0, /* X11 border = 0, we draw our own */ XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */ XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, From bb955715162763c3b008519a42e8c179a933934d Mon Sep 17 00:00:00 2001 From: Deiz Date: Wed, 1 Apr 2015 16:17:26 -0400 Subject: [PATCH 043/243] Make floating window mouse handling consistent with tiled windows It seems that this was the intended behaviour all along, according to the comments. --- src/click.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/click.c b/src/click.c index 10abc057..3cd367cc 100644 --- a/src/click.c +++ b/src/click.c @@ -180,6 +180,9 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod if (con->parent->type == CT_DOCKAREA) goto done; + const bool is_left_or_right_click = (event->detail == XCB_BUTTON_INDEX_1 || + event->detail == XCB_BUTTON_INDEX_3); + /* if the user has bound an action to this click, it should override the * default behavior. */ if (dest == CLICK_DECORATION || dest == CLICK_INSIDE) { @@ -278,7 +281,8 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod return 1; } - if (!in_stacked && dest == CLICK_DECORATION) { + if (!in_stacked && dest == CLICK_DECORATION && + is_left_or_right_click) { /* try tiling resize, but continue if it doesn’t work */ DLOG("tiling resize with fallback\n"); if (tiling_resize(con, event, dest)) @@ -291,7 +295,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod return 1; } - if (dest == CLICK_BORDER) { + if (dest == CLICK_BORDER && is_left_or_right_click) { DLOG("floating resize due to border click\n"); floating_resize_window(floatingcon, proportional, event); return 1; @@ -299,7 +303,8 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod /* 6: dragging, if this was a click on a decoration (which did not lead * to a resize) */ - if (!in_stacked && dest == CLICK_DECORATION) { + if (!in_stacked && dest == CLICK_DECORATION && + (event->detail == XCB_BUTTON_INDEX_1)) { floating_drag_window(floatingcon, event); return 1; } @@ -320,8 +325,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod } /* 8: otherwise, check for border/decoration clicks and resize */ else if ((dest == CLICK_BORDER || dest == CLICK_DECORATION) && - (event->detail == XCB_BUTTON_INDEX_1 || - event->detail == XCB_BUTTON_INDEX_3)) { + is_left_or_right_click) { DLOG("Trying to resize (tiling)\n"); tiling_resize(con, event, dest); } From f35b666631f2a8aff819442f45b776d951f4752b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 1 Apr 2015 17:46:53 +0200 Subject: [PATCH 044/243] Update documentation to state that the configuration file is read by the custom parser as well. --- docs/hacking-howto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hacking-howto b/docs/hacking-howto index 12d6b14e..8d459791 100644 --- a/docs/hacking-howto +++ b/docs/hacking-howto @@ -686,9 +686,9 @@ all commands. In earlier versions of i3, interpreting these commands was done using lex and yacc, but experience has shown that lex and yacc are not well suited for our command language. Therefore, starting from version 4.2, we use a custom parser -for user commands (not yet for the configuration file). +for user commands and the configuration file. The input specification for this parser can be found in the file -+parser-specs/commands.spec+. Should you happen to use Vim as an editor, use ++parser-specs/*.spec+. Should you happen to use Vim as an editor, use :source parser-specs/highlighting.vim to get syntax highlighting for this file (highlighting files for other editors are welcome). From 37811b67b03f8d40fc884e8888de9e2f923b5b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 1 Apr 2015 17:47:17 +0200 Subject: [PATCH 045/243] Update the definition of the workspace spec and describe it. --- docs/hacking-howto | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/hacking-howto b/docs/hacking-howto index 8d459791..9fc5c631 100644 --- a/docs/hacking-howto +++ b/docs/hacking-howto @@ -729,11 +729,14 @@ features. This is its definition: # workspace next|prev|next_on_output|prev_on_output # workspace back_and_forth # workspace +# workspace number state WORKSPACE: direction = 'next_on_output', 'prev_on_output', 'next', 'prev' -> call cmd_workspace($direction) 'back_and_forth' -> call cmd_workspace_back_and_forth() + 'number' + -> WORKSPACE_NUMBER workspace = string -> call cmd_workspace_name($workspace) ---------------------------------------------------------------- @@ -772,6 +775,10 @@ workspace :: single quotes), but just called string. Other possible tokens are word (the same as string, but stops matching at a whitespace) and end (matches the end of the input). +workspace number :: + The workspace command has to be followed by the keyword +number+. It + then transitions into the state +WORKSPACE_NUMBER+, where the actual + parameter will be read. === Introducing a new command From fec96c57bc9388f904b4bbd901e7f07cd8bf8d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 1 Apr 2015 17:47:38 +0200 Subject: [PATCH 046/243] Reworded the documentation slightly and fixed the link to correctly point to Github. --- docs/hacking-howto | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/hacking-howto b/docs/hacking-howto index 9fc5c631..71919e30 100644 --- a/docs/hacking-howto +++ b/docs/hacking-howto @@ -959,18 +959,21 @@ http://web.archive.org/web/20121024222556/http://www.spheredev.org/wiki/Git_for_ or, for more documentation, see http://git-scm.com/documentation Please talk to us before working on new features to see whether they will be -accepted. There are a few things which we don’t want to see in i3, e.g. a -command which will focus windows in an alt+tab like way. +accepted. A good way for this is to open an issue and asking for opinions on it. +Even for accepted features, this can be a good way to refine an idea upfront. However, +we don't want to see certain features in i3, e.g., switching window focus in an +Alt+Tab like way. When working on bugfixes, please make sure you mention that you are working on -it in the corresponding bugreport at https://github.com/i3/i3/issues In case -there is no bugreport yet, please create one. +it in the corresponding bug report at https://github.com/i3/i3/issues. In case +there is no bug report yet, please create one. -After you are done, please submit your work for review at https://github.com/i3/i3 +After you are done, please submit your work for review as a pull request at +https://github.com/i3/i3. Do not send emails to the mailing list or any author directly, and don’t submit them in the bugtracker, since all reviews should be done in public at -http://cr.i3wm.org/. In order to make your review go as fast as possible, you +https://github.com/i3/i3. In order to make your review go as fast as possible, you could have a look at previous reviews and see what the common mistakes are. === Which branch to use? From 5d8dfe0ec546a59dd30f1207d1ef23e26db0e2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 1 Apr 2015 17:45:53 +0200 Subject: [PATCH 047/243] Update docs to clarify that split containers get a representation of their children in the decoration --- docs/hacking-howto | 4 ++-- docs/userguide | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/hacking-howto b/docs/hacking-howto index 71919e30..4219e961 100644 --- a/docs/hacking-howto +++ b/docs/hacking-howto @@ -629,8 +629,8 @@ unmapped if it should not be visible anymore. +WM_STATE+ will be set to +x_draw_decoration+ draws window decorations. It is run for every leaf container (representing an actual X11 window) and for every non-leaf container which is in a stacked/tabbed container (because stacked/tabbed containers -display a window decoration for split containers, which at the moment just says -"another container"). +display a window decoration for split containers, which consists of a representation +of the child container's names. Then, parameters are collected to be able to determine whether this decoration drawing is actually necessary or was already done. This saves a substantial diff --git a/docs/userguide b/docs/userguide index 98629761..547c7ba7 100644 --- a/docs/userguide +++ b/docs/userguide @@ -256,8 +256,9 @@ workspace node’s orientation will be changed to +vertical+. The terminal windo you moved down is directly attached to the workspace and appears on the bottom of the screen. A new (horizontal) container was created to accommodate the other two terminal windows. You will notice this when switching to tabbed mode -(for example). You would end up having one tab called "another container" and -the other one being the terminal window you moved down. +(for example). You would end up having one tab with a representation of the split +container (e.g., "H[urxvt firefox]") and the other one being the terminal window +you moved down. [[configuring]] == Configuring i3 From df0e24cd2d15e32f2987ea66b3c2790fbae5d459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 1 Apr 2015 17:46:20 +0200 Subject: [PATCH 048/243] Clarify that more than one atom is handled by i3 and describe briefly in which way. --- docs/hacking-howto | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/hacking-howto b/docs/hacking-howto index 4219e961..e6313f7d 100644 --- a/docs/hacking-howto +++ b/docs/hacking-howto @@ -404,10 +404,14 @@ can reconfigure themselves). == _NET_WM_STATE -Only the _NET_WM_STATE_FULLSCREEN atom is handled. It calls -``toggle_fullscreen()'' for the specific client which just configures the -client to use the whole screen on which it currently is. Also, it is set as -fullscreen_client for the i3Screen. +Only the _NET_WM_STATE_FULLSCREEN and _NET_WM_STATE_DEMANDS_ATTENTION atoms +are handled. + +The former calls ``toggle_fullscreen()'' for the specific client which just +configures the client to use the whole screen on which it currently is. +Also, it is set as fullscreen_client for the i3Screen. + +The latter is used to set, read and display urgency hints. == WM_NAME From e3e13ade60b2b14f64549e60f5f36252605a6154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 1 Apr 2015 23:13:25 +0200 Subject: [PATCH 049/243] Allow --whole-window right after 'bindsym' within binding modes fixes #1629 --- parser-specs/config.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/parser-specs/config.spec b/parser-specs/config.spec index 433e1d11..d27e0792 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -349,6 +349,8 @@ state MODE_IGNORE_LINE: state MODE_BINDING: release = '--release' -> + whole_window = '--whole-window' + -> modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl', 'Mode_switch', '$mod' -> '+' From 42a666be3ccc5340f6e1577378e30521420c5583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Thu, 2 Apr 2015 11:17:29 +0200 Subject: [PATCH 050/243] Added testcases for --whole-window in a binding inside a mode (#1629) --- testcases/t/201-config-parser.t | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 0f22878d..9ec8b5eb 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -45,6 +45,8 @@ mode "meh" { bindsym Mod1 + Shift + x resize grow bindcode Mod1+44 resize shrink bindsym --release Mod1+x exec foo + bindsym --whole-window button3 nop + bindsym --release --whole-window button3 nop } EOT @@ -53,11 +55,13 @@ cfg_enter_mode(meh) cfg_mode_binding(bindsym, Mod1,Shift, x, (null), (null), resize grow) cfg_mode_binding(bindcode, Mod1, 44, (null), (null), resize shrink) cfg_mode_binding(bindsym, Mod1, x, --release, (null), exec foo) +cfg_mode_binding(bindsym, (null), button3, (null), --whole-window, nop) +cfg_mode_binding(bindsym, (null), button3, --release, --whole-window, nop) EOT is(parser_calls($config), $expected, - 'single number (move workspace 3) ok'); + 'mode bindings ok'); ################################################################################ # exec and exec_always From ce48d5c5d735ff63f5bccd39ed331808f4df16cc Mon Sep 17 00:00:00 2001 From: Deiz Date: Wed, 1 Apr 2015 21:43:46 -0400 Subject: [PATCH 051/243] Add a --border flag to enable mouse binds to trigger on border click --- include/bindings.h | 3 ++- include/config_directives.h | 4 ++-- include/data.h | 4 ++++ parser-specs/config.spec | 12 ++++++++++-- src/bindings.c | 4 +++- src/click.c | 5 +++-- src/config_directives.c | 8 ++++---- testcases/t/201-config-parser.t | 12 ++++++------ 8 files changed, 34 insertions(+), 18 deletions(-) diff --git a/include/bindings.h b/include/bindings.h index 19345f8c..c20152e9 100644 --- a/include/bindings.h +++ b/include/bindings.h @@ -24,7 +24,8 @@ const char *DEFAULT_BINDING_MODE; * */ Binding *configure_binding(const char *bindtype, const char *modifiers, const char *input_code, - const char *release, const char *whole_window, const char *command, const char *mode); + const char *release, const char *border, const char *whole_window, + const char *command, const char *mode); /** * Grab the bound keys (tell X to send us keypress events for those keycodes) diff --git a/include/config_directives.h b/include/config_directives.h index f5039624..e24c834b 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -64,10 +64,10 @@ CFGFUN(color_single, const char *colorclass, const char *color); CFGFUN(floating_modifier, const char *modifiers); CFGFUN(new_window, const char *windowtype, const char *border, const long width); CFGFUN(workspace, const char *workspace, const char *output); -CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command); +CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command); CFGFUN(enter_mode, const char *mode); -CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command); +CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command); CFGFUN(bar_font, const char *font); CFGFUN(bar_separator_symbol, const char *separator); diff --git a/include/data.h b/include/data.h index 50e1f180..43862263 100644 --- a/include/data.h +++ b/include/data.h @@ -255,6 +255,10 @@ struct Binding { B_UPON_KEYRELEASE_IGNORE_MODS = 2, } release; + /** If this is true for a mouse binding, the binding should be executed + * when the button is pressed over the window border. */ + bool border; + /** If this is true for a mouse binding, the binding should be executed * when the button is pressed over any part of the window, not just the * title bar (default). */ diff --git a/parser-specs/config.spec b/parser-specs/config.spec index d27e0792..da534a38 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -300,6 +300,8 @@ state FONT: state BINDING: release = '--release' -> + border = '--border' + -> whole_window = '--whole-window' -> modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl', 'Mode_switch', '$mod' @@ -312,10 +314,12 @@ state BINDING: state BINDCOMMAND: release = '--release' -> + border = '--border' + -> whole_window = '--whole-window' -> command = string - -> call cfg_binding($bindtype, $modifiers, $key, $release, $whole_window, $command) + -> call cfg_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $command) ################################################################################ # Mode configuration @@ -349,6 +353,8 @@ state MODE_IGNORE_LINE: state MODE_BINDING: release = '--release' -> + border = '--border' + -> whole_window = '--whole-window' -> modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl', 'Mode_switch', '$mod' @@ -361,10 +367,12 @@ state MODE_BINDING: state MODE_BINDCOMMAND: release = '--release' -> + border = '--border' + -> whole_window = '--whole-window' -> command = string - -> call cfg_mode_binding($bindtype, $modifiers, $key, $release, $whole_window, $command); MODE + -> call cfg_mode_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $command); MODE ################################################################################ # Bar configuration (i3bar) diff --git a/src/bindings.c b/src/bindings.c index cbac2dfd..e83e0acc 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -49,10 +49,12 @@ static struct Mode *mode_from_name(const char *name) { * */ Binding *configure_binding(const char *bindtype, const char *modifiers, const char *input_code, - const char *release, const char *whole_window, const char *command, const char *modename) { + const char *release, const char *border, const char *whole_window, + const char *command, const char *modename) { Binding *new_binding = scalloc(sizeof(Binding)); DLOG("bindtype %s, modifiers %s, input code %s, release %s\n", bindtype, modifiers, input_code, release); new_binding->release = (release != NULL ? B_UPON_KEYRELEASE : B_UPON_KEYPRESS); + new_binding->border = (border != NULL); new_binding->whole_window = (whole_window != NULL); if (strcmp(bindtype, "bindsym") == 0) { new_binding->input_type = (strncasecmp(input_code, "button", (sizeof("button") - 1)) == 0 diff --git a/src/click.c b/src/click.c index 3cd367cc..40884c34 100644 --- a/src/click.c +++ b/src/click.c @@ -185,12 +185,13 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod /* if the user has bound an action to this click, it should override the * default behavior. */ - if (dest == CLICK_DECORATION || dest == CLICK_INSIDE) { + if (dest == CLICK_DECORATION || dest == CLICK_INSIDE || dest == CLICK_BORDER) { Binding *bind = get_binding_from_xcb_event((xcb_generic_event_t *)event); /* clicks over a window decoration will always trigger the binding and * clicks on the inside of the window will only trigger a binding if * the --whole-window flag was given for the binding. */ - if (bind && (dest == CLICK_DECORATION || bind->whole_window)) { + if (bind && ((dest == CLICK_DECORATION || bind->whole_window) || + (dest == CLICK_BORDER && bind->border))) { CommandResult *result = run_binding(bind, con); /* ASYNC_POINTER eats the event */ diff --git a/src/config_directives.c b/src/config_directives.c index 398e53bb..daf4339b 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -171,8 +171,8 @@ CFGFUN(font, const char *font) { font_pattern = sstrdup(font); } -CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command) { - configure_binding(bindtype, modifiers, key, release, whole_window, command, DEFAULT_BINDING_MODE); +CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command) { + configure_binding(bindtype, modifiers, key, release, border, whole_window, command, DEFAULT_BINDING_MODE); } /******************************************************************************* @@ -181,8 +181,8 @@ CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, co static char *current_mode; -CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command) { - configure_binding(bindtype, modifiers, key, release, whole_window, command, current_mode); +CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command) { + configure_binding(bindtype, modifiers, key, release, border, whole_window, command, current_mode); } CFGFUN(enter_mode, const char *modename) { diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 9ec8b5eb..8664aac3 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -52,11 +52,11 @@ EOT my $expected = <<'EOT'; cfg_enter_mode(meh) -cfg_mode_binding(bindsym, Mod1,Shift, x, (null), (null), resize grow) -cfg_mode_binding(bindcode, Mod1, 44, (null), (null), resize shrink) -cfg_mode_binding(bindsym, Mod1, x, --release, (null), exec foo) -cfg_mode_binding(bindsym, (null), button3, (null), --whole-window, nop) -cfg_mode_binding(bindsym, (null), button3, --release, --whole-window, nop) +cfg_mode_binding(bindsym, Mod1,Shift, x, (null), (null), (null), resize grow) +cfg_mode_binding(bindcode, Mod1, 44, (null), (null), (null), resize shrink) +cfg_mode_binding(bindsym, Mod1, x, --release, (null), (null), exec foo) +cfg_mode_binding(bindsym, (null), button3, (null), (null), --whole-window, nop) +cfg_mode_binding(bindsym, (null), button3, --release, (null), --whole-window, nop) EOT is(parser_calls($config), @@ -624,7 +624,7 @@ EOT $expected = <<'EOT'; cfg_enter_mode(yo) -cfg_mode_binding(bindsym, (null), x, (null), (null), resize shrink left) +cfg_mode_binding(bindsym, (null), x, (null), (null), (null), resize shrink left) ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', '}' ERROR: CONFIG: (in file ) ERROR: CONFIG: Line 1: mode "yo" { From 601043cbf34740bb345736a230e434f71a188f1e Mon Sep 17 00:00:00 2001 From: Deiz Date: Thu, 2 Apr 2015 16:43:54 -0400 Subject: [PATCH 052/243] Update userguide for --border --- docs/userguide | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/userguide b/docs/userguide index 547c7ba7..13ff3fe5 100644 --- a/docs/userguide +++ b/docs/userguide @@ -405,13 +405,16 @@ can configure mouse bindings in a similar way to key bindings. *Syntax*: ---------------------------------- -bindsym [--release] [--whole-window] [Modifiers+]button[n] command +bindsym [--release] [--border] [--whole-window] [Modifiers+]button[n] command ---------------------------------- By default, the binding will only run when you click on the titlebar of the -window. If the +--whole-window+ flag is given, it will run when any part of the -window is clicked. If the +--release+ flag is given, it will run when the mouse -button is released. +window. If the +--release+ flag is given, it will run when the mouse button +is released. + +If the +--whole-window+ flag is given, the binding will also run when any part +of the window is clicked, with the exception of the border. To have a bind run +when the border is clicked, specify the +--border+ flag. *Examples*: -------------------------------- From 547157d19bc73763f5d676dde23b1474a7254599 Mon Sep 17 00:00:00 2001 From: Deiz Date: Thu, 2 Apr 2015 16:46:42 -0400 Subject: [PATCH 053/243] Add test cases for --border --- testcases/t/201-config-parser.t | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 8664aac3..7568de48 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -47,6 +47,8 @@ mode "meh" { bindsym --release Mod1+x exec foo bindsym --whole-window button3 nop bindsym --release --whole-window button3 nop + bindsym --border button3 nop + bindsym --release --border button3 nop } EOT @@ -57,6 +59,8 @@ cfg_mode_binding(bindcode, Mod1, 44, (null), (null), (null), resize shrink) cfg_mode_binding(bindsym, Mod1, x, --release, (null), (null), exec foo) cfg_mode_binding(bindsym, (null), button3, (null), (null), --whole-window, nop) cfg_mode_binding(bindsym, (null), button3, --release, (null), --whole-window, nop) +cfg_mode_binding(bindsym, (null), button3, (null), --border, (null), nop) +cfg_mode_binding(bindsym, (null), button3, --release, --border, (null), nop) EOT is(parser_calls($config), From a952ae74f4d31b5ce0b0a0e04252d44416b6d86e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 3 Apr 2015 22:54:59 +0200 Subject: [PATCH 054/243] Use a reasonable default sep_block_width if a separator_symbol is given --- docs/userguide | 3 +-- i3bar/include/xcb.h | 3 +++ i3bar/src/child.c | 5 ++++- i3bar/src/xcb.c | 3 --- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/userguide b/docs/userguide index 547c7ba7..687dff10 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1319,8 +1319,7 @@ bar { === Custom separator symbol Specifies a custom symbol to be used for the separator as opposed to the vertical, -one pixel thick separator. Note that you may have to adjust the +sep_block_width+ -property. +one pixel thick separator. *Syntax*: ------------------------- diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 8e48c0c1..bb37e7d5 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -44,6 +44,9 @@ struct xcb_color_strings_t { typedef struct xcb_colors_t xcb_colors_t; +/* Cached width of the custom separator if one was set */ +int separator_symbol_width; + /* * Early initialization of the connection to X11: Everything which does not * depend on 'config'. diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 9cc50f2a..41f8880d 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -162,7 +162,10 @@ static int stdin_start_map(void *context) { memset(&(ctx->block), '\0', sizeof(struct status_block)); /* Default width of the separator block. */ - ctx->block.sep_block_width = logical_px(9); + if (config.separator_symbol == NULL) + ctx->block.sep_block_width = logical_px(9); + else + ctx->block.sep_block_width = logical_px(8) + separator_symbol_width; return 1; } diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index e53b9226..ba57b9fa 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -63,9 +63,6 @@ static i3Font font; /* Overall height of the bar (based on font size) */ int bar_height; -/* Cached width of the custom separator if one was set */ -int separator_symbol_width; - /* These are only relevant for XKB, which we only need for grabbing modifiers */ int xkb_base; int mod_pressed = 0; From 1546891e6ab008b0383ebffe85ec0e761f58b7e1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 6 Apr 2015 15:40:12 +0200 Subject: [PATCH 055/243] Bugfix: Remove windows from the save set when unmapping. fixes #1617 --- src/tree.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tree.c b/src/tree.c index b40ba2a2..753b02fc 100644 --- a/src/tree.c +++ b/src/tree.c @@ -253,6 +253,13 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool cookie = xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->window->id, A_WM_STATE, A_WM_STATE, 32, 2, data); + /* Remove the window from the save set. All windows in the save set + * will be mapped when i3 closes its connection (e.g. when + * restarting). This is not what we want, since some apps keep + * unmapped windows around and don’t expect them to suddenly be + * mapped. See http://bugs.i3wm.org/1617 */ + xcb_change_save_set(conn, XCB_SET_MODE_DELETE, con->window->id); + /* Ignore X11 errors for the ReparentWindow request. * X11 Errors are returned when the window was already destroyed */ add_ignore_event(cookie.sequence, 0); From cd4bc2adf5743bcf8b398a5beea9d5c1df690fe0 Mon Sep 17 00:00:00 2001 From: Deiz Date: Mon, 6 Apr 2015 18:28:40 -0400 Subject: [PATCH 056/243] Store Git commit identifier in its own object Fixes #1640 --- include/i3.h | 3 +++ src/config_parser.c | 2 +- src/ipc.c | 2 +- src/main.c | 8 ++++---- src/version.c | 11 +++++++++++ 5 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 src/version.c diff --git a/include/i3.h b/include/i3.h index 5ca87541..70ebc000 100644 --- a/include/i3.h +++ b/include/i3.h @@ -24,6 +24,9 @@ #include "data.h" #include "xcb.h" +/** Git commit identifier, from version.c */ +extern const char *i3_version; + /** The original value of RLIMIT_CORE when i3 was started. We need to restore * this before starting any other process, since we set RLIMIT_CORE to * RLIM_INFINITY for i3 debugging versions. */ diff --git a/src/config_parser.c b/src/config_parser.c index eef03cae..f3254812 100644 --- a/src/config_parser.c +++ b/src/config_parser.c @@ -996,7 +996,7 @@ bool parse_file(const char *f, bool use_nagbar) { check_for_duplicate_bindings(context); if (use_nagbar && (context->has_errors || context->has_warnings)) { - ELOG("FYI: You are using i3 version " I3_VERSION "\n"); + ELOG("FYI: You are using i3 version %s\n", i3_version); if (version == 3) ELOG("Please convert your configfile first, then fix any remaining errors (see above).\n"); diff --git a/src/ipc.c b/src/ipc.c index 8fed75f1..f8138f0a 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -791,7 +791,7 @@ IPC_HANDLER(get_version) { y(integer, PATCH_VERSION); ystr("human_readable"); - ystr(I3_VERSION); + ystr(i3_version); y(map_close); diff --git a/src/main.c b/src/main.c index 8b514178..ac40e7a3 100644 --- a/src/main.c +++ b/src/main.c @@ -188,7 +188,7 @@ static void handle_signal(int sig, siginfo_t *info, void *data) { int main(int argc, char *argv[]) { /* Keep a symbol pointing to the I3_VERSION string constant so that we have * it in gdb backtraces. */ - const char *i3_version __attribute__((unused)) = I3_VERSION; + const char *_i3_version __attribute__((unused)) = i3_version; char *override_configpath = NULL; bool autostart = true; char *layout_path = NULL; @@ -261,11 +261,11 @@ int main(int argc, char *argv[]) { only_check_config = true; break; case 'v': - printf("i3 version " I3_VERSION " © 2009-2014 Michael Stapelberg and contributors\n"); + printf("i3 version %s © 2009-2014 Michael Stapelberg and contributors\n", i3_version); exit(EXIT_SUCCESS); break; case 'm': - printf("Binary i3 version: " I3_VERSION " © 2009-2014 Michael Stapelberg and contributors\n"); + printf("Binary i3 version: %s © 2009-2014 Michael Stapelberg and contributors\n", i3_version); display_running_version(); exit(EXIT_SUCCESS); break; @@ -456,7 +456,7 @@ int main(int argc, char *argv[]) { free(cwd); } - LOG("i3 " I3_VERSION " starting\n"); + LOG("i3 %s starting\n", i3_version); conn = xcb_connect(NULL, &conn_screen); if (xcb_connection_has_error(conn)) diff --git a/src/version.c b/src/version.c new file mode 100644 index 00000000..d7d31b36 --- /dev/null +++ b/src/version.c @@ -0,0 +1,11 @@ +/* + * vim:ts=4:sw=4:expandtab + * + * i3 - an improved dynamic tiling window manager + * © 2009-2015 Michael Stapelberg and contributors (see also: LICENSE) + * + * Stores the latest Git commit identifier so that it can be linked into i3 + * and used dynamically without recompiling every object file. + * + */ +const char *i3_version = I3_VERSION; From edda9306ed6ea940a4310b1b606e3b5e866741f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sat, 11 Apr 2015 10:27:42 +0200 Subject: [PATCH 057/243] Removed comment on removal of legacy "default" layout. closes #1649 --- src/con.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/con.c b/src/con.c index 41dd0196..dab8d29d 100644 --- a/src/con.c +++ b/src/con.c @@ -1355,11 +1355,7 @@ void con_set_layout(Con *con, layout_t layout) { * with an orientation). Since we switched to splith/splitv layouts, * using the "default" layout (which "only" should happen when using * legacy configs) is using the last split layout (either splith or - * splitv) in order to still do the same thing. - * - * Starting from v4.6 though, we will nag users about using "layout - * default", and in v4.9 we will remove it entirely (with an - * appropriate i3-migrate-config mechanism). */ + * splitv) in order to still do the same thing. */ con->layout = con->last_split_layout; /* In case last_split_layout was not initialized… */ if (con->layout == L_DEFAULT) From 2c77d7ceed298caf17a78b382e23af2e48377021 Mon Sep 17 00:00:00 2001 From: hwangcc Date: Fri, 3 Apr 2015 16:16:38 +0800 Subject: [PATCH 058/243] Add a timeout: delay_exit_on_zero_displays Outputs may disappear momentarily and come back later. To prevent i3 from exit when no output is available momentarily, add a timeout delay_exit_on_zero_displays. --- docs/userguide | 25 ++++++++++++++++++ include/config.h | 4 +++ include/config_directives.h | 1 + parser-specs/config.spec | 12 +++++++++ src/config.c | 4 +++ src/config_directives.c | 4 +++ src/main.c | 2 ++ src/randr.c | 45 +++++++++++++++++++++++++++------ testcases/t/201-config-parser.t | 36 +++++++++++++++++++++++++- 9 files changed, 124 insertions(+), 9 deletions(-) diff --git a/docs/userguide b/docs/userguide index 687dff10..66ba2cf8 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1003,6 +1003,31 @@ force_display_urgency_hint ms force_display_urgency_hint 500 ms --------------------------------- +=== Delaying exiting on zero displays + +Outputs may disappear momentarily and come back later. For example, +using a docking station that does not announce the undock (e.g. ACPI Undock +event triggered through manually pushing a button before actually ejecting +the notebook). During the removal of the notebook from the docking station, +all outputs disappear momentarily. + +To prevent i3 from exiting when no output is available momentarily, you can +tell i3 to delay a certain time first and check available outputs again using +the +delay_exit_on_zero_displays+ directive. Setting the value to 0 disables +this feature. + +The default is 500ms. + +*Syntax*: +---------------------------------------- +delay_exit_on_zero_displays ms +---------------------------------------- + +*Example*: +---------------------------------- +delay_exit_on_zero_displays 500 ms +---------------------------------- + === Focus on window activation [[focus_on_window_activation]] diff --git a/include/config.h b/include/config.h index fb11cbe3..d2f1f206 100644 --- a/include/config.h +++ b/include/config.h @@ -167,6 +167,10 @@ struct Config { * flag can be delayed using an urgency timer. */ float workspace_urgency_timer; + /** Use a timer to delay exiting when no output is available. + * This can prevent i3 from exiting when all outputs disappear momentarily. */ + float zero_disp_exit_timer_ms; + /** Behavior when a window sends a NET_ACTIVE_WINDOW message. */ enum { /* Focus if the target workspace is visible, set urgency hint otherwise. */ diff --git a/include/config_directives.h b/include/config_directives.h index f5039624..7c9cfb66 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -51,6 +51,7 @@ CFGFUN(force_focus_wrapping, const char *value); CFGFUN(force_xinerama, const char *value); CFGFUN(fake_outputs, const char *outputs); CFGFUN(force_display_urgency_hint, const long duration_ms); +CFGFUN(delay_exit_on_zero_displays, const long duration_ms); CFGFUN(focus_on_window_activation, const char *mode); CFGFUN(show_marks, const char *value); CFGFUN(hide_edge_borders, const char *borders); diff --git a/parser-specs/config.spec b/parser-specs/config.spec index d27e0792..a0356888 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -39,6 +39,7 @@ state INITIAL: 'workspace_auto_back_and_forth' -> WORKSPACE_BACK_AND_FORTH 'fake_outputs', 'fake-outputs' -> FAKE_OUTPUTS 'force_display_urgency_hint' -> FORCE_DISPLAY_URGENCY_HINT + 'delay_exit_on_zero_displays' -> DELAY_EXIT_ON_ZERO_DISPLAYS 'focus_on_window_activation' -> FOCUS_ON_WINDOW_ACTIVATION 'show_marks' -> SHOW_MARKS 'workspace' -> WORKSPACE @@ -227,6 +228,17 @@ state FORCE_DISPLAY_URGENCY_HINT_MS: end -> call cfg_force_display_urgency_hint(&duration_ms) +# delay_exit_on_zero_displays ms +state DELAY_EXIT_ON_ZERO_DISPLAYS: + duration_ms = number + -> DELAY_EXIT_ON_ZERO_DISPLAYS_MS + +state DELAY_EXIT_ON_ZERO_DISPLAYS_MS: + 'ms' + -> + end + -> call cfg_delay_exit_on_zero_displays(&duration_ms) + # focus_on_window_activation state FOCUS_ON_WINDOW_ACTIVATION: mode = word diff --git a/src/config.c b/src/config.c index 8a1cb99c..117ad571 100644 --- a/src/config.c +++ b/src/config.c @@ -203,6 +203,10 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, if (config.workspace_urgency_timer == 0) config.workspace_urgency_timer = 0.5; + /* Set default zero displays exit delay to 500ms */ + if (config.zero_disp_exit_timer_ms == 0) + config.zero_disp_exit_timer_ms = 500; + parse_configuration(override_configpath, true); if (reload) { diff --git a/src/config_directives.c b/src/config_directives.c index 398e53bb..af0cf2eb 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -329,6 +329,10 @@ CFGFUN(force_display_urgency_hint, const long duration_ms) { config.workspace_urgency_timer = duration_ms / 1000.0; } +CFGFUN(delay_exit_on_zero_displays, const long duration_ms) { + config.zero_disp_exit_timer_ms = duration_ms; +} + CFGFUN(focus_on_window_activation, const char *mode) { if (strcmp(mode, "smart") == 0) config.focus_on_window_activation = FOWA_SMART; diff --git a/src/main.c b/src/main.c index 8b514178..91478afa 100644 --- a/src/main.c +++ b/src/main.c @@ -621,6 +621,8 @@ int main(int argc, char *argv[]) { ELOG("ERROR: No screen at (%d, %d), starting on the first screen\n", pointerreply->root_x, pointerreply->root_y); output = get_first_output(); + if (!output) + die("No usable outputs available.\n"); } con_focus(con_descend_focused(output_get_content(output->con))); diff --git a/src/randr.c b/src/randr.c index a4a0f6fd..2ef21119 100644 --- a/src/randr.c +++ b/src/randr.c @@ -69,7 +69,7 @@ Output *get_first_output(void) { if (output->active) return output; - die("No usable outputs available.\n"); + return NULL; } /* @@ -564,6 +564,8 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, if (!new->active) { DLOG("width/height 0/0, disabling output\n"); return; + } else { + new->to_be_disabled = false; } DLOG("mode: %dx%d+%d+%d\n", new->rect.width, new->rect.height, @@ -585,11 +587,7 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, new->changed = true; } -/* - * (Re-)queries the outputs via RandR and stores them in the list of outputs. - * - */ -void randr_query_outputs(void) { +static bool __randr_query_outputs(void) { Output *output, *other, *first; xcb_randr_get_output_primary_cookie_t pcookie; xcb_randr_get_screen_resources_current_cookie_t rcookie; @@ -603,7 +601,7 @@ void randr_query_outputs(void) { xcb_randr_output_t *randr_outputs; if (randr_disabled) - return; + return true; /* Get screen resources (primary output, crtcs, outputs, modes) */ rcookie = xcb_randr_get_screen_resources_current(conn, root); @@ -615,7 +613,7 @@ void randr_query_outputs(void) { DLOG("primary output is %08x\n", primary->output); if ((res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL)) == NULL) { disable_randr(conn); - return; + return true; } cts = res->config_timestamp; @@ -697,6 +695,11 @@ void randr_query_outputs(void) { DLOG("Output %s disabled, re-assigning workspaces/docks\n", output->name); first = get_first_output(); + if (!first) { + FREE(res); + FREE(primary); + return false; + } /* TODO: refactor the following code into a nice function. maybe * use an on_destroy callback which is implement differently for @@ -812,6 +815,32 @@ void randr_query_outputs(void) { FREE(res); FREE(primary); + + return true; +} + +/* + * (Re-)queries the outputs via RandR and stores them in the list of outputs. + * + */ +void randr_query_outputs(void) { + static bool first_query = true; + + if (first_query) { + /* find monitors at least once via RandR */ + if (!__randr_query_outputs()) + die("No usable outputs available.\n"); + first_query = false; + } else { + /* requery */ + if (!__randr_query_outputs()) { + DLOG("sleep %f ms due to zero displays\n", config.zero_disp_exit_timer_ms); + usleep(config.zero_disp_exit_timer_ms * 1000); + + if (!__randr_query_outputs()) + die("No usable outputs available.\n"); + } + } } /* diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 9ec8b5eb..bb2ddf89 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -365,6 +365,40 @@ is(parser_calls($config), $expected, 'force_display_urgency_hint ok'); +################################################################################ +# delay_exit_on_zero_displays +################################################################################ + +is(parser_calls('delay_exit_on_zero_displays 300'), + "cfg_delay_exit_on_zero_displays(300)\n", + 'delay_exit_on_zero_displays ok'); + +is(parser_calls('delay_exit_on_zero_displays 500 ms'), + "cfg_delay_exit_on_zero_displays(500)\n", + 'delay_exit_on_zero_displays ok'); + +is(parser_calls('delay_exit_on_zero_displays 700ms'), + "cfg_delay_exit_on_zero_displays(700)\n", + 'delay_exit_on_zero_displays ok'); + +$config = <<'EOT'; +delay_exit_on_zero_displays 300 +delay_exit_on_zero_displays 500 ms +delay_exit_on_zero_displays 700ms +delay_exit_on_zero_displays 700 +EOT + +$expected = <<'EOT'; +cfg_delay_exit_on_zero_displays(300) +cfg_delay_exit_on_zero_displays(500) +cfg_delay_exit_on_zero_displays(700) +cfg_delay_exit_on_zero_displays(700) +EOT + +is(parser_calls($config), + $expected, + 'delay_exit_on_zero_displays ok'); + ################################################################################ # workspace ################################################################################ @@ -437,7 +471,7 @@ client.focused #4c7899 #285577 #ffffff #2e9ef4 EOT my $expected_all_tokens = <<'EOT'; -ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'no_focus', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'show_marks', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' +ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'no_focus', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'delay_exit_on_zero_displays', 'focus_on_window_activation', 'show_marks', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' EOT my $expected_end = <<'EOT'; From 2a4524a1e1de0f86751d4aa57814290826c6aed9 Mon Sep 17 00:00:00 2001 From: Nikita Mikhailov Date: Sat, 11 Apr 2015 16:00:57 +0500 Subject: [PATCH 059/243] Bump testsuite dependencies versions --- testcases/Makefile.PL | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testcases/Makefile.PL b/testcases/Makefile.PL index f2c15013..3c2a26f9 100755 --- a/testcases/Makefile.PL +++ b/testcases/Makefile.PL @@ -8,8 +8,8 @@ WriteMakefile( MIN_PERL_VERSION => '5.010000', # 5.10.0 PREREQ_PM => { 'AnyEvent' => 0, - 'AnyEvent::I3' => '0.15', - 'X11::XCB' => '0.09', + 'AnyEvent::I3' => '0.16', + 'X11::XCB' => '0.12', 'Inline' => 0, 'Inline::C' => 0, 'ExtUtils::PkgConfig' => 0, From 5a987cfd6bef1366c881fba4ef14a53c44c643d4 Mon Sep 17 00:00:00 2001 From: Deiz Date: Tue, 7 Apr 2015 13:27:35 -0400 Subject: [PATCH 060/243] Rebuild version.o when version.c or LAST_VERSION change $(TOPDIR)/LAST_VERSION is a cached copy of common.mk's I3_VERSION var, updated only if the two differ. --- .gitignore | 1 + Makefile | 6 ++++++ src/i3.mk | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1d4c1678..617421ac 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ docs/*.html i3-command-parser.stamp i3-config-parser.stamp .clang_complete +LAST_VERSION diff --git a/Makefile b/Makefile index 1fed4df1..fd302101 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,12 @@ include i3-dump-log/i3-dump-log.mk include docs/docs.mk include man/man.mk +# Update $(TOPDIR)/LAST_VERSION if it differs from $I3_VERSION +CACHED_VERSION := '$(shell [ -f $(TOPDIR)/LAST_VERSION ] && cat $(TOPDIR)/LAST_VERSION)' +ifneq ($(CACHED_VERSION),$(I3_VERSION)) +$(shell echo -n ${I3_VERSION} > $(TOPDIR)/LAST_VERSION) +endif + real-all: $(ALL_TARGETS) install: $(INSTALL_TARGETS) diff --git a/src/i3.mk b/src/i3.mk index 8c763464..cfa9fd16 100644 --- a/src/i3.mk +++ b/src/i3.mk @@ -32,6 +32,10 @@ include/all.h.pch: $(i3_HEADERS) echo "[i3] PCH all.h" $(CC) $(I3_CPPFLAGS) $(XCB_CPPFLAGS) $(CPPFLAGS) $(i3_CFLAGS) $(I3_CFLAGS) $(CFLAGS) -x c-header include/all.h -o include/all.h.pch +src/version.o: src/version.c LAST_VERSION $(i3_HEADERS_DEP) + echo "[i3] CC $<" + $(CC) $(I3_CPPFLAGS) $(XCB_CPPFLAGS) $(CPPFLAGS) $(i3_CFLAGS) $(I3_CFLAGS) $(CFLAGS) $(PCH_FLAGS) -c -o $@ ${canonical_path}/$< + src/%.o: src/%.c $(i3_HEADERS_DEP) echo "[i3] CC $<" $(CC) $(I3_CPPFLAGS) $(XCB_CPPFLAGS) $(CPPFLAGS) $(i3_CFLAGS) $(I3_CFLAGS) $(CFLAGS) $(PCH_FLAGS) -c -o $@ ${canonical_path}/$< @@ -92,4 +96,4 @@ install-i3: i3 clean-i3: echo "[i3] Clean" - rm -f $(i3_OBJECTS) $(i3_SOURCES_GENERATED) $(i3_HEADERS_CMDPARSER) include/loglevels.h loglevels.tmp include/all.h.pch i3-command-parser.stamp i3-config-parser.stamp i3 test.config_parser test.commands_parser src/*.gcno src/cfgparse.* src/cmdparse.* + rm -f $(i3_OBJECTS) $(i3_SOURCES_GENERATED) $(i3_HEADERS_CMDPARSER) include/loglevels.h loglevels.tmp include/all.h.pch i3-command-parser.stamp i3-config-parser.stamp i3 test.config_parser test.commands_parser src/*.gcno src/cfgparse.* src/cmdparse.* LAST_VERSION From e2e949f331fd7ac55d7e1b76eafb0521559bcd5d Mon Sep 17 00:00:00 2001 From: Deiz Date: Sat, 11 Apr 2015 18:52:47 -0400 Subject: [PATCH 061/243] Allow complete-run.pl to be run from any directory --- testcases/complete-run.pl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/testcases/complete-run.pl b/testcases/complete-run.pl index 8a3b89f0..911558e5 100755 --- a/testcases/complete-run.pl +++ b/testcases/complete-run.pl @@ -8,7 +8,6 @@ use v5.10; use utf8; # the following are modules which ship with Perl (>= 5.10): use Pod::Usage; -use Cwd qw(abs_path); use File::Temp qw(tempfile tempdir); use Getopt::Long; use POSIX (); @@ -17,8 +16,20 @@ use TAP::Parser; use TAP::Parser::Aggregator; use Time::HiRes qw(time); use IO::Handle; + +my $dirname; + +BEGIN { + use File::Basename; + use Cwd qw(abs_path); + + # fileparse()[1] contains the directory portion of the specified path. + # See File::Basename(3p) for more details. + $dirname = (fileparse(abs_path($0)))[1]; +} + # these are shipped with the testsuite -use lib qw(lib); +use lib $dirname . 'lib'; use StartXServer; use StatusLine; use TestWorker; @@ -70,6 +81,8 @@ my $result = GetOptions( pod2usage(-verbose => 2, -exitcode => 0) if $help; +chdir $dirname or die "Could not chdir into $dirname"; + # Check for missing executables my @binaries = qw( ../i3 From 196e1d0971e756524d30561b3c3e9a32ce4f5710 Mon Sep 17 00:00:00 2001 From: Thomas Anderson Date: Fri, 10 Apr 2015 14:09:00 -0700 Subject: [PATCH 062/243] Respect EXEC_PREFIX and a users' choice of PKG_CONFIG. The Makefiles should put binaries in $(EXEC_PREFIX) and architecture-independent files in $(PREFIX). Also a user may have a prefixed- pkg-config, as in the case of cross compiling on Exherbo Linux, so respect the well-accepted $(PKG_CONFIG) variable for this purpose. --- common.mk | 14 +++++++++----- i3-config-wizard/i3-config-wizard.mk | 4 ++-- i3-dump-log/i3-dump-log.mk | 4 ++-- i3-input/i3-input.mk | 4 ++-- i3-msg/i3-msg.mk | 4 ++-- i3-nagbar/i3-nagbar.mk | 4 ++-- i3bar/i3bar.mk | 4 ++-- src/i3.mk | 22 +++++++++++----------- 8 files changed, 32 insertions(+), 28 deletions(-) diff --git a/common.mk b/common.mk index dcc90c96..c568fb60 100644 --- a/common.mk +++ b/common.mk @@ -2,9 +2,13 @@ UNAME=$(shell uname) DEBUG=1 INSTALL=install LN=ln +PKG_CONFIG=pkg-config ifndef PREFIX PREFIX=/usr endif +ifndef EXEC_PREFIX + EXEC_PREFIX=$(PREFIX) +endif ifndef SYSCONFDIR ifeq ($(PREFIX),/usr) SYSCONFDIR=/etc @@ -59,7 +63,7 @@ I3_CPPFLAGS += -DI3__FILE__=__FILE__ ## Libraries flags -ifeq ($(shell which pkg-config 2>/dev/null 1>/dev/null || echo 1),1) +ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null 1>/dev/null || echo 1),1) $(error "pkg-config was not found") endif @@ -73,15 +77,15 @@ endif # # We redirect stderr to /dev/null because pkg-config prints an error if support # for gnome-config was enabled but gnome-config is not actually installed. -cflags_for_lib = $(shell pkg-config --silence-errors --cflags $(1) 2>/dev/null) -ldflags_for_lib = $(shell pkg-config --exists 2>/dev/null $(1) && pkg-config --libs $(1) 2>/dev/null || echo -l$(2)) +cflags_for_lib = $(shell $(PKG_CONFIG) --silence-errors --cflags $(1) 2>/dev/null) +ldflags_for_lib = $(shell $(PKG_CONFIG) --exists 2>/dev/null $(1) && $(PKG_CONFIG) --libs $(1) 2>/dev/null || echo -l$(2)) # XCB common stuff XCB_CFLAGS := $(call cflags_for_lib, xcb) XCB_CFLAGS += $(call cflags_for_lib, xcb-event) XCB_LIBS := $(call ldflags_for_lib, xcb,xcb) XCB_LIBS += $(call ldflags_for_lib, xcb-event,xcb-event) -ifeq ($(shell pkg-config --exists xcb-util 2>/dev/null || echo 1),1) +ifeq ($(shell $(PKG_CONFIG) --exists xcb-util 2>/dev/null || echo 1),1) XCB_CFLAGS += $(call cflags_for_lib, xcb-atom) XCB_CFLAGS += $(call cflags_for_lib, xcb-aux) XCB_LIBS += $(call ldflags_for_lib, xcb-atom,xcb-atom) @@ -124,7 +128,7 @@ LIBEV_LIBS := $(call ldflags_for_lib, libev,ev) # libpcre PCRE_CFLAGS := $(call cflags_for_lib, libpcre) -ifeq ($(shell pkg-config --atleast-version=8.10 libpcre 2>/dev/null && echo 1),1) +ifeq ($(shell $(PKG_CONFIG) --atleast-version=8.10 libpcre 2>/dev/null && echo 1),1) I3_CPPFLAGS += -DPCRE_HAS_UCP=1 endif PCRE_LIBS := $(call ldflags_for_lib, libpcre,pcre) diff --git a/i3-config-wizard/i3-config-wizard.mk b/i3-config-wizard/i3-config-wizard.mk index 1dab6452..900893f5 100644 --- a/i3-config-wizard/i3-config-wizard.mk +++ b/i3-config-wizard/i3-config-wizard.mk @@ -20,8 +20,8 @@ i3-config-wizard/i3-config-wizard: libi3.a $(i3_config_wizard_OBJECTS) install-i3-config-wizard: i3-config-wizard/i3-config-wizard echo "[i3-config-wizard] Install" - $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -m 0755 i3-config-wizard/i3-config-wizard $(DESTDIR)$(PREFIX)/bin/ + $(INSTALL) -d -m 0755 $(DESTDIR)$(EXEC_PREFIX)/bin + $(INSTALL) -m 0755 i3-config-wizard/i3-config-wizard $(DESTDIR)$(EXEC_PREFIX)/bin/ clean-i3-config-wizard: echo "[i3-config-wizard] Clean" diff --git a/i3-dump-log/i3-dump-log.mk b/i3-dump-log/i3-dump-log.mk index bbce356f..7e5d4499 100644 --- a/i3-dump-log/i3-dump-log.mk +++ b/i3-dump-log/i3-dump-log.mk @@ -20,8 +20,8 @@ i3-dump-log/i3-dump-log: libi3.a $(i3_dump_log_OBJECTS) install-i3-dump-log: i3-dump-log/i3-dump-log echo "[i3-dump-log] Install" - $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -m 0755 i3-dump-log/i3-dump-log $(DESTDIR)$(PREFIX)/bin/ + $(INSTALL) -d -m 0755 $(DESTDIR)$(EXEC_PREFIX)/bin + $(INSTALL) -m 0755 i3-dump-log/i3-dump-log $(DESTDIR)$(EXEC_PREFIX)/bin/ clean-i3-dump-log: echo "[i3-dump-log] Clean" diff --git a/i3-input/i3-input.mk b/i3-input/i3-input.mk index 03f4e0a6..be3e2833 100644 --- a/i3-input/i3-input.mk +++ b/i3-input/i3-input.mk @@ -20,8 +20,8 @@ i3-input/i3-input: libi3.a $(i3_input_OBJECTS) install-i3-input: i3-input/i3-input echo "[i3-input] Install" - $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -m 0755 i3-input/i3-input $(DESTDIR)$(PREFIX)/bin/ + $(INSTALL) -d -m 0755 $(DESTDIR)$(EXEC_PREFIX)/bin + $(INSTALL) -m 0755 i3-input/i3-input $(DESTDIR)$(EXEC_PREFIX)/bin/ clean-i3-input: echo "[i3-input] Clean" diff --git a/i3-msg/i3-msg.mk b/i3-msg/i3-msg.mk index fda56dad..277c43e7 100644 --- a/i3-msg/i3-msg.mk +++ b/i3-msg/i3-msg.mk @@ -20,8 +20,8 @@ i3-msg/i3-msg: libi3.a $(i3_msg_OBJECTS) install-i3-msg: i3-msg/i3-msg echo "[i3-msg] Install" - $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -m 0755 i3-msg/i3-msg $(DESTDIR)$(PREFIX)/bin/ + $(INSTALL) -d -m 0755 $(DESTDIR)$(EXEC_PREFIX)/bin + $(INSTALL) -m 0755 i3-msg/i3-msg $(DESTDIR)$(EXEC_PREFIX)/bin/ clean-i3-msg: echo "[i3-msg] Clean" diff --git a/i3-nagbar/i3-nagbar.mk b/i3-nagbar/i3-nagbar.mk index e98d6582..aba3c09a 100644 --- a/i3-nagbar/i3-nagbar.mk +++ b/i3-nagbar/i3-nagbar.mk @@ -20,8 +20,8 @@ i3-nagbar/i3-nagbar: libi3.a $(i3_nagbar_OBJECTS) install-i3-nagbar: i3-nagbar/i3-nagbar echo "[i3-nagbar] Install" - $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -m 0755 i3-nagbar/i3-nagbar $(DESTDIR)$(PREFIX)/bin/ + $(INSTALL) -d -m 0755 $(DESTDIR)$(EXEC_PREFIX)/bin + $(INSTALL) -m 0755 i3-nagbar/i3-nagbar $(DESTDIR)$(EXEC_PREFIX)/bin/ clean-i3-nagbar: echo "[i3-nagbar] Clean" diff --git a/i3bar/i3bar.mk b/i3bar/i3bar.mk index 53227a8e..737b0b69 100644 --- a/i3bar/i3bar.mk +++ b/i3bar/i3bar.mk @@ -20,8 +20,8 @@ i3bar/i3bar: libi3.a $(i3bar_OBJECTS) install-i3bar: i3bar/i3bar echo "[i3bar] Install" - $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -m 0755 i3bar/i3bar $(DESTDIR)$(PREFIX)/bin/ + $(INSTALL) -d -m 0755 $(DESTDIR)$(EXEC_PREFIX)/bin + $(INSTALL) -m 0755 i3bar/i3bar $(DESTDIR)$(EXEC_PREFIX)/bin/ clean-i3bar: echo "[i3bar] Clean" diff --git a/src/i3.mk b/src/i3.mk index 8c763464..e850e23a 100644 --- a/src/i3.mk +++ b/src/i3.mk @@ -70,25 +70,25 @@ i3: libi3.a $(i3_OBJECTS) install-i3: i3 echo "[i3] Install" - $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/bin + $(INSTALL) -d -m 0755 $(DESTDIR)$(EXEC_PREFIX)/bin $(INSTALL) -d -m 0755 $(DESTDIR)$(SYSCONFDIR)/i3 - $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/include/i3 + $(INSTALL) -d -m 0755 $(DESTDIR)$(EXEC_PREFIX)/include/i3 $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/share/xsessions $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/share/applications - $(INSTALL) -m 0755 i3 $(DESTDIR)$(PREFIX)/bin/ - $(LN) -sf i3 $(DESTDIR)$(PREFIX)/bin/i3-with-shmlog - $(INSTALL) -m 0755 i3-migrate-config-to-v4 $(DESTDIR)$(PREFIX)/bin/ - $(INSTALL) -m 0755 i3-sensible-editor $(DESTDIR)$(PREFIX)/bin/ - $(INSTALL) -m 0755 i3-sensible-pager $(DESTDIR)$(PREFIX)/bin/ - $(INSTALL) -m 0755 i3-sensible-terminal $(DESTDIR)$(PREFIX)/bin/ - $(INSTALL) -m 0755 i3-save-tree $(DESTDIR)$(PREFIX)/bin/ - $(INSTALL) -m 0755 i3-dmenu-desktop $(DESTDIR)$(PREFIX)/bin/ + $(INSTALL) -m 0755 i3 $(DESTDIR)$(EXEC_PREFIX)/bin/ + $(LN) -sf i3 $(DESTDIR)$(EXEC_PREFIX)/bin/i3-with-shmlog + $(INSTALL) -m 0755 i3-migrate-config-to-v4 $(DESTDIR)$(EXEC_PREFIX)/bin/ + $(INSTALL) -m 0755 i3-sensible-editor $(DESTDIR)$(EXEC_PREFIX)/bin/ + $(INSTALL) -m 0755 i3-sensible-pager $(DESTDIR)$(EXEC_PREFIX)/bin/ + $(INSTALL) -m 0755 i3-sensible-terminal $(DESTDIR)$(EXEC_PREFIX)/bin/ + $(INSTALL) -m 0755 i3-save-tree $(DESTDIR)$(EXEC_PREFIX)/bin/ + $(INSTALL) -m 0755 i3-dmenu-desktop $(DESTDIR)$(EXEC_PREFIX)/bin/ test -e $(DESTDIR)$(SYSCONFDIR)/i3/config || $(INSTALL) -m 0644 i3.config $(DESTDIR)$(SYSCONFDIR)/i3/config test -e $(DESTDIR)$(SYSCONFDIR)/i3/config.keycodes || $(INSTALL) -m 0644 i3.config.keycodes $(DESTDIR)$(SYSCONFDIR)/i3/config.keycodes $(INSTALL) -m 0644 i3.xsession.desktop $(DESTDIR)$(PREFIX)/share/xsessions/i3.desktop $(INSTALL) -m 0644 i3-with-shmlog.xsession.desktop $(DESTDIR)$(PREFIX)/share/xsessions/i3-with-shmlog.desktop $(INSTALL) -m 0644 i3.applications.desktop $(DESTDIR)$(PREFIX)/share/applications/i3.desktop - $(INSTALL) -m 0644 include/i3/ipc.h $(DESTDIR)$(PREFIX)/include/i3/ + $(INSTALL) -m 0644 include/i3/ipc.h $(DESTDIR)$(EXEC_PREFIX)/include/i3/ clean-i3: echo "[i3] Clean" From 0492c50fbbe3bc3a2440fe69b14b3c0659c7b324 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 16 Apr 2015 09:08:46 +0200 Subject: [PATCH 063/243] debian: update changelog --- debian/changelog | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 183e5940..023eeac1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,14 @@ -i3-wm (4.10.2-1) experimental; urgency=medium +i3-wm (4.10.3-1) experimental; urgency=medium * NOT YET RELEASED. - -- Michael Stapelberg Sun, 29 Mar 2015 19:10:38 +0200 + -- Michael Stapelberg Thu, 16 Apr 2015 09:08:30 +0200 + +i3-wm (4.10.2-1) experimental; urgency=medium + + * New upstream release. + + -- Michael Stapelberg Thu, 16 Apr 2015 09:02:53 +0200 i3-wm (4.10.1-1) experimental; urgency=medium From d9f483e9469548c2a7245bf9999d11e724c76df1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 16 Apr 2015 09:19:30 +0200 Subject: [PATCH 064/243] release.sh: 4.10.2 release --- release.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/release.sh b/release.sh index 631ff425..c7505179 100755 --- a/release.sh +++ b/release.sh @@ -1,9 +1,9 @@ #!/bin/zsh # This script is used to prepare a new release of i3. -export RELEASE_VERSION="4.10.1" -export PREVIOUS_VERSION="4.10" -export RELEASE_BRANCH="next" +export RELEASE_VERSION="4.10.2" +export PREVIOUS_VERSION="4.10.1" +export RELEASE_BRANCH="master" if [ ! -e "../i3.github.io" ] then From 57c56b29995fc7816d2905a2996fcbf5030571e0 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 16 Apr 2015 09:19:46 +0200 Subject: [PATCH 065/243] release.sh: checkout correct branch before copying docs --- release.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/release.sh b/release.sh index c7505179..af42d9bf 100755 --- a/release.sh +++ b/release.sh @@ -135,6 +135,10 @@ debsign -k4AC8EE1D ${TMPDIR}/debian/*.changes # Section 3: website ################################################################################ +# Ensure we are in the correct branch for copying the docs. +cd ${TMPDIR}/i3 +git checkout ${RELEASE_BRANCH} + cd ${TMPDIR} git clone --quiet ${STARTDIR}/../i3.github.io cd i3.github.io From 25afa30f874f56a657ad0adc1f12e5a04f931e1b Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 16 Apr 2015 09:20:22 +0200 Subject: [PATCH 066/243] release.sh: set up master branch for pushing the website --- release.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/release.sh b/release.sh index af42d9bf..c829f671 100755 --- a/release.sh +++ b/release.sh @@ -176,6 +176,7 @@ git commit -a -m "update docs for ${RELEASE_VERSION}" git remote remove origin git remote add origin git@github.com:i3/i3.github.io.git +git config --add remote.origin.push "+refs/heads/master:refs/heads/master" ################################################################################ # Section 4: prepare release announcement email From e382a8bbbb103e1cc9e9dfc623147d8b98258fcf Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 16 Apr 2015 09:20:43 +0200 Subject: [PATCH 067/243] release.sh: fix encoding and concatenating changelog --- release.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/release.sh b/release.sh index c829f671..bf499009 100755 --- a/release.sh +++ b/release.sh @@ -187,12 +187,14 @@ cat >email.txt < To: i3-announce@i3.zekjur.net Subject: i3 v${RELEASE_VERSION} released +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit Hi, I just released i3 v${RELEASE_VERSION}. Release notes follow: EOT -cat ${TMPDIR}/i3/RELEASE-NOTES-${RELEASE_VERSION}.txt >>email.txt +cat ${TMPDIR}/i3/RELEASE-NOTES-${RELEASE_VERSION} >>email.txt ################################################################################ # Section 5: final push instructions From d05e9df0a13528f1bd9939b7b83d1c0799734860 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 16 Apr 2015 09:21:00 +0200 Subject: [PATCH 068/243] release.sh: add missing commit step for debian changelog --- release.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/release.sh b/release.sh index bf499009..b169c2b5 100755 --- a/release.sh +++ b/release.sh @@ -206,6 +206,7 @@ echo "When satisfied, run:" echo " cd ${TMPDIR}/i3" echo " git checkout next" echo " vi debian/changelog" +echo " git commit -a -m \"debian: update changelog\"" echo " git push" echo "" echo " cd ${TMPDIR}/i3.github.io" From 923a61ae37b2680e9560f83b12ba4c54273c80b1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 16 Apr 2015 09:21:13 +0200 Subject: [PATCH 069/243] release.sh: add missing -t parameter for sendmail --- release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.sh b/release.sh index b169c2b5..16227111 100755 --- a/release.sh +++ b/release.sh @@ -216,7 +216,7 @@ echo " cd ${TMPDIR}/debian" echo " dput *.changes" echo "" echo " cd ${TMPDIR}" -echo " sendmail < email.txt" +echo " sendmail -t < email.txt" echo "" echo "Announce on:" echo " twitter" From 7e424b2d71e4c3dbdb314aad03479fc8ee5480ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sat, 18 Apr 2015 22:02:03 +0200 Subject: [PATCH 070/243] Added testcase for criterion 'window_type'. --- testcases/t/165-for_window.t | 39 ++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/testcases/t/165-for_window.t b/testcases/t/165-for_window.t index ada7c5c5..036fc9d6 100644 --- a/testcases/t/165-for_window.t +++ b/testcases/t/165-for_window.t @@ -370,5 +370,44 @@ is($content[0]->{border}, 'none', 'no border (window_role 2)'); exit_gracefully($pid); +############################################################## +# 10: check that the criterion 'window_type' works +############################################################## + +# test all window types +my %window_types = ( + 'normal' => '_NET_WM_WINDOW_TYPE_NORMAL', + 'dialog' => '_NET_WM_WINDOW_TYPE_DIALOG', + 'utility' => '_NET_WM_WINDOW_TYPE_UTILITY', + 'toolbar' => '_NET_WM_WINDOW_TYPE_TOOLBAR', + 'splash' => '_NET_WM_WINDOW_TYPE_SPLASH', + 'menu' => '_NET_WM_WINDOW_TYPE_MENU', + 'dropdown_menu' => '_NET_WM_WINDOW_TYPE_DROPDOWN_MENU', + 'popup_menu' => '_NET_WM_WINDOW_TYPE_POPUP_MENU', + 'tooltip' => '_NET_WM_WINDOW_TYPE_TOOLTIP' +); + +while (my ($window_type, $atom) = each %window_types) { + + $config = <<"EOT"; +# i3 config file (v4) +font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 +for_window [window_type="$window_type"] floating enable, mark branded +EOT + + $pid = launch_with_config($config); + $tmp = fresh_workspace; + + $window = open_window(window_type => $x->atom(name => $atom)); + + my @nodes = @{get_ws($tmp)->{floating_nodes}}; + cmp_ok(@nodes, '==', 1, 'one floating container on this workspace'); + is($nodes[0]->{nodes}[0]->{mark}, 'branded', "mark set (window_type = $atom)"); + + exit_gracefully($pid); + +} + +############################################################## done_testing; From 9613a0744ddf39adef664b424671cc3246763ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 12 Apr 2015 17:30:31 +0200 Subject: [PATCH 071/243] Added configuration directive for 'move [container|window] [to] mark ' --- docs/userguide | 20 ++++++++++++++++++++ include/commands.h | 6 ++++++ parser-specs/commands.spec | 7 +++++++ src/commands.c | 8 ++++++++ 4 files changed, 41 insertions(+) diff --git a/docs/userguide b/docs/userguide index 96b36902..f7135c6a 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1837,6 +1837,26 @@ bindsym $mod+x move workspace to output right bindsym $mod+x move container to output VGA1 -------------------------------------------------------- +=== Moving containers/workspaces to marks + +To move a container to another container with a specific mark (see <>), +you can use the following command. + +The window will be moved right after the marked container in the tree, i.e., it ends up +in the same position as if you had opened a new window when the marked container was +focused. If the mark is on a split container, the window will appear as a new child +after the currently focused child within that container. + +*Syntax*: +------------------------------------ +move window|container to mark +------------------------------------ + +*Example*: +-------------------------------------------------------- +for_window [instance="tabme"] move window to mark target +-------------------------------------------------------- + [[resizingconfig]] === Resizing containers/windows diff --git a/include/commands.h b/include/commands.h index 0f7e3635..ccb555a4 100644 --- a/include/commands.h +++ b/include/commands.h @@ -132,6 +132,12 @@ void cmd_mode(I3_CMD, char *mode); */ void cmd_move_con_to_output(I3_CMD, char *name); +/** + * Implementation of 'move [window|container] [to] mark '. + * + */ +void cmd_move_con_to_mark(I3_CMD, char *mark); + /** * Implementation of 'floating enable|disable|toggle' * diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec index 87db6cf0..8fe1f569 100644 --- a/parser-specs/commands.spec +++ b/parser-specs/commands.spec @@ -265,6 +265,7 @@ state RENAME_WORKSPACE_NEW_NAME: # move [ [px]] # move [window|container] [to] workspace [|next|prev|next_on_output|prev_on_output|current] # move [window|container] [to] output +# move [window|container] [to] mark # move [window|container] [to] scratchpad # move workspace to [output] # move scratchpad @@ -280,6 +281,8 @@ state MOVE: -> MOVE_WORKSPACE 'output' -> MOVE_TO_OUTPUT + 'mark' + -> MOVE_TO_MARK 'scratchpad' -> call cmd_move_scratchpad() direction = 'left', 'right', 'up', 'down' @@ -321,6 +324,10 @@ state MOVE_TO_OUTPUT: output = string -> call cmd_move_con_to_output($output) +state MOVE_TO_MARK: + mark = string + -> call cmd_move_con_to_mark($mark) + state MOVE_WORKSPACE_TO_OUTPUT: 'output' -> diff --git a/src/commands.c b/src/commands.c index 79071d6b..c81bafb7 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1169,6 +1169,14 @@ void cmd_move_con_to_output(I3_CMD, char *name) { ysuccess(true); } +/* + * Implementation of 'move [container|window] [to] mark '. + * + */ +void cmd_move_con_to_mark(I3_CMD, char *mark) { + ysuccess(true); +} + /* * Implementation of 'floating enable|disable|toggle' * From c4a84385d68373ef19d82441a0e1615c0109f0c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 14 Apr 2015 17:51:28 +0200 Subject: [PATCH 072/243] added function 'con_by_mark' to look up a con holding the given mark --- include/con.h | 7 +++++++ src/con.c | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/con.h b/include/con.h index b025adab..c760643d 100644 --- a/include/con.h +++ b/include/con.h @@ -126,6 +126,13 @@ Con *con_by_window_id(xcb_window_t window); */ Con *con_by_frame_id(xcb_window_t frame); +/** + * Returns the container with the given mark or NULL if no such container + * exists. + * + */ +Con *con_by_mark(const char *mark); + /** * Returns the first container below 'con' which wants to swallow this window * TODO: priority diff --git a/src/con.c b/src/con.c index dab8d29d..066ba1c4 100644 --- a/src/con.c +++ b/src/con.c @@ -460,6 +460,21 @@ Con *con_by_frame_id(xcb_window_t frame) { return NULL; } +/* + * Returns the container with the given mark or NULL if no such container + * exists. + * + */ +Con *con_by_mark(const char *mark) { + Con *con; + TAILQ_FOREACH(con, &all_cons, all_cons) { + if (con->mark != NULL && strcmp(con->mark, mark) == 0) + return con; + } + + return NULL; +} + /* * Returns the first container below 'con' which wants to swallow this window * TODO: priority From 9ab42167871ed0531adf978373a6ee6ff80a9ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 14 Apr 2015 17:56:10 +0200 Subject: [PATCH 073/243] Extract a function from con_move_to_workpsace that deals with moving a container to some other container rather than being restricted to moving to a specific workspace. --- src/con.c | 112 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/src/con.c b/src/con.c index 066ba1c4..266b4d33 100644 --- a/src/con.c +++ b/src/con.c @@ -697,28 +697,12 @@ void con_disable_fullscreen(Con *con) { con_set_fullscreen_mode(con, CF_NONE); } -/* - * Moves the given container to the currently focused container on the given - * workspace. - * - * The fix_coordinates flag will translate the current coordinates (offset from - * the monitor position basically) to appropriate coordinates on the - * destination workspace. - * Not enabling this behaviour comes in handy when this function gets called by - * floating_maybe_reassign_ws, which will only "move" a floating window when it - * *already* changed its coordinates to a different output. - * - * The dont_warp flag disables pointer warping and will be set when this - * function is called while dragging a floating window. - * - * TODO: is there a better place for this function? - * - */ -void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool dont_warp) { +static bool _con_move_to_con(Con *con, Con *target, bool fix_coordinates, bool dont_warp) { /* Prevent moving if this would violate the fullscreen focus restrictions. */ - if (!con_fullscreen_permits_focusing(workspace)) { + Con *target_ws = con_get_workspace(target); + if (!con_fullscreen_permits_focusing(target_ws)) { LOG("Cannot move out of a fullscreen container"); - return; + return false; } if (con_is_floating(con)) { @@ -727,27 +711,23 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool } Con *source_ws = con_get_workspace(con); - if (workspace == source_ws) { - DLOG("Not moving, already there\n"); - return; - } if (con->type == CT_WORKSPACE) { /* Re-parent all of the old workspace's floating windows. */ Con *child; while (!TAILQ_EMPTY(&(source_ws->floating_head))) { child = TAILQ_FIRST(&(source_ws->floating_head)); - con_move_to_workspace(child, workspace, true, true); + con_move_to_workspace(child, target_ws, true, true); } /* If there are no non-floating children, ignore the workspace. */ if (con_is_leaf(con)) - return; + return false; con = workspace_encapsulate(con); if (con == NULL) { ELOG("Workspace failed to move its contents into a container!\n"); - return; + return false; } } @@ -759,34 +739,31 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool Con *current_ws = con_get_workspace(focused); Con *source_output = con_get_output(con), - *dest_output = con_get_output(workspace); + *dest_output = con_get_output(target_ws); /* 1: save the container which is going to be focused after the current * container is moved away */ Con *focus_next = con_next_focused(con); - /* 2: get the focused container of this workspace */ - Con *next = con_descend_focused(workspace); - - /* 3: we go up one level, but only when next is a normal container */ - if (next->type != CT_WORKSPACE) { - DLOG("next originally = %p / %s / type %d\n", next, next->name, next->type); - next = next->parent; + /* 2: we go up one level, but only when target is a normal container */ + if (target->type != CT_WORKSPACE) { + DLOG("target originally = %p / %s / type %d\n", target, target->name, target->type); + target = target->parent; } - /* 4: if the target container is floating, we get the workspace instead. + /* 3: if the target container is floating, we get the workspace instead. * Only tiling windows need to get inserted next to the current container. * */ - Con *floatingcon = con_inside_floating(next); + Con *floatingcon = con_inside_floating(target); if (floatingcon != NULL) { DLOG("floatingcon, going up even further\n"); - next = floatingcon->parent; + target = floatingcon->parent; } if (con->type == CT_FLOATING_CON) { - Con *ws = con_get_workspace(next); + Con *ws = con_get_workspace(target); DLOG("This is a floating window, using workspace %p / %s\n", ws, ws->name); - next = ws; + target = ws; } if (source_output != dest_output) { @@ -800,8 +777,8 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool /* If moving to a visible workspace, call show so it can be considered * focused. Must do before attaching because workspace_show checks to see * if focused container is in its area. */ - if (workspace_is_visible(workspace)) { - workspace_show(workspace); + if (workspace_is_visible(target_ws)) { + workspace_show(target_ws); /* Don’t warp if told so (when dragging floating windows with the * mouse for example) */ @@ -814,29 +791,29 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool /* If moving a fullscreen container and the destination already has a * fullscreen window on it, un-fullscreen the target's fullscreen con. */ - Con *fullscreen = con_get_fullscreen_con(workspace, CF_OUTPUT); + Con *fullscreen = con_get_fullscreen_con(target_ws, CF_OUTPUT); if (con->fullscreen_mode != CF_NONE && fullscreen != NULL) { con_toggle_fullscreen(fullscreen, CF_OUTPUT); fullscreen = NULL; } - DLOG("Re-attaching container to %p / %s\n", next, next->name); - /* 5: re-attach the con to the parent of this focused container */ + DLOG("Re-attaching container to %p / %s\n", target, target->name); + /* 4: re-attach the con to the parent of this focused container */ Con *parent = con->parent; con_detach(con); - con_attach(con, next, false); + con_attach(con, target, false); - /* 6: fix the percentages */ + /* 5: fix the percentages */ con_fix_percent(parent); con->percent = 0.0; - con_fix_percent(next); + con_fix_percent(target); - /* 7: focus the con on the target workspace, but only within that + /* 6: focus the con on the target workspace, but only within that * workspace, that is, don’t move focus away if the target workspace is * invisible. * We don’t focus the con for i3 pseudo workspaces like __i3_scratch and * we don’t focus when there is a fullscreen con on that workspace. */ - if (!con_is_internal(workspace) && !fullscreen) { + if (!con_is_internal(target_ws) && !fullscreen) { /* We need to save the focused workspace on the output in case the * new workspace is hidden and it's necessary to immediately switch * back to the originally-focused workspace. */ @@ -848,7 +825,7 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool con_focus(old_focus); } - /* 8: when moving to another workspace, we leave the focus on the current + /* 7: when moving to another workspace, we leave the focus on the current * workspace. (see also #809) */ /* Descend focus stack in case focus_next is a workspace which can @@ -861,7 +838,7 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool if (source_ws == current_ws) con_focus(con_descend_focused(focus_next)); - /* 9. If anything within the container is associated with a startup sequence, + /* 8. If anything within the container is associated with a startup sequence, * delete it so child windows won't be created on the old workspace. */ struct Startup_Sequence *sequence; xcb_get_property_cookie_t cookie; @@ -895,13 +872,42 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool CALL(parent, on_remove_child); - /* 10. If the container was marked urgent, move the urgency hint. */ + /* 9. If the container was marked urgent, move the urgency hint. */ if (urgent) { workspace_update_urgent_flag(source_ws); con_set_urgency(con, true); } ipc_send_window_event("move", con); + return true; +} + +/* + * Moves the given container to the currently focused container on the given + * workspace. + * + * The fix_coordinates flag will translate the current coordinates (offset from + * the monitor position basically) to appropriate coordinates on the + * destination workspace. + * Not enabling this behaviour comes in handy when this function gets called by + * floating_maybe_reassign_ws, which will only "move" a floating window when it + * *already* changed its coordinates to a different output. + * + * The dont_warp flag disables pointer warping and will be set when this + * function is called while dragging a floating window. + * + * TODO: is there a better place for this function? + * + */ +void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool dont_warp) { + Con *source_ws = con_get_workspace(con); + if (workspace == source_ws) { + DLOG("Not moving, already there\n"); + return; + } + + Con *target = con_descend_focused(workspace); + _con_move_to_con(con, target, fix_coordinates, dont_warp); } /* From 475671ae2aea2d3d2e05b613f2fe5bfa02aca861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 15 Apr 2015 18:36:45 +0200 Subject: [PATCH 074/243] Added 'con_move_to_mark' to move a container to the container holding a certain mark. --- include/con.h | 6 +++++ src/commands.c | 10 +++----- src/con.c | 67 +++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 62 insertions(+), 21 deletions(-) diff --git a/include/con.h b/include/con.h index c760643d..4ee3fb7d 100644 --- a/include/con.h +++ b/include/con.h @@ -210,6 +210,12 @@ void con_disable_fullscreen(Con *con); */ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool dont_warp); +/** + * Moves the given container to the given mark. + * + */ +bool con_move_to_mark(Con *con, const char *mark); + /** * Returns the orientation of the given container (for stacked containers, * vertical orientation is used regardless of the actual orientation of the diff --git a/src/commands.c b/src/commands.c index c81bafb7..736c4027 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1100,12 +1100,10 @@ void cmd_unmark(I3_CMD, char *mark) { } DLOG("removed all window marks"); } else { - Con *con; - TAILQ_FOREACH(con, &all_cons, all_cons) { - if (con->mark && strcmp(con->mark, mark) == 0) { - FREE(con->mark); - con->mark_changed = true; - } + Con *con = con_by_mark(mark); + if (con != NULL) { + FREE(con->mark); + con->mark_changed = true; } DLOG("removed window mark %s\n", mark); } diff --git a/src/con.c b/src/con.c index 266b4d33..a5304553 100644 --- a/src/con.c +++ b/src/con.c @@ -70,20 +70,10 @@ Con *con_new(Con *parent, i3Window *window) { return new; } -/* - * Attaches the given container to the given parent. This happens when moving - * a container or when inserting a new container at a specific place in the - * tree. - * - * ignore_focus is to just insert the Con at the end (useful when creating a - * new split container *around* some containers, that is, detaching and - * attaching them in order without wanting to mess with the focus in between). - * - */ -void con_attach(Con *con, Con *parent, bool ignore_focus) { +static void _con_attach(Con *con, Con *parent, Con *previous, bool ignore_focus) { con->parent = parent; Con *loop; - Con *current = NULL; + Con *current = previous; struct nodes_head *nodes_head = &(parent->nodes_head); struct focus_head *focus_head = &(parent->focus_head); @@ -170,6 +160,20 @@ add_to_focus_head: con_force_split_parents_redraw(con); } +/* + * Attaches the given container to the given parent. This happens when moving + * a container or when inserting a new container at a specific place in the + * tree. + * + * ignore_focus is to just insert the Con at the end (useful when creating a + * new split container *around* some containers, that is, detaching and + * attaching them in order without wanting to mess with the focus in between). + * + */ +void con_attach(Con *con, Con *parent, bool ignore_focus) { + _con_attach(con, parent, NULL, ignore_focus); +} + /* * Detaches the given container from its current parent * @@ -697,7 +701,9 @@ void con_disable_fullscreen(Con *con) { con_set_fullscreen_mode(con, CF_NONE); } -static bool _con_move_to_con(Con *con, Con *target, bool fix_coordinates, bool dont_warp) { +static bool _con_move_to_con(Con *con, Con *target, bool behind_focused, bool fix_coordinates, bool dont_warp) { + Con *orig_target = target; + /* Prevent moving if this would violate the fullscreen focus restrictions. */ Con *target_ws = con_get_workspace(target); if (!con_fullscreen_permits_focusing(target_ws)) { @@ -801,7 +807,7 @@ static bool _con_move_to_con(Con *con, Con *target, bool fix_coordinates, bool d /* 4: re-attach the con to the parent of this focused container */ Con *parent = con->parent; con_detach(con); - con_attach(con, target, false); + _con_attach(con, target, behind_focused ? NULL : orig_target, !behind_focused); /* 5: fix the percentages */ con_fix_percent(parent); @@ -882,6 +888,35 @@ static bool _con_move_to_con(Con *con, Con *target, bool fix_coordinates, bool d return true; } +/* + * Moves the given container to the given mark. + * + */ +bool con_move_to_mark(Con *con, const char *mark) { + Con *target = con_by_mark(mark); + if (target == NULL) { + DLOG("found no container with mark \"%s\"\n", mark); + return false; + } + + /* For floating target containers, we just send the window to the same workspace. */ + if (con_is_floating(target)) { + DLOG("target container is floating, moving container to target's workspace.\n"); + con_move_to_workspace(con, con_get_workspace(target), true, false); + return true; + } + + /* For split containers, we use the currently focused container within it. + * This allows setting marks on, e.g., tabbed containers which will move + * con to a new tab behind the focused tab. */ + if (con_is_split(target)) { + DLOG("target is a split container, descending to the currently focused child.\n"); + target = TAILQ_FIRST(&(target->focus_head)); + } + + return _con_move_to_con(con, target, false, true, false); +} + /* * Moves the given container to the currently focused container on the given * workspace. @@ -900,6 +935,8 @@ static bool _con_move_to_con(Con *con, Con *target, bool fix_coordinates, bool d * */ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool dont_warp) { + assert(workspace->type == CT_WORKSPACE); + Con *source_ws = con_get_workspace(con); if (workspace == source_ws) { DLOG("Not moving, already there\n"); @@ -907,7 +944,7 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool } Con *target = con_descend_focused(workspace); - _con_move_to_con(con, target, fix_coordinates, dont_warp); + _con_move_to_con(con, target, true, fix_coordinates, dont_warp); } /* From 94bbdc9159f43181f9d9069893e812c1226eda00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 14 Apr 2015 17:57:33 +0200 Subject: [PATCH 075/243] Implement the command 'move container to mark ' using 'con_move_to_mark'. --- src/commands.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/commands.c b/src/commands.c index 736c4027..adfffe5f 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1172,7 +1172,19 @@ void cmd_move_con_to_output(I3_CMD, char *name) { * */ void cmd_move_con_to_mark(I3_CMD, char *mark) { - ysuccess(true); + DLOG("moving window to mark \"%s\"\n", mark); + + HANDLE_EMPTY_MATCH; + + bool result = true; + owindow *current; + TAILQ_FOREACH(current, &owindows, owindows) { + DLOG("moving matched window %p / %s to mark \"%s\"\n", current->con, current->con->name, mark); + result &= con_move_to_mark(current->con, mark); + } + + cmd_output->needs_tree_render = true; + ysuccess(result); } /* From 05e8caab1743dc15f1703d51d83f93b53ce06b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 15 Apr 2015 18:41:56 +0200 Subject: [PATCH 076/243] Added testcases for 'move window|container to mark ' fixes #1643 --- testcases/t/243-move-to-mark.t | 273 +++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 testcases/t/243-move-to-mark.t diff --git a/testcases/t/243-move-to-mark.t b/testcases/t/243-move-to-mark.t new file mode 100644 index 00000000..f3451675 --- /dev/null +++ b/testcases/t/243-move-to-mark.t @@ -0,0 +1,273 @@ +#!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) +# +# Tests for the 'move [window|container] to mark' command +# Ticket: #1643 +use i3test; + +# In the following tests descriptions, we will always use the following names: +# * 'S' for the source container which is going to be moved, +# * 'M' for the marked target container to which 'S' will be moved. + +my ($A, $B, $S, $M, $F, $source_ws, $target_ws, $ws); +my ($nodes, $focus); +my $cmd_result; + +############################################################################### +# Given 'M' and 'S' in a horizontal split, when 'S' is moved to 'M', then +# verify that nothing changed. +############################################################################### + +$ws = fresh_workspace; +$M = open_window; +cmd 'mark target'; +$S = open_window; + +cmd 'move container to mark target'; +sync_with_i3; + +($nodes, $focus) = get_ws_content($ws); +is(@{$nodes}, 2, 'there are two containers'); +is($nodes->[0]->{window}, $M->{id}, 'M is left of S'); +is($nodes->[1]->{window}, $S->{id}, 'S is right of M'); + +############################################################################### +# Given 'S' and 'M' in a horizontal split, when 'S' is moved to 'M', then +# both containers switch places. +############################################################################### + +$ws = fresh_workspace; +$S = open_window; +$M = open_window; +cmd 'mark target'; +cmd 'focus left'; + +cmd 'move container to mark target'; +sync_with_i3; + +($nodes, $focus) = get_ws_content($ws); +is(@{$nodes}, 2, 'there are two containers'); +is($nodes->[0]->{window}, $M->{id}, 'M is left of S'); +is($nodes->[1]->{window}, $S->{id}, 'S is right of M'); + +############################################################################### +# Given 'S' and no container 'M' exists, when 'S' is moved to 'M', then +# the command is unsuccessful. +############################################################################### + +$ws = fresh_workspace; +$S = open_window; + +$cmd_result = cmd 'move container to mark absent'; + +is($cmd_result->[0]->{success}, 0, 'command was unsuccessful'); + +############################################################################### +# Given 'S' and 'M' on different workspaces, when 'S' is moved to 'M', then +# 'S' ends up on the same workspace as 'M'. +############################################################################### + +$source_ws = fresh_workspace; +$S = open_window; +$target_ws = fresh_workspace; +$M = open_window; +cmd 'mark target'; + +cmd '[id="' . $S->{id} . '"] move container to mark target'; +sync_with_i3; + +($nodes, $focus) = get_ws_content($source_ws); +is(@{$nodes}, 0, 'source workspace is empty'); + +($nodes, $focus) = get_ws_content($target_ws); +is(@{$nodes}, 2, 'both containers are on the target workspace'); +is($nodes->[0]->{window}, $M->{id}, 'M is left of S'); +is($nodes->[1]->{window}, $S->{id}, 'S is right of M'); + +############################################################################### +# Given 'S' and 'M' on different workspaces and 'S' is urgent, when 'S' is +# moved to 'M', then the urgency flag is transferred to the target workspace. +############################################################################### + +# TODO + +############################################################################### +# Given 'S' and 'M' where 'M' is inside a tabbed container, when 'S' is moved +# to 'M', then 'S' ends up as a new tab. +############################################################################### + +$source_ws = fresh_workspace; +$S = open_window; + +# open tabbed container ['A' 'M' 'B'] +$target_ws = fresh_workspace; +cmd 'layout tabbed'; +$A = open_window; +$M = open_window; +cmd 'mark target'; +$B = open_window; + +cmd '[id="' . $S->{id} . '"] move container to mark target'; +sync_with_i3; + +($nodes, $focus) = get_ws_content($target_ws); +is(@{$nodes}, 1, 'there is a tabbed container'); + +$nodes = $nodes->[0]->{nodes}; +is(@{$nodes}, 4, 'all four containers are on the target workspace'); +is($nodes->[0]->{window}, $A->{id}, 'A is the first tab'); +is($nodes->[1]->{window}, $M->{id}, 'M is the second tab'); +is($nodes->[2]->{window}, $S->{id}, 'S is the third tab'); +is($nodes->[3]->{window}, $B->{id}, 'B is the fourth tab'); + +############################################################################### +# Given 'S' and 'M' where 'M' is a tabbed container where the currently focused +# tab is a nested layout, when 'S' is moved to 'M', then 'S' is a new tab +# within 'M'. +############################################################################### + +$source_ws = fresh_workspace; +$S = open_window; + +$target_ws = fresh_workspace; +cmd 'layout tabbed'; +$A = open_window; +cmd 'focus parent'; +cmd 'mark target'; +cmd 'focus child'; +$B = open_window; +cmd 'split h'; +$F = open_window; + +cmd '[id="' . $S->{id} . '"] move container to mark target'; +sync_with_i3; + +($nodes, $focus) = get_ws_content($target_ws); +is(@{$nodes}, 1, 'there is a tabbed container'); + +$nodes = $nodes->[0]->{nodes}; +is(@{$nodes}, 3, 'there are three tabs'); + +is($nodes->[0]->{window}, $A->{id}, 'A is the first tab'); +is($nodes->[2]->{window}, $S->{id}, 'S is the third tab'); + +############################################################################### +# Given 'S' and 'M' where 'M' is inside a split container inside a tabbed +# container, when 'S' is moved to 'M', then 'S' ends up as a container +# within the same tab as 'M'. +############################################################################### + +$source_ws = fresh_workspace; +$S = open_window; + +# open tabbed container ['A'['B' 'M']] +$target_ws = fresh_workspace; +cmd 'layout tabbed'; +$A = open_window; +$B = open_window; +cmd 'split h'; +$M = open_window; +cmd 'mark target'; + +cmd '[id="' . $S->{id} . '"] move container to mark target'; +sync_with_i3; + +($nodes, $focus) = get_ws_content($target_ws); +is(@{$nodes}, 1, 'there is a tabbed container'); + +$nodes = $nodes->[0]->{nodes}; +is(@{$nodes}, 2, 'there are two tabs'); + +$nodes = $nodes->[1]->{nodes}; +is(@{$nodes}, 3, 'the tab with the marked children has three children'); +is($nodes->[0]->{window}, $B->{id}, 'B is the first tab'); +is($nodes->[1]->{window}, $M->{id}, 'M is the second tab'); +is($nodes->[2]->{window}, $S->{id}, 'S is the third tab'); + +############################################################################### +# Given 'S', 'A' and 'B' where 'A' and 'B' are inside the tabbed container 'M', +# when 'S' is moved to 'M', then 'S' ends up as a new tab in 'M'. +############################################################################### + +$source_ws = fresh_workspace; +$S = open_window; +$target_ws = fresh_workspace; +cmd 'layout tabbed'; +$A = open_window; +$B = open_window; +cmd 'focus parent'; +cmd 'mark target'; +cmd 'focus child'; + +cmd '[id="' . $S->{id} . '"] move container to mark target'; +sync_with_i3; + +($nodes, $focus) = get_ws_content($target_ws); +is(@{$nodes}, 1, 'there is a tabbed container'); + +$nodes = $nodes->[0]->{nodes}; +is(@{$nodes}, 3, 'there are three tabs'); + +is($nodes->[0]->{window}, $A->{id}, 'A is the first tab'); +is($nodes->[1]->{window}, $B->{id}, 'B is the second tab'); +is($nodes->[2]->{window}, $S->{id}, 'S is the third tab'); + +############################################################################### +# Given 'S', 'F' and 'M' where 'F' and 'M' are containers inside the same +# tabbed container and where 'F' has the focus within that container, when +# 'S' is moved to 'M', then 'S' ends up behind 'F'. +############################################################################### + +# TODO needs to be clarified whether this is the behavior we want + +############################################################################### +# Given 'S' and 'M' where 'S' is floating and 'M' on a different workspace, +# when 'S' is moved to 'M', then 'S' is a floating container on the same +# workspaces as 'M'. +############################################################################### + +$source_ws = fresh_workspace; +$S = open_floating_window; +$target_ws = fresh_workspace; +$M = open_window; +cmd 'mark target'; + +cmd '[id="' . $S->{id} . '"] move container to mark target'; +sync_with_i3; + +is(@{get_ws($target_ws)->{floating_nodes}}, 1, 'target workspace has the container now'); + +############################################################################### +# Given 'S' and 'M' where 'M' is floating and on a different workspace, +# when 'S' is moved to 'M', then 'S' ends up as a tiling container on the +# same workspace as 'M'. +############################################################################### + +$source_ws = fresh_workspace; +$S = open_window; +$target_ws = fresh_workspace; +$M = open_floating_window; +cmd 'mark target'; + +cmd '[id="' . $S->{id} . '"] move container to mark target'; +sync_with_i3; + +($nodes, $focus) = get_ws_content($target_ws); +is(@{$nodes}, 1, 'tiling container moved to the target workspace'); + +############################################################################### + +done_testing; From 283b2312907e0babcdb443f8b62e0aeb0a7ddd51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 15 Apr 2015 19:59:53 +0200 Subject: [PATCH 077/243] Disallow moving a container to itself since this would crash i3. --- src/con.c | 5 +++++ testcases/t/243-move-to-mark.t | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/con.c b/src/con.c index a5304553..b82d056a 100644 --- a/src/con.c +++ b/src/con.c @@ -914,6 +914,11 @@ bool con_move_to_mark(Con *con, const char *mark) { target = TAILQ_FIRST(&(target->focus_head)); } + if (con == target) { + DLOG("cannot move the container to itself, aborting.\n"); + return false; + } + return _con_move_to_con(con, target, false, true, false); } diff --git a/testcases/t/243-move-to-mark.t b/testcases/t/243-move-to-mark.t index f3451675..86d71864 100644 --- a/testcases/t/243-move-to-mark.t +++ b/testcases/t/243-move-to-mark.t @@ -268,6 +268,21 @@ sync_with_i3; ($nodes, $focus) = get_ws_content($target_ws); is(@{$nodes}, 1, 'tiling container moved to the target workspace'); +############################################################################### +# Given 'S' and 'M' are the same container, when 'S' is moved to 'M', then +# the command is ignored. +############################################################################### + +$ws = fresh_workspace; +$S = open_window; +$M = $S; +cmd 'mark target'; + +cmd '[id="' . $S->{id} . '"] move container to mark target'; +sync_with_i3; + +does_i3_live; + ############################################################################### done_testing; From fbebd3479b615abe8924ceb158df43b708d682bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 15 Apr 2015 20:38:33 +0200 Subject: [PATCH 078/243] Added testcase for moving a window to a workspace holding the mark --- testcases/t/243-move-to-mark.t | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/testcases/t/243-move-to-mark.t b/testcases/t/243-move-to-mark.t index 86d71864..a9250770 100644 --- a/testcases/t/243-move-to-mark.t +++ b/testcases/t/243-move-to-mark.t @@ -114,8 +114,8 @@ $S = open_window; # open tabbed container ['A' 'M' 'B'] $target_ws = fresh_workspace; -cmd 'layout tabbed'; $A = open_window; +cmd 'layout tabbed'; $M = open_window; cmd 'mark target'; $B = open_window; @@ -143,8 +143,8 @@ $source_ws = fresh_workspace; $S = open_window; $target_ws = fresh_workspace; -cmd 'layout tabbed'; $A = open_window; +cmd 'layout tabbed'; cmd 'focus parent'; cmd 'mark target'; cmd 'focus child'; @@ -175,8 +175,8 @@ $S = open_window; # open tabbed container ['A'['B' 'M']] $target_ws = fresh_workspace; -cmd 'layout tabbed'; $A = open_window; +cmd 'layout tabbed'; $B = open_window; cmd 'split h'; $M = open_window; @@ -205,8 +205,8 @@ is($nodes->[2]->{window}, $S->{id}, 'S is the third tab'); $source_ws = fresh_workspace; $S = open_window; $target_ws = fresh_workspace; -cmd 'layout tabbed'; $A = open_window; +cmd 'layout tabbed'; $B = open_window; cmd 'focus parent'; cmd 'mark target'; @@ -225,6 +225,31 @@ is($nodes->[0]->{window}, $A->{id}, 'A is the first tab'); is($nodes->[1]->{window}, $B->{id}, 'B is the second tab'); is($nodes->[2]->{window}, $S->{id}, 'S is the third tab'); +############################################################################### +# Given 'S', 'A', 'F' and 'M', where 'M' is a workspace containing a tabbed +# container, when 'S' is moved to 'M', then 'S' does not end up as a tab, but +# rather as a new window next to the tabbed container. +############################################################################### + +$source_ws = fresh_workspace; +$S = open_window; +$target_ws = fresh_workspace; +$A = open_window; +cmd 'layout tabbed'; +$F = open_window; +$M = $target_ws; +cmd 'focus parent'; +cmd 'focus parent'; +cmd 'mark target'; +cmd 'focus ' . $source_ws; + +cmd '[id="' . $S->{id} . '"] move container to mark target'; +sync_with_i3; + +($nodes, $focus) = get_ws_content($target_ws); +is(@{$nodes}, 2, 'there is a tabbed container and a window'); +is($nodes->[1]->{window}, $S->{id}, 'S is the second window'); + ############################################################################### # Given 'S', 'F' and 'M' where 'F' and 'M' are containers inside the same # tabbed container and where 'F' has the focus within that container, when From dc19ff9ec5ec20eff0900c3a25034c93b4772534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 15 Apr 2015 20:39:39 +0200 Subject: [PATCH 079/243] fix commands parser test --- testcases/t/187-commands-parser.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testcases/t/187-commands-parser.t b/testcases/t/187-commands-parser.t index 6d67731a..094caeaa 100644 --- a/testcases/t/187-commands-parser.t +++ b/testcases/t/187-commands-parser.t @@ -150,7 +150,7 @@ is(parser_calls('unknown_literal'), 'error for unknown literal ok'); is(parser_calls('move something to somewhere'), - "ERROR: Expected one of these tokens: 'window', 'container', 'to', 'workspace', 'output', 'scratchpad', 'left', 'right', 'up', 'down', 'position', 'absolute'\n" . + "ERROR: Expected one of these tokens: 'window', 'container', 'to', 'workspace', 'output', 'mark', 'scratchpad', 'left', 'right', 'up', 'down', 'position', 'absolute'\n" . "ERROR: Your command: move something to somewhere\n" . "ERROR: ^^^^^^^^^^^^^^^^^^^^^^", 'error for unknown literal ok'); From a59fe0d3d29dfba632dc6d90abc865e1f31a96f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 15 Apr 2015 21:33:59 +0200 Subject: [PATCH 080/243] Added test case for transfer of urgency flag when moving a window to a mark. --- src/con.c | 3 +-- testcases/t/243-move-to-mark.t | 46 +++++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/con.c b/src/con.c index b82d056a..622b7ad5 100644 --- a/src/con.c +++ b/src/con.c @@ -145,8 +145,7 @@ static void _con_attach(Con *con, Con *parent, Con *previous, bool ignore_focus) /* Insert the container after the tiling container, if found. * When adding to a CT_OUTPUT, just append one after another. */ if (current && parent->type != CT_OUTPUT) { - DLOG("Inserting con = %p after last focused tiling con %p\n", - con, current); + DLOG("Inserting con = %p after con %p\n", con, current); TAILQ_INSERT_AFTER(nodes_head, current, con, nodes); } else TAILQ_INSERT_TAIL(nodes_head, con, nodes); diff --git a/testcases/t/243-move-to-mark.t b/testcases/t/243-move-to-mark.t index a9250770..58105d76 100644 --- a/testcases/t/243-move-to-mark.t +++ b/testcases/t/243-move-to-mark.t @@ -26,6 +26,27 @@ my ($A, $B, $S, $M, $F, $source_ws, $target_ws, $ws); my ($nodes, $focus); my $cmd_result; +my $_NET_WM_STATE_REMOVE = 0; +my $_NET_WM_STATE_ADD = 1; +my $_NET_WM_STATE_TOGGLE = 2; + +sub set_urgency { + my ($win, $urgent_flag) = @_; + my $msg = pack "CCSLLLLLL", + X11::XCB::CLIENT_MESSAGE, # response_type + 32, # format + 0, # sequence + $win->id, # window + $x->atom(name => '_NET_WM_STATE')->id, # message type + ($urgent_flag ? $_NET_WM_STATE_ADD : $_NET_WM_STATE_REMOVE), # data32[0] + $x->atom(name => '_NET_WM_STATE_DEMANDS_ATTENTION')->id, # data32[1] + 0, # data32[2] + 0, # data32[3] + 0; # data32[4] + + $x->send_event(0, $x->get_root_window(), X11::XCB::EVENT_MASK_SUBSTRUCTURE_REDIRECT, $msg); +} + ############################################################################### # Given 'M' and 'S' in a horizontal split, when 'S' is moved to 'M', then # verify that nothing changed. @@ -102,7 +123,22 @@ is($nodes->[1]->{window}, $S->{id}, 'S is right of M'); # moved to 'M', then the urgency flag is transferred to the target workspace. ############################################################################### -# TODO +$source_ws = fresh_workspace; +$S = open_window; +$F = open_window; +$target_ws = fresh_workspace; +$M = open_window; +cmd 'mark target'; +cmd 'workspace ' . $source_ws; +set_urgency($S, 1); + +cmd '[id="' . $S->{id} . '"] move container to mark target'; +sync_with_i3; + +$source_ws = get_ws($source_ws); +$target_ws = get_ws($target_ws); +ok(!$source_ws->{urgent}, 'source workspace is no longer urgent'); +ok($target_ws->{urgent}, 'target workspace is urgent'); ############################################################################### # Given 'S' and 'M' where 'M' is inside a tabbed container, when 'S' is moved @@ -250,14 +286,6 @@ sync_with_i3; is(@{$nodes}, 2, 'there is a tabbed container and a window'); is($nodes->[1]->{window}, $S->{id}, 'S is the second window'); -############################################################################### -# Given 'S', 'F' and 'M' where 'F' and 'M' are containers inside the same -# tabbed container and where 'F' has the focus within that container, when -# 'S' is moved to 'M', then 'S' ends up behind 'F'. -############################################################################### - -# TODO needs to be clarified whether this is the behavior we want - ############################################################################### # Given 'S' and 'M' where 'S' is floating and 'M' on a different workspace, # when 'S' is moved to 'M', then 'S' is a floating container on the same From 191671c9b8b66865280b2a73e218c16773468bc4 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 19 Apr 2015 21:11:22 +0200 Subject: [PATCH 081/243] contributing: mention that we cannot support closed-source software --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7a5e0c5f..1e130761 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,11 @@ and https://github.com/i3/i3lock 1. Read http://i3wm.org/docs/debugging.html 2. Make sure you include a link to your logfile in your report (section 3). 3. Make sure you include the i3 version number in your report (section 1). +4. Please be aware that we cannot support compatibility issues with + closed-source software, as digging into compatibility problems without + having access to the source code is too time-consuming. Additionally, + experience has shown that often, the software in question is responsible for + the issue. Please raise an issue with the software in question, not i3. # Pull requests From 798e654af7d8d0a0b685b36433b48f4a62607863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Mon, 20 Apr 2015 17:51:34 +0200 Subject: [PATCH 082/243] Adapt release.sh to update the latest version in the debugging docs. --- docs/debugging | 6 +++--- release.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/debugging b/docs/debugging index 1253b0c5..b8031036 100644 --- a/docs/debugging +++ b/docs/debugging @@ -10,10 +10,10 @@ Thank you for being interested in debugging i3. It really means something to us to get your bug fixed. If you have any questions about the process and/or need further help, do not hesitate to contact us! -== Verify you are using i3 ≥ 4.7 +== Verify you are using i3 ≥ 4.10 -Only the latest major version of i3 is supported, i.e. version 4.7 currently. -To verify which version you are running, use: +Only the latest major version of i3 is supported. To verify which version +you are running, use: --------------- $ i3 --moreversion 2>&- || i3 --version diff --git a/release.sh b/release.sh index 16227111..4dd02777 100755 --- a/release.sh +++ b/release.sh @@ -147,6 +147,7 @@ git add downloads/i3-${RELEASE_VERSION}.tar.bz2* cp ${TMPDIR}/i3/RELEASE-NOTES-${RELEASE_VERSION} downloads/RELEASE-NOTES-${RELEASE_VERSION}.txt git add downloads/RELEASE-NOTES-${RELEASE_VERSION}.txt sed -i "s,

Documentation for i3 v[^<]*

,

Documentation for i3 v${RELEASE_VERSION}

,g" docs/index.html +sed -i "s,Verify you are using i3 ≥ .*,Verify you are using i3 ≥ ${RELEASE_VERSION},g" docs/debugging.html sed -i "s,[^<]*,${RELEASE_VERSION},g" index.html sed -i "s,The current stable version is .*$,The current stable version is ${RELEASE_VERSION}.,g" downloads/index.html sed -i "s,,\n \n ${RELEASE_VERSION}\n i3-${RELEASE_VERSION}.tar.bz2\n $(ls -lh ../i3/i3-${RELEASE_VERSION}.tar.bz2 | awk -F " " {'print $5'} | sed 's/K$/ KiB/g')\n signature\n $(date +'%Y-%m-%d')\n release notes\n \n,g" downloads/index.html From f8a52f0862744160405404d9cac03289e01d73f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 19 Apr 2015 22:37:37 +0200 Subject: [PATCH 083/243] Provide instructions on how to debug i3bar --- docs/debugging | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/debugging b/docs/debugging index 1253b0c5..400a6b2b 100644 --- a/docs/debugging +++ b/docs/debugging @@ -121,3 +121,19 @@ When debugging with us in IRC, be prepared to use a so called nopaste service such as http://nopaste.info or http://pastebin.com because pasting large amounts of text in IRC sometimes leads to incomplete lines (servers have line length limitations) or flood kicks. + +== Debugging i3bar + +To debug i3bar problems, add +verbose yes+ to all +bar {}+ blocks in your i3 config +and then restart all i3bar instances like this: + +--------------------------------------------------------------------- +$ killall i3bar +$ for c in $(i3-msg -t get_bar_config | python -c \ + 'import json,sys;print("\n".join(json.load(sys.stdin)))'); do \ + (i3bar --bar_id=$c >i3bar.$c.log 2>&1) & \ + done; +--------------------------------------------------------------------- + +There will now be +i3bar.*.log+ files in your current directory that you can provide +in your bug report. From 550c0ec31867f780b4bbd1a14f1496e7919a2766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sat, 18 Apr 2015 21:09:03 +0200 Subject: [PATCH 084/243] Implement new criterion 'window_type = normal|dialog|utility|toolbar|splash|menu|dropdown_menu|popup_menu|tooltip' fixes #1658 --- docs/userguide | 4 ++++ include/atoms.xmacro | 5 +++++ include/data.h | 4 ++++ include/xcb.h | 10 ++++++++++ parser-specs/commands.spec | 1 + parser-specs/config.spec | 1 + src/commands.c | 25 ++++++++++++++++++++++++ src/config_directives.c | 25 ++++++++++++++++++++++++ src/ewmh.c | 4 ++-- src/main.c | 40 +++++++++++++++++++------------------- src/manage.c | 3 +++ src/match.c | 15 ++++++++++++-- src/xcb.c | 29 +++++++++++++++++++++++++++ 13 files changed, 142 insertions(+), 24 deletions(-) diff --git a/docs/userguide b/docs/userguide index 687dff10..965f839e 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1508,6 +1508,10 @@ instance:: Compares the window instance (the first part of WM_CLASS) window_role:: Compares the window role (WM_WINDOW_ROLE). +window_type:: + Compare the window type (_NET_WM_WINDOW_TYPE). Possible values are + +normal+, +dialog+, +utility+, +toolbar+, +splash+, +menu+, +dropdown_menu+, + +popup_menu+ and +toolti+. id:: Compares the X11 window ID, which you can get via +xwininfo+ for example. title:: diff --git a/include/atoms.xmacro b/include/atoms.xmacro index 59dab6ed..b9ee4eb7 100644 --- a/include/atoms.xmacro +++ b/include/atoms.xmacro @@ -7,11 +7,16 @@ xmacro(_NET_WM_STATE_DEMANDS_ATTENTION) xmacro(_NET_WM_STATE_MODAL) xmacro(_NET_WM_STATE) xmacro(_NET_WM_WINDOW_TYPE) +xmacro(_NET_WM_WINDOW_TYPE_NORMAL) xmacro(_NET_WM_WINDOW_TYPE_DOCK) xmacro(_NET_WM_WINDOW_TYPE_DIALOG) xmacro(_NET_WM_WINDOW_TYPE_UTILITY) xmacro(_NET_WM_WINDOW_TYPE_TOOLBAR) xmacro(_NET_WM_WINDOW_TYPE_SPLASH) +xmacro(_NET_WM_WINDOW_TYPE_MENU) +xmacro(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU) +xmacro(_NET_WM_WINDOW_TYPE_POPUP_MENU) +xmacro(_NET_WM_WINDOW_TYPE_TOOLTIP) xmacro(_NET_WM_DESKTOP) xmacro(_NET_WM_STRUT_PARTIAL) xmacro(_NET_CLIENT_LIST) diff --git a/include/data.h b/include/data.h index 50e1f180..5fb9a074 100644 --- a/include/data.h +++ b/include/data.h @@ -378,6 +378,9 @@ struct Window { * default will be 'accepts focus'. */ bool doesnt_accept_focus; + /** The _NET_WM_WINDOW_TYPE for this window. */ + xcb_atom_t window_type; + /** Whether the window says it is a dock window */ enum { W_NODOCK = 0, W_DOCK_TOP = 1, @@ -408,6 +411,7 @@ struct Match { struct regex *instance; struct regex *mark; struct regex *window_role; + xcb_atom_t window_type; enum { U_DONTCHECK = -1, U_LATEST = 0, diff --git a/include/xcb.h b/include/xcb.h index 9f4ea91f..69d5af2c 100644 --- a/include/xcb.h +++ b/include/xcb.h @@ -108,6 +108,16 @@ void xcb_raise_window(xcb_connection_t *conn, xcb_window_t window); */ void xcb_set_window_rect(xcb_connection_t *conn, xcb_window_t window, Rect r); +/** + * Returns the first supported _NET_WM_WINDOW_TYPE atom. + * + */ +xcb_atom_t xcb_get_preferred_window_type(xcb_get_property_reply_t *reply); + +/** + * Returns true if the given reply contains the given data. + * + */ bool xcb_reply_contains_atom(xcb_get_property_reply_t *prop, xcb_atom_t atom); /** diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec index 87db6cf0..e6217b19 100644 --- a/parser-specs/commands.spec +++ b/parser-specs/commands.spec @@ -49,6 +49,7 @@ state CRITERIA: ctype = 'con_mark' -> CRITERION ctype = 'title' -> CRITERION ctype = 'urgent' -> CRITERION + ctype = 'window_type' -> CRITERION ']' -> call cmd_criteria_match_windows(); INITIAL state CRITERION: diff --git a/parser-specs/config.spec b/parser-specs/config.spec index d27e0792..c5c8ad25 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -167,6 +167,7 @@ state CRITERIA: ctype = 'window_role' -> CRITERION ctype = 'con_id' -> CRITERION ctype = 'id' -> CRITERION + ctype = 'window_type' -> CRITERION ctype = 'con_mark' -> CRITERION ctype = 'title' -> CRITERION ctype = 'urgent' -> CRITERION diff --git a/src/commands.c b/src/commands.c index 79071d6b..6b720251 100644 --- a/src/commands.c +++ b/src/commands.c @@ -363,6 +363,31 @@ void cmd_criteria_add(I3_CMD, char *ctype, char *cvalue) { return; } + if (strcmp(ctype, "window_type") == 0) { + if (strcasecmp(cvalue, "normal") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_NORMAL; + else if (strcasecmp(cvalue, "dialog") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_DIALOG; + else if (strcasecmp(cvalue, "utility") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_UTILITY; + else if (strcasecmp(cvalue, "toolbar") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLBAR; + else if (strcasecmp(cvalue, "splash") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_SPLASH; + else if (strcasecmp(cvalue, "menu") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_MENU; + else if (strcasecmp(cvalue, "dropdown_menu") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU; + else if (strcasecmp(cvalue, "popup_menu") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_POPUP_MENU; + else if (strcasecmp(cvalue, "tooltip") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLTIP; + else + ELOG("unknown window_type value \"%s\"\n", cvalue); + + return; + } + if (strcmp(ctype, "con_mark") == 0) { current_match->mark = regex_new(cvalue); return; diff --git a/src/config_directives.c b/src/config_directives.c index 398e53bb..49e8d91d 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -89,6 +89,31 @@ CFGFUN(criteria_add, const char *ctype, const char *cvalue) { return; } + if (strcmp(ctype, "window_type") == 0) { + if (strcasecmp(cvalue, "normal") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_NORMAL; + else if (strcasecmp(cvalue, "dialog") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_DIALOG; + else if (strcasecmp(cvalue, "utility") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_UTILITY; + else if (strcasecmp(cvalue, "toolbar") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLBAR; + else if (strcasecmp(cvalue, "splash") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_SPLASH; + else if (strcasecmp(cvalue, "menu") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_MENU; + else if (strcasecmp(cvalue, "dropdown_menu") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU; + else if (strcasecmp(cvalue, "popup_menu") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_POPUP_MENU; + else if (strcasecmp(cvalue, "tooltip") == 0) + current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLTIP; + else + ELOG("unknown window_type value \"%s\"\n", cvalue); + + return; + } + if (strcmp(ctype, "con_mark") == 0) { current_match->mark = regex_new(cvalue); return; diff --git a/src/ewmh.c b/src/ewmh.c index 844a0db9..883b929e 100644 --- a/src/ewmh.c +++ b/src/ewmh.c @@ -234,6 +234,6 @@ 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"); - /* only send the first 24 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */ - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 24, supported_atoms); + /* only send the first 29 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */ + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 29, supported_atoms); } diff --git a/src/main.c b/src/main.c index ac40e7a3..3c534431 100644 --- a/src/main.c +++ b/src/main.c @@ -474,6 +474,12 @@ int main(int argc, char *argv[]) { root_screen = xcb_aux_get_screen(conn, conn_screen); root = root_screen->root; +/* Place requests for the atoms we need as soon as possible */ +#define xmacro(atom) \ + xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom); +#include "atoms.xmacro" +#undef xmacro + /* By default, we use the same depth and visual as the root window, which * usually is TrueColor (24 bit depth) and the corresponding visual. * However, we also check if a 32 bit depth and visual are available (for @@ -491,6 +497,20 @@ int main(int argc, char *argv[]) { xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(conn, root); xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(conn, root); +/* Setup NetWM atoms */ +#define xmacro(name) \ + do { \ + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name##_cookie, NULL); \ + if (!reply) { \ + ELOG("Could not get atom " #name "\n"); \ + exit(-1); \ + } \ + A_##name = reply->atom; \ + free(reply); \ + } while (0); +#include "atoms.xmacro" +#undef xmacro + load_configuration(conn, override_configpath, false); if (config.ipc_socket_path == NULL) { @@ -512,12 +532,6 @@ int main(int argc, char *argv[]) { } DLOG("root geometry reply: (%d, %d) %d x %d\n", greply->x, greply->y, greply->width, greply->height); -/* Place requests for the atoms we need as soon as possible */ -#define xmacro(atom) \ - xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom); -#include "atoms.xmacro" -#undef xmacro - xcursor_load_cursors(); /* Set a cursor for the root window (otherwise the root window will show no @@ -547,20 +561,6 @@ int main(int argc, char *argv[]) { restore_connect(); -/* Setup NetWM atoms */ -#define xmacro(name) \ - do { \ - xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name##_cookie, NULL); \ - if (!reply) { \ - ELOG("Could not get atom " #name "\n"); \ - exit(-1); \ - } \ - A_##name = reply->atom; \ - free(reply); \ - } while (0); -#include "atoms.xmacro" -#undef xmacro - property_handlers_init(); ewmh_setup_hints(); diff --git a/src/manage.c b/src/manage.c index 3499963b..bc9c9bff 100644 --- a/src/manage.c +++ b/src/manage.c @@ -210,6 +210,9 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki /* check if the window needs WM_TAKE_FOCUS */ cwindow->needs_take_focus = window_supports_protocol(cwindow->id, A_WM_TAKE_FOCUS); + /* read the preferred _NET_WM_WINDOW_TYPE atom */ + cwindow->window_type = xcb_get_preferred_window_type(type_reply); + /* Where to start searching for a container that swallows the new one? */ Con *search_at = croot; diff --git a/src/match.c b/src/match.c index dc4d422f..21778ed1 100644 --- a/src/match.c +++ b/src/match.c @@ -27,8 +27,10 @@ */ void match_init(Match *match) { memset(match, 0, sizeof(Match)); - match->dock = -1; + match->dock = M_DONTCHECK; match->urgent = U_DONTCHECK; + /* we use this as the placeholder value for "not set". */ + match->window_type = UINT32_MAX; } /* @@ -48,6 +50,7 @@ bool match_is_empty(Match *match) { match->window_role == NULL && match->urgent == U_DONTCHECK && match->id == XCB_NONE && + match->window_type == UINT32_MAX && match->con_id == NULL && match->dock == -1 && match->floating == M_ANY); @@ -129,6 +132,14 @@ bool match_matches_window(Match *match, i3Window *window) { } } + if (match->window_type != UINT32_MAX) { + if (window->window_type == match->window_type) { + LOG("window_type matches (%i)\n", match->window_type); + } else { + return false; + } + } + Con *con = NULL; if (match->urgent == U_LATEST) { /* if the window isn't urgent, no sense in searching */ @@ -161,7 +172,7 @@ bool match_matches_window(Match *match, i3Window *window) { LOG("urgent matches oldest\n"); } - if (match->dock != -1) { + if (match->dock != M_DONTCHECK) { if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) || (window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) || ((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) && diff --git a/src/xcb.c b/src/xcb.c index 5dda5cce..d081d54d 100644 --- a/src/xcb.c +++ b/src/xcb.c @@ -154,6 +154,35 @@ void xcb_set_window_rect(xcb_connection_t *conn, xcb_window_t window, Rect r) { add_ignore_event(cookie.sequence, -1); } +/* + * Returns the first supported _NET_WM_WINDOW_TYPE atom. + * + */ +xcb_atom_t xcb_get_preferred_window_type(xcb_get_property_reply_t *reply) { + if (reply == NULL || xcb_get_property_value_length(reply) == 0) + return XCB_NONE; + + xcb_atom_t *atoms; + if ((atoms = xcb_get_property_value(reply)) == NULL) + return XCB_NONE; + + for (int i = 0; i < xcb_get_property_value_length(reply) / (reply->format / 8); i++) { + if (atoms[i] == A__NET_WM_WINDOW_TYPE_NORMAL || + atoms[i] == A__NET_WM_WINDOW_TYPE_DIALOG || + atoms[i] == A__NET_WM_WINDOW_TYPE_UTILITY || + atoms[i] == A__NET_WM_WINDOW_TYPE_TOOLBAR || + atoms[i] == A__NET_WM_WINDOW_TYPE_SPLASH || + atoms[i] == A__NET_WM_WINDOW_TYPE_MENU || + atoms[i] == A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU || + atoms[i] == A__NET_WM_WINDOW_TYPE_POPUP_MENU || + atoms[i] == A__NET_WM_WINDOW_TYPE_TOOLTIP) { + return atoms[i]; + } + } + + return XCB_NONE; +} + /* * Returns true if the given reply contains the given atom. * From 1f472b454cdb7d7e5d6d064e273bf927d193be42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 19 Apr 2015 00:29:31 +0200 Subject: [PATCH 085/243] Handle changes to _NET_WM_WINDOW_TYPE after the window has been managed. --- include/window.h | 6 ++++++ src/handlers.c | 20 +++++++++++--------- src/window.c | 17 +++++++++++++++++ 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/include/window.h b/include/window.h index 480cee18..d5b07cb1 100644 --- a/include/window.h +++ b/include/window.h @@ -56,6 +56,12 @@ void window_update_strut_partial(i3Window *win, xcb_get_property_reply_t *prop); */ void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt); +/** + * Updates the _NET_WM_WINDOW_TYPE property. + * + */ +void window_update_type(i3Window *window, xcb_get_property_reply_t *reply); + /** * Updates the WM_HINTS (we only care about the input focus handling part). * diff --git a/src/handlers.c b/src/handlers.c index c80c279e..0d536e44 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -892,15 +892,15 @@ static void handle_client_message(xcb_client_message_event_t *event) { } } -#if 0 -int handle_window_type(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window, - xcb_atom_t atom, xcb_get_property_reply_t *property) { - /* TODO: Implement this one. To do this, implement a little test program which sleep(1)s - before changing this property. */ - ELOG("_NET_WM_WINDOW_TYPE changed, this is not yet implemented.\n"); - return 0; +bool handle_window_type(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window, + xcb_atom_t atom, xcb_get_property_reply_t *reply) { + Con *con; + if ((con = con_by_window_id(window)) == NULL || con->window == NULL) + return false; + + window_update_type(con->window, reply); + return true; } -#endif /* * Handles the size hints set by a window, but currently only the part necessary for displaying @@ -1264,7 +1264,8 @@ static struct property_handler_t property_handlers[] = { {0, UINT_MAX, handle_transient_for}, {0, 128, handle_windowrole_change}, {0, 128, handle_class_change}, - {0, UINT_MAX, handle_strut_partial_change}}; + {0, UINT_MAX, handle_strut_partial_change}, + {0, UINT_MAX, handle_window_type}}; #define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t)) /* @@ -1284,6 +1285,7 @@ void property_handlers_init(void) { property_handlers[6].atom = A_WM_WINDOW_ROLE; property_handlers[7].atom = XCB_ATOM_WM_CLASS; property_handlers[8].atom = A__NET_WM_STRUT_PARTIAL; + property_handlers[9].atom = A__NET_WM_WINDOW_TYPE; } static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) { diff --git a/src/window.c b/src/window.c index 5485bcc3..b87c1db5 100644 --- a/src/window.c +++ b/src/window.c @@ -232,6 +232,23 @@ void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool befo free(prop); } +/* + * Updates the _NET_WM_WINDOW_TYPE property. + * + */ +void window_update_type(i3Window *window, xcb_get_property_reply_t *reply) { + xcb_atom_t new_type = xcb_get_preferred_window_type(reply); + if (new_type == XCB_NONE) { + DLOG("cannot read _NET_WM_WINDOW_TYPE from window.\n"); + return; + } + + window->window_type = new_type; + LOG("_NET_WM_WINDOW_TYPE changed to %i", window->window_type); + + run_assignments(window); +} + /* * Updates the WM_HINTS (we only care about the input focus handling part). * From 18c45a7f098a05549c2ab3dd12d42c77771d1064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 19 Apr 2015 00:30:01 +0200 Subject: [PATCH 086/243] Added testcase for changing _NET_WM_WINDOW_TYPE after the window is already managed. --- testcases/t/165-for_window.t | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/testcases/t/165-for_window.t b/testcases/t/165-for_window.t index 036fc9d6..a7629d63 100644 --- a/testcases/t/165-for_window.t +++ b/testcases/t/165-for_window.t @@ -408,6 +408,39 @@ EOT } +############################################################## +# 11: check that the criterion 'window_type' works if the +# _NET_WM_WINDOW_TYPE is changed after managing. +############################################################## + +while (my ($window_type, $atom) = each %window_types) { + + $config = <<"EOT"; +# i3 config file (v4) +font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 +for_window [window_type="$window_type"] floating enable, mark branded +EOT + + $pid = launch_with_config($config); + $tmp = fresh_workspace; + + $window = open_window(); + + my $atomname = $x->atom(name => '_NET_WM_WINDOW_TYPE'); + my $atomtype = $x->atom(name => 'ATOM'); + $x->change_property(PROP_MODE_REPLACE, $window->id, $atomname->id, $atomtype->id, + 32, 1, pack('L1', $x->atom(name => $atom)->id)); + $x->flush; + sync_with_i3; + + my @nodes = @{get_ws($tmp)->{floating_nodes}}; + cmp_ok(@nodes, '==', 1, 'one floating container on this workspace'); + is($nodes[0]->{nodes}[0]->{mark}, 'branded', "mark set (window_type = $atom)"); + + exit_gracefully($pid); + +} + ############################################################## done_testing; From 761a8713df7c768e939eeae1c922b8d7d1194d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 19 Apr 2015 00:37:10 +0200 Subject: [PATCH 087/243] Added testcase for 'window_type' criterion when used as a command. --- testcases/t/232-cmd-move-criteria.t | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/testcases/t/232-cmd-move-criteria.t b/testcases/t/232-cmd-move-criteria.t index 22a2eb4e..48a51d56 100644 --- a/testcases/t/232-cmd-move-criteria.t +++ b/testcases/t/232-cmd-move-criteria.t @@ -18,6 +18,10 @@ # Bug still in: 4.8-16-g6888a1f use i3test; +############################################################################### +# Tets moving with 'id' criterion. +############################################################################### + my $ws = fresh_workspace; my $win1 = open_window; @@ -34,4 +38,39 @@ my $ws_con = get_ws($ws); is($ws_con->{nodes}[0]->{window}, $win2->{id}, 'the `move [direction]` command should work with criteria'); is($x->input_focus, $win3->{id}, 'it should not disturb focus'); +############################################################################### +# Tets moving with 'window_type' criterion. +############################################################################### + +# test all window types +my %window_types = ( + 'normal' => '_NET_WM_WINDOW_TYPE_NORMAL', + 'dialog' => '_NET_WM_WINDOW_TYPE_DIALOG', + 'utility' => '_NET_WM_WINDOW_TYPE_UTILITY', + 'toolbar' => '_NET_WM_WINDOW_TYPE_TOOLBAR', + 'splash' => '_NET_WM_WINDOW_TYPE_SPLASH', + 'menu' => '_NET_WM_WINDOW_TYPE_MENU', + 'dropdown_menu' => '_NET_WM_WINDOW_TYPE_DROPDOWN_MENU', + 'popup_menu' => '_NET_WM_WINDOW_TYPE_POPUP_MENU', + 'tooltip' => '_NET_WM_WINDOW_TYPE_TOOLTIP' +); + +while (my ($window_type, $atom) = each %window_types) { + + $ws = fresh_workspace; + + $win1 = open_window(window_type => $x->atom(name => $atom)); + $win2 = open_window; + $win3 = open_window; + + cmd '[window_type="' . $window_type . '"] move right'; + + $ws_con = get_ws($ws); + is($ws_con->{nodes}[0]->{window}, $win2->{id}, 'the `move [direction]` command should work with window_type = ' . $window_type); + is($x->input_focus, $win3->{id}, 'it should not disturb focus'); + +} + +############################################################################### + done_testing; From 09d1deda7f471c737d38665c4f6a212429ee5b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 19 Apr 2015 10:47:09 +0200 Subject: [PATCH 088/243] Small cleanups: * Implement criterion specs just like it is done in the spec for the config * Declare variables in test case early so the 'my' keyword can be dropped in the actual test cases --- parser-specs/commands.spec | 14 +++++++------- testcases/t/232-cmd-move-criteria.t | 12 +++++++----- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec index e6217b19..d8f81d3e 100644 --- a/parser-specs/commands.spec +++ b/parser-specs/commands.spec @@ -41,15 +41,15 @@ state INITIAL: 'bar' -> BAR state CRITERIA: - ctype = 'class' -> CRITERION - ctype = 'instance' -> CRITERION + ctype = 'class' -> CRITERION + ctype = 'instance' -> CRITERION ctype = 'window_role' -> CRITERION - ctype = 'con_id' -> CRITERION - ctype = 'id' -> CRITERION - ctype = 'con_mark' -> CRITERION - ctype = 'title' -> CRITERION - ctype = 'urgent' -> CRITERION + ctype = 'con_id' -> CRITERION + ctype = 'id' -> CRITERION ctype = 'window_type' -> CRITERION + ctype = 'con_mark' -> CRITERION + ctype = 'title' -> CRITERION + ctype = 'urgent' -> CRITERION ']' -> call cmd_criteria_match_windows(); INITIAL state CRITERION: diff --git a/testcases/t/232-cmd-move-criteria.t b/testcases/t/232-cmd-move-criteria.t index 48a51d56..c023bca4 100644 --- a/testcases/t/232-cmd-move-criteria.t +++ b/testcases/t/232-cmd-move-criteria.t @@ -18,21 +18,23 @@ # Bug still in: 4.8-16-g6888a1f use i3test; +my ($ws, $win1, $win2, $win3, $ws_con); + ############################################################################### # Tets moving with 'id' criterion. ############################################################################### -my $ws = fresh_workspace; +$ws = fresh_workspace; -my $win1 = open_window; -my $win2 = open_window; -my $win3 = open_window; +$win1 = open_window; +$win2 = open_window; +$win3 = open_window; # move win1 from the left to the right cmd '[id="' . $win1->{id} . '"] move right'; # now they should be switched, with win2 still being focused -my $ws_con = get_ws($ws); +$ws_con = get_ws($ws); # win2 should be on the left is($ws_con->{nodes}[0]->{window}, $win2->{id}, 'the `move [direction]` command should work with criteria'); From e4a86d4aefa0b992fe4e1472d78fc58a352dcea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 19 Apr 2015 10:47:33 +0200 Subject: [PATCH 089/243] Cleanup: delete comments that were accidentally copy-pasted and are incorrect for these test cases --- testcases/t/165-for_window.t | 6 ------ 1 file changed, 6 deletions(-) diff --git a/testcases/t/165-for_window.t b/testcases/t/165-for_window.t index a7629d63..b684d41f 100644 --- a/testcases/t/165-for_window.t +++ b/testcases/t/165-for_window.t @@ -287,9 +287,6 @@ exit_gracefully($pid); # 8: check that the role criterion works properly ############################################################## -# this configuration is broken because "asdf" is not a valid integer -# the for_window should therefore recognize this error and don’t add the -# assignment $config = < Date: Fri, 3 Apr 2015 20:17:56 -0400 Subject: [PATCH 090/243] Update copyright notices and get rid of ranges The script used to make these changes can be found at: https://gist.github.com/Deiz/32322020f76d23e2bf8f --- docs/asciidoc-git.conf | 2 +- generate-command-parser.pl | 2 +- i3-config-wizard/main.c | 2 +- i3-dmenu-desktop | 4 ++-- i3-dump-log/main.c | 2 +- i3-input/main.c | 2 +- i3-msg/main.c | 2 +- i3-nagbar/main.c | 2 +- i3-save-tree | 2 +- i3bar/include/child.h | 2 +- i3bar/include/common.h | 2 +- i3bar/include/config.h | 2 +- i3bar/include/ipc.h | 2 +- i3bar/include/mode.h | 2 +- i3bar/include/outputs.h | 2 +- i3bar/include/parse_json_header.h | 2 +- i3bar/include/trayclients.h | 2 +- i3bar/include/util.h | 2 +- i3bar/include/workspaces.h | 2 +- i3bar/include/xcb.h | 2 +- i3bar/src/child.c | 2 +- i3bar/src/config.c | 2 +- i3bar/src/ipc.c | 2 +- i3bar/src/main.c | 4 ++-- i3bar/src/mode.c | 2 +- i3bar/src/outputs.c | 2 +- i3bar/src/parse_json_header.c | 2 +- i3bar/src/workspaces.c | 2 +- i3bar/src/xcb.c | 2 +- include/all.h | 2 +- include/assignments.h | 2 +- include/bindings.h | 2 +- include/click.h | 2 +- include/cmdparse.h | 2 +- include/commands.h | 2 +- include/commands_parser.h | 2 +- include/con.h | 2 +- include/config.h | 2 +- include/config_directives.h | 2 +- include/config_parser.h | 2 +- include/data.h | 2 +- include/debug.h | 2 +- include/display_version.h | 2 +- include/ewmh.h | 2 +- include/fake_outputs.h | 2 +- include/floating.h | 2 +- include/handlers.h | 2 +- include/i3.h | 2 +- include/i3/ipc.h | 2 +- include/ipc.h | 2 +- include/key_press.h | 2 +- include/libi3.h | 2 +- include/load_layout.h | 2 +- include/log.h | 2 +- include/main.h | 2 +- include/manage.h | 2 +- include/match.h | 2 +- include/move.h | 2 +- include/output.h | 2 +- include/randr.h | 2 +- include/regex.h | 2 +- include/render.h | 2 +- include/resize.h | 2 +- include/restore_layout.h | 2 +- include/scratchpad.h | 2 +- include/shmlog.h | 2 +- include/sighandler.h | 4 ++-- include/startup.h | 2 +- include/tree.h | 2 +- include/util.h | 2 +- include/window.h | 2 +- include/workspace.h | 2 +- include/x.h | 2 +- include/xcb.h | 2 +- include/xcb_compat.h | 2 +- include/xcursor.h | 2 +- include/xinerama.h | 2 +- include/yajl_utils.h | 2 +- libi3/dpi.c | 2 +- libi3/fake_configure_notify.c | 2 +- libi3/font.c | 2 +- libi3/get_colorpixel.c | 2 +- libi3/get_config_path.c | 2 +- libi3/get_mod_mask.c | 2 +- libi3/get_process_filename.c | 2 +- libi3/get_visualtype.c | 2 +- libi3/ipc_connect.c | 2 +- libi3/ipc_recv_message.c | 2 +- libi3/ipc_send_message.c | 2 +- libi3/resolve_tilde.c | 2 +- libi3/root_atom_contents.c | 2 +- libi3/safewrappers.c | 2 +- libi3/string.c | 2 +- libi3/strndup.c | 2 +- libi3/ucs2_conversion.c | 2 +- parser-specs/commands.spec | 2 +- parser-specs/config.spec | 2 +- src/assignments.c | 2 +- src/bindings.c | 2 +- src/click.c | 2 +- src/commands.c | 2 +- src/commands_parser.c | 2 +- src/con.c | 2 +- src/config.c | 2 +- src/config_directives.c | 2 +- src/config_parser.c | 2 +- src/debug.c | 2 +- src/display_version.c | 2 +- src/ewmh.c | 2 +- src/fake_outputs.c | 2 +- src/floating.c | 2 +- src/handlers.c | 2 +- src/ipc.c | 2 +- src/key_press.c | 2 +- src/load_layout.c | 2 +- src/log.c | 2 +- src/main.c | 6 +++--- src/manage.c | 2 +- src/match.c | 2 +- src/move.c | 2 +- src/output.c | 2 +- src/randr.c | 2 +- src/regex.c | 2 +- src/render.c | 2 +- src/resize.c | 2 +- src/restore_layout.c | 2 +- src/scratchpad.c | 2 +- src/sighandler.c | 4 ++-- src/startup.c | 2 +- src/tree.c | 2 +- src/util.c | 2 +- src/version.c | 2 +- src/window.c | 2 +- src/workspace.c | 2 +- src/x.c | 2 +- src/xcb.c | 2 +- src/xcursor.c | 2 +- src/xinerama.c | 2 +- testcases/complete-run.pl | 2 +- 139 files changed, 145 insertions(+), 145 deletions(-) diff --git a/docs/asciidoc-git.conf b/docs/asciidoc-git.conf index 3d42bca8..36bdb6f5 100644 --- a/docs/asciidoc-git.conf +++ b/docs/asciidoc-git.conf @@ -647,7 +647,7 @@ endif::doctype-manpage[] {disable-javascript%

} diff --git a/generate-command-parser.pl b/generate-command-parser.pl index 9b5ef562..f40bb390 100755 --- a/generate-command-parser.pl +++ b/generate-command-parser.pl @@ -2,7 +2,7 @@ # vim:ts=4:sw=4:expandtab # # i3 - an improved dynamic tiling window manager -# © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) +# © 2009 Michael Stapelberg and contributors (see also: LICENSE) # # generate-command-parser.pl: script to generate parts of the command parser # from its specification file parser-specs/commands.spec. diff --git a/i3-config-wizard/main.c b/i3-config-wizard/main.c index 9c9241cd..4c1d9697 100644 --- a/i3-config-wizard/main.c +++ b/i3-config-wizard/main.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * i3-config-wizard: Program to convert configs using keycodes to configs using * keysyms. diff --git a/i3-dmenu-desktop b/i3-dmenu-desktop index cc72f101..a0549ead 100755 --- a/i3-dmenu-desktop +++ b/i3-dmenu-desktop @@ -1,7 +1,7 @@ #!/usr/bin/env perl # vim:ts=4:sw=4:expandtab # -# © 2012-2014 Michael Stapelberg +# © 2012 Michael Stapelberg # # No dependencies except for perl ≥ v5.10 @@ -45,7 +45,7 @@ my $result = GetOptions( 'dmenu=s' => \$dmenu_cmd, 'entry-type=s' => \@entry_types, 'version' => sub { - say "dmenu-desktop 1.5 © 2012-2013 Michael Stapelberg"; + say "dmenu-desktop 1.5 © 2012 Michael Stapelberg"; exit 0; }, 'help' => sub { diff --git a/i3-dump-log/main.c b/i3-dump-log/main.c index 1b0d593c..137554a4 100644 --- a/i3-dump-log/main.c +++ b/i3-dump-log/main.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * i3-dump-log/main.c: Dumps the i3 SHM log to stdout. * diff --git a/i3-input/main.c b/i3-input/main.c index b32d7b66..5a6a740e 100644 --- a/i3-input/main.c +++ b/i3-input/main.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * i3-input/main.c: Utility which lets the user input commands and sends them * to i3. diff --git a/i3-msg/main.c b/i3-msg/main.c index 354e8af9..6a6186d8 100644 --- a/i3-msg/main.c +++ b/i3-msg/main.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * i3-msg/main.c: Utility which sends messages to a running i3-instance using * IPC via UNIX domain sockets. diff --git a/i3-nagbar/main.c b/i3-nagbar/main.c index 83389b34..d93c6585 100644 --- a/i3-nagbar/main.c +++ b/i3-nagbar/main.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * i3-nagbar is a utility which displays a nag message, for example in the case * when the user has an error in their configuration file. diff --git a/i3-save-tree b/i3-save-tree index 289fd8c6..18a1a380 100755 --- a/i3-save-tree +++ b/i3-save-tree @@ -1,7 +1,7 @@ #!/usr/bin/env perl # vim:ts=4:sw=4:expandtab # -# © 2013-2014 Michael Stapelberg +# © 2013 Michael Stapelberg # # Requires perl ≥ v5.10, AnyEvent::I3 and JSON::XS diff --git a/i3bar/include/child.h b/i3bar/include/child.h index b87cfaac..873a3465 100644 --- a/i3bar/include/child.h +++ b/i3bar/include/child.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * child.c: Getting input for the statusline * diff --git a/i3bar/include/common.h b/i3bar/include/common.h index 22b9a28a..90da9388 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2011 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * */ #pragma once diff --git a/i3bar/include/config.h b/i3bar/include/config.h index fdc37445..aeb9f0fd 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2011 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * config.c: Parses the configuration (received from i3). * diff --git a/i3bar/include/ipc.h b/i3bar/include/ipc.h index a60a1eba..686c0322 100644 --- a/i3bar/include/ipc.h +++ b/i3bar/include/ipc.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * ipc.c: Communicating with i3 * diff --git a/i3bar/include/mode.h b/i3bar/include/mode.h index 37e8e017..828d4906 100644 --- a/i3bar/include/mode.h +++ b/i3bar/include/mode.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * mode.c: Handle "mode" event and show current binding mode in the bar * diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 73fbf33f..e6605e1f 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * outputs.c: Maintaining the outputs list * diff --git a/i3bar/include/parse_json_header.h b/i3bar/include/parse_json_header.h index ef13cf78..41e97de2 100644 --- a/i3bar/include/parse_json_header.h +++ b/i3bar/include/parse_json_header.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * parse_json_header.c: Parse the JSON protocol header to determine * protocol version and features. diff --git a/i3bar/include/trayclients.h b/i3bar/include/trayclients.h index 1720ec3b..694faa48 100644 --- a/i3bar/include/trayclients.h +++ b/i3bar/include/trayclients.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2011 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * */ #pragma once diff --git a/i3bar/include/util.h b/i3bar/include/util.h index ac137998..ba08cf76 100644 --- a/i3bar/include/util.h +++ b/i3bar/include/util.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #pragma once diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index 1b8c6c72..5ed84de8 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * workspaces.c: Maintaining the workspace lists * diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index bb37e7d5..2e34c776 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * xcb.c: Communicating with X * diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 41f8880d..e5ce209d 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * child.c: Getting input for the statusline * diff --git a/i3bar/src/config.c b/i3bar/src/config.c index f7abaee7..86f66cbb 100644 --- a/i3bar/src/config.c +++ b/i3bar/src/config.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2011 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * config.c: Parses the configuration (received from i3). * diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 15a26d7b..eb48afea 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * ipc.c: Communicating with i3 * diff --git a/i3bar/src/main.c b/i3bar/src/main.c index a9a972db..32425319 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * */ #include @@ -111,7 +111,7 @@ int main(int argc, char **argv) { socket_path = expand_path(optarg); break; case 'v': - printf("i3bar version " I3_VERSION " © 2010-2014 Axel Wagner and contributors\n"); + printf("i3bar version " I3_VERSION " © 2010 Axel Wagner and contributors\n"); exit(EXIT_SUCCESS); break; case 'b': diff --git a/i3bar/src/mode.c b/i3bar/src/mode.c index 0ff8ba4f..bae08913 100644 --- a/i3bar/src/mode.c +++ b/i3bar/src/mode.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * mode.c: Handle mode event and show current binding mode in the bar * diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 8f5c95dc..b49ff53f 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * outputs.c: Maintaining the outputs list * diff --git a/i3bar/src/parse_json_header.c b/i3bar/src/parse_json_header.c index f5fb84ab..1cd95106 100644 --- a/i3bar/src/parse_json_header.c +++ b/i3bar/src/parse_json_header.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * parse_json_header.c: Parse the JSON protocol header to determine * protocol version and features. diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index e3032526..773f8f54 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * workspaces.c: Maintaining the workspace lists * diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index ba57b9fa..fd268e91 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3bar - an xcb-based status- and ws-bar for i3 - * © 2010-2012 Axel Wagner and contributors (see also: LICENSE) + * © 2010 Axel Wagner and contributors (see also: LICENSE) * * xcb.c: Communicating with X * diff --git a/include/all.h b/include/all.h index a355d3d2..85397d59 100644 --- a/include/all.h +++ b/include/all.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * This header file includes all relevant files of i3 and the most often used * system header files. This reduces boilerplate (the amount of code duplicated diff --git a/include/assignments.h b/include/assignments.h index b83ee03f..22ebafc3 100644 --- a/include/assignments.h +++ b/include/assignments.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * assignments.c: Assignments for specific windows (for_window). * diff --git a/include/bindings.h b/include/bindings.h index c20152e9..75a719e9 100644 --- a/include/bindings.h +++ b/include/bindings.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2014 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * bindings.h: Functions for configuring, finding, and running bindings. * diff --git a/include/click.h b/include/click.h index c63672a7..7ce80d97 100644 --- a/include/click.h +++ b/include/click.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * click.c: Button press (mouse click) events. * diff --git a/include/cmdparse.h b/include/cmdparse.h index 263801f6..2ffa49b0 100644 --- a/include/cmdparse.h +++ b/include/cmdparse.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * cmdparse.y: the parser for commands you send to i3 (or bind on keys) * diff --git a/include/commands.h b/include/commands.h index ccb555a4..bbcd7f6f 100644 --- a/include/commands.h +++ b/include/commands.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * commands.c: all command functions (see commands_parser.c) * diff --git a/include/commands_parser.h b/include/commands_parser.h index cfa44dd5..1acb7fae 100644 --- a/include/commands_parser.h +++ b/include/commands_parser.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * commands.c: all command functions (see commands_parser.c) * diff --git a/include/con.h b/include/con.h index 4ee3fb7d..498fcbaa 100644 --- a/include/con.h +++ b/include/con.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * con.c: Functions which deal with containers directly (creating containers, * searching containers, getting specific properties from containers, diff --git a/include/config.h b/include/config.h index fb11cbe3..4cc58a45 100644 --- a/include/config.h +++ b/include/config.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * include/config.h: Contains all structs/variables for the configurable * part of i3 as well as functions handling the configuration file (calling diff --git a/include/config_directives.h b/include/config_directives.h index e24c834b..019b9bcd 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * config_directives.h: all config storing functions (see config_parser.c) * diff --git a/include/config_parser.h b/include/config_parser.h index 9fc3bf2f..28c28e48 100644 --- a/include/config_parser.h +++ b/include/config_parser.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * config_parser.h: config parser-related definitions * diff --git a/include/data.h b/include/data.h index 43862263..75bff3a2 100644 --- a/include/data.h +++ b/include/data.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * include/data.h: This file defines all data structures used by i3 * diff --git a/include/debug.h b/include/debug.h index 3e65c35e..3875ec6b 100644 --- a/include/debug.h +++ b/include/debug.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * debug.c: Debugging functions, especially FormatEvent, which prints unhandled * events. This code is from xcb-util. diff --git a/include/display_version.h b/include/display_version.h index 6f88ae97..b1a5a0e0 100644 --- a/include/display_version.h +++ b/include/display_version.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * display_version.c: displays the running i3 version, runs as part of * i3 --moreversion. diff --git a/include/ewmh.h b/include/ewmh.h index 3b580628..8fb7902a 100644 --- a/include/ewmh.h +++ b/include/ewmh.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * ewmh.c: Get/set certain EWMH properties easily. * diff --git a/include/fake_outputs.h b/include/fake_outputs.h index 75ef77ba..32b07fa9 100644 --- a/include/fake_outputs.h +++ b/include/fake_outputs.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * Faking outputs is useful in pathological situations (like network X servers * which don’t support multi-monitor in a useful way) and for our testsuite. diff --git a/include/floating.h b/include/floating.h index 8330b6ac..5e7b8e31 100644 --- a/include/floating.h +++ b/include/floating.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * floating.c: Floating windows. * diff --git a/include/handlers.h b/include/handlers.h index 82f6b982..d80a24f8 100644 --- a/include/handlers.h +++ b/include/handlers.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * handlers.c: Small handlers for various events (keypresses, focus changes, * …). diff --git a/include/i3.h b/include/i3.h index 70ebc000..f1912fd5 100644 --- a/include/i3.h +++ b/include/i3.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * i3.h: global variables that are used all over i3. * diff --git a/include/i3/ipc.h b/include/i3/ipc.h index f1b50dec..8912bf13 100644 --- a/include/i3/ipc.h +++ b/include/i3/ipc.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * This public header defines the different constants and message types to use * for the IPC interface to i3 (see docs/ipc for more information). diff --git a/include/ipc.h b/include/ipc.h index 4eed319a..e1c18816 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * ipc.c: UNIX domain socket IPC (initialization, client handling, protocol). * diff --git a/include/key_press.h b/include/key_press.h index 86cc6836..bbfec83b 100644 --- a/include/key_press.h +++ b/include/key_press.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * key_press.c: key press handler * diff --git a/include/libi3.h b/include/libi3.h index da8c8a42..a64b3981 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * libi3: contains functions which are used by i3 *and* accompanying tools such * as i3-msg, i3-config-wizard, … diff --git a/include/load_layout.h b/include/load_layout.h index 8736a50c..f8b7da20 100644 --- a/include/load_layout.h +++ b/include/load_layout.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2014 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * load_layout.c: Restore (parts of) the layout, for example after an inplace * restart. diff --git a/include/log.h b/include/log.h index a5086dbe..e7fc8acb 100644 --- a/include/log.h +++ b/include/log.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * log.c: Logging functions. * diff --git a/include/main.h b/include/main.h index 18c6e374..1ce53954 100644 --- a/include/main.h +++ b/include/main.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * main.c: Initialization, main loop * diff --git a/include/manage.h b/include/manage.h index bd1a14f7..b0c42381 100644 --- a/include/manage.h +++ b/include/manage.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * manage.c: Initially managing new windows (or existing ones on restart). * diff --git a/include/match.h b/include/match.h index 09975cac..dbd9bb79 100644 --- a/include/match.h +++ b/include/match.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * A "match" is a data structure which acts like a mask or expression to match * certain windows or not. For example, when using commands, you can specify a diff --git a/include/move.h b/include/move.h index 939665ec..7debcf28 100644 --- a/include/move.h +++ b/include/move.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * move.c: Moving containers into some direction. * diff --git a/include/output.h b/include/output.h index 6514c477..e0125c06 100644 --- a/include/output.h +++ b/include/output.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * output.c: Output (monitor) related functions. * diff --git a/include/randr.h b/include/randr.h index 43f7efe8..823ddea4 100644 --- a/include/randr.h +++ b/include/randr.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * For more information on RandR, please see the X.org RandR specification at * http://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt diff --git a/include/regex.h b/include/regex.h index e11d377e..2e2f22fd 100644 --- a/include/regex.h +++ b/include/regex.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * regex.c: Interface to libPCRE (perl compatible regular expressions). * diff --git a/include/render.h b/include/render.h index 1794b513..717459e9 100644 --- a/include/render.h +++ b/include/render.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * render.c: Renders (determines position/sizes) the layout tree, updating the * various rects. Needs to be pushed to X11 (see x.c) to be visible. diff --git a/include/resize.h b/include/resize.h index 5c795046..945678d9 100644 --- a/include/resize.h +++ b/include/resize.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * resize.c: Interactive resizing. * diff --git a/include/restore_layout.h b/include/restore_layout.h index 3f0229d3..f952834c 100644 --- a/include/restore_layout.h +++ b/include/restore_layout.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * restore_layout.c: Everything for restored containers that is not pure state * parsing (which can be found in load_layout.c). diff --git a/include/scratchpad.h b/include/scratchpad.h index 1aca73bd..b385550c 100644 --- a/include/scratchpad.h +++ b/include/scratchpad.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * scratchpad.c: Scratchpad functions (TODO: more description) * diff --git a/include/shmlog.h b/include/shmlog.h index 5af697e7..231681ca 100644 --- a/include/shmlog.h +++ b/include/shmlog.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * The format of the shmlog data structure which i3 development versions use by * default (ringbuffer for storing the debug log). diff --git a/include/sighandler.h b/include/sighandler.h index 184db73b..56680bc4 100644 --- a/include/sighandler.h +++ b/include/sighandler.h @@ -2,8 +2,8 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) - * © 2009-2010 Jan-Erik Rediger + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Jan-Erik Rediger * * sighandler.c: Interactive crash dialog upon SIGSEGV/SIGABRT/SIGFPE (offers * to restart inplace). diff --git a/include/startup.h b/include/startup.h index cb784913..7d5d2a39 100644 --- a/include/startup.h +++ b/include/startup.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * startup.c: Startup notification code. Ensures a startup notification context * is setup when launching applications. We store the current diff --git a/include/tree.h b/include/tree.h index b3c2a515..af3309e9 100644 --- a/include/tree.h +++ b/include/tree.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * tree.c: Everything that primarily modifies the layout tree data structure. * diff --git a/include/util.h b/include/util.h index 270b2f22..01f732ca 100644 --- a/include/util.h +++ b/include/util.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * util.c: Utility functions, which can be useful everywhere within i3 (see * also libi3). diff --git a/include/window.h b/include/window.h index 480cee18..5f8b933b 100644 --- a/include/window.h +++ b/include/window.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * window.c: Updates window attributes (X11 hints/properties). * diff --git a/include/workspace.h b/include/workspace.h index d0f801e0..82d18919 100644 --- a/include/workspace.h +++ b/include/workspace.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * workspace.c: Modifying workspaces, accessing them, moving containers to * workspaces. diff --git a/include/x.h b/include/x.h index 07f8a725..b6855cb3 100644 --- a/include/x.h +++ b/include/x.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * x.c: Interface to X11, transfers our in-memory state to X11 (see also * render.c). Basically a big state machine. diff --git a/include/xcb.h b/include/xcb.h index 9f4ea91f..1928d76a 100644 --- a/include/xcb.h +++ b/include/xcb.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * xcb.c: Helper functions for easier usage of XCB * diff --git a/include/xcb_compat.h b/include/xcb_compat.h index 89c2c457..066d834a 100644 --- a/include/xcb_compat.h +++ b/include/xcb_compat.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * xcb_compat.h: uses #define to create aliases for xcb functions which got * renamed. Makes the code work with >= 0.3.8 xcb-util and diff --git a/include/xcursor.h b/include/xcursor.h index bb329e4c..e0ee9813 100644 --- a/include/xcursor.h +++ b/include/xcursor.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * xcursor.c: libXcursor support for themed cursors. * diff --git a/include/xinerama.h b/include/xinerama.h index 46c2a635..936b9653 100644 --- a/include/xinerama.h +++ b/include/xinerama.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * This is LEGACY code (we support RandR, which can do much more than * Xinerama), but necessary for the poor users of the nVidia binary diff --git a/include/yajl_utils.h b/include/yajl_utils.h index e8422aab..93c63d8f 100644 --- a/include/yajl_utils.h +++ b/include/yajl_utils.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * yajl_utils.h * diff --git a/libi3/dpi.c b/libi3/dpi.c index 6f58d57a..a347b08f 100644 --- a/libi3/dpi.c +++ b/libi3/dpi.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2014 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include "libi3.h" diff --git a/libi3/fake_configure_notify.c b/libi3/fake_configure_notify.c index 2c0f5771..225577a4 100644 --- a/libi3/fake_configure_notify.c +++ b/libi3/fake_configure_notify.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/libi3/font.c b/libi3/font.c index 847bc61b..0f30e74e 100644 --- a/libi3/font.c +++ b/libi3/font.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/libi3/get_colorpixel.c b/libi3/get_colorpixel.c index b093594e..44ad295d 100644 --- a/libi3/get_colorpixel.c +++ b/libi3/get_colorpixel.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/libi3/get_config_path.c b/libi3/get_config_path.c index 8b6eeb7c..bad75c4d 100644 --- a/libi3/get_config_path.c +++ b/libi3/get_config_path.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2015 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include "libi3.h" diff --git a/libi3/get_mod_mask.c b/libi3/get_mod_mask.c index cf8cbe38..3b6976ad 100644 --- a/libi3/get_mod_mask.c +++ b/libi3/get_mod_mask.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/libi3/get_process_filename.c b/libi3/get_process_filename.c index 941d4439..a3dee9cd 100644 --- a/libi3/get_process_filename.c +++ b/libi3/get_process_filename.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/libi3/get_visualtype.c b/libi3/get_visualtype.c index d11722f0..ccf266db 100644 --- a/libi3/get_visualtype.c +++ b/libi3/get_visualtype.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include "libi3.h" diff --git a/libi3/ipc_connect.c b/libi3/ipc_connect.c index 69629daa..f493b4f1 100644 --- a/libi3/ipc_connect.c +++ b/libi3/ipc_connect.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/libi3/ipc_recv_message.c b/libi3/ipc_recv_message.c index cb4edd67..0ef4fced 100644 --- a/libi3/ipc_recv_message.c +++ b/libi3/ipc_recv_message.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/libi3/ipc_send_message.c b/libi3/ipc_send_message.c index 80709ed3..a9ba3165 100644 --- a/libi3/ipc_send_message.c +++ b/libi3/ipc_send_message.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/libi3/resolve_tilde.c b/libi3/resolve_tilde.c index a4e82873..3a56cbea 100644 --- a/libi3/resolve_tilde.c +++ b/libi3/resolve_tilde.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2015 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ diff --git a/libi3/root_atom_contents.c b/libi3/root_atom_contents.c index f70c31a7..df54ef09 100644 --- a/libi3/root_atom_contents.c +++ b/libi3/root_atom_contents.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/libi3/safewrappers.c b/libi3/safewrappers.c index db9b6b4a..74460f37 100644 --- a/libi3/safewrappers.c +++ b/libi3/safewrappers.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/libi3/string.c b/libi3/string.c index e6297f9e..28575e1f 100644 --- a/libi3/string.c +++ b/libi3/string.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * string.c: Define an i3String type to automagically handle UTF-8/UCS-2 * conversions. Some font backends need UCS-2 (X core fonts), diff --git a/libi3/strndup.c b/libi3/strndup.c index eec1a0ed..c4032dc5 100644 --- a/libi3/strndup.c +++ b/libi3/strndup.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/libi3/ucs2_conversion.c b/libi3/ucs2_conversion.c index 9a8c478f..3a7d0194 100644 --- a/libi3/ucs2_conversion.c +++ b/libi3/ucs2_conversion.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * */ #include diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec index 8fe1f569..297da145 100644 --- a/parser-specs/commands.spec +++ b/parser-specs/commands.spec @@ -1,7 +1,7 @@ # vim:ts=2:sw=2:expandtab # # i3 - an improved dynamic tiling window manager -# © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) +# © 2009 Michael Stapelberg and contributors (see also: LICENSE) # # parser-specs/commands.spec: Specification file for generate-command-parser.pl # which will generate the appropriate header files for our C parser. diff --git a/parser-specs/config.spec b/parser-specs/config.spec index da534a38..72bea3b8 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -1,7 +1,7 @@ # vim:ts=2:sw=2:expandtab # # i3 - an improved dynamic tiling window manager -# © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) +# © 2009 Michael Stapelberg and contributors (see also: LICENSE) # # parser-specs/config.spec: Specification file for generate-command-parser.pl # which will generate the appropriate header files for our C parser. diff --git a/src/assignments.c b/src/assignments.c index 96834f64..babe890e 100644 --- a/src/assignments.c +++ b/src/assignments.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * assignments.c: Assignments for specific windows (for_window). * diff --git a/src/bindings.c b/src/bindings.c index e83e0acc..a0ca0498 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2014 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * bindings.c: Functions for configuring, finding and, running bindings. */ diff --git a/src/click.c b/src/click.c index 40884c34..690bd1f8 100644 --- a/src/click.c +++ b/src/click.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * click.c: Button press (mouse click) events. * diff --git a/src/commands.c b/src/commands.c index adfffe5f..2a9e3765 100644 --- a/src/commands.c +++ b/src/commands.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * commands.c: all command functions (see commands_parser.c) * diff --git a/src/commands_parser.c b/src/commands_parser.c index fa4c2360..9ae75abe 100644 --- a/src/commands_parser.c +++ b/src/commands_parser.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * commands_parser.c: hand-written parser to parse commands (commands are what * you bind on keys and what you can send to i3 using the IPC interface, like diff --git a/src/con.c b/src/con.c index 622b7ad5..aefe756c 100644 --- a/src/con.c +++ b/src/con.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * con.c: Functions which deal with containers directly (creating containers, * searching containers, getting specific properties from containers, diff --git a/src/config.c b/src/config.c index 8a1cb99c..6eb67a12 100644 --- a/src/config.c +++ b/src/config.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * config.c: Configuration file (calling the parser (src/config_parser.c) with * the correct path, switching key bindings mode). diff --git a/src/config_directives.c b/src/config_directives.c index daf4339b..eea3dba8 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * config_directives.c: all config storing functions (see config_parser.c) * diff --git a/src/config_parser.c b/src/config_parser.c index f3254812..a9baef27 100644 --- a/src/config_parser.c +++ b/src/config_parser.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * config_parser.c: hand-written parser to parse configuration directives. * diff --git a/src/debug.c b/src/debug.c index f3bc106d..bb880b2f 100644 --- a/src/debug.c +++ b/src/debug.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * debug.c: Debugging functions, especially FormatEvent, which prints unhandled * events. This code is from xcb-util. diff --git a/src/display_version.c b/src/display_version.c index a539dad3..6ece3f74 100644 --- a/src/display_version.c +++ b/src/display_version.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * display_version.c: displays the running i3 version, runs as part of * i3 --moreversion. diff --git a/src/ewmh.c b/src/ewmh.c index 844a0db9..328bcab8 100644 --- a/src/ewmh.c +++ b/src/ewmh.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * ewmh.c: Get/set certain EWMH properties easily. * diff --git a/src/fake_outputs.c b/src/fake_outputs.c index 4f274099..b4f92cd4 100644 --- a/src/fake_outputs.c +++ b/src/fake_outputs.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * Faking outputs is useful in pathological situations (like network X servers * which don’t support multi-monitor in a useful way) and for our testsuite. diff --git a/src/floating.c b/src/floating.c index d01cb43d..f5641fff 100644 --- a/src/floating.c +++ b/src/floating.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * floating.c: Floating windows. * diff --git a/src/handlers.c b/src/handlers.c index c80c279e..56e29607 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * handlers.c: Small handlers for various events (keypresses, focus changes, * …). diff --git a/src/ipc.c b/src/ipc.c index f8138f0a..a60b1900 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * ipc.c: UNIX domain socket IPC (initialization, client handling, protocol). * diff --git a/src/key_press.c b/src/key_press.c index 95e5079e..88d09a0c 100644 --- a/src/key_press.c +++ b/src/key_press.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * key_press.c: key press handler * diff --git a/src/load_layout.c b/src/load_layout.c index c4d39fce..e4c4531d 100644 --- a/src/load_layout.c +++ b/src/load_layout.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * load_layout.c: Restore (parts of) the layout, for example after an inplace * restart. diff --git a/src/log.c b/src/log.c index 6f44fa96..7cf98843 100644 --- a/src/log.c +++ b/src/log.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * log.c: Logging functions. * diff --git a/src/main.c b/src/main.c index ac40e7a3..79273627 100644 --- a/src/main.c +++ b/src/main.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * main.c: Initialization, main loop * @@ -261,11 +261,11 @@ int main(int argc, char *argv[]) { only_check_config = true; break; case 'v': - printf("i3 version %s © 2009-2014 Michael Stapelberg and contributors\n", i3_version); + printf("i3 version %s © 2009 Michael Stapelberg and contributors\n", i3_version); exit(EXIT_SUCCESS); break; case 'm': - printf("Binary i3 version: %s © 2009-2014 Michael Stapelberg and contributors\n", i3_version); + printf("Binary i3 version: %s © 2009 Michael Stapelberg and contributors\n", i3_version); display_running_version(); exit(EXIT_SUCCESS); break; diff --git a/src/manage.c b/src/manage.c index 3499963b..ee56c0b3 100644 --- a/src/manage.c +++ b/src/manage.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * manage.c: Initially managing new windows (or existing ones on restart). * diff --git a/src/match.c b/src/match.c index dc4d422f..d16ff0a0 100644 --- a/src/match.c +++ b/src/match.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * A "match" is a data structure which acts like a mask or expression to match * certain windows or not. For example, when using commands, you can specify a diff --git a/src/move.c b/src/move.c index e4da191a..bd228a1c 100644 --- a/src/move.c +++ b/src/move.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * move.c: Moving containers into some direction. * diff --git a/src/output.c b/src/output.c index 822a0f88..ec5d5f47 100644 --- a/src/output.c +++ b/src/output.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * output.c: Output (monitor) related functions. * diff --git a/src/randr.c b/src/randr.c index a4a0f6fd..29183695 100644 --- a/src/randr.c +++ b/src/randr.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * For more information on RandR, please see the X.org RandR specification at * http://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt diff --git a/src/regex.c b/src/regex.c index 60dee5cc..9549a98b 100644 --- a/src/regex.c +++ b/src/regex.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * regex.c: Interface to libPCRE (perl compatible regular expressions). * diff --git a/src/render.c b/src/render.c index d7d57667..76dfa69c 100644 --- a/src/render.c +++ b/src/render.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * render.c: Renders (determines position/sizes) the layout tree, updating the * various rects. Needs to be pushed to X11 (see x.c) to be visible. diff --git a/src/resize.c b/src/resize.c index 4ed835d5..994fd692 100644 --- a/src/resize.c +++ b/src/resize.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * resize.c: Interactive resizing. * diff --git a/src/restore_layout.c b/src/restore_layout.c index 53a70d69..f56372a6 100644 --- a/src/restore_layout.c +++ b/src/restore_layout.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * restore_layout.c: Everything for restored containers that is not pure state * parsing (which can be found in load_layout.c). diff --git a/src/scratchpad.c b/src/scratchpad.c index 75b8e56c..06a7cc73 100644 --- a/src/scratchpad.c +++ b/src/scratchpad.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * scratchpad.c: Moving windows to the scratchpad and making them visible again. * diff --git a/src/sighandler.c b/src/sighandler.c index e971f6bd..4b1307c9 100644 --- a/src/sighandler.c +++ b/src/sighandler.c @@ -4,8 +4,8 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) - * © 2009-2010 Jan-Erik Rediger + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Jan-Erik Rediger * * sighandler.c: Interactive crash dialog upon SIGSEGV/SIGABRT/SIGFPE (offers * to restart inplace). diff --git a/src/startup.c b/src/startup.c index aa347bd7..41f18d00 100644 --- a/src/startup.c +++ b/src/startup.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * startup.c: Startup notification code. Ensures a startup notification context * is setup when launching applications. We store the current diff --git a/src/tree.c b/src/tree.c index 753b02fc..92b56e6c 100644 --- a/src/tree.c +++ b/src/tree.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * tree.c: Everything that primarily modifies the layout tree data structure. * diff --git a/src/util.c b/src/util.c index c891a6bc..0a8ba6e2 100644 --- a/src/util.c +++ b/src/util.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * util.c: Utility functions, which can be useful everywhere within i3 (see * also libi3). diff --git a/src/version.c b/src/version.c index d7d31b36..6e385ada 100644 --- a/src/version.c +++ b/src/version.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2015 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * Stores the latest Git commit identifier so that it can be linked into i3 * and used dynamically without recompiling every object file. diff --git a/src/window.c b/src/window.c index 5485bcc3..253f738d 100644 --- a/src/window.c +++ b/src/window.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * window.c: Updates window attributes (X11 hints/properties). * diff --git a/src/workspace.c b/src/workspace.c index 4a16f3d1..9034f6d5 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * workspace.c: Modifying workspaces, accessing them, moving containers to * workspaces. diff --git a/src/x.c b/src/x.c index d29d4bef..7fe70445 100644 --- a/src/x.c +++ b/src/x.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * x.c: Interface to X11, transfers our in-memory state to X11 (see also * render.c). Basically a big state machine. diff --git a/src/xcb.c b/src/xcb.c index 5dda5cce..d5684353 100644 --- a/src/xcb.c +++ b/src/xcb.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * xcb.c: Helper functions for easier usage of XCB * diff --git a/src/xcursor.c b/src/xcursor.c index 0a8da425..1e1e23b0 100644 --- a/src/xcursor.c +++ b/src/xcursor.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * xcursor.c: xcursor support for themed cursors. * diff --git a/src/xinerama.c b/src/xinerama.c index 9e412e03..ec030230 100644 --- a/src/xinerama.c +++ b/src/xinerama.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * This is LEGACY code (we support RandR, which can do much more than * Xinerama), but necessary for the poor users of the nVidia binary diff --git a/testcases/complete-run.pl b/testcases/complete-run.pl index 911558e5..c1244e08 100755 --- a/testcases/complete-run.pl +++ b/testcases/complete-run.pl @@ -1,6 +1,6 @@ #!/usr/bin/env perl # vim:ts=4:sw=4:expandtab -# © 2010-2012 Michael Stapelberg and contributors +# © 2010 Michael Stapelberg and contributors package complete_run; use strict; use warnings; From 30b6584de1ef77143a4d46dea3ecfcb3778763e3 Mon Sep 17 00:00:00 2001 From: "Kacper Kowalik (Xarthisius)" Date: Sun, 19 Apr 2015 10:26:10 -0500 Subject: [PATCH 091/243] =?UTF-8?q?Fix=20=E2=80=98FALSE=E2=80=99=20undecla?= =?UTF-8?q?red=20(first=20use=20in=20this=20function)=20when=20i3=20is=20b?= =?UTF-8?q?uilt=20without=20PANGO=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/handlers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handlers.c b/src/handlers.c index c80c279e..1c3d10f4 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -880,7 +880,7 @@ static void handle_client_message(xcb_client_message_event_t *event) { floating_drag_window(con->parent, &fake); break; case _NET_WM_MOVERESIZE_SIZE_TOPLEFT... _NET_WM_MOVERESIZE_SIZE_LEFT: - floating_resize_window(con->parent, FALSE, &fake); + floating_resize_window(con->parent, false, &fake); break; default: DLOG("_NET_WM_MOVERESIZE direction %d not implemented\n", direction); From de866c2fead530f11b4f659b5150eab89132aaea Mon Sep 17 00:00:00 2001 From: Georgiy Tugai Date: Tue, 21 Apr 2015 12:28:43 +0930 Subject: [PATCH 092/243] i3bar: fix flickering shortened status bar on other output(s) --- i3bar/src/xcb.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index ba57b9fa..45705c07 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -1792,6 +1792,8 @@ void reconfig_windows(bool redraw_bars) { void draw_bars(bool unhide) { DLOG("Drawing bars...\n"); int workspace_width = 0; + /* Is the currently-rendered statusline using short_text items? */ + bool rendered_statusline_is_short = false; refresh_statusline(false); @@ -1941,8 +1943,15 @@ void draw_bars(bool unhide) { uint32_t max_statusline_width = outputs_walk->rect.w - workspace_width - tray_width - 2 * logical_px(sb_hoff_px); /* If the statusline is too long, try to use short texts. */ - if (statusline_width > max_statusline_width) + if (statusline_width > max_statusline_width) { + /* If the currently rendered statusline is long, render a short status line */ refresh_statusline(true); + rendered_statusline_is_short = true; + } else if (rendered_statusline_is_short) { + /* If the currently rendered statusline is short, render a long status line */ + refresh_statusline(false); + rendered_statusline_is_short = false; + } /* Luckily we already prepared a seperate pixmap containing the rendered * statusline, we just have to copy the relevant parts to the relevant From d12482e5fd08403ce0954318e2993b2fb7214c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Thu, 16 Apr 2015 19:42:31 +0200 Subject: [PATCH 093/243] Added 'con_is_hidden' to check whether a given container is visible to the user assuming its workspace is visible. This is useful for determining whether we want to set the _NET_WM_STATE_HIDDEN atom on the window. --- include/con.h | 9 ++++++++- src/con.c | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/con.h b/include/con.h index 498fcbaa..4813b776 100644 --- a/include/con.h +++ b/include/con.h @@ -42,12 +42,19 @@ bool con_is_leaf(Con *con); */ bool con_has_managed_window(Con *con); -/* +/** * Returns true if a container should be considered split. * */ bool con_is_split(Con *con); +/** + * This will only return true for containers which have some parent with + * a tabbed / stacked parent of which they are not the currently focused child. + * + */ +bool con_is_hidden(Con *con); + /** * Returns true if this node has regular or floating children. * diff --git a/src/con.c b/src/con.c index aefe756c..05f608bd 100644 --- a/src/con.c +++ b/src/con.c @@ -260,6 +260,29 @@ bool con_is_split(Con *con) { } } +/* + * This will only return true for containers which have some parent with + * a tabbed / stacked parent of which they are not the currently focused child. + * + */ +bool con_is_hidden(Con *con) { + Con *current = con; + + /* ascend to the workspace level and memorize the highest-up container + * which is stacked or tabbed. */ + while (current != NULL && current->type != CT_WORKSPACE) { + Con *parent = current->parent; + if (parent != NULL && (parent->layout == L_TABBED || parent->layout == L_STACKED)) { + if (TAILQ_FIRST(&(parent->focus_head)) != current) + return true; + } + + current = parent; + } + + return false; +} + /* * Returns true if this node accepts a window (if the node swallows windows, * it might already have swallowed enough and cannot hold any more). From ffe25d9e4312f1c9b132bc650341a4fa95ec13ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Thu, 16 Apr 2015 19:43:23 +0200 Subject: [PATCH 094/243] Set the _NET_WM_STATE_HIDDEN atom on windows that are currently not visible due to being in the non-focused tab of a stacked or tabbed container. fixes #1648 --- include/atoms.xmacro | 1 + src/ewmh.c | 4 ++-- src/x.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/include/atoms.xmacro b/include/atoms.xmacro index b9ee4eb7..00a346db 100644 --- a/include/atoms.xmacro +++ b/include/atoms.xmacro @@ -5,6 +5,7 @@ xmacro(_NET_WM_MOVERESIZE) xmacro(_NET_WM_STATE_FULLSCREEN) xmacro(_NET_WM_STATE_DEMANDS_ATTENTION) xmacro(_NET_WM_STATE_MODAL) +xmacro(_NET_WM_STATE_HIDDEN) xmacro(_NET_WM_STATE) xmacro(_NET_WM_WINDOW_TYPE) xmacro(_NET_WM_WINDOW_TYPE_NORMAL) diff --git a/src/ewmh.c b/src/ewmh.c index 1a357f23..a1d2489e 100644 --- a/src/ewmh.c +++ b/src/ewmh.c @@ -234,6 +234,6 @@ 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"); - /* only send the first 29 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */ - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 29, supported_atoms); + /* only send the first 30 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */ + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 30, supported_atoms); } diff --git a/src/x.c b/src/x.c index 7fe70445..2dcffe6b 100644 --- a/src/x.c +++ b/src/x.c @@ -36,6 +36,7 @@ typedef struct con_state { bool mapped; bool unmap_now; bool child_mapped; + bool is_hidden; /** The con for which this state is. */ Con *con; @@ -611,6 +612,33 @@ void x_deco_recurse(Con *con) { x_draw_decoration(con); } +/* + * Sets or removes the _NET_WM_STATE_HIDDEN property on con if necessary. + * + */ +static void set_hidden_state(Con *con) { + if (con->window == NULL) { + return; + } + + con_state *state = state_for_frame(con->frame); + bool should_be_hidden = con_is_hidden(con); + if (should_be_hidden == state->is_hidden) + return; + + unsigned int num = 0; + uint32_t values[1]; + if (should_be_hidden) { + DLOG("setting _NET_WM_STATE_HIDDEN for con = %p\n", con); + values[num++] = A__NET_WM_STATE_HIDDEN; + } else { + DLOG("removing _NET_WM_STATE_HIDDEN for con = %p\n", con); + } + + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->window->id, A__NET_WM_STATE, XCB_ATOM_ATOM, 32, num, values); + state->is_hidden = should_be_hidden; +} + /* * This function pushes the properties of each node of the layout tree to * X11 if they have changed (like the map state, position of the window, …). @@ -814,6 +842,8 @@ void x_push_node(Con *con) { fake_absolute_configure_notify(con); } + set_hidden_state(con); + /* Handle all children and floating windows of this node. We recurse * in focus order to display the focused client in a stack first when * switching workspaces (reduces flickering). */ From cd0cf9d65137bb28974cdf06ac5ac7d2fd480a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 17 Apr 2015 20:09:53 +0200 Subject: [PATCH 095/243] Added testcases for setting _NET_WM_STATE_HIDDEN on unfocused containers in tabbed/stacked containers. --- testcases/t/243-net-wm-state-hidden.t | 201 ++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 testcases/t/243-net-wm-state-hidden.t diff --git a/testcases/t/243-net-wm-state-hidden.t b/testcases/t/243-net-wm-state-hidden.t new file mode 100644 index 00000000..3f2301c6 --- /dev/null +++ b/testcases/t/243-net-wm-state-hidden.t @@ -0,0 +1,201 @@ +#!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) +# +# Tests for setting and removing the _NET_WM_STATE_HIDDEN atom properly. +# Ticket: #1648 +use i3test; +use X11::XCB qw(:all); + +sub is_hidden { + sync_with_i3; + my $atom = $x->atom(name => '_NET_WM_STATE_HIDDEN'); + + my ($con) = @_; + my $cookie = $x->get_property( + 0, + $con->{id}, + $x->atom(name => '_NET_WM_STATE')->id, + GET_PROPERTY_TYPE_ANY, + 0, + 4096 + ); + + my $reply = $x->get_property_reply($cookie->{sequence}); + my $len = $reply->{length}; + return 0 if $len == 0; + + my @atoms = unpack("L$len", $reply->{value}); + for (my $i = 0; $i < $len; $i++) { + return 1 if $atoms[$i] == $atom->id; + } + + return 0; +} + +my ($tabA, $tabB, $tabC, $subtabA, $subtabB, $windowA, $windowB); + +############################################################################### +# Given two containers next to each other, when focusing one, then the other +# one does not have _NET_WM_STATE_HIDDEN set. +############################################################################### + +fresh_workspace; +$windowA = open_window; +$windowB = open_window; + +ok(!is_hidden($windowA), 'left window does not have _NET_WM_STATE_HIDDEN set'); +ok(!is_hidden($windowB), 'right window does not have _NET_WM_STATE_HIDDEN set'); + +############################################################################### +# Given two containers on different workspaces, when one is focused, then +# the other one does not have _NET_WM_STATE_HIDDEN set. +############################################################################### + +fresh_workspace; +$windowA = open_window; +fresh_workspace; +$windowB = open_window; + +ok(!is_hidden($windowA), 'left window does not have _NET_WM_STATE_HIDDEN set'); +ok(!is_hidden($windowB), 'right window does not have _NET_WM_STATE_HIDDEN set'); + +############################################################################### +# Given two containers in the same tabbed container, when one is focused, then +# (only) the other one has _NET_WM_STATE_HIDDEN set. +# Given the other tab is focused, then the atom is transferred. +############################################################################### + +fresh_workspace; +$tabA = open_window; +cmd 'layout tabbed'; +$tabB = open_window; + +ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set'); +ok(!is_hidden($tabB), 'focused tab does not have _NET_WM_STATE_HIDDEN set'); + +cmd 'focus left'; + +ok(!is_hidden($tabA), 'focused tab does not have _NET_WM_STATE_HIDDEN set'); +ok(is_hidden($tabB), 'unfocused tab has _NET_WM_STATE_HIDDEN set'); + +############################################################################### +# Given three containers in the same stacked container, when the focused tab +# is moved to another workspace, then the now focused tab does not have +# _NET_WM_STATE_HIDDEN set anymore. +############################################################################### + +fresh_workspace; +$tabA = open_window; +cmd 'layout stacked'; +$tabB = open_window; +$tabC = open_window; +cmd 'move window to workspace unused'; + +ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set'); +ok(!is_hidden($tabB), 'focused tab does not have _NET_WM_STATE_HIDDEN set'); +ok(!is_hidden($tabC), 'moved window does not have _NET_WM_STATE_HIDDEN set'); + +############################################################################### +# Given three containers in the same stacked container, when a not focused +# tab is moved to another workspace, then it does not have _NET_WM_STATE_HIDDEN +# set anymore. +############################################################################### + +fresh_workspace; +$tabA = open_window; +cmd 'layout stacked'; +$tabB = open_window; +cmd 'mark moveme'; +$tabC = open_window; +cmd '[con_mark="moveme"] move window to workspace unused'; + +ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set'); +ok(!is_hidden($tabB), 'moved window does not have _NET_WM_STATE_HIDDEN set'); +ok(!is_hidden($tabC), 'focused tab does not have _NET_WM_STATE_HIDDEN set'); + +############################################################################### +# Given a tabbed container and some other container, when the latter is moved +# into the tabbed container, then all other tabs have _NET_WM_STATE_HIDDEN +# set. +############################################################################### + +fresh_workspace; +$tabA = open_window; +cmd 'layout tabbed'; +$tabB = open_window; +cmd 'focus parent'; +cmd 'split h'; +$tabC = open_window; +cmd 'move left'; + +ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set'); +ok(is_hidden($tabB), 'unfocused tab has _NET_WM_STATE_HIDDEN set'); +ok(!is_hidden($tabC), 'focused tab does not have _NET_WM_STATE_HIDDEN set'); + +############################################################################### +# Given a stacked container nested inside another tabbed container with the +# inner one being in the currently focused tab, then the focused tab of the +# inner container does not have _NET_WM_STATE_HIDDEN set. +############################################################################### + +fresh_workspace; +$tabA = open_window; +cmd 'layout tabbed'; +$tabB = open_window; +cmd 'split h'; +open_window; +cmd 'split v'; +cmd 'layout stacked'; +$subtabA = open_window; +$subtabB = open_window; + +ok(is_hidden($tabA), 'unfocused outer tab has _NET_WM_STATE_HIDDEN set'); +ok(!is_hidden($tabB), 'focused outer tab does not have _NET_WM_STATE_HIDDEN set'); +ok(is_hidden($subtabA), 'unfocused inner tab has _NET_WM_STATE_HIDDEN set'); +ok(!is_hidden($subtabB), 'focused inner tab does not have _NET_WM_STATE_HIDDEN set'); + +cmd 'focus left'; + +ok(!is_hidden($subtabB), 'focused inner tab does not have _NET_WM_STATE_HIDDEN set'); + +############################################################################### +# Given a stacked container nested inside another tabbed container with the +# inner one being in a currently not focused tab, then all tabs of the inner +# container have _NET_WM_STATE_HIDDEN set. +############################################################################### + +fresh_workspace; +$tabA = open_window; +cmd 'layout tabbed'; +$tabB = open_window; +cmd 'split h'; +open_window; +cmd 'split v'; +cmd 'layout stacked'; +$subtabA = open_window; +$subtabB = open_window; +cmd 'focus parent'; +cmd 'focus parent'; +cmd 'focus left'; + +ok(!is_hidden($tabA), 'focused outer tab does not have _NET_WM_STATE_HIDDEN set'); +ok(is_hidden($tabB), 'unfocused outer tab has _NET_WM_STATE_HIDDEN set'); +ok(is_hidden($subtabA), 'unfocused inner tab has _NET_WM_STATE_HIDDEN set'); +ok(is_hidden($subtabB), 'unfocused inner tab has _NET_WM_STATE_HIDDEN set'); + +############################################################################### + +done_testing; From 14e95e765eeb1fd103ee8821656b43bf69c5519d Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 23 Apr 2015 18:21:15 -0400 Subject: [PATCH 096/243] Check if output is disabled in handle_output() Check if the `connection` of the randr output is XCB_RANDR_CONNECTION_DISONNECTED and disable the output if it is. This fixes an issue where the output would not be disabled if the output was physically unplugged from the machine. --- src/randr.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/randr.c b/src/randr.c index 29183695..9e236dcb 100644 --- a/src/randr.c +++ b/src/randr.c @@ -555,6 +555,12 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, return; } + if (output->connection == XCB_RANDR_CONNECTION_DISCONNECTED) { + DLOG("Disabling output %s: it is disconnected\n", new->name); + new->to_be_disabled = true; + return; + } + bool updated = update_if_necessary(&(new->rect.x), crtc->x) | update_if_necessary(&(new->rect.y), crtc->y) | update_if_necessary(&(new->rect.width), crtc->width) | From 57ddd00814706320bf9f0851a1b4fe2c918bc60b Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 24 Apr 2015 18:46:42 +0200 Subject: [PATCH 097/243] =?UTF-8?q?userguide:=20add=20a=20note=20to=20both?= =?UTF-8?q?=20=E2=80=9Cexec=E2=80=9Ds=20about=20semicolon=20and=20comma?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes #1678 --- docs/userguide | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/userguide b/docs/userguide index ad89fae8..301d8c81 100644 --- a/docs/userguide +++ b/docs/userguide @@ -724,6 +724,10 @@ commands will not run when restarting i3, if you need a command to run also when restarting i3 you should use the +exec_always+ keyword. These commands will be run in order. +See <> for details on the special meaning of +;+ (semicolon) +and +,+ (comma): they chain commands together in i3 and need to be escaped if +you want to use them in your command. + *Syntax*: ------------------- exec [--no-startup-id] command @@ -1467,6 +1471,8 @@ do this is to use the +i3-msg+ utility: i3-msg border none -------------------------- +[[command_chaining]] + Commands can be chained by using +;+ (a semicolon). So, to move a window to a specific workspace and immediately switch to that workspace, you can configure the following keybinding: @@ -1540,7 +1546,11 @@ information on how to use them. What good is a window manager if you can’t actually start any applications? The exec command starts an application by passing the command you specify to a shell. This implies that you can use globbing (wildcards) and programs will be -searched in your $PATH. +searched in your +$PATH+. + +See <> for details on the special meaning of +;+ (semicolon) +and +,+ (comma): they chain commands together in i3 and need to be escaped if +you want to use them in your command. *Syntax*: ------------------------------ From bbc66e45f7145fe00a4c76f413f46a645e688d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sat, 25 Apr 2015 23:31:56 +0200 Subject: [PATCH 098/243] Only detect clicks within the statusline width. If the user clicks on the very top of i3bar above a tray icon, i3bar might mistakenly trigger the click event for the last status block. This is due to the fact that the click detection considers the separator width of the block even though on the last block this is ignored, incorrectly spanning the block's width partially (or entirely) across the tray area. --- i3bar/src/xcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index fd268e91..a2f1be9a 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -420,7 +420,7 @@ void handle_button(xcb_button_press_event_t *event) { int offset = walk->rect.w - statusline_width - tray_width - logical_px(sb_hoff_px); x = original_x - offset; - if (x >= 0) { + if (x >= 0 && (size_t)x < statusline_width) { struct status_block *block; int sep_offset_remainder = 0; From 5c32de43c08c0b35ead53fe7d677ad51b5a5ce95 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 25 Apr 2015 20:05:55 -0400 Subject: [PATCH 099/243] Bugfix: serialize con_id with %p in run_binding() %p is equivalent to either %x or %lx, depending on the pointer size of the platform. Before this commit, we always used %d, which has the same behavior on Linux, but is not automatically expanded to %ld on e.g. FreeBSD. fixes #1661 --- src/bindings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings.c b/src/bindings.c index a0ca0498..5815908c 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -431,7 +431,7 @@ CommandResult *run_binding(Binding *bind, Con *con) { if (con == NULL) command = sstrdup(bind->command); else - sasprintf(&command, "[con_id=\"%d\"] %s", con, bind->command); + sasprintf(&command, "[con_id=\"%p\"] %s", con, bind->command); Binding *bind_cp = binding_copy(bind); CommandResult *result = parse_command(command, NULL); From 6cbe349774d16b4acb0f34e9614002e4f4639b57 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 25 Apr 2015 22:43:46 -0400 Subject: [PATCH 100/243] Ignore InputHint when not in WM_HINTS When InputHint is not in WM_HINTS (i.e., the flag is not set), treat the window as if the InputHint was set (the default behavior). This means that i3 will focus the window when it becomes managed. fixes #1676 --- src/window.c | 6 ++++-- testcases/t/158-wm_take_focus.t | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/window.c b/src/window.c index 3ffffa3b..29cd11eb 100644 --- a/src/window.c +++ b/src/window.c @@ -271,8 +271,10 @@ void window_update_hints(i3Window *win, xcb_get_property_reply_t *prop, bool *ur return; } - win->doesnt_accept_focus = !hints.input; - LOG("WM_HINTS.input changed to \"%d\"\n", hints.input); + if (hints.flags & XCB_ICCCM_WM_HINT_INPUT) { + win->doesnt_accept_focus = !hints.input; + LOG("WM_HINTS.input changed to \"%d\"\n", hints.input); + } if (urgency_hint != NULL) *urgency_hint = (xcb_icccm_wm_hints_get_urgency(&hints) != 0); diff --git a/testcases/t/158-wm_take_focus.t b/testcases/t/158-wm_take_focus.t index 050e1162..b8dae3b1 100644 --- a/testcases/t/158-wm_take_focus.t +++ b/testcases/t/158-wm_take_focus.t @@ -50,12 +50,15 @@ sub recv_take_focus { } subtest 'Window without WM_TAKE_FOCUS', sub { - fresh_workspace; + my $ws = fresh_workspace; my $window = open_window; ok(!recv_take_focus($window), 'did not receive ClientMessage'); + my $con = shift get_ws_content($ws); + ok($con->{focused}, 'con is focused'); + done_testing; }; @@ -72,7 +75,7 @@ subtest 'Window without WM_TAKE_FOCUS', sub { # list), the window cannot accept input focus, so we should not try to focus # the window at all. subtest 'Window with WM_TAKE_FOCUS and without InputHint', sub { - fresh_workspace; + my $ws = fresh_workspace; my $take_focus = $x->atom(name => 'WM_TAKE_FOCUS'); @@ -88,6 +91,9 @@ subtest 'Window with WM_TAKE_FOCUS and without InputHint', sub { ok(!recv_take_focus($window), 'did not receive ClientMessage'); + my $con = shift get_ws_content($ws); + ok($con->{focused}, 'con is focused'); + done_testing; }; @@ -97,7 +103,7 @@ subtest 'Window with WM_TAKE_FOCUS and without InputHint', sub { # nearly identical presently, so this is currently used also as a proxy test # for the latter case. subtest 'Window with WM_TAKE_FOCUS and unspecified InputHint', sub { - fresh_workspace; + my $ws = fresh_workspace; my $take_focus = $x->atom(name => 'WM_TAKE_FOCUS'); @@ -105,6 +111,9 @@ subtest 'Window with WM_TAKE_FOCUS and unspecified InputHint', sub { ok(!recv_take_focus($window), 'did not receive ClientMessage'); + my $con = shift get_ws_content($ws); + ok($con->{focused}, 'con is focused'); + done_testing; }; From 19b2f8f0d5cd1a9ec44ef19b12e4f15fd63d236e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 26 Apr 2015 22:51:16 +0200 Subject: [PATCH 101/243] Added a note to the debugging docs about sensitive data. resolves #1687 --- docs/debugging | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/debugging b/docs/debugging index 894a873b..639dbdfe 100644 --- a/docs/debugging +++ b/docs/debugging @@ -69,6 +69,11 @@ i3-msg 'debuglog on; shmlog on; reload' == Obtaining the debug logfile +Please note that log files may contain sensitive data such as window titles. +The best way to avoid submitting such information is to only run the necessary +applications to reproduce the behavior when saving the log file. This will also +make analyzing the log file easier. + No matter whether i3 misbehaved in some way without crashing or whether it just crashed, the logfile provides all information necessary to debug the problem. From f0f906a52ef776067a425b5d55f11eb33496a633 Mon Sep 17 00:00:00 2001 From: Deiz Date: Sun, 26 Apr 2015 14:23:08 -0400 Subject: [PATCH 102/243] Initialize workspace rect to the output's upon creation The comment immediately following implied that this was the intended behaviour. Not doing so means that compound commands that both move a window to a new workspace as well as do something that depends on the workspace's geometry (e.g. 'move position center' or 'floating enable' on a tiled window) would use the workspace's calloc'd 0x0+0x0 geometry. --- src/workspace.c | 1 + ...244-new-workspace-floating-enable-center.t | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 testcases/t/244-new-workspace-floating-enable-center.t diff --git a/src/workspace.c b/src/workspace.c index 9034f6d5..c7f1a1bb 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -29,6 +29,7 @@ static void _workspace_apply_default_orientation(Con *ws) { if (config.default_orientation == NO_ORIENTATION) { Con *output = con_get_output(ws); ws->layout = (output->rect.height > output->rect.width) ? L_SPLITV : L_SPLITH; + ws->rect = output->rect; DLOG("Auto orientation. Workspace size set to (%d,%d), setting layout to %d.\n", output->rect.width, output->rect.height, ws->layout); } else { diff --git a/testcases/t/244-new-workspace-floating-enable-center.t b/testcases/t/244-new-workspace-floating-enable-center.t new file mode 100644 index 00000000..dbc9a80a --- /dev/null +++ b/testcases/t/244-new-workspace-floating-enable-center.t @@ -0,0 +1,53 @@ +#!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) +# +# Ensures that 'move workspace $new, floating enable' on a marked window +# leaves the window centered on the new workspace. +# Bug still in: 4.10.2-137-ga4f0ed6 +use i3test i3_autostart => 0; + +my $config = <rect; + +is(int($pos->{x} + $pos->{width} / 2), int($x->root->rect->width / 2), + 'x coordinates match'); +is(int($pos->{y} + $pos->{height} / 2), int($x->root->rect->height / 2), + 'y coordinates match'); + +exit_gracefully($pid); + +done_testing; From 27c060b2790edcaa0a0e680cf3c6a69bf30e1751 Mon Sep 17 00:00:00 2001 From: Michael Hofmann Date: Tue, 31 Mar 2015 00:07:50 +0200 Subject: [PATCH 103/243] Tray icon size cleanup. - icon_size instead of font.height - consistent spacing with tray_spacing_px --- i3bar/src/xcb.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 11a017cf..b9e5659f 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -60,6 +60,9 @@ xcb_connection_t *conn; /* The font we'll use */ static i3Font font; +/* Icon size (based on font size) */ +int icon_size; + /* Overall height of the bar (based on font size) */ int bar_height; @@ -122,6 +125,9 @@ static const int sb_hoff_px = 4; /* Additional offset between the tray and the statusline, if the tray is not empty */ static const int tray_loff_px = 2; +/* Padding around the tray icons */ +static const int tray_spacing_px = 2; + /* Vertical offset between the bar and a separator */ static const int sep_voff_px = 4; @@ -148,7 +154,7 @@ int get_tray_width(struct tc_head *trayclients) { TAILQ_FOREACH_REVERSE(trayclient, trayclients, tc_head, tailq) { if (!trayclient->mapped) continue; - tray_width += font.height + logical_px(2); + tray_width += icon_size + logical_px(tray_spacing_px); } if (tray_width > 0) tray_width += logical_px(tray_loff_px); @@ -591,8 +597,8 @@ static void configure_trayclients(void) { clients++; DLOG("Configuring tray window %08x to x=%d\n", - trayclient->win, output->rect.w - (clients * (font.height + logical_px(2)))); - uint32_t x = output->rect.w - (clients * (font.height + logical_px(2))); + trayclient->win, output->rect.w - (clients * (icon_size + logical_px(tray_spacing_px)))); + uint32_t x = output->rect.w - (clients * (icon_size + logical_px(tray_spacing_px))); xcb_configure_window(xcb_connection, trayclient->win, XCB_CONFIG_WINDOW_X, @@ -702,16 +708,16 @@ static void handle_client_message(xcb_client_message_event_t *event) { xcb_reparent_window(xcb_connection, client, output->bar, - output->rect.w - font.height - 2, - 2); + output->rect.w - icon_size - logical_px(tray_spacing_px), + logical_px(tray_spacing_px)); /* We reconfigure the window to use a reasonable size. The systray * specification explicitly says: * Tray icons may be assigned any size by the system tray, and * should do their best to cope with any size effectively */ mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; - values[0] = font.height; - values[1] = font.height; + values[0] = icon_size; + values[1] = icon_size; xcb_configure_window(xcb_connection, client, mask, @@ -941,10 +947,10 @@ static void handle_configure_request(xcb_configure_request_event_t *event) { continue; xcb_rectangle_t rect; - rect.x = output->rect.w - (clients * (font.height + 2)); - rect.y = 2; - rect.width = font.height; - rect.height = font.height; + rect.x = output->rect.w - (clients * (icon_size + logical_px(tray_spacing_px))); + rect.y = logical_px(tray_spacing_px); + rect.width = icon_size; + rect.height = icon_size; DLOG("This is a tray window. x = %d\n", rect.x); fake_configure_notify(xcb_connection, rect, event->window, 0); @@ -1215,6 +1221,7 @@ void init_xcb_late(char *fontname) { set_font(&font); DLOG("Calculated font height: %d\n", font.height); bar_height = font.height + 2 * logical_px(ws_voff_px); + icon_size = bar_height - 2 * logical_px(tray_spacing_px); if (config.separator_symbol) separator_symbol_width = predict_text_width(config.separator_symbol); From 99e22cdf197bd08860464af1954dc4a378621ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 26 Apr 2015 23:07:41 +0200 Subject: [PATCH 104/243] Added a section to the debugging docs: * Motivate users to come up with clear and minimal instructions on how to reproduce a problem before submitting an issue. * Encourage users to restart i3 before reproducing the problem so that the log file can stay small and noise-free. * Mention the non-support of closed source software. --- docs/debugging | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/debugging b/docs/debugging index 894a873b..5187c529 100644 --- a/docs/debugging +++ b/docs/debugging @@ -67,6 +67,30 @@ fly: i3-msg 'debuglog on; shmlog on; reload' --------------------------------------- +== Reproducing the problem + +Before submitting an issue, please make sure to close down on the problem as +much as you can yourself. Here are some steps you should consider: + +* Find a deterministic, reliable way to reproduce the problem and provide it + with your bug report. +* Try using the default i3 config to reproduce the problem. If the issue does + not appear with the default config, gradually adapt it to track down what + change(s) to the config introduce the problem. +* Reproduce the problem with a minimal setup, i.e., only use as few applications, + windows and steps as necessary. +* In addition, try to stick to applications that are common and, even more + importantly, free / open source. +* Before obtaining the log file, restart i3 in-place, execute the steps to + reproduce the problem and then save the logs. This keeps the log file as + small as possible and necessary. + +Please be aware that we cannot support compatibility issues with closed-source +software, as digging into compatibility problems without having access to the +source code is too time-consuming. Additionally, experience has shown that +often, the software in question is responsible for the issue. Please raise an +issue with the software in question, not i3. + == Obtaining the debug logfile No matter whether i3 misbehaved in some way without crashing or whether it just From 95f3f7f8c97b057c26ae77505ccc4d55002841ef Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 3 May 2015 18:57:05 +0200 Subject: [PATCH 105/243] =?UTF-8?q?userguide:=20quoted=20strings=20need=20?= =?UTF-8?q?to=20be=20used,=20escaping=20isn=E2=80=99t=20possible?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes #1678 --- docs/userguide | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/userguide b/docs/userguide index 301d8c81..3a3cf002 100644 --- a/docs/userguide +++ b/docs/userguide @@ -725,8 +725,8 @@ also when restarting i3 you should use the +exec_always+ keyword. These commands will be run in order. See <> for details on the special meaning of +;+ (semicolon) -and +,+ (comma): they chain commands together in i3 and need to be escaped if -you want to use them in your command. +and +,+ (comma): they chain commands together in i3, so you need to use quoted +strings if they appear in your command. *Syntax*: ------------------- @@ -1549,8 +1549,8 @@ shell. This implies that you can use globbing (wildcards) and programs will be searched in your +$PATH+. See <> for details on the special meaning of +;+ (semicolon) -and +,+ (comma): they chain commands together in i3 and need to be escaped if -you want to use them in your command. +and +,+ (comma): they chain commands together in i3, so you need to use quoted +strings if they appear in your command. *Syntax*: ------------------------------ From 0319bda1d4aa0f9339d37a3866d606b3ef188d5c Mon Sep 17 00:00:00 2001 From: Michael Hofmann Date: Wed, 6 May 2015 16:28:29 +0200 Subject: [PATCH 106/243] Introduce sstrndup wrapper. --- i3bar/src/workspaces.c | 2 +- include/libi3.h | 7 +++++++ libi3/resolve_tilde.c | 2 +- libi3/safewrappers.c | 7 +++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 773f8f54..961a41f5 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -106,7 +106,7 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, size_t if (!strcmp(params->cur_key, "name")) { const char *ws_name = (const char *)val; - params->workspaces_walk->canonical_name = strndup(ws_name, len); + params->workspaces_walk->canonical_name = sstrndup(ws_name, len); if (config.strip_ws_numbers && params->workspaces_walk->num >= 0) { /* Special case: strip off the workspace number */ diff --git a/include/libi3.h b/include/libi3.h index a64b3981..3e6f8427 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -127,6 +127,13 @@ void *srealloc(void *ptr, size_t size); */ char *sstrdup(const char *str); +/** + * Safe-wrapper around strndup which exits if strndup returns NULL (meaning that + * there is no more memory available) + * + */ +char *sstrndup(const char *str, size_t size); + /** * Safe-wrapper around asprintf which exits if it returns -1 (meaning that * there is no more memory available) diff --git a/libi3/resolve_tilde.c b/libi3/resolve_tilde.c index 3a56cbea..26cbabe5 100644 --- a/libi3/resolve_tilde.c +++ b/libi3/resolve_tilde.c @@ -23,7 +23,7 @@ char *resolve_tilde(const char *path) { char *head, *tail, *result; tail = strchr(path, '/'); - head = strndup(path, tail ? (size_t)(tail - path) : strlen(path)); + head = sstrndup(path, tail ? (size_t)(tail - path) : strlen(path)); int res = glob(head, GLOB_TILDE, NULL, &globbuf); free(head); diff --git a/libi3/safewrappers.c b/libi3/safewrappers.c index 74460f37..f5973cab 100644 --- a/libi3/safewrappers.c +++ b/libi3/safewrappers.c @@ -48,6 +48,13 @@ char *sstrdup(const char *str) { return result; } +char *sstrndup(const char *str, size_t size) { + char *result = strndup(str, size); + if (result == NULL) + err(EXIT_FAILURE, "strndup()"); + return result; +} + int sasprintf(char **strp, const char *fmt, ...) { va_list args; int result; From f2542fc41396df009860123e9de53ad929f92a03 Mon Sep 17 00:00:00 2001 From: Michael Hofmann Date: Mon, 30 Mar 2015 12:02:39 +0200 Subject: [PATCH 107/243] No memcpy on class change. --- src/window.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/window.c b/src/window.c index 29cd11eb..7b0f397d 100644 --- a/src/window.c +++ b/src/window.c @@ -27,30 +27,27 @@ void window_update_class(i3Window *win, xcb_get_property_reply_t *prop, bool bef * null-terminated strings (for compatibility reasons). Instead, we * use strdup() on both strings */ const size_t prop_length = xcb_get_property_value_length(prop); - char *new_class = smalloc(prop_length + 1); - memcpy(new_class, xcb_get_property_value(prop), prop_length); - new_class[prop_length] = '\0'; + char *new_class = xcb_get_property_value(prop); + const size_t class_class_index = strnlen(new_class, prop_length) + 1; FREE(win->class_instance); FREE(win->class_class); - win->class_instance = sstrdup(new_class); - if ((strlen(new_class) + 1) < prop_length) - win->class_class = sstrdup(new_class + strlen(new_class) + 1); + win->class_instance = sstrndup(new_class, prop_length); + if (class_class_index < prop_length) + win->class_class = sstrndup(new_class + class_class_index, prop_length - class_class_index); else win->class_class = NULL; LOG("WM_CLASS changed to %s (instance), %s (class)\n", win->class_instance, win->class_class); if (before_mgmt) { - free(new_class); free(prop); return; } run_assignments(win); - free(new_class); free(prop); } From a74662052a354690c646b7ced5730396aad5ebba Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 12 May 2015 17:04:01 -0400 Subject: [PATCH 108/243] Detect base 16 in cmd criteria Try to detect base 16 numbers given to `con_id` and `id` for command criteria by setting the base of strtol to 0. This should also detect octal. This is necessary because mouse bindings now may be serialized as hex as of 5c32de4. --- src/commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands.c b/src/commands.c index 3263dd03..506ebfb8 100644 --- a/src/commands.c +++ b/src/commands.c @@ -335,7 +335,7 @@ void cmd_criteria_add(I3_CMD, char *ctype, char *cvalue) { if (strcmp(ctype, "con_id") == 0) { char *end; - long parsed = strtol(cvalue, &end, 10); + long parsed = strtol(cvalue, &end, 0); if (parsed == LONG_MIN || parsed == LONG_MAX || parsed < 0 || @@ -350,7 +350,7 @@ void cmd_criteria_add(I3_CMD, char *ctype, char *cvalue) { if (strcmp(ctype, "id") == 0) { char *end; - long parsed = strtol(cvalue, &end, 10); + long parsed = strtol(cvalue, &end, 0); if (parsed == LONG_MIN || parsed == LONG_MAX || parsed < 0 || From 4a585748a475b23f55aa6b62cd1029453f15fb86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 3 May 2015 00:19:26 +0200 Subject: [PATCH 109/243] Implemented new command 'move [window|container] [to] position mouse|cursor|pointer fixes #1696 --- include/commands.h | 6 ++++++ include/floating.h | 6 ++++++ parser-specs/commands.spec | 3 +++ src/commands.c | 24 ++++++++++++++++++++++++ src/floating.c | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 71 insertions(+) diff --git a/include/commands.h b/include/commands.h index bbcd7f6f..afb3c32a 100644 --- a/include/commands.h +++ b/include/commands.h @@ -258,6 +258,12 @@ void cmd_move_window_to_position(I3_CMD, char *method, char *x, char *y); */ void cmd_move_window_to_center(I3_CMD, char *method); +/** + * Implementation of 'move [window|container] [to] position mouse' + * + */ +void cmd_move_window_to_mouse(I3_CMD); + /** * Implementation of 'move scratchpad'. * diff --git a/include/floating.h b/include/floating.h index 5e7b8e31..78e75be8 100644 --- a/include/floating.h +++ b/include/floating.h @@ -70,6 +70,12 @@ bool floating_maybe_reassign_ws(Con *con); */ void floating_center(Con *con, Rect rect); +/** + * Moves the given floating con to the current pointer position. + * + */ +void floating_move_to_pointer(Con *con); + #if 0 /** * Removes the floating client from its workspace and attaches it to the new diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec index 1cd8d2f6..8d497cd1 100644 --- a/parser-specs/commands.spec +++ b/parser-specs/commands.spec @@ -271,6 +271,7 @@ state RENAME_WORKSPACE_NEW_NAME: # move workspace to [output] # move scratchpad # move [window|container] [to] [absolute] position [ [ [px] [px]] | center ] +# move [window|container] [to] position mouse|cursor|pointer state MOVE: 'window' -> @@ -342,6 +343,8 @@ state MOVE_TO_ABSOLUTE_POSITION: state MOVE_TO_POSITION: 'center' -> call cmd_move_window_to_center($method) + 'mouse', 'cursor', 'pointer' + -> call cmd_move_window_to_mouse() coord_x = word -> MOVE_TO_POSITION_X diff --git a/src/commands.c b/src/commands.c index 3263dd03..1f5c8f44 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1833,6 +1833,30 @@ void cmd_move_window_to_center(I3_CMD, char *method) { ysuccess(true); } +/* + * Implementation of 'move [window|container] [to] position mouse' + * + */ +void cmd_move_window_to_mouse(I3_CMD) { + HANDLE_EMPTY_MATCH; + + owindow *current; + TAILQ_FOREACH(current, &owindows, owindows) { + Con *floating_con = con_inside_floating(current->con); + if (floating_con == NULL) { + DLOG("con %p / %s is not floating, cannot move it to the mouse position.\n", + current->con, current->con->name); + continue; + } + + DLOG("moving floating container %p / %s to cursor position\n", floating_con, floating_con->name); + floating_move_to_pointer(floating_con); + } + + cmd_output->needs_tree_render = true; + ysuccess(true); +} + /* * Implementation of 'move scratchpad'. * diff --git a/src/floating.c b/src/floating.c index f5641fff..d44334fe 100644 --- a/src/floating.c +++ b/src/floating.c @@ -426,6 +426,38 @@ void floating_center(Con *con, Rect rect) { con->rect.y = rect.y + (rect.height / 2) - (con->rect.height / 2); } +/* + * Moves the given floating con to the current pointer position. + * + */ +void floating_move_to_pointer(Con *con) { + assert(con->type == CT_FLOATING_CON); + + xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, root), NULL); + if (reply == NULL) { + ELOG("could not query pointer position, not moving this container\n"); + return; + } + + Output *output = get_output_containing(reply->root_x, reply->root_y); + + /* Determine where to put the window. */ + int32_t x = reply->root_x - con->rect.width / 2; + int32_t y = reply->root_y - con->rect.height / 2; + FREE(reply); + + /* Correct target coordinates to be in-bounds. */ + x = MAX(x, (int32_t)output->rect.x); + y = MAX(y, (int32_t)output->rect.y); + if (x + con->rect.width > output->rect.x + output->rect.width) + x = output->rect.x + output->rect.width - con->rect.width; + if (y + con->rect.height > output->rect.y + output->rect.height) + y = output->rect.y + output->rect.height - con->rect.height; + + /* Update container's coordinates to position it correctly. */ + floating_reposition(con, (Rect){x, y, con->rect.width, con->rect.height}); +} + DRAGGING_CB(drag_window_callback) { const struct xcb_button_press_event_t *event = extra; From d2cfe38c048302db7c7d5b306d11ed5c8845ff49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 3 May 2015 14:59:30 +0200 Subject: [PATCH 110/243] Added 'move position mouse' command to the userguide. --- docs/userguide | 68 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/docs/userguide b/docs/userguide index 301d8c81..d52e8045 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1637,15 +1637,17 @@ bindsym $mod+f fullscreen toggle bindsym $mod+t floating toggle -------------- -=== Focusing/Moving containers +[[_focusing_moving_containers]] -To change the focus, use the focus command: +focus left+, +focus right+, +focus -down+ and +focus up+. +=== Focusing containers -There are a few special parameters you can use for the focus command: +To change focus, you can use the +focus+ command. The following options are +available: +left|right|up|down:: + Sets focus to the nearest container in the given direction. parent:: - Sets focus to the +Parent Container+ of the current +Container+. + Sets focus to the parent container of the current container. child:: The opposite of +focus parent+, sets the focus to the last focused child container. @@ -1659,23 +1661,16 @@ output:: Followed by a direction or an output name, this will focus the corresponding output. -For moving, use +move left+, +move right+, +move down+ and +move up+. - *Syntax*: ------------------------------------ -focus -focus -focus output <|output> -move [ px] -move [absolute] position [[ px] [ px]|center] ------------------------------------ - -Note that the amount of pixels you can specify for the +move+ command is only -relevant for floating containers. The default amount is 10 pixels. +---------------------------------------------- +focus left|right|down|up +focus parent|child|floating|tiling|mode_toggle +focus output left|right|up|down| +---------------------------------------------- *Examples*: ----------------------- -# Focus container on the left, bottom, top, right: +------------------------------------------------- +# Focus container on the left, bottom, top, right bindsym $mod+j focus left bindsym $mod+k focus down bindsym $mod+l focus up @@ -1692,8 +1687,33 @@ bindsym $mod+x focus output right # Focus the big output bindsym $mod+x focus output HDMI-2 +------------------------------------------------- -# Move container to the left, bottom, top, right: +=== Moving containers + +Use the +move+ command to move a container. + +*Syntax*: +----------------------------------------------------- +# Moves the container into the given direction. +# The optional pixel argument specifies how far the +# container should be moved if it is floating and +# defaults to 10 pixels. +move [ px] + +# Moves the container either to a specific location +# or to the center of the screen. If 'absolute' is +# used, it is moved to the center of all outputs. +move [absolute] position [[ px] [ px]|center] + +# Moves the container to the current position of the +# mouse cursor. Only affects floating containers. +move position mouse +----------------------------------------------------- + +*Examples*: +------------------------------------------------------- +# Move container to the left, bottom, top, right bindsym $mod+j move left bindsym $mod+k move down bindsym $mod+l move up @@ -1703,10 +1723,12 @@ bindsym $mod+semicolon move right # move more than the default bindsym $mod+j move left 20 px -# Move floating container to the center -# of all outputs +# Move floating container to the center of all outputs bindsym $mod+c move absolute position center ----------------------- + +# Move container to the current position of the cursor +bindsym $mod+m move position mouse +------------------------------------------------------- === Changing (named) workspaces/moving to workspaces From fbbe9cf2e8648fe05b682d4004e6a63750b54a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 3 May 2015 16:19:23 +0200 Subject: [PATCH 111/243] Added testcases for 'move position mouse' --- testcases/t/245-move-position-mouse.t | 142 ++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 testcases/t/245-move-position-mouse.t diff --git a/testcases/t/245-move-position-mouse.t b/testcases/t/245-move-position-mouse.t new file mode 100644 index 00000000..ae049271 --- /dev/null +++ b/testcases/t/245-move-position-mouse.t @@ -0,0 +1,142 @@ +#!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) +# +# Tests the 'move [window|container] [to] position mouse|cursor|pointer command. +# Ticket: #1696 +use i3test i3_autostart => 0; +use POSIX qw(floor); + +sub warp_pointer { + my ($pos_x, $pos_y) = @_; + $x->root->warp_pointer($pos_x, $pos_y); + sync_with_i3; +} + +my ($pid, $config, $ws, $rect, @cons); +my $root_rect = $x->root->rect; + +########################################################################## + +########################################################################## +# Given a floating container and the cursor far from any edges, when +# moving the container to the mouse, then the container is moved such +# that the cursor is centered inside it. +########################################################################## + +$config = <{floating_nodes}}; +$rect = $cons[0]->{rect}; + +is(floor($rect->{x} + $rect->{width} / 2), 100, "con is centered around cursor horizontally"); +is(floor($rect->{y} + $rect->{height} / 2), 100, "con is centered around cursor vertically"); + +exit_gracefully($pid); + +########################################################################## +# Given a floating container and the cursor is in the left upper edge +# of the output, when moving the container to the mouse, then the +# container is moved but adjusted to stay in-bounds. +########################################################################## + +$config = <{floating_nodes}}; +$rect = $cons[0]->{rect}; + +is($rect->{x}, 0, "con is on the left edge"); +is($rect->{y}, 0, "con is on the upper edge"); + +exit_gracefully($pid); + +########################################################################## +# Given a floating container and the cursor is in the left right lower +# edge of the output, when moving the container to the mouse, then the +# container is moved but adjusted to stay in-bounds. +########################################################################## + +$config = <width - 5, $root_rect->height - 5); + +cmd 'move position mouse'; + +@cons = @{get_ws($ws)->{floating_nodes}}; +$rect = $cons[0]->{rect}; + +is($rect->{x} + $rect->{width}, $root_rect->width, "con is on the right edge"); +is($rect->{y} + $rect->{height}, $root_rect->height, "con is on the lower edge"); + +exit_gracefully($pid); + +########################################################################## +# Given a floating container and the cursor being close to the corner of +# an output, when the container is moved to the mouse, then the container +# is moved but adjusted to the output boundaries. +# This test verifies that boundaries of individual outputs are respected +# and not just boundaries of the entire X root screen. +########################################################################## + +$config = <{floating_nodes}}; +$rect = $cons[0]->{rect}; + +is($rect->{x} + $rect->{width}, 500, "con is on the right edge"); +is($rect->{y} + $rect->{height}, 500, "con is on the lower edge"); + +exit_gracefully($pid); + +########################################################################## + +done_testing; From 8801de2399e0c28f3c9acbc717d79fa374f1979f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Thu, 14 May 2015 13:07:56 -0400 Subject: [PATCH 112/243] Protect "move position mouse" against a NULL access. This could happen if two outputs are set up to have a gap in between them and the mouse cursor being in said gap when the command is triggered. --- src/floating.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/floating.c b/src/floating.c index d44334fe..a2843535 100644 --- a/src/floating.c +++ b/src/floating.c @@ -440,6 +440,10 @@ void floating_move_to_pointer(Con *con) { } Output *output = get_output_containing(reply->root_x, reply->root_y); + if (output == NULL) { + ELOG("The pointer is not on any output, cannot move the container here."); + return; + } /* Determine where to put the window. */ int32_t x = reply->root_x - con->rect.width / 2; From 94a46a1e35a9cb4e1618feedf669b61a6c193c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 12 May 2015 18:07:01 -0400 Subject: [PATCH 113/243] Made syntax of syntax descriptions consistent: * denotes that some string must be used which is not a fixed value (e.g., a command), but a variable string (text, a number, ...) * [xyz] denotes that the parameter is optional * abc|xyz denotes that either abc or xyz must be given --- docs/userguide | 226 ++++++++++++++++++++------------------- parser-specs/config.spec | 2 - 2 files changed, 114 insertions(+), 114 deletions(-) diff --git a/docs/userguide b/docs/userguide index 301d8c81..7eea8542 100644 --- a/docs/userguide +++ b/docs/userguide @@ -320,7 +320,7 @@ and fall back to a working font. *Syntax*: ------------------------------ font -font pango:[family list] [style options] [size] +font pango: [