diff options
-rw-r--r-- | src/interface-curses.cpp | 157 | ||||
-rw-r--r-- | src/interface-curses.h | 26 | ||||
-rw-r--r-- | src/parser.cpp | 19 |
3 files changed, 141 insertions, 61 deletions
diff --git a/src/interface-curses.cpp b/src/interface-curses.cpp index c388f93..c3a5b33 100644 --- a/src/interface-curses.cpp +++ b/src/interface-curses.cpp @@ -240,6 +240,21 @@ ViewCurses::initialize_impl(void) setup(); } +InterfaceCurses::InterfaceCurses() : stdout_orig(-1), stderr_orig(-1), + screen(NULL), + screen_tty(NULL), + info_window(NULL), + info_current(NULL), + msg_window(NULL), + cmdline_window(NULL), cmdline_pad(NULL), + cmdline_len(0), cmdline_rubout_len(0) +{ + for (guint i = 0; i < G_N_ELEMENTS(color_table); i++) + color_table[i] = -1; + for (guint i = 0; i < G_N_ELEMENTS(orig_color_table); i++) + orig_color_table[i].r = -1; +} + void InterfaceCurses::main_impl(int &argc, char **&argv) { @@ -261,8 +276,106 @@ InterfaceCurses::main_impl(int &argc, char **&argv) } void +InterfaceCurses::init_color_safe(guint color, guint32 rgb) +{ + short r, g, b; + +#ifdef PDCURSES_WIN32 + if (orig_color_table[color].r < 0) { + color_content((short)color, + &orig_color_table[color].r, + &orig_color_table[color].g, + &orig_color_table[color].b); + } +#endif + + rgb2curses(rgb, r, g, b); + ::init_color((short)color, r, g, b); +} + +#ifdef PDCURSES_WIN32 + +/* + * On PDCurses/win32, color_content() will actually return + * the real console color palette - or at least the default + * palette when the console started. + */ +void +InterfaceCurses::restore_colors(void) +{ + if (!can_change_color()) + return; + + for (guint i = 0; i < G_N_ELEMENTS(orig_color_table); i++) { + if (orig_color_table[i].r < 0) + continue; + + ::init_color((short)i, + orig_color_table[i].r, + orig_color_table[i].g, + orig_color_table[i].b); + } +} + +#elif defined(NCURSES_UNIX) + +/* + * FIXME: On UNIX/ncurses init_color_safe() __may__ change the + * terminal's palette permanently and there does not appear to be + * any portable way of restoring the original one. + * Curses has color_content(), but there is actually no terminal + * that allows querying the current palette and so color_content() + * will return bogus "default" values and only for the first 8 colors. + * It would do more damage to restore the palette returned by + * color_content() than it helps. + * xterm has the escape sequence "\e]104\x07" which restores + * the palette from Xdefaults but not all terminal emulators + * claiming to be "xterm" via $TERM support this escape sequence. + * lxterminal for instance will print gibberish instead. + * So we try to look whether $XTERM_VERSION is set. + * There are hardly any other terminal emulators that support palette + * resets. + * The only emulator I'm aware of which can be identified reliably + * by $TERM supporting a palette reset is the Linux console + * (see console_codes(4)). The escape sequence "\e]R" is already + * part of its terminfo description (orig_colors capability) + * which is apparently sent by endwin(), so the palette is + * already properly restored on endwin(). + * Welcome in Curses hell. + */ +void +InterfaceCurses::restore_colors(void) +{ + if (g_str_has_prefix(g_getenv("TERM") ? : "", "xterm") && + g_getenv("XTERM_VERSION")) { + /* + * Looks like a real xterm. $TERM alone is not + * sufficient to tell. + */ + fputs("\e]104\x07", screen_tty); + fflush(screen_tty); + } +} + +#else /* !PDCURSES_WIN32 && !NCURSES_UNIX */ + +void +InterfaceCurses::restore_colors(void) +{ + /* + * No way to restore the palette, or it's + * unnecessary (e.g. XCurses) + */ +} + +#endif + +void InterfaceCurses::init_color(guint color, guint32 rgb) { + if (color >= G_N_ELEMENTS(color_table)) + return; + #if defined(__PDCURSES__) && !defined(PDC_RGB) /* * PDCurses will usually number color codes differently @@ -272,20 +385,16 @@ InterfaceCurses::init_color(guint color, guint32 rgb) * Therefore we have to swap the bit order of the least * significant 3 bits here. */ - if (color < 16) - color = (color & ~0x5) | - ((color & 0x1) << 2) | ((color & 0x4) >> 2); + color = (color & ~0x5) | + ((color & 0x1) << 2) | ((color & 0x4) >> 2); #endif if (cmdline_window) { /* interactive mode */ - short r, g, b; - if (!can_change_color()) return; - rgb2curses(rgb, r, g, b); - ::init_color((short)color, r, g, b); + init_color_safe(color, rgb); } else { /* * batch mode: store colors, @@ -293,9 +402,6 @@ InterfaceCurses::init_color(guint color, guint32 rgb) * which is called by Scinterm when interactive * mode is initialized */ - if (color >= G_N_ELEMENTS(color_table)) - return; - color_table[color] = (gint32)rgb; } } @@ -442,40 +548,14 @@ InterfaceCurses::init_interactive(void) /* * Only now it's safe to redefine the 16 default colors. - * - * FIXME: On UNIX/ncurses this __may__ change the terminal's palette - * permanently and there does not appear to be any portable way of - * restoring the original one. - * Curses has color_content(), but there is actually no terminal - * that allows querying the current palette and so color_content() - * will return bogus "default" values and only for the first 8 colors. - * xterm has the escape sequence "\e]104\x04" which restores - * the palette from Xdefaults but not all terminal emulators - * claiming to be "xterm" via $TERM support this escape sequence. - * lxterminal for instance will print gibberish instead. - * There are hardly any other terminal emulators that support palette - * resets. - * The only emulator I'm aware of which can be identified reliably - * by $TERM supporting a palette reset is the linux console - * (see console_codes(4)). The escape sequence "\e]R" is already - * part of its terminfo description (orig_colors capability) - * which is apparently sent by endwin(), so the palette is - * already properly restored on endwin(). - * Welcome in Curses hell. */ if (can_change_color()) { for (guint i = 0; i < G_N_ELEMENTS(color_table); i++) { - short r, g, b; - - if (color_table[i] < 0) - /* no redefinition */ - continue; - /* * init_color() may still fail if COLORS < 16 */ - rgb2curses((guint32)color_table[i], r, g, b); - ::init_color((short)i, r, g, b); + if (color_table[i] >= 0) + init_color_safe(i, (guint32)color_table[i]); } } } @@ -499,6 +579,7 @@ InterfaceCurses::restore_batch(void) * (i.e. return to batch mode) */ endwin(); + restore_colors(); /* * Restore stdout and stderr, so output goes to diff --git a/src/interface-curses.h b/src/interface-curses.h index ca3ce04..b43069f 100644 --- a/src/interface-curses.h +++ b/src/interface-curses.h @@ -82,6 +82,16 @@ typedef class InterfaceCurses : public Interface<InterfaceCurses, ViewCurses> { */ gint32 color_table[16]; + /** + * Mapping of the first 16 curses color codes to their + * original values for restoring them on shutdown. + * Unfortunately, this may not be supported on all + * curses ports, so this array may be unused. + */ + struct { + short r, g, b; + } orig_color_table[G_N_ELEMENTS(color_table)]; + int stdout_orig, stderr_orig; SCREEN *screen; FILE *screen_tty; @@ -110,18 +120,7 @@ typedef class InterfaceCurses : public Interface<InterfaceCurses, ViewCurses> { } popup; public: - InterfaceCurses() : stdout_orig(-1), stderr_orig(-1), - screen(NULL), - screen_tty(NULL), - info_window(NULL), - info_current(NULL), - msg_window(NULL), - cmdline_window(NULL), cmdline_pad(NULL), - cmdline_len(0), cmdline_rubout_len(0) - { - for (guint i = 0; i < G_N_ELEMENTS(color_table); i++) - color_table[i] = -1; - } + InterfaceCurses(); ~InterfaceCurses(); /* implementation of Interface::main() */ @@ -163,6 +162,9 @@ public: void event_loop_impl(void); private: + void init_color_safe(guint color, guint32 rgb); + void restore_colors(void); + void init_screen(void); void init_interactive(void); void restore_batch(void); diff --git a/src/parser.cpp b/src/parser.cpp index 1da6905..1942281 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2060,19 +2060,16 @@ StateECommand::custom(gchar chr) * Note that on 8 color terminals, only the first 8 colors * can be redefined (if you are lucky). * Note that due to restrictions of most terminal emulators - * and some curses implementations, this command will not - * and cannot restore the original palette entry or request + * and some curses implementations, this command simply will not + * restore the original palette entry or request * when rubbed out and should generally only be used in * \fIbatch-mode\fP \(em typically when loading a color scheme. - * For the same reasons, palette changes may persist - * after \*(ST terminates on most terminal emulators. - * The only emulator which restores the palette on exit the - * author is aware of is the Linux console driver. - * Few other emulators like \fBxterm\fP(1) might support - * palette resets but this cannot be done automatically - * by \*(ST for technical and historical reasons. - * Users might try to work around this by tweaking their - * \fBterminfo\fP(5) database. + * For the same reasons \(em even though \*(ST tries hard to + * restore the original palette on exit \(em palette changes may + * persist after \*(ST terminates on most terminal emulators on Unix. + * The only emulator which will restore their default palette + * on exit the author is aware of is \fBxterm\fP(1) and + * the Linux console driver. * You have been warned. Good luck. */ case 'J': { |