Cursor: remove surfaceAt()
We now use the wlr_scene API to find out what is at the cursor location.
This commit is contained in:
		
							
								
								
									
										308
									
								
								river/Cursor.zig
									
									
									
									
									
								
							
							
						
						
									
										308
									
								
								river/Cursor.zig
									
									
									
									
									
								
							| @ -34,6 +34,7 @@ const Config = @import("Config.zig"); | ||||
| const LayerSurface = @import("LayerSurface.zig"); | ||||
| const LockSurface = @import("LockSurface.zig"); | ||||
| const Output = @import("Output.zig"); | ||||
| const Root = @import("Root.zig"); | ||||
| const Seat = @import("Seat.zig"); | ||||
| const View = @import("View.zig"); | ||||
| const ViewStack = @import("view_stack.zig").ViewStack; | ||||
| @ -320,8 +321,8 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (self.surfaceAt()) |result| { | ||||
|         if (result.parent == .view and self.handlePointerMapping(event, result.parent.view)) { | ||||
|     if (server.root.at(self.wlr_cursor.x, self.wlr_cursor.y)) |result| { | ||||
|         if (result.node == .view and self.handlePointerMapping(event, result.node.view)) { | ||||
|             // If a mapping is triggered don't send events to clients. | ||||
|             return; | ||||
|         } | ||||
| @ -330,14 +331,16 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P | ||||
|  | ||||
|         _ = self.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state); | ||||
|  | ||||
|         self.mode = .{ | ||||
|             .down = .{ | ||||
|                 .lx = self.wlr_cursor.x, | ||||
|                 .ly = self.wlr_cursor.y, | ||||
|                 .sx = result.sx, | ||||
|                 .sy = result.sy, | ||||
|             }, | ||||
|         }; | ||||
|         if (result.surface != null) { | ||||
|             self.mode = .{ | ||||
|                 .down = .{ | ||||
|                     .lx = self.wlr_cursor.x, | ||||
|                     .ly = self.wlr_cursor.y, | ||||
|                     .sx = result.sx, | ||||
|                     .sy = result.sy, | ||||
|                 }, | ||||
|             }; | ||||
|         } | ||||
|     } else { | ||||
|         self.updateOutputFocus(self.wlr_cursor.x, self.wlr_cursor.y); | ||||
|     } | ||||
| @ -345,8 +348,8 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P | ||||
|     server.root.startTransaction(); | ||||
| } | ||||
|  | ||||
| fn updateKeyboardFocus(self: Self, result: SurfaceAtResult) void { | ||||
|     switch (result.parent) { | ||||
| fn updateKeyboardFocus(self: Self, result: Root.AtResult) void { | ||||
|     switch (result.node) { | ||||
|         .view => |view| { | ||||
|             self.seat.focus(view); | ||||
|         }, | ||||
| @ -485,16 +488,18 @@ fn handleTouchDown( | ||||
|         log.err("out of memory", .{}); | ||||
|     }; | ||||
|  | ||||
|     if (surfaceAtCoords(lx, ly)) |result| { | ||||
|     if (server.root.at(lx, ly)) |result| { | ||||
|         self.updateKeyboardFocus(result); | ||||
|  | ||||
|         _ = self.seat.wlr_seat.touchNotifyDown( | ||||
|             result.surface, | ||||
|             event.time_msec, | ||||
|             event.touch_id, | ||||
|             result.sx, | ||||
|             result.sy, | ||||
|         ); | ||||
|         if (result.surface) |surface| { | ||||
|             _ = self.seat.wlr_seat.touchNotifyDown( | ||||
|                 surface, | ||||
|                 event.time_msec, | ||||
|                 event.touch_id, | ||||
|                 result.sx, | ||||
|                 result.sy, | ||||
|             ); | ||||
|         } | ||||
|     } else { | ||||
|         self.updateOutputFocus(lx, ly); | ||||
|     } | ||||
| @ -518,7 +523,7 @@ fn handleTouchMotion( | ||||
|         log.err("out of memory", .{}); | ||||
|     }; | ||||
|  | ||||
|     if (surfaceAtCoords(lx, ly)) |result| { | ||||
|     if (server.root.at(lx, ly)) |result| { | ||||
|         self.seat.wlr_seat.touchNotifyMotion(event.time_msec, event.touch_id, result.sx, result.sy); | ||||
|     } | ||||
| } | ||||
| @ -649,245 +654,6 @@ fn handleHideCursorTimeout(self: *Self) c_int { | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| const SurfaceAtResult = struct { | ||||
|     surface: *wlr.Surface, | ||||
|     sx: f64, | ||||
|     sy: f64, | ||||
|     parent: union(enum) { | ||||
|         view: *View, | ||||
|         layer_surface: *LayerSurface, | ||||
|         lock_surface: *LockSurface, | ||||
|         xwayland_override_redirect: if (build_options.xwayland) *XwaylandOverrideRedirect else noreturn, | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| /// Find the surface under the cursor if any, and return information about that | ||||
| /// surface and the cursor's position in surface local coords. | ||||
| pub fn surfaceAt(self: Self) ?SurfaceAtResult { | ||||
|     return surfaceAtCoords(self.wlr_cursor.x, self.wlr_cursor.y); | ||||
| } | ||||
|  | ||||
| /// Find the surface at the given layout coords if any, and return information about that | ||||
| /// surface and the surface local coords. | ||||
| /// This function must be kept in sync with the rendering order in render.zig. | ||||
| fn surfaceAtCoords(lx: f64, ly: f64) ?SurfaceAtResult { | ||||
|     const wlr_output = server.root.output_layout.outputAt(lx, ly) orelse return null; | ||||
|     const output = @intToPtr(*Output, wlr_output.data); | ||||
|  | ||||
|     // Get output-local coords from the layout coords | ||||
|     var ox = lx; | ||||
|     var oy = ly; | ||||
|     server.root.output_layout.outputCoords(wlr_output, &ox, &oy); | ||||
|  | ||||
|     if (server.lock_manager.state != .unlocked) { | ||||
|         if (output.lock_surface) |lock_surface| { | ||||
|             var sx: f64 = undefined; | ||||
|             var sy: f64 = undefined; | ||||
|             if (lock_surface.wlr_lock_surface.surface.surfaceAt(ox, oy, &sx, &sy)) |found| { | ||||
|                 return SurfaceAtResult{ | ||||
|                     .surface = found, | ||||
|                     .sx = sx, | ||||
|                     .sy = sy, | ||||
|                     .parent = .{ .lock_surface = lock_surface }, | ||||
|                 }; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     // Find the first visible fullscreen view in the stack if there is one | ||||
|     var it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter); | ||||
|     const fullscreen_view = while (it.next()) |view| { | ||||
|         if (view.current.fullscreen) break view; | ||||
|     } else null; | ||||
|  | ||||
|     // Check surfaces in the reverse order they are rendered in: | ||||
|     // | ||||
|     // fullscreen: | ||||
|     //  1. overlay layer toplevels and popups | ||||
|     //  2. xwayland override redirect windows | ||||
|     //  3. fullscreen view toplevels and popups | ||||
|     // | ||||
|     // non-fullscreen: | ||||
|     //  1. overlay layer toplevels and popups | ||||
|     //  2. top, bottom, background layer popups | ||||
|     //  3. top layer toplevels | ||||
|     //  4. xwayland override redirect windows | ||||
|     //  5. view toplevels and popups | ||||
|     //  6. bottom, background layer toplevels | ||||
|  | ||||
|     if (layerSurfaceAt(output.getLayer(.overlay).*, ox, oy)) |s| return s; | ||||
|  | ||||
|     if (fullscreen_view) |view| { | ||||
|         if (build_options.xwayland) if (xwaylandOverrideRedirectSurfaceAt(lx, ly)) |s| return s; | ||||
|         var sx: f64 = undefined; | ||||
|         var sy: f64 = undefined; | ||||
|         if (view.surfaceAt(ox, oy, &sx, &sy)) |found| { | ||||
|             return SurfaceAtResult{ | ||||
|                 .surface = found, | ||||
|                 .sx = sx, | ||||
|                 .sy = sy, | ||||
|                 .parent = .{ .view = view }, | ||||
|             }; | ||||
|         } | ||||
|     } else { | ||||
|         for ([_]zwlr.LayerShellV1.Layer{ .top, .bottom, .background }) |layer| { | ||||
|             if (layerPopupSurfaceAt(output.getLayer(layer).*, ox, oy)) |s| return s; | ||||
|         } | ||||
|  | ||||
|         if (layerSurfaceAt(output.getLayer(.top).*, ox, oy)) |s| return s; | ||||
|  | ||||
|         if (build_options.xwayland) if (xwaylandOverrideRedirectSurfaceAt(lx, ly)) |s| return s; | ||||
|  | ||||
|         if (viewSurfaceAt(output, ox, oy)) |s| return s; | ||||
|  | ||||
|         for ([_]zwlr.LayerShellV1.Layer{ .bottom, .background }) |layer| { | ||||
|             if (layerSurfaceAt(output.getLayer(layer).*, ox, oy)) |s| return s; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return null; | ||||
| } | ||||
|  | ||||
| /// Find the topmost popup surface on the given layer at ox,oy. | ||||
| fn layerPopupSurfaceAt(layer: std.TailQueue(LayerSurface), ox: f64, oy: f64) ?SurfaceAtResult { | ||||
|     var it = layer.first; | ||||
|     while (it) |node| : (it = node.next) { | ||||
|         const layer_surface = &node.data; | ||||
|         var sx: f64 = undefined; | ||||
|         var sy: f64 = undefined; | ||||
|         if (layer_surface.wlr_layer_surface.popupSurfaceAt( | ||||
|             ox - @intToFloat(f64, layer_surface.box.x), | ||||
|             oy - @intToFloat(f64, layer_surface.box.y), | ||||
|             &sx, | ||||
|             &sy, | ||||
|         )) |found| { | ||||
|             return SurfaceAtResult{ | ||||
|                 .surface = found, | ||||
|                 .sx = sx, | ||||
|                 .sy = sy, | ||||
|                 .parent = .{ .layer_surface = layer_surface }, | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     return null; | ||||
| } | ||||
|  | ||||
| /// Find the topmost surface (or popup surface) on the given layer at ox,oy. | ||||
| fn layerSurfaceAt(layer: std.TailQueue(LayerSurface), ox: f64, oy: f64) ?SurfaceAtResult { | ||||
|     var it = layer.first; | ||||
|     while (it) |node| : (it = node.next) { | ||||
|         const layer_surface = &node.data; | ||||
|         var sx: f64 = undefined; | ||||
|         var sy: f64 = undefined; | ||||
|         if (layer_surface.wlr_layer_surface.surfaceAt( | ||||
|             ox - @intToFloat(f64, layer_surface.box.x), | ||||
|             oy - @intToFloat(f64, layer_surface.box.y), | ||||
|             &sx, | ||||
|             &sy, | ||||
|         )) |found| { | ||||
|             return SurfaceAtResult{ | ||||
|                 .surface = found, | ||||
|                 .sx = sx, | ||||
|                 .sy = sy, | ||||
|                 .parent = .{ .layer_surface = layer_surface }, | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     return null; | ||||
| } | ||||
|  | ||||
| /// Find the topmost visible view surface (incl. popups) at ox,oy. | ||||
| fn viewSurfaceAt(output: *const Output, ox: f64, oy: f64) ?SurfaceAtResult { | ||||
|     var sx: f64 = undefined; | ||||
|     var sy: f64 = undefined; | ||||
|  | ||||
|     // focused, floating views | ||||
|     var it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter); | ||||
|     while (it.next()) |view| { | ||||
|         if (view.current.focus == 0 or !view.current.float) continue; | ||||
|         if (view.surfaceAt(ox, oy, &sx, &sy)) |found| { | ||||
|             return SurfaceAtResult{ | ||||
|                 .surface = found, | ||||
|                 .sx = sx, | ||||
|                 .sy = sy, | ||||
|                 .parent = .{ .view = view }, | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // non-focused, floating views | ||||
|     it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter); | ||||
|     while (it.next()) |view| { | ||||
|         if (view.current.focus != 0 or !view.current.float) continue; | ||||
|         if (view.surfaceAt(ox, oy, &sx, &sy)) |found| { | ||||
|             return SurfaceAtResult{ | ||||
|                 .surface = found, | ||||
|                 .sx = sx, | ||||
|                 .sy = sy, | ||||
|                 .parent = .{ .view = view }, | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // focused, non-floating views | ||||
|     it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter); | ||||
|     while (it.next()) |view| { | ||||
|         if (view.current.focus == 0 or view.current.float) continue; | ||||
|         if (view.surfaceAt(ox, oy, &sx, &sy)) |found| { | ||||
|             return SurfaceAtResult{ | ||||
|                 .surface = found, | ||||
|                 .sx = sx, | ||||
|                 .sy = sy, | ||||
|                 .parent = .{ .view = view }, | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // non-focused, non-floating views | ||||
|     it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter); | ||||
|     while (it.next()) |view| { | ||||
|         if (view.current.focus != 0 or view.current.float) continue; | ||||
|         if (view.surfaceAt(ox, oy, &sx, &sy)) |found| { | ||||
|             return SurfaceAtResult{ | ||||
|                 .surface = found, | ||||
|                 .sx = sx, | ||||
|                 .sy = sy, | ||||
|                 .parent = .{ .view = view }, | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return null; | ||||
| } | ||||
|  | ||||
| fn xwaylandOverrideRedirectSurfaceAt(lx: f64, ly: f64) ?SurfaceAtResult { | ||||
|     var it = server.root.xwayland_override_redirect_views.first; | ||||
|     while (it) |node| : (it = node.next) { | ||||
|         const xwayland_surface = node.data.xwayland_surface; | ||||
|         var sx: f64 = undefined; | ||||
|         var sy: f64 = undefined; | ||||
|         if (xwayland_surface.surface.?.surfaceAt( | ||||
|             lx - @intToFloat(f64, xwayland_surface.x), | ||||
|             ly - @intToFloat(f64, xwayland_surface.y), | ||||
|             &sx, | ||||
|             &sy, | ||||
|         )) |found| { | ||||
|             return SurfaceAtResult{ | ||||
|                 .surface = found, | ||||
|                 .sx = sx, | ||||
|                 .sy = sy, | ||||
|                 .parent = .{ .xwayland_override_redirect = &node.data }, | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     return null; | ||||
| } | ||||
|  | ||||
| fn surfaceAtFilter(view: *View, filter_tags: u32) bool { | ||||
|     return view.tree.node.enabled and view.current.tags & filter_tags != 0; | ||||
| } | ||||
|  | ||||
| pub fn enterMode(self: *Self, mode: enum { move, resize }, view: *View) void { | ||||
|     log.debug("enter {s} cursor mode", .{@tagName(mode)}); | ||||
|  | ||||
| @ -1024,8 +790,8 @@ pub fn checkFocusFollowsCursor(self: *Self) void { | ||||
|     // change can't occur. | ||||
|     if (self.seat.drag == .pointer) return; | ||||
|     if (server.config.focus_follows_cursor == .disabled) return; | ||||
|     if (self.surfaceAt()) |result| { | ||||
|         switch (result.parent) { | ||||
|     if (server.root.at(self.wlr_cursor.x, self.wlr_cursor.y)) |result| { | ||||
|         switch (result.node) { | ||||
|             .view => |view| { | ||||
|                 // Don't re-focus the last focused view when the mode is .normal | ||||
|                 if (server.config.focus_follows_cursor == .normal and | ||||
| @ -1105,15 +871,17 @@ fn shouldPassthrough(self: Self) bool { | ||||
| fn passthrough(self: *Self, time: u32) void { | ||||
|     assert(self.mode == .passthrough); | ||||
|  | ||||
|     if (self.surfaceAt()) |result| { | ||||
|         assert((result.parent == .lock_surface) == (server.lock_manager.state != .unlocked)); | ||||
|         self.seat.wlr_seat.pointerNotifyEnter(result.surface, result.sx, result.sy); | ||||
|         self.seat.wlr_seat.pointerNotifyMotion(time, result.sx, result.sy); | ||||
|     } else { | ||||
|         // There is either no surface under the cursor or input is disallowed | ||||
|         // Reset the cursor image to the default and clear focus. | ||||
|         self.clearFocus(); | ||||
|     if (server.root.at(self.wlr_cursor.x, self.wlr_cursor.y)) |result| { | ||||
|         // TODO audit session lock assertions after wlr_scene upgrade | ||||
|         assert((result.node == .lock_surface) == (server.lock_manager.state != .unlocked)); | ||||
|         if (result.surface) |surface| { | ||||
|             self.seat.wlr_seat.pointerNotifyEnter(surface, result.sx, result.sy); | ||||
|             self.seat.wlr_seat.pointerNotifyMotion(time, result.sx, result.sy); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     self.clearFocus(); | ||||
| } | ||||
|  | ||||
| fn warp(self: *Self) void { | ||||
|  | ||||
| @ -26,11 +26,14 @@ const wl = @import("wayland").server.wl; | ||||
| const server = &@import("main.zig").server; | ||||
| const util = @import("util.zig"); | ||||
|  | ||||
| const DragIcon = @import("DragIcon.zig"); | ||||
| const LayerSurface = @import("LayerSurface.zig"); | ||||
| const LockSurface = @import("LockSurface.zig"); | ||||
| const Output = @import("Output.zig"); | ||||
| const SceneNodeData = @import("SceneNodeData.zig"); | ||||
| const View = @import("View.zig"); | ||||
| const ViewStack = @import("view_stack.zig").ViewStack; | ||||
| const XwaylandOverrideRedirect = @import("XwaylandOverrideRedirect.zig"); | ||||
| const DragIcon = @import("DragIcon.zig"); | ||||
|  | ||||
| scene: *wlr.Scene, | ||||
|  | ||||
| @ -118,6 +121,53 @@ pub fn deinit(self: *Self) void { | ||||
|     self.transaction_timer.remove(); | ||||
| } | ||||
|  | ||||
| pub const AtResult = struct { | ||||
|     surface: ?*wlr.Surface, | ||||
|     sx: f64, | ||||
|     sy: f64, | ||||
|     node: union(enum) { | ||||
|         view: *View, | ||||
|         layer_surface: *LayerSurface, | ||||
|         lock_surface: *LockSurface, | ||||
|         xwayland_override_redirect: if (build_options.xwayland) *XwaylandOverrideRedirect else noreturn, | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| /// Return information about what is currently rendered at the given layout coordinates. | ||||
| pub fn at(self: Self, lx: f64, ly: f64) ?AtResult { | ||||
|     var sx: f64 = undefined; | ||||
|     var sy: f64 = undefined; | ||||
|     const node_at = self.scene.tree.node.at(lx, ly, &sx, &sy) orelse return null; | ||||
|  | ||||
|     const surface: ?*wlr.Surface = blk: { | ||||
|         if (node_at.type == .buffer) { | ||||
|             const scene_buffer = wlr.SceneBuffer.fromNode(node_at); | ||||
|             if (wlr.SceneSurface.fromBuffer(scene_buffer)) |scene_surface| { | ||||
|                 break :blk scene_surface.surface; | ||||
|             } | ||||
|         } | ||||
|         break :blk null; | ||||
|     }; | ||||
|  | ||||
|     { | ||||
|         var it: ?*wlr.SceneNode = node_at; | ||||
|         while (it) |node| : (it = node.parent) { | ||||
|             if (@intToPtr(?*SceneNodeData, node.data)) |scene_node_data| { | ||||
|                 switch (scene_node_data.data) { | ||||
|                     .view => |view| return .{ | ||||
|                         .surface = surface, | ||||
|                         .sx = sx, | ||||
|                         .sy = sy, | ||||
|                         .node = .{ .view = view }, | ||||
|                     }, | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return null; | ||||
| } | ||||
|  | ||||
| fn handleNewOutput(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void { | ||||
|     const self = @fieldParentPtr(Self, "new_output", listener); | ||||
|     std.log.scoped(.output_manager).debug("new output {s}", .{wlr_output.name}); | ||||
|  | ||||
							
								
								
									
										54
									
								
								river/SceneNodeData.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								river/SceneNodeData.zig
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| // This file is part of river, a dynamic tiling wayland compositor. | ||||
| // | ||||
| // Copyright 2023 The River Developers | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, version 3. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
|  | ||||
| const SceneNodeData = @This(); | ||||
|  | ||||
| const build_options = @import("build_options"); | ||||
| const wlr = @import("wlroots"); | ||||
| const wl = @import("wayland").server.wl; | ||||
|  | ||||
| const util = @import("util.zig"); | ||||
|  | ||||
| const View = @import("View.zig"); | ||||
|  | ||||
| const Data = union(enum) { | ||||
|     view: *View, | ||||
| }; | ||||
|  | ||||
| node: *wlr.SceneNode, | ||||
| data: Data, | ||||
| destroy: wl.Listener(void) = wl.Listener(void).init(handleDestroy), | ||||
|  | ||||
| pub fn attach(node: *wlr.SceneNode, data: Data) error{OutOfMemory}!void { | ||||
|     const scene_node_data = try util.gpa.create(SceneNodeData); | ||||
|  | ||||
|     scene_node_data.* = .{ | ||||
|         .node = node, | ||||
|         .data = data, | ||||
|     }; | ||||
|     node.data = @ptrToInt(scene_node_data); | ||||
|  | ||||
|     node.events.destroy.add(&scene_node_data.destroy); | ||||
| } | ||||
|  | ||||
| fn handleDestroy(listener: *wl.Listener(void)) void { | ||||
|     const scene_node_data = @fieldParentPtr(SceneNodeData, "destroy", listener); | ||||
|  | ||||
|     scene_node_data.destroy.link.remove(); | ||||
|     scene_node_data.node.data = 0; | ||||
|  | ||||
|     util.gpa.destroy(scene_node_data); | ||||
| } | ||||
| @ -28,6 +28,7 @@ const server = &@import("main.zig").server; | ||||
| const util = @import("util.zig"); | ||||
|  | ||||
| const Output = @import("Output.zig"); | ||||
| const SceneNodeData = @import("SceneNodeData.zig"); | ||||
| const Seat = @import("Seat.zig"); | ||||
| const ViewStack = @import("view_stack.zig").ViewStack; | ||||
| const XdgToplevel = @import("XdgToplevel.zig"); | ||||
| @ -113,12 +114,14 @@ draw_borders: bool = true, | ||||
| request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate) = | ||||
|     wl.Listener(*wlr.XdgActivationV1.event.RequestActivate).init(handleRequestActivate), | ||||
|  | ||||
| pub fn init(self: *Self, output: *Output, tree: *wlr.SceneTree, impl: Impl) void { | ||||
| pub fn init(self: *Self, output: *Output, tree: *wlr.SceneTree, impl: Impl) error{OutOfMemory}!void { | ||||
|     const initial_tags = blk: { | ||||
|         const tags = output.current.tags & server.config.spawn_tagmask; | ||||
|         break :blk if (tags != 0) tags else output.current.tags; | ||||
|     }; | ||||
|  | ||||
|     try SceneNodeData.attach(&tree.node, .{ .view = self }); | ||||
|  | ||||
|     self.* = .{ | ||||
|         .impl = impl, | ||||
|         .output = output, | ||||
| @ -371,15 +374,6 @@ pub inline fn forEachSurface( | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Return the surface at output coordinates ox, oy and set sx, sy to the | ||||
| /// corresponding surface-relative coordinates, if there is a surface. | ||||
| pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Surface { | ||||
|     return switch (self.impl) { | ||||
|         .xdg_toplevel => |xdg_toplevel| xdg_toplevel.surfaceAt(ox, oy, sx, sy), | ||||
|         .xwayland_view => |xwayland_view| xwayland_view.surfaceAt(ox, oy, sx, sy), | ||||
|     }; | ||||
| } | ||||
|  | ||||
| /// Return the current title of the view if any. | ||||
| pub fn getTitle(self: Self) ?[*:0]const u8 { | ||||
|     return switch (self.impl) { | ||||
|  | ||||
| @ -60,19 +60,21 @@ set_app_id: wl.Listener(void) = wl.Listener(void).init(handleSetAppId), | ||||
| /// The View will add itself to the output's view stack on map | ||||
| pub fn create(output: *Output, xdg_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void { | ||||
|     const node = try util.gpa.create(ViewStack(View).Node); | ||||
|     errdefer util.gpa.destroy(node); | ||||
|     const view = &node.view; | ||||
|  | ||||
|     const tree = try output.tree.createSceneXdgSurface(xdg_toplevel.base); | ||||
|     errdefer tree.node.destroy(); | ||||
|  | ||||
|     view.init(output, tree, .{ .xdg_toplevel = .{ | ||||
|     try view.init(output, tree, .{ .xdg_toplevel = .{ | ||||
|         .view = view, | ||||
|         .xdg_toplevel = xdg_toplevel, | ||||
|     } }); | ||||
|  | ||||
|     const self = &node.view.impl.xdg_toplevel; | ||||
|     xdg_toplevel.base.data = @ptrToInt(self); | ||||
|     xdg_toplevel.base.data = @ptrToInt(view); | ||||
|  | ||||
|     // Add listeners that are active over the view's entire lifetime | ||||
|     const self = &view.impl.xdg_toplevel; | ||||
|     xdg_toplevel.base.events.destroy.add(&self.destroy); | ||||
|     xdg_toplevel.base.events.map.add(&self.map); | ||||
|     xdg_toplevel.base.events.unmap.add(&self.unmap); | ||||
| @ -122,18 +124,6 @@ pub fn setResizing(self: Self, resizing: bool) void { | ||||
|     _ = self.xdg_toplevel.setResizing(resizing); | ||||
| } | ||||
|  | ||||
| /// Return the surface at output coordinates ox, oy and set sx, sy to the | ||||
| /// corresponding surface-relative coordinates, if there is a surface. | ||||
| pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Surface { | ||||
|     const view = self.view; | ||||
|     return self.xdg_toplevel.base.surfaceAt( | ||||
|         ox - @intToFloat(f64, view.current.box.x - view.surface_box.x), | ||||
|         oy - @intToFloat(f64, view.current.box.y - view.surface_box.y), | ||||
|         sx, | ||||
|         sy, | ||||
|     ); | ||||
| } | ||||
|  | ||||
| /// Return the current title of the toplevel if any. | ||||
| pub fn getTitle(self: Self) ?[*:0]const u8 { | ||||
|     return self.xdg_toplevel.title; | ||||
|  | ||||
| @ -142,17 +142,6 @@ pub fn setFullscreen(self: *Self, fullscreen: bool) void { | ||||
|     self.xwayland_surface.setFullscreen(fullscreen); | ||||
| } | ||||
|  | ||||
| /// Return the surface at output coordinates ox, oy and set sx, sy to the | ||||
| /// corresponding surface-relative coordinates, if there is a surface. | ||||
| pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Surface { | ||||
|     return self.xwayland_surface.surface.?.surfaceAt( | ||||
|         ox - @intToFloat(f64, self.view.current.box.x), | ||||
|         oy - @intToFloat(f64, self.view.current.box.y), | ||||
|         sx, | ||||
|         sy, | ||||
|     ); | ||||
| } | ||||
|  | ||||
| /// Get the current title of the xwayland surface if any. | ||||
| pub fn getTitle(self: Self) ?[*:0]const u8 { | ||||
|     return self.xwayland_surface.title; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user