mirror of
https://mzte.de/git/LordMZTE/dotfiles.git
synced 2024-12-13 20:52:59 +01:00
implement wlbg
This commit is contained in:
parent
e763bfbcc4
commit
1e04919f26
13 changed files with 944 additions and 0 deletions
1
scripts/wlbg/.gitignore
vendored
Normal file
1
scripts/wlbg/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/zig-*
|
49
scripts/wlbg/build.zig
Normal file
49
scripts/wlbg/build.zig
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Scanner = @import("wayland").Scanner;
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const scanner = Scanner.create(b, .{});
|
||||||
|
const wayland_mod = b.createModule(.{ .source_file = scanner.result });
|
||||||
|
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "wlbg",
|
||||||
|
.root_source_file = .{ .path = "src/main.zig" },
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
exe.addModule("wayland", wayland_mod);
|
||||||
|
|
||||||
|
scanner.addSystemProtocol("stable/xdg-shell/xdg-shell.xml");
|
||||||
|
scanner.addSystemProtocol("unstable/xdg-output/xdg-output-unstable-v1.xml");
|
||||||
|
scanner.addCustomProtocol("wlr-layer-shell-unstable-v1.xml");
|
||||||
|
|
||||||
|
scanner.generate("wl_compositor", 5);
|
||||||
|
scanner.generate("wl_shm", 1);
|
||||||
|
scanner.generate("zwlr_layer_shell_v1", 4);
|
||||||
|
scanner.generate("zxdg_output_manager_v1", 3);
|
||||||
|
scanner.generate("xdg_wm_base", 5); // dependency of layer shell
|
||||||
|
scanner.generate("wl_seat", 8);
|
||||||
|
scanner.generate("wl_output", 4);
|
||||||
|
|
||||||
|
exe.linkLibC();
|
||||||
|
exe.linkSystemLibrary("wayland-client");
|
||||||
|
exe.linkSystemLibrary("wayland-egl");
|
||||||
|
exe.linkSystemLibrary("EGL");
|
||||||
|
exe.linkSystemLibrary("GLESv2");
|
||||||
|
scanner.addCSource(exe);
|
||||||
|
|
||||||
|
b.installArtifact(exe);
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
}
|
11
scripts/wlbg/build.zig.zon
Normal file
11
scripts/wlbg/build.zig.zon
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
.{
|
||||||
|
.name = "wlbg",
|
||||||
|
.version = "0.0.0",
|
||||||
|
.paths = .{""},
|
||||||
|
.dependencies = .{
|
||||||
|
.wayland = .{
|
||||||
|
.url = "https://git.mzte.de/LordMZTE/zig-wayland/archive/85722422985f928087e56d90c3617ecb04232486.tar.gz",
|
||||||
|
.hash = "1220d992b223e473988d203d66d262e54141b59559c09587eb00231c800d46f9b408",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
84
scripts/wlbg/src/Gfx.zig
Normal file
84
scripts/wlbg/src/Gfx.zig
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const c = @import("ffi.zig").c;
|
||||||
|
|
||||||
|
const glutil = @import("glutil.zig");
|
||||||
|
|
||||||
|
const OutputInfo = @import("OutputInfo.zig");
|
||||||
|
|
||||||
|
egl_dpy: c.EGLDisplay,
|
||||||
|
bg_shader_program: c_uint,
|
||||||
|
time: f64,
|
||||||
|
|
||||||
|
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 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;
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.egl_dpy = egl_dpy,
|
||||||
|
.bg_shader_program = program,
|
||||||
|
.time = 0.0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Gfx) void {
|
||||||
|
c.glDeleteProgram(self.bg_shader_program);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(
|
||||||
|
self: *Gfx,
|
||||||
|
dt: f32,
|
||||||
|
egl_surface: c.EGLSurface,
|
||||||
|
info: OutputInfo,
|
||||||
|
base_xoff: i32,
|
||||||
|
base_yoff: i32,
|
||||||
|
) !void {
|
||||||
|
self.time += dt;
|
||||||
|
|
||||||
|
// 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 vertices = [_]f32{
|
||||||
|
-1.0, -1.0, 0.0, xoff, yoff,
|
||||||
|
1.0, -1.0, 0.0, xoff, yoff,
|
||||||
|
1.0, 1.0, 0.0, xoff, yoff,
|
||||||
|
|
||||||
|
-1.0, -1.0, 0.0, xoff, yoff,
|
||||||
|
1.0, 1.0, 0.0, xoff, yoff,
|
||||||
|
-1.0, 1.0, 0.0, xoff, yoff,
|
||||||
|
};
|
||||||
|
|
||||||
|
c.glClearColor(1.0, 0.0, 0.0, 1.0);
|
||||||
|
c.glClear(c.GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
c.glUseProgram(self.bg_shader_program);
|
||||||
|
|
||||||
|
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.glUniform1f(c.glGetUniformLocation(self.bg_shader_program, "time"), @as(f32, @floatCast(self.time / 10000.0)));
|
||||||
|
|
||||||
|
c.glDrawArrays(c.GL_TRIANGLES, 0, vertices.len / 3);
|
||||||
|
|
||||||
|
if (c.eglSwapBuffers(self.egl_dpy, egl_surface) != c.EGL_TRUE) return error.EGLError;
|
||||||
|
}
|
103
scripts/wlbg/src/Globals.zig
Normal file
103
scripts/wlbg/src/Globals.zig
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const wayland = @import("wayland");
|
||||||
|
|
||||||
|
const wl = wayland.client.wl;
|
||||||
|
const zxdg = wayland.client.zxdg;
|
||||||
|
const zwlr = wayland.client.zwlr;
|
||||||
|
|
||||||
|
const log = std.log.scoped(.globals);
|
||||||
|
|
||||||
|
compositor: *wl.Compositor,
|
||||||
|
layer_shell: *zwlr.LayerShellV1,
|
||||||
|
xdg_output_manager: *zxdg.OutputManagerV1,
|
||||||
|
outputs: std.ArrayList(*wl.Output),
|
||||||
|
|
||||||
|
const Globals = @This();
|
||||||
|
|
||||||
|
const Collector = col: {
|
||||||
|
var fields: []const std.builtin.Type.StructField = &.{};
|
||||||
|
for (std.meta.fields(Globals)) |field| {
|
||||||
|
const Field = @Type(.{ .Optional = .{ .child = field.type } });
|
||||||
|
fields = fields ++ [1]std.builtin.Type.StructField{.{
|
||||||
|
.name = field.name,
|
||||||
|
.type = Field,
|
||||||
|
.default_value = @ptrCast(&@as(Field, null)),
|
||||||
|
.is_comptime = false,
|
||||||
|
.alignment = @alignOf(Field),
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
break :col @Type(.{ .Struct = .{
|
||||||
|
.layout = .Auto,
|
||||||
|
.fields = fields,
|
||||||
|
.decls = &.{},
|
||||||
|
.is_tuple = false,
|
||||||
|
} });
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn collect(dpy: *wl.Display) !Globals {
|
||||||
|
const registry = try dpy.getRegistry();
|
||||||
|
defer registry.destroy();
|
||||||
|
|
||||||
|
var col = Collector{};
|
||||||
|
|
||||||
|
inline for (std.meta.fields(Globals)) |f| {
|
||||||
|
if (comptime isList(f.type)) {
|
||||||
|
@field(col, f.name) = f.type.init(std.heap.c_allocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errdefer inline for (std.meta.fields(Globals)) |f| {
|
||||||
|
if (comptime isList(f.type)) {
|
||||||
|
@field(col, f.name).?.deinit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
registry.setListener(*Collector, registryListener, &col);
|
||||||
|
|
||||||
|
if (dpy.roundtrip() != .SUCCESS) return error.RoundtipFail;
|
||||||
|
|
||||||
|
// TODO don't use undefined. std.mem.zeroInit complains about non-nullable pointers in struct
|
||||||
|
var self: Globals = undefined;
|
||||||
|
inline for (std.meta.fields(Globals)) |f| {
|
||||||
|
@field(self, f.name) = @field(col, f.name) orelse return error.MissingGlobals;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn registryListener(reg: *wl.Registry, ev: wl.Registry.Event, col: *Collector) void {
|
||||||
|
switch (ev) {
|
||||||
|
.global => |global| {
|
||||||
|
inline for (std.meta.fields(Collector)) |f| {
|
||||||
|
const BaseType = std.meta.Child(f.type);
|
||||||
|
const Interface = std.meta.Child(if (comptime isList(BaseType))
|
||||||
|
std.meta.Child(std.meta.FieldType(BaseType, .items))
|
||||||
|
else
|
||||||
|
BaseType);
|
||||||
|
if (std.mem.orderZ(u8, global.interface, Interface.getInterface().name) == .eq) {
|
||||||
|
log.info("binding global {s}@{}", .{ Interface.getInterface().name, global.name });
|
||||||
|
|
||||||
|
const bound = reg.bind(
|
||||||
|
global.name,
|
||||||
|
Interface,
|
||||||
|
Interface.generated_version,
|
||||||
|
) catch return;
|
||||||
|
|
||||||
|
if (comptime isList(BaseType)) {
|
||||||
|
@field(col, f.name).?.append(bound) catch @panic("OOM");
|
||||||
|
} else {
|
||||||
|
@field(col, f.name) = bound;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.global_remove => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isList(comptime T: type) bool {
|
||||||
|
return @typeInfo(T) == .Struct and
|
||||||
|
@hasDecl(T, "init") and
|
||||||
|
@hasDecl(T, "deinit") and
|
||||||
|
@hasDecl(T, "append");
|
||||||
|
}
|
10
scripts/wlbg/src/OutputInfo.zig
Normal file
10
scripts/wlbg/src/OutputInfo.zig
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const wayland = @import("wayland");
|
||||||
|
|
||||||
|
const wl = wayland.client.wl;
|
||||||
|
const xdg = wayland.client.xdg;
|
||||||
|
|
||||||
|
x: i32 = 0,
|
||||||
|
y: i32 = 0,
|
||||||
|
width: i32 = 0,
|
||||||
|
height: i32 = 0,
|
43
scripts/wlbg/src/bg_frag.glsl
Normal file
43
scripts/wlbg/src/bg_frag.glsl
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#version 300 es
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
uniform float time;
|
||||||
|
uniform vec2 offset;
|
||||||
|
|
||||||
|
in vec2 fragCoord;
|
||||||
|
|
||||||
|
/* "Quasar" by @kishimisu (2023) - https://www.shadertoy.com/view/msGyzc
|
||||||
|
449 => 443 chars thanks to @Xor
|
||||||
|
|
||||||
|
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define r(a) mat2(cos(a + asin(vec4(0,1,-1,0)))),
|
||||||
|
#define X(p) p *= r(round(atan(p.x, p.y) * 4.) / 4.)
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 F = fragCoord - offset + .5;
|
||||||
|
vec3 p, R = vec3(1.);
|
||||||
|
float i, t, d, a, b, T = time * .5 + .5;
|
||||||
|
|
||||||
|
vec4 O = vec4(0.);
|
||||||
|
|
||||||
|
for(O *= i; i++ < 44.;
|
||||||
|
O += .04 * (1. + cos(a + t*.3 - T*.8 + vec4(0,1,2,0)))
|
||||||
|
/ (1. + abs(d)*30.) )
|
||||||
|
|
||||||
|
p = t * normalize(vec3(F+F-R.xy, R.y)),
|
||||||
|
p.z -= 4.,
|
||||||
|
p.xz *= r(T/4.)
|
||||||
|
p.yz *= r(sin(T/4.)*.5)
|
||||||
|
X(p.zx) a = p.x,
|
||||||
|
X(p.yx)
|
||||||
|
p.x = mod(b = p.x - T, .5) - .25,
|
||||||
|
|
||||||
|
t += d = length(p) - (2. - a - smoothstep(b+2., b, T)*30.)
|
||||||
|
* (cos(T/6.+1.)+1.) / 2e2;
|
||||||
|
|
||||||
|
gl_FragColor = O;
|
||||||
|
}
|
||||||
|
|
13
scripts/wlbg/src/bg_vert.glsl
Normal file
13
scripts/wlbg/src/bg_vert.glsl
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#version 300 es
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
attribute vec4 vPos;
|
||||||
|
attribute vec2 monitorOffset;
|
||||||
|
|
||||||
|
out vec2 fragCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = vPos;
|
||||||
|
fragCoord = vPos.xy + monitorOffset * 2.0;
|
||||||
|
}
|
5
scripts/wlbg/src/ffi.zig
Normal file
5
scripts/wlbg/src/ffi.zig
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
pub const c = @cImport({
|
||||||
|
@cInclude("wayland-egl.h"); // required for egl include to work
|
||||||
|
@cInclude("EGL/egl.h");
|
||||||
|
@cInclude("GLES2/gl2.h");
|
||||||
|
});
|
24
scripts/wlbg/src/glutil.zig
Normal file
24
scripts/wlbg/src/glutil.zig
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const c = @import("ffi.zig").c;
|
||||||
|
|
||||||
|
pub fn createShader(shadertype: c_uint, src: []const u8) !c_uint {
|
||||||
|
const id = c.glCreateShader(shadertype);
|
||||||
|
c.glShaderSource(
|
||||||
|
id,
|
||||||
|
1,
|
||||||
|
&[_][*]const u8{src.ptr},
|
||||||
|
&[_]c_int{@as(c_int, @intCast(src.len))},
|
||||||
|
);
|
||||||
|
c.glCompileShader(id);
|
||||||
|
|
||||||
|
var success: c_int = 0;
|
||||||
|
c.glGetShaderiv(id, c.GL_COMPILE_STATUS, &success);
|
||||||
|
|
||||||
|
if (success == 0) {
|
||||||
|
var info_log = std.mem.zeroes([512:0]u8);
|
||||||
|
c.glGetShaderInfoLog(id, info_log.len, null, &info_log);
|
||||||
|
std.log.err("shader compile error:\n{s}", .{&info_log});
|
||||||
|
return error.ShaderCompile;
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
210
scripts/wlbg/src/main.zig
Normal file
210
scripts/wlbg/src/main.zig
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const xev = @import("xev");
|
||||||
|
const wayland = @import("wayland");
|
||||||
|
|
||||||
|
const c = @import("ffi.zig").c;
|
||||||
|
|
||||||
|
const Gfx = @import("Gfx.zig");
|
||||||
|
const Globals = @import("Globals.zig");
|
||||||
|
const OutputInfo = @import("OutputInfo.zig");
|
||||||
|
|
||||||
|
const wl = wayland.client.wl;
|
||||||
|
const zwlr = wayland.client.zwlr;
|
||||||
|
const zxdg = wayland.client.zxdg;
|
||||||
|
|
||||||
|
const fps = 10;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
std.log.info("connecting to wayland display", .{});
|
||||||
|
const dpy = try wl.Display.connect(null);
|
||||||
|
defer dpy.disconnect();
|
||||||
|
const globs = try Globals.collect(dpy);
|
||||||
|
defer globs.outputs.deinit();
|
||||||
|
|
||||||
|
const output_info = try std.heap.c_allocator.alloc(OutputInfo, globs.outputs.items.len);
|
||||||
|
defer std.heap.c_allocator.free(output_info);
|
||||||
|
@memset(output_info, .{});
|
||||||
|
|
||||||
|
for (globs.outputs.items, 0..) |output, i| {
|
||||||
|
const xdg_output = try globs.xdg_output_manager.getXdgOutput(output);
|
||||||
|
xdg_output.setListener(*OutputInfo, xdgOutputListener, &output_info[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dpy.roundtrip() != .SUCCESS) return error.RoundtipFail;
|
||||||
|
|
||||||
|
const egl_dpy = c.eglGetDisplay(@ptrCast(dpy)) orelse return error.EGLError;
|
||||||
|
if (c.eglInitialize(egl_dpy, null, null) != c.EGL_TRUE) return error.EGLError;
|
||||||
|
defer _ = c.eglTerminate(egl_dpy);
|
||||||
|
|
||||||
|
const config = egl_conf: {
|
||||||
|
var config: c.EGLConfig = undefined;
|
||||||
|
var n_config: i32 = 0;
|
||||||
|
if (c.eglChooseConfig(
|
||||||
|
egl_dpy,
|
||||||
|
&[_]i32{
|
||||||
|
c.EGL_SURFACE_TYPE, c.EGL_WINDOW_BIT,
|
||||||
|
c.EGL_RENDERABLE_TYPE, c.EGL_OPENGL_ES2_BIT,
|
||||||
|
c.EGL_RED_SIZE, 8,
|
||||||
|
c.EGL_GREEN_SIZE, 8,
|
||||||
|
c.EGL_BLUE_SIZE, 8,
|
||||||
|
c.EGL_NONE,
|
||||||
|
},
|
||||||
|
&config,
|
||||||
|
1,
|
||||||
|
&n_config,
|
||||||
|
) != c.EGL_TRUE) return error.EGLError;
|
||||||
|
break :egl_conf config;
|
||||||
|
};
|
||||||
|
|
||||||
|
std.log.info("creating EGL context", .{});
|
||||||
|
const egl_ctx = c.eglCreateContext(
|
||||||
|
egl_dpy,
|
||||||
|
config,
|
||||||
|
c.EGL_NO_CONTEXT,
|
||||||
|
&[_]i32{
|
||||||
|
c.EGL_CONTEXT_MAJOR_VERSION, 2,
|
||||||
|
c.EGL_CONTEXT_OPENGL_DEBUG, 1,
|
||||||
|
c.EGL_NONE,
|
||||||
|
},
|
||||||
|
) orelse return error.EGLError;
|
||||||
|
defer _ = c.eglDestroyContext(egl_dpy, egl_ctx);
|
||||||
|
|
||||||
|
const output_windows = try std.heap.c_allocator.alloc(OutputWindow, globs.outputs.items.len);
|
||||||
|
defer std.heap.c_allocator.free(output_windows);
|
||||||
|
|
||||||
|
for (output_windows, 0..) |*output_window, i| {
|
||||||
|
std.log.info("creating EGL surface #{}", .{i});
|
||||||
|
const surface = try globs.compositor.createSurface();
|
||||||
|
|
||||||
|
const lsurf = try globs.layer_shell.getLayerSurface(
|
||||||
|
surface,
|
||||||
|
globs.outputs.items[i],
|
||||||
|
.background,
|
||||||
|
"wlbg",
|
||||||
|
);
|
||||||
|
|
||||||
|
var winsize: ?[2]c_int = null;
|
||||||
|
lsurf.setListener(*?[2]c_int, layerSurfaceListener, &winsize);
|
||||||
|
|
||||||
|
lsurf.setAnchor(.{
|
||||||
|
.top = true,
|
||||||
|
.right = true,
|
||||||
|
.bottom = true,
|
||||||
|
.left = true,
|
||||||
|
});
|
||||||
|
lsurf.setExclusiveZone(-1);
|
||||||
|
|
||||||
|
surface.commit();
|
||||||
|
|
||||||
|
if (dpy.dispatch() != .SUCCESS) return error.DispatchFail;
|
||||||
|
|
||||||
|
const egl_win = win: {
|
||||||
|
std.log.info("creating EGL window #{}", .{i});
|
||||||
|
const size = winsize orelse return error.DidNotGetWindowSize;
|
||||||
|
break :win try wl.EglWindow.create(surface, size[0], size[1]);
|
||||||
|
};
|
||||||
|
errdefer egl_win.destroy();
|
||||||
|
|
||||||
|
const egl_surface = c.eglCreateWindowSurface(
|
||||||
|
egl_dpy,
|
||||||
|
config,
|
||||||
|
@ptrCast(egl_win),
|
||||||
|
null,
|
||||||
|
) orelse return error.EGLError;
|
||||||
|
errdefer _ = c.eglDestroySurface(egl_dpy, egl_surface);
|
||||||
|
|
||||||
|
output_window.* = .{
|
||||||
|
.egl_win = egl_win,
|
||||||
|
.egl_surface = egl_surface,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
defer for (output_windows) |output| output.deinit(egl_ctx);
|
||||||
|
|
||||||
|
var total_width: i32 = 0;
|
||||||
|
var total_height: i32 = 0;
|
||||||
|
|
||||||
|
for (output_info) |inf| {
|
||||||
|
const xmax = inf.x;
|
||||||
|
const ymax = inf.y;
|
||||||
|
|
||||||
|
if (xmax > total_width)
|
||||||
|
total_width = xmax;
|
||||||
|
if (ymax > total_height)
|
||||||
|
total_height = ymax;
|
||||||
|
}
|
||||||
|
|
||||||
|
const base_xoff = @divTrunc(total_width, 2);
|
||||||
|
const base_yoff = @divTrunc(total_height, 2);
|
||||||
|
|
||||||
|
if (c.eglMakeCurrent(
|
||||||
|
egl_dpy,
|
||||||
|
output_windows[0].egl_surface,
|
||||||
|
output_windows[0].egl_surface,
|
||||||
|
egl_ctx,
|
||||||
|
) != c.EGL_TRUE) return error.EGLError;
|
||||||
|
|
||||||
|
var gfx = try Gfx.init(egl_dpy);
|
||||||
|
defer gfx.deinit();
|
||||||
|
|
||||||
|
var timer = try std.time.Timer.start();
|
||||||
|
var prev_time = std.time.milliTimestamp();
|
||||||
|
while (true) {
|
||||||
|
const now_time = std.time.milliTimestamp();
|
||||||
|
const delta_time: f32 = @floatFromInt(now_time - prev_time);
|
||||||
|
prev_time = now_time;
|
||||||
|
|
||||||
|
for (output_windows, output_info) |output, info| {
|
||||||
|
if (c.eglMakeCurrent(
|
||||||
|
egl_dpy,
|
||||||
|
output.egl_surface,
|
||||||
|
output.egl_surface,
|
||||||
|
egl_ctx,
|
||||||
|
) != c.EGL_TRUE) return error.EGLError;
|
||||||
|
try gfx.draw(delta_time, output.egl_surface, info, base_xoff, base_yoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dpy.dispatchPending() != .SUCCESS or dpy.flush() != .SUCCESS) {
|
||||||
|
std.log.err("error processing wayland events", .{});
|
||||||
|
return error.DispatchFail;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elapsed = timer.lap();
|
||||||
|
if (elapsed < 1000 * std.time.ns_per_ms / fps)
|
||||||
|
std.os.nanosleep(0, (1000 * std.time.ns_per_ms) / fps - elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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| {
|
||||||
|
winsize.* = .{ @intCast(configure.width), @intCast(configure.height) };
|
||||||
|
lsurf.setSize(configure.width, configure.height);
|
||||||
|
lsurf.ackConfigure(configure.serial);
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn xdgOutputListener(_: *zxdg.OutputV1, ev: zxdg.OutputV1.Event, info: *OutputInfo) void {
|
||||||
|
switch (ev) {
|
||||||
|
.logical_position => |pos| {
|
||||||
|
info.x = pos.x;
|
||||||
|
info.y = pos.y;
|
||||||
|
},
|
||||||
|
.logical_size => |size| {
|
||||||
|
info.width = size.width;
|
||||||
|
info.height = size.height;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
390
scripts/wlbg/wlr-layer-shell-unstable-v1.xml
Normal file
390
scripts/wlbg/wlr-layer-shell-unstable-v1.xml
Normal file
|
@ -0,0 +1,390 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="wlr_layer_shell_unstable_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2017 Drew DeVault
|
||||||
|
|
||||||
|
Permission to use, copy, modify, distribute, and sell this
|
||||||
|
software and its documentation for any purpose is hereby granted
|
||||||
|
without fee, provided that the above copyright notice appear in
|
||||||
|
all copies and that both that copyright notice and this permission
|
||||||
|
notice appear in supporting documentation, and that the name of
|
||||||
|
the copyright holders not be used in advertising or publicity
|
||||||
|
pertaining to distribution of the software without specific,
|
||||||
|
written prior permission. The copyright holders make no
|
||||||
|
representations about the suitability of this software for any
|
||||||
|
purpose. It is provided "as is" without express or implied
|
||||||
|
warranty.
|
||||||
|
|
||||||
|
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||||
|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||||
|
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||||
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||||
|
THIS SOFTWARE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<interface name="zwlr_layer_shell_v1" version="4">
|
||||||
|
<description summary="create surfaces that are layers of the desktop">
|
||||||
|
Clients can use this interface to assign the surface_layer role to
|
||||||
|
wl_surfaces. Such surfaces are assigned to a "layer" of the output and
|
||||||
|
rendered with a defined z-depth respective to each other. They may also be
|
||||||
|
anchored to the edges and corners of a screen and specify input handling
|
||||||
|
semantics. This interface should be suitable for the implementation of
|
||||||
|
many desktop shell components, and a broad number of other applications
|
||||||
|
that interact with the desktop.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="get_layer_surface">
|
||||||
|
<description summary="create a layer_surface from a surface">
|
||||||
|
Create a layer surface for an existing surface. This assigns the role of
|
||||||
|
layer_surface, or raises a protocol error if another role is already
|
||||||
|
assigned.
|
||||||
|
|
||||||
|
Creating a layer surface from a wl_surface which has a buffer attached
|
||||||
|
or committed is a client error, and any attempts by a client to attach
|
||||||
|
or manipulate a buffer prior to the first layer_surface.configure call
|
||||||
|
must also be treated as errors.
|
||||||
|
|
||||||
|
After creating a layer_surface object and setting it up, the client
|
||||||
|
must perform an initial commit without any buffer attached.
|
||||||
|
The compositor will reply with a layer_surface.configure event.
|
||||||
|
The client must acknowledge it and is then allowed to attach a buffer
|
||||||
|
to map the surface.
|
||||||
|
|
||||||
|
You may pass NULL for output to allow the compositor to decide which
|
||||||
|
output to use. Generally this will be the one that the user most
|
||||||
|
recently interacted with.
|
||||||
|
|
||||||
|
Clients can specify a namespace that defines the purpose of the layer
|
||||||
|
surface.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/>
|
||||||
|
<arg name="surface" type="object" interface="wl_surface"/>
|
||||||
|
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
|
||||||
|
<arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/>
|
||||||
|
<arg name="namespace" type="string" summary="namespace for the layer surface"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="role" value="0" summary="wl_surface has another role"/>
|
||||||
|
<entry name="invalid_layer" value="1" summary="layer value is invalid"/>
|
||||||
|
<entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<enum name="layer">
|
||||||
|
<description summary="available layers for surfaces">
|
||||||
|
These values indicate which layers a surface can be rendered in. They
|
||||||
|
are ordered by z depth, bottom-most first. Traditional shell surfaces
|
||||||
|
will typically be rendered between the bottom and top layers.
|
||||||
|
Fullscreen shell surfaces are typically rendered at the top layer.
|
||||||
|
Multiple surfaces can share a single layer, and ordering within a
|
||||||
|
single layer is undefined.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<entry name="background" value="0"/>
|
||||||
|
<entry name="bottom" value="1"/>
|
||||||
|
<entry name="top" value="2"/>
|
||||||
|
<entry name="overlay" value="3"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<!-- Version 3 additions -->
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor" since="3">
|
||||||
|
<description summary="destroy the layer_shell object">
|
||||||
|
This request indicates that the client will not use the layer_shell
|
||||||
|
object any more. Objects that have been created through this instance
|
||||||
|
are not affected.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_layer_surface_v1" version="4">
|
||||||
|
<description summary="layer metadata interface">
|
||||||
|
An interface that may be implemented by a wl_surface, for surfaces that
|
||||||
|
are designed to be rendered as a layer of a stacked desktop-like
|
||||||
|
environment.
|
||||||
|
|
||||||
|
Layer surface state (layer, size, anchor, exclusive zone,
|
||||||
|
margin, interactivity) is double-buffered, and will be applied at the
|
||||||
|
time wl_surface.commit of the corresponding wl_surface is called.
|
||||||
|
|
||||||
|
Attaching a null buffer to a layer surface unmaps it.
|
||||||
|
|
||||||
|
Unmapping a layer_surface means that the surface cannot be shown by the
|
||||||
|
compositor until it is explicitly mapped again. The layer_surface
|
||||||
|
returns to the state it had right after layer_shell.get_layer_surface.
|
||||||
|
The client can re-map the surface by performing a commit without any
|
||||||
|
buffer attached, waiting for a configure event and handling it as usual.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="set_size">
|
||||||
|
<description summary="sets the size of the surface">
|
||||||
|
Sets the size of the surface in surface-local coordinates. The
|
||||||
|
compositor will display the surface centered with respect to its
|
||||||
|
anchors.
|
||||||
|
|
||||||
|
If you pass 0 for either value, the compositor will assign it and
|
||||||
|
inform you of the assignment in the configure event. You must set your
|
||||||
|
anchor to opposite edges in the dimensions you omit; not doing so is a
|
||||||
|
protocol error. Both values are 0 by default.
|
||||||
|
|
||||||
|
Size is double-buffered, see wl_surface.commit.
|
||||||
|
</description>
|
||||||
|
<arg name="width" type="uint"/>
|
||||||
|
<arg name="height" type="uint"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_anchor">
|
||||||
|
<description summary="configures the anchor point of the surface">
|
||||||
|
Requests that the compositor anchor the surface to the specified edges
|
||||||
|
and corners. If two orthogonal edges are specified (e.g. 'top' and
|
||||||
|
'left'), then the anchor point will be the intersection of the edges
|
||||||
|
(e.g. the top left corner of the output); otherwise the anchor point
|
||||||
|
will be centered on that edge, or in the center if none is specified.
|
||||||
|
|
||||||
|
Anchor is double-buffered, see wl_surface.commit.
|
||||||
|
</description>
|
||||||
|
<arg name="anchor" type="uint" enum="anchor"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_exclusive_zone">
|
||||||
|
<description summary="configures the exclusive geometry of this surface">
|
||||||
|
Requests that the compositor avoids occluding an area with other
|
||||||
|
surfaces. The compositor's use of this information is
|
||||||
|
implementation-dependent - do not assume that this region will not
|
||||||
|
actually be occluded.
|
||||||
|
|
||||||
|
A positive value is only meaningful if the surface is anchored to one
|
||||||
|
edge or an edge and both perpendicular edges. If the surface is not
|
||||||
|
anchored, anchored to only two perpendicular edges (a corner), anchored
|
||||||
|
to only two parallel edges or anchored to all edges, a positive value
|
||||||
|
will be treated the same as zero.
|
||||||
|
|
||||||
|
A positive zone is the distance from the edge in surface-local
|
||||||
|
coordinates to consider exclusive.
|
||||||
|
|
||||||
|
Surfaces that do not wish to have an exclusive zone may instead specify
|
||||||
|
how they should interact with surfaces that do. If set to zero, the
|
||||||
|
surface indicates that it would like to be moved to avoid occluding
|
||||||
|
surfaces with a positive exclusive zone. If set to -1, the surface
|
||||||
|
indicates that it would not like to be moved to accommodate for other
|
||||||
|
surfaces, and the compositor should extend it all the way to the edges
|
||||||
|
it is anchored to.
|
||||||
|
|
||||||
|
For example, a panel might set its exclusive zone to 10, so that
|
||||||
|
maximized shell surfaces are not shown on top of it. A notification
|
||||||
|
might set its exclusive zone to 0, so that it is moved to avoid
|
||||||
|
occluding the panel, but shell surfaces are shown underneath it. A
|
||||||
|
wallpaper or lock screen might set their exclusive zone to -1, so that
|
||||||
|
they stretch below or over the panel.
|
||||||
|
|
||||||
|
The default value is 0.
|
||||||
|
|
||||||
|
Exclusive zone is double-buffered, see wl_surface.commit.
|
||||||
|
</description>
|
||||||
|
<arg name="zone" type="int"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_margin">
|
||||||
|
<description summary="sets a margin from the anchor point">
|
||||||
|
Requests that the surface be placed some distance away from the anchor
|
||||||
|
point on the output, in surface-local coordinates. Setting this value
|
||||||
|
for edges you are not anchored to has no effect.
|
||||||
|
|
||||||
|
The exclusive zone includes the margin.
|
||||||
|
|
||||||
|
Margin is double-buffered, see wl_surface.commit.
|
||||||
|
</description>
|
||||||
|
<arg name="top" type="int"/>
|
||||||
|
<arg name="right" type="int"/>
|
||||||
|
<arg name="bottom" type="int"/>
|
||||||
|
<arg name="left" type="int"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<enum name="keyboard_interactivity">
|
||||||
|
<description summary="types of keyboard interaction possible for a layer shell surface">
|
||||||
|
Types of keyboard interaction possible for layer shell surfaces. The
|
||||||
|
rationale for this is twofold: (1) some applications are not interested
|
||||||
|
in keyboard events and not allowing them to be focused can improve the
|
||||||
|
desktop experience; (2) some applications will want to take exclusive
|
||||||
|
keyboard focus.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<entry name="none" value="0">
|
||||||
|
<description summary="no keyboard focus is possible">
|
||||||
|
This value indicates that this surface is not interested in keyboard
|
||||||
|
events and the compositor should never assign it the keyboard focus.
|
||||||
|
|
||||||
|
This is the default value, set for newly created layer shell surfaces.
|
||||||
|
|
||||||
|
This is useful for e.g. desktop widgets that display information or
|
||||||
|
only have interaction with non-keyboard input devices.
|
||||||
|
</description>
|
||||||
|
</entry>
|
||||||
|
<entry name="exclusive" value="1">
|
||||||
|
<description summary="request exclusive keyboard focus">
|
||||||
|
Request exclusive keyboard focus if this surface is above the shell surface layer.
|
||||||
|
|
||||||
|
For the top and overlay layers, the seat will always give
|
||||||
|
exclusive keyboard focus to the top-most layer which has keyboard
|
||||||
|
interactivity set to exclusive. If this layer contains multiple
|
||||||
|
surfaces with keyboard interactivity set to exclusive, the compositor
|
||||||
|
determines the one receiving keyboard events in an implementation-
|
||||||
|
defined manner. In this case, no guarantee is made when this surface
|
||||||
|
will receive keyboard focus (if ever).
|
||||||
|
|
||||||
|
For the bottom and background layers, the compositor is allowed to use
|
||||||
|
normal focus semantics.
|
||||||
|
|
||||||
|
This setting is mainly intended for applications that need to ensure
|
||||||
|
they receive all keyboard events, such as a lock screen or a password
|
||||||
|
prompt.
|
||||||
|
</description>
|
||||||
|
</entry>
|
||||||
|
<entry name="on_demand" value="2" since="4">
|
||||||
|
<description summary="request regular keyboard focus semantics">
|
||||||
|
This requests the compositor to allow this surface to be focused and
|
||||||
|
unfocused by the user in an implementation-defined manner. The user
|
||||||
|
should be able to unfocus this surface even regardless of the layer
|
||||||
|
it is on.
|
||||||
|
|
||||||
|
Typically, the compositor will want to use its normal mechanism to
|
||||||
|
manage keyboard focus between layer shell surfaces with this setting
|
||||||
|
and regular toplevels on the desktop layer (e.g. click to focus).
|
||||||
|
Nevertheless, it is possible for a compositor to require a special
|
||||||
|
interaction to focus or unfocus layer shell surfaces (e.g. requiring
|
||||||
|
a click even if focus follows the mouse normally, or providing a
|
||||||
|
keybinding to switch focus between layers).
|
||||||
|
|
||||||
|
This setting is mainly intended for desktop shell components (e.g.
|
||||||
|
panels) that allow keyboard interaction. Using this option can allow
|
||||||
|
implementing a desktop shell that can be fully usable without the
|
||||||
|
mouse.
|
||||||
|
</description>
|
||||||
|
</entry>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="set_keyboard_interactivity">
|
||||||
|
<description summary="requests keyboard events">
|
||||||
|
Set how keyboard events are delivered to this surface. By default,
|
||||||
|
layer shell surfaces do not receive keyboard events; this request can
|
||||||
|
be used to change this.
|
||||||
|
|
||||||
|
This setting is inherited by child surfaces set by the get_popup
|
||||||
|
request.
|
||||||
|
|
||||||
|
Layer surfaces receive pointer, touch, and tablet events normally. If
|
||||||
|
you do not want to receive them, set the input region on your surface
|
||||||
|
to an empty region.
|
||||||
|
|
||||||
|
Keyboard interactivity is double-buffered, see wl_surface.commit.
|
||||||
|
</description>
|
||||||
|
<arg name="keyboard_interactivity" type="uint" enum="keyboard_interactivity"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="get_popup">
|
||||||
|
<description summary="assign this layer_surface as an xdg_popup parent">
|
||||||
|
This assigns an xdg_popup's parent to this layer_surface. This popup
|
||||||
|
should have been created via xdg_surface::get_popup with the parent set
|
||||||
|
to NULL, and this request must be invoked before committing the popup's
|
||||||
|
initial state.
|
||||||
|
|
||||||
|
See the documentation of xdg_popup for more details about what an
|
||||||
|
xdg_popup is and how it is used.
|
||||||
|
</description>
|
||||||
|
<arg name="popup" type="object" interface="xdg_popup"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="ack_configure">
|
||||||
|
<description summary="ack a configure event">
|
||||||
|
When a configure event is received, if a client commits the
|
||||||
|
surface in response to the configure event, then the client
|
||||||
|
must make an ack_configure request sometime before the commit
|
||||||
|
request, passing along the serial of the configure event.
|
||||||
|
|
||||||
|
If the client receives multiple configure events before it
|
||||||
|
can respond to one, it only has to ack the last configure event.
|
||||||
|
|
||||||
|
A client is not required to commit immediately after sending
|
||||||
|
an ack_configure request - it may even ack_configure several times
|
||||||
|
before its next surface commit.
|
||||||
|
|
||||||
|
A client may send multiple ack_configure requests before committing, but
|
||||||
|
only the last request sent before a commit indicates which configure
|
||||||
|
event the client really is responding to.
|
||||||
|
</description>
|
||||||
|
<arg name="serial" type="uint" summary="the serial from the configure event"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the layer_surface">
|
||||||
|
This request destroys the layer surface.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="configure">
|
||||||
|
<description summary="suggest a surface change">
|
||||||
|
The configure event asks the client to resize its surface.
|
||||||
|
|
||||||
|
Clients should arrange their surface for the new states, and then send
|
||||||
|
an ack_configure request with the serial sent in this configure event at
|
||||||
|
some point before committing the new surface.
|
||||||
|
|
||||||
|
The client is free to dismiss all but the last configure event it
|
||||||
|
received.
|
||||||
|
|
||||||
|
The width and height arguments specify the size of the window in
|
||||||
|
surface-local coordinates.
|
||||||
|
|
||||||
|
The size is a hint, in the sense that the client is free to ignore it if
|
||||||
|
it doesn't resize, pick a smaller size (to satisfy aspect ratio or
|
||||||
|
resize in steps of NxM pixels). If the client picks a smaller size and
|
||||||
|
is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the
|
||||||
|
surface will be centered on this axis.
|
||||||
|
|
||||||
|
If the width or height arguments are zero, it means the client should
|
||||||
|
decide its own window dimension.
|
||||||
|
</description>
|
||||||
|
<arg name="serial" type="uint"/>
|
||||||
|
<arg name="width" type="uint"/>
|
||||||
|
<arg name="height" type="uint"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="closed">
|
||||||
|
<description summary="surface should be closed">
|
||||||
|
The closed event is sent by the compositor when the surface will no
|
||||||
|
longer be shown. The output may have been destroyed or the user may
|
||||||
|
have asked for it to be removed. Further changes to the surface will be
|
||||||
|
ignored. The client should destroy the resource after receiving this
|
||||||
|
event, and create a new surface if they so choose.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/>
|
||||||
|
<entry name="invalid_size" value="1" summary="size is invalid"/>
|
||||||
|
<entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
|
||||||
|
<entry name="invalid_keyboard_interactivity" value="3" summary="keyboard interactivity is invalid"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<enum name="anchor" bitfield="true">
|
||||||
|
<entry name="top" value="1" summary="the top edge of the anchor rectangle"/>
|
||||||
|
<entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/>
|
||||||
|
<entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
|
||||||
|
<entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<!-- Version 2 additions -->
|
||||||
|
|
||||||
|
<request name="set_layer" since="2">
|
||||||
|
<description summary="change the layer of the surface">
|
||||||
|
Change the layer that the surface is rendered on.
|
||||||
|
|
||||||
|
Layer is double-buffered, see wl_surface.commit.
|
||||||
|
</description>
|
||||||
|
<arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
|
@ -31,6 +31,7 @@
|
||||||
(install-zig "scripts/randomwallpaper")
|
(install-zig "scripts/randomwallpaper")
|
||||||
(install-zig "scripts/vinput")
|
(install-zig "scripts/vinput")
|
||||||
(install-zig "scripts/withjava")
|
(install-zig "scripts/withjava")
|
||||||
|
(install-zig "scripts/wlbg")
|
||||||
|
|
||||||
(install-roswell "scripts/launchmenu.ros")
|
(install-roswell "scripts/launchmenu.ros")
|
||||||
(install-roswell "scripts/playvid.ros")
|
(install-roswell "scripts/playvid.ros")
|
||||||
|
|
Loading…
Reference in a new issue