summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2024-10-19 12:05:15 -0400
committerAndrew Opalach <andrew@akon.city> 2024-10-19 12:13:26 -0400
commit42e8c4d28b6fe9cc5e041f02e0c85b390d49a218 (patch)
tree59080eec3dd79d225bb31fb0f7e646cc22880d39
parent2bb807dd32e1c18a6f1e8f22c25141de3334de9f (diff)
downloadmauri-42e8c4d28b6fe9cc5e041f02e0c85b390d49a218.tar.gz
mauri-42e8c4d28b6fe9cc5e041f02e0c85b390d49a218.tar.bz2
mauri-42e8c4d28b6fe9cc5e041f02e0c85b390d49a218.zip
Attempt to make usable and packageable
Signed-off-by: Andrew Opalach <andrew@akon.city>
-rw-r--r--.gitignore16
-rw-r--r--README.md28
-rw-r--r--README.txt34
-rw-r--r--attic/sway_background_covered.diff (renamed from taro/attic/sway_background_covered.diff)12
-rw-r--r--attic/sway_testing_config (renamed from taro/attic/sway_test_config)0
-rw-r--r--flake.lock6
-rw-r--r--flake.nix33
-rw-r--r--meson.build30
-rw-r--r--meson_options.txt2
-rwxr-xr-xscripts/line_count.sh2
-rw-r--r--src/gl.cc22
-rw-r--r--src/gl.h4
-rw-r--r--src/mauri.cc2
-rw-r--r--src/objects/material.cc10
-rw-r--r--src/objects/model.cc2
-rw-r--r--src/objects/model.h2
-rw-r--r--src/objects/pass.cc22
-rw-r--r--src/objects/scene.cc2
-rw-r--r--src/texture.cc12
-rw-r--r--src/util.h1
-rw-r--r--subprojects/notcurses.wrap (renamed from taro/subprojects/notcurses.wrap)0
-rw-r--r--subprojects/packagefiles/notcurses/duration_and_ffmpeg_fix.diff (renamed from taro/subprojects/packagefiles/notcurses/duration_and_ffmpeg_fix.diff)0
-rw-r--r--subprojects/packagefiles/s3tc-dxt-decompression/dxt1_default_alpha.diff13
-rw-r--r--subprojects/s3tc-dxt-decompression.wrap2
-rw-r--r--taro/config.h (renamed from taro/src/config.h)74
-rw-r--r--taro/daemon.c (renamed from taro/src/daemon.c)157
-rw-r--r--taro/db.c (renamed from taro/src/db.c)15
-rw-r--r--taro/db.h (renamed from taro/src/db.h)0
-rw-r--r--taro/file_ext.c (renamed from taro/src/file_ext.c)2
-rw-r--r--taro/file_ext.h (renamed from taro/src/file_ext.h)2
-rw-r--r--taro/meson.build27
-rwxr-xr-xtaro/scripts/run_wallpaper.sh6
-rw-r--r--taro/subprojects/libakiyo.wrap4
-rw-r--r--taro/subprojects/libalabaster.wrap4
-rw-r--r--taro/subprojects/stela.wrap4
-rw-r--r--taro/ui.c (renamed from taro/src/ui.c)351
36 files changed, 495 insertions, 408 deletions
diff --git a/.gitignore b/.gitignore
index 83a6033..3f4dd15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ subprojects/glfw3.wrap
subprojects/glfw3/
subprojects/glm.wrap
subprojects/glm/
+subprojects/jansson.wrap
subprojects/janus/
subprojects/json/
subprojects/libakiyo
@@ -14,23 +15,10 @@ subprojects/libalabaster
subprojects/libalabaster/
subprojects/libev.wrap
subprojects/lz4/
+subprojects/notcurses/
subprojects/s3tc-dxt-decompression/
subprojects/stb/
subprojects/stela
subprojects/stela/
subprojects/wlr-protocols.wrap
-taro/subprojects/c89atomic.wrap
-taro/subprojects/jansson.wrap
-taro/subprojects/jansson/
-taro/subprojects/libakiyo
-taro/subprojects/libakiyo/
-taro/subprojects/libalabaster
-taro/subprojects/libalabaster/
-taro/subprojects/libcurl.wrap
-taro/subprojects/libcurl/
-taro/subprojects/libev.wrap
-taro/subprojects/notcurses/
-taro/subprojects/stela
-taro/subprojects/stela/
-taro/subprojects/wlr-protocols.wrap
workshop_wallpapers*/
diff --git a/README.md b/README.md
deleted file mode 100644
index c272921..0000000
--- a/README.md
+++ /dev/null
@@ -1,28 +0,0 @@
-## mauri: Wallpaper Engine Implementation (for Linux)
-
-This is quite incomplete, it's not meant to be used. Although, it _is_ usable in the simplest case.
-If you find a wallpaper that works well enough and have an X11 environment that supports `_NET_WM_WINDOW_TYPE_DESKTOP`,
-you can run it with `./mauri -p <path_to_scene.pkg> -w <width> -h <height> -b true` and it should be set as your background.
-If you have multiple monitors, you might need to adjust `context_x11:183` to position the window.
-
-Most of the work, especially in the wallpaper engine implementation, was done around late 2019-2020
-and was mostly a learning experience for me. I could have made much better use of tools like
-renderdoc in the beginning, which would have saved a lot of time. It's also why there's a bit of odd logic in the
-implementation code because I was banging rocks together guessing how things worked in wallpaper engine.
-
-I took one last stab at it for about a week in mid 2023 and fixed a bunch of issues and changed the code style.
-Even then, this final version still has many fundemental flaws (and bugs).
-
-Known Major Issues:
-- some gifs are incorrectly positioned
-- some objects are not scaled/positioned properly in the scene
-- some shaders fail to compile for various reasons
-
-Not Implemented:
-- mouse paralax
-- camera shake
-- particles
-- animations/puppet warp
-- javascript scripting
-- 3d models
-- and much more...
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..aebc4be
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,34 @@
+== mauri: Wallpaper Engine Implementation (for Linux)
+
+=== Building
+==== Dependencies
+* C++17 and C99 compiler
+* meson
+* lz4
+* glm
+* nlohmann_json
+* fftw3 `optional (audio)`
+* notcurses `optional (taro)`
+
+==== Compiling
+[source,sh]
+----
+meson setup build -Dwindow=(x11|wayland) -Daudio=(enabled|disabled) -Dtaro=(enabled|disabled)
+ninja -C build
+----
+
+=== Known Issues
+- Some gifs are incorrectly positioned.
+- Some objects are incorrectly scaled and/or positioned.
+- Some shaders fail to compile for various reasons.
+
+==== Not Implemented:
+- Particles
+- Mouse Paralax
+- Camera Shake
+- Animations/Puppet Warp
+- Javascript Scripting
+- 3d Models
+- And much more\...
+
+// vim: set syntax=asciidoc:
diff --git a/taro/attic/sway_background_covered.diff b/attic/sway_background_covered.diff
index 0dc9401..3ba8ef4 100644
--- a/taro/attic/sway_background_covered.diff
+++ b/attic/sway_background_covered.diff
@@ -209,7 +209,7 @@ index 44b941ca..9004c3cb 100644
return output;
}
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
-index f8709a4c..36ea5fc0 100644
+index f8709a4c..1234c1cd 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -88,8 +88,12 @@ struct sway_workspace *workspace_create(struct sway_output *output,
@@ -233,7 +233,7 @@ index f8709a4c..36ea5fc0 100644
list_free(workspace->current.floating);
list_free(workspace->current.tiling);
free(workspace);
-@@ -616,6 +621,77 @@ bool workspace_is_empty(struct sway_workspace *ws) {
+@@ -616,6 +621,75 @@ bool workspace_is_empty(struct sway_workspace *ws) {
return true;
}
@@ -254,10 +254,8 @@ index f8709a4c..36ea5fc0 100644
+ return false;
+}
+
-+static int sort_containers_x_cmp(const void *_a, const void *_b) {
-+ struct sway_container *a = *(void **)_a;
-+ struct sway_container *b = *(void **)_b;
-+ return a->current.x - b->current.x;
++static int containers_x_compare(const void *a, const void *b) {
++ return (*(struct sway_container **)a)->current.x - (*(struct sway_container **)b)->current.x;
+}
+
+#define TERMINAL_APP_ID "kitty"
@@ -284,7 +282,7 @@ index f8709a4c..36ea5fc0 100644
+ ws->sorted->length = 0;
+ add_con_and_or_children_to_list(ws->sorted, ws->tiling);
+ add_con_and_or_children_to_list(ws->sorted, ws->floating);
-+ list_stable_sort(ws->sorted, sort_containers_x_cmp);
++ list_stable_sort(ws->sorted, containers_x_compare);
+ ws->background_covered = ws->sorted->length > 0;
+ struct sway_container *con;
+ for (int i = 0; i < ws->sorted->length; ++i) {
diff --git a/taro/attic/sway_test_config b/attic/sway_testing_config
index 1223428..1223428 100644
--- a/taro/attic/sway_test_config
+++ b/attic/sway_testing_config
diff --git a/flake.lock b/flake.lock
index 72f8d50..cb5aefe 100644
--- a/flake.lock
+++ b/flake.lock
@@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1728241625,
- "narHash": "sha256-yumd4fBc/hi8a9QgA9IT8vlQuLZ2oqhkJXHPKxH/tRw=",
+ "lastModified": 1729070438,
+ "narHash": "sha256-KOTTUfPkugH52avUvXGxvWy8ibKKj4genodIYUED+Kc=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "c31898adf5a8ed202ce5bea9f347b1c6871f32d1",
+ "rev": "5785b6bb5eaae44e627d541023034e1601455827",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index 3555310..c50b66e 100644
--- a/flake.nix
+++ b/flake.nix
@@ -4,7 +4,7 @@
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
- flake-utils.lib.eachDefaultSystem
+ flake-utils.lib.eachSystem [ "x86_64-linux" "i686-linux" "aarch64-linux" ]
(system:
let
pkgs = import nixpkgs { inherit system; };
@@ -14,7 +14,30 @@
packages.default = stdenv.mkDerivation {
name = "mauri";
version = "0.13";
- src = self;
+ src = fetchgit {
+ url = "https://git.akon.city/mauri";
+ rev = "a14ff7afba7f9758fd1f951fcc5ce94977b52d5b";
+ postFetch = ''
+ export NIX_SSL_CERT_FILE=${cacert}/etc/ssl/certs/ca-bundle.crt
+
+ cd "$out"
+ ${lib.getExe meson} subprojects download
+
+ cd "$out/subprojects/libalabaster"
+ ${lib.getExe meson} subprojects download
+
+ cd "$out/subprojects/libakiyo"
+ ${lib.getExe meson} subprojects download
+
+ cd "$out/subprojects/stela"
+ ${lib.getExe meson} subprojects download
+
+ cd "$out"
+
+ find subprojects -type d -name .git -prune -execdir rm -r {} +
+ '';
+ sha256 = "sUwcHgJ9IGrarjV1DSxyD28wyRjsHabWfWZZd9f1I/s=";
+ };
nativeBuildInputs = [
git
gcc
@@ -60,6 +83,7 @@
clang-tools
perf-tools
valgrind
+ asciidoctor
];
buildInputs = packages.default.buildInputs ++ [
# sway build
@@ -74,6 +98,7 @@
gdk-pixbuf
xwayland
xorg.xcbutilwm
+ xorg.xrandr
# wlroots build
mesa
vulkan-headers
@@ -87,7 +112,7 @@
shellHook = ''
export NIX_SHELL="mauri"
unset SOURCE_DATE_EPOCH
- exec ${pkgs.zsh}/bin/zsh
+ exec ${pkgs.zsh}/bin/zsh -l
'';
};
@@ -117,7 +142,7 @@
shellHook = ''
export NIX_SHELL="mauri-mingw64"
unset SOURCE_DATE_EPOCH
- exec ${pkgs.zsh}/bin/zsh
+ exec ${pkgs.zsh}/bin/zsh -l
'';
};
});
diff --git a/meson.build b/meson.build
index 4a09381..458037c 100644
--- a/meson.build
+++ b/meson.build
@@ -8,15 +8,20 @@ is_debug = get_option('buildtype').startswith('debug')
is_windows = host_machine.system() == 'windows'
alabaster = subproject('libalabaster').get_variable('alabaster')
-akiyo = subproject('libakiyo', default_options: ['event-loop=disabled', 'json=disabled']).get_variable('akiyo')
-stela = subproject('stela',
- default_options: [
- 'api=opengl',
- is_windows ? 'window=glfw' : 'window=wayland',
- 'poll=inline',
- 'event-buffer=false',
- 'pause=false'
- ]).get_variable('stela')
+
+akiyo = subproject('libakiyo', default_options: [
+ get_option('taro').enabled() ? 'event-loop=enabled' : 'event-loop=disabled',
+ 'curl=disabled',
+ 'json=enabled'
+]).get_variable('akiyo')
+
+stela = subproject('stela', default_options: [
+ 'api=opengl',
+ is_windows ? 'window=glfw' : 'window='+get_option('window'),
+ 'poll=inline',
+ 'event-buffer=false',
+ 'pause=false'
+]).get_variable('stela')
janus = subproject('janus').get_variable('janus')
stb = subproject('stb').get_variable('stb')
@@ -68,5 +73,8 @@ if is_windows and meson.is_cross_build()
mauri_link_args += ['-static', '-static-libgcc', '-static-libstdc++', '-municode', '-mwindows']
endif
-executable('mauri', mauri_src, dependencies: mauri_deps,
- cpp_args: mauri_cpp_args, link_args: mauri_link_args, install: true)
+executable('mauri', mauri_src, dependencies: mauri_deps, cpp_args: mauri_cpp_args, link_args: mauri_link_args, install: true)
+
+if get_option('taro').enabled()
+ subdir('taro')
+endif
diff --git a/meson_options.txt b/meson_options.txt
index a6dd436..ea6cec6 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1 +1,3 @@
+option('window', type: 'combo', choices: ['wayland', 'x11'], value: 'wayland')
+option('taro', type: 'feature', value: 'enabled')
option('audio', type: 'feature', value: 'disabled')
diff --git a/scripts/line_count.sh b/scripts/line_count.sh
index 1598b1a..8de6ef8 100755
--- a/scripts/line_count.sh
+++ b/scripts/line_count.sh
@@ -1,2 +1,2 @@
#! /usr/bin/env sh
-find ./src ./taro/src -type f | xargs wc -l
+find ./src ./taro/src -type f -exec wc -l {} +
diff --git a/src/gl.cc b/src/gl.cc
index 6629ed6..96f00e9 100644
--- a/src/gl.cc
+++ b/src/gl.cc
@@ -350,22 +350,20 @@ RenderTexture::RenderTexture(bool no_interp, bool clamp, bool filtering, s32 mm_
glBindTexture(GL_TEXTURE_2D, 0);
}
-auto RenderTexture::upload(byte *data, s32 width, s32 height, s32 level, bool dxt) -> void
+auto RenderTexture::upload(const void *ptr, s32 width, s32 height, s32 level, s32 iformat) -> void
{
- if (asset_manager()->prepare_output && data && level == 0)
+ if (asset_manager()->prepare_output && ptr && level == 0)
{
- this->save_pixels(data, width, height);
+ this->save_pixels(ptr, width, height, iformat == GL_UNSIGNED_INT_8_8_8_8);
}
if (!context()->is_draw_enabled()) return;
this->bind(0);
- s32 iformat = (dxt) ? GL_UNSIGNED_INT_8_8_8_8 : GL_UNSIGNED_BYTE;
-
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, width, height, 0,
- format, iformat, data);
+ format, iformat, ptr);
}
auto RenderTexture::bind(s32 index) -> void
@@ -395,10 +393,18 @@ static auto pack_red(byte r) -> u32
return (255 << 24 | 0 << 16 | 0 << 8 | r);
}
-auto RenderTexture::save_pixels(byte *data, s32 width, s32 height) -> void
+auto RenderTexture::save_pixels(const void *ptr, s32 width, s32 height, bool dxt) -> void
{
this->pixels.resize(width * height);
- byte *dp = data;
+ if (dxt)
+ {
+ for (s32 i = 0; i < width * height; i++)
+ {
+ this->pixels[i] = aki_htonl(((u32 *)ptr)[i]);
+ }
+ return;
+ }
+ byte *dp = (byte *)ptr;
switch (format)
{
case GL_RGBA:
diff --git a/src/gl.h b/src/gl.h
index 600c58b..95d8b84 100644
--- a/src/gl.h
+++ b/src/gl.h
@@ -95,11 +95,11 @@ class RenderTexture
std::vector<u32> pixels;
- auto upload(byte *data, s32 width, s32 height, s32 level, bool dxt = false) -> void;
+ auto upload(const void *ptr, s32 width, s32 height, s32 level, s32 iformat = GL_UNSIGNED_BYTE) -> void;
auto bind(s32 index) -> void;
private:
- auto save_pixels(byte *data, s32 width, s32 height) -> void;
+ auto save_pixels(const void *ptr, s32 width, s32 height, bool dxt) -> void;
};
class RenderFramebuffer
diff --git a/src/mauri.cc b/src/mauri.cc
index 737af65..74e2fb1 100644
--- a/src/mauri.cc
+++ b/src/mauri.cc
@@ -68,7 +68,7 @@ auto wmain(s32 argc, wchar_t **argv) -> s32
return EXIT_FAILURE;
}
- if (!stl_global_init()) return EXIT_FAILURE;
+ if (!stl_global_init(false)) return EXIT_FAILURE;
if (args.found("package"))
{
diff --git a/src/objects/material.cc b/src/objects/material.cc
index 7c36d13..8b582ff 100644
--- a/src/objects/material.cc
+++ b/src/objects/material.cc
@@ -31,11 +31,6 @@ auto Material::load(Engine *engine, Object *object, MaterialType type, Pass *pas
{
switch (type)
{
- case MATERIAL_EFFECT:
- {
- pass0->load(engine, MATERIAL_PASS, pass);
- break;
- }
case MATERIAL_MODEL:
{
Pass model_pass;
@@ -59,6 +54,11 @@ auto Material::load(Engine *engine, Object *object, MaterialType type, Pass *pas
break;
}
+ case MATERIAL_EFFECT:
+ {
+ pass0->load(engine, MATERIAL_PASS, pass);
+ break;
+ }
}
}
}
diff --git a/src/objects/model.cc b/src/objects/model.cc
index f5ce9c4..1eb958d 100644
--- a/src/objects/model.cc
+++ b/src/objects/model.cc
@@ -16,6 +16,8 @@ auto Model::parse(Parser &pr, const std::string &path) -> Model *
pr.map_value<bool>(root, "fullscreen", &model->fullscreen, false);
pr.map_value<bool>(root, "passthrough", &model->passthrough, false);
+ pr.map_value<vec2>(root, "cropoffset", &model->cropoffset, vec2(0.f));
+
pr.map_value<f32>(root, "width", &model->width, 0.f);
pr.map_value<f32>(root, "height", &model->height, 0.f);
diff --git a/src/objects/model.h b/src/objects/model.h
index d000bd7..d34130b 100644
--- a/src/objects/model.h
+++ b/src/objects/model.h
@@ -16,6 +16,8 @@ class Model
bool fullscreen = false;
bool passthrough = false;
+ vec2 cropoffset;
+
f32 width;
f32 height;
diff --git a/src/objects/pass.cc b/src/objects/pass.cc
index a7cfc09..afe7c8a 100644
--- a/src/objects/pass.cc
+++ b/src/objects/pass.cc
@@ -1,4 +1,5 @@
#include "../gl.h"
+#include "../context.h"
#include "pass.h"
@@ -199,10 +200,6 @@ RenderPass::RenderPass(Engine *engine, Pass *pass)
if (this->model && i == 0 && this->textures[0])
{
- if (this->textures[0]->is_gif())
- {
- pass->combos.push_back(Combo("SPRITESHEET", 1));
- }
this->object->create_objects(engine, this->textures[0]);
objects_created = true;
}
@@ -222,7 +219,7 @@ RenderPass::RenderPass(Engine *engine, Pass *pass)
{
// Take value as reference because "uniform_override->value" points
// to the value stored in the parser. This allows changing that value
- // to have an instant effect.
+ // to have an immediate effect.
uniform->value = &uniform_override->value;
break;
}
@@ -276,9 +273,9 @@ RenderPass::RenderPass(Engine *engine, Pass *pass)
#ifdef _DEBUG_
debug("PASS (%s)", this->command == COPY ? "copy" : "draw");
- debug(" object: %s (passthrough: %d, fullscreen %d)", this->object->name.c_str(),
- this->object->passthrough, this->object->fullscreen);
- debug(" visible: %d", this->object->visible);
+ debug(" object: %s (passthrough: %s, fullscreen %s)", this->object->name.c_str(),
+ AL_BOOLSTR(this->object->passthrough), AL_BOOLSTR(this->object->fullscreen));
+ debug(" visible: %s", AL_BOOLSTR(this->object->visible));
debug(" shader: %s", this->shader->origin()->name.c_str());
debug(" target: %s", pass->target.c_str());
debug(" textures (%u):", this->shader->origin()->texture_count);
@@ -287,7 +284,7 @@ RenderPass::RenderPass(Engine *engine, Pass *pass)
switch (this->texture_types[i])
{
case STATIC:
- if (pass->textures[i].empty() && !this->shader->origin()->textures[i].empty())
+ if (!this->shader->origin()->textures[i].empty() && pass->textures[i] == this->shader->origin()->textures[i])
{
debug(" [%u] %s (DEFAULT)", i, this->shader->origin()->textures[i].c_str());
}
@@ -307,8 +304,8 @@ RenderPass::RenderPass(Engine *engine, Pass *pass)
debug(" %s %s %s", uniform_type_to_string(uniform->type).c_str(),
uniform->uname.c_str(), glm::to_string(*uniform->value).c_str());
}
- debug(" model: %d", this->model);
- debug(" combine: %d", this->combine);
+ debug(" model: %s", AL_BOOLSTR(this->model));
+ debug(" combine: %s", AL_BOOLSTR(this->combine));
#endif
}
@@ -343,8 +340,7 @@ auto RenderPass::draw(Engine *engine) -> void
Render::color_mask(1.f, 1.f, 1.f, this->combine ? 0.f : 1.f);
- engine->view.default_viewport(
- adjusted_target->buffer->width, adjusted_target->buffer->height);
+ engine->view.default_viewport(adjusted_target->buffer->width, adjusted_target->buffer->height);
this->render_object->draw();
diff --git a/src/objects/scene.cc b/src/objects/scene.cc
index 832cea6..21a2449 100644
--- a/src/objects/scene.cc
+++ b/src/objects/scene.cc
@@ -57,7 +57,6 @@ auto Scene::get_object_by_id(u32 id) -> Object *
auto Scene::load(Engine *engine) -> void
{
- /*
if (this->objects.size() > 0)
{
for (auto it = this->objects.begin(); it != this->objects.end();)
@@ -66,7 +65,6 @@ auto Scene::load(Engine *engine) -> void
else it++;
}
}
- */
for (Object *object : this->objects)
{
diff --git a/src/texture.cc b/src/texture.cc
index 8b7aa23..ea29bc0 100644
--- a/src/texture.cc
+++ b/src/texture.cc
@@ -108,25 +108,23 @@ Texture::Texture(Asset *asset)
{
case RGBA8888:
texture->format = GL_RGBA;
- texture->upload(buffer, mm_width, mm_height, i, false);
+ texture->upload(buffer, mm_width, mm_height, i);
break;
case DXT5:
{
- u32 *decompressed = new u32[decompressed_byte_count];
+ u32 *decompressed = new u32[(mm_width + 3) * (mm_height + 3)];
BlockDecompressImageDXT5(mm_width, mm_height, buffer, decompressed);
texture->format = GL_RGBA;
- assert(decompressed);
- texture->upload((byte *)decompressed, mm_width, mm_height, i, true);
+ texture->upload((byte *)decompressed, mm_width, mm_height, i, GL_UNSIGNED_INT_8_8_8_8);
delete[] decompressed;
break;
}
case DXT1:
{
- u32 *decompressed = new u32[decompressed_byte_count * 2];
+ u32 *decompressed = new u32[(mm_width + 3) * (mm_height + 3)];
BlockDecompressImageDXT1(mm_width, mm_height, buffer, decompressed);
texture->format = GL_RGBA;
- assert(decompressed);
- texture->upload((byte *)decompressed, mm_width, mm_height, i, true);
+ texture->upload((byte *)decompressed, mm_width, mm_height, i, GL_UNSIGNED_INT_8_8_8_8);
delete[] decompressed;
break;
}
diff --git a/src/util.h b/src/util.h
index 1cad09d..42c94a6 100644
--- a/src/util.h
+++ b/src/util.h
@@ -3,6 +3,7 @@
extern "C" {
#include <al/types.h>
+#include <aki/socket.h>
}
#include "log.h"
diff --git a/taro/subprojects/notcurses.wrap b/subprojects/notcurses.wrap
index 64f6731..64f6731 100644
--- a/taro/subprojects/notcurses.wrap
+++ b/subprojects/notcurses.wrap
diff --git a/taro/subprojects/packagefiles/notcurses/duration_and_ffmpeg_fix.diff b/subprojects/packagefiles/notcurses/duration_and_ffmpeg_fix.diff
index 71680f7..71680f7 100644
--- a/taro/subprojects/packagefiles/notcurses/duration_and_ffmpeg_fix.diff
+++ b/subprojects/packagefiles/notcurses/duration_and_ffmpeg_fix.diff
diff --git a/subprojects/packagefiles/s3tc-dxt-decompression/dxt1_default_alpha.diff b/subprojects/packagefiles/s3tc-dxt-decompression/dxt1_default_alpha.diff
new file mode 100644
index 0000000..8527f9b
--- /dev/null
+++ b/subprojects/packagefiles/s3tc-dxt-decompression/dxt1_default_alpha.diff
@@ -0,0 +1,13 @@
+diff --git a/s3tc.cpp b/s3tc.cpp
+index f2642fc..88ea870 100644
+--- a/s3tc.cpp
++++ b/s3tc.cpp
+@@ -83,7 +83,7 @@ void DecompressBlockDXT1(uint32_t x, uint32_t y, uint32_t width, const uint8_t *
+ finalColor = PackRGBA((r0+r1)/2, (g0+g1)/2, (b0+b1)/2, 255);
+ break;
+ case 3:
+- finalColor = PackRGBA(0, 0, 0, 255);
++ finalColor = PackRGBA(0, 0, 0, 0);
+ break;
+ }
+ }
diff --git a/subprojects/s3tc-dxt-decompression.wrap b/subprojects/s3tc-dxt-decompression.wrap
index 2a0c5d4..cc70c7c 100644
--- a/subprojects/s3tc-dxt-decompression.wrap
+++ b/subprojects/s3tc-dxt-decompression.wrap
@@ -3,4 +3,4 @@ url = https://github.com/Benjamin-Dobell/s3tc-dxt-decompression.git
revision = 17074c22c7857cfc4e843a07e99519a09c3a563f
depth = 1
patch_directory = s3tc-dxt-decompression
-diff_files = s3tc-dxt-decompression/explicit_type_sizes.diff, s3tc-dxt-decompression/compiler_warnings.diff
+diff_files = s3tc-dxt-decompression/explicit_type_sizes.diff, s3tc-dxt-decompression/compiler_warnings.diff, s3tc-dxt-decompression/dxt1_default_alpha.diff
diff --git a/taro/src/config.h b/taro/config.h
index ddf3430..1a1f10d 100644
--- a/taro/src/config.h
+++ b/taro/config.h
@@ -1,6 +1,7 @@
#pragma once
#include <al/str.h>
+#include <al/log.h>
#include "file_ext.h"
@@ -19,37 +20,15 @@ static void close_config(struct config *conf)
al_str_free(&conf->wallpaper_dir);
}
-static bool open_config(struct config *conf)
+static bool parse_config_json(struct config *conf, char *envhome, json_t *root)
{
- conf->config_dir = al_str_zero();
- conf->wallpaper_dir = al_str_zero();
-
- char *envhome = getenv("HOME");
- if (!envhome) return false;
- al_str_from(&conf->config_dir, envhome);
- al_str_cat(&conf->config_dir, al_str_c(CONFIG_PATH));
- if (!aki_dir_exists(&conf->config_dir)) {
- if (!aki_dir_create(&conf->config_dir)) {
- close_config(conf);
- return false;
- }
- }
-
- str config_path;
- al_str_clone(&config_path, &conf->config_dir);
- al_str_cat(&config_path, al_str_c("/config.json"));
- json_t *root = aki_file_open_as_json(&config_path);
- al_str_free(&config_path);
- if (!root) {
- close_config(conf);
- return false;
- }
+ bool valid = true;
json_t *wallpaper_dir = json_object_get(root, "wallpaper_directory");
- if (!wallpaper_dir) {
- json_decref(root);
- close_config(conf);
- return false;
+ if (!wallpaper_dir || !json_is_string(wallpaper_dir) || al_strlen(json_string_value(wallpaper_dir)) == 0) {
+ al_log_error("taro", "'wallpaper_directory' not set or invalid");
+ valid = false;
+ goto out;
}
const char *dir_str = json_string_value(wallpaper_dir);
@@ -61,9 +40,48 @@ static bool open_config(struct config *conf)
al_str_from(&conf->wallpaper_dir, dir_str);
}
+out:
json_decref(root);
+ return valid;
+}
+
+static bool open_config(struct config *conf, bool create)
+{
+ al_memset(conf, 0, sizeof(struct config));
+
+ char *envhome = getenv("HOME");
+ if (!envhome) goto err;
+
+ al_str_from(&conf->config_dir, envhome);
+ al_str_cat(&conf->config_dir, al_str_c(CONFIG_PATH));
+ if (!aki_dir_exists(&conf->config_dir)) {
+ if (!create || !aki_dir_create(&conf->config_dir)) {
+ goto err;
+ }
+ }
+
+ str config_path;
+ al_str_clone(&config_path, &conf->config_dir);
+ al_str_cat(&config_path, al_str_c("/config.json"));
+ if (!aki_file_exists(&config_path)) {
+ if (aki_file_create(&config_path)) {
+ json_t *blank = json_object();
+ json_object_set_new(blank, "wallpaper_directory", json_string_nocheck(""));
+ aki_dump_json_and_decref(&config_path, blank);
+ }
+ }
+
+ json_t *root = aki_file_open_as_json(&config_path);
+ al_str_free(&config_path);
+ if (!root) goto err;
+
+ if (!parse_config_json(conf, envhome, root)) goto err;
+
return true;
+err:
+ close_config(conf);
+ return false;
}
AL_UNUSED_FUNCTION_POP
diff --git a/taro/src/daemon.c b/taro/daemon.c
index 45eb599..d632e3d 100644
--- a/taro/src/daemon.c
+++ b/taro/daemon.c
@@ -5,6 +5,7 @@
#include <al/str.h>
#include <aki/common.h>
#include <aki/event_loop.h>
+#include <aki/signal.h>
#include <aki/fs_event.h>
#include <aki/socket.h>
#include <stl/window.h>
@@ -25,11 +26,12 @@ struct monitor {
struct daemon *dmon;
};
-#define IPC_HEADER_LENGTH 14
-#define IPC_MESSAGE_BUF_SIZE 64
+#define SWAY_IPC_HEADER_LENGTH 14
+#define SWAY_IPC_SUBSCRIBE 2
struct daemon {
struct aki_event_loop loop;
+ struct aki_signal quit_signal;
struct aki_poll context_poll;
array(struct monitor *) monitors;
struct aki_socket ipc_socket;
@@ -86,6 +88,16 @@ static bool send_signal_to_pid(pid_t pid, s32 signal)
return true;
}
+static bool signal_monitor(struct monitor *monitor, s32 signal)
+{
+ if (monitor->pid == -1) return false;
+ if (!send_signal_to_pid(monitor->pid, signal)) {
+ monitor->pid = -1;
+ return false;
+ }
+ return true;
+}
+
static pid_t exec_or_exit(char *args[])
{
pid_t pid = fork();
@@ -98,6 +110,7 @@ static pid_t exec_or_exit(char *args[])
// This should return the pid of init if the parent process has already exited.
pid_t ppid = getppid();
if (ppid != 1) send_signal_to_pid(ppid, SIGINT);
+ exit(EXIT_FAILURE);
}
}
return pid;
@@ -108,13 +121,11 @@ static void maybe_kill_wallpaper(struct monitor *monitor)
if (monitor->pid == -1) return;
if (monitor->paused) {
- if (!send_signal_to_pid(monitor->pid, SIGCONT)) {
- send_signal_to_pid(monitor->pid, SIGKILL);
- }
+ signal_monitor(monitor, SIGCONT);
monitor->paused = false;
}
- send_signal_to_pid(monitor->pid, SIGTERM);
+ signal_monitor(monitor, SIGTERM);
monitor->pid = -1;
}
@@ -149,19 +160,28 @@ static bool run_wallpaper(struct daemon *dmon, struct monitor *monitor)
return false;
}
+ if (is_package) {
+ al_str_cat(&wallpaper_path, al_str_c("/scene.pkg"));
+ }
+
al_log_info("tarod", "setting wallpaper %.*s on %s", AL_STR_PRINTF(&wallpaper_path), monitor->os->name);
char width[8], height[8];
- al_sprintf(width, "%d", monitor->os->width / monitor->os->scale);
- al_sprintf(height, "%d", monitor->os->height / monitor->os->scale);
+ al_snprintf(width, sizeof(width), "%d", monitor->os->width / monitor->os->scale);
+ al_snprintf(height, sizeof(height), "%d", monitor->os->height / monitor->os->scale);
char *c_str0 = al_str_to_c_str(&wallpaper_path);
al_str_free(&wallpaper_path);
- monitor->pid = exec_or_exit((char *[]){ "./run_wallpaper.sh",
- AL_BOOLSTR(is_package), c_str0, monitor->os->name, width, height, NULL });
+ if (is_package) {
+ monitor->pid = exec_or_exit((char *[]){
+ "mauri", "-p", c_str0, "-m", monitor->os->name, "-w", width, "-h", height, NULL});
+ } else {
+ monitor->pid = exec_or_exit((char *[]){
+ "mauri", "-d", c_str0, "-m", monitor->os->name, "-w", width, "-h", height, NULL});
+ }
al_free(c_str0);
- if (monitor->covered && send_signal_to_pid(monitor->pid, SIGSTOP)) {
+ if (monitor->covered && signal_monitor(monitor, SIGSTOP)) {
monitor->paused = true;
}
@@ -194,13 +214,13 @@ static void output_discovered_callback(void *userdata, struct stl_monitor *os_mo
}
}
- str config_dir;
- al_str_clone(&config_dir, &dmon->conf.config_dir);
- al_str_cat(&config_dir, al_str_c("/"));
- al_str_cat(&config_dir, al_str_cr(os_monitor->name));
+ str monitor_dir;
+ al_str_clone(&monitor_dir, &dmon->conf.config_dir);
+ al_str_cat(&monitor_dir, al_str_c("/"));
+ al_str_cat(&monitor_dir, al_str_cr(os_monitor->name));
- if (!aki_dir_exists(&config_dir)) {
- if (!aki_dir_create(&config_dir)) return;
+ if (!aki_dir_exists(&monitor_dir)) {
+ if (!aki_dir_create(&monitor_dir)) return;
}
monitor = al_alloc_object(struct monitor);
@@ -208,8 +228,8 @@ static void output_discovered_callback(void *userdata, struct stl_monitor *os_mo
monitor->dmon = dmon;
al_array_push(dmon->monitors, monitor);
- al_str_clone(&monitor->config_dir, &config_dir);
- al_str_free(&config_dir);
+ al_str_clone(&monitor->config_dir, &monitor_dir);
+ al_str_free(&monitor_dir);
al_str_clone(&monitor->selection_path, &monitor->config_dir);
al_str_cat(&monitor->selection_path, al_str_c("/selection"));
@@ -273,9 +293,9 @@ static void ipc_handle_response(struct daemon *dmon, u8 *buf, u32 size)
if (strcmp(monitor->os->name, json_string_value(output)) != 0) continue;
monitor->covered = covered;
if (monitor->pid == -1) goto done;
- if (covered && !monitor->paused && send_signal_to_pid(monitor->pid, SIGSTOP)) {
+ if (covered && !monitor->paused && signal_monitor(monitor, SIGSTOP)) {
monitor->paused = true;
- } else if (!covered && monitor->paused && send_signal_to_pid(monitor->pid, SIGCONT)) {
+ } else if (!covered && monitor->paused && signal_monitor(monitor, SIGCONT)) {
monitor->paused = false;
}
break;
@@ -289,7 +309,7 @@ done:
static void ensure_ipc_buf_size(struct daemon *dmon, ssize_t size)
{
if (dmon->ipc.alloc < size) {
- dmon->ipc.buf = realloc(dmon->ipc.buf, size);
+ dmon->ipc.buf = al_realloc(dmon->ipc.buf, size);
dmon->ipc.alloc = size;
}
}
@@ -316,20 +336,20 @@ static void ipc_poll_callback(void *userdata, s32 revents)
}
if (revents & AKI_POLL_READ) {
- if (dmon->ipc.index < IPC_HEADER_LENGTH) {
+ if (dmon->ipc.index < SWAY_IPC_HEADER_LENGTH) {
dmon->ipc.index += aki_socket_read(&dmon->ipc_socket, dmon->ipc.buf + dmon->ipc.index,
- IPC_HEADER_LENGTH - dmon->ipc.index);
+ SWAY_IPC_HEADER_LENGTH - dmon->ipc.index);
}
- if (dmon->ipc.index == IPC_HEADER_LENGTH && !dmon->ipc.size) {
- dmon->ipc.size = *((s32 *)&dmon->ipc.buf[6]) + IPC_HEADER_LENGTH;
+ if (dmon->ipc.index == SWAY_IPC_HEADER_LENGTH && !dmon->ipc.size) {
+ dmon->ipc.size = *((s32 *)&dmon->ipc.buf[6]) + SWAY_IPC_HEADER_LENGTH;
ensure_ipc_buf_size(dmon, dmon->ipc.size);
}
if (dmon->ipc.size) {
dmon->ipc.index += aki_socket_read(&dmon->ipc_socket, dmon->ipc.buf + dmon->ipc.index,
dmon->ipc.size - dmon->ipc.index);
if (dmon->ipc.index == dmon->ipc.size) {
- ipc_handle_response(dmon, dmon->ipc.buf + IPC_HEADER_LENGTH,
- dmon->ipc.size - IPC_HEADER_LENGTH);
+ ipc_handle_response(dmon, dmon->ipc.buf + SWAY_IPC_HEADER_LENGTH,
+ dmon->ipc.size - SWAY_IPC_HEADER_LENGTH);
dmon->ipc.size = 0;
dmon->ipc.index = 0;
}
@@ -344,39 +364,56 @@ static void context_poll_callback(void *userdata, s32 revents)
stl_global_process_events();
}
+static void quit_signal_callback(void *userdata)
+{
+ struct daemon *dmon = (struct daemon *)userdata;
+ aki_event_loop_break_one(&dmon->loop);
+}
+
+static struct daemon dmon = { 0 };
// https://stackoverflow.com/a/59071370
-static void handle_sigchld(s32 sig)
+static void sigchld_handler(s32 signum)
{
- (void)sig;
+ (void)signum;
s32 saved_errno = errno;
while (waitpid((pid_t)(-1), 0, WNOHANG) > 0) {}
errno = saved_errno;
}
-#define SWAY_IPC_SUBSCRIBE 2
+static void sigint_handler(s32 signum)
+{
+ (void)signum;
+ aki_signal_send(&dmon.quit_signal);
+}
-static struct daemon dmon = { 0 };
+// TODO:
+// - daemon quit
+// - systemd? and related testing
s32 main(void)
{
- if (!aki_common_init()) return EXIT_FAILURE;
+ if (!aki_common_init() || !open_config(&dmon.conf, true)) return EXIT_FAILURE;
- signal(SIGCHLD, handle_sigchld);
+ signal(SIGINT, sigint_handler);
+ signal(SIGCHLD, sigchld_handler);
s32 ret = EXIT_FAILURE;
- if (!open_config(&dmon.conf)) goto out;
-
aki_event_loop_init(&dmon.loop);
- al_array_init(dmon.monitors);
+ aki_signal_init(&dmon.quit_signal, quit_signal_callback, &dmon);
+ aki_signal_start(&dmon.quit_signal, &dmon.loop);
+ al_array_init(dmon.monitors);
stl_set_output_discovered_callback(output_discovered_callback, &dmon);
- if (!stl_global_init()) return EXIT_FAILURE;
- aki_poll_init(&dmon.context_poll, context_poll_callback, &dmon);
- aki_poll_set(&dmon.context_poll, stl_global_get_poll_fd(), AKI_POLL_READ);
- aki_poll_start(&dmon.context_poll, &dmon.loop);
+ if (!stl_global_init(true)) goto out;
+ s32 poll_fd = stl_global_get_poll_fd();
+ if (poll_fd != -1) {
+ aki_poll_init(&dmon.context_poll, context_poll_callback, &dmon);
+ aki_poll_set(&dmon.context_poll, poll_fd, AKI_POLL_READ);
+ aki_poll_start(&dmon.context_poll, &dmon.loop);
+ }
str monitors;
al_str_from(&monitors, "");
@@ -389,28 +426,35 @@ s32 main(void)
str monitors_path;
al_str_clone(&monitors_path, &dmon.conf.config_dir);
al_str_cat(&monitors_path, al_str_c("/monitors"));
- if (!aki_file_exists(&monitors_path)) {
- aki_file_create(&monitors_path);
+ bool monitors_exists = aki_file_exists(&monitors_path) || aki_file_create(&monitors_path);
+ if (monitors_exists) {
+ aki_file_open_and_replace(&monitors_path, &monitors, false);
}
- aki_file_open_and_replace(&monitors_path, &monitors, false);
+ al_str_free(&monitors_path);
+ al_str_free(&monitors);
+ if (!monitors_exists) goto out;
dmon.ipc.buf = NULL;
dmon.ipc.size = 0;
dmon.ipc.index = 0;
dmon.ipc.alloc = 0;
- ensure_ipc_buf_size(&dmon, IPC_HEADER_LENGTH);
+ ensure_ipc_buf_size(&dmon, SWAY_IPC_HEADER_LENGTH);
- json_t *payload = json_array();
- json_array_append(payload, json_string("background_covered"));
- dmon.out.buf = al_malloc(IPC_MESSAGE_BUF_SIZE);
- al_memcpy(dmon.out.buf, "i3-ipc", strlen("i3-ipc"));
+ size_t bufsize = SWAY_IPC_HEADER_LENGTH + 64;
+ dmon.out.buf = al_malloc(bufsize);
+ al_memcpy(dmon.out.buf, "i3-ipc", al_strlen("i3-ipc"));
s32 type = SWAY_IPC_SUBSCRIBE;
al_memcpy(&dmon.out.buf[10], &type, sizeof(s32));
- s32 len = json_dumpb(payload, (char *)&dmon.out.buf[14], IPC_MESSAGE_BUF_SIZE - IPC_HEADER_LENGTH, 0);
+
+ json_t *payload = json_array();
+ json_array_append_new(payload, json_string_nocheck("background_covered"));
+ s32 len = json_dumpb(payload, (char *)&dmon.out.buf[SWAY_IPC_HEADER_LENGTH],
+ bufsize - SWAY_IPC_HEADER_LENGTH, 0);
+ json_decref(payload);
al_memcpy(&dmon.out.buf[6], &len, sizeof(s32));
- dmon.out.size = IPC_HEADER_LENGTH + len;
+
+ dmon.out.size = SWAY_IPC_HEADER_LENGTH + len;
dmon.out.index = 0;
- json_decref(payload);
dmon.ipc_socket.type = AKI_SOCKET_UNIX;
aki_socket_init(&dmon.ipc_socket);
@@ -422,7 +466,7 @@ s32 main(void)
if (swaysock && aki_socket_connect(&dmon.ipc_socket, al_str_cr(swaysock), 0)) {
aki_poll_start(&dmon.ipc_poll, &dmon.loop);
} else {
- al_log_error("tarod", "failed to connect to sway ipc socket");
+ al_log_warn("tarod", "couldn't connect to sway ipc socket");
}
aki_event_loop_run(&dmon.loop);
@@ -431,15 +475,18 @@ s32 main(void)
close_monitor(monitor);
}
al_array_free(dmon.monitors);
+
al_free(dmon.ipc.buf);
+ aki_socket_close(&dmon.ipc_socket);
aki_event_loop_destroy(&dmon.loop);
- close_config(&dmon.conf);
-
ret = EXIT_SUCCESS;
out:
+ close_config(&dmon.conf);
+
+ stl_global_close();
aki_common_close();
return ret;
diff --git a/taro/src/db.c b/taro/db.c
index 9d2ffa2..5202df8 100644
--- a/taro/src/db.c
+++ b/taro/db.c
@@ -147,17 +147,14 @@ bool db_ensure_entry_loaded(struct db *db, struct entry *e)
return e->loaded;
}
-static s32 id_compare(void *a, void *b)
+static s32 wallpaper_id_compare(const void *a, const void *b)
{
+ // Non-integer ids will be at the end.
s64 aid = al_str_to_long(&((struct entry *)a)->id, 10);
s64 bid = al_str_to_long(&((struct entry *)b)->id, 10);
- if (aid > bid) {
- return 1;
- } else if (aid < bid) {
- return -1;
- } else {
- return 0;
- }
+ if (aid > bid) return 1;
+ else if (aid < bid) return -1;
+ return 0;
}
bool db_load_entries(struct db *db, str *path)
@@ -189,7 +186,7 @@ bool db_load_entries(struct db *db, str *path)
al_array_push(db->entries, e);
}
- al_array_sort(db->entries, struct entry, id_compare);
+ al_array_sort(db->entries, struct entry, wallpaper_id_compare);
return true;
}
diff --git a/taro/src/db.h b/taro/db.h
index 78f4c77..78f4c77 100644
--- a/taro/src/db.h
+++ b/taro/db.h
diff --git a/taro/src/file_ext.c b/taro/file_ext.c
index 48dffce..3091fa4 100644
--- a/taro/src/file_ext.c
+++ b/taro/file_ext.c
@@ -39,7 +39,7 @@ json_t *aki_file_open_as_json(str *path)
return root;
}
-bool aki_file_dump_and_decref_json(str *path, json_t *root)
+bool aki_dump_json_and_decref(str *path, json_t *root)
{
str s;
size_t size = json_dumpb(root, NULL, 0, JSON_INDENT(4));
diff --git a/taro/src/file_ext.h b/taro/file_ext.h
index ddaceba..9398eb3 100644
--- a/taro/src/file_ext.h
+++ b/taro/file_ext.h
@@ -4,4 +4,4 @@
bool aki_file_open_and_read_wholly(str *path, str *out, bool lock);
bool aki_file_open_and_replace(str *path, str *buf, bool lock);
json_t *aki_file_open_as_json(str *path);
-bool aki_file_dump_and_decref_json(str *path, json_t *root);
+bool aki_dump_json_and_decref(str *path, json_t *root);
diff --git a/taro/meson.build b/taro/meson.build
index 0291648..935678e 100644
--- a/taro/meson.build
+++ b/taro/meson.build
@@ -1,10 +1,3 @@
-project('taro', 'c', version: '0.01',
- default_options: ['warning_level=2', 'c_std=c99'])
-
-cmake = import('cmake')
-
-is_debug = get_option('buildtype').startswith('debug')
-
notcurses = dependency('notcurses', required: false, allow_fallback: false)
notcurses_core = dependency('notcurses-core', required: false, allow_fallback: false)
if not notcurses.found() or not notcurses_core.found()
@@ -19,27 +12,11 @@ if not notcurses.found() or not notcurses_core.found()
notcurses_core = notcurses_proj.dependency('notcurses-core')
endif
-akiyo = subproject('libakiyo',
- default_options: [
- 'curl=disabled',
- 'json=enabled',
- 'event-loop=enabled'
- ]).get_variable('akiyo')
-
-stela = subproject('stela',
- default_options: [
- 'api=null',
- 'window=wayland',
- 'poll=fd',
- 'event-buffer=false',
- 'pause=false'
- ]).get_variable('stela')
-
taro_deps = [akiyo, notcurses, notcurses_core]
-taro_src = ['src/ui.c', 'src/db.c', 'src/file_ext.c']
+taro_src = ['ui.c', 'db.c', 'file_ext.c']
tarod_deps = [akiyo, stela]
-tarod_src = ['src/daemon.c', 'src/file_ext.c']
+tarod_src = ['daemon.c', 'file_ext.c']
executable('taro', taro_src, dependencies: taro_deps, install: true)
executable('tarod', tarod_src, dependencies: tarod_deps, install: true)
diff --git a/taro/scripts/run_wallpaper.sh b/taro/scripts/run_wallpaper.sh
deleted file mode 100755
index a274889..0000000
--- a/taro/scripts/run_wallpaper.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#! /usr/bin/env sh
-if [ "$1" = "true" ]; then
- exec mauri -p $2/scene.pkg -m $3 -w $4 -h $5
-else
- exec mauri -d $2 -m $3 -w $4 -h $5
-fi
diff --git a/taro/subprojects/libakiyo.wrap b/taro/subprojects/libakiyo.wrap
deleted file mode 100644
index 2cd2caa..0000000
--- a/taro/subprojects/libakiyo.wrap
+++ /dev/null
@@ -1,4 +0,0 @@
-[wrap-git]
-url = https://git.akon.city/libakiyo
-revision = master
-depth = 1
diff --git a/taro/subprojects/libalabaster.wrap b/taro/subprojects/libalabaster.wrap
deleted file mode 100644
index c0358cf..0000000
--- a/taro/subprojects/libalabaster.wrap
+++ /dev/null
@@ -1,4 +0,0 @@
-[wrap-git]
-url = https://git.akon.city/libalabaster
-revision = master
-depth = 1
diff --git a/taro/subprojects/stela.wrap b/taro/subprojects/stela.wrap
deleted file mode 100644
index 7807a8c..0000000
--- a/taro/subprojects/stela.wrap
+++ /dev/null
@@ -1,4 +0,0 @@
-[wrap-git]
-url = https://git.akon.city/stela
-revision = master
-depth = 1
diff --git a/taro/src/ui.c b/taro/ui.c
index b2c700e..5bcaf1d 100644
--- a/taro/src/ui.c
+++ b/taro/ui.c
@@ -1,9 +1,11 @@
#include <notcurses/notcurses.h>
#include <notcurses/nckeys.h>
+#include <al/log.h>
+#include <al/lib.h>
+#include <al/random.h>
#include <aki/common.h>
#include <aki/event_loop.h>
#include <aki/timer.h>
-#include <al/log.h>
#include "db.h"
#include "file_ext.h"
@@ -13,36 +15,39 @@
#define TIMER_UPDATE_BASE 1.f
-#define TILE_WIDTH 18
-#define TILE_HEIGHT 10
-#define FLASH_DURATION 0.3f
+#define TEXT_UPDATE_RATE 0.4f
+#define FLASH_DURATION 0.4f
+
+#define UI_RESERVE_WIDTH 33
+#define UI_RESERVE_HEIGHT 2
-#define TEXT_WIDTH (TILE_WIDTH - 4)
-#define TEXT_UPDATE_RATE 0.3f;
+#define GRID_TILE_WIDTH 18 // img = 16
+#define GRID_TILE_HEIGHT 10 // img = 8
-#define INFO_RES_WIDTH 33
-#define INFO_RES_HEIGHT 2
+#define GRID_TEXT_WIDTH (GRID_TILE_WIDTH - 4)
#define INFO_X_OFFSET 2
#define INFO_Y_OFFSET 1
#define INFO_WIDTH 30
-// INFO_HEIGHT = term_rows + INFO_RES_HEIGHT
+// INFO_HEIGHT = term_rows + UI_RESERVE_HEIGHT
-#define INFO_TILE_WIDTH 24
-#define INFO_TILE_HEIGHT 12
+#define INFO_IMG_WIDTH 24
+#define INFO_IMG_HEIGHT 12
-#define INFO_TEXT_WIDTH (TEXT_WIDTH + 4)
+#define INFO_TEXT_WIDTH (GRID_TEXT_WIDTH + 6)
#define PROP_TEXT_WIDTH 16
-#define MAX_MONITOR_NAME_LEN 255
+#define MAX_MONITOR_NAME 255
struct scrolling_text {
wstr *s;
+ s32 y;
+ s32 x;
s32 width;
- s32 index, max;
- s32 x, y;
+ u32 index;
+ s32 skip;
};
struct image {
@@ -75,13 +80,14 @@ struct monitors {
struct grid {
struct ncplane *p;
- s32 tiles_x, tiles_y;
+ s32 tiles_x;
+ s32 tiles_y;
s32 min_index;
s32 max_index;
s32 selected_index;
s32 set_index;
f32 flash;
- s32 tiles_per_page;
+ u32 tiles_per_page;
array(struct tile) tiles;
};
@@ -114,7 +120,8 @@ struct ui {
struct aki_timer timer;
bool layed_out;
f32 text_update;
- u32 term_rows, term_cols;
+ u32 term_rows;
+ u32 term_cols;
u8 selected_menu;
struct ncplane *p, *mp, *gp, *ip;
struct monitors m;
@@ -200,79 +207,66 @@ static void write_selected_entry_to_config(struct ui *u)
// Interface
// ---------
-static void set_scrolling_text(struct scrolling_text *text, wstr *s, s32 text_width, s32 width, s32 x, s32 y)
+static bool wide_string_to_width(wstr *w, u32 index, s32 max_width, void (*func)(void *, wchar_t), void *userdata)
{
- text->index = 0;
- text->width = width;
- text->s = s;
- if (text_width > text->width) {
- text->max = (text_width - text->width);
- // If the character at text->index is wider than 1 cell,
- // that is the amount the text will scroll by. So, account
- // for that here.
- for (s32 i = 0; i < text->max; i++) {
- s32 wcl = al_wchar_width(al_wstr_at(s, i));
- if (wcl > 1) {
- text->max -= wcl - 1;
- }
+ u32 i = index;
+ s32 width = 0;
+ do {
+ wchar_t wc = al_wstr_at(w, i);
+ width += al_wchar_width(wc);
+ if (width >= max_width) {
+ break;
}
- text->max++;
- } else {
- text->max = -1;
- }
- text->x = x;
- text->y = y;
+ func(userdata, wc);
+ } while (++i < w->len);
+ return i == w->len;
}
-static void draw_scrolling_text(struct ncplane *p, struct scrolling_text *t, bool update)
+static void set_scrolling_text(struct scrolling_text *text, wstr *s, s32 y, s32 x, s32 width)
{
- ncplane_cursor_move_yx(p, t->y, t->x);
- if (t->max != -1) {
- s32 i = 0;
- s32 width = 0;
- while (width < t->width) {
- wchar_t wc = al_wstr_at(t->s, t->index + i);
- width += al_wchar_width(wc);
- if (width > t->width) {
- break;
- }
- ncplane_putwc(p, wc);
- i++;
- }
- if (update) {
- t->index = (t->index + 1) % t->max;
- }
- } else {
- ncplane_putwstr(p, &al_wstr_at(t->s, 0));
- }
+ text->s = s;
+ text->y = y;
+ text->x = x;
+ text->width = width;
+ text->index = 0;
+ text->skip = al_wchar_width(al_wstr_at(s, text->index));
}
-static void set_info_entry(struct ui *u, struct info *n)
+static void draw_func(void *userdata, wchar_t wc)
{
- n->selected_prop = 0;
- n->props.size = 0;
+ struct ncplane *p = (struct ncplane *)userdata;
+ ncplane_putwc(p, wc);
+}
- if (u->g.selected_index == -1 || u->g.selected_index >= (s32)u->db.entries.size) {
- n->e = NULL;
- return;
+static void draw_scrolling_text(struct ncplane *p, struct scrolling_text *text, bool update)
+{
+ ncplane_cursor_move_yx(p, text->y, text->x);
+ bool end = wide_string_to_width(text->s, text->index, text->width, draw_func, p);
+ if (update && !--text->skip) {
+ text->skip = al_wchar_width(al_wstr_at(text->s, text->index));
+ text->index = end ? 0 : text->index + 1;
}
+}
+static void set_info_entry(struct ui *u, struct info *n)
+{
n->e = &al_array_at(u->db.entries, u->g.selected_index);
-
n->blitted = false;
s32 width = al_wstr_width(&u->n.e->title);
s32 tx = 2 + (width < INFO_TEXT_WIDTH ? (INFO_TEXT_WIDTH - width) / 2 : 0);
- set_scrolling_text(&n->text, &u->n.e->title, width, INFO_TEXT_WIDTH, tx, INFO_TILE_HEIGHT + 1);
+ set_scrolling_text(&n->text, &u->n.e->title, INFO_IMG_HEIGHT + 1, tx, INFO_TEXT_WIDTH);
+ n->selected_prop = 0;
+ n->props.size = 0;
struct prop *p;
+ struct info_prop *ip;
al_array_foreach_ptr(u->n.e->props, i, p) {
- struct info_prop ip = { 0 };
- ip.p = p;
- width = al_wstr_width(&p->title);
- s32 ty = (INFO_TILE_HEIGHT + 3) + ((i % n->max_props) * 2);
- set_scrolling_text(&ip.text, &p->title, width, PROP_TEXT_WIDTH, 0, ty);
- al_array_push(n->props, ip);
+ al_array_push(n->props, (struct info_prop){ 0 });
+ ip = &al_array_last(n->props);
+ ip->p = p;
+ s32 ty = INFO_IMG_HEIGHT + 3 + ((i % n->max_props) * 2);
+ set_scrolling_text(&ip->text, &p->title, ty, 0, PROP_TEXT_WIDTH);
}
}
@@ -296,9 +290,9 @@ static bool init_grid(struct grid *g)
return true;
}
-static s32 monitor_cmp(void *va, void *vb)
+static s32 monitor_cmp(const void *va, const void *vb)
{
- return strncmp(*(char **)va, *(char **)vb, MAX_MONITOR_NAME_LEN);
+ return strncmp(*(char **)va, *(char **)vb, MAX_MONITOR_NAME);
}
static bool init_monitors(struct ui *u, struct monitors *m)
@@ -311,7 +305,7 @@ static bool init_monitors(struct ui *u, struct monitors *m)
bool ret = aki_file_open_and_read_wholly(&monitors_path, &monitors, false);
al_str_free(&monitors_path);
if (!ret) {
- al_log_error("taro", "failed to open monitor list, is the daemon configured?");
+ al_log_error("taro", "failed to open monitor list, has `tarod` run?");
return false;
}
str monitor_dir;
@@ -337,6 +331,8 @@ static bool init_monitors(struct ui *u, struct monitors *m)
}
if (u->db.entries.size > 0) {
u->g.selected_index = (u->g.set_index >= 0) ? u->g.set_index : 0;
+ } else {
+ u->g.selected_index = -1;
}
return true;
}
@@ -373,12 +369,10 @@ struct image *get_image_from_pool(struct image_pool *pool, str *path)
}
if (pool->images.size >= pool->max) {
- // al_array_remove_range()...
for (u32 i = 0; i < pool->chunk_size; i++) {
- struct image img;
- al_array_pop_at(pool->images, 0, img);
- ncvisual_destroy(img.v);
+ ncvisual_destroy(al_array_at(pool->images, i).v);
}
+ al_array_remove_range(pool->images, 0, pool->chunk_size);
}
char *c_str = al_str_to_c_str(path);
@@ -436,19 +430,17 @@ static void maybe_destroy_info(struct info *n)
}
}
-static bool layout_info(struct ui *u, struct info *n, struct ncplane *parent, s32 width, s32 height)
+static bool layout_info(struct ui *u, struct info *n, struct ncplane *parent, s32 height)
{
- (void)width;
-
maybe_destroy_info(n);
- n->max_props = (height - INFO_TILE_HEIGHT - 3) / 2;
+ n->max_props = (height - INFO_IMG_HEIGHT - 3) / 2;
if (!n->max_props) return false;
struct ncplane_options nopts = { 0 };
- nopts.cols = INFO_TILE_WIDTH;
- nopts.rows = INFO_TILE_HEIGHT;
+ nopts.cols = INFO_IMG_WIDTH;
+ nopts.rows = INFO_IMG_HEIGHT;
nopts.x = 0;
nopts.y = 1;
@@ -458,7 +450,9 @@ static bool layout_info(struct ui *u, struct info *n, struct ncplane *parent, s3
return false;
}
- set_info_entry(u, &u->n);
+ if (u->g.selected_index >= 0) {
+ set_info_entry(u, &u->n);
+ }
return true;
}
@@ -492,27 +486,35 @@ static void set_grid_tiles(struct ui *u, struct grid *g)
t->blitted = false;
ncplane_erase(t->p);
- if (g->max_index >= (s32)u->db.entries.size) {
+ while (g->max_index < (s32)u->db.entries.size) {
+ t->e = &al_array_at(u->db.entries, g->max_index);
+ if (db_ensure_entry_loaded(&u->db, t->e)) {
+ break;
+ }
+ }
+
+ al_assert(g->max_index <= (s32)u->db.entries.size);
+
+ if (g->max_index == (s32)u->db.entries.size) {
t->e = NULL;
t->text.s = NULL;
ncplane_erase(t->ip);
continue;
}
- t->e = &al_array_at(u->db.entries, g->max_index);
- if (!db_ensure_entry_loaded(&u->db, t->e)) {
- x--;
- continue;
- }
-
s32 width = al_wstr_width(&t->e->title);
- s32 tx = 2 + ((width < TEXT_WIDTH) ? (TEXT_WIDTH - width) / 2 : 0);
- set_scrolling_text(&t->text, &t->e->title, width, TEXT_WIDTH, tx, TILE_HEIGHT - 1);
+ s32 tx = 2 + (width < GRID_TEXT_WIDTH ? (GRID_TEXT_WIDTH - width) / 2 : 0);
+ set_scrolling_text(&t->text, &t->e->title, GRID_TILE_HEIGHT - 1, tx, GRID_TEXT_WIDTH);
g->max_index++;
}}
g->max_index--;
+
+ // This can happen in grid_next_page() and shuffle. Any other case where
+ // `selected_index` goes over `max_index` is undefined. Handling it this way
+ // saves us from a lot of pre-loaded.
+ if (g->selected_index > g->max_index) g->selected_index = g->max_index;
}
static bool layout_grid(struct ui *u, struct grid *g, struct ncplane *parent, s32 width, s32 height)
@@ -522,8 +524,8 @@ static bool layout_grid(struct ui *u, struct grid *g, struct ncplane *parent, s3
s32 inner_width = width;
s32 inner_height = height;
- g->tiles_x = (s32)(width / TILE_WIDTH);
- g->tiles_y = (s32)(height / TILE_HEIGHT);
+ g->tiles_x = width / GRID_TILE_WIDTH;
+ g->tiles_y = height / GRID_TILE_HEIGHT;
if (!g->tiles_x || !g->tiles_y) {
// Window is too small.
@@ -532,8 +534,8 @@ static bool layout_grid(struct ui *u, struct grid *g, struct ncplane *parent, s3
g->tiles_per_page = g->tiles_x * g->tiles_y;
- // Allow 4 pages of tiles in the pool, but never shrink.
- if (u->pool.chunk_size < (u32)g->tiles_per_page) {
+ // Reserve space for 4 pages, but never shrink.
+ if (u->pool.chunk_size < g->tiles_per_page) {
u->pool.chunk_size = g->tiles_per_page;
u->pool.max = u->pool.chunk_size * 4;
al_array_reserve(u->pool.images, u->pool.max);
@@ -551,8 +553,8 @@ static bool layout_grid(struct ui *u, struct grid *g, struct ncplane *parent, s3
nopts.cols = inner_width;
nopts.rows = inner_height;
- nopts.x = (width - (g->tiles_x * TILE_WIDTH)) / 2;
- nopts.y = (height - (g->tiles_y * TILE_HEIGHT)) / 2;
+ nopts.x = (width - (g->tiles_x * GRID_TILE_WIDTH)) / 2;
+ nopts.y = (height - (g->tiles_y * GRID_TILE_HEIGHT)) / 2;
g->p = ncplane_create(parent, &nopts);
if (!g->p) return false;
@@ -561,10 +563,10 @@ static bool layout_grid(struct ui *u, struct grid *g, struct ncplane *parent, s3
for (s32 x = 0; x < g->tiles_x; x++) {
struct tile t = { 0 };
- nopts.cols = TILE_WIDTH;
- nopts.rows = TILE_HEIGHT;
- nopts.x = x * TILE_WIDTH;
- nopts.y = y * TILE_HEIGHT;
+ nopts.cols = GRID_TILE_WIDTH;
+ nopts.rows = GRID_TILE_HEIGHT;
+ nopts.x = x * GRID_TILE_WIDTH;
+ nopts.y = y * GRID_TILE_HEIGHT;
t.p = ncplane_create(g->p, &nopts);
if (!t.p) {
@@ -572,8 +574,8 @@ static bool layout_grid(struct ui *u, struct grid *g, struct ncplane *parent, s3
return false;
}
- nopts.cols = TILE_WIDTH - 2;
- nopts.rows = TILE_HEIGHT - 2;
+ nopts.cols = GRID_TILE_WIDTH - 2;
+ nopts.rows = GRID_TILE_HEIGHT - 2;
nopts.x = 1;
nopts.y = 1;
@@ -586,7 +588,9 @@ static bool layout_grid(struct ui *u, struct grid *g, struct ncplane *parent, s3
al_array_push(g->tiles, t);
}}
- set_grid_tiles(u, g);
+ if (g->selected_index >= 0) {
+ set_grid_tiles(u, g);
+ }
return true;
}
@@ -597,14 +601,17 @@ static void maybe_destroy_ui(struct ui *u)
ncplane_destroy(u->ip);
u->ip = NULL;
}
+
if (u->gp) {
ncplane_destroy(u->gp);
u->gp = NULL;
}
+
if (u->mp) {
ncplane_destroy(u->mp);
u->mp = NULL;
}
+
if (u->p) {
ncplane_destroy(u->p);
u->p = NULL;
@@ -615,10 +622,10 @@ bool layout_ui(struct ui *u)
{
bool even = u->term_cols % 2 == 0;
- u32 rwidth = (even) ? INFO_RES_WIDTH + 1 : INFO_RES_WIDTH;
- u32 rheight = (even) ? INFO_RES_HEIGHT + 1 : INFO_RES_HEIGHT;
+ u32 rwidth = (even) ? UI_RESERVE_WIDTH + 1 : UI_RESERVE_WIDTH;
+ u32 rheight = (even) ? UI_RESERVE_HEIGHT + 1 : UI_RESERVE_HEIGHT;
- if (u->term_cols < TILE_WIDTH + rwidth || u->term_rows < TILE_HEIGHT + rheight) {
+ if (u->term_cols < GRID_TILE_WIDTH + rwidth || u->term_rows < GRID_TILE_HEIGHT + rheight) {
return false;
}
@@ -634,8 +641,8 @@ bool layout_ui(struct ui *u)
return false;
}
- s32 cols = u->term_cols - rwidth;
- s32 rows = u->term_rows - rheight;
+ s32 cols = (s32)u->term_cols - rwidth;
+ s32 rows = (s32)u->term_rows - rheight;
if (cols < 0 || rows < 0) {
maybe_destroy_ui(u);
@@ -669,7 +676,7 @@ bool layout_ui(struct ui *u)
return false;
}
- nopts.x = nopts.cols + ((even) ? INFO_X_OFFSET + 1 : INFO_X_OFFSET);
+ nopts.x = nopts.cols + (even ? INFO_X_OFFSET + 1 : INFO_X_OFFSET);
nopts.y = INFO_Y_OFFSET;
nopts.cols = INFO_WIDTH;
nopts.rows = u->term_rows - rheight;
@@ -680,7 +687,7 @@ bool layout_ui(struct ui *u)
return false;
}
- if (!layout_info(u, &u->n, u->ip, nopts.cols, nopts.rows)) {
+ if (!layout_info(u, &u->n, u->ip, nopts.rows)) {
maybe_destroy_ui(u);
return false;
}
@@ -704,15 +711,15 @@ void draw_monitors(struct ui *u, struct monitors *m)
ncplane_cursor_move_yx(u->mp, 0, x);
al_array_foreach(m->monitors, i, monitor) {
if (m->flash <= 0.f && u->selected_menu == MENU_MONITORS && i == (u32)m->selected_monitor) {
- ncplane_set_bg_rgb8(u->mp, 211, 184, 152);
- ncplane_set_fg_rgb8(u->mp, 13, 22, 45);
+ ncplane_set_bg_palindex(u->mp, 8);
+ ncplane_set_fg_palindex(u->mp, 0);
} else if (i == (u32)m->set_monitor) {
- ncplane_set_bg_rgb8(u->mp, 242, 233, 215);
- ncplane_set_fg_rgb8(u->mp, 13, 22, 45);
+ ncplane_set_bg_palindex(u->mp, 7);
+ ncplane_set_fg_palindex(u->mp, 0);
m->flash -= AL_MAX(TIMER_UPDATE_BASE * (u->delay / 1000000.f), 0.001f);
} else {
- ncplane_set_fg_rgb8(u->mp, 0xff, 0xff, 0xff);
- ncplane_set_bg_palindex(u->mp, 0);
+ ncplane_set_fg_default(u->mp);
+ ncplane_set_bg_default(u->mp);
}
ncplane_cursor_move_rel(u->mp, 0, 1);
ncplane_putstr(u->mp, monitor);
@@ -726,21 +733,25 @@ void draw_info(struct ui *u, struct info *n, bool update_text)
ncplane_erase(u->ip);
struct ncvisual_options vopts = { 0 };
- vopts.scaling = NCSCALE_SCALE;
+ vopts.scaling = NCSCALE_STRETCH;
vopts.blitter = PIXEL_BLIT ? NCBLIT_PIXEL : NCBLIT_2x1;
struct image *img = get_image_from_pool(&u->pool, &n->e->preview_path);
if (img && !n->blitted && !img->errored) {
ncplane_erase(n->ip);
img->errored = img->gif && ncvisual_decode_loop(img->v) < 0;
- u->delay = ncvisual_get_duration(img->v);
if (!img->errored) {
vopts.n = n->ip;
ncvisual_blit(u->nc, img->v, &vopts);
n->blitted = !img->gif;
+ u->delay = ncvisual_get_duration(img->v);
+ if (u->delay == 10000) {
+ // Default 100fps gifs to 10fps, seems like some weird wallpaper engine behavior.
+ u->delay = 100000;
+ }
}
}
- ncplane_set_fg_rgb8(u->ip, 0xff, 0xff, 0xff);
+ ncplane_set_fg_default(u->ip);
draw_scrolling_text(u->ip, &n->text, update_text);
u32 selected_index = n->selected_prop - (n->selected_prop % n->max_props);
@@ -753,9 +764,9 @@ void draw_info(struct ui *u, struct info *n, bool update_text)
}
ip = &al_array_at(n->props, index);
if (u->selected_menu == MENU_INFO && index == (u32)n->selected_prop) {
- ncplane_set_fg_rgb8(u->ip, 211, 184, 152);
+ ncplane_set_fg_palindex(u->ip, 8);
} else {
- ncplane_set_fg_rgb8(u->ip, 0xff, 0xff, 0xff);
+ ncplane_set_fg_default(u->ip);
}
draw_scrolling_text(u->ip, &ip->text, update_text);
switch (ip->p->type) {
@@ -765,31 +776,31 @@ void draw_info(struct ui *u, struct info *n, bool update_text)
break;
case PROP_TYPE_SLIDER: {
char c[16];
- sprintf(c, "%.2f", ((struct slider_value *)ip->p->value)->value);
+ al_snprintf(c, sizeof(c), "%.2f", ((struct slider_value *)ip->p->value)->value);
ncplane_putstr_yx(u->ip, ip->text.y, ip->text.width + 2, c);
break;
}
}
}
if (ip && i == n->max_props && i != n->props.size) {
- ncplane_putstr_yx(u->ip, ip->text.y + 1, (INFO_TILE_WIDTH - 1) / 2, "V");
+ ncplane_putstr_yx(u->ip, ip->text.y + 1, (INFO_IMG_WIDTH - 1) / 2, "V");
}
}
-static void set_highlighted_style(struct tile *t, s32 br, s32 bg, s32 bb, s32 fr, s32 fg, s32 fb)
+static void set_tile_highlight(struct tile *t, s32 bindex, s32 findex)
{
- ncplane_set_fg_rgb8(t->p, br, bg, bb);
ncplane_set_bg_alpha(t->p, NCALPHA_TRANSPARENT);
- u64 c = 0;
- ncchannels_set_bg_rgb8(&c, br, bg, bb);
- ncchannels_set_fg_rgb8(&c, br, bg, bb);
- c = ncchannels_reverse(c);
- ncplane_gradient(t->p, 1, 0, TILE_HEIGHT - 1, TILE_WIDTH, "", 0, c, c, c, c);
- for (s32 i = 0; i < TILE_WIDTH; i++) {
- ncplane_putwc_yx(t->p, 0, i, L'▂');
+ struct nccell ncl;
+ nccell_init(&ncl);
+ nccell_load(t->p, &ncl, " ");
+ nccell_set_bg_palindex(&ncl, bindex);
+ ncplane_polyfill_yx(t->p, 1, 0, &ncl);
+ ncplane_set_fg_palindex(t->p, bindex);
+ for (s32 i = 0; i < GRID_TILE_WIDTH; i++) {
+ ncplane_putwc_yx(t->p, 0, i, L'▃');
}
- ncplane_set_bg_rgb8(t->p, br, bg, bb);
- ncplane_set_fg_rgb8(t->p, fr, fg, fb);
+ ncplane_set_fg_palindex(t->p, findex);
+ ncplane_set_bg_palindex(t->p, bindex);
ncplane_set_bg_alpha(t->p, NCALPHA_OPAQUE);
ncplane_set_styles(t->p, NCSTYLE_BOLD);
}
@@ -799,15 +810,13 @@ void draw_grid_tiles(struct ui *u, struct grid *g, bool update_text)
if (!u->layed_out) return;
struct ncvisual_options vopts = { 0 };
- vopts.scaling = NCSCALE_SCALE;
+ vopts.scaling = NCSCALE_STRETCH;
vopts.blitter = PIXEL_BLIT ? NCBLIT_PIXEL : NCBLIT_2x1;
s32 index = (g->selected_index - (g->selected_index % g->tiles_per_page));
-
struct tile *t;
al_array_foreach_ptr(g->tiles, i, t) {
- if (!t->e) continue;
- if (t->e->has_preview) {
+ if (t->e && t->e->has_preview) {
struct image *img = get_image_from_pool(&u->pool, &t->e->preview_path);
if (img && !t->blitted && !img->errored) {
vopts.n = t->ip;
@@ -815,16 +824,17 @@ void draw_grid_tiles(struct ui *u, struct grid *g, bool update_text)
t->blitted = true;
}
}
- if (g->flash <= 0.f && u->selected_menu == MENU_GRID && index == g->selected_index) {
- set_highlighted_style(t, 211, 184, 152, 13, 22, 45);
- } else if (g->set_index >= 0 && index == g->set_index) {
- set_highlighted_style(t, 242, 233, 215, 13, 22, 45);
+ ncplane_erase(t->p);
+ if (index == g->selected_index && g->flash <= 0.f && u->selected_menu == MENU_GRID) {
+ set_tile_highlight(t, 8, 0);
+ } else if (index == g->set_index && g->set_index >= 0) {
+ set_tile_highlight(t, 7, 0);
g->flash -= AL_MAX(TIMER_UPDATE_BASE * (u->delay / 1000000.f), 0.001f);
} else {
- ncplane_erase(t->p);
- ncplane_set_fg_rgb8(t->p, 0xff, 0xff, 0xff);
- ncplane_set_bg_palindex(t->p, 0);
- ncplane_set_styles(t->p, 0);
+ ncplane_set_fg_default(t->p);
+ ncplane_set_bg_default(t->p);
+ ncplane_set_bg_alpha(t->p, NCALPHA_TRANSPARENT);
+ ncplane_set_styles(t->p, NCSTYLE_NONE);
}
if (t->text.s && t->text.s->len) {
draw_scrolling_text(t->p, &t->text, update_text);
@@ -946,6 +956,7 @@ static bool handle_input_info(struct ui *u, struct info *n, struct ncinput *inpu
static bool grid_next_page(struct ui *u, struct grid *g, s32 offset)
{
+ if (u->db.entries.size == 0) return false;
s32 max = (s32)u->db.entries.size - 1;
if (g->selected_index == max) {
return false;
@@ -959,7 +970,7 @@ static bool grid_next_page(struct ui *u, struct grid *g, s32 offset)
static bool grid_previous_page(struct grid *g, s32 offset)
{
- if (g->selected_index == 0) {
+ if (g->selected_index <= 0) {
return false;
}
g->selected_index -= g->tiles_per_page - offset;
@@ -1020,14 +1031,18 @@ static bool handle_input_grid(struct ui *u, struct grid *g, struct ncinput *inpu
should_redraw_grid = true;
break;
case 'b':
- should_update_grid = grid_previous_page(&u->g, 0);
- should_redraw_info = true;
- should_redraw_grid = true;
+ if (grid_previous_page(&u->g, 0)) {
+ should_update_grid = true;
+ should_redraw_info = true;
+ should_redraw_grid = true;
+ }
break;
case 'f':
- should_update_grid = grid_next_page(u, &u->g, 0);
- should_redraw_info = true;
- should_redraw_grid = true;
+ if (grid_next_page(u, &u->g, 0)) {
+ should_update_grid = true;
+ should_redraw_info = true;
+ should_redraw_grid = true;
+ }
break;
case 'r':
g->set_index = -1;
@@ -1035,6 +1050,14 @@ static bool handle_input_grid(struct ui *u, struct grid *g, struct ncinput *inpu
should_redraw_grid = true;
should_redraw_info = true;
break;
+ case 's': {
+ s32 max = (s32)u->db.entries.size - 1;
+ g->selected_index = al_rand() % max;
+ should_update_grid = true;
+ should_redraw_info = true;
+ should_redraw_grid = true;
+ break;
+ }
case NCKEY_RETURN:
case NCKEY_SPACE: {
if (g->selected_index >= 0) {
@@ -1152,15 +1175,16 @@ s32 main(void)
s32 ret = EXIT_FAILURE;
- if (!open_config(&u.conf)) goto out;
+ if (!open_config(&u.conf, false)) {
+ al_log_error("taro", "failed to open config, run `tarod` at least once to generate needed config");
+ goto out;
+ }
if (!db_load_entries(&u.db, &u.conf.wallpaper_dir)) {
- close_config(&u.conf);
goto out;
}
if (!init_ui(&u)) {
- close_config(&u.conf);
goto out;
}
@@ -1171,7 +1195,6 @@ s32 main(void)
if (!layout_ui(&u)) {
notcurses_stop(u.nc);
- close_config(&u.conf);
al_log_error("taro", "failed to layout ui, your terminal window is probably too small");
goto out;
}
@@ -1192,11 +1215,11 @@ s32 main(void)
notcurses_stop(u.nc);
- close_config(&u.conf);
-
ret = EXIT_SUCCESS;
out:
+ close_config(&u.conf);
+
aki_common_close();
return ret;