Initial atomic layout update implementation
This commit is contained in:
		| @ -5,8 +5,9 @@ pub const c = @cImport({ | ||||
|     @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_buffer.h"); | ||||
|     @cInclude("wlr/types/wlr_compositor.h"); | ||||
|     @cInclude("wlr/types/wlr_cursor.h"); | ||||
|     @cInclude("wlr/types/wlr_data_device.h"); | ||||
|     @cInclude("wlr/types/wlr_input_device.h"); | ||||
|     @cInclude("wlr/types/wlr_keyboard.h"); | ||||
|  | ||||
| @ -98,8 +98,8 @@ pub const Cursor = struct { | ||||
|         // Move the grabbed view to the new position. | ||||
|         // TODO: log on null | ||||
|         if (self.grabbed_view) |view| { | ||||
|             view.x = @floatToInt(c_int, self.wlr_cursor.x - self.grab_x); | ||||
|             view.y = @floatToInt(c_int, self.wlr_cursor.y - self.grab_y); | ||||
|             view.current_state.x = @floatToInt(c_int, self.wlr_cursor.x - self.grab_x); | ||||
|             view.current_state.y = @floatToInt(c_int, self.wlr_cursor.y - self.grab_y); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -119,8 +119,8 @@ pub const Cursor = struct { | ||||
|         const dx: f64 = self.wlr_cursor.x - self.grab_x; | ||||
|         const dy: f64 = self.wlr_cursor.y - self.grab_y; | ||||
|  | ||||
|         var x: f64 = @intToFloat(f64, view.x); | ||||
|         var y: f64 = @intToFloat(f64, view.y); | ||||
|         var x: f64 = @intToFloat(f64, view.current_state.x); | ||||
|         var y: f64 = @intToFloat(f64, view.current_state.y); | ||||
|  | ||||
|         var width = @intToFloat(f64, self.grab_width); | ||||
|         var height = @intToFloat(f64, self.grab_height); | ||||
| @ -143,8 +143,8 @@ pub const Cursor = struct { | ||||
|         } else if (self.resize_edges & @intCast(u32, c.WLR_EDGE_RIGHT) != 0) { | ||||
|             width += dx; | ||||
|         } | ||||
|         view.x = @floatToInt(c_int, x); | ||||
|         view.y = @floatToInt(c_int, y); | ||||
|         view.current_state.x = @floatToInt(c_int, x); | ||||
|         view.current_state.y = @floatToInt(c_int, y); | ||||
|         _ = c.wlr_xdg_toplevel_set_size( | ||||
|             view.wlr_xdg_surface, | ||||
|             @floatToInt(u32, width), | ||||
|  | ||||
| @ -16,7 +16,7 @@ pub const Keyboard = struct { | ||||
|     pub fn init(self: *Self, seat: *Seat, device: *c.wlr_input_device) !void { | ||||
|         self.seat = seat; | ||||
|         self.device = device; | ||||
|         self.wlr_keyboard = device.unnamed_37.keyboard; | ||||
|         self.wlr_keyboard = device.unnamed_133.keyboard; | ||||
|  | ||||
|         // We need to prepare an XKB keymap and assign it to the keyboard. This | ||||
|         // assumes the defaults (e.g. layout = "us"). | ||||
| @ -77,7 +77,7 @@ pub const Keyboard = struct { | ||||
|             @alignCast(@alignOf(*c.wlr_event_keyboard_key), data), | ||||
|         ); | ||||
|  | ||||
|         const wlr_keyboard: *c.wlr_keyboard = keyboard.device.unnamed_37.keyboard; | ||||
|         const wlr_keyboard: *c.wlr_keyboard = keyboard.device.unnamed_133.keyboard; | ||||
|  | ||||
|         // Translate libinput keycode -> xkbcommon | ||||
|         const keycode = event.keycode + 8; | ||||
|  | ||||
							
								
								
									
										104
									
								
								src/output.zig
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								src/output.zig
									
									
									
									
									
								
							| @ -84,19 +84,12 @@ pub const Output = struct { | ||||
|         var it = output.root.views.last; | ||||
|         while (it) |node| : (it = node.prev) { | ||||
|             const view = &node.data; | ||||
|             // TODO: remove this check and move unmaped views back to unmaped TailQueue | ||||
|             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.wlr_xdg_surface, renderSurface, &rdata); | ||||
|             output.renderView(view, &now); | ||||
|         } | ||||
|  | ||||
|         // Hardware cursors are rendered by the GPU on a separate plane, and can be | ||||
| @ -114,9 +107,56 @@ pub const Output = struct { | ||||
|         _ = c.wlr_output_commit(output.wlr_output); | ||||
|     } | ||||
|  | ||||
|     fn renderSurface(opt_surface: ?*c.wlr_surface, sx: c_int, sy: c_int, data: ?*c_void) callconv(.C) void { | ||||
|     fn renderView(self: *Self, view: *View, now: *c.struct_timespec) void { | ||||
|         // If we have a stashed buffer, we are in the middle of a transaction | ||||
|         // and need to render that buffer until the transaction is complete. | ||||
|         if (view.stashed_buffer) |buffer| { | ||||
|             var box = c.wlr_box{ | ||||
|                 .x = view.current_state.x, | ||||
|                 .y = view.current_state.y, | ||||
|                 .width = @intCast(c_int, view.current_state.width), | ||||
|                 .height = @intCast(c_int, view.current_state.height), | ||||
|             }; | ||||
|  | ||||
|             // Scale the box to the output's current scaling factor | ||||
|             scaleBox(&box, self.wlr_output.scale); | ||||
|  | ||||
|             var matrix: [9]f32 = undefined; | ||||
|             c.wlr_matrix_project_box( | ||||
|                 &matrix, | ||||
|                 &box, | ||||
|                 c.enum_wl_output_transform.WL_OUTPUT_TRANSFORM_NORMAL, | ||||
|                 0.0, | ||||
|                 &self.wlr_output.transform_matrix, | ||||
|             ); | ||||
|  | ||||
|             // This takes our matrix, the texture, and an alpha, and performs the actual | ||||
|             // rendering on the GPU. | ||||
|             _ = c.wlr_render_texture_with_matrix( | ||||
|                 self.root.server.wlr_renderer, | ||||
|                 buffer.texture, | ||||
|                 &matrix, | ||||
|                 1.0, | ||||
|             ); | ||||
|         } else { | ||||
|             // Since there is no stashed buffer, we are not in the middle of | ||||
|             // a transaction and may simply render each toplevel surface. | ||||
|             var rdata = RenderData{ | ||||
|                 .output = self.wlr_output, | ||||
|                 .view = view, | ||||
|                 .renderer = self.root.server.wlr_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.wlr_xdg_surface, renderSurface, &rdata); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn renderSurface(_surface: ?*c.wlr_surface, sx: c_int, sy: c_int, data: ?*c_void) callconv(.C) void { | ||||
|         // wlroots says this will never be null | ||||
|         const surface = opt_surface.?; | ||||
|         const surface = _surface.?; | ||||
|         // This function is called for every surface that needs to be rendered. | ||||
|         const rdata = @ptrCast(*RenderData, @alignCast(@alignOf(RenderData), data)); | ||||
|         const view = rdata.view; | ||||
| @ -139,27 +179,23 @@ pub const Output = struct { | ||||
|         var ox: f64 = 0.0; | ||||
|         var oy: f64 = 0.0; | ||||
|         c.wlr_output_layout_output_coords(view.root.wlr_output_layout, output, &ox, &oy); | ||||
|         ox += @intToFloat(f64, view.x + sx); | ||||
|         oy += @intToFloat(f64, view.y + sy); | ||||
|         ox += @intToFloat(f64, view.current_state.x + sx); | ||||
|         oy += @intToFloat(f64, view.current_state.y + sy); | ||||
|  | ||||
|         // We also have to apply the scale factor for HiDPI outputs. This is only | ||||
|         // part of the puzzle, TinyWL does not fully support HiDPI. | ||||
|         const box = c.wlr_box{ | ||||
|             .x = @floatToInt(c_int, ox * output.scale), | ||||
|             .y = @floatToInt(c_int, oy * output.scale), | ||||
|             .width = @floatToInt(c_int, @intToFloat(f32, surface.current.width) * output.scale), | ||||
|             .height = @floatToInt(c_int, @intToFloat(f32, surface.current.height) * output.scale), | ||||
|         var box = c.wlr_box{ | ||||
|             .x = @floatToInt(c_int, ox), | ||||
|             .y = @floatToInt(c_int, oy), | ||||
|             .width = @intCast(c_int, surface.current.width), | ||||
|             .height = @intCast(c_int, surface.current.height), | ||||
|         }; | ||||
|  | ||||
|         // Those familiar with OpenGL are also familiar with the role of matricies | ||||
|         // in graphics programming. We need to prepare a matrix to render the view | ||||
|         // with. wlr_matrix_project_box is a helper which takes a box with a desired | ||||
|         // Scale the box to the output's current scaling factor | ||||
|         scaleBox(&box, output.scale); | ||||
|  | ||||
|         // wlr_matrix_project_box is a helper which takes a box with a desired | ||||
|         // x, y coordinates, width and height, and an output geometry, then | ||||
|         // prepares an orthographic projection and multiplies the necessary | ||||
|         // transforms to produce a model-view-projection matrix. | ||||
|         // | ||||
|         // Naturally you can do this any way you like, for example to make a 3D | ||||
|         // compositor. | ||||
|         var matrix: [9]f32 = undefined; | ||||
|         const transform = c.wlr_output_transform_invert(surface.current.transform); | ||||
|         c.wlr_matrix_project_box(&matrix, &box, transform, 0.0, &output.transform_matrix); | ||||
| @ -173,3 +209,19 @@ pub const Output = struct { | ||||
|         c.wlr_surface_send_frame_done(surface, rdata.when); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// Scale a wlr_box, taking the possibility of fractional scaling into account. | ||||
| fn scaleBox(box: *c.wlr_box, scale: f64) void { | ||||
|     box.x = @floatToInt(c_int, @round(@intToFloat(f64, box.x) * scale)); | ||||
|     box.y = @floatToInt(c_int, @round(@intToFloat(f64, box.y) * scale)); | ||||
|     box.width = scaleLength(box.width, box.x, scale); | ||||
|     box.height = scaleLength(box.height, box.x, scale); | ||||
| } | ||||
|  | ||||
| /// Scales a width/height. | ||||
| /// | ||||
| /// This might seem overly complex, but it needs to work for fractional scaling. | ||||
| fn scaleLength(length: c_int, offset: c_int, scale: f64) c_int { | ||||
|     return @floatToInt(c_int, @round(@intToFloat(f64, offset + length) * scale) - | ||||
|         @round(@intToFloat(f64, offset) * scale)); | ||||
| } | ||||
|  | ||||
							
								
								
									
										84
									
								
								src/root.zig
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								src/root.zig
									
									
									
									
									
								
							| @ -17,9 +17,15 @@ pub const Root = struct { | ||||
|  | ||||
|     // Must stay ordered, first N views in list are the masters | ||||
|     views: std.TailQueue(View), | ||||
|     unmapped_views: std.TailQueue(View), | ||||
|  | ||||
|     // Number of pending configures sent in the current transaction. | ||||
|     // A value of 0 means there is no current transaction. | ||||
|     pending_count: u32, | ||||
|  | ||||
|     pub fn init(self: *Self, server: *Server) !void { | ||||
|         self.server = server; | ||||
|         self.pending_count = 0; | ||||
|  | ||||
|         // Create an output layout, which a wlroots utility for working with an | ||||
|         // arrangement of screens in a physical layout. | ||||
| @ -29,6 +35,7 @@ pub const Root = struct { | ||||
|  | ||||
|         self.outputs = std.TailQueue(Output).init(); | ||||
|         self.views = std.TailQueue(View).init(); | ||||
|         self.unmapped_views = std.TailQueue(View).init(); | ||||
|     } | ||||
|  | ||||
|     pub fn destroy(self: *Self) void { | ||||
| @ -45,7 +52,7 @@ pub const Root = struct { | ||||
|     pub fn addView(self: *Self, wlr_xdg_surface: *c.wlr_xdg_surface) void { | ||||
|         const node = self.views.allocateNode(self.server.allocator) catch unreachable; | ||||
|         node.data.init(self, wlr_xdg_surface); | ||||
|         self.views.append(node); | ||||
|         self.unmapped_views.append(node); | ||||
|     } | ||||
|  | ||||
|     /// Finds the top most view under the output layout coordinates lx, ly | ||||
| @ -59,4 +66,79 @@ pub const Root = struct { | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     pub fn arrange(self: *Self) void { | ||||
|         if (self.views.len == 0) { | ||||
|             return; | ||||
|         } | ||||
|         // Super basic vertical layout for now, no master/slave stuff | ||||
|         // This can't return null if pass null as the reference | ||||
|         const output_box: *c.wlr_box = c.wlr_output_layout_get_box(self.wlr_output_layout, null); | ||||
|         const new_height = output_box.height; | ||||
|         // Allow for a 10px gap | ||||
|         const num_views = @intCast(c_int, self.views.len); | ||||
|         const new_width = @divTrunc(output_box.width, num_views) - (num_views - 1) * 10; | ||||
|  | ||||
|         var x: c_int = 0; | ||||
|         var y: c_int = 0; | ||||
|  | ||||
|         var it = self.views.first; | ||||
|         while (it) |node| : (it = node.next) { | ||||
|             const view = &node.data; | ||||
|             view.pending_state.x = x; | ||||
|             view.pending_state.y = y; | ||||
|             view.pending_state.width = @intCast(u32, new_width); | ||||
|             view.pending_state.height = @intCast(u32, new_height); | ||||
|  | ||||
|             x += new_width + 10; | ||||
|         } | ||||
|  | ||||
|         self.startTransaction(); | ||||
|     } | ||||
|  | ||||
|     /// Initiate an atomic change to the layout. This change will not be | ||||
|     /// applied until all affected clients ack a configure and commit a buffer. | ||||
|     fn startTransaction(self: *Self) void { | ||||
|         std.debug.assert(self.pending_count == 0); | ||||
|  | ||||
|         var it = self.views.first; | ||||
|         while (it) |node| : (it = node.next) { | ||||
|             const view = &node.data; | ||||
|             if (view.needsConfigure()) { | ||||
|                 view.configurePending(); | ||||
|                 self.pending_count += 1; | ||||
|  | ||||
|                 // We save the current buffer, so we can send an early | ||||
|                 // frame done event to give the client a head start on | ||||
|                 // redrawing. | ||||
|                 view.sendFrameDone(); | ||||
|             } | ||||
|             view.stashBuffer(); | ||||
|         } | ||||
|  | ||||
|         // TODO: start a timer and handle timeout waiting for all clients to ack | ||||
|     } | ||||
|  | ||||
|     pub fn notifyConfigured(self: *Self) void { | ||||
|         self.pending_count -= 1; | ||||
|         if (self.pending_count == 0) { | ||||
|             self.commitTransaction(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Apply the pending state and drop stashed buffers. This means that | ||||
|     /// the next frame drawn will be the post-transaction state of the | ||||
|     /// layout. Must only be called after all clients have configured for | ||||
|     /// the new layout. | ||||
|     fn commitTransaction(self: *Self) void { | ||||
|         // TODO: apply damage properly | ||||
|         var it = self.views.first; | ||||
|         while (it) |node| : (it = node.next) { | ||||
|             const view = &node.data; | ||||
|  | ||||
|             // TODO: handle views that timed out | ||||
|             view.current_state = view.pending_state; | ||||
|             view.dropStashedBuffer(); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
							
								
								
									
										109
									
								
								src/view.zig
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								src/view.zig
									
									
									
									
									
								
							| @ -3,6 +3,13 @@ const c = @import("c.zig").c; | ||||
|  | ||||
| const Root = @import("root.zig").Root; | ||||
|  | ||||
| pub const ViewState = struct { | ||||
|     x: i32, | ||||
|     y: i32, | ||||
|     width: u32, | ||||
|     height: u32, | ||||
| }; | ||||
|  | ||||
| pub const View = struct { | ||||
|     const Self = @This(); | ||||
|  | ||||
| @ -10,12 +17,20 @@ pub const View = struct { | ||||
|     wlr_xdg_surface: *c.wlr_xdg_surface, | ||||
|  | ||||
|     mapped: bool, | ||||
|     x: c_int, | ||||
|     y: c_int, | ||||
|  | ||||
|     current_state: ViewState, | ||||
|     // TODO: make this a ?ViewState | ||||
|     pending_state: ViewState, | ||||
|  | ||||
|     pending_serial: ?u32, | ||||
|  | ||||
|     // This is what we render while a transaction is in progress | ||||
|     stashed_buffer: ?*c.wlr_buffer, | ||||
|  | ||||
|     listen_map: c.wl_listener, | ||||
|     listen_unmap: c.wl_listener, | ||||
|     listen_destroy: c.wl_listener, | ||||
|     listen_commit: c.wl_listener, | ||||
|     // listen_request_move: c.wl_listener, | ||||
|     // listen_request_resize: c.wl_listener, | ||||
|  | ||||
| @ -24,8 +39,13 @@ pub const View = struct { | ||||
|         self.wlr_xdg_surface = wlr_xdg_surface; | ||||
|  | ||||
|         self.mapped = false; | ||||
|         self.x = 0; | ||||
|         self.y = 0; | ||||
|         self.current_state = ViewState{ | ||||
|             .x = 0, | ||||
|             .y = 0, | ||||
|             .height = 0, | ||||
|             .width = 0, | ||||
|         }; | ||||
|         self.stashed_buffer = null; | ||||
|  | ||||
|         self.listen_map.notify = handleMap; | ||||
|         c.wl_signal_add(&self.wlr_xdg_surface.events.map, &self.listen_map); | ||||
| @ -36,16 +56,62 @@ pub const View = struct { | ||||
|         self.listen_destroy.notify = handleDestroy; | ||||
|         c.wl_signal_add(&self.wlr_xdg_surface.events.destroy, &self.listen_destroy); | ||||
|  | ||||
|         self.listen_commit.notify = handleCommit; | ||||
|         c.wl_signal_add(&self.wlr_xdg_surface.surface.*.events.commit, &self.listen_commit); | ||||
|  | ||||
|         // const toplevel = xdg_surface.unnamed_160.toplevel; | ||||
|         // c.wl_signal_add(&toplevel.events.request_move, &view.request_move); | ||||
|         // c.wl_signal_add(&toplevel.events.request_resize, &view.request_resize); | ||||
|     } | ||||
|  | ||||
|     pub fn needsConfigure(self: *const Self) bool { | ||||
|         return self.pending_state.width != self.current_state.width or | ||||
|             self.pending_state.height != self.current_state.height; | ||||
|     } | ||||
|  | ||||
|     pub fn configurePending(self: *Self) void { | ||||
|         self.pending_serial = c.wlr_xdg_toplevel_set_size( | ||||
|             self.wlr_xdg_surface, | ||||
|             self.pending_state.width, | ||||
|             self.pending_state.height, | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     pub fn sendFrameDone(self: *Self) void { | ||||
|         var now: c.struct_timespec = undefined; | ||||
|         _ = c.clock_gettime(c.CLOCK_MONOTONIC, &now); | ||||
|         c.wlr_surface_send_frame_done(self.wlr_xdg_surface.surface, &now); | ||||
|     } | ||||
|  | ||||
|     pub fn dropStashedBuffer(self: *Self) void { | ||||
|         std.debug.warn("drop stashed\n", .{}); | ||||
|         // TODO: log debug error | ||||
|         if (self.stashed_buffer) |buffer| { | ||||
|             c.wlr_buffer_unref(buffer); | ||||
|             std.debug.warn("drop stashed\n", .{}); | ||||
|             self.stashed_buffer = null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn stashBuffer(self: *Self) void { | ||||
|         // TODO: log debug error if there is already a saved buffer | ||||
|         const wlr_surface = self.wlr_xdg_surface.surface; | ||||
|         if (c.wlr_surface_has_buffer(wlr_surface)) { | ||||
|             _ = c.wlr_buffer_ref(wlr_surface.*.buffer); | ||||
|             self.stashed_buffer = wlr_surface.*.buffer; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn handleMap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { | ||||
|         // Called when the surface is mapped, or ready to display on-screen. | ||||
|         const view = @fieldParentPtr(View, "listen_map", listener.?); | ||||
|         view.mapped = true; | ||||
|         view.focus(view.wlr_xdg_surface.surface); | ||||
|         view.root.arrange(); | ||||
|  | ||||
|         const node = @fieldParentPtr(std.TailQueue(View).Node, "data", view); | ||||
|         view.root.unmapped_views.remove(node); | ||||
|         view.root.views.prepend(node); | ||||
|     } | ||||
|  | ||||
|     fn handleUnmap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { | ||||
| @ -68,6 +134,17 @@ pub const View = struct { | ||||
|         root.views.destroyNode(target, root.server.allocator); | ||||
|     } | ||||
|  | ||||
|     fn handleCommit(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { | ||||
|         const view = @fieldParentPtr(View, "listen_commit", listener.?); | ||||
|         if (view.pending_serial) |s| { | ||||
|             if (s == view.wlr_xdg_surface.configure_serial) { | ||||
|                 view.root.notifyConfigured(); | ||||
|                 view.pending_serial = null; | ||||
|             } | ||||
|         } | ||||
|         // TODO: check for unexpected change in size and react as needed | ||||
|     } | ||||
|  | ||||
|     // fn xdgToplevelRequestMove(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { | ||||
|     //     // ignore for now | ||||
|     // } | ||||
| @ -94,17 +171,17 @@ pub const View = struct { | ||||
|             _ = c.wlr_xdg_toplevel_set_activated(prev_xdg_surface, false); | ||||
|         } | ||||
|  | ||||
|         // Find the node | ||||
|         var it = root.views.first; | ||||
|         const target = while (it) |node| : (it = node.next) { | ||||
|             if (&node.data == self) { | ||||
|                 break node; | ||||
|             } | ||||
|         } else unreachable; | ||||
|         //// Find the node | ||||
|         //var it = root.views.first; | ||||
|         //const target = while (it) |node| : (it = node.next) { | ||||
|         //    if (&node.data == self) { | ||||
|         //        break node; | ||||
|         //    } | ||||
|         //} else unreachable; | ||||
|  | ||||
|         // Move the view to the front | ||||
|         root.views.remove(target); | ||||
|         root.views.prepend(target); | ||||
|         //// Move the view to the front | ||||
|         //root.views.remove(target); | ||||
|         //root.views.prepend(target); | ||||
|  | ||||
|         // Activate the new surface | ||||
|         _ = c.wlr_xdg_toplevel_set_activated(self.wlr_xdg_surface, true); | ||||
| @ -128,8 +205,8 @@ pub const View = struct { | ||||
|         // coordinates lx and ly (in output Layout Coordinates). If so, it sets the | ||||
|         // surface pointer to that wlr_surface and the sx and sy coordinates to the | ||||
|         // coordinates relative to that surface's top-left corner. | ||||
|         const view_sx = lx - @intToFloat(f64, self.x); | ||||
|         const view_sy = ly - @intToFloat(f64, self.y); | ||||
|         const view_sx = lx - @intToFloat(f64, self.current_state.x); | ||||
|         const view_sy = ly - @intToFloat(f64, self.current_state.y); | ||||
|  | ||||
|         // This variable seems to have been unsued in TinyWL | ||||
|         // struct wlr_surface_state *state = &view->xdg_surface->surface->current; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user