Skip to content

Commit

Permalink
Implement per output configuration & fractional scaling
Browse files Browse the repository at this point in the history
  • Loading branch information
francma committed Oct 14, 2023
1 parent c3db849 commit e18cf4c
Show file tree
Hide file tree
Showing 16 changed files with 711 additions and 347 deletions.
1 change: 0 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ trim_trailing_whitespace = true

[*.{c,h,txt}]
indent_style = tab
indent_size = 4

[*.{xml,yml}]
indent_style = space
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ on:
jobs:
test:
runs-on: ubuntu-latest
container: alpine:3.17
container: alpine:3.18
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: apk update && apk add meson wayland-dev musl-dev wayland-protocols gcc inih-dev pixman-dev cmocka-dev
run: apk update && apk add meson wayland-dev musl-dev wayland-protocols gcc inih-dev cmocka-dev
- name: Run tests
run: meson setup test && ninja -C test test

analyze:
runs-on: ubuntu-latest
container: alpine:3.17
container: alpine:3.18
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: apk update && apk add meson wayland-dev musl-dev wayland-protocols gcc inih-dev pixman-dev cmocka-dev clang15 clang15-extra-tools clang15-analyzer
run: apk update && apk add meson wayland-dev musl-dev wayland-protocols gcc inih-dev cmocka-dev clang16 clang16-extra-tools clang16-analyzer
- name: Run clang-analyzer
if: success() || failure()
run: scan-build meson setup clang-analyzer && scan-build --status-bugs ninja -C clang-analyzer
Expand All @@ -33,10 +33,10 @@ jobs:

format:
runs-on: ubuntu-latest
container: alpine:3.17
container: alpine:3.18
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: apk update && apk add clang15-extra-tools
run: apk update && apk add clang16-extra-tools
- name: Run clang-format
run: clang-format -Werror --dry-run src/* test/*
48 changes: 23 additions & 25 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ project(

cc = meson.get_compiler('c')

wayland_protos = dependency('wayland-protocols', version: '>=1.13')
# minimal version with fractional scaling protocol
wayland_protos = dependency('wayland-protocols', version: '>=1.31')
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
wayland_scanner = find_program('wayland-scanner')
wayland_client = dependency('wayland-client')
Expand All @@ -32,34 +33,31 @@ wayland_scanner_client = generator(
arguments: ['client-header', '@INPUT@', '@OUTPUT@'],
)

client_protocols = [
[wl_protocol_dir + '/stable/xdg-shell', 'xdg-shell.xml'],
[meson.project_source_root() + '/protocols', 'wlr-layer-shell-unstable-v1.xml'],
wl_proto_xml = [
wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml',
wl_protocol_dir / 'stable/viewporter/viewporter.xml',
'protocols/wlr-layer-shell-unstable-v1.xml',
wl_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml',
]

foreach p : client_protocols
xml = join_paths(p)
src = wayland_scanner_code.process(xml)
header = wayland_scanner_client.process(xml)

name = p[1].split('.')[0].underscorify()

lib = static_library(
name,
[src, header],
dependencies: [wayland_client],
)

dep = declare_dependency(
link_with: lib,
sources: header,
)

set_variable(name, dep)
wl_proto_headers = []
wl_proto_src = []
foreach proto : wl_proto_xml
wl_proto_headers += custom_target(
proto.underscorify() + '_client_header',
output: '@[email protected]',
input: proto,
command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'])

wl_proto_src += custom_target(
proto.underscorify() + '_private_code',
output: '@[email protected]',
input: proto,
command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'])
endforeach

wob_sources = ['src/main.c', 'src/image.c', 'src/log.c', 'src/color.c', 'src/config.c', 'src/wob.c']
wob_dependencies = [wayland_client, wlr_layer_shell_unstable_v1, xdg_shell, rt, inih]
wob_sources = ['src/main.c', 'src/image.c', 'src/log.c', 'src/color.c', 'src/config.c', 'src/wob.c', 'src/shm.c', wl_proto_src, wl_proto_headers]
wob_dependencies = [wayland_client, rt, inih]
if seccomp.found()
wob_dependencies += seccomp
wob_sources += 'src/pledge_seccomp.c'
Expand Down
18 changes: 9 additions & 9 deletions protocols/wlr-layer-shell-unstable-v1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<description summary="create surfaces that are layers of the desktop">
Clients can use this interface to assign the surface_layer role to
wl_surfaces. Such surfaces are assigned to a "layer" of the output and
rendered with a defined z-depth respective to each other. They may also be
surface with a defined z-depth respective to each other. They may also be
anchored to the edges and corners of a screen and specify input handling
semantics. This interface should be suitable for the implementation of
many desktop shell components, and a broad number of other applications
Expand All @@ -42,9 +42,9 @@
layer_surface, or raises a protocol error if another role is already
assigned.

Creating a layer surface from a wl_surface which has a buffer attached
Creating a layer surface from a wl_surface which has a shm_data attached
or committed is a client error, and any attempts by a client to attach
or manipulate a buffer prior to the first layer_surface.configure call
or manipulate a shm_data prior to the first layer_surface.configure call
must also be treated as errors.

You may pass NULL for output to allow the compositor to decide which
Expand All @@ -64,15 +64,15 @@
<enum name="error">
<entry name="role" value="0" summary="wl_surface has another role"/>
<entry name="invalid_layer" value="1" summary="layer value is invalid"/>
<entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
<entry name="already_constructed" value="2" summary="wl_surface has a shm_data attached or committed"/>
</enum>

<enum name="layer">
<description summary="available layers for surfaces">
These values indicate which layers a surface can be rendered in. They
These values indicate which layers a surface can be surface in. They
are ordered by z depth, bottom-most first. Traditional shell surfaces
will typically be rendered between the bottom and top layers.
Fullscreen shell surfaces are typically rendered at the top layer.
will typically be surface between the bottom and top layers.
Fullscreen shell surfaces are typically surface at the top layer.
Multiple surfaces can share a single layer, and ordering within a
single layer is undefined.
</description>
Expand All @@ -87,7 +87,7 @@
<interface name="zwlr_layer_surface_v1" version="2">
<description summary="layer metadata interface">
An interface that may be implemented by a wl_surface, for surfaces that
are designed to be rendered as a layer of a stacked desktop-like
are designed to be surface as a layer of a stacked desktop-like
environment.

Layer surface state (layer, size, anchor, exclusive zone,
Expand Down Expand Up @@ -291,7 +291,7 @@

<request name="set_layer" since="2">
<description summary="change the layer of the surface">
Change the layer that the surface is rendered on.
Change the layer that the surface is surface on.

Layer is double-buffered, see wl_surface.commit.
</description>
Expand Down
1 change: 1 addition & 0 deletions src/color.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ wob_color_from_rgba_string(const char *str, struct wob_color *color)
switch (length) {
case 8:
parts[3] = hex_to_int(str[6]) * 16 + hex_to_int(str[7]);
// fallthrough
case 6:
parts[0] = hex_to_int(str[0]) * 16 + hex_to_int(str[1]);
parts[1] = hex_to_int(str[2]) * 16 + hex_to_int(str[3]);
Expand Down
129 changes: 120 additions & 9 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,14 +318,52 @@ handler(void *user, const char *section, const char *name, const char *value)

struct wob_output_config *output_config = wob_config_find_output(config, output_id);
if (output_config == NULL) {
output_config = malloc(sizeof(struct wob_output_config));
output_config = calloc(1, sizeof(struct wob_output_config));
if (output_config == NULL) {
wob_log_panic("calloc() failed");
}

output_config->id = strdup(output_id);
output_config->match = NULL;
output_config->dimensions = config->dimensions;
output_config->margin = config->margin;
output_config->anchor = config->anchor;
wl_list_insert(&config->outputs, &output_config->link);
}

if (strcmp(name, "name") == 0) {
output_config->name = strdup(value);

if (strcmp(name, "match") == 0) {
output_config->match = strdup(value);
return 1;
}
if (strcmp(name, "width") == 0) {
if (parse_number(value, &ul) == false) {
wob_log_error("Width must be a positive value.");
return 0;
}
output_config->dimensions.width = ul;
return 1;
}
if (strcmp(name, "height") == 0) {
if (parse_number(value, &ul) == false) {
wob_log_error("Height must be a positive value.");
return 0;
}
output_config->dimensions.height = ul;
return 1;
}
if (strcmp(name, "margin") == 0) {
if (parse_margin(value, &output_config->margin) == false) {
wob_log_error("Margin must be in format <value> or <value_top> <value_right> <value_bottom> <value_left>.");
return 0;
}
return 1;
}
if (strcmp(name, "anchor") == 0) {
if (parse_anchor(value, &ul) == false) {
wob_log_error("Anchor must be one of 'top', 'bottom', 'left', 'right', 'center'.");
return 0;
}
output_config->anchor = ul;
return 1;
}

Expand All @@ -339,7 +377,11 @@ handler(void *user, const char *section, const char *name, const char *value)

struct wob_style *style = wob_config_find_style(config, style_name);
if (style == NULL) {
style = malloc(sizeof(struct wob_style));
style = calloc(1, sizeof(struct wob_style));
if (style == NULL) {
wob_log_panic("calloc() failed");
}

style->name = strdup(style_name);
style->colors = config->default_style.colors;
style->overflow_colors = config->default_style.overflow_colors;
Expand Down Expand Up @@ -486,6 +528,14 @@ wob_config_load(struct wob_config *config, const char *config_path)
return false;
}

struct wob_output_config *output;
wl_list_for_each (output, &config->outputs, link) {
if (output->match == NULL) {
wob_log_error("Output %s is missing \"match\" property", output->id);
return false;
}
}

return true;
}

Expand Down Expand Up @@ -527,7 +577,23 @@ wob_config_debug(struct wob_config *config)

struct wob_output_config *output_config;
wl_list_for_each (output_config, &config->outputs, link) {
wob_log_debug("config.output.%s.name = %s", output_config->id, output_config->name);
wob_log_debug("config.output.%s.match = %s", output_config->id, output_config->match);
wob_log_debug("config.output.%s.margin.top = %lu", output_config->id, output_config->margin.top);
wob_log_debug("config.output.%s.margin.right = %lu", output_config->id, output_config->margin.right);
wob_log_debug("config.output.%s.margin.bottom = %lu", output_config->id, output_config->margin.bottom);
wob_log_debug("config.output.%s.margin.left = %lu", output_config->id, output_config->margin.left);
wob_log_debug("config.output.%s.dimensions.width = %lu", output_config->id, output_config->dimensions.width);
wob_log_debug("config.output.%s.dimensions.height = %lu", output_config->id, output_config->dimensions.height);
wob_log_debug("config.output.%s.dimensions.border_offset = %lu", output_config->id, output_config->dimensions.border_offset);
wob_log_debug("config.output.%s.dimensions.border_size = %lu", output_config->id, output_config->dimensions.border_size);
wob_log_debug("config.output.%s.dimensions.bar_padding = %lu", output_config->id, output_config->dimensions.bar_padding);
wob_log_debug(
"config.output.%s.dimensions.orientation = %lu (horizontal = %d, vertical = %d)",
output_config->id,
output_config->dimensions.orientation,
WOB_ORIENTATION_HORIZONTAL,
WOB_ORIENTATION_VERTICAL
);
}
}

Expand All @@ -536,7 +602,7 @@ wob_config_destroy(struct wob_config *config)
{
struct wob_output_config *output, *output_tmp;
wl_list_for_each_safe (output, output_tmp, &config->outputs, link) {
free(output->name);
free(output->match);
free(output->id);
free(output);
}
Expand Down Expand Up @@ -591,12 +657,12 @@ wob_config_find_output(struct wob_config *config, const char *output_id)
}

struct wob_output_config *
wob_config_find_output_by_name(struct wob_config *config, const char *output_name)
wob_config_match_output(struct wob_config *config, const char *match)
{
struct wob_output_config *output_config = NULL;
bool output_found = false;
wl_list_for_each (output_config, &config->outputs, link) {
if (strcmp(output_config->name, output_name) == 0) {
if (strstr(output_config->match, match) == 0) {
output_found = true;
break;
}
Expand All @@ -609,3 +675,48 @@ wob_config_find_output_by_name(struct wob_config *config, const char *output_nam
return NULL;
}
}

uint32_t
scale_apply(uint32_t base, uint32_t scale)
{
return base * (scale / 120.);
}

struct wob_dimensions
wob_dimensions_apply_scale(struct wob_dimensions dimensions, uint32_t scale)
{
struct wob_dimensions scaled_dimensions = {
.width = scale_apply(dimensions.width, scale),
.height = scale_apply(dimensions.height, scale),
.bar_padding = scale_apply(dimensions.bar_padding, scale),
.border_offset = scale_apply(dimensions.border_offset, scale),
.border_size = scale_apply(dimensions.border_size, scale),
.orientation = dimensions.orientation,
};

return scaled_dimensions;
}

bool
wob_dimensions_eq(struct wob_dimensions a, struct wob_dimensions b)
{
if (a.height != b.height) return false;
if (a.width != b.width) return false;
if (a.orientation != b.orientation) return false;
if (a.border_offset != b.border_offset) return false;
if (a.border_size != b.border_size) return false;
if (a.bar_padding != b.bar_padding) return false;

return true;
}

bool
wob_margin_eq(struct wob_margin a, struct wob_margin b)
{
if (a.top != b.top) return false;
if (a.right != b.right) return false;
if (a.bottom != b.bottom) return false;
if (a.left != b.left) return false;

return true;
}
Loading

0 comments on commit e18cf4c

Please sign in to comment.