X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/22819cd94f1338130cd1c97f64a6b3451f5b82cd..9a5114ac7e384d28a13c99725380b6024abde5cf:/src/msdos.c diff --git a/src/msdos.c b/src/msdos.c index 89925cc7e3..94b75a5efc 100644 --- a/src/msdos.c +++ b/src/msdos.c @@ -33,10 +33,16 @@ Boston, MA 02111-1307, USA. */ #include #include #include +#include /* for bzero and string functions */ #include /* for _fixpath */ +#include /* for chdir, dup, dup2, etc. */ #if __DJGPP__ >= 2 #include +#include /* for setmode */ +#include /* for __dpmi_xxx stuff */ +#include /* for _farsetsel, _farnspokeb */ #include /* for _USE_LFN */ +#include /* 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 #include #include @@ -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 +#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, ®s, ®s); } +/* 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, ®s, ®s); + } +} + /* 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", 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"); 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, "\n", new_color); + fprintf (termscript, "\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, "\n", new_color); + fprintf (termscript, "\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, ®s, ®s); + 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 + +/* 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 (¤t_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 (¤t_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"