1 /* Terminal control for outputting styled text to a terminal. 2 Copyright (C) 2019-2021 Free Software Foundation, Inc. 3 Written by Bruno Haible <bruno@clisp.org>, 2019. 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 17 18 #ifndef _TERM_STYLE_CONTROL_H 19 #define _TERM_STYLE_CONTROL_H 20 21 #include <stdbool.h> 22 23 /* The user of this file will define a macro 'term_style_user_data', such that 24 'struct term_style_user_data' is a user-defined struct. */ 25 26 27 /* The amount of control to take over the underlying tty in order to avoid 28 garbled output on the screen, due to interleaved output of escape sequences 29 and output from the kernel (such as when the kernel echoes user's input 30 or when the kernel prints '^C' after the user pressed Ctrl-C). */ 31 typedef enum 32 { 33 TTYCTL_AUTO = 0, /* Automatic best-possible choice. */ 34 TTYCTL_NONE, /* No control. 35 Result: Garbled output can occur, and the terminal can 36 be left in any state when the program is interrupted. */ 37 TTYCTL_PARTIAL, /* Signal handling. 38 Result: Garbled output can occur, but the terminal will 39 be left in the default state when the program is 40 interrupted. */ 41 TTYCTL_FULL /* Signal handling and disabling echo and flush-upon-signal. 42 Result: No garbled output, and the the terminal will 43 be left in the default state when the program is 44 interrupted. */ 45 } ttyctl_t; 46 47 /* This struct contains data, used by implementation of this module. 48 You should not access the members of this struct; they may be renamed or 49 removed without notice. */ 50 struct term_style_control_data 51 { 52 int volatile fd; 53 ttyctl_t volatile tty_control; /* Signal handling and tty control. */ 54 #if HAVE_TCGETATTR 55 bool volatile same_as_stderr; 56 #endif 57 bool non_default_active; /* True if activate_term_non_default_mode() 58 is in effect. */ 59 }; 60 61 /* Forward declaration. */ 62 struct term_style_user_data; 63 64 /* This struct contains function pointers. You implement these functions 65 in your application; this module invokes them when it needs to. */ 66 struct term_style_controller 67 { 68 /* This function returns a pointer to the embedded 69 'struct term_style_control_data' contained in a 70 'struct term_style_user_data'. */ 71 struct term_style_control_data * (*get_control_data) (struct term_style_user_data *); 72 73 /* This function brings the terminal's state back to the default state 74 (no styling attributes set). It is invoked when the process terminates 75 through exit(). */ 76 void (*restore) (struct term_style_user_data *); 77 78 /* This function brings the terminal's state back to the default state 79 (no styling attributes set). It is async-safe (see gnulib-common.m4 for 80 the precise definition). It is invoked when the process receives a fatal 81 or stopping signal. */ 82 _GL_ASYNC_SAFE void (*async_restore) (struct term_style_user_data *); 83 84 /* This function brings the terminal's state, from the default state, back 85 to the state where it has the desired attributes set. It is async-safe 86 (see gnulib-common.m4 for the precise definition). It is invoked when 87 the process receives a SIGCONT signal. */ 88 _GL_ASYNC_SAFE void (*async_set_attributes_from_default) (struct term_style_user_data *); 89 }; 90 91 92 #ifdef __cplusplus 93 extern "C" { 94 #endif 95 96 /* This module is used as follows: 97 1. You fill a 'struct term_style_controller' with function pointers. 98 You create a 'struct term_style_user_data' that contains, among other 99 members, a 'struct term_style_control_data'. 100 You will pass these two objects to all API functions below. 101 2. You call activate_term_style_controller to activate this controller. 102 Activation of the controller is the prerequisite for activating 103 the non-default mode, which in turn is the prerequisite for changing 104 the terminal's attributes. 105 When you are done with the styled output, you may deactivate the 106 controller. This is not required before exiting the program, but is 107 required before activating a different controller. 108 You cannot have more than one controller activated at the same time. 109 3. Once the controller is activated, you may turn on the non-default mode. 110 The non-default mode is the prerequisite for changing the terminal's 111 attributes. Once the terminal's attributes are in the default state 112 again, you may turn off the non-default mode again. 113 In other words: 114 - In the default mode, the terminal's attributes MUST be in the default 115 state; no styled output is possible. 116 - In the non-default mode, the terminal's attributes MAY switch among 117 the default state and other states. 118 This module exercises a certain amount of control over the terminal 119 during the non-default mode phases; see above (ttyctl_t) for details. 120 You may switch between the default and the non-default modes any number 121 of times. 122 The idea is that you switch back to the default mode before doing large 123 amounts of output of unstyled text. However, this is not a requirement: 124 You may leave the non-default mode turned on all the time until the 125 the program exits. 126 4. Once the non-default mode is activated, you may change the attributes 127 (foreground color, background color, font weight, font posture, underline 128 decoration, etc.) of the terminal. On Unix, this is typically done by 129 outputting appropriate escape sequences. 130 5. Once attributes are set, text output to the terminal will be rendered 131 with these attributes. 132 Note: You MUST return the terminal to the default state before outputting 133 a newline. 134 */ 135 136 /* Activates a controller. The CONTROLLER and its USER_DATA controls the 137 terminal associated with FD. FD is usually STDOUT_FILENO. 138 TTY_CONTROL specifies the amount of control to take over the underlying tty. 139 The effects of this functions are undone by calling 140 deactivate_term_style_controller. 141 You cannot have more than one controller activated at the same time. 142 You must not close FD while the controller is active. */ 143 extern void 144 activate_term_style_controller (const struct term_style_controller *controller, 145 struct term_style_user_data *user_data, 146 int fd, ttyctl_t tty_control); 147 148 /* Activates the non-default mode. 149 CONTROLLER and its USER_DATA must be a currently active controller. 150 This function fiddles with the signals of the current process and with 151 the underlying tty, to an extent described by TTY_CONTROL. 152 This function is idempotent: When you call it twice in a row, the second 153 invocation does nothing. 154 The effects of this function are undone by calling 155 deactivate_term_non_default_mode. */ 156 extern void 157 activate_term_non_default_mode (const struct term_style_controller *controller, 158 struct term_style_user_data *user_data); 159 160 /* Deactivates the non-default mode. 161 CONTROLLER and its USER_DATA must be a currently active controller. 162 This function is idempotent: When you call it twice in a row, the second 163 invocation does nothing. 164 Before invoking this function, you must put the terminal's attributes in 165 the default state. */ 166 extern void 167 deactivate_term_non_default_mode (const struct term_style_controller *controller, 168 struct term_style_user_data *user_data); 169 170 /* Deactivates a controller. 171 CONTROLLER and its USER_DATA must be a currently active controller. 172 Before invoking this function, you must ensure that the non-default mode 173 is deactivated. */ 174 extern void 175 deactivate_term_style_controller (const struct term_style_controller *controller, 176 struct term_style_user_data *user_data); 177 178 #ifdef __cplusplus 179 } 180 #endif 181 182 #endif /* _TERM_STYLE_CONTROL_H */