Skip to content

Commit dc2dbc8

Browse files
authored
Merge pull request #5066 from egmontkob/5020-ncurses-color-pairs
Ticket: #5020: Allocate fewer ncurses color pairs
2 parents 1796996 + 95f2560 commit dc2dbc8

8 files changed

Lines changed: 196 additions & 149 deletions

File tree

lib/tty/color-internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ void tty_color_try_alloc_lib_pair (tty_color_lib_pair_t *mc_color_pair);
5555

5656
int tty_maybe_map_color (int color);
5757

58+
void tty_colorize_area (int y, int x, int rows, int cols, int color);
59+
5860
/*** inline functions ****************************************************************************/
5961

6062
#endif

lib/tty/color-ncurses.c

Lines changed: 134 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -49,57 +49,78 @@
4949

5050
/*** file scope type declarations ****************************************************************/
5151

52+
typedef struct
53+
{
54+
int pair; // ncurses color pair index
55+
int attrs; // attributes
56+
} mc_tty_ncurses_color_pair_and_attrs_t;
57+
5258
/*** forward declarations (file scope functions) *************************************************/
5359

5460
/*** file scope variables ************************************************************************/
5561

56-
static GHashTable *mc_tty_color_color_pair_attrs = NULL;
62+
/*
63+
* Our bookkeeping of the ncurses color pair indices, indexed by the "{fg}.{bg}" string.
64+
*/
65+
static GHashTable *mc_tty_ncurses_color_pairs = NULL;
66+
67+
/*
68+
* Indexed by mc's color index, points to the mc_tty_ncurses_color_pair_and_attrs_t object
69+
* representing the ncurses color pair index and the attributes.
70+
*
71+
* mc's color index represents unique (fg, bg, attrs) tuples. Allocating an ncurses color pair
72+
* for each of them might be too wasteful and might cause us to run out of available color pairs
73+
* too soon (especially in 8-color terminals), if many combinations only differ in attrs.
74+
* So we allocate a new ncurses color pair only if the (fg, bg) tuple is newly seen.
75+
* See #5020 for details.
76+
*/
77+
static GArray *mc_tty_ncurses_color_pair_and_attrs = NULL;
78+
79+
static int mc_tty_ncurses_next_color_pair = 0;
80+
5781
static int overlay_colors = 0;
5882

5983
/* --------------------------------------------------------------------------------------------- */
6084
/*** file scope functions ************************************************************************/
6185
/* --------------------------------------------------------------------------------------------- */
6286

63-
static inline void
64-
mc_tty_color_attr_destroy_cb (gpointer data)
87+
static int
88+
get_ncurses_color_pair (int ifg, int ibg)
6589
{
66-
g_free (data);
67-
}
68-
69-
/* --------------------------------------------------------------------------------------------- */
90+
char *color_pair_str;
91+
int *ncurses_color_pair;
92+
int init_pair_ret;
7093

71-
static void
72-
mc_tty_color_save_attr (int color_pair, int color_attr)
73-
{
74-
int *attr, *key;
94+
color_pair_str = g_strdup_printf ("%d.%d", ifg, ibg);
7595

76-
attr = g_try_new0 (int, 1);
77-
if (attr == NULL)
78-
return;
96+
ncurses_color_pair =
97+
(int *) g_hash_table_lookup (mc_tty_ncurses_color_pairs, (gpointer) color_pair_str);
7998

80-
key = g_try_new (int, 1);
81-
if (key == NULL)
99+
if (ncurses_color_pair == NULL)
82100
{
83-
g_free (attr);
84-
return;
85-
}
86-
87-
*key = color_pair;
88-
*attr = color_attr;
89-
90-
g_hash_table_replace (mc_tty_color_color_pair_attrs, (gpointer) key, (gpointer) attr);
91-
}
101+
ncurses_color_pair = g_try_new0 (int, 1);
102+
*ncurses_color_pair = mc_tty_ncurses_next_color_pair;
103+
#if NCURSES_VERSION_PATCH >= 20170401 && defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) \
104+
&& defined(HAVE_NCURSES_WIDECHAR)
105+
init_pair_ret = init_extended_pair (*ncurses_color_pair, ifg, ibg);
106+
#else
107+
init_pair_ret = init_pair (*ncurses_color_pair, ifg, ibg);
108+
#endif
92109

93-
/* --------------------------------------------------------------------------------------------- */
110+
if (init_pair_ret == ERR)
111+
{
112+
g_free (ncurses_color_pair);
113+
g_free (color_pair_str);
114+
return 0;
115+
}
94116

95-
static int
96-
color_get_attr (int color_pair)
97-
{
98-
int *fnd = NULL;
117+
g_hash_table_insert (mc_tty_ncurses_color_pairs, color_pair_str, ncurses_color_pair);
118+
mc_tty_ncurses_next_color_pair++;
119+
}
120+
else
121+
g_free (color_pair_str);
99122

100-
if (mc_tty_color_color_pair_attrs != NULL)
101-
fnd = (int *) g_hash_table_lookup (mc_tty_color_color_pair_attrs, (gpointer) &color_pair);
102-
return (fnd != NULL) ? *fnd : 0;
123+
return *ncurses_color_pair;
103124
}
104125

105126
/* --------------------------------------------------------------------------------------------- */
@@ -109,6 +130,8 @@ color_get_attr (int color_pair)
109130
void
110131
tty_color_init_lib (gboolean disable, gboolean force)
111132
{
133+
int default_color_pair_id;
134+
112135
(void) force;
113136

114137
if (has_colors () && !disable)
@@ -122,17 +145,32 @@ tty_color_init_lib (gboolean disable, gboolean force)
122145
tty_use_truecolors (NULL);
123146
}
124147

125-
mc_tty_color_color_pair_attrs = g_hash_table_new_full (
126-
g_int_hash, g_int_equal, mc_tty_color_attr_destroy_cb, mc_tty_color_attr_destroy_cb);
148+
// our tracking of ncurses's color pairs
149+
mc_tty_ncurses_color_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
150+
151+
// ncurses color pair 0 always refers to the default colors; add it to our hash
152+
mc_tty_ncurses_next_color_pair = 0;
153+
default_color_pair_id = get_ncurses_color_pair (-1, -1);
154+
g_assert (default_color_pair_id == 0);
155+
(void) default_color_pair_id; // unused if g_assert is eliminated
156+
157+
// mapping from our index to ncurses's index and attributes
158+
mc_tty_ncurses_color_pair_and_attrs =
159+
g_array_new (FALSE, FALSE, sizeof (mc_tty_ncurses_color_pair_and_attrs_t));
127160
}
128161

129162
/* --------------------------------------------------------------------------------------------- */
130163

131164
void
132165
tty_color_deinit_lib (void)
133166
{
134-
g_hash_table_destroy (mc_tty_color_color_pair_attrs);
135-
mc_tty_color_color_pair_attrs = NULL;
167+
g_hash_table_destroy (mc_tty_ncurses_color_pairs);
168+
mc_tty_ncurses_color_pairs = NULL;
169+
170+
g_array_free (mc_tty_ncurses_color_pair_and_attrs, TRUE);
171+
mc_tty_ncurses_color_pair_and_attrs = NULL;
172+
173+
mc_tty_ncurses_next_color_pair = 0;
136174
}
137175

138176
/* --------------------------------------------------------------------------------------------- */
@@ -164,36 +202,39 @@ tty_color_try_alloc_lib_pair (tty_color_lib_pair_t *mc_color_pair)
164202

165203
// Shady trick: if we don't have the exact color, because it is overlaid by backwards
166204
// compatibility indexed values, just borrow one degree of red. The user won't notice :)
167-
if ((ifg & FLAG_TRUECOLOR) != 0)
205+
if (ifg >= 0 && (ifg & FLAG_TRUECOLOR) != 0)
168206
{
169207
ifg &= ~FLAG_TRUECOLOR;
170-
if (ifg != 0 && ifg <= overlay_colors)
208+
if (ifg <= overlay_colors)
171209
ifg += (1 << 16);
172210
}
173211

174-
if ((ibg & FLAG_TRUECOLOR) != 0)
212+
if (ibg >= 0 && (ibg & FLAG_TRUECOLOR) != 0)
175213
{
176214
ibg &= ~FLAG_TRUECOLOR;
177-
if (ibg != 0 && ibg <= overlay_colors)
215+
if (ibg <= overlay_colors)
178216
ibg += (1 << 16);
179217
}
180218

181-
#if NCURSES_VERSION_PATCH >= 20170401 && defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) \
182-
&& defined(HAVE_NCURSES_WIDECHAR)
183-
init_extended_pair (mc_color_pair->pair_index, ifg, ibg);
184-
#else
185-
init_pair (mc_color_pair->pair_index, ifg, ibg);
186-
#endif
187-
mc_tty_color_save_attr (mc_color_pair->pair_index, attr);
219+
const int ncurses_color_pair = get_ncurses_color_pair (ifg, ibg);
220+
const mc_tty_ncurses_color_pair_and_attrs_t pair_and_attrs = { .pair = ncurses_color_pair,
221+
.attrs = attr };
222+
223+
g_array_insert_val (mc_tty_ncurses_color_pair_and_attrs, mc_color_pair->pair_index,
224+
pair_and_attrs);
188225
}
189226

190227
/* --------------------------------------------------------------------------------------------- */
191228

192229
void
193230
tty_setcolor (int color)
194231
{
232+
mc_tty_ncurses_color_pair_and_attrs_t *pair_and_attrs;
233+
195234
color = tty_maybe_map_color (color);
196-
attr_set (color_get_attr (color), color, NULL);
235+
pair_and_attrs = &g_array_index (mc_tty_ncurses_color_pair_and_attrs,
236+
mc_tty_ncurses_color_pair_and_attrs_t, color);
237+
attr_set (pair_and_attrs->attrs, pair_and_attrs->pair, NULL);
197238
}
198239

199240
/* --------------------------------------------------------------------------------------------- */
@@ -264,3 +305,47 @@ tty_use_truecolors (GError **error)
264305
}
265306

266307
/* --------------------------------------------------------------------------------------------- */
308+
309+
void
310+
tty_colorize_area (int y, int x, int rows, int cols, int color)
311+
{
312+
#ifdef ENABLE_SHADOWS
313+
cchar_t *ctext;
314+
wchar_t wch[CCHARW_MAX + 1];
315+
attr_t attrs;
316+
short color_pair;
317+
318+
if (!use_colors || !tty_clip (&y, &x, &rows, &cols))
319+
return;
320+
321+
color = tty_maybe_map_color (color);
322+
color = g_array_index (mc_tty_ncurses_color_pair_and_attrs,
323+
mc_tty_ncurses_color_pair_and_attrs_t, color)
324+
.pair;
325+
326+
ctext = g_malloc (sizeof (cchar_t) * (cols + 1));
327+
328+
for (int row = 0; row < rows; row++)
329+
{
330+
mvin_wchnstr (y + row, x, ctext, cols);
331+
332+
for (int col = 0; col < cols; col++)
333+
{
334+
getcchar (&ctext[col], wch, &attrs, &color_pair, NULL);
335+
setcchar (&ctext[col], wch, attrs, color, NULL);
336+
}
337+
338+
mvadd_wchnstr (y + row, x, ctext, cols);
339+
}
340+
341+
g_free (ctext);
342+
#else
343+
(void) y;
344+
(void) x;
345+
(void) rows;
346+
(void) cols;
347+
(void) color;
348+
#endif
349+
}
350+
351+
/* --------------------------------------------------------------------------------------------- */

lib/tty/color-slang.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,15 @@ tty_use_truecolors (GError **error)
233233
}
234234

235235
/* --------------------------------------------------------------------------------------------- */
236+
237+
void
238+
tty_colorize_area (int y, int x, int rows, int cols, int color)
239+
{
240+
if (use_colors)
241+
{
242+
color = tty_maybe_map_color (color);
243+
SLsmg_set_color_in_region (color, y, x, rows, cols);
244+
}
245+
}
246+
247+
/* --------------------------------------------------------------------------------------------- */

lib/tty/tty-internal.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ char *mc_tty_normalize_from_utf8 (const char *str);
4242
void tty_init_xterm_support (gboolean is_xterm);
4343
int tty_lowlevel_getch (void);
4444

45-
void tty_colorize_area (int y, int x, int rows, int cols, int color);
46-
4745
/*** inline functions ****************************************************************************/
4846

4947
#endif

0 commit comments

Comments
 (0)