Implement configurable view opacity with fade effect
This commit is contained in:
parent
27b666dbba
commit
b67ea748a3
@ -100,3 +100,5 @@ riverctl float-filter-add "popup"
|
|||||||
# Set app-ids of views which should use client side decorations
|
# Set app-ids of views which should use client side decorations
|
||||||
riverctl csd-filter-add "gedit"
|
riverctl csd-filter-add "gedit"
|
||||||
|
|
||||||
|
# Set opacity and fade effect
|
||||||
|
# riverctl opacity 1.0 0.75 0.0 0.1 20
|
||||||
|
@ -162,6 +162,21 @@ that tag 1 through 9 are visible.
|
|||||||
- move-view
|
- move-view
|
||||||
- resize-view
|
- resize-view
|
||||||
|
|
||||||
|
*opacity* _focused-opacity_ _unfocused-opacity_ _starting-opacity_ _opacity-step_ _opacity-delta-t_
|
||||||
|
Set the server side opacity of views.
|
||||||
|
|
||||||
|
_focused-opacity_ sets the opacity of the focused window, _unfocused-opacity_
|
||||||
|
the opacity of every unfocused window while _starting-opacity_ sets the
|
||||||
|
opacity a window will have at startup before immediately transitioning to
|
||||||
|
either the focused or unfocused opacity. These settings require a floating
|
||||||
|
point number from 0.0 (fully transparent) to 1.0 (fully opaque).
|
||||||
|
|
||||||
|
Opacity transitions can be animated. _opacity-step_ sets the amount the
|
||||||
|
opacity should be increased or decreased per step of the transition. It
|
||||||
|
requires a floating point number from 0.05 to 1.0. If set to 1.0, animations
|
||||||
|
are disabled. _opacity-delta-t_ sets the time between the transition steps
|
||||||
|
in milliseconds.
|
||||||
|
|
||||||
*outer-padding* _pixels_
|
*outer-padding* _pixels_
|
||||||
Set the padding around the edge of the screen to _pixels_.
|
Set the padding around the edge of the screen to _pixels_.
|
||||||
|
|
||||||
|
@ -66,6 +66,21 @@ csd_filter: std.ArrayList([]const u8),
|
|||||||
/// The selected focus_follows_cursor mode
|
/// The selected focus_follows_cursor mode
|
||||||
focus_follows_cursor: FocusFollowsCursorMode = .disabled,
|
focus_follows_cursor: FocusFollowsCursorMode = .disabled,
|
||||||
|
|
||||||
|
/// The opacity of the focused view
|
||||||
|
view_opacity_focused: f32 = 1.0,
|
||||||
|
|
||||||
|
/// The opacity of unfocused views
|
||||||
|
view_opacity_unfocused: f32 = 1.0,
|
||||||
|
|
||||||
|
/// The starting opacity of new views
|
||||||
|
view_opacity_initial: f32 = 1.0,
|
||||||
|
|
||||||
|
/// View opacity transition step
|
||||||
|
view_opacity_delta: f32 = 1.0,
|
||||||
|
|
||||||
|
/// Time between view opacity transition steps in msec
|
||||||
|
view_opacity_delta_t: u31 = 20,
|
||||||
|
|
||||||
pub fn init() !Self {
|
pub fn init() !Self {
|
||||||
var self = Self{
|
var self = Self{
|
||||||
.mode_to_id = std.StringHashMap(usize).init(util.gpa),
|
.mode_to_id = std.StringHashMap(usize).init(util.gpa),
|
||||||
|
@ -250,6 +250,8 @@ fn commitTransaction(self: *Self) void {
|
|||||||
view.current = view.pending;
|
view.current = view.pending;
|
||||||
|
|
||||||
view.dropSavedBuffers();
|
view.dropSavedBuffers();
|
||||||
|
|
||||||
|
view.commitOpacityTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view_tags_changed) output.sendViewTags();
|
if (view_tags_changed) output.sendViewTags();
|
||||||
|
@ -188,6 +188,9 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
|
|||||||
// activated state.
|
// activated state.
|
||||||
if (build_options.xwayland and self.focused.view.impl == .xwayland_view)
|
if (build_options.xwayland and self.focused.view.impl == .xwayland_view)
|
||||||
c.wlr_xwayland_surface_activate(self.focused.view.impl.xwayland_view.wlr_xwayland_surface, false);
|
c.wlr_xwayland_surface_activate(self.focused.view.impl.xwayland_view.wlr_xwayland_surface, false);
|
||||||
|
if (self.focused.view.pending.focus == 0) {
|
||||||
|
self.focused.view.pending.target_opacity = self.input_manager.server.config.view_opacity_unfocused;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c.wlr_seat_keyboard_clear_focus(self.wlr_seat);
|
c.wlr_seat_keyboard_clear_focus(self.wlr_seat);
|
||||||
|
|
||||||
@ -200,6 +203,7 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
|
|||||||
// activated state.
|
// activated state.
|
||||||
if (build_options.xwayland and target_view.impl == .xwayland_view)
|
if (build_options.xwayland and target_view.impl == .xwayland_view)
|
||||||
c.wlr_xwayland_surface_activate(target_view.impl.xwayland_view.wlr_xwayland_surface, true);
|
c.wlr_xwayland_surface_activate(target_view.impl.xwayland_view.wlr_xwayland_surface, true);
|
||||||
|
target_view.pending.target_opacity = self.input_manager.server.config.view_opacity_focused;
|
||||||
},
|
},
|
||||||
.layer => |target_layer| std.debug.assert(self.focused_output == target_layer.output),
|
.layer => |target_layer| std.debug.assert(self.focused_output == target_layer.output),
|
||||||
.none => {},
|
.none => {},
|
||||||
@ -281,7 +285,7 @@ pub fn handleMapping(self: *Self, keysym: c.xkb_keysym_t, modifiers: u32, releas
|
|||||||
if (out) |s| {
|
if (out) |s| {
|
||||||
const stdout = std.io.getStdOut().outStream();
|
const stdout = std.io.getStdOut().outStream();
|
||||||
stdout.print("{}", .{s}) catch
|
stdout.print("{}", .{s}) catch
|
||||||
|err| log.err(.command, "{}: write to stdout failed {}", .{ args[0], err });
|
|err| log.err(.command, "{}: write to stdout failed {}", .{ args[0], err });
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// This file is part of river, a dynamic tiling wayland compositor.
|
// This file is part of river, a dynamic tiling wayland compositor.
|
||||||
//
|
//
|
||||||
// Copyright 2020 Isaac Freund
|
// Copyright 2020 Isaac Freund
|
||||||
|
// Copyright 2020 Leon Henrik Plickat
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
@ -65,6 +66,9 @@ const State = struct {
|
|||||||
|
|
||||||
float: bool = false,
|
float: bool = false,
|
||||||
fullscreen: bool = false,
|
fullscreen: bool = false,
|
||||||
|
|
||||||
|
/// Opacity the view is transitioning to
|
||||||
|
target_opacity: f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SavedBuffer = struct {
|
const SavedBuffer = struct {
|
||||||
@ -109,14 +113,27 @@ saved_buffers: std.ArrayList(SavedBuffer),
|
|||||||
/// view returns to floating mode.
|
/// view returns to floating mode.
|
||||||
float_box: Box = undefined,
|
float_box: Box = undefined,
|
||||||
|
|
||||||
|
/// The current opacity of this view
|
||||||
|
opacity: f32,
|
||||||
|
|
||||||
|
/// Opacity change timer event source
|
||||||
|
opacity_timer: ?*c.wl_event_source = null,
|
||||||
|
|
||||||
draw_borders: bool = true,
|
draw_borders: bool = true,
|
||||||
|
|
||||||
pub fn init(self: *Self, output: *Output, tags: u32, surface: anytype) void {
|
pub fn init(self: *Self, output: *Output, tags: u32, surface: anytype) void {
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.output = output,
|
.output = output,
|
||||||
.current = .{ .tags = tags },
|
.current = .{
|
||||||
.pending = .{ .tags = tags },
|
.tags = tags,
|
||||||
|
.target_opacity = output.root.server.config.view_opacity_initial,
|
||||||
|
},
|
||||||
|
.pending = .{
|
||||||
|
.tags = tags,
|
||||||
|
.target_opacity = output.root.server.config.view_opacity_initial,
|
||||||
|
},
|
||||||
.saved_buffers = std.ArrayList(SavedBuffer).init(util.gpa),
|
.saved_buffers = std.ArrayList(SavedBuffer).init(util.gpa),
|
||||||
|
.opacity = output.root.server.config.view_opacity_initial,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (@TypeOf(surface) == *c.wlr_xdg_surface) {
|
if (@TypeOf(surface) == *c.wlr_xdg_surface) {
|
||||||
@ -337,6 +354,8 @@ pub fn shouldTrackConfigure(self: Self) bool {
|
|||||||
pub fn map(self: *Self) void {
|
pub fn map(self: *Self) void {
|
||||||
const root = self.output.root;
|
const root = self.output.root;
|
||||||
|
|
||||||
|
self.pending.target_opacity = self.output.root.server.config.view_opacity_unfocused;
|
||||||
|
|
||||||
log.debug(.server, "view '{}' mapped", .{self.getTitle()});
|
log.debug(.server, "view '{}' mapped", .{self.getTitle()});
|
||||||
|
|
||||||
// Add the view to the stack of its output
|
// Add the view to the stack of its output
|
||||||
@ -365,6 +384,10 @@ pub fn unmap(self: *Self) void {
|
|||||||
|
|
||||||
self.destroying = true;
|
self.destroying = true;
|
||||||
|
|
||||||
|
if (self.opacity_timer != null) {
|
||||||
|
self.killOpacityTimer();
|
||||||
|
}
|
||||||
|
|
||||||
// Inform all seats that the view has been unmapped so they can handle focus
|
// Inform all seats that the view has been unmapped so they can handle focus
|
||||||
var it = root.server.input_manager.seats.first;
|
var it = root.server.input_manager.seats.first;
|
||||||
while (it) |node| : (it = node.next) {
|
while (it) |node| : (it = node.next) {
|
||||||
@ -379,3 +402,72 @@ pub fn unmap(self: *Self) void {
|
|||||||
|
|
||||||
root.startTransaction();
|
root.startTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change the opacity of a view by config.view_opacity_delta.
|
||||||
|
/// If the target opacity was reached, return true.
|
||||||
|
fn incrementOpacity(self: *Self) bool {
|
||||||
|
// TODO damage view when implementing damage based rendering
|
||||||
|
const config = &self.output.root.server.config;
|
||||||
|
if (self.opacity < self.current.target_opacity) {
|
||||||
|
self.opacity += config.view_opacity_delta;
|
||||||
|
if (self.opacity < self.current.target_opacity) return false;
|
||||||
|
} else {
|
||||||
|
self.opacity -= config.view_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 {
|
||||||
|
if (c.wl_event_source_remove(self.opacity_timer) < 0) unreachable;
|
||||||
|
self.opacity_timer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the timeout on a views opacity timer
|
||||||
|
fn armOpacityTimer(self: *Self) void {
|
||||||
|
const delta_t = self.output.root.server.config.view_opacity_delta_t;
|
||||||
|
if (c.wl_event_source_timer_update(self.opacity_timer, delta_t) < 0) {
|
||||||
|
log.err(.view, "failed to update opacity timer", .{});
|
||||||
|
self.killOpacityTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called by the opacity timer
|
||||||
|
fn handleOpacityTimer(data: ?*c_void) callconv(.C) c_int {
|
||||||
|
const self = util.voidCast(Self, data.?);
|
||||||
|
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 server = self.output.root.server;
|
||||||
|
self.opacity_timer = c.wl_event_loop_add_timer(
|
||||||
|
c.wl_display_get_event_loop(server.wl_display),
|
||||||
|
handleOpacityTimer,
|
||||||
|
self,
|
||||||
|
) orelse {
|
||||||
|
log.err(.view, "failed to create opacity timer for view '{}'", .{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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -251,8 +251,10 @@ fn handleCommit(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
|
|||||||
view.pending_serial = null;
|
view.pending_serial = null;
|
||||||
if (view.shouldTrackConfigure())
|
if (view.shouldTrackConfigure())
|
||||||
view.output.root.notifyConfigured()
|
view.output.root.notifyConfigured()
|
||||||
else
|
else {
|
||||||
view.current = view.pending;
|
view.current = view.pending;
|
||||||
|
view.commitOpacityTransition();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// If the client has not yet acked our configure, we need to send a
|
// If the client has not yet acked our configure, we need to send a
|
||||||
// frame done event so that it commits another buffer. These
|
// frame done event so that it commits another buffer. These
|
||||||
|
@ -49,6 +49,7 @@ const str_to_impl_fn = [_]struct {
|
|||||||
.{ .name = "map-pointer", .impl = @import("command/map.zig").mapPointer },
|
.{ .name = "map-pointer", .impl = @import("command/map.zig").mapPointer },
|
||||||
.{ .name = "mod-master-count", .impl = @import("command/mod_master_count.zig").modMasterCount },
|
.{ .name = "mod-master-count", .impl = @import("command/mod_master_count.zig").modMasterCount },
|
||||||
.{ .name = "mod-master-factor", .impl = @import("command/mod_master_factor.zig").modMasterFactor },
|
.{ .name = "mod-master-factor", .impl = @import("command/mod_master_factor.zig").modMasterFactor },
|
||||||
|
.{ .name = "opacity", .impl = @import("command/opacity.zig").opacity },
|
||||||
.{ .name = "outer-padding", .impl = @import("command/config.zig").outerPadding },
|
.{ .name = "outer-padding", .impl = @import("command/config.zig").outerPadding },
|
||||||
.{ .name = "send-to-output", .impl = @import("command/send_to_output.zig").sendToOutput },
|
.{ .name = "send-to-output", .impl = @import("command/send_to_output.zig").sendToOutput },
|
||||||
.{ .name = "set-focused-tags", .impl = @import("command/tags.zig").setFocusedTags },
|
.{ .name = "set-focused-tags", .impl = @import("command/tags.zig").setFocusedTags },
|
||||||
@ -73,6 +74,7 @@ pub const Error = error{
|
|||||||
InvalidCharacter,
|
InvalidCharacter,
|
||||||
InvalidDirection,
|
InvalidDirection,
|
||||||
InvalidRgba,
|
InvalidRgba,
|
||||||
|
InvalidValue,
|
||||||
UnknownOption,
|
UnknownOption,
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
Other,
|
Other,
|
||||||
@ -113,6 +115,7 @@ pub fn errToMsg(err: Error) [:0]const u8 {
|
|||||||
Error.InvalidCharacter => "invalid character in argument",
|
Error.InvalidCharacter => "invalid character in argument",
|
||||||
Error.InvalidDirection => "invalid direction. Must be 'next' or 'previous'",
|
Error.InvalidDirection => "invalid direction. Must be 'next' or 'previous'",
|
||||||
Error.InvalidRgba => "invalid color format, must be #RRGGBB or #RRGGBBAA",
|
Error.InvalidRgba => "invalid color format, must be #RRGGBB or #RRGGBBAA",
|
||||||
|
Error.InvalidValue => "invalid value",
|
||||||
Error.OutOfMemory => "out of memory",
|
Error.OutOfMemory => "out of memory",
|
||||||
Error.Other => unreachable,
|
Error.Other => unreachable,
|
||||||
};
|
};
|
||||||
|
79
river/command/opacity.zig
Normal file
79
river/command/opacity.zig
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// This file is part of river, a dynamic tiling wayland compositor.
|
||||||
|
//
|
||||||
|
// Copyright 2020 Leon Henrik Plickat
|
||||||
|
//
|
||||||
|
// 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 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 []const u8,
|
||||||
|
out: *?[]const u8,
|
||||||
|
) Error!void {
|
||||||
|
if (args.len < 6) return Error.NotEnoughArguments;
|
||||||
|
if (args.len > 6) return Error.TooManyArguments;
|
||||||
|
|
||||||
|
const server = seat.input_manager.server;
|
||||||
|
|
||||||
|
// Focused opacity
|
||||||
|
server.config.view_opacity_focused = try std.fmt.parseFloat(f32, args[1]);
|
||||||
|
if (server.config.view_opacity_focused < 0.0 or server.config.view_opacity_focused > 1.0)
|
||||||
|
return Error.InvalidValue;
|
||||||
|
|
||||||
|
// Unfocused opacity
|
||||||
|
server.config.view_opacity_unfocused = try std.fmt.parseFloat(f32, args[2]);
|
||||||
|
if (server.config.view_opacity_unfocused < 0.0 or server.config.view_opacity_unfocused > 1.0)
|
||||||
|
return Error.InvalidValue;
|
||||||
|
|
||||||
|
// Starting opacity for new views
|
||||||
|
server.config.view_opacity_initial = try std.fmt.parseFloat(f32, args[3]);
|
||||||
|
if (server.config.view_opacity_initial < 0.0 or server.config.view_opacity_initial > 1.0)
|
||||||
|
return Error.InvalidValue;
|
||||||
|
|
||||||
|
// Opacity transition step
|
||||||
|
server.config.view_opacity_delta = try std.fmt.parseFloat(f32, args[4]);
|
||||||
|
if (server.config.view_opacity_delta < 0.0 or server.config.view_opacity_delta > 1.0)
|
||||||
|
return Error.InvalidValue;
|
||||||
|
|
||||||
|
// Time between step
|
||||||
|
server.config.view_opacity_delta_t = try std.fmt.parseInt(u31, args[5], 10);
|
||||||
|
if (server.config.view_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.view_opacity_focused;
|
||||||
|
} else {
|
||||||
|
vnode.pending.target_opacity = server.config.view_opacity_unfocused;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
server.root.startTransaction();
|
||||||
|
}
|
@ -36,6 +36,8 @@ const SurfaceRenderData = struct {
|
|||||||
output_y: i32,
|
output_y: i32,
|
||||||
|
|
||||||
when: *c.timespec,
|
when: *c.timespec,
|
||||||
|
|
||||||
|
opacity: f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn renderOutput(output: *Output) void {
|
pub fn renderOutput(output: *Output) void {
|
||||||
@ -138,6 +140,7 @@ fn renderLayer(output: Output, layer: std.TailQueue(LayerSurface), now: *c.times
|
|||||||
.output_x = layer_surface.box.x,
|
.output_x = layer_surface.box.x,
|
||||||
.output_y = layer_surface.box.y,
|
.output_y = layer_surface.box.y,
|
||||||
.when = now,
|
.when = now,
|
||||||
|
.opacity = 1.0,
|
||||||
};
|
};
|
||||||
c.wlr_layer_surface_v1_for_each_surface(
|
c.wlr_layer_surface_v1_for_each_surface(
|
||||||
layer_surface.wlr_layer_surface,
|
layer_surface.wlr_layer_surface,
|
||||||
@ -162,6 +165,7 @@ fn renderView(output: Output, view: *View, now: *c.timespec) void {
|
|||||||
.height = @intCast(c_int, saved_buffer.box.height),
|
.height = @intCast(c_int, saved_buffer.box.height),
|
||||||
},
|
},
|
||||||
saved_buffer.transform,
|
saved_buffer.transform,
|
||||||
|
view.opacity,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Since there is no stashed buffer, we are not in the middle of
|
// Since there is no stashed buffer, we are not in the middle of
|
||||||
@ -171,6 +175,7 @@ fn renderView(output: Output, view: *View, now: *c.timespec) void {
|
|||||||
.output_x = view.current.box.x - view.surface_box.x,
|
.output_x = view.current.box.x - view.surface_box.x,
|
||||||
.output_y = view.current.box.y - view.surface_box.y,
|
.output_y = view.current.box.y - view.surface_box.y,
|
||||||
.when = now,
|
.when = now,
|
||||||
|
.opacity = view.opacity,
|
||||||
};
|
};
|
||||||
|
|
||||||
view.forEachSurface(renderSurfaceIterator, &rdata);
|
view.forEachSurface(renderSurfaceIterator, &rdata);
|
||||||
@ -191,6 +196,7 @@ fn renderDragIcons(output: Output, now: *c.timespec) void {
|
|||||||
.output_y = @floatToInt(i32, drag_icon.seat.cursor.wlr_cursor.y) +
|
.output_y = @floatToInt(i32, drag_icon.seat.cursor.wlr_cursor.y) +
|
||||||
drag_icon.wlr_drag_icon.surface.*.sy - output_box.*.y,
|
drag_icon.wlr_drag_icon.surface.*.sy - output_box.*.y,
|
||||||
.when = now,
|
.when = now,
|
||||||
|
.opacity = 1.0,
|
||||||
};
|
};
|
||||||
c.wlr_surface_for_each_surface(drag_icon.wlr_drag_icon.surface, renderSurfaceIterator, &rdata);
|
c.wlr_surface_for_each_surface(drag_icon.wlr_drag_icon.surface, renderSurfaceIterator, &rdata);
|
||||||
}
|
}
|
||||||
@ -209,6 +215,7 @@ fn renderXwaylandUnmanaged(output: Output, now: *c.timespec) void {
|
|||||||
.output_x = wlr_xwayland_surface.x - output_box.*.x,
|
.output_x = wlr_xwayland_surface.x - output_box.*.x,
|
||||||
.output_y = wlr_xwayland_surface.y - output_box.*.y,
|
.output_y = wlr_xwayland_surface.y - output_box.*.y,
|
||||||
.when = now,
|
.when = now,
|
||||||
|
.opacity = 1.0,
|
||||||
};
|
};
|
||||||
c.wlr_surface_for_each_surface(wlr_xwayland_surface.surface, renderSurfaceIterator, &rdata);
|
c.wlr_surface_for_each_surface(wlr_xwayland_surface.surface, renderSurfaceIterator, &rdata);
|
||||||
}
|
}
|
||||||
@ -233,6 +240,7 @@ fn renderSurfaceIterator(
|
|||||||
.height = surface.?.current.height,
|
.height = surface.?.current.height,
|
||||||
},
|
},
|
||||||
surface.?.current.transform,
|
surface.?.current.transform,
|
||||||
|
rdata.opacity,
|
||||||
);
|
);
|
||||||
|
|
||||||
c.wlr_surface_send_frame_done(surface, rdata.when);
|
c.wlr_surface_send_frame_done(surface, rdata.when);
|
||||||
@ -245,6 +253,7 @@ fn renderTexture(
|
|||||||
wlr_texture: ?*c.wlr_texture,
|
wlr_texture: ?*c.wlr_texture,
|
||||||
wlr_box: c.wlr_box,
|
wlr_box: c.wlr_box,
|
||||||
transform: c.wl_output_transform,
|
transform: c.wl_output_transform,
|
||||||
|
opacity: f32,
|
||||||
) void {
|
) void {
|
||||||
const texture = wlr_texture orelse return;
|
const texture = wlr_texture orelse return;
|
||||||
var box = wlr_box;
|
var box = wlr_box;
|
||||||
@ -262,7 +271,7 @@ fn renderTexture(
|
|||||||
|
|
||||||
// This takes our matrix, the texture, and an alpha, and performs the actual
|
// This takes our matrix, the texture, and an alpha, and performs the actual
|
||||||
// rendering on the GPU.
|
// rendering on the GPU.
|
||||||
_ = c.wlr_render_texture_with_matrix(output.getRenderer(), texture, &matrix, 1.0);
|
_ = c.wlr_render_texture_with_matrix(output.getRenderer(), texture, &matrix, opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderBorders(output: Output, view: *View, now: *c.timespec) void {
|
fn renderBorders(output: Output, view: *View, now: *c.timespec) void {
|
||||||
|
Loading…
Reference in New Issue
Block a user