Merge branch '72_preserve_attributes'
[midnight-commander.git] / src / cons.handler.c
blobac2a1b1ce3dab8536877310bab32a959a283989b
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 "global.h"
38 #include "tty.h"
39 #include "cons.saver.h"
41 signed char console_flag = 0;
43 #ifdef __linux__
45 /* The cons saver can't have a pid of 1, used to prevent bunches of
46 * #ifdef linux */
48 int cons_saver_pid = 1;
49 static int pipefd1[2] = { -1, -1 };
50 static int pipefd2[2] = { -1, -1 };
52 static void
53 show_console_contents_linux (int starty, unsigned char begin_line,
54 unsigned char end_line)
56 unsigned char message = 0;
57 unsigned short bytes = 0;
58 int i;
60 /* Is tty console? */
61 if (!console_flag)
62 return;
63 /* Paranoid: Is the cons.saver still running? */
64 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT)) {
65 cons_saver_pid = 0;
66 console_flag = 0;
67 return;
70 /* Send command to the console handler */
71 message = CONSOLE_CONTENTS;
72 write (pipefd1[1], &message, 1);
73 /* Check for outdated cons.saver */
74 read (pipefd2[0], &message, 1);
75 if (message != CONSOLE_CONTENTS)
76 return;
78 /* Send the range of lines that we want */
79 write (pipefd1[1], &begin_line, 1);
80 write (pipefd1[1], &end_line, 1);
81 /* Read the corresponding number of bytes */
82 read (pipefd2[0], &bytes, 2);
84 /* Read the bytes and output them */
85 for (i = 0; i < bytes; i++) {
86 if ((i % COLS) == 0)
87 move (starty + (i / COLS), 0);
88 read (pipefd2[0], &message, 1);
89 addch (message);
92 /* Read the value of the console_flag */
93 read (pipefd2[0], &message, 1);
96 static void
97 handle_console_linux (unsigned char action)
99 char *tty_name;
100 char *mc_conssaver;
101 int status;
103 switch (action) {
104 case CONSOLE_INIT:
105 /* Close old pipe ends in case it is the 2nd time we run cons.saver */
106 close (pipefd1[1]);
107 close (pipefd2[0]);
108 /* Create two pipes for communication */
109 pipe (pipefd1);
110 pipe (pipefd2);
111 /* Get the console saver running */
112 cons_saver_pid = fork ();
113 if (cons_saver_pid < 0) {
114 /* Cannot fork */
115 /* Delete pipes */
116 close (pipefd1[1]);
117 close (pipefd1[0]);
118 close (pipefd2[1]);
119 close (pipefd2[0]);
120 console_flag = 0;
121 } else if (cons_saver_pid > 0) {
122 /* Parent */
123 /* Close the extra pipe ends */
124 close (pipefd1[0]);
125 close (pipefd2[1]);
126 /* Was the child successful? */
127 read (pipefd2[0], &console_flag, 1);
128 if (!console_flag) {
129 close (pipefd1[1]);
130 close (pipefd2[0]);
131 waitpid (cons_saver_pid, &status, 0);
133 } else {
134 /* Child */
135 /* Close the extra pipe ends */
136 close (pipefd1[1]);
137 close (pipefd2[0]);
138 tty_name = ttyname (0);
139 /* Bind the pipe 0 to the standard input */
140 close (0);
141 dup (pipefd1[0]);
142 close (pipefd1[0]);
143 /* Bind the pipe 1 to the standard output */
144 close (1);
145 dup (pipefd2[1]);
146 close (pipefd2[1]);
147 /* Bind standard error to /dev/null */
148 close (2);
149 open ("/dev/null", O_WRONLY);
150 if (tty_name) {
151 /* Exec the console save/restore handler */
152 mc_conssaver = concat_dir_and_file (SAVERDIR, "cons.saver");
153 execl (mc_conssaver, "cons.saver", tty_name, (char *) NULL);
155 /* Console is not a tty or execl() failed */
156 console_flag = 0;
157 write (1, &console_flag, 1);
158 _exit (3);
159 } /* if (cons_saver_pid ...) */
160 break;
162 case CONSOLE_DONE:
163 case CONSOLE_SAVE:
164 case CONSOLE_RESTORE:
165 /* Is tty console? */
166 if (!console_flag)
167 return;
168 /* Paranoid: Is the cons.saver still running? */
169 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT)) {
170 cons_saver_pid = 0;
171 console_flag = 0;
172 return;
174 /* Send command to the console handler */
175 write (pipefd1[1], &action, 1);
176 if (action != CONSOLE_DONE) {
177 /* Wait the console handler to do its job */
178 read (pipefd2[0], &console_flag, 1);
180 if (action == CONSOLE_DONE || !console_flag) {
181 /* We are done -> Let's clean up */
182 close (pipefd1[1]);
183 close (pipefd2[0]);
184 waitpid (cons_saver_pid, &status, 0);
185 console_flag = 0;
187 break;
191 #elif defined(__FreeBSD__)
194 * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
195 * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
198 #define FD_OUT 1
200 static struct scrshot screen_shot;
201 static struct vid_info screen_info;
203 static void
204 console_init (void)
206 if (console_flag)
207 return;
209 screen_info.size = sizeof (screen_info);
210 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
211 return;
213 memset (&screen_shot, 0, sizeof (screen_shot));
214 screen_shot.xsize = screen_info.mv_csz;
215 screen_shot.ysize = screen_info.mv_rsz;
216 if ((screen_shot.buf =
217 g_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2)) == NULL)
218 return;
220 console_flag = 1;
223 static void
224 set_attr (unsigned attr)
227 * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
228 * to indices for ANSI sequences (red=1, green=2, blue=4).
230 static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
231 int bc, tc;
233 tc = attr & 0xF;
234 bc = (attr >> 4) & 0xF;
236 printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
237 color_map[tc & 7], color_map[bc & 7]);
240 #define cursor_to(x, y) do { \
241 printf("\x1B[%d;%df", (y) + 1, (x) + 1); \
242 fflush(stdout); \
243 } while (0)
245 static void
246 console_restore (void)
248 int i, last;
250 if (!console_flag)
251 return;
253 cursor_to (0, 0);
255 /* restoring all content up to cursor position */
256 last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
257 for (i = 0; i < last; ++i) {
258 set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
259 putc (screen_shot.buf[i] & 0xFF, stdout);
262 /* restoring cursor color */
263 set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
265 fflush (stdout);
268 static void
269 console_shutdown (void)
271 if (!console_flag)
272 return;
274 g_free (screen_shot.buf);
276 console_flag = 0;
279 static void
280 console_save (void)
282 int i;
283 scrmap_t map;
284 scrmap_t revmap;
286 if (!console_flag)
287 return;
289 /* screen_info.size is already set in console_init() */
290 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1) {
291 console_shutdown ();
292 return;
295 /* handle console resize */
296 if (screen_info.mv_csz != screen_shot.xsize
297 || screen_info.mv_rsz != screen_shot.ysize) {
298 console_shutdown ();
299 console_init ();
302 if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1) {
303 console_shutdown ();
304 return;
307 if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1) {
308 console_shutdown ();
309 return;
312 for (i = 0; i < 256; i++) {
313 char *p = memchr (map.scrmap, i, 256);
314 revmap.scrmap[i] = p ? p - map.scrmap : i;
317 for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++) {
318 screen_shot.buf[i] =
319 (screen_shot.buf[i] & 0xff00) | (unsigned char) revmap.
320 scrmap[screen_shot.buf[i] & 0xff];
324 static void
325 show_console_contents_freebsd (int starty, unsigned char begin_line,
326 unsigned char end_line)
328 int col, line;
329 char c;
331 if (!console_flag)
332 return;
334 for (line = begin_line; line <= end_line; line++) {
335 move (starty + line - begin_line, 0);
336 for (col = 0; col < min (COLS, screen_info.mv_csz); col++) {
337 c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
338 addch (c);
343 static void
344 handle_console_freebsd (unsigned char action)
346 switch (action) {
347 case CONSOLE_INIT:
348 console_init ();
349 break;
351 case CONSOLE_DONE:
352 console_shutdown ();
353 break;
355 case CONSOLE_SAVE:
356 console_save ();
357 break;
359 case CONSOLE_RESTORE:
360 console_restore ();
361 break;
364 #endif /* __FreeBSD__ */
366 void
367 show_console_contents (int starty, unsigned char begin_line,
368 unsigned char end_line)
370 standend ();
372 if (look_for_rxvt_extensions ()) {
373 show_rxvt_contents (starty, begin_line, end_line);
374 return;
376 #ifdef __linux__
377 show_console_contents_linux (starty, begin_line, end_line);
378 #elif defined (__FreeBSD__)
379 show_console_contents_freebsd (starty, begin_line, end_line);
380 #else
381 console_flag = 0;
382 #endif
385 void
386 handle_console (unsigned char action)
388 (void) action;
390 if (look_for_rxvt_extensions ())
391 return;
393 #ifdef __linux__
394 handle_console_linux (action);
395 #elif defined (__FreeBSD__)
396 handle_console_freebsd (action);
397 #endif