river-status: implement protocol
This commit is contained in:
parent
e8aaadb228
commit
5aa7fe8af8
15 changed files with 385 additions and 28 deletions
|
@ -80,6 +80,7 @@ fn addProtocolDeps(exe: *std.build.LibExeObjStep, protocol_step: *std.build.Step
|
|||
exe.step.dependOn(protocol_step);
|
||||
exe.addIncludeDir("protocol");
|
||||
exe.addCSourceFile("protocol/river-control-unstable-v1-protocol.c", &[_][]const u8{"-std=c99"});
|
||||
exe.addCSourceFile("protocol/river-status-unstable-v1-protocol.c", &[_][]const u8{"-std=c99"});
|
||||
}
|
||||
|
||||
const ScanProtocolsStep = struct {
|
||||
|
|
|
@ -44,7 +44,7 @@ pub fn init(self: *Self, server: *Server) !void {
|
|||
protocol_version,
|
||||
self,
|
||||
bind,
|
||||
) orelse return error.CantCreateRiverWindowManagementGlobal;
|
||||
) orelse return error.CantCreateWlGlobal;
|
||||
|
||||
self.listen_display_destroy.notify = handleDisplayDestroy;
|
||||
c.wl_display_add_destroy_listener(server.wl_display, &self.listen_display_destroy);
|
||||
|
@ -67,11 +67,7 @@ fn bind(wl_client: ?*c.wl_client, data: ?*c_void, version: u32, id: u32) callcon
|
|||
c.wl_client_post_no_memory(wl_client);
|
||||
return;
|
||||
};
|
||||
c.wl_resource_set_implementation(wl_resource, &implementation, self, resourceDestroy);
|
||||
}
|
||||
|
||||
fn resourceDestroy(wl_resource: ?*c.wl_resource) callconv(.C) void {
|
||||
// TODO
|
||||
c.wl_resource_set_implementation(wl_resource, &implementation, self, null);
|
||||
}
|
||||
|
||||
fn runCommand(
|
||||
|
|
|
@ -28,6 +28,7 @@ const Log = @import("log.zig").Log;
|
|||
const Root = @import("Root.zig");
|
||||
const View = @import("View.zig");
|
||||
const ViewStack = @import("view_stack.zig").ViewStack;
|
||||
const OutputStatus = @import("OutputStatus.zig");
|
||||
|
||||
root: *Root,
|
||||
wlr_output: *c.wlr_output,
|
||||
|
@ -55,6 +56,9 @@ master_factor: f64,
|
|||
/// Current layout of the output.
|
||||
layout: Layout,
|
||||
|
||||
/// List of status tracking objects relaying changes to this output to clients.
|
||||
status_trackers: std.SinglyLinkedList(OutputStatus),
|
||||
|
||||
// All listeners for this output, in alphabetical order
|
||||
listen_destroy: c.wl_listener,
|
||||
listen_frame: c.wl_listener,
|
||||
|
@ -133,6 +137,8 @@ pub fn init(self: *Self, root: *Root, wlr_output: *c.wlr_output) !void {
|
|||
// LeftMaster is the default layout for all outputs
|
||||
self.layout = Layout.LeftMaster;
|
||||
|
||||
self.status_trackers = std.SinglyLinkedList(OutputStatus).init();
|
||||
|
||||
// Set up listeners
|
||||
self.listen_destroy.notify = handleDestroy;
|
||||
c.wl_signal_add(&wlr_output.events.destroy, &self.listen_destroy);
|
||||
|
@ -170,20 +176,6 @@ pub fn init(self: *Self, root: *Root, wlr_output: *c.wlr_output) !void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
for (self.layers) |*layer| {
|
||||
while (layer.pop()) |layer_surface_node| {
|
||||
self.root.server.allocator.destroy(layer_surface_node);
|
||||
}
|
||||
}
|
||||
|
||||
while (self.views.first) |node| {
|
||||
node.view.deinit();
|
||||
self.views.remove(node);
|
||||
self.root.server.allocator.destroy(node);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getRenderer(self: Self) *c.wlr_renderer {
|
||||
return c.river_wlr_backend_get_renderer(self.wlr_output.backend);
|
||||
}
|
||||
|
@ -708,7 +700,7 @@ fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
|
|||
while (seat_it) |seat_node| : (seat_it = seat_node.next) {
|
||||
const seat = &seat_node.data;
|
||||
if (seat.focused_output == self) {
|
||||
seat.focused_output = fallback_output;
|
||||
seat.focusOutput(self);
|
||||
seat.focus(null);
|
||||
}
|
||||
}
|
||||
|
|
77
river/OutputStatus.zig
Normal file
77
river/OutputStatus.zig
Normal file
|
@ -0,0 +1,77 @@
|
|||
// This file is part of river, a dynamic tiling wayland compositor.
|
||||
//
|
||||
// Copyright 2020 Isaac Freund
|
||||
//
|
||||
// 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, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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 Self = @This();
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig");
|
||||
|
||||
const Log = @import("log.zig").Log;
|
||||
const Output = @import("Output.zig");
|
||||
const View = @import("View.zig");
|
||||
const ViewStack = @import("view_stack.zig").ViewStack;
|
||||
|
||||
const implementation = c.struct_zriver_output_status_v1_interface{
|
||||
.destroy = destroy,
|
||||
};
|
||||
|
||||
output: *Output,
|
||||
wl_resource: *c.wl_resource,
|
||||
|
||||
pub fn init(self: *Self, output: *Output, wl_resource: *c.wl_resource) void {
|
||||
self.output = output;
|
||||
self.wl_resource = wl_resource;
|
||||
|
||||
c.wl_resource_set_implementation(wl_resource, &implementation, self, handleResourceDestroy);
|
||||
|
||||
// Send view/focused tags once on bind.
|
||||
self.sendViewTags();
|
||||
self.sendFocusedTags();
|
||||
}
|
||||
|
||||
fn handleResourceDestroy(wl_resource: ?*c.wl_resource) callconv(.C) void {
|
||||
const self = @ptrCast(*Self, @alignCast(@alignOf(*Self), c.wl_resource_get_user_data(wl_resource)));
|
||||
const node = @fieldParentPtr(std.SinglyLinkedList(Self).Node, "data", self);
|
||||
self.output.status_trackers.remove(node);
|
||||
}
|
||||
|
||||
fn destroy(wl_client: ?*c.wl_client, wl_resource: ?*c.wl_resource) callconv(.C) void {
|
||||
c.wl_resource_destroy(wl_resource);
|
||||
}
|
||||
|
||||
/// Send the current tags of each view on the output to the client.
|
||||
pub fn sendViewTags(self: Self) void {
|
||||
var view_tags: c.wl_array = undefined;
|
||||
c.wl_array_init(&view_tags);
|
||||
var it = ViewStack(View).iterator(self.output.views.first, std.math.maxInt(u32));
|
||||
while (it.next()) |node| {
|
||||
const ptr = c.wl_array_add(&view_tags, @sizeOf(u32)) orelse {
|
||||
c.wl_resource_post_no_memory(self.wl_resource);
|
||||
Log.Error.log("out of memory", .{});
|
||||
return;
|
||||
};
|
||||
const ptr_u32 = @ptrCast(*u32, @alignCast(@alignOf(u32), ptr));
|
||||
ptr_u32.* = node.view.current_tags;
|
||||
}
|
||||
c.zriver_output_status_v1_send_view_tags(self.wl_resource, &view_tags);
|
||||
}
|
||||
|
||||
/// Send the currently focused tags of the output to the client.
|
||||
pub fn sendFocusedTags(self: Self) void {
|
||||
c.zriver_output_status_v1_send_focused_tags(self.wl_resource, self.output.current_focused_tags);
|
||||
}
|
|
@ -104,7 +104,7 @@ pub fn addOutput(self: *Self, wlr_output: *c.wlr_output) void {
|
|||
// TODO: move views from the noop output to the new one and focus(null)
|
||||
var it = self.server.input_manager.seats.first;
|
||||
while (it) |seat_node| : (it = seat_node.next) {
|
||||
seat_node.data.focused_output = &self.outputs.first.?.data;
|
||||
seat_node.data.focusOutput(&self.outputs.first.?.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -220,8 +220,12 @@ fn commitTransaction(self: *Self) void {
|
|||
);
|
||||
output.current_focused_tags = tags;
|
||||
output.pending_focused_tags = null;
|
||||
var it = output.status_trackers.first;
|
||||
while (it) |node| : (it = node.next) node.data.sendFocusedTags();
|
||||
}
|
||||
|
||||
var view_tags_changed = false;
|
||||
|
||||
var view_it = ViewStack(View).iterator(output.views.first, std.math.maxInt(u32));
|
||||
while (view_it.next()) |view_node| {
|
||||
const view = &view_node.view;
|
||||
|
@ -236,10 +240,16 @@ fn commitTransaction(self: *Self) void {
|
|||
if (view.pending_tags) |tags| {
|
||||
view.current_tags = tags;
|
||||
view.pending_tags = null;
|
||||
view_tags_changed = true;
|
||||
}
|
||||
|
||||
view.dropStashedBuffer();
|
||||
}
|
||||
|
||||
if (view_tags_changed) {
|
||||
var it = output.status_trackers.first;
|
||||
while (it) |node| : (it = node.next) node.data.sendViewTags();
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over all seats and update focus
|
||||
|
|
|
@ -27,9 +27,12 @@ const InputManager = @import("InputManager.zig");
|
|||
const Keyboard = @import("Keyboard.zig");
|
||||
const LayerSurface = @import("LayerSurface.zig");
|
||||
const Output = @import("Output.zig");
|
||||
const SeatStatus = @import("SeatStatus.zig");
|
||||
const View = @import("View.zig");
|
||||
const ViewStack = @import("view_stack.zig").ViewStack;
|
||||
|
||||
// TODO: remove none variant, unify focused_view and focused_layer fields
|
||||
// with type ?FocusTarget
|
||||
const FocusTarget = union(enum) {
|
||||
view: *View,
|
||||
layer: *LayerSurface,
|
||||
|
@ -62,6 +65,9 @@ focus_stack: ViewStack(*View),
|
|||
/// recieve focus.
|
||||
focused_layer: ?*LayerSurface,
|
||||
|
||||
/// List of status tracking objects relaying changes to this seat to clients.
|
||||
status_trackers: std.SinglyLinkedList(SeatStatus),
|
||||
|
||||
listen_request_set_selection: c.wl_listener,
|
||||
|
||||
pub fn init(self: *Self, input_manager: *InputManager, name: []const u8) !void {
|
||||
|
@ -70,6 +76,7 @@ pub fn init(self: *Self, input_manager: *InputManager, name: []const u8) !void {
|
|||
// This will be automatically destroyed when the display is destroyed
|
||||
self.wlr_seat = c.wlr_seat_create(input_manager.server.wl_display, name.ptr) orelse
|
||||
return error.CantCreateWlrSeat;
|
||||
self.wlr_seat.data = self;
|
||||
|
||||
try self.cursor.init(self);
|
||||
errdefer self.cursor.destroy();
|
||||
|
@ -86,6 +93,8 @@ pub fn init(self: *Self, input_manager: *InputManager, name: []const u8) !void {
|
|||
|
||||
self.focused_layer = null;
|
||||
|
||||
self.status_trackers = std.SinglyLinkedList(SeatStatus).init();
|
||||
|
||||
self.listen_request_set_selection.notify = handleRequestSetSelection;
|
||||
c.wl_signal_add(&self.wlr_seat.events.request_set_selection, &self.listen_request_set_selection);
|
||||
}
|
||||
|
@ -167,9 +176,7 @@ pub fn setFocusRaw(self: *Self, focus_target: FocusTarget) void {
|
|||
.view => |target_view| target_view == self.focused_view,
|
||||
.layer => |target_layer| target_layer == self.focused_layer,
|
||||
.none => false,
|
||||
}) {
|
||||
return;
|
||||
}
|
||||
}) return;
|
||||
|
||||
// Obtain the target wlr_surface
|
||||
const target_wlr_surface = switch (focus_target) {
|
||||
|
@ -223,6 +230,23 @@ pub fn setFocusRaw(self: *Self, focus_target: FocusTarget) void {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Inform any clients tracking status of the change
|
||||
var it = self.status_trackers.first;
|
||||
while (it) |node| : (it = node.next) node.data.sendFocusedView();
|
||||
}
|
||||
|
||||
/// Focus the given output, notifying any listening clients of the change.
|
||||
pub fn focusOutput(self: *Self, output: *Output) void {
|
||||
const root = &self.input_manager.server.root;
|
||||
|
||||
var it = self.status_trackers.first;
|
||||
while (it) |node| : (it = node.next) node.data.sendOutput(.unfocused);
|
||||
|
||||
self.focused_output = output;
|
||||
|
||||
it = self.status_trackers.first;
|
||||
while (it) |node| : (it = node.next) node.data.sendOutput(.focused);
|
||||
}
|
||||
|
||||
/// Handle the unmapping of a view, removing it from the focus stack and
|
||||
|
|
81
river/SeatStatus.zig
Normal file
81
river/SeatStatus.zig
Normal file
|
@ -0,0 +1,81 @@
|
|||
// This file is part of river, a dynamic tiling wayland compositor.
|
||||
//
|
||||
// Copyright 2020 Isaac Freund
|
||||
//
|
||||
// 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, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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 Self = @This();
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig");
|
||||
|
||||
const Log = @import("log.zig").Log;
|
||||
const Seat = @import("Seat.zig");
|
||||
const Output = @import("Output.zig");
|
||||
const View = @import("View.zig");
|
||||
|
||||
const FocusState = enum {
|
||||
focused,
|
||||
unfocused,
|
||||
};
|
||||
|
||||
const implementation = c.struct_zriver_seat_status_v1_interface{
|
||||
.destroy = destroy,
|
||||
};
|
||||
|
||||
seat: *Seat,
|
||||
wl_resource: *c.wl_resource,
|
||||
|
||||
pub fn init(self: *Self, seat: *Seat, wl_resource: *c.wl_resource) void {
|
||||
self.seat = seat;
|
||||
self.wl_resource = wl_resource;
|
||||
|
||||
c.wl_resource_set_implementation(wl_resource, &implementation, self, handleResourceDestroy);
|
||||
|
||||
// Send focused output/view once on bind
|
||||
self.sendOutput(.focused);
|
||||
self.sendFocusedView();
|
||||
}
|
||||
|
||||
fn handleResourceDestroy(wl_resource: ?*c.wl_resource) callconv(.C) void {
|
||||
const self = @ptrCast(*Self, @alignCast(@alignOf(*Self), c.wl_resource_get_user_data(wl_resource)));
|
||||
const node = @fieldParentPtr(std.SinglyLinkedList(Self).Node, "data", self);
|
||||
self.seat.status_trackers.remove(node);
|
||||
}
|
||||
|
||||
fn destroy(wl_client: ?*c.wl_client, wl_resource: ?*c.wl_resource) callconv(.C) void {
|
||||
c.wl_resource_destroy(wl_resource);
|
||||
}
|
||||
|
||||
pub fn sendOutput(self: Self, state: FocusState) void {
|
||||
const wl_client = c.wl_resource_get_client(self.wl_resource);
|
||||
const output_resources = &self.seat.focused_output.wlr_output.resources;
|
||||
var output_resource = c.wl_resource_from_link(output_resources.next);
|
||||
while (c.wl_resource_get_link(output_resource) != output_resources) : (output_resource =
|
||||
c.wl_resource_from_link(c.wl_resource_get_link(output_resource).*.next))
|
||||
{
|
||||
if (c.wl_resource_get_client(output_resource) == wl_client) switch (state) {
|
||||
.focused => c.zriver_seat_status_v1_send_focused_output(self.wl_resource, output_resource),
|
||||
.unfocused => c.zriver_seat_status_v1_send_unfocused_output(self.wl_resource, output_resource),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sendFocusedView(self: Self) void {
|
||||
c.zriver_seat_status_v1_send_focused_view(self.wl_resource, if (self.seat.focused_view) |v|
|
||||
v.getTitle()
|
||||
else
|
||||
"");
|
||||
}
|
|
@ -23,15 +23,16 @@ const std = @import("std");
|
|||
const c = @import("c.zig");
|
||||
|
||||
const Config = @import("Config.zig");
|
||||
const Control = @import("Control.zig");
|
||||
const DecorationManager = @import("DecorationManager.zig");
|
||||
const InputManager = @import("InputManager.zig");
|
||||
const LayerSurface = @import("LayerSurface.zig");
|
||||
const Log = @import("log.zig").Log;
|
||||
const Output = @import("Output.zig");
|
||||
const Root = @import("Root.zig");
|
||||
const StatusManager = @import("StatusManager.zig");
|
||||
const View = @import("View.zig");
|
||||
const ViewStack = @import("view_stack.zig").ViewStack;
|
||||
const Control = @import("Control.zig");
|
||||
const XwaylandUnmanaged = @import("XwaylandUnmanaged.zig");
|
||||
|
||||
allocator: *std.mem.Allocator,
|
||||
|
@ -57,6 +58,7 @@ input_manager: InputManager,
|
|||
root: Root,
|
||||
config: Config,
|
||||
control: Control,
|
||||
status_manager: StatusManager,
|
||||
|
||||
pub fn init(self: *Self, allocator: *std.mem.Allocator) !void {
|
||||
self.allocator = allocator;
|
||||
|
@ -123,6 +125,7 @@ pub fn init(self: *Self, allocator: *std.mem.Allocator) !void {
|
|||
// Must be called after root is initialized
|
||||
try self.input_manager.init(self);
|
||||
try self.control.init(self);
|
||||
try self.status_manager.init(self);
|
||||
|
||||
// These all free themselves when the wl_display is destroyed
|
||||
_ = c.wlr_data_device_manager_create(self.wl_display) orelse
|
||||
|
|
146
river/StatusManager.zig
Normal file
146
river/StatusManager.zig
Normal file
|
@ -0,0 +1,146 @@
|
|||
// This file is part of river, a dynamic tiling wayland compositor.
|
||||
//
|
||||
// Copyright 2020 Isaac Freund
|
||||
//
|
||||
// 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, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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 Self = @This();
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig");
|
||||
|
||||
const Log = @import("log.zig").Log;
|
||||
const Output = @import("Output.zig");
|
||||
const OutputStatus = @import("OutputStatus.zig");
|
||||
const Seat = @import("Seat.zig");
|
||||
const SeatStatus = @import("SeatStatus.zig");
|
||||
const Server = @import("Server.zig");
|
||||
|
||||
const protocol_version = 1;
|
||||
|
||||
const implementation = c.struct_zriver_status_manager_v1_interface{
|
||||
.destroy = destroy,
|
||||
.get_river_output_status = getRiverOutputStatus,
|
||||
.get_river_seat_status = getRiverSeatStatus,
|
||||
};
|
||||
|
||||
// TODO: remove this field, move allocator to util or something
|
||||
server: *Server,
|
||||
wl_global: *c.wl_global,
|
||||
|
||||
listen_display_destroy: c.wl_listener,
|
||||
|
||||
pub fn init(self: *Self, server: *Server) !void {
|
||||
self.server = server;
|
||||
self.wl_global = c.wl_global_create(
|
||||
server.wl_display,
|
||||
&c.zriver_status_manager_v1_interface,
|
||||
protocol_version,
|
||||
self,
|
||||
bind,
|
||||
) orelse return error.CantCreateWlGlobal;
|
||||
|
||||
self.listen_display_destroy.notify = handleDisplayDestroy;
|
||||
c.wl_display_add_destroy_listener(server.wl_display, &self.listen_display_destroy);
|
||||
}
|
||||
|
||||
fn handleDisplayDestroy(wl_listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
|
||||
const self = @fieldParentPtr(Self, "listen_display_destroy", wl_listener.?);
|
||||
c.wl_global_destroy(self.wl_global);
|
||||
}
|
||||
|
||||
/// Called when a client binds our global
|
||||
fn bind(wl_client: ?*c.wl_client, data: ?*c_void, version: u32, id: u32) callconv(.C) void {
|
||||
const self = @ptrCast(*Self, @alignCast(@alignOf(*Self), data));
|
||||
const wl_resource = c.wl_resource_create(
|
||||
wl_client,
|
||||
&c.zriver_status_manager_v1_interface,
|
||||
@intCast(c_int, version),
|
||||
id,
|
||||
) orelse {
|
||||
c.wl_client_post_no_memory(wl_client);
|
||||
Log.Error.log("out of memory\n", .{});
|
||||
return;
|
||||
};
|
||||
c.wl_resource_set_implementation(wl_resource, &implementation, self, null);
|
||||
}
|
||||
|
||||
fn destroy(wl_client: ?*c.wl_client, wl_resource: ?*c.wl_resource) callconv(.C) void {}
|
||||
|
||||
fn getRiverOutputStatus(
|
||||
wl_client: ?*c.wl_client,
|
||||
wl_resource: ?*c.wl_resource,
|
||||
new_id: u32,
|
||||
output_wl_resource: ?*c.wl_resource,
|
||||
) callconv(.C) void {
|
||||
const self = @ptrCast(*Self, @alignCast(@alignOf(*Self), c.wl_resource_get_user_data(wl_resource)));
|
||||
// This can be null if the output is inert, in which case we ignore the request
|
||||
const wlr_output = c.wlr_output_from_resource(output_wl_resource) orelse return;
|
||||
const output = @ptrCast(*Output, @alignCast(@alignOf(*Output), wlr_output.*.data));
|
||||
const allocator = self.server.allocator;
|
||||
|
||||
const node = allocator.create(std.SinglyLinkedList(OutputStatus).Node) catch {
|
||||
c.wl_client_post_no_memory(wl_client);
|
||||
Log.Error.log("out of memory\n", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
const output_status_resource = c.wl_resource_create(
|
||||
wl_client,
|
||||
&c.zriver_output_status_v1_interface,
|
||||
protocol_version,
|
||||
new_id,
|
||||
) orelse {
|
||||
c.wl_client_post_no_memory(wl_client);
|
||||
Log.Error.log("out of memory\n", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
node.data.init(output, output_status_resource);
|
||||
output.status_trackers.prepend(node);
|
||||
}
|
||||
|
||||
fn getRiverSeatStatus(
|
||||
wl_client: ?*c.wl_client,
|
||||
wl_resource: ?*c.wl_resource,
|
||||
new_id: u32,
|
||||
seat_wl_resource: ?*c.wl_resource,
|
||||
) callconv(.C) void {
|
||||
const self = @ptrCast(*Self, @alignCast(@alignOf(*Self), c.wl_resource_get_user_data(wl_resource)));
|
||||
// This can be null if the seat is inert, in which case we ignore the request
|
||||
const wlr_seat_client = c.wlr_seat_client_from_resource(wl_resource) orelse return;
|
||||
const seat = @ptrCast(*Seat, @alignCast(@alignOf(*Seat), wlr_seat_client.*.seat.*.data));
|
||||
const allocator = self.server.allocator;
|
||||
|
||||
const node = allocator.create(std.SinglyLinkedList(SeatStatus).Node) catch {
|
||||
c.wl_client_post_no_memory(wl_client);
|
||||
Log.Error.log("out of memory\n", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
const seat_status_resource = c.wl_resource_create(
|
||||
wl_client,
|
||||
&c.zriver_seat_status_v1_interface,
|
||||
protocol_version,
|
||||
new_id,
|
||||
) orelse {
|
||||
c.wl_client_post_no_memory(wl_client);
|
||||
Log.Error.log("out of memory\n", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
node.data.init(seat, seat_status_resource);
|
||||
seat.status_trackers.prepend(node);
|
||||
}
|
|
@ -223,6 +223,14 @@ pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_surfa
|
|||
};
|
||||
}
|
||||
|
||||
/// Return the current title of the view. May be an empty string.
|
||||
pub fn getTitle(self: Self) [*:0]const u8 {
|
||||
return switch (self.impl) {
|
||||
.xdg_toplevel => |xdg_toplevel| xdg_toplevel.getTitle(),
|
||||
.xwayland_view => |xwayland_view| xwayland_view.getTitle(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Called by the impl when the surface is ready to be displayed
|
||||
pub fn map(self: *Self) void {
|
||||
const root = self.output.root;
|
||||
|
|
|
@ -46,3 +46,7 @@ pub fn forEachSurface(
|
|||
pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_surface {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
pub fn getTitle(self: Self) [*:0]const u8 {
|
||||
unreachable;
|
||||
}
|
||||
|
|
|
@ -100,6 +100,15 @@ pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_surfa
|
|||
);
|
||||
}
|
||||
|
||||
/// Return the current title of the toplevel. May be an empty string.
|
||||
pub fn getTitle(self: Self) [*:0]const u8 {
|
||||
const wlr_xdg_toplevel: *c.wlr_xdg_toplevel = @field(
|
||||
self.wlr_xdg_surface,
|
||||
c.wlr_xdg_surface_union,
|
||||
).toplevel;
|
||||
return wlr_xdg_toplevel.title;
|
||||
}
|
||||
|
||||
/// Called when the xdg surface is destroyed
|
||||
fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
|
||||
const self = @fieldParentPtr(Self, "listen_destroy", listener.?);
|
||||
|
|
|
@ -105,6 +105,11 @@ pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_surfa
|
|||
);
|
||||
}
|
||||
|
||||
/// Get the current title of the xwayland surface. May be an empty string
|
||||
pub fn getTitle(self: Self) [*:0]const u8 {
|
||||
return self.wlr_xwayland_surface.title;
|
||||
}
|
||||
|
||||
/// Called when the xwayland surface is destroyed
|
||||
fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
|
||||
const self = @fieldParentPtr(Self, "listen_destroy", listener.?);
|
||||
|
|
|
@ -51,6 +51,7 @@ pub usingnamespace @cImport({
|
|||
@cInclude("include/bindings.h");
|
||||
|
||||
@cInclude("river-control-unstable-v1-protocol.h");
|
||||
@cInclude("river-status-unstable-v1-protocol.h");
|
||||
});
|
||||
|
||||
// These are needed because zig currently names translated anonymous unions
|
||||
|
|
|
@ -45,10 +45,10 @@ pub fn focusOutput(
|
|||
|
||||
// Focus the next/prev output in the list if there is one, else wrap
|
||||
const focused_node = @fieldParentPtr(std.TailQueue(Output).Node, "data", seat.focused_output);
|
||||
seat.focused_output = switch (direction) {
|
||||
seat.focusOutput(switch (direction) {
|
||||
.Next => if (focused_node.next) |node| &node.data else &root.outputs.first.?.data,
|
||||
.Prev => if (focused_node.prev) |node| &node.data else &root.outputs.last.?.data,
|
||||
};
|
||||
});
|
||||
|
||||
seat.focus(null);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue