Ticket #1730 (troubles in mcviewer with utf8)
[midnight-commander.git] / src / cons.handler.c
blob44bdd6ac3995de03f28f7bf8787e07a23778347d
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 signed char console_flag = 0;
50 #ifdef __linux__
51 int cons_saver_pid = 1;
52 #endif /* __linux__ */
54 /*** file scope macro definitions ****************************************************************/
56 #if defined(__FreeBSD__)
57 #define FD_OUT 1
58 #define cursor_to(x, y) \
59 do \
60 { \
61 printf("\x1B[%d;%df", (y) + 1, (x) + 1); \
62 fflush(stdout); \
63 } while (0)
64 #endif /* __linux__ */
66 /*** file scope type declarations ****************************************************************/
68 /*** file scope variables ************************************************************************/
70 #ifdef __linux__
71 /* The cons saver can't have a pid of 1, used to prevent bunches of
72 * #ifdef linux */
73 static int pipefd1[2] = { -1, -1 };
74 static int pipefd2[2] = { -1, -1 };
75 #elif defined(__FreeBSD__)
76 static struct scrshot screen_shot;
77 static struct vid_info screen_info;
78 #endif /* __linux__ */
80 /*** file scope functions ************************************************************************/
81 /* --------------------------------------------------------------------------------------------- */
83 #ifdef __linux__
84 static void
85 show_console_contents_linux (int starty, unsigned char begin_line, unsigned char end_line)
87 unsigned char message = 0;
88 unsigned short bytes = 0;
89 int i;
90 ssize_t ret;
92 /* Is tty console? */
93 if (!console_flag)
94 return;
95 /* Paranoid: Is the cons.saver still running? */
96 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
98 cons_saver_pid = 0;
99 console_flag = 0;
100 return;
103 /* Send command to the console handler */
104 message = CONSOLE_CONTENTS;
105 ret = write (pipefd1[1], &message, 1);
106 /* Check for outdated cons.saver */
107 ret = read (pipefd2[0], &message, 1);
108 if (message != CONSOLE_CONTENTS)
109 return;
111 /* Send the range of lines that we want */
112 ret = write (pipefd1[1], &begin_line, 1);
113 ret = write (pipefd1[1], &end_line, 1);
114 /* Read the corresponding number of bytes */
115 ret = read (pipefd2[0], &bytes, 2);
117 /* Read the bytes and output them */
118 for (i = 0; i < bytes; i++)
120 if ((i % COLS) == 0)
121 tty_gotoyx (starty + (i / COLS), 0);
122 ret = read (pipefd2[0], &message, 1);
123 tty_print_char (message);
126 /* Read the value of the console_flag */
127 ret = read (pipefd2[0], &message, 1);
130 /* --------------------------------------------------------------------------------------------- */
132 static void
133 handle_console_linux (unsigned char action)
135 char *tty_name;
136 char *mc_conssaver;
137 int status;
139 switch (action)
141 case CONSOLE_INIT:
142 /* Close old pipe ends in case it is the 2nd time we run cons.saver */
143 status = close (pipefd1[1]);
144 status = close (pipefd2[0]);
145 /* Create two pipes for communication */
146 if (!((pipe (pipefd1) == 0) && ((pipe (pipefd2)) == 0)))
148 console_flag = 0;
149 break;
151 /* Get the console saver running */
152 cons_saver_pid = fork ();
153 if (cons_saver_pid < 0)
155 /* Cannot fork */
156 /* Delete pipes */
157 status = close (pipefd1[1]);
158 status = close (pipefd1[0]);
159 status = close (pipefd2[1]);
160 status = close (pipefd2[0]);
161 console_flag = 0;
163 else if (cons_saver_pid > 0)
165 /* Parent */
166 /* Close the extra pipe ends */
167 status = close (pipefd1[0]);
168 status = close (pipefd2[1]);
169 /* Was the child successful? */
170 status = read (pipefd2[0], &console_flag, 1);
171 if (!console_flag)
173 pid_t ret;
174 status = close (pipefd1[1]);
175 status = close (pipefd2[0]);
176 ret = waitpid (cons_saver_pid, &status, 0);
179 else
181 /* Child */
182 /* Close the extra pipe ends */
183 status = close (pipefd1[1]);
184 status = close (pipefd2[0]);
185 tty_name = ttyname (0);
186 /* Bind the pipe 0 to the standard input */
189 if (dup2 (pipefd1[0], 0) == -1)
190 break;
191 status = close (pipefd1[0]);
192 /* Bind the pipe 1 to the standard output */
193 if (dup2 (pipefd2[1], 1) == -1)
194 break;
196 status = close (pipefd2[1]);
197 /* Bind standard error to /dev/null */
198 status = open ("/dev/null", O_WRONLY);
199 if (dup2 (status, 2) == -1)
200 break;
201 status = close (status);
202 if (tty_name)
204 /* Exec the console save/restore handler */
205 mc_conssaver = concat_dir_and_file (SAVERDIR, "cons.saver");
206 execl (mc_conssaver, "cons.saver", tty_name, (char *) NULL);
208 /* Console is not a tty or execl() failed */
210 while (0);
211 console_flag = 0;
212 status = write (1, &console_flag, 1);
213 _exit (3);
214 } /* if (cons_saver_pid ...) */
215 break;
217 case CONSOLE_DONE:
218 case CONSOLE_SAVE:
219 case CONSOLE_RESTORE:
220 /* Is tty console? */
221 if (!console_flag)
222 return;
223 /* Paranoid: Is the cons.saver still running? */
224 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
226 cons_saver_pid = 0;
227 console_flag = 0;
228 return;
230 /* Send command to the console handler */
231 status = write (pipefd1[1], &action, 1);
232 if (action != CONSOLE_DONE)
234 /* Wait the console handler to do its job */
235 status = read (pipefd2[0], &console_flag, 1);
237 if (action == CONSOLE_DONE || !console_flag)
239 /* We are done -> Let's clean up */
240 pid_t ret;
241 close (pipefd1[1]);
242 close (pipefd2[0]);
243 ret = waitpid (cons_saver_pid, &status, 0);
244 console_flag = 0;
246 break;
250 #elif defined(__FreeBSD__)
252 /* --------------------------------------------------------------------------------------------- */
254 * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
255 * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
258 static void
259 console_init (void)
261 if (console_flag)
262 return;
264 screen_info.size = sizeof (screen_info);
265 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
266 return;
268 memset (&screen_shot, 0, sizeof (screen_shot));
269 screen_shot.xsize = screen_info.mv_csz;
270 screen_shot.ysize = screen_info.mv_rsz;
271 screen_shot.buf = g_try_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2);
272 if (screen_shot.buf != NULL)
273 console_flag = 1;
276 /* --------------------------------------------------------------------------------------------- */
278 static void
279 set_attr (unsigned attr)
282 * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
283 * to indices for ANSI sequences (red=1, green=2, blue=4).
285 static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
286 int bc, tc;
288 tc = attr & 0xF;
289 bc = (attr >> 4) & 0xF;
291 printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
292 color_map[tc & 7], color_map[bc & 7]);
295 /* --------------------------------------------------------------------------------------------- */
297 static void
298 console_restore (void)
300 int i, last;
302 if (!console_flag)
303 return;
305 cursor_to (0, 0);
307 /* restoring all content up to cursor position */
308 last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
309 for (i = 0; i < last; ++i)
311 set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
312 putc (screen_shot.buf[i] & 0xFF, stdout);
315 /* restoring cursor color */
316 set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
318 fflush (stdout);
321 /* --------------------------------------------------------------------------------------------- */
323 static void
324 console_shutdown (void)
326 if (!console_flag)
327 return;
329 g_free (screen_shot.buf);
331 console_flag = 0;
334 /* --------------------------------------------------------------------------------------------- */
336 static void
337 console_save (void)
339 int i;
340 scrmap_t map;
341 scrmap_t revmap;
343 if (!console_flag)
344 return;
346 /* screen_info.size is already set in console_init() */
347 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
349 console_shutdown ();
350 return;
353 /* handle console resize */
354 if (screen_info.mv_csz != screen_shot.xsize || screen_info.mv_rsz != screen_shot.ysize)
356 console_shutdown ();
357 console_init ();
360 if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1)
362 console_shutdown ();
363 return;
366 if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1)
368 console_shutdown ();
369 return;
372 for (i = 0; i < 256; i++)
374 char *p = memchr (map.scrmap, i, 256);
375 revmap.scrmap[i] = p ? p - map.scrmap : i;
378 for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++)
380 screen_shot.buf[i] =
381 (screen_shot.buf[i] & 0xff00) | (unsigned char) revmap.
382 scrmap[screen_shot.buf[i] & 0xff];
386 /* --------------------------------------------------------------------------------------------- */
388 static void
389 show_console_contents_freebsd (int starty, unsigned char begin_line, unsigned char end_line)
391 int col, line;
392 char c;
394 if (!console_flag)
395 return;
397 for (line = begin_line; line <= end_line; line++)
399 tty_gotoyx (starty + line - begin_line, 0);
400 for (col = 0; col < min (COLS, screen_info.mv_csz); col++)
402 c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
403 tty_print_char (c);
408 /* --------------------------------------------------------------------------------------------- */
410 static void
411 handle_console_freebsd (unsigned char action)
413 switch (action)
415 case CONSOLE_INIT:
416 console_init ();
417 break;
419 case CONSOLE_DONE:
420 console_shutdown ();
421 break;
423 case CONSOLE_SAVE:
424 console_save ();
425 break;
427 case CONSOLE_RESTORE:
428 console_restore ();
429 break;
432 #endif /* __FreeBSD__ */
434 /* --------------------------------------------------------------------------------------------- */
435 /*** public functions ****************************************************************************/
436 /* --------------------------------------------------------------------------------------------- */
438 void
439 show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
441 tty_set_normal_attrs ();
443 if (look_for_rxvt_extensions ())
445 show_rxvt_contents (starty, begin_line, end_line);
446 return;
448 #ifdef __linux__
449 show_console_contents_linux (starty, begin_line, end_line);
450 #elif defined (__FreeBSD__)
451 show_console_contents_freebsd (starty, begin_line, end_line);
452 #else
453 console_flag = 0;
454 #endif
457 /* --------------------------------------------------------------------------------------------- */
459 void
460 handle_console (unsigned char action)
462 (void) action;
464 if (look_for_rxvt_extensions ())
465 return;
467 #ifdef __linux__
468 handle_console_linux (action);
469 #elif defined (__FreeBSD__)
470 handle_console_freebsd (action);
471 #endif
474 /* --------------------------------------------------------------------------------------------- */