river: get rid of all server-created options

- Replace the layout option with new default-layout and output-layout
commands.
- Remove the ability to get/set the output title entirely.
This commit is contained in:
Isaac Freund
2021-04-26 16:35:26 +02:00
parent 84f5283889
commit a6f908d7eb
6 changed files with 94 additions and 56 deletions

View File

@ -59,6 +59,11 @@ csd_filter: std.ArrayList([]const u8),
/// The selected focus_follows_cursor mode
focus_follows_cursor: FocusFollowsCursorMode = .disabled,
/// The default layout namespace for outputs which have never had a per-output
/// value set. Call Output.handleLayoutNamespaceChange() on setting this if
/// Output.layout_namespace is null.
default_layout_namespace: []const u8 = &[0]u8{},
opacity: struct {
/// The opacity of focused views
focused: f32 = 1.0,
@ -119,4 +124,6 @@ pub fn deinit(self: *Self) void {
for (self.csd_filter.items) |s| util.gpa.free(s);
self.csd_filter.deinit();
util.gpa.free(self.default_layout_namespace);
}

View File

@ -61,11 +61,9 @@ pub fn create(client: *wl.Client, version: u32, id: u32, output: *Output, namesp
// If the namespace matches that of the output, set the layout as
// the active one of the output and arrange it.
if (output.layout_option.get().string) |current_layout| {
if (mem.eql(u8, namespace, mem.span(current_layout))) {
output.pending.layout = &node.data;
output.arrangeViews();
}
if (mem.eql(u8, namespace, output.layoutNamespace())) {
output.pending.layout = &node.data;
output.arrangeViews();
}
}

View File

@ -81,6 +81,11 @@ layout_demand: ?LayoutDemand = null,
/// List of all layouts
layouts: std.TailQueue(Layout) = .{},
/// The current layout namespace of the output. If null,
/// config.default_layout_namespace should be used instead.
/// Call handleLayoutNamespaceChange() after setting this.
layout_namespace: ?[]const u8 = null,
/// Determines where new views will be attached to the view stack.
attach_mode: AttachMode = .top,
@ -95,11 +100,6 @@ enable: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleEnable),
frame: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleFrame),
mode: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleMode),
layout_option: *OutputOption,
output_title: wl.Listener(*Option.Value) = wl.Listener(*Option.Value).init(handleTitleChange),
layout_change: wl.Listener(*Option.Value) = wl.Listener(*Option.Value).init(handleLayoutChange),
pub fn init(self: *Self, root: *Root, wlr_output: *wlr.Output) !void {
// Some backends don't have modes. DRM+KMS does, and we need to set a mode
// before we can use the output. The mode is a tuple of (width, height,
@ -116,7 +116,6 @@ pub fn init(self: *Self, root: *Root, wlr_output: *wlr.Output) !void {
.root = root,
.wlr_output = wlr_output,
.usable_box = undefined,
.layout_option = undefined,
};
wlr_output.data = @ptrToInt(self);
@ -155,23 +154,7 @@ pub fn init(self: *Self, root: *Root, wlr_output: *wlr.Output) !void {
try options_manager.createOutputOptions(self);
errdefer options_manager.destroyOutputOptions(self);
// Set the default title of this output
var buf: ["river - ".len + wlr_output.name.len + 1]u8 = undefined;
const default_title = fmt.bufPrintZ(&buf, "river - {}", .{mem.spanZ(&wlr_output.name)}) catch unreachable;
self.setTitle(default_title);
const global_title_option = options_manager.getOption("output_title") orelse unreachable;
const title_option = global_title_option.getOutputOption(self).?;
title_option.set(.{ .string = default_title }) catch |err| switch (err) {
error.TypeMismatch => unreachable,
error.OutOfMemory => return err,
};
const global_layout_option = options_manager.getOption("layout") orelse unreachable;
self.layout_option = global_layout_option.getOutputOption(self).?;
self.layout_option.event.update.add(&self.layout_change);
title_option.event.update.add(&self.output_title);
self.setTitle();
}
}
@ -464,10 +447,10 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) v
self.frame.link.remove();
self.mode.link.remove();
// Cleanup the layout demand, if any
if (self.layout_demand) |demand| demand.deinit();
// Free all memory and clean up the wlr.Output
if (self.layout_demand) |demand| demand.deinit();
if (self.layout_namespace) |namespace| util.gpa.free(namespace);
self.wlr_output.data = undefined;
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
@ -506,7 +489,9 @@ pub fn getEffectiveResolution(self: *Self) struct { width: u32, height: u32 } {
};
}
pub fn setTitle(self: *Self, title: [*:0]const u8) void {
fn setTitle(self: Self) void {
var buf: ["river - ".len + self.wlr_output.name.len + 1]u8 = undefined;
const title = fmt.bufPrintZ(&buf, "river - {}", .{mem.spanZ(&self.wlr_output.name)}) catch unreachable;
if (self.wlr_output.isWl()) {
self.wlr_output.wlSetTitle(title);
} else if (wlr.config.has_x11_backend and self.wlr_output.isX11()) {
@ -514,21 +499,17 @@ pub fn setTitle(self: *Self, title: [*:0]const u8) void {
}
}
fn handleTitleChange(listener: *wl.Listener(*Option.Value), value: *Option.Value) void {
const self = @fieldParentPtr(Self, "output_title", listener);
if (value.string) |title| self.setTitle(title);
}
fn handleLayoutChange(listener: *wl.Listener(*Option.Value), value: *Option.Value) void {
const self = @fieldParentPtr(Self, "layout_change", listener);
pub fn handleLayoutNamespaceChange(self: *Self) void {
// The user changed the layout namespace of this output. Try to find a
// matching layout.
self.pending.layout = if (value.string) |namespace| blk: {
var layout_it = self.layouts.first;
break :blk while (layout_it) |node| : (layout_it = node.next) {
if (mem.eql(u8, mem.span(namespace), node.data.namespace)) break &node.data;
} else null;
var it = self.layouts.first;
self.pending.layout = while (it) |node| : (it = node.next) {
if (mem.eql(u8, self.layoutNamespace(), node.data.namespace)) break &node.data;
} else null;
self.arrangeViews();
self.root.startTransaction();
}
pub fn layoutNamespace(self: Self) []const u8 {
return self.layout_namespace orelse self.root.server.config.default_layout_namespace;
}

View File

@ -50,16 +50,18 @@ const str_to_impl_fn = [_]struct {
.{ .name = "close", .impl = @import("command/close.zig").close },
.{ .name = "csd-filter-add", .impl = @import("command/filter.zig").csdFilterAdd },
.{ .name = "declare-mode", .impl = @import("command/declare_mode.zig").declareMode },
.{ .name = "default-layout", .impl = @import("command/layout.zig").defaultLayout },
.{ .name = "enter-mode", .impl = @import("command/enter_mode.zig").enterMode },
.{ .name = "exit", .impl = @import("command/exit.zig").exit },
.{ .name = "float-filter-add", .impl = @import("command/filter.zig").floatFilterAdd },
.{ .name = "focus-output", .impl = @import("command/focus_output.zig").focusOutput },
.{ .name = "focus-follows-cursor", .impl = @import("command/focus_follows_cursor.zig").focusFollowsCursor },
.{ .name = "focus-output", .impl = @import("command/focus_output.zig").focusOutput },
.{ .name = "focus-view", .impl = @import("command/focus_view.zig").focusView },
.{ .name = "map", .impl = @import("command/map.zig").map },
.{ .name = "map-pointer", .impl = @import("command/map.zig").mapPointer },
.{ .name = "move", .impl = @import("command/move.zig").move },
.{ .name = "opacity", .impl = @import("command/opacity.zig").opacity },
.{ .name = "output-layout", .impl = @import("command/layout.zig").outputLayout },
.{ .name = "resize", .impl = @import("command/move.zig").resize },
.{ .name = "send-to-output", .impl = @import("command/send_to_output.zig").sendToOutput },
.{ .name = "set-focused-tags", .impl = @import("command/tags.zig").setFocusedTags },

54
river/command/layout.zig Normal file
View File

@ -0,0 +1,54 @@
// This file is part of river, a dynamic tiling wayland compositor.
//
// Copyright 2021 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, 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 std = @import("std");
const util = @import("../util.zig");
const Error = @import("../command.zig").Error;
const Seat = @import("../Seat.zig");
pub fn outputLayout(
allocator: *std.mem.Allocator,
seat: *Seat,
args: []const []const u8,
out: *?[]const u8,
) Error!void {
if (args.len < 2) return Error.NotEnoughArguments;
if (args.len > 2) return Error.TooManyArguments;
const output = seat.focused_output;
output.layout_namespace = try util.gpa.dupe(u8, args[1]);
output.handleLayoutNamespaceChange();
}
pub fn defaultLayout(
allocator: *std.mem.Allocator,
seat: *Seat,
args: []const []const u8,
out: *?[]const u8,
) Error!void {
if (args.len < 2) return Error.NotEnoughArguments;
if (args.len > 2) return Error.TooManyArguments;
const server = seat.input_manager.server;
server.config.default_layout_namespace = try util.gpa.dupe(u8, args[1]);
var it = server.root.all_outputs.first;
while (it) |node| : (it = node.next) {
const output = node.data;
if (output.layout_namespace == null) output.handleLayoutNamespaceChange();
}
}