From: Ingo Bürk Date: Tue, 23 Oct 2018 14:41:54 +0000 (+0200) Subject: Merge pull request #3452 from orestisf1993/title_align X-Git-Tag: 4.16~8 X-Git-Url: https://git.sur5r.net/?p=i3%2Fi3;a=commitdiff_plain;h=64e7646c7ee3cec9803597c5fde5d5a907881249;hp=6d82753d53f680432f8167bc0b514fb1aa044fbb Merge pull request #3452 from orestisf1993/title_align Add title_align config directive --- diff --git a/.travis.yml b/.travis.yml index 87c996fb..8098035c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ install: script: - docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-safe-wrappers.sh - docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-formatting.sh - - docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 -e CC ${BASENAME} /bin/sh -c 'autoreconf -fi && mkdir -p build && cd build && (../configure || (cat config.log; false)) && make -j CFLAGS="-Wformat -Wformat-security -Wextra -Wno-unused-parameter -Werror"' + - docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 -e CC ${BASENAME} /bin/sh -c 'autoreconf -fi && mkdir -p build && cd build && (../configure || (cat config.log; false)) && make -j CFLAGS="-Wformat -Wformat-security -Wextra -Wno-unused-parameter -Wstrict-prototypes -Wmissing-prototypes -Werror"' - docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-spelling.pl - docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 -e CC ${BASENAME} ./travis/run-tests.sh - ./travis/skip-pkg.sh || docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/debian-build.sh deb/debian-amd64/DIST diff --git a/debian/control b/debian/control index 46e35dfe..71a2599c 100644 --- a/debian/control +++ b/debian/control @@ -40,7 +40,7 @@ Description: metapackage (i3 window manager, screen locker, menu, statusbar) Package: i3-wm Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, x11-utils +Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} Provides: x-window-manager Recommends: xfonts-base, fonts-dejavu-core, libanyevent-i3-perl (>= 0.12), libjson-xs-perl, rxvt-unicode | x-terminal-emulator Description: improved dynamic tiling window manager diff --git a/docs/userguide b/docs/userguide index 401d5ff2..91060ab2 100644 --- a/docs/userguide +++ b/docs/userguide @@ -245,9 +245,11 @@ you open a new terminal, it will open below the current one. So, how can you open a new terminal window to the *right* of the current one? The solution is to use +focus parent+, which will focus the +Parent Container+ of -the current +Container+. In this case, you would focus the +Vertical Split -Container+ which is *inside* the horizontally oriented workspace. Thus, now new -windows will be opened to the right of the +Vertical Split Container+: +the current +Container+. In default configuration, use +$mod+a+ to navigate one ++Container+ up the tree (you can repeat this multiple times until you get to the ++Workspace Container+). In this case, you would focus the +Vertical Split Container+ +which is *inside* the horizontally oriented workspace. Thus, now new windows will be +opened to the right of the +Vertical Split Container+: image::tree-shot3.png["shot3",title="Focus parent, then open new terminal"] @@ -1014,7 +1016,7 @@ ipc-socket ~/.i3/i3-ipc.sock ---------------------------- You can then use the +i3-msg+ application to perform any command listed in -the next section. +<>. === Focus follows mouse @@ -1735,6 +1737,7 @@ bar { } -------------------------------------- +[[list_of_commands]] == List of commands Commands are what you bind to specific keypresses. You can also issue commands diff --git a/i3-config-wizard/main.c b/i3-config-wizard/main.c index 0c8c705a..4b556657 100644 --- a/i3-config-wizard/main.c +++ b/i3-config-wizard/main.c @@ -104,7 +104,7 @@ static struct xkb_keymap *xkb_keymap; static uint8_t xkb_base_event; static uint8_t xkb_base_error; -static void finish(); +static void finish(void); #include "GENERATED_config_enums.h" @@ -216,7 +216,7 @@ static const char *get_string(const char *identifier) { static void clear_stack(void) { for (int c = 0; c < 10; c++) { - if (stack[c].type == STACK_STR && stack[c].val.str != NULL) + if (stack[c].type == STACK_STR) free(stack[c].val.str); stack[c].identifier = NULL; stack[c].val.str = NULL; @@ -482,7 +482,7 @@ static void txt(int col, int row, char *text, color_t fg, color_t bg) { * Handles expose events, that is, draws the window contents. * */ -static int handle_expose() { +static int handle_expose(void) { const color_t black = draw_util_hex_to_color("#000000"); const color_t white = draw_util_hex_to_color("#FFFFFF"); const color_t green = draw_util_hex_to_color("#00FF00"); @@ -641,7 +641,7 @@ static void handle_button_press(xcb_button_press_event_t *event) { * Creates the config file and tells i3 to reload. * */ -static void finish() { +static void finish(void) { printf("creating \"%s\"...\n", config_path); struct xkb_context *xkb_context; diff --git a/i3-input/main.c b/i3-input/main.c index efb7b20c..d1a2efd7 100644 --- a/i3-input/main.c +++ b/i3-input/main.c @@ -156,7 +156,7 @@ static int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_rel return 1; } -static void finish_input() { +static void finish_input(void) { char *command = (char *)concat_strings(glyphs_utf8, input_position); /* count the occurrences of %s in the string */ diff --git a/i3-nagbar/main.c b/i3-nagbar/main.c index fd7acd6e..4ce74939 100644 --- a/i3-nagbar/main.c +++ b/i3-nagbar/main.c @@ -103,10 +103,10 @@ void debuglog(char *fmt, ...) { } /* - * Starts the given application by passing it through a shell. We use double fork - * to avoid zombie processes. As the started application’s parent exits (immediately), - * the application is reparented to init (process-id 1), which correctly handles - * childs, so we don’t have to do it :-). + * Starts the given application by passing it through a shell. We use double + * fork to avoid zombie processes. As the started application’s parent exits + * (immediately), the application is reparented to init (process-id 1), which + * correctly handles children, so we don’t have to do it :-). * * The shell is determined by looking for the SHELL environment variable. If it * does not exist, /bin/sh is used. diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 7783e877..760ebcdb 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -60,7 +60,7 @@ int separator_symbol_width; * depend on 'config'. * */ -char *init_xcb_early(); +char *init_xcb_early(void); /** * Initialization which depends on 'config' being usable. Called after the diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 1cd7d512..bb5ceaff 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -133,7 +133,7 @@ finish: * Stop and free() the stdin- and SIGCHLD-watchers * */ -void cleanup(void) { +static void cleanup(void) { if (stdin_io != NULL) { ev_io_stop(main_loop, stdin_io); FREE(stdin_io); @@ -400,7 +400,7 @@ static bool read_json_input(unsigned char *input, int length) { * in statusline * */ -void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { +static void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { int rec; unsigned char *buffer = get_buffer(watcher, &rec); if (buffer == NULL) @@ -420,7 +420,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { * whether this is JSON or plain text * */ -void stdin_io_first_line_cb(struct ev_loop *loop, ev_io *watcher, int revents) { +static void stdin_io_first_line_cb(struct ev_loop *loop, ev_io *watcher, int revents) { int rec; unsigned char *buffer = get_buffer(watcher, &rec); if (buffer == NULL) @@ -457,7 +457,7 @@ void stdin_io_first_line_cb(struct ev_loop *loop, ev_io *watcher, int revents) { * anymore * */ -void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { +static void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { int exit_status = WEXITSTATUS(watcher->rstatus); ELOG("Child (pid: %d) unexpectedly exited with status %d\n", @@ -477,7 +477,7 @@ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { draw_bars(false); } -void child_write_output(void) { +static void child_write_output(void) { if (child.click_events) { const unsigned char *output; size_t size; @@ -580,7 +580,7 @@ void start_child(char *command) { atexit(kill_child_at_exit); } -void child_click_events_initialize(void) { +static void child_click_events_initialize(void) { if (!child.click_events_init) { yajl_gen_array_open(gen); child_write_output(); @@ -588,7 +588,7 @@ void child_click_events_initialize(void) { } } -void child_click_events_key(const char *key) { +static void child_click_events_key(const char *key) { yajl_gen_string(gen, (const unsigned char *)key, strlen(key)); } diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 56fe2798..df5a12cf 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -34,7 +34,7 @@ typedef void (*handler_t)(char *); * Since i3 does not give us much feedback on commands, we do not much * */ -void got_command_reply(char *reply) { +static void got_command_reply(char *reply) { /* TODO: Error handling for command replies */ } @@ -42,7 +42,7 @@ void got_command_reply(char *reply) { * Called, when we get a reply with workspaces data * */ -void got_workspace_reply(char *reply) { +static void got_workspace_reply(char *reply) { DLOG("Got workspace data!\n"); parse_workspaces_json(reply); draw_bars(false); @@ -53,7 +53,7 @@ void got_workspace_reply(char *reply) { * Since i3 does not give us much feedback on commands, we do not much * */ -void got_subscribe_reply(char *reply) { +static void got_subscribe_reply(char *reply) { DLOG("Got subscribe reply: %s\n", reply); /* TODO: Error handling for subscribe commands */ } @@ -62,7 +62,7 @@ void got_subscribe_reply(char *reply) { * Called, when we get a reply with outputs data * */ -void got_output_reply(char *reply) { +static void got_output_reply(char *reply) { DLOG("Clearing old output configuration...\n"); free_outputs(); @@ -87,7 +87,7 @@ void got_output_reply(char *reply) { * Called when we get the configuration for our bar instance * */ -void got_bar_config(char *reply) { +static void got_bar_config(char *reply) { DLOG("Received bar config \"%s\"\n", reply); /* We initiate the main function by requesting infos about the outputs and * workspaces. Everything else (creating the bars, showing the right workspace- @@ -132,7 +132,7 @@ handler_t reply_handlers[] = { * Called, when a workspace event arrives (i.e. the user changed the workspace) * */ -void got_workspace_event(char *event) { +static void got_workspace_event(char *event) { DLOG("Got workspace event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } @@ -141,7 +141,7 @@ void got_workspace_event(char *event) { * Called, when an output event arrives (i.e. the screen configuration changed) * */ -void got_output_event(char *event) { +static void got_output_event(char *event) { DLOG("Got output event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); if (!config.disable_ws) { @@ -153,7 +153,7 @@ void got_output_event(char *event) { * Called, when a mode event arrives (i3 changed binding mode). * */ -void got_mode_event(char *event) { +static void got_mode_event(char *event) { DLOG("Got mode event!\n"); parse_mode_json(event); draw_bars(false); @@ -163,7 +163,7 @@ void got_mode_event(char *event) { * Called, when a barconfig_update event arrives (i.e. i3 changed the bar hidden_state or mode) * */ -void got_bar_config_update(char *event) { +static void got_bar_config_update(char *event) { /* check whether this affect this bar instance by checking the bar_id */ char *expected_id; sasprintf(&expected_id, "\"id\":\"%s\"", config.bar_id); @@ -213,7 +213,7 @@ handler_t event_handlers[] = { * Called, when we get a message from i3 * */ -void got_data(struct ev_loop *loop, ev_io *watcher, int events) { +static void got_data(struct ev_loop *loop, ev_io *watcher, int events) { DLOG("Got data!\n"); int fd = watcher->fd; @@ -278,8 +278,8 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { buffer[size] = '\0'; /* And call the callback (indexed by the type) */ - if (type & (1 << 31)) { - type ^= 1 << 31; + if (type & (1UL << 31)) { + type ^= 1UL << 31; event_handlers[type](buffer); } else { if (reply_handlers[type]) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index f90bb312..a818dd97 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -44,7 +44,7 @@ void debuglog(char *fmt, ...) { * Glob path, i.e. expand ~ * */ -char *expand_path(char *path) { +static char *expand_path(char *path) { static glob_t globbuf; if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) { ELOG("glob() failed\n"); @@ -55,7 +55,7 @@ char *expand_path(char *path) { return result; } -void print_usage(char *elf_name) { +static void print_usage(char *elf_name) { printf("Usage: %s -b bar_id [-s sock_path] [-h] [-v]\n", elf_name); printf("\n"); printf("-b, --bar_id \tBar ID for which to get the configuration\n"); @@ -76,7 +76,7 @@ void print_usage(char *elf_name) { * in main() with that * */ -void sig_cb(struct ev_loop *loop, ev_signal *watcher, int revents) { +static void sig_cb(struct ev_loop *loop, ev_signal *watcher, int revents) { switch (watcher->signum) { case SIGTERM: DLOG("Got a SIGTERM, stopping\n"); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index f4509c26..d43a4bdd 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -92,6 +92,9 @@ static mode binding; /* Indicates whether a new binding mode was recently activated */ bool activated_mode = false; +/* The output in which the tray should be displayed. */ +static i3_output *output_for_tray; + /* The parsed colors */ struct xcb_colors_t { color_t bar_fg; @@ -146,13 +149,13 @@ int _xcb_request_failed(xcb_void_cookie_t cookie, char *err_msg, int line) { return 0; } -uint32_t get_sep_offset(struct status_block *block) { +static uint32_t get_sep_offset(struct status_block *block) { if (!block->no_separator && block->sep_block_width > 0) return block->sep_block_width / 2 + block->sep_block_width % 2; return 0; } -int get_tray_width(struct tc_head *trayclients) { +static int get_tray_width(struct tc_head *trayclients) { trayclient *trayclient; int tray_width = 0; TAILQ_FOREACH_REVERSE(trayclient, trayclients, tc_head, tailq) { @@ -193,7 +196,7 @@ static void draw_separator(i3_output *output, uint32_t x, struct status_block *b } } -uint32_t predict_statusline_length(bool use_short_text) { +static uint32_t predict_statusline_length(bool use_short_text) { uint32_t width = 0; struct status_block *block; @@ -245,7 +248,7 @@ uint32_t predict_statusline_length(bool use_short_text) { /* * Redraws the statusline to the output's statusline_buffer */ -void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_colors, bool use_short_text) { +static void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_colors, bool use_short_text) { struct status_block *block; color_t bar_color = (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg); @@ -330,7 +333,7 @@ void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_color * Hides all bars (unmaps them) * */ -void hide_bars(void) { +static void hide_bars(void) { if ((config.hide_on_modifier == M_DOCK) || (config.hidden_state == S_SHOW && config.hide_on_modifier == M_HIDE)) { return; } @@ -349,7 +352,7 @@ void hide_bars(void) { * Unhides all bars (maps them) * */ -void unhide_bars(void) { +static void unhide_bars(void) { if (config.hide_on_modifier != M_HIDE) { return; } @@ -457,7 +460,7 @@ static bool execute_custom_command(xcb_keycode_t input_code, bool event_is_relea * wheel was used and change the workspace appropriately * */ -void handle_button(xcb_button_press_event_t *event) { +static void handle_button(xcb_button_press_event_t *event) { /* Determine, which bar was clicked */ i3_output *walk; xcb_window_t bar = event->event; @@ -758,58 +761,16 @@ static void handle_client_message(xcb_client_message_event_t *event) { } DLOG("X window %08x requested docking\n", client); - i3_output *output = NULL; - i3_output *walk = NULL; - tray_output_t *tray_output = NULL; - /* We need to iterate through the tray_output assignments first in - * order to prioritize them. Otherwise, if this bar manages two - * outputs and both are assigned as tray_output as well, the first - * output in our list would receive the tray rather than the first - * one defined via tray_output. */ - TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) { - SLIST_FOREACH(walk, outputs, slist) { - if (!walk->active) - continue; - - if (strcasecmp(walk->name, tray_output->output) == 0) { - DLOG("Found tray_output assignment for output %s.\n", walk->name); - output = walk; - break; - } - if (walk->primary && strcasecmp("primary", tray_output->output) == 0) { - DLOG("Found tray_output assignment on primary output %s.\n", walk->name); - output = walk; - break; - } - } - - /* If we found an output, we're done. */ - if (output != NULL) - break; - } - - /* If no tray_output has been specified, we fall back to the first - * available output. */ - if (output == NULL && TAILQ_EMPTY(&(config.tray_outputs))) { - SLIST_FOREACH(walk, outputs, slist) { - if (!walk->active) - continue; - DLOG("Falling back to output %s because no primary output is configured\n", walk->name); - output = walk; - break; - } - } - - if (output == NULL) { - ELOG("No output found\n"); + if (output_for_tray == NULL) { + ELOG("No output found for tray\n"); return; } xcb_void_cookie_t rcookie = xcb_reparent_window(xcb_connection, client, - output->bar.id, - output->rect.w - icon_size - logical_px(config.tray_padding), + output_for_tray->bar.id, + output_for_tray->rect.w - icon_size - logical_px(config.tray_padding), logical_px(config.tray_padding)); if (xcb_request_failed(rcookie, "Could not reparent window. Maybe it is using an incorrect depth/visual?")) return; @@ -836,7 +797,7 @@ static void handle_client_message(xcb_client_message_event_t *event) { ev->format = 32; ev->data.data32[0] = XCB_CURRENT_TIME; ev->data.data32[1] = XEMBED_EMBEDDED_NOTIFY; - ev->data.data32[2] = output->bar.id; + ev->data.data32[2] = output_for_tray->bar.id; ev->data.data32[3] = xe_version; xcb_send_event(xcb_connection, 0, @@ -856,7 +817,7 @@ static void handle_client_message(xcb_client_message_event_t *event) { tc->win = client; tc->xe_version = xe_version; tc->mapped = false; - TAILQ_INSERT_TAIL(output->trayclients, tc, tailq); + TAILQ_INSERT_TAIL(output_for_tray->trayclients, tc, tailq); if (map_it) { DLOG("Mapping dock client\n"); @@ -1080,7 +1041,7 @@ static void handle_resize_request(xcb_resize_request_event_t *event) { * events from X11, handle them, then flush our outgoing queue. * */ -void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revents) { +static void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revents) { xcb_generic_event_t *event; if (xcb_connection_has_error(xcb_connection)) { @@ -1177,7 +1138,7 @@ void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revents) { * are triggered * */ -void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { +static void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } /* @@ -1185,7 +1146,7 @@ void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { * depend on 'config'. * */ -char *init_xcb_early() { +char *init_xcb_early(void) { /* FIXME: xcb_connect leaks memory */ xcb_connection = xcb_connect(NULL, &screen); if (xcb_connection_has_error(xcb_connection)) { @@ -1248,7 +1209,7 @@ char *init_xcb_early() { * in xcb. * */ -void register_xkb_keyevents() { +static void register_xkb_keyevents(void) { const xcb_query_extension_reply_t *extreply; extreply = xcb_get_extension_data(conn, &xcb_xkb_id); if (!extreply->present) { @@ -1272,7 +1233,7 @@ void register_xkb_keyevents() { * Deregister from xkb keyevents. * */ -void deregister_xkb_keyevents() { +static void deregister_xkb_keyevents(void) { xcb_xkb_select_events(conn, XCB_XKB_ID_USE_CORE_KBD, 0, @@ -1338,7 +1299,7 @@ static void send_tray_clientmessage(void) { * atom. Afterwards, tray clients will send ClientMessages to our window. * */ -void init_tray(void) { +static void init_tray(void) { DLOG("Initializing system tray functionality\n"); /* request the tray manager atom for the X11 display we are running on */ char atomname[strlen("_NET_SYSTEM_TRAY_S") + 11]; @@ -1567,7 +1528,7 @@ void destroy_window(i3_output *output) { /* Strut partial tells i3 where to reserve space for i3bar. This is determined * by the `position` bar config directive. */ -xcb_void_cookie_t config_strut_partial(i3_output *output) { +static xcb_void_cookie_t config_strut_partial(i3_output *output) { /* A local struct to save the strut_partial property */ struct { uint32_t left; @@ -1609,6 +1570,56 @@ xcb_void_cookie_t config_strut_partial(i3_output *output) { &strut_partial); } +/* + * Returns the output which should hold the tray, if one exists. + * + * An output is returned in these scenarios: + * 1. A specific output was listed in tray_outputs which is also in the list + * of outputs managed by this bar. + * 2. No tray_output directive was specified. In this case, we use the first + * available output. + * 3. 'tray_output primary' was specified. In this case we use the primary + * output. + * + * Three scenarios in which we specifically don't want to use a tray: + * 1. 'tray_output none' was specified. + * 2. A specific output was listed as a tray_output, but is not one of the + * outputs managed by this bar. For example, consider tray_outputs == [VGA-1], + * but outputs == [HDMI-1]. + * 3. 'tray_output primary' was specified and no output in the list is + * primary. + */ +static i3_output *get_tray_output(void) { + i3_output *output = NULL; + if (TAILQ_EMPTY(&(config.tray_outputs))) { + /* No tray_output specified, use first active output. */ + SLIST_FOREACH(output, outputs, slist) { + if (output->active) { + return output; + } + } + return NULL; + } else if (strcasecmp(TAILQ_FIRST(&(config.tray_outputs))->output, "none") == 0) { + /* Check for "tray_output none" */ + return NULL; + } + + /* If one or more tray_output assignments were specified, we ensure that at + * least one of them is actually an output managed by this instance. */ + tray_output_t *tray_output; + TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) { + SLIST_FOREACH(output, outputs, slist) { + if (output->active && + (strcasecmp(output->name, tray_output->output) == 0 || + (strcasecmp(tray_output->output, "primary") == 0 && output->primary))) { + return output; + } + } + } + + return NULL; +} + /* * Reconfigure all bars and create new bars for recently activated outputs * @@ -1616,7 +1627,6 @@ xcb_void_cookie_t config_strut_partial(i3_output *output) { void reconfig_windows(bool redraw_bars) { uint32_t mask; uint32_t values[6]; - static bool tray_configured = false; i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { @@ -1744,58 +1754,6 @@ void reconfig_windows(bool redraw_bars) { exit(EXIT_FAILURE); } - /* Unless "tray_output none" was specified, we need to initialize the tray. */ - bool no_tray = false; - if (!(TAILQ_EMPTY(&(config.tray_outputs)))) { - no_tray = strcasecmp(TAILQ_FIRST(&(config.tray_outputs))->output, "none") == 0; - } - - /* - * There are three scenarios in which we need to initialize the tray: - * 1. A specific output was listed in tray_outputs which is also - * in the list of outputs managed by this bar. - * 2. No tray_output directive was specified. In this case, we - * use the first available output. - * 3. 'tray_output primary' was specified. In this case we use the - * primary output. - * - * Three scenarios in which we specifically don't want to - * initialize the tray are: - * 1. 'tray_output none' was specified. - * 2. A specific output was listed as a tray_output, but is not - * one of the outputs managed by this bar. For example, consider - * tray_outputs == [VGA-1], but outputs == [HDMI-1]. - * 3. 'tray_output primary' was specified and no output in the list - * is primary. - */ - if (!tray_configured && !no_tray) { - /* If no tray_output was specified, we go ahead and initialize the tray as - * we will be using the first available output. */ - if (TAILQ_EMPTY(&(config.tray_outputs))) { - init_tray(); - } - - /* If one or more tray_output assignments were specified, we ensure that at least one of - * them is actually an output managed by this instance. */ - tray_output_t *tray_output; - TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) { - i3_output *output; - bool found = false; - SLIST_FOREACH(output, outputs, slist) { - if (strcasecmp(output->name, tray_output->output) == 0 || - (strcasecmp(tray_output->output, "primary") == 0 && output->primary)) { - found = true; - init_tray(); - break; - } - } - - if (found) - break; - } - - tray_configured = true; - } } else { /* We already have a bar, so we just reconfigure it */ mask = XCB_CONFIG_WINDOW_X | @@ -1889,6 +1847,19 @@ void reconfig_windows(bool redraw_bars) { } } } + + /* Finally, check if we want to initialize the tray or destroy the selection + * window. The result of get_tray_output() is cached. */ + output_for_tray = get_tray_output(); + if (output_for_tray) { + if (selwin == XCB_NONE) { + init_tray(); + } + } else if (selwin != XCB_NONE) { + DLOG("Destroying tray selection window\n"); + xcb_destroy_window(xcb_connection, selwin); + selwin = XCB_NONE; + } } /* diff --git a/include/commands.h b/include/commands.h index b4b3da38..0137460f 100644 --- a/include/commands.h +++ b/include/commands.h @@ -314,13 +314,13 @@ void cmd_rename_workspace(I3_CMD, const char *old_name, const char *new_name); */ void cmd_bar(I3_CMD, const char *bar_type, const char *bar_value, const char *bar_id); -/* +/** * Implementation of 'shmlog |toggle|on|off' * */ void cmd_shmlog(I3_CMD, const char *argument); -/* +/** * Implementation of 'debuglog toggle|on|off' * */ diff --git a/include/commands_parser.h b/include/commands_parser.h index 88b3f6d0..b65ae93f 100644 --- a/include/commands_parser.h +++ b/include/commands_parser.h @@ -13,7 +13,7 @@ #include -/* +/** * Holds an intermediate represenation of the result of a call to any command. * When calling parse_command("floating enable, border none"), the parser will * internally use this struct when calling cmd_floating and cmd_border. diff --git a/include/con.h b/include/con.h index 672d80ac..2c991b0c 100644 --- a/include/con.h +++ b/include/con.h @@ -20,7 +20,8 @@ */ Con *con_new_skeleton(Con *parent, i3Window *window); -/* A wrapper for con_new_skeleton, to retain the old con_new behaviour +/** + * A wrapper for con_new_skeleton, to retain the old con_new behaviour * */ Con *con_new(Con *parent, i3Window *window); @@ -220,7 +221,7 @@ void con_mark_toggle(Con *con, const char *mark, mark_mode_t mode); */ void con_mark(Con *con, const char *mark, mark_mode_t mode); -/* +/** * Removes marks from containers. * If con is NULL, all containers are considered. * If name is NULL, this removes all existing marks. @@ -402,7 +403,7 @@ Con *con_descend_focused(Con *con); */ Con *con_descend_tiling_focused(Con *con); -/* +/** * Returns the leftmost, rightmost, etc. container in sub-tree. For example, if * direction is D_LEFT, then we return the rightmost container and if direction * is D_RIGHT, we return the leftmost container. This is because if we are diff --git a/include/config_parser.h b/include/config_parser.h index ace4041d..009538f2 100644 --- a/include/config_parser.h +++ b/include/config_parser.h @@ -16,7 +16,7 @@ SLIST_HEAD(variables_head, Variable); extern pid_t config_error_nagbar_pid; -/* +/** * An intermediate reprsentation of the result of a parse_config call. * Currently unused, but the JSON output will be useful in the future when we * implement a config parsing IPC command. diff --git a/include/configuration.h b/include/configuration.h index a1e9cc80..6f55ac2a 100644 --- a/include/configuration.h +++ b/include/configuration.h @@ -434,7 +434,7 @@ void ungrab_all_keys(xcb_connection_t *conn); * Sends the current bar configuration as an event to all barconfig_update listeners. * */ -void update_barconfig(); +void update_barconfig(void); /** * Kills the configerror i3-nagbar process, if any. diff --git a/include/i3/ipc.h b/include/i3/ipc.h index 0c57f7fd..884a0cf6 100644 --- a/include/i3/ipc.h +++ b/include/i3/ipc.h @@ -87,7 +87,7 @@ typedef struct i3_ipc_header { * Events from i3 to clients. Events have the first bit set high. * */ -#define I3_IPC_EVENT_MASK (1 << 31) +#define I3_IPC_EVENT_MASK (1UL << 31) /* The workspace event will be triggered upon changes in the workspace list */ #define I3_IPC_EVENT_WORKSPACE (I3_IPC_EVENT_MASK | 0) diff --git a/include/libi3.h b/include/libi3.h index d27437ba..790baba9 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -343,7 +343,7 @@ uint32_t get_colorpixel(const char *hex) __attribute__((const)); #if defined(__APPLE__) -/* +/** * Taken from FreeBSD * Returns a pointer to a new string which is a duplicate of the * string, but only copies at most n characters. @@ -472,7 +472,7 @@ xcb_visualtype_t *get_visualtype(xcb_screen_t *screen); * release version), based on the git version number. * */ -bool is_debug_build() __attribute__((const)); +bool is_debug_build(void) __attribute__((const)); /** * Returns the name of a temporary file with the specified prefix. diff --git a/include/match.h b/include/match.h index 4ff8c485..043c3a8f 100644 --- a/include/match.h +++ b/include/match.h @@ -15,7 +15,7 @@ #include -/* +/** * Initializes the Match data structure. This function is necessary because the * members representing boolean values (like dock) need to be initialized with * -1 instead of 0. diff --git a/include/output.h b/include/output.h index 31084da1..a2ad97b0 100644 --- a/include/output.h +++ b/include/output.h @@ -40,5 +40,12 @@ Output *get_output_for_con(Con *con); * Iterates over all outputs and pushes sticky windows to the currently visible * workspace on that output. * + * old_focus is used to determine if a sticky window is going to be focused. + * old_focus might be different than the currently focused container because the + * caller might need to temporarily change the focus and then call + * output_push_sticky_windows. For example, workspace_show needs to set focus to + * one of its descendants first, then call output_push_sticky_windows that + * should focus a sticky window if it was the focused in the previous workspace. + * */ -void output_push_sticky_windows(Con *to_focus); +void output_push_sticky_windows(Con *old_focus); diff --git a/include/randr.h b/include/randr.h index 39182c54..ec533a28 100644 --- a/include/randr.h +++ b/include/randr.h @@ -137,7 +137,7 @@ Output *get_output_next(direction_t direction, Output *current, output_close_far */ Output *get_output_next_wrap(direction_t direction, Output *current); -/* +/** * Creates an output covering the root window. * */ diff --git a/include/render.h b/include/render.h index 750b7d31..2b2c8dad 100644 --- a/include/render.h +++ b/include/render.h @@ -12,7 +12,10 @@ #include -/* This is used to keep a state to pass around when rendering a con in render_con(). */ +/** + * This is used to keep a state to pass around when rendering a con in render_con(). + * + */ typedef struct render_params { /* A copy of the coordinates of the container which is being rendered. */ int x; @@ -39,7 +42,8 @@ typedef struct render_params { */ void render_con(Con *con, bool render_fullscreen); -/* +/** * Returns the height for the decorations + * */ int render_deco_height(void); diff --git a/include/shmlog.h b/include/shmlog.h index b90211ef..dc8081f1 100644 --- a/include/shmlog.h +++ b/include/shmlog.h @@ -20,7 +20,7 @@ /* Default shmlog size if not set by user. */ extern const int default_shmlog_size; -/* +/** * Header of the shmlog file. Used by i3/src/log.c and i3/i3-dump-log/main.c. * */ diff --git a/include/startup.h b/include/startup.h index 5da221e1..feece575 100644 --- a/include/startup.h +++ b/include/startup.h @@ -21,7 +21,7 @@ * Starts the given application by passing it through a shell. We use double * fork to avoid zombie processes. As the started application’s parent exits * (immediately), the application is reparented to init (process-id 1), which - * correctly handles childs, so we don’t have to do it :-). + * correctly handles children, so we don’t have to do it :-). * * The shell used to start applications is the system's bourne shell (i.e., * /bin/sh). diff --git a/include/util.h b/include/util.h index 90ddc4a4..d08ac69d 100644 --- a/include/util.h +++ b/include/util.h @@ -125,7 +125,7 @@ void i3_restart(bool forget_layout); #if defined(__OpenBSD__) || defined(__APPLE__) -/* +/** * Taken from FreeBSD * Find the first occurrence of the byte string s in byte string l. * diff --git a/libi3/dpi.c b/libi3/dpi.c index a2c40319..d15e35be 100644 --- a/libi3/dpi.c +++ b/libi3/dpi.c @@ -49,14 +49,12 @@ void init_dpi(void) { dpi = 0; goto init_dpi_end; } - dpi = (long)round(in_dpi); + dpi = lround(in_dpi); DLOG("Found Xft.dpi = %ld.\n", dpi); init_dpi_end: - if (resource != NULL) { - free(resource); - } + free(resource); if (database != NULL) { xcb_xrm_database_free(database); diff --git a/libi3/draw_util.c b/libi3/draw_util.c index 6a2e93dc..f88360dc 100644 --- a/libi3/draw_util.c +++ b/libi3/draw_util.c @@ -121,7 +121,7 @@ static void draw_util_set_source_color(surface_t *surface, color_t color) { cairo_set_source_rgba(surface->cr, color.red, color.green, color.blue, color.alpha); } -/** +/* * Draw the given text using libi3. * This function also marks the surface dirty which is needed if other means of * drawing are used. This will be the case when using XCB to draw text. @@ -140,7 +140,7 @@ void draw_util_text(i3String *text, surface_t *surface, color_t fg_color, color_ cairo_surface_mark_dirty(surface->surface); } -/** +/* * Draws a filled rectangle. * This function is a convenience wrapper and takes care of flushing the * surface as well as restoring the cairo state. @@ -167,7 +167,7 @@ void draw_util_rectangle(surface_t *surface, color_t color, double x, double y, cairo_restore(surface->cr); } -/** +/* * Clears a surface with the given color. * */ @@ -191,7 +191,7 @@ void draw_util_clear_surface(surface_t *surface, color_t color) { cairo_restore(surface->cr); } -/** +/* * Copies a surface onto another surface. * */ diff --git a/libi3/font.c b/libi3/font.c index 3dca8124..7be84ee0 100644 --- a/libi3/font.c +++ b/libi3/font.c @@ -224,9 +224,7 @@ i3Font load_font(const char *pattern, const bool fallback) { error->error_code); } } - if (error != NULL) { - free(error); - } + free(error); font.pattern = sstrdup(pattern); LOG("Using X font %s\n", pattern); @@ -275,8 +273,7 @@ void free_font(void) { case FONT_TYPE_XCB: { /* Close the font and free the info */ xcb_close_font(conn, savedFont->specific.xcb.id); - if (savedFont->specific.xcb.info) - free(savedFont->specific.xcb.info); + free(savedFont->specific.xcb.info); break; } case FONT_TYPE_PANGO: diff --git a/libi3/get_colorpixel.c b/libi3/get_colorpixel.c index afba202b..49a9e3b4 100644 --- a/libi3/get_colorpixel.c +++ b/libi3/get_colorpixel.c @@ -43,7 +43,7 @@ uint32_t get_colorpixel(const char *hex) { /* Shortcut: if our screen is true color, no need to do a roundtrip to X11 */ if (root_screen == NULL || root_screen->root_depth == 24 || root_screen->root_depth == 32) { - return (0xFF << 24) | (r << 16 | g << 8 | b); + return (0xFFUL << 24) | (r << 16 | g << 8 | b); } /* Lookup this colorpixel in the cache */ diff --git a/libi3/is_debug_build.c b/libi3/is_debug_build.c index 4e583622..52187bda 100644 --- a/libi3/is_debug_build.c +++ b/libi3/is_debug_build.c @@ -15,7 +15,7 @@ * release version), based on the git version number. * */ -bool is_debug_build() { +bool is_debug_build(void) { /* i3_version contains either something like this: * "4.0.2 (2011-11-11, branch "release")". * or: "4.0.2-123-gCOFFEEBABE (2011-11-11, branch "next")". diff --git a/libi3/mkdirp.c b/libi3/mkdirp.c index 1fc8c346..f5281bd7 100644 --- a/libi3/mkdirp.c +++ b/libi3/mkdirp.c @@ -44,10 +44,7 @@ int mkdirp(const char *path, mode_t mode) { char *sep = strrchr(copy, '/'); if (sep == NULL) { - if (copy != NULL) { - free(copy); - copy = NULL; - } + free(copy); return -1; } *sep = '\0'; diff --git a/libi3/safewrappers.c b/libi3/safewrappers.c index 04bbda44..1802b327 100644 --- a/libi3/safewrappers.c +++ b/libi3/safewrappers.c @@ -70,7 +70,7 @@ ssize_t writeall(int fd, const void *buf, size_t count) { size_t written = 0; while (written < count) { - const ssize_t n = write(fd, buf + written, count - written); + const ssize_t n = write(fd, ((char *)buf) + written, count - written); if (n == -1) { if (errno == EINTR || errno == EAGAIN) continue; @@ -86,7 +86,7 @@ ssize_t writeall_nonblock(int fd, const void *buf, size_t count) { size_t written = 0; while (written < count) { - const ssize_t n = write(fd, buf + written, count - written); + const ssize_t n = write(fd, ((char *)buf) + written, count - written); if (n == -1) { if (errno == EAGAIN) { return written; diff --git a/libi3/string.c b/libi3/string.c index a078b33e..9efa3690 100644 --- a/libi3/string.c +++ b/libi3/string.c @@ -99,7 +99,7 @@ i3String *i3string_from_ucs2(const xcb_char2b_t *from_ucs2, size_t num_glyphs) { return str; } -/** +/* * Copies the given i3string. * Note that this will not free the source string. */ diff --git a/src/bindings.c b/src/bindings.c index ad5fe4f3..6704c816 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -859,8 +859,6 @@ static int fill_rmlvo_from_root(struct xkb_rule_names *xkb_names) { xcb_intern_atom_reply_t *atom_reply; size_t content_max_words = 256; - xcb_window_t root = root_screen->root; - atom_reply = xcb_intern_atom_reply( conn, xcb_intern_atom(conn, 0, strlen("_XKB_RULES_NAMES"), "_XKB_RULES_NAMES"), NULL); if (atom_reply == NULL) diff --git a/src/commands.c b/src/commands.c index 70f3bf18..eecd59fc 100644 --- a/src/commands.c +++ b/src/commands.c @@ -330,7 +330,7 @@ void cmd_move_con_to_workspace(I3_CMD, const char *which) { ysuccess(true); } -/** +/* * Implementation of 'move [window|container] [to] workspace back_and_forth'. * */ @@ -2034,7 +2034,7 @@ void cmd_rename_workspace(I3_CMD, const char *old_name, const char *new_name) { * Implementation of 'bar mode dock|hide|invisible|toggle []' * */ -bool cmd_bar_mode(const char *bar_mode, const char *bar_id) { +static bool cmd_bar_mode(const char *bar_mode, const char *bar_id) { int mode = M_DOCK; bool toggle = false; if (strcmp(bar_mode, "dock") == 0) @@ -2079,7 +2079,7 @@ bool cmd_bar_mode(const char *bar_mode, const char *bar_id) { * Implementation of 'bar hidden_state hide|show|toggle []' * */ -bool cmd_bar_hidden_state(const char *bar_hidden_state, const char *bar_id) { +static bool cmd_bar_hidden_state(const char *bar_hidden_state, const char *bar_id) { int hidden_state = S_SHOW; bool toggle = false; if (strcmp(bar_hidden_state, "hide") == 0) diff --git a/src/commands_parser.c b/src/commands_parser.c index 98f06659..4299c008 100644 --- a/src/commands_parser.c +++ b/src/commands_parser.c @@ -157,7 +157,7 @@ static long get_long(const char *identifier) { // TODO move to a common util static void clear_stack(void) { for (int c = 0; c < 10; c++) { - if (stack[c].type == STACK_STR && stack[c].val.str != NULL) + if (stack[c].type == STACK_STR) free(stack[c].val.str); stack[c].identifier = NULL; stack[c].val.str = NULL; diff --git a/src/con.c b/src/con.c index d50c29be..c9ff44a2 100644 --- a/src/con.c +++ b/src/con.c @@ -312,7 +312,7 @@ bool con_has_managed_window(Con *con) { return (con != NULL && con->window != NULL && con->window->id != XCB_WINDOW_NONE && con_get_workspace(con) != NULL); } -/** +/* * Returns true if this node has regular or floating children. * */ @@ -526,7 +526,7 @@ Con *con_get_fullscreen_covering_ws(Con *ws) { return fs; } -/** +/* * Returns true if the container is internal, such as __i3_scratch * */ @@ -896,7 +896,7 @@ int con_num_children(Con *con) { return children; } -/** +/* * Returns the number of visible non-floating children of this container. * For example, if the container contains a hsplit which has two children, * this will return 2 instead of 1. diff --git a/src/config.c b/src/config.c index 5be1fd52..9631b216 100644 --- a/src/config.c +++ b/src/config.c @@ -18,7 +18,7 @@ Config config; struct modes_head modes; struct barconfig_head barconfigs = TAILQ_HEAD_INITIALIZER(barconfigs); -/** +/* * Ungrabs all keys, to be called before re-grabbing the keys because of a * mapping_notify event or a configuration file reload * @@ -32,7 +32,7 @@ void ungrab_all_keys(xcb_connection_t *conn) { * Sends the current bar configuration as an event to all barconfig_update listeners. * */ -void update_barconfig() { +void update_barconfig(void) { Barconfig *current; TAILQ_FOREACH(current, &barconfigs, configs) { ipc_send_barconfig_update_event(current); diff --git a/src/config_parser.c b/src/config_parser.c index 2d3f3bb9..9f972fed 100644 --- a/src/config_parser.c +++ b/src/config_parser.c @@ -171,7 +171,7 @@ static long get_long(const char *identifier) { static void clear_stack(void) { for (int c = 0; c < 10; c++) { - if (stack[c].type == STACK_STR && stack[c].val.str != NULL) + if (stack[c].type == STACK_STR) free(stack[c].val.str); stack[c].identifier = NULL; stack[c].val.str = NULL; diff --git a/src/floating.c b/src/floating.c index be514ce2..a99d0970 100644 --- a/src/floating.c +++ b/src/floating.c @@ -59,7 +59,7 @@ static void floating_set_hint_atom(Con *con, bool floating) { xcb_flush(conn); } -/** +/* * Called when a floating window is created or resized. * This function resizes the window if its size is higher or lower than the * configured maximum/minimum size, respectively. @@ -899,13 +899,17 @@ bool floating_reposition(Con *con, Rect newrect) { con->rect = newrect; - floating_maybe_reassign_ws(con); + bool reassigned = floating_maybe_reassign_ws(con); /* If this is a scratchpad window, don't auto center it from now on. */ if (con->scratchpad_state == SCRATCHPAD_FRESH) con->scratchpad_state = SCRATCHPAD_CHANGED; - tree_render(); + /* Workspace change will already result in a tree_render. */ + if (!reassigned) { + render_con(con, false); + x_push_node(con); + } return true; } diff --git a/src/handlers.c b/src/handlers.c index c76f1935..238cf26f 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -949,8 +949,8 @@ static void handle_client_message(xcb_client_message_event_t *event) { } } -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) { +static 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; diff --git a/src/ipc.c b/src/ipc.c index 3022d5b3..d0fb965c 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -1580,7 +1580,7 @@ void ipc_send_workspace_event(const char *change, Con *current, Con *old) { y(free); } -/** +/* * For the window events we send, along the usual "change" field, * also the window container, in "container". */ @@ -1610,7 +1610,7 @@ void ipc_send_window_event(const char *property, Con *con) { setlocale(LC_NUMERIC, ""); } -/** +/* * For the barconfig update events, we send the serialized barconfig. */ void ipc_send_barconfig_update_event(Barconfig *barconfig) { diff --git a/src/load_layout.c b/src/load_layout.c index 32da9c47..5a340d2c 100644 --- a/src/load_layout.c +++ b/src/load_layout.c @@ -153,8 +153,7 @@ static int json_end_map(void *ctx) { free(marks[i]); } - free(marks); - marks = NULL; + FREE(marks); num_marks = 0; } diff --git a/src/main.c b/src/main.c index eeeb3419..7eb47c82 100644 --- a/src/main.c +++ b/src/main.c @@ -32,7 +32,7 @@ * RLIM_INFINITY for i3 debugging versions. */ struct rlimit original_rlimit_core; -/** The number of file descriptors passed via socket activation. */ +/* The number of file descriptors passed via socket activation. */ int listen_fds; /* We keep the xcb_prepare watcher around to be able to enable and disable it diff --git a/src/manage.c b/src/manage.c index 4031ade6..c4706b0d 100644 --- a/src/manage.c +++ b/src/manage.c @@ -246,17 +246,13 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki DLOG("Initial geometry: (%d, %d, %d, %d)\n", geom->x, geom->y, geom->width, geom->height); - Con *nc = NULL; - Match *match = NULL; - Assignment *assignment; - - /* TODO: two matches for one container */ - /* See if any container swallows this new window */ - nc = con_for_window(search_at, cwindow, &match); + Match *match = NULL; + Con *nc = con_for_window(search_at, cwindow, &match); const bool match_from_restart_mode = (match && match->restart_mode); if (nc == NULL) { Con *wm_desktop_ws = NULL; + Assignment *assignment; /* If not, check if it is assigned to a specific workspace */ if ((assignment = assignment_for(cwindow, A_TO_WORKSPACE)) || diff --git a/src/move.c b/src/move.c index 32178e6b..545a910a 100644 --- a/src/move.c +++ b/src/move.c @@ -179,18 +179,16 @@ void insert_con_into(Con *con, Con *target, position_t position) { static void attach_to_workspace(Con *con, Con *ws, direction_t direction) { con_detach(con); con_fix_percent(con->parent); - CALL(con->parent, on_remove_child); con->parent = ws; if (direction == D_RIGHT || direction == D_DOWN) { TAILQ_INSERT_HEAD(&(ws->nodes_head), con, nodes); - TAILQ_INSERT_HEAD(&(ws->focus_head), con, focused); } else { TAILQ_INSERT_TAIL(&(ws->nodes_head), con, nodes); - TAILQ_INSERT_TAIL(&(ws->focus_head), con, focused); } + TAILQ_INSERT_TAIL(&(ws->focus_head), con, focused); /* Pretend the con was just opened with regards to size percent values. * Since the con is moved to a completely different con, the old value @@ -205,7 +203,6 @@ static void attach_to_workspace(Con *con, Con *ws, direction_t direction) { * */ static void move_to_output_directed(Con *con, direction_t direction) { - Con *old_ws = con_get_workspace(con); Output *current_output = get_output_for_con(con); Output *output = get_output_next(direction, current_output, CLOSEST_OUTPUT); @@ -222,17 +219,26 @@ static void move_to_output_directed(Con *con, direction_t direction) { return; } + Con *old_ws = con_get_workspace(con); + const bool moves_focus = (focused == con); attach_to_workspace(con, ws, direction); - - /* fix the focus stack */ - con_activate(con); + if (moves_focus) { + /* workspace_show will not correctly update the active workspace because + * the focused container, con, is now a child of ws. To work around this + * and still produce the correct workspace focus events (see + * 517-regress-move-direction-ipc.t) we need to temporarily set focused + * to the old workspace. */ + focused = old_ws; + workspace_show(ws); + con_focus(con); + } /* force re-painting the indicators */ FREE(con->deco_render_params); tree_flatten(croot); - - ipc_send_workspace_event("focus", ws, old_ws); + ipc_send_window_event("move", con); + ewmh_update_wm_desktop(); } /* @@ -292,9 +298,10 @@ void tree_move(Con *con, int direction) { /* easy case: the move is within this container */ if (same_orientation == con->parent) { - DLOG("We are in the same container\n"); - Con *swap; - if ((swap = (direction == D_LEFT || direction == D_UP ? TAILQ_PREV(con, nodes_head, nodes) : TAILQ_NEXT(con, nodes)))) { + Con *swap = (direction == D_LEFT || direction == D_UP) + ? TAILQ_PREV(con, nodes_head, nodes) + : TAILQ_NEXT(con, nodes); + if (swap) { if (!con_is_leaf(swap)) { DLOG("Moving into our bordering branch\n"); target = con_descend_direction(swap, direction); @@ -306,26 +313,22 @@ void tree_move(Con *con, int direction) { insert_con_into(con, target, position); goto end; } - if (direction == D_LEFT || direction == D_UP) + + DLOG("Swapping with sibling.\n"); + if (direction == D_LEFT || direction == D_UP) { TAILQ_SWAP(swap, con, &(swap->parent->nodes_head), nodes); - else + } else { TAILQ_SWAP(con, swap, &(swap->parent->nodes_head), nodes); + } - TAILQ_REMOVE(&(con->parent->focus_head), con, focused); - TAILQ_INSERT_HEAD(&(swap->parent->focus_head), con, focused); - - DLOG("Swapped.\n"); ipc_send_window_event("move", con); - ewmh_update_wm_desktop(); return; } if (con->parent == con_get_workspace(con)) { - /* If we couldn't find a place to move it on this workspace, - * try to move it to a workspace on a different output */ + /* If we couldn't find a place to move it on this workspace, try + * to move it to a workspace on a different output */ move_to_output_directed(con, direction); - ipc_send_window_event("move", con); - ewmh_update_wm_desktop(); return; } @@ -370,6 +373,7 @@ void tree_move(Con *con, int direction) { * and move it to the next output. */ DLOG("Grandparent is workspace\n"); move_to_output_directed(con, direction); + return; } else { DLOG("Moving into container above\n"); position = (direction == D_UP || direction == D_LEFT ? BEFORE : AFTER); diff --git a/src/output.c b/src/output.c index 19a7c4af..ebba5c77 100644 --- a/src/output.c +++ b/src/output.c @@ -72,8 +72,15 @@ Output *get_output_for_con(Con *con) { * Iterates over all outputs and pushes sticky windows to the currently visible * workspace on that output. * + * old_focus is used to determine if a sticky window is going to be focused. + * old_focus might be different than the currently focused container because the + * caller might need to temporarily change the focus and then call + * output_push_sticky_windows. For example, workspace_show needs to set focus to + * one of its descendants first, then call output_push_sticky_windows that + * should focus a sticky window if it was the focused in the previous workspace. + * */ -void output_push_sticky_windows(Con *to_focus) { +void output_push_sticky_windows(Con *old_focus) { Con *output; TAILQ_FOREACH(output, &(croot->focus_head), focused) { Con *workspace, *visible_ws = NULL; @@ -95,18 +102,17 @@ void output_push_sticky_windows(Con *to_focus) { child != TAILQ_END(&(current_ws->focus_head));) { Con *current = child; child = TAILQ_NEXT(child, focused); - if (current->type != CT_FLOATING_CON) + if (current->type != CT_FLOATING_CON || !con_is_sticky(current)) { continue; + } - if (con_is_sticky(current)) { - bool ignore_focus = (to_focus == NULL) || (current != to_focus->parent); - con_move_to_workspace(current, visible_ws, true, false, ignore_focus); - if (!ignore_focus) { - Con *current_ws = con_get_workspace(focused); - con_activate(con_descend_focused(current)); - /* Pushing sticky windows shouldn't change the focused workspace. */ - con_activate(con_descend_focused(current_ws)); - } + bool ignore_focus = (old_focus == NULL) || (current != old_focus->parent); + con_move_to_workspace(current, visible_ws, true, false, ignore_focus); + if (!ignore_focus) { + Con *current_ws = con_get_workspace(focused); + con_activate(con_descend_focused(current)); + /* Pushing sticky windows shouldn't change the focused workspace. */ + con_activate(con_descend_focused(current_ws)); } } } diff --git a/src/randr.c b/src/randr.c index 54d61ddd..6bb8d9e6 100644 --- a/src/randr.c +++ b/src/randr.c @@ -550,7 +550,7 @@ static void output_change_mode(xcb_connection_t *conn, Output *output) { } /* If default_orientation is NO_ORIENTATION, we change the orientation of - * the workspaces and their childs depending on output resolution. This is + * the workspaces and their children depending on output resolution. This is * only done for workspaces with maximum one child. */ if (config.default_orientation == NO_ORIENTATION) { TAILQ_FOREACH(workspace, &(content->nodes_head), nodes) { diff --git a/src/sighandler.c b/src/sighandler.c index 12ed0ef9..e49c30ba 100644 --- a/src/sighandler.c +++ b/src/sighandler.c @@ -62,14 +62,13 @@ static int sighandler_backtrace(void) { char *filename = NULL; int suffix = 0; - struct stat bt; /* Find a unique filename for the backtrace (since the PID of i3 stays the * same), so that we don’t overwrite earlier backtraces. */ do { FREE(filename); sasprintf(&filename, "%s/i3-backtrace.%d.%d.txt", tmpdir, pid_parent, suffix); suffix++; - } while (stat(filename, &bt) == 0); + } while (path_exists(filename)); pid_t pid_gdb = fork(); if (pid_gdb < 0) { @@ -130,7 +129,7 @@ static int sighandler_backtrace(void) { if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { DLOG("GDB did not run properly\n"); return -1; - } else if (stat(filename, &bt) == -1) { + } else if (!path_exists(filename)) { DLOG("GDB executed successfully, but no backtrace was generated\n"); return -1; } @@ -300,7 +299,7 @@ static void sighandler_handle_key_press(xcb_key_press_event_t *event) { } } -void handle_signal(int sig, siginfo_t *info, void *data) { +static void handle_signal(int sig, siginfo_t *info, void *data) { DLOG("i3 crashed. SIG: %d\n", sig); struct sigaction action; diff --git a/src/startup.c b/src/startup.c index b1a2f602..6302d811 100644 --- a/src/startup.c +++ b/src/startup.c @@ -95,7 +95,7 @@ static int _prune_startup_sequences(void) { return active_sequences; } -/** +/* * Deletes a startup sequence, ignoring whether its timeout has elapsed. * Useful when e.g. a window is moved between workspaces and its children * shouldn't spawn on the original workspace. @@ -118,10 +118,10 @@ void startup_sequence_delete(struct Startup_Sequence *sequence) { } /* - * Starts the given application by passing it through a shell. We use double fork - * to avoid zombie processes. As the started application’s parent exits (immediately), - * the application is reparented to init (process-id 1), which correctly handles - * childs, so we don’t have to do it :-). + * Starts the given application by passing it through a shell. We use double + * fork to avoid zombie processes. As the started application’s parent exits + * (immediately), the application is reparented to init (process-id 1), which + * correctly handles children, so we don’t have to do it :-). * * The shell used to start applications is the system's bourne shell (i.e., * /bin/sh). @@ -257,7 +257,7 @@ void startup_monitor_event(SnMonitorEvent *event, void *userdata) { } } -/** +/* * Renames workspaces that are mentioned in the startup sequences. * */ @@ -273,7 +273,7 @@ void startup_sequence_rename_workspace(const char *old_name, const char *new_nam } } -/** +/* * Gets the stored startup sequence for the _NET_STARTUP_ID of a given window. * */ diff --git a/src/util.c b/src/util.c index a59283a8..85f359c0 100644 --- a/src/util.c +++ b/src/util.c @@ -217,7 +217,7 @@ static char **add_argument(char **original, char *opt_char, char *opt_arg, char #define y(x, ...) yajl_gen_##x(gen, ##__VA_ARGS__) #define ystr(str) yajl_gen_string(gen, (unsigned char *)str, strlen(str)) -char *store_restart_layout(void) { +static char *store_restart_layout(void) { setlocale(LC_NUMERIC, "C"); yajl_gen gen = yajl_gen_alloc(NULL); @@ -501,8 +501,7 @@ ssize_t slurp(const char *path, char **buf) { fclose(f); if ((ssize_t)n != stbuf.st_size) { ELOG("File \"%s\" could not be read entirely: got %zd, want %" PRIi64 "\n", path, n, (int64_t)stbuf.st_size); - free(*buf); - *buf = NULL; + FREE(*buf); return -1; } return (ssize_t)n; diff --git a/src/workspace.c b/src/workspace.c index 5f5c8d4f..a2d9b0e8 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -308,7 +308,7 @@ bool workspace_is_visible(Con *ws) { * XXX: we need to clean up all this recursive walking code. * */ -Con *_get_sticky(Con *con, const char *sticky_group, Con *exclude) { +static Con *_get_sticky(Con *con, const char *sticky_group, Con *exclude) { Con *current; TAILQ_FOREACH(current, &(con->nodes_head), nodes) { @@ -410,7 +410,6 @@ static void workspace_defer_update_urgent_hint_cb(EV_P_ ev_timer *w, int revents */ void workspace_show(Con *workspace) { Con *current, *old = NULL; - Con *old_focus = focused; /* safe-guard against showing i3-internal workspaces like __i3_scratch */ if (con_is_internal(workspace)) @@ -433,6 +432,13 @@ void workspace_show(Con *workspace) { return; } + /* Used to correctly update focus when pushing sticky windows. Holds the + * previously focused container in the same output as workspace. For + * example, if a sticky window is focused and then we switch focus to a + * workspace in another output and then switch to a third workspace in the + * first output, the sticky window needs to be refocused. */ + Con *old_focus = old ? con_descend_focused(old) : NULL; + /* Remember currently focused workspace for switching back to it later with * the 'workspace back_and_forth' command. * NOTE: We have to duplicate the name as the original will be freed when @@ -914,7 +920,7 @@ Con *workspace_attach_to(Con *ws) { return new; } -/** +/* * Creates a new container and re-parents all of children from the given * workspace into it. * @@ -949,7 +955,7 @@ Con *workspace_encapsulate(Con *ws) { return new; } -/** +/* * Move the given workspace to the specified output. * This returns true if and only if moving the workspace was successful. */ diff --git a/src/x.c b/src/x.c index ceffd30a..0fc6e714 100644 --- a/src/x.c +++ b/src/x.c @@ -42,7 +42,7 @@ typedef struct con_state { bool child_mapped; bool is_hidden; - /** The con for which this state is. */ + /* The con for which this state is. */ Con *con; /* For reparenting, we have a flag (need_reparent) and the X ID of the old @@ -504,14 +504,12 @@ void x_draw_decoration(Con *con) { /* 3: draw a rectangle in border color around the client */ if (p->border_style != BS_NONE && p->con_is_leaf) { /* We might hide some borders adjacent to the screen-edge */ - adjacent_t borders_to_hide = ADJ_NONE; - borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders; - + adjacent_t borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders; Rect br = con_border_style_rect(con); /* These rectangles represent the border around the child window * (left, bottom and right part). We don’t just fill the whole - * rectangle because some childs are not freely resizable and we want + * rectangle because some children are not freely resizable and we want * their background color to "shine through". */ if (!(borders_to_hide & ADJ_LEFT_SCREEN_EDGE)) { draw_util_rectangle(&(con->frame_buffer), p->color->child_border, 0, 0, br.x, r->height); @@ -1283,7 +1281,7 @@ void x_set_name(Con *con, const char *name) { * Set up the I3_SHMLOG_PATH atom. * */ -void update_shmlog_atom() { +void update_shmlog_atom(void) { if (*shmlogname == '\0') { xcb_delete_property(conn, root, A_I3_SHMLOG_PATH); } else { diff --git a/testcases/inject_randr1.5.c b/testcases/inject_randr1.5.c index 5506d67e..520b0213 100644 --- a/testcases/inject_randr1.5.c +++ b/testcases/inject_randr1.5.c @@ -34,7 +34,7 @@ static void read_server_x11_packet_cb(EV_P_ ev_io *w, int revents); static char *sun_path = NULL; -void cleanup_socket(void) { +static void cleanup_socket(void) { if (sun_path != NULL) { unlink(sun_path); free(sun_path); diff --git a/testcases/t/189-floating-constraints.t b/testcases/t/189-floating-constraints.t index 4ac95e15..ba5f76aa 100644 --- a/testcases/t/189-floating-constraints.t +++ b/testcases/t/189-floating-constraints.t @@ -265,11 +265,13 @@ my sub open_with_max_size { } my sub check_minsize { + sync_with_i3; is($window->rect->{width}, $min_width, 'width = min_width'); is($window->rect->{height}, $min_height, 'height = min_height'); } my sub check_maxsize { + sync_with_i3; is($window->rect->{width}, $max_width, 'width = max_width'); is($window->rect->{height}, $max_height, 'height = max_height'); } @@ -279,7 +281,6 @@ $pid = launch_with_config($config); $window = open_with_max_size; cmd 'floating enable'; cmd 'border none'; -sync_with_i3; cmd "resize set $min_width px $min_height px"; check_minsize; diff --git a/testcases/t/276-ipc-window-move.t b/testcases/t/276-ipc-window-move.t index f3606b4e..708963df 100644 --- a/testcases/t/276-ipc-window-move.t +++ b/testcases/t/276-ipc-window-move.t @@ -34,7 +34,7 @@ sub move_subtest { is($move[0]->{container}->{window}, $window->{id}, 'window id matches'); } -subtest 'move right', \&move_subtest, 'move right'; +subtest 'move left', \&move_subtest, 'move left'; subtest 'move to workspace', \&move_subtest, 'move to workspace ws_new'; done_testing; diff --git a/testcases/t/285-sticky.t b/testcases/t/285-sticky.t index f53e4a93..8dfe9aea 100644 --- a/testcases/t/285-sticky.t +++ b/testcases/t/285-sticky.t @@ -16,7 +16,14 @@ # # Tests sticky windows. # Ticket: #1455 -use i3test; +use i3test i3_config => < 'findme'); +open_window; cmd 'sticky enable'; $ws = fresh_workspace; is(@{get_ws($ws)->{nodes}}, 0, 'tiling sticky container did not move'); is(@{get_ws($ws)->{floating_nodes}}, 0, 'tiling sticky container did not move'); -cmd '[class="findme"] kill'; +kill_all_windows; ############################################################################### # 2: Given a sticky floating container, when the workspace is switched, then # the container moves to the new workspace. ############################################################################### $ws = fresh_workspace; -open_floating_window(wm_class => 'findme'); +open_floating_window; $focused = get_focused($ws); cmd 'sticky enable'; $ws = fresh_workspace; is(@{get_ws($ws)->{floating_nodes}}, 1, 'floating sticky container moved to new workspace'); is(get_focused($ws), $focused, 'sticky container has focus'); -cmd '[class="findme"] kill'; +kill_all_windows; ############################################################################### # 3: Given two sticky floating containers, when the workspace is switched, # then both containers move to the new workspace. ############################################################################### fresh_workspace; -open_floating_window(wm_class => 'findme'); +open_floating_window; cmd 'sticky enable'; -open_floating_window(wm_class => 'findme'); +open_floating_window; cmd 'sticky enable'; $ws = fresh_workspace; is(@{get_ws($ws)->{floating_nodes}}, 2, 'multiple sticky windows can be used at the same time'); -cmd '[class="findme"] kill'; +kill_all_windows; ############################################################################### # 4: Given an unfocused sticky floating container and a tiling container on the @@ -70,13 +77,13 @@ $ws = fresh_workspace; open_window; $focused = get_focused($ws); fresh_workspace; -open_floating_window(wm_class => 'findme'); +open_floating_window; cmd 'sticky enable'; open_window; cmd 'workspace ' . $ws; is(get_focused($ws), $focused, 'the tiling container has focus'); -cmd '[class="findme"] kill'; +kill_all_windows; ############################################################################### # 5: Given a focused sticky floating container and a tiling container on the @@ -86,13 +93,13 @@ cmd '[class="findme"] kill'; $ws = fresh_workspace; open_window; $tmp = fresh_workspace; -open_floating_window(wm_class => 'findme'); +open_floating_window; $focused = get_focused($tmp); cmd 'sticky enable'; cmd 'workspace ' . $ws; is(get_focused($ws), $focused, 'the sticky container has focus'); -cmd '[class="findme"] kill'; +kill_all_windows; ############################################################################### # 6: Given a floating container on a non-visible workspace, when the window @@ -100,13 +107,31 @@ cmd '[class="findme"] kill'; # visible workspace. ############################################################################### fresh_workspace; -open_floating_window(wm_class => 'findme'); +open_floating_window; cmd 'mark sticky'; $ws = fresh_workspace; cmd '[con_mark=sticky] sticky enable'; is(@{get_ws($ws)->{floating_nodes}}, 1, 'the sticky window jumps to the front'); -cmd '[class="findme"] kill'; +kill_all_windows; + +############################################################################### +# 7: Given a sticky floating container and a workspace on another output, when +# a new workspace assigned to the first output is focused, then the sticky +# container should jump to the new workspace and have input focus correctly. +############################################################################### +$ws = fresh_workspace(output => 0); +open_floating_window; +cmd 'sticky enabled'; +$focused = get_focused($ws); +$ws = fresh_workspace(output => 1); + +is(@{get_ws($ws)->{floating_nodes}}, 0, 'the sticky window didn\'t jump to a workspace on a different output'); +$ws = 'ws-on-0'; +cmd "workspace $ws"; +is(@{get_ws($ws)->{floating_nodes}}, 1, 'the sticky window moved to new workspace on first output'); +is(get_focused($ws), $focused, 'the sticky window has focus'); +kill_all_windows; ############################################################################### diff --git a/testcases/t/293-focus-follows-mouse.t b/testcases/t/293-focus-follows-mouse.t index 0cd6e5c3..55958c3e 100644 --- a/testcases/t/293-focus-follows-mouse.t +++ b/testcases/t/293-focus-follows-mouse.t @@ -67,11 +67,8 @@ my $tmp = fresh_workspace; my ($first_floating, $second_floating); synced_warp_pointer(0, 0); -$first_floating = open_floating_window; -$first_floating->rect(X11::XCB::Rect->new(x => 1, y => 1, width => 100, height => 100)); -$second_floating = open_floating_window; -$second_floating->rect(X11::XCB::Rect->new(x => 50, y => 50, width => 100, height => 100)); -sync_with_i3; +$first_floating = open_floating_window(rect => [ 1, 1, 100, 100 ]); +$second_floating = open_floating_window(rect => [ 50, 50, 100, 100 ]); $first = open_window; is($x->input_focus, $first->id, 'first (tiling) window focused'); diff --git a/testcases/t/294-focus-order.t b/testcases/t/294-focus-order.t index c818f1d4..6b16540c 100644 --- a/testcases/t/294-focus-order.t +++ b/testcases/t/294-focus-order.t @@ -16,7 +16,11 @@ # # Verify that the corrent focus stack order is preserved after various # operations. -use i3test; +use i3test i3_config => < 0); +$windows[3] = open_window; +fresh_workspace(output => 1); +$windows[2] = open_window; +$windows[1] = open_window; +$windows[0] = open_window; + +cmd '[id=' . $windows[3]->id . '] move right'; +confirm_focus('unfocused move from other output'); + +##################################################################### +# Test that moving an unfocused container inside its original parent +# maintains the correct focus order. +##################################################################### + +fresh_workspace; +$windows[0] = open_window; +$windows[1] = open_window; +cmd 'split v'; +$windows[2] = open_window; +$windows[3] = open_window; +focus_windows; + +cmd '[id=' . $windows[2]->id . '] move up'; +confirm_focus('split-v + unfocused move inside parent'); + ###################################################################### # Test that moving an unfocused container maintains the correct focus # order. diff --git a/travis/travis-base.Dockerfile b/travis/travis-base.Dockerfile index 7eafb9fb..be3780d4 100644 --- a/travis/travis-base.Dockerfile +++ b/travis/travis-base.Dockerfile @@ -24,6 +24,7 @@ RUN apt-get update && \ # Install i3 build dependencies. COPY debian/control /usr/src/i3-debian-packaging/control +COPY debian/changelog /usr/src/i3-debian-packaging/changelog RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive mk-build-deps --install --remove --tool 'apt-get --no-install-recommends -y' /usr/src/i3-debian-packaging/control && \ rm -rf /var/lib/apt/lists/*