Cursor: remove surfaceAt()
We now use the wlr_scene API to find out what is at the cursor location.
This commit is contained in:
parent
4f0ce8fceb
commit
683ed0f04e
278
river/Cursor.zig
278
river/Cursor.zig
@ -34,6 +34,7 @@ const Config = @import("Config.zig");
|
|||||||
const LayerSurface = @import("LayerSurface.zig");
|
const LayerSurface = @import("LayerSurface.zig");
|
||||||
const LockSurface = @import("LockSurface.zig");
|
const LockSurface = @import("LockSurface.zig");
|
||||||
const Output = @import("Output.zig");
|
const Output = @import("Output.zig");
|
||||||
|
const Root = @import("Root.zig");
|
||||||
const Seat = @import("Seat.zig");
|
const Seat = @import("Seat.zig");
|
||||||
const View = @import("View.zig");
|
const View = @import("View.zig");
|
||||||
const ViewStack = @import("view_stack.zig").ViewStack;
|
const ViewStack = @import("view_stack.zig").ViewStack;
|
||||||
@ -320,8 +321,8 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.surfaceAt()) |result| {
|
if (server.root.at(self.wlr_cursor.x, self.wlr_cursor.y)) |result| {
|
||||||
if (result.parent == .view and self.handlePointerMapping(event, result.parent.view)) {
|
if (result.node == .view and self.handlePointerMapping(event, result.node.view)) {
|
||||||
// If a mapping is triggered don't send events to clients.
|
// If a mapping is triggered don't send events to clients.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -330,6 +331,7 @@ 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.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state);
|
||||||
|
|
||||||
|
if (result.surface != null) {
|
||||||
self.mode = .{
|
self.mode = .{
|
||||||
.down = .{
|
.down = .{
|
||||||
.lx = self.wlr_cursor.x,
|
.lx = self.wlr_cursor.x,
|
||||||
@ -338,6 +340,7 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P
|
|||||||
.sy = result.sy,
|
.sy = result.sy,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.updateOutputFocus(self.wlr_cursor.x, self.wlr_cursor.y);
|
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();
|
server.root.startTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn updateKeyboardFocus(self: Self, result: SurfaceAtResult) void {
|
fn updateKeyboardFocus(self: Self, result: Root.AtResult) void {
|
||||||
switch (result.parent) {
|
switch (result.node) {
|
||||||
.view => |view| {
|
.view => |view| {
|
||||||
self.seat.focus(view);
|
self.seat.focus(view);
|
||||||
},
|
},
|
||||||
@ -485,16 +488,18 @@ fn handleTouchDown(
|
|||||||
log.err("out of memory", .{});
|
log.err("out of memory", .{});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (surfaceAtCoords(lx, ly)) |result| {
|
if (server.root.at(lx, ly)) |result| {
|
||||||
self.updateKeyboardFocus(result);
|
self.updateKeyboardFocus(result);
|
||||||
|
|
||||||
|
if (result.surface) |surface| {
|
||||||
_ = self.seat.wlr_seat.touchNotifyDown(
|
_ = self.seat.wlr_seat.touchNotifyDown(
|
||||||
result.surface,
|
surface,
|
||||||
event.time_msec,
|
event.time_msec,
|
||||||
event.touch_id,
|
event.touch_id,
|
||||||
result.sx,
|
result.sx,
|
||||||
result.sy,
|
result.sy,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.updateOutputFocus(lx, ly);
|
self.updateOutputFocus(lx, ly);
|
||||||
}
|
}
|
||||||
@ -518,7 +523,7 @@ fn handleTouchMotion(
|
|||||||
log.err("out of memory", .{});
|
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);
|
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;
|
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 {
|
pub fn enterMode(self: *Self, mode: enum { move, resize }, view: *View) void {
|
||||||
log.debug("enter {s} cursor mode", .{@tagName(mode)});
|
log.debug("enter {s} cursor mode", .{@tagName(mode)});
|
||||||
|
|
||||||
@ -1024,8 +790,8 @@ pub fn checkFocusFollowsCursor(self: *Self) void {
|
|||||||
// change can't occur.
|
// change can't occur.
|
||||||
if (self.seat.drag == .pointer) return;
|
if (self.seat.drag == .pointer) return;
|
||||||
if (server.config.focus_follows_cursor == .disabled) return;
|
if (server.config.focus_follows_cursor == .disabled) return;
|
||||||
if (self.surfaceAt()) |result| {
|
if (server.root.at(self.wlr_cursor.x, self.wlr_cursor.y)) |result| {
|
||||||
switch (result.parent) {
|
switch (result.node) {
|
||||||
.view => |view| {
|
.view => |view| {
|
||||||
// Don't re-focus the last focused view when the mode is .normal
|
// Don't re-focus the last focused view when the mode is .normal
|
||||||
if (server.config.focus_follows_cursor == .normal and
|
if (server.config.focus_follows_cursor == .normal and
|
||||||
@ -1105,17 +871,19 @@ fn shouldPassthrough(self: Self) bool {
|
|||||||
fn passthrough(self: *Self, time: u32) void {
|
fn passthrough(self: *Self, time: u32) void {
|
||||||
assert(self.mode == .passthrough);
|
assert(self.mode == .passthrough);
|
||||||
|
|
||||||
if (self.surfaceAt()) |result| {
|
if (server.root.at(self.wlr_cursor.x, self.wlr_cursor.y)) |result| {
|
||||||
assert((result.parent == .lock_surface) == (server.lock_manager.state != .unlocked));
|
// TODO audit session lock assertions after wlr_scene upgrade
|
||||||
self.seat.wlr_seat.pointerNotifyEnter(result.surface, result.sx, result.sy);
|
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);
|
self.seat.wlr_seat.pointerNotifyMotion(time, result.sx, result.sy);
|
||||||
} else {
|
return;
|
||||||
// There is either no surface under the cursor or input is disallowed
|
|
||||||
// Reset the cursor image to the default and clear focus.
|
|
||||||
self.clearFocus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.clearFocus();
|
||||||
|
}
|
||||||
|
|
||||||
fn warp(self: *Self) void {
|
fn warp(self: *Self) void {
|
||||||
self.may_need_warp = false;
|
self.may_need_warp = false;
|
||||||
if (self.seat.focused_output == &server.root.noop_output) return;
|
if (self.seat.focused_output == &server.root.noop_output) return;
|
||||||
|
@ -26,11 +26,14 @@ const wl = @import("wayland").server.wl;
|
|||||||
const server = &@import("main.zig").server;
|
const server = &@import("main.zig").server;
|
||||||
const util = @import("util.zig");
|
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 Output = @import("Output.zig");
|
||||||
|
const SceneNodeData = @import("SceneNodeData.zig");
|
||||||
const View = @import("View.zig");
|
const View = @import("View.zig");
|
||||||
const ViewStack = @import("view_stack.zig").ViewStack;
|
const ViewStack = @import("view_stack.zig").ViewStack;
|
||||||
const XwaylandOverrideRedirect = @import("XwaylandOverrideRedirect.zig");
|
const XwaylandOverrideRedirect = @import("XwaylandOverrideRedirect.zig");
|
||||||
const DragIcon = @import("DragIcon.zig");
|
|
||||||
|
|
||||||
scene: *wlr.Scene,
|
scene: *wlr.Scene,
|
||||||
|
|
||||||
@ -118,6 +121,53 @@ pub fn deinit(self: *Self) void {
|
|||||||
self.transaction_timer.remove();
|
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 {
|
fn handleNewOutput(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void {
|
||||||
const self = @fieldParentPtr(Self, "new_output", listener);
|
const self = @fieldParentPtr(Self, "new_output", listener);
|
||||||
std.log.scoped(.output_manager).debug("new output {s}", .{wlr_output.name});
|
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 util = @import("util.zig");
|
||||||
|
|
||||||
const Output = @import("Output.zig");
|
const Output = @import("Output.zig");
|
||||||
|
const SceneNodeData = @import("SceneNodeData.zig");
|
||||||
const Seat = @import("Seat.zig");
|
const Seat = @import("Seat.zig");
|
||||||
const ViewStack = @import("view_stack.zig").ViewStack;
|
const ViewStack = @import("view_stack.zig").ViewStack;
|
||||||
const XdgToplevel = @import("XdgToplevel.zig");
|
const XdgToplevel = @import("XdgToplevel.zig");
|
||||||
@ -113,12 +114,14 @@ draw_borders: bool = true,
|
|||||||
request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate) =
|
request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate) =
|
||||||
wl.Listener(*wlr.XdgActivationV1.event.RequestActivate).init(handleRequestActivate),
|
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 initial_tags = blk: {
|
||||||
const tags = output.current.tags & server.config.spawn_tagmask;
|
const tags = output.current.tags & server.config.spawn_tagmask;
|
||||||
break :blk if (tags != 0) tags else output.current.tags;
|
break :blk if (tags != 0) tags else output.current.tags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
try SceneNodeData.attach(&tree.node, .{ .view = self });
|
||||||
|
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.impl = impl,
|
.impl = impl,
|
||||||
.output = output,
|
.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.
|
/// Return the current title of the view if any.
|
||||||
pub fn getTitle(self: Self) ?[*:0]const u8 {
|
pub fn getTitle(self: Self) ?[*:0]const u8 {
|
||||||
return switch (self.impl) {
|
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
|
/// 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 {
|
pub fn create(output: *Output, xdg_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
|
||||||
const node = try util.gpa.create(ViewStack(View).Node);
|
const node = try util.gpa.create(ViewStack(View).Node);
|
||||||
|
errdefer util.gpa.destroy(node);
|
||||||
const view = &node.view;
|
const view = &node.view;
|
||||||
|
|
||||||
const tree = try output.tree.createSceneXdgSurface(xdg_toplevel.base);
|
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,
|
.view = view,
|
||||||
.xdg_toplevel = xdg_toplevel,
|
.xdg_toplevel = xdg_toplevel,
|
||||||
} });
|
} });
|
||||||
|
|
||||||
const self = &node.view.impl.xdg_toplevel;
|
xdg_toplevel.base.data = @ptrToInt(view);
|
||||||
xdg_toplevel.base.data = @ptrToInt(self);
|
|
||||||
|
|
||||||
// Add listeners that are active over the view's entire lifetime
|
// 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.destroy.add(&self.destroy);
|
||||||
xdg_toplevel.base.events.map.add(&self.map);
|
xdg_toplevel.base.events.map.add(&self.map);
|
||||||
xdg_toplevel.base.events.unmap.add(&self.unmap);
|
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);
|
_ = 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.
|
/// Return the current title of the toplevel if any.
|
||||||
pub fn getTitle(self: Self) ?[*:0]const u8 {
|
pub fn getTitle(self: Self) ?[*:0]const u8 {
|
||||||
return self.xdg_toplevel.title;
|
return self.xdg_toplevel.title;
|
||||||
|
@ -142,17 +142,6 @@ pub fn setFullscreen(self: *Self, fullscreen: bool) void {
|
|||||||
self.xwayland_surface.setFullscreen(fullscreen);
|
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.
|
/// Get the current title of the xwayland surface if any.
|
||||||
pub fn getTitle(self: Self) ?[*:0]const u8 {
|
pub fn getTitle(self: Self) ?[*:0]const u8 {
|
||||||
return self.xwayland_surface.title;
|
return self.xwayland_surface.title;
|
||||||
|
Loading…
Reference in New Issue
Block a user