(text-mode): Contruct paragraph-start so
[bpt/emacs.git] / src / w32console.c
index f7dc3ab..6b7331f 100644 (file)
@@ -1,21 +1,22 @@
-/* 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 ();
@@ -57,28 +58,29 @@ 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);
-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
@@ -88,7 +90,9 @@ HANDLE  keyboard_handle;
 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
@@ -122,25 +126,22 @@ clear_to_end (void)
 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);
 }
 
@@ -198,7 +199,7 @@ ins_del_lines (int vpos, int n)
   
   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
@@ -342,13 +343,14 @@ write_glyphs (register GLYPH *string, register int len)
   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;
@@ -385,12 +387,8 @@ write_glyphs (register GLYPH *string, register int len)
   /* 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);
@@ -418,20 +416,28 @@ delete_glyphs (int n)
 }
 
 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;
@@ -450,25 +456,23 @@ SOUND is nil to use the normal beep.")
       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
@@ -476,29 +480,18 @@ 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);
+  /* 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
@@ -521,65 +514,116 @@ 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)
+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,
@@ -628,6 +672,15 @@ glyph_to_pixel_coords (FRAME_PTR f, int x, int y, int *pix_x, int *pix_y)
 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);