Begin setting up infrastructure for the WM
Mostly just created the very basic Wayland connection needed, but I also bind to the rwm protocol which is neat.
This commit is contained in:
parent
8eec239af6
commit
c87fa2d4af
7 changed files with 1858 additions and 7 deletions
8
LICENSES/ISC.txt
Normal file
8
LICENSES/ISC.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
ISC License:
|
||||||
|
|
||||||
|
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
Copyright (c) 1995-2003 by Internet Software Consortium
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 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.
|
||||||
10
build.zig
10
build.zig
|
|
@ -5,9 +5,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Scanner = @import("wayland").Scanner;
|
const Scanner = @import("wayland").Scanner;
|
||||||
|
|
||||||
// Although this function looks imperative, note that its job is to
|
|
||||||
// declaratively construct a build graph that will be executed by an external
|
|
||||||
// runner.
|
|
||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
@ -19,6 +16,13 @@ pub fn build(b: *std.Build) void {
|
||||||
const scanner = Scanner.create(b, .{});
|
const scanner = Scanner.create(b, .{});
|
||||||
const wayland = b.createModule(.{ .root_source_file = scanner.result });
|
const wayland = b.createModule(.{ .root_source_file = scanner.result });
|
||||||
|
|
||||||
|
scanner.addCustomProtocol(b.path("protocol/river-window-management-v1.xml"));
|
||||||
|
|
||||||
|
scanner.generate("wl_compositor", 4);
|
||||||
|
scanner.generate("wl_shm", 1);
|
||||||
|
scanner.generate("wl_output", 4);
|
||||||
|
scanner.generate("river_window_manager_v1", 1);
|
||||||
|
|
||||||
const exe = b.addExecutable(.{
|
const exe = b.addExecutable(.{
|
||||||
.name = "beansprout",
|
.name = "beansprout",
|
||||||
.root_source_file = b.path("src/main.zig"),
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
|
|
||||||
5
examples/init
Executable file
5
examples/init
Executable file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
./zig-out/bin/beansprout &
|
||||||
|
|
||||||
|
/usr/bin/foot &
|
||||||
1690
protocol/river-window-management-v1.xml
Normal file
1690
protocol/river-window-management-v1.xml
Normal file
File diff suppressed because it is too large
Load diff
112
src/Backend.zig
Normal file
112
src/Backend.zig
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Ben Buhse <me@benbuhse.email>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
const wayland = @import("wayland");
|
||||||
|
const wl = wayland.client.wl;
|
||||||
|
const river = wayland.client.river;
|
||||||
|
|
||||||
|
const log = std.log.scoped(.Backend);
|
||||||
|
|
||||||
|
const Backend = @This();
|
||||||
|
|
||||||
|
allocator: mem.Allocator,
|
||||||
|
initialized: bool,
|
||||||
|
|
||||||
|
display: *wl.Display,
|
||||||
|
registry: *wl.Registry,
|
||||||
|
|
||||||
|
compositor: ?*wl.Compositor = null,
|
||||||
|
shm: ?*wl.Shm = null,
|
||||||
|
|
||||||
|
window_manager: ?*river.WindowManagerV1 = null,
|
||||||
|
|
||||||
|
// outputs: std.SinglyLinkedList(Output) = .{},
|
||||||
|
|
||||||
|
/// Return a new Backend
|
||||||
|
pub fn init(allocator: mem.Allocator) !Backend {
|
||||||
|
const wl_display = wl.Display.connect(null) catch {
|
||||||
|
log.err("Error connecting to Wayland. Exiting", .{});
|
||||||
|
std.posix.exit(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
var backend: Backend = .{
|
||||||
|
.initialized = false,
|
||||||
|
.allocator = allocator,
|
||||||
|
.display = wl_display,
|
||||||
|
.registry = try wl_display.getRegistry(),
|
||||||
|
};
|
||||||
|
backend.registry.setListener(*Backend, registry_listener, &backend);
|
||||||
|
|
||||||
|
// Do an initial roundtrip so the registry globals fire
|
||||||
|
const errno = backend.display.roundtrip();
|
||||||
|
if (errno != .SUCCESS) {
|
||||||
|
log.err("Initial roundtrip failed: E{s}", .{@tagName(errno)});
|
||||||
|
std.posix.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are all required by beansprout.
|
||||||
|
// If we are missing any of them, then let's exit.
|
||||||
|
if (backend.compositor == null) interface_not_advertised(wl.Compositor);
|
||||||
|
if (backend.shm == null) interface_not_advertised(wl.Shm);
|
||||||
|
if (backend.window_manager == null) interface_not_advertised(river.WindowManagerV1);
|
||||||
|
|
||||||
|
return backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deinitialize a Backend
|
||||||
|
pub fn deinit(backend: *Backend) void {
|
||||||
|
_ = backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn registry_listener(registry: *wl.Registry, event: wl.Registry.Event, backend: *Backend) void {
|
||||||
|
// Since we can't return errors from the listener, we use a helper function so that
|
||||||
|
// we can easily log any errors the same way.
|
||||||
|
registry_listener_helper(registry, event, backend) catch |err| {
|
||||||
|
log.err("{any}", .{err});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn registry_listener_helper(registry: *wl.Registry, event: wl.Registry.Event, backend: *Backend) !void {
|
||||||
|
// Use a helper function to log errors; the actual listener can't return an error.
|
||||||
|
switch (event) {
|
||||||
|
.global => |ev| {
|
||||||
|
if (mem.orderZ(u8, ev.interface, wl.Compositor.interface.name) == .eq) {
|
||||||
|
if (ev.version < 4) version_not_supported(wl.Compositor, ev.version, 4);
|
||||||
|
backend.compositor = try registry.bind(ev.name, wl.Compositor, 4);
|
||||||
|
} else if (mem.orderZ(u8, ev.interface, wl.Shm.interface.name) == .eq) {
|
||||||
|
backend.shm = try registry.bind(ev.name, wl.Shm, 1);
|
||||||
|
} else if (mem.orderZ(u8, ev.interface, river.WindowManagerV1.interface.name) == .eq) {
|
||||||
|
backend.window_manager = try registry.bind(ev.name, river.WindowManagerV1, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.global_remove => |ev| {
|
||||||
|
log.debug("TODO...", .{});
|
||||||
|
_ = ev;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_manager_listener(window_manager: *river.WindowManagerV1, event: river.WindowManagerV1.Event, backend: *Backend) !void {
|
||||||
|
_ = backend;
|
||||||
|
_ = window_manager;
|
||||||
|
switch (event) {
|
||||||
|
.update_windowing_start => log.debug("RAAAA"),
|
||||||
|
.update_windowing_end => log.debug("REEE"),
|
||||||
|
else => log.debug("WOOOO"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interface_not_advertised(comptime WaylandGlobal: type) noreturn {
|
||||||
|
log.err("{s} not advertised. Exiting", .{WaylandGlobal.interface.name});
|
||||||
|
std.posix.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version_not_supported(comptime WaylandGlobal: type, have_version: u32, need_version: u32) noreturn {
|
||||||
|
log.err("The compositor only advertised {s} version {d} but version {d} is required. Exiting", .{ WaylandGlobal.interface.name, have_version, need_version });
|
||||||
|
std.posix.exit(1);
|
||||||
|
}
|
||||||
9
src/event_loop.zig
Normal file
9
src/event_loop.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Ben Buhse <me@benbuhse.email>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn run() void {
|
||||||
|
while (true) {}
|
||||||
|
}
|
||||||
31
src/main.zig
31
src/main.zig
|
|
@ -2,8 +2,31 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: EUPL-1.2
|
// SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
std.debug.print("All your {s} are belong to us.\n", .{"protocol"});
|
|
||||||
}
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
const event_loop = @import("event_loop.zig");
|
||||||
|
const Backend = @import("Backend.zig");
|
||||||
|
|
||||||
|
const log = std.log.scoped(.main);
|
||||||
|
|
||||||
|
const usage: []const u8 =
|
||||||
|
\\usage: beansprout [options]
|
||||||
|
\\
|
||||||
|
\\ -i, --image <PATH> TODO TODO TODO TODO
|
||||||
|
\\ -h, --help TODO TODO TODO TODO
|
||||||
|
\\ -V, --version TODO TODO TODO TODO
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
const allocator = std.heap.c_allocator;
|
||||||
|
|
||||||
|
// Set up Wayland stuff
|
||||||
|
var backend = try Backend.init(allocator);
|
||||||
|
defer backend.deinit();
|
||||||
|
|
||||||
|
event_loop.run();
|
||||||
|
|
||||||
|
// TODO: REMOVEME
|
||||||
|
log.debug("Exiting...", .{});
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue