# HG changeset patch # User Eli Zaretskii # Date 908893538 0 # Node ID eee76d0af99cc829dfc0a48baaa78df2ab026f3f # Parent 1518b5946f9f1e6d3e8250090544e1b0eee5bc4b (mouse_init): Reset the button press/release info of the mouse driver. (mouse_preempted): New variable. (dos_rawgetc): Don't generate mouse events if mouse is preempted. (XMenuActivate): Preempt the mouse during menu-handling loop. Release the current time slice while idling in the menu-handling loop. Leave the loop only if the user pressed, then released the same button. Discard all mouse events that are pending in the event queue before exiting. diff -r 1518b5946f9f -r eee76d0af99c src/msdos.c --- a/src/msdos.c Tue Oct 20 14:16:07 1998 +0000 +++ b/src/msdos.c Tue Oct 20 14:25:38 1998 +0000 @@ -214,6 +214,25 @@ return (regs.x.bx != 0); } +static int +mouse_button_depressed (b, xp, yp) + int b, *xp, *yp; +{ + union REGS regs; + + if (b >= mouse_button_count) + return 0; + regs.x.ax = 0x0003; + int86 (0x33, ®s, ®s); + if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0) + { + *xp = regs.x.cx / 8; + *yp = regs.x.dx / 8; + return 1; + } + return 0; +} + void mouse_get_pos (f, insist, bar_window, part, x, y, time) FRAME_PTR *f; @@ -252,6 +271,7 @@ mouse_init () { union REGS regs; + int b; if (termscript) fprintf (termscript, ""); @@ -259,6 +279,18 @@ regs.x.ax = 0x0021; int86 (0x33, ®s, ®s); + /* Reset the mouse last press/release info. It seems that Windows + doesn't do that automatically when function 21h is called, which + causes Emacs to ``remember'' the click that switched focus to the + window just before Emacs was started from that window. */ + for (b = 0; b < mouse_button_count; b++) + { + int dummy_x, dummy_y; + + (void) mouse_pressed (b, &dummy_x, &dummy_y); + (void) mouse_released (b, &dummy_x, &dummy_y); + } + regs.x.ax = 0x0007; regs.x.cx = 0; regs.x.dx = 8 * (ScreenCols () - 1); @@ -1691,6 +1723,7 @@ /* Get a char from keyboard. Function keys are put into the event queue. */ extern void kbd_buffer_store_event (struct input_event *); +static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */ static int dos_rawgetc () @@ -1898,7 +1931,7 @@ kbd_buffer_store_event (&event); } - if (have_mouse > 0) + if (have_mouse > 0 && !mouse_preempted) { int but, press, x, y, ok; @@ -2264,6 +2297,10 @@ if (y0 <= 0) y0 = 1; + /* We will process all the mouse events directly, so we had + better prevented dos_rawgetc from stealing them from us. */ + mouse_preempted++; + state = alloca (menu->panecount * sizeof (struct IT_menu_state)); screensize = screen_size * 2; faces[0] @@ -2386,11 +2423,22 @@ state[statecount - 1].x, faces); } - for (b = 0; b < mouse_button_count; b++) + else + /* We are busy-waiting for the mouse to move, so let's be nice + to other Windows applications by releasing our time slice. */ + __dpmi_yield (); + for (b = 0; b < mouse_button_count && !leave; b++) { - (void) mouse_pressed (b, &x, &y); - if (mouse_released (b, &x, &y)) - leave = 1; + /* Only leave if user both pressed and released the mouse, and in + that order. This avoids popping down the menu pane unless + the user is really done with it. */ + if (mouse_pressed (b, &x, &y)) + { + while (mouse_button_depressed (b, &x, &y)) + __dpmi_yield (); + leave = 1; + } + (void) mouse_released (b, &x, &y); } } @@ -2401,6 +2449,14 @@ while (statecount--) xfree (state[statecount].screen_behind); IT_display_cursor (1); /* turn cursor back on */ + /* Clean up any mouse events that are waiting inside Emacs event queue. + These events are likely to be generated before the menu was even + displayed, probably because the user pressed and released the button + (which invoked the menu) too quickly. If we don't remove these events, + Emacs will process them after we return and surprise the user. */ + discard_mouse_events (); + /* Allow mouse events generation by dos_rawgetc. */ + mouse_preempted--; return result; }