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+
5781static 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)
109130void
110131tty_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
131164void
132165tty_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
192229void
193230tty_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+ /* --------------------------------------------------------------------------------------------- */
0 commit comments