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:
parent
53e3f35ba3
commit
a120d4c79f
|
@ -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 *seat_get_active_child(struct sway_seat *seat,
|
||||||
struct sway_container *container);
|
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
|
* Iterate over the focus-inactive children of the container calling the
|
||||||
* function on each.
|
* function on each.
|
||||||
|
|
|
@ -68,6 +68,9 @@ struct sway_container_state {
|
||||||
struct sway_container *parent;
|
struct sway_container *parent;
|
||||||
list_t *children;
|
list_t *children;
|
||||||
|
|
||||||
|
struct sway_container *focused_inactive_child;
|
||||||
|
bool focused;
|
||||||
|
|
||||||
// View properties
|
// View properties
|
||||||
double view_x, view_y;
|
double view_x, view_y;
|
||||||
double view_width, view_height;
|
double view_width, view_height;
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/criteria.h"
|
#include "sway/criteria.h"
|
||||||
#include "sway/desktop/transaction.h"
|
|
||||||
#include "sway/security.h"
|
#include "sway/security.h"
|
||||||
#include "sway/input/input-manager.h"
|
#include "sway/input/input-manager.h"
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
|
@ -323,7 +322,6 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
|
||||||
cleanup:
|
cleanup:
|
||||||
free(exec);
|
free(exec);
|
||||||
free(views);
|
free(views);
|
||||||
transaction_commit_dirty();
|
|
||||||
if (!results) {
|
if (!results) {
|
||||||
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -543,9 +543,6 @@ static void render_container(struct sway_output *output,
|
||||||
static void render_container_simple(struct sway_output *output,
|
static void render_container_simple(struct sway_output *output,
|
||||||
pixman_region32_t *damage, struct sway_container *con,
|
pixman_region32_t *damage, struct sway_container *con,
|
||||||
bool parent_focused) {
|
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) {
|
for (int i = 0; i < con->current.children->length; ++i) {
|
||||||
struct sway_container *child = con->current.children->items[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 wlr_texture *marks_texture;
|
||||||
struct sway_container_state *state = &child->current;
|
struct sway_container_state *state = &child->current;
|
||||||
|
|
||||||
if (focus == child || parent_focused) {
|
if (state->focused || parent_focused) {
|
||||||
colors = &config->border_colors.focused;
|
colors = &config->border_colors.focused;
|
||||||
title_texture = child->title_focused;
|
title_texture = child->title_focused;
|
||||||
marks_texture = view->marks_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;
|
colors = &config->border_colors.focused_inactive;
|
||||||
title_texture = child->title_focused_inactive;
|
title_texture = child->title_focused_inactive;
|
||||||
marks_texture = view->marks_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);
|
render_view(output, damage, child, colors);
|
||||||
} else {
|
} else {
|
||||||
render_container(output, damage, child,
|
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) {
|
if (!con->current.children->length) {
|
||||||
return;
|
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_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;
|
double width_gap_adjustment = 2 * pstate->current_gaps;
|
||||||
int tab_width =
|
int tab_width =
|
||||||
|
@ -613,11 +608,11 @@ static void render_container_tabbed(struct sway_output *output,
|
||||||
struct wlr_texture *title_texture;
|
struct wlr_texture *title_texture;
|
||||||
struct wlr_texture *marks_texture;
|
struct wlr_texture *marks_texture;
|
||||||
|
|
||||||
if (focus == child || parent_focused) {
|
if (cstate->focused || parent_focused) {
|
||||||
colors = &config->border_colors.focused;
|
colors = &config->border_colors.focused;
|
||||||
title_texture = child->title_focused;
|
title_texture = child->title_focused;
|
||||||
marks_texture = view ? view->marks_focused : NULL;
|
marks_texture = view ? view->marks_focused : NULL;
|
||||||
} else if (child == current) {
|
} else if (child == pstate->focused_inactive_child) {
|
||||||
colors = &config->border_colors.focused_inactive;
|
colors = &config->border_colors.focused_inactive;
|
||||||
title_texture = child->title_focused_inactive;
|
title_texture = child->title_focused_inactive;
|
||||||
marks_texture = view ? view->marks_focused_inactive : NULL;
|
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
|
// Render surface and left/right/bottom borders
|
||||||
if (current) {
|
if (current->type == C_VIEW) {
|
||||||
if (current->type == C_VIEW) {
|
render_view(output, damage, current, current_colors);
|
||||||
render_view(output, damage, current, current_colors);
|
} else {
|
||||||
} else {
|
render_container(output, damage, current,
|
||||||
render_container(output, damage, current,
|
parent_focused || current->current.focused);
|
||||||
parent_focused || current == focus);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,11 +656,9 @@ static void render_container_stacked(struct sway_output *output,
|
||||||
if (!con->current.children->length) {
|
if (!con->current.children->length) {
|
||||||
return;
|
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_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();
|
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 *title_texture;
|
||||||
struct wlr_texture *marks_texture;
|
struct wlr_texture *marks_texture;
|
||||||
|
|
||||||
if (focus == child || parent_focused) {
|
if (cstate->focused || parent_focused) {
|
||||||
colors = &config->border_colors.focused;
|
colors = &config->border_colors.focused;
|
||||||
title_texture = child->title_focused;
|
title_texture = child->title_focused;
|
||||||
marks_texture = view ? view->marks_focused : NULL;
|
marks_texture = view ? view->marks_focused : NULL;
|
||||||
} else if (child == current) {
|
} else if (child == pstate->focused_inactive_child) {
|
||||||
colors = &config->border_colors.focused_inactive;
|
colors = &config->border_colors.focused_inactive;
|
||||||
title_texture = child->title_focused_inactive;
|
title_texture = child->title_focused_inactive;
|
||||||
marks_texture = view ? view->marks_focused_inactive : NULL;
|
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
|
// Render surface and left/right/bottom borders
|
||||||
if (current) {
|
if (current->type == C_VIEW) {
|
||||||
if (current->type == C_VIEW) {
|
render_view(output, damage, current, current_colors);
|
||||||
render_view(output, damage, current, current_colors);
|
} else {
|
||||||
} else {
|
render_container(output, damage, current,
|
||||||
render_container(output, damage, current,
|
parent_focused || current->current.focused);
|
||||||
parent_focused || current == focus);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -738,13 +727,11 @@ static void render_floating_container(struct sway_output *soutput,
|
||||||
pixman_region32_t *damage, struct sway_container *con) {
|
pixman_region32_t *damage, struct sway_container *con) {
|
||||||
if (con->type == C_VIEW) {
|
if (con->type == C_VIEW) {
|
||||||
struct sway_view *view = con->sway_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 border_colors *colors;
|
||||||
struct wlr_texture *title_texture;
|
struct wlr_texture *title_texture;
|
||||||
struct wlr_texture *marks_texture;
|
struct wlr_texture *marks_texture;
|
||||||
|
|
||||||
if (focus == con) {
|
if (con->current.focused) {
|
||||||
colors = &config->border_colors.focused;
|
colors = &config->border_colors.focused;
|
||||||
title_texture = con->title_focused;
|
title_texture = con->title_focused;
|
||||||
marks_texture = view->marks_focused;
|
marks_texture = view->marks_focused;
|
||||||
|
@ -871,9 +858,7 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
render_layer(output, damage,
|
render_layer(output, damage,
|
||||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
|
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
|
||||||
|
|
||||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
render_container(output, damage, workspace, workspace->current.focused);
|
||||||
struct sway_container *focus = seat_get_focus(seat);
|
|
||||||
render_container(output, damage, workspace, focus == workspace);
|
|
||||||
render_floating(output, damage);
|
render_floating(output, damage);
|
||||||
|
|
||||||
render_unmanaged(output, damage,
|
render_unmanaged(output, damage,
|
||||||
|
|
|
@ -139,6 +139,14 @@ static void copy_pending_state(struct sway_container *container,
|
||||||
state->children = create_list();
|
state->children = create_list();
|
||||||
list_cat(state->children, container->children);
|
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,
|
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,
|
.width = instruction->state.swayc_width,
|
||||||
.height = instruction->state.swayc_height,
|
.height = instruction->state.swayc_height,
|
||||||
};
|
};
|
||||||
for (int j = 0; j < root_container.children->length; ++j) {
|
for (int j = 0; j < root_container.current.children->length; ++j) {
|
||||||
struct sway_container *output = root_container.children->items[j];
|
struct sway_container *output = root_container.current.children->items[j];
|
||||||
output_damage_box(output->sway_output, &old_box);
|
if (output->sway_output) {
|
||||||
output_damage_box(output->sway_output, &new_box);
|
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
|
// There are separate children lists for each instruction state, the
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <wlr/types/wlr_idle.h>
|
#include <wlr/types/wlr_idle.h>
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "sway/desktop/transaction.h"
|
||||||
#include "sway/input/cursor.h"
|
#include "sway/input/cursor.h"
|
||||||
#include "sway/layers.h"
|
#include "sway/layers.h"
|
||||||
#include "sway/output.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;
|
struct sway_drag_icon *drag_icon = wlr_drag_icon->data;
|
||||||
drag_icon_update_position(drag_icon);
|
drag_icon_update_position(drag_icon);
|
||||||
}
|
}
|
||||||
|
transaction_commit_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_cursor_motion(struct wl_listener *listener, void *data) {
|
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,
|
wlr_seat_pointer_notify_button(cursor->seat->wlr_seat,
|
||||||
time_msec, button, state);
|
time_msec, button, state);
|
||||||
|
transaction_commit_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_cursor_button(struct wl_listener *listener, void *data) {
|
static void handle_cursor_button(struct wl_listener *listener, void *data) {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <wlr/backend/multi.h>
|
#include <wlr/backend/multi.h>
|
||||||
#include <wlr/backend/session.h>
|
#include <wlr/backend/session.h>
|
||||||
#include <wlr/types/wlr_idle.h>
|
#include <wlr/types/wlr_idle.h>
|
||||||
|
#include "sway/desktop/transaction.h"
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
#include "sway/input/keyboard.h"
|
#include "sway/input/keyboard.h"
|
||||||
#include "sway/input/input-manager.h"
|
#include "sway/input/input-manager.h"
|
||||||
|
@ -126,6 +127,7 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard,
|
||||||
binding->command);
|
binding->command);
|
||||||
config->handler_context.seat = keyboard->seat_device->sway_seat;
|
config->handler_context.seat = keyboard->seat_device->sway_seat;
|
||||||
struct cmd_results *results = execute_command(binding->command, NULL);
|
struct cmd_results *results = execute_command(binding->command, NULL);
|
||||||
|
transaction_commit_dirty();
|
||||||
if (results->status != CMD_SUCCESS) {
|
if (results->status != CMD_SUCCESS) {
|
||||||
wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
|
wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
|
||||||
binding->command, results->error);
|
binding->command, results->error);
|
||||||
|
|
|
@ -661,9 +661,13 @@ void seat_set_focus_warp(struct sway_seat *seat,
|
||||||
if (last_focus) {
|
if (last_focus) {
|
||||||
seat_send_unfocus(last_focus, seat);
|
seat_send_unfocus(last_focus, seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
seat_send_focus(container, 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.
|
// 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) {
|
if (last_workspace && last_workspace != new_workspace) {
|
||||||
cursor_send_pointer_motion(seat->cursor, 0, true);
|
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;
|
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) {
|
struct sway_container *seat_get_focus(struct sway_seat *seat) {
|
||||||
if (!seat->has_focus) {
|
if (!seat->has_focus) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <wayland-server.h>
|
#include <wayland-server.h>
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
|
#include "sway/desktop/transaction.h"
|
||||||
#include "sway/ipc-json.h"
|
#include "sway/ipc-json.h"
|
||||||
#include "sway/ipc-server.h"
|
#include "sway/ipc-server.h"
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
|
@ -484,6 +485,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
||||||
case IPC_COMMAND:
|
case IPC_COMMAND:
|
||||||
{
|
{
|
||||||
struct cmd_results *results = execute_command(buf, NULL);
|
struct cmd_results *results = execute_command(buf, NULL);
|
||||||
|
transaction_commit_dirty();
|
||||||
char *json = cmd_results_to_json(results);
|
char *json = cmd_results_to_json(results);
|
||||||
int length = strlen(json);
|
int length = strlen(json);
|
||||||
client_valid = ipc_send_reply(client, json, (uint32_t)length);
|
client_valid = ipc_send_reply(client, json, (uint32_t)length);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/debug.h"
|
#include "sway/debug.h"
|
||||||
|
#include "sway/desktop/transaction.h"
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
#include "sway/tree/layout.h"
|
#include "sway/tree/layout.h"
|
||||||
#include "sway/ipc-server.h"
|
#include "sway/ipc-server.h"
|
||||||
|
@ -441,6 +442,7 @@ int main(int argc, char **argv) {
|
||||||
free(line);
|
free(line);
|
||||||
list_del(config->cmd_queue, 0);
|
list_del(config->cmd_queue, 0);
|
||||||
}
|
}
|
||||||
|
transaction_commit_dirty();
|
||||||
|
|
||||||
if (!terminate_request) {
|
if (!terminate_request) {
|
||||||
server_run(&server);
|
server_run(&server);
|
||||||
|
|
Loading…
Reference in a new issue