Merge branch '2589_ac_lang_source'
[midnight-commander.git] / src / cons.handler.c
blob31d4c9483ec88ed19220bde87045105f3a6b1bb4
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"
42 #include "lib/util.h" /* concat_dir_and_file() */
44 #include "consaver/cons.saver.h"
46 /*** global variables ****************************************************************************/
48 #ifdef __linux__
49 int cons_saver_pid = 1;
50 #endif /* __linux__ */
52 /*** file scope macro definitions ****************************************************************/
54 #if defined(__FreeBSD__)
55 #define FD_OUT 1
56 #define cursor_to(x, y) \
57 do \
58 { \
59 printf("\x1B[%d;%df", (y) + 1, (x) + 1); \
60 fflush(stdout); \
61 } while (0)
62 #endif /* __linux__ */
64 /*** file scope type declarations ****************************************************************/
66 /*** file scope variables ************************************************************************/
68 #ifdef __linux__
69 /* The cons saver can't have a pid of 1, used to prevent bunches of
70 * #ifdef linux */
71 static int pipefd1[2] = { -1, -1 };
72 static int pipefd2[2] = { -1, -1 };
73 #elif defined(__FreeBSD__)
74 static struct scrshot screen_shot;
75 static struct vid_info screen_info;
76 #endif /* __linux__ */
78 /*** file scope functions ************************************************************************/
79 /* --------------------------------------------------------------------------------------------- */
81 #ifdef __linux__
82 static void
83 show_console_contents_linux (int starty, unsigned char begin_line, unsigned char end_line)
85 unsigned char message = 0;
86 unsigned short bytes = 0;
87 int i;
88 ssize_t ret;
90 /* Is tty console? */
91 if (!mc_global.tty.console_flag)
92 return;
93 /* Paranoid: Is the cons.saver still running? */
94 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
96 cons_saver_pid = 0;
97 mc_global.tty.console_flag = '\0';
98 return;
101 /* Send command to the console handler */
102 message = CONSOLE_CONTENTS;
103 ret = write (pipefd1[1], &message, 1);
104 /* Check for outdated cons.saver */
105 ret = read (pipefd2[0], &message, 1);
106 if (message != CONSOLE_CONTENTS)
107 return;
109 /* Send the range of lines that we want */
110 ret = write (pipefd1[1], &begin_line, 1);
111 ret = write (pipefd1[1], &end_line, 1);
112 /* Read the corresponding number of bytes */
113 ret = read (pipefd2[0], &bytes, 2);
115 /* Read the bytes and output them */
116 for (i = 0; i < bytes; i++)
118 if ((i % COLS) == 0)
119 tty_gotoyx (starty + (i / COLS), 0);
120 ret = read (pipefd2[0], &message, 1);
121 tty_print_char (message);
124 /* Read the value of the mc_global.tty.console_flag */
125 ret = read (pipefd2[0], &message, 1);
128 /* --------------------------------------------------------------------------------------------- */
130 static void
131 handle_console_linux (unsigned char action)
133 char *tty_name;
134 char *mc_conssaver;
135 int status;
137 switch (action)
139 case CONSOLE_INIT:
140 /* Close old pipe ends in case it is the 2nd time we run cons.saver */
141 status = close (pipefd1[1]);
142 status = close (pipefd2[0]);
143 /* Create two pipes for communication */
144 if (!((pipe (pipefd1) == 0) && ((pipe (pipefd2)) == 0)))
146 mc_global.tty.console_flag = '\0';
147 break;
149 /* Get the console saver running */
150 cons_saver_pid = fork ();
151 if (cons_saver_pid < 0)
153 /* Cannot fork */
154 /* Delete pipes */
155 status = close (pipefd1[1]);
156 status = close (pipefd1[0]);
157 status = close (pipefd2[1]);
158 status = close (pipefd2[0]);
159 mc_global.tty.console_flag = '\0';
161 else if (cons_saver_pid > 0)
163 /* Parent */
164 /* Close the extra pipe ends */
165 status = close (pipefd1[0]);
166 status = close (pipefd2[1]);
167 /* Was the child successful? */
168 status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
169 if (!mc_global.tty.console_flag)
171 pid_t ret;
172 status = close (pipefd1[1]);
173 status = close (pipefd2[0]);
174 ret = waitpid (cons_saver_pid, &status, 0);
177 else
179 /* Child */
180 /* Close the extra pipe ends */
181 status = close (pipefd1[1]);
182 status = close (pipefd2[0]);
183 tty_name = ttyname (0);
184 /* Bind the pipe 0 to the standard input */
187 if (dup2 (pipefd1[0], 0) == -1)
188 break;
189 status = close (pipefd1[0]);
190 /* Bind the pipe 1 to the standard output */
191 if (dup2 (pipefd2[1], 1) == -1)
192 break;
194 status = close (pipefd2[1]);
195 /* Bind standard error to /dev/null */
196 status = open ("/dev/null", O_WRONLY);
197 if (dup2 (status, 2) == -1)
198 break;
199 status = close (status);
200 if (tty_name)
202 /* Exec the console save/restore handler */
203 mc_conssaver = concat_dir_and_file (SAVERDIR, "cons.saver");
204 execl (mc_conssaver, "cons.saver", tty_name, (char *) NULL);
206 /* Console is not a tty or execl() failed */
208 while (0);
209 mc_global.tty.console_flag = '\0';
210 status = write (1, &mc_global.tty.console_flag, 1);
211 _exit (3);
212 } /* if (cons_saver_pid ...) */
213 break;
215 case CONSOLE_DONE:
216 case CONSOLE_SAVE:
217 case CONSOLE_RESTORE:
218 /* Is tty console? */
219 if (!mc_global.tty.console_flag)
220 return;
221 /* Paranoid: Is the cons.saver still running? */
222 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
224 cons_saver_pid = 0;
225 mc_global.tty.console_flag = '\0';
226 return;
228 /* Send command to the console handler */
229 status = write (pipefd1[1], &action, 1);
230 if (action != CONSOLE_DONE)
232 /* Wait the console handler to do its job */
233 status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
235 if (action == CONSOLE_DONE || !mc_global.tty.console_flag)
237 /* We are done -> Let's clean up */
238 pid_t ret;
239 close (pipefd1[1]);
240 close (pipefd2[0]);
241 ret = waitpid (cons_saver_pid, &status, 0);
242 mc_global.tty.console_flag = '\0';
244 break;
248 #elif defined(__FreeBSD__)
250 /* --------------------------------------------------------------------------------------------- */
252 * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
253 * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
256 static void
257 console_init (void)
259 if (mc_global.tty.console_flag)
260 return;
262 screen_info.size = sizeof (screen_info);
263 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
264 return;
266 memset (&screen_shot, 0, sizeof (screen_shot));
267 screen_shot.xsize = screen_info.mv_csz;
268 screen_shot.ysize = screen_info.mv_rsz;
269 screen_shot.buf = g_try_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2);
270 if (screen_shot.buf != NULL)
271 mc_global.tty.console_flag = '\001';
274 /* --------------------------------------------------------------------------------------------- */
276 static void
277 set_attr (unsigned attr)
280 * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
281 * to indices for ANSI sequences (red=1, green=2, blue=4).
283 static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
284 int bc, tc;
286 tc = attr & 0xF;
287 bc = (attr >> 4) & 0xF;
289 printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
290 color_map[tc & 7], color_map[bc & 7]);
293 /* --------------------------------------------------------------------------------------------- */
295 static void
296 console_restore (void)
298 int i, last;
300 if (!mc_global.tty.console_flag)
301 return;
303 cursor_to (0, 0);
305 /* restoring all content up to cursor position */
306 last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
307 for (i = 0; i < last; ++i)
309 set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
310 putc (screen_shot.buf[i] & 0xFF, stdout);
313 /* restoring cursor color */
314 set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
316 fflush (stdout);
319 /* --------------------------------------------------------------------------------------------- */
321 static void
322 console_shutdown (void)
324 if (!mc_global.tty.console_flag)
325 return;
327 g_free (screen_shot.buf);
329 mc_global.tty.console_flag = '\0';
332 /* --------------------------------------------------------------------------------------------- */
334 static void
335 console_save (void)
337 int i;
338 scrmap_t map;
339 scrmap_t revmap;
341 if (!mc_global.tty.console_flag)
342 return;
344 /* screen_info.size is already set in console_init() */
345 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
347 console_shutdown ();
348 return;
351 /* handle console resize */
352 if (screen_info.mv_csz != screen_shot.xsize || screen_info.mv_rsz != screen_shot.ysize)
354 console_shutdown ();
355 console_init ();
358 if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1)
360 console_shutdown ();
361 return;
364 if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1)
366 console_shutdown ();
367 return;
370 for (i = 0; i < 256; i++)
372 char *p = memchr (map.scrmap, i, 256);
373 revmap.scrmap[i] = p ? p - map.scrmap : i;
376 for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++)
378 screen_shot.buf[i] =
379 (screen_shot.buf[i] & 0xff00) | (unsigned char) revmap.
380 scrmap[screen_shot.buf[i] & 0xff];
384 /* --------------------------------------------------------------------------------------------- */
386 static void
387 show_console_contents_freebsd (int starty, unsigned char begin_line, unsigned char end_line)
389 int col, line;
390 char c;
392 if (!mc_global.tty.console_flag)
393 return;
395 for (line = begin_line; line <= end_line; line++)
397 tty_gotoyx (starty + line - begin_line, 0);
398 for (col = 0; col < min (COLS, screen_info.mv_csz); col++)
400 c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
401 tty_print_char (c);
406 /* --------------------------------------------------------------------------------------------- */
408 static void
409 handle_console_freebsd (unsigned char action)
411 switch (action)
413 case CONSOLE_INIT:
414 console_init ();
415 break;
417 case CONSOLE_DONE:
418 console_shutdown ();
419 break;
421 case CONSOLE_SAVE:
422 console_save ();
423 break;
425 case CONSOLE_RESTORE:
426 console_restore ();
427 break;
430 #endif /* __FreeBSD__ */
432 /* --------------------------------------------------------------------------------------------- */
433 /*** public functions ****************************************************************************/
434 /* --------------------------------------------------------------------------------------------- */
436 void
437 show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
439 tty_set_normal_attrs ();
441 if (look_for_rxvt_extensions ())
443 show_rxvt_contents (starty, begin_line, end_line);
444 return;
446 #ifdef __linux__
447 show_console_contents_linux (starty, begin_line, end_line);
448 #elif defined (__FreeBSD__)
449 show_console_contents_freebsd (starty, begin_line, end_line);
450 #else
451 mc_global.tty.console_flag = '\0';
452 #endif
455 /* --------------------------------------------------------------------------------------------- */
457 void
458 handle_console (unsigned char action)
460 (void) action;
462 if (look_for_rxvt_extensions ())
463 return;
465 #ifdef __linux__
466 handle_console_linux (action);
467 #elif defined (__FreeBSD__)
468 handle_console_freebsd (action);
469 #endif
472 /* --------------------------------------------------------------------------------------------- */