| /* Terminal control for outputting styled text to a terminal. |
| Copyright (C) 2019-2020 Free Software Foundation, Inc. |
| Written by Bruno Haible <bruno@clisp.org>, 2019. |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| |
| #ifndef _TERM_STYLE_CONTROL_H |
| #define _TERM_STYLE_CONTROL_H |
| |
| #include <stdbool.h> |
| |
| /* The user of this file will define a macro 'term_style_user_data', such that |
| 'struct term_style_user_data' is a user-defined struct. */ |
| |
| |
| /* The amount of control to take over the underlying tty in order to avoid |
| garbled output on the screen, due to interleaved output of escape sequences |
| and output from the kernel (such as when the kernel echoes user's input |
| or when the kernel prints '^C' after the user pressed Ctrl-C). */ |
| typedef enum |
| { |
| TTYCTL_AUTO = 0, /* Automatic best-possible choice. */ |
| TTYCTL_NONE, /* No control. |
| Result: Garbled output can occur, and the terminal can |
| be left in any state when the program is interrupted. */ |
| TTYCTL_PARTIAL, /* Signal handling. |
| Result: Garbled output can occur, but the terminal will |
| be left in the default state when the program is |
| interrupted. */ |
| TTYCTL_FULL /* Signal handling and disabling echo and flush-upon-signal. |
| Result: No garbled output, and the the terminal will |
| be left in the default state when the program is |
| interrupted. */ |
| } ttyctl_t; |
| |
| /* This struct contains data, used by implementation of this module. |
| You should not access the members of this struct; they may be renamed or |
| removed without notice. */ |
| struct term_style_control_data |
| { |
| int volatile fd; |
| ttyctl_t volatile tty_control; /* Signal handling and tty control. */ |
| #if HAVE_TCGETATTR |
| bool volatile same_as_stderr; |
| #endif |
| bool non_default_active; /* True if activate_term_non_default_mode() |
| is in effect. */ |
| }; |
| |
| /* Forward declaration. */ |
| struct term_style_user_data; |
| |
| /* This struct contains function pointers. You implement these functions |
| in your application; this module invokes them when it needs to. */ |
| struct term_style_controller |
| { |
| /* This function returns a pointer to the embedded |
| 'struct term_style_control_data' contained in a |
| 'struct term_style_user_data'. */ |
| struct term_style_control_data * (*get_control_data) (struct term_style_user_data *); |
| |
| /* This function brings the terminal's state back to the default state |
| (no styling attributes set). It is invoked when the process terminates |
| through exit(). */ |
| void (*restore) (struct term_style_user_data *); |
| |
| /* This function brings the terminal's state back to the default state |
| (no styling attributes set). It is async-safe (see gnulib-common.m4 for |
| the precise definition). It is invoked when the process receives a fatal |
| or stopping signal. */ |
| _GL_ASYNC_SAFE void (*async_restore) (struct term_style_user_data *); |
| |
| /* This function brings the terminal's state, from the default state, back |
| to the state where it has the desired attributes set. It is async-safe |
| (see gnulib-common.m4 for the precise definition). It is invoked when |
| the process receives a SIGCONT signal. */ |
| _GL_ASYNC_SAFE void (*async_set_attributes_from_default) (struct term_style_user_data *); |
| }; |
| |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /* This module is used as follows: |
| 1. You fill a 'struct term_style_controller' with function pointers. |
| You create a 'struct term_style_user_data' that contains, among other |
| members, a 'struct term_style_control_data'. |
| You will pass these two objects to all API functions below. |
| 2. You call activate_term_style_controller to activate this controller. |
| Activation of the controller is the prerequisite for activating |
| the non-default mode, which in turn is the prerequisite for changing |
| the terminal's attributes. |
| When you are done with the styled output, you may deactivate the |
| controller. This is not required before exiting the program, but is |
| required before activating a different controller. |
| You cannot have more than one controller activated at the same time. |
| 3. Once the controller is activated, you may turn on the non-default mode. |
| The non-default mode is the prerequisite for changing the terminal's |
| attributes. Once the terminal's attributes are in the default state |
| again, you may turn off the non-default mode again. |
| In other words: |
| - In the default mode, the terminal's attributes MUST be in the default |
| state; no styled output is possible. |
| - In the non-default mode, the terminal's attributes MAY switch among |
| the default state and other states. |
| This module exercises a certain amount of control over the terminal |
| during the non-default mode phases; see above (ttyctl_t) for details. |
| You may switch between the default and the non-default modes any number |
| of times. |
| The idea is that you switch back to the default mode before doing large |
| amounts of output of unstyled text. However, this is not a requirement: |
| You may leave the non-default mode turned on all the time until the |
| the program exits. |
| 4. Once the non-default mode is activated, you may change the attributes |
| (foreground color, background color, font weight, font posture, underline |
| decoration, etc.) of the terminal. On Unix, this is typically done by |
| outputting appropriate escape sequences. |
| 5. Once attributes are set, text output to the terminal will be rendered |
| with these attributes. |
| Note: You MUST return the terminal to the default state before outputting |
| a newline. |
| */ |
| |
| /* Activates a controller. The CONTROLLER and its USER_DATA controls the |
| terminal associated with FD. FD is usually STDOUT_FILENO. |
| TTY_CONTROL specifies the amount of control to take over the underlying tty. |
| The effects of this functions are undone by calling |
| deactivate_term_style_controller. |
| You cannot have more than one controller activated at the same time. |
| You must not close FD while the controller is active. */ |
| extern void |
| activate_term_style_controller (const struct term_style_controller *controller, |
| struct term_style_user_data *user_data, |
| int fd, ttyctl_t tty_control); |
| |
| /* Activates the non-default mode. |
| CONTROLLER and its USER_DATA must be a currently active controller. |
| This function fiddles with the signals of the current process and with |
| the underlying tty, to an extent described by TTY_CONTROL. |
| This function is idempotent: When you call it twice in a row, the second |
| invocation does nothing. |
| The effects of this function are undone by calling |
| deactivate_term_non_default_mode. */ |
| extern void |
| activate_term_non_default_mode (const struct term_style_controller *controller, |
| struct term_style_user_data *user_data); |
| |
| /* Deactivates the non-default mode. |
| CONTROLLER and its USER_DATA must be a currently active controller. |
| This function is idempotent: When you call it twice in a row, the second |
| invocation does nothing. |
| Before invoking this function, you must put the terminal's attributes in |
| the default state. */ |
| extern void |
| deactivate_term_non_default_mode (const struct term_style_controller *controller, |
| struct term_style_user_data *user_data); |
| |
| /* Deactivates a controller. |
| CONTROLLER and its USER_DATA must be a currently active controller. |
| Before invoking this function, you must ensure that the non-default mode |
| is deactivated. */ |
| extern void |
| deactivate_term_style_controller (const struct term_style_controller *controller, |
| struct term_style_user_data *user_data); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* _TERM_STYLE_CONTROL_H */ |