~tuxonice/tuxonice-userui/master

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
};