river: remove opacity command

This code is complex and increases maintenance burden but doesn't
add any functionality, only eye-candy.

Futhermore, neither I nor any of the core contributors use it.

There may be a place in river for such eye-candy down the line, in which
case this code could be revived. Currently river is early enough in its
development that our focus should be on core functionality instead.
This commit is contained in:
Isaac Freund
2021-07-15 13:39:20 +02:00
parent b6212ba972
commit 96e1082156
13 changed files with 6 additions and 240 deletions

View File

@ -76,19 +76,6 @@ default_layout_namespace: []const u8 = &[0]u8{},
/// Determines where new views will be attached to the view stack.
attach_mode: AttachMode = .top,
opacity: struct {
/// The opacity of focused views
focused: f32 = 1.0,
/// The opacity of unfocused views
unfocused: f32 = 1.0,
/// The initial opacity of new views
initial: f32 = 1.0,
/// View opacity transition step
delta: f32 = 1.0,
/// Time between view opacity transition steps in milliseconds
delta_t: u31 = 20,
} = .{},
/// Keyboard repeat rate in characters per second
repeat_rate: u31 = 25,

View File

@ -399,8 +399,6 @@ fn commitTransaction(self: *Self) void {
view.current = view.pending;
view.dropSavedBuffers();
view.commitOpacityTransition();
}
if (view_tags_changed) output.sendViewTags();

View File

@ -199,12 +199,7 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
switch (self.focused) {
.view => |view| {
view.pending.focus -= 1;
if (view.pending.focus == 0) {
view.setActivated(false);
if (!view.pending.fullscreen) {
view.pending.target_opacity = server.config.opacity.unfocused;
}
}
if (view.pending.focus == 0) view.setActivated(false);
},
.layer, .none => {},
}
@ -213,12 +208,7 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
switch (new_focus) {
.view => |target_view| {
std.debug.assert(self.focused_output == target_view.output);
if (target_view.pending.focus == 0) {
target_view.setActivated(true);
if (!target_view.pending.fullscreen) {
target_view.pending.target_opacity = server.config.opacity.focused;
}
}
if (target_view.pending.focus == 0) target_view.setActivated(true);
target_view.pending.focus += 1;
},
.layer => |target_layer| std.debug.assert(self.focused_output == target_layer.output),

View File

@ -71,9 +71,6 @@ const State = struct {
float: bool = false,
fullscreen: bool = false,
/// Opacity the view is transitioning to
target_opacity: f32,
};
const SavedBuffer = struct {
@ -124,12 +121,6 @@ float_box: Box = undefined,
/// and for more intuitive behavior if there is no active layout for the output.
post_fullscreen_box: Box = undefined,
/// The current opacity of this view
opacity: f32,
/// Opacity change timer event source
opacity_timer: ?*wl.EventSource = null,
draw_borders: bool = true,
/// This is created when the view is mapped and destroyed with the view
@ -144,16 +135,9 @@ foreign_close: wl.Listener(*wlr.ForeignToplevelHandleV1) =
pub fn init(self: *Self, output: *Output, tags: u32, surface: anytype) void {
self.* = .{
.output = output,
.current = .{
.tags = tags,
.target_opacity = server.config.opacity.initial,
},
.pending = .{
.tags = tags,
.target_opacity = server.config.opacity.initial,
},
.current = .{ .tags = tags },
.pending = .{ .tags = tags },
.saved_buffers = std.ArrayList(SavedBuffer).init(util.gpa),
.opacity = server.config.opacity.initial,
};
if (@TypeOf(surface) == *wlr.XdgSurface) {
@ -213,7 +197,6 @@ pub fn applyPending(self: *Self) void {
self.setFullscreen(true);
self.post_fullscreen_box = self.current.box;
self.pending.target_opacity = 1.0;
const layout_box = server.root.output_layout.getBox(self.output.wlr_output).?;
self.pending.box = .{
.x = 0,
@ -226,12 +209,6 @@ pub fn applyPending(self: *Self) void {
if (self.current.fullscreen and !self.pending.fullscreen) {
self.setFullscreen(false);
self.pending.box = self.post_fullscreen_box;
// Restore configured opacity
self.pending.target_opacity = if (self.pending.focus > 0)
server.config.opacity.focused
else
server.config.opacity.unfocused;
}
if (arrange_output) self.output.arrangeViews();
@ -449,8 +426,6 @@ pub fn shouldTrackConfigure(self: Self) bool {
/// Called by the impl when the surface is ready to be displayed
pub fn map(self: *Self) void {
self.pending.target_opacity = server.config.opacity.unfocused;
log.debug("view '{s}' mapped", .{self.getTitle()});
if (self.foreign_toplevel_handle == null) {
@ -499,10 +474,6 @@ pub fn unmap(self: *Self) void {
if (self.saved_buffers.items.len == 0) self.saveBuffers();
if (self.opacity_timer != null) {
self.killOpacityTimer();
}
// Inform all seats that the view has been unmapped so they can handle focus
var it = server.input_manager.seats.first;
while (it) |node| : (it = node.next) {
@ -540,69 +511,6 @@ pub fn notifyAppId(self: Self) void {
}
}
/// Change the opacity of a view by config.opacity.delta.
/// If the target opacity was reached, return true.
fn incrementOpacity(self: *Self) bool {
self.output.damage.addWhole();
if (self.opacity < self.current.target_opacity) {
self.opacity += server.config.opacity.delta;
if (self.opacity < self.current.target_opacity) return false;
} else {
self.opacity -= server.config.opacity.delta;
if (self.opacity > self.current.target_opacity) return false;
}
self.opacity = self.current.target_opacity;
return true;
}
/// Destroy a views opacity timer
fn killOpacityTimer(self: *Self) void {
self.opacity_timer.?.remove();
self.opacity_timer = null;
}
/// Set the timeout on a views opacity timer
fn armOpacityTimer(self: *Self) void {
const delta_t = server.config.opacity.delta_t;
self.opacity_timer.?.timerUpdate(delta_t) catch |err| {
log.err("failed to update opacity timer: {s}", .{err});
self.killOpacityTimer();
};
}
/// Called by the opacity timer
fn handleOpacityTimer(self: *Self) callconv(.C) c_int {
if (self.incrementOpacity()) {
self.killOpacityTimer();
} else {
self.armOpacityTimer();
}
return 0;
}
/// Create an opacity timer for a view and arm it
fn attachOpacityTimer(self: *Self) void {
const event_loop = server.wl_server.getEventLoop();
self.opacity_timer = event_loop.addTimer(*Self, handleOpacityTimer, self) catch {
log.err("failed to create opacity timer for view '{s}'", .{self.getTitle()});
return;
};
self.armOpacityTimer();
}
/// Commit an opacity transition
pub fn commitOpacityTransition(self: *Self) void {
if (self.opacity == self.current.target_opacity) return;
// A running timer can handle a target_opacity change
if (self.opacity_timer != null) return;
// Do the first step now, if that step was not enough, attach timer
if (!self.incrementOpacity()) {
self.attachOpacityTimer();
}
}
/// Only honors the request if the view is already visible on the seat's
/// currently focused output. TODO: consider allowing this request to switch
/// output/tag focus.

View File

@ -280,7 +280,6 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) voi
} else {
const self_tags_changed = view.pending.tags != view.current.tags;
view.current = view.pending;
view.commitOpacityTransition();
if (self_tags_changed) view.output.sendViewTags();
view.output.damage.addWhole();
}

View File

@ -66,7 +66,6 @@ const str_to_impl_fn = [_]struct {
.{ .name = "map-pointer", .impl = @import("command/map.zig").mapPointer },
.{ .name = "mod-layout-value", .impl = @import("command/layout.zig").modLayoutValue },
.{ .name = "move", .impl = @import("command/move.zig").move },
.{ .name = "opacity", .impl = @import("command/opacity.zig").opacity },
.{ .name = "output-layout", .impl = @import("command/layout.zig").outputLayout },
.{ .name = "resize", .impl = @import("command/move.zig").resize },
.{ .name = "send-to-output", .impl = @import("command/output.zig").sendToOutput },

View File

@ -1,79 +0,0 @@
// This file is part of river, a dynamic tiling wayland compositor.
//
// Copyright 2020 The River Developers
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
const std = @import("std");
const server = &@import("../main.zig").server;
const Error = @import("../command.zig").Error;
const Seat = @import("../Seat.zig");
const View = @import("../View.zig");
const ViewStack = @import("../view_stack.zig").ViewStack;
fn opacityUpdateFilter(view: *View, context: void) bool {
// We want to update all views
return true;
}
pub fn opacity(
allocator: *std.mem.Allocator,
seat: *Seat,
args: []const [:0]const u8,
out: *?[]const u8,
) Error!void {
if (args.len < 6) return Error.NotEnoughArguments;
if (args.len > 6) return Error.TooManyArguments;
// Focused opacity
server.config.opacity.focused = try std.fmt.parseFloat(f32, args[1]);
if (server.config.opacity.focused < 0.0 or server.config.opacity.focused > 1.0)
return Error.InvalidValue;
// Unfocused opacity
server.config.opacity.unfocused = try std.fmt.parseFloat(f32, args[2]);
if (server.config.opacity.unfocused < 0.0 or server.config.opacity.unfocused > 1.0)
return Error.InvalidValue;
// Starting opacity for new views
server.config.opacity.initial = try std.fmt.parseFloat(f32, args[3]);
if (server.config.opacity.initial < 0.0 or server.config.opacity.initial > 1.0)
return Error.InvalidValue;
// Opacity transition step
server.config.opacity.delta = try std.fmt.parseFloat(f32, args[4]);
if (server.config.opacity.delta < 0.0 or server.config.opacity.delta > 1.0)
return Error.InvalidValue;
// Time between step
server.config.opacity.delta_t = try std.fmt.parseInt(u31, args[5], 10);
if (server.config.opacity.delta_t < 1) return Error.InvalidValue;
// Update opacity of all views
// Unmapped views will be skipped, however their opacity gets updated on map anyway
var oit = server.root.outputs.first;
while (oit) |onode| : (oit = onode.next) {
var vit = ViewStack(View).iter(onode.data.views.first, .forward, {}, opacityUpdateFilter);
while (vit.next()) |vnode| {
if (vnode.current.focus > 0) {
vnode.pending.target_opacity = server.config.opacity.focused;
} else {
vnode.pending.target_opacity = server.config.opacity.unfocused;
}
}
}
server.root.startTransaction();
}

View File

@ -43,8 +43,6 @@ const SurfaceRenderData = struct {
output_y: i32,
when: *os.timespec,
opacity: f32,
};
/// The rendering order in this function must be kept in sync with Cursor.surfaceAt()
@ -186,7 +184,6 @@ fn renderLayer(
.output_x = layer_surface.box.x,
.output_y = layer_surface.box.y,
.when = now,
.opacity = 1.0,
};
switch (role) {
.toplevels => layer_surface.wlr_layer_surface.surface.forEachSurface(
@ -218,7 +215,6 @@ fn renderView(output: *const Output, view: *View, now: *os.timespec) void {
.height = @intCast(c_int, saved_buffer.box.height),
},
saved_buffer.transform,
view.opacity,
);
} else {
// Since there is no stashed buffer, we are not in the middle of
@ -228,7 +224,6 @@ fn renderView(output: *const Output, view: *View, now: *os.timespec) void {
.output_x = view.current.box.x - view.surface_box.x,
.output_y = view.current.box.y - view.surface_box.y,
.when = now,
.opacity = view.opacity,
};
view.surface.?.forEachSurface(*SurfaceRenderData, renderSurfaceIterator, &rdata);
@ -241,7 +236,6 @@ fn renderViewPopups(output: *const Output, view: *View, now: *os.timespec) void
.output_x = view.current.box.x - view.surface_box.x,
.output_y = view.current.box.y - view.surface_box.y,
.when = now,
.opacity = view.opacity,
};
view.forEachPopupSurface(*SurfaceRenderData, renderSurfaceIterator, &rdata);
}
@ -260,7 +254,6 @@ fn renderDragIcons(output: *const Output, now: *os.timespec) void {
.output_y = @floatToInt(i32, drag_icon.seat.cursor.wlr_cursor.y) +
drag_icon.wlr_drag_icon.surface.sy - output_box.y,
.when = now,
.opacity = 1.0,
};
drag_icon.wlr_drag_icon.surface.forEachSurface(*SurfaceRenderData, renderSurfaceIterator, &rdata);
}
@ -279,7 +272,6 @@ fn renderXwaylandUnmanaged(output: *const Output, now: *os.timespec) void {
.output_x = xwayland_surface.x - output_box.x,
.output_y = xwayland_surface.y - output_box.y,
.when = now,
.opacity = 1.0,
};
xwayland_surface.surface.?.forEachSurface(*SurfaceRenderData, renderSurfaceIterator, &rdata);
}
@ -302,7 +294,6 @@ fn renderSurfaceIterator(
.height = surface.current.height,
},
surface.current.transform,
rdata.opacity,
);
surface.sendFrameDone(rdata.when);
@ -315,7 +306,6 @@ fn renderTexture(
texture: *wlr.Texture,
wlr_box: wlr.Box,
transform: wl.Output.Transform,
opacity: f32,
) void {
var box = wlr_box;
@ -333,7 +323,7 @@ fn renderTexture(
// This takes our matrix, the texture, and an alpha, and performs the actual
// rendering on the GPU.
const renderer = output.wlr_output.backend.getRenderer().?;
renderer.renderTextureWithMatrix(texture, &matrix, opacity) catch return;
renderer.renderTextureWithMatrix(texture, &matrix, 1.0) catch return;
}
fn renderBorders(output: *const Output, view: *View, now: *os.timespec) void {