xF: make xC nick colors just work
Alpine 3.24 Success
Arch Linux AUR Success
OpenBSD 7.8 Success

Colour mapping still suffers, just not as heavily.
This commit is contained in:
2026-08-06 04:44:02 +02:00
parent ce848bff0f
commit 65a98dfd7c
5 changed files with 56 additions and 45 deletions
+2 -1
View File
@@ -37,7 +37,8 @@ image::xP.webp[align="center"]
xF
--
The hybrid terminal/X11 frontend for 'xC'. It has simplified word wrapping,
and X11 doesn't support text selection. This frontend is perfect for testing.
limited colour support, and X11 doesn't support text selection.
This frontend is perfect for testing.
xA, xT, xW, xM
--------------
+30
View File
@@ -31,6 +31,7 @@
#include "liberty/liberty.c"
#include <arpa/inet.h>
#include <math.h>
#include <netinet/tcp.h>
static void
@@ -108,6 +109,35 @@ tokenize_host_port (char *address, const char **port)
return address;
}
static int *
filter_color_cube_for_acceptable_nick_colors (size_t *len)
{
// This is a pure function and we don't use threads, static storage is fine
static int table[6 * 6 * 6];
size_t len_counter = 0;
for (int x = 0; x < (int) N_ELEMENTS (table); x++)
{
int r = x / 36;
int g = (x / 6) % 6;
int b = (x % 6);
// The first step is 95/255, the rest are 40/255,
// as an approximation we can double the first step
double linear_R = pow ((r + !!r) / 6., 2.2);
double linear_G = pow ((g + !!g) / 6., 2.2);
double linear_B = pow ((b + !!b) / 6., 2.2);
// Use the relative luminance of colours within the cube to filter
// colours that look okay-ish on terminals with both black and white
// backgrounds (use the test-nick-colors script to calibrate)
double Y = 0.2126 * linear_R + 0.7152 * linear_G + 0.0722 * linear_B;
if (Y >= .25 && Y <= .4)
table[len_counter++] = 16 + x;
}
*len = len_counter;
return table;
}
// --- To be moved to liberty --------------------------------------------------
#define LIST_FOR_EACH_REVERSED(type, iter, tail) \
+1 -1
View File
@@ -9,7 +9,7 @@ export example=$(
#define N_ELEMENTS(a) (sizeof (a) / sizeof ((a)[0]))
$(perl -0777 -ne 'print $& if /^.*?\nfilter_color(?s:.*?)^}$/m' \
"$(dirname "$0")"/xC.c)
"$(dirname "$0")"/common.c)
void main () {
size_t len = 0;
-30
View File
@@ -56,7 +56,6 @@ enum
#include "xD-replies.c"
#include "xC-proto.c"
#include <math.h>
#include <langinfo.h>
#include <locale.h>
#include <pwd.h>
@@ -2137,35 +2136,6 @@ static struct ispect_field g_ctx_ispect[] =
{}
};
static int *
filter_color_cube_for_acceptable_nick_colors (size_t *len)
{
// This is a pure function and we don't use threads, static storage is fine
static int table[6 * 6 * 6];
size_t len_counter = 0;
for (int x = 0; x < (int) N_ELEMENTS (table); x++)
{
int r = x / 36;
int g = (x / 6) % 6;
int b = (x % 6);
// The first step is 95/255, the rest are 40/255,
// as an approximation we can double the first step
double linear_R = pow ((r + !!r) / 6., 2.2);
double linear_G = pow ((g + !!g) / 6., 2.2);
double linear_B = pow ((b + !!b) / 6., 2.2);
// Use the relative luminance of colours within the cube to filter
// colours that look okay-ish on terminals with both black and white
// backgrounds (use the test-nick-colors script to calibrate)
double Y = 0.2126 * linear_R + 0.7152 * linear_G + 0.0722 * linear_B;
if (Y >= .25 && Y <= .4)
table[len_counter++] = 16 + x;
}
*len = len_counter;
return table;
}
static bool
app_iconv_open (iconv_t *target, const char *to, const char *from)
{
+23 -13
View File
@@ -23,7 +23,6 @@
#include "xC-proto.c"
#include <locale.h>
#include <math.h>
#ifdef WITH_X11
#define LIBERTY_XUI_WANT_X11
@@ -340,7 +339,8 @@ enum app_attribute
ATTRIBUTE_COUNT,
};
static struct attrs g_attrs[ATTRIBUTE_COUNT] =
static size_t g_attrs_len = ATTRIBUTE_COUNT;
static struct attrs g_attrs[256] =
{
#define XX(name, fg, bg, attrs_) \
[ATTRIBUTE_ ## name] = { fg, bg, attrs_ },
@@ -350,6 +350,17 @@ static struct attrs g_attrs[ATTRIBUTE_COUNT] =
#undef ATTRIBUTE_TABLE
static void
app_init_line_item_colors (void)
{
size_t colors_len = 0;
int *colors = filter_color_cube_for_acceptable_nick_colors (&colors_len);
hard_assert (g_attrs_len + colors_len <= N_ELEMENTS (g_attrs));
for (size_t i = 0; i < colors_len; i++)
g_attrs[g_attrs_len++] = (struct attrs) { colors[i], -1, 0 };
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
enum { UNREAD_MARKER_HEIGHT = 1 };
@@ -2176,19 +2187,17 @@ app_line_item_color_rgb (int color, int *r, int *g, int *b)
static int
app_line_item_color (int16_t color)
{
// These are the closest 256-colour palette matches for the base 16,
// using the same RGB estimates as xC and XUI.
if (color < 0 || color >= 256)
return -1;
int r = 0, g = 0, b = 0;
app_line_item_color_rgb (color, &r, &g, &b);
int best = 0, best_distance = INT_MAX;
for (int i = 0; i < 16; i++)
for (size_t i = ATTRIBUTE_IRC_0; i < g_attrs_len; i++)
{
int rr = 0, gg = 0, bb = 0;
app_line_item_color_rgb (g_attrs[ATTRIBUTE_IRC_0 + i].fg,
&rr, &gg, &bb);
app_line_item_color_rgb (g_attrs[i].fg, &rr, &gg, &bb);
int distance =
(r - rr) * (r - rr) +
(g - gg) * (g - gg) +
@@ -2227,20 +2236,20 @@ app_line_item_attrs (chtype attrs, bool leaked,
bg = tmp;
}
// XUI attributes use a small, preallocated colour-pair table.
// Preserve its common 16-colour palette, approximating extended colours,
// and preferring the foreground when both colours are set.
// XUI attributes use a preallocated colour-pair table. Quantize colours
// to the IRC base palette plus xC's acceptable nickname colours,
// preferring the foreground when both colours are set.
fg = app_line_item_color (fg);
bg = app_line_item_color (bg);
if (fg >= 0 && bg < 0)
{
attrs &= ~A_COLOR;
attrs |= g_attrs[ATTRIBUTE_IRC_0 + fg].attrs & A_COLOR;
attrs |= g_attrs[fg].attrs & A_COLOR;
}
else if (bg >= 0 && fg < 0)
{
attrs &= ~A_COLOR;
attrs |= g_attrs[ATTRIBUTE_IRC_0 + bg].attrs & A_COLOR;
attrs |= g_attrs[bg].attrs & A_COLOR;
attrs ^= A_REVERSE;
}
else if (item->style & BUFFER_LINE_ITEM_INVERSE)
@@ -3851,9 +3860,10 @@ main (int argc, char *argv[])
xui_preinit ();
app_init_bindings ();
app_init_line_item_colors ();
g_log_message_real = app_log_handler;
xui_start (&g.poller, requested_gui, g_attrs, ATTRIBUTE_COUNT);
xui_start (&g.poller, requested_gui, g_attrs, g_attrs_len);
app_select_backend ();
xui_invalidate ();