Make more progress towards tinywl in zig

This commit is contained in:
Isaac Freund 2020-03-19 21:30:38 +01:00
parent 55506099e9
commit 0c6886cae3
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11

View File

@ -1,11 +1,24 @@
const std = @import("std");
const c = @cImport({
@cDefine("WLR_USE_UNSTABLE", {});
@cInclude("wayland-server-core.h");
@cInclude("wlr/backend.h");
@cInclude("wlr/render/wlr_renderer.h");
@cInclude("wlr/types/wlr_cursor.h");
@cInclude("wlr/types/wlr_compositor.h");
@cInclude("wlr/types/wlr_data_device.h");
@cInclude("wlr/types/wlr_input_device.h");
@cInclude("wlr/types/wlr_keyboard.h");
@cInclude("wlr/types/wlr_matrix.h");
@cInclude("wlr/types/wlr_output.h");
@cInclude("wlr/types/wlr_output_layout.h");
@cInclude("wlr/types/wlr_pointer.h");
@cInclude("wlr/types/wlr_seat.h");
@cInclude("wlr/types/wlr_xcursor_manager.h");
@cInclude("wlr/types/wlr_xdg_shell.h");
@cInclude("wlr/util/log.h");
@cInclude("wlr/types/wlr_xdg_shell.h>");
@cInclude("xkbcommon/xkbcommon.h");
});
const std = @import("std");
const CursorMode = enum {
Passthrough,
@ -27,10 +40,118 @@ fn create_listener() c.wl_listener {
};
}
const RenderData = struct {
output: *c.wlr_output,
renderer: *c.wlr_renderer,
view: *View,
when: *std.os.timespec,
};
fn output_frame(listener: *c.wl_listener, data: *c_void) void {
// This function is called every time an output is ready to display a frame,
// generally at the output's refresh rate (e.g. 60Hz). */
var output = @fieldParentPtr(Output, "frame", listener);
var renderer = output.*.server.*.renderer;
var now = undefined;
std.os.linux.clock_gettime(std.os.CLOCK_MONOTONIC, &now);
// wlr_output_attach_render makes the OpenGL context current.
if (!c.wlr_output_attach_render(output.*.wlr_output, null)) {
return;
}
// The "effective" resolution can change if you rotate your outputs.
var width = undefined;
var height = undefined;
c.wlr_output_effective_resolution(output.*.wlr_output, &width, &height);
// Begin the renderer (calls glViewport and some other GL sanity checks)
c.wlr_renderer_begin(renderer, width, height);
const color = [_]f32{ 0.3, 0.3, 0.3, 1.0 };
c.wlr_renderer_clear(renderer, color);
// Each subsequent window we render is rendered on top of the last. Because
// our view list is ordered front-to-back, we iterate over it backwards.
// wl_list_for_each_reverse(view, &output.*.server.*.views, link) {
var view = @fieldParentPtr(View, "link", &output.*.server.*.views.*.prev);
while (&view.*.link != &output.*.server.*.views) {
if (!view.*.mapped) {
// An unmapped view should not be rendered.
continue;
}
var rdata = RenderData{
.output = output.*.wlr_output,
.view = view,
.renderer = renderer,
.when = &now,
};
// This calls our render_surface function for each surface among the
// xdg_surface's toplevel and popups.
c.wlr_xdg_surface_for_each_surface(view.*.xdg_surface, render_surface, &rdata);
// Move to next item in list
view = @fieldParentPtr(View, "link", view.*.link.*.prev);
}
// Hardware cursors are rendered by the GPU on a separate plane, and can be
// moved around without re-rendering what's beneath them - which is more
// efficient. However, not all hardware supports hardware cursors. For this
// reason, wlroots provides a software fallback, which we ask it to render
// here. wlr_cursor handles configuring hardware vs software cursors for you,
// and this function is a no-op when hardware cursors are in use.
c.wlr_output_render_software_cursors(output.*.wlr_output, null);
// Conclude rendering and swap the buffers, showing the final frame
// on-screen.
c.wlr_renderer_end(renderer);
c.wlr_output_commit(output.*.wlr_output);
}
fn server_new_output(listener: *c.wl_listener, data: *c_void) void {
var server = @fieldParentPtr(Server, "new_output", listener);
var wlr_output = @ptrCast(c.wlr_output, data);
// Some backends don't have modes. DRM+KMS does, and we need to set a mode
// before we can use the output. The mode is a tuple of (width, height,
// refresh rate), and each monitor supports only a specific set of modes. We
// just pick the monitor's preferred mode, a more sophisticated compositor
// would let the user configure it.
if (!c.wl_list_empty(&wlr_output.*.modes)) {
var mode = wlr_output_preferred_mode(wlr_output);
c.wlr_output_set_mode(wlr_output, mode);
c.wlr_output_enable(wlr_output, true);
if (!c.wlr_output_commit(wlr_output)) {
return;
}
}
// Allocates and configures our state for this output
var output = std.heap.c_allocator.create(Output) catch unreachable;
output.*.wlr_output = wlr_output;
output.*.server = server;
// Sets up a listener for the frame notify event.
output.*.frame.notify = output_frame;
c.wl_signal_add(&wlr_output.*.events.frame, &output.*.frame);
c.wl_list_insert(&server.*.outputs, &output.*.link);
// Adds this to the output layout. The add_auto function arranges outputs
// from left-to-right in the order they appear. A more sophisticated
// compositor would let the user configure the arrangement of outputs in the
// layout.
c.wlr_output_layout_add_auto(server.*.output_layout, wlr_output);
// Creating the global adds a wl_output global to the display, which Wayland
// clients can see to find out information about the output (such as
// DPI, scale factor, manufacturer, etc).
c.wlr_output_create_global(wlr_output);
}
const Server = struct {
wl_display: ?*c.wl_display,
backend: ?*c.wlr_backend,
renderer: ?*c.wlr_renderer,
wl_display: *c.wl_display,
backend: *c.wlr_backend,
renderer: *c.wlr_renderer,
xdg_shell: ?*c.wlr_xdg_shell,
new_xdg_surface: c.wl_listener,
@ -49,7 +170,7 @@ const Server = struct {
request_cursor: c.wl_listener,
keyboards: c.wl_list,
cursor_mode: CursorMode,
grabbed_view: ?*c.tinywl_view,
grabbed_view: ?*View,
grab_x: f64,
grab_y: f64,
grab_width: c_int,
@ -59,6 +180,95 @@ const Server = struct {
output_layout: ?*c.wlr_output_layout,
outputs: c.wl_list,
new_output: c.wl_listener,
fn create() Server {
const wl_display = c.wl_display_create();
const backend = c.wlr_backend_autocreate(wl_display, null);
const renderer = c.wlr_backend_get_renderer(server.backend);
wlr_renderer_init_wl_display(renderer, wl_display);
wlr_compositor_create(wl_display, renderer);
wlr_data_device_manager_create(wl_display);
const output_layout = wlr_output_layout_create();
var outputs = create_list();
wl_list_init(&outputs);
new_output = create_listener();
server.new_output.notify = server_new_output;
wl_signal_add(&server.backend.*.events.new_output, &server.new_output);
return Server{
.wl_display = wl_display,
.backend = backend,
.renderer = null,
.xdg_shell = null,
.new_xdg_surface = create_listener(),
.views = create_list(),
.cursor = null,
.cursor_mgr = null,
.cursor_motion = create_listener(),
.cursor_motion_absolute = create_listener(),
.cursor_button = create_listener(),
.cursor_axis = create_listener(),
.cursor_frame = create_listener(),
.seat = null,
.new_input = create_listener(),
.request_cursor = create_listener(),
.keyboards = create_list(),
.cursor_mode = CursorMode.Passthrough,
.grabbed_view = null,
.grab_x = 0.0,
.grab_y = 0.0,
.grab_width = 0,
.grab_height = 0,
.resize_edges = 0,
.output_layout = null,
.outputs = c.wl_list{ .prev = null, .next = null },
.new_output = create_listener(),
};
}
};
const Output = struct {
link: c.wl_list,
server: *c.tinywl_server,
xdg_surface: ?*c.wlr_xdg_surface,
map: c.wl_listener,
unmap: c.wl_listener,
destroy: c.wl_listener,
request_move: c.wl_listener,
request_resize: c.wl_listener,
mapped: bool,
x: c_int,
y: c_int,
};
const View = struct {
link: c.wl_list,
server: *Server,
xdg_surface: ?*c.wlr_xdg_surface,
map: c.wl_listener,
unmap: c.wl_listener,
destroy: c.wl_listener,
request_move: c.wl_listener,
request_resize: c.wl_listener,
mapped: bool,
x: c_int,
y: c_int,
};
const Keyboard = struct {
link: c.wl_list,
server: *Server,
device: ?*c.wlr_input_device,
modifiers: c.wl_listener,
key: c.wl_listener,
};
pub fn main() !void {
@ -66,37 +276,5 @@ pub fn main() !void {
c.wlr_log_init(c.enum_wlr_log_importance.WLR_DEBUG, null);
var server = Server{
.wl_display = null,
.backend = null,
.renderer = null,
.xdg_shell = null,
.new_xdg_surface = create_listener(),
.views = c.wl_list,
.cursor = null,
.cursor_mgr = null,
.cursor_motion = create_listener(),
.cursor_motion_absolute = create_listener(),
.cursor_button = create_listener(),
.cursor_axis = create_listener(),
.cursor_frame = create_listener(),
.seat = null,
.new_input = create_listener(),
.request_cursor = create_listener(),
.keyboards = c.wl_list,
.cursor_mode = CursorMode.Passthrough,
.grabbed_view = null,
.grab_x = 0.0,
.grab_y = 0.0,
.grab_width = 0,
.grab_height = 0,
.resize_edges = 0,
.output_layout = null,
.outputs = c.wl_list{ .prev = null, .next = null },
.new_output = create_listener(){},
};
var server = Server.create();
}