diff options
author | Richard M. Stallman <rms@gnu.org> | 1994-11-14 01:32:24 +0000 |
---|---|---|
committer | Richard M. Stallman <rms@gnu.org> | 1994-11-14 01:32:24 +0000 |
commit | 6cdfb6e60ddaa1486ae70374e13bb5deeb40c2f0 (patch) | |
tree | ef2f9081dde6068a5eaa0fbb284c5d85a1364d0a /src/w32console.c | |
parent | dd3240b7beea10d052584206e477594351fde704 (diff) | |
download | emacs-6cdfb6e60ddaa1486ae70374e13bb5deeb40c2f0.tar.gz |
Initial revision
Diffstat (limited to 'src/w32console.c')
-rw-r--r-- | src/w32console.c | 605 |
1 files changed, 605 insertions, 0 deletions
diff --git a/src/w32console.c b/src/w32console.c new file mode 100644 index 00000000000..53e8e2cbcda --- /dev/null +++ b/src/w32console.c @@ -0,0 +1,605 @@ +/* Terminal hooks for Windows NT port of GNU Emacs. + Copyright (C) 1992 Free Software Foundation, Inc. + + This file is part of GNU Emacs. + + GNU Emacs is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any later + version. + + GNU Emacs is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along + with GNU Emacs; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + Tim Fleehart (apollo@online.com) 1-17-92 + Geoff Voelker (voelker@cs.washington.edu) 9-12-93 +*/ + + +#include <stdlib.h> +#include <stdio.h> + +#include "config.h" + +#include <windows.h> + +#include "lisp.h" +#include "frame.h" +#include "disptab.h" +#include "termhooks.h" + +#include "ntinevt.h" + +/* frrom window.c */ +extern Lisp_Object Frecenter (); + +/* from keyboard.c */ +extern int detect_input_pending (); + +/* from sysdep.c */ +extern int read_input_pending (); + +extern FRAME_PTR updating_frame; +extern int meta_key; + +static void move_cursor (int row, int col); +static void clear_to_end (void); +static void clear_frame (void); +static void clear_end_of_line (int); +static void ins_del_lines (int vpos, int n); +static void change_line_highlight (int, int, int); +static void reassert_line_highlight (int, int); +static void insert_glyphs (GLYPH *start, int len); +static void write_glyphs (GLYPH *string, int len); +static void delete_glyphs (int n); +static void ring_bell (void); +static void reset_terminal_modes (void); +static void set_terminal_modes (void); +static void set_terminal_window (int size); +static void update_begin (FRAME_PTR f); +static void update_end (FRAME_PTR f); +static void reset_kbd (void); +static void unset_kbd (void); +static int hl_mode (int new_highlight); + +void +DebPrint () +{ +} + +/* Init hook called in init_keyboard. */ +void (*keyboard_init_hook)(void) = reset_kbd; + +COORD cursor_coords; +HANDLE prev_screen, cur_screen; +UCHAR char_attr, char_attr_normal, char_attr_reverse; +HANDLE keyboard_handle; + + +/* Setting this as the ctrl handler prevents emacs from being killed when + * someone hits ^C in a 'suspended' session (child shell). */ +BOOL +ctrl_c_handler (unsigned long type) +{ + return (type == CTRL_C_EVENT) ? TRUE : FALSE; +} + +/* If we're updating a frame, use it as the current frame + Otherwise, use the selected frame. */ +#define PICK_FRAME() (updating_frame ? updating_frame : selected_frame) + +/* Move the cursor to (row, col). */ +void +move_cursor (int row, int col) +{ + cursor_coords.X = col; + cursor_coords.Y = row; + + if (updating_frame == NULL) + { + SetConsoleCursorPosition (cur_screen, cursor_coords); + } +} + +/* Clear from cursor to end of screen. */ +void +clear_to_end (void) +{ + FRAME_PTR f = PICK_FRAME (); + + clear_end_of_line (FRAME_WIDTH (f) - 1); + ins_del_lines (cursor_coords.Y, FRAME_HEIGHT (f) - cursor_coords.Y - 1); +} + +/* Clear the frame. */ +void +clear_frame (void) +{ + SMALL_RECT scroll; + COORD dest; + CHAR_INFO fill; + FRAME_PTR f = PICK_FRAME (); + + hl_mode (0); + + scroll.Top = 0; + scroll.Bottom = FRAME_HEIGHT (f) - 1; + scroll.Left = 0; + scroll.Right = FRAME_WIDTH (f) - 1; + + dest.Y = FRAME_HEIGHT (f); + dest.X = 0; + + fill.Char.AsciiChar = 0x20; + fill.Attributes = char_attr; + + ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill); + move_cursor (0, 0); +} + + +static GLYPH glyph_base[256]; +static BOOL ceol_initialized = FALSE; + +/* Clear from Cursor to end (what's "standout marker"?). */ +void +clear_end_of_line (int end) +{ + if (!ceol_initialized) + { + int i; + for (i = 0; i < 256; i++) + { + glyph_base[i] = SPACEGLYPH; /* empty space */ + } + ceol_initialized = TRUE; + } + write_glyphs (glyph_base, end - cursor_coords.X); /* fencepost ? */ +} + +/* Insert n lines at vpos. if n is negative delete -n lines. */ +void +ins_del_lines (int vpos, int n) +{ + int i, nb, save_highlight; + SMALL_RECT scroll; + COORD dest; + CHAR_INFO fill; + FRAME_PTR f = PICK_FRAME (); + + if (n < 0) + { + scroll.Top = vpos - n; + scroll.Bottom = FRAME_HEIGHT (f); + dest.Y = vpos; + } + else + { + scroll.Top = vpos; + scroll.Bottom = FRAME_HEIGHT (f) - n; + dest.Y = vpos + n; + } + scroll.Left = 0; + scroll.Right = FRAME_WIDTH (f); + + dest.X = 0; + + save_highlight = hl_mode (0); + + fill.Char.AsciiChar = 0x20; + fill.Attributes = char_attr; + + ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill); + + /* Here we have to deal with a win32 console flake: If the scroll + region looks like abc and we scroll c to a and fill with d we get + cbd... if we scroll block c one line at a time to a, we get cdd... + Emacs expects cdd consistently... So we have to deal with that + here... (this also occurs scrolling the same way in the other + direction. */ + + if (n > 0) + { + if (scroll.Bottom < dest.Y) + { + for (i = scroll.Bottom; i < dest.Y; i++) + { + move_cursor (i, 0); + clear_end_of_line (FRAME_WIDTH (f)); + } + } + } + else + { + nb = dest.Y + (scroll.Bottom - scroll.Top) + 1; + + if (nb < scroll.Top) + { + for (i = nb; i < scroll.Top; i++) + { + move_cursor (i, 0); + clear_end_of_line (FRAME_WIDTH (f)); + } + } + } + + cursor_coords.X = 0; + cursor_coords.Y = vpos; + + hl_mode (save_highlight); +} + +/* Changes attribute to use when drawing characters to control. */ +static int +hl_mode (int new_highlight) +{ + static int highlight = 0; + int old_highlight; + + old_highlight = highlight; + highlight = (new_highlight != 0); + if (highlight) + { + char_attr = char_attr_reverse; + } + else + { + char_attr = char_attr_normal; + } + return old_highlight; +} + +/* Call this when about to modify line at position VPOS and change whether it + is highlighted. */ +void +change_line_highlight (int new_highlight, int vpos, int first_unused_hpos) +{ + hl_mode (new_highlight); + move_cursor (vpos, 0); + clear_end_of_line (first_unused_hpos); +} + +/* External interface to control of standout mode. Call this when about to + * modify line at position VPOS and not change whether it is highlighted. */ +void +reassert_line_highlight (int highlight, int vpos) +{ + hl_mode (highlight); + vpos; /* pedantic compiler silencer */ +} + +#undef LEFT +#undef RIGHT +#define LEFT 1 +#define RIGHT 0 + +void +scroll_line (int dist, int direction) +{ + /* The idea here is to implement a horizontal scroll in one line to + implement delete and half of insert. */ + SMALL_RECT scroll; + COORD dest; + CHAR_INFO fill; + FRAME_PTR 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_WIDTH (f) - 1; + } + else + { + scroll.Left = cursor_coords.X; + scroll.Right = FRAME_WIDTH (f) - dist - 1; + } + + dest.X = cursor_coords.X; + dest.Y = cursor_coords.Y; + + fill.Char.AsciiChar = 0x20; + fill.Attributes = char_attr; + + ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill); +} + + +/* If start is zero insert blanks instead of a string at start ?. */ +void +insert_glyphs (register GLYPH *start, register int len) +{ + scroll_line (len, RIGHT); + + /* Move len chars to the right starting at cursor_coords, fill with blanks */ + if (start) + { + /* Print the first len characters of start, cursor_coords.X adjusted + by write_glyphs. */ + + write_glyphs (start, len); + } + else + { + clear_end_of_line (cursor_coords.X + len); + } +} + +void +write_glyphs (register GLYPH *string, register int len) +{ + register unsigned int glyph_len = GLYPH_TABLE_LENGTH; + Lisp_Object *glyph_table = GLYPH_TABLE_BASE; + FRAME_PTR f = PICK_FRAME (); + register char *ptr; + GLYPH glyph; + WORD *attrs; + char *chars; + int i; + + attrs = alloca (len * sizeof (*attrs)); + chars = alloca (len * sizeof (*chars)); + if (attrs == NULL || chars == NULL) + { + printf ("alloca failed in write_glyphs\n"); + return; + } + + /* We have to deal with the glyph indirection...go over the glyph + buffer and extract the characters. */ + ptr = chars; + while (--len >= 0) + { + glyph = *string++; + + if (glyph > glyph_len) + { + *ptr++ = glyph & 0xFF; + continue; + } + GLYPH_FOLLOW_ALIASES (glyph_table, glyph_len, glyph); + if (GLYPH_FACE (fixfix, glyph) != 0) + printf ("Glyph face is %d\n", GLYPH_FACE (fixfix, glyph)); + if (GLYPH_SIMPLE_P (glyph_table, glyph_len, glyph)) + { + *ptr++ = glyph & 0xFF; + continue; + } + for (i = 0; i < GLYPH_LENGTH (glyph_table, glyph); i++) + { + *ptr++ = (GLYPH_STRING (glyph_table, glyph))[i]; + } + } + + /* Number of characters we have in the buffer. */ + len = ptr-chars; + + /* Fill in the attributes for these characters. */ + memset (attrs, char_attr, len*sizeof (*attrs)); + + /* Write the attributes. */ + if (!WriteConsoleOutputAttribute (cur_screen, attrs, len, cursor_coords, &i)) + { + printf ("Failed writing console attributes.\n"); + fflush (stdout); + } + + /* Write the characters. */ + if (!WriteConsoleOutputCharacter (cur_screen, chars, len, cursor_coords, &i)) + { + printf ("Failed writing console characters.\n"); + fflush (stdout); + } + + cursor_coords.X += len; + move_cursor (cursor_coords.Y, cursor_coords.X); +} + +void +delete_glyphs (int n) +{ + /* delete chars means scroll chars from cursor_coords.X + n to + cursor_coords.X, anything beyond the edge of the screen should + come out empty... */ + + scroll_line (n, LEFT); +} + +void +ring_bell (void) +{ + Beep (666, 100); +} + +/* Reset to the original console mode but don't get rid of our console + For suspending emacs. */ +void +restore_console (void) +{ + unset_kbd (); + SetConsoleActiveScreenBuffer (prev_screen); +} + +/* Put our console back up, for ending a suspended session. */ +void +take_console (void) +{ + reset_kbd (); + SetConsoleActiveScreenBuffer (cur_screen); +} + +void +reset_terminal_modes (void) +{ + unset_kbd (); + SetConsoleActiveScreenBuffer (prev_screen); + CloseHandle (cur_screen); + cur_screen = NULL; +} + +void +set_terminal_modes (void) +{ + CONSOLE_CURSOR_INFO cci; + + if (cur_screen == NULL) + { + reset_kbd (); + 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); + } + + SetConsoleActiveScreenBuffer (cur_screen); + + /* make cursor big and visible */ + cci.dwSize = 100; + cci.bVisible = TRUE; + (void) SetConsoleCursorInfo (cur_screen, &cci); + } +} + +/* hmmm... perhaps these let us bracket screen changes so that we can flush + clumps rather than one-character-at-a-time... + + we'll start with not moving the cursor while an update is in progress. */ +void +update_begin (FRAME_PTR f) +{ +} + +void +update_end (FRAME_PTR f) +{ + SetConsoleCursorPosition (cur_screen, cursor_coords); +} + +void +set_terminal_window (int size) +{ +} + +void +unset_kbd (void) +{ + SetConsoleMode (keyboard_handle, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | + ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT); +} + +void +reset_kbd (void) +{ + keyboard_handle = GetStdHandle (STD_INPUT_HANDLE); + SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT); +} + +typedef int (*term_hook) (); + +void +initialize_win_nt_display (void) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + + cursor_to_hook = (term_hook) move_cursor; + raw_cursor_to_hook = (term_hook) move_cursor; + clear_to_end_hook = (term_hook) clear_to_end; + clear_frame_hook = (term_hook) clear_frame; + clear_end_of_line_hook = (term_hook) clear_end_of_line; + ins_del_lines_hook = (term_hook) ins_del_lines; + change_line_highlight_hook = (term_hook) change_line_highlight; + reassert_line_highlight_hook = (term_hook) reassert_line_highlight; + insert_glyphs_hook = (term_hook) insert_glyphs; + write_glyphs_hook = (term_hook) write_glyphs; + delete_glyphs_hook = (term_hook) delete_glyphs; + ring_bell_hook = (term_hook) ring_bell; + reset_terminal_modes_hook = (term_hook) reset_terminal_modes; + set_terminal_modes_hook = (term_hook) set_terminal_modes; + set_terminal_window_hook = (term_hook) set_terminal_window; + update_begin_hook = (term_hook) update_begin; + update_end_hook = (term_hook) update_end; + + read_socket_hook = win32_read_socket; + mouse_position_hook = win32_mouse_position; + + prev_screen = GetStdHandle (STD_OUTPUT_HANDLE); + + set_terminal_modes (); + + GetConsoleScreenBufferInfo (cur_screen, &info); + + meta_key = 1; + char_attr = info.wAttributes & 0xFF; + char_attr_normal = char_attr; + char_attr_reverse = ((char_attr & 0xf) << 4) + ((char_attr & 0xf0) >> 4); + + FRAME_HEIGHT (selected_frame) = info.dwSize.Y; /* lines per page */ + FRAME_WIDTH (selected_frame) = info.dwSize.X; /* characters per line */ + + move_cursor (0, 0); + + clear_frame (); +} + +DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0, + "Set screen colors.") + (foreground, background) + Lisp_Object foreground; + Lisp_Object background; +{ + char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4); + char_attr_reverse = XFASTINT (background) + (XFASTINT (foreground) << 4); + + Frecenter (Qnil); + return Qt; +} + +DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0, + "Set cursor size.") + (size) + Lisp_Object size; +{ + CONSOLE_CURSOR_INFO cci; + cci.dwSize = XFASTINT (size); + cci.bVisible = TRUE; + (void) SetConsoleCursorInfo (cur_screen, &cci); + + return Qt; +} + +void +pixel_to_glyph_coords (FRAME_PTR f, int pix_x, int pix_y, int *x, int *y, + void *bounds, int noclip) +{ + *x = pix_x; + *y = pix_y; +} + +void +glyph_to_pixel_coords (FRAME_PTR f, int x, int y, int *pix_x, int *pix_y) +{ + *pix_x = x; + *pix_y = y; +} + +_VOID_ +syms_of_ntterm () +{ + defsubr (&Sset_screen_color); + defsubr (&Sset_cursor_size); +} |