seat: set focus before starting transactions

Focus was made double-buffered in 96a91fd. However, much of the code
still behaved as if focus was separate from the transaction system.
This commit completes the work started in 96a91fd and ensures that
focus is applied consistently in a single transaction.
This commit is contained in:
Isaac Freund 2020-08-12 11:07:29 +02:00
parent bd99428766
commit 7a6ac8eb6e
9 changed files with 36 additions and 29 deletions

View File

@ -48,9 +48,14 @@ const Mode = union(enum) {
fn enter(self: *Self, mode: @TagType(Mode), event: *c.wlr_event_pointer_button, view: *View) void { fn enter(self: *Self, mode: @TagType(Mode), event: *c.wlr_event_pointer_button, view: *View) void {
log.debug(.cursor, "enter {} mode", .{@tagName(mode)}); log.debug(.cursor, "enter {} mode", .{@tagName(mode)});
self.seat.focus(view);
switch (mode) { switch (mode) {
.passthrough => unreachable, .passthrough => unreachable,
.down => self.mode = .{ .down = view }, .down => {
self.mode = .{ .down = view };
view.output.root.startTransaction();
},
.move, .resize => { .move, .resize => {
const cur_box = &view.current.box; const cur_box = &view.current.box;
self.mode = switch (mode) { self.mode = switch (mode) {
@ -366,8 +371,6 @@ fn handleButton(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
// If the target surface has a view, give that view keyboard focus and // If the target surface has a view, give that view keyboard focus and
// perhaps enter move/resize mode. // perhaps enter move/resize mode.
if (View.fromWlrSurface(wlr_surface)) |view| { if (View.fromWlrSurface(wlr_surface)) |view| {
self.seat.focus(view);
if (event.state == .WLR_BUTTON_PRESSED and self.pressed_count == 1) { if (event.state == .WLR_BUTTON_PRESSED and self.pressed_count == 1) {
// If the button is pressed and the pointer modifier is // If the button is pressed and the pointer modifier is
// active, enter cursor mode or close view and return. // active, enter cursor mode or close view and return.

View File

@ -149,6 +149,8 @@ fn handleInhibitDeactivate(listener: ?*c.wl_listener, data: ?*c_void) callconv(.
while (seat_it) |seat_node| : (seat_it = seat_node.next) { while (seat_it) |seat_node| : (seat_it = seat_node.next) {
seat_node.data.focus(null); seat_node.data.focus(null);
} }
self.server.root.startTransaction();
} }
/// This event is raised by the backend when a new input device becomes available. /// This event is raised by the backend when a new input device becomes available.

View File

@ -154,6 +154,8 @@ fn handleUnmap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
const seat = &node.data; const seat = &node.data;
seat.focus(null); seat.focus(null);
} }
self.output.root.startTransaction();
} }
fn handleCommit(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { fn handleCommit(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
@ -181,6 +183,7 @@ fn handleCommit(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
// TODO: only reconfigure if things haven't changed // TODO: only reconfigure if things haven't changed
// https://github.com/swaywm/wlroots/issues/1079 // https://github.com/swaywm/wlroots/issues/1079
self.output.arrangeLayers(); self.output.arrangeLayers();
self.output.root.startTransaction();
} }
fn handleNewPopup(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { fn handleNewPopup(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {

View File

@ -304,7 +304,7 @@ pub fn arrangeViews(self: *Self) void {
var it = ViewStack(View).pendingIterator(self.views.first, self.pending.tags); var it = ViewStack(View).pendingIterator(self.views.first, self.pending.tags);
while (it.next()) |node| { while (it.next()) |node| {
const view = &node.view; const view = &node.view;
if (!view.pending.float) layout_count += 1; if (!view.pending.float and !view.pending.fullscreen) layout_count += 1;
} }
// If the usable area has a zero dimension, trying to arrange the layout // If the usable area has a zero dimension, trying to arrange the layout
@ -394,8 +394,6 @@ pub fn arrangeLayers(self: *Self) void {
} }
} }
} }
self.root.startTransaction();
} }
/// Arrange the layer surfaces of a given layer /// Arrange the layer surfaces of a given layer
@ -585,7 +583,7 @@ fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
while (seat_it) |seat_node| : (seat_it = seat_node.next) { while (seat_it) |seat_node| : (seat_it = seat_node.next) {
const seat = &seat_node.data; const seat = &seat_node.data;
if (seat.focused_output == self) { if (seat.focused_output == self) {
seat.focusOutput(self); seat.focusOutput(fallback_output);
seat.focus(null); seat.focus(null);
} }
} }

View File

@ -241,8 +241,4 @@ fn commitTransaction(self: *Self) void {
if (view_tags_changed) output.sendViewTags(); if (view_tags_changed) output.sendViewTags();
} }
// Iterate over all seats and update focus
var it = self.server.input_manager.seats.first;
while (it) |seat_node| : (it = seat_node.next) seat_node.data.focus(null);
} }

View File

@ -120,21 +120,21 @@ pub fn focus(self: *Self, _view: ?*View) void {
// If the view is not currently visible, behave as if null was passed // If the view is not currently visible, behave as if null was passed
if (view) |v| { if (view) |v| {
if (v.output != self.focused_output or if (v.output != self.focused_output or
v.current.tags & self.focused_output.current.tags == 0) view = null; v.pending.tags & self.focused_output.pending.tags == 0) view = null;
} }
// If the target view is not fullscreen or null, then a fullscreen view // If the target view is not fullscreen or null, then a fullscreen view
// will grab focus if visible. // will grab focus if visible.
if (if (view) |v| !v.current.fullscreen else true) { if (if (view) |v| !v.pending.fullscreen else true) {
var it = ViewStack(*View).iterator(self.focus_stack.first, self.focused_output.current.tags); var it = ViewStack(*View).pendingIterator(self.focus_stack.first, self.focused_output.pending.tags);
view = while (it.next()) |node| { view = while (it.next()) |node| {
if (node.view.output == self.focused_output and node.view.current.fullscreen) break node.view; if (node.view.output == self.focused_output and node.view.pending.fullscreen) break node.view;
} else view; } else view;
} }
if (view == null) { if (view == null) {
// Set view to the first currently visible view in the focus stack if any // Set view to the first currently visible view in the focus stack if any
var it = ViewStack(*View).iterator(self.focus_stack.first, self.focused_output.current.tags); var it = ViewStack(*View).pendingIterator(self.focus_stack.first, self.focused_output.pending.tags);
view = while (it.next()) |node| { view = while (it.next()) |node| {
if (node.view.output == self.focused_output) break node.view; if (node.view.output == self.focused_output) break node.view;
} else null; } else null;
@ -223,9 +223,6 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
// Inform any clients tracking status of the change // Inform any clients tracking status of the change
var it = self.status_trackers.first; var it = self.status_trackers.first;
while (it) |node| : (it = node.next) node.data.sendFocusedView(); while (it) |node| : (it = node.next) node.data.sendFocusedView();
// Start a transaction to apply the pending focus state
self.input_manager.server.root.startTransaction();
} }
/// Focus the given output, notifying any listening clients of the change. /// Focus the given output, notifying any listening clients of the change.

View File

@ -351,7 +351,8 @@ pub fn map(self: *Self) void {
self.output.sendViewTags(); self.output.sendViewTags();
self.output.arrangeViews(); if (!self.current.float) self.output.arrangeViews();
self.output.root.startTransaction(); self.output.root.startTransaction();
} }
@ -377,10 +378,9 @@ pub fn unmap(self: *Self) void {
self.output.sendViewTags(); self.output.sendViewTags();
// Still need to arrange if fullscreened from the layout // Still need to arrange if fullscreened from the layout
if (!self.current.float) { if (!self.current.float) self.output.arrangeViews();
self.output.arrangeViews();
root.startTransaction(); root.startTransaction();
}
} }
/// Destory the view and free the ViewStack node holding it. /// Destory the view and free the ViewStack node holding it.

View File

@ -53,6 +53,7 @@ pub fn focusView(
// Focus the next visible node if there is one // Focus the next visible node if there is one
if (it.next()) |node| { if (it.next()) |node| {
seat.focus(&node.view); seat.focus(&node.view);
output.root.startTransaction();
return; return;
} }
} }
@ -65,4 +66,5 @@ pub fn focusView(
}; };
seat.focus(if (it.next()) |node| &node.view else null); seat.focus(if (it.next()) |node| &node.view else null);
output.root.startTransaction();
} }

View File

@ -31,6 +31,7 @@ pub fn setFocusedTags(
if (seat.focused_output.pending.tags != tags) { if (seat.focused_output.pending.tags != tags) {
seat.focused_output.pending.tags = tags; seat.focused_output.pending.tags = tags;
seat.focused_output.arrangeViews(); seat.focused_output.arrangeViews();
seat.focus(null);
seat.focused_output.root.startTransaction(); seat.focused_output.root.startTransaction();
} }
} }
@ -44,8 +45,10 @@ pub fn setViewTags(
) Error!void { ) Error!void {
const tags = try parseTags(allocator, args, out); const tags = try parseTags(allocator, args, out);
if (seat.focused == .view) { if (seat.focused == .view) {
seat.focused.view.pending.tags = tags; const view = seat.focused.view;
seat.focused.view.applyPending(); view.pending.tags = tags;
seat.focus(null);
view.applyPending();
} }
} }
@ -62,6 +65,7 @@ pub fn toggleFocusedTags(
if (new_focused_tags != 0) { if (new_focused_tags != 0) {
output.pending.tags = new_focused_tags; output.pending.tags = new_focused_tags;
output.arrangeViews(); output.arrangeViews();
seat.focus(null);
output.root.startTransaction(); output.root.startTransaction();
} }
} }
@ -75,10 +79,12 @@ pub fn toggleViewTags(
) Error!void { ) Error!void {
const tags = try parseTags(allocator, args, out); const tags = try parseTags(allocator, args, out);
if (seat.focused == .view) { if (seat.focused == .view) {
const new_tags = seat.focused.view.current.tags ^ tags; const new_tags = seat.focused.view.pending.tags ^ tags;
if (new_tags != 0) { if (new_tags != 0) {
seat.focused.view.pending.tags = new_tags; const view = seat.focused.view;
seat.focused.view.applyPending(); view.pending.tags = new_tags;
seat.focus(null);
view.applyPending();
} }
} }
} }