Make focus part of transactions

Rather than maintain copies of the entire focus stack, this PR
transactionises the focus by introducing two new properties to the
container state and using those when rendering.

* `bool focused` means this container has actual focus. Only one
container should have this equalling true in its current state.
* `struct sway_container *focus_inactive_child` points to the immediate
child that was most recently focused (eg. for tabbed and stacked
containers).
This commit is contained in:
Ryan Dwyer 2018-07-15 15:20:21 +10:00
parent 53e3f35ba3
commit a120d4c79f
10 changed files with 55 additions and 73 deletions

View file

@ -118,17 +118,6 @@ struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat,
struct sway_container *seat_get_active_child(struct sway_seat *seat,
struct sway_container *container);
/**
* Return the immediate child of container which was most recently focused, with
* fallback to selecting the child in the parent's `current` (rendered) children
* list.
*
* This is useful for when a tabbed container and its children are destroyed but
* still being rendered, and we have to render an appropriate child.
*/
struct sway_container *seat_get_active_current_child(struct sway_seat *seat,
struct sway_container *container);
/**
* Iterate over the focus-inactive children of the container calling the
* function on each.

View file

@ -68,6 +68,9 @@ struct sway_container_state {
struct sway_container *parent;
list_t *children;
struct sway_container *focused_inactive_child;
bool focused;
// View properties
double view_x, view_y;
double view_width, view_height;

View file

@ -9,7 +9,6 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/criteria.h"
#include "sway/desktop/transaction.h"
#include "sway/security.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
@ -323,7 +322,6 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
cleanup:
free(exec);
free(views);
transaction_commit_dirty();
if (!results) {
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -543,9 +543,6 @@ static void render_container(struct sway_output *output,
static void render_container_simple(struct sway_output *output,
pixman_region32_t *damage, struct sway_container *con,
bool parent_focused) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *focus = seat_get_focus(seat);
for (int i = 0; i < con->current.children->length; ++i) {
struct sway_container *child = con->current.children->items[i];
@ -556,11 +553,11 @@ static void render_container_simple(struct sway_output *output,
struct wlr_texture *marks_texture;
struct sway_container_state *state = &child->current;
if (focus == child || parent_focused) {
if (state->focused || parent_focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view->marks_focused;
} else if (seat_get_focus_inactive(seat, con) == child) {
} else if (con->current.focused_inactive_child == child) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
marks_texture = view->marks_focused_inactive;
@ -580,7 +577,7 @@ static void render_container_simple(struct sway_output *output,
render_view(output, damage, child, colors);
} else {
render_container(output, damage, child,
parent_focused || focus == child);
parent_focused || child->current.focused);
}
}
}
@ -594,11 +591,9 @@ static void render_container_tabbed(struct sway_output *output,
if (!con->current.children->length) {
return;
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *focus = seat_get_focus(seat);
struct sway_container *current = seat_get_active_current_child(seat, con);
struct border_colors *current_colors = &config->border_colors.unfocused;
struct sway_container_state *pstate = &con->current;
struct sway_container *current = pstate->focused_inactive_child;
struct border_colors *current_colors = &config->border_colors.unfocused;
double width_gap_adjustment = 2 * pstate->current_gaps;
int tab_width =
@ -613,11 +608,11 @@ static void render_container_tabbed(struct sway_output *output,
struct wlr_texture *title_texture;
struct wlr_texture *marks_texture;
if (focus == child || parent_focused) {
if (cstate->focused || parent_focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view ? view->marks_focused : NULL;
} else if (child == current) {
} else if (child == pstate->focused_inactive_child) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
marks_texture = view ? view->marks_focused_inactive : NULL;
@ -644,13 +639,11 @@ static void render_container_tabbed(struct sway_output *output,
}
// Render surface and left/right/bottom borders
if (current) {
if (current->type == C_VIEW) {
render_view(output, damage, current, current_colors);
} else {
render_container(output, damage, current,
parent_focused || current == focus);
}
if (current->type == C_VIEW) {
render_view(output, damage, current, current_colors);
} else {
render_container(output, damage, current,
parent_focused || current->current.focused);
}
}
@ -663,11 +656,9 @@ static void render_container_stacked(struct sway_output *output,
if (!con->current.children->length) {
return;
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *focus = seat_get_focus(seat);
struct sway_container *current = seat_get_active_current_child(seat, con);
struct border_colors *current_colors = &config->border_colors.unfocused;
struct sway_container_state *pstate = &con->current;
struct sway_container *current = pstate->focused_inactive_child;
struct border_colors *current_colors = &config->border_colors.unfocused;
size_t titlebar_height = container_titlebar_height();
@ -680,11 +671,11 @@ static void render_container_stacked(struct sway_output *output,
struct wlr_texture *title_texture;
struct wlr_texture *marks_texture;
if (focus == child || parent_focused) {
if (cstate->focused || parent_focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view ? view->marks_focused : NULL;
} else if (child == current) {
} else if (child == pstate->focused_inactive_child) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
marks_texture = view ? view->marks_focused_inactive : NULL;
@ -704,13 +695,11 @@ static void render_container_stacked(struct sway_output *output,
}
// Render surface and left/right/bottom borders
if (current) {
if (current->type == C_VIEW) {
render_view(output, damage, current, current_colors);
} else {
render_container(output, damage, current,
parent_focused || current == focus);
}
if (current->type == C_VIEW) {
render_view(output, damage, current, current_colors);
} else {
render_container(output, damage, current,
parent_focused || current->current.focused);
}
}
@ -738,13 +727,11 @@ static void render_floating_container(struct sway_output *soutput,
pixman_region32_t *damage, struct sway_container *con) {
if (con->type == C_VIEW) {
struct sway_view *view = con->sway_view;
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *focus = seat_get_focus(seat);
struct border_colors *colors;
struct wlr_texture *title_texture;
struct wlr_texture *marks_texture;
if (focus == con) {
if (con->current.focused) {
colors = &config->border_colors.focused;
title_texture = con->title_focused;
marks_texture = view->marks_focused;
@ -871,9 +858,7 @@ void output_render(struct sway_output *output, struct timespec *when,
render_layer(output, damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *focus = seat_get_focus(seat);
render_container(output, damage, workspace, focus == workspace);
render_container(output, damage, workspace, workspace->current.focused);
render_floating(output, damage);
render_unmanaged(output, damage,

View file

@ -139,6 +139,14 @@ static void copy_pending_state(struct sway_container *container,
state->children = create_list();
list_cat(state->children, container->children);
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
state->focused = seat_get_focus(seat) == container;
if (container->type != C_VIEW) {
state->focused_inactive_child =
seat_get_active_child(seat, container);
}
}
static void transaction_add_container(struct sway_transaction *transaction,
@ -195,10 +203,12 @@ static void transaction_apply(struct sway_transaction *transaction) {
.width = instruction->state.swayc_width,
.height = instruction->state.swayc_height,
};
for (int j = 0; j < root_container.children->length; ++j) {
struct sway_container *output = root_container.children->items[j];
output_damage_box(output->sway_output, &old_box);
output_damage_box(output->sway_output, &new_box);
for (int j = 0; j < root_container.current.children->length; ++j) {
struct sway_container *output = root_container.current.children->items[j];
if (output->sway_output) {
output_damage_box(output->sway_output, &old_box);
output_damage_box(output->sway_output, &new_box);
}
}
// There are separate children lists for each instruction state, the

View file

@ -10,6 +10,7 @@
#include <wlr/types/wlr_idle.h>
#include "list.h"
#include "log.h"
#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/layers.h"
#include "sway/output.h"
@ -219,6 +220,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
struct sway_drag_icon *drag_icon = wlr_drag_icon->data;
drag_icon_update_position(drag_icon);
}
transaction_commit_dirty();
}
static void handle_cursor_motion(struct wl_listener *listener, void *data) {
@ -278,6 +280,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
wlr_seat_pointer_notify_button(cursor->seat->wlr_seat,
time_msec, button, state);
transaction_commit_dirty();
}
static void handle_cursor_button(struct wl_listener *listener, void *data) {

View file

@ -3,6 +3,7 @@
#include <wlr/backend/multi.h>
#include <wlr/backend/session.h>
#include <wlr/types/wlr_idle.h>
#include "sway/desktop/transaction.h"
#include "sway/input/seat.h"
#include "sway/input/keyboard.h"
#include "sway/input/input-manager.h"
@ -126,6 +127,7 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard,
binding->command);
config->handler_context.seat = keyboard->seat_device->sway_seat;
struct cmd_results *results = execute_command(binding->command, NULL);
transaction_commit_dirty();
if (results->status != CMD_SUCCESS) {
wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
binding->command, results->error);

View file

@ -661,9 +661,13 @@ void seat_set_focus_warp(struct sway_seat *seat,
if (last_focus) {
seat_send_unfocus(last_focus, seat);
}
seat_send_focus(container, seat);
container_damage_whole(container->parent);
container_set_dirty(container);
container_set_dirty(container->parent); // for focused_inactive_child
if (last_focus) {
container_set_dirty(last_focus);
}
}
// If we've focused a floating container, bring it to the front.
@ -717,10 +721,6 @@ void seat_set_focus_warp(struct sway_seat *seat,
}
}
if (last_focus) {
container_damage_whole(last_focus);
}
if (last_workspace && last_workspace != new_workspace) {
cursor_send_pointer_motion(seat->cursor, 0, true);
}
@ -840,18 +840,6 @@ struct sway_container *seat_get_active_child(struct sway_seat *seat,
return NULL;
}
struct sway_container *seat_get_active_current_child(struct sway_seat *seat,
struct sway_container *container) {
struct sway_seat_container *current = NULL;
wl_list_for_each(current, &seat->focus_stack, link) {
if (current->container->current.parent == container &&
current->container->current.layout != L_FLOATING) {
return current->container;
}
}
return NULL;
}
struct sway_container *seat_get_focus(struct sway_seat *seat) {
if (!seat->has_focus) {
return NULL;

View file

@ -18,6 +18,7 @@
#include <wayland-server.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/desktop/transaction.h"
#include "sway/ipc-json.h"
#include "sway/ipc-server.h"
#include "sway/output.h"
@ -484,6 +485,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
case IPC_COMMAND:
{
struct cmd_results *results = execute_command(buf, NULL);
transaction_commit_dirty();
char *json = cmd_results_to_json(results);
int length = strlen(json);
client_valid = ipc_send_reply(client, json, (uint32_t)length);

View file

@ -20,6 +20,7 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/debug.h"
#include "sway/desktop/transaction.h"
#include "sway/server.h"
#include "sway/tree/layout.h"
#include "sway/ipc-server.h"
@ -441,6 +442,7 @@ int main(int argc, char **argv) {
free(line);
list_del(config->cmd_queue, 0);
}
transaction_commit_dirty();
if (!terminate_request) {
server_run(&server);