Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Issue #21] Adds the ability to put count and ratio in the layout. #22

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .iwyu.mappings
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[
{ symbol: [ va_start, private, <stdarg.h>, public] },
{ symbol: [ va_end, private, <stdarg.h>, public] }
]
2 changes: 1 addition & 1 deletion GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ doc: wideriver
#
iwyu: override CC = $(IWYU) -Xiwyu --check_also="inc/*h"
iwyu: clean $(SRC_O) $(TST_O)
IWYU = include-what-you-use -Xiwyu --no_fwd_decls -Xiwyu --error=1 -Xiwyu --verbose=3
IWYU = include-what-you-use -Xiwyu --no_fwd_decls -Xiwyu --error=1 -Xiwyu --verbose=3 -Xiwyu --mapping_file=.iwyu.mappings

#
# cppcheck
Expand Down
27 changes: 27 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

90 changes: 90 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
description = "A simple C program using jansson built with Nix flakes";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
};

outputs = { self, nixpkgs }: {
packages = nixpkgs.lib.genAttrs [ "aarch64-darwin" "x86_64-linux" ] (system:
let pkgs = import nixpkgs { inherit system; };
in rec {
wideriver = pkgs.stdenv.mkDerivation {
pname = "wideriver";
version = "1.0";

src = ./.;

nativeBuildInputs = with pkgs; [
wayland-scanner
];
buildInputs = with pkgs; [
clang
wayland
wayland-scanner
wlr-protocols
wlroots
pkg-config
];

buildPhase = ''
make
'';

installFlags = [ "PREFIX=$(out)" ];

installPhase = ''
mkdir -p $out/bin
cp wideriver $out/bin/
'';

meta = with pkgs.lib; {
description = "A simple program using jansson";
license = licenses.mit;
maintainers = [ maintainers.yourname ];
platforms = platforms.unix;
};
};
});

devShell = nixpkgs.lib.genAttrs [ "aarch64-darwin" "x86_64-linux" ] (system:
let pkgs = import nixpkgs { inherit system; };
in pkgs.mkShell {
nativeBuildInputs = with pkgs; [
wayland-scanner
];
buildInputs = with pkgs; [
clang
clang-tools # Includes clangd
cppcheck
cmocka
include-what-you-use
valgrind
wayland
wayland-scanner
wlr-protocols
wlroots
pkg-config
];

shellHook = ''
echo "Development environment loaded."
'';
});

defaultPackage = {
aarch64-darwin = self.packages.aarch64-darwin.wideriver;
x86_64-linux = self.packages.x86_64-linux.wideriver;
};

defaultApp = {
forAllSystems = nixpkgs.lib.mapAttrs' (system: pkg: {
inherit system;
defaultApp = {
type = "app";
program = "${pkg.wideriver}/bin/wideriver";
};
}) self.packages;
};
};
}
4 changes: 4 additions & 0 deletions inc/cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@

#define BORDER_COLOR_UNFOCUSED_DEFAULT "0x586e75"

#define LAYOUT_FORMAT_LEN 90

// never null
extern const struct Cfg * const cfg;

Expand All @@ -61,6 +63,7 @@ struct Cfg {
char border_color_focused[11];
char border_color_focused_monocle[11];
char border_color_unfocused[11];
char layout_format[LAYOUT_FORMAT_LEN];
};

// returns false if not valid
Expand All @@ -77,6 +80,7 @@ bool cfg_set_inner_gaps(const char *s);
bool cfg_set_outer_gaps(const char *s);
bool cfg_set_border_width(const char *s);
bool cfg_set_border_width_monocle(const char *s);
bool cfg_set_layout_format(const char *s);

// returns false if not 0xRRGGBB
bool cfg_set_border_color_focused(const char *s);
Expand Down
8 changes: 8 additions & 0 deletions inc/enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ enum LogThreshold {
LOG_THRESHOLD_DEFAULT = INFO,
};

enum LayoutFormatElem {
LAYOUT = 'l',
COUNT = 'c',
RATIO = 'r',
alex-courtis marked this conversation as resolved.
Show resolved Hide resolved
};

#define DEFAULT_LAYOUT_FORMAT "{l}"

const char *layout_name(const enum Layout layout);
enum Layout layout_val(const char *name);

Expand Down
8 changes: 7 additions & 1 deletion inc/layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct Box {
uint32_t height;
};

// return a river layout name, caller frees
// return a river layout name
const char *layout_description(const struct Demand *demand, const struct Tag *tag);

// populate views with Box for river layout push dimensions, caller frees
Expand All @@ -30,5 +30,11 @@ struct SList *layout(const struct Demand *demand, const struct Tag *tag);
// push Box views
void push(const struct SList *views, struct river_layout_v3 *river_layout_v3, const uint32_t serial);

// layout image
const char *layout_image(const struct Demand* const demand, const struct Tag* const tag);

// fully rendered layout
const char *description_info(const struct Demand* const demand, const struct Tag* const tag);

#endif // LAYOUT_H

1 change: 1 addition & 0 deletions result
9 changes: 9 additions & 0 deletions src/args.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ static struct option cli_long_options[] = {
{ "help-defaults", no_argument, 0, 0, }, // 18
{ "log-threshold", required_argument, 0, 0, }, // 19
{ "version", no_argument, 0, 0, }, // 20
{ "layout-format", required_argument, 0, 0, }, // 21
{ 0, 0, 0, 0, }
};

Expand Down Expand Up @@ -179,6 +180,13 @@ void args_cli(int argc, char **argv) {
fprintf(stdout, "wideriver version %s\n", VERSION);
exit(EXIT_SUCCESS);
return;
case 21:
if (!cfg_set_layout_format(optarg)) {
log_error("invalid --layout-format '%s'\n", optarg);
usage(EXIT_FAILURE);
return;
}
break;
default:
fprintf(stderr, "\n");
usage(EXIT_FAILURE);
Expand All @@ -202,6 +210,7 @@ void args_cli(int argc, char **argv) {
log_info("--border-color-focused %s", cfg->border_color_focused);
log_info("--border-color-focused-monocle %s", cfg->border_color_focused_monocle);
log_info("--border-color-unfocused %s", cfg->border_color_unfocused);
log_info("--layout-format %s", cfg->layout_format);
log_info("--log-threshold %s", log_threshold_name(log_get_threshold()));
}

Expand Down
33 changes: 33 additions & 0 deletions src/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct Cfg c = {
.border_color_focused = BORDER_COLOR_FOCUSED_DEFAULT,
.border_color_focused_monocle = BORDER_COLOR_FOCUSED_MONOCLE_DEFAULT,
.border_color_unfocused = BORDER_COLOR_UNFOCUSED_DEFAULT,
.layout_format = DEFAULT_LAYOUT_FORMAT,
};

const struct Cfg * const cfg = &c;
Expand Down Expand Up @@ -190,6 +191,38 @@ bool cfg_set_border_width_monocle(const char *s) {
}
}

bool cfg_set_layout_format(const char *s) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand the failure cases of this function; I might be missing the point, but could it just be "garbage in, garbage out"?

Can you please add tests to tst-args_cli.c to cover these cases?

if (strlen(s) > LAYOUT_FORMAT_LEN)
return false;

int escaped = 0;
bool in_brackets = false;

for (int i = 0; s[i] != '\0'; i++) {
if (s[i] == '{' && escaped == 0)
in_brackets = true;
else if (s[i] == '}' && escaped == 0 && in_brackets) {
if ((s[i-1] != LAYOUT &&
s[i-1] != COUNT &&
s[i-1] != RATIO) ||
s[i-2] != '{'
) {
return false;
}
in_brackets = false;
} else if (s[i] == '\\' && escaped == 0 && !in_brackets) {
escaped = 2;
}

escaped -= 1;
if (escaped < 0)
escaped = 0;
}

strcpy(c.layout_format, s);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need to be a strncpy - it will trip the linux package security scanners.

return true;
}

bool cfg_set_border_color_focused(const char *s) {
if (valid_colour(s)) {
snprintf(c.border_color_focused, 11, "%s", s);
Expand Down
1 change: 0 additions & 1 deletion src/cmd.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

Expand Down
3 changes: 1 addition & 2 deletions src/enum.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include <unistd.h>
#include <strings.h>

#include <stddef.h>
#include "enum.h"

struct NameVal {
Expand Down
89 changes: 88 additions & 1 deletion src/layout.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>

#include "river-layout-v3.h"
Expand All @@ -8,10 +9,11 @@
#include "log.h"
#include "slist.h"
#include "tag.h"
#include "cfg.h"

#include "layout.h"

const char *description_info(const struct Demand* const demand, const struct Tag* const tag) {
const char *layout_image(const struct Demand* const demand, const struct Tag* const tag) {
static char desc[20];

switch(tag->layout_cur) {
Expand Down Expand Up @@ -54,6 +56,91 @@ const char *description_info(const struct Demand* const demand, const struct Tag
return desc;
}

// nix run .#wideriver -- --layout left --ratio-master 0.5 --count-wide-left 0 --border-width 3 --border-color-focused 0xe0def4 --border-color-unfocused 0x6e6a86 --layout-format "{r}\n{l}\n{c}"
const char *description_info(const struct Demand* const demand, const struct Tag* const tag) {
double ratio = 0;
unsigned int count = 0;
const char *image = layout_image(demand, tag);
switch(tag->layout_cur) {
case LEFT:
case RIGHT:
case TOP:
case BOTTOM:
count = tag->count_master;
ratio = tag->ratio_master;
break;
case WIDE:
count = tag->count_wide_left;
ratio = tag->ratio_wide;
break;
case MONOCLE:
count = demand->view_count;
ratio = 1.0;
break;
}

static char desc[LAYOUT_FORMAT_LEN+5];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works, however it's likely to trip the linux package security scanners.

You're correctly using snprintfs and checking bounds, however the scanners are very strict and won't be able to follow the complex logic here.

First thoughts are that we could just a man 3 regexec, which is known to safely handle buffers and allocation.

Alternatively, we could use strstr or strtok to find the exact tokens instead of looping, as we don't really need a complex pattern.

int j = 0;
int escaped = 0;
bool in_brackets = false;
for (int i = 0; cfg->layout_format[i] != '\0'; i++) {
if (escaped > 0) {
switch (cfg->layout_format[i]) {
case 'n':
desc[j] = '\n';
break;
case 't':
desc[j] = '\t';
break;
case 'r':
desc[j] = '\r';
break;
case 'v':
desc[j] = '\v';
break;
case '{':
desc[j] = '{';
break;
case '}':
desc[j] = '}';
break;
default:
break;
}
j++;
} else if (cfg->layout_format[i] == '{')
in_brackets = true;
else if (cfg->layout_format[i] == '}' && in_brackets) {
switch (cfg->layout_format[i-1]) {
case RATIO:
j += snprintf(desc+j, sizeof(desc)-j, "%g", ratio);
break;
case COUNT:
j += snprintf(desc+j, sizeof(desc)-j, "%u", count);
break;
case LAYOUT:
j += snprintf(desc+j, sizeof(desc)-j, "%s", image);
break;
}
in_brackets = false;
} else if (cfg->layout_format[i] == '\\' && !in_brackets)
escaped = 2;
else if (!in_brackets) {
desc[j] = cfg->layout_format[i];
j++;
}

escaped -= 1;
if (escaped < 0)
escaped = 0;
}

// terminate the string
desc[j] = '\0';

return desc;
}

const char *description_debug(const struct Demand* const demand, const struct Tag* const tag) {
Copy link
Owner

@alex-courtis alex-courtis Dec 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can delete this now :)

description_info can then be moved into layout_description

static char desc[128];

Expand Down
Loading