#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include "lisp.h"
#include "charset.h"
#include "coding.h"
#include "disptab.h"
#include "termhooks.h"
#include "dispextern.h"
#undef HAVE_WINDOW_SYSTEM
#include "frame.h"
#include "w32inevt.h"
extern Lisp_Object Frecenter ();
extern int detect_input_pending ();
extern int read_input_pending ();
extern struct frame * updating_frame;
extern int meta_key;
static void w32con_move_cursor (int row, int col);
static void w32con_clear_to_end (void);
static void w32con_clear_frame (void);
static void w32con_clear_end_of_line (int);
static void w32con_ins_del_lines (int vpos, int n);
static void w32con_insert_glyphs (struct glyph *start, int len);
static void w32con_write_glyphs (struct glyph *string, int len);
static void w32con_delete_glyphs (int n);
void w32_sys_ring_bell (void);
static void w32con_reset_terminal_modes (void);
static void w32con_set_terminal_modes (void);
static void w32con_set_terminal_window (int size);
static void w32con_update_begin (struct frame * f);
static void w32con_update_end (struct frame * f);
static WORD w32_face_attributes (struct frame *f, int face_id);
static COORD cursor_coords;
static HANDLE prev_screen, cur_screen;
static WORD char_attr_normal;
static DWORD prev_console_mode;
#ifndef USE_SEPARATE_SCREEN
static CONSOLE_CURSOR_INFO prev_console_cursor;
#endif
int w32_use_full_screen_buffer;
HANDLE keyboard_handle;
BOOL
ctrl_c_handler (unsigned long type)
{
return (!noninteractive
&& (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT));
}
#define PICK_FRAME() (updating_frame ? updating_frame : SELECTED_FRAME ())
static void
w32con_move_cursor (int row, int col)
{
cursor_coords.X = col;
cursor_coords.Y = row;
if (updating_frame == (struct frame *) NULL)
{
SetConsoleCursorPosition (cur_screen, cursor_coords);
}
}
static void
w32con_clear_to_end (void)
{
struct frame * f = PICK_FRAME ();
w32con_clear_end_of_line (FRAME_COLS (f) - 1);
w32con_ins_del_lines (cursor_coords.Y, FRAME_LINES (f) - cursor_coords.Y - 1);
}
static void
w32con_clear_frame (void)
{
struct frame * f = PICK_FRAME ();
COORD dest;
int n;
DWORD r;
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
n = FRAME_LINES (f) * info.dwSize.X;
dest.X = dest.Y = 0;
FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
w32con_move_cursor (0, 0);
}
static struct glyph glyph_base[256];
static BOOL ceol_initialized = FALSE;
static void
w32con_clear_end_of_line (int end)
{
if (!ceol_initialized)
{
int i;
for (i = 0; i < 256; i++)
{
memcpy (&glyph_base[i], &space_glyph, sizeof (struct glyph));
}
ceol_initialized = TRUE;
}
w32con_write_glyphs (glyph_base, end - cursor_coords.X);
}
static void
w32con_ins_del_lines (int vpos, int n)
{
int i, nb;
SMALL_RECT scroll;
COORD dest;
CHAR_INFO fill;
struct frame * f = PICK_FRAME ();
if (n < 0)
{
scroll.Top = vpos - n;
scroll.Bottom = FRAME_LINES (f);
dest.Y = vpos;
}
else
{
scroll.Top = vpos;
scroll.Bottom = FRAME_LINES (f) - n;
dest.Y = vpos + n;
}
scroll.Left = 0;
scroll.Right = FRAME_COLS (f);
dest.X = 0;
fill.Char.AsciiChar = 0x20;
fill.Attributes = char_attr_normal;
ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
if (n > 0)
{
if (scroll.Bottom < dest.Y)
{
for (i = scroll.Bottom; i < dest.Y; i++)
{
w32con_move_cursor (i, 0);
w32con_clear_end_of_line (FRAME_COLS (f));
}
}
}
else
{
nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;
if (nb < scroll.Top)
{
for (i = nb; i < scroll.Top; i++)
{
w32con_move_cursor (i, 0);
w32con_clear_end_of_line (FRAME_COLS (f));
}
}
}
cursor_coords.X = 0;
cursor_coords.Y = vpos;
}
#undef LEFT
#undef RIGHT
#define LEFT 1
#define RIGHT 0
static void
scroll_line (int dist, int direction)
{
SMALL_RECT scroll;
COORD dest;
CHAR_INFO fill;
struct frame * f = PICK_FRAME ();
scroll.Top = cursor_coords.Y;
scroll.Bottom = cursor_coords.Y;
if (direction == LEFT)
{
scroll.Left = cursor_coords.X + dist;
scroll.Right = FRAME_COLS (f) - 1;
}
else
{
scroll.Left = cursor_coords.X;
scroll.Right = FRAME_COLS (f) - dist - 1;
}
dest.X = cursor_coords.X;
dest.Y = cursor_coords.Y;
fill.Char.AsciiChar = 0x20;
fill.Attributes = char_attr_normal;
ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
}
static void
w32con_insert_glyphs (register struct glyph *start, register int len)
{
scroll_line (len, RIGHT);
if (start)
{
w32con_write_glyphs (start, len);
}
else
{
w32con_clear_end_of_line (cursor_coords.X + len);
}
}
extern unsigned char *encode_terminal_code P_ ((struct glyph *, int,
struct coding_system *));
static void
w32con_write_glyphs (register struct glyph *string, register int len)
{
int produced, consumed;
DWORD r;
struct frame * f = PICK_FRAME ();
WORD char_attr;
unsigned char *conversion_buffer;
struct coding_system *coding;
if (len <= 0)
return;
coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
? &terminal_coding : &safe_terminal_coding);
terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
while (len > 0)
{
int face_id = string->face_id;
int n;
for (n = 1; n < len; ++n)
if (string[n].face_id != face_id)
break;
char_attr = w32_face_attributes (f, face_id);
if (n == len)
coding->mode |= CODING_MODE_LAST_BLOCK;
conversion_buffer = encode_terminal_code (string, n, coding);
if (coding->produced > 0)
{
if (!FillConsoleOutputAttribute (cur_screen, char_attr,
coding->produced, cursor_coords,
&r))
{
printf ("Failed writing console attributes: %d\n",
GetLastError ());
fflush (stdout);
}
if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
coding->produced, cursor_coords,
&r))
{
printf ("Failed writing console characters: %d\n",
GetLastError ());
fflush (stdout);
}
cursor_coords.X += coding->produced;
w32con_move_cursor (cursor_coords.Y, cursor_coords.X);
}
len -= n;
string += n;
}
}
static void
w32con_delete_glyphs (int n)
{
scroll_line (n, LEFT);
}
static unsigned int sound_type = 0xFFFFFFFF;
#define MB_EMACS_SILENT (0xFFFFFFFF - 1)
void
w32_sys_ring_bell (void)
{
if (sound_type == 0xFFFFFFFF)
{
Beep (666, 100);
}
else if (sound_type == MB_EMACS_SILENT)
{
}
else
MessageBeep (sound_type);
}
DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
doc: )
(sound)
Lisp_Object sound;
{
CHECK_SYMBOL (sound);
if (NILP (sound))
sound_type = 0xFFFFFFFF;
else if (EQ (sound, intern ("asterisk")))
sound_type = MB_ICONASTERISK;
else if (EQ (sound, intern ("exclamation")))
sound_type = MB_ICONEXCLAMATION;
else if (EQ (sound, intern ("hand")))
sound_type = MB_ICONHAND;
else if (EQ (sound, intern ("question")))
sound_type = MB_ICONQUESTION;
else if (EQ (sound, intern ("ok")))
sound_type = MB_OK;
else if (EQ (sound, intern ("silent")))
sound_type = MB_EMACS_SILENT;
else
sound_type = 0xFFFFFFFF;
return sound;
}
static void
w32con_reset_terminal_modes (void)
{
#ifdef USE_SEPARATE_SCREEN
SetConsoleActiveScreenBuffer (prev_screen);
#else
SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
#endif
SetConsoleMode (keyboard_handle, prev_console_mode);
}
static void
w32con_set_terminal_modes (void)
{
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 99;
cci.bVisible = TRUE;
(void) SetConsoleCursorInfo (cur_screen, &cci);
SetConsoleActiveScreenBuffer (cur_screen);
SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
}
static void
w32con_update_begin (struct frame * f)
{
}
static void
w32con_update_end (struct frame * f)
{
SetConsoleCursorPosition (cur_screen, cursor_coords);
}
static void
w32con_set_terminal_window (int size)
{
}
static WORD
w32_face_attributes (f, face_id)
struct frame *f;
int face_id;
{
WORD char_attr;
struct face *face = FACE_FROM_ID (f, face_id);
xassert (face != NULL);
char_attr = char_attr_normal;
if (face->foreground != FACE_TTY_DEFAULT_FG_COLOR
&& face->foreground != FACE_TTY_DEFAULT_COLOR)
char_attr = (char_attr & 0xfff0) + (face->foreground % 16);
if (face->background != FACE_TTY_DEFAULT_BG_COLOR
&& face->background != FACE_TTY_DEFAULT_COLOR)
char_attr = (char_attr & 0xff0f) + ((face->background % 16) << 4);
if (((char_attr & 0x00f0) >> 4) == (char_attr & 0x000f))
char_attr ^= 0x0007;
if (face->tty_reverse_p)
char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
+ ((char_attr & 0x00f0) >> 4);
return char_attr;
}
extern char unspecified_fg[], unspecified_bg[];
Lisp_Object
vga_stdcolor_name (int idx)
{
static char *vga_colors[16] = {
"black", "blue", "green", "cyan", "red", "magenta", "brown",
"lightgray", "darkgray", "lightblue", "lightgreen", "lightcyan",
"lightred", "lightmagenta", "yellow", "white"
};
extern Lisp_Object Qunspecified;
if (idx >= 0 && idx < sizeof (vga_colors) / sizeof (vga_colors[0]))
return build_string (vga_colors[idx]);
else
return Qunspecified;
}
typedef int (*term_hook) ();
void
initialize_w32_display (void)
{
CONSOLE_SCREEN_BUFFER_INFO info;
cursor_to_hook = w32con_move_cursor;
raw_cursor_to_hook = w32con_move_cursor;
clear_to_end_hook = w32con_clear_to_end;
clear_frame_hook = w32con_clear_frame;
clear_end_of_line_hook = w32con_clear_end_of_line;
ins_del_lines_hook = w32con_ins_del_lines;
insert_glyphs_hook = w32con_insert_glyphs;
write_glyphs_hook = w32con_write_glyphs;
delete_glyphs_hook = w32con_delete_glyphs;
ring_bell_hook = w32_sys_ring_bell;
reset_terminal_modes_hook = w32con_reset_terminal_modes;
set_terminal_modes_hook = w32con_set_terminal_modes;
set_terminal_window_hook = w32con_set_terminal_window;
update_begin_hook = w32con_update_begin;
update_end_hook = w32con_update_end;
read_socket_hook = w32_console_read_socket;
mouse_position_hook = w32_console_mouse_position;
init_crit ();
keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
GetConsoleMode (keyboard_handle, &prev_console_mode);
prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
#ifdef USE_SEPARATE_SCREEN
cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
0, NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL);
if (cur_screen == INVALID_HANDLE_VALUE)
{
printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
printf ("LastError = 0x%lx\n", GetLastError ());
fflush (stdout);
exit (0);
}
#else
cur_screen = prev_screen;
GetConsoleCursorInfo (prev_screen, &prev_console_cursor);
#endif
{
char * lines = getenv("LINES");
char * columns = getenv("COLUMNS");
if (lines != NULL && columns != NULL)
{
SMALL_RECT new_win_dims;
COORD new_size;
new_size.X = atoi (columns);
new_size.Y = atoi (lines);
GetConsoleScreenBufferInfo (cur_screen, &info);
new_win_dims.Top = 0;
new_win_dims.Left = 0;
new_win_dims.Bottom = min (new_size.Y, info.dwSize.Y) - 1;
new_win_dims.Right = min (new_size.X, info.dwSize.X) - 1;
SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
SetConsoleScreenBufferSize (cur_screen, new_size);
new_win_dims.Top = 0;
new_win_dims.Left = 0;
new_win_dims.Bottom = new_size.Y - 1;
new_win_dims.Right = new_size.X - 1;
SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
}
}
GetConsoleScreenBufferInfo (cur_screen, &info);
meta_key = 1;
char_attr_normal = info.wAttributes;
if ((w32_use_full_screen_buffer
&& (info.dwSize.Y < 20 || info.dwSize.Y > 100
|| info.dwSize.X < 40 || info.dwSize.X > 200))
|| (!w32_use_full_screen_buffer
&& (info.srWindow.Bottom - info.srWindow.Top < 20
|| info.srWindow.Bottom - info.srWindow.Top > 100
|| info.srWindow.Right - info.srWindow.Left < 40
|| info.srWindow.Right - info.srWindow.Left > 100)))
{
FRAME_LINES (SELECTED_FRAME ()) = 25;
SET_FRAME_COLS (SELECTED_FRAME (), 80);
}
else if (w32_use_full_screen_buffer)
{
FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y;
SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X);
}
else
{
FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
info.srWindow.Top;
SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right -
info.srWindow.Left);
}
w32_initialize_display_info (build_string ("Console"));
}
DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
doc: )
(foreground, background)
Lisp_Object foreground;
Lisp_Object background;
{
char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);
Frecenter (Qnil);
return Qt;
}
DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
doc: )
(size)
Lisp_Object size;
{
CONSOLE_CURSOR_INFO cci;
cci.dwSize = XFASTINT (size);
cci.bVisible = TRUE;
(void) SetConsoleCursorInfo (cur_screen, &cci);
return Qt;
}
void
syms_of_ntterm ()
{
DEFVAR_BOOL ("w32-use-full-screen-buffer",
&w32_use_full_screen_buffer,
doc: );
w32_use_full_screen_buffer = 0;
defsubr (&Sset_screen_color);
defsubr (&Sset_cursor_size);
defsubr (&Sset_message_beep);
}