Widget library: added new widget WHLine.
[midnight-commander.git] / src / cons.handler.c
blobbb4674b6bdb89fa1e5845cf020f25484383bfdcd
1 /* Client interface for General purpose Linux console save/restore server
2 Copyright (C) 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2006, 2007 Free Software Foundation, Inc.
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 2 of the License, or
8 (at your option) any later version.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19 /** \file cons.handler.c
20 * \brief Source: client %interface for General purpose Linux console save/restore server
23 #include <config.h>
25 #include <stdlib.h>
26 #include <sys/wait.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #ifdef __FreeBSD__
32 # include <sys/consio.h>
33 # include <sys/ioctl.h>
34 #endif
35 #include <unistd.h>
37 #include "lib/global.h"
39 #include "lib/tty/tty.h"
40 #include "lib/skin.h" /* tty_set_normal_attrs */
41 #include "lib/tty/win.h"
43 #include "consaver/cons.saver.h"
45 signed char console_flag = 0;
47 #ifdef __linux__
49 /* The cons saver can't have a pid of 1, used to prevent bunches of
50 * #ifdef linux */
52 int cons_saver_pid = 1;
53 static int pipefd1[2] = { -1, -1 };
54 static int pipefd2[2] = { -1, -1 };
56 static void
57 show_console_contents_linux (int starty, unsigned char begin_line,
58 unsigned char end_line)
60 unsigned char message = 0;
61 unsigned short bytes = 0;
62 int i;
64 /* Is tty console? */
65 if (!console_flag)
66 return;
67 /* Paranoid: Is the cons.saver still running? */
68 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT)) {
69 cons_saver_pid = 0;
70 console_flag = 0;
71 return;
74 /* Send command to the console handler */
75 message = CONSOLE_CONTENTS;
76 write (pipefd1[1], &message, 1);
77 /* Check for outdated cons.saver */
78 read (pipefd2[0], &message, 1);
79 if (message != CONSOLE_CONTENTS)
80 return;
82 /* Send the range of lines that we want */
83 write (pipefd1[1], &begin_line, 1);
84 write (pipefd1[1], &end_line, 1);
85 /* Read the corresponding number of bytes */
86 read (pipefd2[0], &bytes, 2);
88 /* Read the bytes and output them */
89 for (i = 0; i < bytes; i++) {
90 if ((i % COLS) == 0)
91 tty_gotoyx (starty + (i / COLS), 0);
92 read (pipefd2[0], &message, 1);
93 tty_print_char (message);
96 /* Read the value of the console_flag */
97 read (pipefd2[0], &message, 1);
100 static void
101 handle_console_linux (unsigned char action)
103 char *tty_name;
104 char *mc_conssaver;
105 int status;
107 switch (action) {
108 case CONSOLE_INIT:
109 /* Close old pipe ends in case it is the 2nd time we run cons.saver */
110 close (pipefd1[1]);
111 close (pipefd2[0]);
112 /* Create two pipes for communication */
113 pipe (pipefd1);
114 pipe (pipefd2);
115 /* Get the console saver running */
116 cons_saver_pid = fork ();
117 if (cons_saver_pid < 0) {
118 /* Cannot fork */
119 /* Delete pipes */
120 close (pipefd1[1]);
121 close (pipefd1[0]);
122 close (pipefd2[1]);
123 close (pipefd2[0]);
124 console_flag = 0;
125 } else if (cons_saver_pid > 0) {
126 /* Parent */
127 /* Close the extra pipe ends */
128 close (pipefd1[0]);
129 close (pipefd2[1]);
130 /* Was the child successful? */
131 read (pipefd2[0], &console_flag, 1);
132 if (!console_flag) {
133 close (pipefd1[1]);
134 close (pipefd2[0]);
135 waitpid (cons_saver_pid, &status, 0);
137 } else {
138 /* Child */
139 /* Close the extra pipe ends */
140 close (pipefd1[1]);
141 close (pipefd2[0]);
142 tty_name = ttyname (0);
143 /* Bind the pipe 0 to the standard input */
144 close (0);
145 dup (pipefd1[0]);
146 close (pipefd1[0]);
147 /* Bind the pipe 1 to the standard output */
148 close (1);
149 dup (pipefd2[1]);
150 close (pipefd2[1]);
151 /* Bind standard error to /dev/null */
152 close (2);
153 open ("/dev/null", O_WRONLY);
154 if (tty_name) {
155 /* Exec the console save/restore handler */
156 mc_conssaver = concat_dir_and_file (SAVERDIR, "cons.saver");
157 execl (mc_conssaver, "cons.saver", tty_name, (char *) NULL);
159 /* Console is not a tty or execl() failed */
160 console_flag = 0;
161 write (1, &console_flag, 1);
162 _exit (3);
163 } /* if (cons_saver_pid ...) */
164 break;
166 case CONSOLE_DONE:
167 case CONSOLE_SAVE:
168 case CONSOLE_RESTORE:
169 /* Is tty console? */
170 if (!console_flag)
171 return;
172 /* Paranoid: Is the cons.saver still running? */
173 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT)) {
174 cons_saver_pid = 0;
175 console_flag = 0;
176 return;
178 /* Send command to the console handler */
179 write (pipefd1[1], &action, 1);
180 if (action != CONSOLE_DONE) {
181 /* Wait the console handler to do its job */
182 read (pipefd2[0], &console_flag, 1);
184 if (action == CONSOLE_DONE || !console_flag) {
185 /* We are done -> Let's clean up */
186 close (pipefd1[1]);
187 close (pipefd2[0]);
188 waitpid (cons_saver_pid, &status, 0);
189 console_flag = 0;
191 break;
195 #elif defined(__FreeBSD__)
198 * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
199 * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
202 #define FD_OUT 1
204 static struct scrshot screen_shot;
205 static struct vid_info screen_info;
207 static void
208 console_init (void)
210 if (console_flag)
211 return;
213 screen_info.size = sizeof (screen_info);
214 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
215 return;
217 memset (&screen_shot, 0, sizeof (screen_shot));
218 screen_shot.xsize = screen_info.mv_csz;
219 screen_shot.ysize = screen_info.mv_rsz;
220 screen_shot.buf = g_try_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2);
221 if (screen_shot.buf != NULL)
222 console_flag = 1;
225 static void
226 set_attr (unsigned attr)
229 * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
230 * to indices for ANSI sequences (red=1, green=2, blue=4).
232 static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
233 int bc, tc;
235 tc = attr & 0xF;
236 bc = (attr >> 4) & 0xF;
238 printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
239 color_map[tc & 7], color_map[bc & 7]);
242 #define cursor_to(x, y) do { \
243 printf("\x1B[%d;%df", (y) + 1, (x) + 1); \
244 fflush(stdout); \
245 } while (0)
247 static void
248 console_restore (void)
250 int i, last;
252 if (!console_flag)
253 return;
255 cursor_to (0, 0);
257 /* restoring all content up to cursor position */
258 last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
259 for (i = 0; i < last; ++i) {
260 set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
261 putc (screen_shot.buf[i] & 0xFF, stdout);
264 /* restoring cursor color */
265 set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
267 fflush (stdout);
270 static void
271 console_shutdown (void)
273 if (!console_flag)
274 return;
276 g_free (screen_shot.buf);
278 console_flag = 0;
281 static void
282 console_save (void)
284 int i;
285 scrmap_t map;
286 scrmap_t revmap;
288 if (!console_flag)
289 return;
291 /* screen_info.size is already set in console_init() */
292 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1) {
293 console_shutdown ();
294 return;
297 /* handle console resize */
298 if (screen_info.mv_csz != screen_shot.xsize
299 || screen_info.mv_rsz != screen_shot.ysize) {
300 console_shutdown ();
301 console_init ();
304 if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1) {
305 console_shutdown ();
306 return;
309 if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1) {
310 console_shutdown ();
311 return;
314 for (i = 0; i < 256; i++) {
315 char *p = memchr (map.scrmap, i, 256);
316 revmap.scrmap[i] = p ? p - map.scrmap : i;
319 for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++) {
320 screen_shot.buf[i] =
321 (screen_shot.buf[i] & 0xff00) | (unsigned char) revmap.
322 scrmap[screen_shot.buf[i] & 0xff];
326 static void
327 show_console_contents_freebsd (int starty, unsigned char begin_line,
328 unsigned char end_line)
330 int col, line;
331 char c;
333 if (!console_flag)
334 return;
336 for (line = begin_line; line <= end_line; line++) {
337 tty_gotoyx (starty + line - begin_line, 0);
338 for (col = 0; col < min (COLS, screen_info.mv_csz); col++) {
339 c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
340 tty_print_char (c);
345 static void
346 handle_console_freebsd (unsigned char action)
348 switch (action) {
349 case CONSOLE_INIT:
350 console_init ();
351 break;
353 case CONSOLE_DONE:
354 console_shutdown ();
355 break;
357 case CONSOLE_SAVE:
358 console_save ();
359 break;
361 case CONSOLE_RESTORE:
362 console_restore ();
363 break;
366 #endif /* __FreeBSD__ */
368 void
369 show_console_contents (int starty, unsigned char begin_line,
370 unsigned char end_line)
372 tty_set_normal_attrs ();
374 if (look_for_rxvt_extensions ()) {
375 show_rxvt_contents (starty, begin_line, end_line);
376 return;
378 #ifdef __linux__
379 show_console_contents_linux (starty, begin_line, end_line);
380 #elif defined (__FreeBSD__)
381 show_console_contents_freebsd (starty, begin_line, end_line);
382 #else
383 console_flag = 0;
384 #endif
387 void
388 handle_console (unsigned char action)
390 (void) action;
392 if (look_for_rxvt_extensions ())
393 return;
395 #ifdef __linux__
396 handle_console_linux (action);
397 #elif defined (__FreeBSD__)
398 handle_console_freebsd (action);
399 #endif