-/* Terminal hooks for Windows NT port of GNU Emacs.
+/* Terminal hooks for GNU Emacs on the Microsoft W32 API.
Copyright (C) 1992 Free Software Foundation, Inc.
- This file is part of GNU Emacs.
+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 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.
+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.
+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, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
Tim Fleehart (apollo@online.com) 1-17-92
Geoff Voelker (voelker@cs.washington.edu) 9-12-93
#include <windows.h>
#include "lisp.h"
+#include "charset.h"
#include "frame.h"
#include "disptab.h"
#include "termhooks.h"
-
-#include "ntinevt.h"
+#include "w32inevt.h"
/* from window.c */
extern Lisp_Object Frecenter ();
static void insert_glyphs (GLYPH *start, int len);
static void write_glyphs (GLYPH *string, int len);
static void delete_glyphs (int n);
-void nt_ring_bell (void);
+void w32_sys_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;
+DWORD prev_console_mode;
+
+#ifndef USE_SEPARATE_SCREEN
+CONSOLE_CURSOR_INFO prev_console_cursor;
+#endif
+
+/* Determine whether to make frame dimensions match the screen buffer,
+ or the current window size. The former is desirable when running
+ over telnet, while the latter is more useful when working directly at
+ the console with a large scroll-back buffer. */
+int w32_use_full_screen_buffer;
/* Setting this as the ctrl handler prevents emacs from being killed when
BOOL
ctrl_c_handler (unsigned long type)
{
- return (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT);
+ /* Only ignore "interrupt" events when running interactively. */
+ return (!noninteractive
+ && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT));
}
/* If we're updating a frame, use it as the current frame
void
clear_frame (void)
{
- SMALL_RECT scroll;
- COORD dest;
- CHAR_INFO fill;
FRAME_PTR f = PICK_FRAME ();
-
+ COORD dest;
+ int n, r;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
+
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);
+ /* Remember that the screen buffer might be wider than the window. */
+ n = FRAME_HEIGHT (f) * info.dwSize.X;
+ dest.X = dest.Y = 0;
+
+ FillConsoleOutputAttribute (cur_screen, char_attr, n, dest, &r);
+ FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
+
move_cursor (0, 0);
}
ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
- /* Here we have to deal with a win32 console flake: If the scroll
+ /* Here we have to deal with a w32 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
FRAME_PTR f = PICK_FRAME ();
register char *ptr;
GLYPH glyph;
- WORD *attrs;
char *chars;
int i;
- attrs = alloca (len * sizeof (*attrs));
+ if (len <= 0)
+ return;
+
chars = alloca (len * sizeof (*chars));
- if (attrs == NULL || chars == NULL)
+ if (chars == NULL)
{
printf ("alloca failed in write_glyphs\n");
return;
/* Number of characters we have in the buffer. */
len = ptr-chars;
- /* Fill in the attributes for these characters. */
- for (i = 0; i < len; i++)
- attrs[i] = char_attr;
-
- /* Write the attributes. */
- if (!WriteConsoleOutputAttribute (cur_screen, attrs, len, cursor_coords, &i))
+ /* Set the attribute for these characters. */
+ if (!FillConsoleOutputAttribute (cur_screen, char_attr, len, cursor_coords, &i))
{
printf ("Failed writing console attributes: %d\n", GetLastError ());
fflush (stdout);
}
static unsigned int sound_type = 0xFFFFFFFF;
+#define MB_EMACS_SILENT (0xFFFFFFFF - 1)
void
-nt_ring_bell (void)
+w32_sys_ring_bell (void)
{
if (sound_type == 0xFFFFFFFF)
+ {
Beep (666, 100);
+ }
+ else if (sound_type == MB_EMACS_SILENT)
+ {
+ /* Do nothing. */
+ }
else
- MessageBeep (sound_type);
+ MessageBeep (sound_type);
}
DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
"Set the sound generated when the bell is rung.\n\
-SOUND is 'asterisk, 'exclamation, 'hand, 'question, or 'ok\n\
-to use the corresponding system sound for the bell.\n\
+SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent\n\
+to use the corresponding system sound for the bell. The 'silent sound\n\
+prevents Emacs from making any sound at all.\n\
SOUND is nil to use the normal beep.")
(sound)
Lisp_Object sound;
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;
}
-
-/* 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 ();
+#ifdef USE_SEPARATE_SCREEN
SetConsoleActiveScreenBuffer (prev_screen);
+#else
+ SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
+#endif
+ SetConsoleMode (keyboard_handle, prev_console_mode);
}
void
{
CONSOLE_CURSOR_INFO cci;
- if (cur_screen == NULL)
- {
- reset_kbd ();
- cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
- 0, NULL,
- CONSOLE_TEXTMODE_BUFFER,
- NULL);
+ /* make cursor big and visible (100 on Win95 makes it disappear) */
+ cci.dwSize = 99;
+ cci.bVisible = TRUE;
+ (void) SetConsoleCursorInfo (cur_screen, &cci);
- 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);
- SetConsoleActiveScreenBuffer (cur_screen);
+ SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
- /* make cursor big and visible (100 on Win95 makes it disappear) */
- cci.dwSize = 99;
- cci.bVisible = TRUE;
- (void) SetConsoleCursorInfo (cur_screen, &cci);
- }
+ /* Initialize input mode: interrupt_input off, no flow control, allow
+ 8 bit character input, standard quit char. */
+ Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
}
/* hmmm... perhaps these let us bracket screen changes so that we can flush
{
}
-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)
+initialize_w32_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) nt_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;
-
+ cursor_to_hook = move_cursor;
+ raw_cursor_to_hook = move_cursor;
+ clear_to_end_hook = clear_to_end;
+ clear_frame_hook = clear_frame;
+ clear_end_of_line_hook = clear_end_of_line;
+ ins_del_lines_hook = ins_del_lines;
+ change_line_highlight_hook = change_line_highlight;
+ reassert_line_highlight_hook = reassert_line_highlight;
+ insert_glyphs_hook = insert_glyphs;
+ write_glyphs_hook = write_glyphs;
+ delete_glyphs_hook = delete_glyphs;
+ ring_bell_hook = w32_sys_ring_bell;
+ reset_terminal_modes_hook = reset_terminal_modes;
+ set_terminal_modes_hook = set_terminal_modes;
+ set_terminal_window_hook = set_terminal_window;
+ update_begin_hook = update_begin;
+ update_end_hook = update_end;
+
+ read_socket_hook = w32_console_read_socket;
+ mouse_position_hook = w32_console_mouse_position;
+
+ /* Initialize interrupt_handle. */
+ init_crit ();
+
+ /* Remember original console settings. */
+ keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
+ GetConsoleMode (keyboard_handle, &prev_console_mode);
+
prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
- set_terminal_modes ();
-
+#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
+
+ /* Respect setting of LINES and COLUMNS environment variables. */
+ {
+ 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);
+
+ /* Shrink the window first, so the buffer dimensions can be
+ reduced if necessary. */
+ 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);
+
+ /* Set the window size to match the buffer dimension. */
+ 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 = 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 ();
+
+ if (w32_use_full_screen_buffer)
+ {
+ FRAME_HEIGHT (selected_frame) = info.dwSize.Y; /* lines per page */
+ SET_FRAME_WIDTH (selected_frame, info.dwSize.X); /* characters per line */
+ }
+ else
+ {
+ /* Lines per page. Use buffer coords instead of buffer size. */
+ FRAME_HEIGHT (selected_frame) = 1 + info.srWindow.Bottom -
+ info.srWindow.Top;
+ /* Characters per line. Use buffer coords instead of buffer size. */
+ SET_FRAME_WIDTH (selected_frame, 1 + info.srWindow.Right -
+ info.srWindow.Left);
+ }
}
DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
void
syms_of_ntterm ()
{
+ DEFVAR_BOOL ("w32-use-full-screen-buffer",
+ &w32_use_full_screen_buffer,
+ "Non-nil means make terminal frames use the full screen buffer dimensions.\n\
+This is desirable when running Emacs over telnet, and is the default.\n\
+A value of nil means use the current console window dimensions; this\n\
+may be preferrable when working directly at the console with a large\n\
+scroll-back buffer.");
+ w32_use_full_screen_buffer = 1;
+
defsubr (&Sset_screen_color);
defsubr (&Sset_cursor_size);
defsubr (&Sset_message_beep);