mirror of
https://mzte.de/git/LordMZTE/dotfiles.git
synced 2024-05-16 22:13:46 +02:00
improve wlbg
This commit is contained in:
parent
7c64072005
commit
f2e10a974b
|
@ -82,7 +82,7 @@ env = WLR_NO_HARDWARE_CURSORS, 1
|
|||
<! end !>
|
||||
|
||||
exec-once = waybar
|
||||
exec-once = swww-daemon
|
||||
exec-once = wlbg
|
||||
exec-once = sleep 1 && randomwallpaper
|
||||
exec-once = hyprctl setcursor <% opt.cursor.theme %> <% opt.cursor.size %>
|
||||
<! if opt.commands.notification_daemon.wl then !>
|
||||
|
|
|
@ -4,54 +4,237 @@ const c = @import("ffi.zig").c;
|
|||
const glutil = @import("glutil.zig");
|
||||
|
||||
const OutputInfo = @import("OutputInfo.zig");
|
||||
const OutputWindow = @import("OutputWindow.zig");
|
||||
const PointerState = @import("PointerState.zig");
|
||||
|
||||
egl_dpy: c.EGLDisplay,
|
||||
bg_shader_program: c_uint,
|
||||
main_shader_program: c_uint,
|
||||
bg_bufs: std.MultiArrayList(BgBuf),
|
||||
time: i64,
|
||||
cursor_positions: [][2]c_int,
|
||||
|
||||
const Gfx = @This();
|
||||
|
||||
pub fn init(egl_dpy: c.EGLDisplay) !Gfx {
|
||||
const vert_shader = try glutil.createShader(c.GL_VERTEX_SHADER, @embedFile("bg_vert.glsl"));
|
||||
defer c.glDeleteShader(vert_shader);
|
||||
const frag_shader = try glutil.createShader(c.GL_FRAGMENT_SHADER, @embedFile("bg_frag.glsl"));
|
||||
defer c.glDeleteShader(frag_shader);
|
||||
const BgBuf = struct {
|
||||
texture: c_uint,
|
||||
framebuffer: c_uint,
|
||||
zbuffer: c_uint,
|
||||
};
|
||||
|
||||
const program = c.glCreateProgram();
|
||||
errdefer c.glDeleteProgram(program);
|
||||
c.glAttachShader(program, vert_shader);
|
||||
c.glAttachShader(program, frag_shader);
|
||||
c.glLinkProgram(program);
|
||||
pub fn init(egl_dpy: c.EGLDisplay, output_info: []const OutputInfo) !Gfx {
|
||||
const bg_program = shader: {
|
||||
const vert_shader = try glutil.createShader(c.GL_VERTEX_SHADER, @embedFile("bg_vert.glsl"));
|
||||
defer c.glDeleteShader(vert_shader);
|
||||
const frag_shader = try glutil.createShader(c.GL_FRAGMENT_SHADER, @embedFile("bg_frag.glsl"));
|
||||
defer c.glDeleteShader(frag_shader);
|
||||
|
||||
var success: c_int = 0;
|
||||
c.glGetProgramiv(program, c.GL_LINK_STATUS, &success);
|
||||
if (success != 1)
|
||||
return error.ShaderLinkFail;
|
||||
const program = c.glCreateProgram();
|
||||
errdefer c.glDeleteProgram(program);
|
||||
c.glAttachShader(program, vert_shader);
|
||||
c.glAttachShader(program, frag_shader);
|
||||
c.glLinkProgram(program);
|
||||
|
||||
var success: c_int = 0;
|
||||
c.glGetProgramiv(program, c.GL_LINK_STATUS, &success);
|
||||
if (success != 1)
|
||||
return error.ShaderLinkFail;
|
||||
|
||||
break :shader program;
|
||||
};
|
||||
|
||||
const main_program = shader: {
|
||||
const vert_shader = try glutil.createShader(c.GL_VERTEX_SHADER, @embedFile("main_vert.glsl"));
|
||||
defer c.glDeleteShader(vert_shader);
|
||||
const frag_shader = try glutil.createShader(c.GL_FRAGMENT_SHADER, @embedFile("main_frag.glsl"));
|
||||
defer c.glDeleteShader(frag_shader);
|
||||
|
||||
const program = c.glCreateProgram();
|
||||
errdefer c.glDeleteProgram(program);
|
||||
c.glAttachShader(program, vert_shader);
|
||||
c.glAttachShader(program, frag_shader);
|
||||
c.glLinkProgram(program);
|
||||
|
||||
var success: c_int = 0;
|
||||
c.glGetProgramiv(program, c.GL_LINK_STATUS, &success);
|
||||
if (success != 1)
|
||||
return error.ShaderLinkFail;
|
||||
|
||||
break :shader program;
|
||||
};
|
||||
|
||||
const cursor_positions = try std.heap.c_allocator.alloc([2]c_int, output_info.len);
|
||||
errdefer std.heap.c_allocator.free(cursor_positions);
|
||||
@memset(cursor_positions, .{ 0, 0 });
|
||||
|
||||
var bg_bufs = std.MultiArrayList(BgBuf){};
|
||||
errdefer bg_bufs.deinit(std.heap.c_allocator);
|
||||
|
||||
try bg_bufs.resize(std.heap.c_allocator, output_info.len);
|
||||
|
||||
const bg_slice = bg_bufs.slice();
|
||||
|
||||
// @intCast safety: user is somewhat unlikely to have 2^32 - 1 monitors.
|
||||
c.glGenTextures(@intCast(output_info.len), bg_slice.items(.texture).ptr);
|
||||
errdefer c.glDeleteTextures(@intCast(bg_bufs.len), bg_slice.items(.texture).ptr);
|
||||
c.glGenFramebuffers(@intCast(output_info.len), bg_slice.items(.framebuffer).ptr);
|
||||
errdefer c.glDeleteFramebuffers(@intCast(bg_bufs.len), bg_slice.items(.framebuffer).ptr);
|
||||
c.glGenRenderbuffers(@intCast(output_info.len), bg_slice.items(.zbuffer).ptr);
|
||||
errdefer c.glDeleteRenderbuffers(@intCast(output_info.len), bg_slice.items(.zbuffer).ptr);
|
||||
|
||||
for (
|
||||
output_info,
|
||||
bg_slice.items(.texture),
|
||||
bg_slice.items(.framebuffer),
|
||||
bg_slice.items(.zbuffer),
|
||||
) |inf, tex, fb, zb| {
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, fb);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, tex);
|
||||
c.glBindRenderbuffer(c.GL_RENDERBUFFER, zb);
|
||||
|
||||
c.glTexImage2D(
|
||||
c.GL_TEXTURE_2D,
|
||||
0,
|
||||
c.GL_RGBA,
|
||||
inf.width,
|
||||
inf.height,
|
||||
0,
|
||||
c.GL_RGBA,
|
||||
c.GL_UNSIGNED_BYTE,
|
||||
null,
|
||||
);
|
||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_NEAREST);
|
||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_NEAREST);
|
||||
|
||||
c.glFramebufferTexture2D(
|
||||
c.GL_FRAMEBUFFER,
|
||||
c.GL_COLOR_ATTACHMENT0,
|
||||
c.GL_TEXTURE_2D,
|
||||
tex,
|
||||
0,
|
||||
);
|
||||
|
||||
c.glRenderbufferStorage(c.GL_RENDERBUFFER, c.GL_DEPTH_COMPONENT16, inf.width, inf.height);
|
||||
c.glFramebufferRenderbuffer(c.GL_FRAMEBUFFER, c.GL_DEPTH_ATTACHMENT, c.GL_RENDERBUFFER, zb);
|
||||
|
||||
if (c.glCheckFramebufferStatus(c.GL_FRAMEBUFFER) != c.GL_FRAMEBUFFER_COMPLETE)
|
||||
return error.FramebufferIncomplete;
|
||||
}
|
||||
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, 0);
|
||||
c.glBindRenderbuffer(c.GL_FRAMEBUFFER, 0);
|
||||
|
||||
return .{
|
||||
.egl_dpy = egl_dpy,
|
||||
.bg_shader_program = program,
|
||||
.bg_shader_program = bg_program,
|
||||
.main_shader_program = main_program,
|
||||
.bg_bufs = bg_bufs,
|
||||
.time = 0,
|
||||
.cursor_positions = cursor_positions,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Gfx) void {
|
||||
const bg_slice = self.bg_bufs.slice();
|
||||
c.glDeleteTextures(@intCast(bg_slice.len), bg_slice.items(.texture).ptr);
|
||||
c.glDeleteFramebuffers(@intCast(bg_slice.len), bg_slice.items(.framebuffer).ptr);
|
||||
c.glDeleteRenderbuffers(@intCast(bg_slice.len), bg_slice.items(.zbuffer).ptr);
|
||||
self.bg_bufs.deinit(std.heap.c_allocator);
|
||||
|
||||
c.glDeleteProgram(self.bg_shader_program);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn drawBackground(
|
||||
pub fn draw(
|
||||
self: *Gfx,
|
||||
dt: i64,
|
||||
egl_surface: c.EGLSurface,
|
||||
info: OutputInfo,
|
||||
base_xoff: i32,
|
||||
base_yoff: i32,
|
||||
pointer_state: *PointerState,
|
||||
output_idx: usize,
|
||||
outputs: []const OutputWindow,
|
||||
infos: []const OutputInfo,
|
||||
) !void {
|
||||
_ = dt;
|
||||
self.time += dt;
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0); // use default framebuffer
|
||||
c.glUseProgram(self.main_shader_program);
|
||||
|
||||
for (self.cursor_positions, infos, outputs) |*pos, inf, outp| {
|
||||
const target = if (pointer_state.surface == outp.surface)
|
||||
.{ pointer_state.x, pointer_state.y }
|
||||
else
|
||||
.{ @divTrunc(inf.width, 2), @divTrunc(inf.height, 2) };
|
||||
|
||||
pos[0] = @intFromFloat(std.math.lerp(
|
||||
@as(f32, @floatFromInt(pos[0])),
|
||||
@as(f32, @floatFromInt(target[0])),
|
||||
std.math.clamp(@as(f32, @floatFromInt(dt)) / 1000.0, 0.0, 1.0),
|
||||
));
|
||||
pos[1] = @intFromFloat(std.math.lerp(
|
||||
@as(f32, @floatFromInt(pos[1])),
|
||||
@as(f32, @floatFromInt(target[1])),
|
||||
std.math.clamp(@as(f32, @floatFromInt(dt)) / 1000.0, 0.0, 1.0),
|
||||
));
|
||||
}
|
||||
|
||||
const vertices = [_]f32{
|
||||
-1.0, -1.0, 0.0, 0.0, 0.0,
|
||||
1.0, -1.0, 0.0, 1.0, 0.0,
|
||||
1.0, 1.0, 0.0, 1.0, 1.0,
|
||||
|
||||
-1.0, -1.0, 0.0, 0.0, 0.0,
|
||||
1.0, 1.0, 0.0, 1.0, 1.0,
|
||||
-1.0, 1.0, 0.0, 0.0, 1.0,
|
||||
};
|
||||
|
||||
c.glVertexAttribPointer(0, 3, c.GL_FLOAT, c.GL_FALSE, @sizeOf(f32) * 5, &vertices);
|
||||
c.glEnableVertexAttribArray(0);
|
||||
c.glVertexAttribPointer(
|
||||
1,
|
||||
2,
|
||||
c.GL_FLOAT,
|
||||
c.GL_FALSE,
|
||||
@sizeOf(f32) * 5,
|
||||
@ptrFromInt(@intFromPtr(&vertices) + @sizeOf(f32) * 3),
|
||||
);
|
||||
c.glEnableVertexAttribArray(1);
|
||||
|
||||
c.glClearColor(1.0, 0.0, 0.0, 1.0);
|
||||
c.glClear(c.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, self.bg_bufs.get(output_idx).texture);
|
||||
|
||||
c.glUniform2f(
|
||||
c.glGetUniformLocation(self.main_shader_program, "cursorPos"),
|
||||
@as(f32, @floatFromInt(self.cursor_positions[output_idx][0])) / @as(f32, @floatFromInt(infos[output_idx].width)),
|
||||
1.0 - @as(f32, @floatFromInt(self.cursor_positions[output_idx][1])) / @as(f32, @floatFromInt(infos[output_idx].height)),
|
||||
);
|
||||
c.glUniform1f(
|
||||
c.glGetUniformLocation(self.main_shader_program, "hasCursor"),
|
||||
if (outputs[output_idx].surface == pointer_state.surface) 1.0 else 0.0,
|
||||
);
|
||||
//c.glUniform1f(
|
||||
// c.glGetUniformLocation(self.main_shader_program, "time"),
|
||||
// @as(f32, @floatFromInt(self.time)) / 1000.0,
|
||||
//);
|
||||
|
||||
c.glDrawArrays(c.GL_TRIANGLES, 0, vertices.len / 3);
|
||||
|
||||
if (c.eglSwapInterval(self.egl_dpy, 0) != c.EGL_TRUE or
|
||||
c.eglSwapBuffers(self.egl_dpy, outputs[output_idx].egl_surface) != c.EGL_TRUE) return error.EGLError;
|
||||
}
|
||||
|
||||
pub fn drawBackground(
|
||||
self: *Gfx,
|
||||
info: OutputInfo,
|
||||
output_idx: usize,
|
||||
base_off: [2]i32,
|
||||
rand: f32,
|
||||
) !void {
|
||||
std.log.info("draw bg", .{});
|
||||
// There's just about a 0% chance this works properly when monitors have different resolutions,
|
||||
// but I can't even begin thinking about that.
|
||||
const xoff = @as(f32, @floatFromInt(info.x - base_xoff)) / @as(f32, @floatFromInt(info.width));
|
||||
const yoff = @as(f32, @floatFromInt(info.y - base_yoff)) / @as(f32, @floatFromInt(info.height));
|
||||
const xoff = @as(f32, @floatFromInt(info.x - base_off[0])) / @as(f32, @floatFromInt(info.width));
|
||||
const yoff = @as(f32, @floatFromInt(info.y - base_off[1])) / @as(f32, @floatFromInt(info.height));
|
||||
|
||||
const vertices = [_]f32{
|
||||
-1.0, -1.0, 0.0, xoff, yoff,
|
||||
|
@ -63,6 +246,8 @@ pub fn drawBackground(
|
|||
-1.0, 1.0, 0.0, xoff, yoff,
|
||||
};
|
||||
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, self.bg_bufs.get(output_idx).framebuffer);
|
||||
|
||||
c.glClearColor(1.0, 0.0, 0.0, 1.0);
|
||||
c.glClear(c.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
|
@ -74,11 +259,7 @@ pub fn drawBackground(
|
|||
c.glVertexAttribPointer(1, 2, c.GL_FLOAT, c.GL_FALSE, @sizeOf(f32) * 5, @ptrFromInt(@intFromPtr(&vertices) + @sizeOf(f32) * 3));
|
||||
c.glEnableVertexAttribArray(1);
|
||||
|
||||
const rand = std.crypto.random.float(f32);
|
||||
c.glUniform1f(c.glGetUniformLocation(self.bg_shader_program, "time"), rand * 2000.0 - 1000.0);
|
||||
|
||||
c.glDrawArrays(c.GL_TRIANGLES, 0, vertices.len / 3);
|
||||
|
||||
if (c.eglSwapInterval(self.egl_dpy, 0) != c.EGL_TRUE or
|
||||
c.eglSwapBuffers(self.egl_dpy, egl_surface) != c.EGL_TRUE) return error.EGLError;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ const zwlr = wayland.client.zwlr;
|
|||
|
||||
const log = std.log.scoped(.globals);
|
||||
|
||||
seat: *wl.Seat,
|
||||
compositor: *wl.Compositor,
|
||||
layer_shell: *zwlr.LayerShellV1,
|
||||
xdg_output_manager: *zxdg.OutputManagerV1,
|
||||
|
|
14
scripts/wlbg/src/OutputWindow.zig
Normal file
14
scripts/wlbg/src/OutputWindow.zig
Normal file
|
@ -0,0 +1,14 @@
|
|||
const wl = @import("wayland").client.wl;
|
||||
const c = @import("ffi.zig").c;
|
||||
|
||||
egl_win: *wl.EglWindow,
|
||||
egl_surface: c.EGLSurface,
|
||||
surface: *wl.Surface,
|
||||
|
||||
const OutputWindow = @This();
|
||||
|
||||
pub fn deinit(self: OutputWindow, egl_dpy: c.EGLDisplay) void {
|
||||
self.egl_win.destroy();
|
||||
self.surface.destroy();
|
||||
_ = c.eglDestroySurface(egl_dpy, self.egl_surface);
|
||||
}
|
5
scripts/wlbg/src/PointerState.zig
Normal file
5
scripts/wlbg/src/PointerState.zig
Normal file
|
@ -0,0 +1,5 @@
|
|||
const wl = @import("wayland").client.wl;
|
||||
|
||||
surface: ?*wl.Surface,
|
||||
x: c_int,
|
||||
y: c_int,
|
|
@ -7,11 +7,19 @@ const c = @import("ffi.zig").c;
|
|||
const Gfx = @import("Gfx.zig");
|
||||
const Globals = @import("Globals.zig");
|
||||
const OutputInfo = @import("OutputInfo.zig");
|
||||
const OutputWindow = @import("OutputWindow.zig");
|
||||
const PointerState = @import("PointerState.zig");
|
||||
|
||||
const wl = wayland.client.wl;
|
||||
const zwlr = wayland.client.zwlr;
|
||||
const zxdg = wayland.client.zxdg;
|
||||
|
||||
pub const std_options = struct {
|
||||
pub const log_level = .debug;
|
||||
};
|
||||
|
||||
const fps = 15;
|
||||
|
||||
pub fn main() !void {
|
||||
std.log.info("initializing event loop", .{});
|
||||
var loop = try xev.Loop.init(.{});
|
||||
|
@ -118,10 +126,21 @@ pub fn main() !void {
|
|||
output_window.* = .{
|
||||
.egl_win = egl_win,
|
||||
.egl_surface = egl_surface,
|
||||
.surface = surface,
|
||||
};
|
||||
}
|
||||
defer for (output_windows) |output| output.deinit(egl_ctx);
|
||||
|
||||
var pointer_state = PointerState{
|
||||
.surface = null,
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
};
|
||||
|
||||
const pointer = try globs.seat.getPointer();
|
||||
defer pointer.destroy();
|
||||
pointer.setListener(*PointerState, pointerListener, &pointer_state);
|
||||
|
||||
var total_width: i32 = 0;
|
||||
var total_height: i32 = 0;
|
||||
|
||||
|
@ -145,10 +164,10 @@ pub fn main() !void {
|
|||
egl_ctx,
|
||||
) != c.EGL_TRUE) return error.EGLError;
|
||||
|
||||
var gfx = try Gfx.init(egl_dpy);
|
||||
var gfx = try Gfx.init(egl_dpy, output_info);
|
||||
defer gfx.deinit();
|
||||
|
||||
var rbgdata = RenderBackgroundData{
|
||||
var rdata = RenderData{
|
||||
.gfx = &gfx,
|
||||
.egl_dpy = egl_dpy,
|
||||
.egl_ctx = egl_ctx,
|
||||
|
@ -156,6 +175,7 @@ pub fn main() !void {
|
|||
.output_info = output_info,
|
||||
.last_time = loop.now(),
|
||||
.base_offset = .{ base_xoff, base_yoff },
|
||||
.pointer_state = &pointer_state,
|
||||
};
|
||||
|
||||
var rbg_timer_completion: xev.Completion = undefined;
|
||||
|
@ -166,11 +186,24 @@ pub fn main() !void {
|
|||
&loop,
|
||||
&rbg_timer_completion,
|
||||
0,
|
||||
RenderBackgroundData,
|
||||
&rbgdata,
|
||||
RenderData,
|
||||
&rdata,
|
||||
renderBackgroundCb,
|
||||
);
|
||||
|
||||
var r_timer_completion: xev.Completion = undefined;
|
||||
var r_timer = try xev.Timer.init();
|
||||
defer r_timer.deinit();
|
||||
|
||||
r_timer.run(
|
||||
&loop,
|
||||
&r_timer_completion,
|
||||
0,
|
||||
RenderData,
|
||||
&rdata,
|
||||
renderCb,
|
||||
);
|
||||
|
||||
var wl_poll_completion = xev.Completion{
|
||||
.op = .{ .poll = .{ .fd = dpy.getFd() } },
|
||||
.userdata = dpy,
|
||||
|
@ -182,7 +215,7 @@ pub fn main() !void {
|
|||
try loop.run(.until_done);
|
||||
}
|
||||
|
||||
const RenderBackgroundData = struct {
|
||||
const RenderData = struct {
|
||||
gfx: *Gfx,
|
||||
egl_dpy: c.EGLDisplay,
|
||||
egl_ctx: c.EGLContext,
|
||||
|
@ -190,10 +223,11 @@ const RenderBackgroundData = struct {
|
|||
output_info: []const OutputInfo,
|
||||
last_time: isize,
|
||||
base_offset: [2]c_int,
|
||||
pointer_state: *PointerState,
|
||||
};
|
||||
|
||||
fn renderBackgroundCb(
|
||||
data: ?*RenderBackgroundData,
|
||||
fn renderCb(
|
||||
data: ?*RenderData,
|
||||
loop: *xev.Loop,
|
||||
completion: *xev.Completion,
|
||||
result: xev.Timer.RunError!void,
|
||||
|
@ -201,16 +235,12 @@ fn renderBackgroundCb(
|
|||
result catch unreachable;
|
||||
|
||||
const now = loop.now();
|
||||
|
||||
const delta_time = now - data.?.last_time;
|
||||
data.?.last_time = now;
|
||||
const next_time = now + std.time.ms_per_min;
|
||||
completion.op.timer.reset = .{
|
||||
.tv_sec = @divTrunc(next_time, std.time.ms_per_s),
|
||||
.tv_nsec = @mod(next_time, std.time.ms_per_s) * std.time.ns_per_ms,
|
||||
};
|
||||
|
||||
for (data.?.outputs, data.?.output_info) |output, info| {
|
||||
resetXevTimerCompletion(completion, now, 1000 / fps);
|
||||
|
||||
for (data.?.outputs, 0..) |output, i| {
|
||||
if (c.eglMakeCurrent(
|
||||
data.?.egl_dpy,
|
||||
output.egl_surface,
|
||||
|
@ -222,12 +252,12 @@ fn renderBackgroundCb(
|
|||
return .disarm;
|
||||
}
|
||||
|
||||
data.?.gfx.drawBackground(
|
||||
data.?.gfx.draw(
|
||||
delta_time,
|
||||
output.egl_surface,
|
||||
info,
|
||||
data.?.base_offset[0],
|
||||
data.?.base_offset[1],
|
||||
data.?.pointer_state,
|
||||
i,
|
||||
data.?.outputs,
|
||||
data.?.output_info,
|
||||
) catch |e| {
|
||||
std.log.err("drawing: {}", .{e});
|
||||
loop.stop();
|
||||
|
@ -238,6 +268,34 @@ fn renderBackgroundCb(
|
|||
return .rearm;
|
||||
}
|
||||
|
||||
fn renderBackgroundCb(
|
||||
data: ?*RenderData,
|
||||
loop: *xev.Loop,
|
||||
completion: *xev.Completion,
|
||||
result: xev.Timer.RunError!void,
|
||||
) xev.CallbackAction {
|
||||
result catch unreachable;
|
||||
|
||||
resetXevTimerCompletion(completion, loop.now(), std.time.ms_per_min);
|
||||
|
||||
const rand = std.crypto.random.float(f32);
|
||||
for (data.?.outputs, data.?.output_info, 0..) |output, info, i| {
|
||||
_ = output;
|
||||
data.?.gfx.drawBackground(
|
||||
info,
|
||||
i,
|
||||
data.?.base_offset,
|
||||
rand,
|
||||
) catch |e| {
|
||||
std.log.err("drawing background: {}", .{e});
|
||||
loop.stop();
|
||||
return .disarm;
|
||||
};
|
||||
}
|
||||
|
||||
return .rearm;
|
||||
}
|
||||
|
||||
fn wlPollCb(
|
||||
userdata: ?*anyopaque,
|
||||
loop: *xev.Loop,
|
||||
|
@ -260,16 +318,6 @@ fn wlPollCb(
|
|||
return .rearm;
|
||||
}
|
||||
|
||||
const OutputWindow = struct {
|
||||
egl_win: *wl.EglWindow,
|
||||
egl_surface: c.EGLSurface,
|
||||
|
||||
fn deinit(self: OutputWindow, egl_dpy: c.EGLDisplay) void {
|
||||
self.egl_win.destroy();
|
||||
_ = c.eglDestroySurface(egl_dpy, self.egl_surface);
|
||||
}
|
||||
};
|
||||
|
||||
fn layerSurfaceListener(lsurf: *zwlr.LayerSurfaceV1, ev: zwlr.LayerSurfaceV1.Event, winsize: *?[2]c_int) void {
|
||||
switch (ev) {
|
||||
.configure => |configure| {
|
||||
|
@ -294,3 +342,23 @@ fn xdgOutputListener(_: *zxdg.OutputV1, ev: zxdg.OutputV1.Event, info: *OutputIn
|
|||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn pointerListener(_: *wl.Pointer, ev: wl.Pointer.Event, state: *PointerState) void {
|
||||
switch (ev) {
|
||||
.motion => |motion| {
|
||||
state.x = motion.surface_x.toInt();
|
||||
state.y = motion.surface_y.toInt();
|
||||
},
|
||||
.enter => |enter| state.surface = enter.surface,
|
||||
.leave => state.surface = null,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn resetXevTimerCompletion(completion: *xev.Completion, now: i64, in: i64) void {
|
||||
const next_time = now + in;
|
||||
completion.op.timer.reset = .{
|
||||
.tv_sec = @divTrunc(next_time, std.time.ms_per_s),
|
||||
.tv_nsec = @mod(next_time, std.time.ms_per_s) * std.time.ns_per_ms,
|
||||
};
|
||||
}
|
||||
|
|
20
scripts/wlbg/src/main_frag.glsl
Normal file
20
scripts/wlbg/src/main_frag.glsl
Normal file
|
@ -0,0 +1,20 @@
|
|||
#version 300 es
|
||||
|
||||
precision highp float;
|
||||
|
||||
uniform sampler2D bg;
|
||||
|
||||
uniform vec2 cursorPos;
|
||||
uniform float hasCursor;
|
||||
|
||||
in vec2 fragCoord;
|
||||
in vec2 fragUv;
|
||||
|
||||
void main() {
|
||||
vec2 diff = cursorPos - fragUv;
|
||||
float light = clamp(.1 - (diff.x * diff.x + diff.y * diff.y), 0.0, 1.0);
|
||||
|
||||
vec2 zoomedUv = fragUv * .9 + (.1 / 2.0);
|
||||
gl_FragColor = mix(texture(bg, zoomedUv + (cursorPos - .5) / 10.0), vec4(1.0), light * hasCursor);
|
||||
}
|
||||
|
15
scripts/wlbg/src/main_vert.glsl
Normal file
15
scripts/wlbg/src/main_vert.glsl
Normal file
|
@ -0,0 +1,15 @@
|
|||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
|
||||
attribute vec4 vPos;
|
||||
attribute vec2 uv;
|
||||
|
||||
out vec2 fragCoord;
|
||||
out vec2 fragUv;
|
||||
|
||||
void main() {
|
||||
gl_Position = vPos;
|
||||
fragCoord = vPos.xy;
|
||||
fragUv = uv;
|
||||
}
|
Loading…
Reference in a new issue