]> code.delx.au - gnu-emacs/blobdiff - src/msdos.c
(substitute-key-definition): Fix previous change.
[gnu-emacs] / src / msdos.c
index 89925cc7e36d096a5e924008526569257e254e55..94b75a5efc30c8920c9b3eabdbcbe8ef90bac1a9 100644 (file)
@@ -33,10 +33,16 @@ Boston, MA 02111-1307, USA.  */
 #include <sys/time.h>
 #include <dos.h>
 #include <errno.h>
+#include <string.h>     /* for bzero and string functions */
 #include <sys/stat.h>    /* for _fixpath */
+#include <unistd.h>     /* for chdir, dup, dup2, etc. */
 #if __DJGPP__ >= 2
 #include <fcntl.h>
+#include <io.h>                 /* for setmode */
+#include <dpmi.h>       /* for __dpmi_xxx stuff */
+#include <sys/farptr.h>         /* for _farsetsel, _farnspokeb */
 #include <libc/dosio.h>  /* for _USE_LFN */
+#include <conio.h>      /* for cputs */
 #endif
 
 #include "dosfns.h"
@@ -47,6 +53,8 @@ Boston, MA 02111-1307, USA.  */
 #include "termopts.h"
 #include "frame.h"
 #include "window.h"
+#include "buffer.h"
+#include "commands.h"
 #include <go32.h>
 #include <pc.h>
 #include <ctype.h>
@@ -58,9 +66,14 @@ Boston, MA 02111-1307, USA.  */
 #define _USE_LFN 0
 #endif
 
+#ifndef _dos_ds
+#define _dos_ds _go32_info_block.selector_for_linear_memory
+#endif
+
 #if __DJGPP__ > 1
 
 #include <signal.h>
+#include "syssignal.h"
 
 #ifndef SYSTEM_MALLOC
 
@@ -294,11 +307,6 @@ struct x_output the_only_x_display;
 /* This is never dereferenced.  */
 Display *x_current_display;
 
-
-#define SCREEN_SET_CURSOR()                                            \
-  if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y)        \
-    ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
-
 static
 dos_direct_output (y, x, buf, len)
      int y;
@@ -307,11 +315,17 @@ dos_direct_output (y, x, buf, len)
      int len;
 {
   int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
-  
+
+#if (__DJGPP__ < 2)
   while (--len >= 0) {
     dosmemput (buf++, 1, t);
     t += 2;
   }
+#else
+  /* This is faster.  */
+  for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
+    _farnspokeb (t, *buf);
+#endif
 }
 #endif
 
@@ -365,17 +379,39 @@ ScreenVisualBell (void)
 
 #ifndef HAVE_X_WINDOWS
 
+static int blink_bit = -1;     /* the state of the blink bit at startup */
+
 /* Enable bright background colors.  */
 static void
 bright_bg (void)
 {
   union REGS regs;
 
+  /* Remember the original state of the blink/bright-background bit.
+     It is stored at 0040:0065h in the BIOS data area.  */
+  if (blink_bit == -1)
+    blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
+
   regs.h.bl = 0;
   regs.x.ax = 0x1003;
   int86 (0x10, &regs, &regs);
 }
 
+/* Disable bright background colors (and enable blinking) if we found
+   the video system in that state at startup.  */
+static void
+maybe_enable_blinking (void)
+{
+  if (blink_bit == 1)
+    {
+      union REGS regs;
+
+      regs.h.bl = 1;
+      regs.x.ax = 0x1003;
+      int86 (0x10, &regs, &regs);
+    }
+}
+
 /* Set the screen dimensions so that it can show no less than
    ROWS x COLS frame.  */
 
@@ -647,6 +683,75 @@ IT_cursor_to (int y, int x)
   new_pos_Y = y;
 }
 
+static int cursor_cleared;
+
+static
+IT_display_cursor (int on)
+{
+  if (on && cursor_cleared)
+    {
+      ScreenSetCursor (current_pos_Y, current_pos_X);
+      cursor_cleared = 0;
+    }
+  else if (!on && !cursor_cleared)
+    {
+      ScreenSetCursor (-1, -1);
+      cursor_cleared = 1;
+    }
+}
+
+/* Emacs calls cursor-movement functions a lot when it updates the
+   display (probably a legacy of old terminals where you cannot
+   update a screen line without first moving the cursor there).
+   However, cursor movement is expensive on MSDOS (it calls a slow
+   BIOS function and requires 2 mode switches), while actual screen
+   updates access the video memory directly and don't depend on
+   cursor position.  To avoid slowing down the redisplay, we cheat:
+   all functions that move the cursor only set internal variables
+   which record the cursor position, whereas the cursor is only
+   moved to its final position whenever screen update is complete.
+
+   `IT_cmgoto' is called from the keyboard reading loop and when the
+   frame update is complete.  This means that we are ready for user
+   input, so we update the cursor position to show where the point is,
+   and also make the mouse pointer visible.
+
+   Special treatment is required when the cursor is in the echo area,
+   to put the cursor at the end of the text displayed there.  */
+
+static
+IT_cmgoto (f)
+     FRAME_PTR f;
+{
+  /* Only set the cursor to where it should be if the display is
+     already in sync with the window contents.  */
+  int update_cursor_pos = MODIFF == unchanged_modified;
+
+  /* If we are in the echo area, put the cursor at the end of text.  */
+  if (!update_cursor_pos
+      && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
+    {
+      new_pos_X = FRAME_DESIRED_GLYPHS (f)->used[new_pos_Y];
+      update_cursor_pos = 1;
+    }
+
+  if (update_cursor_pos
+      && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
+    {
+      ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
+      if (termscript)
+       fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
+    }
+
+  /* Maybe cursor is invisible, so make it visible.  */
+  IT_display_cursor (1);
+
+  /* Mouse pointer should be always visible if we are waiting for
+     keyboard input.  */
+  if (!mouse_visible)
+    mouse_on ();
+}
+
 static
 IT_reassert_line_highlight (new, vpos)
      int new, vpos;
@@ -738,10 +843,6 @@ x_set_menu_bar_lines (f, value, oldval)
 static
 IT_set_terminal_modes (void)
 {
-  char *colors;
-  FRAME_PTR f;
-  struct face *fp;
-
   if (termscript)
     fprintf (termscript, "\n<SET_TERM>");
   highlight = 0;
@@ -795,6 +896,10 @@ IT_reset_terminal_modes (void)
     return;
   
   mouse_off ();
+
+  /* Leave the video system in the same state as we found it,
+     as far as the blink/bright-background bit is concerned.  */
+  maybe_enable_blinking ();
  
   /* We have a situation here.
      We cannot just do ScreenUpdate(startup_screen_buffer) because
@@ -869,7 +974,7 @@ IT_set_frame_parameters (f, alist)
              FRAME_FOREGROUND_PIXEL (f) = new_color;
              redraw = 1;
              if (termscript)
-               fprintf (termscript, "<FGCOLOR %d>\n", new_color);
+               fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
            }
        }
       else if (EQ (prop, intern ("background-color")))
@@ -880,7 +985,7 @@ IT_set_frame_parameters (f, alist)
              FRAME_BACKGROUND_PIXEL (f) = new_color;
              redraw = 1;
              if (termscript)
-               fprintf (termscript, "<BGCOLOR %d>\n", new_color);
+               fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
            }
        }
       else if (EQ (prop, intern ("menu-bar-lines")))
@@ -889,12 +994,17 @@ IT_set_frame_parameters (f, alist)
 
   if (redraw)
     {
+      extern void recompute_basic_faces (FRAME_PTR);
+      extern void redraw_frame (FRAME_PTR);
+
       recompute_basic_faces (f);
       if (f == selected_frame)
        redraw_frame (f);
     }
 }
 
+extern void init_frame_faces (FRAME_PTR);
+
 #endif /* !HAVE_X_WINDOWS */
 
 
@@ -963,6 +1073,7 @@ internal_terminal_init ()
   update_begin_hook = IT_update_begin;
   update_end_hook = IT_update_end;
   reassert_line_highlight_hook = IT_reassert_line_highlight;
+  frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
 
   /* These hooks are called by term.c without being checked.  */
   set_terminal_modes_hook = IT_set_terminal_modes;
@@ -1062,6 +1173,7 @@ static struct keyboard_layout_list
 
 static struct dos_keyboard_map *keyboard;
 static int keyboard_map_all;
+static int international_keyboard;
 
 int
 dos_set_keyboard (code, always)
@@ -1069,6 +1181,13 @@ dos_set_keyboard (code, always)
      int always;
 {
   int i;
+  union REGS regs;
+
+  /* See if Keyb.Com is installed (for international keyboard support).  */
+  regs.x.ax = 0xad80;
+  int86 (0x2f, &regs, &regs);
+  if (regs.h.al == 0xff)
+    international_keyboard = 1;
 
   /* Initialize to US settings, for countries that don't have their own.  */
   keyboard = keyboard_layout_list[0].keyboard_map;
@@ -1376,6 +1495,13 @@ dos_get_modifiers (keymask)
              mask |= SUPER_P;
              modifiers |= super_modifier;
            }
+         else if (!international_keyboard)
+           {
+             /* If Keyb.Com is NOT installed, let Right Alt behave
+                like the Left Alt.  */
+             mask &= ~ALT_GR_P;
+             mask |= ALT_P;
+           }
        }
       
       if (regs.h.ah & 1)               /* Left CTRL pressed ? */
@@ -1441,6 +1567,8 @@ and then the scan code.")
 
 /* Get a char from keyboard.  Function keys are put into the event queue.  */
 
+extern void kbd_buffer_store_event (struct input_event *);
+
 static int
 dos_rawgetc ()
 {
@@ -1448,10 +1576,10 @@ dos_rawgetc ()
   union REGS regs;
   
 #ifndef HAVE_X_WINDOWS
-  SCREEN_SET_CURSOR ();
-  if (!mouse_visible) mouse_on ();
+  /* Maybe put the cursor where it should be.  */
+  IT_cmgoto (selected_frame);
 #endif
-    
+
   /* The following condition is equivalent to `kbhit ()', except that
      it uses the bios to do its job.  This pleases DESQview/X.  */
   while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
@@ -1518,7 +1646,19 @@ dos_rawgetc ()
       
       if (c == 0)
        {
-         if (code & Alt)
+        /* We only look at the keyboard Ctrl/Shift/Alt keys when
+           Emacs is ready to read a key.  Therefore, if they press
+           `Alt-x' when Emacs is busy, by the time we get to
+           `dos_get_modifiers', they might have already released the
+           Alt key, and Emacs gets just `x', which is BAD.
+           However, for keys with the `Map' property set, the ASCII
+           code returns zero iff Alt is pressed.  So, when we DON'T
+           have to support international_keyboard, we don't have to
+           distinguish between the left and  right Alt keys, and we
+           can set the META modifier for any keys with the `Map'
+           property if they return zero ASCII code (c = 0).  */
+        if ( (code & Alt)
+             || ( (code & 0xf000) == Map && !international_keyboard))
            modifiers |= meta_modifier;
          if (code & Ctrl)
            modifiers |= ctrl_modifier;
@@ -1994,6 +2134,12 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
   /* Just in case we got here without a mouse present...  */
   if (have_mouse <= 0)
     return XM_IA_SELECT;
+  /* Don't allow non-positive x0 and y0, lest the menu will wrap
+     around the display.  */
+  if (x0 <= 0)
+    x0 = 1;
+  if (y0 <= 0)
+    y0 = 1;
 
   state = alloca (menu->panecount * sizeof (struct IT_menu_state));
   screensize = screen_size * 2;
@@ -2036,6 +2182,10 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
   mouse_off ();
   ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
 
+  /* Turn off the cursor.  Otherwise it shows through the menu
+     panes, which is ugly.  */
+  IT_display_cursor (0);
+
   IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
   if (buffers_num_deleted)
     menu->text[0][7] = ' ';
@@ -2123,6 +2273,7 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
   ScreenUpdate (state[0].screen_behind);
   while (statecount--)
     xfree (state[statecount].screen_behind);
+  IT_display_cursor (1);       /* turn cursor back on */
   return result;
 }
 
@@ -2237,7 +2388,6 @@ crlf_to_lf (n, buf)
   unsigned char *np = buf;
   unsigned char *startp = buf;
   unsigned char *endp = buf + n;
-  unsigned char c;
 
   if (n == 0)
     return n;
@@ -2486,7 +2636,6 @@ The argument object is never altered--the value is a copy.")
   (filename)
      Lisp_Object filename;
 {
-  char *fname;
   Lisp_Object tem;
 
   if (! STRINGP (filename))
@@ -2801,7 +2950,7 @@ run_msdos_command (argv, dir, tempin, tempout, temperr)
   char *saveargv1, *saveargv2, **envv, *lowcase_argv0, *pa, *pl;
   char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS.  */
   int msshell, result = -1;
-  int in, out, inbak, outbak, errbak;
+  int inbak, outbak, errbak;
   int x, y;
   Lisp_Object cmd;
 
@@ -2915,6 +3064,11 @@ run_msdos_command (argv, dir, tempin, tempout, temperr)
       mouse_init ();
       mouse_moveto (x, y);
     }
+
+  /* Some programs might change the meaning of the highest bit of the
+     text attribute byte, so we get blinking characters instead of the
+     bright background colors.  Restore that.  */
+  bright_bg ();
   
  done:
   chdir (oldwd);
@@ -3008,14 +3162,123 @@ int kill (x, y) int x, y; { return -1; }
 nice (p) int p; {}
 void volatile pause () {}
 sigsetmask (x) int x; { return 0; }
+sigblock (mask) int mask; { return 0; } 
 #endif
 
 request_sigio () {}
 setpgrp () {return 0; }
 setpriority (x,y,z) int x,y,z; { return 0; }
-sigblock (mask) int mask; { return 0; } 
 unrequest_sigio () {}
 
+#if __DJGPP__ > 1
+
+#ifdef POSIX_SIGNALS
+
+/* Augment DJGPP library POSIX signal functions.  This is needed
+   as of DJGPP v2.01, but might be in the library in later releases. */
+
+#include <libc/bss.h>
+
+/* A counter to know when to re-initialize the static sets.  */
+static int sigprocmask_count = -1;
+
+/* Which signals are currently blocked (initially none).  */
+static sigset_t current_mask;
+
+/* Which signals are pending (initially none).  */
+static sigset_t pending_signals;
+
+/* Previous handlers to restore when the blocked signals are unblocked.  */
+typedef void (*sighandler_t)(int);
+static sighandler_t prev_handlers[320];
+
+/* A signal handler which just records that a signal occured
+   (it will be raised later, if and when the signal is unblocked).  */
+static void
+sig_suspender (signo)
+     int signo;
+{
+  sigaddset (&pending_signals, signo);
+}
+
+int
+sigprocmask (how, new_set, old_set)
+     int how;
+     const sigset_t *new_set;
+     sigset_t *old_set;
+{
+  int signo;
+  sigset_t new_mask;
+
+  /* If called for the first time, initialize.  */
+  if (sigprocmask_count != __bss_count)
+    {
+      sigprocmask_count = __bss_count;
+      sigemptyset (&pending_signals);
+      sigemptyset (&current_mask);
+      for (signo = 0; signo < 320; signo++)
+       prev_handlers[signo] = SIG_ERR;
+    }
+
+  if (old_set)
+    *old_set = current_mask;
+
+  if (new_set == 0)
+    return 0;
+
+  if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  sigemptyset (&new_mask);
+
+  /* DJGPP supports upto 320 signals.  */
+  for (signo = 0; signo < 320; signo++)
+    {
+      if (sigismember (&current_mask, signo))
+       sigaddset (&new_mask, signo);
+      else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
+       {
+         sigaddset (&new_mask, signo);
+
+         /* SIGKILL is silently ignored, as on other platforms.  */
+         if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
+           prev_handlers[signo] = signal (signo, sig_suspender);
+       }
+      if ((   how == SIG_UNBLOCK
+             && sigismember (&new_mask, signo)
+             && sigismember (new_set, signo))
+         || (how == SIG_SETMASK
+             && sigismember (&new_mask, signo)
+             && !sigismember (new_set, signo)))
+       {
+         sigdelset (&new_mask, signo);
+         if (prev_handlers[signo] != SIG_ERR)
+           {
+             signal (signo, prev_handlers[signo]);
+             prev_handlers[signo] = SIG_ERR;
+           }
+         if (sigismember (&pending_signals, signo))
+           {
+             sigdelset (&pending_signals, signo);
+             raise (signo);
+           }
+       }
+    }
+  current_mask = new_mask;
+  return 0;
+}
+
+#else /* not POSIX_SIGNALS */
+
+sigsetmask (x) int x; { return 0; }
+sigblock (mask) int mask; { return 0; } 
+
+#endif /* not POSIX_SIGNALS */
+#endif /* __DJGPP__ > 1 */
+
 #ifndef HAVE_SELECT
 #include "sysselect.h"