home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / e20313sr.zip / emacs / 20.3.1 / src / w32console.c < prev    next >
C/C++ Source or Header  |  1999-07-31  |  16KB  |  623 lines

  1. /* Terminal hooks for GNU Emacs on the Microsoft W32 API.
  2.    Copyright (C) 1992 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU Emacs.
  5.  
  6. GNU Emacs is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU Emacs is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Emacs; see the file COPYING.  If not, write to
  18. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.
  20.  
  21.    Tim Fleehart (apollo@online.com)        1-17-92
  22.    Geoff Voelker (voelker@cs.washington.edu)    9-12-93
  23. */
  24.  
  25.  
  26. #include <config.h>
  27.  
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <windows.h>
  31.  
  32. #include "lisp.h"
  33. #include "charset.h"
  34. #include "frame.h"
  35. #include "disptab.h"
  36. #include "termhooks.h"
  37. #include "w32inevt.h"
  38.  
  39. /* from window.c */
  40. extern Lisp_Object Frecenter ();
  41.  
  42. /* from keyboard.c */
  43. extern int detect_input_pending ();
  44.  
  45. /* from sysdep.c */
  46. extern int read_input_pending ();
  47.  
  48. extern FRAME_PTR updating_frame;
  49. extern int meta_key;
  50.  
  51. static void move_cursor (int row, int col);
  52. static void clear_to_end (void);
  53. static void clear_frame (void);
  54. static void clear_end_of_line (int);
  55. static void ins_del_lines (int vpos, int n);
  56. static void change_line_highlight (int, int, int);
  57. static void reassert_line_highlight (int, int);
  58. static void insert_glyphs (GLYPH *start, int len);
  59. static void write_glyphs (GLYPH *string, int len);
  60. static void delete_glyphs (int n);
  61. void w32_sys_ring_bell (void);
  62. static void reset_terminal_modes (void);
  63. static void set_terminal_modes (void);
  64. static void set_terminal_window (int size);
  65. static void update_begin (FRAME_PTR f);
  66. static void update_end (FRAME_PTR f);
  67. static int  hl_mode (int new_highlight);
  68.  
  69. COORD    cursor_coords;
  70. HANDLE    prev_screen, cur_screen;
  71. UCHAR    char_attr, char_attr_normal, char_attr_reverse;
  72. HANDLE  keyboard_handle;
  73. DWORD   prev_console_mode;
  74.  
  75. #ifndef USE_SEPARATE_SCREEN
  76. CONSOLE_CURSOR_INFO prev_console_cursor;
  77. #endif
  78.  
  79.  
  80. /* Setting this as the ctrl handler prevents emacs from being killed when
  81.    someone hits ^C in a 'suspended' session (child shell).
  82.    Also ignore Ctrl-Break signals.  */
  83.  
  84. BOOL
  85. ctrl_c_handler (unsigned long type)
  86. {
  87.   /* Only ignore "interrupt" events when running interactively.  */
  88.   return (!noninteractive
  89.       && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT));
  90. }
  91.  
  92. /* If we're updating a frame, use it as the current frame
  93.    Otherwise, use the selected frame.  */
  94. #define PICK_FRAME() (updating_frame ? updating_frame : selected_frame)
  95.  
  96. /* Move the cursor to (row, col).  */
  97. void
  98. move_cursor (int row, int col)
  99. {
  100.   cursor_coords.X = col;
  101.   cursor_coords.Y = row;
  102.   
  103.   if (updating_frame == (FRAME_PTR) NULL)
  104.     {
  105.       SetConsoleCursorPosition (cur_screen, cursor_coords);
  106.     }
  107. }
  108.  
  109. /* Clear from cursor to end of screen.  */
  110. void
  111. clear_to_end (void)
  112. {
  113.   FRAME_PTR f = PICK_FRAME ();
  114.   
  115.   clear_end_of_line (FRAME_WIDTH (f) - 1);
  116.   ins_del_lines (cursor_coords.Y, FRAME_HEIGHT (f) - cursor_coords.Y - 1);
  117. }
  118.  
  119. /* Clear the frame.  */
  120. void
  121. clear_frame (void)
  122. {
  123.   FRAME_PTR  f = PICK_FRAME ();
  124.   COORD         dest;
  125.   int        n, r;
  126.  
  127.   hl_mode (0);
  128.   
  129.   n = FRAME_HEIGHT (f) * FRAME_WIDTH (f);
  130.   dest.X = dest.Y = 0;
  131.  
  132.   FillConsoleOutputAttribute (cur_screen, char_attr, n, dest, &r);
  133.   FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
  134.  
  135.   move_cursor (0, 0);
  136. }
  137.  
  138.  
  139. static GLYPH glyph_base[256];
  140. static BOOL  ceol_initialized = FALSE;
  141.  
  142. /* Clear from Cursor to end (what's "standout marker"?).  */
  143. void
  144. clear_end_of_line (int end)
  145. {
  146.   if (!ceol_initialized)
  147.     {
  148.       int i;
  149.       for (i = 0; i < 256; i++)
  150.         {
  151.       glyph_base[i] = SPACEGLYPH;    /* empty space    */
  152.         }
  153.       ceol_initialized = TRUE;
  154.     }
  155.   write_glyphs (glyph_base, end - cursor_coords.X);    /* fencepost ?    */
  156. }
  157.  
  158. /* Insert n lines at vpos. if n is negative delete -n lines.  */
  159. void
  160. ins_del_lines (int vpos, int n)
  161. {
  162.   int         i, nb, save_highlight;
  163.   SMALL_RECT scroll;
  164.   COORD         dest;
  165.   CHAR_INFO  fill;
  166.   FRAME_PTR  f = PICK_FRAME ();
  167.  
  168.   if (n < 0)
  169.     {
  170.       scroll.Top = vpos - n;
  171.       scroll.Bottom = FRAME_HEIGHT (f);
  172.       dest.Y = vpos;
  173.     }
  174.   else
  175.     {
  176.       scroll.Top = vpos;
  177.       scroll.Bottom = FRAME_HEIGHT (f) - n;
  178.       dest.Y = vpos + n;
  179.     }
  180.   scroll.Left = 0;
  181.   scroll.Right = FRAME_WIDTH (f);
  182.   
  183.   dest.X = 0;
  184.   
  185.   save_highlight = hl_mode (0);
  186.   
  187.   fill.Char.AsciiChar = 0x20;
  188.   fill.Attributes = char_attr;
  189.   
  190.   ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
  191.  
  192.   /* Here we have to deal with a w32 console flake: If the scroll
  193.      region looks like abc and we scroll c to a and fill with d we get
  194.      cbd... if we scroll block c one line at a time to a, we get cdd...
  195.      Emacs expects cdd consistently... So we have to deal with that
  196.      here... (this also occurs scrolling the same way in the other
  197.      direction.  */
  198.  
  199.   if (n > 0)
  200.     {
  201.       if (scroll.Bottom < dest.Y)
  202.         {
  203.       for (i = scroll.Bottom; i < dest.Y; i++)
  204.             {
  205.           move_cursor (i, 0);
  206.           clear_end_of_line (FRAME_WIDTH (f));
  207.             }
  208.         }
  209.     }
  210.   else
  211.     {
  212.       nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;
  213.  
  214.       if (nb < scroll.Top)
  215.         { 
  216.       for (i = nb; i < scroll.Top; i++)
  217.             {
  218.           move_cursor (i, 0);
  219.           clear_end_of_line (FRAME_WIDTH (f));
  220.             }
  221.         }
  222.     }
  223.   
  224.   cursor_coords.X = 0;
  225.   cursor_coords.Y = vpos;
  226.   
  227.   hl_mode (save_highlight);
  228. }
  229.  
  230. /* Changes attribute to use when drawing characters to control.  */
  231. static int
  232. hl_mode (int new_highlight)
  233. {
  234.   static int highlight = 0;
  235.   int old_highlight;
  236.   
  237.   old_highlight = highlight;
  238.   highlight = (new_highlight != 0);
  239.   if (highlight)
  240.     {
  241.       char_attr = char_attr_reverse;
  242.     }
  243.   else
  244.     {
  245.       char_attr = char_attr_normal;
  246.     }
  247.   return old_highlight;
  248. }
  249.  
  250. /* Call this when about to modify line at position VPOS and change whether it
  251.    is highlighted.  */
  252. void
  253. change_line_highlight (int new_highlight, int vpos, int first_unused_hpos)
  254. {
  255.   hl_mode (new_highlight);
  256.   move_cursor (vpos, 0);
  257.   clear_end_of_line (first_unused_hpos);
  258. }
  259.  
  260. /* External interface to control of standout mode. Call this when about to
  261.  * modify line at position VPOS and not change whether it is highlighted.  */
  262. void
  263. reassert_line_highlight (int highlight, int vpos)
  264. {
  265.   hl_mode (highlight);
  266.   vpos;                /* pedantic compiler silencer */
  267. }
  268.  
  269. #undef    LEFT
  270. #undef    RIGHT
  271. #define    LEFT    1
  272. #define    RIGHT    0
  273.  
  274. void
  275. scroll_line (int dist, int direction)
  276. {
  277.   /* The idea here is to implement a horizontal scroll in one line to
  278.      implement delete and half of insert.  */
  279.   SMALL_RECT scroll;
  280.   COORD         dest;
  281.   CHAR_INFO  fill;
  282.   FRAME_PTR  f = PICK_FRAME ();
  283.   
  284.   scroll.Top = cursor_coords.Y;
  285.   scroll.Bottom = cursor_coords.Y;
  286.   
  287.   if (direction == LEFT)
  288.     {
  289.       scroll.Left = cursor_coords.X + dist;
  290.       scroll.Right = FRAME_WIDTH (f) - 1;
  291.     }
  292.   else
  293.     {
  294.       scroll.Left = cursor_coords.X;
  295.       scroll.Right = FRAME_WIDTH (f) - dist - 1;
  296.     }
  297.   
  298.   dest.X = cursor_coords.X;
  299.   dest.Y = cursor_coords.Y;
  300.   
  301.   fill.Char.AsciiChar = 0x20;
  302.   fill.Attributes = char_attr;
  303.   
  304.   ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
  305. }
  306.  
  307.  
  308. /* If start is zero insert blanks instead of a string at start ?. */
  309. void
  310. insert_glyphs (register GLYPH *start, register int len)
  311. {
  312.   scroll_line (len, RIGHT);
  313.  
  314.   /* Move len chars to the right starting at cursor_coords, fill with blanks */
  315.   if (start)
  316.     {
  317.       /* Print the first len characters of start, cursor_coords.X adjusted
  318.      by write_glyphs.  */
  319.     
  320.       write_glyphs (start, len);
  321.     }
  322.   else
  323.     {
  324.       clear_end_of_line (cursor_coords.X + len);
  325.     }
  326. }
  327.  
  328. void
  329. write_glyphs (register GLYPH *string, register int len)
  330. {
  331.   register unsigned int glyph_len = GLYPH_TABLE_LENGTH;
  332.   Lisp_Object *glyph_table = GLYPH_TABLE_BASE;
  333.   FRAME_PTR f = PICK_FRAME ();
  334.   register char *ptr;
  335.   GLYPH glyph;
  336.   WORD *attrs;
  337.   char *chars;
  338.   int i;
  339.   
  340.   if (len <= 0)
  341.     return;
  342.  
  343.   attrs = alloca (len * sizeof (*attrs));
  344.   chars = alloca (len * sizeof (*chars));
  345.   if (attrs == NULL || chars == NULL)
  346.     {
  347.       printf ("alloca failed in write_glyphs\n");
  348.       return;
  349.     }
  350.   
  351.   /* We have to deal with the glyph indirection...go over the glyph
  352.      buffer and extract the characters.  */
  353.   ptr = chars;
  354.   while (--len >= 0)
  355.     {
  356.       glyph = *string++;
  357.  
  358.       if (glyph > glyph_len)
  359.         {
  360.       *ptr++ = glyph & 0xFF;
  361.       continue;
  362.     }
  363.       GLYPH_FOLLOW_ALIASES (glyph_table, glyph_len, glyph);
  364. #ifndef HAVE_NTGUI
  365.       if (GLYPH_FACE (fixfix, glyph) != 0)
  366.     printf ("Glyph face is %d\n", GLYPH_FACE (fixfix, glyph));
  367. #endif /* !HAVE_NTGUI */
  368.       if (GLYPH_SIMPLE_P (glyph_table, glyph_len, glyph))
  369.         {
  370.       *ptr++ = glyph & 0xFF;
  371.       continue;
  372.     }
  373.       for (i = 0; i < GLYPH_LENGTH (glyph_table, glyph); i++)
  374.         {
  375.       *ptr++ = (GLYPH_STRING (glyph_table, glyph))[i];
  376.     }
  377.     }
  378.   
  379.   /* Number of characters we have in the buffer.  */
  380.   len = ptr-chars;
  381.   
  382.   /* Fill in the attributes for these characters.  */
  383.   for (i = 0; i < len; i++)
  384.     attrs[i] = char_attr;
  385.   
  386.   /* Write the attributes.  */
  387.   if (!WriteConsoleOutputAttribute (cur_screen, attrs, len, cursor_coords, &i))
  388.     {
  389.       printf ("Failed writing console attributes: %d\n", GetLastError ());
  390.       fflush (stdout);
  391.     }
  392.  
  393.   /* Write the characters.  */
  394.   if (!WriteConsoleOutputCharacter (cur_screen, chars, len, cursor_coords, &i))
  395.     {
  396.       printf ("Failed writing console characters: %d\n", GetLastError ());
  397.       fflush (stdout);
  398.     }
  399.   
  400.   cursor_coords.X += len;
  401.   move_cursor (cursor_coords.Y, cursor_coords.X);
  402. }
  403.  
  404. void
  405. delete_glyphs (int n)
  406. {
  407.   /* delete chars means scroll chars from cursor_coords.X + n to 
  408.      cursor_coords.X, anything beyond the edge of the screen should 
  409.      come out empty...  */
  410.  
  411.   scroll_line (n, LEFT);
  412. }
  413.  
  414. static unsigned int sound_type = 0xFFFFFFFF;
  415.  
  416. void
  417. w32_sys_ring_bell (void)
  418. {
  419.   if (sound_type == 0xFFFFFFFF) 
  420.       Beep (666, 100);
  421.   else
  422.       MessageBeep (sound_type);
  423. }
  424.  
  425. DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
  426.        "Set the sound generated when the bell is rung.\n\
  427. SOUND is 'asterisk, 'exclamation, 'hand, 'question, or 'ok\n\
  428. to use the corresponding system sound for the bell.\n\
  429. SOUND is nil to use the normal beep.")
  430.      (sound)
  431.      Lisp_Object sound;
  432. {
  433.   CHECK_SYMBOL (sound, 0);
  434.  
  435.   if (NILP (sound)) 
  436.       sound_type = 0xFFFFFFFF;
  437.   else if (EQ (sound, intern ("asterisk")))
  438.       sound_type = MB_ICONASTERISK;
  439.   else if (EQ (sound, intern ("exclamation"))) 
  440.       sound_type = MB_ICONEXCLAMATION;
  441.   else if (EQ (sound, intern ("hand"))) 
  442.       sound_type = MB_ICONHAND;
  443.   else if (EQ (sound, intern ("question"))) 
  444.       sound_type = MB_ICONQUESTION;
  445.   else if (EQ (sound, intern ("ok"))) 
  446.       sound_type = MB_OK;
  447.   else
  448.       sound_type = 0xFFFFFFFF;
  449.  
  450.   return sound;
  451. }
  452.    
  453. void
  454. reset_terminal_modes (void)
  455. {
  456. #ifdef USE_SEPARATE_SCREEN
  457.   SetConsoleActiveScreenBuffer (prev_screen);
  458. #else
  459.   SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
  460. #endif
  461.   SetConsoleMode (keyboard_handle, prev_console_mode);
  462. }
  463.  
  464. void
  465. set_terminal_modes (void)
  466. {
  467.   CONSOLE_CURSOR_INFO cci;
  468.  
  469.   /* make cursor big and visible (100 on Win95 makes it disappear)  */
  470.   cci.dwSize = 99;
  471.   cci.bVisible = TRUE;
  472.   (void) SetConsoleCursorInfo (cur_screen, &cci);
  473.  
  474.   SetConsoleActiveScreenBuffer (cur_screen);
  475.  
  476.   SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
  477.  
  478.   /* Initialize input mode: interrupt_input off, no flow control, allow
  479.      8 bit character input, standard quit char.  */
  480.   Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
  481. }
  482.  
  483. /* hmmm... perhaps these let us bracket screen changes so that we can flush
  484.    clumps rather than one-character-at-a-time...
  485.    
  486.    we'll start with not moving the cursor while an update is in progress.  */
  487. void
  488. update_begin (FRAME_PTR f)
  489. {
  490. }
  491.  
  492. void
  493. update_end (FRAME_PTR f)
  494. {
  495.   SetConsoleCursorPosition (cur_screen, cursor_coords);
  496. }
  497.  
  498. void
  499. set_terminal_window (int size)
  500. {
  501. }
  502.  
  503. typedef int (*term_hook) ();
  504.  
  505. void
  506. initialize_w32_display (void)
  507. {
  508.   CONSOLE_SCREEN_BUFFER_INFO    info;
  509.   
  510.   cursor_to_hook        = move_cursor;
  511.   raw_cursor_to_hook        = move_cursor;
  512.   clear_to_end_hook        = clear_to_end;
  513.   clear_frame_hook        = clear_frame;
  514.   clear_end_of_line_hook    = clear_end_of_line;
  515.   ins_del_lines_hook        = ins_del_lines;
  516.   change_line_highlight_hook    = change_line_highlight;
  517.   reassert_line_highlight_hook  = reassert_line_highlight;
  518.   insert_glyphs_hook        = insert_glyphs;
  519.   write_glyphs_hook        = write_glyphs;
  520.   delete_glyphs_hook        = delete_glyphs;
  521.   ring_bell_hook        = w32_sys_ring_bell;
  522.   reset_terminal_modes_hook    = reset_terminal_modes;
  523.   set_terminal_modes_hook    = set_terminal_modes;
  524.   set_terminal_window_hook    = set_terminal_window;
  525.   update_begin_hook        = update_begin;
  526.   update_end_hook        = update_end;
  527.   
  528.   read_socket_hook = w32_console_read_socket;
  529.   mouse_position_hook = w32_console_mouse_position;
  530.  
  531.   /* Initialize interrupt_handle.  */
  532.   init_crit ();
  533.  
  534.   /* Remember original console settings.  */
  535.   keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
  536.   GetConsoleMode (keyboard_handle, &prev_console_mode);
  537.  
  538.   prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
  539.   
  540. #ifdef USE_SEPARATE_SCREEN
  541.   cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
  542.                       0, NULL,
  543.                       CONSOLE_TEXTMODE_BUFFER,
  544.                       NULL);
  545.  
  546.   if (cur_screen == INVALID_HANDLE_VALUE)
  547.     {
  548.       printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
  549.       printf ("LastError = 0x%lx\n", GetLastError ());
  550.       fflush (stdout);
  551.       exit (0);
  552.     }
  553. #else
  554.   cur_screen = prev_screen;
  555.   GetConsoleCursorInfo (prev_screen, &prev_console_cursor);
  556. #endif
  557.  
  558.   GetConsoleScreenBufferInfo (cur_screen, &info);
  559.   
  560.   meta_key = 1;
  561.   char_attr = info.wAttributes & 0xFF;
  562.   char_attr_normal = char_attr;
  563.   char_attr_reverse = ((char_attr & 0xf) << 4) + ((char_attr & 0xf0) >> 4);
  564.   
  565.   FRAME_HEIGHT (selected_frame) = info.dwSize.Y;    /* lines per page */
  566.   SET_FRAME_WIDTH (selected_frame, info.dwSize.X); /* characters per line */
  567.   
  568. //  move_cursor (0, 0);
  569.   
  570. //  clear_frame ();
  571. }
  572.  
  573. DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
  574.        "Set screen colors.")
  575.     (foreground, background)
  576.     Lisp_Object foreground;
  577.     Lisp_Object background;
  578. {
  579.   char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);
  580.   char_attr_reverse = XFASTINT (background) + (XFASTINT (foreground) << 4);
  581.  
  582.   Frecenter (Qnil);
  583.   return Qt;
  584. }
  585.  
  586. DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
  587.        "Set cursor size.")
  588.     (size)
  589.     Lisp_Object size;
  590. {
  591.   CONSOLE_CURSOR_INFO cci;
  592.   cci.dwSize = XFASTINT (size);
  593.   cci.bVisible = TRUE;
  594.   (void) SetConsoleCursorInfo (cur_screen, &cci);
  595.   
  596.   return Qt;
  597. }
  598.  
  599. #ifndef HAVE_NTGUI
  600. void
  601. pixel_to_glyph_coords (FRAME_PTR f, int pix_x, int pix_y, int *x, int *y,
  602.               void *bounds, int noclip)
  603. {
  604.   *x = pix_x;
  605.   *y = pix_y;
  606. }
  607.  
  608. void
  609. glyph_to_pixel_coords (FRAME_PTR f, int x, int y, int *pix_x, int *pix_y)
  610. {
  611.   *pix_x = x;
  612.   *pix_y = y;
  613. }
  614. #endif /* !HAVE_NTGUI */
  615.  
  616. void
  617. syms_of_ntterm ()
  618. {
  619.   defsubr (&Sset_screen_color);
  620.   defsubr (&Sset_cursor_size);
  621.   defsubr (&Sset_message_beep);
  622. }
  623.