Fixes #2990.
*/
void con_focus(Con *con);
+/**
+ * Sets input focus to the given container and raises it to the top.
+ *
+ */
+void con_activate(Con *con);
+
/**
* Closes the given container.
*
* The splitv container will be focused. */
Con *focused = con->parent;
focused = TAILQ_FIRST(&(focused->focus_head));
- con_focus(focused);
+ con_activate(focused);
/* To prevent scrolling from going outside the container (see ticket
* #557), we first check if scrolling is possible at all. */
bool scroll_prev_possible = (TAILQ_PREV(focused, nodes_head, nodes) != NULL);
}
/* 2: focus this con. */
- con_focus(con);
+ con_activate(con);
/* 3: For floating containers, we also want to raise them on click.
* We will skip handling events on floating cons in fullscreen mode */
if (fullscreen_on_ws && fullscreen_on_ws != con && !con_has_parent(con, fullscreen_on_ws)) {
con_disable_fullscreen(fullscreen_on_ws);
}
- con_focus(con);
+ con_activate(con);
}
/*
* the target workspace, then revert focus. */
Con *currently_focused = focused;
cmd_focus_force_focus(current->con);
- con_focus(currently_focused);
+ con_activate(currently_focused);
/* Now switch to the workspace, then focus */
workspace_show(ws);
LOG("focusing %p / %s\n", current->con, current->con->name);
- con_focus(current->con);
+ con_activate(current->con);
count++;
}
/* the move command should not disturb focus */
if (focused != initially_focused)
- con_focus(initially_focused);
+ con_activate(initially_focused);
// XXX: default reply for now, make this a better reply
ysuccess(true);
LOG("opening new container\n");
Con *con = tree_open_con(NULL, NULL);
con->layout = L_SPLITH;
- con_focus(con);
+ con_activate(con);
y(map_open);
ystr("success");
}
/* Restore the previous focus since con_attach messes with the focus. */
- con_focus(previously_focused);
+ con_activate(previously_focused);
cmd_output->needs_tree_render = true;
ysuccess(true);
workspace_update_urgent_flag(con_get_workspace(con));
ipc_send_window_event("urgent", con);
}
+}
- /* Focusing a container with a floating parent should raise it to the top. Since
- * con_focus is called recursively for each parent we don't need to use
- * con_inside_floating(). */
- if (con->type == CT_FLOATING_CON) {
- floating_raise_con(con);
+/*
+ * Raise container to the top if it is floating or inside some floating
+ * container.
+ *
+ */
+static void con_raise(Con *con) {
+ Con *floating = con_inside_floating(con);
+ if (floating) {
+ floating_raise_con(floating);
}
}
+/*
+ * Sets input focus to the given container and raises it to the top.
+ *
+ */
+void con_activate(Con *con) {
+ con_focus(con);
+ con_raise(con);
+}
+
/*
* Closes the given container.
*
Con *old_focused = focused;
if (fullscreen_mode == CF_GLOBAL && cur_ws != con_ws)
workspace_show(con_ws);
- con_focus(con);
+ con_activate(con);
if (fullscreen_mode != CF_GLOBAL && cur_ws != con_ws)
- con_focus(old_focused);
+ con_activate(old_focused);
con_set_fullscreen_mode(con, fullscreen_mode);
}
* new workspace is hidden and it's necessary to immediately switch
* back to the originally-focused workspace. */
Con *old_focus = TAILQ_FIRST(&(output_get_content(dest_output)->focus_head));
- con_focus(con_descend_focused(con));
+ con_activate(con_descend_focused(con));
/* Restore focus if the output's focused workspace has changed. */
if (con_get_workspace(focused) != old_focus)
- con_focus(old_focus);
+ con_activate(old_focus);
}
/* 7: when moving to another workspace, we leave the focus on the current
/* Set focus only if con was on current workspace before moving.
* Otherwise we would give focus to some window on different workspace. */
if (!ignore_focus && source_ws == current_ws)
- con_focus(con_descend_focused(focus_next));
+ con_activate(con_descend_focused(focus_next));
/* 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. */
con_attach(new, con, false);
if (old_focused)
- con_focus(old_focused);
+ con_activate(old_focused);
tree_flatten(croot);
}
* We don't need to check this for the second container because we've only
* moved the first one at this point.*/
if (first_ws != second_ws && focused_within_first) {
- con_focus(con_descend_focused(current_ws));
+ con_activate(con_descend_focused(current_ws));
}
/* Move second to where first has been originally. */
*/
if (focused_within_first) {
if (first_ws == second_ws) {
- con_focus(old_focus);
+ con_activate(old_focus);
} else {
- con_focus(con_descend_focused(second));
+ con_activate(con_descend_focused(second));
}
} else if (focused_within_second) {
if (first_ws == second_ws) {
- con_focus(old_focus);
+ con_activate(old_focus);
} else {
- con_focus(con_descend_focused(first));
+ con_activate(con_descend_focused(first));
}
}
render_con(con, false);
if (set_focus)
- con_focus(con);
+ con_activate(con);
/* Check if we need to re-assign it to a different workspace because of its
* coordinates and exit if that was done successfully. */
con_fix_percent(con->parent);
if (set_focus)
- con_focus(con);
+ con_activate(con);
floating_set_hint_atom(con, false);
ipc_send_window_event("floating", con);
DLOG("Moving con %p / %s to workspace %p / %s\n", con, con->name, ws, ws->name);
con_move_to_workspace(con, ws, false, true, false);
workspace_show(ws);
- con_focus(con_descend_focused(con));
+ con_activate(con_descend_focused(con));
return true;
}
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);
+ con_activate(con);
tree_render();
} 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);
workspace_show(ws);
/* Re-set focus, even if unchanged from i3’s perspective. */
focused_id = XCB_NONE;
- con_focus(con);
+ con_activate(con);
}
} else {
/* 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);
+ con_activate(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);
if (ws != con_get_workspace(focused))
workspace_show(ws);
- con_focus(con);
+ con_activate(con);
/* We update focused_id because we don’t need to set focus again */
focused_id = event->event;
tree_render();
yajl_free(hand);
if (to_focus) {
- con_focus(to_focus);
+ con_activate(to_focus);
}
}
output = get_first_output();
}
- con_focus(con_descend_focused(output_get_content(output->con)));
+ con_activate(con_descend_focused(output_get_content(output->con)));
free(pointerreply);
}
* proper window event sequence. */
if (set_focus && nc->mapped) {
DLOG("Now setting focus.\n");
- con_focus(nc);
+ con_activate(nc);
}
tree_render();
attach_to_workspace(con, ws, direction);
/* fix the focus stack */
- con_focus(con);
+ con_activate(con);
/* force re-painting the indicators */
FREE(con->deco_render_params);
Con *ws = create_workspace_on_output(output, content);
/* TODO: Set focus in main.c */
- con_focus(ws);
+ con_activate(ws);
}
/*
continue;
DLOG("Focusing primary output %s\n", output_primary_name(output));
- con_focus(con_descend_focused(output->con));
+ con_activate(con_descend_focused(output->con));
}
/* render_layout flushes */
if (next) {
DLOG("now focusing next = %p\n", next);
- con_focus(next);
+ con_activate(next);
workspace_show(con_get_workspace(next));
}
/* use con_descend_tiling_focused to get the last focused
* window inside this scratch container in order to
* keep the focus the same within this container */
- con_focus(con_descend_tiling_focused(walk_con));
+ con_activate(con_descend_tiling_focused(walk_con));
return;
}
}
workspace_show(active);
}
- con_focus(con_descend_focused(con));
+ con_activate(con_descend_focused(con));
}
/*
DLOG("focusing %p / %s\n", next, next->name);
if (next->type == CT_DOCKAREA) {
/* Instead of focusing the dockarea, we need to restore focus to the workspace */
- con_focus(con_descend_focused(output_get_content(next->parent)));
+ con_activate(con_descend_focused(output_get_content(next->parent)));
} else {
if (!force_set_focus && con != focused)
DLOG("not changing focus, the container was not focused before\n");
else
- con_focus(next);
+ con_activate(next);
}
} else {
DLOG("not focusing because we're not killing anybody\n");
/* Skip over floating containers and go directly to the grandparent
* (which should always be a workspace) */
if (focused->parent->type == CT_FLOATING_CON) {
- con_focus(focused->parent->parent);
+ con_activate(focused->parent->parent);
return true;
}
ELOG("'focus parent': Focus is already on the workspace, cannot go higher than that.\n");
return false;
}
- con_focus(focused->parent);
+ con_activate(focused->parent);
return true;
}
next = TAILQ_FIRST(&(next->focus_head));
}
- con_focus(next);
+ con_activate(next);
return true;
}
}
workspace_show(workspace);
- con_focus(focus);
+ con_activate(focus);
x_set_warp_to(&(focus->rect));
return true;
}
TAILQ_INSERT_HEAD(&(parent->floating_head), last, floating_windows);
}
- con_focus(con_descend_focused(next));
+ con_activate(con_descend_focused(next));
return true;
}
/* 3: focus choice comes in here. at the moment we will go down
* until we find a window */
/* TODO: check for window, atm we only go down as far as possible */
- con_focus(con_descend_focused(next));
+ con_activate(con_descend_focused(next));
return true;
}
if (next->urgent && (int)(config.workspace_urgency_timer * 1000) > 0) {
/* focus for now… */
next->urgent = false;
- con_focus(next);
+ con_activate(next);
/* … but immediately reset urgency flags; they will be set to false by
* the timer callback in case the container is focused at the time of
ev_timer_again(main_loop, focused->urgency_timer);
}
} else
- con_focus(next);
+ con_activate(next);
ipc_send_workspace_event("focus", workspace, current);
con_fix_percent(ws);
if (old_focused)
- con_focus(old_focused);
+ con_activate(old_focused);
}
/*
synced_warp_pointer(0, 0);
is($x->input_focus, $second->id, 'second window still focused');
+###################################################################
+# Test that floating windows are focused but not raised to the top.
+# See issue #2990.
+###################################################################
+
+my $ws;
+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 = open_window;
+
+is($x->input_focus, $first->id, 'first (tiling) window focused');
+$ws = get_ws($tmp);
+is($ws->{floating_nodes}->[1]->{nodes}->[0]->{window}, $second_floating->id, 'second floating on top');
+is($ws->{floating_nodes}->[0]->{nodes}->[0]->{window}, $first_floating->id, 'first floating behind');
+
+synced_warp_pointer(40, 40);
+is($x->input_focus, $first_floating->id, 'first floating window focused');
+$ws = get_ws($tmp);
+is($ws->{floating_nodes}->[1]->{nodes}->[0]->{window}, $second_floating->id, 'second floating still on top');
+is($ws->{floating_nodes}->[0]->{nodes}->[0]->{window}, $first_floating->id, 'first floating still behind');
+
done_testing;