0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
1 |
/*
|
2 |
* userui_text.c - Text mode userspace user interface module.
|
|
3 |
*
|
|
4 |
* Copyright (C) 2005, Bernard Blackham <bernard@blackham.com.au>
|
|
5 |
* Copyright (C) 2006-2009, Nigel Cunningham <nigel@tuxonice.net>
|
|
6 |
*
|
|
7 |
* Based on the suspend_text module from Suspend2, written by
|
|
8 |
* Nigel Cunningham <nigel@nigel.tuxonice.net>
|
|
9 |
*
|
|
10 |
* This file is subject to the terms and conditions of the GNU General Public
|
|
11 |
* License v2. See the file COPYING in the main directory of this archive for
|
|
12 |
* more details.
|
|
13 |
*
|
|
14 |
*/
|
|
15 |
||
16 |
#include <sys/ioctl.h> |
|
17 |
#include <sys/types.h> |
|
18 |
#include <sys/stat.h> |
|
19 |
#include <fcntl.h> |
|
20 |
#include <string.h> |
|
21 |
#include <stdarg.h> |
|
22 |
#include <stdio.h> |
|
23 |
#include <stdlib.h> |
|
24 |
#include <termios.h> |
|
25 |
#include <unistd.h> |
|
26 |
||
27 |
#include "userui.h" |
|
28 |
||
29 |
/* We essentially cut and paste the suspend_text plugin */
|
|
30 |
||
31 |
static int barwidth = 0, barposn = -1; |
|
32 |
static int draw_progress_bar = 1; |
|
33 |
||
34 |
static struct termios termios; |
|
35 |
static int lastloglevel = -1; |
|
0.1.1088
by Nigel Cunningham
Single binary support. |
36 |
static int cur_x = -1, cur_y = -1; |
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
37 |
|
38 |
static int vcsa_fd = -1; |
|
39 |
||
55
by Nigel Cunningham
Silence warnings about ignoring return value of write() |
40 |
static inline void clear_display() { if (write(1, "\033[2J", 4)) do {} while(0); } |
41 |
static inline void reset_display() { if (write(1, "\033c", 2)) do {} while(0); } |
|
42 |
static inline void clear_to_eol() { if (write(1, "\033K", 2)) do {} while(0); } |
|
43 |
static inline void hide_cursor() { if (write(1, "\033[?25l\033[?1c", 11)) do {} while(0); } |
|
44 |
static inline void show_cursor() { if (write(1, "\033[?25h\033[?0c", 11)) do {} while(0); } |
|
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
45 |
static inline void move_cursor_to(int c, int r) { printf("\033[%d;%dH", r, c); } |
46 |
||
47 |
static void flush_scrollback() |
|
48 |
{
|
|
49 |
int i; |
|
50 |
for (i = 0; i <= video_num_lines; i++) |
|
55
by Nigel Cunningham
Silence warnings about ignoring return value of write() |
51 |
if (write(1, "\n", 1)) do { |
52 |
} while(0); |
|
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
53 |
}
|
54 |
||
55 |
static int update_cursor_pos(void) |
|
56 |
{
|
|
57 |
struct { |
|
58 |
unsigned char lines, cols, x, y; |
|
59 |
} screen; |
|
60 |
||
61 |
if (vcsa_fd < 0) |
|
62 |
return 0; |
|
63 |
if (lseek(vcsa_fd, 0, SEEK_SET) == -1) |
|
64 |
return 0; |
|
65 |
if (read(vcsa_fd, &screen, sizeof(screen)) == -1) |
|
66 |
return 0; |
|
67 |
cur_x = screen.x+1; |
|
68 |
cur_y = screen.y+1; |
|
69 |
return 1; |
|
70 |
}
|
|
71 |
||
72 |
/*
|
|
73 |
* Help text functions.
|
|
74 |
*/
|
|
75 |
static void update_help(int update_all) |
|
76 |
{
|
|
77 |
char buf[200]; |
|
78 |
||
79 |
if (resuming) |
|
80 |
snprintf(buf, 200, "%-22s", |
|
81 |
(can_use_escape) ? "Esc: Abort resume" : ""); |
|
82 |
else
|
|
83 |
snprintf(buf, 200, "%-22s R: %s reboot after hibernating ", |
|
84 |
(can_use_escape) ? "Esc: Abort hibernating" : "", |
|
85 |
(suspend_action & (1 << SUSPEND_REBOOT)) ? "Disable":" Enable"); |
|
86 |
move_cursor_to(video_num_columns - strlen(buf), video_num_lines); |
|
87 |
printf("%s", buf); |
|
88 |
}
|
|
89 |
||
90 |
/* text_prepare_status
|
|
91 |
* Description: Prepare the 'nice display', drawing the header and version,
|
|
92 |
* along with the current action and perhaps also resetting the
|
|
93 |
* progress bar.
|
|
94 |
* Arguments: int printalways: Whether to print the action when debugging
|
|
95 |
* is on
|
|
96 |
* int clearbar: Whether to reset the progress bar.
|
|
97 |
* const char *fmt, ...: The action to be displayed.
|
|
98 |
*/
|
|
99 |
||
100 |
static void text_prepare_status_real(int printalways, int clearbar, int level, const char *msg) |
|
101 |
{
|
|
102 |
int y, i; |
|
103 |
||
0.1.1088
by Nigel Cunningham
Single binary support. |
104 |
if (msg) |
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
105 |
strncpy(lastheader, msg, 512); |
106 |
||
107 |
if (console_loglevel >= SUSPEND_ERROR) { |
|
108 |
if (!(suspend_action & (1 << SUSPEND_LOGALL)) || level == SUSPEND_UI_MSG) |
|
109 |
printf("\n** %s\n", lastheader); |
|
110 |
return; |
|
111 |
}
|
|
112 |
||
113 |
/* Remember where the cursor was */
|
|
114 |
if (cur_x != -1) |
|
115 |
update_cursor_pos(); |
|
116 |
||
117 |
/* Print version */
|
|
118 |
move_cursor_to(0, video_num_lines); |
|
119 |
printf("%s", software_suspend_version); |
|
120 |
||
121 |
/* Update help text */
|
|
122 |
update_help(0); |
|
123 |
||
124 |
/* Print header */
|
|
125 |
move_cursor_to((video_num_columns - 19) / 2, (video_num_lines / 3) - 3); |
|
126 |
printf("T U X O N I C E"); |
|
127 |
||
128 |
/* Print action */
|
|
129 |
y = video_num_lines / 3; |
|
130 |
move_cursor_to(0, y); |
|
131 |
||
132 |
/* Clear old message */
|
|
133 |
for (i = 0; i < video_num_columns; i++) |
|
134 |
printf(" "); |
|
135 |
||
0.1.1088
by Nigel Cunningham
Single binary support. |
136 |
move_cursor_to((video_num_columns - strlen(lastheader)) / 2, y); |
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
137 |
printf("%s", lastheader); |
138 |
||
139 |
if (draw_progress_bar) { |
|
140 |
/* Draw left bracket of progress bar. */
|
|
141 |
y++; |
|
142 |
move_cursor_to(video_num_columns / 4, y); |
|
143 |
printf("["); |
|
144 |
||
145 |
/* Draw right bracket of progress bar. */
|
|
146 |
move_cursor_to(video_num_columns - (video_num_columns / 4) - 1, y); |
|
147 |
printf("]"); |
|
148 |
||
149 |
if (clearbar) { |
|
150 |
/* Position at start of progress */
|
|
151 |
move_cursor_to(video_num_columns / 4 + 1, y); |
|
152 |
||
153 |
/* Clear bar */
|
|
154 |
for (i = 0; i < barwidth; i++) |
|
155 |
printf(" "); |
|
156 |
||
157 |
move_cursor_to(video_num_columns / 4 + 1, y); |
|
158 |
||
159 |
barposn = 0; |
|
160 |
}
|
|
161 |
}
|
|
162 |
||
163 |
if (cur_x == -1) { |
|
164 |
cur_x = 1; |
|
165 |
cur_y = y+2; |
|
166 |
}
|
|
167 |
move_cursor_to(cur_x, cur_y); |
|
168 |
||
169 |
hide_cursor(); |
|
170 |
}
|
|
171 |
||
172 |
static void text_prepare_status(int printalways, int clearbar, int level, const char *fmt, ...) |
|
173 |
{
|
|
174 |
va_list va; |
|
175 |
char buf[1024]; |
|
176 |
if (fmt) { |
|
177 |
va_start(va, fmt); |
|
178 |
vsnprintf(buf, 1024, fmt, va); |
|
179 |
text_prepare_status_real(printalways, clearbar, level, buf); |
|
180 |
va_end(va); |
|
181 |
} else |
|
182 |
text_prepare_status_real(printalways, clearbar, level, NULL); |
|
183 |
}
|
|
184 |
||
185 |
/* text_loglevel_change
|
|
186 |
*
|
|
187 |
* Description: Update the display when the user changes the log level.
|
|
188 |
* Returns: Boolean indicating whether the level was changed.
|
|
189 |
*/
|
|
190 |
||
191 |
static void text_loglevel_change() |
|
192 |
{
|
|
193 |
/* Only reset the display if we're switching between nice display
|
|
194 |
* and displaying debugging output */
|
|
195 |
||
196 |
if (console_loglevel >= SUSPEND_ERROR) { |
|
197 |
if (lastloglevel < SUSPEND_ERROR) |
|
198 |
clear_display(); |
|
199 |
||
200 |
show_cursor(); |
|
201 |
||
202 |
if (lastloglevel > -1) |
|
203 |
printf("\nSwitched to console loglevel %d.\n", console_loglevel); |
|
204 |
||
205 |
if (lastloglevel > -1 && lastloglevel < SUSPEND_ERROR) { |
|
206 |
printf("\n** %s\n", lastheader); |
|
207 |
}
|
|
208 |
||
209 |
} else if (lastloglevel >= SUSPEND_ERROR || lastloglevel == -1) { |
|
210 |
clear_display(); |
|
211 |
hide_cursor(); |
|
212 |
||
213 |
/* Get the nice display or last action [re]drawn */
|
|
214 |
text_prepare_status(1, 0, SUSPEND_UI_MSG, NULL); |
|
215 |
}
|
|
216 |
||
217 |
lastloglevel = console_loglevel; |
|
218 |
}
|
|
219 |
||
220 |
/* text_update_progress
|
|
221 |
*
|
|
222 |
* Description: Update the progress bar and (if on) in-bar message.
|
|
223 |
* Arguments: U32 value, maximum: Current progress percentage (value/max).
|
|
224 |
* const char *fmt, ...: Message to be displayed in the middle
|
|
225 |
* of the progress bar.
|
|
226 |
* Note that a NULL message does not mean that any previous
|
|
227 |
* message is erased! For that, you need prepare_status with
|
|
228 |
* clearbar on.
|
|
229 |
* Returns: Unsigned long: The next value where status needs to be updated.
|
|
230 |
* This is to reduce unnecessary calls to text_update_progress.
|
|
231 |
*/
|
|
232 |
void text_update_progress(__uint32_t value, __uint32_t maximum, char *msg) |
|
233 |
{
|
|
234 |
int bitshift = generic_fls(maximum) - 16, i; |
|
235 |
int msg_len = msg ? strlen(msg) : 0; |
|
236 |
int msg_start = (video_num_columns - msg_len - 2) / 2 - |
|
237 |
(video_num_columns / 4 + 1); |
|
238 |
char bar_char = '-'; |
|
239 |
||
240 |
if (!maximum) |
|
241 |
return /* maximum */; |
|
242 |
||
243 |
if (value < 0) |
|
244 |
value = 0; |
|
245 |
||
246 |
if (value > maximum) |
|
247 |
value = maximum; |
|
248 |
||
249 |
/* Try to avoid math problems - we can't do 64 bit math here
|
|
250 |
* (and shouldn't need it - anyone got screen resolution
|
|
251 |
* of 65536 pixels or more?) */
|
|
252 |
if (bitshift > 0) { |
|
253 |
__uint32_t temp_maximum = maximum >> bitshift; |
|
254 |
__uint32_t temp_value = value >> bitshift; |
|
255 |
barposn = (__uint32_t) (temp_value * barwidth / temp_maximum); |
|
256 |
} else |
|
257 |
barposn = (__uint32_t) (value * barwidth / maximum); |
|
258 |
||
259 |
if ((console_loglevel >= SUSPEND_ERROR) || (!draw_progress_bar)) |
|
49
by Nigel
Apply Debian patch Fix "warning: implicit declaration of function ‘printk’" |
260 |
return; |
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
261 |
|
262 |
/* Remember where the cursor was */
|
|
263 |
if (cur_x != -1) |
|
264 |
update_cursor_pos(); |
|
265 |
||
266 |
/* Update bar */
|
|
267 |
if (msg_start < 0) { |
|
268 |
move_cursor_to((video_num_columns - msg_len) / 2, |
|
269 |
(video_num_lines / 3) + 1); |
|
270 |
printf(" %s ", msg); |
|
271 |
} else { |
|
272 |
move_cursor_to(video_num_columns / 4 + 1, (video_num_lines / 3) + 1); |
|
273 |
for (i = 0; i < barwidth; i++) { |
|
274 |
if (i == barposn) |
|
275 |
bar_char = ' '; |
|
276 |
if (i == msg_start && msg_len && console_loglevel) { |
|
277 |
printf(" %s ", msg); |
|
278 |
i += msg_len + 2; |
|
279 |
if (i >= barposn) |
|
280 |
bar_char = ' '; |
|
281 |
} else |
|
282 |
printf("%c", bar_char); |
|
283 |
}
|
|
284 |
}
|
|
285 |
||
286 |
if (cur_x != -1) |
|
287 |
move_cursor_to(cur_x, cur_y); |
|
288 |
||
289 |
hide_cursor(); |
|
290 |
}
|
|
291 |
||
292 |
static void text_message(__uint32_t section, __uint32_t level, |
|
293 |
__uint32_t normally_logged, char *msg) |
|
294 |
{
|
|
295 |
if (section && !((1 << section) & suspend_debug)) |
|
296 |
return; |
|
297 |
||
298 |
if (level > console_loglevel) |
|
299 |
return; |
|
300 |
||
301 |
text_prepare_status_real(1, 0, level, msg); |
|
302 |
}
|
|
303 |
||
0.1.1088
by Nigel Cunningham
Single binary support. |
304 |
static int text_load() |
305 |
{
|
|
0.1.1091
by Nigel Cunningham
Fix text ui when fbsplash ui not compiled in. |
306 |
struct winsize winsz; |
307 |
struct termios new_termios; |
|
308 |
||
309 |
lastloglevel = SUSPEND_ERROR; /* start in verbose mode */ |
|
310 |
||
311 |
setvbuf(stdout, NULL, _IONBF, 0); |
|
312 |
||
313 |
/* Turn off canonical mode */
|
|
314 |
ioctl(STDOUT_FILENO, TCGETS, (long)&termios); |
|
315 |
new_termios = termios; |
|
316 |
new_termios.c_lflag &= ~ICANON; |
|
317 |
ioctl(STDOUT_FILENO, TCSETSF, (long)&new_termios); |
|
318 |
||
319 |
/* Find out the screen size */
|
|
320 |
video_num_lines = 24; |
|
321 |
video_num_columns = 80; |
|
322 |
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsz) != -1 && |
|
323 |
winsz.ws_row > 0 && winsz.ws_col > 0) { |
|
324 |
video_num_lines = winsz.ws_row; |
|
325 |
video_num_columns = winsz.ws_col; |
|
326 |
printk("Console is %dx%d.\n", video_num_lines, video_num_columns); |
|
327 |
}
|
|
328 |
||
329 |
/* Calculate progress bar width. Note that whether the
|
|
330 |
* splash screen is on might have changed (this might be
|
|
331 |
* the first call in a new cycle), so we can't take it
|
|
332 |
* for granted that the width is the same as last time
|
|
333 |
* we came in here */
|
|
334 |
barwidth = (video_num_columns - 2 * (video_num_columns / 4) - 2); |
|
335 |
||
336 |
/* Open /dev/vcsa0 so we can find out the cursor position when we need to */
|
|
337 |
vcsa_fd = open("/dev/vcsa0", O_RDONLY); |
|
338 |
/* if it errors, don't worry. we'll check later */
|
|
339 |
||
340 |
return 0; |
|
0.1.1088
by Nigel Cunningham
Single binary support. |
341 |
}
|
342 |
||
343 |
static void text_prepare() |
|
344 |
{
|
|
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
345 |
clear_display(); |
346 |
||
0.1.1088
by Nigel Cunningham
Single binary support. |
347 |
lastloglevel = -1; |
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
348 |
text_loglevel_change(); |
349 |
}
|
|
350 |
||
0.1.1088
by Nigel Cunningham
Single binary support. |
351 |
static void text_unprepare() |
352 |
{
|
|
353 |
clear_display(); |
|
354 |
move_cursor_to(0, 0); |
|
355 |
}
|
|
356 |
||
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
357 |
static void text_cleanup() |
358 |
{
|
|
0.1.1088
by Nigel Cunningham
Single binary support. |
359 |
text_unprepare(); |
360 |
show_cursor(); |
|
361 |
||
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
362 |
if (vcsa_fd >= 0) |
363 |
close(vcsa_fd); |
|
364 |
||
365 |
ioctl(STDOUT_FILENO, TCSETSF, (long)&termios); |
|
366 |
||
367 |
/* chvt back? */
|
|
368 |
}
|
|
369 |
||
370 |
static void text_redraw() |
|
371 |
{
|
|
372 |
clear_display(); |
|
373 |
reset_display(); |
|
374 |
flush_scrollback(); |
|
375 |
cur_x = -1; |
|
376 |
}
|
|
377 |
||
378 |
static void text_keypress(int key) |
|
379 |
{
|
|
380 |
if (common_keypress_handler(key)) |
|
381 |
return; |
|
382 |
switch (key) { |
|
383 |
}
|
|
384 |
}
|
|
385 |
||
0.1.1088
by Nigel Cunningham
Single binary support. |
386 |
struct userui_ops userui_text_ops = { |
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
387 |
.name = "text", |
0.1.1088
by Nigel Cunningham
Single binary support. |
388 |
.load = text_load, |
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
389 |
.prepare = text_prepare, |
0.1.1088
by Nigel Cunningham
Single binary support. |
390 |
.unprepare = text_unprepare, |
0.1.1086
by Nigel Cunningham
Move files from trunk subdirectory. |
391 |
.cleanup = text_cleanup, |
392 |
.message = text_message, |
|
393 |
.update_progress = text_update_progress, |
|
394 |
.log_level_change = text_loglevel_change, |
|
395 |
.redraw = text_redraw, |
|
396 |
.keypress = text_keypress, |
|
397 |
};
|