aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2015-07-14 03:29:29 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2015-07-14 03:29:29 +0200
commit45e2f9a5c6a8ac29ce9fa1bf2e18343098c4a050 (patch)
treef153a392222863bfdec8f1b8b79da28710aa5790
parentc39b54543c81fefdf30a67caac9a86f9f8ecd215 (diff)
downloadsciteco-45e2f9a5c6a8ac29ce9fa1bf2e18343098c4a050.tar.gz
curses UI: support terminal palette restoration on PDCurses/win32 and xterm
* palette changes are persistent on PDCurses/win32, too. Fortunately, on this port we can reliably query the console palette. This is done ONLY on PDcurses/win32 since on other ports (notably ncurses), this can cause more harm than it helps. * support palette restoration on xterm by hardcoding the appropriate escape sequence. $TERM cannot be used to identify xterm, but looking at $XTERM_VERSION is sufficient hopefully.
-rw-r--r--src/interface-curses.cpp157
-rw-r--r--src/interface-curses.h26
-rw-r--r--src/parser.cpp19
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': {